forked from Cryz/battle_royale_sim
added image map generator, map cell's color and emoji legend, death players emoji and color
This commit is contained in:
8
bot.py
8
bot.py
@@ -24,7 +24,7 @@ async def bot_start(update, context):
|
|||||||
['Init/Restart'],
|
['Init/Restart'],
|
||||||
['Add Player', 'Add random Players', 'Add random color Players'],
|
['Add Player', 'Add random Players', 'Add random color Players'],
|
||||||
['Get Players', 'Get Alive Players', 'Get Death Players', 'Get Ranking Players',],
|
['Get Players', 'Get Alive Players', 'Get Death Players', 'Get Ranking Players',],
|
||||||
['Simulate Day', 'Run Periodically', 'Show Map']
|
['Simulate Day', 'Run Periodically', 'Show Map UTF8', 'Show Map Image']
|
||||||
]
|
]
|
||||||
reply_markup= ReplyKeyboardMarkup(keyboard, one_time_keyboard=False, resize_keyboard=True)
|
reply_markup= ReplyKeyboardMarkup(keyboard, one_time_keyboard=False, resize_keyboard=True)
|
||||||
|
|
||||||
@@ -64,8 +64,10 @@ async def bot_commands(update, context):
|
|||||||
return await _cmd.cmd_add_random_players(context, update, chat_id)
|
return await _cmd.cmd_add_random_players(context, update, chat_id)
|
||||||
if text == 'Add random color Players':
|
if text == 'Add random color Players':
|
||||||
return await _cmd.cmd_add_random_color_players(context, update, chat_id)
|
return await _cmd.cmd_add_random_color_players(context, update, chat_id)
|
||||||
if text == 'Show Map':
|
if text == 'Show Map UTF8':
|
||||||
return await _cmd.cmd_show_game_map(context, update, chat_id)
|
return await _cmd.cmd_show_game_map_unicode(context, update, chat_id)
|
||||||
|
if text == 'Show Map Image':
|
||||||
|
return await _cmd.cmd_show_game_map_image(context, update, chat_id)
|
||||||
|
|
||||||
# special commands
|
# special commands
|
||||||
if text == 'upstart': return await _scmd.update_bot(update, context)
|
if text == 'upstart': return await _scmd.update_bot(update, context)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from utils import logs as _log
|
from utils import logs as _log
|
||||||
|
from bot_libs import syms as _bot_syms
|
||||||
from bot_libs import player_handling as _bot_player
|
from bot_libs import player_handling as _bot_player
|
||||||
from bot_libs import simulation as _bot_simulation
|
from bot_libs import simulation as _bot_simulation
|
||||||
from bot_libs import repeating as _bot_repeat
|
from bot_libs import repeating as _bot_repeat
|
||||||
@@ -61,11 +62,20 @@ async def cmd_get_ranking_players(context, update, chat_id):
|
|||||||
async def cmd_simulate_day(context, update, chat_id):
|
async def cmd_simulate_day(context, update, chat_id):
|
||||||
return await _bot_simulation.simulate_day(context, chat_id)
|
return await _bot_simulation.simulate_day(context, chat_id)
|
||||||
|
|
||||||
async def cmd_show_game_map(context, update, chat_id):
|
async def cmd_show_game_map_unicode(context, update, chat_id):
|
||||||
Arena= context.application.bot_data['arena']
|
Arena= context.application.bot_data['arena']
|
||||||
Gamemap= Arena.get_map()
|
Gamemap= Arena.get_map()
|
||||||
rendered_map= Gamemap.get_renderized_map()
|
rendered_map= Gamemap.get_renderized_map()
|
||||||
return await update.message.reply_text(rendered_map)
|
await update.message.reply_text(rendered_map)
|
||||||
|
return await update.message.reply_text(_bot_syms.MAP_UTF8_LEGEND, parse_mode='MarkdownV2')
|
||||||
|
|
||||||
|
async def cmd_show_game_map_image(context, update, chat_id):
|
||||||
|
Arena= context.application.bot_data['arena']
|
||||||
|
Gamemap= Arena.get_map()
|
||||||
|
image_map= Gamemap.get_image_map()
|
||||||
|
bot= update.get_bot()
|
||||||
|
await bot.send_photo(chat_id= chat_id, photo= image_map)
|
||||||
|
return await update.message.reply_text(_bot_syms.MAP_IMAGE_LEGEND, parse_mode='MarkdownV2')
|
||||||
|
|
||||||
async def cmd_simulate_day_cron(context, update, chat_id):
|
async def cmd_simulate_day_cron(context, update, chat_id):
|
||||||
context.application.bot_data['ask_seconds'] = 1
|
context.application.bot_data['ask_seconds'] = 1
|
||||||
|
|||||||
@@ -75,3 +75,40 @@ COLORS_NAMES= [
|
|||||||
"Pearl", "Pumpkin", "Navy", "Ultramarine", "Sapphire", "Desert", "Cherry",
|
"Pearl", "Pumpkin", "Navy", "Ultramarine", "Sapphire", "Desert", "Cherry",
|
||||||
"Tulip",
|
"Tulip",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
MAP_UTF8_FIELD= '🟩'
|
||||||
|
MAP_UTF8_MOUNTAIN= '⛰️'
|
||||||
|
MAP_UTF8_PLAYER_MALE= '👨'
|
||||||
|
MAP_UTF8_PLAYER_FEMALE= '👧🏻'
|
||||||
|
MAP_UTF8_PLAYER_NONBINARY= '⚧️'
|
||||||
|
MAP_UTF8_DEATH_PLAYER= '💀'
|
||||||
|
MAP_UTF8_ITEM= '📦'
|
||||||
|
|
||||||
|
MAP_UTF8_LEGEND= f"""*Legenda*:
|
||||||
|
\- *{MAP_UTF8_FIELD}*: Cella *libera* per muoversi
|
||||||
|
\- *{MAP_UTF8_MOUNTAIN}*: Bordo della mappa, *non raggiungibile*
|
||||||
|
\- *{MAP_UTF8_PLAYER_MALE}*: Posizione di un *giocatore Maschio*
|
||||||
|
\- *{MAP_UTF8_PLAYER_FEMALE}*: Posizione di una *giocatorice Femmina*
|
||||||
|
\- *{MAP_UTF8_PLAYER_NONBINARY}*: Posizione di un *giocatore non binario*
|
||||||
|
\- *{MAP_UTF8_DEATH_PLAYER}*: Posizione di un *giocatore morto*
|
||||||
|
\- *{MAP_UTF8_ITEM}*: Posizione di un *oggetto* \(non ancora implementato\)
|
||||||
|
"""
|
||||||
|
|
||||||
|
MAP_IMAGE_FIELD= (0, 255, 0) # green
|
||||||
|
MAP_IMAGE_MOUNTAIN= (0, 0, 0) # black
|
||||||
|
MAP_IMAGE_PLAYER_MALE= (0, 0, 255) # blue
|
||||||
|
MAP_IMAGE_PLAYER_FEMALE= (255, 0, 0) # red
|
||||||
|
MAP_IMAGE_PLAYER_NONBINARY= (255, 255, 0) # yellow
|
||||||
|
MAP_IMAGE_DEATH_PLAYER= (160, 160, 160) # grey
|
||||||
|
MAP_IMAGE_ITEM= (255, 255, 255) # white
|
||||||
|
|
||||||
|
MAP_IMAGE_LEGEND= """*Legenda*:
|
||||||
|
\- *Verde*: Cella *libera* per muoversi
|
||||||
|
\- *Nero*: Bordo della mappa, *non raggiungibile*
|
||||||
|
\- *Blue*: Posizione di un *giocatore Maschio*
|
||||||
|
\- *Rosso*: Posizione di una *giocatorice Femmina*
|
||||||
|
\- *Giallo*: Posizione di un *giocatore non binario*
|
||||||
|
\- *Grigio*: Posizione di un *giocatore morto*
|
||||||
|
\- *Bianco*: Posizione di un *oggetto* \(non ancora implementato\)
|
||||||
|
"""
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import random as _random
|
import random as _random
|
||||||
import copy as _copy
|
import copy as _copy
|
||||||
|
import io as _io
|
||||||
|
from PIL import Image as _Image
|
||||||
|
from PIL import ImageDraw as _ImageDraw
|
||||||
from utils import logs as _logs
|
from utils import logs as _logs
|
||||||
|
from bot_libs import syms as _bot_syms
|
||||||
|
|
||||||
|
|
||||||
class BrSimMap():
|
class BrSimMap():
|
||||||
@@ -11,13 +15,13 @@ class BrSimMap():
|
|||||||
self.world_width= 10 #seems a reasonable width for smartphones larger maps would go on a new line
|
self.world_width= 10 #seems a reasonable width for smartphones larger maps would go on a new line
|
||||||
self.world_height= 25
|
self.world_height= 25
|
||||||
self.game_map= []
|
self.game_map= []
|
||||||
self.field_sym= '🟩'
|
self.field_sym= _bot_syms.MAP_UTF8_FIELD
|
||||||
self.player_male_sym= '♂️'
|
self.player_male_sym= _bot_syms.MAP_UTF8_PLAYER_MALE
|
||||||
self.player_female_sym= '♀️'
|
self.player_female_sym= _bot_syms.MAP_UTF8_PLAYER_FEMALE
|
||||||
self.player_nonbinary_sym= '⚧️'
|
self.player_nonbinary_sym= _bot_syms.MAP_UTF8_PLAYER_NONBINARY
|
||||||
self.dead_player_sym= '💀'
|
self.dead_player_sym= _bot_syms.MAP_UTF8_DEATH_PLAYER
|
||||||
self.item_sym= '📦'
|
self.item_sym= _bot_syms.MAP_UTF8_ITEM
|
||||||
self.mountain_sym = '⛰️'
|
self.mountain_sym = _bot_syms.MAP_UTF8_MOUNTAIN
|
||||||
self.init_map_matrix()
|
self.init_map_matrix()
|
||||||
self.init_players_coordinates()
|
self.init_players_coordinates()
|
||||||
self.init_items_coordinates()
|
self.init_items_coordinates()
|
||||||
@@ -47,7 +51,8 @@ class BrSimMap():
|
|||||||
def populate_map(self):
|
def populate_map(self):
|
||||||
for player in self.players:
|
for player in self.players:
|
||||||
p_coord_x, p_coord_y= player.get_player_coordinates()
|
p_coord_x, p_coord_y= player.get_player_coordinates()
|
||||||
if player.player_gender_is_male(): self.game_map[p_coord_y][p_coord_x]= self.player_male_sym
|
if not player.is_alive(): self.game_map[p_coord_y][p_coord_x]= self.dead_player_sym
|
||||||
|
elif player.player_gender_is_male(): self.game_map[p_coord_y][p_coord_x]= self.player_male_sym
|
||||||
elif player.player_gender_is_female(): self.game_map[p_coord_y][p_coord_x]= self.player_female_sym
|
elif player.player_gender_is_female(): self.game_map[p_coord_y][p_coord_x]= self.player_female_sym
|
||||||
else: self.game_map[p_coord_y][p_coord_x]= self.player_nonbinary_sym
|
else: self.game_map[p_coord_y][p_coord_x]= self.player_nonbinary_sym
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
@@ -55,23 +60,19 @@ class BrSimMap():
|
|||||||
self.game_map[i_coord_y][i_coord_x]= self.item_sym
|
self.game_map[i_coord_y][i_coord_x]= self.item_sym
|
||||||
|
|
||||||
def _set_coordinates(self, target):
|
def _set_coordinates(self, target):
|
||||||
x= _random.randint(1, self.world_width -2) # -2 because 1 cell is occupied by the mountain
|
x= _random.randint(1, self.world_width -2) # from 1 to width-2 because 1 cell is occupied by the mountain
|
||||||
y= _random.randint(1, self.world_height -2)
|
y= _random.randint(1, self.world_height -2)
|
||||||
while self.get_map_matrix()[y][x] != self.field_sym:
|
while self.get_map_matrix()[y][x] != self.field_sym:
|
||||||
print('init_players_coordinates: collision, regenerate coordinates')
|
_logs.log_debug('_set_coordinates: collision, regenerate coordinates')
|
||||||
x= _random.randint(1, self.world_width -2)
|
x= _random.randint(1, self.world_width -2)
|
||||||
y= _random.randint(1, self.world_height -2)
|
y= _random.randint(1, self.world_height -2)
|
||||||
target.set_player_coordinates(x, y)
|
target.set_player_coordinates(x, y)
|
||||||
|
|
||||||
def init_players_coordinates(self):
|
def init_players_coordinates(self):
|
||||||
# XXX init random player.coord_x and player.coord_y (of course not already used coords)
|
|
||||||
# parse all self.players and define random coordinates (player.coord_x, and player.coord_y)
|
|
||||||
for player in self.players:
|
for player in self.players:
|
||||||
self._set_coordinates(target)
|
self._set_coordinates(player)
|
||||||
|
|
||||||
def init_items_coordinates(self):
|
def init_items_coordinates(self):
|
||||||
# XXX init random item.coord_x and item.coord_y (of course not already used coords)
|
|
||||||
# parse all self.items and define random coordinates (item.coord_x, and item.coord_y)
|
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
self._set_coordinates(item)
|
self._set_coordinates(item)
|
||||||
|
|
||||||
@@ -95,3 +96,53 @@ class BrSimMap():
|
|||||||
res+= x
|
res+= x
|
||||||
res+= '\n'
|
res+= '\n'
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def get_image_map(self):
|
||||||
|
self.populate_map()
|
||||||
|
scale_x= 20
|
||||||
|
scale_y= 20
|
||||||
|
final_x= self.world_width * scale_x
|
||||||
|
final_y= self.world_height * scale_y
|
||||||
|
image = _Image.new('RGB', (final_x, final_y))
|
||||||
|
draw = _ImageDraw.Draw(image)
|
||||||
|
|
||||||
|
for y in range(self.world_height):
|
||||||
|
for x in range(self.world_width):
|
||||||
|
pixel= self.game_map[y][x]
|
||||||
|
if pixel == self.field_sym:
|
||||||
|
pixel_color= _bot_syms.MAP_IMAGE_FIELD
|
||||||
|
elif pixel == self.mountain_sym:
|
||||||
|
pixel_color= _bot_syms.MAP_IMAGE_MOUNTAIN
|
||||||
|
elif pixel == self.item_sym:
|
||||||
|
pixel_color= _bot_syms.MAP_IMAGE_ITEM
|
||||||
|
elif pixel == self.player_male_sym:
|
||||||
|
pixel_color= _bot_syms.MAP_IMAGE_PLAYER_MALE
|
||||||
|
elif pixel == self.player_female_sym:
|
||||||
|
pixel_color= _bot_syms.MAP_IMAGE_PLAYER_FEMALE
|
||||||
|
elif pixel == self.player_nonbinary_sym:
|
||||||
|
pixel_color= _bot_syms.MAP_IMAGE_PLAYER_NONBINARY
|
||||||
|
elif pixel == self.dead_player_sym:
|
||||||
|
pixel_color= _bot_syms.MAP_IMAGE_DEATH_PLAYER
|
||||||
|
|
||||||
|
scaled_x_coord= x * scale_x
|
||||||
|
scaled_y_coord= y * scale_y
|
||||||
|
# if x == 1 distance from top-right is 20 (because everything is 20x bigger)
|
||||||
|
# then we want to draw a rectanghe 20x20 (instead of 1x1)
|
||||||
|
# this mean that if x == 1 (20px from top-right), x+1 == 2 (40px from top-right)
|
||||||
|
# the same for y
|
||||||
|
# this means that i keep the same factor proportions but 20x bigger
|
||||||
|
scaled_x_width= (x + 1) * scale_x
|
||||||
|
scaled_y_height= (y + 1) * scale_y
|
||||||
|
|
||||||
|
draw.rectangle([scaled_x_coord, scaled_y_coord, scaled_x_width, scaled_y_height],
|
||||||
|
fill= pixel_color
|
||||||
|
)
|
||||||
|
|
||||||
|
# debug
|
||||||
|
#image.save('/tmp/battle_royale_map.png')
|
||||||
|
#image.show()
|
||||||
|
|
||||||
|
bio = _io.BytesIO()
|
||||||
|
image.save(bio, 'PNG')
|
||||||
|
bio.seek(0)
|
||||||
|
return bio
|
||||||
|
|||||||
Reference in New Issue
Block a user