~ubuntu-branches/ubuntu/wily/nexuiz/wily

« back to all changes in this revision

Viewing changes to darkplaces/csprogs.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2009-10-16 12:52:25 UTC
  • mto: (1.1.7 upstream) (2.2.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 18.
  • Revision ID: james.westby@ubuntu.com-20091016125225-4mccppxccoa1w39o
ImportĀ upstreamĀ versionĀ 2.5.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include "quakedef.h"
2
 
#include "progsvm.h"
3
 
#include "clprogdefs.h"
4
 
#include "csprogs.h"
5
 
#include "cl_collision.h"
6
 
#include "snd_main.h"
7
 
#include "clvm_cmds.h"
8
 
 
9
 
//============================================================================
10
 
// Client prog handling
11
 
//[515]: omg !!! optimize it ! a lot of hacks here and there also :P
12
 
 
13
 
#define CSQC_RETURNVAL  prog->globals.generic[OFS_RETURN]
14
 
#define CSQC_BEGIN              csqc_tmpprog=prog;prog=0;PRVM_SetProg(PRVM_CLIENTPROG);
15
 
#define CSQC_END                prog=csqc_tmpprog;
16
 
static prvm_prog_t *csqc_tmpprog;
17
 
 
18
 
//[515]: these are required funcs
19
 
static char *cl_required_func[] =
20
 
{
21
 
        "CSQC_Init",
22
 
        "CSQC_InputEvent",
23
 
        "CSQC_UpdateView",
24
 
        "CSQC_ConsoleCommand",
25
 
};
26
 
 
27
 
static int cl_numrequiredfunc = sizeof(cl_required_func) / sizeof(char*);
28
 
 
29
 
void CL_VM_Error (const char *format, ...) DP_FUNC_PRINTF(1);
30
 
void CL_VM_Error (const char *format, ...)      //[515]: hope it will be never executed =)
31
 
{
32
 
        char errorstring[4096];
33
 
        va_list argptr;
34
 
 
35
 
        va_start (argptr, format);
36
 
        dpvsnprintf (errorstring, sizeof(errorstring), format, argptr);
37
 
        va_end (argptr);
38
 
//      Con_Printf( "CL_VM_Error: %s\n", errorstring );
39
 
 
40
 
        PRVM_Crash();
41
 
        cl.csqc_loaded = false;
42
 
 
43
 
        Cvar_SetValueQuick(&csqc_progcrc, -1);
44
 
        Cvar_SetValueQuick(&csqc_progsize, -1);
45
 
 
46
 
//      Host_AbortCurrentFrame();       //[515]: hmmm... if server says it needs csqc then client MUST disconnect
47
 
        Host_Error(va("CL_VM_Error: %s", errorstring));
48
 
}
49
 
void CL_VM_UpdateDmgGlobals (int dmg_take, int dmg_save, vec3_t dmg_origin)
50
 
{
51
 
        prvm_eval_t *val;
52
 
        if(cl.csqc_loaded)
53
 
        {
54
 
                CSQC_BEGIN
55
 
                val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.dmg_take);
56
 
                if(val)
57
 
                        val->_float = dmg_take;
58
 
                val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.dmg_save);
59
 
                if(val)
60
 
                        val->_float = dmg_save;
61
 
                val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.dmg_origin);
62
 
                if(val)
63
 
                {
64
 
                        val->vector[0] = dmg_origin[0];
65
 
                        val->vector[1] = dmg_origin[1];
66
 
                        val->vector[2] = dmg_origin[2];
67
 
                }
68
 
                CSQC_END
69
 
        }
70
 
}
71
 
//[515]: set globals before calling R_UpdateView, WEIRD CRAP
72
 
static void CSQC_SetGlobals (void)
73
 
{
74
 
        prvm_eval_t *val;
75
 
        CSQC_BEGIN
76
 
                prog->globals.client->time = cl.time;
77
 
                prog->globals.client->frametime = max(0, cl.time - cl.oldtime);
78
 
                prog->globals.client->servercommandframe = cls.servermovesequence;
79
 
                prog->globals.client->clientcommandframe = cl.movecmd[0].sequence;
80
 
                VectorCopy(cl.viewangles, prog->globals.client->input_angles);
81
 
                VectorCopy(cl.viewangles, cl.csqc_angles);
82
 
                // // FIXME: this actually belongs into getinputstate().. [12/17/2007 Black]
83
 
                prog->globals.client->input_buttons = cl.movecmd[0].buttons;
84
 
                VectorSet(prog->globals.client->input_movevalues, cl.movecmd[0].forwardmove, cl.movecmd[0].sidemove, cl.movecmd[0].upmove);
85
 
                //VectorCopy(cl.movement_origin, cl.csqc_origin);
86
 
                Matrix4x4_OriginFromMatrix(&cl.entities[cl.viewentity].render.matrix, cl.csqc_origin);
87
 
 
88
 
                // LordHavoc: Spike says not to do this, but without pmove_org the
89
 
                // CSQC is useless as it can't alter the view origin without
90
 
                // completely replacing it
91
 
                VectorCopy(cl.csqc_origin, prog->globals.client->pmove_org);
92
 
                VectorCopy(cl.velocity, prog->globals.client->pmove_vel);
93
 
 
94
 
                if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.view_angles)))
