first commit
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
local spinLocks = {}
|
||||
local gameLocks = {}
|
||||
local blackjackSessions = {}
|
||||
|
||||
local rewards = {
|
||||
{ type = 'cash', amount = 500, label = '500 $ Bargeld' },
|
||||
{ type = 'xp', amount = 25, label = '25 RP-XP' },
|
||||
{ type = 'bank', amount = 1000, label = '1.000 $ Bankguthaben' },
|
||||
{ type = 'cash', amount = 750, label = '750 $ Bargeld' },
|
||||
{ type = 'xp', amount = 50, label = '50 RP-XP' },
|
||||
{ type = 'bank', amount = 1500, label = '1.500 $ Bankguthaben' },
|
||||
{ type = 'cash', amount = 1250, label = '1.250 $ Bargeld' },
|
||||
{ type = 'xp', amount = 100, label = '100 RP-XP' }
|
||||
}
|
||||
|
||||
MySQL.ready(function()
|
||||
MySQL.query.await([[
|
||||
CREATE TABLE IF NOT EXISTS devx_casino_daily (
|
||||
character_id BIGINT UNSIGNED NOT NULL,
|
||||
last_spin DATETIME NULL,
|
||||
total_spins INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (character_id),
|
||||
CONSTRAINT fk_devx_casino_character FOREIGN KEY (character_id)
|
||||
REFERENCES devx_characters (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
]])
|
||||
MySQL.query.await([[
|
||||
CREATE TABLE IF NOT EXISTS devx_casino_wallets (
|
||||
character_id BIGINT UNSIGNED NOT NULL,
|
||||
chips BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (character_id),
|
||||
CONSTRAINT fk_devx_casino_wallet_character FOREIGN KEY (character_id)
|
||||
REFERENCES devx_characters (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
]])
|
||||
end)
|
||||
|
||||
local function amount(value, min, max)
|
||||
local n = math.floor(tonumber(value) or 0)
|
||||
if n < (min or 1) or n > (max or 100000) then return nil end
|
||||
return n
|
||||
end
|
||||
local function wallet(characterId)
|
||||
MySQL.query.await('INSERT IGNORE INTO devx_casino_wallets (character_id, chips) VALUES (?, 0)', { characterId })
|
||||
return tonumber(MySQL.scalar.await('SELECT chips FROM devx_casino_wallets WHERE character_id = ?', { characterId })) or 0
|
||||
end
|
||||
local function addChips(characterId, chips)
|
||||
MySQL.query.await([[
|
||||
INSERT INTO devx_casino_wallets (character_id, chips) VALUES (?, ?)
|
||||
ON DUPLICATE KEY UPDATE chips = chips + VALUES(chips)
|
||||
]], { characterId, chips })
|
||||
return wallet(characterId)
|
||||
end
|
||||
local function removeChips(characterId, chips)
|
||||
local changed = MySQL.update.await([[
|
||||
UPDATE devx_casino_wallets SET chips = chips - ? WHERE character_id = ? AND chips >= ?
|
||||
]], { chips, characterId, chips })
|
||||
return changed and changed > 0, wallet(characterId)
|
||||
end
|
||||
local function spinStatus(characterId)
|
||||
local row = MySQL.single.await([[
|
||||
SELECT UNIX_TIMESTAMP(last_spin) AS lastSpin, total_spins AS totalSpins
|
||||
FROM devx_casino_daily WHERE character_id = ? LIMIT 1
|
||||
]], { characterId })
|
||||
local lastSpin = row and tonumber(row.lastSpin) or 0
|
||||
local nextSpin = lastSpin + DevXCasinoConfig.CooldownSeconds
|
||||
return { available = os.time() >= nextSpin, remainingSeconds = math.max(0, nextSpin - os.time()), totalSpins = row and tonumber(row.totalSpins) or 0 }
|
||||
end
|
||||
local function card()
|
||||
local rank = math.random(1, 13)
|
||||
local labels = { 'A','2','3','4','5','6','7','8','9','10','J','Q','K' }
|
||||
return { rank = rank, label = labels[rank] }
|
||||
end
|
||||
local function handValue(cards)
|
||||
local total, aces = 0, 0
|
||||
for _, item in ipairs(cards) do
|
||||
if item.rank == 1 then total = total + 11; aces = aces + 1
|
||||
elseif item.rank >= 10 then total = total + 10
|
||||
else total = total + item.rank end
|
||||
end
|
||||
while total > 21 and aces > 0 do total = total - 10; aces = aces - 1 end
|
||||
return total
|
||||
end
|
||||
local function blackjackPayload(session, reveal, result)
|
||||
local dealer = {}
|
||||
for index, item in ipairs(session.dealer) do
|
||||
dealer[index] = (reveal or index == 1) and item or { label = '?' }
|
||||
end
|
||||
return {
|
||||
ok = true, active = result == nil, result = result,
|
||||
playerCards = session.player, dealerCards = dealer,
|
||||
playerValue = handValue(session.player), dealerValue = reveal and handValue(session.dealer) or nil,
|
||||
chips = wallet(session.characterId)
|
||||
}
|
||||
end
|
||||
local function settleBlackjack(source, session, outcome)
|
||||
local result = outcome
|
||||
if outcome == 'win' then addChips(session.characterId, session.bet * 2)
|
||||
elseif outcome == 'blackjack' then addChips(session.characterId, math.floor(session.bet * 2.5))
|
||||
elseif outcome == 'push' then addChips(session.characterId, session.bet) end
|
||||
blackjackSessions[source] = nil
|
||||
return blackjackPayload(session, true, result)
|
||||
end
|
||||
|
||||
DevXRegisterCallback('casino:status', function(source)
|
||||
local player = exports.devx_core:GetPlayer(source)
|
||||
if not player then return { ok = false, error = 'Kein Charakter aktiv.' } end
|
||||
local status = spinStatus(player.characterId)
|
||||
status.ok = true; status.chips = wallet(player.characterId)
|
||||
return status
|
||||
end)
|
||||
|
||||
DevXRegisterCallback('casino:exchange', function(source, payload)
|
||||
local player = exports.devx_core:GetPlayer(source)
|
||||
local value = amount(payload.amount, 100, 100000)
|
||||
local direction = payload.direction
|
||||
if not player or not value or (direction ~= 'buy' and direction ~= 'sell') then return { ok = false, error = 'Ungültige Wechselanfrage.' } end
|
||||
if gameLocks[source] then return { ok = false, error = 'Eine Casino-Buchung läuft bereits.' } end
|
||||
gameLocks[source] = true
|
||||
local response
|
||||
if direction == 'buy' then
|
||||
local paid, balance = exports.devx_banking:ChargeCharacter(player.characterId, value, 'Casino-Chips', 'Diamond Casino')
|
||||
if paid then exports.devx_core:SetBankCache(source, balance); response = { ok = true, chips = addChips(player.characterId, value) }
|
||||
else response = { ok = false, error = balance } end
|
||||
else
|
||||
local removed = removeChips(player.characterId, value)
|
||||
if removed then
|
||||
local credited, balance = exports.devx_banking:CreditCharacter(player.characterId, value, 'Casino-Chips eingelöst', 'Diamond Casino')
|
||||
if credited then exports.devx_core:SetBankCache(source, balance); response = { ok = true, chips = wallet(player.characterId) }
|
||||
else addChips(player.characterId, value); response = { ok = false, error = balance } end
|
||||
else response = { ok = false, error = 'Du besitzt nicht genügend Chips.' } end
|
||||
end
|
||||
gameLocks[source] = nil
|
||||
return response
|
||||
end)
|
||||
|
||||
DevXRegisterCallback('casino:spin', function(source)
|
||||
local player = exports.devx_core:GetPlayer(source)
|
||||
if not player then return { ok = false, error = 'Kein Charakter aktiv.' } end
|
||||
if spinLocks[source] then return { ok = false, error = 'Dein Glücksrad-Dreh läuft bereits.' } end
|
||||
spinLocks[source] = true
|
||||
local status = spinStatus(player.characterId)
|
||||
if not status.available then spinLocks[source] = nil; return { ok = false, error = ('Nächster Dreh in %s Stunden.'):format(math.ceil(status.remainingSeconds / 3600)) } end
|
||||
|
||||
local index = math.random(1, #rewards); local reward = rewards[index]; local success = false
|
||||
if reward.type == 'cash' then success = exports.devx_core:AddCash(source, reward.amount, 'Casino-Glücksrad') == true
|
||||
elseif reward.type == 'bank' then
|
||||
local credited, newBalance = exports.devx_banking:CreditCharacter(player.characterId, reward.amount, 'Casino-Glücksrad', 'Diamond Casino')
|
||||
success = credited == true; if success then exports.devx_core:SetBankCache(source, newBalance) end
|
||||
elseif reward.type == 'xp' then success = exports.devx_core:AddMetadataNumber(source, 'rpXp', reward.amount) == true end
|
||||
if not success then spinLocks[source] = nil; return { ok = false, error = 'Gewinn konnte nicht gutgeschrieben werden.' } end
|
||||
|
||||
MySQL.query.await([[
|
||||
INSERT INTO devx_casino_daily (character_id, last_spin, total_spins) VALUES (?, NOW(), 1)
|
||||
ON DUPLICATE KEY UPDATE last_spin = NOW(), total_spins = total_spins + 1
|
||||
]], { player.characterId })
|
||||
spinLocks[source] = nil
|
||||
return { ok = true, reward = reward, segment = index - 1, totalSegments = #rewards, nextSpinSeconds = DevXCasinoConfig.CooldownSeconds }
|
||||
end)
|
||||
|
||||
DevXRegisterCallback('casino:slots', function(source, payload)
|
||||
local player = exports.devx_core:GetPlayer(source); local bet = amount(payload.bet, 100, 5000)
|
||||
if not player or not bet then return { ok = false, error = 'Ungültiger Einsatz.' } end
|
||||
local removed = removeChips(player.characterId, bet)
|
||||
if not removed then return { ok = false, error = 'Nicht genügend Chips.' } end
|
||||
local symbols = { '7', 'BAR', 'KIRSCHE', 'DIAMANT', 'GLOCKE', 'ZITRONE' }
|
||||
local roll = { symbols[math.random(#symbols)], symbols[math.random(#symbols)], symbols[math.random(#symbols)] }
|
||||
local payout = 0
|
||||
if roll[1] == roll[2] and roll[2] == roll[3] then payout = bet * (roll[1] == '7' and 12 or 7)
|
||||
elseif roll[1] == roll[2] or roll[2] == roll[3] or roll[1] == roll[3] then payout = bet * 2 end
|
||||
if payout > 0 then addChips(player.characterId, payout) end
|
||||
return { ok = true, symbols = roll, payout = payout, chips = wallet(player.characterId) }
|
||||
end)
|
||||
|
||||
local redNumbers = { [1]=true,[3]=true,[5]=true,[7]=true,[9]=true,[12]=true,[14]=true,[16]=true,[18]=true,[19]=true,[21]=true,[23]=true,[25]=true,[27]=true,[30]=true,[32]=true,[34]=true,[36]=true }
|
||||
DevXRegisterCallback('casino:roulette', function(source, payload)
|
||||
local player = exports.devx_core:GetPlayer(source); local bet = amount(payload.bet, 100, 10000); local choice = payload.choice
|
||||
if not player or not bet or (choice ~= 'red' and choice ~= 'black' and choice ~= 'green') then return { ok = false, error = 'Ungültiger Einsatz.' } end
|
||||
local removed = removeChips(player.characterId, bet); if not removed then return { ok = false, error = 'Nicht genügend Chips.' } end
|
||||
local number = math.random(0, 36); local color = number == 0 and 'green' or (redNumbers[number] and 'red' or 'black')
|
||||
local payout = color == choice and bet * (color == 'green' and 14 or 2) or 0
|
||||
if payout > 0 then addChips(player.characterId, payout) end
|
||||
return { ok = true, number = number, color = color, payout = payout, chips = wallet(player.characterId) }
|
||||
end)
|
||||
|
||||
DevXRegisterCallback('casino:blackjackStart', function(source, payload)
|
||||
local player = exports.devx_core:GetPlayer(source); local bet = amount(payload.bet, 100, 10000)
|
||||
if not player or not bet then return { ok = false, error = 'Ungültiger Einsatz.' } end
|
||||
if blackjackSessions[source] then return { ok = false, error = 'Du spielst bereits eine Runde.' } end
|
||||
local removed = removeChips(player.characterId, bet); if not removed then return { ok = false, error = 'Nicht genügend Chips.' } end
|
||||
local session = { characterId = player.characterId, bet = bet, player = { card(), card() }, dealer = { card(), card() } }
|
||||
blackjackSessions[source] = session
|
||||
local pv, dv = handValue(session.player), handValue(session.dealer)
|
||||
if pv == 21 and dv == 21 then return settleBlackjack(source, session, 'push') end
|
||||
if pv == 21 then return settleBlackjack(source, session, 'blackjack') end
|
||||
if dv == 21 then return settleBlackjack(source, session, 'lose') end
|
||||
return blackjackPayload(session, false, nil)
|
||||
end)
|
||||
|
||||
DevXRegisterCallback('casino:blackjackAction', function(source, payload)
|
||||
local session = blackjackSessions[source]
|
||||
if not session then return { ok = false, error = 'Keine aktive Blackjack-Runde.' } end
|
||||
if payload.action == 'hit' then
|
||||
session.player[#session.player + 1] = card()
|
||||
local value = handValue(session.player)
|
||||
if value > 21 then return settleBlackjack(source, session, 'bust') end
|
||||
if value == 21 then payload.action = 'stand' else return blackjackPayload(session, false, nil) end
|
||||
end
|
||||
if payload.action == 'stand' then
|
||||
while handValue(session.dealer) < 17 do session.dealer[#session.dealer + 1] = card() end
|
||||
local pv, dv = handValue(session.player), handValue(session.dealer)
|
||||
if dv > 21 or pv > dv then return settleBlackjack(source, session, 'win')
|
||||
elseif pv == dv then return settleBlackjack(source, session, 'push')
|
||||
else return settleBlackjack(source, session, 'lose') end
|
||||
end
|
||||
return { ok = false, error = 'Ungültige Aktion.' }
|
||||
end)
|
||||
|
||||
RegisterCommand('resetwheel', function(source, args)
|
||||
if source ~= 0 and not IsPlayerAceAllowed(source, 'devx.admin') then return end
|
||||
local target = tonumber(args[1]) or source
|
||||
local player = exports.devx_core:GetPlayer(target)
|
||||
if not player then return end
|
||||
MySQL.query.await('DELETE FROM devx_casino_daily WHERE character_id = ?', { player.characterId })
|
||||
TriggerClientEvent('devx_casino:client:notify', target, 'Dein täglicher Glücksrad-Dreh wurde zurückgesetzt.')
|
||||
end, false)
|
||||
|
||||
AddEventHandler('playerDropped', function()
|
||||
spinLocks[source] = nil; gameLocks[source] = nil; blackjackSessions[source] = nil
|
||||
end)
|
||||
Reference in New Issue
Block a user