ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/bin/pclient
(Generate patch)

Comparing deliantra/Deliantra-Client/bin/pclient (file contents):
Revision 1.220 by root, Wed May 17 00:28:46 2006 UTC vs.
Revision 1.235 by root, Mon May 22 02:23:10 2006 UTC

1#!/opt/bin/perl 1#!/opt/bin/perl
2 2
3use strict; 3use strict;
4use utf8; 4use utf8;
5 5
6# do things only needed for single-binary version (par)
6BEGIN { 7BEGIN {
7 if (%PAR::LibCache) { 8 if (%PAR::LibCache) {
8 @INC = grep ref, @INC; # weed out all paths except pars loader refs 9 @INC = grep ref, @INC; # weed out all paths except pars loader refs
9 10
10 while (my ($filename, $zip) = each %PAR::LibCache) { 11 while (my ($filename, $zip) = each %PAR::LibCache) {
13 $zip->extractMember ($_, "$ENV{PAR_TEMP}/$1") 14 $zip->extractMember ($_, "$ENV{PAR_TEMP}/$1")
14 unless -e "$ENV{PAR_TEMP}/$1"; 15 unless -e "$ENV{PAR_TEMP}/$1";
15 } 16 }
16 } 17 }
17 18
19 # TODO: pango-rc file, anybody?
20
18 unshift @INC, $ENV{PAR_TEMP}; 21 unshift @INC, $ENV{PAR_TEMP};
19
20 if ($^O eq "MSWin32") {
21 $ENV{GTK_RC_FILES} = "$ENV{PAR_TEMP}/share/themes/MS-Windows/gtk-2.0/gtkrc";
22 }
23 } 22 }
24} 23}
25 24
26# need to do it again because that pile of garbage called PAR nukes it before main 25# need to do it again because that pile of garbage called PAR nukes it before main
27unshift @INC, $ENV{PAR_TEMP}; 26unshift @INC, $ENV{PAR_TEMP}
27 if %PAR::LibCache;
28 28
29use Time::HiRes 'time'; 29use Time::HiRes 'time';
30use Pod::POM;
30use Event; 31use Event;
31 32
32use Crossfire; 33use Crossfire;
33use Crossfire::Protocol; 34use Crossfire::Protocol;
34 35
100our $DEBUG_STATUS; 101our $DEBUG_STATUS;
101 102
102our $INVWIN; 103our $INVWIN;
103our $INV; 104our $INV;
104our $INVR; 105our $INVR;
106our $INVR_LBL;
105our $OPENCONT; 107our $OPENCONT;
106 108
107sub status { 109sub status {
108 $STATUSBOX->add ($_[0], pri => -10, group => "status", timeout => 20, fg => [1, 1, 0, 1]); 110 $STATUSBOX->add (CFClient::UI::Label::escape $_[0], pri => -10, group => "status", timeout => 20, fg => [1, 1, 0, 1]);
109} 111}
110 112
111sub debug { 113sub debug {
112 $DEBUG_STATUS->set_text ($_[0]); 114 $DEBUG_STATUS->set_text ($_[0]);
113 my ($w, $h) = $DEBUG_STATUS->size_request; 115 my ($w, $h) = $DEBUG_STATUS->size_request;
134 maph => $mapsize, 136 maph => $mapsize,
135 ; 137 ;
136 }; 138 };
137 139
138 if ($CONN) { 140 if ($CONN) {
141 CFClient::lowdelay fileno $CONN->{fh};
142
139 $LOGIN_BUTTON->set_text ("Logout"); 143 $LOGIN_BUTTON->set_text ("Logout");
140
141 status "login successful"; 144 status "login successful";
142 145
143 CFClient::lowdelay fileno $CONN->{fh}; 146 $BUTTONBAR->{children}[1]->emit ("activate")
147 if $BUTTONBAR->{children}[1]->{state};
148
144 } else { 149 } else {
145 status "unable to connect"; 150 status "unable to connect";
146 stop_game(); 151 stop_game();
147 } 152 }
148} 153}
152 157
153 status "connection closed"; 158 status "connection closed";
154 $LOGIN_BUTTON->set_text ("Login"); 159 $LOGIN_BUTTON->set_text ("Login");
155 $CONN->destroy; 160 $CONN->destroy;
156 $CONN = 0; # false, does not autovivify 161 $CONN = 0; # false, does not autovivify
162
163 $BUTTONBAR->{children}[1]->emit ("activate")
164 unless $BUTTONBAR->{children}[1]->{state};
157 165
158 undef $MAPCACHE; 166 undef $MAPCACHE;
159 undef $MAP; 167 undef $MAP;
160} 168}
161 169
458 466
459 my $row = 0; 467 my $row = 0;
460 my $col = 0; 468 my $col = 0;
461 469
462 my %resist_names = ( 470 my %resist_names = (
463 slow => "Slow (slows you down when you are hit by the spell. Monsters will have an opportunity to come near you faster and hit you more often.)", 471 slow => "<b>Slow</b> (slows you down when you are hit by the spell. Monsters will have an opportunity to come near you faster and hit you more often.)",
464 holyw => "Holy Word (resistance you against getting the fear when someone whose god doesn't like you spells the holy word on you.)", 472 holyw => "<b>Holy Word</b> (resistance you against getting the fear when someone whose god doesn't like you spells the holy word on you.)",
465 conf => "Confusion (If you are hit by confusion you will move into random directions, and likely into monsters.)", 473 conf => "<b>Confusion</b> (If you are hit by confusion you will move into random directions, and likely into monsters.)",
466 fire => "Fire (just your resistance to fire spells like burning hands, dragonbreath, meteor swarm fire, ...)", 474 fire => "<b>Fire</b> (just your resistance to fire spells like burning hands, dragonbreath, meteor swarm fire, ...)",
467 depl => "Depletion (some monsters and other effects can cause stats depletion)", 475 depl => "<b>Depletion</b> (some monsters and other effects can cause stats depletion)",
468 magic => "Magic (resistance to magic spells like magic missile or similar)", 476 magic => "<b>Magic</b> (resistance to magic spells like magic missile or similar)",
469 drain => "Draining (some monsters (e.g. vampires) and other effects can steal experience)", 477 drain => "<b>Draining</b> (some monsters (e.g. vampires) and other effects can steal experience)",
470 acid => "Acid (resistance to acid, acid hurts pretty much and also corrodes your weapons)", 478 acid => "<b>Acid</b> (resistance to acid, acid hurts pretty much and also corrodes your weapons)",
471 pois => "Poison (resistance to getting poisoned)", 479 pois => "<b>Poison</b> (resistance to getting poisoned)",
472 para => "Paralysation (this resistance affects the chance you get paralysed)", 480 para => "<b>Paralysation</b> (this resistance affects the chance you get paralysed)",
473 deat => "Death (resistance against death spells)", 481 deat => "<b>Death</b> (resistance against death spells)",
474 phys => "Physical (this is the resistance against physical attacks, like when a monster hit you in melee combat)", 482 phys => "<b>Physical</b> (this is the resistance against physical attacks, like when a monster hit you in melee combat)",
475 blind => "Blind (blind resistance affects the chance of a successful blinding attack)", 483 blind => "<b>Blind</b> (blind resistance affects the chance of a successful blinding attack)",
476 fear => "Fear (this attack will drive you away from monsters who cast this and hit you successfully, being resistant to this helps a lot when fighting those monsters)", 484 fear => "<b>Fear</b> (this attack will drive you away from monsters who cast this and hit you successfully, being resistant to this helps a lot when fighting those monsters)",
477 tund => "Turn undead", 485 tund => "<b>Turn undead</b> (affects your resistancy to various forms of 'turn undead' spells. Only relevant when you are, in fact, undead...",
478 elec => "Electricity (resistance againt electricity, spells like large lightning, small lightning, ...)", 486 elec => "<b>Electricity</b> (resistance against electricity, spells like large lightning, small lightning, ...)",
479 cold => "Cold (this is your resistance against cold spells like icestorm, snowstorm, ...)", 487 cold => "<b>Cold</b> (this is your resistance against cold spells like icestorm, snowstorm, ...)",
480 ghit => "Ghost hit (special attack used by ghosts and ghost-like beings)", 488 ghit => "<b>Ghost hit</b> (special attack used by ghosts and ghost-like beings)",
481 ); 489 );
482 for (qw/slow holyw conf fire depl magic 490 for (qw/slow holyw conf fire depl magic
483 drain acid pois para deat phys 491 drain acid pois para deat phys
484 blind fear tund elec cold ghit/) 492 blind fear tund elec cold ghit/)
485 { 493 {
665 $HOST->set_text ($CFG->{host} = $host); 673 $HOST->set_text ($CFG->{host} = $host);
666 }), 674 }),
667 (new CFClient::UI::Empty expand => 1), 675 (new CFClient::UI::Empty expand => 1),
668 ]); 676 ]);
669 677
670 $table->add ($_ + 1, $y, new CFClient::UI::Label align => $align[$_], text => $m->[$_], fontsize => 0.8) 678 $table->add ($_ + 1, $y, new CFClient::UI::Label
679 ellipsise => 0, align => $align[$_], text => $m->[$_], fontsize => 0.8)
671 for 0 .. $#$m; 680 for 0 .. $#$m;
672 } 681 }
673 } 682 }
674 }); 683 });
675} 684}
741 750
742 $CFG->{mapsize} = $self->{range}[0] = $value = int $value; 751 $CFG->{mapsize} = $self->{range}[0] = $value = int $value;
743 }, 752 },
744 ); 753 );
745 754
755 $table->add (0, 8, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Count");
756 $table->add (1, 8, new CFClient::UI::Entry
757 text => $CFG->{output_count},
758 tooltip => "Should be set to 1 unless you know what you are doing",
759 connect_changed => sub { $CFG->{output_count} = $_[1] },
760 );
761
762 $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Sync");
763 $table->add (1, 9, new CFClient::UI::Entry
764 text => $CFG->{output_sync},
765 tooltip => "Should be set to 1 unless you know what you are doing",
766 connect_changed => sub { $CFG->{output_sync} = $_[1] },
767 );
768
746 $table->add (1, 8, $LOGIN_BUTTON = new CFClient::UI::Button 769 $table->add (1, 10, $LOGIN_BUTTON = new CFClient::UI::Button
747 expand => 1, 770 expand => 1,
748 align => 0, 771 align => 0,
749 text => "Login", 772 text => "Login",
750 connect_activate => sub { 773 connect_activate => sub {
751 $CONN ? stop_game 774 $CONN ? stop_game
763 bg => [0, 0, 0, 0.5], 786 bg => [0, 0, 0, 0.5],
764 user_w => int $::WIDTH / 3, 787 user_w => int $::WIDTH / 3,
765 user_h => int $::HEIGHT / 5, 788 user_h => int $::HEIGHT / 5,
766 child => (my $vbox = new CFClient::UI::VBox); 789 child => (my $vbox = new CFClient::UI::VBox);
767 790
768 $vbox->add ($LOGVIEW = new CFClient::UI::TextView 791 $vbox->add ($LOGVIEW);
769 expand => 1,
770 font => $FONT_FIXED,
771 fontsize => $::CFG->{log_fontsize},
772 );
773 792
774 $vbox->add (my $input = new CFClient::UI::Entry 793 $vbox->add (my $input = new CFClient::UI::Entry
775 connect_focus_in => sub { 794 connect_focus_in => sub {
776 my ($input, $prev_focus) = @_; 795 my ($input, $prev_focus) = @_;
777 796
812 831
813sub make_inventory_window { 832sub make_inventory_window {
814 my $invwin = new CFClient::UI::FancyFrame 833 my $invwin = new CFClient::UI::FancyFrame
815 user_w => $WIDTH * (4/5), user_h => $HEIGHT * (4/5), title => "Inventory"; 834 user_w => $WIDTH * (4/5), user_h => $HEIGHT * (4/5), title => "Inventory";
816 835
817 $invwin->add (my $hb = new CFClient::UI::HBox); 836 $invwin->add (my $hb = new CFClient::UI::HBox expand => 1);
837
838 $hb->add (my $vb1 = new CFClient::UI::VBox expand => 1);
839 $vb1->add (my $lbl = new CFClient::UI::Label);
840 $lbl->set_text ("Player");
818 $hb->add ($INV = new CFClient::UI::Inventory expand => 1); 841 $vb1->add ($INV = new CFClient::UI::Inventory expand => 1);
842
843 $hb->add (my $vb2 = new CFClient::UI::VBox expand => 1);
844 $vb2->add ($INVR_LBL = new CFClient::UI::Label);
845 $INVR_LBL->set_text ("Floor");
819 $hb->add ($INVR = new CFClient::UI::Inventory expand => 1); 846 $vb2->add ($INVR = new CFClient::UI::Inventory expand => 1);
820 847
821 $invwin 848 $invwin
822} 849}
823 850
824sub sdl_init { 851sub sdl_init {
834 ($WIDTH, $HEIGHT) = @{ $SDL_MODES[$CFG->{sdl_mode}] }; 861 ($WIDTH, $HEIGHT) = @{ $SDL_MODES[$CFG->{sdl_mode}] };
835 $FULLSCREEN = $CFG->{fullscreen}; 862 $FULLSCREEN = $CFG->{fullscreen};
836 $FAST = $CFG->{fast}; 863 $FAST = $CFG->{fast};
837 864
838 CFClient::SDL_SetVideoMode $WIDTH, $HEIGHT, $FULLSCREEN 865 CFClient::SDL_SetVideoMode $WIDTH, $HEIGHT, $FULLSCREEN
839 or die "SDL_SetVideoMode failed!\n"; 866 or die "SDL_SetVideoMode failed: " . (CFClient::SDL_GetError) . "\n";
840 867
841 $SDL_ACTIVE = 1; 868 $SDL_ACTIVE = 1;
842 $LAST_REFRESH = time - 0.01; 869 $LAST_REFRESH = time - 0.01;
843 870
844 CFClient::gl_init; 871 CFClient::gl_init;
884 } 911 }
885 }); 912 });
886 $MAPWIDGET->show; 913 $MAPWIDGET->show;
887 $MAPWIDGET->focus_in; 914 $MAPWIDGET->focus_in;
888 915
916 $LOGVIEW = new CFClient::UI::TextView
917 expand => 1,
918 font => $FONT_FIXED,
919 fontsize => $::CFG->{log_fontsize},
920 ;
921
889 $BUTTONBAR = new CFClient::UI::HBox; 922 $BUTTONBAR = new CFClient::UI::HBox;
890 923
891 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Client Setup", other => client_setup); 924 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Client Setup", other => client_setup);
892 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Server Setup", other => server_setup); 925 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Server Setup", other => server_setup);
893 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Message Window", other => message_window); 926 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Message Window", other => message_window);
924my $bgmusic;#TODO#hack#d# 957my $bgmusic;#TODO#hack#d#
925 958
926sub audio_channel_finished { 959sub audio_channel_finished {
927 my ($channel) = @_; 960 my ($channel) = @_;
928 961
929 warn "channel $channel finished\n";#d# 962 #warn "channel $channel finished\n";#d#
930} 963}
931 964
932sub audio_music_finished { 965sub audio_music_finished {
933 return unless $CFG->{bgm_enable}; 966 return unless $CFG->{bgm_enable};
934 967
978my %animate_object; 1011my %animate_object;
979my $animate_timer; 1012my $animate_timer;
980 1013
981my $fps = 9; 1014my $fps = 9;
982 1015
1016my %demo;#d#
1017
983sub force_refresh { 1018sub force_refresh {
984 $fps = $fps * 0.95 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.05; 1019 $fps = $fps * 0.95 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.05;
985 debug sprintf "%3.2f", $fps; 1020 debug sprintf "%3.2f", $fps;
986 1021
987 $CFClient::UI::ROOT->draw; 1022 $CFClient::UI::ROOT->draw;
988 CFClient::SDL_GL_SwapBuffers;
989 1023
990 $WANT_REFRESH = 0; 1024 $WANT_REFRESH = 0;
991 $CAN_REFRESH = 0; 1025 $CAN_REFRESH = 0;
992 $LAST_REFRESH = $NOW; 1026 $LAST_REFRESH = $NOW;
1027
10280 && do {
1029 # some weird model-drawing code, just a joke right now
1030 use CFClient::OpenGL;
1031
1032 $demo{t}{eye_auv} ||= new_from_file CFClient::Texture "eye2.png" or die;
1033 $demo{t}{body_auv} ||= new_from_file CFClient::Texture "body_auv3.png" or die;
1034 $demo{r} ||= do {
1035 my $mod = Compress::LZF::sthaw do { local $/; open my $fh, "<:raw:perlio", "dread.lz3"; <$fh> };
1036 $mod->{v} = pack "f*", @{$mod->{v}};
1037 $_ = [scalar @$_, pack "S!*", @$_]
1038 for values %{$mod->{g}};
1039 $mod
1040 };
1041
1042 my $r = $demo{r} or die;
1043
1044 glDepthMask 1;
1045 glClear GL_DEPTH_BUFFER_BIT;
1046 glEnable GL_TEXTURE_2D;
1047 glEnable GL_DEPTH_TEST;
1048 glEnable GL_CULL_FACE;
1049 glShadeModel $::FAST ? GL_FLAT : GL_SMOOTH;
1050
1051 glMatrixMode GL_PROJECTION;
1052 glLoadIdentity;
1053 glFrustum -1 * ($::WIDTH / $::HEIGHT), 1 * ($::WIDTH / $::HEIGHT), 1, -1, 1, 10000;
1054 #glOrtho 0, $::WIDTH, 0, $::HEIGHT, -10000, 10000;
1055 glMatrixMode GL_MODELVIEW;
1056 glLoadIdentity;
1057
1058 glPushMatrix;
1059 glTranslate 0, 0, -800;
1060 glScale 1, -1, 1;
1061 glRotate $NOW * 1000 % 36000 / 5, 0, 1, 0;
1062 glRotate $NOW * 1000 % 36000 / 6, 1, 0, 0;
1063 glRotate $NOW * 1000 % 36000 / 7, 0, 0, 1;
1064 glScale 50, 50, 50;
1065
1066 glInterleavedArrays GL_T2F_N3F_V3F, 0, $r->{v};
1067 while (my ($k, $v) = each %{$r->{g}}) {
1068 glBindTexture GL_TEXTURE_2D, ($demo{t}{$k}{name} or die);
1069 glDrawElements GL_TRIANGLES, $v->[0], GL_UNSIGNED_SHORT, $v->[1];
1070 }
1071
1072 glPopMatrix;
1073
1074 glShadeModel GL_FLAT;
1075 glDisable GL_DEPTH_TEST;
1076 glDisable GL_TEXTURE_2D;
1077 glDepthMask 0;
1078
1079 $WANT_REFRESH++;
1080};
1081
1082 CFClient::SDL_GL_SwapBuffers;
993} 1083}
994 1084
995my $refresh_watcher = Event->timer (after => 0, hard => 1, interval => 1 / $MAX_FPS, cb => sub { 1085my $refresh_watcher = Event->timer (after => 0, hard => 1, interval => 1 / $MAX_FPS, cb => sub {
996 $NOW = time; 1086 $NOW = time;
997 1087
1020 delete $animate_object{$widget}; 1110 delete $animate_object{$widget};
1021} 1111}
1022 1112
1023@conn::ISA = Crossfire::Protocol::; 1113@conn::ISA = Crossfire::Protocol::;
1024 1114
1115sub conn::new {
1116 my $class = shift;
1117
1118 my $self = $class->Crossfire::Protocol::new (@_);
1119
1120 $MAPWIDGET->clr_commands;
1121
1122 my $parser = new Pod::POM;
1123 my $pod = $parser->parse_file (CFClient::find_rcfile "pod/command_help.pod");
1124
1125 for my $head2 ($pod->head2) {
1126 $head2->title =~ /^(\S+) (?:\s+ \( ([^\)]*) \) )?/x
1127 or next;
1128
1129 my $cmd = $1;
1130 my @args = split /\|/, $2;
1131 @args = (".*") unless @args;
1132
1133 my $text = CFClient::pod_to_pango $head2->content;
1134
1135 for my $arg (@args) {
1136 $arg = $arg eq ".*" ? "" : " $arg";
1137
1138 $MAPWIDGET->add_command ("$cmd$arg", $text);
1139 }
1140 }
1141
1142 $self
1143}
1144
1025sub conn::stats_update { 1145sub conn::stats_update {
1026 my ($self, $stats) = @_; 1146 my ($self, $stats) = @_;
1147
1148 if (my $exp = $stats->{Crossfire::Protocol::CS_STAT_EXP64}) {
1149 my $diff = $exp - $self->{prev_exp};
1150 $STATUSBOX->add ("$diff experience gained", group => "experience $diff", fg => [0.5, 1, 0.5, 0.8], timeout => 5)
1151 if exists $self->{prev_exp} && $diff;
1152 $self->{prev_exp} = $exp;
1153 }
1027 1154
1028 update_stats_window ($stats); 1155 update_stats_window ($stats);
1029} 1156}
1030 1157
1031sub conn::user_send { 1158sub conn::user_send {
1086 $self->set_texture ($id => $data); 1213 $self->set_texture ($id => $data);
1087 } 1214 }
1088 } 1215 }
1089} 1216}
1090 1217
1218# hardcode /world/world_xxx_xxx map names, the savings are enourmous,
1219# (server resource,s latency, bandwidth), so this hack is warranted.
1220# the right fix is to make real tiled maps with an overview file
1221sub conn::send_mapinfo {
1222 my ($self, $data, $cb) = @_;
1223
1224 if ($self->{map_info}[0] =~ m%^/world/world_(\d\d\d)_(\d\d\d)$%) {
1225 my ($wx, $wy) = ($1, $2);
1226
1227 if ($data =~ /^spatial ([1-4]+)$/) {
1228 my @dx = (0, 0, 1, 0, -1);
1229 my @dy = (0, -1, 0, 1, 0);
1230 my ($dx, $dy);
1231
1232 for (split //, $1) {
1233 $dx += $dx[$_];
1234 $dy += $dy[$_];
1235 }
1236
1237 $cb->(spatial => 15,
1238 $self->{map_info}[1] - $MAP->ox + $dx * 50,
1239 $self->{map_info}[2] - $MAP->oy + $dy * 50,
1240 50, 50,
1241 sprintf "/world/world_%03d_%03d", $wx + $dx, $wy + $dy
1242 );
1243
1244 return;
1245 }
1246 }
1247
1248 $self->SUPER::send_mapinfo ($data, $cb);
1249}
1250
1091# this method does a "flood fill" into every tile direction 1251# this method does a "flood fill" into every tile direction
1092# it assumes that tiles are arranged in a rectangular grid, 1252# it assumes that tiles are arranged in a rectangular grid,
1093# i.e. a map is the same as the left of the right map etc. 1253# i.e. a map is the same as the left of the right map etc.
1094# failure to comply are harmless and result in display errors 1254# failure to comply are harmless and result in display errors
1095# at worst. 1255# at worst.
1096sub conn::flood_fill { 1256sub conn::flood_fill {
1097 my ($self, $gx, $gy, $path, $hash, $flags) = @_; 1257 my ($self, $block, $gx, $gy, $path, $hash, $flags) = @_;
1098 1258
1099 # the server does not allow map paths > 6 1259 # the server does not allow map paths > 6
1100 return if 7 <= length $path; 1260 return if 7 <= length $path;
1101 1261
1102 my ($x0, $y0, $x1, $y1) = @{$self->{neigh_rect}}; 1262 my ($x0, $y0, $x1, $y1) = @{$self->{neigh_rect}};
1103 1263
1104 for ( 1264 for (
1105 [1, 0, -1], 1265 [1, 3, 0, -1],
1106 [2, 1, 0], 1266 [2, 4, 1, 0],
1107 [3, 0, 1], 1267 [3, 1, 0, 1],
1108 [4, -1, 0], 1268 [4, 2, -1, 0],
1109 ) { 1269 ) {
1110 my ($tile, $dx, $dy) = @$_; 1270 my ($tile, $tile2, $dx, $dy) = @$_;
1271
1272 next if $block & (1 << $tile);
1273 my $block = $block | (1 << $tile2);
1111 1274
1112 my $gx = $gx + $dx; 1275 my $gx = $gx + $dx;
1113 my $gy = $gy + $dy; 1276 my $gy = $gy + $dy;
1114 1277
1115 next unless $flags & (1 << ($tile - 1)); 1278 next unless $flags & (1 << ($tile - 1));
1117 1280
1118 my $neigh = $self->{neigh_map}{$hash} ||= []; 1281 my $neigh = $self->{neigh_map}{$hash} ||= [];
1119 if (my $info = $neigh->[$tile]) { 1282 if (my $info = $neigh->[$tile]) {
1120 my ($flags, $x, $y, $w, $h, $hash) = @$info; 1283 my ($flags, $x, $y, $w, $h, $hash) = @$info;
1121 1284
1122 $self->flood_fill ($gx, $gy, "$path$tile", $hash, $flags) 1285 $self->flood_fill ($block, $gx, $gy, "$path$tile", $hash, $flags)
1123 if $x >= $x0 && $x + $w < $x1 && $y >= $y0 && $y + $h < $y1; 1286 if $x >= $x0 && $x + $w < $x1 && $y >= $y0 && $y + $h < $y1;
1124 1287
1125 } else { 1288 } else {
1126 $self->send_mapinfo ("spatial $path$tile", sub { 1289 $self->send_mapinfo ("spatial $path$tile", sub {
1127 my ($mode, $flags, $x, $y, $w, $h, $hash) = @_; 1290 my ($mode, $flags, $x, $y, $w, $h, $hash) = @_;
1128 1291
1129 return if $mode ne "spatial"; 1292 return if $mode ne "spatial";
1130 1293
1131 $x += $MAP->ox; 1294 $x += $MAP->ox;
1132 $y += $MAP->oy; 1295 $y += $MAP->oy;
1133 1296
1134 $self->load_map ($hash, $x, $y) 1297 $self->load_map ($hash, $x, $y)
1135 unless $self->{neigh_map}{$hash}[5]++;#d# 1298 unless $self->{neigh_map}{$hash}[5]++;#d#
1136 1299
1137 $neigh->[$tile] = [$flags, $x, $y, $w, $h, $hash]; 1300 $neigh->[$tile] = [$flags, $x, $y, $w, $h, $hash];
1138 1301
1139 $self->flood_fill ($gx, $gy, "$path$tile", $hash, $flags) 1302 $self->flood_fill ($block, $gx, $gy, "$path$tile", $hash, $flags)
1140 if $x >= $x0 && $x + $w < $x1 && $y >= $y0 && $y + $h < $y1; 1303 if $x >= $x0 && $x + $w < $x1 && $y >= $y0 && $y + $h < $y1;
1141 }); 1304 });
1142 } 1305 }
1143 } 1306 }
1144} 1307}
1157 $ox - $mapmapw * 0.5, $oy - $mapmapw * 0.5, 1320 $ox - $mapmapw * 0.5, $oy - $mapmapw * 0.5,
1158 $ox + $mapmapw * 0.5 + $w, $oy + $mapmapw * 0.5 + $h, 1321 $ox + $mapmapw * 0.5 + $w, $oy + $mapmapw * 0.5 + $h,
1159 ]; 1322 ];
1160 1323
1161 delete $self->{neigh_grid}; 1324 delete $self->{neigh_grid};
1162 $self->flood_fill (0, 0, "", $hash, $flags);
1163 1325
1164 $x += $ox; 1326 $x += $ox;
1165 $y += $oy; 1327 $y += $oy;
1166 1328
1167 $self->{map_info} = [$hash, $x, $y, $w, $h]; 1329 $self->{map_info} = [$hash, $x, $y, $w, $h];
1168 1330
1169 my $map = $self->{map_info}[0];
1170 $map =~ s/^.*?\/([^\/]+)$/\1/; 1331 (my $map = $hash) =~ s/^.*?\/([^\/]+)$/\1/;
1171 $STATWIDS->{map}->set_text ("Map: " . $map); 1332 $STATWIDS->{map}->set_text ("Map: " . $map);
1172 1333
1173 $self->load_map ($hash, $x, $y); 1334 $self->load_map ($hash, $x, $y);
1335 $self->flood_fill (0, 0, 0, "", $hash, $flags);
1174} 1336}
1175 1337
1176sub conn::face_find { 1338sub conn::face_find {
1177 my ($self, $facenum, $face) = @_; 1339 my ($self, $facenum, $face) = @_;
1178 1340
1356sub conn::spell_add { 1518sub conn::spell_add {
1357 my ($self, $spell) = @_; 1519 my ($self, $spell) = @_;
1358 1520
1359 # TODO 1521 # TODO
1360 # create a widget dynamically, using spell face (CF::Protocol downloads them) 1522 # create a widget dynamically, using spell face (CF::Protocol downloads them)
1361 $MAPWIDGET->add_command ("invoke $spell->{name}", $spell->{message}); 1523 $MAPWIDGET->add_command ("invoke $spell->{name}", CFClient::UI::Label::escape $spell->{message});
1362 $MAPWIDGET->add_command ("cast $spell->{name}", $spell->{message}); 1524 $MAPWIDGET->add_command ("cast $spell->{name}", CFClient::UI::Label::escape $spell->{message});
1363} 1525}
1364 1526
1365sub conn::spell_delete { 1527sub conn::spell_delete {
1366 my ($self, $spell) = @_; 1528 my ($self, $spell) = @_;
1367} 1529}
1368 1530
1369sub conn::addme_success { 1531sub conn::addme_success {
1370 my ($self) = @_; 1532 my ($self) = @_;
1371 1533
1372 $MAPWIDGET->clr_commands; 1534 $self->send ("command output-sync $CFG->{output_sync}");
1535 $self->send ("command output-count $CFG->{output_count}");
1536
1537 my $parser = new Pod::POM;
1538 my $pod = $parser->parse_file (CFClient::find_rcfile "pod/skill_help.pod");
1539
1540 my %skill_tooltip;
1541
1542 for my $head2 ($pod->head2) {
1543 $skill_tooltip{$head2->title} = CFClient::pod_to_pango $head2->content;
1544 }
1373 1545
1374 for my $skill (values %{$self->{skill_info}}) { 1546 for my $skill (values %{$self->{skill_info}}) {
1375 $MAPWIDGET->add_command ("ready_\\skill $skill", "Ready the skill '$skill'"); 1547 $MAPWIDGET->add_command ("ready_skill $skill",
1376 $MAPWIDGET->add_command ("use_\\skill $skill", "Immediately use the skill '$skill'"); 1548 (CFClient::UI::Label::escape "Ready the skill '$skill'\n\n")
1549 . $skill_tooltip{$skill});
1550 $MAPWIDGET->add_command ("use_skill $skill",
1551 (CFClient::UI::Label::escape "Immediately use the skill '$skill'\n\n")
1552 . $skill_tooltip{$skill});
1377 } 1553 }
1378
1379 $MAPWIDGET->add_command ("pet\\mode defend", "Tell pets to stay close to you and defend you");
1380 $MAPWIDGET->add_command ("pet\\mode arena", "Same as petmode sad, but also attack other players");
1381 $MAPWIDGET->add_command ("pet\\mode sad", "Search &amp; Destroy - tell pets to roam about and attack enemies");
1382 $MAPWIDGET->add_command ("kill\\pets", "Kill your pets");
1383 $MAPWIDGET->add_command ("chat", "chat TEXT\nChat with all other players");
1384 $MAPWIDGET->add_command ("shout", "shout TEXT\nShout loudly, used for emergencies");
1385 $MAPWIDGET->add_command ("tell", "tell USERNAME TEXT\nPrivately tell a specific player");
1386
1387 # TODO: add documentation on these
1388 for (qw(
1389 afk
1390 apply
1391 applymode
1392 body
1393 bowmode
1394 brace
1395 build
1396 disarm
1397 dm
1398 dmhide
1399 drop
1400 dropall
1401 examine
1402 get
1403 gsay
1404 help
1405 hiscore
1406 inventory
1407 invoke
1408 killpets
1409 listen
1410 logs
1411 mapinfo
1412 maps
1413 mark
1414 motd
1415 output-count
1416 output-sync
1417 party
1418 peaceful
1419 petmode
1420 pickup
1421 players
1422 prepare
1423 quests
1424 rename
1425 resistances
1426 rotateshoottype
1427 save
1428 say
1429 search
1430 search-items
1431 showpets
1432 skills
1433 sound
1434 take
1435 throw
1436 time
1437 title
1438 usekeys
1439 version
1440 weather
1441 whereabouts
1442 whereami
1443 who
1444 wimpy
1445 )) {
1446 $MAPWIDGET->add_command ($_, "$_: no help available (yet)");
1447 }
1448
1449 #TODO: add " and ' "aliases" etc.
1450} 1554}
1451 1555
1452sub conn::eof { 1556sub conn::eof {
1453 $MAPWIDGET->clr_commands; 1557 $MAPWIDGET->clr_commands;
1454 1558
1477} 1581}
1478 1582
1479sub conn::container_add { 1583sub conn::container_add {
1480 my ($self, $tag, $items) = @_; 1584 my ($self, $tag, $items) = @_;
1481 1585
1586 #d# print "container_add: container $tag ($self->{player}{tag})\n";
1587
1482 if ($tag == 0) { 1588 if ($tag == 0) {
1483 update_floorbox; 1589 update_floorbox;
1590 $OPENCONT = 0;
1591 $INVR_LBL->set_text ("Floor");
1484 $INVR->set_items ($self->{container}{0}); 1592 $INVR->set_items ($self->{container}{0});
1485 $OPENCONT = 0;
1486 } elsif ($tag == $self->{player}{tag}) { 1593 } elsif ($tag == $self->{player}{tag}) {
1594 $INVR_LBL->set_text ("Player");
1487 $INV->set_items ($self->{container}{$self->{player}{tag}}) 1595 $INV->set_items ($self->{container}{$self->{player}{tag}})
1488 } else { 1596 } else {
1489 $OPENCONT = $tag; 1597 $OPENCONT = $tag;
1598 $INVR_LBL->set_text (CFClient::UI::InventoryItem::_item_to_desc ($self->{item}->{$OPENCONT}));
1490 $INVR->set_items ($self->{container}{$tag}); 1599 $INVR->set_items ($self->{container}{$tag});
1491 } 1600 }
1492 1601
1493 # $self-<{player}{tag} => player inv 1602 # $self-<{player}{tag} => player inv
1494 #use PApp::Util; warn PApp::Util::dumpval $self->{container}{$self->{player}{tag}}; 1603 #use PApp::Util; warn PApp::Util::dumpval $self->{container}{$self->{player}{tag}};
1495} 1604}
1496 1605
1497sub conn::container_clear { 1606sub conn::container_clear {
1498 my ($self, $tag) = @_; 1607 my ($self, $tag) = @_;
1499 1608
1609 #d# print "container_clear: container $tag ($self->{player}{tag})\n";
1610
1500 if ($tag == 0) { 1611 if ($tag == 0) {
1501 update_floorbox; 1612 update_floorbox;
1613 $OPENCONT = 0;
1614 $INVR_LBL->set_text ("Floor");
1502 $INVR->set_items ($self->{container}{0}); 1615 $INVR->set_items ($self->{container}{0});
1503 $OPENCONT = 0;
1504 } elsif ($tag == $self->{player}{tag}) { 1616 } elsif ($tag == $self->{player}{tag}) {
1617 $INVR_LBL->set_text ("Player");
1505 $INV->set_items ($self->{container}{$tag}) 1618 $INV->set_items ($self->{container}{$tag})
1506 } else { 1619 } else {
1620 $OPENCONT = $tag;
1621 $INVR_LBL->set_text (CFClient::UI::InventoryItem::_item_to_desc ($self->{item}->{$OPENCONT}));
1507 $INVR->set_items ($self->{container}{$tag}); 1622 $INVR->set_items ($self->{container}{$tag});
1508 $OPENCONT = $tag;
1509 } 1623 }
1510 1624
1511# use PApp::Util; warn PApp::Util::dumpval $self->{container}{0}; 1625# use PApp::Util; warn PApp::Util::dumpval $self->{container}{0};
1512} 1626}
1513 1627
1514sub conn::item_delete { 1628sub conn::item_delete {
1515 my ($self, @items) = @_; 1629 my ($self, @items) = @_;
1516 1630
1517 for (@items) { 1631 for (@items) {
1632 #d# print "item_delete: $_->{tag} from $_->{container} ($self->{player}{tag})\n";
1633
1518 if ($_->{container} == 0) { 1634 if ($_->{container} == 0) {
1519 update_floorbox; 1635 update_floorbox;
1636 $OPENCONT = 0;
1637 $INVR_LBL->set_text ("Floor");
1520 $INVR->set_items ($self->{container}{0}); 1638 $INVR->set_items ($self->{container}{0});
1521 } elsif ($_->{container} == $self->{player}{tag}) { 1639 } elsif ($_->{container} == $self->{player}{tag}) {
1640 $INVR_LBL->set_text ("Player");
1522 $INV->set_items ($self->{container}{$self->{player}{tag}}) 1641 $INV->set_items ($self->{container}{$self->{player}{tag}})
1523 } else { 1642 } else {
1643 $OPENCONT = $_->{container};
1644 $INVR_LBL->set_text (CFClient::UI::InventoryItem::_item_to_desc ($self->{item}->{$OPENCONT}));
1524 $INVR->set_items ($self->{container}{0}); 1645 $INVR->set_items ($self->{container}{$_->{container}});
1525 } 1646 }
1526 } 1647 }
1527} 1648}
1528 1649
1529sub conn::item_update { 1650sub conn::item_update {
1530 my ($self, $item) = @_; 1651 my ($self, $item) = @_;
1531 1652
1532 if ($item->{container} == 0) { 1653 #d# print "item_update: $item->{tag} in $item->{container} ($self->{player}{tag}) ($OPENCONT)\n";
1533 update_floorbox; 1654
1655 if ($item->{tag} == $OPENCONT && not ($item->{flags} & Crossfire::Protocol::F_OPEN)) {
1656 $OPENCONT = 0;
1657 $INVR_LBL->set_text ("Floor");
1534 $INVR->set_items ($self->{container}{0}); 1658 $INVR->set_items ($self->{container}{0});
1659
1660 $item->{widget}->update_item
1661 if $item->{widget};
1662 } else {
1663 if ($item->{container} == 0) {
1664 update_floorbox;
1665 $OPENCONT = 0;
1666 $INVR_LBL->set_text ("Floor");
1667 $INVR->set_items ($self->{container}{0});
1535 } elsif ($item->{container} == $self->{player}{tag}) { 1668 } elsif ($item->{container} == $self->{player}{tag}) {
1536 $INV->set_items ($self->{container}{$item->{container}}) 1669 $INV->set_items ($self->{container}{$item->{container}})
1670 }
1537 } 1671 }
1538} 1672}
1539 1673
1540%SDL_CB = ( 1674%SDL_CB = (
1541 CFClient::SDL_QUIT => sub { 1675 CFClient::SDL_QUIT => sub {
1588 sdl_mode => 0, 1722 sdl_mode => 0,
1589 width => 640, 1723 width => 640,
1590 height => 480, 1724 height => 480,
1591 fullscreen => 0, 1725 fullscreen => 0,
1592 fast => 0, 1726 fast => 0,
1593 map_scale => 0.5, 1727 map_scale => 1,
1594 fow_enable => 1, 1728 fow_enable => 1,
1595 fow_intensity => 0.45, 1729 fow_intensity => 0.45,
1596 fow_smooth => 0, 1730 fow_smooth => 0,
1597 gui_fontsize => 1, 1731 gui_fontsize => 1,
1598 log_fontsize => 1, 1732 log_fontsize => 1,
1603 host => "crossfire.schmorp.de", 1737 host => "crossfire.schmorp.de",
1604 say_command => 'say', 1738 say_command => 'say',
1605 audio_enable => 1, 1739 audio_enable => 1,
1606 bgm_enable => 1, 1740 bgm_enable => 1,
1607 bgm_volume => 0.25, 1741 bgm_volume => 0.25,
1742 output_sync => 1,
1743 output_count => 1,
1608 ); 1744 );
1609 1745
1610 while (my ($k, $v) = each %DEF_CFG) { 1746 while (my ($k, $v) = each %DEF_CFG) {
1611 $CFG->{$k} = $v unless exists $CFG->{$k}; 1747 $CFG->{$k} = $v unless exists $CFG->{$k};
1612 } 1748 }
1717 1853
1718Typing B<climb> will display a list of commands with I<climb> in their 1854Typing B<climb> will display a list of commands with I<climb> in their
1719name, such as I<ready_skill climbing> and I<use_skill climbing>. 1855name, such as I<ready_skill climbing> and I<use_skill climbing>.
1720 1856
1721You can abbreviate commands by typing only the first character of every 1857You can abbreviate commands by typing only the first character of every
1722word. For example, typing I<iwor> will likely select I<invoke word of 1858word (or even characters within the word - the client will try to make
1723recall>, while I<ccfo> will select I<cast create food>. Likewise, I<rscli> 1859a good guess, as long as the characters are in order). For example,
1724will likely select I<ready_skill climbing> and I<usl> will give you 1860typing I<iwor> will likely select I<invoke word of recall>, while I<ccfo>
1725I<use_skill levitation>. 1861will select I<cast create food>. Likewise, I<rscli> will likely select
1862I<ready_skill climbing> and I<usl> will give you I<use_skill levitation>.
1863
1864You can enter space and other text as arguemnt to the command. For
1865example, C<cfoo waybread> will expand to C<cast create food waybread>.
1726 1866
1727=head2 The map overview 1867=head2 The map overview
1728 1868
1729#TODO# 1869#TODO#
1730 1870

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines