ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/crossedit/Edit.c
Revision: 1.1.1.1 (vendor branch)
Committed: Fri Feb 3 07:11:44 2006 UTC (18 years, 4 months ago) by root
Content type: text/plain
Branch: UPSTREAM
CVS Tags: UPSTREAM_2006_03_15, UPSTREAM_2006_02_22, UPSTREAM_2006_02_03
Changes since 1.1: +0 -0 lines
Log Message:
initial import

File Contents

# User Rev Content
1 root 1.1 /*
2     * CrossEdit - game world editor
3     * Copyright (C) 1993 Jarkko Sonninen & Petri Heinila
4     *
5     * This program is free software; you can redistribute it and/or modify
6     * it under the terms of the GNU General Public License as published by
7     * the Free Software Foundation; either version 2 of the License, or
8     * (at your option) any later version.
9     *
10     * This program is distributed in the hope that it will be useful,
11     * but WITHOUT ANY WARRANTY; without even the implied warranty of
12     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     * GNU General Public License for more details.
14     *
15     * You should have received a copy of the GNU General Public License
16     * along with this program; if not, write to the Free Software
17     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18     *
19     * The authors can be reached via e-mail to Jarkko.Sonninen@lut.fi
20     * or Petri.Heinila@lut.fi .
21     */
22    
23     #include "Defines.h"
24     #include "Edit.h"
25    
26     #include "X11.h"
27     #include "Ansi.h"
28    
29     #include "debug.h"
30    
31     #include "CrList.h"
32     #include "CrEdit.h"
33    
34     #include "Cnv.h"
35     /* HACK Make sure we know how big CnvPromptMax is. */
36     #include "Cnv/config.h"
37     #include "App.h"
38     #include "Attr.h"
39     #include "MapAttr.h"
40     #include "Str.h"
41     #include "Bitmaps.h"
42    
43    
44     /*
45     * This function relinks all _pointers_ to the objects from
46     * one map to another.
47     * Note: You can _not_ free the objects in the original map
48     * after this function has been called.
49     * (What happened to this function? It no longer copies the pointers! -Frank)
50     * moved to Edit.c from common/map.c since Edit.c is the only file that uses it.
51     */
52    
53     void copy_map(mapstruct *m1, mapstruct *m2) {
54     int x,y;
55    
56     memcpy(m2, m1, sizeof(mapstruct));
57    
58     for(x=0;x<MAP_WIDTH(m1)&&x<MAP_WIDTH(m2);x++)
59     for(y=0;y<MAP_HEIGHT(m1)&&y<MAP_HEIGHT(m2);y++) {
60     SET_MAP_FACE(m2,x,y,GET_MAP_FACE(m1,x,y,0),0);
61     SET_MAP_FACE(m2,x,y,GET_MAP_FACE(m1,x,y,1),1);
62     SET_MAP_FACE(m2,x,y,GET_MAP_FACE(m1,x,y,2),2);
63     }
64     }
65    
66     /*
67     * member: copy by translate objects from source to a new map
68     * source: -map
69     * width : width of target map
70     * height: height of target map
71     * dx : positive translate to right
72     * dy : positive translate to down
73     */
74     mapstruct *MapMoveScrollResize(mapstruct *source,
75     int width, int height, int dx, int dy)
76     {
77     mapstruct *target;
78     object *obj,*prt; /* PaRT of obj */
79     int x,y,sx = MAP_WIDTH(source), sy = MAP_HEIGHT(source);
80     int linked = 0, link=0;
81     int i;
82    
83     if (!width) width = sx;
84     if (!height) height = sy;
85     target = get_empty_map (width, height);
86    
87     if(dx < 0) dx += MAP_WIDTH(target);
88     if(dy < 0) dy += MAP_HEIGHT(target);
89    
90     /*
91     * Copy the map-headers from source to target.
92     *
93     * The name, msg and tiling paths are allocated for
94     * each map (see map.c::load_map_header()). Copy
95     * the pointer, then NULL the pointer in source so
96     * the strings aren't freed.
97     *
98     * Statements below in the order the fields appear
99     * in map.h.
100     */
101    
102     #define MOVE_AND_CLEAR(to, from) to = from; from = NULL;
103     strncpy (target->path, source->path, HUGE_BUF - 1);
104     target->path[HUGE_BUF - 1] = '\0';
105     MOVE_AND_CLEAR(target->tmpname, source->tmpname);
106     MOVE_AND_CLEAR(target->name, source->name);
107     target->region = source->region;
108     MAP_WHEN_RESET(target) = MAP_WHEN_RESET(source);
109     MAP_RESET_TIMEOUT(target) = MAP_RESET_TIMEOUT(source);
110     target->fixed_resettime = source->fixed_resettime;
111     target->unique = source->unique;
112     MAP_NOSMOOTH(target) = MAP_NOSMOOTH(source);
113     MAP_TIMEOUT(target) = MAP_TIMEOUT(source);
114     MAP_SWAP_TIME(target) = MAP_SWAP_TIME(source);
115     /* fields players/in_memory not copied */
116     target->compressed = source->compressed;
117     MAP_DIFFICULTY(target) = MAP_DIFFICULTY(source);
118     MAP_DARKNESS(target) = MAP_DARKNESS(source);
119     MAP_WIDTH(target) = width;
120     MAP_HEIGHT(target) = height;
121     MAP_ENTER_X(target) = (MAP_ENTER_X(source) + dx) % width;
122     MAP_ENTER_Y(target) = (MAP_ENTER_Y(source) + dy) % height;
123     target->outdoor = MAP_OUTDOORS(source);
124     MAP_TEMP(target) = MAP_TEMP(source);
125     MAP_PRESSURE(target) = MAP_PRESSURE(source);
126     MAP_HUMID(target) = MAP_HUMID(source);
127     MAP_WINDSPEED(target) = MAP_WINDSPEED(source);
128     MAP_WINDDIRECTION(target) = MAP_WINDDIRECTION(source);
129     MAP_SKYCOND(target) = MAP_SKYCOND(source);
130     /* fields wpartx/wparty not copied */
131     MOVE_AND_CLEAR(target->msg, source->msg)
132     /* Tiling paths. */
133     for (i = 0; i < 4; i++) {
134     MOVE_AND_CLEAR(target->tile_path[i], source->tile_path[i]);
135     }
136     #undef MOVE_AND_CLEAR
137    
138     for(y=0; y < sy && y < MAP_HEIGHT(target); y++)
139     for(x=0; x < sx && x < MAP_WIDTH(target); x++)
140     while((obj = get_map_ob(source,x,y)) && !obj->head) {
141     if ((linked = QUERY_FLAG (obj,FLAG_IS_LINKED))) {
142     link = get_button_value (obj);
143     remove_button_link (obj);
144     }
145     remove_ob(obj);
146     for(prt = obj; prt; prt = prt->more) {
147     prt->x += dx;
148     prt->x %= MAP_WIDTH(target); /* it can be split by edge */
149     prt->y += dy; /* designers problem to fix */
150     prt->y %= MAP_HEIGHT(target);
151     }
152     insert_ob_in_map(obj,target,obj,INS_NO_MERGE | INS_NO_WALK_ON);
153     if (linked)
154     add_button_link(obj, target, link);
155     }
156     /*free_all_objects(source);*/
157     free_map (source, 1);
158     delete_map (source);
159     return target;
160     }
161    
162    
163     object * MapGetRealObject (mapstruct * emap, int x, int y, int z)
164     {
165     object *tmp = MapGetObjectZ (emap, x, y, z);
166     return tmp ? (tmp->head ? tmp->head : tmp) : tmp;
167     }
168    
169     int MapInsertObjectZ(mapstruct *emap,object *o,int x, int y, int z)
170     {
171     object *op, *above, *below;
172    
173     if (o->more)
174     MapInsertObjectZ (emap,o->more, x, y, z);
175    
176     o->x += x;
177     o->y += y;
178     o->map = emap;
179     CLEAR_FLAG(o,FLAG_REMOVED);
180    
181     op = get_map_ob (emap, o->x, o->y);
182     if (z < 0) {
183     above = op;
184     below = NULL;
185     } else {
186     while (op && op->above)
187     op = op->above;
188    
189     above = NULL;
190     below = op;
191     while (op && z-- > 0) {
192     above = op;
193     below = op = op->below;
194     }
195     }
196     o->below = below;
197     o->above = above;
198    
199     if (above)
200     above->below = o;
201     else {
202     SET_MAP_FACE (emap, o->x, o->y, o->face,0);
203     }
204     if (below)
205     below->above = o;
206     else
207     set_map_ob (emap, o->x, o->y, o);
208    
209     return (0);
210     }
211    
212     int MapObjectOut (mapstruct *target, object *obj, int x, int y) {
213     object *tmp;
214     for(tmp = obj; tmp; tmp = tmp->more)
215     if(OUT_OF_REAL_MAP(target,x + tmp->x,y + tmp->y)) return 1;
216     return 0;
217     }
218    
219     object * MapGetObjectZ (mapstruct * emap, int x, int y, int z)
220     {
221     object *op;
222    
223     if (!emap || out_of_map (emap, x, y))
224     return (NULL);
225     op = get_map_ob (emap, x, y);
226     while (op && op->above)
227     op = op->above;
228     while (op && z-- > 0)
229     op = op->below;
230     return (op);
231     }
232    
233    
234    
235    
236     /**********************************************************************
237     * inner declarations
238     **********************************************************************/
239    
240     /*
241     static void CbEditSetPath (Widget w, XtPointer client, XtPointer call);
242     static void EditRefreshCb (Widget w, XtPointer client, XtPointer call);
243     static void CbEditStart (Widget w, XtPointer client, XtPointer call);
244    
245     static void CbEditToggleRead (Widget w, XtPointer client, XtPointer call);
246     static void CbEditToggleOver (Widget w, XtPointer client, XtPointer call);
247     static void CbEditToggleAuto (Widget w, XtPointer client, XtPointer call);
248     */
249     /*
250     static Boolean EdFreeMap ( Edit *);
251     static Boolean Load ( Edit *, char *name );
252     static int EdSelectItem ( Edit *, int x, int y );
253     */
254     static Boolean EdSaveMap (Edit self, char *name);
255     /*
256     static void EditResizeScroll(Edit self,int width,int height,int dx,int dy);
257     */
258     static void EditInsertArch (Edit self, int x, int y, int i, archetype * at);
259    
260     object *EditCloneInsert (Edit self,object *obj,int x, int y, int z);
261     Boolean EditObjectDelete (Edit self, int x, int y, int z);
262    
263     /*
264     * to all refresh
265     */
266     const XRectangle EditRectAll = {
267     0,0,
268     10000,10000
269     };
270    
271     /**********************************************************************
272     * privates
273     **********************************************************************/
274    
275    
276     /*
277     *
278     */
279     static Boolean EdFreeMap (Edit self)
280     {
281     if (!self) return False;
282    
283     /*** no item from self map anymore ***/
284     if (AppItemGetEdit(self->app) == self) {
285     AppItemSet (self->app, NULL,NULL,0);
286     }
287     if(self->app->look.edit == self)
288     AppSelectUnset(self->app);
289     if (self->emap) {
290     *self->emap->path = '\0';
291     free_map (self->emap, 1);
292     delete_map (self->emap);
293     self->emap = NULL;
294     }
295     return True;
296     }
297    
298     /*
299     * member : load map from file to memory
300     * there should no other map loading function for editor
301     * than self
302     * name : filename of map, relative ( level number )
303     * return : True, if map is loaded
304     */
305     static Boolean Load(Edit self, char *name)
306     {
307     int mask;
308     mapstruct *tmp;
309     char path[PATH_MAX+1],save[PATH_MAX+1];
310     char buf[BUFSIZ];
311    
312     strcpy(path, name);
313     if((mask = check_path (path,1)) < 4) {
314     sprintf(buf,"You can't access %s",path);
315     CnvNotify(buf,"Continue",NULL);
316     return False;
317     }
318    
319     /* new map, no refs */
320     if(self->app->look.edit == self) {
321     AppSelectUnset(self->app);
322     AttrChange(self->app->attr,NULL, 0, 0);
323     }
324     /*** remove old mapstructure ***/
325     if(self->emap)
326     strcpy(save,self->emap->path); /* klydge */
327     EdFreeMap (self);
328     if(!(tmp = ready_map_name (path, MAP_FLUSH))) {
329     /* Make the map null, since right now we don't have a valid map
330     * in memory. The CnfNotify call will force a redraw - we
331     * can check for Null map data pretty easy, but can't really check
332     * for unknown map data.
333     */
334     if (self->w) /* only when already a window, open otherwhise coredump */
335     XtVaSetValues(self->w, XtNmap, NULL, NULL);
336     sprintf(buf,"Cannot load map %s",path);
337     CnvNotify(buf,"Continue",NULL);
338     if(!(tmp = ready_map_name(save,MAP_FLUSH))) return False;
339     }
340    
341     /*** initialiaze map ***/
342     debug1("Edit-Load() %s\n",path);
343     if(self->view) XawViewportSetLocation(self->view,0,0);
344     self->emap = tmp;
345     self->read_only = mask & 2 ? 0 : 1;
346     strcpy (self->emap->path, path);
347     EditUnmodified(self);
348     EditUpdate(self);
349     CrEditRefresh(self->w,EditRectAll);
350     return True;
351     }
352    
353     /**********************************************************************
354     * wall handling
355     **********************************************************************/
356    
357     static int direction_x[] = {0, -1, 0, 1};
358     static int direction_y[] = {1, 0, -1, 0};
359    
360     /*
361     *
362     */
363     static int find_draw_arch (mapstruct * emap, int line, archetype * at)
364     {
365     int i;
366     object *tmp;
367    
368     for (i = 0; i < 16; i++)
369     if ((tmp = get_map_ob (emap, i, line)) &&
370     tmp->arch == at)
371     return (i);
372     return (-1);
373     }
374    
375     static void EditInsertArch (Edit self, int x, int y, int i, archetype * at)
376     {
377     Window w;
378     mapstruct *emap;
379     object *op,*tmp;
380     int j = i;
381     XRectangle rect;
382    
383     emap = self->emap;
384     w = XtWindow(self->w);
385     op = get_map_ob (emap, x, y);
386    
387     /* check for duplicate object */
388     while (op && op->above)
389     op = op->above;
390     while (op && j-- > 0)
391     op = op->below;
392     if (op && op->arch == at)
393     return;
394    
395     if (ob_blocked(&at->clone, self->emap, x, y) & P_OUT_OF_MAP) {
396     debug("Out of Map\n");
397     return;
398     }
399     op = object_create_arch (at);
400     if (op) {
401     MapInsertObjectZ(emap,op,x,y,i);
402     /*debug3 ("Inserting %s %d %d\n", op->name, op->x, op->y);*/
403    
404     for (tmp = op; tmp; tmp = tmp->more) {
405     if (self->app->look.rect.x == tmp->x &&
406     self->app->look.rect.y == tmp->y)
407     AppUpdate(self->app);
408     }
409     rect.x = x;
410     rect.y = y;
411     rect.width = rect.height = 1;
412     CrEditRefresh(self->w,rect);
413     } else {
414     free_object (op);
415     debug0 ("Inserting failed\n");
416     }
417    
418     return;
419     }
420    
421     /*
422     * member: hmm
423     */
424     static int update_wall (Edit self, int x, int y, int add, int rem)
425     {
426     int i;
427     object *tmp, *op;
428     Window w;
429     mapstruct * emap;
430    
431     emap = self->emap;
432     w = XtWindow(self->w);
433    
434     if (out_of_map (emap, x, y) || !(op = get_map_ob (emap, x, y)))
435     return False;
436    
437     while (op->above)
438     op = op->above;
439    
440     /*
441     i = find_draw_arch (self->app->item.wall_map,
442     self->app->item.wall_set,
443     op->arch);
444     */
445     i = find_draw_arch (AppItemGetMap(self->app),
446     AppItemGetWall(self->app),
447     op->arch);
448     if (i >= 0) {
449     /* debug4 ("%d | %d & ~%d = %d\n", i, add, rem, (i | add) & ~rem); */
450     remove_ob (op);
451     free_object (op);
452     tmp = get_map_ob (AppItemGetMap(self->app), ((i | add) & ~rem),
453     AppItemGetWall(self->app));
454     if (tmp)
455     EditInsertArch (self, x, y, 0, tmp->arch);
456     return True;
457     }
458     return False;
459     }
460    
461     /*
462     *
463     */
464     static void draw_add (Edit self, int x, int y)
465     {
466     int i, mask = 0;
467    
468     if (!self->app->item.wall_map)
469     CnvDie(self->shell,"No Wall map");
470    
471     if (MAP_WIDTH(self->app->item.wall_map) < 16)
472     CnvDie(self->shell,"Wall Map has wrong width\n");
473    
474     for (i = 0; i < 4; i++)
475     if (update_wall (self, x + direction_x[i], y + direction_y[i],
476     (1 << i), 0))
477     mask |= (1 << (i ^ 2));
478    
479     update_wall (self, x, y, mask, 0);
480     }
481    
482     /*
483     *
484     */
485     static void draw_remove (Edit self, int x, int y)
486     {
487     if (!self->app->item.wall_map)
488     CnvDie(self->shell,"No Wall map");
489    
490     if (MAP_WIDTH(self->app->item.wall_map) < 16)
491     CnvDie(self->shell,"Wall Map has wrong width\n");
492    
493     update_wall (self, x, y + 1, 0, 1);
494     update_wall (self, x - 1, y, 0, 2);
495     update_wall (self, x, y - 1, 0, 4);
496     update_wall (self, x + 1, y, 0, 8);
497     }
498    
499    
500     /*
501     * member: resize and scroll mao of editor
502     * width : new width, if zero, no resize
503     * height: new height, if zero, no resize
504     * dx : amount to scroll, neg. to left, pos. to right
505     * dy : amount to scroll, neg, to up, pos. to down
506     */
507     void EditResizeScroll(Edit self,int width,int height,int dx,int dy)
508     {
509     mapstruct *tmp;
510     char buf[BUFSIZ];
511    
512     if(!self || self->read_only) return;
513     if(self->type != ClipBoard &&
514     (width < MapMinWidth || width > MapMaxWidth ||
515     height < MapMinHeight || height > MapMaxHeight)) {
516     sprintf(buf,"Map cannot be smaller than %dx%d",
517     MapMinWidth,MapMinHeight);
518     CnvNotify(buf,"Continue",NULL);
519     return;
520     }
521    
522    
523     /*
524     * SelectUnset before EdFreeMap, since, it tries to
525     * do that, and there's no mapstuct at that moment
526     */
527     if(self->app->look.edit == self)
528     AppSelectUnset(self->app);
529    
530     tmp = MapMoveScrollResize(self->emap, width, height, dx, dy);
531     self->emap = NULL; /* MapMoveScrollResize destroys the old map */
532     EdFreeMap(self);
533     self->emap = tmp;
534     EditModified(self);
535     EditUpdate(self);
536    
537     CrEditRefresh(self->w,EditRectAll);
538    
539     debug5("EditResizeScroll() %s %dx%d+%d+%d\n",
540     EditGetPath(self),width,height,dx,dy);
541     }
542    
543     /**********************************************************************
544     * File-menu callbacks
545     **********************************************************************/
546    
547     /*
548     * callback: save current map, ask name if not given
549     */
550     static void SaveCb (Widget w, XtPointer client, XtPointer call)
551     {
552     Edit self = (Edit) client;
553     EditSave(self);
554     }
555    
556     /*
557     * callback: save map as name
558     */
559     static void SaveAsCb (Widget w, XtPointer client, XtPointer call)
560     {
561     Edit self = (Edit) client;
562     char path[PATH_MAX];
563    
564     if(CnvPathSelect(self->app->path) == CnvPathCancel) return;
565     sprintf(path,"%s/%s",
566     self->app->path->current,
567     self->app->path->filename);
568     EdSaveMap(self,path);
569     }
570    
571     /*
572     * callback: load current map again
573     */
574     static void ClearCb (Widget w, XtPointer client, XtPointer call)
575     {
576     Edit self = (Edit) client;
577     Map tmp;
578    
579     debug1("ClearCb() %s\n",self->emap->path);
580     if(self->read_only) return;
581     tmp = get_empty_map(MAP_WIDTH(self->emap), MAP_HEIGHT(self->emap));
582     copy_map (self->emap, tmp);
583     EdFreeMap(self);
584     self->emap = tmp;
585     EditUnmodified(self);
586     EditUpdate(self);
587     }
588    
589     /*
590     * callback: load new map
591     */
592     static void LoadCb (Widget w, XtPointer client, XtPointer call)
593     {
594     Edit self = (Edit) client;
595     char path[PATH_MAX+1],buf[BUFSIZ];
596    
597     /*** save, if modified ***/
598     if (self->modified) {
599     switch (CnvNotify ("Map modified, save",
600     "OK","Cancel","No",NULL)) {
601     case 1:
602     EditSave(self);
603     break;
604     case 2:
605     return;
606     default:
607     break;
608     }
609     }
610     /*** load map ***/
611     if(CnvPathSelect(self->app->path) == CnvPathCancel) return;
612     sprintf(path,"%s/%s",self->app->path->current,self->app->path->filename);
613     /*** check out if map can load ***/
614     if (has_been_loaded (path)) {
615     sprintf(buf,"%s already in memory",path);
616     CnvNotify(buf,"Continue",NULL);
617     return;
618     }
619     Load(self,path);
620     }
621    
622     /*
623     * callback: load current map again
624     */
625     static void ReloadCb (Widget w, XtPointer client, XtPointer call)
626     {
627     Edit self = (Edit) client;
628     debug1("ReloadCb() %s\n",self->emap->path);
629     Load(self,self->emap->path);
630     }
631    
632     /*
633     * callback: enter to map in Look window
634     */
635     static void EnterCb (Widget w, XtPointer client, XtPointer call)
636     {
637     Edit self = (Edit) client;
638     object *obj = NULL, *tmp;
639     char buf[BUFSIZ];
640     char loadPath[PATH_MAX+1];
641     const char *path;
642     XRectangle rect;
643    
644     /*** find object ***/
645     if(self->app->look.edit)
646     obj = MapGetObjectZ
647     (self->app->look.edit->emap,
648     self->app->look.rect.x,
649     self->app->look.rect.y,0);
650     if (!obj || !self->app->look.edit) {
651     CnvNotify("Select exit to enter","Continue",NULL);
652     return;
653     }
654     /*** foreach object in list, if exit load it ***/
655     tmp = obj;
656     do {
657     obj = tmp->head ? tmp->head : tmp;
658     if (obj->type == PLAYER_CHANGER || obj->type == TELEPORTER || obj->type==EXIT) {
659     /*** check out if exit leads ***/
660     if(!EXIT_PATH(obj)) {
661     CnvNotify("Exit leads nowhere",
662     "OK",NULL);
663     return;
664     }
665     path = EXIT_PATH(obj);
666     rect.x = EXIT_X(obj);
667     rect.y = EXIT_Y(obj);
668     /*** save current map if modified ***/
669     if (self->modified) {
670     switch (CnvNotify ("Map modified, save",
671     "Save","Cancel","Forget",NULL)) {
672     case 1:
673     EditSave(self);
674     break;
675     case 2:
676     return;
677     default:
678     break;
679     }
680     }
681     /*** load & update ***/
682     StrPathCd(strcpy(loadPath,EditGetPath(self)),path);
683     debug1("EnterCb() %s\n",loadPath);
684    
685     /*** check out if map can load ***/
686     if (has_been_loaded (loadPath)) {
687     sprintf(buf,"%s already in memory",loadPath);
688     CnvNotify(buf,"Continue",NULL);
689     return;
690     }
691     if(!Load(self,loadPath)) return;
692     if (rect.x == 0 && rect.y == 0) {
693     rect.x = MAP_ENTER_X(self->emap);
694     rect.y = MAP_ENTER_Y(self->emap);
695     }
696     rect.width = rect.height = 0;
697     AppSelectSet(self->app, self, rect);
698     CrEditSelect(self->w, rect);
699     return;
700     }
701     tmp = tmp->below;
702     } while(tmp);
703     CnvNotify("That's not exit","Continue",NULL);
704     }
705    
706     /*
707     * callback: reset this map from crossfire
708     */
709     static void ResetCb (Widget w, XtPointer client, XtPointer call)
710     {
711     Edit self = (Edit) client;
712     char cmd[ARG_MAX+1],buf[MAX_INPUT+1];
713    
714     debug0("ResetCb()\n");
715     if(!self->app->res.cmdReset) {
716     CnvNotify("no defined *cmdReset:","Continue",NULL);
717     return;
718     }
719     sprintf(cmd,self->app->res.cmdReset,EditGetPath(self));
720     if(system(cmd)) {
721     sprintf(buf,"Command failed \"%s\"",cmd);
722     CnvNotify(buf,"Continue",NULL);
723     }
724     }
725    
726     /*
727     * callback: quit map editor
728     */
729     static void CloseCb (Widget w, XtPointer client, XtPointer call)
730     {
731     char buf[BUFSIZ];
732     Edit self = (Edit) client;
733     if (EditIsModified(self)) {
734     sprintf (buf, "Quitting, save %s ?", self->emap->path);
735     switch (CnvNotify (buf,"Save","Cancel", "Forget",NULL)) {
736     case 1: /* ok */
737     EditSave(self);
738     break;
739     case 2:
740     return;
741     default:
742     EditUnmodified(self); /* to fool EditDestroy */
743     break;
744     }
745     }
746     EditDestroy(self);
747     }
748    
749     static CnvMenuRec fileMenu[] = {
750     {"save", SaveCb},
751     {"saveAs", SaveAsCb},
752     {"----", NULL},
753     {"load", LoadCb},
754     {"reload", ReloadCb},
755     {"----", NULL},
756     {"clear", ClearCb},
757     {"reset", ResetCb},
758     {"----", NULL},
759     {"enter", EnterCb},
760     {"----", NULL},
761     {"close", CloseCb},
762     {"", NULL },
763     };
764    
765     /**********************************************************************
766     * Auto Creating stuff
767     **********************************************************************/
768    
769     static char * MapMessageCreate (App self) {
770     char buf[MAX_BUF];
771     time_t t = time(NULL);
772     sprintf (buf, "Creator: %s\nEmail: %s\nDate: %s",
773     self->res.creator,self->res.email, ctime (&t));
774     return strdup_local (buf);
775     }
776    
777     #if 0
778     static char * MapNameCreate (String path)
779     {
780     char name[PATH_MAX+1];
781     int i,j;
782    
783     strncpy(name,path,PATH_MAX);
784     name[PATH_MAX] = '\0';
785     for(i = strlen(name)-1; i && name[i] != '/';i--);
786     i++;
787     for(j = i; name[j] && name[j] != '.';j++);
788     if(name[j] == '.') name[j] = 0;
789     return strdup_local (&name[i]);
790     }
791     #endif
792     /**********************************************************************
793     * Options - menu
794     **********************************************************************/
795    
796    
797     #if 0
798     /*
799     * callback: set new path of map
800     */
801     static void SetPathCb (Widget w, XtPointer client, XtPointer call)
802     {
803     char path[CnvPromptMax+1];
804     Edit self = (Edit) client;
805    
806     switch (CnvPrompt ("Set path", self->emap->path, path,
807     "OK","Cancel",NULL)) {
808     case 1:
809     EditSetPath(self,path);
810     default:
811     break;
812     }
813     }
814    
815     /*
816     * callback: resize and scroll map
817     */
818     static void ResizeCb (Widget w, XtPointer client, XtPointer call)
819     {
820     Edit self = (Edit) client;
821     char buf[1025], path[CnvPromptMax+1];
822     unsigned x, y;
823     int sx = 0, sy = 0, res;
824    
825     if (self->read_only)
826     return;
827    
828     sprintf (buf, "%dx%d+0+0",
829     MAP_WIDTH(self->emap), MAP_HEIGHT(self->emap));
830     switch (CnvPrompt ("ResizeScroll",
831     buf, path,"OK",NULL)) {
832     case 1:
833     res = XParseGeometry (path, &sx, &sy, &x, &y);
834    
835     if (!(res & WidthValue))
836     x = MAP_WIDTH(self->emap);
837     if (!(res & HeightValue))
838     y = MAP_HEIGHT(self->emap);
839    
840     if (!(res & XValue))
841     sx = 0;
842     if (!(res & YValue))
843     sy = 0;
844    
845     if (x < 3 || y < 3 || x > 100 || y > 100) {
846     CnvNotify ("Illegal size","OK",NULL);
847     return;
848     }
849     EditResizeScroll (self, x,y,sx, sy);
850     break;
851     default:
852     return;
853     }
854     }
855    
856     /*
857     * callback: set start point
858     */
859     static void StartCb (Widget w, XtPointer client, XtPointer call)
860     {
861     Edit self = (Edit) client;
862     char buf[BUFSIZ], reply[CnvPromptMax+1];
863     int x, y, flags;
864     int width, height;
865    
866     sprintf (buf, "%dx%d",
867     MAP_ENTER_X(self->emap),
868     MAP_ENTER_Y(self->emap));
869     switch (CnvPrompt ("Start of map", buf,reply,
870     "OK","Cancel",NULL)) {
871     case 1: /* ok */
872     flags = XParseGeometry (reply, &x, &y, &width, &height);
873     if ((flags != (WidthValue | HeightValue))) {
874     CnvNotify ( "Illegal value","Ok",NULL);
875     return;
876     }
877     if (out_of_map(self->emap,width,height)) {
878     sprintf (buf, "Point %dx%d out of map", width, height);
879     CnvNotify (buf,"OK",NULL);
880     return;
881     } else {
882     MAP_ENTER_X(self->emap) = width;
883     MAP_ENTER_Y(self->emap) = height;
884     EditModified(self);
885     }
886     EditUpdate(self);
887     return;
888     default:
889     return;
890     }
891     }
892     #endif
893    
894    
895    
896     /*
897     * Edit attributes of the Map
898     */
899     static void AttributesCb (Widget w, XtPointer client, XtPointer call)
900     {
901     Edit self = (Edit)client;
902    
903     debug0("Edit::AttributesCb()\n");
904    
905     if (self->mapattr == NULL) {
906     self->mapattr = MapAttrCreate(self->emap, self->app, self);
907     } else {
908     MapAttrDestroy(self->mapattr);
909     }
910     }
911    
912     /*
913     * callback: refresh map
914     */
915     static void RefreshCb (Widget w, XtPointer client, XtPointer call)
916     {
917     Edit self = (Edit)client;
918     CrEditRefresh(self->w,EditRectAll);
919     EditUpdate(self);
920     }
921    
922     #if 0
923     /*
924     * callback: toggle write accces
925     */
926     static void ToggleReadCb (Widget w, XtPointer client, XtPointer call)
927     {
928     Edit self = (Edit)client;
929    
930     if(self->type == Pick ||
931     self->type == Wall) return;
932     ((Edit) client)->read_only++;
933     EditUpdate(self);
934     debug ("CbEditToggleRead()\n");
935     }
936     #endif
937    
938     /*
939     * callback: Toggle overwrite mode
940     */
941     static void ToggleOverCb (Widget w, XtPointer client, XtPointer call)
942     {
943     Edit self = (Edit)client;
944    
945     if(self->type == Pick ||
946     self->type == Wall) return;
947     ((Edit) client)->overwrite++;
948     EditUpdate(self);
949     debug ("CbEditToggleOver()\n");
950     }
951    
952     /*
953     * callback: Toggle auto choose
954     */
955     static void ToggleAutoCb (Widget w, XtPointer client, XtPointer call)
956     {
957     Edit self = (Edit)client;
958    
959     if(self->type == Pick ||
960     self->type == Wall) return;
961     ((Edit) client)->auto_choose++;
962     EditUpdate(self);
963     debug ("CbEditToggleAuto()\n");
964     }
965    
966     /*
967     * callback: Toggle showing weak walls
968     */
969     static void ToggleWeakCb (Widget w, XtPointer client, XtPointer call)
970     {
971     Edit self = (Edit)client;
972     Cardinal weak_walls;
973    
974     XtVaGetValues(self->w, XtNshow_weak_walls, &weak_walls, NULL);
975     XtVaSetValues(self->w, XtNshow_weak_walls, !weak_walls, NULL);
976    
977     EditUpdate(self);
978     debug("CbEditToggleWeak()\n");
979     }
980    
981     /*
982     * callback: Adjust stacking size
983     */
984     static void SetStackingCb(Widget w, XtPointer client, XtPointer call)
985     {
986     char buf[MAX_BUF];
987     char retbuf[CnvPromptMax+1];
988     Edit self = (Edit)client;
989     Cardinal stacking;
990     int ret;
991    
992     XtVaGetValues(self->w, XtNstacking, &stacking, NULL);
993    
994     snprintf(buf, sizeof(buf), "%d", stacking);
995    
996     ret = CnvPrompt("Set stacking (0 = off)", buf, retbuf, "OK", "Cancel", NULL);
997    
998     if (ret != 1)
999     return;
1000    
1001     stacking = atoi(retbuf);
1002    
1003     debug2("SetStackingCb %s %d\n", retbuf, stacking);
1004    
1005     /* TODO How did they come up with this magic number? */
1006     if (stacking > 48) {
1007     CnvNotify("Illegal space", "Ok", NULL);
1008     return;
1009     }
1010     XtVaSetValues(self->w, XtNstacking, stacking, NULL);
1011    
1012     EditUpdate(self);
1013     }
1014    
1015     static Widget OptionMenu(String name,Edit self,Widget parent)
1016     {
1017     Widget shell,refresh, use;
1018    
1019     shell = XtVaCreatePopupShell
1020     (name, simpleMenuWidgetClass, parent, NULL);
1021    
1022     use = XtVaCreateManagedWidget
1023     ("attributes",smeBSBObjectClass, shell,
1024     NULL);
1025     XtAddCallback(use,XtNcallback,AttributesCb,(XtPointer)self);
1026    
1027     /*** refresh ***/
1028     XtVaCreateManagedWidget ("line", smeLineObjectClass, shell, NULL);
1029     refresh = XtVaCreateManagedWidget
1030     ("refresh",smeBSBObjectClass,shell,
1031     NULL);
1032     XtAddCallback
1033     (refresh,XtNcallback,RefreshCb,(XtPointer)self);
1034     /*** toggles ***/
1035     XtVaCreateManagedWidget ("line", smeLineObjectClass, shell, NULL);
1036     self->iw.overwrite = XtVaCreateManagedWidget
1037     ("overWrite", smeBSBObjectClass, shell, NULL);
1038     XtAddCallback (self->iw.overwrite,
1039     XtNcallback,ToggleOverCb, (XtPointer) self);
1040     self->iw.auto_choose = XtVaCreateManagedWidget
1041     ("autoChoose", smeBSBObjectClass, shell, NULL);
1042     XtAddCallback (self->iw.auto_choose,
1043     XtNcallback,ToggleAutoCb, (XtPointer) self);
1044     self->iw.weak_walls = XtVaCreateManagedWidget
1045     ("weakWalls", smeBSBObjectClass, shell, NULL);
1046     XtAddCallback (self->iw.weak_walls,
1047     XtNcallback,ToggleWeakCb, (XtPointer) self);
1048     self->iw.stacking = XtVaCreateManagedWidget
1049     ("sparse", smeBSBObjectClass, shell, NULL);
1050     XtAddCallback (self->iw.stacking,
1051     XtNcallback,SetStackingCb, (XtPointer) self);
1052    
1053     return shell;
1054     }
1055    
1056     /**********************************************************************
1057     * edit routines - CrEdit callbacks
1058     * insert
1059     * select
1060     * delete
1061     * align
1062     * feed
1063     **********************************************************************/
1064    
1065     static void InsertCb(Widget w,XtPointer clientData,XtPointer callData)
1066     {
1067     Edit self = (Edit)clientData;
1068     CrEditCall call = (CrEditCall)callData;
1069     AppSelectUnset(self->app);
1070     EditInsert(self,call->rect.x,call->rect.y,call->z);
1071     }
1072    
1073     static void SelectCb(Widget w,XtPointer clientData,XtPointer callData)
1074     {
1075     Edit self = (Edit)clientData;
1076     CrEditCall call = (CrEditCall)callData;
1077     if(self->auto_choose) {
1078     if(self->type == Wall && call->rect.x == 0) {
1079     AppItemSet(self->app,self,NULL,call->rect.y);
1080     } else {
1081     object *obj;
1082     obj = MapGetRealObject(self->emap,call->rect.x,call->rect.y,0);
1083     AppItemSet(self->app,self,obj,AppItemNoWall);
1084     }
1085     } else {
1086     AppSelectSet(self->app,self,call->rect);
1087     }
1088     }
1089    
1090     static void PropsCb(Widget w,XtPointer clientData,XtPointer callData)
1091     {
1092     Edit self = (Edit)clientData;
1093     CrEditCall call = (CrEditCall)callData;
1094     debug0 ("PropsCb()\n");
1095     if(!self->auto_choose) {
1096     object *ob = MapGetRealObject
1097     (self->emap, call->rect.x, call->rect.y, call->z);
1098     if(!self->app->attr) {
1099     self->app->attr = AttrCreate
1100     ("attr", self->app, ob, AttrDescription, GetType(ob), self);
1101     } else {
1102     AttrChange (self->app->attr,ob, GetType(ob), self);
1103     }
1104     }
1105     return;
1106     }
1107    
1108     static void DeleteCb(Widget w,XtPointer clientData,XtPointer callData)
1109     {
1110     Edit self = (Edit)clientData;
1111     CrEditCall call = (CrEditCall)callData;
1112     AppSelectUnset(self->app);
1113     EditDelete(self,call->rect.x,call->rect.y,call->z);
1114     }
1115    
1116     static void AlignCb(Widget w,XtPointer clientData,XtPointer callData)
1117     {
1118     Edit self = (Edit)clientData;
1119     CrEditCall call = (CrEditCall)callData;
1120     debug4("Edit::AlignCb() by %dx%d+%d+%d\n",call->rect.width,
1121     call->rect.height,call->rect.x,call->rect.y);
1122     EditResizeScroll(self,call->rect.width,
1123     call->rect.height,call->rect.x,call->rect.y);
1124     }
1125    
1126     static void FeedCb(Widget w,XtPointer clientData,XtPointer callData)
1127     {
1128     Edit self = (Edit)clientData;
1129     CrEditCall call = (CrEditCall)callData;
1130     char buf[BUFSIZ],*str;
1131    
1132     debug("FeedCb()\n");
1133     /*** path, modified for game, not clean thing ***/
1134     str = buf;
1135     if (!self->app->attr || !self->app->attr->op)
1136     return;
1137     if(!strcmp(self->app->attr->op->map->path,call->map->path)) {
1138     StrBasename(buf,self->app->attr->op->map->path);
1139     } else {
1140     strcpy(buf,self->app->attr->op->map->path);
1141     StrPathGenCd(buf,call->map->path);
1142     if(strlen(buf) > 2) str = &buf[2];
1143     }
1144     XtVaSetValues (self->app->attr->tags[I_Path].value,
1145     XtNstring, str,
1146     NULL);
1147     /*** x ***/
1148     sprintf (buf, "%d", call->rect.x);
1149     XtVaSetValues (self->app->attr->tags[I_X].value,
1150     XtNstring, buf,
1151     NULL);
1152     /*** y ***/
1153     sprintf (buf, "%d", call->rect.y);
1154     XtVaSetValues (self->app->attr->tags[I_Y].value,
1155     XtNstring, buf,
1156     NULL);
1157     }
1158    
1159     /**********************************************************************
1160     * layout
1161     **********************************************************************/
1162    
1163     static void Layout(Edit self,Widget parent,Cardinal stacking)
1164     {
1165     Widget vbox, hbox,use;
1166     Widget editMenu, optionMenu;
1167    
1168     /*** shell ***/
1169     self->shell = XtVaCreatePopupShell
1170     ("edit",topLevelShellWidgetClass, self->app->shell,
1171     XtNwidth,
1172     (MAP_WIDTH(self->emap) > self->app->res.mapWidth ?
1173     self->app->res.mapWidth * FontSize :
1174     MAP_WIDTH(self->emap) * FontSize ) + 16,/* kludge */
1175     XtNheight,
1176     (MAP_HEIGHT(self->emap) > self->app->res.mapHeight ?
1177     self->app->res.mapHeight * FontSize :
1178     MAP_HEIGHT(self->emap) * FontSize ) + 46,/* kludge */
1179     XtNiconPixmap,bitmaps.edit,
1180     NULL);
1181     vbox = XtVaCreateManagedWidget ("vbox", panedWidgetClass,
1182     self->shell, NULL);
1183    
1184     /*** menu bar ***/
1185     hbox = XtVaCreateManagedWidget ("hbox", boxWidgetClass,
1186     vbox, NULL);
1187    
1188     if(self->type != ClipBoard) {
1189     use = XtVaCreateManagedWidget
1190     ("mapFileButton", menuButtonWidgetClass, hbox,
1191     XtNmenuName,"fileMenu",
1192     NULL);
1193     CnvMenu("fileMenu",use,fileMenu,(XtPointer)self);
1194    
1195     editMenu = XtVaCreateManagedWidget
1196     ("mapEditButton", menuButtonWidgetClass, hbox,
1197     XtNmenuName,"mapEdit",
1198     NULL);
1199    
1200     optionMenu = XtVaCreateManagedWidget
1201     ("mapOptionButton", menuButtonWidgetClass, hbox,
1202     XtNmenuName,"optionMenu",
1203     NULL);
1204     OptionMenu("optionMenu",self,optionMenu);
1205     }
1206    
1207    
1208     /*** editor-widget ***/
1209     self->view = XtVaCreateManagedWidget
1210     ("veivi",viewportWidgetClass, vbox,
1211     XtNallowResize,True,
1212     XtNforceBars,True,
1213     XtNallowHoriz,True,
1214     XtNallowVert,True,
1215     NULL);
1216     self->w = XtVaCreateManagedWidget
1217     ("cross",crEditWidgetClass,self->view,
1218     XtNresizable,True,
1219     XtNmap,self->emap,
1220     XtNstacking,stacking,
1221     XtNselectArea,True,
1222     NULL);
1223     XtAddCallback(self->w,XtNinsertCallback,InsertCb,(XtPointer)self);
1224     XtAddCallback(self->w,XtNselectCallback,SelectCb,(XtPointer)self);
1225     XtAddCallback(self->w,XtNpropsCallback,PropsCb,(XtPointer)self);
1226     XtAddCallback(self->w,XtNdeleteCallback,DeleteCb,(XtPointer)self);
1227     XtAddCallback(self->w,XtNalignCallback,AlignCb,(XtPointer)self);
1228     XtAddCallback(self->w,XtNfeedCallback,FeedCb,(XtPointer)self);
1229     }
1230    
1231     /**********************************************************************
1232     * public
1233     **********************************************************************/
1234    
1235     /*
1236     * create editing window for map for crossfire-abs-path file-name
1237     */
1238     Edit EditCreate(App app,EditType type,String path)
1239     {
1240     Edit self;
1241    
1242     /*** initialising ***/
1243     self = (Edit)XtMalloc(sizeof(struct _Edit));
1244     self->app = app;
1245     self->shell = NULL;
1246     self->w = NULL;
1247     self->view = NULL;
1248     self->next = NULL;
1249     self->emap = NULL;
1250     self->type = type;
1251     self->overwrite = 0;
1252     self->mapattr = NULL;
1253     self->modified = False;
1254    
1255     /*** load or create map ***/
1256     if (type == ClipBoard) {
1257     if (!self->emap)
1258     self->emap = get_empty_map(MapMinWidth,MapMinHeight);
1259     strcpy (self->emap->path, "/ClipBoard");
1260    
1261     if (!self->emap->msg) {
1262     self->emap->msg = MapMessageCreate (app);
1263     }
1264     } else if(path && *path != '\0') {
1265     if (!Load(self,path)) return 0;
1266     } else {
1267     self->emap = get_empty_map(16,16);
1268     strcpy (self->emap->path, "/Noname");
1269    
1270     if (!self->emap->msg) {
1271     self->emap->msg = MapMessageCreate (app);
1272     }
1273     }
1274    
1275     if (!self->emap)
1276     return 0;
1277    
1278     /*** creating ***/
1279     Layout(self,self->app->shell,0);
1280     EditUnmodified(self);
1281    
1282     /*** type specific ***/
1283     switch (self->type) {
1284     case Regular:
1285     self->read_only = 0;
1286     self->auto_choose = 0;
1287     break;
1288     case Pick:
1289     case Wall:
1290     self->read_only = 1;
1291     self->auto_choose = 1;
1292     XtVaSetValues(self->w,
1293     XtNstacking,1,
1294     XtNselectArea,False,
1295     NULL);
1296     break;
1297     case ClipBoard:
1298     self->read_only = 0;
1299     self->auto_choose = 0;
1300     break;
1301     default:
1302     fprintf(stderr,"unknown MapType");
1303     exit(EXIT_FAILURE);
1304     }
1305     EditUpdate(self);
1306     /*** show-map-editor ***/
1307     if(type != ClipBoard)
1308     XtPopup (self->shell, XtGrabNone);
1309    
1310     return self;
1311     }
1312    
1313     /*
1314     * member: destroy edit
1315     */
1316     void EditDestroy(Edit self)
1317     {
1318     char buf[BUFSIZ];
1319    
1320     if(!self) return;
1321     debug1 ("EditDestroy() %s\n",EditGetPath(self));
1322    
1323     /*** reply to save if designed ***/
1324     if (EditIsModified(self)) {
1325     sprintf (buf, "Quitting, save %s ?", self->emap->path);
1326     switch (CnvNotify (buf,"Save","Forget",NULL)) {
1327     case 1: /* ok */
1328     EditSave(self);
1329     break;
1330     default:
1331     break;
1332     }
1333     }
1334     /*** outer coonections ***/
1335     if (self->mapattr) {
1336     MapAttrDestroy(self->mapattr);
1337     }
1338     if (self->app->attr && self->app->attr->op &&
1339     self->app->attr->op->map == self->emap) {
1340     AttrChange(self->app->attr, NULL, 0, (Edit)0);
1341     }
1342     if (AppItemGetEdit(self->app) == self) {
1343     AppItemSet (self->app, NULL,NULL,0);
1344     }
1345     AppUpdate(self->app);
1346     AppEditDeattach(self->app,self);
1347     EdFreeMap (self);
1348    
1349     /*** inner remove ***/
1350     XtDestroyWidget (self->shell);
1351     XtFree((char*)self);
1352     }
1353    
1354     /*
1355     * member: update Edit values
1356     */
1357     void EditUpdate(Edit self)
1358     {
1359     char buf[BUFSIZ];
1360    
1361     if(!(self && self->shell && self->emap)) return;
1362    
1363     /*** map title ***/
1364     snprintf(buf, sizeof(buf),
1365     "Edit %s %s",
1366     self->emap->path,
1367     self->modified ? "*" : "");
1368     XtVaSetValues(self->shell,
1369     XtNtitle,buf,
1370     XtNiconName,buf,
1371     NULL);
1372    
1373     /*** info ***/
1374     if (self->mapattr != NULL)
1375     MapAttrChange(self->mapattr, self->emap);
1376    
1377     /*** toggles ***/
1378     if(self->type != ClipBoard) {
1379     Cardinal weak_walls;
1380     Cardinal stacking;
1381    
1382     #if 0
1383     XtVaSetValues
1384     (self->iw.read_only,
1385     XtNleftBitmap, self->read_only ? bitmaps.mark : None, NULL);
1386     #endif
1387     XtVaSetValues
1388     (self->iw.overwrite,
1389     XtNleftBitmap, self->overwrite ? bitmaps.mark : None, NULL);
1390     XtVaSetValues
1391     (self->iw.auto_choose,
1392     XtNleftBitmap, self->auto_choose ? bitmaps.mark : None,
1393     NULL);
1394    
1395     XtVaGetValues(self->w, XtNshow_weak_walls, &weak_walls, NULL);
1396     XtVaSetValues
1397     (self->iw.weak_walls,
1398     XtNleftBitmap, weak_walls ? bitmaps.mark : None,
1399     NULL);
1400    
1401     XtVaGetValues(self->w, XtNstacking, &stacking, NULL);
1402     XtVaSetValues
1403     (self->iw.stacking,
1404     XtNleftBitmap, (stacking != 0) ? bitmaps.mark : None,
1405     NULL);
1406     }
1407     /*** map area ***/
1408     if(self->emap && self->w)
1409     XtVaSetValues(self->w,XtNmap,self->emap,NULL);
1410    
1411     if (self->app->look.edit == self)
1412     CrEditRefresh (self->w, self->app->look.rect);
1413     }
1414    
1415     /*
1416     * member : save map from memory to file, there should be no other
1417     * map saving routine than self
1418     * self : pointer to current Edit structure
1419     * name : filename of map, relative ( level number ) ???
1420     * return : True, map is saved
1421     */
1422     static Boolean EdSaveMap (Edit self, char *name)
1423     {
1424     mapstruct *m = self->emap;
1425     char buf[BUFSIZ];
1426    
1427     debug0 ("Saving Map by name\n");
1428    
1429     strcpy (m->path, name);
1430    
1431     /*** updating map name here ***/
1432     EditSetPath(self,name);
1433     if(new_save_map (m, 1)) {
1434     sprintf(buf,"Error in saving map %s",EditGetPath(self));
1435     CnvNotify ("Error in saving map !","OK",NULL);
1436     return False;
1437     }
1438     EditUnmodified(self);
1439     return True;
1440     }
1441    
1442     /*
1443     * member: save contents of map to file
1444     * return: status
1445     */
1446     EditReturn EditSave(Edit self)
1447     {
1448     char path[PATH_MAX+1];
1449    
1450     if (self->read_only) {
1451     CnvNotify ( "Map is read-only!","OK",NULL);
1452     return EditOk;
1453     }
1454     if (!self->modified) {
1455     CnvNotify ( "No changes to save", "OK",NULL);
1456     return EditOk;
1457     }
1458     /*** if empty path, ask it ***/
1459     if (!*self->emap->path) {
1460     if(CnvPathSelect(self->app->path) == CnvPathCancel) return EditOk;
1461     sprintf(path,"%s/%s",self->app->path->current,
1462     self->app->path->filename);
1463     strcpy (self->emap->path, path);
1464     }
1465     if(!EdSaveMap(self,self->emap->path)) return EditOk;
1466     EditUpdate(self);
1467     return EditOk;
1468     }
1469    
1470     /*
1471     * member: load map from file
1472     * self : pointer to current Edit structure
1473     * return : status
1474     */
1475     EditReturn EditLoad(Edit self)
1476     {
1477     if(Load(self, self->emap->path))
1478     return EditOk;
1479     else
1480     return EditError;
1481     }
1482    
1483     /*
1484     * member: make fill
1485     * x,y : point to start fill
1486     */
1487     void EditPerformFill(Edit self, int x, int y)
1488     {
1489     int dx, dy;
1490     if (!self->emap) return;
1491    
1492     for (dx=x; dx< x+self->app->look.rect.width; dx++) {
1493     for (dy=y; dy < y+self->app->look.rect.height; dy++) {
1494     if (!OUT_OF_REAL_MAP (self->emap, dx, dy))
1495     EditInsert(self, dx, dy, 0);
1496     }
1497     }
1498     }
1499    
1500     /*
1501     * member: make fill
1502     * x,y : point to start fill
1503     */
1504     void EditPerformFillBelow(Edit self, int x, int y)
1505     {
1506     int dx, dy;
1507     if (!self->emap) return;
1508    
1509     for (dx=x; dx< x+self->app->look.rect.width; dx++) {
1510     for (dy=y; dy < y+self->app->look.rect.height; dy++) {
1511     if (!OUT_OF_REAL_MAP (self->emap, dx, dy))
1512     EditInsert(self, dx, dy, -1);
1513     }
1514     }
1515     }
1516    
1517     /*
1518     * member: fill
1519     * x,y : point to start fill
1520     */
1521     void EditFillRectangle(Edit self, XRectangle rec)
1522     {
1523     int x,y;
1524    
1525     if (!self->emap || self->read_only)
1526     return;
1527    
1528     for(x = 0; x < rec.width; x++)
1529     for(y = 0; y < rec.height; y++)
1530     EditInsert (self, x + rec.x, y + rec.y, 0);
1531    
1532     return;
1533     }
1534    
1535    
1536     /*
1537     * member: wipe
1538     * x,y : point to start fill
1539     */
1540     void EditWipeRectangle(Edit self, XRectangle rec)
1541     {
1542     int x,y;
1543    
1544     if (!self || !self->emap || self->read_only)
1545     return;
1546    
1547     for(x=0; x < rec.width; x++)
1548     for(y=0; y < rec.height; y++)
1549     while(get_map_ob(self->emap,x + rec.x, y + rec.y))
1550     EditObjectDelete (self, x + rec.x, y + rec.y, 0);
1551     CrEditRefresh (self->w, rec);
1552     return;
1553     }
1554    
1555     /*
1556     * member: shave
1557     * x,y : point to start fill
1558     */
1559     void EditShaveRectangle(Edit self, XRectangle rec)
1560     {
1561     int x,y;
1562    
1563     if (!self || !self->emap || self->read_only)
1564     return;
1565    
1566     for(x=0; x < rec.width; x++)
1567     for(y=0; y < rec.height; y++)
1568     EditObjectDelete (self, x + rec.x, y + rec.y, 0);
1569    
1570     CrEditRefresh (self->w, rec);
1571     return;
1572     }
1573    
1574     void EditShaveRectangleBelow(Edit self, XRectangle rec)
1575     {
1576     int x,y;
1577    
1578     if (!self || !self->emap || self->read_only)
1579     return;
1580    
1581     for(x=0; x < rec.width; x++)
1582     for(y=0; y < rec.height; y++)
1583     EditObjectDelete (self, x + rec.x, y + rec.y, -1);
1584    
1585     CrEditRefresh (self->w, rec);
1586     return;
1587     }
1588    
1589     /*
1590     * member: copy rectangle area (x,y,width,height) from src to
1591     * self to point (x,y)
1592     */
1593     void EditCopyRectangle(Edit self,Edit src,XRectangle rect,int sx,int sy)
1594     {
1595     int x, y, z;
1596     object *obj,*tmp;
1597    
1598     if(!self ||
1599     !src ||
1600     self->read_only)
1601     return;
1602    
1603     if (rect.width > MAP_WIDTH(self->emap) - sx)
1604     rect.width = MAP_WIDTH(self->emap) - sx;
1605     if (rect.width > MAP_WIDTH(src->emap))
1606     rect.width = MAP_WIDTH(src->emap);
1607    
1608     if (rect.height > MAP_HEIGHT(self->emap) - sy)
1609     rect.height = MAP_HEIGHT(self->emap);
1610     if (rect.height > MAP_HEIGHT(src->emap))
1611     rect.height = MAP_HEIGHT(src->emap);
1612    
1613     debug2("EditCopyRectangle() %s -> %s\n",EditGetPath(src),
1614     EditGetPath(self));
1615     if(self->overwrite)
1616     for(x=0; x < rect.width; x++)
1617     for(y=0; y < rect.height; y++)
1618     EditDeletePoint(self,(sx+x),(sy+y));
1619    
1620     for(x=0; x < rect.width; x++)
1621     for(y=0; y < rect.height; y++) {
1622     obj = MapGetObjectZ(src->emap,(rect.x + x),(rect.y + y),0);
1623     for(tmp = obj,z=0; tmp; tmp = tmp->below,z++) {
1624     if(tmp->head) {continue;}
1625     /*EditObjectInsert(self,tmp,(sx+x),(sy+y),z);*/
1626     EditCloneInsert(self,tmp,(sx+x),(sy+y),z);
1627     }
1628     }
1629     rect.x = sx;
1630     rect.y = sy;
1631     CrEditRefresh (self->w, rect);
1632     EditModified(self);
1633     }
1634    
1635     /*
1636     *
1637     */
1638     void EditDeletePoint(Edit self,int x,int y)
1639     {
1640     while(get_map_ob(self->emap,x,y))
1641     EditDelete(self,x,y,0);
1642     }
1643    
1644     /*
1645     * Member: set Edit to modified state
1646     */
1647     void EditModified(Edit self)
1648     {
1649     if (self && !self->modified) {
1650     self->modified = True;
1651     EditUpdate(self);
1652     }
1653     }
1654    
1655     /*
1656     * member: set Edit to modified state
1657     */
1658     void EditUnmodified(Edit self)
1659     {
1660     if (self && self->modified) {
1661     self->modified = False;
1662     EditUpdate(self);
1663     }
1664     }
1665    
1666     static void EditObjectCalc(Edit self,object *obj,XRectangle *rect)
1667     {
1668     object *tmp;
1669    
1670     rect->x = 10000;
1671     rect->y = 10000;
1672     rect->width = 0;
1673     rect->height = 0;
1674     for (tmp = obj; tmp; tmp = tmp->more) {
1675     if (self->app->look.rect.x == tmp->x &&
1676     self->app->look.rect.y == tmp->y)
1677     AppUpdate(self->app);
1678     if(tmp->x < rect->x) rect->x = tmp->x;
1679     if(tmp->y < rect->y) rect->y = tmp->y;
1680     if(tmp->x - rect->x + 1> rect->width)
1681     rect->width = tmp->x - rect->x + 1;
1682     if(tmp->y - rect->y + 1> rect->height)
1683     rect->height = tmp->y - rect->y + 1;
1684     }
1685     }
1686    
1687     /*
1688     * member: delete object from map of editor
1689     * x,y,z : delete object from self point
1690     * return: True, if object deleted
1691     */
1692     Boolean EditDelete (Edit self, int x, int y, int z)
1693     {
1694     object *obj;
1695     XRectangle rect;
1696    
1697     obj = MapGetObjectZ(self->emap, x, y, z);
1698     if (self->read_only || z < 0 || !obj)
1699     return False;
1700     if (obj->head)
1701     obj = obj->head;
1702    
1703     EditObjectCalc (self,obj,&rect);
1704     if (!EditObjectDelete (self, x, y, z))
1705     return False;
1706     CrEditRefresh (self->w,rect);
1707    
1708     if (self->app->item.wall_map)
1709     draw_remove (self, x, y);
1710    
1711     EditModified(self);
1712     return True;
1713     }
1714    
1715     /*
1716     * member: delete object from map of editor
1717     * x,y,z : delete object from self point
1718     * return: True, if object deleted
1719     */
1720     Boolean EditObjectDelete (Edit self, int x, int y, int z)
1721     {
1722     object *obj;
1723    
1724     obj = MapGetObjectZ(self->emap, x, y, z);
1725     if (self->read_only || !obj)
1726     return False;
1727    
1728     if (obj->head)
1729     obj = obj->head;
1730    
1731     if (z < 0) {
1732     if (obj->below)
1733     obj = obj->below;
1734     else
1735     return False;
1736     }
1737     /* This is just plain wrong
1738     ** -- deletes object above the selected object!
1739     ** if (z > 0)
1740     ** obj = obj->above;
1741     */
1742     if (self->app->attr && self->app->attr->op == obj)
1743     AttrChange(self->app->attr, NULL, 0, 0);
1744     if (AppItemGetEdit(self->app) == self)
1745     AppItemSet (self->app, NULL,NULL,0);
1746    
1747     debug4("EditDelete() %s in %dx%dx%d\n",obj->name,x, y, z);
1748    
1749     remove_ob (obj);
1750     free_object (obj);
1751     /* remove_ob should do this for us */
1752     /* But it doesnt - ds */
1753     SET_MAP_FLAGS(self->emap, x, y, P_NEED_UPDATE);
1754     update_position (self->emap, x, y);
1755     return True;
1756     }
1757    
1758     /*
1759     * member: insert object to point of map of editor
1760     * object:
1761     * x,y,z : point to insert
1762     * return: True, if obejct inserted
1763     */
1764     object *EditCloneInsert (Edit self,object *obj,int x, int y, int z)
1765     {
1766     object *op;
1767     int button_value;
1768    
1769     /*** create & insert ***/
1770     if ((op = object_create_clone(obj))) {
1771     /*** object do not fit ***/
1772     if(!MapObjectOut(self->emap,op,x,y)) {
1773     MapInsertObjectZ (self->emap, op, x, y, z);
1774     if (QUERY_FLAG(obj, FLAG_IS_LINKED) &&
1775     (button_value = get_button_value(obj))) {
1776     add_button_link(op, self->emap, button_value);
1777     }
1778     return op;
1779     }
1780     }
1781     debug0 ("Inserting failed\n");
1782     return NULL;
1783     }
1784    
1785     /*
1786     * member: insert object to point of map of editor
1787     * x,y,z : point to insert
1788     * return: True, if obejct inserted
1789     */
1790     Boolean EditInsert (Edit self,int x, int y, int z)
1791     {
1792     int zi = z;
1793     object *op,*tmp;
1794     XRectangle rect;
1795    
1796     /*** ***/
1797     if (!self ||
1798     self->read_only ||
1799     !self->emap ||
1800     out_of_map (self->emap, x, y))
1801     return False;
1802    
1803     /*** something to insert ***/
1804     if (!AppItemGetObject(self->app) && !AppItemGetMap(self->app)) {
1805     CnvNotify ( "Select item to insert.", "OK", NULL);
1806     return False;
1807     }
1808     /*** check for duplicate object ***/
1809     if (z >= 0) {
1810     op = get_map_ob (self->emap, x, y);
1811     while (op && op->above)
1812     op = op->above;
1813     while (op && zi-- > 0)
1814     op = op->below;
1815     if (op && op->arch == self->app->item.clone->arch)
1816     return False;
1817     }
1818     /* Hopefully this doesn't break anything */
1819     else {
1820     op = get_map_ob (self->emap, x, y);
1821     if (op && op->arch == self->app->item.clone->arch)
1822     return False;
1823     }
1824    
1825     debug3("EditInsert() %dx%dx%d\n",x,y,z);
1826    
1827     /*** handle background ***/
1828     if (self->overwrite)
1829     while (get_map_ob (self->emap, x, y))
1830     EditDelete(self, x, y, 0);
1831     else {
1832     tmp = MapGetObjectZ (self->emap, x, y, z);
1833     if (tmp &&
1834     (tmp->arch == self->app->item.clone->arch ||
1835     (self->app->item.wall_map &&
1836     find_draw_arch (AppItemGetMap(self->app),
1837     AppItemGetWall(self->app),
1838     tmp->arch) >= 0)))
1839     return False;
1840     }
1841    
1842     /*** create & insert ***/
1843     op = EditCloneInsert (self, self->app->item.clone, x, y, z);
1844    
1845     if (self->app->item.wall_map)
1846     draw_add (self, x, y);
1847    
1848     EditObjectCalc(self,op,&rect);
1849     SET_MAP_FLAGS(self->emap, x, y, P_NEED_UPDATE);
1850     update_position (self->emap, x, y);
1851     CrEditRefresh(self->w,rect);
1852    
1853     EditModified(self);
1854     return True;
1855     }
1856    
1857    
1858     /*
1859     * member: insert object to point of map of editor
1860     * object:
1861     * x,y,z : point to insert
1862     * return: True, if obejct inserted
1863     */
1864     Boolean EditObjectInsert (Edit self,object *obj,int x, int y, int z)
1865     {
1866     int zi = z;
1867     object *op,*tmp;
1868     XRectangle rect;
1869    
1870     /*** ***/
1871     if (!self ||
1872     self->read_only ||
1873     !self->emap ||
1874     out_of_map (self->emap, x, y) ||
1875     !obj)
1876     return False;
1877    
1878     /*** check for duplicate object ***/
1879     op = get_map_ob (self->emap, x, y);
1880     while (op && op->above)
1881     op = op->above;
1882     while (op && zi-- > 0)
1883     op = op->below;
1884     if (op && op->arch == obj->arch)
1885     return False;
1886    
1887     debug3("EditInsert() %dx%dx%d\n",x,y,z);
1888    
1889     /*** handle background ***/
1890     tmp = MapGetObjectZ (self->emap, x, y, z);
1891     if (tmp && (tmp->arch == obj->arch))
1892     return False;
1893    
1894     /*** create & insert ***/
1895     op = EditCloneInsert (self, op, x, y, z);
1896    
1897     EditObjectCalc(self,op,&rect);
1898     CrEditRefresh(self->w,rect);
1899    
1900     EditModified(self);
1901     return True;
1902     }
1903    
1904     /*
1905     * member: set path name of map
1906     * path : path of file representing map
1907     */
1908     void EditSetPath(Edit self,String path)
1909     {
1910     if(!self) return;
1911     strcpy(self->emap->path,path);
1912     EditUpdate(self);
1913     }
1914    
1915     /*** end of Edit.c ***/