Ejemplo n.º 1
0
class DodgeShooter(EnemyUnit):
    """Dodge with a machine gun unit.

    Represents an enemy unit, which attacks with
    long pauses, but also deals a lot of damage.

    Args:
        model (actor.Actor): Enemy character model.
        id_ (int): Enemy unit id.
        y_positions (list): Free positions along Y.
        enemy_handler (CollisionHandlerEvent): Enemy collisions handler.
        class_data (dict): This unit class description.
    """
    def __init__(self, model, id_, y_positions, enemy_handler, class_data):
        EnemyUnit.__init__(
            self,
            id_,
            "Gun Dodge",
            class_data,
            model,
            y_positions,
            enemy_handler,
        )

        self._col_node = self._init_col_node(
            SHOT_RANGE_MASK,
            MOUSE_MASK,
            CollisionBox(Point3(-0.04, -0.12, -0.02), Point3(0.04, 0.11,
                                                             0.06)),
        )
        base.common_ctrl.traverser.addCollider(  # noqa: F821
            self._col_node, enemy_handler)
        self._shoot_seq = self._set_shoot_anim()
        self._explosion = base.effects_mgr.explosion_big(self)  # noqa: F821
        self._smoke = base.effects_mgr.burn_smoke(self)  # noqa: F821

    def _set_shoot_anim(self):
        """Prepare machine gun shooting animation for this unit.

        Returns:
            direct.interval.MetaInterval.Sequence:
                Shooting animation and sounds sequence.
        """
        shot_snd = base.sound_mgr.loadSfx(  # noqa: F821
            "sounds/combat/machine_gun_shot1.ogg")
        base.sound_mgr.attachSoundToObject(shot_snd, self.model)  # noqa: F821

        fire = loader.loadModel(address("gun_fire2"))  # noqa: F821
        fire.reparentTo(self.model)
        fire.setScale(1, 0.0001, 1)
        if self._y_pos > 0:
            fire.setPos(-0.055, -0.008, 0.076)
            fire.setH(180)
        else:
            fire.setPos(0.065, -0.008, 0.076)

        shoot_par = Parallel(
            Sequence(
                LerpScaleInterval(fire, 0.07, (1, 1, 1)),
                LerpScaleInterval(fire, 0.07, (1, 0.0001, 1)),
                Wait(0.12),
            ),
            SoundInterval(shot_snd, duration=0.25),
        )
        return Sequence(*(shoot_par, ) * 20)

    def capture_train(self):
        """The Train got critical damage - stop near it."""
        EnemyUnit.capture_train(self)

        self._stop_tasks("_shoot_at_train", "_do_damage_to_train",
                         "_stop_doing_damage")

    def enter_the_part(self, part):
        """Start fighting in the given part.

        Args:
            part (train.part.TrainPart): Train part this enemy entered.
        """
        self.current_part = part

        self.model.play("turn_right" if self._y_pos < 0 else "turn_left")

        taskMgr.doMethodLater(  # noqa: F821
            2, self._shoot_at_train, self.id + "_shoot_at_train")

    def leave_the_part(self, _):
        """Stop fighting in the current part."""
        self._stop_tasks("_shoot_at_train", "_do_damage_to_train",
                         "_stop_doing_damage")
        self.current_part = None

    def _shoot_at_train(self, task):
        """Start shooting volley, including logic, animations, sounds."""
        self._shoot_seq.start()
        taskMgr.doMethodLater(  # noqa: F821
            0.5, self._do_damage_to_train, self.id + "_do_damage_to_train")
        taskMgr.doMethodLater(  # noqa: F821
            6,
            taskMgr.remove,  # noqa: F821
            self.id + "_stop_doing_damage",
            extraArgs=[self.id + "_do_damage_to_train"],
        )
        task.delayTime = random.randint(15, 18)
        return task.again

    def _do_damage_to_train(self, task):
        """Deal machine gun damage to the Train."""
        if self.current_part.is_covered:
            if chance(40):
                base.train.get_damage(2)  # noqa: F821
        else:
            base.train.get_damage(2)  # noqa: F821

        base.train.get_shot(self._y_pos > 0)  # noqa: F821
        return task.again

    def _explode(self):
        """Play explosion sequence of effects and sounds.

        Also includes explosion physics.
        """
        self._explosion.play()
        self._smoke.play()

        self._rb_node = BulletRigidBodyNode(self.id + "_physics")
        self._rb_node.setMass(100)
        self._rb_node.addShape(BulletBoxShape(Vec3(0.06, 0.1, 0.028)))
        self._rb_node.deactivation_enabled = False

        phys_node = self.node.attachNewNode(self._rb_node)  # noqa: F821

        self.model.reparentTo(phys_node)
        self.model.setPos(0, 0, -0.03)
        base.world.phys_mgr.attachRigidBody(self._rb_node)  # noqa: F821

        # boom impulse
        angle = round(self.model.getH(render))  # noqa: F821
        x = 0
        y = 0
        if angle == 0:
            y = random.randint(6500, 8500)
        elif angle == 90:
            x = -random.randint(6500, 8500)
        elif angle == -90:
            x = random.randint(6500, 8500)

        self._rb_node.applyForce(Vec3(x, y, random.randint(1500, 2500)),
                                 Point3(0, -0.1, 0))
        self._rb_node.applyTorque(
            Vec3(
                random.randint(-30, 30),
                random.randint(-30, 30),
                random.randint(-30, 30),
            ))

    def _die(self):
        """Die actions for this shooter.

        Returns:
            bool: True, if this shooter dies for the first time.
        """
        if EnemyUnit._die(self):
            self._shoot_seq.finish()
            self._stop_tasks("_shoot_at_train", "_stop_doing_damage",
                             "_do_damage_to_train")
