├── LICENSE
├── LICENSE-MIT
├── README.md
├── biglobby_tweak.xml
├── hooks.xml
├── l10n
├── english.json
├── russian.json
└── schinese.json
├── lua
├── _custom
│ ├── biglobby_globals.lua
│ ├── husl.lua
│ └── menu.lua
└── lib
│ ├── managers
│ ├── _achievementmanager.lua
│ ├── _criminalsmanager.lua
│ ├── _hudmanager.lua
│ ├── _hudmanagerpd2.lua
│ ├── _vehiclemanager.lua
│ ├── group_ai_states
│ │ └── _groupaistatebase.lua
│ ├── hud
│ │ ├── _hudlootscreen.lua
│ │ ├── _hudmissionbriefing.lua
│ │ └── _hudteammate.lua
│ ├── menu
│ │ ├── _contractboxgui.lua
│ │ ├── _crewmanagementgui.lua
│ │ ├── _crimespreemissionsmenucomponent.lua
│ │ ├── _menucomponentmanager.lua
│ │ ├── _menulobbyrenderer.lua
│ │ ├── _menuscenemanager.lua
│ │ └── _missionbriefinggui.lua
│ └── mission
│ │ ├── _elementareatrigger.lua
│ │ └── _elementfilter.lua
│ ├── network
│ ├── base
│ │ ├── _basenetworksession.lua
│ │ ├── _clientnetworksession.lua
│ │ ├── _hostnetworksession.lua
│ │ ├── _networkmanager.lua
│ │ ├── _networkpeer.lua
│ │ ├── handlers
│ │ │ └── _connectionnetworkhandler.lua
│ │ └── session_states
│ │ │ ├── _hoststateingame.lua
│ │ │ └── _hoststateinlobby.lua
│ ├── handlers
│ │ └── _unitnetworkhandler.lua
│ └── matchmaking
│ │ ├── _networkmatchmakingepic.lua
│ │ └── _networkmatchmakingsteam.lua
│ └── tweak_data
│ ├── _moneytweakdata.lua
│ └── _tweakdata.lua
├── mod.txt
├── supermod.xml
└── updates
├── biglobby3.zip
└── meta_biglobby3.json
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU AFFERO GENERAL PUBLIC LICENSE
2 | Version 3, 19 November 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU Affero General Public License is a free, copyleft license for
11 | software and other kinds of works, specifically designed to ensure
12 | cooperation with the community in the case of network server software.
13 |
14 | The licenses for most software and other practical works are designed
15 | to take away your freedom to share and change the works. By contrast,
16 | our General Public Licenses are intended to guarantee your freedom to
17 | share and change all versions of a program--to make sure it remains free
18 | software for all its users.
19 |
20 | When we speak of free software, we are referring to freedom, not
21 | price. Our General Public Licenses are designed to make sure that you
22 | have the freedom to distribute copies of free software (and charge for
23 | them if you wish), that you receive source code or can get it if you
24 | want it, that you can change the software or use pieces of it in new
25 | free programs, and that you know you can do these things.
26 |
27 | Developers that use our General Public Licenses protect your rights
28 | with two steps: (1) assert copyright on the software, and (2) offer
29 | you this License which gives you legal permission to copy, distribute
30 | and/or modify the software.
31 |
32 | A secondary benefit of defending all users' freedom is that
33 | improvements made in alternate versions of the program, if they
34 | receive widespread use, become available for other developers to
35 | incorporate. Many developers of free software are heartened and
36 | encouraged by the resulting cooperation. However, in the case of
37 | software used on network servers, this result may fail to come about.
38 | The GNU General Public License permits making a modified version and
39 | letting the public access it on a server without ever releasing its
40 | source code to the public.
41 |
42 | The GNU Affero General Public License is designed specifically to
43 | ensure that, in such cases, the modified source code becomes available
44 | to the community. It requires the operator of a network server to
45 | provide the source code of the modified version running there to the
46 | users of that server. Therefore, public use of a modified version, on
47 | a publicly accessible server, gives the public access to the source
48 | code of the modified version.
49 |
50 | An older license, called the Affero General Public License and
51 | published by Affero, was designed to accomplish similar goals. This is
52 | a different license, not a version of the Affero GPL, but Affero has
53 | released a new version of the Affero GPL which permits relicensing under
54 | this license.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | TERMS AND CONDITIONS
60 |
61 | 0. Definitions.
62 |
63 | "This License" refers to version 3 of the GNU Affero General Public License.
64 |
65 | "Copyright" also means copyright-like laws that apply to other kinds of
66 | works, such as semiconductor masks.
67 |
68 | "The Program" refers to any copyrightable work licensed under this
69 | License. Each licensee is addressed as "you". "Licensees" and
70 | "recipients" may be individuals or organizations.
71 |
72 | To "modify" a work means to copy from or adapt all or part of the work
73 | in a fashion requiring copyright permission, other than the making of an
74 | exact copy. The resulting work is called a "modified version" of the
75 | earlier work or a work "based on" the earlier work.
76 |
77 | A "covered work" means either the unmodified Program or a work based
78 | on the Program.
79 |
80 | To "propagate" a work means to do anything with it that, without
81 | permission, would make you directly or secondarily liable for
82 | infringement under applicable copyright law, except executing it on a
83 | computer or modifying a private copy. Propagation includes copying,
84 | distribution (with or without modification), making available to the
85 | public, and in some countries other activities as well.
86 |
87 | To "convey" a work means any kind of propagation that enables other
88 | parties to make or receive copies. Mere interaction with a user through
89 | a computer network, with no transfer of a copy, is not conveying.
90 |
91 | An interactive user interface displays "Appropriate Legal Notices"
92 | to the extent that it includes a convenient and prominently visible
93 | feature that (1) displays an appropriate copyright notice, and (2)
94 | tells the user that there is no warranty for the work (except to the
95 | extent that warranties are provided), that licensees may convey the
96 | work under this License, and how to view a copy of this License. If
97 | the interface presents a list of user commands or options, such as a
98 | menu, a prominent item in the list meets this criterion.
99 |
100 | 1. Source Code.
101 |
102 | The "source code" for a work means the preferred form of the work
103 | for making modifications to it. "Object code" means any non-source
104 | form of a work.
105 |
106 | A "Standard Interface" means an interface that either is an official
107 | standard defined by a recognized standards body, or, in the case of
108 | interfaces specified for a particular programming language, one that
109 | is widely used among developers working in that language.
110 |
111 | The "System Libraries" of an executable work include anything, other
112 | than the work as a whole, that (a) is included in the normal form of
113 | packaging a Major Component, but which is not part of that Major
114 | Component, and (b) serves only to enable use of the work with that
115 | Major Component, or to implement a Standard Interface for which an
116 | implementation is available to the public in source code form. A
117 | "Major Component", in this context, means a major essential component
118 | (kernel, window system, and so on) of the specific operating system
119 | (if any) on which the executable work runs, or a compiler used to
120 | produce the work, or an object code interpreter used to run it.
121 |
122 | The "Corresponding Source" for a work in object code form means all
123 | the source code needed to generate, install, and (for an executable
124 | work) run the object code and to modify the work, including scripts to
125 | control those activities. However, it does not include the work's
126 | System Libraries, or general-purpose tools or generally available free
127 | programs which are used unmodified in performing those activities but
128 | which are not part of the work. For example, Corresponding Source
129 | includes interface definition files associated with source files for
130 | the work, and the source code for shared libraries and dynamically
131 | linked subprograms that the work is specifically designed to require,
132 | such as by intimate data communication or control flow between those
133 | subprograms and other parts of the work.
134 |
135 | The Corresponding Source need not include anything that users
136 | can regenerate automatically from other parts of the Corresponding
137 | Source.
138 |
139 | The Corresponding Source for a work in source code form is that
140 | same work.
141 |
142 | 2. Basic Permissions.
143 |
144 | All rights granted under this License are granted for the term of
145 | copyright on the Program, and are irrevocable provided the stated
146 | conditions are met. This License explicitly affirms your unlimited
147 | permission to run the unmodified Program. The output from running a
148 | covered work is covered by this License only if the output, given its
149 | content, constitutes a covered work. This License acknowledges your
150 | rights of fair use or other equivalent, as provided by copyright law.
151 |
152 | You may make, run and propagate covered works that you do not
153 | convey, without conditions so long as your license otherwise remains
154 | in force. You may convey covered works to others for the sole purpose
155 | of having them make modifications exclusively for you, or provide you
156 | with facilities for running those works, provided that you comply with
157 | the terms of this License in conveying all material for which you do
158 | not control copyright. Those thus making or running the covered works
159 | for you must do so exclusively on your behalf, under your direction
160 | and control, on terms that prohibit them from making any copies of
161 | your copyrighted material outside their relationship with you.
162 |
163 | Conveying under any other circumstances is permitted solely under
164 | the conditions stated below. Sublicensing is not allowed; section 10
165 | makes it unnecessary.
166 |
167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
168 |
169 | No covered work shall be deemed part of an effective technological
170 | measure under any applicable law fulfilling obligations under article
171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
172 | similar laws prohibiting or restricting circumvention of such
173 | measures.
174 |
175 | When you convey a covered work, you waive any legal power to forbid
176 | circumvention of technological measures to the extent such circumvention
177 | is effected by exercising rights under this License with respect to
178 | the covered work, and you disclaim any intention to limit operation or
179 | modification of the work as a means of enforcing, against the work's
180 | users, your or third parties' legal rights to forbid circumvention of
181 | technological measures.
182 |
183 | 4. Conveying Verbatim Copies.
184 |
185 | You may convey verbatim copies of the Program's source code as you
186 | receive it, in any medium, provided that you conspicuously and
187 | appropriately publish on each copy an appropriate copyright notice;
188 | keep intact all notices stating that this License and any
189 | non-permissive terms added in accord with section 7 apply to the code;
190 | keep intact all notices of the absence of any warranty; and give all
191 | recipients a copy of this License along with the Program.
192 |
193 | You may charge any price or no price for each copy that you convey,
194 | and you may offer support or warranty protection for a fee.
195 |
196 | 5. Conveying Modified Source Versions.
197 |
198 | You may convey a work based on the Program, or the modifications to
199 | produce it from the Program, in the form of source code under the
200 | terms of section 4, provided that you also meet all of these conditions:
201 |
202 | a) The work must carry prominent notices stating that you modified
203 | it, and giving a relevant date.
204 |
205 | b) The work must carry prominent notices stating that it is
206 | released under this License and any conditions added under section
207 | 7. This requirement modifies the requirement in section 4 to
208 | "keep intact all notices".
209 |
210 | c) You must license the entire work, as a whole, under this
211 | License to anyone who comes into possession of a copy. This
212 | License will therefore apply, along with any applicable section 7
213 | additional terms, to the whole of the work, and all its parts,
214 | regardless of how they are packaged. This License gives no
215 | permission to license the work in any other way, but it does not
216 | invalidate such permission if you have separately received it.
217 |
218 | d) If the work has interactive user interfaces, each must display
219 | Appropriate Legal Notices; however, if the Program has interactive
220 | interfaces that do not display Appropriate Legal Notices, your
221 | work need not make them do so.
222 |
223 | A compilation of a covered work with other separate and independent
224 | works, which are not by their nature extensions of the covered work,
225 | and which are not combined with it such as to form a larger program,
226 | in or on a volume of a storage or distribution medium, is called an
227 | "aggregate" if the compilation and its resulting copyright are not
228 | used to limit the access or legal rights of the compilation's users
229 | beyond what the individual works permit. Inclusion of a covered work
230 | in an aggregate does not cause this License to apply to the other
231 | parts of the aggregate.
232 |
233 | 6. Conveying Non-Source Forms.
234 |
235 | You may convey a covered work in object code form under the terms
236 | of sections 4 and 5, provided that you also convey the
237 | machine-readable Corresponding Source under the terms of this License,
238 | in one of these ways:
239 |
240 | a) Convey the object code in, or embodied in, a physical product
241 | (including a physical distribution medium), accompanied by the
242 | Corresponding Source fixed on a durable physical medium
243 | customarily used for software interchange.
244 |
245 | b) Convey the object code in, or embodied in, a physical product
246 | (including a physical distribution medium), accompanied by a
247 | written offer, valid for at least three years and valid for as
248 | long as you offer spare parts or customer support for that product
249 | model, to give anyone who possesses the object code either (1) a
250 | copy of the Corresponding Source for all the software in the
251 | product that is covered by this License, on a durable physical
252 | medium customarily used for software interchange, for a price no
253 | more than your reasonable cost of physically performing this
254 | conveying of source, or (2) access to copy the
255 | Corresponding Source from a network server at no charge.
256 |
257 | c) Convey individual copies of the object code with a copy of the
258 | written offer to provide the Corresponding Source. This
259 | alternative is allowed only occasionally and noncommercially, and
260 | only if you received the object code with such an offer, in accord
261 | with subsection 6b.
262 |
263 | d) Convey the object code by offering access from a designated
264 | place (gratis or for a charge), and offer equivalent access to the
265 | Corresponding Source in the same way through the same place at no
266 | further charge. You need not require recipients to copy the
267 | Corresponding Source along with the object code. If the place to
268 | copy the object code is a network server, the Corresponding Source
269 | may be on a different server (operated by you or a third party)
270 | that supports equivalent copying facilities, provided you maintain
271 | clear directions next to the object code saying where to find the
272 | Corresponding Source. Regardless of what server hosts the
273 | Corresponding Source, you remain obligated to ensure that it is
274 | available for as long as needed to satisfy these requirements.
275 |
276 | e) Convey the object code using peer-to-peer transmission, provided
277 | you inform other peers where the object code and Corresponding
278 | Source of the work are being offered to the general public at no
279 | charge under subsection 6d.
280 |
281 | A separable portion of the object code, whose source code is excluded
282 | from the Corresponding Source as a System Library, need not be
283 | included in conveying the object code work.
284 |
285 | A "User Product" is either (1) a "consumer product", which means any
286 | tangible personal property which is normally used for personal, family,
287 | or household purposes, or (2) anything designed or sold for incorporation
288 | into a dwelling. In determining whether a product is a consumer product,
289 | doubtful cases shall be resolved in favor of coverage. For a particular
290 | product received by a particular user, "normally used" refers to a
291 | typical or common use of that class of product, regardless of the status
292 | of the particular user or of the way in which the particular user
293 | actually uses, or expects or is expected to use, the product. A product
294 | is a consumer product regardless of whether the product has substantial
295 | commercial, industrial or non-consumer uses, unless such uses represent
296 | the only significant mode of use of the product.
297 |
298 | "Installation Information" for a User Product means any methods,
299 | procedures, authorization keys, or other information required to install
300 | and execute modified versions of a covered work in that User Product from
301 | a modified version of its Corresponding Source. The information must
302 | suffice to ensure that the continued functioning of the modified object
303 | code is in no case prevented or interfered with solely because
304 | modification has been made.
305 |
306 | If you convey an object code work under this section in, or with, or
307 | specifically for use in, a User Product, and the conveying occurs as
308 | part of a transaction in which the right of possession and use of the
309 | User Product is transferred to the recipient in perpetuity or for a
310 | fixed term (regardless of how the transaction is characterized), the
311 | Corresponding Source conveyed under this section must be accompanied
312 | by the Installation Information. But this requirement does not apply
313 | if neither you nor any third party retains the ability to install
314 | modified object code on the User Product (for example, the work has
315 | been installed in ROM).
316 |
317 | The requirement to provide Installation Information does not include a
318 | requirement to continue to provide support service, warranty, or updates
319 | for a work that has been modified or installed by the recipient, or for
320 | the User Product in which it has been modified or installed. Access to a
321 | network may be denied when the modification itself materially and
322 | adversely affects the operation of the network or violates the rules and
323 | protocols for communication across the network.
324 |
325 | Corresponding Source conveyed, and Installation Information provided,
326 | in accord with this section must be in a format that is publicly
327 | documented (and with an implementation available to the public in
328 | source code form), and must require no special password or key for
329 | unpacking, reading or copying.
330 |
331 | 7. Additional Terms.
332 |
333 | "Additional permissions" are terms that supplement the terms of this
334 | License by making exceptions from one or more of its conditions.
335 | Additional permissions that are applicable to the entire Program shall
336 | be treated as though they were included in this License, to the extent
337 | that they are valid under applicable law. If additional permissions
338 | apply only to part of the Program, that part may be used separately
339 | under those permissions, but the entire Program remains governed by
340 | this License without regard to the additional permissions.
341 |
342 | When you convey a copy of a covered work, you may at your option
343 | remove any additional permissions from that copy, or from any part of
344 | it. (Additional permissions may be written to require their own
345 | removal in certain cases when you modify the work.) You may place
346 | additional permissions on material, added by you to a covered work,
347 | for which you have or can give appropriate copyright permission.
348 |
349 | Notwithstanding any other provision of this License, for material you
350 | add to a covered work, you may (if authorized by the copyright holders of
351 | that material) supplement the terms of this License with terms:
352 |
353 | a) Disclaiming warranty or limiting liability differently from the
354 | terms of sections 15 and 16 of this License; or
355 |
356 | b) Requiring preservation of specified reasonable legal notices or
357 | author attributions in that material or in the Appropriate Legal
358 | Notices displayed by works containing it; or
359 |
360 | c) Prohibiting misrepresentation of the origin of that material, or
361 | requiring that modified versions of such material be marked in
362 | reasonable ways as different from the original version; or
363 |
364 | d) Limiting the use for publicity purposes of names of licensors or
365 | authors of the material; or
366 |
367 | e) Declining to grant rights under trademark law for use of some
368 | trade names, trademarks, or service marks; or
369 |
370 | f) Requiring indemnification of licensors and authors of that
371 | material by anyone who conveys the material (or modified versions of
372 | it) with contractual assumptions of liability to the recipient, for
373 | any liability that these contractual assumptions directly impose on
374 | those licensors and authors.
375 |
376 | All other non-permissive additional terms are considered "further
377 | restrictions" within the meaning of section 10. If the Program as you
378 | received it, or any part of it, contains a notice stating that it is
379 | governed by this License along with a term that is a further
380 | restriction, you may remove that term. If a license document contains
381 | a further restriction but permits relicensing or conveying under this
382 | License, you may add to a covered work material governed by the terms
383 | of that license document, provided that the further restriction does
384 | not survive such relicensing or conveying.
385 |
386 | If you add terms to a covered work in accord with this section, you
387 | must place, in the relevant source files, a statement of the
388 | additional terms that apply to those files, or a notice indicating
389 | where to find the applicable terms.
390 |
391 | Additional terms, permissive or non-permissive, may be stated in the
392 | form of a separately written license, or stated as exceptions;
393 | the above requirements apply either way.
394 |
395 | 8. Termination.
396 |
397 | You may not propagate or modify a covered work except as expressly
398 | provided under this License. Any attempt otherwise to propagate or
399 | modify it is void, and will automatically terminate your rights under
400 | this License (including any patent licenses granted under the third
401 | paragraph of section 11).
402 |
403 | However, if you cease all violation of this License, then your
404 | license from a particular copyright holder is reinstated (a)
405 | provisionally, unless and until the copyright holder explicitly and
406 | finally terminates your license, and (b) permanently, if the copyright
407 | holder fails to notify you of the violation by some reasonable means
408 | prior to 60 days after the cessation.
409 |
410 | Moreover, your license from a particular copyright holder is
411 | reinstated permanently if the copyright holder notifies you of the
412 | violation by some reasonable means, this is the first time you have
413 | received notice of violation of this License (for any work) from that
414 | copyright holder, and you cure the violation prior to 30 days after
415 | your receipt of the notice.
416 |
417 | Termination of your rights under this section does not terminate the
418 | licenses of parties who have received copies or rights from you under
419 | this License. If your rights have been terminated and not permanently
420 | reinstated, you do not qualify to receive new licenses for the same
421 | material under section 10.
422 |
423 | 9. Acceptance Not Required for Having Copies.
424 |
425 | You are not required to accept this License in order to receive or
426 | run a copy of the Program. Ancillary propagation of a covered work
427 | occurring solely as a consequence of using peer-to-peer transmission
428 | to receive a copy likewise does not require acceptance. However,
429 | nothing other than this License grants you permission to propagate or
430 | modify any covered work. These actions infringe copyright if you do
431 | not accept this License. Therefore, by modifying or propagating a
432 | covered work, you indicate your acceptance of this License to do so.
433 |
434 | 10. Automatic Licensing of Downstream Recipients.
435 |
436 | Each time you convey a covered work, the recipient automatically
437 | receives a license from the original licensors, to run, modify and
438 | propagate that work, subject to this License. You are not responsible
439 | for enforcing compliance by third parties with this License.
440 |
441 | An "entity transaction" is a transaction transferring control of an
442 | organization, or substantially all assets of one, or subdividing an
443 | organization, or merging organizations. If propagation of a covered
444 | work results from an entity transaction, each party to that
445 | transaction who receives a copy of the work also receives whatever
446 | licenses to the work the party's predecessor in interest had or could
447 | give under the previous paragraph, plus a right to possession of the
448 | Corresponding Source of the work from the predecessor in interest, if
449 | the predecessor has it or can get it with reasonable efforts.
450 |
451 | You may not impose any further restrictions on the exercise of the
452 | rights granted or affirmed under this License. For example, you may
453 | not impose a license fee, royalty, or other charge for exercise of
454 | rights granted under this License, and you may not initiate litigation
455 | (including a cross-claim or counterclaim in a lawsuit) alleging that
456 | any patent claim is infringed by making, using, selling, offering for
457 | sale, or importing the Program or any portion of it.
458 |
459 | 11. Patents.
460 |
461 | A "contributor" is a copyright holder who authorizes use under this
462 | License of the Program or a work on which the Program is based. The
463 | work thus licensed is called the contributor's "contributor version".
464 |
465 | A contributor's "essential patent claims" are all patent claims
466 | owned or controlled by the contributor, whether already acquired or
467 | hereafter acquired, that would be infringed by some manner, permitted
468 | by this License, of making, using, or selling its contributor version,
469 | but do not include claims that would be infringed only as a
470 | consequence of further modification of the contributor version. For
471 | purposes of this definition, "control" includes the right to grant
472 | patent sublicenses in a manner consistent with the requirements of
473 | this License.
474 |
475 | Each contributor grants you a non-exclusive, worldwide, royalty-free
476 | patent license under the contributor's essential patent claims, to
477 | make, use, sell, offer for sale, import and otherwise run, modify and
478 | propagate the contents of its contributor version.
479 |
480 | In the following three paragraphs, a "patent license" is any express
481 | agreement or commitment, however denominated, not to enforce a patent
482 | (such as an express permission to practice a patent or covenant not to
483 | sue for patent infringement). To "grant" such a patent license to a
484 | party means to make such an agreement or commitment not to enforce a
485 | patent against the party.
486 |
487 | If you convey a covered work, knowingly relying on a patent license,
488 | and the Corresponding Source of the work is not available for anyone
489 | to copy, free of charge and under the terms of this License, through a
490 | publicly available network server or other readily accessible means,
491 | then you must either (1) cause the Corresponding Source to be so
492 | available, or (2) arrange to deprive yourself of the benefit of the
493 | patent license for this particular work, or (3) arrange, in a manner
494 | consistent with the requirements of this License, to extend the patent
495 | license to downstream recipients. "Knowingly relying" means you have
496 | actual knowledge that, but for the patent license, your conveying the
497 | covered work in a country, or your recipient's use of the covered work
498 | in a country, would infringe one or more identifiable patents in that
499 | country that you have reason to believe are valid.
500 |
501 | If, pursuant to or in connection with a single transaction or
502 | arrangement, you convey, or propagate by procuring conveyance of, a
503 | covered work, and grant a patent license to some of the parties
504 | receiving the covered work authorizing them to use, propagate, modify
505 | or convey a specific copy of the covered work, then the patent license
506 | you grant is automatically extended to all recipients of the covered
507 | work and works based on it.
508 |
509 | A patent license is "discriminatory" if it does not include within
510 | the scope of its coverage, prohibits the exercise of, or is
511 | conditioned on the non-exercise of one or more of the rights that are
512 | specifically granted under this License. You may not convey a covered
513 | work if you are a party to an arrangement with a third party that is
514 | in the business of distributing software, under which you make payment
515 | to the third party based on the extent of your activity of conveying
516 | the work, and under which the third party grants, to any of the
517 | parties who would receive the covered work from you, a discriminatory
518 | patent license (a) in connection with copies of the covered work
519 | conveyed by you (or copies made from those copies), or (b) primarily
520 | for and in connection with specific products or compilations that
521 | contain the covered work, unless you entered into that arrangement,
522 | or that patent license was granted, prior to 28 March 2007.
523 |
524 | Nothing in this License shall be construed as excluding or limiting
525 | any implied license or other defenses to infringement that may
526 | otherwise be available to you under applicable patent law.
527 |
528 | 12. No Surrender of Others' Freedom.
529 |
530 | If conditions are imposed on you (whether by court order, agreement or
531 | otherwise) that contradict the conditions of this License, they do not
532 | excuse you from the conditions of this License. If you cannot convey a
533 | covered work so as to satisfy simultaneously your obligations under this
534 | License and any other pertinent obligations, then as a consequence you may
535 | not convey it at all. For example, if you agree to terms that obligate you
536 | to collect a royalty for further conveying from those to whom you convey
537 | the Program, the only way you could satisfy both those terms and this
538 | License would be to refrain entirely from conveying the Program.
539 |
540 | 13. Remote Network Interaction; Use with the GNU General Public License.
541 |
542 | Notwithstanding any other provision of this License, if you modify the
543 | Program, your modified version must prominently offer all users
544 | interacting with it remotely through a computer network (if your version
545 | supports such interaction) an opportunity to receive the Corresponding
546 | Source of your version by providing access to the Corresponding Source
547 | from a network server at no charge, through some standard or customary
548 | means of facilitating copying of software. This Corresponding Source
549 | shall include the Corresponding Source for any work covered by version 3
550 | of the GNU General Public License that is incorporated pursuant to the
551 | following paragraph.
552 |
553 | Notwithstanding any other provision of this License, you have
554 | permission to link or combine any covered work with a work licensed
555 | under version 3 of the GNU General Public License into a single
556 | combined work, and to convey the resulting work. The terms of this
557 | License will continue to apply to the part which is the covered work,
558 | but the work with which it is combined will remain governed by version
559 | 3 of the GNU General Public License.
560 |
561 | 14. Revised Versions of this License.
562 |
563 | The Free Software Foundation may publish revised and/or new versions of
564 | the GNU Affero General Public License from time to time. Such new versions
565 | will be similar in spirit to the present version, but may differ in detail to
566 | address new problems or concerns.
567 |
568 | Each version is given a distinguishing version number. If the
569 | Program specifies that a certain numbered version of the GNU Affero General
570 | Public License "or any later version" applies to it, you have the
571 | option of following the terms and conditions either of that numbered
572 | version or of any later version published by the Free Software
573 | Foundation. If the Program does not specify a version number of the
574 | GNU Affero General Public License, you may choose any version ever published
575 | by the Free Software Foundation.
576 |
577 | If the Program specifies that a proxy can decide which future
578 | versions of the GNU Affero General Public License can be used, that proxy's
579 | public statement of acceptance of a version permanently authorizes you
580 | to choose that version for the Program.
581 |
582 | Later license versions may give you additional or different
583 | permissions. However, no additional obligations are imposed on any
584 | author or copyright holder as a result of your choosing to follow a
585 | later version.
586 |
587 | 15. Disclaimer of Warranty.
588 |
589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
597 |
598 | 16. Limitation of Liability.
599 |
600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
608 | SUCH DAMAGES.
609 |
610 | 17. Interpretation of Sections 15 and 16.
611 |
612 | If the disclaimer of warranty and limitation of liability provided
613 | above cannot be given local legal effect according to their terms,
614 | reviewing courts shall apply local law that most closely approximates
615 | an absolute waiver of all civil liability in connection with the
616 | Program, unless a warranty or assumption of liability accompanies a
617 | copy of the Program in return for a fee.
618 |
619 | END OF TERMS AND CONDITIONS
620 |
621 | How to Apply These Terms to Your New Programs
622 |
623 | If you develop a new program, and you want it to be of the greatest
624 | possible use to the public, the best way to achieve this is to make it
625 | free software which everyone can redistribute and change under these terms.
626 |
627 | To do so, attach the following notices to the program. It is safest
628 | to attach them to the start of each source file to most effectively
629 | state the exclusion of warranty; and each file should have at least
630 | the "copyright" line and a pointer to where the full notice is found.
631 |
632 |
633 | Copyright (C)
634 |
635 | This program is free software: you can redistribute it and/or modify
636 | it under the terms of the GNU Affero General Public License as published
637 | by the Free Software Foundation, either version 3 of the License, or
638 | (at your option) any later version.
639 |
640 | This program is distributed in the hope that it will be useful,
641 | but WITHOUT ANY WARRANTY; without even the implied warranty of
642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643 | GNU Affero General Public License for more details.
644 |
645 | You should have received a copy of the GNU Affero General Public License
646 | along with this program. If not, see .
647 |
648 | Also add information on how to contact you by electronic and paper mail.
649 |
650 | If your software can interact with users remotely through a computer
651 | network, you should also make sure that it provides a way for users to
652 | get its source. For example, if your program is a web application, its
653 | interface could display a "Source" link that leads users to an archive
654 | of the code. There are many ways you could offer source, and different
655 | solutions will be better for different programs; see section 13 for the
656 | specific requirements.
657 |
658 | You should also get your employer (if you work as a programmer) or school,
659 | if any, to sign a "copyright disclaimer" for the program, if necessary.
660 | For more information on this, and how to apply and follow the GNU AGPL, see
661 | .
662 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Brennan Kinney
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BigLobby3
2 | BigLobby: No PDMod Required!
3 |
4 | # Credits:
5 | - Polarathene: Original version of the mod located here: https://github.com/polarathene/biglobby
6 | - steam-test1: Contributor to current/previous project
7 | - ZNix: SuperBLT creator, XML injection API used to obsolete the pdmod file
8 | - RESTORATION Mod team: Additional R&D
9 |
--------------------------------------------------------------------------------
/biglobby_tweak.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
--------------------------------------------------------------------------------
/hooks.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/l10n/english.json:
--------------------------------------------------------------------------------
1 | {
2 | "bkin_bl__menu__title" : "BigLobby Options",
3 | "bkin_bl__menu__desc" : "Set the player size of your hosted lobbies.",
4 | "bkin_bl__set_size__title" : "Set max lobby size",
5 | "bkin_bl__set_size__desc" : "How many players do you want to allow in your lobby?",
6 | "bkin_bl__allow_more_bots__title" : "Allow more bots in lobby",
7 | "bkin_bl__allow_more_bots__desc" : "Allows additional bots up to the set lobby size.",
8 | "bkin_bl__set_num_bots__title" : "Set max bots",
9 | "bkin_bl__set_num_bots__desc" : "How many Team AI bots will you allow ingame?",
10 | "bkin_bl__stop_all_bots__title" : "Stop All Bots",
11 | "bkin_bl__stop_all_bots__desc" : "Allows you to stop bots following in stealth",
12 | "bkin_bl__release_all_bots__title" : "Releases All Bots",
13 | "bkin_bl__release_all_bots__desc" : "",
14 | "bkin_bl__auto_stop_all_bots__title" : "Automatically Stop All Bots in stealth",
15 | "bkin_bl__auto_stop_all_bots__desc" : "Allows you to automatically stop all bots in stealth"
16 | }
--------------------------------------------------------------------------------
/l10n/russian.json:
--------------------------------------------------------------------------------
1 | {
2 | "bkin_bl__menu__title" : "BigLobby Настаройки",
3 | "bkin_bl__menu__desc" : "Задать количество игроков для лобби у своего хоста.",
4 | "bkin_bl__set_size__title" : "Задать максимальный размер лобби",
5 | "bkin_bl__set_size__desc" : "Скольким игрокам ты хочешь позволять в своем лобби? (*)",
6 | "bkin_bl__allow_more_bots__title" : "Позволить больше ботов в лобби",
7 | "bkin_bl__allow_more_bots__desc" : "Забить ботами пустые места в лобби.",
8 | "bkin_bl__set_num_bots__title" : "Максимум ботов",
9 | "bkin_bl__set_num_bots__desc" : "Сколько ботов добавить в игру? (*)",
10 | "bkin_bl__stop_all_bots__title" : "Остановить всех ботов",
11 | "bkin_bl__stop_all_bots__desc" : "Запретить ходить ботам в стелсе (*)",
12 | "bkin_bl__release_all_bots__title" : "Распустить ботов",
13 | "bkin_bl__release_all_bots__desc" : "",
14 | "bkin_bl__auto_stop_all_bots__title" : "Автоматическая остановка всех ботов в стелсе",
15 | "bkin_bl__auto_stop_all_bots__desc" : "Даёт возможность автоматической остановки всех ботов в стелсе"
16 | }
--------------------------------------------------------------------------------
/l10n/schinese.json:
--------------------------------------------------------------------------------
1 | {
2 | "bkin_bl__menu__title" : "巨无霸大厅选项",
3 | "bkin_bl__menu__desc" : "设置您主持的大厅人数大小。",
4 | "bkin_bl__set_size__title" : "设置大厅大小",
5 | "bkin_bl__set_size__desc" : "您想允许多少玩家进入您的大厅?",
6 | "bkin_bl__allow_more_bots__title" : "允许更多人机",
7 | "bkin_bl__allow_more_bots__desc" : "允许加入更多的人机,数量为您设定的大厅大小的余位。",
8 | "bkin_bl__set_num_bots__title" : "最大人机数量",
9 | "bkin_bl__set_num_bots__desc" : "在游戏内您想允许多少人机出现?",
10 | "bkin_bl__stop_all_bots__title" : "暂停所有人机",
11 | "bkin_bl__stop_all_bots__desc" : "允许您在潜入时命令人机不要跟随您。",
12 | "bkin_bl__release_all_bots__title" : "释放所有人机",
13 | "bkin_bl__release_all_bots__desc" : "释放所有被暂停的人机。",
14 | "bkin_bl__auto_stop_all_bots__title" : "潜入时自动暂停所有人机",
15 | "bkin_bl__auto_stop_all_bots__desc" : "在潜入时自动允许人机不再跟随您。"
16 | }
--------------------------------------------------------------------------------
/lua/_custom/biglobby_globals.lua:
--------------------------------------------------------------------------------
1 | if not Global.BigLobbyPersist then
2 | Global.BigLobbyPersist = {
3 | num_players = nil -- Set when joining lobbies, nil'd upon leaving
4 | }
5 | end
6 |
7 |
8 | if not _G.BigLobbyGlobals then
9 | _G.BigLobbyGlobals = {}
10 |
11 | -- Settings affected by BigLobby Mod Options
12 | BigLobbyGlobals.num_players_settings = nil
13 | BigLobbyGlobals.num_bots_settings = nil
14 | BigLobbyGlobals.allow_more_bots_settings = nil
15 | BigLobbyGlobals.auto_stop_all_bots_settings = nil
16 |
17 | -- Load custom lua files without specifying them in mod.txt --
18 | BigLobbyGlobals.ModPath = ModPath
19 | BigLobbyGlobals.SavePath = SavePath
20 |
21 | BigLobbyGlobals.ClassPath = "lua/_custom/"
22 |
23 | BigLobbyGlobals.Classes = {
24 | "menu.lua",
25 | "husl.lua"
26 | }
27 |
28 | for _, class in pairs(BigLobbyGlobals.Classes) do
29 | dofile(BigLobbyGlobals.ModPath .. BigLobbyGlobals.ClassPath .. class)
30 | end
31 | -- End custom lua load --
32 |
33 |
34 | -- Initializing menu will apply the default/saved settings
35 | BigLobbyGlobals.Menu = bkin_bl__menu:new()
36 |
37 | -- Set to the size of lobby you join, otherwise use your lobby size preferences for hosting
38 | BigLobbyGlobals.num_players = Global.BigLobbyPersist.num_players or BigLobbyGlobals.num_players_settings
39 |
40 |
41 | function BigLobbyGlobals:num_player_slots()
42 | return self.num_players
43 | end
44 |
45 |
46 | -- It's probably not going to cause any problems, but I'm capping the
47 | -- bot_slots to the lobby size just in case
48 | function BigLobbyGlobals:num_bot_slots()
49 | return math.min(self.num_bots_settings, self:num_player_slots())
50 | end
51 |
52 |
53 | -- Regular lobby / Seamless switching support
54 | function BigLobbyGlobals:is_small_lobby()
55 | --TODO: Changing lobby slot size without reloading mods such as in
56 | -- Crime.Net won't properly update filters. Don't enable until working better
57 | return false --self.num_players<=4
58 | end
59 |
60 |
61 | -- Semantic versioning
62 | function BigLobbyGlobals:version()
63 | return "3.27.6"
64 | end
65 |
66 |
67 | -- GameVersion for matchmaking, integer is expected
68 | function BigLobbyGlobals:gameversion()
69 | return 3276
70 | end
71 |
72 |
73 | -- These tables show the network messages we've modified in the network settings pdmod
74 | -- We will use them for switching to biglobby prefixed messages when in big lobbies.
75 | local connection_network_handler_funcs = {
76 | 'kick_peer',
77 | 'remove_peer_confirmation',
78 | 'join_request_reply',
79 | 'peer_handshake',
80 | 'peer_exchange_info',
81 | 'connection_established',
82 | 'mutual_connection',
83 | 'set_member_ready',
84 | 'request_drop_in_pause',
85 | 'drop_in_pause_confirmation',
86 | 'set_peer_synched',
87 | 'dropin_progress',
88 | 'report_dead_connection',
89 | 'preplanning_reserved',
90 | 'draw_preplanning_event',
91 | 'sync_explode_bullet',
92 | 'sync_flame_bullet',
93 | 'sync_crime_spree_level',
94 | 'sync_player_installed_mod'
95 | }
96 |
97 | local unit_network_handler_funcs = {
98 | 'set_unit',
99 | 'remove_corpse_by_id',
100 | 'mission_ended',
101 | 'sync_trip_mine_setup',
102 | 'from_server_sentry_gun_place_result',
103 | 'place_sentry_gun',
104 | 'picked_up_sentry_gun',
105 | 'sync_equipment_setup',
106 | 'sync_ammo_bag_setup',
107 | 'on_sole_criminal_respawned',
108 | 'sync_grenades',
109 | 'sync_carry_data',
110 | 'sync_throw_projectile',
111 | 'sync_attach_projectile',
112 | 'sync_unlock_asset',
113 | 'sync_equipment_possession',
114 | 'sync_remove_equipment_possession',
115 | 'mark_minion',
116 | 'sync_statistics_result',
117 | 'suspicion',
118 | 'sync_enter_vehicle_host',
119 | 'sync_vehicle_player',
120 | 'sync_exit_vehicle',
121 | 'server_give_vehicle_loot_to_player',
122 | 'sync_give_vehicle_loot_to_player',
123 | 'sync_vehicle_interact_trunk',
124 | 'server_secure_loot',
125 | 'sync_secure_loot'
126 | }
127 |
128 | -- Builds a single table from our two string based keys for each handler above
129 | BigLobbyGlobals.network_handler_funcs = {}
130 | function add_handler_funcs(handler_funcs)
131 | for i = 1, #handler_funcs do
132 | BigLobbyGlobals.network_handler_funcs[handler_funcs[i]] = true
133 | end
134 | end
135 |
136 | add_handler_funcs(connection_network_handler_funcs)
137 | add_handler_funcs(unit_network_handler_funcs)
138 |
139 |
140 | -- Takes the network keys we defined above and prefixes any matches on the given handler
141 | function BigLobbyGlobals:rename_handler_funcs(NetworkHandler)
142 | for key, value in pairs(BigLobbyGlobals.network_handler_funcs) do
143 | if NetworkHandler[key] then
144 | NetworkHandler['biglobby__' .. key] = NetworkHandler[key]
145 | end
146 | end
147 | end
148 |
149 |
150 | -- Nothing calls this anymore for the time being.
151 | local log_data = true -- Can use to turn the logging on/off
152 | function BigLobbyGlobals:logger(content, use_chat)
153 | if log_data then
154 | if not content then return end
155 |
156 | if use_chat then
157 | managers.chat:_receive_message(ChatManager.GAME, "BigLobby", content, tweak_data.system_chat_color)
158 | end
159 |
160 | log(content)
161 | end
162 | end
163 |
164 | end
165 |
--------------------------------------------------------------------------------
/lua/_custom/husl.lua:
--------------------------------------------------------------------------------
1 | -- HUSLP implementation from: https://github.com/husl-colors/husl-lua/blob/master/husl.lua
2 | -- I've modified it so all variables are tied to the `husl` table. PD2 also seems
3 | -- to return degrees and use degrees as input instead of radians for math functions.
4 | -- I've made adjustments to these methods commenting out the original to correct this.
5 | if not _G.HUSL then
6 | -- Version: 1.0.0
7 | -- public api
8 |
9 | local husl = {}
10 |
11 | husl._m = {
12 | { 3.240454162114103, -1.537138512797715, -0.49853140955601},
13 | {-0.96926603050518, 1.876010845446694, 0.041556017530349},
14 | { 0.055643430959114, -0.20402591351675, 1.057225188223179}
15 | }
16 | -- hard-coded d65 illuminant
17 | husl._refX = 0.95047
18 | husl._refY = 1.00000
19 | husl._refZ = 1.08883
20 | husl._refU = (4 * husl._refX) / (husl._refX + (15 * husl._refY) + (3 * husl._refZ))
21 | husl._refV = (9 * husl._refY) / (husl._refX + (15 * husl._refY) + (3 * husl._refZ))
22 |
23 | husl._kappa = 24389 / 27
24 | husl._epsilon = 216 / 24389
25 |
26 | function husl.husl_to_rgb(h, s, l)
27 | return husl.lch_to_rgb(husl.husl_to_lch(h, s, l))
28 | end
29 |
30 | function husl.husl_to_hex(h, s, l)
31 | return husl.rgb_to_hex(husl.husl_to_rgb(h, s, l))
32 | end
33 |
34 | function husl.rgb_to_husl(r, g, b)
35 | return husl.lch_to_husl(husl.rgb_to_lch(r, g, b))
36 | end
37 |
38 | function husl.hex_to_husl(hex)
39 | return husl.rgb_to_husl(husl.hex_to_rgb(hex))
40 | end
41 |
42 | function husl.huslp_to_rgb(h, s, l)
43 | return husl.lch_to_rgb(husl.huslp_to_lch(h, s, l))
44 | end
45 |
46 | function husl.huslp_to_hex(h, s, l)
47 | return husl.rgb_to_hex(husl.huslp_to_rgb(h, s, l))
48 | end
49 |
50 | function husl.rgb_to_huslp(r, g, b)
51 | return husl.lch_to_huslp(husl.rgb_to_lch(r, g, b))
52 | end
53 |
54 | function husl.hex_to_huslp(hex)
55 | return husl.rgb_to_huslp(husl.hex_to_rgb(hex))
56 | end
57 |
58 | function husl.lch_to_rgb(l, c, h)
59 | return husl.xyz_to_rgb(husl.luv_to_xyz(husl.lch_to_luv(l, c, h)))
60 | end
61 |
62 | function husl.rgb_to_lch(r, g, b)
63 | return husl.luv_to_lch(husl.xyz_to_luv(husl.rgb_to_xyz(r, g, b)))
64 | end
65 |
66 | function husl.max_chroma(L, H)
67 | -- local hrad = math.rad(H)
68 | local hrad = H
69 | local sinH = math.sin(hrad)
70 | local cosH = math.cos(hrad)
71 | local sub1 = math.pow(L + 16, 3) / 1560896
72 | local sub2 = (sub1 > husl._epsilon) and sub1 or (L / husl._kappa)
73 |
74 | local result = math.huge
75 |
76 | for _, row in ipairs(husl._m) do
77 | local m1, m2, m3 = unpack(row)
78 |
79 | local top = (12739311 * m3 + 11700000 * m2 + 11120499 * m1) * sub2
80 | local rbottom = 9608480 * m3 - 1921696 * m2
81 | local lbottom = 1441272 * m3 - 4323816 * m1
82 |
83 | local bottom = (rbottom * sinH + lbottom * cosH) * sub2
84 |
85 | local C0 = L * top / bottom
86 | local C1 = L * (top - 11700000) / (bottom + 1921696 * sinH)
87 |
88 | if C0 > 0 and C0 < result then
89 | result = C0
90 | end
91 |
92 | if C1 > 0 and C1 < result then
93 | result = C1
94 | end
95 | end
96 |
97 | return result
98 | end
99 |
100 | function husl.hrad_extremum(L)
101 | local lhs = (math.pow(L, 3) + 48 * math.pow(L, 2) + 768 * L + 4096) / 1560896
102 | local rhs = husl._epsilon
103 | local sub = (lhs > rhs) and lhs or L / husl._kappa
104 |
105 | local chroma = math.huge
106 | local result = nil
107 |
108 | for _, row in ipairs(husl._m) do
109 | local m1, m2, m3 = unpack(row)
110 | local bottom = (3 * m3 - 9 * m1) * sub
111 |
112 | for limit=0,1 do
113 | local top = (20 * m3 - 4 * m2) * sub + 4 * limit
114 | -- local hrad = math.atan2(top, bottom)
115 | local hrad = math.rad(math.atan2(top, bottom))
116 |
117 | -- This is a math hack to deal with tan quadrants, I'm too lazy to figure
118 | -- out how to do this properly
119 | if limit == 1 then
120 | hrad = hrad + math.pi
121 | end
122 |
123 | local test = husl.max_chroma(L, math.deg(hrad))
124 |
125 | if test < chroma then
126 | chroma = test
127 | result = hrad
128 | end
129 | end
130 | end
131 |
132 | return result
133 | end
134 |
135 | function husl.max_chroma_pastel(L)
136 | local H = math.deg(husl.hrad_extremum(L))
137 |
138 | return husl.max_chroma(L, H)
139 | end
140 |
141 | function husl.dot_product(a, b)
142 | local sum = 0
143 |
144 | for i=1,#a do
145 | sum = sum + a[i] * b[i]
146 | end
147 |
148 | return sum
149 | end
150 |
151 | function husl.f(t)
152 | if t > husl._epsilon then
153 | return 116 * math.pow((t / husl._refY), 1 / 3) - 16
154 | else
155 | return t / husl._refY * husl._kappa
156 | end
157 | end
158 |
159 | function husl.f_inv(t)
160 | if t > 8 then
161 | return husl._refY * math.pow((t + 16) / 116, 3)
162 | else
163 | return husl._refY * t / husl._kappa
164 | end
165 | end
166 |
167 | function husl.from_linear(c)
168 | if c <= 0.0031308 then
169 | return 12.92 * c
170 | else
171 | return 1.055 * math.pow(c, 1 / 2.4) - 0.055
172 | end
173 | end
174 |
175 | function husl.to_linear(c)
176 | local a = 0.055
177 |
178 | if c > 0.04045 then
179 | return math.pow((c + a) / (1 + a), 2.4)
180 | else
181 | return c / 12.92
182 | end
183 | end
184 |
185 | function husl.round(number, digits)
186 | local f = math.pow(10, digits or 0)
187 |
188 | return math.floor(number * f + 0.5) / f
189 | end
190 |
191 | function husl.rgb_prepare(r, g, b)
192 | local prepared = {}
193 |
194 | for i, component in ipairs{r, g, b} do
195 | component = husl.round(component, 3)
196 |
197 | assert(component >= -0.0001 and component <= 1.0001, "illegal rgb value " .. component)
198 |
199 | component = math.min(1, math.max(component, 0))
200 |
201 | prepared[i] = husl.round(component * 255)
202 | end
203 |
204 | return unpack(prepared)
205 | end
206 |
207 | function husl.hex_to_rgb(hex)
208 | hex = hex:gsub("#", "")
209 |
210 | local r = tonumber(hex:sub(1,2), 16) / 255
211 | local g = tonumber(hex:sub(3,4), 16) / 255
212 | local b = tonumber(hex:sub(5,6), 16) / 255
213 |
214 | return r, g, b
215 | end
216 |
217 | function husl.rgb_to_hex(r, g, b)
218 | return string.format("#%02x%02x%02x", husl.rgb_prepare(r, g, b))
219 | end
220 |
221 | function husl.xyz_to_rgb(x, y, z)
222 | local rgb = {}
223 |
224 | for i, row in ipairs(husl._m) do
225 | rgb[i] = husl.from_linear(husl.dot_product(row, {x, y, z}))
226 | end
227 |
228 | return unpack(rgb)
229 | end
230 |
231 | function husl.rgb_to_xyz(r, g, b)
232 | local rgb = {
233 | husl.to_linear(r),
234 | husl.to_linear(g),
235 | husl.to_linear(b),
236 | }
237 |
238 | local xyz = {}
239 | local m_inv = {
240 | {0.41245643908969, 0.3575760776439, 0.18043748326639 },
241 | {0.21267285140562, 0.71515215528781, 0.072174993306559},
242 | {0.019333895582329, 0.1191920258813, 0.95030407853636 }
243 | }
244 |
245 | for i, row in ipairs(m_inv) do
246 | xyz[i] = husl.dot_product(row, rgb)
247 | end
248 |
249 | return unpack(xyz)
250 | end
251 |
252 | function husl.xyz_to_luv(X, Y, Z)
253 | if X == 0 and Y == 0 and Z == 0 then
254 | return 0, 0, 0
255 | end
256 |
257 | local varU = (4 * X) / (X + (15 * Y) + (3 * Z))
258 | local varV = (9 * Y) / (X + (15 * Y) + (3 * Z))
259 | local L = husl.f(Y)
260 |
261 | -- Black will create a divide-by-zero error
262 | if L == 0.0 then
263 | return 0, 0, 0
264 | end
265 |
266 | local U = 13 * L * (varU - husl._refU)
267 | local V = 13 * L * (varV - husl._refV)
268 |
269 | return L, U, V
270 | end
271 |
272 | function husl.luv_to_xyz(L, U, V)
273 | if L == 0 then
274 | return 0, 0, 0
275 | end
276 |
277 | local varY = husl.f_inv(L)
278 | local varU = U / (13 * L) + husl._refU
279 | local varV = V / (13 * L) + husl._refV
280 | local Y = varY * husl._refY
281 | local X = -(9 * Y * varU) / ((varU - 4) * varV - varU * varV)
282 | local Z = (9 * Y - (15 * varV * Y) - (varV * X)) / (3 * varV)
283 |
284 | return X, Y, Z
285 | end
286 |
287 | function husl.luv_to_lch(L, U, V)
288 | local C = (math.pow(math.pow(U, 2) + math.pow(V, 2), 0.5))
289 | local hrad = (math.atan2(V, U))
290 |
291 | -- local H = math.deg(hrad)
292 | local H = hrad
293 |
294 | if H < 0 then
295 | H = 360 + H
296 | end
297 |
298 | return L, C, H
299 | end
300 |
301 | function husl.lch_to_luv(L, C, H)
302 | -- local Hrad = math.rad(H)
303 | local Hrad = H
304 | local U = math.cos(Hrad) * C
305 | local V = math.sin(Hrad) * C
306 |
307 | return L, U, V
308 | end
309 |
310 | function husl.husl_to_lch(H, S, L)
311 | if L > 99.9999999 then
312 | return 100, 0, H
313 | elseif L < 0.00000001 then
314 | return 0, 0, H
315 | end
316 |
317 | local mx = husl.max_chroma(L, H)
318 | local C = mx / 100 * S
319 |
320 | return L, C, H
321 | end
322 |
323 | function husl.lch_to_husl(L, C, H)
324 | if L > 99.9999999 then
325 | return H, 0, 100
326 | elseif L < 0.00000001 then
327 | return H, 0, 0
328 | end
329 |
330 | local mx = husl.max_chroma(L, H)
331 | local S = C / mx * 100
332 |
333 | return H, S, L
334 | end
335 |
336 | function husl.huslp_to_lch(H, S, L)
337 | if L > 99.9999999 then
338 | return 100, 0, H
339 | elseif L < 0.00000001 then
340 | return 0, 0, H
341 | end
342 |
343 | local mx = husl.max_chroma_pastel(L)
344 | local C = mx / 100 * S
345 |
346 | return L, C, H
347 | end
348 |
349 | function husl.lch_to_huslp(L, C, H)
350 | if L > 99.9999999 then
351 | return H, 0, 100
352 | elseif L < 0.00000001 then
353 | return H, 0, 0
354 | end
355 |
356 | local mx = husl.max_chroma_pastel(L)
357 | local S = C / mx * 100
358 |
359 | return H, S, L
360 | end
361 |
362 | _G.HUSL = husl
363 | end
364 |
--------------------------------------------------------------------------------
/lua/_custom/menu.lua:
--------------------------------------------------------------------------------
1 | bkin_bl__menu = bkin_bl__menu or class()
2 | bkin_bl__menu.menu_id = "bkin_bl__menu"
3 | bkin_bl__menu._data_path = BigLobbyGlobals.SavePath .. "big_lobby_new.json"
4 | bkin_bl__menu._data = bkin_bl__menu._data or {}
5 |
6 |
7 | function bkin_bl__menu:init()
8 | -- Load the user options
9 | self:Load()
10 |
11 | -- The new player limit is defined here, it should not be greater than
12 | -- the max values set in the network setting file.
13 | self._constants = {}
14 | self._constants.MAX_SLOTS = 128
15 | self._constants.UNIQUE_HEISTERS = 21
16 | self._data.lobby_size = self._data.lobby_size or 22
17 | self._data.allow_more_bots = self._data.allow_more_bots
18 | self._data.num_bots = self._data.num_bots or self._constants.UNIQUE_HEISTERS
19 | self._data.auto_stop_all_bots = self._data.auto_stop_all_bots or true
20 |
21 | -- Apply 'settings' values to BigLobbyGlobals
22 | BigLobbyGlobals.num_players_settings = self._data.lobby_size
23 | BigLobbyGlobals.allow_more_bots_settings = self._data.allow_more_bots
24 | BigLobbyGlobals.num_bots_settings = self._data.num_bots
25 | BigLobbyGlobals.auto_stop_all_bots_settings = self._data.auto_stop_all_bots
26 |
27 | -- Register the hooks for creating the option menu
28 | self:RegisterHooks()
29 | end
30 |
31 |
32 | function bkin_bl__menu:Save()
33 | local file = io.open( self._data_path, "w+" )
34 |
35 | if file then
36 | local json_enc = json.encode( self._data )
37 |
38 | -- Prevents BLT crash bug when trying to parse empty brackets [], empty braces {} are fine though
39 | file:write( json_enc ~= "[]" and json_enc or "{}" )
40 | file:close()
41 | end
42 | end
43 |
44 |
45 | function bkin_bl__menu:Load()
46 | local file = io.open( self._data_path, "r" )
47 |
48 | if file then
49 | self._data = json.decode( file:read("*all") )
50 | file:close()
51 | end
52 | end
53 |
54 |
55 | function bkin_bl__menu:RegisterHooks()
56 | Hooks:Add("LocalizationManagerPostInit", "LocalizationManagerPostInit__bkin_bl", function(loc)
57 | if not language_filename then
58 | local selected_language = SystemInfo:language():key()
59 | local found_language = false
60 |
61 | for _, filename in pairs(file.GetFiles(BigLobbyGlobals.ModPath .. 'l10n/')) do
62 | local str = filename:match('^(.*).json$')
63 | if str and Idstring(str) and Idstring(str):key() == selected_language then
64 | language_filename = filename
65 | found_language = true
66 | break
67 | end
68 | end
69 |
70 | if not found_language then
71 | language_filename = "english.json"
72 | end
73 | end
74 |
75 | if language_filename then
76 | loc:load_localization_file(BigLobbyGlobals.ModPath .. 'l10n/' .. language_filename)
77 | end
78 | end)
79 |
80 |
81 | Hooks:Add("MenuManagerSetupCustomMenus", "MenuManagerSetupCustomMenus__bkin_bl", function( menu_manager, nodes )
82 | MenuHelper:NewMenu( self.menu_id )
83 | end)
84 |
85 |
86 | -- Menu Components and Callbacks
87 | Hooks:Add("MenuManagerPopulateCustomMenus", "MenuManagerPopulateCustomMenus__bkin_bl", function( menu_manager, nodes )
88 | --Callbacks update data used by mod and for saving to file after user changes value
89 | MenuCallbackHandler.bkin_bl__set_size__clbk = function(menu_clbk, item)
90 | local num = math.floor( item:value() )
91 |
92 | item:set_value(num) -- Update the slider display to avoid floating point numbers
93 | self._data.lobby_size = num -- Update so it can be saved
94 | BigLobbyGlobals.num_players_settings = num -- The variable that BigLobby references
95 |
96 | self:Save()
97 | end
98 |
99 | MenuCallbackHandler.bkin_bl__allow_more_bots__clbk = function(menu_clbk, item)
100 | local allow = ( item:value() == "on" and true or false )
101 |
102 | item:set_value(allow)
103 | self._data.allow_more_bots = allow
104 | BigLobbyGlobals.allow_more_bots_settings = allow
105 |
106 | self:Save()
107 | end
108 |
109 | MenuCallbackHandler.bkin_bl__set_num_bots__clbk = function(menu_clbk, item)
110 | local num = math.floor( item:value() )
111 |
112 | item:set_value(num)
113 | self._data.num_bots = num
114 | BigLobbyGlobals.num_bots_settings = num
115 |
116 | self:Save()
117 | end
118 |
119 | MenuCallbackHandler.bkin_bl__auto_stop_all_bots__clbk = function(menu_clbk, item)
120 | local allow = ( item:value() == "on" and true or false )
121 |
122 | item:set_value(allow)
123 | self._data.auto_stop_all_bots = allow
124 | BigLobbyGlobals.auto_stop_all_bots_settings = allow
125 |
126 | self:Save()
127 | end
128 |
129 |
130 | MenuHelper:AddSlider({
131 | id = "lobby_size", --ID only needs to be unique in the scope of the options node we are creating
132 | title = "bkin_bl__set_size__title",
133 | desc = "bkin_bl__set_size__desc",
134 | callback = "bkin_bl__set_size__clbk",
135 | value = self._data.lobby_size,
136 | min = 4,
137 | max = 22,
138 | step = 1,
139 | show_value = true,
140 | menu_id = self.menu_id,
141 | priority = 20
142 | })
143 |
144 | MenuHelper:AddToggle({
145 | id = "num_bots_toggle",
146 | title = "bkin_bl__allow_more_bots__title",
147 | desc = "bkin_bl__allow_more_bots__desc",
148 | callback = "bkin_bl__allow_more_bots__clbk",
149 | value = self._data.allow_more_bots,
150 | menu_id = self.menu_id,
151 | priority = 30
152 | })
153 |
154 | MenuHelper:AddSlider({
155 | id = "num_bots",
156 | title = "bkin_bl__set_num_bots__title",
157 | desc = "bkin_bl__set_num_bots__desc",
158 | callback = "bkin_bl__set_num_bots__clbk",
159 | value = self._data.num_bots,
160 | min = 3,
161 | max = 21,
162 | step = 1,
163 | show_value = true,
164 | menu_id = self.menu_id,
165 | priority = 10
166 | })
167 |
168 | -- MenuHelper:AddToggle({
169 | -- id = "auto_stop_all_bots_toggle",
170 | -- title = "bkin_bl__auto_stop_all_bots__title",
171 | -- desc = "bkin_bl__auto_stop_all_bots__desc",
172 | -- callback = "bkin_bl__auto_stop_all_bots__clbk",
173 | -- value = self._data.auto_stop_all_bots,
174 | -- menu_id = self.menu_id,
175 | -- priority = 6
176 | -- })
177 |
178 | local mod = BLT.Mods.GetModOwnerOfFile and BLT.Mods:GetModOwnerOfFile(BigLobbyGlobals.ModPath) or BLT.Mods.GetMod and BLT.Mods:GetMod("BigLobby3-master")
179 | if not mod then
180 | return
181 | end
182 |
183 | BLT.Keybinds:register_keybind(mod, { id = "bkin_bl__stop_all_bots", allow_game = true, show_in_menu = false, callback = function()
184 | for _, ai in pairs(managers.groupai:state():all_AI_criminals()) do
185 | ai.unit:movement():set_should_stay(true)
186 | end
187 | end })
188 | local bind = BLT.Keybinds:get_keybind("bkin_bl__stop_all_bots")
189 | local key = bind and bind:Key() or ""
190 |
191 | MenuHelper:AddKeybinding({
192 | id = "bkin_bl__stop_all_bots",
193 | title = "bkin_bl__stop_all_bots__title",
194 | desc= "bkin_bl__stop_all_bots__desc",
195 | connection_name = "bkin_bl__stop_all_bots",
196 | binding = key,
197 | button = key,
198 | menu_id = self.menu_id,
199 | priority = 5
200 | })
201 |
202 | BLT.Keybinds:register_keybind(mod, { id = "bkin_bl__release_all_bots", allow_game = true, show_in_menu = false, callback = function()
203 | for _, ai in pairs(managers.groupai:state():all_AI_criminals()) do
204 | ai.unit:movement():set_should_stay(false)
205 | end
206 | end })
207 | local bind = BLT.Keybinds:get_keybind("bkin_bl__release_all_bots")
208 | local key = bind and bind:Key() or ""
209 |
210 | MenuHelper:AddKeybinding({
211 | id = "bkin_bl__release_all_bots",
212 | title = "bkin_bl__release_all_bots__title",
213 | desc= "bkin_bl__release_all_bots__desc",
214 | connection_name = "bkin_bl__release_all_bots",
215 | binding = key,
216 | button = key,
217 | menu_id = self.menu_id,
218 | priority = 4
219 | })
220 | end)
221 |
222 |
223 | Hooks:Add("MenuManagerBuildCustomMenus", "MenuManagerBuildCustomMenus__bkin_bl", function(menu_manager, nodes)
224 | nodes[self.menu_id] = MenuHelper:BuildMenu( self.menu_id )
225 | MenuHelper:AddMenuItem( nodes["blt_options"], self.menu_id, "bkin_bl__menu__title", "bkin_bl__menu__desc", 1 )
226 | end)
227 | end
--------------------------------------------------------------------------------
/lua/lib/managers/_achievementmanager.lua:
--------------------------------------------------------------------------------
1 | -- Disable achievement progress if lobby size is greater than 4 players.
2 | local orig__AchievmentManager = {
3 | award = AchievmentManager.award,
4 | _give_reward = AchievmentManager._give_reward,
5 | award_progress = AchievmentManager.award_progress,
6 | award_steam = AchievmentManager.award_steam,
7 | steam_unlock_result = AchievmentManager.steam_unlock_result,
8 | award_epic = AchievmentManager.award_epic,
9 | epic_unlock_result = AchievmentManager.epic_unlock_result
10 | }
11 |
12 |
13 | function AchievmentManager:disable_achievements()
14 | -- `managers.network:session()` is here to prevent false positive, you should
15 | -- be able to unlock achievements while not in a game and have the mod enabled
16 | local m_session = managers.network:session()
17 |
18 | local isRegularAmount = m_session and (m_session:amount_of_players() > 4)
19 | local isRegularSize = m_session and BigLobbyGlobals:is_small_lobby()
20 |
21 | return isRegularAmount or isRegularSize
22 | end
23 |
24 |
25 | function AchievmentManager.award(self, ...)
26 | if not self:disable_achievements() then
27 | orig__AchievmentManager.award(self, ...)
28 | end
29 | end
30 |
31 |
32 | function AchievmentManager._give_reward(self, ...)
33 | if not self:disable_achievements() then
34 | orig__AchievmentManager._give_reward(self, ...)
35 | end
36 | end
37 |
38 |
39 | function AchievmentManager.award_progress(self, ...)
40 | if not self:disable_achievements() then
41 | orig__AchievmentManager.award_progress(self, ...)
42 | end
43 | end
44 |
45 |
46 | function AchievmentManager.award_steam(self, ...)
47 | if not self:disable_achievements() then
48 | orig__AchievmentManager.award_steam(self, ...)
49 | end
50 | end
51 |
52 |
53 | -- Original is defined in dot notation, presumably doesn't expect self to be
54 | -- passed in as first param?
55 | function AchievmentManager.steam_unlock_result(...)
56 | if not AchievmentManager:disable_achievements() then
57 | orig__AchievmentManager.steam_unlock_result(...)
58 | end
59 | end
60 |
61 | function AchievmentManager:award_epic(...)
62 | if not self:disable_achievements() then
63 | orig__AchievmentManager.award_epic(...)
64 | end
65 | end
66 |
67 | function AchievmentManager.epic_unlock_result(...)
68 | if not self:disable_achievements() then
69 | orig__AchievmentManager.epic_unlock_result(...)
70 | end
71 | end
--------------------------------------------------------------------------------
/lua/lib/managers/_criminalsmanager.lua:
--------------------------------------------------------------------------------
1 | if Global.load_level == true and Global.game_settings.level_id == "vit" then return end
2 | if Global.load_level == true and Global.game_settings.level_id == "pex" then return end
3 |
4 | if BigLobbyGlobals.allow_more_bots_settings then
5 | CriminalsManager.MAX_NR_TEAM_AI = BigLobbyGlobals:num_bot_slots()
6 | end
7 | -- Not sure how useful this is, just updating it in case.
8 | CriminalsManager.MAX_NR_CRIMINALS = BigLobbyGlobals:num_player_slots()
--------------------------------------------------------------------------------
/lua/lib/managers/_hudmanager.lua:
--------------------------------------------------------------------------------
1 | -- Modified to prevent UI bug, local player is no longer panel index 4, but a dynamic
2 | -- value set to `HUDManager.PLAYER_PANEL`.
3 | if BL2Options then return end
4 | function HUDManager:reset_player_hpbar()
5 | -- Only code changed was replacing two values hardcoded as 4 with the variable HUDManager.PLAYER_PANEL
6 | local crim_entry = managers.criminals:character_static_data_by_name(managers.criminals:local_character_name())
7 | if not crim_entry then
8 | return
9 | end
10 | local color_id = managers.network:session():local_peer():id()
11 | self:set_teammate_callsign(HUDManager.PLAYER_PANEL, color_id)
12 | self:set_teammate_name(HUDManager.PLAYER_PANEL, managers.network:session():local_peer():name())
13 | end
14 |
--------------------------------------------------------------------------------
/lua/lib/managers/_hudmanagerpd2.lua:
--------------------------------------------------------------------------------
1 | -- This references 4 as in the 4th panel on the UI(one on the furtherest right) by default.
2 | -- Otherwise known as the local players UI panel.
3 | -- By updating this value, we keep that consistency that the player is used to.
4 | HUDManager.PLAYER_PANEL = BigLobbyGlobals:num_player_slots()
5 | if BL2Options then return end
6 | --Nothing seems to call this, I don't think it's even used.. Panels are created somewhere else
7 | function HUDManager:_create_teammates_panel(hud)
8 | hud = hud or managers.hud:script(PlayerBase.PLAYER_INFO_HUD_PD2)
9 | self._hud.teammate_panels_data = self._hud.teammate_panels_data or {}
10 | self._teammate_panels = {}
11 | if hud.panel:child("teammates_panel") then
12 | hud.panel:remove(hud.panel:child("teammates_panel"))
13 | end
14 | local h = self:teampanels_height()
15 | local teammates_panel = hud.panel:panel({
16 | name = "teammates_panel",
17 | h = h,
18 | y = hud.panel:h() - h,
19 | halign = "grow",
20 | valign = "bottom"
21 | })
22 | local teammate_w = 204
23 | local player_gap = 240
24 | local small_gap = (teammates_panel:w() - player_gap - teammate_w * HUDManager.PLAYER_PANEL) / (HUDManager.PLAYER_PANEL - 1)
25 | for i = 1, HUDManager.PLAYER_PANEL do
26 | local is_player = i == HUDManager.PLAYER_PANEL
27 | --do break end -- unhandled boolean indicator -- Decompile error here, hopefully not causing problems.
28 |
29 | self._hud.teammate_panels_data[i] = {
30 | taken = false, --this was true, but causes problem with add_teammate_panel() and data.taken, so maybe bad decompile bug from above?
31 | special_equipments = {}
32 | }
33 | local pw = teammate_w + (is_player and 0 or 64)
34 | local teammate = HUDTeammate:new(i, teammates_panel, is_player, pw)
35 | local x = math.floor((pw + small_gap) * (i - 1) + (i == HUDManager.PLAYER_PANEL and player_gap or 0))
36 | teammate._panel:set_x(math.floor(x))
37 | table.insert(self._teammate_panels, teammate)
38 | if is_player then
39 | teammate:add_panel()
40 | end
41 | end
42 | end
43 |
44 |
45 | -- TODO: nil check added, must have been causing a problem in past, not sure if still valid problem
46 | -- Possibly safe to delete
47 | local orig__HUDManager = {}
48 | orig__HUDManager.add_weapon = HUDManager.add_weapon
49 | function HUDManager:add_weapon(data)
50 | if not self._teammate_panels[HUDManager.PLAYER_PANEL] and not self._teammate_panels[HUDManager.PLAYER_PANEL]:panel() then
51 | log("[HUDManager :add_weapon] teammate_panels[HUDManager.PLAYER_PANEL] or teammate_panels[HUDManager.PLAYER_PANEL]:panel() is nil, HUDManager.PLAYER_PANEL = " .. tostring(HUDManager.PLAYER_PANEL))
52 | return
53 | end
54 |
55 |
56 | orig__HUDManager.add_weapon(self, data)
57 | end
58 |
59 |
60 | -- `self:set_teammate_callsign(i, ai and 5 or peer_id)`
61 | -- Replaced hardcoded 5 with (HUDManager.PLAYER_PANEL + 1)
62 | -- TODO: Can probably wrap the function call and make the fix afterwards
63 | function HUDManager:add_teammate_panel(character_name, player_name, ai, peer_id)
64 | for i, data in ipairs(self._hud.teammate_panels_data) do
65 | if not data.taken then
66 | self._teammate_panels[i]:add_panel()
67 | self._teammate_panels[i]:set_peer_id(peer_id)
68 | self._teammate_panels[i]:set_ai(ai)
69 | self:set_teammate_callsign(i, ai and (HUDManager.PLAYER_PANEL + 1) or peer_id) -- TODO: this should cater for AI properly(change that 5 to dynamic variable)
70 |
71 |
72 |
73 |
74 | -- Original Code --
75 | self:set_teammate_name(i, player_name)
76 | self:set_teammate_state(i, ai and "ai" or "player")
77 | if peer_id then
78 | local peer_equipment = managers.player:get_synced_equipment_possession(peer_id) or {}
79 | for equipment, amount in pairs(peer_equipment) do
80 | self:add_teammate_special_equipment(i, {
81 | id = equipment,
82 | icon = tweak_data.equipments.specials[equipment].icon,
83 | amount = amount
84 | })
85 | end
86 | local peer_deployable_equipment = managers.player:get_synced_deployable_equipment(peer_id)
87 | if peer_deployable_equipment then
88 | local icon = tweak_data.equipments[peer_deployable_equipment.deployable].icon
89 | self:set_deployable_equipment(i, {
90 | icon = icon,
91 | amount = peer_deployable_equipment.amount
92 | })
93 | end
94 | local peer_cable_ties = managers.player:get_synced_cable_ties(peer_id)
95 | if peer_cable_ties then
96 | local icon = tweak_data.equipments.specials.cable_tie.icon
97 | self:set_cable_tie(i, {
98 | icon = icon,
99 | amount = peer_cable_ties.amount
100 | })
101 | end
102 | local peer_grenades = managers.player:get_synced_grenades(peer_id)
103 | if peer_grenades then
104 | local icon = tweak_data.blackmarket.projectiles[peer_grenades.grenade].icon
105 | self:set_teammate_grenades(i, {
106 | icon = icon,
107 | amount = Application:digest_value(peer_grenades.amount, false)
108 | })
109 | end
110 | end
111 | local unit = managers.criminals:character_unit_by_name(character_name)
112 | if alive(unit) then
113 | local weapon = unit:inventory():equipped_unit()
114 | if alive(weapon) then
115 | local icon = weapon:base():weapon_tweak_data().hud_icon
116 | local equipped_selection = unit:inventory():equipped_selection()
117 | self:_set_teammate_weapon_selected(i, equipped_selection, icon)
118 | end
119 | end
120 | local peer_ammo_info = managers.player:get_synced_ammo_info(peer_id)
121 | if peer_ammo_info then
122 | for selection_index, ammo_info in pairs(peer_ammo_info) do
123 | self:set_teammate_ammo_amount(i, selection_index, unpack(ammo_info))
124 | end
125 | end
126 | local peer_carry_data = managers.player:get_synced_carry(peer_id)
127 | if peer_carry_data then
128 | self:set_teammate_carry_info(i, peer_carry_data.carry_id, managers.loot:get_real_value(peer_carry_data.carry_id, peer_carry_data.multiplier))
129 | end
130 | data.taken = true
131 | return i
132 | end
133 | end
134 | -- End Original Code --
135 | end
136 |
137 | function HUDManager:set_teammate_health(i, data)
138 | if i and self._teammate_panels and self._teammate_panels[i] then
139 | self._teammate_panels[i]:set_health(data)
140 | end
141 | end
--------------------------------------------------------------------------------
/lua/lib/managers/_vehiclemanager.lua:
--------------------------------------------------------------------------------
1 | -- Levels that trigger events that depend on all players inside become a problem with >4 players
2 | -- This caps the `total_players` variable to 4. The vehicle events are triggered by a listener
3 | -- fired by `VehicleManager:on_player_entered_vehicle(vehicle_unit, player)`
4 | -- Only change to this function is the 2nd line added to do the cap.
5 | function VehicleManager:all_players_in_vehicles()
6 | local total_players = managers.network:session():amount_of_alive_players()
7 | total_players = total_players > 4 and 4 or total_players
8 |
9 | local players_in_vehicles = 0
10 | for _, vehicle in pairs(self._vehicles) do
11 | players_in_vehicles = players_in_vehicles + vehicle:vehicle_driving():num_players_inside()
12 | end
13 |
14 | return total_players == players_in_vehicles
15 | end
16 |
--------------------------------------------------------------------------------
/lua/lib/managers/group_ai_states/_groupaistatebase.lua:
--------------------------------------------------------------------------------
1 | -- Modified to support full team size instead of hardcoded 3, not hugely relevant as is a bot thing.
2 | function GroupAIStateBase:on_criminal_team_AI_enabled_state_changed()
3 | local num_player_slots = BigLobbyGlobals:num_player_slots() - 1
4 |
5 | -- Only code changed was replacing hardcoded 3 with variable num_player_slots
6 | if Network:is_client() then
7 | return
8 | end
9 | if managers.groupai:state():team_ai_enabled() then
10 | self:fill_criminal_team_with_AI()
11 | else
12 | for i = 1, num_player_slots do
13 | self:remove_one_teamAI()
14 | end
15 | end
16 | end
17 |
18 | -- Hooks:PostHook( GroupAIStateBase , "whisper_mode" , "GroupAIStateBasePostWhisperMode" , function( self )
19 | -- for _, ai in pairs(self:all_AI_criminals()) do
20 | -- if self._whisper_mode == true and BigLobbyGlobals.auto_stop_all_bots_settings then
21 | -- ai.unit:movement():set_should_stay(true)
22 | -- elseif self._whisper_mode == false and BigLobbyGlobals.auto_stop_all_bots_settings then
23 | -- if ai.unit:movement() and ai.unit:movement()._should_stay then
24 | -- ai.unit:movement():set_should_stay(false)
25 | -- end
26 | -- end
27 | -- end
28 | -- end )
29 |
30 | -- Hooks:PostHook( GroupAIStateBase , "whisper_mode" , "GroupAIStateBasePostWhisperMode" , function( self )
31 | -- for _, ai in pairs(self:all_AI_criminals()) do
32 | -- if self._whisper_mode == true and Network:is_server() then
33 | -- ai.unit:movement():play_redirect("crouch")
34 | -- ai.unit:movement():action_request({
35 | -- align_sync = true,
36 | -- body_part = 1,
37 | -- type = "idle"
38 | -- })
39 | -- else
40 | -- return
41 | -- end
42 | -- end
43 | -- end )
--------------------------------------------------------------------------------
/lua/lib/managers/hud/_hudlootscreen.lua:
--------------------------------------------------------------------------------
1 | -- To avoid overriding `HUDLootScreen:init()` for a loop in the middle of it I'm
2 | -- hooking the first method afterwards to add the extra peers to the required table.
3 | -- It should be safe approach and allow for the rest of the init method to use the
4 | -- extra peers.
5 | HUDLootScreen._init_extra_peers = true
6 |
7 | function HUDLootScreen:set_num_visible(peers_num)
8 | local num_player_slots = BigLobbyGlobals:num_player_slots()
9 |
10 | if HUDLootScreen._init_extra_peers or (table.getn(self._peer_data) == 4 and num_player_slots > 4) then
11 | for i = 5, num_player_slots do
12 | self:create_peer(self._peers_panel, i)
13 | end
14 |
15 | -- This is only run once for `HUDLootScreen:init()`
16 | HUDLootScreen._init_extra_peers = false
17 | end
18 |
19 | -- Only code changed was replacing hardcoded 4 with variable num_player_slots
20 | self._num_visible = math.max(self._num_visible, peers_num)
21 | for i = 1, num_player_slots do
22 | self._peers_panel:child("peer" .. i):set_visible(i <= self._num_visible)
23 | end
24 | self._peers_panel:set_h(self._num_visible * 110)
25 | self._peers_panel:set_center_y(self._hud_panel:h() * 0.5)
26 |
27 | -- TODO: Is this console code useful for reworking the UI layout?
28 | if managers.menu:is_console() and self._num_visible >= 4 then
29 | self._peers_panel:move(0, 30)
30 | end
31 | end
32 |
33 |
34 | function HUDLootScreen:clear_other_peers(peer_id)
35 | local num_player_slots = BigLobbyGlobals:num_player_slots()
36 |
37 | -- Only code changed was replacing hardcoded 4 with variable num_player_slots
38 | peer_id = peer_id or self:get_local_peer_id()
39 | for i = 1, num_player_slots do
40 | if i ~= peer_id then
41 | self:remove_peer(i)
42 | end
43 | end
44 | end
45 |
46 |
47 | function HUDLootScreen:check_all_ready()
48 | local num_player_slots = BigLobbyGlobals:num_player_slots()
49 |
50 | -- Only code changed was replacing hardcoded 4 with variable num_player_slots
51 | local ready = true
52 | for i = 1, num_player_slots do
53 | if self._peer_data[i].active and ready then
54 | ready = self._peer_data[i].ready
55 | end
56 | end
57 | return ready
58 | end
59 |
60 |
61 | function HUDLootScreen:update(t, dt)
62 | local num_player_slots = BigLobbyGlobals:num_player_slots()
63 |
64 | -- Only code changed was replacing hardcoded 4 with variable num_player_slots
65 | for peer_id = 1, num_player_slots do
66 | if self._peer_data[peer_id].wait_t then
67 | self._peer_data[peer_id].wait_t = math.max(self._peer_data[peer_id].wait_t - dt, 0)
68 | local panel = self._peers_panel:child("peer" .. tostring(peer_id))
69 | local card_info_panel = panel:child("card_info")
70 | local main_text = card_info_panel:child("main_text")
71 | main_text:set_text(managers.localization:to_upper_text("menu_l_choose_card_chosen", {
72 | time = math.ceil(self._peer_data[peer_id].wait_t)
73 | }))
74 | local _, _, _, hh = main_text:text_rect()
75 | main_text:set_h(hh + 2)
76 | if self._peer_data[peer_id].wait_t == 0 then
77 | main_text:set_text(managers.localization:to_upper_text("menu_l_choose_card_chosen_suspense"))
78 | local joker = self._peer_data[peer_id].joker
79 | local steam_drop = self._peer_data[peer_id].steam_drop
80 | local effects = self._peer_data[peer_id].effects
81 | panel:child("card" .. self._peer_data[peer_id].selected):animate(callback(self, self, "flipcard"), steam_drop and 5.5 or 2.5, callback(self, self, "show_item"), peer_id, effects)
82 | self._peer_data[peer_id].wait_t = false
83 | end
84 | end
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/lua/lib/managers/hud/_hudmissionbriefing.lua:
--------------------------------------------------------------------------------
1 | -- Instead of overriding methods, I am now hooking them and continuiing the loop
2 | -- to handle >4 peers.
3 | local orig__HUDMissionBriefing = {
4 | init = HUDMissionBriefing.init
5 | }
6 |
7 |
8 | function HUDMissionBriefing:init(...)
9 | orig__HUDMissionBriefing.init(self, ...)
10 |
11 | local num_player_slots = BigLobbyGlobals:num_player_slots()
12 |
13 | local text_font = tweak_data.menu.pd2_small_font
14 | local text_font_size = tweak_data.menu.pd2_small_font_size
15 |
16 | -- Adjust height of panel to accomodate for the amount of player slots
17 | self._ready_slot_panel:set_h( text_font_size * num_player_slots + 20 )
18 |
19 | -- Adds player slot panels for peers >4
20 | if not self._singleplayer then
21 | local voice_icon, voice_texture_rect = tweak_data.hud_icons:get_icon_data("mugshot_talk")
22 | local infamy_icon, infamy_rect = tweak_data.hud_icons:get_icon_data("infamy_icon")
23 | for i = 5, num_player_slots do
24 |
25 |
26 |
27 |
28 | -- Original Code --
29 | local color_id = i
30 | local color = tweak_data.chat_colors[color_id]
31 | local slot_panel = self._ready_slot_panel:panel({
32 | name = "slot_" .. tostring(i),
33 | h = text_font_size,
34 | y = (i - 1) * text_font_size + 10,
35 | x = 10,
36 | w = self._ready_slot_panel:w() - 20
37 | })
38 | local criminal = slot_panel:text({
39 | name = "criminal",
40 | font_size = text_font_size,
41 | font = text_font,
42 | color = color,
43 | text = tweak_data.gui.LONGEST_CHAR_NAME,
44 | blend_mode = "add",
45 | align = "left",
46 | vertical = "center"
47 | })
48 | local voice = slot_panel:bitmap({
49 | name = "voice",
50 | texture = voice_icon,
51 | visible = false,
52 | layer = 2,
53 | texture_rect = voice_texture_rect,
54 | w = voice_texture_rect[3],
55 | h = voice_texture_rect[4],
56 | color = color,
57 | x = 10
58 | })
59 | local name = slot_panel:text({
60 | name = "name",
61 | text = managers.localization:text("menu_lobby_player_slot_available") .. " ",
62 | font = text_font,
63 | font_size = text_font_size,
64 | color = color:with_alpha(0.5),
65 | align = "left",
66 | vertical = "center",
67 | w = 256,
68 | h = text_font_size,
69 | layer = 1,
70 | blend_mode = "add"
71 | })
72 | local status = slot_panel:text({
73 | name = "status",
74 | visible = false,
75 | text = " ",
76 | font = text_font,
77 | font_size = text_font_size,
78 | align = "right",
79 | vertical = "center",
80 | w = 256,
81 | h = text_font_size,
82 | layer = 1,
83 | blend_mode = "add",
84 | color = tweak_data.screen_colors.text:with_alpha(0.5)
85 | })
86 | local infamy = slot_panel:bitmap({
87 | name = "infamy",
88 | texture = infamy_icon,
89 | texture_rect = infamy_rect,
90 | visible = false,
91 | layer = 2,
92 | color = color,
93 | y = 1
94 | })
95 | local detection = slot_panel:panel({
96 | name = "detection",
97 | layer = 2,
98 | visible = false,
99 | w = slot_panel:h(),
100 | h = slot_panel:h()
101 | })
102 | local detection_ring_left_bg = detection:bitmap({
103 | name = "detection_left_bg",
104 | texture = "guis/textures/pd2/mission_briefing/inv_detection_meter",
105 | alpha = 0.2,
106 | blend_mode = "add",
107 | w = detection:w(),
108 | h = detection:h()
109 | })
110 | local detection_ring_right_bg = detection:bitmap({
111 | name = "detection_right_bg",
112 | texture = "guis/textures/pd2/mission_briefing/inv_detection_meter",
113 | alpha = 0.2,
114 | blend_mode = "add",
115 | w = detection:w(),
116 | h = detection:h()
117 | })
118 | detection_ring_right_bg:set_texture_rect(detection_ring_right_bg:texture_width(), 0, -detection_ring_right_bg:texture_width(), detection_ring_right_bg:texture_height())
119 | local detection_ring_left = detection:bitmap({
120 | name = "detection_left",
121 | texture = "guis/textures/pd2/mission_briefing/inv_detection_meter",
122 | render_template = "VertexColorTexturedRadial",
123 | blend_mode = "add",
124 | layer = 1,
125 | w = detection:w(),
126 | h = detection:h()
127 | })
128 | local detection_ring_right = detection:bitmap({
129 | name = "detection_right",
130 | texture = "guis/textures/pd2/mission_briefing/inv_detection_meter",
131 | render_template = "VertexColorTexturedRadial",
132 | blend_mode = "add",
133 | layer = 1,
134 | w = detection:w(),
135 | h = detection:h()
136 | })
137 | detection_ring_right:set_texture_rect(detection_ring_right:texture_width(), 0, -detection_ring_right:texture_width(), detection_ring_right:texture_height())
138 | local detection_value = slot_panel:text({
139 | name = "detection_value",
140 | font_size = text_font_size,
141 | font = text_font,
142 | color = color,
143 | text = " ",
144 | blend_mode = "add",
145 | align = "left",
146 | vertical = "center"
147 | })
148 | detection:set_left(slot_panel:w() * 0.65)
149 | detection_value:set_left(detection:right() + 2)
150 | detection_value:set_visible(detection:visible())
151 | local _, _, w, _ = criminal:text_rect()
152 | voice:set_left(w + 2)
153 | criminal:set_w(w)
154 | criminal:set_align("right")
155 | criminal:set_text("")
156 | name:set_left(voice:right() + 2)
157 | status:set_right(slot_panel:w())
158 | infamy:set_left(name:x())
159 | end
160 | BoxGuiObject:new(self._ready_slot_panel, {
161 | sides = {
162 | 1,
163 | 1,
164 | 1,
165 | 1
166 | }
167 | })
168 | end
169 | -- End Original Code --
170 | end
171 |
--------------------------------------------------------------------------------
/lua/lib/managers/hud/_hudteammate.lua:
--------------------------------------------------------------------------------
1 | -- This function contains a variable `names` which is a table of dummy name strings.
2 | -- Unfortunately the function is massive and that data is hardcoded at the start of
3 | -- the function. Thankfully we might still be able to work around it without breaking
4 | -- other mods such as hud mods which may heavily modify this code.
5 | local orig__HUDTeammate = {
6 | init = HUDTeammate.init
7 | }
8 |
9 | if BL2Options then return end
10 | function HUDTeammate:init(i, teammates_panel, is_player, width)
11 | -- Main difference in this function is based on the `main_player` variable
12 | -- This refers to the local/client player, so as long as we can make that
13 | -- true when appropriate and false when not, we should be good. Just need to
14 | -- fix some settings after the original function finishes and hopefully
15 | -- everything works as it should.
16 | local fake_i = 1
17 | local real_player_panel = HUDManager.PLAYER_PANEL
18 |
19 | if (i == HUDManager.PLAYER_PANEL) then
20 | fake_i = 4
21 | HUDManager.PLAYER_PANEL = 4
22 | end
23 |
24 | orig__HUDTeammate.init(self, fake_i, teammates_panel, is_player, width)
25 |
26 | -- Fix some properties to align with the real i value.
27 | self._id = i
28 | self._panel:set_name("" .. i)
29 | self._panel:child("callsign"):set_color(tweak_data.chat_colors[i]:with_alpha(1))
30 |
31 | HUDManager.PLAYER_PANEL = real_player_panel
32 | end
33 |
--------------------------------------------------------------------------------
/lua/lib/managers/menu/_contractboxgui.lua:
--------------------------------------------------------------------------------
1 | -- Modified to support rendering UI text for additional peers in lobby screen.
2 | -- Instead of overriding methods, I am now hooking them and continuiing the loop
3 | -- to handle >4 peers.
4 | local orig__ContractBoxGui = {
5 | create_contract_box = ContractBoxGui.create_contract_box,
6 | update = ContractBoxGui.update
7 | }
8 |
9 |
10 | function ContractBoxGui:create_contract_box()
11 | orig__ContractBoxGui.create_contract_box(self)
12 |
13 | if not managers.network:session() then
14 | return
15 | end
16 |
17 | local num_player_slots = BigLobbyGlobals:num_player_slots()
18 |
19 | -- Only code changed was replacing hardcoded 4 with variable num_player_slots
20 | for i = 5, num_player_slots do
21 | local peer = managers.network:session():peer(i)
22 | if peer then
23 | local peer_pos = managers.menu_scene:character_screen_position(i)
24 | local peer_name = peer:name()
25 |
26 | if peer_pos then
27 | self:create_character_text(i, peer_pos.x, peer_pos.y, peer_name)
28 | end
29 | end
30 | end
31 | end
32 |
33 |
34 | -- Modified to support rendering UI text for additional peers.
35 | function ContractBoxGui:update(t, dt)
36 | local num_player_slots = BigLobbyGlobals:num_player_slots()
37 |
38 | for i = 5, num_player_slots do
39 | self:update_character(i)
40 | end
41 |
42 | orig__ContractBoxGui.update(self, t, dt)
43 | end
--------------------------------------------------------------------------------
/lua/lib/managers/menu/_crewmanagementgui.lua:
--------------------------------------------------------------------------------
1 |
2 | -- Removes the hard coded 3 preferred characters
3 | function CrewManagementGui:select_characters(data, gui)
4 | local preferred = managers.blackmarket:preferred_henchmen()
5 | local num_player_slots = BigLobbyGlobals:num_player_slots() - 1
6 | if data.equipped_by then
7 | print("unselect")
8 | managers.blackmarket:set_preferred_henchmen(data.equipped_by, nil)
9 | else
10 | local index = math.min(#preferred + 1, num_player_slots)
11 |
12 | print(index, #preferred)
13 | managers.blackmarket:set_preferred_henchmen(index, data.name)
14 | end
15 |
16 | gui:reload()
17 | end
--------------------------------------------------------------------------------
/lua/lib/managers/menu/_crimespreemissionsmenucomponent.lua:
--------------------------------------------------------------------------------
1 | function CrimeSpreeMissionButton:_get_mission_category(mission)
2 | if not mission.add then return end
3 | if mission.add <= 5 then
4 | return "short"
5 | elseif mission.add <= 7 then
6 | return "medium"
7 | else
8 | return "long"
9 | end
10 | end
--------------------------------------------------------------------------------
/lua/lib/managers/menu/_menucomponentmanager.lua:
--------------------------------------------------------------------------------
1 | -- Instead of overriding methods, I am now hooking them and continuiing the loop
2 | -- to handle >4 peers.
3 | local orig__MenuComponentManager = {
4 | create_contract_gui = MenuComponentManager.create_contract_gui,
5 | show_contract_character = MenuComponentManager.show_contract_character
6 | }
7 |
8 |
9 | -- I believe this creates/updates label state based on what the player is doing?
10 | function MenuComponentManager:create_contract_gui()
11 | orig__MenuComponentManager.create_contract_gui(self)
12 |
13 | local num_player_slots = BigLobbyGlobals:num_player_slots()
14 | local peers_state = managers.menu:get_all_peers_state() or {}
15 |
16 | for i = 5, num_player_slots do
17 | self._contract_gui:update_character_menu_state(i, peers_state[i])
18 | end
19 | end
20 |
21 |
22 | -- Shows the peer label over character with alpha of 1 if loaded, or 0.4 if still
23 | -- in a loading/joining state?
24 | function MenuComponentManager:show_contract_character(state)
25 | orig__MenuComponentManager.show_contract_character(self, state)
26 |
27 | local num_player_slots = BigLobbyGlobals:num_player_slots()
28 |
29 | if self._contract_gui then
30 | for i = 5, num_player_slots do
31 | self._contract_gui:set_character_panel_alpha(i, state and 1 or 0.4)
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lua/lib/managers/menu/_menulobbyrenderer.lua:
--------------------------------------------------------------------------------
1 | -- Modified to support additional player slots in the mission briefing screen.
2 | function MenuLobbyRenderer:open(...)
3 | local num_player_slots = BigLobbyGlobals:num_player_slots()
4 |
5 | -- Original Code --
6 | MenuLobbyRenderer.super.open(self, ...)
7 |
8 | local safe_rect_pixels = managers.gui_data:scaled_size()
9 | local scaled_size = safe_rect_pixels
10 |
11 | MenuRenderer._create_framing(self)
12 | self._main_panel:hide()
13 |
14 | self._player_slots = {}
15 | self._menu_bg = self._fullscreen_panel:panel({})
16 |
17 | if _G.IS_VR then
18 | self._menu_bg:rect({
19 | halign = "scale",
20 | valign = "scale",
21 | visible = true,
22 | layer = -1000,
23 | color = Color.black
24 | })
25 | end
26 |
27 | local is_server = Network:is_server()
28 | local server_peer = is_server and managers.network:session():local_peer() or managers.network:session():server_peer()
29 | local is_single_player = Global.game_settings.single_player
30 | local is_multiplayer = not is_single_player
31 |
32 | if not server_peer then
33 | return
34 | end
35 | -- End Original Code --
36 |
37 |
38 |
39 |
40 | -- Only code changed was replacing hardcoded 4 with variable num_player_slots
41 | for i = 1, is_single_player and 1 or num_player_slots do
42 | local t = {
43 | player = {},
44 | free = true,
45 | kit_slots = {},
46 | params = {}
47 | }
48 |
49 | for slot = 1, PlayerManager.WEAPON_SLOTS + 3 do
50 | table.insert(t.kit_slots, slot)
51 | end
52 |
53 | table.insert(self._player_slots, t)
54 | end
55 |
56 |
57 |
58 |
59 | -- Original Code --
60 | if is_server then
61 | local level = managers.experience:current_level()
62 | local rank = managers.experience:current_rank()
63 | local join_stinger_index = managers.infamy:selected_join_stinger_index()
64 |
65 | self:_set_player_slot(1, {
66 | character = "random",
67 | name = server_peer:name(),
68 | peer_id = server_peer:id(),
69 | level = level,
70 | rank = rank,
71 | join_stinger_index = join_stinger_index
72 | })
73 | end
74 |
75 | self:_entered_menu()
76 | -- End Original Code --
77 | end
78 |
--------------------------------------------------------------------------------
/lua/lib/managers/menu/_menuscenemanager.lua:
--------------------------------------------------------------------------------
1 | function MenuSceneManager:_setup_lobby_characters()
2 | local num_player_slots = BigLobbyGlobals:num_player_slots()
3 |
4 |
5 |
6 |
7 | -- Original Code --
8 | if self._lobby_characters then
9 | for _, unit in ipairs(self._lobby_characters) do
10 | self:_delete_character_mask(unit)
11 | World:delete_unit(unit)
12 | end
13 | end
14 | self._lobby_characters = {}
15 | self._characters_offset = Vector3(0, -200, -130)
16 | -- End Original Code --
17 |
18 |
19 |
20 |
21 | -- Code changed was:
22 | -- Replacing hardcoded 4 with variable num_player_slots
23 | -- Replacing the local masks variable from hardcoded table to dynamically generated via loop
24 | -- Replacing self._characters_rotation from hardcoded table to dynamically generated via loop
25 | self._characters_rotation = {}
26 |
27 | -- Dynamically building a range of rotations, used below and by MenuSceneManager:set_lobby_character_out_fit
28 | local min = -130
29 | local max = -56
30 | local range = min - max
31 | local steps = range / (num_player_slots-1)
32 | -- The first half of rotations is for all peers except local peer:
33 | for i = 1, num_player_slots do
34 | self._characters_rotation[i] = (((i-1) * steps) + max)
35 | end
36 |
37 | -- The second half of rotations is what the local peer uses based on their peer id:
38 | for i = 1, num_player_slots do
39 | self._characters_rotation[i+num_player_slots] = (((i-1) * steps) + max)
40 | end
41 |
42 | -- Dummy string filled with "dallas" because that's what it was originally
43 | local masks = {}
44 | for i = 1, num_player_slots do
45 | masks[i] = "dallas"
46 | end
47 |
48 |
49 | -- This added logic should alter positioning of players to start at the center
50 | -- and expand outwards as the player count grows.
51 | local offset = 0 -- Starting offset
52 | local peer_rotations = #self._characters_rotation/2
53 | -- eg 4/2->2, 5/2->2.5->3, 6/2->3, 7/2->3.5->4
54 | local center_index = math.ceil(peer_rotations/2)
55 | local function get_new_index(index)
56 | local is_even = index%2==0
57 | local new_index = is_even and center_index + offset or center_index - offset
58 | -- After adding one to the left and one to the right, increase the offset
59 | -- Unless starting index is odd, then increase straight after(no left/right)
60 | if not is_even then offset = offset + 1 end
61 |
62 | return new_index
63 | end
64 |
65 |
66 | -- Only code changed here was replacing a hardcoded value of 4 with the variable
67 | -- num_player_slots and adding the local function above for set_yaw_pitch_roll
68 | local mvec = Vector3()
69 | local math_up = math.UP
70 | local pos = Vector3()
71 | local rot = Rotation()
72 | for i = 1, num_player_slots do
73 | mrotation.set_yaw_pitch_roll(rot, self._characters_rotation[get_new_index(i)], 0, 0)
74 | mvector3.set(pos, self._characters_offset)
75 | mvector3.rotate_with(pos, rot)
76 | mvector3.set(mvec, pos)
77 | mvector3.negate(mvec)
78 | mvector3.set_z(mvec, 0)
79 | mrotation.set_look_at(rot, mvec, math_up)
80 | local unit_name = tweak_data.blackmarket.characters.locked.menu_unit
81 | local unit = World:spawn_unit(Idstring(unit_name), pos, rot)
82 | self:_init_character(unit, i)
83 | self:set_character_mask(tweak_data.blackmarket.masks[ masks[i] ].unit, unit, nil, masks[i])
84 | table.insert(self._lobby_characters, unit)
85 | self:set_lobby_character_visible(i, false, true)
86 | end
87 | end
88 |
89 | function MenuSceneManager:_select_lobby_character_pose(peer_id, unit, weapon_info)
90 |
91 |
92 |
93 |
94 | -- Original Code --
95 | local state = unit:play_redirect(Idstring("idle_menu"))
96 | local weapon_id = managers.weapon_factory:get_weapon_id_by_factory_id(weapon_info.factory_id)
97 | local category = tweak_data.weapon[weapon_id].category
98 | local lobby_poses = self._lobby_poses[weapon_id]
99 | lobby_poses = lobby_poses or self._lobby_poses[category]
100 | lobby_poses = lobby_poses or self._lobby_poses.generic
101 | if type(lobby_poses[1]) == "string" then
102 | local pose = lobby_poses[math.random(#lobby_poses)]
103 | unit:anim_state_machine():set_parameter(state, pose, 1)
104 | else
105 | -- End Original Code --
106 |
107 |
108 |
109 |
110 | -- Only modification is to use modulus to make sure our lobby peer is given a pose
111 | local pose = lobby_poses[(peer_id % #lobby_poses) + 1][math.random(#lobby_poses[(peer_id % #lobby_poses) + 1])]
112 |
113 |
114 |
115 |
116 | -- Original Code --
117 | unit:anim_state_machine():set_parameter(state, pose, 1)
118 | end
119 | -- End Original Code --
120 | end
121 |
122 |
123 | -- TODO: This shouldn't be relevant to gameplay, should be safe to delete.
124 | -- Not required for this mod to work, just updates the test function to work with more players
125 | -- Only for testing (literally no relevance to the game)
126 | -- function MenuSceneManager:test_show_all_lobby_characters(enable_card, pose)
127 | -- local num_player_slots = 15--BigLobbyGlobals:num_player_slots()
128 | -- pose = pose or "lobby_generic_idle1"
129 | --
130 | -- local mvec = Vector3()
131 | -- local math_up = math.UP
132 | -- local pos = Vector3()
133 | -- local rot = Rotation()
134 | -- -- Forcing all `self._ti` to be static 1, this was for a predictable outcome
135 | -- -- since each call of this function was to test the feature with the client
136 | -- -- player in each of the different player slots?
137 | -- self._ti = 1--(self._ti or 0) + 1
138 | -- --self._ti = (self._ti - 1) % num_player_slots + 1
139 | -- for i = 1, num_player_slots do
140 | -- local is_me = i == self._ti
141 | -- log("TEST LOBBY, is_me = " .. tostring(is_me) .. ", i: " .. tostring(i))
142 | -- local unit = self._lobby_characters[i]
143 | -- if unit and alive(unit) then
144 | -- if enable_card then
145 | -- self:set_character_card(i, math.random(25), unit)
146 | -- else
147 | -- -- Was forcing the pose for some reason instead of fix below?
148 | -- self:_set_character_unit_pose(pose, unit)
149 | -- -- local state = unit:play_redirect(Idstring("idle_menu"))
150 | -- -- Only 4 variations of lobby_generic_idle? 4%4=0 though, might want to + 1 if 0?
151 | -- -- unit:anim_state_machine():set_parameter(state, "lobby_generic_idle" .. i%4, 1)
152 | -- end
153 | -- -- Uses 0+i for rotation index unless it's your player unit then 4+i for some reason?
154 | -- -- I guess this explains the 8 values in `self._characters_rotation`, the last half are specific to the client player
155 | -- -- TODO: Therefore 4 should really be half of the table size?
156 | -- -- will break if not enough rotation indices use a modulus? (or you know, just make the table dynamically built)
157 | -- mrotation.set_yaw_pitch_roll(rot, self._characters_rotation[(is_me and 4 or 0) + i], 0, 0)
158 | -- mvector3.set(pos, self._characters_offset)
159 | -- if is_me then
160 | -- mvector3.set_y(pos, mvector3.y(pos) + 100)
161 | -- end
162 | -- mvector3.rotate_with(pos, rot)
163 | -- mvector3.set(mvec, pos)
164 | -- mvector3.negate(mvec)
165 | -- mvector3.set_z(mvec, 0)
166 | -- mrotation.set_look_at(rot, mvec, math_up)
167 | -- unit:set_position(pos)
168 | -- unit:set_rotation(rot)
169 | -- local character = managers.blackmarket:equipped_character()
170 | -- local mask_blueprint = managers.blackmarket:equipped_mask().blueprint
171 | -- self:change_lobby_character(i, character)
172 | -- unit = self._lobby_characters[i]
173 | -- self:set_character_mask_by_id(managers.blackmarket:equipped_mask().mask_id, mask_blueprint, unit, i)
174 | -- self:set_character_armor(managers.blackmarket:equipped_armor(), unit)
175 | -- self:set_lobby_character_visible(i, true)
176 | -- end
177 | -- end
178 | -- -- I seem to have added this, I guess it was for replacing all the dallas with my own unit? and thus weapons.
179 | -- managers.menu_scene:_set_character_equipment()
180 | -- end
181 |
182 |
183 | -- Modified to hide additional peers.
184 | function MenuSceneManager:hide_all_lobby_characters()
185 | local num_player_slots = BigLobbyGlobals:num_player_slots()
186 |
187 | for i = 1, num_player_slots do
188 | self:set_lobby_character_visible(i, false, true)
189 | end
190 | end
191 |
192 |
193 | -- Affects the x or y position by an offset for a player model in lobby?
194 | -- TODO: needs to support additional players?
195 | -- function MenuSceneManager:character_screen_position(peer_id)
196 | -- local unit = self._lobby_characters[peer_id]
197 | -- if unit and alive(unit) then
198 | -- local is_me = peer_id == managers.network:session():local_peer():id()
199 | -- local peer_3_x_offset = 0
200 | -- if peer_id == 3 then
201 | -- peer_3_x_offset = is_me and -20 or -40
202 | -- end
203 | -- local peer_y_offset = 0
204 | -- if peer_id == 2 then
205 | -- peer_y_offset = is_me and -3 or 0
206 | -- elseif peer_id == 3 then
207 | -- peer_y_offset = is_me and -7 or 0
208 | -- elseif peer_id == 4 then
209 | -- peer_y_offset = is_me and 5 or 0
210 | -- end
211 | -- local spine_pos = unit:get_object(Idstring("Spine")):position() + Vector3(peer_3_x_offset, 0, -5 + 15 * (peer_id % 4) + peer_y_offset)
212 | -- return self._workspace:world_to_screen(self._camera_object, spine_pos)
213 | -- end
214 | -- end
215 |
216 | -- TODO: Probably safe to delete?
217 | -- TODO: Instances of 4 might benefit from being increased to additional player value? I don't think they're related..
218 | -- function MenuSceneManager:mouse_moved(o, x, y)
219 | -- if managers.menu_component:input_focus() == true or managers.menu_component:input_focus() == 1 then
220 | -- return false, "arrow"
221 | -- end
222 | -- if self._character_grabbed then
223 | -- self._character_yaw = self._character_yaw + (x - self._character_grabbed_current_x) / 4
224 | -- if self._use_character_pan and self._character_values and self._scene_templates and self._scene_templates[self._current_scene_template] then
225 | -- local new_z = mvector3.z(self._character_values.pos_target) - (y - self._character_grabbed_current_y) / 12
226 | -- local default_z = mvector3.z(self._scene_templates and self._scene_templates[self._current_scene_template].character_pos or self._character_values.pos_current)
227 | -- new_z = math.clamp(new_z, default_z - 20, default_z + 10)
228 | -- mvector3.set_z(self._character_values.pos_target, new_z)
229 | -- end
230 | -- self._character_unit:set_rotation(Rotation(self._character_yaw, self._character_pitch))
231 | -- self._character_grabbed_current_x = x
232 | -- self._character_grabbed_current_y = y
233 | -- return true, "grab"
234 | -- end
235 | -- if self._item_grabbed then
236 | -- if self._item_unit and alive(self._item_unit.unit) then
237 | -- local diff = (y - self._item_grabbed_current_y) / 4
238 | -- self._item_yaw = (self._item_yaw + (x - self._item_grabbed_current_x) / 4) % 360
239 | -- local yaw_sin = math.sin(self._item_yaw)
240 | -- local yaw_cos = math.cos(self._item_yaw)
241 | -- local treshhold = math.sin(45)
242 | -- if yaw_cos > -treshhold and yaw_cos < treshhold then
243 | -- else
244 | -- self._item_pitch = math.clamp(self._item_pitch + diff * yaw_cos, -30, 30)
245 | -- end
246 | -- if yaw_sin > -treshhold and yaw_sin < treshhold then
247 | -- else
248 | -- self._item_roll = math.clamp(self._item_roll - diff * yaw_sin, -30, 30)
249 | -- end
250 | -- mrotation.set_yaw_pitch_roll(self._item_rot_temp, self._item_yaw, self._item_pitch, self._item_roll)
251 | -- mrotation.set_zero(self._item_rot)
252 | -- mrotation.multiply(self._item_rot, self._camera_object:rotation())
253 | -- mrotation.multiply(self._item_rot, self._item_rot_temp)
254 | -- mrotation.multiply(self._item_rot, self._item_rot_mod)
255 | -- self._item_unit.unit:set_rotation(self._item_rot)
256 | -- local new_pos = self._item_rot_pos + self._item_offset:rotate_with(self._item_rot)
257 | -- self._item_unit.unit:set_position(new_pos)
258 | -- self._item_unit.unit:set_moving(2)
259 | -- end
260 | -- self._item_grabbed_current_x = x
261 | -- self._item_grabbed_current_y = y
262 | -- return true, "grab"
263 | -- elseif self._item_move_grabbed and self._item_unit and alive(self._item_unit.unit) then
264 | -- local diff_x = (x - self._item_move_grabbed_current_x) / 4
265 | -- local diff_y = (y - self._item_move_grabbed_current_y) / 4
266 | -- local move_v = Vector3(diff_x, 0, -diff_y):rotate_with(self._camera_object:rotation())
267 | -- mvector3.add(self._item_rot_pos, move_v)
268 | -- local new_pos = self._item_rot_pos + self._item_offset:rotate_with(self._item_rot)
269 | -- self._item_unit.unit:set_position(new_pos)
270 | -- self._item_unit.unit:set_moving(2)
271 | -- self._item_move_grabbed_current_x = x
272 | -- self._item_move_grabbed_current_y = y
273 | -- return true, "grab"
274 | -- end
275 | -- if self._use_item_grab and self._item_grab:inside(x, y) then
276 | -- return true, "hand"
277 | -- end
278 | -- if self._use_character_grab and self._character_grab:inside(x, y) then
279 | -- return true, "hand"
280 | -- end
281 | -- if self._use_character_grab2 and self._character_grab2:inside(x, y) then
282 | -- return true, "hand"
283 | -- end
284 | -- end
285 |
286 |
287 | -- I run the original method, but then need to correct a hardcoded 4 which requires running a bunch
288 | -- of logic again. Should be safe.
289 |
290 |
291 | local orig__MenuSceneManager = {}
292 | orig__MenuSceneManager.set_lobby_character_out_fit = MenuSceneManager.set_lobby_character_out_fit
293 | function MenuSceneManager:set_lobby_character_out_fit(i, outfit_string, rank)
294 | local num_player_slots = BigLobbyGlobals:num_player_slots()
295 |
296 | orig__MenuSceneManager.set_lobby_character_out_fit(self, i, outfit_string, rank)
297 |
298 |
299 |
300 |
301 | -- Original Code -- as far as flow and relevance is concerned at least.
302 | local unit = self._lobby_characters[i]
303 | local is_me = i == managers.network:session():local_peer():id()
304 | local mvec = Vector3()
305 | local math_up = math.UP
306 | local pos = Vector3()
307 | local rot = Rotation()
308 | -- End Original Code --
309 |
310 |
311 |
312 |
313 | -- Only the hardcoded 4 here is changed to a variable
314 | -- The 4 refers to halfway point of the rotation table, not player count.
315 | mrotation.set_yaw_pitch_roll(rot, self._characters_rotation[(is_me and num_player_slots or 0) + i], 0, 0)
316 |
317 |
318 |
319 |
320 | -- Original Code --
321 | mvector3.set(pos, self._characters_offset)
322 | if is_me then
323 | mvector3.set_y(pos, mvector3.y(pos) + 100)
324 | end
325 | mvector3.rotate_with(pos, rot)
326 | mvector3.set(mvec, pos)
327 | mvector3.negate(mvec)
328 | mvector3.set_z(mvec, 0)
329 | mrotation.set_look_at(rot, mvec, math_up)
330 | unit:set_position(pos)
331 | unit:set_rotation(rot)
332 | self:set_lobby_character_visible(i, true)
333 | -- End Original Code --
334 | end
335 |
--------------------------------------------------------------------------------
/lua/lib/managers/menu/_missionbriefinggui.lua:
--------------------------------------------------------------------------------
1 | -- Modified to support displaying additional peers loadouts.
2 | -- TODO: This becomes undesirable the larger the player count and requires a reworked UI.
3 | function TeamLoadoutItem:init(panel, text, i)
4 | local num_player_slots = BigLobbyGlobals:num_player_slots()
5 |
6 | -- Only code changed was replacing two hardcoded values of 4 with the variable num_player_slots
7 | TeamLoadoutItem.super.init(self, panel, text, i)
8 | self._player_slots = {}
9 | local quarter_width = self._panel:w() / num_player_slots
10 | local slot_panel
11 | for i = 1, num_player_slots do
12 | local old_right = slot_panel and slot_panel:right() or 0
13 | slot_panel = self._panel:panel({
14 | x = old_right,
15 | y = 0,
16 | w = quarter_width,
17 | h = self._panel:h(),
18 | valign = "grow"
19 | })
20 | self._player_slots[i] = {}
21 | self._player_slots[i].panel = slot_panel
22 | self._player_slots[i].outfit = {}
23 | local kit_menu = managers.menu:get_menu("kit_menu")
24 | if kit_menu then
25 | local kit_slot = kit_menu.renderer:get_player_slot_by_peer_id(i)
26 | if kit_slot then
27 | local outfit = kit_slot.outfit
28 | local character = kit_slot.params and kit_slot.params.character
29 | if outfit and character then
30 | self:set_slot_outfit(i, character, outfit)
31 | end
32 | end
33 | end
34 | end
35 | end
36 |
37 |
38 | -- Modified to support additional players. Seems to just reduce font size when needed?
39 | function TeamLoadoutItem:reduce_to_small_font(iteration)
40 | TeamLoadoutItem.super.reduce_to_small_font(self, iteration)
41 |
42 | local num_player_slots = BigLobbyGlobals:num_player_slots()
43 |
44 | -- Only code changed was replacing hardcoded 4 with variable num_player_slots
45 | TeamLoadoutItem.super.reduce_to_small_font(self)
46 | for i = 1, num_player_slots do
47 | if self._player_slots and self._player_slots[i].box then
48 | self._player_slots[i].box:create_sides(self._player_slots[i].panel, {
49 | sides = {
50 | 1,
51 | 1,
52 | 1,
53 | 1
54 | }
55 | })
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/lua/lib/managers/mission/_elementareatrigger.lua:
--------------------------------------------------------------------------------
1 | -- Store original functions from the ones we modify
2 | local orig_ElementAreaTrigger = {
3 | project_amount_all = ElementAreaTrigger.project_amount_all
4 | }
5 |
6 |
7 | -- Capping the value to 4 for `criminals`/`local_criminals` instigators to avoid
8 | -- some event comparisons that fail above expected max value of 4.
9 | -- Start of Framing Frame Day 2 where everyone needs to be in the train is said to be affected
10 | function ElementAreaTrigger:project_amount_all()
11 | local i = orig_ElementAreaTrigger.project_amount_all(self)
12 |
13 | -- Ensure i is no higher than 4 for these instigators (May also want to include `ai_teammates`?)
14 | -- This value for these instigators includes both Peers and AI criminals
15 | if self._values.instigator == "criminals" or self._values.instigator == "local_criminals" then
16 | i = i > 4 and 4 or i
17 | end
18 |
19 | return i
20 | end
21 |
--------------------------------------------------------------------------------
/lua/lib/managers/mission/_elementfilter.lua:
--------------------------------------------------------------------------------
1 | -- Store the original _check_players function for use later
2 | local orig__ElementFilter = {}
3 | orig__ElementFilter._check_players = ElementFilter._check_players
4 |
5 |
6 | -- This function must be modified to allow for proper objective activation with greater than 4 players
7 | function ElementFilter:_check_players()
8 |
9 |
10 |
11 |
12 | -- Original Code --
13 | local players = Global.running_simulation and managers.editor:mission_player()
14 | players = players or managers.network:session() and managers.network:session():amount_of_players()
15 | if not players then
16 | return false
17 | end
18 | -- End Original Code --
19 |
20 |
21 |
22 |
23 | -- Check for >4 players for objective activation fixing
24 | if self._values.player_4 and players >= 4 then
25 | return true
26 | end
27 |
28 | -- Call the original function and return its value if the code above does not return anything
29 | return orig__ElementFilter._check_players(self)
30 | end
31 |
--------------------------------------------------------------------------------
/lua/lib/network/base/_basenetworksession.lua:
--------------------------------------------------------------------------------
1 | local orig_BaseNetworkSession = {
2 | check_peer_preferred_character = BaseNetworkSession.check_peer_preferred_character
3 | }
4 |
5 |
6 | -- Modified to support additional peers.
7 | function BaseNetworkSession:on_network_stopped()
8 | local num_player_slots = BigLobbyGlobals:num_player_slots()
9 |
10 | -- Only code changed was replacing hardcoded 4 with variable num_player_slots
11 | for k = 1, num_player_slots do
12 | self:on_drop_in_pause_request_received(k, nil, false)
13 | local peer = self:peer(k)
14 | if peer then
15 | peer:unit_delete()
16 | end
17 | end
18 | if self._local_peer then
19 | self:on_drop_in_pause_request_received(self._local_peer:id(), nil, false)
20 | end
21 |
22 | -- Resets host lobby size preference when leaving their lobby
23 | Global.BigLobbyPersist.num_players = nil
24 | -- Update this variable in case the player left from lobby screen (doesn't reload the mod)
25 | BigLobbyGlobals.num_players = BigLobbyGlobals.num_players_settings--Global.BigLobbyPersist.num_players
26 | end
27 |
28 |
29 | -- Modified to support additional peers.
30 | function BaseNetworkSession:_get_peer_outfit_versions_str()
31 | local num_player_slots = BigLobbyGlobals:num_player_slots()
32 |
33 | -- Only code changed was replacing hardcoded 4 with variable num_player_slots
34 | local outfit_versions_str = ""
35 | for peer_id = 1, num_player_slots do
36 | local peer
37 | if peer_id == self._local_peer:id() then
38 | peer = self._local_peer
39 | else
40 | peer = self._peers[peer_id]
41 | end
42 | if peer and peer:waiting_for_player_ready() then
43 | outfit_versions_str = outfit_versions_str .. tostring(peer_id) .. "-" .. peer:outfit_version() .. "."
44 | end
45 | end
46 | return outfit_versions_str
47 | end
48 |
49 |
50 | -- Modified to provide all peers with a character, regardless of free characters.
51 | function BaseNetworkSession:check_peer_preferred_character(preferred_character)
52 | local all_characters = clone(CriminalsManager.character_names())
53 | local character
54 |
55 | -- Only get a character through the normal method if one is availiable
56 | if #self._peers_all < #all_characters then
57 | -- Call Original Code
58 | character = orig_BaseNetworkSession.check_peer_preferred_character(self, preferred_character)
59 | end
60 |
61 | -- Get a new character if all have already been taken
62 | if character == nil then
63 | -- Allow them to use their preferred character first
64 | local preferreds = string.split(preferred_character, " ")
65 | for _, preferred in ipairs(preferreds) do
66 | if table.contains(all_characters, preferred) then
67 | return preferred
68 | end
69 | end
70 |
71 | -- Fallback to just getting a random character
72 | character = all_characters[math.random(#all_characters)]
73 | end
74 |
75 | return character
76 | end
77 |
--------------------------------------------------------------------------------
/lua/lib/network/base/_clientnetworksession.lua:
--------------------------------------------------------------------------------
1 | local orig__ClientNetworkSession = {}
2 | orig__ClientNetworkSession.on_join_request_reply = ClientNetworkSession.on_join_request_reply
3 |
4 |
5 | function ClientNetworkSession:on_join_request_reply(...)
6 | -- Place params in table
7 | local params = {...}
8 |
9 | -- Get params we want based on if the func signature is correct
10 | local reply = params[1]
11 | local sender = #params==18 and params[18] -- last param should now be 19
12 | local num_players = sender and type(params[17]) == "number" and params[17] -- param 16 should now be 18
13 |
14 | -- If the response is `1`(ok), set BigLobby to use host preference or 4 if
15 | -- a regular lobby (num_players param is falsey).
16 | if reply == 1 then
17 | -- Persisting the value across BLT reloads is required, otherwise when you
18 | -- reach the mission briefing screen, it will use your prefs not hosts.
19 | Global.BigLobbyPersist.num_players = num_players or 4
20 |
21 | -- Updates state for current BLT instance
22 | BigLobbyGlobals.num_players = Global.BigLobbyPersist.num_players
23 | end
24 |
25 | -- Assign sender to original param 16 for the original func call to use
26 | if sender then params[17] = params[18] end
27 |
28 | -- Pass params on to the original call
29 | orig__ClientNetworkSession.on_join_request_reply(self, unpack(params))
30 | end
31 |
--------------------------------------------------------------------------------
/lua/lib/network/base/_hostnetworksession.lua:
--------------------------------------------------------------------------------
1 | -- Modified hardcoded value to allow returning available peer id up to the actual limit.
2 | -- Assigns a free Peer ID to new joining peer
3 | function HostNetworkSession:_get_free_client_id()
4 | -- The below loop stops when index(i) reaches this value
5 | local num_player_slots = (BigLobbyGlobals:num_player_slots() + 1)
6 |
7 | -- The player slot to start from(Host is 1 so defaults to 2)
8 | local i = 2
9 | repeat
10 | if not self._peers[i] then
11 | local is_dirty = false
12 | for peer_id, peer in pairs(self._peers) do
13 | if peer:handshakes()[i] then
14 | is_dirty = true
15 | end
16 | end
17 | if not is_dirty then
18 | return i
19 | end
20 | end
21 | i = i + 1
22 | until i == num_player_slots
23 | end
24 |
25 |
26 | -- Modified hardcoded value to prevent disabling the ability to join the server until actual limit is reached.
27 | function HostNetworkSession:chk_server_joinable_state()
28 | local num_player_slots = (BigLobbyGlobals:num_player_slots() - 1)
29 |
30 |
31 |
32 |
33 | -- Original Code --
34 | for peer_id, peer in pairs(self._peers) do
35 | if peer:force_open_lobby_state() then
36 | print("force-opening lobby for peer", peer_id)
37 | managers.network.matchmake:set_server_joinable(true)
38 | return
39 | end
40 | end
41 | -- End Original Code --
42 |
43 |
44 |
45 |
46 | -- num_player_slots variable instead of hardcoded 3, prevent disabling join early.
47 | if table.size(self._peers) >= num_player_slots then
48 | managers.network.matchmake:set_server_joinable(false)
49 | return
50 | end
51 |
52 |
53 |
54 |
55 | -- Original Code --
56 | local game_state_name = game_state_machine:last_queued_state_name()
57 | if BaseNetworkHandler._gamestate_filter.any_end_game[game_state_name] then
58 | managers.network.matchmake:set_server_joinable(false)
59 | return
60 | end
61 | if not self:_get_free_client_id() then
62 | managers.network.matchmake:set_server_joinable(false)
63 | return
64 | end
65 | if not self._state:is_joinable(self._state_data) then
66 | managers.network.matchmake:set_server_joinable(false)
67 | return
68 | end
69 | if NetworkManager.DROPIN_ENABLED then
70 | if BaseNetworkHandler._gamestate_filter.lobby[game_state_name] then
71 | managers.network.matchmake:set_server_joinable(true)
72 | return
73 | elseif managers.groupai and not managers.groupai:state():chk_allow_drop_in() or not Global.game_settings.drop_in_allowed then
74 | managers.network.matchmake:set_server_joinable(false)
75 | return
76 | end
77 | elseif not BaseNetworkHandler._gamestate_filter.lobby[game_state_name] then
78 | managers.network.matchmake:set_server_joinable(false)
79 | return
80 | end
81 | managers.network.matchmake:set_server_joinable(true)
82 | -- End Original Code --
83 | end
84 |
--------------------------------------------------------------------------------
/lua/lib/network/base/_networkmanager.lua:
--------------------------------------------------------------------------------
1 | local orig__NetworkManager = {
2 | start_network = NetworkManager.start_network,
3 | on_peer_added = NetworkManager.on_peer_added
4 | }
5 |
6 | -- Modified to alter the display of player count in lobbies
7 | function NetworkManager:on_peer_added(peer, peer_id)
8 | orig__NetworkManager.on_peer_added(self, peer, peer_id)
9 |
10 | if Network:is_server() then
11 | -- Change the crime.net display to show the % of players relative to the lobby size set by host.
12 | local ratio = managers.network:session():amount_of_players() / BigLobbyGlobals:num_player_slots()
13 | local ratio_to_icon = math.clamp( math.ceil(4 * ratio), 1, 4 )
14 |
15 | managers.network.matchmake:set_num_players( ratio_to_icon )
16 | end
17 | end
18 |
19 |
20 | -- Adds two new handlers for network messages to handle the `biglobby__` prefix modifications.
21 | function NetworkManager:start_network()
22 | if not self._started then
23 | self:register_handler("biglobby__connection", BigLobby__ConnectionNetworkHandler)
24 | self:register_handler("biglobby__unit", BigLobby__UnitNetworkHandler)
25 | end
26 |
27 | orig__NetworkManager.start_network(self)
28 | end
29 |
--------------------------------------------------------------------------------
/lua/lib/network/base/_networkpeer.lua:
--------------------------------------------------------------------------------
1 | -- Store original functions from the ones we modify
2 | local orig_NetworkPeer = {
3 | send = NetworkPeer.send
4 | }
5 |
6 |
7 | function NetworkPeer:send(func_name, ...)
8 | -- In biglobby mode if the func is matched, call the prefixed version instead
9 | if not BigLobbyGlobals:is_small_lobby() and BigLobbyGlobals.network_handler_funcs[func_name] then
10 | func_name = 'biglobby__' .. func_name
11 | end
12 |
13 | -- Call Original Code
14 | orig_NetworkPeer.send(self, func_name, ...)
15 | end
16 |
--------------------------------------------------------------------------------
/lua/lib/network/base/handlers/_connectionnetworkhandler.lua:
--------------------------------------------------------------------------------
1 | -- Extends the ConnectionNetworkHandler class to add our own connection network calls
2 | -- For function modifications use the original function name it will be prefixed later
3 | BigLobby__ConnectionNetworkHandler = BigLobby__ConnectionNetworkHandler or class(ConnectionNetworkHandler)
4 |
5 |
6 | -- Additional `num_players` parameter(set in pdmod xml) for adjusting BigLobby to host lobby size preference
7 | -- params: [ reply_id, my_peer_id, my_character, level_index, difficulty_index, state, server_character,
8 | -- user_id, mission, job_id_index, job_stage, alternative_job_stage, interupt_job_stage_level_index,
9 | -- xuid, auth_ticket, num_players, sender ]
10 | -- The function is effectively the same, varargs(...) are used instead to support
11 | -- passing an extra param when in BigLobby mode.
12 | function BigLobby__ConnectionNetworkHandler:join_request_reply(...)
13 | if not self._verify_in_client_session() then
14 | return
15 | end
16 |
17 | managers.network:session():on_join_request_reply(...)
18 | end
19 |
20 |
21 | -- Will add a prefix of `biglobby__` to all functions our definitions use
22 | -- Required to maintain compatibility with normal lobbies.
23 | BigLobbyGlobals:rename_handler_funcs(BigLobby__ConnectionNetworkHandler)
24 |
--------------------------------------------------------------------------------
/lua/lib/network/base/session_states/_hoststateingame.lua:
--------------------------------------------------------------------------------
1 | -- Unfortunately no clean way to modify this bit of code, so I have to include the
2 | -- original code with modified, could cause problems with other mods that would want to touch this function
3 |
4 | function HostStateInGame:on_join_request_received(data, peer_name, peer_account_type_str, peer_account_id, is_invite, client_preferred_character, dlcs, xuid, peer_level, peer_rank, peer_stinger_index, gameversion, join_attempt_identifier, auth_ticket, sender)
5 |
6 | -- Number of players allowed to join the game(excluding the host)
7 | local num_player_slots = BigLobbyGlobals:num_player_slots() - 1
8 |
9 | -- Original Code --
10 | print("[HostStateInGame:on_join_request_received]", data, peer_name, peer_account_type_str, peer_account_id, client_preferred_character, dlcs, xuid, peer_level, gameversion, join_attempt_identifier, sender:ip_at_index(0))
11 |
12 | local peer_id = sender:ip_at_index(0)
13 | local my_user_id = data.local_peer:user_id() or ""
14 | local drop_in_name = peer_name
15 |
16 | if peer_account_type_str == "STEAM" then
17 | local temp = peer_name
18 |
19 | if SystemInfo:distribution() == Idstring("STEAM") then
20 | peer_name = managers.network.account:username_by_id(peer_account_id)
21 | elseif SystemInfo:matchmaking() == Idstring("MM_STEAM") then
22 | peer_name = managers.network.matchmake:username_by_id(peer_account_id)
23 | end
24 |
25 | if peer_name == "" or peer_name == "[unknown]" then
26 | peer_name = temp
27 | end
28 | end
29 |
30 | if SocialHubFriends:is_blocked(peer_id) then
31 | self:_send_request_denied(sender, 11, my_user_id)
32 |
33 | return
34 | end
35 |
36 | if managers.network.matchmake:get_lobby_type() == "friend" then
37 | print("[HostStateInGame:on_join_request_received] lobby type friend only, check if friend")
38 |
39 | if SocialHubFriends:is_friend_global(peer_id, peer_account_type_str, peer_account_id) then
40 | print("[HostStateInGame:on_join_request_received] ok we are friend with ", peer_name)
41 | else
42 | print("[HostStateInGame:on_join_request_received] we are NOT friend with ", peer_name, " deny request")
43 | self:_send_request_denied(sender, 12, my_user_id)
44 |
45 | return
46 | end
47 | end
48 |
49 | if self:_has_peer_left_PSN(peer_name) then
50 | print("this CLIENT has left us from PSN, ignore his request", peer_name)
51 |
52 | return
53 | elseif not self:_is_in_server_state() then
54 | self:_send_request_denied(sender, 0, my_user_id)
55 |
56 | return
57 | elseif not NetworkManager.DROPIN_ENABLED or not Global.game_settings.drop_in_allowed then
58 | self:_send_request_denied(sender, 3, my_user_id)
59 |
60 | return
61 | elseif managers.groupai and not managers.groupai:state():chk_allow_drop_in() then
62 | self:_send_request_denied(sender, 0, my_user_id)
63 |
64 | return
65 | elseif self:_is_banned(peer_name, peer_account_id) then
66 | self:_send_request_denied(sender, 9, my_user_id)
67 |
68 | return
69 | elseif peer_level < Global.game_settings.reputation_permission then
70 | self:_send_request_denied(sender, 6, my_user_id)
71 |
72 | return
73 | elseif gameversion ~= -1 and gameversion ~= managers.network.matchmake.GAMEVERSION then
74 | self:_send_request_denied(sender, 7, my_user_id)
75 |
76 | return
77 | elseif data.wants_to_load_level then
78 | self:_send_request_denied(sender, 13, my_user_id)
79 |
80 | return
81 | elseif not managers.network:session():local_peer() then
82 | self:_send_request_denied(sender, 0, my_user_id)
83 |
84 | return
85 | elseif not MenuCallbackHandler:is_modded_client() and not Global.game_settings.allow_modded_players then
86 | local is_modded = false
87 |
88 | if SystemInfo:distribution() == Idstring("STEAM") and peer_account_type_str == "STEAM" then
89 | local user = Steam:user(sender:ip_at_index(0))
90 | is_modded = user:rich_presence("is_modded") == "1"
91 | end
92 |
93 | if SystemInfo:distribution() == Idstring("EPIC") and peer_account_type_str == "EPIC" then
94 | -- Nothing
95 | end
96 |
97 | if is_modded then
98 | self:_send_request_denied(sender, 10, my_user_id)
99 |
100 | return
101 | end
102 | end
103 |
104 | local old_peer = data.session:chk_peer_already_in(sender)
105 |
106 | if old_peer then
107 | if join_attempt_identifier ~= old_peer:join_attempt_identifier() then
108 | self:_send_request_denied(sender, 14, my_user_id)
109 | data.session:remove_peer(old_peer, old_peer:id(), "lost")
110 | end
111 |
112 | return
113 | end
114 | -- End Original Code --
115 |
116 | -- num_player_slots variable instead of hardcoded 3, removes enforced limit.
117 | if num_player_slots <= table.size(data.peers) then
118 | print("server is full")
119 | self:_send_request_denied(sender, 5, my_user_id)
120 |
121 | return
122 | end
123 |
124 | -- Original Code --
125 | local character = managers.network:session():check_peer_preferred_character(client_preferred_character)
126 | local xnaddr = ""
127 |
128 | if SystemInfo:platform() == Idstring("X360") or SystemInfo:platform() == Idstring("XB1") then
129 | xnaddr = managers.network.matchmake:external_address(sender)
130 | end
131 |
132 | local new_peer_id, new_peer = nil
133 | new_peer_id, new_peer = data.session:add_peer(peer_name, nil, false, false, false, nil, character, sender:ip_at_index(0), peer_account_type_str, peer_account_id, xuid, xnaddr)
134 |
135 | if not new_peer_id then
136 | print("there was no clean peer_id")
137 | self:_send_request_denied(sender, 0, my_user_id)
138 |
139 | return
140 | end
141 |
142 | new_peer:set_dlcs(dlcs)
143 | new_peer:set_xuid(xuid)
144 | new_peer:set_name_drop_in(drop_in_name)
145 | new_peer:set_join_attempt_identifier(join_attempt_identifier)
146 |
147 | local new_peer_rpc = nil
148 |
149 | if sender:protocol_at_index(0) == "TCP_IP" then
150 | new_peer_rpc = managers.network:session():resolve_new_peer_rpc(new_peer, sender)
151 | else
152 | new_peer_rpc = sender
153 | end
154 |
155 | new_peer:set_rpc(new_peer_rpc)
156 | new_peer:set_ip_verified(true)
157 | Network:add_co_client(new_peer_rpc)
158 |
159 | if not new_peer:begin_ticket_session(auth_ticket) then
160 | self:_send_request_denied(sender, 8, my_user_id)
161 | data.session:remove_peer(new_peer, new_peer:id(), "auth_fail")
162 |
163 | return
164 | end
165 |
166 | local ticket = new_peer:create_ticket(data.local_peer:account_id())
167 | local level_index = tweak_data.levels:get_index_from_level_id(Global.game_settings.level_id)
168 | local difficulty_index = tweak_data:difficulty_to_index(Global.game_settings.difficulty)
169 | local job_id_index = 0
170 | local job_stage = 0
171 | local alternative_job_stage = 0
172 | local interupt_job_stage_level_index = 0
173 |
174 | if managers.job:has_active_job() then
175 | job_id_index = tweak_data.narrative:get_index_from_job_id(managers.job:current_job_id())
176 | job_stage = managers.job:current_stage()
177 | alternative_job_stage = managers.job:alternative_stage() or 0
178 | local interupt_stage_level = managers.job:interupt_stage()
179 | interupt_job_stage_level_index = interupt_stage_level and tweak_data.levels:get_index_from_level_id(interupt_stage_level) or 0
180 | end
181 |
182 | local server_xuid = (SystemInfo:platform() == Idstring("X360") or SystemInfo:platform() == Idstring("XB1")) and managers.network.account:player_id() or ""
183 | -- End Original Code --
184 |
185 | -- Appears orginally, but is modified to include the num_player_slots parameter
186 | local params = {
187 | 1,
188 | new_peer_id,
189 | character,
190 | level_index,
191 | difficulty_index,
192 | Global.game_settings.one_down,
193 | self.STATE_INDEX,
194 | data.local_peer:character(),
195 | my_user_id,
196 | Global.game_settings.mission,
197 | job_id_index,
198 | job_stage,
199 | alternative_job_stage,
200 | interupt_job_stage_level_index,
201 | server_xuid,
202 | ticket,
203 | BigLobbyGlobals:num_player_slots()
204 | }
205 |
206 | new_peer:send("join_request_reply", unpack(params))
207 | -- Original Code --
208 | new_peer:send("set_loading_state", false, data.session:load_counter())
209 |
210 | if SystemInfo:platform() == Idstring("X360") or SystemInfo:platform() == Idstring("XB1") then
211 | new_peer:send("request_player_name_reply", managers.network:session():local_peer():name())
212 | end
213 |
214 | managers.vote:sync_server_kick_option(new_peer)
215 | data.session:send_ok_to_load_level()
216 | self:on_handshake_confirmation(data, new_peer, 1)
217 | new_peer:set_rank(peer_rank)
218 | new_peer:set_join_stinger_index(peer_stinger_index)
219 |
220 | self._new_peers[new_peer_id] = true
221 | -- End Original Code --
222 | end
--------------------------------------------------------------------------------
/lua/lib/network/base/session_states/_hoststateinlobby.lua:
--------------------------------------------------------------------------------
1 | -- Unfortunately no clean way to modify this bit of code, so I have to include the
2 | -- original code with modified, could cause problems with other mods that would want to touch this function
3 | function HostStateInLobby:on_join_request_received(data, peer_name, peer_account_type_str, peer_account_id, is_invite, client_preferred_character, dlcs, xuid, peer_level, peer_rank, peer_stinger_index, gameversion, join_attempt_identifier, auth_ticket, sender)
4 | print("[HostStateInLobby:on_join_request_received]", data, peer_name, peer_account_type_str, peer_account_id, is_invite, client_preferred_character, dlcs, xuid, peer_level, peer_rank, peer_stinger_index, gameversion, join_attempt_identifier, auth_ticket, sender:ip_at_index(0))
5 |
6 | -- Number of players allowed to join the game(excluding the host)
7 | local num_player_slots = BigLobbyGlobals:num_player_slots() - 1
8 |
9 | -- Original Code --
10 | local peer_id = sender:ip_at_index(0)
11 | local drop_in_name = peer_name
12 |
13 | if peer_account_type_str == "STEAM" then
14 | local temp = peer_name
15 |
16 | if SystemInfo:distribution() == Idstring("STEAM") then
17 | peer_name = managers.network.account:username_by_id(peer_account_id)
18 | elseif SystemInfo:matchmaking() == Idstring("MM_STEAM") then
19 | peer_name = managers.network.matchmake:username_by_id(peer_account_id)
20 | end
21 |
22 | if peer_name == "" or peer_name == "[unknown]" then
23 | peer_name = temp
24 | end
25 | end
26 |
27 | local my_user_id = data.local_peer:user_id() or ""
28 |
29 | if SocialHubFriends:is_blocked(peer_id) then
30 | self:_send_request_denied(sender, 11, my_user_id)
31 |
32 | return
33 | end
34 |
35 | if not is_invite and managers.network.matchmake:get_lobby_type() == "friend" then
36 | print("[HostStateInLobby:on_join_request_received] lobby type friend only, check if friend")
37 |
38 | if SocialHubFriends:is_friend_global(peer_id, peer_account_type_str, peer_account_id) then
39 | print("[HostStateInLobby:on_join_request_received] ok we are friend with ", peer_name)
40 | else
41 | print("[HostStateInLobby:on_join_request_received] we are NOT friend with ", peer_name, " deny request")
42 | self:_send_request_denied(sender, 12, my_user_id)
43 |
44 | return
45 | end
46 | end
47 |
48 | if self:_has_peer_left_PSN(peer_name) then
49 | print("this CLIENT has left us from PSN, ignore his request", peer_name)
50 |
51 | return
52 | end
53 |
54 | if self:_is_banned(peer_name, peer_account_id) then
55 | self:_send_request_denied(sender, 9, my_user_id)
56 |
57 | return
58 | end
59 |
60 | if not MenuCallbackHandler:is_modded_client() and not Global.game_settings.allow_modded_players then
61 | local is_modded = false
62 |
63 | if SystemInfo:distribution() == Idstring("STEAM") and peer_account_type_str == "STEAM" then
64 | local user = Steam:user(sender:ip_at_index(0))
65 | is_modded = user:rich_presence("is_modded") == "1"
66 | end
67 |
68 | if SystemInfo:distribution() == Idstring("EPIC") and peer_account_type_str == "EPIC" then
69 | -- Nothing
70 | end
71 |
72 | if is_modded then
73 | self:_send_request_denied(sender, 10, my_user_id)
74 |
75 | return
76 | end
77 | end
78 |
79 | if peer_level < Global.game_settings.reputation_permission then
80 | self:_send_request_denied(sender, 6, my_user_id)
81 |
82 | return
83 | end
84 |
85 | if gameversion ~= -1 and gameversion ~= managers.network.matchmake.GAMEVERSION then
86 | self:_send_request_denied(sender, 7, my_user_id)
87 |
88 | return
89 | end
90 |
91 | if data.wants_to_load_level then
92 | self:_send_request_denied(sender, 13, my_user_id)
93 |
94 | return
95 | end
96 |
97 | if not managers.network:session():local_peer() then
98 | self:_send_request_denied(sender, 0, my_user_id)
99 |
100 | return
101 | end
102 |
103 | local old_peer = data.session:chk_peer_already_in(sender)
104 |
105 | if old_peer then
106 | if join_attempt_identifier ~= old_peer:join_attempt_identifier() then
107 | self:_send_request_denied(sender, 14, my_user_id)
108 | data.session:remove_peer(old_peer, old_peer:id(), "lost")
109 | end
110 |
111 | return
112 | end
113 | -- End Original Code --
114 |
115 | -- num_player_slots variable instead of hardcoded 3, removes enforced limit.
116 | if table.size(data.peers) >= num_player_slots then
117 | print("server is full")
118 | self:_send_request_denied(sender, 5, my_user_id)
119 | return
120 | end
121 |
122 | -- Original Code --
123 | print("[HostStateInLobby:on_join_request_received] new peer accepted", peer_name)
124 |
125 | local character = managers.network:session():check_peer_preferred_character(client_preferred_character)
126 | local xnaddr = ""
127 |
128 | if SystemInfo:platform() == Idstring("X360") or SystemInfo:platform() == Idstring("XB1") then
129 | xnaddr = managers.network.matchmake:external_address(sender)
130 | end
131 |
132 | local new_peer_id, new_peer = nil
133 | new_peer_id, new_peer = data.session:add_peer(peer_name, nil, true, false, false, nil, character, sender:ip_at_index(0), peer_account_type_str, peer_account_id, xuid, xnaddr)
134 |
135 | if not new_peer_id then
136 | print("there was no clean peer_id")
137 | self:_send_request_denied(sender, 0, my_user_id)
138 |
139 | return
140 | end
141 |
142 | new_peer:set_dlcs(dlcs)
143 | new_peer:set_xuid(xuid)
144 | new_peer:set_name_drop_in(drop_in_name)
145 | new_peer:set_join_attempt_identifier(join_attempt_identifier)
146 |
147 | local new_peer_rpc = nil
148 |
149 | if sender:protocol_at_index(0) == "TCP_IP" then
150 | new_peer_rpc = managers.network:session():resolve_new_peer_rpc(new_peer, sender)
151 | else
152 | new_peer_rpc = sender
153 | end
154 |
155 | new_peer:set_rpc(new_peer_rpc)
156 | new_peer:set_ip_verified(true)
157 | Network:add_client(new_peer:rpc())
158 |
159 | if not new_peer:begin_ticket_session(auth_ticket) then
160 | self:_send_request_denied(sender, 8, my_user_id)
161 | data.session:remove_peer(new_peer, new_peer:id(), "auth_fail")
162 |
163 | return
164 | end
165 |
166 | local ticket = new_peer:create_ticket(data.local_peer:account_id())
167 |
168 | new_peer:set_entering_lobby(true)
169 |
170 | local level_index = tweak_data.levels:get_index_from_level_id(Global.game_settings.level_id)
171 | local difficulty_index = tweak_data:difficulty_to_index(Global.game_settings.difficulty)
172 | local job_id_index = 0
173 | local job_stage = 0
174 | local alternative_job_stage = 0
175 | local interupt_job_stage_level_index = 0
176 |
177 | if managers.job:has_active_job() then
178 | job_id_index = tweak_data.narrative:get_index_from_job_id(managers.job:current_job_id())
179 | job_stage = managers.job:current_stage()
180 | alternative_job_stage = managers.job:alternative_stage() or 0
181 | local interupt_stage_level = managers.job:interupt_stage()
182 | interupt_job_stage_level_index = interupt_stage_level and tweak_data.levels:get_index_from_level_id(interupt_stage_level) or 0
183 | end
184 | -- End Original Code --
185 |
186 | local server_xuid = (SystemInfo:platform() == Idstring("X360") or SystemInfo:platform() == Idstring("XB1")) and managers.network.account:player_id() or ""
187 |
188 | -- Appears orginally, but is modified to include the num_player_slots parameter
189 | local params = {
190 | 1,
191 | new_peer_id,
192 | character,
193 | level_index,
194 | difficulty_index,
195 | Global.game_settings.one_down,
196 | 1,
197 | data.local_peer:character(),
198 | my_user_id,
199 | Global.game_settings.mission,
200 | job_id_index,
201 | job_stage,
202 | alternative_job_stage,
203 | interupt_job_stage_level_index,
204 | server_xuid,
205 | ticket,
206 | BigLobbyGlobals:num_player_slots()
207 | }
208 |
209 | -- Original Code --
210 | new_peer:send("join_request_reply", unpack(params))
211 | new_peer:send("set_loading_state", false, data.session:load_counter())
212 |
213 | if SystemInfo:platform() == Idstring("X360") or SystemInfo:platform() == Idstring("XB1") then
214 | new_peer:send("request_player_name_reply", managers.network:session():local_peer():name())
215 | end
216 |
217 | managers.vote:sync_server_kick_option(new_peer)
218 | self:_introduce_new_peer_to_old_peers(data, new_peer, false, peer_name, new_peer:character(), "remove", new_peer:xuid(), new_peer:xnaddr())
219 | self:_introduce_old_peers_to_new_peer(data, new_peer)
220 | self:on_handshake_confirmation(data, new_peer, 1)
221 | managers.network:session():local_peer():sync_lobby_data(new_peer)
222 | managers.menu:play_join_stinger_by_index(peer_stinger_index)
223 | managers.network:session():send_to_peers_except(new_peer_id, "peer_joined_sound", peer_stinger_index)
224 | managers.crime_spree:on_peer_finished_loading(new_peer)
225 | -- End Original Code --
226 | end
--------------------------------------------------------------------------------
/lua/lib/network/handlers/_unitnetworkhandler.lua:
--------------------------------------------------------------------------------
1 | -- Extends the UnitNetworkHandler class to add our own unit network calls
2 | -- For function modifications use the original function name it will be prefixed later
3 | BigLobby__UnitNetworkHandler = BigLobby__UnitNetworkHandler or class(UnitNetworkHandler)
4 |
5 | -- Will add a prefix of `biglobby__` to all functions our definitions use
6 | -- Required to maintain compatibility with normal lobbies.
7 | BigLobbyGlobals:rename_handler_funcs(BigLobby__UnitNetworkHandler)
8 |
--------------------------------------------------------------------------------
/lua/lib/network/matchmaking/_networkmatchmakingepic.lua:
--------------------------------------------------------------------------------
1 | -- Used in `NetworkMatchMakingEPIC:create_lobby(settings)` when calling `Steam:create_lobby(f, NetworkMatchMakingEPIC.OPEN_SLOTS, "invisible")`
2 | -- If not adjusted to new player limit will prevent Steam allowing a connection, failing it.
3 | NetworkMatchMakingEPIC.OPEN_SLOTS = BigLobbyGlobals:num_player_slots()
4 |
5 | -- Prevent non BigLobby players from finding/joining this game.
6 | if not BigLobbyGlobals:is_small_lobby() then
7 | -- Version is included in search key now, not sure of any benefit changing game version?
8 | -- Assign a gameversion, to prevent outdated clients from connecting
9 | --NetworkMatchMakingEPIC.GAMEVERSION = BigLobbyGlobals:gameversion()
10 |
11 | -- Use the existing search key and concatenate `:biglobby-{{version}}` to it
12 | -- so other mods can use this filter/isolation method. If search key has not been
13 | -- modified prior it's value is likely `nil`.
14 | local bl_key = ":biglobby-" .. BigLobbyGlobals:version()
15 | local current_key = NetworkMatchMakingEPIC._BUILD_SEARCH_INTEREST_KEY
16 | NetworkMatchMakingEPIC._BUILD_SEARCH_INTEREST_KEY = current_key and current_key .. bl_key or bl_key
17 | end
18 |
--------------------------------------------------------------------------------
/lua/lib/network/matchmaking/_networkmatchmakingsteam.lua:
--------------------------------------------------------------------------------
1 | -- Used in `NetworkMatchMakingSTEAM:create_lobby(settings)` when calling `Steam:create_lobby(f, NetworkMatchMakingSTEAM.OPEN_SLOTS, "invisible")`
2 | -- If not adjusted to new player limit will prevent Steam allowing a connection, failing it.
3 | NetworkMatchMakingSTEAM.OPEN_SLOTS = BigLobbyGlobals:num_player_slots()
4 |
5 | -- Prevent non BigLobby players from finding/joining this game.
6 | if not BigLobbyGlobals:is_small_lobby() then
7 | -- Version is included in search key now, not sure of any benefit changing game version?
8 | -- Assign a gameversion, to prevent outdated clients from connecting
9 | --NetworkMatchMakingSTEAM.GAMEVERSION = BigLobbyGlobals:gameversion()
10 |
11 | -- Use the existing search key and concatenate `:biglobby-{{version}}` to it
12 | -- so other mods can use this filter/isolation method. If search key has not been
13 | -- modified prior it's value is likely `nil`.
14 | local bl_key = ":biglobby-" .. BigLobbyGlobals:version()
15 | local current_key = NetworkMatchMakingSTEAM._BUILD_SEARCH_INTEREST_KEY
16 | NetworkMatchMakingSTEAM._BUILD_SEARCH_INTEREST_KEY = current_key and current_key .. bl_key or bl_key
17 | end
18 |
--------------------------------------------------------------------------------
/lua/lib/tweak_data/_moneytweakdata.lua:
--------------------------------------------------------------------------------
1 | -- moneytweakdata.lua - MoneyTweakData:init, fixes infinite money loss at the results/exp screen.
2 | -- Must be in this seperate hook as the main init function is called on the loading of the tweak_data lua file, so this hook will be added after the main call of it has already taken place
3 | -- This method prevents issues with other mods that may also touch this function
4 | -- Gets called after every call of the init function on the MoneyTweakData class table, init is called in tweak_data after it has already been initialized for a particular difficulty
5 | Hooks:PostHook(MoneyTweakData, "init", "BigLobbyModifyMoneyTweak", function(self, tweak_data)
6 | self.alive_humans_multiplier = self._create_value_table(1, self.alive_players_max, BigLobbyGlobals:num_player_slots(), false, 1)
7 | end)
8 |
--------------------------------------------------------------------------------
/lua/lib/tweak_data/_tweakdata.lua:
--------------------------------------------------------------------------------
1 | -- Updates colours to support UI elements for additional peers while avoiding those
2 | -- that affect gameplay such as orange and yellow
3 |
4 | local num_player_slots = BigLobbyGlobals:num_player_slots()
5 |
6 | -- AI assigned colour:
7 | local team_ai = Vector3(0.2, 0.8, 1)
8 |
9 | -- Fixed colours
10 | tweak_data.peer_vector_colors = {}
11 |
12 | -- This doesn't appear to be referenced, not sure why it still exists in codebase
13 | tweak_data.peer_colors = {}
14 |
15 | -- Make sure we have enough colours to support the number of player slots
16 | local steps = 360 / num_player_slots
17 | for i = 0, num_player_slots - 1 do
18 | -- RGB channels
19 | local hue = i * steps
20 | local col = Vector3(_G.HUSL.huslp_to_rgb(hue, 100, 60))
21 |
22 | table.insert(tweak_data.peer_vector_colors, col)
23 | table.insert(tweak_data.peer_colors, tostring("team_colour_") .. i)
24 | end
25 |
26 | math.randomseed(42)
27 | table.shuffle(tweak_data.peer_vector_colors)
28 | math.randomseed(os.time())
29 |
30 | -- AI labels will use the last value so we add it at the end
31 | table.insert(tweak_data.peer_vector_colors, team_ai)
32 | table.insert(tweak_data.peer_colors, "mrai")
33 |
34 | -- Dynamically added now based on peer_vector_colors table
35 | tweak_data.chat_colors = {}
36 | for i = 1, #tweak_data.peer_vector_colors do
37 | tweak_data.chat_colors[i] = Color(tweak_data.peer_vector_colors[i]:unpack())
38 | end
39 |
40 | -- Use the same colours created for chat for preplanning
41 | tweak_data.preplanning_peer_colors = {}
42 | for i = 1, #tweak_data.peer_vector_colors do
43 | tweak_data.preplanning_peer_colors[i] = Color(tweak_data.peer_vector_colors[i]:unpack())
44 | end
45 |
46 | tweak_data.team_ai.stop_action.distance = 10000000000000000
47 |
--------------------------------------------------------------------------------
/mod.txt:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Biglobby3",
3 | "description": "Increase the player limit of a lobby from the original 4.",
4 | "author": "Polarathene, test1, Znix, Restoration Mod team",
5 | "contact": "no@support.com",
6 | "version": "3.27.6",
7 | "blt_version": 2,
8 | "priority" : 400,
9 | "updates": [
10 | {
11 | "identifier": "biglobby3",
12 | "host": {
13 | "meta": "https://raw.githubusercontent.com/Crackdown-PD2/BigLobby3/master/updates/meta_biglobby3.json"
14 | }
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/supermod.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | <:include src="hooks.xml" />
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/updates/biglobby3.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Crackdown-PD2/BigLobby3/29ea99d6068a0610ce70bc3f402a4bd10774d118/updates/biglobby3.zip
--------------------------------------------------------------------------------
/updates/meta_biglobby3.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "ident": "biglobby3",
4 | "download_url": "https://github.com/Crackdown-PD2/BigLobby3/raw/master/updates/biglobby3.zip",
5 | "patchnotes_url": "https://github.com/Crackdown-PD2/BigLobby3/wiki/Big-Lobby-3-Changelog",
6 | "version": "3.27.6"
7 | }
8 | ]
--------------------------------------------------------------------------------