# RenPy code decompiler 1.5.1
# Decompiles PRYC files from RenPy runtime. Not for a faint of heart.

# 1.1: Update to support renpy 6.15.x Translate/EndTranslate constructs
# 1.1.1: Unicode fix
# 1.1.2: atl & with collision fix, 2+ behinds fix
# 1.2: full atl support
# 1.3: autopatch of "renpy/script.py" is added
# 1.4: screen language 2 is now supported
# 1.5: style, icon and default statements

# ========
# CONTACTS
# ========
# Copyleft by lolbot, member of IIchan.ru eroge project.
#         _                             
#       ,' ".   ,-"-.                        
#      :     '.'▄██▄ '.
#     :      . ▐█▀ ▐█ ;                     
#     :      ; █▌ ▄█▌,   e r o g a m e       
#      :     ; █▐█▀ /                        
#      '.    ; █   /   _      "  __  __  |          
#       '.   ; █  / |," .''l  | /_/ /   -+-            
#        '.  ; ▌ /  |   l__'  | \__ \__  |              
#         '. ;  /           ._]          [_ 
#          '.; /                          
#           './                          
#            '           
# Written on hard day's nights of extremely cold winter 2012.
# You can mail me at: lolbot_iichan@mail.ru

# =============
# NO GUARANTIES
# =============
# Please, note, that this code is not perfect.
# IN FACT, THERE ARE ABSULUTELY NO GUARANTIES.
# Most problems must be marked by decompiler with "#TODO" comments in generated rpy file.
# However, even if there is no such comments, decompiled code still may be in some wrong way.
# Python is not my native language, so sorry for awful non-pythonic style.


# ==========
# WHAT IS IT
# ==========
# This code can be used to decompile game scenarios and python scripts of RenPy game back to source code.
# Notice, that it may be illegal to redistribute decompiled games, so use this code wisely.
#
# I hope that this code would be useful not only for datesim-cheaters, but also for some game developers.
# If you wrote a game long time ago and lost it's sources, you can try now getting them back.
# If you were writing a VN and accidentally lost everything but the rpyc files, you can try restoring your work.

# =============
# HOW TO USE IT
# =============
# There are three ways of using this script
#
# -> BEST WAY TO USE (decompiles python block from source, autopatches "renpy/script.py")
#    1. Put this file to your /game/ dir.
#    2. Run the game and get the "RESTART THE GAME AGAIN TO DECOMPILE IT !!!" error message.
#    3. Run the game again, this time without any error messages.
#
# -> IF IT FAILS (decompiles python block from source, but you patch "renpy/script.py")
#    1. Put this file to your /game/ dir.
#    2. Delete "i.source = None" line of "renpy/script.py" file
#    3. Run the game.
#
# -> IF IT FAILS TOO (decompiles python block from bytecode, tricky)
#    1. Put this file to your /game/ dir.
#    2. Change "__LB_decompile_bytecode = False" line below in this file to "__LB_decompile_bytecode = True"
#    3. Run the game.
#
# Decompiled rpyc will be put at root folder of your game.

# ==============
# MODE SELECTION
# ==============
# False -> decompile python blocks from source code (default, but a patch is needed at "renpy/script.py")
# True  -> decompile python blocks from bytecode (less stable, avaliable in case renpy/script.py is changed in future)
python early:
    __LB_decompile_bytecode = False

# =================
# IT'S NOT ALMIGHTY
# =================
# There are many versions of RenPy and Python, pryc format and bytecode may differ for them.
# Some Python constructions are not decompiled from bytecode, but can be decompiled from source (see "HOW TO USE IT").
# Screen statements are not supported in both modes, sorry.
#
# Tests results on some games that were using and syntetic unittests:
# |
# +-+-RenPy 4.x/5.x with Python 2.3:
# | '---TOTAL FAIL: code injection didn't work for me, imposible to add a new rpy file
# |
# +-+-RenPy 6.x with Python 2.3:
# | +-+-Successfully decompiled using python source or bytecode:
# | | '---Elven Relations 1.1.2
# | +-+-Successfully decompiled using python source only:
# | | '---Magical Boutique 1.2
# | +---Ren'Py statements - excelent, no known errors
# | '---Python blocks - bytecode decompilation works good, but fails on some constructions
# |
# +-+-RenPy 6.x with Python 2.5:
# | +-+-Successfully decompiled using python source or bytecode:
# | | +---Tentacularity-DEMO-1.0.2
# | | +---IIchan.ru Eroge Demo
# | | +---Katawa Shoujo Act 1
# | | '---Katawa Shoujo
# | +---Ren'Py statements - excelent, no known errors
# | +---Python blocks - no known errors in bytecode decompilation
# | '---ATL statements - good, most statements are supported
# |
# '-+-RenPy 6.x with Python 2.6:
#   +-+-Successfully decompiled using python source or bytecode:
#   | '---MiniBot 2.0
#   +-+-Successfully decompiled using python source only:
#   | '---Winter Tale
#   +---Ren'Py statements - excelent, no known errors
#   +---Python blocks - highly recommended to use python source
#   +---ATL statements - good, most statements are supported
#   '---Screen statements - not supported, only their names are detected



# ======================
# LICENSE? WHAT LICENSE?
# ======================
# It's mostly a Proof Of Concept during studying python bytecode. You can use this code however you want, I think.
# But be warned, you won't get any presents from Santa, if you delete all the copylefts and introduce this work as your's.

# =============
# SOME CONTROLS
# =============
# False -> just decompile
# True  -> verbose behavior

python early:
    import codecs
    __LB_renpy_error_on_python_fail = False
    __LB_unit_test_only = False
    __LB_condition_debug = False
    __LB_full_debug = False
    __LB_print_dis = False
    __LB__open = lambda f,e: codecs.open(f,e,"utf-8")

# ==================
# HERE GOES THE CODE
# ==================

init -9001 python:
    import re
    __LB_invisible_space = " "
    __LB_files_filtered_out = [re.compile(".*common.00[a-z_]*.rpy.*"),re.compile(".*common._[a-z_/]*.rpym.*"),re.compile(".*decompile.rpy.*"),re.compile(".*depack.rpy.*"),re.compile(".*injection.rpy.*")]
    __LB_decompiled_files = {}
    _LB_tried_to_patch_isource = False

    def __LB_patch_isource():
        import os, shutil
    
        global _LB_tried_to_patch_isource
        if  _LB_tried_to_patch_isource:
           return True
    
        scriptpath = os.path.join(config.renpy_base,"renpy","script.py")
        if  not os.path.exists(scriptpath):
            return False
    
        script = open(scriptpath, "r")
        script_lines = script.readlines()
        script.close()
        
        re_isource = re.compile("^ * i.source *= *None *$")
        for l in script_lines:
            if  re_isource.match(l):
                matched = l
                break
        else:
            return False
    
        shutil.copy2(scriptpath, scriptpath+".bak")

        f = open(scriptpath, "w")
        for l in script_lines:
            f.write(l.replace(matched,"#"+matched))
        f.close()
    
        _LB_tried_to_patch_isource = True
        return True

    def __LB_make_tab(tabs):
        return "    "*tabs

    def __LB_decompile_python(pycode,tabs=0,noreturn=False):
        if  __LB_decompile_bytecode:
            pyc = pycode.bytecode
            if  isinstance(pyc,str): 
                import marshal
                code = marshal.loads(pyc)
            else:
                code = pyc
            text,stack,is_class = __LB_decompile_python_code(code,tabs)
        else:
            text = pycode.source
            if  text == None:
                if  __LB_patch_isource():
                    renpy.error('Tried to patch "i.source = None" line in renpy/script.rpy. However, you need to restart RenPy manually to make this file reload.\n\n\n\n!!! RESTART THE GAME AGAIN TO DECOMPILE IT !!!\n\n\n\n')
                else:
                    renpy.error('Empty python source.\n\nNOTE: Make sure, that you\'ve really commented out "i.source = None" line in renpy/script.rpy\n\nIf it does not help, try setting "__LB_decompile_bytecode" flag to False')
            if  text.startswith("\n"):
                text = text[1:]
            if  text.endswith("\n"):
                text = text[:-1]
            if  tabs > 0:
                text = __LB_make_tab(tabs) + text.replace("\n","\n"+__LB_make_tab(tabs))
            text = text

        if  noreturn and text.startswith("return "):
            text = text[7:]
        if  noreturn and text.endswith("\n"):
            text = text[:-1]
        return text

# ====================
# SIMPLE dis-LIKE CODE
# ====================
    def __LB_decompile_python_dis(code,tabs):
        from dis import opname
        idx = 0
        result = ""
        while idx < len(code.co_code):
            op = opname[ ord(code.co_code[idx]) ]
            result += __LB_make_tab(tabs) + "#DIS: %d %s"%(idx,op)
            #no HAVE_ARGS in old pythons
            if  op in ['LOAD_CONST','LOAD_GLOBAL','LOAD_NAME','LOAD_FAST','LOAD_ATTR','LOAD_DEREF','STORE_GLOBAL','STORE_NAME','STORE_FAST','STORE_ATTR','STORE_DEREF','DELETE_GLOBAL','DELETE_NAME','DELETE_FAST','DELETE_ATTR','IMPORT_FROM','IMPORT_NAME','BUILD_TUPLE','BUILD_LIST','BUILD_MAP','CALL_FUNCTION','CALL_FUNCTION_VAR','CALL_FUNCTION_KW','CALL_FUNCTION_VAR_KW','COMPARE_OP','SETUP_LOOP','JUMP_ABSOLUTE','JUMP_FORWARD','UNPACK_SEQUENCE','DUP_TOPX','LOAD_CLOSURE','BUILD_SLICE','FOR_ITER','RAISE_VARARGS','BUILD_CLASS','MAKE_FUNCTION','MAKE_CLOSURE','JUMP_IF_FALSE', 'JUMP_IF_TRUE', 'SETUP_EXCEPT']:
                param = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                result += " %d"%(param)
                idx += 3
            else:
                idx += 1
            result += "\n"
        return result

