1 /*
2 * editobj.cc
3 * Object editing 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 "_edit.h"
33 #include "dialog.h"
34 #include "editobj.h"
35 #include "entry.h"
36 #include "flats.h"
37 #include "game.h"
38 #include "gfx.h"
39 #include "levels.h"
40 #include "objects.h"
41 #include "objid.h"
42 #include "oldmenus.h"
43 #include "s_slice.h"
44 #include "s_swapf.h"
45 #include "selectn.h"
46 #include "t_spin.h"
47 #include "x_mirror.h"
48 #include "x_rotate.h"
49
50
51 /*
52 ask for an object number and check for maximum valid number
53 (this is just like InputIntegerValue, but with a different prompt)
54 */
55
InputObjectNumber(int x0,int y0,int objtype,int curobj)56 int InputObjectNumber (int x0, int y0, int objtype, int curobj)
57 {
58 int val, key;
59 char prompt[80];
60
61 HideMousePointer ();
62 sprintf (prompt, "Enter a %s number between 0 and %d:",
63 GetObjectTypeName (objtype), GetMaxObjectNum (objtype));
64 if (x0 < 0)
65 x0 = (ScrMaxX - 25 - 8 * strlen (prompt)) / 2;
66 if (y0 < 0)
67 y0 = (ScrMaxY - 55) / 2;
68 DrawScreenBox3D (x0, y0, x0 + 25 + 8 * strlen (prompt), y0 + 55);
69 set_colour (WHITE);
70 DrawScreenText (x0 + 10, y0 + 8, prompt);
71 val = curobj;
72 while ((key
73 = InputInteger (x0 + 10, y0 + 28, &val, 0, GetMaxObjectNum (objtype)))
74 != YK_RETURN && key != YK_ESC)
75 Beep ();
76 ShowMousePointer ();
77 return val;
78 }
79
80
81 /*
82 * input_objid - ask for an object number of the specified type
83 *
84 * If the user hit [Return], set objid.type to init.type
85 * and objid.num to whatever number the user entered. If
86 * the user hit [Esc], call nil() on objid.
87 */
input_objid(Objid & objid,const Objid & init,int x0,int y0)88 void input_objid (Objid& objid, const Objid& init, int x0, int y0)
89 {
90 char prompt[80];
91
92 HideMousePointer ();
93 sprintf (prompt, "Enter a %s number between 0 and %d:",
94 GetObjectTypeName (init.type), GetMaxObjectNum (init.type));
95 if (x0 < 0)
96 x0 = (ScrMaxX - 25 - 8 * strlen (prompt)) / 2;
97 if (y0 < 0)
98 y0 = (ScrMaxY - 55) / 2;
99 DrawScreenBox3D (x0, y0, x0 + 25 + 8 * strlen (prompt), y0 + 55);
100 set_colour (WHITE);
101 DrawScreenText (x0 + 10, y0 + 8, prompt);
102 int num = init.num;
103 int key;
104 while ((key
105 = InputInteger (x0 + 10, y0 + 28, &num, 0, GetMaxObjectNum (init.type)))
106 != YK_RETURN && key != YK_ESC)
107 Beep ();
108 if (key == YK_ESC)
109 objid.nil ();
110 else if (key == YK_RETURN)
111 {
112 objid.type = init.type;
113 objid.num = num;
114 }
115 else
116 {
117 nf_bug ("input_objid: bad key %d", (int) key); // Can't happen
118 objid.nil ();
119 }
120 ShowMousePointer ();
121 }
122
123
124 /*
125 ask for an object number and display a warning message
126 */
127
InputObjectXRef(int x0,int y0,int objtype,bool allownone,int curobj)128 int InputObjectXRef (int x0, int y0, int objtype, bool allownone, int curobj)
129 {
130 const char *const msg1 = "Warning: modifying the cross-references";
131 const char *const msg2 = "between some objects may crash the game.";
132 char prompt[80];
133 size_t maxlen = 0;
134 int width;
135 int height;
136
137 // Dimensions
138 sprintf (prompt, "Enter a %s number between 0 and %d%c",
139 GetObjectTypeName (objtype),
140 GetMaxObjectNum (objtype), allownone ? ',' : ':');
141 maxlen = 40; // Why 40 ? -- AYM 2002-04-17
142 if (strlen (prompt) > maxlen);
143 maxlen = strlen (prompt);
144 if (strlen (msg1) > maxlen)
145 maxlen = strlen (msg1);
146 if (strlen (msg2) > maxlen)
147 maxlen = strlen (msg2);
148 int ya = 0 + BOX_BORDER + WIDE_VSPACING;
149 int yb = ya;
150 if (allownone)
151 yb += FONTH;
152 int yc = yb + FONTH + WIDE_VSPACING;
153 // FIXME should query InputInteger() instead
154 int yd = yc + 2 * HOLLOW_BORDER + 2 * NARROW_VSPACING + FONTH + WIDE_VSPACING;
155 int ye = yd + FONTH;
156 int yf = ye + FONTH + WIDE_VSPACING + BOX_BORDER;
157 width = 2 * BOX_BORDER + 2 * WIDE_HSPACING + maxlen * FONTW;
158 height = yf - 0;
159
160 // Position
161 if (x0 < 0)
162 x0 = (ScrMaxX - width) / 2;
163 if (y0 < 0)
164 y0 = (ScrMaxY - height) / 2;
165
166 HideMousePointer ();
167 DrawScreenBox3D (x0, y0, x0 + width, y0 + height);
168 set_colour (WHITE);
169 int x = x0 + BOX_BORDER + WIDE_HSPACING;
170 DrawScreenText (x, y0 + ya, prompt);
171 if (allownone)
172 DrawScreenText (x, y0 + yb, "or -1 for none:");
173 set_colour (LIGHTRED);
174 DrawScreenText (x, y0 + yd, msg1);
175 DrawScreenText (x, y0 + ye, msg2);
176
177 int val = curobj;
178 int key;
179 int min = allownone ? -1 : 0;
180 int max = GetMaxObjectNum (objtype);
181 while (key = InputInteger (x, y0 + yc, &val, min, max),
182 key != YK_RETURN && key != YK_ESC)
183 Beep ();
184 ShowMousePointer ();
185 return val;
186 }
187
188
189
190 /*
191 ask for two vertex numbers and check for maximum valid number
192 */
193
Input2VertexNumbers(int x0,int y0,const char * prompt1,int * v1,int * v2)194 bool Input2VertexNumbers (int x0, int y0, const char *prompt1, int *v1, int *v2)
195 {
196 int key;
197 int maxlen, first;
198 char prompt2[80];
199 int text_x0;
200 int text_y0;
201 int entry1_x0;
202 int entry1_y0;
203 int entry2_x0;
204 int entry2_y0;
205 // FIXME should let InputInteger() tell us
206 const int entry_width = 2 * HOLLOW_BORDER + 2 * NARROW_HSPACING + 7 * FONTW;
207 const int entry_height = 2 * HOLLOW_BORDER + 2 * NARROW_VSPACING + FONTH;
208
209 HideMousePointer ();
210 sprintf (prompt2, "Enter two numbers between 0 and %d:", NumVertices - 1);
211
212 if (strlen (prompt1) > strlen (prompt2))
213 maxlen = strlen (prompt1);
214 else
215 maxlen = strlen (prompt2);
216 if (x0 < 0)
217 x0 = (ScrMaxX - 25 - 8 * maxlen) / 2;
218 if (y0 < 0)
219 y0 = (ScrMaxY - 75) / 2;
220 text_x0 = x0 + BOX_BORDER + WIDE_HSPACING;
221 text_y0 = y0 + BOX_BORDER + WIDE_VSPACING;
222 entry1_x0 = text_x0 + 13 * FONTW;
223 entry1_y0 = text_y0 + 3 * FONTH - HOLLOW_BORDER - NARROW_VSPACING;
224 entry2_x0 = entry1_x0;
225 entry2_y0 = text_y0 + 5 * FONTH - HOLLOW_BORDER - NARROW_VSPACING;
226
227 DrawScreenBox3D (x0, y0,
228 x0 + 2 * BOX_BORDER + 2 * WIDE_HSPACING
229 + y_max (entry_width + 13 * FONTW, maxlen * FONTW) - 1,
230 y0 + 2 * BOX_BORDER + 2 * WIDE_VSPACING + 6 * FONTH - 1);
231 set_colour (WHITE);
232 DrawScreenText (text_x0, text_y0, prompt1);
233 set_colour (WINFG);
234 DrawScreenText (text_x0, text_y0 + FONTH, prompt2);
235 DrawScreenText (text_x0, text_y0 + 3 * FONTH, "Start vertex");
236 DrawScreenText (text_x0, text_y0 + 5 * FONTH, "End vertex");
237
238 first = 1;
239 key = 0;
240 for (;;)
241 {
242 DrawScreenBoxHollow (entry1_x0, entry1_y0,
243 entry1_x0 + entry_width - 1, entry1_y0 + entry_height - 1, BLACK);
244 set_colour (first ? WHITE : DARKGREY);
245 DrawScreenText (entry1_x0 + HOLLOW_BORDER + NARROW_HSPACING,
246 entry1_y0 + HOLLOW_BORDER + NARROW_VSPACING, "%d", *v1);
247
248 DrawScreenBoxHollow (entry2_x0, entry2_y0,
249 entry2_x0 + entry_width - 1, entry2_y0 + entry_height - 1, BLACK);
250 set_colour (! first ? WHITE : DARKGREY);
251 DrawScreenText (entry2_x0 + HOLLOW_BORDER + NARROW_HSPACING,
252 entry2_y0 + HOLLOW_BORDER + NARROW_VSPACING, "%d", *v2);
253
254 if (first)
255 key = InputInteger (entry1_x0, entry1_y0, v1, 0, NumVertices - 1);
256 else
257 key = InputInteger (entry2_x0, entry2_y0, v2, 0, NumVertices - 1);
258 if (key==YK_LEFT || key==YK_RIGHT || key==YK_TAB || key==YK_BACKTAB)
259 first = !first;
260 else if (key == YK_ESC)
261 break;
262 else if (key == YK_RETURN)
263 {
264 if (first)
265 first = 0;
266 else if (*v1 < 0 || *v1 >= NumVertices
267 || *v2 < 0 || *v2 >= NumVertices)
268 Beep ();
269 else
270 break;
271 }
272 else
273 Beep ();
274 }
275 ShowMousePointer ();
276 return (key == YK_RETURN);
277 }
278
279
280
281 /*
282 edit an object or a group of objects
283 */
284
EditObjectsInfo(int x0,int y0,int objtype,SelPtr obj)285 void EditObjectsInfo (int x0, int y0, int objtype, SelPtr obj) /* SWAP! */
286 {
287 char *menustr[3];
288 int n, val;
289 SelPtr cur;
290 int subwin_y0;
291
292 ObjectsNeeded (objtype, 0);
293 if (! obj)
294 return;
295 switch (objtype)
296 {
297 case OBJ_THINGS:
298 ThingProperties (x0, y0, obj);
299 break;
300
301 case OBJ_VERTICES:
302 for (n = 0; n < 3; n++)
303 menustr[n] = (char *) GetMemory (60);
304 sprintf (menustr[2], "Edit Vertex #%d", obj->objnum);
305 sprintf (menustr[0], "Change X position (Current: %d)",
306 Vertices[obj->objnum].x);
307 sprintf (menustr[1], "Change Y position (Current: %d)",
308 Vertices[obj->objnum].y);
309 #ifdef OLDMEN
310 val = DisplayMenuArray (0, y0,
311 menustr[2], 2, NULL, menustr, NULL, NULL, NULL);
312 #else
313 val = vDisplayMenu (0, y0, menustr[2],
314 menustr[0], YK_, 0,
315 menustr[1], YK_, 0,
316 NULL);
317 #endif
318 for (n = 0; n < 3; n++)
319 FreeMemory (menustr[n]);
320 subwin_y0 = y0 + BOX_BORDER + (2 + val) * FONTH;
321 switch (val)
322 {
323 case 1:
324 val = InputIntegerValue (x0 + 42, subwin_y0,
325 y_min (MapMinX, -10000),
326 y_max (MapMaxX, 10000),
327 Vertices[obj->objnum].x);
328 if (val != IIV_CANCEL)
329 {
330 n = val - Vertices[obj->objnum].x;
331 for (cur = obj; cur; cur = cur->next)
332 Vertices[cur->objnum].x += n;
333 MadeChanges = 1;
334 MadeMapChanges = 1;
335 }
336 break;
337
338 case 2:
339 val = InputIntegerValue (x0 + 42, subwin_y0,
340 y_min (MapMinY, -10000),
341 y_max (MapMaxY, 10000),
342 Vertices[obj->objnum].y);
343 if (val != IIV_CANCEL)
344 {
345 n = val - Vertices[obj->objnum].y;
346 for (cur = obj; cur; cur = cur->next)
347 Vertices[cur->objnum].y += n;
348 MadeChanges = 1;
349 MadeMapChanges = 1;
350 }
351 break;
352 }
353 break;
354
355 case OBJ_LINEDEFS:
356 LinedefProperties (x0, y0, obj);
357 break;
358
359 case OBJ_SECTORS:
360 SectorProperties (x0, y0, obj);
361 break;
362 }
363 }
364
365
366 /*
367 Yuck! Dirty piece of code...
368 */
369
Input2Numbers(int x0,int y0,const char * name1,const char * name2,int v1max,int v2max,int * v1,int * v2)370 bool Input2Numbers (int x0, int y0, const char *name1, const char *name2,
371 int v1max, int v2max, int *v1, int *v2)
372 {
373 int key;
374 int maxlen, first;
375 bool ok;
376 char prompt[80];
377 // FIXME copied from InputInteger()...
378 int entry_width = 2 * HOLLOW_BORDER + 2 * NARROW_HSPACING + 7 * FONTW;
379 int entry_height = 2 * HOLLOW_BORDER + 2 * NARROW_VSPACING + FONTH;
380
381 y_snprintf (prompt, sizeof prompt, "Give the %s and %s for the object:",
382 name1, name2);
383 maxlen = strlen (prompt);
384
385 int title_x0 = BOX_BORDER + FONTW;
386 int title_y0 = BOX_BORDER + FONTH / 2;
387 int label1_x0 = title_x0;
388 int label1_y0 = title_y0 + 2 * FONTH;
389 int label2_x0 = title_x0 + (strlen (name1) + 2) * FONTW;
390 {
391 int bound = label1_x0 + entry_width + int (FONTW);
392 if (label2_x0 < bound)
393 label2_x0 = bound;
394 }
395 // FIXME Assuming the range is not longer than the name
396 int label2_y0 = label1_y0;
397 int entry1_out_x0 = label1_x0;
398 int entry1_out_y0 = label1_y0 + 3 * FONTH / 2;
399 int entry1_text_x0 = entry1_out_x0 + HOLLOW_BORDER + NARROW_HSPACING;
400 int entry1_text_y0 = entry1_out_y0 + HOLLOW_BORDER + NARROW_VSPACING;
401 int entry1_out_x1 = entry1_out_x0 + entry_width - 1;
402 int entry1_out_y1 = entry1_out_y0 + entry_height - 1;
403 int entry2_out_x0 = label2_x0;
404 int entry2_out_y0 = label2_y0 + 3 * FONTH / 2;
405 int entry2_text_x0 = entry2_out_x0 + HOLLOW_BORDER + NARROW_HSPACING;
406 int entry2_text_y0 = entry2_out_y0 + HOLLOW_BORDER + NARROW_VSPACING;
407 int entry2_out_x1 = entry2_out_x0 + entry_width - 1;
408 int entry2_out_y1 = entry2_out_y0 + entry_height - 1;
409 int range1_x0 = entry1_out_x0;
410 int range1_y0 = entry1_out_y1 + FONTH / 2;
411 int range2_x0 = entry2_out_x0;
412 int range2_y0 = entry2_out_y1 + FONTH / 2;
413 int window_x1 = entry2_out_x1 + FONTW + BOX_BORDER;
414 int window_y1 = range1_y0 + 3 * FONTH / 2 + BOX_BORDER;
415 {
416 int bound = 2 * BOX_BORDER + (maxlen + 2) * int (FONTW);
417 if (window_x1 < bound)
418 window_x1 = bound;
419 }
420
421 if (x0 < 0)
422 x0 = (ScrMaxX - window_x1) / 2;
423 if (y0 < 0)
424 y0 = (ScrMaxY - window_y1) / 2;
425
426 HideMousePointer ();
427 DrawScreenBox3D (x0, y0, x0 + window_x1, y0 + window_y1);
428 set_colour (WHITE);
429 DrawScreenText (x0 + title_x0, y0 + title_x0, prompt);
430 DrawScreenText (x0 + label1_x0, y0 + label1_y0, name1);
431 DrawScreenText (x0 + label2_x0, y0 + label2_y0, name2);
432 DrawScreenText (x0 + range1_x0, y0 + range1_y0, "(0-%d)", v1max);
433 DrawScreenText (x0 + range2_x0, y0 + range2_y0, "(0-%d)", v2max);
434
435 first = 1;
436 key = 0;
437 for (;;)
438 {
439 ok = true;
440 DrawScreenBoxHollow (x0 + entry1_out_x0, y0 + entry1_out_y0,
441 x0 + entry1_out_x1, y0 + entry1_out_y1, BLACK);
442 if (*v1 < 0 || *v1 > v1max)
443 {
444 set_colour (DARKGREY);
445 ok = false;
446 }
447 else
448 set_colour (LIGHTGREY);
449 DrawScreenText (x0 + entry1_text_x0, y0 + entry1_text_y0, "%d", *v1);
450 DrawScreenBoxHollow (x0 + entry2_out_x0, y0 + entry2_out_y0,
451 x0 + entry2_out_x1, y0 + entry2_out_y1, BLACK);
452 if (*v2 < 0 || *v2 > v2max)
453 {
454 set_colour (DARKGREY);
455 ok = false;
456 }
457 else
458 set_colour (LIGHTGREY);
459 DrawScreenText (x0 + entry2_text_x0, y0 + entry2_text_y0, "%d", *v2);
460 if (first)
461 key = InputInteger (x0 + entry1_out_x0, y0 + entry1_out_y0, v1, 0, v1max);
462 else
463 key = InputInteger (x0 + entry2_out_x0, y0 + entry2_out_y0, v2, 0, v2max);
464 if (key==YK_LEFT || key==YK_RIGHT || key==YK_TAB || key==YK_BACKTAB)
465 first = !first;
466 else if (key == YK_ESC)
467 break;
468 else if (key == YK_RETURN)
469 {
470 if (first)
471 first = 0;
472 else if (ok)
473 break;
474 else
475 Beep ();
476 }
477 else
478 Beep ();
479 }
480 ShowMousePointer ();
481 return (key == YK_RETURN);
482 }
483
484
485
486 /*
487 insert a standard object at given position
488 */
489
InsertStandardObject(int xpos,int ypos,int choice)490 void InsertStandardObject (int xpos, int ypos, int choice) /* SWAP! */
491 {
492 int sector;
493 int n;
494 int a, b;
495
496 /* show where the object will be inserted */
497 HideMousePointer ();
498 DrawPointer (1);
499 ShowMousePointer ();
500 /* are we inside a Sector? */
501 Objid o;
502 GetCurObject (o, OBJ_SECTORS, xpos, ypos);
503 sector = o.num;
504
505 /* !!!! Should also check for overlapping objects (sectors) !!!! */
506 switch (choice)
507 {
508 case 1:
509 a = 256;
510 b = 128;
511 if (Input2Numbers (-1, -1, "Width", "Height", 2000, 2000, &a, &b))
512 {
513 if (a < 8)
514 a = 8;
515 if (b < 8)
516 b = 8;
517 xpos = xpos - a / 2;
518 ypos = ypos - b / 2;
519 InsertObject (OBJ_VERTICES, -1, xpos, ypos);
520 InsertObject (OBJ_VERTICES, -1, xpos + a, ypos);
521 InsertObject (OBJ_VERTICES, -1, xpos + a, ypos + b);
522 InsertObject (OBJ_VERTICES, -1, xpos, ypos + b);
523 if (sector < 0)
524 InsertObject (OBJ_SECTORS, -1, 0, 0);
525 for (n = 0; n < 4; n++)
526 {
527 InsertObject (OBJ_LINEDEFS, -1, 0, 0);
528 LineDefs[NumLineDefs - 1].sidedef1 = NumSideDefs;
529 InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
530 if (sector >= 0)
531 SideDefs[NumSideDefs - 1].sector = sector;
532 }
533 ObjectsNeeded (OBJ_LINEDEFS, 0);
534 if (sector >= 0)
535 {
536 LineDefs[NumLineDefs - 4].start = NumVertices - 4;
537 LineDefs[NumLineDefs - 4].end = NumVertices - 3;
538 LineDefs[NumLineDefs - 3].start = NumVertices - 3;
539 LineDefs[NumLineDefs - 3].end = NumVertices - 2;
540 LineDefs[NumLineDefs - 2].start = NumVertices - 2;
541 LineDefs[NumLineDefs - 2].end = NumVertices - 1;
542 LineDefs[NumLineDefs - 1].start = NumVertices - 1;
543 LineDefs[NumLineDefs - 1].end = NumVertices - 4;
544 }
545 else
546 {
547 LineDefs[NumLineDefs - 4].start = NumVertices - 1;
548 LineDefs[NumLineDefs - 4].end = NumVertices - 2;
549 LineDefs[NumLineDefs - 3].start = NumVertices - 2;
550 LineDefs[NumLineDefs - 3].end = NumVertices - 3;
551 LineDefs[NumLineDefs - 2].start = NumVertices - 3;
552 LineDefs[NumLineDefs - 2].end = NumVertices - 4;
553 LineDefs[NumLineDefs - 1].start = NumVertices - 4;
554 LineDefs[NumLineDefs - 1].end = NumVertices - 1;
555 }
556 }
557 break;
558 case 2:
559 a = 8;
560 b = 128;
561 if (Input2Numbers (-1, -1, "Number of sides", "Radius", 32, 2000, &a, &b))
562 {
563 if (a < 3)
564 a = 3;
565 if (b < 8)
566 b = 8;
567 InsertPolygonVertices (xpos, ypos, a, b);
568 if (sector < 0)
569 InsertObject (OBJ_SECTORS, -1, 0, 0);
570 for (n = 0; n < a; n++)
571 {
572 InsertObject (OBJ_LINEDEFS, -1, 0, 0);
573 LineDefs[NumLineDefs - 1].sidedef1 = NumSideDefs;
574 InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
575 if (sector >= 0)
576 SideDefs[NumSideDefs - 1].sector = sector;
577 }
578 ObjectsNeeded (OBJ_LINEDEFS, 0);
579 if (sector >= 0)
580 {
581 LineDefs[NumLineDefs - 1].start = NumVertices - 1;
582 LineDefs[NumLineDefs - 1].end = NumVertices - a;
583 for (n = 2; n <= a; n++)
584 {
585 LineDefs[NumLineDefs - n].start = NumVertices - n;
586 LineDefs[NumLineDefs - n].end = NumVertices - n + 1;
587 }
588 }
589 else
590 {
591 LineDefs[NumLineDefs - 1].start = NumVertices - a;
592 LineDefs[NumLineDefs - 1].end = NumVertices - 1;
593 for (n = 2; n <= a; n++)
594 {
595 LineDefs[NumLineDefs - n].start = NumVertices - n + 1;
596 LineDefs[NumLineDefs - n].end = NumVertices - n;
597 }
598 }
599 }
600 break;
601 case 3:
602 /*
603 a = 6;
604 b = 16;
605 if (Input2Numbers (-1, -1, "Number of steps", "Step height", 32, 48, &a, &b))
606 {
607 if (a < 2)
608 a = 2;
609 ObjectsNeeded (OBJ_SECTORS, 0);
610 n = Sectors[sector].ceilh;
611 h = Sectors[sector].floorh;
612 if (a * b < n - h)
613 {
614 Beep ();
615 Notify (-1, -1, "The stairs are too high for this Sector", 0);
616 return;
617 }
618 xpos = xpos - 32;
619 ypos = ypos - 32 * a;
620 for (n = 0; n < a; n++)
621 {
622 InsertObject (OBJ_VERTICES, -1, xpos, ypos);
623 InsertObject (OBJ_VERTICES, -1, xpos + 64, ypos);
624 InsertObject (OBJ_VERTICES, -1, xpos + 64, ypos + 64);
625 InsertObject (OBJ_VERTICES, -1, xpos, ypos + 64);
626 ypos += 64;
627 InsertObject (OBJ_SECTORS, sector, 0, 0);
628 h += b;
629 Sectors[NumSectors - 1].floorh = h;
630
631 InsertObject (OBJ_LINEDEFS, -1, 0, 0);
632 LineDefs[NumLineDefs - 1].sidedef1 = NumSideDefs;
633 LineDefs[NumLineDefs - 1].sidedef2 = NumSideDefs + 1;
634 InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
635 SideDefs[NumSideDefs - 1].sector = sector;
636 InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
637
638 ObjectsNeeded (OBJ_LINEDEFS, 0);
639 LineDefs[NumLineDefs - 4].start = NumVertices - 4;
640 LineDefs[NumLineDefs - 4].end = NumVertices - 3;
641 LineDefs[NumLineDefs - 3].start = NumVertices - 3;
642 LineDefs[NumLineDefs - 3].end = NumVertices - 2;
643 LineDefs[NumLineDefs - 2].start = NumVertices - 2;
644 LineDefs[NumLineDefs - 2].end = NumVertices - 1;
645 LineDefs[NumLineDefs - 1].start = NumVertices - 1;
646 LineDefs[NumLineDefs - 1].end = NumVertices - 4;
647 }
648 }
649 break;
650 */
651 case 4:
652 NotImplemented ();
653 break;
654 }
655 }
656
657
658
659 /*
660 menu of miscellaneous operations
661 */
662
MiscOperations(int objtype,SelPtr * list,int val)663 void MiscOperations (int objtype, SelPtr *list, int val) /* SWAP! */
664 {
665 char msg[80];
666 int angle, scale;
667
668 if (val > 1 && ! *list)
669 {
670 Beep ();
671 sprintf (msg, "You must select at least one %s", GetObjectTypeName (objtype));
672 Notify (-1, -1, msg, 0);
673 return;
674 }
675
676 /* I think this switch statement deserves a prize for "worst
677 gratuitous obfuscation" or something. -- AYM 2000-11-07 */
678 switch (val)
679 {
680 case 1:
681 // * -> First free tag number
682 sprintf (msg, "First free tag number: %d", FindFreeTag ());
683 Notify (-1, -1, msg, 0);
684 break;
685
686 case 2:
687 // * -> Rotate and scale
688 if ((objtype == OBJ_THINGS
689 || objtype == OBJ_VERTICES) && ! (*list)->next)
690 {
691 Beep ();
692 sprintf (msg, "You must select more than one %s",
693 GetObjectTypeName (objtype));
694 Notify (-1, -1, msg, 0);
695 return;
696 }
697 angle = 0;
698 scale = 100;
699 if (Input2Numbers (-1, -1, "rotation angle (�)", "scale (%)",
700 360, 1000, &angle, &scale))
701 RotateAndScaleObjects (objtype, *list, (double) angle * 0.0174533,
702 (double) scale * 0.01);
703 break;
704
705 case 3:
706 // Linedef -> Split
707 if (objtype == OBJ_LINEDEFS)
708 {
709 SplitLineDefs (*list);
710 }
711 // Sector -> Make door from sector
712 else if (objtype == OBJ_SECTORS)
713 {
714 if ((*list)->next)
715 {
716 Beep ();
717 Notify (-1, -1, "You must select exactly one sector", 0);
718 }
719 else
720 {
721 MakeDoorFromSector ((*list)->objnum);
722 }
723 }
724 // Thing -> Spin 45� clockwise
725 else if (objtype == OBJ_THINGS)
726 {
727 spin_things (*list, -45);
728 }
729 // Vertex -> Delete and join linedefs
730 else if (objtype == OBJ_VERTICES)
731 {
732 DeleteVerticesJoinLineDefs (*list);
733 ForgetSelection (list);
734 }
735 break;
736
737 case 4:
738 // Linedef -> Split linedefs and sector
739 if (objtype == OBJ_LINEDEFS)
740 {
741 if (! (*list)->next || (*list)->next->next)
742 {
743 Beep ();
744 Notify (-1, -1, "You must select exactly two linedefs", 0);
745 }
746 else
747 {
748 SplitLineDefsAndSector ((*list)->next->objnum, (*list)->objnum);
749 ForgetSelection (list);
750 }
751 }
752 // Sector -> Make lift from sector
753 else if (objtype == OBJ_SECTORS)
754 {
755 if ((*list)->next)
756 {
757 Beep ();
758 Notify (-1, -1, "You must select exactly one Sector", 0);
759 }
760 else
761 {
762 MakeLiftFromSector ((*list)->objnum);
763 }
764 }
765 // Thing -> Spin 45� counter-clockwise
766 else if (objtype == OBJ_THINGS)
767 spin_things (*list, 45);
768 // Vertex -> Merge
769 else if (objtype == OBJ_VERTICES)
770 {
771 MergeVertices (list);
772 }
773 break;
774
775 case 5:
776 // Linedef -> Delete linedefs and join sectors
777 if (objtype == OBJ_LINEDEFS)
778 {
779 DeleteLineDefsJoinSectors (list);
780 }
781 // Sector -> Distribute sector floor heights
782 else if (objtype == OBJ_SECTORS)
783 {
784 if (! (*list)->next || ! (*list)->next->next)
785 {
786 Beep ();
787 Notify (-1, -1, "You must select three or more sectors", 0);
788 }
789 else
790 {
791 DistributeSectorFloors (*list);
792 }
793 }
794 // Thing -> Mirror horizontally
795 else if (objtype == OBJ_THINGS)
796 {
797 flip_mirror (*list, OBJ_THINGS, 'm');
798 }
799 // Vertex -> Add linedef and split sector
800 else if (objtype == OBJ_VERTICES)
801 {
802 if (! (*list)->next || (*list)->next->next)
803 {
804 Beep ();
805 Notify (-1, -1, "You must select exactly two vertices", 0);
806 }
807 else
808 {
809 SplitSector ((*list)->next->objnum, (*list)->objnum);
810 ForgetSelection (list);
811 }
812 }
813 break;
814
815 case 6:
816 // Linedef -> Flip
817 if (objtype == OBJ_LINEDEFS)
818 {
819 FlipLineDefs (*list, 1);
820 }
821 // Sector -> Distribute ceiling heights
822 else if (objtype == OBJ_SECTORS)
823 {
824 if (! (*list)->next || ! (*list)->next->next)
825 {
826 Beep ();
827 Notify (-1, -1, "You must select three or more sectors", 0);
828 }
829 else
830 {
831 DistributeSectorCeilings (*list);
832 }
833 }
834 // Things -> Mirror vertically
835 else if (objtype == OBJ_THINGS)
836 {
837 flip_mirror (*list, OBJ_THINGS, 'f');
838 }
839 // Vertex -> Mirror horizontally
840 else if (objtype == OBJ_VERTICES)
841 {
842 flip_mirror (*list, OBJ_VERTICES, 'm');
843 }
844 break;
845
846 case 7:
847 // Linedefs -> Swap sidedefs
848 if (objtype == OBJ_LINEDEFS)
849 {
850 if (Expert
851 || blindly_swap_sidedefs
852 || Confirm (-1, -1,
853 "Warning: the sector references are also swapped",
854 "You may get strange results if you don't know what you are doing..."))
855 FlipLineDefs (*list, 0);
856 }
857 // Sectors -> Raise or lower
858 else if (objtype == OBJ_SECTORS)
859 {
860 RaiseOrLowerSectors (*list);
861 }
862 // Vertices -> Mirror vertically
863 else if (objtype == OBJ_VERTICES)
864 {
865 flip_mirror (*list, OBJ_VERTICES, 'f');
866 }
867 break;
868
869 case 8:
870 // Linedef -> Align textures vertically
871 if (objtype == OBJ_LINEDEFS)
872 {
873 SelPtr sdlist, cur;
874
875 /* select all sidedefs */
876 ObjectsNeeded (OBJ_LINEDEFS);
877 sdlist = 0;
878 for (cur = *list; cur; cur = cur->next)
879 {
880 if (LineDefs[cur->objnum].sidedef1 >= 0)
881 SelectObject (&sdlist, LineDefs[cur->objnum].sidedef1);
882 if (LineDefs[cur->objnum].sidedef2 >= 0)
883 SelectObject (&sdlist, LineDefs[cur->objnum].sidedef2);
884 }
885 /* align the textures along the Y axis (height) */
886 AlignTexturesY (&sdlist);
887 }
888 // Sector -> Brighten or darken
889 else if (objtype == OBJ_SECTORS)
890 {
891 BrightenOrDarkenSectors (*list);
892 }
893 break;
894
895 case 9:
896 // Linedef -> Align texture horizontally
897 if (objtype == OBJ_LINEDEFS)
898 {
899 SelPtr sdlist, cur;
900
901 /* select all sidedefs */
902 ObjectsNeeded (OBJ_LINEDEFS,0);
903 sdlist = 0;
904 for (cur = *list; cur; cur = cur->next)
905 {
906 if (LineDefs[cur->objnum].sidedef1 >= 0)
907 SelectObject (&sdlist, LineDefs[cur->objnum].sidedef1);
908 if (LineDefs[cur->objnum].sidedef2 >= 0)
909 SelectObject (&sdlist, LineDefs[cur->objnum].sidedef2);
910 }
911 /* align the textures along the X axis (width) */
912 AlignTexturesX (&sdlist);
913 }
914 // Sector -> Unlink room
915 else if (objtype == OBJ_SECTORS)
916 {
917 NotImplemented (); // FIXME
918 break;
919 }
920 break;
921
922 case 10:
923 // Linedef -> Make linedef single-sided
924 if (objtype == OBJ_LINEDEFS)
925 {
926 SelPtr cur;
927 ObjectsNeeded (OBJ_LINEDEFS, 0);
928 for (cur = *list; cur; cur = cur->next)
929 {
930 struct LineDef *l = LineDefs + cur->objnum;
931 l->sidedef2 = -1; /* remove ref. to 2nd SD */
932 l->flags &= ~0x04; /* clear "2S" bit */
933 l->flags |= 0x01; /* set "Im" bit */
934
935 if (is_sidedef (l->sidedef1))
936 {
937 struct SideDef *s = SideDefs + l->sidedef1;
938 strcpy (s->tex1, "-");
939 strcpy (s->tex2, "-");
940 strcpy (s->tex3, default_middle_texture);
941 }
942 /* Don't delete the 2nd sidedef, it could be used
943 by another linedef. And if it isn't, the next
944 cross-references check will delete it anyway. */
945 }
946 }
947 // Sector -> Mirror horizontally
948 else if (objtype == OBJ_SECTORS)
949 {
950 flip_mirror (*list, OBJ_SECTORS, 'm');
951 }
952 break;
953
954 case 11:
955 // Linedef -> Make rectangular nook
956 if (objtype == OBJ_LINEDEFS)
957 MakeRectangularNook (*list, 32, 16, 0);
958 // Sector -> Mirror vertically
959 else if (objtype == OBJ_SECTORS)
960 {
961 flip_mirror (*list, OBJ_SECTORS, 'f');
962 }
963 break;
964
965 case 12:
966 // Linedef -> Make rectangular boss
967 if (objtype == OBJ_LINEDEFS)
968 MakeRectangularNook (*list, 32, 16, 1);
969 // Sector -> Swap flats
970 else if (objtype == OBJ_SECTORS)
971 swap_flats (*list);
972 break;
973
974 case 13:
975 // Linedef -> Set length (1st vertex)
976 if (objtype == OBJ_LINEDEFS)
977 {
978 static int length = 24;
979 length = InputIntegerValue (-1, -1, -10000, 10000, length);
980 if (length != IIV_CANCEL)
981 SetLinedefLength (*list, length, 0);
982 }
983 break;
984
985 case 14:
986 // Linedef -> Set length (2nd vertex)
987 if (objtype == OBJ_LINEDEFS)
988 {
989 static int length = 24;
990 length = InputIntegerValue (-1, -1, -10000, 10000, length);
991 if (length != IIV_CANCEL)
992 SetLinedefLength (*list, length, 1);
993 }
994 break;
995
996 case 15:
997 // Linedef -> Unlink 1st sidedef
998 if (objtype == OBJ_LINEDEFS)
999 unlink_sidedef (*list, 1, 0);
1000 break;
1001
1002 case 16:
1003 // Linedef -> Unlink 2nd sidedef
1004 if (objtype == OBJ_LINEDEFS)
1005 unlink_sidedef (*list, 0, 1);
1006 break;
1007
1008 case 17:
1009 // Linedef -> Mirror horizontally
1010 flip_mirror (*list, OBJ_LINEDEFS, 'm');
1011 break;
1012
1013 case 18 :
1014 // Linedef -> Mirror vertically
1015 flip_mirror (*list, OBJ_LINEDEFS, 'f');
1016 break;
1017
1018 case 19 :
1019 // Linedef -> Cut a slice out of a sector
1020 if (objtype == OBJ_LINEDEFS)
1021 {
1022 if (! (*list)->next || (*list)->next->next)
1023 {
1024 Beep ();
1025 Notify (-1, -1, "You must select exactly two linedefs", 0);
1026 }
1027 else
1028 {
1029 sector_slice ((*list)->next->objnum, (*list)->objnum);
1030 ForgetSelection (list);
1031 }
1032 }
1033 break;
1034 }
1035 }
1036
1037
1038
1039