feat(game): 添加连续奖励表格和银行选项图标
- 在游戏规则模态框中添加连续奖励表格组件 - 更新英文和印尼语的游戏规则文本内容 - 添加银行选项的图标显示功能,支持自定义logo或默认地标图标 - 实现连续奖励数据类型和接口定义 - 在游戏会话存储中添加连续奖励行数据管理 - 集成银行选择下拉菜单中的图标展示 - 更新WithdrawField组件以支持银行图标显示
This commit is contained in:
@@ -33,6 +33,7 @@ import type {
|
||||
GameLobbyInitDto,
|
||||
GameLobbyInitResult,
|
||||
GameLobbyPeriodDto,
|
||||
GameLobbyStreakWinRewardRowDto,
|
||||
GamePeriodTickDto,
|
||||
GamePlaceBetDto,
|
||||
GamePlaceBetRequestDto,
|
||||
@@ -45,6 +46,7 @@ import type {
|
||||
RoundPhase,
|
||||
RoundSnapshot,
|
||||
RoundSnapshotDto,
|
||||
StreakWinRewardRow,
|
||||
TrendEntry,
|
||||
TrendEntryDto,
|
||||
} from '@/type'
|
||||
@@ -260,6 +262,26 @@ function normalizeLobbyCells(dictionary: GameLobbyInitDto['dictionary']) {
|
||||
)
|
||||
}
|
||||
|
||||
function normalizeStreakWinRewardRows(rows?: GameLobbyStreakWinRewardRowDto[]) {
|
||||
if (!Array.isArray(rows)) {
|
||||
return []
|
||||
}
|
||||
|
||||
return rows
|
||||
.filter((row) => Number.isFinite(row.streak))
|
||||
.map(
|
||||
(row) =>
|
||||
({
|
||||
fixedAmount: row.fixed_amount,
|
||||
isJackpot: row.is_jackpot,
|
||||
oddsFactor: Number(row.odds_factor) || 0,
|
||||
rewardType: row.reward_type,
|
||||
streak: Math.floor(row.streak),
|
||||
}) satisfies StreakWinRewardRow,
|
||||
)
|
||||
.sort((left, right) => left.streak - right.streak)
|
||||
}
|
||||
|
||||
export function normalizePeriodTickRound(
|
||||
period: GamePeriodTickDto,
|
||||
previousRound?: Pick<RoundSnapshot, 'id' | 'startedAt'> | null,
|
||||
@@ -408,6 +430,9 @@ export async function getGameLobbyInit() {
|
||||
runtimeEnabled: dto.runtime_enabled,
|
||||
serverTime: dto.server_time,
|
||||
snapshot: normalizeGameLobbyInit(dto),
|
||||
streakWinRewardRows: normalizeStreakWinRewardRows(
|
||||
dto.streak_win_reward?.rows,
|
||||
),
|
||||
userSnapshot: dto.user_snapshot,
|
||||
} satisfies GameLobbyInitResult
|
||||
}
|
||||
|
||||
@@ -1,175 +1,191 @@
|
||||
import { Fragment, type ReactNode } from 'react'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const STREAK_REWARD_TABLE_SLOT = '{{STREAK_REWARD_TABLE}}'
|
||||
|
||||
interface RulesMarkdownContentProps {
|
||||
children?: ReactNode
|
||||
className?: string
|
||||
content: string
|
||||
compact?: boolean
|
||||
}
|
||||
|
||||
function RulesMarkdownContent({
|
||||
children,
|
||||
className,
|
||||
compact = false,
|
||||
content,
|
||||
}: RulesMarkdownContentProps) {
|
||||
const contentParts = content.split(STREAK_REWARD_TABLE_SLOT)
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
h1: ({ children }) => (
|
||||
<h1
|
||||
className={cn(
|
||||
'font-bold leading-tight text-[#F4FFFF]',
|
||||
compact
|
||||
? 'mb-design-8 text-design-15'
|
||||
: 'mb-design-14 text-design-24',
|
||||
)}
|
||||
{contentParts.map((contentPart, index) => (
|
||||
<Fragment key={contentPart || STREAK_REWARD_TABLE_SLOT}>
|
||||
{contentPart ? (
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
h1: ({ children }) => (
|
||||
<h1
|
||||
className={cn(
|
||||
'font-bold leading-tight text-[#F4FFFF]',
|
||||
compact
|
||||
? 'mb-design-8 text-design-15'
|
||||
: 'mb-design-14 text-design-24',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</h1>
|
||||
),
|
||||
h2: ({ children }) => (
|
||||
<h2
|
||||
className={cn(
|
||||
'font-bold leading-tight text-[#E7FFFF]',
|
||||
compact
|
||||
? 'mb-design-6 mt-design-12 text-design-14'
|
||||
: 'mb-design-10 mt-design-18 text-design-22',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</h2>
|
||||
),
|
||||
h3: ({ children }) => (
|
||||
<h3
|
||||
className={cn(
|
||||
'font-bold leading-tight text-[#8FE7EF]',
|
||||
compact
|
||||
? 'mb-design-5 mt-design-10 text-design-13'
|
||||
: 'mb-design-8 mt-design-16 text-design-20',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</h3>
|
||||
),
|
||||
h4: ({ children }) => (
|
||||
<h4
|
||||
className={cn(
|
||||
'font-semibold leading-tight text-[#FFF2B8]',
|
||||
compact
|
||||
? 'mb-design-4 mt-design-9 text-design-12'
|
||||
: 'mb-design-7 mt-design-14 text-design-18',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</h4>
|
||||
),
|
||||
p: ({ children }) => (
|
||||
<p
|
||||
className={cn(
|
||||
'text-[#B9E7EA]',
|
||||
compact
|
||||
? 'mb-design-7 leading-[1.66]'
|
||||
: 'mb-design-11 leading-[1.76]',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
),
|
||||
strong: ({ children }) => (
|
||||
<strong className="font-bold text-[#FFF2B8]">
|
||||
{children}
|
||||
</strong>
|
||||
),
|
||||
ul: ({ children }) => (
|
||||
<ul
|
||||
className={cn(
|
||||
'list-disc text-[#B9E7EA]',
|
||||
compact
|
||||
? 'mb-design-8 space-y-design-4 pl-design-15'
|
||||
: 'mb-design-12 space-y-design-6 pl-design-22',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
),
|
||||
ol: ({ children }) => (
|
||||
<ol
|
||||
className={cn(
|
||||
'list-decimal text-[#B9E7EA]',
|
||||
compact
|
||||
? 'mb-design-8 space-y-design-4 pl-design-15'
|
||||
: 'mb-design-12 space-y-design-6 pl-design-22',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</ol>
|
||||
),
|
||||
li: ({ children }) => (
|
||||
<li className={compact ? 'leading-[1.62]' : 'leading-[1.72]'}>
|
||||
{children}
|
||||
</li>
|
||||
),
|
||||
code: ({ children }) => (
|
||||
<code className="rounded-[calc(var(--design-unit)*4)] border border-[rgba(255,226,41,0.18)] bg-[rgba(255,226,41,0.08)] px-design-5 py-[1px] font-mono text-[#FFF2B8]">
|
||||
{children}
|
||||
</code>
|
||||
),
|
||||
pre: ({ children }) => (
|
||||
<pre
|
||||
className={cn(
|
||||
'overflow-x-auto rounded-[calc(var(--design-unit)*8)] border border-[rgba(126,234,244,0.16)] bg-[rgba(2,15,26,0.72)] font-mono text-[#D8FCFF]',
|
||||
compact
|
||||
? 'mb-design-9 px-design-9 py-design-7 text-design-10'
|
||||
: 'mb-design-13 px-design-14 py-design-10 text-design-15',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</pre>
|
||||
),
|
||||
table: ({ children }) => (
|
||||
<div className="mb-design-12 overflow-x-auto rounded-[calc(var(--design-unit)*8)] border border-[rgba(126,234,244,0.16)]">
|
||||
<table className="w-full min-w-max border-collapse bg-[rgba(2,15,26,0.58)]">
|
||||
{children}
|
||||
</table>
|
||||
</div>
|
||||
),
|
||||
thead: ({ children }) => (
|
||||
<thead className="bg-[rgba(126,234,244,0.12)] text-[#E9FFFF]">
|
||||
{children}
|
||||
</thead>
|
||||
),
|
||||
th: ({ children }) => (
|
||||
<th
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.13)] text-center font-semibold',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</th>
|
||||
),
|
||||
td: ({ children }) => (
|
||||
<td
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.1)] text-center text-[#C8F4F7]',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</td>
|
||||
),
|
||||
hr: () => (
|
||||
<hr className="my-design-12 border-0 border-t border-[rgba(126,234,244,0.16)]" />
|
||||
),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</h1>
|
||||
),
|
||||
h2: ({ children }) => (
|
||||
<h2
|
||||
className={cn(
|
||||
'font-bold leading-tight text-[#E7FFFF]',
|
||||
compact
|
||||
? 'mb-design-6 mt-design-12 text-design-14'
|
||||
: 'mb-design-10 mt-design-18 text-design-22',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</h2>
|
||||
),
|
||||
h3: ({ children }) => (
|
||||
<h3
|
||||
className={cn(
|
||||
'font-bold leading-tight text-[#8FE7EF]',
|
||||
compact
|
||||
? 'mb-design-5 mt-design-10 text-design-13'
|
||||
: 'mb-design-8 mt-design-16 text-design-20',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</h3>
|
||||
),
|
||||
h4: ({ children }) => (
|
||||
<h4
|
||||
className={cn(
|
||||
'font-semibold leading-tight text-[#FFF2B8]',
|
||||
compact
|
||||
? 'mb-design-4 mt-design-9 text-design-12'
|
||||
: 'mb-design-7 mt-design-14 text-design-18',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</h4>
|
||||
),
|
||||
p: ({ children }) => (
|
||||
<p
|
||||
className={cn(
|
||||
'text-[#B9E7EA]',
|
||||
compact
|
||||
? 'mb-design-7 leading-[1.66]'
|
||||
: 'mb-design-11 leading-[1.76]',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
),
|
||||
strong: ({ children }) => (
|
||||
<strong className="font-bold text-[#FFF2B8]">{children}</strong>
|
||||
),
|
||||
ul: ({ children }) => (
|
||||
<ul
|
||||
className={cn(
|
||||
'list-disc text-[#B9E7EA]',
|
||||
compact
|
||||
? 'mb-design-8 space-y-design-4 pl-design-15'
|
||||
: 'mb-design-12 space-y-design-6 pl-design-22',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
),
|
||||
ol: ({ children }) => (
|
||||
<ol
|
||||
className={cn(
|
||||
'list-decimal text-[#B9E7EA]',
|
||||
compact
|
||||
? 'mb-design-8 space-y-design-4 pl-design-15'
|
||||
: 'mb-design-12 space-y-design-6 pl-design-22',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</ol>
|
||||
),
|
||||
li: ({ children }) => (
|
||||
<li className={compact ? 'leading-[1.62]' : 'leading-[1.72]'}>
|
||||
{children}
|
||||
</li>
|
||||
),
|
||||
code: ({ children }) => (
|
||||
<code className="rounded-[calc(var(--design-unit)*4)] border border-[rgba(255,226,41,0.18)] bg-[rgba(255,226,41,0.08)] px-design-5 py-[1px] font-mono text-[#FFF2B8]">
|
||||
{children}
|
||||
</code>
|
||||
),
|
||||
pre: ({ children }) => (
|
||||
<pre
|
||||
className={cn(
|
||||
'overflow-x-auto rounded-[calc(var(--design-unit)*8)] border border-[rgba(126,234,244,0.16)] bg-[rgba(2,15,26,0.72)] font-mono text-[#D8FCFF]',
|
||||
compact
|
||||
? 'mb-design-9 px-design-9 py-design-7 text-design-10'
|
||||
: 'mb-design-13 px-design-14 py-design-10 text-design-15',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</pre>
|
||||
),
|
||||
table: ({ children }) => (
|
||||
<div className="mb-design-12 overflow-x-auto rounded-[calc(var(--design-unit)*8)] border border-[rgba(126,234,244,0.16)]">
|
||||
<table className="w-full min-w-max border-collapse bg-[rgba(2,15,26,0.58)]">
|
||||
{children}
|
||||
</table>
|
||||
</div>
|
||||
),
|
||||
thead: ({ children }) => (
|
||||
<thead className="bg-[rgba(126,234,244,0.12)] text-[#E9FFFF]">
|
||||
{children}
|
||||
</thead>
|
||||
),
|
||||
th: ({ children }) => (
|
||||
<th
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.13)] text-center font-semibold',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</th>
|
||||
),
|
||||
td: ({ children }) => (
|
||||
<td
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.1)] text-center text-[#C8F4F7]',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</td>
|
||||
),
|
||||
hr: () => (
|
||||
<hr className="my-design-12 border-0 border-t border-[rgba(126,234,244,0.16)]" />
|
||||
),
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</ReactMarkdown>
|
||||
{contentPart}
|
||||
</ReactMarkdown>
|
||||
) : null}
|
||||
{index < contentParts.length - 1 ? children : null}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
197
src/components/streak-reward-table.tsx
Normal file
197
src/components/streak-reward-table.tsx
Normal file
@@ -0,0 +1,197 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useGameSessionStore } from '@/store'
|
||||
import type { StreakRewardType } from '@/type'
|
||||
|
||||
interface StreakRewardTableProps {
|
||||
compact?: boolean
|
||||
}
|
||||
|
||||
function formatFixedAmount(value: string, locale: string) {
|
||||
const amount = Number(value)
|
||||
|
||||
if (!Number.isFinite(amount)) {
|
||||
return value
|
||||
}
|
||||
|
||||
return amount.toLocaleString(locale, {
|
||||
maximumFractionDigits: 2,
|
||||
minimumFractionDigits: amount % 1 === 0 ? 0 : 2,
|
||||
})
|
||||
}
|
||||
|
||||
function StreakRewardTable({ compact = false }: StreakRewardTableProps) {
|
||||
const { i18n, t } = useTranslation()
|
||||
const rows = useGameSessionStore((state) => state.streakWinRewardRows)
|
||||
const sortedRows = useMemo(
|
||||
() => [...rows].sort((left, right) => left.streak - right.streak),
|
||||
[rows],
|
||||
)
|
||||
|
||||
const getRewardTypeLabel = (rewardType: StreakRewardType) => {
|
||||
if (rewardType === 'coefficient') {
|
||||
return t('game.modals.rules.streakRewardTable.rewardTypes.coefficient')
|
||||
}
|
||||
|
||||
if (rewardType === 'fixed') {
|
||||
return t('game.modals.rules.streakRewardTable.rewardTypes.fixed')
|
||||
}
|
||||
|
||||
return rewardType
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'overflow-hidden rounded-[calc(var(--design-unit)*8)] border border-[rgba(126,234,244,0.16)] bg-[rgba(2,15,26,0.58)]',
|
||||
compact ? 'mb-design-9' : 'mb-design-13',
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'border-b border-[rgba(126,234,244,0.16)] bg-[rgba(126,234,244,0.08)] font-semibold text-[#FFF2B8]',
|
||||
compact ? 'px-design-8 py-design-6' : 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{t('game.modals.rules.streakRewardTable.title')}
|
||||
</div>
|
||||
{sortedRows.length > 0 ? (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full min-w-max border-collapse">
|
||||
<thead className="bg-[rgba(126,234,244,0.12)] text-[#E9FFFF]">
|
||||
<tr>
|
||||
<th
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.13)] text-center font-semibold',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{t('game.modals.rules.streakRewardTable.columns.streak')}
|
||||
</th>
|
||||
<th
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.13)] text-center font-semibold',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{t('game.modals.rules.streakRewardTable.columns.rewardType')}
|
||||
</th>
|
||||
<th
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.13)] text-center font-semibold',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{t('game.modals.rules.streakRewardTable.columns.oddsFactor')}
|
||||
</th>
|
||||
<th
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.13)] text-center font-semibold',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{t('game.modals.rules.streakRewardTable.columns.fixedAmount')}
|
||||
</th>
|
||||
<th
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.13)] text-center font-semibold',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{t('game.modals.rules.streakRewardTable.columns.isJackpot')}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{sortedRows.map((row) => (
|
||||
<tr key={`${row.streak}-${row.rewardType}`}>
|
||||
<td
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.1)] text-center text-[#C8F4F7]',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{t('game.modals.rules.streakRewardTable.streakValue', {
|
||||
streak: row.streak,
|
||||
})}
|
||||
</td>
|
||||
<td
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.1)] text-center text-[#C8F4F7]',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{getRewardTypeLabel(row.rewardType)}
|
||||
</td>
|
||||
<td
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.1)] text-center text-[#C8F4F7]',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{row.rewardType === 'coefficient' && row.oddsFactor > 0
|
||||
? `1:${row.oddsFactor}`
|
||||
: '-'}
|
||||
</td>
|
||||
<td
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.1)] text-center text-[#C8F4F7]',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{row.rewardType === 'fixed'
|
||||
? `💎${formatFixedAmount(row.fixedAmount, i18n.language)}`
|
||||
: '-'}
|
||||
</td>
|
||||
<td
|
||||
className={cn(
|
||||
'border border-[rgba(126,234,244,0.1)] text-center font-semibold',
|
||||
row.isJackpot ? 'text-[#FFF2B8]' : 'text-[#C8F4F7]',
|
||||
compact
|
||||
? 'px-design-7 py-design-6'
|
||||
: 'px-design-12 py-design-9',
|
||||
)}
|
||||
>
|
||||
{row.isJackpot
|
||||
? t('game.modals.rules.streakRewardTable.yes')
|
||||
: t('game.modals.rules.streakRewardTable.no')}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={cn(
|
||||
'text-center text-[#B9E7EA]',
|
||||
compact ? 'px-design-8 py-design-10' : 'px-design-12 py-design-14',
|
||||
)}
|
||||
>
|
||||
{t('game.modals.rules.streakRewardTable.empty')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StreakRewardTable
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Minus, Plus } from 'lucide-react'
|
||||
import { Landmark, Minus, Plus } from 'lucide-react'
|
||||
import { type ReactNode, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import lengthBlueBtn from '@/assets/system/length-blue-btn.webp'
|
||||
@@ -16,7 +16,7 @@ import { useWithdrawSubmit } from '@/hooks/use-withdraw-submit'
|
||||
import { useWithdrawVm } from '@/hooks/use-withdraw-vm'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useModalStore } from '@/store'
|
||||
import type { FinanceCurrencyConfig } from '@/type'
|
||||
import type { FinanceCurrencyConfig, FinanceWithdrawBank } from '@/type'
|
||||
|
||||
const PANEL_CLASS =
|
||||
'rounded-md border border-[rgba(110,229,243,0.24)] bg-[linear-gradient(180deg,rgba(7,30,43,0.9),rgba(3,15,26,0.94))] shadow-[inset_0_0_calc(var(--design-unit)*14)_rgba(88,225,238,0.08),0_0_calc(var(--design-unit)*10)_rgba(32,163,186,0.12)]'
|
||||
@@ -33,6 +33,22 @@ function getPaymentGlyph(code: string, name: string) {
|
||||
return name.trim().slice(0, 1).toUpperCase() || code.slice(0, 1).toUpperCase()
|
||||
}
|
||||
|
||||
function BankOptionLogo({ bank }: { bank: FinanceWithdrawBank }) {
|
||||
if (bank.logo.trim()) {
|
||||
return (
|
||||
<img
|
||||
src={bank.logo}
|
||||
alt={bank.label}
|
||||
className="h-design-22 w-design-22 shrink-0 rounded-[calc(var(--design-unit)*4)] object-contain"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Landmark className="h-design-18 w-design-18 shrink-0 text-[#8DE4EA]" />
|
||||
)
|
||||
}
|
||||
|
||||
function WithdrawField({
|
||||
label,
|
||||
children,
|
||||
@@ -557,7 +573,10 @@ function DesktopWithdraw() {
|
||||
<SelectContent>
|
||||
{vm.sortedBanks.map((bank) => (
|
||||
<SelectItem key={bank.code} value={bank.code}>
|
||||
{bank.label}
|
||||
<span className="flex min-w-0 items-center gap-design-6">
|
||||
<BankOptionLogo bank={bank} />
|
||||
<span className="min-w-0 truncate">{bank.label}</span>
|
||||
</span>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Minus, Plus } from 'lucide-react'
|
||||
import { Landmark, Minus, Plus } from 'lucide-react'
|
||||
import { type ReactNode, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import lengthBlueBtn from '@/assets/system/length-blue-btn.webp'
|
||||
@@ -16,7 +16,7 @@ import { useWithdrawSubmit } from '@/hooks/use-withdraw-submit'
|
||||
import { useWithdrawVm } from '@/hooks/use-withdraw-vm'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useModalStore } from '@/store'
|
||||
import type { FinanceCurrencyConfig } from '@/type'
|
||||
import type { FinanceCurrencyConfig, FinanceWithdrawBank } from '@/type'
|
||||
|
||||
const PANEL_CLASS =
|
||||
'rounded-md border border-[rgba(110,229,243,0.24)] bg-[linear-gradient(180deg,rgba(7,30,43,0.9),rgba(3,15,26,0.94))] shadow-[inset_0_0_calc(var(--design-unit)*10)_rgba(88,225,238,0.08)]'
|
||||
@@ -33,6 +33,22 @@ function getPaymentGlyph(code: string, name: string) {
|
||||
return name.trim().slice(0, 1).toUpperCase() || code.slice(0, 1).toUpperCase()
|
||||
}
|
||||
|
||||
function BankOptionLogo({ bank }: { bank: FinanceWithdrawBank }) {
|
||||
if (bank.logo.trim()) {
|
||||
return (
|
||||
<img
|
||||
src={bank.logo}
|
||||
alt={bank.label}
|
||||
className="h-design-18 w-design-18 shrink-0 rounded-[calc(var(--design-unit)*3)] object-contain"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Landmark className="h-design-15 w-design-15 shrink-0 text-[#8DE4EA]" />
|
||||
)
|
||||
}
|
||||
|
||||
function WithdrawField({
|
||||
label,
|
||||
children,
|
||||
@@ -537,7 +553,10 @@ function MobileWithdraw() {
|
||||
<SelectContent>
|
||||
{vm.sortedBanks.map((bank) => (
|
||||
<SelectItem key={bank.code} value={bank.code}>
|
||||
{bank.label}
|
||||
<span className="flex min-w-0 items-center gap-design-4">
|
||||
<BankOptionLogo bank={bank} />
|
||||
<span className="min-w-0 truncate">{bank.label}</span>
|
||||
</span>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -70,10 +70,10 @@ export function useTopupVm() {
|
||||
)
|
||||
const methods = useMemo(
|
||||
() =>
|
||||
config.deposit.methods.filter(
|
||||
(selectedPayChannel?.methods ?? []).filter(
|
||||
(method) => method.currencyCode === selectedCurrencyCode,
|
||||
),
|
||||
[config.deposit.methods, selectedCurrencyCode],
|
||||
[selectedCurrencyCode, selectedPayChannel?.methods],
|
||||
)
|
||||
const [selectedPaymentMethodCode, setSelectedPaymentMethodCode] = useState(
|
||||
() => methods[0]?.code ?? '',
|
||||
|
||||
@@ -180,7 +180,7 @@ export function useWithdrawVm() {
|
||||
convertedFiatAmount > selectedPaymentMaximumAmount
|
||||
const sortedBanks = useMemo(
|
||||
() =>
|
||||
[...config.withdraw.banks]
|
||||
[...(selectedPaymentChannel?.banks ?? [])]
|
||||
.filter(
|
||||
(bank) =>
|
||||
bank.status === 1 &&
|
||||
@@ -188,7 +188,7 @@ export function useWithdrawVm() {
|
||||
(!bank.currencyCode || bank.currencyCode === selectedCurrencyCode),
|
||||
)
|
||||
.sort((left, right) => left.sort - right.sort),
|
||||
[config.withdraw.banks, selectedCurrencyCode],
|
||||
[selectedPaymentChannel, selectedCurrencyCode],
|
||||
)
|
||||
const setAmount = useCallback(
|
||||
(nextAmount: number) => {
|
||||
|
||||
@@ -215,134 +215,153 @@ export default {
|
||||
rules: {
|
||||
title: 'Game Rules',
|
||||
content: [
|
||||
'## 36 Zihua · Gameplay Guide',
|
||||
'## 36 Zihua Rules Guide',
|
||||
'',
|
||||
'### 1. Game Introduction',
|
||||
'',
|
||||
'**36 Zihua** is a fast-paced number guessing game with **one round every 30 seconds**. Each round, the system draws **one winning number** from **36 symbols** (Rat, Ox, Tiger… Azure Dragon, White Tiger, Vermilion Bird, Black Tortoise, and more). During the betting window, players pick numbers and place bets. Guess correctly to win prizes. Win consecutive rounds to increase your rewards — **10 wins in a row** can earn you the **Million Jackpot**.',
|
||||
'**36 Zihua** is a number prediction game. In each round, **1 winning number** is drawn from **36 symbols**. Players select numbers and place bets during the betting stage. If they guess correctly, they win a reward. Consecutive wins can increase rewards, and after reaching the jackpot tier, players also have a chance to win the **Million Jackpot**.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 2. How to Play',
|
||||
'### 2. Gameplay',
|
||||
'',
|
||||
'Each round lasts about **30 seconds**:',
|
||||
'Each round is divided into the following stages:',
|
||||
'',
|
||||
'**Step 1 — Betting window (0–20 seconds)**',
|
||||
'Pick numbers on the 36-grid (up to **5 numbers** by default), choose a chip amount (e.g. 💎1, 5, 10, 25, 50, 100), then confirm your bet. Your balance is deducted and the bet is placed.',
|
||||
'1. **Betting Stage**',
|
||||
' Players choose the numbers they want to bet on from 36 numbers, select chips, confirm the bet, and the system deducts the balance and creates the bet order.',
|
||||
' The maximum number of selections per round depends on the current system configuration.',
|
||||
'',
|
||||
'**Step 2 — Lock (at 20 seconds)**',
|
||||
'No more bets are accepted. Any bet placed after lock is invalid.',
|
||||
'2. **Bet Closing Stage**',
|
||||
' Once the round enters the closing stage, the system stops accepting new bets.',
|
||||
'',
|
||||
'**Step 3 — Draw & settlement (20–30 seconds)**',
|
||||
'The winning number is announced and prizes are paid according to the reward rules.',
|
||||
'3. **Draw and Settlement Stage**',
|
||||
' The system announces the winning number for the round and automatically settles rewards according to the current rules.',
|
||||
'',
|
||||
'**Step 4 — Next round**',
|
||||
'After settlement, the next round begins automatically.',
|
||||
'4. **Next Round Begins**',
|
||||
' After the current round is settled, the system automatically starts the next round.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 3. Winning Rules',
|
||||
'',
|
||||
'- Only **one** winning number is drawn each round (from 1 to 36).',
|
||||
'- You win if **your selected numbers include the winning number**.',
|
||||
'- If you don’t match, you receive no prize for that round.',
|
||||
'1. Only **1 winning number** is drawn in each round.',
|
||||
'2. If the player’s selected numbers **include the winning number**, the bet is considered a win.',
|
||||
'3. If a player selects multiple numbers and the bet amount is the same for each number, then:',
|
||||
'',
|
||||
'**Hit stake (amount on the winning number):**',
|
||||
'- When every selected number has the same stake:',
|
||||
' **Hit stake = total bet amount ÷ number of selected numbers**',
|
||||
'- Example: 5 numbers, total bet 💎50 → 💎10 per number. If the winning number is among your picks, 💎10 is used for prize calculation.',
|
||||
'```text',
|
||||
'Winning Number Stake = Total Bet Amount ÷ Number of Selected Numbers',
|
||||
'```',
|
||||
'',
|
||||
'**Example:**',
|
||||
'If a player selects **5 numbers** with a total bet of **💎50**, then each number carries a stake of **💎10**.',
|
||||
'If the winning number is among those 5 numbers, the reward is calculated based on **💎10**.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 4. Reward Types',
|
||||
'### 4. Reward Rules',
|
||||
'',
|
||||
'Streak rewards come in **two types**. Each tier uses **one type only** — they are **not combined**:',
|
||||
'Streak rewards are divided into **two types**, and only one type applies to each streak tier:',
|
||||
'',
|
||||
'#### Type A — Coefficient Reward',
|
||||
'#### 1. Coefficient Reward',
|
||||
'',
|
||||
'Prize is calculated using an odds multiplier:',
|
||||
'The reward is calculated by multiplying the winning number stake by the odds coefficient of the current tier:',
|
||||
'',
|
||||
'```',
|
||||
'Prize = hit stake × odds factor',
|
||||
'```text',
|
||||
'Winning Amount = Winning Number Stake × Odds Coefficient',
|
||||
'```',
|
||||
'',
|
||||
'#### Type B — Fixed Reward',
|
||||
'#### 2. Fixed Reward',
|
||||
'',
|
||||
'You receive a **fixed amount** set in the configuration.',
|
||||
'**It does not depend on your bet size and does not use an odds multiplier.**',
|
||||
'The system directly pays the configured fixed amount, regardless of the bet amount of the current round:',
|
||||
'',
|
||||
'```',
|
||||
'Prize = fixed amount',
|
||||
'```text',
|
||||
'Winning Amount = Fixed Reward Amount',
|
||||
'```',
|
||||
'',
|
||||
'**Comparison (Tier 10 example):**',
|
||||
'#### 3. Reward Table Notes',
|
||||
'',
|
||||
'| Reward Type | Hit Stake | Prize |',
|
||||
'|:---:|:---:|:---:|',
|
||||
'| Coefficient (1:330) | 💎50 | 💎50 × 330 = **16,500** |',
|
||||
'| Fixed reward | Any | **1,000,000** (configured value) |',
|
||||
'The current streak reward table is based on the system’s backend configuration, and the frontend should display it using the live configuration data.',
|
||||
'Each tier contains the following information:',
|
||||
'',
|
||||
'- Streak tier',
|
||||
'- Reward type',
|
||||
'- Odds coefficient',
|
||||
'- Fixed reward amount',
|
||||
'- Whether it is a jackpot tier',
|
||||
'',
|
||||
'In other words, the reward table is not hardcoded. The actual content always follows the current system configuration.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 5. Win Streak Rules',
|
||||
'### 5. Streak Rules',
|
||||
'',
|
||||
'When you **win consecutive rounds**, rewards increase by streak tier. By default, **coefficient rewards** apply with escalating odds:',
|
||||
'When a player wins consecutive rounds, they enter a streak state. The higher the streak, the higher the reward tier.',
|
||||
'',
|
||||
'| Streak | Odds | Factor |',
|
||||
'|:---:|:---:|:---:|',
|
||||
'| 1st win | 1:33 | 33 |',
|
||||
'| 2 in a row | 1:66 | 66 |',
|
||||
'| 3 in a row | 1:99 | 99 |',
|
||||
'| 4 in a row | 1:132 | 132 |',
|
||||
'| 5 in a row | 1:165 | 165 |',
|
||||
'| 6 in a row | 1:198 | 198 |',
|
||||
'| 7 in a row | 1:231 | 231 |',
|
||||
'| 8 in a row | 1:264 | 264 |',
|
||||
'| 9 in a row | 1:297 | 297 |',
|
||||
'| 10 in a row | 1:330 | 330 |',
|
||||
'#### 1. Streak Calculation Rules',
|
||||
'',
|
||||
'**Streak rules:**',
|
||||
'1. After a player wins, the streak count increases.',
|
||||
'2. Rewards are calculated based on the **streak tier at the time the bet is placed**.',
|
||||
'3. If the player loses any round, the streak is immediately reset to **0**.',
|
||||
'4. Under the current implementation, a normal win continues the streak, but if the player hits a **jackpot tier**, the streak is reset to **0** after that round is settled.',
|
||||
'',
|
||||
'- Rewards are based on your **streak at the time you place the bet**: if you already have N consecutive wins, a win this round pays at tier **(N+1)**.',
|
||||
'- **Any losing round** resets your streak to zero — you start again from tier 1.',
|
||||
'- **Skipping a round** (no bet placed) during an active streak also **resets your streak to zero**.',
|
||||
'#### 2. Jackpot Streak Bet Limit',
|
||||
'',
|
||||
'**Examples (coefficient reward):**',
|
||||
'When a player’s streak reaches the first **jackpot tier** configured by the system, the player enters the jackpot streak bet restriction stage.',
|
||||
'',
|
||||
'| Scenario | Hit Stake | Streak Tier | Odds | Prize |',
|
||||
'|:---:|:---:|:---:|:---:|:---:|',
|
||||
'| First win | 💎10 | 1st | 1:33 | **330** |',
|
||||
'| 3-win streak | 💎50 | 3rd | 1:99 | **4,950** |',
|
||||
'| 10-win streak | 💎50 | 10th | 1:330 | **16,500** |',
|
||||
'The rules are as follows:',
|
||||
'',
|
||||
'1. In every following round, the **total bet amount** must **not exceed** the total bet amount of the **first jackpot-winning round** in the current streak.',
|
||||
'2. This cap remains locked throughout the current streak and does not change even if the player wins jackpot again later.',
|
||||
'3. Once the streak is broken, the restriction is removed immediately.',
|
||||
'4. Normal streaks before reaching the jackpot tier are not affected by this rule.',
|
||||
'',
|
||||
'{{STREAK_REWARD_TABLE}}',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 6. Million Jackpot',
|
||||
'',
|
||||
'When a player **bets and wins 10 consecutive rounds**, and each bet during the streak is **at least 💎50**, the Million Jackpot is triggered.',
|
||||
'When a player reaches the system-configured jackpot tier through consecutive wins, and that jackpot tier is configured as a fixed jackpot reward, the player can receive the Million Jackpot.',
|
||||
'',
|
||||
'**Requirements:**',
|
||||
'#### 1. Trigger Conditions',
|
||||
'',
|
||||
'1. **10 consecutive rounds** with a bet placed and won in each;',
|
||||
'2. **Every round** in the streak must have a stake of **at least 💎50**;',
|
||||
'3. If any round in the streak is below 💎50, you only receive the regular streak reward — **the Million Jackpot does not apply**.',
|
||||
'1. The player must keep winning until reaching the current system-configured jackpot tier.',
|
||||
'2. If the jackpot tier is configured as a **fixed reward**, for example **💎1,000,000**, the player will directly receive the Million Jackpot when hitting that tier.',
|
||||
'3. Under the current implementation, there is **no extra minimum bet requirement**. As long as the player meets the platform’s minimum allowed bet amount, they can participate in the jackpot streak.',
|
||||
'4. After hitting the jackpot tier, once the settlement is completed, the streak will be reset to **0**.',
|
||||
'',
|
||||
'**How it is paid (depends on backend configuration):**',
|
||||
'#### 2. Payout Rules',
|
||||
'',
|
||||
'- **Fixed reward**: If tier 10 is set as a fixed amount, 10 consecutive wins pay **💎1,000,000** directly.',
|
||||
'- **Coefficient reward**: If tier 10 uses coefficient odds, you first receive the regular prize at **1:330**, plus any additional jackpot per campaign rules.',
|
||||
'- If the jackpot tier is configured as a **fixed reward**: the configured fixed jackpot amount is paid directly.',
|
||||
'- If the jackpot tier is configured as a **coefficient reward**: settlement still follows “Winning Number Stake × Odds Coefficient”, and a fixed million reward is not automatically paid.',
|
||||
'',
|
||||
'**Example — fixed reward at tier 10 (💎1,000,000), hit stake 💎50 each round:**',
|
||||
'**Example:**',
|
||||
'',
|
||||
'- 10 wins in a row → **💎1,000,000**',
|
||||
'- Streak resets to **zero** after the jackpot is awarded',
|
||||
'- If the jackpot tier is configured as a fixed reward of **💎1,000,000**',
|
||||
'- The player reaches that jackpot tier and wins',
|
||||
'- The player directly receives **💎1,000,000**',
|
||||
'',
|
||||
'**Example — coefficient reward at tier 10 (1:330), hit stake 💎50:**',
|
||||
'',
|
||||
'- Tier 10 regular prize: 💎50 × 330 = **💎16,500**',
|
||||
'- If a separate Jackpot campaign applies, an additional million-prize may be added on top',
|
||||
'---',
|
||||
].join('\n'),
|
||||
confirm: 'Understood',
|
||||
streakRewardTable: {
|
||||
title: 'Streak Reward Table',
|
||||
columns: {
|
||||
streak: 'Streak',
|
||||
rewardType: 'Reward Type',
|
||||
oddsFactor: 'Odds',
|
||||
fixedAmount: 'Fixed Reward',
|
||||
isJackpot: 'Jackpot',
|
||||
},
|
||||
rewardTypes: {
|
||||
coefficient: 'Coefficient Reward',
|
||||
fixed: 'Fixed Reward',
|
||||
},
|
||||
streakValue: 'Round {{streak}}',
|
||||
yes: TEXT_YES,
|
||||
no: TEXT_NO,
|
||||
empty: 'No reward configuration available',
|
||||
},
|
||||
},
|
||||
procedures: {
|
||||
title: 'Top Up / Withdraw',
|
||||
|
||||
@@ -214,134 +214,153 @@ export default {
|
||||
rules: {
|
||||
title: 'Aturan Permainan',
|
||||
content: [
|
||||
'## 36 Zihua · Panduan Permainan',
|
||||
'## Panduan Peraturan 36 Zihua',
|
||||
'',
|
||||
'### 1. Pengenalan Permainan',
|
||||
'### 1. Pengenalan Game',
|
||||
'',
|
||||
'**36 Zihua** adalah permainan tebak angka berkecepatan tinggi dengan **satu putaran setiap 30 detik**. Setiap putaran, sistem mengeluarkan **satu nomor pemenang** dari **36 simbol** (Tikus, Kerbau, Harimau… Naga Biru, Harimau Putih, Burung Merah, Kura-kura Hitam, dan lainnya). Selama periode taruhan, pemain memilih nomor dan memasang taruhan. Tebak dengan benar untuk memenangkan hadiah. Menang berturut-turut dapat meningkatkan hadiah Anda — **10 kemenangan berturut-turut** dapat memberikan **Jackpot Satu Juta**.',
|
||||
'**36 Zihua** adalah permainan prediksi angka. Dalam setiap putaran, **1 nomor pemenang** akan dipilih dari **36 simbol**. Pemain memilih nomor dan memasang taruhan pada tahap taruhan. Jika tebakan benar, pemain akan mendapatkan hadiah. Kemenangan beruntun dapat meningkatkan hadiah, dan setelah mencapai tier jackpot, pemain juga berkesempatan memenangkan **Jackpot Satu Juta**.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 2. Cara Bermain',
|
||||
'',
|
||||
'Setiap putaran berlangsung sekitar **30 detik**:',
|
||||
'Setiap putaran dibagi menjadi beberapa tahap berikut:',
|
||||
'',
|
||||
'**Langkah 1 — Periode taruhan (0–20 detik)**',
|
||||
'Pilih nomor pada grid 36 kotak (default maksimum **5 nomor**), pilih nilai chip (mis. 💎1, 5, 10, 25, 50, 100), lalu konfirmasi taruhan. Saldo Anda akan dipotong dan taruhan dikonfirmasi.',
|
||||
'1. **Tahap Taruhan**',
|
||||
' Pemain memilih nomor yang ingin dipertaruhkan dari 36 nomor, memilih chip, mengonfirmasi taruhan, dan sistem akan memotong saldo serta membuat catatan taruhan.',
|
||||
' Jumlah maksimum nomor yang dapat dipilih per putaran bergantung pada konfigurasi sistem saat ini.',
|
||||
'',
|
||||
'**Langkah 2 — Penutupan (pada detik ke-20)**',
|
||||
'Tidak ada taruhan baru yang diterima. Taruhan yang dipasang setelah penutupan tidak berlaku.',
|
||||
'2. **Tahap Penutupan Taruhan**',
|
||||
' Setelah putaran memasuki tahap penutupan, sistem berhenti menerima taruhan baru.',
|
||||
'',
|
||||
'**Langkah 3 — Pengundian & penyelesaian (20–30 detik)**',
|
||||
'Nomor pemenang diumumkan dan hadiah dibayarkan sesuai aturan hadiah.',
|
||||
'3. **Tahap Pengundian dan Penyelesaian**',
|
||||
' Sistem akan mengumumkan nomor pemenang untuk putaran tersebut dan secara otomatis menyelesaikan hadiah sesuai aturan yang berlaku.',
|
||||
'',
|
||||
'**Langkah 4 — Putaran berikutnya**',
|
||||
'Setelah penyelesaian, putaran berikutnya dimulai secara otomatis.',
|
||||
'4. **Putaran Berikutnya Dimulai**',
|
||||
' Setelah putaran saat ini selesai diselesaikan, sistem akan otomatis memulai putaran berikutnya.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 3. Aturan Kemenangan',
|
||||
'',
|
||||
'- Hanya **satu** nomor pemenang yang dikeluarkan setiap putaran (dari 1 hingga 36).',
|
||||
'- Anda menang jika **nomor yang dipilih mencakup nomor pemenang**.',
|
||||
'- Jika tidak kena, tidak ada hadiah untuk putaran tersebut.',
|
||||
'1. Hanya **1 nomor pemenang** yang akan dikeluarkan di setiap putaran.',
|
||||
'2. Jika nomor yang dipilih pemain **mencakup nomor pemenang**, maka taruhan tersebut dianggap menang.',
|
||||
'3. Jika pemain memilih beberapa nomor dan jumlah taruhan untuk setiap nomor sama, maka:',
|
||||
'',
|
||||
'**Jumlah taruhan pada nomor kena:**',
|
||||
'- Jika setiap nomor dipilih dengan jumlah taruhan yang sama:',
|
||||
' **Jumlah taruhan pada nomor kena = total taruhan ÷ jumlah nomor yang dipilih**',
|
||||
'- Contoh: 5 nomor, total taruhan 💎50 → 💎10 per nomor. Jika nomor pemenang termasuk dalam pilihan Anda, 💎10 digunakan untuk perhitungan hadiah.',
|
||||
'```text',
|
||||
'Nilai Taruhan Nomor Menang = Total Taruhan ÷ Jumlah Nomor yang Dipilih',
|
||||
'```',
|
||||
'',
|
||||
'**Contoh:**',
|
||||
'Jika pemain memilih **5 nomor** dengan total taruhan **💎50**, maka setiap nomor memiliki nilai taruhan **💎10**.',
|
||||
'Jika nomor pemenang berada di antara 5 nomor tersebut, hadiah akan dihitung berdasarkan **💎10**.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 4. Jenis Hadiah',
|
||||
'### 4. Aturan Hadiah',
|
||||
'',
|
||||
'Hadiah kemenangan berturut-turut terdiri dari **dua jenis**. Setiap tingkat hanya menggunakan **satu jenis** — **tidak digabungkan**:',
|
||||
'Hadiah kemenangan beruntun dibagi menjadi **dua jenis**, dan hanya satu jenis yang berlaku pada setiap tier kemenangan beruntun:',
|
||||
'',
|
||||
'#### Jenis A — Hadiah Koefisien',
|
||||
'#### 1. Hadiah Koefisien',
|
||||
'',
|
||||
'Hadiah dihitung menggunakan pengali odds:',
|
||||
'Hadiah dihitung dengan mengalikan nilai taruhan nomor menang dengan koefisien odds pada tier saat ini:',
|
||||
'',
|
||||
'```',
|
||||
'Hadiah = jumlah taruhan pada nomor kena × koefisien odds',
|
||||
'```text',
|
||||
'Jumlah Kemenangan = Nilai Taruhan Nomor Menang × Koefisien Odds',
|
||||
'```',
|
||||
'',
|
||||
'#### Jenis B — Hadiah Tetap',
|
||||
'#### 2. Hadiah Tetap',
|
||||
'',
|
||||
'Anda menerima **jumlah tetap** yang ditetapkan dalam konfigurasi.',
|
||||
'**Tidak bergantung pada jumlah taruhan dan tidak menggunakan koefisien odds.**',
|
||||
'Sistem akan langsung membayar jumlah tetap yang telah dikonfigurasi, tanpa bergantung pada jumlah taruhan pada putaran tersebut:',
|
||||
'',
|
||||
'```',
|
||||
'Hadiah = jumlah tetap',
|
||||
'```text',
|
||||
'Jumlah Kemenangan = Jumlah Hadiah Tetap',
|
||||
'```',
|
||||
'',
|
||||
'**Perbandingan (contoh Tingkat 10):**',
|
||||
'#### 3. Catatan Tabel Hadiah',
|
||||
'',
|
||||
'| Jenis Hadiah | Jumlah Taruhan pada Nomor Kena | Hadiah |',
|
||||
'|:---:|:---:|:---:|',
|
||||
'| Koefisien (1:330) | 💎50 | 💎50 × 330 = **16.500** |',
|
||||
'| Hadiah tetap | Berapa pun | **1.000.000** (nilai konfigurasi) |',
|
||||
'Tabel hadiah kemenangan beruntun saat ini mengikuti konfigurasi backend sistem, dan frontend harus menampilkannya berdasarkan data konfigurasi terbaru.',
|
||||
'Setiap tier berisi informasi berikut:',
|
||||
'',
|
||||
'- Tier kemenangan beruntun',
|
||||
'- Jenis hadiah',
|
||||
'- Koefisien odds',
|
||||
'- Jumlah hadiah tetap',
|
||||
'- Apakah termasuk tier jackpot',
|
||||
'',
|
||||
'Dengan kata lain, tabel hadiah tidak ditulis tetap. Isi sebenarnya selalu mengikuti konfigurasi sistem saat ini.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 5. Aturan Kemenangan Berturut-turut',
|
||||
'',
|
||||
'Saat Anda **menang berturut-turut**, hadiah meningkat sesuai tingkat kemenangan. Secara default, **hadiah koefisien** digunakan dengan odds yang meningkat:',
|
||||
'Saat pemain menang dalam beberapa putaran berturut-turut, pemain akan masuk ke status kemenangan beruntun. Semakin tinggi kemenangan beruntun, semakin tinggi tier hadiah.',
|
||||
'',
|
||||
'| Kemenangan Berturut-turut | Odds | Koefisien |',
|
||||
'|:---:|:---:|:---:|',
|
||||
'| Kemenangan ke-1 | 1:33 | 33 |',
|
||||
'| 2 berturut-turut | 1:66 | 66 |',
|
||||
'| 3 berturut-turut | 1:99 | 99 |',
|
||||
'| 4 berturut-turut | 1:132 | 132 |',
|
||||
'| 5 berturut-turut | 1:165 | 165 |',
|
||||
'| 6 berturut-turut | 1:198 | 198 |',
|
||||
'| 7 berturut-turut | 1:231 | 231 |',
|
||||
'| 8 berturut-turut | 1:264 | 264 |',
|
||||
'| 9 berturut-turut | 1:297 | 297 |',
|
||||
'| 10 berturut-turut | 1:330 | 330 |',
|
||||
'#### 1. Aturan Perhitungan Kemenangan Beruntun',
|
||||
'',
|
||||
'**Aturan kemenangan berturut-turut:**',
|
||||
'1. Setelah pemain menang, jumlah kemenangan beruntun akan bertambah.',
|
||||
'2. Hadiah dihitung berdasarkan **tier kemenangan beruntun saat taruhan dipasang**.',
|
||||
'3. Jika pemain kalah di putaran mana pun, kemenangan beruntun akan langsung direset ke **0**.',
|
||||
'4. Dalam implementasi saat ini, kemenangan biasa akan melanjutkan kemenangan beruntun, tetapi jika pemain mengenai **tier jackpot**, maka kemenangan beruntun akan langsung direset ke **0** setelah putaran tersebut selesai diselesaikan.',
|
||||
'',
|
||||
'- Hadiah dihitung berdasarkan **status kemenangan berturut-turut saat Anda memasang taruhan**: jika Anda sudah memiliki N kemenangan berturut-turut, kemenangan putaran ini dibayar pada tingkat **(N+1)**.',
|
||||
'- **Putaran tanpa kemenangan** akan mengatur ulang kemenangan berturut-turut ke nol — Anda mulai lagi dari tingkat 1.',
|
||||
'- **Melewatkan putaran** (tidak memasang taruhan) selama kemenangan berturut-turut aktif juga akan **mengatur ulang kemenangan berturut-turut ke nol**.',
|
||||
'#### 2. Batas Taruhan Saat Kemenangan Beruntun Jackpot',
|
||||
'',
|
||||
'**Contoh (hadiah koefisien):**',
|
||||
'Ketika kemenangan beruntun pemain mencapai tier **jackpot pertama** yang dikonfigurasi oleh sistem, pemain akan masuk ke tahap pembatasan taruhan jackpot.',
|
||||
'',
|
||||
'| Skenario | Jumlah Taruhan pada Nomor Kena | Tingkat | Odds | Hadiah |',
|
||||
'|:---:|:---:|:---:|:---:|:---:|',
|
||||
'| Kemenangan pertama | 💎10 | Ke-1 | 1:33 | **330** |',
|
||||
'| 3 kemenangan berturut-turut | 💎50 | Ke-3 | 1:99 | **4.950** |',
|
||||
'| 10 kemenangan berturut-turut | 💎50 | Ke-10 | 1:330 | **16.500** |',
|
||||
'Aturannya sebagai berikut:',
|
||||
'',
|
||||
'1. Dalam setiap putaran berikutnya, **total jumlah taruhan** **tidak boleh melebihi** jumlah taruhan dari **putaran pertama yang memenangkan jackpot** dalam kemenangan beruntun saat ini.',
|
||||
'2. Batas ini akan tetap terkunci selama kemenangan beruntun saat ini berlangsung dan tidak akan berubah meskipun pemain kembali memenangkan jackpot setelah itu.',
|
||||
'3. Setelah kemenangan beruntun terputus, pembatasan ini akan langsung dihapus.',
|
||||
'4. Kemenangan beruntun biasa sebelum mencapai tier jackpot tidak terpengaruh oleh aturan ini.',
|
||||
'',
|
||||
'{{STREAK_REWARD_TABLE}}',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 6. Jackpot Satu Juta',
|
||||
'',
|
||||
'Saat pemain **bertaruh dan menang 10 putaran berturut-turut**, dan setiap taruhan selama kemenangan berturut-turut **minimal 💎50**, Jackpot Satu Juta akan dipicu.',
|
||||
'Ketika pemain mencapai tier jackpot yang dikonfigurasi sistem melalui kemenangan beruntun, dan tier jackpot tersebut dikonfigurasi sebagai hadiah tetap, pemain bisa menerima Jackpot Satu Juta.',
|
||||
'',
|
||||
'**Syarat:**',
|
||||
'#### 1. Syarat Pemicu',
|
||||
'',
|
||||
'1. **10 putaran berturut-turut** dengan taruhan dipasang dan dimenangkan di setiap putaran;',
|
||||
'2. **Setiap putaran** dalam kemenangan berturut-turut harus memiliki taruhan **minimal 💎50**;',
|
||||
'3. Jika ada putaran dalam kemenangan berturut-turut di bawah 💎50, Anda hanya menerima hadiah kemenangan berturut-turut biasa — **Jackpot Satu Juta tidak berlaku**.',
|
||||
'1. Pemain harus terus menang sampai mencapai tier jackpot yang saat ini dikonfigurasi oleh sistem.',
|
||||
'2. Jika tier jackpot dikonfigurasi sebagai **hadiah tetap**, misalnya **💎1,000,000**, pemain akan langsung menerima Jackpot Satu Juta saat berhasil mengenai tier tersebut.',
|
||||
'3. Dalam implementasi saat ini, **tidak ada syarat taruhan minimum tambahan**. Selama pemain memenuhi jumlah taruhan minimum yang diizinkan oleh platform, pemain dapat mengikuti kemenangan beruntun jackpot.',
|
||||
'4. Setelah mengenai tier jackpot, begitu penyelesaian selesai, kemenangan beruntun akan direset ke **0**.',
|
||||
'',
|
||||
'**Cara pembayaran (tergantung konfigurasi backend):**',
|
||||
'#### 2. Aturan Pembayaran',
|
||||
'',
|
||||
'- **Hadiah tetap**: Jika tingkat 10 ditetapkan sebagai jumlah tetap, 10 kemenangan berturut-turut membayar **💎1.000.000** secara langsung.',
|
||||
'- **Hadiah koefisien**: Jika tingkat 10 menggunakan odds koefisien, Anda menerima hadiah reguler pada **1:330** terlebih dahulu, ditambah jackpot tambahan sesuai aturan kampanye.',
|
||||
'- Jika tier jackpot dikonfigurasi sebagai **hadiah tetap**, jumlah jackpot tetap yang telah dikonfigurasi akan dibayarkan langsung.',
|
||||
'- Jika tier jackpot dikonfigurasi sebagai **hadiah koefisien**, hadiah akan dihitung sebagai **nilai taruhan nomor menang × koefisien odds**, dan satu juta tetap tidak akan dibayarkan secara otomatis.',
|
||||
'',
|
||||
'**Contoh — hadiah tetap pada tingkat 10 (💎1.000.000), jumlah taruhan pada nomor kena 💎50 setiap putaran:**',
|
||||
'**Contoh:**',
|
||||
'',
|
||||
'- 10 kemenangan berturut-turut → **💎1.000.000**',
|
||||
'- Kemenangan berturut-turut diatur ulang ke **nol** setelah jackpot diberikan',
|
||||
'- Jika tier jackpot dikonfigurasi sebagai hadiah tetap **💎1,000,000**',
|
||||
'- Pemain mencapai tier jackpot tersebut dan menang',
|
||||
'- Maka pemain akan langsung menerima **💎1,000,000**',
|
||||
'',
|
||||
'**Contoh — hadiah koefisien pada tingkat 10 (1:330), jumlah taruhan pada nomor kena 💎50:**',
|
||||
'',
|
||||
'- Hadiah reguler tingkat 10: 💎50 × 330 = **💎16.500**',
|
||||
'- Jika kampanye Jackpot terpisah berlaku, hadiah satu juta tambahan dapat ditambahkan di atasnya',
|
||||
'---',
|
||||
].join('\n'),
|
||||
confirm: 'Saya Mengerti',
|
||||
streakRewardTable: {
|
||||
title: 'Tabel Hadiah Kemenangan Beruntun',
|
||||
columns: {
|
||||
streak: 'Tier',
|
||||
rewardType: 'Jenis Hadiah',
|
||||
oddsFactor: 'Odds',
|
||||
fixedAmount: 'Hadiah Tetap',
|
||||
isJackpot: 'Jackpot',
|
||||
},
|
||||
rewardTypes: {
|
||||
coefficient: 'Hadiah Koefisien',
|
||||
fixed: 'Hadiah Tetap',
|
||||
},
|
||||
streakValue: 'Putaran {{streak}}',
|
||||
yes: TEXT_YES,
|
||||
no: TEXT_NO,
|
||||
empty: 'Belum ada konfigurasi hadiah',
|
||||
},
|
||||
},
|
||||
procedures: {
|
||||
title: 'Isi Ulang / Tarik Dana',
|
||||
|
||||
@@ -217,134 +217,153 @@ export default {
|
||||
rules: {
|
||||
title: 'Peraturan Permainan',
|
||||
content: [
|
||||
'## 36 Zihua · Panduan Permainan',
|
||||
'## Panduan Peraturan 36 Zihua',
|
||||
'',
|
||||
'### 1. Pengenalan Permainan',
|
||||
'',
|
||||
'**36 Zihua** ialah permainan teka nombor berkelajuan tinggi dengan **satu pusingan setiap 30 saat**. Setiap pusingan, sistem akan mengeluarkan **satu nombor kemenangan** daripada **36 simbol** (Tikus, Lembu, Harimau… Naga Biru, Harimau Putih, Burung Merah, Kura-kura Hitam, dan lain-lain). Dalam tempoh pertaruhan, pemain memilih nombor dan membuat pertaruhan. Teka dengan betul untuk memenangi hadiah. Menang berturut-turut boleh meningkatkan ganjaran anda — **10 kemenangan berturut-turut** boleh membawa anda **Jackpot Sejuta**.',
|
||||
'**36 Zihua** ialah permainan ramalan nombor. Dalam setiap pusingan, **1 nombor kemenangan** akan dipilih daripada **36 simbol**. Pemain memilih nombor dan membuat pertaruhan semasa peringkat pertaruhan. Jika tekaan tepat, pemain akan menerima ganjaran. Kemenangan berturut-turut boleh meningkatkan ganjaran, dan selepas mencapai peringkat jackpot, pemain juga berpeluang memenangi **Jackpot Sejuta**.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 2. Cara Bermain',
|
||||
'',
|
||||
'Setiap pusingan mengambil masa kira-kira **30 saat**:',
|
||||
'Setiap pusingan dibahagikan kepada beberapa peringkat berikut:',
|
||||
'',
|
||||
'**Langkah 1 — Tempoh pertaruhan (0–20 saat)**',
|
||||
'Pilih nombor pada grid 36 petak (lalai maksimum **5 nombor**), pilih nilai cip (cth. 💎1, 5, 10, 25, 50, 100), kemudian sahkan pertaruhan. Baki anda akan ditolak dan pertaruhan disahkan.',
|
||||
'1. **Peringkat Pertaruhan**',
|
||||
' Pemain memilih nombor yang ingin dipertaruhkan daripada 36 nombor, memilih cip, mengesahkan pertaruhan, dan sistem akan menolak baki serta menjana rekod pertaruhan.',
|
||||
' Bilangan maksimum nombor yang boleh dipilih bagi setiap pusingan bergantung pada konfigurasi semasa sistem.',
|
||||
'',
|
||||
'**Langkah 2 — Penutupan (pada saat ke-20)**',
|
||||
'Tiada pertaruhan baharu diterima. Sebarang pertaruhan selepas penutupan adalah tidak sah.',
|
||||
'2. **Peringkat Penutupan Pertaruhan**',
|
||||
' Apabila pusingan memasuki peringkat penutupan, sistem akan berhenti menerima pertaruhan baharu.',
|
||||
'',
|
||||
'**Langkah 3 — Cabutan & penyelesaian (20–30 saat)**',
|
||||
'Nombor kemenangan diumumkan dan hadiah dibayar mengikut peraturan ganjaran.',
|
||||
'3. **Peringkat Cabutan dan Penyelesaian**',
|
||||
' Sistem akan mengumumkan nombor kemenangan bagi pusingan tersebut dan secara automatik menyelesaikan ganjaran mengikut peraturan semasa.',
|
||||
'',
|
||||
'**Langkah 4 — Pusingan seterusnya**',
|
||||
'Selepas penyelesaian, pusingan seterusnya bermula secara automatik.',
|
||||
'4. **Pusingan Seterusnya Bermula**',
|
||||
' Selepas pusingan semasa selesai diselesaikan, sistem akan memulakan pusingan seterusnya secara automatik.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 3. Peraturan Kemenangan',
|
||||
'',
|
||||
'- Hanya **satu** nombor kemenangan dikeluarkan setiap pusingan (daripada 1 hingga 36).',
|
||||
'- Anda menang jika **nombor yang dipilih termasuk nombor kemenangan**.',
|
||||
'- Jika tidak kena, tiada hadiah untuk pusingan tersebut.',
|
||||
'1. Hanya **1 nombor kemenangan** akan dikeluarkan dalam setiap pusingan.',
|
||||
'2. Jika nombor yang dipilih oleh pemain **mengandungi nombor kemenangan**, pertaruhan tersebut dianggap menang.',
|
||||
'3. Jika pemain memilih beberapa nombor dan jumlah pertaruhan bagi setiap nombor adalah sama, maka:',
|
||||
'',
|
||||
'**Jumlah pertaruhan pada nombor kena:**',
|
||||
'- Apabila setiap nombor dipilih dengan jumlah pertaruhan yang sama:',
|
||||
' **Jumlah pertaruhan pada nombor kena = jumlah pertaruhan ÷ bilangan nombor dipilih**',
|
||||
'- Contoh: 5 nombor, jumlah pertaruhan 💎50 → 💎10 setiap nombor. Jika nombor kemenangan termasuk dalam pilihan anda, 💎10 digunakan untuk pengiraan hadiah.',
|
||||
'```text',
|
||||
'Nilai Pertaruhan Nombor Menang = Jumlah Pertaruhan ÷ Bilangan Nombor yang Dipilih',
|
||||
'```',
|
||||
'',
|
||||
'**Contoh:**',
|
||||
'Jika pemain memilih **5 nombor** dengan jumlah pertaruhan **💎50**, maka setiap nombor membawa nilai pertaruhan **💎10**.',
|
||||
'Jika nombor kemenangan berada dalam 5 nombor tersebut, ganjaran akan dikira berdasarkan **💎10**.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 4. Jenis Ganjaran',
|
||||
'### 4. Peraturan Ganjaran',
|
||||
'',
|
||||
'Ganjaran kemenangan berturut-turut terdiri daripada **dua jenis**. Setiap peringkat hanya menggunakan **satu jenis** — **tidak digabungkan**:',
|
||||
'Ganjaran kemenangan berturut-turut dibahagikan kepada **dua jenis**, dan hanya satu jenis akan digunakan bagi setiap peringkat kemenangan berturut-turut:',
|
||||
'',
|
||||
'#### Jenis A — Ganjaran Pekali',
|
||||
'#### 1. Ganjaran Pekali',
|
||||
'',
|
||||
'Hadiah dikira menggunakan pekali odds:',
|
||||
'Ganjaran dikira dengan mendarab nilai pertaruhan nombor menang dengan pekali odds bagi peringkat semasa:',
|
||||
'',
|
||||
'```',
|
||||
'Hadiah = jumlah pertaruhan pada nombor kena × pekali odds',
|
||||
'```text',
|
||||
'Jumlah Kemenangan = Nilai Pertaruhan Nombor Menang × Pekali Odds',
|
||||
'```',
|
||||
'',
|
||||
'#### Jenis B — Ganjaran Tetap',
|
||||
'#### 2. Ganjaran Tetap',
|
||||
'',
|
||||
'Anda menerima **jumlah tetap** yang ditetapkan dalam konfigurasi.',
|
||||
'**Tidak bergantung pada jumlah pertaruhan dan tidak menggunakan pekali odds.**',
|
||||
'Sistem akan terus membayar jumlah tetap yang telah dikonfigurasikan, tanpa mengambil kira jumlah pertaruhan dalam pusingan semasa:',
|
||||
'',
|
||||
'```',
|
||||
'Hadiah = jumlah tetap',
|
||||
'```text',
|
||||
'Jumlah Kemenangan = Jumlah Ganjaran Tetap',
|
||||
'```',
|
||||
'',
|
||||
'**Perbandingan (contoh Peringkat 10):**',
|
||||
'#### 3. Nota Jadual Ganjaran',
|
||||
'',
|
||||
'| Jenis Ganjaran | Jumlah Pertaruhan pada Nombor Kena | Hadiah |',
|
||||
'|:---:|:---:|:---:|',
|
||||
'| Pekali (1:330) | 💎50 | 💎50 × 330 = **16,500** |',
|
||||
'| Ganjaran tetap | Sebarang | **1,000,000** (nilai konfigurasi) |',
|
||||
'Jadual ganjaran kemenangan berturut-turut semasa adalah berdasarkan konfigurasi backend sistem, dan frontend perlu memaparkannya menggunakan data konfigurasi semasa.',
|
||||
'Setiap peringkat mengandungi maklumat berikut:',
|
||||
'',
|
||||
'- Peringkat kemenangan berturut-turut',
|
||||
'- Jenis ganjaran',
|
||||
'- Pekali odds',
|
||||
'- Jumlah ganjaran tetap',
|
||||
'- Sama ada ia peringkat jackpot',
|
||||
'',
|
||||
'Dengan kata lain, jadual ganjaran tidak ditulis tetap. Kandungan sebenar sentiasa mengikut konfigurasi semasa sistem.',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 5. Peraturan Kemenangan Berturut-turut',
|
||||
'',
|
||||
'Apabila anda **menang berturut-turut**, ganjaran meningkat mengikut peringkat kemenangan. Secara lalai, **ganjaran pekali** digunakan dengan odds yang meningkat:',
|
||||
'Apabila pemain menang dalam beberapa pusingan berturut-turut, pemain akan memasuki status kemenangan berturut-turut. Semakin tinggi kemenangan berturut-turut, semakin tinggi peringkat ganjaran.',
|
||||
'',
|
||||
'| Kemenangan Berturut-turut | Odds | Pekali |',
|
||||
'|:---:|:---:|:---:|',
|
||||
'| Kemenangan ke-1 | 1:33 | 33 |',
|
||||
'| 2 berturut-turut | 1:66 | 66 |',
|
||||
'| 3 berturut-turut | 1:99 | 99 |',
|
||||
'| 4 berturut-turut | 1:132 | 132 |',
|
||||
'| 5 berturut-turut | 1:165 | 165 |',
|
||||
'| 6 berturut-turut | 1:198 | 198 |',
|
||||
'| 7 berturut-turut | 1:231 | 231 |',
|
||||
'| 8 berturut-turut | 1:264 | 264 |',
|
||||
'| 9 berturut-turut | 1:297 | 297 |',
|
||||
'| 10 berturut-turut | 1:330 | 330 |',
|
||||
'#### 1. Peraturan Pengiraan Kemenangan Berturut-turut',
|
||||
'',
|
||||
'**Peraturan kemenangan berturut-turut:**',
|
||||
'1. Selepas pemain menang, bilangan kemenangan berturut-turut akan bertambah.',
|
||||
'2. Ganjaran dikira berdasarkan **peringkat kemenangan berturut-turut semasa pertaruhan dibuat**.',
|
||||
'3. Jika pemain kalah dalam mana-mana pusingan, kemenangan berturut-turut akan terus direset kepada **0**.',
|
||||
'4. Dalam pelaksanaan semasa, kemenangan biasa akan meneruskan kemenangan berturut-turut, tetapi jika pemain mengenai **peringkat jackpot**, kemenangan berturut-turut akan direset kepada **0** selepas penyelesaian pusingan tersebut.',
|
||||
'',
|
||||
'- Ganjaran dikira berdasarkan **status kemenangan berturut-turut semasa anda membuat pertaruhan**: jika anda sudah mempunyai N kemenangan berturut-turut, kemenangan pusingan ini dibayar pada peringkat **(N+1)**.',
|
||||
'- **Sebarang pusingan tanpa kemenangan** akan menetapkan semula kemenangan berturut-turut kepada sifar — anda bermula semula dari peringkat 1.',
|
||||
'- **Melangkau pusingan** (tiada pertaruhan dibuat) semasa kemenangan berturut-turut aktif juga akan **menetapkan semula kemenangan berturut-turut kepada sifar**.',
|
||||
'#### 2. Had Pertaruhan Semasa Kemenangan Berturut-turut Jackpot',
|
||||
'',
|
||||
'**Contoh (ganjaran pekali):**',
|
||||
'Apabila kemenangan berturut-turut pemain mencapai peringkat **jackpot pertama** yang ditetapkan oleh sistem, pemain akan memasuki peringkat sekatan pertaruhan jackpot.',
|
||||
'',
|
||||
'| Senario | Jumlah Pertaruhan pada Nombor Kena | Peringkat | Odds | Hadiah |',
|
||||
'|:---:|:---:|:---:|:---:|:---:|',
|
||||
'| Kemenangan pertama | 💎10 | Ke-1 | 1:33 | **330** |',
|
||||
'| 3 kemenangan berturut-turut | 💎50 | Ke-3 | 1:99 | **4,950** |',
|
||||
'| 10 kemenangan berturut-turut | 💎50 | Ke-10 | 1:330 | **16,500** |',
|
||||
'Peraturannya adalah seperti berikut:',
|
||||
'',
|
||||
'1. Dalam setiap pusingan berikutnya, **jumlah keseluruhan pertaruhan** **tidak boleh melebihi** jumlah pertaruhan bagi **pusingan pertama yang memenangi jackpot** dalam kemenangan berturut-turut semasa.',
|
||||
'2. Had ini akan kekal dikunci sepanjang kemenangan berturut-turut semasa dan tidak akan berubah walaupun pemain menang jackpot lagi selepas itu.',
|
||||
'3. Sebaik sahaja kemenangan berturut-turut terputus, sekatan ini akan dibuang serta-merta.',
|
||||
'4. Kemenangan berturut-turut biasa sebelum mencapai peringkat jackpot tidak tertakluk kepada peraturan ini.',
|
||||
'',
|
||||
'{{STREAK_REWARD_TABLE}}',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'### 6. Jackpot Sejuta',
|
||||
'',
|
||||
'Apabila pemain **bertaruh dan menang 10 pusingan berturut-turut**, dan setiap pertaruhan semasa kemenangan berturut-turut adalah **sekurang-kurangnya 💎50**, Jackpot Sejuta akan dicetuskan.',
|
||||
'Apabila pemain mencapai peringkat jackpot yang dikonfigurasikan sistem melalui kemenangan berturut-turut, dan peringkat jackpot tersebut dikonfigurasikan sebagai ganjaran tetap, pemain boleh menerima Jackpot Sejuta.',
|
||||
'',
|
||||
'**Syarat:**',
|
||||
'#### 1. Syarat Pencetus',
|
||||
'',
|
||||
'1. **10 pusingan berturut-turut** dengan pertaruhan dibuat dan dimenangi dalam setiap pusingan;',
|
||||
'2. **Setiap pusingan** dalam kemenangan berturut-turut mesti mempunyai pertaruhan **sekurang-kurangnya 💎50**;',
|
||||
'3. Jika mana-mana pusingan dalam kemenangan berturut-turut kurang daripada 💎50, anda hanya menerima ganjaran kemenangan berturut-turut biasa — **Jackpot Sejuta tidak terpakai**.',
|
||||
'1. Pemain mesti terus menang sehingga mencapai peringkat jackpot semasa yang dikonfigurasikan oleh sistem.',
|
||||
'2. Jika peringkat jackpot dikonfigurasikan sebagai **ganjaran tetap**, contohnya **💎1,000,000**, pemain akan terus menerima Jackpot Sejuta apabila mengenai peringkat tersebut.',
|
||||
'3. Dalam pelaksanaan semasa, **tiada syarat pertaruhan minimum tambahan**. Selagi pemain memenuhi jumlah pertaruhan minimum yang dibenarkan oleh platform, pemain boleh menyertai kemenangan berturut-turut jackpot.',
|
||||
'4. Selepas mengenai peringkat jackpot, sebaik sahaja penyelesaian selesai, kemenangan berturut-turut akan direset kepada **0**.',
|
||||
'',
|
||||
'**Cara pembayaran (bergantung pada konfigurasi backend):**',
|
||||
'#### 2. Peraturan Bayaran',
|
||||
'',
|
||||
'- **Ganjaran tetap**: Jika peringkat 10 ditetapkan sebagai jumlah tetap, 10 kemenangan berturut-turut membayar **💎1,000,000** secara langsung.',
|
||||
'- **Ganjaran pekali**: Jika peringkat 10 menggunakan odds pekali, anda menerima hadiah biasa pada **1:330** terlebih dahulu, ditambah jackpot tambahan mengikut peraturan kempen.',
|
||||
'- Jika peringkat jackpot dikonfigurasikan sebagai **ganjaran tetap**, jumlah jackpot tetap yang telah dikonfigurasikan akan dibayar terus.',
|
||||
'- Jika peringkat jackpot dikonfigurasikan sebagai **ganjaran pekali**, ganjaran tetap akan dikira sebagai **nilai pertaruhan nombor menang × pekali odds**, dan satu juta tetap tidak akan dibayar secara automatik.',
|
||||
'',
|
||||
'**Contoh — ganjaran tetap pada peringkat 10 (💎1,000,000), jumlah pertaruhan pada nombor kena 💎50 setiap pusingan:**',
|
||||
'**Contoh:**',
|
||||
'',
|
||||
'- 10 kemenangan berturut-turut → **💎1,000,000**',
|
||||
'- Kemenangan berturut-turut ditetapkan semula kepada **sifar** selepas jackpot diberikan',
|
||||
'- Jika peringkat jackpot dikonfigurasikan sebagai ganjaran tetap **💎1,000,000**',
|
||||
'- Pemain mencapai peringkat jackpot tersebut dan menang',
|
||||
'- Maka pemain akan terus menerima **💎1,000,000**',
|
||||
'',
|
||||
'**Contoh — ganjaran pekali pada peringkat 10 (1:330), jumlah pertaruhan pada nombor kena 💎50:**',
|
||||
'',
|
||||
'- Hadiah biasa peringkat 10: 💎50 × 330 = **💎16,500**',
|
||||
'- Jika kempen Jackpot berasingan terpakai, hadiah sejuta tambahan mungkin ditambah di atasnya',
|
||||
'---',
|
||||
].join('\n'),
|
||||
confirm: 'Saya Faham',
|
||||
streakRewardTable: {
|
||||
title: 'Jadual Ganjaran Kemenangan Berturut-turut',
|
||||
columns: {
|
||||
streak: 'Peringkat',
|
||||
rewardType: 'Jenis Ganjaran',
|
||||
oddsFactor: 'Odds',
|
||||
fixedAmount: 'Ganjaran Tetap',
|
||||
isJackpot: 'Jackpot',
|
||||
},
|
||||
rewardTypes: {
|
||||
coefficient: 'Ganjaran Pekali',
|
||||
fixed: 'Ganjaran Tetap',
|
||||
},
|
||||
streakValue: 'Pusingan {{streak}}',
|
||||
yes: TEXT_YES,
|
||||
no: TEXT_NO,
|
||||
empty: 'Tiada konfigurasi ganjaran',
|
||||
},
|
||||
},
|
||||
procedures: {
|
||||
title: 'Tambah Nilai / Pengeluaran',
|
||||
|
||||
@@ -211,119 +211,143 @@ export default {
|
||||
rules: {
|
||||
title: '玩法规则',
|
||||
content: [
|
||||
'## 36 字花 · 玩法指南',
|
||||
'## 36字花规则说明',
|
||||
'',
|
||||
'### 一、游戏介绍',
|
||||
'',
|
||||
'「36字花」是一款 **30 秒一期** 的高频数字竞猜游戏。系统每期从 **36 个字号**(鼠、牛、虎……青龙、白虎、朱雀、玄武等)中开出 **1 个中奖号码**。玩家在下注期内选号押注,猜中即可获得奖金;连续猜中可提升奖励,**连中 10 场** 还可获得 **百万大奖**。',
|
||||
'「36字花」是一款数字竞猜游戏。每期从 **36 个字号** 中开出 **1 个中奖号码**。玩家在下注阶段选号押注,猜中即获奖;连续猜中可提升奖励,达到大奖档后还有机会获得 **百万大奖**。',
|
||||
'',
|
||||
'### 二、玩法说明',
|
||||
'',
|
||||
'每期约 **30 秒**,流程如下:',
|
||||
'每期游戏分为以下几个阶段:',
|
||||
'',
|
||||
'**1. 下注期(0~20 秒)**',
|
||||
'在 36 宫格中选择号码(默认最多 **5 个**),选择筹码面额(如 💎1、5、10、25、50、100),点击确认下注,系统扣款后注单生效。',
|
||||
'1. **下注阶段**',
|
||||
' 玩家在 36 个号码中选择想要押注的号码,选择筹码后确认下注,系统扣款并生成注单。',
|
||||
' 单期最多可选号码数,以系统当前配置为准。',
|
||||
'',
|
||||
'**2. 封盘(20 秒)**',
|
||||
'停止接受新注单,之后下注无效。',
|
||||
'2. **封盘阶段**',
|
||||
' 进入封盘后,系统停止接受新注单。',
|
||||
'',
|
||||
'**3. 开奖结算(20~30 秒)**',
|
||||
'公布本期中奖号码,系统按规则结算派彩。',
|
||||
'3. **开奖结算阶段**',
|
||||
' 系统公布本期中奖号码,并按当前规则自动派彩。',
|
||||
'',
|
||||
'**4. 下一期**',
|
||||
'结算完成后自动进入下一期,循环进行。',
|
||||
'4. **下一期开始**',
|
||||
' 当前期结算完成后,系统自动进入下一期。',
|
||||
'',
|
||||
'### 三、中奖说明',
|
||||
'',
|
||||
'- 每期只开出 **1 个** 中奖号码(1~36 中之一)。',
|
||||
'- 玩家押注的号码中,**包含开奖号码即算中奖**。',
|
||||
'- 未押中则本期无奖金。',
|
||||
'1. 每期只开出 **1 个中奖号码**。',
|
||||
'2. 如果玩家押注的号码中 **包含开奖号码**,则视为中奖。',
|
||||
'3. 如果玩家选择了多个号码,且每个号码押注金额相同,则:',
|
||||
'',
|
||||
'**压中号码面额** 计算方式:',
|
||||
'- 同一期内各号押注相同时:',
|
||||
' **压中号码面额 = 本笔压注总额 ÷ 所选号码个数**',
|
||||
'- 示例:选 5 个号、总押 💎50 → 每个号面额 💎10;若开奖号在其中,按 💎10 参与奖金计算。',
|
||||
'```text',
|
||||
'压中号码面额 = 本笔压注总额 ÷ 所选号码个数',
|
||||
'```',
|
||||
'',
|
||||
'**示例:**',
|
||||
'若玩家选择 **5 个号码**,总押注 **💎50**,则每个号码面额为 **💎10**。',
|
||||
'若开奖号码在这 5 个号码中,则按 **💎10** 作为中奖计算基础。',
|
||||
'',
|
||||
'### 四、奖励说明',
|
||||
'',
|
||||
'连胜奖励分为 **两种类型**,每档 **二选一**,不会同时享受:',
|
||||
'连胜奖励分为 **两种类型**,每个连胜档位只会生效其中一种:',
|
||||
'',
|
||||
'#### 1. 系数奖励',
|
||||
'',
|
||||
'按赔率系数计算:',
|
||||
'按压中号码面额乘以当前档位的赔率系数结算:',
|
||||
'',
|
||||
'`中奖金额 = 压中号码面额 × 赔率系数`',
|
||||
'```text',
|
||||
'中奖金额 = 压中号码面额 × 赔率系数',
|
||||
'```',
|
||||
'',
|
||||
'#### 2. 固定奖励',
|
||||
'',
|
||||
'直接发放配置的 **固定金额**,**与押注面额无关,也不使用赔率系数**。',
|
||||
'直接发放系统配置的固定金额,与本期压注面额无关:',
|
||||
'',
|
||||
'`中奖金额 = 固定金额`',
|
||||
'```text',
|
||||
'中奖金额 = 固定奖励金额',
|
||||
'```',
|
||||
'',
|
||||
'**示例对比**(第 10 档):',
|
||||
'#### 3. 奖励表说明',
|
||||
'',
|
||||
'| 奖励类型 | 押中面额 | 中奖金额 |',
|
||||
'|:---:|:---:|:---:|',
|
||||
'| 系数奖励(1:330) | 💎50 | 💎50 × 330 = **16,500** |',
|
||||
'| 固定奖励 | 任意 | **1,000,000**(配置值) |',
|
||||
'当前游戏的连胜奖励表以系统后台配置为准,前端展示应读取当前配置数据。',
|
||||
'每个档位包含以下信息:',
|
||||
'',
|
||||
'- 连胜档位',
|
||||
'- 奖励类型',
|
||||
'- 赔率系数',
|
||||
'- 固定奖励金额',
|
||||
'- 是否大奖档',
|
||||
'',
|
||||
'也就是说,奖励表不是固定写死的,实际以系统当前配置内容为准。',
|
||||
'',
|
||||
'### 五、连胜说明',
|
||||
'',
|
||||
'玩家 **连续中奖** 时,奖励按连胜场次递增。默认采用 **系数奖励**,赔率累加如下:',
|
||||
'玩家连续中奖后,会进入连胜状态;连胜越高,对应奖励档位越高。',
|
||||
'',
|
||||
'| 连胜场次 | 赔率 | 系数 |',
|
||||
'|:---:|:---:|:---:|',
|
||||
'| 第 1 场中奖 | 1:33 | 33 |',
|
||||
'| 连中 2 场 | 1:66 | 66 |',
|
||||
'| 连中 3 场 | 1:99 | 99 |',
|
||||
'| 连中 4 场 | 1:132 | 132 |',
|
||||
'| 连中 5 场 | 1:165 | 165 |',
|
||||
'| 连中 6 场 | 1:198 | 198 |',
|
||||
'| 连中 7 场 | 1:231 | 231 |',
|
||||
'| 连中 8 场 | 1:264 | 264 |',
|
||||
'| 连中 9 场 | 1:297 | 297 |',
|
||||
'| 连中 10 场 | 1:330 | 330 |',
|
||||
'#### 1. 连胜计算规则',
|
||||
'',
|
||||
'**连胜规则:**',
|
||||
'1. 玩家中奖后,连胜场次增加。',
|
||||
'2. 奖励按 **下注时所在的连胜档位** 计算。',
|
||||
'3. 任意一期未中奖,连胜立即清零。',
|
||||
'4. 当前实现中,普通中奖会继续累加连胜;如果本次命中的是 **大奖档**,则本次结算完成后,连胜会直接重置为 **0**。',
|
||||
'',
|
||||
'- 赔率按 **下注时的连胜状态** 计算:下注时已是 N 连胜,本期中奖则按第 **(N+1)** 场奖励结算。',
|
||||
'- **任意一期未中奖** → 连胜清零,从第 1 场重新计算。',
|
||||
'- **连胜期间跳局未下注** → 连胜也会清零。',
|
||||
'#### 2. 大奖连胜压注限制',
|
||||
'',
|
||||
'**计算示例**(系数奖励):',
|
||||
'当玩家连胜达到系统配置的首个 **大奖档** 后,会进入大奖连胜压注限制阶段。',
|
||||
'',
|
||||
'| 场景 | 压中面额 | 连胜场次 | 赔率 | 中奖金额 |',
|
||||
'|:---:|:---:|:---:|:---:|:---:|',
|
||||
'| 首次中奖 | 💎10 | 第 1 场 | 1:33 | **330** |',
|
||||
'| 三连胜 | 💎50 | 第 3 场 | 1:99 | **4,950** |',
|
||||
'| 十连胜 | 💎50 | 第 10 场 | 1:330 | **16,500** |',
|
||||
'规则如下:',
|
||||
'',
|
||||
'1. 后续每一期的**压注总额**,**不得超过** 本次连胜中“首次中大奖”那一笔的压注总额。',
|
||||
'2. 该上限在本轮连胜期间保持锁定,之后即使再次中大奖,也不会改变。',
|
||||
'3. 一旦连胜中断,限制立即解除。',
|
||||
'4. 未达到大奖档之前的普通连胜,不受该限制。',
|
||||
'',
|
||||
'{{STREAK_REWARD_TABLE}}',
|
||||
'',
|
||||
'### 六、百万大奖',
|
||||
'',
|
||||
'当玩家 **连续 10 期均有下注且全部中奖**,且连胜期间 **每期押注不低于 💎50**,即可触发百万大奖。',
|
||||
'当玩家连续中奖达到系统配置的大奖档,并且该大奖档配置为固定大奖时,即可获得百万奖励。',
|
||||
'',
|
||||
'**触发条件:**',
|
||||
'#### 1. 触发条件',
|
||||
'',
|
||||
'1. 连续 **10 期** 均有下注且全部中奖;',
|
||||
'2. 连胜期间 **每一期押注面额均不低于 💎50**;',
|
||||
'3. 若连胜中有任意一期低于 💎50,仅享受常规连胜奖励,**不触发百万大奖**。',
|
||||
'1. 玩家需连续中奖,直到达到系统当前配置的大奖档。',
|
||||
'2. 若大奖档配置为 **固定奖励**,例如 **💎1,000,000**,则命中该档时可直接获得百万大奖。',
|
||||
'3. 当前实现下,**无额外最低压注要求**。只要满足平台本身允许的最小下注金额,即可参与大奖连胜。',
|
||||
'4. 命中大奖档后,本次结算完成,连胜将重置为 **0**。',
|
||||
'',
|
||||
'**派发方式(视后台配置):**',
|
||||
'#### 2. 派发规则',
|
||||
'',
|
||||
'- **固定奖励**:第 10 档设为固定金额时,连中 10 场直接获得 **💎1,000,000**。',
|
||||
'- **系数奖励**:第 10 档为系数奖励时,先按 **1:330** 发放常规奖金,再按活动规则叠加额外大奖。',
|
||||
'- 若大奖档配置为 **固定奖励**:直接发放配置的固定大奖金额。',
|
||||
'- 若大奖档配置为 **系数奖励**:则仍按“压中号码面额 × 赔率系数”结算,不会自动发放固定一百万。',
|
||||
'',
|
||||
'**示例**(第 10 档为固定奖励 💎1,000,000,每局压中面额 💎50):',
|
||||
'**示例:**',
|
||||
'',
|
||||
'- 连中 10 场 → 获得 **💎1,000,000**',
|
||||
'- 触发后连胜 **归零**,下一期从第 1 场重新计算',
|
||||
'- 若大奖档配置为固定奖励 **💎1,000,000**',
|
||||
'- 玩家达到该大奖档并成功中奖',
|
||||
'- 则直接获得 **💎1,000,000**',
|
||||
'',
|
||||
'**示例**(第 10 档为系数奖励 1:330,每局压中面额 💎50):',
|
||||
'',
|
||||
'- 第 10 场常规奖金:💎50 × 330 = **💎16,500**',
|
||||
'- 若另有 Jackpot 活动叠加,可额外获得百万奖金',
|
||||
'---',
|
||||
].join('\n'),
|
||||
confirm: '我知道了',
|
||||
streakRewardTable: {
|
||||
title: '连胜奖励表',
|
||||
columns: {
|
||||
streak: '连胜场次',
|
||||
rewardType: '奖励类型',
|
||||
oddsFactor: '奖励倍率',
|
||||
fixedAmount: '固定奖励',
|
||||
isJackpot: '是否大奖',
|
||||
},
|
||||
rewardTypes: {
|
||||
coefficient: '倍率奖励',
|
||||
fixed: '固定奖励',
|
||||
},
|
||||
streakValue: '第 {{streak}} 场',
|
||||
yes: TEXT_YES,
|
||||
no: TEXT_NO,
|
||||
empty: '暂无奖励配置',
|
||||
},
|
||||
},
|
||||
procedures: {
|
||||
title: '充值 / 提现',
|
||||
|
||||
@@ -30,6 +30,9 @@ export function MainEntryPage() {
|
||||
const selectChip = useGameRoundStore((state) => state.selectChip)
|
||||
const hydrateSession = useGameSessionStore((state) => state.hydrateSession)
|
||||
const syncConnection = useGameSessionStore((state) => state.syncConnection)
|
||||
const setStreakWinRewardRows = useGameSessionStore(
|
||||
(state) => state.setStreakWinRewardRows,
|
||||
)
|
||||
const setCurrentUser = useAuthStore((state) => state.setCurrentUser)
|
||||
const authStatus = useAuthStore((state) => state.status)
|
||||
const authIsHydrated = useAuthStore((state) => state.isHydrated)
|
||||
@@ -97,6 +100,7 @@ export function MainEntryPage() {
|
||||
connection: snapshot.connection,
|
||||
dashboard: snapshot.dashboard,
|
||||
})
|
||||
setStreakWinRewardRows(result.streakWinRewardRows)
|
||||
|
||||
const currentUser = useAuthStore.getState().currentUser
|
||||
|
||||
@@ -151,6 +155,7 @@ export function MainEntryPage() {
|
||||
isReloginRequired,
|
||||
selectChip,
|
||||
setCurrentUser,
|
||||
setStreakWinRewardRows,
|
||||
syncConnection,
|
||||
t,
|
||||
])
|
||||
|
||||
@@ -3,6 +3,7 @@ import lengthBlueBtn from '@/assets/system/length-blue-btn.webp'
|
||||
import { CenterModal } from '@/components/center-modal.tsx'
|
||||
import RulesMarkdownContent from '@/components/rules-markdown-content.tsx'
|
||||
import { SmartBackground } from '@/components/smart-background.tsx'
|
||||
import StreakRewardTable from '@/components/streak-reward-table.tsx'
|
||||
import { useModalStore } from '@/store'
|
||||
|
||||
function DesktopRulesModal() {
|
||||
@@ -29,7 +30,9 @@ function DesktopRulesModal() {
|
||||
>
|
||||
<div className="flex h-full flex-col gap-design-24 px-design-28 pb-design-30 pt-design-10">
|
||||
<div className="flex-1 overflow-y-auto rounded-[12px] bg-black/35 p-design-20 text-design-18 text-[#B9E7EA]">
|
||||
<RulesMarkdownContent content={t('game.modals.rules.content')} />
|
||||
<RulesMarkdownContent content={t('game.modals.rules.content')}>
|
||||
<StreakRewardTable />
|
||||
</RulesMarkdownContent>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center">
|
||||
|
||||
@@ -3,6 +3,7 @@ import lengthBlueBtn from '@/assets/system/length-blue-btn.webp'
|
||||
import { MobileCenterModal } from '@/components/mobile-center-modal.tsx'
|
||||
import RulesMarkdownContent from '@/components/rules-markdown-content.tsx'
|
||||
import { SmartBackground } from '@/components/smart-background.tsx'
|
||||
import StreakRewardTable from '@/components/streak-reward-table.tsx'
|
||||
import { useModalStore } from '@/store'
|
||||
|
||||
function MobileRulesModal() {
|
||||
@@ -32,7 +33,9 @@ function MobileRulesModal() {
|
||||
<RulesMarkdownContent
|
||||
compact
|
||||
content={t('game.modals.rules.content')}
|
||||
/>
|
||||
>
|
||||
<StreakRewardTable compact />
|
||||
</RulesMarkdownContent>
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 justify-center">
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
DashboardState,
|
||||
GameBootstrapSnapshot,
|
||||
JackpotBroadcastItem,
|
||||
StreakWinRewardRow,
|
||||
} from '@/type'
|
||||
|
||||
type GameSessionSlice = Pick<
|
||||
@@ -34,6 +35,8 @@ export interface GameSessionStoreState extends GameSessionSlice {
|
||||
requestRealtimeConnection: () => void
|
||||
resetRealtimeConnectionRequest: () => void
|
||||
shouldConnectRealtime: boolean
|
||||
setStreakWinRewardRows: (rows: StreakWinRewardRow[]) => void
|
||||
streakWinRewardRows: StreakWinRewardRow[]
|
||||
setConnectionLatency: (latencyMs: number | null) => void
|
||||
setConnectionStatus: (status: ConnectionStatus) => void
|
||||
syncConnection: (patch: Partial<ConnectionState>) => void
|
||||
@@ -54,6 +57,7 @@ export const useGameSessionStore = create<GameSessionStoreState>()((set) => ({
|
||||
...createInitialSessionState(),
|
||||
jackpotBroadcasts: [],
|
||||
shouldConnectRealtime: false,
|
||||
streakWinRewardRows: [],
|
||||
dismissAnnouncement: (announcementId) => {
|
||||
set((state) => ({
|
||||
announcements: {
|
||||
@@ -122,6 +126,9 @@ export const useGameSessionStore = create<GameSessionStoreState>()((set) => ({
|
||||
resetRealtimeConnectionRequest: () => {
|
||||
set({ shouldConnectRealtime: false })
|
||||
},
|
||||
setStreakWinRewardRows: (rows) => {
|
||||
set({ streakWinRewardRows: rows })
|
||||
},
|
||||
setConnectionLatency: (latencyMs) => {
|
||||
set((state) => ({
|
||||
connection: {
|
||||
|
||||
@@ -27,6 +27,7 @@ export type GamePeriodStatus =
|
||||
| (string & {})
|
||||
export type RevealAnimationPhase = 'idle' | 'spinning' | 'stopping' | 'result'
|
||||
export type RewardAnimationType = 'none' | 'small' | 'big'
|
||||
export type StreakRewardType = 'coefficient' | 'fixed' | (string & {})
|
||||
export type FinanceRecordType = 'deposit' | 'withdraw'
|
||||
export type ConfirmState =
|
||||
| 'idle'
|
||||
@@ -199,6 +200,14 @@ export interface JackpotBroadcastItem {
|
||||
totalWin: string
|
||||
}
|
||||
|
||||
export interface StreakWinRewardRow {
|
||||
fixedAmount: string
|
||||
isJackpot: boolean
|
||||
oddsFactor: number
|
||||
rewardType: StreakRewardType
|
||||
streak: number
|
||||
}
|
||||
|
||||
export interface UserStreakMessageData {
|
||||
currentStreak: number
|
||||
maxBetPerNumber?: number
|
||||
@@ -418,18 +427,34 @@ export interface GameLobbyDictionaryItemDto {
|
||||
|
||||
export interface GameLobbyUserSnapshotDto {
|
||||
coin: string
|
||||
fixed_amount?: string
|
||||
current_streak: number
|
||||
is_jackpot?: boolean
|
||||
odds_factor?: number
|
||||
reward_type?: StreakRewardType
|
||||
streak_level?: number
|
||||
}
|
||||
|
||||
export interface GameLobbyStreakWinRewardRowDto {
|
||||
fixed_amount: string
|
||||
is_jackpot: boolean
|
||||
odds_factor: number
|
||||
reward_type: StreakRewardType
|
||||
streak: number
|
||||
}
|
||||
|
||||
export interface GameLobbyStreakWinRewardDto {
|
||||
first_jackpot_streak_level?: number
|
||||
rows: GameLobbyStreakWinRewardRowDto[]
|
||||
}
|
||||
|
||||
export interface GameLobbyInitDto {
|
||||
bet_config: GameLobbyBetConfigDto
|
||||
dictionary: GameLobbyDictionaryItemDto[]
|
||||
period?: GameLobbyPeriodDto | null
|
||||
runtime_enabled: boolean
|
||||
server_time: number
|
||||
streak_win_reward?: GameLobbyStreakWinRewardDto | null
|
||||
user_snapshot: GameLobbyUserSnapshotDto
|
||||
}
|
||||
|
||||
@@ -437,6 +462,7 @@ export interface GameLobbyInitResult {
|
||||
runtimeEnabled: boolean
|
||||
serverTime: number
|
||||
snapshot: GameBootstrapSnapshot
|
||||
streakWinRewardRows: StreakWinRewardRow[]
|
||||
userSnapshot: GameLobbyInitDto['user_snapshot']
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user