Skip to content

Commit

Permalink
result sheet visual 1
Browse files Browse the repository at this point in the history
  • Loading branch information
yakMM committed Sep 20, 2020
1 parent 0af123a commit 40359c5
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 74 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# v1.15:
- Cap points are no longer counted in team netscore
- Updated score sheet visual

# v1.14:
- Added sub command for staff
- Updated help embeds for all channels
Expand Down
2 changes: 1 addition & 1 deletion bot/classes/teams.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def clear(self):
def addCap(self, points):
self.__cap += points
self.__score += points
self.__net += points
# self.__net += points

def addScore(self, points):
self.__score += points
Expand Down
26 changes: 15 additions & 11 deletions bot/matches.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,12 @@ def __init__(self, mId, ch=None):
self.__resultMsg = None
_allMatches[mId] = self
self.__accounts = None
self.__roundsStamps = list()
self.__roundStamps = list()

@classmethod
def newFromData(cls, data):
obj = cls(data["_id"])
obj.__roundsStamps = data["round_stamps"]
obj.__roundStamps = data["round_stamps"]
obj.__mapSelector = MapSelection.newFromId(data["_id"], data["base_id"])
for i in range(len(data["teams"])):
obj.__teams[i] = Team.newFromData(i, data["teams"][i], obj)
Expand Down Expand Up @@ -229,8 +229,8 @@ def getData(self):
for tm in self.__teams:
teamsData.append(tm.getData())
data = {"_id": self.__number,
"round_stamps": self.__roundsStamps,
"round_length_min": cfg.ROUND_LENGHT,
"round_stamps": self.__roundStamps,
"round_length_min": cfg.ROUND_LENGTH,
"base_id": self.__mapSelector.map.id,
"teams": teamsData
}
Expand Down Expand Up @@ -380,7 +380,7 @@ async def __ready(self):
self.__status = MatchStatus.IS_WAITING
await channelSend("MATCH_CONFIRM", self.__id, *captainPings, match=self)

@tasks.loop(minutes=cfg.ROUND_LENGHT, delay=1, count=2)
@tasks.loop(minutes=cfg.ROUND_LENGTH, delay=1, count=2)
async def _onMatchOver(self):
playerPings = [" ".join(tm.allPings) for tm in self.__teams]
await channelSend("MATCH_ROUND_OVER", self.__id, *playerPings, self.roundNo)
Expand Down Expand Up @@ -422,7 +422,7 @@ async def __startMatch(self):
await sleep(10)
playerPings = [" ".join(tm.allPings) for tm in self.__teams]
await channelSend("MATCH_STARTED", self.__id, *playerPings, self.roundNo)
self.__roundsStamps.append(int(dt.timestamp(dt.now())))
self.__roundStamps.append(int(dt.timestamp(dt.now())))
self.__status = MatchStatus.IS_PLAYING
self._onMatchOver.start()

Expand Down Expand Up @@ -468,7 +468,7 @@ async def clear(self):
self.__accounts = None
self.__mapSelector = None
self.__teams = [None, None]
self.__roundsStamps.clear()
self.__roundStamps.clear()
self.__resultMsg = None
self.__players.clear()
await channelSend("MATCH_CLEARED", self.__id)
Expand All @@ -488,14 +488,18 @@ def players(self):
@property
def roundNo(self):
if self.__status is MatchStatus.IS_PLAYING:
return len(self.__roundsStamps)
return len(self.__roundStamps)
if self.__status in (MatchStatus.IS_STARTING, MatchStatus.IS_WAITING):
return len(self.__roundsStamps)+1
return len(self.__roundStamps)+1
return 0

@property
def startStamp(self):
return self.__roundsStamps[-1]
return self.__roundStamps[-1]

@property
def roundStamps(self):
return self.__roundStamps

@property
def mapSelector(self):
Expand All @@ -509,7 +513,7 @@ def mapSelector(self):
# # DEV
# @startStamp.setter
# def startStamp(self, st):
# self.__roundsStamps = st
# self.__roundStamps = st

