+//====================
+// DP_CSQC_SPAWNPARTICLE
+// a QC hook to engine's CL_NewParticle
+//====================
+
+// particle theme struct
+typedef struct vmparticletheme_s
+{
+ unsigned short typeindex;
+ qboolean initialized;
+ pblend_t blendmode;
+ porientation_t orientation;
+ int color1;
+ int color2;
+ int tex;
+ float size;
+ float sizeincrease;
+ float alpha;
+ float alphafade;
+ float gravity;
+ float bounce;
+ float airfriction;
+ float liquidfriction;
+ float originjitter;
+ float velocityjitter;
+ qboolean qualityreduction;
+ float lifetime;
+ float stretch;
+ int staincolor1;
+ int staincolor2;
+ int staintex;
+ float stainalpha;
+ float stainsize;
+ float delayspawn;
+ float delaycollision;
+ float angle;
+ float spin;
+}vmparticletheme_t;
+
+// particle spawner
+typedef struct vmparticlespawner_s
+{
+ mempool_t *pool;
+ qboolean initialized;
+ qboolean verified;
+ vmparticletheme_t *themes;
+ int max_themes;
+ // global addresses
+ float *particle_type;
+ float *particle_blendmode;
+ float *particle_orientation;
+ float *particle_color1;
+ float *particle_color2;
+ float *particle_tex;
+ float *particle_size;
+ float *particle_sizeincrease;
+ float *particle_alpha;
+ float *particle_alphafade;
+ float *particle_time;
+ float *particle_gravity;
+ float *particle_bounce;
+ float *particle_airfriction;
+ float *particle_liquidfriction;
+ float *particle_originjitter;
+ float *particle_velocityjitter;
+ float *particle_qualityreduction;
+ float *particle_stretch;
+ float *particle_staincolor1;
+ float *particle_staincolor2;
+ float *particle_stainalpha;
+ float *particle_stainsize;
+ float *particle_staintex;
+ float *particle_delayspawn;
+ float *particle_delaycollision;
+ float *particle_angle;
+ float *particle_spin;
+}vmparticlespawner_t;
+
+vmparticlespawner_t vmpartspawner;
+
+// TODO: automatic max_themes grow
+static void VM_InitParticleSpawner (int maxthemes)
+{
+ prvm_eval_t *val;
+
+ // bound max themes to not be an insane value
+ if (maxthemes < 4)
+ maxthemes = 4;
+ if (maxthemes > 2048)
+ maxthemes = 2048;
+ // allocate and set up structure
+ if (vmpartspawner.initialized) // reallocate
+ {
+ Mem_FreePool(&vmpartspawner.pool);
+ memset(&vmpartspawner, 0, sizeof(vmparticlespawner_t));
+ }
+ vmpartspawner.pool = Mem_AllocPool("VMPARTICLESPAWNER", 0, NULL);
+ vmpartspawner.themes = (vmparticletheme_t *)Mem_Alloc(vmpartspawner.pool, sizeof(vmparticletheme_t)*maxthemes);
+ vmpartspawner.max_themes = maxthemes;
+ vmpartspawner.initialized = true;
+ vmpartspawner.verified = true;
+ // get field addresses for fast querying (we can do 1000 calls of spawnparticle in a frame)
+ #define getglobal(v,s) val = PRVM_GLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset(s)); if (val) { vmpartspawner.v = &val->_float; } else { VM_Warning("VM_InitParticleSpawner: missing global '%s', spawner cannot work\n", s); vmpartspawner.verified = false; }
+ #define getglobalvector(v,s) val = PRVM_GLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset(s)); if (val) { vmpartspawner.v = (float *)val->vector; } else { VM_Warning("VM_InitParticleSpawner: missing global '%s', spawner cannot work\n", s); vmpartspawner.verified = false; }
+ getglobal(particle_type, "particle_type");
+ getglobal(particle_blendmode, "particle_blendmode");
+ getglobal(particle_orientation, "particle_orientation");
+ getglobalvector(particle_color1, "particle_color1");
+ getglobalvector(particle_color2, "particle_color2");
+ getglobal(particle_tex, "particle_tex");
+ getglobal(particle_size, "particle_size");
+ getglobal(particle_sizeincrease, "particle_sizeincrease");
+ getglobal(particle_alpha, "particle_alpha");
+ getglobal(particle_alphafade, "particle_alphafade");
+ getglobal(particle_time, "particle_time");
+ getglobal(particle_gravity, "particle_gravity");
+ getglobal(particle_bounce, "particle_bounce");
+ getglobal(particle_airfriction, "particle_airfriction");
+ getglobal(particle_liquidfriction, "particle_liquidfriction");
+ getglobal(particle_originjitter, "particle_originjitter");
+ getglobal(particle_velocityjitter, "particle_velocityjitter");
+ getglobal(particle_qualityreduction, "particle_qualityreduction");
+ getglobal(particle_stretch, "particle_stretch");
+ getglobalvector(particle_staincolor1, "particle_staincolor1");
+ getglobalvector(particle_staincolor2, "particle_staincolor2");
+ getglobal(particle_stainalpha, "particle_stainalpha");
+ getglobal(particle_stainsize, "particle_stainsize");
+ getglobal(particle_staintex, "particle_staintex");
+ getglobal(particle_staintex, "particle_staintex");
+ getglobal(particle_delayspawn, "particle_delayspawn");
+ getglobal(particle_delaycollision, "particle_delaycollision");
+ getglobal(particle_angle, "particle_angle");
+ getglobal(particle_spin, "particle_spin");
+ #undef getglobal
+ #undef getglobalvector
+}
+
+// reset particle theme to default values
+static void VM_ResetParticleTheme (vmparticletheme_t *theme)
+{
+ theme->initialized = true;
+ theme->typeindex = pt_static;
+ theme->blendmode = PBLEND_ADD;
+ theme->orientation = PARTICLE_BILLBOARD;
+ theme->color1 = 0x808080;
+ theme->color2 = 0xFFFFFF;
+ theme->tex = 63;
+ theme->size = 2;
+ theme->sizeincrease = 0;
+ theme->alpha = 256;
+ theme->alphafade = 512;
+ theme->gravity = 0.0f;
+ theme->bounce = 0.0f;
+ theme->airfriction = 1.0f;
+ theme->liquidfriction = 4.0f;
+ theme->originjitter = 0.0f;
+ theme->velocityjitter = 0.0f;
+ theme->qualityreduction = false;
+ theme->lifetime = 4;
+ theme->stretch = 1;
+ theme->staincolor1 = -1;
+ theme->staincolor2 = -1;
+ theme->staintex = -1;
+ theme->delayspawn = 0.0f;
+ theme->delaycollision = 0.0f;
+ theme->angle = 0.0f;
+ theme->spin = 0.0f;
+}
+
+// particle theme -> QC globals
+void VM_CL_ParticleThemeToGlobals(vmparticletheme_t *theme)
+{
+ *vmpartspawner.particle_type = theme->typeindex;
+ *vmpartspawner.particle_blendmode = theme->blendmode;
+ *vmpartspawner.particle_orientation = theme->orientation;
+ vmpartspawner.particle_color1[0] = (theme->color1 >> 16) & 0xFF; // VorteX: int only can store 0-255, not 0-256 which means 0 - 0,99609375...
+ vmpartspawner.particle_color1[1] = (theme->color1 >> 8) & 0xFF;
+ vmpartspawner.particle_color1[2] = (theme->color1 >> 0) & 0xFF;
+ vmpartspawner.particle_color2[0] = (theme->color2 >> 16) & 0xFF;
+ vmpartspawner.particle_color2[1] = (theme->color2 >> 8) & 0xFF;
+ vmpartspawner.particle_color2[2] = (theme->color2 >> 0) & 0xFF;
+ *vmpartspawner.particle_tex = (float)theme->tex;
+ *vmpartspawner.particle_size = theme->size;
+ *vmpartspawner.particle_sizeincrease = theme->sizeincrease;
+ *vmpartspawner.particle_alpha = theme->alpha/256;
+ *vmpartspawner.particle_alphafade = theme->alphafade/256;
+ *vmpartspawner.particle_time = theme->lifetime;
+ *vmpartspawner.particle_gravity = theme->gravity;
+ *vmpartspawner.particle_bounce = theme->bounce;
+ *vmpartspawner.particle_airfriction = theme->airfriction;
+ *vmpartspawner.particle_liquidfriction = theme->liquidfriction;
+ *vmpartspawner.particle_originjitter = theme->originjitter;
+ *vmpartspawner.particle_velocityjitter = theme->velocityjitter;
+ *vmpartspawner.particle_qualityreduction = theme->qualityreduction;
+ *vmpartspawner.particle_stretch = theme->stretch;
+ vmpartspawner.particle_staincolor1[0] = ((int)theme->staincolor1 >> 16) & 0xFF;
+ vmpartspawner.particle_staincolor1[1] = ((int)theme->staincolor1 >> 8) & 0xFF;
+ vmpartspawner.particle_staincolor1[2] = ((int)theme->staincolor1 >> 0) & 0xFF;
+ vmpartspawner.particle_staincolor2[0] = ((int)theme->staincolor2 >> 16) & 0xFF;
+ vmpartspawner.particle_staincolor2[1] = ((int)theme->staincolor2 >> 8) & 0xFF;
+ vmpartspawner.particle_staincolor2[2] = ((int)theme->staincolor2 >> 0) & 0xFF;
+ *vmpartspawner.particle_staintex = (float)theme->staintex;
+ *vmpartspawner.particle_stainalpha = (float)theme->stainalpha/256;
+ *vmpartspawner.particle_stainsize = (float)theme->stainsize;
+ *vmpartspawner.particle_delayspawn = theme->delayspawn;
+ *vmpartspawner.particle_delaycollision = theme->delaycollision;
+ *vmpartspawner.particle_angle = theme->angle;
+ *vmpartspawner.particle_spin = theme->spin;
+}
+
+// QC globals -> particle theme
+void VM_CL_ParticleThemeFromGlobals(vmparticletheme_t *theme)
+{
+ theme->typeindex = (unsigned short)*vmpartspawner.particle_type;
+ theme->blendmode = (pblend_t)*vmpartspawner.particle_blendmode;
+ theme->orientation = (porientation_t)*vmpartspawner.particle_orientation;
+ theme->color1 = ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]);
+ theme->color2 = ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]);
+ theme->tex = (int)*vmpartspawner.particle_tex;
+ theme->size = *vmpartspawner.particle_size;
+ theme->sizeincrease = *vmpartspawner.particle_sizeincrease;
+ theme->alpha = *vmpartspawner.particle_alpha*256;
+ theme->alphafade = *vmpartspawner.particle_alphafade*256;
+ theme->lifetime = *vmpartspawner.particle_time;
+ theme->gravity = *vmpartspawner.particle_gravity;
+ theme->bounce = *vmpartspawner.particle_bounce;
+ theme->airfriction = *vmpartspawner.particle_airfriction;
+ theme->liquidfriction = *vmpartspawner.particle_liquidfriction;
+ theme->originjitter = *vmpartspawner.particle_originjitter;
+ theme->velocityjitter = *vmpartspawner.particle_velocityjitter;
+ theme->qualityreduction = (*vmpartspawner.particle_qualityreduction) ? true : false;
+ theme->stretch = *vmpartspawner.particle_stretch;
+ theme->staincolor1 = ((int)vmpartspawner.particle_staincolor1[0])*65536 + (int)(vmpartspawner.particle_staincolor1[1])*256 + (int)(vmpartspawner.particle_staincolor1[2]);
+ theme->staincolor2 = (int)(vmpartspawner.particle_staincolor2[0])*65536 + (int)(vmpartspawner.particle_staincolor2[1])*256 + (int)(vmpartspawner.particle_staincolor2[2]);
+ theme->staintex =(int)*vmpartspawner.particle_staintex;
+ theme->stainalpha = *vmpartspawner.particle_stainalpha*256;
+ theme->stainsize = *vmpartspawner.particle_stainsize;
+ theme->delayspawn = *vmpartspawner.particle_delayspawn;
+ theme->delaycollision = *vmpartspawner.particle_delaycollision;
+ theme->angle = *vmpartspawner.particle_angle;
+ theme->spin = *vmpartspawner.particle_spin;
+}
+
+// init particle spawner interface
+// # float(float max_themes) initparticlespawner
+void VM_CL_InitParticleSpawner (void)
+{
+ VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_InitParticleSpawner);
+ VM_InitParticleSpawner((int)PRVM_G_FLOAT(OFS_PARM0));
+ vmpartspawner.themes[0].initialized = true;
+ VM_ResetParticleTheme(&vmpartspawner.themes[0]);
+ PRVM_G_FLOAT(OFS_RETURN) = (vmpartspawner.verified == true) ? 1 : 0;
+}
+
+// void() resetparticle
+void VM_CL_ResetParticle (void)
+{
+ VM_SAFEPARMCOUNT(0, VM_CL_ResetParticle);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_ResetParticle: particle spawner not initialized\n");
+ return;
+ }
+ VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+}
+
+// void(float themenum) particletheme
+void VM_CL_ParticleTheme (void)
+{
+ int themenum;
+
+ VM_SAFEPARMCOUNT(1, VM_CL_ParticleTheme);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_ParticleTheme: particle spawner not initialized\n");
+ return;
+ }
+ themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
+ if (themenum < 0 || themenum >= vmpartspawner.max_themes)
+ {
+ VM_Warning("VM_CL_ParticleTheme: bad theme number %i\n", themenum);
+ VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+ return;
+ }
+ if (vmpartspawner.themes[themenum].initialized == false)
+ {
+ VM_Warning("VM_CL_ParticleTheme: theme #%i not exists\n", themenum);
+ VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+ return;
+ }
+ // load particle theme into globals
+ VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[themenum]);
+}
+
+// float() saveparticletheme
+// void(float themenum) updateparticletheme
+void VM_CL_ParticleThemeSave (void)
+{
+ int themenum;
+
+ VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_ParticleThemeSave);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_ParticleThemeSave: particle spawner not initialized\n");
+ return;
+ }
+ // allocate new theme, save it and return
+ if (prog->argc < 1)
+ {
+ for (themenum = 0; themenum < vmpartspawner.max_themes; themenum++)
+ if (vmpartspawner.themes[themenum].initialized == false)
+ break;
+ if (themenum >= vmpartspawner.max_themes)
+ {
+ if (vmpartspawner.max_themes == 2048)
+ VM_Warning("VM_CL_ParticleThemeSave: no free theme slots\n");
+ else
+ VM_Warning("VM_CL_ParticleThemeSave: no free theme slots, try initparticlespawner() with highter max_themes\n");
+ PRVM_G_FLOAT(OFS_RETURN) = -1;
+ return;
+ }
+ vmpartspawner.themes[themenum].initialized = true;
+ VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum]);
+ PRVM_G_FLOAT(OFS_RETURN) = themenum;
+ return;
+ }
+ // update existing theme
+ themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
+ if (themenum < 0 || themenum >= vmpartspawner.max_themes)
+ {
+ VM_Warning("VM_CL_ParticleThemeSave: bad theme number %i\n", themenum);
+ return;
+ }
+ vmpartspawner.themes[themenum].initialized = true;
+ VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum]);
+}
+
+// void(float themenum) freeparticletheme
+void VM_CL_ParticleThemeFree (void)
+{
+ int themenum;
+
+ VM_SAFEPARMCOUNT(1, VM_CL_ParticleThemeFree);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_ParticleThemeFree: particle spawner not initialized\n");
+ return;
+ }
+ themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
+ // check parms
+ if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
+ {
+ VM_Warning("VM_CL_ParticleThemeFree: bad theme number %i\n", themenum);
+ return;
+ }
+ if (vmpartspawner.themes[themenum].initialized == false)
+ {
+ VM_Warning("VM_CL_ParticleThemeFree: theme #%i already freed\n", themenum);
+ VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+ return;
+ }
+ // free theme
+ VM_ResetParticleTheme(&vmpartspawner.themes[themenum]);
+ vmpartspawner.themes[themenum].initialized = false;
+}
+
+// float(vector org, vector dir, [float theme]) particle
+// returns 0 if failed, 1 if succesful
+void VM_CL_SpawnParticle (void)
+{
+ float *org, *dir;
+ vmparticletheme_t *theme;
+ particle_t *part;
+ int themenum;
+
+ VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_SpawnParticle2);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_SpawnParticle: particle spawner not initialized\n");
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ org = PRVM_G_VECTOR(OFS_PARM0);
+ dir = PRVM_G_VECTOR(OFS_PARM1);
+
+ if (prog->argc < 3) // global-set particle
+ {
+ part = CL_NewParticle(org, (unsigned short)*vmpartspawner.particle_type, ((int)(vmpartspawner.particle_color1[0]) << 16) + ((int)(vmpartspawner.particle_color1[1]) << 8) + ((int)(vmpartspawner.particle_color1[2])), ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]), (int)*vmpartspawner.particle_tex, *vmpartspawner.particle_size, *vmpartspawner.particle_sizeincrease, *vmpartspawner.particle_alpha*256, *vmpartspawner.particle_alphafade*256, *vmpartspawner.particle_gravity, *vmpartspawner.particle_bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], *vmpartspawner.particle_airfriction, *vmpartspawner.particle_liquidfriction, *vmpartspawner.particle_originjitter, *vmpartspawner.particle_velocityjitter, (*vmpartspawner.particle_qualityreduction) ? true : false, *vmpartspawner.particle_time, *vmpartspawner.particle_stretch, (pblend_t)*vmpartspawner.particle_blendmode, (porientation_t)*vmpartspawner.particle_orientation, (int)(vmpartspawner.particle_staincolor1[0])*65536 + (int)(vmpartspawner.particle_staincolor1[1])*256 + (int)(vmpartspawner.particle_staincolor1[2]), (int)(vmpartspawner.particle_staincolor2[0])*65536 + (int)(vmpartspawner.particle_staincolor2[1])*256 + (int)(vmpartspawner.particle_staincolor2[2]), (int)*vmpartspawner.particle_staintex, *vmpartspawner.particle_stainalpha*256, *vmpartspawner.particle_stainsize, *vmpartspawner.particle_angle, *vmpartspawner.particle_spin);
+ if (!part)
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ if (*vmpartspawner.particle_delayspawn)
+ part->delayedspawn = cl.time + *vmpartspawner.particle_delayspawn;
+ //if (*vmpartspawner.particle_delaycollision)
+ // part->delayedcollisions = cl.time + *vmpartspawner.particle_delaycollision;
+ }
+ else // quick themed particle
+ {
+ themenum = (int)PRVM_G_FLOAT(OFS_PARM2);
+ if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
+ {
+ VM_Warning("VM_CL_SpawnParticle: bad theme number %i\n", themenum);
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ theme = &vmpartspawner.themes[themenum];
+ part = CL_NewParticle(org, theme->typeindex, theme->color1, theme->color2, theme->tex, theme->size, theme->sizeincrease, theme->alpha, theme->alphafade, theme->gravity, theme->bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], theme->airfriction, theme->liquidfriction, theme->originjitter, theme->velocityjitter, theme->qualityreduction, theme->lifetime, theme->stretch, theme->blendmode, theme->orientation, theme->staincolor1, theme->staincolor2, theme->staintex, theme->stainalpha, theme->stainsize, theme->angle, theme->spin);
+ if (!part)
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ if (theme->delayspawn)
+ part->delayedspawn = cl.time + theme->delayspawn;
+ //if (theme->delaycollision)
+ // part->delayedcollisions = cl.time + theme->delaycollision;
+ }
+ PRVM_G_FLOAT(OFS_RETURN) = 1;
+}
+
+// float(vector org, vector dir, float spawndelay, float collisiondelay, [float theme]) delayedparticle
+// returns 0 if failed, 1 if success
+void VM_CL_SpawnParticleDelayed (void)
+{
+ float *org, *dir;
+ vmparticletheme_t *theme;
+ particle_t *part;
+ int themenum;
+
+ VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_SpawnParticle2);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_SpawnParticle: particle spawner not initialized\n");
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ org = PRVM_G_VECTOR(OFS_PARM0);
+ dir = PRVM_G_VECTOR(OFS_PARM1);
+ if (prog->argc < 5) // global-set particle
+ part = CL_NewParticle(org, (unsigned short)*vmpartspawner.particle_type, ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]), ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]), (int)*vmpartspawner.particle_tex, *vmpartspawner.particle_size, *vmpartspawner.particle_sizeincrease, *vmpartspawner.particle_alpha*256, *vmpartspawner.particle_alphafade*256, *vmpartspawner.particle_gravity, *vmpartspawner.particle_bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], *vmpartspawner.particle_airfriction, *vmpartspawner.particle_liquidfriction, *vmpartspawner.particle_originjitter, *vmpartspawner.particle_velocityjitter, (*vmpartspawner.particle_qualityreduction) ? true : false, *vmpartspawner.particle_time, *vmpartspawner.particle_stretch, (pblend_t)*vmpartspawner.particle_blendmode, (porientation_t)*vmpartspawner.particle_orientation, ((int)vmpartspawner.particle_staincolor1[0] << 16) + ((int)vmpartspawner.particle_staincolor1[1] << 8) + ((int)vmpartspawner.particle_staincolor1[2]), ((int)vmpartspawner.particle_staincolor2[0] << 16) + ((int)vmpartspawner.particle_staincolor2[1] << 8) + ((int)vmpartspawner.particle_staincolor2[2]), (int)*vmpartspawner.particle_staintex, *vmpartspawner.particle_stainalpha*256, *vmpartspawner.particle_stainsize, *vmpartspawner.particle_angle, *vmpartspawner.particle_spin);
+ else // themed particle
+ {
+ themenum = (int)PRVM_G_FLOAT(OFS_PARM4);
+ if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
+ {
+ VM_Warning("VM_CL_SpawnParticle: bad theme number %i\n", themenum);
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ theme = &vmpartspawner.themes[themenum];
+ part = CL_NewParticle(org, theme->typeindex, theme->color1, theme->color2, theme->tex, theme->size, theme->sizeincrease, theme->alpha, theme->alphafade, theme->gravity, theme->bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], theme->airfriction, theme->liquidfriction, theme->originjitter, theme->velocityjitter, theme->qualityreduction, theme->lifetime, theme->stretch, theme->blendmode, theme->orientation, theme->staincolor1, theme->staincolor2, theme->staintex, theme->stainalpha, theme->stainsize, theme->angle, theme->spin);
+ }
+ if (!part)
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ part->delayedspawn = cl.time + PRVM_G_FLOAT(OFS_PARM2);
+ //part->delayedcollisions = cl.time + PRVM_G_FLOAT(OFS_PARM3);
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+}
+
+//====================
+//CSQC engine entities query
+//====================
+
+// float(float entitynum, float whatfld) getentity;
+// vector(float entitynum, float whatfld) getentityvec;
+// querying engine-drawn entity
+// VorteX: currently it's only tested with whatfld = 1..7
+void VM_CL_GetEntity (void)
+{
+ int entnum, fieldnum;
+ float org[3], v1[3], v2[3];
+ VM_SAFEPARMCOUNT(2, VM_CL_GetEntityVec);
+
+ entnum = PRVM_G_FLOAT(OFS_PARM0);
+ if (entnum < 0 || entnum >= cl.num_entities)
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ fieldnum = PRVM_G_FLOAT(OFS_PARM1);
+ switch(fieldnum)
+ {
+ case 0: // active state
+ PRVM_G_FLOAT(OFS_RETURN) = cl.entities_active[entnum];
+ break;
+ case 1: // origin
+ Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ case 2: // forward
+ Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, PRVM_G_VECTOR(OFS_RETURN), v1, v2, org);
+ break;
+ case 3: // right
+ Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, v1, PRVM_G_VECTOR(OFS_RETURN), v2, org);
+ break;
+ case 4: // up
+ Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, v1, v2, PRVM_G_VECTOR(OFS_RETURN), org);
+ break;
+ case 5: // scale
+ PRVM_G_FLOAT(OFS_RETURN) = Matrix4x4_ScaleFromMatrix(&cl.entities[entnum].render.matrix);
+ break;
+ case 6: // origin + v_forward, v_right, v_up
+ Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ case 7: // alpha
+ PRVM_G_FLOAT(OFS_RETURN) = cl.entities[entnum].render.alpha;
+ break;
+ case 8: // colormor
+ VectorCopy(cl.entities[entnum].render.colormod, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ case 9: // pants colormod
+ VectorCopy(cl.entities[entnum].render.colormap_pantscolor, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ case 10: // shirt colormod
+ VectorCopy(cl.entities[entnum].render.colormap_shirtcolor, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ case 11: // skinnum
+ PRVM_G_FLOAT(OFS_RETURN) = cl.entities[entnum].render.skinnum;
+ break;
+ case 12: // mins
+ VectorCopy(cl.entities[entnum].render.mins, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ case 13: // maxs
+ VectorCopy(cl.entities[entnum].render.maxs, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ case 14: // absmin
+ Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org);
+ VectorAdd(cl.entities[entnum].render.mins, org, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ case 15: // absmax
+ Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org);
+ VectorAdd(cl.entities[entnum].render.maxs, org, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ case 16: // light
+ VectorMA(cl.entities[entnum].render.modellight_ambient, 0.5, cl.entities[entnum].render.modellight_diffuse, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ default:
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ break;
+ }
+}
+