1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 
21 #include "ui_local.h"
22 
23 /*
24 =============================================================================
25 
26 PLAYER MODELS
27 
28 =============================================================================
29 */
30 
31 static const char *baseWeaponNames[] = {
32 	"w_bfg.md2",
33 	"w_blaster.md2",
34 	"w_chaingun.md2",
35 	"w_glauncher.md2",
36 	"w_hyperblaster.md2",
37 	"w_machinegun.md2",
38 	"w_railgun.md2",
39 	"w_rlauncher.md2",
40 	"w_shotgun.md2",
41 	"w_sshotgun.md2",
42 	NULL
43 };
44 
IconOfSkinExists(char * skin,char ** pcxfiles,int npcxfiles)45 static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles ) {
46 	int i;
47 	char scratch[MAX_OSPATH];
48 
49 	COM_StripExtension( skin, scratch, sizeof( scratch ) );
50 	Q_strcat( scratch, sizeof( scratch ), "_i.pcx" );
51 
52 	for( i = 0 ; i < npcxfiles ; i++ ) {
53 		if( strcmp( pcxfiles[i], scratch ) == 0 )
54 			return qtrue;
55 	}
56 
57 	return qfalse;
58 }
59 
pmicmpfnc(const void * _a,const void * _b)60 static int pmicmpfnc( const void *_a, const void *_b ) {
61 	const playerModelInfo_t *a = (const playerModelInfo_t *)_a;
62 	const playerModelInfo_t *b = (const playerModelInfo_t *)_b;
63 
64 	/*
65 	** sort by male, female, then alphabetical
66 	*/
67 	if( strcmp( a->directory, "male" ) == 0 )
68 		return -1;
69 	else if( strcmp( b->directory, "male" ) == 0 )
70 		return 1;
71 
72 	if( strcmp( a->directory, "female" ) == 0 )
73 		return -1;
74 	else if( strcmp( b->directory, "female" ) == 0 )
75 		return 1;
76 
77 	return strcmp( a->directory, b->directory );
78 }
79 
PlayerModel_Load(void)80 void PlayerModel_Load( void ) {
81 	char scratch[MAX_QPATH];
82 	int ndirs = 0;
83 	char *dirnames[MAX_PLAYERMODELS];
84 	int i, j;
85 	char **list;
86 	char *p;
87 	int numFiles;
88 	playerModelInfo_t *pmi;
89 
90 	uis.numPlayerModels = 0;
91 
92 	/*
93 	** get a list of directories
94 	*/
95 	if( !( list = fs.ListFiles( NULL, "players/*/*", FS_SEARCH_BYFILTER|FS_SEARCH_SAVEPATH, &numFiles ) ) ) {
96 		return;
97 	}
98 
99 	for( i = 0; i < numFiles; i++ ) {
100 		Q_strncpyz( scratch, list[i] + 8, sizeof( scratch ) );
101 		if( ( p = strchr( scratch, '/' ) ) ) {
102 			*p = 0;
103 		}
104 
105 		for( j = 0; j < ndirs; j++ ) {
106 			if( !strcmp( dirnames[j], scratch ) ) {
107 				break;
108 			}
109 		}
110 
111 		if( j != ndirs ) {
112 			continue;
113 		}
114 
115 		dirnames[ndirs++] = UI_CopyString( scratch );
116 		if( ndirs == MAX_PLAYERMODELS ) {
117 			break;
118 		}
119 	}
120 
121 	fs.FreeFileList( list );
122 
123 	if( !ndirs ) {
124 		return;
125 	}
126 
127 	/*
128 	** go through the subdirectories
129 	*/
130 
131 	for( i = 0; i < ndirs; i++ ) {
132 		int k, s;
133 		char **pcxnames;
134 		char **skinnames;
135 		int npcxfiles;
136 		int nskins = 0;
137 		int numWeapons;
138 		char **weaponNames;
139 
140 		// verify the existence of tris.md2
141 		Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", dirnames[i] );
142 		if( fs.LoadFile( scratch, NULL ) < 1 ) {
143 			continue;
144 		}
145 
146 		// verify the existence of at least one pcx skin
147 		Com_sprintf( scratch, sizeof( scratch ), "players/%s", dirnames[i] );
148 		pcxnames = fs.ListFiles( scratch, ".pcx", 0, &npcxfiles );
149 		if( !pcxnames ) {
150 			continue;
151 		}
152 
153 		// count valid skins, which consist of a skin with a matching "_i" icon
154 		for( k = 0; k < npcxfiles; k++ ) {
155 			if( !strstr( pcxnames[k], "_i.pcx" ) ) {
156 				if( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles ) ) {
157 					nskins++;
158 				}
159 			}
160 		}
161 
162 		if( !nskins ) {
163 			fs.FreeFileList( pcxnames );
164 			continue;
165 		}
166 
167 		skinnames = UI_Malloc( sizeof( char * ) * ( nskins + 1 ) );
168         skinnames[nskins] = NULL;
169 
170 		// copy the valid skins
171 		for( s = 0, k = 0; k < npcxfiles; k++ ) {
172 			if( !strstr( pcxnames[k], "_i.pcx" ) ) {
173 				if( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles ) ) {
174 					COM_StripExtension( pcxnames[k], scratch, sizeof( scratch ) );
175 					skinnames[s++] = UI_CopyString( scratch );
176 				}
177 			}
178 		}
179 
180 		fs.FreeFileList( pcxnames );
181 
182 		// load vweap models
183 		Com_sprintf( scratch, sizeof( scratch ), "players/%s/w_*.md2", dirnames[i] );
184 		weaponNames = fs.ListFiles( NULL, scratch, FS_SEARCH_BYFILTER, &numWeapons );
185 
186 		pmi = &uis.pmi[uis.numPlayerModels++];
187 		pmi->numWeapons = 0;
188 
189 		if( weaponNames ) {
190 			pmi->weaponNames = UI_Malloc( sizeof( char * ) * numWeapons );
191 
192 			for( j = 0; j < numWeapons ; j++ ) {
193 				for( k = 0; baseWeaponNames[k] ; k++ ) {
194 					if( !strcmp( weaponNames[j], baseWeaponNames[k] ) ) {
195 						break;
196 					}
197 				}
198 				if( !baseWeaponNames[k] ) {
199 					continue;
200 				}
201 
202 				pmi->weaponNames[pmi->numWeapons++] = UI_CopyString( weaponNames[j] );
203 			}
204 
205 			fs.FreeFileList( weaponNames );
206 		}
207 
208 		// at this point we have a valid player model
209 		pmi->nskins = nskins;
210 		pmi->skindisplaynames = skinnames;
211 
212 		// make short name for the model
213 		strcpy( pmi->directory, dirnames[i] );
214 	}
215 
216 	for( i = 0; i < ndirs; i++ ) {
217 		com.Free( dirnames[i] );
218 	}
219 
220 	qsort( uis.pmi, uis.numPlayerModels, sizeof( uis.pmi[0] ), pmicmpfnc );
221 }
222 
223 
224 
PlayerModel_Free(void)225 void PlayerModel_Free( void ) {
226 	playerModelInfo_t *pmi;
227 	int i, j;
228 
229 	for( i = 0, pmi = uis.pmi; i < uis.numPlayerModels; i++, pmi++ ) {
230 		if( pmi->skindisplaynames ) {
231 			for( j = 0; j < pmi->nskins; j++ ) {
232 				com.Free( pmi->skindisplaynames[j] );
233 			}
234 			com.Free( pmi->skindisplaynames );
235 		}
236 		if( pmi->weaponNames ) {
237 			for( j = 0; j < pmi->numWeapons; j++ ) {
238 				com.Free( pmi->weaponNames[j] );
239 			}
240 			com.Free( pmi->weaponNames );
241 		}
242 		memset( pmi, 0, sizeof( *pmi ) );
243 	}
244 
245 	uis.numPlayerModels = 0;
246 }
247 
248