95
 
                        VectorCopy(cl.viewangles, val->vector);
96
 
                prog->globals.client->maxclients = cl.maxclients;
97
 
        CSQC_END
98
 
}
99
 
 
100
 
void CSQC_Predraw (prvm_edict_t *ed)
101
 
{
102
 
        int b;
103
 
        if(!ed->fields.client->predraw)
104
 
                return;
105
 
        b = prog->globals.client->self;
106
 
        prog->globals.client->self = PRVM_EDICT_TO_PROG(ed);
107
 
        PRVM_ExecuteProgram(ed->fields.client->predraw, "CSQC_Predraw: NULL function\n");
108
 
        prog->globals.client->self = b;
109
 
}
110
 
 
111
 
void CSQC_Think (prvm_edict_t *ed)
112
 
{
113
 
        int b;
114
 
        if(ed->fields.client->think)
115
 
        if(ed->fields.client->nextthink && ed->fields.client->nextthink <= prog->globals.client->time)
116
 
        {
117
 
                ed->fields.client->nextthink = 0;
118
 
                b = prog->globals.client->self;
119
 
                prog->globals.client->self = PRVM_EDICT_TO_PROG(ed);
120
 
                PRVM_ExecuteProgram(ed->fields.client->think, "CSQC_Think: NULL function\n");
121
 
                prog->globals.client->self = b;
122
 
        }
123
 
}
124
 
 
125
 
extern cvar_t cl_noplayershadow;
126
 
qboolean CSQC_AddRenderEdict(prvm_edict_t *ed)
127
 
{
128
 
        int renderflags;
129
 
        int c;
130
 
        float scale;
131
 
        prvm_eval_t *val;
132
 
        entity_render_t *entrender;
133
 
        dp_model_t *model;
134
 
        matrix4x4_t tagmatrix, matrix2;
135
 
 
136
 
        model = CL_GetModelFromEdict(ed);
137
 
        if (!model)
138
 
                return false;
139
 
 
140
 
        entrender = CL_NewTempEntity();
141
 
        if (!entrender)
142
 
                return false;
143
 
 
144
 
        entrender->model = model;
145
 
        entrender->skinnum = (int)ed->fields.client->skin;
146
 
        entrender->effects |= entrender->model->effects;
147
 
        scale = 1;
148
 
        renderflags = 0;
149
 
        if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.renderflags)) && val->_float)     renderflags = (int)val->_float;
150
 
        if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.alpha)) && val->_float)           entrender->alpha = val->_float;
151
 
        if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.scale)) && val->_float)           entrender->scale = scale = val->_float;
152
 
        if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, entrender->colormod);
153
 
        if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.effects)) && val->_float) entrender->effects |= (int)val->_float;
154
 
        if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.tag_entity)) && val->edict)
155
 
        {
156
 
                int tagentity;
157
 
                int tagindex = 0;
158
 
                tagentity = val->edict;
159
 
                if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.tag_index)) && val->_float)
160
 
                        tagindex = (int)val->_float;
161
 
                CL_GetTagMatrix (&tagmatrix, PRVM_PROG_TO_EDICT(tagentity), tagindex);
162
 
        }
163
 
        else
164
 
                Matrix4x4_CreateIdentity(&tagmatrix);
165
 
 
166
 
        if (renderflags & RF_USEAXIS)
167
 
        {
168
 
                vec3_t left;
169
 
                VectorNegate(prog->globals.client->v_right, left);
170
 
                Matrix4x4_FromVectors(&matrix2, prog->globals.client->v_forward, left, prog->globals.client->v_up, ed->fields.client->origin);
171
 
                Matrix4x4_Scale(&matrix2, scale, 1);
172
 
        }
173
 
        else
174
 
        {
175
 
                vec3_t angles;
176
 
                VectorCopy(ed->fields.client->angles, angles);
177
 
                // if model is alias, reverse pitch direction
178
 
                if (entrender->model->type == mod_alias)
179
 
                        angles[0] = -angles[0];
180
 
 
181
 
                // set up the render matrix
182
 
                Matrix4x4_CreateFromQuakeEntity(&matrix2, ed->fields.client->origin[0], ed->fields.client->origin[1], ed->fields.client->origin[2], angles[0], angles[1], angles[2], scale);
183
 
        }
