def __init__(self, args):

        self.args = args

        self.buildings_colour = (0, 0, 10)  # blue-black
        self.auto_mode = False

        self.projectiles = []
        self.tick_count = 0

        pygame.init()
        pygame.surfarray.use_arraytype("numpy")

        #        self.score_font = pygame.font.Font(pygame.font.get_default_font(), 20)
        self.score_font = pygame.font.Font(
            pygame.font.match_font("Monospace", True), 20)

        self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        surf = self.screen.get_rect()
        self.resolution = (surf.width, surf.height)

        self.buildings_surface = pygame.Surface(self.resolution, 0, 8)
        self.buildings_surface.set_palette(((0, 0, 0), self.buildings_colour))
        self.buildings_surface.set_colorkey(0, pygame.RLEACCEL)

        self.reset()

        if self.args.eyetracker:
            self.client = iViewXClient(self.args.eyetracker, 4444)
            self.client.addDispatcher(self.d)
            self.fp = VelocityFP()
            self.calibrator = Calibrator(self.client,
                                         self.screen,
                                         reactor=reactor)
    def __init__(self, args):
        
        self.args = args
        
        self.buildings_colour = (0,0,10)   # blue-black
        self.auto_mode = False
        
        self.projectiles = [] 
        self.tick_count = 0
                
        pygame.init()
        pygame.surfarray.use_arraytype("numpy")        
        
#        self.score_font = pygame.font.Font(pygame.font.get_default_font(), 20)
        self.score_font = pygame.font.Font(pygame.font.match_font("Monospace", True), 20)
        
        self.screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN)
        surf = self.screen.get_rect()
        self.resolution = (surf.width, surf.height)
        
        self.buildings_surface = pygame.Surface(self.resolution, 0, 8)
        self.buildings_surface.set_palette(((0,0,0), self.buildings_colour))
        self.buildings_surface.set_colorkey(0, pygame.RLEACCEL)
        
        self.reset()
        
        if self.args.eyetracker:
            self.client = iViewXClient( self.args.eyetracker, 4444 )
            self.client.addDispatcher( self.d )
            self.fp = VelocityFP()
            self.calibrator = Calibrator( self.client, self.screen, reactor = reactor )
Example #3
0
    def __init__( self, args, subjectInfo ):
        super( World, self ).__init__()

        self.args = args

        self.modifier = pygame.KMOD_CTRL
        if platform.system() == 'Darwin':
            self.modifier = pygame.KMOD_META

        self.lc = None
        self.fix_data = None
        self.eye_position = None
        self.fixating = False
        self.ret = 0

        self.colors = [( 204, 255, 102 ), ( 255, 153, 255 )]
        if args.color:
            self.colors = self.colors[::-1]
        self.bgcolor = ( 0, 0, 0 )
        self.fix_shape = u'\u25CB'

        self.replicates = 10
        self.trialPool = self.generateTrialPool( self.replicates )
        self.blockLength = len( self.trialPool )
        self.lastTrial = self.blockLength * int( self.args.blocks )
        self.colorSetup = 1
        if self.args.color:
            self.colorSetup = 2

        self.subjectInfo = subjectInfo

        self.screenshot = 1

        if self.subjectInfo:
            eid = rin2id( subjectInfo['rin'] )
            subjectInfo['encrypted_rin'] = eid
            subjectInfo['cipher'] = 'AES/CBC (RIJNDAEL) - 16Byte Key'
            self.log_basename = cwsubject.makeLogFileBase( 'SaccadeTask_' + eid[:8] )

        self.logdir = args.logdir
        if self.args.subdir:
            self.logdir = os.path.join(self.logdir, eid[:8])
        if not os.path.exists( self.logdir ):
            os.makedirs( self.logdir )

        self.log_filename = None
        if self.subjectInfo:
            cwsubject.writeHistoryFile( os.path.join( self.logdir, self.log_basename ), self.subjectInfo )
            self.log_filename = os.path.join( self.logdir, self.log_basename + '.txt.incomplete')
            self.output = open( self.log_filename, 'w' )
        else:
            if self.args.logfile:
                self.log_filename = os.path.join( self.logdir, args.logfile + '.incomplete')
                self.output = open( self.log_filename, 'w' )
            else:
                self.output = sys.stdout

        pygame.mouse.set_visible( False )
        if self.args.fullscreen:
            self.screen = pygame.display.set_mode( ( 0, 0 ), pygame.FULLSCREEN )
        else:
            self.screen = pygame.display.set_mode( ( 1024, 768 ), 0 )
        self.width, self.height = self.screen.get_size()
        self.center_x = int( self.width / 2 )
        self.center_y = int( self.height / 2 )
        self.offset = int( self.width / 3 )
        self.offsets = [int( self.center_x - self.offset ), int( self.center_x + self.offset )]
        self.worldsurf = self.screen.copy()
        self.worldsurf_rect = self.worldsurf.get_rect()
        obj_width = int( self.center_y * self.args.arrowsize )
        self.fontname = 'DejaVuSansMono.ttf'
        self.obj_widths = [obj_width, int( math.ceil( obj_width * 1.5 ) ), int( math.ceil( obj_width * 2 ) )]
        self.arrow_font = pygame.font.Font( self.fontname, self.obj_widths[0] )
        self.mask_font = pygame.font.Font( self.fontname, int( self.obj_widths[2] * 1.5 ) )
        self.demo_font = pygame.font.Font( self.fontname, int( self.obj_widths[2] * 4 ) )
        self.cue_fonts = [pygame.font.Font( self.fontname, self.obj_widths[0] ),
                          pygame.font.Font( self.fontname, self.obj_widths[1] ),
                          pygame.font.Font( self.fontname, self.obj_widths[2] )]
        self.arrows = ['', u'\u25B6', u'\u25B2', u'\u25C0']
        self.arrow_text = ['', '>', '^', '<']
        self.clock = pygame.time.Clock()
        self.accuracy = []

        self.EVENT_SHOW_CUE = pygame.USEREVENT + 1
        self.EVENT_SHOW_ARROW = pygame.USEREVENT + 2
        self.EVENT_SHOW_MASK = pygame.USEREVENT + 3
        self.EVENT_HIDE_FIX = pygame.USEREVENT + 4

        self.mode_text = ''

        self.trial = 0
        self.size = self.cue_side = self.fix_delay = -1
        self.answer = self.mask_time = self.cue_time = self.trial_stop = self.trial_start = 0

        if self.args.eyetracker and self.args.fullscreen:
            self.client = iViewXClient( self.args.eyetracker, 4444 )
            self.client.addDispatcher( self.d )
            self.fp = VelocityFP(self.width, self.height, 473.76, 296.1, 500, 23, 45)
            self.calibrator = Calibrator( self.client, self.screen, reactor = reactor)
