1
0

Compare commits

...

69 Commits

Author SHA256 Message Date
andrea
5002890540 debug random map generator 2025-07-28 20:08:15 +02:00
andrea
9653965d2b show players and items on the map 2025-07-28 20:03:08 +02:00
andrea
37578437f6 clear error message for missing local_settings.py 2025-07-28 18:55:33 +02:00
frostbite
9b503872e8 fixed code 2025-07-28 14:16:03 +02:00
frostbite
e604743796 added end of the map 2025-07-28 12:50:52 +02:00
frostbite
4dcb87723d added mountain icon 2025-07-28 12:20:21 +02:00
frostbite
5c3e349cb6 added icon dead player 2025-07-28 12:12:43 +02:00
andrea
5e6816269b define players and items coordinates to be used on the map 2025-07-27 23:34:35 +02:00
andrea
a7fd66e9e4 define Map class with basics rendering and parsing methods 2025-07-27 23:23:21 +02:00
andrea
172b387dcc fix duplicate logs 2025-07-27 09:10:09 +02:00
andrea
4639d85f00 better loggings but i need to fix a duplicate log line error 2025-07-27 08:56:40 +02:00
andrea
24f0f3e3e1 daily logs with a new file hanlder 2025-07-27 08:40:01 +02:00
andrea
0bfa74c0e2 cleanings to make code more compact and readable 2025-07-27 08:17:12 +02:00
andrea
c82f31a101 less logs 2025-07-27 00:07:20 +02:00
andrea
b9161a052f fix logs command 2025-07-27 00:06:59 +02:00
andrea
bd0601e115 better log name 2025-07-26 23:59:35 +02:00
andrea
bee2e94f82 item 2025-07-26 23:10:51 +02:00
andrea
da0368d6c5 fix loop requesting seconds 2025-07-26 22:41:24 +02:00
andrea
f8a3e12909 less logs lines 2025-07-26 22:33:56 +02:00
111e5e04df Update README.md 2025-07-26 22:13:36 +02:00
1a0422414c Update README.md 2025-07-26 22:11:59 +02:00
af70d30279 Update README.md 2025-07-26 22:10:40 +02:00
308107fdc7 Update README.md 2025-07-26 22:09:47 +02:00
7c6e7fb7b4 Update README.md 2025-07-26 22:09:29 +02:00
876c55522d Update README.md 2025-07-26 22:08:58 +02:00
76a14d69ce Update README.md 2025-07-26 22:08:02 +02:00
aa46acc812 Update README.md 2025-07-26 22:06:36 +02:00
c1c8301e11 Update README.md 2025-07-26 22:06:04 +02:00
andrea
269724345d show logs inside the telegram bot 2025-07-26 21:58:38 +02:00
andrea
a9cb58100f README 2025-07-26 21:32:52 +02:00
andrea
8f3d6dfaff explicit logs 2025-07-26 21:25:38 +02:00
andrea
460a6ccdec clean bot and fix autostop with scheduled game 2025-07-26 20:58:35 +02:00
andrea
2bf65583b7 cleanings 2025-07-26 20:34:15 +02:00
andrea
5e530e1af1 move upstart code 2025-07-26 19:44:45 +02:00
andrea
ffbaa1c3b5 more logs 2025-07-26 19:30:13 +02:00
andrea
72ec279036 better logs format 2025-07-26 19:24:45 +02:00
andrea
f55afe5959 logging info 2025-07-26 19:13:32 +02:00
andrea
669701dbb7 typo 2025-07-26 19:12:00 +02:00
andrea
9b538e7d2f fix 2025-07-26 19:11:26 +02:00
andrea
4d3dd5c781 fix binary path 2025-07-26 19:09:34 +02:00
andrea
a948db5af3 add logging lib 2025-07-26 19:04:17 +02:00
andrea
11e4f9b2dd upstart bot 2025-07-26 18:38:40 +02:00
andrea
56e5e35b53 upstart bot 2025-07-26 18:28:46 +02:00
f55a6a2cdb Merge pull request 'master' (#5) from green/battle_royale_sim:master into master
Reviewed-on: Cryz/battle_royale_sim#5
2025-07-26 18:07:53 +02:00
andrea
4729a45c30 player stats review and minor bot improvements 2025-07-26 18:07:14 +02:00
5a6810e948 merge upstream 2025-07-26 17:57:18 +02:00
31637dc845 ranking as commands or at the end of each day 2025-07-26 17:56:54 +02:00
andrea
079dcd6639 README 2025-07-26 17:17:21 +02:00
andrea
65688b9100 add random health, random damage and show full player stats with emoji 2025-07-26 15:53:26 +02:00
andrea
308c9e3602 use internal method to get the player's gender 2025-07-26 15:36:22 +02:00
andrea
871b3d2ab1 fix player random extraction number 2025-07-26 15:35:45 +02:00
andrea
5f0d6ad3f5 fix bug where a death player is killed multiple time during the same day 2025-07-26 15:31:28 +02:00
andrea
551c2ef8ef cleans 2025-07-26 15:25:27 +02:00
andrea
4ce19d1a50 add kills counter random agility for each player and random init players 2025-07-26 15:20:03 +02:00
andrea
67804a394d split main bot lib into multiple smaller libs and improve end game message 2025-07-26 14:44:16 +02:00
andrea
415cdfc123 Merge branch 'green-master' 2025-07-26 14:08:24 +02:00
9f745bd451 player reputation for sponsor and alliance 2025-07-26 13:52:08 +02:00
andrea
fe356864c8 debug daily events, now all players plays during a day 2025-07-26 12:52:55 +02:00
andrea
c5a6b886d6 allow multiple players insertion 2025-07-26 12:38:06 +02:00
andrea
a7c6dd25df show winner player and break loop game if you executed the periodically game 2025-07-26 11:52:01 +02:00
andrea
888f22ac1b show better names on telegram message 2025-07-26 11:22:55 +02:00
andrea
0a6deafd32 improve message and add periodically run 2025-07-26 11:15:44 +02:00
andrea
100bb4fe53 implement bot keyboard with basics commands 2025-07-26 11:00:20 +02:00
andrea
f360fe4200 move syms location 2025-07-26 10:13:20 +02:00
andrea
0df960ea22 split player commands from main bot 2025-07-26 10:04:19 +02:00
andrea
634c651cb5 typo fix and better players output 2025-07-26 09:46:04 +02:00
Crystal
07dd5611e5 fix missing message return, and immediate first message of the day 2025-07-26 00:06:29 +02:00
Crystal
09c892a786 unused imports 2025-07-25 23:57:25 +02:00
Crystal
3d2a0bcc70 telegram bot more commands, and use the debug function to start a first day iteration 2025-07-25 23:41:44 +02:00
19 changed files with 817 additions and 143 deletions

View File

@@ -1,3 +1,51 @@
# battle_royale_sim # Battle Royale Simulator (Hunger Games)
Hunger Games Simulator Hunger Games Simulator for telegram.
You can find the Official Bot here:
@Brsimgen_Bot - https://t.me/Brsimgen_Bot
Feel free to fork the project and make your own Bot
# Bot Instrictions
1. start a chat with the bot: https://t.me/Brsimgen_Bot
2. open the bot keyboard
3. Press button "Init/Restart" to initialize the world
4. now is time to add players (max players is 70):
- you can manually add new players with button "Add Player" then you'll need to insert the player name (or multiple names comma separated)
- test
5. Now you can start with the game simulation
- press "Simulate Day" to make time elapse till the end of the day, and watch what's happend during the day
- press "Run Periodically" to make the bot do everything, you only need to insert the periodicity of the scheduler: for example 30
now every day will automatically end in 30 seconds
6. you can always check the game status with the buttons:
- Get Players: (see all the players)
- Get Alive Players: (list of alive players)
- Get Death Players: (list of death players)
- Get Ranking Players: (this is the leaderboard, based on number of kills)
# Fork Instructions
if you want to fork this project
remember to create a file
`local_settings.py`
on the same folder of
`bot.py`
file
containing
```
TOKEN = 'your-bot-token'
BOT_PATH= '/the/path/of/the/project'
BOT_EXEC_CMD= 'python3 bot.py' # or any other way you start the bot
SUPER_USERS= [ your_chat_id ]
```

117
bot.py
View File

@@ -1,67 +1,90 @@
import asyncio from telegram.ext import Application
import datetime from telegram.ext import CommandHandler
import pytz from telegram.ext import MessageHandler
from telegram.ext import Application, CommandHandler, MessageHandler, filters from telegram.ext import filters
import bot_syms as _botsyms from telegram import ReplyKeyboardMarkup
import main as _brsim from telegram import ReplyKeyboardRemove
from utils import logs as _log
from entities import arena as _arena
from bot_libs import special_commands as _scmd
from bot_libs import syms as _botsyms
from bot_libs import commands_handling as _cmd
async def loop_game(context):
chat_id = context.job.chat_id
if 'arena' in context.application.bot_data:
print(f'{chat_id}: Guarino ha trovato l\'arena')
pass
else:
print('Arena non trovata')
await update.message.reply_text('Che e\' successo? un Guarino ha rubato l\'arena, avvia una nuova partita con /start')
async def bot_start(update, context): async def bot_start(update, context):
await update.message.reply_text(_botsyms.START_MSG) await update.message.reply_text(_botsyms.START_MSG)
if 'ask_name' in context.application.bot_data:
del(context.application.bot_data['ask_name'])
if 'ask_seconds' in context.application.bot_data:
del(context.application.bot_data['ask_seconds'])
keyboard = [
['Init/Restart'],
['Add Player', 'Add random Players', 'Add random color Players'],
['Get Players', 'Get Alive Players', 'Get Death Players', 'Get Ranking Players',],
['Simulate Day', 'Run Periodically']
]
reply_markup= ReplyKeyboardMarkup(keyboard, one_time_keyboard=False, resize_keyboard=True)
chat_id = update.effective_chat.id chat_id = update.effective_chat.id
print(f'{chat_id}: Sto costruendo il mondo di gioco...') _log.log_debug(f'bot_start: {chat_id} - I\'m building the world\'s game...')
Arena= _brsim.init_arena() Arena= _arena.BrSimArena()
players= Arena.get_players()
weapons= Arena.get_weapons()
print(f'Ecco il mondo di gioco, questi sono i giocatori: {players}')
print(f'Ecco le armi disponibili nel mondo: {weapons}')
await update.message.reply_text('Ho creato il mondo di gioco') await update.message.reply_text('Ho creato il mondo di gioco', reply_markup=reply_markup)
await update.message.reply_text(f'Ecco la lista degli sfortunati avventurieri:\n{players}')
await update.message.reply_text(f'Queste le armi che avranno a disposizione nell\'arena:\n{weapons}')
context.application.bot_data['arena'] = Arena context.application.bot_data['arena'] = Arena
async def bot_commands(update, context):
text= update.message.text
chat_id = update.effective_chat.id
_log.log_info(f'bot_command: {chat_id} - text received: {text}')
# init or restart the game
if text == 'Init/Restart':
return await bot_start(update, context)
#context.job_queue.run_repeating(loop_game, interval=10, first=0, chat_id= chat_id) # player game commands
timezone = pytz.timezone('Europe/Rome') if text == 'Add Player':
context.job_queue.run_daily( return await _cmd.cmd_add_player(context, update, chat_id)
loop_game, if text == 'Get Players':
time=datetime.time(hour=13, minute=0, second=0, tzinfo= timezone), return await _cmd.cmd_get_players(context, update, chat_id)
chat_id=chat_id, if text == 'Get Alive Players':
name=str(chat_id) return await _cmd.cmd_get_alive_players(context, update, chat_id)
) if text == 'Get Death Players':
print(f'Job giornaliero creato per la chat {chat_id}') return await _cmd.cmd_get_death_players(context, update, chat_id)
if text == 'Get Ranking Players':
return await _cmd.cmd_get_ranking_players(context, update, chat_id)
if text == 'Simulate Day':
return await _cmd.cmd_simulate_day(context, update, chat_id)
if text == 'Run Periodically':
return await _cmd.cmd_simulate_day_cron(context, update, chat_id)
if text == 'Add random Players':
return await _cmd.cmd_add_random_players(context, update, chat_id)
if text == 'Add random color Players':
return await _cmd.cmd_add_random_color_players(context, update, chat_id)
# special commands
if text == 'upstart': return await _scmd.update_bot(update, context)
if text == 'logs': return await _scmd.show_logs(update, context)
# get user input
if context.application.bot_data.get('ask_name'):
return await _cmd.cmd_get_player_name(context, update, chat_id, text)
if context.application.bot_data.get('ask_seconds'):
return await _cmd.cmd_get_cron_time(context, update, chat_id, text)
async def echo(update, context): _log.log_debug(f'bot_command: {chat_id} - sent this text: {text}')
testo_ricevuto = update.message.text
await update.message.reply_text(_botsyms.WIP_MSG) await update.message.reply_text(_botsyms.WIP_MSG)
async def add_player(update, context):
name= " ".join(context.args)
print(f'sto aggiungendo il giocatore {name} all\'arena')
_brsim.BrSimArena
Arena= context.application.bot_data['arena']
Arena.add_player(name)
print(f'Giocatori: {Arena.get_players()}')
await update.message.reply_text(f'Ecco i giocatori presenti nel mondo do gioco: \n{Arena.get_players()}')
def main(): def main():
application = Application.builder().token(_botsyms.TOKEN).build() application = Application.builder().token(_botsyms.TOKEN).build()
application.add_handler(CommandHandler('start', bot_start)) application.add_handler(CommandHandler('start', bot_start))
application.add_handler(CommandHandler('addplayer', add_player)) application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, bot_commands))
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
print('Bot in esecuzione...') _log.log_info('main: Bot is running...')
application.run_polling() application.run_polling()
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -0,0 +1,68 @@
from utils import logs as _log
from bot_libs import player_handling as _bot_player
from bot_libs import simulation as _bot_simulation
from bot_libs import repeating as _bot_repeat
### parse user input
async def _cmd_list_of_players(context, update, chat_id):
Arena= context.application.bot_data['arena']
players= [p.get_name_and_stats() for p in Arena.get_players()]
players_str= '\n'.join(players)
return await update.message.reply_text(f'Ecco i {len(players)} giocatori presenti nel mondo do gioco: \n{players_str}')
async def cmd_get_player_name(context, update, chat_id, text):
_log.log_info(f'cmd_get_player_name: {chat_id} - Collected Player Name {text}')
if not 'ask_name' in context.application.bot_data: return
del(context.application.bot_data['ask_name'])
players= text.split(',')
for player in players:
await _bot_player.add_player(update, context, chat_id, player.strip())
return await _cmd_list_of_players(context, update, chat_id)
async def cmd_get_cron_time(context, update, chat_id, text):
_log.log_info(f'cmd_get_cron_time: {chat_id} - User Wants to auto-run the game every {text} seconds')
try: text= int(text)
except: return
seconds= max(1, text)
if 'ask_seconds' in context.application.bot_data:
del(context.application.bot_data['ask_seconds'])
return await _bot_repeat.start_loop_game(update, context, seconds)
### basic commands handling
async def cmd_add_random_players(context, update, chat_id):
await _bot_player.add_random_players(update, context, chat_id, colors_names= False)
return await _cmd_list_of_players(context, update, chat_id)
async def cmd_add_random_color_players(context, update, chat_id):
await _bot_player.add_random_players(update, context, chat_id, colors_names= True)
return await _cmd_list_of_players(context, update, chat_id)
async def cmd_add_player(context, update, chat_id):
context.application.bot_data['ask_name'] = 1
if 'ask_seconds' in context.application.bot_data:
del(context.application.bot_data['ask_seconds'])
return await update.message.reply_text('Inserisci il Nome del giocatore (o piu\' nomi separati da virgola)')
async def cmd_get_players(context, update, chat_id):
return await _bot_player.get_players(update, context, chat_id)
async def cmd_get_alive_players(context, update, chat_id):
return await _bot_player.get_alive_players(update, context, chat_id)
async def cmd_get_death_players(context, update, chat_id):
return await _bot_player.get_death_players(update, context, chat_id)
async def cmd_get_ranking_players(context, update, chat_id):
return await _bot_player.get_ranking_players(update, context, chat_id)
async def cmd_simulate_day(context, update, chat_id):
return await _bot_simulation.simulate_day(context, chat_id)
async def cmd_simulate_day_cron(context, update, chat_id):
context.application.bot_data['ask_seconds'] = 1
if 'ask_name' in context.application.bot_data:
del(context.application.bot_data['ask_name'])
return await update.message.reply_text('Inserisci il numero di secondi, ad esempio \n(60 = 1 minuto)(600 = 10 minuti)\n(3600 = 1 ora)\n(86400 = 1 giorno)')

