ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/crossedit/Edit.c
Revision: 1.4
Committed: Sun Aug 13 17:16:01 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +0 -0 lines
State: FILE REMOVED
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

# Content
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 #include "libproto.h"
44 #include "proto.h"
45
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 void copy_map(mapstruct *m1, mapstruct *m2) {
56 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 mapstruct *MapMoveScrollResize(mapstruct *source,
77 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 object * MapGetRealObject (mapstruct * emap, int x, int y, int z)
166 {
167 object *tmp = MapGetObjectZ (emap, x, y, z);
168 return tmp ? (tmp->head ? tmp->head : tmp) : tmp;
169 }
170
171 int MapInsertObjectZ(mapstruct *emap,object *o,int x, int y, int z)
172 {
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 int MapObjectOut (mapstruct *target, object *obj, int x, int y) {
215 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 ***/