Example #4
0
class World( object ):
    """Task Environment"""

    d = Dispatcher()

    def __init__( self, args, subjectInfo ):
        super( World, self ).__init__()

        self.args = args

        self.modifier = pygame.KMOD_CTRL
        if platform.system() == 'Darwin':
            self.modifier = pygame.KMOD_META

        self.lc = None
        self.fix_data = None
        self.eye_position = None
        self.fixating = False
        self.ret = 0

        self.colors = [( 204, 255, 102 ), ( 255, 153, 255 )]
        if args.color:
            self.colors = self.colors[::-1]
        self.bgcolor = ( 0, 0, 0 )
        self.fix_shape = u'\u25CB'

        self.replicates = 10
        self.trialPool = self.generateTrialPool( self.replicates )
        self.blockLength = len( self.trialPool )
        self.lastTrial = self.blockLength * int( self.args.blocks )
        self.colorSetup = 1
        if self.args.color:
            self.colorSetup = 2

        self.subjectInfo = subjectInfo

        self.screenshot = 1

        if self.subjectInfo:
            eid = rin2id( subjectInfo['rin'] )
            subjectInfo['encrypted_rin'] = eid
            subjectInfo['cipher'] = 'AES/CBC (RIJNDAEL) - 16Byte Key'
            self.log_basename = cwsubject.makeLogFileBase( 'SaccadeTask_' + eid[:8] )

        self.logdir = args.logdir
        if self.args.subdir:
            self.logdir = os.path.join(self.logdir, eid[:8])
        if not os.path.exists( self.logdir ):
            os.makedirs( self.logdir )

        self.log_filename = None
        if self.subjectInfo:
            cwsubject.writeHistoryFile( os.path.join( self.logdir, self.log_basename ), self.subjectInfo )
            self.log_filename = os.path.join( self.logdir, self.log_basename + '.txt.incomplete')
            self.output = open( self.log_filename, 'w' )
        else:
            if self.args.logfile:
                self.log_filename = os.path.join( self.logdir, args.logfile + '.incomplete')
                self.output = open( self.log_filename, 'w' )
            else:
                self.output = sys.stdout

        pygame.mouse.set_visible( False )
        if self.args.fullscreen:
            self.screen = pygame.display.set_mode( ( 0, 0 ), pygame.FULLSCREEN )
        else:
            self.screen = pygame.display.set_mode( ( 1024, 768 ), 0 )
        self.width, self.height = self.screen.get_size()
        self.center_x = int( self.width / 2 )
        self.center_y = int( self.height / 2 )
        self.offset = int( self.width / 3 )
        self.offsets = [int( self.center_x - self.offset ), int( self.center_x + self.offset )]
        self.worldsurf = self.screen.copy()
        self.worldsurf_rect = self.worldsurf.get_rect()
        obj_width = int( self.center_y * self.args.arrowsize )
        self.fontname = 'DejaVuSansMono.ttf'
        self.obj_widths = [obj_width, int( math.ceil( obj_width * 1.5 ) ), int( math.ceil( obj_width * 2 ) )]
        self.arrow_font = pygame.font.Font( self.fontname, self.obj_widths[0] )
        self.mask_font = pygame.font.Font( self.fontname, int( self.obj_widths[2] * 1.5 ) )
        self.demo_font = pygame.font.Font( self.fontname, int( self.obj_widths[2] * 4 ) )
        self.cue_fonts = [pygame.font.Font( self.fontname, self.obj_widths[0] ),
                          pygame.font.Font( self.fontname, self.obj_widths[1] ),
                          pygame.font.Font( self.fontname, self.obj_widths[2] )]
        self.arrows = ['', u'\u25B6', u'\u25B2', u'\u25C0']
        self.arrow_text = ['', '>', '^', '<']
        self.clock = pygame.time.Clock()
        self.accuracy = []

        self.EVENT_SHOW_CUE = pygame.USEREVENT + 1
        self.EVENT_SHOW_ARROW = pygame.USEREVENT + 2
        self.EVENT_SHOW_MASK = pygame.USEREVENT + 3
        self.EVENT_HIDE_FIX = pygame.USEREVENT + 4

        self.mode_text = ''

        self.trial = 0
        self.size = self.cue_side = self.fix_delay = -1
        self.answer = self.mask_time = self.cue_time = self.trial_stop = self.trial_start = 0

        if self.args.eyetracker and self.args.fullscreen:
            self.client = iViewXClient( self.args.eyetracker, 4444 )
            self.client.addDispatcher( self.d )
            self.fp = VelocityFP(self.width, self.height, 473.76, 296.1, 500, 23, 45)
            self.calibrator = Calibrator( self.client, self.screen, reactor = reactor)

    def generateTrialPool( self, n ):
        return sample( [1, 2, 3, 4] * n, 4 * n )

    def getNextPoolTrial( self ):
        if len( self.trialPool ) < 1:
            self.trialPool = self.generateTrialPool( self.replicates )
        return self.trialPool.pop()

    def get_fixation_interval( self ):
        return randrange( 1500, 3500, 1 )

    def draw_arrow( self, type, size, x ):
        self.draw_text( self.arrows[type], self.arrow_font, ( 0, 0, 0 ), ( x, self.center_y ) )

    def draw_mask( self, x ):
        self.draw_text( u'\u25A9', self.mask_font, ( 128, 128, 128 ), ( x, self.center_y ) )

    def draw_cue( self, x, size ):
        self.draw_text( u'\u25CF', self.cue_fonts[size], ( 0, 0, 0 ), ( x, self.center_y ) )

    def draw_fixation_circle( self ):
        if self.show_fix:
            self.draw_text( self.fix_shape, self.cue_fonts[0], ( 0, 0, 0 ), ( self.center_x, self.center_y ) )

    def draw_text( self, text, font, color, loc ):
        t = font.render( text, True, color )
        tr = t.get_rect()
        tr.center = loc
        self.worldsurf.blit( t, tr )

    def clear( self ):
        self.worldsurf.fill( self.bgcolor )

    def update_world( self ):
        self.screen.blit( self.worldsurf, self.worldsurf_rect )
        pygame.display.flip()

    @d.listen( 'ET_SPL' )
    def iViewXEvent( self, inResponse ):
        self.eye_position = map( float, inResponse[10:] )
        if self.state < 0:
            return
        t = int( inResponse[0] )
        x = float( inResponse[2] )
        y = float( inResponse[4] )
        ex = np.mean( ( float( inResponse[10] ), float( inResponse[11] ) ) )
        ey = np.mean( ( float( inResponse[12] ), float( inResponse[13] ) ) )
        ez = np.mean( ( float( inResponse[14] ), float( inResponse[15] ) ) )
        dia = int( inResponse[6] ) > 0 and int( inResponse[7] ) > 0 and int( inResponse[8] ) > 0 and int( inResponse[9] ) > 0
        self.fixating, self.fix_data = self.fp.processData( t, x, y, ex, ey, ez )

        result = [time.time(), 'EVENT_SMI']
        if self.trial_start != 0 and self.trial_stop == 0:
            if self.trial_start == -1:
                self.trial_start = int( inResponse[0] )
            result.append('SAMPLE_IN')
        else:
            result.append('SAMPLE_OUT')
        result = result + [self.trial, self.mode_text, self.center_x, self.center_y,
                           self.offset, self.fix_delay, self.obj_widths[self.size],
                           self.cue_side, self.arrow_text[self.answer], dia, t,
                           t - self.trial_start, x, y, ex, ey, ez]
        self.output.write( '\t'.join(map(str,result)) + '\n' )
        if self.cue_time > 0:
            if not self.fix_data and self.saccade_latency == 0:
                self.saccade_latency = time.time() - self.cue_time
                print self.saccade_latency
            elif self.saccade_latency > 0 and self.saccade_direction == 'none':
                if x < self.center_x:
                    self.saccade_direction = 'left'
                else:
                    self.saccade_direction = 'right'

    def process_events( self ):
        ret = False
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                ret = True
                if ( pygame.key.get_mods() & self.modifier ):
                        if event.key == pygame.K_q:
		                    if len( self.accuracy ) > 0:
		                        self.do_stats()
		                    self.ret = 1
		                    self.lc.stop()
		                    return
                if self.state == -3 and event.key == pygame.K_SPACE:
                    self.client.acceptCalibrationPoint()
                elif self.state == -2:
                    if event.key == pygame.K_r:
                        self.calibrationResults = []
                        self.state = -3
                        self.client.startCalibration( 9 )
                    elif event.key == pygame.K_SPACE:
                        self.state = -1
                elif self.state == -1:
                    self.state = 0
                elif self.state == 5:
                    if event.key == pygame.K_LEFT or event.key == pygame.K_UP or event.key == pygame.K_RIGHT:
                        self.trial_stop = -1
                        rt = time.time() - self.target_time
                        result = [time.time(), 'EVENT_SYSTEM', 'RESULT', self.trial, self.mode_text, self.colorSetup, self.center_x, self.center_y, self.offset, self.fix_delay, self.obj_widths[self.size], self.cue_side, self.arrow_text[self.answer]]
                        if event.key == pygame.K_LEFT:
                            result.append( '<' )
                            if self.answer == 3:
                                result.append( 1 )
                            else:
                                result.append( 0 )
                        elif event.key == pygame.K_UP:
                            result.append( '^' )
                            if self.answer == 2:
                                result.append( 1 )
                            else:
                                result.append( 0 )
                        elif event.key == pygame.K_RIGHT:
                            result.append( '>' )
                            if self.answer == 1:
                                result.append( 1 )
                            else:
                                result.append( 0 )
                        result.append( rt )
                        self.trial_stop = time.time()
                        self.state = 0
                        if self.args.eyetracker:
                            result.append( self.saccade_direction )
                            result.append( self.saccade_latency )
                            self.output.write( '\t'.join(map(str,result)) + '\n' )
                        self.output.write( "%f\tEVENT_SYSTEM\tTRIAL_END\n" % ( time.time() ) )
                        self.accuracy.append( result )
            elif event.type == self.EVENT_HIDE_FIX:
                self.output.write( "%f\tEVENT_SYSTEM\tHIDE_FIX\n" % ( time.time() ) )
                pygame.time.set_timer( self.EVENT_HIDE_FIX, 0 )
                self.show_fix = False
            elif event.type == self.EVENT_SHOW_CUE:
                self.output.write( "%f\tEVENT_SYSTEM\tSHOW_CUE\n" % ( time.time() ) )
                pygame.time.set_timer( self.EVENT_SHOW_CUE, 0 )
                self.state = 3
                pygame.time.set_timer( self.EVENT_SHOW_ARROW, 400 )
                self.cue_time = time.time()
                self.trial_start = -1
            elif event.type == self.EVENT_SHOW_ARROW:
                self.output.write( "%f\tEVENT_SYSTEM\tSHOW_ARROW\n" % ( time.time() ) )
                pygame.time.set_timer( self.EVENT_SHOW_ARROW, 0 )
                self.state = 4
                pygame.time.set_timer( self.EVENT_SHOW_MASK, 150 )
                self.target_time = time.time()
            elif event.type == self.EVENT_SHOW_MASK:
                self.output.write( "%f\tEVENT_SYSTEM\tSHOW_MASK\n" % ( time.time() ) )
                pygame.time.set_timer( self.EVENT_SHOW_MASK, 0 )
                self.state = 5
        self.mask_time = time.time()
        return ret

    def draw_fix( self ):
        if self.fix_data:
            pygame.draw.circle( self.worldsurf, ( 0, 228, 0 ), ( int( self.fix_data[1] ), int( self.fix_data[2] ) ), 5, 0 )

    def draw_world( self ):
        self.clear()
        if self.state == -1:
            self.show_intro()
        elif self.state == 1 or self.state == 2:
            self.draw_fixation_circle()
        elif self.state == 3:
            self.draw_cue( self.loc1, self.size )
        elif self.state == 4:
            self.draw_arrow( self.answer, self.obj_widths[0], self.loc2 )
        elif self.state == 5:
            self.draw_mask( self.loc2 )
        if self.args.eyetracker and self.args.showfixation:
            self.draw_fix()
        self.update_world()

    def generate_trial( self ):
        self.size = self.cue_side = self.fix_delay = -1
        self.answer = self.target_time = self.mask_time = self.cue_time = self.trial_stop = self.trial_start = 0
        self.show_fix = True
        self.fix_shape = u'\u25CB'
        self.saccade_latency = 0
        self.saccade_direction = 'none'
        self.answer = choice( [3, 2, 1] )
        self.size = 0#choice([2,1,0])
        self.fix_color = ( 255, 255, 0 )
        if self.args.balanced:
            trial = self.getNextPoolTrial()
            if trial < 3:
                self.loc1 = self.offsets[0]
                self.loc2 = self.offsets[1]
            else:
                self.loc1 = self.offsets[1]
                self.loc2 = self.offsets[0]
            if trial % 2 == 0:
                self.mode_text = 'anti'
                self.bgcolor = self.colors[0]
            else:
                self.mode_text = 'pro'
                self.bgcolor = self.colors[1]
                self.loc2 = self.loc1
        else:
            self.loc1, self.loc2 = sample( self.offsets, 2 )
            self.mode_text = 'anti'
            self.bgcolor = self.colors[0]
            if self.args.mode == 'pro':
                self.bgcolor = self.colors[1]
                self.loc2 = self.loc1
                self.mode_text = 'anti'
            elif self.args.mode == 'random':
                self.loc2 = sample( self.offsets, 1 )[0]
                if self.loc1 == self.loc2:
                    self.mode_text = 'pro'
                    self.bgcolor = self.colors[1]
                else:
                    self.mode_text = 'anti'
                    self.bgcolor = self.colors[0]
        self.cue_side = 'left'
        if self.loc1 > self.center_x:
            self.cue_side = 'right'
        self.trial += 1

    def showPauseScreen( self ):
        ifont1 = pygame.font.Font( None, 34 )
        self.bgcolor = ( 0, 0, 0 )
        self.clear()
        self.draw_text( 'Take a moment to relax your eyes!', ifont1, ( 255, 255, 255 ), ( self.center_x, self.center_y - 40 ) )
        self.draw_text( 'Press any key to continue when ready...', ifont1, ( 255, 255, 255 ), ( self.center_x, self.center_y ) )
        self.update_world()
        while ( True ):
            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    return

    def show_intro( self ):
        ifont1 = pygame.font.Font( None, 34 )
        ifont2 = pygame.font.Font( None, 24 )
        self.draw_text( u'\u25A0', self.demo_font, self.colors[0], ( self.center_x / 2, self.center_y / 8 * 4 ) )
        self.draw_text( 'Look away from cue!', ifont1, ( 255, 255, 255 ), ( self.center_x / 2, self.center_y / 8 * 6.5 ) )
        self.draw_text( u'\u25A0', self.demo_font, self.colors[1], ( self.center_x + self.center_x / 2, self.center_y / 8 * 4 ) )
        self.draw_text( 'Look towards cue!', ifont1, ( 255, 255, 255 ), ( self.center_x + self.center_x / 2, self.center_y / 8 * 6.5 ) )
        intro = ifont2.render( "Press Any Key To Begin", True, ( 255, 255, 255 ) )
        intro_rect = intro.get_rect()
        intro_rect.centerx = self.center_x
        intro_rect.centery = int( self.center_y / 2 * 3 )
        self.worldsurf.blit( intro, intro_rect )

    def do_stats( self ):
        pass

    def refresh( self ):
        if self.state == 0:
            if self.trial == self.lastTrial:
                if len( self.accuracy ) > 0:
                    self.do_stats()
                self.cleanup()
            elif self.trial > 0 and self.trial % self.blockLength == 0:
                self.showPauseScreen()
            self.generate_trial()
            self.output.write( "%f\tEVENT_SYSTEM\tTRIAL_START\n" % ( time.time() ) )
            if self.args.eyetracker:
                self.state = 1
            else:
                self.state = 2
                self.fix_delay = self.get_fixation_interval()
                pygame.time.set_timer( self.EVENT_SHOW_CUE, self.fix_delay )
                if not self.args.nogap:
                    pygame.time.set_timer( self.EVENT_HIDE_FIX, self.fix_delay - 233 )
        elif self.state == 1:
            if self.fixating:
                xdiff = abs( self.fix_data[1] - self.center_x )
                ydiff = abs( self.fix_data[2] - self.center_y )
                if xdiff <= 100 and ydiff <= 100:
                    self.fix_color = ( 0, 255, 0 )
                    self.fix_shape = u'\u25C9'
                    if self.fp.nSamples > 50: # Means at least 100ms
                        self.state = 2
                        self.fix_delay = self.get_fixation_interval()
                        pygame.time.set_timer( self.EVENT_SHOW_CUE, self.fix_delay )
                        if not self.args.nogap:
                            pygame.time.set_timer( self.EVENT_HIDE_FIX, self.fix_delay - 233 )
            else:
                self.fix_color = ( 255, 255, 0 )
                self.fix_shape = u'\u25CB'
        elif self.state == 2 and self.args.eyetracker:
            if self.fix_data:
                xdiff = abs( self.fix_data[1] - self.center_x )
                ydiff = abs( self.fix_data[2] - self.center_y )
                if xdiff > 100 or ydiff > 100:
                    self.output.write( "%f\tEVENT_SYSTEM\tTRIAL_RESET\n" % ( time.time() ) )
                    #sys.stderr.write('False start, resetting trial.\n')
                    pygame.time.set_timer( self.EVENT_SHOW_CUE, 0 )
                    pygame.time.set_timer( self.EVENT_HIDE_FIX, 0 )
                    self.state = 1
                    self.fix_color = ( 255, 0, 0 )
                    self.fix_shape = u'\u25CB'
                    self.show_fix = True
            """else:
                self.output.write( "%f\tEVENT_SYSTEM\tTRIAL_RESET\n" % ( time.time() ) )
                #sys.stderr.write('Lost gaze, resetting trial.\n')
                pygame.time.set_timer( self.EVENT_SHOW_CUE, 0 )
                pygame.time.set_timer( self.EVENT_HIDE_FIX, 0 )
                self.state = 1
                self.fix_color = ( 255, 0, 0 )
                self.fix_shape = u'\u25CB'
                self.show_fix = True"""
        self.draw_world()
        self.process_events()

    def start( self, lc, results ):
        if results:
            self.output.write( "%f\tEVENT_SMI\tCALIBRATION_RESULTS\t'%s'\n" % ( time.time(), json.dumps(results, encoding="cp1252" ) ) )
        self.state = -1
        self.lc = LoopingCall( self.refresh )
        d = self.lc.start( 1.0 / 30 )
        d.addCallbacks( self.cleanup )

    def run( self ):
        self.state = -2
        if self.args.eyetracker:
            reactor.listenUDP( 5555, self.client )
            self.calibrator.start( self.start )
            self.output.write( 'clock\tevent_type\tevent_details\ttrial\tmode\tsetup\tcenter_x\tcenter_y\toffset\tfix_delay\tcue_size\tcue_side\ttarget\tresponse\tcorrect\trt\t1st_saccade_direction\t1st_saccade_latency\tgaze_found\ttimestamp\ttrial_time\tgaze_x\tgaze_y\n' )
        else:
            self.output.write( 'clock\tevent_type\tevent_details\ttrial\tmode\tsetup\tcenter_x\tcenter_y\toffset\tfix_delay\tcue_size\tcue_side\ttarget\tresponse\tcorrect\trt\n' )
            self.start( None, None )
        reactor.run()

    def cleanup( self, *args, **kwargs ):
        if self.args.logfile:
            self.output.close()
            if self.ret == 0 and self.log_filename:
                os.rename( self.log_filename, self.log_filename[:-11] )
        reactor.stop()
