ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/crossedit/Edit.c
Revision: 1.2
Committed: Sun May 7 08:19:29 2006 UTC (18 years ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.1: +7 -5 lines
Log Message:
A few cleanups of Crossedit and a fix to automake so it doesn't build
Crossedit if the needed headers aren't found.

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