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