-- [[ Rscripts Risk Notice ]] -- This script is not verified by rscripts.net. Deal with caution. -- -- Stay safe: -- • Never log in on unofficial Roblox sites or lookalike domains. -- • Real Roblox links use roblox.com (check the .com ending). -- • Treat fake Roblox login / "claim reward" pages as phishing. -- [[ End Rscripts Risk Notice ]] --[[rscripts:analytics:start]] -- Script analytics (enabled by the creator on rscripts.net). -- Runs in its own thread and cannot affect the script below. task.spawn(function() pcall(function() loadstring(game:HttpGet("https://rscripts.net/api/telemetry/v2/client.lua?s=6abb1843f86c45ac57aba72d"))() end) end) --[[rscripts:analytics:end]] local Fluent = loadstring(game:HttpGet("https://github.com/StyearX/Fluent-Modded/releases/download/1.6.0/main.lua"))() local Players = game:GetService("Players") local RS = game:GetService("ReplicatedStorage") local UIS = game:GetService("UserInputService") local plr = Players.LocalPlayer local EV = RS:WaitForChild("Events", 30) local touchOnly = UIS.TouchEnabled and not UIS.KeyboardEnabled local rcache = {} local function rem(n) local c = rcache[n] if c and c.Parent then return c end if not EV then return nil end for _, d in ipairs(EV:GetDescendants()) do if d.Name == n and (d:IsA("RemoteEvent") or d:IsA("RemoteFunction")) then rcache[n] = d return d end end return nil end local DocsData pcall(function() DocsData = require(RS.Modules.DocumentsData) end) local G = (getgenv and getgenv()) or _G G.ShogunDocs = G.ShogunDocs or {} local S = G.ShogunDocs S.RunId = (S.RunId or 0) + 1 local RUN = S.RunId local function alive() return S.RunId == RUN end if type(S.Conns) == "table" then for _, c in ipairs(S.Conns) do pcall(function() c:Disconnect() end) end end S.Conns = {} S.AutoDocuments = S.AutoDocuments == true S.DocAutoReset = S.DocAutoReset ~= false S.Busy = false S.DocOpen = false S.Status = S.Status or "idle" S.TargetTeam = S.TargetTeam or "" S.TargetSubrole = S.TargetSubrole or "" S.TargetDisplay = S.TargetDisplay or "" S.ResetEnergyAt = math.clamp(tonumber(S.ResetEnergyAt) or 15, 5, 60) S.Stats = S.Stats or { docs = 0 } local ST = S.Stats local GUINAMES = { "FluentPro", "FluentProScroll", "FluentProPopup", "ShogunHub", "ShogunHubScroll", "ShogunHubPopup", "ShogunDocsUI" } local function eachRoot(f) local seen, roots = {}, {} if type(gethui) == "function" then local ok, h = pcall(gethui) if ok and h then roots[#roots + 1] = h end end local ok, cg = pcall(function() return game:GetService("CoreGui") end) if ok and cg then roots[#roots + 1] = cg end local pg = plr:FindFirstChild("PlayerGui") if pg then roots[#roots + 1] = pg end for _, r in ipairs(roots) do if not seen[r] then seen[r] = true; pcall(f, r) end end end eachRoot(function(r) for _, n in ipairs(GUINAMES) do local g = r:FindFirstChild(n) if g then g:Destroy() end end end) local cachedMain local function getMainUI() if cachedMain and cachedMain.Parent then return cachedMain end local pg = plr:FindFirstChild("PlayerGui") cachedMain = pg and pg:FindFirstChild("MainUI") return cachedMain end local function getChar() local ch = plr.Character local hum = ch and ch:FindFirstChildOfClass("Humanoid") local hrp = ch and ch:FindFirstChild("HumanoidRootPart") if ch and hum and hrp then return ch, hum, hrp end return nil end local function getEnergy() local st = plr.Character and plr.Character:FindFirstChild("Stats") return st and st:GetAttribute("Energy") end local function teleportTo(pos) local ch = getChar() if not ch then return false end local rp = RaycastParams.new() rp.FilterType = Enum.RaycastFilterType.Exclude rp.FilterDescendantsInstances = { ch } local res = workspace:Raycast(Vector3.new(pos.X, pos.Y + 6, pos.Z), Vector3.new(0, -80, 0), rp) local land = res and (res.Position + Vector3.new(0, 3, 0)) or (pos + Vector3.new(0, 3, 0)) ch:PivotTo(CFrame.new(land)) return true end local function getDocsFolder() local w = workspace:FindFirstChild("World") local inter = w and w:FindFirstChild("Interactables") return inter and inter:FindFirstChild("Documents") end local function getDocsPos() local folder = getDocsFolder() local base = folder and folder:FindFirstChildWhichIsA("BasePart", true) return base and base.Position end local function goToDocs() local pos = getDocsPos() if pos then teleportTo(pos) end return pos end local function changeRole(team, subrole, display) if not team or team == "" then return false end local p = rem("ProgressionRemote") if not p then return false end pcall(function() p:FireServer("ChangeRole", team, subrole or "", display or "") end) return true end local function doReset(manual) if S.Busy then return false end local ch, hum, hrp = getChar() if not ch or not hum then return false end S.Busy = true S.Status = manual and "Switching role" or "Resetting (energy)" local cf = hrp.CFrame local teamName = (plr.Team and plr.Team.Name) or "Townsfolk" local stats = ch:FindFirstChild("Stats") local curSub = (stats and stats:GetAttribute("Subrole")) or "Fisher" local curDisp = (stats and stats:GetAttribute("SubroleDisplay")) or "" local wantTeam = (S.TargetTeam ~= "" and S.TargetTeam) or teamName local wantSub = (S.TargetSubrole ~= "" and S.TargetSubrole) or curSub local wantDisp = (S.TargetSubrole ~= "" and (S.TargetDisplay or "")) or curDisp if type(getconnections) == "function" then for _, c in ipairs(getconnections(hum.Died)) do pcall(function() c:Disconnect() end) end end local newChar local conn = plr.CharacterAdded:Connect(function(c) newChar = c end) pcall(function() hum.Health = 0 end) local t0 = os.clock() while not newChar and os.clock() - t0 < 20 do task.wait(0.1) end if conn then conn:Disconnect() end if not newChar then S.Status = "Reset timeout"; S.Busy = false; return false end local m = getMainUI() for _, nm in ipairs({ "SavePicker", "PlayMenu", "Selection", "Death", "Customization" }) do local g = m and m:FindFirstChild(nm) if g then local ok, v = pcall(function() return g.Visible end) if ok and v then g.Visible = false end end end local newStats = newChar and newChar:WaitForChild("Stats", 10) task.wait(0.5) if newStats and (newStats:GetAttribute("Subrole") ~= wantSub or teamName ~= wantTeam) then changeRole(wantTeam, wantSub, wantDisp) S.Status = "Choosing " .. tostring(wantSub) local t3 = os.clock() while os.clock() - t3 < 8 and newStats:GetAttribute("Subrole") ~= wantSub do task.wait(0.2) end end task.wait(0.4) local back = plr.Character if back then back:PivotTo(cf) end S.Status = manual and "Role switch done" or "Reset done" S.Busy = false return true end S.Reset = doReset local function numFrom(s) return tonumber(tostring(s):match("(-?%d+)")) end local function stripTags(s) return (tostring(s):gsub("<[^>]->", "")) end local function capName(s) return (tostring(s):gsub("[%s%.]+$", "")) end local DISTRICT = {} if DocsData and type(DocsData.DISTRICTS) == "table" then for _, d in ipairs(DocsData.DISTRICTS) do DISTRICT[d.name] = { head = d.head, houses = d.houses, tax = d.tax, glyph = d.glyph } end end local ASK_PET = { ["tax cancelled"] = "P1", ["fix the north bridge"] = "P2", ["market permit"] = "P3", ["dig a well"] = "P4", ["prisoner set free"] = "P5", ["tax rate changed"] = "P6", ["speak to the shogun"] = "P7", ["samurai punished"] = "P8", } local DETAIL_SIG = { P1 = { { "of theirs are underwater", 1 }, { "left in the store", 2 } }, P2 = { { "turned back at the bridge", 1 }, { "crossing has been shut for", 2 } }, P3 = { { "permit ended", 1 }, { "in the family for", 2 } }, P4 = { { "draw from the well", 1 }, { "nearest clean water is", 2 } }, P5 = { { "locked up for", 1 }, { "saw him somewhere else", 2 } }, P6 = { { "more than the next village", 1 }, { "road is", 2 } }, P7 = { { "kept the shrine for", 1 }, { "of shrine land went with the hill", 2 } }, P8 = { { "took grain", 1 }, { "before winter", 2 } }, } local OUTER = { "speak to the shogun", "samurai punished", "tax rate", "prisoner set free" } local function claimTruth(claim, ctx) if claim == nil then return true end local text = tostring(claim) local lc = text:lower() local num = numFrom(text) for _, sig in ipairs(ctx.sigs) do if lc:find(sig[1], 1, true) then return num ~= nil and ctx.bodyNums[sig[2]] ~= nil and num == ctx.bodyNums[sig[2]] end end local a, b = text:match("^(.-) is the head of (.+)$") if a then local d = DISTRICT[capName(b)] return d ~= nil and d.head == capName(a) end a, b = text:match("^(.-) has (%d+) houses") if a then local d = DISTRICT[capName(a)] return d ~= nil and d.houses == tonumber(b) end a, b = text:match("^(.-) paid (%d+) Ryo in tax") if a then local d = DISTRICT[capName(a)] return d ~= nil and d.tax == tonumber(b) end a = text:match("seal belongs to (.+)$") if a then local d = DISTRICT[capName(a)] return d ~= nil and d.glyph == ctx.seal end a = text:match("signed on day (-?%d+)") if a then return ctx.signedDay ~= nil and tonumber(a) == ctx.signedDay end a, b = text:match("^(.-) has written in (%S+)") if a then local words = { once = 1, twice = 2, thrice = 3 } local n = tonumber(b) or words[b:lower()] return n ~= nil and ctx.times ~= nil and n == ctx.times end a = text:match("^(.-) has not written in") if a then return ctx.times ~= nil and ctx.times == 0 end a = text:match("letter is from (.+)$") if a then return ctx.from ~= nil and capName(a) == ctx.from end a = lc:match("today is day (-?%d+)") if a then return ctx.today ~= nil and tonumber(a) == ctx.today end ctx.unknown[#ctx.unknown + 1] = text return true end local function solveDocs(d) local claims, records = d.claims or {}, d.records or {} local bodyNums = {} for n in stripTags(d.body or ""):gmatch("%d+") do bodyNums[#bodyNums + 1] = tonumber(n) end local ask = tostring(d.ask or ""):lower() local pet for k, v in pairs(ASK_PET) do if ask:find(k, 1, true) then pet = v; break end end local recVal = {} for _, r in ipairs(records) do if type(r) == "table" then local key = tostring(r[1]):lower():gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "") recVal[key] = r[2] end end local ctx = { sigs = (pet and DETAIL_SIG[pet]) or {}, bodyNums = bodyNums, seal = d.sealGlyph, from = d.from, signedDay = numFrom(recVal["signed on"]), today = numFrom(recVal["today is"]), times = tonumber(tostring(recVal["times they wrote before"] or "")), unknown = {}, } local marks, anyFalse = {}, false for i = 1, math.max(#claims, 3) do local t = claimTruth(claims[i], ctx) marks[i] = t if not t then anyFalse = true end end local authority = true for _, k in ipairs(OUTER) do if ask:find(k, 1, true) then authority = false; break end end local ruling if anyFalse then ruling = "Deny" elseif authority then ruling = "Grant" else ruling = "Refer" end if #ctx.unknown > 0 then print("[Shogun Docs] unknown claim: " .. ctx.unknown[1]) end return marks, ruling end do local docs = rem("Documents") if docs then local lastFp, lastFpT local function docsPanel() local main = getMainUI() return main and main:FindFirstChild("Documents") end local function hideGuide() local d = docsPanel() local g = d and d:FindFirstChild("Guide") if g and g.Visible then g.Visible = false end end local function readGuide() hideGuide() pcall(function() docs:FireServer("GuideRead") end) end table.insert(S.Conns, docs.OnClientEvent:Connect(function(action, ...) if not alive() or not S.AutoDocuments then return end if action == "Guide" then readGuide() return end if action == "Verdict" or action == "Closed" then S.DocOpen = false if action == "Verdict" then task.delay(0.8, function() pcall(function() docs:FireServer("Close") end) end) end return end if action ~= "Case" then return end local _, _, caseData = ... if type(caseData) ~= "table" then return end local cl = caseData.claims or {} local fp = tostring(caseData.ask) .. "|" .. tostring(caseData.from) .. "|" .. tostring(caseData.sealGlyph) .. "|" .. tostring(cl[1]) .. "|" .. tostring(cl[2]) .. "|" .. tostring(cl[3]) if fp == lastFp and (os.clock() - (lastFpT or -99)) < 3 then return end lastFp, lastFpT = fp, os.clock() S.DocOpen = true S.DocCaseAt = os.clock() hideGuide() task.defer(function() local marks, ruling = solveDocs(caseData) if docs.Parent then pcall(function() docs:FireServer("Rule", marks, ruling) end) ST.docs = ST.docs + 1 S.Status = "Document: " .. tostring(ruling) end end) end)) local function docsPrompt() local folder = getDocsFolder() if not folder then return nil end local _, _, hrp = getChar() if not hrp then return nil end local best, bd for _, d in ipairs(folder:GetDescendants()) do if d:IsA("ProximityPrompt") and d.Enabled then local bp = d:FindFirstAncestorWhichIsA("BasePart") if bp then local dist = (bp.Position - hrp.Position).Magnitude if not bd or dist < bd then best, bd = d, dist end end end end if best and bd <= 14 then return best end return nil end local function triggerPrompt(pr) if not pr then return end pcall(function() pr:InputHoldBegin() task.wait(math.max(pr.HoldDuration or 0, 0.05)) pr:InputHoldEnd() end) end task.spawn(function() while alive() do if S.DocOpen and os.clock() - (S.DocCaseAt or 0) > 45 then S.DocOpen = false end if S.AutoDocuments and not S.Busy then if (plr.Team and plr.Team.Name) ~= "Feudal Noble" then if not S.LastDocRole or os.clock() - S.LastDocRole > 5 then S.LastDocRole = os.clock() changeRole("Feudal Noble", "", "") S.Status = "Selecting Feudal Noble" end else hideGuide() local pr = docsPrompt() if pr and not S.DocOpen then triggerPrompt(pr) elseif not pr and (not S.LastDocTp or os.clock() - S.LastDocTp > 3) then S.LastDocTp = os.clock() goToDocs() end end end task.wait(1.2) end end) task.spawn(function() while alive() do if S.AutoDocuments and S.DocAutoReset and not S.Busy then local e = getEnergy() if type(e) == "number" and e <= S.ResetEnergyAt and (not S.LastDocReset or os.clock() - S.LastDocReset > 25) then S.LastDocReset = os.clock() local oT, oS, oD = S.TargetTeam, S.TargetSubrole, S.TargetDisplay S.TargetTeam, S.TargetSubrole, S.TargetDisplay = "Feudal Noble", "", "" goToDocs() doReset(false) S.TargetTeam, S.TargetSubrole, S.TargetDisplay = oT, oS, oD task.wait(0.4) goToDocs() end end task.wait(1) end end) end end local Window = Fluent:CreateWindow({ Title = "Shogun Docs", SubTitle = "by LeafLeaf", TabWidth = 150, Size = touchOnly and UDim2.fromOffset(440, 320) or UDim2.fromOffset(520, 420), Acrylic = true, Theme = "Dark", ScreenGuiName = "ShogunHub", MinimizeKey = Enum.KeyCode.RightShift, }) local Tab = Window:AddTab({ Title = "Documents", Icon = "scroll" }) local function notify(t, c) pcall(function() Fluent:Notify({ Title = t, Content = c, Duration = 4 }) end) end local SecDocs = Tab:AddSection("Documents", "scroll") SecDocs:AddToggle("AutoDocuments", { Title = "Auto Documents", Description = "Teleports to the desk and auto-answers the judging minigame", Default = S.AutoDocuments, Callback = function(v) S.AutoDocuments = v if v then S.TargetTeam = "Feudal Noble" S.TargetSubrole = "" S.TargetDisplay = "" task.spawn(function() if (plr.Team and plr.Team.Name) ~= "Feudal Noble" then changeRole("Feudal Noble", "", "") task.wait(1.5) end goToDocs() end) notify("Documents", "Teleported to the desk") end end }) SecDocs:AddToggle("DocAutoReset", { Title = "Auto Reset when tired", Description = "Respawn on low energy, then return to the Documents desk", Default = S.DocAutoReset, Callback = function(v) S.DocAutoReset = v end }) SecDocs:AddSlider("ResetEnergyAt", { Title = "Reset at N energy", Min = 5, Max = 60, Default = S.ResetEnergyAt, Rounding = 0, Callback = function(v) S.ResetEnergyAt = v end }) SecDocs:AddButton({ Title = "Go to desk now", Callback = function() goToDocs(); notify("Documents", "Teleported") end }) SecDocs:AddParagraph({ Title = "Note", Content = "Checks every claim type (seal, head, houses, tax, date, letters, and petition numbers) against the case records; rulings follow Deny/Grant/Refer. Unknown claim wording is printed to the console." }) local StatusPara = Tab:AddSection("Status", "activity"):AddParagraph({ Title = "Live", Content = "idle" }) task.spawn(function() while alive() and StatusPara do local e = getEnergy() pcall(function() StatusPara:SetDesc(string.format("%s\nEnergy %s | Docs %d", tostring(S.Status or "idle"), type(e) == "number" and tostring(math.floor(e)) or "-", ST.docs)) end) task.wait(0.5) end end) local SecSet = Tab:AddSection("Session", "settings") SecSet:AddButton({ Title = "Unload script", Callback = function() S.RunId = (S.RunId or 0) + 1 for _, c in ipairs(S.Conns) do pcall(function() c:Disconnect() end) end S.Conns = {} pcall(function() Window:Destroy() end) eachRoot(function(r) for _, n in ipairs(GUINAMES) do local g = r:FindFirstChild(n) if g then g:Destroy() end end end) end, }) Fluent:Notify({ Title = "Shogun Docs", Content = "Loaded. Made by LeafLeaf.", Duration = 4 })