mirror of
https://github.com/wlinator/luminara.git
synced 2024-10-02 18:03:12 +00:00
init - clone from personal Git
This commit is contained in:
commit
5bc6e3dca4
25 changed files with 3039 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
venv/
|
||||
.idea/
|
||||
__pycache__/
|
||||
|
||||
*.db
|
||||
.env
|
339
LICENSE
Normal file
339
LICENSE
Normal file
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
53
data/BlackJackStats.py
Normal file
53
data/BlackJackStats.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
import json
|
||||
|
||||
from db import database
|
||||
|
||||
|
||||
class BlackJackStats:
|
||||
def __init__(self, user_id, is_won, bet, payout, hand_player, hand_dealer):
|
||||
self.user_id = user_id
|
||||
self.is_won = is_won
|
||||
self.bet = bet
|
||||
self.payout = payout
|
||||
self.hand_player = json.dumps(hand_player)
|
||||
self.hand_dealer = json.dumps(hand_dealer)
|
||||
|
||||
def push_one(self):
|
||||
query = """
|
||||
INSERT INTO stats_bj (user_id, is_won, bet, payout, hand_player, hand_dealer)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
"""
|
||||
|
||||
values = (self.user_id, self.is_won, self.bet, self.payout, self.hand_player, self.hand_dealer)
|
||||
|
||||
database.execute_query(query, values)
|
||||
|
||||
@staticmethod
|
||||
def fetch_all():
|
||||
query = "SELECT * FROM stats_bj"
|
||||
rows = database.select_query(query)
|
||||
|
||||
stats_list = []
|
||||
for row in rows:
|
||||
# extract individual columns from the row
|
||||
id, user_id, is_won, bet, payout, hand_player_json, hand_dealer_json = row
|
||||
|
||||
# convert hands from JSON strings to lists
|
||||
hand_player = json.loads(hand_player_json)
|
||||
hand_dealer = json.loads(hand_dealer_json)
|
||||
|
||||
# assign to dictionary
|
||||
stats_data = {
|
||||
'id': id,
|
||||
'user_id': user_id,
|
||||
'is_won': bool(is_won),
|
||||
'bet': bet,
|
||||
'payout': payout,
|
||||
'hand_player': hand_player,
|
||||
'hand_dealer': hand_dealer
|
||||
}
|
||||
|
||||
# add the row to the list
|
||||
stats_list.append(stats_data)
|
||||
|
||||
return stats_list
|
47
data/Currency.py
Normal file
47
data/Currency.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
from db import database
|
||||
|
||||
|
||||
class Currency:
|
||||
@staticmethod
|
||||
def get_cash_balance(user_id):
|
||||
query = "SELECT cash_balance FROM currency WHERE user_id={}".format(user_id)
|
||||
cash_balance = database.select_query(query)
|
||||
|
||||
if not cash_balance:
|
||||
Currency.create_new_balance(user_id)
|
||||
return 50
|
||||
|
||||
return cash_balance[0][0]
|
||||
|
||||
@staticmethod
|
||||
def get_special_balance(user_id):
|
||||
query = "SELECT special_balance FROM currency WHERE user_id={}".format(user_id)
|
||||
special_balance = database.select_query(query)
|
||||
|
||||
if not special_balance:
|
||||
Currency.create_new_balance(user_id)
|
||||
return 3
|
||||
|
||||
return special_balance[0][0]
|
||||
|
||||
@staticmethod
|
||||
def update_cash_balance(user_id, amount):
|
||||
if amount < 0:
|
||||
amount = 0
|
||||
|
||||
query = "UPDATE currency SET cash_balance = {} WHERE user_id = {}".format(round(amount, 2), user_id)
|
||||
database.execute_query(query)
|
||||
|
||||
@staticmethod
|
||||
def update_special_balance(user_id, amount):
|
||||
if amount < 0:
|
||||
amount = 0
|
||||
|
||||
query = "UPDATE currency SET special_balance = {} WHERE user_id = {}".format(amount, user_id)
|
||||
database.execute_query(query)
|
||||
|
||||
@staticmethod
|
||||
def create_new_balance(user_id):
|
||||
query = "INSERT INTO currency(user_id, cash_balance, special_balance) VALUES ({}, 50, 3)".format(user_id)
|
||||
database.execute_query(query)
|
||||
print(f"BALANCE UPDATE --- USER with ID {user_id} created new balance")
|
46
data/Dailies.py
Normal file
46
data/Dailies.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
import json
|
||||
import time
|
||||
|
||||
from db import database
|
||||
|
||||
with open("json/economy.json") as file:
|
||||
json_data = json.load(file)
|
||||
|
||||
|
||||
class Dailies:
|
||||
def __init__(self, user_id, claimed_at, next_available):
|
||||
self.user_id = user_id
|
||||
self.amount = json_data["daily_reward"]
|
||||
self.claimed_at = claimed_at
|
||||
self.next_available = next_available
|
||||
|
||||
def push(self):
|
||||
query = """
|
||||
INSERT INTO dailies (user_id, amount, claimed_at, next_available)
|
||||
VALUES (?, ?, ?, ?)
|
||||
"""
|
||||
|
||||
values = (self.user_id, self.amount, self.claimed_at, self.next_available)
|
||||
|
||||
database.execute_query(query, values)
|
||||
|
||||
@staticmethod
|
||||
def cooldown_check(user_id):
|
||||
query = """
|
||||
SELECT next_available
|
||||
FROM dailies
|
||||
WHERE id = (
|
||||
SELECT MAX(id)
|
||||
FROM dailies
|
||||
WHERE user_id = ?
|
||||
)
|
||||
"""
|
||||
|
||||
values = (user_id,)
|
||||
result = database.select_query_one(query, values)
|
||||
current_time = time.time()
|
||||
|
||||
if result and current_time < result:
|
||||
return False, result
|
||||
|
||||
return True, result
|
23
data/SlotsStats.py
Normal file
23
data/SlotsStats.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
import json
|
||||
|
||||
from db import database
|
||||
|
||||
|
||||
class SlotsStats:
|
||||
def __init__(self, user_id, is_won, bet, payout, spin_type, icons):
|
||||
self.user_id = user_id
|
||||
self.is_won = is_won
|
||||
self.bet = bet
|
||||
self.payout = payout
|
||||
self.spin_type = spin_type
|
||||
self.icons = json.dumps(icons)
|
||||
|
||||
def push_one(self):
|
||||
query = """
|
||||
INSERT INTO stats_slots (user_id, is_won, bet, payout, spin_type, icons)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
"""
|
||||
|
||||
values = (self.user_id, self.is_won, self.bet, self.payout, self.spin_type, self.icons)
|
||||
|
||||
database.execute_query(query, values)
|
125
data/Xp.py
Normal file
125
data/Xp.py
Normal file
|
@ -0,0 +1,125 @@
|
|||
import os
|
||||
import random
|
||||
import time
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from db import database
|
||||
from sb_tools import xp_functions
|
||||
|
||||
load_dotenv('.env')
|
||||
|
||||
|
||||
class Xp:
|
||||
|
||||
@staticmethod
|
||||
def get_user_xp_data(user_id):
|
||||
query = "SELECT user_xp, user_level, cooldown FROM xp WHERE user_id = {}".format(user_id)
|
||||
data = database.select_query(query)
|
||||
|
||||
if data:
|
||||
return data
|
||||
else:
|
||||
Xp.create_new_user_xp(user_id)
|
||||
return [(3, 0, time.time())]
|
||||
|
||||
@staticmethod
|
||||
def update_user_xp(user_id, new_xp, new_level, new_cooldown):
|
||||
query = "UPDATE xp SET user_xp = {}, user_level = {}, cooldown = {} WHERE user_id = {}" \
|
||||
.format(new_xp, new_level, new_cooldown, user_id)
|
||||
database.execute_query(query)
|
||||
|
||||
@staticmethod
|
||||
def create_new_user_xp(user_id):
|
||||
query = "INSERT INTO xp(user_id, user_xp, user_level, cooldown) VALUES ({}, 3, 0, {})".format(user_id,
|
||||
time.time())
|
||||
database.execute_query(query)
|
||||
print(f"XP UPDATE --- USER with ID {user_id} started leveling (db_lvl_null)")
|
||||
|
||||
@staticmethod
|
||||
def calculate_rank(user_id):
|
||||
query = "SELECT user_id, user_xp, user_level FROM xp ORDER BY user_level DESC, user_xp DESC"
|
||||
data = database.select_query(query)
|
||||
|
||||
leaderboard = []
|
||||
rank = 1
|
||||
for row in data:
|
||||
row_user_id = row[0]
|
||||
user_xp = row[1]
|
||||
user_level = row[2]
|
||||
leaderboard.append((row_user_id, user_xp, user_level, rank))
|
||||
rank += 1
|
||||
|
||||
user_rank = None
|
||||
for entry in leaderboard:
|
||||
if entry[0] == user_id:
|
||||
user_rank = entry[3]
|
||||
break
|
||||
|
||||
return user_rank
|
||||
|
||||
@staticmethod
|
||||
async def assign_level_role(user, level):
|
||||
|
||||
level_roles = {
|
||||
"level_5": 1118491431036792922,
|
||||
"level_10": 1118491486259003403,
|
||||
"level_15": 1118491512536301570,
|
||||
"level_20": 1118491532111126578,
|
||||
"level_25": 1118491554005393458,
|
||||
"level_30": 1118491572770713710,
|
||||
"level_35": 1118491596820840492,
|
||||
"level_40": 1118491622045405287,
|
||||
"level_45": 1118491650721853500,
|
||||
"level_50": 1118491681004732466,
|
||||
# Add more level roles as needed
|
||||
}
|
||||
|
||||
guild = user.guild
|
||||
current_level_role = None
|
||||
new_level_role_id = level_roles.get(f"level_{level}")
|
||||
|
||||
for role in user.roles:
|
||||
if role.id in level_roles.values() and role.id != new_level_role_id:
|
||||
current_level_role = role
|
||||
break
|
||||
|
||||
new_level_role = guild.get_role(new_level_role_id)
|
||||
await user.add_roles(new_level_role)
|
||||
|
||||
if current_level_role:
|
||||
await user.remove_roles(current_level_role)
|
||||
|
||||
return new_level_role_id
|
||||
|
||||
@staticmethod
|
||||
def generate_progress_bar(current_value, target_value, bar_length=10):
|
||||
progress = current_value / target_value
|
||||
filled_length = int(bar_length * progress)
|
||||
empty_length = bar_length - filled_length
|
||||
bar = "▰" * filled_length + "▱" * empty_length
|
||||
return f"`{bar}` {current_value}/{target_value}"
|
||||
|
||||
@staticmethod
|
||||
def load_leaderboard():
|
||||
query = "SELECT user_id, user_xp, user_level FROM xp ORDER BY user_level DESC, user_xp DESC"
|
||||
data = database.select_query(query)
|
||||
|
||||
leaderboard = []
|
||||
rank = 1
|
||||
for row in data:
|
||||
row_user_id = row[0]
|
||||
user_xp = row[1]
|
||||
user_level = row[2]
|
||||
needed_xp_for_next_level = xp_functions.xp_needed_for_next_level(user_level)
|
||||
leaderboard.append((row_user_id, user_xp, user_level, rank, needed_xp_for_next_level))
|
||||
rank += 1
|
||||
|
||||
return leaderboard
|
||||
|
||||
@staticmethod
|
||||
def load_gain_data():
|
||||
xp_gain = list(map(int, os.getenv("XP_GAIN").split(",")))
|
||||
cooldown = list(map(int, os.getenv("COOLDOWN").split(",")))
|
||||
|
||||
return random.choice(xp_gain), random.choice(cooldown)
|
61
db/database.py
Normal file
61
db/database.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
import sqlite3
|
||||
from sqlite3 import Error
|
||||
|
||||
|
||||
def create_connection():
|
||||
try:
|
||||
conn = sqlite3.connect("db/rcu.db")
|
||||
except Error as e:
|
||||
print("'create_connection()' Error occurred: {}".format(e))
|
||||
return
|
||||
|
||||
return conn
|
||||
|
||||
|
||||
def execute_query(query, values=None):
|
||||
conn = create_connection()
|
||||
cursor = conn.cursor()
|
||||
try:
|
||||
if values:
|
||||
cursor.execute(query, values)
|
||||
else:
|
||||
cursor.execute(query)
|
||||
|
||||
conn.commit()
|
||||
except Error as e:
|
||||
print("'execute_query()' Error occurred: {}".format(e))
|
||||
|
||||
return cursor
|
||||
|
||||
|
||||
def select_query(query, values=None):
|
||||
conn = create_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
if values:
|
||||
return cursor.execute(query, values).fetchall()
|
||||
else:
|
||||
return cursor.execute(query).fetchall()
|
||||
|
||||
except Error as e:
|
||||
return f"ERROR: {e}"
|
||||
|
||||
|
||||
def select_query_one(query, values=None):
|
||||
conn = create_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
if values:
|
||||
output = cursor.execute(query, values).fetchone()
|
||||
else:
|
||||
output = cursor.execute(query).fetchone()
|
||||
|
||||
if output:
|
||||
return output[0]
|
||||
|
||||
return None
|
||||
|
||||
except Error as e:
|
||||
return f"ERROR: {e}"
|
72
db/tables.py
Normal file
72
db/tables.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
from db import database
|
||||
|
||||
xp_table = """
|
||||
CREATE TABLE IF NOT EXISTS xp (
|
||||
user_id INTEGER PRIMARY KEY NOT NULL,
|
||||
user_xp INTEGER NOT NULL,
|
||||
user_level INTEGER NOT NULL,
|
||||
cooldown REAL
|
||||
)
|
||||
"""
|
||||
|
||||
currency_table = """
|
||||
CREATE TABLE IF NOT EXISTS currency (
|
||||
user_id INTEGER PRIMARY KEY NOT NULL,
|
||||
cash_balance INTEGER NOT NULL,
|
||||
special_balance INTEGER
|
||||
)
|
||||
"""
|
||||
|
||||
dailies_table = """
|
||||
CREATE TABLE IF NOT EXISTS dailies (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER,
|
||||
amount INTEGER,
|
||||
claimed_at REAL,
|
||||
next_available REAL
|
||||
)
|
||||
"""
|
||||
|
||||
stats_bj = """
|
||||
CREATE TABLE IF NOT EXISTS stats_bj (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER,
|
||||
is_won INTEGER,
|
||||
bet INTEGER,
|
||||
payout INTEGER,
|
||||
hand_player TEXT,
|
||||
hand_dealer TEXT
|
||||
)
|
||||
"""
|
||||
|
||||
stats_slots = """
|
||||
CREATE TABLE IF NOT EXISTS stats_slots (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER,
|
||||
is_won INTEGER,
|
||||
bet INTEGER,
|
||||
payout INTEGER,
|
||||
spin_type TEXT,
|
||||
icons TEXT
|
||||
)
|
||||
"""
|
||||
|
||||
stats_duel = """
|
||||
CREATE TABLE IF NOT EXISTS stats_duel (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER,
|
||||
is_won INTEGER,
|
||||
bet INTEGER
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
def sync_database():
|
||||
database.execute_query(xp_table)
|
||||
database.execute_query(currency_table)
|
||||
database.execute_query(dailies_table)
|
||||
database.execute_query(stats_bj)
|
||||
database.execute_query(stats_slots)
|
||||
database.execute_query(stats_duel)
|
||||
|
||||
print("On startup: database synced.")
|
213
json/economy.json
Normal file
213
json/economy.json
Normal file
|
@ -0,0 +1,213 @@
|
|||
{
|
||||
"emotes_guild_id": 1038051105642401812,
|
||||
"rc_guild_id": 719227135151046699,
|
||||
"daily_reward": 50,
|
||||
"daily_cooldown": 86400,
|
||||
"blackjack": {
|
||||
"emotes": {
|
||||
"hit_id": 1119262723285467156,
|
||||
"stand_id": 1118923298298929154
|
||||
},
|
||||
"reward_multiplier": 1,
|
||||
"deck_suits": [
|
||||
"♠",
|
||||
"♡",
|
||||
"♢",
|
||||
"♣"
|
||||
],
|
||||
"deck_ranks": [
|
||||
"A",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"10",
|
||||
"J",
|
||||
"Q",
|
||||
"K"
|
||||
]
|
||||
},
|
||||
"slots": {
|
||||
"emotes": {
|
||||
"slots_animated_id": 1119262805309259776,
|
||||
"slots_0_id": 1119262803816095825,
|
||||
"slots_1_id": 1119262801261760592,
|
||||
"slots_2_id": 1119262800049614939,
|
||||
"slots_3_id": 1119262796497039510,
|
||||
"slots_4_id": 1119262794676715681,
|
||||
"slots_5_id": 1119262792386621555,
|
||||
"slots_6_id": 1119262791061229669,
|
||||
"S_Wide": 1119286730302955651,
|
||||
"L_Wide": 1119286763802857533,
|
||||
"O_Wide": 1119286787169329203,
|
||||
"T_Wide": 1119286804634406942,
|
||||
"CBorderBLeft": 1119286973572595712,
|
||||
"CBorderBRight": 1119286918459445408,
|
||||
"CBorderTLeft": 1119287006464331806,
|
||||
"CBorderTRight": 1119286865284051035,
|
||||
"HBorderB": 1119286936155213835,
|
||||
"HBorderT": 1119287027662344322,
|
||||
"VBorder": 1119286889854279680,
|
||||
"WSmall": 1119288536282173490,
|
||||
"ISmall": 1119288552673517608,
|
||||
"NSmall": 1119288579382857830,
|
||||
"LCentered": 1119287296127156325,
|
||||
"OCentered": 1119287563245584394,
|
||||
"SCentered": 1119287327588634647,
|
||||
"ECentered": 1119287343833165945,
|
||||
"Blank": 1119287267001905283,
|
||||
"lost": 1119288454212243607
|
||||
},
|
||||
"reward_multipliers": {
|
||||
"pair": 1,
|
||||
"three_of_a_kind": 3,
|
||||
"three_diamonds": 4,
|
||||
"jackpot": 5
|
||||
}
|
||||
},
|
||||
"duel": {
|
||||
"combat_messages": [
|
||||
"{} unleashes a devastating tickle attack on {}, leaving them laughing uncontrollably and unable to fight back.",
|
||||
"{} defeats {} with a cunning move called 'The Poultry Surprise,' involving a rubber chicken and a confetti cannon.",
|
||||
"With a perfectly timed banana peel maneuver, {} sends {} slipping and sliding out of the arena, much to everyone's amusement.",
|
||||
"{} pulls off an impressive dance-off against {}, leaving them stunned and distracted long enough to claim victory.",
|
||||
"{} defeats {} by telling them an incredibly cheesy joke, causing them to burst into laughter and surrender.",
|
||||
"In a bizarre turn of events, {} manages to defeat {} by challenging them to a thumb wrestling match, and coming out on top.",
|
||||
"{} defeats {} using a comically oversized foam finger, dramatically poking them into submission.",
|
||||
"{} wins the fight against {} by offering them a plate of freshly baked cookies, distracting them with deliciousness.",
|
||||
"With a cunning strategy involving whoopee cushions and fake snakes, {} manages to startle {} into submission.",
|
||||
"{} defeats {} by challenging them to a game of rock-paper-scissors and successfully predicting their every move.",
|
||||
"In an unexpected twist, {} defeats {} by challenging them to a dance battle, showing off some surprisingly smooth moves.",
|
||||
"{} emerges victorious by launching a barrage of rubber duckies at {}, overwhelming them with adorable and distracting quacks.",
|
||||
"With a well-timed 'knock-knock' joke, {} manages to catch {} off guard, leaving them vulnerable and defeated.",
|
||||
"{} defeats {} by using an inflatable sumo suit, bouncing them right out of the arena in a hilarious spectacle.",
|
||||
"In a truly peculiar turn of events, {} defeats {} by engaging them in an intense thumb war and emerging as the undisputed champion.",
|
||||
"{} wins the fight against {} by tickling them mercilessly, reducing them to a fit of giggles and surrender.",
|
||||
"With a strategically placed whoopee cushion, {} manages to surprise and defeat {} in the most hilarious way possible.",
|
||||
"{} defeats {} by unleashing a swarm of rubber chickens, causing chaos and uncontrollable laughter in the arena.",
|
||||
"In a battle of wits, {} manages to outwit {} by challenging them to a game of 'Rock, Paper, Scissors, Lizard, Spock' and claiming victory.",
|
||||
"{} emerges victorious against {} by skillfully executing the legendary 'Chicken Dance of Doom,' rendering their opponent speechless.",
|
||||
"{} defeats {} by employing an unexpected strategy involving a squirting flower, leaving their opponent bewildered and soaked.",
|
||||
"With a masterful display of slapstick comedy, {} manages to trip up {} and claim a hilarious victory.",
|
||||
"{} wins the fight against {} by cunningly distracting them with an impromptu magic trick, leaving them spellbound and defeated.",
|
||||
"In an epic showdown, {} defeats {} by challenging them to a contest of dad jokes, causing their opponent to surrender out of sheer comedic defeat.",
|
||||
"{} emerges as the victor by engaging {} in a fierce battle of puns, leaving their opponent groaning and conceding defeat.",
|
||||
"{} defeats {} with a perfectly timed 'banana peel slip' maneuver, turning the fight into a sidesplitting comedy act.",
|
||||
"With an arsenal of whoopee cushions and squirting flowers, {} manages to defeat {} in a battle that can only be described as 'clownish'.",
|
||||
"{} claims a comical victory against {} by using a rubber chicken as a formidable weapon, leaving their opponent in stitches.",
|
||||
"In a hilarious turn of events, {} defeats {} by engaging them in a fierce tickle fight, reducing their opponent to fits of laughter and surrender.",
|
||||
"{} emerges triumphant by employing an unexpected weapon—silly string—to disarm and defeat {} in a messy but amusing battle.",
|
||||
"{} obliterates {} with a deadly barrage of pillow fluff, demonstrating the true power of softness.",
|
||||
"{} achieves victory by strategically deploying an army of rubber ducks, overwhelming {} with cuteness.",
|
||||
"In a stunning turn of events, {} wins the fight against {} by convincing them that the floor is lava.",
|
||||
"{} emerges victorious after an intense dance-off, proving that their killer moves are not to be underestimated.",
|
||||
"With a swift and devastating attack of dad jokes, {} renders {} defenseless with laughter and takes the win.",
|
||||
"{} successfully hypnotizes {} with their mesmerizing disco dance moves, leaving their opponent dazed and confused.",
|
||||
"In a battle of wits, {} defeats {} by challenging them to a game of 'Guess the Number' and revealing the meaning of life as the answer.",
|
||||
"{} outsmarts {} by unleashing an army of mischievous squirrels, distracting their opponent and securing an unconventional victory.",
|
||||
"With an expertly executed paper airplane assault, {} effortlessly subdues {} and claims the title of Paper Airplane Champion.",
|
||||
"{} triumphs over {} by unleashing a barrage of terrible puns, effectively disarming their opponent's will to fight.",
|
||||
"In a display of sheer absurdity, {} emerges victorious by defeating {} with an inflatable rubber chicken as their weapon of choice.",
|
||||
"{} wins the fight against {} by summoning an army of invisible ninjas, leaving their opponent bewildered and defeated.",
|
||||
"With a well-timed prank involving a whoopee cushion, {} takes the fight out of {} and secures an uproarious victory.",
|
||||
"{} utilizes the power of bad breath to defeat {} in a battle of close-quarters combat, leaving their opponent gasping for fresh air.",
|
||||
"{} emerges triumphant by utilizing the ancient technique of tickling, reducing {} to a giggling mess and claiming the win.",
|
||||
"In an astonishing display of ridiculousness, {} defeats {} by transforming into a human burrito, effectively immobilizing their opponent.",
|
||||
"{} takes the fight to a whole new level by challenging {} to a game of 'Rock, Paper, Scissors, Lizard, Spock, Dynamite,' and detonating their way to victory.",
|
||||
"By harnessing the uncontrollable forces of chaos and mayhem, {} emerges as the reigning champion, leaving {} wondering what just happened.",
|
||||
"{} obliterates {} with the fearsome weapon of 'Sarcasm Strike,' cutting their opponent down with devastatingly witty remarks.",
|
||||
"In a battle that defies all logic, {} manages to defeat {} with a strategically timed 'facepalm' attack, leaving their opponent bewildered and defeated.",
|
||||
"{} emerges victorious by channeling the power of sheer silliness, leaving {} wondering if they accidentally stepped into a clown convention.",
|
||||
"With a triumphant mic drop and a sly grin, {} outshines {} in a battle of one-liners, proving that words can be as deadly as fists.",
|
||||
"{} claims victory over {} by using an unexpected weapon—a rubber chicken armed with laser eyes—which proved too much for their opponent to handle.",
|
||||
"In an act of pure audacity, {} defeats {} by unleashing an unstoppable barrage of dad jokes, leaving their opponent both defeated and embarrassed.",
|
||||
"{} emerges triumphant by launching a relentless assault of puns, leaving {} defenseless against the power of linguistic wit.",
|
||||
"{} achieves a comical victory over {} by outmaneuvering them with a surprising breakdance routine, leaving their opponent in awe and confusion.",
|
||||
"By transforming the battlefield into a whimsical playground, {} manages to disarm and defeat {} with a joyful and mischievous spirit.",
|
||||
"{} emerges as the victor by invoking the ancient art of slapstick comedy, reducing {} to uncontrollable fits of laughter and surrender.",
|
||||
"{} triumphs over {} by launching a surprise attack with a barrage of rubber chickens.",
|
||||
"{} defeats {} using the power of interpretive dance, leaving their opponent bewildered and slightly confused.",
|
||||
"With a single eyebrow raise, {} disarms and defeats {} in a battle of snarky one-liners.",
|
||||
"{} emerges victorious by unleashing an army of ferocious kittens armed with laser pointers against {}.",
|
||||
"In an epic display of butter-fingered combat skills, {} accidentally defeats {} with an unexpected banana peel slip.",
|
||||
"By engaging {} in a heated debate about the best flavor of ice cream, {} successfully distracts their opponent and secures the win.",
|
||||
"{} claims victory over {} through the ingenious tactic of challenging them to a thumb war and emerging as the thumb wrestling champion.",
|
||||
"With a well-timed 'YOLO' battle cry, {} surprises and defeats {} in the most unconventional manner possible.",
|
||||
"{} outwits {} by reciting an endless stream of cheesy pickup lines, leaving their opponent both amused and defeated.",
|
||||
"By executing a perfectly synchronized dance routine, {} dazzles and confuses {} into submission.",
|
||||
"{} secures a hilarious win against {} by challenging them to a game of 'Rock, Paper, Scissors, Lizard, Spock' and emerging as the undisputed champion.",
|
||||
"With a crafty move straight out of a Looney Tunes cartoon, {} outmaneuvers and outwits {} to claim victory.",
|
||||
"By releasing a swarm of mischievous squirrels armed with water balloons, {} leaves {} soaked and defeated in the most hilarious way possible.",
|
||||
"{} emerges triumphant by employing the ancient martial art of 'Tickle Fu,' rendering {} defenseless with uncontrollable laughter.",
|
||||
"{} defeats {} using the power of bad breath and a strategically timed exhale, leaving their opponent breathless and defeated.",
|
||||
"With a well-timed 'dad joke' assault, {} leaves {} rolling their eyes and unable to recover from the hilarity.",
|
||||
"{} claims victory over {} by unleashing a pack of mischievous clowns armed with whoopee cushions and squirting flowers.",
|
||||
"By strategically summoning a swarm of angry bees, {} overwhelms and defeats {} in a buzzing spectacle.",
|
||||
"In an unexpected twist, {} defeats {} by challenging them to a game of 'Rock, Paper, Scissors' and emerging as the reigning champion.",
|
||||
"With the power of their outrageous fashion sense, {} distracts and confuses {} into defeat.",
|
||||
"{} emerges victorious by reciting an incredibly long and nonsensical tongue twister, leaving {} tongue-tied and defeated.",
|
||||
"By engaging in a heated dance battle, {} grooves their way to victory, leaving {} in awe of their dance-floor prowess.",
|
||||
"{} claims victory over {} by employing the ancient art of 'Sarcastic-Fu,' leaving their opponent at a loss for words.",
|
||||
"With a perfectly timed 'facepalm' maneuver, {} disorients and defeats {} in the most hilarious fashion possible.",
|
||||
"{} emerges triumphant by engaging {} in an intense game of 'Rock, Paper, Scissors, Lizard, Spock,' with the universe on the line.",
|
||||
"By transforming into a human tornado of chaos and confusion, {} overwhelms and defeats {} in a whirlwind of hilarity.",
|
||||
"{} secures a hilarious win over {} by challenging them to a game of 'Tic-Tac-Toe' and emerging as the ultimate champion.",
|
||||
"With a cleverly executed 'boop' to the nose, {} renders {} momentarily stunned and unable to continue the fight.",
|
||||
"{} claims victory over {} by unleashing their secret weapon: an unstoppable army of dancing flamingos.",
|
||||
"By reciting a never-ending series of puns, {} leaves {} in stitches and secures a comedic victory.",
|
||||
"{} emerges triumphant by unleashing an army of overly affectionate puppies, distracting and defeating {} with cuteness overload.",
|
||||
"With the power of an awkward silence, {} disarms and defeats {} in a battle of uncomfortable social encounters.",
|
||||
"{} claims victory over {} by summoning a torrential downpour of confetti, leaving their opponent both bewildered and sparkly.",
|
||||
"By unleashing a relentless barrage of 'Yo Mama' jokes, {} overwhelms and defeats {} in a duel of comedic insults.",
|
||||
"{} secures a hilarious win over {} by challenging them to a 'dance-off' and showcasing an unimaginable array of bizarre dance moves.",
|
||||
"With the cunning strategy of 'reverse psychology,' {} convinces {} to defeat themselves, leaving them utterly perplexed and defeated.",
|
||||
"{} emerges victorious by summoning a legion of clumsy penguins, who inadvertently trip up {} and secure the win in the most amusing fashion.",
|
||||
"By harnessing the power of awkwardly timed laughter, {} confuses and defeats {} in a battle that can only be described as 'laugh-out-loud' funny.",
|
||||
"{} claims victory over {} by employing an army of mischievous squirrels armed with acorns, leaving their opponent both annoyed and defeated.",
|
||||
"With the precision of a somersaulting unicorn, {} outmaneuvers and defeats {} in a display of mythical combat prowess.",
|
||||
"{} secures a hilarious win over {} by engaging them in an epic dance-off and showcasing a series of wildly questionable dance moves.",
|
||||
"By unleashing a squad of highly trained rubber ducks, {} leaves {} splashing in defeat and quacking with laughter.",
|
||||
"{} emerges triumphant by employing the power of 'awkward silence,' rendering {} unable to continue the fight due to extreme discomfort.",
|
||||
"With a well-timed 'mic drop' moment, {} leaves {} speechless and defeated in a battle of epic comebacks.",
|
||||
"{} claims victory over {} by skillfully executing a perfectly timed 'knock-knock' joke, leaving their opponent both entertained and defeated.",
|
||||
"By employing an army of ticklish feathers, {} reduces {} to helpless laughter and claims a comical victory.",
|
||||
"With a brilliantly executed 'banana slip' maneuver, {} sends {} tumbling into defeat in the most slapstick way possible.",
|
||||
"{} secures a hilarious win over {} by engaging them in a rap battle and delivering an unexpected, mind-blowing performance.",
|
||||
"By summoning a cloud of uncontrollable giggles, {} overwhelms and defeats {} in a battle of infectious laughter.",
|
||||
"{} emerges triumphant by deploying a squad of ninja squirrels armed with whoopee cushions, leaving {} both startled and defeated.",
|
||||
"With the power of their unstoppable dance moves, {} outshines and defeats {} in a battle of toe-tapping proportions.",
|
||||
"{} claims victory over {} by utilizing the art of 'face-swap,' rendering their opponent disoriented and hilariously confused.",
|
||||
"By launching an arsenal of marshmallows and pillow feathers, {} successfully overwhelms and defeats {} in a fluffy spectacle of victory.",
|
||||
"{} secures a hilarious win over {} by challenging them to a battle of 'Dad Jokes' and delivering the ultimate punchline.",
|
||||
"With the stealth of a tiptoeing hippo, {} sneaks up on {} and claims a surprise victory in the most unexpected manner.",
|
||||
"By summoning a stampede of clumsy llamas, {} causes chaos and laughter, ultimately defeating {} in a riotous spectacle.",
|
||||
"{} obliterates {} with the power of a thousand bad hair days, leaving their opponent in a state of follicular defeat.",
|
||||
"By utilizing the ancient technique of 'tickle-fu,' {} reduces {} to a giggling mess and claims a hilarious victory.",
|
||||
"{} emerges victorious by channeling the energy of a hyperactive squirrel, outmaneuvering and confusing {} at every turn.",
|
||||
"With the precision of a ninja clown, {} delivers a flurry of hilarious pranks, leaving {} both entertained and defeated.",
|
||||
"{} claims victory over {} by unleashing a barrage of terrible puns, rendering their opponent unable to continue due to excessive eye-rolling.",
|
||||
"By summoning a legion of malfunctioning whoopee cushions, {} turns the battle into a symphony of laughter and defeats {} with comedic flair.",
|
||||
"{} secures a humorous win over {} by challenging them to a 'dad joke' showdown and delivering the ultimate punchline that leaves their opponent groaning.",
|
||||
"With the grace of a clumsy flamingo, {} stumbles upon victory, leaving {} bewildered and wondering how they managed to lose.",
|
||||
"{} emerges triumphant by using the power of 'awkward small talk,' leaving {} cringing and defeated in a battle of uncomfortable conversations.",
|
||||
"By deploying a squad of mischievous rubber chickens, {} creates a cacophony of laughter and distractions, securing a comical victory over {}.",
|
||||
"{} claims victory over {} by transforming into a human whoopee cushion, causing uncontrollable laughter and sealing their triumph in a most absurd manner.",
|
||||
"With the impeccable timing of a comedic genius, {} delivers a devastating one-liner that leaves {} in stitches and clinches the win with style.",
|
||||
"{} secures a comical win over {} by using their unparalleled expertise in interpretive dance, leaving their opponent bewildered and tapping out in laughter.",
|
||||
"By unleashing a swarm of ticklish kittens, {} reduces {} to a state of uncontrollable laughter and claims a hilarious victory in the most adorable fashion.",
|
||||
"With the strategic deployment of banana peels, whoopee cushions, and a giant foam finger, {} orchestrates a slapstick symphony that leaves {} defeated and the audience in stitches.",
|
||||
"{} emerges triumphant by harnessing the power of 'dad jokes' to induce groans and eye-rolls in {}, ultimately causing their opponent's defeat through sheer cringeworthiness.",
|
||||
"By employing an arsenal of whoopee cushions, squirting flowers, and oversized novelty glasses, {} overwhelms {} with a spectacle of slapstick comedy, securing an uproarious victory.",
|
||||
"{} claims victory over {} by transforming into the ultimate embodiment of awkwardness, rendering their opponent speechless and awkwardly defeated in a battle of uncomfortable social encounters.",
|
||||
"With the stealth and finesse of a comedic ninja, {} uses pranks and puns to outwit and outmaneuver {}, leaving their opponent laughing too hard to continue the fight.",
|
||||
"{} secures a hilarious win over {} by challenging them to a 'dance-off' and showcasing a repertoire of comically bizarre dance moves that leave their opponent in fits of laughter.",
|
||||
"By wielding the power of sarcasm and witty comebacks, {} verbally outduels and defeats {}, leaving their opponent dumbfounded and unable to match their comedic prowess.",
|
||||
"{} emerges triumphant by unleashing a barrage of 'knock-knock' jokes that reduce {} to a state of uncontrollable laughter, ultimately securing a whimsically victorious outcome.",
|
||||
"With the cunning strategy of 'reverse psychology' and a well-timed comedic twist, {} convinces {} to defeat themselves, leaving their opponent both baffled and ironically defeated."
|
||||
]
|
||||
}
|
||||
}
|
48
main.py
Normal file
48
main.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
""" .ENV TEMPLATE
|
||||
TOKEN=
|
||||
OWNER_ID=
|
||||
XP_GAIN=
|
||||
COOLDOWN=
|
||||
CASH_BALANCE_NAME=
|
||||
SPECIAL_BALANCE_NAME=
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from dotenv import load_dotenv
|
||||
|
||||
import db.tables
|
||||
import sb_tools.resources
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
load_dotenv('.env')
|
||||
|
||||
sbbot = discord.Bot(
|
||||
owner_id=os.getenv('OWNER_ID'),
|
||||
intents=discord.Intents.all(),
|
||||
activity=discord.Game(f"v{sb_tools.resources.__version__}"),
|
||||
status=discord.Status.do_not_disturb
|
||||
)
|
||||
|
||||
|
||||
@sbbot.event
|
||||
async def on_ready():
|
||||
# wait until the bot is ready
|
||||
# then sync the sqlite3 database
|
||||
db.tables.sync_database()
|
||||
|
||||
"""
|
||||
https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready
|
||||
This function isn't guaranteed to only be called once.
|
||||
Event is called when RESUME request fails.
|
||||
"""
|
||||
|
||||
|
||||
for filename in os.listdir('./modules'):
|
||||
if filename.endswith('.py'):
|
||||
sbbot.load_extension(f'modules.{filename[:-3]}')
|
||||
|
||||
sbbot.run(os.getenv('TOKEN'))
|
389
modules/basic.py
Normal file
389
modules/basic.py
Normal file
|
@ -0,0 +1,389 @@
|
|||
import asyncio
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
from sb_tools import interaction, embeds, universal
|
||||
|
||||
|
||||
class Basic(commands.Cog):
|
||||
def __init__(self, sbbot):
|
||||
self.bot = sbbot
|
||||
|
||||
@commands.slash_command(
|
||||
name="ping",
|
||||
description="Show the bot's latency."
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
async def ping(self, ctx):
|
||||
await ctx.respond(f"SB latency: {round(self.bot.latency * 1000, 2)} ms")
|
||||
|
||||
@commands.slash_command(
|
||||
name="intro",
|
||||
guild_only=False,
|
||||
description="This command can only be done in DMs."
|
||||
)
|
||||
@commands.dm_only()
|
||||
async def intro(self, ctx):
|
||||
guild_id = 719227135151046699
|
||||
channel_id = 973619250507972618
|
||||
muted_role_id = 754895743151505489
|
||||
|
||||
nickname = None
|
||||
age = None
|
||||
location = None
|
||||
pronouns = None
|
||||
likes = None
|
||||
dislikes = None
|
||||
languages = None
|
||||
sexuality = None
|
||||
relationship_status = None
|
||||
extra = None
|
||||
|
||||
guild = self.bot.get_guild(guild_id)
|
||||
member = await guild.fetch_member(ctx.author.id)
|
||||
if member and discord.utils.get(member.roles, id=muted_role_id):
|
||||
em = discord.Embed(description="You're muted in the Rave Cave. You can't perform this command.",
|
||||
color=0xadcca6)
|
||||
await ctx.respond(embed=em)
|
||||
return
|
||||
|
||||
elif member and not discord.utils.get(member.roles, id=719995790319157279):
|
||||
em = discord.Embed(description="It seems that you don't have permission to do that!")
|
||||
await ctx.respond(embed=em)
|
||||
return
|
||||
|
||||
embed = discord.Embed(color=0xadcca6,
|
||||
title=f"Hey {ctx.author.name}!",
|
||||
description=f"This command will serve as a questionnaire "
|
||||
f"for your entry to <#{channel_id}>. Please keep your answers \"PG-13.\"")
|
||||
|
||||
embed.add_field(name="Short intro", value="Click the blue button to use the short form, this one has "
|
||||
"__6 questions__, which is filled out promptly & contains the "
|
||||
"most important elements needed to briefly describe you.")
|
||||
|
||||
embed.add_field(name="Extended intro", value="Click the green button to fill out an extended form with "
|
||||
"__10 questions__ (including an \"extras\" field where you "
|
||||
"can unleash your creativity), this one takes a bit longer "
|
||||
"to fill out but gives a more detailed portrayal of you.")
|
||||
|
||||
embed.set_footer(text="Please don't abuse this command.")
|
||||
embed.set_thumbnail(url="https://cdn.discordapp.com/icons/719227135151046699/49df8c284382af9dbcfd629c8eadc52c"
|
||||
".webp?size=96")
|
||||
|
||||
view = interaction.IntroButtons(ctx)
|
||||
await ctx.respond(embed=embed, view=view)
|
||||
await view.wait()
|
||||
|
||||
def check(message):
|
||||
return message.author == ctx.author and isinstance(message.channel, discord.DMChannel)
|
||||
|
||||
if view.clickedShort:
|
||||
|
||||
# START NICKNAME
|
||||
await ctx.send(embed=embeds.simple_question_first("How would you like to be identified in the server?"))
|
||||
|
||||
try:
|
||||
nickname_message = await self.bot.wait_for('message', check=check, timeout=120)
|
||||
nickname = nickname_message.content
|
||||
if len(nickname) > 100:
|
||||
nickname = nickname[:100]
|
||||
nickname = nickname.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: nickname {nickname}")
|
||||
|
||||
# START AGE
|
||||
await ctx.send(embed=embeds.simple_question_5("How old are you?"),
|
||||
content=f"Recorded answer: {nickname}")
|
||||
|
||||
try:
|
||||
age_message = await self.bot.wait_for('message', check=check, timeout=120)
|
||||
age = age_message.content
|
||||
if len(age) > 5:
|
||||
age = age[:5]
|
||||
age = age.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: age {age}")
|
||||
|
||||
# START LOCATION
|
||||
view = interaction.LocationOptions(ctx)
|
||||
await ctx.send(embed=embeds.simple_question_none("Where do you live?"),
|
||||
view=view,
|
||||
content=f"Recorded answer: {age}")
|
||||
|
||||
await view.wait()
|
||||
location = view.location
|
||||
print(f"New form info for {ctx.author.name}: location {location}")
|
||||
|
||||
if not view.location:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
# START PRONOUNS
|
||||
await ctx.send(
|
||||
embed=embeds.simple_question_30("What are your preferred pronouns?"),
|
||||
content=f"Recorded answer: {location}")
|
||||
|
||||
try:
|
||||
pronouns_message = await self.bot.wait_for('message', check=check, timeout=120)
|
||||
pronouns = pronouns_message.content
|
||||
if len(pronouns) > 30:
|
||||
pronouns = pronouns[:30]
|
||||
pronouns = pronouns.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: pronouns {pronouns}")
|
||||
|
||||
# START LIKES
|
||||
await ctx.send(embed=embeds.simple_question_300("Likes & interests"),
|
||||
content=f"Recorded answer: {pronouns}")
|
||||
|
||||
try:
|
||||
likes_message = await self.bot.wait_for('message', check=check, timeout=300)
|
||||
likes = likes_message.content
|
||||
if len(likes) > 300:
|
||||
likes = likes[:300]
|
||||
likes = likes.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: likes {likes}")
|
||||
|
||||
# START DISLIKES
|
||||
await ctx.send(embed=embeds.simple_question_300("Dislikes"),
|
||||
content=f"Recorded answer: {likes}")
|
||||
|
||||
try:
|
||||
dislikes_message = await self.bot.wait_for('message', check=check, timeout=300)
|
||||
dislikes = dislikes_message.content
|
||||
if len(dislikes) > 300:
|
||||
dislikes = dislikes[:300]
|
||||
dislikes = dislikes.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: dislikes {dislikes}")
|
||||
|
||||
# POST EXAMPLE EMBED AND FINAL IF APPROVED
|
||||
em = embeds.final_embed_short(ctx, nickname, age, location, pronouns, likes, dislikes)
|
||||
|
||||
view = interaction.Confirm(ctx)
|
||||
await ctx.send(embed=em, content=f"Introduction of <@{ctx.author.id}>", view=view)
|
||||
await view.wait()
|
||||
|
||||
if view.clickedConfirm:
|
||||
intro_channel = guild.get_channel(channel_id)
|
||||
await intro_channel.send(embed=em, content=f"Introduction of <@{ctx.author.id}>")
|
||||
await ctx.send(embed=embeds.final_confirmation(channel_id))
|
||||
return
|
||||
else:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
elif view.clickedLong:
|
||||
# START NICKNAME
|
||||
await ctx.send(embed=embeds.simple_question_first_extended(
|
||||
"How would you like to be identified in the server?"))
|
||||
|
||||
try:
|
||||
nickname_message = await self.bot.wait_for('message', check=check, timeout=120)
|
||||
nickname = nickname_message.content
|
||||
if len(nickname) > 100:
|
||||
nickname = nickname[:100]
|
||||
nickname = nickname.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: nickname {nickname}")
|
||||
|
||||
# START AGE
|
||||
await ctx.send(embed=embeds.simple_question_5("How old are you?"),
|
||||
content=f"Recorded answer: {nickname}")
|
||||
|
||||
try:
|
||||
age_message = await self.bot.wait_for('message', check=check, timeout=120)
|
||||
age = age_message.content
|
||||
if len(age) > 5:
|
||||
age = age[:5]
|
||||
age = age.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: age {age}")
|
||||
|
||||
# START LOCATION
|
||||
view = interaction.LocationOptions(ctx)
|
||||
await ctx.send(embed=embeds.simple_question_none("Where do you live?"),
|
||||
view=view,
|
||||
content=f"Recorded answer: {age}")
|
||||
|
||||
await view.wait()
|
||||
location = view.location
|
||||
print(f"New form info for {ctx.author.name}: location {location}")
|
||||
|
||||
if not view.location:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
# START LANGUAGES
|
||||
await ctx.send(
|
||||
embed=embeds.simple_question_100("Which languages do you speak?"),
|
||||
content=f"Recorded answer: {location}"
|
||||
)
|
||||
|
||||
try:
|
||||
languages_message = await self.bot.wait_for('message', check=check, timeout=200)
|
||||
languages = languages_message.content
|
||||
if len(languages) > 30:
|
||||
languages = languages[:30]
|
||||
languages = languages.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: languages {languages}")
|
||||
|
||||
# START PRONOUNS
|
||||
await ctx.send(
|
||||
embed=embeds.simple_question_30("What are your preferred pronouns?"),
|
||||
content=f"Recorded answer: {languages}")
|
||||
|
||||
try:
|
||||
pronouns_message = await self.bot.wait_for('message', check=check, timeout=120)
|
||||
pronouns = pronouns_message.content
|
||||
if len(pronouns) > 30:
|
||||
pronouns = pronouns[:30]
|
||||
pronouns = pronouns.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: pronouns {pronouns}")
|
||||
|
||||
# START SEXUALITY
|
||||
await ctx.send(
|
||||
embed=embeds.simple_question_30("What's your sexuality?"),
|
||||
content=f"Recorded answer: {pronouns}")
|
||||
|
||||
try:
|
||||
sexuality_message = await self.bot.wait_for('message', check=check, timeout=120)
|
||||
sexuality = sexuality_message.content
|
||||
if len(sexuality) > 30:
|
||||
sexuality = sexuality[:30]
|
||||
sexuality = sexuality.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: sexuality {sexuality}")
|
||||
|
||||
# START RELATIONSHIP_STATUS
|
||||
await ctx.send(
|
||||
embed=embeds.simple_question_30("What's your current relationship status?"),
|
||||
content=f"Recorded answer: {sexuality}")
|
||||
|
||||
try:
|
||||
relationship_status_message = await self.bot.wait_for('message', check=check,
|
||||
timeout=120)
|
||||
relationship_status = relationship_status_message.content
|
||||
if len(relationship_status) > 30:
|
||||
relationship_status = relationship_status[:30]
|
||||
relationship_status = relationship_status.replace("\n", " ")
|
||||
print(
|
||||
f"New form info for {ctx.author.name}: relationship_status {relationship_status}")
|
||||
|
||||
# START LIKES
|
||||
await ctx.send(embed=embeds.simple_question_300("Likes & interests"),
|
||||
content=f"Recorded answer: {relationship_status}")
|
||||
|
||||
try:
|
||||
likes_message = await self.bot.wait_for('message', check=check, timeout=300)
|
||||
likes = likes_message.content
|
||||
if len(likes) > 300:
|
||||
likes = likes[:300]
|
||||
likes = likes.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: likes {likes}")
|
||||
|
||||
# START DISLIKES
|
||||
await ctx.send(embed=embeds.simple_question_300("Dislikes"),
|
||||
content=f"Recorded answer: {likes}")
|
||||
|
||||
try:
|
||||
dislikes_message = await self.bot.wait_for('message', check=check,
|
||||
timeout=300)
|
||||
dislikes = dislikes_message.content
|
||||
if len(dislikes) > 300:
|
||||
dislikes = dislikes[:300]
|
||||
dislikes = dislikes.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: dislikes {dislikes}")
|
||||
|
||||
# START EXTRA
|
||||
await ctx.send(embed=embeds.simple_question_300(
|
||||
"EXTRAS: job status, zodiac sign, hobbies, etc. "
|
||||
"Tell us about yourself!"),
|
||||
content=f"Recorded answer: {dislikes}")
|
||||
|
||||
try:
|
||||
extra_message = await self.bot.wait_for('message', check=check,
|
||||
timeout=300)
|
||||
extra = extra_message.content
|
||||
if len(extra) > 300:
|
||||
extra = extra[:300]
|
||||
extra = extra.replace("\n", " ")
|
||||
print(f"New form info for {ctx.author.name}: extra {extra}")
|
||||
|
||||
# POST EXAMPLE EMBED AND FINAL IF APPROVED
|
||||
em = embeds.final_embed_extended(ctx, nickname, age, location,
|
||||
languages, pronouns, sexuality,
|
||||
relationship_status, likes,
|
||||
dislikes, extra)
|
||||
|
||||
view = interaction.Confirm(ctx)
|
||||
await ctx.send(embed=em, content=f"Introduction of <@{ctx.author.id}>",
|
||||
view=view)
|
||||
await view.wait()
|
||||
|
||||
if view.clickedConfirm:
|
||||
intro_channel = guild.get_channel(channel_id)
|
||||
await intro_channel.send(embed=em,
|
||||
content=f"Introduction of <@{ctx.author.id}>")
|
||||
await ctx.send(embed=embeds.final_confirmation(channel_id))
|
||||
return
|
||||
else:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
else:
|
||||
await ctx.send(embed=embeds.no_time())
|
||||
return
|
||||
|
||||
|
||||
def setup(sbbot):
|
||||
sbbot.add_cog(Basic(sbbot))
|
187
modules/economy.py
Normal file
187
modules/economy.py
Normal file
|
@ -0,0 +1,187 @@
|
|||
import json
|
||||
import os
|
||||
import time
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from data.Currency import Currency
|
||||
from data.Dailies import Dailies
|
||||
from sb_tools import economy_embeds, universal, interaction
|
||||
|
||||
load_dotenv('.env')
|
||||
|
||||
active_blackjack_games = {}
|
||||
special_balance_name = os.getenv("SPECIAL_BALANCE_NAME")
|
||||
cash_balance_name = os.getenv("CASH_BALANCE_NAME")
|
||||
|
||||
with open("json/economy.json") as file:
|
||||
json_data = json.load(file)
|
||||
|
||||
|
||||
class Economy(commands.Cog):
|
||||
def __init__(self, sbbot):
|
||||
self.bot = sbbot
|
||||
|
||||
@commands.slash_command(
|
||||
name="balance",
|
||||
description="See how much cash you have.",
|
||||
guild_only=True
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
async def balance(self, ctx):
|
||||
cash_balance = Currency.get_cash_balance(ctx.author.id)
|
||||
special_balance = Currency.get_special_balance(ctx.author.id)
|
||||
|
||||
await ctx.respond(embed=economy_embeds.currency_balance(ctx, cash_balance, special_balance))
|
||||
|
||||
@commands.slash_command(
|
||||
name="give",
|
||||
description="Give another user some currency.",
|
||||
guild_only=True
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
async def give(self, ctx, *,
|
||||
user: discord.Option(discord.Member),
|
||||
currency: discord.Option(choices=["cash", special_balance_name]),
|
||||
amount: discord.Option(int)):
|
||||
|
||||
if ctx.author.id == user.id:
|
||||
return await ctx.respond(embed=economy_embeds.give_yourself_error(currency))
|
||||
elif user.bot:
|
||||
return await ctx.respond(embed=economy_embeds.give_bot_error(currency))
|
||||
|
||||
try:
|
||||
if currency == "cash":
|
||||
author_cash_balance = Currency.get_cash_balance(ctx.author.id)
|
||||
|
||||
if author_cash_balance < amount or author_cash_balance <= 0:
|
||||
return await ctx.respond(embed=economy_embeds.not_enough_cash())
|
||||
|
||||
target_cash_balance = Currency.get_cash_balance(user.id)
|
||||
|
||||
target_new_cash_balance = target_cash_balance + amount
|
||||
author_new_cash_balance = author_cash_balance - amount
|
||||
|
||||
Currency.update_cash_balance(user.id, target_new_cash_balance)
|
||||
Currency.update_cash_balance(ctx.author.id, author_new_cash_balance)
|
||||
|
||||
elif currency == special_balance_name:
|
||||
author_special_balance = Currency.get_special_balance(ctx.author.id)
|
||||
|
||||
if author_special_balance < amount or author_special_balance <= 0:
|
||||
return await ctx.respond(embed=economy_embeds.not_enough_special_balance())
|
||||
|
||||
target_special_balance = Currency.get_special_balance(user.id)
|
||||
|
||||
target_new_special_balance = target_special_balance + amount
|
||||
author_new_special_balance = author_special_balance - amount
|
||||
|
||||
Currency.update_special_balance(user.id, target_new_special_balance)
|
||||
Currency.update_special_balance(ctx.author.id, author_new_special_balance)
|
||||
|
||||
except Exception as e:
|
||||
await ctx.channel.respond("Something funky happened.. Tell Tess.", ephemeral=True)
|
||||
print(e)
|
||||
return
|
||||
|
||||
await ctx.respond(embed=economy_embeds.give(ctx, user, currency, amount))
|
||||
|
||||
@commands.slash_command(
|
||||
name="exchange",
|
||||
description=f"Exchange {special_balance_name} for cash.",
|
||||
guild_only=True
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
async def exchange(self, ctx, *, amount: discord.Option(int)):
|
||||
author_special_balance = Currency.get_special_balance(ctx.author.id)
|
||||
|
||||
if author_special_balance < amount or author_special_balance <= 0:
|
||||
return await ctx.respond(embed=economy_embeds.not_enough_special_balance())
|
||||
|
||||
view = interaction.ExchangeConfirmation(ctx)
|
||||
await ctx.respond(embed=economy_embeds.exchange_confirmation(amount), view=view)
|
||||
await view.wait()
|
||||
|
||||
if view.clickedConfirm:
|
||||
author_new_special_balance = author_special_balance - amount
|
||||
author_new_cash_balance = Currency.get_cash_balance(ctx.author.id) + (amount * 1000)
|
||||
|
||||
Currency.update_cash_balance(ctx.author.id, author_new_cash_balance)
|
||||
Currency.update_special_balance(ctx.author.id, author_new_special_balance)
|
||||
|
||||
return await ctx.edit(embed=economy_embeds.exchange_done(amount))
|
||||
|
||||
await ctx.edit(embed=economy_embeds.exchange_stopped())
|
||||
|
||||
@commands.slash_command(
|
||||
name="award",
|
||||
description="Award currency - owner only command.",
|
||||
guild_only=True
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
@commands.check(universal.owner_check)
|
||||
async def award(self, ctx, *,
|
||||
user: discord.Option(discord.Member),
|
||||
currency: discord.Option(choices=["cash_balance", "special_balance"]),
|
||||
amount: discord.Option(int)):
|
||||
|
||||
try:
|
||||
if currency == "cash_balance":
|
||||
current_cash_balance = Currency.get_cash_balance(user.id)
|
||||
new_cash_balance = int(current_cash_balance) + amount
|
||||
Currency.update_cash_balance(user.id, new_cash_balance)
|
||||
|
||||
else:
|
||||
current_special_balance = Currency.get_special_balance(user.id)
|
||||
new_special_balance = int(current_special_balance) + amount
|
||||
Currency.update_special_balance(user.id, new_special_balance)
|
||||
|
||||
except Exception as e:
|
||||
await ctx.channel.respond("Something went wrong. Check console.", ephemeral=True)
|
||||
print(e)
|
||||
return
|
||||
|
||||
await ctx.respond(embed=economy_embeds.award(user, currency, amount))
|
||||
|
||||
@commands.slash_command(
|
||||
name="daily",
|
||||
description="Claim your daily cash!",
|
||||
guild_only=True
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
async def daily(self, ctx):
|
||||
(can_claim, next_claim) = Dailies.cooldown_check(ctx.author.id)
|
||||
amount = json_data["daily_reward"]
|
||||
current_time = time.time()
|
||||
|
||||
if can_claim:
|
||||
await ctx.respond(embed=economy_embeds.daily_claim(amount))
|
||||
|
||||
# give money
|
||||
current_cash_balance = Currency.get_cash_balance(ctx.author.id)
|
||||
Currency.update_cash_balance(ctx.author.id, current_cash_balance + amount)
|
||||
|
||||
# push daily to DB
|
||||
daily = Dailies(
|
||||
user_id=ctx.author.id,
|
||||
claimed_at=current_time,
|
||||
next_available=current_time + json_data["daily_cooldown"]
|
||||
)
|
||||
daily.push()
|
||||
|
||||
else:
|
||||
cooldown = next_claim - current_time
|
||||
|
||||
hours = int(cooldown // 3600)
|
||||
minutes = int((cooldown % 3600) // 60)
|
||||
seconds = int(cooldown % 60)
|
||||
|
||||
cooldown_text = f"{str(hours).zfill(2)}:{str(minutes).zfill(2)}:{str(seconds).zfill(2)}"
|
||||
|
||||
await ctx.respond(embed=economy_embeds.daily_wait(cooldown_text))
|
||||
|
||||
|
||||
def setup(sbbot):
|
||||
sbbot.add_cog(Economy(sbbot))
|
290
modules/gambling.py
Normal file
290
modules/gambling.py
Normal file
|
@ -0,0 +1,290 @@
|
|||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from data.BlackJackStats import BlackJackStats
|
||||
from data.Currency import Currency
|
||||
from data.SlotsStats import SlotsStats
|
||||
from sb_tools import economy_embeds, economy_functions, universal, interaction, embeds
|
||||
|
||||
load_dotenv('.env')
|
||||
|
||||
active_blackjack_games = {}
|
||||
special_balance_name = os.getenv("SPECIAL_BALANCE_NAME")
|
||||
cash_balance_name = os.getenv("CASH_BALANCE_NAME")
|
||||
|
||||
with open("json/economy.json") as file:
|
||||
json_data = json.load(file)
|
||||
|
||||
|
||||
class Gambling(commands.Cog):
|
||||
def __init__(self, sbbot):
|
||||
self.bot = sbbot
|
||||
|
||||
# @commands.slash_command(
|
||||
# name="coinflip",
|
||||
# description="Flip a coin and bet on the outcome.",
|
||||
# guild_only=True
|
||||
# )
|
||||
# @commands.check(universal.channel_check)
|
||||
# @commands.check(universal.beta_check)
|
||||
# async def coinflip(self, ctx, *, side: discord.Option(choices=["heads", "tails"]), bet: discord.Option(int)):
|
||||
# player_cash_balance = Currency.get_cash_balance(ctx.author.id)
|
||||
# if bet > player_cash_balance:
|
||||
# await ctx.respond(embed=economy_embeds.not_enough_cash())
|
||||
# return
|
||||
#
|
||||
# side_list = ["heads", "tails"]
|
||||
# throw_side = random.choice(side_list)
|
||||
#
|
||||
# if throw_side is side:
|
||||
# await ctx.respond(embed=economy_embeds.coinflip())
|
||||
|
||||
@commands.slash_command(
|
||||
name="blackjack",
|
||||
description="Start a game of blackjack.",
|
||||
guild_only=True
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
async def blackjack(self, ctx, *, bet: discord.Option(int)):
|
||||
|
||||
# check if the player already has an active blackjack going
|
||||
if ctx.author.id in active_blackjack_games:
|
||||
await ctx.respond(embed=economy_embeds.already_playing("BlackJack"))
|
||||
return
|
||||
|
||||
# check if the user has enough cash
|
||||
player_cash_balance = Currency.get_cash_balance(ctx.author.id)
|
||||
if bet > player_cash_balance or bet <= 0:
|
||||
await ctx.respond(embed=economy_embeds.not_enough_cash())
|
||||
return
|
||||
|
||||
active_blackjack_games[ctx.author.id] = True
|
||||
|
||||
try:
|
||||
|
||||
player_hand = []
|
||||
dealer_hand = []
|
||||
deck = economy_functions.blackjack_get_new_deck()
|
||||
view = interaction.BlackJackButtons(ctx)
|
||||
|
||||
# deal initial cards (player draws two & dealer one)
|
||||
player_hand.append(economy_functions.blackjack_deal_card(deck))
|
||||
player_hand.append(economy_functions.blackjack_deal_card(deck))
|
||||
dealer_hand.append(economy_functions.blackjack_deal_card(deck))
|
||||
|
||||
# calculate initial hands
|
||||
player_hand_value = economy_functions.blackjack_calculate_hand_value(player_hand)
|
||||
dealer_hand_value = economy_functions.blackjack_calculate_hand_value(dealer_hand)
|
||||
|
||||
status = "game_start"
|
||||
|
||||
await ctx.respond(embed=economy_embeds.blackjack_show(ctx, bet, player_hand,
|
||||
dealer_hand, player_hand_value,
|
||||
dealer_hand_value, status=status), view=view,
|
||||
content=ctx.author.mention)
|
||||
|
||||
while status == "game_start":
|
||||
await view.wait()
|
||||
|
||||
if view.clickedHit:
|
||||
# player draws a card & value is calculated
|
||||
player_hand.append(economy_functions.blackjack_deal_card(deck))
|
||||
player_hand_value = economy_functions.blackjack_calculate_hand_value(player_hand)
|
||||
|
||||
if player_hand_value > 21:
|
||||
status = "player_busted"
|
||||
|
||||
elif view.clickedStand:
|
||||
# player stands, dealer draws cards until he wins OR busts
|
||||
while dealer_hand_value <= player_hand_value:
|
||||
dealer_hand.append(economy_functions.blackjack_deal_card(deck))
|
||||
dealer_hand_value = economy_functions.blackjack_calculate_hand_value(dealer_hand)
|
||||
|
||||
if dealer_hand_value > 21:
|
||||
status = "dealer_busted"
|
||||
else:
|
||||
status = "dealer_won"
|
||||
|
||||
else:
|
||||
status = "timed_out"
|
||||
break
|
||||
|
||||
# edit the embed, disable view if game is over.
|
||||
if status == "game_start":
|
||||
view = interaction.BlackJackButtons(ctx)
|
||||
else:
|
||||
view = None
|
||||
|
||||
await ctx.edit(embed=economy_embeds.blackjack_show(ctx, bet, player_hand,
|
||||
dealer_hand, player_hand_value,
|
||||
dealer_hand_value, status=status), view=view,
|
||||
content=ctx.author.mention)
|
||||
|
||||
# change balance
|
||||
if status == "player_busted" or status == "dealer_won":
|
||||
Currency.update_cash_balance(ctx.author.id, player_cash_balance - bet)
|
||||
|
||||
# push stats (low priority)
|
||||
stats = BlackJackStats(
|
||||
user_id=ctx.author.id,
|
||||
is_won=False,
|
||||
bet=bet,
|
||||
payout=0,
|
||||
hand_player=player_hand,
|
||||
hand_dealer=dealer_hand
|
||||
)
|
||||
stats.push_one()
|
||||
|
||||
elif status == "timed_out":
|
||||
await ctx.send(embed=economy_embeds.out_of_time(), content=ctx.author.mention)
|
||||
|
||||
else:
|
||||
# bet multiplier
|
||||
payout = bet * 1.2
|
||||
Currency.update_cash_balance(ctx.author.id, player_cash_balance + payout)
|
||||
|
||||
# push stats (low priority)
|
||||
stats = BlackJackStats(
|
||||
user_id=ctx.author.id,
|
||||
is_won=True,
|
||||
bet=bet,
|
||||
payout=payout,
|
||||
hand_player=player_hand,
|
||||
hand_dealer=dealer_hand
|
||||
)
|
||||
stats.push_one()
|
||||
|
||||
except Exception as e:
|
||||
await ctx.respond(embed=embeds.command_error_1())
|
||||
print("Something went wrong in the gambling command:\n", e)
|
||||
|
||||
finally:
|
||||
# remove player from active games list
|
||||
del active_blackjack_games[ctx.author.id]
|
||||
|
||||
@commands.slash_command(
|
||||
name="slots",
|
||||
descriptions="Spin the slots for a chance to win the jackpot!",
|
||||
guild_only=True
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
async def slots(self, ctx, *, bet: discord.Option(int)):
|
||||
|
||||
# check if the user has enough cash
|
||||
player_cash_balance = Currency.get_cash_balance(ctx.author.id)
|
||||
if bet > player_cash_balance or bet <= 0:
|
||||
await ctx.respond(embed=economy_embeds.not_enough_cash())
|
||||
return
|
||||
|
||||
# calculate the results before the command is shown
|
||||
results = [random.randint(0, 6) for i in range(3)]
|
||||
calculated_results = economy_functions.calculate_slots_results(bet, results)
|
||||
|
||||
type = calculated_results[0]
|
||||
payout = calculated_results[1]
|
||||
multiplier = calculated_results[2]
|
||||
is_won = True
|
||||
|
||||
if type == "lost":
|
||||
is_won = False
|
||||
|
||||
# start with default "spinning" embed
|
||||
await ctx.respond(embed=economy_embeds.slots_spinning(ctx, 3, bet, results, self.bot))
|
||||
await asyncio.sleep(1)
|
||||
await ctx.edit(embed=economy_embeds.slots_spinning(ctx, 2, bet, results, self.bot),
|
||||
allowed_mentions=discord.AllowedMentions.none())
|
||||
await asyncio.sleep(1)
|
||||
await ctx.edit(embed=economy_embeds.slots_spinning(ctx, 1, bet, results, self.bot),
|
||||
allowed_mentions=discord.AllowedMentions.none())
|
||||
await asyncio.sleep(1)
|
||||
await ctx.edit(embed=economy_embeds.slots_finished(ctx, type, multiplier, bet, results, self.bot),
|
||||
allowed_mentions=discord.AllowedMentions.none())
|
||||
|
||||
# user payout
|
||||
Currency.update_cash_balance(ctx.author.id, player_cash_balance + payout)
|
||||
|
||||
# push stats (low priority)
|
||||
if payout <= 0:
|
||||
payout = 0
|
||||
|
||||
stats = SlotsStats(
|
||||
user_id=ctx.author.id,
|
||||
is_won=is_won,
|
||||
bet=bet,
|
||||
payout=payout,
|
||||
spin_type=type,
|
||||
icons=results
|
||||
)
|
||||
|
||||
stats.push_one()
|
||||
|
||||
@commands.slash_command(
|
||||
name="duel",
|
||||
description="Challenge another player to a fight.",
|
||||
guild_only=True
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
async def duel(self, ctx, *, opponent: discord.Option(discord.Member), bet: discord.Option(int)):
|
||||
challenger = ctx.author
|
||||
|
||||
if challenger.id == opponent.id:
|
||||
return await ctx.respond(content="You cannot duel yourself.")
|
||||
elif opponent.bot:
|
||||
return await ctx.respond(content="You cannot duel a bot.")
|
||||
|
||||
# check if challenger has enough cash
|
||||
challenger_cash_balance = Currency.get_cash_balance(challenger.id)
|
||||
if bet > challenger_cash_balance or bet <= 0:
|
||||
return await ctx.respond(embed=economy_embeds.not_enough_cash())
|
||||
|
||||
# if opponent doesn't have sufficient money, the bet will become the opponent's cash
|
||||
opponent_cash_balance = Currency.get_cash_balance(opponent.id)
|
||||
all_in = ""
|
||||
if opponent_cash_balance <= 0:
|
||||
return await ctx.respond(f"Woops, you can't do that because **{opponent.name}** has no money.")
|
||||
elif bet > opponent_cash_balance:
|
||||
bet = opponent_cash_balance
|
||||
all_in = " | opponent's all-in"
|
||||
|
||||
# challenge message
|
||||
view = interaction.DuelChallenge(opponent)
|
||||
|
||||
await ctx.respond(
|
||||
content=f"**{challenger.name}** challenges {opponent.mention} to a duel ({cash_balance_name}{bet}{all_in})\n"
|
||||
f"Use the buttons to accept/deny (challenge expires after 60s)", view=view)
|
||||
await view.wait()
|
||||
|
||||
if view.clickedConfirm:
|
||||
winner = random.choice([challenger, opponent])
|
||||
loser = opponent if winner == challenger else challenger
|
||||
combat_message = random.choice(json_data["duel"]["combat_messages"]).format(f"**{winner.name}**",
|
||||
f"**{loser.name}**")
|
||||
|
||||
await ctx.respond(content=f"{combat_message}\n\n"
|
||||
f"{winner.mention} wins **{cash_balance_name}{bet}**\n"
|
||||
f"{loser.mention} loses this bet.")
|
||||
|
||||
# payouts
|
||||
if winner == challenger:
|
||||
Currency.update_cash_balance(challenger.id, challenger_cash_balance + bet)
|
||||
Currency.update_cash_balance(opponent.id, opponent_cash_balance - bet)
|
||||
|
||||
elif winner == opponent:
|
||||
Currency.update_cash_balance(opponent.id, opponent_cash_balance + bet)
|
||||
Currency.update_cash_balance(challenger.id, challenger_cash_balance - bet)
|
||||
|
||||
elif view.clickedDeny:
|
||||
await ctx.edit(content=f"**{opponent.name}** canceled the duel.")
|
||||
|
||||
else:
|
||||
await ctx.edit(content=f"Time ran out.")
|
||||
|
||||
|
||||
def setup(sbbot):
|
||||
sbbot.add_cog(Gambling(sbbot))
|
94
modules/leveling.py
Normal file
94
modules/leveling.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
import time
|
||||
|
||||
from discord.ext import commands
|
||||
|
||||
from data.Currency import Currency
|
||||
from data.Xp import Xp
|
||||
from sb_tools import embeds, universal, level_messages, reactions, xp_functions
|
||||
|
||||
|
||||
class Leveling(commands.Cog):
|
||||
def __init__(self, sbbot):
|
||||
self.bot = sbbot
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
if message.author.bot:
|
||||
return
|
||||
|
||||
await reactions.check_for_reaction(message)
|
||||
|
||||
user_id = message.author.id
|
||||
current_time = time.time()
|
||||
xp_data = Xp.get_user_xp_data(user_id)
|
||||
(current_xp, current_level, cooldown) = xp_data[0]
|
||||
|
||||
if cooldown and current_time < cooldown:
|
||||
print(f"XP UPDATE --- {message.author.name} sent a message but is on XP cooldown.")
|
||||
return
|
||||
|
||||
gain_data = Xp.load_gain_data()
|
||||
xp_gain = gain_data[0]
|
||||
cooldown = gain_data[1]
|
||||
|
||||
new_xp = current_xp + xp_gain
|
||||
needed_xp_for_next_level = xp_functions.xp_needed_for_next_level(current_level)
|
||||
|
||||
if new_xp >= needed_xp_for_next_level:
|
||||
# new level was reached
|
||||
new_level = current_level + 1
|
||||
new_xp = 0
|
||||
|
||||
Xp.update_user_xp(user_id, new_xp, new_level, current_time + cooldown)
|
||||
print(f"XP UPDATE --- {message.author.name} leveled up; new_level = {new_level}.")
|
||||
await message.channel.send(content=f"<@{user_id}> {level_messages.load_level_message(new_level)}")
|
||||
|
||||
# assign level role if necessary:
|
||||
if new_level in [5, 10, 15, 20, 25, 30, 35, 40, 45, 50]:
|
||||
await Xp.assign_level_role(message.author, new_level)
|
||||
|
||||
# award a special_balance_currency
|
||||
amount = 1
|
||||
current_special_balance = Currency.get_special_balance(user_id)
|
||||
new_special_balance = int(current_special_balance) + amount
|
||||
Currency.update_special_balance(user_id, new_special_balance)
|
||||
|
||||
else:
|
||||
# user gained XP but not new level
|
||||
Xp.update_user_xp(user_id, new_xp, current_level, current_time + cooldown)
|
||||
print(f"XP UPDATE --- {message.author.name} gained {xp_gain} XP; new_xp = {new_xp}.")
|
||||
|
||||
"""
|
||||
Level calculation
|
||||
Linear = 9x + 27
|
||||
"""
|
||||
|
||||
@commands.slash_command(
|
||||
name="level",
|
||||
description="Displays your level and rank.",
|
||||
guild_only=True
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
async def level(self, ctx):
|
||||
xp_data = Xp.get_user_xp_data(ctx.author.id)
|
||||
(current_xp, current_level, cooldown) = xp_data[0]
|
||||
rank = Xp.calculate_rank(ctx.author.id)
|
||||
needed_xp_for_next_level = xp_functions.xp_needed_for_next_level(current_level)
|
||||
|
||||
await ctx.respond(embed=embeds.level_command_message(ctx, current_level, current_xp,
|
||||
needed_xp_for_next_level, rank))
|
||||
|
||||
@commands.slash_command(
|
||||
name="leaderboard",
|
||||
description="Are ya winnin' son?",
|
||||
guild_only=True
|
||||
)
|
||||
@commands.check(universal.channel_check)
|
||||
async def leaderboard(self, ctx):
|
||||
leaderboard = Xp.load_leaderboard()
|
||||
embed = await embeds.leaderboard_message(ctx, leaderboard)
|
||||
await ctx.respond(embed=embed)
|
||||
|
||||
|
||||
def setup(sbbot):
|
||||
sbbot.add_cog(Leveling(sbbot))
|
4
requirements.txt
Normal file
4
requirements.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
py-cord==2.4.1
|
||||
python-dotenv==1.0.0
|
||||
setuptools==67.8.0
|
||||
pytz==2023.3
|
347
sb_tools/economy_embeds.py
Normal file
347
sb_tools/economy_embeds.py
Normal file
|
@ -0,0 +1,347 @@
|
|||
import datetime
|
||||
import json
|
||||
import os
|
||||
|
||||
import discord
|
||||
import pytz
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv('.env')
|
||||
|
||||
cash_balance_name = os.getenv("CASH_BALANCE_NAME")
|
||||
special_balance_name = os.getenv("SPECIAL_BALANCE_NAME")
|
||||
est = pytz.timezone('US/Eastern')
|
||||
|
||||
with open("json/economy.json") as file:
|
||||
json_data = json.load(file)
|
||||
|
||||
|
||||
def currency_balance(ctx, cash_balance, special_balance):
|
||||
embed = discord.Embed(
|
||||
description=f"**Cash**: {cash_balance_name}{cash_balance}\n"
|
||||
f"**{special_balance_name.capitalize()}**: {special_balance}"
|
||||
)
|
||||
embed.set_author(name=f"{ctx.author.name}'s wallet", icon_url=ctx.author.avatar.url)
|
||||
embed.set_footer(text=f"Level up to earn {special_balance_name}!")
|
||||
return embed
|
||||
|
||||
|
||||
def award(user, currency, amount):
|
||||
reward = f"{amount}"
|
||||
if currency == "cash_balance":
|
||||
reward = cash_balance_name + reward
|
||||
else:
|
||||
reward = f"{reward} {special_balance_name}"
|
||||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.green(),
|
||||
description=f"Awarded **{reward}** to {user.name}."
|
||||
)
|
||||
return embed
|
||||
|
||||
|
||||
def give(ctx, user, currency, amount):
|
||||
reward = f"{amount}"
|
||||
if currency == "cash":
|
||||
reward = cash_balance_name + reward
|
||||
else:
|
||||
reward = f"{reward} {special_balance_name}"
|
||||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.green(),
|
||||
description=f"**{ctx.author.name}** gave **{reward}** to {user.name}."
|
||||
)
|
||||
embed.set_footer(text="Say thanks! :)")
|
||||
return embed
|
||||
|
||||
|
||||
def give_yourself_error(currency):
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.red(),
|
||||
description=f"You can't give {currency} to yourself, silly."
|
||||
)
|
||||
return embed
|
||||
|
||||
|
||||
def give_bot_error(currency):
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.red(),
|
||||
description=f"You can't give {currency} to a bot, silly."
|
||||
)
|
||||
return embed
|
||||
|
||||
|
||||
def already_playing(game):
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.red(),
|
||||
description=f"You're already playing {game}. Please finish this game first."
|
||||
)
|
||||
return embed
|
||||
|
||||
|
||||
def not_enough_cash():
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.red(),
|
||||
description="Oops! Your current cash balance isn't sufficient to do that."
|
||||
)
|
||||
return embed
|
||||
|
||||
|
||||
def not_enough_special_balance():
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.red(),
|
||||
description=f"Oops! Your current {special_balance_name} balance isn't sufficient to do that."
|
||||
)
|
||||
return embed
|
||||
|
||||
|
||||
def out_of_time():
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.red(),
|
||||
description="Uh-oh! Time's up. Your bet is forfeited as the game concludes."
|
||||
)
|
||||
return embed
|
||||
|
||||
|
||||
def exchange_confirmation(amount):
|
||||
embed = discord.Embed(
|
||||
description=f"You're about to sell {amount} {special_balance_name} for {cash_balance_name}{amount * 1000}. "
|
||||
f"Are you absolutely sure about this? Keep in mind that repurchasing {special_balance_name} "
|
||||
f"later is considerably more expensive."
|
||||
)
|
||||
return embed
|
||||
|
||||
|
||||
def exchange_done(amount):
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.green(),
|
||||
description=f"You successfully exchanged **{amount} {special_balance_name}** "
|
||||
f"for **{cash_balance_name}{amount * 1000}**."
|
||||
)
|
||||
return embed
|
||||
|
||||
|
||||
def exchange_stopped():
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.red(),
|
||||
description="The exchange was canceled because you clicked \"Stop\" or ran out of time."
|
||||
)
|
||||
return embed
|
||||
|
||||
|
||||
def coinflip(ctx, guess_side, throw_side, bet):
|
||||
embed = discord.Embed(
|
||||
title=f"You bet {cash_balance_name}{bet} on {guess_side}."
|
||||
)
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
|
||||
if throw_side == "heads":
|
||||
embed.set_thumbnail(url="https://media.tenor.com/nEu74vu_sT4AAAAC/heads-coinflip.gif")
|
||||
else:
|
||||
embed.set_thumbnail(url="https://media.tenor.com/kK8D7hQXX5wAAAAC/coins-tails.gif")
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def coinflip_finished(side, status):
|
||||
color = None
|
||||
|
||||
if status == "success":
|
||||
color = discord.Color.green()
|
||||
|
||||
|
||||
def blackjack_show(ctx, bet, player_hand, dealer_hand, player_hand_value, dealer_hand_value, status):
|
||||
current_time = datetime.datetime.now(est).strftime("%I:%M %p")
|
||||
you_text = "You"
|
||||
dealer_text = "Dealer"
|
||||
title_text = "BlackJack"
|
||||
thumbnail_url = None
|
||||
color = discord.Color.dark_orange()
|
||||
|
||||
if status == "player_busted":
|
||||
you_text = "You | BUSTED"
|
||||
title_text = "YOU LOST!"
|
||||
thumbnail_url = "https://i.imgur.com/rc68c43.png"
|
||||
color = discord.Color.red()
|
||||
|
||||
elif status == "dealer_busted":
|
||||
dealer_text = "Dealer | BUSTED"
|
||||
title_text = "YOU WON!"
|
||||
thumbnail_url = "https://i.imgur.com/dvIIr2G.png"
|
||||
color = discord.Color.green()
|
||||
|
||||
elif status == "dealer_won":
|
||||
title_text = "YOU LOST!"
|
||||
thumbnail_url = "https://i.imgur.com/rc68c43.png"
|
||||
color = discord.Color.red()
|
||||
|
||||
embed = discord.Embed(
|
||||
title=title_text,
|
||||
color=color
|
||||
)
|
||||
embed.add_field(name=you_text, value=f"**Score: {player_hand_value}**\n"
|
||||
f"*Hand: {' + '.join(player_hand)}*")
|
||||
|
||||
if len(dealer_hand) < 2:
|
||||
embed.add_field(name=dealer_text, value=f"**Score: {dealer_hand_value}**\n"
|
||||
f"*Hand: {dealer_hand[0]} + ??*", inline=False)
|
||||
else:
|
||||
embed.add_field(name=dealer_text, value=f"**Score: {dealer_hand_value}**\n"
|
||||
f"*Hand: {' + '.join(dealer_hand)}*", inline=False)
|
||||
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
embed.set_footer(text=f"Bet {cash_balance_name}{bet} • deck shuffled • Today at {current_time}",
|
||||
icon_url="https://i.imgur.com/96jPPXO.png")
|
||||
|
||||
if thumbnail_url:
|
||||
embed.set_thumbnail(url=thumbnail_url)
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def slots_spinning(ctx, spinning_icons_amount, bet, results, sbbot):
|
||||
first_slots_emote = sbbot.get_emoji(json_data["slots"]["emotes"][f"slots_{results[0]}_id"])
|
||||
second_slots_emote = sbbot.get_emoji(json_data["slots"]["emotes"][f"slots_{results[1]}_id"])
|
||||
slots_animated_emote = sbbot.get_emoji(json_data["slots"]["emotes"][f"slots_animated_id"])
|
||||
|
||||
decoration = json_data["slots"]["emotes"]
|
||||
S_Wide = sbbot.get_emoji(decoration["S_Wide"])
|
||||
L_Wide = sbbot.get_emoji(decoration["L_Wide"])
|
||||
O_Wide = sbbot.get_emoji(decoration["O_Wide"])
|
||||
T_Wide = sbbot.get_emoji(decoration["T_Wide"])
|
||||
|
||||
CBorderBLeft = sbbot.get_emoji(decoration["CBorderBLeft"])
|
||||
CBorderBRight = sbbot.get_emoji(decoration["CBorderBRight"])
|
||||
CBorderTLeft = sbbot.get_emoji(decoration["CBorderTLeft"])
|
||||
CBorderTRight = sbbot.get_emoji(decoration["CBorderTRight"])
|
||||
HBorderB = sbbot.get_emoji(decoration["HBorderB"])
|
||||
HBorderT = sbbot.get_emoji(decoration["HBorderT"])
|
||||
VBorder = sbbot.get_emoji(decoration["VBorder"])
|
||||
|
||||
Blank = sbbot.get_emoji(decoration["Blank"])
|
||||
|
||||
current_time = datetime.datetime.now(est).strftime("%I:%M %p")
|
||||
one = slots_animated_emote
|
||||
two = slots_animated_emote
|
||||
three = slots_animated_emote
|
||||
|
||||
if spinning_icons_amount == 3:
|
||||
pass
|
||||
elif spinning_icons_amount == 2:
|
||||
one = first_slots_emote
|
||||
elif spinning_icons_amount == 1:
|
||||
one = first_slots_emote
|
||||
two = second_slots_emote
|
||||
|
||||
description = f"🎰{S_Wide}{L_Wide}{O_Wide}{T_Wide}{S_Wide}🎰\n" \
|
||||
f"{CBorderTLeft}{HBorderT}{HBorderT}{HBorderT}{HBorderT}{HBorderT}{CBorderTRight}\n" \
|
||||
f"{VBorder}{one}{VBorder}{two}{VBorder}{three}{VBorder}\n" \
|
||||
f"{CBorderBLeft}{HBorderB}{HBorderB}{HBorderB}{HBorderB}{HBorderB}{CBorderBRight}\n" \
|
||||
f"{Blank}{Blank}❓❓❓{Blank}{Blank}{Blank}"
|
||||
|
||||
embed = discord.Embed(
|
||||
description=description
|
||||
)
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
embed.set_footer(text=f"Bet {cash_balance_name}{bet} • jackpot = x5 • {current_time}",
|
||||
icon_url="https://i.imgur.com/wFsgSnr.png")
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def slots_finished(ctx, payout_type, multiplier, bet, results, sbbot):
|
||||
first_slots_emote = sbbot.get_emoji(json_data["slots"]["emotes"][f"slots_{results[0]}_id"])
|
||||
second_slots_emote = sbbot.get_emoji(json_data["slots"]["emotes"][f"slots_{results[1]}_id"])
|
||||
third_slots_emote = sbbot.get_emoji(json_data["slots"]["emotes"][f"slots_{results[2]}_id"])
|
||||
current_time = datetime.datetime.now(est).strftime("%I:%M %p")
|
||||
|
||||
decoration = json_data["slots"]["emotes"]
|
||||
S_Wide = sbbot.get_emoji(decoration["S_Wide"])
|
||||
L_Wide = sbbot.get_emoji(decoration["L_Wide"])
|
||||
O_Wide = sbbot.get_emoji(decoration["O_Wide"])
|
||||
T_Wide = sbbot.get_emoji(decoration["T_Wide"])
|
||||
|
||||
CBorderBLeft = sbbot.get_emoji(decoration["CBorderBLeft"])
|
||||
CBorderBRight = sbbot.get_emoji(decoration["CBorderBRight"])
|
||||
CBorderTLeft = sbbot.get_emoji(decoration["CBorderTLeft"])
|
||||
CBorderTRight = sbbot.get_emoji(decoration["CBorderTRight"])
|
||||
HBorderB = sbbot.get_emoji(decoration["HBorderB"])
|
||||
HBorderT = sbbot.get_emoji(decoration["HBorderT"])
|
||||
VBorder = sbbot.get_emoji(decoration["VBorder"])
|
||||
|
||||
WSmall = sbbot.get_emoji(decoration["WSmall"])
|
||||
ISmall = sbbot.get_emoji(decoration["ISmall"])
|
||||
NSmall = sbbot.get_emoji(decoration["NSmall"])
|
||||
|
||||
LCentered = sbbot.get_emoji(decoration["LCentered"])
|
||||
OCentered = sbbot.get_emoji(decoration["OCentered"])
|
||||
SCentered = sbbot.get_emoji(decoration["SCentered"])
|
||||
ECentered = sbbot.get_emoji(decoration["ECentered"])
|
||||
|
||||
Blank = sbbot.get_emoji(decoration["Blank"])
|
||||
lost_emoji = sbbot.get_emoji(decoration["lost"])
|
||||
|
||||
field_name = "You lost."
|
||||
field_value = f"You lost **{cash_balance_name}{bet}**."
|
||||
color = discord.Color.red()
|
||||
is_lost = True
|
||||
|
||||
if payout_type == "pair":
|
||||
field_name = "Pair"
|
||||
field_value = f"You won **{cash_balance_name}{bet * multiplier}**."
|
||||
is_lost = False
|
||||
discord.Color.dark_green()
|
||||
elif payout_type == "three_of_a_kind":
|
||||
field_name = "3 of a kind"
|
||||
field_value = f"You won **{cash_balance_name}{bet * multiplier}**."
|
||||
is_lost = False
|
||||
discord.Color.dark_green()
|
||||
elif payout_type == "three_diamonds":
|
||||
field_name = "Triple Diamonds!"
|
||||
field_value = f"You won **{cash_balance_name}{bet * multiplier}**."
|
||||
is_lost = False
|
||||
discord.Color.green()
|
||||
elif payout_type == "jackpot":
|
||||
field_name = "JACKPOT!!"
|
||||
field_value = f"You won **{cash_balance_name}{bet * multiplier}**."
|
||||
is_lost = False
|
||||
discord.Color.green()
|
||||
|
||||
description = f"🎰{S_Wide}{L_Wide}{O_Wide}{T_Wide}{S_Wide}🎰\n" \
|
||||
f"{CBorderTLeft}{HBorderT}{HBorderT}{HBorderT}{HBorderT}{HBorderT}{CBorderTRight}\n" \
|
||||
f"{VBorder}{first_slots_emote}{VBorder}{second_slots_emote}{VBorder}{third_slots_emote}{VBorder}\n" \
|
||||
f"{CBorderBLeft}{HBorderB}{HBorderB}{HBorderB}{HBorderB}{HBorderB}{CBorderBRight}"
|
||||
|
||||
if is_lost:
|
||||
description += f"\n{Blank}{LCentered}{OCentered}{SCentered}{ECentered}{lost_emoji}{Blank}"
|
||||
else:
|
||||
description += f"\n{Blank}🎉{WSmall}{ISmall}{NSmall}🎉{Blank}"
|
||||
|
||||
embed = discord.Embed(
|
||||
color=color,
|
||||
description=description
|
||||
)
|
||||
embed.add_field(name=field_name, value=field_value)
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
embed.set_footer(text=f"Bet {cash_balance_name}{bet} • jackpot = x5 • {current_time}",
|
||||
icon_url="https://i.imgur.com/wFsgSnr.png")
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def daily_claim(amount):
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.green(),
|
||||
description=f"You claimed your daily reward of **{cash_balance_name}{amount}**."
|
||||
)
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def daily_wait(time):
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.red(),
|
||||
description=f"You can't claim that yet! Please wait **{time}**."
|
||||
)
|
||||
|
||||
return embed
|
82
sb_tools/economy_functions.py
Normal file
82
sb_tools/economy_functions.py
Normal file
|
@ -0,0 +1,82 @@
|
|||
import random
|
||||
from collections import Counter
|
||||
|
||||
|
||||
def blackjack_get_new_deck():
|
||||
suits = ['♠', '♡', '♢', '♣']
|
||||
ranks = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
|
||||
deck = []
|
||||
for suit in suits:
|
||||
for rank in ranks:
|
||||
deck.append(rank + suit)
|
||||
random.shuffle(deck)
|
||||
return deck
|
||||
|
||||
|
||||
def blackjack_deal_card(deck):
|
||||
return deck.pop()
|
||||
|
||||
|
||||
def blackjack_calculate_hand_value(hand):
|
||||
value = 0
|
||||
has_ace = False
|
||||
aces_count = 0
|
||||
|
||||
for card in hand:
|
||||
if card is None:
|
||||
continue
|
||||
|
||||
rank = card[:-1]
|
||||
|
||||
if rank.isdigit():
|
||||
value += int(rank)
|
||||
|
||||
elif rank in ['J', 'Q', 'K']:
|
||||
value += 10
|
||||
|
||||
elif rank == 'A':
|
||||
value += 11
|
||||
has_ace = True
|
||||
aces_count += 1
|
||||
|
||||
"""
|
||||
An Ace will have a value of 11 unless that would give a player
|
||||
or the dealer a score in excess of 21; in which case, it has a value of 1
|
||||
"""
|
||||
if value > 21 and has_ace:
|
||||
value -= 10 * aces_count
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def calculate_slots_results(bet, results):
|
||||
type = None
|
||||
multiplier = None
|
||||
|
||||
# count occurrences of each item in the list
|
||||
counts = Counter(results)
|
||||
|
||||
# no icons match
|
||||
if len(counts) == 3:
|
||||
type = "lost"
|
||||
multiplier = -1
|
||||
|
||||
# pairs
|
||||
elif len(counts) == 2:
|
||||
type = "pair"
|
||||
multiplier = 1
|
||||
|
||||
# 3 of a kind
|
||||
elif len(counts) == 1:
|
||||
if results[0] == 5:
|
||||
type = "three_diamonds"
|
||||
multiplier = 4
|
||||
elif results[0] == 6:
|
||||
type = "jackpot"
|
||||
multiplier = 5
|
||||
else:
|
||||
type = "three_of_a_kind"
|
||||
multiplier = 3
|
||||
|
||||
payout = bet * multiplier
|
||||
return type, payout, multiplier
|
145
sb_tools/embeds.py
Normal file
145
sb_tools/embeds.py
Normal file
|
@ -0,0 +1,145 @@
|
|||
import discord
|
||||
|
||||
from data.Xp import Xp
|
||||
|
||||
|
||||
def command_error_1():
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.red(),
|
||||
description="I'm not even sure how you reached this error but here we are. Try the command again."
|
||||
)
|
||||
embed.set_footer(text="And tell Tess!!!")
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def simple_question_5(question):
|
||||
embed = discord.Embed(color=0xadcca6,
|
||||
title=question)
|
||||
|
||||
embed.set_footer(text="max. 5 characters")
|
||||
return embed
|
||||
|
||||
|
||||
def simple_question_30(question):
|
||||
embed = discord.Embed(color=0xadcca6,
|
||||
title=question)
|
||||
|
||||
embed.set_footer(text="max. 30 characters")
|
||||
return embed
|
||||
|
||||
|
||||
def simple_question_100(question):
|
||||
embed = discord.Embed(color=0xadcca6,
|
||||
title=question)
|
||||
|
||||
embed.set_footer(text="max. 100 characters")
|
||||
return embed
|
||||
|
||||
|
||||
def simple_question_300(question):
|
||||
embed = discord.Embed(color=0xadcca6,
|
||||
title=question)
|
||||
|
||||
embed.set_footer(text="max. 300 characters")
|
||||
return embed
|
||||
|
||||
|
||||
def simple_question_none(question):
|
||||
embed = discord.Embed(color=0xadcca6,
|
||||
title=question)
|
||||
return embed
|
||||
|
||||
|
||||
def simple_question_first(question):
|
||||
embed = discord.Embed(color=0xadcca6,
|
||||
title=f"You chose to go with the short introduction! "
|
||||
f"Let's start with your nickname. {question}")
|
||||
embed.set_footer(text="max. 100 characters")
|
||||
return embed
|
||||
|
||||
|
||||
def simple_question_first_extended(question):
|
||||
embed = discord.Embed(color=0xadcca6,
|
||||
title=f"You chose to go with the extended introduction! "
|
||||
f"Let's start with your nickname. {question}")
|
||||
embed.set_footer(text="max. 100 characters")
|
||||
return embed
|
||||
|
||||
|
||||
def no_time():
|
||||
embed = discord.Embed(description="You ran out of time or clicked the \"Stop\" button. "
|
||||
"If you wish to start over, do **/intro**.")
|
||||
return embed
|
||||
|
||||
|
||||
def final_embed_short(ctx, nickname, age, location, pronouns, likes, dislikes):
|
||||
embed = discord.Embed(color=0x2200FF, description=
|
||||
f"**(Nick)name:** {nickname}\n\n**Age:** {age}\n\n"
|
||||
f"**Region:** {location}\n\n**Pronouns:** {pronouns}\n\n"
|
||||
f"**Likes & interests:** {likes}\n\n**Dislikes:** {dislikes}")
|
||||
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
embed.set_footer(text="Type: Short Introduction")
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def final_embed_extended(ctx, nickname, age, location, languages, pronouns,
|
||||
sexuality, relationship_status, likes, dislikes, extra):
|
||||
embed = discord.Embed(color=0xD91E1E, description=
|
||||
f"**(Nick)name:** {nickname}\n\n**Age:** {age}\n\n"
|
||||
f"**Region:** {location}\n\n**Languages:** {languages}\n\n"
|
||||
f"**Pronouns:** {pronouns}\n\n**Sexuality** {sexuality}\n\n"
|
||||
f"**Relationship status:** {relationship_status}\n\n**Likes & interests:** {likes}\n\n"
|
||||
f"**Dislikes:** {dislikes}\n\n**EXTRAS:** {extra}")
|
||||
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
embed.set_footer(text="Type: Extended Introduction")
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def final_confirmation(channel_id):
|
||||
embed = discord.Embed(color=0xadcca6,
|
||||
title="Your introduction has been posted in the server!",
|
||||
description=f"<#{channel_id}>")
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
#
|
||||
# def level_up_message(level, rank):
|
||||
# embed = discord.Embed(color=0xadcca6,
|
||||
# title=f"You reached level {level}!")
|
||||
# embed.set_footer(text=f"Rank: #{rank} | Leaderboard coming soon")
|
||||
# return embed
|
||||
|
||||
|
||||
def level_command_message(ctx, level, xp, next_level_xp, rank):
|
||||
embed = discord.Embed(color=0xadcca6,
|
||||
title=f"{ctx.author.name} - lv. {level}")
|
||||
embed.add_field(name="Progress to Next Level", value=Xp.generate_progress_bar(xp, next_level_xp), inline=False)
|
||||
embed.set_footer(text=f"The Rave Cave | Server Rank: #{rank}")
|
||||
embed.set_thumbnail(url=ctx.author.avatar.url)
|
||||
return embed
|
||||
|
||||
|
||||
async def leaderboard_message(ctx, leaderboard):
|
||||
embed = discord.Embed(
|
||||
color=0xadcca6
|
||||
)
|
||||
embed.set_author(name="Rave Cave Leaderboard",
|
||||
icon_url="https://cdn.discordapp.com/icons/719227135151046699/"
|
||||
"49df8c284382af9dbcfd629c8eadc52c.webp?size=96")
|
||||
embed.set_footer(text=f"Do /level to see your rank.")
|
||||
embed.set_thumbnail(url="https://i.imgur.com/79XfsbS.png")
|
||||
for i, (user_id, xp, level, rank, xp_needed_for_next_level) in enumerate(leaderboard[:5], start=1):
|
||||
member = await ctx.guild.fetch_member(user_id)
|
||||
embed.add_field(
|
||||
name=f"#{rank} - {member.name}",
|
||||
value=f"level: `{level}`\nxp: `{xp}/{xp_needed_for_next_level}`",
|
||||
inline=False
|
||||
)
|
||||
|
||||
return embed
|
232
sb_tools/interaction.py
Normal file
232
sb_tools/interaction.py
Normal file
|
@ -0,0 +1,232 @@
|
|||
import discord
|
||||
from discord.ui import View
|
||||
|
||||
|
||||
class IntroButtons(View):
|
||||
def __init__(self, ctx):
|
||||
super().__init__(timeout=300)
|
||||
self.ctx = ctx
|
||||
self.clickedShort = False
|
||||
self.clickedLong = False
|
||||
|
||||
async def on_timeout(self):
|
||||
for child in self.children:
|
||||
child.disabled = True
|
||||
await self.message.edit(view=None)
|
||||
|
||||
@discord.ui.button(label="Short", style=discord.ButtonStyle.primary)
|
||||
async def short_button_callback(self, button, interaction):
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.clickedShort = True
|
||||
self.stop()
|
||||
|
||||
@discord.ui.button(label="Extended", style=discord.ButtonStyle.green)
|
||||
async def extended_button_callback(self, button, interaction):
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.clickedLong = True
|
||||
self.stop()
|
||||
|
||||
@discord.ui.button(label="Stop", style=discord.ButtonStyle.red)
|
||||
async def stop_button_callback(self, button, interaction):
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.stop()
|
||||
|
||||
# async def on_timeout(self):
|
||||
# await self.ctx.
|
||||
|
||||
async def interaction_check(self, interaction) -> bool:
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message("You can't use these buttons, they're someone else's!",
|
||||
ephemeral=True)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
class BlackJackButtons(View):
|
||||
def __init__(self, ctx):
|
||||
super().__init__(timeout=180)
|
||||
self.ctx = ctx
|
||||
self.clickedHit = False
|
||||
self.clickedStand = False
|
||||
self.clickedDoubleDown = False
|
||||
|
||||
async def on_timeout(self):
|
||||
for child in self.children:
|
||||
child.disabled = True
|
||||
await self.message.edit(view=None)
|
||||
|
||||
@discord.ui.button(label="hit", style=discord.ButtonStyle.gray, emoji="<:hit:1119262723285467156> ")
|
||||
async def hit_button_callback(self, button, interaction):
|
||||
self.clickedHit = True
|
||||
await interaction.response.defer()
|
||||
self.stop()
|
||||
|
||||
@discord.ui.button(label="stand", style=discord.ButtonStyle.gray, emoji="<:stand:1118923298298929154>")
|
||||
async def stand_button_callback(self, button, interaction):
|
||||
self.clickedStand = True
|
||||
await interaction.response.defer()
|
||||
self.stop()
|
||||
|
||||
# @discord.ui.button(label="double down", style=discord.ButtonStyle.gray, emoji="<:double_down:1118923344549523656>")
|
||||
# async def double_down_button_callback(self):
|
||||
# self.clickedDoubleDown = True
|
||||
# self.stop()
|
||||
|
||||
async def interaction_check(self, interaction) -> bool:
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message("You can't use these buttons, they're someone else's!",
|
||||
ephemeral=True)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
class ExchangeConfirmation(View):
|
||||
def __init__(self, ctx):
|
||||
super().__init__(timeout=180)
|
||||
self.ctx = ctx
|
||||
self.clickedConfirm = False
|
||||
|
||||
async def on_timeout(self):
|
||||
for child in self.children:
|
||||
child.disabled = True
|
||||
await self.message.edit(view=None)
|
||||
|
||||
@discord.ui.button(label="Confirm", style=discord.ButtonStyle.green)
|
||||
async def confirm_button_callback(self, button, interaction):
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.clickedConfirm = True
|
||||
self.stop()
|
||||
|
||||
@discord.ui.button(label="Stop", style=discord.ButtonStyle.red)
|
||||
async def stop_button_callback(self, button, interaction):
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.stop()
|
||||
|
||||
async def interaction_check(self, interaction) -> bool:
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message("You can't use these buttons, they're someone else's!",
|
||||
ephemeral=True)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
class Confirm(View):
|
||||
def __init__(self, ctx):
|
||||
super().__init__(timeout=300)
|
||||
self.ctx = ctx
|
||||
self.clickedConfirm = False
|
||||
|
||||
async def on_timeout(self):
|
||||
for child in self.children:
|
||||
child.disabled = True
|
||||
await self.message.edit(view=None)
|
||||
|
||||
@discord.ui.button(label="Post it!", style=discord.ButtonStyle.green)
|
||||
async def short_button_callback(self, button, interaction):
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.clickedConfirm = True
|
||||
self.stop()
|
||||
|
||||
@discord.ui.button(label="Stop", style=discord.ButtonStyle.red)
|
||||
async def extended_button_callback(self, button, interaction):
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.stop()
|
||||
|
||||
# async def on_timeout(self):
|
||||
# await self.ctx.
|
||||
|
||||
async def interaction_check(self, interaction) -> bool:
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message("You can't use these buttons, they're someone else's!",
|
||||
ephemeral=True)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
class DuelChallenge(View):
|
||||
def __init__(self, opponent):
|
||||
super().__init__(timeout=60)
|
||||
self.opponent = opponent
|
||||
self.clickedConfirm = False
|
||||
self.clickedDeny = False
|
||||
|
||||
async def on_timeout(self):
|
||||
for child in self.children:
|
||||
child.disabled = True
|
||||
await self.message.edit(view=None)
|
||||
|
||||
@discord.ui.button(label="accept", style=discord.ButtonStyle.green)
|
||||
async def short_button_callback(self, button, interaction):
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.clickedConfirm = True
|
||||
self.stop()
|
||||
|
||||
@discord.ui.button(label="deny", style=discord.ButtonStyle.red)
|
||||
async def extended_button_callback(self, button, interaction):
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.clickedDeny = True
|
||||
self.stop()
|
||||
|
||||
async def interaction_check(self, interaction) -> bool:
|
||||
if interaction.user != self.opponent:
|
||||
await interaction.response.send_message("You can't use these buttons, they're someone else's!",
|
||||
ephemeral=True)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
class LocationOptions(discord.ui.View):
|
||||
def __init__(self, ctx):
|
||||
super().__init__(timeout=120)
|
||||
self.ctx = ctx
|
||||
self.location = None
|
||||
|
||||
async def on_timeout(self):
|
||||
for child in self.children:
|
||||
child.disabled = True
|
||||
await self.message.edit(view=None)
|
||||
|
||||
async def interaction_check(self, interaction) -> bool:
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message("You can't use this menu, it's someone else's!", ephemeral=True)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
@discord.ui.select(
|
||||
min_values=1,
|
||||
max_values=1,
|
||||
options=[
|
||||
discord.SelectOption(
|
||||
label="Choose a continent",
|
||||
default=True
|
||||
),
|
||||
discord.SelectOption(
|
||||
label="Africa"
|
||||
),
|
||||
discord.SelectOption(
|
||||
label="Europe"
|
||||
),
|
||||
discord.SelectOption(
|
||||
label="Asia"
|
||||
),
|
||||
discord.SelectOption(
|
||||
label="North America"
|
||||
),
|
||||
discord.SelectOption(
|
||||
label="South America"
|
||||
),
|
||||
discord.SelectOption(
|
||||
label="Oceania"
|
||||
)
|
||||
]
|
||||
)
|
||||
async def select_callback(self, select, interaction):
|
||||
self.location = select.values[0]
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.stop()
|
150
sb_tools/level_messages.py
Normal file
150
sb_tools/level_messages.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
import random
|
||||
|
||||
|
||||
def load_level_message(level):
|
||||
if level in [5, 10, 15, 20, 25, 30, 35, 40, 45, 50]:
|
||||
return f"Congratulations! You've reached **Level {level}** and earned a new level role!"
|
||||
elif level < 10:
|
||||
return random.choice(level_under_10).format(level)
|
||||
elif 10 < level < 20:
|
||||
return random.choice(level_10_to_20).format(level)
|
||||
elif 20 < level < 40:
|
||||
return random.choice(level_20_to_40).format(level)
|
||||
elif 40 < level < 60:
|
||||
return random.choice(level_40_to_60).format(level)
|
||||
elif level == 100:
|
||||
return level_100.format(level)
|
||||
else:
|
||||
return random.choice(level_above_60).format(level)
|
||||
|
||||
|
||||
level_100 = "YOU HAVE REACHED **LEVEL {}**!!I know you have something to say and I know you're eager to say it so I'll " \
|
||||
"get right to the point: Shut " \
|
||||
"the fuck up. Nobody wants to hear it. Nobody will ever want to hear it. Nobody cares. And the fact that " \
|
||||
"you thought someone might care is honestly baffling to me. I've actually pulled the entire world. Here's " \
|
||||
"a composite of the faces of everybody who wants you to shut the fuck up. It seems as if this is a " \
|
||||
"composite of every human being on the planet. Interesting. Now for a composite of the faces that want " \
|
||||
"you to keep talking: Interesting, it seems as if nothing has happened. Here's the world map. Now here's " \
|
||||
"the text: Shut the fuck up. That's what you should do. But you know what? Maybe I am being a little too " \
|
||||
"harsh here. I actually do have it on good authority thanks to my pulling data that there is as at least " \
|
||||
"1 person who actually wants to hear you speak. It's a little child in Mozambique and he oh? He's dead? " \
|
||||
"Well sorry man I guess nobody wants to hear you talk anymore. Please shut the fuck up."
|
||||
|
||||
|
||||
level_under_10 = [
|
||||
"Wow, look who finally managed to crawl their way to **Level {}**! Congrats, I guess.",
|
||||
"You're like a **Level {}** pebble in the vast ocean of talent. Keep striving!",
|
||||
"**Level {}**? That's cute. Maybe one day you'll reach mediocrity.",
|
||||
"Congratulations on **Level {}**! You must be so proud of yourself... or not.",
|
||||
"A wild **Level {}** appears! Brace yourself for mild amusement.",
|
||||
"Oh, **Level {}**! That's like a participation trophy, right?",
|
||||
"Achievement unlocked: **Level {}**! Your parents must be thrilled.",
|
||||
"Breaking news: **Level {}** has entered the chat! Prepare for underwhelming feats.",
|
||||
"Welcome to **Level {}**, where average is the new extraordinary.",
|
||||
"**Level {}**! Slow and steady wins the race... except when it comes to leveling up.",
|
||||
"Congratulations on **Level {}**. Your progress is... mildly amusing.",
|
||||
"Breaking news: **Level {}** has unlocked the 'Barely Trying' achievement!",
|
||||
"Attention, **Level {}**! Your achievement is about as significant as a grain of sand.",
|
||||
"Behold! **Level {}** has emerged from the shadows of insignificance.",
|
||||
"You've unlocked the 'Bare Minimum' achievement at **Level {}**. Bravo!",
|
||||
"Welcome to the realm of **Level {}**. Prepare for mild excitement.",
|
||||
"Congratulations on your ascent to **Level {}**. It's a small step for mankind.",
|
||||
"At **Level {}**, you're like a firework that fizzles out before it even begins.",
|
||||
"**Level {}** has been reached! Commence the average dance of mild enthusiasm.",
|
||||
"Alert! **Level {}** has been activated. Don't expect any fireworks.",
|
||||
"Congratulations on reaching **Level {}**. Let the underwhelming festivities commence!",
|
||||
"Rumor has it that reaching **Level {}** unlocks the ability to slightly impress others.",
|
||||
"**Level {}** has been achieved! Brace yourself for a lukewarm round of applause.",
|
||||
"You've made it to **Level {}**. Prepare for a dose of lukewarm recognition.",
|
||||
"At **Level {}**, you're one step closer to the realm of mild accomplishment.",
|
||||
"Rejoice! **Level {}** has been conquered, ushering in an era of moderate achievement.",
|
||||
"**Level {}** is here! Your accomplishment might raise an eyebrow or two.",
|
||||
"Congratulations on reaching **Level {}**. It's a humble feat, to say the least.",
|
||||
"Behold, **Level {}**! Let the celebration be as mild as the achievement itself.",
|
||||
"You've reached **Level {}**, where average becomes the new extraordinary.",
|
||||
"Prepare to be mildly impressed. It's **Level {}**, the master of slight accomplishments.",
|
||||
"Congratulations on unlocking the 'Just Getting Started' achievement at **Level {}**!",
|
||||
"Welcome to **Level {}**. It's like a lukewarm bath for your achievements.",
|
||||
]
|
||||
|
||||
|
||||
level_10_to_20 = [
|
||||
"Congratulations motherfucker you leveled the fuck up to **Level {}**.",
|
||||
"levle **{}** cmoning in! Let's celbraet!",
|
||||
"yay you reach the level **{}** waw you are so cool many time",
|
||||
"omg senpai you weach wevew **{}**",
|
||||
"reached **Level {}** but you'll never get on MY level HAAHAHAHAHA",
|
||||
"*elevator music* Welcome to **level {}**.",
|
||||
"Oh, look who's managed to crawl their way up to **Level {}**. Prepare for disappointment.",
|
||||
"Congratulations on reaching the underwhelming heights of **Level {}**. Your achievements astound no one.",
|
||||
"Ah, **Level {}**, where the bar is set so low even you can stumble over it.",
|
||||
"Bravo on reaching **Level {}**. It must be exhausting exerting such minimal effort.",
|
||||
"Welcome to the world of **Level {}**, where mediocrity is celebrated with empty enthusiasm.",
|
||||
"You've unlocked the dubious achievement of **Level {}**. Prepare for the resounding sound of indifference.",
|
||||
"Kudos on reaching **Level {}**. I'm sure the world will pause to celebrate this momentous occasion... just as "
|
||||
"soon as it remembers you exist.",
|
||||
"Prepare for the overwhelming roar of applause as you reach **Level {}**. Just kidding, it's more like the sound "
|
||||
"of crickets chirping in disappointment."
|
||||
"Behold, the prodigious talent of **Level {}**. Just kidding, there's nothing impressive about it.",
|
||||
"Well, well, well, **Level {}**. Your accomplishments are as impressive as a deflated balloon.",
|
||||
"Prepare for the parade in your honor, oh illustrious **Level {}**. Just kidding, no one cares.",
|
||||
"Ah, **Level {}**, where dreams come to die a slow and painful death. Enjoy your stay.",
|
||||
"Congratulations on reaching **Level {}**. Your insignificance knows no bounds.",
|
||||
]
|
||||
|
||||
level_20_to_40 = [
|
||||
"Oh my god! Did you set up a macro for this? You're **level {}**!",
|
||||
"**Level {}**. If you don't stop leveling up... **I am going to commit a fucking war crime.**",
|
||||
"**Level {}** 👍",
|
||||
"Wow you're **level {}**. I regret not just using Tatsumaki bot for this.",
|
||||
"**Level {}**. If you don't stop leveling up, I might have to stage an intervention. Discord addiction is real!",
|
||||
"**Level {}**. Are you sure your life isn't just an elaborate Discord role-playing game?",
|
||||
"Look who's slacking off work to level up on Discord. **Level {}** and counting!",
|
||||
"**Level {}**? Have you considered that there might be an entire world outside of Discord?",
|
||||
"Congratulations on reaching **level {}**. Your dedication to Discord is truly unparalleled.",
|
||||
"Wow, you've climbed to **level {}**. Is Discord your full-time job now?",
|
||||
"**Level {}**. I bet your parents are so proud of the countless hours you've spent on Discord.",
|
||||
"Oh look, it's **level {}**! Are you sure you're not secretly a Discord bot in disguise?",
|
||||
"Achievement unlocked: **level {}**! You must have broken Discord's leveling algorithm by now.",
|
||||
"You've reached **level {}**. I hope you're using your Discord powers for good and not just spamming memes.",
|
||||
"**Level {}** and still going strong. Who needs a social life when you have Discord, right?",
|
||||
"Oh, **level {}**. I'm starting to think you might actually be a sentient Discord notification.",
|
||||
"Congratulations on leveling up to **level {}**. I hope Discord gives you a lifetime supply of virtual cookies.",
|
||||
"**Level {}**. At this rate, you'll surpass even the Discord founders in Discord addiction.",
|
||||
"Look who's made it to **level {}**. I'm starting to think you're more Discord than human.",
|
||||
"Wow, **level {}**! Do you ever wonder if Discord should be paying you a salary at this point?",
|
||||
"Congratulations on reaching **level {}**. Your dedication to Discord is both awe-inspiring and mildly concerning.",
|
||||
"You've unlocked the 'Master of Procrastination' achievement at **level {}**. Your parents must be so proud.",
|
||||
"**Level {}**? I bet you have more Discord badges than real-life achievements.",
|
||||
"Well, well, well, **level {}**. Your Discord addiction is reaching legendary status.",
|
||||
]
|
||||
|
||||
|
||||
level_40_to_60 = [
|
||||
"You've reached **Level {}**. Stop. Just stop. You've had enough of this app. Go away.",
|
||||
"TOUCH GRASS. You didn't deserve **Level {}** but here it is I guess..",
|
||||
"I'm so tired of giving you levels. I'm not even going to say which level you just reached. Just kidding it's **Level {}**."
|
||||
"Oh, look who's flexing their **Level {}** status. Don't strain a muscle.",
|
||||
"Congratulations on reaching **Level {}**. Are you trying to make the rest of us feel inadequate?",
|
||||
"Breaking news: **Level {}** has officially mastered the art of pressing buttons. Amazing.",
|
||||
"Hats off to **Level {}**. Your dedication is truly admirable... or slightly concerning.",
|
||||
"Are you okay...? **Level {}** is seriously unhealthy bro. Sleep.",
|
||||
"STOP. LEVELING. LEAVE. ME. ALONE. Here's your damn level: **{}**"
|
||||
"HAS REACHED **LEVEL {}**, FUCK YEAH."
|
||||
"**Level {}**. The second-hand embarrassment is real."
|
||||
]
|
||||
|
||||
level_above_60 = [
|
||||
"You've weached **W-Wevew {}**. stawp. Just stawp. Y-Y-You've had enyough of this a-app. Go a-away.",
|
||||
"TOUCH GWASS. Y-You didn't d-desewve **W-Wevew {}** but h-hewe it is I guess..",
|
||||
"I'm so tiwed of giving you w-wevews. I'm nyot even going to say which wevew you just weached. Just kidding it's **{}**."
|
||||
"Oh, wook who's fwexing theiw **W-Wevew {}** status. Don't stwain a muscwe.",
|
||||
"Congwatuwations on weaching **W-Wevew {}**. Awe you twying to make the w-west of us feew inyadequate?",
|
||||
"Bweaking nyews: **W-Wevew {}** has officiawwy wiciawwy mastewed the awt of pwessing buttons. Amazing.",
|
||||
"Hats o-o-off to **W-Wevew {}**. Youw dedication is twuwy wuwy admiwabwe... ow swightwy wightwy concewnying.",
|
||||
"Awe you okay...? **W-Wevew {}** i-is s-s-sewiouswy wewiouswy unheawthy weawthy bwo. Sweep.",
|
||||
"STAWP. WEVEWING. WEAVE. ME. AWONYE. Hewe's youw dawn wevew: **{}**"
|
||||
"HAS WEACHED **WEVEW {}**, FWICK YEAH."
|
||||
"**Wevew {}**. The second-hand embawwassment is w-w-weaw."
|
||||
]
|
||||
|
19
sb_tools/reactions.py
Normal file
19
sb_tools/reactions.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
import discord
|
||||
|
||||
trigger_list=[
|
||||
"good bot",
|
||||
"racu"
|
||||
]
|
||||
|
||||
|
||||
async def check_for_reaction(message):
|
||||
content = message.content.lower()
|
||||
|
||||
# check if whole message = trigger
|
||||
if content in trigger_list:
|
||||
if content == trigger_list[0]:
|
||||
await message.reply(content="Thanks!")
|
||||
|
||||
# check if trigger is in message
|
||||
if trigger_list[1] in content:
|
||||
await message.add_reaction("❤️")
|
5
sb_tools/resources.py
Normal file
5
sb_tools/resources.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
__title__ = "RCU"
|
||||
__version__ = "1.2.17"
|
||||
__author__ = "Esther J. J."
|
||||
__author_email__ = "dokimakimaki@gmail.com"
|
||||
__license__ = "GNU GENERAL PUBLIC LICENSE v2"
|
42
sb_tools/universal.py
Normal file
42
sb_tools/universal.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
load_dotenv('.env')
|
||||
|
||||
|
||||
async def channel_check(ctx):
|
||||
desired_channel_id = 1118587309365940407 # bot-chat in RCU
|
||||
owner_id = os.getenv("OWNER_ID")
|
||||
|
||||
if ctx.channel.id != desired_channel_id and ctx.author.id != int(owner_id):
|
||||
channel_mention = f"<#{desired_channel_id}>"
|
||||
await ctx.respond(f"You can only do that command in {channel_mention}.", ephemeral=True)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def beta_check(ctx):
|
||||
owner_id = os.getenv("OWNER_ID")
|
||||
if ctx.author.id != int(owner_id):
|
||||
embed = discord.Embed(description=f"You can't use this command just yet! It's currently undergoing testing and "
|
||||
f"fine-tuning to ensure the best experience for all users. Stay tuned for its "
|
||||
f"official release.",
|
||||
color=discord.Color.red())
|
||||
await ctx.respond(embed=embed)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def owner_check(ctx):
|
||||
owner_id = os.getenv("OWNER_ID")
|
||||
if ctx.author.id != int(owner_id):
|
||||
embed = discord.Embed(description=f"Only Tess can do this command.",
|
||||
color=discord.Color.red())
|
||||
await ctx.respond(embed=embed)
|
||||
return False
|
||||
|
||||
return True
|
20
sb_tools/xp_functions.py
Normal file
20
sb_tools/xp_functions.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
def xp_needed_for_next_level(current_level):
|
||||
formula_mapping = {
|
||||
(10, 19): lambda level: 12 * level + 27,
|
||||
(20, 29): lambda level: 15 * level + 27,
|
||||
(30, 39): lambda level: 18 * level + 27,
|
||||
(40, 49): lambda level: 21 * level + 27,
|
||||
(50, 59): lambda level: 24 * level + 27,
|
||||
(60, 69): lambda level: 27 * level + 27,
|
||||
(70, 79): lambda level: 30 * level + 27,
|
||||
(80, 89): lambda level: 33 * level + 27,
|
||||
(90, 99): lambda level: 36 * level + 27,
|
||||
(100, 109): lambda level: 39 * level + 27,
|
||||
}
|
||||
|
||||
for level_range, formula in formula_mapping.items():
|
||||
if level_range[0] <= current_level <= level_range[1]:
|
||||
return formula(current_level)
|
||||
|
||||
# For levels below 10 and levels 110 and above
|
||||
return 9 * current_level + 27 if current_level < 30 else 42 * current_level + 27
|
Loading…
Reference in a new issue