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 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 checkForMove(self): for message in messaging.getByType(MessageType.EntityMoved): entity = EntityFinder.findCharacterByGroupId( self.world, message.groupId) renderable = self.world.component_for_entity( entity, system.graphics.renderable.Renderable) # just updated direction # NOTE this only works for CharacterTexture's if message.data['x'] == 0 and message.data['y'] == 0: renderable.texture.changeAnimation( renderable.texture.characterAnimationType, renderable.direction) continue if (renderable.texture.characterAnimationType is CharacterAnimationType.walking): if message.data['didChangeDirection']: renderable.texture.changeAnimation( CharacterAnimationType.walking, renderable.direction) else: renderable.texture.advanceStep() else: renderable.texture.changeAnimation( CharacterAnimationType.walking, renderable.direction)
def printAttackbar(self, color, attr, bgcolor, playerEntity): playerGroupId = self.world.world.component_for_entity( playerEntity, GroupId) playerOffensiveAttack = EntityFinder.findOffensiveAttackByGroupId( self.world.world, playerGroupId.getId()) weaponIdx = 42 self.viewport.addstrStatic(1, weaponIdx, 'W:' + playerOffensiveAttack.getWeaponStr(), color, attr, bg=bgcolor) weaponIdx = 52 self.viewport.addstrStatic(1, weaponIdx, 'APM:' + str(int(apm.getApm() * 60)), color, attr, bg=bgcolor) weaponIdx = 62 self.viewport.addstrStatic(1, weaponIdx, 'DMG/s:' + str(int(damageStat.getDamageStat())), color, attr, bg=bgcolor)
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 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 setSomeSpawnCoordinates(self, renderable, direction): # X if direction is Direction.right: myx = self.viewport.getx() + Config.columns + 1 else: myx = self.viewport.getx() - 1 - renderable.texture.width minY = Config.areaMoveable['miny'] maxY = Config.areaMoveable['maxy'] myy = random.randint(minY, maxY) renderable.setLocation(Coordinates(myx, myy)) # if enemies overlap, move them sideway away from player spotFree = False while not spotFree: if EntityFinder.isDestinationEmpty( world=self.world, renderable=renderable ): spotFree = True else: if direction is Direction.right: renderable.coordinates.x += 3 else: renderable.coordinates.x -= 3
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 advance(self, dt): for particle in self.particleEmiter.particleActive: particle.advance(dt) if not EntityFinder.isDestinationEmptyForParticle( self.world, particle): # Note: it already did damage and everything particle.setActive(False) if not particle.isActive(): self.particleEmiter.unuse(particle)
def checkDefenseMessages(self): for msg in messaging.getByType(MessageType.Defense): location = msg.data['location'] groupId = msg.data['groupId'] entity = EntityFinder.findByGroupId(self.world, groupId) defense = self.world.component_for_entity(entity, Defense) defense.coordinates = location defense.isActive = True defense.timer.reset()
def checkForKnockdown(self): for message in messaging.getByType(MessageType.EntityKnockdown): entity = EntityFinder.findCharacterByGroupId( self.world, message.groupId) meRenderable = self.world.component_for_entity( entity, system.graphics.renderable.Renderable) meRenderable.texture.changeAnimation( characterAnimationType=CharacterAnimationType.knockdown, direction=meRenderable.direction, interrupt=True)
def tryAttacking(self): if self.canAttackTimer.timeIsUp(): logger.debug("{}: Check if i can attack player".format(self.name)) if self.canAttackPlayer(): if (EntityFinder.numEnemiesInState(self.brain.owner.world, 'attack') < Config.maxEnemiesInStateAttacking): self.brain.pop() self.brain.push("attackwindup") self.canAttackTimer.reset()
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 checkForDying(self): for message in messaging.getByType(MessageType.EntityDying): entity = EntityFinder.findCharacterByGroupId( self.world, message.groupId) meRenderable = self.world.component_for_entity( entity, system.graphics.renderable.Renderable) animationIndex = random.randint(0, 1) meRenderable.texture.changeAnimation( characterAnimationType=CharacterAnimationType.dying, direction=meRenderable.direction, subtype=animationIndex, interrupt=False)
def checkForStun(self): for message in messaging.getByType(MessageType.EntityStun): entity = EntityFinder.findCharacterByGroupId( self.world, message.groupId) entityRenderable = self.world.component_for_entity( entity, system.graphics.renderable.Renderable) # here we also store the current animation # by interrupt=True entityRenderable.texture.changeAnimation( CharacterAnimationType.stun, entityRenderable.direction, interrupt=True) for message in messaging.getByType(MessageType.EntityEndStun): entity = EntityFinder.findCharacterByGroupId( self.world, message.groupId) entityRenderable = self.world.component_for_entity( entity, system.graphics.renderable.Renderable) # restore saved animation entityRenderable.texture.previousAnimationRestore()
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 process(self, dt): meRenderable = self.brain.owner.world.component_for_entity( self.brain.owner.entity, system.graphics.renderable.Renderable) meAttackable = self.brain.owner.world.component_for_entity( self.brain.owner.entity, system.gamelogic.attackable.Attackable) meEnemy = self.brain.owner.world.component_for_entity( self.brain.owner.entity, system.gamelogic.enemy.Enemy) if meAttackable.isStunned: return self.lastInputTimer.advance(dt) if self.lastInputTimer.timeIsUp(): self.getInputWander() self.lastInputTimer.reset() if self.timeIsUp(): if (EntityFinder.numEnemiesInState(self.brain.owner.world, 'chase') < Config.maxEnemiesInStateChase): logger.info("{}: Too long wandering, chase again a bit".format( self.owner)) self.brain.pop() self.brain.push("chase") elif Utility.isIdentical(meRenderable.getLocation(), self.destCoord): # No reset of wander state atm, just a new location self.chooseDestination() else: # check if player is close for message in messaging.getByType(MessageType.PlayerLocation): distance = Utility.distance( message.data, meRenderable.getLocation()) if distance['sum'] < meEnemy.enemyInfo.wanderAttackDistance: logger.info("{}: Player is close, chasing".format(self.owner)) self.brain.pop() self.brain.push("chase")
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 moveEnemy(self): for msg in directMessaging.getByType(DirectMessageType.moveEnemy): entity = EntityFinder.findCharacterByGroupId( self.world, msg.groupId) if entity is None: # May be already deleted? continue meRenderable = self.world.component_for_entity( entity, system.graphics.renderable.Renderable) # these are the actual x/y position change we will use to move x = msg.data['x'] y = msg.data['y'] # turning on the spot if meRenderable.direction is Direction.left and x > 0: self.updateRenderableDirection(meRenderable, Direction.right, msg.groupId) continue if meRenderable.direction is Direction.right and x < 0: self.updateRenderableDirection(meRenderable, Direction.left, msg.groupId) continue meRenderable.storeCoords() meRenderable.changeLocationFromStored(x, y) if msg.data['force']: canMove = True # push player out of the way, if there isDestEmpty = EntityFinder.isDestinationEmpty( self.world, meRenderable) if not isDestEmpty: if EntityFinder.isDestinationWithPlayer( self.world, meRenderable): directMessaging.add( groupId=0, type=DirectMessageType.movePlayer, data={ 'x': x, 'y': 0, 'dontChangeDirection': True, 'whenMoved': None, }, ) else: canMove = EntityFinder.isDestinationEmpty( self.world, meRenderable) if not canMove: # seems we cannot move in the chose direction. # if there are two components in the coordinates, just try one of # them if x != 0 and y != 0: # try x. yes this is ugly, but fast x = msg.data['x'] y = 0 meRenderable.changeLocationFromStored(x, y) canMove = EntityFinder.isDestinationEmpty( self.world, meRenderable) if not canMove: # try y... ugh x = 0 y = msg.data['y'] meRenderable.changeLocationFromStored(x, y) canMove = EntityFinder.isDestinationEmpty( self.world, meRenderable) # check if we are stuck if not canMove: meRenderable.restoreCoords() isStuck = not EntityFinder.isDestinationEmpty( self.world, meRenderable) if isStuck: logger.info( "{}: Overlaps, force way out".format(meRenderable)) # force our way out of here. do intended path x = msg.data['x'] y = msg.data['y'] canMove = True else: # not stuck, just wait until we are free, # as another enemy most likely blocks our way logger.info( "{}: Does not overlap, wait until moving".format( meRenderable)) pass meRenderable.restoreCoords() if canMove: self.moveRenderable(meRenderable, msg.groupId, x, y, msg.data['dontChangeDirection'], msg.data['updateTexture'])
def checkReceiveDamage(self): healthUpdated = False for msg in directMessaging.getByType(DirectMessageType.receiveDamage): entity = EntityFinder.findAttackableByGroupId( self.world, msg.groupId) if entity is None: # May be already deleted? continue meRenderable = self.world.component_for_entity(entity, Renderable) meAttackable = self.world.component_for_entity(entity, Attackable) meGroupId = self.world.component_for_entity(entity, GroupId) damage = msg.data['damage'] byPlayer = msg.data['byPlayer'] direction = msg.data['direction'] knockback = msg.data['knockback'] stun = msg.data['stun'] isPlayer = self.world.has_component(entity, Player) # enemy can attack player, and vice-versa if not byPlayer ^ isPlayer: continue if damage == 0: continue # change health meAttackable.adjustHealth(-1 * damage) healthUpdated = True logger.info("{} got {} damage, new health: {}".format( meRenderable, damage, meAttackable.getHealth())) # gfx: show floating damage numbers if Config.showEnemyDamageNumbers: messaging.add(type=MessageType.EmitMirageParticleEffect, data={ 'location': meRenderable.getLocationTopCenter(), 'effectType': ParticleEffectType.floatingDamage, 'damage': damage, 'byPlayer': byPlayer, 'direction': Direction.none, }) # gfx: emit on-hit particles if Config.showBurstOnImpact: if damage > Config.showBurstOnImpactDamage: messaging.add( type=MessageType.EmitMirageParticleEffect, data={ 'location': meRenderable.getAttackBaseLocationInverted(), 'effectType': ParticleEffectType.hitBurst, 'damage': 0, 'byPlayer': byPlayer, 'direction': direction, }) # no stun, knockdown, knockback, or new color if there is no health left # (animations may overwrite each other) if meAttackable.getHealth() <= 0.0: continue # gfx: set texture color healthPercentage = meAttackable.getHealthPercentage() if healthPercentage > 0.5: meRenderable.texture.setOverwriteColorFor( Config.overwriteColorTime, ColorPalette.getColorByColor(Color.yellow)) else: meRenderable.texture.setOverwriteColorFor( Config.overwriteColorTime, ColorPalette.getColorByColor(Color.red)) # handle: stun if stun and meAttackable.isStunnable(): stunTime = meAttackable.stunTime meAttackable.stunTimer.setTimer(timerValue=stunTime) meAttackable.stunTimer.start() meAttackable.isStunned = True meAttackable.addStun(stunTime=stunTime) # handle: knockdown if random.random() < meAttackable.knockdownChance: messaging.add( type=MessageType.EntityKnockdown, data={}, groupId=meGroupId.getId(), ) else: messaging.add( type=MessageType.EntityStun, data={ 'timerValue': stunTime, }, groupId=meGroupId.getId(), ) # no additional effects continue # handle: knockback if knockback and random.random() < meAttackable.knockbackChance: if direction is Direction.left: x = -2 else: x = 2 if isPlayer: directMessaging.add( groupId=meGroupId.getId(), type=DirectMessageType.movePlayer, data={ 'x': x, 'y': 0, 'dontChangeDirection': True, 'whenMoved': "showOnKnockback", }, ) else: directMessaging.add( groupId=meGroupId.getId(), type=DirectMessageType.moveEnemy, data={ 'x': x, 'y': 0, 'dontChangeDirection': True, 'updateTexture': False, 'force': True, }, ) # no additional effects continue return healthUpdated
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()
def test_renderableCollisionDetection(self): game.isunittest.setIsUnitTest() fileTextureLoader.loadFromFiles() self.viewport = MockWin(20, 10) self.world = esper.World() self.textureEmiter = None particleEmiter = ParticleEmiter(viewport=self.viewport) renderableProcessor = RenderableProcessor( textureEmiter=self.textureEmiter, particleEmiter=particleEmiter) movementProcessor = MovementProcessor(mapManager=None) inputProcessor = InputProcessor() renderableMinimalProcessor = RenderableMinimalProcessor( viewport=self.viewport, textureEmiter=self.textureEmiter) self.world.add_processor(inputProcessor) self.world.add_processor(movementProcessor) self.world.add_processor(renderableMinimalProcessor) self.world.add_processor(renderableProcessor) # Player playerEntity = self.world.create_entity() texture = CharacterTexture( characterTextureType=CharacterTextureType.player, characterAnimationType=CharacterAnimationType.standing, name='Player') coordinates = Coordinates(10, 10) playerRenderable = Renderable(texture=texture, viewport=self.viewport, parent=None, coordinates=coordinates, direction=Direction.right, name='Player') physics = Physics() self.world.add_component(playerEntity, playerRenderable) self.world.add_component(playerEntity, physics) # /Player # Enemy enemyEntity = self.world.create_entity() texture = CharacterTexture( characterTextureType=CharacterTextureType.player, characterAnimationType=CharacterAnimationType.standing, name='Enemy') coordinates = Coordinates(10, 10) enemyRenderable = Renderable(texture=texture, viewport=self.viewport, parent=None, coordinates=coordinates, direction=Direction.right, name='Enemy') physics = Physics() self.world.add_component(enemyEntity, enemyRenderable) self.world.add_component(playerEntity, physics) # /Enemy # process it targetFrameTime = 1.0 / Config.fps # sprites overlap, but not with chars (foot is in shoulder) # o # /|\ # o/ \ # /|\ # / \ enemyRenderable.coordinates.y -= 2 enemyRenderable.coordinates.x += 2 self.world.process(targetFrameTime) self.viewport.internalPrint() overlap = enemyRenderable.overlapsWith(playerRenderable) self.assertTrue(overlap) # inprecise check, true overlap = playerRenderable.overlapsWithRenderablePixel(enemyRenderable) self.assertFalse(overlap) # precise check, false overlap = enemyRenderable.overlapsWithRenderablePixel(playerRenderable) self.assertFalse(overlap) # precise check, false empty = EntityFinder.isDestinationEmpty(self.world, enemyRenderable) self.assertTrue(empty) empty = EntityFinder.isDestinationEmpty(self.world, playerRenderable) self.assertTrue(empty) distance = enemyRenderable.distanceToBorder(playerRenderable) self.assertTrue(distance['x'] == -1) self.assertTrue(distance['y'] == -1)