With cordite in the air, splintered steel, shell casings and powder burns, there’s only one explanation...
Discuss & improve the game engine.

Moderators: sparcdr, torhu, Tequila

Enemy models forcing for 1.1

Postby Lucky Bro » Tue Aug 18, 2009 10:15 pm

Good day,

Variables:
cg_enemyModel <model/skin>
cg_teamModel <model/skin>
cg_forceModelTeamSkin <1/0>
All of them are used only when cg_forceModel is 1.
Enemy and team models are obvious:
Enemy model is used for opponent team and team model for your own team.
A few words about cg_forceModelTeamSkin:
If it set to 1, the skins are forced for both team (blue has blue and red has red) independently on which team you are. Also skins are forced anyway when you spectate.
This is doubtable, so feel free to comment/suggest as always.
Without skin forcing feature the skins from forceModels variables will be used. Thus, when you spectate it will be enemy skin for everyone!
Also your own skin is always separate. It is taken from model variable.
Implementation notes:
I'm not sure about only one thing:
Should I check player team at CG_NewClientInfo() via cgs.clientinfo[cg.clientNum].team or via cg.snap->ps.persistant[PERS_TEAM]?..
To do:
To set default models for teamModel and enemyModel. Right when some models will be done.
Right when player's effect colors will be unlocked we may do some shaders and use them for coloring models. Like each model will have some places for such colors (it could be some details on hat/belt, etc). Would be nice. A lot of games using it and it makes you character unique :)

The patch text for discussion:
Index: code/cgame/cg_local.h
===================================================================
--- code/cgame/cg_local.h (revision 263)
+++ code/cgame/cg_local.h (working copy)
@@ -1702,6 +1702,9 @@
extern vmCvar_t cg_teamChatHeight;
extern vmCvar_t cg_stats;
extern vmCvar_t cg_forceModel;
+extern vmCvar_t cg_enemyModel;
+extern vmCvar_t cg_teamModel;
+extern vmCvar_t cg_forceModelTeamSkin;
extern vmCvar_t cg_buildScript;
extern vmCvar_t cg_paused;
#ifdef SMOKINGUNS
@@ -1937,6 +1940,7 @@
extern int sortedTeamPlayers[TEAM_MAXOVERLAY];
extern int numSortedTeamPlayers;
extern int drawTeamOverlayModificationCount;
+extern int forceModelModificationCount;
extern char systemChat[256];
extern char teamChat1[256];
extern char teamChat2[256];
Index: code/cgame/cg_main.c
===================================================================
--- code/cgame/cg_main.c (revision 263)
+++ code/cgame/cg_main.c (working copy)
@@ -164,6 +164,10 @@
vmCvar_t cg_stats;
vmCvar_t cg_buildScript;
vmCvar_t cg_forceModel;
+vmCvar_t cg_forceModelTeamSkin;
+vmCvar_t cg_teamModel;
+vmCvar_t cg_enemyModel;
+
vmCvar_t cg_paused;
#ifdef SMOKINGUNS
vmCvar_t cg_menu;
@@ -392,6 +396,9 @@
{ &cg_teamChatTime, "cg_teamChatTime", "3000", CVAR_ARCHIVE },
{ &cg_teamChatHeight, "cg_teamChatHeight", "0", CVAR_ARCHIVE },
{ &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE },
+ { &cg_forceModelTeamSkin, "cg_forceModelTeamSkin", "1", CVAR_ARCHIVE },
+ { &cg_enemyModel, "cg_enemyModel", "", CVAR_ARCHIVE },
+ { &cg_teamModel, "cg_teamModel", "", CVAR_ARCHIVE },
{ &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE },
#ifndef SMOKINGUNS
{ &cg_deferPlayers, "cg_deferPlayers", "0", CVAR_ARCHIVE },
Index: code/cgame/cg_players.c
===================================================================
--- code/cgame/cg_players.c (revision 263)
+++ code/cgame/cg_players.c (working copy)
@@ -1386,6 +1386,31 @@
v = Info_ValueForKey( configstring, "t" );
newInfo.team = atoi( v );

