summaryrefslogblamecommitdiff
path: root/game/misc.rpy
blob: ec7fcfbdfac8ed8ff1efd5c827a1b250197009f4 (plain) (tree)




































                                                                                        
                                                                                      













































































                                                                                                                                                                                                                                                                                                                                                                       


                                                                   



                                                                 















































                                                                                    

       



                               
              




































                     


















                                                                                        


                       
                                        
                                           








                                             

              
                    
                                                                                  
                                
                                          

              



                                                              
 






                                             

                                                   
                                                                                        
 







                                                                                                                                                 




                                                                                                          


                              




                                                                                                          




                                             




                                                                                                      






                                                          
 










                                                                              
                                                            

                            
                                                       



























































































                                                                                                                                          
                                        
                                                                         
                                                                                                  





                                                                     

                                                                  
                         
                                          






















                                                                                     



                                                                     






































                                                                                      
                                                                                                       

































                                                                                                                                                                                  
                                                           











                                                                    
                                                               


                            
########################################################################################
#     This file is part of Castle.
#     Copyright (C) 2015  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
########################################################################################
# Miscellaneous functions from another game, also under LGPL

init python:
    # Core processing to be on a while loop
    def hit_verbose(someone, damage, counting, dmgfactor, fixfactor):
        someone["hp"]  -= dmgfactor
        counting += dmgfactor
        if counting+fixfactor == damage:
            someone["hp"]-=(fixfactor)
            counting+=fixfactor
        # TODO: What if something went wrong?
        renpy.pause(0.001)    
        return someone, damage, counting, dmgfactor, fixfactor

    # Main hit verbose function
    def hit_someone_verbose(someone, damage, fast=False):
        counting = 0

        # We can use dmgfactor
        if ((damage > 10) or (damage < 10)) and (preferences.text_cps) and (not fast):
            fixfactor=damage%10
            dmgfactor=int(damage/10)
            dbg_interactions=0
            dbg_srchp=0+someone["hp"]

            # Which loop to use?
            if damage > 0:
                while counting < damage:
                    someone, damage, counting, dmgfactor, fixfactor=hit_verbose(someone, damage, counting, dmgfactor, fixfactor)
                    someone["hp"]=int(someone["hp"])
                    dbg_interactions+=1

                    # Something went wrong
                    if dbg_interactions > 15:
                        raise Exception("WARNING 15 interactions or more happened without hit_verbose concluding.\n\nBy all means report this bug\nBUG ID: HSV FAILED on hpbar_handler with params unit_id, damage, counting, dmgfactor, fixfactor being %s,%d,%d,%d.\n\nClick \"Ignore\" to continue." % (someone["unit_id"], damage, counting, dmgfactor, fixfactor))
                        counting=damage
                        someone["hp"]=dbg_srchp-damage

            # So, healing it is
            else:
                while counting > damage:
                    someone, damage, counting, dmgfactor, fixfactor=hit_verbose(someone, damage, counting, dmgfactor, fixfactor)
                    someone["hp"]=int(someone["hp"])
                    dbg_interactions+=1

                    # Something went wrong
                    if dbg_interactions > 15:
                        raise Exception("WARNING 15 interactions or more happened without hit_verbose concluding.\n\nBy all means report this bug\nBUG ID: HSV FAILED on hpbar_handler with params unit_id, damage, counting, dmgfactor, fixfactor being %s,%d,%d,%d.\n\nClick \"Ignore\" to continue." % (someone["unit_id"], damage, counting, dmgfactor, fixfactor))
                        counting=damage
                        someone["hp"]=dbg_srchp-damage

        # We cannot use dmgfactor
        else:
            someone["hp"]  -= damage

        if (someone["hp"] > someone["max_hp"]):
            someone["hp"]=int(someone["max_hp"])   # Apply some corrections. TODO possible alias?
        renpy.block_rollback()              # No rollback from there.







































    """
    https://github.com/websocket-client/websocket-client/issues/532
    Due to #532 we had to disable SSL... again

    threading.enumerate() → Find one which name is "MainThread"
    Create a threading.Event in an overlay .set() 
    To send the RenpyQuit exception??

    https://grandsphere.fandom.com/wiki/Champion_Challenge
    

    # Priority: Story.json option to call label instead (story.rpy - SQ<id>_)

    # Priority: Summon Button
    # Priority: Move "system header" to overlay, and hide during fights
    # Priority: Tavern Persiana
    # And also: Calculate chance for units (adding czoom_25) on draws
    # Don't forget to quote price etc.
    # Priority: Tavern: We could determine if a tavern is on/off in tavern.py
    # Specially if we make "high ranking knight taverns", we could even use
    # them during events, returning "107: Selected tavern is not yet open"
    # But how can the client know about this and when to display?
    # Eval() is not really safe. We could use persiana for this, though.
    # Priority: charge GP for upgrade
    # Priority: Unit Selling
    # Priority: Daily Quest (Fairies and Mana Eggs)
    # Priority: Daily Login reward screen
    # Priority: Token rewrite
    # Priority: Skill system
    # Priority: Card swapping (Move cards sideways)
    # Priority: AP potions

    # Notes
    #    renpy.invoke_in_thread(?)
    # raise KeyboardException → renpy.reload_script() or renpy.quit(relaunch=True)
    # if (renpy.android) use androidID, but we could get MAC at server?
    # or (renpy.mobile)

    # TODO
    # Login with already valid token: Currently, it returns the data associated
    # to the token, instead of executing login sequence.
    # Tokens are still a safety concern, specially with multi-device.
    # salted MD5 is not exactly safe. It does the trick, but isn't safe.
    # Maybe we should salt this further with account ID?

    # Future Improvement:
    # Server Protocol Version (compatibility for legacy clients/servers ?)
    # Or just check in the client packet?
    # 
    # Result[token] and Battle[token]
    # Result[token] contains operation history, loot, gp
    # Send two packages: update_battle at final
    # battle retrieves Result[token]
    # Result loot in icons

    # Weekly event switcher (Raids, etc. → events.py)
    """

