123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816 |
- ########################################################################
- # 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)
- """Quests
- """
- class IdAmountPair(list):
- def __init__(self, data=[0,1]):
- list.__init__(self, data)
- def __hash__(self): return self.id
- @property
- def id(self): return self[0]
- @property
- def amount(self): return self[1]
- @id.setter
- def id(self, value): self[0] = value
- @amount.setter
- def amount(self, value): self[1] = value
- class QuestRequirements(list):
- ## [level=0, species=[], fractions=[], classes=[], completedQuests=[]]
- def __init__(self, data=[0,[],[],[],[]]):
- list.__init__(self, data)
- @property
- def level(self): return self[0]
- @property
- def species(self): return self[1]
- @property
- def fractions(self): return self[2]
- @property
- def classes(self): return self[3]
- @property
- def completedQuests(self): return self[4]
- @level.setter
- def level(self, value): self[0] = value
- @species.setter
- def species(self, value): self[1] = value
- @fractions.setter
- def fractions(self, value): self[2] = value
- @classes.setter
- def classes(self, value): self[3] = value
- @completedQuests.setter
- def completedQuests(self, value): self[4] = value
- class QuestRewards(list):
- ## [experience=0, items=[]]
- def __init__(self, data=[0,[]]):
- list.__init__(self, data)
- @property
- def experience(self): return self[0]
- @property
- def items(self): return self[1]
- @experience.setter
- def experience(self, value): self[0] = value
- @items.setter
- def items(self, value): self[1] = value
- class QuestObjectives(list):
- ## [talkTo=[], locations=[], defeats=[], items=[]]
- def __init__(self, data=[[],[],[],[]]):
- list.__init__(self, data)
- @property
- def talkTo(self):
- return [IdAmountPair(itemPair) for itemPair in self[0]]
- #return self[0]
- @property
- def locations(self): return self[1]
- @property
- def defeats(self):
- #return self[2]
- return [IdAmountPair(itemPair) for itemPair in self[2]]
- @property
- def items(self): return self[3]
- @talkTo.setter
- def talkTo(self, value): self[0] = value
- @locations.setter
- def locations(self, value): self[1] = value
- @defeats.setter
- def defeats(self, value): self[2] = value
- @items.setter
- def items(self, value): self[3] = value
- class QuestData(GenericDataList):
- empty = ['new', '', [0,[],[],[],[]], [0,[]], [[],[],[],[]]]
- def __init__(self, _id=-1, data=None):
- GenericDataList.__init__(self, _id, data=data)
- if data:
- self._data[2] = QuestRequirements(self._data[2])
- self._data[3] = QuestRewards(self._data[3])
- self._data[4] = QuestObjectives(self._data[4])
- """
- 0 title = ""
- 1 description = ""
- 2 requirements = QuestRequirements
- 3 rewards = QuestRewards
- 4 objectives = QuestObjectives
- """
- @property
- def title(self): return self._data[0]
- @property
- def description(self): return self._data[1]
- @property
- def requirements(self): return self._data[2]
- @property
- def rewards(self): return self._data[3]
- @property
- def objectives(self): return self._data[4]
- @title.setter
- def title(self, value): self._data[0] = value
- @description.setter
- def description(self, value): self._data[1] = value
- @requirements.setter
- def requirements(self, value): self._data[2] = value
- @rewards.setter
- def rewards(self, value): self._data[3] = value
- @objectives.setter
- def objectives(self, value): self._data[4] = value
- """Classes
- """
- class ClassData(GenericDataList):
- empty = ['new',[]]
- def __init__(self, _id=-1, data=None):
- GenericDataList.__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
- """ Fractions
- """
- class FractionData(GenericDataList):
- empty = ['new',[],[]]
- def __init__(self, _id=-1, data=None):
- GenericDataList.__init__(self, _id, data=data)
- """
- 0 name
- 1 allies [] (list with fraction id's)
- 2 enemies [] (list with fraction id's)
- """
- @property
- def name(self): return self._data[0]
- @property
- def allies(self): return self._data[1]
- @property
- def enemies(self): return self._data[2]
- @name.setter
- def name(self, value): self._data[0] = value
- @allies.setter
- def allies(self, value): self._data[1] = value
- @enemies.setter
- def enemies(self, value): self._data[2] = 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 int(self._data[0])
- @property
- def value(self): return int(self._data[1])
- @max.setter
- def max(self, value): self._data[0] = int(value)
- @value.setter
- def value(self, value): self._data[1] = int(value)
- class StatsData(GenericDataList):
- empty = [
- (10, 0), # level
- (80, 80), # health
- (50, 50), # energy
- (10, 1), # strength
- (10, 1), # stamina
- (25, 2), # resistance
- (10, 0.5), # reflexes
- (10, 0) # spitit
- ]
- 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[0])
- @property
- def health(self): return StatData(self._data[1])
- @property
- def energy(self): return StatData(self._data[2])
- @property
- def strength(self): return StatData(self._data[3])
- @property
- def stamina(self): return StatData(self._data[4])
- @property
- def resistance(self): return StatData(self._data[5])
- @property
- def reflexes(self): return StatData(self._data[6])
- @property
- def spitit(self): return StatData(self._data[7])
- @level.setter
- def level(self, value): self._data[0] = int(value)
- @health.setter
- def health(self, value): self._data[1] = int(value)
- @energy.setter
- def energy(self, value): self._data[2] = int(value)
- @strength.setter
- def strength(self, value): self._data[3] = int(value)
- @stamina.setter
- def stamina(self, value): self._data[4] = int(value)
- @resistance.setter
- def resistance(self, value): self._data[5] = int(value)
- @reflexes.setter
- def reflexes(self, value): self._data[6] = int(value)
- @spitit.setter
- def spitit(self, value): self._data[7] = int(value)
- class PlayerStatsData(StatsData):
- empty = [
- (10, 0), # level
- (80, 80), # health
- (50, 50), # energy
- (10, 1), # strength
- (10, 1), # stamina
- (25, 2), # resistance
- (10, 0.5), # reflexes
- (10, 0), # spitit
- (0,100) # experience
- ]
- def __init__(self, _id=-1, data=None):
- StatsData.__init__(self, _id, data)
- """
- 8 experience
- """
- @property
- def experience(self): return StatData(self._data[8])
- @experience.setter
- def experience(self, value): self._data[8] = value
- class CharacterData(GenericDataList):
- """
- 0 name
- 1 dirName
- 2 file
- 3 animations {}
- 4 stats {}
- 5 collisionShape {}
- 6 speciesId
- 7 fractionId
- 8 spellIds []
- """
- 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]
- @property
- def fractionId(self): return self._data[7]
- @property
- def spells(self): return self._data[8]
- @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
- @fractionId.setter
- def fractionId(self, value): self._data[7] = value
- @spells.setter
- def spells(self, value): self._data[8] = 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])
- @stats.setter
- def stats(self, value): self._data[4] = value
- """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):
- """
- 0 name
- 1 dirName
- 2 file
- 3 animations {}
- 4 stats {}
- 5 collisionShape []
- 6 speciesId
- 7 fractionId
- 8 spellIds []
- """
- empty = [
- 'new',
- 'dir-name',
- '.egg',
- {'idle':'.egg', 'walk':'.egg', 'run':'.egg', 'jump':'.egg'},
- StatsData.empty,
- [1,1],
- 1,
- 1,
- []
- ]
- 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,0,0,[0,1],1,1,1,"new","unknown.png",""]
- def __init__(self, _id=-1, data=None):
- GenericDataList.__init__(self, _id, data=data)
- """
- 0. castTime
- 1. coolDown
- 2. methodId
- 3. targetType (selected, self or range)
- 4. range [start, end]
- 5. facingAngle (set to 360 if not requiring facing target)
- 6. impactPoints (- for damage, + for healing)
- 7. energyCost
- 8. name
- 9. icon
- 10. desc
- """
- def iconPath(self):
- # return full icon path
- return os.path.join(str(AssetsPath), 'icons/', self.icon)
- @property
- def castTime(self): return float(self._data[0])
- @property
- def coolDown(self): return float(self._data[1])
- @property
- def method(self): return int(self._data[2])
- @property
- def targetType(self): return int(self._data[3])
- @property
- def range(self): return self._data[4]
- @property
- def facingAngle(self): return int(self._data[5])
- @property
- def impactPoints(self): return int(self._data[6])
- @property
- def energyCost(self): return int(self._data[7])
- @property
- def name(self): return self._data[8]
- @property
- def icon(self): return self._data[9]
- @property
- def desc(self): return self._data[10]
- @property
- def rangeStart(self): return self._data[4][0]
- @property
- def rangeEnd(self): return self._data[4][1]
- @castTime.setter
- def castTime(self, value): self._data[0] = float(value)
- @coolDown.setter
- def coolDown(self, value): self._data[1] = float(value)
- @method.setter
- def method(self, value): self._data[2] = int(value)
- @targetType.setter
- def targetType(self, value): self._data[3] = int(value)
- @range.setter
- def range(self, value): self._data[4] = value
- @facingAngle.setter
- def facingAngle(self, value): self._data[5] = int(value)
- @impactPoints.setter
- def impactPoints(self, value): self._data[6] = int(value)
- @energyCost.setter
- def energyCost(self, value): self._data[7] = int(value)
- @name.setter
- def name(self, value): self._data[8] = value
- @icon.setter
- def icon(self, value): self._data[9] = value
- @desc.setter
- def desc(self, value): self._data[10] = 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 __contains__(self, id):
- return bool(id in self._data)
- 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 _SpellMethods:
- names = ['Basic']
- basic = 0
- class _SpellTargetTypes:
- names = ['Self', 'Selected', 'Range']
- self = 0
- selected = 1
- range = 2
- class _Spells(Table):
- def __init__(self):
- Table.__init__(self, _file='spells.json', _type=SpellData)
- @property
- def methods(self):
- """ Returns the avaiable processing methods.
- A method will do the actual processing.
- @rtype: _SpellMethods
- @return:
- """
- return _SpellMethods
- @property
- def targetTypes(self):
- """ Returns the avaiable target types.
- Self - Target self.
- Selected - Target selected.
- Range - Target all NPC's in set range.
- @rtype: _SpellTargetTypes
- @return:
- """
- return _SpellTargetTypes
- 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 _Fractions(Table):
- def __init__(self):
- Table.__init__(self, _file='fractions.json', _type=FractionData)
- class _Quests(Table):
- def __init__(self):
- Table.__init__(self, _file='quests.json', _type=QuestData)
- 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()
- Fractions = _Fractions()
- Quests = _Quests()
|