Legend of the Gold Box... A game written for the LOWREZJAM 2018 game jam
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

863 lines
32KB

  1. from . import gbe
  2. import pygame
  3. class NodeOptions(gbe.nodes.Node2D):
  4. def __init__(self, name="Options", parent=None):
  5. try:
  6. gbe.nodes.Node2D.__init__(self, name, parent)
  7. except gbe.nodes.NodeError as e:
  8. raise e
  9. self._options = []
  10. self._oindex = 0
  11. self._color_select = (255,255,0)
  12. self._color_idle = (255,255,255)
  13. def add_option(self, font_src, size, text, event, params={}):
  14. nodeName = "OpText{}".format(len(self._options))
  15. nodeOption = gbe.nodes.NodeText(nodeName, self)
  16. nodeOption.font_src = font_src
  17. nodeOption.size = size
  18. nodeOption.text = text
  19. nodeOption.antialias = False
  20. if len(self._options) == 0:
  21. nodeOption.set_color(*self._color_select)
  22. else:
  23. nodeOption.set_color(*self._color_idle)
  24. li = len(self._options)-1
  25. lp = self._options[li][0].position
  26. ls = self._options[li][0].size
  27. nodeOption.position = (lp[0], lp[1] + ls + 1)
  28. self._options.append([nodeOption, event, params])
  29. def on_start(self):
  30. self.listen("KEYPRESSED", self.on_keypressed)
  31. def on_pause(self):
  32. self.unlisten("KEYPRESSED", self.on_keypressed)
  33. def on_keypressed(self, event, params):
  34. if params["key_name"] == "w":
  35. if self._oindex > 0:
  36. self._options[self._oindex][0].set_color(*self._color_idle)
  37. self._oindex -= 1
  38. self._options[self._oindex][0].set_color(*self._color_select)
  39. elif params["key_name"] == "s":
  40. if self._oindex < len(self._options) - 1:
  41. self._options[self._oindex][0].set_color(*self._color_idle)
  42. self._oindex += 1
  43. self._options[self._oindex][0].set_color(*self._color_select)
  44. elif params["key_name"] in ["enter", "return"]:
  45. if len(self._options) > 0:
  46. op = self._options[self._oindex]
  47. self.emit(op[1], op[2])
  48. elif params["key_name"] == "escape":
  49. self.emit("QUIT")
  50. class NodeGameMap(gbe.nodes.Node2D):
  51. def __init__(self, name="GameMap", parent=None):
  52. try:
  53. gbe.nodes.Node2D.__init__(self, name, parent)
  54. except gbe.nodes.NodeError as e:
  55. raise e
  56. self._renderMode = 0 # 0 = Top-down | 1 = Perspective
  57. self._layer = {}
  58. self._currentLayer = ""
  59. self._res = {
  60. "env_src":"",
  61. "env":None,
  62. "h_index":0,
  63. "g_index":0,
  64. "wall_src":"",
  65. "walls":None,
  66. "wall_index":-1,
  67. "door_index":-1
  68. }
  69. self._topdown = {
  70. "size":8, # Pixels square
  71. "wall_color":pygame.Color(255, 255, 255),
  72. "blocked_color":pygame.Color(255, 0, 0)
  73. }
  74. self._cellpos = [0,0]
  75. self._orientation = "n"
  76. @property
  77. def environment_source(self):
  78. return self._res["env_src"]
  79. @property
  80. def wall_source(self):
  81. return self._res["wall_src"]
  82. @property
  83. def layer_count(self):
  84. return len(self._layer)
  85. @property
  86. def current_layer(self):
  87. return self._currentLayer
  88. @property
  89. def current_layer_width(self):
  90. if self._currentLayer != "":
  91. return self._layer[self._currentLayer]["w"]
  92. return 0
  93. @property
  94. def current_layer_height(self):
  95. if self._currentLayer != "":
  96. return self._layer[self._currentLayer]["h"]
  97. return 0
  98. @property
  99. def layer_names(self):
  100. names = []
  101. for key in self._layer:
  102. names.append(names)
  103. return names
  104. @property
  105. def orientation(self):
  106. return self._orientation
  107. @property
  108. def cell_position(self):
  109. return (self._cellpos[0], self._cellpos[1])
  110. def load_map(self, src, user=True):
  111. rtype = "maps"
  112. if user == True:
  113. rtype = "user_maps"
  114. rm = self.resource
  115. m = None
  116. try:
  117. m = rm.load(rtype, src)
  118. m = m.data
  119. except Exception as e:
  120. print ("Failed to load '{}': {}".format(src, e))
  121. if "version" not in m:
  122. print("Invalid Map Data!")
  123. return
  124. if m["version"] != "0.0.1":
  125. print ("Invalid map version.")
  126. return
  127. if "count" not in m:
  128. print("Invalid Map Data!")
  129. return
  130. if not isinstance(m["count"], int):
  131. print("Invalid Map Data!")
  132. return
  133. if "layers" not in m:
  134. print ("Invalid Map Data!")
  135. return
  136. if len(m["layers"]) != m["count"]:
  137. print ("Map Layer count mismatch!")
  138. return
  139. if "player" not in m:
  140. print ("Invalid Map Data!")
  141. return
  142. # OK... these are weak tests, but we'll just accept it from here!
  143. self._layer = m["layers"]
  144. self._currentLayer = m["player"]["layer_name"]
  145. self._cellpos = m["player"]["pos"]
  146. self._orientation = m["player"]["orientation"]
  147. print("Map '{}' loaded!".format(src))
  148. def save_map(self, dst):
  149. rm = self.resource
  150. m = {
  151. "version":"0.0.1",
  152. "count":self.layer_count,
  153. "layers":self._layer,
  154. "player":{
  155. "layer_name":self._currentLayer,
  156. "pos":(self._cellpos[0], self._cellpos[1]),
  157. "orientation":self._orientation
  158. }
  159. }
  160. try:
  161. rm.save("user_maps", dst, m)
  162. except Exception as e:
  163. print("Failed to save '{}': {}".format(dst, e))
  164. return
  165. print ("Map '{}' saved.".format(dst))
  166. def set_resources(self, env_src, wall_src):
  167. res = self.resource
  168. if env_src != "" and env_src != self._res["env_src"]:
  169. if res.is_valid("json", env_src):
  170. if not res.has("json", env_src):
  171. res.store("json", env_src)
  172. e = res.get("json", env_src)
  173. if e is not None and e() is not None:
  174. self._res["env_src"] = env_src
  175. self._res["env"] = e
  176. # NOTE: Making a lot of assumptions to the structural validity of the data file.
  177. isrc1 = e().data["horizon"]["src"]
  178. isrc2 = e().data["ground"]["src"]
  179. if res.is_valid("graphic", isrc1) and res.is_valid("graphic", isrc2):
  180. if not res.has("graphic", isrc1):
  181. res.store("graphic", isrc1)
  182. if not res.has("graphic", isrc2):
  183. res.store("graphic", isrc2)
  184. if wall_src != "" and wall_src != self._res["wall_src"]:
  185. if res.is_valid("json", wall_src):
  186. if not res.has("json", wall_src):
  187. print("Storing resource {}".format(wall_src))
  188. res.store("json", wall_src)
  189. w = res.get("json", wall_src)
  190. if w is not None and w() is not None:
  191. self._res["wall_src"] = wall_src
  192. self._res["walls"] = w
  193. # NOTE: I'm making a lot of assumptions to the structural validity of the data file, but...
  194. imgsrc = w().data["src"]
  195. if res.is_valid("graphic", imgsrc):
  196. if not res.has("graphic", imgsrc):
  197. res.store("graphic", imgsrc)
  198. else:
  199. print("Failed to get JSON instance {}".format(wall_src))
  200. else:
  201. print("Invalid JSON {}".format(wall_src))
  202. def add_layer(self, name, w, h):
  203. if name == "" or name in self._layer:
  204. return
  205. self._layer[name] = {
  206. "w":w,
  207. "h":h,
  208. "cells":[]
  209. }
  210. for c in range(0, w*h):
  211. self._layer[name]["cells"].append({
  212. "h":0, # Horizon
  213. "g":0, # Ground
  214. "n":[-1, False, -1, None], # North Wall | [<graphic index, -1 = None>, <blocking>, <door index, -1 = None, 0 = closed, 1=open>, <door target>]
  215. "s":[-1, False, -1, None], # South Wall
  216. "e":[-1, False, -1, None], # East Wall
  217. "w":[-1, False, -1, None], # West Wall
  218. })
  219. if self._currentLayer == "":
  220. self._currentLayer = name
  221. def set_active_layer(self, name, x=0, y=0):
  222. if name == "" or not (name in self._layers):
  223. return
  224. layer = self._layers[name]
  225. if x >= 0 and x < layer["w"] and y >= 0 and y < layer["h"]:
  226. self._currentLayer = name
  227. self._cellpos = [x,y]
  228. def set_cell_env(self, x, y, ceiling=-1, ground=-1):
  229. if self._currentLayer == "":
  230. return
  231. layer = self._layer[self._currentLayer]
  232. if x >= 0 and x < layer["w"] and y >= 0 and y < layer["h"]:
  233. index = (y * layer["w"]) + x
  234. cell = layer["cells"]
  235. if ceiling >= 0:
  236. cell[index]["c"] = ceiling
  237. if ground >= 0:
  238. cell[index]["g"] = ground
  239. def fill_cell_env(self, x1, y1, x2, y2, ceiling=-1, ground=-1):
  240. if self._currentLayer == "":
  241. return
  242. for y in range(y1, y2+1):
  243. for x in range(x1, x2+1):
  244. self.set_cell_env(x, y, ceiling, ground)
  245. def set_cell_face(self, x, y, face, gi=-2, blocking=None):
  246. if self._currentLayer == "" or not (face == "n" or face == "s" or face == "w" or face == "e"):
  247. return
  248. layer = self._layer[self._currentLayer]
  249. if x >= 0 and x < layer["w"] and y >= 0 and y < layer["h"]:
  250. index = (y * layer["w"]) + x
  251. cell = layer["cells"]
  252. if gi <= -2:
  253. gi = self._res["wall_index"]
  254. if gi >= -1:
  255. cell[index][face][0] = gi
  256. if blocking is not None:
  257. cell[index][face][1] = (blocking == True)
  258. else:
  259. if gi == -1: # If gi = -1, there is no wall, so, by default, there is no blocking.
  260. cell[index][face][1] = False
  261. else: # Otherwise, blocking is assumed :)
  262. cell[index][face][1] = True
  263. elif blocking is not None:
  264. blocking = (blocking == True) # Forcing a boolean
  265. cell[index][face][1] = blocking
  266. def next_wall(self):
  267. if self._res["walls"] is not None:
  268. w = self._res["walls"]()
  269. if w is not None:
  270. windex = self._res["wall_index"] + 1
  271. if windex >= len(w.data["walls"]):
  272. windex = -1
  273. self._res["wall_index"] = windex
  274. print("Next Wall Index: {}".format(windex))
  275. def prev_wall(self):
  276. if self._res["walls"] is not None:
  277. w = self._res["walls"]()
  278. if w is not None:
  279. windex = self._res["wall_index"] - 1
  280. if windex < -1:
  281. windex = len(w.data["walls"]) - 1
  282. self._res["wall_index"] = windex
  283. print("Prev Wall Index: {}".format(windex))
  284. def turn_left(self):
  285. onum = self._d_s2n(self._orientation)
  286. onum -= 1
  287. if onum < 0:
  288. onum = 3
  289. self._orientation = self._d_n2s(onum)
  290. def turn_right(self):
  291. onum = self._d_s2n(self._orientation)
  292. onum += 1
  293. if onum > 3:
  294. onum = 0
  295. self._orientation = self._d_n2s(onum)
  296. def move_to(self, x, y):
  297. if x >= 0 and x < self.current_layer_width and y >= 0 and y < self.current_layer_height:
  298. self._cellpos = [x, y]
  299. def move_forward(self, ignore_passible=False):
  300. if ignore_passible or self.is_passible(self._cellpos[0], self._cellpos[1], self._orientation):
  301. x = self._cellpos[0]
  302. y = self._cellpos[1]
  303. if self._orientation == "n":
  304. y -= 1
  305. elif self._orientation == "e":
  306. x += 1
  307. elif self._orientation == "s":
  308. y += 1
  309. elif self._orientation == "w":
  310. x -= 1
  311. self.move_to(x, y)
  312. def move_backward(self, ignore_passible=False):
  313. orient = self._orientation
  314. if self._orientation == "n":
  315. self._orientation = "s"
  316. elif self._orientation == "s":
  317. self._orientation = "n"
  318. elif self._orientation == "e":
  319. self._orientation = "w"
  320. elif self._orientation == "w":
  321. self._orientation = "e"
  322. self.move_forward(ignore_passible)
  323. self._orientation = orient
  324. def is_passible(self, x, y, d):
  325. """
  326. Returns true if it's possible to move forward from the x, y map position in the direction given.
  327. d - 0 = North, 1 = East, 2 = South, 3 = West
  328. """
  329. if self._currentLayer == "" or d < 0 or d >= 4:
  330. return False
  331. layer = self._layer[self._currentLayer]
  332. if x >= 0 and x < layer["w"] and y >= 0 and y < layer["h"]:
  333. index = (y * layer["w"]) + x
  334. d = self._d_n2s(d)
  335. return not layer["cells"][index][d][1]
  336. return False
  337. def toggle_render_mode(self):
  338. if self._renderMode == 0:
  339. self._renderMode = 1
  340. else:
  341. self._renderMode = 0
  342. def set_render_mode(self, mode):
  343. if mode <= 0:
  344. self._renderMode = 0
  345. else:
  346. self._renderMode = 1
  347. def get_render_mode(self):
  348. return self._renderMode
  349. def _d_n2s(self, d): # _(d)irection_(n)umber_to_(s)tring
  350. if d == 0:
  351. return "n"
  352. elif d == 1:
  353. return "e"
  354. elif d == 2:
  355. return "s"
  356. elif d == 3:
  357. return "w"
  358. return ""
  359. def _d_s2n(self, d):
  360. if d == "n":
  361. return 0
  362. elif d == "e":
  363. return 1
  364. elif d == "s":
  365. return 2
  366. elif d == "w":
  367. return 3
  368. return -1
  369. def _indexFromPos(self, x, y):
  370. if x >= 0 and x < self.current_layer_width and y >= 0 and y < self.current_layer_height:
  371. return (y * self.current_layer_width) + x
  372. return -1
  373. def _getCell(self, x, y):
  374. if x >=- 0 and x < self.current_layer_width and y >= 0 and y < self.current_layer_height:
  375. index = self._indexFromPos(x, y)
  376. return self._layer[self._currentLayer]["cells"][index]
  377. return None
  378. def _getOrientVec(self):
  379. if self._orientation == "n":
  380. return (0, -1)
  381. elif self._orientation == "s":
  382. return (0, 1)
  383. elif self._orientation == "e":
  384. return (1, 0)
  385. elif self._orientation == "w":
  386. return (-1, 0)
  387. return (0,0)
  388. def _RenderTopDown(self):
  389. cell_size = self._topdown["size"]
  390. size = self.resolution
  391. pos = self._cellpos
  392. lsize = (self.current_layer_width, self.current_layer_height)
  393. hcells = int(size[0] / cell_size)
  394. vcells = int(size[1] / cell_size)
  395. cx = pos[0] - int(hcells * 0.5)
  396. cy = pos[1] - int(vcells * 0.5)
  397. ry = -int(cell_size*0.5)
  398. for j in range(0, vcells+1):
  399. y = cy + j
  400. if y >= 0 and y < lsize[1]:
  401. rx = -int(cell_size*0.5)
  402. for i in range(0, hcells+1):
  403. x = cx + i
  404. if x >= 0 and x < lsize[0]:
  405. cell = self._getCell(x, y)
  406. if cell["n"][0] >= 0:
  407. self.draw_rect((rx, ry, cell_size, 2), self._topdown["wall_color"], 0, self._topdown["wall_color"])
  408. if cell["e"][0] >= 0:
  409. self.draw_rect((rx+(cell_size-2), ry, 2, cell_size), self._topdown["wall_color"], 0, self._topdown["wall_color"])
  410. if cell["s"][0] >= 0:
  411. self.draw_rect((rx, ry+(cell_size-2), cell_size, 2), self._topdown["wall_color"], 0, self._topdown["wall_color"])
  412. if cell["w"][0] >= 0:
  413. self.draw_rect((rx, ry, 2, cell_size), self._topdown["wall_color"], 0, self._topdown["wall_color"])
  414. if cell["n"][1] == True:
  415. self.draw_lines([(rx+1, ry+1), (rx+(cell_size-2), ry+1)], self._topdown["blocked_color"], 1)
  416. if cell["e"][1] == True:
  417. self.draw_lines([(rx+(cell_size-2), ry+1), (rx+(cell_size-2), ry+(cell_size-2))], self._topdown["blocked_color"], 1)
  418. if cell["s"][1] == True:
  419. self.draw_lines([(rx+1, ry+(cell_size-2)), (rx+(cell_size-2), ry+(cell_size-2))], self._topdown["blocked_color"], 1)
  420. if cell["w"][1] == True:
  421. self.draw_lines([(rx+1, ry+1), (rx+1, ry+(cell_size-2))], self._topdown["blocked_color"], 1)
  422. rx += cell_size
  423. ry += cell_size
  424. def _RenderPersFar(self, pos, size, o, orr, orl, wdat, wsurf):
  425. ovec = self._getOrientVec()
  426. fx = pos[0] + (ovec[0]*2)
  427. fy = pos[1] + (ovec[1]*2)
  428. fcell = self._getCell(fx, fy)
  429. if fcell == None:
  430. return # If we can't see the cell directly ahead, the other's won't be visible either!
  431. lcell = llcell = rcell = rrcell = None
  432. if ovec[0] == 0: # Facing North/South
  433. lcell = self._getCell(fx + ovec[1], fy)
  434. llcell = self._getCell(fx + (ovec[1]*2), fy)
  435. rcell = self._getCell(fx - ovec[1], fy)
  436. rrcell = self._getCell(fx - (ovec[1]*2), fy)
  437. else: # Facing East/West
  438. lcell = self._getCell(fx, fy - ovec[0])
  439. llcell = self._getCell(fx, fy - (ovec[0]*2))
  440. rcell = self._getCell(fx, fy + ovec[0])
  441. rrcell = self._getCell(fx, fy + (ovec[0]*2))
  442. hsw = int(size[0]*0.5)
  443. hsh = int(size[1]*0.5)
  444. # Rendering from edges to center
  445. if llcell is not None:
  446. if llcell[o][0] >= 0:
  447. rect = wdat["walls"][llcell[o][0]]["f_far"]
  448. hw = int(rect[2]*0.5)
  449. hh = int(rect[3]*0.5)
  450. self.draw_image(wsurf, (0, hsh-hh), (rect[0], rect[1], hw, rect[3]))
  451. if rrcell is not None:
  452. if rrcell[o][0] >= 0:
  453. rect = wdat["walls"][rrcell[o][0]]["f_far"]
  454. hw = int(rect[2]*0.5)
  455. hh = int(rect[3]*0.5)
  456. self.draw_image(wsurf, (size[0]-hw, hsh-hh), (rect[0]+hw, rect[1], hw, rect[3]))
  457. if lcell is not None:
  458. if lcell[o][0] >= 0:
  459. rect = wdat["walls"][lcell[o][0]]["f_far"]
  460. hw = int(rect[2]*0.5)
  461. hh = int(rect[3]*0.5)
  462. self.draw_image(wsurf, (hw, hsh-hh), (rect[0], rect[1], rect[2], rect[3]))
  463. if lcell[orl][0] >= 0:
  464. rect = wdat["walls"][lcell[orl][0]]["s_far"]
  465. lsurf = pygame.transform.flip(wsurf.subsurface(rect), True, False)
  466. hh = int(rect[3]*0.5)
  467. self.draw_image(lsurf, (0, hsh-hh))
  468. if rcell is not None:
  469. if rcell[o][0] >= 0:
  470. rect = wdat["walls"][rcell[o][0]]["f_far"]
  471. hw = int(rect[2]*0.5)
  472. hh = int(rect[3]*0.5)
  473. self.draw_image(wsurf, (size[0]-(rect[2]+hw), hsh-hh), (rect[0], rect[1], rect[2], rect[3]))
  474. if rcell[orr][0] >= 0:
  475. rect = wdat["walls"][rcell[orr][0]]["s_far"]
  476. hh = int(rect[3]*0.5)
  477. self.draw_image(wsurf, (size[0]-rect[2], hsh-hh), (rect[0], rect[1], rect[2], rect[3]))
  478. # Rendering the main cell!!
  479. frect = None # This will be used to place walls
  480. if fcell[o][0] >= 0:
  481. frect = wdat["walls"][fcell[o][0]]["f_far"]
  482. hw = int(frect[2]*0.5)
  483. hh = int(frect[3]*0.5)
  484. self.draw_image(wsurf, (hsw-hw, hsh-hh), (frect[0], frect[1], frect[2], frect[3]))
  485. if fcell[orl][0] >= 0:
  486. rect = wdat["walls"][fcell[orl][0]]["s_far"]
  487. if frect is None:
  488. # Kinda cheating in that it's known that all walls are the same size.
  489. frect = wdat["walls"][fcell[orl][0]]["f_far"]
  490. hw = int(frect[2]*0.5)
  491. lsurf = pygame.transform.flip(wsurf.subsurface(rect), True, False)
  492. self.draw_image(lsurf, (hsw-(hw+rect[2]), hsh-int(rect[3]*0.5)))
  493. if fcell[orr][0] >= 0:
  494. rect = wdat["walls"][fcell[orr][0]]["s_far"]
  495. if frect is None:
  496. frect = wdat["walls"][fcell[orr][0]]["f_far"]
  497. hw = int(frect[2]*0.5)
  498. self.draw_image(wsurf, (hsw+hw, hsh-int(rect[3]*0.5)), (rect[0], rect[1], rect[2], rect[3]))
  499. def _RenderPersMid(self, pos, size, o, orr, orl, wdat, wsurf):
  500. ovec = self._getOrientVec()
  501. fx = pos[0] + ovec[0]
  502. fy = pos[1] + ovec[1]
  503. fcell = self._getCell(fx, fy)
  504. if fcell == None:
  505. return # If we can't see the cell directly ahead, the other's won't be visible either!
  506. lcell = rcell = None
  507. if ovec[0] == 0: # Facing North/South
  508. lcell = self._getCell(fx + ovec[1], fy)
  509. rcell = self._getCell(fx - ovec[1], fy)
  510. else: # Facing East/West
  511. lcell = self._getCell(fx, fy - ovec[0])
  512. rcell = self._getCell(fx, fy + ovec[0])
  513. hsw = int(size[0]*0.5)
  514. hsh = int(size[1]*0.5)
  515. # Render from outside inwards!
  516. if lcell is not None:
  517. if lcell[o][0] >= 0:
  518. rect = wdat["walls"][lcell[o][0]]["f_mid"]
  519. hw = int(rect[2]*0.5)
  520. hh = int(rect[3]*0.5)
  521. self.draw_image(wsurf, (0, hsh-hh), (rect[0]+hw, rect[1], int(rect[2]*0.5), rect[3]))
  522. if rcell is not None:
  523. if rcell[o][0] >= 0:
  524. rect = wdat["walls"][rcell[o][0]]["f_mid"]
  525. hw = int(rect[2]*0.5)
  526. hh = int(rect[3]*0.5)
  527. self.draw_image(wsurf, (size[0]-hw, hsh-hh), (rect[0], rect[1], hw, rect[3]))
  528. # Rendering the main cell!!
  529. frect = None # This will be used to place walls
  530. if fcell[o][0] >= 0:
  531. frect = wdat["walls"][fcell[o][0]]["f_mid"]
  532. hw = int(frect[2]*0.5)
  533. hh = int(frect[3]*0.5)
  534. self.draw_image(wsurf, (hsw-hw, hsh-hh), (frect[0], frect[1], frect[2], frect[3]))
  535. if fcell[orl][0] >= 0:
  536. rect = wdat["walls"][fcell[orl][0]]["s_mid"]
  537. if frect is None:
  538. # Kinda cheating in that it's known that all walls are the same size.
  539. frect = wdat["walls"][fcell[orl][0]]["f_mid"]
  540. hw = int(frect[2]*0.5)
  541. lsurf = pygame.transform.flip(wsurf.subsurface(rect), True, False)
  542. self.draw_image(lsurf, (hsw-(hw+rect[2]), hsh-int(rect[3]*0.5)))
  543. if fcell[orr][0] >= 0:
  544. rect = wdat["walls"][fcell[orr][0]]["s_mid"]
  545. if frect is None:
  546. frect = wdat["walls"][fcell[orr][0]]["f_mid"]
  547. hw = int(frect[2]*0.5)
  548. self.draw_image(wsurf, (hsw+hw, hsh-int(rect[3]*0.5)), (rect[0], rect[1], rect[2], rect[3]))
  549. def _RenderPersClose(self, pos, size, o, orr, orl, cell, wdat, wsurf):
  550. fcell = self._getCell(pos[0], pos[1])
  551. hsw = int(size[0]*0.5)
  552. hsh = int(size[1]*0.5)
  553. ovec = self._getOrientVec()
  554. lcell = rcell = None
  555. if ovec[0] == 0: # Facing North/South
  556. lcell = self._getCell(pos[0] + ovec[1], pos[1])
  557. rcell = self._getCell(pos[0] - ovec[1], pos[1])
  558. else: # Facing East/West
  559. lcell = self._getCell(pos[0], pos[1] - ovec[0])
  560. rcell = self._getCell(pos[0], pos[1] + ovec[0])
  561. hsw = int(size[0]*0.5)
  562. hsh = int(size[1]*0.5)
  563. # Render from outside inwards!
  564. if lcell is not None:
  565. if lcell[o][0] >= 0:
  566. rect = wdat["walls"][lcell[o][0]]["f_close"]
  567. hw = int(rect[2]*0.5)
  568. hh = int(rect[3]*0.5)
  569. rw = hsw - hw
  570. self.draw_image(wsurf, (0, hsh-hh), (rect[0]+(rect[2]-rw), rect[1], rw, rect[3]))
  571. if rcell is not None:
  572. if rcell[o][0] >= 0:
  573. rect = wdat["walls"][rcell[o][0]]["f_close"]
  574. hw = int(rect[2]*0.5)
  575. hh = int(rect[3]*0.5)
  576. rw = hsw - hw
  577. self.draw_image(wsurf, (size[0]-rw, hsh-hh), (rect[0], rect[1], rw, rect[3]))
  578. # Rendering the main cell!!
  579. frect = None # This will be used to place walls
  580. if fcell[o][0] >= 0:
  581. idx = fcell[o][0]
  582. frect = wdat["walls"][idx]["f_close"]
  583. hw = int(frect[2]*0.5)
  584. hh = int(frect[3]*0.5)
  585. self.draw_image(wsurf, (hsw-hw, hsh-hh), (frect[0], frect[1], frect[2], frect[3]))
  586. if fcell[orl][0] >= 0:
  587. idx = fcell[orl][0]
  588. rect = wdat["walls"][idx]["s_close"]
  589. if frect is None:
  590. # Kinda cheating in that it's known that all walls are the same size.
  591. frect = wdat["walls"][idx]["f_close"]
  592. hw = int(frect[2]*0.5)
  593. lsurf = pygame.transform.flip(wsurf.subsurface(rect), True, False)
  594. self.draw_image(lsurf, (hsw-(hw+rect[2]), hsh-int(rect[3]*0.5)))
  595. if fcell[orr][0] >= 0:
  596. idx = fcell[orr][0]
  597. rect = wdat["walls"][idx]["s_close"]
  598. if frect is None:
  599. frect = wdat["walls"][idx]["f_close"]
  600. hw = int(frect[2]*0.5)
  601. self.draw_image(wsurf, (hsw+hw, hsh-int(rect[3]*0.5)), (rect[0], rect[1], rect[2], rect[3]))
  602. def _RenderPerspective(self):
  603. # Getting ALL of the core resources
  604. rm = self.resource
  605. edat = self._res["env"]
  606. wdat = self._res["walls"]
  607. if edat is None or wdat is None or edat() is None or wdat() is None:
  608. return
  609. edat = edat().data
  610. wdat = wdat().data
  611. ehsurf = rm.get("graphic", edat["horizon"]["src"])
  612. egsurf = rm.get("graphic", edat["ground"]["src"])
  613. wsurf = rm.get("graphic", wdat["src"])
  614. if ehsurf is None or egsurf is None or wsurf is None:
  615. return
  616. if ehsurf() is None or egsurf() is None or wsurf() is None:
  617. return
  618. oshift = lambda d: d if d >= 0 and d < 4 else (0 if d > 3 else 3)
  619. px = self._cellpos[0]
  620. py = self._cellpos[1]
  621. orl = self._d_n2s(oshift(self._d_s2n(self._orientation) - 1))
  622. orr = self._d_n2s(oshift(self._d_s2n(self._orientation) + 1))
  623. cell = self._getCell(px, py)
  624. # First, output the ground and horizon
  625. # TODO Later, perhaps cut the horizon and ground to represent each possible cell instead of just the current one?
  626. self.draw_image(ehsurf(), (0,0), edat["horizon"]["defs"][cell["h"]]["rect"])
  627. self.draw_image(egsurf(), (0,32), edat["ground"]["defs"][cell["g"]]["rect"])
  628. # Rendering the rest
  629. size = self.resolution
  630. self._RenderPersFar((px, py), size, self._orientation, orr, orl, wdat, wsurf())
  631. self._RenderPersMid((px, py), size, self._orientation, orr, orl, wdat, wsurf())
  632. self._RenderPersClose((px, py), size, self._orientation, orr, orl, cell, wdat, wsurf())
  633. def on_render(self):
  634. if self._renderMode == 0:
  635. self._RenderTopDown()
  636. else:
  637. self._RenderPerspective()
  638. class NodeMapEditor(gbe.nodes.Node2D):
  639. def __init__(self, name="MapEditor", parent=None):
  640. try:
  641. gbe.nodes.Node2D.__init__(self, name, parent)
  642. except gbe.nodes.Node2D as e:
  643. raise e
  644. self._last_orientation = ""
  645. self._size = 0
  646. self._thickness = 1
  647. self._color = pygame.Color(255,255,255)
  648. self._points = None
  649. self._filename = None
  650. self._fileiomode = 0 # 0 = Save | 1 = Load
  651. self.pointer_size = 4
  652. self._fnnode = gbe.nodes.NodeText("FileText", self)
  653. self._fnnode.size = 4
  654. self._fnnode.font_src = "IttyBitty.ttf"
  655. self._fnnode.antialias = False
  656. self._fnnode.set_color(255,255,255)
  657. self._fnnode.set_background(0,0,0,128)
  658. self._fnnode.visible = False
  659. def _getPoints(self, size):
  660. p = self.parent
  661. o = p.orientation
  662. points = self._points[o]
  663. hw = int(size[0]*0.5)
  664. hh = int(size[1]*0.5)
  665. return (
  666. (points[0][0] + hw, points[0][1] + hh),
  667. (points[1][0] + hw, points[1][1] + hh),
  668. (points[2][0] + hw, points[2][1] + hh)
  669. )
  670. @property
  671. def pointer_size(self):
  672. return self._size
  673. @pointer_size.setter
  674. def pointer_size(self, size):
  675. if not isinstance(size, int):
  676. raise TypeError("Size expected to be an integer.")
  677. if size <= 0:
  678. raise ValueError("Size must be greater than zero.")
  679. if size != self._size:
  680. self._size = size
  681. # Now updating all of the pointer... ummm... points
  682. hs = max(1, int(size * 0.5))
  683. self._points = {
  684. "n": ((0,-hs),(hs,hs),(-hs,hs)),
  685. "s": ((0,hs),(hs,-hs),(-hs,-hs)),
  686. "e": ((-hs,hs),(hs,0),(-hs,-hs)),
  687. "w": ((hs,hs),(-hs,0),(hs,-hs))
  688. }
  689. def set_color(self, color):
  690. if isinstance(color, (tuple, list)):
  691. clen = len(color)
  692. if clen == 3 or clen == 4:
  693. iscolor = lambda v : isinstance(v, int) and v >= 0 and v < 256
  694. if iscolor(color[0]) and iscolor(color[1]) and iscolor(color[2]):
  695. if clen == 3:
  696. self._color = pygame.Color(color[0], color[1], color[2])
  697. elif clen == 4 and iscolor(color[3]):
  698. self._color = pygame.Color(color[0], color[1], color[2], color[3])
  699. def get_color(self):
  700. return (self._color.r, self._color.g, self._color.b, self._color.a)
  701. def on_start(self):
  702. self.listen("KEYPRESSED", self.on_keypressed)
  703. def on_pause(self):
  704. self.unlisten("KEYPRESSED", self.on_keypressed)
  705. def on_keypressed(self, event, data):
  706. p = self.parent
  707. if p is None or not isinstance(p, NodeGameMap):
  708. return
  709. if data["key_name"] == "escape":
  710. if self._filename is None:
  711. self.emit("SCENECHANGE", {"scene":"MAIN_MENU", "hold":False})
  712. else:
  713. self._filename = None
  714. self._fnnode.visible = False
  715. elif data["key_name"] in ["enter", "return"] and self._filename is not None:
  716. if len(self._filename) > 0:
  717. if self._fileiomode == 0:
  718. p.save_map(self._filename)
  719. else:
  720. p.load_map(self._filename)
  721. # Call SAVE on the game map.
  722. self._filename = None
  723. self._fnnode.visible = False
  724. if self._filename is None:
  725. if data["key_name"] == "tab":
  726. p.toggle_render_mode()
  727. elif data["key_name"] == "w":
  728. p.move_forward(True)
  729. elif data["key_name"] == "s":
  730. p.move_backward(True)
  731. elif data["key_name"] == "a":
  732. p.turn_left()
  733. elif data["key_name"] == "d":
  734. p.turn_right()
  735. elif data["key_name"] == "space":
  736. o = p.orientation
  737. cpos = p.cell_position
  738. p.set_cell_face(cpos[0], cpos[1], o)
  739. elif data["key_name"] == "e":
  740. p.next_wall()
  741. elif data["key_name"] == "q":
  742. p.prev_wall()
  743. elif data["key_name"] in ["o", "l"]:
  744. self._fileiomode = 0
  745. if data["key_name"] == "l":
  746. self._fileiomode = 1
  747. self._filename = ""
  748. self._fnnode.text = ""
  749. self._fnnode.visible = True
  750. elif len(data["key_name"]) == 1:
  751. self._filename = "{}{}".format(self._filename, data["key_name"])
  752. self._fnnode.text = self._filename
  753. def on_render(self):
  754. size = self.resolution
  755. self.draw_lines(self._getPoints(size), self._color, self._thickness, True)