Files
battle_royale_sim/entities/gamemap.py

168 lines
6.2 KiB
Python

import random as _random
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 bot_libs import syms as _bot_syms
from entities import resource as _resource
class BrSimMap():
def __init__(self, players= None, items= None):
self.players= players or []
self.items= items or []
self.world_width= 10 #seems a reasonable width for smartphones larger maps would go on a new line
self.world_height= 10
self.game_map= []
self.field_sym= _bot_syms.MAP_UTF8_FIELD
self.player_male_sym= _bot_syms.MAP_UTF8_PLAYER_MALE
self.player_female_sym= _bot_syms.MAP_UTF8_PLAYER_FEMALE
self.player_nonbinary_sym= _bot_syms.MAP_UTF8_PLAYER_NONBINARY
self.dead_player_sym= _bot_syms.MAP_UTF8_DEATH_PLAYER
self.item_sym= _bot_syms.MAP_UTF8_ITEM
self.mountain_sym = _bot_syms.MAP_UTF8_MOUNTAIN
self.init_map_matrix()
self.init_players_coordinates()
self.init_items_coordinates()
self.populate_map()
def init_map_matrix(self):
# show a matrix representing the game's map
# 🟩 is and empty cell
# (tomorrow we can choose different colors for different locations
# 🟠 this is a player (we could use different colors for different genders)
# 📦 this is an item (weapon or another item)
# 💀 this is icon when the player is dead
# ⛰️ this is icon for the mountain (We can prevent players from passing through the mountains and thus use them for map boundaries.)
width= []
#mon = []
#for i in range(self.world_width):
#mon.append(self.mountain_sym)
for i in range(self.world_width):
#if i == 0 or i == self.world_width - 1: width.append(self.mountain_sym)
#else: width.append(self.field_sym)
width.append(None)
#width.append(self.field_sym)
for i in range(self.world_height):
#if i == 0 or i == self.world_height - 1: self.game_map.append(mon)
#else: self.game_map.append(_copy.deepcopy(width))
self.game_map.append(_copy.deepcopy(width))
_logs.log_debug(f'init_map_matrix: {self.game_map}')
def populate_map(self):
for player in self.players:
p_coord_x, p_coord_y= player.get_coordinates()
self.game_map[p_coord_y][p_coord_x]= player
#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
#else: self.game_map[p_coord_y][p_coord_x]= self.player_nonbinary_sym
for item in self.items:
i_coord_x, i_coord_y= item.get_coordinates()
self.game_map[p_coord_y][p_coord_x]= item
#self.game_map[i_coord_y][i_coord_x]= self.item_sym
def _set_coordinates(self, target):
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)
resource= self.get_map_matrix()[y][x]
while resource:
#while self.get_map_matrix()[y][x] != self.field_sym:
_logs.log_debug('_set_coordinates: collision, regenerate coordinates')
x= _random.randint(1, self.world_width -2)
y= _random.randint(1, self.world_height -2)
target.set_coordinates(x, y)
def init_players_coordinates(self):
for player in self.players:
self._set_coordinates(player)
def init_items_coordinates(self):
for item in self.items:
self._set_coordinates(item)
def add_player_to_map(self, player):
self.players.append(player)
self._set_coordinates(player)
def add_item_to_map(self, item):
self.items.append(item)
self._set_coordinates(item)
def get_map_matrix(self):
return self.game_map
def get_renderized_map(self):
res= ''
self.populate_map()
game_map= self.get_map_matrix()
for y in game_map:
for x in y:
if not x: el= self.field_sym
#XXX how to manage mountains?
elif x.is_player():
if x.player_gender_is_male(): el= self.player_male_sym
elif x.player_gender_is_female(): el= self.player_female_sym
else: el= self.player_nonbinary_sym
elif x.is_item():
el= self.item_sym
res+= el
res+= '\n'
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)
outline= '#000000'
for y in range(self.world_height):
for x in range(self.world_width):
resource= self.game_map[y][x]
if not resource:
pixel_color= _bot_syms.MAP_IMAGE_FIELD
# XXX how to manage mountains? maybe another class?
#elif resource == self.mountain_sym:
#pixel_color= _bot_syms.MAP_IMAGE_MOUNTAIN
elif resource.is_item():
pixel_color= _bot_syms.MAP_IMAGE_ITEM
elif resource.is_player():
if not resource.is_alive():
pixel_color= _bot_syms.MAP_IMAGE_DEATH_PLAYER
elif resource.player_gender_is_male():
pixel_color= _bot_syms.MAP_IMAGE_PLAYER_MALE
elif resource.player_gender_is_female():
pixel_color= _bot_syms.MAP_IMAGE_PLAYER_FEMALE
elif resource.player_gender_is_not_binary():
pixel_color= _bot_syms.MAP_IMAGE_PLAYER_NONBINARY
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, outline= outline
)
# debug
#image.save('/tmp/battle_royale_map.png')
#image.show()
bio = _io.BytesIO()
image.save(bio, 'PNG')
bio.seek(0)
return bio