+ //Check if the player has changed his team
+ //Don't check everyone - only main one
+ if (cg_forceModel.integer && (cgs.gametype >= GT_TEAM) &&
+ (cg.clientNum == clientNum) && (newInfo.team != ci->team)) {
+ switch (ci->team) {
+ case TEAM_BLUE:
+ case TEAM_BLUE_SPECTATOR:
+ //We may use the following logic because TEAM_BLUE_SPECTATOR != TEAM_BLUE,
+ //otherwise don't use it!
+ if ((newInfo.team != TEAM_BLUE_SPECTATOR) && (newInfo.team != TEAM_BLUE))
+ //Player has switched teams (from one team to another or to spectator)
+ forceModelModificationCount--;
+ break;
+ case TEAM_RED:
+ case TEAM_RED_SPECTATOR:
+ if ((newInfo.team != TEAM_RED_SPECTATOR) && (newInfo.team != TEAM_RED))
+ //Player has switched teams (from one team to another or to spectator)
+ forceModelModificationCount--;
+ break;
+ default:
+ //Player has switched teams (from spectator to team)
+ forceModelModificationCount--;
+ }
+ }
+
// team task
v = Info_ValueForKey( configstring, "tt" );
newInfo.teamTask = atoi(v);
@@ -1416,48 +1441,68 @@
char modelStr[MAX_QPATH];
char *skin;

- if( cgs.gametype >= GT_TEAM ) {
-#ifndef SMOKINGUNS
- Q_strncpyz( newInfo.modelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.modelName ) );
- Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
-#else
- Q_strncpyz( newInfo.modelName, DEFAULT_MODEL, sizeof( newInfo.modelName ) );
- Q_strncpyz( newInfo.skinName, "red", sizeof( newInfo.skinName ) );
-#endif
+ //Model section
+ if( cgs.gametype >= GT_TEAM && cg.clientNum != clientNum ) {
+ switch (cgs.clientinfo[cg.clientNum].team) {
+ case TEAM_BLUE:
+ case TEAM_BLUE_SPECTATOR:
+ if ((newInfo.team == TEAM_BLUE_SPECTATOR) ||
+ (newInfo.team == TEAM_BLUE)) {
+ trap_Cvar_VariableStringBuffer( "cg_teamModel", modelStr, sizeof( modelStr ) );
+ } else {
+ trap_Cvar_VariableStringBuffer( "cg_enemyModel", modelStr, sizeof( modelStr ) );
+ }
+ break;
+ case TEAM_RED:
+ case TEAM_RED_SPECTATOR:
+ if ((newInfo.team == TEAM_RED_SPECTATOR) ||
+ (newInfo.team == TEAM_RED)) {
+ trap_Cvar_VariableStringBuffer( "cg_teamModel", modelStr, sizeof( modelStr ) );
+ } else {
+ trap_Cvar_VariableStringBuffer( "cg_enemyModel", modelStr, sizeof( modelStr ) );
+ }
+ break;
+ default:
+ trap_Cvar_VariableStringBuffer( "cg_enemyModel", modelStr, sizeof( modelStr ) );
+ }
} else {
trap_Cvar_VariableStringBuffer( "model", modelStr, sizeof( modelStr ) );
- if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
-#ifndef SMOKINGUNS
- skin = "default";
-#else
- skin = "red";
-#endif
- } else {
- *skin++ = 0;
+ }
+ //Skins section
+ if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
+ //model name doesn't include a skin name
+ skin = "red";
+ } else {
+ //Cutting off the skin name is required for force skins feature!
+ //Without it the model won't be taken
+ *skin++ = 0;
+ }
+ if (cgs.gametype >= GT_TEAM && (cg_forceModelTeamSkin.integer ||
+ (cgs.clientinfo[cg.clientNum].team == TEAM_SPECTATOR))) {
+ //Force skins in team games
+ //Skins are forced if player is just spectating
+ switch (newInfo.team) {
+ case TEAM_BLUE:
+ case TEAM_BLUE_SPECTATOR:
+ skin = "blue";
+ break;
+ case TEAM_RED:
+ case TEAM_RED_SPECTATOR:
+ default:
+ skin = "red";
}
-
- Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) );
- Q_strncpyz( newInfo.modelName, modelStr, sizeof( newInfo.modelName ) );
}

