/python/gamestate/units.py

https://github.com/cpius/rosewarsgame · Python · 264 lines · 172 code · 50 blank · 42 comment · 54 complexity · e33615ebbe0ddb86672ab1f9a7839f7a MD5 · raw file

  1. from gamestate.gamestate_library import *
  2. from game.game_library import *
  3. from gamestate.enums import *
  4. from game.settings import beginner_mode
  5. class UnitClass():
  6. def __init__(self):
  7. self.attributes = {}
  8. unit = None
  9. type = None
  10. experience_to_upgrade = 0
  11. base_attack = 0
  12. base_defence = 0
  13. base_range = 0
  14. base_movement = 0
  15. upgrades = {}
  16. @property
  17. def attack(self):
  18. return self.base_attack + self.get(Trait.attack_skill)
  19. @property
  20. def defence(self):
  21. return self.base_defence + self.get(Trait.defence_skill)
  22. @property
  23. def range(self):
  24. return self.base_range + self.get(Trait.range_skill)
  25. @property
  26. def movement(self):
  27. return self.base_movement + self.get(Trait.movement_skill)
  28. def __repr__(self):
  29. return self.unit.name
  30. def __eq__(self, other):
  31. return self.to_document() == other.to_document()
  32. def __ne__(self, other):
  33. return not self.__eq__(other)
  34. @property
  35. def name(self):
  36. return self.unit.name
  37. @property
  38. def pretty_name(self):
  39. return prettify(self.unit.name)
  40. @property
  41. def states(self):
  42. return [attribute for attribute in self.attributes if attribute in State]
  43. @property
  44. def effects(self):
  45. return [attribute for attribute in self.attributes if attribute in Effect]
  46. @property
  47. def abilities(self):
  48. return [attribute for attribute in self.attributes if attribute in Ability]
  49. def set(self, attribute, value=1, duration=None, level=1):
  50. """
  51. :param attribute: A state or effect.
  52. :param value: A value for states. Default 1.
  53. :param duration: A duration for effects.
  54. :param level: A level for effects. Default 1.
  55. """
  56. if attribute in State:
  57. self.attributes[attribute] = AttributeValues(value=value)
  58. elif attribute in Effect:
  59. self.attributes[attribute] = AttributeValues(duration=duration, level=level)
  60. def decrease(self, attribute):
  61. """
  62. :param attribute: A state or effect.
  63. :return: If the attribute is a state, decrease the value by 1. If the attribute is an effect, decrease the
  64. duration by 1. If the value or duration is set to 0, remove the attribute.
  65. """
  66. if attribute in self.states:
  67. self.attributes[attribute].value -= 1
  68. if self.get(attribute) == 0:
  69. self.remove(attribute)
  70. if attribute in self.effects:
  71. self.attributes[attribute].duration -= 1
  72. if self.attributes[attribute].duration == 0:
  73. self.remove(attribute)
  74. def has(self, attribute, number=None):
  75. """
  76. :param attribute: An attribute
  77. :param number: A level or value depending on the attribute type
  78. :return: If a number is not given, returns whether the unit has the attribute.
  79. If a number is given, returns whether the unit has the attribute at that specific level / value.
  80. """
  81. if attribute not in self.attributes:
  82. return False
  83. elif number is None:
  84. return True
  85. if attribute in State:
  86. return self.attributes[attribute].value == number
  87. else:
  88. return self.attributes[attribute].level == number
  89. def get(self, attribute):
  90. """
  91. :param attribute: An attribute
  92. :return: If the attribute is a state, returns the state value. Otherwise returns the state level.
  93. """
  94. if attribute in State:
  95. return self.attributes[attribute].value if attribute in self.attributes else 0
  96. else:
  97. return self.attributes[attribute].level if attribute in self.attributes else 0
  98. def remove(self, attribute):
  99. if attribute in self.attributes:
  100. del self.attributes[attribute]
  101. def increase(self, attribute, n=1):
  102. """
  103. :param attribute: An attribute
  104. :return: If the attribute is a state, increase the value by n. Otherwise increase the level by n.
  105. """
  106. if attribute in State:
  107. if self.has(attribute):
  108. self.attributes[attribute].value += n
  109. else:
  110. self.attributes[attribute] = AttributeValues(value=n)
  111. else:
  112. if self.has(attribute):
  113. self.attributes[attribute].level += n
  114. else:
  115. self.attributes[attribute] = AttributeValues(level=n)
  116. def gain_experience(self):
  117. if not self.has(State.used) and not beginner_mode:
  118. self.increase(State.experience)
  119. @property
  120. def has_extra_life(self):
  121. return self.has(Trait.extra_life) and not self.has(State.lost_extra_life)
  122. @property
  123. def has_javelin(self):
  124. return self.has(Trait.javelin) and not self.has(State.javelin_thrown)
  125. @property
  126. def is_melee(self):
  127. return self.range == 1
  128. @property
  129. def is_ranged(self):
  130. return self.range > 1
  131. def get_upgraded_unit_from_upgrade(self, upgrade):
  132. """
  133. :param upgrade: A unit enum or a dictionary with enums as keys and AttributeValues as values.
  134. :return: A new UnitClass object, based on the unit and with the upgrade.
  135. """
  136. if upgrade in Unit:
  137. upgraded_unit = base_units[upgrade]()
  138. for attribute in self.states + self.effects:
  139. upgraded_unit.attributes[attribute] = self.attributes[attribute]
  140. upgraded_unit.remove(State.experience)
  141. else:
  142. upgraded_unit = base_units[self.unit]()
  143. upgraded_unit.attributes = dict(self.attributes)
  144. upgraded_unit.increase(State.rank, 1)
  145. upgraded_unit.remove(State.experience)
  146. for attribute, attribute_values in upgrade.items():
  147. upgraded_unit.increase(attribute, attribute_values.level)
  148. return upgraded_unit
  149. def get_upgraded_unit_from_choice(self, choice):
  150. """
  151. :param choice: upgrade choice 0 or 1.
  152. :return: A new UnitClass object, based on the unit and with the upgrade.
  153. """
  154. upgrade = self.get_upgrade_choices()[choice]
  155. return self.get_upgraded_unit_from_upgrade(upgrade)
  156. def get_upgrade_choices(self):
  157. """
  158. :param choice: upgrade choice 0 or 1.
  159. :return: The chosen unit upgrade in enum upgrade format. (Dictionary with enums as keys and AttributeValues as
  160. values.)
  161. """
  162. if version == 1.0:
  163. return [{Trait.attack_skill: AttributeValues(level=1)}, {Trait.defence_skill: AttributeValues(level=1)}]
  164. def has_upgrade(check_upgrade):
  165. if check_upgrade in Unit:
  166. return False
  167. for attribute, attribute_values in check_upgrade.items():
  168. level = attribute_values.level
  169. return self.has(attribute, level) and not base_units[self.unit]().has(attribute, level)
  170. possible_upgrade_choices = []
  171. for upgrade_category in ["once_1", "once_2", "unit_1", "unit_2", "repeat_1", "repeat_2"]:
  172. if upgrade_category in self.upgrades:
  173. upgrade = get_enum_attributes(self.upgrades[upgrade_category])
  174. if not (upgrade_category in ["once_1", "once_2"] and has_upgrade(upgrade)):
  175. possible_upgrade_choices.append(upgrade)
  176. return possible_upgrade_choices
  177. def should_be_upgraded(self):
  178. return self.has(State.experience) and self.get(State.experience) % self.experience_to_upgrade == 0
  179. def to_document(self):
  180. write_attributes = {attribute: attribute_values for attribute, attribute_values in self.attributes.items() if
  181. not base_units[self.unit]().has(attribute)}
  182. if write_attributes:
  183. unit_dict = get_string_attributes(write_attributes)
  184. unit_dict["name"] = self.name
  185. return unit_dict
  186. else:
  187. return self.name
  188. attributes_units = {}
  189. def make_unit_subclasses_from_document(document):
  190. """
  191. :param document: A document containing the specifications for units.
  192. :return: A dictionary of unit objects.
  193. """
  194. unit_class_dictionary = {}
  195. for name, unit_class_content in document.items():
  196. unit_class_content["unit"] = Unit[name]
  197. for key, value in unit_class_content.items():
  198. if key in ["attack", "defence", "movement", "range"]:
  199. unit_class_content["base_" + key] = value
  200. del unit_class_content[key]
  201. attributes_units[name] = {get_enum_attributes(key): value for key, value in unit_class_content["attributes"].items()}
  202. def init(self):
  203. super(type(self), self).__init__()
  204. for attribute, level in attributes_units[self.name].items():
  205. self.attributes[attribute] = AttributeValues(level=level)
  206. del unit_class_content["attributes"]
  207. unit_class_content["__init__"] = init
  208. unit_class_content["type"] = Type[unit_class_content["type"]]
  209. unit_class_content["name"] = name
  210. unit_class = type(name, (UnitClass,), unit_class_content)
  211. unit_class_dictionary[Unit[name]] = unit_class
  212. return unit_class_dictionary
  213. unit_document = read_json("./../Version_1.1/Units.json")
  214. base_units = make_unit_subclasses_from_document(unit_document)