184
 
 
185
 
        // set up the animation data
186
 
        // self.frame is the interpolation target (new frame)
187
 
        // self.frame1time is the animation base time for the interpolation target
188
 
        // self.frame2 is the interpolation start (previous frame)
189
 
        // self.frame2time is the animation base time for the interpolation start
190
 
        entrender->frame1 = entrender->frame2 = ed->fields.client->frame;
191
 
        if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2))) entrender->frame2 = val->_float;
192
 
        if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame1time))) entrender->frame2time = val->_float;
193
 
        if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2time))) entrender->frame1time = val->_float;
194
 
        if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac))) entrender->framelerp = val->_float;
195
 
 
196
 
        // concat the matrices to make the entity relative to its tag
197
 
        Matrix4x4_Concat(&entrender->matrix, &tagmatrix, &matrix2);
198
 
 
199
 
        if(renderflags)
200
 
        {
201
 
                if(renderflags & RF_VIEWMODEL)  entrender->flags |= RENDER_VIEWMODEL;
202
 
                if(renderflags & RF_EXTERNALMODEL)entrender->flags |= RENDER_EXTERIORMODEL;
203
 
                if(renderflags & RF_DEPTHHACK)  entrender->effects |= EF_NODEPTHTEST;
204
 
                if(renderflags & RF_ADDITIVE)           entrender->effects |= EF_ADDITIVE;
205
 
        }
206
 
 
207
 
        c = (int)ed->fields.client->colormap;
208
 
        if (c <= 0)
209
 
                CL_SetEntityColormapColors(entrender, -1);
210
 
        else if (c <= cl.maxclients && cl.scores != NULL)
211
 
                CL_SetEntityColormapColors(entrender, cl.scores[c-1].colors);
212
 
        else
213
 
                CL_SetEntityColormapColors(entrender, c);
214
 
 
215
 
        // either fullbright or lit
216
 
        if (!(entrender->effects & EF_FULLBRIGHT) && !r_fullbright.integer)
217
 
                entrender->flags |= RENDER_LIGHT;
218
 
        // hide player shadow during intermission or nehahra movie
219
 
        if (!(entrender->effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST))
220
 
         &&  (entrender->alpha >= 1)
221
 
         && !(entrender->flags & RENDER_VIEWMODEL)
222
 
         && (!(entrender->flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer)))
223
 
                entrender->flags |= RENDER_SHADOW;
224
 
        if (entrender->flags & RENDER_VIEWMODEL)
225
 
                entrender->flags |= RENDER_NOSELFSHADOW;
226
 
 
227
 
        // make the other useful stuff
228
 
        CL_UpdateRenderEntity(entrender);
229
 
 
230
 
        return true;
231
 
}
232
 
 
233
 
qboolean CL_VM_InputEvent (qboolean down, int key, int ascii)
234
 
{
235
 
        qboolean r;
236
 
 
237
 
        if(!cl.csqc_loaded)
238
 
                return false;
239
 
 
240
 
        CSQC_BEGIN
241
 
                if (!prog->funcoffsets.CSQC_InputEvent)
242
 
                        r = false;
243
 
                else
244
 
                {
245
 
                        prog->globals.client->time = cl.time;
246
 
                        prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
247
 
                        PRVM_G_FLOAT(OFS_PARM0) = !down; // 0 is down, 1 is up
248
 
                        PRVM_G_FLOAT(OFS_PARM1) = key;
249
 
                        PRVM_G_FLOAT(OFS_PARM2) = ascii;
250
 
                        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_InputEvent, "QC function CSQC_InputEvent is missing");
251
 
                        r = CSQC_RETURNVAL;
252
 
                }
253
 
        CSQC_END
254
 
        return r;
255
 
}
256
 
 
257
 
qboolean CL_VM_UpdateView (void)
258
 
{
259
 
        vec3_t emptyvector;
260
 
        emptyvector[0] = 0;
261
 
        emptyvector[1] = 0;
262
 
        emptyvector[2] = 0;
263
 
//      vec3_t oldangles;
264
 
        if(!cl.csqc_loaded)
265
 
                return false;
266
 
        CSQC_BEGIN
267
 
                //VectorCopy(cl.viewangles, oldangles);
268
 
                prog->globals.client->time = cl.time;
269
 
                prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
270
 
                CSQC_SetGlobals();
271
 
                // clear renderable entity and light lists to prevent crashes if the
272
 
                // CSQC_UpdateView function does not call R_ClearScene as it should
273
 
                r_refdef.scene.numentities = 0;
274
 
                r_refdef.scene.numlights = 0;
275
 
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_UpdateView, "QC function CSQC_UpdateView is missing");
276
 
                //VectorCopy(oldangles, cl.viewangles);
