ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/Util.pm
Revision: 1.4
Committed: Sun Mar 12 23:32:58 2006 UTC (18 years, 4 months ago) by elmex
Branch: MAIN
Changes since 1.3: +29 -1 lines
Log Message:
implemented file->new and implemented attredit

File Contents

# Content
1 package GCE::Util;
2 =head1 NAME
3
4 GCE::Util - some utility functions
5
6 =over 4
7
8 =cut
9
10 use base 'Exporter';
11
12 use Crossfire;
13
14 use Carp ();
15 use Storable;
16 use List::Util qw(min max);
17
18 use Crossfire;
19 use Crossfire::MapWidget;
20
21 our @EXPORT = qw(insert_arch_stack_layer replace_arch_stack_layer new_arch_pb fill_pb_from_arch arch_is_floor stack_find_floor stack_find_wall stack_find arch_is_wall arch_is_monster add_table_widget);
22
23 sub new_arch_pb {
24 # this is awful, is this really the best way?
25 my $pb = new Gtk2::Gdk::Pixbuf 'rgb', 1, 8, TILESIZE, TILESIZE;
26 return $pb;
27 }
28
29 sub fill_pb_from_arch {
30 my ($pb, $arch) = @_;
31
32 $pb->fill (0x00000000);
33 $TILE->composite ($pb,
34 0, 0,
35 TILESIZE, TILESIZE,
36 - ($arch->{_face} % 64) * TILESIZE, - TILESIZE * int $arch->{_face} / 64,
37 1, 1, 'nearest', 255
38 );
39 }
40
41 sub classify_arch_layer {
42 my ($arch) = @_;
43
44 if ($arch->{invisible}) { # just a heuristic for 'special' tiles (er. pedestals)
45
46 return 'below';
47
48 } elsif ($arch->{monster}) {
49
50 return 'top';
51
52 } else { # $arch->{is_floor} and all other arches are 'between' monsters and floor
53
54 return 'between';
55 }
56 }
57
58 sub arch_is_floor {
59 my ($a) = @_;
60 return $Crossfire::ARCH{$a->{_name}}->{is_floor};
61 }
62
63 sub arch_is_wall {
64 my ($a) = @_;
65 return $Crossfire::ARCH{$a->{_name}}->{no_pass};
66 }
67
68 sub arch_is_monster {
69 my ($a) = @_;
70 my $arch = $Crossfire::ARCH{$a->{_name}};
71 return $arch->{alive} and ($arch->{monster} or $arch->{generator});
72 }
73
74 sub stack_find {
75 my ($stack, $dir, $pred) = @_;
76
77
78 if ($dir eq 'from_top') {
79 my $i = scalar (@$stack) - 1;
80 if ($i < 0) { $i = 0 }
81
82 for (reverse @$stack) {
83 $pred->($_)
84 and return $i;
85
86 $i--;
87 }
88
89 } else {
90 my $i = 0;
91
92 for (@$stack) {
93 $pred->($_)
94 and return $i;
95
96 $i++;
97 }
98 }
99
100 return 0;
101
102 }
103
104 sub stack_find_floor {
105 my ($stack, $dir) = @_;
106 return stack_find ($stack, $dir, \&arch_is_floor);
107 }
108
109 sub stack_find_wall {
110 my ($stack, $dir) = @_;
111 return stack_find ($stack, $dir, \&arch_is_wall);
112 }
113
114 sub insert_arch_stack_layer {
115 my ($stack, $arch) = @_;
116
117 unless (@$stack) {
118 return [ $arch ];
119 }
120
121 my @outstack;
122
123 my $l = classify_arch_layer ($Crossfire::ARCH{$arch->{_name}});
124
125 if ($l eq 'between') {
126
127 # loop until we reached the first 'between' arch above 'below' arches and the floor
128 while (my $a = shift @$stack) {
129
130 unless ($Crossfire::ARCH{$a->{_name}}->{is_floor}
131 or classify_arch_layer ($Crossfire::ARCH{$a->{_name}}) eq 'below') {
132
133 unshift @$stack, $a;
134 last;
135 }
136
137 push @outstack, $a;
138 }
139
140 # ignore duplicates
141 # FIXME: Broken if non-floor are drawn (too tired to fix)
142 return [ @outstack, @$stack ]
143 if @outstack and $outstack[-1]->{_name} eq $arch->{_name};
144
145 push @outstack, ($arch, @$stack);
146
147 } elsif ($l eq 'top') {
148
149 # ignore duplicates
150 return [ @$stack ]
151 if $stack->[-1]->{_name} eq $arch->{_name};
152
153 @outstack = (@$stack, $arch);
154
155 } else {
156
157 # ignore duplicates
158 return [ @$stack ]
159 if $stack->[0]->{_name} eq $arch->{_name};
160
161 @outstack = ($arch, @$stack);
162 }
163
164 return \@outstack;
165 }
166
167 sub add_table_widget {
168 my ($table, $row, $data, $type, $cb) = @_;
169 my $edwid;
170
171 if ($type eq 'string') {
172 $table->attach_defaults (my $lbl = Gtk2::Label->new ($data->[0]), 0, 1, $row, $row + 1);
173 $edwid = Gtk2::Entry->new;
174 $edwid->set_text ($data->[1]);
175 $edwid->signal_connect (changed => sub {
176 $data->[1] = $_[0]->get_text;
177 $cb->($data->[1]) if $cb;
178 });
179 $table->attach_defaults ($edwid, 1, 2, $row, $row + 1);
180
181 } elsif ($type eq 'button') {
182 $table->attach_defaults (my $b = Gtk2::Button->new_with_label ($data), 0, 2, $row, $row + 1);
183 $b->signal_connect (clicked => ($cb || sub {}));
184
185 } elsif ($type eq 'label') {
186 $table->attach_defaults (my $lbl = Gtk2::Label->new ($data->[0]), 0, 1, $row, $row + 1);
187 $edwid = Gtk2::Label->new ($data->[1]);
188 $table->attach_defaults ($edwid, 1, 2, $row, $row + 1);
189
190 } else {
191 $edwid = Gtk2::Label->new ("FOO");
192 }
193 }
194
195 sub replace_arch_stack_layer {
196 my ($stack, $arch) = @_;
197
198 my @outstack;
199
200 my $l = classify_arch_layer ($Crossfire::ARCH{$arch->{_name}});
201
202 if ($l eq 'between') {
203
204 while (shift @$stack) {
205 last unless $Crossfire::ARCH{$_->{_name}}->{is_floor};
206 push @outstack, $_;
207 }
208
209 if (@outstack and $Crossfire::ARCH{$outstack[-1]->{_name}}->{is_floor}) {
210 pop @outstack;
211 }
212
213 push @outstack, ($arch, @$stack);
214
215 } elsif ($l eq 'top') {
216
217 @outstack = (@$stack, $arch);
218
219 } else {
220
221 @outstack = ($arch, @$stack);
222 }
223
224 return \@outstack;
225 }
226
227 =head1 AUTHOR
228
229 Marc Lehmann <schmorp@schmorp.de>
230 http://home.schmorp.de/
231
232 Robin Redeker <elmex@ta-sa.org>
233 http://www.ta-sa.org/
234
235 =cut
236 1;