Legend of the Gold Box... A game written for the LOWREZJAM 2018 game jam
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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)