/* 文件名:Steal.nut 路径:Project/Steal/Steal.nut 创建日期:2026-04-07 05:19 文件用途: */ class StealC_Password_Box extends LenheartNewUI_CommonUi { NumberSeq = null; ScrollPixelOffset = 0; ScrollBaseIndex = 0; InitBaseIndex = 0; ScrollStartTimeMs = 0; RowDurationMs = 250; RowHeight = 24; ColumnYOffset = 0; CorrectIndex = 0; IsStopped = false; IsLockedCorrect = false; StopSnapOffsetY = 0; PassStr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]; constructor(X, Y, ...) { LenheartNewUI_CommonUi.constructor(X, Y, 30, 120); local PhaseIndex = 0; if (vargc > 0) { PhaseIndex = vargv[0]; } ColumnYOffset = -(PhaseIndex * 8); NumberSeq = []; for (local i = 0; i< 10; i++) { local Info = { num = PassStr[sq_getRandom(0, PassStr.len() - 1)], CorrectFlag = false, } NumberSeq.append(Info); } CorrectIndex = sq_getRandom(0, 9); NumberSeq[CorrectIndex].CorrectFlag = true; local SeqLen = NumberSeq.len(); if (SeqLen > 0) { local Phase = PhaseIndex % SeqLen; if (Phase< 0) { Phase += SeqLen; } ScrollBaseIndex = Phase; InitBaseIndex = Phase; } ScrollStartTimeMs = Clock(); } function GetLoopIndex(Index) { local SeqLen = NumberSeq.len(); if (SeqLen <= 0) { return 0; } local Value = Index % SeqLen; if (Value< 0) { Value += SeqLen; } return Value; } function UpdateScrollByClock() { if (RowDurationMs <= 0) { RowDurationMs = 1; } local RunTimeMs = Clock() - ScrollStartTimeMs; if (RunTimeMs< 0) { RunTimeMs = 0; } local PassedRows = (RunTimeMs / RowDurationMs).tointeger(); local CycleMs = RunTimeMs % RowDurationMs; ScrollPixelOffset = sq_GetUniformVelocity(0, RowHeight - 1, CycleMs, RowDurationMs).tointeger(); ScrollBaseIndex = GetLoopIndex(InitBaseIndex - PassedRows); } function GetCorrectCenterY(RefY) { local SeqLen = NumberSeq.len(); if (SeqLen <= 0) { return Y; } local Delta = GetLoopIndex(CorrectIndex - ScrollBaseIndex); local TextY = Y + 10; local BaseY = TextY + Delta * RowHeight + ScrollPixelOffset + ColumnYOffset + 8; local CycleHeight = SeqLen * RowHeight; local BestY = BaseY; local BestDist = abs(BestY - RefY); for (local k = -2; k <= 2; k++) { local CY = BaseY + (k * CycleHeight); local Dist = abs(CY - RefY); if (Dist< BestDist) { BestY = CY; BestDist = Dist; } } return BestY; } function TryLockByRect(LockTopY, LockHeight, SnapExtraOffsetY) { if (IsStopped) { return false; } UpdateScrollByClock(); local LockCenterY = LockTopY + (LockHeight / 2).tointeger(); local CorrectCenterY = GetCorrectCenterY(LockCenterY); if (CorrectCenterY >= LockTopY && CorrectCenterY <= (LockTopY + LockHeight)) { StopSnapOffsetY = (LockCenterY - CorrectCenterY) + SnapExtraOffsetY; IsStopped = true; IsLockedCorrect = true; return true; } return false; } function Show(obj) { Parent.Img.DrawExPng(10, X, Y, 0, sq_RGBA(255, 255, 255, 90), 1.0, 1.0); local SeqLen = NumberSeq.len(); if (SeqLen <= 0) { return; } if (!IsStopped) { UpdateScrollByClock(); } local DrawCount = (Height / RowHeight).tointeger() + 4; local TextY = Y + 10; for (local i = -2; i< DrawCount - 2; i++) { local Info = NumberSeq[GetLoopIndex(ScrollBaseIndex + i)]; local NumStr = Info.num.tostring(); local Color = Info.CorrectFlag ? sq_RGBA(157, 245, 10, 255) : sq_RGBA(150, 150, 150, 255); local DrawY = TextY + i * RowHeight + ScrollPixelOffset + ColumnYOffset + StopSnapOffsetY; L_sq_DrawCode(NumStr, X + 15 - LenheartTextClass.GetStringLength(NumStr) / 2, DrawY, Color, 0, 1); } } } class StealC extends LenheartNewUI_Windows { //调试模式 // DeBugMode = true; //不是窗口 // NoWindow = true; //是否可见 Visible = false; Img = Rindro_Image("steal/widget.img"); //解锁完成度 UnlockComplete = 0.0; CorrectLockedCount = 0; LockBoxHeight = 24; LockSnapOffsetY = -6; AllUnlockedTriggered = false; AniQueue = null; UnlockSuccessAni = null; UnlockAniPlaying = false; UnlockAniFinished = false; UnlockFinalizeDone = false; UnlockAniFrameDelay = 60; NPCList = null; RequestNpcId = -1; NpcEachRegistered = false; constructor(gObjectId, gX, gY, gWidth, gHeight, gTitleH) { Childrens = []; AniQueue = QuestQueue(); //注册控件 RegisterWidget(); LenheartNewUI_Windows.constructor(gObjectId, gX, gY, gWidth, gHeight, gTitleH); RefreshUnlockComplete(); InitStealConfig(); RegisterStealNpcEach(); RegisterPack(21017002, function(Chunk) { local Jso = Json.Decode(Chunk); if (Jso.rawin("ret") && Jso.ret == true) { ResetStealSession(); Visible = true; ResetFocus(); } else { Visible = false; } }.bindenv(this)); } function RegisterWidget() { // //关闭按钮 // local CloseButton = LenheartNewUI_BaseButton(278, 0, 11, 12, "interface/lenheartwindowcommon.img", 276); // CloseButton.OnClick = function() { // this.Visible = false; // }.bindenv(this); // Childrens.append(CloseButton); for (local i = 0; i< 8; i++) { local PasswordBox = StealC_Password_Box(280 + i * 30, 268, i); AddChild(PasswordBox); } } //绘制主界面 function InitStealConfig() { NPCList = []; Rindro_Script.GetFileData("etc/steal.etc", function(DataTable, Data) { while (!Data.Eof()) { local Fragment = Data.Get(); if (Fragment == "[npc list]") { while (true) { local Value = Data.Get(); if (Value == "[/npc list]") { break; } local NpcId = Value; try { NpcId = Value.tointeger(); } catch (exception) {} NPCList.append(NpcId); } } } }.bindenv(this)); } function RegisterStealNpcEach() { if (NpcEachRegistered) { return; } if (!NPCList || NPCList.len() <= 0) { return; } local RootTab = getroottable(); local EachManager = null; if (RootTab.rawin("L_Each_Obj")) { EachManager = RootTab["L_Each_Obj"]; } else if (RootTab.rawin("Lenheart_Get_EachObj")) { EachManager = RootTab["Lenheart_Get_EachObj"](); } if (!EachManager) { return; } foreach(id in NPCList) { EachManager.AddEachForNpc(id, function(SThis) { local StealButton = LenheartNewUI_Each_BaseButton(0, 0, 100, 21, "interface2/popup_menu/popup_back.img", 3); StealButton.Icon = "interface2/popup_menu/popup_icon_cn.img"; StealButton.IconIdx = 27; StealButton.Str = "偷窃"; StealButton.OnClick = function(Button) { local NpcId = Button.Parent.NPC_Index; RequestNpcId = NpcId; Button.Parent.CloseAllEach(); Button.Parent.CloseWindow(); SendPackEx({ op = 21017001, npcid = NpcId }); }.bindenv(this); StealButton.SetCallBackFunc(function(Button) {}) SThis.AddChild(StealButton); }.bindenv(this)); } NpcEachRegistered = true; } function ResetStealSession() { UnlockComplete = 0.0; CorrectLockedCount = 0; AllUnlockedTriggered = false; UnlockAniPlaying = false; UnlockAniFinished = false; UnlockFinalizeDone = false; UnlockSuccessAni = null; AniQueue = QuestQueue(); Childrens = []; RegisterWidget(); RefreshUnlockComplete(); } function GetLockTopY() { return Y + 268 + 60; } function GetFocusPasswordBox() { foreach(Child in Childrens) { if ((Child instanceof StealC_Password_Box) && !Child.IsStopped) { return Child; } } return null; } function GetPasswordBoxTotal() { local Total = 0; foreach(Child in Childrens) { if (Child instanceof StealC_Password_Box) { Total += 1; } } return Total; } function RefreshUnlockComplete() { local Total = GetPasswordBoxTotal(); if (Total <= 0) { UnlockComplete = 0.0; return; } UnlockComplete = CorrectLockedCount.tofloat() / Total.tofloat(); } function BuildUnlockFrameArr() { local FrameArr = []; local Delay = UnlockAniFrameDelay; if (Delay <= 0) { Delay = 60; } for (local i = 0; i< 13; i++) { FrameArr.append({ ImgIndex = i, Delay = Delay, Pos = [0, 0] }); } return FrameArr; } function StartUnlockSuccessSequence() { if (UnlockAniPlaying || UnlockAniFinished) { return; } local FrameArr = BuildUnlockFrameArr(); UnlockSuccessAni = Lenheart_Ani("", FrameArr, [X + 269, Y + 260]); UnlockSuccessAni.ImgPath = "steal/unlock.img"; UnlockSuccessAni.LoopFlag = false; UnlockSuccessAni.Reset(); UnlockAniPlaying = true; UnlockAniFinished = false; if (AniQueue) { AniQueue.RemoveQuest("StealUnlockSuccessAni"); AniQueue.AddQuest("StealUnlockSuccessAni", function(Name, Time) { if (!UnlockSuccessAni) { UnlockAniPlaying = false; UnlockAniFinished = true; AniQueue.RemoveQuest(Name); FinalizeUnlockSuccess(); return; } UnlockSuccessAni.X = X + 324; UnlockSuccessAni.Y = Y + 109; UnlockSuccessAni.Show(Duration); if (UnlockSuccessAni.State == 0) { UnlockAniPlaying = false; UnlockAniFinished = true; AniQueue.RemoveQuest(Name); FinalizeUnlockSuccess(); } }.bindenv(this)); } else { UnlockAniPlaying = false; UnlockAniFinished = true; FinalizeUnlockSuccess(); } } function FinalizeUnlockSuccess() { if (UnlockFinalizeDone) { return; } UnlockFinalizeDone = true; SendStealUnlockPack(); CloseWindow(); Visible = false; } function SendStealUnlockPack() { if (RequestNpcId == null || RequestNpcId <= 0) { return; } SendPackEx({ op = 21017003, npcid = RequestNpcId }); } function OnAllUnlockedInternal() { R_Utils.PlaySound("GAMBLE_RESULT_GOOD"); StartUnlockSuccessSequence(); } function CheckAllUnlocked() { if (AllUnlockedTriggered) { return; } local Total = GetPasswordBoxTotal(); if (Total <= 0) { return; } if (CorrectLockedCount >= Total) { AllUnlockedTriggered = true; OnAllUnlockedInternal(); } } function CheckSpaceLock() { if (!Visible) { return; } if (!KeyPressNB.isKeyPress(7, "StealC")) { return; } local FocusBox = GetFocusPasswordBox(); if (!FocusBox) { return; } if (FocusBox.TryLockByRect(GetLockTopY(), LockBoxHeight, LockSnapOffsetY)) { R_Utils.PlaySound("TRADE_OK"); CorrectLockedCount += 1; RefreshUnlockComplete(); CheckAllUnlocked(); } else { R_Utils.PlaySound("ALERT_2"); } } function DrawMain(obj) { //灰色背景 DrawNineBoxAlpha(X, Y, 800, 600, "interface2/common/mypopup/popup.img", 0, 150); //宝箱动画 local Ani = DrawAniEx(X + 425, Y + 230, "npc/animation/storagediamond.ani"); Ani.setImageRateFromOriginal(1.7, 1.7); //如果未解锁 if (UnlockComplete< 1.0) { //宝箱锁图像 Img.DrawPng(12, X + 335, Y + 120); } //完成度文字 local StealCompleteStr = "解锁完成度: " + UnlockComplete * 100.0 + "%"; L_sq_DrawCode(StealCompleteStr, X + 410 - LenheartTextClass.GetStringLength(StealCompleteStr) / 2, Y + 406, sq_RGBA(255, 255, 255, 255), 0, 1); //完成度进度条 Img.DrawPng(2, X + 162, Y + 425); setClip(X + 168, Y + 429, X + 168 + (463 * UnlockComplete).tointeger(), Y + 429 + 6); Img.DrawPng(3, X + 168, Y + 429); releaseClip(); //裁切结束 //解锁界面 Img.DrawPng(9, X + 269, Y + 260); //解锁锁定条 Img.DrawPng(11, X + 269 + 8, Y + 260 + 60); } function Show(obj) { DrawMain(obj); if (AniQueue) { AniQueue.Run(); } //裁切遮罩密码框 setClip(X + 280, Y + 268, X + 280 + 8 * 30, Y + 268 + 120); LenheartNewUI_Windows.Show(obj); releaseClip(); //裁切结束 } //逻辑入口 function Proc(obj) { LenheartNewUI_Windows.SyncPos(X, Y); if (!NpcEachRegistered) { RegisterStealNpcEach(); } CheckSpaceLock(); } } L_Windows_List <- []; getroottable().rawdelete("LenheartPluginsInitFlag"); getroottable().rawdelete("EventList_Obj") getroottable().rawdelete("Steal_Obj"); getroottable().rawdelete("L_Each_Obj"); function Lenheart_Steal_Fun(obj) { local RootTab = getroottable(); if (!RootTab.rawin("Steal_Obj")) { RootTab.rawset("Steal_Obj", true); LenheartNewUI_CreateWindow(StealC, "Steal_Window", 0, 0, 800, 600, 0); } } getroottable()["LenheartFuncTab"].rawset("StealFuncN", Lenheart_Steal_Fun);