Ejemplo n.º 2
0
class EnemyMotorcyclist(EnemyUnit):
    """Enemy unit on motorcycle base class.

    Includes a motocycle explosion effect and a
    collision node appropriate for any motorcyclist.

    Args:
        id_ (int): Enemy unit id.
        class_ (str): Enemy class name.
        class_data (dict): Enemy class description.
        model (actor.Actor): Enemy character model.
        y_positions (list): Free positions along Y.
        enemy_handler (CollisionHandlerEvent): Enemy collisions handler.
    """
    def __init__(self, id_, class_, class_data, model, y_positions,
                 enemy_handler):
        EnemyUnit.__init__(self, id_, class_, class_data, model, y_positions,
                           enemy_handler)
        if chance(50):
            taskMgr.doMethodLater(  # noqa: F821
                random.randint(26, 28), self._play_idle_anim,
                self.id + "_idle")
            self._cry_snd = base.sound_mgr.loadSfx(  # noqa: F821
                "sounds/combat/enemy_cry{num}.ogg".format(
                    num=random.randint(1, 3)))
            self._cry_snd.setVolume(0.4)
            base.sound_mgr.attachSoundToObject(self._cry_snd,
                                               self.model)  # noqa: F821
        else:
            self._cry_snd = None

        taskMgr.doMethodLater(  # noqa: F821
            random.randint(27, 29),
            base.world.play_fight_music,  # noqa: F821
            "play_music",
        )
        self._col_node = self._init_col_node(SHOT_RANGE_MASK, MOUSE_MASK,
                                             CollisionSphere(0, 0, 0.05, 0.05))
        base.common_ctrl.traverser.addCollider(  # noqa: F821
            self._col_node, enemy_handler)
        self._explosion = base.effects_mgr.explosion(self)  # noqa: F821

    def _explode(self):
        """Play explosion sequence of effects and sounds.

        Also includes explosion physics.
        """
        self._explosion.play()

        self._rb_node = BulletRigidBodyNode(self.id + "_physics")
        self._rb_node.setMass(80)
        self._rb_node.addShape(BulletBoxShape(Vec3(0.005, 0.04, 0.028)))
        self._rb_node.deactivation_enabled = False

        phys_node = self.node.attachNewNode(self._rb_node)  # noqa: F821

        self.model.reparentTo(phys_node)
        self.model.setPos(0, -0.01, -0.025)
        base.world.phys_mgr.attachRigidBody(self._rb_node)  # noqa: F821

        # boom impulse
        angle = self.model.getH(render)  # noqa: F821
        x = 0
        y = 0
        if angle == 0:
            y = random.randint(6500, 8500)
        elif angle == 90:
            x = -random.randint(6500, 8500)
        elif angle == -90:
            x = random.randint(6500, 8500)

        self._rb_node.applyForce(Vec3(x, y, random.randint(1500, 2500)),
                                 Point3(0))
        self._rb_node.applyTorque(
            Vec3(
                random.randint(-35, 35),
                random.randint(-35, 35),
                random.randint(-35, 35),
            ))

    def _play_idle_anim(self, task):
        """Play enemy unit idle animation."""
        self.model.play(random.choice(("idle1", "idle2")))
        if self._cry_snd is not None:
            self._cry_snd.play()

        return task.done