1.优化中奖,当余额不足支付惩罚时,直接扣完钱包

This commit is contained in:
2026-06-01 14:09:26 +08:00
parent d77e390fa3
commit 3f97905ffa
5 changed files with 47 additions and 37 deletions

View File

@@ -50,6 +50,8 @@ class PlayStartLogic
private const SUPER_WIN_GRID_NUMBERS = [5, 10, 15, 20, 25, 30];
/** 5 和 30 抽到即豹子,不参与 BIGWIN 权重判定10/15/20/25 按 BIGWIN weight 判定是否豹子 */
private const SUPER_WIN_ALWAYS_GRID_NUMBERS = [5, 30];
/** T4 惩罚格余额不足时写入游玩记录的备注 */
private const REMARK_T4_INSUFFICIENT_BALANCE = '惩罚格奖励:玩家余额不足,已扣尽钱包剩余余额';
/**
* 执行一局游戏
@@ -124,26 +126,8 @@ class PlayStartLogic
// 付费抽奖:开始前扣除费用 ante * UNIT_COST
$paidAmount = $ticketType === self::LOTTERY_TYPE_PAID ? round($ante * self::UNIT_COST, 2) : 0.0;
// 游玩前余额校验(按 T4 惩罚最大值兜底):
// 门槛 = paidAmount(压注*1) + abs(T4最小real_ev)*ante
$t4List = DiceRewardConfig::getCachedByTier('T4', $configDeptId);
$t4MinRealEv = null;
foreach ($t4List as $row) {
$ev = $row['real_ev'] ?? null;
if ($ev === null || $ev === '') {
continue;
}
$evFloat = filter_var($ev, FILTER_VALIDATE_FLOAT);
if ($evFloat === false) {
continue;
}
if ($t4MinRealEv === null || $evFloat < $t4MinRealEv) {
$t4MinRealEv = $evFloat;
}
}
$t4PenaltyAbs = $t4MinRealEv === null ? 0.0 : abs($t4MinRealEv) * $ante;
$needMinBalance = round($paidAmount + $t4PenaltyAbs, 2);
if ($coin < $needMinBalance) {
// 付费抽奖余额不足单局费用ante * UNIT_COST时不允许开始惩罚格不足部分在局内扣尽剩余余额
if ($ticketType === self::LOTTERY_TYPE_PAID && $coin < $paidAmount) {
throw new ApiException('余额不足');
}
@@ -265,6 +249,7 @@ class PlayStartLogic
$winCoin = round($superWinCoin + $rewardWinCoin, 2); // 赢取平台币 = 中大奖 + 摇色子中奖(豹子时 rewardWinCoin 已为 0
$record = null;
$settledWinCoin = $winCoin;
$configId = (int) $config->id;
$type0ConfigId = (int) $configType0->id;
$rewardId = ($isWin === 1 && $superWinCoin > 0) ? 0 : $targetIndex; // 中豹子不记录原奖励配置 id
@@ -293,9 +278,31 @@ class PlayStartLogic
$rollArray,
$isTierT5,
$tier,
&$record
&$record,
&$settledWinCoin
) {
$rewardTier = ($isWin === 1 && $superWinCoin > 0) ? 'BIGWIN' : (string) ($tier ?? '');
$p = DicePlayer::find($playerId);
if (!$p) {
throw new \RuntimeException('玩家不存在');
}
$coinBefore = (float) $p->coin;
// 开始前先扣付费金额,再加中奖金额(免费抽奖 paid_amount=0
$coinAfter = round($coinBefore - $paidAmount + $winCoin, 2);
$recordWinCoin = $winCoin;
$recordRewardWinCoin = $rewardWinCoin;
$playRecordRemark = null;
// T4 惩罚:扣完购券费用后若不足以支付全额惩罚,则扣尽钱包剩余余额并记录备注
if ($rewardTier === 'T4' && $coinAfter < 0) {
$walletRemain = round($coinBefore - $paidAmount, 2);
$coinAfter = 0.0;
$recordWinCoin = round(-$walletRemain, 2);
$recordRewardWinCoin = $recordWinCoin;
$playRecordRemark = self::REMARK_T4_INSUFFICIENT_BALANCE;
}
$settledWinCoin = $recordWinCoin;
$record = DicePlayRecord::create([
'player_id' => $playerId,
'dept_id' => $playerDeptId,
@@ -305,9 +312,9 @@ class PlayStartLogic
'ante' => $ante,
'paid_amount' => $paidAmount,
'is_win' => $isWin,
'win_coin' => $winCoin,
'win_coin' => $recordWinCoin,
'super_win_coin' => $superWinCoin,
'reward_win_coin' => $rewardWinCoin,
'reward_win_coin' => $recordRewardWinCoin,
'direction' => $direction,
'reward_tier' => $rewardTier,
'start_index' => $startIndex,
@@ -315,19 +322,9 @@ class PlayStartLogic
'roll_array' => is_array($rollArray) ? json_encode($rollArray) : $rollArray,
'roll_number' => is_array($rollArray) ? array_sum($rollArray) : 0,
'status' => self::RECORD_STATUS_SUCCESS,
'remark' => $playRecordRemark,
]);
$p = DicePlayer::find($playerId);
if (!$p) {
throw new \RuntimeException('玩家不存在');
}
$coinBefore = (float) $p->coin;
// 开始前先扣付费金额,再加中奖金额(免费抽奖 paid_amount=0
$coinAfter = round($coinBefore - $paidAmount + $winCoin, 2);
// T4 惩罚兜底:扣完购券费用后若余额不足以承受本次惩罚(导致为负),统一按“余额不足”提示
if ($rewardTier === 'T4' && $coinAfter < 0) {
throw new ApiException('余额不足');
}
$p->coin = $coinAfter;
// 免费抽奖消耗:优先消耗 free_ticket.count耗尽则清空 free_ticket否则兼容旧 free_ticket_count
if ($ticketType === self::LOTTERY_TYPE_FREE) {
@@ -429,7 +426,7 @@ class PlayStartLogic
// 彩金池累计盈利累加在 name=default 彩金池上:
// 付费:每局按「本局赢取平台币 win_coin - 抽奖费用 paid_amountante*UNIT_COST
// 免费券paid_amount=0只计入 win_coin
$perPlayProfit = ($ticketType === self::LOTTERY_TYPE_PAID) ? ($winCoin - $paidAmount) : $winCoin;
$perPlayProfit = ($ticketType === self::LOTTERY_TYPE_PAID) ? ($recordWinCoin - $paidAmount) : $recordWinCoin;
$addProfit = round($perPlayProfit, 2);
try {
DiceLotteryPoolConfig::where('id', $type0ConfigId)->update([
@@ -459,12 +456,15 @@ class PlayStartLogic
}
$walletBeforeDraw = $coinBefore - $paidAmount;
$drawRemark = ($winCoin >= 0 ? '抽奖中奖' : '抽奖惩罚') . '|play_record_id=' . $record->id;
$drawRemark = ($recordWinCoin >= 0 ? '抽奖中奖' : '抽奖惩罚') . '|play_record_id=' . $record->id;
if ($playRecordRemark !== null) {
$drawRemark .= '|' . $playRecordRemark;
}
DicePlayerWalletRecord::create([
'player_id' => $playerId,
'dept_id' => $playerDeptId,
'admin_id' => $adminId,
'coin' => $winCoin,
'coin' => $recordWinCoin,
'type' => self::WALLET_TYPE_DRAW,
'wallet_before' => round($walletBeforeDraw, 2),
'wallet_after' => $coinAfter,

View File

@@ -31,6 +31,7 @@ use think\model\relation\BelongsTo;
* @property $use_coins 消耗平台币(兼容字段:付费局=paid_amount免费局=0
* @property $direction 方向:0=顺时针,1=逆时针
* @property $reward_tier 中奖档位T1,T2,T3,T4,T5,BIGWIN
* @property $remark 备注(如惩罚格余额不足)
* @property $lottery_id 奖池
* @property $start_index 起始索引
* @property $target_index 结束索引