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