home *** CD-ROM | disk | FTP | other *** search
/ Superpower (Alt) / SUPERPOWER.iso / q / source / map.m < prev    next >
Encoding:
Text File  |  1996-08-08  |  18.5 KB  |  1,122 lines

  1.  
  2. #include "qedefs.h"
  3.  
  4. id    map_i;
  5.  
  6. @implementation Map
  7.  
  8. /*
  9. ===============================================================================
  10.  
  11. FILE METHODS
  12.  
  13. ===============================================================================
  14. */
  15.  
  16. - init
  17. {
  18.     [super init];
  19.     map_i = self;
  20.     minz = 0;
  21.     maxz = 80;
  22.     
  23.     oldselection = [[List alloc] init];
  24.     
  25.     return self;
  26. }
  27.  
  28. - saveSelected
  29. {
  30.     int        i, c;
  31.     id        o, w;
  32.     
  33.     [oldselection empty];
  34.     w = [self objectAt: 0];
  35.     c = [w count];
  36.     sb_newowner = oldselection;
  37.     for (i=0 ; i<c ; i++)
  38.     {
  39.         o = [w objectAt: 0];
  40.         if ([o selected])
  41.             [o moveToEntity];
  42.         else
  43.         {
  44.             [w removeObjectAt: 0];
  45.             [o free];
  46.         }
  47.     }
  48.     
  49.     c = [self count];
  50.     for (i=0 ; i<c ; i++)
  51.     {
  52.         o = [self objectAt: 0];
  53.         [self removeObjectAt: 0];
  54.         [o freeObjects];
  55.         [o free];
  56.     }
  57.  
  58.     return self;
  59. }
  60.  
  61. - addSelected
  62. {
  63.     int        i, c;
  64.     id        n, w;
  65.     
  66.     c = [oldselection count];
  67.     w = [self objectAt: 0];    // world object
  68.  
  69.     sb_newowner = w;
  70.     for (i=0 ; i<c ; i++)
  71.     {
  72.         n = [oldselection objectAt:i];
  73.         [n moveToEntity];
  74.         i--;
  75.         c--;
  76.     }
  77.     [oldselection empty];
  78.     
  79.     return self;
  80. }
  81.  
  82.  
  83. - newMap
  84. {
  85.     id    ent;
  86.     
  87.     [self saveSelected];
  88.     ent = [[Entity alloc] initClass: "worldspawn"];
  89.     [self addObject: ent];
  90.     currentEntity = NULL;
  91.     [self setCurrentEntity: ent];
  92.     [self addSelected];
  93.  
  94.     return self;
  95. }
  96.  
  97. - currentEntity
  98. {
  99.     return currentEntity;
  100. }
  101.  
  102. - setCurrentEntity: ent
  103. {
  104.     id    old;
  105.     
  106.     old = currentEntity;
  107.     currentEntity = ent;
  108.     if (old != ent)
  109.     {
  110.         [things_i newCurrentEntity];    // update inspector
  111.         [inspcontrol_i changeInspectorTo:i_things];
  112.     }
  113.     
  114.     return self;
  115. }
  116.  
  117. - (float)currentMinZ
  118. {
  119.     float    grid;
  120.     
  121.     grid = [xyview_i gridsize];
  122.     minz = grid * rint(minz/grid);
  123.     return minz;
  124. }
  125.  
  126. - setCurrentMinZ: (float)m
  127. {
  128.     if (m > -2048)
  129.         minz = m;
  130.     return self;
  131. }
  132.  
  133. - (float)currentMaxZ
  134. {
  135.     float    grid;
  136.     
  137.     [self currentMinZ];    // grid align
  138.     
  139.     grid = [xyview_i gridsize];
  140.     maxz = grid * rint(maxz/grid);
  141.  
  142.     if (maxz <= minz)
  143.         maxz = minz + grid;
  144.     return maxz;
  145. }
  146.  
  147. - setCurrentMaxZ: (float)m
  148. {
  149.     if (m < 2048)
  150.         maxz = m;
  151.     return self;
  152. }
  153.  
  154. - removeObject: o
  155. {
  156.     o = [super removeObject: o];
  157.     
  158.     if (o == currentEntity)
  159.     {    // select the world
  160.         [self setCurrentEntity: [self objectAt: 0]];
  161.     }
  162.  
  163.     return o;
  164. }
  165.  
  166. - writeStats
  167. {
  168.     FILE    *f;
  169.     extern    int    c_updateall;
  170.     struct timeval tp;
  171.     struct timezone tzp;
  172.  
  173.     gettimeofday(&tp, &tzp);
  174.     
  175.     f = fopen (FN_DEVLOG, "a");
  176.     fprintf (f,"%i %i\n", (int)tp.tv_sec, c_updateall);
  177.     c_updateall = 0;
  178.     fclose (f);
  179.     return self;
  180. }
  181.  
  182. - (int)numSelected
  183. {
  184.     int        i, c;
  185.     int        num;
  186.     
  187.     num = 0;
  188.     c = [currentEntity count];
  189.     for (i=0 ; i<c ; i++)
  190.         if ( [[currentEntity objectAt: i] selected] )
  191.             num++;
  192.     return num;
  193. }
  194.  
  195. - selectedBrush
  196. {
  197.     int        i, c;
  198.     int        num;
  199.     
  200.     num = 0;
  201.     c = [currentEntity count];
  202.     for (i=0 ; i<c ; i++)
  203.         if ( [[currentEntity objectAt: i] selected] )
  204.             return [currentEntity objectAt: i];
  205.     return nil;
  206. }
  207.  
  208.  
  209. /*
  210. =================
  211. readMapFile
  212. =================
  213. */
  214. - readMapFile: (char *)fname
  215. {
  216.     char    *dat, *cl;
  217.     id        new;
  218.     id        ent;
  219.     int        i, c;
  220.     vec3_t    org;
  221.     float    angle;
  222.     
  223.     [self saveSelected];
  224.     
  225.     qprintf ("loading %s\n", fname);
  226.  
  227.     LoadFile (fname, (void **)&dat);
  228.     StartTokenParsing (dat);
  229.  
  230.     do
  231.     {
  232.         new = [[Entity alloc] initFromTokens];
  233.         if (!new)
  234.             break;
  235.         [self addObject: new];        
  236.     } while (1);
  237.  
  238.     free (dat);
  239.  
  240.     [self setCurrentEntity: [self objectAt: 0]];
  241.  
  242.     [self addSelected];
  243.         
  244. // load the apropriate texture wad
  245.     dat = [currentEntity valueForQKey: "wad"];
  246.     if (dat && dat[0])
  247.     {
  248.         if (dat[0] == '/')    // remove old style fullpaths
  249.             [currentEntity removeKeyPair: "wad"];
  250.         else
  251.         {
  252.             if (strcmp ([texturepalette_i currentWad], dat) )
  253.                 [project_i     setTextureWad: dat];
  254.         }
  255.     }
  256.  
  257. // center the camera and XY view on the playerstart
  258.     c = [self count];
  259.     for (i=1 ; i<c ; i++)
  260.     {
  261.         ent = [self objectAt: i];
  262.         cl = [ent valueForQKey: "classname"];
  263.         if (cl && !strcasecmp (cl,"info_player_start"))
  264.         {
  265.             angle = atof( [ent valueForQKey: "angle"] );
  266.             angle = angle/180*M_PI;
  267.             [ent getVector: org forKey: "origin"];
  268.             [cameraview_i setOrigin: org angle:angle];
  269.             [xyview_i centerOn: org];
  270.             break;
  271.         }
  272.     }
  273.     
  274.     return self;
  275. }
  276.  
  277. /*
  278. =================
  279. writeMapFile
  280. =================
  281. */
  282. - writeMapFile: (char *)fname useRegion: (BOOL)reg
  283. {
  284.     FILE    *f;
  285.     int        i;
  286.     
  287.     qprintf ("writeMapFile: %s", fname);
  288.     
  289.     f = fopen (fname,"w");
  290.     if (!f)
  291.         Error ("couldn't write %s", fname);
  292.     
  293.     for (i=0 ; i<numElements ; i++)
  294.         [[self objectAt: i] writeToFILE: f region: reg];
  295.             
  296.     fclose (f);
  297.     
  298.     return self;
  299. }
  300.  
  301. /*
  302. ==============================================================================
  303.  
  304. DRAWING
  305.  
  306. ==============================================================================
  307. */
  308.  
  309. - ZDrawSelf
  310. {
  311.     int        i, count;
  312.     
  313.     count = [self count];
  314.  
  315.     for (i=0 ; i<count ; i++)
  316.         [[self objectAt: i] ZDrawSelf];
  317.  
  318.     return self;
  319. }
  320.  
  321. - RenderSelf: (void (*) (face_t *))callback
  322. {
  323.     int        i, count;
  324.     
  325.     count = [self count];
  326.  
  327.     for (i=0 ; i<count ; i++)
  328.         [[self objectAt: i] RenderSelf: callback];
  329.  
  330.     return self;
  331. }
  332.  
  333.  
  334. //============================================================================
  335.  
  336.  
  337. /*
  338. ===================
  339. entityConnect
  340.  
  341. A command-shift-click on an entity while an entity is selected will
  342. make a target connection from the original entity.
  343. ===================
  344. */
  345. - entityConnect: (vec3_t)p1 : (vec3_t)p2
  346. {
  347.     id    oldent, ent;
  348.     
  349.     oldent = [self currentEntity];
  350.     if (oldent == [self objectAt: 0])
  351.     {
  352.         qprintf ("Must have a non-world entity selected to connect");
  353.         return self;
  354.     }
  355.  
  356.     [self selectRay: p1 : p2 : YES];
  357.     ent = [self currentEntity];
  358.     if (ent == oldent)
  359.     {
  360.         qprintf ("Must click on a different entity to connect");
  361.         return self;
  362.     }
  363.     
  364.     if (ent == [self objectAt: 0])
  365.     {
  366.         qprintf ("Must click on a non-world entity to connect");
  367.         return self;
  368.     }
  369.     
  370.     [oldent setKey:"target" toValue: [ent targetname]];
  371.     [quakeed_i updateAll];
  372.  
  373.     return self;
  374. }
  375.  
  376.  
  377. /*
  378. =================
  379. selectRay
  380.  
  381. If ef is true, any entity brush along the ray will be selected in preference
  382. to intervening world brushes
  383. =================
  384. */
  385. - selectRay: (vec3_t)p1 : (vec3_t)p2 : (BOOL)ef
  386. {
  387.     int        i, j, c, c2;
  388.     id        ent, bestent;
  389.     id        brush, bestbrush;
  390.     int        face, bestface;
  391.     float    time, besttime;
  392.     texturedef_t    *td;
  393.     
  394.     bestent = nil;
  395.     bestface = -1;
  396.     bestbrush = nil;
  397.     besttime = 99999;
  398.     
  399.     c = [self count];
  400.     for (i=c-1 ; i>=0 ; i--)
  401.     {
  402.         ent = [self objectAt: i];
  403.         c2 = [ent count];
  404.         for (j=0 ; j<c2 ; j++)
  405.         {
  406.             brush = [ent objectAt: j];
  407.             [brush hitByRay: p1 : p2 : &time : &face];
  408.             if (time < 0 || time >besttime)
  409.                 continue;
  410.             bestent = ent;
  411.             besttime = time;
  412.             bestbrush = brush;
  413.             bestface = face;
  414.         }
  415.         if (i == 1 && ef && bestbrush)
  416.             break;        // found an entity, so don't check the world
  417.     }
  418.     
  419.     if (besttime == 99999)
  420.     {
  421.         qprintf ("trace missed");
  422.         return self;
  423.     }
  424.  
  425.     if ( [bestbrush regioned] )
  426.     {
  427.         qprintf ("WANRING: clicked on regioned brush");
  428.         return self;
  429.     }
  430.     
  431.     if (bestent != currentEntity)
  432.     {
  433.         [self makeSelectedPerform: @selector(deselect)];
  434.         [self setCurrentEntity: bestent];
  435.     }
  436.     
  437.     [quakeed_i disableFlushWindow];
  438.     if ( ![bestbrush selected] )
  439.     {
  440.         if ( [map_i numSelected] == 0)
  441.         {    // don't grab texture if others are selected
  442.             td = [bestbrush texturedefForFace: bestface];
  443.             [texturepalette_i setTextureDef: td];
  444.         }
  445.  
  446.         [bestbrush setSelected: YES];
  447.         qprintf ("selected entity %i brush %i face %i", [self indexOf:bestent], [bestent indexOf: bestbrush], bestface);
  448.     }
  449.     else 
  450.     {
  451.         [bestbrush setSelected: NO];
  452.         qprintf ("deselected entity %i brush %i face %i", [self indexOf:bestent], [bestent indexOf: bestbrush], bestface);
  453.     }
  454.  
  455.     [quakeed_i reenableFlushWindow];
  456.     [quakeed_i updateAll];
  457.     
  458.     return self;
  459. }
  460.  
  461. /*
  462. =================
  463. grabRay
  464.  
  465. only checks the selected brushes
  466. Returns the brush hit, or nil if missed.
  467. =================
  468. */
  469. - grabRay: (vec3_t)p1 : (vec3_t)p2
  470. {
  471.     int        i, j, c, c2;
  472.     id        ent;
  473.     id        brush, bestbrush;
  474.     int        face;
  475.     float    time, besttime;
  476.     
  477.     bestbrush = nil;
  478.     besttime = 99999;
  479.     
  480.     c = [self count];
  481.     for (i=0 ; i<c ; i++)
  482.     {
  483.         ent = [self objectAt: i];        
  484.         c2 = [ent count];
  485.         for (j=0 ; j<c2 ; j++)
  486.         {
  487.             brush = [ent objectAt: j];
  488.             if (![brush selected])
  489.                 continue;
  490.             [brush hitByRay: p1 : p2 : &time : &face];
  491.             if (time < 0 || time >besttime)
  492.                 continue;
  493.             besttime = time;
  494.             bestbrush = brush;
  495.         }
  496.     }
  497.     
  498.     if (besttime == 99999)
  499.         return nil;
  500.     
  501.     return bestbrush;
  502. }
  503.  
  504. /*
  505. =================
  506. getTextureRay
  507. =================
  508. */
  509. - getTextureRay: (vec3_t)p1 : (vec3_t)p2
  510. {
  511.     int        i, j, c, c2;
  512.     id        ent, bestent;
  513.     id        brush, bestbrush;
  514.     int        face, bestface;
  515.     float    time, besttime;
  516.     texturedef_t    *td;
  517.     vec3_t    mins, maxs;        
  518.  
  519.  
  520.     bestbrush = nil;
  521.     bestent = nil;
  522.     besttime = 99999;
  523.     bestface = -1;
  524.     c = [self count];
  525.     for (i=0 ; i<c ; i++)
  526.     {
  527.         ent = [self objectAt: i];        
  528.         c2 = [ent count];
  529.         for (j=0 ; j<c2 ; j++)
  530.         {
  531.             brush = [ent objectAt: j];
  532.             [brush hitByRay: p1 : p2 : &time : &face];
  533.             if (time < 0 || time >besttime)
  534.                 continue;
  535.             bestent = ent;
  536.             bestface = face;
  537.             besttime = time;
  538.             bestbrush = brush;
  539.         }
  540.     }
  541.     
  542.     if (besttime == 99999)
  543.         return nil;
  544.  
  545.     if ( ![bestent modifiable])
  546.     {
  547.         qprintf ("can't modify spawned entities");
  548.         return self;
  549.     }
  550.     
  551.     td = [bestbrush texturedefForFace: bestface];
  552.     [texturepalette_i setTextureDef: td];
  553.     
  554.     qprintf ("grabbed texturedef and sizes");
  555.     
  556.     [bestbrush getMins: mins maxs: maxs];
  557.     
  558.     minz = mins[2];
  559.     maxz = maxs[2];
  560.     
  561.     return bestbrush;
  562. }
  563.  
  564. /*
  565. =================
  566. setTextureRay
  567. =================
  568. */
  569. - setTextureRay: (vec3_t)p1 : (vec3_t)p2 : (BOOL)allsides;
  570. {
  571.     int        i, j, c, c2;
  572.     id        ent, bestent;
  573.     id        brush, bestbrush;
  574.     int        face, bestface;
  575.     float    time, besttime;
  576.     texturedef_t    td;
  577.         
  578.     bestent = nil;
  579.     bestface = -1;
  580.     bestbrush = nil;
  581.     besttime = 99999;
  582.     
  583.     c = [self count];
  584.     for (i=0 ; i<c ; i++)
  585.     {
  586.         ent = [self objectAt: i];        
  587.         c2 = [ent count];
  588.         for (j=0 ; j<c2 ; j++)
  589.         {
  590.             brush = [ent objectAt: j];
  591.             [brush hitByRay: p1 : p2 : &time : &face];
  592.             if (time < 0 || time >besttime)
  593.                 continue;
  594.             bestent = ent;
  595.             besttime = time;
  596.             bestbrush = brush;
  597.             bestface = face;
  598.         }
  599.     }
  600.     
  601.     if (besttime == 99999)
  602.     {
  603.         qprintf ("trace missed");
  604.         return self;
  605.     }
  606.  
  607.     if ( ![bestent modifiable])
  608.     {
  609.         qprintf ("can't modify spawned entities");
  610.         return self;
  611.     }
  612.     
  613.     if ( [bestbrush regioned] )
  614.     {
  615.         qprintf ("WANRING: clicked on regioned brush");
  616.         return self;
  617.     }
  618.     
  619.     [texturepalette_i getTextureDef: &td];
  620.     
  621.     [quakeed_i disableFlushWindow];
  622.     if (allsides)
  623.     {
  624.         [bestbrush setTexturedef: &td];
  625.         qprintf ("textured entity %i brush %i", [self indexOf:bestent], [bestent indexOf: bestbrush]);
  626.     }
  627.     else 
  628.     {
  629.         [bestbrush setTexturedef: &td forFace: bestface];
  630.         qprintf ("deselected entity %i brush %i face %i", [self indexOf:bestent], [bestent indexOf: bestbrush], bestface);
  631.     }
  632.     [quakeed_i reenableFlushWindow];
  633.         
  634.     [quakeed_i updateAll];
  635.     
  636.     return self;
  637. }
  638.  
  639.  
  640. /*
  641. ==============================================================================
  642.  
  643. OPERATIONS ON SELECTIONS
  644.  
  645. ==============================================================================
  646. */
  647.  
  648. - makeSelectedPerform: (SEL)sel
  649. {
  650.     int    i,j, c, c2;
  651.     id    ent, brush;
  652.     int    total;
  653.     
  654.     total = 0;
  655.     c = [self count];
  656.     for (i=c-1 ; i>=0 ; i--)
  657.     {
  658.         ent = [self objectAt: i];
  659.         c2 = [ent count];
  660.         for (j = c2-1 ; j >=0 ; j--)
  661.         {
  662.             brush = [ent objectAt: j];
  663.             if (! [brush selected] )
  664.                 continue;
  665.             if ([brush regioned])
  666.                 continue;
  667.             total++;
  668.             [brush perform:sel];
  669.         }
  670.     }
  671.  
  672. //    if (!total)
  673. //        qprintf ("nothing selected");
  674.         
  675.     return self;    
  676. }
  677.  
  678. - makeUnselectedPerform: (SEL)sel
  679. {
  680.     int    i,j, c, c2;
  681.     id    ent, brush;
  682.     
  683.     c = [self count];
  684.     for (i=c-1 ; i>=0 ; i--)
  685.     {
  686.         ent = [self objectAt: i];
  687.         c2 = [ent count];
  688.         for (j = c2-1 ; j >=0 ; j--)
  689.         {
  690.             brush = [ent objectAt: j];
  691.             if ( [brush selected] )
  692.                 continue;
  693.             if ([brush regioned])
  694.                 continue;
  695.             [brush perform:sel];
  696.         }
  697.     }
  698.  
  699.     return self;    
  700. }
  701.  
  702. - makeAllPerform: (SEL)sel
  703. {
  704.     int    i,j, c, c2;
  705.     id    ent, brush;
  706.     
  707.     c = [self count];
  708.     for (i=c-1 ; i>=0 ; i--)
  709.     {
  710.         ent = [self objectAt: i];
  711.         c2 = [ent count];
  712.         for (j = c2-1 ; j >=0 ; j--)
  713.         {
  714.             brush = [ent objectAt: j];
  715.             if ([brush regioned])
  716.                 continue;
  717.             [brush perform:sel];
  718.         }
  719.     }
  720.  
  721.     return self;    
  722. }
  723.  
  724. - makeGlobalPerform: (SEL)sel    // in and out of region
  725. {
  726.     int    i,j, c, c2;
  727.     id    ent, brush;
  728.     
  729.     c = [self count];
  730.     for (i=c-1 ; i>=0 ; i--)
  731.     {
  732.         ent = [self objectAt: i];
  733.         c2 = [ent count];
  734.         for (j = c2-1 ; j >=0 ; j--)
  735.         {
  736.             brush = [ent objectAt: j];
  737.             [brush perform:sel];
  738.         }
  739.     }
  740.  
  741.     return self;    
  742. }
  743.  
  744.  
  745. void sel_identity (void)
  746. {
  747.     sel_x[0]=1; sel_x[1]=0; sel_x[2]=0;
  748.     sel_y[0]=0; sel_y[1]=1; sel_y[2]=0;
  749.     sel_z[0]=0; sel_z[1]=0; sel_z[2]=1;
  750. }
  751.  
  752. - transformSelection
  753. {
  754.     if ( ![currentEntity modifiable])
  755.     {
  756.         qprintf ("can't modify spawned entities");
  757.         return self;
  758.     }
  759.  
  760. // find an origin to apply the transformation to
  761.     sb_mins[0] = sb_mins[1] = sb_mins[2] = 99999;
  762.     sb_maxs[0] = sb_maxs[1] = sb_maxs[2] = -99999;
  763.     [self makeSelectedPerform: @selector(addToBBox)];
  764.     sel_org[0] = [xyview_i snapToGrid: (sb_mins[0] + sb_maxs[0])/2];
  765.     sel_org[1] = [xyview_i snapToGrid: (sb_mins[1] + sb_maxs[1])/2];
  766.     sel_org[2] = [xyview_i snapToGrid: (sb_mins[2] + sb_maxs[2])/2];
  767.     
  768. // do it!
  769.     [self makeSelectedPerform: @selector(transform)];
  770.  
  771.     [quakeed_i updateAll];
  772.     return self;
  773. }
  774.  
  775.  
  776. void swapvectors (vec3_t a, vec3_t b)
  777. {
  778.     vec3_t    temp;
  779.     
  780.     VectorCopy (a, temp);
  781.     VectorCopy (b, a);
  782.     VectorSubtract (vec3_origin, temp, b);
  783. }
  784.  
  785. /*
  786. ===============================================================================
  787.  
  788. UI operations
  789.  
  790. ===============================================================================
  791. */
  792.  
  793. - rotate_x: sender
  794. {
  795.     sel_identity ();
  796.     swapvectors(sel_y, sel_z);
  797.     [self transformSelection];
  798.     return self;
  799. }
  800.  
  801. - rotate_y: sender
  802. {
  803.     sel_identity ();
  804.     swapvectors(sel_x, sel_z);
  805.     [self transformSelection];
  806.     return self;
  807. }
  808.  
  809. - rotate_z: sender
  810. {
  811.     sel_identity ();
  812.     swapvectors(sel_x, sel_y);
  813.     [self transformSelection];
  814.     return self;
  815. }
  816.  
  817.  
  818. - flip_x: sender
  819. {
  820.     sel_identity ();
  821.     sel_x[0] = -1;
  822.     [self transformSelection];
  823.     [map_i makeSelectedPerform: @selector(flipNormals)];
  824.     return self;
  825. }
  826.  
  827. - flip_y: sender
  828. {
  829.     sel_identity ();
  830.     sel_y[1] = -1;
  831.     [self transformSelection];
  832.     [map_i makeSelectedPerform: @selector(flipNormals)];
  833.     return self;
  834. }
  835.  
  836.  
  837. - flip_z: sender
  838. {
  839.     sel_identity ();
  840.     sel_z[2] = -1;
  841.     [self transformSelection];
  842.     [map_i makeSelectedPerform: @selector(flipNormals)];
  843.     return self;
  844. }
  845.  
  846.  
  847. - cloneSelection: sender
  848. {
  849.     int        i,j , c, originalElements;
  850.     id        o, b;
  851.     id        new;
  852.     
  853.     sb_translate[0] = sb_translate[1] = [xyview_i gridsize];
  854.     sb_translate[2] = 0;
  855.  
  856. // copy individual brushes in the world entity
  857.     o = [self objectAt: 0];
  858.     c = [o count];
  859.     for (i=0 ; i<c ; i++)
  860.     {
  861.         b = [o objectAt: i];
  862.         if (![b selected])
  863.             continue;
  864.             
  865.     // copy the brush, then translate the original
  866.         new = [b copy];
  867.         [new setSelected: YES];
  868.         [new translate];
  869.         [b setSelected: NO];
  870.         [o addObject: new];
  871.     }
  872.     
  873. // copy entire entities otherwise
  874.     originalElements = numElements;    // don't copy the new ones
  875.     for (i=1 ; i<originalElements ; i++)
  876.     {
  877.         o = [self objectAt: i];
  878.         if (![[o objectAt: 0] selected])
  879.             continue;
  880.  
  881.         new = [o copy];
  882.         [self addObject: new];
  883.  
  884.         c = [o count];
  885.         for (j=0 ; j<c ; j++)
  886.             [[o objectAt: j] setSelected: NO];
  887.         
  888.         c = [new count];
  889.         for (j=0 ; j<c ; j++)
  890.         {
  891.             b = [new objectAt: j];
  892.             [b translate];
  893.             [b setSelected: YES];
  894.         }
  895.     }
  896.  
  897.     [quakeed_i updateAll];
  898.  
  899.     return self;
  900. }
  901.  
  902.  
  903. - selectCompleteEntity: sender
  904. {
  905.     id    o;
  906.     int    i, c;
  907.     
  908.     o = [self selectedBrush];
  909.     if (!o)
  910.     {
  911.         qprintf ("nothing selected");
  912.         return self;
  913.     }
  914.     o = [o parent];
  915.     c = [o count];
  916.     for (i=0 ; i<c ; i++)
  917.         [[o objectAt: i] setSelected: YES];    
  918.     qprintf ("%i brushes selected", c);
  919.  
  920.     [quakeed_i updateAll];
  921.  
  922.     return self;
  923. }
  924.  
  925. - makeEntity: sender
  926. {
  927.     if (currentEntity != [self objectAt: 0])
  928.     {
  929.         qprintf ("ERROR: can't makeEntity inside an entity");
  930.         NXBeep ();
  931.         return self;
  932.     }
  933.     
  934.     if ( [self numSelected] == 0)
  935.     {
  936.         qprintf ("ERROR: must have a seed brush to make an entity");
  937.         NXBeep ();
  938.         return self;
  939.     }
  940.     
  941.     sb_newowner = [[Entity alloc] initClass: [things_i spawnName]];
  942.  
  943.     if ( [sb_newowner modifiable] )
  944.         [self makeSelectedPerform: @selector(moveToEntity)];
  945.     else
  946.     {    // throw out seed brush and select entity fixed brush
  947.         [self makeSelectedPerform: @selector(remove)];
  948.         [[sb_newowner objectAt: 0] setSelected: YES];
  949.     }
  950.     
  951.     [self addObject: sb_newowner];
  952.     [self setCurrentEntity: sb_newowner];
  953.     
  954.     [quakeed_i updateAll];
  955.     
  956.     return self;
  957. }
  958.  
  959.  
  960. - selbox: (SEL)selector
  961. {
  962.     id    b;
  963.     
  964.     if ([self numSelected] != 1)
  965.     {
  966.         qprintf ("must have a single brush selected");
  967.         return self;
  968.     } 
  969.  
  970.     b = [self selectedBrush];
  971.     [b getMins: select_min maxs: select_max];
  972.     [b remove];
  973.     
  974.     [self makeUnselectedPerform: selector];
  975.     
  976.     qprintf ("identified contents");
  977.     [quakeed_i updateAll];
  978.     
  979.     return self;
  980. }
  981.  
  982. - selectCompletelyInside: sender
  983. {
  984.     return [self selbox:  @selector(selectComplete)];
  985. }
  986.  
  987. - selectPartiallyInside: sender
  988. {
  989.     return [self selbox:  @selector(selectPartial)];
  990. }
  991.  
  992.  
  993. - tallBrush: sender
  994. {
  995.     id        b;
  996.     vec3_t    mins, maxs;
  997.     texturedef_t    td;
  998.     
  999.     if ([self numSelected] != 1)
  1000.     {
  1001.         qprintf ("must have a single brush selected");
  1002.         return self;
  1003.     } 
  1004.  
  1005.     b = [self selectedBrush];
  1006.     td = *[b texturedef];
  1007.     [b getMins: mins maxs: maxs];
  1008.     [b remove];
  1009.  
  1010.     mins[2] = -2048;
  1011.     maxs[2] = 2048;
  1012.     
  1013.     b = [[SetBrush alloc] initOwner: [map_i objectAt:0] mins: mins maxs: maxs texture: &td];
  1014.     [[map_i objectAt: 0] addObject: b];
  1015.     [b setSelected: YES];
  1016.     [quakeed_i updateAll];
  1017.         
  1018.     return self;
  1019. }
  1020.  
  1021. - shortBrush: sender
  1022. {
  1023.     id        b;
  1024.     vec3_t    mins, maxs;
  1025.     texturedef_t    td;
  1026.     
  1027.     if ([self numSelected] != 1)
  1028.     {
  1029.         qprintf ("must have a single brush selected");
  1030.         return self;
  1031.     } 
  1032.  
  1033.     b = [self selectedBrush];
  1034.     td = *[b texturedef];
  1035.     [b getMins: mins maxs: maxs];
  1036.     [b remove];
  1037.  
  1038.     mins[2] = 0;
  1039.     maxs[2] = 16;
  1040.     
  1041.     b = [[SetBrush alloc] initOwner: [map_i objectAt:0] mins: mins maxs: maxs texture: &td];
  1042.     [[map_i objectAt: 0] addObject: b];
  1043.     [b setSelected: YES];
  1044.     [quakeed_i updateAll];
  1045.     
  1046.     return self;
  1047. }
  1048.  
  1049. /*
  1050. ==================
  1051. subtractSelection
  1052. ==================
  1053. */
  1054. - subtractSelection: semder
  1055. {
  1056.     int        i, j, c, c2;
  1057.     id        o, o2;
  1058.     id        sellist, sourcelist;
  1059.     
  1060.     qprintf ("performing brush subtraction...");
  1061.  
  1062.     sourcelist = [[List alloc] init];
  1063.     sellist = [[List alloc] init];
  1064.     carve_in = [[List alloc] init];
  1065.     carve_out = [[List alloc] init];
  1066.     
  1067.     c = [currentEntity count];
  1068.     for (i=0 ; i<c ; i++)
  1069.     {
  1070.         o = [currentEntity objectAt: i];
  1071.         if ([o selected])
  1072.             [sellist addObject: o];
  1073.         else
  1074.             [sourcelist addObject: o];
  1075.     }
  1076.     
  1077.         
  1078.     c = [sellist count];
  1079.     for (i=0 ; i<c ; i++)
  1080.     {
  1081.         o = [sellist objectAt: i];
  1082.         [o setCarveVars];
  1083.         
  1084.         c2 = [sourcelist count];
  1085.         for (j=0 ; j<c2 ; j++)
  1086.         {
  1087.             o2 = [sourcelist objectAt: j];
  1088.             [o2 carve];
  1089.             [carve_in freeObjects];
  1090.         }
  1091.  
  1092.         [sourcelist free];    // the individual have been moved/freed
  1093.         sourcelist = carve_out;
  1094.         carve_out = [[List alloc] init];
  1095.     }
  1096.  
  1097. // add the selection back to the remnants
  1098.     [currentEntity empty];
  1099.     [currentEntity appendList: sourcelist];
  1100.     [currentEntity appendList: sellist];
  1101.  
  1102.     [sourcelist free];
  1103.     [sellist free];
  1104.     [carve_in free];
  1105.     [carve_out free];
  1106.     
  1107.     if (![currentEntity count])
  1108.     {
  1109.         o = currentEntity;
  1110.         [self removeObject: o];
  1111.         [o free];
  1112.     }
  1113.  
  1114.     qprintf ("subtracted selection");
  1115.     [quakeed_i updateAll];
  1116.     
  1117.     return self;
  1118. }
  1119.  
  1120.  
  1121. @end
  1122.