# ==================================================
# HERE IS THE >  > >> P Y T H O N << <  < DECOMPILER
# ==================================================
# walks through bytecode
# decompiles known patterns
# lot's of copypaste, sorry

    def __LB_decompile_python_code(code,tabs,code_from=0,code_to=None,glob=[],exception_mode=0):
        from dis import opname, cmp_op
        import sys

        lbcode = {}
        lbcode["str"] = ""
        lbcode["stack"] = []

        idx = code_from
        if  code_to==None:
            if  __LB_print_dis:
                lbcode["str"] += __LB_decompile_python_dis(code,tabs)
            idx_max = len(code.co_code)
        else:
            idx_max = code_to

        if  __LB_unit_test_only and not code.co_filename.endswith("unit_test_current.rpy"):
            return "#TODO Only unit_test_current.rpy is parsed",[],False

        if  len([1 for matcher in __LB_files_filtered_out if matcher.match(code.co_filename)]) > 0:
            return "#TODO File name filtered",[],False

        if  code_to and code_from >= code_to:
            return __LB_make_tab(tabs) + "pass" + "\n",[],False

        if  exception_mode:
            extra_stack = 3
            lbcode["stack"] += ["_LB_EXCEPT_TYPE_MAGIC_CONST_","_LB_EXCEPT_EXCEPTION_MAGIC_CONST_"] + ["_LB_EXCEPT_MAGIC_CONST_"]*(extra_stack-2)
        else:
            extra_stack = 0
        original_extra_stack = extra_stack
        code_globals = [i for i in glob]
        import_mode = False
        loop_mode = False
        print_item_to_mode = False
        yield_mode = False
        if_condition = {}
        if_condition["list"] = []
        unpack = {}
        unpack["stack"] = []
        unpack["lvalue"] = ""
        unpack["op"] = ""
        for_loop = {}
        for_loop["should_jump"] = False
        for_loop["target"] = 0
        for_loop["body"] = None
        for_loop["active"] = False
        comprehention_stack = []
        is_class = False

        def __LB_decompile_if_condition_unused(arr, idx_to=None):
            original_idx_to = idx_to
            if  idx_to == None:
                idx_to = arr[-1][0]
            elems = [ item for item in arr if idx_to == item[1] ] + [ item for item in arr if idx_to == item[0] ]
            if  len(elems) == 0:
                return []
            if  len(elems) == 1:
                return [elems[0][0]]
            last_elem = elems[-1]
            elems = elems[:-1]
            result = [last_elem[0]]
            for elem in elems:
                result += __LB_decompile_if_condition_unused(arr,elem[0])
            if  original_idx_to != None:
                return result
            return [item for item in arr if not item[0] in result]
            

        def __LB_decompile_if_condition(arr, idx_to=None):
            original_idx_to = idx_to
            if  idx_to == None:
                idx_to = arr[-1][0]
            result = ""
            op = {'JUMP_IF_TRUE':' or ','JUMP_IF_FALSE':' and '}
            elems = [ item for item in arr if idx_to == item[1] ] + [ item for item in arr if idx_to == item[0] ]
            if  len(elems) == 0:
                return result
            if  len(elems) == 1:
                return elems[0][3]
            last_elem = elems[-1]
            elems = elems[:-1]
            result = ""
            for elem in elems:
                if  elem[2] == 'UNARY_NOT':
                    last_elem[3] = "not " + __LB_decompile_if_condition(arr,elem[0])
            result += "(" + "".join([__LB_decompile_if_condition(arr,elem[0])+op[elem[2]] for elem in elems if elem[2] != 'UNARY_NOT' ]+[last_elem[3]]) + ")"
            if  original_idx_to != None:
                return result

            unused_list = __LB_decompile_if_condition_unused(arr)
            if  len(unused_list) > 0:
                lbcode["str"] += "#TODO: unused if conditions " + `unused_list` + "\n"
            return result

        def __LB_decompile_printable_result_real(result,idx):
            if  len(if_condition["list"]) > 0:
                result = __LB_decompile_if_condition(if_condition["list"] + [[idx,idx+1,"JUMP_IF_FALSE",result]])
                if_condition["list"] = []
            return result

        def __LB_decompile_printable_result(result,idx):
            return result

        def __LB_decompile_unpack_add_value(name,result,tabs,idx):
            unpack["lvalue"] += name
            if  len(unpack["stack"]) > 0:
                unpack["stack"][-1] -= 1
                if  unpack["stack"][-1] > 0:
                    unpack["lvalue"] += ", "
                while len(unpack["stack"]) > 0 and unpack["stack"][-1]==0:
                    unpack["lvalue"] += ")"
                    unpack["stack"].pop()
                    if  len(unpack["stack"]) > 0 and unpack["stack"][-1]>0:
                        unpack["stack"][-1] -= 1
                        if  unpack["stack"][-1] > 0:
                            unpack["lvalue"] += ", "
            code_tmp = ""
            if  len(unpack["stack"]) == 0:
                result = __LB_decompile_printable_result(result,idx)
                if  for_loop["active"]:
                    tmp_target = for_loop["target"]
                    for_body, for_stack, for_class = __LB_decompile_python_code(code,tabs+1,idx+3,for_loop["body_end"],code_globals)
                    code_tmp = __LB_make_tab(tabs) + "for " + unpack["lvalue"] + result + ":" + "\n" + for_body
                    for_loop["target"] = tmp_target
                    for_loop["body_end"] = None
                    for_loop["active"] = False
                    for_loop["should_jump"] = True
                elif unpack["lvalue"].startswith("$"):
                    comprehention_stack.append([])
                elif len(comprehention_stack):
                    comprehention_stack[-1] += [ unpack["lvalue"] + result ]
                elif result == "_LB_EXCEPT_EXCEPTION_MAGIC_CONST_":
                    code_tmp = "#_LB_EXCEPTION_MAGIC_CONST_: " + unpack["lvalue"] + ":\n" # magical hardcode for future code restructuring
                else:
                    code_tmp = __LB_make_tab(tabs) + unpack["lvalue"] + " " + unpack["op"] + "= " + result + "\n"
                unpack["stack"] = []
                unpack["lvalue"] = ""
                unpack["op"] = ""
            lbcode["str"] += code_tmp

        try:
            while idx < idx_max:
                opcode = opname[ ord(code.co_code[idx]) ]
#http://docs.python.org/library/dis.html#python-bytecode-instructions

                if  not opcode in ['JUMP_IF_FALSE','JUMP_IF_TRUE','UNARY_NOT']:
                    if  len(if_condition["list"]) > 0 and len([item for item in if_condition["list"] if item[1] == idx]) > 0:
                        lbcode["stack"][-1] = __LB_decompile_printable_result_real(lbcode["stack"][-1],idx)

                if  import_mode:
                    if  opcode in ["STORE_NAME","STORE_FAST","STORE_GLOBAL","IMPORT_FROM"]:
                        pass
                    elif opcode in ["POP_TOP","IMPORT_STAR"]:
                        import_mode = False
                    else:
                        return lbcode["str"] + "#TODO python fail: " + opcode + " after import at %d/%d"%(idx,idx_max) + "\n",lbcode["stack"],is_class
                else:
                    if  opcode == 'LOAD_CONST':
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        if  isinstance(code.co_consts[id],unicode):
                            code_tmp = code.co_consts[id].replace("\\","\\\\").replace("\n","\\n").replace("\t","\\t").replace("\"","\\\"")
                            code_tmp = 'u"' + code_tmp + '"'
                        elif hasattr(code.co_consts[id],"co_code"):
                            code_tmp = code.co_consts[id]
                        else:
                            code_tmp = repr(code.co_consts[id])
                        lbcode["stack"] += [code_tmp]

                    elif opcode in ['LOAD_CLOSURE', 'LOAD_DEREF']:
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        lbcode["stack"] += [(code.co_cellvars+code.co_freevars)[id]]
    
                    elif opcode == 'LOAD_FAST':
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        lbcode["stack"] += [code.co_varnames[id]]
    
                    elif opcode in ["LOAD_NAME","LOAD_GLOBAL"]:
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        lbcode["stack"] += [code.co_names[id]]
    
                    elif opcode == 'STORE_DEREF':
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        __LB_decompile_unpack_add_value((code.co_cellvars+code.co_freevars)[id],lbcode["stack"].pop(),tabs,idx)
    
                    elif opcode == 'STORE_FAST':
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        __LB_decompile_unpack_add_value(code.co_varnames[id],lbcode["stack"].pop(),tabs,idx)
    
                    elif opcode in ["STORE_NAME","STORE_GLOBAL"]:
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        if  opcode == 'STORE_GLOBAL' and not code.co_names[id] in code_globals:
                            code_globals += [ code.co_names[id] ]
                            lbcode["str"] += __LB_make_tab(tabs) + "global " + code.co_names[id] + "\n"
                        value = lbcode["stack"].pop()
                        if  code.co_names[id] == "__module__" and value == "__name__":
                            is_class = True
                        else:
                            __LB_decompile_unpack_add_value(code.co_names[id],value,tabs,idx)
    
                    elif opcode == 'DELETE_FAST':
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        if  code.co_varnames[id].startswith("$"):
                            code_tmp = "[" + comprehention_stack[-1][1] + " for " + comprehention_stack[-1][0]
                            if  len(comprehention_stack[-1]) == 3:
                                code_tmp += " if " + comprehention_stack[-1][2]
                            code_tmp += "]"
                            lbcode["stack"][-1] = code_tmp
                            comprehention_stack.pop()
                        else:
                            lbcode["str"] += __LB_make_tab(tabs) + "del " + code.co_varnames[id] + "\n"
    
                    elif opcode in ["DELETE_NAME","DELETE_GLOBAL"]:
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        if  code.co_names[id].startswith("$"):
                            code_tmp = "[" + comprehention_stack[-1][1] + " for " + comprehention_stack[-1][0]
                            if  len(comprehention_stack[-1]) == 3:
                                code_tmp += " if " + comprehention_stack[-1][2]
                            code_tmp += "]"
                            lbcode["stack"][-1] = code_tmp
                            comprehention_stack.pop()
                        else:
                            lbcode["str"] += __LB_make_tab(tabs) + "del " + code.co_names[id] + "\n"
    
                    elif opcode in ["SLICE+0","SLICE+1","SLICE+2","SLICE+3"]:
                        code_tmp1 = ""
                        code_tmp2 = ""
                        if  opcode in ["SLICE+2","SLICE+3"]:
                            code_tmp2 = lbcode["stack"].pop()
                        if  opcode in ["SLICE+1","SLICE+3"]:
                            code_tmp1 = lbcode["stack"].pop()
                        code_tmp = lbcode["stack"].pop() + "[" + code_tmp1 + ":" + code_tmp2 + "]"
                        lbcode["stack"] += [ code_tmp ]

                    elif opcode == 'BUILD_SLICE':
                        num = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        if  num == 3:
                            code_tmp3 = lbcode["stack"].pop()
                            if  code_tmp3 == "None":
                                code_tmp3 = ""
                        else:
                            code_tmp3 = ""
                        code_tmp2 = lbcode["stack"].pop()
                        if  code_tmp2 == "None":
                            code_tmp2 = ""
                        code_tmp1 = lbcode["stack"].pop()
                        if  code_tmp1 == "None":
                            code_tmp1 = ""
                        if  num == 3:
                            code_tmp = code_tmp1 + ":" + code_tmp2 + ":" + code_tmp3
                        else:
                            code_tmp = code_tmp1 + ":" + code_tmp2
                        lbcode["stack"] += [ code_tmp ]
    
                    elif opcode in ["STORE_SLICE+0","STORE_SLICE+1","STORE_SLICE+2","STORE_SLICE+3"]:
                        code_tmp1 = ""
                        code_tmp2 = ""
                        if  opcode in ["STORE_SLICE+2","STORE_SLICE+3"]:
                            code_tmp2 = lbcode["stack"].pop()
                        if  opcode in ["STORE_SLICE+1","STORE_SLICE+3"]:
                            code_tmp1 = lbcode["stack"].pop()
                        code_tmp = lbcode["stack"].pop() + "[" + code_tmp1 + ":" + code_tmp2 + "]"
                        __LB_decompile_unpack_add_value(code_tmp,lbcode["stack"].pop(),tabs,idx)
    
                    elif opcode in ["DELETE_SLICE+0","DELETE_SLICE+1","DELETE_SLICE+2","DELETE_SLICE+3"]:
                        code_tmp1 = ""
                        code_tmp2 = ""
                        if  opcode in ["DELETE_SLICE+2","DELETE_SLICE+3"]:
                            code_tmp2 = lbcode["stack"].pop()
                        if  opcode in ["DELETE_SLICE+1","DELETE_SLICE+3"]:
                            code_tmp1 = lbcode["stack"].pop()
                        code_tmp = lbcode["stack"].pop() + "[" + code_tmp1 + ":" + code_tmp2 + "]"
                        lbcode["str"] += __LB_make_tab(tabs) + "del " + code_tmp + "\n"
    
                    elif opcode == 'RAISE_VARARGS':
                        nargs = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        code_tmp = ""
                        for i in range(nargs):
                            code_tmp = lbcode["stack"].pop() + ", " + code_tmp
                        lbcode["str"] += __LB_make_tab(tabs) + "raise " + code_tmp[:-2] + "\n"

                    elif opcode == 'RETURN_VALUE':
                        code_tmp = __LB_decompile_printable_result(lbcode["stack"].pop(),idx)
                        if  code_tmp != "_LB_LOCALS_MAGIC_CONST_":
                            lbcode["str"] += __LB_make_tab(tabs) + "return " + code_tmp + "\n"
    
                    elif opcode == 'YIELD_VALUE':
                        code_tmp = __LB_decompile_printable_result(lbcode["stack"][-1],idx)
                        lbcode["str"] += __LB_make_tab(tabs) + "yield " + code_tmp + "\n"
