def _getTorpedoToFire(self, enemy: Enemy, enterprise: Enterprise) -> BaseEnemyTorpedo:
        """

        Args:
            enemy:      The Klingon, Commander, or Super Commander that is firing
            enterprise: Where Captain Kirk is waiting

        Returns:  A torpedo of the correct kind
        """
        #
        # Use the enterprise arcade position rather than compute the sector center;  That way we
        # can use Arcade collision detection
        #
        klingonPoint:    ArcadePoint = ArcadePoint(x=enemy.center_x, y=enemy.center_y)
        enterprisePoint: ArcadePoint = ArcadePoint(x=enterprise.center_x, y=enterprise.center_y)

        speeds: TorpedoSpeeds = self._intelligence.getTorpedoSpeeds(playerType=self._gameState.playerType)

        klingonTorpedo: KlingonTorpedo = KlingonTorpedo(speed=speeds.klingon)

        klingonTorpedo.center_x = klingonPoint.x
        klingonTorpedo.center_y = klingonPoint.y
        klingonTorpedo.inMotion = True
        klingonTorpedo.destinationPoint = enterprisePoint
        klingonTorpedo.firedFromPosition = enemy.gameCoordinates
        klingonTorpedo.firedBy = enemy.id
        klingonTorpedo.followers = self.torpedoFollowers

        return klingonTorpedo
예제 #2
0
    def _getTorpedoToFire(self, enemy: Enemy,
                          enterprise: Enterprise) -> BaseEnemyTorpedo:
        """
        Must be implemented by subclass to create correct type of torpedo

        Args:
            enemy:      The Klingon, Commander, or Super Commander that is firing
            enterprise: Where Captain Kirk is waiting

        Returns:  A torpedo of the correct kind
        """
        klingonPoint: ArcadePoint = ArcadePoint(x=enemy.center_x,
                                                y=enemy.center_y)
        enterprisePoint: ArcadePoint = ArcadePoint(x=enterprise.center_x,
                                                   y=enterprise.center_y)

        speeds: TorpedoSpeeds = self._intelligence.getTorpedoSpeeds(
            playerType=self._gameState.playerType)

        commanderTorpedo: CommanderTorpedo = CommanderTorpedo(
            speed=speeds.commander)

        commanderTorpedo.center_x = klingonPoint.x
        commanderTorpedo.center_y = klingonPoint.y
        commanderTorpedo.inMotion = True
        commanderTorpedo.destinationPoint = enterprisePoint
        commanderTorpedo.firedFromPosition = enemy.gameCoordinates
        commanderTorpedo.firedBy = enemy.id
        commanderTorpedo.followers = self.torpedoFollowers

        return commanderTorpedo
예제 #3
0
    def fireEnterpriseTorpedoesAtKlingons(self, quadrant: Quadrant):

        if self._gameState.torpedoCount <= 0:
            self._soundMachine.playSound(SoundType.UnableToComply)
            self._messageConsole.displayMessage(
                "You are out of photon torpedoes!!")
            return  # Take a shortcut out of here

        self._messageConsole.displayMessage("Firing Torpedoes!!")

        enterprise: Enterprise = quadrant.enterprise

        enemies: Enemies = Enemies([])
        enemies.extend(quadrant.klingons)
        enemies.extend(quadrant.commanders)
        enemies.extend(quadrant.superCommanders)

        numberOfEnemies: int = len(enemies)
        if numberOfEnemies == 0:
            self._messageConsole.displayMessage(
                "Don't waste torpedoes.  Nothing to fire at")
            self._soundMachine.playSound(SoundType.Inaccurate)
        else:
            startingPoint: ArcadePoint = ArcadePoint(x=enterprise.center_x,
                                                     y=enterprise.center_y)
            #
            #  Only fire as many torpedoes as we have available
            #  TODO:  Fire only 'N' torpedoes at randomly selected enemies
            #
            for enemy in enemies:
                endPoint: ArcadePoint = ArcadePoint(x=enemy.center_x,
                                                    y=enemy.center_y)

                clearLineOfSight: LineOfSightResponse = self._doWeHaveLineOfSight(
                    quadrant, startingPoint, endPoint)
                if clearLineOfSight.answer is True:
                    self._pointAtEnemy(enterprise=enterprise, enemy=enemy)
                    if self._intelligence.rand(
                    ) <= self._gameSettings.photonTorpedoMisfireRate:
                        self._messageConsole.displayMessage(
                            f'Torpedo pointed at {enemy} misfired')
                        self._soundMachine.playSound(
                            SoundType.PhotonTorpedoMisfire)
                    else:
                        self._fireTorpedo(enterprise=enterprise, enemy=enemy)
                        self._soundMachine.playSound(
                            SoundType.PhotonTorpedoFired)
                        self._gameState.torpedoCount -= 1
                else:
                    msg: str = (
                        f'Cannot fire at {enemy.id} '
                        f'because a {clearLineOfSight.obstacle.id} is in the way'
                    )
                    self._messageConsole.displayMessage(message=msg)
                    self.logger.info(msg)
            enterprise.angle = 0
