1228 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
		
		
			
		
	
	
			1228 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
|  | /* | ||
|  | 文件名:ScriptManager.nut | ||
|  | 路径:Dps_A/BaseClass/ScriptManager/ScriptManager.nut | ||
|  | 创建日期:2024-10-11	12:24 | ||
|  | 文件用途:pvf 管理器 | ||
|  | */ | ||
|  | class Script { | ||
|  | 
 | ||
|  |     constructor(Path = "/home/neople/game/Script.pvf") { | ||
|  |         print("正在初始化PVF..."); | ||
|  |         local StartTime = time(); | ||
|  |         //文件 | ||
|  |         local FileIo = null; | ||
|  |         try { | ||
|  |             FileIo = file(Path, "rb"); | ||
|  |         } catch (exception) { | ||
|  |             error("打不开Script文件!"); | ||
|  |         } | ||
|  |         if (!FileIo) return; | ||
|  |         local FileRo = BlobEx(FileIo.readblob(FileIo.len())); | ||
|  |         InitPvfTreeHeader(FileRo); | ||
|  |         FileIo.close(); | ||
|  | 
 | ||
|  |         InitStringBin(FileRo); | ||
|  |         InitLoadString(FileRo); | ||
|  | 
 | ||
|  |         // local AllFileStartPos = ScriptData.StartPos; | ||
|  |         // foreach(FilePath, Info in ScriptData.PvfFileInfo) { | ||
|  | 
 | ||
|  |         //     //Ani太多了 加载的时候解密  其他文件 现在解密 | ||
|  |         //     //构建AniMap | ||
|  |         //     if (endswith(FilePath, ".ani") && !endswith(FilePath, ".als")) { | ||
|  |         //         // ScriptData.Ani[FilePath] <- InitPvfAni(FileRo); | ||
|  |         //         ScriptData.AniPathTable[FilePath] <- { | ||
|  |         //             Pos = (AllFileStartPos + Info.ROffset), | ||
|  |         //             Length = Info.Length, | ||
|  |         //             Cr32 = Info.Cr32 | ||
|  |         //         } | ||
|  |         //     } else { | ||
|  |         //         FileRo.seek(AllFileStartPos + Info.ROffset); | ||
|  |         //         CrcDecode(FileRo, Info.Length, Info.Cr32); | ||
|  |         //         // 解密完需要重新调整指针位置 | ||
|  |         //         FileRo.seek(AllFileStartPos + Info.ROffset); | ||
|  |         //     } | ||
|  |         // } | ||
|  | 
 | ||
|  |         ScriptData.IO = FileRo; | ||
|  |         ScriptData.Init(); | ||
|  | 
 | ||
|  |         print("PVF初始化完毕!!!"); | ||
|  |         print("用时: " + (time() - StartTime) + "秒"); | ||
|  |     } | ||
|  | 
 | ||
|  |     function charPtrToInt(arr) { | ||
|  |         local value = ((arr[0]) << 0) | ((arr[1]) << 8) | ((arr[2]) << 16) | ((arr[3]) << 24); | ||
|  |         return value; | ||
|  |     } | ||
|  | 
 | ||
|  |     function CrcDecode(Ro, Length, crc32) { | ||
|  |         local num = 0x81A79011; | ||
|  |         for (local i = 0; i< Length; i += 4) { | ||
|  |             local Pos = Ro.tell(); | ||
|  |             local anInt = charPtrToInt([Ro[Pos], Ro[Pos + 1], Ro[Pos + 2], Ro[Pos + 3]]); | ||
|  |             local val = (anInt ^ num ^ crc32); | ||
|  |             local jiemi = (val >>> 6) | ((val << (32 - 6)) & 0xFFFFFFFF); | ||
|  | 
 | ||
|  |             Ro[Pos] = ((jiemi >>> 0) & 0xFF); | ||
|  |             Ro[Pos + 1] = ((jiemi >>> 8) & 0xFF); | ||
|  |             Ro[Pos + 2] = ((jiemi >>> 16) & 0xFF); | ||
|  |             Ro[Pos + 3] = ((jiemi >>> 24) & 0xFF); | ||
|  |             Ro.seek(4, 'c'); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     //初始化PVF文件树 | ||
|  |     function InitPvfTreeHeader(HeaderRo) { | ||
|  |         //读取UUID的长度 | ||
|  |         local UUID_LENGTH = HeaderRo.GetInt(); | ||
|  |         //UUID  读 1 - 36位 构造 UTF8 string | ||
|  |         local UUID = HeaderRo.GetString(UUID_LENGTH); | ||
|  |         //版本号 | ||
|  |         local Version = HeaderRo.GetInt(); | ||
|  |         // 文件路径数据的大小 | ||
|  |         local AlignedIndexHeaderSize = HeaderRo.GetInt(); | ||
|  |         // 解密密钥 | ||
|  |         local IndexHeaderCrc = HeaderRo.GetInt(); | ||
|  |         // 文件数量 | ||
|  |         local IndexSize = HeaderRo.GetInt(); | ||
|  |         local FristPos = HeaderRo.tell(); | ||
|  | 
 | ||
|  | 
 | ||
|  |         CrcDecode(HeaderRo, AlignedIndexHeaderSize, IndexHeaderCrc) | ||
|  |         // HeaderRo.CrcDecode(AlignedIndexHeaderSize, IndexHeaderCrc); | ||
|  | 
 | ||
|  | 
 | ||
|  |         local CurrPos = 0; | ||
|  |         ScriptData.StartPos = AlignedIndexHeaderSize + 56; | ||
|  | 
 | ||
|  |         for (local i = 0; i< IndexSize; i++) { | ||
|  |             HeaderRo.seek(FristPos + CurrPos); | ||
|  |             local FileNumber = HeaderRo.GetInt(); | ||
|  |             local FilePathLength = HeaderRo.GetInt(); | ||
|  |             local FileName = HeaderRo.GetString(FilePathLength); | ||
|  |             local FileLength = HeaderRo.GetInt(); | ||
|  |             local Cre32 = HeaderRo.GetInt(); | ||
|  |             local RelativeOffset = HeaderRo.GetInt(); | ||
|  |             if (FileLength > 0) { | ||
|  |                 local RealFileLength = (FileLength + 3) & 4294967292; | ||
|  |                 ScriptData.PvfFileInfo[FileName] <- { | ||
|  |                     ROffset = RelativeOffset, | ||
|  |                     Cr32 = Cre32, | ||
|  |                     Length = RealFileLength, | ||
|  |                     DecodeFlag = 0 | ||
|  |                 } | ||
|  |             } | ||
|  |             CurrPos += 20; | ||
|  |             CurrPos += FilePathLength; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     function InitStringBin(Ro) { | ||
|  |         local Info = ScriptData.GetFileInfo("stringtable.bin"); | ||
|  |         if (!Info) return; | ||
|  | 
 | ||
|  |         Ro.seek(ScriptData.StartPos + Info.ROffset); | ||
|  |         CrcDecode(Ro, Info.Length, Info.Cr32); | ||
|  |         //解密完需要重新调整指针位置 | ||
|  |         Ro.seek(ScriptData.StartPos + Info.ROffset); | ||
|  | 
 | ||
|  |         local FileHPos = Ro.tell(); | ||
|  |         local Count = Ro.GetInt(); | ||
|  | 
 | ||
|  | 
 | ||
|  |         local CurrentIndex = 0; | ||
|  |         for (local i = 0; i< Count; i++) { | ||
|  |             Ro.seek(FileHPos + CurrentIndex * 4 + 4); | ||
|  |             local StartPos = Ro.GetInt(); | ||
|  |             local EndPos = Ro.GetInt(); | ||
|  |             local Len = EndPos - StartPos; | ||
|  |             Ro.seek(FileHPos + StartPos + 4); | ||
|  |             local Str = Ro.GetString(Len); | ||
|  |             ScriptData.BinString[CurrentIndex] <- Str; | ||
|  |             CurrentIndex++; | ||
|  |         } | ||
|  |         ScriptData.RemoveFileInfo("stringtable.bin"); | ||
|  |         // print("初始化StringTable完成,数量: " + ScriptData.BinString.len()); | ||
|  |     } | ||
|  | 
 | ||
|  |     function InitLoadString(Ro) { | ||
|  |         local Info = ScriptData.GetFileInfo("n_string.lst"); | ||
|  |         if (!Info) return; | ||
|  | 
 | ||
|  |         Ro.seek(ScriptData.StartPos + Info.ROffset); | ||
|  |         CrcDecode(Ro, Info.Length, Info.Cr32); | ||
|  |         //解密完需要重新调整指针位置 | ||
|  |         Ro.seek(ScriptData.StartPos + Info.ROffset); | ||
|  | 
 | ||
|  |         local FileHPos = Ro.tell(); | ||
|  |         local Flag = Ro.GetUShort(); | ||
|  |         // print("Flag :" + Flag); | ||
|  |         local i = 2; | ||
|  |         while (i< Info.Length) { | ||
|  |             if ((Info.Length - i) >= 10) { | ||
|  |                 Ro.seek(FileHPos + i + 6); | ||
|  |                 local FindKey = Ro.GetInt(); | ||
|  |                 local Key = ScriptData.GetBinString(FindKey); | ||
|  |                 if (Key) { | ||
|  |                     local FileInfo = ScriptData.GetFileInfo(Key.tolower()); | ||
|  | 
 | ||
|  |                     Ro.seek(ScriptData.StartPos + FileInfo.ROffset); | ||
|  |                     CrcDecode(Ro, FileInfo.Length, FileInfo.Cr32); | ||
|  |                     //解密完需要重新调整指针位置 | ||
|  |                     Ro.seek(ScriptData.StartPos + FileInfo.ROffset); | ||
|  |                     local Str = Ro.GetString(FileInfo.Length); | ||
|  |                     local StrArr = split(Str, "\r\n"); | ||
|  |                     foreach(index, strobj in StrArr) { | ||
|  |                         if (strobj.find(">") != null) { | ||
|  |                             local strobjarr = split(strobj, ">"); | ||
|  |                             if (strobjarr.len() > 1) | ||
|  |                                 ScriptData.LoadString[strobjarr[0]] <- strobjarr[1]; | ||
|  |                         } | ||
|  |                     } | ||
|  |                     ScriptData.RemoveFileInfo(Key.tolower()); | ||
|  |                 } | ||
|  |             } else break; | ||
|  |             i += 10; | ||
|  |         } | ||
|  |         ScriptData.RemoveFileInfo("n_string.lst"); | ||
|  |         // print("初始化LoadString完成,数量: " + ScriptData.LoadString.len()); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class GlobaData { | ||
|  |     //加载完成的Flag | ||
|  |     InitFlag = false; | ||
|  |     //PVF的文件解析集合 | ||
|  |     PvfFileInfo = null; | ||
|  |     //PVF文件的开始下标 | ||
|  |     StartPos = null; | ||
|  |     //PVF文件的IO | ||
|  |     IO = null; | ||
|  | 
 | ||
|  |     AniPathTable = null; | ||
|  |     Ani = null; | ||
|  |     LoadString = null; | ||
|  |     BinString = null; | ||
|  | 
 | ||
|  |     //怪物List | ||
|  |     MonsterLst = null; | ||
|  |     MonsterConfigLst = null; | ||
|  |     //地图List | ||
|  |     MapLst = null; | ||
|  |     MapConfigLst = null; | ||
|  |     //地板List | ||
|  |     TileConfigLst = null; | ||
|  |     //被动对象List | ||
|  |     PassiveObjectLst = null; | ||
|  |     PassiveObjectConfigLst = null; | ||
|  |     //角色配置信息路径List | ||
|  |     CharacterLst = null; | ||
|  |     CharacterConfigLst = null; | ||
|  |     //装备List | ||
|  |     EquipmentLst = null; | ||
|  |     EquipmentConfigLst = null; | ||
|  |     //APC List | ||
|  |     AICharacterLst = null; | ||
|  |     AICharacterConfigLst = null; | ||
|  |     //Atk List | ||
|  |     AttackinfoConfigLst = null; | ||
|  | 
 | ||
|  |     constructor() { | ||
|  |         PvfFileInfo = {}; | ||
|  |         Ani = {}; | ||
|  |         AniPathTable = {}; | ||
|  |         LoadString = {}; | ||
|  |         BinString = {}; | ||
|  |         MonsterConfigLst = {}; | ||
|  |         MapConfigLst = {}; | ||
|  |         TileConfigLst = {}; | ||
|  |         PassiveObjectConfigLst = {}; | ||
|  |         CharacterConfigLst = {}; | ||
|  |         EquipmentConfigLst = {}; | ||
|  |         AICharacterConfigLst = {}; | ||
|  |         AttackinfoConfigLst = {}; | ||
|  |     } | ||
|  | 
 | ||
|  |     function InitList(Path, ErrorStr, TableName) { | ||
|  |         this[TableName] = {}; | ||
|  |         local HeaderPath = Path + "/"; | ||
|  |         local Info = ScriptData.GetFileInfo(HeaderPath + Path + ".lst"); | ||
|  |         if (!Info) return error(ErrorStr + "列表不存在。加载失败!"); | ||
|  |         IO.seek(ScriptData.StartPos + Info.ROffset); | ||
|  | 
 | ||
|  |         local FileHPos = IO.tell(); | ||
|  |         local Flag = IO.GetUShort(); | ||
|  | 
 | ||
|  |         local i = 2; | ||
|  |         while (i< Info.Length) { | ||
|  |             if ((Info.Length - i) >= 10) { | ||
|  |                 IO.seek(FileHPos + i + 1); | ||
|  |                 local Id; | ||
|  |                 if (Path == "equipment") { | ||
|  |                     Id = IO.GetInt(); | ||
|  |                     IO.seek(1, 'c'); | ||
|  |                 } else { | ||
|  |                     Id = IO.GetShort(); | ||
|  |                     IO.seek(3, 'c'); | ||
|  |                 } | ||
|  |                 local FindKey = IO.readn('i'); | ||
|  |                 local Key = ScriptData.GetBinString(FindKey); | ||
|  |                 Key = HeaderPath + Key.tolower(); | ||
|  |                 this[TableName][Id] <- Key; | ||
|  |             } else break; | ||
|  |             i += 10; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     function Init() { | ||
|  |         //初始化怪物列表 | ||
|  |         InitList("monster", "怪物", "MonsterLst"); | ||
|  |         //初始化地图列表 | ||
|  |         InitList("map", "地图", "MapLst"); | ||
|  |         //初始化被动对象列表 | ||
|  |         InitList("passiveobject", "被动对象", "PassiveObjectLst"); | ||
|  |         //初始化角色配置信息列表 | ||
|  |         InitList("character", "角色配置", "CharacterLst"); | ||
|  |         //初始化角色配置信息列表 | ||
|  |         InitList("equipment", "装备", "EquipmentLst"); | ||
|  |         // Util.PrintTable(EquipmentLst); | ||
|  |         //初始化APC列表 | ||
|  |         InitList("aicharacter", "APC", "AICharacterLst"); | ||
|  | 
 | ||
|  |         ScriptData.InitFlag = true; | ||
|  |     } | ||
|  | 
 | ||
|  |     function RegRealPath(Path) { | ||
|  |         if (Path.find("../") != null) { | ||
|  |             while (true) { | ||
|  |                 local rbuf = regexp("[^/]+/../"); | ||
|  |                 local Ret = rbuf.capture(Path); | ||
|  |                 if (Ret) { | ||
|  |                     Path = Path.slice(0, Ret[0].begin) + Path.slice(Ret[0].end); | ||
|  |                 } else { | ||
|  |                     return Path; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |         return Path; | ||
|  |     } | ||
|  | 
 | ||
|  |     function GetFileInfo(Path) { | ||
|  |         Path = RegRealPath(Path); | ||
|  |         if (!PvfFileInfo.rawin(Path)) return null; | ||
|  |         else { | ||
|  |             //如果是未解密的需要先解密 | ||
|  |             if (Path != "stringtable.bin" && Path != "n_string.lst" && !(endswith(Path, ".str")) && PvfFileInfo[Path].DecodeFlag == 0) { | ||
|  |                 local Info = PvfFileInfo[Path]; | ||
|  |                 IO.seek(StartPos + Info.ROffset); | ||
|  |                 Script.CrcDecode(IO, Info.Length, Info.Cr32); | ||
|  |                 // 解密完需要重新调整指针位置 | ||
|  |                 // FileRo.seek(StartPos + Info.ROffset); | ||
|  |             } | ||
|  |             return PvfFileInfo[Path]; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     function RemoveFileInfo(Path) { | ||
|  |         if (PvfFileInfo.rawin(Path)) { | ||
|  |             delete PvfFileInfo[Path] | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     function GetAni(Path) { | ||
|  |         Path = RegRealPath(Path); | ||
|  |         if (Path in Ani) | ||
|  |             return Ani[Path]; | ||
|  |         else { | ||
|  |             try { | ||
|  |                 IO.seek(AniPathTable[Path].Pos); | ||
|  |                 CrcDecode(IO, AniPathTable[Path].Length, AniPathTable[Path].Cr32); | ||
|  |                 IO.seek(AniPathTable[Path].Pos); | ||
|  |                 Ani[Path] <- InitPvfAni(IO); | ||
|  |                 return Ani[Path]; | ||
|  |             } catch (exception) { | ||
|  |                 print(Path + "找不到文件!"); | ||
|  |                 error(exception); | ||
|  |             } | ||
|  |             // print(Path + "找不到文件!"); | ||
|  |             return null; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     function GetBinString(Path) { | ||
|  |         if (Path in BinString) | ||
|  |             return BinString[Path]; | ||
|  |         else { | ||
|  |             print(Path + "找不到文件!"); | ||
|  |             return null; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     function GetLoadString(Path) { | ||
|  |         if (Path in LoadString) | ||
|  |             return LoadString[Path]; | ||
|  |         else { | ||
|  |             print(Path + "找不到文件!"); | ||
|  |             return null; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     function UnpackData(FilePos, i) { | ||
|  |         local out = ""; | ||
|  |         IO.seek(FilePos + i); //内容指示位 | ||
|  |         local currentByte = IO.readn('c'); //内容指示位 | ||
|  |         local after = IO.GetInt(); | ||
|  |         switch (currentByte) { | ||
|  |             case 10: { | ||
|  |                 IO.seek(FilePos + i - 4); | ||
|  |                 local Before = IO.GetInt(); | ||
|  |                 local Buf = GetBinString(after); | ||
|  |                 if (!Buf) { | ||
|  |                     Buf = ""; | ||
|  |                 } else { | ||
|  |                     Buf = "<" + Before + "::" + Buf + "`" + GetLoadString(Buf) + "`>"; | ||
|  |                 } | ||
|  |                 Buf = Buf + "\r\n"; | ||
|  |                 out += Buf; | ||
|  |                 break; | ||
|  |             } | ||
|  |             case 2: { | ||
|  |                 out += after + '\t'; | ||
|  |                 break; | ||
|  |             } | ||
|  |             case 4: { | ||
|  |                 local Bbuf = blob(4); | ||
|  |                 Bbuf.writen(after, 'i'); | ||
|  |                 Bbuf.seek(0); | ||
|  |                 local Buf = Bbuf.readn('f'); | ||
|  |                 out += after + '\t'; | ||
|  |                 break; | ||
|  |             } | ||
|  |             case 6: | ||
|  |             case 8: | ||
|  |             case 7: | ||
|  |             case 5: { | ||
|  |                 local Buf = GetBinString(after); | ||
|  |                 if (!Buf) Buf = ""; | ||
|  |                 return Buf; | ||
|  |             } | ||
|  |             default: | ||
|  |                 out += ""; | ||
|  |                 break; | ||
|  |         } | ||
|  | 
 | ||
|  |         return out; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     function Decompile_attackinfo(DirPath, FileRealName, Info) { | ||
|  |         local AttackinfoAtt = {}; | ||
|  |         IO.seek(StartPos + Info.ROffset); | ||
|  |         local FilePos = IO.tell(); | ||
|  |         local out = ""; | ||
|  |         if (Info.Length >= 7) { | ||
|  |             //以5为单步从第二位开始遍历字节 | ||
|  |             local i = 2; | ||
|  |             while (true) { | ||
|  |                 //到最后了就不处理了防止内存越界 | ||
|  |                 if (i< Info.Length && Info.Length - i >= 5) { | ||
|  |                     local str = UnpackData(FilePos, i); | ||
|  |                     i += 5; | ||
|  |                     //攻击类型 攻击属性类型 损伤反应 | ||
|  |                     if (str == "[attack type]" || str == "[elemental property]" || str == "[damage reaction]") { | ||
|  |                         local Ret = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         AttackinfoAtt[str.slice(1, -1)] <- Ret.slice(1, -1); | ||
|  |                     } | ||
|  |                     //武器伤害应用 推力  抬起 | ||
|  |                     else if (str == "[weapon damage apply]" || str == "[push aside]" || str == "[lift up]") { | ||
|  |                         local Ret = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         AttackinfoAtt[str.slice(1, -1)] <- ((Ret.tointeger() - 9).tofloat()); | ||
|  |                     } | ||
|  |                     //打击音效 | ||
|  |                     else if (str == "[hit wav]") { | ||
|  |                         local Ret = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         AttackinfoAtt[str.slice(1, -1)] <- Ret; | ||
|  |                     } | ||
|  |                     //打击效果 | ||
|  |                     else if (str == "[hit info]") { | ||
|  |                         AttackinfoAtt["hit_info"] <- {}; | ||
|  |                         local HitType = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         AttackinfoAtt["hit_info"].Type <- HitType; | ||
|  |                         local Ret = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         AttackinfoAtt["hit_info"].BloodType <- Ret.slice(1, -1); | ||
|  |                         local Value0 = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         local Value1 = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         AttackinfoAtt["hit_info"].Value <- [Value0, Value1]; | ||
|  |                     } | ||
|  |                 } else break; | ||
|  |             } | ||
|  | 
 | ||
|  |         } | ||
|  |         return AttackinfoAtt; | ||
|  |     } | ||
|  | 
 | ||
|  |     //获取ATK | ||
|  |     function GetAtk(Path) { | ||
|  |         Path = RegRealPath(Path); | ||
|  |         if (AttackinfoConfigLst.rawin(Path)) return AttackinfoConfigLst[Path]; | ||
|  |         local Pos = 0; | ||
|  |         while (true) { | ||
|  |             local Buf = Path.find("/", Pos + 1); | ||
|  |             if (Buf != null) | ||
|  |                 Pos = Buf; | ||
|  |             else break; | ||
|  |         } | ||
|  |         local DirPath = Path.slice(0, Pos + 1); | ||
|  |         local FileRealName = Path.slice(Pos + 1); | ||
|  |         local Info = GetFileInfo(Path); | ||
|  |         if (Info) { | ||
|  |             local InfoObj = Decompile_attackinfo(DirPath, FileRealName, Info); | ||
|  |             AttackinfoConfigLst[Path] <- InfoObj; | ||
|  |             return InfoObj; | ||
|  |         } else error(Path + " AttackInfo不存在!"); | ||
|  |     } | ||
|  | 
 | ||
|  |     function Decompile_monster(DirPath, FileRealName, Info) { | ||
|  |         local MonsterAtt = {}; | ||
|  |         //属性表 | ||
|  |         MonsterAtt.Attributes <- {}; | ||
|  |         IO.seek(StartPos + Info.ROffset); | ||
|  |         local FilePos = IO.tell(); | ||
|  |         local out = ""; | ||
|  |         if (Info.Length >= 7) { | ||
|  |             //以5为单步从第二位开始遍历字节 | ||
|  |             local i = 2; | ||
|  |             while (true) { | ||
|  |                 //到最后了就不处理了防止内存越界 | ||
|  |                 if (i< Info.Length && Info.Length - i >= 5) { | ||
|  |                     local str = UnpackData(FilePos, i); | ||
|  |                     i += 5; | ||
|  |                     //大小 | ||
|  |                     if (str == "[size]") { | ||
|  |                         local gx = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         local gy = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         MonsterAtt.size <- { | ||
|  |                             x = gx.tointeger(), | ||
|  |                             y = gy.tointeger() | ||
|  |                         }; | ||
|  |                     } | ||
|  |                     //属性 | ||
|  |                     else if (str == "[HpMax]" || str == "[Attack]" || str == "[Speed]" || str == "[Defense]" || str == "[DeployCost]" || str == "[Resilience]" || str == "[FirePower]" || str == "[IcePower]" || str == "[LightningPower]" || str == "[DarkPower]" || str == "[FireResistance]" || str == "[IceResistance]" || str == "[LightningResistance]" || str == "[DarkResistance]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         MonsterAtt.Attributes[RealKey] <- UnpackData(FilePos, i).tointeger() - 9; | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     // //属性 | ||
|  |                     // else if (str == "[ability]") { | ||
|  |                     //     MonsterAtt.ability <- {}; | ||
|  |                     //     while (true) { | ||
|  |                     //         local Ret = UnpackData(FilePos, i); | ||
|  |                     //         i += 5; | ||
|  |                     //         if (Ret == "[/ability]") break; | ||
|  |                     //         if (endswith(Ret, "]")) { | ||
|  |                     //             local Value = UnpackData(FilePos, i); | ||
|  |                     //             i += 5; | ||
|  |                     //             MonsterAtt.ability[Ret.slice(1, Ret.len() - 1)] <- Value.tointeger(); | ||
|  |                     //         } | ||
|  |                     //     } | ||
|  |                     // } | ||
|  |                     //标签 | ||
|  |                     else if (str == "[category]") { | ||
|  |                         MonsterAtt.category <- {}; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/category]") break; | ||
|  |                             if (endswith(Ret, "]")) { | ||
|  |                                 MonsterAtt.category[Ret.slice(1, Ret.len() - 1)] <- true; | ||
|  |                             } | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //等级 移动速度 攻击速度 释放速度 硬直 重量 | ||
|  |                     else if (str == "[level]" || str == "[move speed]" || str == "[attack speed]" || str == "[cast speed]" || str == "[hit recovery]" || str == "[weight]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         MonsterAtt[RealKey] <- {}; | ||
|  |                         MonsterAtt[RealKey].min <- UnpackData(FilePos, i).tointeger(); | ||
|  |                         i += 5; | ||
|  |                         MonsterAtt[RealKey].max <- UnpackData(FilePos, i).tointeger(); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //视力 针对最近 好战 攻击延迟(僵值) 名字 | ||
|  |                     else if (str == "[sight]" || str == "[targeting nearest]" || str == "[warlike]" || str == "[attack delay]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         MonsterAtt[RealKey] <- UnpackData(FilePos, i).tointeger(); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //名字 | ||
|  |                     else if (str == "[name]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         MonsterAtt[RealKey] <- UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //头像 | ||
|  |                     else if (str == "[face image]") { | ||
|  |                         local buf1 = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         local buf2 = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         MonsterAtt.face <- { | ||
|  |                             path = buf1, | ||
|  |                             index = buf2 | ||
|  |                         }; | ||
|  |                     } | ||
|  |                     //Ani | ||
|  |                     else if (str == "[animotion]") { | ||
|  |                         MonsterAtt.animotion <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/animotion]") break; | ||
|  |                             MonsterAtt.animotion.append(DirPath + Ret.tolower()); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //Atk | ||
|  |                     else if (str == "[attack info]") { | ||
|  |                         MonsterAtt.attackinfo <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/attack info]") break; | ||
|  |                             MonsterAtt.attackinfo.append(DirPath + Ret.tolower()); | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } else break; | ||
|  |             } | ||
|  | 
 | ||
|  |         } | ||
|  |         return MonsterAtt; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     function GetMonster(Idx) { | ||
|  |         if (MonsterLst.rawin(Idx)) { | ||
|  |             local Path = MonsterLst[Idx]; | ||
|  |             if (MonsterConfigLst.rawin(Path)) return MonsterConfigLst[Path]; | ||
|  |             local Pos = 0; | ||
|  |             while (true) { | ||
|  |                 local Buf = Path.find("/", Pos + 1); | ||
|  |                 if (Buf != null) | ||
|  |                     Pos = Buf; | ||
|  |                 else break; | ||
|  |             } | ||
|  |             local DirPath = Path.slice(0, Pos + 1); | ||
|  |             local FileRealName = Path.slice(Pos + 1); | ||
|  |             local Info = GetFileInfo(Path); | ||
|  |             local InfoObj = Decompile_monster(DirPath, FileRealName, Info); | ||
|  |             MonsterConfigLst[Path] <- InfoObj; | ||
|  |             return InfoObj; | ||
|  |         } else error(Idx + " 号怪物不存在!"); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     function Decompile_map(DirPath, FileRealName, Info) { | ||
|  |         local MapAtt = {}; | ||
|  |         IO.seek(StartPos + Info.ROffset); | ||
|  |         local FilePos = IO.tell(); | ||
|  |         local out = ""; | ||
|  |         if (Info.Length >= 7) { | ||
|  |             //以5为单步从第二位开始遍历字节 | ||
|  |             local i = 2; | ||
|  |             while (true) { | ||
|  |                 //到最后了就不处理了防止内存越界 | ||
|  |                 if (i< Info.Length && Info.Length - i >= 5) { | ||
|  |                     local str = UnpackData(FilePos, i); | ||
|  |                     i += 5; | ||
|  |                     //远景速度 中景速度 近景速度 | ||
|  |                     if (str == "[far sight scroll]" || str == "[middle sight scroll]" || str == "[near sight scroll]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         MapAtt[RealKey] <- UnpackData(FilePos, i).tointeger(); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //名字 | ||
|  |                     else if (str == "[map name]" || str == "[map type]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         MapAtt[RealKey] <- UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //地板 | ||
|  |                     else if (str == "[tile]") { | ||
|  |                         MapAtt.tile <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/tile]") break; | ||
|  |                             MapAtt.tile.append(DirPath + Ret.tolower()); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //音乐 | ||
|  |                     else if (str == "[sound]") { | ||
|  |                         MapAtt.sound <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/sound]") break; | ||
|  |                             MapAtt.sound.append(Ret); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //对象 | ||
|  |                     else if (str == "[passive object]") { | ||
|  |                         MapAtt.passiveobject <- []; | ||
|  |                         while (true) { | ||
|  |                             local Id = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Id == "[/passive object]") break; | ||
|  |                             local XPos = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             local YPos = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             local ZPos = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             local Tbuf = { | ||
|  |                                 id = Id.tointeger() - 9, | ||
|  |                                 x = XPos.tointeger() - 9, | ||
|  |                                 y = YPos.tointeger() - 9, | ||
|  |                                 z = ZPos.tointeger() - 9, | ||
|  |                             } | ||
|  |                             MapAtt.passiveobject.append(Tbuf); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //Ani | ||
|  |                     else if (str == "[animation]") { | ||
|  |                         MapAtt.animation <- []; | ||
|  |                         while (true) { | ||
|  |                             local Path = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Path == "[/animation]") break; | ||
|  |                             local Layer = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             local XPos = UnpackData(FilePos, i).tointeger(); | ||
|  |                             i += 5; | ||
|  |                             local YPos = UnpackData(FilePos, i).tointeger(); | ||
|  |                             i += 5; | ||
|  |                             local ZPos = UnpackData(FilePos, i).tointeger(); | ||
|  |                             i += 5; | ||
|  |                             local Tbuf = { | ||
|  |                                 path = DirPath + Path.tolower(), | ||
|  |                                 layer = Layer, | ||
|  |                                 x = XPos - 9, | ||
|  |                                 y = YPos - 9, | ||
|  |                                 z = ZPos - 9 | ||
|  |                             } | ||
|  |                             MapAtt.animation.append(Tbuf); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //背景动画 | ||
|  |                     else if (str == "[background animation]") { | ||
|  |                         MapAtt.backgroundani <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/background animation]") break; | ||
|  |                             if (Ret == "[ani info]") { | ||
|  |                                 local AniBuf = {}; | ||
|  |                                 while (true) { | ||
|  |                                     local Key = UnpackData(FilePos, i); | ||
|  |                                     i += 5; | ||
|  |                                     if (Key == "[/ani info]") break; | ||
|  |                                     local Value = UnpackData(FilePos, i); | ||
|  |                                     i += 5; | ||
|  |                                     if (Key == "[filename]") Value = DirPath + Value.tolower(); | ||
|  |                                     AniBuf[Key] <- Value; | ||
|  |                                 } | ||
|  |                                 MapAtt.backgroundani.append(AniBuf); | ||
|  |                             } | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } else break; | ||
|  |             } | ||
|  | 
 | ||
|  |         } | ||
|  |         return MapAtt; | ||
|  |     } | ||
|  | 
 | ||
|  |     function GetMap(Idx) { | ||
|  |         if (MapLst.rawin(Idx)) { | ||
|  |             local Path = MapLst[Idx]; | ||
|  |             if (MapConfigLst.rawin(Path)) return MapConfigLst[Path]; | ||
|  |             local Pos = 0; | ||
|  |             while (true) { | ||
|  |                 local Buf = Path.find("/", Pos + 1); | ||
|  |                 if (Buf != null) | ||
|  |                     Pos = Buf; | ||
|  |                 else break; | ||
|  |             } | ||
|  |             local DirPath = Path.slice(0, Pos + 1); | ||
|  |             local FileRealName = Path.slice(Pos + 1); | ||
|  |             local Info = GetFileInfo(Path); | ||
|  |             local InfoObj = Decompile_map(DirPath, FileRealName, Info); | ||
|  |             MapConfigLst[Path] <- InfoObj; | ||
|  |             return InfoObj; | ||
|  |         } else error(Idx + " 号地图不存在!"); | ||
|  |     } | ||
|  | 
 | ||
|  |     function Decompile_tile(Info) { | ||
|  |         local TileAtt = {}; | ||
|  |         IO.seek(StartPos + Info.ROffset); | ||
|  |         local FilePos = IO.tell(); | ||
|  |         local out = ""; | ||
|  |         if (Info.Length >= 7) { | ||
|  |             //以5为单步从第二位开始遍历字节 | ||
|  |             local i = 2; | ||
|  |             while (true) { | ||
|  |                 //到最后了就不处理了防止内存越界 | ||
|  |                 if (i< Info.Length && Info.Length - i >= 5) { | ||
|  |                     local str = UnpackData(FilePos, i); | ||
|  |                     i += 5; | ||
|  |                     if (str == "[IMAGE]") { | ||
|  |                         local gpath = "sprite/" + UnpackData(FilePos, i).tolower(); | ||
|  |                         i += 5; | ||
|  |                         local gidx = UnpackData(FilePos, i).tointeger() - 9; | ||
|  |                         i += 5; | ||
|  |                         TileAtt.image <- { | ||
|  |                             path = gpath, | ||
|  |                             idx = gidx | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //偏移 | ||
|  |                     else if (str == "[img pos]") { | ||
|  |                         TileAtt.pos <- UnpackData(FilePos, i).tointeger(); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                 } else break; | ||
|  |             } | ||
|  | 
 | ||
|  |         } | ||
|  |         return TileAtt; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     //读取地板 | ||
|  |     function GetTile(Path) { | ||
|  |         if (TileConfigLst.rawin(Path)) return TileConfigLst[Path]; | ||
|  |         local Info = GetFileInfo(Path); | ||
|  |         local InfoObj = Decompile_tile(Info); | ||
|  |         TileConfigLst[Path] <- InfoObj; | ||
|  |         return InfoObj; | ||
|  |     } | ||
|  | 
 | ||
|  |     function Decompile_passiveobject(DirPath, FileRealName, Info) { | ||
|  |         local PassiveobjectAtt = {}; | ||
|  |         IO.seek(StartPos + Info.ROffset); | ||
|  |         local FilePos = IO.tell(); | ||
|  |         local out = ""; | ||
|  |         if (Info.Length >= 7) { | ||
|  |             //以5为单步从第二位开始遍历字节 | ||
|  |             local i = 2; | ||
|  |             while (true) { | ||
|  |                 //到最后了就不处理了防止内存越界 | ||
|  |                 if (i< Info.Length && Info.Length - i >= 5) { | ||
|  |                     local str = UnpackData(FilePos, i); | ||
|  |                     i += 5; | ||
|  |                     //大小 | ||
|  |                     if (str == "[size]") { | ||
|  |                         local gx = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         local gy = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         PassiveobjectAtt.size <- { | ||
|  |                             x = gx.tointeger(), | ||
|  |                             y = gy.tointeger() | ||
|  |                         }; | ||
|  |                     } | ||
|  |                     //浮动高度 图层 通过类型 名字 | ||
|  |                     else if (str == "[floating height]" || str == "[layer]" || str == "[pass type]" || str == "[name]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         PassiveobjectAtt[RealKey] <- UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //Ani | ||
|  |                     else if (str == "[animotion]") { | ||
|  |                         PassiveobjectAtt.animotion <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/animotion]") break; | ||
|  |                             PassiveobjectAtt.animotion.append(DirPath + Ret.tolower()); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //Atk | ||
|  |                     else if (str == "[attack info]") { | ||
|  |                         PassiveobjectAtt.attackinfo <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/attack info]") break; | ||
|  |                             PassiveobjectAtt.attackinfo.append(DirPath + Ret.tolower()); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //回调函数 | ||
|  |                     else if (str == "[create function]" || str == "[proc function]" || str == "[destroy function]" || str == "[attack function]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         local Path = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         // Path = "sqr/PassiveObjectFunc/" + Path + ".nut"; | ||
|  |                         // PassiveobjectAtt[RealKey] <- dofile(Path); | ||
|  |                         Path = "PassiveObject_" + Path; | ||
|  |                         if (getroottable().PassiveObjectFunction.rawin(Path)) | ||
|  |                             PassiveobjectAtt[RealKey] <- getroottable().PassiveObjectFunction[Path]; | ||
|  |                     } | ||
|  |                 } else break; | ||
|  |             } | ||
|  | 
 | ||
|  |         } | ||
|  |         return PassiveobjectAtt; | ||
|  |     } | ||
|  | 
 | ||
|  |     //获取被动对象 | ||
|  |     function GetPassiveObject(Idx) { | ||
|  |         if (PassiveObjectLst.rawin(Idx)) { | ||
|  |             local Path = PassiveObjectLst[Idx]; | ||
|  |             if (PassiveObjectConfigLst.rawin(Path)) return PassiveObjectConfigLst[Path]; | ||
|  |             local Pos = 0; | ||
|  |             while (true) { | ||
|  |                 local Buf = Path.find("/", Pos + 1); | ||
|  |                 if (Buf != null) | ||
|  |                     Pos = Buf; | ||
|  |                 else break; | ||
|  |             } | ||
|  |             local DirPath = Path.slice(0, Pos + 1); | ||
|  |             local FileRealName = Path.slice(Pos + 1); | ||
|  |             local Info = GetFileInfo(Path); | ||
|  |             local InfoObj = Decompile_passiveobject(DirPath, FileRealName, Info); | ||
|  |             PassiveObjectConfigLst[Path] <- InfoObj; | ||
|  |             return InfoObj; | ||
|  |         } else error(Idx + " 号被动对象不存在!"); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |     function Decompile_character(DirPath, FileRealName, Info) { | ||
|  |         local CharacterAtt = {}; | ||
|  |         IO.seek(StartPos + Info.ROffset); | ||
|  |         local FilePos = IO.tell(); | ||
|  |         local out = ""; | ||
|  |         if (Info.Length >= 7) { | ||
|  |             //以5为单步从第二位开始遍历字节 | ||
|  |             local i = 2; | ||
|  |             while (true) { | ||
|  |                 //到最后了就不处理了防止内存越界 | ||
|  |                 if (i< Info.Length && Info.Length - i >= 5) { | ||
|  |                     local str = UnpackData(FilePos, i); | ||
|  |                     i += 5; | ||
|  | 
 | ||
|  |                     //职业 | ||
|  |                     if (str == "[job]") { | ||
|  |                         local RealKey = str.slice(1, -1); | ||
|  |                         CharacterAtt[RealKey] <- UnpackData(FilePos, i).slice(1, -1); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //基础属性 | ||
|  |                     else if (str == "[HP MAX]]" || str == "[MP MAX]]" || str == "[physical attack]]" || str == "[physical defense]]" || str == "[magical attack]]" || str == "[magical defense]]" || str == "[inventory limit]]" || str == "[MP regen speed]]" || str == "[move speed]]" || str == "[attack speed]]" || str == "[cast speed]]" || str == "[hit recovery]]" || str == "[jump power]]" || str == "[weight]]" || str == "[jump speed]]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         CharacterAtt[RealKey] <- UnpackData(FilePos, i).tofloat(); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //基础Ani | ||
|  |                     else if (str == "[waiting motion]" || str == "[move motion]" || str == "[sit motion]" || str == "[damage motion 1]" || str == "[damage motion 2]" || str == "[down motion]" || str == "[overturn motion]" || str == "[jump motion]" || str == "[jumpattack motion]" || str == "[rest motion]" || str == "[throw motion 1-1]" || str == "[throw motion 1-2]" || str == "[throw motion 2-1]" || str == "[throw motion 2-2]" || str == "[throw motion 3-1]" || str == "[throw motion 3-2]" || str == "[throw motion 4-1]" || str == "[throw motion 4-2]" || str == "[dash motion]" || str == "[dashattack motion]" || str == "[getitem motion]" || str == "[buff motion]" || str == "[simple rest motion]" || str == "[simple move motion]" || str == "[back motion]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         CharacterAtt[RealKey] <- (UnpackData(FilePos, i).tolower()); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //普攻Ani | ||
|  |                     else if (str == "[attack motion]") { | ||
|  |                         CharacterAtt.attack_motion <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/attack motion]") break; | ||
|  |                             CharacterAtt.attack_motion.append(Ret.tolower()); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //进阶Ani | ||
|  |                     else if (str == "[etc motion]") { | ||
|  |                         CharacterAtt.etc_motion <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/etc motion]") break; | ||
|  |                             CharacterAtt.etc_motion.append(Ret.tolower()); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //基础Atk | ||
|  |                     else if (str == "[jumpattack info]" || str == "[dashattack info]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         CharacterAtt[RealKey] <- (DirPath + UnpackData(FilePos, i).tolower()); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //普攻Atk | ||
|  |                     else if (str == "[attack info]") { | ||
|  |                         CharacterAtt.attack_info <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/attack info]") break; | ||
|  |                             CharacterAtt.attack_info.append(DirPath + Ret.tolower()); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //进阶Atk | ||
|  |                     else if (str == "[etc attack info]") { | ||
|  |                         CharacterAtt.etc_attack_info <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/etc attack info]") break; | ||
|  |                             CharacterAtt.etc_attack_info.append(DirPath + Ret.tolower()); | ||
|  |                         } | ||
|  |                     } | ||
|  | 
 | ||
|  |                 } else break; | ||
|  |             } | ||
|  | 
 | ||
|  |         } | ||
|  |         return CharacterAtt; | ||
|  |     } | ||
|  |     //获取角色配置 | ||
|  |     function GetCharacter(Idx) { | ||
|  |         //如果已经读取过配置 直接返回配置 | ||
|  |         if (CharacterConfigLst.rawin(Idx)) return CharacterConfigLst[Idx]; | ||
|  |         if (CharacterLst.rawin(Idx)) { | ||
|  |             local Path = CharacterLst[Idx]; | ||
|  |             local Pos = 0; | ||
|  |             while (true) { | ||
|  |                 local Buf = Path.find("/", Pos + 1); | ||
|  |                 if (Buf != null) | ||
|  |                     Pos = Buf; | ||
|  |                 else break; | ||
|  |             } | ||
|  |             local DirPath = Path.slice(0, Pos + 1); | ||
|  |             local FileRealName = Path.slice(Pos + 1); | ||
|  |             local Info = GetFileInfo(Path); | ||
|  |             local InfoObj = Decompile_character(DirPath, FileRealName, Info); | ||
|  |             InfoObj.DirPath <- DirPath; | ||
|  |             CharacterConfigLst[Idx] <- InfoObj; | ||
|  |             // Util.PrintTable(InfoObj); | ||
|  |             return InfoObj; | ||
|  |         } else error(Idx + " 号角色配置不存在!"); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     function Decompile_equipment(DirPath, FileRealName, Info) { | ||
|  |         local EquipmentAtt = {}; | ||
|  |         IO.seek(StartPos + Info.ROffset); | ||
|  |         local FilePos = IO.tell(); | ||
|  |         local out = ""; | ||
|  |         if (Info.Length >= 7) { | ||
|  |             //以5为单步从第二位开始遍历字节 | ||
|  |             local i = 2; | ||
|  |             while (true) { | ||
|  |                 //到最后了就不处理了防止内存越界 | ||
|  |                 if (i< Info.Length && Info.Length - i >= 5) { | ||
|  |                     local str = UnpackData(FilePos, i); | ||
|  |                     i += 5; | ||
|  | 
 | ||
|  |                     //名称 | ||
|  |                     if (str == "[name]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         EquipmentAtt[RealKey] <- UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //grade 套装Id | ||
|  |                     else if (str == "[grade]" || str == "[part set index]" || str == "[anti evil]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         EquipmentAtt[RealKey] <- UnpackData(FilePos, i).tointeger() - 9; | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //适用角色 | ||
|  |                     else if (str == "[usable job]") { | ||
|  |                         EquipmentAtt.usable_job <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/usable job]") break; | ||
|  |                             EquipmentAtt.usable_job.append(Ret.slice(1, -1).tolower()); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //图标 | ||
|  |                     else if (str == "[icon]") { | ||
|  |                         EquipmentAtt.icon <- {}; | ||
|  |                         local Ret = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         EquipmentAtt.icon.path <- Ret.tolower(); | ||
|  |                         Ret = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         EquipmentAtt.icon.index <- Ret.tointeger(); | ||
|  |                     } | ||
|  |                     //装备类型 | ||
|  |                     else if (str == "[equipment type]") { | ||
|  |                         EquipmentAtt.type <- {}; | ||
|  |                         local Ret = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         EquipmentAtt.type.path <- Ret.tolower().slice(1, -1); | ||
|  |                         Ret = UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                         EquipmentAtt.type.index <- Ret.tointeger(); | ||
|  |                     } | ||
|  |                     //Ani | ||
|  |                     else if (str == "[animation job]") { | ||
|  |                         local Job = UnpackData(FilePos, i).slice(1, -1); | ||
|  |                         i += 5; | ||
|  |                         EquipmentAtt["Ani_" + Job] <- {}; | ||
|  |                         i += 5; | ||
|  | 
 | ||
|  |                         local Index1 = UnpackData(FilePos, i).tointeger() - 9; | ||
|  |                         i += 5; | ||
|  |                         local Index2 = UnpackData(FilePos, i).tointeger() - 9; | ||
|  |                         i += 5; | ||
|  |                         EquipmentAtt["Ani_" + Job].variation <- [Index1, Index2]; | ||
|  |                         EquipmentAtt["Ani_" + Job].layer_variation <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[animation job]" || (endswith(Ret, "]") && Ret != "[equipment ani script]" && Ret != "[layer variation]")) { | ||
|  |                                 i -= 5; | ||
|  |                                 break; | ||
|  |                             } else if (Ret == "[layer variation]") { | ||
|  |                                 local InfoBuf = {}; | ||
|  |                                 InfoBuf.Zorder <- UnpackData(FilePos, i).tointeger() - 9; | ||
|  |                                 i += 5; | ||
|  |                                 InfoBuf.Path <- UnpackData(FilePos, i); | ||
|  |                                 i += 5; | ||
|  |                                 EquipmentAtt["Ani_" + Job].layer_variation.append(InfoBuf); | ||
|  |                             } | ||
|  |                         } | ||
|  |                     } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |                 } else break; | ||
|  |             } | ||
|  | 
 | ||
|  |         } | ||
|  |         return EquipmentAtt; | ||
|  |     } | ||
|  | 
 | ||
|  |     //获取装备配置 | ||
|  |     function GetEquipment(Idx) { | ||
|  |         //如果已经读取过配置 直接返回配置 | ||
|  |         if (EquipmentConfigLst.rawin(Idx)) return EquipmentConfigLst[Idx]; | ||
|  |         if (EquipmentLst.rawin(Idx)) { | ||
|  |             local Path = EquipmentLst[Idx]; | ||
|  |             local Pos = 0; | ||
|  |             while (true) { | ||
|  |                 local Buf = Path.find("/", Pos + 1); | ||
|  |                 if (Buf != null) | ||
|  |                     Pos = Buf; | ||
|  |                 else break; | ||
|  |             } | ||
|  |             local DirPath = Path.slice(0, Pos + 1); | ||
|  |             local FileRealName = Path.slice(Pos + 1); | ||
|  |             local Info = GetFileInfo(Path); | ||
|  |             local InfoObj = Decompile_equipment(DirPath, FileRealName, Info); | ||
|  |             InfoObj.DirPath <- DirPath; | ||
|  |             EquipmentConfigLst[Idx] <- InfoObj; | ||
|  |             // Util.PrintTable(InfoObj); | ||
|  |             return InfoObj; | ||
|  |         } else error(Idx + " 号装备配置不存在!"); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     function Decompile_aicharacter(DirPath, FileRealName, Info) { | ||
|  |         local AICharacterAtt = {}; | ||
|  |         //属性表 | ||
|  |         AICharacterAtt.Attributes <- {}; | ||
|  |         IO.seek(StartPos + Info.ROffset); | ||
|  |         local FilePos = IO.tell(); | ||
|  |         local out = ""; | ||
|  |         if (Info.Length >= 7) { | ||
|  |             //以5为单步从第二位开始遍历字节 | ||
|  |             local i = 2; | ||
|  |             while (true) { | ||
|  |                 //到最后了就不处理了防止内存越界 | ||
|  |                 if (i< Info.Length && Info.Length - i >= 5) { | ||
|  |                     local str = UnpackData(FilePos, i); | ||
|  |                     i += 5; | ||
|  | 
 | ||
|  |                     //名称 | ||
|  |                     if (str == "[name]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         AICharacterAtt[RealKey] <- UnpackData(FilePos, i); | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //属性 | ||
|  |                     else if (str == "[HpMax]" || str == "[Attack]" || str == "[Speed]" || str == "[Defense]" || str == "[DeployCost]" || str == "[Resilience]" || str == "[FirePower]" || str == "[IcePower]" || str == "[LightningPower]" || str == "[DarkPower]" || str == "[FireResistance]" || str == "[IceResistance]" || str == "[LightningResistance]" || str == "[DarkResistance]") { | ||
|  |                         local RealKey = str.slice(1, str.len() - 1); | ||
|  |                         AICharacterAtt.Attributes[RealKey] <- UnpackData(FilePos, i).tointeger() - 9; | ||
|  |                         i += 5; | ||
|  |                     } | ||
|  |                     //装备 | ||
|  |                     else if (str == "[equipment]") { | ||
|  |                         AICharacterAtt.equipment <- []; | ||
|  |                         while (true) { | ||
|  |                             local Ret = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (Ret == "[/equipment]") break; | ||
|  |                             AICharacterAtt.equipment.append(Ret.tointeger() - 9); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     //基础信息 | ||
|  |                     else if (str == "[minimum info]") { | ||
|  |                         AICharacterAtt["minimum info"] <- []; | ||
|  |                         for (local o = 0; o< 16; o++) { | ||
|  |                             local Buf = UnpackData(FilePos, i); | ||
|  |                             i += 5; | ||
|  |                             if (o == 0 || o == 12) { | ||
|  |                                 AICharacterAtt["minimum info"].append(Buf); | ||
|  |                             } else { | ||
|  |                                 AICharacterAtt["minimum info"].append(Buf.tointeger() - 9); | ||
|  |                             } | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } else break; | ||
|  |             } | ||
|  | 
 | ||
|  |         } | ||
|  |         return AICharacterAtt; | ||
|  |     } | ||
|  | 
 | ||
|  |     //获取APC配置 | ||
|  |     function GetAICharacter(Idx) { | ||
|  |         //如果已经读取过配置 直接返回配置 | ||
|  |         if (AICharacterConfigLst.rawin(Idx)) return AICharacterConfigLst[Idx]; | ||
|  |         if (AICharacterLst.rawin(Idx)) { | ||
|  |             local Path = AICharacterLst[Idx]; | ||
|  |             local Pos = 0; | ||
|  |             while (true) { | ||
|  |                 local Buf = Path.find("/", Pos + 1); | ||
|  |                 if (Buf != null) | ||
|  |                     Pos = Buf; | ||
|  |                 else break; | ||
|  |             } | ||
|  |             local DirPath = Path.slice(0, Pos + 1); | ||
|  |             local FileRealName = Path.slice(Pos + 1); | ||
|  |             local Info = GetFileInfo(Path); | ||
|  |             local InfoObj = Decompile_aicharacter(DirPath, FileRealName, Info); | ||
|  |             InfoObj.DirPath <- DirPath; | ||
|  |             AICharacterConfigLst[Idx] <- InfoObj; | ||
|  |             // Util.PrintTable(InfoObj); | ||
|  |             return InfoObj; | ||
|  |         } else error(Idx + " 号APC配置不存在!"); | ||
|  |     } | ||
|  | 
 | ||
|  | } | ||
|  | getroottable().ScriptData <- GlobaData(); |