label msgbox_label(msgcode):
    call screen msgbox(msgcode)
    return

image spinner:
    "gfx/spinner.png"
    rotate 30.0
    pause 0.05
    "gfx/spinner.png"
    rotate 60.0
    pause 0.05
    "gfx/spinner.png"
    rotate 90.0
    pause 0.05
    "gfx/spinner.png"
    rotate 120.0
    pause 0.05
    "gfx/spinner.png"
    rotate 150.0
    pause 0.05
    "gfx/spinner.png"
    rotate 180.0
    pause 0.05
    "gfx/spinner.png"
    rotate 210.0
    pause 0.05
    "gfx/spinner.png"
    rotate 240.0
    pause 0.05
    "gfx/spinner.png"
    rotate 270.0
    pause 0.05
    "gfx/spinner.png"
    rotate 300.0
    pause 0.05
    "gfx/spinner.png"
    rotate 330.0
    pause 0.05
    "gfx/spinner.png"
    #rotate 360.0
    pause 0.05
    repeat

########################################################################################
#     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
########################################################################################
# Player data internals
init python:
    def ap_restore():
        # Request AP Data from websocket
        raw=send_packet("apdata", fg=False)
        apdata=json_decode(raw)
        try:
            Player["ap"]=apdata["ap"]
            Player["max_ap"]=apdata["max_ap"]
            Player["aptime"]=apdata["aptime"]
        except:
            stdout("Failed to restore AP!")
            traceback.print_exc()
            pass
        return

    def update_ap():
        # TODO: This aptime update might be wrong =/ But it will be overriden soon
        Player["aptime"] = now()
        renpy.invoke_in_thread(ap_restore)
        return

    # Techinically a battle function, readjusts a status value
    # Must be exactly the same as server side function!!
    def readjust_status(lvl, val):
        return val+int(val*(max(lvl-1, 0)/100.0))

    def async_loader():
        print("Now loading images to RAM...")
        t = now()
        for c in persistent.allfiles:
            try:
                show_img(c[0], False)
            except:
                print("Unable to load %s" % str(c))
                traceback.print_exc()
        print("Loaded %d images in %d seconds." % (len(persistent.allfiles), now() - t))