- if ( cgs.gametype >= GT_TEAM ) {
- // keep skin name
- slash = strchr( v, '/' );
- if ( slash ) {
- Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
- }
- }
+ //Set skin&model
+ Q_strncpyz( newInfo.modelName, modelStr, sizeof( newInfo.modelName ) );
+ Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) );
} else {
Q_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) );

slash = strchr( newInfo.modelName, '/' );
if ( !slash ) {
// modelName didn not include a skin name
-#ifndef SMOKINGUNS
- Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
-#else
Q_strncpyz( newInfo.skinName, "red", sizeof( newInfo.skinName ) );
-#endif
} else {
Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
// truncate modelName
Index: code/game/g_client.c
===================================================================
--- code/game/g_client.c (revision 263)
+++ code/game/g_client.c (working copy)
@@ -1322,22 +1322,6 @@
}
*/

-#ifdef SMOKINGUNS
- // team skin in Smokin' Guns
- switch( team ) {
- case TEAM_RED:
- case TEAM_RED_SPECTATOR:
- ForceClientSkin(client, model, "red");
- ForceClientSkin(client, headModel, "red");
- break;
- case TEAM_BLUE:
- case TEAM_BLUE_SPECTATOR:
- ForceClientSkin(client, model, "blue");
- ForceClientSkin(client, headModel, "blue");
- break;
- }
-#endif
-
#ifndef SMOKINGUNS
if (g_gametype.integer >= GT_TEAM) {
client->pers.teamInfo = qtrue;


The patch file:
EnemyModels.patch

This was so far hardest thing to implement since I'm not familiar with Q3 engine.
So there could be some mistakes. Please report them. Also review the code if you have time and wish. That is very important feature for upcoming release.

Very big notice:
We have to re-do all models and textures that are not free (everything for now). Those could be the same models but just not total copies!

Thanks for attention!
Have a good day!
Last edited by Lucky Bro on Wed Aug 19, 2009 10:15 am, edited 3 times in total.
"You should know that the lies won't hide your flaws/No sense in hiding all of yours/You gave up on your dreams along the way" (c) "Fake it" by Seether
P.S. English isn't my native language.
User avatar
Lucky Bro
Gunslinger
 
Posts: 143
Joined: Mon Mar 09, 2009 4:12 pm



Postby RailedRobin » Tue Aug 18, 2009 11:25 pm

If I understand correctly (am very tired at the moment) this would enable me to choose which models are used when using force models?
So I can make everyone in my team look like The Mexican, and everyone in the other team look like Clint?

If so: Great! :D
I really admire all the hard work you're doing with this game. Keep it up!
A bullet may have your name on it, but dynamite is addressed "to whom it may concern."
User avatar
RailedRobin
Quick Draw
 
Posts: 54
Joined: Tue Jul 18, 2006 9:57 pm
Location: The frozen north



Indeed :)

Postby Lucky Bro » Wed Aug 19, 2009 8:40 am

You got it right.
Yesterday I was playing with company (bots of course) of wq_female1 as my teamModel and wq_male2 (second Clint's model) as enemy model while me was wq_male3 (the Tuco's one). It was like "Go girls! let's show those Clint's how to shoot!" :)
I didn't invent that feature :) It is used for years not only in Q games.
And actually all that I've done are easy jobs - everyone can do them. You don't need to have deep knowledge of engine to do such. One of main goals is to show that it is possible like mapping or texturing and gaming itself.
The next stop is big 1.1 code review.

Btw, that reminds me that we have to re-do every model and texture :( Because they have to be free. I think if we don't have our own modelers and artists we may use some hired ones. At least I see reason to pay for that. But before do that I think we have to try to find free ones. Really try - not only on our forum but outside it too.

Have a good day!
"You should know that the lies won't hide your flaws/No sense in hiding all of yours/You gave up on your dreams along the way" (c) "Fake it" by Seether
P.S. English isn't my native language.
User avatar
Lucky Bro
Gunslinger
 
Posts: 143
Joined: Mon Mar 09, 2009 4:12 pm




Return to Code

Show Sidebar
Show Sidebar

User Control Panel

cron