처음 유저 데이터를 만들었을 때 레벨도 추가했었지만 거의 더미데이터 수준으로 쓰이지 않았다
일단 레벨업부터 만들어보자
아직 레벨업 수단에 대해서 생각해둔 게 없기 때문에 임의로 경험치를 추가 할 수 있는 명령어도 만들어야 한다
레벨 관련 코드 추가
먼저 userDB.xlsx를 조금 수정한다
레벨업에 필요한 경험치(exp)를 추가하고 column의 위치도 조금 바꾸었다
다음으로 user.py에서 필요한 코드를 수정한다
column의 위치를 다시 정해주고 회원가입과 정보를 가져오는 함수에 exp를 추가했다
#user.py
...
c_name = 1
c_id = 2
c_lvl = 3
c_exp = 4
c_money = 5
c_loss = 6
...
def Signup(_name, _id):
loadFile()
_row = checkFirstRow()
ws.cell(row=_row, column=c_name, value=_name)
ws.cell(row=_row, column=c_id, value =hex(_id))
ws.cell(row=_row, column=c_lvl, value = 1)
ws.cell(row=_row, column=c_exp, value = 0)
ws.cell(row=_row, column=c_money, value = default_money)
ws.cell(row=_row, column=c_loss, value = 0)
saveFile()
...
def userInfo(_row):
loadFile()
_lvl = ws.cell(_row,c_lvl).value
_exp = wsl.cell(_row,c_exp).value
_money = ws.cell(_row,c_money).value
_loss = ws.cell(_row,c_loss).value
saveFile()
return _lvl, _exp, _money, _loss
...
def addExp(_row, _amount):
loadFile()
ws.cell(_row, c_exp).value += _amount
saveFile()
main.py에서도 정보관련 함수를 수정한다
정보를 가져올 때 exp를 추가하고 embed에도 exp 정보를 보내도록 수정한다
#main.py
...
@bot.command()
async def 내정보(ctx):
userExistance, userRow = checkUser(ctx.author.name, ctx.author.id)
if not userExistance:
await ctx.send("회원가입 후 자신의 정보를 확인할 수 있습니다.")
else:
level, exp, money, loss = userInfo(userRow)
embed = discord.Embed(title="유저 정보", description = ctx.author.name, color = 0x62D0F6)
embed.add_field(name = "레벨", value = level)
embed.add_field(name = "경험치", value = exp)
embed.add_field(name = "보유 자산", value = money, inline = False)
embed.add_field(name = "도박으로 날린 돈", value = loss, inline = False)
await ctx.send(embed=embed)
@bot.command()
async def 정보(ctx, user: discord.User):
userExistance, userRow = checkUser(user.name, user.id)
if not userExistance:
await ctx.send(user.name + " 은(는) 등록되지 않은 사용자입니다.")
else:
level, exp, money, loss = userInfo(userRow)
embed = discord.Embed(title="유저 정보", description = user.name, color = 0x62D0F6)
embed.add_field(name = "레벨", value = level)
embed.add_field(name = "경험치", value = exp)
embed.add_field(name = "보유 자산", value = money, inline = False)
embed.add_field(name = "도박으로 날린 돈", value = loss, inline = False)
await ctx.send(embed=embed)
...
정보 확인도 문제 없이 되었다
레벨업 시스템
일단은 채팅을 치면 경험치를 얻는 것으로 하고 코딩을 하려고 했으나
봇이 돌아가는 동안 어떻게 레벨업을 확인할지 그림이 안그려졌다
일단 discord.py에서는 on_message(msg)라는 event를 가지고 있는데 이걸 그대로 사용하면
계속 이 함수에서만 돌기 때문에 지금까지 만든 모든 명령어를 이쪽으로 옮기는 작업을 해야한다...
그런 미친짓을 할 수 없기에 일단 열심히 검색을 해봤다
누가 말했지
코딩을 하면서 뭔가 안된다면 검색을 해보라고...
어딘가 사는 누군가가 이미 그걸 경험했고 다른 누군가가 해결책을 제시했다고...
이렇게 하면 된다고 한다
확인을 위해 main.py에 코드를 살짝 추가했다
...
@bot.event
async def on_message(message):
if message.author == bot.user:
return
print("levelup!")
await bot.process_commands(message)
...
성공했다!
이제 레벨업을 확인하는 함수를 만들어야겠다
레벨업 당 필요한 경험치는 마인크래프트 위키를 참고했다
뭔가 많지만 귀찮으니 첫번째줄만 사용한다
#main.py
...
@bot.event
async def on_message(message):
if message.author == bot.user:
return
userExistance, userRow = checkUser(message.author.name, message.author.id)
channel = message.channel
if userExistance:
levelUp, lvl = levelupCheck(userRow)
if levelUp:
embed = discord.Embed(title = "레벨업", description = None, color = 0x00A260)
embed.set_footer(text = message.author.name + "이 " + str(lvl) + "레벨 달성!")
await channel.send(embed=embed)
else:
addExp(userRow, 1)
await bot.process_commands(message)
...
#user.py
...
def levelupCheck(_row):
print("user.py - levelupCheck")
loadFile()
name = ws.cell(_row, c_name).value
exp = ws.cell(_row, c_exp).value
lvl = ws.cell(_row, c_lvl).value
amount_to_up = lvl*lvl + 6*lvl
if exp >= amount_to_up:
ws.cell(_row, c_lvl).value += 1
ws.cell(_row, c_exp).value -= amount_to_up
return True, lvl+1
else:
return False, lvl
...
def addExp(_row, _amount):
loadFile()
ws.cell(_row, c_exp).value += _amount
saveFile()
...
메세지 보낸게 봇이면 무시하고 levelupCheck를 통해 레벨업 여부 판단하여 메세지를 보낸다
다만 아직 문제가 좀 있는게 갑자기 많은 경험치를 주었을 때 한번에 레벨업하지 않는다
아마 반복문으로 해결 가능할 듯 하다
#user.py
...
def levelupCheck(_row):
loadFile()
name = ws.cell(_row, c_name).value
exp = ws.cell(_row, c_exp).value
lvl = ws.cell(_row, c_lvl).value
amount_to_up = lvl*lvl + 6*lvl
count = 0
if exp >= amount_to_up:
while(exp >= amount_to_up and exp >= 0):
ws.cell(_row, c_lvl).value += 1
count += 1
ws.cell(_row, c_exp).value -= amount_to_up
lvl = ws.cell(_row, c_lvl).value
exp = ws.cell(_row, c_exp).value
amount_to_up = lvl*lvl + 6*lvl
return True, lvl+count
else:
return False, lvl
반복문으로 수정한 결과 한번에 많은 경험치가 들어와도 정상적으로 레벨업 처리가 되었다
랭킹 시스템
이제 랭킹을 만들어보자
먼저 내정보에서 자신의 순위를 볼 수 있게 하자
#user.py
...
def ranking():
loadFile()
userRanking = {}
userNum = checkUserNum()
for row in range(2, 2+userNum):
_name = ws.cell(row, c_name).value
_lvl = ws.cell(row, c_lvl).value
userRanking[_name] = _lvl
a = sorted(userRanking.items(), reverse=True, key=lambda item:item[1])
result = []
for items in a:
result.append(items[0])
result.append(items[1])
return result
def getRank(_row):
print("user.py - getRank")
user = ws.cell(_row, c_name).value
rank = ranking()
result = int(rank.index(user)/2)+1
return result
...
내림차순 정렬에 엄청난 시간을 들였다...
간단히 설명하면 Dictionary로 이름(key), 레벨(value)를 저장하고
레벨(value)에 따라 내림차순 정렬한다
이때 저장되는 건 tuple로 된 list이다
tuple된건 써먹기 귀찮기 때문에 이걸 list로 다시 바꾸어준다
이걸 출력하면 이렇게 나온다
이걸 반환값으로 넣고 getRank함수에서 user의 index를 찾아 순위로 만들고 최종적으로 반환한다
이제 정보, 내정보 함수의 embed에 순위만 추가하면 된다
#main.py
...
@bot.command()
async def 내정보(ctx):
userExistance, userRow = checkUser(ctx.author.name, ctx.author.id)
if not userExistance:
await ctx.send("회원가입 후 자신의 정보를 확인할 수 있습니다.")
else:
level, exp, money, loss = userInfo(userRow)
rank = getRank(userRow)
userNum = checkUserNum()
embed = discord.Embed(title="유저 정보", description = ctx.author.name, color = 0x62D0F6)
embed.add_field(name = "레벨", value = level)
embed.add_field(name = "경험치", value = str(exp) + "/" + str(level*level + 6*level))
embed.add_field(name = "순위", value = str(rank) + "/" + str(userNum))
embed.add_field(name = "보유 자산", value = money, inline = False)
embed.add_field(name = "도박으로 날린 돈", value = loss, inline = False)
await ctx.send(embed=embed)
@bot.command()
async def 정보(ctx, user: discord.User):
userExistance, userRow = checkUser(user.name, user.id)
if not userExistance:
await ctx.send(user.name + " 은(는) 등록되지 않은 사용자입니다.")
else:
level, exp, money, loss = userInfo(userRow)
rank = getRank(userRow)
userNum = chekcUserNum()
embed = discord.Embed(title="유저 정보", description = user.name, color = 0x62D0F6)
embed.add_field(name = "레벨", value = level)
embed.add_field(name = "경험치", value = str(exp) + "/" + str(level*level + 6*level))
embed.add_field(name = "순위", value = str(rank) + "/" + str(userNum))
embed.add_field(name = "보유 자산", value = money, inline = False)
embed.add_field(name = "도박으로 날린 돈", value = loss, inline = False)
await ctx.send(embed=embed)
...
위의 두 부분만 추가하면 된다
내정보를 통해 이름, 레벨, 경험치, 순위, 보유자산, 도박으로 날린 돈까지 볼 수 있게 되었다
이제 마지막으로 랭킹을 집계해보자
#main.py
...
@bot.command()
async def 랭킹(ctx):
rank = ranking()
embed = discord.Embed(title = "레벨 랭킹", description = None, color = 0x4A44FF)
for i in range(0,len(rank)):
if i%2 == 0:
name = rank[i]
lvl = rank[i+1]
embed.add_field(name = str(int(i/2+1))+"위 "+name, value ="레벨: "+str(lvl), inline=False)
await ctx.send(embed=embed)
...
랭킹을 만드는건 그렇게 어렵지 않았다
ranking함수로 list를 받아와서 반복문으로 돌리면 되니...
얘도 간단히 설명하면
이 list에서 2로 나누어 떨어지는 index, 즉 이름이 들어가 있는 위치를 찾아서
name에 그 이름을, lvl에는 그 이름 바로 뒤에 있는 레벨을 할당하고
embed.add_field를 해주면 끝!
다음에는 묵혀두었던 음악봇을 다시 만들어 보자
'프로젝트 > 디스코드 봇' 카테고리의 다른 글
디스코드 봇 만들기#12 - 서버 호스팅 (20) | 2021.04.02 |
---|---|
디스코드 봇 만들기#11 - 음악 봇 (4) | 2021.03.26 |
디스코드 봇 만들기#9 - 홀짝 게임 (4) | 2021.03.12 |
디스코드 봇 만들기#8 - 송금 (0) | 2021.03.05 |
디스코드 봇 만들기#7.5 - 내정보 확인 (0) | 2021.02.26 |