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.

nodes.py 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  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()