ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/EditAction.pm
Revision: 1.19
Committed: Thu Mar 16 22:43:22 2006 UTC (18 years, 2 months ago) by elmex
Branch: MAIN
Changes since 1.18: +3 -3 lines
Log Message:
put some keybindings in

File Contents

# User Rev Content
1 elmex 1.1 package GCE::EditAction;
2    
3     =head1 NAME
4    
5     GCE::EditActions - this is the abstraction of edit actions (placing, deleting, etc.)
6    
7     =cut
8    
9     use Gtk2;
10     use Gtk2::Gdk::Keysyms;
11     use Gtk2::SimpleMenu;
12    
13     use Crossfire;
14     use Crossfire::MapWidget;
15    
16     use strict;
17    
18     sub new {
19     my $class = shift;
20     my $self = { @_ };
21     bless $self, $class;
22 elmex 1.6 $self->init;
23 elmex 1.1 return $self;
24     }
25    
26 elmex 1.10 sub name { } # a unique name for this tool (for storing it in a hash in the main window)
27    
28 elmex 1.7 sub tool_widget { if ($_[1]) { $_[0]->{widget} = $_[1] } $_[0]->{widget} }
29 elmex 1.6 sub init { }
30    
31 elmex 1.1 sub want_cursor { 1 }
32    
33     sub special_arrow { }
34    
35     # edits one tile of the map
36     sub edit_one {
37     my ($self, $x, $y) = @_;
38     # do one edition
39     }
40    
41     # edits a selection
42     sub edit_selection {
43     }
44    
45     # abstraction for edit_one and edit_selection ?
46     # takes selection if present
47     sub edit {
48 elmex 1.10 my ($self, $map, $x, $y) = @_;
49 elmex 1.1 }
50    
51     sub begin {
52 elmex 1.10 my ($self, $map, $x, $y) = @_;
53 root 1.3
54     $map->change_begin (ref $self);
55 elmex 1.1 }
56 root 1.3
57 elmex 1.1 sub end {
58 root 1.3 my ($self, $map) = @_;
59    
60     if (my $changeset = $map->change_end) {
61     splice @{ $map->{undo_stack} ||= [] },
62 root 1.4 $map->{undo_stack_pos}++, 1e6,
63 root 1.3 $changeset;
64    
65     #TODO: limit undo stack size to some preconfigured limit
66     }
67 elmex 1.1 }
68    
69 elmex 1.7 package GCE::EditAction::RadioModed;
70    
71     our @ISA = qw/GCE::EditAction/;
72    
73     sub add_mode_button {
74     my ($self, $vb, $lbl, $mode, $default) = @_;
75    
76     $vb->pack_start (my $b = Gtk2::RadioButton->new ($self->{place_radio_grp}, $lbl), 0, 1, 0);
77     unless (defined $self->{place_radio_grp}) {
78     $self->{place_radio_grp} = $b->get_group;
79    
80     unless (defined $default) {
81     $b->set_active (1);
82     $self->set_mode ($mode);
83     }
84     }
85     if ($default) {
86     $b->set_active (1);
87     $self->set_mode ($mode);
88     }
89     $b->signal_connect (clicked => sub {
90     $self->set_mode ($mode);
91     });
92     }
93    
94     sub set_mode {
95     my ($self, $mode) = @_;
96     $self->{place_mode} = $mode;
97     }
98    
99     sub get_mode {
100     my ($self) = @_;
101     $self->{place_mode}
102     }
103    
104     sub init {
105     my ($self) = @_;
106    
107     die "Implement me!!";
108    
109     # my $vb = new Gtk2::VBox;
110     # $self->_add_mode_button ($vb, "auto", "auto");
111     # $self->_add_mode_button ($vb, "top", "top");
112     # $self->_add_mode_button ($vb, "above floor", "above");
113     # $self->_add_mode_button ($vb, "below floor", "below");
114     # $self->_add_mode_button ($vb, "bottom", "bottom");
115     #
116     # $self->{widget} = $vb;
117     }
118 elmex 1.1
119     package GCE::EditAction::Pick;
120 elmex 1.7 use strict;
121 elmex 1.1
122     our @ISA = qw/GCE::EditAction/;
123    
124 elmex 1.10 sub name { 'pick' }
125    
126 elmex 1.7 sub want_cursor { 0 }
127    
128 elmex 1.1 sub special_arrow { 'GDK_HAND2' }
129    
130     sub begin {
131 elmex 1.10 my ($self, $map, $x, $y) = @_;
132 elmex 1.1
133 elmex 1.10 $self->SUPER::begin ($map, $x, $y);
134     $self->edit ($map, $x, $y);
135 elmex 1.1 }
136    
137     sub edit {
138 elmex 1.10 my ($self, $map, $x, $y) = @_;
139 elmex 1.1
140     my $cstack = $map->get ($x, $y);
141    
142     my $arch = $cstack->[-1];
143    
144     # virtual... grmbl....
145     # FIXME: I have to patch the stack of the real arch??? argl.. how??
146     if ($arch->{_virtual}) {
147 root 1.3 $x = $arch->{virtual_x};
148     $y = $arch->{virtual_y};
149 elmex 1.1 $arch = $arch->{_virtual};
150 elmex 1.6 $cstack = $map->get ($x, $y);
151 elmex 1.1 }
152    
153 root 1.5 $::MAINWIN->set_pick ($arch)
154 elmex 1.10 if @$cstack;
155 elmex 1.1
156 root 1.5 $::MAINWIN->update_attr_editor ($arch, sub {
157 elmex 1.8 $map->change_begin (ref $self);
158 root 1.3 $map->change_stack ($x, $y, $cstack);
159 elmex 1.8 # XXX: Put this into a generic function!!! See also EditTools.pm
160     # FIXME: Fix the automatic update on undo here!
161     if (my $changeset = $map->change_end) {
162     splice @{ $map->{undo_stack} ||= [] },
163     $map->{undo_stack_pos}++, 1e6,
164     $changeset;
165     }
166 elmex 1.1 });
167    
168 root 1.5 $::MAINWIN->update_stack_view ($map, $x, $y);
169 elmex 1.1 }
170    
171 elmex 1.13 package GCE::EditAction::Perl;
172    
173     use GCE::Util;
174     use Gtk2;
175     use strict;
176    
177     our @ISA = qw/GCE::EditAction/;
178    
179     sub name { 'perl' }
180    
181 elmex 1.15 sub special_arrow { 'GDK_HEART' }
182    
183 elmex 1.13 sub init {
184     my ($self) = @_;
185    
186     my $vb = new Gtk2::VBox;
187     $vb->pack_start (my $sw = Gtk2::ScrolledWindow->new, 1, 1, 0);
188     $sw->add ($self->{txt} = Gtk2::TextView->new);
189    
190     $self->tool_widget ($vb);
191     }
192    
193     sub want_cursor { 0 }
194    
195     sub begin {
196     my ($self, $map, $x, $y) = @_;
197    
198     $self->SUPER::begin ($map, $x, $y);
199     $self->edit ($map, $x, $y);
200     }
201    
202     sub edit {
203     my ($self, $map, $x, $y) = @_;
204    
205     my $pick = $::MAINWIN->get_pick;
206     my $as = $map->get ($x, $y);
207    
208     $as = $self->eval ($map, $pick, $as, $x, $y);
209     $map->change_stack ($x, $y, $as); # insert_arch_stack_layer ($as, $arch));
210     }
211    
212     sub eval {
213     my ($self, $map, $pick, $stack, $x, $y) = @_;
214     my $buf = $self->{txt}->get_buffer;
215     my $code = $buf->get_text ($buf->get_start_iter, $buf->get_end_iter, 0);
216    
217     eval $code;
218     return $stack;
219     }
220    
221 elmex 1.18 package GCE::EditAction::FollowExit;
222     use Storable qw/dclone/;
223     use File::Spec::Functions;
224     use GCE::Util;
225     use Gtk2;
226     use strict;
227    
228     our @ISA = qw/GCE::EditAction/;
229    
230     sub name { 'place' }
231    
232     sub init {
233     my ($self) = @_;
234    
235     my $vb = new Gtk2::VBox;
236    
237     $self->tool_widget ($vb);
238     }
239    
240     sub want_cursor { 0 }
241    
242     sub begin {
243     my ($self, $map, $x, $y) = @_;
244    
245     # $self->SUPER::begin ($map, $x, $y);
246     $self->edit ($map, $x, $y);
247     }
248    
249     sub edit {
250     my ($self, $map, $x, $y) = @_;
251    
252     my $as = $map->get ($x, $y);
253    
254     my $exit;
255     for (@$as) {
256     my $a = $Crossfire::ARCH{$_->{_name}};
257     if ($a->{type} eq '66') {
258     $exit = $_;
259     }
260     }
261    
262     if ($exit) {
263     my $dest = $exit->{slaying};
264     my $dir;
265     if (File::Spec->file_name_is_absolute($dest)) {
266     $dir = catdir ($Crossfire::LIB, 'maps', $dest);
267     } else {
268     $dir = File::Spec->rel2abs ($dest, catdir ($Crossfire::LIB, 'maps'));
269     }
270     $::MAINWIN->open_map_editor ($dir);
271     }
272     }
273    
274     sub end {
275     my ($self, $map, $x, $y, $mape) = @_;
276     # $::MAINWIN->{edit_collection}{pick}->edit ($map, $x, $y);
277     #$self->SUPER::end ($map, $x, $y, $mape);
278     }
279    
280 elmex 1.1 package GCE::EditAction::Place;
281 elmex 1.14 use Storable qw/dclone/;
282 elmex 1.2 use GCE::Util;
283 elmex 1.6 use Gtk2;
284     use strict;
285 elmex 1.2
286 elmex 1.7 our @ISA = qw/GCE::EditAction::RadioModed/;
287 elmex 1.6
288 elmex 1.10 sub name { 'place' }
289    
290 elmex 1.6 sub init {
291     my ($self) = @_;
292    
293     my $vb = new Gtk2::VBox;
294 elmex 1.7 $self->add_mode_button ($vb, "auto", "auto");
295     $self->add_mode_button ($vb, "top", "top");
296     $self->add_mode_button ($vb, "above floor", "above");
297     $self->add_mode_button ($vb, "below floor", "below");
298     $self->add_mode_button ($vb, "bottom", "bottom");
299 elmex 1.6
300 elmex 1.17 $vb->pack_start ($self->{place_clean} = Gtk2::CheckButton->new ('place clean'), 0, 1, 0);
301    
302 elmex 1.7 $self->tool_widget ($vb);
303 elmex 1.6 }
304    
305 elmex 1.1 sub want_cursor { 0 }
306    
307     sub begin {
308 elmex 1.10 my ($self, $map, $x, $y) = @_;
309 elmex 1.1
310 elmex 1.10 $self->SUPER::begin ($map, $x, $y);
311     $self->edit ($map, $x, $y);
312 elmex 1.1 }
313    
314     sub edit {
315 elmex 1.10 my ($self, $map, $x, $y) = @_;
316 elmex 1.1
317 elmex 1.10 my $pick = $::MAINWIN->get_pick;
318     my $as = $map->get ($x, $y);
319 elmex 1.1
320 elmex 1.17 if ($self->{place_clean}->get_active) {
321     $pick = { _name => $pick->{_name} };
322     }
323    
324 elmex 1.14 $self->stack_action ($as, dclone ($pick));
325 elmex 1.10 $map->change_stack ($x, $y, $as); # insert_arch_stack_layer ($as, $arch));
326 elmex 1.1 }
327    
328 elmex 1.17 sub end {
329     my ($self, $map, $x, $y, $mape) = @_;
330     $::MAINWIN->{edit_collection}{pick}->edit ($map, $x, $y);
331     $self->SUPER::end ($map, $x, $y, $mape);
332     }
333    
334 elmex 1.6 sub stack_action {
335     my ($self, $stack, $arch) = @_;
336    
337 elmex 1.7 my $m = $self->get_mode;
338 elmex 1.6
339     if ($m eq 'top') {
340     if (@$stack == 0 or $stack->[-1]->{_name} ne $arch->{_name}) {
341     push @$stack, $arch;
342     }
343    
344     } elsif ($m eq 'bottom') {
345     if (@$stack == 0 or $stack->[0]->{_name} ne $arch->{_name}) {
346     unshift @$stack, $arch;
347     }
348    
349     } elsif ($m eq 'above') {
350     my $fidx = stack_find_floor ($stack, 'from_top');
351    
352     if (@$stack == 0
353     or not ($stack->[$fidx + 1])
354     or $stack->[$fidx + 1]->{_name} ne $arch->{_name})
355     {
356     splice (@$stack, $fidx + 1, 0, $arch);
357     }
358    
359     } elsif ($m eq 'below') {
360     my $fidx = stack_find_floor ($stack, 'from_bottom');
361    
362     if (@$stack == 0
363     or $fidx == 0
364     or not ($stack->[$fidx - 1])
365     or $stack->[$fidx - 1]->{_name} ne $arch->{_name})
366     {
367     splice (@$stack, $fidx, 0, $arch);
368     }
369    
370     } elsif ($m eq 'auto') {
371     my $fidx = stack_find_floor ($stack, 'from_top');
372     my $widx = stack_find_wall ($stack);
373    
374     if (arch_is_floor ($arch)) { # we want to place a floor tile
375    
376     if (arch_is_floor ($stack->[$fidx])) { # replace
377     $stack->[$fidx] = $arch;
378    
379     } else { # insert on bottom
380     unshift @$stack, $arch;
381     }
382    
383     } elsif (arch_is_wall ($arch)) { # we want to place a wall
384    
385     if (arch_is_wall ($stack->[$widx])) { # replace
386     $stack->[$widx] = $arch;
387    
388     } else { # insert above floor
389     splice (@$stack, $fidx + 1, 0, $arch);
390     }
391    
392     } else {
393    
394     if (arch_is_wall ($stack->[$widx])) {
395 elmex 1.9 # if we have a wall above the floor, replace it with the to place item
396     $stack->[$widx] = $arch;
397 elmex 1.6 return;
398     }
399    
400     if (@$stack == 0
401     or not ($stack->[-1])
402     or $stack->[-1]->{_name} ne $arch->{_name})
403     {
404     push @$stack, $arch;
405     }
406     }
407     }
408     }
409    
410 elmex 1.12 package GCE::EditAction::Select;
411 elmex 1.11 use GCE::Util;
412     use Gtk2;
413 elmex 1.12 use Crossfire;
414     use Storable qw/dclone/;
415 elmex 1.11 use strict;
416    
417     our @ISA = qw/GCE::EditAction::RadioModed/;
418    
419 elmex 1.12 sub name { 'select' }
420 elmex 1.11
421 elmex 1.15 sub special_arrow { 'GDK_CIRCLE' }
422    
423 elmex 1.11 sub init {
424     my ($self) = @_;
425    
426     my $vb = new Gtk2::VBox;
427    
428 elmex 1.19 $vb->pack_start (my $bt = Gtk2::Button->new_with_mnemonic ("_copy"), 0, 1, 0);
429 elmex 1.12 $bt->signal_connect (clicked => sub { $self->copy });
430     $vb->pack_start ($self->{paste_top} = Gtk2::CheckButton->new ('paste on top'), 0, 1, 0);
431 elmex 1.19 $vb->pack_start (my $bt = Gtk2::Button->new_with_mnemonic ("paste (_v)"), 0, 1, 0);
432 elmex 1.12 $bt->signal_connect (clicked => sub { $self->paste });
433     $vb->pack_start (Gtk2::HSeparator->new, 0, 1, 0);
434     $self->add_mode_button ($vb, "place", "place");
435     $self->add_mode_button ($vb, "erase", "erase");
436 elmex 1.15 $self->add_mode_button ($vb, "perl", "perl");
437 elmex 1.19 $vb->pack_start (my $bt = Gtk2::Button->new_with_mnemonic ("i_nvoke"), 0, 1, 0);
438 elmex 1.12 $bt->signal_connect (clicked => sub { $self->invoke });
439 elmex 1.11
440     $self->tool_widget ($vb);
441     }
442    
443 elmex 1.12 sub copy {
444     my ($self) = @_;
445    
446     return unless $self->{selection}->{a};
447     my ($x1, $y1) = @{$self->{selection}->{a}};
448     my ($x2, $y2) = @{$self->{selection}->{b}};
449    
450     if ($x1 > $x2) { ($x2, $x1) = ($x1, $x2) }
451     if ($y1 > $y2) { ($y2, $y1) = ($y1, $y2) }
452    
453     my $map = $self->{selection}->{map};
454    
455     $self->{copy_coords} = [$x1, $y1, $x2, $y2];
456     $self->{copy};
457     for (my $x = $x1; $x <= $x2; $x++) {
458     for (my $y = $y1; $y <= $y2; $y++) {
459     $self->{copy}->[$x - $x1]->[$y - $y1] = $map->get ($x, $y);
460     }
461     }
462     }
463    
464     sub paste {
465     my ($self, $xp, $yp) = @_;
466    
467     return unless $self->{selection}->{a};
468    
469     my ($x1, $y1);
470    
471 elmex 1.15 if (defined $xp) {
472 elmex 1.12 ($x1, $y1) = ($xp, $yp);
473     } else {
474     ($x1, $y1) = @{$self->{selection}->{a}};
475     }
476    
477     my $map = $self->{selection}->{map};
478    
479     my $p_o_top = $self->{paste_top}->get_active * 1;
480    
481     my $w = $self->{copy_coords}->[2] - $self->{copy_coords}->[0];
482     my $h = $self->{copy_coords}->[3] - $self->{copy_coords}->[1];
483     $self->{copy};
484     $self->SUPER::begin ($map, $x1, $y1);
485     for (my $x = $x1; $x <= ($x1 + $w); $x++) {
486     for (my $y = $y1; $y <= ($y1 + $h); $y++) {
487     my $cstck = $map->get ($x, $y);
488    
489     if ($p_o_top) {
490     push @$cstck, @{dclone ($self->{copy}->[$x - $x1]->[$y - $y1] || [])};
491     $map->change_stack ($x, $y, $cstck);
492     } else {
493     $map->change_stack ($x, $y, dclone ($self->{copy}->[$x - $x1]->[$y - $y1] || []));
494     }
495     }
496     }
497     $self->SUPER::end ($map);
498     $map->invalidate_all;
499     }
500    
501     sub invoke {
502     my ($self) = @_;
503    
504     return unless $self->{selection}->{a};
505     my ($x1, $y1) = @{$self->{selection}->{a}};
506     my ($x2, $y2) = @{$self->{selection}->{b}};
507    
508     if ($x1 > $x2) { ($x2, $x1) = ($x1, $x2) }
509     if ($y1 > $y2) { ($y2, $y1) = ($y1, $y2) }
510    
511     my $map = $self->{selection}->{map};
512    
513     my $m = $self->get_mode;
514     $self->SUPER::begin ($map, $x1, $y1);
515     for (my $x = $x1; $x <= $x2; $x++) {
516     for (my $y = $y1; $y <= $y2; $y++) {
517     if ($m eq 'place') {
518     $::MAINWIN->{edit_collection}{place}->edit ($map, $x, $y);
519     } elsif ($m eq 'erase') {
520     $::MAINWIN->{edit_collection}{erase}->edit ($map, $x, $y);
521 elmex 1.15 } elsif ($m eq 'perl') {
522     $::MAINWIN->{edit_collection}{perl}->edit ($map, $x, $y);
523 elmex 1.12 }
524     }
525     }
526     $self->SUPER::end ($map);
527     }
528    
529 elmex 1.11 sub want_cursor { 0 }
530    
531     sub begin {
532     my ($self, $map, $x, $y) = @_;
533    
534     delete $self->{selection};
535    
536 elmex 1.12 $self->{selection}->{a} = [$x, $y];
537 elmex 1.11 $self->edit ($map, $x, $y);
538 elmex 1.12 }
539 elmex 1.11
540 elmex 1.12 sub end {
541 elmex 1.11 }
542    
543     sub edit {
544     my ($self, $map, $x, $y) = @_;
545    
546     $self->{selection}->{b} = [$x, $y];
547 elmex 1.12 $self->{selection}->{map} = $map;
548 elmex 1.11 $self->update_overlay ($map);
549     }
550    
551     sub update_overlay {
552     my ($self, $map) = @_;
553    
554 elmex 1.12 my ($x1, $y1) = @{$self->{selection}->{a}};
555     my ($x2, $y2) = @{$self->{selection}->{b}};
556    
557     if ($x1 > $x2) { ($x2, $x1) = ($x1, $x2) }
558     if ($y1 > $y2) { ($y2, $y1) = ($y1, $y2) }
559 elmex 1.11
560 elmex 1.12 my $w = ($x2 - $x1) + 1;
561     my $h = ($y2 - $y1) + 1;
562    
563     $map->overlay (selection =>
564     $x1 * TILESIZE, $y1 * TILESIZE,
565     $w * TILESIZE, $h * TILESIZE,
566     sub {
567     my ($self, $x, $y) = @_;
568     $self->{window}->draw_rectangle (
569     $_ & 1 ? $self->style->black_gc : $self->style->white_gc,
570     0,
571     $x + $_, $y + $_,
572     ($w * TILESIZE) - 1 - $_ * 2,
573     ($h * TILESIZE) - 1 - $_ * 2
574     ) for 0..3;
575     }
576     );
577 elmex 1.11 }
578    
579 elmex 1.1 package GCE::EditAction::Erase;
580 elmex 1.7 use GCE::Util;
581     use Gtk2;
582     use strict;
583 elmex 1.1
584 elmex 1.7 our @ISA = qw/GCE::EditAction::RadioModed/;
585 elmex 1.1
586 elmex 1.10 sub name { 'erase' }
587    
588 elmex 1.1 sub want_cursor { 0 }
589    
590 elmex 1.15 sub special_arrow { 'GDK_DIAMOND_CROSS' }
591 elmex 1.10
592 elmex 1.7 sub init {
593     my ($self) = @_;
594    
595     my $vb = new Gtk2::VBox;
596     $self->add_mode_button ($vb, "top", "top");
597     $self->add_mode_button ($vb, "walls", "walls");
598     $self->add_mode_button ($vb, "above floor", "above", 'default');
599     $self->add_mode_button ($vb, "floor", "floor");
600     $self->add_mode_button ($vb, "below floor", "below");
601     $self->add_mode_button ($vb, "bottom", "bottom");
602     $self->add_mode_button ($vb, "pick match", "match");
603    
604     $self->tool_widget ($vb);
605    
606     $vb->pack_start ($self->{no_wall_check} = Gtk2::CheckButton->new ("exclude walls"), 0, 1, 0);
607     $vb->pack_start ($self->{no_monsters_check} = Gtk2::CheckButton->new ("exclude monsters"), 0, 1, 0);
608     }
609    
610     sub check_excluded {
611     my ($self, $arch) = @_;
612    
613     my $a1 = $self->{no_monsters_check}->get_active;
614     my $a2 = $self->{no_wall_check}->get_active;
615    
616     my $r = ($self->{no_wall_check}->get_active && arch_is_wall ($arch))
617     || ($self->{no_monsters_check}->get_active && arch_is_monster ($arch));
618     return $r;
619     }
620    
621 elmex 1.1 sub begin {
622 elmex 1.10 my ($self, $map, $x, $y) = @_;
623 elmex 1.1
624 elmex 1.10 $self->SUPER::begin ($map, $x, $y);
625     $self->edit ($map, $x, $y);
626 elmex 1.1 }
627    
628     sub edit {
629 elmex 1.10 my ($self, $map, $x, $y) = @_;
630 elmex 1.1
631     my $as = $map->get ($x, $y);
632 elmex 1.7 $self->stack_action ($as);
633 root 1.3 $map->change_stack ($x, $y, $as);
634 elmex 1.1 }
635    
636 elmex 1.7 sub stack_action {
637     my ($self, $stack) = @_;
638    
639     my $m = $self->get_mode;
640    
641     if ($m eq 'top') {
642     pop @$stack;
643    
644     } elsif ($m eq 'bottom') {
645     shift @$stack;
646    
647     } elsif ($m eq 'above') {
648     my $fidx = stack_find_floor ($stack, 'from_top');
649    
650     if (arch_is_floor ($stack->[$fidx]) and $stack->[$fidx + 1]) {
651     splice (@$stack, $fidx + 1, 1)
652     unless $self->check_excluded ($stack->[$fidx + 1])
653    
654     } elsif (not arch_is_floor ($stack->[$fidx])) {
655     splice (@$stack, $fidx, 1)
656     unless $self->check_excluded ($stack->[$fidx])
657    
658     }
659    
660     } elsif ($m eq 'below') {
661     my $fidx = stack_find_floor ($stack, 'from_bottom');
662    
663     if ($fidx > 0 and not arch_is_floor ($stack->[$fidx - 1])) {
664     splice (@$stack, $fidx - 1, 1)
665     unless $self->check_excluded ($stack->[$fidx - 1])
666    
667     } elsif (not arch_is_floor ($stack->[$fidx])) { # no floor found
668     splice (@$stack, $fidx, 1)
669     unless $self->check_excluded ($stack->[$fidx])
670    
671     }
672    
673     } elsif ($m eq 'walls') {
674     my $widx = stack_find_wall ($stack, 'from_top');
675    
676     while (arch_is_wall ($stack->[$widx])) {
677     splice (@$stack, $widx, 1);
678     $widx = stack_find_wall ($stack, 'from_top')
679     }
680    
681     } elsif ($m eq 'floor') {
682     my $fidx = stack_find_floor ($stack, 'from_top');
683    
684     while (arch_is_floor ($stack->[$fidx])) {
685     splice (@$stack, $fidx, 1);
686     $fidx = stack_find_floor ($stack, 'from_top')
687     }
688    
689     } elsif ($m eq 'match') {
690     my $pick_name = $::MAINWIN->get_pick ()->{_name};
691     my $idx = stack_find ($stack, 'from_top', sub { $_[0]->{_name} eq $pick_name });
692    
693     while ($stack->[$idx] and $stack->[$idx]->{_name} eq $pick_name) {
694     splice (@$stack, $idx, 1);
695     $idx = stack_find ($stack, 'from_top', sub { $_[0]->{_name} eq $pick_name });
696     }
697     }
698     }
699    
700 elmex 1.18 package GCE::EditAction::ConnectExit;
701 elmex 1.16 use Storable qw/dclone/;
702     use GCE::Util;
703     use Gtk2;
704     use File::Spec::Functions;
705     use strict;
706    
707     our @ISA = qw/GCE::EditAction::RadioModed/;
708    
709 elmex 1.18 sub name { 'connectexit' }
710 elmex 1.16
711     sub init {
712     my ($self) = @_;
713    
714     my $vb = new Gtk2::VBox;
715     $self->add_mode_button ($vb, "exit", "exit");
716     # $self->add_mode_button ($vb, "triggers", "trig");
717 elmex 1.18 $vb->pack_start ($self->{sel_edt} = Gtk2::Entry->new, 0, 1, 0);
718     $self->{sel_edt}->set_text (catfile ($Crossfire::LIB, 'maps'));
719    
720 elmex 1.16 $vb->pack_start ($self->{sel_lbl} = Gtk2::Label->new, 0, 0, 0);
721     $self->tool_widget ($vb);
722     }
723    
724     sub want_cursor { 0 }
725    
726     sub begin {
727     my ($self, $map, $x, $y, $mapedit) = @_;
728    
729     $self->edit ($map, $x, $y, $mapedit);
730     }
731    
732     sub edit {
733     my ($self, $map, $x, $y, $mapedit) = @_;
734    
735     my $pick = $::MAINWIN->get_pick;
736     my $as = $map->get ($x, $y);
737    
738     my $exit;
739     for (@$as) {
740     my $a = $Crossfire::ARCH{$_->{_name}};
741     if ($a->{type} eq '66') {
742     $exit = $_;
743     }
744     }
745    
746 elmex 1.18 my $ent = $self->{sel_edt}->get_text;
747 elmex 1.16 if ($exit) {
748     if ($self->{sel_exit}) {
749    
750     $exit->{hp} = $self->{sel_exit}->[3];
751     $exit->{sp} = $self->{sel_exit}->[4];
752     $exit->{slaying} = File::Spec->abs2rel ($self->{sel_exit}->[5], $ent);
753    
754     my $exit2 = $self->{sel_exit}->[0];
755    
756     $exit2->{hp} = $x;
757     $exit2->{sp} = $y;
758     $exit2->{slaying} = File::Spec->abs2rel ($mapedit->{path}, $ent);
759    
760     unless ($exit2->{slaying} =~ m/^\.\./) {
761     $exit2->{slaying} = '/' . $exit2->{slaying};
762     }
763     unless ($exit->{slaying} =~ m/^\.\./) {
764     $exit->{slaying} = '/' . $exit->{slaying};
765     }
766    
767     $self->SUPER::begin ($map, $x, $y, $mapedit);
768     $map->change_stack ($x, $y, $as);
769     $self->SUPER::end ($map);
770     $self->SUPER::begin ($self->{sel_exit}->[1], $exit->{hp}, $exit->{sp});
771     $self->{sel_exit}->[1]->change_stack ($exit->{hp}, $exit->{sp}, $self->{sel_exit}->[2]);
772     $self->SUPER::end ($self->{sel_exit}->[1]);
773    
774     quick_msg ($mapedit, "$exit->{slaying} ($x:$y) $exit->{_name} <=> $exit2->{slaying} ($exit2->{hp}:$exit2->{sp}) $exit2->{_name}", 0);
775    
776     $::MAINWIN->{edit_collection}{pick}->edit ($map, $x, $y);
777    
778     $self->{sel_exit} = undef;
779     $self->{sel_lbl}->set_text ('');
780     } else {
781     $self->{sel_lbl}->set_text ("src: ($x:$y) $exit->{_name}");
782     $self->{sel_exit} = [$exit, $map, $as, $x, $y, $mapedit->{path}];
783     }
784     } else {
785 elmex 1.18 if ($self->{sel_exit}) {
786    
787     my $exit2 = $self->{sel_exit}->[0];
788    
789     $exit2->{hp} = $x;
790     $exit2->{sp} = $y;
791     $exit2->{slaying} = File::Spec->abs2rel ($mapedit->{path}, $ent);
792     print "TO: $x:$y => $exit2->{slaying}\n";
793    
794     unless ($exit2->{slaying} =~ m/^\.\./) {
795     $exit2->{slaying} = '/' . $exit2->{slaying};
796     }
797    
798     $self->SUPER::begin ($self->{sel_exit}->[1], $exit->{hp}, $exit->{sp});
799     $self->{sel_exit}->[1]->change_stack ($self->{sel_exit}->[3], $self->{sel_exit}->[4], $self->{sel_exit}->[2]);
800     $self->SUPER::end ($self->{sel_exit}->[1]);
801    
802     quick_msg ($mapedit, "$self->{sel_exit}->[5] ($self->{sel_exit}->[3]:$self->{sel_exit}->[4]) $self->{sel_exit}->[0]->{_name} => $exit2->{slaying} ($x:$y) $exit2->{_name}", 0);
803    
804     $::MAINWIN->{edit_collection}{pick}->edit ($map, $x, $y);
805    
806     $self->{sel_exit} = undef;
807     $self->{sel_lbl}->set_text ('');
808     } else {
809     quick_msg ($mapedit, "no exit object found");
810     }
811 elmex 1.16 }
812    
813     # $self->stack_action ($as, dclone ($pick));
814     #$map->change_stack ($x, $y, $as); # insert_arch_stack_layer ($as, $arch));
815     }
816    
817     sub end {}
818 elmex 1.7
819    
820 elmex 1.1 =head1 AUTHOR
821    
822     Marc Lehmann <schmorp@schmorp.de>
823     http://home.schmorp.de/
824    
825     Robin Redeker <elmex@ta-sa.org>
826     http://www.ta-sa.org/
827    
828     =cut
829 root 1.5
830     1
831 elmex 1.1