From b689a40595fcf4c4d68eec7115079a9866ef1d39 Mon Sep 17 00:00:00 2001 From: zhenhui <1276357500@qq.com> Date: Fri, 20 Mar 2026 10:24:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=80=E5=88=86=E6=97=B6?= =?UTF-8?q?=E4=B8=8D=E8=A7=A6=E5=8F=91=E4=B8=AD=E5=A4=A7=E5=A5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/app/api/logic/PlayStartLogic.php | 135 ++++++++++++++++-------- 1 file changed, 90 insertions(+), 45 deletions(-) diff --git a/server/app/api/logic/PlayStartLogic.php b/server/app/api/logic/PlayStartLogic.php index d91641b..945b329 100644 --- a/server/app/api/logic/PlayStartLogic.php +++ b/server/app/api/logic/PlayStartLogic.php @@ -109,6 +109,13 @@ class PlayStartLogic Log::warning("档位 {$tier} 方向 {$direction} 无任何 DiceReward,重新摇取档位"); continue; } + if ($usePoolWeights) { + $tierRewards = self::filterOutSuperWinOnlyGrids($tierRewards); + if (empty($tierRewards)) { + Log::warning("档位 {$tier} 方向 {$direction} 杀分档位下排除 5/30 后无可用奖励,重新摇取档位"); + continue; + } + } try { $chosen = self::drawRewardByWeight($tierRewards); } catch (\RuntimeException $e) { @@ -133,36 +140,44 @@ class PlayStartLogic $rewardWinCoin = $isTierT5 ? $realEv : (100 + $realEv); // 豹子判定:5/30 必豹子;10/15/20/25 按 DiceRewardConfig 中 BIGWIN 该点数的 weight 判定(0-10000,10000=100%) + // 杀分档位:不触发豹子,5/30 已在上方抽取时排除,10/15/20/25 仅生成非豹子组合 $superWinCoin = 0; $isWin = 0; $bigWinRealEv = 0.0; if (in_array($rollNumber, self::SUPER_WIN_GRID_NUMBERS, true)) { - $bigWinConfig = DiceRewardConfig::getCachedByTierAndGridNumber('BIGWIN', $rollNumber); - $alwaysSuperWin = in_array($rollNumber, self::SUPER_WIN_ALWAYS_GRID_NUMBERS, true); - $doSuperWin = $alwaysSuperWin; - if (!$doSuperWin) { - $bigWinWeight = 10000; - if ($bigWinConfig !== null && isset($bigWinConfig['weight'])) { - $bigWinWeight = min(10000, max(0, (int) $bigWinConfig['weight'])); - $bigWinRealEv = (float) ($bigWinConfig['real_ev'] ?? 0); - } - $roll = (random_int(0, PHP_INT_MAX - 1) / (float) PHP_INT_MAX); - $doSuperWin = $bigWinWeight > 0 && $roll < ($bigWinWeight / 10000.0); - } else { - if ($bigWinConfig !== null) { - $bigWinRealEv = (float) ($bigWinConfig['real_ev'] ?? 0); - } - } - if ($doSuperWin) { - $rollArray = $this->getSuperWinRollArray($rollNumber); - $isWin = 1; - $superWinCoin = $bigWinRealEv > 0 ? $bigWinRealEv : self::SUPER_WIN_BONUS; - // 中 BIGWIN 豹子:不走原奖励流程,不记录原奖励,不触发 T5 再来一次,仅发放豹子奖金 - $rewardWinCoin = 0; - $realEv = 0; - $isTierT5 = false; - } else { + if ($usePoolWeights) { + // 杀分档位:绝不触发豹子,仅生成非豹子组合,不发放豹子奖金 + $isWin = 0; + $superWinCoin = 0.0; $rollArray = $this->generateNonSuperWinRollArrayWithSum($rollNumber); + } else { + $bigWinConfig = DiceRewardConfig::getCachedByTierAndGridNumber('BIGWIN', $rollNumber); + $alwaysSuperWin = in_array($rollNumber, self::SUPER_WIN_ALWAYS_GRID_NUMBERS, true); + $doSuperWin = $alwaysSuperWin; + if (!$doSuperWin) { + $bigWinWeight = 10000; + if ($bigWinConfig !== null && isset($bigWinConfig['weight'])) { + $bigWinWeight = min(10000, max(0, (int) $bigWinConfig['weight'])); + $bigWinRealEv = (float) ($bigWinConfig['real_ev'] ?? 0); + } + $roll = (random_int(0, PHP_INT_MAX - 1) / (float) PHP_INT_MAX); + $doSuperWin = $bigWinWeight > 0 && $roll < ($bigWinWeight / 10000.0); + } else { + if ($bigWinConfig !== null) { + $bigWinRealEv = (float) ($bigWinConfig['real_ev'] ?? 0); + } + } + if ($doSuperWin) { + $rollArray = $this->getSuperWinRollArray($rollNumber); + $isWin = 1; + $superWinCoin = $bigWinRealEv > 0 ? $bigWinRealEv : self::SUPER_WIN_BONUS; + // 中 BIGWIN 豹子:不走原奖励流程,不记录原奖励,不触发 T5 再来一次,仅发放豹子奖金 + $rewardWinCoin = 0; + $realEv = 0; + $isTierT5 = false; + } else { + $rollArray = $this->generateNonSuperWinRollArrayWithSum($rollNumber); + } } } else { $rollArray = $this->generateRollArrayFromSum($rollNumber); @@ -330,6 +345,21 @@ class PlayStartLogic /** 该组配置权重均为 0 时抛出,供调用方重试 */ private const EXCEPTION_WEIGHT_ALL_ZERO = 'REWARD_WEIGHT_ALL_ZERO'; + /** 杀分档位需排除的豹子号:5 和 30 只能组成豹子,无法生成非豹子组合 */ + private const KILL_MODE_EXCLUDE_GRIDS = [5, 30]; + + /** + * 杀分档位下排除 grid_number=5/30 的奖励(5/30 只能豹子,无法剔除) + * @return array 排除后的奖励列表,保持索引连续 + */ + private static function filterOutSuperWinOnlyGrids(array $rewards): array + { + return array_values(array_filter($rewards, function ($r) { + $g = (int) ($r['grid_number'] ?? 0); + return !in_array($g, self::KILL_MODE_EXCLUDE_GRIDS, true); + })); + } + /** * 按权重抽取一条配置:仅 weight>0 参与抽取(weight=0 不会被摇到) * 使用 [0, total) 浮点随机,支持最小权重 0.1%(如 weight=0.1),避免整数随机导致小权重失真 @@ -463,6 +493,14 @@ class PlayStartLogic if (empty($tierRewards)) { continue; } + // 免费券或 killScore 池:与实际流程一致,排除 5/30 且不触发豹子 + $useKillMode = ($lotteryType === 1) || ($config !== null && (string) ($config->name ?? '') === 'killScore'); + if ($useKillMode) { + $tierRewards = self::filterOutSuperWinOnlyGrids($tierRewards); + if (empty($tierRewards)) { + continue; + } + } try { $chosen = self::drawRewardByWeight($tierRewards); } catch (\RuntimeException $e) { @@ -488,27 +526,34 @@ class PlayStartLogic $isWin = 0; $bigWinRealEv = 0.0; if (in_array($rollNumber, self::SUPER_WIN_GRID_NUMBERS, true)) { - $bigWinConfig = DiceRewardConfig::getCachedByTierAndGridNumber('BIGWIN', $rollNumber); - $alwaysSuperWin = in_array($rollNumber, self::SUPER_WIN_ALWAYS_GRID_NUMBERS, true); - $doSuperWin = $alwaysSuperWin; - if (!$doSuperWin) { - $bigWinWeight = 10000; - if ($bigWinConfig !== null && isset($bigWinConfig['weight'])) { - $bigWinWeight = min(10000, max(0, (int) $bigWinConfig['weight'])); - } - $roll = (random_int(0, PHP_INT_MAX - 1) / (float) PHP_INT_MAX); - $doSuperWin = $bigWinWeight > 0 && $roll < ($bigWinWeight / 10000.0); - } - if ($bigWinConfig !== null && isset($bigWinConfig['real_ev'])) { - $bigWinRealEv = (float) $bigWinConfig['real_ev']; - } - if ($doSuperWin) { - $rollArray = $this->getSuperWinRollArray($rollNumber); - $isWin = 1; - $superWinCoin = $bigWinRealEv > 0 ? $bigWinRealEv : self::SUPER_WIN_BONUS; - $rewardWinCoin = 0; - } else { + if ($useKillMode) { + // 杀分档位:绝不触发豹子,仅生成非豹子组合,不发放豹子奖金 + $isWin = 0; + $superWinCoin = 0.0; $rollArray = $this->generateNonSuperWinRollArrayWithSum($rollNumber); + } else { + $bigWinConfig = DiceRewardConfig::getCachedByTierAndGridNumber('BIGWIN', $rollNumber); + $alwaysSuperWin = in_array($rollNumber, self::SUPER_WIN_ALWAYS_GRID_NUMBERS, true); + $doSuperWin = $alwaysSuperWin; + if (!$doSuperWin) { + $bigWinWeight = 10000; + if ($bigWinConfig !== null && isset($bigWinConfig['weight'])) { + $bigWinWeight = min(10000, max(0, (int) $bigWinConfig['weight'])); + } + $roll = (random_int(0, PHP_INT_MAX - 1) / (float) PHP_INT_MAX); + $doSuperWin = $bigWinWeight > 0 && $roll < ($bigWinWeight / 10000.0); + } + if ($bigWinConfig !== null && isset($bigWinConfig['real_ev'])) { + $bigWinRealEv = (float) $bigWinConfig['real_ev']; + } + if ($doSuperWin) { + $rollArray = $this->getSuperWinRollArray($rollNumber); + $isWin = 1; + $superWinCoin = $bigWinRealEv > 0 ? $bigWinRealEv : self::SUPER_WIN_BONUS; + $rewardWinCoin = 0; + } else { + $rollArray = $this->generateNonSuperWinRollArrayWithSum($rollNumber); + } } } else { $rollArray = $this->generateRollArrayFromSum($rollNumber);