ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/kgsueme/kgsueme/game.pl
(Generate patch)

Comparing kgsueme/kgsueme/game.pl (file contents):
Revision 1.107 by root, Mon May 31 02:04:40 2004 UTC vs.
Revision 1.114 by root, Tue Jun 1 12:46:54 2004 UTC

1use utf8; 1use utf8;
2 2
3use Scalar::Util (); 3use Scalar::Util ();
4
5### GO CLOCK WIDGET #########################################################
4 6
5package game::goclock; 7package game::goclock;
6 8
7# Lo and Behold! I admit it! The rounding stuff etc.. in goclock 9# Lo and Behold! I admit it! The rounding stuff etc.. in goclock
8# is completely borked. 10# is completely borked.
32sub configure { 34sub configure {
33 my ($self, $timesys, $main, $interval, $count) = @_; 35 my ($self, $timesys, $main, $interval, $count) = @_;
34 36
35 if ($timesys == TIMESYS_ABSOLUTE) { 37 if ($timesys == TIMESYS_ABSOLUTE) {
36 $self->{format} = sub { 38 $self->{format} = sub {
37 if ($_[0] <= 0) { 39 if ($_[0] < 0) {
38 "TIMEOUT"; 40 "TIMEOUT";
39 } else { 41 } else {
40 util::format_time $_[0]; 42 util::format_time $_[0];
41 } 43 }
42 }; 44 };
43 45
44 } elsif ($timesys == TIMESYS_BYO_YOMI) { 46 } elsif ($timesys == TIMESYS_BYO_YOMI) {
45 my $low = $interval * $count; 47 my $low = $interval * $count;
46 48
47 $self->{format} = sub { 49 $self->{format} = sub {
48 if ($_[0] <= 0) { 50 if ($_[0] < 0) {
49 "TIMEOUT"; 51 "TIMEOUT";
50 } elsif ($_[0] > $low) { 52 } elsif ($_[0] > $low) {
51 util::format_time $_[0] - $low; 53 util::format_time $_[0] - $low;
52 } else { 54 } else {
53 sprintf "%s (%d)", 55 sprintf "%s (%d)",
56 } 58 }
57 }; 59 };
58 60
59 } elsif ($timesys == TIMESYS_CANADIAN) { 61 } elsif ($timesys == TIMESYS_CANADIAN) {
60 $self->{format} = sub { 62 $self->{format} = sub {
61 if ($_[0] <= 0) { 63 if ($_[0] < 0) {
62 "TIMEOUT"; 64 "TIMEOUT";
63 } elsif (!$self->{moves}) { 65 } elsif (!$self->{moves}) {
64 util::format_time $_[0] - $low; 66 util::format_time $_[0] - $low;
65 } else { 67 } else {
66 my $time = int (($_[0] - 1) % $interval + 1); 68 my $time = int (($_[0] - 1) % $interval + 1);
127 my ($self) = @_; 129 my ($self) = @_;
128 130
129 remove Glib::Source delete $self->{timeout} if $self->{timeout}; 131 remove Glib::Source delete $self->{timeout} if $self->{timeout};
130} 132}
131 133
134### USER PANEL ##############################################################
135
132package game::userpanel; 136package game::userpanel;
133 137
138use KGS::Constants;
139
134use Glib::Object::Subclass 140use Glib::Object::Subclass
135 Gtk2::HBox, 141 Gtk2::Frame,
136 properties => [ 142 properties => [
137 Glib::ParamSpec->IV ("colour", "colour", "User Colour", 0, 1, 0, [qw(construct-only writable)]), 143 Glib::ParamSpec->IV ("colour", "colour", "User Colour",
144 COLOUR_BLACK, COLOUR_WHITE, COLOUR_BLACK,
145 [qw(construct-only readable writable)]),
138 ]; 146 ];
139 147
140sub INIT_INSTANCE { 148sub INIT_INSTANCE {
141 my ($self) = @_; 149 my ($self) = @_;
142 150
143 $self->add (my $vbox = new Gtk2::VBox); 151 $self->add (my $vbox = new Gtk2::VBox);
144 152
145 $vbox->add ($self->{name} = new Gtk2::Label $self->{name}); 153 $vbox->pack_start (($self->{name} = new Gtk2::Label "-"), 1, 1, 0);
146 $vbox->add ($self->{info} = new Gtk2::Label ""); 154 $vbox->pack_start (($self->{info} = new Gtk2::Label "-"), 1, 1, 0);
147 $vbox->add ($self->{clock} = new game::goclock); Scalar::Util::weaken $self->{clock}; 155 $vbox->pack_start (($self->{clock} = new game::goclock), 1, 1, 0);
148 156
149 $vbox->add ($self->{imagebox} = new Gtk2::VBox); 157 $vbox->add ($self->{imagebox} = new Gtk2::VBox);
150 158
151 $self; 159 $self;
152} 160}
188 my ($self, $start, $time, $moves) = @_; 196 my ($self, $start, $time, $moves) = @_;
189 197
190 $self->{clock}->set_time ($start, $time, $moves); 198 $self->{clock}->set_time ($start, $time, $moves);
191} 199}
192 200
201### GAME WINDOW #############################################################
202
193package game; 203package game;
194 204
195use Scalar::Util qw(weaken); 205use Scalar::Util qw(weaken);
196 206
197use KGS::Constants; 207use KGS::Constants;
226 236
227 # LEFT PANE 237 # LEFT PANE
228 238
229 $hpane->pack1 (($self->{left} = new Gtk2::VBox), 1, 0); 239 $hpane->pack1 (($self->{left} = new Gtk2::VBox), 1, 0);
230 240
231 $self->{boardbox} = new Gtk2::VBox;
232
233 $hpane->pack1((my $vbox = new Gtk2::VBox), 1, 1); 241 $hpane->pack1((my $vbox = new Gtk2::VBox), 1, 1);
234 242
235 # board box (aspect/canvas) 243 # board box (aspect/canvas)
236 244
237 #$self->{boardbox}->pack_start((my $frame = new Gtk2::Frame), 0, 1, 0);
238
239 # RIGHT PANE 245 # RIGHT PANE
240 246
241 $hpane->pack2 ((my $vbox = new Gtk2::VBox), 1, 1); 247 $hpane->pack2 ((my $vbox = new Gtk2::VBox), 1, 1);
242 $hpane->set (position_set => 1); 248 $hpane->set (position_set => 1);
243 249
244 $vbox->pack_start ((my $frame = new Gtk2::Frame), 0, 1, 0); 250 $vbox->pack_start ((my $frame = new Gtk2::Frame), 0, 1, 0);
245 251
246 { 252 {
247 $frame->add (my $vbox = new Gtk2::VBox); 253 $frame->add (my $vbox = new Gtk2::VBox);
248 $vbox->add ($self->{title} = new Gtk2::Label $title); 254 $vbox->add ($self->{title} = new Gtk2::Label "-");
249 255
250 $vbox->add (my $hbox = new Gtk2::HBox); 256 $vbox->add (my $hbox = new Gtk2::HBox);
251 257
252 $hbox->pack_start (($self->{board_label} = new Gtk2::Label), 0, 1, 0); 258 $hbox->pack_start (($self->{board_label} = new Gtk2::Label), 0, 0, 0);
253 259
254 $self->{moveadj} = new Gtk2::Adjustment 1, 1, 1, 1, 5, 0; 260 $self->{moveadj} = new Gtk2::Adjustment 1, 1, 1, 1, 5, 0;
255 261
256 $hbox->pack_start ((my $scale = new Gtk2::HScale $self->{moveadj}), 1, 1, 0); 262 $hbox->pack_start ((my $scale = new Gtk2::HScale $self->{moveadj}), 1, 1, 0);
257 $scale->set_draw_value (0); 263 $scale->set_draw_value (0);
316 } 322 }
317 }); 323 });
318 } 324 }
319} 325}
320 326
327### JOIN/LEAVE ##############################################################
328
329sub join {
330 my ($self) = @_;
331 return if $self->{joined};
332
333 $self->SUPER::join;
334}
335
336sub event_join {
337 my ($self) = @_;
338
339 $self->SUPER::event_join (@_);
340 $self->init_tree;
341 $self->event_update_game;
342}
343
344sub event_part {
345 my ($self) = @_;
346
347 $self->SUPER::event_part;
348 $self->destroy;
349}
350
351sub event_quit {
352 my ($self) = @_;
353
354 $self->SUPER::event_quit;
355 $self->destroy;
356}
357
358### USERS ###################################################################
359
360sub draw_users {
361 my ($self, $inlay) = @_;
362
363 for (sort keys %{$self->{users}}) {
364 $inlay->append_text (" <user>" . $self->{users}{$_}->as_string . "</user>");
365 }
366}
367
321sub event_update_users { 368sub event_update_users {
322 my ($self, $add, $update, $remove) = @_; 369 my ($self, $add, $update, $remove) = @_;
323 370
324# $self->{userlist}->update ($add, $update, $remove); 371# $self->{userlist}->update ($add, $update, $remove);
325 372
341 $self->{chat}->append_text ("\n<header>Parts:</header>"); 388 $self->{chat}->append_text ("\n<header>Parts:</header>");
342 $self->{chat}->append_text (" <user>" . $_->as_string . "</user>") for @users; 389 $self->{chat}->append_text (" <user>" . $_->as_string . "</user>") for @users;
343 } 390 }
344} 391}
345 392
346sub join { 393### GAME INFO ###############################################################
394
395sub draw_setup {
347 my ($self) = @_; 396 my ($self, $inlay) = @_;
397
348 return if $self->{joined}; 398 return unless $self->{joined};
349 399
350 $self->SUPER::join; 400 my $rules = $self->{rules};
401
402 my $text = "";
403
404 $text .= "\nTeacher: <user>" . (util::toxml $self->{teacher}) . "</user>"
405 if $self->{teacher};
406
407 $text .= "\nOwner: <user>" . (util::toxml $self->{owner}->as_string) . "</user>"
408 if $self->{owner}->is_valid;
409
410 if ($self->is_inprogress) {
411 $text .= "\nPlayers: <user>" . (util::toxml $self->{white}->as_string) . "</user>"
412 . " vs. <user>" . (util::toxml $self->{black}->as_string) . "</user>";
413 }
414 $text .= "\nType: " . util::toxml $gametype{$self->type};
415
416 $text .= "\nRuleset: " . $ruleset{$rules->{ruleset}};
417
418 $text .= "\nTime: ";
419
420 if ($rules->{timesys} == TIMESYS_NONE) {
421 $text .= "UNLIMITED";
422 } elsif ($rules->{timesys} == TIMESYS_ABSOLUTE) {
423 $text .= util::format_time $rules->{time};
424 $text .= " ABS";
425 } elsif ($rules->{timesys} == TIMESYS_BYO_YOMI) {
426 $text .= util::format_time $rules->{time};
427 $text .= sprintf " + %s (%d) BY", util::format_time $rules->{interval}, $rules->{count};
428 } elsif ($rules->{timesys} == TIMESYS_CANADIAN) {
429 $text .= util::format_time $rules->{time};
430 $text .= sprintf " + %s/%d CAN", util::format_time $rules->{interval}, $rules->{count};
431 }
432
433 $text .= "\nFlags:";
434 $text .= " private" if $self->is_private;
435 $text .= " started" if $self->is_inprogress;
436 $text .= " adjourned" if $self->is_adjourned;
437 $text .= " scored" if $self->is_scored;
438 $text .= " saved" if $self->is_saved;
439
440 if ($self->is_inprogress) {
441 $text .= "\nHandicap: " . $self->{handicap};
442 $text .= "\nKomi: " . $self->{komi};
443 $text .= "\nSize: " . $self->size_string;
444 }
445
446 if ($self->is_scored) {
447 $text .= "\nResult: " . $self->score_string;
448 }
449
450 $inlay->append_text ("<infoblock>$text</infoblock>");
451
452}
453
454sub event_update_game {
455 my ($self) = @_;
456
457 $self->SUPER::event_update_game;
458
459 return unless $self->{joined};
460
461 $self->{colour} = $self->player_colour ($self->{conn}{name});
462
463 $self->{user}[COLOUR_BLACK] = $self->{black};
464 $self->{user}[COLOUR_WHITE] = $self->{white};
465
466 # show board
467 if ($self->is_inprogress) {
468 if (!$self->{board}) {
469 $self->{left}->add ($self->{board} = new Gtk2::GoBoard size => $self->{size});
470 $self->{board}->signal_connect (button_release => sub {
471 return unless $self->{cur_board};
472 if ($_[1] == 1) {
473 $self->{board_click}->($_[2], $_[3]) if $self->{board_click};
474 }
475 });
476 $self->{board}->show_all;
477 }
478 if (my $ch = delete $self->{challenge}) {
479 $_->{inlay}->destroy for values %$ch;
480 }
481 $self->update_cursor;
482 }
483
484 my $title = defined $self->{channel}
485 ? $self->owner->as_string . " " . $self->opponent_string
486 : "Game Window";
487 $self->set_title ("KGS Game $title");
488 $self->{title}->set_text ($title); # title gets redrawn wrongly
489
490 $self->{rules_inlay}->refresh;
491
492 if (exists $self->{teacher}) {
493 $self->{teacher_inlay} ||= $self->{chat}->new_inlay;
494 $self->{teacher_inlay}->clear;
495 $self->{teacher_inlay}->append_text ("\n<header>Teacher:</header> <user>"
496 . (util::toxml $self->{teacher}) . "</user>");
497 } elsif ($self->{teacher_inlay}) {
498 (delete $self->{teacher_inlay})->clear;
499 }
500
501 $self->update_cursor;
502}
503
504sub event_update_rules {
505 my ($self, $rules) = @_;
506
507 $self->{rules} = $rules;
508
509 if ($self->{user}) {
510 # todo. gets drawn wrongly
511
512 $self->{userpanel}[$_]->configure ($self->{app}, $self->{user}[$_], $rules)
513 for COLOUR_BLACK, COLOUR_WHITE;
514 }
515
516 sound::play 3, "gamestart";
517 $self->{rules_inlay}->refresh;
518}
519
520### BOARD DISPLAY ###########################################################
521
522sub update_timers {
523 my ($self, $timers) = @_;
524
525 my $running = $self->{showmove} == @{$self->{path}} && !$self->{teacher};
526
527 for my $colour (COLOUR_BLACK, COLOUR_WHITE) {
528 my $t = $timers->[$colour];
529 $self->{userpanel}[$colour]->set_timer (
530 $running && $colour == $self->{whosemove} && $t->[0],
531 $t->[1] || $self->{rules}{time}
532 + ($self->{rules}{timesys} == TIMESYS_BYO_YOMI
533 && $self->{rules}{interval} * $self->{rules}{count}),
534 $t->[2]);
535 }
536}
537
538sub inject_set_gametime {
539 my ($self, $msg) = @_;
540
541 $self->{timers} = [
542 [$msg->{NOW}, $msg->{black_time}, $msg->{black_moves}],
543 [$msg->{NOW}, $msg->{white_time}, $msg->{white_moves}],
544 ];
545
546 $self->update_timers ($self->{timers})
547 if $self->{showmove} == @{$self->{path}};
351} 548}
352 549
353sub update_cursor { 550sub update_cursor {
354 my ($self) = @_; 551 my ($self) = @_;
355 552
553 return unless $self->{cur_board};
554
356 my $running = $self->{showmove} == @{$self->{path}} && $self->is_active; 555 my $running = $self->{showmove} == @{$self->{path}} && $self->is_active;
357 556
358 delete $self->{board_click}; 557 delete $self->{board_click};
359 558
559 $self->{colour} = COLOUR_BLACK;#d#
560 $self->{whosemove} = COLOUR_BLACK;#d#
360 if ($self->{teacher} eq $self->{app}{conn}) { 561 if ($self->{teacher} eq $self->{app}{conn}) {
361 #TODO# # teaching mode not implemented 562 #TODO# # teaching mode not implemented
362 $self->{button_pass}->set (label => "Pass", visible => 1, sensitive => 1); 563 $self->{button_pass}->set (label => "Pass", visible => 1, sensitive => 1);
363 $self->{button_undo}->hide; 564 $self->{button_undo}->hide;
364 $self->{button_resign}->hide; 565 $self->{button_resign}->hide;
378 : $_[0]; 579 : $_[0];
379 }); 580 });
380 $self->{board_click} = sub { 581 $self->{board_click} = sub {
381 if ($_[0] == 255) { 582 if ($_[0] == 255) {
382 $self->{button_pass}->sensitive (0); 583 $self->{button_pass}->sensitive (0);
383 warn sprintf "SEND DONE @{$self->{done}} %x\n", $self->{doneid};#d#
384 $self->done; 584 $self->done;
385 } else { 585 } else {
386 $self->send (mark_dead => 586 $self->send (mark_dead =>
387 channel => $self->{channel}, 587 channel => $self->{channel},
388 x => $_[0], 588 x => $_[0],
394 594
395 } elsif ($self->{colour} == $self->{whosemove}) { 595 } elsif ($self->{colour} == $self->{whosemove}) {
396 # normal move 596 # normal move
397 $self->{button_pass}->set (label => "Pass", visible => 1, sensitive => 1); 597 $self->{button_pass}->set (label => "Pass", visible => 1, sensitive => 1);
398 $self->{board}->set (cursor => sub { 598 $self->{board}->set (cursor => sub {
399 # if is_valid_move oder so#TODO# 599 $self->{cur_board}
400 $_[0] & (MARK_B | MARK_W) 600 && $self->{cur_board}->is_valid_move ($self->{colour}, $_[1], $_[2],
401 ? $_[0] 601 $self->{rules}{ruleset} == RULESET_NEW_ZEALAND)
402 : $_[0] | MARK_GRAYED | ($self->{colour} == COLOUR_WHITE ? MARK_W : MARK_B); 602 ? $_[0] | MARK_GRAYED | ($self->{colour} == COLOUR_WHITE ? MARK_W : MARK_B)
603 : $_[0];
403 }); 604 });
404 $self->{board_click} = sub { 605 $self->{board_click} = sub {
606 return unless
607 $self->{cur_board}->is_valid_move ($self->{colour}, $_[1], $_[2],
608 $self->{rules}{ruleset} == RULESET_NEW_ZEALAND);
405 $self->send (game_move => channel => $self->{channel}, x => $_[0], y => $_[1]); 609 $self->send (game_move => channel => $self->{channel}, x => $_[0], y => $_[1]);
406 $self->{board}->set (cursor => undef); 610 $self->{board}->set (cursor => undef);
407 delete $self->{board_click}; 611 delete $self->{board_click};
408 $self->{button_pass}->sensitive (0); 612 $self->{button_pass}->sensitive (0);
409 }; 613 };
418 $self->{board}->set (cursor => undef); 622 $self->{board}->set (cursor => undef);
419 #TODO# # implement coordinate-grabbing 623 #TODO# # implement coordinate-grabbing
420 } 624 }
421} 625}
422 626
423sub update_timers {
424 my ($self, $timers) = @_;
425
426 my $running = $self->{showmove} == @{$self->{path}} && !$self->{teacher};
427
428 for my $colour (COLOUR_BLACK, COLOUR_WHITE) {
429 my $t = $timers->[$colour];
430 $self->{userpanel}[$colour]->set_timer (
431 $running && $colour == $self->{whosemove} && $t->[0],
432 $t->[1] || $self->{rules}{time}
433 + ($self->{rules}{timesys} == TIMESYS_BYO_YOMI
434 && $self->{rules}{interval} * $self->{rules}{count}),
435 $t->[2] || $self->{rules}{count});
436 }
437}
438
439sub update_board { 627sub update_board {
440 my ($self) = @_; 628 my ($self) = @_;
629
441 return unless $self->{path}; 630 return unless $self->{path};
442
443 $self->{board_label}->set_text ("Move " . ($self->{showmove} - 1));
444
445 $self->{cur_board} = new KGS::Game::Board $self->{size};
446 $self->{cur_board}->interpret_path ([@{$self->{path}}[0 .. $self->{showmove} - 1]]);
447
448 $self->{userpanel}[$_]->set_captures ($self->{cur_board}{captures}[$_])
449 for COLOUR_WHITE, COLOUR_BLACK;
450 631
451 if ($self->{rules}{ruleset} == RULESET_JAPANESE) { 632 if ($self->{rules}{ruleset} == RULESET_JAPANESE) {
452 if ($self->{curnode}{move} == 0) { 633 if ($self->{curnode}{move} == 0) {
453 $self->{whosemove} = $self->{handicap} ? COLOUR_WHITE : COLOUR_BLACK; 634 $self->{whosemove} = $self->{handicap} ? COLOUR_WHITE : COLOUR_BLACK;
454 } else { 635 } else {
457 } else { 638 } else {
458 # Chinese, Aga, NZ all have manual placement 639 # Chinese, Aga, NZ all have manual placement
459 if ($self->{curnode}{move} < $self->{handicap}) { 640 if ($self->{curnode}{move} < $self->{handicap}) {
460 $self->{whosemove} = COLOUR_BLACK; 641 $self->{whosemove} = COLOUR_BLACK;
461 } elsif ($self->{curnode}{move} == $self->{handicap}) { 642 } elsif ($self->{curnode}{move} == $self->{handicap}) {
462 $self->{whosemove} = COLOUR_WHITE; 643 $self->{whosemove} = $self->{handicap} ? COLOUR_WHITE : COLOUR_BLACK;
463 } else { 644 } else {
464 $self->{whosemove} = 1 - $self->{cur_board}{last}; 645 $self->{whosemove} = 1 - $self->{cur_board}{last};
465 } 646 }
466 } 647 }
648
649 $self->{board_label}->set_text ("Move " . ($self->{showmove} - 1));
650
651 $self->{cur_board} = new KGS::Game::Board $self->{size};
652 $self->{cur_board}->interpret_path ([@{$self->{path}}[0 .. $self->{showmove} - 1]]);
653
654 $self->update_cursor;
655
656 $self->{userpanel}[$_]->set_captures ($self->{cur_board}{captures}[$_])
657 for COLOUR_WHITE, COLOUR_BLACK;
467 658
468 my $start_time = $self->{rules}{time}; 659 my $start_time = $self->{rules}{time};
469 660
470 if ($self->{showmove} == @{$self->{path}}) { 661 if ($self->{showmove} == @{$self->{path}}) {
471 $self->{timers} = [ 662 $self->{timers} = [
491 . "Black: $self->{cur_board}{score}[COLOUR_BLACK]" 682 . "Black: $self->{cur_board}{score}[COLOUR_BLACK]"
492 . "</score>"); 683 . "</score>");
493 } elsif ($self->{score_inlay}) { 684 } elsif ($self->{score_inlay}) {
494 (delete $self->{score_inlay})->clear; 685 (delete $self->{score_inlay})->clear;
495 } 686 }
496
497 $self->update_cursor;
498} 687}
499 688
500sub event_update_tree { 689sub event_update_tree {
501 my ($self) = @_; 690 my ($self) = @_;
502 691
555 } 744 }
556 745
557 $self->{chat}->append_text ($text); 746 $self->{chat}->append_text ($text);
558} 747}
559 748
560sub event_join {
561 my ($self) = @_;
562
563 $self->SUPER::event_join (@_);
564 $self->init_tree;
565 $self->event_update_game;
566}
567
568sub event_part {
569 my ($self) = @_;
570
571 $self->SUPER::event_part;
572 $self->destroy;
573}
574
575sub event_move { 749sub event_move {
576 my ($self, $pass) = @_; 750 my ($self, $pass) = @_;
577 751
578 sound::play 1, $pass ? "pass" : "move"; 752 sound::play 1, $pass ? "pass" : "move";
579} 753}
580 754
581sub event_update_game { 755### GAMEPLAY EVENTS #########################################################
582 my ($self) = @_;
583
584 $self->SUPER::event_update_game;
585
586 return unless $self->{joined};
587
588 $self->{colour} = $self->player_colour ($self->{conn}{name});
589
590 my $title = defined $self->{channel}
591 ? $self->owner->as_string . " " . $self->opponent_string
592 : "Game Window";
593 $self->set_title ("KGS Game $title");
594 $self->{title}->set_text ($title);
595
596 $self->{user}[COLOUR_BLACK] = $self->{black};
597 $self->{user}[COLOUR_WHITE] = $self->{white};
598
599 # show board
600 if ($self->is_inprogress) {
601 if (!$self->{boardbox}->parent) {
602 $self->{boardbox}->add ($self->{board} = new Gtk2::GoBoard size => $self->{size});
603 $self->{left}->add ($self->{boardbox});
604 $self->{board}->signal_connect (button_release => sub {
605 if ($_[1] == 1) {
606 $self->{board_click}->($_[2], $_[3]) if $self->{board_click};
607 }
608 });
609 }
610 if (my $ch = delete $self->{challenge}) {
611 $_->{inlay}->destroy for values %$ch;
612 }
613 $self->update_cursor;
614 }
615
616 $self->{left}->show_all;
617
618 $self->{rules_inlay}->refresh;
619
620}
621
622sub draw_setup {
623 my ($self, $inlay) = @_;
624
625 return unless $self->{joined};
626
627 my $rules = $self->{rules};
628
629 my $text = "";
630
631 $text .= "\nTeacher: <user>" . (util::toxml $self->{teacher}) . "</user>"
632 if $self->{teacher};
633
634 $text .= "\nOwner: <user>" . (util::toxml $self->{owner}->as_string) . "</user>"
635 if $self->{owner}->is_valid;
636
637 if ($self->is_inprogress) {
638 $text .= "\nPlayers: <user>" . (util::toxml $self->{white}->as_string) . "</user>"
639 . " vs. <user>" . (util::toxml $self->{black}->as_string) . "</user>";
640 }
641 $text .= "\nType: " . util::toxml $gametype{$self->type};
642
643 $text .= "\nRuleset: " . $ruleset{$rules->{ruleset}};
644
645 $text .= "\nTime: ";
646
647 if ($rules->{timesys} == TIMESYS_NONE) {
648 $text .= "UNLIMITED";
649 } elsif ($rules->{timesys} == TIMESYS_ABSOLUTE) {
650 $text .= util::format_time $rules->{time};
651 $text .= " ABS";
652 } elsif ($rules->{timesys} == TIMESYS_BYO_YOMI) {
653 $text .= util::format_time $rules->{time};
654 $text .= sprintf " + %s (%d) BY", util::format_time $rules->{interval}, $rules->{count};
655 } elsif ($rules->{timesys} == TIMESYS_CANADIAN) {
656 $text .= util::format_time $rules->{time};
657 $text .= sprintf " + %s/%d CAN", util::format_time $rules->{interval}, $rules->{count};
658 }
659
660 $text .= "\nFlags:";
661 $text .= " private" if $self->is_private;
662 $text .= " started" if $self->is_inprogress;
663 $text .= " adjourned" if $self->is_adjourned;
664 $text .= " scored" if $self->is_scored;
665 $text .= " saved" if $self->is_saved;
666
667 if ($self->is_inprogress) {
668 $text .= "\nHandicap: " . $self->{handicap};
669 $text .= "\nKomi: " . $self->{komi};
670 $text .= "\nSize: " . $self->size_string;
671 }
672
673 if ($self->is_scored) {
674 $text .= "\nResult: " . $self->score_string;
675 }
676
677 $inlay->append_text ("<infoblock>$text</infoblock>");
678
679}
680
681sub event_update_rules {
682 my ($self, $rules) = @_;
683
684 $self->{rules} = $rules;
685
686 if ($self->{user}) {
687 $self->{userpanel}[$_]->configure ($self->{app}, $self->{user}[$_], $rules)
688 for COLOUR_BLACK, COLOUR_WHITE;
689 }
690
691 sound::play 3, "gamestart";
692 $self->{rules_inlay}->refresh;
693}
694 756
695sub event_resign_game { 757sub event_resign_game {
696 my ($self, $player) = @_; 758 my ($self, $player) = @_;
697 759
698 sound::play 3, "resign"; 760 sound::play 3, "resign";
699 $self->{chat}->append_text ("\n<infoblock><header>Resign</header>" 761 $self->{chat}->append_text ("\n<infoblock><header>Resign</header>"
700 . "\n<user>" 762 . "\n<user>"
701 . (util::toxml $self->{user}[$msg->{player}]->as_string) 763 . (util::toxml $self->{user}[$msg->{player}]->as_string)
702 . "</user> resigned.</infoblock>"); 764 . "</user> resigned."
765 . "\n<user>"
766 . (util::toxml $self->{user}[1 - $msg->{player}]->as_string)
767 . "</user> wins the game."
768 . "</infoblock>");
703} 769}
704 770
705sub event_out_of_time { 771sub event_time_win {
706 my ($self, $player) = @_; 772 my ($self, $player) = @_;
707 773
708 sound::play 3, "timewin"; 774 sound::play 3, "timewin";
709 $self->{chat}->append_text ("\n<infoblock><header>Out of Time</header>" 775 $self->{chat}->append_text ("\n<infoblock><header>Out of Time</header>"
710 . "\n<user>" 776 . "\n<user>"
777 . (util::toxml $self->{user}[1 - $msg->{player}]->as_string)
778 . "</user> ran out of time and lost."
779 . "\n<user>"
711 . (util::toxml $self->{user}[$msg->{player}]->as_string) 780 . (util::toxml $self->{user}[$msg->{player}]->as_string)
781 . "</user> wins the game."
782 . "</infoblock>");
783}
784
785sub event_owner_left {
786 my ($self) = @_;
787
788 sound::play 2, "info";
789 $self->{chat}->append_text ("\n<infoblock><header>Owner left</header>"
712 . "</user> ran out of time and lost.</infoblock>"); 790 . "\nThe owner of this game left.</infoblock>");
791}
792
793sub event_teacher_left {
794 my ($self) = @_;
795
796 sound::play 2, "info";
797 $self->{chat}->append_text ("\n<infoblock><header>Teacher left</header>"
798 . "\nThe teacher left the game.</infoblock>");
713} 799}
714 800
715sub event_done { 801sub event_done {
716 my ($self) = @_; 802 my ($self) = @_;
717 803
718 warn sprintf "EVENT DONE @{$self->{done}} %x\n", $self->{doneid};#d#
719
720 if ($self->{done}[1 - $self->{colour}] && !$self->{done}[$self->{colour}]) { 804 if ($self->{done}[1 - $self->{colour}] && !$self->{done}[$self->{colour}]) {
721 sound::play 2, "ring" unless $inlay->{count}; 805 sound::play 2, "info" unless $inlay->{count};
722 $self->{chat}->append_text ("\n<infoblock><header>Press Done</header>" 806 $self->{chat}->append_text ("\n<infoblock><header>Press Done</header>"
723 . "\nYour opponent pressed done. Now it's up to you."); 807 . "\nYour opponent pressed done. Now it's up to you.");
724 } 808 }
725 if ($self->{doneid} & 0x80000000) { 809 if ($self->{doneid} & 0x80000000) {
726 sound::play 2, "warning" unless $inlay->{count}; 810 sound::play 2, "info" unless $inlay->{count};
727 $self->{chat}->append_text ("\n<infoblock><header>Press Done Again</header>" 811 $self->{chat}->append_text ("\n<infoblock><header>Press Done Again</header>"
728 . "\nYour opponent changed the board.."); 812 . "\nThe board has changed.");
729 } 813 }
730 814
731 $self->{button_pass}->sensitive (!$self->{done}[$self->{colour}]); 815 $self->{button_pass}->sensitive (!$self->{done}[$self->{colour}]);
732 816
733 $self->{chat}->set_end; 817 $self->{chat}->set_end;
739 $self->{chat}->append_text ("<infoblock>\n<header>Game Over</header>" 823 $self->{chat}->append_text ("<infoblock>\n<header>Game Over</header>"
740 . "\nWhite Score " . (util::toxml $msg->{whitescore}->as_string) 824 . "\nWhite Score " . (util::toxml $msg->{whitescore}->as_string)
741 . "\nBlack Score " . (util::toxml $msg->{blackscore}->as_string) 825 . "\nBlack Score " . (util::toxml $msg->{blackscore}->as_string)
742 . "</infoblock>" 826 . "</infoblock>"
743 ); 827 );
744}
745
746sub inject_set_gametime {
747 my ($self, $msg) = @_;
748
749 $self->{timers} = [
750 [$msg->{NOW}, $msg->{black_time}, $msg->{black_moves}],
751 [$msg->{NOW}, $msg->{white_time}, $msg->{white_moves}],
752 ];
753
754 $self->update_timers ($self->{timers})
755 if $self->{showmove} == @{$self->{path}};
756} 828}
757 829
758sub inject_req_undo { 830sub inject_req_undo {
759 my ($self, $msg) = @_; 831 my ($self, $msg) = @_;
760 832
788 } 860 }
789 861
790 $self->{chat}->append_text ("\n<header>Game successfully created on server.</header>"); 862 $self->{chat}->append_text ("\n<header>Game successfully created on server.</header>");
791 delete $self->{cid}; 863 delete $self->{cid};
792} 864}
865
866### CHALLENGE HANDLING ######################################################
793 867
794sub draw_challenge { 868sub draw_challenge {
795 my ($self, $id) = @_; 869 my ($self, $id) = @_;
796 870
797 my $info = $self->{challenge}{$id}; 871 my $info = $self->{challenge}{$id};
953 }); 1027 });
954 } 1028 }
955 } 1029 }
956} 1030}
957 1031
958sub draw_users { 1032sub new_game_challenge {
959 my ($self, $inlay) = @_; 1033 my ($self) = @_;
960 1034
961 for (sort keys %{$self->{users}}) { 1035 my $d = $self->{app}{defaults};
962 $inlay->append_text (" <user>" . $self->{users}{$_}->as_string . "</user>"); 1036
1037 $self->{challenge}{""} = {
1038 gametype => $d->{gametype},
1039 flags => 0,
1040 notes => $d->{stones},
1041 rules => {
1042 ruleset => $d->{ruleset},
1043 size => $d->{size},
1044 timesys => $d->{timesys},
1045 time => $d->{time},
1046 interval => $d->{timesys} == TIMESYS_BYO_YOMI ? $d->{byo_time} : $d->{can_time},
1047 count => $d->{timesys} == TIMESYS_BYO_YOMI ? $d->{byo_periods} : $d->{can_stones},
1048 },
1049
1050 inlay => $self->{chat}->new_inlay,
963 } 1051 };
1052 $self->draw_challenge ("");
964} 1053}
965 1054
966sub event_challenge { 1055sub event_challenge {
967 my ($self, $info) = @_; 1056 my ($self, $info) = @_;
968 1057
969 my $as_black = $info->{black}->{name} eq $self->{conn}{name}; 1058 my $as_black = $info->{black}->{name} eq $self->{conn}{name};
970 my $opponent = $as_black ? $info->{white} : $info->{black}; 1059 my $opponent = $as_black ? $info->{white} : $info->{black};
971 1060
972 my $id = $opponent->{name}; 1061 my $id = $opponent->{name};
1062
1063 sound::play 2, "info";
973 1064
974 $self->{challenge}{$id} = $info; 1065 $self->{challenge}{$id} = $info;
975 $self->{challenge}{$id}{inlay} = $self->{chat}->new_switchable_inlay ( 1066 $self->{challenge}{$id}{inlay} = $self->{chat}->new_switchable_inlay (
976 exists $self->{challenge}{""} 1067 exists $self->{challenge}{""}
977 ? "Challenge from $opponent->{name}" 1068 ? "Challenge from " . $opponent->as_string
978 : "Challenge to $opponent->{name}", 1069 : "Challenge to " . $opponent->as_string,
979 sub { 1070 sub {
980 $self->{challenge}{$id}{inlay} = $_[0]; 1071 $self->{challenge}{$id}{inlay} = $_[0];
981 $self->draw_challenge ($id); 1072 $self->draw_challenge ($id);
982 }, 1073 },
983 !exists $self->{challenge}{""} # only open when not offerer 1074 !exists $self->{challenge}{""} # only open when not offerer

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines