00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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,
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
00144 for (s = spawns; s->name; s++) {
00145
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
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
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
00239 while (1) {
00240
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
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
00260
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();
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;
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
00335 entnum = 0;
00336 while (1) {
00337
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
00354 VecToPos(ent->origin, ent->pos);
00355
00356
00357 ED_CallSpawn(ent);
00358
00359
00360 if (ent->solid == SOLID_BBOX)
00361 G_EdictCalcOrigin(ent);
00362 }
00363
00364
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
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
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
00458 level.num_spawnpoints[ent->team]++;
00459 ent->classname = "actor";
00460 ent->type = ET_ACTORSPAWN;
00461 ent->fieldSize = ACTOR_SIZE_NORMAL;
00462
00463
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
00474 ent->dir = AngleToDir(ent->angle);
00475 assert(ent->dir < CORE_DIRECTIONS);
00476 ent->solid = SOLID_BBOX;
00477
00478
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
00491 level.num_2x2spawnpoints[ent->team]++;
00492 ent->classname = "ugv";
00493 ent->type = ET_ACTOR2x2SPAWN;
00494 ent->fieldSize = ACTOR_SIZE_2x2;
00495
00496
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
00505 ent->dir = AngleToDir(ent->angle);
00506 assert(ent->dir < CORE_DIRECTIONS);
00507 ent->solid = SOLID_BBOX;
00508
00509
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
00522
00523 G_FreeEdict(ent);
00524 }
00525
00532 static void SP_player_start (edict_t *ent)
00533 {
00534
00535 if (sv_maxclients->integer == 1) {
00536 G_FreeEdict(ent);
00537 return;
00538 }
00539
00541
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
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
00575 if (sv_maxclients->integer > 1) {
00576 G_FreeEdict(ent);
00577 return;
00578 }
00579
00580 ent->STUN = 0;
00581 ent->HP = MAX_HP;
00582
00583 if (!ent->team)
00584 ent->team = TEAM_PHALANX;
00585
00586
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
00591 G_Actor2x2Spawn(ent);
00592 }
00593
00598 static void SP_alien_start (edict_t *ent)
00599 {
00600
00601 if (sv_maxclients->integer > 1 && !ai_numactors->integer) {
00602 G_FreeEdict(ent);
00603 return;
00604 }
00605 ent->team = TEAM_ALIEN;
00606
00607 ent->STUN = 0;
00608 ent->HP = MAX_HP;
00609
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
00634 if (sv_maxclients->integer > 1 && !ai_numcivilians->integer) {
00635 G_FreeEdict(ent);
00636 return;
00637 }
00638 ent->team = TEAM_CIVILIAN;
00639
00640 ent->STUN = 99;
00641 ent->HP = MAX_HP;
00642 ent->count = 100;
00643 G_ActorSpawn(ent);
00644 }
00645
00653 static void SP_civilian_target (edict_t *ent)
00654 {
00655
00656 ent->team = TEAM_CIVILIAN;
00657 ent->classname = "civtarget";
00658 ent->type = ET_CIVILIANTARGET;
00659 ent->fieldSize = ACTOR_SIZE_NORMAL;
00660
00661
00662 G_AddToWayPointList(ent);
00663
00664
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
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
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
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
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
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
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
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
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
00868
00869 G_FreeEdict(ent);
00870 }
00871
00880 static void SP_worldspawn (edict_t *ent)
00881 {
00882 ent->solid = SOLID_BSP;
00883
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
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 }