diff --git a/src/classes/Dependency.py b/src/classes/Dependency.py new file mode 100644 index 0000000..378981a --- /dev/null +++ b/src/classes/Dependency.py @@ -0,0 +1,47 @@ +# + +from itertools import chain + +_dependencies = {} +_dependent_vars = set() + +def addDependency(dep1: str, dep2: str): + global _dependencies, _dependent_vars + if dep1 in _dependencies.keys(): + if not dep2 in _dependencies[dep1]: + _dependencies[dep1].append(dep2) + #print(f"Appending DEP: {dep1} -> {dep2}") + else: + _dependencies[dep1] = [dep2] + #print(f"Adding DEP: {dep1} -> {dep2}") + _dependent_vars = set(chain.from_iterable(_dependencies.values())) + #print("DV: \n", _dependent_vars) + +def getDependentVars(): + return _dependent_vars + +def getDependencies(): + return _dependencies + +class Dependency: + def _reset_dependent_vars(self, name: str): + #print(f"DEP\n{_dependencies}") + for var in _dependencies[name]: + #print(f"Resetting: {var} (due to {name})") + try: + super().__delattr__(f"{var}") + except: + #print(f"FAIL") + pass + if var in _dependencies: + self._reset_dependent_vars(var) + + def __setattr__(self, name: str, value): + global _dependencies, _dependent_vars + if name in _dependent_vars: + raise AttributeError("Cannot set this value.") + if name in _dependencies: + self._reset_dependent_vars(name) + name = f"_{name}" + #print(f"Setting {name} to {value}") + super().__setattr__(name, value) diff --git a/src/classes/ModDB.py b/src/classes/ModDB.py new file mode 100644 index 0000000..00bf0b2 --- /dev/null +++ b/src/classes/ModDB.py @@ -0,0 +1,68 @@ +# + +from Modifiers import Modifier + +class ModifierDatabase: + def __init__(self, owner = None): + self.owner = owner + self.clear() + + def addEntry(self, entry: Modifier): + name = entry.name + type = entry.type + if name not in self.db.keys(): + self.db[name] = dict() + if type not in self.db[name].keys(): + self.db[name][type] = [entry] + else: + if not entry in self.db[name][type]: + self.db[name][type].append(entry) + + def getBase(self, name: str): + retVal = 0 + if name in self.db.keys() and "BASE" in self.db[name].keys(): + for entry in self.db[name]["BASE"]: + retVal += entry.getValue(self.owner) + return retVal + return 0 + + def getFlat(self, name: str): + retVal = 0 + if name in self.db.keys() and "FLAT" in self.db[name].keys(): + for entry in self.db[name]["FLAT"]: + retVal += entry.getValue(self.owner) + return retVal + return 0 + + def getInc(self, name: str): + retVal = 0 + if name in self.db.keys() and "INC" in self.db[name].keys(): + for entry in self.db[name]["INC"]: + retVal += entry.getValue(self.owner) + return retVal + return retVal + + def getMore(self, name: str): + retVal = 0 + if name in self.db.keys() and "MORE" in self.db[name].keys(): + for entry in self.db[name]["MORE"]: + retVal += entry.getValue(self.owner) + return retVal + return retVal + + def clear(self): + self.db = dict() + +def test(): + db = ModifierDatabase() + mod1 = Modifier("Health", "BASE", 12, "", tags = { "type": "Multiplier", "var": "Level" }) + mod2 = Modifier("Health", "BASE", 13, "") + db.addEntry(mod1) + db.addEntry(mod2) + import pprint + pprint.pprint(db.db) + + print("BASE: " + str(db.getBase("Health"))) + +if __name__ == "__main__": + test() diff --git a/src/classes/Modifiers.py b/src/classes/Modifiers.py new file mode 100644 index 0000000..fe10884 --- /dev/null +++ b/src/classes/Modifiers.py @@ -0,0 +1,44 @@ +# + +from Dependency import addDependency, _dependencies +from math import floor + +class Modifier: + def __init__(self, name: str, type: str, value, source: str, conditionals: set = set(), tags: dict = {}): + self.name = name + self.type = type + self.value = value + self.source = source + self.conditionals = conditionals + self.tags = tags + self.process() + + def process(self): + if 'type' in self.tags.keys() and self.tags['type'] == "Multiplier": + addDependency(self.tags['var'].lower(), f"{self.type.lower()}_{self.name.lower()}") + addDependency(f"{self.type.lower()}_{self.name.lower()}", f"max_{self.name.lower()}") + #print(self) + + def getValue(self, caller = None): + if caller: + #print(f"getting var: {self.name}:{self.type}") + if 'type' in self.tags.keys() and self.tags['type'] == "Multiplier": + var = f"{self.tags['var'].lower()}" + l = caller.__getattribute__(var) + #print(f"{var}: {l}") + return floor(self.value * l) + return self.value + return self.value + + def __repr__(self): + ret = f"{self.name}:{self.type}\n" + ret += f"Value: {self.value}\n" + ret += f"{self.tags} -- {self.source}" + return ret + +def test(): + m = Modifier("Health", "BASE", 12, "", tags = { "type": "Multiplier", "var": "Level" }) + print(m) + +if __name__ == "__main__": + test() diff --git a/src/classes/Player.py b/src/classes/Player.py new file mode 100644 index 0000000..cad8f39 --- /dev/null +++ b/src/classes/Player.py @@ -0,0 +1,114 @@ +# + +from functools import cached_property +from math import floor + +from Dependency import Dependency, getDependencies +from ModDB import ModifierDatabase +from Modifiers import Modifier + +class Player(Dependency): + def __init__(self, level, strength): + self.modDB = ModifierDatabase(self) + self._level = level + + self.addMod(Modifier("Health", "BASE", 12, "Base Per Level", tags = { "type": "Multiplier", "var": "Level" })) + self.addMod(Modifier("Health", "BASE", 0.5, "Base Per Strength", tags = { "type": "Multiplier", "var": "Max_Strength"})) + self.addMod(Modifier("Strength", "BASE", strength, "Starting")) + + def addMod(self, mod: Modifier): + self.modDB.addEntry(mod) + attr = f"{mod.type.lower()}_{mod.name.lower()}" + try: + self.__delattr__(f"{attr}") + except: + #print("FAIL") + pass + if attr in getDependencies(): + self._reset_dependent_vars(attr) + + @cached_property + def base_health(self): + #ret = 38 + self.level * 12 + floor(self.max_strength / 2) + self.flat_health + ret = 38 + self.modDB.getBase("Health") + self.flat_health + print(f"BASE Health calculated: {ret}") + return ret + + @cached_property + def max_health(self): + ret = floor(self.base_health * (1 + self.inc_health / 100) * (1 + self.more_health / 100)) + print(f"Total Health calculated: {ret}") + return ret + + @cached_property + def base_strength(self): + ret = self.modDB.getBase("Strength") + print(f"BASE Strength calculated: {ret}") + return ret + + @cached_property + def max_strength(self): + ret = floor((self.base_strength + self.flat_strength) * (1 + self.inc_strength / 100) * (1 + self.more_strength / 100)) + print(f"Total Strength calculated: {ret}") + return ret + + @property + def level(self): + return self._level + + @cached_property + def flat_health(self): + ret = self.modDB.getFlat("Health") + print(f"FLAT Health calculated: {ret}") + return ret + + @cached_property + def more_health(self): + ret = self.modDB.getMore("Health") + print(f"MORE Health calculated: {ret}") + return ret + + @cached_property + def inc_health(self): + ret = self.modDB.getInc("Health") + print(f"INC Health calculated: {ret}") + return ret + + @cached_property + def flat_strength(self): + ret = self.modDB.getFlat("Strength") + print(f"FLAT Strength calculated: {ret}") + return ret + + @cached_property + def more_strength(self): + ret = self.modDB.getMore("Strength") + print(f"MORE Strength calculated: {ret}") + return ret + + @cached_property + def inc_strength(self): + ret = self.modDB.getInc("Strength") + print(f"INC Strength calculated: {ret}") + return ret + +def test(): + player = Player(1, 20) + #print(f"{player.base_health}\n") + print(f"{player.max_health}\n") + + player.level = 5 + print(f"{player.max_health}\n") + + player.addMod(Modifier("Health", "MORE", 100, "")) + print(f"{player.max_health}\n") + + player.addMod(Modifier("Strength", "FLAT", 100, "")) + player.addMod(Modifier("Strength", "INC", 30, "")) + player.addMod(Modifier("Strength", "MORE", 15, "")) + player.addMod(Modifier("Health", "FLAT", 500, "")) + #print(f"{player.max_strength}\n") + print(f"{player.max_health}\n") + +if __name__ == "__main__": + test() diff --git a/src/classes/__init__.py b/src/classes/__init__.py new file mode 100644 index 0000000..e69de29