#no pop() at python 2.5
                        if  sys.version_info[0] == 2 and sys.version_info[1] > 4:
                            yield_mode = True
                        else:
                            lbcode["stack"].pop()

                    elif opcode == 'LOAD_ATTR':
                        base = lbcode["stack"].pop()
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        lbcode["stack"] += [base + "." + code.co_names[id]]
    
                    elif opcode == 'STORE_ATTR':
                        base = lbcode["stack"].pop()
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        code_tmp = base + "." + code.co_names[id]
                        __LB_decompile_unpack_add_value(code_tmp,lbcode["stack"].pop(),tabs,idx)
    
                    elif opcode == 'DELETE_ATTR':
                        base = lbcode["stack"].pop()
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        lbcode["str"] += __LB_make_tab(tabs) + "del " + base + "." + code.co_names[id] + "\n"
    
                    elif opcode == 'BREAK_LOOP':
                        lbcode["str"] += __LB_make_tab(tabs) + "break" + "\n"
    
                    elif opcode == 'COMPARE_OP':
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        op = cmp_op[id]
                        code_tmp = lbcode["stack"].pop()
                        if  op == "exception match":
                            lbcode["stack"].pop()
                            lbcode["stack"] += ["_LB_EXCEPTION_MATCH_MAGIC_CONST_"]
                            lbcode["stack"] += [code_tmp]
                        else:
                            code_tmp = "(" + lbcode["stack"].pop() + ") " + op + " (" + code_tmp + ")"
                            lbcode["stack"] += [code_tmp]
    
                    elif opcode in ['UNARY_POSITIVE','UNARY_NEGATIVE','UNARY_NOT','UNARY_INVERT']:
                        if  opcode == 'UNARY_NOT' and len(if_condition["list"])>0:
                            if_condition["list"] += [[idx,idx+1,opcode,lbcode["stack"][-1]]]
                        else:
                            op = {'UNARY_POSITIVE':"+",'UNARY_NEGATIVE':"-",'UNARY_NOT':"not ",'UNARY_INVERT':"~"}[opcode]
                            code_tmp = op + "(" + lbcode["stack"].pop() + ")"
                            lbcode["stack"] += [code_tmp]


    
                    elif opcode == 'UNARY_CONVERT':
                        code_tmp = "`" + lbcode["stack"].pop() + "`"
                        lbcode["stack"] += [code_tmp]
    
                    elif opcode in ['BINARY_POWER','BINARY_MULTIPLY','BINARY_DIVIDE','BINARY_MODULO','BINARY_ADD','BINARY_SUBTRACT','BINARY_FLOOR_DIVIDE','BINARY_TRUE_DIVIDE','BINARY_LSHIFT','BINARY_RSHIFT','BINARY_AND','BINARY_XOR','BINARY_OR']:
                        op = {'BINARY_POWER':"**",'BINARY_MULTIPLY':"*",'BINARY_DIVIDE':"/",'BINARY_MODULO':"%",'BINARY_ADD':"+",'BINARY_SUBTRACT':"-",'BINARY_FLOOR_DIVIDE':"//",'BINARY_TRUE_DIVIDE':"/",'BINARY_LSHIFT':"<<",'BINARY_RSHIFT':">>",'BINARY_AND':"&",'BINARY_XOR':"^",'BINARY_OR':"|"}[opcode]
                        code_tmp = lbcode["stack"].pop()
                        code_tmp = "(" + lbcode["stack"].pop() + ") " + op + " (" + code_tmp + ")"
                        lbcode["stack"] += [code_tmp]
    
                    elif opcode in ['INPLACE_ADD','INPLACE_SUBTRACT','INPLACE_MULTIPLY','INPLACE_DIVIDE','INPLACE_MODULO','INPLACE_POWER','INPLACE_FLOOR_DIVIDE','INPLACE_TRUE_DIVIDE','INPLACE_LSHIFT','INPLACE_RSHIFT','INPLACE_AND','INPLACE_XOR','INPLACE_OR']:
                        optype = opname[ ord(code.co_code[idx+1]) ]
                        op = {'INPLACE_ADD':"+",'INPLACE_SUBTRACT':"-",'INPLACE_MULTIPLY':"*",'INPLACE_DIVIDE':"/",'INPLACE_MODULO':"%",'INPLACE_POWER':"**",'INPLACE_FLOOR_DIVIDE':"//",'INPLACE_TRUE_DIVIDE':"/",'INPLACE_LSHIFT':"<<",'INPLACE_RSHIFT':">>",'INPLACE_AND':"&",'INPLACE_XOR':"^",'INPLACE_OR':"|"}[opcode]
                        unpack["op"] = op
                        code_tmp = lbcode["stack"].pop()
                        lbcode["stack"].pop()
                        lbcode["stack"] += [ code_tmp ]
    
                    elif opcode in ['CALL_FUNCTION','CALL_FUNCTION_VAR','CALL_FUNCTION_KW','CALL_FUNCTION_VAR_KW']:
                        nargs1 = ord(code.co_code[idx+1])
                        nargs2 = ord(code.co_code[idx+2])
                        code_last = ""
                        code_func = ""
                        code_params = ""
                        if  opcode in ['CALL_FUNCTION_KW','CALL_FUNCTION_VAR_KW']:
                            code_last = ", **" + lbcode["stack"].pop() + code_last
                        if  opcode in ['CALL_FUNCTION_VAR','CALL_FUNCTION_VAR_KW']:
                            code_last = ", *" + lbcode["stack"].pop() + code_last
                        if  nargs1 == 0 and nargs2 == 0:
                            if  code_last != "":
                                code_params = code_last[2:]
                        else:
                            code_tmp = ""
                            for i in range(nargs2):
                                val = lbcode["stack"].pop()
                                var = lbcode["stack"].pop().replace("'","")
                                code_tmp = var + "=" + val + ", " + code_tmp
                            for i in range(nargs1):
                                code_tmp = __LB_decompile_printable_result(lbcode["stack"].pop(),idx) + ", " + code_tmp
                            code_params = code_tmp[:-2] + code_last
                        code_func = lbcode["stack"].pop()
                        if  code_func in ["__renpy__list__", "__renpy__dict__"]:
                            lbcode["stack"] += [code_params]
                        elif code_func.startswith("$") and len(comprehention_stack)>0:
                            comprehention_stack[-1] += [ code_params ]
                            lbcode["stack"] += [code_params]
                        else:
                            code_tmp = code_func + "(" + code_params + ")"
                            lbcode["stack"] += [code_tmp]
    
                    elif opcode in ['BUILD_TUPLE','BUILD_LIST','BUILD_MAP']:
                        opening = {'BUILD_TUPLE':"(",'BUILD_LIST':"[",'BUILD_MAP':"{"}
                        closing = {'BUILD_TUPLE':")",'BUILD_LIST':"]",'BUILD_MAP':"}"}
                        nargs = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        if  nargs == 0 or opcode == 'BUILD_MAP':
                            code_tmp = opening[opcode] + closing[opcode]
                            lbcode["stack"] += [code_tmp]
                        else:
                            code_tmp = ""
                            if  opcode != "h":
                                for i in range(nargs):
                                    code_tmp = lbcode["stack"].pop() + ", " + code_tmp
                            if  nargs == 1 and opcode == 'BUILD_TUPLE':
                                code_tmp = opening[opcode] + code_tmp + closing[opcode]
                            else:
                                code_tmp = opening[opcode] + code_tmp[:-2] + closing[opcode]
                            lbcode["stack"] += [code_tmp]
    
                    elif opcode == 'BUILD_CLASS':
                        func,func_params = lbcode["stack"].pop()
                        class_bases = lbcode["stack"].pop()
                        if  class_bases.endswith(", )"):
                            class_bases = class_bases[:-3] + ")"
                        if  class_bases == "()":
                            class_bases = ""
                        class_name = lbcode["stack"].pop()
                        optype = opname[ ord(code.co_code[idx+1]) ]
                        if  optype in ['STORE_FAST','STORE_NAME','STORE_GLOBAL']:
                            id = ord(code.co_code[idx+2]) + ord(code.co_code[idx+3])*256
                            if  optype == 'STORE_FAST':
                                code_tmp = "class " + code.co_varnames[id] + class_bases + ":" + "\n" + func
                            else:
                                code_tmp = "class " + code.co_names[id] + class_bases + ":" + "\n" + func
                            lbcode["str"] += __LB_make_tab(tabs) + code_tmp
                        else:
                            return lbcode["str"] + "#TODO python fail: " + optype + " after " + opcode + " at %d/%d"%(idx,idx_max) + "\n",lbcode["stack"],is_class
    
                    elif opcode in ['MAKE_FUNCTION','MAKE_CLOSURE']:
                        ndefaults = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        code_new = lbcode["stack"].pop()
                        code_args = [ [code_new.co_varnames[i]] for i in range(code_new.co_argcount) ]

                        if  opcode == 'MAKE_CLOSURE':
                            lbcode["stack"].pop()
                            for i in range(ndefaults):
                                code_args[code_new.co_argcount-1-i] += [ lbcode["stack"].pop() ]
                        else:
                            for i in range(ndefaults):
                                code_args[code_new.co_argcount-1-i] += [ lbcode["stack"].pop() ]

                        if  code_new.co_flags & 4:
                            code_args += [ [ "*" + code_new.co_varnames[code_new.co_argcount] ] ]
                            if  code_new.co_flags & 8:
                                code_args += [ [ "**" + code_new.co_varnames[code_new.co_argcount+1] ] ]
                        elif  code_new.co_flags & 8:
                            code_args += [ [ "**" + code_new.co_varnames[code_new.co_argcount] ] ]
                        code_tmp = ""
                        for arg in code_args:
                            code_tmp += ", " + arg[0]
                            if  len(arg)>1:
                                code_tmp += "=" + arg[1]
                        if  code_tmp != "":
                            code_tmp = code_tmp[2:]
                        func,func_stack,func_is_class = __LB_decompile_python_code(code_new,tabs+1)
                        if  len(func) == 0:
                            func = __LB_make_tab(tabs+1) + "pass" + "\n"

                        optype = opname[ ord(code.co_code[idx+3]) ]
                        decorators = []
                        while optype == 'CALL_FUNCTION' and not func_is_class and (ord(code.co_code[idx+4]) + ord(code.co_code[idx+5])*256) == 1:
                            idx += 3
                            optype = opname[ ord(code.co_code[idx+3]) ]
                            decorators += [lbcode["stack"].pop()]
                        while len(decorators):
                            lbcode["str"] += __LB_make_tab(tabs) + "@" + decorators.pop() + "\n"

                        if  optype in ['STORE_FAST','STORE_NAME','STORE_GLOBAL','STORE_DEREF']:
                            id = ord(code.co_code[idx+4]) + ord(code.co_code[idx+5])*256
                            if  optype == 'STORE_FAST':
                                code_tmp = "def " + code.co_varnames[id] + "(" + code_tmp + "):"
                            elif optype == 'STORE_DEREF':
                                code_tmp = "def " + (code.co_cellvars+code.co_freevars)[id] + "(" + code_tmp + "):"
                            else:
                                code_tmp = "def " + code.co_names[id] + "(" + code_tmp + "):"
                            code_tmp += "\n" + func
                            lbcode["str"] += __LB_make_tab(tabs) + code_tmp
                        elif optype == 'CALL_FUNCTION' and func_is_class:
                            lbcode["stack"] += [[func,code_tmp]]
                        elif optype == 'CALL_FUNCTION' and (ord(code.co_code[idx+4]) + ord(code.co_code[idx+5])*256) == 1:
                            lbcode["stack"] += [[func,code_tmp]]
                        else:
                            return lbcode["str"] + "#TODO python fail: " + opcode + " after " + opcode + " at %d/%d"%(idx,idx_max) + "\n" + func + `[(attr,getattr(code,attr)) for attr in dir(code)]` + "\n",lbcode["stack"],is_class
    
                    elif opcode == 'BINARY_SUBSCR':
                        key = lbcode["stack"].pop()
                        base = lbcode["stack"].pop()
                        code_tmp = base + "[" + key + "]"
                        lbcode["stack"] += [code_tmp]
    
                    elif opcode == 'STORE_SUBSCR':
                        key = lbcode["stack"].pop()
                        base = lbcode["stack"].pop()
                        if  base.startswith("{") and base.endswith("}"):
                            if  base == "{}":
                                code_tmp = "{" + key + ":" + lbcode["stack"].pop() + "}"
                            else:
                                code_tmp = base[:-1] + ", " + key + ":" + lbcode["stack"].pop() + "}"
                            if  lbcode["stack"][-1].startswith("{") and lbcode["stack"][-1].endswith("}"):
                                lbcode["stack"][-1] = code_tmp
                            else:
                                return lbcode["str"] + "#TODO python fail: " + opcode + " at %d/%d"%(idx,idx_max) + "\n",lbcode["stack"],is_class
                        else:
                            code_tmp = base + "[" + key + "]" 
                            __LB_decompile_unpack_add_value(code_tmp,lbcode["stack"].pop(),tabs,idx)
    
                    elif opcode == 'STORE_MAP':
                        key = lbcode["stack"].pop()
                        value = lbcode["stack"].pop()
                        code_tmp = lbcode["stack"].pop()
                        if  code_tmp == "{}":
                            lbcode["stack"] += ["{" + key + ":" + value + "}"]
                        else:
                            lbcode["stack"] += [code_tmp[:-1] + ", " + key + ":" + value + "}"]

                    elif opcode == 'DELETE_SUBSCR':
                        key = lbcode["stack"].pop()
                        base = lbcode["stack"].pop()
                        code_tmp = base + "[" + key + "]"
                        lbcode["str"] += __LB_make_tab(tabs) + "del " + code_tmp + "\n"
    
                    elif opcode == 'UNPACK_SEQUENCE':
                        num = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        unpack["stack"] += [num]
                        unpack["lvalue"] += "("
                        lbcode["stack"] += ["_LB_UNPACK_MAGIC_CONST_"]*(num-1)
    
                    elif opcode == 'PRINT_ITEM':
                        lbcode["str"] += __LB_make_tab(tabs) + "print " + lbcode["stack"].pop() + ", " + "\n"

                    elif opcode == 'PRINT_NEWLINE':
                        lbcode["str"] += __LB_make_tab(tabs) + "print " + "\n"

                    elif opcode == 'PRINT_ITEM_TO':
                        print_item_to_mode = True
                        code_tmp = lbcode["stack"].pop()
                        lbcode["str"] += __LB_make_tab(tabs) + "print >> " + code_tmp + ", " + lbcode["stack"].pop() + ", " + "\n"

                    elif opcode == 'PRINT_NEWLINE_TO':
                        print_item_to_mode = False
                        lbcode["str"] += __LB_make_tab(tabs) + "print >> " + lbcode["stack"].pop() + "\n"

                    elif opcode == 'DUP_TOPX':
                        num = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        for i in range(num):
                            lbcode["stack"] += [lbcode["stack"][-num]]
    
                    elif opcode == 'DUP_TOP':
                        lbcode["stack"] += [lbcode["stack"][-1]]
    
                    elif opcode == 'ROT_FOUR':
                        tmp = lbcode["stack"][-1]
                        lbcode["stack"][-1] = lbcode["stack"][-2]
                        lbcode["stack"][-2] = lbcode["stack"][-3]
                        lbcode["stack"][-3] = lbcode["stack"][-4]
                        lbcode["stack"][-4] = tmp
    
                    elif opcode == 'ROT_THREE':
                        tmp = lbcode["stack"][-1]
                        lbcode["stack"][-1] = lbcode["stack"][-2]
                        lbcode["stack"][-2] = lbcode["stack"][-3]
                        lbcode["stack"][-3] = tmp
    
                    elif opcode == 'ROT_TWO':
                        tmp = lbcode["stack"][-1]
                        lbcode["stack"][-1] = lbcode["stack"][-2]
                        lbcode["stack"][-2] = tmp
    
                    elif opcode == 'POP_TOP':
                        code_tmp = lbcode["stack"].pop()
                        if  print_item_to_mode:
                            print_item_to_mode = False
                        elif extra_stack > 0:
                            extra_stack -= 1
                        elif yield_mode:
                            yield_mode = False
                        elif len(comprehention_stack):
                            pass
                        elif loop_mode:
                            if  len(if_condition["list"]) == 0:
                                loop_mode = False
                        elif len(if_condition["list"]) > 0:
                            pass
                        else:
                            lbcode["str"] += __LB_make_tab(tabs) + code_tmp + "\n"
    
                    elif opcode == 'POP_BLOCK':
                        pop = lbcode["stack"].pop()
                        if  pop not in ["_LB_LOOP_MAGIC_CONST_"]:
                                return lbcode["str"] + "#TODO python fail: " + opcode + " at %d/%d"%(idx,idx_max) + "\n",lbcode["stack"],is_class
    
                    elif opcode == 'GET_ITER':
                        code_tmp = lbcode["stack"].pop()
                        lbcode["stack"] += [" in " + code_tmp]

                    elif opcode == 'FOR_ITER':
                        if  loop_mode and lbcode["stack"][-2] == "_LB_LOOP_MAGIC_CONST_":
                            loop_mode = False
                            delta = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                            for_loop["target"] = idx + delta + 3
                            for_loop["body_end"] = idx+delta
                            for_loop["active"] = True
                        elif len(comprehention_stack) > 0:
                            pass
                        else:
                            return lbcode["str"] + "#TODO python fail: " + opcode + " at %d/%d"%(idx,idx_max) + "\n",lbcode["stack"],is_class
    
                    elif opcode == 'SETUP_LOOP':
                        loop_mode = True
                        lbcode["stack"] += ["_LB_LOOP_MAGIC_CONST_"]
    
                    elif opcode == 'CONTINUE_LOOP':
                        lbcode["str"] += __LB_make_tab(tabs) + "continue" + "\n"

                    elif opcode == 'JUMP_ABSOLUTE':
                        if  not len(comprehention_stack):
                            #FIXME: check where are we actually jumping, lol
                            lbcode["str"] += __LB_make_tab(tabs) + "continue" + "\n"

                    elif opcode == 'END_FINALLY':
                        #FIXME: maybe, do something else too
                        return lbcode["str"] + __LB_make_tab(tabs) + "pass #NOTE: END_FINALLY" + "\n",lbcode["stack"],is_class

                    elif opcode == 'SETUP_EXCEPT':
                        delta = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        lbcode["str"] += __LB_make_tab(tabs) + "try:" + "\n"
                        try_block, try_stack, try_is_class = __LB_decompile_python_code(code,tabs+1,idx+3,idx+delta-1,code_globals)
                        lbcode["str"] += try_block
                        optype = opname[ ord(code.co_code[idx+delta]) ]
                        if  optype == 'JUMP_FORWARD':
                            idx += delta
                            delta = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                            except_block, except_stack, except_is_class = __LB_decompile_python_code(code,tabs+1,idx+3,idx+delta-1,code_globals,True)
                            if  not except_block.startswith(__LB_make_tab(tabs) + "except"):
                                lbcode["str"] += __LB_make_tab(tabs) + "except:" + "\n"
                            lbcode["str"] += except_block
                            idx += delta+3
                        else:
                            return lbcode["str"] + "#TODO python fail: " + optype + " after " + opcode + " at %d/%d"%(idx,idx_max) + "\n",lbcode["stack"],is_class

                    elif opcode in ['JUMP_IF_FALSE','JUMP_IF_TRUE']:
                        if  loop_mode:
                            delta = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                            if_condition["list"] += [[idx,idx+delta+3,opcode,lbcode["stack"][-1]]]
                            if len(lbcode["stack"])>1 and lbcode["stack"][-2] == "_LB_LOOP_MAGIC_CONST_":
                                if  opname[ ord(code.co_code[idx+delta]) ] == 'JUMP_ABSOLUTE':
                                    if_block_code, if_block_stack, if_is_class = __LB_decompile_python_code(code,tabs+1,idx+3+1,idx+delta,code_globals)
                                    idx += delta
                                    delta = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                                    lbcode["stack"][-1] = __LB_decompile_if_condition(if_condition["list"])
                                    lbcode["str"] += __LB_make_tab(tabs) + "while " + lbcode["stack"][-1] + ":" + "\n"
                                    lbcode["str"] += if_block_code
                                    idx += 3
                                    if_condition["list"] = []
                                else:
                                    idx += 3
                            else:
                                import dis
                                lbcode["str"] += "#NOTE: " + dis.dis(code) + "\n"
                                lbcode["str"] += "#NOTE: " + "unsupported situation at idx %d in code "%idx + `[(attr,getattr(code,attr)) for attr in dir(code)]` + "\n"
                                return lbcode["str"] + "#TODO python fail: " + " no _LB_LOOP_MAGIC_CONST_ below TOS in LOOP mode " + opcode + " at %d/%d"%(idx,idx_max) + "\n",lbcode["stack"],is_class
                        else:
                            delta = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                            if_condition["list"] += [[idx,idx+delta+3,opcode,lbcode["stack"][-1]]]

