Legend of the Gold Box... A game written for the LOWREZJAM 2018 game jam
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

894 lines
33KB

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