home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / ENTITY.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  18.5 KB  |  913 lines

  1. #include "stdafx.h"
  2. #include "qe3.h"
  3.  
  4. //
  5. int g_entityId = 1;
  6.  
  7. char *ValueForKey ( epair_t *&e, const char *key)
  8. {
  9.   epair_t *ep;
  10.   for (ep=e ; ep ; ep=ep->next)
  11.   {
  12.         if (!strcmp (ep->key, key) )
  13.     {
  14.       return ep->value;
  15.     }
  16.   }
  17.   return "";
  18. }
  19.  
  20.  
  21. char *ValueForKey (entity_t *ent, const char *key)
  22. {
  23.   return ValueForKey(ent->epairs, key);
  24. }
  25.  
  26. void TrackMD3Angles(entity_t *e, const char *key, const char *value)
  27. {
  28.   if (strcmpi(key, "angle") != 0)
  29.   {
  30.     return;
  31.   }
  32.  
  33.   if (e->eclass->fixedsize && e->eclass->nShowFlags & ECLASS_MISCMODEL)
  34.   {
  35.     float a = FloatForKey (e, "angle");
  36.     float b = atof(value);
  37.     if (a != b)
  38.     {
  39.       vec3_t vAngle;
  40.       vAngle[0] = vAngle[1] = 0;
  41.       vAngle[2] = -a;
  42.       Brush_Rotate(e->brushes.onext, vAngle, e->origin, true);
  43.       vAngle[2] = b;
  44.       Brush_Rotate(e->brushes.onext, vAngle, e->origin, true);
  45.     }
  46.   }
  47. }
  48.  
  49. void     SetKeyValue (epair_t *&e, const char *key, const char *value)
  50. {
  51.     epair_t    *ep;
  52.   for (ep=e ; ep ; ep=ep->next)
  53.   {
  54.         if (!strcmp (ep->key, key) )
  55.         {
  56.             free (ep->value);
  57.             ep->value = (char*)qmalloc(strlen(value)+1);
  58.             strcpy (ep->value, value);
  59.             return;
  60.         }
  61.   }
  62.     ep = (epair_t*)qmalloc (sizeof(*ep));
  63.     ep->next = e;
  64.     e = ep;
  65.     ep->key = (char*)qmalloc(strlen(key)+1);
  66.     strcpy (ep->key, key);
  67.     ep->value = (char*)qmalloc(strlen(value)+1);
  68.     strcpy (ep->value, value);
  69.  
  70. }
  71.  
  72.  
  73. void     SetKeyValue (entity_t *ent, const char *key, const char *value)
  74. {
  75.  
  76.     if (ent == NULL)
  77.         return;
  78.  
  79.     if (!key || !key[0])
  80.         return;
  81.  
  82.   TrackMD3Angles(ent, key, value);
  83.  
  84.   SetKeyValue(ent->epairs, key, value);
  85.  
  86. }
  87.  
  88. void     DeleteKey (epair_t *&e, const char *key)
  89. {
  90.     epair_t    **ep, *next;
  91.     
  92.     ep = &e;
  93.     while (*ep)
  94.     {
  95.         next = *ep;
  96.         if ( !strcmp (next->key, key) )
  97.         {
  98.             *ep = next->next;
  99.             free(next->key);
  100.             free(next->value);
  101.             free(next);
  102.             return;
  103.         }
  104.         ep = &next->next;
  105.     }
  106. }
  107.  
  108.  
  109. void     DeleteKey (entity_t *ent, const char *key)
  110. {
  111.   DeleteKey(ent->epairs, key);
  112. }
  113.  
  114.  
  115.  
  116.  
  117. float    FloatForKey (entity_t *ent, const char *key)
  118. {
  119.     char    *k;
  120.     
  121.     k = ValueForKey (ent, key);
  122.     return atof(k);
  123. }
  124.  
  125. int IntForKey (entity_t *ent, const char *key)
  126. {
  127.     char    *k;
  128.     
  129.     k = ValueForKey (ent, key);
  130.     return atoi(k);
  131. }
  132.  
  133. void     GetVectorForKey (entity_t *ent, const char *key, vec3_t vec)
  134. {
  135.     char    *k;
  136.     
  137.     k = ValueForKey (ent, key);
  138.     sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]);
  139. }
  140.  
  141. /*
  142. ===============
  143. Entity_FreeEpairs
  144.  
  145. Frees the entity epairs.
  146. ===============
  147. */
  148. void Entity_FreeEpairs(entity_t *e)
  149. {
  150.     epair_t    *ep, *next;
  151.  
  152.     for (ep = e->epairs; ep; ep = next)
  153.     {
  154.         next = ep->next;
  155.         free (ep->key);
  156.         free (ep->value);
  157.         free (ep);
  158.     }
  159.     e->epairs = NULL;
  160. }
  161.  
  162. /*
  163. ===========
  164. Entity_AddToList
  165. ===========
  166. */
  167. void Entity_AddToList(entity_t *e, entity_t *list)
  168. {
  169.     if (e->next || e->prev)
  170.         Error ("Entity_AddToList: allready linked");
  171.     e->next = list->next;
  172.     list->next->prev = e;
  173.     list->next = e;
  174.     e->prev = list;
  175. }
  176.  
  177. /*
  178. ===========
  179. Entity_RemoveFromList
  180. ===========
  181. */
  182. void Entity_RemoveFromList (entity_t *e)
  183. {
  184.     if (!e->next || !e->prev)
  185.         Error ("Entity_RemoveFromList: not linked");
  186.     e->next->prev = e->prev;
  187.     e->prev->next = e->next;
  188.     e->next = e->prev = NULL;
  189. }
  190.  
  191.  
  192.  
  193. /*
  194. ===============
  195. Entity_Free
  196.  
  197. Frees the entity and any brushes is has.
  198. The entity is removed from the global entities list.
  199. ===============
  200. */
  201. void Entity_Free (entity_t *e)
  202. {
  203.     // do we have a plugin entity ?
  204.     if ( e->pPlugEnt )
  205.     {
  206.         e->pPlugEnt->DecRef();
  207.         e->pPlugEnt = NULL;
  208.     }
  209.  
  210.     while (e->brushes.onext != &e->brushes)
  211.         Brush_Free (e->brushes.onext);
  212.  
  213.     if (e->next)
  214.     {
  215.         e->next->prev = e->prev;
  216.         e->prev->next = e->next;
  217.     }
  218.  
  219.     Entity_FreeEpairs(e);
  220.  
  221.     free (e);
  222. }
  223.  
  224. /*
  225. =================
  226. Entity_MemorySize
  227. =================
  228. */
  229. int Entity_MemorySize(entity_t *e)
  230. {
  231.     epair_t    *ep;
  232.     int size = 0;
  233.  
  234.     for (ep = e->epairs; ep; ep = ep->next)
  235.     {
  236.         size += _msize(ep->key);
  237.         size += _msize(ep->value);
  238.         size += _msize(ep);
  239.     }
  240.     size += _msize(e);
  241.     return size;
  242. }
  243.  
  244. /*
  245. =================
  246. ParseEpair
  247. =================
  248. */
  249. epair_t *ParseEpair (void)
  250. {
  251.     epair_t    *e;
  252.     
  253.     e = (epair_t*)qmalloc (sizeof(*e));
  254.     
  255.     e->key = (char*)qmalloc(strlen(token)+1);
  256.     strcpy (e->key, token);
  257.  
  258.     GetToken (false);
  259.     e->value = (char*)qmalloc(strlen(token)+1);
  260.     strcpy (e->value, token);
  261.  
  262.     return e;
  263. }
  264.  
  265. /*
  266. ================
  267. Entity_Parse
  268.  
  269. If onlypairs is set, the classname info will not
  270. be looked up, and the entity will not be added
  271. to the global list.  Used for parsing the project.
  272. ================
  273. */
  274. entity_t    *Entity_Parse (qboolean onlypairs, brush_t* pList)
  275. {
  276.     entity_t    *ent;
  277.     eclass_t    *e;
  278.     brush_t        *b;
  279.     vec3_t        mins, maxs;
  280.     epair_t        *ep;
  281.     qboolean    has_brushes;
  282.     
  283.     if (!GetToken (true))
  284.         return NULL;
  285.     
  286.     if (strcmp (token, "{") )
  287.         Error ("ParseEntity: { not found");
  288.     
  289.     ent = (entity_t*)qmalloc (sizeof(*ent));
  290.     ent->entityId = g_entityId++;
  291.     ent->brushes.onext = ent->brushes.oprev = &ent->brushes;
  292.  
  293.   int n = 0;
  294.     do
  295.     {
  296.         if (!GetToken (true))
  297.         {
  298.             Warning ("ParseEntity: EOF without closing brace");
  299.             return NULL;
  300.         }
  301.         if (!strcmp (token, "}") )
  302.             break;
  303.         if (!strcmp (token, "{") )
  304.         {
  305.             b = Brush_Parse ();
  306.             if (b != NULL)
  307.             {
  308.                 b->owner = ent;
  309.                 // add to the end of the entity chain
  310.                 b->onext = &ent->brushes;
  311.                 b->oprev = ent->brushes.oprev;
  312.                 ent->brushes.oprev->onext = b;
  313.                 ent->brushes.oprev = b;
  314.             }
  315.             else
  316.             {
  317.                 break;
  318.             }
  319.         }
  320.         else
  321.         {
  322.             ep = ParseEpair ();
  323.             ep->next = ent->epairs;
  324.             ent->epairs = ep;
  325.         }
  326.     } while (1);
  327.     
  328.   // group info entity?
  329.   if (strcmp(ValueForKey (ent, "classname"), "group_info") == 0)
  330.     return ent;
  331.  
  332.     if (onlypairs)
  333.         return ent;
  334.     
  335.     if (ent->brushes.onext == &ent->brushes)
  336.         has_brushes = false;
  337.     else
  338.         has_brushes = true;
  339.     
  340.     GetVectorForKey (ent, "origin", ent->origin);
  341.     
  342.     e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes);
  343.     ent->eclass = e;
  344.     if ( e->nShowFlags & ECLASS_PLUGINENTITY )
  345.     {
  346.         // locate the plugin
  347.         CPlugIn * pPlug = g_pParentWnd->GetPlugInMgr().PluginForModule( e->hPlug );
  348.         if (pPlug)
  349.         {
  350.             // create the plugin entity
  351.             IPluginEntity* pPlugEnt = pPlug->CreatePluginEntity( ent );
  352.             if (pPlugEnt)
  353.             {
  354.                 ent->pPlugEnt = pPlugEnt;
  355.                 // the brush is used to select and move
  356.                 pPlugEnt->GetBounds( mins, maxs );
  357.             }
  358.             else
  359.             {
  360.                 // give it a default bounding box
  361.                 SetKeyValue (ent, "model", "");
  362.                 mins[0] = -4; mins[1] = -4; mins[2] = -4;
  363.                 maxs[0] = 4; maxs[1] = 4; maxs[2] = 4;
  364.                 VectorAdd( mins, ent->origin, mins );
  365.                 VectorAdd( maxs, ent->origin, maxs );
  366.             }
  367.             b = Brush_Create (mins, maxs, &ent->eclass->texdef);
  368.             Entity_LinkBrush (ent, b);
  369.             Brush_Build( b, true );
  370.         }
  371.         else
  372.             Sys_Printf("WARNING: plugin lookup failed for plugin entities\n");
  373.     }
  374.     else if (e->fixedsize)
  375.     {    // fixed size entity
  376.         if (ent->brushes.onext != &ent->brushes)
  377.         {
  378.             printf ("Warning: Fixed size entity with brushes\n");
  379. #if 0
  380.             while (ent->brushes.onext != &ent->brushes)
  381.             {    // FIXME: this will free the entity and crash!
  382.                 Brush_Free (b);
  383.             }
  384. #endif
  385.             ent->brushes.next = ent->brushes.prev = &ent->brushes;
  386.         }
  387.         
  388.         // create a custom brush
  389.         VectorAdd (e->mins, ent->origin, mins);
  390.         VectorAdd (e->maxs, ent->origin, maxs);
  391.         
  392.         float a = 0;
  393.         if (e->nShowFlags & ECLASS_MISCMODEL)
  394.         {
  395.             char* p = ValueForKey(ent, "model");
  396.             if (p != NULL && strlen(p) > 0)
  397.             {
  398.                 vec3_t vMin, vMax;
  399.                 a = FloatForKey (ent, "angle");
  400.                 if (GetCachedModel(ent, p, vMin, vMax))
  401.                 {
  402.                     // create a custom brush
  403.                     VectorAdd (ent->md3Class->mins, ent->origin, mins);
  404.                     VectorAdd (ent->md3Class->maxs, ent->origin, maxs);
  405.                 }
  406.             }
  407.         }
  408.         
  409.         b = Brush_Create (mins, maxs, &e->texdef);
  410.         
  411.         if (a)
  412.         {
  413.             vec3_t vAngle;
  414.             vAngle[0] = vAngle[1] = 0;
  415.             vAngle[2] = a;
  416.             Brush_Rotate(b, vAngle, ent->origin, false);
  417.         }
  418.         
  419.         
  420.         b->owner = ent;
  421.         
  422.         b->onext = ent->brushes.onext;
  423.         b->oprev = &ent->brushes;
  424.         ent->brushes.onext->oprev = b;
  425.         ent->brushes.onext = b;
  426.     }
  427.     else
  428.     {    // brush entity
  429.         if (ent->brushes.next == &ent->brushes)
  430.             printf ("Warning: Brush entity with no brushes\n");
  431.     }
  432.     
  433.     // add all the brushes to the main list
  434.     if (pList)
  435.     {
  436.         for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext)
  437.         {
  438.             b->next = pList->next;
  439.             pList->next->prev = b;
  440.             b->prev = pList;
  441.             pList->next = b;
  442.         }
  443.     }
  444.     
  445.     return ent;
  446. }
  447.  
  448. void VectorMidpoint(vec3_t va, vec3_t vb, vec3_t& out)
  449. {
  450.   for (int i = 0; i < 3; i++)
  451.     out[i] = va[i] + ((vb[i] - va[i]) / 2);
  452. }
  453.  
  454.  
  455. /*
  456. ============
  457. Entity_Write
  458. ============
  459. */
  460. void Entity_Write (entity_t *e, FILE *f, qboolean use_region)
  461. {
  462.     epair_t        *ep;
  463.     brush_t        *b;
  464.     vec3_t        origin;
  465.     char        text[128];
  466.     int            count;
  467.  
  468.     // if none of the entities brushes are in the region,
  469.     // don't write the entity at all
  470.     if (use_region)
  471.     {
  472.         // in region mode, save the camera position as playerstart
  473.         if ( !strcmp(ValueForKey (e, "classname"), "info_player_start") )
  474.         {
  475.             fprintf (f, "{\n");
  476.             fprintf (f, "\"classname\" \"info_player_start\"\n");
  477.             fprintf (f, "\"origin\" \"%i %i %i\"\n", (int)g_pParentWnd->GetCamera()->Camera().origin[0],
  478.                 (int)g_pParentWnd->GetCamera()->Camera().origin[1], (int)g_pParentWnd->GetCamera()->Camera().origin[2]);
  479.             fprintf (f, "\"angle\" \"%i\"\n", (int)g_pParentWnd->GetCamera()->Camera().angles[YAW]);
  480.             fprintf (f, "}\n");
  481.             return;
  482.         }
  483.  
  484.         for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
  485.             if (!Map_IsBrushFiltered(b))
  486.                 break;    // got one
  487.  
  488.         if (b == &e->brushes)
  489.             return;        // nothing visible
  490.     }
  491.  
  492.     if ( e->eclass->nShowFlags & ECLASS_PLUGINENTITY )
  493.     {
  494.         // NOTE: the whole brush placement / origin stuff is a mess
  495.         VectorCopy( e->origin, origin );
  496.         sprintf (text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
  497.         SetKeyValue (e, "origin", text);
  498.     }
  499.     // if fixedsize, calculate a new origin based on the current
  500.     // brush position
  501.     else if (e->eclass->fixedsize)
  502.     {
  503.         if (e->eclass->nShowFlags & ECLASS_MISCMODEL && e->md3Class != NULL)
  504.         {
  505.             VectorCopy(e->origin, origin);
  506.             //VectorSubtract (e->brushes.onext->mins, e->md3Class->mins, origin);
  507.         }
  508.         else
  509.         {
  510.             VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin);
  511.         }
  512.         sprintf (text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
  513.         SetKeyValue (e, "origin", text);
  514.     }
  515.  
  516.     fprintf (f, "{\n");
  517.     for (ep = e->epairs ; ep ; ep=ep->next)
  518.         fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value);
  519.  
  520.     if (!e->eclass->fixedsize)
  521.     {
  522.         count = 0;
  523.         for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
  524.         {
  525.             if (!use_region || !Map_IsBrushFiltered (b))
  526.       {
  527.                 fprintf (f, "// brush %i\n", count);
  528.                 count++;
  529.                 Brush_Write (b, f);
  530.             }
  531.         }
  532.     }
  533.     fprintf (f, "}\n");
  534. }
  535.  
  536.  
  537.  
  538. qboolean IsBrushSelected(brush_t* bSel)
  539. {
  540.     for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next)
  541.   {
  542.     if (b == bSel)
  543.       return true;
  544.   }
  545.   return false;
  546. }
  547.  
  548. //
  549. //============
  550. //Entity_WriteSelected
  551. //============
  552. //
  553. void Entity_WriteSelected(entity_t *e, FILE *f)
  554. {
  555.     epair_t        *ep;
  556.     brush_t        *b;
  557.     vec3_t        origin;
  558.     char        text[128];
  559.     int            count;
  560.  
  561.     for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
  562.         if (IsBrushSelected(b))
  563.             break;    // got one
  564.  
  565.     if (b == &e->brushes)
  566.         return;        // nothing selected
  567.  
  568.     // if fixedsize, calculate a new origin based on the current
  569.     // brush position
  570.     if (e->eclass->fixedsize)
  571.     {
  572.     if (e->eclass->nShowFlags & ECLASS_MISCMODEL && e->md3Class != NULL)
  573.     {
  574.       VectorCopy(e->origin, origin);
  575.           //VectorSubtract (e->brushes.onext->mins, e->md3Class->mins, origin);
  576.     }
  577.     else
  578.     {
  579.           VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin);
  580.     }
  581.     sprintf (text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
  582.         SetKeyValue (e, "origin", text);
  583.     }
  584.  
  585.   fprintf (f, "{\n");
  586.     for (ep = e->epairs ; ep ; ep=ep->next)
  587.       fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value);
  588.  
  589.   if (!e->eclass->fixedsize)
  590.   {
  591.       count = 0;
  592.       for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
  593.       {
  594.           if (IsBrushSelected(b))
  595.           {
  596.               fprintf (f, "// brush %i\n", count);
  597.               count++;
  598.               Brush_Write (b, f);
  599.           }
  600.       }
  601.   }
  602.     fprintf (f, "}\n");
  603. }
  604.  
  605.  
  606. //
  607. //============
  608. //Entity_WriteSelected to a CMemFile
  609. //============
  610. //
  611. void Entity_WriteSelected(entity_t *e, CMemFile* pMemFile)
  612. {
  613.     epair_t        *ep;
  614.     brush_t        *b;
  615.     vec3_t        origin;
  616.     char        text[128];
  617.     int            count;
  618.  
  619.     for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
  620.         if (IsBrushSelected(b))
  621.             break;    // got one
  622.  
  623.     if (b == &e->brushes)
  624.         return;        // nothing selected
  625.  
  626.     // if fixedsize, calculate a new origin based on the current
  627.     // brush position
  628.     if (e->eclass->fixedsize)
  629.     {
  630.     if (e->eclass->nShowFlags & ECLASS_MISCMODEL && e->md3Class != NULL)
  631.     {
  632.           //VectorSubtract (e->brushes.onext->mins, e->md3Class->mins, origin);
  633.       VectorCopy(e->origin, origin);
  634.     }
  635.     else
  636.     {
  637.           VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin);
  638.     }
  639.     sprintf (text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
  640.         SetKeyValue (e, "origin", text);
  641.     }
  642.  
  643.   MemFile_fprintf(pMemFile, "{\n");
  644.     for (ep = e->epairs ; ep ; ep=ep->next)
  645.       MemFile_fprintf(pMemFile, "\"%s\" \"%s\"\n", ep->key, ep->value);
  646.  
  647.   if (!e->eclass->fixedsize)
  648.   {
  649.       count = 0;
  650.       for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
  651.       {
  652.           if (IsBrushSelected(b))
  653.           {
  654.               MemFile_fprintf(pMemFile, "// brush %i\n", count);
  655.               count++;
  656.               Brush_Write (b, pMemFile);
  657.           }
  658.       }
  659.   }
  660.     MemFile_fprintf(pMemFile, "}\n");
  661. }
  662.  
  663.  
  664.  
  665.  
  666. /*
  667. ============
  668. Entity_Create
  669.  
  670. Creates a new entity out of the selected_brushes list.
  671. If the entity class is fixed size, the brushes are only
  672. used to find a midpoint.  Otherwise, the brushes have
  673. their ownership transfered to the new entity.
  674. ============
  675. */
  676. entity_t    *Entity_Create (eclass_t *c)
  677. {
  678.     entity_t    *e;
  679.     brush_t        *b;
  680.     vec3_t        mins, maxs;
  681.     int            i;
  682.  
  683.     // check to make sure the brushes are ok
  684.  
  685.     for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
  686.   {
  687.         if (b->owner != world_entity)
  688.         {
  689.             Sys_Printf ("Entity NOT created, brushes not all from world\n");
  690.             Sys_Beep ();
  691.             return NULL;
  692.         }
  693.   }
  694.  
  695.     // create it
  696.  
  697.     e = (entity_t*)qmalloc(sizeof(*e));
  698.     e->entityId = g_entityId++;
  699.     e->brushes.onext = e->brushes.oprev = &e->brushes;
  700.     e->eclass = c;
  701.     SetKeyValue (e, "classname", c->name);
  702.  
  703.     // add the entity to the entity list
  704.   Entity_AddToList(e, &entities);
  705.  
  706.     // plugin entity ?
  707.     if (c->nShowFlags & ECLASS_PLUGINENTITY)
  708.     {
  709.         // locate the plugin
  710.         CPlugIn * pPlug = g_pParentWnd->GetPlugInMgr().PluginForModule( c->hPlug );
  711.         if (pPlug)
  712.         {
  713.             //
  714.             // just use the selection for positioning
  715.             //
  716.             b = selected_brushes.next;
  717.             for (i=0 ; i<3 ; i++)
  718.                 e->origin[i] = b->mins[i] - c->mins[i];
  719.  
  720.             // create the plugin entity
  721.             IPluginEntity* pPlugEnt = pPlug->CreatePluginEntity( e );
  722.             
  723.             if (pPlugEnt)
  724.             {
  725.                 e->pPlugEnt = pPlugEnt;
  726.                 // the brush is used to select and move
  727.                 pPlugEnt->GetBounds( mins, maxs );
  728.                 b = Brush_Create (mins, maxs, &c->texdef);
  729.                 
  730.                 Entity_LinkBrush (e, b);
  731.                 
  732.                 // delete the current selection
  733.                 Select_Delete ();
  734.                 
  735.                 // select the new brush
  736.                 b->next = b->prev = &selected_brushes;
  737.                 selected_brushes.next = selected_brushes.prev = b;
  738.                 
  739.                 Brush_Build( b );
  740.             }
  741.         }
  742.         else
  743.         {
  744.             Sys_Printf( "WARNING: plugin lookup failed while creating a plugin entitiy in Entity_Create\n" );
  745.             return NULL;
  746.         }
  747.     }
  748.     else if (c->fixedsize)
  749.     {
  750.         //
  751.         // just use the selection for positioning
  752.         //
  753.         b = selected_brushes.next;
  754.         for (i=0 ; i<3 ; i++)
  755.             e->origin[i] = b->mins[i] - c->mins[i];
  756.  
  757.         // create a custom brush
  758.         VectorAdd (c->mins, e->origin, mins);
  759.         VectorAdd (c->maxs, e->origin, maxs);
  760.  
  761.       b = Brush_Create (mins, maxs, &c->texdef);
  762.  
  763.         Entity_LinkBrush (e, b);
  764.  
  765.         // delete the current selection
  766.         Select_Delete ();
  767.  
  768.         // select the new brush
  769.         b->next = b->prev = &selected_brushes;
  770.         selected_brushes.next = selected_brushes.prev = b;
  771.  
  772.         Brush_Build( b );
  773.     }
  774.     else
  775.     {
  776.         //
  777.         // change the selected brushes over to the new entity
  778.         //
  779.         for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
  780.         {
  781.             Entity_UnlinkBrush (b);
  782.             Entity_LinkBrush (e, b);
  783.             Brush_Build( b );    // so the key brush gets a name
  784.         }
  785.     }
  786.  
  787.     Sys_UpdateWindows (W_ALL);
  788.     return e;
  789. }
  790.  
  791.  
  792. /*
  793. ===========
  794. Entity_LinkBrush
  795. ===========
  796. */
  797. void Entity_LinkBrush (entity_t *e, brush_t *b)
  798. {
  799.     if (b->oprev || b->onext)
  800.         Error ("Entity_LinkBrush: Allready linked");
  801.     b->owner = e;
  802.  
  803.     b->onext = e->brushes.onext;
  804.     b->oprev = &e->brushes;
  805.     e->brushes.onext->oprev = b;
  806.     e->brushes.onext = b;
  807. }
  808.  
  809. /*
  810. ===========
  811. Entity_UnlinkBrush
  812. ===========
  813. */
  814. void Entity_UnlinkBrush (brush_t *b)
  815. {
  816.     //if (!b->owner || !b->onext || !b->oprev)
  817.     if (!b->onext || !b->oprev)
  818.         Error ("Entity_UnlinkBrush: Not currently linked");
  819.     b->onext->oprev = b->oprev;
  820.     b->oprev->onext = b->onext;
  821.     b->onext = b->oprev = NULL;
  822.     b->owner = NULL;
  823. }
  824.  
  825.  
  826. /*
  827. ===========
  828. Entity_Clone
  829. ===========
  830. */
  831. entity_t    *Entity_Clone (entity_t *e)
  832. {
  833.     entity_t    *n;
  834.     epair_t        *ep, *np;
  835.  
  836.     n = (entity_t*)qmalloc(sizeof(*n));
  837.     n->entityId = g_entityId++;
  838.     n->brushes.onext = n->brushes.oprev = &n->brushes;
  839.     n->eclass = e->eclass;
  840.  
  841.     // add the entity to the entity list
  842.     Entity_AddToList(n, &entities);
  843.  
  844.     for (ep = e->epairs ; ep ; ep=ep->next)
  845.     {
  846.         np = (epair_t*)qmalloc(sizeof(*np));
  847.         np->key = copystring(ep->key);
  848.         np->value = copystring(ep->value);
  849.         np->next = n->epairs;
  850.         n->epairs = np;
  851.     }
  852.     return n;
  853. }
  854.  
  855. int GetUniqueTargetId(int iHint)
  856. {
  857.     int iMin, iMax, i;
  858.     BOOL fFound;
  859.     entity_t *pe;
  860.     
  861.     fFound = FALSE;
  862.     pe = entities.next;
  863.     iMin = 0; 
  864.     iMax = 0;
  865.     
  866.     for (; pe != NULL && pe != &entities ; pe = pe->next)
  867.     {
  868.         i = IntForKey(pe, "target");
  869.         if (i)
  870.         {
  871.             iMin = min(i, iMin);
  872.             iMax = max(i, iMax);
  873.             if (i == iHint)
  874.                 fFound = TRUE;
  875.         }
  876.     }
  877.  
  878.     if (fFound)
  879.         return iMax + 1;
  880.     else
  881.         return iHint;
  882. }
  883.  
  884. entity_t *FindEntity(char *pszKey, char *pszValue)
  885. {
  886.     entity_t *pe;
  887.     
  888.     pe = entities.next;
  889.     
  890.     for (; pe != NULL && pe != &entities ; pe = pe->next)
  891.     {
  892.         if (!strcmp(ValueForKey(pe, pszKey), pszValue))
  893.             return pe;
  894.     }
  895.  
  896.     return NULL;
  897. }
  898.  
  899. entity_t *FindEntityInt(char *pszKey, int iValue)
  900. {
  901.     entity_t *pe;
  902.     
  903.     pe = entities.next;
  904.     
  905.     for (; pe != NULL && pe != &entities ; pe = pe->next)
  906.     {
  907.         if (IntForKey(pe, pszKey) == iValue)
  908.             return pe;
  909.     }
  910.  
  911.     return NULL;
  912. }
  913.