#JUMP_ABSOLUTE at python 2.3
#JUMP_FORWARD at python 2.5
                            if  opname[ ord(code.co_code[idx+delta]) ] in [ 'JUMP_FORWARD', 'JUMP_ABSOLUTE' ]:
                                if  len(lbcode["stack"]) > 1 and lbcode["stack"][-2] == "_LB_EXCEPTION_MATCH_MAGIC_CONST_":
                                    if_block_code, if_block_stack, if_is_class = __LB_decompile_python_code(code,tabs,idx+3+1,idx+delta,code_globals,exception_mode)
                                else:
                                    if_block_code, if_block_stack, if_is_class = __LB_decompile_python_code(code,tabs+1,idx+3+1,idx+delta,code_globals,exception_mode)
                                idx += delta
                                if  opname[ ord(code.co_code[idx]) ] == 'JUMP_FORWARD':
                                    delta = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                                else:
                                    delta = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256 - idx
                                    delta_original = delta
                                    if  idx+delta >= idx_max:
                                        delta = idx_max - idx - 3
                                    if  delta < 1:
                                        delta = 1
                                if  __LB_condition_debug:
                                    lbcode["str"] += __LB_make_tab(tabs) + "#NOTE: " + `if_condition["list"]` + '\n'
                                lbcode["stack"][-1] = __LB_decompile_if_condition(if_condition["list"])
                                if  idx+delta+3 > idx+3+1:
                                    if  len(lbcode["stack"]) > 1 and lbcode["stack"][-2] == "_LB_EXCEPTION_MATCH_MAGIC_CONST_":
                                        else_block_code, else_block_stack, else_is_class = __LB_decompile_python_code(code,tabs,idx+3+1,idx+delta-1,code_globals,exception_mode)
                                        lbcode["str"] += __LB_make_tab(tabs-1) + "except " + lbcode["stack"].pop() + ":" + "\n"
                                        lbcode["stack"].pop() # "_LB_EXCEPTION_MATCH_MAGIC_CONST_"
                                        if  if_block_code.startswith("#_LB_EXCEPTION_MAGIC_CONST_: "):
                                            lbcode["str"] = lbcode["str"][:-2] + ", "
                                            if_block_code = if_block_code[len("#_LB_EXCEPTION_MAGIC_CONST_: "):]
                                        lbcode["str"] += if_block_code
                                        if  not else_block_code.startswith(__LB_make_tab(tabs-1) + "except"):
                                            lbcode["str"] += __LB_make_tab(tabs-1) + "except:" + "\n"
                                        if  len(else_block_code) > 0:
                                            lbcode["str"] += else_block_code
                                        else:
                                            lbcode["str"] += __LB_make_tab(tabs) + "pass" + "\n"
                                    else:
                                        else_block_code, else_block_stack, else_is_class = __LB_decompile_python_code(code,tabs+1,idx+3+1,idx+delta+3,code_globals,exception_mode)
                                        if  len(if_block_stack) > 0 and len(else_block_stack) > 0:
                                            code_tmp = if_block_stack[-1] + " if " + lbcode["stack"].pop() + " else " + else_block_stack[-1]
                                            lbcode["stack"] += [ code_tmp ]
                                        else:
                                            lbcode["str"] += __LB_make_tab(tabs) + "if " + lbcode["stack"].pop() + ":" + "\n"
                                            lbcode["str"] += if_block_code
                                            lbcode["str"] += __LB_make_tab(tabs) + "else:" + "\n"
                                            lbcode["str"] += else_block_code
                                elif len(comprehention_stack)>0:
                                    code_tmp = lbcode["stack"].pop()
                                    if_block_code = if_block_code[if_block_code.find("(")+1:if_block_code.rfind(")")]
                                    comprehention_stack[-1] += [if_block_code,code_tmp]
                                else:
                                    lbcode["str"] += __LB_make_tab(tabs) + "if " + lbcode["stack"].pop() + ":" + "\n"
                                    lbcode["str"] += if_block_code
                                    if  opname[ ord(code.co_code[idx]) ] == 'JUMP_ABSOLUTE' and delta_original<=1:
                                        lbcode["str"] += __LB_make_tab(tabs+1) + "continue" + "\n"
                                idx += delta + 3
                                if_condition["list"] = []
                            else:
                                idx += 3
    
                    elif opcode == 'LOAD_LOCALS':
                        lbcode["stack"] += ["_LB_LOCALS_MAGIC_CONST_"]
    
                    elif opcode == 'EXEC_STMT':
                        code_locals = lbcode["stack"].pop()
                        code_globals = lbcode["stack"].pop()
                        code_tmp = lbcode["stack"].pop()
                        if  code_globals != "None":
                            code_tmp += ", " + code_globals
                        if  code_locals != "None":
                            code_tmp += ", " + code_locals
                        if  code_tmp.startswith("(") and code_tmp.endswith(")"):
                            code_tmp = code_tmp[1:-1]
                        lbcode["str"] += __LB_make_tab(tabs) + "exec(" + code_tmp + ")" + "\n"

    
                    elif opcode == 'IMPORT_NAME':
                        id = ord(code.co_code[idx+1]) + ord(code.co_code[idx+2])*256
                        collection = lbcode["stack"].pop()
                        if  collection == "None":
                            lbcode["str"] += __LB_make_tab(tabs) + "import " + code.co_names[id] + "\n"
                            idx += 3
                        else:
                            import_mode = True
                            code_tmp = "from " + code.co_names[id] + " import " + collection.replace(",)",")")[1:-1].replace("'","")
                            if  code_tmp != "from __future__ import with_statement":
                                lbcode["str"] += __LB_make_tab(tabs) + code_tmp + "\n"
