/* 文件名:NpcTransaction.nut 路径:Project/NpcTransaction/NpcTransaction.nut 创建日期:2025-10-23 12:50 文件用途:NPC交易系统 */ class NpcTransactionC extends LenheartNewUI_Windows { //调试模式 // DeBugMode = true; //不是窗口 // NoWindow = true; //是否可见 Visible = false; NPCPath = null; EquList = null; NPCList = null; Dialog = null; CurDialog = -1; mode = 0; DiaTimer = 0; //置换装备 ReplacementEqu = null; //交易金币 TransactionGlod = 0; //交易装备 TransactionEqu = null; Img = Rindro_Image("npctransation/main.img"); Charc = null; PlayerName = "无名"; PlayerLevel = 0; AvatarInfoIdx = [0x3038, 0x3010, 0x3014, 0x3018, 0x301c, 0x3020, 0x3024, 0x3028, 0x302c, 0x3030, 0x3034]; NpcName = "赛利亚"; //当前交互NPCId CurNpcId = -1; NPCAvatar = null; //当前交易NPC头像信息 CurNpcAvatar = null; constructor(gObjectId, gX, gY, gWidth, gHeight, gTitleH) { Childrens = []; NPCAvatar = {}; //注册控件 RegisterWidget(); LenheartNewUI_Windows.constructor(gObjectId, gX, gY, gWidth, gHeight, gTitleH); InifPvf(); RegNpc(); local obj = sq_getMyCharacter(); local C_Object = L_sq_RA(0x1ab7cdc); local job = sq_getJob(obj); //记录装备 local equiitemsbuf = []; foreach(offset in AvatarInfoIdx) { local AvatarEquiAddress = L_sq_RA(C_Object + offset); if (AvatarEquiAddress >= 0x400000) { local NormalIndex = L_sq_RA(AvatarEquiAddress + 0x1c); local ExIndex = L_sq_RA(AvatarEquiAddress + 0x13E0); equiitemsbuf.append(ExIndex == 0 ? NormalIndex : ExIndex); } } Charc = Rindro_Draw_Character(job, equiitemsbuf, "rest.ani", null); PlayerName = L_Sq_GetObjectName(obj); PlayerLevel = L_Sq_GetObjectLevel(obj); DiscardItemCallBackFunc.rawset("RecoveryC", DiscardItem.bindenv(this)); Pack_Control.rawset(21005002, function(Chunk) { local Jso = Json.Decode(Chunk); local flag = Jso.flag; CurDialog = flag; mode = flag; DiaTimer = Clock(); if (Jso.rawin("glod")) { TransactionGlod = Jso.glod; R_Utils.PlaySound("GOLD_PAY_OUT"); } if (Jso.rawin("equ")) { TransactionEqu = Jso.equ; } else { R_Utils.PlaySound("ALERT_2"); } }.bindenv(this)); Pack_Control.rawset(21005006, function(Chunk) { ReplacementEqu = null; }.bindenv(this)); } function RegisterWidget() { //关闭按钮 local CloseButton = LenheartNewUI_BaseButton(250, 14, 11, 12, "interface/lenheartwindowcommon.img", 276); CloseButton.OnClick = function() { this.Visible = false; }.bindenv(this); Childrens.append(CloseButton); //确认按钮 local ConfirmButton = LenheartNewUI_ButtonText(56, 313, 15, "同意交易"); ConfirmButton.DWidth = 18; ConfirmButton.Width = 74; ConfirmButton.SetTextOffset(-4, 1); ConfirmButton.OnClickEx = function(Btn) { if (!Btn.Visible) return; local T = { op = 21005003, npc = CurNpcId, } SendPackEx(T); CloseWindow(); }.bindenv(this); ConfirmButton.SetCallBackFunc(function(Btn) { if (mode >= 1 && mode< 3) { Btn.Visible = true; } else { Btn.Visible = false; } }.bindenv(this)); AddChild(ConfirmButton); local CancelButton = LenheartNewUI_ButtonText(145, 313, 15, "取消交易"); CancelButton.DWidth = 18; CancelButton.Width = 74; CancelButton.SetTextOffset(-4, 1); CancelButton.OnClick = function() { CloseWindow(); }.bindenv(this); AddChild(CancelButton); } //绘制主界面 function DrawMain(obj) { Img.DrawPng(0, X, Y); if (Charc) Charc.DrawFace(X + 20, Y + 188); L_sq_DrawCode("Lv." + PlayerLevel.tostring(), X + 46, Y + 185, sq_RGBA(179, 169, 135, 255), 0, 1); L_sq_DrawCode(PlayerName, X + 46, Y + 196, sq_RGBA(179, 169, 135, 255), 0, 1); if (CurNpcAvatar) { L_sq_DrawImg(CurNpcAvatar.Path, CurNpcAvatar.Index, X + 20, Y + 44); L_sq_DrawCode(CurNpcAvatar.Name, X + 46, Y + 47, sq_RGBA(179, 169, 135, 255), 0, 1); } //置换装备 if (ReplacementEqu) { L_Sq_DrawItem(X + 122, Y + 242, ReplacementEqu, 1, 0, 0, 0); } //交易金币 if (TransactionGlod > 0) { L_sq_DrawCode(TransactionGlod.tostring(), X + 165, Y + 48, sq_RGBA(179, 169, 135, 255), 0, 1); } //交易装备 if (TransactionEqu) { DrawItemBase(X + 122, Y + 98, TransactionEqu, 1); } //对话 if (Dialog && CurDialog != -1) { ShowMessageBox(X + Dialog[CurDialog].x, Y + Dialog[CurDialog].y, Dialog[CurDialog].str); } } function Show(obj) { DrawMain(obj); LenheartNewUI_Windows.Show(obj); } //逻辑入口 function Proc(obj) { LenheartNewUI_Windows.SyncPos(X, Y); if (DiaTimer != 0 && Clock() - DiaTimer > 2000) { DiaTimer = 0; CurDialog = -1; } } //回收道具回调 function DiscardItem(ItemAddress) { if (!Visible) return true; else { local info = FindItemPosByForeachInven(ItemAddress); if (!EquList.rawin(info.itemId)) { return; } if (info) { info.op <- 21005001; info.npc <- CurNpcId; ReplacementEqu = info.itemId; SendPackEx(info); } R_Utils.PlaySound("CHANGE_ALERT"); } } //遍历背包查找Item function FindItemPosByForeachInven(FindAddress) { local Inven = L_sq_RA(0x1A5FB24); local InvenAdd = L_sq_RA(Inven + 56); InvenAdd += 36; for (local z = 0; z< 5; z++) { for (local i = 0; i< 48; i++) { local ItemAdd = L_sq_RA(InvenAdd + ((i + (z * 48)) * 4)); if (ItemAdd == FindAddress) return { type = z, pos = i, vis = false, count = MemoryTool.DecodeMemoryData(FindAddress + 0x1A4), itemId = L_sq_RA(FindAddress + 0x1c) } } } return null; } function InifPvf() { EquList = {}; Rindro_Script.GetFileData("etc/rindro/npctransaction/npctransaction.etc", function(DataTable, Data) { while (!Data.Eof()) { local Fragment = Data.Get(); if (Fragment == "[npc list]") { NPCList = []; while (true) { local Fbuf = Data.Get(); if (Fbuf == "[/npc list]") { break; } NPCList.append(Fbuf); } } else if (Fragment == "[event dialog]") { Dialog = []; for (local i = 0; i< 4; i++) { local T = { str = Sq_ConvertWideChar(Data.Get(), "big5"), x = Data.Get(), y = Data.Get() } Dialog.append(T); } } else if (Fragment == "[value]") { while (true) { local Fbuf = Data.Get(); if (Fbuf == "[/value]") { break; } local Value = Data.Get(); EquList.rawset(Fbuf, Value); } } } }); NPCPath = {}; Rindro_Script.GetFileData("npc/npc.lst", function(DataTable, Data) { while (!Data.Eof()) { local Id = Data.Get(); local Path = "npc/" + Data.Get().tolower(); NPCPath.rawset(Id, Path); } }); } function RegNpc() { local EachManager = getroottable()["L_Each_Obj"]; foreach(id in NPCList) { EachManager.AddEachForNpc(id, function(SThis) { //关闭按钮 local ApplyEngagementButton = LenheartNewUI_Each_BaseButton(0, 0, 100, 21, "interface2/popup_menu/popup_back.img", 3); ApplyEngagementButton.Icon = "interface2/popup_menu/popup_icon_cn.img"; ApplyEngagementButton.IconIdx = 27; ApplyEngagementButton.Str = "交易"; ApplyEngagementButton.Data = SThis.NPC_Index; ApplyEngagementButton.OnClick = function(Button) { CurNpcId = Button.Data; TransactionEqu = null; TransactionGlod = 0; mode = 0; ReplacementEqu = null; CurDialog = -1; InitWindow(); //打开背包 L_sq_Open_ExWindow(0x1ADE090, 0, 0, 1); Button.Parent.CloseAllEach(); Button.Parent.CloseWindow(); ResetFocus(); R_Utils.PlaySound("WINDOW_SHOW"); }.bindenv(this); ApplyEngagementButton.SetCallBackFunc(function(Button) {}) SThis.AddChild(ApplyEngagementButton); }.bindenv(this)); } } function ShowMessageBox(X, Y, STR) { local StrDrawLen = LenheartTextClass.GetStringLength(STR); local WLen = ((StrDrawLen - 30) / 12) + 1; local HLen = (StrDrawLen / 110); WLen = WLen > 7 ? 7 : WLen; //Item信息框一般为211的宽度 L_sq_DrawImg("interface/messageballoon.img", 49, X + (-50 + (WLen * 12)), Y + 11 + ((HLen + 1) * 13)); L_sq_DrawWindow(X, Y, 30 + (WLen * 12), 21 + (HLen * 13), "interface/messageballoon.img", 40, 9, 12, 9, 13); //绘制字符串 local Buf = L_sq_GetStringDrawArray(STR, 123); foreach(Line, Str in Buf) { L_sq_DrawCode(Str, X + 8, Y + 8 + (Line * 14), sq_RGBA(255, 255, 255, 255), 0, 1); } } function GetNpcAvatar(Id) { if (NPCAvatar.rawin(Id)) return NPCAvatar[Id]; //获取NPC路径 local Path = NPCPath.rawget(CurNpcId); local Info = Rindro_Script.GetFileData(Path, function(DataTable, Data) { while (!Data.Eof()) { local Fragment = Data.Get(); if (Fragment == "[popup face]") { DataTable.ImgPath <- Data.Get().tolower(); DataTable.Index <- Data.Get(); } else if (Fragment == "[name]") { DataTable.Name <- Sq_ConvertWideChar(Data.Get(), "big5"); } } }); NPCAvatar.rawset(Id, { Path = Info.ImgPath, Index = Info.Index, Name = Info.Name }); return NPCAvatar[Id]; } function InitWindow() { CurNpcAvatar = GetNpcAvatar(CurNpcId); Visible = true; } } L_Windows_List <- []; getroottable().rawdelete("LenheartPluginsInitFlag"); getroottable().rawdelete("EventList_Obj") getroottable().rawdelete("NpcTransaction_Obj"); getroottable().rawdelete("L_Each_Obj"); function Lenheart_NpcTransaction_Fun(obj) { local RootTab = getroottable(); if (!RootTab.rawin("NpcTransaction_Obj")) { RootTab.rawset("NpcTransaction_Obj", true); LenheartNewUI_CreateWindow(NpcTransactionC, "npc交易窗口", 100, 120, 272, 334, 32); } } getroottable()["LenheartFuncTab"].rawset("NpcTransactionFuncN", Lenheart_NpcTransaction_Fun);