# THIS IS A SOURCE CODE FILE FROM I'M NOT EVEN HUMAN THE GAME.
# IT COULD BE USED IN A DIFFERENT PIECE OF SOFTWARE ( LIKE A
# DIFFERENT GAME ), BUT IT WAS ORIGINALLY WRITTEN FOR I'M NOT
# EVEN HUMAN THE GAME.

# THE DEVELOPERS OF THE GAME ARE : (C) J.Y.AMIHUD, AYYZEE AND 
# OTHER CONTRIBUTORS. THIS AND OTHER FILES IN THIS GAME,
# UNLESS SPECIFICALLY NOTED, COULD BE USED UNDER THE TERMS OF
# GNU GENERAL PUBLIC LICENSE VERSION 3 OR ANY LATER VERSION.

import os
import json
import math
import cairo

from modules import ui
from modules import gameplay

def draw(game, outlayer, x, y, w, h, grid=True):

    """This function will draw the level it self"""

    # FPS ( Frames per second ) change mid game. It's inevitable.
    # To make things like falling and walking smooth even though
    # the speed of the frame rendering is changing, we need to
    # get this 'withFPS' value. To which we gonna multiply all things
    # that ought to be the same speed regardless of the FPS.
    
    withFPS = (1/game.FPS*60)


    # Camera position could be a float. And there is nothing wrong with
    # that. But it might cause rendering issues to keep it a float. So
    # before each frame we make sure to convert the camera into an integer.
    
    game.current["camera"][0] = int(game.current["camera"][0])
    game.current["camera"][1] = int(game.current["camera"][1])

    # Doing the same with the input values of 
    
    x = int(x)  # Where to draw the frame of the world X
    y = int(y)  #                                      Y
    w = int(w)  # The size of the frame of the world Width
    h = int(h)  #                                    Height

    # Now we gonna make an image buffer for this layer. It will temporarily store the
    # world that we draw before we are going to merge it with whatever layer it is.

    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,w,h) # This is the cairo image surface
    layer = cairo.Context(surface)                        # This is the brush for the image
    layer.set_antialias(cairo.ANTIALIAS_NONE)             # Turning off anti-aliasing to make it pixelated


    # If testing mode is enabled we want to outline the frame in red
    
    if game.current["testing"]:
        ui.color(game, layer, "red")
        layer.rectangle(0,0,w-1,h-1)
        layer.stroke()

    # 'grid' means in the level editor. ( Which is we show a grid ) . So if not in the level editor.
    # if in the game it self, then the sky should be 'blue'.
        
    if not grid:
        ui.color(game, layer, "blue")
        layer.rectangle(0,0,w,h)
        layer.fill()

    # Establishing the size of one tile. 
    
    sidex = 64
    sidey = 36
    offsetx = int(sidex / 2)
    offsety = int(sidey / 2)

    # If you are in the editor you want to move the world with the Middle Mouse Button
    # this code does the job. By moving the camera but the difference of mouse between
    # this frame and the last one.
    
    if game.current["MMB"] and grid\
    and int(game.current["mx"]) in range(x, x+w)\
    and int(game.current["my"]) in range(y, y+h):
        game.current["camera"][0] += (game.current["mx"] - game.previous["mx"])
        game.current["camera"][1] += (game.current["my"] - game.previous["my"])

    # For the editor ( and other things ) we might need to know which tile is currently
    # mouse over. It would be simple if tiles were square. But they are not, so it will
    # require multiple steps. Keep in mind the 'wmod' and 'wmo' variables to see how it's
    # calculated.
        
    if "world_mo" not in game.current:
        game.current["world_mo"] = [0,0,0]
    wmod = 1000000000       # Artbitrary large number
    wmo  = [-500,-500,0]    # This updates game.current["world_mo"] for the next frame



    # We do not want to render all the chunks ( part of the level ) at once.
    
    rendered_chunks = []
    render_coordinates = "0:0"

    # Coordinates of the currently selected character. The main character is usually 79th, but
    # it could be any other currently selected character. We are using 79 for convenience. 

    x79 = 0
    y79 = 0
    
    for asset in game.current["state"]["controlling"]:
        if game.current["state"]["controlling"][asset]:
            x79 = game.current["state"]["objects"][asset]["xyz"][0] + game.current["camera"][0]
            y79 = game.current["state"]["objects"][asset]["xyz"][1] + game.current["camera"][1]
            break
            
    # Some assets are not parts of the level chunk. Anything in the chunk is static. Dynamic
    # or temporary objects are rendered as a separate list. All of them also need to index
    # their tile ( to render properly and be obstructed by objects above and in front of them
    # and to calculate their physics ).

    render_assets = {}        # General list of assets to try rendering
    cell_assets_figurer = {}  # similar to 'wmod' variable but for each asset
    cell_assets_results = {}  # similar to 'wmo' variable but for each asset
    cell_colliders = {}       # list of possible collisions that the asset could make.
    
    if not grid:
        for asset, t in enumerate(game.current["state"]["objects"]):

            assx = game.current["state"]["objects"][asset]["xyz"][0] + game.current["camera"][0]
            assy = game.current["state"]["objects"][asset]["xyz"][1] + game.current["camera"][1]
                        
            # Let's exclude this step from all the character that are not on screen.
                    
            if int(assx) in range(int(x), int(x+w))\
            and int(assy) in range(int(x), int(y+h)):
            
                # Appending all the stuff to render the asset

                cell_assets_figurer[asset] = 1000000000
                cell_assets_results[asset] = [-500,-500]
                cell_colliders[asset] = [[game.current["state"]["objects"][asset]["cell"]]]         

                # Figuring out the asset's address. ( Tile in which the asset will render )

                addr = game.current["state"]["objects"][asset]["cell"]
                addz = game.current["state"]["objects"][asset]["xyz"][2]
                addr = str(addr[0])+":"+str(addr[1])+":"+str(int(round(addz)))

                # Adding the asset into the list of that tile.

                if addr not in render_assets:
                    render_assets[addr] = []

                render_assets[addr].append(asset)

    # If mouse in screen
    if int(game.current["mx"]) in range(int(x), int(x+w))\
    and int(game.current["my"]) in range(int(y), int(y+h)):
        mouseinscreen = True
    else:
        mouseinscreen = False
                

    ###################################################################
    #                                                                 #
    #                                                                 #
    #                           MAIN LOOP                             #
    #                                                                 #
    #                                                                 #
    ###################################################################

    # Here it becomes interesting. So we do 3 for loops one inside the other
    # which is quite necessary. Because the game is technically 3D even though
    # we could see it only from one side and it's rendered using static
    # pre-drawn assets.  
    
    for lh in range(-3, 4): # Every vertical level ( 0 ('lh == 0') being the active level) 

    
        # Depth of field hack ( setup )
        
        if lh > 1 or lh < -1:
            oldsurface = surface
            oldlayer = layer
            surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,w,h)
            layer = cairo.Context(surface)
            layer.set_antialias(cairo.ANTIALIAS_NONE)

            
        for th in range(int(h/offsety)+6): # Length-wise loop

            # Because we draw isometric, every second line of tiles
            # should be offset half the tile sideways.
            
            offx = game.current["camera"][0] % sidex
            offy = game.current["camera"][1] % sidey
            if th % 2 == 0:
                offx += offsetx
                
            for tw in range(int(w/sidex)+3): # For cells from right to left

                # Where to draw the cell
                drawx = (tw-2)*sidex+offx
                drawy = (th-3)*offsety+offy

                # Where is the cell's center
                centerx = offsetx+((tw-2)*sidex+offx)
                centery = offsety+((th-3)*offsety+offy)

                # What is the cell's tile address separatelly
                xaddr = 0-int( (game.current["camera"][0] - drawx) / offsetx )
                yaddr = 0-int( (game.current["camera"][1] - drawy) / offsety )

                # The address combined into list
                celladdr = [xaddr, yaddr]

                # To calculate the active cell we are going to find which one
                # of the cells is closest to the mouse ( or the active pixel ).
                
                # So here is the mouse coordinates on the map
                dtox = game.current["mx"]-x
                dtoy = game.current["my"]-y

                # Or position of the main character if the are playing.
                if not grid:
                    dtox = x79
                    dtoy = y79 

                
                # Then we look for the distance between the active pixel to the center
                # pixel of the cell
                dtomouse = ui.distance([dtox, dtoy],
                                    [centerx,centery])

                # Figuring out if the cell is closest to the active pixel.
                # Here are the 'wmo' and 'wmod' variables.
                if dtomouse < wmod and (mouseinscreen or not grid):
                    wmo = celladdr    # The closest ( so far ) address of a cell
                    wmod = dtomouse   # And the distance to the mouse of this cell
                    
                # Now we are trying to do that for all the characters on screen:
                if not grid:
                    for asset in cell_assets_figurer:
                        assx = game.current["state"]["objects"][asset]["xyz"][0] + game.current["camera"][0]
                        assy = game.current["state"]["objects"][asset]["xyz"][1] + game.current["camera"][1]
                        
                        # If the asset is in a reasonable proximity to the cell.
                        
                        if int(assx) in range(int(drawx-sidex), int(drawx+sidex*2))\
                        and int(assy) in range(int(drawy-sidey), int(drawy+sidey*2)):

                            # We find the distance of the asset to the cell.
                            
                            assd = ui.distance([assx, assy],
                                               [centerx,centery])
                            
                            
                            try:
                                prev = cell_assets_figurer[asset]
                                nowappnd = [celladdr,[centerx, centery]]

                                
                                # Similar to 'wmo' and 'wmod' but for the assset
                                if assd < prev:
                                    cell_assets_figurer[asset] = assd
                                    cell_assets_results[asset] = celladdr
                                    

                                # And if a cell is anywhere in the 15 pixel radius
                                # we want to add it as a possible collider. It will
                                # be checked later.
                                
                                if assd < 15:
                                    if nowappnd not in cell_colliders[asset]:
                                        cell_colliders[asset].append(nowappnd)
                                
                            except:
                                pass

                                
            
                # Managing chunk files ( dynamically loaded open world )    
                    
                # The chunk address for the cell ( a json file for the world cache )                
                chunk = str(int(xaddr/100))+":"+str(int(yaddr/100))+":"+str(game.current["camera"][2]+lh)

                # Loading chunk from the json
                if chunk not in game.chunks[1]:
                    load_chunk(game, chunk)
                    
                # Checking if the chunk is not rendered, to remove it from cache
                if not chunk in rendered_chunks:
                    rendered_chunks.append(chunk)

                # Address inside the chunk    
                addr  = str(xaddr)+":"+str(yaddr)
                

                # If current Vertical Layer
                if lh == 0:

                    if grid:
                        # Actually render the grid itself if in editor.
                        ui.image(game, layer,
                                 drawx,
                                 drawy,
                                 "assets/grid.png", "grid", color=False)

                    # If mouse over this cell
                    selectedcells = [game.current["world_mo"]]
                    if game.current["editor_brush"] > 1:
                        bax = game.current["world_mo"][0]
                        bay = game.current["world_mo"][1]
                        bs =  game.current["editor_brush"] - 1
                        for bx in range(bax-bs, bax+bs):
                            for by in range(bay-bs, bay+bs):
                                selectedcells.append([bx,by])
                    
                    if celladdr in selectedcells:
                        render_coordinates = addr

                        # Selection image grid thingy
                        if grid:
                            ui.image(game, layer,
                                     drawx,
                                     drawy,
                                     "assets/grid.png", "selected", color=False)
                            
                            # Pressing RMB to delete things in editor
                            if game.current["RMB"]:
                                if chunk not in game.current["temporary_chunks"]:
                                    game.current["temporary_chunks"].append(chunk)

                                try:
                                    
                                    del game.chunks[1][chunk][addr]
                                except:
                                    pass

                            # Pressing LMB to draw
                            if game.current["LMB"]:
                                if chunk not in game.current["temporary_chunks"]:
                                    game.current["temporary_chunks"].append(chunk)

                                types = game.current["editor_selection"][0]
                                asset = game.current["editor_selection"][1]
                                version = game.elements[types][asset][game.current["editor_selection"][2]]["title"]

                                addfile = types+"/"+asset

                                # Making sure they are both in the list
                                for i in (version, addfile):
                                    if i not in game.chunks[0]:
                                        game.chunks[0].append(i)
                                        # Getting their indexes
                                version = game.chunks[0].index(version)
                                addfile = game.chunks[0].index(addfile)

                                
                                game.chunks[1][chunk][addr] = [addfile, version]
                                        

                            # SAVE CHUNK
                            if ((not game.current["LMB"] and game.previous["LMB"])\
                            or (not game.current["RMB"] and game.previous["RMB"]))\
                            and game.settings["autosave"]:
                                save_chunk(game, chunk)
                      
                # Rendering of dynamic assets
                
                abaddr = addr+":"+str(game.current["camera"][2]+lh) # Asset address
                collision = False
                if abaddr in render_assets:
                    for asset in render_assets[abaddr]:

                        # Render location of the asset on screen
                        
                        assx = game.current["state"]["objects"][asset]["xyz"][0] + game.current["camera"][0]
                        assy = game.current["state"]["objects"][asset]["xyz"][1] + game.current["camera"][1]

                        gotdamage = False

                        
                        assaddr = game.current["state"]["objects"][asset]["cell"]
                        
                        asset_draw = game.current["state"]["objects"][asset]["asset"]
                        

                        #### VELOCITY CALCULATE ###

                        # Here we adjust the location of the asset by it's velocity
                        # to do things like gravity and jumping. And other fun things.

                        for v in [0,1,2]:
                            val = game.current["state"]["objects"][asset]["velocity"][v]

                            game.current["state"]["objects"][asset]["xyz"][v] += val *withFPS

                            if v == 2:
                                game.current["state"]["objects"][asset]["xyz"][1] -= (val*sidey) *withFPS
                            
                        #### FALLING LOGIC ####

                        falling = True
                        coll_cent = [centerx, centery]
                        for coll_cell in cell_colliders.get(asset, []):
                            colladdr = str(coll_cell[0][0])+":"+str(coll_cell[0][1])

                            if chunk+":"+colladdr in game.current["state"]["map_exclude"]:
                                continue
                            
                            try: # Colide with something endernieth
                                bottomchunk = chunk[:chunk.rfind(":")]+":"+str(game.current["camera"][2]+lh-1)
                                bottomaddr = colladdr[:addr.rfind(":")]+":"+str(assaddr[1]+2)
                                chunkasst = game.chunks[1][bottomchunk][bottomaddr]
                                chunkasst = [ game.chunks[0][chunkasst[0]],  game.chunks[0][chunkasst[1]] ]

                                colass, colsprite = "assets/elements/"+chunkasst[0], chunkasst[1]

                                frames = game.images[colass][colsprite]
                                frame = frames[game.current["anim_pulse"] % len(frames)]

                                if falling:
                                    falling = not frame.get("collision", True)

                                if frame.get("damage", False):
                                    game.current["state"]["objects"][asset]["health"] -= frame.get("damage_amount", 0.01) *withFPS
                                    gotdamage = True

                            except Exception as e:
                                pass

                        if falling:
                            
                            if game.current["state"]["objects"][asset]["velocity"][2] > -0.1: #*withFPS:
                                game.current["state"]["objects"][asset]["velocity"][2] -= 0.004 # *withFPS

                            game.current["state"]["objects"][asset]["grounded"] = False
                        else:

                            if game.current["state"]["objects"][asset]["velocity"][2] <= -0.1:
                                game.current["state"]["objects"][asset]["health"] -= 0.3
                                gotdamage = True

                            if game.current["state"]["objects"][asset]["velocity"][2] == 0:
                                game.current["state"]["objects"][asset]["xyz"][2] = int(round(game.current["state"]["objects"][asset]["xyz"][2]))
                            if game.current["state"]["objects"][asset]["velocity"][2] < 0:
                                game.current["state"]["objects"][asset]["velocity"][2] = 0

                            
                            ui.image(game, layer,
                                     assx,
                                     assy,
                                     "assets/elements/characters/shadow.png",
                                     "shadow-normal",
                                     offset=True, dynamic=True)
                                     
                            game.current["state"]["objects"][asset]["grounded"] = True


                        ##### WALLL COLLISION LOGIC #####

                        collision = False
                        coll_cent = [centerx, centery]
                        for coll_cell in cell_colliders.get(asset, []):
                            colladdr = str(coll_cell[0][0])+":"+str(coll_cell[0][1])

                            if chunk+":"+colladdr in game.current["state"]["map_exclude"]:
                                continue
                            
                            try:
                                # We are trying to get any thing at this point
                                chunkasst = game.chunks[1][chunk][colladdr]
                                chunkasst = [ game.chunks[0][chunkasst[0]],  game.chunks[0][chunkasst[1]] ]

                                colass, colsprite = "assets/elements/"+chunkasst[0], chunkasst[1]

                                frames = game.images[colass][colsprite]
                                frame = frames[game.current["anim_pulse"] % len(frames)]
                                
                                ramp = frame.get("ramp", False)
                                if ramp:
                                    # Ramp logic

                                    # TODO: The commented out code tried to make the ramp more dynamic.
                                    # it worked only half descently. Perhaps I need to rework it
                                    
                                    # if "ramp" not in game.current["state"]["objects"][asset]:
                                    #     game.current["state"]["objects"][asset]["ramp"] = game.current["state"]["objects"][asset]["xyz"].copy()

                                    # rampx = game.current["state"]["objects"][asset]["ramp"][0] + game.current["camera"][0]
                                    # rampy = game.current["state"]["objects"][asset]["ramp"][1] + game.current["camera"][1]
                                    # rampz = game.current["state"]["objects"][asset]["ramp"][2]

                                    # So we are trying to find a direction toward
                                    # a center of the ramp

                                    # rampcx = centerx
                                    # rampcy = centery

                                    # try:
                                    #     rampcx = coll_cell[1][0]
                                    #     rempcy = coll_cell[1][1]
                                    # except:
                                    #     pass

                                    # targetx = rampcx + (rampcx - rampx)
                                    # targety = rampcy + (rampcy - rampy) - 36

                                    # rampisx = 0-(assx - rampx) / (targetx - rampx)*-1
                                    # rampisy = 0-(assy - rampy) / (targety - rampy)*-1
                                    # rampis = (rampisx + rampisy) / 2

                                    # # Strength multiplier
                                    # rampis = rampis * 1
                                    
                                    # # Strength limiter
                                    # rampis = max(rampis, 0)
                                    # rampis = min(rampis, 1)

                                    game.current["state"]["objects"][asset]["xyz"][2] = int(game.current["camera"][2]+lh+1)#rampz+rampis
                                    # TODO: I was trying to offset the characters on Y axis as well
                                    # but it tent to break things. Look into it.
                                    game.current["state"]["objects"][asset]["xyz"][1]  -= 36
                                    #game.current["state"]["objects"][asset]["ramp"][1] -= rampis*36
                                    
                                # else:
                                #     try:
                                #         del game.current["state"]["objects"][asset]["ramp"]
                                #     except:
                                #         pass

                                
                                if not collision and not ramp:
                                    collision = frame.get("collision", True)

                                if not frame.get("collision", True):
                                    continue
                                    
                                if collision:
                                    col_div = 3
                                    try:
                                        coll_cent = coll_cell[1]
                                    except:
                                        pass
                                    

                            except:

                                # If we still don't have collision we might check the dynamic objects.
                                if len(render_assets[abaddr]) > 1:
                                    collision = True
                                    col_div = 1
                                    
                                try:
                                    del game.current["state"]["objects"][asset]["ramp"]
                                except:
                                    pass

                        if collision:
                            # If we got, we have colision

                            game.current["state"]["objects"][asset]["xyz"] = game.current["state"]["objects"][asset]["last_before_colision"].copy()
                            game.current["state"]["objects"][asset]["xyz"][0] += 0-(coll_cent[0]- assx)/col_div
                            game.current["state"]["objects"][asset]["xyz"][1] += 0-(coll_cent[1]- assy)/col_div
                            game.current["state"]["objects"][asset]["xyz"][2] += 0-(int(game.current["camera"][2]+lh)- game.current["state"]["objects"][asset]["xyz"][2])/col_div

                            game.current["state"]["objects"][asset]["grounded"] = False
                            
                        else:
                            game.current["state"]["objects"][asset]["last_before_colision"] = game.current["state"]["objects"][asset]["xyz"].copy()

                        orientation = game.current["state"]["objects"][asset]["orientation"]
                        if orientation not in game.images.get("assets/elements/"+asset_draw+".png",{}):
                            orientation = "Down-Left"

                        
                            
                        colordamage = False
                        if gotdamage and game.current["state"]["objects"][asset]["orientation"] != "Dead":
                            colordamage = True
                            ui.image(game, layer,
                                 assx,
                                 assy,
                                 "assets/elements/"+asset_draw+".png",
                                 orientation,
                                 offset=True, dynamic=True)

                            ui.color(game, layer, "red", 0.5)

                            
                        ui.image(game, layer,
                                 assx,
                                 assy,
                                 "assets/elements/"+asset_draw+".png",
                                 orientation,
                                 offset=True, dynamic=True, color=colordamage)


                        
                       
                    
                            
                # Try drawing the asset in this cell
        
                try:

                    chunkasst = game.chunks[1][chunk][addr]
                    chunkasst = [ game.chunks[0][chunkasst[0]],  game.chunks[0][chunkasst[1]] ]


                    colass, colsprite = "assets/elements/"+chunkasst[0], chunkasst[1]

                    

                    
                    if not grid:
                        if chunk+":"+addr in game.current["state"]["map_exclude"]:
                            continue

                        
                        colass, colsprite = "assets/elements/"+chunkasst[0], chunkasst[1]

                        frames = game.images[colass][colsprite]
                        frame = frames[game.current["anim_pulse"] % len(frames)]

                        ##### IF THE OBJECT IS DYNAMIC #######

                        dynamic = frame.get("dynamic", False)


                        if dynamic:
                            print("DYNAMIC", colass)
                            newx = centerx - game.current["camera"][0]
                            newy = centery - game.current["camera"][1] -5
                            newz = game.current["camera"][2]+lh# + 1

                            game.current["state"]["objects"].append({
                                "asset":chunkasst[0].replace(".png", ""),
                                "xyz":[newx,newy,newz],
                                "velocity":[0,0,0],
                                "cell":[0,0],
                                "last_before_colision":[0,0,0],
                                "check_mark":[0,0,0],
                                "orientation":colsprite,
                                "grounded":False,
                                "health":1.0,
                                "time-falling":0})
                            game.current["state"]["map_exclude"].append(chunk+":"+addr)
                            index_for_this_character = len(game.current["state"]["objects"])-1
                            
                            if frame.get("main_character", False):
                                try:
                                    gameplay.follow_last(game, index_for_this_character)
                                except Exception as e:
                                    print("What", e)
                                
                                game.current["state"]["controlling"][index_for_this_character] = False
                            
                            continue


                    if grid:
                        # Dynamic transparency 
                        dalpha = 1

                        #        [ 0:0 ]
                        #    [ -1:1 ][ 1:1 ]
                        #        [ 0:2 ]
                        #
                        seltmp = game.current["world_mo"]
                        tcolumns = [
                            seltmp,
                            [seltmp[0]-1, seltmp[1]+1],
                            [seltmp[0]+1, seltmp[1]+1],
                            [seltmp[0], seltmp[1]+2]]

                        for i in tcolumns:
                            if celladdr[0] == i[0]\
                            and celladdr[1] in range( i[1]-(lh*2), i[1]+1)\
                            and ( mouseinscreen or not grid ):
                                if celladdr == seltmp and lh == 0 and grid:
                                    dalpha = 1
                                else:
                                    dalpha = 0.25
                                    if lh > 1:
                                        dalpha = 0.1

                    else:
                        dalpha = 1                


                    frames = game.images[colass][colsprite]
                    frame = frames[game.current["anim_pulse"] % len(frames)]
                                
                    invisible = frame.get("invisible", False)
                        
                                    
                    if grid or not invisible:
                        # Draw cell        
                        ui.image(game, layer,
                                 drawx,
                                 drawy,
                                 "assets/elements/"+chunkasst[0], chunkasst[1],
                                 offset=True, alpha=dalpha)


                    
                    
                    # Highlight cell in red when mouse over
                    if celladdr in selectedcells :
                        if lh == 0:

                            if not grid:
                                pass
                                # game.current["state"]["4211D79"]["colision"] = \
                                #     [drawx+offsetx - game.current["camera"][0],
                                #      drawy+offsety - game.current["camera"][1]] 
                            else:
                                ui.color(game, layer, "red", 0.5)
                                ui.image(game, layer,
                                         drawx,
                                         drawy,
                                         "assets/elements/"+chunkasst[0], chunkasst[1],
                                         offset=True, color=True)

                        # Select the current thing for the editor.
                        try:
                            if game.previous["MMB"] and not game.current["MMB"]\
                            and int(game.current["mx"]) == int(game.previous["MMB"][0])\
                            and int(game.current["my"]) == int(game.previous["MMB"][1]):

                                types = chunkasst[0].split("/")[0]
                                asset = chunkasst[0].split("/")[1]
                                for version, names in enumerate(game.elements[types][asset]):
                                    if names["title"] == chunkasst[1]:
                                        break

                                game.current["editor_selection"][0] = types
                                game.current["editor_selection"][1] = asset
                                game.current["editor_selection"][2] = version
                        except Exception as e:
                            print(e)
                            
                    if collision and game.current["testing"]:
                        ui.image(game, layer,
                                 drawx,
                                 drawy,
                                 "assets/grid.png", "grid", color=False)
                        
                except Exception as e:
                    pass
                
                
        # Depth of field actually done
        if lh > 1 or lh < -1:


            factor = ( max(lh, 0) - min(lh, 0) ) 
            

            oldlayer.set_source_surface(ui.blur(surface, game, factor), 0, 0)
            if lh > 0:
                oldlayer.paint_with_alpha(1/(factor))
            else:
                oldlayer.paint()
                ui.color(game, oldlayer, "blue", alpha=1/(factor))
                oldlayer.rectangle(0,0,w-1,h-1)
                oldlayer.fill()
                
                
            layer = oldlayer
            surface = oldsurface
                
    # If Editor Show the currently selected item
    if grid:
        types = game.current["editor_selection"][0]
        asset = game.current["editor_selection"][1]
        version = game.elements[types][asset][game.current["editor_selection"][2]]
        ui.image(game, layer,
                 game.current["mx"]-x-offsetx,
                 game.current["my"]-y-offsety,
                 "assets/elements/"+types+"/"+asset, version["title"], offset=True, alpha=0.5)

    # Select the mouse over cell
    game.current["world_mo"] = wmo

  
    
    if not grid:
        for asset, t in enumerate(game.current["state"]["objects"]):
            try:
                game.current["state"]["objects"][asset]["cell"] = cell_assets_results[asset]
            except:
                pass


    # Removing chunks that are not rendered currently from the memory
    for i in list(game.chunks[1].keys()):
        if i not in rendered_chunks and i not in game.current["temporary_chunks"]:
            del game.chunks[1][i]

    # The current Z ( height ) rendering in top, right corner
    if game.current["testing"]:
        ui.color(game, layer, "yellow")
        ui.text(game,layer, str(game.current["camera"][2]),
                            60,
                            40)
        ui.text(game,layer, render_coordinates,
                            60,
                            60)
    

    # Numpad + to go up
    if 65451 in game.current["keys"]:
        game.current["camera"][2] += 1
        game.current["keys"] = []

    # Numpad - to go down
    if 65453 in game.current["keys"]:
        game.current["camera"][2] -= 1
        game.current["keys"] = []
    
    # Drawing the world to the outlayer
    outlayer.set_source_surface(surface, x , y)
    outlayer.paint()


    