View File

@@ -0,0 +1,52 @@
import random as _rand
from utils import logs as _log
from bot_libs import syms as _bot_syms
async def add_player(update, context, chat_id, name):
_log.log_info(f'add_player: {chat_id} - {name}')
Arena= context.application.bot_data['arena']
if len(Arena.get_players()) >= 70: return # prevent message too long error
Arena.add_player(name)
async def add_random_players(update, context, chat_id, colors_names= False):
if colors_names: names= _bot_syms.COLORS_NAMES
else: names= _bot_syms.RANDOM_NAMES
max_players= len(names)
min_players= min(7, max_players)
players_num= _rand.randint(min_players, max_players)
_rand.shuffle(names)
lucky_players= _rand.sample(names, players_num)
_log.log_info(f'add_random_players: {chat_id} - extracting {players_num} random players for the game')
for name in lucky_players: await add_player(update, context, chat_id, name)
async def get_players(update, context, chat_id):
Arena= context.application.bot_data['arena']
players= [p.get_name_and_stats() for p in Arena.get_players()]
players_str= '\n'.join(players)
_log.log_info(f'get_players: {chat_id} - {players_str}')
await update.message.reply_text(f'Ecco i giocatori presenti nel mondo do gioco: \n{players_str}')
async def get_alive_players(update, context, chat_id):
Arena= context.application.bot_data['arena']
alive= [a.get_name_and_stats() for a in Arena.get_alive_players()]
alive_str= '\n'.join(alive)
_log.log_info(f'get_alive_players: {chat_id} - {alive_str}')
await update.message.reply_text(f'Ecco i giocatori ancora vivi: \n{alive_str}')
async def get_death_players(update, context, chat_id):
Arena= context.application.bot_data['arena']
death= [d.get_name_and_stats() for d in Arena.get_death_players()]
death_str= '\n'.join(death)
_log.log_info(f'get_death_players: {chat_id} - {death_str}')
await update.message.reply_text(f'Ecco i giocatori morti x.x: \n{death_str}')
async def get_ranking_players(update, context, chat_id):
Arena = context.application.bot_data['arena']
leaderboard_text = Arena.get_ranking()
_log.log_info(f'get_ranking_players: {chat_id} - {leaderboard_text}')
await update.message.reply_text(
f'{leaderboard_text}',
parse_mode='Markdown'
)

