1
0

Compare commits

..

13 Commits

Author SHA256 Message Date
Crystal
b12db42c0b more players 2025-07-24 23:07:33 +02:00
5986e0f880 initial event picker idea 2025-07-24 23:00:34 +02:00
Crystal
0bb2c840f9 lgbtq+ texts 2025-07-24 22:58:46 +02:00
526668ed5d initial event picker idea 2025-07-24 22:57:28 +02:00
Crystal
1c284bad97 basic player entity and debug module to quickly test player attack 2025-07-24 22:36:36 +02:00
Crystal
761cf794b4 fix requirements for job-queue 2025-07-24 21:36:34 +02:00
andrea
f193464006 bot reframe, based on local_settings TOKEN, and periodic run 2025-07-24 21:28:42 +02:00
andrea
c5a6f4ea36 syntax bugfix 2025-07-24 21:27:36 +02:00
andrea
5a672b336f requirements 2025-07-24 19:18:43 +02:00
andrea
05d1718775 is_alive() is now based on player's health instead of a dedicated state 2025-07-24 19:16:30 +02:00
e66a6fbd9c Merge pull request 'master' (#3) from frostbite/battle_royale_sim:master into master
Reviewed-on: Cryz/battle_royale_sim#3
2025-07-24 19:11:17 +02:00
0098861e54 Merge pull request 'arena as class' (#2) from green/battle_royale_sim:master into master
Reviewed-on: Cryz/battle_royale_sim#2
2025-07-24 16:38:56 +02:00
db86f3dd06 arena as class 2025-07-24 16:08:06 +02:00
9 changed files with 278 additions and 122 deletions

14
assets/events.py Normal file
View File

@@ -0,0 +1,14 @@
EVENTS = [
{
'id' : 'ATTACK',
'text' : '{Player1} ha attacato {player2}',
'resolve_text' : '{Player1} ha causato {effetto_collaterale}',
'fail_text' : '{Player1} ha fallito, {player2} è indenne',
'success_percentage' : 80,
'fail_percentage' : 19,
'extreme_fail_percentage' : 1,
'required_items' : [],
'weight' : 1,
'number_of_players' : 2,
},
]

21
bot.py
View File

@@ -1,19 +1,20 @@
import asyncio import asyncio
import datetime import datetime
from telegram import Update import pytz
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes from telegram.ext import Application, CommandHandler, MessageHandler, filters
import bot_syms as _botsyms import bot_syms as _botsyms
import main as _brsim import main as _brsim
async def loop_game(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def loop_game(context):
chat_id = update.effective_chat.id chat_id = context.job.chat_id
if 'arena' in context.application.bot_data: if 'arena' in context.application.bot_data:
print(f'{chat_id}: Guarino ha trovato l\'arena')
pass pass
else: else:
print('Arena non trovata') print('Arena non trovata')
await update.message.reply_text('Che e\' successo? un Guarino ha rubato l\'arena, avvia una nuova partita con /start') 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: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def bot_start(update, context):
await update.message.reply_text(_botsyms.START_MSG) await update.message.reply_text(_botsyms.START_MSG)
chat_id = update.effective_chat.id chat_id = update.effective_chat.id
@@ -28,20 +29,22 @@ async def bot_start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.message.reply_text(f'Ecco la lista degli sfortunati avventurieri:\n{players}') 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}') 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
#context.job_queue.run_repeating(loop_game, interval=10, first=0, chat_id= chat_id)
timezone = pytz.timezone('Europe/Rome')
context.job_queue.run_daily( context.job_queue.run_daily(
loop_game, loop_game,
time=datetime.time(hour=0, minute=0, second=5, tzinfo=datetime.timezone.utc), time=datetime.time(hour=13, minute=0, second=0, tzinfo= timezone),
chat_id=chat_id, chat_id=chat_id,
name=str(chat_id) name=str(chat_id)
) )
print(f'Job giornaliero creato per la chat {chat_id}') print(f'Job giornaliero creato per la chat {chat_id}')
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def echo(update, context):
testo_ricevuto = update.message.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: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def add_player(update, context):
name= " ".join(context.args) name= " ".join(context.args)
print(f'sto aggiungendo il giocatore {name} all\'arena') print(f'sto aggiungendo il giocatore {name} all\'arena')
_brsim.BrSimArena _brsim.BrSimArena

View File

@@ -1,4 +1,6 @@
TOKEN = "7670066927:AAG8jI5n9NcyxPksYky7LPYqA08BThs07c4" from local_settings import TOKEN as _token
TOKEN= _token
START_MSG= """Benvenuto nel crudele mondo di Battle Royal Simulator, START_MSG= """Benvenuto nel crudele mondo di Battle Royal Simulator,
La tua avventura e quella dei tuoi compagni inizia qui. La tua avventura e quella dei tuoi compagni inizia qui.

51
debug.py Normal file
View File

@@ -0,0 +1,51 @@
import time as _time
import random as _rand
import main as _main
from entities import weapon_syms as _wsyms
def init_debug():
players= [
{
'name': 'Elara',
},
{
'name': 'Kaelen',
},
{
'name': 'Zephyr',
},
{
'name': 'Lyra',
},
{
'name': 'Orion',
},
{
'name': 'Seraphina',
},
]
#w= _wsyms.KNIFE
##weapons= [{_wsyms.WEAPONS[w]['name' ]: 1}]
#weapons= [{w: 1}]
weapons= []
Arena= _main.init_arena(players, weapons)
print(f'Players: {Arena.get_players()}')
print(f'Weapons: {Arena.get_weapons()}')
while (len(Arena.get_alive_players()) > 1):
alive_players= Arena.get_alive_players()
p_one, p_two= _rand.sample(alive_players, 2)
p_one.attack(p_two)
#Start a day
#At 23:59:
Arena.next_day()
_time.sleep(0.3)
#End of day
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')
if __name__ == '__main__':
init_debug()

68
entities/arena.py Normal file
View File

@@ -0,0 +1,68 @@
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
class BrSimArena():
# 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
def __init__(self, players, weapons):
self.day= 1
self.players= [_player.BrSimPlayer(p['name'], p.get('inventory')) for p in players]
self.weapons= []
self.eventClass = _events.ArenaEventPicker(self.players)
for weapon in weapons:
for wtype, quantity in weapon.items():
for i in range(quantity): self.weapons.append(_weapons.BrSimWeapon(wtype))
def next_day(self):
self.day+= 1
print(f'Giorno: {self.day}')
alive_players_str= ', '.join([p.get_name() for p in self.get_alive_players()])
print(f'Giocatori vivi: {alive_players_str}')
death_players= self.get_death_players()
if (death_players):
death_players_str= ', '.join([p.get_name() for p in death_players])
print(f'Giocatori morti: {death_players_str}')
def get_alive_players(self):
res= []
for p in self.players:
if not p.is_alive(): continue
res.append(p)
return res
def get_death_players(self):
res= []
for p in self.players:
if p.is_alive(): continue
res.append(p)
return res
def do_random_event(self):
#XXX random player does random action according to his inventory health, wounds, available weapons on the world, etc...
pass
def supporter_donation(self):
#XXX supporter donate a random item or weapon to a random player
#TODO maybe in future a player can have charism stats that can influence the chance to get a donation
pass
def add_player(self, name, inventory= None):
player= _player.BrSimPlayer(name, inventory)
self.players.append(player)
def get_players(self):
res= []
for p in self.players:
res.append(p.get_data())
return res
def get_weapons(self):
res= []
for w in self.weapons:
#XXX implement me
res.append(w)
return res

13
entities/event_picker.py Normal file
View File

@@ -0,0 +1,13 @@
from assets.events import EVENTS
import random
class ArenaEventPicker():
def __init__(self, players):
self.players = players
self.event_list = EVENTS
self.already_picked_players = []
def pick_event():
pass

View File

@@ -1,75 +1,133 @@
import random as _random import random as _random
import uuid as _uuid
class BrSimPlayer(): class BrSimPlayer():
def __init__(self, name, inventory= None): def __init__(self, name, inventory= None):
self.id= str(_uuid.uuid4())
self.name= name self.name= name
self.health= 1 self.health= 1
self.inventory= inventory or [] self.inventory= inventory or []
self.damage= 1 # this is the punch damage amount self.damage= 1 # 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.is_alive= True
self.agility= 10 # chance to avoid an hit self.agility= 10 # chance to avoid an hit
self.kills= 0 # track the number of kills
self.survived_days= 0 # track the number of the survived days
self.equipped_weapon= None
self.gender= _random.sample(['m', 'f', '-'], 1)[0] # for now get a random gender
def is_alive(self): ### control methods
return self.is_alive
def attack(self, target): def get_id(self):
if not self.is_alive(): return return self.id
if not target.is_alive(): return
if target.try_to_avoid_hit(): return # print something like 'enemy doges the attacl'
target.accuses_damage(self.damage)
def accuses_damage(self, damage): def get_name(self):
self.health -= damage return self.name
if self.health <= 0:
self.health = 0
self.is_alive = False
# show something like 'player is dead'
else:
# show something like 'get hit'
pass
def try_to_avoid_hit(self): def get_gender(self):
# maybe depend on the attack, if it is a gun shot it's quite impossible to dodge return self.gender
rnd= _random.randint(0, 100)
# if rnd > self.agility: return True ## XXX this is strange, if the agility is high the chances to dodge are lower
if rnd < self.agility: return True
return False
def steal(self):
#XXX can steal from death players or from sleeping players
pass
def escape(self):
#XXX It can run away from the fighting
pass
def heal(self):
#XXX if you have a wound and you have a medikit item, you can heal your wound or sickness
pass
def get_inventory(self): def get_inventory(self):
return self.inventory return self.inventory
def get_name(self): def get_inventory_weight(self):
return self.name weight= 0
for inv in self.get_inventory():
weight+= inv.get_weight()
return weight
def get_max_weight(self):
return self.max_weight
def get_health(self): def get_health(self):
return self.health return self.health
def get_damage(self): def get_damage(self):
return self.damage if not self.equipped_weapon: return self.damage
return self.equipped_weapon.damage
def get_agility(self): def get_agility(self):
return self.agility return self.agility
def get_data(self): def get_data(self):
return { return {
'id': self.get_id(),
'name': self.get_name(), 'name': self.get_name(),
'gender': self.get_gender(),
'inventory': self.get_inventory(), 'inventory': self.get_inventory(),
'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(),
} }
def is_alive(self):
return self.health > 0
### player actions
def _equip_weapon(self):
if not self.inventory: return
available_weapons= []
for inv in self.get_inventory():
# XXX
# i don't know yet if this is ok,
# we'll see it when weapon and items are defined
if not inv.damage: continue
available_weapons.append(inv)
self.equipped_weapon= random.sample(available_weapons, 1)[0]
def dodge(self):
# maybe depend on the attack, if it is a gun shot it's quite impossible to dodge
rnd= _random.randint(0, 100)
if rnd < self.agility: return True
return False
def accuses_damage(self, damage):
self.health -= damage
if self.health > 0: return self.get_health()
self.health = 0
if self.get_gender() == 'm':
print(f'[{self.get_name()}]: Guarino, perdonami se sono morto x.x')
elif self.get_gender() == 'f':
print(f'[{self.get_name()}]: Guarino, perdonami se sono morta x.x')
else:
print(f'[{self.get_name()}]: Guarino, perdonami se sono mort* x.x')
return damage
def attack(self, target):
self._equip_weapon()
if target.dodge():
if target.get_gender() == 'm':
print(f'Ehhhh voleviiii!!! sei lentoo! {target.get_name()} schiva il colpo di {self.get_name()}')
elif target.get_gender() == 'f':
print(f'Ehhhh voleviiii!!! sei lentaa! {target.get_name()} schiva il colpo di {self.get_name()}')
else:
print(f'Ehhhh voleviiii!!! sei lent##! {target.get_name()} schiva il colpo di {self.get_name()}')
return 0
target.accuses_damage(self.damage)
print(f'{self.get_name()} Colpisce {target.get_name()} in nome di Guarino')
return self.damage
def get_item(self, item):
if self.get_inventory_weight() + item.get_weight() >= self.get_max_weight():
if self.get_gender() == 'm':
print(f'Sono sovraccarico, {self.get_name} non puo\' prendere questo oggetto')
elif self.get_gender() == 'f':
print(f'Sono sovraccarica, {self.get_name} non puo\' prendere questo oggetto')
else:
print(f'Sono sovraccaric#, {self.get_name} non puo\' prendere questo oggetto')
return False
self.inventory.append(item)
def escape(self):
# TODO It can run away from the fighting
return
def heal(self):
# TODO heal system
# if you have a wound and you have a medikit item,
# you can heal your wound or sickness
return

91
main.py
View File

@@ -1,82 +1,27 @@
from entities import player as _player import random as _random
from entities import weapons as _weapons
from entities import weapon_syms as _wsyms from entities import weapon_syms as _wsyms
from entities import arena as _arena
class BrSimArena(): def init_arena(players, weapons):
return _arena.BrSimArena(players, weapons)
# players = [{'name': name, 'inventory': default_inventory, other_stats}] def run_events(Arena):
# weapons = [{WEAPON.KNIFE: quantity}, etc...] # this is the whole quantity of the items available on the world #A event for each player:
def __init__(self, players, weapons):
self.day= 1
self.players= [_player.BrSimPlayer(p['name'], p.get('inventory')) for p in players]
self.weapons= []
for weapon in weapons:
for wtype, quantity in weapon.items():
for i in range(quantity): self.weapons.append(_weapons.BrSimWeapon(wtype))
def next_day(self):
self.day+= 1
print(f'Giorno: {self.day}')
print(f'Giocatori vivi: {self.get_alive_players()}')
death_players= self.get_death_players()
if (death_players):
print(f'Giocatori morti: {death_players}')
def get_alive_players(self):
res= []
for p in self.players:
if not p.is_alive(): continue
res.append(p)
return res
def get_death_players(self):
res= []
for p in self.players:
if p.is_alive(): continue
res.append(p)
return res
def do_random_event(self):
#XXX random player does random action according to his inventory health, wounds, available weapons on the world, etc...
pass
def supporter_donation(self):
#XXX supporter donate a random item or weapon to a random player
#TODO maybe in future a player can have charism stats that can influence the chance to get a donation
pass
def add_player(self, name, inventory= None):
player= _player.BrSimPlayer(name, inventory)
self.players.append(player)
def get_players(self):
res= []
for p in self.players:
res.append(p.get_data())
return res
def get_weapons(self):
res= []
for w in self.weapons:
#XXX implement me
res.append(w)
return res
def init_arena():
players= [{'name': 'Crystal'}, {'name': 'Andrea'}]
w= _wsyms.KNIFE
#weapons= [{_wsyms.WEAPONS[w]['name' ]: 1}]
weapons= [{w: 1}]
return BrSimArena(players, weapons)
def run_event(Arena):
pass pass
def local_debug(): def local_debug():
Arena= init_arena() 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'Players: {Arena.get_players()}')
print(f'Weapons: {Arena.get_weapons()}') print(f'Weapons: {Arena.get_weapons()}')
run_event(Arena) while (len(Arena.get_alive_players()) > 1):
#Start a day
run_events(Arena)
#At 23:59:
Arena.next_day()
#End of day

View File

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