예제 #4
0
    def testComputeCenterPointMid(self):

        startPoint: ArcadePoint = ArcadePoint(x=0, y=0)
        endPoint:   ArcadePoint = ArcadePoint(x=400, y=400)

        midPoint: ArcadePoint = Computer.computeCenterPoint(start=startPoint, end=endPoint)

        self.logger.debug(f'{startPoint=} {endPoint=} {midPoint=}')

        expectedPoint: ArcadePoint = ArcadePoint(x=200, y=200)
        self.assertEqual(expectedPoint, midPoint, 'Mid Center point does not match')
예제 #5
0
    def testComputeCenterPointLong(self):

        startPoint: ArcadePoint = ArcadePoint(x=10, y=10)
        endPoint:   ArcadePoint = ArcadePoint(x=SCREEN_HEIGHT-10, y=QUADRANT_GRID_WIDTH-10)

        midPoint: ArcadePoint = Computer.computeCenterPoint(start=startPoint, end=endPoint)

        self.logger.debug(f'{startPoint=} {endPoint=} {midPoint=}')

        expectedPoint: ArcadePoint = ArcadePoint(x=415, y=320)
        self.assertEqual(expectedPoint, midPoint, 'Long Center point does not match')
예제 #6
0
    def testComputeAngleToTargetDirectWest(self):
        """
        East is right
        """

        shooter:  ArcadePoint = ArcadePoint(x=500.0, y=100.0)
        deadMeat: ArcadePoint = ArcadePoint(x=100.0, y=100.0)

        actualAngle:   float = self.smarty.computeAngleToTarget(shooter=shooter, deadMeat=deadMeat)
        expectedAngle: float = 180.0

        self.assertEqual(expectedAngle, actualAngle, 'Bad computation')
예제 #7
0
    def testComputeAngleToTargetDirectNorth(self):
        """
        North is up
        """

        shooter:  ArcadePoint = ArcadePoint(x=100, y=100)
        deadMeat: ArcadePoint = ArcadePoint(x=100, y=500)

        actualAngle = self.smarty.computeAngleToTarget(shooter=shooter, deadMeat=deadMeat)
        expectedAngle = 90

        self.assertEqual(expectedAngle, actualAngle, 'Bad computation')
예제 #8
0
    def testComputeAngleToTargetDirectSouth(self):
        """
        South is down
        """

        shooter:  ArcadePoint = ArcadePoint(x=100.0, y=500.0)
        deadMeat: ArcadePoint = ArcadePoint(x=100.0, y=100.0)

        actualAngle:   float = self.smarty.computeAngleToTarget(shooter=shooter, deadMeat=deadMeat)
        expectedAngle: float = -90.0

        self.assertEqual(expectedAngle, actualAngle, 'Bad computation')
