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