Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

ENTITY.CPP

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 #include "stdafx.h"
00023 #include "qe3.h"
00024 
00025 //
00026 int g_entityId = 1;
00027 
00028 char *ValueForKey ( epair_t *&e, const char *key)
00029 {
00030   epair_t *ep;
00031   for (ep=e ; ep ; ep=ep->next)
00032   {
00033         if (!strcmp (ep->key, key) )
00034     {
00035       return ep->value;
00036     }
00037   }
00038   return "";
00039 }
00040 
00041 
00042 char *ValueForKey (entity_t *ent, const char *key)
00043 {
00044   return ValueForKey(ent->epairs, key);
00045 }
00046 
00047 void TrackMD3Angles(entity_t *e, const char *key, const char *value)
00048 {
00049   if (strcmpi(key, "angle") != 0)
00050   {
00051     return;
00052   }
00053 
00054   if (e->eclass->fixedsize && e->eclass->nShowFlags & ECLASS_MISCMODEL)
00055   {
00056     float a = FloatForKey (e, "angle");
00057     float b = atof(value);
00058     if (a != b)
00059     {
00060       vec3_t vAngle;
00061       vAngle[0] = vAngle[1] = 0;
00062       vAngle[2] = -a;
00063       Brush_Rotate(e->brushes.onext, vAngle, e->origin, true);
00064       vAngle[2] = b;
00065       Brush_Rotate(e->brushes.onext, vAngle, e->origin, true);
00066     }
00067   }
00068 }
00069 
00070 void    SetKeyValue (epair_t *&e, const char *key, const char *value)
00071 {
00072     epair_t *ep;
00073   for (ep=e ; ep ; ep=ep->next)
00074   {
00075         if (!strcmp (ep->key, key) )
00076         {
00077             free (ep->value);
00078             ep->value = (char*)qmalloc(strlen(value)+1);
00079             strcpy (ep->value, value);
00080             return;
00081         }
00082   }
00083     ep = (epair_t*)qmalloc (sizeof(*ep));
00084     ep->next = e;
00085     e = ep;
00086     ep->key = (char*)qmalloc(strlen(key)+1);
00087     strcpy (ep->key, key);
00088     ep->value = (char*)qmalloc(strlen(value)+1);
00089     strcpy (ep->value, value);
00090 
00091 }
00092 
00093 
00094 void    SetKeyValue (entity_t *ent, const char *key, const char *value)
00095 {
00096 
00097     if (ent == NULL)
00098         return;
00099 
00100     if (!key || !key[0])
00101         return;
00102 
00103   TrackMD3Angles(ent, key, value);
00104 
00105   SetKeyValue(ent->epairs, key, value);
00106 
00107 }
00108 
00109 void    DeleteKey (epair_t *&e, const char *key)
00110 {
00111     epair_t **ep, *next;
00112     
00113     ep = &e;
00114     while (*ep)
00115     {
00116         next = *ep;
00117         if ( !strcmp (next->key, key) )
00118         {
00119             *ep = next->next;
00120             free(next->key);
00121             free(next->value);
00122             free(next);
00123             return;
00124         }
00125         ep = &next->next;
00126     }
00127 }
00128 
00129 
00130 void    DeleteKey (entity_t *ent, const char *key)
00131 {
00132   DeleteKey(ent->epairs, key);
00133 }
00134 
00135 
00136 
00137 
00138 float   FloatForKey (entity_t *ent, const char *key)
00139 {
00140     char    *k;
00141     
00142     k = ValueForKey (ent, key);
00143     return atof(k);
00144 }
00145 
00146 int IntForKey (entity_t *ent, const char *key)
00147 {
00148     char    *k;
00149     
00150     k = ValueForKey (ent, key);
00151     return atoi(k);
00152 }
00153 
00154 void    GetVectorForKey (entity_t *ent, const char *key, vec3_t vec)
00155 {
00156     char    *k;
00157     
00158     k = ValueForKey (ent, key);
00159     sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]);
00160 }
00161 
00162 /*
00163 ===============
00164 Entity_FreeEpairs
00165 
00166 Frees the entity epairs.
00167 ===============
00168 */
00169 void Entity_FreeEpairs(entity_t *e)
00170 {
00171     epair_t *ep, *next;
00172 
00173     for (ep = e->epairs; ep; ep = next)
00174     {
00175         next = ep->next;
00176         free (ep->key);
00177         free (ep->value);
00178         free (ep);
00179     }
00180     e->epairs = NULL;
00181 }
00182 
00183 /*
00184 ===========
00185 Entity_AddToList
00186 ===========
00187 */
00188 void Entity_AddToList(entity_t *e, entity_t *list)
00189 {
00190     if (e->next || e->prev)
00191         Error ("Entity_AddToList: allready linked");
00192     e->next = list->next;
00193     list->next->prev = e;
00194     list->next = e;
00195     e->prev = list;
00196 }
00197 
00198 /*
00199 ===========
00200 Entity_RemoveFromList
00201 ===========
00202 */
00203 void Entity_RemoveFromList (entity_t *e)
00204 {
00205     if (!e->next || !e->prev)
00206         Error ("Entity_RemoveFromList: not linked");
00207     e->next->prev = e->prev;
00208     e->prev->next = e->next;
00209     e->next = e->prev = NULL;
00210 }
00211 
00212 
00213 
00214 /*
00215 ===============
00216 Entity_Free
00217 
00218 Frees the entity and any brushes is has.
00219 The entity is removed from the global entities list.
00220 ===============
00221 */
00222 void Entity_Free (entity_t *e)
00223 {
00224     // do we have a plugin entity ?
00225     if ( e->pPlugEnt )
00226     {
00227         e->pPlugEnt->DecRef();
00228         e->pPlugEnt = NULL;
00229     }
00230 
00231     while (e->brushes.onext != &e->brushes)
00232         Brush_Free (e->brushes.onext);
00233 
00234     if (e->next)
00235     {
00236         e->next->prev = e->prev;
00237         e->prev->next = e->next;
00238     }
00239 
00240     Entity_FreeEpairs(e);
00241 
00242     free (e);
00243 }
00244 
00245 /*
00246 =================
00247 Entity_MemorySize
00248 =================
00249 */
00250 int Entity_MemorySize(entity_t *e)
00251 {
00252     epair_t *ep;
00253     int size = 0;
00254 
00255     for (ep = e->epairs; ep; ep = ep->next)
00256     {
00257         size += _msize(ep->key);
00258         size += _msize(ep->value);
00259         size += _msize(ep);
00260     }
00261     size += _msize(e);
00262     return size;
00263 }
00264 
00265 /*
00266 =================
00267 ParseEpair
00268 =================
00269 */
00270 epair_t *ParseEpair (void)
00271 {
00272     epair_t *e;
00273     
00274     e = (epair_t*)qmalloc (sizeof(*e));
00275     
00276     e->key = (char*)qmalloc(strlen(token)+1);
00277     strcpy (e->key, token);
00278 
00279     GetToken (false);
00280     e->value = (char*)qmalloc(strlen(token)+1);
00281     strcpy (e->value, token);
00282 
00283     return e;
00284 }
00285 
00286 /*
00287 ================
00288 Entity_Parse
00289 
00290 If onlypairs is set, the classname info will not
00291 be looked up, and the entity will not be added
00292 to the global list.  Used for parsing the project.
00293 ================
00294 */
00295 entity_t    *Entity_Parse (qboolean onlypairs, brush_t* pList)
00296 {
00297     entity_t    *ent;
00298     eclass_t    *e;
00299     brush_t     *b;
00300     vec3_t      mins, maxs;
00301     epair_t     *ep;
00302     qboolean    has_brushes;
00303     
00304     if (!GetToken (true))
00305         return NULL;
00306     
00307     if (strcmp (token, "{") )
00308         Error ("ParseEntity: { not found");
00309     
00310     ent = (entity_t*)qmalloc (sizeof(*ent));
00311     ent->entityId = g_entityId++;
00312     ent->brushes.onext = ent->brushes.oprev = &ent->brushes;
00313 
00314   int n = 0;
00315     do
00316     {
00317         if (!GetToken (true))
00318         {
00319             Warning ("ParseEntity: EOF without closing brace");
00320             return NULL;
00321         }
00322         if (!strcmp (token, "}") )
00323             break;
00324         if (!strcmp (token, "{") )
00325         {
00326             b = Brush_Parse ();
00327             if (b != NULL)
00328             {
00329                 b->owner = ent;
00330                 // add to the end of the entity chain
00331                 b->onext = &ent->brushes;
00332                 b->oprev = ent->brushes.oprev;
00333                 ent->brushes.oprev->onext = b;
00334                 ent->brushes.oprev = b;
00335             }
00336             else
00337             {
00338                 break;
00339             }
00340         }
00341         else
00342         {
00343             ep = ParseEpair ();
00344             ep->next = ent->epairs;
00345             ent->epairs = ep;
00346         }
00347     } while (1);
00348     
00349   // group info entity?
00350   if (strcmp(ValueForKey (ent, "classname"), "group_info") == 0)
00351     return ent;
00352 
00353     if (onlypairs)
00354         return ent;
00355     
00356     if (ent->brushes.onext == &ent->brushes)
00357         has_brushes = false;
00358     else
00359         has_brushes = true;
00360     
00361     GetVectorForKey (ent, "origin", ent->origin);
00362     
00363     e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes);
00364     ent->eclass = e;
00365     if ( e->nShowFlags & ECLASS_PLUGINENTITY )
00366     {
00367         // locate the plugin
00368         CPlugIn * pPlug = g_pParentWnd->GetPlugInMgr().PluginForModule( e->hPlug );
00369         if (pPlug)
00370         {
00371             // create the plugin entity
00372             IPluginEntity* pPlugEnt = pPlug->CreatePluginEntity( ent );
00373             if (pPlugEnt)
00374             {
00375                 ent->pPlugEnt = pPlugEnt;
00376                 // the brush is used to select and move
00377                 pPlugEnt->GetBounds( mins, maxs );
00378             }
00379             else
00380             {
00381                 // give it a default bounding box
00382                 SetKeyValue (ent, "model", "");
00383                 mins[0] = -4; mins[1] = -4; mins[2] = -4;
00384                 maxs[0] = 4; maxs[1] = 4; maxs[2] = 4;
00385                 VectorAdd( mins, ent->origin, mins );
00386                 VectorAdd( maxs, ent->origin, maxs );
00387             }
00388             b = Brush_Create (mins, maxs, &ent->eclass->texdef);
00389             Entity_LinkBrush (ent, b);
00390             Brush_Build( b, true );
00391         }
00392         else
00393             Sys_Printf("WARNING: plugin lookup failed for plugin entities\n");
00394     }
00395     else if (e->fixedsize)
00396     {   // fixed size entity
00397         if (ent->brushes.onext != &ent->brushes)
00398         {
00399             printf ("Warning: Fixed size entity with brushes\n");
00400 #if 0
00401             while (ent->brushes.onext != &ent->brushes)
00402             {   // FIXME: this will free the entity and crash!
00403                 Brush_Free (b);
00404             }
00405 #endif
00406             ent->brushes.next = ent->brushes.prev = &ent->brushes;
00407         }
00408         
00409         // create a custom brush
00410         VectorAdd (e->mins, ent->origin, mins);
00411         VectorAdd (e->maxs, ent->origin, maxs);
00412         
00413         float a = 0;
00414         if (e->nShowFlags & ECLASS_MISCMODEL)
00415         {
00416             char* p = ValueForKey(ent, "model");
00417             if (p != NULL && strlen(p) > 0)
00418             {
00419                 vec3_t vMin, vMax;
00420                 a = FloatForKey (ent, "angle");
00421                 if (GetCachedModel(ent, p, vMin, vMax))
00422                 {
00423                     // create a custom brush
00424                     VectorAdd (ent->md3Class->mins, ent->origin, mins);
00425                     VectorAdd (ent->md3Class->maxs, ent->origin, maxs);
00426                 }
00427             }
00428         }
00429         
00430         b = Brush_Create (mins, maxs, &e->texdef);
00431         
00432         if (a)
00433         {
00434             vec3_t vAngle;
00435             vAngle[0] = vAngle[1] = 0;
00436             vAngle[2] = a;
00437             Brush_Rotate(b, vAngle, ent->origin, false);
00438         }
00439         
00440         
00441         b->owner = ent;
00442         
00443         b->onext = ent->brushes.onext;
00444         b->oprev = &ent->brushes;
00445         ent->brushes.onext->oprev = b;
00446         ent->brushes.onext = b;
00447     }
00448     else
00449     {   // brush entity
00450         if (ent->brushes.next == &ent->brushes)
00451             printf ("Warning: Brush entity with no brushes\n");
00452     }
00453     
00454     // add all the brushes to the main list
00455     if (pList)
00456     {
00457         for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext)
00458         {
00459             b->next = pList->next;
00460             pList->next->prev = b;
00461             b->prev = pList;
00462             pList->next = b;
00463         }
00464     }
00465     
00466     return ent;
00467 }
00468 
00469 void VectorMidpoint(vec3_t va, vec3_t vb, vec3_t& out)
00470 {
00471   for (int i = 0; i < 3; i++)
00472     out[i] = va[i] + ((vb[i] - va[i]) / 2);
00473 }
00474 
00475 
00476 /*
00477 ============
00478 Entity_Write
00479 ============
00480 */
00481 void Entity_Write (entity_t *e, FILE *f, qboolean use_region)
00482 {
00483     epair_t     *ep;
00484     brush_t     *b;
00485     vec3_t      origin;
00486     char        text[128];
00487     int         count;
00488 
00489     // if none of the entities brushes are in the region,
00490     // don't write the entity at all
00491     if (use_region)
00492     {
00493         // in region mode, save the camera position as playerstart
00494         if ( !strcmp(ValueForKey (e, "classname"), "info_player_start") )
00495         {
00496             fprintf (f, "{\n");
00497             fprintf (f, "\"classname\" \"info_player_start\"\n");
00498             fprintf (f, "\"origin\" \"%i %i %i\"\n", (int)g_pParentWnd->GetCamera()->Camera().origin[0],
00499                 (int)g_pParentWnd->GetCamera()->Camera().origin[1], (int)g_pParentWnd->GetCamera()->Camera().origin[2]);
00500             fprintf (f, "\"angle\" \"%i\"\n", (int)g_pParentWnd->GetCamera()->Camera().angles[YAW]);
00501             fprintf (f, "}\n");
00502             return;
00503         }
00504 
00505         for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
00506             if (!Map_IsBrushFiltered(b))
00507                 break;  // got one
00508 
00509         if (b == &e->brushes)
00510             return;     // nothing visible
00511     }
00512 
00513     if ( e->eclass->nShowFlags & ECLASS_PLUGINENTITY )
00514     {
00515         // NOTE: the whole brush placement / origin stuff is a mess
00516         VectorCopy( e->origin, origin );
00517         sprintf (text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
00518         SetKeyValue (e, "origin", text);
00519     }
00520     // if fixedsize, calculate a new origin based on the current
00521     // brush position
00522     else if (e->eclass->fixedsize)
00523     {
00524         if (e->eclass->nShowFlags & ECLASS_MISCMODEL && e->md3Class != NULL)
00525         {
00526             VectorCopy(e->origin, origin);
00527             //VectorSubtract (e->brushes.onext->mins, e->md3Class->mins, origin);
00528         }
00529         else
00530         {
00531             VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin);
00532         }
00533         sprintf (text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
00534         SetKeyValue (e, "origin", text);
00535     }
00536 
00537     fprintf (f, "{\n");
00538     for (ep = e->epairs ; ep ; ep=ep->next)
00539         fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value);
00540 
00541     if (!e->eclass->fixedsize)
00542     {
00543         count = 0;
00544         for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
00545         {
00546             if (!use_region || !Map_IsBrushFiltered (b))
00547       {
00548                 fprintf (f, "// brush %i\n", count);
00549                 count++;
00550                 Brush_Write (b, f);
00551             }
00552         }
00553     }
00554     fprintf (f, "}\n");
00555 }
00556 
00557 
00558 
00559 qboolean IsBrushSelected(brush_t* bSel)
00560 {
00561     for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next)
00562   {
00563     if (b == bSel)
00564       return true;
00565   }
00566   return false;
00567 }
00568 
00569 //
00570 //============
00571 //Entity_WriteSelected
00572 //============
00573 //
00574 void Entity_WriteSelected(entity_t *e, FILE *f)
00575 {
00576     epair_t     *ep;
00577     brush_t     *b;
00578     vec3_t      origin;
00579     char        text[128];
00580     int         count;
00581 
00582     for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
00583         if (IsBrushSelected(b))
00584             break;  // got one
00585 
00586     if (b == &e->brushes)
00587         return;     // nothing selected
00588 
00589     // if fixedsize, calculate a new origin based on the current
00590     // brush position
00591     if (e->eclass->fixedsize)
00592     {
00593     if (e->eclass->nShowFlags & ECLASS_MISCMODEL && e->md3Class != NULL)
00594     {
00595       VectorCopy(e->origin, origin);
00596           //VectorSubtract (e->brushes.onext->mins, e->md3Class->mins, origin);
00597     }
00598     else
00599     {
00600           VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin);
00601     }
00602     sprintf (text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
00603         SetKeyValue (e, "origin", text);
00604     }
00605 
00606   fprintf (f, "{\n");
00607     for (ep = e->epairs ; ep ; ep=ep->next)
00608       fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value);
00609 
00610   if (!e->eclass->fixedsize)
00611   {
00612       count = 0;
00613       for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
00614       {
00615           if (IsBrushSelected(b))
00616           {
00617               fprintf (f, "// brush %i\n", count);
00618               count++;
00619               Brush_Write (b, f);
00620           }
00621       }
00622   }
00623     fprintf (f, "}\n");
00624 }
00625 
00626 
00627 //
00628 //============
00629 //Entity_WriteSelected to a CMemFile
00630 //============
00631 //
00632 void Entity_WriteSelected(entity_t *e, CMemFile* pMemFile)
00633 {
00634     epair_t     *ep;
00635     brush_t     *b;
00636     vec3_t      origin;
00637     char        text[128];
00638     int         count;
00639 
00640     for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
00641         if (IsBrushSelected(b))
00642             break;  // got one
00643 
00644     if (b == &e->brushes)
00645         return;     // nothing selected
00646 
00647     // if fixedsize, calculate a new origin based on the current
00648     // brush position
00649     if (e->eclass->fixedsize)
00650     {
00651     if (e->eclass->nShowFlags & ECLASS_MISCMODEL && e->md3Class != NULL)
00652     {
00653           //VectorSubtract (e->brushes.onext->mins, e->md3Class->mins, origin);
00654       VectorCopy(e->origin, origin);
00655     }
00656     else
00657     {
00658           VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin);
00659     }
00660     sprintf (text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
00661         SetKeyValue (e, "origin", text);
00662     }
00663 
00664   MemFile_fprintf(pMemFile, "{\n");
00665     for (ep = e->epairs ; ep ; ep=ep->next)
00666       MemFile_fprintf(pMemFile, "\"%s\" \"%s\"\n", ep->key, ep->value);
00667 
00668   if (!e->eclass->fixedsize)
00669   {
00670       count = 0;
00671       for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
00672       {
00673           if (IsBrushSelected(b))
00674           {
00675               MemFile_fprintf(pMemFile, "// brush %i\n", count);
00676               count++;
00677               Brush_Write (b, pMemFile);
00678           }
00679       }
00680   }
00681     MemFile_fprintf(pMemFile, "}\n");
00682 }
00683 
00684 
00685 
00686 
00687 /*
00688 ============
00689 Entity_Create
00690 
00691 Creates a new entity out of the selected_brushes list.
00692 If the entity class is fixed size, the brushes are only
00693 used to find a midpoint.  Otherwise, the brushes have
00694 their ownership transfered to the new entity.
00695 ============
00696 */
00697 entity_t    *Entity_Create (eclass_t *c)
00698 {
00699     entity_t    *e;
00700     brush_t     *b;
00701     vec3_t      mins, maxs;
00702     int         i;
00703 
00704     // check to make sure the brushes are ok
00705 
00706     for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
00707   {
00708         if (b->owner != world_entity)
00709         {
00710             Sys_Printf ("Entity NOT created, brushes not all from world\n");
00711             Sys_Beep ();
00712             return NULL;
00713         }
00714   }
00715 
00716     // create it
00717 
00718     e = (entity_t*)qmalloc(sizeof(*e));
00719     e->entityId = g_entityId++;
00720     e->brushes.onext = e->brushes.oprev = &e->brushes;
00721     e->eclass = c;
00722     SetKeyValue (e, "classname", c->name);
00723 
00724     // add the entity to the entity list
00725   Entity_AddToList(e, &entities);
00726 
00727     // plugin entity ?
00728     if (c->nShowFlags & ECLASS_PLUGINENTITY)
00729     {
00730         // locate the plugin
00731         CPlugIn * pPlug = g_pParentWnd->GetPlugInMgr().PluginForModule( c->hPlug );
00732         if (pPlug)
00733         {
00734             //
00735             // just use the selection for positioning
00736             //
00737             b = selected_brushes.next;
00738             for (i=0 ; i<3 ; i++)
00739                 e->origin[i] = b->mins[i] - c->mins[i];
00740 
00741             // create the plugin entity
00742             IPluginEntity* pPlugEnt = pPlug->CreatePluginEntity( e );
00743             
00744             if (pPlugEnt)
00745             {
00746                 e->pPlugEnt = pPlugEnt;
00747                 // the brush is used to select and move
00748                 pPlugEnt->GetBounds( mins, maxs );
00749                 b = Brush_Create (mins, maxs, &c->texdef);
00750                 
00751                 Entity_LinkBrush (e, b);
00752                 
00753                 // delete the current selection
00754                 Select_Delete ();
00755                 
00756                 // select the new brush
00757                 b->next = b->prev = &selected_brushes;
00758                 selected_brushes.next = selected_brushes.prev = b;
00759                 
00760                 Brush_Build( b );
00761             }
00762         }
00763         else
00764         {
00765             Sys_Printf( "WARNING: plugin lookup failed while creating a plugin entitiy in Entity_Create\n" );
00766             return NULL;
00767         }
00768     }
00769     else if (c->fixedsize)
00770     {
00771         //
00772         // just use the selection for positioning
00773         //
00774         b = selected_brushes.next;
00775         for (i=0 ; i<3 ; i++)
00776             e->origin[i] = b->mins[i] - c->mins[i];
00777 
00778         // create a custom brush
00779         VectorAdd (c->mins, e->origin, mins);
00780         VectorAdd (c->maxs, e->origin, maxs);
00781 
00782       b = Brush_Create (mins, maxs, &c->texdef);
00783 
00784         Entity_LinkBrush (e, b);
00785 
00786         // delete the current selection
00787         Select_Delete ();
00788 
00789         // select the new brush
00790         b->next = b->prev = &selected_brushes;
00791         selected_brushes.next = selected_brushes.prev = b;
00792 
00793         Brush_Build( b );
00794     }
00795     else
00796     {
00797         //
00798         // change the selected brushes over to the new entity
00799         //
00800         for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
00801         {
00802             Entity_UnlinkBrush (b);
00803             Entity_LinkBrush (e, b);
00804             Brush_Build( b );   // so the key brush gets a name
00805         }
00806     }
00807 
00808     Sys_UpdateWindows (W_ALL);
00809     return e;
00810 }
00811 
00812 
00813 /*
00814 ===========
00815 Entity_LinkBrush
00816 ===========
00817 */
00818 void Entity_LinkBrush (entity_t *e, brush_t *b)
00819 {
00820     if (b->oprev || b->onext)
00821         Error ("Entity_LinkBrush: Allready linked");
00822     b->owner = e;
00823 
00824     b->onext = e->brushes.onext;
00825     b->oprev = &e->brushes;
00826     e->brushes.onext->oprev = b;
00827     e->brushes.onext = b;
00828 }
00829 
00830 /*
00831 ===========
00832 Entity_UnlinkBrush
00833 ===========
00834 */
00835 void Entity_UnlinkBrush (brush_t *b)
00836 {
00837     //if (!b->owner || !b->onext || !b->oprev)
00838     if (!b->onext || !b->oprev)
00839         Error ("Entity_UnlinkBrush: Not currently linked");
00840     b->onext->oprev = b->oprev;
00841     b->oprev->onext = b->onext;
00842     b->onext = b->oprev = NULL;
00843     b->owner = NULL;
00844 }
00845 
00846 
00847 /*
00848 ===========
00849 Entity_Clone
00850 ===========
00851 */
00852 entity_t    *Entity_Clone (entity_t *e)
00853 {
00854     entity_t    *n;
00855     epair_t     *ep, *np;
00856 
00857     n = (entity_t*)qmalloc(sizeof(*n));
00858     n->entityId = g_entityId++;
00859     n->brushes.onext = n->brushes.oprev = &n->brushes;
00860     n->eclass = e->eclass;
00861 
00862     // add the entity to the entity list
00863     Entity_AddToList(n, &entities);
00864 
00865     for (ep = e->epairs ; ep ; ep=ep->next)
00866     {
00867         np = (epair_t*)qmalloc(sizeof(*np));
00868         np->key = copystring(ep->key);
00869         np->value = copystring(ep->value);
00870         np->next = n->epairs;
00871         n->epairs = np;
00872     }
00873     return n;
00874 }
00875 
00876 int GetUniqueTargetId(int iHint)
00877 {
00878     int iMin, iMax, i;
00879     BOOL fFound;
00880     entity_t *pe;
00881     
00882     fFound = FALSE;
00883     pe = entities.next;
00884     iMin = 0; 
00885     iMax = 0;
00886     
00887     for (; pe != NULL && pe != &entities ; pe = pe->next)
00888     {
00889         i = IntForKey(pe, "target");
00890         if (i)
00891         {
00892             iMin = min(i, iMin);
00893             iMax = max(i, iMax);
00894             if (i == iHint)
00895                 fFound = TRUE;
00896         }
00897     }
00898 
00899     if (fFound)
00900         return iMax + 1;
00901     else
00902         return iHint;
00903 }
00904 
00905 entity_t *FindEntity(char *pszKey, char *pszValue)
00906 {
00907     entity_t *pe;
00908     
00909     pe = entities.next;
00910     
00911     for (; pe != NULL && pe != &entities ; pe = pe->next)
00912     {
00913         if (!strcmp(ValueForKey(pe, pszKey), pszValue))
00914             return pe;
00915     }
00916 
00917     return NULL;
00918 }
00919 
00920 entity_t *FindEntityInt(char *pszKey, int iValue)
00921 {
00922     entity_t *pe;
00923     
00924     pe = entities.next;
00925     
00926     for (; pe != NULL && pe != &entities ; pe = pe->next)
00927     {
00928         if (IntForKey(pe, pszKey) == iValue)
00929             return pe;
00930     }
00931 
00932     return NULL;
00933 }

Generated on Thu Aug 25 12:38:28 2005 for Quake III Arena by  doxygen 1.3.9.1