123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- ########################################################################
- # Hello Worlds - Libre 3D RPG game.
- # Copyright (C) 2020 CYBERDEViL
- #
- # This file is part of Hello Worlds.
- #
- # Hello Worlds is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # Hello Worlds is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
- #
- ########################################################################
- import os
- import json
- global AssetsPath
- global Spells
- global NPCs
- global Maps
- global Players
- global Classes
- class GenericData: # dict
- empty = {}
- def __init__(self, _id=-1, data=None):
- self._id = _id
- if data: self._load(_id, data)
- else: self.setEmpty()
- def _load(self, _id, data):
- self._id = _id
- self._data = data
- @property
- def id(self): return self._id
- @id.setter
- def id(self, value): self._id = value
- def data(self): return self._data
- def columns(self): return len(self.data())
- def setEmpty(self):
- self._data = self.empty.copy()
- class GenericDataList(GenericData): # list
- empty = []
- def __init__(self, _id=-1, data=None):
- GenericData.__init__(self, _id=_id, data=data)
- """Classes
- """
- class ClassData(GenericDataList):
- empty = ['new',[]]
- def __init__(self, _id=-1, data=None):
- GenericData.__init__(self, _id, data=data)
- """
- 0 name
- 1 default spells/actions
- """
- @property
- def name(self): return self._data[0]
- @property
- def spells(self): return self._data[1] #[Spells[spellId] for spellId in self._data[1]]
- @name.setter
- def name(self, value): self._data[0] = value
- @spells.setter
- def spells(self, value):
- self._data[1] = value
- """CharacterData - base for PlayerData and NPCData
- """
- class StatData:
- def __init__(self, data):
- self._data = data
- def data(self): return self._data
- @property
- def max(self): return self._data[0]
- @property
- def value(self): return self._data[1]
- @max.setter
- def max(self, value): self._data[0] = value
- @value.setter
- def value(self, value): self._data[1] = value
- class StatsData(GenericData):
- empty = {
- 'level' : (10, 0),
- 'health' : (80, 80), # max, value
- 'energy' : (50, 50),
- 'strength' : (10, 1),
- 'stamina' : (10, 1),
- 'resistance': (25, 2),
- 'reflexes' : (10, 0.5),
- 'spitit' : (10, 0)
- }
- def __init__(self, _id=-1, data=None):
- GenericData.__init__(self, _id, data=data)
- """
- 0 level
- 1 health
- 2 energy
- 3 strength
- 4 stamina
- 5 resistance
- 6 reflexes
- 7 spitit
- """
- @property
- def level(self): return StatData(self._data['level'])
- @property
- def health(self): return StatData(self._data['health'])
- @property
- def energy(self): return StatData(self._data['energy'])
- @property
- def strength(self): return StatData(self._data['strength'])
- @property
- def stamina(self): return StatData(self._data['stamina'])
- @property
- def resistance(self): return StatData(self._data['resistance'])
- @property
- def reflexes(self): return StatData(self._data['reflexes'])
- @property
- def spitit(self): return StatData(self._data['spirit'])
- @level.setter
- def level(self, value): self._data['level'] = value
- @health.setter
- def health(self, value): self._data['health'] = value
- @energy.setter
- def energy(self, value): self._data['energy'] = value
- @strength.setter
- def strength(self, value): self._data['strength'] = value
- @stamina.setter
- def stamina(self, value): self._data['stamina'] = value
- @resistance.setter
- def resistance(self, value): self._data['resistance'] = value
- @reflexes.setter
- def reflexes(self, value): self._data['reflexes'] = value
- @spitit.setter
- def spitit(self, value): self._data['spirit'] = value
- class PlayerStatsData(StatsData):
- empty = {
- 'level' : (10, 0),
- 'health' : (80, 80), # max, value
- 'energy' : (50, 50),
- 'strength' : (10, 1),
- 'stamina' : (10, 1),
- 'resistance': (25, 2),
- 'reflexes' : (10, 0.5),
- 'spitit' : (10, 0),
- 'experience': (0,100)
- }
- def __init__(self, _id=-1, data=None):
- StatsData.__init__(self, _id, data)
- """
- 8 experience
- """
- @property
- def experience(self): return StatData(self._data['experience'])
- @experience.setter
- def experience(self, value): self._data['experience'] = value
- class CharacterData(GenericDataList):
- """
- 0 name
- 1 dirName
- 2 file
- 3 animations {}
- 4 stats {}
- 5 collisionShape {}
- 6 speciesId
- """
- empty = [
- 'new',
- 'dir-name',
- '.egg',
- {'idle':'.egg', 'walk':'.egg', 'run':'.egg', 'jump':'.egg'},
- StatsData.empty,
- [1,1],
- 1
- ]
- def __init__(self, _id=-1, data=None):
- GenericDataList.__init__(self, _id, data=data)
- @property
- def name(self): return self._data[0]
- @property
- def dirName(self): return self._data[1]
- @property
- def file(self): return self._data[2]
- @property
- def animations(self): return self._data[3]
- @property
- def stats(self): return StatsData(data = self._data[4])
- @property
- def collisionShape(self): return self._data[5]
- @property
- def speciesId(self): return self._data[6]
- @name.setter
- def name(self, value): self._data[0] = value
- @dirName.setter
- def dirName(self, value): self._data[1] = value
- @file.setter
- def file(self, value): self._data[2] = value
- @animations.setter
- def animations(self, value): self._data[3] = value
- @stats.setter
- def stats(self, value): self._data[4] = value
- @collisionShape.setter
- def collisionShape(self, value): self._data[5] = value
- @speciesId.setter
- def speciesId(self, value): self._data[6] = value
- """Players
- """
- class PlayerData(CharacterData):
- empty = [
- 'new',
- 'dir-name',
- '.egg',
- {'idle':'.egg', 'walk':'.egg', 'run':'.egg', 'jump':'.egg'},
- PlayerStatsData.empty,
- [1,1],
- 1
- ]
- def __init__(self, _id=-1, data=None):
- CharacterData.__init__(self, _id, data)
- @property
- def filePath(self): return os.path.join(AssetsPath.players, self.dirName, self.file)
- @property
- def stats(self):
- return PlayerStatsData(data = self._data[4])
- """Maps
- """
- class MapData(GenericDataList):
- empty = ['New map','map','.egg','.egg']
- def __init__(self, _id=-1, data=None):
- GenericData.__init__(self, _id, data)
- """
- 0 name
- 1 dir-name
- 2 file-name.egg
- 3 ortho-file-name.egg
- """
- @property
- def name(self): return self._data[0]
- @property
- def dirName(self): return self._data[1]
- @property
- def file(self): return self._data[2]
- @property
- def filePath(self): return os.path.join(AssetsPath.maps, self.dirName, self.file)
- @property
- def orthoFile(self): return self._data[3]
- @property
- def orthoFilePath(self): return os.path.join(AssetsPath.maps, self.dirName, self.orthoFile)
- @property
- def spawns(self): return Spawns(self.dirName)
- @name.setter
- def name(self, value): self._data[0] = value
- @dirName.setter
- def dirName(self, value): self._data[1] = value
- @file.setter
- def file(self, value): self._data[2] = value
- @orthoFile.setter
- def orthoFile(self, value): self._data[3] = value
- """Spawn data
- """
- class GenericSpawnData(GenericDataList):
- empty = [1,0,0,0,0]
- def __init__(self, _id=-1, data=None):
- GenericDataList.__init__(self, _id, data=data)
- """
- 0 characterId (npc or player-character)
- 1 x
- 2 y
- 3 z
- 4 o
- """
- #if data: self._load(_id, data)
- @property
- def characterId(self): return self._data[0]
- @property
- def x(self): return self._data[1]
- @property
- def y(self): return self._data[2]
- @property
- def z(self): return self._data[3]
- @property
- def orientation(self): return self._data[4]
- @property
- def pos(self): return (self.x, self.y, self.z)
- @characterId.setter
- def characterId(self, value): self._data[0] = value
- @x.setter
- def x(self, value): self._data[1] = value
- @y.setter
- def y(self, value): self._data[2] = value
- @z.setter
- def z(self, value): self._data[3] = value
- @orientation.setter
- def orientation(self, value): self._data[4] = value
- class NPCSpawnData(GenericSpawnData):
- empty = GenericSpawnData.empty + [10]
- def __init__(self, _id=-1, data=None):
- GenericSpawnData.__init__(self, _id, data)
- """
- 5 respawnTime - in seconds
- """
- @property
- def respawnTime(self): return self._data[5]
- @respawnTime.setter
- def respawnTime(self, value): self._data[5] = value
- """NPCs
- """
- class NPCData(CharacterData):
- def __init__(self, _id=-1, data=None):
- CharacterData.__init__(self, _id, data)
- @property
- def filePath(self): return os.path.join(AssetsPath.npcs, self.dirName, self.file)
- """Spells
- """
- class SpellData(GenericDataList):
- empty = [1,0,1,1,"new","unknown.png",""]
- def __init__(self, _id=-1, data=None):
- GenericDataList.__init__(self, _id, data=data)
- """
- 0 castTime
- 1 coolDown
- 2 damage
- 3 energy
- 4 name
- 5 icon
- 6 desc
- """
- def iconPath(self):
- # return full icon path
- return os.path.join(str(AssetsPath), 'icons/', self.icon)
- @property
- def castTime(self): return self._data[0]
- @property
- def coolDown(self): return self._data[1]
- @property
- def damage(self): return self._data[2]
- @property
- def energy(self): return self._data[3]
- @property
- def name(self): return self._data[4]
- @property
- def icon(self): return self._data[5]
- @property
- def desc(self): return self._data[6]
- @castTime.setter
- def castTime(self, value): self._data[0] = value
- @coolDown.setter
- def coolDown(self, value): self._data[1] = value
- @damage.setter
- def damage(self, value): self._data[2] = value
- @energy.setter
- def energy(self, value): self._data[3] = value
- @name.setter
- def name(self, value): self._data[4] = value
- @icon.setter
- def icon(self, value): self._data[5] = value
- @desc.setter
- def desc(self, value): self._data[6] = value
- class _AssetsPath:
- def __init__(self, path='assets/'):
- self._path = path
- self._callbacks = []
- def __str__(self): return self._path
- def __repr__(self): return self._path
- @property
- def icons(self): return os.path.join(str(self), 'icons/')
- @property
- def npcs(self): return os.path.join(str(self), 'creatures/')
- @property
- def maps(self): return os.path.join(str(self), 'maps/')
- @property
- def players(self): return os.path.join(str(self), 'characters/')
- @property
- def widgets(self): return os.path.join(str(self), 'widgets/')
- def joinPath(self, other):
- return os.path.join(str(self), other)
- def set(self, path):
- self._path = path
- for cb in self._callbacks: cb()
- def addReloadCallback(self, cb):
- self._callbacks.append(cb)
- class Table:
- def __init__(self, _file, _type):
- self._file = _file
- self._filePath = self.filePath()
- self._fileValid = False
- self._data = {}
- self._type = _type
- AssetsPath.addReloadCallback(self.__load)
- def columns(self): return len(self._type.empty) + 1 # +1 for id
- def __iter__(self):
- for _id, item in self._data.items(): yield item
- def __getitem__(self, key):
- return self._data.get(str(key))
- def reload(self): self.__load()
- def __load(self):
- self._data = {}
- if os.path.isfile(self.filePath()):
- print(" [OK] Found {0}".format(self._file))
- with open(self.filePath()) as f:
- try:
- data = json.load(f)
- for _id, d in data.items():
- self._data.update({_id : self._type(_id, d)})
- except json.decoder.JSONDecodeError as err:
- print("\t! Empty or corrupt file! Error: {0}".format(err))
- else:
- print(" [XX] Not found {0}".format(self._file))
- def __save(self):
- data = {}
- for item in self:
- data.update({item.id : item.data()})
- with open(self.filePath(), 'w') as fp:
- json.dump(data, fp)
- def _getNewId(self):
- for i in range(1, 1024):
- if str(i) not in self._data: return str(i)
- def filePath(self): return os.path.join(str(AssetsPath), self._file)
- def new(self, data=[]):
- if not data: data = self._type.empty
- _id = self._getNewId()
- self.edit(_id, data)
- return _id
- def edit(self, _id, newData):
- self._data.update({_id : self._type(_id, newData)})
- def remove(self, _id):
- self._data.pop(_id)
- def save(self): self.__save()
- class _Spells(Table):
- def __init__(self):
- Table.__init__(self, _file='spells.json', _type=SpellData)
- class _NPCs(Table):
- def __init__(self):
- Table.__init__(self, _file='npcs.json', _type=NPCData)
- class _Maps(Table):
- def __init__(self):
- Table.__init__(self, _file='maps.json', _type=MapData)
- class _Players(Table):
- def __init__(self):
- Table.__init__(self, _file='players.json', _type=PlayerData)
- class _Classes(Table):
- def __init__(self):
- Table.__init__(self, _file='classes.json', _type=ClassData)
- class Spawns(Table):
- def __init__(self, mapDir):
- _file = 'spawns.json'
- self._subPath = os.path.join(mapDir, _file)
- Table.__init__(self, _file=_file, _type=NPCSpawnData)
- self.reload()
- def filePath(self): return os.path.join(AssetsPath.maps, self._subPath)
- AssetsPath = _AssetsPath()
- Spells = _Spells()
- NPCs = _NPCs()
- Maps = _Maps()
- Players = _Players()
- Classes = _Classes()
|