summaryrefslogblamecommitdiff
path: root/game/defs.rpy
blob: 5c5d5b130e79a20af41c0623239013d8ab3a71fe (plain) (tree)





















                                                                                        
                                                  
                           















                                                                                                                                                                      
                                         



                                                     
                                        
                                    
                                        



                                     
                             






                                                 
               


































































































































































                                                                                                                       
                                 







                                                    
                                 


























                                                                                                                                            
                                                        

























































                                                                            

                                             

                     
                      
                           
                              

                                                      



                                                        

                            
























































































                                                                                                      

                                       
 


                                                            
               



                              

                                     

                                                                    






                                             
 
                                                                      


                                                
                         



                      

















                                                                                                                            
                     





































































































































































































































































































































































                                                                                                                                                            
########################################################################################
#     This file is part of Spheres.
#     Copyright (C) 2019  Jesusalva

#     This library is free software; you can redistribute it and/or
#     modify it under the terms of the GNU Lesser General Public
#     License as published by the Free Software Foundation; either
#     version 2.1 of the License, or (at your option) any later version.

#     This library is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#     Lesser General Public License for more details.

#     You should have received a copy of the GNU Lesser General Public
#     License along with this library; if not, write to the Free Software
#     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
########################################################################################
# Definitions

init -3 python:
    renpy.add_python_directory("python-extra")
    import requests, zlib, base64, sys, copy, uuid
    import websock as wsock

    # set PYTHON_VERSION variable (should be 2713, 3605 could fail)
    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 or PYTHON_VERSION > 3000):
        raise Exception("WARNING: Python version is not 2.7\nStrange bugs may happen on your client.\n\nClick on \"Ignore\" to continue.\nClick on \"Quit\" to exit.")

    # Why setting this...?
    ApTimer=""

    # Configuration
    config.autoreload = False
    config.save_on_mobile_background = False
    persistent.release_name = "Christmas"
    if persistent.host is None:
        persistent.host="spheres.tmw2.org"
        # FIXME: Set good defaults (=bad) for Android
        if renpy.android:
            persistent.nothreading=False
            persistent.fatality=True
            persistent.ssl_enabled=False
    if (persistent.allfiles is None):
        persistent.allfiles=[]
    allfiles=[]
    HOST=str(persistent.host)
    PORT=str(persistent.port)
    UPDP=10302
    FAILUREMSG="Request failed, Please try again"
    OFFLINEMSG="401 Unauthorized"
    OKMSG="200 OK"
    TIMEOUT_INTERVAL=3.0
    MAX_IRC_BUFFER=50
    SSL_IS_BROKEN=False
    CERT_NONE=0
    debug=copy.copy(config.developer)

    # Error Codes
    ERR_JSONDECODER=101
    ERR_LOGIN_DEFAULT=102
    ERR_INVALID=103
    ERR_TIMEOUT=104
    ERR_NOGEMS=105
    ERR_INVFULL=106
    ERR_OK=200

    # All error code library
    ERRNO=[FAILUREMSG, OFFLINEMSG, OKMSG, ERR_LOGIN_DEFAULT, ERR_INVALID, ERR_TIMEOUT, ERR_NOGEMS, ERR_INVFULL, ERR_OK]

    # Core musics/sfx
    MUSIC_OPENING="sfx/bgm01.mp3"
    MUSIC_TOWN="sfx/bgm02.mp3"

    # Spheres actions
    AP_NONE     =False
    AP_SPHERE   =1
    AP_SKILL    =2

    # Status
    ST_TOWN     =0
    ST_QUEST    =1

    # Unit flags
    UF_NOLVL    =1
    UF_NOPART   =2
    UF_EXPUP    =4
    UF_EVOMAT   =8
    UF_SUPEREVO =64

    # Jobs
    Job_Swordsman   =1
    Job_Assassin    =2
    Job_Mage        =3
    Job_Archer      =4
    Job_Gunner      =5

    # IRC flags
    IRC_AUTH_NONE   =0
    IRC_AUTH_USER   =1
    IRC_AUTH_NICK   =2
    IRC_AUTH_CHAN   =3

    # Smart Print command
    def stdout(message):
        if debug:
            if renpy.android:
                if not renpy.is_init_phase():
                    renpy.notify(message)
            else:
                print(message)
            renpy.write_log("[DEBUG] %s" % message)
        else:
            renpy.write_log("[GAME] %s" % message)
        return

    # 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)

    class ExecuteOnCall():
        def __init__(self, callable, *args, **kwargs):
            self.callable = callable
            self.args = args
            self.kwargs = kwargs

        def __call__(self):
            rv = self.callable(*self.args, **self.kwargs)
            return rv

        def id(self):
            return self.__call__()

    class RetString():
        def __init__(self, string):
            self.string = string

        def __call__(self):
            return self.string

        def id(self):
            return self.__call__()

    # Screen Functions/class
    # Override
    class SpheresMainMenu(MainMenu):
        def __call__(self):

            if not self.get_sensitive():
                return

            if self.confirm:
                if config.autosave_on_quit:
                    renpy.force_autosave()

                layout.yesno_screen(layout.MAIN_MENU, SpheresMainMenu(False))
            else:
                # Flush labels/sockets/timers as needed
                renpy.call_in_new_context("quit")
                # Restart
                renpy.full_restart(config.game_main_transition)

    class ExtraImage(renpy.display.im.Image):
        """
        Custom image manipulator, based on bink's code, topic 11732
        """

        def __init__(self, loc, **properties):
            """
            @param loc: Where the image really is (get_path already applied)
            """

            super(ExtraImage, self).__init__(loc, **properties)
            self.loc = loc

        def load(self, unscaled=False): # W0221
            try:
                #page = open(self.loc, "rb")
                #pd = page.read()
                #picdata = os.tmpfile()
                #picdata.write(pd)
                #picdata.seek(0) # reset seek position
                stdout("Requested to open: %s" % repr(self.loc))
                picdata = open(self.loc, "rb")
                stdout("Picdata is open (%s)" % self.loc)

                if unscaled:
                    surf = renpy.display.pgrender.load_image_unscaled(picdata, self.loc)
                else:
                    surf = renpy.display.pgrender.load_image(picdata, self.loc)

                stdout("Picdata was closed")
                picdata.close()
                #page.close()

                return surf
            except Exception, e:
                if renpy.config.missing_image_callback:
                    im = renpy.config.missing_image_callback(self.loc)
                    if im is None:
                        raise e
                    return im.load()
                raise

    def virtpos(posix):
        if isinstance(posix, float):
            return posix*1024
        else:
            return posix/1024.0

    # File Managment Functions
    def get_path(path):
        if True or renpy.android:
            #print "Android detected"
            path=path.replace("/", "_")
            #return renpy.loader.get_path(path)
            return renpy.config.savedir + "/" + path
        else:
            return renpy.loader.get_path(path)

    def get_path_if_exists(path):
        if True or renpy.android:
            print "Android detected, not checking"
            path=path.replace("/", "_")
            #return renpy.loader.get_path(path)
            return renpy.config.savedir + "/" + path
        else:
            return renpy.loader.transfn(path)

    # URL3 Function
    def GAME_UPDATER():
        global tr_load
        tr_load=False

        # If no version is provided, we are using default files
        # Default files version is "1" (Should never happen)
        if (persistent.version is None):
            persistent.version=1

        # Download upstream version
        x=requests.get("http://"+HOST+'/version.txt')
        try:
            ver=int(x.text)
        except:
            stdout("IMPOSSIBLE TO DETERMINE VERSION")
            raise Exception("Could not estabilish a connection to update server:\n%s is not valid." % x.text) # TODO: Show this beautifully?
            # TODO: Should we set a "ver"?

        if (int(persistent.version) < ver):
            # TODO: Check if the server have SSL support

            # Download quests.json
            f=open(get_path("quests.json"), "w")
            stdout("Downloading quests.json")
            x=requests.get("http://"+HOST+'/quests.json')
            f.write(x.text)
            f.close()

            # Download units.json
            f=open(get_path("units.json"), "w")
            stdout("Downloading units.json")
            x=requests.get("http://"+HOST+'/units.json')
            f.write(x.text)
            f.close()

            # Download story.json
            f=open(get_path("story.json"), "w")
            stdout("Downloading story.json")
            x=requests.get("http://"+HOST+'/story.json')
            f.write(x.text)
            f.close()

            # Download world.json
            f=open(get_path("world.json"), "w")
            stdout("Downloading world.json")
            x=requests.get("http://"+HOST+'/world.json')
            f.write(x.text)
            f.close()

            # Download bar.json
            f=open(get_path("bar.json"), "w")
            stdout("Downloading bar.json")
            x=requests.get("http://"+HOST+'/bar.json')
            f.write(x.text)
            f.close()

            # Download summons.json
            f=open(get_path("summons.json"), "w")
            stdout("Downloading summons.json")
            x=requests.get("http://"+HOST+'/summons.json')
            f.write(x.text)
            f.close()

            persistent.version=ver
            stdout("Update complete")

        # Download server news
        # Handled by GAME_LOADER

        tr_load=True
        return tr_load





############################################################################
init -1 python:
    import socket, time, json
    # Android might have special SSL problems
    if renpy.android:
        try:
            import ssl
        except ImportError:
            SSL_IS_BROKEN=True
            stdout("Android SSL misbehavior detected")
            import _openssl as ssl
    else:
        import ssl
        print("Using system-wide SSL implementation...")

    # wsock already imported

    print("======================= %s %s %s" % (config.name, config.version, persistent.release_name))
    print "[STDBY] Loading Basic functions......."

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

    def check_fail(raw):
        global debug, FAILUREMSG

        if (debug):
            stdout(str(raw))
        if (raw == FAILUREMSG):
            return True
        return False

    def json_decode(raw):
        global ERRNO

        if (check_fail(raw)):
            return ERR_LOGIN_DEFAULT

        # TODO Move this to check_fail and rewrite check_fail
        # ERR_OFF should be handled top-level no? With full_restart()
        if raw in ERRNO:
            return raw

        try:
            return int(raw)
        except:
            pass

        # Maybe base 64
        try:
            rw=base64.b64decode(raw)
            raw=rw
            if (debug):
                print "base64 decoded"
        except:
            pass

        # Maybe zlib compressed
        try:
            rw=zlib.decompress(raw)
            raw=rw
            if (debug):
                print str(raw)
        except:
            pass

        # Decode JSON
        try:
            return json.loads(raw)
        except:
            return ERR_JSONDECODER

    def get_token():
        try:
            t=Player['token']
        except:
            t="0" #"f528764d624db129b32c21fbca0cb8d6"
        return t

    def login():
        global Player
        stdout("Login requested for %s" % logindata())
        raw=send_packet("login", logindata())

        Player=json_decode(raw)
        if (Player == ERR_JSONDECODER):
            return ERR_JSONDECODER
        if (Player == ERR_LOGIN_DEFAULT):
            return ERR_LOGIN_DEFAULT

        try:
            Player["inv"]=dlist()
        except:
            pass
        return Player["code"]

    def send_packet_now(packet, args="", legacy=False):
        global tr_load, tr_val, tr_busy
        global ws

        stdout("Sending: %s" % packet)
        try:
            ws.send(get_token() + ";" + packet + ";" + args)
        except:
            return False
        # TODO: Wait for onmsg
        # TODO: ping packets
        return True

    def send_packet(packet, args=""):
        global tr_load, tr_val, tr_busy
        # TODO: if tr_busy already true, wait until it is made false
        while tr_busy:
            renpy.pause(0.02)

        # Book processing space for ourselves
        tr_busy=True
        tr_load=False
        tr_val=None

        # This is a secret variable which disables threading and queue
        # This may cause hangs and other issues.
        if persistent.nothreading:
            send_packet_now(packet, args)
            tr_busy=False
            val=tr_val
            return val

        timeout=0.0
        renpy.show("spinner", at_list=[truecenter])
        renpy.invoke_in_thread(send_packet_now, packet, args)
        while not tr_load:
            renpy.pause(0.1)
            timeout+=0.1

            if timeout >= TIMEOUT_INTERVAL:
                # FIXME: What if a screen is already being displayed? BUG
                try:
                    renpy.call_screen("msgbox", "Error Code: %d\n\nApplication timeout, click to try again" % (ERR_TIMEOUT))
                    timeout=0.0
                except:
                    if not "ping" in packet.lower():
                        stdout("WARNING, ILLEGAL PACKET ON SCREEN TIME: %s" % packet)
                    pass

        renpy.hide("spinner")
        val=tr_val
        tr_busy=False
        del tr_val

        print "value obtained"
        if (val is None):
            return ERR_INVALID
        return val

    def GAME_LOADER():
        global allunitsbase, allunits, allquests, allstory, allworld, alltaverns
        global allnews, tr_load
        tr_load=False

        # Load unit data
        if renpy.android:
            allunitsbase=json.loads(requests.get("http://"+HOST+'/units.json').text)
        else:
            f=open(get_path_if_exists("units.json"), "r")
            allunitsbase=json.load(f)
            f.close()

        # Reorder unit data
        allunits={}
        for j in allunitsbase:
            allunits[j["unit_id"]]=j

        # Load summons data
        f=open(get_path_if_exists("summons.json"), "r")
        allworld=json.load(f)
        f.close()

        # Load quest data
        f=open(get_path_if_exists("quests.json"), "r")
        allquests=json.load(f)
        f.close()

        # Load story data
        f=open(get_path_if_exists("story.json"), "r")
        allstory=json.load(f)
        f.close()

        # Load world data
        f=open(get_path_if_exists("world.json"), "r")
        allworld=json.load(f)
        f.close()

        # Load tavern data
        f=open(get_path_if_exists("bar.json"), "r")
        alltaverns=json.load(f)
        f.close()

        # Load server news
        try:
            allnews=json.loads(requests.get("http://"+HOST+'/news.json', timeout=5.0).text)
        except:
            allnews=[]
            pass

        print "[OK] Basic functions loaded"
        tr_load=True
        return tr_load





