Source code for usf.entity_skin

################################################################################
# copyright 2008 Gabriel Pettier <gabriel.pettier@gmail.com>                   #
#                                                                              #
# This file is part of UltimateSmashFriends                                    #
#                                                                              #
# UltimateSmashFriends is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by         #
# the Free Software Foundation, either version 3 of the License, or            #
# (at your option) any later version.                                          #
#                                                                              #
# UltimateSmashFriends is distributed in the hope that it will be useful,      #
# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
# GNU General Public License for more details.                                 #
#                                                                              #
# You should have received a copy of the GNU General Public License            #
# along with UltimateSmashFriends.  If not, see <http://www.gnu.org/licenses/>.#
################################################################################
'''
this module deal with what's definied in xml files for entities

'''

import os
import random
import pygame
import logging
from xml.etree import ElementTree

from usf.animations import Frame, PreciseTimedAnimation
from usf import loaders
from usf import CONFIG 

SIZE = (CONFIG.general.WIDTH,
        CONFIG.general.HEIGHT)


[docs]class EntitySkin (object): """ An EntitySkin contains all information about a player or an item, which is mainly animations frames, with their timings and vectors, and less importants information as the character/item name and such details. """ def __init__(self, dir_name, server=False, xml_from_str=None, keep_xml=False, animation='static'): """ The dir_name is the relative path of the directory where the item/player is defined, the class search for an xml file of the same name as the directory there. """ self.animations = {} if xml_from_str: a = ElementTree.ElementTree() # FIXME this is DIRTY f = open('/tmp/erf', 'w') f.write(xml_from_str) f.close() a.parse('/tmp/erf') else: f = os.path.join( CONFIG.system_path, dir_name, dir_name.split(os.sep)[-1] +os.extsep+'xml') #logging.debug(f) a = ElementTree.ElementTree( None, f) if keep_xml: # keep this to use it for editors self.xml = a attribs = a.getroot().attrib self.filename = dir_name self.name = attribs['name'] self.image = os.path.join( CONFIG.system_path, dir_name, attribs['image']) self.weight = attribs['weight'] if 'armor' in attribs: self.armor = int(attribs['armor']) else: self.armor = 0 self.action_events = {} self.sounds = {} self.vectors = {} self.hardshape = self.load_hardshape(attribs) self.shield_center = self.load_shield_center(attribs) self.load_movements(a, dir_name, server) # FIXME: this is about the state of the player, should be in the entity # class self.current_animation = animation self.animation = self.animations[self.current_animation] self.animation_change = True
[docs] def load_hardshape(self, attribs): return pygame.Rect([int(i) for i in attribs['hardshape'].split(' ')])
[docs] def load_shield_center(self, attribs): if 'shield_center' in attribs: return [int(i) for i in attribs['shield_center'].split(' ')] else: logging.warning( 'warning, entity '+self.name+' has no attribute shield_center'+ ', guessing from hardshape') return ( self.hardshape[0] + .5 * self.hardshape[2], self.hardshape[1] + .5 * self.hardshape[3])
[docs] def load_movements(self, a, dir_name, server): for movement in a.findall('movement'): frames = [] events = [] sounds = [] vectors = [] trails = [] for event in movement.findall('vector'): #logging.debug('vector found') x, y = [int(n) for n in event.attrib['vector'].split(',')] vectors.append( ( (x, y), int(event.attrib['time']))) self.vectors[movement.attrib['name']] = vectors for event in movement.findall('event'): events.append( ( event.attrib['action'], [int(i) for i in event.attrib['period'].split(',')])) self.action_events[movement.attrib['name']] = events for sound in movement.findall('sound'): sounds.append( os.path.join( CONFIG.system_path, dir_name, sound.attrib['filename'])) self.sounds[movement.attrib['name']] = sounds for frame in movement.findall('frame'): image = os.path.join( CONFIG.system_path, dir_name, frame.attrib['image']) trails = ( 'trails' in frame.attrib and [os.path.join( CONFIG.system_path, dir_name, x) for x in frame.attrib['trails'].split(',')] or False) frames.append( Frame( image, frame.attrib['time'], ('hardshape' in frame.attrib and frame.attrib['hardshape'] or self.hardshape), trails=trails)) for agressiv in frame.findall('agressiv-point'): coords = agressiv.attrib['coords'].split(',') vector = agressiv.attrib['vector'].split(',') frames[-1].add_agressiv_point([int(i) for i in coords], [int(i) for i in vector]) self.animations[movement.attrib['name']] = PreciseTimedAnimation( frames, movement.attrib, server)
[docs] def valid_animation(self, anim_name): """ return true if the animation is in the character animations and is 'static' or not the current animation. """ return ( anim_name in self.animations and ( anim_name == 'static' or anim_name != self.current_animation)) #FIXME: this should be in the entity class
[docs] def change_animation(self, anim_name, game=None, params=dict()): """ Change animation of the entity skin, updating hardshape and agressiv points. Add associated events to game. """ if self.valid_animation(anim_name): if 'entity' in params and params['entity'].upgraded: if anim_name + '_upgraded' in self.animations: self.current_animation = anim_name + '_upgraded' else: logging.debug( ' '.join((self.name, 'character has no upgraded version of ', anim_name, 'falling back to normal version'))) self.current_animation = anim_name else: self.current_animation = anim_name self.animation_change = True params['world'] = game params['gametime'] = game is not None or 0 params['anim_name'] = anim_name self.add_events(anim_name, game, params) #logging.debug(self.vectors[anim_name]) self.add_vectors(anim_name, game, params) if self.sounds[anim_name] != []: # XXX reactivate the try/except with the good exception when you # know it #try: loaders.track(random.choice(self.sounds[anim_name])).play() #except (Exception), e: #logging.warning(e) else: #logging.debug( "entity_skin "+self.name+" has no "+anim_name+"\ #animation.") pass
[docs] def backup(self): """ save current state of the entity skin """ return (self.current_animation, self.animation, self.animation.playing, self.animation.start_time)
[docs] def restore(self, backup): """ restore entity_skin from a backup state """ (self.current_animation, self.animation, self.animation.playing, self.animation._start_time) = backup
[docs] def add_vectors(self, anim_name, game, params): """ add vectors of the animation to the game as events """ for vector in self.vectors[anim_name]: #logging.debug('vector added') params2 = params.copy() # because we want to change some of # them for this time. params2['vector'] = vector[0] params2['anim_name'] = anim_name game.events.add_event( 'VectorEvent', period=(None, game.gametime+vector[1]/1000.0), params=params2)
[docs] def add_events(self, anim_name, game, params): """ add events of the animation to the game """ for event in self.action_events[anim_name]: if event[1][0] is 0: p1 = None else: p1 = game.gametime+(event[1][0]/1000.0) if event[1][1] is 0: p2 = None else: p2 = game.gametime+(event[1][1]/1000.0) try: game.events.add_event( event[0], period=(p1, p2), params=params) except AttributeError: logging.debug((self.name, game), 3) raise
[docs] def update(self, t, reverse=False, upgraded=False, server=False): """ Update the skin's animation if necessary. """ if self.animation_change: self.animation = self.animations[self.current_animation] self.animation_change = False self.animation.start(t) if self.animation.playing == 0: a = 'static' + upgraded * '_upgraded' if 'upgraded' in a and a not in self.animations: a = 'static' self.current_animation = a self.animation = self.animations[self.current_animation] self.animation.start(t) self.animation.update(t, reverse, server) self.hardshape = self.animation.hardshape