label add_server:
    centered "This allows you to add a new custom server.\n\
This option is intended for {color=#0f0}advanced users only{/color}.\n\
\n\
We provide no warranty for custom servers, and they cannot be removed from the server list, so be careful, as they might harm your phone.\n\
\n\
Remember that selecting a new server will disconnect you from the one you are set to login automatically.\n\
Make sure to note down the password or have provided a valid email, or you'll lose access to your account!\n\n{fast}{w=2.0}Click to continue →"
    if renpy.android:
        $ namai=renpy.call_screen("input_box", "What is the host of the server you want to add?\n\
                                  Default: spheres.tmw2.org")
    else:
        $ namai=renpy.input("What is the host of the server you want to add?", default="spheres.tmw2.org")
    if (namai == ""):
        $ renpy.full_restart()
        return
    if renpy.android:
        $ porta=renpy.call_screen("input_box", "In which port is it listening to?\n\
                                  Default: 61000") or "61000"
    else:
        $ porta=renpy.input("In which port is it listening to?", default="61000", allow="0123456789") or 0
    $ porta=int(porta)
    if (porta > 65535 or porta < 1):
        centered "Ports only go up to 65535."
        $ renpy.full_restart()
        return
    if renpy.android:
        $ human=renpy.call_screen("input_box", "What is the human readable name of the server?\n\
                                  Default: Custom Server") or "Custom Server"
    else:
        $ human=renpy.input("What is the human readable name of the server?", default="Custom Server")
    if (human == ""):
        $ renpy.full_restart()
        return
    $ persistent.serverlist.append([human, namai, porta])
    centered "The new server has been added successfully!"
    $ renpy.full_restart()
    return

label clear_all:
    python:
        rl=False

        # Your version is no longer valid
        if (HOST != persistent.host):
            print("Host changed from %s to %s" % (str(HOST), persistent.host))
            persistent.version=1
            rl=True
            # TODO: Clear cache

        # Update host and delete password (and reset summon)
        HOST=persistent.host
        PORT=persistent.port
        persistent.summon=ifte(config.developer, 15, 0)
        renpy.notify("Deleting password: %s" % persistent.password)
        persistent.password=None

    if debug or config.developer:
        "Spheres" "Techinical info:\n\nServer: [HOST]:[PORT]"

    if rl:
        "Spheres" "Server data purged, we will now relaunch the game."
        $renpy.quit(relaunch=True)
    else:
        "Spheres" "You have logged out successfully."
        $ renpy.full_restart()
    # ???
    jump start

label clear_cache:
    python:
        import os

        # Your version is no longer valid
        if persistent.host != "localhost":
            persistent.version=1

        # Find path to cached files
        #if renpy.android:
        root=get_path("")
        #else:
        #    root=get_path("extra/")

        # Remove cached files
        for file in os.listdir(root):
            if file.endswith('.png') or file.endswith('.mp3') or file.endswith('.jpg') or file.endswith('.webp') or file.endswith('.ogg'):
                try:
                    os.remove(root+file)
                    stdout("[CC] Removing %s" % (root+file))
                except:
                    stdout("[CC] Removing %s... FAILED" % root+file)
                    os.remove(get_path(root+file))
                    stdout("[CC] Removing %s" % get_path(root+file))
            continue

        # Erase file memory
        persistent.allfiles=[]
        allfiles=[]

    "Spheres" "Cache deleted. Space was freed!"
    $renpy.full_restart()
    jump start


#################################################################################
#     Everything below this line is part of Mana Launcher.
#     Copyright (C) 2021  Jesusalva <jesusalva@tmw2.org>
#
#     Distributed under the MIT license.
#################################################################################
screen loading():
    zorder 100

    fixed:
        frame:
            xfill True
            yfill True
            background Frame("gfx/bg/forest_sunset.png", 0, 0)
        bar:
            value progress
            range max_value
            xalign 0.5
            yalign 0.45
            xmaximum 0.75
        label "{color=#fff}[statusmsg]{/color}":
            xalign 0.5
            yalign 0.55