24
bot_libs/repeating.py Normal file
View File

@@ -0,0 +1,24 @@
from utils import logs as _log
from bot_libs import simulation as _bot_sim
async def _loop_game(context):
chat_id = context.job.chat_id
_log.log_info(f'_loop_game: {chat_id} - run game simulation day')
return await _bot_sim.simulate_day(context, chat_id)
async def start_loop_game(update, context, seconds):
await update.message.reply_text(f'Ok capo!! giochero\' per te ogni {seconds}s')
chat_id = update.effective_chat.id
if 'arena' not in context.application.bot_data:
_log.log_info(f'start_loop_game: {chat_id} - Arena not found')
await update.message.reply_text(f'Arena non trovata, avviare con /start')
return
Arena= context.application.bot_data['arena']
if len(Arena.get_players()) < 2:
_log.log_info(f'start_loop_game: {chat_id} - Not enough player to start the match')
await update.message.reply_text(f'Servono almeno 2 giocatori. Ecco i giocatori presenti nel mondo do gioco: \n{Arena.get_players()}')
return
context.job_queue.run_repeating(_loop_game, interval= seconds, first=1, chat_id= chat_id)
_log.log_info(f'start_loop_game: {chat_id} - Cron job started')

41
bot_libs/simulation.py Normal file
View File

