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