summaryrefslogblamecommitdiff
path: root/game/core.rpy
blob: 65ee1651af80825450d7508f2c4d8b9963bffcc2 (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                                                                 
                                                                    
                       
                      
                      
 
                                                     
 

                                                                                 





                                                                                                        



                                                                                  
                              
                      



                            
                                                                     
         
                            
                               
                     
                       
                                                                                            
 
                                                                                 
               













                                                       






                                                                                                                                                                                               
                         
                                  




                                             



                                                       























                                                   

                              

                                                       
                                       

                                                    
                                                    
 
                                                                                 











                                                                                    
                                             



                                                                    
                  
                     


                                         









                                                                                    

                            
                                                     











                                                                           
 










                                                                                 

                                         

                                                             

                                      

                                     

                                                                                 

                          



                                       

                                                                                 
                                                                   
                        


                                                         

                                                               
 


                            

                                         
                                                  





                                                                                
                         
                
                                                      



                                                                       
                                                                                                                                                             





                                                                            








                                                                         


                   





                                                         
 
                               
                                                        
 

                 
                                  





                                                
                                                                  
                                  
 

                            
                                           



                                    


                  
                       
                                     
                         


                                

          




                             


                                         
                         
                         

                         
                      
                       
                       
                     
 

                         
                          
                     
                 
                        
                                                    
                                            

                                                 
                       



                                                                              
                            
                            
                                         
                 

                                



                                           
                                  

                                           
                                   

                                                 


                                                  











                                                                 
                                    
                                                                                 






                                                                           
                            
                                 




                                                                                  
                                                       


                                                                      



                                                                           
                            




                                           

                                                                                  


                                                          
 

                                  
                                                                     





                                    
#################################################################################
#     This file is part of Mana Launcher.
#     Copyright (C) 2021  Jesusalva <jesusalva@tmw2.org>
#
#     Distributed under the MIT license.
#################################################################################

init -3 python:
    renpy.add_python_directory("python-extra")
    import requests, zlib, base64, sys, copy, uuid, time, json, traceback
    import os.path, os, shutil, subprocess, hashlib, zipfile, pbkdf2
    import hmac, struct
    # non-free imports
    import discord_rpc

    print("\n[STDBY] Loading Basic functions.......")

    #############################################################################
    ## Compatibility
    # set PYTHON_VERSION variable (e.g. 2715, 3605 etc.)
    PYTHON_VERSION="%d%d%02d" % (sys.version_info.major, sys.version_info.minor, sys.version_info.micro)
    PYTHON_VERSION=int(PYTHON_VERSION)

    # Ren'Py should come with Python 2.7.10 (2710), but just in case
    # After all, I only tested with 2.7.10, 2.7.13 and 2.7.15
    if (PYTHON_VERSION < 2700):
        raise KeyboardInterrupt("Unsupported Python version: %d" % PYTHON_VERSION)
    elif (PYTHON_VERSION > 3000):
        # This is Python 3.x
        execute=subprocess.run
        LEGACY = False
        if config.developer:
            import mwclient
        else:
            mwclient = None
        print("Python 3.x detected! Version is %d." % PYTHON_VERSION)
    else:
        # This is Python 2.7
        execute=subprocess.call
        LEGACY = True
        mwclient = None
        print("Python 2.7 detected! Compatibility mode enabled! (ver: %d)" % PYTHON_VERSION)

    #############################################################################
    # Functions
    # Encodes something to md5
    def md5(string):
        return hashlib.md5(string.encode()).hexdigest()

    def md5sum(f):
        md5=hashlib.md5()
        fp=open(f, "rb")
        ct=fp.read()
        md5.update(ct)
        rt=copy.copy(md5.hexdigest())
        fp.close()
        del ct
        return rt

    # Sanitize a command (strip some flow control chars)
    # While it covers all control operators and most metacharacters,
    # it doesn't covers well the reserved words.
    # ...Of course, it relies on this client not being compromised.
    def san(cmd):
        return cmd.replace(";", "").replace("|", "").replace(">", "").replace("<", "").replace("&", "").replace("(", "").replace(")", "").replace("\n", "").replace("[[", "").replace("]]", "")

    # Smart Print command
    def stdout(message, bd=False):
        if config.developer:
            if renpy.android:
                if not renpy.is_init_phase():
                    renpy.notify(message)
            else:
                if bd:
                    print("\033[1m%s\033[0m" % message)
                else:
                    print(message)
            renpy.write_log("[DEBUG] %s" % message)
        else:
            renpy.write_log("[GAME] %s" % message)
        return

    # Smart wait
    def sdelay(delta=0.02):
        try:
            renpy.pause(delta, hard=True)
        except:
            time.sleep(delta)
        return

    # IF Then Else (IFTE)
    def ifte(ifs, then, elses):
        if (ifs):
            return then
        else:
            return elses

    # Returns number of seconds since UNIX EPOCH
    def now():
        return int(time.time())

    # File Managment Functions
    def get_path(path):
        # Not all systems can record on the game folder
        if renpy.android:
            path=path.replace("/", "_")
            return renpy.config.savedir + "/" + path
        else:
            return renpy.config.basedir + "/" + path

    #############################################################################
    # Global classes
    # We need to override standard list method. Original by Triptych (stackoverflow)
    class dlist(list):

        def __setitem__(self, index, value):
            size = len(self)
            if index >= size:
                self.extend(None for _ in range(size, index + 1))

            list.__setitem__(self, index, value)

    # Search for array[?][key]==search in an array of dicts
    # Returns the dictionary, or returns None
    def dl_search(array, key, search):
        try:
            r=(item for item in array if item[key] == search).next()
        except:
            r=None
        if r is None:
            stdout("dlsearch: r is None")
        return r

    # Search for array[?][key]==search in an array of dicts
    # Returns the index, or returns -1
    def dl_search_idx(array, key, search):
        try:
            r=next((i for i, item in enumerate(array) if item[key] == search), None)
        except:
            traceback.print_exc()
            r=-1
        return ifte(r is None, -1, r)

    # Calculates a 2FA Token
    def calcOTP(key):
        if not LEGACY and not isinstance(key, bytes):
            key = bytes(key, 'ascii')
        msg = struct.pack(">Q", int(time.time()/30))
        h = hmac.new(key, msg, hashlib.sha1).digest()
        if LEGACY:
            o = ord(h[19]) & 15
        else:
            o = (h[19] & 15)
        _return = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
        _return = "%06d" % _return
        print("TOTP: %s" % _return)
        del msg, h, o
        return _return

    #############################################################################
    ## Some other stuff
    if renpy.linux:
        os.environ["APPIMAGELAUNCHER_DISABLE"]="1"

    #############################################################################
    ## Configuration and Defaults
    if (persistent.discord is None):
        persistent.discord = True
    if (persistent.steam is None):
        persistent.steam = False
    if (persistent.evol2cli is None):
        persistent.evol2cli = "manaverse"
    if (persistent.iconify is None):
        persistent.iconify = ifte(renpy.windows, False, True)
    if (persistent.autologin is None):
        persistent.autologin = True
    if (persistent.maskpass is None):
        persistent.maskpass = True

    #############################################################################
    ## Conditional imports
    if persistent.steam:
        try:
            import _renpysteam as steam
        except:
            persistent.steam = False

    #############################################################################
    # ["themanaworld.org", "germantmw.de", "moubootaurlegends.org"]
    if config.developer:
        VAULT_HOST = "https://localhost:13370"
        VAULT_CERT = "http://localhost/launcher/cert.pem"
    else:
        VAULT_HOST = "https://api.themanaworld.org:13370"
        VAULT_CERT = False#"https://tmw2.org/launcher/cert.pem"

    ###################
    # Vault SSL wrapper
    vault=requests.Session()
    if VAULT_CERT:
        vault.cert = get_path("cert.pem")
        vault.verify = False #get_path("cert.pem")

    ############################################################################
    ## Retrieve the Vault certificate. Otherwise, we cannot proceed.
    ## From here and until the end of this code block,
    ## ALL ERRORS ARE FATAL
    def build_vault():
        while VAULT_CERT:
            try:
                ######################################
                # Fetch a new PEM Certificate
                stdout("Fetching SSL Certificate from %s" % VAULT_CERT)
                r = requests.get(VAULT_CERT)
                if (r.status_code != 200):
                    raise Exception("\nFailed to fetch Vault SSL Certificate.\n\n Returned HTTP error %d.\n\nClick \"Ignore\" to retry.\n\n" % r.status_code)
                # Save it
                with open(get_path("cert.pem"), 'wb') as fd:
                    for chunk in r.iter_content(chunk_size=128):
                        fd.write(chunk)
                # Presumably all good, so do not continue and break the loop
                stdout("PEM Download OK")
                break
            except:
                traceback.print_exc()
                raise
                stdout("Automatically retry in 5 seconds...")
                time.sleep(5.0)
            ## End FATAL mode
            #############################################################

init 10 python:
    ########
    ## Force Update
    #if persistent.version != config.version:
    #    persistent.version = config.version
    #    if (persistent.evol2cli is not None and
    #        persistent.host is not None and
    #        handle_client(launch=True, download=False)):
    #            md5check_client(silent=True)

    persistent.last_run = now()
    mp = MultiPersistent("vault.themanaworld.org", True)

    ########
    ## Fix keymap
    config.keymap['screenshot']=[]
    config.keymap['screenshot'].append('K_F10')
    config.keymap['screenshot'].append('K_F12')
    config.keymap['toggle_skip'].remove('K_TAB')
    config.keymap['fast_skip'].remove('>')
    config.keymap['toggle_skip'].append('>')
    config.keymap['focus_down'].append('K_TAB')
    config.keymap['toggle_fullscreen'].remove('noshift_K_f') # 'f'
    config.keymap['director'] = []

######### Done with pre-init
label splashscreen:
    show TMW2 at truecenter with None #fade
    python:
        if persistent.hello is None:
            p1=2.5
            p2=1.5
        else:
            p1=0.5
            p2=0.5
        renpy.pause(p1)
    hide TMW2 with None #Dissolve(p2)
    call before_main_menu
    if persistent.hello is None:
        call screen preferences
        $ persistent.hello=True
    return

label die:
    $ stdout("Program died.")
    pause
    return

####### Defaults
default statusmsg = "Not yet initialized"
default progress = 0
default responsive = True
default has_steam = False
default SCR_PROMPT = None
default SCR_RESULT = None
default SCR_CUTIN = ""
default MLP_DEST = None
default running = False
default mySoul = None

## Command Line Interface
init -4 python:
    USE_DUMMY_DATA = False
    AUTOLAUNCH = True
    AUTOWORLD = 0
    def parse_command():
        global USE_DUMMY_DATA, AUTOLAUNCH, AUTOWORLD
        global vault, VAULT_HOST, VAULT_CERT
        parser = renpy.arguments.ArgumentParser()

        ## Collect args
        parser.add_argument('args', nargs='+', help="Command-line arguments.")
        targs = parser.parse_args()
        args = targs.args

        ## Debug information
        if config.developer:
            print("Args: %s" % str(args))
        print("")

        ## Command Line Defaults
        for cmd in args:
            if (cmd == "steam"):
                print("Steam Mode Enabled")
                persistent.steam = True
            elif (cmd == "dummy"):
                print("Dummy Mode Enabled")
                USE_DUMMY_DATA = True
            elif (cmd == "launch"):
                print("Auto-launch mode Enabled")
                AUTOLAUNCH = True
            elif (cmd == "select"):
                print("Auto-launch mode Disabled")
                AUTOLAUNCH = True
            elif (cmd == "remote"):
                print("Using remote servers...")
                VAULT_HOST = "https://api.themanaworld.org:13370"
                VAULT_CERT = False
                vault=requests.Session()
            elif (cmd == "local"):
                print("Using local servers...")
                VAULT_HOST = "https://localhost:13370"
                VAULT_CERT = "http://localhost/launcher/cert.pem"
                vault=requests.Session()
                vault.cert = get_path("cert.pem")
                vault.verify = get_path("cert.pem")
            elif (cmd == "version"):
                print("%s v%s %s" % (config.name, config.version, "Mirror Lake"))
                print("%s %s" % (str(renpy.version()), renpy.version_name))
                if renpy.linux:
                    print("Linux")
                elif renpy.windows:
                    print("Windows")
                else:
                    print("Unsupported plataform")
                renpy.quit()
            elif (cmd == "help"):
                print("=========================================================")
                print("Commands:")
                print("steam - Enables Steam login")
                print("dummy - do not login, use a dummy data for testing")
                print("launch - skip main menu screen")
                print("select - show main menu screen")
                print("version - shows the program version and exits")
                print("help - shows this help screen and exits")
                print("")
                print("Advanced:")
                print("w<id> - logins to world <id> upon launching")
                print("")
                print("Latter commands have precedence over earlier ones.")
                renpy.quit()
            elif (cmd.startswith("w")):
                try:
                    AUTOWORLD=int(cmd[1:])
                except:
                    pass # Invalid world id
            else:
                print("\033[31;1mWARNING:\033[0m Unrecognized argument: %s" % cmd)
        return True

    renpy.arguments.register_command('adv', parse_command)

label main_menu:
    ## Autolaunch - Skip main menu
    if AUTOLAUNCH and persistent.last_run in range(now()-5, now()+1):
        $stdout("Auto-launching...")
        $AUTOLAUNCH=False
        return
    call screen main_menu()
    $ renpy.quit()