This commit is contained in:
SpudGunMan
2024-09-19 16:01:30 -07:00
10 changed files with 1923 additions and 11 deletions
+12 -4
View File
@@ -16,12 +16,12 @@ The bot will report on anyone who is getting close to the configured lat/long, i
Store and forward-like message re-play with `messages`, and there is a repeater module for dual radio bots to cross post messages. Messages are also logged locally to disk.
There is a small collection of games to play like DopeWars or Lemonade Stand and BlackJack to name a few, issuing `games` displays help
The bot can also be used to monitor a radio frequency and let you know when high SNR RF activity is seen. Using Hamlib(rigctld) to watch the S meter on a connected radio. You can send alerts to channels when a frequency is detected for 20 seconds within the thresholds set in config.ini
Any messages that are over 160 characters are chunked into 160 message bytes to help traverse hops, in testing, this keeps delivery success higher.
[Donate$](https://www.paypal.com/donate?token=ZpiU7zDh-AQDyK76nWmWPQLf04iOm-Iyr3f85lpubt37NWGRYtfe11UyC0LmY1wdcC20UubWo4Kec-_G) via PayPal if you like the project!
## Full list of commands for the bot
- Various solar details for radio propagation (spaceWeather module)
@@ -46,6 +46,9 @@ Any messages that are over 160 characters are chunked into 160 message bytes to
- `motd` or to set the message `motd $New Message Of the day`
- `lheard` returns the last 5 heard nodes with SNR, can also use `sitrep`
- `cmd` returns the list of commands (the help message)
- Games
- `lemonstand` plays the classic Lemonade Stand Finance game via DM
- `dopewars` plays the classic drug trader game via DM
## pong_bot.sh
Stripped-down bot, mostly around for archive purposes. The mesh-bot enhanced modules can be disabled by config to disable features.
@@ -245,6 +248,11 @@ I used ideas and snippets from other responder bots and want to call them out!
- https://github.com/pdxlocations/meshtastic-Python-Examples
- https://github.com/geoffwhittington/meshtastic-matrix-relay
GitHub user mrpatrick1991 For Docker configs, PiDiBi looking at test functions and other suggestions like wxc, CPU use, and alerting ideas
Discord and Mesh user Cisien, and github Hailo1999, for testing and ideas!
Games Ported from..
- https://github.com/tigerpointe/Lemonade-Stand/
- https://github.com/Reconfirefly/drugwars
- https://github.com/Himan10/BlackJack
GitHub user mrpatrick1991 For Docker configs, PiDiBi looking at test functions and other suggestions like wxc, CPU use, and alerting ideas
Discord and Mesh user Cisien, and github Hailo1999, for testing and ideas! Lots of individuals on the Meshtastic discord who have tossed out ideas and tested code!
+6
View File
@@ -52,6 +52,12 @@ LogMessagesToFile = False
# Logging of system messages to file
SyslogToFile = False
[games]
# enable or disable the games module(s)
dopeWars = True
lemonade = True
blackjack = True
[sentry]
# detect anyone close to the bot
SentryEnabled = True
+26 -1
View File
@@ -23,7 +23,32 @@ except:
except:
print ("\nSystem: bbsdm.pkl not found")
# Game HS tables
try:
with open('../lemonade_hs.pkl', 'rb') as f:
lemon_score = pickle.load(f)
except:
try:
with open('lemonade_hs.pkl', 'rb') as f:
lemon_score = pickle.load(f)
except:
print ("\nSystem: lemonade_hs.pkl not found")
try:
with open('../dopewar_hs.pkl', 'rb') as f:
dopewar_score = pickle.load(f)
except:
try:
with open('dopewar_hs.pkl', 'rb') as f:
dopewar_score = pickle.load(f)
except:
print ("\nSystem: dopewar_hs.pkl not found")
print ("\nSystem: bbs_messages")
print (bbs_messages)
print ("\nSystem: bbs_dm")
print (bbs_dm)
print (bbs_dm)
print ("Game HS tables")
print (f"lemon:{lemon_score}")
print (f"dopewar:{dopewar_score}")
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python3
# # Simulate meshing-around de K7MHI 2024
from modules.log import * # err? Move .py out of etc/ and place it in the root of the project
import time
import random
# Initialize the tool
projectName = "example_handler" # name of _handler function to match the function name under test
randomNode = False # Set to True to use random node IDs
def get_NodeID():
nodeList = [4258675309, 1212121212, 1234567890, 9876543210]
if randomNode:
nodeID = random.choice(nodeList) # get a random node ID
else:
nodeID = nodeList[0]
return nodeID
# # end Initialization of the tool
# # Function to handle, or the project in test
def example_handler(nodeID, message):
readableTime = time.ctime(time.time())
msg = "Hello World! "
msg += f" You are Node ID: {nodeID} "
msg += f" Its: {readableTime} "
msg += f" You just sent: {message}"
return msg
# # end of function test code
# # Simulate the meshing-around mesh-bot for prototyping new projects
if __name__ == '__main__': # represents the bot's main loop
packet = ""
nodeInt = 1 # represents the device/node number
logger.info(f"System: Meshing-Around Simulator Starting for {projectName}")
while True: # represents the onReceive() loop in the bot.py
nodeID = get_NodeID() # assign a nodeID for this iteration
projectResponse = ""
responseLength = 0
if packet != "":
#try:
projectResponse = globals()[projectName](nodeID, packet) # Call the project handler under test
# except Exception as e:
# logger.error(f"System: Handler: {e}")
# projectResponse = "Error in handler"
if projectResponse:
responseLength = len(projectResponse) # Evaluate the response length
logger.info(f"Device:{nodeInt} " + CustomFormatter.red + f"Sending {responseLength} long DM: " +\
CustomFormatter.white + projectResponse + CustomFormatter.purple + " To: " + CustomFormatter.white + str(nodeID))
packet = input("CLIENT INPUT: " ) # Emulate the client input
time.sleep(0.5)
# # End of launcher
+157 -6
View File
@@ -25,6 +25,10 @@ def auto_response(message, snr, rssi, hop, message_from_id, channel_number, devi
"wxc": lambda: handle_wxc(message_from_id, deviceID, 'wxc'),
"wx": lambda: handle_wxc(message_from_id, deviceID, 'wx'),
"wiki:": lambda: handle_wiki(message),
"games": lambda: gamesCmdList,
"dopewars": lambda: handleDopeWars(message_from_id, message, deviceID),
"lemonstand": lambda: handleLemonade(message_from_id, message),
"blackjack": lambda: handleBlackJack(message_from_id, message),
"ask:": lambda: handle_llm(message_from_id, channel_number, deviceID, message, publicChannel),
"askai": lambda: handle_llm(message_from_id, channel_number, deviceID, message, publicChannel),
"joke": tell_joke,
@@ -190,6 +194,92 @@ def handle_llm(message_from_id, channel_number, deviceID, message, publicChannel
return response
def handleDopeWars(nodeID, message, rxNode):
global dwPlayerTracker, dwHighScore
# get player's last command
last_cmd = None
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
last_cmd = dwPlayerTracker[i].get('cmd')
# welcome new player
if not last_cmd:
msg = 'Welcome to Dope Wars! You have ' + str(total_days) + ' days to make as much money as possible! '
high_score = getHighScoreDw()
msg += 'The High Score is $' + "{:,}".format(high_score.get('cash')) + ' by user ' + get_name_from_number(high_score.get('userID') , 'short', rxNode) + f'.\n'
msg += playDopeWars(nodeID, message)
else:
logger.debug("System: DopeWars: last_cmd: " + str(last_cmd))
msg = playDopeWars(nodeID, message)
# wait a second to keep from message collision
time.sleep(1)
return msg
def handleLemonade(nodeID, message):
global lemonadeTracker, lemonadeCups, lemonadeLemons, lemonadeSugar, lemonadeWeeks, lemonadeScore, lemon_starting_cash, lemon_total_weeks
def create_player(nodeID):
# create new player
logger.debug("System: Lemonade: New Player: " + str(nodeID))
lemonadeTracker.append({'nodeID': nodeID, 'cups': 0, 'lemons': 0, 'sugar': 0, 'cash': lemon_starting_cash, 'start': lemon_starting_cash, 'cmd': 'new', 'time': time.time()})
lemonadeCups.append({'nodeID': nodeID, 'cost': 2.50, 'count': 25, 'min': 0.99, 'unit': 0.00})
lemonadeLemons.append({'nodeID': nodeID, 'cost': 4.00, 'count': 8, 'min': 2.00, 'unit': 0.00})
lemonadeSugar.append({'nodeID': nodeID, 'cost': 3.00, 'count': 15, 'min': 1.50, 'unit': 0.00})
lemonadeScore.append({'nodeID': nodeID, 'value': 0.00, 'total': 0.00})
lemonadeWeeks.append({'nodeID': nodeID, 'current': 1, 'total': lemon_total_weeks, 'sales': 99, 'potential': 0, 'unit': 0.00, 'price': 0.00})
# get player's last command from tracker if not new player
last_cmd = ""
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
last_cmd = lemonadeTracker[i]['cmd']
# create new player if not in tracker
if last_cmd == "":
create_player(nodeID)
msg = start_lemonade(nodeID=nodeID, message=message, celsius=False)
# wait a second to keep from message collision
time.sleep(1)
return msg
def handleBlackJack(nodeID, message):
global jackTracker
msg = ""
# if player sends a L for leave table
if message.lower().startswith("l"):
logger.debug(f"System: BlackJack: {nodeID} is leaving the table")
# add 16 hours to the player time to leave the table, this will be detected by bot logic as player leaving
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
jackTracker[i]['leaveTime'] = time.time() + 57600
jackTracker[i]['cmd'] = "new"
else:
# Play BlackJack
msg = playBlackJack(nodeID=nodeID, message=message)
# get player's last command from tracker
last_cmd = ""
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
last_cmd = jackTracker[i]['cmd']
# find higest dollar amount in tracker for high score
if last_cmd == "new":
high_score = 0
for i in range(len(jackTracker)):
if jackTracker[i]['cash'] > high_score:
high_score = int(jackTracker[i]['cash'])
user = jackTracker[i]['nodeID']
if user != 0:
msg += f" Ranking🥇:{get_name_from_number(user)} with {high_score} chips. "
if last_cmd != "":
logger.debug(f"System: BlackJack: {nodeID} last command: {last_cmd}")
return msg
def handle_wxc(message_from_id, deviceID, cmd):
location = get_node_location(message_from_id, deviceID)
if use_meteo_wxApi and not "wxc" in cmd and not use_metric:
@@ -435,13 +525,72 @@ def onReceive(packet, interface):
# respond with DM
send_message(auto_response(message_string, snr, rssi, hop, message_from_id, channel_number, rxNode), channel_number, message_from_id, rxNode)
else:
if llm_enabled:
llm = handle_llm(message_from_id, channel_number, rxNode, message_string, publicChannel)
send_message(llm, channel_number, message_from_id, rxNode)
# DM is usefull for games or LLM
if games_enabled:
playingGame = False
# if in a game we cant use LLM disable for duration of game
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == message_from_id:
# check if the player has played in the last 8 hours
if dwPlayerTracker[i].get('last_played') > (time.time() - 28800):
playingGame = True
game = "DopeWars"
if llm_enabled:
logger.debug(f"System: LLM Disabled for {message_from_id} for duration of game")
#if time exceeds 8 hours reset the player
if dwPlayerTracker[i].get('last_played') < (time.time() - 28800):
logger.debug(f"System: DopeWars: Resetting player {message_from_id}")
dwPlayerTracker.pop(i)
# play the game
send_message(handleDopeWars(message_from_id, message_string, rxNode), channel_number, message_from_id, rxNode)
for i in range(0, len(lemonadeTracker)):
if lemonadeTracker[i].get('nodeID') == message_from_id:
# check if the player has played in the last 8 hours
if lemonadeTracker[i].get('time') > (time.time() - 28800):
playingGame = True
game = "LemonadeStand"
if llm_enabled:
logger.debug(f"System: LLM Disabled for {message_from_id} for duration of game")
#if time exceeds 8 hours reset the player
if lemonadeTracker[i].get('time') < (time.time() - 28800):
logger.debug(f"System: LemonadeStand: Resetting player {message_from_id}")
lemonadeTracker.pop(i)
# play the game
send_message(handleLemonade(message_from_id, message_string), channel_number, message_from_id, rxNode)
for i in range(0, len(jackTracker)):
if jackTracker[i].get('nodeID') == message_from_id:
# check if the player has played in the last 8 hours
if jackTracker[i].get('time') > (time.time() - 28800):
playingGame = True
game = "BlackJack"
if llm_enabled:
logger.debug(f"System: LLM Disabled for {message_from_id} for duration of game")
#if time exceeds 8 hours reset the player
if jackTracker[i].get('time') < (time.time() - 28800):
logger.debug(f"System: BlackJack: Resetting player {message_from_id}")
jackTracker.pop(i)
# play the game
send_message(handleBlackJack(message_from_id, message_string), channel_number, message_from_id, rxNode)
else:
# respond with welcome message on DM
logger.warning(f"Device:{rxNode} Ignoring DM: {message_string} From: {get_name_from_number(message_from_id, 'long', rxNode)}")
send_message(welcome_message, channel_number, message_from_id, rxNode)
playingGame = False
if not playingGame:
if llm_enabled:
# respond with LLM
llm = handle_llm(message_from_id, channel_number, rxNode, message_string, publicChannel)
send_message(llm, channel_number, message_from_id, rxNode)
else:
# respond with welcome message on DM
logger.warning(f"Device:{rxNode} Ignoring DM: {message_string} From: {get_name_from_number(message_from_id, 'long', rxNode)}")
send_message(welcome_message, channel_number, message_from_id, rxNode)
# log the message to the message log
msgLogger.info(f"Device:{rxNode} Channel:{channel_number} | {get_name_from_number(message_from_id, 'long', rxNode)} | " + message_string.replace('\n', '-nl-'))
@@ -532,6 +681,8 @@ async def start_rx():
logger.debug(f"System: Location Telemetry Enabled using NOAA API")
if dad_jokes_enabled:
logger.debug(f"System: Dad Jokes Enabled!")
if games_enabled:
logger.debug(f"System: Games Enabled!")
if wikipedia_enabled:
logger.debug(f"System: Wikipedia search Enabled")
if motd_enabled:
+431
View File
@@ -0,0 +1,431 @@
# Port of https://github.com/Himan10/BlackJack
# Adapted for Meshtastic mesh-bot by K7MHI Kelly Keeton 2024
from random import choices, shuffle
from modules.log import *
import time
jack_starting_cash = 100 # Replace 100 with your desired starting cash value
jackTracker= [{'nodeID': 0, 'cmd': 'new', 'time': time.time(), 'cash': jack_starting_cash,\
'bet': 0, 'gameStats': {'p_win': 0, 'd_win': 0, 'draw': 0}, 'p_cards':[], 'd_cards':[], 'p_hand':[], 'd_hand':[], 'next_card':[]}]
SUITS = ("♥️", "♦️", "♠️", "♣️")
RANKS = (
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"J",
"Q",
"K",
"A",
)
VALUES = {
"2": 2,
"3": 3,
"4": 4,
"5": 5,
"6": 6,
"7": 7,
"8": 8,
"9": 9,
"10": 10,
"J": 10,
"Q": 10,
"K": 10,
"A": 11,
}
class Card:
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank
def __str__(self):
return self.rank + " of " + self.suit
class Deck:
""" Creating a Deck of cards and Deal two cards to both player and dealer. """
def __init__(self):
self.deck = []
self.player = []
self.dealer = []
for suit in SUITS:
for rank in RANKS:
self.deck.append((suit, rank))
def shuffle(self):
shuffle(self.deck)
def deal_cards(self):
self.player = choices(self.deck, k=2)
self.delete_cards(self.player)
self.dealer = choices(self.deck, k=2)
self.delete_cards(self.dealer) # Delete Drawn Cards
return self.player, self.dealer
def delete_cards(self, total_drawn):
""" Delete Drawn cards from the Decks """
try:
for i in total_drawn:
self.deck.remove(i)
except ValueError:
pass
class Hand:
""" Adding the values of player/dealer cards and change the values of Aces acc. to situation. """
def __init__(self):
self.cards = []
self.value = 0
self.aces = 0
def add_cards(self, card):
self.cards.extend(card)
for count, ele in enumerate(card, 0):
if ele[1] == "A":
self.aces += 1
self.value += VALUES[ele[1]]
self.adjust_for_ace()
def adjust_for_ace(self):
while self.aces > 0 and self.value > 21:
self.value -= 10
self.aces -= 1
class Chips:
""" Player/dealer chips for making bets and Adding/Deducting amount in/from Player's total. """
def __init__(self):
self.total = jack_starting_cash
self.bet = 0
self.winnings = 0
def win_bet(self):
self.total += self.bet
self.winnings += 1
def loss_bet(self):
self.total -= self.bet
self.winnings -= 1
def take_bet(bet_amount, player_money):
try:
while bet_amount > player_money or bet_amount <= 0:
return f"Enter a bet amount between 1 and {player_money}"
return bet_amount
except TypeError:
return "Invalid bet amount"
def success_rate(card, obj_h):
""" Calculate Success rate of 'HIT' new cards """
msg = ""
rate = 0
diff = 21 - obj_h.value
if diff != 0:
rate = (VALUES[card[0][1]] / diff) * 100
if rate < 100:
msg += f"If Hit, chance {100-int(rate)}% success, {int(rate)}% failure."
elif rate > 100:
l_rate = int(rate - (rate - 99)) # Round to 99
if card[0][1] == "A":
l_rate -= 99
msg += f"If Hit, chance {100-l_rate}% failure, and {l_rate}% success."
else:
msg += f"If Hit, a low chance of success."
return msg
def hits(obj_de):
new_card = [obj_de.deal_cards()[0][0]]
# obj_h.add_cards(new_card)
return new_card
def display_hand(hand):
# Display the cards in the hand nicely
d = "" # display
for card in hand:
d += f"{card[1]}{card[0]}"
if card != hand[-1]:
d += ", "
return d
def show_some(player_cards, dealer_cards, obj_h):
msg = f"PLAYER[{obj_h.value}] {display_hand(player_cards)} "
msg += f"DEALER[{VALUES[dealer_cards[1][1]]}] {dealer_cards[1][1]}{dealer_cards[1][0]} "
return msg
def show_all(player_cards, dealer_cards, obj_h, obj_d):
msg = f"PLAYER_CARDS [{obj_h.value}] {display_hand(player_cards)} "
msg += f"DEALER_CARDS [{obj_d.value}] {display_hand(dealer_cards)}"
return msg
def player_bust(obj_h, obj_c):
if obj_h.value > 21:
obj_c.loss_bet()
return True
return False
def player_wins(obj_h, obj_d, obj_c):
if any((obj_h.value == 21, obj_h.value > obj_d.value and obj_h.value < 21)):
obj_c.win_bet()
return True
return False
def dealer_bust(obj_d, obj_h, obj_c):
if obj_d.value > 21:
if obj_h.value < 21:
obj_c.win_bet()
return True
return False
def dealer_wins(obj_h, obj_d, obj_c):
if any((obj_d.value == 21, obj_d.value > obj_h.value and obj_d.value < 21)):
obj_c.loss_bet()
return True
return False
def push(obj_h, obj_d):
if obj_h.value == obj_d.value:
return True
return False
def player_surrender(obj_c):
obj_c.loss_bet()
return True
def gameStats(p_count, d_count, draw_c):
msg = f"\n📊WINS:{p_count},DEALER:{d_count},DRAW:{draw_c}"
return msg
def getLastCmdJack(nodeID):
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
return jackTracker[i]['cmd']
return None
def setLastCmdJack(nodeID, cmd):
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
jackTracker[i]['cmd'] = cmd
return True
return False
def playBlackJack(nodeID, message):
# Initalize the Game
msg, last_cmd = '', None
p_win, d_win, draw = 0, 0, 0
p_chips = Chips()
p_hand = Hand()
d_hand = Hand()
p_cards, d_cards = [], []
bet_money = 0
# Initalize the Cards
cards_deck = Deck()
cards_deck.shuffle()
p_cards, d_cards = cards_deck.deal_cards()
# Deal the cards to player and dealer
p_hand.add_cards(p_cards)
d_hand.add_cards(d_cards)
next_card = hits(cards_deck)
# Check if player, use tracking
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
last_cmd = jackTracker[i]['cmd']
p_chips.total = jackTracker[i]['cash']
p_win = jackTracker[i]['gameStats']['p_win']
d_win = jackTracker[i]['gameStats']['d_win']
draw = jackTracker[i]['gameStats']['draw']
bet_money = jackTracker[i]['bet']
p_chips.bet = bet_money
if last_cmd == "playing":
p_cards = jackTracker[i]['p_cards']
d_cards = jackTracker[i]['d_cards']
p_hand = jackTracker[i]['p_hand']
d_hand = jackTracker[i]['d_hand']
next_card = jackTracker[i]['next_card']
if last_cmd is None:
# create new player if not in tracker
logger.debug(f"System: BlackJack: New Player {nodeID}")
jackTracker.append({'nodeID': nodeID, 'cmd': 'new', 'time': time.time(), 'cash': jack_starting_cash,\
'bet': 0, 'gameStats': {'p_win': p_win, 'd_win': d_win, 'draw': draw}, 'p_cards':p_cards, 'd_cards':d_cards, 'p_hand':p_hand.cards, 'd_hand':d_hand.cards, 'next_card':next_card})
return f"Welcome to BlackJack! you have {p_chips.total} chips, Whats your bet?"
if getLastCmdJack(nodeID) == "new":
# Place Bet
try:
if message == "b":
if bet_money == 0:
bet_money = 5
else:
bet_money = bet_money
if bet_money != 0:
bet_money = int(bet_money)
else:
bet_money = int(message)
if bet_money < p_chips.total or bet_money <= 0:
p_chips.bet = take_bet(bet_money, p_chips.total)
else:
return f"Invalid Bet, the maximum bet you can place is {p_chips.total}"
except ValueError:
p_chips.bet = 5
# Show the cards
msg += show_some(p_cards, d_cards, p_hand)
# check for blackjack 21 and only two cards
if p_hand.value == 21 and len(p_hand.cards) == 2:
msg += "Player 🎰 BLAAAACKJACKKKK 💰"
p_chips.total += round(p_chips.bet * 1.5)
setLastCmdJack(nodeID, "dealerTurn")
# Save the game state
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
jackTracker[i]['cash'] = p_chips.total
break
else:
# Display the statistics
stats = success_rate(next_card, p_hand)
msg += stats
setLastCmdJack(nodeID, "betPlaced")
if getLastCmdJack(nodeID) == "betPlaced":
setLastCmdJack(nodeID, "playing")
msg += "(H)it,(S)tand,(F)orfit,(D)ouble"
# save the game state
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
jackTracker[i]['cash'] = p_chips.total
jackTracker[i]['bet'] = p_chips.bet
jackTracker[i]['p_cards'] = p_cards
jackTracker[i]['d_cards'] = d_cards
jackTracker[i]['p_hand'] = p_hand
jackTracker[i]['d_hand'] = d_hand
jackTracker[i]['next_card'] = next_card
return msg
while getLastCmdJack(nodeID) == "playing": # Recall var. from hit and stand function
next_card = hits(cards_deck)
# Get the statistics
stats = success_rate(next_card, p_hand)
# Player's Turn
choice = message.lower()
if choice == "hit" or choice == "h":
# hits(obj_de, p_hand)
p_hand.add_cards(next_card)
msg += show_some(p_hand.cards, d_cards, p_hand)
elif choice == "stand" or choice == "s":
setLastCmdJack(nodeID, "dealerTurn")
elif choice == "forfit" or choice == "f":
p_chips.bet = p_chips.bet / 2
setLastCmdJack(nodeID, "dealerTurn")
p_hand.value += 21
elif choice == "double" or choice == "d":
if p_chips.bet * 2 <= p_chips.total:
p_chips.bet *= 2
next_d_card = hits(cards_deck)
p_hand.add_cards(next_d_card)
setLastCmdJack(nodeID, "dealerTurn")
else:
return "You can't Double Down, dont have enough chips"
else:
return "Invalid Choice"
# Check if player bust
if player_bust(p_hand, p_chips):
d_win += 1
msg += "Player BUUUSSTTT💥"
setLastCmdJack(nodeID, "dealerTurn")
if getLastCmdJack(nodeID) == "playing":
msg += stats
msg += "[H,S,F,D,L]"
# Save the game state
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
jackTracker[i]['cash'] = p_chips.total
jackTracker[i]['bet'] = p_chips.bet
jackTracker[i]['gameStats']['p_win'] = p_win
jackTracker[i]['gameStats']['d_win'] = d_win
jackTracker[i]['gameStats']['draw'] = draw
jackTracker[i]['p_cards'] = p_cards
jackTracker[i]['d_cards'] = d_cards
jackTracker[i]['p_hand'] = p_hand
jackTracker[i]['d_hand'] = d_hand
break
if getLastCmdJack(nodeID) == "dealerTurn":
break
return msg
if getLastCmdJack(nodeID) == "dealerTurn":
if p_hand.value <= 21:
# Dealer's Turn
while d_hand.value < 17:
d_card = hits(cards_deck)
d_hand.add_cards(d_card)
if dealer_bust(d_hand, p_hand, p_chips):
p_win += 1
msg += "Dealer BUUUSSTTT💥"
break
# Show all cards
msg += show_all(p_hand.cards, d_hand.cards, p_hand, d_hand)
# Check who wins
if push(p_hand, d_hand):
draw += 1
msg += f"👌PUSH"
elif player_wins(p_hand, d_hand, p_chips):
p_win += 1
msg += f"🎉PLAYER WINS🎰"
elif dealer_wins(p_hand, d_hand, p_chips):
d_win += 1
msg += f"👎DEALER WINS"
else:
msg += f"👎DEALER WINS"
# Display the Game Stats
msg += gameStats(str(p_win), str(d_win), str(draw))
# Display the chips left
if p_chips.total < 1:
if p_chips.total > 0:
msg += f"🪙Keep the change you filthy animal!"
else:
msg += "💸NO MORE MONEY! Game Over!"
p_chips.total = jack_starting_cash
else:
msg += f"💰You have {p_chips.total} chips left"
msg += "(B)et or (L)eave table."
# Reset the game
setLastCmdJack(nodeID, "new")
jackTracker[i]['cash'] = p_chips.total
jackTracker[i]['gameStats']['p_win'] = p_win
jackTracker[i]['gameStats']['d_win'] = d_win
jackTracker[i]['gameStats']['draw'] = draw
jackTracker[i]['p_cards'] = []
jackTracker[i]['d_cards'] = []
jackTracker[i]['p_hand'] = []
jackTracker[i]['d_hand'] = []
jackTracker[i]['time'] = time.time()
return msg
+648
View File
@@ -0,0 +1,648 @@
# Port of https://github.com/Reconfirefly/drugwars/tree/master
# Adapted for Meshtastic mesh-bot by K7MHI Kelly Keeton 2024
import random
import time
import pickle
from modules.log import *
# Global variables
total_days = 7 # number of days or rotations the player has to play
starting_cash = 5000
# Database for the game reset on boot
dwInventoryDb = [{'userID': 1234567890, 'inventory': 0, 'priceList': [], 'amount': []}]
dwCashDb = [{'userID': 1234567890, 'cash': starting_cash},]
dwGameDayDb = [{'userID': 1234567890, 'day': 0},]
dwLocationDb = [{'userID': 1234567890, 'location': 'USA', 'loc_choice': 0},]
dwPlayerTracker = [{'userID': 1234567890, 'last_played': time.time(), 'cmd': 'start'},]
# high score is saved in a pickle file
dwHighScore = {}
class Drugs:
def __init__(self, name, price_range):
self.name = name
self.price_range = price_range
self.price_check()
def price_check(self):
# the * is to unpack the touple of values that the random goes between
self.price = random.randint(*self.price_range)
# print("the price of " + self.name + " is " + str(self.price))
return self.price
class Events:
def __init__(self, name, text, price_range):
self.name = name
self.price_range = price_range
self.text = text
self.price_mod()
def price_mod(self):
self.price = random.randint(*self.price_range)
return self.price
my_drugs = [
# Drugs("Name", (min price, max price), amount)
Drugs("Cocaine", (15000, 28000)),
Drugs("Heroin", (2000, 10000)),
Drugs("Weed", (300, 1000)),
Drugs("Hash", (200, 1200)),
Drugs("Opium", (400, 1800)),
Drugs("Acid", (1000, 4200)),
Drugs("Ludes", (18, 75)),
]
event_list = [
# Events("Name", "Text", (min price, max price))
Events("Cocaine", 'El Chapo Arrested! 🚔 Coke price thru the roof! 📈', (40000, 110000)),
Events("Heroin", 'Trump cracks down on opiates! Heroin in high demand by addicts📈', (9000, 25000)),
Events("Weed", 'The DEA has fully legalized weed! Prices are at an all time low!📉', (50, 400)),
Events("Hash", 'Ricky\'s hash driveway burned down! 🚒 Look at the price boys!📈', (800, 2000)),
Events("Opium", 'Shenzhen 深圳 Opium 鸦片 Den 塔 was raided! 🚔 Street price is popping off!📈', (1800, 6000)),
Events("Acid", 'The Grateful Dead are on tour! Acid prices are skyrocketing!📈', (5000, 15000)),
Events("Ludes", 'The Wolf of Wall Street is back! Ludes are in demand!', (100, 300)),
Events("Cocaine", "The Biden administration has legalized cocaine! Prices are at an all time low!📉", (3000, 10000)),
Events("Heroin", "Oregon has legalized heroin! Prices are at an all time low!📉", (500, 2500)),
Events("Weed", "Prices are at an all time HIGH!📈", (1000, 5000)),
Events("Hash", "The Middle East has legalised hash! Prices are at an all time low!📉", (50, 1000)),
Events("Opium", "The Sackler's flood the market with cheap opium! Prices are at an all time low!📉", (300, 900)),
Events("Acid", "The FBI admits to dosing the water supply with LSD! Acid at an all time low!📉", (500, 2000)),
Events("Ludes", "The FDA approves ludes for sale! Prices are at an all time low!📉", (3, 45))
]
def generatelocations():
# dictionary of locations
locs = {'Canada': ('Red Deer', 'Edmonton', 'Calgary', 'Toronto', 'Vancouver', 'St. Johns'),
'USA': ('L.A.', 'NYC', 'Chicago', 'Miami', 'Houston', 'Phoenix'), 'Mexico': ('Tijuana', 'Mexico City', 'Cancun', 'Juarez', 'Acapulco', 'Guadalajara'),\
'South America': ('Bogota', 'Caracas', 'Lima', 'Santiago', 'Buenos Aires', 'Rio'), 'Europe': ('London', 'Paris', 'Berlin', 'Rome', 'Madrid', 'Moscow')}
country = list(locs.keys())
country = country[random.randint(0, len(country)-1)]
# return the location list for the user's country
location = []
for i in range(len(locs[country])):
location.append(locs[country][i])
return location
def generate_event():
# roll to see if an event happens
event_choice = random.randint(0, len(event_list)-1)
if random.randint(0, 100) > 35:
return event_choice
else:
return -1
def officer(nodeID):
global dwCashDb, dwInventoryDb
# get the inventory for the user
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
inventory = dwInventoryDb[i].get('inventory')
amount = check_inv(nodeID)
# get the cash for the user
for i in range(0, len(dwCashDb)):
if dwCashDb[i].get('userID') == nodeID:
cash = dwCashDb[i].get('cash')
# rolls to see if the officer takes drugs from you
# odds are (1 - event chance) * (officer chance) * (confiscation chance)
# currently (1 - 0.35) * (0.20) * (0.35) = 4.55%
# chance is approximate, not sure how randint handles endpoints, close enough for my purposes
if random.randint(0, 100) > 65: # confiscation chance
k = 0
j = 0
# removes all drugs from inventory tally and individual class attirbute
for i in range(0, len(my_drugs)):
j = amount[i]
amount[i] = 0
k += j
inventory -= k
# sends 'conf' for confiscated. sending a string is better than a number here
cash_taken = 'conf'
return cash_taken
# rolls to see if the officer takes cash from you
# odds are (1 - event chance) * (officer chance) * (1 - confiscation chance)
# currently (1 - 0.35) * (0.20) * (0.65) = 8.45%
# chance is approximate, not sure how randint handles endpoints, close enough for my purposes
cash_taken = random.randint(1, cash-1)
cash -= cash_taken
# Update the cash_db and inventory_db
for i in range(0, len(dwCashDb)):
if dwCashDb[i].get('userID') == nodeID:
dwCashDb[i]['cash'] = cash
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
dwInventoryDb[i]['inventory'] = inventory
amount = dwInventoryDb[i].get('amount')
return cash_taken
def price_change(event_number):
price_list = []
for i in range(0, len(my_drugs)):
j = my_drugs[i]
k = j.price_check()
price_list.append(k)
# check if IndexError will be thrown and find a new event_number with generate_event
while event_number > len(price_list)-1:
event_number = generate_event()
if event_number != -1:
price_list[event_number] = event_list[event_number].price_mod()
return price_list
def check_inv(nodeID):
global dwInventoryDb
# get the inventory ammount for the user
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
amount = dwInventoryDb[i].get('amount')
# if ammount is empty list initialize it
if not amount:
amount = []
for i in range(0, len(my_drugs)):
amount.append(0,)
# save the amount to the inventory_db
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
dwInventoryDb[i]['amount'] = amount
return amount
def buy_func(nodeID, price_list, choice=0, value='0'):
global dwCashDb, dwInventoryDb, dwPlayerTracker
msg = ''
# get the inventory for the user
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
inventory = dwInventoryDb[i].get('inventory')
amount = check_inv(nodeID)
# get the cash for the user
for i in range(0, len(dwCashDb)):
if dwCashDb[i].get('userID') == nodeID:
cash = dwCashDb[i].get('cash')
drug_choice = choice
if choice == 0:
msg = "Enter b or s and the drug number and qty you want to buy or sell. ex: b,1,10 buys 10 of drug 1"
return msg
else:
if drug_choice in range(1, len(my_drugs) + 1):
drug_choice = drug_choice - 1
msg = my_drugs[drug_choice].name + ": you have " + str(amount[drug_choice]) + " "
msg += " The going price is: $" + str(price_list[drug_choice]) + " "
buy_amount = value
if buy_amount == 'm':
buy_amount = cash // price_list[drug_choice]
if buy_amount > 100 - inventory:
buy_amount = 100 - inventory
if buy_amount == 0:
msg = "Enter b or s and the drug number and qty you want to buy or sell. ex: b,1,10 buys 10 of drug 1"
return msg
buy_amount = int(buy_amount)
if buy_amount not in range(1, 101):
msg = f"Enter qty or m for max"
return msg
if buy_amount > 100 - inventory:
msg = "You don\'t have enough space for all that."
return msg
if buy_amount * price_list[drug_choice] <= cash:
amount[drug_choice] += buy_amount
cash -= buy_amount * price_list[drug_choice]
inventory += buy_amount
msg += "You bought " + str(buy_amount) + " " + my_drugs[drug_choice].name + '. Remaining cash: $' + str(cash)
msg += f"\nBuy Sell Fly?"
else:
msg = "You don\'t have enough cash!"
return msg
# update the cash_db and inventory_db values
for i in range(0, len(dwCashDb)):
if dwCashDb[i].get('userID') == nodeID:
dwCashDb[i]['cash'] = cash
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
dwInventoryDb[i]['inventory'] = inventory
# save the last command as ask_bsf
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
dwPlayerTracker[i]['cmd'] = 'ask_bsf'
return msg
def sell_func(nodeID, price_list, choice=0, value='0'):
global dwCashDb, dwInventoryDb, dwPlayerTracker
msg = ''
# get the inventory for the user
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
inventory = dwInventoryDb[i].get('inventory')
amount = check_inv(nodeID)
# get the cash for the user
for i in range(0, len(dwCashDb)):
if dwCashDb[i].get('userID') == nodeID:
cash = dwCashDb[i].get('cash')
# get the drug choice and amount to sell
drug_choice = choice
sell_amount = value
try:
if sell_amount == 'm':
sell_amount = amount[drug_choice - 1]
else:
sell_amount = int(sell_amount)
if sell_amount not in range(1, 101):
msg = f"You can only sell between 1 and 100"
return msg
except ValueError:
msg = f"Enter qty or m for max"
return msg
# check if the user has any of the drug they are trying to sell
if choice == 0:
msg = "Enter b or s and the drug number and qty you want to buy or sell. ex: b,1,10 buys 10 of drug 1"
return msg
else:
if drug_choice in range(1, len(my_drugs) + 1) and amount[drug_choice - 1] > 0:
drug_choice = drug_choice - 1
msg = my_drugs[drug_choice].name + ": you have " + str(amount[drug_choice]) +\
" The going price is: $" + str(price_list[drug_choice])
# check if the user has enough of the drug to sell
if sell_amount <= amount[drug_choice]:
amount[drug_choice] -= sell_amount
cash += sell_amount * price_list[drug_choice]
inventory -= sell_amount
msg += " You sold " + str(sell_amount) + " " + my_drugs[drug_choice].name + ' for $' +\
str(sell_amount * price_list[drug_choice]) + '. Total cash: $' + str(cash)
else:
msg = "You don't have that much"
return msg
else:
msg = "You don't have any " + my_drugs[drug_choice - 1].name
return msg
# update the cash_db and inventory_db values
for i in range(0, len(dwCashDb)):
if dwCashDb[i].get('userID') == nodeID:
dwCashDb[i]['cash'] = cash
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
dwInventoryDb[i]['inventory'] = inventory
dwInventoryDb[i]['amount'] = amount
# save the last command as ask_bsf
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
dwPlayerTracker[i]['cmd'] = 'ask_bsf'
return msg
def get_location_table(nodeID, choice=0):
global dwLocationDb
# get the location for the user
for i in range(0, len(dwLocationDb)):
if dwLocationDb[i].get('userID') == nodeID:
loc = dwLocationDb[i].get('location')
# list the lcaitons and their index in two columns
loc_table_string = ''
for i in range(len(loc)):
loc_table_string += str(i+1) + '. ' + loc[i] + ' '
loc_table_string += f'Where do you want to go?#'
return loc_table_string
def endGameDw(nodeID):
global dwCashDb, dwInventoryDb, dwLocationDb, dwGameDayDb, dwHighScore
msg = ''
dwHighScore = getHighScoreDw()
# Confirm the cash for the user
for i in range(0, len(dwCashDb)):
if dwCashDb[i].get('userID') == nodeID:
cash = dwCashDb[i].get('cash')
logger.debug("System: DopeWars: Game Over for user: " + str(nodeID) + " with cash: " + str(cash))
# remove the player from the game databases
for i in range(0, len(dwCashDb)):
if dwCashDb[i].get('userID') == nodeID:
dwCashDb.pop(i)
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
dwInventoryDb.pop(i)
for i in range(0, len(dwLocationDb)):
if dwLocationDb[i].get('userID') == nodeID:
dwLocationDb.pop(i)
for i in range(0, len(dwGameDayDb)):
if dwGameDayDb[i].get('userID') == nodeID:
dwGameDayDb.pop(i)
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
dwPlayerTracker.pop(i)
# checks if the player's score is higher than the high score and writes a new high score if it is
if cash > dwHighScore.get('cash'):
dwHighScore = ({'userID': nodeID, 'cash': round(cash, 2)})
with open('dopewar_hs.pkl', 'wb') as file:
pickle.dump(dwHighScore, file)
msg = "You finished with $" + str(cash) + " and beat the high score!🎉💰"
return msg
if cash > starting_cash:
msg = 'You made money! 💵 Up ' + str((cash/starting_cash).__round__()) + 'x! Well done.'
return msg
if cash == starting_cash:
msg = 'You broke even... hope you at least had fun 💉💊'
return msg
if cash < starting_cash:
msg = "You lost money, better go get a real job.💸"
logger.debug("System: DopeWars: Game Over for user: " + str(nodeID) + " with cash: " + str(cash))
return msg
def getHighScoreDw():
global dwHighScore
# Load high score table
try:
with open('dopewar_hs.pkl', 'rb') as file:
dwHighScore = pickle.load(file)
except FileNotFoundError:
logger.debug("System: DopeWars: No high score table found")
# high score pickle file is a touple of the nodeID and the high score
dwHighScore = ({"userID": 4258675309, "cash": 100})
# write a new high score file if one is not found
with open('dopewar_hs.pkl', 'wb') as file:
pickle.dump(dwHighScore, file)
return dwHighScore
def render_game_screen(userID, day_play, total_day, loc_choice, event_number, price_list, cash_stolen):
global dwCashDb, dwInventoryDb, dwLocationDb
msg = ''
# get the location for the user
for i in range(0, len(dwLocationDb)):
if dwLocationDb[i].get('userID') == userID:
loc = dwLocationDb[i].get('location')
if event_number != -1:
msg += event_list[event_number].text + f"\n"
if event_number == -1 and cash_stolen != 0 and cash_stolen != 'conf':
msg += "🚔Officer Leroy stopped you and took $" + str(cash_stolen) + " from you." + f"\n"
if event_number == -1 and cash_stolen == 'conf':
msg += "🚔Officer Leroy stopped you and took all of your drugs." + f"\n"
# get the inventory for the user
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == userID:
inventory = dwInventoryDb[i].get('inventory')
amount = check_inv(userID)
# get the cash for the user
for i in range(0, len(dwCashDb)):
if dwCashDb[i].get('userID') == userID:
cash = dwCashDb[i].get('cash')
msg += "Location: " + loc[int(loc_choice) - 1] + ", Day:" + str(day_play) + '/' + str(total_day) + ", $" + str(cash) + " Backpack: " + str(inventory) + "/100" + f"\n"
for i, drug in enumerate(my_drugs, 1):
qty = amount[i-1]
msg += f'#{str(i)}.{drug.name}/${price_list[i-1]}({qty}) '
return msg
def dopeWarGameDay(nodeID, day_play, total_day):
global dwCashDb, dwLocationDb, dwInventoryDb
cash_stolen = 0
# roll for the event of the day
event_number = generate_event()
# get the location for the user
for i in range(0, len(dwLocationDb)):
if dwLocationDb[i].get('userID') == nodeID:
loc = dwLocationDb[i].get('location')
loc_choice = dwLocationDb[i].get('loc_choice')
# rolls to see if the officer event happens
# odds are (1 - event chance) * (officer chance)
# currently (1 - 0.35) * (0.20) = 13%
# chance is approximate, not sure how randint handles endpoints, close enough for my purposes
if event_number == -1 and random.randint(0, 100) > 80:
cash_stolen = officer(nodeID)
price_list = price_change(event_number)
# set the price_list for the user
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
dwInventoryDb[i]['priceList'] = price_list
check_inv(nodeID)
# main game display print
msg = render_game_screen(nodeID, day_play, total_day, loc_choice, event_number, price_list, cash_stolen)
return msg
def playDopeWars(nodeID, cmd):
global dwGameDayDb, dwPlayerTracker, dwCashDb, dwInventoryDb, dwLocationDb, dwHighScore
inGame = False
msg = ''
# check if the player is currently playing the game
for i in range(0, len(dwGameDayDb)):
if dwGameDayDb[i].get('userID') == nodeID:
inGame = True
if not inGame:
# initalize player in the database
loc = generatelocations()
dwInventoryDb.append({'userID': nodeID, 'inventory': 0, 'priceList': []})
dwCashDb.append({'userID': nodeID, 'cash': starting_cash})
dwLocationDb.append({'userID': nodeID, 'location': loc, 'loc_choice': 0})
dwGameDayDb.append({'userID': nodeID, 'day': 0})
dwPlayerTracker.append({'userID': nodeID, 'last_played': time.time(), 'cmd': 'start'})
logger.debug("System: DopeWars: New player: " + str(nodeID))
# get the day for the user
for i in range(0, len(dwGameDayDb)):
if dwGameDayDb[i].get('userID') == nodeID:
game_day = dwGameDayDb[i].get('day')
# get the player's last command
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
last_cmd = dwPlayerTracker[i].get('cmd')
# get the price_list for the user
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
price_list = dwInventoryDb[i].get('priceList')
# get the location for the user
for i in range(0, len(dwLocationDb)):
if dwLocationDb[i].get('userID') == nodeID:
loc_choice = dwLocationDb[i].get('loc_choice')
# Pick Starting City
if last_cmd == 'start':
# print the location table
msg = get_location_table(nodeID)
# set the player's last command to location to start the game
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
dwPlayerTracker[i]['cmd'] = 'location'
if last_cmd == 'ask_bsf':
msg = 'example Buy: b,Drug,Qty or Sell s,1,10. Fly: f. Price list: p or end'
menu_choice = cmd.lower()
if ',' in menu_choice:
#split the choice into a letter and a number for the buy/sell functions
menu_choice = menu_choice.split(',')
try:
if int(menu_choice[1]) not in range(1, 8):
raise ValueError
else:
menu_choice[1] = int(menu_choice[1])
if menu_choice[0] not in ['b', 's']:
raise ValueError
if menu_choice[2] != 'm':
if int(menu_choice[2]) not in range(1, 101):
raise ValueError
else:
menu_choice[2] = int(menu_choice[2])
except ValueError:
msg = 'a value was bad, example dopeware Buy or Sell b,1,10 or s,1,m'
return msg
if menu_choice[0] == 'b':
# set last command to ask_bsf and buy
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
dwPlayerTracker[i]['cmd'] = 'ask_bsf'
msg = buy_func(nodeID, price_list, menu_choice[1], menu_choice[2])
return msg
if menu_choice[0] == 's':
# set last command to ask_bsf and sell
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
dwPlayerTracker[i]['cmd'] = 'ask_bsf'
msg = sell_func(nodeID, price_list, menu_choice[1], menu_choice[2])
return msg
elif 's' in menu_choice:
msg = ''
# sell everything we have in backpack
for i in range(0, len(dwInventoryDb)):
if dwInventoryDb[i].get('userID') == nodeID:
inventory = dwInventoryDb[i].get('inventory')
if inventory == 0:
msg = "You don't have anything to sell"
else:
for i in range(1, (len(my_drugs) +1)):
sell = sell_func(nodeID, price_list, i, 'm')
# ignore starts with "You don't have any"
if not sell.startswith("You don't have any"):
msg += sell
if i != len(my_drugs):
msg += '\n'
return msg
elif 'f' in menu_choice:
# set last command to location
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
dwPlayerTracker[i]['cmd'] = 'location'
last_cmd = 'location'
elif 'p' in menu_choice:
# render_game_screen
msg = render_game_screen(nodeID, game_day, total_days, loc_choice, -1, price_list, 0)
return msg
elif 'end' in menu_choice:
msg = endGameDw(nodeID)
return msg
else:
msg = 'example Buy: b,Drug,Qty or Sell s,1,10. Fly: f. Price list: p or end'
return msg
# Buy
if last_cmd == 'buy':
# ned to collect which drug # and qty to buy
msg = buy_func(nodeID, price_list)
return msg
# Sell
if last_cmd == 'sell':
msg = sell_func(nodeID, price_list)
return msg
# Pick Location, and display main game screen
if last_cmd == 'location':
# validate the location choice
try:
loc_choice = int(cmd)
if loc_choice not in range(1, 6):
raise ValueError
except ValueError:
loc_choice = random.randint(1, 6)
# set the player's location choice
for i in range(0, len(dwLocationDb)):
if dwLocationDb[i].get('userID') == nodeID:
dwLocationDb[i]['loc_choice'] = loc_choice
# set the player's last command
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
dwPlayerTracker[i]['cmd'] = 'display_main'
# increment the game_day
game_day += 1
for i in range(0, len(dwGameDayDb)):
if dwGameDayDb[i].get('userID') == nodeID:
dwGameDayDb[i]['day'] = game_day
# update the player's last played time
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
dwPlayerTracker[i]['last_played'] = time.time()
last_cmd = 'display_main'
# Display Main Game Screen and ask for buy, sell, or fly
if last_cmd == 'display_main':
msg = dopeWarGameDay(nodeID, game_day, total_days)
msg += f"\nBuy, Sell, Fly? Price list?"
# set the player's last command
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:
dwPlayerTracker[i]['cmd'] = 'ask_bsf'
# Game end
if game_day == total_days + 1:
msg = endGameDw(nodeID)
return msg
+544
View File
@@ -0,0 +1,544 @@
# Port of https://github.com/tigerpointe/Lemonade-Stand/blob/main/lemonade.py MIT License Copyright (c) 2023 TigerPointe Software, LLC
# Adapted for Meshtastic mesh-bot by K7MHI Kelly Keeton 2024
from collections import OrderedDict # ordered dictionaries
from random import randrange, uniform # random numbers
from types import SimpleNamespace # namespaces support
import pickle # pickle file support
import time # time functions
from modules.log import * # mesh-bot logging
import locale # culture specific locale
import math # math functions
import re # regular expressions
# Set all of the locale category elements as default
# ex. print(locale.currency(12345.67, grouping=True))
locale.setlocale(locale.LC_ALL, '')
lemon_starting_cash = 30.00
lemon_total_weeks = 7
lemonadeTracker = [{'nodeID': 0, 'cups': 0, 'lemons': 0, 'sugar': 0, 'cash': lemon_starting_cash, 'start': lemon_starting_cash, 'cmd': 'new', 'time': time.time()}]
lemonadeCups = [{'nodeID': 0, 'cost': 2.50, 'count': 25, 'min': 0.99, 'unit': 0.00}]
lemonadeLemons = [{'nodeID': 0, 'cost': 4.00, 'count': 8, 'min': 2.00, 'unit': 0.00}]
lemonadeSugar = [{'nodeID': 0, 'cost': 3.00, 'count': 15, 'min': 1.50, 'unit': 0.00}]
lemonadeWeeks = [{'nodeID': 0, 'current': 1, 'total': lemon_total_weeks, 'sales': 99, 'potential': 0, 'unit': 0.00, 'price': 0.00}]
lemonadeScore = [{'nodeID': 0, 'value': 0.00, 'total': 0.00}]
def get_sales_amount(potential, unit, price):
"""Gets the sales amount.
Multiply the potential sales by a ratio of unit cost to actual price; the
exponent results in the values falling along a curve, rather than along a
straight line, resulting in more realistic sales values at each price.
Parameters
potential : Potential sales
unit : Unit cost
price : Actual price
"""
return math.floor(potential * (unit / (price ** 1.5)))
def getHighScoreLemon():
global high_score
# Load high score table
try:
with open('lemonade_hs.pkl', 'rb') as file:
high_score = pickle.load(file)
except FileNotFoundError:
logger.debug("System: Lemonade: No high score table found")
# high score pickle file is a touple of the nodeID and the high score
high_score = ({"userID": 4258675309, "cash": 2, "success": 0})
# write a new high score file if one is not found
with open('lemonade_hs.pkl', 'wb') as file:
pickle.dump(high_score, file)
return high_score
def start_lemonade(nodeID, message, celsius=False):
global lemonadeTracker, lemonadeCups, lemonadeLemons, lemonadeSugar, lemonadeWeeks, lemonadeScore
potential = 0
unit = 0.0
price = 0.0
high_score = getHighScoreLemon()
def saveValues():
# save playerDB values
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
lemonadeTracker[i]['cups'] = inventory.cups
lemonadeTracker[i]['lemons'] = inventory.lemons
lemonadeTracker[i]['sugar'] = inventory.sugar
lemonadeTracker[i]['cash'] = inventory.cash
lemonadeTracker[i]['start'] = inventory.start
for i in range(len(lemonadeCups)):
if lemonadeCups[i]['nodeID'] == nodeID:
lemonadeCups[i]['cost'] = cups.cost
lemonadeCups[i]['unit'] = cups.unit
for i in range(len(lemonadeLemons)):
if lemonadeLemons[i]['nodeID'] == nodeID:
lemonadeLemons[i]['cost'] = lemons.cost
lemonadeLemons[i]['unit'] = lemons.unit
for i in range(len(lemonadeSugar)):
if lemonadeSugar[i]['nodeID'] == nodeID:
lemonadeSugar[i]['cost'] = sugar.cost
lemonadeSugar[i]['unit'] = sugar.unit
for i in range(len(lemonadeWeeks)):
if lemonadeWeeks[i]['nodeID'] == nodeID:
lemonadeWeeks[i]['current'] = weeks.current
lemonadeWeeks[i]['total'] = weeks.total
lemonadeWeeks[i]['sales'] = weeks.sales
lemonadeWeeks[i]['potential'] = potential
lemonadeWeeks[i]['unit'] = unit
lemonadeWeeks[i]['price'] = price
for i in range(len(lemonadeScore)):
if lemonadeScore[i]['nodeID'] == nodeID:
lemonadeScore[i]['value'] = score.value
lemonadeScore[i]['total'] = score.total
def endGame(nodeID):
# remove the player from the tracker
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
lemonadeTracker.pop(i)
for i in range(len(lemonadeCups)):
if lemonadeCups[i]['nodeID'] == nodeID:
lemonadeCups.pop(i)
for i in range(len(lemonadeLemons)):
if lemonadeLemons[i]['nodeID'] == nodeID:
lemonadeLemons.pop(i)
for i in range(len(lemonadeSugar)):
if lemonadeSugar[i]['nodeID'] == nodeID:
lemonadeSugar.pop(i)
for i in range(len(lemonadeWeeks)):
if lemonadeWeeks[i]['nodeID'] == nodeID:
lemonadeWeeks.pop(i)
for i in range(len(lemonadeScore)):
if lemonadeScore[i]['nodeID'] == nodeID:
lemonadeScore.pop(i)
logger.debug("System: Lemonade: Game Over for " + str(nodeID))
# Check for end of game
if "end" in message.lower():
endGame(nodeID)
return "Goodbye!👋"
title="Lemonade Stand🍋"
# Define the temperature unit symbols
fahrenheit_unit = "ºF"
celsius_unit = "ºC"
# Inventory data (contains the item levels)
inventoryd = {
'cups' : 0,
'lemons' : 0,
'sugar' : 0,
'cash' : lemon_starting_cash,
'start' : lemon_starting_cash
}
inventory = SimpleNamespace(**inventoryd)
# Cups data (includes a calculated cost per unit)
cupsd = {
'cost' : 2.50, # current price
'count' : 25, # servings per box
'min' : 0.99, # minimum price
'unit' : 0.00 # unit price
}
cups = SimpleNamespace(**cupsd)
cups.unit = round(cups.cost / cups.count, 2)
# Lemons data (includes a calculated cost per unit)
lemonsd = {
'cost' : 4.00, # current price
'count' : 8, # servings per bag
'min' : 2.00, # minimum price
'unit' : 0.00 # unit price
}
lemons = SimpleNamespace(**lemonsd)
lemons.unit = round(lemons.cost / lemons.count, 2)
# Sugar data (includes a calculated cost per unit)
sugard = {
'cost' : 3.00, # current price
'count' : 15, # servings per bag
'min' : 1.50, # minimum price
'unit' : 0.00 # unit price
}
sugar = SimpleNamespace(**sugard)
sugar.unit = round(sugar.cost / sugar.count, 2)
# Weeks data (measures the session duration)
weeksd = {
'current' : 1, # start with the 1st week
'total' : 12, # span the 12 weeks of Summer
'sales' : 99, # 99 maximum sales per week
'summary' : [] # empty array
}
weeks = SimpleNamespace(**weeksd)
# Forecast data (includes percentage values, UTF8 glyphs and display names)
forecastd = OrderedDict()
forecastd['sunny'] = [1.00, 0x2600, "Sunny"]
forecastd['partly'] = [0.90, 0x26C5, "Partly Sunny"]
forecastd['cloudy'] = [0.70, 0x2601, "Mostly Cloudy"]
forecastd['rainy'] = [0.40, 0x2602, "Rainy"]
forecastd['stormy'] = [0.10, 0x26C8, "Stormy"]
# Temperature data (uses Fahrenheit as the percentage values)
temperatured = {
'min' : 69,
'max' : 100,
'units' : fahrenheit_unit,
'forecast' : None,
'value' : None
}
temperature = SimpleNamespace(**temperatured)
# Score data (based on actual vs. maximum net sales)
scored = {
'value' : 0.00,
'total' : 0.00
}
score = SimpleNamespace(**scored)
# Check for Celsius
if (celsius):
temperature.units = celsius_unit
# load playerDB values
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
inventory.cups = lemonadeTracker[i]['cups']
inventory.lemons = lemonadeTracker[i]['lemons']
inventory.sugar = lemonadeTracker[i]['sugar']
inventory.cash = lemonadeTracker[i]['cash']
inventory.start = lemonadeTracker[i]['start']
last_cmd = lemonadeTracker[i]['cmd']
for i in range(len(lemonadeCups)):
if lemonadeCups[i]['nodeID'] == nodeID:
cups.cost = lemonadeCups[i]['cost']
cups.unit = lemonadeCups[i]['unit']
for i in range(len(lemonadeLemons)):
if lemonadeLemons[i]['nodeID'] == nodeID:
lemons.cost = lemonadeLemons[i]['cost']
lemons.unit = lemonadeLemons[i]['unit']
for i in range(len(lemonadeSugar)):
if lemonadeSugar[i]['nodeID'] == nodeID:
sugar.cost = lemonadeSugar[i]['cost']
sugar.unit = lemonadeSugar[i]['unit']
for i in range(len(lemonadeWeeks)):
if lemonadeWeeks[i]['nodeID'] == nodeID:
weeks.current = lemonadeWeeks[i]['current']
weeks.total = lemonadeWeeks[i]['total']
weeks.sales = lemonadeWeeks[i]['sales']
potential = lemonadeWeeks[i]['potential']
unit = lemonadeWeeks[i]['unit']
price = lemonadeWeeks[i]['price']
for i in range(len(lemonadeScore)):
if lemonadeScore[i]['nodeID'] == nodeID:
score.value = lemonadeScore[i]['value']
score.total = lemonadeScore[i]['total']
logger.debug("System: Lemonade: Last Command: " + last_cmd)
# Start the main loop
if (weeks.current <= weeks.total):
if "new" in last_cmd:
# set the last command to cups in the inventory db
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
lemonadeTracker[i]['cmd'] = "cups"
# Create a new display buffer for the text messages
buffer= ""
# the current week number
buffer += title + "Week #" + str(weeks.current) + " of " + str(weeks.total) + " "
# Generate a random weather forecast and temperature and display
temperature.forecast = randrange(0, len(forecastd))
temperature.value = randrange(temperature.min, temperature.max)
formatted = str(temperature.value)
if (temperature.units == celsius_unit):
formatted = str(round(((temperature.value - 32) * (5/9))))
glyph = chr(forecastd[list(forecastd)[temperature.forecast]][1])
buffer += "wx: " + \
formatted + temperature.units + " " + \
forecastd[list(forecastd)[temperature.forecast]][2] + \
" " + glyph
# Calculate the potential sales as a percentage of the maximum value
# (lower temperature = fewer sales, severe weather = fewer sales)
forecast = forecastd[list(forecastd)[temperature.forecast]][0]
potential = math.floor(weeks.sales * \
(temperature.value / 100) * \
forecast)
# Update the cups cost
cups.cost = cups.cost + round(uniform(-1.50, 1.50), 2)
if (cups.cost < cups.min):
cups.cost = cups.min
cups.unit = round(cups.cost / cups.count, 2)
# Update the lemons cost
lemons.cost = lemons.cost + round(uniform(-1.50, 1.50), 2)
if (lemons.cost < lemons.min):
lemons.cost = lemons.min
lemons.unit = round(lemons.cost / lemons.count, 2)
# Update the sugar cost
sugar.cost = sugar.cost + round(uniform(-1.50, 1.50), 2)
if (sugar.cost < sugar.min):
sugar.cost = sugar.min
sugar.unit = round(sugar.cost / sugar.count, 2)
# Calculate the unit cost and display the estimated sales from the forecast potential
unit = cups.unit + lemons.unit + sugar.unit
buffer += locale.currency(unit, grouping=True) + " per cup."
buffer += " Potential Sales:" + str(potential) + " cups "
# Display the current inventory
buffer += "Inventory"
buffer += " Cups:" + str(inventory.cups)
buffer += " Lemons:" + str(inventory.lemons)
buffer += " Sugar:" + str(inventory.sugar)
# Display the updated item prices
buffer += f"\nPrices, "
buffer += "Cups:" + \
locale.currency(cups.cost, grouping=True) + " box of " + str(cups.count) + "."
buffer += " Lemons:" + \
locale.currency(lemons.cost, grouping=True) + " bag of " + str(lemons.count) + "."
buffer += " Sugar:" + \
locale.currency(sugar.cost, grouping=True) + " bag for " + str(sugar.count) + " cups. "
# Display the current cash
gainloss = inventory.cash - inventory.start
buffer += " Cash:" + \
locale.currency(inventory.cash, grouping=True)
buffer += " P&L:" + \
locale.currency(gainloss, grouping=True)
buffer += f"\nCups to buy? Have {inventory.cups}, Cost {locale.currency(cups.cost, grouping=True)}/box25"
saveValues()
return buffer
if "cups" in last_cmd:
# Read the number of cup boxes to purchase
newcups = -1
try:
newcups = int(message)
if (newcups > 0):
cost = round(newcups * cups.cost, 2)
if (cost > inventory.cash):
return "You do not have enough cash."
inventory.cups += (newcups * cups.count)
inventory.cash -= cost
msg = "Purchased " + str(newcups) + " box(es) of cups. "
msg += str(inventory.cups) + " cup inventory, " + locale.currency(inventory.cash, grouping=True) + " remaining"
else:
msg = "No cups were purchased"
except Exception as e:
msg = "invalid input"
newcups = -1
# set the last command to lemons in the inventory db
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
lemonadeTracker[i]['cmd'] = "lemons"
saveValues()
msg += f"\nLemons to buy? Have {inventory.lemons}, Cost {locale.currency(lemons.cost, grouping=True)}/bag8"
return msg
if "lemons" in last_cmd:
# Read the number of lemon bags to purchase
newlemons = -1
try:
newlemons = int(message)
if (newlemons > 0):
cost = round(newlemons * lemons.cost, 2)
if (cost > inventory.cash):
return "You do not have enough cash."
inventory.lemons += (newlemons * lemons.count)
inventory.cash -= cost
msg = "Purchased " + str(newlemons) + " bag(s) of lemons. "
msg += str(inventory.lemons) + " lemon inventory, " + locale.currency(inventory.cash, grouping=True) + " remaining"
else:
msg = "No lemons were purchased"
except Exception as e:
newlemons = -1
return "invalid input, enter the number of lemons to purchase"
# set the last command to sugar in the inventory db
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
lemonadeTracker[i]['cmd'] = "sugar"
saveValues()
msg += f"\nSugar to buy? You have {inventory.sugar} cups, Cost {locale.currency(sugar.cost, grouping=True)}/15cup bag"
return msg
if "sugar" in last_cmd:
# Read the number of sugar bags to purchase
newsugar = -1
try:
newsugar = int(message)
if (newsugar > 0):
cost = round(newsugar * sugar.cost, 2)
if (cost > inventory.cash):
return "You do not have enough cash."
inventory.sugar += (newsugar * sugar.count)
inventory.cash -= cost
msg = " Purchased " + str(newsugar) + " bag(s) of sugar for " + locale.currency(cost, grouping=True)
msg += ". " + str(inventory.sugar) + " sugar inventory, " + locale.currency(inventory.cash, grouping=True) + " cash remaining"
else:
msg = "No additional sugar was purchased"
except Exception as e:
return "invalid input, enter the number of sugar bags to purchase"
# set the last command to price in the inventory db
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
lemonadeTracker[i]['cmd'] = "price"
saveValues()
msg += f"\nPrice to Sell? Cost of goods is {locale.currency(unit, grouping=True)} per cup"
return msg
if "price" in last_cmd:
# Read the actual price
price = 0.00
while (price <= 0.00):
try:
raw = message
price = float(re.sub("[^0-9.-]", "", raw) or 0.00)
if (price <= 0.00):
return "The price must be greater than zero."
except Exception as e:
price = 0.00
return "Invalid input, enter the price of the lemonade per cup"
# this isnt sent to the user, not needed
#msg = " Setting the price at " + locale.currency(price, grouping=True)
# set the last command to sales in the inventory db
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
lemonadeTracker[i]['cmd'] = "sales"
saveValues()
last_cmd = "sales"
if "sales" in last_cmd:
# Calculate the weekly sales based on price and lowest inventory level
# (higher markup price = fewer sales, limited by the inventory on-hand)
sales = get_sales_amount(potential, unit, price)
sales = min(potential, sales, \
inventory.cups, inventory.lemons, \
inventory.sugar) # "min" returns lowest value
margin = price - unit
gross = sales * price
net = sales * margin
# Add a new row to the summary
weeks.summary.append({ 'sales' : sales, 'price' : price })
# Update the inventory levels to reflect consumption
inventory.cups = inventory.cups - sales
inventory.lemons = inventory.lemons - sales
inventory.sugar = inventory.sugar - sales
inventory.cash = inventory.cash + gross
gainloss= inventory.cash - inventory.start
# Display the calculated sales information
msg = "Results Week #" + str(weeks.current) + " of " + str(weeks.total)
msg += " Cost/Price:" + locale.currency(unit, grouping=True) + "/" + locale.currency(price, grouping=True)
msg += " P.Margin:" + locale.currency(margin, grouping=True)
msg += " T.Sales:" + str(sales) + " x " + locale.currency(price, grouping=True)
msg += " G.Profit: " + locale.currency(gross, grouping=True)
msg += " N.Profit:" + locale.currency(net, grouping=True)
# Display the updated inventory levels
msg += "\nRemaining"
msg += " Cups:" + str(inventory.cups)
msg += " Lemons:" + str(inventory.lemons)
msg += " Sugar:" + str(inventory.sugar)
msg += " Cash:" + locale.currency(inventory.cash, grouping=True)
msg += " P&L:" + locale.currency(gainloss, grouping=True)
# Display the weekly sales summary
pad_week = len(str(weeks.total))
pad_sale = len(str(weeks.sales))
total = 0
msg += "\nWeekly Summary"
for i in range(len(weeks.summary)):
msg += " Week " + str(weeks.current).rjust(pad_week) + ": " + str(weeks.summary[i]['sales']).rjust(pad_sale) + \
" sold x " + locale.currency(weeks.summary[i]['price'], grouping=True) + " ea."
total = total + weeks.summary[i]['sales']
# Loop through a range of prices to find the highest net profit
maxsales = 0
maxprice = 0.00
maxgross = 0.00
maxnet = 0.00
minnet = net
for i in range(25, 2500, 25):
price = i / 100 # range uses integers, not currency (floats)
sales = get_sales_amount(potential, unit, price)
margin = price - unit
gross = sales * price
net = sales * margin
if (sales > 0) and \
(sales <= potential) and \
(unit <= price):
if (net > maxnet):
maxsales = sales
maxprice = price
maxgross = gross
maxnet = net
if (maxnet > minnet):
msg += "Sales could have been:"
msg += " " + str(maxsales) + " sold x " + locale.currency(maxprice, grouping=True) + " ea. = " + \
locale.currency(maxgross, grouping=True) + " for a net profit of " + locale.currency(maxnet, grouping=True)
if (inventory.cups <= 0):
msg += " You ran out of cups.🥤"
if (inventory.lemons <= 0):
msg += " You ran out of lemons.🍋"
if (inventory.sugar <= 0):
msg += " You ran out of sugar.🍚"
else:
msg += "\nCongratulations -- your sales were perfect!🎉"
# Increment the score counters
score.value = score.value + minnet
score.total = score.total + maxnet
# Increment the week number
if (weeks.current == weeks.total):
# end of the game
success = round((score.value / score.total) * 100)
msg += "\nYou've made " + locale.currency(score.value, grouping=True) + " out of a possible " + \
locale.currency(score.total, grouping=True) + " for a score of " + str(success) + "% "
msg += "You've sold " + str(total) + " total cups -- see you again next time!🍋"
# check for high score
high_score = getHighScoreLemon()
if (inventory.cash > int(high_score['cash'])):
msg += "\nCongratulations! You've set a new high score!🎉💰🍋"
high_score['cash'] = inventory.cash
high_score['success'] = success
high_score['userID'] = nodeID
with open('lemonade_hs.pkl', 'wb') as file:
pickle.dump(high_score, file)
endGame()
else:
# keep playing
# set the last command to new in the inventory db
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
lemonadeTracker[i]['cmd'] = "new"
weeks.current = weeks.current + 1
msg += f"\nPlay another week? send 'end' to end game"
saveValues()
return msg
+12
View File
@@ -29,6 +29,7 @@ wiki_return_limit = 3 # limit the number of sentences returned off the first par
llmRunCounter = 0
llmTotalRuntime = []
llmLocationTable = []
playingGame = False
# Read the config file, if it does not exist, create basic config file
config = configparser.ConfigParser()
@@ -85,6 +86,7 @@ else:
# variables
try:
# general
useDMForResponse = config['general'].getboolean('respond_by_dm_only', True)
publicChannel = config['general'].getint('defaultChannel', 0) # the meshtastic public channel
zuluTime = config['general'].getboolean('zuluTime', False) # aka 24 hour time
@@ -103,12 +105,14 @@ try:
llm_enabled = config['general'].getboolean('ollama', False) # https://ollama.com
llmModel = config['general'].get('ollamaModel', 'gemma2:2b') # default gemma2:2b
# sentry
sentry_enabled = config['sentry'].getboolean('SentryEnabled', False) # default False
secure_channel = config['sentry'].getint('SentryChannel', 2) # default 2
sentry_holdoff = config['sentry'].getint('SentryHoldoff', 9) # default 9
sentryIgnoreList = config['sentry'].get('sentryIgnoreList', '').split(',')
sentry_radius = config['sentry'].getint('SentryRadius', 100) # default 100 meters
# location
location_enabled = config['location'].getboolean('enabled', True)
latitudeValue = config['location'].getfloat('lat', 48.50)
longitudeValue = config['location'].getfloat('lon', -123.0)
@@ -118,14 +122,17 @@ try:
numWxAlerts = config['location'].getint('NOAAalertCount', 2) # default 2 alerts
wxAlertsEnabled = config['location'].getboolean('NOAAalertsEnabled', True) # default True not enabled yet
# bbs
bbs_enabled = config['bbs'].getboolean('enabled', False)
bbsdb = config['bbs'].get('bbsdb', 'bbsdb.pkl')
bbs_ban_list = config['bbs'].get('bbs_ban_list', '').split(',')
bbs_admin_list = config['bbs'].get('bbs_admin_list', '').split(',')
# repeater
repeater_enabled = config['repeater'].getboolean('enabled', False)
repeater_channels = config['repeater'].get('repeater_channels', '').split(',')
# radio monitoring
radio_detection_enabled = config['radioMon'].getboolean('enabled', False)
rigControlServerAddress = config['radioMon'].get('rigControlServerAddress', 'localhost:4532') # default localhost:4532
sigWatchBroadcastCh = config['radioMon'].get('sigWatchBroadcastCh', '2').split(',') # default Channel 2
@@ -133,6 +140,11 @@ try:
signalHoldTime = config['radioMon'].getint('signalHoldTime', 10) # default 10 seconds
signalCooldown = config['radioMon'].getint('signalCooldown', 5) # default 1 second
signalCycleLimit = config['radioMon'].getint('signalCycleLimit', 5) # default 5 cycles, used with SIGNAL_COOLDOWN
# games
dopewars_enabled = config['games'].getboolean('dopeWars', True)
lemonade_enabled = config['games'].getboolean('lemonade', True)
blackjack_enabled = config['games'].getboolean('blackjack', True)
except KeyError as e:
print(f"System: Error reading config file: {e}")
+32
View File
@@ -13,6 +13,7 @@ from modules.log import *
trap_list = ("cmd","cmd?") # default trap list
help_message = "CMD?:"
asyncLoop = asyncio.new_event_loop()
games_enabled = False
# Ping Configuration
if ping_enabled:
@@ -76,6 +77,37 @@ if llm_enabled:
trap_list = trap_list + trap_list_llm # items ask:
help_message = help_message + ", askai"
# DopeWars Configuration
if dopewars_enabled:
from modules.dopewar import * # from the spudgunman/meshing-around repo
trap_list = trap_list + ("dopewars",)
games_enabled = True
# Lemonade Stand Configuration
if lemonade_enabled:
from modules.lemonade import * # from the spudgunman/meshing-around repo
trap_list = trap_list + ("lemonstand",)
games_enabled = True
# BlackJack Configuration
if blackjack_enabled:
from modules.blackjack import * # from the spudgunman/meshing-around repo
trap_list = trap_list + ("blackjack",)
games_enabled = True
# Games Configuration
if games_enabled is True:
help_message = help_message + ", games"
trap_list = trap_list + ("games",)
gamesCmdList = "CMD: "
if dopewars_enabled:
gamesCmdList += "DopeWars, "
if lemonade_enabled:
gamesCmdList += "LemonStand, "
if blackjack_enabled:
gamesCmdList += "BlackJack, "
gamesCmdList = gamesCmdList[:-2] # remove the last comma
# Scheduled Broadcast Configuration
if scheduler_enabled:
import schedule # pip install schedule