예제 #9
0
    def testDoMotion(self):

        currentPoint: ArcadePoint = ArcadePoint(x=0, y=0)
        destinationPoint: ArcadePoint = ArcadePoint(x=0, y=500)

        self.smoothMotion.computeArcadeMotion(
            currentPoint=currentPoint,
            destinationPoint=destinationPoint,
            spriteRotationAngle=0,
            rotationalSpeed=TestSmoothMotion.TEST_ROTATIONAL_SPEED)

        mockSprite: MagicMock(spec=GamePiece)
예제 #10
0
    def _pointAtTarget(self,
                       shooter: Sprite,
                       target: GamePiece,
                       rotationAngle: int = 125):

        currentPoint: ArcadePoint = ArcadePoint(x=shooter.center_x,
                                                y=shooter.center_y)
        destinationPoint: ArcadePoint = ArcadePoint(x=target.center_x,
                                                    y=target.center_y)

        normalAngle: float = self._computer.computeAngleToTarget(
            shooter=currentPoint, deadMeat=destinationPoint)
        shooter.angle = normalAngle + rotationAngle

        self._baseMediatorLogger.info(f'{normalAngle=} -  {shooter.angle=}')
예제 #11
0
    def klingonTorpedoExplosionPoint(self) -> ArcadePoint:
        if self._ktxPoint is None:
            self._ktxPoint = ArcadePoint(
                x=HALF_SCREEN_WIDTH + EXPLOSION_X_OFFSET,
                y=HALF_SCREEN_HEIGHT + EXPLOSION_Y_OFFSET)

        return self._ktxPoint
예제 #12
0
    def superCommanderTorpedoExplosionPoint(self) -> ArcadePoint:
        if self._stxPoint is None:
            self._stxPoint = ArcadePoint(
                x=HALF_SCREEN_WIDTH + EXPLOSION_X_OFFSET,
                y=HALF_SCREEN_HEIGHT - EXPLOSION_Y_OFFSET)

        return self._stxPoint
예제 #13
0
    def gamePositionToScreenPoint(cls,
                                  gameCoordinates: Coordinates) -> ArcadePoint:
        """
        This is strictly for the GameView;  GamePieces need to use GamePiece.gamePositionToScreenPosition
        Computes x,y arcade position within the galaxy
        Args:
            gameCoordinates:   The game coordinates

        Returns:  Arcade x,y Position

        """

        sectorX: int = gameCoordinates.x
        sectorY: int = gameCoordinates.y
        #
        # because game coordinates are top L - R and down
        # and game coordinates are 0-based
        adjustSectorX: int = sectorX
        adjustSectorY: int = (QUADRANT_ROWS - sectorY) - 1

        xMargins = -12  # Font Fudge Factor
        yMargins = -12  # Font Fudge Factor

        x = (adjustSectorX *
             QUADRANT_PIXEL_WIDTH) + HALF_QUADRANT_PIXEL_WIDTH + xMargins
        y = (adjustSectorY * QUADRANT_PIXEL_HEIGHT
             ) + HALF_QUADRANT_PIXEL_HEIGHT + yMargins + CONSOLE_HEIGHT

        return ArcadePoint(x=x, y=y)
