Draw: purge SELFPARAM
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hook.qc
1 #include "hook.qh"
2 #include "_all.qh"
3
4 #include "hud.qh"
5
6 #include "../common/teams.qh"
7
8 #include "../csqcmodellib/interpolate.qh"
9
10 #include "../warpzonelib/common.qh"
11
12 entityclass(Hook);
13 class(Hook) .float HookType; // ENT_CLIENT_*
14 class(Hook) .vector origin;
15 class(Hook) .vector velocity;
16 class(Hook) .float HookSilent;
17 class(Hook) .float HookRange;
18
19 string Draw_GrapplingHook_trace_callback_tex;
20 float Draw_GrapplingHook_trace_callback_rnd;
21 vector Draw_GrapplingHook_trace_callback_rgb;
22 float Draw_GrapplingHook_trace_callback_a;
23 void Draw_GrapplingHook_trace_callback(vector start, vector hit, vector end)
24 {
25         float i;
26         vector vorg;
27         vorg = WarpZone_TransformOrigin(WarpZone_trace_transform, view_origin);
28         for(i = 0; i < Draw_GrapplingHook_trace_callback_a; ++i)
29                 Draw_CylindricLine(hit, start, 8, Draw_GrapplingHook_trace_callback_tex, 0.25, Draw_GrapplingHook_trace_callback_rnd, Draw_GrapplingHook_trace_callback_rgb, min(1, Draw_GrapplingHook_trace_callback_a - i), DRAWFLAG_NORMAL, vorg);
30         Draw_GrapplingHook_trace_callback_rnd += 0.25 * vlen(hit - start) / 8;
31 }
32
33 class(Hook) .float teleport_time;
34 void Draw_GrapplingHook(entity this)
35 {
36         vector a, b, atrans;
37         string tex;
38         vector rgb;
39         float t;
40         int s;
41         vector vs;
42         float intensity, offset;
43
44         if(self.teleport_time)
45         if(time > self.teleport_time)
46         {
47                 sound (self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM); // safeguard
48                 self.teleport_time = 0;
49         }
50
51         InterpolateOrigin_Do();
52
53         s = autocvar_cl_gunalign;
54         if(s != 1 && s != 2 && s != 4)
55                 s = 3; // default value
56         --s;
57         switch(self.HookType)
58         {
59                 default:
60                 case ENT_CLIENT_HOOK:
61                         vs = hook_shotorigin[s];
62                         break;
63                 case ENT_CLIENT_ARC_BEAM:
64                         vs = lightning_shotorigin[s];
65                         break;
66         }
67
68         if((self.owner.sv_entnum == player_localentnum - 1) && autocvar_chase_active <= 0)
69         {
70                 switch(self.HookType)
71                 {
72                         default:
73                         case ENT_CLIENT_HOOK:
74                                 a = view_origin + view_forward * vs.x + view_right * -vs.y + view_up * vs.z;
75                                 b = self.origin;
76                                 break;
77                         case ENT_CLIENT_ARC_BEAM:
78                                 if(self.HookRange)
79                                         b = view_origin + view_forward * self.HookRange;
80                                 else
81                                         b = view_origin + view_forward * vlen(self.velocity - self.origin); // honor original length of beam!
82                                 WarpZone_TraceLine(view_origin, b, MOVE_NORMAL, world);
83                                 b = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
84                                 a = view_origin + view_forward * vs.x + view_right * -vs.y + view_up * vs.z;
85                                 break;
86                 }
87         }
88         else
89         {
90                 switch(self.HookType)
91                 {
92                         default:
93                         case ENT_CLIENT_HOOK:
94                                 a = self.velocity;
95                                 b = self.origin;
96                                 break;
97                         case ENT_CLIENT_ARC_BEAM:
98                                 a = self.origin;
99                                 b = self.velocity;
100                                 break;
101                 }
102         }
103
104         t = GetPlayerColorForce(self.owner.sv_entnum);
105
106         switch(self.HookType)
107         {
108                 default:
109                 case ENT_CLIENT_HOOK:
110                         intensity = 1;
111                         offset = 0;
112                         switch(t)
113                         {
114                                 case NUM_TEAM_1: tex = "particles/hook_red"; rgb = '1 0.3 0.3'; break;
115                                 case NUM_TEAM_2: tex = "particles/hook_blue"; rgb = '0.3 0.3 1'; break;
116                                 case NUM_TEAM_3: tex = "particles/hook_yellow"; rgb = '1 1 0.3'; break;
117                                 case NUM_TEAM_4: tex = "particles/hook_pink"; rgb = '1 0.3 1'; break;
118                                 default: tex = "particles/hook_white"; rgb = getcsqcplayercolor(self.sv_entnum); break;
119                         }
120                         break;
121                 case ENT_CLIENT_ARC_BEAM: // todo
122                         intensity = bound(0.2, 1 + Noise_Pink(self, frametime) * 1 + Noise_Burst(self, frametime, 0.03) * 0.3, 2);
123                         offset = Noise_Brown(self, frametime) * 10;
124                         tex = "particles/lgbeam";
125                         rgb = '1 1 1';
126                         break;
127         }
128
129         Draw_GrapplingHook_trace_callback_tex = tex;
130         Draw_GrapplingHook_trace_callback_rnd = offset;
131         Draw_GrapplingHook_trace_callback_rgb = rgb;
132         Draw_GrapplingHook_trace_callback_a = intensity;
133         WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, ((self.HookType == ENT_CLIENT_HOOK) ? MOVE_NOTHING : MOVE_NORMAL), world, world, Draw_GrapplingHook_trace_callback);
134         Draw_GrapplingHook_trace_callback_tex = string_null;
135
136         atrans = WarpZone_TransformOrigin(WarpZone_trace_transform, a);
137
138         switch(self.HookType)
139         {
140                 default:
141                 case ENT_CLIENT_HOOK:
142                         if(vlen(trace_endpos - atrans) > 0.5)
143                         {
144                                 setorigin(self, trace_endpos); // hook endpoint!
145                                 self.angles = vectoangles(trace_endpos - atrans);
146                                 self.drawmask = MASK_NORMAL;
147                         }
148                         else
149                         {
150                                 self.drawmask = 0;
151                         }
152                         break;
153                 case ENT_CLIENT_ARC_BEAM:
154                         setorigin(self, a); // beam origin!
155                         break;
156         }
157
158         switch(self.HookType)
159         {
160                 default:
161                 case ENT_CLIENT_HOOK:
162                         break;
163                 case ENT_CLIENT_ARC_BEAM:
164                         pointparticles(particleeffectnum(EFFECT_ARC_LIGHTNING2), trace_endpos, normalize(atrans - trace_endpos), frametime * intensity); // todo: new effect
165                         break;
166         }
167 }
168
169 void Remove_GrapplingHook()
170 {SELFPARAM();
171         sound (self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
172 }
173
174 void Ent_ReadHook(float bIsNew, float type)
175 {SELFPARAM();
176         self.HookType = type;
177
178         int sf = ReadByte();
179
180         self.HookSilent = (sf & 0x80);
181         self.iflags = IFLAG_VELOCITY | IFLAG_ORIGIN;
182
183         InterpolateOrigin_Undo();
184
185         if(sf & 1)
186         {
187                 int myowner = ReadByte();
188                 self.owner = playerslots[myowner - 1];
189                 self.sv_entnum = myowner;
190                 switch(self.HookType)
191                 {
192                         default:
193                         case ENT_CLIENT_HOOK:
194                                 self.HookRange = 0;
195                                 break;
196                         case ENT_CLIENT_ARC_BEAM:
197                                 self.HookRange = ReadCoord();
198                                 break;
199                 }
200         }
201         if(sf & 2)
202         {
203                 self.origin_x = ReadCoord();
204                 self.origin_y = ReadCoord();
205                 self.origin_z = ReadCoord();
206                 setorigin(self, self.origin);
207         }
208         if(sf & 4)
209         {
210                 self.velocity_x = ReadCoord();
211                 self.velocity_y = ReadCoord();
212                 self.velocity_z = ReadCoord();
213         }
214
215         InterpolateOrigin_Note();
216
217         if(bIsNew || !self.teleport_time)
218         {
219                 self.draw = Draw_GrapplingHook;
220                 self.entremove = Remove_GrapplingHook;
221
222                 switch(self.HookType)
223                 {
224                         default:
225                         case ENT_CLIENT_HOOK:
226                                 // for the model
227                                 setmodel(self, MDL_HOOK);
228                                 self.drawmask = MASK_NORMAL;
229                                 break;
230                         case ENT_CLIENT_ARC_BEAM:
231                                 sound (self, CH_SHOTS_SINGLE, SND_LGBEAM_FLY, VOL_BASE, ATTEN_NORM);
232                                 break;
233                 }
234         }
235
236         self.teleport_time = time + 10;
237 }
238
239 // TODO: hook: temporarily transform self.origin for drawing the model along warpzones!