… | |
… | |
21 | |
21 | |
22 | $self->{set} = sub { }; |
22 | $self->{set} = sub { }; |
23 | $self->{format} = sub { "???" }; |
23 | $self->{format} = sub { "???" }; |
24 | } |
24 | } |
25 | |
25 | |
|
|
26 | sub FINALIZE_INSTANCE { |
|
|
27 | my $self = shift; |
|
|
28 | |
|
|
29 | $self->stop; |
|
|
30 | } |
|
|
31 | |
26 | sub configure { |
32 | sub configure { |
27 | my ($self, $timesys, $main, $interval, $count) = @_; |
33 | my ($self, $timesys, $main, $interval, $count) = @_; |
28 | |
34 | |
29 | if ($timesys == TIMESYS_ABSOLUTE) { |
35 | if ($timesys == TIMESYS_ABSOLUTE) { |
30 | $self->{set} = sub { $self->{time} = $_[0] }; |
36 | $self->{format} = sub { |
31 | $self->{format} = sub { util::format_time $_[0] }; |
37 | if ($_[0] <= 0) { |
|
|
38 | "TIMEOUT"; |
|
|
39 | } else { |
|
|
40 | util::format_time $_[0]; |
|
|
41 | } |
|
|
42 | }; |
32 | |
43 | |
33 | } elsif ($timesys == TIMESYS_BYO_YOMI) { |
44 | } elsif ($timesys == TIMESYS_BYO_YOMI) { |
34 | my $low = $interval * $count; |
45 | my $low = $interval * $count; |
35 | |
46 | |
36 | $self->{set} = sub { $self->{time} = $_[0] }; |
|
|
37 | |
|
|
38 | $self->{format} = sub { |
47 | $self->{format} = sub { |
|
|
48 | if ($_[0] <= 0) { |
|
|
49 | "TIMEOUT"; |
39 | if ($_[0] > $low) { |
50 | } elsif ($_[0] > $low) { |
40 | util::format_time $_[0] - $low; |
51 | util::format_time $_[0] - $low; |
41 | } else { |
52 | } else { |
42 | sprintf "%s (%d)", |
53 | sprintf "%s (%d)", |
43 | util::format_time int (($_[0] - 1) % $interval + 1), |
54 | util::format_time int (($_[0] - 1) % $interval + 1), |
44 | ($_[0] - 1) / $interval; |
55 | ($_[0] - 1) / $interval; |
45 | } |
56 | } |
46 | }; |
57 | }; |
47 | |
58 | |
48 | } elsif ($timesys == TIMESYS_CANADIAN) { |
59 | } elsif ($timesys == TIMESYS_CANADIAN) { |
49 | $self->{set} = sub { $self->{time} = $_[0]; $self->{moves} = $_[1] }; |
|
|
50 | |
|
|
51 | $self->{format} = sub { |
60 | $self->{format} = sub { |
|
|
61 | if ($_[0] <= 0) { |
|
|
62 | "TIMEOUT"; |
52 | if (!$self->{moves}) { |
63 | } elsif (!$self->{moves}) { |
53 | util::format_time $_[0] - $low; |
64 | util::format_time $_[0] - $low; |
54 | } else { |
65 | } else { |
55 | my $time = int (($_[0] - 1) % $interval + 1); |
66 | my $time = int (($_[0] - 1) % $interval + 1); |
56 | |
67 | |
57 | sprintf "%s/%d =%d", |
68 | sprintf "%s/%d =%d", |
… | |
… | |
63 | } |
74 | } |
64 | }; |
75 | }; |
65 | |
76 | |
66 | } else { |
77 | } else { |
67 | # none, or unknown |
78 | # none, or unknown |
68 | $self->{set} = sub { }; |
|
|
69 | $self->{format} = sub { "---" } |
79 | $self->{format} = sub { "-" } |
70 | } |
80 | } |
71 | } |
81 | } |
72 | |
82 | |
73 | sub refresh { |
83 | sub refresh { |
74 | my ($self, $timestamp) = @_; |
84 | my ($self, $timestamp) = @_; |
… | |
… | |
76 | |
86 | |
77 | # we round the timer value slightly... the protocol isn't exact anyways, |
87 | # we round the timer value slightly... the protocol isn't exact anyways, |
78 | # and this gives smoother timers ;) |
88 | # and this gives smoother timers ;) |
79 | my $timer2 = int $timer + 0.4; |
89 | my $timer2 = int $timer + 0.4; |
80 | |
90 | |
81 | if ($timer2 <= 0) { |
91 | $self->set_text ($self->{format}->($timer2)); |
82 | $timer2 = 0 if $timer2 < 0; |
92 | |
83 | $self->set_text ("TIME OUT"); |
93 | $timer - int $timer; |
|
|
94 | } |
|
|
95 | |
|
|
96 | sub set_time { |
|
|
97 | my ($self, $start, $time, $moves) = @_; |
|
|
98 | |
|
|
99 | $self->{time} = $time; |
|
|
100 | $self->{moves} = $moves; |
|
|
101 | |
|
|
102 | if ($start) { |
|
|
103 | $self->{start} = $start; |
|
|
104 | $self->start; |
84 | } else { |
105 | } else { |
85 | $self->set_text ($self->{format}->($timer2)); |
106 | $self->stop; |
86 | } |
|
|
87 | |
|
|
88 | $timer - int $timer; |
|
|
89 | } |
|
|
90 | |
|
|
91 | sub set_time { |
|
|
92 | my ($self, $time, $moves) = @_; |
|
|
93 | |
|
|
94 | # we ignore requests to re-set the time of a running clock. |
|
|
95 | # this is the easiest way to ensure that commentary etc. |
|
|
96 | # doesn't re-set the clock. yes, this is frickle design, |
|
|
97 | # but I think the protocol is to blame here, which gives |
|
|
98 | # very little time information. (cgoban2 also has had quite |
|
|
99 | # a lot of small time update problems...) |
|
|
100 | unless ($self->{timeout}) { |
|
|
101 | $self->{set}->($time, $moves); |
|
|
102 | $self->refresh ($self->{start}); |
107 | $self->refresh ($self->{start}); |
103 | } |
108 | } |
104 | } |
109 | } |
105 | |
110 | |
106 | sub start { |
111 | sub start { |
107 | my ($self, $when) = @_; |
112 | my ($self) = @_; |
108 | |
113 | |
109 | $self->stop; |
114 | $self->stop; |
110 | |
|
|
111 | $self->{start} = $when; |
|
|
112 | |
115 | |
113 | my $timeout; $timeout = sub { |
116 | my $timeout; $timeout = sub { |
114 | my $next = $self->refresh (Time::HiRes::time) * 1000; |
117 | my $next = $self->refresh (Time::HiRes::time) * 1000; |
115 | $next += 1000 if $next < 0; |
118 | $next += 1000 if $next < 0; |
116 | $self->{timeout} = add Glib::Timeout $next, $timeout; |
119 | $self->{timeout} = add Glib::Timeout $next, $timeout; |
… | |
… | |
180 | |
183 | |
181 | $self->{info}->set_text ("$captures pris."); |
184 | $self->{info}->set_text ("$captures pris."); |
182 | } |
185 | } |
183 | |
186 | |
184 | sub set_timer { |
187 | sub set_timer { |
185 | my ($self, $when, $time, $moves) = @_; |
188 | my ($self, $start, $time, $moves) = @_; |
186 | |
189 | |
187 | $self->{clock}->stop unless $when; |
|
|
188 | $self->{clock}->set_time ($time, $moves); |
190 | $self->{clock}->set_time ($start, $time, $moves); |
189 | $self->{clock}->start ($when) if $when; |
|
|
190 | } |
191 | } |
191 | |
192 | |
192 | package game; |
193 | package game; |
193 | |
194 | |
194 | use Scalar::Util qw(weaken); |
195 | use Scalar::Util qw(weaken); |
… | |
… | |
388 | dead => !($self->{cur_board}{board}[$_[0]][$_[1]] & MARK_GRAYED), |
389 | dead => !($self->{cur_board}{board}[$_[0]][$_[1]] & MARK_GRAYED), |
389 | ); |
390 | ); |
390 | } |
391 | } |
391 | }; |
392 | }; |
392 | |
393 | |
393 | } elsif (1 - $self->{colour} == $self->{cur_board}{last}) { |
394 | } elsif ($self->{colour} == $self->{whosemove}) { |
394 | # normal move |
395 | # normal move |
395 | $self->{button_pass}->set (label => "Pass", sensitive => 1, visible => 1); |
396 | $self->{button_pass}->set (label => "Pass", sensitive => 1, visible => 1); |
396 | $self->{board}->set (cursor => sub { |
397 | $self->{board}->set (cursor => sub { |
397 | # if is_valid_move oder so#TODO# |
398 | # if is_valid_move oder so#TODO# |
398 | $_[0] & (MARK_B | MARK_W) |
399 | $_[0] & (MARK_B | MARK_W) |
… | |
… | |
405 | delete $self->{board_click}; |
406 | delete $self->{board_click}; |
406 | $self->{button_pass}->sensitive (0); |
407 | $self->{button_pass}->sensitive (0); |
407 | }; |
408 | }; |
408 | } else { |
409 | } else { |
409 | $self->{button_pass}->set (label => "Pass", sensitive => 0, visible => 1); |
410 | $self->{button_pass}->set (label => "Pass", sensitive => 0, visible => 1); |
|
|
411 | $self->{board}->set (cursor => undef); |
410 | } |
412 | } |
411 | } else { |
413 | } else { |
412 | $self->{button_undo}->hide; |
414 | $self->{button_undo}->hide; |
413 | $self->{button_resign}->hide; |
415 | $self->{button_resign}->hide; |
414 | $self->{button_pass}->hide; |
416 | $self->{button_pass}->hide; |
… | |
… | |
423 | my $running = $self->{showmove} == @{$self->{path}} && !$self->{teacher}; |
425 | my $running = $self->{showmove} == @{$self->{path}} && !$self->{teacher}; |
424 | |
426 | |
425 | for my $colour (COLOUR_BLACK, COLOUR_WHITE) { |
427 | for my $colour (COLOUR_BLACK, COLOUR_WHITE) { |
426 | my $t = $timers->[$colour]; |
428 | my $t = $timers->[$colour]; |
427 | $self->{userpanel}[$colour]->set_timer ( |
429 | $self->{userpanel}[$colour]->set_timer ( |
428 | $running && $self->{lastmove_colour} == 1 - $colour && $t->[0], |
430 | $running && $colour == $self->{whosemove} && $t->[0], |
429 | $t->[1], $t->[2]); |
431 | $t->[1] || $self->{rules}{time} |
|
|
432 | + ($self->{rules}{timesys} == TIMESYS_BYO_YOMI |
|
|
433 | && $self->{rules}{interval} * $self->{rules}{count}), |
|
|
434 | $t->[2] || $self->{rules}{count}); |
430 | } |
435 | } |
431 | } |
436 | } |
432 | |
437 | |
433 | sub update_board { |
438 | sub update_board { |
434 | my ($self) = @_; |
439 | my ($self) = @_; |
… | |
… | |
439 | $self->{cur_board} = new KGS::Game::Board $self->{size}; |
444 | $self->{cur_board} = new KGS::Game::Board $self->{size}; |
440 | $self->{cur_board}->interpret_path ([@{$self->{path}}[0 .. $self->{showmove} - 1]]); |
445 | $self->{cur_board}->interpret_path ([@{$self->{path}}[0 .. $self->{showmove} - 1]]); |
441 | |
446 | |
442 | $self->{userpanel}[$_]->set_captures ($self->{cur_board}{captures}[$_]) |
447 | $self->{userpanel}[$_]->set_captures ($self->{cur_board}{captures}[$_]) |
443 | for COLOUR_WHITE, COLOUR_BLACK; |
448 | for COLOUR_WHITE, COLOUR_BLACK; |
|
|
449 | |
|
|
450 | if ($self->{rules}{ruleset} == RULESET_JAPANESE) { |
|
|
451 | if ($self->{curnode}{move} == 0) { |
|
|
452 | $self->{whosemove} = $self->{handicap} ? COLOUR_WHITE : COLOUR_BLACK; |
|
|
453 | } else { |
|
|
454 | $self->{whosemove} = 1 - $self->{cur_board}{last}; |
|
|
455 | } |
|
|
456 | } else { |
|
|
457 | # Chinese, Aga, NZ all have manual placement |
|
|
458 | if ($self->{curnode}{move} < $self->{handicap}) { |
|
|
459 | $self->{whosemove} = COLOUR_BLACK; |
|
|
460 | } elsif ($self->{curnode}{move} == $self->{handicap}) { |
|
|
461 | $self->{whosemove} = COLOUR_WHITE; |
|
|
462 | } else { |
|
|
463 | $self->{whosemove} = 1 - $self->{cur_board}{last}; |
|
|
464 | } |
|
|
465 | } |
|
|
466 | |
|
|
467 | my $start_time = $self->{rules}{time}; |
444 | |
468 | |
445 | if ($self->{showmove} == @{$self->{path}}) { |
469 | if ($self->{showmove} == @{$self->{path}}) { |
446 | $self->{timers} = [ |
470 | $self->{timers} = [ |
447 | [$self->{lastmove_time}, @{$self->{cur_board}{timer}[0]}], |
471 | [$self->{lastmove_time}, @{$self->{cur_board}{timer}[0]}], |
448 | [$self->{lastmove_time}, @{$self->{cur_board}{timer}[1]}], |
472 | [$self->{lastmove_time}, @{$self->{cur_board}{timer}[1]}], |
… | |
… | |
455 | ]); |
479 | ]); |
456 | } |
480 | } |
457 | |
481 | |
458 | $self->{board}->set_board ($self->{cur_board}); |
482 | $self->{board}->set_board ($self->{cur_board}); |
459 | |
483 | |
|
|
484 | if ($self->{cur_board}{score}) { |
|
|
485 | $self->{score_inlay} ||= $self->{chat}->new_inlay; |
|
|
486 | $self->{score_inlay}->clear; |
|
|
487 | $self->{score_inlay}->append_text ("\n<header>Scoring</header>" |
|
|
488 | . "\n<score>" |
|
|
489 | . "White: $self->{cur_board}{score}[COLOUR_WHITE], " |
|
|
490 | . "Black: $self->{cur_board}{score}[COLOUR_BLACK]" |
|
|
491 | . "</score>"); |
|
|
492 | } elsif ($self->{score_inlay}) { |
|
|
493 | (delete $self->{score_inlay})->clear; |
|
|
494 | } |
|
|
495 | |
460 | $self->update_cursor; |
496 | $self->update_cursor; |
461 | } |
497 | } |
462 | |
498 | |
463 | sub event_update_tree { |
499 | sub event_update_tree { |
464 | my ($self) = @_; |
500 | my ($self) = @_; |
|
|
501 | |
|
|
502 | (delete $self->{undo_inlay})->clear |
|
|
503 | if $self->{undo_inlay}; |
465 | |
504 | |
466 | $self->{path} = $self->get_path; |
505 | $self->{path} = $self->get_path; |
467 | |
506 | |
468 | if ($self->{moveadj}) { |
507 | if ($self->{moveadj}) { |
469 | my $upper = $self->{moveadj}->upper; |
508 | my $upper = $self->{moveadj}->upper; |
… | |
… | |
533 | } |
572 | } |
534 | |
573 | |
535 | sub event_move { |
574 | sub event_move { |
536 | my ($self, $pass) = @_; |
575 | my ($self, $pass) = @_; |
537 | sound::play 1, $pass ? "pass" : "move"; |
576 | sound::play 1, $pass ? "pass" : "move"; |
538 | |
|
|
539 | if ($self->{undo_inlay}) { |
|
|
540 | (delete $self->{undo_inlay})->clear; |
|
|
541 | } |
|
|
542 | } |
577 | } |
543 | |
578 | |
544 | sub event_update_game { |
579 | sub event_update_game { |
545 | my ($self) = @_; |
580 | my ($self) = @_; |
546 | |
581 | |
… | |
… | |
701 | $self->{timers} = [ |
736 | $self->{timers} = [ |
702 | [$msg->{NOW}, $msg->{black_time}, $msg->{black_moves}], |
737 | [$msg->{NOW}, $msg->{black_time}, $msg->{black_moves}], |
703 | [$msg->{NOW}, $msg->{white_time}, $msg->{white_moves}], |
738 | [$msg->{NOW}, $msg->{white_time}, $msg->{white_moves}], |
704 | ]; |
739 | ]; |
705 | |
740 | |
706 | print "SGT\n";#d# |
|
|
707 | $self->update_timers ($self->{timers}) |
741 | $self->update_timers ($self->{timers}) |
708 | if $self->{showmove} == @{$self->{path}}; |
742 | if $self->{showmove} == @{$self->{path}}; |
709 | } |
743 | } |
710 | |
744 | |
711 | sub inject_req_undo { |
745 | sub inject_req_undo { |
… | |
… | |
718 | $inlay->{count}++; |
752 | $inlay->{count}++; |
719 | |
753 | |
720 | $inlay->clear; |
754 | $inlay->clear; |
721 | $inlay->append_text ("\n<undo>Undo requested ($inlay->{count} times)</undo>\n"); |
755 | $inlay->append_text ("\n<undo>Undo requested ($inlay->{count} times)</undo>\n"); |
722 | $inlay->append_button ("Grant", sub { |
756 | $inlay->append_button ("Grant", sub { |
723 | $inlay->clear; |
757 | (delete $self->{undo_inlay})->clear; |
724 | $self->send (grant_undo => channel => $self->{channel}); |
758 | $self->send (grant_undo => channel => $self->{channel}); |
725 | }); |
759 | }); |
726 | $inlay->append_button ("Ignore", sub { |
760 | $inlay->append_button ("Ignore", sub { |
727 | $inlay->clear; |
761 | $inlay->clear; |
728 | $inlay->{ignore} = 1; |
762 | $inlay->{ignore} = 1; |
… | |
… | |
747 | my $rules = $info->{rules}; |
781 | my $rules = $info->{rules}; |
748 | |
782 | |
749 | my $as_black = $info->{black}{name} eq $self->{conn}{name} ? 1 : 0;; |
783 | my $as_black = $info->{black}{name} eq $self->{conn}{name} ? 1 : 0;; |
750 | my $opponent = $as_black ? $info->{white} : $info->{black}; |
784 | my $opponent = $as_black ? $info->{white} : $info->{black}; |
751 | |
785 | |
752 | my ($size, $time, $interval, $count); |
786 | my ($size, $time, $interval, $count, $type); |
753 | |
787 | |
754 | if (!$self->{channel}) { |
788 | if (!$self->{channel}) { |
755 | $inlay->append_text ("\nNotes: "); |
789 | $inlay->append_text ("\nNotes: "); |
756 | $inlay->append_entry (\$info->{notes}, 20, ""); |
790 | $inlay->append_entry (\$info->{notes}, 20, ""); |
757 | $inlay->append_text ("\nGlobal Offer: "); |
791 | $inlay->append_text ("\nGlobal Offer: "); |
… | |
… | |
762 | } else { |
796 | } else { |
763 | $inlay->append_text ("\nNotes: " . util::toxml $info->{notes}); |
797 | $inlay->append_text ("\nNotes: " . util::toxml $info->{notes}); |
764 | } |
798 | } |
765 | |
799 | |
766 | $inlay->append_text ("\nType: "); |
800 | $inlay->append_text ("\nType: "); |
767 | $inlay->append_optionmenu ( |
801 | $type = $inlay->append_optionmenu ( |
768 | \$info->{gametype}, |
802 | \$info->{gametype}, |
769 | GAMETYPE_DEMONSTRATION , "Demonstration", |
803 | GAMETYPE_DEMONSTRATION , "Demonstration (not yet)", |
770 | GAMETYPE_DEMONSTRATION | GAMETYPE_PRIVATE, "Demonstration (P)", |
804 | GAMETYPE_DEMONSTRATION | GAMETYPE_PRIVATE, "Demonstration (P) (not yet)", |
771 | GAMETYPE_TEACHING , "Teaching", |
805 | GAMETYPE_TEACHING , "Teaching (not yet)", |
772 | GAMETYPE_TEACHING | GAMETYPE_PRIVATE, "Teaching (P)", |
806 | GAMETYPE_TEACHING | GAMETYPE_PRIVATE, "Teaching (P) (not yet)", |
773 | GAMETYPE_SIMUL , "Simul (not yet!)", |
807 | GAMETYPE_SIMUL , "Simul (not yet!)", |
774 | GAMETYPE_FREE , "Free", |
808 | GAMETYPE_FREE , "Free", |
775 | GAMETYPE_RATED , "Rated", |
809 | GAMETYPE_RATED , "Rated", |
776 | sub { |
810 | sub { |
777 | $size->set_history (2) if $_[0] eq GAMETYPE_RATED; |
811 | $size->set_history (2) if $_[0] eq GAMETYPE_RATED; |
… | |
… | |
801 | RULESET_NEW_ZEALAND, "New Zealand", |
835 | RULESET_NEW_ZEALAND, "New Zealand", |
802 | ); |
836 | ); |
803 | |
837 | |
804 | $inlay->append_text ("\nSize: "); |
838 | $inlay->append_text ("\nSize: "); |
805 | $size = $inlay->append_optionmenu ( |
839 | $size = $inlay->append_optionmenu ( |
|
|
840 | \$info->{rules}{size}, |
806 | \$info->{rules}{size}, 9 => 9, 13 => 13, 19 => 19, map +($_, $_), 2..38 |
841 | (9 => 9, 13 => 13, 19 => 19, map +($_, $_), 2..38), |
|
|
842 | sub { |
|
|
843 | $type->set_history (5) # reset to free |
|
|
844 | if $_[0] != 19 && $info->{gametype} == GAMETYPE_RATED; |
|
|
845 | }, |
807 | ); |
846 | ); |
808 | |
847 | |
809 | if ($self->{channel}) { |
848 | if ($self->{channel}) { |
810 | $inlay->append_text ("\nHandicap: "); |
849 | $inlay->append_text ("\nHandicap: "); |
811 | $inlay->append_optionmenu (\$info->{rules}{handicap}, map +($_, $_), 0..9); |
850 | $inlay->append_optionmenu (\$info->{rules}{handicap}, map +($_, $_), 0..9); |