277
 
                // Dresk : Reset Dmg Globals Here
278
 
                CL_VM_UpdateDmgGlobals(0, 0, emptyvector);
279
 
        CSQC_END
280
 
        return true;
281
 
}
282
 
 
283
 
extern sizebuf_t vm_tempstringsbuf;
284
 
qboolean CL_VM_ConsoleCommand (const char *cmd)
285
 
{
286
 
        int restorevm_tempstringsbuf_cursize;
287
 
        qboolean r = false;
288
 
        if(!cl.csqc_loaded)
289
 
                return false;
290
 
        CSQC_BEGIN
291
 
        if (prog->funcoffsets.CSQC_ConsoleCommand)
292
 
        {
293
 
                prog->globals.client->time = cl.time;
294
 
                prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
295
 
                restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
296
 
                PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(cmd);
297
 
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_ConsoleCommand, "QC function CSQC_ConsoleCommand is missing");
298
 
                vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
299
 
                r = CSQC_RETURNVAL;
300
 
        }
301
 
        CSQC_END
302
 
        return r;
303
 
}
304
 
 
305
 
qboolean CL_VM_Parse_TempEntity (void)
306
 
{
307
 
        int                     t;
308
 
        qboolean        r = false;
309
 
        if(!cl.csqc_loaded)
310
 
                return false;
311
 
        CSQC_BEGIN
312
 
        if(prog->funcoffsets.CSQC_Parse_TempEntity)
313
 
        {
314
 
                t = msg_readcount;
315
 
                prog->globals.client->time = cl.time;
316
 
                prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
317
 
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_TempEntity, "QC function CSQC_Parse_TempEntity is missing");
318
 
                r = CSQC_RETURNVAL;
319
 
                if(!r)
320
 
                {
321
 
                        msg_readcount = t;
322
 
                        msg_badread = false;
323
 
                }
324
 
        }
325
 
        CSQC_END
326
 
        return r;
327
 
}
328
 
 
329
 
void CL_VM_Parse_StuffCmd (const char *msg)
330
 
{
331
 
        int restorevm_tempstringsbuf_cursize;
332
 
        if(msg[0] == 'c')
333
 
        if(msg[1] == 's')
334
 
        if(msg[2] == 'q')
335
 
        if(msg[3] == 'c')
336
 
        {
337
 
                // if this is setting a csqc variable, deprotect csqc_progcrc
338
 
                // temporarily so that it can be set by the cvar command,
339
 
                // and then reprotect it afterwards
340
 
                int crcflags = csqc_progcrc.flags;
341
 
                int sizeflags = csqc_progcrc.flags;
342
 
                csqc_progcrc.flags &= ~CVAR_READONLY;
343
 
                csqc_progsize.flags &= ~CVAR_READONLY;
344
 
                Cmd_ExecuteString (msg, src_command);
345
 
                csqc_progcrc.flags = crcflags;
346
 
                csqc_progsize.flags = sizeflags;
347
 
                return;
348
 
        }
349
 
        if(!cl.csqc_loaded)
350
 
        {
351
 
                Cbuf_AddText(msg);
352
 
                return;
353
 
        }
354
 
        CSQC_BEGIN
355
 
        if(prog->funcoffsets.CSQC_Parse_StuffCmd)
356
 
        {
357
 
                prog->globals.client->time = cl.time;
358
 
                prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
359
 
                restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
360
 
                PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
361
 
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_StuffCmd, "QC function CSQC_Parse_StuffCmd is missing");
362
 
                vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
363
 
        }
364
 
        else
365
 
                Cbuf_AddText(msg);
366
 
        CSQC_END
367
 
}
368
 
 
369
 
static void CL_VM_Parse_Print (const char *msg)
370
 
{
371
 
        int restorevm_tempstringsbuf_cursize;
372
 
        prog->globals.client->time = cl.time;
373
 
        prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
374
 
        restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
375
 
        PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
376
 
        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_Print, "QC function CSQC_Parse_Print is missing");
377
 
        vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
378
 
}
379
 
 
380
 
void CSQC_AddPrintText (const char *msg)
381
 
