|
@@ -1,4 +1,4 @@
|
|
|
-from random import randint, gauss, shuffle
|
|
|
+from random import randint, gauss, shuffle, choices
|
|
|
from datetime import datetime, timedelta
|
|
|
import pickle
|
|
|
|
|
@@ -33,6 +33,16 @@ class RollcoinBlockchain:
|
|
|
self.puzzle = None
|
|
|
|
|
|
|
|
|
+@as_sender_singleton
|
|
|
+class RollcoinGamblingWallet:
|
|
|
+ balance: float = 0.0
|
|
|
+
|
|
|
+
|
|
|
+@as_group_singleton
|
|
|
+class RollcoinMarket:
|
|
|
+ state: str = "neutral"
|
|
|
+
|
|
|
+
|
|
|
def setup_initial_balances(plugin, db):
|
|
|
bot = plugin.bot
|
|
|
bot.logger.info("Setting up rollcoin wallets")
|
|
@@ -56,8 +66,8 @@ def setup_initial_balances(plugin, db):
|
|
|
@with_startup(setup_initial_balances)
|
|
|
@with_help("Check your balance of Rollcoins")
|
|
|
@as_plugin
|
|
|
-def balance(wallet_data: RollcoinWallet):
|
|
|
- return f"You have {wallet_data.balance} Rollcoins"
|
|
|
+def balance(wallet_data: RollcoinWallet, gambling_data: RollcoinGamblingWallet):
|
|
|
+ return f"You have {wallet_data.balance} Rollcoins in your wallet and {gambling_data.balance} Rollcoins in the market"
|
|
|
|
|
|
|
|
|
@with_help("Tip someone else some Rollcoins: !tip target amount")
|
|
@@ -73,12 +83,15 @@ def tip(msg, db, sender_wallet_data: RollcoinWallet, wallet_cfg: "rollcoin.walle
|
|
|
except ValueError:
|
|
|
return RollbotFailure.INVALID_ARGUMENTS.with_reason(f"Amount should be a number - not {raw_amount}")
|
|
|
|
|
|
+ if amount <= 0:
|
|
|
+ return RollbotFailure.INVALID_ARGUMENTS.with_reason(f"Amount should be positive")
|
|
|
+
|
|
|
target_id = wallet_cfg.get(target.lower(), None)
|
|
|
if target_id is None:
|
|
|
return RollbotFailure.INVALID_ARGUMENTS.with_reason(f"Could not find wallet-holder {target}")
|
|
|
|
|
|
if sender_wallet_data.balance < amount:
|
|
|
- return f"Insufficient funds! You need {round(amount - sender_wallet_data.balance, 2)} more Rollcoins. Have you tried to !mine or !beg?"
|
|
|
+ return f"Insufficient funds! You need {round(amount - sender_wallet_data.balance, 2)} more Rollcoins. Have you tried to !mine, !beg, or !gamble?"
|
|
|
|
|
|
target_wallet = db.query(RollcoinWallet).get(target_id)
|
|
|
if target_wallet is None:
|
|
@@ -161,4 +174,47 @@ def beg(wallet_data: RollcoinWallet, cooldown_data: RollcoinBegCooldown, cooldow
|
|
|
increase = round(abs(gauss(1, 1)), 2)
|
|
|
wallet_data.balance = wallet_data.balance + increase
|
|
|
return f"Fine, I've given you {increase} Rollcoins, which brings your balance to {wallet_data.balance}"
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+@with_help("Gamble some Rollcoins")
|
|
|
+@as_plugin
|
|
|
+def gamble(db, msg, wallet_data: RollcoinWallet, gambling_data: RollcoinGamblingWallet, market_data: RollcoinMarket, market_cfg: "rollcoin.market"):
|
|
|
+ # pos moves money wallet -> gambling, neg moves money gambling -> wallet
|
|
|
+ # market has a current state (neutral, bull, bear, boom, bust, collapse, etc.)
|
|
|
+ # after a transfer is made, the market evolves based on
|
|
|
+ # - direction of transfer (buy vs sell)
|
|
|
+ # - current market state
|
|
|
+ # - rng
|
|
|
+ # market enters new state and affects all gambling wallets, multiplying their balances
|
|
|
+ args = msg.arg_list()
|
|
|
+ if len(args) != 1:
|
|
|
+ return RollbotFailure.INVALID_ARGUMENTS.with_reason("Gambling requires exactly one argument: the amount to transfer (can be positive or negative)")
|
|
|
+
|
|
|
+ try:
|
|
|
+ amount = float(args[0])
|
|
|
+ except ValueError:
|
|
|
+ return RollbotFailure.INVALID_ARGUMENTS.with_reason(f"Amount should be a number - not {args[0]}")
|
|
|
+
|
|
|
+ if amount == 0:
|
|
|
+ return RollbotFailure.INVALID_ARGUMENTS.with_reason(f"Amount should be nonzero")
|
|
|
+
|
|
|
+ buying = amount > 0
|
|
|
+ abs_amount = abs(amount)
|
|
|
+ if buying and abs_amount > wallet_data.balance:
|
|
|
+ return f"Insufficient funds! You need {round(abs_amount - wallet_data.balance, 2)} more Rollcoins. Have you tried to !mine, !beg, or !gamble?"
|
|
|
+ elif not buying and abs_amount > gambling_data.balance:
|
|
|
+ return f"Insufficient holdings! You would need {round(abs_amount - gambling_data.balance, 2)} more Rollcoins in the market."
|
|
|
+
|
|
|
+ options = market_cfg[market_data.state]["buy" if buying else "sell"]
|
|
|
+ transition = choices(options, weights=tuple(x["weight"] for x in options))[0]
|
|
|
+ multiplier = transition["multiplier"]
|
|
|
+ market_data.state = transition["new_state"]
|
|
|
+ wallet_data.balance = wallet_data.balance - amount
|
|
|
+ gambling_data.balance = multiplier * (gambling_data.balance + amount)
|
|
|
+
|
|
|
+ for holdings in db.query(RollcoinGamblingWallet
|
|
|
+ ).filter(RollcoinGamblingWallet.sender_id != gambling_data.sender_id
|
|
|
+ ).all():
|
|
|
+ holdings.balance = multiplier * holdings.balance
|
|
|
+
|
|
|
+ return f"{transition['message']}\nYour current holdings: {gambling_data.balance}"
|