Files
KfChatDotNet/KfChatDotNetBot/Models/DbModels/MoneyDbModels.cs
barelyprofessional 5e85566577 Refactored krash
2026-04-06 21:13:19 -05:00

450 lines
15 KiB
C#

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using KfChatDotNetBot.Services;
namespace KfChatDotNetBot.Models.DbModels;
public class GamblerDbModel
{
/// <summary>
/// ID fo the database row
/// </summary>
public int Id { get; set; }
/// <summary>
/// User that this gambler entity is associated with.
/// A user can have multiple associated gambler entities, but only one should be active
/// </summary>
public required UserDbModel User { get; set; }
/// <summary>
/// Gambler's balance. It can be negative if an admin has forced them into an overdraft
/// Values are fractional, it is NOT stored as cents, therefore 100.00 KKK is stored as "100" in the database
/// </summary>
public required decimal Balance { get; set; }
/// <summary>
/// What state the gambler entity is in
/// </summary>
public required GamblerState State { get; set; } = GamblerState.Active;
/// <summary>
/// The seed value given to any instance of Random that's associated with the gambler
/// </summary>
[MaxLength(256)]
public required string RandomSeed { get; set; }
/// <summary>
/// When the gambler entity was created
/// </summary>
public required DateTimeOffset Created { get; set; }
/// <summary>
/// Reference value for total wagered during the entity's lifetime
/// This value is recalculated whenever the bot restarts to ensure integrity
/// </summary>
public required decimal TotalWagered { get; set; }
/// <summary>
/// Wager requirement for the next VIP level
/// If TotalWagered reaches this value, it'll trigger the calculation
/// </summary>
public required decimal NextVipLevelWagerRequirement { get; set; }
}
public class TransactionDbModel
{
/// <summary>
/// ID fo the database row
/// </summary>
public int Id { get; set; }
/// <summary>
/// Gambler whose balance was affected by this transaction
/// </summary>
public required GamblerDbModel Gambler { get; set; }
/// <summary>
/// Source of the transaction event
/// </summary>
public required TransactionSourceEventType EventSource { get; set; }
/// <summary>
/// Time when the event occurred
/// </summary>
public required DateTimeOffset Time { get; set; }
/// <summary>
/// Time represented as a 64-bit UNIX epoch
/// This just exists to make it far more efficient to query a range of txns
/// as then we can use native SQLite dialect to select e.g. last 24 hours
/// instead of copying thousands of rows into memory and using LINQ
/// </summary>
public required long TimeUnixEpochSeconds { get; set; }
/// <summary>
/// Effect of the transaction, plus or minus
/// </summary>
public required decimal Effect { get; set; }
/// <summary>
/// Optional descriptive comment for the transaction. e.g. "Win from wager [id]", "Balance adjustment by Avenue", "Juicer from Null", etc.
/// </summary>
public string? Comment { get; set; } = null;
/// <summary>
/// Sender of the transaction in the case of a juicer, null otherwise
/// </summary>
public GamblerDbModel? From { get; set; } = null;
/// <summary>
/// Snapshot of the gambler's balance after this transaction's effect was applied
/// </summary>
public required decimal NewBalance { get; set; }
}
public class WagerDbModel
{
/// <summary>
/// ID fo the database row
/// </summary>
public int Id { get; set; }
/// <summary>
/// Gambler who wagered
/// </summary>
public required GamblerDbModel Gambler { get; set; }
/// <summary>
/// Time they wagered
/// </summary>
public required DateTimeOffset Time { get; set; }
/// <summary>
/// Time represented as a 64-bit UNIX epoch
/// This just exists to make it far more efficient to query a range of wagers
/// as then we can use native SQLite dialect to select e.g. last 24 hours
/// instead of copying thousands of rows into memory and using LINQ
/// </summary>
public required long TimeUnixEpochSeconds { get; set; }
/// <summary>
/// Amount the gambler wagered
/// </summary>
public required decimal WagerAmount { get; set; }
/// <summary>
/// Effect of the wager on the gambler's balance
/// </summary>
public required decimal WagerEffect { get; set; }
/// <summary>
/// Game they played to wager the amount (Note: enum must be extended for any new games.
/// Don't remove games which are legacy from the enum, just give them the Obsolete attribute)
/// </summary>
public required WagerGame Game { get; set; }
/// <summary>
/// Multiplier, e.g. 10.5x if a $1 wager paid out $10.50. 0 if it was a complete loss
/// </summary>
public required decimal Multiplier { get; set; }
/// <summary>
/// An optional field to store serialized information about the game that was played
/// </summary>
public string? GameMeta { get; set; } = null;
/// <summary>
/// Whether the results of the wager have been realized yet (i.e., is the game 'complete'?)
/// This is useful for wagers related to bets on the outcome of events
/// For incomplete bets: set the effect to -wager, subtract it from the user's balance, generate a txn for the wager
/// Then when the outcome of the bet is fully realized, modify the effect accordingly, generate a new txn for the
/// payout and set a multiplier based on the win (if any)
/// </summary>
public required bool IsComplete { get; set; }
}
public class GamblerExclusionDbModel
{
/// <summary>
/// ID fo the database row
/// </summary>
public int Id { get; set; }
/// <summary>
/// Gambler who is excluded
/// </summary>
public required GamblerDbModel Gambler { get; set; }
/// <summary>
/// When the exclusion expires
/// </summary>
public required DateTimeOffset Expires { get; set; }
/// <summary>
/// When the exclusion was created / began
/// </summary>
public required DateTimeOffset Created { get; set; }
/// <summary>
/// What triggered the exclusion
/// </summary>
public required ExclusionSource Source { get; set; }
}
public class GamblerPerkDbModel
{
/// <summary>
/// ID fo the database row
/// </summary>
public int Id { get; set; }
/// <summary>
/// Gambler entity the perk is associated with
/// </summary>
public required GamblerDbModel Gambler { get; set; }
/// <summary>
/// Name of the perk
/// </summary>
[MaxLength(256)]
public required string PerkName { get; set; }
/// <summary>
/// Time when the perk was attained
/// </summary>
public required DateTimeOffset Time { get; set; }
/// <summary>
/// Optional metadata associated with the perk
/// </summary>
public string? Metadata { get; set; } = null;
/// <summary>
/// What type of perk is this
/// </summary>
public required GamblerPerkType PerkType { get; set; }
/// <summary>
/// The tier the perk is at.
/// If tiers are not applicable, set to null
/// </summary>
public int? PerkTier { get; set; }
/// <summary>
/// The payout from this perk, if any. If none, set to null
/// </summary>
public decimal? Payout { get; set; }
}
public class KasinoShopProfileDbModel
{
/// <summary>
/// ID for the database row
/// </summary>
public int Id { get; set; }
/// <summary>
/// Shop profiles belong to a user, not their gambler ID
/// they persist even if the user abandons their profile
/// </summary>
public required UserDbModel User { get; set; }
public required List<KasinoShopProfileAssetDbModel> Assets { get; set; }
public required List<KasinoShopProfileLoanDbModel> Loans { get; set; }
}
public class KasinoShopProfileLoanDbModel
{
/// <summary>
/// ID for the database row
/// </summary>
public int Id { get; set; }
// Foreign key that the powers that be told me I need for the fancy navigation property
public int ProfileId { get; set; }
/// <summary>
/// Profile of the user who owns this loan
/// </summary>
public required KasinoShopProfileDbModel Profile { get; set; }
// Foreign key that the powers that be told me I need for the fancy navigation property
public int PayableToId { get; set; }
/// <summary>
/// Profile of the user to whom this loan is owed/payable to
/// </summary>
public required KasinoShopProfileDbModel PayableTo { get; set; }
/// <summary>
/// Amount loaned
/// </summary>
public required decimal Amount { get; set; }
/// <summary>
/// Amount to be paid out to the loaner
/// </summary>
public required decimal PayoutAmount { get; set; }
/// <summary>
/// Date and time loan entry was created
/// </summary>
public required DateTimeOffset Created { get; set; }
}
public class KasinoShopProfileAssetDbModel
{
/// <summary>
/// ID for the database row
/// </summary>
public int Id { get; set; }
/// <summary>
/// Profile of the user who owns this asset
/// </summary>
public required KasinoShopProfileDbModel Profile { get; set; }
/// <summary>
/// Value of the item at the time of acquisition in Krypto
/// </summary>
public required decimal OriginalValue { get; set; }
/// <summary>
/// Asset name
/// </summary>
public required string Name { get; set; }
/// <summary>
/// Asset type
/// </summary>
public required AssetType AssetType { get; set; }
/// <summary>
/// Date and time the asset was acquired
/// </summary>
public required DateTimeOffset Acquired { get; set; }
/// <summary>
/// History of value changes (e.g. interest events)
/// </summary>
public required List<KasinoShopProfileAssetValueChangeDbModel> ValueChangeReports { get; set; }
/// <summary>
/// Serialized JSON for extra information useful for certain assets (e.g. car model)
/// </summary>
public string? Extra { get; set; } = null;
}
public class KasinoShopProfileAssetValueChangeDbModel
{
/// <summary>
/// ID for the database row
/// </summary>
public int Id { get; set; }
/// <summary>
/// Related asset
/// </summary>
public required KasinoShopProfileAssetDbModel Asset { get; set; }
/// <summary>
/// Effect of the change
/// </summary>
public required decimal ValueChangeEffect { get; set; }
/// <summary>
/// Change percent as a decimal fraction?
/// </summary>
public required decimal ValueChangePercent { get; set; }
/// <summary>
/// Descriptive text for the value change (like the source of it)
/// </summary>
public required string Description { get; set; }
}
public enum GamblerPerkType
{
/// <summary>
/// For literally anything else, though you should probably just extend this enum
/// </summary>
Other = -1,
/// <summary>
/// Used for tracking VIP levels attained
/// </summary>
[Description("VIP Level")]
VipLevel
}
public enum ExclusionSource
{
/// <summary>
/// Exclusion as a result of the hostess' action
/// </summary>
Hostess,
/// <summary>
/// Exclusions placed by administrators
/// </summary>
Administrative
}
/// <summary>
/// What event triggered this transaction
/// </summary>
public enum TransactionSourceEventType
{
/// <summary>
/// Generic catch-all type if nothing else suits
/// </summary>
Other,
/// <summary>
/// Juice from another user. This is only for person to person transactions, use Bonus for kasino rewards
/// </summary>
Juicer,
/// <summary>
/// Transaction generated from the result of a wager
/// </summary>
Gambling,
/// <summary>
/// For recording events related to an administrative action. e.g. balance adjustments
/// </summary>
Administrative,
/// <summary>
/// Some type of bonus, like a VIP level up. Rakeback / reloads have separate enums for this
/// </summary>
Bonus,
/// <summary>
/// Specifically use for rakeback as we use the delta between last rakeback txn to calculate total wagered
/// to figure out what the next rakeback should be (if they've wagered enough to be eligible for one)
/// </summary>
Rakeback,
/// <summary>
/// Use specifically for daily reloads as we use the timing of the last reload txn to figure out if the most
/// recent reload has been claimed yet or not
/// </summary>
Reload,
/// <summary>
/// Use this only for hostess juicers as the sum of these juicers in a given day can influence the hostess' behavior
/// </summary>
Hostess,
/// <summary>
/// Specifically use for lossback as we use the delta between last lossback txn to calculate total lost
/// to figure out what the next lossback should be. (Basically return a small % of the player's losses
/// unless the player's actual position is positive during the period, then tell them to fuck off)
/// </summary>
Lossback,
/// <summary>
/// A specific form of 24 hour time-based reload that has no wager requirement
/// </summary>
DailyDollar,
///<summary>
///A form of juicer where the value is split among a number of participants
/// </summary>
Rain,
Deposit,
Withdraw,
Sponsorship,
Loan
}
public enum WagerGame
{
Limbo,
Dice,
Mines,
Planes,
[Description("Lambchop")]
LambChop,
Keno,
[Description("Coinflip")]
CoinFlip,
/// <summary>
/// This is for betting pools based on some sort of event or outcome
/// </summary>
Event,
[Description("Guess what number I'm thinking of")]
GuessWhatNumber,
Wheel,
Slots,
Blackjack,
[Description("Plinko")]
Plinko,
[Description("Roulette but live")]
Roulette,
Krash
}
public enum GamblerState
{
/// <summary>
/// Gambler entity is active and user can wager using the profile
/// </summary>
Active,
/// <summary>
/// Gambler entity has been disabled by an administrator (e.g. due to cheating)
/// The user will get a new gambler entity when they next interact with the kasino
/// </summary>
AdministrativelyDisabled,
/// <summary>
/// Gambler entity that was abandoned by the user (e.g. to escape an exclusion or crippling debt)
/// </summary>
Abandoned,
/// <summary>
/// Entity was permanently banned. This will prevent future gambler entities being created for this user
/// and will effectively lock them out of the game entirely
/// </summary>
PermanentlyBanned,
/// <summary>
/// Gambler rendered inactive by the End of Year 2025 Great Reset
/// This is treated no different to abandonment, state exists for
/// the purposes of tracking statistics later to see how much KKK
/// was erased by this event
/// </summary>
EndOfYear2025Liquidated
}