{
382
 
        size_t i;
383
 
        if(!cl.csqc_loaded)
384
 
        {
385
 
                Con_Print(msg);
386
 
                return;
387
 
        }
388
 
        CSQC_BEGIN
389
 
        if(prog->funcoffsets.CSQC_Parse_Print)
390
 
        {
391
 
                // FIXME: is this bugged?
392
 
                i = strlen(msg)-1;
393
 
                if(msg[i] != '\n' && msg[i] != '\r')
394
 
                {
395
 
                        if(strlen(cl.csqc_printtextbuf)+i >= MAX_INPUTLINE)
396
 
                        {
397
 
                                CL_VM_Parse_Print(cl.csqc_printtextbuf);
398
 
                                cl.csqc_printtextbuf[0] = 0;
399
 
                        }
400
 
                        else
401
 
                                strlcat(cl.csqc_printtextbuf, msg, MAX_INPUTLINE);
402
 
                        return;
403
 
                }
404
 
                strlcat(cl.csqc_printtextbuf, msg, MAX_INPUTLINE);
405
 
                CL_VM_Parse_Print(cl.csqc_printtextbuf);
406
 
                cl.csqc_printtextbuf[0] = 0;
407
 
        }
408
 
        else
409
 
                Con_Print(msg);
410
 
        CSQC_END
411
 
}
412
 
 
413
 
void CL_VM_Parse_CenterPrint (const char *msg)
414
 
{
415
 
        int restorevm_tempstringsbuf_cursize;
416
 
        if(!cl.csqc_loaded)
417
 
        {
418
 
                SCR_CenterPrint((char*)msg);
419
 
                return;
420
 
        }
421
 
        CSQC_BEGIN
422
 
        if(prog->funcoffsets.CSQC_Parse_CenterPrint)
423
 
        {
424
 
                prog->globals.client->time = cl.time;
425
 
                prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
426
 
                restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
427
 
                PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
428
 
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_CenterPrint, "QC function CSQC_Parse_CenterPrint is missing");
429
 
                vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
430
 
        }
431
 
        else
432
 
                SCR_CenterPrint((char*)msg);
433
 
        CSQC_END
434
 
}
435
 
 
436
 
void CL_VM_UpdateIntermissionState (int intermission)
437
 
{
438
 
        prvm_eval_t *val;
439
 
        if(cl.csqc_loaded)
440
 
        {
441
 
                CSQC_BEGIN
442
 
                val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.intermission);
443
 
                if(val)
444
 
                        val->_float = intermission;
445
 
                CSQC_END
446
 
        }
447
 
}
448
 
void CL_VM_UpdateShowingScoresState (int showingscores)
449
 
{
450
 
        prvm_eval_t *val;
451
 
        if(cl.csqc_loaded)
452
 
        {
453
 
                CSQC_BEGIN
454
 
                val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.sb_showscores);
455
 
                if(val)
456
 
                        val->_float = showingscores;
457
 
                CSQC_END
458
 
        }
459
 
}
460
 
qboolean CL_VM_Event_Sound(int sound_num, int volume, int channel, float attenuation, int ent, vec3_t pos)
461
 
{
462
 
        qboolean r = false;
463
 
        if(cl.csqc_loaded)
464
 
        {
465
 
                CSQC_BEGIN
466
 
                if(prog->funcoffsets.CSQC_Event_Sound)
467
 
                {
468
 
                        prog->globals.client->time = cl.time;
469
 
                        prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
470
 
                        PRVM_G_FLOAT(OFS_PARM0) = ent;
471
 
                        PRVM_G_FLOAT(OFS_PARM1) = channel;
472
 
                        PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(cl.sound_name[sound_num] );
473
 
                        PRVM_G_FLOAT(OFS_PARM3) = volume;
474
 
                        PRVM_G_FLOAT(OFS_PARM4) = attenuation;
475
 
                        VectorCopy(pos, PRVM_G_VECTOR(OFS_PARM5) );
476
 
                        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Event_Sound, "QC function CSQC_Event_Sound is missing");
477
 
                        r = CSQC_RETURNVAL;
478
 
                }
479
 
                CSQC_END
480
 
        }
481
 
 
482
 
        return r;
483
 
}
484
 
void CL_VM_UpdateCoopDeathmatchGlobals (int gametype)
485
 
{
486
 
        // Avoid global names for clean(er) coding
487
 
        int localcoop;
488
 
        int localdeathmatch;
489
 
 
490
 
        prvm_eval_t *val;
491
 
        if(cl.csqc_loaded)
492
 
        {
493
 
                if(gametype == GAME_COOP)
494
 
                {
495
 
                        localcoop = 1;
496
 
                        localdeathmatch = 0;
497
 
                }
498
 
                else
499
 
                if(gametype == GAME_DEATHMATCH)
500
 
                {
501
 
                        localcoop = 0;
502
 
                        localdeathmatch = 1;
503
 
                }
504
 
                else
505
 
                {
506
 
                        // How did the ServerInfo send an unknown gametype?
507
 
                        // Better just assign the globals as 0...
508
 
                        localcoop = 0;
509
 
                        localdeathmatch = 0;
510
 
                }
511
 
                CSQC_BEGIN
512
 
                val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.coop);
513
 
                if(val)
514
 
                        val->_float = localcoop;
515
 
                val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.deathmatch);
516
 
                if(val)
