def setup(self): super(AIBlocker, self).setup() # change milliseconds to seconds (as returned by the system clock) self.movement_timer = Timer() self.movement_timer.alarm = self.update_freq self.block_timer = Timer() temp = [] for ani in AIBlocker.defeat_animations: try: temp.append(self.avatar.get_animation(ani)) except KeyError: pass self.defeat_animations = temp get_animation = self.avatar.get_animation self.forward_animation = get_animation(self.forward_animation) self.backward_animation = get_animation(self.backward_animation) self.idle_animation = get_animation(self.idle_animation) # block frames are frames that contain hitboxes that can block attacks self.block_frames = [] # search all the animations and make a list of block frames for anim in self.avatar.animations.values(): if anim not in self.defeat_animations: if anim.frames[0] != []: self.block_frames.append(anim.frames[0])
def main(): timer = Timer(1., callback) try: timer.start() while True: pass except KeyboardInterrupt: timer.stop()
def setup(self): super(AIFighter, self).setup() self.all_frames = [] self.next_animation = None self.in_attack = False # flagged if we are attacking self.ai_timer = Timer() for anim in self.avatar.animations.values(): if anim not in self.defeat_animations: self.all_frames.extend(anim.frames)
def __init__(self, parent=None): super(SimpleAvatar, self).__init__(parent) self.callback = None # this is called when animation is finished self.current_frame_no = 0 self.current_animation = None self.previous_frame = None self.callback = None self._is_paused = False self.looped = 0 # timer initialization self.timer = Timer()
class SimpleAvatar(StaticAvatar): def __init__(self, parent=None): super(SimpleAvatar, self).__init__(parent) self.callback = None # this is called when animation is finished self.current_frame_no = 0 self.current_animation = None self.previous_frame = None self.callback = None self._is_paused = False self.looped = 0 # timer initialization self.timer = Timer() # this is an override @property def state(self): return (self.current_animation, self.current_frame_no) def add_animation(self, anim): self.current_animation = anim """ BUG: we only test the next frame. its possible the if the system is too slow that the animation could lag behind because frames won't get dropped """ def update(self, time): self.time += time if self._is_paused == True: return # ttl == -1: special way to end an animation. if self.current_frame.ttl == -1: self.paused = True self.timer.update(time) if self.timer.finished: self.advance_frame() # sets the children of this to None, so that they can be garbage collected. # always call super last def cleanup(self): self.current_animation.cleanup() super(SimpleAvatar, self).cleanup() def advance_frame(self): if self._is_paused and self.current_frame.pause: return self.paused self.current_frame_no += 1 if self.current_frame_no >= len(self.current_animation): # the animation has reached the end if self.current_animation.looping == 0: return self.stop() # loop, but count the loops elif self.current_animation.looping > 0: if self.looped > self.current_animation.looping: self.stop() else: self.set_frame(self.current_animation.loop_frame) self.looped += 1 # loop forever, don't count the loops else: self.set_frame(self.current_animation.loop_frame) else: # just set the next frame self.set_frame(self.current_frame_no) def set_frame(self, frame_no): # deref for speed new_frame = self.current_animation.frames[frame_no] self.previous_frame = self.current_frame self.current_frame = new_frame self.current_frame_no = frame_no self.dirty = 1 if new_frame.face(self.facing) == False: new_frame.update(self.position) # handle frames that may want to move the avatar's position pos = list(self.position) if new_frame.move_avatar != (0,0): pos[0] = pos[0] + new_frame.move_avatar[0] pos[1] = pos[1] + new_frame.move_avatar[1] # update the parent, engine will update us later self.parent.set_position(pos) new_frame.update(pos) new_frame.sound.stop() new_frame.sound.play() self.timer.alarm = self.current_frame.ttl #@property def get_paused(self): return self._is_paused #@paused.setter def set_paused(self, value): self._is_paused = value if value == False: self.previous_frame_no = self.current_frame_no self.dirty = 0 paused = property(get_paused, set_paused) def play(self, name=None, start_frame=0, callback=None, arg=[]): if self.paused: return # reset some state stuff self.looped = 0 self.dirty = 1 self.paused = False if callback != None: self.callback = (callback, arg) debug("playing %s, %s: %s\n" % (self.current_animation, self.dirty, self)) self.set_frame(start_frame) def stop(self): self.paused = True if self.callback != None: self.callback[0](*self.callback[1])
class AIBlocker(CpuFighter): """ CPU AI class that will block attacks. Can be used as a base class for human players to provide autoblocking The trick used here is unique because of the animation ripped from IK+. Most animations are only 2-3 frames long, and the 1st or 2nd frame in some animations could be used as a block. The autoblock works by first detecting a hit from the other fighter, then changing the animation to on that includes a blocking frame, which could be a kick, block, etc. It is cheating, in a pure sense, since it relies on first taking a hit. Other solutions may come later. """ forward_animation = "walk forward" backward_animation = "walk backward" idle_animation = "idle" defeat_animations = ["fall backward", "fall forward"] banned_animations = ["crazy"] difficulty = 10 # x/100 update_freq = 30 # milliseconds between updating personal_space = 50 # will not move if distance is less than x aggressiveness = 100 # x/100 def reset(self): super(AIBlocker, self).reset() def setup(self): super(AIBlocker, self).setup() # change milliseconds to seconds (as returned by the system clock) self.movement_timer = Timer() self.movement_timer.alarm = self.update_freq self.block_timer = Timer() temp = [] for ani in AIBlocker.defeat_animations: try: temp.append(self.avatar.get_animation(ani)) except KeyError: pass self.defeat_animations = temp get_animation = self.avatar.get_animation self.forward_animation = get_animation(self.forward_animation) self.backward_animation = get_animation(self.backward_animation) self.idle_animation = get_animation(self.idle_animation) # block frames are frames that contain hitboxes that can block attacks self.block_frames = [] # search all the animations and make a list of block frames for anim in self.avatar.animations.values(): if anim not in self.defeat_animations: if anim.frames[0] != []: self.block_frames.append(anim.frames[0]) # make sure fighter has enough space to fight, and is not # moving out-of-bounds. return True if avatar needs to change def position_self(self): foe = self.match.closest_foe(self) x = self.position[0] if self.avatar.facing == 0: if foe.position[0] > x: self.reset() self.avatar.face(1) return True else: if foe.position[0] < x: self.reset() self.avatar.face(0) return True # if self.avatar.current_animation != self.idle_animation: # return False # left bounds of screen if x < 40: self.avatar.face(1) self.avatar.play(self.forward_animation) return True # right bounds elif x > 290: self.avatar.face(0) self.avatar.play(self.forward_animation) return True return False # used to back away from the other fighter def get_space(self): foe = self.match.closest_foe(self) x = self.position[0] if self.avatar.current_animation != self.idle_animation: return False if abs(x - foe.position[0]) <= self.personal_space: if random.random() <= .75: self.avatar.play(self.backward_animation) else: self.avatar.play(self.forward_animation) return True # stop walking! elif self.avatar.current_animation in \ [self.backward_animation, self.forward_animation]: self.reset() return True # rising means that odds are higher as difficulty is higher def rand_diff(self, easy, difficult): if easy > difficult: mod = float(float(100 - self.difficulty) / float(100)) magic = int(mod * float(easy - difficult) + difficult) else: mod = float(float(self.difficulty) / float(100)) magic = int(mod * float(difficult - easy) + easy) # print "Magic:", magic if random.randint(0, magic) == 0: return True else: return False def update(self, time): self.avatar.update(time) self.movement_timer.update(time) # dead, dont do anything if self.avatar.current_animation in self.defeat_animations: return True if self.movement_timer.finished: # make sure we are in the area if self.position_self(): self.movement_timer.alarm = random.randint(300, 700) return True # position ourselves away from the opponent if self.get_space(): self.movement_timer.alarm = random.randint(300, 800) return True # elif self.avatar.current_animation in \ # [self.backward_animation, self.forward_animation]: # self.reset() # return True self.movement_timer.alarm = self.update_freq * 4 if self.auto_block != None: self.block_timer.update(time) if self.block_timer.finished: self.unset_hold() return True # test if the attack's frame is still the same as when attacked avatar = self.auto_block[1].parent.parent.parent # stop blocking when the other player's animation frame changes if avatar.current_frame != self.auto_block[1].parent: # self.unset_hold() pass def handle_attack(self, attack): if random.random() * 100 > 101 - self.difficulty: self.update_block_frames() other = attack[0].parent.parent.parent block = self.plan_block(attack) # see if we can block if len(block) > 0: evasive_manuever = block[random.randint(0, len(block) - 1)] self.avatar.play(evasive_manuever) return self._test_attack(attack) evade = self.plan_evade(attack) # nope, can we evade it? if len(evade) > 0: evasive_manuever = evade[random.randint(0, len(evade) - 1)] self.avatar.play(evasive_manuever) r = attack[0].collidelist(self.avatar.current_frame.block_box) return self._test_attack(attack) else: return True def _test_attack(self, attack): r = attack[0].collidelist(self.avatar.current_frame.block_box) if r > -1: self.set_hold(attack) return False r = attack[0].collidelist(self.avatar.current_frame.dmg_box) if r > -1: return True return None # moves that could cause a block (parry) def plan_block(self, attack): hit = attack[0] other = attack[0].parent.parent.parent possible = [frame.parent for frame in self.block_frames \ if hit.collidelistall(frame.block_box) != []] return possible def plan_evade(self, attack): hit = attack[0] other = attack[0].parent.parent.parent possible = [frame.parent for frame in self.block_frames \ if hit.collidelistall(frame.dmg_box) == []] return possible def update_block_frames(self): # we have to call update() on the frames to update hitboxes [frame.face(self.avatar.facing) for frame in self.block_frames] [frame.update(self.position) for frame in self.block_frames] def set_hold(self, attack): self.auto_block = attack self.avatar.paused = True self.block_timer.alarm = 250 def unset_hold(self): self.auto_block = None self.avatar.paused = False
class AIFighter(AIBlocker): """ CPU AI class that can perform attacks. Since this class cannot block, it should (and is) be a subclass of another class that can block. The built-in timer will determine when the AI will search for a move. When the timer is finished, the class will search through attacking frames and determine which animations would deal damage, then choose one at random. """ def setup(self): super(AIFighter, self).setup() self.all_frames = [] self.next_animation = None self.in_attack = False # flagged if we are attacking self.ai_timer = Timer() for anim in self.avatar.animations.values(): if anim not in self.defeat_animations: self.all_frames.extend(anim.frames) def reset(self): super(AIFighter, self).reset() self.ai_timer.alarm = self.update_freq self.in_attack = False def attack_landed(self, attack): super(AIFighter, self).attack_landed(attack) self.in_attack = False def attack_blocked(self, attack): super(AIFighter, self).attack_blocked(attack) self.in_attack = False def attack_missed(self, attack=None): super(AIFighter, self).attack_missed(attack) self.in_attack = False def handle_attack(self, attack): if self.in_attack: return True else: return super(AIFighter, self).handle_attack(attack) def set_hold(self, attack): # don't block during an attack super(AIFighter, self).set_hold(attack) hold = self.avatar.current_frame.ttl self.ai_timer.alarm = random.randint(hold, hold * 3) def update(self, time): update = super(AIFighter, self).update(time) self.ai_timer.update(time) # the super has already made a change to the avatar if update == True: return True # we are attacking right now, so just let it be... if self.ai_timer.finished: # if we are attacking, then let it finish if self.in_attack: return # make it dumb by stopping once in a while if self.rand_diff(5, 40): self.ai_timer.alarm = random.randint(250, 1000) return # get a list of stuff we could do here to punish options = self.plan_attack() # WE DON'T WANT THE BANNED ONES for ani in self.banned_animations: try: options.remove(ani) except ValueError: pass if options == []: # play random animation, just for variety if self.rand_diff(5, 15): ani = self.block_frames[ random.randint(0, len(self.block_frames) - 1)].parent self.avatar.play(ani) self.ai_timer.alarm = random.randint(250, 1000) return # if we are idling, then we can walk foe = self.match.closest_foe(self) if self.avatar.current_animation == self.idle_animation: if abs(foe.position[0] - self.position[ 0]) > self.personal_space: self.avatar.play(self.forward_animation) self.ai_timer.alarm = random.randint(60, 120) return True else: # throw an attack we can land if random.random() * 100 > 101 - self.difficulty: if self.avatar.current_animation == self.idle_animation: attack = options[random.randint(0, len(options) - 1)] self.avatar.play(attack) # BUG: causes race conditions # self.in_attack = attack self.ai_timer.alarm = random.randint(200, 400) return else: self.avatar.play(self.idle_animation) self.ai_timer.alarm = random.randint(120, 200) self.ai_timer.alarm = self.update_freq # return a list of all frames that will land an attack def plan_attack(self, state=None): [frame.face(self.avatar.facing) for frame in self.all_frames] [frame.update(self.position) for frame in self.all_frames] possible = [frame.parent for frame in self.all_frames \ if self.avatar.resolve_attack(frame) != []] return possible
def Main(): Screen.WakeScreen() Timer.SetTimeOut('sleep_screen', 7, Screen.SleepScreen, permanent=True) RefreshDesktop()
self.history = history def emit(self, record): current_time = time.strftime("%H:%M:%S", time.gmtime()) message = f"{current_time} - {record.name} - {record.msg}" print(message) self.history.insert(0, message) self.history.pop() if args.display_enabled: for h in list(logger.handlers): logger.removeHandler(h) logger.addHandler(Handler(log)) timer = Timer(args) controller = Controller(args) vehicle = Vehicle(args, timer, controller) display = Display(args, timer, controller, vehicle) def restart(display, sig, frame): if display: display.down() logger.info("restarting...") try: p = psutil.Process(os.getpid()) for handler in p.open_files() + p.connections(): os.close(handler.fd) except Exception as e:
def Thread(): serial_port = SystemState.PhoneState.serial_port # Infinite loop to pass found messages to InterruptSystem() in cobblr. while True: # Looks for incomming serial messages (calls, texts, etc). try: serial_data = serial_port.readlines() except serial.SerialException: serial_data = [] # Evil. serial_data = ParseSerialData(serial_data) if len(serial_data) > 0: print 'serial data: ', serial_data # Call related interrupts if len(serial_data) > 0: message_type = serial_data[0] if message_type == 'RING': serial_data = serial_data[1].strip() stripped_number = serial_data.split('"')[1].strip('"') Screen.WakeScreen() # Setting RING timeout timer to hang up if NO CARRIER is not received. callback = Menu.Back callback_args = {'change_application': True} Timer.DeleteTimeOut('ring_timeout') Timer.SetTimeOut('ring_timeout', 6, callback, callback_args) # Changes menu callback_args = { 'screen_mode': 3, 'application': 'phone', 'change_application': True, 'store_history': False } message = { 'callback': Menu.JumpTo, 'callback_args': callback_args } SystemState.interrupt_queue.put(message) # Print's 'Incomming Call' on the screen. callback_args = { 'permatext': True, 'text': 'Incomming Call', 'text_type': 'message' } message = { 'callback': TextWriter.Write, 'callback_args': callback_args } SystemState.interrupt_queue.put(message) # Print's the phone number on the screen. callback_args = { 'permatext': True, 'text': stripped_number, 'text_type': 'subtext' } message = { 'callback': TextWriter.Write, 'callback_args': callback_args } SystemState.interrupt_queue.put(message) if message_type == 'ATA': Timer.DeleteTimeOut('ring_timeout') # If someone hang's up, go back to the lass application. if message_type == 'NO CARRIER': Timer.DeleteTimeOut('ring_timeout') callback_args = {'change_application': True} message = { 'callback': Menu.Back, 'callback_args': callback_args } SystemState.interrupt_queue.put(message)
class AIBlocker(CpuFighter): """ CPU AI class that will block attacks. Can be used as a base class for human players to provide autoblocking The trick used here is unique because of the animation ripped from IK+. Most animations are only 2-3 frames long, and the 1st or 2nd frame in some animations could be used as a block. The autoblock works by first detecting a hit from the other fighter, then changing the animation to on that includes a blocking frame, which could be a kick, block, etc. It is cheating, in a pure sense, since it relies on first taking a hit. Other solutions may come later. """ forward_animation = "walk forward" backward_animation = "walk backward" idle_animation = "idle" defeat_animations = ["fall backward", "fall forward"] banned_animations = ["crazy"] difficulty = 10 # x/100 update_freq = 30 # milliseconds between updating personal_space = 50 # will not move if distance is less than x aggressiveness = 100 # x/100 def reset(self): super(AIBlocker, self).reset() def setup(self): super(AIBlocker, self).setup() # change milliseconds to seconds (as returned by the system clock) self.movement_timer = Timer() self.movement_timer.alarm = self.update_freq self.block_timer = Timer() temp = [] for ani in AIBlocker.defeat_animations: try: temp.append(self.avatar.get_animation(ani)) except KeyError: pass self.defeat_animations = temp get_animation = self.avatar.get_animation self.forward_animation = get_animation(self.forward_animation) self.backward_animation = get_animation(self.backward_animation) self.idle_animation = get_animation(self.idle_animation) # block frames are frames that contain hitboxes that can block attacks self.block_frames = [] # search all the animations and make a list of block frames for anim in self.avatar.animations.values(): if anim not in self.defeat_animations: if anim.frames[0] != []: self.block_frames.append(anim.frames[0]) # make sure fighter has enough space to fight, and is not # moving out-of-bounds. return True if avatar needs to change def position_self(self): foe = self.match.closest_foe(self) x = self.position[0] if self.avatar.facing == 0: if foe.position[0] > x: self.reset() self.avatar.face(1) return True else: if foe.position[0] < x: self.reset() self.avatar.face(0) return True #if self.avatar.current_animation != self.idle_animation: # return False # left bounds of screen if x < 40: self.avatar.face(1) self.avatar.play(self.forward_animation) return True # right bounds elif x > 290: self.avatar.face(0) self.avatar.play(self.forward_animation) return True return False # used to back away from the other fighter def get_space(self): foe = self.match.closest_foe(self) x = self.position[0] if self.avatar.current_animation != self.idle_animation: return False if abs(x - foe.position[0]) <= self.personal_space: if random.random() <= .75: self.avatar.play(self.backward_animation) else: self.avatar.play(self.forward_animation) return True # stop walking! elif self.avatar.current_animation in \ [self.backward_animation, self.forward_animation]: self.reset() return True # rising means that odds are higher as difficulty is higher def rand_diff(self, easy, difficult): if easy > difficult: mod = float(float(100-self.difficulty) / float(100)) magic = int(mod * float(easy - difficult) + difficult) else: mod = float(float(self.difficulty) / float(100)) magic = int(mod * float(difficult - easy) + easy) #print "Magic:", magic if random.randint(0, magic) == 0: return True else: return False def update(self, time): self.avatar.update(time) self.movement_timer.update(time) # dead, dont do anything if self.avatar.current_animation in self.defeat_animations: return True if self.movement_timer.finished: # make sure we are in the area if self.position_self(): self.movement_timer.alarm = random.randint(300, 700) return True # position ourselves away from the opponent if self.get_space(): self.movement_timer.alarm = random.randint(300, 800) return True #elif self.avatar.current_animation in \ # [self.backward_animation, self.forward_animation]: # self.reset() # return True self.movement_timer.alarm = self.update_freq * 4 if self.auto_block != None: self.block_timer.update(time) if self.block_timer.finished: self.unset_hold() return True # test if the attack's frame is still the same as when attacked avatar = self.auto_block[1].parent.parent.parent # stop blocking when the other player's animation frame changes if avatar.current_frame != self.auto_block[1].parent: #self.unset_hold() pass def handle_attack(self, attack): if random.random() * 100 > 101 - self.difficulty: self.update_block_frames() other = attack[0].parent.parent.parent block = self.plan_block(attack) # see if we can block if len(block) > 0: evasive_manuever = block[random.randint(0, len(block)-1)] self.avatar.play(evasive_manuever) return self._test_attack(attack) evade = self.plan_evade(attack) # nope, can we evade it? if len(evade) > 0: evasive_manuever = evade[random.randint(0, len(evade)-1)] self.avatar.play(evasive_manuever) r = attack[0].collidelist(self.avatar.current_frame.block_box) return self._test_attack(attack) else: return True def _test_attack(self, attack): r = attack[0].collidelist(self.avatar.current_frame.block_box) if r > -1: self.set_hold(attack) return False r = attack[0].collidelist(self.avatar.current_frame.dmg_box) if r > -1 : return True return None # moves that could cause a block (parry) def plan_block(self, attack): hit = attack[0] other = attack[0].parent.parent.parent possible = [ frame.parent for frame in self.block_frames \ if hit.collidelistall(frame.block_box) != [] ] return possible def plan_evade(self, attack): hit = attack[0] other = attack[0].parent.parent.parent possible = [ frame.parent for frame in self.block_frames \ if hit.collidelistall(frame.dmg_box) == [] ] return possible def update_block_frames(self): # we have to call update() on the frames to update hitboxes [ frame.face(self.avatar.facing) for frame in self.block_frames ] [ frame.update(self.position) for frame in self.block_frames ] def set_hold(self, attack): self.auto_block = attack self.avatar.paused = True self.block_timer.alarm = 250 def unset_hold(self): self.auto_block = None self.avatar.paused = False
class AIFighter(AIBlocker): """ CPU AI class that can perform attacks. Since this class cannot block, it should (and is) be a subclass of another class that can block. The built-in timer will determine when the AI will search for a move. When the timer is finished, the class will search through attacking frames and determine which animations would deal damage, then choose one at random. """ def setup(self): super(AIFighter, self).setup() self.all_frames = [] self.next_animation = None self.in_attack = False # flagged if we are attacking self.ai_timer = Timer() for anim in self.avatar.animations.values(): if anim not in self.defeat_animations: self.all_frames.extend(anim.frames) def reset(self): super(AIFighter, self).reset() self.ai_timer.alarm = self.update_freq self.in_attack = False def attack_landed(self, attack): super(AIFighter, self).attack_landed(attack) self.in_attack = False def attack_blocked(self, attack): super(AIFighter, self).attack_blocked(attack) self.in_attack = False def attack_missed(self, attack=None): super(AIFighter, self).attack_missed(attack) self.in_attack = False def handle_attack(self, attack): if self.in_attack: return True else: return super(AIFighter, self).handle_attack(attack) def set_hold(self, attack): # don't block during an attack super(AIFighter, self).set_hold(attack) hold = self.avatar.current_frame.ttl self.ai_timer.alarm = random.randint(hold, hold*3) def update(self, time): update = super(AIFighter, self).update(time) self.ai_timer.update(time) # the super has already made a change to the avatar if update == True: return True # we are attacking right now, so just let it be... if self.ai_timer.finished: # if we are attacking, then let it finish if self.in_attack: return # make it dumb by stopping once in a while if self.rand_diff(5, 40): self.ai_timer.alarm = random.randint(250, 1000) return # get a list of stuff we could do here to punish options = self.plan_attack() # WE DON'T WANT THE BANNED ONES for ani in self.banned_animations: try: options.remove(ani) except ValueError: pass if options == []: # play random animation, just for variety if self.rand_diff(5, 15): ani = self.block_frames[random.randint(0, len(self.block_frames)-1)].parent self.avatar.play(ani) self.ai_timer.alarm = random.randint(250, 1000) return # if we are idling, then we can walk foe = self.match.closest_foe(self) if self.avatar.current_animation == self.idle_animation: if abs(foe.position[0] - self.position[0]) > self.personal_space: self.avatar.play(self.forward_animation) self.ai_timer.alarm = random.randint(60, 120) return True else: # throw an attack we can land if random.random() * 100 > 101 - self.difficulty: if self.avatar.current_animation == self.idle_animation: attack = options[random.randint(0, len(options)-1)] self.avatar.play(attack) # BUG: causes race conditions #self.in_attack = attack self.ai_timer.alarm = random.randint(200, 400) return else: self.avatar.play(self.idle_animation) self.ai_timer.alarm = random.randint(120, 200) self.ai_timer.alarm = self.update_freq # return a list of all frames that will land an attack def plan_attack(self, state=None): [ frame.face(self.avatar.facing) for frame in self.all_frames ] [ frame.update(self.position) for frame in self.all_frames ] possible = [ frame.parent for frame in self.all_frames \ if self.avatar.resolve_attack(frame) != [] ] return possible
class SimpleAvatar(StaticAvatar): def __init__(self, parent=None): super(SimpleAvatar, self).__init__(parent) self.callback = None # this is called when animation is finished self.current_frame_no = 0 self.current_animation = None self.previous_frame = None self.callback = None self._is_paused = False self.looped = 0 # timer initialization self.timer = Timer() # this is an override @property def state(self): return (self.current_animation, self.current_frame_no) def add_animation(self, anim): self.current_animation = anim """ BUG: we only test the next frame. its possible the if the system is too slow that the animation could lag behind because frames won't get dropped """ def update(self, time): self.time += time if self._is_paused == True: return # ttl == -1: special way to end an animation. if self.current_frame.ttl == -1: self.paused = True self.timer.update(time) if self.timer.finished: self.advance_frame() # sets the children of this to None, so that they can be garbage collected. # always call super last def cleanup(self): self.current_animation.cleanup() super(SimpleAvatar, self).cleanup() def advance_frame(self): if self._is_paused and self.current_frame.pause: return self.paused self.current_frame_no += 1 if self.current_frame_no >= len(self.current_animation): # the animation has reached the end if self.current_animation.looping == 0: return self.stop() # loop, but count the loops elif self.current_animation.looping > 0: if self.looped > self.current_animation.looping: self.stop() else: self.set_frame(self.current_animation.loop_frame) self.looped += 1 # loop forever, don't count the loops else: self.set_frame(self.current_animation.loop_frame) else: # just set the next frame self.set_frame(self.current_frame_no) def set_frame(self, frame_no): # deref for speed new_frame = self.current_animation.frames[frame_no] self.previous_frame = self.current_frame self.current_frame = new_frame self.current_frame_no = frame_no self.dirty = 1 if new_frame.face(self.facing) == False: new_frame.update(self.position) # handle frames that may want to move the avatar's position pos = list(self.position) if new_frame.move_avatar != (0, 0): pos[0] = pos[0] + new_frame.move_avatar[0] pos[1] = pos[1] + new_frame.move_avatar[1] # update the parent, engine will update us later self.parent.set_position(pos) new_frame.update(pos) new_frame.sound.stop() new_frame.sound.play() self.timer.alarm = self.current_frame.ttl #@property def get_paused(self): return self._is_paused #@paused.setter def set_paused(self, value): self._is_paused = value if value == False: self.previous_frame_no = self.current_frame_no self.dirty = 0 paused = property(get_paused, set_paused) def play(self, name=None, start_frame=0, callback=None, arg=[]): if self.paused: return # reset some state stuff self.looped = 0 self.dirty = 1 self.paused = False if callback != None: self.callback = (callback, arg) debug("playing %s, %s: %s\n" % (self.current_animation, self.dirty, self)) self.set_frame(start_frame) def stop(self): self.paused = True if self.callback != None: self.callback[0](*self.callback[1])