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 // cg_location.c
22 //
23
24 #include "cg_local.h"
25
26 typedef struct cg_location_s {
27 struct cg_location_s *next;
28
29 char *name;
30 vec3_t location;
31 } cg_location_t;
32
33 static cg_location_t *cg_locationList;
34 static char cg_locFileName[MAX_QPATH];
35
36 /*
37 =============================================================================
38
39 LOADING
40
41 =============================================================================
42 */
43
44 /*
45 ====================
46 CG_FreeLocations
47
48 Called on map change, full shutdown, and to release a bad loc file
49 ====================
50 */
CG_FreeLocations(void)51 static void CG_FreeLocations (void)
52 {
53 if (cg_locationList) {
54 cg_locationList->next = NULL;
55 cg_locationList = NULL;
56 }
57
58 // Empty memory in pool
59 CG_FreeTag (CGTAG_LOCATION);
60 }
61
62
63 /*
64 ====================
65 CG_LoadLocations
66
67 Called on map change or location addition to reload the file
68 ====================
69 */
CG_LoadLocations(char * mapName)70 void CG_LoadLocations (char *mapName)
71 {
72 cg_location_t *loc;
73 vec3_t location;
74 qBool finished;
75 char *buf;
76 char *token;
77 int fileLen;
78
79 CG_FreeLocations ();
80
81 if (!mapName || !mapName[0])
82 return;
83
84 Com_StripExtension (cg_locFileName, sizeof (cg_locFileName), mapName);
85 Q_snprintfz (cg_locFileName, sizeof (cg_locFileName), "%s.loc", cg_locFileName);
86
87 fileLen = cgi.FS_LoadFile (cg_locFileName, (void **)&buf, "\n\0");
88 if (!buf || fileLen <= 0) {
89 Com_DevPrintf (PRNT_WARNING, "WARNING: can't load '%s' -- %s\n", cg_locFileName, (fileLen == -1) ? "not found" : "empty file");
90 return;
91 }
92
93 token = strtok (buf, "\t ");
94 finished = qFalse;
95 while (token) {
96 finished = qFalse;
97
98 // X coordinate
99 location[0] = (float)atoi (token)*0.125f;
100
101 // Y coordinate
102 token = strtok (NULL, "\t ");
103 if (!token)
104 break;
105 location[1] = (float)atoi (token)*0.125f;
106
107 // Z coordinate
108 token = strtok (NULL, "\t ");
109 if (!token)
110 break;
111 location[2] = (float)atoi (token)*0.125f;
112
113 // Location
114 token = strtok (NULL, "\n\r");
115 if (!token)
116 break;
117
118 // Allocate
119 loc = CG_AllocTag (sizeof (cg_location_t), qTrue, CGTAG_LOCATION);
120 loc->name = CG_TagStrDup (token, CGTAG_LOCATION);
121 Vec3Copy (location, loc->location);
122
123 // Link it in
124 loc->next = cg_locationList;
125 cg_locationList = loc;
126
127 // Go to the next x coord
128 token = strtok (NULL, "\n\r\t ");
129 if (!token)
130 finished = qTrue;
131 }
132
133 if (!finished) {
134 Com_Printf (PRNT_ERROR, "CG_LoadLocations: Bad loc file '%s'\n", cg_locFileName);
135 CG_FreeLocations ();
136 }
137
138 CG_FS_FreeFile (buf);
139 }
140
141 /*
142 =============================================================================
143
144 MESSAGE PREPROCESSING
145
146 =============================================================================
147 */
148
149 /*
150 ====================
151 CG_GetLocation
152
153 Grabs the location for the message preprocessing
154 ====================
155 */
CG_GetLocation(vec3_t where)156 static char *CG_GetLocation (vec3_t where)
157 {
158 cg_location_t *loc, *best;
159 uint32 length, bestLength = 0xFFFFFFFF;
160
161 best = NULL;
162 for (loc=cg_locationList ; loc ; loc=loc->next) {
163 length = Vec3Dist (loc->location, where);
164 if (length < bestLength && loc->name && loc->name[0]) {
165 best = loc;
166 bestLength = length;
167 }
168 }
169
170 if (best)
171 return best->name;
172
173 return NULL;
174 }
175
176
177 /*
178 ====================
179 CG_Say_Preprocessor
180 ====================
181 */
CG_Say_Preprocessor(void)182 void CG_Say_Preprocessor (void)
183 {
184 char *locName, *p;
185 char *sayText;
186 int locLen, cmdLen, c;
187 trace_t tr;
188 vec3_t end;
189
190 if (cg_locationList) {
191 sayText = p = cgi.Cmd_Args ();
192
193 while (*sayText && *(sayText+1)) {
194 if (sayText[0] == '@') {
195 c = Q_tolower (sayText[1]);
196
197 locName = NULL;
198 switch (c) {
199 case 't':
200 // Trace and find the end-point for the location
201 end[0] = cg.refDef.viewOrigin[0] + cg.refDef.viewAxis[0][0] * 65536 - cg.refDef.viewAxis[1][0];
202 end[1] = cg.refDef.viewOrigin[1] + cg.refDef.viewAxis[0][1] * 65536 - cg.refDef.viewAxis[1][1];
203 end[2] = cg.refDef.viewOrigin[2] + cg.refDef.viewAxis[0][2] * 65536 - cg.refDef.viewAxis[1][2];
204 CG_PMTrace (&tr, cg.refDef.viewOrigin, NULL, NULL, end, qFalse);
205 if (tr.fraction < 1) {
206 locName = CG_GetLocation (tr.endPos);
207 if (locName)
208 break;
209 }
210
211 // FALL THROUGH
212 case 'l':
213 // Local location
214 locName = CG_GetLocation (cg.refDef.viewOrigin);
215 break;
216 }
217
218 // Insert if found
219 if (locName) {
220 // Lengths
221 cmdLen = strlen (cgi.Cmd_Args ());
222 locLen = strlen (locName);
223
224 // Check if it will fit
225 if (cmdLen + locLen >= MAX_STRING_CHARS) {
226 Com_DevPrintf (0, "CG_Say_Preprocessor: location expansion aborted, not enough space\n");
227 break;
228 }
229
230 // Insert
231 memmove (sayText+locLen, sayText+2, cmdLen-(sayText-p)-1);
232 memcpy (sayText, locName, locLen);
233 sayText += locLen-1;
234 }
235 }
236 sayText++;
237 }
238 }
239
240 if (cgi.CL_ForwardCmdToServer ())
241 return;
242
243 // Command unknown (shouldn't honestly happen but oh well)
244 Com_Printf (0, "Unknown command \"%s" S_STYLE_RETURN "\"\n", cgi.Cmd_Argv (0));
245 }
246
247 /*
248 =============================================================================
249
250 CONSOLE COMMANDS
251
252 =============================================================================
253 */
254
255 /*
256 ====================
257 CG_AddLoc_f
258 ====================
259 */
CG_AddLoc_f(void)260 static void CG_AddLoc_f (void)
261 {
262 FILE *f;
263 char path[MAX_QPATH];
264
265 if (cgi.Cmd_Argc () < 2) {
266 Com_Printf (0, "syntax: addloc <message>\n");
267 return;
268 }
269
270 if (!cg_locFileName[0]) {
271 Com_Printf (0, "CG_AddLoc_f: No map loaded!\n");
272 return;
273 }
274
275 Q_snprintfz (path, sizeof (path), "%s/%s", cgi.FS_Gamedir (), cg_locFileName);
276
277 f = fopen (path, "ab");
278 if (!f) {
279 Com_Printf (PRNT_ERROR, "ERROR: Couldn't write %s\n", path);
280 return;
281 }
282
283 fprintf (f, "%i %i %i %s\n",
284 (int)(cg.refDef.viewOrigin[0]*8),
285 (int)(cg.refDef.viewOrigin[1]*8),
286 (int)(cg.refDef.viewOrigin[2]*8),
287 cgi.Cmd_Args ());
288
289 fclose (f);
290
291 // Tell them
292 Com_Printf (0, "Saved location (x%i y%i z%i): \"%s\"\n",
293 (int)cg.refDef.viewOrigin[0],
294 (int)cg.refDef.viewOrigin[1],
295 (int)cg.refDef.viewOrigin[2],
296 cgi.Cmd_Args ());
297
298 CG_LoadLocations (cg_locFileName);
299 }
300
301 /*
302 =============================================================================
303
304 INIT / SHUTDOWN
305
306 =============================================================================
307 */
308
309 static void *cmd_addLoc;
310
311 /*
312 ====================
313 CG_LocationInit
314 ====================
315 */
CG_LocationInit(void)316 void CG_LocationInit (void)
317 {
318 // Clear locations
319 CG_FreeLocations ();
320
321 // Add console commands
322 cmd_addLoc = cgi.Cmd_AddCommand ("addloc", CG_AddLoc_f, "");
323
324 // Clear the loc filename
325 cg_locFileName[0] = '\0';
326 }
327
328
329 /*
330 ====================
331 CG_LocationShutdown
332 ====================
333 */
CG_LocationShutdown(void)334 void CG_LocationShutdown (void)
335 {
336 // Free locations
337 CG_FreeLocations ();
338
339 // Remove console commands
340 cgi.Cmd_RemoveCommand ("addloc", cmd_addLoc);
341 }
342