@@ -0,0 +1,41 @@
import debug as _dbg
from utils import logs as _log
def get_winner(context, Arena, chat_id):
winner= Arena.get_alive_players()[0]
try:
context.job.schedule_removal()
_log.log_info(f'simulate_day: {chat_id} Loop removed')
except: pass
msg= f'{winner.get_name_and_stats()} Vince la cruenta battaglia '
msg+= f'uccidendo {winner.get_kills()} giocatori '
msg+= f'e schivando {winner.get_dodges()} colpi nemici, e vive felice e '
if winner.player_gender_is_male():
msg+= 'contento con Guarino'
elif winner.player_gender_is_female():
msg+= 'contenta con Guarino'
else:
msg+= 'content# con Guarino'
return msg
async def simulate_day(context, chat_id):
if 'arena' not in context.application.bot_data:
_log.log_info('simulate_day: {chat_id} Arena not Found')
await context.bot.send_message(chat_id, 'Che e\' successo? un Guarino ha rubato l\'arena, avvia una nuova partita con /start')
return
Arena= context.application.bot_data['arena']
if len(Arena.get_alive_players()) <= 1: return await context.bot.send_message(chat_id, 'Il gioco e\' finito, Grazie per aver giocato!')
await context.bot.send_message(chat_id, f'Giorno #{Arena.day}')
msg= _dbg.play_one_day_debug(Arena)
await context.bot.send_message(chat_id, msg)
#Print the ranking each day
msg= Arena.get_ranking()
await context.bot.send_message(chat_id, msg)
if len(Arena.get_alive_players()) == 1:
msg= get_winner(context, Arena, chat_id)
return await context.bot.send_message(chat_id, msg)

View File

@@ -0,0 +1,50 @@
import os as _os
from utils import logs as _log
from bot_libs import syms as _botsyms
async def _pull_repo(update):
err= _os.system(f'cd {_botsyms.BOT_PATH}; /usr/bin/git pull')
if err:
_log.log_error(f'update_bot: {chat_id} error {err} while trying to update the app')
await update.message.reply_text('Errore durante l\'aggiornamento del Bot')
return err
async def _upstart_service(update):
err= _os.system(_botsyms.BOT_EXEC_CMD)
# this error is fake, probably due to systemd restart that make the bot istance broke
#if err:
#_log.log_error(f'update_bot: {chat_id} error {err} while trying to upstart the app')
#return await update.message.reply_text('Errore durante il riavvio del Bot')
async def update_bot(update, context):
chat_id = update.effective_chat.id
if update.message.chat.id not in _botsyms.SUPER_USERS:
return _log.log_warning(f'update_bot: user {chat_id} not allowed')
await update.message.reply_text('Sto aggiornando il Bot...')
_log.log_info(f'update_bot: {chat_id} bot is updating...')
err= await _pull_repo(update)
if err: return
err= await _upstart_service(update)
if err: return
_log.log_info(f'update_bot: {chat_id} bot successfully updated')
await update.message.reply_text('Bot aggiornato e riavviato!')
async def show_logs(update, context):
chat_id = update.effective_chat.id
if update.message.chat.id not in _botsyms.SUPER_USERS:
return _log.log_warning(f'open_logs: user {chat_id} not allowed')
await update.message.reply_text('Sto provando ad aprire i log...')
_log.log_debug(f'open_logs: {chat_id} trying opening logs...')
try:
game_log= _os.path.expanduser(f'{_log.get_log_name()}')
with open(game_log, 'r') as _log_file:
lines= _log_file.readlines()[-30:]
log_content= '\n'.join(lines)
await update.message.reply_text(f"Contenuto del log:\n{log_content}")
except Exception as e:
await update.message.reply_text(f"Errore nella lettura del file di log: {str(e)}")

77
bot_libs/syms.py Normal file
View File

