purchase.py (4923B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\characterskills\purchase.py 2 import abc 3 4 def purchase_skills(context, skill_type_ids): 5 skill_type_ids = list(skill_type_ids) 6 context.validate(skill_type_ids) 7 skills_to_inject = [] 8 try: 9 for skill_type_id in skill_type_ids: 10 context.pay_for_skill(skill_type_id) 11 skills_to_inject.append(skill_type_id) 12 13 finally: 14 if skills_to_inject: 15 context.inject_skills(skills_to_inject) 16 17 return skills_to_inject 18 19 20 class SkillPurchaseContext(object): 21 __metaclass__ = abc.ABCMeta 22 23 @abc.abstractmethod 24 def get_validator(self): 25 pass 26 27 @abc.abstractmethod 28 def inject_skills(self, skill_type_ids): 29 pass 30 31 @abc.abstractmethod 32 def pay_for_skill(self, skill_type_id): 33 pass 34 35 def validate(self, skill_type_ids): 36 validator = self.get_validator() 37 validator.validate(skill_type_ids) 38 39 40 class SkillPurchaseValidator(object): 41 __metaclass__ = abc.ABCMeta 42 43 @abc.abstractmethod 44 def get_account_balance(self): 45 pass 46 47 @abc.abstractmethod 48 def get_skill_price(self, skill_type_id): 49 pass 50 51 @abc.abstractmethod 52 def is_skill(self, type_id): 53 pass 54 55 @abc.abstractmethod 56 def is_skill_available_for_purchase(self, skill_type_id): 57 pass 58 59 @abc.abstractmethod 60 def is_skill_injected(self, skill_type_id): 61 pass 62 63 def validate(self, skill_type_ids): 64 self._check_no_duplicate_skills(skill_type_ids) 65 self._check_all_type_ids_are_skills(skill_type_ids) 66 self._check_all_skills_available_for_purchase(skill_type_ids) 67 self._check_no_skills_already_injected(skill_type_ids) 68 self._check_balance_can_cover_purchase_cost(skill_type_ids) 69 70 def _check_no_duplicate_skills(self, skill_type_ids): 71 duplicates = find_duplicates(skill_type_ids) 72 if duplicates: 73 raise DuplicateSkillValueError(duplicates) 74 75 def _check_all_type_ids_are_skills(self, type_ids): 76 for type_id in type_ids: 77 if not self.is_skill(type_id): 78 raise TypeIsNotSkillError(type_id) 79 80 def _check_no_skills_already_injected(self, skill_type_ids): 81 for skill_type_id in skill_type_ids: 82 if self.is_skill_injected(skill_type_id): 83 raise SkillAlreadyInjectedError(skill_type_id) 84 85 def _check_all_skills_available_for_purchase(self, skill_type_ids): 86 for skill_type_id in skill_type_ids: 87 if not self.is_skill_available_for_purchase(skill_type_id): 88 raise SkillUnavailableForPurchaseError(skill_type_id) 89 90 def _check_balance_can_cover_purchase_cost(self, skill_type_ids): 91 total_cost = sum(map(self.get_skill_price, skill_type_ids)) 92 balance = self.get_account_balance() 93 if total_cost > balance: 94 raise NotEnoughMoneyError(total_cost, balance) 95 96 97 def find_duplicates(seq): 98 seen = set() 99 duplicates = set() 100 for item in seq: 101 if item in seen: 102 duplicates.add(item) 103 else: 104 seen.add(item) 105 106 return duplicates 107 108 109 class SkillPurchaseError(Exception): 110 pass 111 112 113 class SkillAlreadyInjectedError(SkillPurchaseError): 114 MESSAGE_TEMPLATE = 'The skill (type ID {}) is already injected' 115 116 def __init__(self, type_id): 117 message = self.MESSAGE_TEMPLATE.format(type_id) 118 super(SkillAlreadyInjectedError, self).__init__(message) 119 self.type_id = type_id 120 121 122 class SkillUnavailableForPurchaseError(SkillPurchaseError): 123 MESSAGE_TEMPLATE = 'The skill (type ID {}) is not available for purchase' 124 125 def __init__(self, type_id): 126 message = self.MESSAGE_TEMPLATE.format(type_id) 127 super(SkillUnavailableForPurchaseError, self).__init__(message) 128 self.type_id = type_id 129 130 131 class TypeIsNotSkillError(SkillPurchaseError): 132 MESSAGE_TEMPLATE = 'Type ID {} is not a skill' 133 134 def __init__(self, type_id): 135 message = self.MESSAGE_TEMPLATE.format(type_id) 136 super(TypeIsNotSkillError, self).__init__(message) 137 self.type_id = type_id 138 139 140 class NotEnoughMoneyError(SkillPurchaseError): 141 MESSAGE_TEMPLATE = 'You need {} to complete this purchase but only have {}' 142 143 def __init__(self, required_amount, current_balance): 144 message = self.MESSAGE_TEMPLATE.format(required_amount, current_balance) 145 super(NotEnoughMoneyError, self).__init__(message) 146 self.required_amount = required_amount 147 self.current_balance = current_balance 148 149 150 class DuplicateSkillValueError(SkillPurchaseError): 151 MESSAGE_TEMPLATE = 'The following skill type IDs occurr more than once in the input: {}' 152 153 def __init__(self, type_ids): 154 message = self.MESSAGE_TEMPLATE.format(', '.join(map(str, type_ids))) 155 super(DuplicateSkillValueError, self).__init__(message) 156 self.type_ids = type_ids