예제 #14
0
    def phaserFirePoint(self) -> ArcadePoint:

        if self._phaserFirePoint is None:
            x: int = HALF_SCREEN_WIDTH + (HALF_SCREEN_WIDTH // 2)
            self._phaserFirePoint = ArcadePoint(x=x, y=HALF_SCREEN_HEIGHT)

        return self._phaserFirePoint
예제 #15
0
    def enterpriseTorpedoExplosionPoint(self) -> ArcadePoint:

        if self._etxPoint is None:
            self._etxPoint = ArcadePoint(x=HALF_SCREEN_WIDTH // 2,
                                         y=HALF_SCREEN_HEIGHT // 2)

        return self._etxPoint
예제 #16
0
 def on_mouse_press(self, x: float, y: float, button: int, key_modifiers: int):
     """
     Called when the user presses a mouse button.
     """
     if button == MOUSE_BUTTON_LEFT:
         arcadePoint: ArcadePoint = ArcadePoint(x=x, y=y)
         if x < QUADRANT_GRID_WIDTH and y >= CONSOLE_HEIGHT:
             self._enterpriseMediator.impulse(quadrant=self._quadrant, arcadePoint=arcadePoint)
예제 #17
0
    def _placePhaserBolt(self, enterprise: Enterprise, enemy: Enemy):

        start: ArcadePoint = ArcadePoint(x=enterprise.center_x,
                                         y=enterprise.center_y)
        end: ArcadePoint = ArcadePoint(x=enemy.center_x, y=enemy.center_y)
        centerPoint: ArcadePoint = self._computer.computeCenterPoint(
            start=start, end=end)

        phaserBolt: PhaserBolt = PhaserBolt(
            textureList=self._phaserFireTextures)

        phaserBolt.center_x = centerPoint.x
        phaserBolt.center_y = centerPoint.y

        self._pointAtTarget(shooter=phaserBolt,
                            target=enterprise,
                            rotationAngle=180)

        self._phaserBolts.append(phaserBolt)
예제 #18
0
    def testGamePositionToScreenPositionZeroNine(self):

        sectorCoordinates: Coordinates = Coordinates(x=0, y=9)
        arcadePoint: ArcadePoint = GamePiece.gamePositionToScreenPosition(
            gameCoordinates=sectorCoordinates)

        self.logger.info(f'{arcadePoint=}')

        expectedPoint: ArcadePoint = ArcadePoint(x=32.0, y=222.0)
        self.assertEqual(expectedPoint, arcadePoint,
                         'Calculation must have changed')
예제 #19
0
    def computeCenterPoint(cls, start: ArcadePoint,
                           end: ArcadePoint) -> ArcadePoint:

        x1: float = start.x
        x2: float = end.x
        y1: float = start.y
        y2: float = end.y

        midX: float = (x1 + x2) // 2
        midY: float = (y1 + y2) // 2

        return ArcadePoint(x=midX, y=midY)
예제 #20
0
    def _fireTorpedo(self, enterprise: Enterprise, enemy: Enemy):

        enterprisePoint: ArcadePoint = ArcadePoint(x=enterprise.center_x,
                                                   y=enterprise.center_y)
        klingonPoint: ArcadePoint = ArcadePoint(x=enemy.center_x,
                                                y=enemy.center_y)

        speeds: TorpedoSpeeds = self._intelligence.getTorpedoSpeeds(
            playerType=self._gameState.playerType)
        torpedo: PhotonTorpedo = PhotonTorpedo(speed=speeds.enterprise)

        torpedo.center_x = enterprisePoint.x
        torpedo.center_y = enterprisePoint.y
        torpedo.inMotion = True
        torpedo.firedAt = enemy.id
        torpedo.destinationPoint = klingonPoint

        self._torpedoes.append(torpedo)
        self._messageConsole.displayMessage(
            f'Enterprise fire from: {enterprise.gameCoordinates} at Klingon {enemy.id}'
        )
예제 #21
0
    def update(self):

        if self.inMotion is True:

            radianInfo: RadianInfo = self.computeArcadeMotion(
                currentPoint=ArcadePoint(x=self.center_x, y=self.center_y),
                destinationPoint=self.destinationPoint,
                spriteRotationAngle=self.angle,
                rotationalSpeed=self.rotationSpeed)

            self.doMotion(gamePiece=self,
                          destinationPoint=self.destinationPoint,
                          angleDiffRadians=radianInfo.angleDiffRadians,
                          actualAngleRadians=radianInfo.actualAngleRadians)
예제 #22
0
    def gamePositionToScreenPosition(cls, gameCoordinates: Coordinates) -> ArcadePoint:

        sectorX: int = gameCoordinates.x
        sectorY: int = gameCoordinates.y
        #
        # because game coordinates are top L - R and down
        # and game coordinates are 0-based
        adjustSectorX: int = sectorX
        adjustSectorY: int = (QUADRANT_ROWS - sectorY) - 1

        x = (adjustSectorX * QUADRANT_PIXEL_WIDTH) + HALF_QUADRANT_PIXEL_WIDTH
        y = (adjustSectorY * QUADRANT_PIXEL_HEIGHT) + HALF_QUADRANT_PIXEL_HEIGHT + CONSOLE_HEIGHT

        arcadePoint: ArcadePoint = ArcadePoint(x=x, y=y)
        return arcadePoint
    def update(self, quadrant: Quadrant):

        enterprise: Enterprise = quadrant.enterprise

        arcadePoint: ArcadePoint = GamePiece.gamePositionToScreenPosition(quadrant.enterpriseCoordinates)
        arcadeX:     float       = arcadePoint.x
        arcadeY:     float       = arcadePoint.y
        if enterprise.inMotion is True:

            self.logger.debug(f'Enterprise arcade position: ({arcadeX},{arcadeY})')
            enterprise.destinationPoint = ArcadePoint(x=arcadeX, y=arcadeY)
            enterprise.update()
        else:
            enterprise.center_x = arcadeX
            enterprise.center_y = arcadeY
예제 #24
0
    def on_mouse_release(self, x: float, y: float, button: int,
                         keyModifiers: int):
        """
        Called when the user presses a mouse button.
        """
        self.logger.info(f'{button=} {keyModifiers=}')
        if button == MOUSE_BUTTON_LEFT and keyModifiers == arcadeKey.MOD_CTRL:
            # Try klingons first
            clickedEnemies: List[Sprite] = get_sprites_at_point(
                point=(x, y), sprite_list=self._quadrantMediator.klingonList)

            # The Commanders
            if len(clickedEnemies) == 0:
                clickedEnemies = get_sprites_at_point(
                    point=(x, y),
                    sprite_list=self._quadrantMediator.commanderList)

            # Must be Super Commanders
            if len(clickedEnemies) == 0:
                clickedEnemies = get_sprites_at_point(
                    point=(x, y),
                    sprite_list=self._quadrantMediator.superCommanderList)

            for enemy in clickedEnemies:
                print(f'Delete {enemy}')
                enemy.remove_from_sprite_lists()
        elif button == MOUSE_BUTTON_LEFT:

            if self._selectedGamePiece is None:
                clickedPaletteSprites: List[Sprite] = get_sprites_at_point(
                    point=(x, y), sprite_list=self._staticSprites)

                for paletteSprite in clickedPaletteSprites:
                    paletteSprite.color = color.BLACK
                    self._selectedGamePiece = paletteSprite
            else:
                # A palette sprite is selected
                self._placeSpriteOnBoard(x=x, y=y)

                self.logger.info(f'Clear selected Sprite')
                self._selectedGamePiece.color = color.WHITE
                self._selectedGamePiece = cast(GamePiece, None)

        arcadePoint: ArcadePoint = ArcadePoint(x=x, y=y)
        self._quadrantMediator.handleMousePress(quadrant=self._quadrant,
                                                arcadePoint=arcadePoint,
                                                button=button,
                                                keyModifiers=keyModifiers)
예제 #25
0
    def update(self):

        if self.inMotion is True:
            radianInfo: RadianInfo = self.computeArcadeMotion(
                currentPoint=ArcadePoint(x=self.center_x, y=self.center_y),
                destinationPoint=self.destinationPoint,
                spriteRotationAngle=self.angle,
                rotationalSpeed=self.rotationSpeed)

            # self._baseEnemyTorpedoLogger.debug(f'{radianInfo=} {self.destinationPoint=}')
            self.doMotion(gamePiece=self,
                          destinationPoint=self.destinationPoint,
                          angleDiffRadians=radianInfo.angleDiffRadians,
                          actualAngleRadians=radianInfo.actualAngleRadians)
            # self.doMotion2(gamePiece=self, destinationPoint=self.destinationPoint)

            self._potentiallyCreateAFollower()
    def _fireTorpedoesAtEnterpriseIfNecessary(self,
                                              quadrant: Quadrant,
                                              enemies: Enemies,
                                              rotationAngle: int = 125):
        """

        Args:
            quadrant:   Quadrant we are in
            enemies:    The enemies to fire from
            rotationAngle: The offset to add to the image when pointing at the enterprise
        """

        currentTime: float = self._gameEngine.gameClock

        for enemy in enemies:
            deltaClockTime: float = currentTime - enemy.lastTimeCheck
            if deltaClockTime > enemy.firingInterval:
                self._baseTorpedoMediatorLogger.debug(
                    f'Time for {enemy} to fire torpedoes')

                endPoint: ArcadePoint = ArcadePoint(
                    x=quadrant.enterprise.center_x,
                    y=quadrant.enterprise.center_y)
                lineOfSightResponse: LineOfSightResponse = self._doWeHaveLineOfSight(
                    quadrant, shooter=enemy, endPoint=endPoint)
                if lineOfSightResponse.answer is True:
                    self._pointAtEnterprise(enemy=enemy,
                                            enterprise=quadrant.enterprise,
                                            rotationAngle=rotationAngle)
                    self._fireTorpedo(enemy=enemy,
                                      enterprise=quadrant.enterprise)
                else:
                    self._playCannotFireSound()
                    self._messageConsole.displayMessage(
                        f'{enemy.id} cannot shoot, blocked by {lineOfSightResponse.obstacle.id}'
                    )

                enemy.lastTimeCheck = round(currentTime)
    def _doWeHaveLineOfSight(self, quadrant: Quadrant, shooter: Enemy,
                             endPoint: ArcadePoint) -> LineOfSightResponse:

        startingPoint: ArcadePoint = ArcadePoint(x=shooter.center_x,
                                                 y=shooter.center_y)
        obstacles: SpriteList = SpriteList()

        if quadrant.hasPlanet is True:
            obstacles.append(quadrant.planet)
        if quadrant.hasStarBase is True:
            obstacles.append(quadrant.starBase)

        otherEnemies: Enemies = self.__buildEligibleEnemyObstacles(
            shooter=shooter, enemies=quadrant.klingons)

        obstacles.extend(otherEnemies)

        results: LineOfSightResponse = self._hasLineOfSight(
            startingPoint=startingPoint,
            endPoint=endPoint,
            obstacles=obstacles)

        self._baseTorpedoMediatorLogger.debug(f'{results=}')
        return results
예제 #28
0
    def testGalaxyArcadePosition_276_530(self):

        expectedArcade: ArcadePoint = ArcadePoint(x=276, y=530)
        actualArcade:   ArcadePoint = Computer.gamePositionToScreenPoint(gameCoordinates=Coordinates(x=4, y=4))

        self.assertEqual(expectedArcade, actualArcade, 'Computer is broken')
예제 #29
0
    def testGalaxyArcadePosition_84_786(self):

        expectedArcade: ArcadePoint = ArcadePoint(x=84, y=786)
        actualArcade:   ArcadePoint = Computer.gamePositionToScreenPoint(gameCoordinates=Coordinates(x=1, y=0))

        self.assertEqual(expectedArcade, actualArcade, 'Computer is broken')
예제 #30
0
    def testGalaxyArcadePosition_596_201(self):

        expectedArcade: ArcadePoint = ArcadePoint(x=596, y=210)
        actualArcade:   ArcadePoint = Computer.gamePositionToScreenPoint(gameCoordinates=Coordinates(x=9, y=9))

        self.assertEqual(expectedArcade, actualArcade, 'Computer is broken')