@@ -0,0 +1,77 @@
import os as _os
_MISSING_LOCAL_SETTINGS= """
=============== ERROR ===============
Missing local configurations:
create: local_settings.py
with these settings:
TOKEN= '<this_is_your_token_id>' # created using https://t.me/BotFather
BOT_PATH= '/path/of/your/repo/directory' # used for upstart command
LOG_PATH= '/path/where/you/place/logs' # used to save daily logs
BOT_EXEC_CMD= 'python /path/of/your/repo/directory/bot.py' # the command you use to launch the bot instance
SUPER_USERS= [<chat_id>] # this is the superuser, allowed to use special commands (upstart and logs)
=====================================
"""
try:
from local_settings import TOKEN as _token
TOKEN= _token
except: print(_MISSING_LOCAL_SETTINGS)
try:
from local_settings import BOT_PATH as _bot_path
BOT_PATH= _os.path.expanduser(_bot_path)
except: BOT_PATH= ''
try:
from local_settings import LOG_PATH as _log_path
LOG_PATH= _os.path.expanduser(_log_path)
except: LOG_PATH= '/tmp'
try:
from local_settings import BOT_EXEC_CMD as _bot_exec_cmd
BOT_EXEC_CMD= _bot_exec_cmd
except: BOT_EXEC_CMD= None
try:
from local_settings import SUPER_USERS as _superusers
SUPER_USERS= _superusers
except: SUPER_USERS= []
START_MSG= """Benvenuto nel crudele mondo di Battle Royal Simulator,
La tua avventura e quella dei tuoi compagni inizia qui.
Questo Bot simula Hunger Games,
Tu e i tuoi compagni, sarete catapultati in questo mondo,
ma solo 1 di voi riuscira' a salvarsi.
Uccidi o sarai tu ad essere ucciso
"""
WIP_MSG= "Ehi, mio padre mi sta ancora finendo di creare, abbi pazienza, che fretta hai di entrare in questo mondo per morire?"
RANDOM_NAMES = [
"Aeliana", "Thorne", "Kael", "Seraphine", "Jaxon", "Lyra", "Darius", "Elowen",
"Zander", "Nyssa", "Orion", "Vesper", "Kieran", "Isolde", "Riven", "Calista",
"Draven", "Mira", "Zephyr", "Selene", "Ashen", "Talia", "Finnian", "Aria",
"Kaelan", "Liora", "Soren", "Elara", "Thalia", "Jett", "Cressida", "Lucian",
"Freya", "Ronan", "Niamh", "Kellan", "Zara", "Dorian", "Amara", "Jace",
"Elysia", "Caius", "Sable", "Alaric", "Veda", "Quinn", "Thorne", "Lirael",
"Rhea", "Kade", "Isadora", "Ash", "Nyx", "Cassian", "Elowen", "Tamsin",
"Rylan", "Faye", "Jorah", "Sienna", "Kieran", "Astra", "Zane", "Lyric",
"Dax", "Ember", "Orion", "Selah", "Juno", "Kaia", "Thorne", "Vespera",
"Riven", "Caden", "Liora", "Soren", "Elara", "Talia", "Jett", "Freya",
"Ronan", "Niamh", "Kellan", "Zara", "Dorian", "Amara", "Jace", "Elysia",
"Caius", "Sable", "Alaric", "Veda", "Quinn", "Thorne", "Lirael", "Rhea",
"Kade", "Isadora", "Ash", "Nyx",
]
COLORS_NAMES= [
"Yellow", "Grey", "Violet", "Black", "Lime", "Ruby", "Avocado", "Crystal",
"Pink", "Maize", "Coral", "Jade", "Platinum", "Emerald", "Carmine", "Nickel",
"Chocolate", "Slate", "Turquoise", "Silver", "Teal", "Jet", "Ivory", "Cobalt",
"Vermillion", "Aero", "Orange", "Rhythm", "Amber", "Olive", "Sepia", "Cyan",
"Green", "Ochre", "Denim", "Erin", "Fuchsia", "Aqua", "Iceberg", "Blue",
"Canary", "Red", "Mint", "Scarlet", "Coffee", "Indigo", "Mystic", "Rose",
"Pearl", "Pumpkin", "Navy", "Ultramarine", "Sapphire", "Desert", "Cherry",
"Tulip",
]

View File

@@ -1,13 +0,0 @@
from local_settings import TOKEN as _token
TOKEN= _token
START_MSG= """Benvenuto nel crudele mondo di Battle Royal Simulator,
La tua avventura e quella dei tuoi compagni inizia qui.
Questo Bot simula Hunger Games,
Tu e i tuoi compagni, sarete catapultati in questo mondo,
ma solo 1 di voi riuscira' a salvarsi.
Uccidi o sarai tu ad essere ucciso
"""
WIP_MSG= "Ehi, mio padre mi sta ancora finendo di creare, abbi pazienza, che fretta hai di entrare in questo mondo per morire?"

View File

@@ -1,9 +1,8 @@
import time as _time import time as _time
import random as _rand import random as _rand
import main as _main import main as _main
from entities import weapon_syms as _wsyms
def init_debug(): def _debug_data():
players= [ players= [
{ {
'name': 'Elara', 'name': 'Elara',
@@ -24,14 +23,46 @@ def init_debug():
'name': 'Seraphina', 'name': 'Seraphina',
}, },
] ]
#w= _wsyms.KNIFE
##weapons= [{_wsyms.WEAPONS[w]['name' ]: 1}]
#weapons= [{w: 1}]
weapons= [] weapons= []
Arena= _main.init_arena(players, weapons) Arena= _main.init_arena(players, weapons)
print(f'Players: {Arena.get_players()}') print(f'Players: {Arena.get_players()}')
print(f'Weapons: {Arena.get_weapons()}') print(f'Weapons: {Arena.get_weapons()}')
return Arena
def _end_game_debug(alive_players, day):
last_player= alive_players[0]
msg= f'{last_player.get_name()} sopravvive e vince dopo {day} lunghi Giorni, conquistando l\'amore eterno di Guarino'
print(msg)
return msg
def play_one_day_debug(Arena):
if not Arena.get_players(): return
print(f'Giorno #{Arena.day}')
alive_players= Arena.get_alive_players()
if len(alive_players) == 1:
day= Arena.day
return _end_game_debug(alive_players, day)
daily_events= []
_rand.shuffle(alive_players)
for p_one in alive_players:
if not p_one.is_alive(): continue # he could be dead during this day cycle
p_two= _rand.sample(Arena.get_alive_players(), 1)[0]
while p_one.get_id() == p_two.get_id():
p_two= _rand.sample(Arena.get_alive_players(), 1)[0]
_dmg, msg= p_one.attack(p_two)
daily_events.append(msg)
Arena.next_day()
res= '\n'.join(daily_events)
return res
#p_one, p_two= _rand.sample(alive_players, 2)
#_dmg, msg= p_one.attack(p_two)
#return msg
def init_debug_loop():
Arena= _debug_data()
while (len(Arena.get_alive_players()) > 1): while (len(Arena.get_alive_players()) > 1):
alive_players= Arena.get_alive_players() alive_players= Arena.get_alive_players()
@@ -47,5 +78,12 @@ def init_debug():
last_player= Arena.get_alive_players()[0] last_player= Arena.get_alive_players()[0]
print(f'{last_player.get_name()} sopravvive e vince dopo {Arena.day} lunghi Giorni, conquistando l\'amore eterno di Guarino') print(f'{last_player.get_name()} sopravvive e vince dopo {Arena.day} lunghi Giorni, conquistando l\'amore eterno di Guarino')
def debug_random_map():
from entities import map as _map;
from entities import player;
M= _map.BrSimMap(players= [player.BrSimPlayer(i) for i in range(20)]);
res= M.get_renderized_map()
print(res)
if __name__ == '__main__': if __name__ == '__main__':
init_debug() init_debug()

