######################################################################################## # 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 ######################################################################################## # Combat Functions init python: ######################## Server Communications def reload_battle(): raw=send_packet("reload_battle", "") bt=json_decode(raw) if (bt == ERR_JSONDECODER): return ERR_JSONDECODER return bt label combat: # Implement combat view $stdout("================= prepare for combat") $ hud_clear() $ show_img("bg %s" % TMP_BACKG, False) scene bg battle # Load variables python: try: fx1="unit_"+str(Battle["party"][0]["unit_id"]) show_img(fx1, False) # Validate except: fx1="" try: fx2="unit_"+str(Battle["party"][1]["unit_id"]) show_img(fx2, False) # Validate except: fx2="" try: fx3="unit_"+str(Battle["party"][2]["unit_id"]) show_img(fx3, False) # Validate except: fx3="" try: fx4="unit_"+str(Battle["party"][3]["unit_id"]) show_img(fx4, False) # Validate except: fx4="" try: fx5="unit_"+str(Battle["party"][4]["unit_id"]) show_img(fx5, False) # Validate except: fx5="" try: en1=Battle["enemy"][0] show_img("mob_"+str(en1["unit_id"]), False) # Validate except: en1=copy.copy(ERR_MOBSTRUCT) try: en2=Battle["enemy"][1] show_img("mob_"+str(en2["unit_id"]), False) # Validate except: en2=copy.copy(ERR_MOBSTRUCT) try: en3=Battle["enemy"][2] show_img("mob_"+str(en3["unit_id"]), False) # Validate except: en3=copy.copy(ERR_MOBSTRUCT) while len(Battle["party"]) < 4: Battle["party"].append(copy.copy(ERR_PLAYERSTRUCT)) $stdout("================= call begin") # TODO: Swap units support # TODO: Display Spheres in the right place $ use_sphere=[AP_NONE, AP_NONE, AP_NONE, AP_NONE, AP_NONE] $ btl_ready = False python: try: renpy.call_screen("battle", _with_none=True) except: traceback.print_exc() stdout("FAILED to render battle screen, trying again...") renpy.hide_screen("battle") sdelay(1.5) if (debug): raise renpy.jump("combat") stdout("================= call ended") btl_ready=True renpy.show_screen("battle") # TODO: Send to server new arrangement of units # Update Battle with server response $ response=loadbattle(Battle["party"]) # Maybe we error'ed out and should relog if (response in [FAILUREMSG, OFFLINEMSG, ERR_JSONDECODER, ERR_LOGIN_DEFAULT]): $ renpy.call_screen("msgbox", "Error:\n\n%s" % response) # Try again (x2) $ response=loadbattle(Battle["party"]) # Maybe we error'ed out and should relog if (response in [FAILUREMSG, OFFLINEMSG, ERR_JSONDECODER, ERR_LOGIN_DEFAULT]): $ renpy.call_screen("msgbox", "Error:\n\n%s" % response) # Try again (x3) $ response=loadbattle(Battle["party"]) # Maybe we error'ed out and should relog if (response in [FAILUREMSG, OFFLINEMSG, ERR_JSONDECODER, ERR_LOGIN_DEFAULT]): $ renpy.call_screen("msgbox", "Error:\n\n%s\nYou'll be taken to main screen." % response) # Better no longer insist return # TODO The server should send a JSON of results... # Wait for server to confirm the fight end if (response["result"] != ""): $ renpy.free_memory() # TODO: Announce the result screen jump results # Fight continues # TODO this is suboptimal, and the loops are also wrong # Maybe we should get info about what was used and whatnot? python: # TODO: Render sphere usage # Render enemy damage idx=0 while idx < len(Battle["enemy"]): try: # TODO: Draw the updates in "sequence" if (response["wave"] != Battle["wave"]): hit_someone_verbose(Battle["enemy"][idx], Battle["enemy"][idx]["hp"]) else: hit_someone_verbose(Battle["enemy"][idx], Battle["enemy"][idx]["hp"]-response["enemy"][idx]["hp"]) idx+=1 renpy.pause(0.1) except: idx+=1 pass # Render party damage idx=0 try: while idx < len(Battle["party"]): hit_someone_verbose(Battle["party"][idx], Battle["party"][idx]["hp"]-response["party"][idx]["hp"]) idx+=1 renpy.pause(0.1) except: idx+=1 pass # We may be going to boss fight if (response["wave"] != Battle["wave"] and response["wave"] == response["max_wave"]): play music MUSIC_BOSS.id() fadein 0.5 $ renpy.notify("BOSS FIGHT!") $ Battle=response jump combat label results: $ Player["status"]=ST_TOWN if (response["result"] == "DEFEAT"): $ renpy.call_screen("msgbox", "Result:\n%s" % _("DEFEAT")) jump restore play music MUSIC_VICTORY.id() fadein 0.5 # TODO: Use small icons python: # Save current quest to 'quest' variable (wasn't it set before?) quest=dl_search(allquests[Battle["world"]], "quest_id", Battle["quest_id"]) if (quest == ERR_INVALID): raise Exception("ERROR, QUEST NOT FOUND, %d" % Battle["quest_id"]) # Update other data Player["crystals"]+=int(response["crystals"]) Player["gp"]+=int(response["gp"]) Player["exp"]+=int(response["exp"]) # Write loot array loot="\n" if (response["crystals"]): loot+="%d Crystals\n" % response["crystals"] for unit in response["loot"]: try: loot+="%s %s\n" % (star_write(allunits[unit]["rare"]), allunits[unit]["name"]) except: loot+="error" # Maybe you ranked up? expmsg="Exp: %d -> %d" % (Player["exp"]-response["exp"], Player["exp"]) if (response["rank"]): Player["level"]+=1 Player["max_ap"]+=response["rank"]-1 # TODO: Update exp/max_exp fields update_ap() #Player["exp"]+=1 expmsg="PLAYER {b}RANK UP!{/b} (Max Ap: %d -> %d)" % (Player["max_ap"]-response["rank"]+1, Player["max_ap"]) Player["exp"]=response["rk_exp"] Player["max_exp"]=response["rk_mexp"] # Report screen try: renpy.call_screen("msgbox", "Result:\n%s\n\nGp: %d\n%s\nLoot:\n%s" % ( _("VICTORY!"), response["gp"], expmsg, "{size=12}"+loot+"{/size}" )) except: stdout("ERROR SHOWING VICTORY BOX") pass # Update inventory data and restore $ inv=get_inventory() python: try: renpy.call_screen("msgbox", "Error: %d" % int(inv)) except: Player["inv"]=dlist() for a in inv: Player["inv"].append(a) qid=Battle["quest_id"] # WAIT THERE! Perhaps we have some sort of history to show?! # TODO: Memory if Player["quest"] < qid: story=dl_search(allstory, "quest_id", qid) if (story != ERR_INVALID): try: renpy.hide_screen("battle") except: stdout("Failed to hide screen battle D:") pass hud_story() print(".:: Story logs (%d) ::." % qid) if isinstance(story["post_dialog"], str) or isinstance(story["post_dialog"], unicode): print("Calling in new context: %s" % (story["post_dialog"])) renpy.call_in_new_context(story["post_dialog"]) else: bg_is_showing=False for dial in story["post_dialog"]: # Background if str(dial["bg"]) != "": if bg_is_showing: renpy.hide("sbg") show_img("bg "+dial["bg"], tag="sbg") bg_is_showing=True show_img("dialog_"+dial["left_sprite"], at_list=[tleft], tag="l") show_img("dialog_"+dial["center_sprite"], at_list=[tcenter], tag="c") show_img("dialog_"+dial["right_sprite"], at_list=[tright], tag="r") renpy.say(dial["name"], dial["message"]) renpy.hide("l") renpy.hide("c") renpy.hide("r") print("%s: %s" % (dial["name"], dial["message"])) # Background Clean up if bg_is_showing: renpy.hide("sbg") del bg_is_showing # Maybe we should update player quest if not (quest["flags"] & 4): if Player["quest"] < Battle["quest_id"]: Player["quest"]=copy.copy(Battle["quest_id"]) # Cleaning up python: del Battle jump restore