void EAVYSetupFlagSpots(void) { edict_t *ent, *spot; spot = G_Find (NULL, FOFS(classname), "misc_ctf_small_banner"); if (!spot && ctf->value) { ent = G_Find (NULL, FOFS(classname), "info_player_team1"); spot = G_Find (NULL, FOFS(classname), "info_player_team2"); if (!ent && !spot) { ent = G_Find (NULL, FOFS(classname), "item_flag_team1"); spot = G_Spawn (); spot->classname = "misc_ctf_small_banner"; spot->spawnflags = 0; VectorCopy (ent->s.origin, spot->s.origin); ED_CallSpawn (spot); EAVYSpawnTeamNearFlag (ent); ent = G_Find (NULL, FOFS(classname), "item_flag_team2"); spot = G_Spawn (); spot->classname = "misc_ctf_small_banner"; spot->spawnflags = 1; VectorCopy (ent->s.origin, spot->s.origin); ED_CallSpawn (spot); EAVYSpawnTeamNearFlag (ent); EAVYSpawnTeamNearFlagCheck(); } } }
void EAVYSpawnFlags(void) { edict_t *redflag, *blueflag; redflag = G_Find (NULL, FOFS(classname), "item_flag_team1"); blueflag = G_Find (NULL, FOFS(classname), "item_flag_team2"); if (ctf->value && !redflag) { redflag = G_Find (NULL, FOFS(classname), "info_player_deathmatch"); redflag = EAVYFindFarthestFlagPosition(redflag); if (!redflag) redflag = G_Find (NULL, FOFS(classname), "info_player_start"); if (redflag) { redflag->classname = "item_flag_team1"; ED_CallSpawn (redflag); } } if (redflag && !blueflag) { blueflag = EAVYFindFarthestFlagPosition(redflag); if (blueflag) { blueflag->classname = "item_flag_team2"; ED_CallSpawn (blueflag); } } if (ctf->value && !blueflag) gi.dprintf ("EAVY.EAVYSpawnFlags = FAILED!\n"); }
/* void medic_dodge (edict_t *self, edict_t *attacker, float eta, trace_t *tr) { if (random() > 0.25) return; if (!self->enemy) self->enemy = attacker; self->monsterinfo.currentmove = &medic_move_duck; //=========== //PMM - rogue rewrite of dodge code. float r; float height; int shooting = 0; // this needs to be before the AI_MEDIC check, because // a) if AI_MEDIC is set, we should have an enemy anyway and // b) FoundTarget calls medic_run, which can set AI_MEDIC if (!self->enemy) { self->enemy = attacker; FoundTarget (self); } // don't dodge if you're healing if (self->monsterinfo.aiflags & AI_MEDIC) return; // PMM - don't bother if it's going to hit anyway; fix for weird in-your-face etas (I was // seeing numbers like 13 and 14) if ((eta < 0.1) || (eta > 5)) return; r = random(); if (r > (0.25*((skill->value)+1))) return; if ((self->monsterinfo.currentmove == &medic_move_attackHyperBlaster) || (self->monsterinfo.currentmove == &medic_move_attackCable) || (self->monsterinfo.currentmove == &medic_move_attackBlaster)) { shooting = 1; } if (self->monsterinfo.aiflags & AI_DODGING) { height = self->absmax[2]; } else { height = self->absmax[2]-32-1; // the -1 is because the absmax is s.origin + maxs + 1 } // check to see if it makes sense to duck if (tr->endpos[2] <= height) { vec3_t right, diff; if (shooting) { self->monsterinfo.attack_state = AS_SLIDING; return; } AngleVectors (self->s.angles, NULL, right, NULL); VectorSubtract (tr->endpos, self->s.origin, diff); if (DotProduct (right, diff) < 0) { self->monsterinfo.lefty = 1; } // if it doesn't sense to duck, try to strafe away monster_done_dodge (self); self->monsterinfo.currentmove = &medic_move_run; self->monsterinfo.attack_state = AS_SLIDING; return; } if (skill->value == 0) { self->monsterinfo.currentmove = &medic_move_duck; // PMM - stupid dodge self->monsterinfo.duck_wait_time = level.time + eta + 1; self->monsterinfo.aiflags |= AI_DODGING; return; } if (!shooting) { self->monsterinfo.currentmove = &medic_move_duck; self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value)); self->monsterinfo.aiflags |= AI_DODGING; } return; //PMM //=========== } */ void MedicCommanderCache (void) { edict_t *newEnt; int modelidx; int i; //FIXME - better way to do this? this is quick and dirty for (i=0; i < 7; i++) { newEnt = G_Spawn(); VectorCopy(vec3_origin, newEnt->s.origin); VectorCopy(vec3_origin, newEnt->s.angles); newEnt->classname = ED_NewString (reinforcements[i]); newEnt->monsterinfo.aiflags |= AI_DO_NOT_COUNT; ED_CallSpawn(newEnt); // FIXME - could copy mins/maxs into reinforcements from here G_FreeEdict (newEnt); } modelidx = gi.modelindex("models/items/spawngro/tris.md2"); modelidx = gi.modelindex("models/items/spawngro2/tris.md2"); }
int LoadFlagsFromFile (char *mapname) { FILE *fp; char buf[1024], *s; // int len; int i; edict_t *ent; vec3_t position; sprintf (buf, "%s/tng/%s.flg", GAMEVERSION, mapname); fp = fopen (buf, "r"); if (!fp) { gi.dprintf ("Warning: No flag definition file for map %s.\n", mapname); return 0; } // FIXME: remove this functionality completely in the future gi.dprintf ("Warning: .flg files are deprecated, use .ctf ones for more control!\n"); i = 0; while (fgets(buf, 1000, fp) != NULL) { //first remove trailing spaces s = buf+strlen(buf)-1; for (; *s && (*s == '\r' || *s == '\n' || *s == ' '); s--) *s = '\0'; //check if it's a valid line if (strlen(buf) >= 5 && strncmp(buf, "#", 1) && strncmp(buf, "//", 2) && i < 2) { //a little bit dirty... :) if (sscanf(buf, "<%f %f %f>", &position[0], &position[1], &position[2]) != 3) continue; ent = G_Spawn (); ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY | SPAWNFLAG_NOT_MEDIUM | SPAWNFLAG_NOT_HARD | SPAWNFLAG_NOT_COOP | SPAWNFLAG_NOT_DEATHMATCH); VectorCopy(position, ent->s.origin); if (!i) // Red Flag ent->classname = ED_NewString ("item_flag_team1"); else // Blue Flag ent->classname = ED_NewString ("item_flag_team2"); ED_CallSpawn (ent); i++; } } fclose (fp); if(i < 2) return (0); return (1); }
static void G_ParseString(void) { const char *entities = level.entstring; edict_t *ent; int inhibit = 0; char *token; // parse ents while (1) { // parse the opening brace token = COM_Parse(&entities); if (!entities) break; if (token[0] != '{') gi.error("%s: found %s when expecting {", __func__, token); ent = G_Spawn(); ED_ParseEdict(&entities, ent); // remove things from different skill levels or deathmatch if (ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH) { G_FreeEdict(ent); inhibit++; continue; } ent->spawnflags &= ~INHIBIT_MASK; ED_CallSpawn(ent); } gi.dprintf("%i entities inhibited\n", inhibit); }
edict_t * DoRandomRespawn(edict_t *ent) { edict_t *newEnt; char *classname; if (!ent) { return NULL; } classname = FindSubstituteItem(ent); if (classname == NULL) { return NULL; } gi.unlinkentity(ent); newEnt = G_Spawn(); newEnt->classname = classname; VectorCopy(ent->s.origin, newEnt->s.origin); VectorCopy(ent->s.old_origin, newEnt->s.old_origin); VectorCopy(ent->mins, newEnt->mins); VectorCopy(ent->maxs, newEnt->maxs); VectorSet(newEnt->gravityVector, 0, 0, -1); ED_CallSpawn(newEnt); newEnt->s.renderfx |= RF_IR_VISIBLE; return newEnt; }
void Pet_Create (edict_t *ent, char * szClass, const char * name) { edict_t * pet; vec3_t offset; vec3_t forward, right; vec3_t start; if (ent->svflags & SVF_NOCLIENT) return; if (ent->client->PetStrength > petquota->value + 200 * deathmatch->value) return; if (ent->client->PetCount > petquota->value/50) return; pet = G_Spawn(); pet->classname = szClass; pet->monsterinfo.PetOwner = ent; pet->monsterinfo.TargetCounter = 0; pet->monsterinfo.PetState = PET_DEFAULT; strcpy(pet->monsterinfo.name, name); VectorSet(offset, 40, 40, ent->viewheight-8); AngleVectors (ent->client->v_angle, forward, right, NULL); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); pet->spawnflags = 69; VectorCopy(start, pet->s.origin); VectorCopy(ent->s.angles, pet->s.angles); ED_CallSpawn(pet); // copied from KillBox { trace_t tr; // unlink to make sure it can't possibly interfere with KillBox gi.unlinkentity (pet); tr = gi.trace (pet->s.origin, pet->mins, pet->maxs, pet->s.origin, NULL, MASK_PLAYERSOLID); if (tr.fraction < 1.0) { G_FreeEdict(pet); return; } gi.linkentity (pet); } if (!strcmp(szClass, "monster_decoy")) { //Use same model and skin as the person creating decoy pet->model = ent->model; pet->s.skinnum = ent->s.skinnum; pet->s.modelindex = ent->s.modelindex; pet->s.modelindex2 = ent->s.modelindex; } ent->client->PetCount++; ent->client->PetStrength += pet->max_health; }
void EAVYSpawnTeamNearFlagCheck(void) { edict_t *flag, *spot = NULL; float dist; vec3_t v; flag = G_Find (NULL, FOFS(classname), "item_flag_team1"); while(spot = G_Find (spot, FOFS(classname), "info_player_team2")) { VectorSubtract (spot->s.origin, flag->s.origin, v); dist = VectorLength (v); if (EAVY_RESTRICTED_RADIUS > dist) { spot->classname = "info_player_deathmatch"; spot->svflags &= ~SVF_NOCLIENT; spot->s.effects &= ~EF_COLOR_SHELL; spot->s.renderfx &= ~RF_SHELL_BLUE; ED_CallSpawn (spot); } } flag = G_Find (NULL, FOFS(classname), "item_flag_team2"); while(spot = G_Find (spot, FOFS(classname), "info_player_team1")) { VectorSubtract (spot->s.origin, flag->s.origin, v); dist = VectorLength (v); if (EAVY_RESTRICTED_RADIUS > dist) { spot->classname = "info_player_deathmatch"; spot->svflags &= ~SVF_NOCLIENT; spot->s.effects &= ~EF_COLOR_SHELL; spot->s.renderfx &= ~RF_SHELL_RED; ED_CallSpawn (spot); } } }
void use_target_spawner (edict_t *self, edict_t *other, edict_t *activator) { edict_t *ent; ent = G_Spawn(); ent->classname = self->target; VectorCopy (self->s.origin, ent->s.origin); VectorCopy (self->s.angles, ent->s.angles); ED_CallSpawn (ent); gi.unlinkentity (ent); KillBox (ent); gi.linkentity (ent); if (self->speed) VectorCopy (self->movedir, ent->velocity); }
qboolean SpawnZ(gitem_t *item, edict_t *spot) { edict_t *ent; vec3_t forward; vec3_t angles; vec3_t start; vec3_t end; trace_t tr; int ang = 0; int startAng = 0; ent = G_Spawn(); ent->classname = item->classname; VectorSet (ent->mins, -15, -15, -15); VectorSet (ent->maxs, 15, 15, 15); ent->solid = SOLID_TRIGGER; ent->movetype = MOVETYPE_BOUNCE; ED_CallSpawn(ent); startAng = rand() % 360; VectorCopy(spot->s.origin, start); start[2] += 16; for (ang = startAng; ang < startAng + 360; ang += 15) { angles[0] = 0; angles[1] = ang; angles[2] = 0; AngleVectors (angles, forward, NULL, NULL); VectorMA(start, 128, forward, end); tr = gi.trace(start, ent->mins, ent->maxs, end, NULL, MASK_SHOT); if (tr.fraction < 1.0) continue; VectorCopy(end, ent->s.origin); gi.linkentity(ent); return true; } G_FreeEdict(ent); return false; }
void EAVYSpawnTeamNearFlag(edict_t *flag) { edict_t *spot = NULL; float dist; vec3_t v; while(spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) { VectorSubtract (spot->s.origin, flag->s.origin, v); dist = VectorLength (v); if (EAVY_RESTRICTED_RADIUS > dist) { if (!strcmp(flag->classname, "item_flag_team1")) spot->classname = "info_player_team1"; if (!strcmp(flag->classname, "item_flag_team2")) spot->classname = "info_player_team2"; spot->svflags |= SVF_NOCLIENT; spot->solid = SOLID_NOT; ED_CallSpawn (spot); } } }
// Lazarus: Rocket_Evade tells monsters to get da hell outta da way void Rocket_Evade (edict_t *rocket, vec3_t dir, float speed) { float rocket_dist, best_r, best_yaw, dist, r; float time; float dot; float yaw; int i; edict_t *ent=NULL; trace_t tr; vec3_t hitpoint; vec3_t forward, pos, best_pos; vec3_t rocket_vec, vec; // Find out what rocket will hit, assuming everything remains static VectorMA(rocket->s.origin,8192,dir,rocket_vec); tr = gi.trace(rocket->s.origin,rocket->mins,rocket->maxs,rocket_vec,rocket,MASK_SHOT); VectorCopy(tr.endpos,hitpoint); VectorSubtract(hitpoint,rocket->s.origin,vec); dist = VectorLength(vec); time = dist / speed; while ((ent = findradius(ent, hitpoint, rocket->dmg_radius)) != NULL) { if (!ent->inuse) continue; if (!(ent->svflags & SVF_MONSTER)) continue; if (!ent->takedamage) continue; if (ent->health <= 0) continue; if (!ent->monsterinfo.run) // takes care of turret_driver continue; if (rocket->owner == ent) continue; VectorSubtract(hitpoint,ent->s.origin,rocket_vec); rocket_dist = VectorNormalize(rocket_vec); // Not much hope in evading if distance is < 1K or so. if(rocket_dist < 1024) continue; // Find best escape route. best_r = 9999; for(i=0; i<8; i++) { yaw = anglemod( i*45 ); forward[0] = cos( DEG2RAD(yaw) ); forward[1] = sin( DEG2RAD(yaw) ); forward[2] = 0; dot = DotProduct(forward,dir); if((dot > 0.96) || (dot < -0.96)) continue; // Estimate of required distance to run. This is conservative. r = rocket->dmg_radius + rocket_dist*DotProduct(forward,rocket_vec) + ent->size[0] + 16; if( r < best_r ) { VectorMA(ent->s.origin,r,forward,pos); tr = gi.trace(ent->s.origin,ent->mins,ent->maxs,pos,ent,MASK_MONSTERSOLID); if(tr.fraction < 1.0) continue; best_r = r; best_yaw = yaw; VectorCopy(tr.endpos,best_pos); } } if(best_r < 9000) { edict_t *thing = SpawnThing(); VectorCopy(best_pos,thing->s.origin); thing->touch_debounce_time = level.time + time; thing->target_ent = ent; ED_CallSpawn(thing); ent->ideal_yaw = best_yaw; ent->movetarget = ent->goalentity = thing; ent->monsterinfo.aiflags &= ~AI_SOUND_TARGET; ent->monsterinfo.aiflags |= (AI_CHASE_THING | AI_EVADE_GRENADE); ent->monsterinfo.run(ent); } } }
/* ============== SpawnEntities Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. ============== */ void SpawnEntities (char *mapname, char *entities, char *spawnpoint) { edict_t *ent; int inhibit; char *com_token; int i; float skill_level; skill_level = floor (skill->value); if (skill_level < 0) skill_level = 0; if (skill_level > 3) skill_level = 3; if (skill->value != skill_level) gi.cvar_forceset("skill", va("%f", skill_level)); SaveClientData (); gi.FreeTags (TAG_LEVEL); memset (&level, 0, sizeof(level)); memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0])); strncpy (level.mapname, mapname, sizeof(level.mapname)-1); strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1); // set client fields on player ents for (i=0 ; i<game.maxclients ; i++) g_edicts[i+1].client = game.clients + i; ent = NULL; inhibit = 0; // parse ents while (1) { // parse the opening brace com_token = COM_Parse (&entities); if (!entities) break; if (com_token[0] != '{') gi.error ("ED_LoadFromFile: found %s when expecting {",com_token); if (!ent) ent = g_edicts; else ent = G_Spawn (); entities = ED_ParseEdict (entities, ent); // yet another map hack if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27")) ent->spawnflags &= ~SPAWNFLAG_NOT_HARD; // remove things (except the world) from different skill levels or deathmatch if (ent != g_edicts) { if (deathmatch->value) { if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH ) { G_FreeEdict (ent); inhibit++; continue; } } else { if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */ ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) ) { G_FreeEdict (ent); inhibit++; continue; } } ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH); } ED_CallSpawn (ent); } gi.dprintf ("%i entities inhibited\n", inhibit); #ifdef DEBUG i = 1; ent = EDICT_NUM(i); while (i < globals.num_edicts) { if (ent->inuse != 0 || ent->inuse != 1) Com_DPrintf("Invalid entity %d\n", i); i++, ent++; } #endif G_FindTeams (); PlayerTrail_Init (); }
/* ============== SpawnEntities Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. ============== */ void SpawnEntities (char *mapname, char *entities, char *spawnpoint) { edict_t *ent = NULL; int inhibit = 0; char *com_token; int i; float skill_level; //AQ2:TNG New Location Code char locfile[MAX_QPATH], line[256]; FILE *f; int readmore, x, y, z, rx, ry, rz, count; char *locationstr, *param; cvar_t *game_cvar; int u; // placedata_t temp; // Reset teamplay stuff for(i = TEAM1; i < TEAM_TOP; i++) { teams[i].score = teams[i].total = 0; teams[i].ready = teams[i].locked = 0; teams[i].pauses_used = teams[i].wantReset = 0; gi.cvar_forceset(teams[i].teamscore->name, "0"); } matchtime = 0; day_cycle_at = 0; team_round_going = team_game_going = team_round_countdown = 0; lights_camera_action = holding_on_tie_check = 0; timewarning = fragwarning = 0; teamCount = 2; if (ctf->value) { // Make sure teamplay is enabled if (!teamplay->value) { gi.dprintf ("CTF Enabled - Forcing teamplay on\n"); gi.cvar_forceset(teamplay->name, "1"); } if (use_3teams->value) { gi.dprintf ("CTF Enabled - Forcing 3Teams off\n"); gi.cvar_forceset(use_3teams->name, "0"); } if(teamdm->value) { gi.dprintf ("CTF Enabled - Forcing Team DM off\n"); gi.cvar_forceset(teamdm->name, "0"); } if (use_tourney->value) { gi.dprintf ("CTF Enabled - Forcing Tourney off\n"); gi.cvar_forceset(use_tourney->name, "0"); } if (!((int) (dmflags->value) & DF_NO_FRIENDLY_FIRE)) { gi.dprintf ("CTF Enabled - Forcing Friendly Fire off\n"); gi.cvar_forceset(dmflags->name, va("%i", (int)dmflags->value | DF_NO_FRIENDLY_FIRE)); } strcpy(teams[TEAM1].name, "RED"); strcpy(teams[TEAM2].name, "BLUE"); strcpy(teams[TEAM1].skin, "male/ctf_r"); strcpy(teams[TEAM2].skin, "male/ctf_b"); strcpy(teams[TEAM1].skin_index, "../players/male/ctf_r_i"); strcpy(teams[TEAM2].skin_index, "../players/male/ctf_b_i"); if(ctf->value == 2) gi.cvar_forceset(ctf->name, "1"); //for now } else if(teamdm->value) { if (!teamplay->value) { gi.dprintf ("Team Deathmatch Enabled - Forcing teamplay on\n"); gi.cvar_forceset(teamplay->name, "1"); } if (use_3teams->value) { gi.dprintf ("Team Deathmatch Enabled - Forcing 3Teams off\n"); gi.cvar_forceset(use_3teams->name, "0"); } if (use_tourney->value) { gi.dprintf ("Team Deathmatch Enabled - Forcing Tourney off\n"); gi.cvar_forceset(use_tourney->name, "0"); } } else if (use_3teams->value) { teamCount = 3; if (!teamplay->value) { gi.dprintf ("3 Teams Enabled - Forcing teamplay on\n"); gi.cvar_forceset(teamplay->name, "1"); } if (use_tourney->value) { gi.dprintf ("3 Teams Enabled - Forcing Tourney off\n"); gi.cvar_forceset(use_tourney->name, "0"); } if (!use_oldspawns->value) { gi.dprintf ("3 Teams Enabled - Forcing use_oldspawns on\n"); gi.cvar_forceset(use_oldspawns->name, "1"); } } else if (matchmode->value) { if (!teamplay->value) { gi.dprintf ("Matchmode Enabled - Forcing teamplay on\n"); gi.cvar_forceset(teamplay->name, "1"); } if (use_tourney->value) { gi.dprintf ("Matchmode Enabled - Forcing Tourney off\n"); gi.cvar_forceset(use_tourney->name, "0"); } } else if (use_tourney->value) { if (!teamplay->value) { gi.dprintf ("Tourney Enabled - Forcing teamplay on\n"); gi.cvar_forceset(teamplay->name, "1"); } } skill_level = floor (skill->value); if (skill_level < 0) skill_level = 0; if (skill_level > 3) skill_level = 3; if (skill->value != skill_level) gi.cvar_forceset ("skill", va("%f", skill_level)); SaveClientData (); gi.FreeTags (TAG_LEVEL); memset (&level, 0, sizeof (level)); memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0])); Q_strncpyz(level.mapname, mapname, sizeof(level.mapname)); Q_strncpyz(game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)); // set client fields on player ents for (i = 0; i < game.maxclients; i++) g_edicts[i + 1].client = game.clients + i; // parse ents while (1) { // parse the opening brace com_token = COM_Parse (&entities); if (!entities) break; if (com_token[0] != '{') gi.error ("ED_LoadFromFile: found %s when expecting {", com_token); if (!ent) ent = g_edicts; else ent = G_Spawn (); entities = ED_ParseEdict (entities, ent); // yet another map hack if (!Q_stricmp (level.mapname, "command") && !Q_stricmp (ent->classname, "trigger_once") && !Q_stricmp (ent->model, "*27")) ent->spawnflags &= ~SPAWNFLAG_NOT_HARD; // remove things (except the world) from different skill levels or deathmatch if (ent != g_edicts) { if (deathmatch->value) { if (ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH) { G_FreeEdict (ent); inhibit++; continue; } } else { if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */ ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD))) { G_FreeEdict (ent); inhibit++; continue; } } ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY | SPAWNFLAG_NOT_MEDIUM | SPAWNFLAG_NOT_HARD | SPAWNFLAG_NOT_COOP | SPAWNFLAG_NOT_DEATHMATCH); } ED_CallSpawn (ent); } gi.dprintf ("%i entities inhibited\n", inhibit); // AQ2:TNG Igor adding .flg files // CTF configuration if(ctf->value) { if(!CTFLoadConfig(level.mapname)) { if ((!G_Find(NULL, FOFS (classname), "item_flag_team1") || !G_Find(NULL, FOFS (classname), "item_flag_team2"))) { gi.dprintf ("No native CTF map, loading flag positions from file\n"); if (LoadFlagsFromFile (level.mapname)) ChangePlayerSpawns (); } } } // AQ2:TNG End adding .flg files G_FindTeams (); PlayerTrail_Init (); // TNG:Freud - Ghosts num_ghost_players = 0; //FIREBLADE if (!teamplay->value || teamdm->value || ctf->value == 2) { //FIREBLADE //zucc for special items SetupSpecSpawn (); } else if (teamplay->value) { GetSpawnPoints (); //TNG:Freud - New spawning system if(!use_oldspawns->value) NS_GetSpawnPoints(); } //AQ2:TNG Slicer - New location code memset (ml_build, 0, sizeof (ml_build)); memset (ml_creator, 0, sizeof (ml_creator)); game_cvar = gi.cvar ("game", "", 0); if (!*game_cvar->string) Com_sprintf(locfile, sizeof(locfile), "%s/tng/%s.aqg", GAMEVERSION, level.mapname); else Com_sprintf(locfile, sizeof(locfile), "%s/tng/%s.aqg", game_cvar->string, level.mapname); f = fopen (locfile, "rt"); if (!f) { ml_count = 0; gi.dprintf ("No location file for %s\n", level.mapname); return; } gi.dprintf ("Location file: %s\n", level.mapname); readmore = 1; count = 0; while (readmore) { readmore = (fgets (line, 256, f) != NULL); param = strtok (line, " :\r\n\0"); if (line[0] == '#' && line[2] == 'C') { u = 0; for (i = 10; line[i] != '\n'; i++) { if (line[i] == '\r') continue; ml_creator[u] = line[i]; u++; } } if (line[0] == '#' && line[2] == 'B') { u = 0; for (i = 8; line[i] != '\n'; i++) { if (line[i] != ' ' && line[i] != '\r') { ml_build[u] = line[i]; u++; } } } ml_build[5] = 0; ml_creator[100] = 0; // TODO: better support for file comments if (!param || param[0] == '#') continue; x = atoi (param); param = strtok (NULL, " :\r\n\0"); if (!param) continue; y = atoi (param); param = strtok (NULL, " :\r\n\0"); if (!param) continue; z = atoi (param); param = strtok (NULL, " :\r\n\0"); if (!param) continue; rx = atoi (param); param = strtok (NULL, " :\r\n\0"); if (!param) continue; ry = atoi (param); param = strtok (NULL, " :\r\n\0"); if (!param) continue; rz = atoi (param); param = strtok (NULL, "\r\n\0"); if (!param) continue; locationstr = param; locationbase[count].x = x; locationbase[count].y = y; locationbase[count].z = z; locationbase[count].rx = rx; locationbase[count].ry = ry; locationbase[count].rz = rz; Q_strncpyz (locationbase[count].desc, locationstr, sizeof(locationbase[count].desc)); count++; if (count >= MAX_LOCATIONS_IN_BASE) { gi.dprintf ("Cannot read more than %d locations.\n", MAX_LOCATIONS_IN_BASE); break; } } ml_count = count; fclose (f); gi.dprintf ("Found %d locations.\n", count); }
void Grenade_Evade (edict_t *monster) { edict_t *grenade; vec3_t grenade_vec; float grenade_dist, best_r, best_yaw, r; float yaw; int i; vec3_t forward; vec3_t pos, best_pos; trace_t tr; // We assume on entry here that monster is alive and that he's not already // AI_CHASE_THING grenade = world->next_grenade; while(grenade) { // we only care about grenades on the ground if(grenade->inuse && grenade->groundentity) { // if it ain't in the PVS, it can't hurt us (I think?) if(gi.inPVS(grenade->s.origin,monster->s.origin)) { VectorSubtract(grenade->s.origin,monster->s.origin,grenade_vec); grenade_dist = VectorNormalize(grenade_vec); if(grenade_dist <= grenade->dmg_radius) break; } } grenade = grenade->next_grenade; } if(!grenade) return; // Find best escape route. best_r = 9999; for(i=0; i<8; i++) { yaw = anglemod( i*45 ); forward[0] = cos( DEG2RAD(yaw) ); forward[1] = sin( DEG2RAD(yaw) ); forward[2] = 0; // Estimate of required distance to run. This is conservative. r = grenade->dmg_radius + grenade_dist*DotProduct(forward,grenade_vec) + monster->size[0] + 16; if( r < best_r ) { VectorMA(monster->s.origin,r,forward,pos); tr = gi.trace(monster->s.origin,monster->mins,monster->maxs,pos,monster,MASK_MONSTERSOLID); if(tr.fraction < 1.0) continue; best_r = r; best_yaw = yaw; VectorCopy(tr.endpos,best_pos); } } if(best_r < 9000) { edict_t *thing = SpawnThing(); VectorCopy(best_pos,thing->s.origin); thing->touch_debounce_time = grenade->nextthink; thing->target_ent = monster; ED_CallSpawn(thing); monster->ideal_yaw = best_yaw; monster->movetarget = monster->goalentity = thing; monster->monsterinfo.aiflags &= ~AI_SOUND_TARGET; monster->monsterinfo.aiflags |= (AI_CHASE_THING | AI_EVADE_GRENADE); monster->monsterinfo.run(monster); monster->next_grenade = grenade; } }
void medic_cable_attack(edict_t *self) { vec3_t offset, start, end, f, r; trace_t tr; vec3_t dir, angles; float distance; if (!self) { return; } if (!self->enemy->inuse) { return; } AngleVectors(self->s.angles, f, r, NULL); VectorCopy(medic_cable_offsets[self->s.frame - FRAME_attack42], offset); G_ProjectSource(self->s.origin, offset, f, r, start); /* check for max distance */ VectorSubtract(start, self->enemy->s.origin, dir); distance = VectorLength(dir); if (distance > 256) { return; } /* check for min/max pitch */ vectoangles(dir, angles); if (angles[0] < -180) { angles[0] += 360; } if (fabs(angles[0]) > 45) { return; } tr = gi.trace(start, NULL, NULL, self->enemy->s.origin, self, MASK_SHOT); if ((tr.fraction != 1.0) && (tr.ent != self->enemy)) { return; } if (self->s.frame == FRAME_attack43) { gi.sound(self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0); self->enemy->monsterinfo.aiflags |= AI_RESURRECTING; } else if (self->s.frame == FRAME_attack50) { self->enemy->spawnflags = 0; self->enemy->monsterinfo.aiflags = 0; self->enemy->target = NULL; self->enemy->targetname = NULL; self->enemy->combattarget = NULL; self->enemy->deathtarget = NULL; self->enemy->owner = self; ED_CallSpawn(self->enemy); self->enemy->owner = NULL; if (self->enemy->think) { self->enemy->nextthink = level.time; self->enemy->think(self->enemy); } self->enemy->monsterinfo.aiflags |= AI_RESURRECTING; if (self->oldenemy && self->oldenemy->client) { self->enemy->enemy = self->oldenemy; FoundTarget(self->enemy); } } else { if (self->s.frame == FRAME_attack44) { gi.sound(self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0); } } /* adjust start for beam origin being in middle of a segment */ VectorMA(start, 8, f, start); /* adjust end z for end spot since the monster is currently dead */ VectorCopy(self->enemy->s.origin, end); end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2; gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_MEDIC_CABLE_ATTACK); gi.WriteShort(self - g_edicts); gi.WritePosition(start); gi.WritePosition(end); gi.multicast(self->s.origin, MULTICAST_PVS); }
/* ============== SpawnEntities Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. ============== */ void SpawnEntities (const char *mapname, char *entities, const char *spawnpoint) { edict_t *ent; int inhibit; const char *com_token; int i; float skill_level; int oldmaxent; skill_level = floor (skill->value); if (skill_level < 0) skill_level = 0; if (skill_level > 3) skill_level = 3; if (skill->value != skill_level) gi.cvar_forceset("skill", va("%f", skill_level)); SaveClientData (); gi.FreeTags (TAG_LEVEL); memset (&level, 0, sizeof(level)); memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0])); strncpy (level.mapname, mapname, sizeof(level.mapname)-1); strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1); // set client fields on player ents for (i=0 ; i<game.maxclients ; i++) g_edicts[i+1].client = game.clients + i; ent = NULL; inhibit = 0; // parse ents while (1) { // parse the opening brace com_token = COM_Parse (&entities); if (!entities) break; if (com_token[0] != '{') gi.error ("ED_LoadFromFile: found %s when expecting {",com_token); if (!ent) ent = g_edicts; else ent = G_Spawn (); ent->spawnflags2 = 0; entities = ED_ParseEdict (entities, ent); // yet another map hack if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27")) ent->spawnflags &= ~SPAWNFLAG_NOT_HARD; // remove things (except the world) from different skill levels or deathmatch if (ent != g_edicts) { if (deathmatch->value) { if ( (ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH) || (ent->spawnflags2 & SPAWNFLAG2_NOT_SINGLE) ) { G_FreeEdict (ent); inhibit++; continue; } } #if 0 // FIXME: DG: coop stuff from rogue else if (coop->value) { if (ent->spawnflags & SPAWNFLAG_NOT_COOP) { G_FreeEdict(ent); inhibit++; continue; } /* stuff marked !easy & !med & !hard are coop only, all levels */ if (!((ent->spawnflags & SPAWNFLAG_NOT_EASY) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM) && (ent->spawnflags & SPAWNFLAG_NOT_HARD))) { if (((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD))) { G_FreeEdict(ent); inhibit++; continue; } } } #endif // 0 else { if (((!coop->value) && (ent->spawnflags2 & SPAWNFLAG2_NOT_SINGLE)) || ((coop->value) && (ent->spawnflags2 & SPAWNFLAG2_NOT_COOP)) || ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) ) { G_FreeEdict (ent); inhibit++; continue; } } ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH); } ED_CallSpawn (ent); } oldmaxent = globals.num_edicts; gi.dprintf("%i entities created\n", globals.num_edicts); gi.dprintf ("%i entities inhibited\n", inhibit); G_FindTeams (); PlayerTrail_Init (); Z_SpawnDMItems(); }
void medic_cable_attack (edict_t *self) { vec3_t offset, start, end, f, r; trace_t tr; vec3_t dir; // vec3_t angles; float distance; if ((!self->enemy) || (!self->enemy->inuse) || (self->enemy->s.effects & EF_GIB)) { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("medic_commander - aborting heal due to target's disappearance\n"); abortHeal (self, true, false, false); return; } // see if our enemy has changed to a client, or our target has more than 0 health, // abort it .. we got switched to someone else due to damage if ((self->enemy->client) || (self->enemy->health > 0)) { abortHeal (self, true, false, false); return; } AngleVectors (self->s.angles, f, r, NULL); VectorCopy (medic_cable_offsets[self->s.frame - FRAME_attack42], offset); G_ProjectSource (self->s.origin, offset, f, r, start); // check for max distance // not needed, done in checkattack // check for min distance VectorSubtract (start, self->enemy->s.origin, dir); distance = VectorLength(dir); if (distance < MEDIC_MIN_DISTANCE) { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("medic_commander - aborting heal due to proximity to target "); abortHeal (self, true, true, false ); return; } // if ((g_showlogic)&&(g_showlogic->value)) // gi.dprintf ("distance to target is %f\n", distance); // if (distance > 300) // return; // check for min/max pitch // PMM -- took out since it doesn't look bad when it fails // vectoangles (dir, angles); // if (angles[0] < -180) // angles[0] += 360; // if (fabs(angles[0]) > 45) // { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("medic_commander - aborting heal due to bad angle\n"); // abortHeal(self); // return; // } tr = gi.trace (start, NULL, NULL, self->enemy->s.origin, self, MASK_SOLID); if (tr.fraction != 1.0 && tr.ent != self->enemy) { if (tr.ent == world) { // give up on second try if (self->monsterinfo.medicTries > 1) { abortHeal (self, true, false, true); return; } self->monsterinfo.medicTries++; cleanupHeal (self, 1); return; } // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("medic_commander - aborting heal due to beamus interruptus\n"); abortHeal (self, true, false, false); return; } if (self->s.frame == FRAME_attack43) { // PMM - commander sounds if (self->mass == 400) gi.sound (self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0); else gi.sound (self->enemy, CHAN_AUTO, commander_sound_hook_hit, 1, ATTN_NORM, 0); self->enemy->monsterinfo.aiflags |= AI_RESURRECTING; self->enemy->takedamage = DAMAGE_NO; M_SetEffects (self->enemy); } else if (self->s.frame == FRAME_attack50) { vec3_t maxs; self->enemy->spawnflags = 0; self->enemy->monsterinfo.aiflags = 0; self->enemy->target = NULL; self->enemy->targetname = NULL; self->enemy->combattarget = NULL; self->enemy->deathtarget = NULL; self->enemy->monsterinfo.healer = self; VectorCopy (self->enemy->maxs, maxs); maxs[2] += 48; // compensate for change when they die tr = gi.trace (self->enemy->s.origin, self->enemy->mins, maxs, self->enemy->s.origin, self->enemy, MASK_MONSTERSOLID); if (tr.startsolid || tr.allsolid) { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("Spawn point obstructed, aborting heal!\n"); abortHeal (self, true, true, false); return; } else if (tr.ent != world) { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf("heal in entity %s\n", tr.ent->classname); abortHeal (self, true, true, false); return; } /* else if (tr.ent == world) { if ((g_showlogic) && (g_showlogic->value)) gi.dprintf ("heal in world, aborting!\n"); abortHeal (self, 1); return; } */ else { self->enemy->monsterinfo.aiflags |= AI_DO_NOT_COUNT; ED_CallSpawn (self->enemy); if (self->enemy->think) { self->enemy->nextthink = level.time; self->enemy->think (self->enemy); } // self->enemy->monsterinfo.aiflags |= AI_RESURRECTING; self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING; self->enemy->monsterinfo.aiflags |= AI_IGNORE_SHOTS|AI_DO_NOT_COUNT; // turn off flies self->enemy->s.effects &= ~EF_FLIES; self->enemy->monsterinfo.healer = NULL; if ((self->oldenemy) && (self->oldenemy->inuse) && (self->oldenemy->health > 0)) { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("setting heal target's enemy to %s\n", self->oldenemy->classname); self->enemy->enemy = self->oldenemy; // HuntTarget (self->enemy); FoundTarget (self->enemy); } else { // if (g_showlogic && g_showlogic->value) // gi.dprintf ("no valid enemy to set!\n"); self->enemy->enemy = NULL; if (!FindTarget (self->enemy)) { // no valid enemy, so stop acting self->enemy->monsterinfo.pausetime = level.time + 100000000; self->enemy->monsterinfo.stand (self->enemy); } self->enemy = NULL; self->oldenemy = NULL; if (!FindTarget (self)) { // no valid enemy, so stop acting self->monsterinfo.pausetime = level.time + 100000000; self->monsterinfo.stand (self); return; } } } } else { if (self->s.frame == FRAME_attack44) // PMM - medic commander sounds if (self->mass == 400) gi.sound (self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0); else gi.sound (self, CHAN_WEAPON, commander_sound_hook_heal, 1, ATTN_NORM, 0); } // adjust start for beam origin being in middle of a segment VectorMA (start, 8, f, start); // adjust end z for end spot since the monster is currently dead VectorCopy (self->enemy->s.origin, end); end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2; gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_MEDIC_CABLE_ATTACK); gi.WriteShort (self - g_edicts); gi.WritePosition (start); gi.WritePosition (end); gi.multicast (self->s.origin, MULTICAST_PVS); }
void medic_cable_attack (edict_t *self) { vec3_t offset, start, end, f, r; trace_t tr; vec3_t dir; float distance; if ((!self->enemy) || (!self->enemy->inuse) || (self->enemy->svflags & SVF_GIB)) { //gi.dprintf ("medic_cable_attack: aborting heal due to target being removed or gibbed\n"); abortHeal (self,false); return; } //Knightmare- don't heal insanes or actors or critters if (!strcmp (self->enemy->classname, "misc_insane") || !strcmp (self->enemy->classname, "misc_actor") || !strcmp (self->enemy->classname, "monster_mutant") || !strcmp (self->enemy->classname, "monster_flipper")) { //gi.dprintf ("medic_cable_attack: not healing insane or actor or critter\n"); abortHeal (self, true); return; } // Lazarus: check embeddment if (embedded(self->enemy)) { //gi.dprintf ("medic_cable_attack: dead monster embedded in solid, aborting heal\n"); abortHeal (self,false); return; } // see if our enemy has changed to a client, or our target has more than 0 health, // abort it .. we got switched to someone else due to damage if ((self->enemy->client) || (self->enemy->health > 0)) { //gi.dprintf ("medic_cable_attack: aborting heal due to target health > 0 or client\n"); abortHeal (self,false); return; } AngleVectors (self->s.angles, f, r, NULL); VectorCopy (medic_cable_offsets[self->s.frame - FRAME_attack42], offset); G_ProjectSource (self->s.origin, offset, f, r, start); // check for max distance // Lazarus: Not needed, done in checkattack // check for min distance VectorSubtract (self->enemy->s.origin, start, dir); distance = VectorLength(dir); if (distance < MEDIC_MIN_DISTANCE) { //gi.dprintf("medic_cable_attack: MEDIC_MIN_DISTANCE\n"); abortHeal (self,false); return; } // Lazarus: Check for enemy behind muzzle... don't do these guys, 'cause usually this // results in monster entanglement VectorNormalize(dir); if(DotProduct(dir,f) < 0.) { //gi.dprintf ("medic_cable_attack: aborting heal due to possible entanglment\n"); abortHeal (self,false); return; } // check for min/max pitch // Rogue takes this out... makes medic more likely to heal and // comments say "doesn't look bad when it fails"... we'll see /* vectoangles (dir, angles); if (angles[0] < -180) angles[0] += 360; if (fabs(angles[0]) > 45) return; */ tr = gi.trace (start, NULL, NULL, self->enemy->s.origin, self, MASK_SHOT); if (tr.fraction != 1.0 && tr.ent != self->enemy) { if (tr.ent == world) { // give up on second try if (self->monsterinfo.medicTries > 1) { abortHeal (self,true); return; } self->monsterinfo.medicTries++; cleanupHeal (self, 1); return; } abortHeal (self,false); return; } if (self->s.frame == FRAME_attack43) { gi.sound (self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0); self->enemy->monsterinfo.aiflags |= AI_RESURRECTING; M_SetEffects(self->enemy); } else if (self->s.frame == FRAME_attack50) { self->enemy->spawnflags &= SF_MONSTER_NOGIB; self->enemy->monsterinfo.aiflags = 0; self->enemy->target = NULL; self->enemy->targetname = NULL; self->enemy->combattarget = NULL; self->enemy->deathtarget = NULL; self->enemy->owner = self; // Lazarus: reset initially dead monsters to use the INVERSE of their // initial health, and force gib_health to default value if(self->enemy->max_health < 0) { self->enemy->max_health = -self->enemy->max_health; self->enemy->gib_health = 0; } self->enemy->health = self->enemy->max_health; self->enemy->takedamage = DAMAGE_AIM; self->enemy->flags &= ~FL_NO_KNOCKBACK; self->enemy->pain_debounce_time = 0; self->enemy->damage_debounce_time = 0; self->enemy->deadflag = DEAD_NO; if(self->enemy->s.effects & EF_FLIES) M_FliesOff(self->enemy); ED_CallSpawn (self->enemy); self->enemy->monsterinfo.healer = NULL; self->enemy->owner = NULL; // Knightmare- disable deadmonster_think if (self->enemy->postthink) self->enemy->postthink = NULL; if (self->enemy->think) { self->enemy->nextthink = level.time; self->enemy->think (self->enemy); } self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING; M_SetEffects(self->enemy); if (self->oldenemy && self->oldenemy->client) { self->enemy->enemy = self->oldenemy; FoundTarget (self->enemy); } else { // Lazarus: this should make oblivious monsters // find player again self->enemy->enemy = NULL; } } else { if (self->s.frame == FRAME_attack44) gi.sound (self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0); } // adjust start for beam origin being in middle of a segment // Lazarus: This isn't right... this causes cable start point to be well above muzzle // when target is closeby. f should be vector from muzzle to target, not // the forward viewing direction. PLUS... 8 isn't right... the model is // actually 32 units long, so use 16.. fixed below. // VectorMA (start, 8, f, start); //Knightmare- if enemy went away, like after returning from another level, return if (!self->enemy) return; // adjust end z for end spot since the monster is currently dead VectorCopy (self->enemy->s.origin, end); end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2; // Lazarus fix VectorSubtract(end,start,f); VectorNormalize(f); VectorMA(start,16,f,start); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_MEDIC_CABLE_ATTACK); gi.WriteShort (self - g_edicts); gi.WritePosition (start); gi.WritePosition (end); gi.multicast (self->s.origin, MULTICAST_PVS); }
void LoadTransitionEnts() { if(developer->value) gi.dprintf("==== LoadTransitionEnts ====\n"); if(game.transition_ents) { char t_file[_MAX_PATH]; int i, j; FILE *f; vec3_t v_spawn; edict_t *ent; edict_t *spawn; VectorClear(v_spawn); if(strlen(game.spawnpoint)) { spawn = G_Find(NULL,FOFS(targetname),game.spawnpoint); while(spawn) { if(!Q_stricmp(spawn->classname,"info_player_start")) { VectorCopy(spawn->s.origin,v_spawn); break; } spawn = G_Find(spawn,FOFS(targetname),game.spawnpoint); } } trans_ent_filename (t_file); f = fopen(t_file,"rb"); if(!f) gi.error("LoadTransitionEnts: Cannot open %s\n",t_file); else { for(i=0; i<game.transition_ents; i++) { ent = G_Spawn(); ReadEdict(f,ent); // Correction for monsters with health EXACTLY 0 // If we don't do this, spawn function will bring // 'em back to life if(ent->svflags & SVF_MONSTER) { if(!ent->health) { ent->health = -1; ent->deadflag = DEAD_DEAD; } else if(ent->deadflag == DEAD_DEAD) { ent->health = min(ent->health,-1); } } VectorAdd(ent->s.origin,v_spawn,ent->s.origin); VectorCopy(ent->s.origin,ent->s.old_origin); ED_CallSpawn (ent); if(ent->owner_id) { if(ent->owner_id < 0) { ent->owner = &g_edicts[-ent->owner_id]; } else { // We KNOW owners precede owned ents in the // list because of the way it was constructed ent->owner = NULL; for(j=game.maxclients+1; j<globals.num_edicts && !ent->owner; j++) { if(ent->owner_id == g_edicts[j].id) ent->owner = &g_edicts[j]; } } ent->owner_id = 0; } ent->s.renderfx |= RF_IR_VISIBLE; } fclose(f); } } }
/* ============== SpawnEntities Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. ============== */ void G_SpawnEntities(const char *mapname, const char *entities, const char *spawnpoint) { edict_t *ent; gclient_t *client; int i; client_persistant_t pers; char *token; char playerskin[MAX_QPATH]; #if USE_SQLITE G_OpenDatabase(); G_LogClients(); #endif gi.FreeTags(TAG_LEVEL); memset(&level, 0, sizeof(level)); memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0])); Q_strlcpy(level.mapname, mapname, sizeof(level.mapname)); G_LoadScores(); // set client fields on player ents for (i = 0; i < game.maxclients; i++) { ent = &g_edicts[i + 1]; client = &game.clients[i]; ent->client = client; ent->inuse = qfalse; if (!client->pers.connected) { continue; } // clear everything but the persistant data pers = client->pers; memset(client, 0, sizeof(*client)); client->pers = pers; client->edict = ent; client->clientNum = i; client->pers.connected = CONN_CONNECTED; // combine name and skin into a configstring Q_concat(playerskin, sizeof(playerskin), client->pers.netname, "\\", client->pers.skin, NULL); gi.configstring(CS_PLAYERSKINS + i, playerskin); gi.configstring(CS_PLAYERNAMES + i, client->pers.netname); } // parse worldspawn token = COM_Parse(&entities); if (!entities) gi.error("%s: empty entity string", __func__); if (token[0] != '{') gi.error("%s: found %s when expecting {", __func__, token); ent = g_edicts; ED_ParseEdict(&entities, ent); ED_CallSpawn(ent); level.entstring = entities; G_ParseString(); G_FindTeams(); //G_UpdateItemBans(); // find spawnpoints ent = NULL; while ((ent = G_Find(ent, FOFS(classname), "info_player_deathmatch")) != NULL) { level.spawns[level.numspawns++] = ent; if (level.numspawns == MAX_SPAWNS) { break; } } gi.dprintf("%d spawn points\n", level.numspawns); }
/* ============== SpawnEntities Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. ============== */ void SpawnEntities (char *mapname, char *entities, char *spawnpoint) { edict_t *ent; int inhibit; char *com_token; int i; float skill_level; extern int max_modelindex; extern int max_soundindex; extern int lastgibframe; if (developer->value) gi.dprintf("====== SpawnEntities ========\n"); skill_level = floor (skill->value); if (skill_level < 0) skill_level = 0; if (skill_level > 3) skill_level = 3; if (skill->value != skill_level) gi.cvar_forceset("skill", va("%f", skill_level)); SaveClientData (); gi.FreeTags (TAG_LEVEL); memset (&level, 0, sizeof(level)); memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0])); // Lazarus: these are used to track model and sound indices // in g_main.c: max_modelindex = 0; max_soundindex = 0; // Lazarus: last frame a gib was spawned in lastgibframe = 0; strncpy (level.mapname, mapname, sizeof(level.mapname)-1); strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1); // set client fields on player ents for (i=0 ; i<game.maxclients ; i++) g_edicts[i+1].client = game.clients + i; ent = NULL; inhibit = 0; // Knightamre- load the entity alias script file LoadAliasData(); //gi.dprintf ("Size of alias data: %i\n", alias_data_size); // parse ents while (1) { // parse the opening brace com_token = COM_Parse (&entities); if (!entities) break; if (com_token[0] != '{') gi.error ("ED_LoadFromFile: found %s when expecting {",com_token); if (!ent) ent = g_edicts; else ent = G_Spawn (); entities = ED_ParseEdict (entities, ent); // yet another map hack if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27")) ent->spawnflags &= ~SPAWNFLAG_NOT_HARD; // remove things (except the world) from different skill levels or deathmatch if (ent != g_edicts) { if (deathmatch->value) { if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH ) { G_FreeEdict (ent); inhibit++; continue; } } else if (coop->value) // Knightmare added- not in coop flag support { if ( ent->spawnflags & SPAWNFLAG_NOT_COOP ) { G_FreeEdict (ent); inhibit++; continue; } // NOT_EASY && NOT_MEDIUM && NOT_HARD && NOT_DM == COOP_ONLY if ( (ent->spawnflags & SPAWNFLAG_NOT_EASY) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM) && (ent->spawnflags & SPAWNFLAG_NOT_HARD) && (ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH) ) goto removeflags; if( ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || ((skill->value >= 2) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) ) { G_FreeEdict (ent); inhibit++; continue; } } else // single player { if( ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || ((skill->value >= 2) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) ) { G_FreeEdict (ent); inhibit++; continue; } } removeflags: // Knightmare- remove no coop flag ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_DEATHMATCH|SPAWNFLAG_NOT_COOP); } ED_CallSpawn (ent); ent->s.renderfx |= RF_IR_VISIBLE; // ir goggles flag } // Knightmare- unload the alias script file if (alias_data) { // If no alias file was loaded, don't bother #ifdef KMQUAKE2_ENGINE_MOD // use new engine function instead gi.FreeFile(alias_data); #else if (alias_from_pak) gi.TagFree(alias_data); else free(&alias_data); #endif } // Knightmare- unload the replacement entity data /* if (newents) // If no alias file was loaded, don't bother #ifdef KMQUAKE2_ENGINE_MOD // use new engine function instead gi.FreeFile(newents); #else free(&newents); #endif*/ gi.dprintf ("%i entities inhibited\n", inhibit); #ifdef DEBUG i = 1; ent = EDICT_NUM(i); while (i < globals.num_edicts) { if (ent->inuse != 0 || ent->inuse != 1) Com_DPrintf("Invalid entity %d\n", i); i++, ent++; } #endif G_FindTeams (); // DWH G_FindCraneParts(); // Get origin offsets (mainly for brush models w/o origin brushes) for (i=1, ent=g_edicts+i ; i < globals.num_edicts ; i++,ent++) { VectorAdd(ent->absmin,ent->absmax,ent->origin_offset); VectorScale(ent->origin_offset,0.5,ent->origin_offset); VectorSubtract(ent->origin_offset,ent->s.origin,ent->origin_offset); } // end DWH PlayerTrail_Init (); //ZOID CTFSpawn(); // Knightmare added if (deathmatch->value && !ctf->value) CTFSetupTechSpawn(); //ZOID if (!deathmatch->value) SetupHintPaths(); for(i=1, ent=g_edicts+i; i < globals.num_edicts; i++, ent++) { if(!ent->movewith) continue; if(ent->movewith_ent) continue; ent->movewith_ent = G_Find(NULL,FOFS(targetname),ent->movewith); // Make sure that we can really "movewith" this guy. This check // allows us to have movewith parent with same targetname as // other entities while(ent->movewith_ent && (Q_stricmp(ent->movewith_ent->classname,"func_train") && Q_stricmp(ent->movewith_ent->classname,"model_train") && Q_stricmp(ent->movewith_ent->classname,"func_door") && Q_stricmp(ent->movewith_ent->classname,"func_vehicle") && Q_stricmp(ent->movewith_ent->classname,"func_tracktrain") )) ent->movewith_ent = G_Find(ent->movewith_ent,FOFS(targetname),ent->movewith); if(ent->movewith_ent) movewith_init(ent->movewith_ent); } /* for(i=1, ent=g_edicts+i; i < globals.num_edicts; i++, ent++) { gi.dprintf("%s:%s - movewith=%s, movewith_ent=%s:%s, movewith_next=%s:%s\n====================\n", ent->classname, (ent->targetname ? ent->targetname : "noname"), (ent->movewith ? ent->movewith : "N/A"), (ent->movewith_ent ? ent->movewith_ent->classname : "N/A"), (ent->movewith_ent ? (ent->movewith_ent->targetname ? ent->movewith_ent->targetname : "noname") : "N/A"), (ent->movewith_next ? ent->movewith_next->classname : "N/A"), (ent->movewith_next ? (ent->movewith_next->targetname ? ent->movewith_next->targetname : "noname") : "N/A")); } */ if(game.transition_ents) LoadTransitionEnts(); actor_files(); }
/* * Creates a server's entity / program execution context by * parsing textual entity definitions out of an ent file. */ void SpawnEntities(const char *mapname, char *entities, const char *spawnpoint) { edict_t *ent; int inhibit; const char *com_token; int i; float skill_level; static qboolean monster_count_city3 = false; if (!mapname || !entities || !spawnpoint) { return; } skill_level = floor(skill->value); if (skill_level < 0) { skill_level = 0; } if (skill_level > 3) { skill_level = 3; } if (skill->value != skill_level) { gi.cvar_forceset("skill", va("%f", skill_level)); } SaveClientData(); gi.FreeTags(TAG_LEVEL); memset(&level, 0, sizeof(level)); memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0])); Q_strlcpy(level.mapname, mapname, sizeof(level.mapname)); Q_strlcpy(game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)); /* set client fields on player ents */ for (i = 0; i < game.maxclients; i++) { g_edicts[i + 1].client = game.clients + i; } ent = NULL; inhibit = 0; /* parse ents */ while (1) { /* parse the opening brace */ com_token = COM_Parse(&entities); if (!entities) { break; } if (com_token[0] != '{') { gi.error("ED_LoadFromFile: found %s when expecting {", com_token); } if (!ent) { ent = g_edicts; } else { ent = G_Spawn(); } entities = ED_ParseEdict(entities, ent); /* yet another map hack */ if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27")) { ent->spawnflags &= ~SPAWNFLAG_NOT_HARD; } /* * The 'monsters' count in city3.bsp is wrong. * There're two monsters triggered in a hidden * and unreachable room next to the security * pass. * * We need to make sure that this hack is only * applied once! */ if(!Q_stricmp(level.mapname, "city3") && !monster_count_city3) { level.total_monsters = level.total_monsters - 2; monster_count_city3 = true; } /* remove things (except the world) from different skill levels or deathmatch */ if (ent != g_edicts) { if (deathmatch->value) { if (ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH) { G_FreeEdict(ent); inhibit++; continue; } } else { if (((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) ) { G_FreeEdict(ent); inhibit++; continue; } } ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY | SPAWNFLAG_NOT_MEDIUM | SPAWNFLAG_NOT_HARD | SPAWNFLAG_NOT_COOP | SPAWNFLAG_NOT_DEATHMATCH); } ED_CallSpawn(ent); } gi.dprintf("%i entities inhibited.\n", inhibit); G_FindTeams(); PlayerTrail_Init(); }
void ParseEntityString (qboolean respawn) { edict_t *ent; int inhibit; const char *com_token; const char *entities; int i; entities = level.entity_string; ent = NULL; inhibit = 0; i = 0; //mark all the spawned_entities as inuse so G_Spawn doesn't try to pick them during //trigger spawning etc for (i = 0; i < num_spawned_entities; i++) spawned_entities[i]->inuse = true; i = 0; // parse ents while (1) { // parse the opening brace com_token = COM_Parse (&entities); if (!entities) break; if (com_token[0] != '{') gi.error ("ED_LoadFromFile: found %s when expecting {",com_token); if (respawn) { ent = spawned_entities[i]; if (ent != world) { //double check we aren't overwriting stuff that we shouldn't be if (ent->enttype == ENT_DOOR_TRIGGER || ent->enttype == ENT_PLAT_TRIGGER) TDM_Error ("ParseEntityString: Trying to reuse an already spawned ent!"); G_FreeEdict (ent); G_InitEdict (ent); } i++; } else { if (!ent) ent = g_edicts; else ent = G_Spawn (); } entities = ED_ParseEdict (entities, ent); // yet another map hack if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27")) ent->spawnflags &= ~SPAWNFLAG_NOT_HARD; // remove things (except the world) from different skill levels or deathmatch if (ent != g_edicts) { if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH ) { G_FreeEdict (ent); inhibit++; //have to keep num_spawned in sync for respawn if (!respawn) spawned_entities[num_spawned_entities++] = ent; continue; } ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH); } else if (respawn) continue; ED_CallSpawn (ent); if (!respawn) { if (num_spawned_entities == MAX_EDICTS * 4) TDM_Error ("Exceeded MAX_EDICTS * 4 entities during entity string parse"); spawned_entities[num_spawned_entities++] = ent; } else { //an elevator or something respawned on top of a player? don't do it for match start, since //players will be respawning anyway. if (tdm_match_status < MM_PLAYING && (ent->solid == SOLID_BBOX || ent->solid == SOLID_BSP)) { edict_t *touch[MAX_EDICTS]; int count; int j; //r1: fix 00000196, can't killbox during map spawn due to risk of killing half-spawned //map entities. do a pseudo-killbox that only whacks players instead. count = gi.BoxEdicts (ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_SOLID); for (j = 0; j < count; j++) { if (touch[j] == ent) continue; //no point killing anything that won't clip (eg corpses) if (touch[j]->solid == SOLID_NOT || touch[j]->enttype == ENT_BODYQUE) continue; if (!touch[j]->client) continue; if (touch[j]->inuse) T_Damage (touch[j], ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG); } } } } //gi.dprintf ("%i entities inhibited\n", inhibit); #ifdef DEBUG i = 1; ent = EDICT_NUM(i); while (i < globals.num_edicts) { if (ent->inuse != 0 || ent->inuse != 1) Com_DPrintf("Invalid entity %d\n", i); i++, ent++; } #endif G_FindTeams (); }
void use_target_spawner (edict_t *self, edict_t *other, edict_t *activator) { edict_t *ent; int r, maxr = -1, minr = -1; int oldskill = skill->value; int newskill; char command[32]; ent = G_Spawn(); if (self->spawnflags & 32) { if (self->target) ent->target = self->target; else { gi.dprintf("%s with spawnflag 32 and no target at %s\n", self->classname, vtos(self->s.origin)); G_FreeEdict(ent); return; } } else if (self->target) ent->classname = self->target; if ((self->spawnflags & 32) || (!self->target)) { if (self->spawnflags & 1) { minr = 0; maxr = 4; } if (self->spawnflags & 2) { if (minr == -1) minr = 5; else minr = 0; maxr = 7; } if (self->spawnflags & 4) { if (minr == -1) minr = 8; else minr = 0; maxr = 10; } if (self->spawnflags & 8) { if (minr == -1) minr = 11; else minr = 0; maxr = 13; } if (minr == -1) { gi.dprintf("%s with NULL target and no spawnflags at %s\n", self->classname, vtos(self->s.origin)); G_FreeEdict(ent); return; } r = (int) (random() * (maxr - minr) + minr); switch(r) { case 0: ent->classname = "monster_soldier_light"; break; case 1: ent->classname = "monster_soldier"; break; case 2: ent->classname = "monster_soldier_ss"; break; case 3: ent->classname = "monster_infantry"; break; case 4: ent->classname = "monster_parasite"; break; case 5: ent->classname = "monster_chick"; break; case 6: ent->classname = "monster_mutant"; break; case 7: ent->classname = "monster_gunner"; break; case 8: ent->classname = "monster_tank"; break; case 9: ent->classname = "monster_tank_commander"; break; case 10: ent->classname = "monster_gladiator"; break; case 11: ent->classname = "monster_supertank"; break; case 12: ent->classname = "monster_boss2"; break; case 13: if (random() < 0.3) ent->classname = "monster_jorg"; else ent->classname = "monster_supertank"; break; default: return; //break; } } if (!ent->classname) { gi.dprintf("%s spawning no classname at %s\n", self->classname, vtos(self->s.origin)); G_FreeEdict(ent); return; } // Due to buggy fact2, we can't allow target_spawner to spawn misc_insane if (ent->classid == CI_M_INSANE) { G_FreeEdict(ent); return; } if (ent->health == -1) { newskill = (oldskill * ent->dmg_radius) + ent->dmg; } else { newskill = ent->health + random() * (ent->max_health - ent->health); } sprintf(command, "%d", newskill); gi.cvar_forceset("skill", command); VectorCopy (self->s.origin, ent->s.origin); VectorCopy (self->s.angles, ent->s.angles); ED_CallSpawn (ent); sprintf(command, "%d", oldskill); gi.cvar_forceset("skill", command); gi.unlinkentity (ent); if (!KillBox2 (ent)) return; gi.linkentity (ent); if (self->speed) VectorCopy (self->movedir, ent->velocity); }
/** * @brief Creates a server's entity / program execution context * by parsing textual entity definitions out of an ent file. * @sa CM_EntityString * @sa SV_SpawnServer */ void G_SpawnEntities (const char *mapname, bool day, const char *entities) { int entnum; G_FreeTags(TAG_LEVEL); OBJZERO(level); level.pathingMap = (pathing_t *)G_TagMalloc(sizeof(*level.pathingMap), TAG_LEVEL); G_EdictsReset(); /* initialize reactionFire data */ G_ReactionFireTargetsInit(); Q_strncpyz(level.mapname, mapname, sizeof(level.mapname)); level.day = day; G_ResetClientData(); level.activeTeam = TEAM_NO_ACTIVE; level.actualRound = 1; level.hurtAliens = sv_hurtaliens->integer; ai_waypointList = NULL; /* parse ents */ entnum = 0; while (1) { edict_t *ent; /* parse the opening brace */ const char *token = Com_Parse(&entities); if (!entities) break; if (token[0] != '{') gi.Error("ED_LoadFromFile: found %s when expecting {", token); ent = G_Spawn(); entities = ED_ParseEdict(entities, ent); ent->mapNum = entnum++; /* Set the position of the entity */ VecToPos(ent->origin, ent->pos); /* Call this entity's specific initializer (sets ent->type) */ ED_CallSpawn(ent); /* if this entity is an bbox (e.g. actor), then center its origin based on its position */ if (ent->solid == SOLID_BBOX) G_EdictCalcOrigin(ent); } /* spawn ai players, if needed */ if (level.num_spawnpoints[TEAM_CIVILIAN]) { if (AI_CreatePlayer(TEAM_CIVILIAN) == NULL) gi.DPrintf("Could not create civilian\n"); } if ((sv_maxclients->integer == 1 || ai_numactors->integer) && level.num_spawnpoints[TEAM_ALIEN]) { if (AI_CreatePlayer(TEAM_ALIEN) == NULL) gi.DPrintf("Could not create alien\n"); } Com_Printf("Used inventory slots after ai spawn: %i\n", game.i.GetUsedSlots(&game.i)); G_FindEdictGroups(); }
/* * Creates a server's entity / program execution context by * parsing textual entity definitions out of an ent file. */ void SpawnEntities(char *mapname, char *entities, char *spawnpoint) { edict_t *ent; int inhibit; char *com_token; int i; float skill_level; skill_level = floor(skill->value); if (skill_level < 0) { skill_level = 0; } if (skill_level > 3) { skill_level = 3; } if (skill->value != skill_level) { gi.cvar_forceset("skill", va("%f", skill_level)); } SaveClientData(); gi.FreeTags(TAG_LEVEL); memset(&level, 0, sizeof(level)); memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0])); strncpy(level.mapname, mapname, sizeof(level.mapname) - 1); strncpy(game.spawnpoint, spawnpoint, sizeof(game.spawnpoint) - 1); /* set client fields on player ents */ for (i = 0; i < game.maxclients; i++) { g_edicts[i + 1].client = game.clients + i; } ent = NULL; inhibit = 0; /* parse ents */ while (1) { /* parse the opening brace */ com_token = COM_Parse(&entities); if (!entities) { break; } if (com_token[0] != '{') { gi.error("ED_LoadFromFile: found %s when expecting {", com_token); } if (!ent) { ent = g_edicts; } else { ent = G_Spawn(); } entities = ED_ParseEdict(entities, ent); /* yet another map hack */ if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27")) { ent->spawnflags &= ~SPAWNFLAG_NOT_HARD; } /* remove things (except the world) from different skill levels or deathmatch */ if (ent != g_edicts) { if (deathmatch->value) { if (ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH) { G_FreeEdict(ent); inhibit++; continue; } } else { if (((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) ) { G_FreeEdict(ent); inhibit++; continue; } } ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY | SPAWNFLAG_NOT_MEDIUM | SPAWNFLAG_NOT_HARD | SPAWNFLAG_NOT_COOP | SPAWNFLAG_NOT_DEATHMATCH); } ED_CallSpawn(ent); } gi.dprintf("%i entities inhibited.\n", inhibit); G_FindTeams(); PlayerTrail_Init(); CTFSpawn(); }
void fixbot_fire_laser (edict_t *self) { vec3_t forward, right, up; vec3_t tempang, start; vec3_t dir, angles, end; edict_t *ent; // critter dun got blown up while bein' fixed if (self->enemy->health <= self->enemy->gib_health) { self->monsterinfo.currentmove = &fixbot_move_stand; self->monsterinfo.aiflags &= ~AI_MEDIC; return; } gi.sound(self, CHAN_AUTO, gi.soundindex("misc/lasfly.wav"), 1, ATTN_STATIC, 0); VectorCopy (self->s.origin, start); VectorCopy (self->enemy->s.origin, end); VectorSubtract (end, start, dir); vectoangles (dir, angles); ent = G_Spawn (); VectorCopy (self->s.origin, ent->s.origin); VectorCopy (angles, tempang); AngleVectors (tempang, forward, right, up); VectorCopy (tempang, ent->s.angles); VectorCopy (ent->s.origin, start); VectorMA (start, 16, forward, start); VectorCopy (start, ent->s.origin); ent->enemy = self->enemy; ent->owner = self; ent->dmg = -1; monster_dabeam (ent); if (self->enemy->health > (self->enemy->mass/10)) { // sorry guys but had to fix the problem this way // if it doesn't do this then two creatures can share the same space // and its real bad. if (check_telefrag (self)) { self->enemy->spawnflags = 0; self->enemy->monsterinfo.aiflags = 0; self->enemy->target = NULL; self->enemy->targetname = NULL; self->enemy->combattarget = NULL; self->enemy->deathtarget = NULL; self->enemy->owner = self; ED_CallSpawn (self->enemy); self->enemy->owner = NULL; self->s.origin[2] += 1; self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING; self->monsterinfo.currentmove = &fixbot_move_stand; self->monsterinfo.aiflags &= ~AI_MEDIC; } } else self->enemy->monsterinfo.aiflags |= AI_RESURRECTING; }