1 /*
2 * objects.cc
3 * Object handling routines.
4 * BW & RQ sometime in 1993 or 1994.
5 */
6
7
8 /*
9 This file is part of Yadex.
10
11 Yadex incorporates code from DEU 5.21 that was put in the public domain in
12 1994 by Rapha�l Quinet and Brendon Wyber.
13
14 The rest of Yadex is Copyright � 1997-2003 Andr� Majorel and others.
15
16 This program is free software; you can redistribute it and/or modify it under
17 the terms of the GNU General Public License as published by the Free Software
18 Foundation; either version 2 of the License, or (at your option) any later
19 version.
20
21 This program is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License along with
26 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
27 Place, Suite 330, Boston, MA 02111-1307, USA.
28 */
29
30
31 #include "yadex.h"
32 #include "drawmap.h"
33 #include "gfx.h"
34 #include "l_vertices.h"
35 #include "levels.h"
36 #include "objects.h"
37 #include "objid.h"
38 #include "s_vertices.h"
39 #include "selectn.h"
40 #include "things.h"
41
42
43 /*
44 highlight the selected objects
45 */
HighlightSelection(int objtype,SelPtr list)46 void HighlightSelection (int objtype, SelPtr list) /* SWAP! */
47 {
48 SelPtr cur;
49
50 if (! list)
51 return;
52 for (cur = list; cur; cur = cur->next)
53 HighlightObject (objtype, cur->objnum, GREEN);
54 }
55
56
57
58 /*
59 get the number of objects of a given type minus one
60 */
GetMaxObjectNum(int objtype)61 obj_no_t GetMaxObjectNum (int objtype)
62 {
63 switch (objtype)
64 {
65 case OBJ_THINGS:
66 return NumThings - 1;
67 case OBJ_LINEDEFS:
68 return NumLineDefs - 1;
69 case OBJ_SIDEDEFS:
70 return NumSideDefs - 1;
71 case OBJ_VERTICES:
72 return NumVertices - 1;
73 case OBJ_SECTORS:
74 return NumSectors - 1;
75 }
76 return -1;
77 }
78
79
80 /*
81 highlight the selected object
82 */
HighlightObject(int objtype,int objnum,int colour)83 void HighlightObject (int objtype, int objnum, int colour) /* SWAP! */
84 {
85 int n, m;
86
87 /* use XOR mode : drawing any line twice erases it */
88 SetDrawingMode (1);
89 set_colour (colour);
90 switch (objtype)
91 {
92 case OBJ_THINGS:
93 ObjectsNeeded (OBJ_THINGS, 0);
94 m = (get_thing_radius (Things[objnum].type) * 3) / 2;
95 DrawMapLine (Things[objnum].xpos - m, Things[objnum].ypos - m,
96 Things[objnum].xpos - m, Things[objnum].ypos + m);
97 DrawMapLine (Things[objnum].xpos - m, Things[objnum].ypos + m,
98 Things[objnum].xpos + m, Things[objnum].ypos + m);
99 DrawMapLine (Things[objnum].xpos + m, Things[objnum].ypos + m,
100 Things[objnum].xpos + m, Things[objnum].ypos - m);
101 DrawMapLine (Things[objnum].xpos + m, Things[objnum].ypos - m,
102 Things[objnum].xpos - m, Things[objnum].ypos - m);
103 DrawMapArrow (Things[objnum].xpos, Things[objnum].ypos,
104 Things[objnum].angle * 182);
105 break;
106
107 case OBJ_LINEDEFS:
108 ObjectsNeeded (OBJ_LINEDEFS, OBJ_VERTICES, 0);
109 n = (Vertices[LineDefs[objnum].start].x
110 + Vertices[LineDefs[objnum].end].x) / 2;
111 m = (Vertices[LineDefs[objnum].start].y
112 + Vertices[LineDefs[objnum].end].y) / 2;
113 DrawMapLine (n, m, n + (Vertices[LineDefs[objnum].end].y
114 - Vertices[LineDefs[objnum].start].y) / 3,
115 m + (Vertices[LineDefs[objnum].start].x
116 - Vertices[LineDefs[objnum].end].x) / 3);
117 SetLineThickness (1);
118 DrawMapVector (Vertices[LineDefs[objnum].start].x,
119 Vertices[LineDefs[objnum].start].y,
120 Vertices[LineDefs[objnum].end].x,
121 Vertices[LineDefs[objnum].end].y);
122 if (colour != LIGHTRED && LineDefs[objnum].tag > 0)
123 {
124 for (m = 0; m < NumSectors; m++)
125 if (Sectors[m].tag == LineDefs[objnum].tag)
126 HighlightObject (OBJ_SECTORS, m, LIGHTRED);
127 }
128 SetLineThickness (0);
129 break;
130
131 case OBJ_VERTICES:
132 ObjectsNeeded (OBJ_VERTICES, 0);
133 {
134 int r = vertex_radius (Scale) * 3 / 2;
135 int scrx0 = SCREENX (Vertices[objnum].x) - r;
136 int scrx9 = SCREENX (Vertices[objnum].x) + r;
137 int scry0 = SCREENY (Vertices[objnum].y) - r;
138 int scry9 = SCREENY (Vertices[objnum].y) + r;
139 DrawScreenLine (scrx0, scry0, scrx9, scry0);
140 DrawScreenLine (scrx9, scry0, scrx9, scry9);
141 DrawScreenLine (scrx9, scry9, scrx0, scry9);
142 DrawScreenLine (scrx0, scry9, scrx0, scry0);
143 }
144 break;
145
146 case OBJ_SECTORS:
147 {
148 ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, OBJ_VERTICES, 0);
149 SetLineThickness (1);
150 const int mapx0 = MAPX (0);
151 const int mapy0 = MAPY (ScrMaxY);
152 const int mapx1 = MAPX (ScrMaxX);
153 const int mapy1 = MAPY (0);
154 for (n = 0; n < NumLineDefs; n++)
155 if (LineDefs[n].sidedef1 != -1
156 && SideDefs[LineDefs[n].sidedef1].sector == objnum
157 || LineDefs[n].sidedef2 != -1
158 && SideDefs[LineDefs[n].sidedef2].sector == objnum)
159 {
160 const struct Vertex *v1 = Vertices + LineDefs[n].start;
161 const struct Vertex *v2 = Vertices + LineDefs[n].end;
162 if (v1->x < mapx0 && v2->x < mapx0
163 || v1->x > mapx1 && v2->x > mapx1
164 || v1->y < mapy0 && v2->y < mapy0
165 || v1->y > mapy1 && v2->y > mapy1)
166 continue; // Off-screen
167 DrawMapLine (v1->x, v1->y, v2->x, v2->y);
168 }
169 if (colour != LIGHTRED && Sectors[objnum].tag > 0)
170 {
171 for (m = 0; m < NumLineDefs; m++)
172 if (LineDefs[m].tag == Sectors[objnum].tag)
173 HighlightObject (OBJ_LINEDEFS, m, LIGHTRED);
174 }
175 SetLineThickness (0);
176 }
177 break;
178 }
179 /* restore normal write mode */
180 SetDrawingMode (0);
181 }
182
183
184
185 /*
186 delete an object
187 */
DeleteObject(const Objid & obj)188 void DeleteObject (const Objid& obj) /* SWAP! */
189 {
190 SelPtr list;
191
192 list = 0;
193 SelectObject (&list, obj.num);
194 DeleteObjects (obj.type, &list);
195 }
196
197
198
199 /*
200 delete a group of objects (*recursive*)
201 */
DeleteObjects(int objtype,SelPtr * list)202 void DeleteObjects (int objtype, SelPtr *list) /* SWAP! */
203 {
204 int n, objnum;
205 SelPtr cur;
206
207 MadeChanges = 1;
208 switch (objtype)
209 {
210 case OBJ_THINGS:
211 ObjectsNeeded (OBJ_THINGS, 0);
212 if (*list)
213 {
214 things_angles++;
215 things_types++;
216 }
217 while (*list)
218 {
219 objnum = (*list)->objnum;
220 if (objnum < 0 || objnum >= NumThings) // Paranoia
221 {
222 nf_bug ("attempt to delete non-existent thing #%d", objnum);
223 goto next_thing;
224 }
225 // Delete the thing
226 NumThings--;
227 if (NumThings > 0)
228 {
229 for (n = objnum; n < NumThings; n++)
230 Things[n] = Things[n + 1];
231 Things = (TPtr) ResizeFarMemory (Things,
232 NumThings * sizeof (struct Thing));
233 }
234 else
235 {
236 FreeFarMemory (Things);
237 Things = 0;
238 }
239 for (cur = (*list)->next; cur; cur = cur->next)
240 if (cur->objnum > objnum)
241 cur->objnum--;
242 next_thing:
243 UnSelectObject (list, objnum);
244 }
245 break;
246
247 case OBJ_VERTICES:
248 if (*list)
249 MadeMapChanges = 1;
250 while (*list)
251 {
252 objnum = (*list)->objnum;
253 if (objnum < 0 || objnum >= NumVertices) // Paranoia
254 {
255 nf_bug ("attempt to delete non-existent vertex #%d", objnum);
256 goto next_vertex;
257 }
258 // Delete the linedefs bound to this vertex and change the references
259 ObjectsNeeded (OBJ_LINEDEFS, 0);
260 for (n = 0; n < NumLineDefs; n++)
261 {
262 if (LineDefs[n].start == objnum || LineDefs[n].end == objnum)
263 DeleteObject (Objid (OBJ_LINEDEFS, n--));
264 else
265 {
266 if (LineDefs[n].start >= objnum)
267 LineDefs[n].start--;
268 if (LineDefs[n].end >= objnum)
269 LineDefs[n].end--;
270 }
271 }
272 // Delete the vertex
273 ObjectsNeeded (OBJ_VERTICES, 0);
274 NumVertices--;
275 if (NumVertices > 0)
276 {
277 for (n = objnum; n < NumVertices; n++)
278 Vertices[n] = Vertices[n + 1];
279 Vertices = (VPtr) ResizeFarMemory (Vertices,
280 NumVertices * sizeof (struct Vertex));
281 }
282 else
283 {
284 FreeFarMemory (Vertices);
285 Vertices = 0;
286 }
287 for (cur = (*list)->next; cur; cur = cur->next)
288 if (cur->objnum > objnum)
289 cur->objnum--;
290 next_vertex:
291 UnSelectObject (list, objnum);
292 }
293 break;
294
295 case OBJ_LINEDEFS:
296 /* In DEU, deleting a linedef was not considered to be a
297 map change. Deleting a _sidedef_ was. In Yadex,
298 sidedefs are not automatically deleted when the linedef
299 is because some sidedefs are shared by more than one
300 linedef. So we need to set MadeMapChanges here. */
301 if (*list)
302 MadeMapChanges = 1;
303 /* AYM 19980203 I've removed the deletion of sidedefs
304 because if several linedefs use the same sidedef, this
305 would lead to trouble. Instead, I let the xref checking
306 take care of that. */
307 while (*list)
308 {
309 ObjectsNeeded (OBJ_LINEDEFS, 0);
310 objnum = (*list)->objnum;
311 if (objnum < 0 || objnum >= NumLineDefs) // Paranoia
312 {
313 nf_bug ("attempt to delete non-existent linedef #%d", objnum);
314 goto next_linedef;
315 }
316 // delete the linedef
317 NumLineDefs--;
318 if (NumLineDefs > 0)
319 {
320 for (n = objnum; n < NumLineDefs; n++)
321 LineDefs[n] = LineDefs[n + 1];
322 LineDefs = (LDPtr) ResizeFarMemory (LineDefs,
323 NumLineDefs * sizeof (struct LineDef));
324 }
325 else
326 {
327 FreeFarMemory (LineDefs);
328 LineDefs = 0;
329 }
330 for (cur = (*list)->next; cur; cur = cur->next)
331 if (cur->objnum > objnum)
332 cur->objnum--;
333 next_linedef:
334 UnSelectObject (list, objnum);
335 }
336 break;
337
338 case OBJ_SIDEDEFS:
339 if (*list)
340 MadeMapChanges = 1;
341 while (*list)
342 {
343 objnum = (*list)->objnum;
344 if (objnum < 0 || objnum >= NumSideDefs) // Paranoia
345 {
346 nf_bug ("attempt to delete non-existent sidedef #%d", objnum);
347 goto next_sidedef;
348 }
349 /* change the linedefs references */
350 ObjectsNeeded (OBJ_LINEDEFS, 0);
351 for (n = 0; n < NumLineDefs; n++)
352 {
353 if (LineDefs[n].sidedef1 == objnum)
354 LineDefs[n].sidedef1 = -1;
355 else if (LineDefs[n].sidedef1 >= objnum)
356 LineDefs[n].sidedef1--;
357 if (LineDefs[n].sidedef2 == objnum)
358 LineDefs[n].sidedef2 = -1;
359 else if (LineDefs[n].sidedef2 >= objnum)
360 LineDefs[n].sidedef2--;
361 }
362 /* delete the sidedef */
363 ObjectsNeeded (OBJ_SIDEDEFS, 0);
364 NumSideDefs--;
365 if (NumSideDefs > 0)
366 {
367 for (n = objnum; n < NumSideDefs; n++)
368 SideDefs[n] = SideDefs[n + 1];
369 SideDefs = (SDPtr) ResizeFarMemory (SideDefs,
370 NumSideDefs * sizeof (struct SideDef));
371 }
372 else
373 {
374 FreeFarMemory (SideDefs);
375 SideDefs = 0;
376 }
377 for (cur = (*list)->next; cur; cur = cur->next)
378 if (cur->objnum > objnum)
379 cur->objnum--;
380 next_sidedef:
381 UnSelectObject (list, objnum);
382 }
383 break;
384 case OBJ_SECTORS:
385 while (*list)
386 {
387 objnum = (*list)->objnum;
388 if (objnum < 0 || objnum >= NumSectors) // Paranoia
389 {
390 nf_bug ("attempt to delete non-existent sector #%d", objnum);
391 goto next_sector;
392 }
393 // Delete the sidedefs bound to this sector and change the references
394 // AYM 19980203: Hmm, hope this is OK with multiply used sidedefs...
395 ObjectsNeeded (OBJ_SIDEDEFS, 0);
396 for (n = 0; n < NumSideDefs; n++)
397 if (SideDefs[n].sector == objnum)
398 DeleteObject (Objid (OBJ_SIDEDEFS, n--));
399 else if (SideDefs[n].sector >= objnum)
400 SideDefs[n].sector--;
401 /* delete the sector */
402 ObjectsNeeded (OBJ_SECTORS, 0);
403 NumSectors--;
404 if (NumSectors > 0)
405 {
406 for (n = objnum; n < NumSectors; n++)
407 Sectors[n] = Sectors[n + 1];
408 Sectors = (SPtr) ResizeFarMemory (Sectors,
409 NumSectors * sizeof (struct Sector));
410 }
411 else
412 {
413 FreeFarMemory (Sectors);
414 Sectors = 0;
415 }
416 for (cur = (*list)->next; cur; cur = cur->next)
417 if (cur->objnum > objnum)
418 cur->objnum--;
419 next_sector:
420 UnSelectObject (list, objnum);
421 }
422 break;
423 default:
424 nf_bug ("DeleteObjects: bad objtype %d", (int) objtype);
425 }
426 }
427
428
429
430 /*
431 * InsertObject
432 * Insert a new object of type <objtype> at map coordinates
433 * (<xpos>, <ypos>).
434 *
435 * If <copyfrom> is a valid object number, the other properties
436 * of the new object are set from the properties of that object,
437 * with the exception of sidedef numbers, which are forced
438 * to OBJ_NO_NONE.
439 *
440 * The object is inserted at the exact coordinates given.
441 * No snapping to grid is done.
442 */
InsertObject(obj_type_t objtype,obj_no_t copyfrom,int xpos,int ypos)443 void InsertObject (obj_type_t objtype, obj_no_t copyfrom, int xpos, int ypos)
444 /* SWAP! */
445 {
446 int last;
447
448 ObjectsNeeded (objtype, 0);
449 MadeChanges = 1;
450 switch (objtype)
451 {
452 case OBJ_THINGS:
453 last = NumThings++;
454 if (last > 0)
455 Things = (TPtr) ResizeFarMemory (Things,
456 (unsigned long) NumThings * sizeof (struct Thing));
457 else
458 Things = (TPtr) GetFarMemory (sizeof (struct Thing));
459 Things[last].xpos = xpos;
460 Things[last].ypos = ypos;
461 things_angles++;
462 things_types++;
463 if (is_obj (copyfrom))
464 {
465 Things[last].type = Things[copyfrom].type;
466 Things[last].angle = Things[copyfrom].angle;
467 Things[last].when = Things[copyfrom].when;
468 }
469 else
470 {
471 Things[last].type = default_thing;
472 Things[last].angle = 0;
473 Things[last].when = 0x07;
474 }
475 break;
476
477 case OBJ_VERTICES:
478 last = NumVertices++;
479 if (last > 0)
480 Vertices = (VPtr) ResizeFarMemory (Vertices,
481 (unsigned long) NumVertices * sizeof (struct Vertex));
482 else
483 Vertices = (VPtr) GetFarMemory (sizeof (struct Vertex));
484 Vertices[last].x = xpos;
485 Vertices[last].y = ypos;
486 if (Vertices[last].x < MapMinX)
487 MapMinX = Vertices[last].x;
488 if (Vertices[last].x > MapMaxX)
489 MapMaxX = Vertices[last].x;
490 if (Vertices[last].y < MapMinY)
491 MapMinY = Vertices[last].y;
492 if (Vertices[last].y > MapMaxY)
493 MapMaxY = Vertices[last].y;
494 MadeMapChanges = 1;
495 break;
496
497 case OBJ_LINEDEFS:
498 last = NumLineDefs++;
499 if (last > 0)
500 LineDefs = (LDPtr) ResizeFarMemory (LineDefs,
501 (unsigned long) NumLineDefs * sizeof (struct LineDef));
502 else
503 LineDefs = (LDPtr) GetFarMemory (sizeof (struct LineDef));
504 if (is_obj (copyfrom))
505 {
506 LineDefs[last].start = LineDefs[copyfrom].start;
507 LineDefs[last].end = LineDefs[copyfrom].end;
508 LineDefs[last].flags = LineDefs[copyfrom].flags;
509 LineDefs[last].type = LineDefs[copyfrom].type;
510 LineDefs[last].tag = LineDefs[copyfrom].tag;
511 }
512 else
513 {
514 LineDefs[last].start = 0;
515 LineDefs[last].end = NumVertices - 1;
516 LineDefs[last].flags = 1;
517 LineDefs[last].type = 0;
518 LineDefs[last].tag = 0;
519 }
520 LineDefs[last].sidedef1 = OBJ_NO_NONE;
521 LineDefs[last].sidedef2 = OBJ_NO_NONE;
522 break;
523
524 case OBJ_SIDEDEFS:
525 last = NumSideDefs++;
526 if (last > 0)
527 SideDefs = (SDPtr) ResizeFarMemory (SideDefs,
528 (unsigned long) NumSideDefs * sizeof (struct SideDef));
529 else
530 SideDefs = (SDPtr) GetFarMemory (sizeof (struct SideDef));
531 if (is_obj (copyfrom))
532 {
533 SideDefs[last].xoff = SideDefs[copyfrom].xoff;
534 SideDefs[last].yoff = SideDefs[copyfrom].yoff;
535 strncpy (SideDefs[last].tex1, SideDefs[copyfrom].tex1, WAD_TEX_NAME);
536 strncpy (SideDefs[last].tex2, SideDefs[copyfrom].tex2, WAD_TEX_NAME);
537 strncpy (SideDefs[last].tex3, SideDefs[copyfrom].tex3, WAD_TEX_NAME);
538 SideDefs[last].sector = SideDefs[copyfrom].sector;
539 }
540 else
541 {
542 SideDefs[last].xoff = 0;
543 SideDefs[last].yoff = 0;
544 strcpy (SideDefs[last].tex1, "-");
545 strcpy (SideDefs[last].tex2, "-");
546 strcpy (SideDefs[last].tex3, default_middle_texture);
547 SideDefs[last].sector = NumSectors - 1;
548 }
549 MadeMapChanges = 1;
550 break;
551
552 case OBJ_SECTORS:
553 last = NumSectors++;
554 if (last > 0)
555 Sectors = (SPtr) ResizeFarMemory (Sectors,
556 (unsigned long) NumSectors * sizeof (struct Sector));
557 else
558 Sectors = (SPtr) GetFarMemory (sizeof (struct Sector));
559 if (is_obj (copyfrom))
560 {
561 Sectors[last].floorh = Sectors[copyfrom].floorh;
562 Sectors[last].ceilh = Sectors[copyfrom].ceilh;
563 strncpy (Sectors[last].floort, Sectors[copyfrom].floort, WAD_FLAT_NAME);
564 strncpy (Sectors[last].ceilt, Sectors[copyfrom].ceilt, WAD_FLAT_NAME);
565 Sectors[last].light = Sectors[copyfrom].light;
566 Sectors[last].special = Sectors[copyfrom].special;
567 Sectors[last].tag = Sectors[copyfrom].tag;
568 }
569 else
570 {
571 Sectors[last].floorh = default_floor_height;
572 Sectors[last].ceilh = default_ceiling_height;
573 strncpy (Sectors[last].floort, default_floor_texture, WAD_FLAT_NAME);
574 strncpy (Sectors[last].ceilt, default_ceiling_texture, WAD_FLAT_NAME);
575 Sectors[last].light = default_light_level;
576 Sectors[last].special = 0;
577 Sectors[last].tag = 0;
578 }
579 break;
580
581 default:
582 nf_bug ("InsertObject: bad objtype %d", (int) objtype);
583 }
584 }
585
586
587
588 /*
589 check if a (part of a) LineDef is inside a given block
590 */
IsLineDefInside(int ldnum,int x0,int y0,int x1,int y1)591 bool IsLineDefInside (int ldnum, int x0, int y0, int x1, int y1) /* SWAP - needs Vertices & LineDefs */
592 {
593 int lx0 = Vertices[LineDefs[ldnum].start].x;
594 int ly0 = Vertices[LineDefs[ldnum].start].y;
595 int lx1 = Vertices[LineDefs[ldnum].end].x;
596 int ly1 = Vertices[LineDefs[ldnum].end].y;
597 int i;
598
599 /* do you like mathematics? */
600 if (lx0 >= x0 && lx0 <= x1 && ly0 >= y0 && ly0 <= y1)
601 return 1; /* the linedef start is entirely inside the square */
602 if (lx1 >= x0 && lx1 <= x1 && ly1 >= y0 && ly1 <= y1)
603 return 1; /* the linedef end is entirely inside the square */
604 if ((ly0 > y0) != (ly1 > y0))
605 {
606 i = lx0 + (int) ((long) (y0 - ly0) * (long) (lx1 - lx0) / (long) (ly1 - ly0));
607 if (i >= x0 && i <= x1)
608 return true; /* the linedef crosses the y0 side (left) */
609 }
610 if ((ly0 > y1) != (ly1 > y1))
611 {
612 i = lx0 + (int) ((long) (y1 - ly0) * (long) (lx1 - lx0) / (long) (ly1 - ly0));
613 if (i >= x0 && i <= x1)
614 return true; /* the linedef crosses the y1 side (right) */
615 }
616 if ((lx0 > x0) != (lx1 > x0))
617 {
618 i = ly0 + (int) ((long) (x0 - lx0) * (long) (ly1 - ly0) / (long) (lx1 - lx0));
619 if (i >= y0 && i <= y1)
620 return true; /* the linedef crosses the x0 side (down) */
621 }
622 if ((lx0 > x1) != (lx1 > x1))
623 {
624 i = ly0 + (int) ((long) (x1 - lx0) * (long) (ly1 - ly0) / (long) (lx1 - lx0));
625 if (i >= y0 && i <= y1)
626 return true; /* the linedef crosses the x1 side (up) */
627 }
628 return false;
629 }
630
631
632
633 /*
634 get the sector number of the sidedef opposite to this sidedef
635 (returns -1 if it cannot be found)
636 */
GetOppositeSector(int ld1,bool firstside)637 int GetOppositeSector (int ld1, bool firstside) /* SWAP! */
638 {
639 int x0, y0, dx0, dy0;
640 int x1, y1, dx1, dy1;
641 int x2, y2, dx2, dy2;
642 int ld2, dist;
643 int bestld, bestdist, bestmdist;
644
645 /* get the coords for this LineDef */
646 ObjectsNeeded (OBJ_LINEDEFS, OBJ_VERTICES, 0);
647 x0 = Vertices[LineDefs[ld1].start].x;
648 y0 = Vertices[LineDefs[ld1].start].y;
649 dx0 = Vertices[LineDefs[ld1].end].x - x0;
650 dy0 = Vertices[LineDefs[ld1].end].y - y0;
651
652 /* find the normal vector for this LineDef */
653 x1 = (dx0 + x0 + x0) / 2;
654 y1 = (dy0 + y0 + y0) / 2;
655 if (firstside)
656 {
657 dx1 = dy0;
658 dy1 = -dx0;
659 }
660 else
661 {
662 dx1 = -dy0;
663 dy1 = dx0;
664 }
665
666 bestld = -1;
667 /* use a parallel to an axis instead of the normal vector (faster method) */
668 if (abs (dy1) > abs (dx1))
669 {
670 if (dy1 > 0)
671 {
672 /* get the nearest LineDef in that direction (increasing Y's: North) */
673 bestdist = 32767;
674 bestmdist = 32767;
675 for (ld2 = 0; ld2 < NumLineDefs; ld2++)
676 if (ld2 != ld1 && ((Vertices[LineDefs[ld2].start].x > x1)
677 != (Vertices[LineDefs[ld2].end].x > x1)))
678 {
679 x2 = Vertices[LineDefs[ld2].start].x;
680 y2 = Vertices[LineDefs[ld2].start].y;
681 dx2 = Vertices[LineDefs[ld2].end].x - x2;
682 dy2 = Vertices[LineDefs[ld2].end].y - y2;
683 dist = y2 + (int) ((long) (x1 - x2) * (long) dy2 / (long) dx2);
684 if (dist > y1 && (dist < bestdist
685 || (dist == bestdist && (y2 + dy2 / 2) < bestmdist)))
686 {
687 bestld = ld2;
688 bestdist = dist;
689 bestmdist = y2 + dy2 / 2;
690 }
691 }
692 }
693 else
694 {
695 /* get the nearest LineDef in that direction (decreasing Y's: South) */
696 bestdist = -32767;
697 bestmdist = -32767;
698 for (ld2 = 0; ld2 < NumLineDefs; ld2++)
699 if (ld2 != ld1 && ((Vertices[LineDefs[ld2].start].x > x1)
700 != (Vertices[LineDefs[ld2].end].x > x1)))
701 {
702 x2 = Vertices[LineDefs[ld2].start].x;
703 y2 = Vertices[LineDefs[ld2].start].y;
704 dx2 = Vertices[LineDefs[ld2].end].x - x2;
705 dy2 = Vertices[LineDefs[ld2].end].y - y2;
706 dist = y2 + (int) ((long) (x1 - x2) * (long) dy2 / (long) dx2);
707 if (dist < y1 && (dist > bestdist
708 || (dist == bestdist && (y2 + dy2 / 2) > bestmdist)))
709 {
710 bestld = ld2;
711 bestdist = dist;
712 bestmdist = y2 + dy2 / 2;
713 }
714 }
715 }
716 }
717 else
718 {
719 if (dx1 > 0)
720 {
721 /* get the nearest LineDef in that direction (increasing X's: East) */
722 bestdist = 32767;
723 bestmdist = 32767;
724 for (ld2 = 0; ld2 < NumLineDefs; ld2++)
725 if (ld2 != ld1 && ((Vertices[LineDefs[ld2].start].y > y1)
726 != (Vertices[LineDefs[ld2].end].y > y1)))
727 {
728 x2 = Vertices[LineDefs[ld2].start].x;
729 y2 = Vertices[LineDefs[ld2].start].y;
730 dx2 = Vertices[LineDefs[ld2].end].x - x2;
731 dy2 = Vertices[LineDefs[ld2].end].y - y2;
732 dist = x2 + (int) ((long) (y1 - y2) * (long) dx2 / (long) dy2);
733 if (dist > x1 && (dist < bestdist
734 || (dist == bestdist && (x2 + dx2 / 2) < bestmdist)))
735 {
736 bestld = ld2;
737 bestdist = dist;
738 bestmdist = x2 + dx2 / 2;
739 }
740 }
741 }
742 else
743 {
744 /* get the nearest LineDef in that direction (decreasing X's: West) */
745 bestdist = -32767;
746 bestmdist = -32767;
747 for (ld2 = 0; ld2 < NumLineDefs; ld2++)
748 if (ld2 != ld1 && ((Vertices[LineDefs[ld2].start].y > y1)
749 != (Vertices[LineDefs[ld2].end].y > y1)))
750 {
751 x2 = Vertices[LineDefs[ld2].start].x;
752 y2 = Vertices[LineDefs[ld2].start].y;
753 dx2 = Vertices[LineDefs[ld2].end].x - x2;
754 dy2 = Vertices[LineDefs[ld2].end].y - y2;
755 dist = x2 + (int) ((long) (y1 - y2) * (long) dx2 / (long) dy2);
756 if (dist < x1 && (dist > bestdist
757 || (dist == bestdist && (x2 + dx2 / 2) > bestmdist)))
758 {
759 bestld = ld2;
760 bestdist = dist;
761 bestmdist = x2 + dx2 / 2;
762 }
763 }
764 }
765 }
766
767 /* no intersection: the LineDef was pointing outwards! */
768 if (bestld < 0)
769 return -1;
770
771 /* now look if this LineDef has a SideDef bound to one sector */
772 if (abs (dy1) > abs (dx1))
773 {
774 if ((Vertices[LineDefs[bestld].start].x
775 < Vertices[LineDefs[bestld].end].x) == (dy1 > 0))
776 x0 = LineDefs[bestld].sidedef1;
777 else
778 x0 = LineDefs[bestld].sidedef2;
779 }
780 else
781 {
782 if ((Vertices[LineDefs[bestld].start].y
783 < Vertices[LineDefs[bestld].end].y) != (dx1 > 0))
784 x0 = LineDefs[bestld].sidedef1;
785 else
786 x0 = LineDefs[bestld].sidedef2;
787 }
788
789 /* there is no SideDef on this side of the LineDef! */
790 if (x0 < 0)
791 return -1;
792
793 /* OK, we got it -- return the Sector number */
794 ObjectsNeeded (OBJ_SIDEDEFS, 0);
795 return SideDefs[x0].sector;
796 }
797
798
799
800 /*
801 copy a group of objects to a new position
802 */
CopyObjects(int objtype,SelPtr obj)803 void CopyObjects (int objtype, SelPtr obj) /* SWAP! */
804 {
805 int n, m;
806 SelPtr cur;
807 SelPtr list1, list2;
808 SelPtr ref1, ref2;
809
810 if (! obj)
811 return;
812 ObjectsNeeded (objtype, 0);
813 /* copy the object(s) */
814 switch (objtype)
815 {
816 case OBJ_THINGS:
817 for (cur = obj; cur; cur = cur->next)
818 {
819 InsertObject (OBJ_THINGS, cur->objnum, Things[cur->objnum].xpos,
820 Things[cur->objnum].ypos);
821 cur->objnum = NumThings - 1;
822 }
823 MadeChanges = 1;
824 break;
825
826 case OBJ_VERTICES:
827 for (cur = obj; cur; cur = cur->next)
828 {
829 InsertObject (OBJ_VERTICES, cur->objnum, Vertices[cur->objnum].x,
830 Vertices[cur->objnum].y);
831 cur->objnum = NumVertices - 1;
832 }
833 MadeChanges = 1;
834 MadeMapChanges = 1;
835 break;
836
837 case OBJ_LINEDEFS:
838 list1 = 0;
839 list2 = 0;
840
841 // Create the linedefs and maybe the sidedefs
842 for (cur = obj; cur; cur = cur->next)
843 {
844 int old = cur->objnum; // No. of original linedef
845 int New; // No. of duplicate linedef
846
847 InsertObject (OBJ_LINEDEFS, old, 0, 0);
848 New = NumLineDefs - 1;
849
850 if (copy_linedef_reuse_sidedefs)
851 {
852 /* AYM 1997-07-25: not very orthodox (the New linedef and
853 the old one use the same sidedefs). but, in the case where
854 you're copying into the same sector, it's much better than
855 having to create the New sidedefs manually. plus it saves
856 space in the .wad and also it makes editing easier (editing
857 one sidedef impacts all linedefs that use it). */
858 LineDefs[New].sidedef1 = LineDefs[old].sidedef1;
859 LineDefs[New].sidedef2 = LineDefs[old].sidedef2;
860 }
861 else
862 {
863 /* AYM 1998-11-08: duplicate sidedefs too.
864 DEU 5.21 just left the sidedef references to -1. */
865 if (is_sidedef (LineDefs[old].sidedef1))
866 {
867 InsertObject (OBJ_SIDEDEFS, LineDefs[old].sidedef1, 0, 0);
868 LineDefs[New].sidedef1 = NumSideDefs - 1;
869 }
870 if (is_sidedef (LineDefs[old].sidedef2))
871 {
872 InsertObject (OBJ_SIDEDEFS, LineDefs[old].sidedef2, 0, 0);
873 LineDefs[New].sidedef2 = NumSideDefs - 1;
874 }
875 }
876 cur->objnum = New;
877 if (!IsSelected (list1, LineDefs[New].start))
878 {
879 SelectObject (&list1, LineDefs[New].start);
880 SelectObject (&list2, LineDefs[New].start);
881 }
882 if (!IsSelected (list1, LineDefs[New].end))
883 {
884 SelectObject (&list1, LineDefs[New].end);
885 SelectObject (&list2, LineDefs[New].end);
886 }
887 }
888
889 // Create the vertices
890 CopyObjects (OBJ_VERTICES, list2);
891 ObjectsNeeded (OBJ_LINEDEFS, 0);
892
893 // Update the references to the vertices
894 for (ref1 = list1, ref2 = list2;
895 ref1 && ref2;
896 ref1 = ref1->next, ref2 = ref2->next)
897 {
898 for (cur = obj; cur; cur = cur->next)
899 {
900 if (ref1->objnum == LineDefs[cur->objnum].start)
901 LineDefs[cur->objnum].start = ref2->objnum;
902 if (ref1->objnum == LineDefs[cur->objnum].end)
903 LineDefs[cur->objnum].end = ref2->objnum;
904 }
905 }
906 ForgetSelection (&list1);
907 ForgetSelection (&list2);
908 break;
909
910 case OBJ_SECTORS:
911 ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
912 list1 = 0;
913 list2 = 0;
914 // Create the linedefs (and vertices)
915 for (cur = obj; cur; cur = cur->next)
916 {
917 for (n = 0; n < NumLineDefs; n++)
918 if ((((m = LineDefs[n].sidedef1) >= 0
919 && SideDefs[m].sector == cur->objnum)
920 || ((m = LineDefs[n].sidedef2) >= 0
921 && SideDefs[m].sector == cur->objnum))
922 && ! IsSelected (list1, n))
923 {
924 SelectObject (&list1, n);
925 SelectObject (&list2, n);
926 }
927 }
928 CopyObjects (OBJ_LINEDEFS, list2);
929 /* create the sidedefs */
930 ObjectsNeeded (OBJ_LINEDEFS, 0);
931 for (ref1 = list1, ref2 = list2;
932 ref1 && ref2;
933 ref1 = ref1->next, ref2 = ref2->next)
934 {
935 if ((n = LineDefs[ref1->objnum].sidedef1) >= 0)
936 {
937 InsertObject (OBJ_SIDEDEFS, n, 0, 0);
938 n = NumSideDefs - 1;
939 ObjectsNeeded (OBJ_LINEDEFS, 0);
940 LineDefs[ref2->objnum].sidedef1 = n;
941 }
942 if ((m = LineDefs[ref1->objnum].sidedef2) >= 0)
943 {
944 InsertObject (OBJ_SIDEDEFS, m, 0, 0);
945 m = NumSideDefs - 1;
946 ObjectsNeeded (OBJ_LINEDEFS, 0);
947 LineDefs[ref2->objnum].sidedef2 = m;
948 }
949 ref1->objnum = n;
950 ref2->objnum = m;
951 }
952 /* create the Sectors */
953 for (cur = obj; cur; cur = cur->next)
954 {
955 InsertObject (OBJ_SECTORS, cur->objnum, 0, 0);
956 ObjectsNeeded (OBJ_SIDEDEFS, 0);
957 for (ref1 = list1, ref2 = list2;
958 ref1 && ref2;
959 ref1 = ref1->next, ref2 = ref2->next)
960 {
961 if (ref1->objnum >= 0
962 && SideDefs[ref1->objnum].sector == cur->objnum)
963 SideDefs[ref1->objnum].sector = NumSectors - 1;
964 if (ref2->objnum >= 0
965 && SideDefs[ref2->objnum].sector == cur->objnum)
966 SideDefs[ref2->objnum].sector = NumSectors - 1;
967 }
968 cur->objnum = NumSectors - 1;
969 }
970 ForgetSelection (&list1);
971 ForgetSelection (&list2);
972 break;
973 }
974 }
975
976
977
978 /*
979 * MoveObjectsToCoords
980 * Move a group of objects to a new position
981 *
982 * You must first call it with obj == NULL and newx and newy
983 * set to the coordinates of the reference point (E.G. the
984 * object being dragged).
985 * Then, every time the object being dragged has changed its
986 * coordinates, call the it again with newx and newy set to
987 * the new position and obj set to the selection.
988 *
989 * Returns <>0 iff an object was moved.
990 */
MoveObjectsToCoords(int objtype,SelPtr obj,int newx,int newy,int grid)991 bool MoveObjectsToCoords (
992 int objtype,
993 SelPtr obj,
994 int newx,
995 int newy,
996 int grid) /* SWAP! */
997 {
998 int dx, dy;
999 SelPtr cur, vertices;
1000 static int refx, refy; /* previous position */
1001
1002 ObjectsNeeded (objtype, 0);
1003 if (grid > 0)
1004 {
1005 newx = (newx + grid / 2) & ~(grid - 1);
1006 newy = (newy + grid / 2) & ~(grid - 1);
1007 }
1008
1009 // Only update the reference point ?
1010 if (! obj)
1011 {
1012 refx = newx;
1013 refy = newy;
1014 return true;
1015 }
1016
1017 /* compute the displacement */
1018 dx = newx - refx;
1019 dy = newy - refy;
1020 /* nothing to do? */
1021 if (dx == 0 && dy == 0)
1022 return false;
1023
1024 /* move the object(s) */
1025 switch (objtype)
1026 {
1027 case OBJ_THINGS:
1028 for (cur = obj; cur; cur = cur->next)
1029 {
1030 Things[cur->objnum].xpos += dx;
1031 Things[cur->objnum].ypos += dy;
1032 }
1033 refx = newx;
1034 refy = newy;
1035 MadeChanges = 1;
1036 break;
1037
1038 case OBJ_VERTICES:
1039 for (cur = obj; cur; cur = cur->next)
1040 {
1041 Vertices[cur->objnum].x += dx;
1042 Vertices[cur->objnum].y += dy;
1043 }
1044 refx = newx;
1045 refy = newy;
1046 MadeChanges = 1;
1047 MadeMapChanges = 1;
1048 break;
1049
1050 case OBJ_LINEDEFS:
1051 vertices = list_vertices_of_linedefs (obj);
1052 MoveObjectsToCoords (OBJ_VERTICES, vertices, newx, newy, grid);
1053 ForgetSelection (&vertices);
1054 break;
1055
1056 case OBJ_SECTORS:
1057 ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
1058 vertices = list_vertices_of_sectors (obj);
1059 MoveObjectsToCoords (OBJ_VERTICES, vertices, newx, newy, grid);
1060 ForgetSelection (&vertices);
1061 break;
1062 }
1063 return true;
1064 }
1065
1066
1067
1068 /*
1069 get the coordinates (approx.) of an object
1070 */
GetObjectCoords(int objtype,int objnum,int * xpos,int * ypos)1071 void GetObjectCoords (int objtype, int objnum, int *xpos, int *ypos) /* SWAP! */
1072 {
1073 int n, v1, v2, sd1, sd2;
1074 long accx, accy, num;
1075
1076 switch (objtype)
1077 {
1078 case OBJ_THINGS:
1079 if (! is_thing (objnum)) // Can't happen
1080 {
1081 nf_bug ("GetObjectCoords: bad thing# %d", objnum);
1082 *xpos = 0;
1083 *ypos = 0;
1084 return;
1085 }
1086 ObjectsNeeded (OBJ_THINGS, 0);
1087 *xpos = Things[objnum].xpos;
1088 *ypos = Things[objnum].ypos;
1089 break;
1090
1091 case OBJ_VERTICES:
1092 if (! is_vertex (objnum)) // Can't happen
1093 {
1094 nf_bug ("GetObjectCoords: bad vertex# %d", objnum);
1095 *xpos = 0;
1096 *ypos = 0;
1097 return;
1098 }
1099 ObjectsNeeded (OBJ_VERTICES, 0);
1100 *xpos = Vertices[objnum].x;
1101 *ypos = Vertices[objnum].y;
1102 break;
1103
1104 case OBJ_LINEDEFS:
1105 if (! is_linedef (objnum)) // Can't happen
1106 {
1107 nf_bug ("GetObjectCoords: bad linedef# %d", objnum);
1108 *xpos = 0;
1109 *ypos = 0;
1110 return;
1111 }
1112 ObjectsNeeded (OBJ_LINEDEFS, 0);
1113 v1 = LineDefs[objnum].start;
1114 v2 = LineDefs[objnum].end;
1115 ObjectsNeeded (OBJ_VERTICES, 0);
1116 *xpos = (Vertices[v1].x + Vertices[v2].x) / 2;
1117 *ypos = (Vertices[v1].y + Vertices[v2].y) / 2;
1118 break;
1119
1120 case OBJ_SIDEDEFS:
1121 if (! is_sidedef (objnum)) // Can't happen
1122 {
1123 nf_bug ("GetObjectCoords: bad sidedef# %d", objnum);
1124 *xpos = 0;
1125 *ypos = 0;
1126 return;
1127 }
1128 ObjectsNeeded (OBJ_LINEDEFS, 0);
1129 for (n = 0; n < NumLineDefs; n++)
1130 if (LineDefs[n].sidedef1 == objnum || LineDefs[n].sidedef2 == objnum)
1131 {
1132 v1 = LineDefs[n].start;
1133 v2 = LineDefs[n].end;
1134 ObjectsNeeded (OBJ_VERTICES, 0);
1135 *xpos = (Vertices[v1].x + Vertices[v2].x) / 2;
1136 *ypos = (Vertices[v1].y + Vertices[v2].y) / 2;
1137 return;
1138 }
1139 *xpos = (MapMinX + MapMaxX) / 2;
1140 *ypos = (MapMinY + MapMaxY) / 2;
1141 // FIXME is the fall through intentional ? -- AYM 2000-11-08
1142
1143 case OBJ_SECTORS:
1144 if (! is_sector (objnum)) // Can't happen
1145 {
1146 nf_bug ("GetObjectCoords: bad sector# %d", objnum);
1147 *xpos = 0;
1148 *ypos = 0;
1149 return;
1150 }
1151 accx = 0L;
1152 accy = 0L;
1153 num = 0L;
1154 for (n = 0; n < NumLineDefs; n++)
1155 {
1156 ObjectsNeeded (OBJ_LINEDEFS, 0);
1157 sd1 = LineDefs[n].sidedef1;
1158 sd2 = LineDefs[n].sidedef2;
1159 v1 = LineDefs[n].start;
1160 v2 = LineDefs[n].end;
1161 ObjectsNeeded (OBJ_SIDEDEFS, 0);
1162 if ((sd1 >= 0 && SideDefs[sd1].sector == objnum)
1163 || (sd2 >= 0 && SideDefs[sd2].sector == objnum))
1164 {
1165 ObjectsNeeded (OBJ_VERTICES, 0);
1166 /* if the Sector is closed, all Vertices will be counted twice */
1167 accx += (long) Vertices[v1].x;
1168 accy += (long) Vertices[v1].y;
1169 num++;
1170 accx += (long) Vertices[v2].x;
1171 accy += (long) Vertices[v2].y;
1172 num++;
1173 }
1174 }
1175 if (num > 0)
1176 {
1177 *xpos = (int) ((accx + num / 2L) / num);
1178 *ypos = (int) ((accy + num / 2L) / num);
1179 }
1180 else
1181 {
1182 *xpos = (MapMinX + MapMaxX) / 2;
1183 *ypos = (MapMinY + MapMaxY) / 2;
1184 }
1185 break;
1186
1187 default:
1188 nf_bug ("GetObjectCoords: bad objtype %d", objtype); // Can't happen
1189 *xpos = 0;
1190 *ypos = 0;
1191 }
1192 }
1193
1194
1195
1196 /*
1197 find a free tag number
1198 */
FindFreeTag()1199 int FindFreeTag () /* SWAP! */
1200 {
1201 int tag, n;
1202 bool ok;
1203
1204 ObjectsNeeded (OBJ_LINEDEFS, OBJ_SECTORS, 0);
1205 tag = 1;
1206 ok = false;
1207 while (! ok)
1208 {
1209 ok = true;
1210 for (n = 0; n < NumLineDefs; n++)
1211 if (LineDefs[n].tag == tag)
1212 {
1213 ok = false;
1214 break;
1215 }
1216 if (ok)
1217 for (n = 0; n < NumSectors; n++)
1218 if (Sectors[n].tag == tag)
1219 {
1220 ok = false;
1221 break;
1222 }
1223 tag++;
1224 }
1225 return tag - 1;
1226 }
1227
1228
1229