- def multiple_calls_wrapper(func, count):
- def wrapper(*args, **kwargs):
- for _ in range(count):
- func(*args, **kwargs)
- return wrapper
- custom_round = lambda x: int(x) + 1 if x % 1 > 0.5 else int(x)
- class Potion:
- def __init__(self, effects, duration):
- self.effects = effects
- self.intensities = {effect : 1 for effect in self.effects.keys()}
- self.depleted_effects = set()
- self.is_depleted = False
- self.is_applied = False
- self.duration = duration
- def __getattr__(self, name):
- if self.is_depleted:
- raise TypeError("Potion is now part of something bigger than itself.")
- elif self.is_applied or name in self.effects and name in self.depleted_effects:
- raise TypeError("Effect is depleted.")
- elif name in self.effects and name not in self.depleted_effects:
- self.depleted_effects.add(name)
- self.is_applied = self.depleted_effects == set(self.effects)
- return multiple_calls_wrapper(self.effects[name], self.intensities[name])
- else:
- raise AttributeError(f"Couldn't find {name} attribute")
- def __add__(self, other_potion):
- if self.is_depleted or other_potion.is_depleted:
- raise TypeError("Potion is now part of something bigger than itself.")
- if self.is_applied or other_potion.is_applied:
- raise TypeError("Potion is depleted.")
- self.is_depleted = True
- other_potion.is_depleted = True
- new_duration = max(self.duration, other_potion.duration)
- new_effects = {**self.effects, **other_potion.effects}
- #union of intensities, where intensities are summed for common effects
- new_intensities = {key : self.intensities.get(key) for key in set(self.intensities.keys()) - self.depleted_effects}
- for key in set(other_potion.intensities.keys()) - other_potion.depleted_effects:
- if key in new_intensities:
- new_intensities[key] += other_potion.intensities[key]
- else:
- new_intensities[key] = other_potion.intensities[key]
- result = Potion(new_effects, new_duration)
- result.intensities = new_intensities
- return result
- def __mul__(self, times):
- if self.is_depleted:
- raise TypeError("Potion is now part of something bigger than itself.")
- if self.is_applied:
- raise TypeError("Potion is depleted.")
- self.is_depleted = True
- #dict comprehension with custom rounding criteria
- #(>x.5 is rounded to x + 1; <=x.5 is rounded to x)
- new_intensities = {key: custom_round(times * val)
- for (key, val) in self.intensities.items()}
- result = Potion(self.effects, self.duration)
- result.intensities = new_intensities
- result.depleted_effects = self.depleted_effects
- return result
- def __rmul__(self, times):
- return self.__mul__(times)
- def __imul__(self, times):
- self = self.__mul__(times)
- return self
- def __sub__(self, other_potion):
- if self.is_depleted or other_potion.is_depleted:
- raise TypeError("Potion is now part of something bigger than itself.")
- if self.is_applied or other_potion.is_applied:
- raise TypeError("Potion is depleted.")
- self.is_depleted = True
- other_potion.is_depleted = True
- if not (set(other_potion.effects.keys()) <= set(self.effects.keys())):
- raise TypeError("Invalid subtract")
- new_intensities = self.intensities
- for effect in other_potion.intensities:
- new_intensities[effect] -= other_potion.intensities[effect]
- if new_intensities[effect] < 0:
- del new_intensities[effect]
- new_effects = {key : val for (key, val) in self.effects.items() if key in new_intensities}
- result = Potion(new_effects, self.duration)
- result.intensities = new_intensities
- result.depleted_effects = self.depleted_effects & set(new_effects.keys())
- return result
- def __truediv__(self, times):
- if self.is_depleted:
- raise TypeError("Potion is now part of something bigger than itself.")
- if self.is_applied:
- raise TypeError("Potion is depleted.")
- self.is_depleted = True
- new_intensities = {key : custom_round(val / times) for (key, val) in self.intensities.items()}
- result = Potion(self.effects, self.duration)
- result.intensities = new_intensities
- return tuple([result for _ in range(times)])
- def __eq__(self, other_potion):
- first_effects = set(self.intensities) - set(self.depleted_effects)
- sec - set(other_potion.depleted_effects)
- if first_effects != second_effects:
- return False
- for effect in first_effects:
- if other_potion.intensities[effect] != self.intensities[effect]:
- return False
- return True
- def __gt__(self, other_potion):
- first_sum = sum([self.intensities[effect] for effect in self.effects if effect not in self.depleted_effects])
- sec for effect in other_potion.effects
- if effect not in other_potion.depleted_effects])
- return first_sum > second_sum
- class ГоспожатаПоХимия:
- def __init__(self):
- pass
- #history = {}
- def apply(self, target, potion):
- if potion.is_applied:
- raise TypeError("Potion is depleted.")
- if potion.is_depleted:
- raise TypeError("Potion is now part of something bigger than itself.")
- # if not target in self.history.keys():
- # self.history[target] = [target.__dict__.copy()]
- #self.history[target].extend([potion.__dict__.copy(), potion.duration])
- inorder_effects = [effect for effect in potion.effects.keys() if not effect in potion.depleted_effects]
- inorder_effects.sort(key = lambda x : sum([ord(ch) for ch in x]), reverse = True)
- for effect in inorder_effects:
- potion.__getattr__(effect)(target)
- potion.is_applied = True
- def tick(self):
- pass
- #for key, val in self.history.items():
- #testing:
- class Target:
- def __init__(self):
- self.size = 5
- target = Target()
- effects = {'grow': lambda target: setattr(target, 'size', target.size*2)}
- grow_potion=Potion(effects,duration=2)
- def elemental_dmg_immunity(target):
- target.fire_dmg_resistance = 1.0 # Percentage value between 0 and 1
- target.water_dmg_resistance = 1.0
- target.earth_dmg_resistance = 1.0
- target.air_dmg_resistance = 1.0
- def physical_dmg_immunity(target):
- target.bludgeoning_dmg_resistance = 1.0
- target.slashing_dmg_resistance = 1.0
- target.piercing_dmg_resistance = 1.0
- immunity_potion = Potion({'make_elemental_immune': elemental_dmg_immunity,
- 'make_physical_immune': physical_dmg_immunity},
- duration=1)
- dimitrichka = ГоспожатаПоХимия()
- # grow_potion и immunity_potion са отварите от горния пример
- grow_and_immunity_potion = grow_potion + immunity_potion
- # target.size = 5
- print(target.__dict__)
- print('----------------------------')
- dimitrichka.apply(target, grow_and_immunity_potion)
- print(target.__dict__)
- # target.size = 10
- # target.*_resistance = 1.0 (* за да не ги изброяваме)