init python:
    import hashlib, zipfile
    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

    def dall_fetch():
      global pat, statusmsg, progress, max_value, status
      try:
        statusmsg = "Fetching assets..."
        print("Fetching http://%s/assets%s ..." % (persistent.host, pat))
        r = requests.get("http://%s/assets%s" % (persistent.host, pat), verify=False, stream=True)
        if r.status_code / 100 != 2:
            raise Exception("Aborted with status %d" % r.status_code)

        ## Download the file, slowly as it may be...
        max_value = int(r.headers.get('content-length', 0))
        print "Blocks: %d" % max_value
        ## TODO: use blocks of 1024 on DSL and 16384 on broadband?
        ## 16KiB is the default for Torrent
        block_size = 8192
        max_value = max_value / block_size
        statusmsg = "Downloading the zip file..."
        with open(get_path("allinone.zip"), 'wb') as f:
            for data in r.iter_content(block_size):
                f.write(data)
                progress += 1
        print "Finished OK"
        status = 1
      except:
        traceback.print_exc()
        print("Download All: Not successful!")
        statusmsg = "Download failed.\n\nClick anywhere to continue." % r.status_code
        status = -1
      return

    def dall_save():
      global statusmsg, progress, max_value, status
      try:
        statusmsg = "Extracting..."; progress = 0
        with zipfile.ZipFile(get_path("allinone.zip"), 'r') as zip_ref:
            max_value=len(zip_ref.namelist())
            print "Blocks: %d" % max_value
            for f in zip_ref.namelist():
                try:
                    # FIXME: Check if file already exists.
                    # `continue` if it is already in the allfiles
                    # (Right now, it overrides; Alright, but then it
                    # goes ahead and pollutes persistent.allfiles...)
                    print("Extracting %s..." % f)
                    monday = "extra_"+f
                    if "." in f:
                        pass
                    elif f.startswith("sfx"):
                        monday += ".mp3"
                    else:
                        monday += ".webp"
                    addr=get_path(monday)
                    ## Work-around to save as
                    with open(addr, 'wb') as zf:
                        zf.write(zip_ref.read(f))
                    ## ...Better always save path in full
                    path=((f, addr))
                    persistent.allfiles.append(path)
                except:
                    traceback.print_exc()
                    print("[ERROR] Skipping %s..." % f)
                progress+=1
        print "Finished OK"
        status = 1
      except:
        traceback.print_exc()
        print("Extraction error!")
        statusmsg = "Extraction error.\n\nClick anywhere to continue." % r.status_code
        status = -1
      return

label download_all:
    $ statusmsg = "Preparing to download..."
    $ progress = 0
    $ max_value = 1000
    $ status = 0
    $ pat = "" # Download
    $ md5 = "" # MD5 Hash
    show screen loading with dissolve
    python:
        ## Where the zip file is located?
        try:
            x = requests.get("http://%s/assets/fetch.txt" % persistent.host, verify=False, timeout=8.0)
            assert x.status_code == 200, "Status Code Error"
            print "%s" % str(x.text)
            pat = x.text.split("#")[0]
            md5 = x.text.split("#")[1].replace("\n", "")
        except:
            # Oh noes - something went *terribly* wrong
            traceback.print_exc()
            x=requests.Response()
            x.status_code=403

        ## Did we manage to get the location?
        if x.status_code / 100 != 2:
            statusmsg = "Error downloading!\nResource unavailable for the selected host.\n\nClick anywhere to continue."; renpy.pause(); renpy.full_restart(); renpy.jump("start")

        ## Now we know what to download
        # Must be done in thread, or Ren'Py will be blocked
        renpy.invoke_in_thread(dall_fetch)
        while not status:
            sdelay()

        if status < 0:
            renpy.pause(); renpy.full_restart(); renpy.jump("start")

        status = 0

        ## Verify if download was successful...
        statusmsg = "Integrity Check...";
        md4 = md5sum(get_path("allinone.zip"))
        if (md4 != md5):
            statusmsg = "{color=#f00}Download failed.{/color}\n%s != %s\nClick anywhere to retry." % (md4, md5); renpy.jump("download_all")
        else:
            print("Integrity check passed: %s" % md4)

        ## We downloaded, but we need to extract it
        # Must be done in thread, or Ren'Py will be blocked
        renpy.invoke_in_thread(dall_save)
        while not status:
            sdelay()

        if status < 0:
            renpy.pause(); renpy.full_restart(); renpy.jump("start")

        status = 0

        statusmsg = "Complete.\nClick anywhere to continue."
        renpy.pause()

        ## TODO: Maybe delete `allinone.zip`? Waste of space...
        renpy.full_restart()
    jump start