517
 
                        val->_float = localdeathmatch;
518
 
                CSQC_END
519
 
        }
520
 
}
521
 
float CL_VM_Event (float event)         //[515]: needed ? I'd say "YES", but don't know for what :D
522
 
{
523
 
        float r = 0;
524
 
        if(!cl.csqc_loaded)
525
 
                return 0;
526
 
        CSQC_BEGIN
527
 
        if(prog->funcoffsets.CSQC_Event)
528
 
        {
529
 
                prog->globals.client->time = cl.time;
530
 
                prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
531
 
                PRVM_G_FLOAT(OFS_PARM0) = event;
532
 
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Event, "QC function CSQC_Event is missing");
533
 
                r = CSQC_RETURNVAL;
534
 
        }
535
 
        CSQC_END
536
 
        return r;
537
 
}
538
 
 
539
 
void CSQC_ReadEntities (void)
540
 
{
541
 
        unsigned short entnum, oldself, realentnum;
542
 
        if(!cl.csqc_loaded)
543
 
        {
544
 
                Host_Error ("CSQC_ReadEntities: CSQC is not loaded");
545
 
                return;
546
 
        }
547
 
 
548
 
        CSQC_BEGIN
549
 
                prog->globals.client->time = cl.time;
550
 
                oldself = prog->globals.client->self;
551
 
                while(1)
552
 
                {
553
 
                        entnum = MSG_ReadShort();
554
 
                        if(!entnum || msg_badread)
555
 
                                return;
556
 
                        realentnum = entnum & 0x7FFF;
557
 
                        prog->globals.client->self = cl.csqc_server2csqcentitynumber[realentnum];
558
 
                        if(entnum & 0x8000)
559
 
                        {
560
 
                                if(prog->globals.client->self)
561
 
                                {
562
 
                                        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Remove, "QC function CSQC_Ent_Remove is missing");
563
 
                                        cl.csqc_server2csqcentitynumber[realentnum] = 0;
564
 
                                }
565
 
                                else
566
 
                                        Con_Printf("Bad csqc_server2csqcentitynumber map\n");   //[515]: never happens ?
567
 
                        }
568
 
                        else
569
 
                        {
570
 
                                if(!prog->globals.client->self)
571
 
                                {
572
 
                                        if(!prog->funcoffsets.CSQC_Ent_Spawn)
573
 
                                        {
574
 
                                                prvm_edict_t    *ed;
575
 
                                                ed = PRVM_ED_Alloc();
576
 
                                                ed->fields.client->entnum = realentnum;
577
 
                                                prog->globals.client->self = cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT_TO_PROG(ed);
578
 
                                        }
579
 
                                        else
580
 
                                        {
581
 
                                                // entity( float entnum ) CSQC_Ent_Spawn;
582
 
                                                // the qc function should set entnum, too (this way it also can return world [2/1/2008 Andreas]
583
 
                                                PRVM_G_FLOAT(OFS_PARM0) = (float) realentnum;
584
 
                                                // make sure no one gets wrong ideas
585
 
                                                prog->globals.client->self = 0;
586
 
                                                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Spawn, "QC function CSQC_Ent_Spawn is missing");
587
 
                                                prog->globals.client->self = cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT( PRVM_G_INT( OFS_RETURN ) );
588
 
                                        }
589
 
                                        PRVM_G_FLOAT(OFS_PARM0) = 1;
590
 
                                        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Update, "QC function CSQC_Ent_Update is missing");
591
 
                                }
592
 
                                else {
593
 
                                        PRVM_G_FLOAT(OFS_PARM0) = 0;
594
 
                                        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Update, "QC function CSQC_Ent_Update is missing");
595
 
                                }
596
 
                        }
597
 
                }
598
 
                prog->globals.client->self = oldself;
599
 
        CSQC_END
600
 
}
601
 
 
602
 
void CL_VM_CB_BeginIncreaseEdicts(void)
603
 
{
604
 
        // links don't survive the transition, so unlink everything
605
 
        World_UnlinkAll(&cl.world);
606
 
}
607
 
 
608
 
void CL_VM_CB_EndIncreaseEdicts(void)
609
 
{
610
 
        int i;
611
 
        prvm_edict_t *ent;
612
 
 
613
 
        // link every entity except world
614
 
        for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
615
 
                if (!ent->priv.server->free)
616
 
                        CL_LinkEdict(ent);
617
 
}
618
 
 
619
 
void CL_VM_CB_InitEdict(prvm_edict_t *e)
620
 
{
621
 
        e->priv.server->move = false; // don't move on first frame
622
 
}
623
 
 
624
 
void CL_VM_CB_FreeEdict(prvm_edict_t *ed)
625
 