View File

@@ -1,18 +1,27 @@
from entities import player as _player from entities import player as _player
from entities import weapons as _weapons
from entities import weapon_syms as _wsyms
from entities import event_picker as _events from entities import event_picker as _events
from entities.items import weapons as _weapons
class BrSimArena(): class BrSimArena():
# players = [{'name': name, 'inventory': default_inventory, other_stats}] # players = [{'name': name, 'inventory': default_inventory, other_stats}]
# weapons = [{WEAPON.KNIFE: quantity}, etc...] # this is the whole quantity of the items available on the world # weapons = [{WEAPON.KNIFE: quantity}, etc...] # this is the whole quantity of the items available on the world
def __init__(self, players, weapons): def __init__(self, players= None, weapons= None):
self.day= 1 self.day= 1
self.players= [_player.BrSimPlayer(p['name'], p.get('inventory')) for p in players] self.players= []
self.weapons= [] self.weapons= []
self.eventClass = _events.ArenaEventPicker(self.players) self.eventClass = _events.ArenaEventPicker(self.players)
self.init_players(players)
self.init_weapons(weapons)
def init_players(self, players):
if not players: return
for player in players:
self.add_player(player['name'], player.get('inventory'))
def init_weapons(self, weapons):
if not weapons: return
for weapon in weapons: for weapon in weapons:
for wtype, quantity in weapon.items(): for wtype, quantity in weapon.items():
for i in range(quantity): self.weapons.append(_weapons.BrSimWeapon(wtype)) for i in range(quantity): self.weapons.append(_weapons.BrSimWeapon(wtype))
@@ -41,6 +50,54 @@ class BrSimArena():
res.append(p) res.append(p)
return res return res
def sort_players_by_kills_and_health(self, players):
def player_sort_key(player):
kills= player.get_kills()
health= player.get_health()
#Negative values to sort in decr mode
return (-kills, -health)
return sorted(players, key=player_sort_key)
def get_ranking(self):
medals = ['🥇', '🥈', '🥉']
leaderboard = []
leaderboard.append('🏆 *Classifica attuale:* \n')
alive_players= self.get_alive_players();
alive_sorted= self.sort_players_by_kills_and_health(alive_players)
death_players= self.get_death_players()
death_sorted= self.sort_players_by_kills_and_health(death_players)
# Alive Players
alive_players= self.get_alive_players();
alive_sorted= self.sort_players_by_kills_and_health(alive_players)
for index, player in enumerate(alive_sorted):
name = player.get_name()
kills = player.get_kills()
health = '♥️' * player.get_health()
if index < 3:
position = medals[index]
else:
position = f"{index + 1}."
line = f"{position} {name} - {kills} uccision{'i' if kills != 1 else 'e'}, {health}"
leaderboard.append(line)
# Death players:
death_players= self.get_death_players()
death_sorted= self.sort_players_by_kills_and_health(death_players)
if death_sorted:
leaderboard.append("\n-- GIOCATORI ELIMINATI --")
for player in death_sorted:
name = player.get_name()
kills = player.get_kills()
health = player.get_health()
line = f"💀 {name} - {kills} uccision{'i' if kills != 1 else 'e'}"
leaderboard.append(line)
return '\n'.join(leaderboard)
def do_random_event(self): def do_random_event(self):
#XXX random player does random action according to his inventory health, wounds, available weapons on the world, etc... #XXX random player does random action according to his inventory health, wounds, available weapons on the world, etc...
pass pass
@@ -54,11 +111,12 @@ class BrSimArena():
player= _player.BrSimPlayer(name, inventory) player= _player.BrSimPlayer(name, inventory)
self.players.append(player) self.players.append(player)
def add_weapon(self, weapon_type):
weapon= _weapons.BrSimWeapon(weapon_type)
self.weapons.append(weapon)
def get_players(self): def get_players(self):
res= [] return self.players
for p in self.players:
res.append(p.get_data())
return res
def get_weapons(self): def get_weapons(self):
res= [] res= []

29
entities/items/item.py Normal file
View File

@@ -0,0 +1,29 @@
import random as _random
class BrSimItem():
def __init__(self):
self.coord_x= 0
self.coord_y= 0
def get_name(self):
return self.name
def get_item_type(self):
return self.item_type
def get_weight(self):
return self.weight
def is_weapon(self):
return False
def is_cure(self):
return False
def get_item_coordinates(self):
return self.coord_x, self.coord_y
def set_item_coordinates(self, x, y):
self.coord_x= x
self.coord_y= y

View File

@@ -1,6 +1,5 @@
KNIFE= 1 KNIFE= 1
GUN= 2 ARCH= 2
BOMB= 3
SHORT_RANGE= 1 SHORT_RANGE= 1
FAR_RANGE= 2 FAR_RANGE= 2
@@ -14,7 +13,7 @@ WEAPONS= {
'ammons': -1, # -1, no limit 'ammons': -1, # -1, no limit
'range': SHORT_RANGE, 'range': SHORT_RANGE,
}, },
GUN: { ARCH: {
'weight': 2, 'weight': 2,
'name': 'gun', 'name': 'gun',
'damage': 3, 'damage': 3,
@@ -22,12 +21,4 @@ WEAPONS= {
'ammons': 10, # -1, no limit 'ammons': 10, # -1, no limit
'range': FAR_RANGE, 'range': FAR_RANGE,
}, },
BOMB: {
'weight': 2,
'name': 'bomb',
'damage': 10,
'miss_chance': 5, # from 0 to 100, this is the probably to miss the hit
'ammons': 1,
'range': FAR_RANGE,
},
} }

View File

@@ -1,10 +1,11 @@
import random as _random import random as _random
from entities import weapon_syms as _syms from entities.items import item as _item
from entities.items import weapon_syms as _syms
class BrSimWeapon(): class BrSimWeapon(_item.BrSimItem):
def __init__(self, wtype): def __init__(self, wtype= None):
self.weapon= _syms.WEAPONS[wtype] self.weapon= _syms.WEAPONS[wtype or _random.randint(1,2)]
self.name= self.weapon['name'] self.name= self.weapon['name']
self.damage= self.weapon['damage'] self.damage= self.weapon['damage']
self.weight= self.weapon['weight'] self.weight= self.weapon['weight']