def update_elements(game):

    """This function caches all assets"""

    game.elements = {}
    
    # elements
    #   Element type ( blocks, characters, vehicles )
    #     Image assets
    
    for types in os.listdir(os.getcwd()+"/assets/elements"):

        game.elements[types] = {}

        for asset in os.listdir(os.getcwd()+"/assets/elements/"+types):

            if asset.endswith(".png"):
                asseturl = "assets/elements/"+types+"/"+asset
                ui.cache_sprite_sheet(game, asseturl, [types, asset])

    # Now let's generate the selection for the editor
    game.current["editor_selection"] = [
        list(game.elements.keys())[0],
        list(list(game.elements.values())[0].keys())[0],
        0]

    # Make the brush 0
    game.current["editor_brush"] = 1


    # YANK THAT CODE LATER

    # every chunk is 100 by 100
    game.chunks = [[],{}]

    game.current["temporary_chunks"] = [] # Chunks that are not saved


def save_chunk(game, chunk_input=False):

    """This function saves the chunk"""
    for c in game.chunks[1]:
        if chunk_input == c or not chunk_input:
            chunk = c
            print("saving chunk", chunk)
            
            # Getting the raw chunk
            savedata = [[], game.chunks[1][chunk].copy()]

    
            # Adding all the asset names to it
            for ind in savedata[1]:
                i = savedata[1][ind]
                savedata[1][ind] = i.copy()

                for n, b in enumerate(i):
                    add = game.chunks[0][b]
                    if add not in savedata[0]:
                        savedata[0].append(add)

                    savedata[1][ind][n] = savedata[0].index(add)

            # Save the json
            savefilename = "assets/worlds/"+game.settings["world"]+"/"+chunk+".json"

            with open(savefilename, 'w') as f:
                json.dump(savedata, f)

            try:
                game.current["temporary_chunks"].remove(chunk)
            except:
                pass

    print("saved")

def load_chunk(game, chunk):

    """This function loads a chunk."""

    # Load the json
    loadfilename = "assets/worlds/"+game.settings["world"]+"/"+chunk+".json"


    
    try:
        with open(loadfilename) as f:
            loaddata = json.load(f)
        
    except:
        loaddata = [[],{}]

    for ind in  loaddata[1]:

        i = loaddata[1][ind]
        
        for n, b in enumerate(i):
            add = loaddata[0][b]
            if add not in game.chunks[0]:
                game.chunks[0].append(add)

            loaddata[1][ind][n] = game.chunks[0].index(add)

    game.chunks[1][chunk] = loaddata[1]

    