{
626
 
        World_UnlinkEdict(ed);
627
 
        memset(ed->fields.client, 0, sizeof(*ed->fields.client));
628
 
}
629
 
 
630
 
void CL_VM_CB_CountEdicts(void)
631
 
{
632
 
        int             i;
633
 
        prvm_edict_t    *ent;
634
 
        int             active = 0, models = 0, solid = 0;
635
 
 
636
 
        for (i=0 ; i<prog->num_edicts ; i++)
637
 
        {
638
 
                ent = PRVM_EDICT_NUM(i);
639
 
                if (ent->priv.server->free)
640
 
                        continue;
641
 
                active++;
642
 
                if (ent->fields.client->solid)
643
 
                        solid++;
644
 
                if (ent->fields.client->model)
645
 
                        models++;
646
 
        }
647
 
 
648
 
        Con_Printf("num_edicts:%3i\n", prog->num_edicts);
649
 
        Con_Printf("active    :%3i\n", active);
650
 
        Con_Printf("view      :%3i\n", models);
651
 
        Con_Printf("touch     :%3i\n", solid);
652
 
}
653
 
 
654
 
qboolean CL_VM_CB_LoadEdict(prvm_edict_t *ent)
655
 
{
656
 
        return true;
657
 
}
658
 
 
659
 
void Cmd_ClearCsqcFuncs (void);
660
 
 
661
 
void CL_VM_Init (void)
662
 