class MissileDefenceGame(object):

    if eyetrackerSupport:
        d = Dispatcher()

    def reset(self):
        self.background = background.StarryBackground(self.resolution)
        self.physics = Physics(self)
        self.cannon = DefenceCannon(centre=(self.resolution[0] / 2,
                                            self.resolution[1] - 99),
                                    game=self)
        self.buildings = Buildings(generate_city(self.resolution),
                                   self.resolution)
        self.firing = False
        self.fixation_firing = False
        self.fire_cycle = 0
        self.shield_dome = ShieldDome(self.resolution)
        self.shield_dome.health = 2
        self.missile_threshold = 0.01
        self.projectiles = []
        self.initial_buildings_sum = self.get_buildings_sum()
        self.buildings_sum = self.initial_buildings_sum
        self.score = 0

        self.fix = None
        self.samp = 0

    def __init__(self, args):

        self.args = args

        self.buildings_colour = (0, 0, 10)  # blue-black
        self.auto_mode = False

        self.projectiles = []
        self.tick_count = 0

        pygame.init()
        pygame.surfarray.use_arraytype("numpy")

        #        self.score_font = pygame.font.Font(pygame.font.get_default_font(), 20)
        self.score_font = pygame.font.Font(
            pygame.font.match_font("Monospace", True), 20)

        self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        surf = self.screen.get_rect()
        self.resolution = (surf.width, surf.height)

        self.buildings_surface = pygame.Surface(self.resolution, 0, 8)
        self.buildings_surface.set_palette(((0, 0, 0), self.buildings_colour))
        self.buildings_surface.set_colorkey(0, pygame.RLEACCEL)

        self.reset()

        if self.args.eyetracker:
            self.client = iViewXClient(self.args.eyetracker, 4444)
            self.client.addDispatcher(self.d)
            self.fp = VelocityFP()
            self.calibrator = Calibrator(self.client,
                                         self.screen,
                                         reactor=reactor)

    def generate_missile(self):
        p = projectiles.Missile(position=(uniform(-500,
                                                  self.resolution[0] + 500),
                                          -50),
                                velocity=(uniform(-3, 3), uniform(2, 7)))

        count = 0
        while p.position[1] < -20 and count < 100:
            p.apply_physics(self.physics, self.buildings)
            count += 1

        return p

    def handle_events(self):
        force_fire = False

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.quit()
            elif event.type == pygame.KEYDOWN and event.key == ord("q"):
                self.quit()
            elif event.type == pygame.KEYDOWN and event.key == ord(
                    "s"):  # screenshot
                pygame.image.save(self.screen, "screenshot.png")
            elif event.type == pygame.KEYDOWN and event.key == ord(
                    "a"):  # auto mode
                self.auto_mode = not self.auto_mode
            elif event.type == pygame.KEYDOWN and event.key == ord(
                    "r"):  # reset
                self.reset()
            elif event.type == pygame.KEYDOWN and event.key == ord("d"):
                self.shield_dome.health += 20
            elif event.type == pygame.MOUSEBUTTONDOWN:
                force_fire = True  # fire event if there was a mouse up too
                self.fire_cycle = 0
                self.firing = True
            elif event.type == pygame.MOUSEBUTTONUP:
                self.firing = False

        stuff_nearby = any(
            size_squared(array(p.position) -
                         array(self.cannon.centre)) < p.radius * p.radius
            for p in self.projectiles)

        if not self.auto_mode:
            self.cannon.target = array(pygame.mouse.get_pos())

        if not stuff_nearby:
            if self.auto_mode and self.cannon.can_fire():

                valid_targets = [
                    p for p in self.projectiles
                    if p.position[0] > 0 and p.position[1] > 0
                    and p.position[0] < self.resolution[0]
                    and p.position[1] < self.resolution[1] -
                    300 and p.velocity[1] > 0 and not p.exploding
                ]
                if len(valid_targets) > 0:
                    target = random.choice(valid_targets)
                    target_pos = array(
                        target.position) + array(target.velocity) * 4
                    self.cannon.fire(target_pos)
                    self.cannon.target = target_pos

            elif self.firing or force_fire:
                self.cannon.fire(pygame.mouse.get_pos())

    def get_buildings_sum(self):
        # restart if most of the buildings are destroyed and no explosions in progress
        sum = 0
        for y in range(self.resolution[1] - 100, self.resolution[1]):
            sum += numpy.ma.sum(self.buildings.pixeldata[y])
        return sum

    def draw(self, intro=False):
        self.background.draw(self.screen)
        pygame.surfarray.blit_array(self.buildings_surface,
                                    self.buildings.pixeldata)

        self.screen.blit(self.buildings_surface, (0, 0))

        self.shield_dome.draw(self.screen)

        for p in self.projectiles:
            p.draw(self.screen)

        self.cannon.draw(self.screen)

        # draw score
        score_surf = self.score_font.render(format(self.score, "08"), True,
                                            (255, 255, 255))
        self.screen.blit(score_surf, (30, 30))
        pygame.display.flip()

    def apply_physics(self):
        self.physics.update_location_cache()

        projectiles_keep = []
        # process projectiles
        for p in self.projectiles:
            p.apply_physics(self.physics, self.buildings)

            # keep any projectiles that aren't destroyed/off-screen
            if not p.is_garbage(self.resolution):
                projectiles_keep.append(p)
        self.projectiles = projectiles_keep
        self.buildings.apply_physics()
        self.cannon.apply_physics()

    def refresh(self):
        self.handle_events()

        self.tick_count += 1

        if self.tick_count % 100 == 0:
            self.background.darken()

        if self.tick_count % 30 == 0:
            self.buildings_sum = self.get_buildings_sum()
            if float(self.buildings_sum) / self.initial_buildings_sum < 0.2:
                self.reset()

            self.score += 100

        # randomly add more projectiles
        self.missile_threshold += 0.0001

        m = self.missile_threshold
        while m > 0:
            m -= random.random()
            if m > 0:
                self.projectiles.append(self.generate_missile())

        self.apply_physics()

        self.draw()

    def start(self, lc, results):
        self.lc = LoopingCall(self.refresh)
        cleanupD = self.lc.start(1.0 / 30)
        cleanupD.addCallbacks(self.quit)

    def run(self):
        if self.args.eyetracker:
            reactor.listenUDP(5555, self.client)
            self.calibrator.start(self.start)
        else:
            self.start(None)
        reactor.run()

    def quit(self, lc=None):
        reactor.stop()

    if eyetrackerSupport:

        @d.listen('ET_SPL')
        def iViewXEvent(self, inSender, inEvent, inResponse):
            t = int(inResponse[0])
            x = float(inResponse[2])
            y = float(inResponse[4])
            ex = numpy.mean((float(inResponse[10]), float(inResponse[11])))
            ey = numpy.mean((float(inResponse[12]), float(inResponse[13])))
            ez = numpy.mean((float(inResponse[14]), float(inResponse[15])))
            dia = int(inResponse[6]) > 0 and int(inResponse[7]) > 0 and int(
                inResponse[8]) > 0 and int(inResponse[9]) > 0
            self.fix, self.samp = self.fp.processData(t, dia, x, y, ex, ey, ez)

            if self.fix:
                if not self.fixation_firing and self.samp > 100:
                    self.fixation_firing = True
                    self.cannon.fire(self.fix)
            else:
                self.fixation_firing = False
