From 1d8db21f1818626116e8d8309427fc5517e31b0b Mon Sep 17 00:00:00 2001 From: KingMcDonalds Date: Sat, 28 Mar 2026 00:24:08 -0700 Subject: [PATCH] fixing mlopd --- resources/Fire-Script/LICENSE | 674 -------- resources/Fire-Script/README.md | 48 - resources/Fire-Script/client/dispatch.lua | 131 -- resources/Fire-Script/client/fire.lua | 227 --- resources/Fire-Script/client/main.lua | 394 ----- resources/Fire-Script/client/utils.lua | 34 - resources/Fire-Script/config.lua | 31 - resources/Fire-Script/fires.json | 1 - resources/Fire-Script/fxmanifest.lua | 26 - resources/Fire-Script/server/dispatch.lua | 72 - resources/Fire-Script/server/fire.lua | 330 ---- resources/Fire-Script/server/main.lua | 598 ------- resources/Fire-Script/server/utils.lua | 120 -- resources/Fire-Script/server/whitelist.lua | 68 - resources/Fire-Script/whitelist.json | 1 - resources/SmartFires/.fxap | Bin 0 -> 185 bytes resources/SmartFires/Documentation.url | 5 + resources/SmartFires/cl_exports.lua | 59 + resources/SmartFires/cl_smartfires.lua | Bin 0 -> 24102 bytes resources/SmartFires/cl_utils.lua | 48 + resources/SmartFires/config.lua | 1528 +++++++++++++++++ resources/SmartFires/fxmanifest.lua | 38 + resources/SmartFires/shared.lua | 30 + resources/SmartFires/sv_exports.lua | 182 ++ resources/SmartFires/sv_smartfires.lua | Bin 0 -> 7263 bytes resources/SmartFires/sv_utils.lua | 1083 ++++++++++++ .../LAPDFPIS_4pack/stream/lapdfpis2+hi.ytd | 3 - .../LAPDFPIS_4pack/stream/lapdfpis2.yft | 3 - .../LAPDFPIS_4pack/stream/lapdfpis2.ytd | 3 - .../LAPDFPIS_4pack/stream/lapdfpis2_hi.yft | 3 - .../[lapd-pack]/LAPDFPIS_4pack/vehicles.meta | 128 +- .../lapd19fpisv/carvariations.meta | 2 +- .../[lasd-packs]/lasd25fpiu/vehicles.meta | 77 +- .../lasdoldtahoe/stream/lasd08tahoe.ytd | 4 +- .../lasdoldtahoe/stream/lasd08tahoe2.ytd | 4 +- .../lasdoldtahoe/stream/lasd14tahoe.ytd | 4 +- resources/ulc/config.lua | 1438 ++++++++++++---- server.cfg | 4 +- 38 files changed, 4119 insertions(+), 3282 deletions(-) delete mode 100644 resources/Fire-Script/LICENSE delete mode 100644 resources/Fire-Script/README.md delete mode 100644 resources/Fire-Script/client/dispatch.lua delete mode 100644 resources/Fire-Script/client/fire.lua delete mode 100644 resources/Fire-Script/client/main.lua delete mode 100644 resources/Fire-Script/client/utils.lua delete mode 100644 resources/Fire-Script/config.lua delete mode 100644 resources/Fire-Script/fires.json delete mode 100644 resources/Fire-Script/fxmanifest.lua delete mode 100644 resources/Fire-Script/server/dispatch.lua delete mode 100644 resources/Fire-Script/server/fire.lua delete mode 100644 resources/Fire-Script/server/main.lua delete mode 100644 resources/Fire-Script/server/utils.lua delete mode 100644 resources/Fire-Script/server/whitelist.lua delete mode 100644 resources/Fire-Script/whitelist.json create mode 100644 resources/SmartFires/.fxap create mode 100644 resources/SmartFires/Documentation.url create mode 100644 resources/SmartFires/cl_exports.lua create mode 100644 resources/SmartFires/cl_smartfires.lua create mode 100644 resources/SmartFires/cl_utils.lua create mode 100644 resources/SmartFires/config.lua create mode 100644 resources/SmartFires/fxmanifest.lua create mode 100644 resources/SmartFires/shared.lua create mode 100644 resources/SmartFires/sv_exports.lua create mode 100644 resources/SmartFires/sv_smartfires.lua create mode 100644 resources/SmartFires/sv_utils.lua delete mode 100644 resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2+hi.ytd delete mode 100644 resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2.yft delete mode 100644 resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2.ytd delete mode 100644 resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2_hi.yft diff --git a/resources/Fire-Script/LICENSE b/resources/Fire-Script/LICENSE deleted file mode 100644 index f288702d2..000000000 --- a/resources/Fire-Script/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - 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/resources/Fire-Script/README.md b/resources/Fire-Script/README.md deleted file mode 100644 index 6b54b9b65..000000000 --- a/resources/Fire-Script/README.md +++ /dev/null @@ -1,48 +0,0 @@ -![Logo](https://i.imgur.com/cfPLDVh.png) - -[![License GNU-GPL v3](https://img.shields.io/github/license/gimicze/firescript?style=for-the-badge)](https://github.com/gimicze/firescript/blob/master/LICENSE "License") -[![Latest release](https://img.shields.io/github/v/release/gimicze/firescript?style=for-the-badge)](https://github.com/gimicze/firescript/releases/latest "Latest release") -[![Total downloads](https://img.shields.io/github/downloads/gimicze/firescript/total?style=for-the-badge)](https://github.com/gimicze/firescript/releases/latest "Total downloads") - -A FiveM resource enabling whitelisted users to create a (*somewhat*) realistic fires. As far as I am aware, the only fire script compatible with OneSync Infinity / Beyond. - -
-In-game screenshots - -![Example fire](https://i.imgur.com/XOLJN7v.png "Example fire") -![Example fire](https://i.imgur.com/IYmE6qn.png) -
- -# Instalation - -1. Extract the contents into folder called `firescript` into your resources folder. -2. Start the script: **a)** in the `server.cfg` file; **b)** through the console - -## Starting a resource through console - -1. In a server console, or client console (F8), type in `refresh` and confirm using ENTER -2. Type in `start firescript` and confirm using ENTER - -## Starting a resource in `server.cfg` -1. Add this line to your server.cfg -``` -start firescript -``` -2. Save the file and restart the server. - -# Usage & Commands - -*Tutorial moved to [the wiki](https://github.com/gimicze/firescript/wiki).* - -# Known bugs -*None! Feel free to open issue when you find any!* - -# Credits -- Albo1125 and foregz - I borrowed some particles from their fire scripts. Thanks! -- MadMick#0773, Mickey#2590 and MadLadClip for testing and help with the script. - -# Contributing -Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. - -# License -[GNU GPL 3.0](https://github.com/gimicze/firescript/blob/main/LICENSE) diff --git a/resources/Fire-Script/client/dispatch.lua b/resources/Fire-Script/client/dispatch.lua deleted file mode 100644 index 6cdf2656d..000000000 --- a/resources/Fire-Script/client/dispatch.lua +++ /dev/null @@ -1,131 +0,0 @@ ---================================-- --- FIRE SCRIPT v1.6.3 -- --- by GIMI (+ foregz, Albo1125) -- --- License: GNU GPL 3.0 -- ---================================-- - -Dispatch = { - lastCall = nil, - blips = {}, - __index = self, - init = function(o) - o = o or {active = {}, removed = {}} - setmetatable(o, self) - self.__index = self - return o - end -} - -function Dispatch:renderRoute(coords) - ClearGpsMultiRoute() - - StartGpsMultiRoute(6, true, true) - AddPointToGpsMultiRoute(table.unpack(coords)) - SetGpsMultiRouteRender(true) -end - -function Dispatch:create(dispatchNumber, coords) - if not (dispatchNumber and coords) then - return - end - - -- Create a fire blip - local blip = AddBlipForCoord(table.unpack(coords)) - SetBlipSprite(blip, 436) - SetBlipDisplay(blip, 4) - SetBlipScale(blip, 1.5) - SetBlipColour(blip, 1) - SetBlipAsShortRange(blip, false) - BeginTextCommandSetBlipName("STRING") - AddTextComponentString("Fire #" .. dispatchNumber) - EndTextCommandSetBlipName(blip) - - self.blips[dispatchNumber] = { - coords = coords, - blip = blip - } - - self:renderRoute(coords) - - if Config.Dispatch.playSound then - Citizen.CreateThread( - function() - for i = 1, 3 do - PlaySoundFromEntity(-1, "IDLE_BEEP", GetPlayerPed(-1), "EPSILONISM_04_SOUNDSET", 0) - Citizen.Wait(300) - end - end - ) - end - - FlashMinimapDisplay() - - Citizen.SetTimeout( - Config.Dispatch.removeBlipTimeout, - function() - if self.blips[dispatchNumber] and self.blips[dispatchNumber].blip then - RemoveBlip(blip) - self.blips[dispatchNumber].blip = false - end - if self.lastCall == dispatchNumber then - ClearGpsMultiRoute() - end - end - ) - - -- Only store the last 'Config.Dispatch.storeLast' dispatches' data. - if countElements(self.blips) > Config.Dispatch.storeLast then - local order = {} - - for k, v in pairs(self.blips) do - table.insert(order, k) - end - - table.sort(order) - self.blips[order[1]] = nil - end - - self.lastCall = dispatchNumber -end - -function Dispatch:clear(dispatchNumber) - ClearGpsMultiRoute() - - if dispatchNumber and self.blips[dispatchNumber] and self.blips[dispatchNumber].blip then - RemoveBlip(self.blips[dispatchNumber].blip) - self.blips[dispatchNumber].blip = false - elseif dispatchNumber == 0 then - for k, v in pairs(self.blips) do - if self.blips[k].blip then - RemoveBlip(self.blips[k].blip) - self.blips[k].blip = false - end - end - end -end - -function Dispatch:remind(dispatchNumber) - if self.blips[dispatchNumber] then - SetNewWaypoint(table.unpack(self.blips[dispatchNumber].coords.xy)) - return true - else - return false - end -end - ---================================-- --- DISPATCH ROUTE REMOVAL -- ---================================-- - -if Config.Dispatch.clearGpsRadius and tonumber(Config.Dispatch.clearGpsRadius) then - Citizen.CreateThread( - function() - while true do - Citizen.Wait(5000) - if Dispatch.lastCall and Dispatch.blips[Dispatch.lastCall] and Dispatch.blips[Dispatch.lastCall].blip and #(Dispatch.blips[Dispatch.lastCall].coords - GetEntityCoords(GetPlayerPed(-1))) < Config.Dispatch.clearGpsRadius then - ClearGpsMultiRoute() - end - end - end - ) -end \ No newline at end of file diff --git a/resources/Fire-Script/client/fire.lua b/resources/Fire-Script/client/fire.lua deleted file mode 100644 index 57d4d253c..000000000 --- a/resources/Fire-Script/client/fire.lua +++ /dev/null @@ -1,227 +0,0 @@ ---================================-- --- FIRE SCRIPT v1.7.6 -- --- by GIMI (+ foregz, Albo1125) -- --- License: GNU GPL 3.0 -- ---================================-- - -Fire = { - active = {}, - removed = {}, - __index = self, - init = function(o) - o = o or {active = {}, removed = {}} - setmetatable(o, self) - self.__index = self - return o - end -} - -function Fire:createFlame(fireIndex, flameIndex, coords) - if not self.removed[fireIndex] then - if self.active[fireIndex] == nil then - self.active[fireIndex] = { - flameCoords = {}, - flames = {}, - particles = {}, - flameParticles = {} - } - end - self.active[fireIndex].flameCoords[flameIndex] = coords - end -end - -function Fire:removeFlame(fireIndex, flameIndex) - if not (fireIndex and flameIndex and self.active[fireIndex]) then - return - end - - if self.active[fireIndex].flames[flameIndex] and self.active[fireIndex].flames[flameIndex] > -1 then - RemoveScriptFire(self.active[fireIndex].flames[flameIndex]) - self.active[fireIndex].flames[flameIndex] = nil - end - - if self.active[fireIndex].particles[flameIndex] and self.active[fireIndex].particles[flameIndex] ~= 0 then - local particles = self.active[fireIndex].particles[flameIndex] - Citizen.SetTimeout( - 5000, - function() - StopParticleFxLooped(particles, false) - RemoveParticleFx(particles, true) - end - ) - self.active[fireIndex].particles[flameIndex] = nil - end - - if self.active[fireIndex].flameParticles[flameIndex] and self.active[fireIndex].flameParticles[flameIndex] ~= 0 then - local flameParticles = self.active[fireIndex].flameParticles[flameIndex] - Citizen.SetTimeout( - 5000, - function() - StopParticleFxLooped(flameParticles, false) - RemoveParticleFx(flameParticles, true) - end - ) - self.active[fireIndex].flameParticles[flameIndex] = nil - end - - self.active[fireIndex].flameCoords[flameIndex] = nil - - if self.active[fireIndex] ~= nil and countElements(self.active[fireIndex].flames) < 1 then - self.active[fireIndex] = nil - self.removed[fireIndex] = true - end -end - -function Fire:remove(fireIndex, callback) - if not (self.active[fireIndex] and self.active[fireIndex].particles) then - return - end - - for k, v in pairs(self.active[fireIndex].flameCoords) do - self:removeFlame(fireIndex, k) - Citizen.Wait(20) - end - - Citizen.SetTimeout( - 200, - function() - if self.active[fireIndex] and next(self.active[fireIndex].flames) ~= nil then - print("WARNING: A fire persisted!") - self:remove(fireIndex) - elseif callback then - callback(fireIndex) - end - end - ) -end - -function Fire:removeAll(callback) - for k, v in pairs(self.active) do - self:remove(k) - Citizen.Wait(20) - end - - self.active = {} - self.removed = {} - - if callback then - callback() - end -end - ---================================-- --- PARTICLES & FIRE EXTINGUISHING -- ---================================-- - -Citizen.CreateThread( - function() - if not HasNamedPtfxAssetLoaded("scr_agencyheistb") then - RequestNamedPtfxAsset("scr_agencyheistb") - while not HasNamedPtfxAssetLoaded("scr_agencyheistb") do - Wait(1) - end - end - - if not HasNamedPtfxAssetLoaded("scr_trevor3") then - RequestNamedPtfxAsset("scr_trevor3") - while not HasNamedPtfxAssetLoaded("scr_trevor3") do - Wait(1) - end - end - - while true do - Citizen.Wait(1500) - for fireIndex, v in pairs(Fire.active) do - if countElements(v.particles) ~= 0 then - for flameIndex, _v in pairs(v.particles) do - if v.flameCoords[flameIndex] ~= nil then - local isFirePresent = GetNumberOfFiresInRange( - v.flameCoords[flameIndex].x, - v.flameCoords[flameIndex].y, - v.flameCoords[flameIndex].z, - 0.05 - ) - if isFirePresent == 0 then - TriggerServerEvent('fireManager:removeFlame', fireIndex, flameIndex) - end - end - end - end - end - end - end -) - -Citizen.CreateThread( - function() - while true do - local pedCoords = GetEntityCoords(GetPlayerPed(-1)) - for fireIndex, v in pairs(Fire.active) do - for flameIndex, coords in pairs(Fire.active[fireIndex].flameCoords) do - Citizen.Wait(10) - while syncInProgress do - Citizen.Wait(10) - end - syncInProgress = true - if Fire.active[fireIndex] and Fire.active[fireIndex].flameCoords[flameIndex] and not Fire.active[fireIndex].particles[flameIndex] and #(coords - pedCoords) < 300.0 then - local z = coords.z - - repeat - Wait(0) - ground, newZ = GetGroundZFor_3dCoord(coords.x, coords.y, z) - if not ground then - z = z + 0.1 - end - until ground - z = newZ - - Fire.active[fireIndex].flames[flameIndex] = StartScriptFire(coords.x, coords.y, z, 0, false) - - if Fire.active[fireIndex].flames[flameIndex] then -- Make sure the fire has been spawned properly - Fire.active[fireIndex].flameCoords[flameIndex] = vector3(coords.x, coords.y, z) - - SetPtfxAssetNextCall("scr_agencyheistb") - - Fire.active[fireIndex].particles[flameIndex] = StartParticleFxLoopedAtCoord( - "scr_env_agency3b_smoke", - Fire.active[fireIndex].flameCoords[flameIndex].x, - Fire.active[fireIndex].flameCoords[flameIndex].y, - Fire.active[fireIndex].flameCoords[flameIndex].z + 1.0, - 0.0, - 0.0, - 0.0, - 1.0, - false, - false, - false, - false - ) - - SetPtfxAssetNextCall("scr_trevor3") - - Fire.active[fireIndex].flameParticles[flameIndex] = StartParticleFxLoopedAtCoord( - "scr_trev3_trailer_plume", - Fire.active[fireIndex].flameCoords[flameIndex].x, - Fire.active[fireIndex].flameCoords[flameIndex].y, - Fire.active[fireIndex].flameCoords[flameIndex].z + 1.2, - 0.0, - 0.0, - 0.0, - 1.0, - false, - false, - false, - false - ) - - else - Fire.active[fireIndex].flames[flameIndex] = nil - end - end - syncInProgress = false - end - end - Citizen.Wait(1500) - end - end -) \ No newline at end of file diff --git a/resources/Fire-Script/client/main.lua b/resources/Fire-Script/client/main.lua deleted file mode 100644 index 06003de45..000000000 --- a/resources/Fire-Script/client/main.lua +++ /dev/null @@ -1,394 +0,0 @@ ---================================-- --- FIRE SCRIPT v1.7.6 -- --- by GIMI (+ foregz, Albo1125) -- --- License: GNU GPL 3.0 -- ---================================-- - ---================================-- --- CHAT -- ---================================-- - -TriggerEvent("chat:addTemplate", "firescript", '
{0} {1}
') - -TriggerEvent('chat:addSuggestion', '/startfire', 'Creates a fire', { - { - name = "spread", - help = "How many times can the fire spread?" - }, - { - name = "chance", - help = "0 - 100; How quickly the fire spreads?" - }, - { - name = "dispatch", - help = "true or false (default false)" - }, - { - name = "dispatchMessage", - help = "Sets a custom dispatch message (leave empty to generate automatically)" - } -}) - -TriggerEvent('chat:addSuggestion', '/stopfire', 'Stops the fire', { - { - name = "index", - help = "The fire's index" - } -}) - -TriggerEvent('chat:addSuggestion', '/stopallfires', 'Stops all fires') - -TriggerEvent('chat:addSuggestion', '/registerscenario', 'Registers a new fire configuration') - -TriggerEvent('chat:addSuggestion', '/addflame', 'Adds a flame to a scenario', { - { - name = "scenarioID", - help = "The scenario" - }, - { - name = "spread", - help = "How many times can the flame spread?" - }, - { - name = "chance", - help = "How many out of 100 chances should the fire spread? (0-100)" - } -}) - -TriggerEvent('chat:addSuggestion', '/removeflame', 'Removes a flame from a scenario', { - { - name = "scenarioID", - help = "The fire ID" - }, - { - name = "flameID", - help = "The flame ID" - } -}) - -TriggerEvent('chat:addSuggestion', '/removescenario', 'Removes a scenario', { - { - name = "scenarioID", - help = "The fire ID" - } -}) - -TriggerEvent('chat:addSuggestion', '/startscenario', 'Starts a scenario', { - { - name = "scenarioID", - help = "The fire ID" - }, - { - name = "triggerDispatch", - help = "true / false - should the script trigger dispatch after spawning the fire? (default false)" - } -}) - -TriggerEvent('chat:addSuggestion', '/stopscenario', 'Stops a scenario', { - { - name = "scenarioID", - help = "The fire ID" - } -}) - -TriggerEvent('chat:addSuggestion', '/firewl', 'Manages the fire script whitelist', { - { - name = "action", - help = "add / remove" - }, - { - name = "playerID", - help = "The player's server ID" - } -}) - -TriggerEvent('chat:addSuggestion', '/firewlreload', 'Reloads the whitelist from the config') - -TriggerEvent('chat:addSuggestion', '/firedispatch', 'Manages the fire script dispatch subscribers', { - { - name = "action", - help = "add / remove / scenario (scenario = sets the scenario's dispatch message)" - }, - { - name = "playerID / scenarioID", - help = "The player's server ID / the scenario's ID" - }, - { - name = "dispatchMessage", - help = "(optional) Sets a custom dispatch message for the scenario (use only with par. #1 scenario; leave empty to remove previous custom message)" - } -}) - -TriggerEvent('chat:addSuggestion', '/remindme', 'Sets the GPS waypoint to the specified dispatch call.', { - { - name = "dispatchID", - help = "The dispatch identifier (number)" - } -}) - -TriggerEvent('chat:addSuggestion', '/cleardispatch', 'Clears navigation to the last dispatch call.', { - { - name = "dispatchID", - help = "(optional) The dispatch identifier, if filled in, the call's blip will be removed. Set to 0 to remove all dispatch blips." - } -}) - -TriggerEvent('chat:addSuggestion', '/randomfires', 'Manages the random fire spawner', { - { - name = "action", - help = "add / remove / enable / disable" - }, - { - name = "p2", - help = "(optional) For add / remove action, fill in the scenario ID." - } -}) - ---================================-- --- SYNC ON CONNECT -- ---================================-- - -RegisterNetEvent('playerSpawned') -AddEventHandler( - 'playerSpawned', - function() - print("Requested synchronization..") - TriggerServerEvent('fireManager:requestSync') - end -) - -RegisterNetEvent('onClientResourceStart') -AddEventHandler( - 'onClientResourceStart', - function(resourceName) - if resourceName == GetCurrentResourceName() then - -- Check the command whitelist - TriggerServerEvent('fireManager:checkWhitelist') - end - end -) - ---================================-- --- COMMANDS -- ---================================-- - -RegisterCommand( - 'remindme', - function(source, args, rawCommand) - local dispatchNumber = tonumber(args[1]) - if not dispatchNumber then - sendMessage("Invalid argument.") - return - end - - local success = Dispatch:remind(dispatchNumber) - - if not success then - sendMessage("Couldn't find the specified dispatch.") - return - end - end, - false -) - -RegisterCommand( - 'cleardispatch', - function(source, args, rawCommand) - Dispatch:clear(tonumber(args[1])) - end, - false -) - -RegisterCommand( - 'startfire', - function(source, args, rawCommand) - local maxSpread = tonumber(args[1]) - local probability = tonumber(args[2]) - local triggerDispatch = args[3] == "true" - - table.remove(args, 1) - table.remove(args, 1) - table.remove(args, 1) - - local dispatchMessage = next(args) and table.concat(args, " ") or nil - - TriggerServerEvent('fireManager:command:startfire', GetEntityCoords(GetPlayerPed(-1)), maxSpread, probability, triggerDispatch, dispatchMessage) - end, - false -) - -RegisterCommand( - 'registerscenario', - function(source, args, rawCommand) - local coords = nil - - local x = tonumber(args[1]) - local y = tonumber(args[2]) - local z = tonumber(args[3]) - - if x and y and z then - coords = vector3(x, y, z) - end - - TriggerServerEvent('fireManager:command:registerscenario', coords or GetEntityCoords(GetPlayerPed(-1))) - end, - false -) - -RegisterCommand( - 'addflame', - function(source, args, rawCommand) - local registeredFireID = tonumber(args[1]) - local spread = tonumber(args[2]) - local chance = tonumber(args[3]) - - local coords = nil - - local x = tonumber(args[4]) - local y = tonumber(args[5]) - local z = tonumber(args[6]) - - if x and y and z then - coords = vector3(x, y, z) - end - - if registeredFireID and spread and chance then - TriggerServerEvent('fireManager:command:addflame', registeredFireID, coords or GetEntityCoords(GetPlayerPed(-1)), spread, chance) - end - end, - false -) - --- Aliases - -RegisterCommand( - 'registerfire', - function(source, args, rawCommand) - ExecuteCommand("registerscenario" .. rawCommand:sub(13)) - end, - false -) - -RegisterCommand( - 'removeregisteredfire', - function(source, args, rawCommand) - ExecuteCommand("removescenario" .. rawCommand:sub(21)) - end, - false -) - -RegisterCommand( - 'startregisteredfire', - function(source, args, rawCommand) - ExecuteCommand("startscenario" .. rawCommand:sub(20)) - end, - false -) - -RegisterCommand( - 'stopregisteredfire', - function(source, args, rawCommand) - ExecuteCommand("stopscenario" .. rawCommand:sub(19)) - end, - false -) - ---================================-- --- EVENTS -- ---================================-- - -RegisterNetEvent('fireClient:synchronizeFlames') -AddEventHandler( - 'fireClient:synchronizeFlames', - function(fires) - syncInProgress = true - Fire:removeAll( - function() - for k, v in pairs(fires) do - for _k, _v in ipairs(v) do - Fire:createFlame(k, _k, _v) - end - end - syncInProgress = false - end - ) - end -) - -RegisterNetEvent('fireClient:removeFire') -AddEventHandler( - 'fireClient:removeFire', - function(fireIndex) - while syncInProgress do - Citizen.Wait(10) - end - syncInProgress = true - Fire:remove(fireIndex) - syncInProgress = false - end -) - -RegisterNetEvent('fireClient:removeAllFires') -AddEventHandler( - 'fireClient:removeAllFires', - function() - while syncInProgress do - Citizen.Wait(10) - end - syncInProgress = true - Fire:removeAll( - function() - syncInProgress = false - end - ) - end -) - -RegisterNetEvent("fireClient:removeFlame") -AddEventHandler( - "fireClient:removeFlame", - function(fireIndex, flameIndex) - while syncInProgress do - Citizen.Wait(10) - end - syncInProgress = true - Fire:removeFlame(fireIndex, flameIndex) - syncInProgress = false - end -) - -RegisterNetEvent("fireClient:createFlame") -AddEventHandler( - "fireClient:createFlame", - function(fireIndex, flameIndex, coords) - while syncInProgress do - Citizen.Wait(10) - end - syncInProgress = true - Fire:createFlame(fireIndex, flameIndex, coords) - syncInProgress = false - end -) - --- Dispatch - -if Config.Dispatch.enabled == true then - RegisterNetEvent('fd:dispatch') - AddEventHandler( - 'fd:dispatch', - function(coords) - local streetName, crossingRoad = GetStreetNameAtCoord(coords.x, coords.y, coords.z) - local streetName = GetStreetNameFromHashKey(streetName) - local text = ("A fire broke out at %s."):format((crossingRoad > 0) and streetName .. " / " .. GetStreetNameFromHashKey(crossingRoad) or streetName) - TriggerServerEvent('fireDispatch:create', text, coords) - end - ) -end - -RegisterNetEvent('fireClient:createDispatch') -AddEventHandler( - 'fireClient:createDispatch', - function(dispatchNumber, coords) - Dispatch:create(dispatchNumber, coords) - end -) diff --git a/resources/Fire-Script/client/utils.lua b/resources/Fire-Script/client/utils.lua deleted file mode 100644 index de4e371ba..000000000 --- a/resources/Fire-Script/client/utils.lua +++ /dev/null @@ -1,34 +0,0 @@ ---================================-- --- FIRE SCRIPT v1.7.6 -- --- by GIMI (+ foregz, Albo1125) -- --- License: GNU GPL 3.0 -- ---================================-- - --- Chat - -function sendMessage(text) - TriggerEvent( - "chat:addMessage", - { - templateId = "firescript", - args = { - "FireScript v1.7.4", - text - } - } - ) -end - --- Table functions - -function countElements(table) - local count = 0 - if type(table) == "table" then - for k, v in pairs(table) do - count = count + 1 - end - end - return count -end - -syncInProgress = false \ No newline at end of file diff --git a/resources/Fire-Script/config.lua b/resources/Fire-Script/config.lua deleted file mode 100644 index 21100974a..000000000 --- a/resources/Fire-Script/config.lua +++ /dev/null @@ -1,31 +0,0 @@ ---================================-- --- FIRE SCRIPT v1.7.6 -- --- by GIMI (+ foregz, Albo1125) -- --- License: GNU GPL 3.0 -- ---================================-- - -Config = {} - -Config.Fire = { - fireSpreadChance = 5, -- Out of 100 chances, how many lead to fire spreading? (not exactly percents) - maximumSpreads = 5, - spawner = { -- Requires the use of the built-in dispatch system - enableOnStartup = true, - interval = 1800000, -- Random fire spawn interval (set to nil or false if you don't want to spawn random fires) in ms - chance = 50, -- Fire spawn chance (out of 100 chances, how many lead to spawning a fire?); Set to values between 1-100 - players = 3, -- Sets the minimum number of players subscribed to dispatch for the spawner to spawn fires. - firefighterJobs = { -- If using ESX (Config.Dispatch.enableESX), you can specify which players will count as firefighters in Config.Fire.spawner.players above; If not using ESX you can set this to nil - ["fd"] = false -- Always set the job name in the key, value has to be true - } - } -} - -Config.Dispatch = { - enabled = true, -- Set this to false if you don't want to use the default dispatch system - timeout = 15000, -- The amount of time in ms to delay the dispatch after the fire has been created - storeLast = 5, -- The client will store the last five dispatch coordinates for use with /remindme - clearGpsRadius = 20.0, -- If you don't want to automatically clear the route upon arrival, leave this to false - removeBlipTimeout = 400000, -- The amount of time in ms after which the dispatch call blip will be automatically removed - playSound = true, - enableESX = "fd" -- Set to a ESX job / jobs you want to be automatically subscribed to dispatch; Set to nil or false if you don't want to use this -} \ No newline at end of file diff --git a/resources/Fire-Script/fires.json b/resources/Fire-Script/fires.json deleted file mode 100644 index 0637a088a..000000000 --- a/resources/Fire-Script/fires.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/resources/Fire-Script/fxmanifest.lua b/resources/Fire-Script/fxmanifest.lua deleted file mode 100644 index 82a5b9fcf..000000000 --- a/resources/Fire-Script/fxmanifest.lua +++ /dev/null @@ -1,26 +0,0 @@ -fx_version 'adamant' - -games { - 'gta5' -} - -author 'GIMI, foregz, Albo1125' -version '1.7.6' -description 'Fire Script' - -client_scripts { - "config.lua", - "client/utils.lua", - "client/fire.lua", - "client/dispatch.lua", - "client/main.lua", -} - -server_scripts { - "config.lua", - "server/utils.lua", - "server/whitelist.lua", - "server/fire.lua", - "server/dispatch.lua", - "server/main.lua", -} diff --git a/resources/Fire-Script/server/dispatch.lua b/resources/Fire-Script/server/dispatch.lua deleted file mode 100644 index 61a6194ab..000000000 --- a/resources/Fire-Script/server/dispatch.lua +++ /dev/null @@ -1,72 +0,0 @@ ---================================-- --- FIRE SCRIPT v1.7.2 -- --- by GIMI (+ foregz, Albo1125) -- --- License: GNU GPL 3.0 -- ---================================-- - -Dispatch = { - _players = {}, - _firefighters = {}, - lastNumber = 0, - expectingInfo = {}, - __index = self, - init = function(object) - object = object or {_players = {}, _firefighters = {}, lastNumber = 0, expectingInfo = {}} - setmetatable(object, self) - return object - end -} - -function Dispatch:create(text, coords) - text = tostring(text) - - if not (text and coords) then - return - end - - self.lastNumber = self.lastNumber + 1 - - for k, v in pairs(self._players) do - sendMessage(k, text, ("Dispatch (#%s)"):format(self.lastNumber)) - TriggerClientEvent('fireClient:createDispatch', k, self.lastNumber, coords) - end -end - -function Dispatch:subscribe(serverId, isFirefighter) - serverId = tonumber(serverId) - self._players[serverId] = true - if isFirefighter then - self:addFirefighter(serverId) - end -end - -function Dispatch:unsubscribe(serverId) - serverId = tonumber(serverId) - self._players[serverId] = nil - self:removeFirefighter(serverId) -end - -function Dispatch:addFirefighter(serverId) - serverId = tonumber(serverId) - self._firefighters[serverId] = true -end - -function Dispatch:removeFirefighter(serverId) - serverId = tonumber(serverId) - self._firefighters[serverId] = nil -end - -function Dispatch:firefighters() - return table.length(self._firefighters) -end - -function Dispatch:players() - return table.length(self._players) -end - -function Dispatch:getRandomPlayer() - if not next(self._players) then - return next(GetPlayers()) or false - end - return table.random(self._players) -end \ No newline at end of file diff --git a/resources/Fire-Script/server/fire.lua b/resources/Fire-Script/server/fire.lua deleted file mode 100644 index c3e74af68..000000000 --- a/resources/Fire-Script/server/fire.lua +++ /dev/null @@ -1,330 +0,0 @@ ---================================-- --- FIRE SCRIPT v1.7.6 -- --- by GIMI (+ foregz, Albo1125) -- --- License: GNU GPL 3.0 -- ---================================-- - -Fire = { - registered = {}, - random = {}, - active = {}, - binds = {}, - activeBinds = {}, - __index = self, - init = function(o) - o = o or {registered = {}, random = {}, active = {}, binds = {}, activeBinds = {}} - setmetatable(o, self) - self.__index = self - return o - end -} - -function Fire:create(coords, maximumSpread, spreadChance) - maximumSpread = maximumSpread and maximumSpread or Config.Fire.maximumSpreads - spreadChance = spreadChance and spreadChance or Config.Fire.fireSpreadChance - - local fireIndex = highestIndex(self.active) - fireIndex = fireIndex + 1 - - self.active[fireIndex] = { - maxSpread = maxSpread, - spreadChance = spreadChance - } - - self:createFlame(fireIndex, coords) - - local spread = true - - -- Spreading - Citizen.CreateThread( - function() - while spread do - Citizen.Wait(2000) - local index, flames = highestIndex(self.active, fireIndex) - if flames ~= 0 and flames <= maximumSpread and self.active[fireIndex] ~= nil then - for k, v in ipairs(self.active[fireIndex]) do - index, flames = highestIndex(self.active, fireIndex) - local rndSpread = math.random(100) - if flames <= maximumSpread and rndSpread <= spreadChance then - local x = self.active[fireIndex][k].x - local y = self.active[fireIndex][k].y - local z = self.active[fireIndex][k].z - - local xSpread = math.random(-3, 3) - local ySpread = math.random(-3, 3) - - coords = vector3(x + xSpread, y + ySpread, z) - - self:createFlame(fireIndex, coords) - elseif flames > maximumSpread then - spread = false - break - end - end - elseif flames == 0 or self.active[fireIndex] == nil then - break - end - end - end - ) - - self.active[fireIndex].stopSpread = function() - spread = false - end - - return fireIndex -end - -function Fire:createFlame(fireIndex, coords) - local flameIndex = highestIndex(self.active, fireIndex) + 1 - self.active[fireIndex][flameIndex] = coords - TriggerClientEvent('fireClient:createFlame', -1, fireIndex, flameIndex, coords) -end - -function Fire:remove(fireIndex) - if not (self.active[fireIndex] and next(self.active[fireIndex])) then - return false - end - - self.active[fireIndex].stopSpread() - TriggerClientEvent('fireClient:removeFire', -1, fireIndex) - - if self.activeBinds[fireIndex] then - self.binds[self.activeBinds[fireIndex]][fireIndex] = nil - - if self.activeBinds[fireIndex] == self.currentRandom and next(self.binds[self.activeBinds[fireIndex]]) == nil then - self.currentRandom = nil - end - end - - self.active[fireIndex] = {} - return true -end - -function Fire:removeFlame(fireIndex, flameIndex) - if self.active[fireIndex] and self.active[fireIndex][flameIndex] then - self.active[fireIndex][flameIndex] = nil - if type(next(self.active[fireIndex])) == "string" then - self:remove(fireIndex) - end - end - TriggerClientEvent('fireClient:removeFlame', -1, fireIndex, flameIndex) -end - -function Fire:removeAll() - TriggerClientEvent('fireClient:removeAllFires', -1) - for k, v in pairs(self.active) do - if v.stopSpread then - v.stopSpread() - end - end - self.active = {} - self.activeBinds = {} - self.binds = {} - self.currentRandom = nil -end - -function Fire:register(coords) - local registeredFireID = highestIndex(self.registered) + 1 - - self.registered[registeredFireID] = { - flames = {} - } - - if coords then - self.registered[registeredFireID].dispatchCoords = coords - end - - self:saveRegistered() - - return registeredFireID -end - -function Fire:startRegistered(registeredFireID, triggerDispatch, dispatchPlayer) - if not self.registered[registeredFireID] then - return false - end - - if not self.binds[registeredFireID] then - self.binds[registeredFireID] = {} - end - - for k, v in pairs(self.registered[registeredFireID].flames) do - local fireID = Fire:create(v.coords, v.spread, v.chance) - self.binds[registeredFireID][fireID] = true - self.activeBinds[fireID] = registeredFireID - Citizen.Wait(10) - end - - if self.registered[registeredFireID].dispatchCoords and triggerDispatch and dispatchPlayer then - local dispatchCoords = self.registered[registeredFireID].dispatchCoords - Citizen.SetTimeout( - Config.Dispatch.timeout, - function() - if Config.Dispatch.enabled then - if self.registered[registeredFireID].message ~= nil then - Dispatch:create(self.registered[registeredFireID].message, dispatchCoords) - else - Dispatch.expectingInfo[dispatchPlayer] = true - TriggerClientEvent('fd:dispatch', dispatchPlayer, dispatchCoords) - end - end - end - ) - end - - return true -end - -function Fire:stopRegistered(registeredFireID) - if not self.binds[registeredFireID] then - return false - end - - for k, v in pairs(self.binds[registeredFireID]) do - self.activeBinds[k] = nil - Fire:remove(k) - Citizen.Wait(10) - end - - self.binds[registeredFireID] = nil - - if self.currentRandom and self.currentRandom == registeredFireID then - self.currentRandom = nil - end - - return true -end - -function Fire:deleteRegistered(registeredFireID) - if not self.registered[registeredFireID] then - return false - end - - if self.registered[registeredFireID].random then - self:setRandom(registeredFireID, false) - end - - self.registered[registeredFireID] = nil - - self:saveRegistered() - - return true -end - -function Fire:addFlame(registeredFireID, coords, spread, chance) - if not (registeredFireID and coords and spread and chance and self.registered[registeredFireID]) then - return false - end - - local flameID = highestIndex(self.registered[registeredFireID].flames) + 1 - - self.registered[registeredFireID].flames[flameID] = {} - self.registered[registeredFireID].flames[flameID].coords = coords - self.registered[registeredFireID].flames[flameID].spread = spread - self.registered[registeredFireID].flames[flameID].chance = chance - - self:saveRegistered() - - return flameID -end - -function Fire:deleteFlame(registeredFireID, flameID) - if not (self.registered[registeredFireID] and self.registered[registeredFireID].flames[flameID]) then - return false - end - - table.remove(self.registered[registeredFireID].flames, flameID) - - self:saveRegistered() - - return true -end - -function Fire:setRandom(registeredFireID, random) - random = random or nil - registeredFireID = tonumber(registeredFireID) - - if not registeredFireID or not self.registered[registeredFireID] then - return false - end - - self.registered[registeredFireID].random = random - self.random[registeredFireID] = random - - self:saveRegistered() - - return true -end - -function Fire:startSpawner(frequency, chance) - frequency = tonumber(frequency) or Config.Fire.spawner.interval - chance = tonumber(chance) or Config.Fire.spawner.chance - - if self._stopSpawner or not self.random or not frequency then - return false - end - - local spawnerActive = true - - self._stopSpawner = function() - spawnerActive = nil - end - - Citizen.CreateThread( - function() - while spawnerActive do - if next(self.random) and not self.currentRandom and Dispatch:firefighters() >= Config.Fire.spawner.players then - if math.random(100) < chance then - local randomRegisteredFireID = table.random(self.random) - local randomPlayer = Dispatch:getRandomPlayer() - - if randomRegisteredFireID and randomPlayer then - if self:startRegistered(randomRegisteredFireID, true, randomPlayer) then - self.currentRandom = randomRegisteredFireID - end - end - end - end - - Citizen.Wait(frequency) - end - end - ) - - return true -end - -function Fire:stopSpawner() - if self._stopSpawner then - self._stopSpawner() - self._stopSpawner = nil - end -end - --- Saving registered fires - -function Fire:saveRegistered() - saveData(self.registered, "fires") -end - -function Fire:loadRegistered() - local firesFile = loadData("fires") - self.random = {} - if firesFile ~= nil then - for index, fire in pairs(firesFile) do - for _, flame in pairs(fire.flames) do - flame.coords = vector3(flame.coords.x, flame.coords.y, flame.coords.z) - end - if fire.dispatchCoords then - fire.dispatchCoords = vector3(fire.dispatchCoords.x, fire.dispatchCoords.y, fire.dispatchCoords.z) - end - if fire.random == true then - self.random[index] = true - end - end - self.registered = firesFile - else - saveData({}, "fires") - end -end \ No newline at end of file diff --git a/resources/Fire-Script/server/main.lua b/resources/Fire-Script/server/main.lua deleted file mode 100644 index 99443b881..000000000 --- a/resources/Fire-Script/server/main.lua +++ /dev/null @@ -1,598 +0,0 @@ ---================================-- --- FIRE SCRIPT v1.7.6 -- --- by GIMI (+ foregz, Albo1125) -- --- License: GNU GPL 3.0 -- ---================================-- - ---================================-- --- VERSION CHECK -- ---================================-- - -Version = "1.7.6" -LatestVersionFeed = "https://api.github.com/repos/gimicze/firescript/releases/latest" - -Citizen.CreateThread( - checkVersion -) - ---================================-- --- INITIALIZE -- ---================================-- - -function onResourceStart(resourceName) - if (GetCurrentResourceName() == resourceName) then - Whitelist:load() - Fire:loadRegistered() - if Config.Fire.spawner.enableOnStartup and Config.Fire.spawner.interval then - if not Fire:startSpawner() then - sendMessage(0, "Couldn't start fire spawner.") - end - end - end -end - -RegisterNetEvent('onResourceStart') -AddEventHandler( - 'onResourceStart', - onResourceStart -) - ---================================-- --- CLEAN-UP -- ---================================-- - -function onPlayerDropped() - Whitelist:removePlayer(source) - Dispatch:unsubscribe(source) -end - -RegisterNetEvent('playerDropped') -AddEventHandler( - 'playerDropped', - onPlayerDropped -) - ---================================-- --- COMMANDS -- ---================================-- - -RegisterNetEvent('fireManager:command:startfire') -AddEventHandler( - 'fireManager:command:startfire', - function(coords, maxSpread, chance, triggerDispatch, dispatchMessage) - if not Whitelist:isWhitelisted(source, "firescript.start") then - sendMessage(source, "Insufficient permissions.") - return - end - - local _source = source - - local maxSpread = (maxSpread ~= nil and tonumber(maxSpread) ~= nil) and tonumber(maxSpread) or Config.Fire.maximumSpreads - local chance = (chance ~= nil and tonumber(chance) ~= nil) and tonumber(chance) or Config.Fire.fireSpreadChance - - local fireIndex = Fire:create(coords, maxSpread, chance) - - sendMessage(source, "Spawned fire #" .. fireIndex) - - if triggerDispatch then - Citizen.SetTimeout( - Config.Dispatch.timeout, - function() - if Config.Dispatch.enabled and not Config.Dispatch.disableCalls then - if dispatchMessage then - Dispatch:create(dispatchMessage, coords) - else - Dispatch.expectingInfo[_source] = true - TriggerClientEvent('fd:dispatch', _source, coords) - end - end - end - ) - end - end -) - -RegisterNetEvent('fireManager:command:registerscenario') -AddEventHandler( - 'fireManager:command:registerscenario', - function(coords) - if not Whitelist:isWhitelisted(source, "firescript.manage") then - sendMessage(source, "Insufficient permissions.") - return - end - - local registeredFireID = Fire:register(coords) - - sendMessage(source, "Created scenario #" .. registeredFireID) - end -) - -RegisterNetEvent('fireManager:command:addflame') -AddEventHandler( - 'fireManager:command:addflame', - function(registeredFireID, coords, spread, chance) - if not Whitelist:isWhitelisted(source, "firescript.manage") then - sendMessage(source, "Insufficient permissions.") - return - end - - local registeredFireID = tonumber(registeredFireID) - local spread = tonumber(spread) - local chance = tonumber(chance) - - if not (coords and registeredFireID and spread and chance) then - return - end - - local flameID = Fire:addFlame(registeredFireID, coords, spread, chance) - - if not flameID then - sendMessage(source, "No such scenario.") - return - end - - sendMessage(source, "Added flame #" .. flameID) - end -) - -RegisterCommand( - 'stopfire', - function(source, args, rawCommand) - if not Whitelist:isWhitelisted(source, "firescript.stop") then - sendMessage(source, "Insufficient permissions.") - return - end - - local fireIndex = tonumber(args[1]) - - if not fireIndex then - return - end - - if Fire:remove(fireIndex) then - sendMessage(source, "Stopping fire #" .. fireIndex) - TriggerClientEvent("pNotify:SendNotification", source, { - text = "Fire " .. fireIndex .. " going out...", - type = "info", - timeout = 5000, - layout = "centerRight", - queue = "fire" - }) - end - end, - false -) - -RegisterCommand( - 'stopallfires', - function(source, args, rawCommand) - if not Whitelist:isWhitelisted(source, "firescript.stop") then - sendMessage(source, "Insufficient permissions.") - return - end - - Fire:removeAll() - - sendMessage(source, "Stopping fires") - TriggerClientEvent("pNotify:SendNotification", source, { - text = "Fires going out...", - type = "info", - timeout = 5000, - layout = "centerRight", - queue = "fire" - }) - end, - false -) - -RegisterCommand( - 'removeflame', - function(source, args, rawCommand) - if not Whitelist:isWhitelisted(source, "firescript.manage") then - sendMessage(source, "Insufficient permissions.") - return - end - - local registeredFireID = tonumber(args[1]) - local flameID = tonumber(args[2]) - - if not (registeredFireID and flameID) then - return - end - - local success = Fire:deleteFlame(registeredFireID, flameID) - - if not success then - sendMessage(source, "No such fire or flame registered.") - return - end - - sendMessage(source, "Removed flame #" .. flameID) - end, - false -) - -RegisterCommand( - 'removescenario', - function(source, args, rawCommand) - if not Whitelist:isWhitelisted(source, "firescript.manage") then - sendMessage(source, "Insufficient permissions.") - return - end - local registeredFireID = tonumber(args[1]) - if not registeredFireID then - return - end - - local success = Fire:deleteRegistered(registeredFireID) - - if not success then - sendMessage(source, "No such scenario.") - return - end - - sendMessage(source, "Removed scenario #" .. registeredFireID) - end, - false -) - -RegisterCommand( - 'startscenario', - function(source, args, rawCommand) - if not Whitelist:isWhitelisted(source, "firescript.start") then - sendMessage(source, "Insufficient permissions.") - return - end - local _source = source - local registeredFireID = tonumber(args[1]) - local triggerDispatch = args[2] == "true" - - if not registeredFireID then - return - end - - local success = Fire:startRegistered(registeredFireID, triggerDispatch, source) - - if not success then - sendMessage(source, "No such scenario.") - return - end - - sendMessage(source, "Started scenario #" .. registeredFireID) - end, - false -) - -RegisterCommand( - 'stopscenario', - function(source, args, rawCommand) - if not Whitelist:isWhitelisted(source, "firescript.stop") then - sendMessage(source, "Insufficient permissions.") - return - end - local _source = source - local registeredFireID = tonumber(args[1]) - - if not registeredFireID then - return - end - - local success = Fire:stopRegistered(registeredFireID) - - if not success then - sendMessage(source, "No such scenario active.") - return - end - - sendMessage(source, "Stopping scenario #" .. registeredFireID) - - TriggerClientEvent("pNotify:SendNotification", source, { - text = "Fire going out...", - type = "info", - timeout = 5000, - layout = "centerRight", - queue = "fire" - }) - end, - false -) - -RegisterCommand( - 'firewl', - function(source, args, rawCommand) - local _source = source - local action = args[1] - local serverId = tonumber(args[2]) - - if not (action and serverId) or serverId < 1 then - return - end - - local identifier = GetPlayerIdentifier(serverId, 0) - - if not identifier then - sendMessage(source, "Player not online.") - return - end - - if action == "add" then - Whitelist:addPlayer(serverId, identifier) - sendMessage(source, ("Added %s to the whitelist."):format(GetPlayerName(serverId))) - elseif action == "remove" then - Whitelist:removePlayer(serverId, identifier) - sendMessage(source, ("Removed %s from the whitelist."):format(GetPlayerName(serverId))) - else - sendMessage(source, "Invalid action.") - end - end, - true -) - -RegisterCommand( - 'firewlreload', - function(source, args, rawCommand) - Whitelist:load() - sendMessage(source, "Reloaded whitelist from config.") - end, - true -) - -RegisterCommand( - 'firewlsave', - function(source, args, rawCommand) - Whitelist:save() - sendMessage(source, "Saved whitelist.") - end, - true -) - -RegisterCommand( - 'firedispatch', - function(source, args, rawCommand) - local _source = source - local action = args[1] - local serverId = tonumber(args[2]) - - if not (action and serverId) or serverId < 1 then - return - end - - if action == "scenario" then - if not Fire.registered[serverId] then - sendMessage(source, "The specified scenario hasn't been found.") - return - end - - table.remove(args, 1) - table.remove(args, 1) - - Fire.registered[serverId].message = next(args) and table.concat(args, " ") or nil - Fire:saveRegistered() - sendMessage(source, ("Changed scenario's (#%s) dispatch message."):format(serverId)) - else - local identifier = GetPlayerIdentifier(serverId, 0) - - if not identifier then - sendMessage(source, "Player not online.") - return - end - - if action == "add" then - Dispatch:subscribe(serverId, (not args[3] or args[3] ~= "false")) - sendMessage(source, ("Subscribed %s to dispatch."):format(GetPlayerName(serverId))) - elseif action == "remove" then - Dispatch:unsubscribe(serverId, identifier) - sendMessage(source, ("Unsubscribed %s from the dispatch."):format(GetPlayerName(serverId))) - else - sendMessage(source, "Invalid action.") - end - end - end, - true -) - -RegisterCommand( - 'randomfires', - function(source, args, rawCommand) - if not Whitelist:isWhitelisted(source, "firescript.manage") then - sendMessage(source, "Insufficient permissions.") - return - end - - local _source = source - local action = args[1] - local registeredFireID = tonumber(args[2]) - - if not action then - return - end - - if action == "add" then - if not registeredFireID then - sendMessage(source, "Invalid argument (2).") - return - end - Fire:setRandom(registeredFireID, true) - sendMessage(source, ("Set scenario #%s to start randomly."):format(registeredFireID)) - elseif action == "remove" then - if not registeredFireID then - sendMessage(source, "Invalid argument (2).") - return - end - Fire:setRandom(registeredFireID, false) - sendMessage(source, ("Set scenario #%s not to start randomly."):format(registeredFireID)) - elseif action == "disable" then - Fire:stopSpawner() - sendMessage(source, "Disabled random fire spawn.") - elseif action == "enable" then - Fire:startSpawner() - sendMessage(source, "Enabled random fire spawn.") - else - sendMessage(source, "Invalid action.") - end - end, - false -) - ---================================-- --- FIRE SYNC -- ---================================-- - -RegisterNetEvent('fireManager:requestSync') -AddEventHandler( - 'fireManager:requestSync', - function() - if source > 0 then - TriggerClientEvent('fireClient:synchronizeFlames', source, Fire.active) - end - end -) - -RegisterNetEvent('fireManager:createFlame') -AddEventHandler( - 'fireManager:createFlame', - function(fireIndex, coords) - Fire:createFlame(fireIndex, coords) - end -) - -RegisterNetEvent('fireManager:createFire') -AddEventHandler( - 'fireManager:createFire', - function() - Fire:create(coords, maximumSpread, spreadChance) - end -) - -RegisterNetEvent('fireManager:removeFire') -AddEventHandler( - 'fireManager:removeFire', - function(fireIndex) - Fire:remove(fireIndex) - end -) - -RegisterNetEvent('fireManager:removeAllFires') -AddEventHandler( - 'fireManager:removeAllFires', - function() - Fire:removeAll() - end -) - -RegisterNetEvent('fireManager:removeFlame') -AddEventHandler( - 'fireManager:removeFlame', - function(fireIndex, flameIndex) - Fire:removeFlame(fireIndex, flameIndex) - end -) - ---================================-- --- DISPATCH -- ---================================-- - -RegisterNetEvent('fireDispatch:registerPlayer') -AddEventHandler( - 'fireDispatch:registerPlayer', - function(playerSource, isFirefighter) - source = tonumber(source) - playerSource = tonumber(playerSource) - if (source and source > 0) or not playerSource or playerSource < 0 then - return - end - - Dispatch:subscribe(playerSource, not (isFirefighter)) - end -) - -RegisterNetEvent('fireDispatch:removePlayer') -AddEventHandler( - 'fireDispatch:removePlayer', - function(playerSource) - source = tonumber(source) - playerSource = tonumber(playerSource) - if (source and source > 0) or not playerSource or playerSource < 0 then - return - end - - Dispatch:subscribe(playerSource) - end -) - -RegisterNetEvent('fireDispatch:create') -AddEventHandler( - 'fireDispatch:create', - function(text, coords) - if not Config.Dispatch.disableCalls and (source < 1 or Dispatch.expectingInfo[source]) then - Dispatch:create(text, coords) - if source > 0 then - Dispatch.expectingInfo[source] = nil - end - end - end -) - ---================================-- --- WHITELIST -- ---================================-- - -RegisterNetEvent('fireManager:checkWhitelist') -AddEventHandler( - 'fireManager:checkWhitelist', - function(serverId) - if serverId then - source = tonumber(serverId) or source - end - - Whitelist:check(source) - end -) - ---================================-- --- AUTO-SUBSCRIBE -- ---================================-- - -if Config.Dispatch.enabled and Config.Dispatch.enableESX then - ESX = nil - - TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) - - local allowedJobs = {} - local firefighterJobs = Config.Fire.spawner.firefighterJobs or {} - - if type(Config.Dispatch.enableESX) == "table" then - for k, v in pairs(Config.Dispatch.enableESX) do - allowedJobs[v] = true - end - else - allowedJobs[Config.Dispatch.enableESX] = true - firefighterJobs[Config.Dispatch.enableESX] = true - end - - RegisterNetEvent("esx:setJob") - AddEventHandler( - "esx:setJob", - function(source) - local xPlayer = ESX.GetPlayerFromId(source) - - if allowedJobs[xPlayer.job.name] then - Dispatch:subscribe(source, firefighterJobs[xPlayer.job.name]) - else - Dispatch:unsubscribe(source) - end - end - ) - - RegisterNetEvent("esx:playerLoaded") - AddEventHandler( - "esx:playerLoaded", - function(source, xPlayer) - if allowedJobs[xPlayer.job.name] then - Dispatch:subscribe(source, firefighterJobs[xPlayer.job.name]) - else - Dispatch:unsubscribe(source) - end - end - ) -end \ No newline at end of file diff --git a/resources/Fire-Script/server/utils.lua b/resources/Fire-Script/server/utils.lua deleted file mode 100644 index 8a456dd32..000000000 --- a/resources/Fire-Script/server/utils.lua +++ /dev/null @@ -1,120 +0,0 @@ ---================================-- --- FIRE SCRIPT v1.6.3 -- --- by GIMI (+ foregz, Albo1125) -- --- License: GNU GPL 3.0 -- ---================================-- - -function checkVersion() - PerformHttpRequest( - LatestVersionFeed, - function(errorCode, data, headers) - if tonumber(errorCode) == 200 then - data = json.decode(data) - if not data then - print("^3[FireScript]^7 Couldn't check version - no data returned!") - return - end - if data.tag_name == "v" .. Version then - print("^2[FireScript]^7 Up to date.") - else - print(("^3[FireScript]^7 The script isn't up to date! Please update to version %s."):format(data.tag_name)) - end - else - print(("^3[FireScript]^7 Couldn't check version! Error code %s."):format(errorCode)) - print(LatestVersionFeed) - end - end, - 'GET', - '', - { - ['User-Agent'] = ("FireScript v%s"):format(Version) - } - ) -end - --- Chat - -function sendMessage(source, text, customName) - if source > 0 then - TriggerClientEvent( - "chat:addMessage", - source, - { - templateId = "firescript", - args = { - ((customName ~= nil) and customName or ("FireScript v%s"):format(Version)), - text - } - } - ) - else - print(("[FireScript v%s] %s"):format(Version, text)) - end -end - --- Table functions - -function highestIndex(table, fireIndex) - if not table then - return - end - local table = fireIndex ~= nil and table[fireIndex] or table - local index = 0 - local count = 0 - - for k, v in ipairs(table) do - count = count + 1 - if k >= index then - index = k - end - end - - return index, count -end - -function table.length(t) - if not t or type(t) ~= "table" then - return - end - - local count = 0 - - for k, v in pairs(t) do count = count + 1 end - - return count -end - -function table.random(t) - if not t or type(t) ~= "table" or next(t) == nil then - return false - end - - local randomPosition = math.random(1, table.length(t)) - local currentPosition = 0 - local randomKey = nil - - for k, v in pairs(t) do -- Select a random registered fire - currentPosition = currentPosition + 1 - - if currentPosition == randomPosition then - randomKey = k - break - end - end - - return randomKey, t[randomKey] -end - --- JSON config - -function saveData(data, keyword) - if type(keyword) ~= "string" then - return - end - SaveResourceFile(GetCurrentResourceName(), keyword .. ".json", json.encode(data), -1) -end - -function loadData(keyword) - local fileContents = LoadResourceFile(GetCurrentResourceName(), keyword .. ".json") - return fileContents and json.decode(fileContents) or nil -end \ No newline at end of file diff --git a/resources/Fire-Script/server/whitelist.lua b/resources/Fire-Script/server/whitelist.lua deleted file mode 100644 index 4810a742f..000000000 --- a/resources/Fire-Script/server/whitelist.lua +++ /dev/null @@ -1,68 +0,0 @@ ---================================-- --- FIRE SCRIPT v1.6.10 -- --- by GIMI (+ foregz, Albo1125) -- --- License: GNU GPL 3.0 -- ---================================-- - -Whitelist = { - players = {}, - config = {}, - __index = self, - init = function(object) - object = object or {players = {}, config = {}} - setmetatable(object, self) - return object - end -} - -function Whitelist:check(serverId) - if serverId > 0 then - local steamID = GetPlayerIdentifier(serverId, 0) - if self.config[steamID] == true or IsPlayerAceAllowed(serverId, "firescript.all") then - self.players[serverId] = true - elseif self.players[serverId] ~= nil then - self.players[serverId] = nil - end - end -end - -function Whitelist:isWhitelisted(serverId, ace) - ace = tostring(ace) - return (serverId > 0 and (self.players[serverId] == true or (ace and IsPlayerAceAllowed(serverId, ace)))) -end - -function Whitelist:addPlayer(serverId, steamId) - if steamId then - self.config[steamId] = true - Whitelist:save() - end - if serverId then - self.players[serverId] = true - end -end - -function Whitelist:removePlayer(serverId, steamId) - if steamId then - self.config[steamId] = nil - Whitelist:save() - end - if serverId then - self.players[serverId] = nil - end -end - -function Whitelist:load() - local whitelistFile = loadData("whitelist") - if whitelistFile ~= nil then - self.config = whitelistFile - for _, playerId in ipairs(GetPlayers()) do - self:check(tonumber(playerId)) - end - else - saveData({}, "whitelist") - end -end - -function Whitelist:save() - saveData(self.config, "whitelist") -end \ No newline at end of file diff --git a/resources/Fire-Script/whitelist.json b/resources/Fire-Script/whitelist.json deleted file mode 100644 index c48d16cb5..000000000 --- a/resources/Fire-Script/whitelist.json +++ /dev/null @@ -1 +0,0 @@ -{"steam:11000013c64f700":true,"steam:11000014684169a":true,"steam:110000112db6102":true,"steam:1100001698dbf6b":true,"steam:110000131ff8eae":true,"steam:110000147619e76":true,"steam:11000010e6980a7":true} \ No newline at end of file diff --git a/resources/SmartFires/.fxap b/resources/SmartFires/.fxap new file mode 100644 index 0000000000000000000000000000000000000000..ae3ebd1d9cbcd10e8e0c798189f496017864f813 GIT binary patch literal 185 zcmV;q07m~tSV2$$000000Jrvsoi=i*7JyvmfOyJ9;4tRX9?HbsAmlDVm4&=IrHPl` z0VfgD*yT19XCsm`o4#qK=olF1u2%Ex*mXrj1p%wm`J&7K$eRoFGm5NHD0I7c2q1?s zA_wxM;Fa0XrG?t>dakmK2-LaoyJ$$~%Q7BZ!^`Y_-8y&cI0qCySwI8Jx*7^RBF n$$*FtyC+l1!M$#e9Yapco>CpXnBC=|{P+AEOORBz!}OMcW4T_8 literal 0 HcmV?d00001 diff --git a/resources/SmartFires/Documentation.url b/resources/SmartFires/Documentation.url new file mode 100644 index 000000000..80fe48e05 --- /dev/null +++ b/resources/SmartFires/Documentation.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://docs.londonstudios.net/ diff --git a/resources/SmartFires/cl_exports.lua b/resources/SmartFires/cl_exports.lua new file mode 100644 index 000000000..716a66378 --- /dev/null +++ b/resources/SmartFires/cl_exports.lua @@ -0,0 +1,59 @@ +function IsFireNearby(range) + if range == nil then range = 15.0 end + for k, v in pairs(fires) do + local coords = GetEntityCoords(PlayerPedId()) + if v.active then + local distance = #(coords - v.coords) + if distance < range then + return true + end + end + end + return false +end + +exports("IsFireNearby", IsFireNearby) + +function IsSmokeNearby(range) + if range == nil then range = 15.0 end + for k, v in pairs(smoke) do + local coords = GetEntityCoords(PlayerPedId()) + if v.active then + local distance = #(coords - v.coords) + if distance < range then + return true + end + end + end + return false +end + +exports("IsSmokeNearby", IsSmokeNearby) + +-- This will only work if you are using HoseLS (or an alternative hose) +-- This will not work if you are using SmartHose, our paid hose +function SetFoamEnabled(enabled) + foam = enabled +end + +exports("SetFoam", SetFoamEnabled) + +function IsFireStillActive(id) + if fires[id] ~= nil then + return true + end +end + +exports("IsFireStillActive", IsFireStillActive) + +function GetAllFires() + return fires +end + +exports("GetAllFires", GetAllFires) + +function GetAllSmokes() + return smoke +end + +exports("GetAllSmokes", GetAllSmokes) \ No newline at end of file diff --git a/resources/SmartFires/cl_smartfires.lua b/resources/SmartFires/cl_smartfires.lua new file mode 100644 index 0000000000000000000000000000000000000000..f43ec7dd6be4b1e4e637bad79ac434d4dac2f1da GIT binary patch literal 24102 zcmV(oK=HpuSV2$$000000K~Gr_!YupPjO*Q7Ui_mC9dmEINA5X?!{L|bc_WhkA9-@ zfQPh#-j#A-{;?u`Lht(MlwvhD$gjZY@frKm0FHeF;V}^tH5{^G^U|c~)_`LLZjPdb zau2I+v#?XtuFNM}C2O`1V~m5fjapNEn=IoJS*Yc|$OS}4IUWP>o@i}!#LC1BeO9gP zDc28DP$N5^W+PkIQ`7!G)RHJ_sP-{wII z%J2ENi*-05KBc89mxcMC;K{*Gvh+ff)-LInaIZtSG?lu@*jP0h#ngl0Z5Vw?nRv!8WSFGecU82&M&36cGV! z(`+-NMWM0_#=hg+cQe?I=Kk0ccw6O>0r7^vJo^u@;0*IqjIi~I1;&RWP(wwfIkPGS zXwo%S9Fjur_kEicdr0`H>n@AL^xLM_gzSlHz5Vbyk^bD;C_Yiv#~~cy^HlFhc`J1* zl^hvm%x@97QU!&;>8?zrYicz01R<|Sp38l1hoSUmsCN7fjjmK6p-(!nA!uunFo!JA z@vA^Qs;E>~vM2b~;h3ud&QK4!wKY>9Z~CE($Wj$ITNDWHrsc3$Ap@bXSl?(!;9he- zl?FdirP$8*N@3ef*OD3;+)NWUj0ZAdwBklUSg^I@IzFO=4)#MA9*K~z{$wryX3_kh zbx4?JSTqof^apjT-r#qDI1O<}t;7RK!m|S*vFn;1_@uS$D}Xhlsgt*V51lU)@0JhcqNYz~L90WBn%+{DJ zl~d0tN($IGktEd~&U`%KNf$I8$TEWG z)|Xy8UWPkQ`0)n|OUnAY7;{OHeDf?cEtW&5i@*{R$MKQEnjz z)Q4U&j2zx7z_WAiz2Nif@3){mzbp__Dg>!vOpZi)cjDj+cTCN6@_^FUEup+qIHa z?g^x#pdJp`F1#^TE;T8g4U`}V)QbfSTe5b^Y+pxP*=?0Z4$}AtwJ}=t{@?R8UoMOe+prA{z#yD39ps=1gX{|n}j7*dJ z(ouK5_#E9&ef>UTC#cs9V%9G!La}2BpG*NTHU2*NS%{G@=J`M7hp0?VeiW)Yven2* z|K_oPWKbcQhfB`IadA9$#veB}+?=D8KNa86^0D-orb0!^X>h0APdX^T^Yh~-EKiL6 zl409ErPe;JIkmV|s#CONK349&tS#?CcTa;iVDd3EUw`?AdNlmVS9aV2ylHE70S%x8?+bsjJ0wj`0v0RMeQ8Qf@{V0|jq z)arCC2t}{r=4Bz|*xiN7oNHr=+yt+6@~qatRW>C!ov(nm&4*pIVk>SB#UQe@_3&tQ z=oMX1oSD>o_Dmk)YwF@5gv|2nJt|xk#s(H(j|xMb7dNfp0j39g zRbiO(L7h_Vg5Mvh@2gO#jac2WEBO5H1Y-~1uaGY0_iLDf=q%PN^Yen#5^*;u#_Yi{ zyd}1h6^xQ@ThfW0K`V(7ZQ26Tt7pZtqu=SH*-0bFd(uSRATVR`rUEG$hh4?c-BG0} zz*o_-`ZVDtobZOg0-&N$SL+eBB~16kj2mjA2I72Ayxy#wf2s>c!>DptY~>4-=#7a* ztVf>RqDG;|pTO1%r|fidEx{JNO3|-+!a)bmxJ^i$S;=XE?DBjjIF~yUi3AOgQ)df8^1Am4{AOKoxfGZ|`|_-pj;>`~`UlC4EAJ+qCp+?fYaH zy-pYF$DX@cQwBQzIPRqU(2UR`s9E{c_jw!tn*;2n-h60kqupF$8C0``P81_-LgC#P z=7946qa8FKg-A>j_V28%vJf9G5@D8jt>^K(`UHLf;1S+Ax6k=!me+QxKT0v3NWD!9 zG{Va(D^x&GYoaWzxt+ngu!KLsU(1(Oe!gCHmD5r%s9y6L=xij3Ssj#bjr0P@=R)^< z0gPoVj%u=1IK<|5y$oDR4<=FS7YNbdYwexaL$ZA~YXkrGU0^M}O$r%;mR`>>%R;zc z0EIsK4&;`CB*rxHx?b!^)yo;u!4iS%zRuQU*y#{2$!)U}a1?h@-JIkrT@wqHqt={D zl96)JyFlIF7*XNm=w_Bb{`#3wq*k#=fep9|U>F%)U|mPH-@{ffjzrH{Y`y(p5K1oU z0?*!UxP=Q&O}ufUC$jkLkt!Hfov2T09Qpf=tvV*q%Ja>!aVeA1v|bVcF*RY+uXym~ zX1ZkSIGJj@+9Fe2%KSniq_An4T0BO9chi#xtne|1#=1{pM)oZvY?Y}wztWqF3xqb< zL63H;nf*wzsg+Ut)Ki5d56Ju{3`IZr)txR)>hn_)#Dal%haUlkCuqQ(*0?rXPQ{?x z8cS5*^wd<`4j-%YM7;6mc<+1_{#F%Gza1 zA|cU@=NyT}{rzDPn^CNlk$K_#KuvV5cEVcgKrV3r)Pu>e&Cldm$gx66OHAbgOaAv|mBtI6I?^rA$38m%(A5~kZG=PNLD{`ro-Gv@j6 z_;D$*w&k6bucj$2{&?x$=rgOtzS_sT4dW$h$ispB*1U0R_hP~ogu{wA-=1@|Ke2lf znksWYWf>lfa(6h}1bPK$_wF}VfqH(97EVl#*?16JE~&&+Qy{%xgyFCo&KjymkJtTf zx|eHz$r)UY0xSdYy1_7`?_7GlWwOGp(#X+vl&(29l2DY&Hh2ps1NIQS!{WV3+=DW{52S1)7v zqG-y)@4*EcH7z$Ii4pqo7V_7UuwMub8}kb2G`HA7DmOsJC^$jXygdH4A zj)ziLWjR6itkk-3mdxP9o;p6@ zQTyM6%>Rss8|pobX~k1{W@l2~znYiIk1u>G_`=xIGm35;xcV zUv&?{6rIyy+mBdbuU7dCMYULkf)Aa^mAtS#LY<~w#CsB zIfCDLpL_gt(#+WoVo8QHd3t=OuPtdt9kP#Rs&T{?d^+--D=M5q3jd6u1D4IwK)=zz z0aeE5U-XwE_PXTH8(eb9Q4@i9&#nL{$W(Q=f%kAEtA$8)|KF=xn76dJr+gW4tSLb zc*rMLSK6)9OH%)ht-0w26Z`aU+r26pzigZ{p9Uv9rB_P80=iI_i=J5bs-`I28X;Ln za^-eI1>yyw@vn@@rB;DE(V3;Ok8h`&S*gy)C_Q*6;vcVFBm?#MdRy($PVc6Qh!jPzg=*fdUJ_ zH2Go{aH3>e%r~FHRwt{kU{{}OAj-J{?j7BD46;IF`dgCTi_%g(VjDcB_cu-a?9)n* zc#EEiH3Gc`XEVRbwEuKpSX|Me!=En>=P#al^psmyc!FbN$mHoZ_xM+~=AHeoL-M#D zR>8!6bAD4i$0HgsJV2H-t>)(aD{r4d-yD4|x?LuL9&at-+fg=3!PV2*&~xJH=Ivq` z>c-9xkrmv77qiLxx9&HzS=oLw&&C-G!6F7%)}(*%-QMf%w1uY3-e(Fd810Bwawd&V zC%yYQj}IxK0e){*2tn)dHFFY}0F$SS&V31p{(tKbW3WO8-rAyTstBoyq@+KE!PB=Xq%@*;6=BvI zYbpI~IZ?KR$|tyQ`$EI|{h^OWJtO-pUQ6e09RkLDlWLk&`XW~WR|i^Jgkkw)MkZWEIG{g_S)sUEp{JvJ?^y%2032Gmkl29Y|Z@wSpDqmBecU zc33R-p}BFk*_@z3ezqbtuiME+hZNX|ZGmJ-vsAJ-j{AK-NU^_Gs#{EE0a3N)->p?5 zK}Ot$Fja0*x$!SoK~2-`axIVSkUo6poLl*yC87l)l*Aod^r7H4IYf0--z{pE;glcfeIzt^@k+sIX;u^1H*&3tqLjX%4WiCKCGa zetRw(GGQ8gMEVcXPHy!~lbv8-Fb^rL6LgyC<`K8k(B8wi-j0AynA_)vH9d#3t{-aD z7t&|c(pmJ(E_sH88a|$3x_m01yPSdJ@6i>FA#dnHUi! zeU0Fk+B6046od(N1DP#U--Pn`bJl5PqyDRPwOuK5h_uUk(>IWH+)%Dk^=^`Ago^!% zbAq2euQRUV)@6=nV_kp>bJmgY&?#M5h*IDyKo%rJYtDaOwR=k$yZoht&E=$^l zeV>vf%QUP+7uS}jsadCtC262(L)SehL8aw!_+tv@&jIL(`eK~BO5aKP*N> zzfJSsX0reoSw2(h^%jW9>un?Zs4s3R0o@jzE?oA*R?HSR> z*u%_Fszo9jJBAalrB;|GX1Ei=)w+c?&|ecNXnsd0Svv*2=8IT@b!b6nX!-c!H{V;u zl*HNZN6%1~=Hnpm#yR*@=-Bkx=uCMWK_g9(f+X(!P*z2t;<{K|8_J^>Q{0xIUlP!s)7(>3#!%3E#QRs~1LOyW@+*Ra7;9+o*_Mu}jbctQg_NN~4z zBhPXsMr=~xkR&X3>%hN;hofB}X)(jIfo$jnVEugEvM~6ziRZN4kldvHPUXnKoXP>8 zEebN6dy*XG*>(jzcKV!CJQ?PGW*W#!c38?)?`r$p%^B=UVXEGS%SQIk{eHNh!p3jG zEtKT0uQ2=Bi%O7+lFswr^&cSbZx5<8~wEhw;HAPoDq&}JCx#oI*Tn$K1~+% z5m<7>$|#Z81BzGX@^CKCyT>v2sp6)pOmnF0J<%W$u3{^A@Y^0Chg$*I3!>GUk5hm&Yt_DG`Wg-lW zn#XZNx(^r_|CJ7I;7Vr!KEr6vS6ajZj~9_wrAvJXI_|$lWxE3vSR*$j0NC73e!$po z5eh{in!NE?*n|FxLBe4*A~{Nxmh z8A&kUBgDe!R(l`0lv(Al$S^z#*_YO7~|KV@c_xr#{ z)eB-;L=jjB_NL5)@PEctkrw;Kg^=ei%^vJ3od&v!1f9FL;A>2mMvtT}BgeY3{_+!#Fid2p92(h1(^|ACitC z)BGJ{xM)V_kIXtW7!~ElFtKnwu{+z4b| zARN9cnXH|YJIYwKwmtE@gDYwE#aC8vPPAWSbuXxN-+uaj^rgsEa1U>RYhv=mbY=dW z_WON{hY)-#Nr5_qM~v11eCI^xTRBOxaeVwbQHf_T)CM?W0D}2pGE~`JB2qN(37Dh2 zwvKP?@p{Xci~Jz3+hN1r(1KvA&P5zV{`5D*^lv)acX0hbPe%CUj6f>`Ukwvo5Z^sV z$xH7dzrW)q9tGe^prTiz!9OYeV8I*hAc!2A4~s92S%aB)LXe0f_G-^rrd4)BmxHIl zzv$l?V9$1N8kMOYDU$;d^W;_`J@7wtCEogF&{-FHO6MEFppA{%APslq8k_vbaAUX_u; z)=+D6K>r+HJcj1|U<!M8CdIWQ8J(&w=NvZpbyMcs14@h3j0PrTZriwn(a)GsSi zvuek2`uBh#W!PJB{iiJ?6w@?7!P>G&<~d8N-kp}rwc*@TU|2 zrN|GGxsig(*rZ4zlNGd=s{{lpFO^5F^G zcof{?oy-mq6XkM9lu>%ksJ~EA*m1Y0N^X)g1mRE0@4uwc>nb|m5I%}4N4a+!CAm(m zc~bK1|3nBDDo7Um_0gJf=_Q<$Eq^G6`g_|}Tp{z_Dj?fScJar;d^rV(n!X1@ zNXtiX+>)-~^e4FI8A-{t9whbs%sD9VZ0W-MO>uKU$fz3$jmYBR?J+$n{AEVu4fWVZ zl;157NI5*q3;mLMtv6*s=5BG4nDLFFv+yd|j~``2h3u+iWa5f)V;ZU1q^$sC4OHgg zTcRE*WEE0?PxRhu%E3tA{YAiMj%c@GCB?3lq3?nc|DmjCKCz)#s4E97E9=UpE*xVM z^O(|)Bj3+r*b2OZy!`E%>o_t$NY0c?cWL*l-0=?%C7w<=CXeeSJ)L_LF_u#OiY5?- zLBzn3<<Vx+F%ik zeeX+cYHGy>po7rM;%3r?WFZs{e-Si+~1kW#J!no%ZBd_V0RAql%Z_F|snA!35*t zegbjQs*-V9eby&)J;_)K!y35{>v-u~s5`JRF+KR}^Pmt8la`a>v;BV%bJd)#WRtg> zlyaA#Ob3{|prl#lx5ZVAZVj+{e1eWgkY1A*;uNsd21M4Zs82H6Sv*+xn(nv=ypSub z5j*QNgZSHZfISk)UJxqeI)-7^D2zgh&O?nF+`%yl`|XkJkK1hiZxKGaVFwxKz(PG> zPi3J-Ha8}7Y4vBV0Gyx^5oE{j`Ly!qUAa3C(;?H22CEy@*$=s@da4oqIT9LR zj)oVj?!Di8yn69wk9hUxeCmaBRyT8n%|z6mokD)PDQg0MJd|w;pL=>Y`Q+on6xJ%~ z(_|Ech95IV*!|%!KE(;1OoPSfoxxH2qg^OCqW2J&;=2)RwodcHBr`KW)`%obvu|>! z-J6uFHz@4Q4k-t~xvKcL&SWwE3qq7Dhy~4q12bB$H>brCK5Gx|u;|*NS2jwTzwQ9L zphIk018u;~CnL&F&YvdB4|F%Hpf@%GHbr3ptnconGv_;xpLXLH;Q9;(LdL!`T>Pzy zfn-6-nIA2WEUHd8bNTEr`nMs2S-LON4v>;npykTp@s?&@M$#W7e0Ge8RdcJ|NYgAc zV+{a2JIkr@(zuGlPphZ3#m#E$=p(=&CR{FuCdh^QsvrjHW;OWPPYud<)`)MevPwf` z3HAHSlP=h=LrcX4m|=}8)HTYtaO*H-6Y(k9_}vVaN)3N+h5qCfhg^mn$X{{%O==|X zuL_DIhWG}fNm_?W;f<^z2)HZXb0Uv1ty7r_8etF z4A`#vj|Sd#92$5%er?(lj$KgXsXtT$8lf??yU}_E&g^u23CK|&DZP_LY+3NkfSQt% zTs$~El3A2mF|YG=-r34Xab1FX4kpKJ z0^vh%BxFtoFDEhpba6|E`ZFcJT7S|yB$s#M{ts+wVdu& zenr%46L(%DbF4_RsI^3r={E#O1W5c{n>HG)QKxg0<7A_s4SJd?#(d(*Q86YX8~rQz zHu|z~JAlF`E|7Z}Jg{6q3MQ4fzY;!|0(8Au?HgP%*?L2e`Ue12`Sz1ofF%LwC7cm6 z0_pWPP*^%RAWI{v*ZAC`^2SLgRoFLqi`Vd|WAU3{hJ0?i2< z^T73c%w}@C%D}3pf6T4ZMtSora*)`qwXotPcS8PZ`w~3~;RExJMMqE9CbyUCX%D*rTh_i5$3=Fjf$~ z3L8P-S~Hb4JIb75V=6}Dk0B4tx75CPXNA;(&>FnyyzsQIckL=9T!GuHUlAI?@^E9G z9w^PgXOk|79^kMmUW8Wb#t{C*Ull0)}22dTDA z_AR`A=z5rQ)tV=v*u@$SHEDHUQ5xKX1>LrrHjAL%d>Kg?X1wLJ6hNZ#=>FPLQl*ZP zO_ExtF*b8XwH|GRJ>X3;nN-rJdP7-9OZ}g+zF6sDaCx+{`GA z62zt={&kkxe#s)2%ft<1U%tK(2e&pKSXfQ14jS1}&2||qEZFLg73;sQlq_v9GM!rR ze(Nn?>{tb*W5mQgqIUt+3Ll^$O2OWmtJlR~PM5<9^21K z3D3A>r2pjK8YPfbYJI$YGhblWi&8Y1_n!pNdhp~*2A8s>_U*0a#}9sx(e|6zNE*Q( zGcm!62mX;hL$%1FU>a!(?SZSjJtBS)gE?|JqV8hHnYH|frAm%2o*+wwfVApvx*zC` z7AZ7~!8@OmV19qbSgAk33x|ta_4(dW$$h-%0GDW$u_ebuDS+tIcx+@Y2fJ znvtHpkWU=7iKrKiBCbN40?E`=MAF(E#s7JeL8NlIk8|H;zXFe$$nP1*U*Q^u^tgJO z{lzhWjphrBw?4*-;-fSI|6II|!ezW~8WmYPnTY(wa|P+_MQ0@d#7Ar+06VjX$3&^P z3&91Aw>GEyz?z#nj0A=KQyDz}9?)en;P=QP9WSBIIdNeP}sx$ya@+;$rlEb;bR zPtoM(1sT^rDx9+hSnbRvO+5h6Y0mj2Bxd!|U_gJ3XMoRBvVS#gD|nJR(1{?J;^vgE zRwX={O7I(e*T%NtvMX+6oV!;<58naHU6|kI#S|^NsfBJn#!VkQZ=!EDv zd(*+dZg)B0p)1Q`vy;uv;5r8?IWG;VQUG3Vd2Wu|Me49y!IvLTfj;LBs7-9Z)@#4- zIKR~`-x*JWHbSd36^aqxL@~_(0hD6F6sT63tB-KLc=e@+C68ytjV`R(Uuz2Q`h@(d zQ{FB|CdVdv8Lpn9*SKA8$*2QIQ(j90+;H<6CfpIRH_^gK7qaxD?UnBNUbjN>R3amX zT42-SoJafbbhopXLvu4n{o#xx&*?SfJKv|Yiu;97nUW7fUlBEz@sP$X{Y!0CD^B>& z&QKUPa)8aX4&#XwUwj(|2J|hlwmFGBj@;zpxLS=VTC;Md3z@xnQ0U_xho^&kds%c> z4QazspI>aFCws9(bg5h^y8^{tefGxr3fk4j6=#gE=P(;Kqyecb?r@IRE!eewA;b*! zF67Vr5v3!3xFF240eG2@hOJTzsioZ7ZWYu<1vo`_|072gdMYA67`VXye;8<;s%IP! zgnd87sbt%^4jb4T+jC185Xx!q!V(MvQufK9*4SB)9SM8X15kzp z3~W%_kh;hqzSx}g2gGNT6418<|C2 zh9plrB=)Xdkjuz`gmz{6)CcP4O^}Ge$?DIHjwJ+6^QFt_B^NP-Wo5Sjd@^~HpU2gK zs8&)H%yDgP)K49XlqilhKKe01mIUI0Kv!D)HH9U6@G<4c8G0s?r>>L66k+E0w;boyq>XcjSS z+$H^{U!l3RmlOfn%sPzTTuEg!k#X~J7;UxNz{ANa%f%j>V~72i;)m4Jvh0;euT6T2 zTyZL%arNnZ^IWphJv;e)ROQ%Ns0G2iyx6!$pl3=CFA_&u98e1E;+I~eXwMR@M$2dv z{+6(_ryKOI^IqN4Ie3UeesS_lCBKw&rCd0Ik?T_&O&KA6nX-615iD>{QHZ+;gyAyH zwN5)|+LiF+rA2FSb0%EmvybNK{i!ySpEQOJ6FG0;L)2z4B`d(~Yd)vMx#~ReuBx;H zBZ}OE8IHN&A02J9z+%tH)G?_V31Z}LeCDssDVd}1*WO-TA& zJLQ@=x2EnjT(-)V+n;C-x>Tgda*?Vdksu-%{EET-N0u-cM0?r5P|g}=<}W7&7yld( zEo6HD&AAf||oK(=sqEGMAd`P)5+erce*mN{oqwG znN=q#$+Qrn0F?~03UoNBLw$p}yz3<*nRU8PiZGo%b&EnnKE~EF@^zErG+;Uq;EI0f z`FLa%PQ{8brwghMwnFLTvx!d%h)KL=ph)1Zd^|GM_fW?k+BfdXW|Ik;$)D~h)9|Y{ zjaGlhh4uH=Be}_(H{o^K2!)~=&bizXfg8!tq9Bv&0bDB30k9p+vZJ*jwDDTG_n216 z1I}?}Z(nqZ6Vg!y&1dG_6gz#BXZLPQ-}-0C4YW87F3ly7WiphIAah(w2%hf*0qycV z#s~7|MX2eR|5PBAQ_GN45etGbt#XaE}L`9nDf#|(qa1agdhM+pY7dU zeGUa+1eRD(#urTq|2Ft8+@uu=a8!cRXnICVEh;ytf;~V!xnjpXvibIGXpO{*)KLlWZ+sc5Dxyk45o+Ib* zQ~EhKpZMk)9DD(iO-}`{@Ky}A+(ohCR{)i*ee7*9N$5JzY_QTbx4^(Duh|?gnuvrU zYEr|(ij;I#2by1a&WBT?R*Z`hDsY${oQk=kHq*-$z0!=(ycec61(#@gwtV|8&DWEF ztdIDr&^F?8NEFxRu!}Acb02_BMUxJ>v5@&z`1k_Dy+3dR%8qq;TABW?)0iN!Q&8&; zPeGh3c6SQ;5h`WW(lUgy$=6}tFA)o0FQ@nmeh;p4>-D6#&$yvDhKy+~u|sTMi#xk7^XYCFt{j^6V?RdritCsKm7^M?Rs$1o zdcqPxHM7Gose&#@@-mq{)lF|Kpu7g(MLY|YG=`QGkN!gzSiD-k3@2Ozcl4OTHVSaZ z5=NKm`M%C|wusc_cdSVR z$9W^Cvz<$hD_Mt6K=w}SDEiVE9`Ig8Oof8asO}F+kT||3Gd6Od%cJrvtu&6G7n?&L zAYoSSb#9RNwC~i7TiJq+eBkJXv`ee`*Uck62ILc4l>+wW)`wb3aW3`8nQ>8Dw{EeY0CjTS39J5t>R0#TEu zEg4{x+yVGG;e%#;qZ>Dyz9d&#B((E$+SvBI2O;4#pxU1;^%q5|Bj55dN+AWhmY58v`9)y-DMxeB9lI-K zd8TQv2d^ra#XxVgyC9Z)0Q_>b-v7TQ=Xq6uxZIEobS2OuU0M^>ou4$HdAf6Q5d=PBj=mUf^1at z0(#m-2^T#Kw;n>ZfvMTC%|~qmfVj;9ew0>>fBdSmDzxF(WPCyLu-^}_-Xf-T?C56* zg?tTI!Ek;-^w}{?Z4Z6?6-@i==TI-?W1x~nsfTQI@2`Qno%1O#H`BHqGB43dJfWeD zP?;!lL)5%83a!PomK{b^bnbzg%5k9j7ZYy_|N2j`KF&x+YC0UpqsO>4(vfA*6$4Cq zKl-fHZ#hx2Geuw>LU89dP=pmoN_AQtSHE4;ynq=sxtDTM;MCeuUf z56*h;_J^fsPVXze-SL_Bx^ghvW`VS#dLz`Y>l3Oa`&X);E;W&L!nk*;zNY)(^4S;m z*;Fk^?jBE%Hnby~aB1!=gaN6_q`3-if~p9}Gsza4EG&F0I!3PLxiXo`IJ%yDFfyV%Al@o-;+i zdpRXlE2#S|H9*xGePurAFN)XyL>%4nTpqe1Hf*!IjTiN}&sDd38A2gN<3-obw46fy zz*p+iTSyD-^Rv+z92B86GX^m=%Q`BJRd!Qk-7b?|Ng>$UfougU@1@ji3I;MIDOzgw zR7@4@U6Uu{_AG!_!>%F-26N%6=CuSTRcZLUFM~@gPx7=m^OvSrt`z^*E%4)oWPbcg zFZD?|ig4onarN>3|J$zX7+acKb!fQh*nRa=r*7#av|sOI{b1zjp7AG}8n{Q@mZ#ub zgp{Z{UR)yh8!oC-`eZ|VuIQ;I)EBjTlrgp9V)3`ES#oKgo3d0V;(LZj`ohr4>5#@9 zfD-E0A-(m?%uZ0q<#l;2*jt;u6znRtCV4O+S{(-m$#fdTBFXY39_gsQ z#+qNu(-j?3P!obf<^@CD`xNSt?vfK^cg4@41c&d3aR%wZo}pmk-1?tPlmW7##K{V^ zDf4Yyqjw?j0R7Q9%&9_3$g`VQv>C&Rl2vkcOeeV`RdZOY%o$DwP$h)xt5Xbjcl~lD%{~9FKyo&_g&3Z2bV@|jjzrCG9J2;1 zq)l*PsbYM4#4K1qyzTQ}H8$sSVdYE=ajY z4n~%KGb)sa7Km?1P6eZh4sU8m92vIhz-ugNPp=615 z=!o#Z!|a?}k#%lnUqlZm4wh2>#XuI<8`C(Z9@?Y2+j>1CJ^{hr?1od;Wd^f4ClWE*ABlB!5*h z+0hNC^5IjUk*F3}Hz#|~HoDke0TPa*4sJ^NiVRur2aX39yAckoP>T5~LS}Unwat>U zw~uJCK-k*r8q?^qbaFAMuKso+0{oa~=bWpwvDScJR(K}{B_&Wg*VIV%(2Ag#nk1sd z8Ex~5MHmvyF6A^gO;@6IkSME@;S%Ti!;dT0V4V{62*hM`;h|DR${7l(s|+$YUp_CO z5%|%!%bXbBis^X*7wD~98-GyhG*z0U`N{xYeK72{7bp5vWGL(^>En6|7`Zo#6$$f- zjzw;!4VV687&O^K$5xlm4U5R;5%@v$>{!$pbbr;O;GNY<u`cETTt$#vi->gZg$nS1x&2m~Qhx(tDOkt^Ba=Tp=48zU&U;DE|H_E$TH<}}YG-$^$=tcg9FpD@+<=M%Q7X5|;75a_SDlOD3kg;) z!%3V_^P8Zefo>mb{Vpzlr_>T;m;m1KBfWys?(`OCd6rb(_k{IpJnavyp&pRQ3dS&q z#NtSboS}+UaXK(G09bC;&FCyS){eDCF1lQP)xShBixd1mWnVS2H5L_w1hYhr_Ld&$ zl}3tx+c26rZ!kXH-otkv84AAx=B;-`^^)XEAuB{!8_C}STGrGtzX0yGc59Im2CqDS zwf+M~Qguq#Pf#^Fh!%rjVvAlAPU>jQ7)UHk#vQQ@L7Y2?C-r8~O!L9v*|326zSR_!$iV8@3S+4K!;*$U06T`M&L1uWPD z2HYXHAhT6Z!A$Z<%iDbeJf5HDXpNM5c+BRRUZ*RH__8YN9#HX;dQT5WbieWJMlecc zW7p;+NJYl-Ut79?O9}szeFo+WVEacIaV!}kOgy7x>V`7Y+R^NX+&*fML<1sPzwa$J zaOrhD!UTHrBB@xw&OZ*@Af#g)t6rl%Vj#5$c2E(`gZOl}Z@x==}( zcl5$S6RQ-J>xfgGEw@luBNex>>%EVK!M59RzOfCdbEnuKCJ?Nd`+3w8Ip<9~?sDk= zmz;F!J`QdPWDS0&l%ytZSEH^72=Ll(;OK>pLHznMPl})miilYjXo`yE4>W4VA3}GX za9R}4_w`tAbmq%AMlcm65QsWtwfhv3CQ%4)g9|C<>h?%jSx6_(J?L1XbW#m?AU^{E zutqvs8;hsTt_i+5O<_LUBYU4wIv&gZEke=#G~``+jan36w6TXd1%T%C&Q z(vpLgiN?;I;Ot|9{Q(Ksc*=j0JOHws3TJMM=Bqs#-l0%3q1}FoGC?EO z?QF6b0I@`Ju(12H%Zn*jDWcU$Zn|!K-sMy=P@IcwH%M# z_jNSQoxNLa112|Z7<8$dTq1gG!8*Ui3kvH0hodrFu^=H(2wm4X44q@vSK{5eBjuX* z^`X?*%vnm7H{1d(jsjkOv=*}ic7ZGVI{_FT=iz%eLY3J4V!X@x!^2xRR4pzH6v!;Z z28skO?RadVj5uU2%fB;cAFL7(>z<~{OSXaGG}I|2bvq4&z;rsX*t3muMCB&`G5*~y z8PQ&i4=>jv%r`7k)vlfb)hH5_R&hE$!Q_VbJcbUx%}@8@Jp4#`LK`Ft!5GSUTnwZ9 zrzHA!T=*`QSnKz?Q*}sip;;oVfMfQN^ZEC|)+m!T%rJ0qRu}{*{eo@0n+=PVki`4s{4+d@x*}P?u}#@HF|)~u1pjYy^&u6^Kw4ZYJq-~=GSvVLwZ|X z0o5h~rVvW$iwNUJDN)GKbU& zjB-xDad*NHZ9a#S#fh&t0i`A7!?c>mqIV`P?HTF?DY!s47SA2fjK@p4i5mc%9{+J6 zznIaGTq_GaA=-PC71#S*A9T%J5AUVGnh7Sd2pLT`HZzYx+X3H}oE?HQ^K{pV%X)%M zkZ5(~q)VNf2mTwdAh&x9kgtbCM=K-tONgpuJw^IY5A`u`@5B zw?x%KROAF1ZzBh%9y<$^#zW@~phw~v4V7w^vuUoV=< z)}o5joOu$lo!OQqtSI21H+tXC;HjSMHccZ5x}I4a7$cvFo8V*XhNtJ(LhOhS2k%cL zW#HTZ64a!W?%7Q!|C^VYKyaU`kIY*xcfIVffr<-Px^bbJk8%)sQv;Y3*Gm4S6OF8J zb&Ib9pOb(`ikD_05inXy7n+$+-K$OYf75rin=UckBFfJCWuPl7ejG4jVLde*Ob+Fj zl(}CHbi4mY?Dvuv4T^N_L+!F`Xb4mAWwnNi?127ImJuS7O&Xz|!sF zAR+m}DKbPTbQlo}^Q&m|ily?+ZHxLfC|MTh00**6K5nya9E4^#j$(4Ea=xNjSqYZU zO!1LXgx;*n+FVCYiXjbO`{SU2L-$R)ur;B_Y|Ma;X7{gD!EnzC zz6#l0x{?pS7UxdM>_7#?wBGl6c~d;c>;>$Zjm^?`CGOSi>$npQB!T4y)taA;pRm&l zfCv?xC#fj|hus_Q#ZX+GxSFr^mNG1fATDP=jbMvyw}!Rra!UwW8O|LiPXl5V%fB~* z%=I4B7m*GD1me6kBg-(Yhs*_J?2*y?roME&@}6)PuDE6}%kxg88)#M!`YSI#JChK& zjajFMG>y(qA_1ogYCe0<9Q8lUH5-a3*S)S^3}@&L`Ad-RA5-?mnHoH0ql03_aRvQt zA{z>m73C`G=8*Ezp^K?_8g^_Vaq4nYbieDT^4xjPt*qP@b0{PxeSJ)m&l1Hp9 z7eY)Z&?X9}%F*cXJV4*a!{?IGpQjZc^fK6&Y`(}Y<$b0ov+cl%maQ|u2|3abAE~xd zwSv?9+qR5|t7lHOBFp@9!HN>~{jbI2vvApqTxBCs9C`vHfmHmhZ_3{PDTWYywhK_> z$_$4Fidolc)a!iUE=@Z@{NR&fs3T^xH(X`jR$`=$j{`TkLMK$u$_Z|@dkdM;@6~Qc zPVaG9EXZNPRO+4@>Ai_1HGMqc@wgd^Y>oeWmzZvZ7roO$qj+R`Jpz z6d=)*C8)e$9~|P(@u>w;ePY2j7qmM3hk-DqEw&_v>c%lCg9??_;K6MLcGEP3W~`1( z)hf7AvNebvtZ*=@cMv1*As0XK=-V3^a$8Ks`Jw@qP$(z85wW&1LQ&I?uSR5lbyn>~ zC?xjsT;zrvk2M%H${Q_-?+MwwCum6-7yaX!lK=!S!&0EB8>vr4jn_Z55oyf`cLBkf z{P<;Vg5nk7aYV0fg=#D9mCq?nXlsS4K(Ch*VDD&vA~Q=#`&h+xDQ&o~rVaPl4Zw>V z{wXm4O&yz^lPSV$fx0l0$yWKw#Nq-yRL+rXT1;(*t9m3)Xbyb6kJtn-eDfk$50pXf zX*T7&M`^OJjGlh}x&ejvOigvqyi35EffmM+RPWlx6j5k{RuOQG?Fw+79AZ9qlC zogd<$I->5CnwFXcl%N=@d1CD1B0zo+-zP2|Zs6^gk=n(J!FDcJ%#Dl2*udjKWF)r% zO#R{KIi(d-}4^71;r?){Lae9Vb&e)w=6(oGw@=w<&jd6 za>y0~7^Ne0E{5t4>KW3Ah0y2ZLQUprDs{yD6LecbEG2h(S(%k$Vg{1NBgs_*Hwd=j zLuF}Rgi`!Gr8F1ogoR&=9JWxw(LVbEJi?qFAS8={okIs1v($HAz2~Wn9`9Cz4qCuY zQ7C55JP-g5YkNr`qc~O-H(A3QverQnk!m6wNMtFAVq%rJ45u&t4{$xb{#|J4(U>=N z&0eDCZUVm+8$rN9p587BRR)L)T^QAaAJ9IwqV@JOT1Pa_fFh8Ed&T_Nq^H6l;xk z>7%g@H24#{4v+_}w81FZ&_HrN6dyKOYS`%Oy>@!nnO< z20C?|rDCnw5T~>9nP!%?ng@|z5D98)&BB;smGDrw`2%#$H6Cpw{o`XnFw%*yEH~S* z?OAlodvkJ>@x%~#JQqIALj!Xpa==UT3;e4rmx87p`O)8&b?e6bVrVnTm(PmrE~zc^ z6+VP1P1*FJusv=oQ9LM?d{MaaJpu=@2Uy(w5}(C|DnT3-R-T8S%|w%9w~vIHj{lR! z^#}q>r!Zgwq;;5cIiv1W;lF2B$%05~F*7{8xk{Kq8izmK^hLfrV@~I9#x7+z0oNb} zvivc_akd*PbL;)|P-;lASEf@KTaV85Ab*2p0~Q>3WcMA5LLKFo3oeAH`P(gt`39Q% zme57hHJeiFSkHl0V4@dX(77_{`Edo+s0f?6QcQjP>MU_5d!@u?uEL<4PPDeHpz9$KRxYHhQY};O7NOeJZ7~cl_S#Sh)HrndBT?WW+AU$!5H=`3(-Vkr5tSb45<>gDS`>16Ky%$EHSgvnQ_BVPx`& zb~s`@?OV#fz75=?HkKtlE4ULQd9M!QYRvqP z;(=Yn)KaFnypdKh51`<-$HWmgYTW*3Dh)O%ZqP2$ zZiUL4W;-|e0#EBwr#VmVEk4W`!b{GGI#c4oZ(2ibtB|lTO5NL(&|0&pINo5`No~crM)+3hl<&NdE5S1TcPM2&hv_7a0UwE%!;vn}Cfm@C)@7kQ89*-S0X39- z%~+K8;#|6I=E2AtZz6wuTCcKIJ|{W!%Sp27fC$>T#90XO9OtGJn}7I%R1<9S`93c8 zPt-h7kNYaVCFi5b?{*Fcj_6vhaBwUi1}CjW2v|K$m2EQ=ZUaec-u^P5$Y3O)Br)b| z9W#ffkz^VRAxfWPROvK8-0JTmDriS?w5?AMAVyMhXqnGv25gA=JdVGqVNfD#iZD}k zGu`SLBGbaRr3SwtFp$rqRJ45@@?;OSQ;twE7WzCI%aUa7giJu6H?oL}O$k z3iA^@C6lXGxQc^syQk_4=(VmMqe~0}OG5Z(aou+^ucvmVuMDLP1w&c_)EXS*HMswi zPs=Z32;9js6%+f4@)U~TC}K=}MI*nvyDZPiS+VvmO$41{+KjGTO}iNNJ6m(do*q!t+n~EzTG_5^4T#xU^4fS z)7Pje(tsQpX0&3+0hLfMGW_@B5mB0_oZG2Gco-R(bG+fg7O^|`g1*>cV2QV@a6K}d z_hJiw4p%W-)F(s>G$^~a6FSE-mG}fJRzCY7Fu6=t48G$d2`C?$H~%<#Qc^~%U@HHp zE=vu6waGSO^|d)9Qr#Ee7!z=JCQr5N<}G?;J(@b11Sz(bZ2!QWN5`2djLC9;a+Z{x z2PqDlHU(1O0FMtSL9R%53-xPAi(U@PWjaU+?-lclhv8$kI|kBslkee}e?n&VJK5In zim=*|w@Q5brKo~a05ua{0yu~t0{Q9!6YrXM zjARnQ%02DJV?D6YsxpWaw?&I&%1BbV){oQe^nMc457?iz2+kvr29;>+o3+(GJ$}GG z`KAi{TY-oY@k4{7MPm_#F)VPW(a*PZis z2t|NcR2L`9*Is)H$N5ODSm&oDMzG}a5qLY6C}Uqr_vkam8xw5krNPJi<6L;%8(Y;d zTw(=sKEAL zl^B{pMs5xqiY8dC9ypo-w9%AYKbFkR)6o~6w7%g!>`zM~_!Ht0YZG}_k7h7A>)%6Y{I|cs$oN_gn826bm?pz%+ zax1y6L6<4iPS5CI_f&lX;Cj%xEnL5id3!QhAUHe`Zawap8wg2Zkw36@JgpZad9;7 zW*>9c(`nz(7(9{QGR+4B|7WC?S;dlp2%VmS%#84ys9!*#HsN#65;FgxLE5T+kk;Fe z>1!qN8TFb!v^0H1c;Xdh4HGL1;goL=zE@H@r zy^$2C%vbYbFn&MBHY6sy=SAMVmC9(AuH33phdH{vi<*@z7!Y+i!OpOuP&kxxP?N=! z{}9s+zql+cJBa^Cr-zWqnC#otK3q>}2hc=V5@E`i?DF8br`xQ<-ODvJ-}0^ug(l99 z3xdFo>3+BkP0tE5fC%a!6*(F%c8yb#NtQJYzY!ACIzP_gk&13Lb2Z_^LXb0t{sXYD zBFBbbpidX1q)Mkgq_X}_B6V_$NewkXrxTS7GoL3Me|Z<57HfTr9Z&g$mZVc_kOB7D z<)^Abs&l%!!MlSM#Ms*FA@Rxbn8zprMM$5gB@9O>ShjL)6_=`_!}R_2NhwlaYX^>d z9scUk^p?4q#~*_~{-a zFGl6}#?p5WK9T?=J%%#QF5^9|ZWvB^OhMC+>?le{f*d;SEpxg8KeI+uMgb7SH~dkO z)3pRN`^WixK`LD6U&=<^!DKr5dF-Y&$}evV1h24z?k=5cZ~!^H7`Pf}6wwT? z?*z*FO!w?9*0G$r_(iPYzOWvNzAAy-GZJm8-0=3&9i>W(pojRSetD@Lq8WSL1j}o5;tWhaBrq8&^eY7yctj zDqRV>mR~8eh_VaOKuf-jua3)={}wAXO&sB`ivcQalAp2{1yX&28+BM+_vxA|a9LtR zXS9>CZL&>`{sLzuc|?`?be^bQY7vm#VArO9cF@*^sDuM{MY@kqZg1dn_Iv zxz~q)EcZs|(0JL|z>3A)4#w@E6^r;)jf7lbF)Dop7wJ9Ce*CPp7){T&nFKI8z%sVM z-^d||zz%xw2L9>v_{+H?EgXML3>EQ@Z(c#06N0ae50drzASw<)>PMUCj|le2<)WZu z5o@h{=?u%fx#j7lvjrCf9UQLQ8YkimY>uCR+-L`*LY+qQNnGwu@e5bXsi}kDp9{(} zXK$!|fT`wszdg|DWJKKmz;JbyBYb4N)2t%kEgB}qtZ(9 zaMh)Lnj_?Rr^9T?m#4h-Qq-YBGf#fF_OPF3L|tQzJz_yLSgEL8A6c` zC4+1mRuy3zC2TrjZSAITd*Ocxz7N9`a1S$GGX2C#)CSud-*@bI@F&`l;i$$f2g3hh z7=~KKBc#NbpQa^;N#wxsZn|5HSC-R1jN`K}+9T4MrOHIkyJkTI1F4=Q)Xm+Dfxn9E z;a$Pnbqa6x^E6e$Aq}q{zN4yGx-A0$;RAE6u%oc1 z&myjf-(U78!}B!qEXnk8PVcko!_5S)Cm)tIB%}<)c0I*8I=f?gOs8MZ$PSTw55eM* zfPW_=D*+gu8cEwfm^CG5DEQ~n)Rs~22fls78^ z7P43pIS-8V5&e}7uIhqIzdq-)Hw#>|%M)8g67{#opLQ`957H@DQS_1!*M1-MaPSGe zF$rFc$Zc|&5T`wcRk&Z6p$DA!s4UG+Fv0FIvVj;^Z`@@M^LIvufhR#@eX>)$Q^HTT zwx(E9OOb2q>g4;Wdgk&6XoyLBVQ2k**1@sN(a_rF=9L0)4p8 zU;11AXo;q_VWtjD-kj1@SIHi*1X?dW9*mv?&8fe*@F@Z}!42EYMC;0=Fk9#UUW1m0DyrTvFb_UEx-m;sgr z4!dg0D8{Tj;ge!hHUg&0n9Zo3p zG+4A>Q|c1XG+iu6BJ_e=j;BdJ>KTUrdeK`eD9Pv^nV3Z;3AB#t=}Du01ZW>!HoZ}d p*#^wvReWW$Y=y(B82ndw&YeciRC%G|cozbvP7R6J!`RSxt!g;l_&Wdq literal 0 HcmV?d00001 diff --git a/resources/SmartFires/cl_utils.lua b/resources/SmartFires/cl_utils.lua new file mode 100644 index 000000000..89bc3073e --- /dev/null +++ b/resources/SmartFires/cl_utils.lua @@ -0,0 +1,48 @@ +RegisterNetEvent("Client:fireNotify") +AddEventHandler("Client:fireNotify", function(message) + showNotification(message) +end) + +function showNotification(text) + + if not main.notifications.Enabled then + return + end + + if main.notifications.Framework.ESX then + if ESX ~= nil then + ESX.ShowNotification(text) + end + elseif main.notifications.Framework.QBCore then + TriggerEvent('QBCore:Notify', text, 'primary') + elseif main.notifications.Framework.QBX then + exports.qbx_core:Notify(text, 'inform') + elseif main.notifications.Framework.vRP then + vRP.notify(source, {text}) + elseif main.notifications.Framework.okok then + exports['okokNotify']:Alert("Smart Fires", text, 2000, 'info', true) + else + showBaseNotification(text) + end +end + +function showBaseNotification(message) + -- Base game notifications + SetNotificationTextEntry("STRING") + AddTextComponentString(message) + DrawNotification(0,1) +end + +RegisterNetEvent("Client:fireNotificationCodeM") +AddEventHandler("Client:fireNotificationCodeM", function(coords, message) + local data = { + coords = coords, + type = main.fireAlerts.codeMDispatch.dispatchType, + header = message, + text = messge, + code = main.fireAlerts.codeMDispatch.dispatchCode, + job = main.fireAlerts.codeMDispatch.dispatchJobs, + } + + exports['codem-dispatch']:CustomDispatch(data) +end) diff --git a/resources/SmartFires/config.lua b/resources/SmartFires/config.lua new file mode 100644 index 000000000..f9f1f9e96 --- /dev/null +++ b/resources/SmartFires/config.lua @@ -0,0 +1,1528 @@ +-- Please read our documentation before configuring +-- https://docs.londonstudios.net/ +-- If you are still having issues, contact us + +-- Discord link: https://discord.gg/AtPt9ND + +main = { + + -- This allows configuration of notifications + notifications = { + Enabled = true, + Framework = { + QBCore = false, + QBX = false, + ESX = false, + vRP = false, + okok = false, + }, + -- This allows you to setup a notification cooldown + Cooldown = { + Enabled = true, + Duration = 5000, -- 5 seconds cooldown (set in milliseconds) + } + }, + + -- This section is regarding the lighter item: + + lighterEnabled = true, + + lighterFramework = { + + command = { -- This section allows you to use the lighter without a framework, instead as a command + commandEnabled = true, + + -- This is a cooldown for the command usage + cooldown = { + enabled = true, + duration = 5000, -- 5 seconds cooldown (set in milliseconds) + }, + + commandName = "lighter", -- The command name to use the lighter + + -- Setup permissions for the lighter command only + permissions = { + acePermissions = { + enabled = false, + -- This enables ace permissions on the lighter command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + }, + + }, + -- These are the frameworks that will be used to check if the player has a lighter in their inventory + oxInventory = false, + QBCore = false, + ESX = false, + vRP = false, + }, + + removeFiresAutomatically = { + automaticFires = true, + explosionFires = true, + manualFires = true, + timer = 600, -- (seconds) : will lead to the automatic removal of a fire if it is not extinguished already + }, + + lighterFireSize = 2.0, + lighterOffset = {x = 0.0, y = 0.0, z = 0.2}, -- You can change these values to change the offset of the fire spawned from the actual item itself + + fireSpawnDistance = 200.0, -- This is the distance the player must be within to a fire to spawn in (for performance) + smokeSpawnDistance = 500.0,-- This is the distance the player must be within to smoke to spawn in (for performance) + distanceToSpawnFiresInFront = 4.0, -- Distance to spawn fires in front (to avoid player being damaged initially) + maxWidthOfFiresMultipler = 0.5, -- Max width of fires. E.g, a 15 flame fire would have a maximum width of 22.5m (rounded to nearest integer) + maximumFinalWidth = 20.0, -- This is the maximum width, incase the multiplier leads the maximum to be too big + minimumSizeToExtinguish = 0.7, -- This is the minimum size a fire can be whilst being put out before the script removes it completely + + debugMode = true, + + distanceToExtinguish = 10.0, + + overallFireDifficulty = 75, --this can be increased if needed + + explosionFires = { + startFireOnExplosion = true, -- This will start a fire when an explosion occurs + defaultFireSize = 2.0, -- This is the size of the fire that will be spawned from an explosion + defaultFireType = "normal", -- This is the type of fire that will be spawned from an explosion + offSet = {0.0, 0.0, 0.5}, -- X, Y, Z + + -- https://wiki.rage.mp/wiki/Explosions + -- If there is not a configured fire type, it will use the default + customFireTypes = { + ["3"] = {size = 2.0, type = "normal"}, -- molotov + ["2"] = {size = 4.0, type = "chemical"}, -- sticky bomb + }, + + -- These explosion types wont start a smart fires fire - fire types here; https://altv.stuyk.com/docs/articles/tables/explosions.html + -- We've added the fire hydrant and SNOWBALL explosions by default as these commonly cause unwanted fires, and we recommend you keep these. + ignoreFireTypes = {13, 39}, + }, + + societyPayments = { + qbBanking = false, + okok = false, + qbBossMenu = false, + esxAddonAccount = false, + qsBanking = false, + renewedBanking = false, + societyName = "firefighters", + amountPerFire = {3000, 7000} -- Random number between 3k and 7k + }, + + -- This section allows you to setup spreadable fires + spreadableFires = { + automaticFires = true, -- This will allow automatic fires to spread + manualFires = true, -- This will set whether manual fires will spread by default (unless disabled manually when running the command) + explosionFires = false, + spreadTimer = 120, -- (seconds): Fires will spread every 2 minutes + spreadDistance = 2.0, -- Distance fires can spread + }, + + fireAlerts = { + alertTypes = { + automaticFires = true, + manualFires = true, + explosionFires = true, + }, + + inGameAlerts = { + notification = true, + sound = { -- https://wiki.rage.mp/index.php?title=Sounds (titles are the audio ref) + enabled = true, + soundName = "CONFIRM_BEEP", + soundSet = "HUD_MINI_GAME_SOUNDSET", + } + }, + + blips = { + enabled = true, + sprite = 436, + colour = 49, + scale = 1.0, + shortRange = false, + routeEnabled = true, -- This sets up a route on the map to the blip + routeColour = 49, + }, + + cdDispatch = { + enabled = false, + jobs = {'firefighter'}, + title = 'New Fire', + }, + + cdDispatch3D = { + enabled = false, + jobs = {'firefighter'}, + title = "New Fire", + flash = 0, + sound = 1, + blip = { + sprite = 431, + scale = 1.2, + colour = 3, + flashes = false, + text = 'New Fire', + time = 5, + radius = 0, + } + }, + + coreDispatch = { + enabled = false, + code = "20-12", + jobs = {'police'}, + notificationTime = 3000, + blipSprite = 11, + blipColour = 5, + priority = true, + }, + + rcoreDispatch = { + enabled = false, + resourceName = "rcore_dispatch", + jobs = {'police'}, + priority = "high", + displayCode = "10-420", + alertType = 'alerts', + blipName = "New Fire", + radius = 0, + blipTime = 5, -- Time in seconds before the blip fades + blipSprite = 436, + blipColour = 1, + blipScale = 1.5, + blipLength = 3, + blipflash = true, + imageUrl = '', -- Insert your image URL here + soundUrl = '' -- Insert your sound URL here + }, + + qsDispatch = { + enabled = false, + resourceName = "qs-dispatch", + jobs = {'fire', 'police'}, + callCode = { + code = '', + snippet = '', + }, + flashes = false, + image = 'https://dunb17ur4ymx4.cloudfront.net/webstore/logos/30cf9edc7043455c60397ba2f12e620993426e29.png', -- URL here + blipSprite = 436, + blipColour = 1, + blipScale = 1.5, + blipLength = 3, + blipflash = true, + blipText = "Fire", + blipTime = 60000, -- Time in milliseconds before the blip fades + }, + + sonoranCAD = { -- This requires the call commands plugin + enabled = false, + useNearestPostal = true, + }, + + lbTablet = { + enabled = false, + priority = 'medium', + code = '', + title = 'New Fire', + time = 5, -- Seconds + image = '', + job = 'fire', + sound = false, -- or set to a string to play a sound + }, + + imperialCAD = { + enabled = false, + useNearestPostal = true, + status = "", + priority = "", + }, + + psDispatch = { + enabled = false, + jobs = {'police'}, + codeName = "fire", + code = "10-50", + priority = 1, + sprite = 436, + color = 1, + scale = 1.5, + length = 3, + flash = true, + sound = "Lose_1st", + icon = 'fas fa-fire-extinguisher', + }, + + -- This allows integration with the Inferno Station Alert resource + infernoStationAlert = { + enabled = false, + unitIndicatorColors = {"red"}, + tone = "" + }, + + -- This allows integration with the Inferno Pager resource + infernoPager = { + enabled = false, + pagersToTrigger = {"fire"}, -- These are the pagers to trigger + }, + + -- This allows integration with the Inferno Pager Reborn resource + infernoPagerReborn = { + enabled = false, + addressesToPage = {"emg.fire"}, -- These are the addresses to page + }, + + nightsSoftwareMdt = { + enabled = false, + }, + + codeMDispatch = { + enabled = false, + dispatchType = "Fire", + dispatchCode = "10-4", + dispatchJobs = {"fire", "firefighter"}, + }, + + tkDispatch = { + enabled = false, + title = "New Fire", + code = "10-70", + priority = "1", + removeTime = 100 * 60 * 10, + showTime = 10000, + color = 'red', + playSound = true, + flash = true, + jobs = {'firedepartment', 'ambulance'}, + blip = { + sprite = 436, + scale = 1.0, + color = 1, + } + }, + + tkMdt = { + enabled = false, + title = "New Fire", + type = 'ambulance', + time = 1000 * 60 * 10, + callsign = "10-70", + }, + + -- https://shop.loverp-scripts.de/package/4887641 + emergencyDispatch = { + enabled = false, + job = "fire", + }, + + origenPolice = { + enabled = false, + dispatchType = "GENERAL", + job = "fire", + title = "Fire Alert", + }, + }, + + automaticFires = { + enabled = true, -- Here you can enable or disable automatic fires + toggledOnInitially = false, + + -- Below you can set the script to spawn in relation to the number of players currently on a certain job, e.g, firefighters + -- If you aren't using a job check and just want fires to spawn randomly, ignore the job check section and just configure "frequencyOfFires" and "removeFiresAutomatically" + -- Only enable one of the frameworks below if you want to spawn fires in relation to the number of players on a certain job + main = { + QBCore = { -- This enables the job check for QBCore + enabled = false, + jobs = {"fire", "firefighter"}, + }, + ESX = { -- This enables the job check for ESX + enabled = false, + jobs = {"fire", "firefighter"}, + }, + vRP = { -- This enables the job check for vRP + enabled = false, + groups = {"fire", "firefighter"}, + permissions = {}, -- Leave blank if you do not want to use permissions to spawn fires + }, + QBX = { -- This enables the job check for QBX + enabled = false, + checkJob = { + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + -- This command is designed for standalone servers who still want to use automatic fires and spawn them according to the number of clocked on users + clockOnSystem = { + enabled = false, + clockOnCommand = { + enabled = true, -- Disable this command if you are using a menu to trigger an event/export to clock people on instead + commandName = "clockfireon", + acePermissions = { + enabled = false, + -- This enables ace permissions on the clock on command + }, + }, + -- We do not need permission on the clock off command, as we have already checked it for them to clock on + clockOffCommand = { + enabled = true, -- Disable this command if you are using a menu to trigger an event/export to clock people off instead + commandName = "clockfireoff", + }, + }, + minimumNumberOfPlayers = 1, -- This is the mininum number of players of that group/job to start spawning automatic fires (and explosion fires) + explosionFires = false, -- This applies the setting to explosion based fires + playersPerFire = 5, -- This means that for every 3 players (or below) part of that group/job, we will spawn one fire (ignore this if you aren't using automatic fires) + frequencyOfFires = { + min = 540, -- seconds (min) + max = 1000 -- seconds (max) + }, -- Fires will spawn every 540 seconds (9 minutes) + }, + + enableLocationCommand = { + enabled = false, -- The command will give you your current location to insert here, if enabled + commandName = "mylocation", + locationColour = "~b~", -- blue + }, + + -- This will enable the area of patrol settings, allowing you to choose an area of patrol where automatic fires will spawn, live in game + -- If this setting is not enabled, you can still categorise coordinates and the script will just pick a random one out of any category + enableAreaOfPatrolSettings = { + enabled = true, + defaultAreaOfPatrol = "city", + setAreaOfPatrolCommand = { + enabled = true, + commandName = "setfiresaop", + acePermissions = { + enabled = false, + -- This enables ace permissions on the toggle automatic fires command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBX integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + }, + -- This command will toggle all areas of patrol on or off + -- When toggled on, this means that fires will spawn in all areas of patrol + toggleAllAreasOfPatrolCommand = { + enabled = true, + commandName = "togglefiresaop", + acePermissions = { + enabled = false, + -- This enables ace permissions on the toggle automatic fires command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + }, + }, + + -- Use lowercase for location categories + locations = { + ["city"] = { + { coords = vector3(-292.85, 102.69, 68.26), description = "Garbagecan Eclipse Blvd", type = "normal2", size = 2.0, numberOfFlames = 1, spreadable = true }, -- If type and size is not defined, random will be picked + { coords = vector3(64.25, -399.12, 39.92), description = "Garbagecan Alta Street", type = "normal2", size = 2.0, numberOfFlames = 1, spreadable = true }, -- You can override the global spreadable variable by setting spreadable for individual fires + { coords = vector3(148.86, -1032.2, 29.34), description = "ATM cubepark", type = "electrical", size = 2.0, numberOfFlames = 1 }, + { coords = vector3(-27.33, -80.09, 57.25), description = "Garbagecan LagunaPlace", type = "normal2", size = 2.0, numberOfFlames = 1 }, + { coords = vector3(682.79, 120.06, 80.75), description = "power generator", type = "electrical", size = 10.0, numberOfFlames = 3 }, + { coords = vector3(212.01, -168.09, 56.34), description = "Garbagecan Alta Place", type = "normal", size = 2.0, numberOfFlames = 1 }, + { coords = vector3(-494.88, -1035.05, 31.32), description = "construction site fire", type = "bonfire", size = 8.0, numberOfFlames = 1 }, + { coords = vector3(-19.63, -198.12, 52.37), description = "BalvenueStreet Fire", type = "normal2", size = 3.0, numberOfFlames = 1 }, + { coords = vector3(632.93, 245.62, 103.3), description = "Gas Station Garbage", type = "normal2", size = 3.0, numberOfFlames = 1 }, + { coords = vector3(610.17, 149.29, 97.59), description = "Electricitysecuritiy case", type = "electrical", size = 3.0, numberOfFlames = 1 }, + { coords = vector3(-148.96, -833.41, 53.59), description = "Cubepark building", type = "bonfire", size = 2.0, numberOfFlames = 1 }, + { coords = vector3(989.57, -106.78, 74.3), description = "Lost MC", type = "bonfire", size = 1.0, numberOfFlames = 1 }, + { coords = vector3(-1172.47, -1572.56, 4.66), description = "Smoke on the Water", type = "normal", size = 1.0, numberOfFlames = 2 }, + { coords = vector3(-1093.70, -1648.62, 4.46), description = "San Andreas Building Site", type = "bonfire", size = 2.0, numberOfFlames = 4}, + { coords = vector3(-1669.83, -791.50, 10.1), description = "Del Perro Beach Building Site", type = "electrical", size = 1.0, numberOfFlames = 1}, + { coords = vector3(-2076.41, -307.16, 13.1), description = "Pacific Bluffs Petrol Station", type = "chemical", size = 5.0, numberOfFlames = 1}, + { coords = vector3(-1697.22, -279.02, 51.88), description = "Pacific Bluffs Church Bins", type = "normal", size = 3.0, numberOfFlames = 1}, + { coords = vector3(-1449.71, -236.74, 49.81), description = "Morningwood Ponsobys", type = "electrical", size = 1.0, numberOfFlames = 1}, + { coords = vector3(-1670.90, -171.87, 61.75), description = "University Bin", type = "normal", size = 1.0, numberOfFlames = 1}, + { coords = vector3(-2283.01, 362.91, 174.60), description = "Kortz Center Vending Machines", type = "electrical", size = 2.0, numberOfFlames = 1}, + { coords = vector3(-1694.62, -76.87, 77.69), description = "Richman Wildfire", type = "normal", size = 3.0, numberOfFlames = 5}, + { coords = vector3(-1158.61, -521.57, 32.83), description = "Backlot Studios Catering Van", type = "chemical", size = 2.0, numberOfFlames = 1}, + { coords = vector3(-1286.73, -1119.18, 6.99), description = "Vespucci Canals Barbers", type = "normal", size = 1.0, numberOfFlames = 1}, + { coords = vector3(-1286.73, -1119.18, 6.99), description = "Vespucci Canals Barbers", type = "normal", size = 1.0, numberOfFlames = 1}, + { coords = vector3(-906.94, -315.66, 39.49), description = "Portola Trinity MC - Bin", type = "normal", size = 1.0, numberOfFlames = 1}, + { coords = vector3(-796.41, -117.72, 19.05), description = "Rockford Hills - Underground Tracks", type = "electrical", size = 5.0, numberOfFlames = 2}, + { coords = vector3(-825.00, -128.36, 28.17), description = "Rockford Hills - Underground Bin", type = "normal", size = 2.0, numberOfFlames = 1}, + { coords = vector3(-711.78, -912.05, 19.21), description = "Little Seoul - Petrol Station", type = "normal", size = 2.0, numberOfFlames = 6}, + { coords = vector3(-829.29, -1260.08, 5.00), description = "La Puerta/Tackle Street - Dumpster", type = "normal", size = 2.0, numberOfFlames = 2}, + { coords = vector3(-234.41, -1999.19, 24.00), description = "Fame or Shame", type = "bonfire", size = 1.0, numberOfFlames = 1}, + { coords = vector3(-16.04, -2170.53, 7.80), description = "Banning - Globe Oil", type = "normal2", size = 5.0, numberOfFlames = 6}, + { coords = vector3(-1266.85, -2727.8789, 13.94), description = "LSIA - Jet Engine", type = "electrical", size = 2.0, numberOfFlames = 1}, + { coords = vector3(-1127.66, -1972.71, 13.16), description = "LSIA - Los Santos Customs", type = "normal", size = 1.0, numberOfFlames = 3}, + { coords = vector3(-882.72, -2748.33, 13.93), description = "LSIA - Dumpsters", type = "bonfire", size = 1.0, numberOfFlames = 1}, + { coords = vector3(-622.48, -229.67, 38.05), description = "Rockford Drive - Vangelico", type = "electrical", size = 1.0, numberOfFlames = 1}, + { coords = vector3(-1075.30, -240.67, 44.05), description = "Life Invader", type = "normal", size = 4.0, numberOfFlames = 5}, + { coords = vector3(-1245.30, -466.50, 33.05), description = "Marathon Avenue - Electrical Box", type = "electrical", size = 1.0, numberOfFlames = 1}, + { coords = vector3(-929.18, -748.83, 19.84), description = "Little Seoul - BB Courts Bins", type = "normal", size = 5.0, numberOfFlames = 1}, + { coords = vector3(-542.03, -1219.93, 18.45), description = "Little Seoul - Petrol Station Bins", type = "normal", size = 5.0, numberOfFlames = 3}, + { coords = vector3(-922.7173, 885.3636, 192.4451), description = "Vinewood Hills - Wildfire", type = "normal", size = 3.0, numberOfFlames = 5}, + { coords = vector3(-722.7173, -1496.08, 5.00), description = "La Puerta - Helipads", type = "normal2", size = 3.0, numberOfFlames = 1}, + { coords = vector3(-661.2731, -937.1542, 21.8292), description = "Little Seoul - Ammunation", type = "normal", size = 7.0, numberOfFlames = 2}, + }, + ["sandy"] = { + { coords = vector3(1154.1, 2393.6, 57.81), description = "Redwood Track", type = "electrical", numberOfFlames = 2 }, + { coords = vector3(849.78, 2420.47, 54.7), description = "Redwood Track 2", type = "electrical", numberOfFlames = 4 }, + { coords = vector3(367.96, 2563.13, 43.52), description = "Harmony Trailer Park", type = "normal", numberOfFlames = 2 }, + { coords = vector3(553.21, 2651.31, 42.23), description = "Harmony 24/7", type = "normal2", numberOfFlames = 3 }, + { coords = vector3(973.53, 2722.57, 39.5), description = "Grand Senora Desert Home 1", type = "normal", numberOfFlames = 2 }, + { coords = vector3(2060.93, 3171.09, 45.17), description = "Grand Senora Desert Small Junkyard", type = "normal2", numberOfFlames = 5 }, + { coords = vector3(1595.96, 3587.69, 38.77), description = "GSD Deserted Motel", type = "normal2", numberOfFlames = 7 }, + { coords = vector3(1536.85, 3701.01, 34.53), description = "GSD Wrecked Trailer", type = "normal", numberOfFlames = 3 }, + { coords = vector3(1391.68, 3603.62, 38.94), description = "GSD Methlab", type = "bonfire", numberOfFlames = 2 }, + { coords = vector3(1788.53, 3895.95, 34.39), description = "GSD Wrecked Shelter", type = "normal", numberOfFlames = 2 }, + { coords = vector3(2186.47, 3728.54, 34.47), description = "GSD Homeless Camp", type = "normal2", numberOfFlames = 1 }, + { coords = vector3(2275.42, 3757.44, 38.44), description = "GSD Railway Transformer", type = "electrical", numberOfFlames = 2 }, + { coords = vector3(2465.87, 3829.83, 40.26), description = "GSD Hotdog Stand", type = "normal", numberOfFlames = 1 }, + { coords = vector3(2521.91, 4212.65, 40.17), description = "GSD Gas Station", type = "normal2", numberOfFlames = 3 }, + { coords = vector3(2892.09, 4496.74, 47.98), description = "GSD Wood Pile", type = "bonfire", numberOfFlames = 2 }, + { coords = vector3(2940.34, 4620.13, 48.72), description = "GSD Train Storage", type = "normal", numberOfFlames = 5 }, + { coords = vector3(2680.89, 4572.22, 40.62), description = "Grapeseed Telecommunications Pole", type = "electrical", numberOfFlames = 3 }, + { coords = vector3(2433.29, 4968.62, 42.35), description = "Grapeseed Methlab", type = "normal2", numberOfFlames = 3 }, + { coords = vector3(2329.19, 4900.57, 41.81), description = "Grapeseed Wood Pile", type = "bonfire", numberOfFlames = 1 }, + { coords = vector3(1677.77, 4884.26, 42.04), description = "Grapeseed Grocery Stand", type = "normal", numberOfFlames = 1 }, + { coords = vector3(725.07, 4190.91, 40.71), description = "Grapeseed Home 1", type = "electrical", numberOfFlames = 2 }, + }, + ["paleto"] = { + { coords = vector3(-2199.24, 4282.4, 49.17), description = "Hookies Restaurant", type = "normal", numberOfFlames = 2 }, + { coords = vector3(-1592.22, 5193.49, 4.31), description = "Paleto Pier Cafe", type = "normal2", size = 1.0, numberOfFlames = 1 }, + { coords = vector3(-785.29, 5398.01, 34.13), description = "Paleto Logging Camp", type = "bonfire", numberOfFlames = 3 }, + { coords = vector3(-501.67, 5280.94, 80.62), description = "Paleto Sawmill - Plank Storage", type = "bonfire", size = 2.0, numberOfFlames = 3 }, + { coords = vector3(-470.27, 5382.18, 79.79), description = "Paleto Sawmill - Log Storage", type = "bonfire", size = 1.0, numberOfFlames = 2 }, + { coords = vector3(-665.16, 5809.71, 17.52), description = " Bayview Lodge - Rear Patio", type = "normal", size = 1.0, numberOfFlames = 1 }, + { coords = vector3(-701.54, 5792.99, 17.33), description = "Bayview Lodge - Front Patio", type = "normal3", numberOfFlames = 3 }, + { coords = vector3(-471.32, 6288.76, 13.61), description = "Paleto Beach Barn", type = "normal", size = 1.0, numberOfFlames = 2 }, + { coords = vector3(-289.88, 6021.72, 31.51), description = "Paleto Trainyard Transformer", type = "electrical", size = 1.0, numberOfFlames = 2 }, + { coords = vector3(-112.15, 6219.17, 31.32), description = "Clucking Bell Electrical Shed", type = "electrical", numberOfFlames = 2 }, + { coords = vector3(-161.86, 6158.63, 31.21), description = "Clucking Bell Warehouse", type = "normal2", size = 2.0, numberOfFlames = 4 }, + { coords = vector3(-433.9, 6156.37, 31.48), description = "Paleto Postal Depot", type = "normal2", numberOfFlames = 1 }, + { coords = vector3(-286.86, 6307.65, 31.69), description = "Paleto Home - Bin Fire", type = "normal", numberOfFlames = 1 }, + { coords = vector3(-178.8, 6268.88, 32.01), description = "Reds Auto Repairs", type = "normal3", size = 2.0, numberOfFlames = 2 }, + { coords = vector3(55.73, 6645.41, 32.28), description = "Paleto Old Home", type = "normal", numberOfFlames = 2 }, + { coords = vector3(356.38, 6476.46, 29.71), description = "Paleto Farm - Crops", type = "normal2", size = 1.0, numberOfFlames = 4 }, + { coords = vector3(-38.31, 6579.78, 31.4), description = "Paleto Home - Garbage Bags", type = "normal2", size = 1.0, numberOfFlames = 1.0 }, + { coords = vector3(-74.35, 6505.76, 31.49), description = "Paleto Willies Pharmacy", type = "normal", numberOfFlames = 2 }, + { coords = vector3(-97.03, 6475.27, 31.43), description = "Paleto Savings Bank - Rear Electics", type = "electrical", numberOfFlames = 2 }, + { coords = vector3(29.51, 6496.38, 31.43), description = "Paleto Warehouse - Crates", type = "normal", size = 2.0, numberOfFlames = 3 }, + { coords = vector3(-61.29, 6651.01, 29.66), description = "Paleto Home - Old Sofa", type = "normal3", numberOfFlames = 1 }, + { coords = vector3(36.8, 6631.61, 31.49), description = "Paleto Electrical Box", type = "electrical", numberOfFlames = 2 }, + { coords = vector3(1087.65, 6510.9, 21.05), description = "Paleto Fruit Stall", type = "normal", size = 2.0, numberOfFlames = 3 }, + { coords = vector3(1580.88, 6458.28, 25.45), description = "Paleto Diner - Trash", type = "normal2", numberOfFlames = 1 }, + { coords = vector3(1442.06, 6332.95, 23.92), description = "Paleto Homeless Camp", type = "normal", size = 2.0, numberOfFlames = 5 }, + { coords = vector3(1347.29, 6385.61, 33.21), description = "Paleto Electrical Transformer", type = "electrical", numberOfFlames = 3 }, + { coords = vector3(1741.98, 6411.23, 35.02), description = "Chiliad Store - Pallets", type = "bonfire", size = 1.0, numberOfFlames = 1 }, + { coords = vector3(2195.65, 5595.34, 53.77), description = "Chiliad Farm Storage", type = "normal3", numberOfFlames = 2 }, + }, + }, + + + fireTypesToSpawn = { -- Chance set out of 1 + -- To set the minimum and maximum automatic fire sizes, see each fire type individually + -- The fire types listed here must all be valid fire types configured in the fireTypes section. + { type = "normal", chance = 0.6}, + { type = "chemical", chance = 0.2}, + { type = "normal2", chance = 0.4}, + { type = "normal3", chance = 0.5}, + { type = "bonfire", chance = 0.1}, + { type = "electrical", chance = 0.2}, + }, + + toggleAutomaticFiresCommand = { + enabled = true, + commandName = "toggleautofires", + acePermissions = { + enabled = false, + -- This enables ace permissions on the toggle automatic fires command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + }, + + triggerAutomaticFireCommand = { + enabled = true, + commandName = "triggerautofire", + acePermissions = { + enabled = false, + -- This enables ace permissions on the trigger automatic fires command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + }, + }, + + startFireCommand = { + enabled = true, + commandName = "startfire", + cooldownEnabled = false, + cooldownLength = 60, -- Length of cooldown in seconds + acePermissions = { + enabled = false, + -- This enables ace permissions on the start fire command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + enableMultipleFlames = true, + }, + + -- This allows you to enable Discord logging for the fires and smokes + -- You must add your webhook in sv_utils.lua + logging = { + enabled = true, + displayName = "Smart Fires", + colour = 31487, + title = "**New Log**", + icon = "https://i.imgur.com/n3n7JNW.png", + footerIcon = "https://i.imgur.com/n3n7JNW.png", + dateFormat = "%d-%m-%Y %H:%M:%S", -- Day-Month-Year Hour-Minute-Second + }, + + -- The stop fire command can be run without any arguments, this will stop the closest fire. + -- Alternatively, it takes an argument of a distance, eg, 4.0 + stopFireCommand = { + enabled = true, + commandName = "stopfire", + maxNearestDistance = 150.0, -- If no argument is given for radius, this is the maximum distance the "nearest fire" can be + maxSpecifiedRadius = 150.0, -- This is the maximum radius that can be specified to put fires out within nearby + acePermissions = { + enabled = false, + -- This enables ace permissions on the stop fire command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + }, + + -- This command stops all fires + stopAllFiresCommand = { + enabled = true, + commandName = "stopallfires", + acePermissions = { + enabled = false, + -- This enables ace permissions on the stop fire command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + }, + + -- This command starts smoke manually + startSmokeCommand = { + enabled = true, + commandName = "startsmoke", + acePermissions = { + enabled = false, + -- This enables ace permissions on the start smoke command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + }, + + + + -- The stop smoke command can be run without any arguments, this will stop the closest smoke. + -- Alternatively, it takes an argument of a distance, eg, 4.0 + stopSmokeCommand = { + enabled = true, + commandName = "stopsmoke", + maxNearestDistance = 150.0, -- If no argument is given for radius, this is the maximum distance the "nearest smoke" can be + maxSpecifiedRadius = 150.0, -- This is the maximum radius that can be specified to put smokes out within nearby + acePermissions = { + enabled = false, + -- This enables ace permissions on the stop smoke command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + }, + + + + -- This command stops all smoke + stopAllSmokeCommand = { + enabled = true, + commandName = "stopallsmoke", + acePermissions = { + enabled = false, + -- This enables ace permissions on the stop smoke command + }, + -- We've added ESX integration. All you need to do is enable it below and configure which jobs can use the command + ESX = { + enabled = false, + checkJob = { + enabled = true, -- Enable this to use ESX job check + jobs = {"fire", "firefighter"} -- A user can have any of the following jobs, allowing you to add multiple + } + }, + -- We've added vRP integration. All you need to do is enable it below. Then, configure if you wish to check for groups or permissions, or even both + vRP = { + enabled = false, + checkGroup = { + enabled = false, -- Enable this to use vRP group check + groups = {"fire", "admin"}, -- A user can have any of the following groups, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use vRP permission check + permissions = {"player.kick"} -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + -- We've added QBCore integration. All you need to do is enable it below. Then, configure if you wish to check for jobs or permissions, or even both + QBCore = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBCore job check + jobs = {"fire"}, -- A user can have any of the following jobs, meaning you can add different jobs + }, + checkPermission = { + enabled = false, -- Enable this to use QBCore permission check + permissions = {"god"}, -- A user can have any of the following permissions, allowing you to add multiple + }, + }, + QBX = { + enabled = false, + checkJob = { + enabled = false, -- Enable this to use QBX job check + jobs = {"fireman"}, -- A user can have any of the following jobs, meaning you can add different jobs + } + }, + }, +} + +-- This configures the weapons used to put out either fires requiring water, or those requiring an extinguisher +weapons = { + water = { -- This integrates with our Smart Hose [v2] resource, or some other hose resources + model = `weapon_hose`, + name = "Hose", + }, + extinguisher = { -- This is the base game fire extinguisher + model = `weapon_fireextinguisher`, + name = "Fire Extinguisher", + }, + foam = { -- This integrates with our Smart Hose [v2] resource + model = `weapon_hose`, + name = "Foam", + }, + waterMonitor = { -- This integrates with our water monitor resource + name = "Water Monitor", + }, + deckGun = { -- This utilises base game deck guns + name = "Deck Gun", + }, + zHose = false, +} + + +-- Here you can translate all elements of the resource into another language +translations = { + foamCommandName = "foam", + foamCommandHelpText = "Toggle foam mode on your fire hose", + startFireCommandHelpText = "Start a fire with a defined type and size", + startFireParameterType = "Fire Type", + startFireParameterSize = "Fire Size", + startFireParameterSizeHelp = "Eg, 4.0", + startFireCommandTypeSeparator = ", ", + startSmokeCommandTypeSeparator = ", ", + invalidFireTypeError = "~r~Error~w~: You must select a valid fire type.", + invalidFireTypeAndSizeError = "~r~Error~w~: You must select a valid fire type and size.", + invalidFireSizeError = "~r~Error~w~: You must select a valid fire size.", + fireSizeAboveMaximumError = "~r~Error~w~: You have exceeded the maximum fire size for this type.", + fireSizeBelowMinimumError = "~r~Error~w~: The fire size is below the minimum for this type.", + stopFireCommandHelpText = "Stop the nearest fire or within a radius", + stopFireCommandParameterName = "Radius", + stopFireCommandParameterHelp = "Eg, 4.0 (optional)", + noNearbyFireFound = "~r~Error~w~: No nearby fire found to stop", + noNearbyFiresFoundInRadius = "~r~Error~w~: No nearby fires found to stop within the specified radius", + specifiedRadiusTooLarge = "~r~Error~w~: No nearby fires found to stop within the specified radius", + stopped = "~g~Success~w~: Stopped", + fire = "fire.", + fires = "fires.", + smoke = "smoke.", + smokes = "smokes.", + nearbyFireStopped = "~g~Success~w~: The closest fire has been stopped.", + stopAllFiresCommandHelpText = "Stop all fires", + allFiresStopped = "~g~Success~w~: All fires have been stopped.", + noFiresFound = "~r~Error~w~: No fires found to stop", + invalidSmokeTypeAndSizeError = "~r~Error~w~: You must select a valid smoke type and size.", + invalidSmokeTypeError = "~r~Error~w~: You must select a valid smoke type.", + invalidSmokeSizeError = "~r~Error~w~: You must select a valid smoke size.", + smokeSizeAboveMaximumError = "~r~Error~w~: You have exceeded the maximum smoke size for this type.", + smokeSizeBelowMinimumError = "~r~Error~w~: The smoke size is below the minimum for this type.", + startSmokeCommandHelpText = "Start smoke with a defined type and size", + startSmokeParameterType = "Smoke Type", + startSmokeParameterSize = "Smoke Size", + startSmokeParameterSizeHelp = "Eg, 4.0", + specifiedRadiusTooLargeSmoke = "~r~Error~w~: No nearby smoke found to stop within the specified radius", + noNearbySmokeFoundInRadius = "~r~Error~w~: No nearby smoke found to stop within the specified radius", + noNearbySmokeFound = "~r~Error~w~: No nearby smoke found to stop", + nearbySmokeStopped = "~g~Success~w~: The closest smoke has been stopped.", + stopSmokeCommandHelpText = "Stop the nearest smoke or within a radius", + stopSmokeCommandParameterName = "Radius", + stopSmokeCommandParameterHelp = "Eg, 4.0 (optional)", + allSmokeStopped = "~g~Success~w~: All smoke has been stopped.", + noSmokeFound = "~r~Error~w~: No smoke found to stop", + stopAllSmokeCommandHelpText = "Stop all smoke", + numberOfFlames = "Number of flames", + numberOfFlamesParameterHelp = "Eg, 4", + numberOfFlamesTooLargeError = "~r~Error~w~: Number of flames exceeds the maximum allowed.", + multiFlamesNotAllowedFireType = "~r~Error~w~: Multiple flames are not allowed for this fire type.", + numberOfFlamesTooLargeFireType = "~r~Error~w~: Number of flames exceeds the maximum allowed for this fire type.", + foamModeDisabled = "Foam mode is now ~r~disabled~w~.", + foamModeEnabled = "Foam mode is now ~g~enabled~w~.", + allFiresStoppedManually = "All Fires Stopped Manually", + streetName = "Street Name: ", + smokeStoppedManually = "Smoke Stopped Manually", + type = "Type: ", + fireExtinguished = "Fire Extinguished", + weapon = "Weapon: ", + fireType = ", Fire Type: ", + lighterCommandHelp = "Set fire to the nearest dumpster", + initialSize = ", Initial Size: ", + multiFlameFireStartedManually = "Fire Started Manually (Multi Flame)", + size = ", Size: ", + fireStartedManually = "Fire Started Manually", + fireStartedByLighter = "Fire Started By Lighter", + lighterCooldown = "You are currently on cooldown for the lighter", + smokeStartedManually = "Smoke Started Manually", + fireStoppedManually = "Fire Stopped Manually", + id = ", ID: ", + radiusSpecified = ", Radius Specified: ", + firesStopped = ", Fires Stopped: ", + allSmokeStoppedManually = "All Smoke Stopped Manually", + numberOfFlames2 = "Number of flames: ", + fireDescription = "Fire", + fireAlert ="~r~Alert~w~: New", -- additional information is added after this notification + toggleFireCommandHelp = "Toggle automatic fires", + automaticFiresEnabled ="~r~Alert~w~: Automatic fires enabled", + automaticFiresDisabled ="~r~Alert~w~: Automatic fires disabled", + automaticFiresEnabledLog = "Toggled automatic fires on", + automaticFiresDisabledLog = "Toggled automatic fires off", + triggerAutomaticFireHelp = "Trigger an automatic fire immediately", + triggeredAnAutomaticFire = "Triggered an automatic fire", + noPermission = "~r~Error~w~: You do not have permission to access this command.", + postal = "Postal", + automaticFireCreated = "Automatic Fire Created", + idAutomatic = "ID: ", + typeAutomatic = ", Type: ", + waterMonitorFireExtinguished = "Water Monitor - Fire Extinguished", + descriptionAutomatic = ", Description: ", + areaOfPatrolUpdated = "~b~Success~w~: Area of patrol updated to ", + invalidAreaOfPatrol = "~r~Error~w~: The area of patrol selected is invalid.", + updatedAreaOfPatrolTo = "Updated area of patrol to ", + nowClockedOff = "~b~Success~w~: You are now clocked off.", + nowClockedOn = "~b~Success~w~: You are now clocked on.", + alreadyClockedOff = "~r~Error~w~: You are already clocked off.", + alreadyClockedOn = "~r~Error~w~: You are already clocked on.", + allAreasOfPatrolOn = "~b~Success~w~: All areas of patrol are now set to enable fire spawning.", + allAreasOfPatrolOff = "~b~Success~w~: All areas of patrol are now disabled.", + allAreasOfPatrolOnLog = "All areas of patrol are now set to enable fire spawning.", + allAreasOfPatrolOffLog = "All areas of patrol are now disabled.", + clockedOffLog = "User clocked off", + clockedOnLog = "User clocked on", + clockOnSuggestion = "Clock on for fires", + clockOffSuggestion = "Clock off for fires", + spreadable = "Spreadable", + spreadableHelp = "true/false", + commandOnCooldown = "~r~Error~w~: This command is currently on cooldown", + dumpsterTooFar = "~r~Error~w~: You are not near a dumpster.", + setAreaOfPatrolHelp = "Set the area of patrol for fire spawning", + areaOfPatrol = "Area of Patrol", + areaOfPatrolHelp = "Eg, city", + toggleAllAreasOfPatrolHelp = "Toggle all areas of patrol for fire spawning", + explosionBased = "Explosion Based Fire", +} + +smokeTypes = { + ["normal"] = { + dict = "scr_agencyheistb", + name = "scr_env_agency3b_smoke", + maximumSizeManual = 20.0, + minimumSizeManual = 1.0, + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + }, + }, + ["electrical"] = { + dict = "core", + name = "ent_amb_elec_crackle", + maximumSizeManual = 20.0, + minimumSizeManual = 1.0, + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + }, + }, + ["normal2"] = { + dict = "core", + name = "ent_amb_smoke_foundry", + maximumSizeManual = 20.0, + minimumSizeManual = 1.0, + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + }, + }, + ["foggy"] = { + dict = "core", + name = "ent_amb_fbi_smoke_fogball", + maximumSizeManual = 20.0, + minimumSizeManual = 1.0, + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + }, + }, + ["normal3"] = { + dict = "core", + name = "ent_amb_stoner_vent_smoke", + maximumSizeManual = 20.0, + minimumSizeManual = 1.0, + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + }, + }, + ["normal4"] = { + dict = "core", + name = "ent_amb_smoke_general", + maximumSizeManual = 20.0, + minimumSizeManual = 1.0, + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + }, + }, + ["normal5"] = { + dict = "core", + name = "proj_grenade_smoke", + maximumSizeManual = 20.0, + minimumSizeManual = 1.0, + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + }, + }, + ["normal6"] = { + dict = "core", + name = "ent_amb_generator_smoke", + maximumSizeManual = 20.0, + minimumSizeManual = 1.0, + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + }, + }, + ["white"] = { + dict = "core", + name = "ent_amb_smoke_factory_white", + maximumSizeManual = 20.0, + minimumSizeManual = 1.0, + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + }, + }, +} + +fireTypes = { + ["normal"] = { + dict = "core", + name = "fire_wrecked_truck_vent", + smoke = { + enabled = true, + type = "normal2", + sizeMultiplier = 0.1, -- This is the size of smoke compared to the size of the fire + keepAfterFire = true, + keepAfterFireDuration = 30, -- This keeps smoke in the area for x seconds after the fire + keepAfterFireSize = 0.1, -- This is the size of smoke after the fire compared to the initial size + }, + toPutOut = { weapons.water, weapons.extinguisher, weapons.foam, weapons.waterMonitor, weapons.deckGun }, + toIncrease = {}, + multiFlamesAllowed = true, -- This defines if multiple flames are allowed for this fire type + maximumMultipleFlames = 16, -- This defines the maximum flames allowed for this fire type + difficulty = 20, -- This is how difficult the fire is to put out (out of 50) + maximumFireSizeManual = 10.0, -- This is the maximum fire size that can be created using the create fire command + minimumFireSizeAutomatic = 1.5, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeAutomatic = 4.5, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeWhenExtinguishing = 10.0, -- This is the maximum fire size that can be created automatically (such as using the wrong weapon to increase the size, such as water on an electrical fire) + minimumFireSizeManual = 0.5, -- This is the minimum fire size that can be created using the create fire command + damageDistance = 1.5, -- The distance a player must be nearby to be damaged by the fire + -- We do not recommend editing the offSet section. This is used to adjust the offset of fires when spawning, for example they may be spawning too low below the player. + offSet = { + x = 0.0, + y = 0.0, + z = -0.4, + } + }, + ["normal2"] = { + dict = "scr_trevor3", + name = "scr_trev3_trailer_plume", + smoke = { + enabled = false, + type = "normal", + sizeMultiplier = 1.4, -- This is the size of smoke compared to the size of the fire + keepAfterFire = false, + keepAfterFireDuration = 200, -- This keeps smoke in the area for x seconds after the fire + keepAfterFireSize = 1.0, -- This is the size of smoke after the fire compared to the initial size, e.g. 1.0 = same size as initial fire + }, + toPutOut = { weapons.water, weapons.extinguisher, weapons.foam, weapons.waterMonitor, weapons.deckGun }, + toIncrease = {}, + multiFlamesAllowed = true, -- This defines if multiple flames are allowed for this fire type + maximumMultipleFlames = 16, -- This defines the maximum flames allowed for this fire type + difficulty = 30, -- This is how difficult the fire is to put out (out of 50) + minimumFireSizeAutomatic = 1.5, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeAutomatic = 2.5, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeManual = 2.0, -- This is the maximum fire size that can be created using the create fire command + maximumFireSizeWhenExtinguishing = 3.0, -- This is the maximum fire size that can be created automatically (such as using the wrong weapon to increase the size, such as water on an electrical fire) + minimumFireSizeManual = 0.1, -- This is the minimum fire size that can be created using the create fire command + -- We do not recommend editing the offSet section. This is used to adjust the offset of fires when spawning, for example they may be spawning too low below the player. + damageDistance = 1.5, -- The distance a player must be nearby to be damaged by the fire + -- We do not recommend editing the offSet section. This is used to adjust the offset of fires when spawning, for example they may be spawning too low below the player. + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + } + }, + ["normal3"] = { + dict = "core", + name = "ent_ray_meth_fires", + smoke = { + enabled = true, + type = "normal6", + sizeMultiplier = 1.4, -- This is the size of smoke compared to the size of the fire + keepAfterFire = true, + keepAfterFireDuration = 30, -- This keeps smoke in the area for x seconds after the fire + keepAfterFireSize = 1.6, -- This is the size of smoke after the fire compared to the initial size, e.g. 1.0 = same size as initial fire + }, + toPutOut = { weapons.water, weapons.extinguisher, weapons.foam, weapons.waterMonitor, weapons.deckGun }, + toIncrease = {}, + multiFlamesAllowed = true, -- This defines if multiple flames are allowed for this fire type + maximumMultipleFlames = 16, -- This defines the maximum flames allowed for this fire type + difficulty = 30, -- This is how difficult the fire is to put out (out of 50) + maximumFireSizeManual = 2.0, -- This is the maximum fire size that can be created using the create fire command + minimumFireSizeAutomatic = 1.5, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeAutomatic = 2.0, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeWhenExtinguishing = 3.0, -- This is the maximum fire size that can be created automatically (such as using the wrong weapon to increase the size, such as water on an electrical fire) + minimumFireSizeManual = 0.5, -- This is the minimum fire size that can be created using the create fire command + damageDistance = 1.5, -- The distance a player must be nearby to be damaged by the fire + -- We do not recommend editing the offSet section. This is used to adjust the offset of fires when spawning, for example they may be spawning too low below the player. + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + } + }, + ["bonfire"] = { + dict = "scr_michael2", + name = "scr_mich3_heli_fire", + smoke = { + enabled = true, + type = "normal", + sizeMultiplier = 1.4, -- This is the size of smoke compared to the size of the fire + keepAfterFire = true, + keepAfterFireDuration = 200, -- This keeps smoke in the area for x seconds after the fire + keepAfterFireSize = 1.0, -- This is the size of smoke after the fire compared to the initial size, e.g. 1.0 = same size as initial fire + }, + toPutOut = { weapons.water, weapons.extinguisher, weapons.foam, weapons.waterMonitor, weapons.deckGun }, + toIncrease = {}, + multiFlamesAllowed = true, -- This defines if multiple flames are allowed for this fire type + maximumMultipleFlames = 5, -- This defines the maximum flames allowed for this fire type + difficulty = 30, -- This is how difficult the fire is to put out (out of 50) + maximumFireSizeManual = 2.0, -- This is the maximum fire size that can be created using the create fire command + minimumFireSizeAutomatic = 1.5, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeAutomatic = 3.0, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeWhenExtinguishing = 2.0, -- This is the maximum fire size that can be created automatically (such as using the wrong weapon to increase the size, such as water on an electrical fire) + minimumFireSizeManual = 0.5, -- This is the minimum fire size that can be created using the create fire command + damageDistance = 1.5, -- The distance a player must be nearby to be damaged by the fire + -- We do not recommend editing the offSet section. This is used to adjust the offset of fires when spawning, for example they may be spawning too low below the player. + offSet = { + x = 0.0, + y = 0.0, + z = 0.0, + } + }, + ["chemical"] = { + dict = "core", + name = "fire_petroltank_truck", + smoke = { + enabled = false, + type = "normal", + sizeMultiplier = 1.4, -- This is the size of smoke compared to the size of the fire + keepAfterFire = true, + keepAfterFireDuration = 200, -- This keeps smoke in the area for x seconds after the fire + keepAfterFireSize = 1.0, -- This is the size of smoke after the fire compared to the initial size, e.g. 1.0 = same size as initial fire + }, + toPutOut = { weapons.extinguisher, weapons.foam }, + toIncrease = { weapons.water, weapons.waterMonitor, weapons.deckGun }, + multiFlamesAllowed = true, -- This defines if multiple flames are allowed for this fire type + maximumMultipleFlames = 16, -- This defines the maximum flames allowed for this fire type + difficulty = 30, -- This is how difficult the fire is to put out (out of 50) + maximumFireSizeManual = 10.0, -- This is the maximum fire size that can be created using the create fire command + minimumFireSizeAutomatic = 1.5, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeAutomatic = 6.5, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeWhenExtinguishing = 10.0, -- This is the maximum fire size that can be created automatically (such as using the wrong weapon to increase the size, such as water on an electrical fire) + minimumFireSizeManual = 0.5, -- This is the minimum fire size that can be created using the create fire command + damageDistance = 1.5, -- The distance a player must be nearby to be damaged by the fire + -- We do not recommend editing the offSet section. This is used to adjust the offset of fires when spawning, for example they may be spawning too low below the player. + offSet = { + x = 0.0, + y = 0.0, + z = -1.0, + } + + }, + ["electrical"] = { + dict = "core", + name = "fire_petroltank_truck", + smoke = { + enabled = true, + type = "electrical", + sizeMultiplier = 1.4, -- This is the size of smoke compared to the size of the fire + keepAfterFire = true, + keepAfterFireDuration = 200, -- This keeps smoke in the area for x seconds after the fire + keepAfterFireSize = 1.0, -- This is the size of smoke after the fire compared to the initial size, e.g. 1.0 = same size as initial fire + }, + toPutOut = { weapons.extinguisher, weapons.foam }, + toIncrease = { weapons.water, weapons.waterMonitor, weapons.deckGun }, + multiFlamesAllowed = true, -- This defines if multiple flames are allowed for this fire type + maximumMultipleFlames = 16, -- This defines the maximum flames allowed for this fire type + difficulty = 30, -- This is how difficult the fire is to put out (out of 50) + maximumFireSizeManual = 10.0, -- This is the maximum fire size that can be created using the create fire command + minimumFireSizeAutomatic = 1.5, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeAutomatic = 6.5, -- This is the minimum fire size that is started automatically (if automatic fires are enabled) + maximumFireSizeWhenExtinguishing = 10.0, -- This is the maximum fire size that can be created automatically (such as using the wrong weapon to increase the size, such as water on an electrical fire) + minimumFireSizeManual = 0.5, -- This is the minimum fire size that can be created using the create fire command + damageDistance = 1.5, -- The distance a player must be nearby to be damaged by the fire + -- We do not recommend editing the offSet section. This is used to adjust the offset of fires when spawning, for example they may be spawning too low below the player. + offSet = { + x = 0.0, + y = 0.0, + z = -1.0, + } + }, +} + +main.fireProps = { + [`v_serv_waste_bin1`] = true, + [`prop_dumpster_02b`] = true, + [`prop_snow_dumpster_01`] = true, + [`prop_bin_11b`] = true, + [`prop_bin_11a`] = true, + [`prop_bin_10a`] = true, + [`v_med_bin`] = true, + [`prop_bin_04a`] = true, + [`v_ret_gc_bin`] = true, + [`prop_bin_07c`] = true, + [`vw_prop_vw_casino_bin_01a`] = true, + [`prop_cs_bin_02`] = true, + [`ch_prop_casino_bin_01a`] = true, + [`prop_bin_12a`] = true, + [`sc1_07_clinical_bin`] = true, + [`prop_bin_06a`] = true, + [`prop_bin_01a`] = true, + [`hei_heist_kit_bin_01`] = true, + [`prop_cs_dumpster_01a`] = true, + [`mp_b_kit_bin_01`] = true, + [`prop_bin_08open`] = true, + [`prop_dumpster_3a`] = true, + [`prop_snow_bin_01`] = true, + [`prop_bin_13a`] = true, + [`prop_bin_05a`] = true, + [`prop_bin_03a`] = true, + [`prop_cs_bin_03`] = true, + [`prop_dumpster_4a`] = true, + [`prop_bin_09a`] = true, + [`prop_bin_14b`] = true, + [`prop_dumpster_01a`] = true, + [`prop_dumpster_02a`] = true, + [`prop_bin_10b`] = true, + [`prop_bin_08a`] = true, + [`prop_bin_delpiero_b`] = true, + [`prop_bin_beach_01d`] = true, + [`v_ret_csr_bin`] = true, + [`prop_bin_07a`] = true, + [`prop_bin_07b`] = true, + [`prop_bin_beach_01a`] = true, + [`prop_bin_02a`] = true, + [`prop_gas_binunit01`] = true, + [`prop_dumpster_4b`] = true, + [`prop_bin_delpiero`] = true, + [`prop_cs_bin_01`] = true, + [`prop_snow_bin_02`] = true, + [`prop_bin_14a`] = true, +} \ No newline at end of file diff --git a/resources/SmartFires/fxmanifest.lua b/resources/SmartFires/fxmanifest.lua new file mode 100644 index 000000000..cad48a084 --- /dev/null +++ b/resources/SmartFires/fxmanifest.lua @@ -0,0 +1,38 @@ +fx_version 'bodacious' + +games { 'gta5' } + +author 'London Studios' +description 'Create and fight realistic fires with a host of features' +version '1.0.0' +lua54 'yes' + +client_scripts { + 'shared.lua', + 'config.lua', + 'cl_utils.lua', + 'cl_smartfires.lua', + 'cl_exports.lua', +} + +server_scripts { + -- "@vrp/lib/utils.lua", + 'shared.lua', + 'config.lua', + 'sv_smartfires.lua', + 'sv_utils.lua', + 'sv_exports.lua', +} + +escrow_ignore { + 'shared.lua', + 'config.lua', + 'sv_utils.lua', + 'sv_exports.lua', + 'cl_utils.lua', + 'cl_exports.lua', +} + +-- Smart Fires created by London Studios. +-- Join our Discord server here: https://discord.gg/htyaZNaG +dependency '/assetpacks' \ No newline at end of file diff --git a/resources/SmartFires/shared.lua b/resources/SmartFires/shared.lua new file mode 100644 index 000000000..b57bba696 --- /dev/null +++ b/resources/SmartFires/shared.lua @@ -0,0 +1,30 @@ +function tableHas(data, value) + for k in pairs(data) do + if data[k] == value then return true end + end + return false +end + +function tableLength(T) + local count = 0 + if T ~= nil then + for _ in pairs(T) do count = count + 1 end + end + return count +end + +-- This generates a random UUID (function taken from Stack Overflow) +-- New math.random seed generated each time ensures it is random +function createFireId() + local random = math.random + local template ='xxxxxxx' + return string.gsub(template, '[xy]', function (c) + local v = (c == 'x') and random(0, 0xf) or random(8, 0xb) + return string.format('%x', v) + end) +end + +function roundNumber(num, numDecimalPlaces) + local mult = 10^(numDecimalPlaces or 0) + return math.floor(num * mult + 0.5) / mult +end \ No newline at end of file diff --git a/resources/SmartFires/sv_exports.lua b/resources/SmartFires/sv_exports.lua new file mode 100644 index 000000000..a858c810d --- /dev/null +++ b/resources/SmartFires/sv_exports.lua @@ -0,0 +1,182 @@ +function CreateFire(coords, size, type, notify) + local id = createFireId() + fires[id] = {coords = coords, size = size + 0.0, type = type, active = false, spreadable = false, original = true, originalId = id, initialSize = size, automatic = {created = false, type=""}} + TriggerClientEvent("Client:updateFireTable", -1, id, fires[id], false, false) + local count, playerTable = checkJobsForAutomaticFires() + if usingJobCheck and notify then + local count, playerTable = checkJobsForAutomaticFires() + for k, v in pairs(playerTable) do + TriggerClientEvent("Client:automaticFireAlert", k, id) + end + end + return id +end + +exports("CreateFire", CreateFire) + +function StopFireById(id) + if fires[id] ~= nil then + local entry = fires[id] + handleSmokeAfterFire(id, entry) + fires[id] = nil + TriggerClientEvent("Client:updateFireTable", -1, id, entry, true, false) + end +end + +function IsFireStillActive(id) + return fires[id] ~= nil +end + +exports("IsFireStillActive", IsFireStillActive) + +function IsSmokeStillActive(id) + return smoke[id] ~= nil +end + +exports("IsSmokeStillActive", IsSmokeStillActive) + +exports("StopFireById", StopFireById) + +function UpdateSmokeSize(id, size) + if smoke[id] ~= nil then + smoke[id].size = size + TriggerClientEvent("Client:updateSmokeTable", -1, id, smoke[id], false, true) + end +end + +exports("UpdateSmokeSize", UpdateSmokeSize) + +function UpdateFireSize(id, size) + if fires[id] ~= nil then + fires[id].size = size + TriggerClientEvent("Client:updateFireTable", -1, id, fires[id], false, true) + end +end + +exports("UpdateFireSize", UpdateFireSize) + +if main.automaticFires.enabled then + function TriggerAutomaticFire() + local id = triggerAutoFire() + return id + end + + function ToggleAutomaticFires() + if automaticFiresEnabled then + automaticFiresEnabled = false + TriggerClientEvent("Client:automaticFiresToggle", -1, false) + else + automaticFiresEnabled = true + TriggerClientEvent("Client:automaticFiresToggle", -1, false) + end + end + + exports("ToggleAutomaticFires", ToggleAutomaticFires) + + exports("TriggerAutomaticFire", TriggerAutomaticFire) +end + +function StopAllFires() + fires = {} + TriggerClientEvent("Client:clearAllFires", -1) +end + +exports("StopAllFires", StopAllFires) + +function CreateSmoke(coords, size, type) + local id = createFireId() + local smokeHandle = {coords = coords, size = size, type = type, active = false, initialSize = size} + smoke[id] = smokeHandle + TriggerClientEvent("Client:updateSmokeTable", -1, id, smokeHandle, false) + return id +end + +exports("CreateSmoke", CreateSmoke) + +function StopSmokeById(id) + if smoke[id] ~= nil then + local entry = smoke[id] + smoke[id] = nil + TriggerClientEvent("Client:updateSmokeTable", -1, id, entry, true) + end +end + +exports("StopSmokeById", StopSmokeById) + +function StopAllSmoke() + smoke = {} + TriggerClientEvent("Client:clearAllSmoke", -1) +end + +exports("StopAllSmoke", StopAllSmoke) + +-- This event allows you to receive data on new automatic fires +RegisterServerEvent("Server:newAutomaticFire") +AddEventHandler("Server:newAutomaticFire", function(id, coords, description, size) +end) + +-- This event allows you to receive data on any new fires +RegisterServerEvent("Server:newFireEvent") +AddEventHandler("Server:newFireEvent", function(id, coords, size) + +end) + +-- This event allows you to receive data on any new smoke +RegisterServerEvent("Server:newSmokeEvent") +AddEventHandler("Server:newSmokeEvent", function(id, coords, size) + +end) + +function GetAllFires() + return fires +end + +exports("GetAllFires", GetAllFires) + +function GetAllSmokes() + return smoke +end + +exports("GetAllSmokes", GetAllSmokes) + +if main.automaticFires.main.clockOnSystem.enabled then + function ClockOnUser(serverId) + if serverId == nil then return nil end + if main.logging.enabled then + normalLog(serverId, translations.clockedOnLog, "") + end + clockedOn[serverId] = true + end + + exports("ClockOnUser", ClockOnUser) + + function ClockOffUser(serverId) + if serverId == nil then return nil end + if main.logging.enabled then + normalLog(serverId, translations.clockedOffLog, "") + end + clockedOn[serverId] = false + end + + exports("ClockOffUser", ClockOffUser) + + -- This event allows you to receive data on users clocking on + RegisterServerEvent("Server:userClockedOn") + AddEventHandler("Server:userClockedOn", function(id) + local serverId = id + end) + + -- This event allows you to receive data on users clocking off + RegisterServerEvent("Server:userClockedOff") + AddEventHandler("Server:userClockedOff", function(id) + local serverId = id + end) +end + +function changeAOP(areaSelected) + if main.automaticFires.locations[areaSelected] ~= nil then + areaOfPatrol = areaSelected + end +end + +exports('changeAOP', changeAOP) \ No newline at end of file diff --git a/resources/SmartFires/sv_smartfires.lua b/resources/SmartFires/sv_smartfires.lua new file mode 100644 index 0000000000000000000000000000000000000000..c80398aa6a67053589808307dc8b3100a18858c8 GIT binary patch literal 7263 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 0 then + for k, v in pairs(main.automaticFires.main.vRP.permissions) do + local players = vRP.getUsersByPermission({v}) + for k, v in pairs(players) do + playerTable[vRP.getUserSource({v})] = vRP.getUserSource({v}) + count = count + 1 + end + end + end + end + + if main.automaticFires.main.ESX.enabled then + local xPlayers = ESX.GetExtendedPlayers() + for k, v in pairs(xPlayers) do + local xPlayer = ESX.GetPlayerFromId(v.source) + local src = v.source + for k, v in pairs(main.automaticFires.main.ESX.jobs) do + if xPlayer.job.name == v then + playerTable[src] = src + count = count + 1 + break + end + end + end + end + + if main.automaticFires.main.QBX.enabled then + local players = exports.qbx_core:GetPlayersData() + for k, v in pairs(players) do + for y, u in pairs(main.automaticFires.main.QBX.checkJob.jobs) do + if v.job.name == u then + playerTable[v.source] = v.source + count = count + 1 + break + end + end + end + end + + if main.automaticFires.main.clockOnSystem.enabled then + for k, v in pairs(clockedOn) do + if v then + playerTable[k] = k + count = count + 1 + end + end + end + + if not usingJobCheck then + local players = GetPlayers() + + for k, v in pairs(players) do + count = count + 1 + playerTable[k] = k + end + end + + return count, playerTable +end + +function firstToUpper(str) + return (str:gsub("^%l", string.upper)) +end + +if main.startFireCommand.enabled then + -- id is either originalId, or the id of the linked fire + RegisterServerEvent("Server:updateFireTableManualAdd") + AddEventHandler("Server:updateFireTableManualAdd", function(eKey, coords, size, type, spreadable, original, lighter, receivedId) + if eventKey == eKey then + local source = source + local permission = userHasPermission(source, main.startFireCommand) + + if permission or lighter then + local id = 0 + local originalId = 0 + + if original and receivedId ~= nil then + id = receivedId + else + id = createFireId() + originalId = receivedId + end + + local fire = {coords = coords, size = size, type = type, active = false, spreadable = spreadable, original = original, originalId = originalId, initialSize = size, automatic = {created = false, type=""}} + fires[id] = fire + TriggerClientEvent("Client:updateFireTable", -1, id, fire, false, false) + if original then + TriggerEvent("Server:newFireEvent", id, coords, size) + + if main.fireAlerts.alertTypes.manualFires then + if lighter then + triggerFireNotification(id, firstToUpper(fires[id].type) .. " " .. translations.fireStartedByLighter) + else + triggerFireNotification(id, firstToUpper(fires[id].type) .. " " .. translations.fireStartedManually) + end + end + + if main.removeFiresAutomatically.manualFires then -- Remove fire automatically after x amount of time + Citizen.SetTimeout(main.removeFiresAutomatically.timer * 1000, function() + + if fires[id] ~= nil then + TriggerClientEvent("Client:updateFireTable", -1, id, fires[id], true, false) + end + + for k, v in pairs(fires) do + if not v.original and v.originalId == id then + TriggerClientEvent("Client:updateFireTable", -1, k, fires[k], true, false) + fires[k] = nil + end + end + + fires[id] = nil + end) + end + end + end + end + end) + + RegisterCommand(main.startFireCommand.commandName, function(source, args) + local source = source + local args = args + + local permission = userHasPermission(source, main.startFireCommand) + if permission then + TriggerClientEvent("Client:startFireCommand", source, args) + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.startFireCommand.acePermissions.enabled) +end + +if main.stopFireCommand.enabled then + RegisterCommand(main.stopFireCommand.commandName, function(source, args) + local source = source + local args = args + + local permission = userHasPermission(source, main.stopFireCommand) + if permission then + TriggerClientEvent("Client:stopFireCommand", source, args) + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.stopFireCommand.acePermissions.enabled) +end + +local lighterCooldown = {} + +if main.lighterEnabled and main.lighterFramework.command.commandEnabled then + RegisterCommand(main.lighterFramework.command.commandName, function(source) + local source = source + + if main.lighterFramework.command.cooldown.enabled and lighterCooldown[source] then + TriggerClientEvent("Client:fireNotify", source, translations.lighterCooldown) + return nil + end + + local permission = userHasPermission(source, main.lighterFramework.command.permissions) + if permission then + + lighterCooldown[source] = true + + if main.lighterFramework.command.cooldown.enabled then + Citizen.SetTimeout(main.lighterFramework.command.cooldown.duration, function() + lighterCooldown[source] = nil + end) + end + + TriggerClientEvent("Client:FindNearbyDumpster", source) + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.stopFireCommand.acePermissions.enabled) +end + +if main.stopAllFiresCommand.enabled then + RegisterCommand(main.stopAllFiresCommand.commandName, function(source, args) + local source = source + local successful = false + local count = tableLength(fires) + if count > 0 then + successful = true + end + local permission = userHasPermission(source, main.stopAllFiresCommand) + if permission then + TriggerClientEvent("Client:stopAllFiresCommand", source, successful, count) + if successful then + fires = {} + TriggerClientEvent("Client:clearAllFires", -1) + end + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.stopAllFiresCommand.acePermissions.enabled) +end + +if main.startSmokeCommand.enabled then + RegisterServerEvent("Server:updateSmokeTableManualAdd") + AddEventHandler("Server:updateSmokeTableManualAdd", function(eKey, coords, size, type) + if eKey == eventKey then + local source = source + local permission = userHasPermission(source, main.startSmokeCommand) + + if permission then + local id = createFireId() + local smokeHandle = {coords = coords, size = size, type = type, active = false, initialSize = size} + smoke[id] = smokeHandle + TriggerClientEvent("Client:updateSmokeTable", -1, id, smokeHandle, false) + + TriggerEvent("Server:newSmokeEvent", id, coords, size) + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end + end) + + RegisterCommand(main.startSmokeCommand.commandName, function(source, args) + local source = source + local args = args + local permission = userHasPermission(source, main.startSmokeCommand) + if permission then + TriggerClientEvent("Client:startSmokeCommand", source, args) + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.startSmokeCommand.acePermissions.enabled) +end + +if main.automaticFires.toggleAutomaticFiresCommand.enabled then + RegisterCommand(main.automaticFires.toggleAutomaticFiresCommand.commandName, function(source, args) + local source = source + local permission = userHasPermission(source, main.automaticFires.toggleAutomaticFiresCommand) + if permission then + toggleAutoFires(source) + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.automaticFires.toggleAutomaticFiresCommand.acePermissions.enabled) +end + +if main.automaticFires.enableAreaOfPatrolSettings.enabled and main.automaticFires.enableAreaOfPatrolSettings.setAreaOfPatrolCommand.enabled then + RegisterCommand(main.automaticFires.enableAreaOfPatrolSettings.setAreaOfPatrolCommand.commandName, function(source, args) + local source = source + local permission = userHasPermission(source, main.automaticFires.enableAreaOfPatrolSettings.setAreaOfPatrolCommand) + if permission then + local areaSelected = string.lower(tostring(args[1])) + if main.automaticFires.locations[areaSelected] ~= nil then + if areaOfPatrol == "all" then + TriggerClientEvent("Client:fireNotify", source, translations.allAreasOfPatrolOff) + TriggerClientEvent("Client:fireLogAction", source, translations.updatedAreaOfPatrolToDefault) + end + + areaOfPatrol = areaSelected + TriggerClientEvent("Client:fireNotify", source, translations.areaOfPatrolUpdated..areaSelected..".") + TriggerClientEvent("Client:fireLogAction", source, translations.updatedAreaOfPatrolTo..areaSelected..".") + else + TriggerClientEvent("Client:fireNotify", source, translations.invalidAreaOfPatrol) + end + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.automaticFires.enableAreaOfPatrolSettings.setAreaOfPatrolCommand.acePermissions.enabled) +end + +if main.automaticFires.enableAreaOfPatrolSettings.enabled and main.automaticFires.enableAreaOfPatrolSettings.toggleAllAreasOfPatrolCommand.enabled then + RegisterCommand(main.automaticFires.enableAreaOfPatrolSettings.toggleAllAreasOfPatrolCommand.commandName, function(source, args) + local source = source + local permission = userHasPermission(source, main.automaticFires.enableAreaOfPatrolSettings.toggleAllAreasOfPatrolCommand) + if permission then + if areaOfPatrol == "all" then + areaOfPatrol = main.automaticFires.enableAreaOfPatrolSettings.defaultAreaOfPatrol + TriggerClientEvent("Client:fireNotify", source, translations.allAreasOfPatrolOff) + TriggerClientEvent("Client:fireLogAction", source, translations.allAreasOfPatrolOffLog) + else + areaOfPatrol = "all" + TriggerClientEvent("Client:fireNotify", source, translations.allAreasOfPatrolOn) + TriggerClientEvent("Client:fireLogAction", source, translations.allAreasOfPatrolOnLog) + end + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.automaticFires.enableAreaOfPatrolSettings.toggleAllAreasOfPatrolCommand.acePermissions.enabled) +end + +if main.automaticFires.triggerAutomaticFireCommand.enabled then + RegisterCommand(main.automaticFires.triggerAutomaticFireCommand.commandName, function(source, args) + local source = source + local permission = userHasPermission(source, main.automaticFires.triggerAutomaticFireCommand) + if permission then + triggerAutoFire(source) + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.automaticFires.toggleAutomaticFiresCommand.acePermissions.enabled) +end + +if main.stopAllSmokeCommand.enabled then + RegisterCommand(main.stopAllSmokeCommand.commandName, function(source, args) + local source = source + local successful = false + local count = tableLength(smoke) + if count > 0 then + successful = true + end + local permission = userHasPermission(source, main.stopAllSmokeCommand) + if permission then + TriggerClientEvent("Client:stopAllSmokeCommand", source, successful, count) + if successful then + smoke = {} + TriggerClientEvent("Client:clearAllSmoke", -1) + end + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.stopAllSmokeCommand.acePermissions.enabled) +end + +if main.stopSmokeCommand.enabled then + RegisterCommand(main.stopSmokeCommand.commandName, function(source, args) + local source = source + local args = args + local permission = userHasPermission(source, main.stopSmokeCommand) + if permission then + TriggerClientEvent("Client:stopSmokeCommand", source, args, true) + else + TriggerClientEvent("Client:fireNotify", source, translations.noPermission) + end + end, main.stopSmokeCommand.acePermissions.enabled) +end + +if main.automaticFires.main.clockOnSystem.enabled then + AddEventHandler('playerDropped', function (reason) + clockedOn[source] = nil + end) + if main.automaticFires.main.clockOnSystem.clockOnCommand.enabled then + RegisterCommand(main.automaticFires.main.clockOnSystem.clockOnCommand.commandName, function(source, args) + local source = source + if clockedOn[source] == nil then + TriggerClientEvent("Client:fireNotify", source, translations.nowClockedOn) + TriggerEvent("Server:userClockedOn", source) + if main.logging.enabled then + TriggerClientEvent("Client:fireLogAction", source, translations.clockedOnLog) + + end + clockedOn[source] = true + else + if clockedOn[source] == true then + TriggerClientEvent("Client:fireNotify", source, translations.alreadyClockedOn) + else + TriggerClientEvent("Client:fireNotify", source, translations.nowClockedOn) + if main.logging.enabled then + TriggerClientEvent("Client:fireLogAction", source, translations.clockedOnLog) + end + TriggerEvent("Server:userClockedOn", source) + clockedOn[source] = true + end + end + + end, main.automaticFires.main.clockOnSystem.clockOnCommand.acePermissions.enabled) + end + if main.automaticFires.main.clockOnSystem.clockOffCommand.enabled then + RegisterCommand(main.automaticFires.main.clockOnSystem.clockOffCommand.commandName, function(source, args) + local source = source + if clockedOn[source] == nil then + TriggerClientEvent("Client:fireNotify", source, translations.alreadyClockedOff) + clockedOn[source] = false + else + if clockedOn[source] == true then + TriggerClientEvent("Client:fireNotify", source, translations.nowClockedOff) + if main.logging.enabled then + TriggerClientEvent("Client:fireLogAction", source, translations.clockedOffLog) + end + TriggerEvent("Server:userClockedOff", source) + clockedOn[source] = false + else + TriggerClientEvent("Client:fireNotify", source, translations.alreadyClockedOff) + end + end + + end, false) + end +end + +local notificationCooldown = false + +function triggerFireNotification(id, message) + + if main.notifications.Cooldown.Enabled and notificationCooldown then + return nil + end + + local count, playerTable = checkJobsForAutomaticFires() + + if usingJobCheck then + for k, v in pairs(playerTable) do + TriggerClientEvent("Client:automaticFireAlert", k, id) + end + else + TriggerClientEvent("Client:automaticFireAlert", -1, id) + end + + local player = GetPlayers()[1] + + if player ~= nil and player ~= 0 then + TriggerClientEvent("Client:fetchStreetName", player, id, fires[id].coords) + + local timeout = false + Citizen.SetTimeout(2000, function() + timeout = true + end) + + while fires[id].streetName == nil and not timeout do + Wait(0) + end + + if fires[id].streetName == nil then + fires[id].streetName = "Unknown Address" + end + else + fires[id].streetName = "Unknown Address" + end + + + if main.fireAlerts.infernoPager.enabled then + local message = {firstToUpper(fires[id].type), translations.fireDescription} + if fires[id].automatic.created then + message = {fires[id].automatic.type, translations.fireDescription} + end + TriggerClientEvent("Fire-EMS-Pager:PlayTones", -1, main.fireAlerts.infernoPager.pagersToTrigger, true, message) + end + + if main.fireAlerts.infernoPagerReborn.enabled then + local description = translations.fireDescription + + if fires[id].automatic.created then + description = fires[id].automatic.type .. " " .. description + else + description = firstToUpper(fires[id].type) .. " " .. description + end + + TriggerEvent("Inferno-Collection:Server:PagerReborn:Editable:CreatePage", { + addresses = main.fireAlerts.infernoPagerReborn.addressesToPage, + description = description, + location = fires[id].streetName + }) + end + + if main.fireAlerts.psDispatch.enabled then + local dispatchData = { + coords = fires[id].coords, + message = message, + code = main.fireAlerts.psDispatch.code, + codeName = main.fireAlerts.psDispatch.codeName, + sprite = main.fireAlerts.psDispatch.sprite, + color = main.fireAlerts.psDispatch.color, + scale = main.fireAlerts.psDispatch.scale, + length = main.fireAlerts.psDispatch.length, + jobs = main.fireAlerts.psDispatch.jobs, + priority = main.fireAlerts.psDispatch.priority, + flash = main.fireAlerts.psDispatch.flash, + icon = main.fireAlerts.psDispatch.icon, + sound = main.fireAlerts.psDispatch.sound, + alertTime = nil, + alert = { + sprite = main.fireAlerts.psDispatch.sprite, + color = main.fireAlerts.psDispatch.color, + scale = main.fireAlerts.psDispatch.scale, + flash = main.fireAlerts.psDispatch.flash, + sound = main.fireAlerts.psDispatch.sound, + length = main.fireAlerts.psDispatch.length, + }, + } + + TriggerEvent('ps-dispatch:server:notify', dispatchData) + end + + if main.fireAlerts.qsDispatch.enabled then + TriggerEvent((main.fireAlerts.qsDispatch.resourceName .. ':server:CreateDispatchCall'), { + job = main.fireAlerts.qsDispatch.jobs, + callLocation = fires[id].coords, + callCode = main.fireAlerts.qsDispatch.callCode, + message = message, + flashes = main.fireAlerts.qsDispatch.flashes, + image = main.fireAlerts.qsDispatch.image, + blip = { + sprite = main.fireAlerts.qsDispatch.blipSprite, + scale = main.fireAlerts.qsDispatch.blipScale, + colour = main.fireAlerts.qsDispatch.blipColour, + flashes = main.fireAlerts.qsDispatch.blipflash, + text = main.fireAlerts.qsDispatch.blipText, + time = main.fireAlerts.qsDispatch.blipTime, + } + }) + end + + if main.fireAlerts.lbTablet.enabled then + local dispatchId = exports["lb-tablet"]:AddDispatch({ + priority = main.fireAlerts.lbTablet.priority, + code = main.fireAlerts.lbTablet.code, + title = main.fireAlerts.lbTablet.title, + description = message, + location = { label="", coords = {x = fires[id].coords.x, y = fires[id].coords.y}}, + time = main.fireAlerts.lbTablet.time, + image = main.fireAlerts.lbTablet.image, + job = main.fireAlerts.lbTablet.job, + sound = main.fireAlerts.lbTablet.sound, + }) + end + + if main.fireAlerts.tkDispatch.enabled then + exports.tk_dispatch:addCall({ + title = main.fireAlerts.tkDispatch.title, + code = main.fireAlerts.tkDispatch.code, + priority = main.fireAlerts.tkDispatch.priority, + message = message, + coords = fires[id].coords, + location = fires[id].streetName, + removeTime = main.fireAlerts.tkDispatch.removeTime, + showTime = main.fireAlerts.tkDispatch.showTime, + color = main.fireAlerts.tkDispatch.color, + flash = main.fireAlerts.tkDispatch.flash, + playSound = main.fireAlerts.tkDispatch.playSound, + jobs = main.fireAlerts.tkDispatch.jobs, + blip = { + sprite = main.fireAlerts.tkDispatch.blip.sprite, + scale = main.fireAlerts.tkDispatch.blip.scale, + color = main.fireAlerts.tkDispatch.blip.color, + }, + }) + end + + if main.fireAlerts.tkMdt.enabled then + exports.tk_mdt:addCall({ + title = main.fireAlerts.tkMdt.title, + type = main.fireAlerts.tkMdt.type, + time = main.fireAlerts.tkMdt.time, + callsign = main.fireAlerts.tkMdt.callsign, + location = fires[id].streetName, + coords = fires[id].coords, + }) + end + + if main.fireAlerts.coreDispatch.enabled then + for k, v in pairs(main.fireAlerts.coreDispatch.jobs) do + exports['core_dispatch']:addCall(main.fireAlerts.coreDispatch.code, message, {}, {fires[id].coords.x, fires[id].coords.y, fires[id].coords.z}, v, main.fireAlerts.coreDispatch.notificationTime, main.fireAlerts.coreDispatch.blipSprite, main.fireAlerts.coreDispatch.blipColour, main.fireAlerts.coreDispatch.priority) + end + end + + if main.fireAlerts.emergencyDispatch.enabled then + TriggerEvent('emergencydispatch:emergencycall:new', main.fireAlerts.emergencyDispatch.job, message, fires[id].coords, true) + end + + if main.fireAlerts.rcoreDispatch.enabled then + + local data = { + code = main.fireAlerts.rcoreDispatch.displayCode, + default_priority = main.fireAlerts.rcoreDispatch.priority, + coords = fires[id].coords, + job = main.fireAlerts.rcoreDispatch.jobs, + text = main.fireAlerts.rcoreDispatch.blipName, + type = 'alerts', + blip_time = main.fireAlerts.rcoreDispatch.blipTime, + image = main.fireAlerts.rcoreDispatch.imageUrl, + custom_sound = main.fireAlerts.rcoreDispatch.soundUrl, + blip = { -- Blip table - optional, remove this table to disable blips + sprite = main.fireAlerts.rcoreDispatch.blipSprite, + colour = main.fireAlerts.rcoreDispatch.blipColour, + scale = main.fireAlerts.rcoreDispatch.blipScale, + text = main.fireAlerts.rcoreDispatch.blipName, + flashes = main.fireAlerts.rcoreDispatch.blipFlash, + radius = main.fireAlerts.rcoreDispatch.radius, + } + } + + TriggerEvent(main.fireAlerts.rcoreDispatch.resourceName .. ':server:sendAlert', data) + end + + + + if main.fireAlerts.cdDispatch.enabled then + TriggerClientEvent('cd_dispatch:AddNotification', -1, { + job_table = main.fireAlerts.cdDispatch.jobs, + coords = fires[id].coords, + + title = main.fireAlerts.cdDispatch.title, + message = message, + flash = 0, + unique_id = tostring(math.random(0000000,9999999)), + blip = { + sprite = 431, + scale = 1.2, + colour = 3, + flashes = false, + text = message, + time = (5*60*1000), + sound = 1, + } + }) + end + + if main.fireAlerts.cdDispatch3D.enabled then + TriggerEvent('cd_dispatch:AddNotification', { + job_table = main.fireAlerts.cdDispatch3D.jobs, + coords = fires[id].coords, + title = main.fireAlerts.cdDispatch3D.title, + message = message, + flash = main.fireAlerts.cdDispatch3D.flash, + sound = main.fireAlerts.cdDispatch3D.sound, + blip = main.fireAlerts.cdDispatch3D.blip + }) + end + + if main.fireAlerts.origenPolice.enabled then + exports['origen_police']:SendAlert({ + coords = fires[id].coords, + title = main.fireAlerts.origenPolice.title, + type = 'GENERAL', + message = message, + job = main.fireAlerts.origenPolice.job, + }) + end + + if main.fireAlerts.infernoStationAlert.enabled then + exports["inferno-station-alert"]:newAlertNearestStationWithPlayers(fires[id].coords, { + ["message"] = "-station-, " .. fires[id].streetName .. ", " .. "reported fire", + ["unitColors"] = main.fireAlerts.infernoStationAlert.unitIndicatorColors, + ["tone"] = main.fireAlerts.infernoStationAlert.tone + }) + end + + if main.fireAlerts.imperialCAD.enabled then + local postal = "" + + if main.fireAlerts.imperialCAD.useNearestPostal then + local postalCoords = {fires[id].coords.x, fires[id].coords.y, fires[id].coords.z} + postal = exports['nearest-postal']:getPostalServer(postalCoords) + end + + exports["ImperialCAD"]:CreateCall({ + users_discordID = "", -- Not required + street = fires[id].streetName, + cross_street = fires[id].streetName, + postal = postal, + city = "", + county = "", + info = message, + nature = "Fire", + status = fires[id].status, + priority = fires[id].priority + }, function(success, resultData) + -- you could manage the response here if needed + end) + end + + if main.fireAlerts.sonoranCAD.enabled then + -- Fetch the street name from first client in players table + + local postal = "" + + if main.fireAlerts.sonoranCAD.useNearestPostal then + local postalCoords = {fires[id].coords.x, fires[id].coords.y, fires[id].coords.z} + postal = exports['nearest-postal']:getPostalServer(postalCoords) + end + + exports.sonorancad.call911("Fire", fires[id].coords, message, postal) + end + + if main.fireAlerts.nightsSoftwareMdt.enabled then + + + exports.night_shifts:CreateEmergencyCallViaServer(true --[[isEmergency]], + false --[[isPoliceRequired]], + false --[[isAmbulanceRequired]], + true --[[isFireRequired]], + false --[[isTowRequired]], + message, + fires[id].streetName, + "" --[[string]], + "Fire Department" --[[string]], + fires[id].coords --[[vector3]], + "Fire Department" --[[string]]) + end + + if main.fireAlerts.codeMDispatch.enabled then + TriggerClientEvent("Client:fireNotificationCodeM", -1, fires[id].coords, message) + end + + if main.notifications.Cooldown.Enabled and not notificationCooldown then + notificationCooldown = true + Citizen.SetTimeout(main.notifications.Cooldown.Duration, function() + notificationCooldown = false + end) + end +end + +function handleAutomaticFireCreation(playerTable) + local firesCreated = {} + local id = createFireId() + local originalId = id + local fire, autoFireDetails = generateRandomFire() + fire.automatic.originalId = id + fire.originalId = id + if autoFireDetails.numberOfFlames ~= nil then + local firesToCreate = autoFireDetails.numberOfFlames - 1 + local radius = 2.0 + if autoFireDetails.numberOfFlames > 4 then + radius = 4.0 + end + for i=1,firesToCreate do + local fire = generateNewFireFromExisting(fire, radius) + local id = createFireId() + fires[id] = fire + TriggerClientEvent("Client:updateFireTable", -1, id, fire, false, false) + table.insert(firesCreated, id) + end + end + + table.insert(firesCreated, id) + fires[id] = fire + TriggerClientEvent("Client:updateFireTable", -1, id, fire, false, false) + + local description = fire.automatic.type.." "..translations.fireDescription + + if main.fireAlerts.alertTypes.automaticFires then + triggerFireNotification(id, description) + end + + normalLog("", translations.automaticFireCreated, translations.idAutomatic..id..translations.typeAutomatic .. fires[id].automatic.type ..translations.descriptionAutomatic..description) + + + TriggerEvent("Server:newAutomaticFire", id, fires[id].coords, description, fires[id].size) + + TriggerEvent("Server:newFireEvent", id, fires[id].coords, fires[id].size) + + if main.removeFiresAutomatically.automaticFires then -- Remove fire automatically after x amount of time + Citizen.SetTimeout(main.removeFiresAutomatically.timer * 1000, function() + -- for k, v in pairs(firesCreated) do + -- if fires[v] ~= nil then + -- TriggerClientEvent("Client:updateFireTable", -1, v, fires[v], true, false) + -- fires[v] = nil + -- end + -- end + + if fires[id] ~= nil then + TriggerClientEvent("Client:updateFireTable", -1, id, fires[id], true, false) + end + + for k, v in pairs(fires) do + if not v.original and v.originalId == id then + TriggerClientEvent("Client:updateFireTable", -1, k, fires[k], true, false) + fires[k] = nil + end + end + + fires[id] = nil + end) + end + + return id +end + +if main.lighterFramework.QBCore then + if main.lighterEnabled then + Citizen.CreateThread(function() + QBCore.Functions.CreateUseableItem("lighter", function(source, item) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.Functions.GetItemByName(item.name) then + TriggerClientEvent("Client:FindNearbyDumpster", source) + end + end) + end) + end + +elseif main.lighterFramework.ESX then + if main.lighterEnabled then + Citizen.CreateThread(function() + while ESX == nil do Wait(0) end + ESX.RegisterUsableItem("lighter", function(source) + TriggerClientEvent("Client:FindNearbyDumpster", source) + end) + end) + end +end + +if main.lighterFramework.oxInventory then + if main.lighterEnabled then + exports('useLighter', function(event, item, inventory, slot, data) + if event == 'usingItem' then + TriggerClientEvent("Client:FindNearbyDumpster", inventory.player.source) + end + end) + end +end + +Citizen.CreateThread(function() + Wait(10000) + while true do + if automaticFiresEnabled then + local count, playerTable = checkJobsForAutomaticFires() + local numberOfFires = 0 + if usingJobCheck then + local newCount = math.floor((count / main.automaticFires.main.playersPerFire) + 0.5) + if newCount < 1 then + if count == main.automaticFires.main.playersPerFire then + newCount = 1 + else + if count >= main.automaticFires.main.minimumNumberOfPlayers then + newCount = 1 + else + newCount = 0 + end + end + end + numberOfFires = newCount + if count == 0 then numberOfFires = 0 end + else + if count > 0 then + numberOfFires = 1 + else + numberOfFires = 0 + end + end + + if numberOfFires > 0 then + for i=0, numberOfFires do + if automaticFiresEnabled then + local count, playerTable = checkJobsForAutomaticFires() + handleAutomaticFireCreation(playerTable) + end + interval = math.random(main.automaticFires.main.frequencyOfFires.min, main.automaticFires.main.frequencyOfFires.max) + Wait((interval * 1000) / numberOfFires) + end + end + + if numberOfFires == 0 then + interval = math.random(main.automaticFires.main.frequencyOfFires.min, main.automaticFires.main.frequencyOfFires.max) + Wait(interval * 1000) + else + Wait(0) + end + else + Wait(100) + end + end +end) + +function userHasPermission(source, location) + local permission = false + local usingPermissions = false + -- Ace Permissions + if location.acePermissions.enabled then + usingPermissions = true + -- Ace Permission Validation (if enabled in config) + if IsPlayerAceAllowed(source, "command."..location.commandName) then + permission = true + end + end + + -- ESX Permissions + if location.ESX.enabled then + local xPlayer = ESX.GetPlayerFromId(source) + if location.ESX.checkJob.enabled then + usingPermissions = true + for k, v in pairs(location.ESX.checkJob.jobs) do + if xPlayer.job.name == v then + permission = true + end + end + end + end + + -- vRP Permission + if location.vRP.enabled then + if location.vRP.checkPermission.enabled then + usingPermissions = true + for k, v in pairs(location.vRP.checkPermission.permissions) do + if vRP.hasPermission({vRP.getUserId({source}),v}) then + permission = true + end + end + end + + if location.vRP.checkGroup.enabled then + usingPermissions = true + for k, v in pairs(location.vRP.checkGroup.groups) do + if vRP.hasGroup({vRP.getUserId({source}),v}) then + permission = true + end + end + end + end + + -- QBCore Permission + if location.QBCore.enabled then + local player = QBCore.Functions.GetPlayer(source) + if location.QBCore.checkJob.enabled then + usingPermissions = true + for k, v in pairs(location.QBCore.checkJob.jobs) do + if player.PlayerData.job.name == v then + permission = true + end + end + end + if location.QBCore.checkPermission.enabled then + usingPermissions = true + for k, v in pairs(location.QBCore.checkPermission.permissions) do + if QBCore.Functions.HasPermission(source, v) then + permission = true + end + end + end + end + + if location.QBX.enabled then + local player = exports.qbx_core:GetPlayer(source) + usingPermissions = true + for k, v in pairs(location.QBX.checkJob.jobs) do + if player.PlayerData.job.name == v then + permission = true + end + end + end + + if not usingPermissions then + permission = true + end + return permission +end + +RegisterServerEvent("Server:newFireLog") +AddEventHandler("Server:newFireLog", function(eKey, action, data) + if eventKey == eKey then + local source = source + normalLog(source, action, data) + end +end) + +-- This handles the Discord logging system +function normalLog(source, action, data) + if not main.logging.enabled then return nil end + local embed = {} + if source == "" then + embed = { + { + ["fields"] = { + { + ["name"] = "**Event:**", + ["value"] = action, + ["inline"] = false + }, + { + ["name"] = "**Data:**", + ["value"] = tostring(data), + ["inline"] = false + }, + }, + ["color"] = main.logging.colour, + ["title"] = main.logging.title, + ["description"] = "", + ["footer"] = { + ["text"] = "Timestamp: "..os.date(main.logging.dateFormat), + ["icon_url"] = main.logging.footerIcon, + }, + ["thumbnail"] = { + ["url"] = main.logging.icon, + }, + } + } + else + embed = { + { + ["fields"] = { + { + ["name"] = "**Player:**", + ["value"] = GetPlayerName(source).." ("..source..")", + ["inline"] = true + }, + { + ["name"] = "**Action:**", + ["value"] = action, + ["inline"] = false + }, + { + ["name"] = "**Data:**", + ["value"] = tostring(data), + ["inline"] = false + }, + }, + ["color"] = main.logging.colour, + ["title"] = main.logging.title, + ["description"] = "", + ["footer"] = { + ["text"] = "Timestamp: "..os.date(main.logging.dateFormat), + ["icon_url"] = main.logging.footerIcon, + }, + ["thumbnail"] = { + ["url"] = main.logging.icon, + }, + } + } + end + + PerformHttpRequest(main.logging.webhook, function(err, text, headers) end, 'POST', json.encode({username = main.logging.displayName, embeds = embed}), { ['Content-Type'] = 'application/json' }) +end + +-- These setup the foundations for ESX / vRP / QBCore permissions +if main.startFireCommand.ESX.enabled or main.stopFireCommand.ESX.enabled or main.stopAllFiresCommand.ESX.enabled or main.startSmokeCommand.ESX.enabled or main.stopSmokeCommand.ESX.enabled or main.stopAllSmokeCommand.ESX.enabled or main.automaticFires.main.ESX.enabled or main.lighterFramework.ESX then + ESX = nil + ESX = exports["es_extended"]:getSharedObject() +end + +if main.startFireCommand.vRP.enabled or main.stopFireCommand.vRP.enabled or main.stopAllFiresCommand.vRP.enabled or main.startSmokeCommand.vRP.enabled or main.stopSmokeCommand.vRP.enabled or main.stopAllSmokeCommand.vRP.enabled or main.automaticFires.main.vRP.enabled then + Proxy = module("vrp", "lib/Proxy") + vRP = Proxy.getInterface("vRP") +end + +if main.startFireCommand.QBCore.enabled or main.stopFireCommand.QBCore.enabled or main.stopAllFiresCommand.QBCore.enabled or main.startSmokeCommand.QBCore.enabled or main.stopSmokeCommand.QBCore.enabled or main.stopAllSmokeCommand.QBCore.enabled or main.automaticFires.main.QBCore.enabled or main.lighterFramework.QBCore then + QBCore = exports["qb-core"]:GetCoreObject() +end +-- End of permissions setup + +function addMoneyToSociety() + local amount = math.random(main.societyPayments.amountPerFire[1], main.societyPayments.amountPerFire[2]) + if main.societyPayments.esxAddonAccount then + TriggerEvent('esx_addonaccount:getSharedAccount', main.societyPayments.societyName, function(account) + if account ~= nil then + account.addMoney(amount) + else + print("ERROR: " .. main.societyPayments.societyName .. " requires a society in order to receive money!") + end + end) + elseif main.societyPayments.qbBossMenu then + TriggerEvent('qb-bossmenu:server:addAccountMoney', main.societyPayments.societyName, amount) + elseif main.societyPayments.qbBanking then + exports['qb-banking']:AddMoney(main.societyPayments.societyName, amount, "Smart Fires Society Payment") + elseif main.societyPayments.okok then + exports['okokBanking']:AddMoney(main.societyPayments.societyName, amount) + elseif main.societyPayments.renewedBanking then + exports['Renewed-Banking']:addAccountMoney(main.societyPayments.societyName, amount) + elseif main.societyPayments.qsBanking then + exports['qs-banking']:AddMoney(main.societyPayments.societyName, amount, "Smart Fires Society Payment") + end +end + +RegisterNetEvent("Server:returnStreetName", function(fireId, streetName) + fires[fireId].streetName = streetName or nil +end) \ No newline at end of file diff --git a/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2+hi.ytd b/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2+hi.ytd deleted file mode 100644 index f302839b4..000000000 --- a/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2+hi.ytd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5da47c3d99cfedf01843fb97bb4f73d0a5c857ab54bbcc724c450d4bfa463e46 -size 2756292 diff --git a/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2.yft b/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2.yft deleted file mode 100644 index f7e6a9787..000000000 --- a/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2.yft +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a15ad3d1a07b9dcabfcfa69c599eacc7b4c174eb8fb982496c18d8661882b55 -size 2407572 diff --git a/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2.ytd b/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2.ytd deleted file mode 100644 index bc83cc257..000000000 --- a/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2.ytd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:91323a64ae53319486b9c31c8e652d98937f28109c93951cfd93af36f96096ab -size 4104714 diff --git a/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2_hi.yft b/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2_hi.yft deleted file mode 100644 index c91740961..000000000 --- a/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/stream/lapdfpis2_hi.yft +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c9b17804201b97acf986a4248b3fdea185fdd3d7dca5da2b6f0645fbc5fac98e -size 4856956 diff --git a/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/vehicles.meta b/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/vehicles.meta index ca944fcad..b35c417b7 100644 --- a/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/vehicles.meta +++ b/resources/[EGRP-CarPacks]/[lapd-pack]/LAPDFPIS_4pack/vehicles.meta @@ -245,127 +245,7 @@ RANGER_PRANGER_REAR_RIGHT - - lapdfpis2 - lapdfpis2 - TAURUS - lapdfpis2 - 18FORD - null - null - null - null - - null - ecoboostv6 - LAYOUT_STD_EXITFIXUP - POLICE3_COVER_OFFSET_INFO - EXPLOSION_INFO_DEFAULT - - DEFAULT_FOLLOW_VEHICLE_CAMERA - MID_BOX_VEHICLE_AIM_CAMERA - VEHICLE_BONNET_CAMERA_MID_NEAR - DEFAULT_POV_CAMERA_LOOKAROUND - - - - - - - - - - - - - - - - - - - - - - - - - - - - VFXVEHICLEINFO_CAR_GENERIC - - - - - - - - - - - - - - - - - - - - - - 35.000000 - 45.000000 - 95.000000 - 150.000000 - 300.000000 - 500.000000 - - - - - - - - - - - SWANKNESS_1 - - FLAG_HAS_LIVERY FLAG_HAS_INTERIOR_EXTRAS FLAG_LAW_ENFORCEMENT FLAG_EMERGENCY_SERVICE FLAG_ALLOW_HATS_NO_ROOF - VEHICLE_TYPE_CAR - VPT_FRONT_AND_BACK_PLATES - VDT_FEROCI - VC_EMERGENCY - VWT_SUV - - - - - - - - - - - - WHEEL_FRONT_RIGHT_CAMERA - WHEEL_FRONT_LEFT_CAMERA - WHEEL_REAR_RIGHT_CAMERA - WHEEL_REAR_LEFT_CAMERA - - - - - - - RANGER_CAVALCADE_FRONT_LEFT - RANGER_FRONT_RIGHT - RANGER_PRANGER_REAR_LEFT - RANGER_PRANGER_REAR_RIGHT - - + @@ -376,9 +256,7 @@ vehicles_feroci_interior lapdfpis - - vehicles_feroci_interior - lapdfpis2 - + + \ No newline at end of file diff --git a/resources/[EGRP-CarPacks]/[lapd-pack]/lapd19fpisv/carvariations.meta b/resources/[EGRP-CarPacks]/[lapd-pack]/lapd19fpisv/carvariations.meta index 58d3ab792..6df180fa0 100644 --- a/resources/[EGRP-CarPacks]/[lapd-pack]/lapd19fpisv/carvariations.meta +++ b/resources/[EGRP-CarPacks]/[lapd-pack]/lapd19fpisv/carvariations.meta @@ -282,7 +282,7 @@ - + diff --git a/resources/[EGRP-CarPacks]/[lasd-packs]/lasd25fpiu/vehicles.meta b/resources/[EGRP-CarPacks]/[lasd-packs]/lasd25fpiu/vehicles.meta index 449e73bdb..643e19e0f 100644 --- a/resources/[EGRP-CarPacks]/[lasd-packs]/lasd25fpiu/vehicles.meta +++ b/resources/[EGRP-CarPacks]/[lasd-packs]/lasd25fpiu/vehicles.meta @@ -2,12 +2,12 @@ vehshare - + lasd25fpiu lasd25fpiu - 20fpiu - nrgy + 20Fpiu + lasd25fpiu null null @@ -16,38 +16,38 @@ null ecoboostv6 - LAYOUT_STANDARD - SHERIFF_COVER_OFFSET_INFO + LAYOUT_STD_EXITFIXUP + POLICE3_COVER_OFFSET_INFO EXPLOSION_INFO_DEFAULT DEFAULT_FOLLOW_VEHICLE_CAMERA - DEFAULT_THIRD_PERSON_VEHICLE_AIM_CAMERA - VEHICLE_BONNET_CAMERA_MID_HIGH + MID_BOX_VEHICLE_AIM_CAMERA + VEHICLE_BONNET_CAMERA_MID_NEAR DEFAULT_POV_CAMERA - - - - - - + + + + + + - + - - + + - + - + - + @@ -58,11 +58,11 @@ - - - + + + - + @@ -73,10 +73,10 @@ - 500.000000 - 500.000000 - 500.000000 - 500.000000 + 35.000000 + 55.000000 + 70.000000 + 140.000000 500.000000 500.000000 @@ -91,17 +91,17 @@ SWANKNESS_1 - FLAG_HAS_LIVERY FLAG_EXTRAS_REQUIRE FLAG_EXTRAS_STRONG FLAG_LAW_ENFORCEMENT FLAG_EMERGENCY_SERVICE FLAG_NO_RESPRAY FLAG_DONT_SPAWN_IN_CARGEN FLAG_REPORT_CRIME_IF_STANDING_ON FLAG_HAS_INTERIOR_EXTRAS + FLAG_EXTRAS_STRONG FLAG_HAS_LIVERY FLAG_EXTRAS_ALL FLAG_LAW_ENFORCEMENT FLAG_EMERGENCY_SERVICE FLAG_NO_RESPRAY FLAG_DONT_SPAWN_IN_CARGEN FLAG_HAS_INTERIOR_EXTRAS FLAG_REPORT_CRIME_IF_STANDING_ON VEHICLE_TYPE_CAR - VPT_FRONT_AND_BACK_PLATES - VDT_GENTAXI + VPT_BACK_PLATES + VDT_FEROCI VC_EMERGENCY - VWT_MUSCLE + VWT_SPORT - S_M_Y_Sheriff_01 + S_M_Y_Cop_01 @@ -127,14 +127,17 @@ - STD_POLICE_FRONT_LEFT - STD_POLICE_FRONT_RIGHT - STD_POLICE_REAR_LEFT - STD_POLICE_REAR_RIGHT + STD_POLICE3_FRONT_LEFT + STD_POLICE3_FRONT_RIGHT + STD_POLICE2_REAR_LEFT + STD_POLICE2_REAR_RIGHT - + + vehicles_feroci_interior + lasd25fpiu + \ No newline at end of file diff --git a/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd08tahoe.ytd b/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd08tahoe.ytd index 52e36db45..6b57d326a 100644 --- a/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd08tahoe.ytd +++ b/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd08tahoe.ytd @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:565e4af201695eaf21e05b59ebce6e9e4358673d10153d37b468a64b4bab9f4a -size 8233380 +oid sha256:22c5bb30701466d879995aee0646d682b17fbaf3fea3d6ceb04d607590036165 +size 8701710 diff --git a/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd08tahoe2.ytd b/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd08tahoe2.ytd index 28b389d20..281b97b35 100644 --- a/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd08tahoe2.ytd +++ b/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd08tahoe2.ytd @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ef9c48c2b0a64540dea8162f8f24a8cd657725826d58e6d0a2fa8a8d313d65d -size 8295502 +oid sha256:87d1b99542be78ba80f4c7c9129714ede1df230b7f2e09f2d8ac6fba0baca5b1 +size 8804175 diff --git a/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd14tahoe.ytd b/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd14tahoe.ytd index 2c7680ddf..cbe2cd820 100644 --- a/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd14tahoe.ytd +++ b/resources/[EGRP-CarPacks]/[lasd-packs]/lasdoldtahoe/stream/lasd14tahoe.ytd @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b11eecefe3bbec5e8ceebf7b5991f16cf384ad3b9d1a1e4bbb6a4078135e0c49 -size 7364969 +oid sha256:fa6719e01ca2d76a1734dad201da1fd680047ab87b5e515d3921103ad083acf4 +size 7879700 diff --git a/resources/ulc/config.lua b/resources/ulc/config.lua index 6a7efa17f..5adee38be 100644 --- a/resources/ulc/config.lua +++ b/resources/ulc/config.lua @@ -61,234 +61,326 @@ Config = { -- Add the resource names of vehicle resources that include a ulc.lua config file ExternalVehResources = { -- ex. "my-police-vehicle", - "08lapdcvpi1", - "08lapdcvpi2", - "08lapdcvpighost", - "08lapdcvpiharbor", - "08lapdcvpisecsd", - "21f150", - "18charger", - "18chargerb", - "21rangost", - "21tacouc", - "22f150rb", - "21silvst", - "montereypkpd23taho_184", - "23f150pr", - "23f150prbb", - "23f150st", - "23gmcleo", - "23gmcleoslick", - "23ram6", - "23ramrb", - "24ramambo", - "24sub", - "5500wrecker", - "7728", - "aspa22", - "caltransf150", - "ccso1", - "ccso4", - "CHP18D", - "chp11cvpi", - "chp16fpiup", - "chp15fpiu", - "chp15fpiuw", - "chp15fpiuk9", - "chp15fpius", - "chp15fpiup", - "chp23durangop", - "chp20fpiup", - "chp21tahoe", - "chp23charg", - "chp23charggr", - "c15expd", - "chp20fpiu", - "chp23chargp", - "chp20tahoe", - "chp15f250", - "chp13fpiu", - "chp13fpiuS", - "chp221tahoe", - "chp21tahoe", - "chp211tahoe", - "chp15fpiuw", - "chp19charg", - "chp19must", - "chp16fpiu", - "chpisuimpala", - "chpum16fpiu", - "chp18charg", - "chp18chargnp", - "chp18chargst", - "chp15fpiup", - "chp15fpius", - "chp18tahoe", - "chp20tahoe", - "chp25fpiu", - "chp16fpiu", - "chp15fpiuk9", - "chp18chargst", - "chp23durango", - "chpfpiuk9", - "chptahoe2", - "chptahoe3", - "chptahoe4", - "chptahoek9", - "chpcvpist1", - "chpcvpist2", - "chpcvpirotator", - "chpcvpirotatork9", - "95lasdtaurus", - "GL_minidrugvan", - "gl_q50", - "vcsd25piu", - "southlandexclusive", - "sbcsd08tahoe", - "sbcsd13fpiu2", - "sbcsd18tahoe", - "sbcsd20fpiu", - "sbcsd20fpiu2", - "sbcsd20fpiuX", - "sbcsd21durango", - "sbcsdcharger", - "sbcsdcharger2", - "2002chpb4c", - "e350vanb", - "e450ambo", - "f350bubba", - "g18charger2", - "g18charger2rb", - "lapd09charger1", - "lapd09charger2", - "lapd09dual", - "lapd14charger", - "lapd14chargertd", - "metrocharger", - "lapd14tahoe1", - "lapd14tahoe2", - "lapd14tahoe3", - "lapd14tahoe4", - "lapd16fpiu", - "lapd16fpiu2", - "lapd16fpiusecsd", - "lapd16fpiutraffic", - "lapd16fpiutraffic2", - "metro16fpiu", - "metro16fpiu2", - "metro16fpiu3", - "lapd16fpiua", - "lapd16fpiub", - "lapd16funm", - "lapd16sfpiua", - "lapd16sfpiub", - "lapd16tfpiua", - "lapd16tfpiub", - "lapd16tfpiuc", - "lapd16tfpiud", - "lapd17funm", - "lapd18funm", - "lapd19funm", - "lapd20fpiua", - "lapd20fpiub", - "lapd20fpiuc", - "lapd20sl", - "lapd20talpra", - "lapd20talprb", - "lapd20tfpiu", - "lapd20unm1", - "lapd20unm2", - "lapd24fpiu", - "hybrid20fpiu", - "lapd20fpiu", - "lapd20fpiu2", - "lapd20fpiutraffic", - "lapd20fpiutraffic2", - "LAPD12000", - "17colorado", - "lapdcvpialpr", - "lapdcvpithermal", - "2005LAPDCVPI_Hybrid1", - "2005LAPDCVPI_Hybrid2", - "2005LAPDCVPI_HybridH", - "2008LAPDCVPI_77th1", - "2008LAPDCVPI_77th2", - "2008LAPDCVPI_Hardtop1", - "2008LAPDCVPI_Hardtop2", - "2008LAPDCVPI_Hybrid1", - "2008LAPDCVPI_Hybrid2", - "2008LAPDCVPI_HybridT", - "2008LAPDCVPI_Traffic1", - "08hybridcvpi1", - "08hybridcvpi2", - "08lapdcvpi1", - "08lapdcvpi2", - "08lapdcvpighost", - "08lapdcvpiharbor", - "08lapdcvpisecsd", - "08lapdsap", - "SHOP89471", - "83727", - "84361", - "85734", - "86385", - "86399", - "86486", - "hybridfpis", - "lapdfpis", - "lapdfpis2", - "SHOP00000", - "SHOP80693", - "SHOP81622", - "SHOP83039", - "SHOP89471", - "SHOPFPIS", - "lapd18chrgr", - "lapd18chrgrb", - "lapd20chrgra", - "lapd20chrgrb", - "lapd20det", - "lapd13fpis", - "lapd13fsl", - "lapd13fsli", - "lapd13fsunm", - "lapd19fsl", - "lapd19fsunm", - "lapd19flv", - "lapd19fpisv", - - "25fpiupov", - "transportram", - "senorapd18fpiu_817", - "ocsd18dur", - "ocsd20fpiust", - "lasd2025tahoe1", - "fs25f150", - "spec25silvrb", - "spec25silvbb", - "lasd05cvpi", - "lasd06cvpi", - "lasd06cvpicarson", - "lasd06cvpisd7100", - "lasd08cvpi", - "lasd08cvpilomita", - "lasd08cvpitransit", - "lacpvic", - "lasd06m", - "lasd06u", - "lasdcrownvic", - "lasdlithium", - "lasdparamount", - "lasdsd7100", - "lasdvicslicktop", - "lapdfpiua", - "lasd06cvpi", - "lasd06cvpicarson", - "lasd06cvpisd7100", - "lasd06m", - "lasd08cvpi", - "lasd08cvpilomita", - "lasd08cvpitransit", + "615", + "ccso1", + "24sub", + "20slickfpiu3", + "20legacyfpiu3", + "24ramambo", + "704", + "640", + "128", + "258charger", + "275charger", + "296charger", + "351charger", + "352charger", + "554charger", + "643charger", + "689charger", + "751charger", + "767charger", + "891charger", + "940charger", + "gu1", + "gu2", + "gu3", + "gu4", + "k9_18tahoe", + "k9_durango", + "k9_f150", + "k9_ff250", + "k9_fpiu1", + "k9_fpiu2", + "k9_fpiu3", + "lcso_2016", + "lcso_2020", + "lscso1", + "lscso2", + "lscso3", + "lscso3k9", + "lscso4", + "lscso5", + "lscso6", + "lscso6k9", + "lscso7", + "lscso8", + "lscso9", + "lscso10", + "lscso11", + "lscso12", + "lscso13", + "sok91", + "sok92", + "sok93", + "sok94", + "sok95", + "sok96", + "so1", + "so2", + "so3", + "so4", + "so5", + "so6", + "so7", + "so8", + "so9", + "so10", + "so11", + "so12", + "st_charger1", + "tpd_2020", + "24sodur_ht", + "montereyparkpd25dura_180", + "sbcsd21durango", + "18charg", + "21ppv3", + "21ppvHCSO", + "23f150", + "23hoe", + "25legacyrango1", + "233ppv", + "BCSO21ppv", + "fs23hoe", + "leg21tahoeht_rb", + "MPD21ppv", + "sos23hoe", + "sbcsdcharger", + "sbcsdcharger2", + "24valor20utility4", + "24valor20utility20", + "24valor20utility20sl", + "24valor2500", + "24valor25002", + "24valor25003", + "24valor25004", + "24valor250020sl", + "24valor25002", + "24valor250020", + "24valor1500", + "24valor15003", + "24valor15004", + "24valor150020sl", + "24valor15002", + "24valor150020", + "24valor150020sl", + "22silv2visor", + "22silv2", + "firef250", + "fd_drone", + "22expdrbb", + "22expdr", + "202346gmc", + "23gmc2", + "23gmc2visor", + "23ff1150", + "23gmc2", + "22silv2visor", + "23gmc2visor", + "22silv2", + "22sierralib", + "18charg", + "21ppv3", + "21ppvHCSO", + "23f150", + "23hoe", + "25legacyrango1", + "233ppv", + "BCSO21ppv", + "fs23hoe", + "leg21tahoeht_rb", + "MPD21ppv", + "sos23hoe", + "sbcsdcharger", + "sbcsdcharger2", + "23ff1150", + "atltahoe", + "leg20fpiurb", + "mpowercharg1", + "mpowercharg2", + "23f150pr2", + "23f150pr", + "20sosfpiu1", + "20slickfpiu3", + "21silvst", + "25fpiupov", + "spec25silvbb", + "spec25silvrb", + "222challenger", + "270challenger", + "646challenger", + "716challenger", + "979challenger", + "23ff1150", + "960charger", + "704durango", + "146charger", + "122charger", + "2010cvpipov", + "7644camaro", + "843tahoe", + "438camaro", + "104charger", + "4003cpd", + "1830", + "1822", + "1806charger", + "878truck", + "975tahoe", + "gpd7", + "lasd25fpiu", + "gpdchief1", + "st23tahoe", + "23gmcleoslick", + "23gmcleo", + "24rampumper", + "23sierrafire", + "24rampumper", + "e350vanb", + "ccso4", + "e450ambo", + "751", + "aspa22", + "7738", + "Polmrambb23", + "psp20fpiu2", + "chp18charger", + "sahp18tahoe", + "188tahoe", + "uhp24tahoe", + "23sdjfpiu", + "fhp1", + "dsp19tahoe", + "nhsp606", + "903um", + "psp16fpiulib2", + "chp20fpiup", + "psp16fpiu", + "chp23charg", + "188tahoe", + "vpd3", + "188tahoe", + "23sdjfpiu", + "23hoe", + "23hoeb", + "Specfpui2016", + "20fpiu20", + "21rangostb", + "21rangost", + "18charger", + "18chargerb", + "2020charger", + "2020chargerb", + "hard23charger", + "hard23chargerb", + "slick20durango", + "slick20durangob", + "slick23charger", + "slick23chargerb", + "slick20fpiu", + "slick20fpiub", + "slick21chargb", + "slick21charg", + "uc_charger", + "uc_chargerb", + "slick23tahoe", + "slick23tahoeb", + "19corvette", + "19corvetteb", + "slick25durango", + "slick25durangob", + "uc23suburban", + "uc23suburbanb", + "08hybridcvpi1", + "08hybridcvpi2", + "08lapdcvpi1", + "08lapdcvpi2", + "08lapdcvpighost", + "08lapdcvpiharbor", + "08lapdcvpisecsd", + "08lapdsap", + "13lasdfpiu", + "13lasdfpiu2", + "13lasdfpiua", + "13lasdfpiuseb", + "dualpurpose1", + "dualpurpose2", + "dualpurpose3", + "hybridfpis", + "lacpvic", + "lapd13fpiuv", + "lapd14charger", + "lapd14chargertd", + "lapd16fpiu", + "lapd16fpiu2", + "lapd16fpiusecsd", + "lapd16fpiutraffic", + "lapd16fpiutraffic2", + "lapd20chrgra", + "lapd20sl", + "lapd20unm1", + "lapdalpr20", + "lapdfpis", + "lapdfpis2", + "lapdfpiua", + "lasd05cvpi", + "lasd06cvpi", + "lasd06cvpicarson", + "lasd06cvpisd7100", + "lasd06m", + "lasd06u", + "lasd08cvpi", + "lasd08cvpilomita", + "lasd08cvpitransit", + "lasd15k9", + "lasd15tahoe", + "lasd15tunm", + "lasd16asap", + "lasd20fs", + "lasd20k9", + "lasd20tunm", + "lasdchrg14", + "lasdcrownvic", + "lasdlithium", + "lasdparamount", + "lasdsd7100", + "lasdvicslicktop", + "metro16fpiu", + "metro16fpiu2", + "metro16fpiu3", + "metrocharger", + "s650", + "ht23legacyf150", + "lb18mustang", + "11lapdvic", + "11lapdvic2", + "13lapdexp", + "13lapdfpis", + "13lapdfpis2", + "14lapdchg", + "16lapdexp", + "16lapdexpk9", + "20lapdexp", + "20lapdexp2", + "20lapdexp3", + "20lapdexpk9", + "lasdchg", + "lasdexp", + "lasdexp2", + "lasdfpiu", + "lasdfpiu2", + "lasdfpiu3", + "lasdfpiu4", + "lasdtahoe", + "lasdtahoe2", + "lasdtahoek9", + "lasd14ta", + "lasd14tb", + "lasd14tc", + "lasd14td", + "lasd14tseb", + "lasd14tseb2", + "lasd14tv", "lasd15tahoe", "lasd15tahoeb", "lasd15k9", @@ -307,128 +399,784 @@ Config = { "lasd16fpiub", "lasd16rfr", "lasd16rfrb", - "lasd23tunm", - "lasd20funm", - "fs25f150", - "ram3500hrr", - "ram3500h", - "lasd13fasap", + "lasd13fasap", "lasd13fpiu1", "lasd13fpiu2", "lasd13fpiu3", "lasd13fpiu4", - "lasd13fpiu5", - "lasdchrg14", - "lasdcrownvic", - "lasdparamount", - "lasdsd7100", - "lasdchg", - "lasdexp", - "lasdfpiu2", - "lasdfpiu3", - "lasdfpiu4", - "lasdtahoe2", - "lasd25fpiu", - "lasdvic", - "lasdvic2", - "LASD16T6", - "lasd08tahoe", - "lasd08tahoe2", - "lasd14tahoe", - "lasd14ta", - "lasd14tb", - "lasd14tc", - "lasd14td", - "lasd14tseb", - "lasd14tseb2", - "lasd14tv", - "23silverltbb", - "23silverlt", - "Polmrambb23", - "chp16ram", - "chp18tahoe", - "thpram", - "wtfpiu", - "fs23hoe", - "23sir", - "23f150", - "lasd18chrg", - "2010cvpipov", - "spec20legcyfpiu", - "maxang", - "FranksRTCharger", - "GSD2013GenericSUVK9", - "19mustgtrb", - "19mustgtrw", - "23camss", - "24mustgt", - "24sodur_ht", - "ecsortrango", - "thp24dur", - "lib20fpiu", - "Specfpui2016", - "24sodur_ht", - "22silv2", - "22silv2visor", - "25darkhorse", - "233ppv", - "BCSO21ppv", - "IDHP_25stang", - "SOcamaro", - "wc20fpiustrb", - "ISP_20charger", - "GSD2013GenericSUVK9Slicktop", - "LSFR25DUR", - "LSFR25DURST", - "BCSO21ppv", - "23camsSs", - "wc20fpiustrb", - "233ppv", - "24sodur_ht", - "19mustgtrw", - "19mustgtrb", - "23ram2", - "23ram3", - "arrowxt1", - "24mustgt", - "25darkhorse", - "23camsSs", - "pbpd1", - "wc20fpiustrb", - "704durango", - "reevesaceunit", - "615", - "montereyparkpd25dura_180", - "t880nrclafd65", - "18charg", - "21ppv3", - "21ppvHCSO", - "23f150", - "23hoe", - "25legacyrango1", - "233ppv", - "BCSO21ppv", - "fs23hoe", - "leg21tahoeht_rb", - "MPD21ppv", - "sos23hoe", - "col20fpiu", - "Maxlasd18charger", + "lasd13fpiu5", + "lasd13fsfpiu", + "asd13funm", + "lasd13funm2", + "lasd13funm3", + "lasd13funm4", + "lasdvic", + "lasdvic2", + "mustang19", + "rcsd13fpiu", + "rcsd13fpiu2", + "rcsd16fpiu", + "rcsd16fpiu2", + "rcsd16fpiu3", + "rcsd16fpiu4", + "rcsd20fpiu", + "rcsd20fpiu3", + "rcsdcaprice", + "rcsdcvpi", + "rcsdcvpi2", + "rcsdcvpi3", + "rcsdcvpi4", + "rcsdf150", + "rcsdf250", + "rcsdf2502", + "rcsdtahoe", + "chp11cvpi" , + "chpcvpirotator", + "chpcvpirotatork9", + "chpcvpist1", + "chpcvpist2", + "f350", + "s2", + "h1", + "hcfbi2", + "ocsd1", + "ocsd2", + "ocsd3", + "ocsd4", + "ocsd5", + "ocsd6", + "ocsd7", + "ocsd8", + "dot1", + "uc_charger", + "slick23tahoe", + "slick23tahoeb", + "slick20durangob", + "slick25durango", + "slick25durangob", + "slick20fpiub", + "slick23charger", + "tp_raptor", + "uc23suburban", + "SMPDF150", + "19corvetteb", + "2020chargerb", + "19corvette", + "lacod6", + "lacofdbat", + "lacofdbug", + "lacofddztrk", + "lacofdeng", + "lacofdfoam", + "lacofdpat", + "lacofdrs", + "lacofdsup", + "lacofdt3", + "lacofdtrlr", + "lacofdusartrk", + "lacofdusartrlr", + "lacofdutil", + "mmech", + "petewrecker", + "chp20fpiu", + "chp20fpiugr", + "21rangostb", + "2020chargerb", + "slick23charger", + "uc_charger", + "uc23suburban", + "tp_raptor", + "walkinarrow", + "slick23tahoe", + "hp23charger1", + "hp21charger1", + "smpd16fpiu01", + "smpd16fpiu02", + "smpd16fpiu03", + "smpd16fpiu04", + "smpd16fpiu05", + "smpd16fpiu06", + "23ram6", + "23ram1", + "psp20fpiu2", + "5500wrecker", + "e450ambo", + "20slickfpiu3", + "20legacyfpiu3", + "21ppv3", + "21ppv1", + "21ppv2", + "23f150pr", + "23f150prbb", + "caltransf150", + "25rango1", + "25rango2", + "25rango3", + "25rango4", + "25rango5", + "25rango6", + "staff-25durangosl", + "maxhargu", + "staff-l2fpiu", + "staff-sl23hoe", + "maxchasrt", + "21f150", + "leg20fpiurb", + "leg21tahoeht_rb", + "24tactrd", + "f350bubba", + "23tahoeppvrb", + "23tahoessvrb", + "23hoe", + "23hoeb", + "23f150st", + "23ssjam", + "22f150rb", + "23f150pr", + "23f150prbb", + "BombSquadF450", + "sof250", + "sof250slick", + "sof250k9", + "rye20fpiu", + "rye20fpiurb", + "rye23tahoe", + "ls14calpr", + "ls14chrgr", + "ls14tahoe", + "ls14talpr", + "ls16falpr", + "ls18calpr", + "ls18chrgr", + "chp11cvpi", + "chp15expedition", + "chp15f250", + "chp15f250st", + "chp15fpiuk9", + "chp15fpiup", + "chp15fpius", + "chp15fpiu", + "chp15fpiuw", + "chp16fpiu", + "chp16fpiup", + "chp16ram", + "chp18charg", + "chp18chargst", + "chp18tahoe", + "chp20charg", + "chp20tahoe", + "chp21tahoe", + "chp23charg", + "chp23charg", + "chp23chargp", + "chp23durango", + "chp23durangop", + "chpum15fpiu", + "chp20fpiup", + "chp20fpiu", + "chp20fpiugr", + "chp20fpiu", + "chp21tahoe3", + "chp21tahoe4", + "chp20tahoek9", + "hp1", + "asp14charg", + "aspa9", + "aspa46", + "aspdbenton", + "aspg3", + "aspkdavis", + "aspst1", + "asp18tahoe1", + "asp18tahoe2", + "asp16fpiu", + "asp18dur", + "asp18durst", + "asp21dur", + "asp21durst", + "hab23charger", + "hab23chargerb", + "hp2", + "hp3", + "hp5", + "hp1st", + "hp3st", + "CHP9", + "ls20falpr", + "ls20tahoe", + "ls20talpr", + "21silvst", + "21silvstbb", + "25silvslick", + "25silvslickbb", + "1601", + "1615", + "1609", + "bostoncvpi", + "civ25durango", + "csp23chgr", + "ecsortrango", + "fhpmustang", + "fs23chgr", + "fs23chgrbb", + "fs23durango", + "fs23durangobb", + "fs23tahoe", + "fs23tahoebb", + "fs25f150", + "fs25f150bb", + "hmlegsilv", + "hmlegsilvbb", + "isp24tahoe", + "isp25durango", + "isp25durangopb", + "isp25durangopb3", + "ksp23tahoe", + "ksp23tahoeslick", + "ksp25durango", + "leg25durango", + "lib16fpiurb", + "mshp13explorer", + "mshp16explorer", + "mshp16explorerst", + "mshpcharger", + "mshpchargerst", + "mshpdurango", + "mshpdurangost", + "mshpstang", + "mst16fpiu", + "mst25durango", + "psp24tahoe", + "sos23chgrrb", + "wh23chgr", + "wh23chgrbb", + "SW8", + "2020charger", + "2020chargerb", + "hard23charger", + "hard23chargerb", + "slick20durango", + "slick20durangob", + "slick23charger", + "slick23chargerb", + "slick20fpiu", + "slick20fpiub", + "slick21chargb", + "slick21charg", + "uc_charger", + "uc_chargerb", + "slick23tahoe", + "slick23tahoeb", + "19corvette", + "19corvetteb", + "slick25durango", + "slick25durangob", + "uc23suburban", + "uc23suburbanb", + "lapd20fpiua", + "lapd20fpiub", + "lapd20sl", + "lapd20talpra", + "lapd20talprb", + "lapd20unm1", + "lapd20unm2", + "lasd20piu", + "vcsd25piu", + "2010cvpipov", + "jus16fpis", + "25f150xlt", + "lasd23tunm", + "lasd22tunm", + "lasd20funm", + "lasdf150u", + "22silv2visor", + "22silv2", + "firef250", + "22expdrbb", + "22expdr", + "202346gmc", + "lasd2025tahoe1", + "lasd13tahoe", + "bochechedesigns_t880nrclafd65", + "lapd19fpisv", + "lapd19flv", + "lapd19fsunm", + "lapd19fsl", + "lapd13fsunm", + "lapd13fsli", + "lapd13fsl", + "lapd13fpis", + "lapd20det", + "lapd20chrgrb", + "lapd18chrgrb", + "lapd18chrgr", + "lapd20chrgra", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", - "146charger", - "122charger", - "891charger", - "979challenger", - "716challenger", - "646challenger", - "270challenger", - "222challenger", - "843tahoe", - "104charger", - "cc20fpiu", - "20fpiu_pd", - "hab23charger", - "chp16ram", + + + + + "23ppv", + "hpdghost1", + "hpdghost2", + "23ppv", + "hpdghost1", + "hpdghost2", + "16dpsppv", + "ISP_20charger", + "HCSO25FPIU", + "25darkhorse", + "19mustgtbb", + "19mustgtrw", + "19mustgtrb", + "21ppvHCSO", + "SOcamaro", + "25piuumbb", + "25piuum", + "MPD21ppv", + "MPD22ppv", + "MPD23ppv", + "MPD24ppv", + "BCSO21ppv", + "IDHP_25stang", + "PCSO18ppv", + "PSLPD_unit95", + "SO11", + "SO4", + "SO2", + "HCSO16006", + "SO8", + "GSP627", + "233ppv", + "lib20fpiu", + "PD1", + "PD3", + "PD2", + "leg21tahoest_rb", + "leg21tahoest_bb", + "leg21tahoeht_bb", + "leg21tahoeht_rb", + "fwpd_stbb", + "fwpd_st", + "903jr", + "23silverlt", + "18chargbb", + "18charg", + "24mustgt", + "21canine", + "22canine", + "24umhoe", + "reevesaceunit", + "SO21hoe_bb", + "SO21hoe_rb", + "23camss", + "31587", + "wc20fpiustbb", + "wc20fpiustrb", + "24sodur_ht", + "23ram1", + "23ram6", + "23ram2", + "23ram3", + "SW3", + "SW2", + "SW1", + "sdpd23fpiu", + "sdpd21tahoe ", + "sdpd20fpiu", + "sdpd18tahoe", + "sdpd16fwatch", + "sdpd16fpiust", + "sdpd16fpiu", + "sdpd13fpiu", + "ocsdk9hoe", + "ocsd24hoe", + "ocsd24hoe1", + "ocsd24durst", + "ocsd24dur", + "ocsd20fpiutrans", + "ocsd20fpiust", + "ocsd20fpiu2", + "ocsd20fpiu", + "ocsd18tahoe", + "ocsd18tahoest", + "ocsd16fpiust", + "ocsd16fpiu", + "orlando23tahoe", + "thp24dur", + "258charger", + "275charger", + "296charger", + "351charger", + "554charger", + "643charger", + "689charger", + "751charger", + "767charger", + "891charger", + "940charger", + "960charger", + "704durango", + "146charger", + "122charger", + "7644camaro", + "843tahoe", + "438camaro", + "104charger", + "4003cpd", + "1830", + "1822", + "1806charger", + "352charger", + "878truck", + "975tahoe", + "615", + "gt24non", + "gspcharger", + "128durango", + "640", + "704", + "751", + "128", + "asp14charg", + "asp16fpiu", + "asp18dur", + "asp18durst", + "asp18tahoe1", + "asp18tahoe2", + "asp21dur", + "asp21durst", + "aspa9", + "aspa46", + "aspdbenton", + "aspg3", + "aspkdavis", + "aspst1", + "fhp_20fpiu2", + "fhp_20fpiu2st", + "fhp_charger3", + "fhp_charger3bw", + "fhp_charger3st", + "fhp_charger3ta", + "fhp_charger3uc", + "21silvst", + "21silvstbb", + "1601", + "1609", + "1615", + "bostoncvpi", + "civ25durango", + "csp23chgr", + "ecsortrango", + "fhpmustang", + "fs23chgr", + "fs23chgrbb", + "fs23durango", + "fs23durangobb", + "fs23tahoe", + "fs23tahoebb", + "fs25f150", + "fs25f150bb", + "hmlegsilv", + "hmlegsilvbb", + "isp24tahoe", + " ", + "isp25durango", + "isp25durangopb", + "isp25durangopb3", + "ksp23tahoe", + "ksp23tahoeslick", + "ksp25durango", + "leg25durango", + "lib16fpiurb", + "mshp13explorer", + "mshp16explorer", + "mshp16explorerst", + "mshpcharger", + "mshpchargerst", + "mshpdurango", + "mshpdurangost", + "mshpstang", + "mst16fpiu", + "mst25durango", + "psp24tahoe", + "sos23chgrrb", + "wh23chgr", + "wh23chgrbb", + "st25", + "uc18chargbb", + "apdfpiuwestin", + "apdfpiu", + "apdcharger2", + "col20fpiub", + "col20fpiu", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "GL_Mustang", + "24mustunmr1", + "rbst18charger", + "opd20slickrb", + "opd20slick", + "23sirbb", + "23sir", + "chp23durangop", + " ", + " ", }, Vehicles = { diff --git a/server.cfg b/server.cfg index 069486043..86885512b 100644 --- a/server.cfg +++ b/server.cfg @@ -216,6 +216,8 @@ ensure ebu_trailer ensure ebu_flatbeds ensure Maxlasd18charger ensure ox_target-main +ensure SmartFires + ensure cd_holsteranimation ensure cd_holsteranimationsounds @@ -765,7 +767,7 @@ ensure adis_rfpd_ext ensure adis_rfpd_int ensure bgn-dvs-28-parkinglot ensure matus_sheriff_davis_v2 -ensure int-little-seoul-polstation +///ensure int-little-seoul-polstation ensure LA-NATURE