def createFloatingDamage(self, loc, direction, byPlayer, damage): dmgStr = str(damage) speed = 0.1 if byPlayer: color = ColorPalette.getColorByColor(Color.brightcyan) else: color = ColorPalette.getColorByColor(Color.red) n = 0 for char in dmgStr: particle = self.particlePool.pop() particle.init( x=loc.x + n, y=loc.y - 1, life=10, angle=90, speed=speed, fadeout=False, byStep=False, charType=0, active=True, damage=0, damageEveryStep=False, byPlayer=byPlayer, color=color) particle.char = dmgStr[n] self.particleActive.append(particle) n += 1
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 readAnimation( self, characterTextureType :CharacterTextureType, characterAnimationType :CharacterAnimationType, ) -> Animation: ct = characterTextureType.name cat = characterAnimationType.name filename = "data/textures/character/{}/{}_{}.ascii".format(ct, ct, cat) # return fake animation if file does not exist(yet) if not os.path.isfile(filename): animation = Animation() animation.arr = [[['X', 'X', 'X'], ['X', 'X', 'X'], ['X', 'X', 'X']]] animation.height = 3 animation.width = 3 animation.frameCount = 1 animation.frameTime = [10.0] animation.frameColors = [ColorPalette.getColorByColor(Color.white)] logger.debug("Could not find animation {}, replacing".format( filename )) return animation animation = TextureHelper.readAnimationFile(filename) animation.name = "{}_{}".format(ct, cat) filenameYaml = "data/textures/character/{}/{}_{}.yaml".format(ct, ct, cat) TextureHelper.loadYamlIntoAnimation(filenameYaml, animation) return animation
def createHitBurst(self, loc, direction, byPlayer, damage): particleCount = 5 life = 20 spacingAngle = 10.0 n = 0 while n < particleCount: particle = self.particlePool.pop() if direction is Direction.right: angle = (spacingAngle * particleCount / 2) - (spacingAngle * n) else: angle = 180 + (spacingAngle * particleCount / 2) - (spacingAngle * n) x = loc.x y = loc.y particle.init( x=x, y=y, life=life, angle=angle, speed=0.1, fadeout=True, byStep=False, charType=3, active=True, damage=damage, damageEveryStep=False, color=ColorPalette.getColorByColor(Color.grey)) self.particleActive.append(particle) n += 1
def loadYamlIntoAnimation(filename :str, animation :Animation): with open(filename, 'r') as stream: data = yaml.safe_load(stream) try: animation.endless = data['endless'] animation.advanceByStep = data['advanceByStep'] animation.frameColors = data['frameColors'] except TypeError as error: raise Exception("Error, missing field in yaml file {}, error {}".format( filename, error )) # FrameTime can be non-existing, e.g. if 'advanceByStep' = True, # or if it is one frame and endless... # Therefore, frameTime will be None, as defined in Animation if 'frameTime' in data: animation.frameTime = data['frameTime'] # convert to float for (idx, frameTimeEntry) in enumerate(animation.frameTime): animation.frameTime[idx] = float(frameTimeEntry) if 'direction' in data: if data['direction'] == 'left': animation.originalDirection = Direction.left elif data['direction'] == 'right': animation.originalDirection = Direction.right else: animation.originalDirection = Direction.none # colors: # - <Color>: white, brightblue, ... # - ColorType.<ColorType>: background, world, ... for (n, color) in enumerate(data['frameColors']): if color.startswith('ColorType.'): color = color.split('.')[1] colorType = ColorPalette.getColorTypeByStr(color) animation.frameColors[n] = ColorPalette.getColorByColorType( colorType) else: color = ColorPalette.getColorByStr(color) animation.frameColors[n] = ColorPalette.getColorByColor( color)
def showCharAtPos(self, char: str, timeout: float, coordinate: Coordinates, color: Color): textureMinimal = TextureMinimal( char=char, colorArr=[ColorPalette.getColorByColor(color)], timeArr=[timeout], ) renderableMinimal = RenderableMinimal( texture=textureMinimal, coordinates=coordinate, ) self.addRenderableMinimal(renderableMinimal)
def draw2(self, frame: int): """Draws foremost layer (e.g. "pause" sign)""" if self.sceneManager.currentScene.showMap(): self.statusBar.drawStatusbar() if self.showStats: self.drawStats() # not drawing related, but who cares if frame % 1000 == 0: self.logEntityStats() if self.pause: color, attr = ColorPalette.getColorByColor(Color.white) self.viewport.addstr(12, 40, "Paused", color, attr)
def init( self, x :int =0, y :int =0, life :int =0, angle :float =0, speed :int =1, fadeout :bool =True, byStep :bool =False, charType :int =0, active :bool =False, damage :int =0, damageEveryStep :bool =False, byPlayer :bool =True, color =None, ): self.x = x self.y = y self.life = life self.originalLife = life self.angle = angle self.speed = speed self.fadeout = fadeout self.byStep = byStep self.charType = charType self.damage = damage self.damageEveryStep = damageEveryStep self.byPlayer = byPlayer self.angleInRadians = angle * math.pi / 180 self.velocity = { 'x': speed * math.cos(self.angleInRadians), 'y': -speed * math.sin(self.angleInRadians) } self.color, self.attr = ColorPalette.getColorByColor(Color.brightmagenta) if color is not None: self.color = color[0] self.attr = color[1] self.setChar() self.rx = 0.0 self.ry = 0.0 self.movementTimer.setTimer(self.speed) self.active = active
def createChar(self, loc, direction, byPlayer, damage): particle = self.particlePool.pop() x = loc.x y = loc.y particle.init( x=x, y=y, life=100, angle=0, speed=0.0, fadeout=True, byStep=False, charType=3, active=True, damage=damage, damageEveryStep=False, color=ColorPalette.getColorByColor(Color.green)) self.particleActive.append(particle)
def createImpact(self, loc, direction, byPlayer, damage): particle = self.particlePool.pop() particle.init( x=loc.x, y=loc.y, life=10, angle=0, speed=0.0, fadeout=True, byStep=False, charType=4, active=True, damage=0, damageEveryStep=False, color=ColorPalette.getColorByColor(Color.red)) self.particleActive.append(particle)
def getAnimation(self, displayText=None, direction=Direction.right, time=1.5): animation = Animation() animation.width = len(displayText) + 2 animation.height = 4 animation.frameCount = 1 animation.frameTime = [ time, ] animation.frameColors = [ ColorPalette.getColorByColor(Color.white) ] animation.endless = False animation.advanceByStep = False l = animation.width animation.arr = [[]] l1 = [] l1.append('.') l1.extend(list('-' * (l - 2))) l1.append('.') animation.arr[0].append(l1) l2 = [] l2.append('|') l2.extend(list(displayText)) l2.append('|') animation.arr[0].append(l2) l3 = [] l3.append('`') l3.append(',') l3.extend(list('-' * (l - 3))) l3.append('\'') animation.arr[0].append(l3) l4 = [] l4.append('/') l4.extend(list('' * (l - 1))) animation.arr[0].append(l4) return animation
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 convertMapAnsiToUnicode(self): xp_file_layer = self.xpmap['layer_data'][0] for x in range(xp_file_layer['width']): for y in range(xp_file_layer['height']): # {'keycode': 65, 'fore_r': 178, 'fore_g': 134, 'fore_b': 0, # 'back_r': 0, 'back_g': 0, 'back_b': 0} char = xp_file_layer['cells'][x][y]['keycode'] color = ColorPalette.getColorByRgb( xp_file_layer['cells'][x][y]['fore_r'], xp_file_layer['cells'][x][y]['fore_g'], xp_file_layer['cells'][x][y]['fore_b']) # we only accept official palette colors. if it is not recognized, i # gnore character completely (artefact? misclick?) if color is not None: xp_file_layer['cells'][x][y]['color'] = color if char != 32 and char != 0: k = chr(ansitounicode.getUnicode(char)) xp_file_layer['cells'][x][y]['keycode'] = k else: xp_file_layer['cells'][x][y]['keycode'] = '' else: xp_file_layer['cells'][x][y]['keycode'] = ''
def createBullet(self, loc, direction, byPlayer, damage): particle = self.particlePool.pop() if direction is Direction.left: angle = 180 else: angle = 0 particle.init( x=loc.x, y=loc.y, life=100, angle=angle, speed=0.1, fadeout=False, byStep=False, charType=5, active=True, damage=10, damageEveryStep=True, byPlayer=byPlayer, color=ColorPalette.getColorByColor(Color.red)) self.particleActive.append(particle)
def makeEffect(self, effect, pos, x, y, char, columnCount, rowCnt, charDirection): if effect is TextureEmiterEffect.explode: movementX = 0 movementY = 0 if y == 0: movementY = -1 if x == 0: movementX = -1 if y == columnCount - 1: movementY = 1 if x == rowCnt - 1: movementX = 1 c = Coordinates( x=pos.x + x, y=pos.y + y, ) timeArr = [0.1, 0.1, 0.1] colorArr = [ ColorPalette.getColorByColor(Color.brightyellow), ColorPalette.getColorByColor(Color.yellow), ColorPalette.getColorByColor(Color.grey), ] textureMinimal = TextureMinimal(char=char, movementX=movementX, movementY=movementY, timeArr=timeArr, colorArr=colorArr) renderableMinimal = RenderableMinimal( texture=textureMinimal, coordinates=c, ) self.addRenderableMinimal(renderableMinimal) # push away if effect is TextureEmiterEffect.pushback: if charDirection is Direction.right: d = -1 else: d = 1 c = Coordinates( x=pos.x + x, y=pos.y + y, ) timeArr = [0.05, 0.1, 0.2, 0.4] colorArr = [ ColorPalette.getColorByColor(Color.white), ColorPalette.getColorByColor(Color.white), ColorPalette.getColorByColor(Color.grey), ColorPalette.getColorByColor(Color.grey), ] textureMinimal = TextureMinimal(char=char, movementX=d * 2, movementY=0, timeArr=timeArr, colorArr=colorArr) renderableMinimal = RenderableMinimal(texture=textureMinimal, coordinates=c) self.addRenderableMinimal(renderableMinimal)
def createBg(self, width, height, uni=False): box = [] width = self.viewport.win._buffer._width height = self.viewport.win._buffer._height fg, attr = ColorPalette.getColorByColor(Color.black) bg, _ = ColorPalette.getColorByColor(Color.black) w = 1 tl = (ord(u"┌"), fg, attr, bg, w) tr = (ord(u"┐"), fg, attr, bg, w) bl = (ord(u"└"), fg, attr, bg, w) br = (ord(u"┘"), fg, attr, bg, w) h = (ord(u"─"), fg, attr, bg, w) v = (ord(u"│"), fg, attr, bg, w) s = (ord(u" "), fg, attr, bg, w) meWidth = Config.columns meHeight = Config.rows # top line line = [] line.append(tl) n = 0 while n < meWidth - 2: line.append(h) n += 1 line.append(tr) while n < width: line.append(s) n += 1 box.append(line) # middle line = [] line.append(v) n = 0 while n < meWidth - 2: line.append(s) n += 1 line.append(v) # rest while n < width: line.append(s) n += 1 for _ in range(meHeight - 2): box.append(line) # bottom line line = [] line.append(bl) n = 0 while n < meWidth - 2: line.append(h) n += 1 line.append(br) while n < width: line.append(s) n += 1 box.append(line) # rest y = meHeight while y < height: line = [] n = 0 while n < width: line.append(s) n += 1 y += 1 box.append(line) return box
def handleState(self): # interactive, aka a hack, but it works if (self.state is IntroSceneState.wait1 or self.state is IntroSceneState.flydown or self.state is IntroSceneState.drop or self.state is IntroSceneState.flyup): c1, a1 = ColorPalette.getColorByColor(Color.blue) c2, a2 = ColorPalette.getColorByColor(Color.brightblue) self.viewport.addstr(5, 40, "N Key Rollover", c1, a1) self.viewport.addstr(6, 40, "Escape from Hong Kong", c2, a2) c3, a3 = ColorPalette.getColorByColor(Color.cyan) self.viewport.addstr(8, 40, "Moving: arrow keys, shift to strafe", c3, a3) self.viewport.addstr(9, 40, "Select attack: 1 2 3 4", c3, a3) self.viewport.addstr(10, 40, "Attack : space", c3, a3) self.viewport.addstr(11, 40, "Skills : q w e r", c3, a3) self.viewport.addstr(12, 40, "Heal, Port : f g", c3, a3) # state if self.state is IntroSceneState.wait1: # for next scene: Flydown if self.myTimer.timeIsUp(): self.state = IntroSceneState.flydown self.myTimer.setTimer(0.1) self.renderableCopter.setActive(True) logger.debug("Scene: Go to State: Flydown") elif self.state is IntroSceneState.flydown: if self.myTimer.timeIsUp(): self.myTimer.reset() self.renderableCopter.coordinates.y += 1 # for next scene: Drop if self.renderableCopter.coordinates.y == 8: self.myTimer.setTimer(0.1) logger.debug("Scene: Go to State: Drop") self.addRenderable(self.renderablePlayer) self.state = IntroSceneState.drop elif self.state is IntroSceneState.drop: # for next scene: Flyup if self.myTimer.timeIsUp(): self.myTimer.reset() self.renderableCopter.coordinates.y -= 1 if self.renderableCopter.coordinates.y == self.copterSpawn.y: self.myTimer.setTimer(0.1) self.addRenderable(self.renderableEnemy) self.renderableEnemy.texture.changeAnimation( CharacterAnimationType.walking, direction=Direction.left) self.state = IntroSceneState.spawnenemy self.isShowMap = True logger.info("Scene: Go to State: SpawnEnemy") elif self.state is IntroSceneState.spawnenemy: if self.myTimer.timeIsUp(): self.myTimer.reset() self.renderableEnemy.coordinates.x -= 1 self.renderableEnemy.advanceStep() if (self.renderableEnemy.coordinates.x == self.renderablePlayer.coordinates.x + 15): self.renderableEnemy.texture.changeAnimation( CharacterAnimationType.standing, direction=Direction.none) self.myTimer.setTimer(2.0) self.state = IntroSceneState.speakenemy self.textureEmiter.showSpeechBubble( 'The princess is in another castle...', time=3.0, parentRenderable=self.renderableEnemy ) elif self.state is IntroSceneState.speakenemy: if self.myTimer.timeIsUp(): self.state = IntroSceneState.leaveenemy self.renderableEnemy.texture.changeAnimation( CharacterAnimationType.walking, direction=Direction.right) self.myTimer.setTimer(0.1) elif self.state is IntroSceneState.leaveenemy: if self.myTimer.timeIsUp(): self.myTimer.reset() self.renderableEnemy.advanceStep() self.renderableEnemy.coordinates.x += 1 if (self.renderableEnemy.coordinates.x == Config.columns): self.state = IntroSceneState.done elif self.state is IntroSceneState.done: pass
def generateCity(self, width, height): # generate complete map color, attr = ColorPalette.getColorByColor(Color.black) bg, _ = ColorPalette.getColorByColor(Color.black) emptyCell = { 'keycode': '', 'color': color, 'bgcolor': bg, 'attr': attr, } cells = [[copy.copy(emptyCell) for i in range(height)] for j in range(width)] # fill map # street border y = self.topborder x = 0 while x < width: cells[x][y]['keycode'] = '─' cells[x][y]['attr'] = Screen.A_BOLD x += 1 # street horizontal y = self.topborder + 7 x = 0 while x < width: if x % 6 == 0: cells[x][y]['keycode'] = '─' cells[x + 1][y]['keycode'] = '─' cells[x][y]['attr'] = Screen.A_BOLD cells[x + 1][y]['attr'] = Screen.A_BOLD x += 1 # street vertical/diagonal y = self.topborder + 7 x = 0 logging.info("W: {}".format(width)) while x < width - 40: if x % 80 == 0: # logging.info("L: {}".format(x)) xx = 0 yy = 24 while xx < 16: cells[x + xx][yy]['keycode'] = '/' cells[x + xx][yy]['attr'] = Screen.A_BOLD xx += 1 yy -= 1 x += 1 # buildings x = 0 while x < width - 8: xOff = random.choice([-1, -2, 0, 1, 2]) theight = random.choice([4, 5, 6, 7]) yOff = self.topborder - theight + 1 twidth = random.choice([4, 5, 6]) x += xOff y = yOff #logging.info("Create tower: {}/{} height: {} width: {}".format( # x, y, height, width #)) #logging.info("Y: {} {} {}".format(self.topborder, theight, y)) c = self.createTower(theight, twidth) self.insertArr(cells, c, x, y) x += twidth return cells
def createTower(self, height, width): color, attr = ColorPalette.getColorByColor(Color.black) bg, _ = ColorPalette.getColorByColor(Color.black) emptyCell = { 'keycode': '', 'color': color, 'bgcolor': bg, 'attr': attr, } cells = [[copy.copy(emptyCell) for i in range(height)] for j in range(width)] m = ' ' bgColors = random.choice([ ColorPalette.getColorByColor(Color.blue), ColorPalette.getColorByColor(Color.blue), ColorPalette.getColorByColor(Color.black), ]) # attr = random.choice( # None, # Screen.A_BOLD # ) x = 0 while x < len(cells): y = 0 while y < len(cells[x]): # corner bottom left if x == 0 and y == len(cells[0]) - 1: cells[x][y]['keycode'] = '┴' cells[x][y]['attr'] = Screen.A_BOLD # corner top left elif x == 0 and y == 0: cells[x][y]['keycode'] = '┌' cells[x][y]['attr'] = Screen.A_BOLD # corner bottom right elif x == len(cells) - 1 and y == len(cells[0]) - 1: cells[x][y]['keycode'] = '┴' cells[x][y]['attr'] = Screen.A_BOLD # corner top right elif x == len(cells) - 1 and y == 0: cells[x][y]['keycode'] = '┐' cells[x][y]['attr'] = Screen.A_BOLD elif x == 0: cells[x][y]['keycode'] = '│' cells[x][y]['attr'] = Screen.A_BOLD elif x == len(cells) - 1: cells[x][y]['keycode'] = '│' cells[x][y]['attr'] = Screen.A_BOLD elif y == 0: cells[x][y]['keycode'] = '─' cells[x][y]['attr'] = Screen.A_BOLD elif y == len(cells[0]) - 1: cells[x][y]['keycode'] = '─' cells[x][y]['attr'] = Screen.A_BOLD else: cells[x][y]['keycode'] = m cells[x][y]['bgcolor'] = bgColors[0] # no attr for bgcolor y += 1 x += 1 # logging.info("A: {}".format(cells)) return cells
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