#no pop() at python 2.5
                        if  sys.version_info[0] == 2 and sys.version_info[1] > 4:
                            lbcode["stack"].pop()
    
                    else:
                        return lbcode["str"] + "#TODO python fail: " + opcode + " at %d/%d"%(idx,idx_max) + "\n",lbcode["stack"],is_class

                if  __LB_full_debug:
                    lbcode["str"] += __LB_make_tab(tabs) + "#NOTE: done " + opcode + " | stack is " + `lbcode["stack"]` + " | comprehention_stack is " + `comprehention_stack` + " | if_condition is " + `if_condition["list"]` + "\n"

                if  for_loop["should_jump"]:
                    idx = for_loop["target"]
                    for_loop["target"] = None
                    for_loop["should_jump"] = False
                elif  opcode in ['LOAD_CONST','LOAD_GLOBAL','LOAD_NAME','LOAD_FAST','LOAD_ATTR','LOAD_DEREF','STORE_GLOBAL','STORE_NAME','STORE_FAST','STORE_ATTR','STORE_DEREF','DELETE_GLOBAL','DELETE_NAME','DELETE_FAST','DELETE_ATTR','IMPORT_FROM','IMPORT_NAME','BUILD_TUPLE','BUILD_LIST','BUILD_MAP','CALL_FUNCTION','CALL_FUNCTION_VAR','CALL_FUNCTION_KW','CALL_FUNCTION_VAR_KW','COMPARE_OP','SETUP_LOOP','JUMP_ABSOLUTE','UNPACK_SEQUENCE','DUP_TOPX','LOAD_CLOSURE','BUILD_SLICE','FOR_ITER','RAISE_VARARGS']:
                    idx += 3
                elif opcode in ['INPLACE_ADD','INPLACE_SUBTRACT','INPLACE_MULTIPLY','INPLACE_DIVIDE','INPLACE_MODULO','INPLACE_POWER','INPLACE_FLOOR_DIVIDE','INPLACE_TRUE_DIVIDE','INPLACE_LSHIFT','INPLACE_RSHIFT','INPLACE_AND','INPLACE_XOR','INPLACE_OR','POP_TOP','ROT_TWO','ROT_THREE','ROT_FOUR','DUP_TOP','BINARY_POWER','BINARY_MULTIPLY','BINARY_DIVIDE','BINARY_MODULO','BINARY_ADD','BINARY_SUBTRACT','BINARY_SUBSCR','BINARY_FLOOR_DIVIDE','BINARY_TRUE_DIVIDE','BINARY_LSHIFT','BINARY_RSHIFT','BINARY_AND','BINARY_XOR','BINARY_OR','STORE_SUBSCR','DELETE_SUBSCR','YIELD_VALUE','RETURN_VALUE','UNARY_POSITIVE','UNARY_NEGATIVE','UNARY_NOT','UNARY_CONVERT','UNARY_INVERT','IMPORT_STAR','SLICE+0','SLICE+1','SLICE+2','SLICE+3','DELETE_SLICE+0','DELETE_SLICE+1','DELETE_SLICE+2','DELETE_SLICE+3','STORE_SLICE+0','STORE_SLICE+1','STORE_SLICE+2','STORE_SLICE+3','POP_BLOCK','GET_ITER','BREAK_LOOP','CONTINUE_LOOP','PRINT_ITEM','PRINT_NEWLINE','PRINT_ITEM_TO','PRINT_NEWLINE_TO','LOAD_LOCALS','EXEC_STMT','END_FINALLY','STORE_MAP']:
                    idx += 1
                elif opcode in ['BUILD_CLASS']:
                    idx += 4
                elif opcode in ['MAKE_FUNCTION', 'MAKE_CLOSURE']:
                    idx += 6
                elif opcode in [ 'JUMP_IF_FALSE', 'JUMP_IF_TRUE', 'SETUP_EXCEPT']:
                    pass
                else:
                    return lbcode["str"] + "#TODO python fail: " + opcode + " at %d/%d"%(idx,idx_max) + "\n",lbcode["stack"],is_class
#
#                                         *       *                 
#                    *                    ║               \/        
#                                  *      ║               /\    *   
#                             \/          ║      \ /                
#                             /\          ╬     --*--               
#                                       ╒═╩═╕    / \                
#                                       │:::│                       
#                   \ /                 │:::│             *         
#                  --*--     *          │:::│                  \/   
#                   / \                ╞╧╧╧╧╧╡                 /\   
#                                \ /   │::@::│   *     \ /          
#                               --*--  │:::::│        --*--         
#                   *            / \   │:::::│         / \          
#                        \/          ┌┐│:::::│┌┐                 *  
#                        /\         ╒╪╪╧═════╧╪╪╕                   
#                                   │││:::::::│││         *         
#                              *    │││:::::::│││    \/             
#                  ┌┐               │││:::::::│││    /\         ┌┐  
#                 ╞╧╧╡ *            │││:::::::│││              ╞╧╧╡ 
#                 │09│           ┌┐ │││:::::::│││ ┌┐           │lb│ 
#                ╞╧══╧╦══════════╪╧═╡││:::::::││╞═╧╪══════════╦╧══╧╡
#                │::::║::::::::::│::│││:::::::│││::│::::::::::║::::│
#                │::::║::::::::::│::│││:::::::│││::│::::::::::║::::│
#                │::::║::::::::::│::│││:::::::│││::│::::::::::║::::│
#                │::::║::::::::::│::│││:::▄:::│││::│::::::::::║::::│
#                │::::║::::::::::│┌─┴┴┴▀▀▀▀▀▀▀┴┴┴─┐│::::::::::║::::│
#                │::::║::::::::::││  In  another  ││::::::::::║::::│
#                │::::║::::::::::││castle? Or not?││::::::::::║::::│
#                └────╨──────────┴┴───────────────┴┴──────────╨────┘
#
#             Most bytecodes for 16-bit python are supported quite well.
#
        except:
            if  __LB_renpy_error_on_python_fail:
                raise
            lbcode["str"] += __LB_make_tab(tabs) + "# TODO: [%d] exception caught on opcode:"%idx + opcode + `lbcode["stack"]` + "\n"


        if  code_to == None and lbcode["str"].endswith("return None\n"):
            lbcode["str"] = "\n".join(lbcode["str"].split("\n")[:-2]+[""])
        if  len(lbcode["str"].split("\n")) == 1:
            lbcode["str"] = __LB_make_tab(tabs) + "pass" + "\n"
        for i in range(original_extra_stack):
            try:
                lbcode["stack"].pop()
            except: pass
        if  len(lbcode["stack"]) > 0:
            lbcode["str"] += __LB_make_tab(tabs) + "# TODO: non-empty stack on exit:" + `lbcode["stack"]` + "\n"
        return lbcode["str"],lbcode["stack"],is_class










