Merge branch 'master' into fruitiex/fruitbalance
[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
10 void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float alpha, float drawflag)
11 {
12         // I want to draw a quad...
13         // from and to are MIDPOINTS.
14         
15         vector axis, thickdir, A, B, C, D;
16         float length_tex;
17
18         axis = normalize(to - from);
19         length_tex = aspect * vlen(to - from) / thickness;
20
21         // direction is perpendicular to the view normal, and perpendicular to the axis
22         thickdir = normalize(cross(axis, view_origin - from));
23
24 /*
25         print("from ", vtos(from), "\n");
26         print("to ", vtos(to), "\n");
27         print("org ", vtos(view_origin), "\n");
28         print("dir ", vtos(thickdir), "\n");
29 */
30
31         A = from - thickdir * (thickness / 2);
32         B = from + thickdir * (thickness / 2);
33         C = to + thickdir * (thickness / 2);
34         D = to - thickdir * (thickness / 2);
35
36         R_BeginPolygon(texture, drawflag);
37         R_PolygonVertex(A, '0 0 0' + shift * '1 0 0', rgb, alpha);
38         R_PolygonVertex(B, '0 1 0' + shift * '1 0 0', rgb, alpha);
39         R_PolygonVertex(C, '0 1 0' + (shift + length_tex) * '1 0 0', rgb, alpha);
40         R_PolygonVertex(D, '0 0 0' + (shift + length_tex) * '1 0 0', rgb, alpha);
41         R_EndPolygon();
42 }
43
44 string Draw_GrapplingHook_trace_callback_tex;
45 float Draw_GrapplingHook_trace_callback_rnd;
46 void Draw_GrapplingHook_trace_callback(vector start, vector hit, vector end)
47 {
48         Draw_CylindricLine(hit, start, 8, Draw_GrapplingHook_trace_callback_tex, 0.25, Draw_GrapplingHook_trace_callback_rnd, '1 1 1', 1, DRAWFLAG_NORMAL);
49         Draw_GrapplingHook_trace_callback_rnd += 0.25 * vlen(hit - start) / 8;
50 }
51
52 void Draw_GrapplingHook()
53 {
54         vector a, b;
55         string tex;
56         vector rgb;
57         float t;
58         float s;
59         vector vs;
60
61         if(time < self.HookKillTime)
62         {
63                 s = cvar("cl_gunalign");
64                 if(s != 1 && s != 2 && s != 4)
65                         s = 3; // default value
66                 --s;
67                 vs = hook_shotorigin[s];
68
69                 if(self.sv_entnum == player_localentnum - 1)
70                         a = view_origin + view_forward * vs_x + view_right * -vs_y + view_up * vs_z;
71                 else
72                         a = self.HookStart;
73                 b = self.HookEnd;
74
75                 t = GetPlayerColorForce(self.sv_entnum);
76
77                 if(t == COLOR_TEAM1)
78                 {
79                         tex = "particles/hook_red";
80                         rgb = '1 .3 .3';
81                 }
82                 else if(t == COLOR_TEAM2)
83                 {
84                         tex = "particles/hook_blue";
85                         rgb = '.3 .3 1';
86                 }
87                 else if(t == COLOR_TEAM3)
88                 {
89                         tex = "particles/hook_yellow";
90                         rgb = '1 1 .3';
91                 }
92                 else if(t == COLOR_TEAM4)
93                 {
94                         tex = "particles/hook_pink";
95                         rgb = '1 .3 1';
96                 }
97                 else
98                 {
99                         tex = "particles/hook_green";
100                         rgb = '.3 1 .3';
101                 }
102
103                 Draw_GrapplingHook_trace_callback_tex = tex;
104                 Draw_GrapplingHook_trace_callback_rnd = random();
105                 WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, MOVE_NOMONSTERS, world, world, Draw_GrapplingHook_trace_callback);
106                 Draw_GrapplingHook_trace_callback_tex = string_null;
107         }
108
109         if(time < self.LGBeamKillTime)
110         {
111                 s = cvar("cl_gunalign");
112                 if(s != 1 && s != 2 && s != 4)
113                         s = 3; // default value
114                 --s;
115                 vs = electro_shotorigin[s];
116
117                 if(self.sv_entnum == player_localentnum - 1)
118                 {
119                         b = view_origin + view_forward * MAX_SHOT_DISTANCE;
120                         WarpZone_TraceLine(view_origin, b, MOVE_NORMAL, world);
121                         a = view_origin + view_forward * vs_x + view_right * -vs_y + view_up * vs_z;
122                 }
123                 else
124                 {
125                         a = self.LGBeamStart;
126                         b = self.LGBeamEnd;
127                 }
128
129                 tex = "particles/lgbeam";
130                 rgb = '1 1 1';
131
132                 Draw_GrapplingHook_trace_callback_tex = tex;
133                 Draw_GrapplingHook_trace_callback_rnd = random();
134                 WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, MOVE_NORMAL, world, world, Draw_GrapplingHook_trace_callback);
135                 Draw_GrapplingHook_trace_callback_tex = string_null;
136
137                 // helps the sound
138                 setorigin(self, a);
139         }
140
141         if(time < self.LGBeamKillTime && !self.LGBeamSilent)
142         {
143                 if(!self.LGBeamSound)
144                 {
145                         sound (self, CHAN_PROJECTILE, "weapons/lgbeam_fly.wav", VOL_BASE, ATTN_NORM);
146                         self.LGBeamSound = 1;
147                 }
148         }
149         else
150         {
151                 if(self.LGBeamSound)
152                 {
153                         sound (self, CHAN_PROJECTILE, "misc/null.wav", VOL_BASE, ATTN_NORM);
154                         self.LGBeamSound = 0;
155                 }
156         }
157 }
158
159 void Net_GrapplingHook()
160 {
161         float i, t;
162         vector start, end;
163         entity p;
164
165         i = ReadByte();
166         t = ReadByte();
167         end_x = ReadCoord();
168         end_y = ReadCoord();
169         end_z = ReadCoord();
170         start_x = ReadCoord();
171         start_y = ReadCoord();
172         start_z = ReadCoord();
173
174         if(i <= 0 || i >= 256) // not owned by a client
175                 return;
176         --i;
177
178         p = playerslots[i];
179         if(!p)
180                 return;
181
182         switch(t)
183         {
184                 case 0: // hook beam
185                         p.HookKillTime = time + 0.1;
186                         p.HookStart = start;
187                         p.HookEnd = end;
188                         p.draw = Draw_GrapplingHook;
189                         break;
190                 case 1: // electro lgbeam
191                         p.LGBeamKillTime = time + 0.1;
192                         p.LGBeamStart = start;
193                         p.LGBeamEnd = end;
194                         p.LGBeamSilent = 0;
195                         p.draw = Draw_GrapplingHook;
196                         break;
197                 case 2: // silent electro lgbeam
198                         p.LGBeamKillTime = time + 0.1;
199                         p.LGBeamStart = start;
200                         p.LGBeamEnd = end;
201                         p.LGBeamSilent = 1;
202                         p.draw = Draw_GrapplingHook;
203                         break;
204         }
205 }
206
207 void Hook_Precache()
208 {
209         precache_sound("weapons/lgbeam_fly.wav");
210 }