summaryrefslogtreecommitdiffhomepage
path: root/FelicityBot.py
blob: e3c3a3cf3f8d18632639c0d899b473f442cc7c51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
#Code written by Tradam --> https://github.com/realtradam

import os

import discord
import random
import json
import re #regular expression
from mcstatus import MinecraftServer #Use 'python3 -m pip install mcstatus' to install, required for minecraft capabilities
from dotenv import load_dotenv #Substitues the API key variable

storedStats = {}
#{userid : {hp : num, damage : num, death: num}, etc.}

#The following are usef for emoji conversion, changes set depending on which server
#	is sending the message.
storedEmoji1 = {"<normal-emoji-on-server>": "<custom-animated-emoji>"}
#The first emoji set is set for a specific server of your choice
#You can set emojis on your server to be converted into emojis
#	of your choice(ones that are animated for example)
				
storedEmoji2 = {"!cheer": "<a:cheated:690837457440210945>", 
				"!stress": "<a:stressed:690851643863990302>",
				"!dance": "<a:dance:690853091704176660>",
				"🦜": "<a:partyparrot:691049985264975933>",
				"!trash": "<a:blobtrash:691090868123467866>",
				"!jojo": "<a:jotarodance:691090868513538048>",
				"!bongo": "<a:bongoowo:691090866965839912>"}
#The second emoji set will work on any server, but uses generic commands

load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')# You need to set up a .env file which holds your token

client = discord.Client()

#Sets up the bot, its variables, etc. when the bot is initially run
@client.event
async def on_ready():
	global storedStats
	print('{} is connected to the following servers:'.format(client.user))
	for guild in client.guilds:
		print('\t- {} (id: {})'.format(guild.name,guild.id))
	await client.change_presence(status = 'None', activity=discord.Game('you like a damn fiddle'))
	
	#Loads up the statistics of players using the !attack command
	json1_file = open('attacks.json')
	json1_str = json1_file.read()
	storedStats = json.loads(json1_str)
	
	print("save data loaded")
	print('Bot is live!')
#            break