# # DEV
# @mapSelector.setter
Expand Down
2 changes: 1 addition & 1 deletion bot/modules/census.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
async def processScore(match):
igDict = dict()
start = match.startStamp
end = start+cfg.ROUND_LENGHT*60
end = start+cfg.ROUND_LENGTH*60
for tm in match.teams:
for aPlayer in tm.players:
igDict[aPlayer.igId] = aPlayer
Expand Down
2 changes: 1 addition & 1 deletion bot/modules/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

## STATIC PARAMETERS:
AFK_TIME = 15 # minutes
ROUND_LENGHT = 10 # minutes
ROUND_LENGTH = 10 # minutes

## DYNAMIC PARAMETERS:
# (pulled from the config file)
Expand Down
35 changes: 18 additions & 17 deletions bot/modules/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,36 +45,40 @@ async def channelSend(stringName, id, *args, **kwargs):
Returns the message sent
"""
channel = _client.get_channel(id)
return await _StringEnum[stringName].value.display(channel,False, *args, **kwargs)
return await _StringEnum[stringName].value.display(channel, channel.send, *args, **kwargs)

async def privateSend(stringName, id, *args, **kwargs):
""" Send the message stringName in dm to user identified with id, with aditional strings *args. Pass **kwargs to the embed function, if any
Returns the message sent
"""
user = _client.get_user(id)
return await _StringEnum[stringName].value.display(user, False, *args, **kwargs)
return await _StringEnum[stringName].value.display(user, user.send, *args, **kwargs)

async def send(stringName, ctx, *args, **kwargs):
""" Send the message stringName in context ctx, with aditional strings *args. Pass **kwargs to the embed function, if any
Returns the message sent
"""
return await _StringEnum[stringName].value.display(ctx, False, *args, **kwargs)
try:
sendFct = ctx.send
except AttributeError:
sendFct = _client.get_channel(ctx.channel.id).send
return await _StringEnum[stringName].value.display(ctx, sendFct, *args, **kwargs)

async def edit(stringName, ctx, *args, **kwargs):
""" Replaces the message ctx by the message stringName, with aditional strings *args. Pass **kwargs to the embed function, if any
Returns the message sent
"""
return await _StringEnum[stringName].value.display(ctx, True, *args, **kwargs)
return await _StringEnum[stringName].value.display(ctx, ctx.edit, *args, **kwargs)

async def remReaction(message, user=None):
if user is None:
global _client
user = _client.user
return await message.remove_reaction("✅", user)

async def imageSend(channelId, imagePath):
async def imageSend(stringName, channelId, imagePath, *args):
channel = _client.get_channel(channelId)
return await channel.send(file=File(imagePath))
return await channel.send(content=_StringEnum[stringName].value.string.format(*args), file=File(imagePath))

## PRIVATE:

Expand Down Expand Up @@ -379,16 +383,18 @@ def _jaegerCalendar(arg):
class _Message():
""" Class for the enum to use
"""
def __init__(self,str,ping=True,embed=None):
self.__str = str
def __init__(self, string, ping=True, embed=None):
self.__str = string
self.__embedFct = embed
self.__ping = ping

@property
def string(self):
return self.__str

async def display(self, ctx, edit, *args, **kwargs):
async def display(self, ctx, sendFct, *args, **kwargs):
# If is Context instead of a Message, get the Message:
embed = None
sendFct = None
msg = None

try:
Expand All @@ -403,13 +409,6 @@ async def display(self, ctx, edit, *args, **kwargs):
embed = self.__embedFct(ctx, **kwargs)
# Fixes the embed mobile bug but ugly af:
#embed.set_author(name="_____________________________")
if edit:
sendFct = ctx.edit
else:
try:
sendFct = ctx.send
except AttributeError:
sendFct = _client.get_channel(ctx.channel.id).send

if self.__ping and not author is None:
msg = await sendFct(content=f'{author.mention} {string}', embed=embed)
Expand Down Expand Up @@ -574,6 +573,8 @@ class _StringEnum(Enum):

SC_ILLEGAL_WE = _Message("{} used {} during match {}! This weapon is banned! Ignoring {} kill(s)...")
SC_PLAYERS_STRING = _Message("Here is player data for squittal script:\n{}")
SC_RESULT_HALF = _Message("Match {} - **halftime**")
SC_RESULT = _Message("Match {}")

SUB_NO = _Message("This player can't be subbed!")
SUB_NO_CAPTAIN = _Message("Can't sub a Team Captain!")
Expand Down
126 changes: 83 additions & 43 deletions bot/modules/imageMaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,91 +3,131 @@
from modules.display import imageSend
from modules.enumerations import MatchStatus
import modules.config as cfg
from datetime import datetime as dt

bigFont = ImageFont.truetype("../fonts/OpenSans2.ttf", 50)
font = ImageFont.truetype("../fonts/OpenSans2.ttf", 40)
fill = (255,255,255)
bigFont = ImageFont.truetype("../fonts/OpenSans2.ttf", 100)
font = ImageFont.truetype("../fonts/OpenSans2.ttf", 80)
smallFont = ImageFont.truetype("../fonts/OpenSans2.ttf", 60)
white = (255,255,255)
yellow = (254, 227, 76)
grey1 = (219,219,219)
grey2 = (178,178,178)
yellow_light = (254,244,186)
Y_SPACING = 120
Y_BIG_SPACE = 150

X_OFFSET=300
X_OFFSET=100


def _drawScoreLine(draw, xStart, y, values, font):
def _drawScoreLine(draw, xStart, y, values, font, fill):
for i in range(len(values)):
draw.text((xStart+300*i,y), values[i], font=font, fill=fill)

def _findCutOffSize(string, font, treshold):
def _binarySearch(i):
iHalf = i//2
half = font.getsize(string[:iHalf])[0]
half1 = font.getsize(string[:iHalf+1])[0]
if half <= treshold and half1 >= treshold:
return iHalf
if half >= treshold:
return _binarySearch(half)
_binarySearch(treshold)


def _cutOffString(string, font, treshold):
def _binarySearch(base, i):
size = font.getsize(string[:base+i]+"...")[0]
size1 = font.getsize(string[:base+i+1]+"...")[0]
if size <= treshold and size1 >= treshold:
return base+i
if i==1:
return base+i+1
if size >= treshold:
return _binarySearch(base,i//2)
if size <= treshold:
return _binarySearch(base+i,i//2)
if font.getsize(string)[0] <= treshold:
return string
res = _binarySearch(0,len(string))
return string[:res]+"..."

def _teamDisplay(draw, team, yOffset):

# Team name:
draw.text((X_OFFSET,100+yOffset), team.name, font=bigFont, fill=fill)

# Titles:
_drawScoreLine(draw, X_OFFSET+1000, yOffset, ["SCORE","NET","KILLS","DEATHS"], font)
_drawScoreLine(draw, X_OFFSET+2200, yOffset, ["Score","Net","Kills","Deaths"], font, yellow)

# Team scores:
scores = [str(team.score), str(team.net), str(team.kills), str(team.deaths)]
_drawScoreLine(draw, X_OFFSET+1000, 100+yOffset, scores, bigFont)
_drawScoreLine(draw, X_OFFSET+2200, Y_SPACING+yOffset, scores, bigFont, white)

# Cap
draw.text((X_OFFSET+500,800+yOffset), "CAP", font=font, fill=fill)
draw.text((X_OFFSET+1000,800+yOffset), str(team.cap), font=font, fill=fill)
# Team name:
draw.text((X_OFFSET,Y_SPACING+yOffset),
f'{team.name} ({cfg.factions[team.faction]})', font=bigFont, fill=white)

# Players:
color = [white, white]
for i in range(len(team.players)):
aPlayer = team.players[i]

# Scores:
scores = [str(aPlayer.score), str(aPlayer.net), str(aPlayer.kills), str(aPlayer.deaths)]
_drawScoreLine(draw, X_OFFSET+1000, 200+100*i+yOffset, scores, font)
_drawScoreLine(draw, X_OFFSET+2200, Y_BIG_SPACE*2+Y_SPACING*i+yOffset, scores,
font, color[i%2])

# Names:
name = aPlayer.name
igName = aPlayer.igName
print(font.getsize(name))
if len(name) > 20:
name = name[:20] + "..."
name = _cutOffString(aPlayer.name, font, 1000)
igName = _cutOffString(aPlayer.igName, font, 1000)

if len(igName) > 20:
igName = igName[:20] + "..."

draw.text((X_OFFSET,200+100*i+yOffset), name, font=font, fill=fill)
draw.text((X_OFFSET+500,200+100*i+yOffset), igName, font=font, fill=fill)
draw.text((X_OFFSET,Y_BIG_SPACE*2+Y_SPACING*i+yOffset), name, font=font, fill=color[i%2])
draw.text((X_OFFSET+1100,Y_BIG_SPACE*2+Y_SPACING*i+yOffset), igName, font=font, fill=color[i%2])





def _makeImage(match):
img = Image.new('RGB', (2600, 2500), color = (17, 0, 68))
#img = Image.open("pil_template.png")
img = Image.new('RGB', (3600, 3100), color = (17, 0, 68))
logo = Image.open("../logos/bot.png")
logo = logo.resize((600,600))
img.paste(logo, (300,100), logo)
#img = Image.open("score_template.png")
yOff = lambda tId : 325+Y_SPACING*4+1200*tId
draw = ImageDraw.Draw(img)
draw.text((1150,150), f"MATCH {match.number}", font=bigFont, fill=fill)
if match.status is not MatchStatus.IS_RESULT:
draw.text((1150,250), f"Halftime", font=bigFont, fill=fill)
x = X_OFFSET+1100
xTitle = (3600-bigFont.getsize(f"Planetside Open Games - Match {match.number}")[0])//2
draw.text((xTitle,100), f"Planetside Open Games - Match {match.number}", font=bigFont, fill=white)
draw.text((x,200+100), f"Base: {match.map.name}", font=smallFont, fill=white)
for i in range(len(match.roundStamps)):
rs = match.roundStamps[i]
text = dt.utcfromtimestamp(rs).strftime("%Y-%m-%d %H:%M")
draw.text((x,200+100*(2+i)), f"Round {i+1}: {text}", font=smallFont, fill=white)
if len(match.roundStamps) < 2:
draw.text((x,200+100*3), f"Round 2: ", font=smallFont, fill=white)
draw.text((x+smallFont.getsize("Round 2: ")[0],200+100*3), f"In progress...", font=smallFont, fill=yellow)
draw.text((x,200+100*4), f"Round length: {cfg.ROUND_LENGTH} minutes", font=smallFont, fill=white)

halSize = 25
xMax=3600
yMax=3100
draw.line([halSize, 0, halSize,yMax], fill =(0,0,0), width = halSize*2)
draw.line([0, halSize, xMax,halSize], fill =(0,0,0), width = halSize*2)
draw.line([0, yMax-halSize, xMax,yMax-halSize], fill =(0,0,0), width = halSize*2)
draw.line([xMax-halSize, 0, xMax-halSize,yMax], fill =(0,0,0), width = halSize*2)
for tm in match.teams:
_teamDisplay(draw, tm, 400+1100*tm.id)
yOffset = yOff(tm.id)
draw.line([halSize*2, yOffset-20, xMax-halSize*2,yOffset-20], fill =white, width = 10)
draw.line([100, yOffset+Y_BIG_SPACE*2-20, xMax-100,yOffset+Y_BIG_SPACE*2-20],
fill =yellow, width = 10)

draw.text((X_OFFSET+2200,200+100), f"Captures:", font=smallFont, fill=white)
for tm in match.teams:
draw.text((X_OFFSET+2200,200+100*(tm.id+2)), f"{tm.name}: {tm.cap} points", font=smallFont, white=white)
_teamDisplay(draw, tm, yOff(tm.id))
img.save(f'../matches/match_{match.number}.png')


async def publishMatchImage(match):
loop = get_event_loop()
await loop.run_in_executor(None, _makeImage, match)

msg = match.msg
if msg is not None:
await msg.delete()
msg = await imageSend(cfg.channels["results"], f'../matches/match_{match.number}.png')

if match.status is MatchStatus.IS_RESULT:
string = "SC_RESULT"
else:
string = "SC_RESULT_HALF"
msg = await imageSend(string, cfg.channels["results"], f'../matches/match_{match.number}.png', match.number)
return msg

Binary file removed fonts/Helvetica.ttf
Binary file not shown.
Binary file removed fonts/OpenSans.ttf
Binary file not shown.
Binary file removed fonts/PlanetSide2.ttf
Binary file not shown.
Binary file modified logos/bot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 40359c5

Please sign in to comment.