Ignore spurious style12 events.
[kaya.git] / lib / plugins / ics / lib / match_handler.rb
blobbfe6e7fe12b07ada585feac7c8e8e2abd223f509
1 # Copyright (c) 2009 Paolo Capriotti <p.capriotti@gmail.com>
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 require 'interaction/match'
9 require_bundle 'ics', 'icsplayer'
11 module ICS
14 # Handler for ICS games.
15
16 # Responds to ICS protocol events creating and updating matches.
17 # Matches are stored in the @matches instance variable. It is possible to
18 # have more than one match running on FICS because of the observe feature.
19
20 class MatchHandler
21   include Observer
22   
23   attr_reader :matches
24   
25   def initialize(user, protocol)
26     @protocol = protocol
27     @matches = { }
28     @user = user
29     
30     protocol.add_observer(self)
31   end
32   
33   def on_creating_game(data)
34     match = Match.new(data[:game], 
35         :kind => :ics, 
36         :editable => false,
37         :time_running => true)
38     @matches[data[:number]] = [match, data.merge(:type => :played)]
39   end
40   
41   def on_end_game(data)
42     entry = @matches.delete(data[:game_number])
43     if entry
44       match, info = entry
45       match.close(data[:result], data[:message])
46     end
47   end
48   
49   def on_end_examination(number)
50     on_end_game(:game_number => number,
51                 :result => '',
52                 :message => '')
53   end
54   
55   def on_examination_revert(data)
56     match, match_info = @matches[data[:game_number]]
57     if match_info
58       match_info[:about_to_revert_to] = data[:index]
59     end
60   end
61   
62   def on_style12(style12)
63     match, match_info = @matches[style12.game_number]
64     if match.nil?
65       if style12.relation == Style12::Relation::EXAMINING
66         # Examined games on ics have no header, so we have to be prepared to
67         # create a new match on the fly at this point.
68         # Create an editable Game.dummy match for the moment.
69         match = Match.new(Game.dummy, :kind => :ics, :editable => true, :navigable => true)
70         match_info = style12.match_info.merge(:type => :examined)
71         @matches[style12.game_number] = [match, match_info]
72         
73         # We want to change the game type at some point, so request the game
74         # movelist to the server.
75         @protocol.connection.send_text('moves')
76         @protocol.observe_limited(:movelist) do |movelist|
77           puts "movelist = #{movelist.inspect}"
78           true
79         end
80       else
81         # ignore spurious style12 events
82         return
83       end
84     end
85     
86     if match.started?
87       match_info[:icsplayer].on_style12(style12)
88     else
89       rel = style12.relation
90       state = style12.state
91       turns = [state.turn, state.opposite_turn(state.turn)]
92       @user.color, opponent_color =
93         if rel == Style12::Relation::MY_MOVE
94           turns
95         elsif rel == Style12::Relation::NOT_MY_MOVE
96           turns.reverse
97         else
98           [nil, turns[1]]
99         end
100       opponent = ICSPlayer.new(
101         lambda {|msg| @protocol.connection.send_text(msg) },
102         opponent_color,
103         match,
104         match_info)
105       match_info[:icsplayer] = opponent
106       
107       player = @user
108       
109       # in examined games, playing moves for the opponent is allowed
110       if @user.color.nil?
111         player = DummyPlayer.new(state.turn)
112         @user.add_controlled_player(player)
113         @user.add_controlled_player(opponent)
114         @user.premove = false
115       else
116         @user.premove = true
117       end
118       
119       player.name = match_info[player.color][:name]
120       
121       match.register(player)
122       match.register(opponent)
123       
124       match.start(player)
125       match.start(opponent)
126       
127       raise "couldn't start match" unless match.started?
128       unless match_info[:icsapi].same_state(match.state, style12.state)
129         match.history.state = style12.state
130       end
131       
132       @user.reset(match)
133       
134       match.update_time(style12.time)
135     end
136     
137     
138   end