]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/items/items.qc
Purge client/defs.qh
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / items / items.qc
1 #include "items.qh"
2
3 #include <common/items/_mod.qh>
4
5 #include <client/main.qh>
6 #include <common/physics/movetypes/movetypes.qh>
7 #include <common/weapons/_all.qh>
8 #include <lib/csqcmodel/cl_model.qh>
9 #include <lib/csqcmodel/common.qh>
10 #include <lib/warpzone/common.qh>
11
12 bool autocvar_cl_ghost_items_vehicle = true;
13 .vector item_glowmod;
14 .bool item_simple; // probably not really needed, but better safe than sorry
15 .float alpha;
16 .bool pushable;
17 void Item_SetAlpha(entity this)
18 {
19         bool veh_hud = (hud && autocvar_cl_ghost_items_vehicle);
20
21         if(!veh_hud && (this.ItemStatus & ITS_AVAILABLE))
22         {
23                 this.alpha = 1;
24                 this.colormod = '1 1 1';
25                 this.glowmod = this.item_glowmod;
26         }
27         else
28         {
29                 this.alpha = autocvar_cl_ghost_items;
30                 this.colormod = this.glowmod = autocvar_cl_ghost_items_color;
31         }
32
33         if((!veh_hud) && (this.ItemStatus & ITS_STAYWEP))
34         {
35                 this.colormod = this.glowmod = autocvar_cl_weapon_stay_color;
36                 this.alpha = autocvar_cl_weapon_stay_alpha;
37         }
38
39         this.drawmask = ((this.alpha <= 0) ? 0 : MASK_NORMAL);
40 }
41
42 void ItemDraw(entity this)
43 {
44     if(this.gravity)
45     {
46         Movetype_Physics_MatchServer(this, false);
47         if(IS_ONGROUND(this))
48         { // For some reason avelocity gets set to '0 0 0' here ...
49             this.oldorigin = this.origin;
50             this.gravity = 0;
51
52             if(autocvar_cl_animate_items)
53             { // ... so reset it if animations are requested.
54                 if(this.ItemStatus & ITS_ANIMATE1)
55                     this.avelocity = '0 180 0';
56
57                 if(this.ItemStatus & ITS_ANIMATE2)
58                     this.avelocity = '0 -90 0';
59             }
60
61             // delay is for blocking item's position for a while;
62             // it's a workaround for dropped weapons that receive the position
63             // another time right after they spawn overriding animation position
64             this.onground_time = time + 0.5;
65         }
66     }
67     else if (autocvar_cl_animate_items && !this.item_simple) // no bobbing applied to simple items, for consistency's sake (no visual difference between ammo and weapons)
68     {
69         if(this.ItemStatus & ITS_ANIMATE1)
70         {
71                 this.angles += this.avelocity * frametime;
72             float fade_in = bound(0, time - this.onground_time, 1);
73             setorigin(this, this.oldorigin + fade_in * ('0 0 10' + '0 0 8' * sin((time - this.onground_time) * 2)));
74         }
75
76         if(this.ItemStatus & ITS_ANIMATE2)
77         {
78                 this.angles += this.avelocity * frametime;
79             float fade_in = bound(0, time - this.onground_time, 1);
80             setorigin(this, this.oldorigin + fade_in * ('0 0 8' + '0 0 4' * sin((time - this.onground_time) * 3)));
81         }
82     }
83
84     Item_SetAlpha(this);
85 }
86
87 void Item_PreDraw(entity this)
88 {
89         if(warpzone_warpzones_exist)
90         {
91                 setpredraw(this, func_null); // no need to keep running this
92                 return;
93         }
94         float alph;
95         vector org = getpropertyvec(VF_ORIGIN);
96         //if(!checkpvs(org, this)) // this makes sense as long as we don't support recursive warpzones
97                 //alph = 0; // this shouldn't be needed, since items behind walls are culled anyway
98         if(this.fade_start)
99         {
100                 if(vdist(org - this.origin, >, this.fade_end))
101                         alph = 0; // save on some processing
102                 else if(vdist(org - this.origin, <, this.fade_start))
103                         alph = 1; // more processing saved
104                 else
105                         alph = bound(0, (this.fade_end - vlen(org - this.origin - 0.5 * (this.mins + this.maxs))) / (this.fade_end - this.fade_start), 1);
106         }
107         else
108                 alph = 1;
109         //printf("%v <-> %v\n", view_origin, this.origin + 0.5 * (this.mins + this.maxs));
110         if(!hud && (this.ItemStatus & ITS_AVAILABLE))
111                 this.alpha = alph;
112         if(alph <= 0)
113                 this.drawmask = 0;
114         //else
115                 //this.drawmask = MASK_NORMAL; // reset by the setalpha function
116 }
117
118 void ItemRemove(entity this)
119 {
120         strfree(this.mdl);
121 }
122
123 HashMap ENT_CLIENT_ITEM_simple;
124 STATIC_INIT(ENT_CLIENT_ITEM_simple)
125 {
126         HM_NEW(ENT_CLIENT_ITEM_simple);
127 }
128 SHUTDOWN(ENT_CLIENT_ITEM_simple)
129 {
130         HM_DELETE(ENT_CLIENT_ITEM_simple);
131 }
132
133 NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
134 {
135     int sf = ReadByte();
136
137     if(sf & ISF_LOCATION)
138     {
139         this.origin = ReadVector();
140         setorigin(this, this.origin);
141         this.oldorigin = this.origin;
142     }
143
144     if(sf & ISF_ANGLES)
145     {
146         this.angles = ReadAngleVector();
147     }
148
149     if(sf & ISF_SIZE)
150     {
151         setsize(this, '-16 -16 0', '16 16 48');
152     }
153
154     if(sf & ISF_STATUS) // need to read/write status first so model can handle simple, fb etc.
155     {
156         this.ItemStatus = ReadByte();
157
158         Item_SetAlpha(this);
159
160         if(this.ItemStatus & ITS_ALLOWFB)
161             this.effects |= EF_FULLBRIGHT;
162         else
163             this.effects &= ~EF_FULLBRIGHT;
164
165         if(this.ItemStatus & ITS_GLOW)
166         {
167             if(this.ItemStatus & ITS_AVAILABLE)
168                 this.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
169             else
170                 this.effects &= ~(EF_ADDITIVE | EF_FULLBRIGHT);
171         }
172     }
173
174     if(sf & ISF_MODEL)
175     {
176         this.drawmask  = MASK_NORMAL;
177                 set_movetype(this, MOVETYPE_TOSS);
178                 if (isnew) IL_PUSH(g_drawables, this);
179         this.draw       = ItemDraw;
180         this.solid = SOLID_TRIGGER;
181         //this.flags |= FL_ITEM;
182
183         this.fade_end = ReadShort();
184         this.fade_start = ReadShort();
185         if(!warpzone_warpzones_exist && this.fade_start && !autocvar_cl_items_nofade)
186                 setpredraw(this, Item_PreDraw);
187
188                 strfree(this.mdl);
189
190         string _fn = ReadString();
191         this.item_simple = false; // reset it!
192
193         if(autocvar_cl_simple_items && (this.ItemStatus & ITS_ALLOWSI))
194         {
195             string _fn2 = substring(_fn, 0 , strlen(_fn) -4);
196             this.item_simple = true;
197
198                         #define extensions(x) \
199                                 x(md3) \
200                                 x(dpm) \
201                                 x(iqm) \
202                                 x(mdl) \
203                                 /**/
204                         #define tryext(ext) { \
205                                 string s = strcat(_fn2, autocvar_cl_simpleitems_postfix, "." #ext); \
206                                 string cached = HM_gets(ENT_CLIENT_ITEM_simple, s); \
207                                 if (cached == "") { \
208                                         HM_sets(ENT_CLIENT_ITEM_simple, s, cached = fexists(s) ? "1" : "0"); \
209                                 } \
210                                 if (cached != "0") { \
211                                         strcpy(this.mdl, s); \
212                                         break; \
213                                 } \
214                         }
215                         do {
216                                 extensions(tryext);
217                                 this.item_simple = false;
218                 LOG_TRACEF("Simple item requested for %s but no model exists for it", _fn);
219                         } while (0);
220                         #undef tryext
221                         #undef extensions
222         }
223
224         if(!this.item_simple)
225             strcpy(this.mdl, _fn);
226
227         if(this.mdl == "")
228             LOG_WARNF("this.mdl is unset for item %s", this.classname);
229
230         precache_model(this.mdl);
231         _setmodel(this, this.mdl);
232
233         setsize(this, '-16 -16 0', '16 16 48');
234     }
235
236     if(sf & ISF_COLORMAP)
237     {
238         this.colormap = ReadShort();
239         this.item_glowmod_x = ReadByte() / 255.0;
240         this.item_glowmod_y = ReadByte() / 255.0;
241         this.item_glowmod_z = ReadByte() / 255.0;
242     }
243
244     if(sf & ISF_DROP)
245     {
246         this.gravity = 1;
247         this.pushable = true;
248         //this.angles = '0 0 0';
249         set_movetype(this, MOVETYPE_TOSS);
250         this.velocity = ReadVector();
251         setorigin(this, this.oldorigin);
252
253         if(!this.move_time)
254         {
255             this.move_time = time;
256             this.spawntime = time;
257         }
258         else
259             this.move_time = max(this.move_time, time);
260     }
261
262     if(autocvar_cl_animate_items)
263     {
264         if(this.ItemStatus & ITS_ANIMATE1)
265             this.avelocity = '0 180 0';
266
267         if(this.ItemStatus & ITS_ANIMATE2)
268             this.avelocity = '0 -90 0';
269     }
270
271     this.entremove = ItemRemove;
272
273     return true;
274 }