3a6765e9d46fbfc7ed9025238cfe8017a1fc5bde
[xonotic/xonotic-data.pk3dir.git] / qcsrc / lib / warpzone / client.qc
1 #include "client.qh"
2 #include "common.qh"
3
4 #if defined(CSQC)
5         #include <client/autocvars.qh>
6         #include <lib/csqcmodel/cl_model.qh>
7 #elif defined(MENUQC)
8 #elif defined(SVQC)
9 #endif
10
11 void WarpZone_Fade_PreDraw(entity this)
12 {
13         vector org;
14         org = getpropertyvec(VF_ORIGIN);
15         if(!checkpvs(org, this)) // this makes sense as long as we don't support recursive warpzones
16                 this.alpha = 0;
17         else if(this.warpzone_fadestart)
18                 this.alpha = bound(0, (this.warpzone_fadeend - vlen(org - this.origin - 0.5 * (this.mins + this.maxs))) / (this.warpzone_fadeend - this.warpzone_fadestart), 1);
19         else
20                 this.alpha = 1;
21         //printf("%v <-> %v\n", view_origin, this.origin + 0.5 * (this.mins + this.maxs));
22         if(this.alpha <= 0)
23                 this.drawmask = 0;
24         else
25                 this.drawmask = MASK_NORMAL;
26 }
27
28 void WarpZone_Touch(entity this, entity toucher);
29 NET_HANDLE(ENT_CLIENT_WARPZONE, bool isnew)
30 {
31         warpzone_warpzones_exist = 1;
32         if (!this.enemy)
33         {
34                 this.enemy = new(warpzone_from);
35         }
36         this.classname = "trigger_warpzone";
37
38         if(isnew)
39                 IL_PUSH(g_warpzones, this);
40
41         int f = ReadByte();
42         this.warpzone_isboxy = (f & 1);
43         if(f & 4)
44         {
45                 this.origin = ReadVector();
46         }
47         else
48                 this.origin = '0 0 0';
49         this.modelindex = ReadShort();
50         this.mins = ReadVector();
51         this.maxs = ReadVector();
52         this.scale = ReadByte() / 16;
53         this.enemy.oldorigin = ReadVector();
54         this.enemy.avelocity = ReadVector();
55         this.oldorigin = ReadVector();
56         this.avelocity = ReadVector();
57
58         if(f & 2)
59         {
60                 this.warpzone_fadestart = ReadShort();
61                 this.warpzone_fadeend = max(this.warpzone_fadestart + 1, ReadShort());
62         }
63         else
64         {
65                 this.warpzone_fadestart = 0;
66                 this.warpzone_fadeend = 0;
67         }
68
69         // common stuff
70         WarpZone_SetUp(this, this.enemy.oldorigin, this.enemy.avelocity, this.oldorigin, this.avelocity);
71
72         // link me
73         //setmodel(this, this.model);
74         setorigin(this, this.origin);
75         setsize(this, this.mins, this.maxs);
76
77         // how to draw
78         // engine currently wants this
79         setpredraw(this, WarpZone_Fade_PreDraw);
80
81         //settouch(this, WarpZone_Touch);
82         return true;
83 }
84
85 NET_HANDLE(ENT_CLIENT_WARPZONE_CAMERA, bool isnew)
86 {
87         warpzone_cameras_exist = 1;
88         this.classname = "func_warpzone_camera";
89
90         int f = ReadByte();
91         if(f & 4)
92         {
93                 this.origin = ReadVector();
94         }
95         else
96                 this.origin = '0 0 0';
97         this.modelindex = ReadShort();
98         this.mins = ReadVector();
99         this.maxs = ReadVector();
100         this.scale = ReadByte() / 16;
101         this.oldorigin = ReadVector();
102         this.avelocity = ReadVector();
103
104         if(f & 2)
105         {
106                 this.warpzone_fadestart = ReadShort();
107                 this.warpzone_fadeend = max(this.warpzone_fadestart + 1, ReadShort());
108         }
109         else
110         {
111                 this.warpzone_fadestart = 0;
112                 this.warpzone_fadeend = 0;
113         }
114
115         // common stuff
116         WarpZone_Camera_SetUp(this, this.oldorigin, this.avelocity);
117
118         // engine currently wants this
119         this.drawmask = MASK_NORMAL;
120
121         // link me
122         //setmodel(this, this.model);
123         setorigin(this, this.origin);
124         setsize(this, this.mins, this.maxs);
125
126         // how to draw
127         // engine currently wants this
128         setpredraw(this, WarpZone_Fade_PreDraw);
129         return true;
130 }
131
132 void CL_RotateMoves(vector ang) = #638;
133 NET_HANDLE(ENT_CLIENT_WARPZONE_TELEPORTED, bool isnew)
134 {
135         this.classname = "warpzone_teleported";
136         vector v = ReadVector();
137         return = true;
138         if (!isnew) return;
139         this.warpzone_transform = v;
140         setproperty(VF_CL_VIEWANGLES, WarpZone_TransformVAngles(this, getpropertyvec(VF_CL_VIEWANGLES)));
141         if(checkextension("DP_CSQC_ROTATEMOVES"))
142                 CL_RotateMoves(v);
143                 //CL_RotateMoves('0 90 0');
144 }
145
146 float warpzone_fixingview;
147 float warpzone_fixingview_drawexteriormodel;
148
149 void WarpZone_View_Outside()
150 {
151         if(!warpzone_fixingview)
152                 return;
153         warpzone_fixingview = 0;
154         cvar_set("r_drawexteriormodel", ftos(warpzone_fixingview_drawexteriormodel));
155 }
156
157 void WarpZone_View_Inside()
158 {
159         if(autocvar_chase_active)
160         {
161                 WarpZone_View_Outside();
162                 return;
163         }
164         if(warpzone_fixingview)
165                 return;
166         warpzone_fixingview = 1;
167         warpzone_fixingview_drawexteriormodel = cvar("r_drawexteriormodel");
168         cvar_set("r_drawexteriormodel", "0");
169 }
170
171 vector WarpZone_FixNearClip(vector o, vector c0, vector c1, vector c2, vector c3)
172 {
173         vector mi, ma;
174         entity e;
175         float pd;
176
177         mi.x = min(o.x, c0_x, c1_x, c2_x, c3_x);
178         ma.x = max(o.x, c0_x, c1_x, c2_x, c3_x);
179         mi.y = min(o.y, c0_y, c1_y, c2_y, c3_y);
180         ma.y = max(o.y, c0_y, c1_y, c2_y, c3_y);
181         mi.z = min(o.z, c0_z, c1_z, c2_z, c3_z);
182         ma.z = max(o.z, c0_z, c1_z, c2_z, c3_z);
183
184         e = WarpZone_Find(mi, ma);
185         if(e)
186         {
187                 if(WarpZone_PlaneDist(e, o) < 0)
188                         return '0 0 0';
189                         // can't really be, though, but if it is, this is not my warpzone, but a random different one in the same mins/maxs
190                 pd = min(
191                                 WarpZone_PlaneDist(e, c0),
192                                 WarpZone_PlaneDist(e, c1),
193                                 WarpZone_PlaneDist(e, c2),
194                                 WarpZone_PlaneDist(e, c3)
195                         );
196                 if(pd < 0)
197                         return e.warpzone_forward * -pd;
198         }
199
200         return '0 0 0';
201 }
202
203 void WarpZone_FixPMove()
204 {
205         entity e = WarpZone_Find(pmove_org, pmove_org);
206         if(e)
207         {
208                 pmove_org = WarpZone_TransformOrigin(e, pmove_org);
209                 input_angles = WarpZone_TransformVAngles(e, input_angles);
210         }
211 }
212
213 #ifndef KEEP_ROLL
214 float autocvar_cl_rollkillspeed = 10;
215 #endif
216 void WarpZone_FixView()
217 {
218         entity e;
219         vector org, ang, nearclip, corner0, corner1, corner2, corner3, o;
220
221         warpzone_save_view_origin = org = getpropertyvec(VF_ORIGIN);
222         warpzone_save_view_angles = ang = getpropertyvec(VF_ANGLES);
223
224         e = WarpZone_Find(org, org);
225         if(e)
226         {
227                 org = WarpZone_TransformOrigin(e, org);
228                 ang = WarpZone_TransformVAngles(e, ang);
229                 WarpZone_View_Inside();
230         }
231         else
232                 WarpZone_View_Outside();
233
234 #ifndef KEEP_ROLL
235         float rick;
236         float f;
237         static float rollkill;
238         if (STAT(HEALTH) > 0 || STAT(HEALTH) == -666 || STAT(HEALTH) == -2342)
239         {
240                 f = 0;
241                 // reset roll when passing through a warpzone that change player's roll angle
242                 if(autocvar_cl_rollkillspeed)
243                         f = max(0, (1 - frametime * autocvar_cl_rollkillspeed));
244                 if(rollkill)
245                         rollkill = 0;
246         }
247         else
248         {
249                 f = 1;
250                 // roll the view when killed (v_deathtilt)
251                 if(autocvar_cl_rollkillspeed)
252                 {
253                         rollkill += frametime * autocvar_cl_rollkillspeed;
254                         f = min(1, rollkill);
255                 }
256                 else if(rollkill)
257                         rollkill = 0;
258         }
259
260         rick = getproperty(VF_CL_VIEWANGLES_Z);
261         rick *= f;
262         setproperty(VF_CL_VIEWANGLES_Z, rick);
263         ang.z *= f;
264 #endif
265
266         setproperty(VF_ORIGIN, org);
267         setproperty(VF_ANGLES, ang);
268
269         nearclip = '0 0 1' * (cvar("r_nearclip") * 1.125);
270         corner0 = cs_unproject('0 0 0' + nearclip);
271         corner1 = cs_unproject('1 0 0' * cvar("vid_conwidth") + nearclip);
272         corner2 = cs_unproject('0 1 0' * cvar("vid_conheight") + nearclip);
273         corner3 = cs_unproject('1 0 0' * cvar("vid_conwidth") + '0 1 0' * cvar("vid_conheight") + nearclip);
274         o = WarpZone_FixNearClip(org, corner0, corner1, corner2, corner3);
275         if(o != '0 0 0')
276                 setproperty(VF_ORIGIN, org + o);
277 }
278
279 void WarpZone_Shutdown()
280 {
281         WarpZone_View_Outside();
282 }