############################################################################
# This is the JSON data formatter
init python:
    import json
    def logindata():
        global password
        # TODO: Obtain user id based on device
        return """{
                "passwd": "%s",
                "version": "%s"
                }""" % (password, config.version)


    def recruitdata(t, a):
        return """{
                "tavern": %d,
                "amount": %d
                }""" % (t, a)


    def questdata(q, p):
        return """{
                "quest_id": %d,
                "party_id": %d
                }""" % (q, p)


    def battledata(u, s):
        return """{
                "unit": %s,
                "sphere": %s
                }""" % (json.dumps(u), json.dumps(s))

    def card_composite(cid, path):
        # We need to try to get rarity
        try:
            r=allunits[int(cid)]["rare"]
        except:
            r=4 # FIXME

        # We need to try to get the element
        try:
            e=allunits[int(cid)]["attribute"]
            print str(e)
        except:
            e=0

        return Composite(
            (640, 960),
            (0, 0), "gfx/cards/bg.png",
            (0, 0), path,
            (0, 0), "gfx/cards/"+str(r)+".png",
            (0, 0), "gfx/cards/ele/"+str(e)+".png")
        # size,)

    # TODO: square_ and gfx/square/units
    # Converts regular image filepaths to displayables names and vice-versa
    def img_regex(name, reverse=False):
        if not reverse:
            # Extension is ommited, add them yourself!
            if name.startswith("unit_"):
                return "gfx/units/%s" % name.replace("unit_")
            elif name.startswith("mob_"):
                return "gfx/mobs/%s" % name.replace("mob_")
            elif name.startswith("dialog_"):
                return "gfx/dialog/%s" % name.replace("dialog_")
            elif name.startswith("bg "):
                return "gfx/bg/%s" % name.replace("bg ")
            elif name.startswith("summon_"):
                return "gfx/summons/%s" % name.replace("summon_")
            else:
                print("ERROR: Not a regular filename")
                return name
        else:
            if name.startswith("gfx/units/"):
                return "unit_%s" % name
            elif name.startswith("gfx/mobs/"):
                return "mob_%s" % name
            elif name.startswith("gfx/dialog/"):
                return "dialog_%s" % name
            elif name.startswith("gfx/bg/"):
                return "bg %s" % name
            elif name.startswith("gfx/summons/"):
                return "summon_%s" % name
            else:
                print("ERROR: Not a regular display name")
                return name

    # Loads a sound called VAL
    def get_sfx(val, ext):
        # Search for the sound
        show_img(val, False, ext=ext)

        valb=dl_search(persistent.allfiles, 0, val)[1]
        if valb == ERR_INVALID:
            print ("Invalid Sound: %s (%s)" % (path, val))
            return "sfx/regnum.mp3" # FIXME
        return valb

    # Load sprite images: "unit"
    for file in renpy.list_files():
        fn=file.replace('gfx/units/','').replace('/', ' ').replace('.png','')
        if file.startswith('gfx/units/'):
            if file.endswith('.png') or file.endswith('.webp'):
                name = "unit_"+fn
                #renpy.image(name, Image(file, yanchor=1.0))
                renpy.image(name, card_composite(fn, file))

                dl=dl_search(persistent.allfiles, 0, name)
                if dl is not ERR_INVALID:
                    persistent.allfiles.append((name, file))
                allfiles.append(name)
                continue
            continue

    # Load sprite images: "mob"
    for file in renpy.list_files():
        fn=file.replace('gfx/mobs/','').replace('/', ' ').replace('.png','')
        if file.startswith('gfx/mobs/'):
            if file.endswith('.png') or file.endswith('.webp'):
                name = "mob_"+fn
                renpy.image(name, Image(file, yanchor=1.0))
                if not name in persistent.allfiles:
                    persistent.allfiles.append((name, file))
                allfiles.append(name)
                continue
            continue


    # Load sprite images: "dialog"
    for file in renpy.list_files():
        fn=file.replace('gfx/dialog/','').replace('/', ' ').replace('.png','').replace('.webp','')
        if file.startswith('gfx/dialog/'):
            if file.endswith('.png') or file.endswith('.webp'):
                name = "dialog_"+fn
                renpy.image(name, Image(file, yanchor=1.0))
                dl=dl_search(persistent.allfiles, 0, name)
                if dl is not ERR_INVALID:
                    persistent.allfiles.append((name, file))
                allfiles.append(name)
                continue
            continue


    # Load background images: "bg"
    for file in renpy.list_files():
        fn=file.replace('gfx/bg/','').replace('/', ' ').replace('.png','').replace('.webp','')
        if file.startswith('gfx/bg/'):
            if file.endswith('.png') or file.endswith('.webp'):
                name = "bg "+fn
                renpy.image(name, Frame(file, 0, 0))
                dl=dl_search(persistent.allfiles, 0, name)
                if dl is not ERR_INVALID:
                    persistent.allfiles.append((name, file))
                allfiles.append(name)
                continue
            continue


    # Load summon images: "summon"
    for file in renpy.list_files():
        fn=file.replace('gfx/summons/','').replace('/', ' ').replace('.png','').replace('.webp','')
        if file.startswith('gfx/summons/'):
            if file.endswith('.png') or file.endswith('.webp'):
                name = "summon_"+fn
                renpy.image(name, Image(file, yanchor=1.0))
                dl=dl_search(persistent.allfiles, 0, name)
                if dl is not ERR_INVALID:
                    persistent.allfiles.append((name, file))
                allfiles.append(name)
                continue
            continue

    def star_write(am):
        i, st = 0, ""
        while i < am:
            i+=1
            st+="★"
        return st


    # Overrides renpy.image() method
    def new_img(name, where):
        # d: Downloaded path
        if not isinstance(name, tuple):
            name = tuple(name.split())

        #d = renpy.renpy.easy.displayable(where)
        if renpy.android:
            d=ExtraImage(where)
        else:
            d = renpy.renpy.easy.displayable(where)
        renpy.renpy.display.image.register_image(name, d)
        return

    # Retrieves Ren'Py displayable name associated to PATH
    def get_img(path):
        # Search for the image name
        val=img_regex(path, True)
        show_img(val, False)

        valb=dl_search(persistent.allfiles, 0, val)[1]
        if valb == ERR_INVALID:
            print ("Invalid Image: %s (%s)" % (path, val))
            return "gfx/spinner.png"
        return valb

    # Overrides renpy.show() and renpy.image() methods
    # Missing: transient=False, munge_name=True
    def show_img(img, show=True, at_list=[ ], tag=None, zorder=None, behind=[ ], atl=None, what=None, layer=None, ext=".png"):
        global tr_loading
        # Image exists, display it
        if img in allfiles:
            if show:
                renpy.show(img, at_list=at_list, tag=tag, zorder=zorder, behind=behind, atl=atl, what=what, layer=layer)
            return

        # Have we downloaded this image previously?
        path=dl_search(persistent.allfiles, 0, img)
        print str(path)

        # Image doesn't exists, we must download it
        while (path == ERR_INVALID):
            tr_loading=True
            # Latest version converts these formats to WebP
            if ext in [".png", ".jpg", ".jpeg"]:
                ext=".webp"
            # Otherwise, preserve extension.
            if renpy.android:
                addr="extra_%s%s" % (img.replace(" ", "_"), ext)
            else:
                addr="extra/%s%s" % (img.replace(" ", "_"), ext)

            f=open(get_path(addr), "w")
            stdout("Downloading additional file: %s" % img.replace(" ", "_"))
            x=requests.get("http://%s:%d/%s?token=%s" % (HOST, UPDP, img.replace(" ", "_"), get_token())) # , timeout=8.0 → Need to handle sudden death
            if x.status_code == 200:
                f.write(x.content)
                f.close()
                # Android needs paths to be saved by full
                if renpy.android:
                    addr=get_path(addr)
                path=((img, addr))
                persistent.allfiles.append(path)
            else:
                try:
                    retry=renpy.call_screen("confirm", "Error downloading file.\nError Code: %d\n\nRetry?" % x.status_code, Return(True), Return(False))
                    if not retry:
                        if tag is None:
                            tag=img
                        path=None
                        if show:
                            renpy.show("spinner", at_list=at_list, tag=tag, zorder=zorder, behind=behind, atl=atl, what=what, layer=layer) # TODO Show error
                        return
                    # TODO: “Retry?”
                except:
                    print("Failed, trying again")

        # Image exists, but wasn't loaded yet
        if (path != ERR_INVALID and path is not None):
            print "Detected not loaded image"
            # Valid Image Extensions: PNG, JPG, JPEG, GIF, WEBP
            if ext in [".png", ".jpg", ".jpeg", ".gif", ".webp"]:
                # Maybe it is an unit
                if img.startswith("unit_"):
                    new_img(img, card_composite(img.replace("unit_", ""), path[1]))
                else:
                    new_img(img, path[1])

            stdout("registered image: "+path[1])
            allfiles.append(img)
            if show:
                renpy.show(img, at_list=at_list, tag=tag, zorder=zorder, behind=behind, atl=atl, what=what, layer=layer)
            tr_loading=False
            return

        # Something went wrong
        stdout("show_img reached abnormal ending")
        return

    ##########################################################
    # Other Music
    MUSIC_BATTLE=RetString("sfx/bgm03.mp3")
    MUSIC_BOSS=RetString("sfx/bgm04.mp3")
    MUSIC_PARTY=RetString("sfx/bgm02.mp3")
    #MUSIC_PARTY=ExecuteOnCall(get_sfx, "sfx_bgm05", ".mp3")#"sfx/bgm05.mp3"
    MUSIC_VICTORY=RetString("sfx/bgm06.mp3")
    MUSIC_WORLDMAP=RetString("sfx/bgm02.mp3")
    #MUSIC_WORLDMAP=ExecuteOnCall(get_sfx, "sfx_bgm07", ".mp3")#"sfx/bgm07.mp3"
    MUSIC_PROLOGUE01=RetString("sfx/regnum.mp3")
    MUSIC_PROLOGUE02=RetString("sfx/prologue.mp3")
    MUSIC_PROLOGUE03=RetString("sfx/shining.mp3")