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