]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/cl_impulse.qc
huge patch that breaks everything: add a new stat "weapons", network weapon bits...
[divverent/nexuiz.git] / data / qcsrc / server / cl_impulse.qc
1 .vector personal_v_angle; // view angles to restore on impulse 77
2 .vector personal_velocity; // velocity to restore on impulse 77
3
4 void CopyBody(float keepvelocity);
5
6 // changes by LordHavoc on 03/30/04
7 // cleaned up dummy code
8 // dummies are now removed eventually after being gibbed (norespawn = TRUE)
9 // dummy impulse now checks sv_cheats to prevent players from overwhelming server with dummies
10 // dummies now use player code where possible
11
12 void player_anim (void);
13 void DummyThink(void)
14 {
15         self.think = DummyThink;
16         self.nextthink = time;
17         SV_PlayerPhysics();
18         PlayerPreThink();
19         //player_anim();
20         PlayerPostThink();
21 }
22
23 // from dpmod
24 void printsurfaceinfo(entity e, vector v)
25 {
26         local float surfnum, numpoints, vnum;
27         local string s;
28         local vector n;
29         surfnum = getsurfacenearpoint(e, v);
30         if (surfnum >= 0)
31         {
32                 sprint(self, "texture: ");
33                 s = getsurfacetexture(e, surfnum);
34                 sprint(self, s);
35                 sprint(self, " normal: ");
36                 n = getsurfacenormal(e, surfnum);
37                 sprint(self, vtos(n));
38                 sprint(self, " ");
39                 numpoints = getsurfacenumpoints(e, surfnum);
40                 sprint(self, ftos(numpoints));
41                 sprint(self, " verts:");
42                 vnum = 0;
43                 while (vnum < numpoints)
44                 {
45                         sprint(self, " ");
46                         n = getsurfacepoint(e, surfnum, vnum);
47                         sprint(self, vtos(n));
48                         vnum = vnum + 1;
49                 }
50                 sprint(self, " point tested: ");
51                 sprint(self, vtos(v));
52                 sprint(self, " nearest point on surface: ");
53                 n = getsurfaceclippedpoint(e, surfnum, v);
54                 sprint(self, vtos(n));
55                 sprint(self, "\n");
56         }
57 };
58
59 /*
60  * Impulse map:
61  *
62  * 0 reserved (no input)
63  * 1 to 9: weapon shortcuts
64  * 10: next weapon
65  * 11: most recently used weapon
66  * 12: previous weapon
67  * 13: best weapon
68  * 17: throw weapon
69  *
70  * 30 to 39: create waypoints
71  * 47: clear personal waypoints
72  * 48: clear team waypoints
73  * 49: turn base waypoints on/off
74  *
75  * 99: loaded
76  *
77  * 140: moving clone
78  * 141: ctf speedrun
79  * 142: fixed clone
80  * 143: emergency teleport
81  * 144: printsurfaceinfo
82  * 145: distance
83  *
84  * TODO:
85  * 200 to 209: prev weapon shortcuts
86  * 210 to 219: best weapon shortcuts
87  * 220 to 229: next weapon shortcuts
88  * 230 to 253: individual weapons (up to 24)
89  */
90
91 void ImpulseCommands (void)
92 {
93         local float imp;
94         vector start, end, enddown;
95         float i;
96         float m;
97         float good, evil, evilsurf;
98         float maxattempts;
99         vector org, delta;
100         float wep;
101         entity e;
102
103         imp = self.impulse;
104         if (!imp || gameover)
105                 return;
106         self.impulse = 0;
107
108         if (timeoutStatus == 2) //don't allow any impulses while the game is paused
109                 return;
110
111         if (imp >= 1 && imp <= 9)
112         {
113                 // weapon switching impulses
114                 if(self.deadflag == DEAD_NO)
115                 {
116                         switch(imp)
117                         {
118                                 case 1: W_CycleWeapon("1", +1); break;
119                                 case 2: W_CycleWeapon("2", +1); break;
120                                 case 3: W_CycleWeapon("3", +1); break;
121                                 case 4: W_CycleWeapon("4", +1); break;
122                                 case 5: W_CycleWeapon("5", +1); break;
123                                 case 6: W_CycleWeapon("6", +1); break;
124                                 case 7: W_CycleWeapon("7", +1); break;
125                                 case 8: W_CycleWeapon("8", +1); break;
126                                 case 9: W_CycleWeapon("9", +1); break;
127                         }
128                 }
129                 else
130                         self.impulse = imp; // retry in next frame
131         }
132         else if(imp >= 10 && imp <= 17)
133         {
134                 if(self.deadflag == DEAD_NO)
135                 {
136                         switch(imp)
137                         {
138                                 case 10:
139                                         W_NextWeapon ();
140                                         break;
141                                 case 11:
142                                         W_SwitchWeapon (self.cnt); // previously used
143                                         break;
144                                 case 12:
145                                         W_PreviousWeapon ();
146                                         break;
147                                 case 13:
148                                         W_SwitchWeapon (w_getbestweapon(self));
149                                         break;
150                                 case 17:
151                                         if (!g_minstagib)
152                                                 W_ThrowWeapon(W_CalculateProjectileVelocity(self.velocity, v_forward * 750), '0 0 0', TRUE);
153                                         break;
154                                 }
155                 }
156                 else
157                         self.impulse = imp; // retry in next frame
158         }
159         else if(imp >= 200 && imp <= 229)
160         {
161                 if(self.deadflag == DEAD_NO)
162                 {
163                         // custom order weapon cycling
164                         i = mod(imp, 10);
165                         m = (imp - (210 + i)); // <0 for prev, =0 for best, >0 for next
166                         W_CycleWeapon(self.(cvar_cl_weaponpriorities[i]), m);
167                 }
168                 else
169                         self.impulse = imp; // retry in next frame
170         }
171         else if(imp >= 230 && imp <= 253)
172         {
173                 if(self.deadflag == DEAD_NO)
174                         W_SwitchWeapon (imp - 230 + WEP_FIRST);
175                 else
176                         self.impulse = imp; // retry in next frame
177         }
178         // deploy waypoints
179         else if (imp >= 30 && imp <= 49)
180         {
181                 switch(imp)
182                 {
183                         case 30:
184                                 WaypointSprite_DeployPersonal("waypoint", self.origin);
185                                 self.personal_v_angle = self.v_angle;
186                                 self.personal_velocity = self.velocity;
187                                 sprint(self, "personal waypoint spawned at location\n");
188                                 break;
189                         case 31:
190                                 WaypointSprite_DeployPersonal("waypoint", self.cursor_trace_endpos);
191                                 self.personal_v_angle = self.v_angle;
192                                 self.personal_velocity = '0 0 0';
193                                 sprint(self, "personal waypoint spawned at crosshair\n");
194                                 break;
195                         case 32:
196                                 if(vlen(self.death_origin))
197                                 {
198                                         WaypointSprite_DeployPersonal("waypoint", self.death_origin);
199                                         self.personal_v_angle = self.v_angle;
200                                         self.personal_velocity = '0 0 0';
201                                         sprint(self, "personal waypoint spawned at death location\n");
202                                 }
203                                 break;
204                         case 33:
205                                 if(self.deadflag == DEAD_NO && teams_matter)
206                                 {
207                                         WaypointSprite_Attach("helpme", TRUE);
208                                         sprint(self, "HELP ME attached\n");
209                                 }
210                                 break;
211                         case 34:
212                                 WaypointSprite_DeployFixed("here", FALSE, self.origin);
213                                 sprint(self, "HERE spawned at location\n");
214                                 break;
215                         case 35:
216                                 WaypointSprite_DeployFixed("here", FALSE, self.cursor_trace_endpos);
217                                 sprint(self, "HERE spawned at crosshair\n");
218                                 break;
219                         case 36:
220                                 if(vlen(self.death_origin))
221                                 {
222                                         WaypointSprite_DeployFixed("here", FALSE, self.death_origin);
223                                         sprint(self, "HERE spawned at death location\n");
224                                 }
225                                 break;
226                         case 37:
227                                 WaypointSprite_DeployFixed("danger", FALSE, self.origin);
228                                 sprint(self, "DANGER spawned at location\n");
229                                 break;
230                         case 38:
231                                 WaypointSprite_DeployFixed("danger", FALSE, self.cursor_trace_endpos);
232                                 sprint(self, "DANGER spawned at crosshair\n");
233                                 break;
234                         case 39:
235                                 if(vlen(self.death_origin))
236                                 {
237                                         WaypointSprite_DeployFixed("danger", FALSE, self.death_origin);
238                                         sprint(self, "DANGER spawned at death location\n");
239                                 }
240                                 break;
241                         case 47:
242                                 WaypointSprite_ClearPersonal();
243                                 sprint(self, "personal waypoint cleared\n");
244                                 break;
245                         case 48:
246                                 WaypointSprite_ClearOwned();
247                                 sprint(self, "all waypoints cleared\n");
248                                 break;
249                         case 49:
250                                 self.cvar_cl_hidewaypoints = !(self.cvar_cl_hidewaypoints);
251                                 sprint(self, "fixed waypoints now ");
252                                 if(self.cvar_cl_hidewaypoints)
253                                         sprint(self, "OFF\n");
254                                 else
255                                         sprint(self, "ON\n");
256                                 break;
257                 }
258         }
259         else if(imp >= 140 && imp <= 149 || imp == 99) // 10 cheats ought to be enough for anyone
260         {
261                 if(sv_cheats)
262                 if(self.deadflag == DEAD_NO)
263                 {
264                         switch(imp)
265                         {
266                                 case 99:
267                                         self.weapons |= WEPBIT_ALL;
268                                         self.ammo_shells = g_pickup_shells_max;
269                                         self.ammo_nails = g_pickup_nails_max;
270                                         self.ammo_rockets = g_pickup_rockets_max;
271                                         self.ammo_cells = g_pickup_cells_max;
272                                         self.health = g_pickup_healthsmall_max;
273                                         self.armorvalue = g_pickup_armorsmall_max;
274                                         self.pauserotarmor_finished = time + cvar("g_balance_pause_armor_rot_spawn");
275                                         self.pauserothealth_finished = time + cvar("g_balance_pause_health_rot_spawn");
276                                         self.pauseregen_finished = time + cvar("g_balance_pause_health_regen_spawn");
277                                         // precache weapon models/sounds
278                                         wep = WEP_FIRST;
279                                         while (wep <= WEP_LAST)
280                                         {
281                                                 weapon_action(wep, WR_PRECACHE);
282                                                 wep = wep + 1;
283                                         }
284                                         break;
285                                 case 140:
286                                         makevectors (self.v_angle);
287                                         self.velocity = self.velocity + v_forward * 300;
288                                         CopyBody(1);
289                                         self.lip += 1;
290                                         self.velocity = self.velocity - v_forward * 300;
291                                         break;
292                                 case 141:
293                                         if(self.waypointsprite_deployed_personal)
294                                         {
295                                                 self.speedrunning = TRUE;
296                                                 tracebox(self.waypointsprite_deployed_personal.origin, self.mins, self.maxs, self.waypointsprite_deployed_personal.origin, MOVE_WORLDONLY, self);
297                                                 if(trace_startsolid)
298                                                 {
299                                                         sprint(self, "Cannot move there, cheater - only waypoints set using g_waypointsprite_personal work\n");
300                                                 }
301                                                 else
302                                                 {
303                                                         // Abort speedrun, teleport back
304                                                         setorigin(self, self.waypointsprite_deployed_personal.origin);
305                                                         self.oldvelocity = self.velocity = self.personal_velocity;
306                                                         self.angles = self.personal_v_angle;
307                                                         self.fixangle = TRUE;
308                                                         if(self.flagcarried)
309                                                         {
310                                                                 bprint("The ", self.flagcarried.netname, " was returned to base by its carrier\n");
311                                                                 ReturnFlag(self.flagcarried);
312                                                         }
313                                                 }
314                                                 self.ammo_rockets = 999;
315                                                 self.ammo_nails = 999;
316                                                 self.ammo_cells = 999;
317                                                 self.ammo_shells = 999;
318                                                 self.health = start_health;
319                                                 self.armorvalue = start_armorvalue;
320                                                 self.weapons |= weaponsInMap;
321                                                 self.pauserotarmor_finished = time + cvar("g_balance_pause_armor_rot_spawn");
322                                                 self.pauserothealth_finished = time + cvar("g_balance_pause_health_rot_spawn");
323                                                 self.pauseregen_finished = time + cvar("g_balance_pause_health_regen_spawn");
324                                         }
325                                         else if(self.deadflag != DEAD_NO)
326                                                 sprint(self, "UR DEAD AHAHAH))\n");
327                                         else
328                                                 sprint(self, "No waypoint set, cheater (use g_waypointsprite_personal to set one)\n");
329                                         break;
330                                 case 142:
331                                         CopyBody(0);
332                                         self.lip += 1;
333                                         break;
334                                 case 143:
335                                         good = DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP;
336                                         evil = DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER;
337                                         evilsurf = Q3SURFACEFLAG_SKY;
338
339                                         m = self.dphitcontentsmask;
340                                         self.dphitcontentsmask = good | evil;
341
342                                         org = world.mins;
343                                         delta = world.maxs - world.mins;
344
345                                         maxattempts = ((sv_cheats >= 2) ? 100000 : 100);
346
347                                         for(i = 0; i < maxattempts; ++i)
348                                         {
349                                                 start_x = org_x + random() * delta_x;
350                                                 start_y = org_y + random() * delta_y;
351                                                 start_z = org_z + random() * delta_z;
352
353                                                 // rule 1: start inside world bounds, and outside
354                                                 // solid, and don't start from somewhere where you can
355                                                 // fall down to evil
356                                                 tracebox(start, self.mins, self.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, self);
357                                                 if(trace_fraction >= 1)
358                                                         continue;
359                                                 if(trace_startsolid)
360                                                         continue;
361                                                 dprint("hit contents ", ftos(trace_dphitcontents), "\n");
362                                                 if(trace_dphitcontents & evil)
363                                                         continue;
364                                                 if(trace_dphitq3surfaceflags & evilsurf)
365                                                         continue;
366
367                                                 // rule 2: if we are too high, lower the point
368                                                 if(trace_fraction * delta_z > 1024)
369                                                         start = trace_endpos + '0 0 1024';
370                                                 enddown = trace_endpos;
371
372                                                 // these can be traceLINES as we already verified the starting box
373                                                 traceline(start, start + '1 0 0' * delta_x, MOVE_NORMAL, self);
374                                                 if(trace_fraction >= 1)
375                                                         continue;
376                                                 traceline(start, start - '1 0 0' * delta_x, MOVE_NORMAL, self);
377                                                 if(trace_fraction >= 1)
378                                                         continue;
379                                                 traceline(start, start + '0 1 0' * delta_y, MOVE_NORMAL, self);
380                                                 if(trace_fraction >= 1)
381                                                         continue;
382                                                 traceline(start, start - '0 1 0' * delta_y, MOVE_NORMAL, self);
383                                                 if(trace_fraction >= 1)
384                                                         continue;
385                                                 traceline(start, start + '0 0 1' * delta_z, MOVE_NORMAL, self);
386                                                 if(trace_fraction >= 1)
387                                                         continue;
388
389                                                 end_x = org_x + random() * delta_x;
390                                                 end_y = org_y + random() * delta_y;
391                                                 end_z = org_z + random() * delta_z;
392                                                 end = start + normalize(end - start) * vlen(delta);
393
394                                                 // rule 3: start TO end must not be too short
395                                                 tracebox(start, self.mins, self.maxs, end, MOVE_NORMAL, self);
396                                                 if(trace_startsolid)
397                                                         continue;
398                                                 if(trace_fraction < 256 / vlen(delta))
399                                                         continue;
400
401                                                 // rule 4: don't want to look at sky
402                                                 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
403                                                         continue;
404
405                                                 // rule 5: we must not end up in trigger_hurt
406                                                 if(tracebox_hits_trigger_hurt(start, self.mins, self.maxs, enddown))
407                                                 {
408                                                         dprint("trigger_hurt! ouch! and nothing else could find it!\n");
409                                                         continue;
410                                                 }
411
412                                                 break;
413                                         }
414
415                                         if(i < maxattempts)
416                                         {
417                                                 self.origin = start;
418                                                 self.angles = vectoangles(end - start);
419                                                 self.angles_x = -self.angles_x;
420                                                 self.fixangle = TRUE;
421                                                 self.velocity = '0 0 0';
422                                                 dprint("Needed ", ftos(i + 1), " attempts\n");
423                                         }
424                                         else
425                                                 sprint(self, "Emergency teleport could not find a good location, forget it!\n");
426
427                                         self.dphitcontentsmask = m;
428                                         break;
429                                 case 144:
430                                         makevectors(self.v_angle);
431                                         traceline(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * MAX_SHOT_DISTANCE, FALSE, self);
432                                         if (trace_fraction < 1)
433                                                 printsurfaceinfo(trace_ent, trace_endpos);
434                                         break;
435                                 case 145:
436                                         makevectors(self.v_angle);
437                                         traceline(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * 65536, FALSE, self);
438                                         sprint(self, strcat("distance: ", ftos(fabs(vlen(trace_endpos - (self.origin + self.view_ofs)))), "\n"));
439                                         break;
440                         }
441                 }
442         }
443         else if(imp >= 103 && imp <= 106)
444         {
445                 if(cvar("g_waypointeditor"))
446                 {
447                         switch(imp)
448                         {
449                                 case 103:
450                                         waypoint_schedulerelink(waypoint_spawn(self.origin, self.origin, 0));
451                                         break;
452                                 case 104:
453                                         e = navigation_findnearestwaypoint(self, FALSE);
454                                         if (e)
455                                                 waypoint_remove(e);
456                                         break;
457                                 case 105:
458                                         waypoint_schedulerelinkall();
459                                         break;
460                                 case 106:
461                                         waypoint_saveall();
462                                         break;
463                         }
464                 }
465         }
466
467         //TetrisImpulses(imp);
468 }