91
entities/map.py Normal file
View File

@@ -0,0 +1,91 @@
import random as _random
import copy as _copy
from utils import logs as _logs
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= 25
self.game_map= []
self.field_sym= '🟩'
self.player_male_sym= '♂️'
self.player_female_sym= '♀️'
self.player_nonbinary_sym= '⚧️'
self.dead_player_sym= '💀'
self.item_sym= '📦'
self.mountain_sym = '⛰️'
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)
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))
_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_player_coordinates()
if 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_item_coordinates()
self.game_map[i_coord_y][i_coord_x]= self.item_sym
def get_map_matrix(self):
return self.game_map
def get_renderized_map(self):
res= ''
game_map= self.get_map_matrix()
for y in game_map:
for x in y:
res+= x
res+= '\n'
return res
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:
x= _random.randint(1, self.world_width -2) # -2 because 1 cell is occupied by the mountain
y= _random.randint(1, self.world_height -2)
while self.get_map_matrix()[y][x] != self.field_sym:
print('init_players_coordinates: collision, regenerate coordinates')
x= _random.randint(1, self.world_width -2)
y= _random.randint(1, self.world_height -2)
player.set_player_coordinates(x, y)
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:
x= _random.randint(1, self.world_width -2) # -2 because 1 cell is occupied by the mountain
y= _random.randint(1, self.world_height -2)
while self.get_map_matrix()[y][x] != self.field_sym:
print('init_items_coordinates: collision, regenerate coordinates')
x= _random.randint(1, self.world_width -2)
y= _random.randint(1, self.world_height -2)
item.set_item_coordinates(x, y)

View File

@@ -6,18 +6,41 @@ class BrSimPlayer():
def __init__(self, name, inventory= None): def __init__(self, name, inventory= None):
self.id= str(_uuid.uuid4()) self.id= str(_uuid.uuid4())
self.name= name self.name= name
self.health= 1 self.stats= ''
self.health= _random.randint(1,3)
self.inventory= inventory or [] self.inventory= inventory or []
self.damage= 1 # this is the punch damage amount self.damage= _random.randint(1,2) # this is the punch damage amount
self.max_weight= 5 # this is the max inventory weight self.max_weight= 5 # this is the max inventory weight
self.agility= 10 # chance to avoid an hit self.agility= _random.randint(1,3) # chance to avoid an hit
self.kills= 0 # track the number of kills self.kills= 0 # track the number of kills
self.accused_damage= 0
self.survived_days= 0 # track the number of the survived days self.survived_days= 0 # track the number of the survived days
self.dodges= 0
self.equipped_weapon= None self.equipped_weapon= None
self.gender= _random.sample(['m', 'f', '-'], 1)[0] # for now get a random gender self.gender= _random.sample(['m', 'f', '-'], 1)[0] # for now get a random gender
self.reputation= 50 #Like RDR2 the player can be evil(0) or good(100). This should influence the sponsors and internal alliance
self.coord_x= 0
self.coord_y= 0
### control methods ### control methods
def get_player_coordinates(self):
return self.coord_x, self.coord_y
def set_player_coordinates(self, x, y):
self.coord_x= x
self.coord_y= y
def get_name_and_stats(self):
health= '♥️' * self.health or '☠️'
strength= '⚔️' * self.damage
agility= '🚀' * self.agility
if self.player_gender_is_male(): gender= ''
elif self.player_gender_is_female(): gender= ''
else: gender= ''
name= f'{self.name} {gender} {health} {strength} {agility}'
return name
def get_id(self): def get_id(self):
return self.id return self.id
@@ -27,98 +50,131 @@ class BrSimPlayer():
def get_gender(self): def get_gender(self):
return self.gender return self.gender
def player_gender_is_male(self):
return self.gender == 'm'
def player_gender_is_female(self):
return self.gender == 'f'
def player_gender_is_not_binary(self):
return self.gender == '-'
def get_inventory(self): def get_inventory(self):
return self.inventory return self.inventory
def get_inventory_weight(self): def get_inventory_weight(self):
weight= 0 weight= 0
for inv in self.get_inventory(): for item in self.get_inventory():
weight+= inv.get_weight() weight+= item.get_weight()
return weight return weight
def get_dodges(self):
return self.dodges
def get_max_weight(self): def get_max_weight(self):
return self.max_weight return self.max_weight
def get_health(self): def get_health(self):
return self.health return self.health
def get_equipped_weapon(self):
return self.equipped_weapon
def get_damage(self): def get_damage(self):
if not self.equipped_weapon: return self.damage weapon= self.get_equipped_weapon()
return self.equipped_weapon.damage if not weapon: return self.damage
return weapon.get_damage()
def get_agility(self): def get_agility(self):
return self.agility return self.agility
def get_reputation(self):
return self.reputation
def get_data(self): def get_data(self):
return { return {
'id': self.get_id(), 'id': self.get_id(),
'name': self.get_name(), 'name': self.get_name(),
'name_stats': self.get_name_and_stats(),
'gender': self.get_gender(), 'gender': self.get_gender(),
'inventory': self.get_inventory(), 'inventory': self.get_inventory(),
'inventory_weight': self.get_inventory_weight(), 'inventory_weight': self.get_inventory_weight(),
'health': self.get_health(), 'health': self.get_health(),
'damage': self.get_damage(), 'damage': self.get_damage(),
'agility': self.get_agility(), 'agility': self.get_agility(),
'reputation': self.get_reputation(),
} }
def is_alive(self): def is_alive(self):
return self.health > 0 return self.health > 0
def get_kills(self):
return self.kills
### player actions ### player actions
def _equip_weapon(self): def _equip_weapon(self):
if not self.inventory: return if not self.inventory: return
available_weapons= [] available_weapons= []
for inv in self.get_inventory(): for item in self.get_inventory():
# XXX # XXX
# i don't know yet if this is ok, # i don't know yet if this is ok,
# we'll see it when weapon and items are defined # we'll see it when weapon and items are defined
if not inv.damage: continue # maybe we need item.is_weapon() method
available_weapons.append(inv) if not item.damage: continue
available_weapons.append(item)
self.equipped_weapon= random.sample(available_weapons, 1)[0] self.equipped_weapon= random.sample(available_weapons, 1)[0]
def dodge(self): def dodge(self):
# maybe depend on the attack, if it is a gun shot it's quite impossible to dodge # maybe depend on the attack, if it is a gun shot it's quite impossible to dodge
rnd= _random.randint(0, 100) rnd= _random.randint(0, 10)
if rnd < self.agility: return True if rnd < self.agility:
self.dodges+= 1
return True
return False return False
def accuses_damage(self, damage): def accuses_damage(self, damage):
self.health -= damage self.health-= damage
self.accused_damage+= damage
if self.health > 0: return self.get_health() if self.health > 0: return self.get_health()
self.health = 0 self.health= 0
if self.get_gender() == 'm': if self.player_gender_is_male():
print(f'[{self.get_name()}]: Guarino, perdonami se sono morto x.x') print(f'[{self.get_name_and_stats()}]: Guarino, perdonami se sono morto x.x')
elif self.get_gender() == 'f': elif self.player_gender_is_female():
print(f'[{self.get_name()}]: Guarino, perdonami se sono morta x.x') print(f'[{self.get_name_and_stats()}]: Guarino, perdonami se sono morta x.x')
else: else:
print(f'[{self.get_name()}]: Guarino, perdonami se sono mort* x.x') print(f'[{self.get_name_and_stats()}]: Guarino, perdonami se sono mort* x.x')
return damage return damage
def attack(self, target): def attack(self, target):
self._equip_weapon() self._equip_weapon()
if target.dodge(): if target.dodge():
if target.get_gender() == 'm': if target.player_gender_is_male():
print(f'Ehhhh voleviiii!!! sei lentoo! {target.get_name()} schiva il colpo di {self.get_name()}') msg= f'Ehhhh voleviiii!!! sei lentoo! {target.get_name_and_stats()} schiva il colpo di {self.get_name_and_stats()}'
elif target.get_gender() == 'f': elif target.player_gender_is_female():
print(f'Ehhhh voleviiii!!! sei lentaa! {target.get_name()} schiva il colpo di {self.get_name()}') msg= f'Ehhhh voleviiii!!! sei lentaa! {target.get_name_and_stats()} schiva il colpo di {self.get_name_and_stats()}'
else: else:
print(f'Ehhhh voleviiii!!! sei lent##! {target.get_name()} schiva il colpo di {self.get_name()}') msg= f'Ehhhh voleviiii!!! sei lent##! {target.get_name_and_stats()} schiva il colpo di {self.get_name_and_stats()}'
return 0 return 0, msg
target.accuses_damage(self.damage) target.accuses_damage(self.damage)
print(f'{self.get_name()} Colpisce {target.get_name()} in nome di Guarino')
return self.damage msg= f'{self.get_name_and_stats()} Colpisce {target.get_name_and_stats()}'
weapon= self.get_equipped_weapon()
if weapon: msg+= f' con un {weapon.get_name}'
else: msg+= f' con un pugno'
self.kills+= 1
return self.damage, msg
def get_item(self, item): def get_item(self, item):
if self.get_inventory_weight() + item.get_weight() >= self.get_max_weight(): if self.get_inventory_weight() + item.get_weight() >= self.get_max_weight():
if self.get_gender() == 'm': if self.player_gender_is_male():
print(f'Sono sovraccarico, {self.get_name} non puo\' prendere questo oggetto') print(f'Sono sovraccarico, {self.get_name_and_stats} non puo\' prendere questo oggetto')
elif self.get_gender() == 'f': elif self.player_gender_is_female():
print(f'Sono sovraccarica, {self.get_name} non puo\' prendere questo oggetto') print(f'Sono sovraccarica, {self.get_name_and_stats} non puo\' prendere questo oggetto')
else: else:
print(f'Sono sovraccaric#, {self.get_name} non puo\' prendere questo oggetto') print(f'Sono sovraccaric#, {self.get_name_and_stats} non puo\' prendere questo oggetto')
return False return False
self.inventory.append(item) self.inventory.append(item)

