/* ============= G_FindByTargetname ============= */ gentity_t *G_FindByTargetname(gentity_t *from, const char *match) { gentity_t *max = &g_entities[level.num_entities]; int hash = BG_StringHashValue(match); if (!from) { from = g_entities; } else { from++; } for ( ; from < max ; from++) { if (!from->inuse) { continue; } if (from->targetnamehash == hash && !Q_stricmp(from->targetname, match)) { return from; } } return NULL; }
/* =================== G_SpawnGEntityFromSpawnVars Spawn an entity and fill in all of the level fields from level.spawnVars[], then call the class specfic spawn function =================== */ gentity_t *G_SpawnGEntityFromSpawnVars(void) { int i; gentity_t *ent = G_Spawn(); // get the next free entity char *str; for (i = 0 ; i < level.numSpawnVars ; i++) { G_ParseField(level.spawnVars[i][0], level.spawnVars[i][1], ent); } // check for "notteam" / "notfree" flags G_SpawnInt("notteam", "0", &i); if (i) { G_FreeEntity(ent); return NULL; } // allowteams handling G_SpawnString("allowteams", "", &str); if (str[0]) { str = Q_strlwr(str); if (strstr(str, "axis")) { ent->allowteams |= ALLOW_AXIS_TEAM; } if (strstr(str, "allies")) { ent->allowteams |= ALLOW_ALLIED_TEAM; } if (strstr(str, "cvops")) { ent->allowteams |= ALLOW_DISGUISED_CVOPS; } } if (ent->targetname && *ent->targetname) { ent->targetnamehash = BG_StringHashValue(ent->targetname); } else { ent->targetnamehash = -1; } // move editor origin to pos VectorCopy(ent->s.origin, ent->s.pos.trBase); VectorCopy(ent->s.origin, ent->r.currentOrigin); // if we didn't get a classname, don't bother spawning anything if (!G_CallSpawn(ent)) { G_FreeEntity(ent); } return ent; }
/** * @brief "activator" should be set to the entity that initiated the firing. * Search for (string)targetname in all entities that * match (string)self.target and call their .use function */ void G_UseTargets(gentity_t *ent, gentity_t *activator) { gentity_t *t; int hash; if (!ent) { return; } if (!ent->target) { return; } t = NULL; hash = BG_StringHashValue(ent->target); while ((t = G_FindByTargetnameFast(t, ent->target, hash)) != NULL) { if (t == ent) { G_Printf(S_COLOR_YELLOW "WARNING G_UseTargets: Entity used itself.\n"); } else { if (t->use) { //G_Printf ("ent->classname %s ent->targetname %s t->targetname %s t->s.number %d\n", ent->classname, ent->targetname, t->targetname, t->s.number); t->flags |= (ent->flags & FL_KICKACTIVATE); // If 'ent' was kicked to activate, pass this along to it's targets. // It may become handy to put a "KICKABLE" flag in ents so that it knows whether to pass this along or not // Right now, the only situation where it would be weird would be an invisible_user that is a 'button' near // a rotating door that it triggers. Kick the switch and the door next to it flies open. t->flags |= (ent->flags & FL_SOFTACTIVATE); // likewise for soft activation if (activator && ((Q_stricmp(t->classname, "func_door") == 0) || (Q_stricmp(t->classname, "func_door_rotating") == 0) ) ) { // check door usage rules before allowing any entity to trigger a door open G_TryDoor(t, ent, activator); // (door,other,activator) } else { G_UseEntity(t, ent, activator); } } } if (!ent->inuse) { G_Printf(S_COLOR_YELLOW "WARNING G_UseTargets: entity was removed while using targets\n"); return; } } }
/* =============== G_CallSpawn Finds the spawn function for the entity and calls it, returning qfalse if not found =============== */ qboolean G_CallSpawn( gentity_t *ent ) { spawn_t *s; gitem_t *item; int hash; if ( !ent->classname ) { G_Printf( "G_CallSpawn: NULL classname\n" ); return qfalse; } if ( g_deathmatch.integer ) { if ( !strcmp( "func_explosive", ent->classname ) ) { return qfalse; } if ( !strcmp( "trigger_hurt", ent->classname ) ) { return qfalse; } // don't spawn the flags in cp if ( g_gametype.integer == 7 && !strcmp( "team_WOLF_checkpoint", ent->classname ) ) { return qfalse; } } // check item spawn functions for ( item = bg_itemlist + 1 ; item->classname ; item++ ) { if ( !strcmp( item->classname, ent->classname ) ) { // found it // DHM - Nerve :: allow flags in GTWOLF if ( item->giType == IT_TEAM && ( g_gametype.integer != GT_CTF && g_gametype.integer < GT_WOLF ) ) { return qfalse; } G_SpawnItem( ent, item ); return qtrue; } } // check normal spawn functions hash = BG_StringHashValue( ent->classname ); for ( s = spawns ; s->name ; s++ ) { if ( s->hash == hash ) { // found it s->spawn( ent ); // RF, entity scripting if ( ent->s.number >= MAX_CLIENTS && ent->scriptName ) { G_Script_ScriptParse( ent ); G_Script_ScriptEvent( ent, "spawn", "" ); } return qtrue; } } G_Printf( "%s doesn't have a spawn function\n", ent->classname ); return qfalse; }
/* ============= G_FindByTargetname ============= */ gentity_t *G_FindByTargetname(gentity_t *from, const char *match) { gentity_t *max = &g_entities[level.num_entities]; int hash; hash = BG_StringHashValue(match); if (hash == -1) // if there is no name (not empty string!) BG_StringHashValue returns -1 { G_Printf("G_FindByTargetname WARNING: invalid match pointer '%s' - run devmap & g_scriptdebug 1 to get more info about\n", match); //return NULL; ?! - won't be found - NULL is returned anyway } if (!from) { from = g_entities; } else { from++; } for ( ; from < max ; from++) { if (!from->inuse) { continue; } if (!from->targetname) // there are ents with no targetname set { continue; } if (from->targetnamehash == hash && !Q_stricmp(from->targetname, match)) { return from; } } return NULL; }
/* =================== G_SpawnGEntityFromSpawnVars Spawn an entity and fill in all of the level fields from level.spawnVars[], then call the class specfic spawn function =================== */ void G_SpawnGEntityFromSpawnVars( void ) { int i; gentity_t *ent; // get the next free entity ent = G_Spawn(); for ( i = 0 ; i < level.numSpawnVars ; i++ ) { G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent ); } if ( g_gametype.integer >= GT_TEAM ) { G_SpawnInt( "notteam", "0", &i ); if ( i ) { G_FreeEntity( ent ); return; } } else { G_SpawnInt( "notfree", "0", &i ); if ( i ) { G_FreeEntity( ent ); return; } } if ( ent->targetname && *ent->targetname ) { ent->targetnamehash = BG_StringHashValue( ent->targetname ); } else { ent->targetnamehash = -1; } // move editor origin to pos VectorCopy( ent->s.origin, ent->s.pos.trBase ); VectorCopy( ent->s.origin, ent->r.currentOrigin ); // if we didn't get a classname, don't bother spawning anything if ( !G_CallSpawn( ent ) ) { G_FreeEntity( ent ); } }
/* ============ AnimParseAnimConfig returns qfalse if error, qtrue otherwise ============ */ static qboolean AnimParseAnimConfig( playerInfo_t *animModelInfo, const char *filename, const char *input ) { char *text_p, *token; animation_t *animations; // headAnimation_t *headAnims; int i, fps, skip = -1; // if (!weaponStringsInited) { // BG_InitWeaponStrings(); // } // globalFilename = (char *)filename; animations = animModelInfo->animations; animModelInfo->numAnimations = 0; // headAnims = animModelInfo->headAnims; text_p = (char *)input; COM_BeginParseSession( "AnimParseAnimConfig" ); animModelInfo->footsteps = FOOTSTEP_NORMAL; VectorClear( animModelInfo->headOffset ); animModelInfo->gender = GENDER_MALE; animModelInfo->isSkeletal = qfalse; animModelInfo->version = 0; // read optional parameters while ( 1 ) { token = COM_Parse( &text_p ); if ( !token ) { break; } if ( !Q_stricmp( token, "footsteps" ) ) { token = COM_Parse( &text_p ); if ( !token ) { break; } if ( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) { animModelInfo->footsteps = FOOTSTEP_NORMAL; } else if ( !Q_stricmp( token, "boot" ) ) { animModelInfo->footsteps = FOOTSTEP_BOOT; } else if ( !Q_stricmp( token, "flesh" ) ) { animModelInfo->footsteps = FOOTSTEP_FLESH; } else if ( !Q_stricmp( token, "mech" ) ) { animModelInfo->footsteps = FOOTSTEP_MECH; } else if ( !Q_stricmp( token, "energy" ) ) { animModelInfo->footsteps = FOOTSTEP_ENERGY; } else { // BG_AnimParseError( "Bad footsteps parm '%s'\n", token ); } continue; } else if ( !Q_stricmp( token, "headoffset" ) ) { for ( i = 0 ; i < 3 ; i++ ) { token = COM_Parse( &text_p ); if ( !token ) { break; } animModelInfo->headOffset[i] = atof( token ); } continue; } else if ( !Q_stricmp( token, "sex" ) ) { token = COM_Parse( &text_p ); if ( !token ) { break; } if ( token[0] == 'f' || token[0] == 'F' ) { animModelInfo->gender = GENDER_FEMALE; } else if ( token[0] == 'n' || token[0] == 'N' ) { animModelInfo->gender = GENDER_NEUTER; } else { animModelInfo->gender = GENDER_MALE; } continue; } else if ( !Q_stricmp( token, "version" ) ) { token = COM_Parse( &text_p ); if ( !token ) { break; } animModelInfo->version = atoi( token ); continue; } else if ( !Q_stricmp( token, "skeletal" ) ) { animModelInfo->isSkeletal = qtrue; continue; } if ( animModelInfo->version < 2 ) { // if it is a number, start parsing animations if ( Q_isnumeric( token[0] ) ) { text_p -= strlen( token ); // unget the token break; } } // STARTANIMS marks the start of the animations if ( !Q_stricmp( token, "STARTANIMS" ) ) { break; } // BG_AnimParseError( "unknown token '%s'", token ); } // read information for each frame for ( i = 0 ; ( animModelInfo->version > 1 ) || ( i < MAX_ANIMATIONS ) ; i++ ) { token = COM_Parse( &text_p ); if ( !token ) { break; } if ( animModelInfo->version > 1 ) { // includes animation names at start of each line if ( !Q_stricmp( token, "ENDANIMS" ) ) { // end of animations break; } Q_strncpyz( animations[i].name, token, sizeof( animations[i].name ) ); // convert to all lower case Q_strlwr( animations[i].name ); // token = COM_ParseExt( &text_p, qfalse ); if ( !token || !token[0] ) { // BG_AnimParseError( "end of file without ENDANIMS" ); break; } } else { // just set it to the equivalent animStrings[] Q_strncpyz( animations[i].name, animStrings[i], sizeof( animations[i].name ) ); // convert to all lower case Q_strlwr( animations[i].name ); } animations[i].firstFrame = atoi( token ); if ( !animModelInfo->isSkeletal ) { // skeletal models dont require adjustment // leg only frames are adjusted to not count the upper body only frames if ( i == LEGS_WALKCR ) { skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame; } if ( i >= LEGS_WALKCR ) { animations[i].firstFrame -= skip; } } token = COM_ParseExt( &text_p, qfalse ); if ( !token || !token[0] ) { // BG_AnimParseError( "end of file without ENDANIMS" ); break; } animations[i].numFrames = atoi( token ); token = COM_ParseExt( &text_p, qfalse ); if ( !token || !token[0] ) { // BG_AnimParseError( "end of file without ENDANIMS: line %i" ); break; } animations[i].loopFrames = atoi( token ); token = COM_ParseExt( &text_p, qfalse ); if ( !token || !token[0] ) { // BG_AnimParseError( "end of file without ENDANIMS: line %i" ); break; } fps = atof( token ); if ( fps == 0 ) { fps = 1; } animations[i].frameLerp = 1000 / fps; animations[i].initialLerp = 1000 / fps; // movespeed token = COM_ParseExt( &text_p, qfalse ); if ( !token || !token[0] ) { // BG_AnimParseError( "end of file without ENDANIMS" ); break; } animations[i].moveSpeed = atoi( token ); // animation blending token = COM_ParseExt( &text_p, qfalse ); // must be on same line if ( !token ) { animations[i].animBlend = 0; } else { animations[i].animBlend = atoi( token ); } // calculate the duration animations[i].duration = animations[i].initialLerp + animations[i].frameLerp * animations[i].numFrames + animations[i].animBlend; // get the nameHash animations[i].nameHash = BG_StringHashValue( animations[i].name ); if ( !Q_strncmp( animations[i].name, "climb", 5 ) ) { animations[i].flags |= ANIMFL_LADDERANIM; } if ( strstr( animations[i].name, "firing" ) ) { animations[i].flags |= ANIMFL_FIRINGANIM; animations[i].initialLerp = 40; } } animModelInfo->numAnimations = i; if ( animModelInfo->version < 2 && i != MAX_ANIMATIONS ) { // BG_AnimParseError( "Incorrect number of animations" ); return qfalse; } #if 0 // check for head anims token = COM_Parse( &text_p ); if ( token && token[0] ) { if ( animModelInfo->version < 2 || !Q_stricmp( token, "HEADFRAMES" ) ) { // read information for each head frame for ( i = 0 ; i < MAX_HEAD_ANIMS ; i++ ) { token = COM_Parse( &text_p ); if ( !token || !token[0] ) { break; } if ( animModelInfo->version > 1 ) { // includes animation names at start of each line // just throw this information away, not required for head token = COM_ParseExt( &text_p, qfalse ); if ( !token || !token[0] ) { break; } } if ( !i ) { skip = atoi( token ); } headAnims[i].firstFrame = atoi( token ); // modify according to last frame of the main animations, since the head is totally seperate headAnims[i].firstFrame -= animations[MAX_ANIMATIONS - 1].firstFrame + animations[MAX_ANIMATIONS - 1].numFrames + skip; token = COM_ParseExt( &text_p, qfalse ); if ( !token || !token[0] ) { break; } headAnims[i].numFrames = atoi( token ); // skip the movespeed token = COM_ParseExt( &text_p, qfalse ); } // animModelInfo->numHeadAnims = i; if ( i != MAX_HEAD_ANIMS ) { // BG_AnimParseError( "Incorrect number of head frames" ); return qfalse; } } } #endif return qtrue; }
static qboolean BG_SS_ParseSpeaker(int handle) { pc_token_t token; bg_speaker_t speaker; memset(&speaker, 0, sizeof(speaker)); speaker.volume = 127; speaker.range = 1250; if (!trap_PC_ReadToken(handle, &token) || Q_stricmp(token.string, "{")) { return BG_SS_ParseError(handle, "expected '{'"); } while (1) { if (!trap_PC_ReadToken(handle, &token)) { break; } if (token.string[0] == '}') { break; } if (!Q_stricmp(token.string, "noise")) { if (!PC_String_ParseNoAlloc(handle, speaker.filename, sizeof(speaker.filename))) { return BG_SS_ParseError(handle, "expected sound filename"); } } else if (!Q_stricmp(token.string, "origin")) { if (!PC_Vec_Parse(handle, &speaker.origin)) { return BG_SS_ParseError(handle, "expected origin vector"); } } else if (!Q_stricmp(token.string, "targetname")) { if (!PC_String_ParseNoAlloc(handle, speaker.targetname, sizeof(speaker.targetname))) { return BG_SS_ParseError(handle, "expected targetname string"); } else { speaker.targetnamehash = BG_StringHashValue(speaker.targetname); } } else if (!Q_stricmp(token.string, "looped")) { if (!trap_PC_ReadToken(handle, &token)) { return BG_SS_ParseError(handle, "expected loop value"); } else { if (!Q_stricmp(token.string, "no")) { speaker.loop = S_LT_NOT_LOOPED; } else if (!Q_stricmp(token.string, "on")) { speaker.loop = S_LT_LOOPED_ON; speaker.activated = qtrue; } else if (!Q_stricmp(token.string, "off")) { speaker.loop = S_LT_LOOPED_OFF; } else { return BG_SS_ParseError(handle, "unknown loop value '%s'", token.string); } } } else if (!Q_stricmp(token.string, "broadcast")) { if (!trap_PC_ReadToken(handle, &token)) { return BG_SS_ParseError(handle, "expected broadcast value"); } else { if (!Q_stricmp(token.string, "no")) { speaker.broadcast = S_BT_LOCAL; } else if (!Q_stricmp(token.string, "global")) { speaker.broadcast = S_BT_GLOBAL; } else if (!Q_stricmp(token.string, "nopvs")) { speaker.broadcast = S_BT_NOPVS; } else { return BG_SS_ParseError(handle, "unknown broadcast value '%s'", token.string); } } } else if (!Q_stricmp(token.string, "wait")) { if (!PC_Int_Parse(handle, &speaker.wait)) { return BG_SS_ParseError(handle, "expected wait value"); } else if (speaker.wait < 0) { return BG_SS_ParseError(handle, "wait value %i is invalid", speaker.wait); } } else if (!Q_stricmp(token.string, "random")) { if (!PC_Int_Parse(handle, &speaker.random)) { return BG_SS_ParseError(handle, "expected random value"); } else if (speaker.random < 0) { return BG_SS_ParseError(handle, "random value %i is invalid", speaker.random); } } else if (!Q_stricmp(token.string, "volume")) { if (!PC_Int_Parse(handle, &speaker.volume)) { return BG_SS_ParseError(handle, "expected volume value"); } else if (speaker.volume < 0 || speaker.volume > 65535) { return BG_SS_ParseError(handle, "volume value %i is invalid", speaker.volume); } } else if (!Q_stricmp(token.string, "range")) { if (!PC_Int_Parse(handle, &speaker.range)) { return BG_SS_ParseError(handle, "expected range value"); } else if (speaker.range < 0) { return BG_SS_ParseError(handle, "range value %i is invalid", speaker.range); } } else { return BG_SS_ParseError(handle, "unknown token '%s'", token.string); } } if (!BG_SS_StoreSpeaker(&speaker)) { return BG_SS_ParseError(handle, "Failed to store speaker", token.string); } return qtrue; }
static animation_t * BG_RAG_FindFreeAnimation(const char *mdxFileName, const char *name) #endif // CGAMEDLL { int i; for (i = 0; i < MAX_ANIMPOOL_SIZE; i++) { #ifdef CGAMEDLL if (animationPool[i].mdxFile == mdxFile && !Q_stricmp(animationPool[i].name, name)) { #else if (*animationPool[i].mdxFileName && !Q_stricmp(animationPool[i].mdxFileName, mdxFileName) && !Q_stricmp(animationPool[i].name, name)) { #endif // CGAMEDLL return(&animationPool[i]); } } for (i = 0; i < MAX_ANIMPOOL_SIZE; i++) { #ifdef CGAMEDLL if (!animationPool[i].mdxFile) { animationPool[i].mdxFile = mdxFile; #else if (!animationPool[i].mdxFileName[0]) { Q_strncpyz(animationPool[i].mdxFileName, mdxFileName, sizeof(animationPool[i].mdxFileName)); #endif // CGAMEDLL Q_strncpyz(animationPool[i].name, name, sizeof(animationPool[i].name)); return(&animationPool[i]); } } return NULL; } static qboolean BG_RAG_ParseError(int handle, char *format, ...) { int line; char filename[128]; va_list argptr; static char string[4096]; va_start(argptr, format); Q_vsnprintf(string, sizeof(string), format, argptr); va_end(argptr); filename[0] = '\0'; line = 0; trap_PC_SourceFileAndLine(handle, filename, &line); Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string); trap_PC_FreeSource(handle); return qfalse; } static qboolean BG_RAG_ParseAnimation(int handle, animation_t *animation) { int i; animation->flags = 0; if (!PC_Int_Parse(handle, &animation->firstFrame)) { return BG_RAG_ParseError(handle, "expected first frame integer"); } if (!PC_Int_Parse(handle, &animation->numFrames)) { return BG_RAG_ParseError(handle, "expected length integer"); } if (!PC_Int_Parse(handle, &animation->loopFrames)) { return BG_RAG_ParseError(handle, "expected looping integer"); } if (!PC_Int_Parse(handle, &i)) { return BG_RAG_ParseError(handle, "expected fps integer"); } if (i == 0) { i = 1; } animation->frameLerp = 1000 / (float)i; animation->initialLerp = 1000 / (float)i; if (!PC_Int_Parse(handle, &animation->moveSpeed)) { return BG_RAG_ParseError(handle, "expected move speed integer"); } if (!PC_Int_Parse(handle, &animation->animBlend)) { return BG_RAG_ParseError(handle, "expected transition integer"); } if (!PC_Int_Parse(handle, &i)) { return BG_RAG_ParseError(handle, "expected reversed integer"); } if (i == 1) { animation->flags |= ANIMFL_REVERSED; } // calculate the duration animation->duration = animation->initialLerp + animation->frameLerp * animation->numFrames + animation->animBlend; // get the nameHash animation->nameHash = BG_StringHashValue(animation->name); // hacky-ish stuff if (!Q_strncmp(animation->name, "climb", 5)) { animation->flags |= ANIMFL_LADDERANIM; } if (strstr(animation->name, "firing")) { animation->flags |= ANIMFL_FIRINGANIM; animation->initialLerp = 40; } return qtrue; }
static qboolean BG_RAG_ParseAnimation(int handle, animation_t *animation) { int i; animation->flags = 0; if (!PC_Int_Parse(handle, &animation->firstFrame)) { return BG_RAG_ParseError(handle, "expected first frame integer"); } if (!PC_Int_Parse(handle, &animation->numFrames)) { return BG_RAG_ParseError(handle, "expected length integer"); } if (!PC_Int_Parse(handle, &animation->loopFrames)) { return BG_RAG_ParseError(handle, "expected looping integer"); } if (!PC_Int_Parse(handle, &i)) { return BG_RAG_ParseError(handle, "expected fps integer"); } if (i == 0) { i = 1; } animation->frameLerp = 1000 / (float)i; animation->initialLerp = 1000 / (float)i; if (!PC_Int_Parse(handle, &animation->moveSpeed)) { return BG_RAG_ParseError(handle, "expected move speed integer"); } if (!PC_Int_Parse(handle, &animation->animBlend)) { return BG_RAG_ParseError(handle, "expected transition integer"); } if (!PC_Int_Parse(handle, &i)) { return BG_RAG_ParseError(handle, "expected reversed integer"); } if (i == 1) { animation->flags |= ANIMFL_REVERSED; } // calculate the duration animation->duration = animation->initialLerp + animation->frameLerp * animation->numFrames + animation->animBlend; // get the nameHash animation->nameHash = BG_StringHashValue(animation->name); // hacky-ish stuff if (!Q_strncmp(animation->name, "climb", 5)) { animation->flags |= ANIMFL_LADDERANIM; } if (strstr(animation->name, "firing")) { animation->flags |= ANIMFL_FIRINGANIM; animation->initialLerp = 40; } return qtrue; }