text: from Assembler.Assembler2 import *
  from Base.ED6FCBase import *
  import Instruction.ScenaOpTableED6FC as ed6fc
  
  ExtractText = not True
  # ed6fc.CODE_PAGE = '932'
  # CODE_PAGE = ed6fc.CODE_PAGE
  
  NUMBER_OF_INCLUDE_FILE  = 8
  
  SCN_INFO_CHIP           = 0
  SCN_INFO_CHIP_PAT       = 1
  SCN_INFO_NPC            = 2
  SCN_INFO_MONSTER        = 3
  SCN_INFO_EVENT          = 4
  SCN_INFO_ACTOR          = 5
  SCN_INFO_MAXIMUM        = 6
  
  textPosTable = OrderedDict()
  replaceOption = {}
  
  class ScenarioEntry:
      def __init__(self, offset = 0, size = 0):
          self.Offset = offset
          self.Size = size
  
  class ScenarioEntryPoint:
      def __init__(self, fs = None):
          # size = 0x44
  
          if fs is None:
              fs = fileio.FileStream(b'\x00' * 0x44)
  
          self.Unknown_00         = fs.ReadLong()
          self.Unknown_04         = fs.ReadLong()
          self.Unknown_08         = fs.ReadLong()
          self.Unknown_0C         = fs.ReadUShort()
          self.Unknown_0E         = fs.ReadUShort()
          self.Unknown_10         = fs.ReadLong()
          self.Unknown_14         = fs.ReadLong()
          self.Unknown_18         = fs.ReadLong()
          self.Unknown_1C         = fs.ReadLong()
          self.Unknown_20         = fs.ReadLong()
          self.Unknown_24         = fs.ReadLong()
          self.Unknown_28         = fs.ReadLong()
          self.Unknown_2C         = fs.ReadLong()
          self.Unknown_30         = fs.ReadUShort()
          self.Unknown_32         = fs.ReadUShort()
          self.Unknown_34         = fs.ReadUShort()
          self.Unknown_36         = fs.ReadUShort()
          self.Unknown_38         = fs.ReadUShort()
          self.Unknown_3A         = fs.ReadUShort()
          self.InitScenaIndex     = fs.ReadUShort()
          self.InitFunctionIndex  = fs.ReadUShort()        # byte
          self.EntryScenaIndex    = fs.ReadUShort()
          self.EntryFunctionIndex = fs.ReadUShort()       # byte
  
      def params(self):
          align = 24
          return [
              '%s %s,' % (alignFormatKw(align, 'Unknown_00'),         self.Unknown_00),
              '%s %s,' % (alignFormatKw(align, 'Unknown_04'),         self.Unknown_04),
              '%s %s,' % (alignFormatKw(align, 'Unknown_08'),         self.Unknown_08),
              '%s %s,' % (alignFormatKw(align, 'Unknown_0C'),         self.Unknown_0C),
              '%s %s,' % (alignFormatKw(align, 'Unknown_0E'),         self.Unknown_0E),
              '%s %s,' % (alignFormatKw(align, 'Unknown_10'),         self.Unknown_10),
              '%s %s,' % (alignFormatKw(align, 'Unknown_14'),         self.Unknown_14),
              '%s %s,' % (alignFormatKw(align, 'Unknown_18'),         self.Unknown_18),
              '%s %s,' % (alignFormatKw(align, 'Unknown_1C'),         self.Unknown_1C),
              '%s %s,' % (alignFormatKw(align, 'Unknown_20'),         self.Unknown_20),
              '%s %s,' % (alignFormatKw(align, 'Unknown_24'),         self.Unknown_24),
              '%s %s,' % (alignFormatKw(align, 'Unknown_28'),         self.Unknown_28),
              '%s %s,' % (alignFormatKw(align, 'Unknown_2C'),         self.Unknown_2C),
              '%s %s,' % (alignFormatKw(align, 'Unknown_30'),         self.Unknown_30),
              '%s %s,' % (alignFormatKw(align, 'Unknown_32'),         self.Unknown_32),
              '%s %s,' % (alignFormatKw(align, 'Unknown_34'),         self.Unknown_34),
              '%s %s,' % (alignFormatKw(align, 'Unknown_36'),         self.Unknown_36),
              '%s %s,' % (alignFormatKw(align, 'Unknown_38'),         self.Unknown_38),
              '%s %s,' % (alignFormatKw(align, 'Unknown_3A'),         self.Unknown_3A),
              '%s %s,' % (alignFormatKw(align, 'InitScenaIndex'),     self.InitScenaIndex),
              '%s %s,' % (alignFormatKw(align, 'InitFunctionIndex'),  self.InitFunctionIndex),
              '%s %s,' % (alignFormatKw(align, 'EntryScenaIndex'),    self.EntryScenaIndex),
              '%s %s,' % (alignFormatKw(align, 'EntryFunctionIndex'), self.EntryFunctionIndex),
          ]
  
      def binary(self):
          return struct.pack('<LLLHHLLLLLLLLHHHHHHHHHH',
                      ULONG(self.Unknown_00).value,
                      ULONG(self.Unknown_04).value,
                      ULONG(self.Unknown_08).value,
                      USHORT(self.Unknown_0C).value,
                      USHORT(self.Unknown_0E).value,
                      ULONG(self.Unknown_10).value,
                      ULONG(self.Unknown_14).value,
                      ULONG(self.Unknown_18).value,
                      ULONG(self.Unknown_1C).value,
                      ULONG(self.Unknown_20).value,
                      ULONG(self.Unknown_24).value,
                      ULONG(self.Unknown_28).value,
                      ULONG(self.Unknown_2C).value,
                      USHORT(self.Unknown_30).value,
                      USHORT(self.Unknown_32).value,
                      USHORT(self.Unknown_34).value,
                      USHORT(self.Unknown_36).value,
                      USHORT(self.Unknown_38).value,
                      USHORT(self.Unknown_3A).value,
                      USHORT(self.InitScenaIndex).value,
                      USHORT(self.InitFunctionIndex).value,
                      USHORT(self.EntryScenaIndex).value,
                      USHORT(self.EntryFunctionIndex).value,
                  )
  
  class ScenarioNpcInfo:
      def __init__(self, fs = None):
          # size = 0x20
          if fs is None:
              fs = fileio.FileStream(b'\x00' * 0x20)
  
          self.X                  = fs.ReadULong()
          self.Z                  = fs.ReadULong()
          self.Y                  = fs.ReadULong()
          self.Direction          = fs.ReadUShort()   # 0 90 270 360
          self.Unknown2           = fs.ReadUShort()
          self.Unknown3           = fs.ReadULong()
  
          self.ChipIndex          = fs.ReadUShort()
          self.NpcIndex           = fs.ReadUShort()
  
          self.InitFunctionIndex  = fs.ReadUShort()
          self.InitScenaIndex     = fs.ReadUShort()
          self.TalkFunctionIndex  = fs.ReadUShort()
          self.TalkScenaIndex     = fs.ReadUShort()
  
      def __str__(self):
          return str(self.binary())
  
      def params(self):
          align = 20
          return [
              '%s %d,'   % (alignFormatKw(align, 'X'),                  LONG(self.X).value),
              '%s %d,'   % (alignFormatKw(align, 'Z'),                  LONG(self.Z).value),
              '%s %d,'   % (alignFormatKw(align, 'Y'),                  LONG(self.Y).value),
              '%s %d,'   % (alignFormatKw(align, 'Direction'),          LONG(self.Direction).value),
              '%s %s,'   % (alignFormatKw(align, 'Unknown2'),           SHORT(self.Unknown2).value),
              '%s %s,'   % (alignFormatKw(align, 'Unknown3'),           LONG(self.Unknown3).value),
              '%s 0x%X,' % (alignFormatKw(align, 'ChipIndex'),        SHORT(self.ChipIndex).value),
              '%s 0x%X,' % (alignFormatKw(align, 'NpcIndex'),         SHORT(self.NpcIndex).value),
              '%s %s,'   % (alignFormatKw(align, 'InitFunctionIndex'),  SHORT(self.InitFunctionIndex).value),
              '%s %s,'   % (alignFormatKw(align, 'InitScenaIndex'),     SHORT(self.InitScenaIndex).value),
              '%s %s,'   % (alignFormatKw(align, 'TalkFunctionIndex'),  SHORT(self.TalkFunctionIndex).value),
              '%s %s,'   % (alignFormatKw(align, 'TalkScenaIndex'),     SHORT(self.TalkScenaIndex).value),
          ]
  
      def binary(self):
          return struct.pack('<LLLHHLHHHHHH',
                      ULONG(self.X).value,
                      ULONG(self.Z).value,
                      ULONG(self.Y).value,
                      USHORT(self.Direction).value,
                      USHORT(self.Unknown2).value,
                      ULONG(self.Unknown3).value,
                      USHORT(self.ChipIndex).value,
                      USHORT(self.NpcIndex).value,
                      USHORT(self.InitFunctionIndex).value,
                      USHORT(self.InitScenaIndex).value,
                      USHORT(self.TalkFunctionIndex).value,
                      USHORT(self.TalkScenaIndex).value,
                  )
  
  class ScenarioMonsterInfo:
      def __init__(self, fs = None):
          # size = 0x1C
          if fs is None:
              fs = fileio.FileStream(b'\x00' * 0x1C)
  
          self.X                      = fs.ReadLong()
          self.Z                      = fs.ReadLong()
          self.Y                      = fs.ReadLong()
          self.Unknown_0C             = fs.ReadUShort()
          self.Unknown_0E             = fs.ReadUShort()
          self.Unknown_10             = fs.ReadByte()
          self.Unknown_11             = fs.ReadByte()
          self.Unknown_12             = fs.ReadULong()
          self.BattleIndex            = fs.ReadUShort()
          self.Unknown_18             = fs.ReadUShort()
          self.Unknown_1A             = fs.ReadUShort()
  
      def __str__(self):
          return str(self.binary())
  
      def params(self):
          align = 20
          return [
              '%s %d,'   % (alignFormatKw(align, 'X'),           self.X),
              '%s %d,'   % (alignFormatKw(align, 'Z'),           self.Z),
              '%s %d,'   % (alignFormatKw(align, 'Y'),           self.Y),
              '%s %d,'   % (alignFormatKw(align, 'Unknown_0C'),  self.Unknown_0C),
              '%s %d,'   % (alignFormatKw(align, 'Unknown_0E'),  self.Unknown_0E),
              '%s %d,'   % (alignFormatKw(align, 'Unknown_10'),  self.Unknown_10),
              '%s %d,'   % (alignFormatKw(align, 'Unknown_11'),  self.Unknown_11),
              '%s 0x%X,' % (alignFormatKw(align, 'Unknown_12'),  self.Unknown_12),
              '%s 0x%X,' % (alignFormatKw(align, 'BattleIndex'), self.BattleIndex),
              '%s %d,'   % (alignFormatKw(align, 'Unknown_18'),  self.Unknown_18),
              '%s %d,'   % (alignFormatKw(align, 'Unknown_1A'),  self.Unknown_1A),
          ]
  
      def binary(self):
          return struct.pack('<LLLHHBBLHHH',
                      ULONG(self.X).value,
                      ULONG(self.Z).value,
                      ULONG(self.Y).value,
                      USHORT(self.Unknown_0C).value,
                      USHORT(self.Unknown_0E).value,
                      BYTE(self.Unknown_10).value,
                      BYTE(self.Unknown_11).value,
                      ULONG(self.Unknown_12).value,
                      USHORT(self.BattleIndex).value,
                      USHORT(self.Unknown_18).value,
                      USHORT(self.Unknown_1A).value,
                  )
  
  class ScenarioEventInfo:
      def __init__(self, fs = None):
          # size = 0x20
  
          if fs is None:
              fs = fileio.FileStream(b'\x00' * 0x20)
  
          self.X              = fs.ReadLong()
          self.Y              = fs.ReadLong()
          self.Z              = fs.ReadLong()
          self.Range          = fs.ReadLong()
          self.Unknown_10     = fs.ReadULong()
          self.Unknown_14     = fs.ReadULong()
          self.Unknown_18     = fs.ReadULong()
          self.Unknown_1C     = fs.ReadULong()
  
      def __str__(self):
         return str(self.binary())
  
      def params(self):
          align = 20
          return [
              '%s %d,'   % (alignFormatKw(align, 'X'),            self.X),
              '%s %d,'   % (alignFormatKw(align, 'Y'),            self.Y),
              '%s %d,'   % (alignFormatKw(align, 'Z'),            self.Z),
              '%s %d,'   % (alignFormatKw(align, 'Range'),        self.Range),
              '%s 0x%X,' % (alignFormatKw(align, 'Unknown_10'),   self.Unknown_10),
              '%s 0x%X,' % (alignFormatKw(align, 'Unknown_14'),   self.Unknown_14),
              '%s 0x%X,' % (alignFormatKw(align, 'Unknown_18'),   self.Unknown_18),
              '%s %d,'   % (alignFormatKw(align, 'Unknown_1C'),   self.Unknown_1C),
          ]
  
      def binary(self):
          return struct.pack('<LLLLLLLL',
                      ULONG(self.X).value,
                      ULONG(self.Y).value,
                      ULONG(self.Z).value,
                      ULONG(self.Range).value,
                      ULONG(self.Unknown_10).value,
                      ULONG(self.Unknown_14).value,
                      ULONG(self.Unknown_18).value,
                      ULONG(self.Unknown_1C).value,
                  )
  
  class ScenarioActorInfo:
      def __init__(self, fs = None):
          # size = 0x24
          if fs is None:
              fs = fileio.FileStream(b'\x00' * 0x24)
  
          self.TriggerX           = fs.ReadULong()
          self.TriggerZ           = fs.ReadULong()
          self.TriggerY           = fs.ReadULong()
          self.TriggerRange       = fs.ReadULong()
          self.ActorX             = fs.ReadULong()
          self.ActorZ             = fs.ReadULong()
          self.ActorY             = fs.ReadULong()
          self.Flags              = fs.ReadUShort()
          self.TalkScenaIndex     = fs.ReadUShort()
          self.TalkFunctionIndex  = fs.ReadUShort()
          self.Unknown_22         = fs.ReadUShort()
  
      def __str__(self):
          return str(self.Binary)
  
      def params(self):
          align = 20
          p = [
              '%s %d,' % (alignFormatKw(align, 'TriggerX'),           LONG(self.TriggerX).value),
              '%s %d,' % (alignFormatKw(align, 'TriggerZ'),           LONG(self.TriggerZ).value),
              '%s %d,' % (alignFormatKw(align, 'TriggerY'),           LONG(self.TriggerY).value),
              '%s %d,' % (alignFormatKw(align, 'TriggerRange'),       LONG(self.TriggerRange).value),
              '%s %s,' % (alignFormatKw(align, 'ActorX'),             LONG(self.ActorX).value),
              '%s %s,' % (alignFormatKw(align, 'ActorZ'),             LONG(self.ActorZ).value),
              '%s %s,' % (alignFormatKw(align, 'ActorY'),             LONG(self.ActorY).value),
              '%s 0x%X,' % (alignFormatKw(align, 'Flags'),            USHORT(self.Flags).value),
              '%s %s,' % (alignFormatKw(align, 'TalkScenaIndex'),     SHORT(self.TalkScenaIndex).value),
              '%s %s,' % (alignFormatKw(align, 'TalkFunctionIndex'),  SHORT(self.TalkFunctionIndex).value),
              '%s %s,' % (alignFormatKw(align, 'Unknown_22'),         USHORT(self.Unknown_22).value),
          ]
  
          return p
  
      def param(self):
          p = '%d, %d, %d, %d, %d, %d, %d, 0x%04X, %d, %d, 0x%04X' % (
                      LONG(self.TriggerX).value,
                      LONG(self.TriggerZ).value,
                      LONG(self.TriggerY).value,
                      LONG(self.TriggerRange).value,
                      LONG(self.ActorX).value,
                      LONG(self.ActorZ).value,
                      LONG(self.ActorY).value,
  
                      USHORT(self.Flags).value,
                      USHORT(self.TalkScenaIndex).value,
                      USHORT(self.TalkFunctionIndex).value,
                      USHORT(self.Unknown_22).value,
                  )
  
          space = [9, 9, 9, 9, 9, 9, 9, 4, 4, 4, 4]
          return AdjustParam(p, space)
  
      def binary(self):
          return struct.pack('<lllllllHHHH',
                      LONG(self.TriggerX).value,
                      LONG(self.TriggerZ).value,
                      LONG(self.TriggerY).value,
                      LONG(self.TriggerRange).value,
                      LONG(self.ActorX).value,
                      LONG(self.ActorZ).value,
                      LONG(self.ActorY).value,
  
                      USHORT(self.Flags).value,
                      USHORT(self.TalkScenaIndex).value,
                      USHORT(self.TalkFunctionIndex).value,
                      USHORT(self.Unknown_22).value
                  )
  
  class ScenarioInfo:
      def __init__(self):
          # file header
  
          self.MapName                    = ''
          self.Location                   = ''
          self.MapIndex                   = 0
          self.MapDefaultBGM              = -1
          self.Flags                      = 0
          self.IncludedScenario           = []
          self.StringTableOffset          = 0
          self.ScnInfoOffset              = [0] * SCN_INFO_MAXIMUM
          self.ScenaFunctionTable         = ScenarioEntry()
          self.ChipFrameInfoOffset        = 0
          self.PlaceNameOffset            = 0
          self.PlaceNameNumber            = 0
          self.PreInitFunctionIndex       = 0
          self.ScnInfoNumber              = [0] * SCN_INFO_MAXIMUM
  
          # file header end
  
          self.ScenaFunctions     = []
          self.PlaceName          = ''
          self.StringTable        = []
          self.ScnInfo            = []
          self.CodeBlocks         = []
  
          self.GlobalLabelTable   = {}
  
          for i in range(SCN_INFO_MAXIMUM):
              self.ScnInfo.append([])
              #self.ScnInfoOffset.append(0)
              #self.ScnInfoNumber.append(0)
  
      def binary(self):
          buffer = fileio.FileStream(b'')
  
          buffer.Write(self.MapName.encode(ed6fc.CODE_PAGE).ljust(0xA, b'\x00')[:0xA])
          buffer.Write(self.Location.encode(ed6fc.CODE_PAGE).ljust(0xE, b'\x00')[:0xE])
          buffer.WriteUShort(self.MapIndex)
          buffer.WriteUShort(self.MapDefaultBGM.Index())
          buffer.WriteUShort(self.Flags)
          buffer.WriteUShort(self.EntryFunctionIndex)
  
          for inc in self.IncludedScenario:
              buffer.WriteULong(inc)
  
          buffer.WriteUShort(self.Reserved)
  
          for i in range(len(self.ScnInfoOffset)):
              buffer.WriteUShort(self.ScnInfoOffset[i])
              buffer.WriteUShort(self.ScnInfoNumber[i])
  
          buffer.WriteUShort(self.StringTableOffset)
          buffer.WriteULong(self.HeaderEndOffset)
  
          buffer.WriteUShort(self.ScenaFunctionTable.Offset)
          buffer.WriteUShort(self.ScenaFunctionTable.Size)
  
          buffer.Position = 0
  
          return buffer.Read()
  
      def open(self, scenafile):
          fs = fileio.FileStream(scenafile)
          if fs.Length == 0:
              return False
  
          self.InitMapNameList(scenafile)
  
          self.scenaName = os.path.splitext(os.path.basename(scenafile))[0].strip().upper()
          self.scenaTextIndex = 1
  
          # file header
  
          self.MapName            = fs.read(0xA).decode(ed6fc.CODE_PAGE).split('\x00', 1)[0]
          self.Location           = fs.read(0xE).decode(ed6fc.CODE_PAGE).split('\x00', 1)[0]
          self.MapIndex           = fs.ReadUShort()
          self.MapDefaultBGM      = BGMFileIndex(fs.ReadUShort())
          self.Flags              = fs.ReadUShort()
          self.EntryFunctionIndex = fs.ReadUShort()
          self.IncludedScenario   = list(struct.unpack('<' + 'I' * NUMBER_OF_INCLUDE_FILE, fs.read(NUMBER_OF_INCLUDE_FILE * 4)))
          self.Reserved           = fs.ReadUShort()
          self.ScnInfoOffset      = [ScenarioEntry(fs.ReadUShort(), fs.ReadUShort()) for _ in range(SCN_INFO_MAXIMUM)]
          self.StringTableOffset  = fs.ReadUShort()
          self.HeaderEndOffset    = fs.ReadULong()
          self.ScenaFunctionTable = ScenarioEntry(fs.ReadUShort(), fs.ReadUShort())
  
          self.IncludedScenario.index(0xFFFFFFFF)
  
          self.EntryPoint = [ScenarioEntryPoint(fs) for i in range((self.ScnInfoOffset[0].Offset - fs.Position) // 0x44)]
  
          # file header end
  
          self.InitScenaInfo(fs)
          self.InitOtherInfo(fs)
  
          self.CodeBlocks = self.DisassembleBlocks(fs)
  
  
      def InitMapNameList(self, scenafile):
          self.MapNameList = []
  
          try:
              t_town = os.path.abspath(os.path.join(GAME_PATH, 'ED6_DT02\\T_TOWN  ._DT'))
              town = fileio.FileStream(t_town)
  
              offsetlist = []
              for i in range(town.ReadUShort()):
                  offsetlist.append(town.ReadUShort())
  
              for offset in offsetlist:
                  town.seek(offset)
                  self.MapNameList.append(town.ReadMultiByte('GBK'))
  
          except:
              self.MapNameList = []
  
      def GetMapNameByIndex(self, index):
          if self.MapName.startswith('map'):
              return '调试地图'
  
          if index == 1:
              return {
                  'rolent'    : '洛连特',
                  'zeiss'     : '蔡斯',
                  'grancel'   : '格兰赛尔',
                  'ruan'      : '卢安',
                  'bose'      : '柏斯',
              }.get(self.MapName.lower(), '')
  
          if index >= len(self.MapNameList):
              return ''
  
          return self.MapNameList[index]
  
      def InitScenaInfo(self, fs):
          ScnInfoTypes = \
          [
              ScenarioChipInfo,
              ScenarioChipInfo,
              ScenarioNpcInfo,
              ScenarioMonsterInfo,
              ScenarioEventInfo,
              ScenarioActorInfo,
          ]
  
          for i in range(len(self.ScnInfoOffset)):
              fs.seek(self.ScnInfoOffset[i].Offset)
              ScnInfoType = ScnInfoTypes[i]
              for n in range(self.ScnInfoOffset[i].Size):
                  self.ScnInfo[i].append(ScnInfoType(fs))
  
      def InitOtherInfo(self, fs):
          fs.seek(self.ScenaFunctionTable.Offset)
          self.ScenaFunctions = list(struct.unpack('<' + 'H' * int(self.ScenaFunctionTable.Size / 2), fs.read(self.ScenaFunctionTable.Size)))
  
          fs.seek(self.StringTableOffset)
  
          buf = fs.read()
          #endmz = buf.find(b'\x00\x00')
          #if endmz != -1:
          #    buf = buf[:endmz]
  
          if len(buf) > 0 and buf[-1] == 0:
              buf = buf[0:-1]
  
          self.StringTable = buf.decode(ed6fc.CODE_PAGE).split('\x00')
  
          if ExtractText:
              textPosTable[self.scenaName] = [self.StringTable]
          else:
              try:
                  strtbl = textPosTable[self.scenaName][0]
                  if len(strtbl) != len(self.StringTable):
                      raise Exception('%s\n\n%s' % (strtbl, self.StringTable))
                  self.StringTable = strtbl
              except KeyError:
                  pass
  
      def DiasmInstructionCallback(self, data):
          if data.Reason != HANDLER_REASON_DISASM:
              return
  
          inst, fs = data.Instruction, data.FileStream
  
          if inst.OpCode == ed6fc.SetPlaceName:
              self.PlaceName = self.GetMapNameByIndex(inst.Operand[0])
  
          if inst.OpCode not in [
                  ed6fc.ChrTalk,
                  ed6fc.AnonymousTalk,
                  ed6fc.NpcTalk,
                  ed6fc.Menu,
                  ed6fc.SetChrName
              ]:
              return
  
          if ExtractText:
              if inst.OpCode == ed6fc.ChrTalk:
                  text = inst.Operand[1]
                  textPosTable[self.scenaName].append([s.dump() for s in text])
  
              elif inst.OpCode == ed6fc.AnonymousTalk:
                  text = inst.Operand[0]
                  textPosTable[self.scenaName].append([s.dump() for s in text])
  
              elif inst.OpCode == ed6fc.NpcTalk:
                  for text in inst.Operand[1:]:
                      textPosTable[self.scenaName].append([s.dump() for s in text])
  
              elif inst.OpCode in [ed6fc.Menu, ed6fc.SetChrName]:
                  text = inst.Operand[-1]
                  textPosTable[self.scenaName].append([s.dump() for s in text])
  
          else:
              try:
                  cntext = textPosTable[self.scenaName]
              except KeyError:
                  return
  
              try:
                  ignoreText = replaceOption[self.scenaName]['text']
              except KeyError:
                  ignoreText = None
  
              def checkIgnore(oprlist):
                  if ignoreText is None:
                      return
  
                  for i in oprlist:
                      for string in inst.Operand[i]:
                          string = str(string)
                          for t in ignoreText:
                              if t in string:
                                  return True
  
                  return False
  
              if inst.OpCode == ed6fc.ChrTalk:
                  if checkIgnore([1]):
                      return
  
                  inst.Operand[1] = self.loadScpStringList(cntext[self.scenaTextIndex])
  
              elif inst.OpCode == ed6fc.AnonymousTalk:
                  if checkIgnore([0]):
                      return
  
                  inst.Operand[0] = self.loadScpStringList(cntext[self.scenaTextIndex])
  
              elif inst.OpCode == ed6fc.NpcTalk:
                  if checkIgnore([1, 2]):
                      return
  
                  inst.Operand[1] = self.loadScpStringList(cntext[self.scenaTextIndex])
                  inst.Operand[2] = self.loadScpStringList(cntext[self.scenaTextIndex + 1])
                  self.scenaTextIndex += 1
  
              elif inst.OpCode in [ed6fc.Menu, ed6fc.SetChrName]:
                  if checkIgnore([-1]):
                      return
  
                  inst.Operand[-1] = self.loadScpStringList(cntext[self.scenaTextIndex])
  
              self.scenaTextIndex += 1
  
      def loadScpStringList(self, paramList):
          return [ed6fc.ScpString(**p) for p in paramList]
  
      def DisassembleBlocks(self, fs):
          disasm = Disassembler(ed6fc.ed6fc_op_table, self.DiasmInstructionCallback)
  
          index = -1
          codeblocks = []
          blockoffsetmap = {}
          for func in self.ScenaFunctions:
              index += 1
              plog('Function_%d_%X' % (index, func))
              if func in blockoffsetmap:
                  codeblocks.append(blockoffsetmap[func])
                  continue
  
              fs.seek(func)
  
              data = Disassembler.DisasmData()
              data.Stream = fs
              data.GlobalLabelTable = self.GlobalLabelTable
  
              block = disasm.DisasmBlock2(data)
  
              block.Name = 'Function_%d_%X' % (index, block.Offset) if not USE_INDEX_LABEL_NAME else 'Function_%d' % index
              codeblocks.append(block)
  
              blockoffsetmap[func] = block
  
          #for i in range(fs.size()): if i not in offsetlist: print('%X' % i)
          #input()
  
          return codeblocks
  
      def GenerateFunctionLabelList(self, blocks):
          l = []
          for block in blocks:
              l.append(block.Name)
              l += self.GenerateFunctionLabelList(block.CodeBlocks)
  
          return l
  
      def FormatInstructionCallback(self, data, text):
          if data.Instruction.OpCode == ed6fc.SetPlaceName and self.PlaceName:
              return [text[0] + ' # ' + self.PlaceName]
  
      def FormatCodeBlocks(self):
          ed6fc.ed6fc_op_table.FunctionLabelList = self.GenerateFunctionLabelList(self.CodeBlocks)
          disasm = Disassembler(ed6fc.ed6fc_op_table, self.FormatInstructionCallback)
  
          blocks = []
          blockoffsetmap = {}
  
          for block in self.CodeBlocks:
              if block.Offset in blockoffsetmap:
                  continue
  
              blockoffsetmap[block.Offset] = True
  
              data = Disassembler.FormatData()
  
              data.Block = block
              data.GlobalLabelTable = self.GlobalLabelTable
  
              blocks.append(['def %s(): pass' % block.Name])
              blocks.append(disasm.FormatCodeBlock2(data))
  
          #for x in disasmtbl: print('%08X' % x)
          #input()
  
          return blocks
  
      def GenerateStringList(self):
  
          lines = []
  
          if len(self.StringTable) == 0:
              return lines
  
          index = 8
          lines.append('BuildStringList(')
          for string in self.StringTable:
              lines.append('    %s# %d' % (alignFormatArg(40, '%s' % repr(string)), index))
              index += 1
  
          lines.append(')')
          lines.append('')
  
          return lines
  
      def GenerateHeader(self, filename):
          filename = os.path.splitext(os.path.splitext(os.path.basename(filename))[0])[0] + '._SN'
  
          mapname = self.PlaceName or self.GetMapNameByIndex(self.MapIndex)
  
          align = 20
  
          hdr = []
          hdr.append('from ED6ScenarioHelper import *')
          hdr.append('')
          hdr.append('SetCodePage("%s")'                          % ed6fc.CODE_PAGE)
          hdr.append('')
  
          if mapname:
              hdr.append('# ' + mapname)
              hdr.append('')
  
          hdr.append('CreateScenaFile(')
  
          hdr.append('    %s %r,'     % (alignFormatKw(align, 'FileName'),            filename))
          hdr.append('    %s %r,'     % (alignFormatKw(align, 'MapName'),             self.MapName))
          hdr.append('    %s %r,'     % (alignFormatKw(align, 'Location'),            self.Location))
          hdr.append('    %s %s,'     % (alignFormatKw(align, 'MapIndex'),            self.MapIndex))
          hdr.append('    %s %s,'     % (alignFormatKw(align, 'MapDefaultBGM'),       self.MapDefaultBGM.param()))
          hdr.append('    %s %s,'     % (alignFormatKw(align, 'Flags'),               self.Flags))
          hdr.append('    %s %s,'     % (alignFormatKw(align, 'EntryFunctionIndex'),  self.EntryFunctionIndex == 0xFFFF and '0xFFFF' or self.EntryFunctionIndex))
          hdr.append('    %s %s,'     % (alignFormatKw(align, 'Reserved'),            self.Reserved))
          hdr.append('    %s [\n            %s\n        ],'   % (alignFormatKw(align, 'IncludedScenario'),  ',\n            '.join([repr(ScenarioFileIndex(scp).Name()) for scp in self.IncludedScenario])))
  
          hdr.append(')')
          hdr.append('')
  
          hdr += self.GenerateStringList()
  
          def AppendScpInfo(info, func):
              if len(info) == 0:
                  return
  
              for i in info:
                  if hasattr(i, 'params'):
                      params = i.params()
                      hdr.append('%s(' % func)
                      hdr.extend(['    ' + p for p in params])
                      hdr.append(')')
                  else:
                      hdr.append('%s(%s)' % (func, i.param()))
  
                  hdr.append('')
  
              hdr.append('')
  
          AppendScpInfo(self.EntryPoint, 'DeclEntryPoint')
  
          if len(self.ScnInfo[SCN_INFO_CHIP]) != 0:
              hdr.append('AddCharChip(')
  
              index = 0
              for chip in self.ScnInfo[SCN_INFO_CHIP]:
                  x = ('    %s,' % chip.param()).ljust(40)
                  x += ' # %02X' % index
                  hdr.append(x)
                  index += 1
  
              hdr.append(')')
              hdr.append('')
  
          if len(self.ScnInfo[SCN_INFO_CHIP_PAT]) != 0:
              hdr.append('AddCharChipPat(')
  
              index = 0
              for chip in self.ScnInfo[SCN_INFO_CHIP_PAT]:
                  x = ('    %s,' % chip.param()).ljust(40)
                  x += ' # %02X' % index
                  hdr.append(x)
                  index += 1
  
              hdr.append(')')
              hdr.append('')
  
          AppendScpInfo(self.ScnInfo[SCN_INFO_NPC],       'DeclNpc')
          AppendScpInfo(self.ScnInfo[SCN_INFO_MONSTER],   'DeclMonster')
          AppendScpInfo(self.ScnInfo[SCN_INFO_EVENT],     'DeclEvent')
          AppendScpInfo(self.ScnInfo[SCN_INFO_ACTOR],     'DeclActor')
  
          hdr.append('ScpFunction(')
          index = 0
          for block in self.CodeBlocks:
              s = ljust_cn('    "%s",' % block.Name, 30)
              s += ' # %02X, %d' % (index, index)
              hdr.append(s)
              index += 1
  
          hdr.append(')')
          hdr.append('')
          hdr.append('')
  
          return hdr
  
      def SaveToFile(self, filename, append_place_name = True):
          lines = []
  
          basename, ext = os.path.splitext(filename)
          basename = basename.strip()
  
          lines += self.GenerateHeader(filename)
  
          blocks = self.FormatCodeBlocks()
  
          for block in blocks:
              lines += block
  
          lines.append('SaveToFile()')
          lines.append('')
  
          #txt = '\r\n'.join(lines)
          #lines = txt.replace('\r\n', '\n').replace('\r', '\n').split('\n')
  
          for i in range(2, len(lines)):
              if lines[i] != '':
                  lines[i] = '    ' + lines[i]
  
          lines.insert(2, 'def main():')
          lines.append('Try(main)')
          lines.append('')
  
          filename = '%s%s' % (basename, ext)
  
          if append_place_name:
              if not self.PlaceName:
                  self.PlaceName = self.GetMapNameByIndex(self.MapIndex)
  
              if self.PlaceName:
                  filename = '%s.%s%s' % (basename, self.PlaceName, ext)
  
          fs = open(filename, 'wb')
          fs.write(''.encode('utf_8_sig'))
          fs.write('\r\n'.join(lines).encode('UTF8'))
  
      def __str__(self):
          info = []
          info.append('MapName                = %s' % self.MapName)
          info.append('Location               = %s' % self.Location)
          info.append('MapIndex               = %08X' % self.MapIndex)
          info.append('MapDefaultBGM          = %s' % self.MapDefaultBGM.Name())
          info.append('Flags                  = %08X' % self.Flags)
  
          buf = 'IncludedScenario       = '
          for include in self.IncludedScenario:
              buf += '%08X ' % include
  
          info.append(buf)
  
          info.append('StringTableOffset          = %08X' % (self.StringTableOffset))
  
          info.append('')
          info.append('ScnInfoOffset    ScnInfoNumber')
          for i in range(len(self.ScnInfoOffset)):
              info.append('  %08X          %08X' % (self.ScnInfoOffset[i], self.ScnInfoNumber[i]))
          info.append('')
  
          ScnInfoNames = \
          [
              'ChipInfo',
              'NpcInformation',
              'MonsterInformation',
              'ScpInfo',
              'InfoUnknown1',
          ]
  
          info.append('ScnInfo:')
          for i in range(len(self.ScnInfo)):
              info.append('  %s:' % ScnInfoNames[i])
              for scninfo in self.ScnInfo[i]:
                  info.append('    %s' % scninfo)
  
              info.append('')
  
          info.append('')
  
          info.append('ScenaFunctionTable         = %04X, %04X' % (self.ScenaFunctionTable.Offset, self.ScenaFunctionTable.Size))
          info.append('ChipFrameInfoOffset        = %04X' % self.ChipFrameInfoOffset)
          info.append('PlaceNameOffset            = %04X' % self.PlaceNameOffset)
          info.append('PlaceNameNumber            = %02X' % (self.PlaceNameNumber))
          info.append('PreInitFunctionIndex       = %02X' % (self.PreInitFunctionIndex))
          info.append('Unknown_51                 = %s' % self.Unknown_51)
  
          info.append('')
          #info.append('Information:')
          #info.append('%s' % (self.InitData))
          #info.append('')
  
          info.append('ScenaFunctions:')
          for sec in self.ScenaFunctions:
              info.append('  %08X' % sec)
          info.append('')
  
          info.append('NpcName:')
          for i in range(len(self.NpcName)):
              info.append('  %2d.%s' % (i + 1, self.NpcName[i]))
          info.append('')
  
          return '\r\n'.join(info)
  
  
  def procfile(file, append_place_name = True):
      console.setTitle(os.path.basename(file))
      print('disasm %s' % file)
      scena = ScenarioInfo()
      if scena.open(file) is not False:
          scena.SaveToFile(os.path.splitext(file)[0] + '.py', append_place_name)
  
  def main():
      global textPosTable, replaceOption
  
      #os.chdir(os.path.dirname(__file__))
  
      #if not ExtractText:
      #    textPosTable = json.load(open('fc_sn_text_final.json', 'r', encoding = 'utf-8-sig'))
      #    replaceOption = json.load(open('replace_option.json', 'r', encoding = 'utf-8-sig'))
  
      cp = 'gbk'
      gp = r'D:\Steam\steamapps\common\Trails in the Sky FC'
      files = []
      i = 1
      append_place_name = False
      use_index_lable = False
  
      while i < len(sys.argv):
          if sys.argv[i].startswith('--cp='):
              cp = sys.argv[i][5:]
          elif sys.argv[i].startswith('--cppy='):
              cppy = os.path.abspath(sys.argv[i][7:])
              ccode = importlib.machinery.SourceFileLoader(os.path.basename(cppy).split('.')[0], cppy).load_module()
              ccode.register()
              cp = ccode.get_name()
          elif sys.argv[i].startswith('--gp='):
              gp = os.path.abspath(sys.argv[i][5:])
          elif sys.argv[i].lower() == '--append_place_name=true':
              append_place_name = True
          elif sys.argv[i].lower() == '--indexlabel=true':
              use_index_lable = True
          else:
              files.extend(iterlib.forEachGetFiles(sys.argv[i], '*._SN'))
  
          i += 1
  
      global CODE_PAGE
      CODE_PAGE = cp
      ed6fc.CODE_PAGE = cp
      ed6fc.ed6fc_op_table.CodePage = cp
      setCodePage(cp);
  
      global GAME_PATH
      GAME_PATH = gp
      setGamePath(gp)
      initDatFileNameTable(GAME_PATH)
  
      global USE_INDEX_LABEL_NAME
      if use_index_lable:
          USE_INDEX_LABEL_NAME = True
          ed6fc.USE_INDEX_LABEL_NAME = True
          ed6fc.UseIndexLabelName()
      
      #Log.OpenLog(sys.argv[start_argv] + '\..\log.txt')
  
      global LAMBDA_INDEX
      for file in files:
          plog('START %s' % file)
          ed6fc.ResetIndex()
          ed6fc.ResetLabmdaIndex()
          procfile(file, append_place_name)
          plog('FINISHED %s' % file)
  
      if ExtractText:
          open('fc_sn_text.json', 'wb').write(json.dumps(textPosTable, indent = 2, ensure_ascii = False).encode('utf_8_sig'))
  
  if __name__ == '__main__':
      Try(main)
  