world.py 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. # THIS IS A SOURCE CODE FILE FROM I'M NOT EVEN HUMAN THE GAME.
  2. # IT COULD BE USED IN A DIFFERENT PIECE OF SOFTWARE ( LIKE A
  3. # DIFFERENT GAME ), BUT IT WAS ORIGINALLY WRITTEN FOR I'M NOT
  4. # EVEN HUMAN THE GAME.
  5. # THE DEVELOPERS OF THE GAME ARE : (C) J.Y.AMIHUD, AYYZEE AND
  6. # OTHER CONTRIBUTORS. THIS AND OTHER FILES IN THIS GAME,
  7. # UNLESS SPECIFICALLY NOTED, COULD BE USED UNDER THE TERMS OF
  8. # GNU GENERAL PUBLIC LICENSE VERSION 3 OR ANY LATER VERSION.
  9. import os
  10. import json
  11. import math
  12. import cairo
  13. from modules import ui
  14. from modules import gameplay
  15. def draw(game, outlayer, x, y, w, h, grid=True):
  16. """This function will draw the level it self"""
  17. # FPS ( Frames per second ) change mid game. It's inevitable.
  18. # To make things like falling and walking smooth even though
  19. # the speed of the frame rendering is changing, we need to
  20. # get this 'withFPS' value. To which we gonna multiply all things
  21. # that ought to be the same speed regardless of the FPS.
  22. withFPS = (1/game.FPS*60)
  23. # Camera position could be a float. And there is nothing wrong with
  24. # that. But it might cause rendering issues to keep it a float. So
  25. # before each frame we make sure to convert the camera into an integer.
  26. game.current["camera"][0] = int(game.current["camera"][0])
  27. game.current["camera"][1] = int(game.current["camera"][1])
  28. # Doing the same with the input values of
  29. x = int(x) # Where to draw the frame of the world X
  30. y = int(y) # Y
  31. w = int(w) # The size of the frame of the world Width
  32. h = int(h) # Height
  33. # Now we gonna make an image buffer for this layer. It will temporarily store the
  34. # world that we draw before we are going to merge it with whatever layer it is.
  35. surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,w,h) # This is the cairo image surface
  36. layer = cairo.Context(surface) # This is the brush for the image
  37. layer.set_antialias(cairo.ANTIALIAS_NONE) # Turning off anti-aliasing to make it pixelated
  38. # If testing mode is enabled we want to outline the frame in red
  39. if game.current["testing"]:
  40. ui.color(game, layer, "red")
  41. layer.rectangle(0,0,w-1,h-1)
  42. layer.stroke()
  43. # 'grid' means in the level editor. ( Which is we show a grid ) . So if not in the level editor.
  44. # if in the game it self, then the sky should be 'blue'.
  45. if not grid:
  46. ui.color(game, layer, "blue")
  47. layer.rectangle(0,0,w,h)
  48. layer.fill()
  49. # Establishing the size of one tile.
  50. sidex = 64
  51. sidey = 36
  52. offsetx = int(sidex / 2)
  53. offsety = int(sidey / 2)
  54. # If you are in the editor you want to move the world with the Middle Mouse Button
  55. # this code does the job. By moving the camera but the difference of mouse between
  56. # this frame and the last one.
  57. if game.current["MMB"] and grid\
  58. and int(game.current["mx"]) in range(x, x+w)\
  59. and int(game.current["my"]) in range(y, y+h):
  60. game.current["camera"][0] += (game.current["mx"] - game.previous["mx"])
  61. game.current["camera"][1] += (game.current["my"] - game.previous["my"])
  62. # For the editor ( and other things ) we might need to know which tile is currently
  63. # mouse over. It would be simple if tiles were square. But they are not, so it will
  64. # require multiple steps. Keep in mind the 'wmod' and 'wmo' variables to see how it's
  65. # calculated.
  66. if "world_mo" not in game.current:
  67. game.current["world_mo"] = [0,0,0]
  68. wmod = 1000000000 # Artbitrary large number
  69. wmo = [-500,-500,0] # This updates game.current["world_mo"] for the next frame
  70. # We do not want to render all the chunks ( part of the level ) at once.
  71. rendered_chunks = []
  72. render_coordinates = "0:0"
  73. # Coordinates of the currently selected character. The main character is usually 79th, but
  74. # it could be any other currently selected character. We are using 79 for convenience.
  75. x79 = 0
  76. y79 = 0
  77. for asset in game.current["state"]["controlling"]:
  78. if game.current["state"]["controlling"][asset]:
  79. x79 = game.current["state"]["objects"][asset]["xyz"][0] + game.current["camera"][0]
  80. y79 = game.current["state"]["objects"][asset]["xyz"][1] + game.current["camera"][1]
  81. break
  82. # Some assets are not parts of the level chunk. Anything in the chunk is static. Dynamic
  83. # or temporary objects are rendered as a separate list. All of them also need to index
  84. # their tile ( to render properly and be obstructed by objects above and in front of them
  85. # and to calculate their physics ).
  86. render_assets = {} # General list of assets to try rendering
  87. cell_assets_figurer = {} # similar to 'wmod' variable but for each asset
  88. cell_assets_results = {} # similar to 'wmo' variable but for each asset
  89. cell_colliders = {} # list of possible collisions that the asset could make.
  90. if not grid:
  91. for asset, t in enumerate(game.current["state"]["objects"]):
  92. assx = game.current["state"]["objects"][asset]["xyz"][0] + game.current["camera"][0]
  93. assy = game.current["state"]["objects"][asset]["xyz"][1] + game.current["camera"][1]
  94. # Let's exclude this step from all the character that are not on screen.
  95. if int(assx) in range(int(x), int(x+w))\
  96. and int(assy) in range(int(x), int(y+h)):
  97. # Appending all the stuff to render the asset
  98. cell_assets_figurer[asset] = 1000000000
  99. cell_assets_results[asset] = [-500,-500]
  100. cell_colliders[asset] = [[game.current["state"]["objects"][asset]["cell"]]]
  101. # Figuring out the asset's address. ( Tile in which the asset will render )
  102. addr = game.current["state"]["objects"][asset]["cell"]
  103. addz = game.current["state"]["objects"][asset]["xyz"][2]
  104. addr = str(addr[0])+":"+str(addr[1])+":"+str(int(round(addz)))
  105. # Adding the asset into the list of that tile.
  106. if addr not in render_assets:
  107. render_assets[addr] = []
  108. render_assets[addr].append(asset)
  109. # If mouse in screen
  110. if int(game.current["mx"]) in range(int(x), int(x+w))\
  111. and int(game.current["my"]) in range(int(y), int(y+h)):
  112. mouseinscreen = True
  113. else:
  114. mouseinscreen = False
  115. ###################################################################
  116. # #
  117. # #
  118. # MAIN LOOP #
  119. # #
  120. # #
  121. ###################################################################
  122. # Here it becomes interesting. So we do 3 for loops one inside the other
  123. # which is quite necessary. Because the game is technically 3D even though
  124. # we could see it only from one side and it's rendered using static
  125. # pre-drawn assets.
  126. for lh in range(-3, 4): # Every vertical level ( 0 ('lh == 0') being the active level)
  127. # Depth of field hack ( setup )
  128. if lh > 1 or lh < -1:
  129. oldsurface = surface
  130. oldlayer = layer
  131. surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,w,h)
  132. layer = cairo.Context(surface)
  133. layer.set_antialias(cairo.ANTIALIAS_NONE)
  134. for th in range(int(h/offsety)+6): # Length-wise loop
  135. # Because we draw isometric, every second line of tiles
  136. # should be offset half the tile sideways.
  137. offx = game.current["camera"][0] % sidex
  138. offy = game.current["camera"][1] % sidey
  139. if th % 2 == 0:
  140. offx += offsetx
  141. for tw in range(int(w/sidex)+3): # For cells from right to left
  142. # Where to draw the cell
  143. drawx = (tw-2)*sidex+offx
  144. drawy = (th-3)*offsety+offy
  145. # Where is the cell's center
  146. centerx = offsetx+((tw-2)*sidex+offx)
  147. centery = offsety+((th-3)*offsety+offy)
  148. # What is the cell's tile address separatelly
  149. xaddr = 0-int( (game.current["camera"][0] - drawx) / offsetx )
  150. yaddr = 0-int( (game.current["camera"][1] - drawy) / offsety )
  151. # The address combined into list
  152. celladdr = [xaddr, yaddr]
  153. # To calculate the active cell we are going to find which one
  154. # of the cells is closest to the mouse ( or the active pixel ).
  155. # So here is the mouse coordinates on the map
  156. dtox = game.current["mx"]-x
  157. dtoy = game.current["my"]-y
  158. # Or position of the main character if the are playing.
  159. if not grid:
  160. dtox = x79
  161. dtoy = y79
  162. # Then we look for the distance between the active pixel to the center
  163. # pixel of the cell
  164. dtomouse = ui.distance([dtox, dtoy],
  165. [centerx,centery])
  166. # Figuring out if the cell is closest to the active pixel.
  167. # Here are the 'wmo' and 'wmod' variables.
  168. if dtomouse < wmod and (mouseinscreen or not grid):
  169. wmo = celladdr # The closest ( so far ) address of a cell
  170. wmod = dtomouse # And the distance to the mouse of this cell
  171. # Now we are trying to do that for all the characters on screen:
  172. if not grid:
  173. for asset in cell_assets_figurer:
  174. assx = game.current["state"]["objects"][asset]["xyz"][0] + game.current["camera"][0]
  175. assy = game.current["state"]["objects"][asset]["xyz"][1] + game.current["camera"][1]
  176. # If the asset is in a reasonable proximity to the cell.
  177. if int(assx) in range(int(drawx-sidex), int(drawx+sidex*2))\
  178. and int(assy) in range(int(drawy-sidey), int(drawy+sidey*2)):
  179. # We find the distance of the asset to the cell.
  180. assd = ui.distance([assx, assy],
  181. [centerx,centery])
  182. try:
  183. prev = cell_assets_figurer[asset]
  184. nowappnd = [celladdr,[centerx, centery]]
  185. # Similar to 'wmo' and 'wmod' but for the assset
  186. if assd < prev:
  187. cell_assets_figurer[asset] = assd
  188. cell_assets_results[asset] = celladdr
  189. # And if a cell is anywhere in the 15 pixel radius
  190. # we want to add it as a possible collider. It will
  191. # be checked later.
  192. if assd < 15:
  193. if nowappnd not in cell_colliders[asset]:
  194. cell_colliders[asset].append(nowappnd)
  195. except:
  196. pass
  197. # Managing chunk files ( dynamically loaded open world )
  198. # The chunk address for the cell ( a json file for the world cache )
  199. chunk = str(int(xaddr/100))+":"+str(int(yaddr/100))+":"+str(game.current["camera"][2]+lh)
  200. # Loading chunk from the json
  201. if chunk not in game.chunks[1]:
  202. load_chunk(game, chunk)
  203. # Checking if the chunk is not rendered, to remove it from cache
  204. if not chunk in rendered_chunks:
  205. rendered_chunks.append(chunk)
  206. # Address inside the chunk
  207. addr = str(xaddr)+":"+str(yaddr)
  208. # If current Vertical Layer
  209. if lh == 0:
  210. if grid:
  211. # Actually render the grid itself if in editor.
  212. ui.image(game, layer,
  213. drawx,
  214. drawy,
  215. "assets/grid.png", "grid", color=False)
  216. # If mouse over this cell
  217. selectedcells = [game.current["world_mo"]]
  218. if game.current["editor_brush"] > 1:
  219. bax = game.current["world_mo"][0]
  220. bay = game.current["world_mo"][1]
  221. bs = game.current["editor_brush"] - 1
  222. for bx in range(bax-bs, bax+bs):
  223. for by in range(bay-bs, bay+bs):
  224. selectedcells.append([bx,by])
  225. if celladdr in selectedcells:
  226. render_coordinates = addr
  227. # Selection image grid thingy
  228. if grid:
  229. ui.image(game, layer,
  230. drawx,
  231. drawy,
  232. "assets/grid.png", "selected", color=False)
  233. # Pressing RMB to delete things in editor
  234. if game.current["RMB"]:
  235. if chunk not in game.current["temporary_chunks"]:
  236. game.current["temporary_chunks"].append(chunk)
  237. try:
  238. del game.chunks[1][chunk][addr]
  239. except:
  240. pass
  241. # Pressing LMB to draw
  242. if game.current["LMB"]:
  243. if chunk not in game.current["temporary_chunks"]:
  244. game.current["temporary_chunks"].append(chunk)
  245. types = game.current["editor_selection"][0]
  246. asset = game.current["editor_selection"][1]
  247. version = game.elements[types][asset][game.current["editor_selection"][2]]["title"]
  248. addfile = types+"/"+asset
  249. # Making sure they are both in the list
  250. for i in (version, addfile):
  251. if i not in game.chunks[0]:
  252. game.chunks[0].append(i)
  253. # Getting their indexes
  254. version = game.chunks[0].index(version)
  255. addfile = game.chunks[0].index(addfile)
  256. game.chunks[1][chunk][addr] = [addfile, version]
  257. # SAVE CHUNK
  258. if ((not game.current["LMB"] and game.previous["LMB"])\
  259. or (not game.current["RMB"] and game.previous["RMB"]))\
  260. and game.settings["autosave"]:
  261. save_chunk(game, chunk)
  262. # Rendering of dynamic assets
  263. abaddr = addr+":"+str(game.current["camera"][2]+lh) # Asset address
  264. collision = False
  265. if abaddr in render_assets:
  266. for asset in render_assets[abaddr]:
  267. # Render location of the asset on screen
  268. assx = game.current["state"]["objects"][asset]["xyz"][0] + game.current["camera"][0]
  269. assy = game.current["state"]["objects"][asset]["xyz"][1] + game.current["camera"][1]
  270. gotdamage = False
  271. assaddr = game.current["state"]["objects"][asset]["cell"]
  272. asset_draw = game.current["state"]["objects"][asset]["asset"]
  273. #### VELOCITY CALCULATE ###
  274. # Here we adjust the location of the asset by it's velocity
  275. # to do things like gravity and jumping. And other fun things.
  276. for v in [0,1,2]:
  277. val = game.current["state"]["objects"][asset]["velocity"][v]
  278. game.current["state"]["objects"][asset]["xyz"][v] += val *withFPS
  279. if v == 2:
  280. game.current["state"]["objects"][asset]["xyz"][1] -= (val*sidey) *withFPS
  281. #### FALLING LOGIC ####
  282. falling = True
  283. coll_cent = [centerx, centery]
  284. for coll_cell in cell_colliders.get(asset, []):
  285. colladdr = str(coll_cell[0][0])+":"+str(coll_cell[0][1])
  286. if chunk+":"+colladdr in game.current["state"]["map_exclude"]:
  287. continue
  288. try: # Colide with something endernieth
  289. bottomchunk = chunk[:chunk.rfind(":")]+":"+str(game.current["camera"][2]+lh-1)
  290. bottomaddr = colladdr[:addr.rfind(":")]+":"+str(assaddr[1]+2)
  291. chunkasst = game.chunks[1][bottomchunk][bottomaddr]
  292. chunkasst = [ game.chunks[0][chunkasst[0]], game.chunks[0][chunkasst[1]] ]
  293. colass, colsprite = "assets/elements/"+chunkasst[0], chunkasst[1]
  294. frames = game.images[colass][colsprite]
  295. frame = frames[game.current["anim_pulse"] % len(frames)]
  296. if falling:
  297. falling = not frame.get("collision", True)
  298. if frame.get("damage", False):
  299. game.current["state"]["objects"][asset]["health"] -= frame.get("damage_amount", 0.01) *withFPS
  300. gotdamage = True
  301. except Exception as e:
  302. pass
  303. if falling:
  304. if game.current["state"]["objects"][asset]["velocity"][2] > -0.1: #*withFPS:
  305. game.current["state"]["objects"][asset]["velocity"][2] -= 0.004 # *withFPS
  306. game.current["state"]["objects"][asset]["grounded"] = False
  307. else:
  308. if game.current["state"]["objects"][asset]["velocity"][2] <= -0.1:
  309. game.current["state"]["objects"][asset]["health"] -= 0.3
  310. gotdamage = True
  311. if game.current["state"]["objects"][asset]["velocity"][2] == 0:
  312. game.current["state"]["objects"][asset]["xyz"][2] = int(round(game.current["state"]["objects"][asset]["xyz"][2]))
  313. if game.current["state"]["objects"][asset]["velocity"][2] < 0:
  314. game.current["state"]["objects"][asset]["velocity"][2] = 0
  315. ui.image(game, layer,
  316. assx,
  317. assy,
  318. "assets/elements/characters/shadow.png",
  319. "shadow-normal",
  320. offset=True, dynamic=True)
  321. game.current["state"]["objects"][asset]["grounded"] = True
  322. ##### WALLL COLLISION LOGIC #####
  323. collision = False
  324. coll_cent = [centerx, centery]
  325. for coll_cell in cell_colliders.get(asset, []):
  326. colladdr = str(coll_cell[0][0])+":"+str(coll_cell[0][1])
  327. if chunk+":"+colladdr in game.current["state"]["map_exclude"]:
  328. continue
  329. try:
  330. # We are trying to get any thing at this point
  331. chunkasst = game.chunks[1][chunk][colladdr]
  332. chunkasst = [ game.chunks[0][chunkasst[0]], game.chunks[0][chunkasst[1]] ]
  333. colass, colsprite = "assets/elements/"+chunkasst[0], chunkasst[1]
  334. frames = game.images[colass][colsprite]
  335. frame = frames[game.current["anim_pulse"] % len(frames)]
  336. ramp = frame.get("ramp", False)
  337. if ramp:
  338. # Ramp logic
  339. # TODO: The commented out code tried to make the ramp more dynamic.
  340. # it worked only half descently. Perhaps I need to rework it
  341. # if "ramp" not in game.current["state"]["objects"][asset]:
  342. # game.current["state"]["objects"][asset]["ramp"] = game.current["state"]["objects"][asset]["xyz"].copy()
  343. # rampx = game.current["state"]["objects"][asset]["ramp"][0] + game.current["camera"][0]
  344. # rampy = game.current["state"]["objects"][asset]["ramp"][1] + game.current["camera"][1]
  345. # rampz = game.current["state"]["objects"][asset]["ramp"][2]
  346. # So we are trying to find a direction toward
  347. # a center of the ramp
  348. # rampcx = centerx
  349. # rampcy = centery
  350. # try:
  351. # rampcx = coll_cell[1][0]
  352. # rempcy = coll_cell[1][1]
  353. # except:
  354. # pass
  355. # targetx = rampcx + (rampcx - rampx)
  356. # targety = rampcy + (rampcy - rampy) - 36
  357. # rampisx = 0-(assx - rampx) / (targetx - rampx)*-1
  358. # rampisy = 0-(assy - rampy) / (targety - rampy)*-1
  359. # rampis = (rampisx + rampisy) / 2
  360. # # Strength multiplier
  361. # rampis = rampis * 1
  362. # # Strength limiter
  363. # rampis = max(rampis, 0)
  364. # rampis = min(rampis, 1)
  365. game.current["state"]["objects"][asset]["xyz"][2] = int(game.current["camera"][2]+lh+1)#rampz+rampis
  366. # TODO: I was trying to offset the characters on Y axis as well
  367. # but it tent to break things. Look into it.
  368. game.current["state"]["objects"][asset]["xyz"][1] -= 36
  369. #game.current["state"]["objects"][asset]["ramp"][1] -= rampis*36
  370. # else:
  371. # try:
  372. # del game.current["state"]["objects"][asset]["ramp"]
  373. # except:
  374. # pass
  375. if not collision and not ramp:
  376. collision = frame.get("collision", True)
  377. if not frame.get("collision", True):
  378. continue
  379. if collision:
  380. col_div = 3
  381. try:
  382. coll_cent = coll_cell[1]
  383. except:
  384. pass
  385. except:
  386. # If we still don't have collision we might check the dynamic objects.
  387. if len(render_assets[abaddr]) > 1:
  388. collision = True
  389. col_div = 1
  390. try:
  391. del game.current["state"]["objects"][asset]["ramp"]
  392. except:
  393. pass
  394. if collision:
  395. # If we got, we have colision
  396. game.current["state"]["objects"][asset]["xyz"] = game.current["state"]["objects"][asset]["last_before_colision"].copy()
  397. game.current["state"]["objects"][asset]["xyz"][0] += 0-(coll_cent[0]- assx)/col_div
  398. game.current["state"]["objects"][asset]["xyz"][1] += 0-(coll_cent[1]- assy)/col_div
  399. game.current["state"]["objects"][asset]["xyz"][2] += 0-(int(game.current["camera"][2]+lh)- game.current["state"]["objects"][asset]["xyz"][2])/col_div
  400. game.current["state"]["objects"][asset]["grounded"] = False
  401. else:
  402. game.current["state"]["objects"][asset]["last_before_colision"] = game.current["state"]["objects"][asset]["xyz"].copy()
  403. orientation = game.current["state"]["objects"][asset]["orientation"]
  404. if orientation not in game.images.get("assets/elements/"+asset_draw+".png",{}):
  405. orientation = "Down-Left"
  406. colordamage = False
  407. if gotdamage and game.current["state"]["objects"][asset]["orientation"] != "Dead":
  408. colordamage = True
  409. ui.image(game, layer,
  410. assx,
  411. assy,
  412. "assets/elements/"+asset_draw+".png",
  413. orientation,
  414. offset=True, dynamic=True)
  415. ui.color(game, layer, "red", 0.5)
  416. ui.image(game, layer,
  417. assx,
  418. assy,
  419. "assets/elements/"+asset_draw+".png",
  420. orientation,
  421. offset=True, dynamic=True, color=colordamage)
  422. # Try drawing the asset in this cell
  423. try:
  424. chunkasst = game.chunks[1][chunk][addr]
  425. chunkasst = [ game.chunks[0][chunkasst[0]], game.chunks[0][chunkasst[1]] ]
  426. colass, colsprite = "assets/elements/"+chunkasst[0], chunkasst[1]
  427. if not grid:
  428. if chunk+":"+addr in game.current["state"]["map_exclude"]:
  429. continue
  430. colass, colsprite = "assets/elements/"+chunkasst[0], chunkasst[1]
  431. frames = game.images[colass][colsprite]
  432. frame = frames[game.current["anim_pulse"] % len(frames)]
  433. ##### IF THE OBJECT IS DYNAMIC #######
  434. dynamic = frame.get("dynamic", False)
  435. if dynamic:
  436. print("DYNAMIC", colass)
  437. newx = centerx - game.current["camera"][0]
  438. newy = centery - game.current["camera"][1] -5
  439. newz = game.current["camera"][2]+lh# + 1
  440. game.current["state"]["objects"].append({
  441. "asset":chunkasst[0].replace(".png", ""),
  442. "xyz":[newx,newy,newz],
  443. "velocity":[0,0,0],
  444. "cell":[0,0],
  445. "last_before_colision":[0,0,0],
  446. "check_mark":[0,0,0],
  447. "orientation":colsprite,
  448. "grounded":False,
  449. "health":1.0,
  450. "time-falling":0})
  451. game.current["state"]["map_exclude"].append(chunk+":"+addr)
  452. index_for_this_character = len(game.current["state"]["objects"])-1
  453. if frame.get("main_character", False):
  454. try:
  455. gameplay.follow_last(game, index_for_this_character)
  456. except Exception as e:
  457. print("What", e)
  458. game.current["state"]["controlling"][index_for_this_character] = False
  459. continue
  460. if grid:
  461. # Dynamic transparency
  462. dalpha = 1
  463. # [ 0:0 ]
  464. # [ -1:1 ][ 1:1 ]
  465. # [ 0:2 ]
  466. #
  467. seltmp = game.current["world_mo"]
  468. tcolumns = [
  469. seltmp,
  470. [seltmp[0]-1, seltmp[1]+1],
  471. [seltmp[0]+1, seltmp[1]+1],
  472. [seltmp[0], seltmp[1]+2]]
  473. for i in tcolumns:
  474. if celladdr[0] == i[0]\
  475. and celladdr[1] in range( i[1]-(lh*2), i[1]+1)\
  476. and ( mouseinscreen or not grid ):
  477. if celladdr == seltmp and lh == 0 and grid:
  478. dalpha = 1
  479. else:
  480. dalpha = 0.25
  481. if lh > 1:
  482. dalpha = 0.1
  483. else:
  484. dalpha = 1
  485. frames = game.images[colass][colsprite]
  486. frame = frames[game.current["anim_pulse"] % len(frames)]
  487. invisible = frame.get("invisible", False)
  488. if grid or not invisible:
  489. # Draw cell
  490. ui.image(game, layer,
  491. drawx,
  492. drawy,
  493. "assets/elements/"+chunkasst[0], chunkasst[1],
  494. offset=True, alpha=dalpha)
  495. # Highlight cell in red when mouse over
  496. if celladdr in selectedcells :
  497. if lh == 0:
  498. if not grid:
  499. pass
  500. # game.current["state"]["4211D79"]["colision"] = \
  501. # [drawx+offsetx - game.current["camera"][0],
  502. # drawy+offsety - game.current["camera"][1]]
  503. else:
  504. ui.color(game, layer, "red", 0.5)
  505. ui.image(game, layer,
  506. drawx,
  507. drawy,
  508. "assets/elements/"+chunkasst[0], chunkasst[1],
  509. offset=True, color=True)
  510. # Select the current thing for the editor.
  511. try:
  512. if game.previous["MMB"] and not game.current["MMB"]\
  513. and int(game.current["mx"]) == int(game.previous["MMB"][0])\
  514. and int(game.current["my"]) == int(game.previous["MMB"][1]):
  515. types = chunkasst[0].split("/")[0]
  516. asset = chunkasst[0].split("/")[1]
  517. for version, names in enumerate(game.elements[types][asset]):
  518. if names["title"] == chunkasst[1]:
  519. break
  520. game.current["editor_selection"][0] = types
  521. game.current["editor_selection"][1] = asset
  522. game.current["editor_selection"][2] = version
  523. except Exception as e:
  524. print(e)
  525. if collision and game.current["testing"]:
  526. ui.image(game, layer,
  527. drawx,
  528. drawy,
  529. "assets/grid.png", "grid", color=False)
  530. except Exception as e:
  531. pass
  532. # Depth of field actually done
  533. if lh > 1 or lh < -1:
  534. factor = ( max(lh, 0) - min(lh, 0) )
  535. oldlayer.set_source_surface(ui.blur(surface, game, factor), 0, 0)
  536. if lh > 0:
  537. oldlayer.paint_with_alpha(1/(factor))
  538. else:
  539. oldlayer.paint()
  540. ui.color(game, oldlayer, "blue", alpha=1/(factor))
  541. oldlayer.rectangle(0,0,w-1,h-1)
  542. oldlayer.fill()
  543. layer = oldlayer
  544. surface = oldsurface
  545. # If Editor Show the currently selected item
  546. if grid:
  547. types = game.current["editor_selection"][0]
  548. asset = game.current["editor_selection"][1]
  549. version = game.elements[types][asset][game.current["editor_selection"][2]]
  550. ui.image(game, layer,
  551. game.current["mx"]-x-offsetx,
  552. game.current["my"]-y-offsety,
  553. "assets/elements/"+types+"/"+asset, version["title"], offset=True, alpha=0.5)
  554. # Select the mouse over cell
  555. game.current["world_mo"] = wmo
  556. if not grid:
  557. for asset, t in enumerate(game.current["state"]["objects"]):
  558. try:
  559. game.current["state"]["objects"][asset]["cell"] = cell_assets_results[asset]
  560. except:
  561. pass
  562. # Removing chunks that are not rendered currently from the memory
  563. for i in list(game.chunks[1].keys()):
  564. if i not in rendered_chunks and i not in game.current["temporary_chunks"]:
  565. del game.chunks[1][i]
  566. # The current Z ( height ) rendering in top, right corner
  567. if game.current["testing"]:
  568. ui.color(game, layer, "yellow")
  569. ui.text(game,layer, str(game.current["camera"][2]),
  570. 60,
  571. 40)
  572. ui.text(game,layer, render_coordinates,
  573. 60,
  574. 60)
  575. # Numpad + to go up
  576. if 65451 in game.current["keys"]:
  577. game.current["camera"][2] += 1
  578. game.current["keys"] = []
  579. # Numpad - to go down
  580. if 65453 in game.current["keys"]:
  581. game.current["camera"][2] -= 1
  582. game.current["keys"] = []
  583. # Drawing the world to the outlayer
  584. outlayer.set_source_surface(surface, x , y)
  585. outlayer.paint()
  586. def update_elements(game):
  587. """This function caches all assets"""
  588. game.elements = {}
  589. # elements
  590. # Element type ( blocks, characters, vehicles )
  591. # Image assets
  592. for types in os.listdir(os.getcwd()+"/assets/elements"):
  593. game.elements[types] = {}
  594. for asset in os.listdir(os.getcwd()+"/assets/elements/"+types):
  595. if asset.endswith(".png"):
  596. asseturl = "assets/elements/"+types+"/"+asset
  597. ui.cache_sprite_sheet(game, asseturl, [types, asset])
  598. # Now let's generate the selection for the editor
  599. game.current["editor_selection"] = [
  600. list(game.elements.keys())[0],
  601. list(list(game.elements.values())[0].keys())[0],
  602. 0]
  603. # Make the brush 0
  604. game.current["editor_brush"] = 1
  605. # YANK THAT CODE LATER
  606. # every chunk is 100 by 100
  607. game.chunks = [[],{}]
  608. game.current["temporary_chunks"] = [] # Chunks that are not saved
  609. def save_chunk(game, chunk_input=False):
  610. """This function saves the chunk"""
  611. for c in game.chunks[1]:
  612. if chunk_input == c or not chunk_input:
  613. chunk = c
  614. print("saving chunk", chunk)
  615. # Getting the raw chunk
  616. savedata = [[], game.chunks[1][chunk].copy()]
  617. # Adding all the asset names to it
  618. for ind in savedata[1]:
  619. i = savedata[1][ind]
  620. savedata[1][ind] = i.copy()
  621. for n, b in enumerate(i):
  622. add = game.chunks[0][b]
  623. if add not in savedata[0]:
  624. savedata[0].append(add)
  625. savedata[1][ind][n] = savedata[0].index(add)
  626. # Save the json
  627. savefilename = "assets/worlds/"+game.settings["world"]+"/"+chunk+".json"
  628. with open(savefilename, 'w') as f:
  629. json.dump(savedata, f)
  630. try:
  631. game.current["temporary_chunks"].remove(chunk)
  632. except:
  633. pass
  634. print("saved")
  635. def load_chunk(game, chunk):
  636. """This function loads a chunk."""
  637. # Load the json
  638. loadfilename = "assets/worlds/"+game.settings["world"]+"/"+chunk+".json"
  639. try:
  640. with open(loadfilename) as f:
  641. loaddata = json.load(f)
  642. except:
  643. loaddata = [[],{}]
  644. for ind in loaddata[1]:
  645. i = loaddata[1][ind]
  646. for n, b in enumerate(i):
  647. add = loaddata[0][b]
  648. if add not in game.chunks[0]:
  649. game.chunks[0].append(add)
  650. loaddata[1][ind][n] = game.chunks[0].index(add)
  651. game.chunks[1][chunk] = loaddata[1]