# =============================
# LET'S DECOMPILE ATL COMMANDS
# =============================


    def __LB_decompile_atl(atl,tabs):
        lbcode_str = ""

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Pass_Statement
        if  len(atl.statements) == 0:
            lbcode_str += __LB_make_tab(tabs) + "pass" + "\n"
            
        for item in atl.statements:
#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Choice_Statement
            if  hasattr(renpy.atl, "RawChoice") and isinstance(item,renpy.atl.RawChoice):
                for chance, block in item.choices:
                    if  chance == "1.0":
                        lbcode_str += __LB_make_tab(tabs) + "choice:" + "\n"
                    else:
                        lbcode_str += __LB_make_tab(tabs) + "choice " + chance + ":" + "\n"
                    lbcode_str += __LB_decompile_atl(block,tabs+1)

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Parallel_Statement
            elif hasattr(renpy.atl, "RawParallel") and isinstance(item,renpy.atl.RawParallel):
                for block in item.blocks:
                    lbcode_str += __LB_make_tab(tabs) + "parallel:" + "\n"
                    lbcode_str += __LB_decompile_atl(block,tabs+1)

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Repeat_Statement
            elif hasattr(renpy.atl, "RawRepeat") and isinstance(item,renpy.atl.RawRepeat):
                if  item.repeats == None:
                    lbcode_str += __LB_make_tab(tabs) + "repeat" + "\n"
                else:
                    lbcode_str += __LB_make_tab(tabs) + "repeat " + item.repeats + "\n"

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Block_Statement
            elif hasattr(renpy.atl, "RawBlock") and isinstance(item,renpy.atl.RawBlock):
                lbcode_str += __LB_make_tab(tabs) + "block:" + "\n"
                lbcode_str += __LB_decompile_atl(item,tabs+1)                

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Function_Statement
            elif hasattr(renpy.atl, "RawFunction") and isinstance(item,renpy.atl.RawFunction):
                lbcode_str += __LB_make_tab(tabs) + "function " + item.expr + "\n"

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Interpolation_Statement
#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Expression_Statement
            elif hasattr(renpy.atl, "RawMultipurpose") and isinstance(item,renpy.atl.RawMultipurpose):
                expression = ""
                if item.warper == None and item.warp_function != None:
                    expression += "warp " + item.warp_function + __LB_invisible_space + item.duration + __LB_invisible_space
                elif item.warper != None:
                    expression += item.warper + " " + item.duration + __LB_invisible_space
                for i in item.expressions:
                    if  i[1]:
                        expression += " with ".join(i) + " "
                    else:
                        expression += i[0] + " "
                for i in item.properties:
                    if  i[1]:
                        expression += " ".join(i) + __LB_invisible_space
                    else:
                        expression += i[0] + " "
                for i in item.splines:
                    expression += i[0] + " "
                    expression += i[1][-1] + __LB_invisible_space
                    for idx in range(len(i[1])-1):
                        expression += "knot " + i[1][idx] + __LB_invisible_space
                if  item.revolution:
                    expression += item.revolution + " "
                if  item.circles != "0":
                    expression += "circles " + item.circles
                lbcode_str += __LB_make_tab(tabs) + expression + "\n"

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Contains_Statement
            elif hasattr(renpy.atl, "RawContainsExpr") and isinstance(item,renpy.atl.RawContainsExpr):
                lbcode_str += __LB_make_tab(tabs) + "contains " + item.expression + "\n"
            elif hasattr(renpy.atl, "RawChild") and isinstance(item,renpy.atl.RawChild):
                for i in item.children:
                    lbcode_str += __LB_make_tab(tabs) + "contains:" + "\n"
                    lbcode_str += __LB_decompile_atl(i,tabs+1)                

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Event_Statement
            elif hasattr(renpy.atl, "RawEvent") and isinstance(item,renpy.atl.RawEvent):
                lbcode_str += __LB_make_tab(tabs) + "event " + item.name + "\n"

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#On_Statement
            elif hasattr(renpy.atl, "RawOn") and isinstance(item,renpy.atl.RawOn):
                for name, block in item.handlers.iteritems():
                    lbcode_str += __LB_make_tab(tabs) + "on " + name + ":" + "\n"
                    lbcode_str += __LB_decompile_atl(block,tabs+1)                

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language#Time_Statement
            elif hasattr(renpy.atl, "RawTime") and isinstance(item,renpy.atl.RawTime):
                lbcode_str += __LB_make_tab(tabs) + "time " + item.time + "\n"


            else:
                result = "#TODO atl "+`item`
#
#                                    
#                                   /\
#                                  /~~\
#                                 /~~~~\
#                                '┬────┬'
#                                 │ ┌┐ │
#                     *          ┌┴─┴┴─┴┐          *
#                    /~\         └┬────┬┘         /~\
#                   /~~~\         │    │         /~~~\
#                  '┬───┬┌┐┌┐┌┐┌┐┌┤┌┐┌┐├┐┌┐┌┐┌┐┌┐┬───┬'
#                   │   ├┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┤   │
#                   │   │                        │   │
#                ───┴───┴────────────────────────┴───┴
#                       ... in another castle ...
#
#                     See "renpy/atl.py" for details.
#        
                lbcode_str += __LB_make_tab(tabs)+ result + "\n"
        return lbcode_str





# =============================
# LET'S DECOMPILE SL2 COMMANDS
# =============================


    def __LB_decompile_sl2(sl2,tabs,first_child=0):
        lbcode_str = ""

#http://www.renpy.org/doc/html/screens.html#screen-statement
        if  hasattr(renpy.sl2.slast, "SLScreen") and isinstance(sl2,renpy.sl2.slast.SLScreen):
            if  not "modal" in dict(sl2.keyword) and hasattr(sl2, "modal") and sl2.modal == None and sl2.modal != "False":
                lbcode_str += __LB_make_tab(tabs) + "modal " + sl2.modal + "\n"
            if  not "tag" in dict(sl2.keyword) and hasattr(sl2, "tag") and sl2.tag != None:
                lbcode_str += __LB_make_tab(tabs) + "tag " + sl2.tag + "\n"
            if  not "zorder" in dict(sl2.keyword) and hasattr(sl2, "zorder") and sl2.zorder != "0":
                lbcode_str += __LB_make_tab(tabs) + "zorder " + sl2.zorder + "\n"
            if  not "variant" in dict(sl2.keyword) and hasattr(sl2, "variant") and sl2.variant != None and sl2.variant != "None":
                lbcode_str += __LB_make_tab(tabs) + "variant " + `sl2.variant` + "\n"

        if  len(sl2.children) == first_child and len(sl2.keyword) == 0:
            lbcode_str += __LB_make_tab(tabs) + "pass" + "\n"
            
        for k in sl2.keyword:
            if  k[1] is not None:
                lbcode_str += __LB_make_tab(tabs) + k[0] + " " + k[1] + "\n"
            else:
                lbcode_str += __LB_make_tab(tabs) + k[0] + "\n"

        for item in sl2.children[first_child:]:
            if  hasattr(renpy.sl2.slast, "SLDisplayable") and isinstance(item,renpy.sl2.slast.SLDisplayable):
                if  item.displayable.__module__ == "renpy.ui" and item.displayable.__name__[0] == "_":
                    item_disp = item.displayable.__name__[1:]
                elif item.displayable.__module__ == "renpy.text.text" and item.displayable.__name__ in ["Text"]:
                    item_disp = item.displayable.__name__.lower()
                elif item.displayable.__module__ == "renpy.display.im" and item.displayable.__name__ in ["image"]:
                    item_disp = item.displayable.__name__.lower()
                elif item.displayable.__module__ == "renpy.display.motion" and item.displayable.__name__ in ["Transform"]:
                    item_disp = item.displayable.__name__.lower()
                elif item.displayable.__module__ == "renpy.display.dragdrop" and item.displayable.__name__ in ["Drag","DragGroup"]:
                    item_disp = item.displayable.__name__.lower()
                elif item.displayable.__module__ == "renpy.display.layout" and item.displayable.__name__ in ["Null","Grid","Side"]:
                    item_disp = item.displayable.__name__.lower()
                elif item.displayable.__module__ == "renpy.display.layout" and item.displayable.__name__ in ["Window","MultiBox"]:
                    if  hasattr(item,"style"):
                        item_disp = item.style
                    else:
                        item_disp = item.displayable.__name__.lower()
                elif item.displayable.__module__ == "renpy.display.behavior" and item.displayable.__name__ in ["Button","Input","Timer","MouseArea"]:
                    item_disp = item.displayable.__name__.lower()
                elif item.displayable.__module__ == "renpy.display.behavior" and item.displayable.__name__ in ["OnEvent"]:
                    item_disp = "on"
                elif item.displayable.__module__ == "renpy.sl2.sldisplayables" and item.displayable.__name__.startswith("sl2"):
                    item_disp = item.displayable.__name__[3:]
                elif item.displayable.__module__ == "store.icon" and item.displayable.__name__ == "Icon":
                    item_disp = item.displayable.__name__.lower()
                else:
                    item_disp = "#TODO item_disp " + item.displayable.__module__ + "." + item.displayable.__name__
                lbcode_str += __LB_make_tab(tabs) + item_disp + (" " if len(item.positional) else "") + " ".join(item.positional)
                if  item.children or item.keyword:
                    lbcode_str += ":\n" + __LB_decompile_sl2(item,tabs+1)
                else:
                    lbcode_str += "\n"
#http://www.renpy.org/doc/html/screens.html#if
            elif  hasattr(renpy.sl2.slast, "SLIf") and isinstance(item,renpy.sl2.slast.SLIf):
                for i, (c, block) in enumerate(item.entries):
                    if  c != None and i == 0:
                        lbcode_str += __LB_make_tab(tabs) + "if " + c + ":\n"
                    if  c != None and i != 0:
                        lbcode_str += __LB_make_tab(tabs) + "elif " + c + ":\n"
                    if  c == None and i == 0:
                        lbcode_str += __LB_make_tab(tabs) + "if True:\n"
                    if  c == None and i != 0:
                        lbcode_str += __LB_make_tab(tabs) + "else:\n"
                    lbcode_str += __LB_decompile_sl2(block,tabs+1)
#http://www.renpy.org/doc/html/screens.html#for
            elif  hasattr(renpy.sl2.slast, "SLFor") and isinstance(item,renpy.sl2.slast.SLFor):
                item_variable = item.variable
                children_since = 0
                if  item.variable == "_sl2_i" and isinstance(item.children[0],renpy.sl2.slast.SLPython):
                    code = __LB_decompile_python(item.children[0].code,0)
                    if  len(code.split("\n")) == 1 and code.endswith(" = _sl2_i"):
                        item_variable = code[:-len(" = _sl2_i")]
                        children_since = 1
                lbcode_str += __LB_make_tab(tabs) + "for " + item_variable + " in " + item.expression + ":\n"
                lbcode_str += __LB_decompile_sl2(item,tabs+1,children_since)