class MissileDefenceGame(object):
    
    if eyetrackerSupport:
        d = Dispatcher()
    
    def reset(self):
        self.background = background.StarryBackground(self.resolution)                       
        self.physics = Physics(self)        
        self.cannon = DefenceCannon(centre=(self.resolution[0] / 2,
                                            self.resolution[1] - 99),
                                    game=self)
        self.buildings = Buildings(generate_city(self.resolution),
                                   self.resolution)
        self.firing = False
        self.fixation_firing = False
        self.fire_cycle = 0
        self.shield_dome = ShieldDome(self.resolution)
        self.shield_dome.health = 2
        self.missile_threshold = 0.01
        self.projectiles = []
        self.initial_buildings_sum = self.get_buildings_sum()
        self.buildings_sum = self.initial_buildings_sum
        self.score = 0
        
        self.fix = None
        self.samp = 0
        
    def __init__(self, args):
        
        self.args = args
        
        self.buildings_colour = (0,0,10)   # blue-black
        self.auto_mode = False
        
        self.projectiles = [] 
        self.tick_count = 0
                
        pygame.init()
        pygame.surfarray.use_arraytype("numpy")        
        
#        self.score_font = pygame.font.Font(pygame.font.get_default_font(), 20)
        self.score_font = pygame.font.Font(pygame.font.match_font("Monospace", True), 20)
        
        self.screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN)
        surf = self.screen.get_rect()
        self.resolution = (surf.width, surf.height)
        
        self.buildings_surface = pygame.Surface(self.resolution, 0, 8)
        self.buildings_surface.set_palette(((0,0,0), self.buildings_colour))
        self.buildings_surface.set_colorkey(0, pygame.RLEACCEL)
        
        self.reset()
        
        if self.args.eyetracker:
            self.client = iViewXClient( self.args.eyetracker, 4444 )
            self.client.addDispatcher( self.d )
            self.fp = VelocityFP()
            self.calibrator = Calibrator( self.client, self.screen, reactor = reactor )
        
    def generate_missile(self):
        p = projectiles.Missile(position=(uniform(-500, self.resolution[0] + 500), -50),
                                velocity=(uniform(-3, 3), 
                                          uniform(2, 7)))
        
        count = 0
        while p.position[1] < -20 and count < 100:
            p.apply_physics(self.physics, self.buildings)
            count += 1
            
        return p

    def handle_events(self):
        force_fire = False
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.quit()
            elif event.type == pygame.KEYDOWN and event.key == ord("q"):
                self.quit()
            elif event.type == pygame.KEYDOWN and event.key == ord("s"): # screenshot
                pygame.image.save(self.screen, "screenshot.png")
            elif event.type == pygame.KEYDOWN and event.key == ord("a"): # auto mode
                self.auto_mode = not self.auto_mode
            elif event.type == pygame.KEYDOWN and event.key == ord("r"): # reset
                self.reset()
            elif event.type == pygame.KEYDOWN and event.key == ord("d"):
                self.shield_dome.health += 20
            elif event.type == pygame.MOUSEBUTTONDOWN:
                force_fire  = True # fire event if there was a mouse up too
                self.fire_cycle = 0
                self.firing = True
            elif event.type == pygame.MOUSEBUTTONUP:
                self.firing = False
       
        stuff_nearby = any(
            size_squared(array(p.position) - array(self.cannon.centre)) < p.radius * p.radius  
            for p in self.projectiles)
            
        if not self.auto_mode:
            self.cannon.target = array(pygame.mouse.get_pos())

        if not stuff_nearby:
            if self.auto_mode and self.cannon.can_fire():

                valid_targets = [p for p in self.projectiles if
                                 p.position[0] > 0 and p.position[1] > 0 and
                                 p.position[0] < self.resolution[0] and
                                 p.position[1] < self.resolution[1] - 300 and
                                 p.velocity[1] > 0 and not p.exploding]
                if len(valid_targets) > 0:
                    target = random.choice(valid_targets)
                    target_pos = array(target.position) + array(target.velocity) * 4
                    self.cannon.fire(target_pos)
                    self.cannon.target = target_pos
                    
            elif self.firing or force_fire:            
                self.cannon.fire(pygame.mouse.get_pos()) 
                
    def get_buildings_sum(self):
        # restart if most of the buildings are destroyed and no explosions in progress
        sum = 0
        for y in range(self.resolution[1] - 100, self.resolution[1]):
            sum += numpy.ma.sum(self.buildings.pixeldata[y])
        return sum
        
    def draw(self, intro=False):
        self.background.draw(self.screen)
        pygame.surfarray.blit_array(self.buildings_surface,
                                    self.buildings.pixeldata)
        
        self.screen.blit(self.buildings_surface, (0,0))

        self.shield_dome.draw(self.screen)
                
        for p in self.projectiles:
            p.draw(self.screen)
            
        self.cannon.draw(self.screen)
        
        # draw score
        score_surf = self.score_font.render(format(self.score, "08"), True, (255,255,255))
        self.screen.blit(score_surf, (30, 30))
        pygame.display.flip()
    
    
    
    def apply_physics(self):
        self.physics.update_location_cache()
        
        projectiles_keep = []  
        # process projectiles
        for p in self.projectiles:
            p.apply_physics(self.physics, self.buildings)
            
            # keep any projectiles that aren't destroyed/off-screen
            if not p.is_garbage(self.resolution):
               projectiles_keep.append(p)               
        self.projectiles = projectiles_keep        
        self.buildings.apply_physics()   
        self.cannon.apply_physics()
        
    def refresh(self):
        self.handle_events()
                        
        self.tick_count += 1

        if self.tick_count % 100 == 0:
            self.background.darken()        
            
        if self.tick_count % 30 == 0:
            self.buildings_sum   = self.get_buildings_sum()
            if float(self.buildings_sum) / self.initial_buildings_sum < 0.2:
                self.reset()
         
            self.score += 100
                       
        # randomly add more projectiles
        self.missile_threshold += 0.0001
        
        m = self.missile_threshold
        while m > 0:
            m -= random.random() 
            if m > 0:
                self.projectiles.append(self.generate_missile())
        
        self.apply_physics()
        
        self.draw()
        
    def start( self, lc, results):
        self.lc = LoopingCall( self.refresh )
        cleanupD = self.lc.start( 1.0 / 30 )
        cleanupD.addCallbacks( self.quit )

    def run( self ):
        if self.args.eyetracker:
            reactor.listenUDP( 5555, self.client )
            self.calibrator.start( self.start )
        else:
            self.start( None )
        reactor.run()
                
    def quit( self, lc=None ):
        reactor.stop()
            
    if eyetrackerSupport:
        @d.listen( 'ET_SPL' )
        def iViewXEvent( self, inSender, inEvent, inResponse ):
            t = int( inResponse[0] )
            x = float( inResponse[2] )
            y = float( inResponse[4] )
            ex = numpy.mean( ( float( inResponse[10] ), float( inResponse[11] ) ) )
            ey = numpy.mean( ( float( inResponse[12] ), float( inResponse[13] ) ) )
            ez = numpy.mean( ( float( inResponse[14] ), float( inResponse[15] ) ) )
            dia = int( inResponse[6] ) > 0 and int( inResponse[7] ) > 0 and int( inResponse[8] ) > 0 and int( inResponse[9] ) > 0
            self.fix, self.samp = self.fp.processData( t, dia, x, y, ex, ey, ez )
            
            if self.fix:
                if not self.fixation_firing and self.samp > 100:
                    self.fixation_firing = True
                    self.cannon.fire(self.fix)
            else:
                self.fixation_firing = False