summaryrefslogtreecommitdiff
path: root/game/defs.rpy
diff options
context:
space:
mode:
Diffstat (limited to 'game/defs.rpy')
-rw-r--r--game/defs.rpy921
1 files changed, 921 insertions, 0 deletions
diff --git a/game/defs.rpy b/game/defs.rpy
new file mode 100644
index 0000000..3d1e18a
--- /dev/null
+++ b/game/defs.rpy
@@ -0,0 +1,921 @@
+########################################################################################
+# 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
+
+ # 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 = "Renewal"
+ if persistent.host is None:
+ persistent.host="spheres.tmw2.org"
+ # FIXME: Set good defaults (=bad) for Android
+ if renpy.android:
+ persistent.nothreading=True
+ persistent.fatality=True
+ if (persistent.allfiles is None):
+ persistent.allfiles=[]
+ allfiles=[]
+ HOST=str(persistent.host)
+ PORT=10301
+ 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
+ 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 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 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):
+ # Check if the server have SSL support
+ try:
+ stdout("Downloading certificate from server")
+ x=requests.get("http://"+HOST+'/certificate.pem')
+ #print len(x.text)
+ if "BEGIN CERTIFICATE" in x.text:
+ persistent.ssl_enabled=True
+ stdout("Updating server certificate")
+ f=open(get_path("cert/certificate.pem"), "w")
+ f.write(x.text)
+ f.close()
+ stdout("SSL: ENABLED")
+ else:
+ raise Exception("Not a certificate")
+ except:
+ stdout("SSL: DISABLED")
+ persistent.ssl_enabled=False
+
+ # 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, sys, time, json
+ if renpy.android:
+ try:
+ import androidssl as ssl
+ except:
+ SSL_IS_BROKEN=True
+ import ssl
+ stdout("Broken Android SSL detected, FALLING BACK")
+ else:
+ import ssl
+ print("Using system-wide SSL implementation...")
+
+ 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
+ try:
+ sock80 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ if not renpy.android:
+ sock80.settimeout(10)
+ else:
+ stdout("RAW Socket Ready")
+
+ # TODO: Request server if it is running with SSL or not
+ # If SSL is enabled (server configuration)
+ if persistent.ssl_enabled:
+ if not SSL_IS_BROKEN:
+ # Create the contest
+ context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
+
+ # Protect the most possible, if appliable.
+ context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
+
+ # FIXME We should check it
+ if persistent.ssl_enabled != "IGNORE":
+ context.check_hostname = True
+ context.verify_mode = ssl.CERT_OPTIONAL
+ else:
+ stdout("[SECURITY] SSL VERIFICATION DISABLED.")
+ context.check_hostname = False
+ context.verify_mode = ssl.CERT_NONE
+ #context.load_default_certs() # <- A .crt file
+ context.load_verify_locations(get_path("cert/certificate.pem"))
+ stdout("SSL Context Ready")
+
+ sock = context.wrap_socket(sock80, server_hostname=HOST)
+ else:
+ CIPHERS_OVERRIDE = ":".join(
+ [
+ "ECDHE+AESGCM",
+ #"ECDHE+CHACHA20",
+ #"DHE+AESGCM",
+ #"DHE+CHACHA20",
+ "ECDH+AESGCM",
+ #"DH+AESGCM",
+ "ECDH+AES",
+ #"DH+AES",
+ "RSA+AESGCM",
+ "RSA+AES",
+ #"!aNULL",
+ #"!eNULL",
+ #"!MD5",
+ #"!DSS",
+ ]
+ )
+ if persistent.ssl_enabled != "IGNORE":
+ sock = ssl.wrap_socket(sock80, ca_certs=get_path("cert/certificate.pem"), ssl_version=2, cert_reqs=ssl.CERT_OPTIONAL, ciphers=CIPHERS_OVERRIDE)
+ else:
+ stdout("[SECURITY] SSL VERIFICATION DISABLED.")
+ sock = ssl.wrap_socket(sock80, ca_certs=get_path("cert/certificate.pem"), ssl_version=2, cert_reqs=ssl.CERT_NONE, ciphers=CIPHERS_OVERRIDE)
+ stdout("Android SSL Wrapper Ready")
+
+ else:
+ sock=sock80
+
+ if not renpy.android:
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ else:
+ stdout("Socket Ready")
+
+ sock.connect((HOST, PORT))
+
+ if renpy.android:
+ stdout("Socket Ready")
+ stdout("Connected: (%s, %d), Socket %s" % (HOST, PORT, sock.getsockname()))
+ renpy.pause(1.0)
+
+ #m=get_token() + ";" + packet
+ m=get_token() + ";" + packet + ";" + args
+
+ stdout("Sending: %s" % m)
+ sock.sendall(m)
+
+ # Receive data from the server
+ received = sock.recv(2048)
+ stdout("received: %s" % received)
+
+ # Close the socket
+ sock.shutdown(socket.SHUT_RDWR)
+ sock.close()
+ except:
+ received=FAILUREMSG
+
+ if persistent.fatality is not None:
+ raise
+
+ # Legacy support (for ping)
+ if legacy:
+ return received
+
+ tr_load=True
+ tr_val=str(received)
+ return
+
+ def send_packet(packet, args=""):
+ global tr_load, tr_val
+ # This is a secret variable which disables threading
+ # This may cause hangs and other issues.
+ if persistent.nothreading:
+ send_packet_now(packet, args)
+ val=tr_val
+ return val
+
+ timeout=0.0
+ tr_load=False
+ tr_val=None
+ 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
+ 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")
+