#http://www.renpy.org/doc/html/screens.html#python
            elif  hasattr(renpy.sl2.slast, "SLPython") and isinstance(item,renpy.sl2.slast.SLPython):
                if  len(__LB_decompile_python(item.code,0).split("\n")) == 1:
                    lbcode_str += __LB_make_tab(tabs) + "$ " + __LB_decompile_python(item.code,0) + "\n"
                else:
                    lbcode_str += __LB_make_tab(tabs) + "python:\n"
                    lbcode_str += __LB_decompile_python(item.code,tabs+1) + "\n"
            elif  hasattr(renpy.sl2.slast, "SLDefault") and isinstance(item,renpy.sl2.slast.SLDefault):
                lbcode_str += __LB_make_tab(tabs) + "default " + item.variable + " = " + item.expression + "\n"
            elif  hasattr(renpy.sl2.slast, "SLUse") and isinstance(item,renpy.sl2.slast.SLUse):
                lbcode_str += __LB_make_tab(tabs) + "use " + item.target
                if  item.args:
                    lbcode_str += __LB_decompile_ArgumentInfo(item.args)
                if  item.id:
                    lbcode_str += " id " + item.id
                lbcode_str += "\n"
            else:
                result = "#TODO sl2 "+`item`
#
#                               !~~
#                           ┌┐┌┐│┌┐┌┐ 
#                           │└┘└┴┘└┘│                
#                  ┌┐       └┐     ┌┘       ┌┐       
#                ┌─┴┴─┐      │     │      ┌─┴┴─┐   
#                └┬──┬┘      │     │      └┬──┬┘   
#              ┌──┴──┴──┐    │     │    ┌──┴──┴──┐                           
#              └─┬────┬─┴────┴─────┴────┴─┬────┬─┘
#                │    │       ┌─┬─┐       │    │
#                │    │       │ │ │       │    │
#            ────┴────┴───────┴─┴─┴───────┴────┴────
#                       ... in another castle ...
#
#                     See "renpy/sl2/slatl.py" for details.
#        
                lbcode_str += __LB_make_tab(tabs)+ result + "\n"
        return lbcode_str






# ==============================================
# THIS AWFUL SWITCH WORKS WITH STRING COLLISIONS
# ==============================================
#
# "init:" + "python:" -> "init python:"
#
    
    def __LB_add_string(file,line,str,tabs):
        global __LB_decompiled_files
        if  not file in __LB_decompiled_files:
            __LB_decompiled_files[file] = {}
        if  not line in __LB_decompiled_files[file]:
            __LB_decompiled_files[file][line] = (tabs,str)
        else:
            (t,s) = __LB_decompiled_files[file][line]
            if  not s.startswith(str) and not str.startswith(s):
                if  s.startswith("call ") and str.startswith("label "):
                    if  not " from " in s:
                        s += " from "+str[5:-1]
                        __LB_decompiled_files[file][line] = (t,s)
                elif  str.startswith("call ") and s.startswith("label "):
                    if  not " from " in str:
                        str += " from "+s[5:-1]
                        __LB_decompiled_files[file][line] = (tabs,str)
                elif  s.startswith("init") and str.startswith("python"):
                    s = s[:-1] + " " + str
                    __LB_decompiled_files[file][line] = (t,s)
                elif  str.startswith("init") and s.startswith("python"):
                    str = str[:-1] + " " + s
                    __LB_decompiled_files[file][line] = (tabs,str)
                elif  str == "return":
                    __LB_decompiled_files[file][line] = (t-1 if t else 0,s)
                elif  s == "return":
                    __LB_decompiled_files[file][line] = (tabs-1 if tabs else 0,str)
                elif  str.startswith("init") and s.startswith("define"):
                    pass
                elif  s.startswith("init") and str.startswith("define"):
                    __LB_decompiled_files[file][line] = (tabs,str)
                elif  s.startswith("init") and str.startswith("screen"):
                    __LB_decompiled_files[file][line] = (tabs,str)
                elif  str.startswith("init") and s.startswith("screen"):
                    pass
                elif  str.startswith("init") and s.startswith("image"):
                    pass
                elif  s.startswith("init") and str.startswith("image"):
                    __LB_decompiled_files[file][line] = (tabs,str)
                elif  str.startswith("init") and s.startswith("transform"):
                    pass
                elif  s.startswith("init") and str.startswith("transform"):
                    __LB_decompiled_files[file][line] = (tabs,str)
                elif  str.startswith("init") and s.startswith("#TODO"):
                    pass
                elif  s.startswith("init") and str.startswith("#TODO"):
                    __LB_decompiled_files[file][line] = (tabs,str)
                elif  str.startswith("pass") and s.startswith("call"):
                    pass
                elif  s.startswith("pass") and str.startswith("call"):
                    __LB_decompiled_files[file][line] = (tabs,str)
                elif  str.startswith("menu") and s.startswith("label "):
                    suffix = ""
                    if  str.find("\n") != -1:
                        suffix = str[str.find("\n"):]
                    __LB_decompiled_files[file][line] = (tabs,"menu "+s[6:]+suffix)
                elif  s.startswith("menu") and str.startswith("label "):
                    suffix = ""
                    if  s.find("\n") != -1:
                        suffix = s[s.find("\n"):]
                    __LB_decompiled_files[file][line] = (t,"menu "+str[6:]+suffix)
                elif  s.startswith("menu") and str.startswith("menu"):
                    if  len(str) > len(s):
                        __LB_decompiled_files[file][line] = (tabs,str)
                elif  str.startswith("menu") and not s.startswith("menu"):
                    __LB_decompiled_files[file][line] = (tabs,str + "\n" + __LB_make_tab(tabs+1) + s)
                elif  s.startswith("menu") and not str.startswith("menu"):
                    __LB_decompiled_files[file][line] = (t,s + "\n" + __LB_make_tab(t+1) + str)
                elif  s.startswith("python") and str.startswith("python"):
                    if  len(str) > len(s):
                        __LB_decompiled_files[file][line] = (tabs,str)
                elif  s.startswith("transform") and str.startswith("transform"):
                    if  len(str) > len(s):
                        __LB_decompiled_files[file][line] = (tabs,str)
                elif  s.startswith("image") and str.startswith("image"):
                    if  len(str) > len(s):
                        __LB_decompiled_files[file][line] = (tabs,str)
                elif  s.startswith("show") and str.startswith("show"):
                    if  len(str) > len(s):
                        __LB_decompiled_files[file][line] = (tabs,str)
                elif  s.startswith("scene") and str.startswith("scene"):
                    if  len(str) > len(s):
                        __LB_decompiled_files[file][line] = (tabs,str)
                elif  s.startswith("style") and str.startswith("style"):
                    if  len(str) > len(s):
                        __LB_decompiled_files[file][line] = (tabs,str)
                elif  s.startswith("screen") and str.startswith("screen"):
                    if  tabs < t:
                        __LB_decompiled_files[file][line] = (tabs,str)
                elif  "with " in str:
                    if  "with " in s:
                        pass
                    else:
                        __LB_decompiled_files[file][line] = (tabs,s+" "+str)
                elif  "with " in s:
                    if  "with " in str:
                        pass
                    elif ":\n" in str:
                        __LB_decompiled_files[file][line] = (tabs,str.replace(":\n"," "+s+":\n",1))
                    else:
                        __LB_decompiled_files[file][line] = (tabs,str+" "+s)
                else:
                    __LB_decompiled_files[file][line] = (tabs,"#TODO: collision: '''" + str + "''' --- '''" + s + "'''")
            if  t < tabs and not str.startswith("screen"):
                __LB_decompiled_files[file][line] = (tabs,str)



# ====================================
# RENPY STATEMENTS LANGUAGE DECOMPILER
# ====================================

    def __LB_decompile_ArgumentInfo(arguments):
        result_tmp = ""
        for (x,val) in arguments.arguments:
            if  x:
                result_tmp += ", "+x+"="+val
            else:
                result_tmp += ", "+val
        if  arguments.extrapos:
            result_tmp += ", *"+arguments.extrapos
        if  arguments.extrakw:
            result_tmp += ", **"+arguments.extrakw
        return " (" + result_tmp[2:] + ")"

    def __LB_decompile_item(item,tabs=0):
        result = "#" + repr(item)

#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Call_Statement
        if  hasattr(renpy.ast, "Call") and isinstance(item,renpy.ast.Call):
            result = "call "
            if  item.expression:
                result += "expression "
            result += item.label
            if  hasattr(item, "arguments") and item.arguments:
                if  item.expression:
                    result += " pass"
                result += __LB_decompile_ArgumentInfo(item.arguments)
            __LB_add_string(item.filename,item.linenumber,result,tabs)

#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Define_Statement
        elif  hasattr(renpy.ast, "Define") and isinstance(item,renpy.ast.Define):
            result = "define " + item.varname + " = "
            if  item.code.source:
                result += item.code.source
            else:
                result += __LB_decompile_python(item.code,0,True)
            __LB_add_string(item.filename,item.linenumber,result,tabs)

        elif  hasattr(renpy.ast, "Default") and isinstance(item,renpy.ast.Default):
            result = "default " + item.varname + " = "
            if  item.code.source:
                result += item.code.source
            else:
                result += __LB_decompile_python(item.code,0,True)
            __LB_add_string(item.filename,item.linenumber,result,tabs)

#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#If_Statement
        elif  hasattr(renpy.ast, "If") and isinstance(item,renpy.ast.If):
            entries = [(condition, block) for condition, block in item.entries]
            (condition, block) = entries[0]
            result = "if "+condition+":"
            __LB_add_string(item.filename,item.linenumber,result,tabs)
            for (condition, block) in entries[1:-1]:                
                result = "elif "+condition+":"
                linenumber = block[0].linenumber-1
                __LB_add_string(item.filename,linenumber,result,tabs)
            if len(entries)>1:
                (condition, block) = entries[-1]
                if  condition == "True":
                    result = "else:"
                else:
                    result = "elif "+condition+":"
                linenumber = block[0].linenumber-1
                __LB_add_string(item.filename,linenumber,result,tabs)

            for (condition, block) in entries:                
                for it in block:
                    __LB_decompile_item(it,tabs+1)

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language
        elif  hasattr(renpy.ast, "Transform") and isinstance(item,renpy.ast.Transform):
            if  isinstance(item.varname,str) or isinstance(item.varname,unicode):
                result = "transform " + item.varname
            else:
                result = "transform " + " ".join(item.varname)
            if  item.parameters != None:
                result_tmp = ""
                for (x,val) in item.parameters.parameters:
                    if  val:
                        result_tmp += ", "+x+"="+val
                    else:
                        result_tmp += ", "+x
                if item.parameters.extrapos:
                    result_tmp += ", *"+item.parameters.extrapos
                if item.parameters.extrakw:
                    result_tmp += ", **"+item.parameters.extrakw
                result += " (" + result_tmp[2:] + ")"
            result += ":\n" + __LB_decompile_atl(item.atl,tabs+1)
            __LB_add_string(item.filename,item.linenumber,result,tabs)

#http://www.renpy.org/wiki/renpy/doc/reference/Animation_and_Transformation_Language
#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Image_Statement
        elif  hasattr(renpy.ast, "Image") and isinstance(item,renpy.ast.Image):
            if  isinstance(item.imgname,str) or isinstance(item.imgname,unicode):
                name = item.imgname
            else:
                name = " ".join(item.imgname)
            if  item.code:
                result = "image " + name + " = " + __LB_decompile_python(item.code,0,True)
            else:
                result = "image " + name + ":\n" + __LB_decompile_atl(item.atl,tabs+1)
            __LB_add_string(item.filename,item.linenumber,result,tabs)

#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Init_Statement
        elif  hasattr(renpy.ast, "Init") and isinstance(item,renpy.ast.Init):
            if  item.priority:
                result = "init " + "%d"%item.priority + ":"
            else:
                result = "init:"
            __LB_add_string(item.filename,item.linenumber,result,tabs)
            if  len(item.block)>1 or not isinstance(item.block[0],renpy.ast.Python) or item.block[0].linenumber != item.linenumber:
                for it in item.block:
                    __LB_decompile_item(it,tabs+1)


