Quake II RTX doxygen  1.0 dev
locs.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 2003-2006 Andrey Nazarov
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 //
20 // cl_locs.c
21 //
22 
23 #include "client.h"
24 
25 typedef struct {
26  list_t entry;
27  vec3_t origin;
28  char name[1];
29 } location_t;
30 
31 static LIST_DECL(cl_locations);
32 
33 static cvar_t *loc_draw;
34 static cvar_t *loc_trace;
35 static cvar_t *loc_dist;
36 
37 /*
38 ==============
39 LOC_Alloc
40 ==============
41 */
42 static location_t *LOC_Alloc(const char *name)
43 {
44  location_t *loc;
45  size_t len;
46 
47  len = strlen(name);
48  loc = Z_Malloc(sizeof(*loc) + len);
49  memcpy(loc->name, name, len + 1);
50 
51  return loc;
52 }
53 
54 /*
55 ==============
56 LOC_LoadLocations
57 ==============
58 */
60 {
61  char path[MAX_OSPATH];
62  char *buffer, *s, *p;
63  int line, count;
64  location_t *loc;
65  int argc;
66  qerror_t ret;
67 
68  // load from main directory
69  Q_concat(path, sizeof(path), "locs/", cl.mapname, ".loc", NULL);
70 
71  ret = FS_LoadFile(path, (void **)&buffer);
72  if (!buffer) {
73  if (ret != Q_ERR_NOENT) {
74  Com_EPrintf("Couldn't load %s: %s\n", path, Q_ErrorString(ret));
75  }
76  return;
77  }
78 
79  s = buffer;
80  line = count = 0;
81  while (*s) {
82  p = strchr(s, '\n');
83  if (p) {
84  *p = 0;
85  }
86 
87  Cmd_TokenizeString(s, qfalse);
88  line++;
89 
90  argc = Cmd_Argc();
91  if (argc) {
92  if (argc < 4) {
93  Com_WPrintf("Line %d is incomplete in %s\n", line, path);
94  } else {
95  loc = LOC_Alloc(Cmd_RawArgsFrom(3));
96  loc->origin[0] = atof(Cmd_Argv(0)) * 0.125f;
97  loc->origin[1] = atof(Cmd_Argv(1)) * 0.125f;
98  loc->origin[2] = atof(Cmd_Argv(2)) * 0.125f;
99  List_Append(&cl_locations, &loc->entry);
100  count++;
101  }
102  }
103 
104  if (!p) {
105  break;
106  }
107 
108  s = p + 1;
109  }
110 
111  Com_DPrintf("Loaded %d location%s from %s\n",
112  count, count == 1 ? "" : "s", path);
113 
114  FS_FreeFile(buffer);
115 }
116 
117 /*
118 ==============
119 LOC_FreeLocations
120 ==============
121 */
123 {
124  location_t *loc, *next;
125 
126  LIST_FOR_EACH_SAFE(location_t, loc, next, &cl_locations, entry) {
127  Z_Free(loc);
128  }
129 
130  List_Init(&cl_locations);
131 }
132 
133 /*
134 ==============
135 LOC_FindClosest
136 ==============
137 */
138 static location_t *LOC_FindClosest(vec3_t pos)
139 {
140  location_t *loc, *nearest;
141  vec3_t dir;
142  float dist, minDist;
143  trace_t trace;
144 
145  minDist = 99999;
146  nearest = NULL;
147  LIST_FOR_EACH(location_t, loc, &cl_locations, entry) {
148  VectorSubtract(pos, loc->origin, dir);
149  dist = VectorLength(dir);
150 
151  if (dist > loc_dist->value) {
152  continue;
153  }
154 
155  if (loc_trace->integer) {
156  CM_BoxTrace(&trace, pos, loc->origin, vec3_origin, vec3_origin,
157  cl.bsp->nodes, MASK_SOLID);
158  if (trace.fraction != 1.0f) {
159  continue;
160  }
161  }
162 
163  if (dist < minDist) {
164  minDist = dist;
165  nearest = loc;
166  }
167  }
168 
169  return nearest;
170 }
171 
172 /*
173 ==============
174 LOC_AddLocationsToScene
175 ==============
176 */
178 {
179  location_t *loc, *nearest;
180  vec3_t dir;
181  float dist;
182  entity_t ent;
183 
184  if (!loc_draw->integer) {
185  return;
186  }
187 
188  memset(&ent, 0, sizeof(ent));
189  ent.model = R_RegisterModel("models/items/c_head/tris.md2");
190  ent.skin = R_RegisterSkin("models/items/c_head/skin.pcx");
191 
193  if (!nearest) {
194  return;
195  }
196 
197  LIST_FOR_EACH(location_t, loc, &cl_locations, entry) {
198  VectorSubtract(cl.playerEntityOrigin, loc->origin, dir);
199  dist = VectorLength(dir);
200 
201  if (dist > loc_dist->integer) {
202  continue;
203  }
204 
205  VectorCopy(loc->origin, ent.origin);
206 
207  if (loc == nearest) {
208  ent.origin[2] += 10.0f * sin(cl.time * 0.01f);
209  V_AddLight(loc->origin, 200, 1, 1, 1);
210  }
211 
212  V_AddEntity(&ent);
213  }
214 }
215 
216 /*
217 ==============
218 LOC_Here_m
219 ==============
220 */
221 static size_t LOC_Here_m(char *buffer, size_t size)
222 {
223  location_t *loc;
224  size_t ret;
225 
226  ret = Q_strlcpy(buffer, "unknown", size);
227  if (cls.state != ca_active) {
228  return ret;
229  }
230 
232  if (loc) {
233  ret = Q_strlcpy(buffer, loc->name, size);
234  }
235 
236  return ret;
237 }
238 
239 /*
240 ==============
241 LOC_There_m
242 ==============
243 */
244 static size_t LOC_There_m(char *buffer, size_t size)
245 {
246  location_t *loc;
247  vec3_t pos;
248  trace_t trace;
249  int ret;
250 
251  ret = Q_strlcpy(buffer, "unknown", size);
252  if (cls.state != ca_active) {
253  return ret;
254  }
255 
256  VectorMA(cl.playerEntityOrigin, 8192, cl.v_forward, pos);
258  cl.bsp->nodes, MASK_SOLID);
259 
260  loc = LOC_FindClosest(trace.endpos);
261  if (loc) {
262  ret = Q_strlcpy(buffer, loc->name, size);
263  }
264 
265  return ret;
266 }
267 
268 static void LOC_Add_f(void)
269 {
270  location_t *loc;
271 
272  if (Cmd_Argc() < 2) {
273  Com_Printf("Usage: %s <name>\n", Cmd_Argv(0));
274  return;
275  }
276 
277  if (cls.state != ca_active) {
278  Com_Printf("Must be in a level.\n");
279  return;
280  }
281 
282  loc = LOC_Alloc(Cmd_Args());
283  VectorCopy(cl.playerEntityOrigin, loc->origin);
284  List_Append(&cl_locations, &loc->entry);
285 }
286 
287 static void LOC_Delete_f(void)
288 {
289  location_t *loc;
290 
291  if (cls.state != ca_active) {
292  Com_Printf("Must be in a level.\n");
293  return;
294  }
295 
297  if (!loc) {
298  Com_Printf("No closest location.\n");
299  return;
300  }
301 
302  List_Remove(&loc->entry);
303  Z_Free(loc);
304 }
305 
306 static void LOC_Update_f(void)
307 {
308  location_t *oldloc, *newloc;
309 
310  if (Cmd_Argc() < 2) {
311  Com_Printf("Usage: %s <name>\n", Cmd_Argv(0));
312  return;
313  }
314 
315  if (cls.state != ca_active) {
316  Com_Printf("Must be in a level.\n");
317  return;
318  }
319 
321  if (!oldloc) {
322  Com_Printf("No closest location.\n");
323  return;
324  }
325 
326  newloc = LOC_Alloc(Cmd_Args());
327  VectorCopy(oldloc->origin, newloc->origin);
328  List_Link(oldloc->entry.prev, oldloc->entry.next, &newloc->entry);
329  Z_Free(oldloc);
330 }
331 
332 static void LOC_Write_f(void)
333 {
334  char buffer[MAX_OSPATH];
335  location_t *loc;
336  qhandle_t f;
337  int count;
338 
339  if (cls.state != ca_active) {
340  Com_Printf("Must be in a level.\n");
341  return;
342  }
343 
344  if (LIST_EMPTY(&cl_locations)) {
345  Com_Printf("No locations to write.\n");
346  return;
347  }
348 
349  f = FS_EasyOpenFile(buffer, sizeof(buffer), FS_MODE_WRITE | FS_FLAG_TEXT,
350  "locs/", cl.mapname, ".loc");
351  if (!f) {
352  return;
353  }
354 
355  count = 0;
356  LIST_FOR_EACH(location_t, loc, &cl_locations, entry) {
357  FS_FPrintf(f, "%d %d %d %s\n",
358  (int)(loc->origin[0] * 8),
359  (int)(loc->origin[1] * 8),
360  (int)(loc->origin[2] * 8),
361  loc->name);
362  count++;
363  }
364 
365  Com_Printf("Wrote %d location%s to %s\n",
366  count, count == 1 ? "" : "s", buffer);
367 
368  FS_FCloseFile(f);
369 }
370 
371 /*
372 ==============
373 LOC_Init
374 ==============
375 */
376 void LOC_Init(void)
377 {
378  loc_trace = Cvar_Get("loc_trace", "0", 0);
379  loc_draw = Cvar_Get("loc_draw", "0", 0);
380  loc_dist = Cvar_Get("loc_dist", "500", 0);
381 
382  Cmd_AddMacro("loc_here", LOC_Here_m);
383  Cmd_AddMacro("loc_there", LOC_There_m);
384 
385  Cmd_AddCommand("loc_add", LOC_Add_f);
386  Cmd_AddCommand("loc_delete", LOC_Delete_f);
387  Cmd_AddCommand("loc_update", LOC_Update_f);
388  Cmd_AddCommand("loc_write", LOC_Write_f);
389 }
390 
client_state_s::bsp
bsp_t * bsp
Definition: client.h:300
loc_draw
static cvar_t * loc_draw
Definition: locs.c:33
CM_BoxTrace
void CM_BoxTrace(trace_t *trace, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, mnode_t *headnode, int brushmask)
Definition: cmodel.c:683
FS_EasyOpenFile
qhandle_t FS_EasyOpenFile(char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext)
Definition: files.c:1846
LOC_Update_f
static void LOC_Update_f(void)
Definition: locs.c:306
LOC_Write_f
static void LOC_Write_f(void)
Definition: locs.c:332
LIST_DECL
static LIST_DECL(cl_locations)
Cmd_AddCommand
void Cmd_AddCommand(const char *name, xcommand_t function)
Definition: cmd.c:1562
client_state_s::v_forward
vec3_t v_forward
Definition: client.h:258
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
Q_ErrorString
const char * Q_ErrorString(qerror_t error)
Definition: error.c:51
LOC_Delete_f
static void LOC_Delete_f(void)
Definition: locs.c:287
LOC_FreeLocations
void LOC_FreeLocations(void)
Definition: locs.c:122
ca_active
@ ca_active
Definition: client.h:340
FS_FPrintf
ssize_t FS_FPrintf(qhandle_t f, const char *format,...)
Definition: files.c:2039
client_static_s::state
connstate_t state
Definition: client.h:375
loc_trace
static cvar_t * loc_trace
Definition: locs.c:34
Cmd_Args
char * Cmd_Args(void)
Definition: cmd.c:933
Cmd_TokenizeString
void Cmd_TokenizeString(const char *text, qboolean macroExpand)
Definition: cmd.c:1399
Cmd_RawArgsFrom
char * Cmd_RawArgsFrom(int from)
Definition: cmd.c:1021
V_AddEntity
void V_AddEntity(entity_t *ent)
Definition: view.c:91
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:899
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:889
LOC_Alloc
static location_t * LOC_Alloc(const char *name)
Definition: locs.c:42
vec3_origin
vec3_t vec3_origin
Definition: shared.c:21
location_t::entry
list_t entry
Definition: locs.c:26
loc_dist
static cvar_t * loc_dist
Definition: locs.c:35
R_RegisterModel
qhandle_t R_RegisterModel(const char *name)
Definition: models.c:305
client_state_s::playerEntityOrigin
vec3_t playerEntityOrigin
Definition: client.h:263
LOC_AddLocationsToScene
void LOC_AddLocationsToScene(void)
Definition: locs.c:177
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
client_state_s::time
int time
Definition: client.h:244
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
LOC_LoadLocations
void LOC_LoadLocations(void)
Definition: locs.c:59
V_AddLight
#define V_AddLight(org, intensity, r, g, b)
Definition: client.h:728
LOC_Here_m
static size_t LOC_Here_m(char *buffer, size_t size)
Definition: locs.c:221
client_state_s::mapname
char mapname[MAX_QPATH]
Definition: client.h:290
location_t
Definition: locs.c:25
cl
client_state_t cl
Definition: main.c:99
cls
client_static_t cls
Definition: main.c:98
LOC_Init
void LOC_Init(void)
Definition: locs.c:376
location_t::origin
vec3_t origin
Definition: locs.c:27
LOC_Add_f
static void LOC_Add_f(void)
Definition: locs.c:268
client.h
LOC_There_m
static size_t LOC_There_m(char *buffer, size_t size)
Definition: locs.c:244
LOC_FindClosest
static location_t * LOC_FindClosest(vec3_t pos)
Definition: locs.c:138
Cmd_AddMacro
void Cmd_AddMacro(const char *name, xmacro_t function)
Definition: cmd.c:770
FS_FCloseFile
void FS_FCloseFile(qhandle_t f)
Definition: files.c:759
Q_concat
size_t Q_concat(char *dest, size_t size,...)
Definition: shared.c:758
location_t::name
char name[1]
Definition: locs.c:28