fix is_right
[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                         a = view_origin + view_forward * vs_x + view_right * -vs_y + view_up * vs_z;
119                 else
120                         a = self.LGBeamStart;
121                 b = self.LGBeamEnd;
122
123                 tex = "particles/lgbeam";
124                 rgb = '1 1 1';
125
126                 Draw_GrapplingHook_trace_callback_tex = tex;
127                 Draw_GrapplingHook_trace_callback_rnd = random();
128                 WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, MOVE_NOMONSTERS, world, world, Draw_GrapplingHook_trace_callback);
129                 Draw_GrapplingHook_trace_callback_tex = string_null;
130
131                 // helps the sound
132                 setorigin(self, a);
133         }
134
135         if(time < self.LGBeamKillTime && !self.LGBeamSilent)
136         {
137                 if(!self.LGBeamSound)
138                 {
139                         sound (self, CHAN_PROJECTILE, "weapons/lgbeam_fly.wav", VOL_BASE, ATTN_NORM);
140                         self.LGBeamSound = 1;
141                 }
142         }
143         else
144         {
145                 if(self.LGBeamSound)
146                 {
147                         sound (self, CHAN_PROJECTILE, "misc/null.wav", VOL_BASE, ATTN_NORM);
148                         self.LGBeamSound = 0;
149                 }
150         }
151 }
152
153 void Net_GrapplingHook()
154 {
155         float i, t;
156         vector start, end;
157         entity p;
158
159         i = ReadByte();
160         t = ReadByte();
161         end_x = ReadCoord();
162         end_y = ReadCoord();
163         end_z = ReadCoord();
164         start_x = ReadCoord();
165         start_y = ReadCoord();
166         start_z = ReadCoord();
167
168         if(i <= 0 || i >= 256) // not owned by a client
169                 return;
170         --i;
171
172         p = playerslots[i];
173         if(!p)
174                 return;
175
176         switch(t)
177         {
178                 case 0: // hook beam
179                         p.HookKillTime = time + 0.1;
180                         p.HookStart = start;
181                         p.HookEnd = end;
182                         p.draw = Draw_GrapplingHook;
183                         break;
184                 case 1: // electro lgbeam
185                         p.LGBeamKillTime = time + 0.1;
186                         p.LGBeamStart = start;
187                         p.LGBeamEnd = end;
188                         p.LGBeamSilent = 0;
189                         p.draw = Draw_GrapplingHook;
190                         break;
191                 case 2: // silent electro lgbeam
192                         p.LGBeamKillTime = time + 0.1;
193                         p.LGBeamStart = start;
194                         p.LGBeamEnd = end;
195                         p.LGBeamSilent = 1;
196                         p.draw = Draw_GrapplingHook;
197                         break;
198         }
199 }
200
201 void Hook_Precache()
202 {
203         precache_sound("weapons/lgbeam_fly.wav");
204 }