#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Jump_Statement
        elif  hasattr(renpy.ast, "Jump") and isinstance(item,renpy.ast.Jump):
            result = "jump "
            if  item.expression:
                result += "expression "
            result += item.target
            __LB_add_string(item.filename,item.linenumber,result,tabs)

#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Label_Statement
        elif  hasattr(renpy.ast, "Label") and isinstance(item,renpy.ast.Label):
            result = "label " + item.name
            if  hasattr(item, "parameters") and item.parameters:
                result_tmp = ""
                for (x,val) in item.parameters.parameters:
                    if  val:
                        result_tmp += ", "+x+"="+val
                    else:
                        result_tmp += ", "+x
                if item.parameters.extrapos:
                    result_tmp += ", *"+item.parameters.extrapos
                if item.parameters.extrakw:
                    result_tmp += ", **"+item.parameters.extrakw
                result += " (" + result_tmp[2:] + "):"
            else:
                result += ":"
            __LB_add_string(item.filename,item.linenumber,result,tabs)
            for it in item.block:
                __LB_decompile_item(it,tabs+1)

#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Menu_Statement
        elif  hasattr(renpy.ast, "Menu") and isinstance(item,renpy.ast.Menu):
            result = "menu:"
            if  hasattr(item,"with_") and item.with_ != None:
                result += "\n" + __LB_make_tab(tabs+1) + "with " + item.with_
            if  hasattr(item,"set") and item.set != None:
                result += "\n" + __LB_make_tab(tabs+1) + "set " + item.set
            for (label, condition, block) in item.items:
                label = label.replace("\\","\\\\").replace("\n","\\n").replace("\t","\\t").replace("\"","\\\"")
                if  block == None:
                    result += "\n" + __LB_make_tab(tabs+1) + '"'+label+'"'
            __LB_add_string(item.filename,item.linenumber,result,tabs)

            for (label, condition, block) in item.items:
                label = label.replace("\\","\\\\").replace("\n","\\n").replace("\t","\\t").replace("\"","\\\"")
                if  block != None:
                    result = '"'+label+'"'
                    if  condition != "True":
                        result += " if " + condition
                    result += ":"
                    linenumber = block[0].linenumber-1
                    __LB_add_string(item.filename,linenumber,result,tabs+1)
                    for it in block:
                        __LB_decompile_item(it,tabs+2)


#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Pass_Statement
        elif  hasattr(renpy.ast, "Pass") and isinstance(item,renpy.ast.Pass):
            result = "pass"
            __LB_add_string(item.filename,item.linenumber,result,tabs)


#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Python_Statement
        elif  hasattr(renpy.ast, "Python") and isinstance(item,renpy.ast.Python):
            if  item.hide:
                result = "python hide:\n"
            else:
                result = "python:\n"
            if  __LB_renpy_error_on_python_fail:
                result += __LB_decompile_python(item.code,tabs+1)
            else:
                try:
                    result += __LB_decompile_python(item.code,tabs+1)
                except:
                    result += "#TODO: parse this python code"
            __LB_add_string(item.filename,item.linenumber,result,tabs)
        elif  hasattr(renpy.ast, "EarlyPython") and isinstance(item,renpy.ast.EarlyPython):
            if  item.hide:
                result = "python early hide:\n"
            else:
                result = "python early:\n"
            result += __LB_decompile_python(item.code,tabs+1)
            __LB_add_string(item.filename,item.linenumber,result,tabs)

#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Return_Statement
        elif  hasattr(renpy.ast, "Return") and isinstance(item,renpy.ast.Return):
            result = "return"
            if  hasattr(item, "expression") and item.expression:
                result += " " + item.expression
            __LB_add_string(item.filename,item.linenumber,result,tabs)

#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#With_Statement
        elif  hasattr(renpy.ast, "With") and isinstance(item,renpy.ast.With):
            result = "with "
            if  item.expr != "None":
                result += item.expr
                if  item.paired:
                    result += "#TODO with two expressions: " + item.paired
            else:
                if  item.paired:
                    result += item.paired
                else:
                    result += "None"
            __LB_add_string(item.filename,item.linenumber,result,tabs)

#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#While_Statement
        elif  hasattr(renpy.ast, "While") and isinstance(item,renpy.ast.While):
            result = "while "+item.condition+":"
            __LB_add_string(item.filename,item.linenumber,result,tabs)
            for it in item.block:
                __LB_decompile_item(it,tabs+1)

#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Scene_Statement
#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Show_Statement
#http://www.renpy.org/wiki/renpy/doc/reference/The_Ren'Py_Language#Hide_Statement
        elif  (hasattr(renpy.ast, "Scene") and isinstance(item,renpy.ast.Scene)) or (hasattr(renpy.ast, "Show") and isinstance(item,renpy.ast.Show)) or (hasattr(renpy.ast, "Hide") and isinstance(item,renpy.ast.Hide)):
            if isinstance(item,renpy.ast.Scene):
                result = "scene "
            elif isinstance(item,renpy.ast.Show):
                result = "show "
            elif isinstance(item,renpy.ast.Hide):
                result = "hide "

            if  item.imspec != None:
                zorder = 0
                expression = None
                tag = None
                behind = []
                if len(item.imspec) == 3:
                    name, at_list, layer = item.imspec
                elif len(item.imspec) == 6:
                    name, expression, tag, at_list, layer, zorder = item.imspec
                elif len(item.imspec) == 7:
                    name, expression, tag, at_list, layer, zorder, behind = item.imspec
                if  expression == None:
                    result += " ".join(item.imspec[0]) + " "
                else:
                    result += "expression " + expression + " "
                if  len(at_list) > 0:
                    result += "at " + ", ".join([i for i in at_list]) + " "
                if  tag != None:
                    result += "as " + tag + " "
                if  len(behind) > 0:
                    result += "behind " + (", ".join(behind)) + " "
                if  layer and layer != "master":
                    result += "onlayer " + layer + " "
                if  zorder != 0 and zorder != None:
                    result += "zorder " + zorder + " "
                if  hasattr(item,"atl") and item.atl:
                    result = result.rstrip() + ":\n" + __LB_decompile_atl(item.atl,tabs+1)
            __LB_add_string(item.filename,item.linenumber,result,tabs)

        elif  hasattr(renpy.ast, "Screen") and isinstance(item,renpy.ast.Screen):
            if  isinstance(item.screen.name,str) or isinstance(item.screen.name,unicode):
                name = item.screen.name
            else:
                name = " ".split(item.screen.name)

            if  hasattr(renpy, "sl2") and isinstance(item.screen,renpy.sl2.slast.SLScreen):
#WOOOOOH! SCREEN LANG 2.0 IS AWESOME
                result = "screen " + name + ":\n"
                result += __LB_decompile_sl2(item.screen,tabs+1)
            else:
                result = "#TODO screen " + name + ":"
#TODO item.screen.code.bytecode - python bycode for screen         
            __LB_add_string(item.filename,item.linenumber,result,tabs)

        elif  hasattr(renpy.ast, "Style") and isinstance(item,renpy.ast.Style):
            name = item.style_name
            parent = item.parent

            result = "style " + name + (" is "+parent if parent else "")
            if  item.clear or item.properties or item.take:
                result += ":"

            if  item.delattr:
                result += "#TODO item.delattr" + `item.delattr`
            if  item.variant:
                result += "#TODO item.variant" + `item.variant`

            if  item.clear:
                result += "\n" + __LB_make_tab(tabs+1) + "clear"
            for k,v in item.properties.iteritems():
                result += "\n" + __LB_make_tab(tabs+1) + k + " " + v
            if  item.take:
                result += "\n" + __LB_make_tab(tabs+1) + "take " + item.take

            __LB_add_string(item.filename,item.linenumber,result,tabs)

        elif  hasattr(renpy.ast, "Say") and isinstance(item,renpy.ast.Say):
            result = ""
            if  item.who == None:
                pass
            elif isinstance(item.who,unicode):
                result += item.who+" "
            what = item.what.replace("\\","\\\\").replace("\n","\\n").replace("\t","\\t").replace("\"","\\\"")
            result += "\""+what+"\""
            if  item.with_:
                result += " with " + item.with_
#TODO item.who_fast - True/False
#TODO item.interact - True/False
            __LB_add_string(item.filename,item.linenumber,result,tabs)

        elif  hasattr(renpy.ast, "Translate") and isinstance(item,renpy.ast.Translate):
            if  item.language is None:
                for it in item.block:
                    __LB_decompile_item(it,tabs)
            else:
                result = "translation " + item.language + " " + item.identifier + ":\n"
                for it in item.block:
                    __LB_decompile_item(it,tabs)
        elif  hasattr(renpy.ast, "EndTranslate") and isinstance(item,renpy.ast.EndTranslate):
            pass
        
        elif  hasattr(renpy.ast, "UserStatement") and isinstance(item,renpy.ast.UserStatement):
            result = item.line
            __LB_add_string(item.filename,item.linenumber,result,tabs)

        else:
            result = "#TODO" + repr(item)
#        
#                               !~~
#                              /~\
#                             /~~~\
#                            /~~~~~\            
#               ┌┐┌┐┌┐┌┐┌┐  '┬─────┬'  ┌┐┌┐┌┐┌┐┌┐
#               │└┘└┘└┘└┘│   │  █  │   │└┘└┘└┘└┘│
#               └┐      ┌┘   │     │   └┐      ┌┘
#                │  ▐▌  │    │     │    │  ▐▌  │
#                │      ├────┴─────┴────┤      │
#                │      │       V       │      │
#                │      │       ▄       │      │
#                │      │      ▐█▌      │      │
#            ────┴──────┴──────▀▀▀──────┴──────┴────
#                   ... in another castle ...
#        
#                See "renpy/ast.py" for details.
#        
            __LB_add_string(item.filename,item.linenumber,result,tabs)
        result = __LB_make_tab(tabs) + result + "\n"
        return result

    def __LB_decompile_all():
        for key,val in renpy.game.script.namemap.iteritems():
            __LB_decompile_item(val)
        for fname in __LB_decompiled_files:
            fname_print = fname.replace("/","_").replace("\\","_").replace(":","_")+".txt"
            if  len([1 for matcher in __LB_files_filtered_out if matcher.match(fname_print)]) > 0:
                continue
            out = __LB__open(fname_print,"wb")
            lines = [i for i in __LB_decompiled_files[fname]]
            lines.sort()
            for i in range(1,lines[-1]+1):
                if  not i in __LB_decompiled_files[fname]:
                    out.write("\n")
                elif  __LB_decompiled_files[fname][i] != None:
                    (tabs,str) = __LB_decompiled_files[fname][i]
                    if  str[-1:] == "\n":
                        str = str[:-1]
                    if  str.startswith("python:") and len(str.split("\n")) == 2:
                            str = str[7:]
                            while  str != str.replace("\n    ","\n"):
                                str = str.replace("\n    ","\n")
                            str = "$ " + str.replace("\n","")
                    try:
                        out.write(__LB_make_tab(tabs) + str + "\n")
                    except:
                        renpy.error((fname_print,i,__LB_make_tab(tabs) + str + "\n"))
                    for j in range(1,len(str.split("\n"))):
                        if  i+j in __LB_decompiled_files[fname]:
                            break
                        __LB_decompiled_files[fname][i+j] = None
                    i += 1
            out.close()

    __LB_decompile_all()