3 #include <client/main.qh>
4 #include <common/items/_mod.qh>
5 #include <common/physics/movetypes/movetypes.qh>
6 #include <common/weapons/_all.qh>
7 #include <lib/csqcmodel/cl_model.qh>
8 #include <lib/csqcmodel/common.qh>
9 #include <lib/warpzone/common.qh>
12 .bool item_simple; // probably not really needed, but better safe than sorry
15 .float anim_start_time; // reusing for bob waveform synchronisation
16 .vector angles_held; // reusing for (re)storing original angles
18 void ItemDraw(entity this)
20 // no bobbing applied to simple items, for consistency's sake (no visual difference between ammo and weapons)
21 bool animate = autocvar_cl_items_animate & 1 && this.item_simple <= 0 && (this.ItemStatus & ITS_ANIMATE1 || this.ItemStatus & ITS_ANIMATE2);
23 // rotation must be set before running physics
27 this.angles = this.angles_held; // restore angles sent from server
29 else if(!this.avelocity_y) // unset by MOVETYPE_TOSS or animation was disabled previously
31 if(this.ItemStatus & ITS_ANIMATE1)
32 this.avelocity_y = 180;
33 else if(this.ItemStatus & ITS_ANIMATE2)
34 this.avelocity_y = -90;
37 // CSQC physics OR bobbing (both would look weird)
38 float bobheight = 0; // reset bob offset if animations are disabled
39 if(this.move_movetype && (!IS_ONGROUND(this) || this.velocity != '0 0 0'))
41 // this isn't equivalent to player prediction but allows smooth motion with very low ISF_LOCATION rate
42 // which requires running this even if the item is just outside visible range (it could be moving into range)
44 bobheight = this.origin_z - this.oldorigin_z;
45 Movetype_Physics_NoMatchTicrate(this, frametime, true);
46 this.oldorigin = this.origin; // update real (SVQC equivalent) origin
51 this.anim_start_time += frametime; // bobbing is paused this frame
52 this.oldorigin_z -= bobheight; // restore bob offset (CSQC physics uses the offset bbox)
56 this.anim_start_time = time; // starting our bob animation from NOW
57 if(this.ItemStatus & ITS_ANIMATE1)
58 bobheight = 10; // height of wave at 0 time
59 else if(this.ItemStatus & ITS_ANIMATE2)
60 bobheight = 8; // height of wave at 0 time
66 this.angles += this.avelocity * frametime; // MOVETYPE_TOSS does this while it's moving
68 if(this.ItemStatus & ITS_ANIMATE1)
69 bobheight = 10 + 8 * sin((time - this.anim_start_time) * 2);
70 else if(this.ItemStatus & ITS_ANIMATE2)
71 bobheight = 8 + 4 * sin((time - this.anim_start_time) * 3);
74 // apply new bob offset
75 if (bobheight != this.origin_z - this.oldorigin_z)
77 this.origin_z = this.oldorigin_z + bobheight;
78 this.mins_z = 0 - bobheight; // don't want the absmin and absmax to bob
79 this.maxs_z = 48 - bobheight;
80 // bones_was_here TODO: network proper box size for sv_legacy_bbox_expand 0
83 // set alpha based on distance
86 if(this.fade_end && !warpzone_warpzones_exist)
88 vector org = getpropertyvec(VF_ORIGIN);
89 if(vdist(org - this.origin, >, this.fade_end))
90 this.alpha = 0; // save on some processing
91 else if(autocvar_cl_items_fadedist > 0)
93 this.fade_start = max(500, this.fade_end - autocvar_cl_items_fadedist);
94 if(vdist(org - this.origin, >, this.fade_start))
95 this.alpha = bound(0, (this.fade_end - vlen(org - this.origin - 0.5 * (this.mins + this.maxs))) / (this.fade_end - this.fade_start), 1);
102 // modify alpha based on availability and vehicle hud
103 if(this.ItemStatus & ITS_AVAILABLE)
105 if(hud) // apparently this means we're in a vehicle lol
107 this.alpha *= autocvar_cl_items_vehicle_alpha;
108 this.colormod = this.glowmod = autocvar_cl_items_vehicle_color;
110 else if(this.ItemStatus & ITS_STAYWEP)
112 this.alpha *= autocvar_cl_weapon_stay_alpha;
113 this.colormod = this.glowmod = autocvar_cl_weapon_stay_color;
117 this.colormod = '1 1 1';
118 this.glowmod = this.item_glowmod;
123 this.alpha *= autocvar_cl_ghost_items;
124 this.colormod = this.glowmod = autocvar_cl_ghost_items_color;
127 this.drawmask = this.alpha <= 0 ? 0 : MASK_NORMAL;
130 void ItemRemove(entity this)
135 HashMap ENT_CLIENT_ITEM_simple;
136 STATIC_INIT(ENT_CLIENT_ITEM_simple)
138 HM_NEW(ENT_CLIENT_ITEM_simple);
140 SHUTDOWN(ENT_CLIENT_ITEM_simple)
142 HM_DELETE(ENT_CLIENT_ITEM_simple);
145 NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
149 if(sf & ISF_LOCATION)
151 float bobheight = this.origin_z - this.oldorigin_z;
152 this.origin = this.oldorigin = ReadVector();
153 this.origin_z += bobheight; // restore animation offset (SVQC physics is unaware of CSQC bbox offset)
154 setorigin(this, this.origin); // link
159 this.angles = this.angles_held = ReadAngleVector();
164 setsize(this, '-16 -16 0', '16 16 48');
167 if(sf & ISF_STATUS) // need to read/write status first so model can handle simple, fb etc.
169 this.ItemStatus = ReadByte();
171 if(this.ItemStatus & ITS_ALLOWFB)
172 this.effects |= EF_FULLBRIGHT;
174 this.effects &= ~EF_FULLBRIGHT;
176 if(this.ItemStatus & ITS_GLOW)
178 if(this.ItemStatus & ITS_AVAILABLE)
179 this.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
181 this.effects &= ~(EF_ADDITIVE | EF_FULLBRIGHT);
187 if (isnew) IL_PUSH(g_drawables, this);
188 this.draw = ItemDraw;
189 this.solid = SOLID_TRIGGER;
190 //this.flags |= FL_ITEM;
192 this.fade_end = ReadShort();
196 string _fn = ReadString();
197 this.item_simple = false; // reset it!
199 if(autocvar_cl_simple_items && (this.ItemStatus & ITS_ALLOWSI))
201 string _fn2 = substring(_fn, 0 , strlen(_fn) -4);
202 this.item_simple = true;
204 #define extensions(x) \
210 #define tryext(ext) { \
211 string s = strcat(_fn2, autocvar_cl_simpleitems_postfix, "." #ext); \
212 string cached = HM_gets(ENT_CLIENT_ITEM_simple, s); \
213 if (cached == "") { \
214 HM_sets(ENT_CLIENT_ITEM_simple, s, cached = fexists(s) ? "1" : "0"); \
216 if (cached != "0") { \
217 strcpy(this.mdl, s); \
223 this.item_simple = false;
224 LOG_TRACEF("Simple item requested for %s but no model exists for it", _fn);
230 if(!this.item_simple)
231 strcpy(this.mdl, _fn);
234 LOG_WARNF("this.mdl is unset for item %s", this.classname);
236 precache_model(this.mdl);
237 _setmodel(this, this.mdl);
239 this.skin = ReadByte();
241 setsize(this, '-16 -16 0', '16 16 48');
244 if(sf & ISF_COLORMAP)
246 this.colormap = ReadShort();
247 this.item_glowmod_x = ReadByte() / 255.0;
248 this.item_glowmod_y = ReadByte() / 255.0;
249 this.item_glowmod_z = ReadByte() / 255.0;
255 this.pushable = true;
256 //this.angles = '0 0 0';
257 set_movetype(this, MOVETYPE_TOSS);
258 this.velocity = ReadVector();
261 this.entremove = ItemRemove;