mirror of
https://github.com/barelyprofessional/KfChatDotNet.git
synced 2026-04-30 03:22:04 -04:00
- Added investments as a derivative of assets - Added profile state flags which can retain basic states like IsSponsored - Added profile state data using EF Core's JSON functionality so it should automatically serialize / deserialize the accompanying model for convenience (OnModelCreating code commented out due to the models not yet having a DbSet as I won't bake them in until KasinoShop is ready)
2114 lines
81 KiB
C#
2114 lines
81 KiB
C#
using System.Text.Json;
|
|
using KfChatDotNetBot.Extensions;
|
|
using KfChatDotNetBot.Models.DbModels;
|
|
using KfChatDotNetBot.Settings;
|
|
using NLog;
|
|
using StackExchange.Redis;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using RandN;
|
|
using RandN.Compat;
|
|
|
|
namespace KfChatDotNetBot.Services;
|
|
|
|
public class KasinoShop
|
|
{
|
|
private static RandomShim<StandardRng> _rand = RandomShim.Create(StandardRng.Create());
|
|
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
|
private IDatabase? _redisDb;
|
|
public static ChatBot BotInstance = null!;
|
|
public int[]? activeLoanIds = null;
|
|
public Dictionary<int, KasinoShopProfile> Gambler_Profiles = new(); //list of all profiles, accesesd via kf user id
|
|
public decimal DefaultHouseEdgeModifier = 0;
|
|
|
|
public KasinoShop(ChatBot kfChatBot)
|
|
{
|
|
BotInstance = kfChatBot;
|
|
|
|
var connectionString = SettingsProvider.GetValueAsync(BuiltIn.Keys.BotRedisConnectionString).Result;
|
|
if (string.IsNullOrEmpty(connectionString.Value))
|
|
{
|
|
_logger.Error($"Can't initialize the Kasino Mines service as Redis isn't configured in {BuiltIn.Keys.BotRedisConnectionString}");
|
|
return;
|
|
}
|
|
|
|
var redis = ConnectionMultiplexer.Connect(connectionString.Value);
|
|
_redisDb = redis.GetDatabase();
|
|
|
|
LoadProfiles();
|
|
|
|
}
|
|
|
|
public async void LoadProfiles()
|
|
{
|
|
if (_redisDb == null) throw new InvalidOperationException("Kasino shop service isn't initialized");
|
|
var json = await _redisDb.StringGetAsync($"Shop.Profiles.State");
|
|
var json2 = await _redisDb.StringGetAsync($"Shop.LoanIds.State");
|
|
if (string.IsNullOrEmpty(json)) return;
|
|
try
|
|
{
|
|
var options = new JsonSerializerOptions{IncludeFields = true};
|
|
Gambler_Profiles = JsonSerializer.Deserialize<Dictionary<int, KasinoShopProfile>>(json.ToString(), options) ??
|
|
throw new InvalidOperationException();
|
|
activeLoanIds = JsonSerializer.Deserialize<int[]>(json2.ToString(), options) ?? throw new InvalidOperationException();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_logger.Error(e);
|
|
_logger.Error("Potentially failed to deserialize kasinoshop details");
|
|
Gambler_Profiles = new Dictionary<int, KasinoShopProfile>();
|
|
activeLoanIds = new int[0];
|
|
}
|
|
}
|
|
|
|
public async Task SaveProfiles()
|
|
{
|
|
if (_redisDb == null) throw new InvalidOperationException("Kasino mines service isn't initialized");
|
|
var options = new JsonSerializerOptions
|
|
{
|
|
IncludeFields = true,
|
|
WriteIndented = false
|
|
};
|
|
var json = JsonSerializer.Serialize(Gambler_Profiles, options);
|
|
var json2 = JsonSerializer.Serialize(activeLoanIds, options);
|
|
await _redisDb.StringSetAsync($"Shop.Profiles.State", json, null, When.Always);
|
|
await _redisDb.StringSetAsync($"Shop.LoanIds.State", json2, null, When.Always);
|
|
}
|
|
|
|
public async Task ResetProfiles()
|
|
{
|
|
Gambler_Profiles = new Dictionary<int, KasinoShopProfile>();
|
|
activeLoanIds = new int[0];
|
|
await SaveProfiles();
|
|
}
|
|
|
|
|
|
public async Task PrintBalance(GamblerDbModel gambler)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
}
|
|
|
|
public async Task ResetAllLoans()
|
|
{
|
|
foreach (var key in Gambler_Profiles.Keys)
|
|
{
|
|
Gambler_Profiles[key].Loans.Clear();
|
|
}
|
|
await SaveProfiles();
|
|
}
|
|
|
|
public async Task GetCurrentRiggingState()
|
|
{
|
|
string str = "";
|
|
List<decimal> values = new() { 1.02m, -0.9m, 0 };
|
|
List<decimal> differences = new() {values[0] - DefaultHouseEdgeModifier, values[1] - DefaultHouseEdgeModifier, values[2] - DefaultHouseEdgeModifier };
|
|
if (DefaultHouseEdgeModifier == 1.02m)
|
|
{
|
|
await BotInstance.SendChatMessageAsync("The switch was flipped twice.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
else if (DefaultHouseEdgeModifier == -0.9m)
|
|
{
|
|
await BotInstance.SendChatMessageAsync("The switch was flipped once.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
else if (DefaultHouseEdgeModifier == 0)
|
|
{
|
|
await BotInstance.SendChatMessageAsync("The button is pressed.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
var currentDHEM = DefaultHouseEdgeModifier;
|
|
|
|
|
|
while (currentDHEM != 0)
|
|
{
|
|
var ld = LowestDifferenceIndex(differences);
|
|
if (ld.i == 0)
|
|
{
|
|
str += "A switch was flipped twice.[br]";
|
|
currentDHEM -= values[ld.i];
|
|
}
|
|
else if (ld.i == 1)
|
|
{
|
|
str += "A switch was flipped once.[br]";
|
|
currentDHEM -= values[ld.i];
|
|
}
|
|
else if (ld.i == 2)
|
|
{
|
|
if (ld.d < 0)
|
|
{
|
|
currentDHEM += 0.01m;
|
|
str += "A dial was moved down.[br]";
|
|
}
|
|
else
|
|
{
|
|
currentDHEM -= 0.01m;
|
|
str += "A dial was moved up.[br]";
|
|
}
|
|
}
|
|
differences = new() {values[0] - DefaultHouseEdgeModifier, values[1] - DefaultHouseEdgeModifier, values[2] - DefaultHouseEdgeModifier };
|
|
}
|
|
await BotInstance.SendChatMessageAsync(str, true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
|
|
(int i, decimal d) LowestDifferenceIndex(List<decimal> diffs)
|
|
{
|
|
var lowestDifference = Math.Abs(differences[0]);
|
|
var lowestDifferenceIndex = 0;
|
|
if (Math.Abs(diffs[1]) < lowestDifference)
|
|
{
|
|
lowestDifference = Math.Abs(differences[1]);
|
|
lowestDifferenceIndex = 1;
|
|
}
|
|
|
|
if (Math.Abs(diffs[2]) < lowestDifference)
|
|
{
|
|
lowestDifference = Math.Abs(differences[2]);
|
|
lowestDifferenceIndex = 2;
|
|
}
|
|
|
|
return (lowestDifferenceIndex, lowestDifference);
|
|
}
|
|
}
|
|
public async Task ProcessRigging(Rigging type, decimal num = -1, bool? dial = null)
|
|
{
|
|
/*
|
|
* FLIP SWITCH - variate default house edge modifier to -0.9, then to 1.02 if it's currently -0.9
|
|
*
|
|
* PUSH BUTTON - reset house edge modifier to 0
|
|
*
|
|
* DIAL UP/DOWN - decrease or increase default house edge modifier by 0.01
|
|
*
|
|
* PULL LEVER - does nothing
|
|
*
|
|
* KEYPAD <num> - sets the house edge modifier to num
|
|
*/
|
|
var oldDefault = DefaultHouseEdgeModifier;
|
|
decimal difference = 0;
|
|
switch (type)
|
|
{
|
|
case Rigging.Lever:
|
|
await BotInstance.SendChatMessageAsync("A lever was pulled.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
await Task.Delay(TimeSpan.FromMinutes(5));
|
|
await BotInstance.SendChatMessageAsync("A lever returned to its original position.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
break;
|
|
case Rigging.Keypad:
|
|
if (num == -1) throw new Exception("Invalid number passed into keypad");
|
|
DefaultHouseEdgeModifier = num;
|
|
difference = DefaultHouseEdgeModifier - oldDefault;
|
|
await BotInstance.SendChatMessageAsync("Keypad value accepted.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
break;
|
|
case Rigging.Switch:
|
|
if (DefaultHouseEdgeModifier != -0.9m)
|
|
{
|
|
DefaultHouseEdgeModifier = -0.9m;
|
|
}
|
|
else DefaultHouseEdgeModifier = 1.02m;
|
|
difference = DefaultHouseEdgeModifier - oldDefault;
|
|
await BotInstance.SendChatMessageAsync("A switch was flipped.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
break;
|
|
case Rigging.Button:
|
|
DefaultHouseEdgeModifier = 0;
|
|
difference = DefaultHouseEdgeModifier - oldDefault;
|
|
break;
|
|
case Rigging.Dial:
|
|
if (dial == null) throw new Exception("Invalid dial value passed into dial");
|
|
if (dial.Value)
|
|
{
|
|
DefaultHouseEdgeModifier += 0.01m;
|
|
}
|
|
else DefaultHouseEdgeModifier -= 0.01m;
|
|
difference = DefaultHouseEdgeModifier - oldDefault;
|
|
break;
|
|
}
|
|
foreach (var key in Gambler_Profiles.Keys)
|
|
{
|
|
Gambler_Profiles[key].HouseEdgeModifier += difference;
|
|
}
|
|
await SaveProfiles();
|
|
}
|
|
|
|
public decimal GetCurrentCrackPrice(GamblerDbModel gambler)
|
|
{
|
|
return CrackPrice * Gambler_Profiles[gambler.User.KfId].CrackCounter;
|
|
}
|
|
|
|
public async Task PrintDrugMarket(GamblerDbModel gambler)
|
|
{
|
|
int cc = Gambler_Profiles[gambler.User.KfId].CrackCounter;
|
|
List<string> drugs = new();
|
|
var crackPrice = CrackPrice * cc;
|
|
drugs.Add($"1. Crack: {await crackPrice.FormatKasinoCurrencyAsync()} per dose");
|
|
drugs.Add($"2. Weed: {await WeedPricePerHour.FormatKasinoCurrencyAsync()} per hour");
|
|
if (Gambler_Profiles[gambler.User.KfId].FloorNugs > 0)
|
|
{
|
|
drugs.Add($"3. Floor Nugs: {Gambler_Profiles[gambler.User.KfId].FloorNugs}");
|
|
}
|
|
}
|
|
|
|
public bool CheckWagerReq(GamblerDbModel gambler)
|
|
{
|
|
if (Gambler_Profiles[gambler.User.KfId].SponsorWagerLock[0] >
|
|
Gambler_Profiles[gambler.User.KfId].SponsorWagerLock[1]) return false;
|
|
return true;
|
|
}
|
|
|
|
public decimal RemainingWagerReq(GamblerDbModel gambler)
|
|
{
|
|
return Gambler_Profiles[gambler.User.KfId].SponsorWagerLock[0] - Gambler_Profiles[gambler.User.KfId].SponsorWagerLock[1];
|
|
}
|
|
|
|
public async Task ProcessDrugUse(GamblerDbModel gambler, decimal amount, int drug)
|
|
{
|
|
Dictionary<int, string> drugs = new()
|
|
{
|
|
{1, "Crack"},
|
|
{2, "Weed"},
|
|
{3, "Floor Nugs"}
|
|
};
|
|
if (drug != 3)
|
|
{
|
|
if (Gambler_Profiles[gambler.User.KfId].Balance()[0] < amount)
|
|
{
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you can't afford to buy {await amount.FormatKasinoCurrencyAsync()} worth of {drugs[drug]}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Gambler_Profiles[gambler.User.KfId].FloorNugs < amount)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you only have {Gambler_Profiles[gambler.User.KfId].FloorNugs} floor nugs, so that's all you could smoke right now.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
amount = Gambler_Profiles[gambler.User.KfId].FloorNugs;
|
|
}
|
|
}
|
|
|
|
if (drug == 1)
|
|
{
|
|
_ = Gambler_Profiles[gambler.User.KfId].SmokeCrack();
|
|
}
|
|
else if (drug == 2)
|
|
{
|
|
TimeSpan weedDuration = TimeSpan.FromHours((double)(amount / WeedPricePerHour));
|
|
_ = Gambler_Profiles[gambler.User.KfId].SmokeWeed(weedDuration);
|
|
}
|
|
else
|
|
{
|
|
TimeSpan dur = TimeSpan.FromMinutes(6 * (int)amount);
|
|
_ = Gambler_Profiles[gambler.User.KfId].SmokeWeed(dur);
|
|
}
|
|
}
|
|
|
|
public async Task<bool> ProcessLoan(int receiverKfId, decimal amount, GamblerDbModel gUser, int senderGamblerId)
|
|
{
|
|
var sender = gUser.User;
|
|
//check if the person they tried to loan to is able to get a loan
|
|
await using var db = new ApplicationDbContext();
|
|
var targetUser = await db.Users.FirstOrDefaultAsync(u => u.KfId == receiverKfId);
|
|
if (targetUser == null)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{sender.FormatUsername()}, user with KF ID {receiverKfId} not found.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return false;
|
|
}
|
|
if (!Gambler_Profiles[receiverKfId].IsLoanable)
|
|
{
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{sender.FormatUsername()}, {targetUser.FormatUsername()} is not loanable, they need to beg for a loan first.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return false;
|
|
}
|
|
//check if the loaner has enough crypto to send loan
|
|
if (Gambler_Profiles[sender.KfId].Balance()[1] < amount)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{sender.FormatUsername()}, you don't have enough krypto to loan {targetUser.FormatUsername()}. {amount}. {await Gambler_Profiles[sender.KfId].FormatBalanceAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return false;
|
|
}
|
|
|
|
Random rand = new Random();
|
|
int loanId = (int)(1000000000 * rand.NextDouble());
|
|
if (activeLoanIds == null) activeLoanIds = new int[1];
|
|
else
|
|
{
|
|
int[] newLoans = new int[activeLoanIds.Length + 1];
|
|
activeLoanIds.CopyTo(newLoans, 1);
|
|
newLoans[0] = loanId;
|
|
activeLoanIds = newLoans;
|
|
}
|
|
await using var gamblerdb = new ApplicationDbContext();
|
|
var targetgambler = await gamblerdb.Gamblers.FirstOrDefaultAsync(g => g.User.KfId == Gambler_Profiles[receiverKfId].GamblerId);
|
|
if (targetgambler == null)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{sender.FormatUsername()}, gambler profile for user with KF ID {receiverKfId} not found.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return false;
|
|
}
|
|
//public Loan(decimal amount, int payableToGambler, int payableToKf, int recieverGambler, int recieverKf, int Id)
|
|
Loan loan = new Loan(amount, senderGamblerId, sender.Id, targetgambler.Id, receiverKfId, loanId, sender);
|
|
//take from senders crypto balance and deposit into receivers kasino balance
|
|
Gambler_Profiles[sender.KfId].ModifyBalance(-amount);
|
|
await Money.ModifyBalanceAsync(targetgambler.Id, amount, TransactionSourceEventType.Loan);
|
|
Gambler_Profiles[sender.KfId].Loans.Add(loanId, loan);
|
|
Gambler_Profiles[receiverKfId].Loans.Add(loanId, loan);
|
|
Gambler_Profiles[receiverKfId].OutstandingLoanBalance += amount;
|
|
Gambler_Profiles[receiverKfId].IsLoanable = false;
|
|
Gambler_Profiles[receiverKfId].KreditScore -= Convert.ToInt32(amount / 2);
|
|
await SaveProfiles();
|
|
return true;
|
|
}
|
|
|
|
public async Task PrintSmashableShop(GamblerDbModel gambler)
|
|
{
|
|
string str = "";
|
|
int counter = 1;
|
|
foreach (var type in Enum.GetValues<SmashableType>())
|
|
{
|
|
str += $"{counter}: {type} - $10000 KKK[br]";
|
|
}
|
|
}
|
|
|
|
public async Task ProcessSmashablePurchase(GamblerDbModel gambler, int type)
|
|
{
|
|
var smashTypes = Enum.GetValues<SmashableType>();
|
|
type--;
|
|
if (type < 0 || type > smashTypes.Length - 1)
|
|
{
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, invalid smashable type. 1 - {smashTypes.Length}", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
if (Gambler_Profiles[gambler.User.KfId].Balance()[1] < 10000)
|
|
{
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you don't have enough krypto to buy smashables. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
return;
|
|
}
|
|
var id = GenerateRandomId(gambler);
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Add(id, new Smashable(id, 10000, smashTypes[type]));
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(-10000);
|
|
}
|
|
public async Task ProcessRepayment(GamblerDbModel payerGambler, UserDbModel payer, int payeeKfId, decimal amount) //loans can be repaid from crypto balance and kasino balance. it prefers to take from your crypto balance first if you have any
|
|
{
|
|
decimal payerTotalBalance = payerGambler.Balance + Gambler_Profiles[payer.KfId].Balance()[0];
|
|
if (payerTotalBalance < amount)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{payer.FormatUsername()}, you don't have enough to repay {await amount.FormatKasinoCurrencyAsync()}. Your total balance: {await payerTotalBalance.FormatKasinoCurrencyAsync()}");
|
|
return;
|
|
}
|
|
|
|
|
|
int loanId = -1;
|
|
//find the loan
|
|
foreach (var loan in Gambler_Profiles[payeeKfId].Loans.Values)
|
|
{
|
|
if (loan.payableToKf == payer.KfId)
|
|
{
|
|
loanId = loan.Id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (loanId == -1)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{payer.FormatUsername()}, you don't have a loan with {payeeKfId}.");
|
|
return;
|
|
}
|
|
var theloan = Gambler_Profiles[payeeKfId].Loans[loanId];
|
|
//compare the amount paid to the amount of the loan
|
|
if (amount >= theloan.payoutAmount)
|
|
{
|
|
//if the amount is more or equal, clear the loan when you pay, and give the payer credit score bonus for repaying the loan
|
|
amount = theloan.payoutAmount;
|
|
Gambler_Profiles[payer.KfId].KreditScore += Convert.ToInt32(Gambler_Profiles[payer.KfId].Loans[loanId].amount * 3 / 4);
|
|
Gambler_Profiles[payer.KfId].Loans.Remove(loanId);
|
|
Gambler_Profiles[payeeKfId].Loans.Remove(loanId);
|
|
var newLoans = new int[activeLoanIds!.Length - 1];
|
|
if (activeLoanIds.Length > 1)
|
|
{
|
|
for (int i = 0; i < activeLoanIds.Length - 1; i++)
|
|
{
|
|
if (activeLoanIds[i] != loanId) newLoans[i] = activeLoanIds[i];
|
|
}
|
|
}
|
|
activeLoanIds = newLoans;
|
|
}
|
|
else if (amount < Gambler_Profiles[payeeKfId].Loans[loanId].payoutAmount)
|
|
{
|
|
Gambler_Profiles[payeeKfId].Loans[loanId].payoutAmount -= amount;
|
|
}
|
|
//split the amount from crypto and kasino balance as available
|
|
decimal takeFromCrypto = 0;
|
|
decimal takeFromKasino = 0;
|
|
|
|
if (amount > Gambler_Profiles[payeeKfId].Balance()[0])
|
|
{
|
|
//if the amount is more than the amount of crypto you have, take from kasino balance as well
|
|
takeFromCrypto = Gambler_Profiles[payeeKfId].Balance()[0];
|
|
takeFromKasino = amount - takeFromCrypto;
|
|
}
|
|
else takeFromCrypto = amount;
|
|
//process the payments
|
|
Gambler_Profiles[payer.KfId].ModifyBalance(-takeFromCrypto);
|
|
await Money.ModifyBalanceAsync(payerGambler.Id, -takeFromKasino, TransactionSourceEventType.Loan);
|
|
Gambler_Profiles[payeeKfId].ModifyBalance(amount);
|
|
await SaveProfiles();
|
|
}
|
|
|
|
public async Task PrintLoansList(GamblerDbModel gambler)
|
|
{
|
|
var user = gambler.User;
|
|
string message = $"{user.FormatUsername()}";
|
|
var msg = await BotInstance.SendChatMessageAsync($"{message}", true);
|
|
await BotInstance.WaitForChatMessageAsync(msg);
|
|
if (Gambler_Profiles[user.KfId].Loans.Count == 0)
|
|
{
|
|
message += " is debt free!";
|
|
await BotInstance.KfClient.EditMessageAsync(msg.ChatMessageUuid, message);
|
|
await Task.Delay(TimeSpan.FromSeconds(10));
|
|
await BotInstance.KfClient.DeleteMessageAsync(msg.ChatMessageUuid);
|
|
return;
|
|
}
|
|
|
|
foreach (var loan in Gambler_Profiles[user.KfId].Loans.Values)
|
|
{
|
|
message += $"[br]{await loan.ToStringAsync(gambler.User.KfId)}";
|
|
await BotInstance.KfClient.EditMessageAsync(msg.ChatMessageUuid, message);
|
|
await Task.Delay(10);
|
|
}
|
|
await Task.Delay(TimeSpan.FromSeconds(10));
|
|
await BotInstance.KfClient.DeleteMessageAsync(msg.ChatMessageUuid);
|
|
}
|
|
|
|
|
|
public async Task ProcessBeg(GamblerDbModel gambler)
|
|
{
|
|
var user = gambler.User;
|
|
_ = Gambler_Profiles[user.KfId].Beg(user);
|
|
}
|
|
|
|
public async Task ProcessWithdraw(GamblerDbModel gambler, decimal amount)
|
|
{
|
|
int kfId = gambler.User.KfId;
|
|
if (amount > gambler.Balance)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you don't have enough to withdraw {await amount.FormatKasinoCurrencyAsync()}. Balance: {await gambler.Balance.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
Gambler_Profiles[gambler.User.KfId].Withdraw(amount);
|
|
var newBalance = await Money.ModifyBalanceAsync(gambler.Id, amount, TransactionSourceEventType.Withdraw);
|
|
await SaveProfiles();
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you withdrew {await amount.FormatKasinoCurrencyAsync()} to your krypto balance. Kasino Balance: {await newBalance.FormatKasinoCurrencyAsync()} | {await Gambler_Profiles[kfId].FormatBalanceAsync()}",
|
|
true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
|
|
}
|
|
|
|
public async Task ProcessDeposit(GamblerDbModel gambler, decimal amount)
|
|
{
|
|
int kfId = gambler.User.KfId;
|
|
if (amount > Gambler_Profiles[kfId].Balance()[0])
|
|
{
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you don't have enough krypto to deposit {await amount.FormatKasinoCurrencyAsync()}. {await Gambler_Profiles[kfId].FormatBalanceAsync()}");
|
|
return;
|
|
}
|
|
var newBalance = await Money.ModifyBalanceAsync(gambler.Id, amount, TransactionSourceEventType.Deposit);
|
|
Gambler_Profiles[kfId].Deposit(amount);
|
|
await SaveProfiles();
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you deposited {await amount.FormatKasinoCurrencyAsync()} to your kasino balance. Kasino Balance: {await newBalance.FormatKasinoCurrencyAsync()} | {await Gambler_Profiles[kfId].FormatBalanceAsync()}",
|
|
true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
|
|
}
|
|
|
|
public async Task ProcessInvestment(GamblerDbModel gambler, int item, decimal amount)
|
|
{
|
|
if (amount > Gambler_Profiles[gambler.User.KfId].Balance()[1])
|
|
{
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you can't afford this investment. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
if (item < 1 || item > 3)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, invalid investment choice. 1 - gold, 2 - silver, 3 - house.",true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
int id = GenerateRandomId(gambler);
|
|
|
|
string str;
|
|
switch (item)
|
|
{
|
|
case 1:
|
|
str = Money.GetRandomDouble(gambler) < 0.5 ? "chain" : "coin";
|
|
Investment newGold = new Investment(id, amount, GoldInterestRange, InvestmentType.Gold, $"Gold {str}");
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Add(id, newGold);
|
|
break;
|
|
case 2:
|
|
str = Money.GetRandomDouble(gambler) < 0.5 ? "chain" : "coin";
|
|
Investment newSilver = new Investment(id, amount, SilverInterestRange, InvestmentType.Silver, $"Silver {str}");
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Add(id, newSilver);
|
|
break;
|
|
case 3:
|
|
Investment newHouse = new Investment(id, amount, HouseInterestRange, InvestmentType.House, "House");
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Add(id, newHouse);
|
|
break;
|
|
}
|
|
|
|
await SaveProfiles();
|
|
}
|
|
|
|
|
|
|
|
public async Task ProcessCarPurchase(GamblerDbModel gambler, int carId)
|
|
{
|
|
//civic audi bentley bmw
|
|
foreach (var asset in Gambler_Profiles[gambler.User.KfId].Assets.Values)
|
|
{
|
|
if (asset is Car c)
|
|
{
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you can't buy a car you already have one: {c}.", true,
|
|
autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
}
|
|
var car = DefaultCars.ElementAt(carId).Value;
|
|
car.SetId(gambler);
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Add(car.Id, car);
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you bought {car}", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
await SaveProfiles();
|
|
}
|
|
|
|
public void ProcessLossBackTracking(GamblerDbModel gambler, decimal amount)
|
|
{
|
|
Gambler_Profiles[gambler.User.KfId].Tracker.AddLossback(amount);
|
|
}
|
|
|
|
public async Task ProcessWorkJob(GamblerDbModel gambler)
|
|
{
|
|
bool hasCar = false;
|
|
int carId = -1;
|
|
foreach (var assetKey in Gambler_Profiles[gambler.User.KfId].Assets.Keys)
|
|
{
|
|
if (Gambler_Profiles[gambler.User.KfId].Assets[assetKey] is Car car)
|
|
{
|
|
carId = assetKey;
|
|
hasCar = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!hasCar)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you don't have a car to get a job with.", true, autoDeleteAfter:TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
await ((Car)(Gambler_Profiles[gambler.User.KfId].Assets[carId])).ProcessWorkJob(gambler);
|
|
await SaveProfiles();
|
|
}
|
|
public async Task ProcessWagerTracking(GamblerDbModel gambler, WagerGame game, decimal amount, decimal net, decimal newBalance)
|
|
{
|
|
Gambler_Profiles[gambler.User.KfId].Tracker.AddWager(game, amount, net);
|
|
if (newBalance < 1 && Gambler_Profiles[gambler.User.KfId].SponsorWagerLock[0] > 0) //if you ran out of money after that gamble reset your wager lock
|
|
{
|
|
Gambler_Profiles[gambler.User.KfId].SponsorWagerLock = new decimal[] { 0, 0 };
|
|
}
|
|
|
|
if (Gambler_Profiles[gambler.User.KfId].SponsorWagerLock[0] >
|
|
Gambler_Profiles[gambler.User.KfId].SponsorWagerLock[1])
|
|
{
|
|
Gambler_Profiles[gambler.User.KfId].SponsorWagerLock = new decimal[] { 0, 0 };
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you have reached the wager requirement for your sponsorship!", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
}
|
|
await SaveProfiles();
|
|
}
|
|
|
|
public async Task ProcessJuicerOrRainTracking(GamblerDbModel sender, GamblerDbModel reciever, decimal amountPerReciever)
|
|
{
|
|
Gambler_Profiles[sender.User.KfId].Tracker.AddWithdrawal(amountPerReciever);
|
|
if (Gambler_Profiles.ContainsKey(reciever.User.KfId)) Gambler_Profiles[reciever.User.KfId].Tracker.AddDeposit(amountPerReciever);
|
|
if (Gambler_Profiles.ContainsKey(sender.User.KfId)) Gambler_Profiles[sender.User.KfId].Tracker.AddWithdrawal(amountPerReciever);
|
|
await SaveProfiles();
|
|
}
|
|
|
|
public async Task ProcessStake(GamblerDbModel gambler, decimal amount)
|
|
{
|
|
//check if they have enough crypto for the stake
|
|
if (Gambler_Profiles[gambler.User.KfId].Balance()[1] < amount)
|
|
{
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you don't have enough krypto to stake {await amount.FormatKasinoCurrencyAsync()}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}",true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
int id = GenerateRandomId(gambler);
|
|
|
|
var stake = new Investment(id, amount, CryptoStakeInterestRange, InvestmentType.Stake, "Stake");
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Add(id, stake);
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(-amount);
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you staked {await amount.FormatKasinoCurrencyAsync()} krypto.[br] {Gambler_Profiles[gambler.User.KfId].Assets[id]} {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
await SaveProfiles();
|
|
}
|
|
|
|
public async Task ProcessSponsorship(GamblerDbModel gambler)
|
|
{
|
|
if (Gambler_Profiles[gambler.User.KfId].IsSponsored)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you are already sponsored.", true,
|
|
autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
Gambler_Profiles[gambler.User.KfId].IsSponsored = true;
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you are now sponsored! You can claim your bonus every day with !sponsor bonus", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
await SaveProfiles();
|
|
}
|
|
|
|
public async Task ProcessSponsorshipEnd(GamblerDbModel gambler)
|
|
{
|
|
Gambler_Profiles[gambler.User.KfId].IsSponsored = false;
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you are no longer sponsored!", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
await SaveProfiles();
|
|
}
|
|
|
|
public async Task ProcessSponsorBonus(GamblerDbModel gambler)
|
|
{
|
|
Gambler_Profiles[gambler.User.KfId].ProcessSponsorBonus(KASINO_SPONSOR_BONUS);
|
|
Gambler_Profiles[gambler.User.KfId].SponsorWagerLock[1] += KASINO_SPONSOR_BONUS;
|
|
Gambler_Profiles[gambler.User.KfId].lastSponsorBonus = DateTime.UtcNow;
|
|
var newBalance = await Money.ModifyBalanceAsync(gambler.Id, KASINO_SPONSOR_BONUS, TransactionSourceEventType.Sponsorship);
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you claimed your sponsor bonus of {await KASINO_SPONSOR_BONUS.FormatKasinoCurrencyAsync()}. Balance: {await newBalance.FormatKasinoCurrencyAsync()}");
|
|
await SaveProfiles();
|
|
}
|
|
public async Task UnStake(GamblerDbModel gambler, decimal amount = -1, int assetId = -1, bool all = false)
|
|
{
|
|
bool noId = assetId == -1;
|
|
//check if they have a stake
|
|
int stakeCounter = 0;
|
|
bool validId = false;
|
|
foreach (var asset in Gambler_Profiles[gambler.User.KfId].Assets.Values)
|
|
{
|
|
if (asset is Investment inv && inv.investment_type == InvestmentType.Stake)
|
|
{
|
|
stakeCounter++;
|
|
if (assetId == -1) assetId = inv.Id;
|
|
if (assetId == inv.Id) validId = true;
|
|
}
|
|
}
|
|
if (stakeCounter == 0)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you don't have a stake to unstake.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
if (!validId)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you don't have a stake with that ID.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
Investment stake;
|
|
int cooldown;
|
|
decimal value;
|
|
decimal totalStakedValue = 0;
|
|
if (all || amount >= totalStakedValue)
|
|
{
|
|
bool success = false;
|
|
foreach (var asset in Gambler_Profiles[gambler.User.KfId].Assets.Values)
|
|
{
|
|
if (asset is Investment inv && inv.investment_type == InvestmentType.Stake)
|
|
{
|
|
stake = inv;
|
|
value = stake.GetCurrentValue();
|
|
totalStakedValue += value;
|
|
cooldown = (DateTime.UtcNow - inv.acquired).Days;
|
|
if (cooldown > 7)
|
|
{
|
|
success = true;
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Remove(asset.Id);
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(value);
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()} unstaked {stake}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!success)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you don't have any stakes that are ready to be unstaked.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
}
|
|
else if (stakeCounter == 1)
|
|
{
|
|
stake = (Investment)Gambler_Profiles[gambler.User.KfId].Assets[assetId];
|
|
value = stake.GetCurrentValue();
|
|
cooldown = (DateTime.UtcNow - stake.acquired).Days;
|
|
if (cooldown < 7)
|
|
{
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you can't unstake your stake yet, {7-cooldown} days until it unlocks.");
|
|
}
|
|
|
|
if (amount == -1 || amount >= value)
|
|
{
|
|
//unstake the whole thing if no amount or if amount is greater than its value
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Remove(assetId);
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(value);
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()} unstaked {stake}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
}
|
|
else
|
|
{
|
|
((Investment)Gambler_Profiles[gambler.User.KfId].Assets[assetId]).StakePartialSale(amount);
|
|
stake = ((Investment)Gambler_Profiles[gambler.User.KfId].Assets[assetId]);
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(amount);
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()} partially unstaked {stake}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
}
|
|
|
|
}
|
|
else //if you have multiple stakes
|
|
{
|
|
stake = (Investment)Gambler_Profiles[gambler.User.KfId].Assets[assetId];
|
|
value = stake.GetCurrentValue();
|
|
if (amount == -1)
|
|
{
|
|
//unstake whole stake based on the id
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Remove(assetId);
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(value);
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()} unstaked {stake}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
}
|
|
else
|
|
{
|
|
var originalAmount = amount;
|
|
if (noId)
|
|
{
|
|
|
|
foreach (var asset in Gambler_Profiles[gambler.User.KfId].Assets.Values)
|
|
{
|
|
if (asset is Investment inv && inv.investment_type == InvestmentType.Stake)
|
|
{
|
|
value = inv.GetCurrentValue();
|
|
if (amount >= value)
|
|
{
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Remove(assetId);
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(value);
|
|
amount -= value;
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()} unstaked {stake}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
}
|
|
else
|
|
{
|
|
((Investment)Gambler_Profiles[gambler.User.KfId].Assets[assetId]).StakePartialSale(amount);
|
|
stake = ((Investment)Gambler_Profiles[gambler.User.KfId].Assets[assetId]);
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(amount);
|
|
amount = 0;
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, partially unstaked {stake}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, successfully unstaked {await originalAmount.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//partially unstake based on ID
|
|
((Investment)Gambler_Profiles[gambler.User.KfId].Assets[assetId]).StakePartialSale(amount);
|
|
stake = ((Investment)Gambler_Profiles[gambler.User.KfId].Assets[assetId]);
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(amount);
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()} partially unstaked {stake}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
}
|
|
}
|
|
}
|
|
await SaveProfiles();
|
|
}
|
|
public async Task ProcessAssetSale(GamblerDbModel gambler, int assetId)
|
|
{
|
|
if (!Gambler_Profiles[gambler.User.KfId].Assets.ContainsKey(assetId))
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you don't have any assets with id {assetId}.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
var asset = Gambler_Profiles[gambler.User.KfId].Assets[assetId];
|
|
int cooldown;
|
|
if (asset is Investment inv)
|
|
{
|
|
switch (inv.investment_type)
|
|
{
|
|
case InvestmentType.Gold or InvestmentType.Silver:
|
|
cooldown = (DateTime.UtcNow - inv.acquired).Days;
|
|
if (cooldown < 5)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you can't sell your {inv.investment_type} investment yet, It's been less than 5 days since you bought it. {cooldown} days until it arrives.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
break;
|
|
case InvestmentType.Stake:
|
|
cooldown = (DateTime.UtcNow - inv.acquired).Days;
|
|
if (cooldown < 7)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you can't sell your Stake yet, {7-cooldown} days until it unlocks.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
else if (asset is Smashable smash)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, nobody wants to buy your shitty {smash}.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Remove(assetId);
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(asset.GetCurrentValue());
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()} sold {asset}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
await SaveProfiles();
|
|
}
|
|
|
|
|
|
public async Task ProcessSkinPurchase(GamblerDbModel gambler, int num)
|
|
{
|
|
//first confirm sufficient balance
|
|
var skin = BotInstance.BotServices.KasinoShop!.Gambler_Profiles[gambler.User.KfId].sMarket.GetSkins(gambler)[num];
|
|
if (BotInstance.BotServices.KasinoShop!.Gambler_Profiles[gambler.User.KfId].Balance()[1] < skin.originalValue)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you don't have enough krypto to buy this skin. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
BotInstance.BotServices.KasinoShop!.Gambler_Profiles[gambler.User.KfId].ModifyBalance(-skin.originalValue);
|
|
BotInstance.BotServices.KasinoShop!.Gambler_Profiles[gambler.User.KfId].Assets.Add(skin.Id, skin);
|
|
BotInstance.BotServices.KasinoShop!.Gambler_Profiles[gambler.User.KfId].sMarket.SellsSkinTo(gambler, num);
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you bought {skin}. {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
await SaveProfiles();
|
|
}
|
|
public async Task PrintSkinMarket(GamblerDbModel gambler)
|
|
{
|
|
string str = $"{gambler.User.FormatUsername()}'s skins:[br]";
|
|
var profile = Gambler_Profiles[gambler.User.KfId];
|
|
var skins = profile.sMarket.GetSkins(gambler);
|
|
for (int i = 0; i < skins.Count; i++)
|
|
{
|
|
str += $"{i + 1}: {skins[i]}[br]";
|
|
}
|
|
await BotInstance.SendChatMessageAsync(str, true, autoDeleteAfter: TimeSpan.FromSeconds(15));
|
|
}
|
|
|
|
|
|
public async Task PrintShoeMarket(GamblerDbModel gambler)
|
|
{
|
|
string str = "Shoes for sale:[br]";
|
|
var shoeMarket = Gambler_Profiles[gambler.User.KfId].shMarket;
|
|
int counter = 1;
|
|
foreach (var shoe in shoeMarket.GetShoes(gambler))
|
|
{
|
|
str += $"{counter}: {shoe}[br]";
|
|
counter++;
|
|
}
|
|
await BotInstance.SendChatMessageAsync(str, true, autoDeleteAfter: TimeSpan.FromSeconds(15));
|
|
}
|
|
public async Task ProcessShoePurchase(GamblerDbModel gambler, int num)
|
|
{
|
|
//yeezy adidas jordan
|
|
|
|
var shoeMarket = Gambler_Profiles[gambler.User.KfId].shMarket;
|
|
var shoe = shoeMarket.GetShoes(gambler)[num];
|
|
|
|
if (Gambler_Profiles[gambler.User.KfId].Balance()[1] < shoe.originalValue)
|
|
{
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()}, you don't have enough krypto to buy {shoe}.[br] {await Gambler_Profiles[gambler.User.KfId].FormatBalanceAsync()}");
|
|
return;
|
|
}
|
|
Gambler_Profiles[gambler.User.KfId].Assets.Add(shoe.Id, shoe);
|
|
Gambler_Profiles[gambler.User.KfId].ModifyBalance(-shoe.originalValue);
|
|
}
|
|
public async Task UpdateGambler(GamblerDbModel gambler)
|
|
{
|
|
//if someone abandons their gambler profile they can do !shop update gambler to update their gambler profile
|
|
Gambler_Profiles[gambler.User.KfId].GamblerId = gambler.Id;
|
|
await SaveProfiles();
|
|
}
|
|
|
|
|
|
/*
|
|
* STUFF TO IMPLEMENT IF THIS PROBLEM ACTUALLY HAPPENS, CURRENTLY UNIMPLEMENTED----------------------------------------------------------------
|
|
*/
|
|
public async Task UpdateProfileId(GamblerDbModel gambler)
|
|
{
|
|
//if someone gets their account fucked with by null, assuming their gambler id stays the same
|
|
foreach (var key in Gambler_Profiles.Keys)
|
|
{
|
|
if (Gambler_Profiles[key].GamblerId == gambler.Id)
|
|
{
|
|
Gambler_Profiles[key].ID = gambler.User.KfId;
|
|
}
|
|
}
|
|
await SaveProfiles();
|
|
}
|
|
/*
|
|
* -----------------------------------------------------------------------------------------------------------------------------------------
|
|
*/
|
|
public async Task ProcessSmash(GamblerDbModel gambler)
|
|
{
|
|
await BotInstance.BotServices.KasinoShop!.Gambler_Profiles[gambler.User.KfId].Smash(gambler);
|
|
|
|
await SaveProfiles();
|
|
}
|
|
|
|
public async Task PrintRtp(GamblerDbModel gambler)
|
|
{
|
|
var rtp = Gambler_Profiles[gambler.User.KfId].Tracker.GetRtp();
|
|
await BotInstance.SendChatMessageAsync(rtp, true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
}
|
|
|
|
public async Task PrintAssets(GamblerDbModel gambler)
|
|
{
|
|
string str = $"{gambler.User.FormatUsername()}'s assets:[br]";
|
|
int counter = 1;
|
|
bool hasAssets = false;
|
|
foreach (var asset in Gambler_Profiles[gambler.User.KfId].Assets.Values)
|
|
{
|
|
str += $"{counter}: {asset}[br]";
|
|
counter++;
|
|
hasAssets = true;
|
|
}
|
|
if (!hasAssets) str = $"{gambler.User.FormatUsername()}, you don't have any assets.";
|
|
await BotInstance.SendChatMessageAsync(str, true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
}
|
|
|
|
public async Task PrintInvestments(GamblerDbModel gambler)
|
|
{
|
|
string str = $"{gambler.User.FormatUsername()}'s investments:[br]";
|
|
int counter = 1;
|
|
bool hasInvestments = false;
|
|
foreach (var asset in Gambler_Profiles[gambler.User.KfId].Assets.Values)
|
|
{
|
|
if (asset is Investment i)
|
|
{
|
|
str += $"{counter}: {i}[br]";
|
|
counter++;
|
|
hasInvestments = true;
|
|
}
|
|
}
|
|
if (!hasInvestments) str = $"{gambler.User.FormatUsername()}, you don't have any investments.";
|
|
await BotInstance.SendChatMessageAsync(str, true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
}
|
|
|
|
public async Task CreateProfile(GamblerDbModel gambler)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"Creating profile for {gambler.User.FormatUsername()}...", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
if (Gambler_Profiles.ContainsKey(gambler.User.KfId))
|
|
{
|
|
throw new Exception("Attempted to create a new profile for someone who seems to already have a profile?");
|
|
}
|
|
var profile = new KasinoShopProfile(gambler);
|
|
Gambler_Profiles.Add(profile.ID, profile);
|
|
await SaveProfiles();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class KasinoShopProfile
|
|
{
|
|
public int ID { get; set; }
|
|
public int GamblerId { get; set; }
|
|
public string name;
|
|
private decimal CryptoBalance;
|
|
public decimal OutstandingLoanBalance;
|
|
public Dictionary<int, Asset> Assets;
|
|
public Dictionary<int, Loan> Loans = new();
|
|
public decimal[] SponsorWagerLock = new decimal[2]; //[0] is how much you've wagered against your wager requirement, [1] is the wager requirement
|
|
public decimal HouseEdgeModifier = 0;
|
|
public int CrackCounter = 0;
|
|
public int FloorNugs = 0;
|
|
public DateTime LastSmokedCrack = DateTime.MinValue;
|
|
public bool IsSponsored;
|
|
public DateTime lastSponsorBonus = DateTime.MinValue;
|
|
public bool IsWeeded;
|
|
public bool IsCracked;
|
|
public bool IsInWithdrawal;
|
|
public bool IsLoanable;
|
|
public SkinMarket sMarket;
|
|
public ShoeMarket shMarket;
|
|
private CancellationTokenSource CrackToken = new();
|
|
private CancellationTokenSource WeedToken = new();
|
|
private CancellationTokenSource BegToken = new();
|
|
private TimeSpan WeedTimer = TimeSpan.FromSeconds(0); //time remaining on your weed buff
|
|
private TimeSpan CrackTimer = TimeSpan.FromSeconds(0);
|
|
public int KreditScore;
|
|
public StatTracker Tracker;
|
|
|
|
public KasinoShopProfile(GamblerDbModel gambler)
|
|
{
|
|
int gid = gambler.Id;
|
|
int kfid = gambler.User.KfId;
|
|
ID = kfid;
|
|
GamblerId = gid;
|
|
Assets = new();
|
|
CryptoBalance = 0;
|
|
OutstandingLoanBalance = 0;
|
|
IsSponsored = false;
|
|
IsWeeded = false;
|
|
IsCracked = false;
|
|
IsInWithdrawal = false;
|
|
IsLoanable = false;
|
|
KreditScore = 100;
|
|
Tracker = new StatTracker(gid, kfid);
|
|
name = gambler.User.FormatUsername();
|
|
sMarket = new SkinMarket(gambler);
|
|
shMarket = new ShoeMarket(gambler);
|
|
|
|
}
|
|
|
|
public async Task Beg(UserDbModel user)
|
|
{
|
|
CancellationToken bToken = BegToken.Token;
|
|
IsLoanable = true;
|
|
var msg = await BotInstance.SendChatMessageAsync($"{user.FormatUsername()}({user.KfId}) is begging for a loan. {user.FormatUsername()} can be trused with ${KreditScore} KKK in krypto with a 1.5x return.");
|
|
int counter = 0;
|
|
while (!bToken.IsCancellationRequested && counter < 100)
|
|
{
|
|
await Task.Delay(TimeSpan.FromSeconds(120), bToken);
|
|
counter++;
|
|
}
|
|
|
|
|
|
await BotInstance.KfClient.EditMessageAsync(msg.ChatMessageUuid,
|
|
$"{user.FormatUsername()}, nobody wanted to give you a loan. !beg to continue begging for a loan.");
|
|
IsLoanable = false;
|
|
await Task.Delay(TimeSpan.FromSeconds(10));
|
|
await BotInstance.KfClient.DeleteMessageAsync(msg.ChatMessageUuid);
|
|
|
|
}
|
|
|
|
public bool SponsorBonusDue()
|
|
{
|
|
if (DateTime.UtcNow - lastSponsorBonus < TimeSpan.FromDays(1)) return false;
|
|
return true;
|
|
}
|
|
|
|
public void ProcessSponsorBonus(decimal amount)
|
|
{
|
|
Tracker.AddDeposit(amount);
|
|
}
|
|
public void ModifyBalance(decimal amount)
|
|
{
|
|
CryptoBalance += amount;
|
|
}
|
|
public async Task<string> FormatBalanceAsync()
|
|
{
|
|
var netBalance = CryptoBalance - OutstandingLoanBalance;
|
|
string str = OutstandingLoanBalance > 0 ? $"| Net Balance: {await netBalance.FormatKasinoCurrencyAsync()}":"";
|
|
return $"Balance: {await CryptoBalance.FormatKasinoCurrencyAsync()}{str}";
|
|
}
|
|
public decimal[] Balance()
|
|
{
|
|
return new decimal[] {CryptoBalance, CryptoBalance - OutstandingLoanBalance};
|
|
}
|
|
public async Task SmokeCrack()
|
|
{
|
|
CancellationToken cToken = CrackToken.Token;
|
|
if (IsCracked || IsInWithdrawal)
|
|
{
|
|
CrackToken.Cancel();
|
|
await Task.Delay(TimeSpan.FromSeconds(5));
|
|
}
|
|
LastSmokedCrack = DateTime.UtcNow;
|
|
IsCracked = true;
|
|
CrackTimer += TimeSpan.FromMinutes(2);
|
|
CrackCounter++;
|
|
HouseEdgeModifier += (decimal).05;
|
|
|
|
for (int i = 0; i < CrackTimer.Seconds/5; i++)
|
|
{
|
|
await Task.Delay(TimeSpan.FromSeconds(5));
|
|
CrackTimer -= TimeSpan.FromSeconds(5);
|
|
if (cToken.IsCancellationRequested)
|
|
{
|
|
//if you smoked more crack within that 2 minutes, add another 2 minutes of crack instead, stack the buffs and postpone the withdrawal symptoms
|
|
return;
|
|
}
|
|
}
|
|
//now you are in withdrawal
|
|
IsInWithdrawal = true;
|
|
IsCracked = false;
|
|
|
|
HouseEdgeModifier -= (decimal)(.06 * CrackCounter);
|
|
for (int i = 0; i < CrackCounter*100; i++)
|
|
{
|
|
await Task.Delay(TimeSpan.FromSeconds(5));
|
|
if (cToken.IsCancellationRequested)
|
|
{
|
|
//if you smoke crack while in withdraw, get the basic benefits of crack back but do not reset crackcounter
|
|
HouseEdgeModifier = BotInstance.BotServices.KasinoShop!.DefaultHouseEdgeModifier;
|
|
return;
|
|
}
|
|
}
|
|
//reset the house edge modifier and crack counter after withdrawal has passed
|
|
CrackCounter = 0;
|
|
HouseEdgeModifier = BotInstance.BotServices.KasinoShop!.DefaultHouseEdgeModifier;
|
|
IsInWithdrawal = false;
|
|
}
|
|
|
|
public async Task SmokeWeed(TimeSpan buffLength)
|
|
{
|
|
if (buffLength > TimeSpan.FromMinutes(12)) FloorNugs++;
|
|
CancellationToken wToken = WeedToken.Token;
|
|
CancellationToken cToken = CrackToken.Token;
|
|
if (IsWeeded)
|
|
{
|
|
WeedToken.Cancel();
|
|
await Task.Delay(TimeSpan.FromSeconds(5));
|
|
}
|
|
IsWeeded = true;
|
|
if (HouseEdgeModifier < 0)
|
|
{
|
|
//if you're currently in crack withdrawal
|
|
HouseEdgeModifier /= 2;
|
|
}
|
|
else
|
|
{
|
|
HouseEdgeModifier += (decimal)0.01;
|
|
}
|
|
|
|
WeedTimer += buffLength;
|
|
for (int i = 0; i < buffLength.Seconds / 5; i++)
|
|
{
|
|
await Task.Delay(TimeSpan.FromSeconds(1));
|
|
WeedTimer -= TimeSpan.FromSeconds(1);
|
|
if (wToken.IsCancellationRequested) return;
|
|
if (cToken.IsCancellationRequested) return;
|
|
|
|
}
|
|
await Task.Delay(buffLength);
|
|
if (HouseEdgeModifier > 0) HouseEdgeModifier -= (decimal)0.01;
|
|
IsWeeded = false;
|
|
|
|
}
|
|
|
|
public async Task Smash(GamblerDbModel gambler)
|
|
{
|
|
List<int> smashableAssetIds = new();
|
|
bool smashableAssets = false;
|
|
foreach (var key in Assets.Keys)
|
|
{
|
|
if (Assets[key] is Smashable smash)
|
|
{
|
|
smashableAssetIds.Add(key);
|
|
smashableAssets = true;
|
|
}
|
|
}
|
|
if (!smashableAssets)
|
|
{
|
|
//check if they have any physical assets in their possesion, shoes, gold, silver, house, car, small chance to damage one of those instead
|
|
List<int> physicalAssetIds = new();
|
|
foreach (var key in Assets.Keys)
|
|
{
|
|
if (Assets[key] is Investment inv)
|
|
{
|
|
if (inv.investment_type != InvestmentType.Stake && inv.investment_type != InvestmentType.Skin)
|
|
{
|
|
physicalAssetIds.Add(key);
|
|
}
|
|
}
|
|
else if (Assets[key] is Shoe shoe)
|
|
{
|
|
physicalAssetIds.Add(key);
|
|
}
|
|
else if (Assets[key] is Car car)
|
|
{
|
|
physicalAssetIds.Add(key);
|
|
}
|
|
}
|
|
|
|
int num = Money.GetRandomNumber(gambler, 0, 100);
|
|
if (physicalAssetIds.Count == 0 || num < 90)
|
|
{
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you don't have anything to smash.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
return;
|
|
}
|
|
|
|
//now "smash" one of the assets
|
|
num = Money.GetRandomNumber(gambler, 0, 4);
|
|
var assetId = smashableAssetIds[num];
|
|
if (Assets[assetId] is Shoe sh)
|
|
{
|
|
sh.Smash();
|
|
}
|
|
else if (Assets[assetId] is Car car)
|
|
{
|
|
car.Smash();
|
|
}
|
|
else if (Assets[assetId] is Investment inv)
|
|
{
|
|
inv.Smash();
|
|
}
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you smashed {Assets[assetId]}.", true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
foreach (var lKey in Loans.Keys)
|
|
{
|
|
Loans[lKey].ProcessSmash(ID, BotInstance);
|
|
}
|
|
|
|
return;
|
|
}
|
|
foreach (var id in smashableAssetIds)
|
|
{
|
|
((Smashable)Assets[id]).Smash();
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, you smashed {Assets[id]}.");
|
|
if (Assets[id].GetCurrentValue() == 0)
|
|
{
|
|
Assets.Remove(id);
|
|
await BotInstance.SendChatMessageAsync($"{gambler.User.FormatUsername()}, {Assets[id]} is worthless now so you throw it away.");
|
|
}
|
|
if (Money.GetRandomNumber(gambler, 0, 100) < 50) break;
|
|
}
|
|
|
|
foreach (var lKey in Loans.Keys)
|
|
{
|
|
Loans[lKey].ProcessSmash(ID, BotInstance);
|
|
}
|
|
}
|
|
public void Withdraw(decimal amount)
|
|
{
|
|
CryptoBalance += amount;
|
|
Tracker.AddWithdrawal(amount);
|
|
}
|
|
|
|
public void Deposit(decimal amount)
|
|
{
|
|
CryptoBalance -= amount;
|
|
Tracker.AddDeposit(amount);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class StatTracker
|
|
{
|
|
public int GamblerId;
|
|
public int KfId;
|
|
public decimal totalDeposited = 0;
|
|
public decimal totalWithdrawn = 0;
|
|
public decimal totalLossBack = 0;
|
|
public Dictionary<WagerGame, decimal[]> totalWageredByGame; //0 is total wagered, 1 is total paid back
|
|
|
|
public StatTracker(int gid, int kfid)
|
|
{
|
|
GamblerId = gid;
|
|
KfId = kfid;
|
|
totalWageredByGame = new Dictionary<WagerGame, decimal[]>();
|
|
foreach (var game in Enum.GetValues<WagerGame>())
|
|
{
|
|
totalWageredByGame.Add(game, new decimal[] {0, 0});
|
|
}
|
|
}
|
|
|
|
public void AddNewGameToTracker(WagerGame game)
|
|
{
|
|
totalWageredByGame.Add(game, new decimal[] {0, 0});
|
|
}
|
|
|
|
public void AddWager(WagerGame game, decimal amount, decimal net)
|
|
{
|
|
if (!totalWageredByGame.ContainsKey(game)) AddNewGameToTracker(game);
|
|
totalWageredByGame[game][0] += amount;
|
|
totalWageredByGame[game][1] += net;
|
|
}
|
|
|
|
public void AddDeposit(decimal amount)
|
|
{
|
|
totalDeposited += amount;
|
|
}
|
|
public void AddWithdrawal(decimal amount)
|
|
{
|
|
totalWithdrawn += amount;
|
|
}
|
|
|
|
public void AddLossback(decimal amount)
|
|
{
|
|
totalLossBack += amount;
|
|
}
|
|
|
|
public string GetRtp()
|
|
{
|
|
decimal totalWagered = 0;
|
|
decimal totalWinnings = 0;
|
|
foreach (var wagered in totalWageredByGame.Values)
|
|
{
|
|
totalWagered += wagered[0];
|
|
totalWinnings += wagered[1];
|
|
}
|
|
|
|
using var db = new ApplicationDbContext();
|
|
var gambler = db.Gamblers.FirstOrDefaultAsync(g => g.Id == GamblerId).GetAwaiter().GetResult();
|
|
decimal RTP = (totalWagered - totalWithdrawn - gambler!.Balance) / totalWagered;
|
|
string returnVal = $"{gambler.User.FormatUsername()}[br]" +
|
|
$"Global RTP: {RTP * 100}%[br]";
|
|
foreach (var game in totalWageredByGame.Keys)
|
|
{
|
|
returnVal += $"{game} RTP: {(totalWageredByGame[game][1] / totalWageredByGame[game][0]) * 100}%[br]";
|
|
}
|
|
|
|
return returnVal;
|
|
}
|
|
}
|
|
|
|
}
|
|
public abstract class Asset
|
|
{
|
|
public decimal originalValue;
|
|
public string name;
|
|
public AssetType type;
|
|
public DateTime acquired;
|
|
public List<AssetValueChangeReport> ValueChangeReports;
|
|
public int Id;
|
|
|
|
public abstract decimal GetCurrentValue();
|
|
}
|
|
|
|
public class AssetValueChangeReport
|
|
{
|
|
private decimal valueChangeAmount;
|
|
private decimal valueChangePcnt;
|
|
public DateTime time;
|
|
|
|
public AssetValueChangeReport(decimal valueChangeAmount, decimal valueChangePcnt, DateTime time)
|
|
{
|
|
this.valueChangeAmount = valueChangeAmount;
|
|
this.valueChangePcnt = valueChangePcnt;
|
|
this.time = time;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
string symbol = valueChangeAmount > 0 ? AssetValueIncreaseIndicator[true] : AssetValueIncreaseIndicator[false];
|
|
string color = valueChangeAmount > 0 ? AssetValueIncreaseColor[true] : AssetValueIncreaseColor[false];
|
|
string timeString = DateTime.UtcNow - time > TimeSpan.FromDays(7) ? time.ToString("g") : time.ToString("f");
|
|
return $"{symbol}[color={color}]${valueChangeAmount} KKK({valueChangePcnt}%)[/color] {timeString}";
|
|
}
|
|
}
|
|
|
|
public class Loan
|
|
{
|
|
public decimal amount;
|
|
public decimal payoutAmount;
|
|
public int payableToGambler; //gambler id
|
|
public int payableToKf;//kfid
|
|
public int recieverGambler;
|
|
public int recieverKf;
|
|
public int Id;
|
|
public string payableTo;
|
|
|
|
public Loan(decimal amount, int payableToGambler, int payableToKf, int recieverGambler, int recieverKf, int Id, UserDbModel payableTo)
|
|
{
|
|
this.amount = amount;
|
|
payoutAmount = amount * 1.5m;
|
|
this.payableToGambler = payableToGambler;
|
|
this.payableToKf = payableToKf;
|
|
this.recieverGambler = recieverGambler;
|
|
this.recieverKf = recieverKf;
|
|
this.Id = Id;
|
|
this.payableTo = payableTo.FormatUsername();
|
|
}
|
|
|
|
public async Task<string> ToStringAsync(int kfId)
|
|
{
|
|
if (kfId == payableToKf) //if the person calling the command (ex !list loans) is the one who is owed
|
|
{
|
|
await using var db = new ApplicationDbContext();
|
|
var gambler = await db.Gamblers.FirstOrDefaultAsync(g => g.Id == payableToGambler);
|
|
return $"is owed ${await payoutAmount.FormatKasinoCurrencyAsync()} from {gambler!.User.FormatUsername()}";
|
|
}
|
|
|
|
return $"owes {payableTo}({payableToKf}) ${payoutAmount}KKK";
|
|
}
|
|
|
|
public void ProcessSmash(int smasherId, ChatBot instance)
|
|
{
|
|
if (smasherId == recieverKf)
|
|
{
|
|
if (payoutAmount > amount)
|
|
{
|
|
payoutAmount = amount;
|
|
instance.BotServices.KasinoShop!.Gambler_Profiles[payableToKf].Loans[Id].payoutAmount = amount;
|
|
}
|
|
}
|
|
}
|
|
|
|
[Obsolete("Don't use base ToString, use await ToStringAsync(int kfId) instead", true)]
|
|
public override string ToString()
|
|
{
|
|
return "Generated incorrect string for loan. Screenshot and send to Alogindtractor2";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public class Investment : Asset //gold, silver, stake, or house
|
|
{
|
|
private decimal _currentValue;
|
|
public InvestmentType investment_type;
|
|
private DateTime _lastInterestCalculation = DateTime.UtcNow;
|
|
public decimal[] interestRange;
|
|
|
|
[Obsolete("Dont use base constructor", true)]
|
|
protected Investment()
|
|
{
|
|
throw new Exception("Investment should not be instantiated directly. Use Gold, Silver, or House");
|
|
}
|
|
public Investment(int id, decimal value, decimal[] range, InvestmentType type, string name)
|
|
{
|
|
originalValue = value;
|
|
_currentValue = value;
|
|
investment_type = type;
|
|
interestRange = range;
|
|
Id = id;
|
|
this.type = AssetType.Investment;
|
|
this.name = name;
|
|
ValueChangeReports = new();
|
|
ValueChangeReports.Add(new AssetValueChangeReport(0, 0, DateTime.UtcNow));
|
|
}
|
|
|
|
public override decimal GetCurrentValue()
|
|
{
|
|
//apply daily interest if applicable
|
|
if (DateTime.UtcNow - _lastInterestCalculation > TimeSpan.FromDays(1))
|
|
{
|
|
int interestIterations = (DateTime.UtcNow - acquired).Days;
|
|
for (int i = 0; i < interestIterations; i++)
|
|
{
|
|
|
|
double range = (double)(interestRange[1] - interestRange[0]);
|
|
double random = _rand.NextDouble() * range;
|
|
random += (double)interestRange[0];
|
|
var oldValue = _currentValue;
|
|
_currentValue *= (decimal)(1 + random);
|
|
ValueChangeReports.Add(new AssetValueChangeReport(_currentValue - oldValue, (decimal)(random), DateTime.UtcNow - TimeSpan.FromDays(i+1)));
|
|
}
|
|
}
|
|
return _currentValue;
|
|
}
|
|
public override string ToString()
|
|
{
|
|
return $"{type} {investment_type}: {name}(ID: {Id}) worth {GetCurrentValue()} {ValueChangeReports[^1]}";
|
|
}
|
|
|
|
public void StakePartialSale(decimal amount)
|
|
{
|
|
if (this.investment_type != InvestmentType.Stake) throw new Exception("attempted to partially sell something other than a stake");
|
|
var oldval = _currentValue;
|
|
_currentValue -= amount;
|
|
ValueChangeReports.Add(new AssetValueChangeReport(-amount, -(_currentValue/oldval), DateTime.UtcNow));
|
|
}
|
|
|
|
public void Smash()
|
|
{
|
|
if (investment_type == InvestmentType.Stake || investment_type == InvestmentType.Skin) throw new Exception("attempted to smash a stake");
|
|
var oldval = _currentValue;
|
|
_currentValue -= originalValue/2;
|
|
ValueChangeReports.Add(new AssetValueChangeReport(_currentValue - oldval, (_currentValue - oldval) / oldval, DateTime.UtcNow));
|
|
}
|
|
}
|
|
|
|
public class Shoe : Investment
|
|
{
|
|
public ShoeBrand brand;
|
|
public Shoe(int id, decimal value, ShoeBrand brand) : base(id, value, ShoeAprRange, InvestmentType.Shoes, $"{brand} shoes")
|
|
{
|
|
this.brand = brand;
|
|
}
|
|
}
|
|
|
|
public class Skin : Investment
|
|
{
|
|
private decimal _currentValue;
|
|
private DateTime _lastInterestCalculation = DateTime.UtcNow;
|
|
private string _objName;
|
|
private string _tag;
|
|
private string _color;
|
|
private string _emoji;
|
|
|
|
public Skin(int id, decimal value, string obj, string tag, string color, string emoji) : base(id, value, CsSkinAprRange, InvestmentType.Skin, $"[color={color}][b][{emoji}{tag}]{obj}[/b][/color]")
|
|
{
|
|
_objName = obj;
|
|
_tag = tag;
|
|
_color = color;
|
|
_emoji = emoji;
|
|
}
|
|
|
|
//use same getCurrentValue as investment
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"{name} (ID: {Id}) worth ${GetCurrentValue()} KKK | {ValueChangeReports[^1]}";
|
|
}
|
|
}
|
|
|
|
public class Smashable : Asset // computer equipment
|
|
{
|
|
public bool isSmashed = false;
|
|
public decimal currentValue;
|
|
|
|
public Smashable(int id, decimal value, SmashableType type)
|
|
{
|
|
Id = id;
|
|
originalValue = value;
|
|
currentValue = value;
|
|
this.type = AssetType.Smashable;
|
|
this.name = $"{type}";
|
|
acquired = DateTime.UtcNow;
|
|
ValueChangeReports = new();
|
|
}
|
|
|
|
public override decimal GetCurrentValue()
|
|
{
|
|
return currentValue;
|
|
}
|
|
|
|
public void Smash()
|
|
{
|
|
isSmashed = true;
|
|
currentValue -= originalValue / 2;
|
|
name = $"Smashed {name}";
|
|
ValueChangeReports.Add(new AssetValueChangeReport(-originalValue/2, -.5m, DateTime.UtcNow));
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"{name}(ID: {Id}) worth {currentValue} {ValueChangeReports[^1]}";
|
|
}
|
|
}
|
|
|
|
|
|
public class Car : Asset
|
|
{
|
|
private decimal _currentValue;
|
|
public new AssetType type = AssetType.Car;
|
|
public Cars car_type;
|
|
public decimal job_value;
|
|
|
|
[Obsolete("Dont use base constructor", true)]
|
|
public Car()
|
|
{
|
|
throw new Exception("Car should not be instantiated directly. Use Car(int id, string name, decimal value, Cars car_type, decimal job_value)");
|
|
}
|
|
public Car(Cars type)
|
|
{
|
|
acquired = DateTime.UtcNow;
|
|
car_type = type;
|
|
_currentValue = CarPrices[type];
|
|
originalValue = _currentValue;
|
|
job_value = CarPrices[type] / 10;
|
|
name = type.ToString();
|
|
ValueChangeReports = new();
|
|
}
|
|
|
|
public override decimal GetCurrentValue()
|
|
{
|
|
return _currentValue;
|
|
}
|
|
|
|
public void SetId(GamblerDbModel gambler) //sets the id of the car to a unique number when you buy it so you can interact with it later
|
|
{
|
|
Id = GenerateRandomId(gambler);
|
|
}
|
|
|
|
public async Task ProcessWorkJob(GamblerDbModel gambler)
|
|
{
|
|
decimal oldVal = _currentValue;
|
|
_currentValue -= job_value / 5;
|
|
ValueChangeReports.Add(new AssetValueChangeReport(-job_value / 5, (_currentValue - oldVal) / oldVal, DateTime.UtcNow));
|
|
BotInstance.BotServices.KasinoShop!.Gambler_Profiles[gambler.User.KfId].ModifyBalance(job_value);
|
|
if (_currentValue <= 0) // if your car dies it gets removed from your asset list
|
|
{
|
|
BotInstance.BotServices.KasinoShop!.Gambler_Profiles[gambler.User.KfId].Assets.Remove(Id);
|
|
await BotInstance.SendChatMessageAsync(
|
|
$"{gambler.User.FormatUsername()} totalled their car on the way home from work.", true,
|
|
autoDeleteAfter: TimeSpan.FromSeconds(10));
|
|
}
|
|
|
|
}
|
|
|
|
public void Smash() //car can be damaged as a result of smashing but not destroyed
|
|
{
|
|
var oldval = _currentValue;
|
|
_currentValue -= _currentValue / 4;
|
|
ValueChangeReports.Add(new AssetValueChangeReport(_currentValue - oldval, (_currentValue - oldval) / oldval, DateTime.UtcNow));
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"{type} {name} worth ${GetCurrentValue()} KKK";
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//KasinoShop.[]Market - used to generate a list of items for you to buy when you interact with the shop. takes your shop profiles current state into account
|
|
//for example if you have a car, you can take meth queen home with you and buy meth
|
|
//markets get new options every day except drug market which stays the same outside of prices
|
|
|
|
|
|
public class ShoeMarket
|
|
{
|
|
private List<Shoe> _shoes = new();
|
|
private DateTime _opened = DateTime.UtcNow;
|
|
|
|
public ShoeMarket(GamblerDbModel gambler)
|
|
{
|
|
var shoePrices = KasinoShop.ShoePrices(gambler);
|
|
foreach (var shoeType in shoePrices.Keys)
|
|
{
|
|
_shoes.Add(new Shoe(GenerateRandomId(gambler), shoePrices[shoeType], shoeType));
|
|
}
|
|
}
|
|
|
|
public bool Old()
|
|
{
|
|
if (DateTime.UtcNow - _opened > TimeSpan.FromDays(1)) return true;
|
|
return false;
|
|
}
|
|
|
|
public List<Shoe> GetShoes(GamblerDbModel gambler)
|
|
{
|
|
if (Old())
|
|
{
|
|
var shoePrices = KasinoShop.ShoePrices(gambler);
|
|
_shoes.Clear();
|
|
foreach (var shoeType in shoePrices.Keys)
|
|
{
|
|
_shoes.Add(new Shoe(GenerateRandomId(gambler), shoePrices[shoeType], shoeType));
|
|
}
|
|
}
|
|
|
|
return _shoes;
|
|
}
|
|
|
|
}
|
|
|
|
public class SkinMarket
|
|
{
|
|
private List<Skin> _skins = new();
|
|
private DateTime _opened = DateTime.UtcNow;
|
|
|
|
public SkinMarket(GamblerDbModel gambler)
|
|
{
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
_skins.Add(GenerateRandomSkin(gambler));
|
|
}
|
|
}
|
|
private bool Old()
|
|
{
|
|
return DateTime.UtcNow - _opened > TimeSpan.FromDays(1);
|
|
}
|
|
|
|
public List<Skin> GetSkins(GamblerDbModel gambler)
|
|
{
|
|
if (Old())
|
|
{
|
|
_skins.Clear();
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
_skins.Add(GenerateRandomSkin(gambler));
|
|
}
|
|
}
|
|
|
|
return _skins;
|
|
}
|
|
|
|
public void SellsSkinTo(GamblerDbModel gambler, int skindex)
|
|
{
|
|
_skins.RemoveAt(skindex);
|
|
_skins.Add(GenerateRandomSkin(gambler));
|
|
}
|
|
}
|
|
|
|
|
|
public static readonly decimal CrackPrice = 10000m;
|
|
public static readonly decimal WeedPricePerHour = 1000m;
|
|
public static readonly TimeSpan WeedNugLength = TimeSpan.FromMinutes(6);
|
|
public static readonly decimal CsSkinMinBaseValue = 1000;
|
|
public static readonly decimal[] ShoeAprRange = { -0.05m, 0.05m };
|
|
public static readonly decimal[] CsSkinAprRange = { -0.25m, 0.25m };
|
|
public static decimal HomeApr = 0.1m;
|
|
|
|
public static Skin GenerateRandomSkin(GamblerDbModel gambler)
|
|
{
|
|
int obj = Money.GetRandomNumber(gambler, 0, CsSkinObjects.Count - 1);
|
|
int tg = Money.GetRandomNumber(gambler, 0, CsSkinTags.Count - 1);
|
|
int emo = Money.GetRandomNumber(gambler, 0, CsSkinEmotes.Count - 1);
|
|
string color = GetRandomColor(gambler);
|
|
int id = GenerateRandomId(gambler);
|
|
decimal val = CsSkinTags.ElementAt(tg).Value + CsSkinEmotes.ElementAt(emo).Value;
|
|
if (val < CsSkinMinBaseValue) val = CsSkinMinBaseValue;
|
|
return new Skin(id, val, CsSkinObjects[obj], CsSkinTags.ElementAt(tg).Key, color, CsSkinEmotes.ElementAt(emo).Key);
|
|
}
|
|
|
|
|
|
public static int GenerateRandomId(GamblerDbModel gambler)
|
|
{
|
|
var profile = BotInstance.BotServices.KasinoShop!.Gambler_Profiles[gambler.User.KfId];
|
|
int counter = 0;
|
|
int id = Money.GetRandomNumber(gambler, 0, 999999999);
|
|
if (profile.Assets.ContainsKey(id))
|
|
{
|
|
while (profile.Assets.ContainsKey(id))
|
|
{
|
|
id = Money.GetRandomNumber(gambler, 0, 999999999);
|
|
counter++;
|
|
if (counter > 10000)
|
|
{
|
|
throw new Exception("failed to generate unique skin ID after 10000 attempts");
|
|
}
|
|
}
|
|
}
|
|
|
|
return id;
|
|
}
|
|
|
|
public static readonly Dictionary<Cars, Car> DefaultCars = new()
|
|
{
|
|
{Cars.Civic, new Car(Cars.Civic)},
|
|
{Cars.Audi, new Car(Cars.Audi)},
|
|
{Cars.Bentley, new Car(Cars.Bentley)},
|
|
{Cars.Bmw, new Car(Cars.Bmw)}
|
|
};
|
|
public static readonly Dictionary<Cars, decimal> CarPrices = new()
|
|
{
|
|
{ Cars.Civic , 2_000_000 },
|
|
{ Cars.Audi, 4_000_000 },
|
|
{ Cars.Bentley , 6_000_000 },
|
|
{ Cars.Bmw , 8_000_000 },
|
|
};
|
|
|
|
public static readonly List<string> CsSkinObjects = new()
|
|
{
|
|
"P2000",
|
|
"USP-S",
|
|
"Glock-18",
|
|
"Dual Berettas",
|
|
"P250",
|
|
"Tec-9",
|
|
"Five-SeveN",
|
|
"CZ75-Auto",
|
|
"R8 Revolver",
|
|
"Desert Eagle",
|
|
"Mac-10",
|
|
"UMP-45",
|
|
"MP5 SD",
|
|
"MP7",
|
|
"MP9",
|
|
"P90",
|
|
"PP-Bizon",
|
|
"Nova",
|
|
"Sawed-Off",
|
|
"Mag-7",
|
|
"XM1014",
|
|
"SSG 08",
|
|
"Galil AR",
|
|
"FAMAS",
|
|
"AK-47",
|
|
"M4A1-S",
|
|
"SG 553",
|
|
"M4A4",
|
|
"AUG",
|
|
"AWP",
|
|
"G3SG1",
|
|
"SCAR-20",
|
|
"Bayonet",
|
|
"Bowie Knife",
|
|
"Butterfly Knife",
|
|
"Falchion Knife",
|
|
"Flip Knife",
|
|
"Gut Knife",
|
|
"Huntsman Knife",
|
|
"Karambit",
|
|
"M9 Bayonet",
|
|
"Navaja Knife",
|
|
"Nomad Knife",
|
|
"Paracord Knife",
|
|
"Shadow Daggers",
|
|
"Skeleton Knife",
|
|
"Stiletto Knife",
|
|
"Survival Knife",
|
|
"Talon Knife",
|
|
"Ursus Knife",
|
|
"Kukri Knife",
|
|
"Sport Gloves",
|
|
"Specialist Gloves",
|
|
"Driver Gloves",
|
|
"Hand Wraps",
|
|
"Moto Gloves",
|
|
"Bloodhound Gloves",
|
|
"Hydra Gloves",
|
|
"Broken Fang Gloves"
|
|
};
|
|
|
|
public static readonly Dictionary<string, decimal> CsSkinTags = new()
|
|
{
|
|
{"SNEED", 10000000},
|
|
{"R", 9000000},
|
|
{"RIGGED", 8000000},
|
|
{"GREEDY", 100000},
|
|
{"DEWISH", 6000000},
|
|
{"JEWISH", 6000000},
|
|
{"SCAMMER", 7000000},
|
|
{"SCAM", 7777777},
|
|
{"5", 5555555},
|
|
{"9", 9999999},
|
|
{"OSRS", 1000},
|
|
{"666", 6666666},
|
|
{"CRACK", 5000000},
|
|
{"WEED", 4200000},
|
|
{"EEEEEEEEEE", 3333333},
|
|
{"COFFEE", 3000000},
|
|
{"FATGO", 2000000},
|
|
{"YO", 75000},
|
|
{"ELF", 60000},
|
|
{"OMFG", 20000},
|
|
{"IHML", 7000},
|
|
{"FUCKIN DEWD", 60000},
|
|
{"MILF", 40000},
|
|
{"KKK", 1000000},
|
|
{"KASINO", 1000000},
|
|
{"METH", 4000000},
|
|
{"GOOBR", 2000000},
|
|
{"TRAPPER", 500000},
|
|
{"TRAPPERTURD", 100000},
|
|
{"CHRISTMAS", 10000},
|
|
{"MR.CHRISTMAS", 10000},
|
|
{"DEPAKOTE", 1000},
|
|
{"RAT", 50000},
|
|
{"MATI", 20000},
|
|
{"GERMAN RAP", 15000},
|
|
{"EVIL EDDIE", 10000},
|
|
{"NASTY NOAH", 5000},
|
|
{"BOSSMAN", 25000},
|
|
{"RATDAD", 80000},
|
|
{"PICKLETIME", -1000000m},
|
|
|
|
};
|
|
|
|
|
|
public static string GetRandomColor(GamblerDbModel gambler)
|
|
{
|
|
int r = Money.GetRandomNumber(gambler, 0, 255);
|
|
int g = Money.GetRandomNumber(gambler, 0, 255);
|
|
int b = Money.GetRandomNumber(gambler, 0, 255);
|
|
return $"{r:X2}{g:X2}{b:X2}";
|
|
}
|
|
|
|
public static readonly Dictionary<string, decimal> CsSkinEmotes = new()
|
|
{
|
|
{"🤣", 15000},
|
|
{"😂", 14000},
|
|
{"🙂", 13000},
|
|
{"😝", 12000},
|
|
{"🤨", 11000},
|
|
{"🙄", 10000},
|
|
{"🤥", 20000},
|
|
{"🤧", 30000},
|
|
{"🤯", 8000000},
|
|
{"😭", 30000},
|
|
{"😤", 40000},
|
|
{"💩", 60000},
|
|
{"💢", 700000},
|
|
{"💥", 600000},
|
|
{"💤", 10000},
|
|
{"🫵", 70000},
|
|
{"🙏", 50000},
|
|
{"🎅", 10000},
|
|
{"🐀", 10000000},
|
|
{"🐹", 220000},
|
|
{"🦨", 110000},
|
|
{"🐦🔥", 330000},
|
|
{"🐍", 88000},
|
|
{"🐉", 77000},
|
|
{"🦞", 66000},
|
|
{"☘", 300000},
|
|
{"🍀", 1000000},
|
|
{"🥩", 400000},
|
|
{"🚔", 500000},
|
|
{"🚗", 50000},
|
|
{"✈", 1000000},
|
|
{":winner:", 4000000},
|
|
{":juice:", 2000000},
|
|
{":ross:", 3000000},
|
|
{"♠", 75000},
|
|
{"♥", 75000},
|
|
{"♦", 75000},
|
|
{"♣", 75000},
|
|
{"💎", 150000},
|
|
{"🪫", 85000},
|
|
{"🪙", 45000},
|
|
{"💵", 10000},
|
|
{"🧲", 25000},
|
|
{"💊", 100000},
|
|
{"🚬", 650000},
|
|
{"🪪", 750000},
|
|
{"🚭", 820000},
|
|
{"✡", 6666666},
|
|
{"❓", 250000},
|
|
{"💲", 500000},
|
|
{"🆗", 360000},
|
|
{"🤡", 1000000},
|
|
{"👅", 9999999},
|
|
{"👴", 105000},
|
|
{"🛹", 90000},
|
|
{"🥒", -1000000m},
|
|
{"🎄", 42069},
|
|
{"🕹", 12000},
|
|
{"🎰", 7777777},
|
|
|
|
};
|
|
|
|
|
|
|
|
public static readonly Dictionary<bool, string> AssetValueIncreaseIndicator = new() { {false, "🔻"}, {true, "🔺"} };
|
|
public static readonly Dictionary<bool, string> AssetValueIncreaseColor = new() { {false, "red"}, {true, "lightgreen"} };
|
|
|
|
public static Dictionary<ShoeBrand, decimal> ShoePrices(GamblerDbModel gambler)
|
|
{
|
|
|
|
return new Dictionary<ShoeBrand, decimal>
|
|
{
|
|
{ ShoeBrand.Yeezy , Money.GetRandomNumber(gambler, 6_000, 100_000) },
|
|
{ ShoeBrand.Adidas , Money.GetRandomNumber(gambler, 1_800, 50_000) },
|
|
{ ShoeBrand.Jordan , Money.GetRandomNumber(gambler, 9_000, 380_000) },
|
|
};
|
|
}
|
|
|
|
private static List<string> SmashCarousel = new()
|
|
{
|
|
"https://i.ddos.lgbt/u/KhMr9v.webp",
|
|
"https://i.ddos.lgbt/u/KYaOqH.webp",
|
|
"https://i.ddos.lgbt/u/w3wAyB.webp",
|
|
"https://i.ddos.lgbt/u/c4znnv.webp",
|
|
"https://i.ddos.lgbt/u/qGHbNp.webp",
|
|
"https://i.ddos.lgbt/u/65lz4m.webp",
|
|
"https://i.ddos.lgbt/u/ZCDWeO.webp",
|
|
"https://i.ddos.lgbt/u/2025-12-12_19:17:16.gif",
|
|
"https://i.ddos.lgbt/u/oBXBV4.webp",
|
|
"https://i.ddos.lgbt/u/2025-12-12_19:08:15.gif",
|
|
"https://i.ddos.lgbt/u/fuxIHW.webp",
|
|
"https://i.ddos.lgbt/u/0dtwl3.webp",
|
|
|
|
};
|
|
|
|
public static readonly decimal GoldBasePriceOz = 300000;
|
|
public static readonly decimal[] GoldInterestRange = new decimal[] { 0.01m, 0.05m };
|
|
public static readonly decimal SilverBasePriceOz = 10000;
|
|
public static readonly decimal[] SilverInterestRange = new decimal[] { 0.01m, 0.05m };
|
|
public static readonly decimal BaseHousePrice = 100000000;
|
|
public static readonly decimal[] HouseInterestRange = new decimal[] { 0.01m, 0.15m };
|
|
public static readonly decimal[] CryptoStakeInterestRange = new decimal[] { -0.01m, 0.05m };
|
|
|
|
public static String GetRandomSmashImage(GamblerDbModel gambler)
|
|
{
|
|
int rand = Money.GetRandomNumber(gambler, 0, SmashCarousel.Count - 1);
|
|
return SmashCarousel[rand];
|
|
}
|
|
|
|
public decimal KASINO_SPONSOR_BONUS = 1000;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public enum SmashableType
|
|
{
|
|
Headphones,
|
|
Keyboard,
|
|
Mouse
|
|
}
|
|
public enum InvestmentType
|
|
{
|
|
Shoes,
|
|
Stake,
|
|
Gold,
|
|
Silver,
|
|
Skin,
|
|
House,
|
|
Random
|
|
}
|
|
|
|
public enum AssetType
|
|
{
|
|
Investment,
|
|
Smashable,
|
|
Car,
|
|
Random
|
|
}
|
|
|
|
public enum ShoeBrand
|
|
{
|
|
Yeezy,
|
|
Adidas,
|
|
Jordan,
|
|
}
|
|
|
|
public enum Cars
|
|
{
|
|
Civic,
|
|
Bentley,
|
|
Audi,
|
|
Bmw
|
|
}
|
|
|
|
public enum Rigging
|
|
{
|
|
Switch,
|
|
Button,
|
|
Lever,
|
|
Panel,
|
|
Keypad,
|
|
Dial,
|
|
Electromagnet
|
|
}
|
|
|
|
|
|
|