#Invoked whenever a message is sent in a server
@client.event
async def on_message(message):
	#Variable set up
	global storedStats, storedEmoji1, storedEmoji2
	temp = 0
	temp1 = 0
	temp2 = 0
	#Used for user identification
	isVerified = "false"
	isAdmin = "false"
	#Address to server
	mcServer = MinecraftServer("<server.ip>", <port>)
	
	#If the bot sent the message, ignore
	if message.author == client.user:
		return
		
	#Determines user permissions(will later check agaisnt role name)
	for item in message.author.roles:
		if(str(item) == "Minecraft"):
			isVerified = "true"
		if(str(item) == "ADMIN"):
			isAdmin = "true"
	
	#Depending on which server the message was in: what emoji set should be used
	if str(message.guild.id) == str("<server-id>"):
		animatedEmoji = storedEmoji1
	else: #All other servers use the generic set
		animatedEmoji = storedEmoji2
	
	#Show info about the minecraft server
	if message.content.lower() == "!mc":
		if(isVerified == "true"):
			try:
				status = mcServer.status()
				query = mcServer.query()
				players = query.players.online
				if players == 0:
					await message.channel.send("The server is Online with no active players")
				elif players == 1:
					await message.channel.send("The server is Online with 1 active player: {}".format(", ".join(query.players.names)))
				elif players > 1:
					await message.channel.send("The server is Online with {} active players: {}".format(players, ", ".join(query.players.names)))
			except ConnectionError:
				await message.channel.send("Server is Offline (Unless it has just been booted up)")
		else:
			await message.channel.send("You do not have permission to do that")
			
	#Run the mc server, if it is not running
	if message.content.lower() == "!mcstart":
		if(isVerified == "true"):
			try:
				status = mcServer.status()
				await message.channel.send("The server is already Online!")
			except ConnectionError:
				os.system('(cd <path/to/folder>; ./<runnable-script>)')#Run a script that will correctly start your server
				await message.channel.send("Server is Offline. Bootup has started, it usually takes up to about 2 minutes to finish booting and become visible online so please be patient")
				return
			return
		else:
			await message.channel.send("You do not have permission to do that")
	
	#Stop the mc server, if it is empty
	if message.content.lower() == "!mcstop":
		if(isVerified == "true"):
			try:
				status = mcServer.status()
				players = status.players.online
				if players > 0:
					await message.channel.send("The server still has players on it! The server must be empty before shutdown can happen")
				else:
					with open ("<path/to/PID.txt>", "r") as myfile: #path to text file that stores the PID of the minecraft server, so that the server can be told to shut down
						pid = myfile.read()
					os.system("kill -15 {}".format(pid))
					await message.channel.send("Server has shut down")
			except ConnectionError:
				await message.channel.send("The server is already Offline (Or if you just booted it up, hasn't come Online yet)")
		else:
			await message.channel.send("You do not have permission to do that")
	
	#Splits the message, so the first word can be matched to a command, and use the rest of the words as parameters
	temp = message.content.lower().split()
	if (len(temp) == 2): #If the command has a parameter
		if (temp[0] == "!react") and (len(temp) == 2):
			for key in animatedEmoji:
				if temp[1] == key:
					await message.delete()
					async for react in message.channel.history(limit=1):
						await react.add_reaction(animatedEmoji[key])
						return
			return
		
		if (temp[0] == "!delete") and (len(temp) == 2) and (isAdmin == "true"):
			#This can be optimized by sending a batch delete rather then increment once
			#It's somehwere in the discord.py api
			async for delete in message.channel.history(limit=(int(temp[1])+1)):
				await delete.delete()
			return
		
		if (temp[0] == '!attack') and (len(temp) == 2):
			#A little game where users can attack eachother
			#These variable names NEED to be cleaned up
			temp1 = temp[1]
			temp2 = [temp1[:2],temp1[2:-1],temp1[-1:]]
			if temp2[1][:1] == '!':
				temp2[1] = temp2[1][1:]
			if temp2[0] == '<@' and temp2[2] == '>':
				temp = random.randint(1,29)
				if str(message.author.id) not in storedStats:
					storedStats[str(message.author.id)] = {'hp' : 50, 'damage' : 0, 'deaths' : 0}
				if str(temp2[1]) == "<id-of-this-bot>":
					await message.channel.send('<a:angryAwooGlitch:691087516819914772>')
					return
				elif str(temp2[1]) not in storedStats:
					storedStats[str(temp2[1])] = {'hp' : 50, 'damage' : 0, 'deaths' : 0}
				
				storedStats[str(temp2[1])]['hp'] -= temp
				if storedStats[str(temp2[1])]['hp'] <= 0:
					storedStats[str(temp2[1])]['deaths'] += 1
					storedStats[str(temp2[1])]['hp'] = 50
					if str(message.author.id) == str(temp2[1]):
						await message.channel.send('<a:blobhang:691023822576549930>')
						await message.channel.send('<@{}> killed themselves'.format(message.author.id))
						return
					await message.channel.send('<:killed:690998665686548483>')
					await message.channel.send('<@{}> dealt {} damage, killing {}!'.format(message.author.id,'{:,}'.format(temp),temp1))
					storedStats[str(message.author.id)]['damage'] += temp
				else:
					await message.channel.send('You dealt {0} damage to {1}\n{1} has {2} HP remaining'.format('{:,}'.format(temp),temp1,'{:,}'.format((storedStats[str(temp2[1])]['hp']))))
					storedStats[str(message.author.id)]['damage'] += temp
			return
				
		if temp[0] == '!roll':
			if len(temp) > 1:
				await message.channel.send("<@{}> rolled a {}".format(message.author.id, random.randint(1, int(temp[1]))))
			else:
				await message.channel.send("Type a space and a number after !roll to roll a dice that size")
			return

	
	if message.content.lower() == '!stats':
		if str(message.author.id) not in storedStats:
			storedStats[str(message.author.id)] = {'hp' : 50, 'damage' : 0, 'deaths' : 0}
		await message.channel.send('<@{}>\nHP: {}\nDamage Dealt: {}\nDeaths: {}'.format(str(message.author.id),'{:,}'.format(storedStats[str(message.author.id)]['hp']),'{:,}'.format(storedStats[str(message.author.id)]['damage']),'{:,}'.format(storedStats[str(message.author.id)]['deaths'])))
	
	if message.content.lower() == '!save' and (isAdmin == "true"):
		with open('attacks.json', 'w') as fp:
			json.dump(storedStats,fp)
		print("data saved to server")
		await message.channel.send("data saved to server")
	
	if message.content.lower() == '!load' and (isAdmin == "true"):
		json1_file = open('attacks.json')
		json1_str = json1_file.read()
		storedStats = json.loads(json1_str)
		print("save data loaded")
		await message.channel.send("save data loaded")
		
	if message.content.lower() == '!flip':
		if random.randint(1, 2) == 1:#heads
			await message.add_reaction('👧')#react heads
		else:
			await message.add_reaction('🐀')#react tails
		return

	
	if message.content.lower() == '!list':
		temp = ""
		for key in animatedEmoji:
			temp += '{} --> {}\n'.format(key,animatedEmoji[key])
		await message.channel.send(temp)
		return
	
	#The following searches the user's message to see if any of the custom emoji set matches
	#If it does then it will replace it, and resend the message on behalf of the user
	#	while also deleting the original users message
	#To identify the original user who sent the message, it also @'s them
	temp2 = message.content
	switchFlag = 0
	for key in animatedEmoji:
		temp = re.search(re.escape(key), message.content, flags=re.I)
		if (str(temp) != "None"):
			temp2 = re.sub(re.escape(key), animatedEmoji[key], temp2, flags=re.I)
			switchFlag = 1#sets a flag that a match was made, and should replace the message
	if  switchFlag == 1:#ONLY replace if a match was found
		await message.channel.send('<@{}>:'.format(message.author.id))
		await message.delete()
		await message.channel.send(temp2)
		



client.run(TOKEN)