Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
csqcmodel_hooks.qc
Go to the documentation of this file.
1#include "csqcmodel_hooks.qh"
2
9#include <common/ent_cs.qh>
11#include <common/mapinfo.qh>
14#include <common/viewloc.qh>
19
21
22// FEATURE: LOD
28void CSQCModel_LOD_Apply(entity this, bool isplayer)
29{
30 int detailreduction = ((isplayer) ? autocvar_cl_playerdetailreduction : autocvar_cl_modeldetailreduction);
31
32 // LOD model loading
33 if(this.lodmodelindex0 != this.modelindex && this.lodmodelindex1 != this.modelindex && this.lodmodelindex2 != this.modelindex)
34 {
35 string modelname = this.model;
36 string s;
37
38 vector mi = this.mins;
39 vector ma = this.maxs;
40
41 // set modelindex
42 this.lodmodelindex0 = this.modelindex;
43 this.lodmodelindex1 = this.modelindex;
44 this.lodmodelindex2 = this.modelindex;
45
46 // FIXME: this only supports 3-letter extensions
47 s = strcat(substring(modelname, 0, strlen(modelname)-4), "_lod1", substring(modelname, -4, 4));
48 if(fexists(s))
49 {
50 precache_model(s);
51 _setmodel(this, s);
52 if(this.modelindex)
53 this.lodmodelindex2 = this.lodmodelindex1 = this.modelindex;
54 }
55
56 s = strcat(substring(modelname, 0, strlen(modelname)-4), "_lod2", substring(modelname, -4, 4));
57 if(fexists(s))
58 {
59 precache_model(s);
60 _setmodel(this, s);
61 if(this.modelindex)
62 this.lodmodelindex2 = this.modelindex;
63 }
64
65 _setmodel(this, modelname); // make everything normal again
66 setsize(this, mi, ma);
67 }
68
69 // apply LOD
70 if(detailreduction <= 0)
71 {
72 if(detailreduction <= -2)
73 this.modelindex = this.lodmodelindex2;
74 else if(detailreduction <= -1)
75 this.modelindex = this.lodmodelindex1;
76 else
77 this.modelindex = this.lodmodelindex0;
78 }
79 else
80 {
81 float distance = vlen(((isplayer) ? this.origin : NearestPointOnBox(this, view_origin)) - view_origin); // TODO: perhaps it should just use NearestPointOnBox all the time, player hitbox can potentially be huge
82 float dist1 = (this.loddistance1 > 0) ? this.loddistance1 : autocvar_cl_loddistance1;
83 float dist2 = (this.loddistance2 > 0) ? this.loddistance2 : autocvar_cl_loddistance2;
84 float f = (distance * current_viewzoom + 100.0) * detailreduction;
85 f *= 1.0 / bound(0.01, view_quality, 1);
86 if(f > dist2)
87 this.modelindex = this.lodmodelindex2;
88 else if(f > dist1)
89 this.modelindex = this.lodmodelindex1;
90 else
91 this.modelindex = this.lodmodelindex0;
92 }
93}
94
95// FEATURE: forcemodel and model color selection (MUST be called BEFORE LOD!)
100
104
106
111
114
117
118.vector glowmod;
119
142void CSQCPlayer_ModelAppearance_Apply(entity this, bool islocalplayer)
143{
144 int cm = this.forceplayermodels_savecolormap;
145 cm = (cm >= 1024) ? cm : (entcs_GetClientColors(cm - 1) + 1024);
146
147 if(MUTATOR_CALLHOOK(ForcePlayermodels_Skip, this, islocalplayer))
148 goto skipforcemodels;
149
150 // FORCEMODEL
151 // which one is ALWAYS good?
153 {
154 entity e = spawn();
155 precache_model(cvar_defstring("_cl_playermodel"));
156 _setmodel(e, cvar_defstring("_cl_playermodel"));
159 delete(e);
160 }
161
162 // first, try finding it from the server
164 {
165 if(islocalplayer)
166 {
167 if(!isdemo()) // this is mainly cheat protection; not needed for demos
168 {
169 // trust server's idea of "own player model"
175 }
176 }
177 }
178
179 // forcemodel finding
181 {
183
184 // only if this failed, find it out on our own
185 entity e = spawn();
186 precache_model(autocvar__cl_playermodel);
187 _setmodel(e, autocvar__cl_playermodel); // this is harmless, see below
189 forceplayermodels_model = e.model;
190 forceplayermodels_modelindex = e.modelindex;
192 delete(e);
193 }
194
196 {
197 entity e = spawn();
198 _setmodel(e, autocvar_cl_forcemyplayermodel); // this is harmless, see below
201 forceplayermodels_mymodelindex = e.modelindex;
202 delete(e);
203 }
204
205 // apply it
206 bool isfriend;
207
208 if(teamplay)
209 isfriend = (cm == 1024 + 17 * myteam);
210 else
211 isfriend = islocalplayer;
212
214 {
218 }
220 {
224 }
226 {
230 }
231 else
232 {
236 }
237
238 LABEL(skipforcemodels)
239
240 if(MUTATOR_CALLHOOK(ForcePlayercolors_Skip, this, islocalplayer))
241 goto skipforcecolors;
242
243 bool forceplayercolors_enabled = false;
244 #define fpc autocvar_cl_forceplayercolors
245 if (gametype.m_1v1)
246 {
247 if ((myteam != NUM_SPECTATOR) && (fpc == 1 || fpc == 2 || fpc == 3 || fpc == 5))
248 forceplayercolors_enabled = true;
249 }
250 else if (teamplay)
251 {
252 if ((team_count == 2) && (myteam != NUM_SPECTATOR) && (fpc == 2 || fpc == 4 || fpc == 5))
253 forceplayercolors_enabled = true;
254 }
255 else
256 {
257 if (fpc == 1 || fpc == 2)
258 forceplayercolors_enabled = true;
259 }
260
261 // forceplayercolors too
262 if(teamplay)
263 {
264 // own team's color is never forced
265 int forcecolor_friend = 0, forcecolor_enemy = 0;
266 entity tm;
267
269 forcecolor_friend = 1024 + autocvar_cl_forcemyplayercolors;
270
271 if(forceplayercolors_enabled)
272 forcecolor_enemy = 1024 + autocvar__cl_color;
273
274 if(forcecolor_enemy && !forcecolor_friend)
275 {
276 // only enemy color is forced?
277 // verify it is not equal to the friend color
278 if(forcecolor_enemy == 1024 + 17 * myteam)
279 forcecolor_enemy = 0;
280 }
281
282 if(forcecolor_friend && !forcecolor_enemy)
283 {
284 // only friend color is forced?
285 // verify it is not equal to the enemy color
286 for(tm = teams.sort_next; tm; tm = tm.sort_next)
287 // note: we even compare against our own team.
288 // if we rejected because we matched our OWN team color,
289 // this is not bad; we then simply keep our color as is
290 // anyway.
291 if(forcecolor_friend == 1024 + 17 * tm.team)
292 forcecolor_friend = 0;
293 }
294
295 if(cm == 1024 + 17 * myteam)
296 {
297 if(forcecolor_friend)
298 this.colormap = forcecolor_friend;
299 }
300 else
301 {
302 if(forcecolor_enemy)
303 this.colormap = forcecolor_enemy;
304 }
305 }
306 else // if(!teamplay)
307 {
308 if(autocvar_cl_forcemyplayercolors && islocalplayer)
310 else if (autocvar_cl_forceuniqueplayercolors && !islocalplayer && !gametype.m_1v1)
311 {
312 // Assign each enemy an unique color combination
313 // pick colors from 0 to 14 since 15 is the rainbow color
314 // pl01 0 1, pl02 1 2, ..., pl14 13 14, pl15 14 0
315 // pl16 0 2, pl17 1 3, ..., pl29 13 0, pl30 14 1
316 int num;
318 num = this.entnum - 1;
319 else
320 num = this.sv_entnum - 1;
321 int c1 = num % 15;
322 int q = floor(num / 15);
323 int c2 = (c1 + 1 + q) % 15;
324 this.colormap = 1024 + (c1 << 4) + c2;
325 }
326 else if(forceplayercolors_enabled)
327 this.colormap = player_localnum + 1;
328 }
329
330 LABEL(skipforcecolors)
331
333 {
334 this.glowmod = '0 0 0';
335 this.colormap = 0;
336 return;
337 }
338
339 // GLOWMOD AND DEATH FADING
340 if(this.colormap > 0)
341 this.glowmod = colormapPaletteColor(((this.colormap >= 1024) ? this.colormap : entcs_GetClientColors(this.colormap - 1)) & 0x0F, true);
342 else
343 this.glowmod = '1 1 1';
344
346 {
347 if(this.csqcmodel_isdead)
348 {
349 float min_factor = bound(0, autocvar_cl_deathglow_min, 1);
350 if(this.colormap > 0)
351 min_factor /= 2;
352 float glow_fade = bound(0, 1 - (time - this.death_time) / autocvar_cl_deathglow, 1);
353 this.glowmod *= (min_factor + glow_fade * (1 - min_factor));
354 if (this.glowmod == '0 0 0')
355 this.glowmod.x = 0.000001;
356 }
357 }
358
359 // don't let the engine increase player's glowmod
362
363 //printf("CSQCPlayer_ModelAppearance_Apply(): state = %s, colormap = %f, glowmod = %s\n", (this.csqcmodel_isdead ? "DEAD" : "ALIVE"), this.colormap, vtos(this.glowmod));
364}
365
366// FEATURE: fallback frames
369#ifdef CSQCMODEL_HAVE_TWO_FRAMES
370.int csqcmodel_saveframe3;
371.int csqcmodel_saveframe4;
372#endif
374
375#define IS_DEAD_FRAME(f) ((f) == 0 || (f) == 1)
377{
378 this.frame = this.csqcmodel_saveframe;
379 this.frame2 = this.csqcmodel_saveframe2;
380#ifdef CSQCMODEL_HAVE_TWO_FRAMES
381 this.frame3 = this.csqcmodel_saveframe3;
382 this.frame4 = this.csqcmodel_saveframe4;
383#endif
384}
386{
387 this.csqcmodel_saveframe = this.frame;
388 this.csqcmodel_saveframe2 = this.frame2;
389#ifdef CSQCMODEL_HAVE_TWO_FRAMES
390 this.csqcmodel_saveframe3 = this.frame3;
391 this.csqcmodel_saveframe4 = this.frame4;
392#endif
393
394 // hack for death animations: set their frametime to zero in case a
395 // player "pops in"
396 if(isnew)
397 {
398#define FIX_FRAMETIME(f,ft) MACRO_BEGIN \
399 if(IS_DEAD_FRAME(this.f) && this.ft != 0 && this.death_time != 0) \
400 this.ft = this.death_time; \
401MACRO_END
404#ifdef CSQCMODEL_HAVE_TWO_FRAMES
407#endif
408 }
410}
416{
417 TC(int, f);
418 if(frameduration(this.modelindex, f) > 0)
419 return f; // goooooood
420 if(frameduration(this.modelindex, 1) <= 0)
421 return f; // this is a static model. We can't fix it if we wanted to
422 switch(f)
423 {
424 case 23: return 11; // anim_melee -> anim_shoot
425 case 24: return 4; // anim_duckwalkbackwards -> anim_duckwalk
426 case 25: return 4; // anim_duckwalkstrafeleft -> anim_duckwalk
427 case 26: return 4; // anim_duckwalkstraferight -> anim_duckwalk
428 case 27: return 4; // anim_duckwalkforwardright -> anim_duckwalk
429 case 28: return 4; // anim_duckwalkforwardleft -> anim_duckwalk
430 case 29: return 4; // anim_duckwalkbackright -> anim_duckwalk
431 case 30: return 4; // anim_duckwalkbackleft -> anim_duckwalk
432 }
433 LOG_DEBUGF("Frame %d missing in model %s, and we have no fallback - FAIL!", f, this.model);
434 return f;
435}
437{
438 this.frame = CSQCPlayer_FallbackFrame(this, this.frame);
439 this.frame2 = CSQCPlayer_FallbackFrame(this, this.frame2);
440#ifdef CSQCMODEL_HAVE_TWO_FRAMES
441 this.frame3 = CSQCPlayer_FallbackFrame(this, this.frame3);
442 this.frame4 = CSQCPlayer_FallbackFrame(this, this.frame4);
443#endif
444}
445
446// FEATURE: auto tag_index
451{
452 if(this.tag_entity && wasfreed(this.tag_entity))
453 this.tag_entity = NULL;
454
455 MUTATOR_CALLHOOK(TagIndex_Update, this);
456
457 if(this.tag_networkentity)
458 {
459 // we are ATTACHED!
460 bool changed = 0;
461 if(this.tag_entity.entnum != this.tag_networkentity)
462 {
464 changed = 1;
465 }
466
467 // recursive predraw call to fix issues with forcemodels and LOD if bone indexes mismatch
468 if(this.tag_entity.classname == "ENT_CLIENT_MODEL")
469 {
470 CSQCModel_Hook_PreDraw(this.tag_entity, (this.tag_entity.isplayermodel & ISPLAYER_CLIENT));
471 }
472
473 if(this.tag_entity.modelindex != this.tag_entity_lastmodelindex)
474 {
475 this.tag_entity_lastmodelindex = this.tag_entity.modelindex;
476 changed = 1;
477 }
478 if(changed)
479 {
480 if(this.tag_entity)
481 {
482 // the best part is: IT EXISTS
483 if(substring(this.model, 0, 14) == "models/weapons")
484 {
485 if(substring(this.tag_entity.model, 0, 14) == "models/weapons")
486 {
487 this.tag_index = gettagindex(this.tag_entity, "weapon");
488 if(!this.tag_index)
489 this.tag_index = gettagindex(this.tag_entity, "tag_weapon");
490 if(!this.tag_index)
491 {
492 // we need to prevent this from 'appening
493 this.tag_entity = NULL;
494 this.drawmask = 0;
495 LOG_TRACE("h_ model lacks weapon attachment, but v_ model is attached to it");
496 }
497 }
498 else if((this.tag_entity.isplayermodel & ISPLAYER_MODEL))
499 {
501 this.tag_index = this.tag_entity.bone_weapon;
502 }
503 }
504
505 if(substring(this.tag_entity.model, 0, 14) == "models/weapons")
506 {
507 this.tag_index = gettagindex(this.tag_entity, "shot");
508 if(!this.tag_index)
509 this.tag_index = gettagindex(this.tag_entity, "tag_shot");
510 }
511
512 MUTATOR_CALLHOOK(TagIndex_Apply, this);
513 }
514 else
515 {
516 // damn, see you next frame
517 this.drawmask = 0;
518 }
519 }
520 }
521}
522
524{
525 this.effects = this.csqcmodel_effects;
527 this.traileffect = this.csqcmodel_traileffect;
528}
529void Reset_ArcBeam();
531{
532 if (this == csqcplayer) {
533 if (this.csqcmodel_teleported) {
535 }
536 }
537 this.csqcmodel_effects = this.effects;
539 this.csqcmodel_traileffect = this.traileffect;
540 this.effects = 0;
541 this.modelflags = 0;
542 if(this.csqcmodel_teleported)
543 Projectile_ResetTrail(this, this.origin);
544}
547{
548 float dt = bound(0, frametime, 0.1);
550 int tref = this.csqcmodel_traileffect;
551
553 this.effects = 0;
554 this.traileffect = 0;
555
556 float pl_alpha = (!this.alpha ? 1 : this.alpha);
557 if (eff & EF_BRIGHTFIELD)
558 tref = EFFECT_TR_NEXUIZPLASMA.m_id;
559 // ignoring EF_MUZZLEFLASH
560 if ((eff & EF_NODRAW) || pl_alpha < 0)
561 this.drawmask = 0;
562 if (eff & EF_ADDITIVE)
563 this.renderflags |= RF_ADDITIVE;
564 // ignoring EF_NOGUNBOB
565 if (eff & EF_FULLBRIGHT)
567
568 if (pl_alpha > 0)
569 {
570 if (eff & EF_BLUE)
571 adddynamiclight(this.origin, 200 * pl_alpha, '0.15 0.15 1.5');
572 if (eff & EF_RED)
573 adddynamiclight(this.origin, 200 * pl_alpha, '1.5 0.15 0.15');
574 if (eff & EF_BRIGHTLIGHT)
575 adddynamiclight(this.origin, 400 * pl_alpha, '3 3 3');
576 if (eff & EF_DIMLIGHT)
577 adddynamiclight(this.origin, 200 * pl_alpha, '1.5 1.5 1.5');
578 if (eff & EF_FLAME)
579 {
580 particles_alphamin = particles_alphamax = pl_alpha; // scale by player alpha
581 // XONRELEASE TODO: xonotic-v0.9.0 after release remove the ef_shock_num check
582 // NOTE here we check if EF_SHOCK exists because it was added together with the change to EF_FLAME
583 int ef_shock_num = particleeffectnum(EFFECT_EF_SHOCK);
584 if (ef_shock_num >= 0) // in the old version of EF_FLAME the light was spawned by boxparticles
585 adddynamiclight2(this.origin + '0 0 10', 200 * particles_alphamin, '1 0.35 0', 6, "", PFLAGS_FULLDYNAMIC); // no PFLAGS_CORONA, it looks bad
586 int ef_flame_num = particleeffectnum(EFFECT_EF_FLAME);
587 boxparticles(ef_flame_num, this, this.absmin, this.absmax, this.velocity, this.velocity, dt, PARTICLES_USEALPHA);
588 //pointparticles(EFFECT_EF_FLAME, this.origin, '0 0 0', dt);
589 }
590 if (eff & EF_SHOCK)
591 {
592 particles_alphamin = particles_alphamax = pl_alpha; // scale by player alpha
593 // XONRELEASE TODO: xonotic-v0.9.0 after release remove the ef_shock_num check
594 int ef_shock_num = particleeffectnum(EFFECT_EF_SHOCK);
595 if (ef_shock_num >= 0) // in ARC_LIGHTNING the light is spawned by boxparticles
596 adddynamiclight2(this.origin, 50 * particles_alphamin, '3.1 4.4 10', 10, "", PFLAGS_FULLDYNAMIC); // no PFLAGS_CORONA, it looks bad
597 else
598 ef_shock_num = particleeffectnum(EFFECT_ARC_LIGHTNING);
599 boxparticles(ef_shock_num, this, this.absmin, this.absmax, '0 0 0', '0 0 0', dt, PARTICLES_USEALPHA);
600 //pointparticles(EFFECT_ARC_LIGHTNING, this.origin, '0 0 0', dt);
601 }
602 if (eff & EF_SPEED)
603 {
604 float speed = vlen(this.velocity);
605 if (speed > 0)
606 {
607 particles_alphamin = particles_alphamax = pl_alpha * min(speed / PHYS_MAXSPEED(this), 1); // scale by player alpha, and more transparent at lower speeds
608 vector dir = this.velocity * 1 / speed;
609 // XONRELEASE TODO: xonotic-v0.9.0 post-release remove the ef_speed_num check
610 int ef_speed_num = particleeffectnum(EFFECT_EF_SPEED);
611 int foot_L_idx = gettagindex(this, "foot_L"); // left & right feet on the playermodel,
612 int foot_R_idx = gettagindex(this, "foot_R"); // roughly at the heel
613 if (foot_L_idx && foot_R_idx)
614 {
615 vector foot_L_org = gettaginfo(this, foot_L_idx);
616 vector foot_R_org = gettaginfo(this, foot_R_idx);
617 if (ef_speed_num >= 0)
618 {
619 // NOTE: to make this a proper trail the old foot_*_org will need to be stored, however it looks fine as-is
620 WarpZone_TrailParticles_WithMultiplier(this, ef_speed_num, foot_L_org - dir, foot_L_org + dir, dt, PARTICLES_USEALPHA);
621 WarpZone_TrailParticles_WithMultiplier(this, ef_speed_num, foot_R_org - dir, foot_R_org + dir, dt, PARTICLES_USEALPHA);
622 }
623 // No fallback since nothing looks similar, light will still draw though
624 adddynamiclight(foot_L_org, 45 * particles_alphamin, STATUSEFFECT_Speed.m_color);
625 adddynamiclight(foot_R_org, 45 * particles_alphamin, STATUSEFFECT_Speed.m_color);
626 }
627 else
628 {
629 vector org = this.origin + 0.5 * (this.mins + this.maxs); // center
630 if (ef_speed_num >= 0)
632 //pointparticles(EFFECT_EF_SPEED, org, '0 0 0', dt);
633 adddynamiclight(org, 45 * particles_alphamin, STATUSEFFECT_Speed.m_color);
634 }
635 }
636 }
637 if (eff & EF_STARDUST)
638 {
639 particles_alphamin = particles_alphamax = pl_alpha; // scale by player alpha
640 boxparticles(particleeffectnum(EFFECT_EF_STARDUST), this, this.absmin, this.absmax, this.velocity, this.velocity, dt, PARTICLES_USEALPHA);
641 //pointparticles(EFFECT_EF_STARDUST, this.origin, '0 0 0', dt);
642 }
643 }
644
645 if (eff & EF_NOSHADOW)
646 this.renderflags |= RF_NOSHADOW;
647 if (eff & EF_NODEPTHTEST)
649 // ignoring EF_SELECTABLE
650 if (eff & EF_DOUBLESIDED)
651 this.effects |= EF_DOUBLESIDED;
652 if (eff & EF_NOSELFSHADOW)
653 this.effects |= EF_NOSELFSHADOW;
654 if (eff & EF_DYNAMICMODELLIGHT)
656 // ignoring EF_UNUSED18, EF_UNUSED19, EF_RESTARTANIM_BIT, EF_TELEPORT_BIT, EF_LOWPRECISION
657
658 if (false)
659 ;
660#define TRAIL_FROM_MODEL(modelflag, trailent) \
661 else if (this.csqcmodel_modelflags & (modelflag)) \
662 tref = EFFECT_##trailent.m_id
663 TRAIL_FROM_MODEL(MF_TRACER3, TR_VORESPIKE);
664 TRAIL_FROM_MODEL(MF_TRACER2, TR_KNIGHTSPIKE);
665 TRAIL_FROM_MODEL(MF_ZOMGIB, TR_SLIGHTBLOOD);
666 TRAIL_FROM_MODEL(MF_TRACER, TR_WIZSPIKE);
667 TRAIL_FROM_MODEL(MF_GIB, TR_BLOOD);
668 TRAIL_FROM_MODEL(MF_GRENADE, TR_GRENADE);
669 TRAIL_FROM_MODEL(MF_ROCKET, TR_ROCKET);
670#undef TRAIL_FROM_MODEL
672 {
673 // This will be hard to replace with MAKE_VECTORS because it's called as part of the predraw function
674 // as documented in csprogs.h in the engine. The globals can then be read in many places in the engine.
675 // However MF_ROTATE is currently only used in one place - might be possible to get rid of it entirely.
676 this.renderflags |= RF_USEAXIS;
677 makevectors(this.angles + '0 100 0' * fmod(time, 3.6));
678 }
679
680 this.traileffect = tref;
681
682 if (this.drawmask)
683 Projectile_DrawTrail(this, this.origin);
684 else
685 Projectile_ResetTrail(this, this.origin);
686
688 this.renderflags |= RF_ADDITIVE;
689 // also special in CSQCPlayer_GlowMod_Apply
690
692 {
693 if (!this.snd_looping)
694 {
697 }
698 }
699 else
700 {
701 if (this.snd_looping)
702 {
704 this.snd_looping = 0;
705 }
706 }
707}
708
709// general functions
720void CSQCModel_Hook_PreDraw(entity this, bool isplayer)
721{
723 return;
725
726 if(!this.modelindex || this.model == "null")
727 {
728 this.drawmask = 0;
729 if(this.snd_looping > 0)
730 {
732 this.snd_looping = 0;
733 }
734 return;
735 }
736 else
737 this.drawmask = MASK_NORMAL;
738
739 if((this.isplayermodel & ISPLAYER_MODEL) && this.drawmask) // this checks if it's a player MODEL!
740 {
742 CSQCModel_LOD_Apply(this, true);
743
744 if(!isplayer)
745 {
746 skeleton_loadinfo(this);
747 bool doblend = (this.bone_upperbody >= 0);
749 if(doblend)
750 {
752 }
753 else
754 {
756 // just in case, clear these (we're animating in frame and frame3)
757 this.lerpfrac = 0;
758 this.lerpfrac4 = 0;
759 }
760 }
761 else
762 {
763 // we know that frame3 and frame4 fields, used by InterpolateAnimation, are left alone - but that is all we know!
764 skeleton_loadinfo(this);
765 bool doblend = (this.bone_upperbody >= 0);
766 bool onground = 0;
767 if(this == csqcplayer)
768 {
769 if(IS_ONGROUND(this))
770 onground = 1;
771 this.anim_prev_pmove_flags = this.flags;
772 if(this.flags & FL_DUCKED)
773 animdecide_setstate(this, this.anim_state | ANIMSTATE_DUCK, false);
774 else if(this.anim_state & ANIMSTATE_DUCK)
775 animdecide_setstate(this, this.anim_state - ANIMSTATE_DUCK, false);
776 }
777 else
778 {
779 tracebox(this.origin + '0 0 1', this.mins, this.maxs, this.origin - '0 0 4', MOVE_NORMAL, this);
781 onground = 1;
782 // predicted clients handle smoothing in the prediction code
783 this.origin = CSQCModel_ApplyStairSmoothing(this, onground, this.origin);
784 }
786 animdecide_setimplicitstate(this, onground);
788 int sf = 0;
789 if(this.anim_saveframe != this.anim_frame || this.anim_saveframe1time != this.anim_frame1time)
791 if(this.anim_saveframe2 != this.anim_frame2 || this.anim_saveframe2time != this.anim_frame2time)
793 this.anim_saveframe = this.anim_frame;
795 this.anim_saveframe2 = this.anim_frame2;
797 // Note: we always consider lerpfrac "changed", as it uses fixed values every time anyway.
798 // This ensures that .frame etc. are always written.
800 this.lerpfrac = (doblend ? 0.5 : 0);
801 this.frame = this.anim_frame;
802 this.frame1time = this.anim_frame1time;
803 this.frame2 = this.anim_frame2;
804 this.frame2time = this.anim_frame2time;
807 if(doblend)
808 {
810 }
811 else
812 {
814 // just in case, clear these (we're animating in frame and frame3)
815 this.lerpfrac = 0;
816 this.lerpfrac4 = 0;
817 }
818 }
819 }
820 else
821 CSQCModel_LOD_Apply(this, false);
822
824
826}
827
828void CSQCModel_Hook_PreUpdate(entity this, bool isnew, bool isplayer, bool islocalplayer)
829{
830 // interpolate v_angle
831 this.iflags |= IFLAG_V_ANGLE_X;
832 // revert to values from server
834 if((this.isplayermodel & ISPLAYER_MODEL))
835 {
836 if(!isplayer)
839 }
840}
841
842void CSQCModel_Hook_PostUpdate(entity this, bool isnew, bool isplayer, bool islocalplayer)
843{
844 // is it a player model? (shared state)
845 bool is_playermodel = (substring(this.model, 0, 14) == "models/player/" || substring(this.model, 0, 17) == "models/ok_player/" ||
846 (substring(this.model, 0, 16) == "models/monsters/" && (this.isplayermodel & BIT(1))));
847 this.isplayermodel = BITSET(this.isplayermodel, ISPLAYER_MODEL, is_playermodel);
848 this.csqcmodel_isdead = false; // workaround for dead players who become a spectator
849
850 // save values set by server
851 if((this.isplayermodel & ISPLAYER_MODEL))
852 {
854 if(isplayer)
856 else
858 }
860}
float frame3time
start time of framegroup animation
Definition anim.qh:26
float frame1time
start time of framegroup animation
Definition anim.qh:22
float frame2time
start time of framegroup animation
Definition anim.qh:24
float frame2
secondary framegroup animation (strength = lerpfrac)
Definition anim.qh:8
float lerpfrac
strength of framegroup blend
Definition anim.qh:15
float frame3
tertiary framegroup animation (strength = lerpfrac3)
Definition anim.qh:10
float lerpfrac4
strength of framegroup blend
Definition anim.qh:19
float frame4time
start time of framegroup animation
Definition anim.qh:28
float frame4
quaternary framegroup animation (strength = lerpfrac4)
Definition anim.qh:12
float frame
primary framegroup animation (strength = 1 - lerpfrac - lerpfrac3 - lerpfrac4)
Definition anim.qh:6
void animdecide_setimplicitstate(entity e, float onground)
void animdecide_load_if_needed(entity e)
Definition animdecide.qc:53
void animdecide_setframes(entity e, float support_blending,.float fld_frame,.float fld_frame1time,.float fld_frame2,.float fld_frame2time)
void animdecide_setstate(entity e, int newstate, float restart)
const int ANIMSTATE_DEAD1
int anim_state
const int ANIMSTATE_DEAD2
const int ANIMSTATE_DUCK
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition bits.qh:8
#define BITSET(var, mask, flag)
Definition bits.qh:11
#define boolean(value)
Definition bool.qh:9
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
void CSQCModel_InterpolateAnimation_2To4_PreNote(entity this, int sf)
Definition cl_model.qc:37
void CSQCModel_InterpolateAnimation_2To4_Note(entity this, int sf, bool set_times)
Definition cl_model.qc:73
void CSQCModel_InterpolateAnimation_2To4_Do(entity this)
Definition cl_model.qc:109
float csqcmodel_teleported
Definition cl_model.qh:39
vector CSQCModel_ApplyStairSmoothing(entity this, bool isonground, vector v)
Definition cl_player.qc:248
entity csqcplayer
Definition cl_player.qh:26
float alpha
Definition items.qc:13
float current_viewzoom
Definition main.qh:118
vector view_origin
Definition main.qh:109
int framecount
Definition main.qh:180
float view_quality
Definition main.qh:174
float renderflags
Definition main.qh:111
entity gametype
Definition main.qh:43
int sv_entnum
Definition main.qh:186
float team_count
Definition main.qh:59
entity teams
Definition main.qh:58
#define colormapPaletteColor(c, isPants)
Definition color.qh:5
#define PHYS_MAXSPEED(s)
Definition player.qh:138
#define LABEL(id)
Definition compiler.qh:34
const int EF_SPEED
Definition constants.qh:96
const int FL_DUCKED
Definition constants.qh:81
const int EF_SHOCK
Definition constants.qh:95
float flags
const float EF_STARDUST
float drawmask
float modelindex
const float RF_ADDITIVE
const float RF_USEAXIS
float frametime
const float MASK_NORMAL
float player_localnum
const float MOVE_NORMAL
vector mins
const float EF_RED
vector velocity
const float EF_ADDITIVE
const float EF_FULLBRIGHT
float effects
float time
float trace_startsolid
vector maxs
const float EF_FLAME
float particles_alphamax
float colormap
const float EF_BLUE
vector absmax
float entnum
const float EF_NODEPTHTEST
vector origin
float PARTICLES_USEALPHA
float trace_fraction
float particles_alphamin
vector absmin
const float RF_FULLBRIGHT
float RF_DYNAMICMODELLIGHT
const float EF_NOSHADOW
const float EF_NODRAW
const float RF_NOSHADOW
const float RF_DEPTHHACK
const float PFLAGS_FULLDYNAMIC
#define spawn
#define IS_DEAD_FRAME(f)
int lodmodelindex2
int forceplayermodels_savemodelindex
string forceplayermodels_isgoodmodel_mdl
int anim_prev_pmove_flags
float loddistance2
string forceplayermodels_mymodel
int lodmodelindex1
int anim_saveframe2
bool forceplayermodels_isgoodmodel
int anim_frame2
#define TRAIL_FROM_MODEL(modelflag, trailent)
void CSQCModel_Hook_PreDraw(entity this, bool isplayer)
void CSQCModel_AutoTagIndex_Apply(entity this)
int forceplayermodels_saveskin
int modelflags
void CSQCPlayer_FallbackFrame_Apply(entity this)
int csqcmodel_saveframe2
int anim_frame
int anim_frame1time
int anim_frame2time
int forceplayermodels_skin
void CSQCPlayer_ModelAppearance_PostUpdate(entity this)
float loddistance1
void CSQCPlayer_ModelAppearance_Apply(entity this, bool islocalplayer)
int tag_entity_lastmodelindex
void Reset_ArcBeam()
Definition arc.qc:814
string forceplayermodels_savemodel
void CSQCModel_Hook_PostUpdate(entity this, bool isnew, bool isplayer, bool islocalplayer)
entity tag_entity
bool forceplayermodels_attempted
void CSQCModel_LOD_Apply(entity this, bool isplayer)
void CSQCPlayer_FallbackFrame_PreUpdate(entity this)
int forceplayermodels_savecolormap
int forceplayermodels_mymodelindex
void CSQCModel_Effects_PreUpdate(entity this)
int csqcmodel_saveframe
#define fpc
void CSQCPlayer_FallbackFrame_PostUpdate(entity this, bool isnew)
int anim_saveframe1time
void CSQCPlayer_AnimDecide_PostUpdate(entity this, bool isnew)
bool forceplayermodels_myisgoodmodel
int forceplayermodels_modelindex
vector glowmod
int lodmodelindex0
bool forceplayermodels_modelisgoodmodel
void CSQCModel_Effects_Apply(entity this)
int csqcmodel_predraw_run
#define FIX_FRAMETIME(f, ft)
int anim_saveframe
int csqcmodel_framecount
string forceplayermodels_model
int anim_saveframe2time
int tag_index
void CSQCModel_Effects_PostUpdate(entity this)
void CSQCPlayer_ModelAppearance_PreUpdate(entity this)
int CSQCPlayer_FallbackFrame(entity this, int f)
int forceplayermodels_goodmodelindex
int snd_looping
string forceplayermodels_goodmodel
void CSQCModel_Hook_PreUpdate(entity this, bool isnew, bool isplayer, bool islocalplayer)
bool autocvar_cl_respawn_ghosts_keepcolors
const int MF_ROTATE
const int MF_GRENADE
int autocvar__cl_color
const int MF_TRACER3
int autocvar_cl_modeldetailreduction
int csqcmodel_traileffect
float autocvar_cl_deathglow
int autocvar_cl_forcemyplayerskin
int csqcmodel_effects
bool autocvar_cl_forceplayermodels
float death_time
float autocvar_cl_deathglow_min
int autocvar__cl_playerskin
float autocvar_cl_loddistance1
bool autocvar_cl_forceuniqueplayercolors
float autocvar_cl_loddistance2
const int MF_TRACER
string autocvar_cl_forcemyplayermodel
const int EF_BRIGHTFIELD
const int MF_ROCKET
const int MF_GIB
int autocvar_cl_playerdetailreduction
const int EF_BRIGHTLIGHT
const int MF_ZOMGIB
int autocvar_cl_forcemyplayercolors
const int EF_DIMLIGHT
float autocvar_r_hdr_glowintensity
float autocvar_cl_jetpack_attenuation
int csqcmodel_modelflags
const int MF_TRACER2
const int EF_NOSELFSHADOW
string autocvar__cl_playermodel
bool csqcmodel_isdead
int isplayermodel
const int EF_DOUBLESIDED
const int EF_DYNAMICMODELLIGHT
#define CSQCMODEL_EF_RESPAWNGHOST
float tag_networkentity
#define gettagindex
#define strlen
float speed
Definition dynlight.qc:9
#define particleeffectnum(e)
Definition effect.qh:3
ent angles
Definition ent_cs.qc:146
model
Definition ent_cs.qc:164
skin
Definition ent_cs.qc:168
int entcs_GetClientColors(int i)
Definition ent_cs.qh:111
ERASEABLE bool fexists(string f)
Definition file.qh:4
const int IFLAG_V_ANGLE_X
int iflags
#define TC(T, sym)
Definition _all.inc:82
const int CSQCMODEL_PROPERTY_FRAME2
Definition common.qh:67
const int ISPLAYER_LOCAL
Definition common.qh:58
const int CSQCMODEL_PROPERTY_FRAME
Definition common.qh:61
const int ISPLAYER_MODEL
Definition common.qh:56
const int ISPLAYER_CLIENT
Definition common.qh:57
const int CSQCMODEL_PROPERTY_LERPFRAC
Definition common.qh:68
void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, int boxflags)
Definition common.qc:466
#define LOG_TRACE(...)
Definition log.qh:74
#define LOG_INFOF(...)
Definition log.qh:63
#define LOG_DEBUGF(...)
Definition log.qh:79
float fmod(float e, float f)
Definition mathlib.qc:203
float isdemo()
float bound(float min, float value, float max)
string substring(string s, float start, float length)
float vlen(vector v)
float min(float f,...)
float floor(float f)
const string cvar_defstring(string name)
entity findfloat(entity start,.float field, float match)
#define IS_ONGROUND(s)
Definition movetypes.qh:16
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
void skeleton_loadinfo(entity e)
void skeleton_from_frames(entity e, bool is_dead)
void free_skeleton_from_frames(entity e)
#define NULL
Definition post.qh:14
#define makevectors
Definition post.qh:21
#define adddynamiclight2
Definition post.qh:30
#define gettaginfo
Definition post.qh:32
#define adddynamiclight
Definition post.qh:29
void Projectile_DrawTrail(entity this, vector to)
Definition projectile.qc:32
void Projectile_ResetTrail(entity this, vector to)
Definition projectile.qc:26
vector
Definition self.qh:96
vector org
Definition self.qh:96
int dir
Definition impulse.qc:89
const int CH_TRIGGER_SINGLE
Definition sound.qh:13
const float VOL_BASE
Definition sound.qh:36
#define sound(e, c, s, v, a)
Definition sound.qh:52
int myteam
Definition teams.qh:60
const int NUM_SPECTATOR
Definition teams.qh:23
bool teamplay
Definition teams.qh:59
ERASEABLE vector NearestPointOnBox(entity box, vector org)
Definition vector.qh:187