def chooseDestination(self): meRenderable = self.brain.owner.world.component_for_entity( self.brain.owner.entity, system.graphics.renderable.Renderable) # if true: go to a static point close to the current enemy position # if false: go to a point relative to the enemy # self.destIsPoint = random.choice([True, False]) # note that getLocation() will return a reference. we need to copy it here. playerEntity = EntityFinder.findPlayer(self.brain.owner.world) if not playerEntity: return playerRenderable = self.brain.owner.world.component_for_entity( playerEntity, system.graphics.renderable.Renderable) self.destCoord = AiHelper.pickDestAroundPlayer( playerRenderable, distanceX=meRenderable.texture.width, distanceY=meRenderable.texture.height) if Config.showEnemyWanderDest: messaging.add( type=MessageType.EmitTextureMinimal, data={ 'char': '.', 'timeout': self.timer, 'coordinate': self.destCoord, 'color': Color.grey } )
def advance(self, deltaTime): playerEntity = EntityFinder.findPlayer(self.world) if playerEntity is None: return player = self.world.component_for_entity(playerEntity, Player) player.advance(deltaTime)
def drawStatusbar(self): # fps = 0 # if n > 100: # fps = 1000 * (float)(n) / (float)(current_milli_time() - self.startTime) # #fps = self.workTime * 1000.0 playerEntity = EntityFinder.findPlayer(self.world.world) if playerEntity is None: # No player here yet return #self.viewport.erase() #self.viewport.border() playerAttackable = self.world.world.component_for_entity( playerEntity, Attackable) player = self.world.world.component_for_entity(playerEntity, Player) color, attr = ColorPalette.getColorByColor(Color.black) bgcolor, _ = ColorPalette.getColorByColor(Color.white) s = " Health: " + str(playerAttackable.getHealth()) s += " Points: " + str(player.points) s += " " * (Config.columns - 2 - len(s)) #s += " FPS: %.0f" % (fps) self.viewport.addstrStatic(1, 1, s, color, attr, bg=bgcolor) self.printSkillbar(color, attr, bgcolor, playerEntity) self.printAttackbar(color, attr, bgcolor, playerEntity)
def checkAttack(self): for message in messaging.getByType(MessageType.PlayerAttack): # most likely just one such message playerEntity = EntityFinder.findPlayer(self.world) player = self.world.component_for_entity( playerEntity, system.gamelogic.player.Player) player.setAttacking( attackTime=message.data['attackAnimationLength'])
def deathAnimation(self): playerEntity = EntityFinder.findPlayer(self.world) meRenderable = self.world.component_for_entity( playerEntity, system.graphics.renderable.Renderable) meRenderable.texture.changeAnimation( characterAnimationType=CharacterAnimationType.dying, direction=meRenderable.direction, subtype=0, interrupt=False)
def getPlayerSkill(self): playerEntity = EntityFinder.findPlayer(self.world) if playerEntity is None: return None meGroupId = self.world.component_for_entity(playerEntity, system.groupid.GroupId) offensiveSkillEntity = EntityFinder.findOffensiveSkillByGroupId( self.world, meGroupId.getId()) return offensiveSkillEntity
def checkForAttack(self): messages = messaging.get() for message in messages: # PlayerAttack - Player if message.type == MessageType.PlayerAttack: playerEntity = EntityFinder.findPlayer(self.world) playerRenderable = self.world.component_for_entity( playerEntity, system.graphics.renderable.Renderable) playerRenderable.texture.changeAnimation( message.data['characterAttackAnimationType'], playerRenderable.direction, interrupt=True) # EntityAttack - Enemies if message.type == MessageType.EntityAttack: entity = EntityFinder.findCharacterByGroupId( self.world, message.groupId) entityRenderable = self.world.component_for_entity( entity, system.graphics.renderable.Renderable) entityRenderable.texture.changeAnimation( CharacterAnimationType.hitting, entityRenderable.direction, interrupt=True) # EntityAttack - Enemies if message.type == MessageType.EntityStanding: entity = EntityFinder.findCharacterByGroupId( self.world, message.groupId) entityRenderable = self.world.component_for_entity( entity, system.graphics.renderable.Renderable) entityRenderable.texture.changeAnimation( CharacterAnimationType.standing, entityRenderable.direction, interrupt=True) # attackWindup- only for Enemies if message.type == MessageType.attackWindup: entity = EntityFinder.findCharacterByGroupId( self.world, message.groupId) entityRenderable = self.world.component_for_entity( entity, system.graphics.renderable.Renderable) entityRenderable.texture.changeAnimation( CharacterAnimationType.hitwindup, entityRenderable.direction, interrupt=True)
def getPlayerAttack(self): # find player playerEntity = EntityFinder.findPlayer(self.world) if playerEntity is None: return None, None mePlayer = self.world.component_for_entity( playerEntity, system.gamelogic.player.Player) # find characterattack for player meGroupId = self.world.component_for_entity( playerEntity, system.groupid.GroupId) ret = EntityFinder.findOffensiveAttackByGroupId(self.world, meGroupId.getId()) return ret, mePlayer
def showDestAroundPlayer(self): playerEntity = EntityFinder.findPlayer(self.world) meRenderable = self.world.component_for_entity( playerEntity, system.graphics.renderable.Renderable) destCoord = AiHelper.pickDestAroundPlayer( meRenderable, distanceX=meRenderable.texture.width, distanceY=meRenderable.texture.height) messaging.add(type=MessageType.EmitTextureMinimal, data={ 'char': '.', 'timeout': 10.0, 'coordinate': destCoord, 'color': Color.grey })
def handleKeyboardInput(self): playerEntity = EntityFinder.findPlayer(self.world) if playerEntity is None: return player = self.world.component_for_entity( playerEntity, system.gamelogic.player.Player) renderable = self.world.component_for_entity( playerEntity, system.graphics.renderable.Renderable) attackable = self.world.component_for_entity( playerEntity, system.gamelogic.attackable.Attackable) # return if we cannot handle key, but cache it first if attackable.isStunned or player.isAttacking: for message in messaging.getByType(MessageType.PlayerKeypress): # store a few movement commands if len(self.keyCache) >= 1: del (self.keyCache[0]) self.keyCache.append(message) return if not player.isAlive: return didMove = False for message in self.keyCache: # identical to bottom loop atm apm.tick(message.data['time']) didMoveTmp = self.handleKeyPress(message.data['key'], player, renderable, playerEntity) if didMoveTmp: didMove = True self.keyCache.clear() for message in messaging.getByType(MessageType.PlayerKeypress): apm.tick(message.data['time']) didMoveTmp = self.handleKeyPress(message.data['key'], player, renderable, playerEntity) if didMoveTmp: didMove = True # to allow diagonal movement, we allow multiple movement keys per input # cycle, without resetting the timer. if didMove: self.movementTimer.reset()
def canAttackPlayer(self): if self.lastKnownPlayerPosition is None: # we may not yet have received a location. # find it directly via player entity # this is every time we go into chase state playerEntity = EntityFinder.findPlayer(self.brain.owner.world) # player not spawned if playerEntity is not None: playerRenderable = self.brain.owner.world.component_for_entity( playerEntity, system.graphics.renderable.Renderable) self.lastKnownPlayerPosition = playerRenderable.getLocationAndSize( ) canAttack = AiHelper.canAttackPlayer(self.brain.owner, self.lastKnownPlayerPosition) return canAttack
def on_enter(self): self.cooldownTimer.setTimer(0.5) self.attackingTimer.setTimer(4.0) playerEntity = EntityFinder.findPlayer(self.brain.owner.world) if playerEntity is None: return meRenderable = self.brain.owner.world.component_for_entity( self.brain.owner.entity, system.graphics.renderable.Renderable) meGroupId = self.brain.owner.world.component_for_entity( self.brain.owner.entity, system.groupid.GroupId) self.turnIfNecessary(playerEntity, meRenderable, meGroupId) # attack messaging.add(type=MessageType.EntityAttack, groupId=meGroupId.getId(), data=None)
def advance(self, dt): self.time += dt if len(self.speechBubbles) > 0: speechEntry = self.speechBubbles[0] if self.time > speechEntry['timeSpawn']: playerEnt = EntityFinder.findPlayer(self.world) playerGroupId = self.world.component_for_entity( playerEnt, system.groupid.GroupId) directMessaging.add( groupId = playerGroupId.getId(), type = DirectMessageType.activateSpeechBubble, data = { 'text': speechEntry['text'], 'time': speechEntry['timeShow'], 'waitTime': 0, } ) self.speechBubbles.pop(0)
def drawStats(self): x = 2 y = 1 color, attr = ColorPalette.getColorByColorType(ColorType.menu) o = [] enemiesAlive = EntityFinder.numEnemies(world=self.world) enemiesAttacking = EntityFinder.numEnemiesInState(world=self.world, state='attack') enemiesChasing = EntityFinder.numEnemiesInState(world=self.world, state='chase') enemiesWandering = EntityFinder.numEnemiesInState(world=self.world, state='wander') o.append("Enemies:") o.append(" Alive : {}".format(enemiesAlive)) o.append(" Attacking : {}".format(enemiesAttacking)) o.append(" Chasing : {}".format(enemiesChasing)) o.append(" Wandering: {}".format(enemiesWandering)) playerEntity = EntityFinder.findPlayer(self.world) playerRenderable = self.world.component_for_entity( playerEntity, Renderable) o.append('Player:') o.append(' Location:' + str(playerRenderable.getLocation())) o.append('Scene:') o.append(' Name:' + self.sceneManager.currentScene.name) o.append(' Scne State:' + str(self.sceneProcessor.state)) o.append(' Enemies Alive:' + str(self.sceneProcessor.numEnemiesAlive())) o.append(' Enemies Visible:' + str(self.sceneProcessor.numEnemiesVisible())) n = 0 while n < len(o): self.viewport.addstr(y + n, x, o[n], color=color, attr=attr) n += 1
def process(self, dt): self.screenMoveTimer.advance(dt) self.gameoverTimer.advance(dt) for message in messaging.getByType(MessageType.Gameover): self.gameoverTimer.reset() self.gameoverTimer.start() self.setState(State.gameover) messaging.add(type=MessageType.EmitPhenomenaTexture, data={ 'phenomenaTextureType': PhenomenaType.gameover, 'location': Coordinates(10, 10), 'staticLocation': True, 'direction': Direction.right, 'physics': False, }) if self.state is State.gameover: for message in messaging.getByType(MessageType.PlayerKeypress): if self.gameoverTimer.timeIsUp(): messaging.add(type=MessageType.ClearRenderables, data={}) self.setState(State.start) elif self.state is State.start: self.sceneManager.restartScene() self.setState(State.brawl) for message in messaging.getByType(MessageType.EntityDying): # if no enemies are alive, we want to go to the next akt if self.numEnemiesAlive() == 0: self.screenMoveTimer.start() if self.state is not State.gameover: self.setState(State.pushToNextScene) break for message in messaging.getByType(MessageType.PlayerLocation): self.lastKnownPlayerPos = message.data if self.state is State.pushToNextScene: # if suddenly enemies appear, let the player free if self.numEnemiesVisible() > 0: self.setState(State.brawl) if self.state is State.brawl: if (self.numEnemiesVisible() == 0 and not self.enemiesLeftOfChar(self.lastKnownPlayerPos.x)): self.screenMoveTimer.start() self.setState(State.pushToEnemies) if self.state is State.pushToEnemies: if self.numEnemiesVisible() > 0: self.setState(State.brawl) playerScreenCoords = self.viewport.getScreenCoords(message.data) # adjust viewport on move if self.state is State.pushToNextScene: # screen follows player # player is left side of screen (screen pushes player right) if playerScreenCoords.x != 10: distance = int(playerScreenCoords.x - 10) if distance < 0: self.adjustViewport(-1) self.screenMoveTimer.reset() elif distance > 0: self.adjustViewport(1) self.screenMoveTimer.reset() elif self.state is State.pushToEnemies: # screen follows player # player is middle of the screen if playerScreenCoords.x != self.xCenter: distance = int(playerScreenCoords.x - self.xCenter) if distance < 0: self.adjustViewport(-1) self.screenMoveTimer.reset() elif distance > 0: self.adjustViewport(1) self.screenMoveTimer.reset() elif self.state is State.brawl: if not self.enemiesLeftOfChar(self.lastKnownPlayerPos.x): # player can move freely # coming close to left/right of the screen will move it if playerScreenCoords.x >= Config.moveBorderRight: distance = playerScreenCoords.x - Config.moveBorderRight self.adjustViewport(distance) if playerScreenCoords.x <= Config.moveBorderLeft: distance = playerScreenCoords.x - Config.moveBorderLeft self.adjustViewport(distance) # /adjust viewport on move # let the scene decide if we need more enemies self.sceneManager.currentScene.handlePosition( message.data, self.viewport.getx(), self.numEnemiesAlive()) for message in messaging.getByType(MessageType.PlayerKeypress): key = message.data['key'] self.sceneManager.handlePlayerKeyPress(key) if key == ord('k'): logger.info("Scene: Kill All Enemies") self.killAllEnemies() if key == ord('n'): logger.info("Scene: Go to next part") self.killAllEnemies() enemyCell = self.sceneManager.currentScene.getNextEnemy() playerEntity = EntityFinder.findPlayer(self.world) meGroupId = self.world.component_for_entity( playerEntity, system.groupid.GroupId) renderable = self.world.component_for_entity( playerEntity, system.graphics.renderable.Renderable) distX = enemyCell.spawnX - renderable.coordinates.x directMessaging.add( groupId=meGroupId.getId(), type=DirectMessageType.movePlayer, data={ 'x': distX, 'y': 0, 'dontChangeDirection': False, 'whenMoved': None, }, ) # move screen animation if self.screenMoveTimer.timeIsUp( ) and self.lastKnownPlayerPos is not None: playerScreenCoords = self.viewport.getScreenCoords( self.lastKnownPlayerPos) if self.state is State.pushToNextScene: # screen follows player # player is left side of screen (screen pushes player right) if playerScreenCoords.x != 10: distance = int(playerScreenCoords.x - 10) if distance < 0: self.adjustViewport(-1) self.screenMoveTimer.reset() elif distance > 0: self.adjustViewport(1) self.screenMoveTimer.reset() else: self.screenMoveTimer.stop() elif self.state is State.pushToEnemies: # screen follows player # player is middle of the screen if playerScreenCoords.x != self.xCenter: distance = int(playerScreenCoords.x - self.xCenter) if distance < 0: self.adjustViewport(-1) self.screenMoveTimer.reset() elif distance > 0: self.adjustViewport(1) self.screenMoveTimer.reset() else: self.screenMoveTimer.stop() self.sceneManager.advance(dt)
def movePlayer(self): playerEntity = EntityFinder.findPlayer(self.world) if playerEntity is None: return for msg in directMessaging.getByType(DirectMessageType.movePlayer): # usually just one msg... playerGroupId = self.world.component_for_entity( playerEntity, system.groupid.GroupId) playerRenderable = self.world.component_for_entity( playerEntity, system.graphics.renderable.Renderable) x = msg.data['x'] y = msg.data['y'] dontChangeDirection = msg.data['dontChangeDirection'] whenMoved = msg.data['whenMoved'] # only turn, dont walk if not dontChangeDirection and Config.turnOnSpot: if playerRenderable.direction is Direction.left and x > 0: self.updateRenderableDirection(playerRenderable, Direction.right, playerGroupId.getId()) continue if playerRenderable.direction is Direction.right and x < 0: self.updateRenderableDirection(playerRenderable, Direction.left, playerGroupId.getId()) continue playerRenderable.storeCoords() playerRenderable.changeLocationFromStored(x, y) canMove = EntityFinder.isDestinationEmpty(self.world, playerRenderable) if not canMove: # try with one step, instead of the original two if x > 0: x -= 1 playerRenderable.changeLocationFromStored(x, y) elif x < 0: x += 1 playerRenderable.changeLocationFromStored(x, y) canMove = EntityFinder.isDestinationEmpty( self.world, playerRenderable) if not canMove: # we are stuck playerRenderable.restoreCoords() continue else: # can move with new coordinates pass playerRenderable.restoreCoords() didMove = self.moveRenderable(playerRenderable, playerGroupId.getId(), x, y, dontChangeDirection) if didMove: if whenMoved == "showAppearEffect": locCenter = playerRenderable.getLocationCenter() messaging.add(type=MessageType.EmitMirageParticleEffect, data={ 'location': locCenter, 'effectType': ParticleEffectType.appear, 'damage': 0, 'byPlayer': True, 'direction': Direction.none, }) if whenMoved == "showOnKnockback": pass # for now extcords = ExtCoordinates(playerRenderable.coordinates.x, playerRenderable.coordinates.y, playerRenderable.texture.width, playerRenderable.texture.height) messaging.add(type=MessageType.PlayerLocation, data=extcords)
def getAttackVectorToPlayer(owner, meRenderable): # enemy will walk to this distance # allows player to come close # but not inside of him, will walk backwards keepDistance = 1 attackBaseLocation = meRenderable.getAttackBaseLocation() attackBaseLocationInverted = meRenderable.getAttackBaseLocationInverted() playerEntity = EntityFinder.findPlayer(owner.world) # player not spawned if not playerEntity: return plyrRend = owner.world.component_for_entity( playerEntity, system.graphics.renderable.Renderable) playerLocation = plyrRend.getLocation() # check distance, from both the direction we are facing, # and the other one distanceNormal = Utility.distance(playerLocation, attackBaseLocation) distanceInverted = Utility.distance(playerLocation, attackBaseLocationInverted) # logger.info("--- Loc Enemy : {} / {}".format( # meRenderable.coordinates.x, # meRenderable.coordinates.x + meRenderable.texture.width - 1)) # logger.info("--- Loc Player: {}".format(playerRenderable.coordinates.x)) # decide on which reference point we will take # and if we wanna change direction atkLoc = None dontChangeDirection = False if distanceNormal['x'] < distanceInverted['x']: # logger.info("--- n: {} i: {} dontChange, use normal".format( # distanceNormal['x'], distanceInverted['x'] # )) dontChangeDirection = True atkLoc = attackBaseLocation else: # logger.info("--- n: {} i: {} change, use inverted".format( # distanceNormal['x'], distanceInverted['x'] # )) dontChangeDirection = False atkLoc = attackBaseLocationInverted # logger.info("--- Loc Atk : {}".format(attackLoc.x)) moveX = 0 moveY = 0 # check if player overlaps with out attackpoint # if yes, we are too close if (atkLoc.x >= plyrRend.coordinates.x and atkLoc.x <= plyrRend.coordinates.x + plyrRend.texture.width - 1): # logger.info("--- Overlap :-(") # if refLoc.x >= playerRenderable.coordinates.x: if meRenderable.direction is Direction.left: if Config.xDoubleStep: moveX = 2 else: moveX = 1 else: if Config.xDoubleStep: moveX = -2 else: moveX = -1 # logger.info("--- Overlap decision: {}".format(moveX)) else: # logger.info("--- No overlap :-)") playerref = 0 if atkLoc.x <= playerLocation.x + int(plyrRend.texture.width / 2): # logger.info("--- Enemy is left of player") playerref = playerLocation.x else: # logger.info("--- Enemy is right of player. Ex:{} Px:{}".format( # attackLoc.x, playerRenderable.coordinates.x # )) playerref = playerLocation.x + plyrRend.texture.width - 1 tempDistance = atkLoc.x - playerref if tempDistance > keepDistance: if Config.xDoubleStep: moveX = -2 else: moveX = -1 elif tempDistance < -keepDistance: if Config.xDoubleStep: moveX = 2 else: moveX = 1 # logger.info("--- Distance: {} because {} - {} ".format( # tempDistance, attackLoc.x, playerref)) # logger.info("--- Enemy: moveX: {} dontChangeDirection: {}".format( # moveX, dontChangeDirection # )) # we can walk diagonally, no elif here if attackBaseLocation.y < playerLocation.y: moveY = 1 elif attackBaseLocation.y > playerLocation.y + plyrRend.texture.height - 1: moveY = -1 return moveX, moveY, dontChangeDirection
def checkHealth(self): # player playerEntity = EntityFinder.findPlayer(self.world) if playerEntity is not None: player = self.world.component_for_entity(playerEntity, Player) if player.isAlive: playerAttackable = self.world.component_for_entity( playerEntity, Attackable) playerGroupId = self.world.component_for_entity( playerEntity, GroupId) if playerAttackable.isActive and playerAttackable.getHealth( ) <= 0: player.setAlive(False) playerAttackable.setActive(False) messaging.add(type=MessageType.EntityDying, groupId=playerGroupId.getId(), data={}) messaging.add(type=MessageType.Gameover, data={}) # if enemies have less than 0 health, make them gonna die for ent, (meAtk, meEnemy, ai, meGroupId, meRend) in self.world.get_components(Attackable, Enemy, Ai, GroupId, Renderable): if meAtk.getHealth() <= 0: if ai.brain.state.name != 'dead' and ai.brain.state.name != 'dying': # update state ai.brain.pop() ai.brain.push('dying') messaging.add(type=MessageType.EntityDying, groupId=meGroupId.getId(), data={}) # 50% chance to display a fancy death animation if random.choice([True, False]): logger.info(meRend.name + " Death animation deluxe") effect = random.choice([ TextureEmiterEffect.explode, TextureEmiterEffect.pushback ]) messaging.add(type=MessageType.EmitTexture, data={ 'effect': effect, 'pos': meRend.getLocation(), 'frame': meRend.texture.getCurrentFrameCopy(), 'charDirection': meRend.direction, }) meRend.setActive(False) # environment for ent, (destructable, meAtk, meGroupId, meRend) in self.world.get_components(Destructable, Attackable, GroupId, Renderable): if meAtk.getHealth() <= 0: meRend.texture.setActive(False) else: frameCount = meRend.texture.animation.frameCount - 1 d = meAtk.getHealth() / (meAtk.initialHealth / frameCount) animationIndex = frameCount - int(d) if animationIndex != meRend.texture.frameIndex: meRend.texture.advanceStep()