laser secondary gauntlet, lots of improvements to code
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hook.qc
1 .vector HookStart;
2 .vector HookEnd;
3 .float HookKillTime;
4 .vector LGBeamStart;
5 .vector LGBeamEnd;
6 .float LGBeamKillTime;
7 .float LGBeamSound;
8 .float LGBeamSilent;
9 .vector GauntletBeamStart;
10 .vector GauntletBeamEnd;
11 .float GauntletBeamKillTime;
12 .float GauntletBeamSound;
13 .float GauntletBeamSilent;
14
15
16 void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float alpha, float drawflag)
17 {
18         // I want to draw a quad...
19         // from and to are MIDPOINTS.
20         
21         vector axis, thickdir, A, B, C, D;
22         float length_tex;
23
24         axis = normalize(to - from);
25         length_tex = aspect * vlen(to - from) / thickness;
26
27         // direction is perpendicular to the view normal, and perpendicular to the axis
28         thickdir = normalize(cross(axis, view_origin - from));
29
30 /*
31         print("from ", vtos(from), "\n");
32         print("to ", vtos(to), "\n");
33         print("org ", vtos(view_origin), "\n");
34         print("dir ", vtos(thickdir), "\n");
35 */
36
37         A = from - thickdir * (thickness / 2);
38         B = from + thickdir * (thickness / 2);
39         C = to + thickdir * (thickness / 2);
40         D = to - thickdir * (thickness / 2);
41
42         R_BeginPolygon(texture, drawflag);
43         R_PolygonVertex(A, '0 0 0' + shift * '1 0 0', rgb, alpha);
44         R_PolygonVertex(B, '0 1 0' + shift * '1 0 0', rgb, alpha);
45         R_PolygonVertex(C, '0 1 0' + (shift + length_tex) * '1 0 0', rgb, alpha);
46         R_PolygonVertex(D, '0 0 0' + (shift + length_tex) * '1 0 0', rgb, alpha);
47         R_EndPolygon();
48 }
49
50 string Draw_GrapplingHook_trace_callback_tex;
51 float Draw_GrapplingHook_trace_callback_rnd;
52 void Draw_GrapplingHook_trace_callback(vector start, vector hit, vector end)
53 {
54         Draw_CylindricLine(hit, start, 8, Draw_GrapplingHook_trace_callback_tex, 0.25, Draw_GrapplingHook_trace_callback_rnd, '1 1 1', 1, DRAWFLAG_NORMAL);
55         Draw_GrapplingHook_trace_callback_rnd += 0.25 * vlen(hit - start) / 8;
56 }
57
58 void Draw_GrapplingHook()
59 {
60         vector a, b;
61         string tex;
62         vector rgb;
63         float t;
64         float s;
65         vector vs;
66
67         if(time < self.HookKillTime)
68         {
69                 s = cvar("cl_gunalign");
70                 if(s != 1 && s != 2 && s != 4)
71                         s = 3; // default value
72                 --s;
73                 vs = hook_shotorigin[s];
74
75                 if(self.sv_entnum == player_localentnum - 1)
76                         a = view_origin + view_forward * vs_x + view_right * -vs_y + view_up * vs_z;
77                 else
78                         a = self.HookStart;
79                 b = self.HookEnd;
80
81                 t = GetPlayerColorForce(self.sv_entnum);
82
83                 if(t == COLOR_TEAM1)
84                 {
85                         tex = "particles/hook_red";
86                         rgb = '1 .3 .3';
87                 }
88                 else if(t == COLOR_TEAM2)
89                 {
90                         tex = "particles/hook_blue";
91                         rgb = '.3 .3 1';
92                 }
93                 else if(t == COLOR_TEAM3)
94                 {
95                         tex = "particles/hook_yellow";
96                         rgb = '1 1 .3';
97                 }
98                 else if(t == COLOR_TEAM4)
99                 {
100                         tex = "particles/hook_pink";
101                         rgb = '1 .3 1';
102                 }
103                 else
104                 {
105                         tex = "particles/hook_green";
106                         rgb = '.3 1 .3';
107                 }
108
109                 Draw_GrapplingHook_trace_callback_tex = tex;
110                 Draw_GrapplingHook_trace_callback_rnd = random();
111                 WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, MOVE_NOMONSTERS, world, world, Draw_GrapplingHook_trace_callback);
112                 Draw_GrapplingHook_trace_callback_tex = string_null;
113         }
114
115         if(time < self.LGBeamKillTime)
116         {
117                 s = cvar("cl_gunalign");
118                 if(s != 1 && s != 2 && s != 4)
119                         s = 3; // default value
120                 --s;
121                 vs = electro_shotorigin[s];
122
123                 if(self.sv_entnum == player_localentnum - 1)
124                 {
125                         b = view_origin + view_forward * MAX_SHOT_DISTANCE;
126                         WarpZone_TraceLine(view_origin, b, MOVE_NORMAL, world);
127                         a = view_origin + view_forward * vs_x + view_right * -vs_y + view_up * vs_z;
128                 }
129                 else
130                 {
131                         a = self.LGBeamStart;
132                         b = self.LGBeamEnd;
133                 }
134
135                 tex = "particles/lgbeam";
136                 rgb = '1 1 1';
137
138                 Draw_GrapplingHook_trace_callback_tex = tex;
139                 Draw_GrapplingHook_trace_callback_rnd = random();
140                 WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, MOVE_NORMAL, world, world, Draw_GrapplingHook_trace_callback);
141                 Draw_GrapplingHook_trace_callback_tex = string_null;
142
143                 // helps the sound
144                 setorigin(self, a);
145         }
146
147         if(time < self.GauntletBeamKillTime)
148         {
149                 s = cvar("cl_gunalign");
150                 if(s != 1 && s != 2 && s != 4)
151                         s = 3; // default value
152                 --s;
153                 vs = gauntlet_shotorigin[s];
154
155                 if(self.sv_entnum == player_localentnum - 1)
156                 {
157                         b = view_origin + view_forward * MAX_SHOT_DISTANCE;
158                         WarpZone_TraceLine(view_origin, b, MOVE_NORMAL, world);
159                         a = view_origin + view_forward * vs_x + view_right * -vs_y + view_up * vs_z;
160                 }
161                 else
162                 {
163                         a = self.GauntletBeamStart;
164                         b = self.GauntletBeamEnd;
165                 }
166
167                 tex = "particles/gauntletbeam";
168                 rgb = '1 1 1';
169
170                 Draw_GrapplingHook_trace_callback_tex = tex;
171                 Draw_GrapplingHook_trace_callback_rnd = random();
172                 WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, MOVE_NORMAL, world, world, Draw_GrapplingHook_trace_callback);
173                 Draw_GrapplingHook_trace_callback_tex = string_null;
174
175                 // helps the sound
176                 setorigin(self, a);
177         }
178
179         if(time < self.LGBeamKillTime && !self.LGBeamSilent)
180         {
181                 if(!self.LGBeamSound)
182                 {
183                         sound (self, CHAN_PROJECTILE, "weapons/lgbeam_fly.wav", VOL_BASE, ATTN_NORM);
184                         self.LGBeamSound = 1;
185                 }
186         }
187         else
188         {
189                 if(self.LGBeamSound)
190                 {
191                         sound (self, CHAN_PROJECTILE, "misc/null.wav", VOL_BASE, ATTN_NORM);
192                         self.LGBeamSound = 0;
193                 }
194         }
195
196         if(time < self.GauntletBeamKillTime && !self.GauntletBeamSilent)
197         {
198                 if(!self.GauntletBeamSound)
199                 {
200                         sound (self, CHAN_PROJECTILE, "weapons/gauntletbeam_fly.wav", VOL_BASE, ATTN_NORM);
201                         self.GauntletBeamSound = 1;
202                 }
203         }
204         else
205         {
206                 if(self.GauntletBeamSound)
207                 {
208                         sound (self, CHAN_PROJECTILE, "misc/null.wav", VOL_BASE, ATTN_NORM);
209                         self.GauntletBeamSound = 0;
210                 }
211         }
212 }
213
214 void Net_GrapplingHook()
215 {
216         float i, t;
217         vector start, end;
218         entity p;
219
220         i = ReadByte();
221         t = ReadByte();
222         end_x = ReadCoord();
223         end_y = ReadCoord();
224         end_z = ReadCoord();
225         start_x = ReadCoord();
226         start_y = ReadCoord();
227         start_z = ReadCoord();
228
229         if(i <= 0 || i >= 256) // not owned by a client
230                 return;
231         --i;
232
233         p = playerslots[i];
234         if(!p)
235                 return;
236
237         switch(t)
238         {
239                 case 0: // hook beam
240                         p.HookKillTime = time + 0.1;
241                         p.HookStart = start;
242                         p.HookEnd = end;
243                         p.draw = Draw_GrapplingHook;
244                         break;
245                 case 1: // electro lgbeam
246                         p.LGBeamKillTime = time + 0.1;
247                         p.LGBeamStart = start;
248                         p.LGBeamEnd = end;
249                         p.LGBeamSilent = 0;
250                         p.draw = Draw_GrapplingHook;
251                         break;
252                 case 2: // silent electro lgbeam
253                         p.LGBeamKillTime = time + 0.1;
254                         p.LGBeamStart = start;
255                         p.LGBeamEnd = end;
256                         p.LGBeamSilent = 1;
257                         p.draw = Draw_GrapplingHook;
258                         break;
259                 case 3: // gauntlet beam
260                         p.GauntletBeamKillTime = time + 0.1;
261                         p.GauntletBeamStart = start;
262                         p.GauntletBeamEnd = end;
263                         p.GauntletBeamSilent = 0;
264                         p.draw = Draw_GrapplingHook;
265                         break;
266         }
267 }
268
269 void Hook_Precache()
270 {
271         precache_sound("weapons/lgbeam_fly.wav");
272         precache_sound("weapons/gauntletbeam_fly.wav");
273 }