g_spawn.c

Go to the documentation of this file.
00001 
00006 /*
00007 All original material Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 Original file from Quake 2 v3.21: quake2-2.31/game/g_spawn.c
00010 Copyright (C) 1997-2001 Id Software, Inc.
00011 
00012 This program is free software; you can redistribute it and/or
00013 modify it under the terms of the GNU General Public License
00014 as published by the Free Software Foundation; either version 2
00015 of the License, or (at your option) any later version.
00016 
00017 This program is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00020 
00021 See the GNU General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; if not, write to the Free Software
00025 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00026 
00027 */
00028 
00029 
00030 #include "g_local.h"
00031 #include "../shared/parse.h"
00032 
00033 static spawn_temp_t st;
00034 
00035 static void SP_light(edict_t *ent);
00036 static void SP_dummy(edict_t *ent);
00037 static void SP_player_start(edict_t *ent);
00038 static void SP_human_start(edict_t *ent);
00039 static void SP_alien_start(edict_t *ent);
00040 static void SP_civilian_start(edict_t *ent);
00041 static void SP_worldspawn(edict_t *ent);
00042 static void SP_2x2_start(edict_t *ent);
00043 static void SP_civilian_target(edict_t *ent);
00044 static void SP_misc_model(edict_t *ent);
00045 static void SP_misc_item(edict_t *ent);
00046 static void SP_misc_mission(edict_t *ent);
00047 static void SP_misc_mission_aliens(edict_t *ent);
00048 static void SP_misc_message(edict_t *ent);
00049 
00050 typedef struct {
00051     const char *name;
00052     void (*spawn) (edict_t * ent);
00053 } spawn_t;
00054 
00055 static const spawn_t spawns[] = {
00056     {"worldspawn", SP_worldspawn},
00057     {"light", SP_light},
00058     {"misc_item", SP_misc_item},
00059     {"misc_sound", SP_dummy},
00060     {"misc_model", SP_misc_model},
00061     {"misc_particle", SP_dummy},
00062     {"misc_mission", SP_misc_mission},
00063     {"misc_mission_aliens", SP_misc_mission_aliens},
00064     {"info_player_start", SP_player_start},
00065     {"info_human_start", SP_human_start},
00066     {"info_alien_start", SP_alien_start},
00067     {"info_civilian_start", SP_civilian_start},
00068     {"info_civilian_target", SP_civilian_target},
00069     {"info_2x2_start", SP_2x2_start},
00070     {"info_null", SP_dummy},
00071     {"func_breakable", SP_func_breakable},
00072     {"func_door", SP_func_door},
00073     {"func_rotating", SP_func_rotating},
00074     {"trigger_hurt", SP_trigger_hurt},
00075     {"trigger_touch", SP_trigger_touch},
00076     {"trigger_rescue", SP_trigger_rescue},
00077     {"misc_message", SP_misc_message},
00078 
00079     {NULL, NULL}
00080 };
00081 
00082 typedef enum {
00083     F_INT,
00084     F_FLOAT,
00085     F_LSTRING,                  /* string on disk, pointer in memory, TAG_LEVEL */
00086     F_VECTOR,
00087     F_IGNORE
00088 } fieldtype_t;
00089 
00090 typedef struct {
00091     const char *name;
00092     size_t ofs;
00093     fieldtype_t type;
00094     int flags;
00095 } field_t;
00096 
00097 static const field_t fields[] = {
00098     {"classname", offsetof(edict_t, classname), F_LSTRING, 0},
00099     {"model", offsetof(edict_t, model), F_LSTRING, 0},
00100     {"spawnflags", offsetof(edict_t, spawnflags), F_INT, 0},
00101     {"speed", offsetof(edict_t, speed), F_INT, 0},
00102     {"target", offsetof(edict_t, target), F_LSTRING, 0},
00103     {"targetname", offsetof(edict_t, targetname), F_LSTRING, 0},
00104     {"item", offsetof(edict_t, item), F_LSTRING, 0},
00105     {"noise", offsetof(edict_t, noise), F_LSTRING, 0},
00106     {"particle", offsetof(edict_t, particle), F_LSTRING, 0},
00107     {"frame", offsetof(edict_t, frame), F_INT, 0},
00108     {"team", offsetof(edict_t, team), F_INT, 0},
00109     {"group", offsetof(edict_t, group), F_LSTRING, 0},
00110     {"size", offsetof(edict_t, fieldSize), F_INT, 0},
00111     {"count", offsetof(edict_t, count), F_INT, 0},
00112     {"time", offsetof(edict_t, time), F_INT, 0},
00113     {"health", offsetof(edict_t, HP), F_INT, 0},
00114     {"sounds", offsetof(edict_t, sounds), F_INT, 0},
00115     {"material", offsetof(edict_t, material), F_INT, 0},
00116     {"light", 0, F_IGNORE, 0},
00119     {"maxteams", 0, F_IGNORE, 0},
00120     {"maxlevel", 0, F_IGNORE, 0},
00121     {"dmg", offsetof(edict_t, dmg), F_INT, 0},
00122     {"origin", offsetof(edict_t, origin), F_VECTOR, 0},
00123     {"angles", offsetof(edict_t, angles), F_VECTOR, 0},
00124     {"angle", offsetof(edict_t, angle), F_FLOAT, 0},
00125     {"message", offsetof(edict_t, message), F_LSTRING, 0},
00126 
00127     {"nextmap", offsetof(spawn_temp_t, nextmap), F_LSTRING, FFL_SPAWNTEMP},
00128     {"randomspawn", offsetof(spawn_temp_t, randomSpawn), F_INT, FFL_SPAWNTEMP},
00129 
00130     {0, 0, 0, 0}
00131 };
00132 
00136 static void ED_CallSpawn (edict_t * ent)
00137 {
00138     const spawn_t *s;
00139 
00140     if (!ent->classname)
00141         return;
00142 
00143     /* check normal spawn functions */
00144     for (s = spawns; s->name; s++) {
00145         /* found it */
00146         if (!strcmp(s->name, ent->classname)) {
00147             s->spawn(ent);
00148             return;
00149         }
00150     }
00151 
00152     ent->inuse = qfalse;
00153 }
00154 
00160 static char *ED_NewString (const char *string)
00161 {
00162     char *newb, *new_p;
00163     int i;
00164     const size_t l = strlen(string) + 1;
00165 
00166     newb = (char*)G_TagMalloc(l, TAG_LEVEL);
00167     new_p = newb;
00168 
00169     for (i = 0; i < l; i++) {
00170         /* check for special chars and convert them */
00171         if (string[i] == '\\' && i < l - 1) {
00172             i++;
00173             if (string[i] == 'n')
00174                 *new_p++ = '\n';
00175             else
00176                 *new_p++ = '\\';
00177         } else
00178             *new_p++ = string[i];
00179     }
00180 
00181     return newb;
00182 }
00183 
00187 static void ED_ParseField (const char *key, const char *value, edict_t * ent)
00188 {
00189     const field_t *f;
00190     byte *b;
00191     vec3_t vec;
00192 
00193     for (f = fields; f->name; f++) {
00194         if (!(f->flags & FFL_NOSPAWN) && !Q_strcasecmp(f->name, key)) {
00195             /* found it */
00196             if (f->flags & FFL_SPAWNTEMP)
00197                 b = (byte *) & st;
00198             else
00199                 b = (byte *) ent;
00200 
00201             switch (f->type) {
00202             case F_LSTRING:
00203                 *(char **) (b + f->ofs) = ED_NewString(value);
00204                 break;
00205             case F_VECTOR:
00206                 sscanf(value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
00207                 ((float *) (b + f->ofs))[0] = vec[0];
00208                 ((float *) (b + f->ofs))[1] = vec[1];
00209                 ((float *) (b + f->ofs))[2] = vec[2];
00210                 break;
00211             case F_INT:
00212                 *(int *) (b + f->ofs) = atoi(value);
00213                 break;
00214             case F_FLOAT:
00215                 *(float *) (b + f->ofs) = atof(value);
00216                 break;
00217             case F_IGNORE:
00218                 break;
00219             }
00220             return;
00221         }
00222     }
00223 }
00224 
00230 static const char *ED_ParseEdict (const char *data, edict_t * ent)
00231 {
00232     qboolean init;
00233     char keyname[MAX_VAR];
00234 
00235     init = qfalse;
00236     memset(&st, 0, sizeof(st));
00237 
00238     /* go through all the dictionary pairs */
00239     while (1) {
00240         /* parse key */
00241         const char *c = Com_Parse(&data);
00242         if (c[0] == '}')
00243             break;
00244         if (!data)
00245             gi.Error("ED_ParseEntity: EOF without closing brace");
00246 
00247         Q_strncpyz(keyname, c, sizeof(keyname));
00248 
00249         /* parse value */
00250         c = Com_Parse(&data);
00251         if (!data)
00252             gi.Error("ED_ParseEntity: EOF without closing brace");
00253 
00254         if (c[0] == '}')
00255             gi.Error("ED_ParseEntity: closing brace without data");
00256 
00257         init = qtrue;
00258 
00259         /* keynames with a leading underscore are used for utility comments,
00260          * and are immediately discarded by ufo */
00261         if (keyname[0] == '_')
00262             continue;
00263 
00264         ED_ParseField(keyname, c, ent);
00265     }
00266 
00267     if (!init)
00268         memset(ent, 0, sizeof(*ent));
00269 
00270     return data;
00271 }
00272 
00278 static void G_FindEdictGroups (void)
00279 {
00280     edict_t *ent = G_EdictsGetFirst(); /* the first edict is always a world edict that can be skipped */
00281 
00282     while ((ent = G_EdictsGetNextInUse(ent))) {
00283         edict_t *ent2, *chain;
00284 
00285         if (!ent->group)
00286             continue;
00287         if (ent->flags & FL_GROUPSLAVE)
00288             continue;
00289         chain = ent;
00290         ent->groupMaster = ent;
00291         ent2 = ent;         /* search only the remainder of the entities */
00292         while ((ent2 = G_EdictsGetNextInUse(ent2))) {
00293             if (!ent2->group)
00294                 continue;
00295             if (ent2->flags & FL_GROUPSLAVE)
00296                 continue;
00297             if (!strcmp(ent->group, ent2->group)) {
00298                 chain->groupChain = ent2;
00299                 ent2->groupMaster = ent;
00300                 chain = ent2;
00301                 ent2->flags |= FL_GROUPSLAVE;
00302             }
00303         }
00304     }
00305 }
00306 
00313 void G_SpawnEntities (const char *mapname, qboolean day, const char *entities)
00314 {
00315     edict_t *ent;
00316     int entnum;
00317 
00318     G_FreeTags(TAG_LEVEL);
00319 
00320     memset(&level, 0, sizeof(level));
00321     G_EdictsReset();
00322 
00323     Q_strncpyz(level.mapname, mapname, sizeof(level.mapname));
00324     level.day = day;
00325 
00326     G_ResetClientData();
00327 
00328     ent = NULL;
00329     level.activeTeam = TEAM_NO_ACTIVE;
00330     level.actualRound = 1;
00331     level.hurtAliens = sv_hurtaliens->integer;
00332     ai_waypointList = NULL;
00333 
00334     /* parse ents */
00335     entnum = 0;
00336     while (1) {
00337         /* parse the opening brace */
00338         const char *token = Com_Parse(&entities);
00339         if (!entities)
00340             break;
00341         if (token[0] != '{')
00342             gi.Error("ED_LoadFromFile: found %s when expecting {", token);
00343 
00344         if (!ent)
00345             ent = G_EdictsGetFirst();
00346         else
00347             ent = G_Spawn();
00348 
00349         entities = ED_ParseEdict(entities, ent);
00350 
00351         ent->mapNum = entnum++;
00352 
00353         /* Set the position of the entity */
00354         VecToPos(ent->origin, ent->pos);
00355 
00356         /* Call this entity's specific initializer (sets ent->type) */
00357         ED_CallSpawn(ent);
00358 
00359         /* if this entity is an bbox (e.g. actor), then center its origin based on its position */
00360         if (ent->solid == SOLID_BBOX)
00361             G_EdictCalcOrigin(ent);
00362     }
00363 
00364     /* spawn ai players, if needed */
00365     if (level.num_spawnpoints[TEAM_CIVILIAN]) {
00366         if (AI_CreatePlayer(TEAM_CIVILIAN) == NULL)
00367             gi.DPrintf("Could not create civilian\n");
00368     }
00369 
00370     if ((sv_maxclients->integer == 1 || ai_numactors->integer) && level.num_spawnpoints[TEAM_ALIEN]) {
00371         if (AI_CreatePlayer(TEAM_ALIEN) == NULL)
00372             gi.DPrintf("Could not create alien\n");
00373     }
00374 
00375     Com_Printf("Used inventory slots after ai spawn: %i\n", game.i.GetUsedSlots(&game.i));
00376 
00377     G_FindEdictGroups();
00378 }
00379 
00383 static inline void G_InitEdict (edict_t * ent)
00384 {
00385     ent->inuse = qtrue;
00386     ent->classname = "noclass";
00387     ent->number = G_EdictsGetNumber(ent);
00388     ent->fieldSize = ACTOR_SIZE_NORMAL;
00389 }
00390 
00400 edict_t *G_Spawn (void)
00401 {
00402     edict_t *ent = G_EdictsGetNewEdict();
00403 
00404     if (!ent)
00405         gi.Error("G_Spawn: no free edicts");
00406 
00407     G_InitEdict(ent);
00408     return ent;
00409 }
00410 
00415 edict_t *G_SpawnFloor (const pos3_t pos)
00416 {
00417     edict_t *floor;
00418 
00419     floor = G_Spawn();
00420     floor->classname = "item";
00421     floor->type = ET_ITEM;
00422     /* make sure that the item is always on a field that even the smallest actor can reach */
00423     floor->fieldSize = ACTOR_SIZE_NORMAL;
00424     VectorCopy(pos, floor->pos);
00425     floor->pos[2] = gi.GridFall(gi.routingMap, floor->fieldSize, floor->pos);
00426     G_EdictCalcOrigin(floor);
00427     return floor;
00428 }
00429 
00434 edict_t *G_SpawnParticle (const vec3_t origin, int spawnflags, const char *particle)
00435 {
00436     edict_t *ent = G_Spawn();
00437     ent->classname = "particle";
00438     ent->type = ET_PARTICLE;
00439     VectorCopy(origin, ent->origin);
00440 
00441     /* Set the position of the entity */
00442     VecToPos(ent->origin, ent->pos);
00443 
00444     ent->particle = particle;
00445     ent->spawnflags = spawnflags;
00446 
00447     G_CheckVis(ent, qtrue);
00448 
00449     return ent;
00450 }
00451 
00455 static void G_ActorSpawn (edict_t *ent)
00456 {
00457     /* set properties */
00458     level.num_spawnpoints[ent->team]++;
00459     ent->classname = "actor";
00460     ent->type = ET_ACTORSPAWN;
00461     ent->fieldSize = ACTOR_SIZE_NORMAL;
00462 
00463     /* Fall to ground */
00464     if (ent->pos[2] >= PATHFINDING_HEIGHT)
00465         ent->pos[2] = PATHFINDING_HEIGHT - 1;
00466 
00467     ent->pos[2] = gi.GridFall(gi.routingMap, ent->fieldSize, ent->pos);
00468     if (ent->pos[2] >= PATHFINDING_HEIGHT)
00469         gi.DPrintf("G_ActorSpawn: Warning: z level is out of bounds: %i\n", ent->pos[2]);
00470 
00471     G_EdictCalcOrigin(ent);
00472 
00473     /* link it for collision detection */
00474     ent->dir = AngleToDir(ent->angle);
00475     assert(ent->dir < CORE_DIRECTIONS);
00476     ent->solid = SOLID_BBOX;
00477 
00478     /* Set bounding box. Maybe this is already set in one of the spawn functions? */
00479     if (ent->maxs[0] == 0)
00480         VectorSet(ent->maxs, PLAYER_WIDTH, PLAYER_WIDTH, PLAYER_STAND);
00481     if (ent->mins[0] == 0)
00482         VectorSet(ent->mins, -PLAYER_WIDTH, -PLAYER_WIDTH, PLAYER_MIN);
00483 }
00484 
00488 static void G_Actor2x2Spawn (edict_t *ent)
00489 {
00490     /* set properties */
00491     level.num_2x2spawnpoints[ent->team]++;
00492     ent->classname = "ugv";
00493     ent->type = ET_ACTOR2x2SPAWN;
00494     ent->fieldSize = ACTOR_SIZE_2x2;
00495 
00496     /* Fall to ground */
00497     if (ent->pos[2] >= PATHFINDING_HEIGHT)
00498         ent->pos[2] = PATHFINDING_HEIGHT - 1;
00499     ent->pos[2] = gi.GridFall(gi.routingMap, ent->fieldSize, ent->pos);
00500     if (ent->pos[2] >= PATHFINDING_HEIGHT)
00501         gi.DPrintf("G_Actor2x2Spawn: Warning: z level is out of bounds: %i\n", ent->pos[2]);
00502     G_EdictCalcOrigin(ent);
00503 
00504     /* link it for collision detection */
00505     ent->dir = AngleToDir(ent->angle);
00506     assert(ent->dir < CORE_DIRECTIONS);
00507     ent->solid = SOLID_BBOX;
00508 
00509     /* Set bounding box. Maybe this is already set in one of the spawn functions? */
00510     if (ent->maxs[0] == 0)
00511         VectorSet(ent->maxs, PLAYER2x2_WIDTH, PLAYER2x2_WIDTH, PLAYER_STAND);
00512     if (ent->mins[0] == 0)
00513         VectorSet(ent->mins, -PLAYER2x2_WIDTH, -PLAYER2x2_WIDTH, PLAYER_MIN);
00514 }
00515 
00519 static void SP_light (edict_t *ent)
00520 {
00521     /* lights aren't client-server communicated items */
00522     /* they are completely client side */
00523     G_FreeEdict(ent);
00524 }
00525 
00532 static void SP_player_start (edict_t *ent)
00533 {
00534     /* only used in multi player */
00535     if (sv_maxclients->integer == 1) {
00536         G_FreeEdict(ent);
00537         return;
00538     }
00539 
00541     /* maybe there are already the max soldiers allowed per team connected */
00542     if (sv_maxsoldiersperteam->integer > level.num_spawnpoints[ent->team]) {
00543         ent->STUN = 0;
00544         ent->HP = MAX_HP;
00545         G_ActorSpawn(ent);
00546     } else
00547         G_FreeEdict(ent);
00548 }
00549 
00554 static void SP_human_start (edict_t *ent)
00555 {
00556     /* only used in single player */
00557     if (sv_maxclients->integer > 1) {
00558         G_FreeEdict(ent);
00559         return;
00560     }
00561     ent->team = TEAM_PHALANX;
00562     ent->STUN = 0;
00563     ent->HP = MAX_HP;
00564     G_ActorSpawn(ent);
00565 }
00566 
00567 
00572 static void SP_2x2_start (edict_t *ent)
00573 {
00574     /* no 2x2 unit in multiplayer */
00575     if (sv_maxclients->integer > 1) {
00576         G_FreeEdict(ent);
00577         return;
00578     }
00579     /* set stats */
00580     ent->STUN = 0;
00581     ent->HP = MAX_HP;
00582 
00583     if (!ent->team)
00584         ent->team = TEAM_PHALANX;
00585 
00586     /* these units are bigger */
00587     VectorSet(ent->maxs, PLAYER_WIDTH * 2, PLAYER_WIDTH * 2, PLAYER_STAND);
00588     VectorSet(ent->mins, -(PLAYER_WIDTH * 2), -(PLAYER_WIDTH * 2), PLAYER_MIN);
00589 
00590     /* spawn singleplayer 2x2 unit */
00591     G_Actor2x2Spawn(ent);
00592 }
00593 
00598 static void SP_alien_start (edict_t *ent)
00599 {
00600     /* deactivateable in multiplayer */
00601     if (sv_maxclients->integer > 1 && !ai_numactors->integer) {
00602         G_FreeEdict(ent);
00603         return;
00604     }
00605     ent->team = TEAM_ALIEN;
00606     /* set stats */
00607     ent->STUN = 0;
00608     ent->HP = MAX_HP;
00609     /* hurt aliens in ufo crash missions (5%: almost dead, 15%: wounded, 30%: stunned)  */
00610     if (level.hurtAliens) {
00611         const float random = frand();
00612         if (random <= .05f) {
00613             ent->STUN = 50;
00614             ent->HP = 5;
00615         } else if (random <= .15f) {
00616             ent->STUN = 30;
00617             ent->HP /= 2;
00618         } else if (random <= .3f) {
00619             ent->STUN = 75;
00620         }
00621     }
00622 
00623     G_ActorSpawn(ent);
00624 }
00625 
00626 
00631 static void SP_civilian_start (edict_t *ent)
00632 {
00633     /* deactivateable in multiplayer */
00634     if (sv_maxclients->integer > 1 && !ai_numcivilians->integer) {
00635         G_FreeEdict(ent);
00636         return;
00637     }
00638     ent->team = TEAM_CIVILIAN;
00639     /* set stats */
00640     ent->STUN = 99; 
00641     ent->HP = MAX_HP;
00642     ent->count = 100; /* current waypoint */
00643     G_ActorSpawn(ent);
00644 }
00645 
00653 static void SP_civilian_target (edict_t *ent)
00654 {
00655     /* target point for which team */
00656     ent->team = TEAM_CIVILIAN;
00657     ent->classname = "civtarget";
00658     ent->type = ET_CIVILIANTARGET;
00659     ent->fieldSize = ACTOR_SIZE_NORMAL; /* to let the grid fall function work */
00660 
00661     /* add the edict to the list of known waypoints */
00662     G_AddToWayPointList(ent);
00663 
00664     /* fall to ground */
00665     if (ent->pos[2] >= PATHFINDING_HEIGHT)
00666         ent->pos[2] = PATHFINDING_HEIGHT - 1;
00667     ent->pos[2] = gi.GridFall(gi.routingMap, ent->fieldSize, ent->pos);
00668     G_EdictCalcOrigin(ent);
00669 }
00670 
00674 static void SP_misc_mission (edict_t *ent)
00675 {
00676     edict_t *other;
00677 
00678     ent->classname = "mission";
00679     ent->type = ET_MISSION;
00680 
00681     /* maybe this was set to something else for multiplayer */
00682     if (!ent->team)
00683         ent->team = TEAM_PHALANX;
00684 
00685     ent->solid = SOLID_BBOX;
00686 
00687     if (ent->HP) {
00688         ent->flags |= FL_DESTROYABLE;
00689         ent->destroy = G_MissionDestroy;
00690     }
00691 
00692     if (!ent->HP && !ent->time && !ent->target) {
00693         G_FreeEdict(ent);
00694         gi.DPrintf("misc_mission given with no objective\n");
00695         return;
00696     }
00697 
00698     /* think function values */
00699     ent->think = G_MissionThink;
00700     ent->nextthink = 1;
00701 
00702     VectorSet(ent->absmax, PLAYER_WIDTH * 3, PLAYER_WIDTH * 3, PLAYER_STAND);
00703     VectorSet(ent->absmin, -(PLAYER_WIDTH * 3), -(PLAYER_WIDTH * 3), PLAYER_MIN);
00704 
00705     /* spawn the trigger entity */
00706     other = G_TriggerSpawn(ent);
00707     other->touch = G_MissionTouch;
00708     if (ent->target)
00709         ent->use = G_MissionUse;
00710     ent->child = other;
00711 
00712     gi.LinkEdict(ent);
00713 }
00714 
00718 static void SP_misc_mission_aliens (edict_t *ent)
00719 {
00720     edict_t *other;
00721 
00722     ent->classname = "mission";
00723     ent->type = ET_MISSION;
00724     ent->team = TEAM_ALIEN;
00725     ent->solid = SOLID_BBOX;
00726 
00727     /* think function values */
00728     ent->think = G_MissionThink;
00729     ent->nextthink = 1;
00730 
00731     VectorSet(ent->absmax, PLAYER_WIDTH * 3, PLAYER_WIDTH * 3, PLAYER_STAND);
00732     VectorSet(ent->absmin, -(PLAYER_WIDTH * 3), -(PLAYER_WIDTH * 3), PLAYER_MIN);
00733 
00734     /* spawn the trigger entity */
00735     other = G_TriggerSpawn(ent);
00736     other->touch = G_MissionTouch;
00737     ent->child = other;
00738 
00739     gi.LinkEdict(ent);
00740 }
00741 
00747 static void G_BuildForbiddenListForEntity (edict_t *ent)
00748 {
00749     pos3_t mins, maxs, origin;
00750     vec3_t center, shiftedMins, shiftedMaxs;
00751     int xDelta, yDelta, size, i, j;
00752 
00753     VectorAdd(ent->absmin, ent->origin, shiftedMins);
00754     VectorAdd(ent->absmax, ent->origin, shiftedMaxs);
00755 
00756     VectorCenterFromMinsMaxs(shiftedMins, shiftedMaxs, center);
00757     VecToPos(shiftedMins, mins);
00758     VecToPos(shiftedMaxs, maxs);
00759     VecToPos(center, origin);
00760 
00761     xDelta = max(1, maxs[0] - mins[0]);
00762     yDelta = max(1, maxs[1] - mins[1]);
00763 
00764     size = xDelta * yDelta;
00765     ent->forbiddenListPos = (pos3_t *)G_TagMalloc(size * sizeof(pos3_t), TAG_LEVEL);
00766     ent->forbiddenListSize = size;
00767 
00768     for (i = 0; i < xDelta; i++) {
00769         for (j = 0; j < yDelta; j++) {
00770             const pos_t x = mins[0] + i;
00771             const pos_t y = mins[1] + j;
00772             const pos_t z = origin[2];
00773             VectorSet(ent->forbiddenListPos[i], x, y, z);
00774         }
00775     }
00776 }
00777 
00778 #define MISC_MODEL_SOLID 256
00779 
00782 static void SP_misc_model (edict_t *ent)
00783 {
00784     if (ent->spawnflags & MISC_MODEL_SOLID) {
00785         if (ent->model && ent->model[0] != '\0') {
00786             vec3_t modelMins, modelMaxs;
00787             if (gi.LoadModelMinsMaxs(ent->model, ent->frame, modelMins, modelMaxs)) {
00788                 ent->classname = "model";
00789                 VectorCopy(modelMaxs, ent->absmax);
00790                 VectorCopy(modelMins, ent->absmin);
00791                 ent->type = ET_SOLID;
00792                 ent->solid = SOLID_BBOX;
00794                 ent->fieldSize = ACTOR_SIZE_NORMAL;
00795                 G_BuildForbiddenListForEntity(ent);
00796                 gi.LinkEdict(ent);
00797             } else {
00798                 gi.DPrintf("Could not get mins/maxs for model '%s'\n", ent->model);
00799                 G_FreeEdict(ent);
00800             }
00801         } else {
00802             gi.DPrintf("server_solid misc_model with no model given\n");
00803             G_FreeEdict(ent);
00804         }
00805     } else {
00806         /* handled client side */
00807         G_FreeEdict(ent);
00808     }
00809 }
00810 
00814 static void SP_misc_item (edict_t *ent)
00815 {
00816     if (!ent->item) {
00817         gi.DPrintf("No item defined in misc_item\n");
00818         G_FreeEdict(ent);
00819         return;
00820     }
00821 
00822     G_AddItemToFloor(ent->pos, ent->item);
00823 
00824     /* now we can free the original edict */
00825     G_FreeEdict(ent);
00826 }
00827 
00828 static qboolean Message_Use (edict_t *self, edict_t *activator)
00829 {
00830     if (!activator || !G_IsActor(activator)) {
00831         return qfalse;
00832     } else {
00833         player_t *player = G_PLAYER_FROM_ENT(activator);
00834         const char *msg = self->message;
00835         /* remove gettext marker */
00836         if (msg[0] == '_')
00837             msg++;
00838         G_ClientPrintf(player, PRINT_HUD, "%s", msg);
00839 
00840         if (self->spawnflags & 1)
00841             G_FreeEdict(self);
00842 
00843         return qfalse;
00844     }
00845 }
00846 
00847 static void SP_misc_message (edict_t *ent)
00848 {
00849     if (!ent->message) {
00850         G_FreeEdict(ent);
00851         return;
00852     }
00853 
00854     if (ent->message[0] != '_')
00855         gi.DPrintf("No translation marker for misc_message set\n");
00856     ent->use = Message_Use;
00857     ent->classname = "misc_message";
00858     ent->type = ET_MESSAGE;
00859     ent->solid = SOLID_NOT;
00860 }
00861 
00865 static void SP_dummy (edict_t *ent)
00866 {
00867     /* particles aren't client-server communicated items
00868      * they are completely client side */
00869     G_FreeEdict(ent);
00870 }
00871 
00880 static void SP_worldspawn (edict_t *ent)
00881 {
00882     ent->solid = SOLID_BSP;
00883     /* since the world doesn't use G_Spawn() */
00884     ent->inuse = qtrue;
00885     ent->classname = "worldspawn";
00886 
00887     if (st.nextmap)
00888         Q_strncpyz(level.nextmap, st.nextmap, sizeof(level.nextmap));
00889     level.randomSpawn = st.randomSpawn;
00890 
00891     gi.ConfigString(CS_MAXCLIENTS, "%i", sv_maxclients->integer);
00892 
00893     /* only used in multi player */
00894     if (sv_maxclients->integer >= 2) {
00895         gi.ConfigString(CS_MAXSOLDIERSPERTEAM, "%i", sv_maxsoldiersperteam->integer);
00896         gi.ConfigString(CS_MAXSOLDIERSPERPLAYER, "%i", sv_maxsoldiersperplayer->integer);
00897         gi.ConfigString(CS_ENABLEMORALE, "%i", sv_enablemorale->integer);
00898         gi.ConfigString(CS_MAXTEAMS, "%s", sv_maxteams->string);
00899     }
00900 }

Generated by  doxygen 1.6.2