/*QUAKED misc_model_breakable (1 0 0) (-16 -16 -16) (16 16 16) SOLID AUTOANIMATE DEADSOLID NO_DMODEL NO_SMOKE USE_MODEL USE_NOT_BREAK PLAYER_USE NO_EXPLOSION START_OFF SOLID - Movement is blocked by it, if not set, can still be broken by explosions and shots if it has health AUTOANIMATE - Will cycle it's anim DEADSOLID - Stay solid even when destroyed (in case damage model is rather large). NO_DMODEL - Makes it NOT display a damage model when destroyed, even if one exists USE_MODEL - When used, will toggle to it's usemodel (model + "_u1.md3")... this obviously does nothing if USE_NOT_BREAK is not checked USE_NOT_BREAK - Using it, doesn't make it break, still can be destroyed by damage PLAYER_USE - Player can use it with the use button NO_EXPLOSION - By default, will explode when it dies...this is your override. START_OFF - Will start off and will not appear until used. "model" arbitrary .md3 file to display "modelscale" "x" uniform scale "modelscale_vec" "x y z" scale model in each axis - height, width and length - bbox will scale with it "health" how much health to have - default is zero (not breakable) If you don't set the SOLID flag, but give it health, it can be shot but will not block NPCs or players from moving "targetname" when used, dies and displays damagemodel (model + "_d1.md3"), if any (if not, removes itself) "target" What to use when it dies "target2" What to use when it's repaired "target3" What to use when it's used while it's broken "paintarget" target to fire when hit (but not destroyed) "count" the amount of armor/health/ammo given (default 50) "radius" Chunk code tries to pick a good volume of chunks, but you can alter this to scale the number of spawned chunks. (default 1) (.5) is half as many chunks, (2) is twice as many chunks "NPC_targetname" - Only the NPC with this name can damage this "forcevisible" - When you turn on force sight (any level), you can see these draw through the entire level... "redCrosshair" - crosshair turns red when you look at this "gravity" if set to 1, this will be affected by gravity "throwtarget" if set (along with gravity), this thing, when used, will throw itself at the entity whose targetname matches this string "mass" if gravity is on, this determines how much damage this thing does when it hits someone. Default is the size of the object from one corner to the other, that works very well. Only override if this is an object whose mass should be very high or low for it's size (density) Damage: default is none "splashDamage" - damage to do (will make it explode on death) "splashRadius" - radius for above damage "team" - This cannot take damage from members of this team: "player" "neutral" "enemy" "material" - default is "8 - MAT_NONE" - choose from this list: 0 = MAT_METAL (grey metal) 1 = MAT_GLASS 2 = MAT_ELECTRICAL (sparks only) 3 = MAT_ELEC_METAL (METAL chunks and sparks) 4 = MAT_DRK_STONE (brown stone chunks) 5 = MAT_LT_STONE (tan stone chunks) 6 = MAT_GLASS_METAL (glass and METAL chunks) 7 = MAT_METAL2 (blue/grey metal) 8 = MAT_NONE (no chunks-DEFAULT) 9 = MAT_GREY_STONE (grey colored stone) 10 = MAT_METAL3 (METAL and METAL2 chunk combo) 11 = MAT_CRATE1 (yellow multi-colored crate chunks) 12 = MAT_GRATE1 (grate chunks--looks horrible right now) 13 = MAT_ROPE (for yavin_trial, no chunks, just wispy bits ) 14 = MAT_CRATE2 (red multi-colored crate chunks) 15 = MAT_WHITE_METAL (white angular chunks for Stu, NS_hideout ) */ void SP_misc_model_breakable( gentity_t *ent ) { char damageModel[MAX_QPATH]; char chunkModel[MAX_QPATH]; char useModel[MAX_QPATH]; int len; // Chris F. requested default for misc_model_breakable to be NONE...so don't arbitrarily change this. G_SpawnInt( "material", "8", (int*)&ent->material ); G_SpawnFloat( "radius", "1", &ent->radius ); // used to scale chunk code if desired by a designer qboolean bHasScale = G_SpawnVector("modelscale_vec", "0 0 0", ent->s.modelScale); if (!bHasScale) { float temp; G_SpawnFloat( "modelscale", "0", &temp); if (temp != 0.0f) { ent->s.modelScale[ 0 ] = ent->s.modelScale[ 1 ] = ent->s.modelScale[ 2 ] = temp; bHasScale = qtrue; } } CacheChunkEffects( ent->material ); misc_model_breakable_init( ent ); len = strlen( ent->model ) - 4; assert(ent->model[len]=='.');//we're expecting ".md3" strncpy( damageModel, ent->model, sizeof(damageModel) ); damageModel[len] = 0; //chop extension strncpy( chunkModel, damageModel, sizeof(chunkModel)); strncpy( useModel, damageModel, sizeof(useModel)); if (ent->takedamage) { //Dead/damaged model if( !(ent->spawnflags & 8) ) { //no dmodel strcat( damageModel, "_d1.md3" ); ent->s.modelindex2 = G_ModelIndex( damageModel ); } //Chunk model strcat( chunkModel, "_c1.md3" ); ent->s.modelindex3 = G_ModelIndex( chunkModel ); } //Use model if( ent->spawnflags & 32 ) { //has umodel strcat( useModel, "_u1.md3" ); ent->sound1to2 = G_ModelIndex( useModel ); } if ( !ent->mins[0] && !ent->mins[1] && !ent->mins[2] ) { VectorSet (ent->mins, -16, -16, -16); } if ( !ent->maxs[0] && !ent->maxs[1] && !ent->maxs[2] ) { VectorSet (ent->maxs, 16, 16, 16); } // Scale up the tie-bomber bbox a little. if ( ent->model && Q_stricmp( "models/map_objects/ships/tie_bomber.md3", ent->model ) == 0 ) { VectorSet (ent->mins, -80, -80, -80); VectorSet (ent->maxs, 80, 80, 80); //ent->s.modelScale[ 0 ] = ent->s.modelScale[ 1 ] = ent->s.modelScale[ 2 ] *= 2.0f; //bHasScale = qtrue; } if (bHasScale) { //scale the x axis of the bbox up. ent->maxs[0] *= ent->s.modelScale[0];//*scaleFactor; ent->mins[0] *= ent->s.modelScale[0];//*scaleFactor; //scale the y axis of the bbox up. ent->maxs[1] *= ent->s.modelScale[1];//*scaleFactor; ent->mins[1] *= ent->s.modelScale[1];//*scaleFactor; //scale the z axis of the bbox up and adjust origin accordingly ent->maxs[2] *= ent->s.modelScale[2]; float oldMins2 = ent->mins[2]; ent->mins[2] *= ent->s.modelScale[2]; ent->s.origin[2] += (oldMins2-ent->mins[2]); } if ( ent->spawnflags & 2 ) { ent->s.eFlags |= EF_ANIM_ALLFAST; } G_SetOrigin( ent, ent->s.origin ); G_SetAngles( ent, ent->s.angles ); gi.linkentity (ent); if ( ent->spawnflags & 128 ) {//Can be used by the player's BUTTON_USE ent->svFlags |= SVF_PLAYER_USABLE; } if ( ent->team && ent->team[0] ) { ent->noDamageTeam = (team_t)GetIDForString( TeamTable, ent->team ); if ( ent->noDamageTeam == TEAM_FREE ) { G_Error("team name %s not recognized\n", ent->team); } } ent->team = NULL; //HACK if ( ent->model && Q_stricmp( "models/map_objects/ships/x_wing_nogear.md3", ent->model ) == 0 ) { if( ent->splashDamage > 0 && ent->splashRadius > 0 ) { ent->s.loopSound = G_SoundIndex( "sound/vehicles/x-wing/loop.wav" ); ent->s.eFlags |= EF_LESS_ATTEN; } } else if ( ent->model && Q_stricmp( "models/map_objects/ships/tie_fighter.md3", ent->model ) == 0 ) {//run a think G_EffectIndex( "explosions/fighter_explosion2" ); G_SoundIndex( "sound/weapons/tie_fighter/tiepass1.wav" ); /* G_SoundIndex( "sound/weapons/tie_fighter/tiepass2.wav" ); G_SoundIndex( "sound/weapons/tie_fighter/tiepass3.wav" ); G_SoundIndex( "sound/weapons/tie_fighter/tiepass4.wav" ); G_SoundIndex( "sound/weapons/tie_fighter/tiepass5.wav" );*/ G_SoundIndex( "sound/weapons/tie_fighter/tie_fire.wav" ); /* G_SoundIndex( "sound/weapons/tie_fighter/tie_fire2.wav" ); G_SoundIndex( "sound/weapons/tie_fighter/tie_fire3.wav" );*/ G_SoundIndex( "sound/weapons/tie_fighter/TIEexplode.wav" ); RegisterItem( FindItemForWeapon( WP_TIE_FIGHTER )); ent->s.eFlags |= EF_LESS_ATTEN; if( ent->splashDamage > 0 && ent->splashRadius > 0 ) { ent->s.loopSound = G_SoundIndex( "sound/vehicles/tie-bomber/loop.wav" ); //ent->e_ThinkFunc = thinkF_TieFighterThink; //ent->e_UseFunc = thinkF_TieFighterThink; //ent->nextthink = level.time + FRAMETIME; ent->e_UseFunc = useF_TieFighterUse; // Yeah, I could have just made this value changable from the editor, but I // need it immediately! float light; vec3_t color; qboolean lightSet, colorSet; // if the "color" or "light" keys are set, setup constantLight lightSet = qtrue;//G_SpawnFloat( "light", "100", &light ); light = 255; //colorSet = "1 1 1"//G_SpawnVector( "color", "1 1 1", color ); colorSet = qtrue; color[0] = 1; color[1] = 1; color[2] = 1; if ( lightSet || colorSet ) { int r, g, b, i; r = color[0] * 255; if ( r > 255 ) { r = 255; } g = color[1] * 255; if ( g > 255 ) { g = 255; } b = color[2] * 255; if ( b > 255 ) { b = 255; } i = light / 4; if ( i > 255 ) { i = 255; } ent->s.constantLight = r | ( g << 8 ) | ( b << 16 ) | ( i << 24 ); } } } else if ( ent->model && Q_stricmp( "models/map_objects/ships/tie_bomber.md3", ent->model ) == 0 ) { G_EffectIndex( "ships/tiebomber_bomb_falling" ); G_EffectIndex( "ships/tiebomber_explosion2" ); G_EffectIndex( "explosions/fighter_explosion2" ); G_SoundIndex( "sound/weapons/tie_fighter/TIEexplode.wav" ); ent->e_ThinkFunc = thinkF_TieBomberThink; ent->nextthink = level.time + FRAMETIME; ent->attackDebounceTime = level.time + 1000; // We only take damage from a heavy weapon class missiles. ent->flags |= FL_DMG_BY_HEAVY_WEAP_ONLY; ent->s.loopSound = G_SoundIndex( "sound/vehicles/tie-bomber/loop.wav" ); ent->s.eFlags |= EF_LESS_ATTEN; } float grav = 0; G_SpawnFloat( "gravity", "0", &grav ); if ( grav ) {//affected by gravity G_SetAngles( ent, ent->s.angles ); G_SetOrigin( ent, ent->currentOrigin ); G_SpawnString( "throwtarget", NULL, &ent->target4 ); // used to throw itself at something misc_model_breakable_gravity_init( ent, qtrue ); } // Start off. if ( ent->spawnflags & 4096 ) { ent->spawnContents = ent->contents; // It Navs can temporarly turn it "on" ent->s.solid = 0; ent->contents = 0; ent->clipmask = 0; ent->svFlags |= SVF_NOCLIENT; ent->s.eFlags |= EF_NODRAW; ent->count = 0; } int forceVisible = 0; G_SpawnInt( "forcevisible", "0", &forceVisible ); if ( forceVisible ) {//can see these through walls with force sight, so must be broadcast //ent->svFlags |= SVF_BROADCAST; ent->s.eFlags |= EF_FORCE_VISIBLE; } int redCrosshair = 0; G_SpawnInt( "redCrosshair", "0", &redCrosshair ); if ( redCrosshair ) {//can see these through walls with force sight, so must be broadcast ent->flags |= FL_RED_CROSSHAIR; } }
/* ================= ConsoleCommand // these are added in cg_main, CG_Init so they tab-complete ================= */ qboolean ConsoleCommand( void ) { char *cmd; cmd = gi.argv(0); if ( Q_stricmp (cmd, "entitylist") == 0 ) { Svcmd_EntityList_f(); return qtrue; } if (Q_stricmp (cmd, "game_memory") == 0) { Svcmd_GameMem_f(); return qtrue; } // if (Q_stricmp (cmd, "addbot") == 0) { // Svcmd_AddBot_f(); // return qtrue; // } if (Q_stricmp (cmd, "nav") == 0) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_Nav_f (); return qtrue; } if (Q_stricmp (cmd, "npc") == 0) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_NPC_f (); return qtrue; } if (Q_stricmp (cmd, "use") == 0) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_Use_f (); return qtrue; } if ( Q_stricmp( cmd, "ICARUS" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Quake3Game()->Svcmd(); return qtrue; } if ( Q_stricmp( cmd, "saberColor" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_SaberColor_f(); return qtrue; } if ( Q_stricmp( cmd, "saber" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_Saber_f(); return qtrue; } if ( Q_stricmp( cmd, "saberblade" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_SaberBlade_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceJump" ) == 0 ) { Svcmd_ForceJump_f(); return qtrue; } if ( Q_stricmp( cmd, "setSaberThrow" ) == 0 ) { Svcmd_SaberThrow_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceHeal" ) == 0 ) { Svcmd_ForceHeal_f(); return qtrue; } if ( Q_stricmp( cmd, "setForcePush" ) == 0 ) { Svcmd_ForcePush_f(); return qtrue; } if ( Q_stricmp( cmd, "setForcePull" ) == 0 ) { Svcmd_ForcePull_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceSpeed" ) == 0 ) { Svcmd_ForceSpeed_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceGrip" ) == 0 ) { Svcmd_ForceGrip_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceLightning" ) == 0 ) { Svcmd_ForceLightning_f(); return qtrue; } if ( Q_stricmp( cmd, "setMindTrick" ) == 0 ) { Svcmd_MindTrick_f(); return qtrue; } if ( Q_stricmp( cmd, "setSaberDefense" ) == 0 ) { Svcmd_SaberDefense_f(); return qtrue; } if ( Q_stricmp( cmd, "setSaberOffense" ) == 0 ) { Svcmd_SaberOffense_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceRage" ) == 0 ) { Svcmd_ForceSetLevel_f( FP_RAGE ); return qtrue; } if ( Q_stricmp( cmd, "setForceDrain" ) == 0 ) { Svcmd_ForceSetLevel_f( FP_DRAIN ); return qtrue; } if ( Q_stricmp( cmd, "setForceProtect" ) == 0 ) { Svcmd_ForceSetLevel_f( FP_PROTECT ); return qtrue; } if ( Q_stricmp( cmd, "setForceAbsorb" ) == 0 ) { Svcmd_ForceSetLevel_f( FP_ABSORB ); return qtrue; } if ( Q_stricmp( cmd, "setForceSight" ) == 0 ) { Svcmd_ForceSetLevel_f( FP_SEE ); return qtrue; } if ( Q_stricmp( cmd, "setForceAll" ) == 0 ) { Svcmd_ForceJump_f(); Svcmd_SaberThrow_f(); Svcmd_ForceHeal_f(); Svcmd_ForcePush_f(); Svcmd_ForcePull_f(); Svcmd_ForceSpeed_f(); Svcmd_ForceGrip_f(); Svcmd_ForceLightning_f(); Svcmd_MindTrick_f(); Svcmd_SaberDefense_f(); Svcmd_SaberOffense_f(); Svcmd_ForceSetLevel_f( FP_RAGE ); Svcmd_ForceSetLevel_f( FP_DRAIN ); Svcmd_ForceSetLevel_f( FP_PROTECT ); Svcmd_ForceSetLevel_f( FP_ABSORB ); Svcmd_ForceSetLevel_f( FP_SEE ); for ( int i = SS_FAST; i < SS_NUM_SABER_STYLES; i++ ) { g_entities[0].client->ps.saberStylesKnown |= (1<<i); } return qtrue; } if ( Q_stricmp( cmd, "saberAttackCycle" ) == 0 ) { Svcmd_SaberAttackCycle_f(); return qtrue; } if ( Q_stricmp( cmd, "runscript" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } char *cmd2 = gi.argv(1); if ( cmd2 && cmd2[0] ) { char *cmd3 = gi.argv(2); if ( cmd3 && cmd3[0] ) { gentity_t *found = NULL; if ( (found = G_Find(NULL, FOFS(targetname), cmd2 ) ) != NULL ) { Quake3Game()->RunScript( found, cmd3 ); } else { //can't find cmd2 gi.Printf( S_COLOR_RED"runscript: can't find targetname %s\n", cmd2 ); } } else { Quake3Game()->RunScript( &g_entities[0], cmd2 ); } } else { gi.Printf( S_COLOR_RED"usage: runscript <ent targetname> scriptname\n" ); } //FIXME: else warning return qtrue; } if ( Q_stricmp( cmd, "playerteam" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } char *cmd2 = gi.argv(1); int n; if ( !*cmd2 || !cmd2[0] ) { gi.Printf( S_COLOR_RED"'playerteam' - change player team, requires a team name!\n" ); gi.Printf( S_COLOR_RED"Valid team names are:\n"); for ( n = (TEAM_FREE + 1); n < TEAM_NUM_TEAMS; n++ ) { gi.Printf( S_COLOR_RED"%s\n", GetStringForID( TeamTable, n ) ); } } else { team_t team; team = (team_t)GetIDForString( TeamTable, cmd2 ); if ( team == -1 ) { gi.Printf( S_COLOR_RED"'playerteam' unrecognized team name %s!\n", cmd2 ); gi.Printf( S_COLOR_RED"Valid team names are:\n"); for ( n = TEAM_FREE; n < TEAM_NUM_TEAMS; n++ ) { gi.Printf( S_COLOR_RED"%s\n", GetStringForID( TeamTable, n ) ); } } else { g_entities[0].client->playerTeam = team; //FIXME: convert Imperial, Malon, Hirogen and Klingon to Scavenger? } } return qtrue; } if ( Q_stricmp( cmd, "control" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } char *cmd2 = gi.argv(1); if ( !*cmd2 || !cmd2[0] ) { if ( !G_ClearViewEntity( &g_entities[0] ) ) { gi.Printf( S_COLOR_RED"control <NPC_targetname>\n", cmd2 ); } } else { Q3_SetViewEntity( 0, cmd2 ); } return qtrue; } if ( Q_stricmp( cmd, "grab" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } char *cmd2 = gi.argv(1); if ( !*cmd2 || !cmd2[0] ) { if ( !G_ReleaseEntity( &g_entities[0] ) ) { gi.Printf( S_COLOR_RED"grab <NPC_targetname>\n", cmd2 ); } } else { G_GrabEntity( &g_entities[0], cmd2 ); } return qtrue; } if ( Q_stricmp( cmd, "knockdown" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } G_Knockdown( &g_entities[0], &g_entities[0], vec3_origin, 300, qtrue ); return qtrue; } if ( Q_stricmp( cmd, "playerModel" ) == 0 ) { if ( gi.argc() == 1 ) { gi.Printf( S_COLOR_RED"USAGE: playerModel <NPC Name>\n playerModel <g2model> <skinhead> <skintorso> <skinlower>\n playerModel player (builds player from customized menu settings)\n" ); gi.Printf( "playerModel = %s ", va("%s %s %s %s\n", g_char_model->string, g_char_skin_head->string, g_char_skin_torso->string, g_char_skin_legs->string ) ); } else if ( gi.argc() == 2 ) { G_ChangePlayerModel( &g_entities[0], gi.argv(1) ); } else if ( gi.argc() == 5 ) { //instead of setting it directly via a command, we now store it in cvars //G_ChangePlayerModel( &g_entities[0], va("%s|%s|%s|%s", gi.argv(1), gi.argv(2), gi.argv(3), gi.argv(4)) ); gi.cvar_set("g_char_model", gi.argv(1) ); gi.cvar_set("g_char_skin_head", gi.argv(2) ); gi.cvar_set("g_char_skin_torso", gi.argv(3) ); gi.cvar_set("g_char_skin_legs", gi.argv(4) ); G_InitPlayerFromCvars( &g_entities[0] ); } return qtrue; } if ( Q_stricmp( cmd, "playerTint" ) == 0 ) { if ( gi.argc() == 4 ) { g_entities[0].client->renderInfo.customRGBA[0] = atoi(gi.argv(1)); g_entities[0].client->renderInfo.customRGBA[1] = atoi(gi.argv(2)); g_entities[0].client->renderInfo.customRGBA[2] = atoi(gi.argv(3)); gi.cvar_set("g_char_color_red", gi.argv(1) ); gi.cvar_set("g_char_color_green", gi.argv(2) ); gi.cvar_set("g_char_color_blue", gi.argv(3) ); } else { gi.Printf( S_COLOR_RED"USAGE: playerTint <red 0 - 255> <green 0 - 255> <blue 0 - 255>\n" ); gi.Printf( "playerTint = %s\n", va("%d %d %d", g_char_color_red->integer, g_char_color_green->integer, g_char_color_blue->integer ) ); } return qtrue; } if ( Q_stricmp( cmd, "nexttestaxes" ) == 0 ) { G_NextTestAxes(); } if ( Q_stricmp( cmd, "exitview" ) == 0 ) { Svcmd_ExitView_f(); } if (Q_stricmp (cmd, "iknowkungfu") == 0) { gi.cvar_set( "g_debugMelee", "1" ); G_SetWeapon( &g_entities[0], WP_MELEE ); /* for ( int i = FP_FIRST; i < NUM_FORCE_POWERS; i++ ) { g_entities[0].client->ps.forcePowersKnown |= ( 1 << i ); if ( i == FP_TELEPATHY ) { g_entities[0].client->ps.forcePowerLevel[i] = FORCE_LEVEL_4; } else { g_entities[0].client->ps.forcePowerLevel[i] = FORCE_LEVEL_3; } } */ } return qfalse; }
/* ================= ClientCommand ================= */ void ClientCommand( int clientNum ) { gentity_t *ent; const char *cmd; ent = g_entities + clientNum; if ( !ent->client ) { return; // not fully in game yet } cmd = gi.argv(0); if (Q_stricmp (cmd, "spawn") == 0) { Cmd_Spawn( ent ); return; } if (Q_stricmp (cmd, "give") == 0) Cmd_Give_f (ent); else if (Q_stricmp (cmd, "god") == 0) Cmd_God_f (ent); else if (Q_stricmp (cmd, "undying") == 0) Cmd_Undying_f (ent); else if (Q_stricmp (cmd, "notarget") == 0) Cmd_Notarget_f (ent); else if (Q_stricmp (cmd, "noclip") == 0) { Cmd_Noclip_f (ent); } else if (Q_stricmp (cmd, "kill") == 0) { if ( !CheatsOk( ent ) ) { return; } Cmd_Kill_f (ent); } else if (Q_stricmp (cmd, "levelshot") == 0) Cmd_LevelShot_f (ent); else if (Q_stricmp (cmd, "where") == 0) Cmd_Where_f (ent); else if (Q_stricmp (cmd, "setviewpos") == 0) Cmd_SetViewpos_f( ent ); else if (Q_stricmp (cmd, "setobjective") == 0) Cmd_SetObjective_f( ent ); else if (Q_stricmp (cmd, "viewobjective") == 0) Cmd_ViewObjective_f( ent ); else if (Q_stricmp (cmd, "force_throw") == 0) { ent = G_GetSelfForPlayerCmd(); ForceThrow( ent, qfalse ); } else if (Q_stricmp (cmd, "force_pull") == 0) { ent = G_GetSelfForPlayerCmd(); ForceThrow( ent, qtrue ); } else if (Q_stricmp (cmd, "force_speed") == 0) { ent = G_GetSelfForPlayerCmd(); ForceSpeed( ent ); } else if (Q_stricmp (cmd, "force_heal") == 0) { ent = G_GetSelfForPlayerCmd(); ForceHeal( ent ); } else if (Q_stricmp (cmd, "force_grip") == 0) { ent = G_GetSelfForPlayerCmd(); ForceGrip( ent ); } else if (Q_stricmp (cmd, "force_distract") == 0) { ent = G_GetSelfForPlayerCmd(); ForceTelepathy( ent ); } else if (Q_stricmp (cmd, "force_rage") == 0) { ent = G_GetSelfForPlayerCmd(); ForceRage(ent); } else if (Q_stricmp (cmd, "force_protect") == 0) { ent = G_GetSelfForPlayerCmd(); ForceProtect(ent); } else if (Q_stricmp (cmd, "force_absorb") == 0) { ent = G_GetSelfForPlayerCmd(); ForceAbsorb(ent); } else if (Q_stricmp (cmd, "force_sight") == 0) { ent = G_GetSelfForPlayerCmd(); ForceSeeing(ent); } else if (Q_stricmp (cmd, "addsaberstyle") == 0) { ent = G_GetSelfForPlayerCmd(); if ( !ent || !ent->client ) {//wtf? return; } if ( gi.argc() < 2 ) { gi.SendServerCommand( ent-g_entities, va("print \"usage: addsaberstyle <saber style>\n\"")); gi.SendServerCommand( ent-g_entities, va("print \"Valid styles: SS_FAST, SS_MEDIUM, SS_STRONG, SS_DESANN, SS_TAVION, SS_DUAL and SS_STAFF\n\"")); return; } int addStyle = GetIDForString( SaberStyleTable, gi.argv(1) ); if ( addStyle > SS_NONE && addStyle < SS_STAFF ) { ent->client->ps.saberStylesKnown |= (1<<addStyle); } } else if (Q_stricmp (cmd, "setsaberstyle") == 0) { ent = G_GetSelfForPlayerCmd(); if ( !ent || !ent->client ) {//wtf? return; } if ( gi.argc() < 2 ) { gi.SendServerCommand( ent-g_entities, va("print \"usage: setsaberstyle <saber style>\n\"")); gi.SendServerCommand( ent-g_entities, va("print \"Valid styles: SS_FAST, SS_MEDIUM, SS_STRONG, SS_DESANN, SS_TAVION, SS_DUAL and SS_STAFF\n\"")); return; } int setStyle = GetIDForString( SaberStyleTable, gi.argv(1) ); if ( setStyle > SS_NONE && setStyle < SS_STAFF ) { ent->client->ps.saberStylesKnown = (1<<setStyle); cg.saberAnimLevelPending = ent->client->ps.saberAnimLevel = setStyle; } } else if (Q_stricmp (cmd, "taunt") == 0) { ent = G_GetSelfForPlayerCmd(); // G_Taunt( ent ); G_SetTauntAnim( ent, TAUNT_TAUNT ); } else if (Q_stricmp (cmd, "bow") == 0) { ent = G_GetSelfForPlayerCmd(); G_SetTauntAnim( ent, TAUNT_BOW ); } else if (Q_stricmp (cmd, "meditate") == 0) { ent = G_GetSelfForPlayerCmd(); G_SetTauntAnim( ent, TAUNT_MEDITATE ); } else if (Q_stricmp (cmd, "flourish") == 0) { ent = G_GetSelfForPlayerCmd(); G_SetTauntAnim( ent, TAUNT_FLOURISH ); } else if (Q_stricmp (cmd, "gloat") == 0) { ent = G_GetSelfForPlayerCmd(); G_SetTauntAnim( ent, TAUNT_GLOAT ); } /* else if (Q_stricmp (cmd, "drive") == 0) { if ( !CheatsOk( ent ) ) { return; } if ( gi.argc() < 2 ) { gi.SendServerCommand( ent-g_entities, va("print \"usage: drive <vehicle name>\n\"")); gi.SendServerCommand( ent-g_entities, va("print \"Vehicles will be in vehicles.cfg, try using 'speeder' for now\n\"")); return; } G_DriveVehicle( ent, NULL, gi.argv(1) ); } */ else if (Q_stricmp (cmd, "NPCdrive") == 0) { if ( !CheatsOk( ent ) ) { return; } if ( gi.argc() < 3 ) { gi.SendServerCommand( ent-g_entities, va("print \"usage: drive <NPC_targetname> <vehicle name>\n\"")); gi.SendServerCommand( ent-g_entities, va("print \"Vehicles will be in vehicles.cfg, try using 'speeder' for now\n\"")); return; } gentity_t *found = G_Find( NULL, FOFS(targetname), gi.argv(1) ); if ( found && found->health > 0 && found->client ) { // TEMPORARY! BRING BACK LATER!!! //G_DriveVehicle( found, NULL, gi.argv(2) ); } } else if (Q_stricmp (cmd, "thereisnospoon") == 0) G_StartMatrixEffect( ent ); else if (Q_stricmp (cmd, "use_electrobinoculars") == 0) Cmd_UseElectrobinoculars_f( ent ); else if (Q_stricmp (cmd, "use_bacta") == 0) Cmd_UseBacta_f( ent ); else if (Q_stricmp (cmd, "use_seeker") == 0) Cmd_UseSeeker_f( ent ); else if (Q_stricmp (cmd, "use_lightamp_goggles") == 0) Cmd_UseGoggles_f( ent ); else if (Q_stricmp (cmd, "use_sentry") == 0) Cmd_UseSentry_f( ent ); else if (Q_stricmp (cmd, "fx") == 0) Cmd_Fx( ent ); else if (Q_stricmp (cmd, "invuse") == 0) { Cmd_UseInventory_f( ent ); } else if (Q_stricmp (cmd, "playmusic") == 0) { const char *cmd2 = gi.argv(1); if ( cmd2 ) { gi.SetConfigstring( CS_MUSIC, cmd2 ); } } else if (Q_stricmp (cmd, "flushcam") == 0) { Cmd_FlushCamFile_f( ent ); } else if ( Q_stricmp( cmd, "dropsaber" ) == 0 ) { const char *cmd2 = gi.argv(1); int saberNum = 2;//by default, drop both if ( cmd2 && cmd2[0] ) { saberNum = atoi(cmd2); } if ( saberNum > 1 ) {//drop both Cmd_SaberDrop_f( ent, 1 ); Cmd_SaberDrop_f( ent, 0 ); } else {//drop either left or right Cmd_SaberDrop_f( ent, saberNum ); } } else { gi.SendServerCommand( clientNum, va("print \"Unknown command %s\n\"", cmd ) ); } }
static qboolean BG_ParseWeaponFile ( const char *weaponFilePath ) { cJSON *json = NULL; cJSON *jsonNode = NULL; char error[MAX_STRING_CHARS]; const char *str = NULL; int weapon; int i; char weaponFileData[MAX_WEAPON_FILE_LENGTH]; fileHandle_t f; int fileLen = strap_FS_FOpenFile (weaponFilePath, &f, FS_READ); weaponData_t weaponData; fmLoadCounter = 0; if ( !f || fileLen == -1 ) { Com_Printf (S_COLOR_RED "%s: failed to read the weapon file. File is unreadable or is empty.\n", weaponFilePath); return qfalse; } if ( (fileLen + 1) >= MAX_WEAPON_FILE_LENGTH ) { trap_FS_FCloseFile (f); Com_Printf (S_COLOR_RED "%s: file too big (%d bytes, maximum is %d).\n", weaponFilePath, fileLen, MAX_WEAPON_FILE_LENGTH - 1); return qfalse; } strap_FS_Read (&weaponFileData, fileLen, f); weaponFileData[fileLen] = '\0'; strap_FS_FCloseFile (f); json = cJSON_ParsePooled (weaponFileData, error, sizeof (error)); if ( json == NULL ) { Com_Printf (S_COLOR_RED "%s: %s\n", weaponFilePath, error); return qfalse; } BG_InitializeWeaponData (&weaponData); ReadString (json, "classname", weaponData.classname, sizeof (weaponData.classname)); jsonNode = cJSON_GetObjectItem (json, "type"); str = cJSON_ToString (jsonNode); weapon = GetIDForString (WPTable, str); weaponData.weaponBaseIndex = weapon; jsonNode = cJSON_GetObjectItem (json, "variation"); weapon = cJSON_ToNumber (jsonNode); weaponData.weaponModIndex = weapon; jsonNode = cJSON_GetObjectItem (json, "stats"); BG_ParseWeaponStats (&weaponData, jsonNode); weaponData.numFiringModes = 0; for(i = 0; i < MAX_FIREMODES; i++) { jsonNode = cJSON_GetObjectItem (json, va("firemode%i", i)); if(jsonNode != NULL) { BG_ParseWeaponFireMode (&weaponData.firemodes[i], jsonNode); weaponData.numFiringModes++; } } // Old stuff for when we had primary/alt attacks --eez /*jsonNode = cJSON_GetObjectItem (json, "primaryattack"); BG_ParseWeaponFireMode (&weaponData.firemodes[0], jsonNode); jsonNode = cJSON_GetObjectItem (json, "secondaryattack"); if ( jsonNode != NULL ) { weaponData.hasSecondary = 1; BG_ParseWeaponFireMode (&weaponData.firemodes[1], jsonNode); }*/ jsonNode = cJSON_GetObjectItem (json, "playeranims"); BG_ParseWeaponPlayerAnimations (&weaponData, jsonNode); jsonNode = cJSON_GetObjectItem (json, "name"); str = cJSON_ToString (jsonNode); Q_strncpyz (weaponData.displayName, str, sizeof (weaponData.displayName)); #ifdef CGAME // TODO: Maybe we can turn this into a loop somehow? It's just turning into a stupidly long list. jsonNode = cJSON_GetObjectItem (json, "weaponanims"); // TODO jsonNode = cJSON_GetObjectItem (json, "description"); str = cJSON_ToString (jsonNode); Q_strncpyz (weaponData.visuals.description, str, sizeof (weaponData.visuals.description)); jsonNode = cJSON_GetObjectItem (json, "visual"); BG_ParseVisuals (&weaponData, jsonNode); #endif /*if ( weaponData.zoomType != ZOOM_NONE ) { // If we have zoom mode, then copy over the data from the primary to the secondary // so it's as if we haven't changed fire modes at all! Ingenious! (And also temporary) weaponData.firemodes[1] = weaponData.firemodes[0]; }*/ BG_AddWeaponData (&weaponData); cJSON_Delete (json); return qtrue; }
static void BG_ParseWeaponFireMode ( weaponFireModeStats_t *fireModeStats, cJSON *fireModeNode ) { cJSON *node; const char *str = NULL; if ( fireModeNode == NULL ) { return; } node = cJSON_GetObjectItem (fireModeNode, "ammo"); str = cJSON_ToString (node); if ( str && str[0] ) { fireModeStats->ammo = BG_GetAmmo (str); } node = cJSON_GetObjectItem (fireModeNode, "damage"); #ifdef QAGAME BG_ParseDamage (fireModeStats, node, qfalse); node = cJSON_GetObjectItem (fireModeNode, "secondarydamage"); BG_ParseDamage (fireModeStats, node, qtrue); #else fireModeStats->baseDamage = cJSON_ToInteger (node); #endif node = cJSON_GetObjectItem (fireModeNode, "grenade"); fireModeStats->isGrenade = (qboolean)cJSON_ToBooleanOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "grenadeBounces"); fireModeStats->grenadeBounces = (qboolean)cJSON_ToBooleanOpt (node, 1); node = cJSON_GetObjectItem (fireModeNode, "grenadeBounceDMG"); fireModeStats->grenadeBounceDMG = (char)cJSON_ToIntegerOpt (node, 10); node = cJSON_GetObjectItem (fireModeNode, "ballistic"); fireModeStats->applyGravity = (char)cJSON_ToBooleanOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "bounces"); fireModeStats->bounceCount = (char)cJSON_ToIntegerOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "hitscan"); fireModeStats->hitscan = (char)cJSON_ToBooleanOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "projectiles"); fireModeStats->shotCount = (char)cJSON_ToIntegerOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "collisionsize"); fireModeStats->boxSize = (float)cJSON_ToNumberOpt (node, 0.0); node = cJSON_GetObjectItem (fireModeNode, "maxchargetime"); fireModeStats->chargeMaximum = (short)cJSON_ToIntegerOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "chargedamage"); fireModeStats->chargeMultiplier = (float)cJSON_ToNumberOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "chargedelay"); fireModeStats->chargeTime = (short)cJSON_ToIntegerOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "ammocost"); fireModeStats->cost = (char)cJSON_ToIntegerOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "firingtype"); BG_ParseFireModeFiringType (fireModeStats, cJSON_ToStringOpt (node, "auto")); // 0 means fully automatic, otherwise one burst will fire weapon n times. node = cJSON_GetObjectItem (fireModeNode, "shotsperburst"); fireModeStats->shotsPerBurst = (char)cJSON_ToIntegerOpt (node, 0); // 0 means infinite delay (semi-automatic), otherwise n milliseconds between // rounds in a burst. node = cJSON_GetObjectItem (fireModeNode, "burstshotdelay"); fireModeStats->burstFireDelay = (short)cJSON_ToIntegerOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "firedelay"); fireModeStats->delay = (short)cJSON_ToIntegerOpt (node, 0); node = cJSON_GetObjectItem (fireModeNode, "range"); fireModeStats->range = (float)cJSON_ToIntegerOpt (node, WPR_M); node = cJSON_GetObjectItem (fireModeNode, "splashrange"); fireModeStats->rangeSplash = (float)cJSON_ToNumberOpt (node, 0.0); node = cJSON_GetObjectItem (fireModeNode, "recoil"); fireModeStats->recoil = (float)cJSON_ToNumberOpt (node, 0.0); //node = cJSON_GetObjectItem (fireModeNode, "spread"); //fireModeStats->spread = (float)cJSON_ToNumberOpt (node, 0.0); node = cJSON_GetObjectItem (fireModeNode, "accuracy"); if( node ) { cJSON *child = NULL; child = cJSON_GetObjectItem( node, "accuracyRating" ); fireModeStats->weaponAccuracy.accuracyRating = (vec_t)cJSON_ToNumberOpt( child, 32.0f ); child = cJSON_GetObjectItem( node, "crouchModifier" ); fireModeStats->weaponAccuracy.crouchModifier = (float)cJSON_ToNumberOpt( child, 0.8f ); child = cJSON_GetObjectItem( node, "runModifier" ); fireModeStats->weaponAccuracy.runModifier = (float)cJSON_ToNumberOpt( child, 2.0f ); child = cJSON_GetObjectItem( node, "sightsModifier" ); fireModeStats->weaponAccuracy.sightsModifier = (float)cJSON_ToNumberOpt( child, 0.2f ); child = cJSON_GetObjectItem( node, "walkModifier" ); fireModeStats->weaponAccuracy.walkModifier = (float)cJSON_ToNumberOpt( child, 1.55f ); child = cJSON_GetObjectItem( node, "inAirModifier" ); fireModeStats->weaponAccuracy.inAirModifier = (float)cJSON_ToNumberOpt( child, 3.0f ); child = cJSON_GetObjectItem( node, "accuracyRatingPerShot" ); fireModeStats->weaponAccuracy.accuracyRatingPerShot = (int)cJSON_ToNumberOpt( child, 2 ); child = cJSON_GetObjectItem( node, "msToDrainAccuracy" ); fireModeStats->weaponAccuracy.msToDrainAccuracy = (int)cJSON_ToNumberOpt( child, 200 ); child = cJSON_GetObjectItem( node, "maxAccuracyAdd" ); fireModeStats->weaponAccuracy.maxAccuracyAdd = (int)cJSON_ToNumberOpt( child, 128 ); } else { fireModeStats->weaponAccuracy.accuracyRating = 32.0f; fireModeStats->weaponAccuracy.crouchModifier = 0.8f; fireModeStats->weaponAccuracy.runModifier = 2.0f; fireModeStats->weaponAccuracy.sightsModifier = 0.2f; fireModeStats->weaponAccuracy.walkModifier = 1.55f; fireModeStats->weaponAccuracy.inAirModifier = 3.0f; fireModeStats->weaponAccuracy.accuracyRatingPerShot = 2; fireModeStats->weaponAccuracy.msToDrainAccuracy = 200; fireModeStats->weaponAccuracy.maxAccuracyAdd = 128; } node = cJSON_GetObjectItem (fireModeNode, "projectilespeed"); fireModeStats->speed = (float)cJSON_ToNumberOpt (node, 0.0); node = cJSON_GetObjectItem (fireModeNode, "projectileclass"); str = cJSON_ToStringOpt (node, "unknown_proj"); Q_strncpyz (fireModeStats->weaponClass, str, sizeof (fireModeStats->weaponClass)); node = cJSON_GetObjectItem (fireModeNode, "meansofdeath"); str = cJSON_ToStringOpt (node, "MOD_UNKNOWN"); fireModeStats->weaponMOD = GetIDForString (MODTable, str); node = cJSON_GetObjectItem (fireModeNode, "splashmeansofdeath"); str = cJSON_ToStringOpt (node, "MOD_UNKNOWN"); fireModeStats->weaponSplashMOD = GetIDForString (MODTable, str); }
qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) { const char *token; const char *value; const char *p; char useSaber[1024]; float f; int n; qboolean triedDefault = qfalse; if ( !saber ) { return qfalse; } //Set defaults so that, if it fails, there's at least something there WP_SaberSetDefaults( saber ); if ( !SaberName || !SaberName[0] ) { strcpy(useSaber, DEFAULT_SABER); //default triedDefault = qtrue; } else { strcpy(useSaber, SaberName); } //try to parse it out p = SaberParms; COM_BeginParseSession("saberinfo"); // look for the right saber while ( p ) { token = COM_ParseExt( &p, qtrue ); if ( token[0] == 0 ) { if (!triedDefault) { //fall back to default and restart, should always be there p = SaberParms; COM_BeginParseSession("saberinfo"); strcpy(useSaber, DEFAULT_SABER); triedDefault = qtrue; } else { return qfalse; } } if ( !Q_stricmp( token, useSaber ) ) { break; } SkipBracedSection( &p ); } if ( !p ) { //even the default saber isn't found? return qfalse; } //got the name we're using for sure strcpy(saber->name, useSaber); if ( BG_ParseLiteral( &p, "{" ) ) { return qfalse; } // parse the saber info block while ( 1 ) { token = COM_ParseExt( &p, qtrue ); if ( !token[0] ) { Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", useSaber ); return qfalse; } if ( !Q_stricmp( token, "}" ) ) { break; } //saber fullName if ( !Q_stricmp( token, "name" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } strcpy(saber->fullName, value); continue; } //saber type if ( !Q_stricmp( token, "saberType" ) ) { int saberType; if ( COM_ParseString( &p, &value ) ) { continue; } saberType = GetIDForString( SaberTable, value ); if ( saberType >= SABER_SINGLE && saberType <= NUM_SABERS ) { saber->type = (saberType_t)saberType; } continue; } //saber hilt if ( !Q_stricmp( token, "saberModel" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } strcpy(saber->model, value); continue; } if ( !Q_stricmp( token, "customSkin" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->skin = trap_R_RegisterSkin(value); continue; } //on sound if ( !Q_stricmp( token, "soundOn" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->soundOn = BG_SoundIndex( (char *)value ); continue; } //loop sound if ( !Q_stricmp( token, "soundLoop" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->soundLoop = BG_SoundIndex( (char *)value ); continue; } //off sound if ( !Q_stricmp( token, "soundOff" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->soundOff = BG_SoundIndex( (char *)value ); continue; } if ( !Q_stricmp( token, "numBlades" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 1 || n >= MAX_BLADES ) { Com_Error(ERR_DROP, "WP_SaberParseParms: saber %s has illegal number of blades (%d) max: %d", useSaber, n, MAX_BLADES ); continue; } saber->numBlades = n; continue; } // saberColor if ( !Q_stricmpn( token, "saberColor", 10 ) ) { if (strlen(token)==10) { n = -1; } else if (strlen(token)==11) { n = atoi(&token[10])-1; if (n > 7 || n < 1 ) { #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW"WARNING: bad saberColor '%s' in %s\n", token, useSaber ); #endif continue; } } else { #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW"WARNING: bad saberColor '%s' in %s\n", token, useSaber ); #endif continue; } if ( COM_ParseString( &p, &value ) ) //read the color { continue; } if (n==-1) {//NOTE: this fills in the rest of the blades with the same color by default saber_colors_t color = TranslateSaberColor( value ); for ( n = 0; n < MAX_BLADES; n++ ) { saber->blade[n].color = color; } } else { saber->blade[n].color = TranslateSaberColor( value ); } continue; } //saber length if ( !Q_stricmpn( token, "saberLength", 11 ) ) { if (strlen(token)==11) { n = -1; } else if (strlen(token)==12) { n = atoi(&token[11])-1; if (n > 7 || n < 1 ) { #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW"WARNING: bad saberLength '%s' in %s\n", token, useSaber ); #endif continue; } } else { #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW"WARNING: bad saberLength '%s' in %s\n", token, useSaber ); #endif continue; } if ( COM_ParseFloat( &p, &f ) ) { SkipRestOfLine( &p ); continue; } //cap if ( f < 4.0f ) { f = 4.0f; } if (n==-1) {//NOTE: this fills in the rest of the blades with the same length by default for ( n = 0; n < MAX_BLADES; n++ ) { saber->blade[n].lengthMax = f; } } else { saber->blade[n].lengthMax = f; } continue; } //blade radius if ( !Q_stricmpn( token, "saberRadius", 11 ) ) { if (strlen(token)==11) { n = -1; } else if (strlen(token)==12) { n = atoi(&token[11])-1; if (n > 7 || n < 1 ) { #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW"WARNING: bad saberRadius '%s' in %s\n", token, useSaber ); #endif continue; } } else { #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW"WARNING: bad saberRadius '%s' in %s\n", token, useSaber ); #endif continue; } if ( COM_ParseFloat( &p, &f ) ) { SkipRestOfLine( &p ); continue; } //cap if ( f < 0.25f ) { f = 0.25f; } if (n==-1) {//NOTE: this fills in the rest of the blades with the same length by default for ( n = 0; n < MAX_BLADES; n++ ) { saber->blade[n].radius = f; } } else { saber->blade[n].radius = f; } continue; } //locked saber style if ( !Q_stricmp( token, "saberStyle" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->style = TranslateSaberStyle( value ); continue; } //maxChain if ( !Q_stricmp( token, "maxChain" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->maxChain = n; continue; } //lockable if ( !Q_stricmp( token, "lockable" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->lockable = ((qboolean)(n!=0)); continue; } //throwable if ( !Q_stricmp( token, "throwable" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->throwable = ((qboolean)(n!=0)); continue; } //disarmable if ( !Q_stricmp( token, "disarmable" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->disarmable = ((qboolean)(n!=0)); continue; } //active blocking if ( !Q_stricmp( token, "blocking" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->activeBlocking = ((qboolean)(n!=0)); continue; } //twoHanded if ( !Q_stricmp( token, "twoHanded" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->twoHanded = ((qboolean)(n!=0)); continue; } //force power restrictions if ( !Q_stricmp( token, "forceRestrict" ) ) { int fp; if ( COM_ParseString( &p, &value ) ) { continue; } fp = GetIDForString( FPTable, value ); if ( fp >= FP_FIRST && fp < NUM_FORCE_POWERS ) { saber->forceRestrictions |= (1<<fp); } continue; } //lockBonus if ( !Q_stricmp( token, "lockBonus" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->lockBonus = n; continue; } //parryBonus if ( !Q_stricmp( token, "parryBonus" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->parryBonus = n; continue; } //breakParryBonus if ( !Q_stricmp( token, "breakParryBonus" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->breakParryBonus = n; continue; } //disarmBonus if ( !Q_stricmp( token, "disarmBonus" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->disarmBonus = n; continue; } //single blade saber style if ( !Q_stricmp( token, "singleBladeStyle" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->singleBladeStyle = TranslateSaberStyle( value ); continue; } //single blade throwable if ( !Q_stricmp( token, "singleBladeThrowable" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->singleBladeThrowable = ((qboolean)(n!=0)); continue; } //broken replacement saber1 (right hand) if ( !Q_stricmp( token, "brokenSaber1" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } //saber->brokenSaber1 = G_NewString( value ); continue; } //broken replacement saber2 (left hand) if ( !Q_stricmp( token, "brokenSaber2" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } //saber->brokenSaber2 = G_NewString( value ); continue; } //spins and does damage on return from saberthrow if ( !Q_stricmp( token, "returnDamage" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->returnDamage = ((qboolean)(n!=0)); continue; } //stops the saber from drawing marks on the world (good for real-sword type mods) if ( !Q_stricmp( token, "noWallMarks" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->noWallMarks = ((qboolean)(n!=0)); continue; } //stops the saber from drawing a dynamic light (good for real-sword type mods) if ( !Q_stricmp( token, "noDlight" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->noDlight = ((qboolean)(n!=0)); continue; } //stops the saber from drawing a blade (good for real-sword type mods) if ( !Q_stricmp( token, "noBlade" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->noBlade = ((qboolean)(n!=0)); continue; } //default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods) if ( !Q_stricmp( token, "trailStyle" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->trailStyle = n; continue; } //if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" if ( !Q_stricmp( token, "g2MarksShader" ) ) { if ( COM_ParseString( &p, &value ) ) { SkipRestOfLine( &p ); continue; } #ifdef QAGAME//cgame-only cares about this #elif defined CGAME saber->g2MarksShader = trap_R_RegisterShader( value ); #endif continue; } //if non-zero, uses damage done to calculate an appropriate amount of knockback if ( !Q_stricmp( token, "knockbackScale" ) ) { if ( COM_ParseFloat( &p, &f ) ) { SkipRestOfLine( &p ); continue; } saber->knockbackScale = f; continue; } //scale up or down the damage done by the saber if ( !Q_stricmp( token, "damageScale" ) ) { if ( COM_ParseFloat( &p, &f ) ) { SkipRestOfLine( &p ); continue; } saber->damageScale = f; continue; } //if non-zero, the saber never does dismemberment (good for pointed/blunt melee weapons) if ( !Q_stricmp( token, "noDismemberment" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->noDismemberment = ((qboolean)(n!=0)); continue; } //if non-zero, the saber will not do damage or any effects when it is idle (not in an attack anim). (good for real-sword type mods) if ( !Q_stricmp( token, "noIdleEffect" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->noIdleEffect = ((qboolean)(n!=0)); continue; } //spin sound (when thrown) if ( !Q_stricmp( token, "spinSound" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->spinSound = BG_SoundIndex( (char *)value ); continue; } //swing sound - NOTE: must provide all 3!!! if ( !Q_stricmp( token, "swingSound1" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->swingSound[0] = BG_SoundIndex( (char *)value ); continue; } //swing sound - NOTE: must provide all 3!!! if ( !Q_stricmp( token, "swingSound2" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->swingSound[1] = BG_SoundIndex( (char *)value ); continue; } //swing sound - NOTE: must provide all 3!!! if ( !Q_stricmp( token, "swingSound3" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->swingSound[2] = BG_SoundIndex( (char *)value ); continue; } //hit sound - NOTE: must provide all 3!!! if ( !Q_stricmp( token, "hitSound1" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->hitSound[0] = BG_SoundIndex( (char *)value ); continue; } //hit sound - NOTE: must provide all 3!!! if ( !Q_stricmp( token, "hitSound2" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->hitSound[1] = BG_SoundIndex( (char *)value ); continue; } //hit sound - NOTE: must provide all 3!!! if ( !Q_stricmp( token, "hitSound3" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->hitSound[2] = BG_SoundIndex( (char *)value ); continue; } //block sound - NOTE: must provide all 3!!! if ( !Q_stricmp( token, "blockSound1" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->blockSound[0] = BG_SoundIndex( (char *)value ); continue; } //block sound - NOTE: must provide all 3!!! if ( !Q_stricmp( token, "blockSound2" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->blockSound[1] = BG_SoundIndex( (char *)value ); continue; } //block sound - NOTE: must provide all 3!!! if ( !Q_stricmp( token, "blockSound3" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } saber->blockSound[2] = BG_SoundIndex( (char *)value ); continue; } //block effect - when saber/sword hits another saber/sword if ( !Q_stricmp( token, "blockEffect" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } #ifdef QAGAME//cgame-only cares about this #elif defined CGAME saber->blockEffect = trap_FX_RegisterEffect( (char *)value ); #endif continue; } //hit person effect - when saber/sword hits a person if ( !Q_stricmp( token, "hitPersonEffect" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } #ifdef QAGAME//cgame-only cares about this #elif defined CGAME saber->hitPersonEffect = trap_FX_RegisterEffect( (char *)value ); #endif continue; } //hit other effect - when saber/sword hits sopmething else damagable if ( !Q_stricmp( token, "hitOtherEffect" ) ) { if ( COM_ParseString( &p, &value ) ) { continue; } #ifdef QAGAME//cgame-only cares about this #elif defined CGAME saber->hitOtherEffect = trap_FX_RegisterEffect( (char *)value ); #endif continue; } //if non-zero, the saber will not do the big, white clash flare with other sabers if ( !Q_stricmp( token, "noClashFlare" ) ) { if ( COM_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } saber->noClashFlare = ((qboolean)(n!=0)); continue; } if ( !Q_stricmp( token, "notInMP" ) ) {//ignore this SkipRestOfLine( &p ); continue; } //FIXME: saber sounds (on, off, loop) #ifdef _DEBUG Com_Printf( "WARNING: unknown keyword '%s' while parsing '%s'\n", token, useSaber ); #endif SkipRestOfLine( &p ); } //FIXME: precache the saberModel(s)? return qtrue; }
void CG_LoadHolsterData (clientInfo_t *ci) {//adjusts the manual holster positional data based on the holster.cfg file associated with the model or simply //use the default values int i; fileHandle_t f; int fLen = 0; char fileBuffer[MAX_HOLSTER_INFO_SIZE]; char holsterTypeValue[MAX_QPATH]; char holsterTypeGroup[MAX_HOLSTER_INFO_SIZE]; char *s; vec3_t vectorData; InitHolsterData(ci); if ( !ci->skinName || !Q_stricmp( "default", ci->skinName ) ) {//try default holster.cfg first fLen = trap_FS_FOpenFile(va("models/players/%s/holster.cfg", ci->modelName), &f, FS_READ); if( !f ) {//no file, use kyle's then. fLen = trap_FS_FOpenFile("models/players/kyle/holster.cfg", &f, FS_READ); } } else {//use the holster.cfg associated with this skin fLen = trap_FS_FOpenFile(va("models/players/%s/holster_%s.cfg", ci->modelName, ci->skinName), &f, FS_READ); if ( !f ) {//fall back to default holster.cfg fLen = trap_FS_FOpenFile(va("models/players/%s/holster.cfg", ci->modelName), &f, FS_READ); } if( !f ) {//still no dice, use kyle's then. fLen = trap_FS_FOpenFile("models/players/kyle/holster.cfg", &f, FS_READ); } } if ( !f || !fLen ) {//couldn't open file or it was empty, just use the defaults return; } if( fLen >= MAX_HOLSTER_INFO_SIZE ) { CG_Printf("Error: holster.cfg for %s is over the holster.cfg filesize limit.\n", ci->modelName); trap_FS_FCloseFile( f ); return; } trap_FS_Read(fileBuffer, fLen, f); trap_FS_FCloseFile( f ); s = fileBuffer; //parse file while( (s = BG_GetNextValueGroup(s, holsterTypeGroup)) != NULL ) { if( !BG_SiegeGetPairedValue(holsterTypeGroup, "holsterType", holsterTypeValue) ) {//couldn't find holster type in group CG_Printf("Error: The holster.cfg for %s appears to be missing a holsterType in one of its define groups.\n", ci->modelName); continue; } i = GetIDForString(holsterTypeTable, holsterTypeValue); if( i == -1 ) {//bad holster type CG_Printf("Error: The holster.cfg for %s has a bad holsterType in one of the define groups.\n", ci->modelName); continue; } if( BG_SiegeGetPairedValue(holsterTypeGroup, "boneIndex", holsterTypeValue) ) {//have bone index data for this holster type, use it if(!Q_stricmp(holsterTypeValue, "disabled") ) {//disable the rendering of this holster type on this model ci->holsterData[i].boneIndex = HOLSTER_NONE; } else { ci->holsterData[i].boneIndex = GetIDForString(holsterBoneTable, holsterTypeValue); } } if( BG_SiegeGetPairedValue(holsterTypeGroup, "posOffset", holsterTypeValue) ) {//parsing positional offset data sscanf (holsterTypeValue, "%f, %f, %f", &vectorData[0], &vectorData[1], &vectorData[2]); VectorCopy(vectorData, ci->holsterData[i].posOffset); //&ci->holsterData[i].posOffset[0], &ci->holsterData[i].posOffset[1], //&ci->holsterData[i].posOffset[2]); } if( BG_SiegeGetPairedValue(holsterTypeGroup, "angOffset", holsterTypeValue) ) {//parsing angular offset sscanf (holsterTypeValue, "%f, %f, %f", &vectorData[0], &vectorData[1], &vectorData[2]); VectorCopy(vectorData, ci->holsterData[i].angOffset); } } #ifdef _DEBUG CG_Printf("Holstered Weapon Data Loaded for %s.\n", ci->modelName); #endif }
/* ====================== CG_ParseAnimationFile Read a configuration file containing animation coutns and rates models/players/visor/animation.cfg, etc ====================== */ qboolean G_ParseAnimationFile( const char *filename ) { char *text_p; int len; int i; char *token; float fps; int skip; char text[20000]; fileHandle_t f; int animNum; animation_t *animations = knownAnimFileSets[numKnownAnimFileSets].animations; // load the file len = gi.FS_FOpenFile( filename, &f, FS_READ ); if ( len <= 0 ) { return qfalse; } if ( len >= sizeof( text ) - 1 ) { gi.Printf( "File %s too long\n", filename ); return qfalse; } gi.FS_Read( text, len, f ); text[len] = 0; gi.FS_FCloseFile( f ); // parse the text text_p = text; skip = 0; // quiet the compiler warning //FIXME: have some way of playing anims backwards... negative numFrames? //initialize anim array so that from 0 to MAX_ANIMATIONS, set default values of 0 1 0 100 for(i = 0; i < MAX_ANIMATIONS; i++) { animations[i].firstFrame = 0; animations[i].numFrames = 0; animations[i].loopFrames = -1; animations[i].frameLerp = 100; animations[i].initialLerp = 100; } // read information for each frame while(1) { token = COM_Parse( &text_p ); if ( !token || !token[0]) { break; } animNum = GetIDForString(animTable, token); if(animNum == -1) { Com_Printf(S_COLOR_RED"WARNING: Unknown token %s in %s\n", token, filename); continue; } token = COM_Parse( &text_p ); if ( !token ) { break; } animations[animNum].firstFrame = atoi( token ); token = COM_Parse( &text_p ); if ( !token ) { break; } animations[animNum].numFrames = atoi( token ); token = COM_Parse( &text_p ); if ( !token ) { break; } animations[animNum].loopFrames = atoi( token ); token = COM_Parse( &text_p ); if ( !token ) { break; } fps = atof( token ); if ( fps == 0 ) { fps = 1;//Don't allow divide by zero error } if ( fps < 0 ) {//backwards animations[animNum].frameLerp = floor(1000.0f / fps); } else { animations[animNum].frameLerp = ceil(1000.0f / fps); } animations[animNum].initialLerp = ceil(1000.0f / fabs(fps)); } return qtrue; }