def __init__(self, sound_mixer): self.animation_loader_logger = LoggerMaster( self.__class__.__name__, LoggingLevelType.DEBUG.value) self.sound_mixer = sound_mixer self.sounds = dict() self.load_sound_sets()
class GameEngine: def __init__(self): self.run_game = True self.run_stage = True self.game_engine_logger = LoggerMaster(self.__class__.__name__, file_streamer=False, console_streamer=True) self.game_engine_logger.log_info_header( f'[ Starting {self.__class__.__name__} ]:') # Initializing Game Attributes, Sound Master, Animation Master self.game_attributes = GameAttributes() self.sound_master = SoundMaster() self.animation_master = AnimationMaster(self.game_attributes.surface) # Initializing Stage Initializer: This should call Stage Selector in the near future self.stage_initializer = StageInitializer(self.game_attributes, self.animation_master, self.sound_master) def run(self): while constants.globals.run_game: self.game_attributes.surface.fill(Color('Black')) self.stage_initializer.run_stage() event_controller.manage_events() display.update() quit()
def __init__(self): self.animation_loader_logger = LoggerMaster( self.__class__.__name__, LoggingLevelType.DEBUG.value) self.environment_animation_sets = [] self.unit_animation_sets = self.load_resource_sets( UNIT_ANIMATION_SETS, AnimationResourceType.UNITS.value) self.skill_animation_sets = self.load_resource_sets( SKILL_ANIMATION_SETS, AnimationResourceType.SKILLS.value)
def __init__(self, player): self.experience_master_logger = LoggerMaster( 'ExperienceMaster', LoggingLevelType.DEBUG.value) self.player = player self.experience = 0 self.exp_level_break = 5 self.experience_to_gain = 0 self.previous_exp = 0
def __init__(self): self.run_game = True self.run_stage = True self.game_engine_logger = LoggerMaster(self.__class__.__name__, file_streamer=False, console_streamer=True) self.game_engine_logger.log_info_header( f'[ Starting {self.__class__.__name__} ]:') # Initializing Game Attributes, Sound Master, Animation Master self.game_attributes = GameAttributes() self.sound_master = SoundMaster() self.animation_master = AnimationMaster(self.game_attributes.surface) # Initializing Stage Initializer: This should call Stage Selector in the near future self.stage_initializer = StageInitializer(self.game_attributes, self.animation_master, self.sound_master)
class StageTreeBuilder: def __init__(self): self.stage_tree_logger = LoggerMaster(__class__.__name__, level=LoggingLevelType.DEBUG.value) def roll_leaf_level_properties(self, stage_tree): pass def roll_node_level_properties(self, stage_tree, node_lvl): pass def build_tree(self, max_number_of_children): stage_tree = StageTree() self.stage_tree_logger.log_debug_header(f'[ {self.__class__.__name__} ]:' f' Building {stage_tree.__class__.__name__}') self.stage_tree_logger.log_debug_message() stage_root_node = stage_tree.add_node(root=True) self.build_branch(stage_tree, stage_root_node, max_number_of_children) return stage_tree def build_branch(self, stage_tree, parent_stage_node, max_number_of_children, diminishing=0): diminishing_list = [95, 75, 60, 20, 0] for child in range(0, max_number_of_children, 1): branch_chance = randint(1, 99) < diminishing_list[diminishing] if branch_chance: current_stage_node = stage_tree.add_node(parent_stage_node.node_lvl + 1, parent_stage_node.node_identifier) stage_tree.set_max_node_level(parent_stage_node.node_lvl + 1) self.stage_tree_logger.log_debug_message(f'[ {self.__class__.__name__} ]:' f' Generate {current_stage_node.__class__.__name__}' f' Parent Stage Level {parent_stage_node.node_lvl}' f' Child Number {child}' f' with {diminishing_list[diminishing]} diminishing' f' CREATED') parent_stage_node.add_children(current_stage_node) self.build_branch(stage_tree, current_stage_node, max_number_of_children, diminishing + 1) else: self.stage_tree_logger.log_debug_message(f'[ {self.__class__.__name__} ]:' f' Generate StageNode Parent Stage Level' f' Parent Stage Level {parent_stage_node.node_lvl}' f' Child Number {child}' f' with {diminishing_list[diminishing]} diminishing' f' FAILED') def build_node_properties(self): pass
class ExperienceMaster: def __init__(self, player): self.experience_master_logger = LoggerMaster( 'ExperienceMaster', LoggingLevelType.DEBUG.value) self.player = player self.experience = 0 self.exp_level_break = 5 self.experience_to_gain = 0 self.previous_exp = 0 def next_experience_level_break(self): self.exp_level_break = round(self.exp_level_break * 1.3) self.experience_master_logger.log_debug_message( f'Next Level Break will be {self.exp_level_break}') def has_enough_experience(self): return self.experience >= self.exp_level_break def gain_experience(self): self.experience += self.experience_to_gain self.experience_to_gain = 0 if self.has_enough_experience(): self.experience_master_logger.log_debug_message( f'Player Has Enough Experience to Level Up') self.level_up() self.experience_master_logger.log_debug_message( f'Player Has {self.experience} Left') self.gain_experience() def level_up(self): strength_raise = randint(2, 3) dexterity_raise = randint(1, 2) magic_raise = randint(1, 3) vitality_raise = randint(2, 4) resilience_raise = randint(1, 2) luck_raise = randint(1, 2) self.level_up_stats(strength_raise, dexterity_raise, magic_raise, vitality_raise, resilience_raise, luck_raise) self.previous_exp = self.experience self.experience = self.previous_exp - self.exp_level_break self.next_experience_level_break() self.player.level += 1 def level_up_stats(self, strength_raise, dexterity_raise, magic_raise, vitality_raise, resilience_raise, luck_raise): self.player.strength += strength_raise self.player.dexterity += dexterity_raise self.player.magic += magic_raise self.player.vitality += vitality_raise self.player.resilience += resilience_raise self.player.luck += luck_raise # This will be used when changing equipment to recover the raw value for the hero. self.player.raw_strength += strength_raise self.player.raw_dexterity += dexterity_raise self.player.raw_magic += magic_raise self.player.raw_vitality += vitality_raise self.player.raw_resilience += resilience_raise self.player.raw_luck += luck_raise self.player.attack_power = self.player.strength * 1 self.player.attack_rating = self.player.dexterity * 1 self.player.magic_power = self.player.magic * 1 # calculate max hp and max mp self.player.max_hp = self.player.vitality * 3 self.player.current_hp = self.player.current_hp + vitality_raise * 3 self.player.max_mp = self.player.magic * 2 + self.player.resilience self.player.current_mp = self.player.current_mp + magic_raise * 2 + resilience_raise self.player.re_calculate_hero_stats() def evaluate_kill(self, target, text_sprite): if not target.alive: self.experience_to_gain += target.level damage_text.cast(self.player, "+EXP!", text_sprite) self.experience_master_logger.log_debug_message( f'Player Kills {target.__class__.__name__} ' f'and Gains +{target.level} XP') def evaluate_group_kill(self, target_list, pre_target_list, post_target_list, text_sprite): for index, target_unit in enumerate(post_target_list): if pre_target_list[index] is True and post_target_list[ index] is False: self.experience_to_gain += target_list[index].level self.experience_master_logger.log_debug_message( f'Player Kills {target_list[index].__class__.__name__} ' f'and Gains +{target_list[index].level} XP') damage_text.cast(self.player, "+EXP!", text_sprite)
def __init__(self): self.stage_tree_logger = LoggerMaster(__class__.__name__, level=LoggingLevelType.DEBUG.value)
class AnimationLoader: def __init__(self): self.animation_loader_logger = LoggerMaster( self.__class__.__name__, LoggingLevelType.DEBUG.value) self.environment_animation_sets = [] self.unit_animation_sets = self.load_resource_sets( UNIT_ANIMATION_SETS, AnimationResourceType.UNITS.value) self.skill_animation_sets = self.load_resource_sets( SKILL_ANIMATION_SETS, AnimationResourceType.SKILLS.value) def get_skill_resource_animation_set(self, resource_type): return self.skill_animation_sets[resource_type] def get_unit_resource_animation_set(self, resource_type): return self.unit_animation_sets[resource_type] @staticmethod def generate_animation_callback(index): return lambda animation_set: (animation_set.set_action(index), animation_set.reset_frame_index()) def load_resource_sets(self, animation_pool, resource_type): self.animation_loader_logger.log_debug_header( f'[ Loading {resource_type.title()} Animation Resources ]:') animation_sets = dict() # For Each AnimationSet present in AnimationSets: Environment, Skills, Units for animation_set_type in animation_pool: animation_set = [] animation_set_callbacks = dict() # Load Each Animation Resource present in the Animation to be displayed self.animation_loader_logger.log_debug_message() self.animation_loader_logger.log_debug_message( f'Animation Resource Type: {animation_set_type.value}') self.animation_loader_logger.log_debug_message('------' * 10) for index, animation_resource in enumerate( animation_pool[animation_set_type]): animation_set_callbacks[ animation_resource.animation_type. value] = self.generate_animation_callback(index) # Load: Sequence Animations using Path to Resources self.animation_loader_logger.log_debug_message( f'Animation Resource: {animation_resource.animation_type.value}' ) animation_set.append( self.load_resource_sequence( resource_type, animation_set_type.value, animation_resource.animation_type, animation_resource.frames, animation_resource.scale_x, animation_resource.scale_y)) animation_sets[animation_set_type.value + 'CallBacks'] = animation_set_callbacks animation_sets[animation_set_type.value] = animation_set self.animation_loader_logger.log_debug_message() self.animation_loader_logger.log_debug_message('Done.') return animation_sets def load_resource_sequence(self, resource_type, name, animation, sequence_length, x_scale, y_scale): # Load: Unit Animation Sequence based on Resource Type animation_sequence = [] for index in range(sequence_length): animation_sequence.append( self.load_resource(resource_type, name, animation.value, index, x_scale, y_scale)) return animation_sequence def load_resource(self, resource_type, unit_type, value, index, x_scale, y_scale): image_path = f"resources/animation/{resource_type}/{unit_type.lower()}/sprites/{value}/{index}.png" self.animation_loader_logger.log_debug_message('> ' + image_path) loaded_image = image.load(image_path) normalized_image = transform.scale( loaded_image, (round(loaded_image.get_width() * x_scale), round(loaded_image.get_height() * y_scale))) return normalized_image
def __init__(self, sound_master): self.combat_resolver_logger = LoggerMaster( 'CombatResolver', LoggingLevelType.DEBUG.value) self.sound_master = sound_master
class CombatResolver: def __init__(self, sound_master): self.combat_resolver_logger = LoggerMaster( 'CombatResolver', LoggingLevelType.DEBUG.value) self.sound_master = sound_master def resolve_attack(self, caster, target, input_damage, input_type, text_sprite, multi_strike=False): if not multi_strike: constants.globals.action_cooldown = 0 self.combat_resolver_logger.log_debug_message( f'Caster {caster.__class__.__name__} performs Attack, ' f'Target {target.__class__.__name__} ' f'receives {input_type.value.title()} ' f'for {input_damage}') # Activates Block Animation & Sound on the current Target if input_type is CombatTypeResolution.BLOCKED: target.use_animation('Block') self.sound_master.play_unit_fx_sound('block') # Activates Miss Animation & Sound on the current Target elif input_type is CombatTypeResolution.MISS: target.use_animation('Miss') self.sound_master.play_unit_fx_sound('miss') # Activates Hurt/Death Animation and Sound on the current Target else: if input_damage != 0: target.use_animation('Hurt') # Activates Critical Hit Sound if input_type is CombatTypeResolution.CRITICAL_HIT: self.sound_master.play_unit_fx_sound('critical_hit') else: self.sound_master.play_unit_fx_sound('hit_cut') # Updates current Target Health target.reduce_health(input_damage) if target.has_fury(): # Updates current Target Fury, Saves Previous for Sound Effect Condition previous_fury = target.current_fury target.gain_fury(input_damage) # Only Play Sound of Ultimate Up if player reaches 50 if previous_fury < 50 and target.current_fury >= 50: self.sound_master.play_unit_fx_sound('ultimate_up') elif previous_fury < target.max_fury and target.current_fury == target.max_fury: self.sound_master.play_unit_fx_sound('ultimate_up') # TODO Activates hurt sound # Evaluate Death: Target if target.is_dead(): self.combat_resolver_logger.log_debug_message( f'Target {target.__class__.__name__} Dies') target.death() target.use_animation('Death') constants.globals.clicked = False if caster.has_experience(): caster.evaluate_kill(target, text_sprite) combat_text_resolver.resolve(target, input_damage, input_type, text_sprite) def resolve_aoe_attack(self, caster, target_list, input_damage_list, input_damage_type_list, text_sprite): for index, target in enumerate(target_list): if target.alive: self.resolve_attack(caster, target, input_damage_list[index], input_damage_type_list[index], text_sprite, True) def resolve_multi_attack(self, caster, target_list, multi_strike, text_sprite): alive_enemy = get_alive_targets(target_list) # TODO: pass de proper wait time instead of 90 if self.multi_attacks_left >= 0: if constants.globals.action_cooldown >= 90: if len(alive_enemy) > 0: target = alive_enemy[randint(0, len(alive_enemy) - 1)] caster.use_animation('Attack') caster.cast_attack(self, target, text_sprite, True) self.multi_attacks_left -= 1 constants.globals.action_cooldown = 65 else: self.multi_attacks_left = 7 caster.ultimate_status = False # Action Delay: Next Enemy Action will be delayed after the ultimate cast constants.globals.action_cooldown = -40 def resolve_fixed_damage_attack(self, target, input_damage, input_type, text_sprite): target.use_animation('Hurt') self.sound_master.play_unit_fx_sound('hit_cut') target.reduce_health(input_damage) if target.has_fury(): target.gain_fury(input_damage) if target.has_enough_fury(50) or target.has_enough_fury(): self.sound_master.play_unit_fx_sound('ultimate_up') if target.is_dead(): target.death() target.use_animation('Death') constants.globals.clicked = False combat_text_resolver.resolve(target, input_damage, input_type, text_sprite)
class SoundLoader: def __init__(self, sound_mixer): self.animation_loader_logger = LoggerMaster( self.__class__.__name__, LoggingLevelType.DEBUG.value) self.sound_mixer = sound_mixer self.sounds = dict() self.load_sound_sets() def load_sound_sets(self): self.animation_loader_logger.log_debug_header( '[ Loading Sound Resources ]:') sound_type = dict() # For Each AnimationSet present in AnimationSets: Environment, Skills, Units for sound_resource_type in SOUND_POOL: sound_subtype = dict() self.animation_loader_logger.log_debug_message() self.animation_loader_logger.log_debug_message( f'Sound Type: {sound_resource_type.value}') self.animation_loader_logger.log_debug_message('------' * 10) for index, sound_set in enumerate(SOUND_POOL[sound_resource_type]): sound_resource = dict() self.animation_loader_logger.log_debug_message( f'Sound Sub Type: {sound_set.value}') for sound in SOUND_POOL[sound_resource_type][sound_set]: sound_resource[sound.sound_name] = self.load_resource( sound_resource_type.value, sound_set.value, sound.sound_name, sound.file_extension, sound.volume) sound_subtype[sound_set.value.lower()] = sound_resource sound_type[sound_resource_type.value.lower()] = sound_subtype self.animation_loader_logger.log_debug_message() self.animation_loader_logger.log_debug_message('Done') self.sounds = sound_type def load_resource(self, resource_type, sound_set, sound_name, sound_file_extension, sound_volume): sound_path = f'resources/sound/{resource_type.lower()}/{sound_set.lower()}/{sound_name.lower()}.{sound_file_extension.value}' self.animation_loader_logger.log_debug_message('> ' + sound_path) sound_resource = WrappedSound(sound_path) sound_resource.set_volume(sound_volume) return sound_resource
def __init__(self, sound_master): self.loot_master_logger = LoggerMaster(self.__class__.__name__, LoggingLevelType.DEBUG.value) self.sound_master = sound_master
class LootMaster: def __init__(self, sound_master): self.loot_master_logger = LoggerMaster(self.__class__.__name__, LoggingLevelType.DEBUG.value) self.sound_master = sound_master def loot(self, caster, target, text_sprite): if type(target) is Bandit or type(target) is BoneWizard or type( target) is Lizard: self.roll_basic_loot(caster, target, text_sprite) elif type(target) is BanditChief or type(target) is SmallDragon \ or type(target) is Djinn or type(target) is Dragon \ or type(target) is Demon or type(target) is Medusa: self.roll_boss_loot(caster, target, text_sprite) def roll_basic_loot(self, caster, target, text_sprite): loot_chance = randint(0, 5) if not target.is_looted(): if loot_chance == 0: self.sound_master.play_item_fx_sound('empty') damage_text.warning(target, f'Empty!', text_sprite) self.loot_master_logger.log_debug_message( f'Player Loots {target.__class__.__name__} ' f'Receiving Nothing') elif loot_chance == 1: self.sound_master.play_item_fx_sound('health_potion') caster.stash.add_healing_potion(1) damage_text.warning(target, f'x1 Health Potion Found!', text_sprite) self.loot_master_logger.log_debug_message( f'Player Loots {target.__class__.__name__} ' f'Receiving Health Potion') elif loot_chance == 2: self.sound_master.play_item_fx_sound('health_potion') caster.stash.add_mana_potion(1) damage_text.warning(target, f'x1 Mana Potion Found!', text_sprite) self.loot_master_logger.log_debug_message( f'Player Loots {target.__class__.__name__} ' f'Receiving Mana Potion') elif loot_chance == 3: quality_roll = randint(0, 50) if quality_roll > target.level: damage_text.warning(target, f'Food Found!', text_sprite) BREAD.consume(caster, text_sprite) self.sound_master.play_item_fx_sound('eat') self.loot_master_logger.log_debug_message( f'Player Loots {target.__class__.__name__} ' f'Receiving Bread') else: damage_text.warning(target, f'Large Food Found!', text_sprite) LARGE_BREAD.consume(caster, text_sprite) self.sound_master.play_item_fx_sound('eat') self.loot_master_logger.log_debug_message( f'Player Loots {target.__class__.__name__} ' f'Receiving Large Bread') elif loot_chance == 4: quality_roll = randint(0, 50) if quality_roll > target.level: damage_text.warning(target, f'Drink Found!', text_sprite) DRINK.consume(caster, text_sprite) self.sound_master.play_item_fx_sound('drink') self.sound_master.play_item_fx_sound('eat') self.loot_master_logger.log_debug_message( f'Player Loots {target.__class__.__name__}' f' Receiving Drink') else: damage_text.warning(target, f'Large Drink Found!', text_sprite) LARGE_DRINK.consume(caster, text_sprite) self.sound_master.play_item_fx_sound('drink') self.loot_master_logger.log_debug_message( f'Player Loots {target.__class__.__name__}' f' Receiving Large Drink') elif loot_chance == 5: gold = randint(1, 9) + target.level caster.stash.add_gold(gold) damage_text.cast(target, f'{gold} Gold Found!', text_sprite) self.sound_master.play_item_fx_sound('gold') self.loot_master_logger.log_debug_message( f'Player Loots {target.__class__.__name__}' f' Receiving {gold} Gold') target.update_looted_status() else: self.loot_error(target, text_sprite) def roll_boss_loot(self, caster, target, text_sprite): item_generator = EquipmentGenerator() if not target.is_looted(): self.sound_master.play_item_fx_sound('drum_roll') # Todo: Proper setup for loot boss, based on level roll_item = item_generator.get_item(30, 1000) item_name = roll_item.get_item_name() damage_text.heal(target, f'{item_name}', text_sprite) self.loot_master_logger.log_debug_message( f'Player Loots {target.__class__.__name__}' f' Receiving {item_name.title()}') target.update_looted_status() # Note: Temporary Approach caster.backpack.add_item(roll_item) else: self.loot_error(target, text_sprite) caster.re_calculate_hero_stats() def loot_error(self, target, text_sprite): # Todo: Init with -30y damage_text.warning(target, f'ALREADY LOOTED!', text_sprite) self.sound_master.play_item_fx_sound('error')