Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # ---------------------------------------------------------
- # Author : domdom
- # Project : Windice Dice Bot
- # License : Free to use and modify for Windice community members
- # API Documentation : https://windice.org/docsapi
- # -----------------------------------------------------------
- import re
- import time
- import requests
- import threading
- import winsound
- import tkinter as tk
- from tkinter import ttk, messagebox
- # Global flag to control the background betting thread state
- is_running = False
- HOUSE_EDGE = 2.0
- # ===========================================================
- # 1. WINDICE API FUNCTIONS (Direct Token / Raw Header Authorization)
- # ===========================================================
- BASE_URL = "https://windice.org"
- # >>> REPLACE WITH YOUR ACTUAL WINDICE API KEY <<<
- API_KEY = "YOUR API KEY HERE".strip()
- # HTTP headers required for API authentication
- HEADERS = {
- "Authorization": API_KEY,
- "Content-Type": "application/json"
- }
- def get_user_info_api():
- """Fetch user account details and coin balances from the API."""
- url = f"{BASE_URL}/api/v1/api/user"
- try:
- # request information to user api using requests.get()
- response = requests.get(url, headers=HEADERS, timeout=10)
- return response.json()
- except Exception as e:
- return {"status": "error", "message": str(e)}
- def place_roll_api(currency, bet_amount, game_type, min_range, max_range):
- """Send a dice roll bet request to the API."""
- url = f"{BASE_URL}/api/v1/api/roll"
- payload = {
- "curr": str(currency).lower(),
- "bet": float(bet_amount),
- "game": str(game_type),
- "low": int(min_range),
- "high": int(max_range)
- }
- try:
- # send a request to the roll api with paramters using requests.post()
- response = requests.post(url, json=payload, headers=HEADERS, timeout=10)
- return response.json()
- except Exception as e:
- return {"status": "error", "message": str(e)}
- # ==============================================================================
- # 2. GUI LOGIC & EVENT HANDLERS
- # ==============================================================================
- def update_account_info():
- """Fetch user profile and update balance labels asynchronously."""
- selected_coin = combo_coins.get().strip().lower()
- def fetch():
- res = get_user_info_api()
- # If API successfully returns user data
- if res.get("status") == "success":
- data = res.get("data", {})
- username = data.get("username", "Unknown")
- balances = data.get("balance", {})
- coin_balance = 0.0
- if isinstance(balances, dict):
- coin_balance = balances.get(selected_coin, 0.0)
- # Update GUI elements safely on the main thread
- def apply_ui():
- lbl_username_val.config(text=username)
- lbl_balance_val.config(text=f"{float(coin_balance):.8f} {selected_coin.upper()}")
- root.after(0, apply_ui)
- else:
- # If authentication or request fails
- def apply_err():
- lbl_username_val.config(text="Auth Failed")
- lbl_balance_val.config(text="0.00000000")
- root.after(0, apply_err)
- # Run network request in a background thread to prevent GUI freezing
- threading.Thread(target=fetch, daemon=True).start()
- def on_coin_change(event=None):
- """Reset bet size and refresh balance when a new coin is selected."""
- entry_bet_size.delete(0, tk.END)
- entry_bet_size.insert(0, "0.00000000")
- update_account_info()
- def calculate_payout(event=None):
- """Calculate potential multiplier payout based on win chance and house edge."""
- try:
- r_min = float(entry_range_min.get())
- r_max = float(entry_range_max.get())
- win_chance = (r_max - r_min) + 1.0
- entry_payout.config(state="normal")
- entry_payout.delete(0, tk.END)
- # Check if win chance is within valid platform limits and range order is correct
- if 1.0 <= win_chance <= 10000.0 and r_max >= r_min:
- rtp = 100.0 - HOUSE_EDGE
- payout = (rtp * 100.0) / win_chance
- entry_payout.insert(0, f"{payout:.4f}")
- else:
- entry_payout.insert(0, "Invalid")
- entry_payout.config(state="readonly")
- except ValueError:
- entry_payout.config(state="normal")
- entry_payout.delete(0, tk.END)
- entry_payout.config(state="readonly")
- def update_table(bet_id, roll, target, profit, status):
- """Insert a new roll result row into the Treeview table with color tags."""
- item_id = tree.insert("", 0, values=(bet_id, roll, target, profit, status))
- # Apply green color for wins, red for losses
- if status == "WIN":
- tree.item(item_id, tags=("win_tag",))
- else:
- tree.item(item_id, tags=("loss_tag",))
- def clear_table():
- """Clear all records from the history table."""
- for item in tree.get_children():
- tree.delete(item)
- def extract_minimum_bet(error_msg):
- """Parse minimum bet value from API error messages using regex."""
- match = re.search(r"Minimum bet\s+(\d+(?:\.\d+)?)", error_msg, re.IGNORECASE)
- if match:
- return match.group(1)
- return None
- def play_victory_chime():
- """Play custom win audio alert"""
- try:
- winsound.PlaySound("mybot-win.wav", winsound.SND_FILENAME | winsound.SND_ASYNC)
- except Exception:
- winsound.MessageBeep(winsound.MB_ICONASTERISK)
- def betting_loop():
- """Main automated betting loop running in a background thread."""
- global is_running
- try:
- # Lock configuration inputs while bot is running
- combo_coins.config(state="disabled")
- entry_bet_size.config(state="disabled")
- # Pass all input field values to variables
- total_bets = int(entry_num_bets.get())
- bet_size = float(entry_bet_size.get())
- currency = combo_coins.get()
- r_min = float(entry_range_min.get())
- r_max = float(entry_range_max.get())
- t_min_str = entry_target_min.get().strip()
- t_max_str = entry_target_max.get().strip()
- has_target = bool(t_min_str and t_max_str)
- t_min = float(t_min_str) if has_target else None
- t_max = float(t_max_str) if has_target else None
- # --- Range Validation ---
- if r_min > r_max:
- root.after(0, lambda: messagebox.showerror("Error", "Min Range cannot be greater than Max Range!"))
- stop_betting()
- return
- except ValueError:
- root.after(0, lambda: messagebox.showerror("Error", "Please check your numeric inputs!"))
- stop_betting()
- return
- # Loop through the specified number of bets
- for i in range(1, total_bets + 1):
- # Stop loop immediately if user clicked Stop button
- if not is_running:
- break
- res = place_roll_api(
- currency=currency,
- bet_amount=bet_size,
- game_type="in",
- min_range=r_min,
- max_range=r_max
- )
- # If roll request succeeds
- if res.get("status") == "success":
- data = res.get("data", {})
- roll_result = data.get("result", 0)
- win_amount = data.get("win", 0.0)
- is_win = (win_amount > 0)
- profit = (win_amount - bet_size) if is_win else -bet_size
- status = "WIN" if is_win else "LOSS"
- is_target_hit = has_target and (t_min <= roll_result <= t_max)
- # Update table and account balance on GUI thread
- root.after(0, update_table, i, roll_result, "YES" if is_target_hit else "-", f"{profit:+.8f}", status)
- root.after(0, update_account_info)
- # Handle target hit events & audio notification
- if is_target_hit:
- play_victory_chime()
- should_continue = [True]
- event_done = threading.Event()
- def ask_user(r_res):
- answer = messagebox.askyesno(
- "Target Hit!",
- f"Target hit detected on roll: {r_res}\n\nDo you want to CONTINUE betting?"
- )
- should_continue[0] = answer
- event_done.set()
- root.after(0, ask_user, roll_result)
- event_done.wait()
- # Stop if user clicks No on confirmation dialog
- if not should_continue[0]:
- is_running = False
- break
- else:
- # If roll request returns an error from server
- err_msg = res.get("message", "API Request Failed")
- # Auto-detect minimum bet if error matches platform rules
- extracted_min = extract_minimum_bet(err_msg)
- if extracted_min and bet_size == 0:
- def autofill_bet(val):
- entry_bet_size.config(state="normal")
- entry_bet_size.delete(0, tk.END)
- entry_bet_size.insert(0, val)
- entry_bet_size.config(state="disabled")
- messagebox.showinfo("Minimum Bet Set", f"Auto detected minimum bet for {currency.upper()}: {val}")
- root.after(0, autofill_bet, extracted_min)
- else:
- # Show generic API error popup
- root.after(0, lambda m=err_msg: messagebox.showerror("API Error", m))
- break
- time.sleep(0.25) # Short delay between bets in seconds
- root.after(0, stop_betting)
- def start_betting():
- """Start the automated betting worker thread."""
- global is_running
- clear_table()
- is_running = True
- btn_start.config(state="disabled")
- btn_stop.config(state="normal")
- threading.Thread(target=betting_loop, daemon=True).start()
- def stop_betting():
- """Stop active betting and restore GUI element states."""
- global is_running
- is_running = False
- btn_start.config(state="normal")
- btn_stop.config(state="disabled")
- combo_coins.config(state="readonly")
- entry_bet_size.config(state="normal")
- # ==============================================================================
- # 3. TKINTER GUI LAYOUT
- # ==============================================================================
- root = tk.Tk()
- root.title("Windice Simple Betting Bot (Tutorial)")
- root.geometry("600x600")
- root.resizable(False, False)
- # Main Top Container Frame
- top_container = ttk.Frame(root, padding=5)
- top_container.pack(fill="x", padx=5, pady=5)
- # --- Left Column: Betting Settings Panel ---
- input_frame = ttk.LabelFrame(top_container, text=" Betting Settings ", padding=10)
- input_frame.pack(side="left", fill="both", expand=True, padx=5)
- # Coins Dropdown selection
- ttk.Label(input_frame, text="Coins:", width=14).grid(row=0, column=0, sticky="w", pady=4)
- combo_coins = ttk.Combobox(input_frame, values=["WIN", "USDT", "BTC", "ETH", "TRX", "LTC", "DOGE", "BCH",
- "XRP", "BNB", "TON"], state="readonly", width=14)
- combo_coins.current(0)
- combo_coins.grid(row=0, column=1, columnspan=3, sticky="ew", pady=4)
- combo_coins.bind("<<ComboboxSelected>>", on_coin_change)
- # Bet Size Input field
- ttk.Label(input_frame, text="Bet Size:").grid(row=1, column=0, sticky="w", pady=4)
- entry_bet_size = ttk.Entry(input_frame, width=16)
- entry_bet_size.insert(0, "0.00000000")
- entry_bet_size.grid(row=1, column=1, columnspan=3, sticky="ew", pady=4)
- # Range (Min - Max) Inputs
- ttk.Label(input_frame, text="Range:").grid(row=2, column=0, sticky="w", pady=4)
- entry_range_min = ttk.Entry(input_frame, width=7)
- entry_range_min.insert(0, "0")
- entry_range_min.grid(row=2, column=1, pady=4)
- ttk.Label(input_frame, text="-").grid(row=2, column=2, pady=4)
- entry_range_max = ttk.Entry(input_frame, width=7)
- entry_range_max.insert(0, "4999")
- entry_range_max.grid(row=2, column=3, pady=4)
- entry_range_min.bind("<KeyRelease>", calculate_payout)
- entry_range_max.bind("<KeyRelease>", calculate_payout)
- # Calculated Payout Display (Readonly)
- ttk.Label(input_frame, text="Payout:").grid(row=3, column=0, sticky="w", pady=4)
- entry_payout = ttk.Entry(input_frame, state="readonly", width=16)
- entry_payout.grid(row=3, column=1, columnspan=3, sticky="ew", pady=4)
- # Target Roll Range Inputs
- ttk.Label(input_frame, text="Target:").grid(row=4, column=0, sticky="w", pady=4)
- entry_target_min = ttk.Entry(input_frame, width=7)
- entry_target_min.grid(row=4, column=1, pady=4)
- ttk.Label(input_frame, text="-").grid(row=4, column=2, pady=4)
- entry_target_max = ttk.Entry(input_frame, width=7)
- entry_target_max.grid(row=4, column=3, pady=4)
- # Number of Bets Input
- ttk.Label(input_frame, text="No. Bets:").grid(row=5, column=0, sticky="w", pady=4)
- entry_num_bets = ttk.Entry(input_frame, width=16)
- entry_num_bets.insert(0, "10")
- entry_num_bets.grid(row=5, column=1, columnspan=3, sticky="ew", pady=4)
- # --- Right Column: Account Information Panel ---
- account_frame = ttk.LabelFrame(top_container, text=" Account Info ", padding=10)
- account_frame.pack(side="right", fill="both", expand=True, padx=5)
- ttk.Label(account_frame, text="Username:", font=("Helvetica", 9, "bold")).pack(anchor="w", pady=(5, 2))
- lbl_username_val = ttk.Label(account_frame, text="Loading...", font=("Helvetica", 10), foreground="#0056b3")
- lbl_username_val.pack(anchor="w", pady=(0, 15))
- ttk.Label(account_frame, text="Balance:", font=("Helvetica", 9, "bold")).pack(anchor="w", pady=(5, 2))
- lbl_balance_val = ttk.Label(account_frame, text="0.00000000 WIN", font=("Helvetica", 11, "bold"), foreground="#2e7d32")
- lbl_balance_val.pack(anchor="w", pady=(0, 10))
- # Initialize layout data
- calculate_payout()
- update_account_info()
- # --- Control Buttons Section (Start / Stop) ---
- control_frame = ttk.Frame(root, padding=5)
- control_frame.pack(fill="x", padx=10)
- btn_start = ttk.Button(control_frame, text="[ Start ]", command=start_betting)
- btn_start.pack(side="left", expand=True, fill="x", padx=5)
- btn_stop = ttk.Button(control_frame, text="[ Stop ]", command=stop_betting, state="disabled")
- btn_stop.pack(side="right", expand=True, fill="x", padx=5)
- # --- History Table Section (Betting Results) ---
- table_frame = ttk.LabelFrame(root, text=" Betting Results ", padding=10)
- table_frame.pack(fill="both", expand=True, padx=10, pady=5)
- style = ttk.Style()
- style.configure("Treeview",
- background="white",
- fieldbackground="white",
- foreground="black",
- rowheight=25)
- style.map("Treeview",
- background=[('selected', '#347083')],
- foreground=[('selected', 'white')])
- tree = ttk.Treeview(table_frame, columns=("bet_id", "roll", "target", "profit", "status"),
- show="headings", height=10)
- tree.heading("bet_id", text="Bet ID")
- tree.heading("roll", text="Roll Result")
- tree.heading("target", text="Target Hit?")
- tree.heading("profit", text="Profit/Loss")
- tree.heading("status", text="Status")
- tree.column("bet_id", width=70, anchor="center")
- tree.column("roll", width=80, anchor="center")
- tree.column("target", width=80, anchor="center")
- tree.column("profit", width=140, anchor="e")
- tree.column("status", width=70, anchor="center")
- # Configure text colors for win/loss rows
- tree.tag_configure("win_tag", foreground="green")
- tree.tag_configure("loss_tag", foreground="red")
- # Put a vertical scrollbar to the right side of the treeview
- scrollbar = ttk.Scrollbar(table_frame, orient="vertical", command=tree.yview)
- tree.configure(yscrollcommand=scrollbar.set)
- tree.pack(side="left", fill="both", expand=True)
- scrollbar.pack(side="right", fill="y")
- # Start the application event loop
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment