]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/extra/qe4/entity.c
Q2Tools source - didn't import this in initially
[xonotic/netradiant.git] / tools / quake2 / extra / qe4 / entity.c
1 /*
2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
4
5 This file is part of Quake 2 Tools source code.
6
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22
23 #include "qe3.h"
24
25 char    *ValueForKey (entity_t *ent, char *key)
26 {
27         epair_t *ep;
28
29         for (ep=ent->epairs ; ep ; ep=ep->next)
30                 if (!strcmp (ep->key, key) )
31                         return ep->value;
32         return "";
33 }
34
35 void    SetKeyValue (entity_t *ent, char *key, char *value)
36 {
37         epair_t *ep;
38
39         if (ent == NULL)
40                 return;
41
42         if (!key || !key[0])
43                 return;
44
45         for (ep=ent->epairs ; ep ; ep=ep->next)
46                 if (!strcmp (ep->key, key) )
47                 {
48                         free (ep->value);
49                         ep->value = qmalloc(strlen(value)+1);
50                         strcpy (ep->value, value);
51                         return;
52                 }
53         ep = qmalloc (sizeof(*ep));
54         ep->next = ent->epairs;
55         ent->epairs = ep;
56         ep->key = qmalloc(strlen(key)+1);
57         strcpy (ep->key, key);
58         ep->value = qmalloc(strlen(value)+1);
59         strcpy (ep->value, value);
60 }
61
62 void    DeleteKey (entity_t *ent, char *key)
63 {
64         epair_t **ep, *next;
65
66         ep = &ent->epairs;
67         while (*ep)
68         {
69                 next = *ep;
70                 if ( !strcmp (next->key, key) )
71                 {
72                         *ep = next->next;
73                         free(next->key);
74                         free(next->value);
75                         free(next);
76                         return;
77                 }
78                 ep = &next->next;
79         }
80 }
81
82 float   FloatForKey (entity_t *ent, char *key)
83 {
84         char    *k;
85
86         k = ValueForKey (ent, key);
87         return atof(k);
88 }
89
90 int IntForKey (entity_t *ent, char *key)
91 {
92         char    *k;
93
94         k = ValueForKey (ent, key);
95         return atoi(k);
96 }
97
98 void    GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
99 {
100         char    *k;
101
102         k = ValueForKey (ent, key);
103         sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]);
104 }
105
106
107 /*
108 ===============
109 Entity_Free
110
111 Frees the entity and any brushes is has.
112 The entity is removed from the global entities list.
113 ===============
114 */
115 void Entity_Free (entity_t *e)
116 {
117         epair_t *ep, *next;
118
119         while (e->brushes.onext != &e->brushes)
120                 Brush_Free (e->brushes.onext);
121
122         if (e->next)
123         {
124                 e->next->prev = e->prev;
125                 e->prev->next = e->next;
126         }
127
128         for (ep = e->epairs ; ep ; ep=next)
129         {
130                 next = ep->next;
131                 free (ep);
132         }
133         free (e);
134 }
135
136 /*
137 =================
138 ParseEpair
139 =================
140 */
141 epair_t *ParseEpair (void)
142 {
143         epair_t *e;
144
145         e = qmalloc (sizeof(*e));
146
147         e->key = qmalloc(strlen(token)+1);
148         strcpy (e->key, token);
149
150         GetToken (false);
151         e->value = qmalloc(strlen(token)+1);
152         strcpy (e->value, token);
153
154         return e;
155 }
156
157 /*
158 ================
159 Entity_Parse
160
161 If onlypairs is set, the classname info will not
162 be looked up, and the entity will not be added
163 to the global list.  Used for parsing the project.
164 ================
165 */
166 entity_t        *Entity_Parse (qboolean onlypairs)
167 {
168         entity_t        *ent;
169         eclass_t        *e;
170         brush_t         *b;
171         vec3_t          mins, maxs;
172         epair_t         *ep;
173         qboolean        has_brushes;
174
175         if (!GetToken (true))
176                 return NULL;
177
178         if (strcmp (token, "{") )
179                 Error ("ParseEntity: { not found");
180
181         ent = qmalloc (sizeof(*ent));
182         ent->brushes.onext = ent->brushes.oprev = &ent->brushes;
183
184         do
185         {
186                 if (!GetToken (true))
187                         Error ("ParseEntity: EOF without closing brace");
188                 if (!strcmp (token, "}") )
189                         break;
190                 if (!strcmp (token, "{") )
191                 {
192                         b = Brush_Parse ();
193                         b->owner = ent;
194
195                         // add to the end of the entity chain
196                         b->onext = &ent->brushes;
197                         b->oprev = ent->brushes.oprev;
198                         ent->brushes.oprev->onext = b;
199                         ent->brushes.oprev = b;
200                 }
201                 else
202                 {
203                         ep = ParseEpair ();
204                         ep->next = ent->epairs;
205                         ent->epairs = ep;
206                 }
207         } while (1);
208
209         if (onlypairs)
210                 return ent;
211
212         if (ent->brushes.onext == &ent->brushes)
213                 has_brushes = false;
214         else
215                 has_brushes = true;
216
217         GetVectorForKey (ent, "origin", ent->origin);
218
219         e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes);
220         ent->eclass = e;
221         if (e->fixedsize)
222         {       // fixed size entity
223                 if (ent->brushes.onext != &ent->brushes)
224                 {
225                         printf ("Warning: Fixed size entity with brushes\n");
226 #if 0
227                         while (ent->brushes.onext != &ent->brushes)
228                         {       // FIXME: this will free the entity and crash!
229                                 Brush_Free (b);
230                         }
231 #endif
232 ent->brushes.next = ent->brushes.prev = &ent->brushes;
233                 }
234                 // create a custom brush
235                 VectorAdd (e->mins, ent->origin, mins);
236                 VectorAdd (e->maxs, ent->origin, maxs);
237                 b = Brush_Create (mins, maxs, &e->texdef);
238                 b->owner = ent;
239
240                 b->onext = ent->brushes.onext;
241                 b->oprev = &ent->brushes;
242                 ent->brushes.onext->oprev = b;
243                 ent->brushes.onext = b;
244         }
245         else
246         {       // brush entity
247                 if (ent->brushes.next == &ent->brushes)
248                         printf ("Warning: Brush entity with no brushes\n");
249         }
250
251         // add all the brushes to the main list
252         for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext)
253         {
254                 b->next = active_brushes.next;
255                 active_brushes.next->prev = b;
256                 b->prev = &active_brushes;
257                 active_brushes.next = b;
258         }
259
260         return ent;
261 }
262
263 /*
264 ============
265 Entity_Write
266 ============
267 */
268 void Entity_Write (entity_t *e, FILE *f, qboolean use_region)
269 {
270         epair_t         *ep;
271         brush_t         *b;
272         vec3_t          origin;
273         char            text[128];
274         int                     count;
275
276         // if none of the entities brushes are in the region,
277         // don't write the entity at all
278         if (use_region)
279         {
280                 // in region mode, save the camera position as playerstart
281                 if ( !strcmp(ValueForKey (e, "classname"), "info_player_start") )
282                 {
283                         fprintf (f, "{\n");
284                         fprintf (f, "\"classname\" \"info_player_start\"\n");
285                         fprintf (f, "\"origin\" \"%i %i %i\"\n", (int)camera.origin[0],
286                                 (int)camera.origin[1], (int)camera.origin[2]);
287                         fprintf (f, "\"angle\" \"%i\"\n", (int)camera.angles[YAW]);
288                         fprintf (f, "}\n");
289                         return;
290                 }
291
292                 for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
293                         if (!Map_IsBrushFiltered(b))
294                                 break;  // got one
295
296                 if (b == &e->brushes)
297                         return;         // nothing visible
298         }
299
300         // if fixedsize, calculate a new origin based on the current
301         // brush position
302         if (e->eclass->fixedsize)
303         {
304                 VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin);
305                 sprintf (text, "%i %i %i", (int)origin[0],
306                         (int)origin[1], (int)origin[2]);
307                 SetKeyValue (e, "origin", text);
308         }
309
310         fprintf (f, "{\n");
311         for (ep = e->epairs ; ep ; ep=ep->next)
312                 fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value);
313
314         if (!e->eclass->fixedsize)
315         {
316                 count = 0;
317                 for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
318                 {
319                         if (!use_region || !Map_IsBrushFiltered (b))
320                         {
321                                 fprintf (f, "// brush %i\n", count);
322                                 count++;
323                                 Brush_Write (b, f);
324                         }
325                 }
326         }
327         fprintf (f, "}\n");
328 }
329
330
331
332 /*
333 ============
334 Entity_Create
335
336 Creates a new entity out of the selected_brushes list.
337 If the entity class is fixed size, the brushes are only
338 used to find a midpoint.  Otherwise, the brushes have
339 their ownershi[ transfered to the new entity.
340 ============
341 */
342 entity_t        *Entity_Create (eclass_t *c)
343 {
344         entity_t        *e;
345         brush_t         *b;
346         vec3_t          mins, maxs;
347         int                     i;
348
349         // check to make sure the brushes are ok
350
351         for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
352                 if (b->owner != world_entity)
353                 {
354                         Sys_Printf ("Entity NOT created, brushes not all from world\n");
355                         Sys_Beep ();
356                         return NULL;
357                 }
358
359         // create it
360
361         e = qmalloc(sizeof(*e));
362         e->brushes.onext = e->brushes.oprev = &e->brushes;
363         e->eclass = c;
364         SetKeyValue (e, "classname", c->name);
365
366         // add the entity to the entity list
367         e->next = entities.next;
368         entities.next = e;
369         e->next->prev = e;
370         e->prev = &entities;
371
372         if (c->fixedsize)
373         {
374                 //
375                 // just use the selection for positioning
376                 //
377                 b = selected_brushes.next;
378                 for (i=0 ; i<3 ; i++)
379                         e->origin[i] = b->mins[i] - c->mins[i];
380
381                 // create a custom brush
382                 VectorAdd (c->mins, e->origin, mins);
383                 VectorAdd (c->maxs, e->origin, maxs);
384                 b = Brush_Create (mins, maxs, &c->texdef);
385
386                 Entity_LinkBrush (e, b);
387
388                 // delete the current selection
389                 Select_Delete ();
390
391                 // select the new brush
392                 b->next = b->prev = &selected_brushes;
393                 selected_brushes.next = selected_brushes.prev = b;
394
395                 Brush_Build( b );
396         }
397         else
398         {
399                 //
400                 // change the selected brushes over to the new entity
401                 //
402                 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
403                 {
404                         Entity_UnlinkBrush (b);
405                         Entity_LinkBrush (e, b);
406                         Brush_Build( b );       // so the key brush gets a name
407                 }
408         }
409
410         Sys_UpdateWindows (W_ALL);
411         return e;
412 }
413
414
415 /*
416 ===========
417 Entity_LinkBrush
418 ===========
419 */
420 void Entity_LinkBrush (entity_t *e, brush_t *b)
421 {
422         if (b->oprev || b->onext)
423                 Error ("Entity_LinkBrush: Allready linked");
424         b->owner = e;
425
426         b->onext = e->brushes.onext;
427         b->oprev = &e->brushes;
428         e->brushes.onext->oprev = b;
429         e->brushes.onext = b;
430 }
431
432 /*
433 ===========
434 Entity_UnlinkBrush
435 ===========
436 */
437 void Entity_UnlinkBrush (brush_t *b)
438 {
439         if (!b->owner || !b->onext || !b->oprev)
440                 Error ("Entity_UnlinkBrush: Not currently linked");
441         b->onext->oprev = b->oprev;
442         b->oprev->onext = b->onext;
443         b->onext = b->oprev = NULL;
444         b->owner = NULL;
445 }
446
447
448
449 /*
450 ===========
451 Entity_Clone
452 ===========
453 */
454 entity_t        *Entity_Clone (entity_t *e)
455 {
456         entity_t        *n;
457         epair_t         *ep, *np;
458
459         n = qmalloc(sizeof(*n));
460         n->brushes.onext = n->brushes.oprev = &n->brushes;
461         n->eclass = e->eclass;
462
463         // add the entity to the entity list
464         n->next = entities.next;
465         entities.next = n;
466         n->next->prev = n;
467         n->prev = &entities;
468
469         for (ep = e->epairs ; ep ; ep=ep->next)
470         {
471                 np = qmalloc(sizeof(*np));
472                 np->key = copystring(ep->key);
473                 np->value = copystring(ep->value);
474                 np->next = n->epairs;
475                 n->epairs = np;
476         }
477         return n;
478 }
479
480 int GetUniqueTargetId(int iHint)
481 {
482         int iMin, iMax, i;
483         BOOL fFound;
484         entity_t *pe;
485
486         fFound = FALSE;
487         pe = entities.next;
488         iMin = 0;
489         iMax = 0;
490
491         for (; pe != NULL && pe != &entities ; pe = pe->next)
492         {
493                 i = IntForKey(pe, "target");
494                 if (i)
495                 {
496                         iMin = min(i, iMin);
497                         iMax = max(i, iMax);
498                         if (i == iHint)
499                                 fFound = TRUE;
500                 }
501         }
502
503         if (fFound)
504                 return iMax + 1;
505         else
506                 return iHint;
507 }
508
509 entity_t *FindEntity(char *pszKey, char *pszValue)
510 {
511         entity_t *pe;
512
513         pe = entities.next;
514
515         for (; pe != NULL && pe != &entities ; pe = pe->next)
516         {
517                 if (!strcmp(ValueForKey(pe, pszKey), pszValue))
518                         return pe;
519         }
520
521         return NULL;
522 }
523
524 entity_t *FindEntityInt(char *pszKey, int iValue)
525 {
526         entity_t *pe;
527
528         pe = entities.next;
529
530         for (; pe != NULL && pe != &entities ; pe = pe->next)
531         {
532                 if (IntForKey(pe, pszKey) == iValue)
533                         return pe;
534         }
535
536         return NULL;
537 }
538