def __init__( self, game, window=None, x=0, y=0, modifiers={'str': 5, 'int': 5, 'cha': 5, 'agi': 5}, mainstat="agi" ): super().__init__() self.game = game self.child_objects = [] self.cast_object = None self.x, self.y = x, y # self.movement = Movement(self) self.lhand_offset = (0, 0) self.rhand_offset = (0, 0) self.body_offset = (0, 0) self.child_objects.append(HeadBobbing(self, duration=0.5, amount=3)) if window: self.windowpos = (window.width // 2, window.height // 2) logging.debug("Adding sprite to player.") self.window = window sprite_x, sprite_y = window.get_windowpos(x, y, precise=True) self.sprite = pyglet.sprite.Sprite( window.textures["player_body"], x=window.width // 2, y=window.height // 2, batch=window.batches["creatures"], group=window.fg_group ) self.glow = pyglet.sprite.Sprite( window.textures["player_body_glow"], x=window.width // 2, y=window.height // 2, batch=window.batches["creatures"], group=window.mid_group ) self.glow.color = (255, 255, 255) self.glow.opacity = 0 else: logging.info("No window specified, not adding sprite to player.") self.limbs = dict( left=Hand( self, (-10, 8), window.textures["player_hand"], glow_texture=window.textures["player_hand_glow"], glow_color=(20, 160, 120) ), right=Hand( self, (10, 8), window.textures["player_hand"], glow_texture=window.textures["player_hand_glow"], glow_color=(175, 50, 110) ) ) self.child_objects.append(Pulse(self.limbs["right"].glow)) self.child_objects.append( Pulse(self.limbs["left"].glow, frequency=0.3) ) self.child_objects.append( Pulse( self.glow, frequency=2.5, max_opacity=0.3, min_scale=0.8, max_scale=1.3 ) ) self.action = None self.actions = dict( sprint=False, movement=False, targeting=False, ) self.auto_attack_target = None self.target = None self.modifiers = modifiers self.modifiers_items = modifiers self.mainstat = mainstat self.move_dir = dict( left=False, right=False, up=False, down=False ) self.last_dir = "down" self.head_dir = (1, 0) self.base_stats = load_cfg("PlayerBaseStats") self.base_stats_items = self.base_stats.copy() self.equipped_items = dict( head=None, torso=None, hands=None, feet=None, acc_1=None, acc_2=None, weapon_l=None, weapon_r=None, weapon_2h=None ) self.attack_effects = dict( dmg=30, dmg_type="physical", stun=0, slow=0, aoe=0, aoe_dmg=0, dot=None, dot_dmg=None, penetration=0, crit=10 ) self.stats = StatSystem(self) self.stats.set_base_attack(self.attack_effects) self.stats.set_base_stats(self.base_stats) self.stats.recalculate_items() self.abilities = dict( slot1=abilities.FireBall(self), slot2=abilities.SpreadBalls(self), slot3=abilities.Blink(self), slot4=abilities.Spark(self), ) self.hp = self.max_hp = self.base_stats["hp"] self.mp = self.max_mp = self.base_stats["mp"] self.sta = self.max_sta = self.base_stats["sta"] self.xp = 0 self.attack_cd = 0 self.update_stats() self.restore_stats()
class Player(Actor): def __init__( self, game, window=None, x=0, y=0, modifiers={'str': 5, 'int': 5, 'cha': 5, 'agi': 5}, mainstat="agi" ): super().__init__() self.game = game self.child_objects = [] self.cast_object = None self.x, self.y = x, y # self.movement = Movement(self) self.lhand_offset = (0, 0) self.rhand_offset = (0, 0) self.body_offset = (0, 0) self.child_objects.append(HeadBobbing(self, duration=0.5, amount=3)) if window: self.windowpos = (window.width // 2, window.height // 2) logging.debug("Adding sprite to player.") self.window = window sprite_x, sprite_y = window.get_windowpos(x, y, precise=True) self.sprite = pyglet.sprite.Sprite( window.textures["player_body"], x=window.width // 2, y=window.height // 2, batch=window.batches["creatures"], group=window.fg_group ) self.glow = pyglet.sprite.Sprite( window.textures["player_body_glow"], x=window.width // 2, y=window.height // 2, batch=window.batches["creatures"], group=window.mid_group ) self.glow.color = (255, 255, 255) self.glow.opacity = 0 else: logging.info("No window specified, not adding sprite to player.") self.limbs = dict( left=Hand( self, (-10, 8), window.textures["player_hand"], glow_texture=window.textures["player_hand_glow"], glow_color=(20, 160, 120) ), right=Hand( self, (10, 8), window.textures["player_hand"], glow_texture=window.textures["player_hand_glow"], glow_color=(175, 50, 110) ) ) self.child_objects.append(Pulse(self.limbs["right"].glow)) self.child_objects.append( Pulse(self.limbs["left"].glow, frequency=0.3) ) self.child_objects.append( Pulse( self.glow, frequency=2.5, max_opacity=0.3, min_scale=0.8, max_scale=1.3 ) ) self.action = None self.actions = dict( sprint=False, movement=False, targeting=False, ) self.auto_attack_target = None self.target = None self.modifiers = modifiers self.modifiers_items = modifiers self.mainstat = mainstat self.move_dir = dict( left=False, right=False, up=False, down=False ) self.last_dir = "down" self.head_dir = (1, 0) self.base_stats = load_cfg("PlayerBaseStats") self.base_stats_items = self.base_stats.copy() self.equipped_items = dict( head=None, torso=None, hands=None, feet=None, acc_1=None, acc_2=None, weapon_l=None, weapon_r=None, weapon_2h=None ) self.attack_effects = dict( dmg=30, dmg_type="physical", stun=0, slow=0, aoe=0, aoe_dmg=0, dot=None, dot_dmg=None, penetration=0, crit=10 ) self.stats = StatSystem(self) self.stats.set_base_attack(self.attack_effects) self.stats.set_base_stats(self.base_stats) self.stats.recalculate_items() self.abilities = dict( slot1=abilities.FireBall(self), slot2=abilities.SpreadBalls(self), slot3=abilities.Blink(self), slot4=abilities.Spark(self), ) self.hp = self.max_hp = self.base_stats["hp"] self.mp = self.max_mp = self.base_stats["mp"] self.sta = self.max_sta = self.base_stats["sta"] self.xp = 0 self.attack_cd = 0 self.update_stats() self.restore_stats() def get_windowpos(self): return self.windowpos def award_kill(self, xp=0, gold=0): if xp: self.xp += xp print(self.xp) if gold: pass def levelup(self, attribute=None): if not attribute: # If no attribute given, assign random upgrade attribute = random.choice(["str", "int", "agi"]) # Increases the chosen attribute by 1 self.stats.increase_stat(attribute) logging.info( "Level up, increased attribute \"{0}\" by 1 to {1}".format( attribute, self.stats.get(attribute) ) ) self.update_stats() self.restore_stats() def restore_stats(self): logging.debug("Player hp, mana and stamina restored to full status.") self.hp = self.max_hp self.mp = self.max_mp self.sta = self.max_sta def equip_item(self, item): if not self.equipped_items[item.slot]: self.equipped_items[item.slot] = item logging.debug( "Player equipped item {0} in slot {1}.".format( item.get_name(), item.slot ) ) self.stats.recalculate_items() def unequip_item(self, slot): if self.equipped_items[slot]: logging.info( "Removed item {0} in slot {1} from player".format( self.equipped_items[slot], slot ) ) self.equipped_items[slot] = None else: logging.error("No item in slot \"{0}\"".format(slot)) self.stats.recalculate_items() def use_ability(self, ability, target=None): a = None if ability == 1: a = self.abilities["slot1"] elif ability == 2: a = self.abilities["slot2"] elif ability == 3: a = self.abilities["slot3"] elif ability == 4: a = self.abilities["slot4"] if a: logging.debug("Player uses ability {}.".format(a.get_name())) if isinstance(a, abilities.ProjectileAbility): self.window.set_reticule("projectile") self.actions["targeting"] = a else: self.clear_ability_target() a.use(target=target) else: logging.debug("No ability in slot {0}.".format(ability)) def clear_ability_target(self): self.actions["targeting"] = False self.window.set_reticule("default") def set_target(self, target): self.target = target def clear_target(self): self.auto_attack_target = None self.target = None def halt_movement(self): for key, value in self.move_dir.items(): self.move_dir[key] = False def set_move_sprite(self): anim = self.window.player_anim_grid static = self.window.player_static_img d = self.move_dir spd = 0.2 * 80 / self.stats.get("ms") if d["left"] and d["down"]: self.last_dir = "leftdown" if not self.sprite.image == anim["leftdown"]: self.sprite.image = anim["leftdown"] elif d["right"] and d["down"]: self.last_dir = "rightdown" if not self.sprite.image == anim["rightdown"]: self.sprite.image = anim["rightdown"] elif d["left"] and d["up"]: self.last_dir = "leftup" if not self.sprite.image == anim["leftup"]: self.sprite.image = anim["leftup"] elif d["right"] and d["up"]: self.last_dir = "rightup" if not self.sprite.image == anim["rightup"]: self.sprite.image = anim["rightup"] elif d["up"] and not d["down"]: self.last_dir = "up" if not self.sprite.image == anim["up"]: self.sprite.image = anim["up"] elif d["down"] and not d["up"]: self.last_dir = "down" if not self.sprite.image == anim["down"]: self.sprite.image = anim["down"] elif d["left"] and not d["right"]: self.last_dir = "left" if not self.sprite.image == anim["left"]: self.sprite.image = anim["left"] elif d["right"] and not d["left"]: self.last_dir = "right" if not self.sprite.image == anim["right"]: self.sprite.image = anim["right"] else: if not self.sprite.image == static[self.last_dir]: self.sprite.image = static[self.last_dir] if isinstance(self.sprite.image, pyglet.image.Animation): set_duration(self.sprite.image, spd) def auto_attack(self, dt): t = self.auto_attack_target if t not in self.game.enemies: # To prevent having a zombie of target t = self.auto_attack_target = None if not self.cast_object and self.attack_cd <= 0: if t: dist = get_dist(self.x, self.y, t.x, t.y) attack_range = self.stats.get("arng") if dist <= attack_range: angle = math.degrees( get_angle(self.x, self.y, t.x, t.y) ) anglediff = ( (self.angle - angle + 180) % 360 - 180 ) if anglediff <= 45 and anglediff >= -45: self.attack(t) self.attack_cd = self.stats.get("aspd") else: self.attack_cd -= dt def attack(self, t): attack_effects = self.attack_effects.copy() attack_effects["dmg"] = self.stats.get("dmg") attack_effects["crit"] = self.stats.get("crit") result = t.do_effect(attack_effects, origin=self) self.attack_fx(t) if result["crit"]: force = 100 else: force = 50 vec = ((t.x - self.x), (t.y - self.y)) force_x = force_y = force force_x -= abs(vec[0]) force_y -= abs(vec[1]) force_vec = (vec[0] * force_x), (vec[1] * force_y) t.body.apply_impulse(force_vec) if result["crit"]: self.child_objects.append( HandAnimAttack( self, "left", duration=self.stats.get("aspd") / 3 ) ) self.child_objects.append( HandAnimAttack( self, "right", duration=self.stats.get("aspd") / 3 ) ) else: hand = random.choice(["right", "left"]) self.child_objects.append( HandAnimAttack(self, hand, duration=self.stats.get("aspd") / 3) ) def critical_strike(self, critchance): if random.randrange(1, 100) <= critchance: return True else: return False def attack_fx(self, t): midpoint = get_midpoint((self.x, self.y), (t.x, t.y)) fx_point = get_midpoint(midpoint, (t.x, t.y)) apos = self.game.window.get_windowpos( *fx_point ) effect = random.choice(["Melee 1", "Melee 2", "Melee 5"]) self.game.window.animator.spawn_anim( effect, apos, scale=0.25, rotation=self.angle - 45 ) def update_stats(self): self.stats.update_owner_stats() def update_regen(self, dt): if self.hp < self.max_hp: self.hp += self.stats.get("hp_regen") * dt if self.mp < self.max_mp: self.mp += self.stats.get("mp_regen") * dt if self.sta < self.max_sta and not self.actions["sprint"]: self.sta += self.stats.get("sta_regen") * dt def update_degen(self, dt): if self.actions["sprint"]: if self.sta > 0: for d, val in self.move_dir.items(): if val: self.sta -= 15 * dt break else: self.actions["sprint"] = False def update_body(self): angle = get_angle(self.sprite.x, self.sprite.y, *self.window.mouse_pos) self.angle = math.degrees(angle) for key, limb in self.limbs.items(): limb.update_pos() self.sprite.x, self.sprite.y = rotate2d( math.radians(self.angle + 90), ( self.windowpos[0] + self.body_offset[0], self.windowpos[1] + self.body_offset[1] ), self.windowpos ) self.sprite.rotation = self.angle + 90 self.glow.x, self.glow.y = self.sprite.x, self.sprite.y self.glow.rotation = self.sprite.rotation def die(self): pos = self.window.get_windowpos(self.x, self.y, precise=True) self.window.animator.spawn_anim("Blood Splash", pos, scale=0.8) # self.active_effects = [] self.limbs = {} self.child_objects = [] self.sprite.delete() self.glow.delete() self.remove_body() self.clear_target() self.clear_ability_target() self.game.player = None # self.sprite.visible = False logging.info("Player died!") def update(self, dt): if self.hp <= 0: self.die() else: if self.xp >= 30: self.levelup() self.xp = 0 self.movement.speed = self.stats.get("ms") old_x, old_y = self.x, self.y self.movement.update(dt) self.window.update_offset(dx=old_x - self.x, dy=old_y - self.y) if self.actions["movement"] and self.cast_object: self.cast_object = None logging.info("Cast interrupted by movement.") self.auto_attack(dt) self.update_regen(dt) self.update_degen(dt) self.update_stats() for o in self.child_objects: try: o.update(dt) except Exception as e: logging.error(e) if self.cast_object: self.cast_object.update(dt) self.update_body()