# Different lifebars. import os, pygame, fontfx from listener import Listener from constants import * LIVING, FAILED, WON = range(3) # The base lifebar class from which most other ones inherit. class AbstractLifeBar(Listener, pygame.sprite.Sprite): def __init__(self, playernum, maxlife, songconf, game): pygame.sprite.Sprite.__init__(self) self.gameover = LIVING self.maxlife = maxlife * songconf["life"] self.image = pygame.Surface([204, 28]) self.deltas = {} self.record = [] self.last_record_update = 0 self.failtext = fontfx.embfade("FAILED", 28, 3, [80, 32], [224, 32, 32]) self.failtext.set_colorkey(self.failtext.get_at([0, 0]), RLEACCEL) self.rect = self.image.get_rect() self.rect.top = 30 self.rect.centerx = game.sprite_center + playernum * game.player_offset def set_song(self, *args): self.last_record_update = 0 def stepped(self, pid, dir, curtime, etime, rating, combo): if self.life >= 0: self.life += self.deltas.get(rating, 0) self.life = min(self.life, self.maxlife) def update(self, time): if self.gameover: return False if self.life < 0: self.life = -1 elif self.life > self.maxlife: self.life = self.maxlife if time - self.last_record_update > 0.5 and self.life >= 0: self.record.append(float(self.life) / float(self.maxlife)) self.last_record_update = time # Regular DDR-style lifebar, life from 0 to 100. class LifeBarDisp(AbstractLifeBar): def __init__(self, playernum, theme, songconf, game): AbstractLifeBar.__init__(self, playernum, 1.0, songconf, game) self.life = self.maxlife / 2.0 self.displayed_life = self.life self.deltas = {"V": 0.008, "P": 0.008, "G": 0.004, "B": -0.04, "M": -0.08} self.full, self.empty = theme.get_lifebar() def draw(self, time): time = int(1000 * time) full = self.full[(time / 33) % len(self.full)] empty = self.empty[(time / 33) % len(self.empty)] self.image.blit(empty, [0, 0]) self.image.set_clip([0, 0, int(202 * self.displayed_life / self.maxlife), 28]) self.image.blit(full, [0, 0]) self.image.set_clip() def update(self, time): if self.gameover and self.displayed_life <= 0: return if self.displayed_life < self.life: self.displayed_life += 0.01 elif self.displayed_life > self.life: self.displayed_life -= 0.01 if abs(self.displayed_life - self.life) < 0.01: self.displayed_life = self.life AbstractLifeBar.update(self, time) if self.life < 0: self.gameover = FAILED if self.displayed_life < 0: self.displayed_life = 0 self.draw(time) if self.gameover: self.image.blit(self.failtext, (70, 2)) # A lifebar that only goes down. class DropLifeBarDisp(LifeBarDisp): def __init__(self, playernum, theme, songconf, game): LifeBarDisp.__init__(self, playernum, theme, songconf, game) self.life = self.maxlife # Start at full life for k in self.deltas: if self.deltas[k] > 0: self.deltas[k] = 0 # Only greats make the bar go up. class GreatAttack(LifeBarDisp): def __init__(self, playernum, theme, songconf, game): LifeBarDisp.__init__(self, playernum, theme, songconf, game) self.deltas = {"V": -0.005, "P": -0.005, "G": 0.008, "O": -0.005, "B": -0.02, "M": -0.06} # Tug of war lifebar, increases your lifebar and decreases your opponents'. class TugLifeBarDisp(LifeBarDisp): active_bars = [] def __init__(self, playernum, theme, songconf, game): LifeBarDisp.__init__(self, playernum, theme, songconf, game) self.wontext = fontfx.embfade("WON",28,3,(80,32),(224,32,32)) self.wontext.set_colorkey(self.failtext.get_at((0,0)), RLEACCEL) self.deltas = {"V": 0.02, "P": 0.02, "G": 0.01, "B": -0.01, "M": -0.02 } # If we're player 1, it's a new game, so delete the old lifebars. if playernum == 0: TugLifeBarDisp.active_bars = [self] else: TugLifeBarDisp.active_bars.append(self) def stepped(self, pid, dir, curtime, etime, rating, combo): LifeBarDisp.stepped(self, pid, dir, curtime, etime, rating, combo) for bar in TugLifeBarDisp.active_bars: if bar != self: bar.update_life_opponent(rating) def update_life_opponent(self, rating): if self.life >= 0: self.life -= self.deltas.get(rating, 0) def update(self, time): if self.gameover and self.displayed_life <= 0: return if self.displayed_life < self.life: self.displayed_life += 0.01 elif self.displayed_life > self.life: self.displayed_life -= 0.01 if abs(self.displayed_life - self.life) < 0.01: self.displayed_life = self.life AbstractLifeBar.update(self, time) if self.life < 0: self.gameover = FAILED if self.displayed_life < 0: self.displayed_life = 0 self.draw(time) if self.gameover == WON: self.image.blit(self.wontext, (70, 2)) elif self.gameover == FAILED: self.image.blit(self.failtext, (70, 2)) for lifebar in TugLifeBarDisp.active_bars: if lifebar != self and not lifebar.gameover: lifebar.gameover = WON # Lifebar where doing too good also fails you. class MediocreLifeBarDisp(AbstractLifeBar): def __init__(self, playernum, theme, songconf, game): AbstractLifeBar.__init__(self, playernum, 1.0, songconf, game) self.life = self.maxlife / 2 self.deltas = {"V": 0.04, "P": 0.04, "G": 0.02, "O": -0, "B": -0.02, "M": -0.04 } self.image = pygame.surface.Surface([202, 28]) self.image.fill([255, 255, 255]) def update(self, time): if self.gameover: return AbstractLifeBar.update(self, time) if self.life < 0 or self.life == self.maxlife: self.gameover = FAILED pct = abs(self.life - self.maxlife) / self.maxlife * 2 if pct > 1: pct = max(2 - pct, 0) self.image.fill([int(255 * pct)] * 3) if self.gameover: self.image.blit(self.failtext, (70, 2)) # Oni mode lifebar, anything that breaks a combo loses a life. class OniLifeBarDisp(AbstractLifeBar): lose_sound = pygame.mixer.Sound(os.path.join(sound_path, "loselife.ogg")) def __init__(self, playernum, theme, songconf, game): AbstractLifeBar.__init__(self, playernum, songconf["onilives"], songconf, game) # Override the songconf["diff"] stuff. self.maxlife = self.life = songconf["onilives"] self.deltas = { "O": -1, "B": -1, "M": -1} self.empty = theme.theme_data.get_image('oni-empty.png') self.bar = theme.theme_data.get_image('oni-bar.png') self.width = 192 / self.maxlife self.bar = pygame.transform.scale(self.bar, (self.width, 20)) def set_song(self, pid, bpm, diff, count, hold, feet): self.life = min(self.maxlife, self.life + 1) def broke_hold(self, pid, time, dir, whichone): OniLifeBarDisp.lose_sound.play() self.life -= 1 def stepped(self, pid, dir, curtime, etime, rating, combo): AbstractLifeBar.stepped(self, pid, dir, curtime, etime, rating, combo) if self.deltas.get(rating, 0) < 0: OniLifeBarDisp.lose_sound.play() def update(self, time): if self.gameover: return AbstractLifeBar.update(self, time) self.image.blit(self.empty, [0, 0]) for i in range(self.life): self.image.blit(self.bar, [6 + self.width * i, 4]) if self.life < 0: self.gameover = FAILED if self.gameover: self.image.blit(self.failtext, [70, 2]) bars = [LifeBarDisp, OniLifeBarDisp, DropLifeBarDisp, MediocreLifeBarDisp, TugLifeBarDisp, GreatAttack] lifebar_opt = [(0, "Normal", ""), (1, "Battery", "A few points of life, increasing each song."), (2, "Power Drop", "Like normal, but never goes back up."), (3, "Mediocre", "Fail if you do too poorly or too well."), (4, "Tug of War", "Fight with the other player for life."), (5, "Great Attack", "Only greats make the bar go up.")]