{
663
 
        const char* csprogsfn;
664
 
        unsigned char *csprogsdata;
665
 
        fs_offset_t csprogsdatasize;
666
 
        int csprogsdatacrc, requiredcrc;
667
 
        int requiredsize;
668
 
        prvm_eval_t *val;
669
 
 
670
 
        // reset csqc_progcrc after reading it, so that changing servers doesn't
671
 
        // expect csqc on the next server
672
 
        requiredcrc = csqc_progcrc.integer;
673
 
        requiredsize = csqc_progsize.integer;
674
 
        Cvar_SetValueQuick(&csqc_progcrc, -1);
675
 
        Cvar_SetValueQuick(&csqc_progsize, -1);
676
 
 
677
 
        // if the server is not requesting a csprogs, then we're done here
678
 
        if (requiredcrc < 0)
679
 
                return;
680
 
 
681
 
        // see if the requested csprogs.dat file matches the requested crc
682
 
        csprogsdatacrc = -1;
683
 
        csprogsfn = va("dlcache/%s.%i.%i", csqc_progname.string, requiredsize, requiredcrc);
684
 
        csprogsdata = FS_LoadFile(csprogsfn, tempmempool, true, &csprogsdatasize);
685
 
        if (!csprogsdata)
686
 
        {
687
 
                csprogsfn = csqc_progname.string;
688
 
                csprogsdata = FS_LoadFile(csprogsfn, tempmempool, true, &csprogsdatasize);
689
 
        }
690
 
        if (csprogsdata)
691
 
        {
692
 
                csprogsdatacrc = CRC_Block(csprogsdata, csprogsdatasize);
693
 
                Mem_Free(csprogsdata);
694
 
                if (csprogsdatacrc != requiredcrc || csprogsdatasize != requiredsize)
695
 
                {
696
 
                        if (cls.demoplayback)
697
 
                        {
698
 
                                Con_Printf("^1Warning: Your %s is not the same version as the demo was recorded with (CRC/size are %i/%i but should be %i/%i)\n", csqc_progname.string, csprogsdatacrc, (int)csprogsdatasize, requiredcrc, requiredsize);
699
 
                                return;
700
 
                        }
701
 
                        else
702
 
                        {
703
 
                                Con_Printf("^1Your %s is not the same version as the server (CRC is %i/%i but should be %i/%i)\n", csqc_progname.string, csprogsdatacrc, (int)csprogsdatasize, requiredcrc, requiredsize);
704
 
                                CL_Disconnect();
705
 
                                return;
706
 
                        }
707
 
                }
708
 
        }
709
 
        else
710
 
        {
711
 
                if (requiredcrc >= 0)
712
 
                {
713
 
                        if (cls.demoplayback)
714
 
                                Con_Printf("CL_VM_Init: demo requires CSQC, but \"%s\" wasn't found\n", csqc_progname.string);
715
 
                        else
716
 
                                Con_Printf("CL_VM_Init: server requires CSQC, but \"%s\" wasn't found\n", csqc_progname.string);
717
 
                        CL_Disconnect();
718
 
                }
719
 
                return;
720
 
        }
721
 
 
722
 
        PRVM_Begin;
723
 
        PRVM_InitProg(PRVM_CLIENTPROG);
724
 
 
725
 
        // allocate the mempools
726
 
        prog->progs_mempool = Mem_AllocPool(csqc_progname.string, 0, NULL);
727
 
        prog->headercrc = CL_PROGHEADER_CRC;
728
 
        prog->edictprivate_size = 0; // no private struct used
729
 
        prog->name = CL_NAME;
730
 
        prog->num_edicts = 1;
731
 
        prog->max_edicts = 512;
732
 
        prog->limit_edicts = CL_MAX_EDICTS;
733
 
        prog->reserved_edicts = 0;
734
 
        prog->edictprivate_size = sizeof(edict_engineprivate_t);
735
 
        // TODO: add a shared extension string #define and add real support for csqc extension strings [12/5/2007 Black]
736
 
        prog->extensionstring = vm_sv_extensions;
737
 
        prog->builtins = vm_cl_builtins;
738
 
        prog->numbuiltins = vm_cl_numbuiltins;
739
 
        prog->begin_increase_edicts = CL_VM_CB_BeginIncreaseEdicts;
740
 
        prog->end_increase_edicts = CL_VM_CB_EndIncreaseEdicts;
741
 
        prog->init_edict = CL_VM_CB_InitEdict;
742
 
        prog->free_edict = CL_VM_CB_FreeEdict;
743
 
        prog->count_edicts = CL_VM_CB_CountEdicts;
744
 
        prog->load_edict = CL_VM_CB_LoadEdict;
745
 
        prog->init_cmd = VM_CL_Cmd_Init;
746
 
        prog->reset_cmd = VM_CL_Cmd_Reset;
747
 
        prog->error_cmd = CL_VM_Error;
748
 
 
749
 
        PRVM_LoadProgs(csprogsfn, cl_numrequiredfunc, cl_required_func, 0, NULL, 0, NULL);
750
 
 
751
 
        if (!prog->loaded)
752
 
        {
753
 
                CL_VM_Error("CSQC %s ^2failed to load\n", csprogsfn);
754
 
                if(!sv.active)
755
 
                        CL_Disconnect();
756
 
                return;
757
 
        }
758
 
 
759
 
        Con_Printf("CSQC %s ^5loaded (crc=%i, size=%i)\n", csprogsfn, csprogsdatacrc, (int)csprogsdatasize);
760
 
 
761
 
        // check if OP_STATE animation is possible in this dat file
762
 
        if (prog->fieldoffsets.nextthink >= 0 && prog->fieldoffsets.frame >= 0 && prog->fieldoffsets.think >= 0 && prog->globaloffsets.self >= 0)
763
 
                prog->flag |= PRVM_OP_STATE;
764
 
 
765
 
        // set time
766
 
        prog->globals.client->time = cl.time;
767
 
        prog->globals.client->self = 0;
768
 
 
769
 
        prog->globals.client->mapname = cl.worldmodel ? PRVM_SetEngineString(cl.worldmodel->name) : PRVM_SetEngineString("");
770
 
        prog->globals.client->player_localentnum = cl.playerentity;
771
 
 
772
 
        // set map description (use world entity 0)
773
 
        val = PRVM_EDICTFIELDVALUE(prog->edicts, prog->fieldoffsets.message);
774
 
        if(val)
775
 
                val->string = PRVM_SetEngineString(cl.levelname);
776
 
        VectorCopy(cl.world.mins, prog->edicts->fields.client->mins);
777
 
        VectorCopy(cl.world.maxs, prog->edicts->fields.client->maxs);
778
 
 
779
 
        // call the prog init
780
 
        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Init, "QC function CSQC_Init is missing");
781
 
 
782
 
        PRVM_End;
783
 
        cl.csqc_loaded = true;
784
 
 
785
 
        cl.csqc_vidvars.drawcrosshair = false;
786
 
        cl.csqc_vidvars.drawenginesbar = false;
787
 
 
788
 
        // Update Coop and Deathmatch Globals (at this point the client knows them from ServerInfo)
789
 
        CL_VM_UpdateCoopDeathmatchGlobals(cl.gametype);
790
 
}
791
 
 
792
 
void CL_VM_ShutDown (void)
793
 
{
794
 
        Cmd_ClearCsqcFuncs();
795
 
        Cvar_SetValueQuick(&csqc_progcrc, -1);
796
 
        Cvar_SetValueQuick(&csqc_progsize, -1);
797
 
        if(!cl.csqc_loaded)
798
 
                return;
799
 
        CSQC_BEGIN
800
 
                prog->globals.client->time = cl.time;
801
 
                prog->globals.client->self = 0;
802
 
                if (prog->funcoffsets.CSQC_Shutdown)
803
 
                        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Shutdown, "QC function CSQC_Shutdown is missing");
804
 
                PRVM_ResetProg();
805
 
        CSQC_END
806
 
        Con_Print("CSQC ^1unloaded\n");
807
 
        cl.csqc_loaded = false;
808
 
}