db.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  1. ########################################################################
  2. # Hello Worlds - Libre 3D RPG game.
  3. # Copyright (C) 2020 CYBERDEViL
  4. #
  5. # This file is part of Hello Worlds.
  6. #
  7. # Hello Worlds is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # Hello Worlds is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. #
  20. ########################################################################
  21. import os
  22. import json
  23. global AssetsPath
  24. global Spells
  25. global NPCs
  26. global Maps
  27. global Players
  28. global Classes
  29. class GenericData: # dict
  30. empty = {}
  31. def __init__(self, _id=-1, data=None):
  32. self._id = _id
  33. if data: self._load(_id, data)
  34. else: self.setEmpty()
  35. def _load(self, _id, data):
  36. self._id = _id
  37. self._data = data
  38. @property
  39. def id(self): return self._id
  40. @id.setter
  41. def id(self, value): self._id = value
  42. def data(self): return self._data
  43. def columns(self): return len(self.data())
  44. def setEmpty(self):
  45. self._data = self.empty.copy()
  46. class GenericDataList(GenericData): # list
  47. empty = []
  48. def __init__(self, _id=-1, data=None):
  49. GenericData.__init__(self, _id=_id, data=data)
  50. """Quests
  51. """
  52. class IdAmountPair(list):
  53. def __init__(self, data=[0,1]):
  54. list.__init__(self, data)
  55. def __hash__(self): return self.id
  56. @property
  57. def id(self): return self[0]
  58. @property
  59. def amount(self): return self[1]
  60. @id.setter
  61. def id(self, value): self[0] = value
  62. @amount.setter
  63. def amount(self, value): self[1] = value
  64. class QuestRequirements(list):
  65. ## [level=0, species=[], fractions=[], classes=[], completedQuests=[]]
  66. def __init__(self, data=[0,[],[],[],[]]):
  67. list.__init__(self, data)
  68. @property
  69. def level(self): return self[0]
  70. @property
  71. def species(self): return self[1]
  72. @property
  73. def fractions(self): return self[2]
  74. @property
  75. def classes(self): return self[3]
  76. @property
  77. def completedQuests(self): return self[4]
  78. @level.setter
  79. def level(self, value): self[0] = value
  80. @species.setter
  81. def species(self, value): self[1] = value
  82. @fractions.setter
  83. def fractions(self, value): self[2] = value
  84. @classes.setter
  85. def classes(self, value): self[3] = value
  86. @completedQuests.setter
  87. def completedQuests(self, value): self[4] = value
  88. class QuestRewards(list):
  89. ## [experience=0, items=[]]
  90. def __init__(self, data=[0,[]]):
  91. list.__init__(self, data)
  92. @property
  93. def experience(self): return self[0]
  94. @property
  95. def items(self): return self[1]
  96. @experience.setter
  97. def experience(self, value): self[0] = value
  98. @items.setter
  99. def items(self, value): self[1] = value
  100. class QuestObjectives(list):
  101. ## [talkTo=[], locations=[], defeats=[], items=[]]
  102. def __init__(self, data=[[],[],[],[]]):
  103. list.__init__(self, data)
  104. @property
  105. def talkTo(self):
  106. return [IdAmountPair(itemPair) for itemPair in self[0]]
  107. #return self[0]
  108. @property
  109. def locations(self): return self[1]
  110. @property
  111. def defeats(self):
  112. #return self[2]
  113. return [IdAmountPair(itemPair) for itemPair in self[2]]
  114. @property
  115. def items(self): return self[3]
  116. @talkTo.setter
  117. def talkTo(self, value): self[0] = value
  118. @locations.setter
  119. def locations(self, value): self[1] = value
  120. @defeats.setter
  121. def defeats(self, value): self[2] = value
  122. @items.setter
  123. def items(self, value): self[3] = value
  124. class QuestData(GenericDataList):
  125. empty = ['new', '', [0,[],[],[],[]], [0,[]], [[],[],[],[]]]
  126. def __init__(self, _id=-1, data=None):
  127. GenericDataList.__init__(self, _id, data=data)
  128. if data:
  129. self._data[2] = QuestRequirements(self._data[2])
  130. self._data[3] = QuestRewards(self._data[3])
  131. self._data[4] = QuestObjectives(self._data[4])
  132. """
  133. 0 title = ""
  134. 1 description = ""
  135. 2 requirements = QuestRequirements
  136. 3 rewards = QuestRewards
  137. 4 objectives = QuestObjectives
  138. """
  139. @property
  140. def title(self): return self._data[0]
  141. @property
  142. def description(self): return self._data[1]
  143. @property
  144. def requirements(self): return self._data[2]
  145. @property
  146. def rewards(self): return self._data[3]
  147. @property
  148. def objectives(self): return self._data[4]
  149. @title.setter
  150. def title(self, value): self._data[0] = value
  151. @description.setter
  152. def description(self, value): self._data[1] = value
  153. @requirements.setter
  154. def requirements(self, value): self._data[2] = value
  155. @rewards.setter
  156. def rewards(self, value): self._data[3] = value
  157. @objectives.setter
  158. def objectives(self, value): self._data[4] = value
  159. """Classes
  160. """
  161. class ClassData(GenericDataList):
  162. empty = ['new',[]]
  163. def __init__(self, _id=-1, data=None):
  164. GenericDataList.__init__(self, _id, data=data)
  165. """
  166. 0 name
  167. 1 default spells/actions
  168. """
  169. @property
  170. def name(self): return self._data[0]
  171. @property
  172. def spells(self): return self._data[1] #[Spells[spellId] for spellId in self._data[1]]
  173. @name.setter
  174. def name(self, value): self._data[0] = value
  175. @spells.setter
  176. def spells(self, value):
  177. self._data[1] = value
  178. """ Fractions
  179. """
  180. class FractionData(GenericDataList):
  181. empty = ['new',[],[]]
  182. def __init__(self, _id=-1, data=None):
  183. GenericDataList.__init__(self, _id, data=data)
  184. """
  185. 0 name
  186. 1 allies [] (list with fraction id's)
  187. 2 enemies [] (list with fraction id's)
  188. """
  189. @property
  190. def name(self): return self._data[0]
  191. @property
  192. def allies(self): return self._data[1]
  193. @property
  194. def enemies(self): return self._data[2]
  195. @name.setter
  196. def name(self, value): self._data[0] = value
  197. @allies.setter
  198. def allies(self, value): self._data[1] = value
  199. @enemies.setter
  200. def enemies(self, value): self._data[2] = value
  201. """CharacterData - base for PlayerData and NPCData
  202. """
  203. class StatData:
  204. def __init__(self, data):
  205. self._data = data
  206. def data(self): return self._data
  207. @property
  208. def max(self): return int(self._data[0])
  209. @property
  210. def value(self): return int(self._data[1])
  211. @max.setter
  212. def max(self, value): self._data[0] = int(value)
  213. @value.setter
  214. def value(self, value): self._data[1] = int(value)
  215. class StatsData(GenericDataList):
  216. empty = [
  217. (10, 0), # level
  218. (80, 80), # health
  219. (50, 50), # energy
  220. (10, 1), # strength
  221. (10, 1), # stamina
  222. (25, 2), # resistance
  223. (10, 0.5), # reflexes
  224. (10, 0) # spitit
  225. ]
  226. def __init__(self, _id=-1, data=None):
  227. GenericData.__init__(self, _id, data=data)
  228. """
  229. 0 level
  230. 1 health
  231. 2 energy
  232. 3 strength
  233. 4 stamina
  234. 5 resistance
  235. 6 reflexes
  236. 7 spitit
  237. """
  238. @property
  239. def level(self): return StatData(self._data[0])
  240. @property
  241. def health(self): return StatData(self._data[1])
  242. @property
  243. def energy(self): return StatData(self._data[2])
  244. @property
  245. def strength(self): return StatData(self._data[3])
  246. @property
  247. def stamina(self): return StatData(self._data[4])
  248. @property
  249. def resistance(self): return StatData(self._data[5])
  250. @property
  251. def reflexes(self): return StatData(self._data[6])
  252. @property
  253. def spitit(self): return StatData(self._data[7])
  254. @level.setter
  255. def level(self, value): self._data[0] = int(value)
  256. @health.setter
  257. def health(self, value): self._data[1] = int(value)
  258. @energy.setter
  259. def energy(self, value): self._data[2] = int(value)
  260. @strength.setter
  261. def strength(self, value): self._data[3] = int(value)
  262. @stamina.setter
  263. def stamina(self, value): self._data[4] = int(value)
  264. @resistance.setter
  265. def resistance(self, value): self._data[5] = int(value)
  266. @reflexes.setter
  267. def reflexes(self, value): self._data[6] = int(value)
  268. @spitit.setter
  269. def spitit(self, value): self._data[7] = int(value)
  270. class PlayerStatsData(StatsData):
  271. empty = [
  272. (10, 0), # level
  273. (80, 80), # health
  274. (50, 50), # energy
  275. (10, 1), # strength
  276. (10, 1), # stamina
  277. (25, 2), # resistance
  278. (10, 0.5), # reflexes
  279. (10, 0), # spitit
  280. (0,100) # experience
  281. ]
  282. def __init__(self, _id=-1, data=None):
  283. StatsData.__init__(self, _id, data)
  284. """
  285. 8 experience
  286. """
  287. @property
  288. def experience(self): return StatData(self._data[8])
  289. @experience.setter
  290. def experience(self, value): self._data[8] = value
  291. class CharacterData(GenericDataList):
  292. """
  293. 0 name
  294. 1 dirName
  295. 2 file
  296. 3 animations {}
  297. 4 stats {}
  298. 5 collisionShape {}
  299. 6 speciesId
  300. 7 fractionId
  301. 8 spellIds []
  302. """
  303. empty = [
  304. 'new',
  305. 'dir-name',
  306. '.egg',
  307. {'idle':'.egg', 'walk':'.egg', 'run':'.egg', 'jump':'.egg'},
  308. StatsData.empty,
  309. [1,1],
  310. 1,
  311. []
  312. ]
  313. def __init__(self, _id=-1, data=None):
  314. GenericDataList.__init__(self, _id, data=data)
  315. @property
  316. def name(self): return self._data[0]
  317. @property
  318. def dirName(self): return self._data[1]
  319. @property
  320. def file(self): return self._data[2]
  321. @property
  322. def animations(self): return self._data[3]
  323. @property
  324. def stats(self): return StatsData(data = self._data[4])
  325. @property
  326. def collisionShape(self): return self._data[5]
  327. @property
  328. def speciesId(self): return self._data[6]
  329. @property
  330. def fractionId(self): return self._data[7]
  331. @property
  332. def spells(self): return self._data[8]
  333. @name.setter
  334. def name(self, value): self._data[0] = value
  335. @dirName.setter
  336. def dirName(self, value): self._data[1] = value
  337. @file.setter
  338. def file(self, value): self._data[2] = value
  339. @animations.setter
  340. def animations(self, value): self._data[3] = value
  341. @stats.setter
  342. def stats(self, value): self._data[4] = value
  343. @collisionShape.setter
  344. def collisionShape(self, value): self._data[5] = value
  345. @speciesId.setter
  346. def speciesId(self, value): self._data[6] = value
  347. @fractionId.setter
  348. def fractionId(self, value): self._data[7] = value
  349. @spells.setter
  350. def spells(self, value): self._data[8] = value
  351. """Players
  352. """
  353. class PlayerData(CharacterData):
  354. empty = [
  355. 'new',
  356. 'dir-name',
  357. '.egg',
  358. {'idle':'.egg', 'walk':'.egg', 'run':'.egg', 'jump':'.egg'},
  359. PlayerStatsData.empty,
  360. [1,1],
  361. 1,
  362. []
  363. ]
  364. def __init__(self, _id=-1, data=None):
  365. CharacterData.__init__(self, _id, data)
  366. @property
  367. def filePath(self): return os.path.join(AssetsPath.players, self.dirName, self.file)
  368. @property
  369. def stats(self):
  370. return PlayerStatsData(data = self._data[4])
  371. @stats.setter
  372. def stats(self, value): self._data[4] = value
  373. """Maps
  374. """
  375. class MapData(GenericDataList):
  376. empty = ['New map','map','.egg','.egg']
  377. def __init__(self, _id=-1, data=None):
  378. GenericData.__init__(self, _id, data)
  379. """
  380. 0 name
  381. 1 dir-name
  382. 2 file-name.egg
  383. 3 ortho-file-name.egg
  384. """
  385. @property
  386. def name(self): return self._data[0]
  387. @property
  388. def dirName(self): return self._data[1]
  389. @property
  390. def file(self): return self._data[2]
  391. @property
  392. def filePath(self): return os.path.join(AssetsPath.maps, self.dirName, self.file)
  393. @property
  394. def orthoFile(self): return self._data[3]
  395. @property
  396. def orthoFilePath(self): return os.path.join(AssetsPath.maps, self.dirName, self.orthoFile)
  397. @property
  398. def spawns(self): return Spawns(self.dirName)
  399. @name.setter
  400. def name(self, value): self._data[0] = value
  401. @dirName.setter
  402. def dirName(self, value): self._data[1] = value
  403. @file.setter
  404. def file(self, value): self._data[2] = value
  405. @orthoFile.setter
  406. def orthoFile(self, value): self._data[3] = value
  407. """Spawn data
  408. """
  409. class GenericSpawnData(GenericDataList):
  410. empty = [1,0,0,0,0]
  411. def __init__(self, _id=-1, data=None):
  412. GenericDataList.__init__(self, _id, data=data)
  413. """
  414. 0 characterId (npc or player-character)
  415. 1 x
  416. 2 y
  417. 3 z
  418. 4 o
  419. """
  420. #if data: self._load(_id, data)
  421. @property
  422. def characterId(self): return self._data[0]
  423. @property
  424. def x(self): return self._data[1]
  425. @property
  426. def y(self): return self._data[2]
  427. @property
  428. def z(self): return self._data[3]
  429. @property
  430. def orientation(self): return self._data[4]
  431. @property
  432. def pos(self): return (self.x, self.y, self.z)
  433. @characterId.setter
  434. def characterId(self, value): self._data[0] = value
  435. @x.setter
  436. def x(self, value): self._data[1] = value
  437. @y.setter
  438. def y(self, value): self._data[2] = value
  439. @z.setter
  440. def z(self, value): self._data[3] = value
  441. @orientation.setter
  442. def orientation(self, value): self._data[4] = value
  443. class NPCSpawnData(GenericSpawnData):
  444. empty = GenericSpawnData.empty + [10]
  445. def __init__(self, _id=-1, data=None):
  446. GenericSpawnData.__init__(self, _id, data)
  447. """
  448. 5 respawnTime - in seconds
  449. """
  450. @property
  451. def respawnTime(self): return self._data[5]
  452. @respawnTime.setter
  453. def respawnTime(self, value): self._data[5] = value
  454. """NPCs
  455. """
  456. class NPCData(CharacterData):
  457. """
  458. 0 name
  459. 1 dirName
  460. 2 file
  461. 3 animations {}
  462. 4 stats {}
  463. 5 collisionShape []
  464. 6 speciesId
  465. 7 fractionId
  466. 8 spellIds []
  467. """
  468. empty = [
  469. 'new',
  470. 'dir-name',
  471. '.egg',
  472. {'idle':'.egg', 'walk':'.egg', 'run':'.egg', 'jump':'.egg'},
  473. StatsData.empty,
  474. [1,1],
  475. 1,
  476. 1,
  477. []
  478. ]
  479. def __init__(self, _id=-1, data=None):
  480. CharacterData.__init__(self, _id, data)
  481. @property
  482. def filePath(self): return os.path.join(AssetsPath.npcs, self.dirName, self.file)
  483. """Spells
  484. """
  485. class SpellData(GenericDataList):
  486. empty = [1,0,0,0,[0,1],1,1,1,"new","unknown.png",""]
  487. def __init__(self, _id=-1, data=None):
  488. GenericDataList.__init__(self, _id, data=data)
  489. """
  490. 0. castTime
  491. 1. coolDown
  492. 2. methodId
  493. 3. targetType (selected, self or range)
  494. 4. range [start, end]
  495. 5. facingAngle (set to 360 if not requiring facing target)
  496. 6. impactPoints (- for damage, + for healing)
  497. 7. energyCost
  498. 8. name
  499. 9. icon
  500. 10. desc
  501. """
  502. def iconPath(self):
  503. # return full icon path
  504. return os.path.join(str(AssetsPath), 'icons/', self.icon)
  505. @property
  506. def castTime(self): return float(self._data[0])
  507. @property
  508. def coolDown(self): return float(self._data[1])
  509. @property
  510. def method(self): return int(self._data[2])
  511. @property
  512. def targetType(self): return int(self._data[3])
  513. @property
  514. def range(self): return self._data[4]
  515. @property
  516. def facingAngle(self): return int(self._data[5])
  517. @property
  518. def impactPoints(self): return int(self._data[6])
  519. @property
  520. def energyCost(self): return int(self._data[7])
  521. @property
  522. def name(self): return self._data[8]
  523. @property
  524. def icon(self): return self._data[9]
  525. @property
  526. def desc(self): return self._data[10]
  527. @property
  528. def rangeStart(self): return self._data[4][0]
  529. @property
  530. def rangeEnd(self): return self._data[4][1]
  531. @castTime.setter
  532. def castTime(self, value): self._data[0] = float(value)
  533. @coolDown.setter
  534. def coolDown(self, value): self._data[1] = float(value)
  535. @method.setter
  536. def method(self, value): self._data[2] = int(value)
  537. @targetType.setter
  538. def targetType(self, value): self._data[3] = int(value)
  539. @range.setter
  540. def range(self, value): self._data[4] = value
  541. @facingAngle.setter
  542. def facingAngle(self, value): self._data[5] = int(value)
  543. @impactPoints.setter
  544. def impactPoints(self, value): self._data[6] = int(value)
  545. @energyCost.setter
  546. def energyCost(self, value): self._data[7] = int(value)
  547. @name.setter
  548. def name(self, value): self._data[8] = value
  549. @icon.setter
  550. def icon(self, value): self._data[9] = value
  551. @desc.setter
  552. def desc(self, value): self._data[10] = value
  553. class _AssetsPath:
  554. def __init__(self, path='assets/'):
  555. self._path = path
  556. self._callbacks = []
  557. def __str__(self): return self._path
  558. def __repr__(self): return self._path
  559. @property
  560. def icons(self): return os.path.join(str(self), 'icons/')
  561. @property
  562. def npcs(self): return os.path.join(str(self), 'creatures/')
  563. @property
  564. def maps(self): return os.path.join(str(self), 'maps/')
  565. @property
  566. def players(self): return os.path.join(str(self), 'characters/')
  567. @property
  568. def widgets(self): return os.path.join(str(self), 'widgets/')
  569. def joinPath(self, other):
  570. return os.path.join(str(self), other)
  571. def set(self, path):
  572. self._path = path
  573. for cb in self._callbacks: cb()
  574. def addReloadCallback(self, cb):
  575. self._callbacks.append(cb)
  576. class Table:
  577. def __init__(self, _file, _type):
  578. self._file = _file
  579. self._filePath = self.filePath()
  580. self._fileValid = False
  581. self._data = {}
  582. self._type = _type
  583. AssetsPath.addReloadCallback(self.__load)
  584. def columns(self): return len(self._type.empty) + 1 # +1 for id
  585. def __iter__(self):
  586. for _id, item in self._data.items(): yield item
  587. def __getitem__(self, key):
  588. return self._data.get(str(key))
  589. def __contains__(self, id):
  590. return bool(id in self._data)
  591. def reload(self): self.__load()
  592. def __load(self):
  593. self._data = {}
  594. if os.path.isfile(self.filePath()):
  595. print(" [OK] Found {0}".format(self._file))
  596. with open(self.filePath()) as f:
  597. try:
  598. data = json.load(f)
  599. for _id, d in data.items():
  600. self._data.update({_id : self._type(_id, d)})
  601. except json.decoder.JSONDecodeError as err:
  602. print("\t! Empty or corrupt file! Error: {0}".format(err))
  603. else:
  604. print(" [XX] Not found {0}".format(self._file))
  605. def __save(self):
  606. data = {}
  607. for item in self:
  608. data.update({item.id : item.data()})
  609. with open(self.filePath(), 'w') as fp:
  610. json.dump(data, fp)
  611. def _getNewId(self):
  612. for i in range(1, 1024):
  613. if str(i) not in self._data: return str(i)
  614. def filePath(self): return os.path.join(str(AssetsPath), self._file)
  615. def new(self, data=[]):
  616. if not data: data = self._type.empty
  617. _id = self._getNewId()
  618. self.edit(_id, data)
  619. return _id
  620. def edit(self, _id, newData):
  621. self._data.update({_id : self._type(_id, newData)})
  622. def remove(self, _id):
  623. self._data.pop(_id)
  624. def save(self): self.__save()
  625. class _SpellMethods:
  626. names = ['Basic']
  627. basic = 0
  628. class _SpellTargetTypes:
  629. names = ['Self', 'Selected', 'Range']
  630. self = 0
  631. selected = 1
  632. range = 2
  633. class _Spells(Table):
  634. def __init__(self):
  635. Table.__init__(self, _file='spells.json', _type=SpellData)
  636. @property
  637. def methods(self):
  638. """ Returns the avaiable processing methods.
  639. A method will do the actual processing.
  640. @rtype: _SpellMethods
  641. @return:
  642. """
  643. return _SpellMethods
  644. @property
  645. def targetTypes(self):
  646. """ Returns the avaiable target types.
  647. Self - Target self.
  648. Selected - Target selected.
  649. Range - Target all NPC's in set range.
  650. @rtype: _SpellTargetTypes
  651. @return:
  652. """
  653. return _SpellTargetTypes
  654. class _NPCs(Table):
  655. def __init__(self):
  656. Table.__init__(self, _file='npcs.json', _type=NPCData)
  657. class _Maps(Table):
  658. def __init__(self):
  659. Table.__init__(self, _file='maps.json', _type=MapData)
  660. class _Players(Table):
  661. def __init__(self):
  662. Table.__init__(self, _file='players.json', _type=PlayerData)
  663. class _Classes(Table):
  664. def __init__(self):
  665. Table.__init__(self, _file='classes.json', _type=ClassData)
  666. class _Fractions(Table):
  667. def __init__(self):
  668. Table.__init__(self, _file='fractions.json', _type=FractionData)
  669. class _Quests(Table):
  670. def __init__(self):
  671. Table.__init__(self, _file='quests.json', _type=QuestData)
  672. class Spawns(Table):
  673. def __init__(self, mapDir):
  674. _file = 'spawns.json'
  675. self._subPath = os.path.join(mapDir, _file)
  676. Table.__init__(self, _file=_file, _type=NPCSpawnData)
  677. self.reload()
  678. def filePath(self): return os.path.join(AssetsPath.maps, self._subPath)
  679. AssetsPath = _AssetsPath()
  680. Spells = _Spells()
  681. NPCs = _NPCs()
  682. Maps = _Maps()
  683. Players = _Players()
  684. Classes = _Classes()
  685. Fractions = _Fractions()
  686. Quests = _Quests()