21
main.py
View File

@@ -1,27 +1,8 @@
import random as _random
from entities import weapon_syms as _wsyms
from entities import arena as _arena from entities import arena as _arena
def init_arena(players, weapons): def init_arena(players= None, weapons= None):
return _arena.BrSimArena(players, weapons) return _arena.BrSimArena(players, weapons)
def run_events(Arena): def run_events(Arena):
#A event for each player: #A event for each player:
pass pass
def local_debug():
players= [{'name': 'Crystal'}, {'name': 'Andrea'}, {'name' : 'giampi'}]
w= _wsyms.KNIFE
#weapons= [{_wsyms.WEAPONS[w]['name' ]: 1}]
weapons= [{w: 1}]
Arena= init_arena(players, weapons)
print(f'Players: {Arena.get_players()}')
print(f'Weapons: {Arena.get_weapons()}')
while (len(Arena.get_alive_players()) > 1):
#Start a day
run_events(Arena)
#At 23:59:
Arena.next_day()
#End of day

View File

@@ -1,2 +1 @@
python-telegram-bot[job-queue]==22.3 python-telegram-bot[job-queue]==22.3
pytz==2025.2

60
utils/logs.py Normal file
View File

@@ -0,0 +1,60 @@
import os as _os
import logging as _logging
from datetime import datetime as _dt
from bot_libs import syms as _bot_syms
logger= _logging.getLogger(__name__)
file_handler= None
def get_log_name():
now= _dt.now()
year= now.year
month= now.month
if month < 10: month= f'0{month}'
day= now.day
if day < 10: day= f'0{day}'
fname= f'battle_royale-{now.year}{month}{day}.log'
return _os.path.join(_bot_syms.LOG_PATH, fname)
def _create_file_handler():
global file_handler
print('### create file handler')
current_log_file = get_log_name()
file_handler = _logging.FileHandler(current_log_file, encoding='utf-8')
formatter = _logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.setLevel(_logging.INFO)
return file_handler
def _setup_logging_file():
print('### setup logging')
current_log_file = get_log_name()
if not file_handler: return _create_file_handler()
if file_handler.baseFilename == _os.path.abspath(current_log_file): return
logger.removeHandler(file_handler)
file_handler.close()
_create_file_handler()
def log_debug(txt):
_setup_logging_file()
logger.debug(txt)
def log_info(txt):
_setup_logging_file()
logger.info(txt)
def log_warning(txt):
_setup_logging_file()
logger.warning(txt)
def log_error(txt):
_setup_logging_file()
logger.error(txt)
def log_critical(txt):
_setup_logging_file()
logger.critical(txt)