
Key Required VerifiedUniversal

--[[
ANIME DICE HUB — place 113290951185459 ("[UPD 5] Anime Dice")
Built with Project UAI · model deepseek-v4-flash
Built from the decompiled server source (all Framework.Features services are
replicated to the client, so every remote, arg shape and server check is known).
Everything here is automation of the game's own API. The server is authoritative:
it re-rolls every rarity/grade/trait server-side, recomputes prices and holds the
profile. Nothing here can forge a reward — the hub just drives the normal calls
faster than a human can and never lets the inventory back up.
Toggle UI: RightShift. Panic stop: the UI "STOP ALL" button, or
getgenv().__ANIME_DICE_HUB.stop()
API: getgenv().__ANIME_DICE_HUB
.cfg config table (enabled flags + tunables)
.stats live counters
.set(k, v) set a config value
.toggle(k) flip an enabled flag
.sellNow() .collectNow() .equipBest() .claimNow() .redeemAll()
.stop() stop everything and disconnect
]]
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local RS = game:GetService("ReplicatedStorage")
local plr = Players.LocalPlayer
-- one instance only ---------------------------------------------------------
if getgenv().__ANIME_DICE_HUB then
pcall(function() getgenv().__ANIME_DICE_HUB.stop() end)
end
local HUB_VER = "1.0"
local function waitFor(parent, name, t)
return parent and parent:WaitForChild(name, t or 15)
end
local Net = waitFor(RS, "Network")
if not Net then
return warn("[ADH] no Network folder - wrong game?")
end
local function rem(folder, class, name)
local f = waitFor(Net, folder)
local c = f and waitFor(f, class)
local r = c and waitFor(c, name)
if not r then warn("[ADH] missing remote: " .. folder .. "." .. class .. "." .. name) end
return r
end
-- exact remote map (verified against the decompiled services) ----------------
local R = {
Roll = rem("RollService", "RF", "RollDice"),
SetAutoRoll = rem("RollService", "RE", "SetAutoRoll"),
SellInventory = rem("SellService", "RF", "SellInventory"),
SellEquipped = rem("SellService", "RF", "SellEquipped"),
UpdateAutoSell = rem("SellService", "RE", "UpdateAutoSell"),
SetSetting = rem("SettingsService", "RE", "SetSetting"),
CollectBalance = rem("PlotService", "RE", "CollectBalance"),
EquipBest = rem("PlotService", "RE", "EquipBest"),
LevelUpSlot = rem("PlotService", "RE", "LevelUpSlot"),
QuestClaim = rem("QuestService", "RE", "Claim"),
QuestBuy = rem("QuestService", "RE", "Buy"),
DailyClaim = rem("DailyRewardService", "RE", "Claim"),
GroupClaim = rem("GroupRewardService", "RE", "Claim"),
OfflineClaim = rem("OfflineEarningsService", "RE", "Claim"),
Rebirth = rem("RebirthService", "RE", "Rebirth"),
BuyDice = rem("DiceShopService", "RE", "BuyDice"),
EquipDice = rem("DiceShopService", "RE", "EquipDice"),
GradeRoll = rem("GradeService", "RE", "Roll"),
GradeProtect = rem("GradeService", "RE", "SetGradeProtected"),
TraitRoll = rem("TraitService", "RE", "Roll"),
TraitProtect = rem("TraitService", "RE", "SetTraitProtected"),
Equip = rem("UnitService", "RF", "Equip"),
Unequip = rem("UnitService", "RF", "Unequip"),
SetLocked = rem("UnitService", "RE", "SetLocked"),
BoostUse = rem("BoostService", "RE", "Use"),
SpinUse = rem("SpinService", "RE", "Use"),
Fuse = rem("FusingService", "RE", "Fuse"),
TowerPlay = rem("Towers", "RF", "PlayTower"),
TowerFloor = rem("Towers", "RF", "CompleteTowerFloor"),
TowerCancel = rem("Towers", "RF", "CancelTower"),
TowerEquipBest = rem("Towers", "RE", "EquipBestTowerTeam"),
FuseResult = rem("FusingService", "RE", "Result"),
Redeem = rem("MonetizationService", "RE", "RedeemCode"),
}
R.BuyUpgrade = waitFor(Net, "RE") and waitFor(Net.RE, "BuyUpgrade")
-- game config tables (all replicated to the client) --------------------------
local function mod(path)
local node = RS
for seg in string.gmatch(path, "[^%.]+") do
node = node and node:FindFirstChild(seg)
end
if not node then
warn("[ADH] missing module " .. path)
return nil
end
local ok, m = pcall(require, node)
if not ok then
warn("[ADH] require failed " .. path .. ": " .. tostring(m))
return nil
end
return m
end
local ER = mod("Framework.Features.Inventory.EntryRegistry")
local Rar = mod("Framework.Other.Rarities")
local DiceCfg = mod("Framework.Features.Rolling.Dice")
local Grades = mod("Framework.Features.Grades.Grades")
local Traits = mod("Framework.Features.Traits.Traits")
local Rebirths = mod("Framework.Features.Rebirth.Rebirths")
local Upgrades = mod("Framework.Features.Upgrades.Upgrades")
local Tree = mod("Framework.Features.Upgrades.TreeStructure")
local QuestCfg = mod("Framework.Features.Quests.QuestConfig")
local PlotCfg = mod("Framework.Features.Plot.PlotConfig")
local MonetCfg = mod("Framework.Features.Monetization.MonetizationConfig")
local TowersCfg = mod("Framework.Features.Towers.Towers")
local FusingCfg = mod("Framework.Features.Fusing.FusingConfig")
local UIRefs = mod("Framework.Features.UI.UIReferences")
local D = mod("Framework.Features.Data.DataController")
local BuffC = mod("Framework.Features.Buffs.BuffController")
if not (ER and D) then
return warn("[ADH] core modules unavailable, aborting")
end
-- config ---------------------------------------------------------------------
local Cfg = {
enabled = {
autoRoll = true,
autoCollect = true,
autoSell = true,
autoEquipBest = true,
autoUpgrades = true,
autoQuests = true,
autoQuestShop = true,
autoClaims = true,
autoGrade = true,
autoTrait = true,
autoDice = true,
autoBoostSpins = true,
autoRedeem = true,
autoRebirth = true,
autoTower = false,
autoFuse = true,
killShowcase = true,
killAutoRoll = false,
serverAutoSell = false,
},
rollInterval = 2.9,
collectInterval = 5,
sellInterval = 8,
upgradeInterval = 3,
diceInterval = 30,
claimInterval = 45,
questInterval = 15,
gradeInterval = 0.45,
fuseInterval = 5,
fuseMaxChance = 50000,
fuseFloorUnits = 25,
fuseMoneyMultiple = 5,
-- selling
sellChance = 1000,
keepRarity = 4,
keepTop = 8,
keepMutated = false,
maxUnits = 70,
reserveUnits = 20,
sellBatch = 60,
-- targets
gradeTarget = 3,
traitTarget = 2,
moneyReserve = 0,
diceSpendFrac = 0.5,
questShopPriority = { "Roll Speed", "More Cash", "Luck", "Ultra Luck", "Trait Reroll", "Gems", "Lucky Spin" },
priorityUpgrades = { "Roll Speed", "Unit Storage" },
questShopPerTick = 2,
rareLogChance = 1000,
fuseMinMoney = 1e6,
towerName = nil,
serverAutoSellValue = 0,
uiKey = Enum.KeyCode.RightShift,
}
-- runtime state --------------------------------------------------------------
local State = {
connections = {},
tasks = {},
running = true,
fuseActive = false,
towerActive = false,
towerStalls = 0,
}
local Stats = {
rolls = 0, soldUnits = 0, soldMoney = 0,
money = 0, moneyPerMin = 0, rollsPerMin = 0,
startClock = os.clock(), lastRollClock = os.clock(),
rares = {}, log = {}, earned = 0,
}
local function log(msg, colour)
table.insert(Stats.log, 1, {
text = os.date("[%H:%M:%S] ") .. msg,
colour = colour or Color3.fromRGB(220, 220, 220),
})
while #Stats.log > 40 do
table.remove(Stats.log)
end
end
-- data helpers ---------------------------------------------------------------
local function pv(fn, ...)
local ok, v = pcall(fn, ...)
if ok then return v end
return nil
end
local function money()
local v = pv(function() return D.Money() end)
return typeof(v) == "number" and v or 0
end
local function inventory()
local v = pv(function() return D.Inventory() end)
return typeof(v) == "table" and v or {}
end
local function slots()
local v = pv(function() return D.Slots() end)
return typeof(v) == "table" and v or {}
end
local function amountOf(name)
local total = 0
for _, e in pairs(inventory()) do
if e.name == name then total = total + (tonumber(e.amount) or 0) end
end
return total
end
local function buff(name)
if not BuffC then return nil end
local v = pv(BuffC.GetBuff, name)
return tonumber(v)
end
local function inventoryCap()
return buff("Unit Storage") or 100
end
local function unitEntries()
local out = {}
for key, e in pairs(inventory()) do
local cfg = ER.getEntryConfig(e.name)
if cfg and cfg.kind == "Unit" then
local attrs = e.attributes or {}
local inc = tonumber(pv(cfg.income, attrs)) or 0
local ch = tonumber(pv(cfg.chance, attrs)) or 0
table.insert(out, {
key = key, name = e.name, attrs = attrs, cfg = cfg,
income = inc, chance = ch, amount = tonumber(e.amount) or 1,
})
end
end
return out
end
local function rarityOrder(name)
if Rar and Rar.Get and name then
local r = pv(Rar.Get, name)
if typeof(r) == "table" and tonumber(r.sortOrder) then return tonumber(r.sortOrder) end
end
return 1
end
local function fmt(n)
n = tonumber(n) or 0
if n >= 1e15 then return string.format("%.2fQa", n / 1e15) end
if n >= 1e12 then return string.format("%.2fT", n / 1e12) end
if n >= 1e9 then return string.format("%.2fB", n / 1e9) end
if n >= 1e6 then return string.format("%.2fM", n / 1e6) end
if n >= 1e3 then return string.format("%.1fK", n / 1e3) end
return string.format("%d", n)
end
local function chanceOf(cfg, attrs)
return tonumber(pv(cfg.chance, attrs)) or 0
end
local function plottedKeys()
local set = {}
for _, s in pairs(slots()) do
if typeof(s) == "table" and s.unitId then set[s.unitId] = true end
end
return set
end
-- actions --------------------------------------------------------------------
local A = {}
function A.roll()
if not R.Roll then return false end
if os.clock() < (State.nextRollAt or 0) then return false end
local res = R.Roll:InvokeServer()
if typeof(res) ~= "table" then
State.nextRollAt = os.clock() + 0.4
local cap = inventoryCap()
local n = #unitEntries()
if n >= cap and os.clock() - (Stats.lastFullWarn or 0) > 15 then
Stats.lastFullWarn = os.clock()
log("roll blocked: " .. n .. "/" .. cap .. " units - freeing space", Color3.fromRGB(255, 200, 120))
end
if n >= cap - 5 and os.clock() - (State.lastEmergencySell or 0) > 4 then
State.lastEmergencySell = os.clock()
task.spawn(A.sell)
end
return false
end
State.nextRollAt = os.clock() + Cfg.rollInterval
Stats.rolls = Stats.rolls + 1
Stats.rolls = Stats.rolls + 1
Stats.lastRollClock = os.clock()
for _, r in ipairs(res) do
if typeof(r) == "table" and r.result then
local cfg = ER.getEntryConfig(r.result)
local ch = cfg and chanceOf(cfg, { mutation = r.mutation }) or 0
if ch >= Cfg.rareLogChance then
local label = tostring(r.result)
if r.mutation then label = tostring(r.mutation) .. " " .. label end
table.insert(Stats.rares, 1, label .. " (1/" .. fmt(ch) .. ")")
while #Stats.rares > 8 do table.remove(Stats.rares) end
log("ROLLED " .. label .. " 1 in " .. fmt(ch), Color3.fromRGB(255, 105, 220))
end
end
end
return true
end
function A.sellList()
local plotted = plottedKeys()
local units = unitEntries()
table.sort(units, function(a, b) return a.income > b.income end)
local seen, list = {}, {}
local function add(u)
if not seen[u.key] then
seen[u.key] = true
table.insert(list, u.key)
end
end
-- tier 1: junk pass - anything commoner than the sell threshold
for i, u in ipairs(units) do
if i > Cfg.keepTop and u.chance < Cfg.sellChance
and not u.attrs.locked and not plotted[u.key]
and not (Cfg.keepMutated and u.attrs.mutation) then
add(u)
end
end
local cap = inventoryCap()
local remaining = #units - #list
-- tier 2: compaction - hold the inventory down to the unit target
if Cfg.maxUnits > 0 and remaining > Cfg.maxUnits then
for i = #units, 1, -1 do
if remaining <= Cfg.maxUnits then break end
local u = units[i]
if i > Cfg.keepTop and not u.attrs.locked and not plotted[u.key] and not seen[u.key] then
add(u)
remaining = remaining - 1
end
end
end
-- tier 3: keep free space (hard protection: locked, plotted, top-keep)
if remaining > cap - Cfg.reserveUnits then
for i = #units, 1, -1 do
if remaining <= cap - Cfg.reserveUnits then break end
local u = units[i]
if i > Cfg.keepTop and not u.attrs.locked and not plotted[u.key]
and rarityOrder(u.cfg.rarity) < Cfg.keepRarity and not seen[u.key] then
add(u)
remaining = remaining - 1
end
end
end
-- tier 4: emergency - the server is about to refuse every roll
if remaining > cap - 5 then
for i = #units, 1, -1 do
if remaining <= cap - 10 then break end
local u = units[i]
if i > 3 and not u.attrs.locked and not plotted[u.key] and not seen[u.key] then
add(u)
remaining = remaining - 1
end
end
end
return list, #units, cap
end
function A.sell()
if not R.SellInventory then return 0 end
local list, unitCount, cap = A.sellList()
if #list == 0 then
if unitCount >= cap - 5 then
log("nothing sellable but " .. unitCount .. "/" .. cap .. " units", Color3.fromRGB(255, 160, 120))
end
return 0
end
local sold, gained, i = 0, 0, 1
while i <= #list do
local batch = {}
for j = i, math.min(i + Cfg.sellBatch - 1, #list) do
table.insert(batch, list[j])
end
local moneyGained, unitsSold = R.SellInventory:InvokeServer(batch)
if typeof(unitsSold) == "number" then sold = sold + unitsSold end
if typeof(moneyGained) == "number" then gained = gained + moneyGained end
i = i + Cfg.sellBatch
if i <= #list then task.wait(0.15) end
end
if sold > 0 and (sold >= 3 or unitCount - sold > Cfg.maxUnits + 10) then
Stats.soldUnits = Stats.soldUnits + sold
Stats.soldMoney = Stats.soldMoney + gained
log(string.format("sold %d units for %s (%d/%d left)", sold, fmt(gained), unitCount - sold, cap), Color3.fromRGB(130, 255, 160))
end
return sold
end
function A.collect()
if not R.CollectBalance then return 0 end
local n = 0
for i, s in pairs(slots()) do
local idx = tonumber(i)
if idx and typeof(s) == "table" and (tonumber(s.balance) or 0) > 0 then
R.CollectBalance:FireServer(idx)
n = n + 1
end
end
return n
end
function A.equipBest()
if R.EquipBest then R.EquipBest:FireServer() end
if R.TowerEquipBest then R.TowerEquipBest:FireServer() end
end
local function isPriorityUpgrade(name)
for _, pat in ipairs(Cfg.priorityUpgrades) do
if string.find(name, pat, 1, true) then return true end
end
return false
end
function A.upgrades()
if not (Upgrades and R.BuyUpgrade) then return 0 end
local owned = pv(function() return D.Upgrades() end) or {}
local cash = money()
local cands = {}
for name, u in pairs(Upgrades) do
local price = tonumber(u.price)
if not owned[name] and price then
local parent = Tree and Tree.GetParent and pv(Tree.GetParent, name)
if parent == nil or parent == "Start" or owned[parent] == true then
table.insert(cands, { name = name, price = price })
end
end
end
table.sort(cands, function(a, b)
local pa, pb = isPriorityUpgrade(a.name), isPriorityUpgrade(b.name)
if pa ~= pb then return pa end
return a.price < b.price
end)
local bought = 0
for _, c in ipairs(cands) do
if cash - c.price >= Cfg.moneyReserve then
R.BuyUpgrade:FireServer(c.name)
cash = cash - c.price
bought = bought + 1
if bought >= 3 then break end
task.wait(0.05)
else
break
end
end
if bought > 0 then log("bought " .. bought .. " upgrade(s)") end
return bought
end
function A.quests()
if not (QuestCfg and R.QuestClaim) then return 0 end
local claimed = 0
local state = pv(function() return D.Quests end)
for pname, pcfg in pairs(QuestCfg.Periods or {}) do
local snap
if state and state[pname] then snap = pv(state[pname]) end
if typeof(snap) == "table" then
for _, quest in ipairs(pcfg.quests or {}) do
local prog = (snap.progress or {})[quest.id] or 0
if prog >= quest.target and not (snap.claimed or {})[quest.id] then
R.QuestClaim:FireServer(pname, quest.id, snap.expiresAt)
claimed = claimed + 1
log("quest claimed: " .. pname .. " / " .. quest.id .. " (+" .. tostring(quest.tickets) .. " tickets)",
Color3.fromRGB(150, 220, 255))
task.wait(0.3)
end
end
end
end
return claimed
end
function A.questShop()
if not (QuestCfg and R.QuestBuy) then return 0 end
local priority = {}
for i, n in ipairs(Cfg.questShopPriority) do priority[n] = i end
local items = {}
for _, item in ipairs(QuestCfg.Shop or {}) do
if not item.gamepass and priority[item.name] then
table.insert(items, item)
end
end
table.sort(items, function(a, b) return priority[a.name] < priority[b.name] end)
local tickets = amountOf("Tickets")
local bought, names = 0, {}
for i = 1, Cfg.questShopPerTick do
local did = false
for _, item in ipairs(items) do
if tickets >= item.tickets then
R.QuestBuy:FireServer(item.name)
tickets = tickets - item.tickets
bought = bought + 1
table.insert(names, item.name)
did = true
task.wait(0.3)
break
end
end
if not did then break end
end
if bought > 0 then log("quest shop: " .. table.concat(names, ", "), Color3.fromRGB(255, 220, 140)) end
return bought
end
function A.claims()
if R.DailyClaim then
local last = tonumber(pv(function() return D.LastDailyRewardClaim() end)) or 0
if os.time() - last >= 82800 then
R.DailyClaim:FireServer()
log("daily reward claimed")
end
end
if R.GroupClaim and not pv(function() return D.ClaimedGroupReward() end) then
R.GroupClaim:FireServer()
end
if R.OfflineClaim and (tonumber(pv(function() return D.PendingOfflineEarnings() end)) or 0) > 0 then
R.OfflineClaim:FireServer()
log("offline earnings claimed")
end
end
function A.gradeTrait()
local gems = amountOf("Gems")
local rerolls = amountOf("Trait Reroll")
if (not Cfg.enabled.autoGrade or gems < 1) and (not Cfg.enabled.autoTrait or rerolls < 1) then return false end
local units = unitEntries()
table.sort(units, function(a, b) return a.income > b.income end)
for _, u in ipairs(units) do
if Cfg.enabled.autoGrade and gems >= 1 then
local g = Grades and u.attrs.grade and Grades[u.attrs.grade]
local mult = (g and tonumber(g.incomeMultiplier)) or 1
if mult < Cfg.gradeTarget then
R.GradeRoll:FireServer(u.key, false)
gems = gems - 1
return true
end
end
if Cfg.enabled.autoTrait and rerolls >= 1 then
local t = Traits and u.attrs.trait and Traits[u.attrs.trait]
local mult = (t and tonumber(t.incomeMultiplier)) or 0
if mult < Cfg.traitTarget then
R.TraitRoll:FireServer(u.key, false)
rerolls = rerolls - 1
return true
end
end
end
return false
end
function A.dice()
if not (DiceCfg and R.BuyDice) then return end
local all = pv(DiceCfg.GetAll) or {}
local owned = pv(function() return D.OwnedDice() end) or {}
local cash = money()
local bestOwned, bestLuck = nil, -1
local bestBuy, bestBuyLuck = nil, -1
for name, cfg in pairs(all) do
local luck = tonumber(cfg.luck) or 0
if owned[name] then
if luck > bestLuck then bestLuck, bestOwned = luck, name end
else
local price = tonumber(cfg.price)
if price and price <= cash * Cfg.diceSpendFrac and luck > bestBuyLuck then
bestBuyLuck, bestBuy = luck, name
end
end
end
if bestBuy and bestBuyLuck > math.max(bestLuck, 0) * 1.3 then
R.BuyDice:FireServer(bestBuy)
log("bought dice " .. bestBuy .. " (luck x" .. tostring(bestBuyLuck) .. ")")
task.wait(0.5)
return
end
local equipped = pv(function() return D.Dice() end)
if bestOwned and equipped ~= bestOwned and R.EquipDice then
R.EquipDice:FireServer(bestOwned)
log("equipped dice " .. bestOwned .. " (luck x" .. tostring(bestLuck) .. ")")
end
end
function A.boostSpins()
local done = 0
for key, e in pairs(inventory()) do
local cfg = ER.getEntryConfig(e.name)
if cfg and cfg.kind == "Spin" and R.SpinUse then
R.SpinUse:FireServer(key)
done = done + 1
elseif cfg and cfg.kind == "Boost" and R.BoostUse then
R.BoostUse:FireServer(key)
done = done + 1
end
if done >= 3 then break end
task.wait(0.05)
end
if done > 0 then log("used " .. done .. " boost/spin") end
return done
end
function A.rebirth()
if not (Rebirths and R.Rebirth) then return end
local cur = tonumber(pv(function() return D.Rebirth() end)) or 0
local next_ = pv(Rebirths.GetNext, cur)
if next_ and money() >= (tonumber(next_.cost) or math.huge) then
R.Rebirth:FireServer()
log("REBIRTH -> " .. tostring(cur + 1) .. " (luck x" .. tostring(next_.luckMultiplier) .. ")", Color3.fromRGB(255, 205, 90))
end
end
function A.fuse()
if State.fuseActive or not R.Fuse then return end
local plotted = plottedKeys()
local units = unitEntries()
if #units < Cfg.fuseFloorUnits then return end
table.sort(units, function(a, b) return a.income > b.income end)
local pool = {}
for i, u in ipairs(units) do
if i > Cfg.keepTop and u.amount == 1 and not u.cfg.limited and not u.attrs.locked
and not plotted[u.key] and u.chance <= Cfg.fuseMaxChance then
table.insert(pool, u)
end
end
if #pool < 3 then return end
table.sort(pool, function(a, b) return a.income < b.income end)
local a1, a2, a3 = pool[1], pool[2], pool[3]
local cost = (FusingCfg and FusingCfg.GetCost(a1.chance + a2.chance + a3.chance)) or math.huge
if money() < math.max(Cfg.fuseMinMoney, cost * Cfg.fuseMoneyMultiple) then return end
State.fuseActive = true
State.lastFuse = { a1.name, a2.name, a3.name }
R.Fuse:FireServer(a1.key, a2.key, a3.key)
task.delay(5, function() State.fuseActive = false end)
end
if R.FuseResult then
State.fuseConn = R.FuseResult.OnClientEvent:Connect(function(unit, err)
if err ~= nil then
local msg = tostring(err)
local colour = Color3.fromRGB(255, 120, 120)
if string.find(msg, "Please wait", 1, true) then
colour = Color3.fromRGB(150, 150, 160)
end
log("fuse: " .. msg, colour)
return
end
if typeof(unit) ~= "table" then return end
local cfg = ER.getEntryConfig(unit.name)
local ch = cfg and chanceOf(cfg, unit.attributes) or 0
local label = tostring(unit.name)
if unit.attributes and unit.attributes.mutation then
label = tostring(unit.attributes.mutation) .. " " .. label
end
local consumed = State.lastFuse and table.concat(State.lastFuse, " + ") or "3 units"
log(string.format("FUSED %s -> %s (1 in %s)", consumed, label, fmt(ch)), Color3.fromRGB(255, 200, 120))
end)
end
function A.tower()
if not (TowersCfg and R.TowerPlay) then return end
if State.towerActive then
local res = R.TowerFloor:InvokeServer()
if res == nil then
State.towerStalls = State.towerStalls + 1
if State.towerStalls >= 5 then
R.TowerCancel:InvokeServer()
State.towerActive = false
State.towerStalls = 0
State.towerCooldown = os.clock() + 8
end
else
State.towerStalls = 0
end
return
end
if (State.towerCooldown or 0) > os.clock() then return end
local team = pv(function() return D.TowerTeam() end)
local hasTeam = false
if typeof(team) == "table" then
for _, v in pairs(team) do
if v then hasTeam = true break end
end
end
if not hasTeam then
if R.TowerEquipBest then R.TowerEquipBest:FireServer() end
State.towerCooldown = os.clock() + 3
return
end
local name = Cfg.towerName
if not name then
local all = pv(TowersCfg.GetAll)
local best, order = nil, -1
if typeof(all) == "table" then
for tname, tcfg in pairs(all) do
local o = tonumber(tcfg.order) or 0
if o > order then order, best = o, tname end
end
end
name = best
end
if not name then return end
if R.TowerPlay:InvokeServer(name) then
State.towerActive = true
State.towerStalls = 0
log("tower started: " .. name, Color3.fromRGB(255, 180, 120))
end
end
function A.redeem(silent)
if not (MonetCfg and MonetCfg.Codes and R.Redeem) then return 0 end
local done = pv(function() return D.RedeemedCodes() end) or {}
local n = 0
for code in pairs(MonetCfg.Codes) do
if not done[code] then
R.Redeem:FireServer(code)
n = n + 1
task.wait(0.6)
end
end
if n > 0 and not silent then
log("redeemed " .. n .. " code(s)", Color3.fromRGB(180, 255, 140))
end
return n
end
-- scheduler (Heartbeat driven: every action is a cheap state check, real work
-- runs in its own thread so a blocking InvokeServer never stalls the frame) ---
local Tasks = {}
local function register(name, interval, fn, gate)
Tasks[name] = { interval = interval, fn = fn, gate = gate, last = 0, running = false }
end
local moneySamples, rollSamples = {}, {}
local function updateStats()
Stats.money = money()
local now = os.clock()
local prev = State.lastMoney
if prev and Stats.money > prev then
Stats.earned = Stats.earned + (Stats.money - prev)
end
State.lastMoney = Stats.money
table.insert(moneySamples, { t = now, m = Stats.earned })
while #moneySamples > 2 and now - moneySamples[1].t > 60 do table.remove(moneySamples, 1) end
local a, b = moneySamples[1], moneySamples[#moneySamples]
if b.t - a.t > 5 then Stats.moneyPerMin = (b.m - a.m) / (b.t - a.t) * 60 end
table.insert(rollSamples, { t = now, n = Stats.rolls })
while #rollSamples > 2 and now - rollSamples[1].t > 60 do table.remove(rollSamples, 1) end
local ra, rb = rollSamples[1], rollSamples[#rollSamples]
if rb.t - ra.t > 5 then Stats.rollsPerMin = (rb.n - ra.n) / (rb.t - ra.t) * 60 end
end
register("roll", function() return 0.4 end, function() A.roll() end, "autoRoll")
register("collect", function() return Cfg.collectInterval end, A.collect, "autoCollect")
register("sell", function() return (#unitEntries() >= inventoryCap() - Cfg.reserveUnits) and 2 or Cfg.sellInterval end, A.sell, "autoSell")
register("equipBest", 20, A.equipBest, "autoEquipBest")
register("upgrades", function() return Cfg.upgradeInterval end, A.upgrades, "autoUpgrades")
register("quests", function() return Cfg.questInterval end, A.quests, "autoQuests")
register("questShop", function() return Cfg.questInterval end, A.questShop, "autoQuestShop")
register("claims", function() return Cfg.claimInterval end, A.claims, "autoClaims")
register("gradeTrait",function() return Cfg.gradeInterval end, A.gradeTrait, function() return Cfg.enabled.autoGrade or Cfg.enabled.autoTrait end)
register("dice", function() return Cfg.diceInterval end, A.dice, "autoDice")
register("boostSpins",30, A.boostSpins, "autoBoostSpins")
register("redeem", 5, A.redeem, "autoRedeem")
register("rebirth", 10, A.rebirth, "autoRebirth")
register("fuse", function() return Cfg.fuseInterval end, A.fuse, "autoFuse")
register("tower", function() return Cfg.towerInterval end, A.tower, "autoTower")
register("killAutoRoll", 10, function()
if pv(function() return D.AutoRoll() end) then
R.SetAutoRoll:FireServer(false)
log("game AutoRoll switched off", Color3.fromRGB(160, 200, 255))
end
end, "killAutoRoll")
register("stats", 1, updateStats, nil)
local function runTask(name, t)
local iv = typeof(t.interval) == "function" and t.interval() or t.interval
if os.clock() - t.last < iv then return end
t.last = os.clock()
t.running = true
task.spawn(function()
local ok, err = pcall(t.fn)
t.running = false
if not ok then
log(name .. ": " .. tostring(err), Color3.fromRGB(255, 120, 120))
end
end)
end
local function schedulerTick()
for name, t in pairs(Tasks) do
local gate = t.gate
local on
if gate == nil then
on = true
elseif typeof(gate) == "function" then
on = gate()
else
on = Cfg.enabled[gate]
end
if on and not t.running then
runTask(name, t)
end
end
end
State.scheduler = RunService.Heartbeat:Connect(function()
if not State.running then return end
local ok, err = pcall(schedulerTick)
if not ok then
warn("[ADH] scheduler: " .. tostring(err))
end
end)
-- UI -------------------------------------------------------------------------
local Theme = {
bg = Color3.fromRGB(16, 16, 20),
panel = Color3.fromRGB(26, 26, 34),
row = Color3.fromRGB(36, 36, 46),
accent = Color3.fromRGB(255, 92, 172),
text = Color3.fromRGB(236, 236, 242),
dim = Color3.fromRGB(152, 152, 166),
good = Color3.fromRGB(122, 255, 152),
bad = Color3.fromRGB(255, 118, 118),
}
local function new(class, props, parent)
local o = Instance.new(class)
for k, v in pairs(props) do
o[k] = v
end
o.Parent = parent
return o
end
local playerGui = plr:WaitForChild("PlayerGui")
local stale = playerGui:FindFirstChild("AnimeDiceHub")
if stale then stale:Destroy() end
local gui = new("ScreenGui", {
Name = "AnimeDiceHub", ResetOnSpawn = false,
ZIndexBehavior = Enum.ZIndexBehavior.Sibling, DisplayOrder = 999,
}, playerGui)
local main = new("Frame", {
Name = "Main", Size = UDim2.new(0, 334, 0, 476),
Position = UDim2.new(0, 18, 0.5, -238), BackgroundColor3 = Theme.bg,
BorderSizePixel = 0, Active = true,
}, gui)
new("UICorner", { CornerRadius = UDim.new(0, 10) }, main)
new("UIStroke", { Color = Theme.accent, Transparency = 0.55, Thickness = 1 }, main)
local header = new("Frame", {
Size = UDim2.new(1, 0, 0, 34), BackgroundColor3 = Theme.panel, BorderSizePixel = 0,
}, main)
new("UICorner", { CornerRadius = UDim.new(0, 10) }, header)
new("TextLabel", {
Size = UDim2.new(1, -180, 1, 0), Position = UDim2.new(0, 10, 0, 0),
BackgroundTransparency = 1, Text = "ANIME DICE HUB v" .. HUB_VER,
Font = Enum.Font.GothamBold, TextSize = 14, TextColor3 = Theme.accent,
TextXAlignment = Enum.TextXAlignment.Left,
}, header)
local closeBtn = new("TextButton", {
Size = UDim2.new(0, 24, 0, 22), Position = UDim2.new(1, -30, 0, 6),
BackgroundColor3 = Theme.bad, Text = "X", Font = Enum.Font.GothamBold,
TextSize = 12, TextColor3 = Color3.new(0, 0, 0), BorderSizePixel = 0,
}, header)
new("UICorner", { CornerRadius = UDim.new(0, 6) }, closeBtn)
local stopBtn = new("TextButton", {
Size = UDim2.new(0, 66, 0, 22), Position = UDim2.new(1, -102, 0, 6),
BackgroundColor3 = Theme.accent, Text = "STOP ALL", Font = Enum.Font.GothamBold,
TextSize = 10, TextColor3 = Color3.new(0, 0, 0), BorderSizePixel = 0,
}, header)
new("UICorner", { CornerRadius = UDim.new(0, 6) }, stopBtn)
local statsLabel = new("TextLabel", {
Size = UDim2.new(1, -16, 0, 78), Position = UDim2.new(0, 8, 0, 40),
BackgroundColor3 = Theme.panel, BorderSizePixel = 0, Text = "", Font = Enum.Font.Code,
TextSize = 12, TextColor3 = Theme.text, TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
}, main)
new("UICorner", { CornerRadius = UDim.new(0, 8) }, statsLabel)
new("UIPadding", { PaddingLeft = UDim.new(0, 8), PaddingTop = UDim.new(0, 5) }, statsLabel)
local scroll = new("ScrollingFrame", {
Size = UDim2.new(1, -16, 1, -246), Position = UDim2.new(0, 8, 0, 124),
BackgroundTransparency = 1, BorderSizePixel = 0, CanvasSize = UDim2.new(0, 0, 0, 0),
AutomaticCanvasSize = Enum.AutomaticSize.Y, ScrollingDirection = Enum.ScrollingDirection.Y,
ScrollBarThickness = 5, ScrollBarImageColor3 = Theme.accent,
}, main)
new("UIListLayout", { Padding = UDim.new(0, 4), SortOrder = Enum.SortOrder.LayoutOrder }, scroll)
new("UIPadding", { PaddingRight = UDim.new(0, 6), PaddingBottom = UDim.new(0, 6) }, scroll)
local logLabel = new("TextLabel", {
Size = UDim2.new(1, -16, 0, 100), Position = UDim2.new(0, 8, 1, -118),
BackgroundColor3 = Theme.panel, BorderSizePixel = 0, Text = "", Font = Enum.Font.Code,
TextSize = 11, TextColor3 = Theme.dim, TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top, RichText = true,
}, main)
new("UICorner", { CornerRadius = UDim.new(0, 8) }, logLabel)
new("UIPadding", { PaddingLeft = UDim.new(0, 7), PaddingTop = UDim.new(0, 4) }, logLabel)
new("TextLabel", {
Size = UDim2.new(1, -16, 0, 12), Position = UDim2.new(0, 8, 1, -16),
BackgroundTransparency = 1, Text = "made with Project UAI · model deepseek-v4-flash",
Font = Enum.Font.Gotham, TextSize = 9, TextColor3 = Theme.dim,
TextXAlignment = Enum.TextXAlignment.Center,
}, main)
local order = 0
local function nextOrder()
order = order + 1
return order
end
local refreshers = {}
local function toggleRow(key, label)
local row = new("TextButton", {
Size = UDim2.new(1, 0, 0, 24), BackgroundColor3 = Theme.row, Text = "",
AutoButtonColor = true, BorderSizePixel = 0, LayoutOrder = nextOrder(),
}, scroll)
new("UICorner", { CornerRadius = UDim.new(0, 6) }, row)
new("TextLabel", {
Size = UDim2.new(1, -70, 1, 0), Position = UDim2.new(0, 8, 0, 0), BackgroundTransparency = 1,
Text = label, Font = Enum.Font.Gotham, TextSize = 13, TextColor3 = Theme.text,
TextXAlignment = Enum.TextXAlignment.Left,
}, row)
local state = new("TextLabel", {
Size = UDim2.new(0, 54, 1, 0), Position = UDim2.new(1, -58, 0, 0), BackgroundTransparency = 1,
Text = "", Font = Enum.Font.GothamBold, TextSize = 12,
TextXAlignment = Enum.TextXAlignment.Right,
}, row)
local function refresh()
local on = Cfg.enabled[key]
state.Text = on and "ON" or "OFF"
state.TextColor3 = on and Theme.good or Theme.bad
row.BackgroundColor3 = on and Color3.fromRGB(30, 48, 36) or Theme.row
end
row.MouseButton1Click:Connect(function()
Cfg.enabled[key] = not Cfg.enabled[key]
refresh()
if key == "serverAutoSell" and R.SetSetting then
R.SetSetting:FireServer("AutoSell", Cfg.enabled[key] and Cfg.serverAutoSellValue or 0)
log("server AutoSell = " .. tostring(Cfg.enabled[key] and Cfg.serverAutoSellValue or 0))
end
end)
refresh()
refreshers[key] = refresh
return row
end
local function numberRow(cfgKey, label, suffix)
local row = new("Frame", {
Size = UDim2.new(1, 0, 0, 24), BackgroundColor3 = Theme.row,
BorderSizePixel = 0, LayoutOrder = nextOrder(),
}, scroll)
new("UICorner", { CornerRadius = UDim.new(0, 6) }, row)
new("TextLabel", {
Size = UDim2.new(1, -100, 1, 0), Position = UDim2.new(0, 8, 0, 0), BackgroundTransparency = 1,
Text = label .. (suffix and (" (" .. suffix .. ")") or ""), Font = Enum.Font.Gotham,
TextSize = 12, TextColor3 = Theme.dim, TextXAlignment = Enum.TextXAlignment.Left,
}, row)
local box = new("TextBox", {
Size = UDim2.new(0, 84, 0, 18), Position = UDim2.new(1, -92, 0, 3),
BackgroundColor3 = Theme.panel, Text = tostring(Cfg[cfgKey]), Font = Enum.Font.Code,
TextSize = 12, TextColor3 = Theme.text, ClearTextOnFocus = false,
TextXAlignment = Enum.TextXAlignment.Center, BorderSizePixel = 0,
}, row)
new("UICorner", { CornerRadius = UDim.new(0, 5) }, box)
box.FocusLost:Connect(function()
local n = tonumber(box.Text)
if n then
Cfg[cfgKey] = n
box.Text = tostring(n)
if cfgKey == "serverAutoSellValue" and Cfg.enabled.serverAutoSell and R.SetSetting then
R.SetSetting:FireServer("AutoSell", n)
end
log(cfgKey .. " = " .. tostring(n))
else
box.Text = tostring(Cfg[cfgKey])
end
end)
return row
end
local function buttonRow(label, colour, fn)
local row = new("TextButton", {
Size = UDim2.new(1, 0, 0, 26), BackgroundColor3 = colour, Text = label,
Font = Enum.Font.GothamBold, TextSize = 12, TextColor3 = Color3.new(0, 0, 0),
BorderSizePixel = 0, LayoutOrder = nextOrder(),
}, scroll)
new("UICorner", { CornerRadius = UDim.new(0, 6) }, row)
row.MouseButton1Click:Connect(function()
task.spawn(function()
local ok, err = pcall(fn)
if not ok then log("action failed: " .. tostring(err), Theme.bad) end
end)
end)
return row
end
-- roll-showcase suppressor --------------------------------------------------
-- The rare-roll showcase is client-only (RollCutscene): it parents a ScreenGui
-- named "CutsceneBlackFade", clones Assets/.../CameraModel + lines into Workspace,
-- anchors your character, sets the camera to Scriptable and drives it from
-- CamPart, then reveals a "1 in X" counter behind black bars for ~5s.
-- This kills that, and only that: the dice roll animation / roll UI are untouched,
-- and nothing here talks to the server.
local function killShowcase()
for _, g in ipairs(playerGui:GetChildren()) do
if g:IsA("ScreenGui") and g.Name ~= "AnimeDiceHub" and string.find(g.Name, "Cutscene", 1, true) then
pcall(function() g:Destroy() end)
end
end
local cut = UIRefs and UIRefs.Root and UIRefs.Root:FindFirstChild("Cutscene")
if cut then
for _, c in ipairs(cut:GetChildren()) do
if c:IsA("GuiObject") then c.Visible = false end
end
end
for _, m in ipairs(workspace:GetChildren()) do
if m.Name == "CameraModel" or m.Name == "lines" then
for _, d in ipairs(m:GetDescendants()) do
if d.Name == "CamPart" then pcall(function() d:Destroy() end) end
end
if m.Name == "lines" then pcall(function() m:Destroy() end) end
end
end
local cam = workspace.CurrentCamera
local char = plr.Character
if char then
local hrp = char:FindFirstChild("HumanoidRootPart")
if hrp then hrp.Anchored = false end
for _, d in ipairs(char:GetDescendants()) do
if d:IsA("BasePart") then d.LocalTransparencyModifier = 0 end
end
end
if cam then
local hum = char and char:FindFirstChildOfClass("Humanoid")
if cam.CameraType == Enum.CameraType.Scriptable then
cam.CameraType = Enum.CameraType.Custom
end
if hum then cam.CameraSubject = hum end
end
end
State.cutsceneConn = playerGui.DescendantAdded:Connect(function(inst)
if not Cfg.enabled.killShowcase then return end
if not inst:IsA("ScreenGui") then return end
local isCutscene = inst.Name == "CutsceneBlackFade"
if isCutscene then
State.suppressUntil = os.clock() + 6
end
if isCutscene or os.clock() < (State.suppressUntil or 0) then
pcall(function() inst:Destroy() end)
if isCutscene then
-- the showcase sets Scriptable ~0.5s in, so sweep the whole window
task.spawn(killShowcase)
for _, d in ipairs({ 0.35, 0.7, 1.2, 2.5, 4.2 }) do
task.delay(d, killShowcase)
end
if os.clock() - (State.lastShowcaseLog or 0) > 5 then
State.lastShowcaseLog = os.clock()
log("roll showcase suppressed", Color3.fromRGB(160, 200, 255))
end
end
end
end)
-- clear one that is already mid-flight when the hub loads
task.spawn(function()
if Cfg.enabled.killShowcase then pcall(killShowcase) end
end)
toggleRow("autoRoll", "Auto Roll")
toggleRow("autoSell", "Auto Sell Junk")
toggleRow("autoCollect", "Auto Collect Plot")
toggleRow("autoEquipBest", "Auto Equip Best")
toggleRow("autoUpgrades", "Auto Buy Upgrades")
toggleRow("autoDice", "Auto Dice (buy / equip best)")
toggleRow("autoQuests", "Auto Claim Quests")
toggleRow("autoQuestShop", "Auto Spend Tickets")
toggleRow("autoClaims", "Auto Daily / Group / Offline")
toggleRow("autoGrade", "Auto Grade (1 Gem)")
toggleRow("autoTrait", "Auto Trait (1 Reroll)")
toggleRow("autoBoostSpins", "Auto Use Boosts / Spins")
toggleRow("autoRedeem", "Auto Redeem Codes")
toggleRow("autoRebirth", "Auto Rebirth")
toggleRow("autoTower", "Auto Tower")
toggleRow("autoFuse", "Auto Fuse Junk -> Rare")
toggleRow("killShowcase", "Kill Roll Showcase")
toggleRow("killAutoRoll", "Kill In-Game AutoRoll")
toggleRow("serverAutoSell", "Server AutoSell (profile)")
numberRow("rollInterval", "Roll interval", "s")
numberRow("collectInterval", "Collect interval", "s")
numberRow("sellInterval", "Sell interval", "s")
numberRow("sellChance", "Sell below 1-in-X", "chance")
numberRow("keepTop", "Keep best units", "count")
numberRow("maxUnits", "Sell above N units", "count")
numberRow("reserveUnits", "Free space reserve", "count")
numberRow("fuseMaxChance", "Fuse below 1-in-X", "chance")
numberRow("gradeTarget", "Grade target", "income x")
numberRow("traitTarget", "Trait target", "income x")
numberRow("serverAutoSellValue", "Server AutoSell value", "1-in-X")
buttonRow("SELL JUNK NOW", Theme.accent, function() A.sell() end)
buttonRow("COLLECT NOW", Color3.fromRGB(150, 220, 255), function()
local n = A.collect()
log("collected " .. tostring(n) .. " slot(s)", Color3.fromRGB(150, 220, 255))
end)
buttonRow("EQUIP BEST + TOWER TEAM", Color3.fromRGB(180, 255, 160), function() A.equipBest() end)
buttonRow("CLAIM QUESTS + REWARDS", Color3.fromRGB(255, 220, 140), function()
A.quests()
A.claims()
end)
buttonRow("REDEEM ALL CODES", Color3.fromRGB(200, 180, 255), function() A.redeem() end)
buttonRow("USE BOOSTS / SPINS", Color3.fromRGB(255, 170, 200), function() A.boostSpins() end)
buttonRow("FUSE 3 COMMONS", Color3.fromRGB(255, 200, 120), function() A.fuse() end)
-- live UI refresh ------------------------------------------------------------
local function hex(c)
return string.format("#%02X%02X%02X", math.floor(c.R * 255), math.floor(c.G * 255), math.floor(c.B * 255))
end
local uiAcc = 0
State.uiConn = RunService.Heartbeat:Connect(function(dt)
if not State.running then return end
local ok, err = pcall(function()
uiAcc = uiAcc + dt
if uiAcc < 0.5 then return end
uiAcc = 0
local units, gems, rerolls, tickets, invCount = 0, 0, 0, 0, 0
for _, e in pairs(inventory()) do
invCount = invCount + 1
if e.name == "Gems" then gems = gems + (tonumber(e.amount) or 0)
elseif e.name == "Trait Reroll" then rerolls = rerolls + (tonumber(e.amount) or 0)
elseif e.name == "Tickets" then tickets = tickets + (tonumber(e.amount) or 0)
else
local cfg = ER.getEntryConfig(e.name)
if cfg and cfg.kind == "Unit" then units = units + 1 end
end
end
statsLabel.Text = table.concat({
string.format("Money %-9s +%s/min", fmt(Stats.money), fmt(Stats.moneyPerMin)),
string.format("Rolls %-9d %.0f/min sold %d (%s)", Stats.rolls, Stats.rollsPerMin, Stats.soldUnits, fmt(Stats.soldMoney)),
string.format("Units %d/%d rebirth %s dice %s", units, inventoryCap(),
tostring(pv(function() return D.Rebirth() end)), tostring(pv(function() return D.Dice() end))),
string.format("Buffs Luck x%s Money x%s Roll %ss", tostring(buff("Luck")), tostring(buff("Money Multiplier")), tostring(buff("Roll Duration"))),
string.format("Gems %-6d Rerolls %-6d Tickets %-6d", gems, rerolls, tickets),
string.format("Rares: %s", #Stats.rares > 0 and Stats.rares[1] or "-"),
}, "\n")
local lines = {}
for i = 1, math.min(7, #Stats.log) do
local e = Stats.log[i]
table.insert(lines, "<font color='" .. hex(e.colour) .. "'>" .. e.text .. "</font>")
end
logLabel.Text = table.concat(lines, "\n")
end)
if not ok then warn("[ADH] ui: " .. tostring(err)) end
end)
-- dragging -------------------------------------------------------------------
local dragging, dragStart, startPos = false, nil, nil
header.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
dragging = true
dragStart = input.Position
startPos = main.Position
local conn
conn = input.Changed:Connect(function()
if input.UserInputState == Enum.UserInputState.End then
dragging = false
conn:Disconnect()
end
end)
end
end)
State.dragConn = UserInputService.InputChanged:Connect(function(input)
if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then
local d = input.Position - dragStart
main.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + d.X, startPos.Y.Scale, startPos.Y.Offset + d.Y)
end
end)
State.keyConn = UserInputService.InputBegan:Connect(function(input, gpe)
if gpe then return end
if input.KeyCode == Cfg.uiKey then
main.Visible = not main.Visible
end
end)
closeBtn.MouseButton1Click:Connect(function()
main.Visible = false
end)
-- API ------------------------------------------------------------------------
local API = {}
API.version = HUB_VER
API.cfg = Cfg
API.stats = Stats
API.actions = A
API.tasks = Tasks
function API.set(k, v)
Cfg[k] = v
if refreshers[k] then refreshers[k]() end
end
function API.toggle(k)
Cfg.enabled[k] = not Cfg.enabled[k]
if refreshers[k] then refreshers[k]() end
if k == "serverAutoSell" and R.SetSetting then
R.SetSetting:FireServer("AutoSell", Cfg.enabled[k] and Cfg.serverAutoSellValue or 0)
end
return Cfg.enabled[k]
end
API.sellNow = A.sell
API.collectNow = A.collect
API.equipBest = A.equipBest
API.claimNow = A.claims
API.redeemAll = A.redeem
API.log = log
function API.stop()
getgenv().__ADH_STOP = debug.traceback("[ADH] stop called", 2)
State.running = false
for _, key in ipairs({ "scheduler", "uiConn", "dragConn", "keyConn", "fuseConn", "cutsceneConn" }) do
local c = State[key]
if typeof(c) == "RBXScriptConnection" then pcall(function() c:Disconnect() end) end
State[key] = nil
end
if gui then gui:Destroy() end
getgenv().__ANIME_DICE_HUB = nil
warn("[ADH] stopped")
end
stopBtn.MouseButton1Click:Connect(function() API.stop() end)
getgenv().__ANIME_DICE_HUB = API
-- startup --------------------------------------------------------------------
task.spawn(function()
log("ANIME DICE HUB v" .. HUB_VER .. " online · Project UAI / deepseek-v4-flash")
print(string.format("[ADH] hub loaded: %d tasks, %d remotes", (function() local n = 0 for _ in pairs(Tasks) do n = n + 1 end return n end)(), 33))
pcall(A.claims)
pcall(A.collect)
pcall(A.equipBest)
pcall(A.quests)
pcall(A.redeem)
pcall(A.boostSpins)
warn("[ADH] ready - RightShift toggles the UI")
end)
return APINo comments yet for this script.



