|
@@ -16,6 +16,7 @@ final class PromotionRules
|
|
|
public const TASKS = ['online', 'login', 'invite', 'deposit', 'team_deposit', 'bet', 'team_bet'];
|
|
public const TASKS = ['online', 'login', 'invite', 'deposit', 'team_deposit', 'bet', 'team_bet'];
|
|
|
public const DAILY = ['online', 'login'];
|
|
public const DAILY = ['online', 'login'];
|
|
|
public const PRIZES = ['0-666', '100', '50', '200', '350', '500', '150', '366'];
|
|
public const PRIZES = ['0-666', '100', '50', '200', '350', '500', '150', '366'];
|
|
|
|
|
+ public const ORDINARY_POOL_RULE = '未完成本轮全部任务时,普通抽奖最多累计至600。任务完成后,未命中666时按剩余差额和达成概率控制单次奖额。可用奖项等概率,固定奖项按面额发放。';
|
|
|
public const REWARD_MODES = ['cash', 'coupon'];
|
|
public const REWARD_MODES = ['cash', 'coupon'];
|
|
|
public const COUPON_CATEGORIES = ['self:sport', 'self:lottery'];
|
|
public const COUPON_CATEGORIES = ['self:sport', 'self:lottery'];
|
|
|
private const COUPON_KEYS = ['reward_mode', 'coupon_valid_from', 'coupon_valid_until', 'coupon_categories', 'inviter_coupons', 'invitee_coupons'];
|
|
private const COUPON_KEYS = ['reward_mode', 'coupon_valid_from', 'coupon_valid_until', 'coupon_categories', 'inviter_coupons', 'invitee_coupons'];
|
|
@@ -143,13 +144,27 @@ final class PromotionRules
|
|
|
$random ??= fn (int $min, int $max) => random_int($min, $max);
|
|
$random ??= fn (int $min, int $max) => random_int($min, $max);
|
|
|
$remaining = 66600 - $coins;
|
|
$remaining = 66600 - $coins;
|
|
|
if ($remaining <= 0) throw new \LogicException('请先领取本轮奖金');
|
|
if ($remaining <= 0) throw new \LogicException('请先领取本轮奖金');
|
|
|
- $hit = $complete && $random(1, 10000) <= (int)bcmul($probability, '100', 0);
|
|
|
|
|
|
|
+ $probabilityBps = (int)bcmul($probability, '100', 0);
|
|
|
|
|
+ $hit = $complete && $random(1, 10000) <= $probabilityBps;
|
|
|
if ($hit) return ['prize_index' => 0, 'amount_cents' => $remaining, 'reached' => true];
|
|
if ($hit) return ['prize_index' => 0, 'amount_cents' => $remaining, 'reached' => true];
|
|
|
|
|
+
|
|
|
|
|
+ if ($complete) {
|
|
|
|
|
+ // Use twice the expected draws, rounded up and capped at ten. Budget one unit per draw,
|
|
|
|
|
+ // then spread the remaining cents across that many misses once inside the buffer.
|
|
|
|
|
+ $pacedSpins = (int)min(10, ceil(20000 / max(1, $probabilityBps)));
|
|
|
|
|
+ $maxAmount = min($remaining - 1, max($remaining - $pacedSpins * 100, intdiv($remaining - 1, $pacedSpins), 1));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Leave 66 for the qualified stage and award at most a quarter of the available room, rounded up to a cent.
|
|
|
|
|
+ $headroom = max(0, 60000 - $coins);
|
|
|
|
|
+ $maxAmount = intdiv($headroom + 3, 4);
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($maxAmount === 0) return ['prize_index' => 0, 'amount_cents' => 0, 'reached' => false];
|
|
|
|
|
+
|
|
|
// Choose eligible sectors before drawing. A fixed face value is never truncated.
|
|
// Choose eligible sectors before drawing. A fixed face value is never truncated.
|
|
|
$eligible = [0];
|
|
$eligible = [0];
|
|
|
- foreach (self::PRIZES as $i => $amount) if ($i && (int)$amount * 100 < $remaining) $eligible[] = $i;
|
|
|
|
|
|
|
+ foreach (self::PRIZES as $i => $amount) if ($i && (int)$amount * 100 <= $maxAmount) $eligible[] = $i;
|
|
|
$index = $eligible[$random(0, count($eligible) - 1)];
|
|
$index = $eligible[$random(0, count($eligible) - 1)];
|
|
|
- $amount = $index === 0 ? $random(0, $remaining - 1) : (int)self::PRIZES[$index] * 100;
|
|
|
|
|
|
|
+ $amount = $index === 0 ? $random(1, $maxAmount) : (int)self::PRIZES[$index] * 100;
|
|
|
return ['prize_index' => $index, 'amount_cents' => $amount, 'reached' => false];
|
|
return ['prize_index' => $index, 'amount_cents' => $amount, 'reached' => false];
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|