Xonotic
sv_spawn_near_teammate.qc File Reference
+ Include dependency graph for sv_spawn_near_teammate.qc:

Go to the source code of this file.

Functions

 MUTATOR_HOOKFUNCTION (spawn_near_teammate, Spawn_Score)
 
 MUTATOR_HOOKFUNCTION (spawn_near_teammate, PlayerSpawn)
 
 REGISTER_MUTATOR (spawn_near_teammate, expr_evaluate(autocvar_g_spawn_near_teammate))
 

Variables

string autocvar_g_spawn_near_teammate
 
float autocvar_g_spawn_near_teammate_distance
 
int autocvar_g_spawn_near_teammate_ignore_spawnpoint
 
bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health
 
bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath
 
float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay
 
float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death
 
int autocvar_g_spawn_near_teammate_ignore_spawnpoint_max
 
entity msnt_lookat
 
float msnt_timer
 
vector snt_ofs [6]
 

Function Documentation

◆ MUTATOR_HOOKFUNCTION() [1/2]

MUTATOR_HOOKFUNCTION ( spawn_near_teammate  ,
Spawn_Score   
)

Definition at line 22 of file sv_spawn_near_teammate.qc.

References autocvar_g_spawn_near_teammate_distance, autocvar_g_spawn_near_teammate_ignore_spawnpoint, checkpvs(), CS_CVAR, entity(), FOREACH_CLIENT, IS_DEAD, IS_PLAYER, M_ARGV, NULL, RandomSelection_AddEnt, RandomSelection_chosen_ent, RandomSelection_Init(), SAME_TEAM, SPAWN_PRIO_NEAR_TEAMMATE_FOUND, SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM, teamplay, vdist, and vector().

23 {
24  if (!teamplay) return;
25 
26  entity player = M_ARGV(0, entity);
27  entity spawn_spot = M_ARGV(1, entity);
28  vector spawn_score = M_ARGV(2, vector);
29 
31  return;
32 
33  spawn_spot.msnt_lookat = NULL;
34 
36  FOREACH_CLIENT(IS_PLAYER(it) && it != player && SAME_TEAM(it, player) && !IS_DEAD(it), {
37  if(vdist(spawn_spot.origin - it.origin, >, autocvar_g_spawn_near_teammate_distance))
38  continue;
39  if(vdist(spawn_spot.origin - it.origin, <, 48))
40  continue;
41  if(!checkpvs(spawn_spot.origin, it))
42  continue;
43  RandomSelection_AddEnt(it, 1, 1);
44  });
45 
47  {
48  spawn_spot.msnt_lookat = RandomSelection_chosen_ent;
49  spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_FOUND;
50  }
51  else if(player.team == spawn_spot.team)
52  spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM; // prefer same team, if we can't find a spawn near teammate
53 
54  M_ARGV(2, vector) = spawn_score;
55 }
ERASEABLE void RandomSelection_Init()
Definition: random.qc:4
entity() spawn
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
const int SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM
Definition: spawnpoints.qh:11
#define CS_CVAR(this)
Definition: state.qh:51
float checkpvs(vector viewpos, entity viewee)
#define RandomSelection_AddEnt(e, weight, priority)
Definition: random.qh:14
entity RandomSelection_chosen_ent
Definition: random.qh:5
#define NULL
Definition: post.qh:17
#define SAME_TEAM(a, b)
Definition: teams.qh:239
float teamplay
Definition: progsdefs.qc:31
#define M_ARGV(x, type)
Definition: events.qh:17
#define IS_DEAD(s)
Definition: utils.qh:26
vector(float skel, float bonenum) _skel_get_boneabs_hidden
const int SPAWN_PRIO_NEAR_TEAMMATE_FOUND
Definition: spawnpoints.qh:10
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
float autocvar_g_spawn_near_teammate_distance
#define IS_PLAYER(v)
Definition: utils.qh:9
int autocvar_g_spawn_near_teammate_ignore_spawnpoint
+ Here is the call graph for this function:

◆ MUTATOR_HOOKFUNCTION() [2/2]

MUTATOR_HOOKFUNCTION ( spawn_near_teammate  ,
PlayerSpawn   
)

Definition at line 58 of file sv_spawn_near_teammate.qc.

References autocvar_g_balance_health_regenstable, autocvar_g_spawn_near_teammate_ignore_spawnpoint, autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health, autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath, autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay, autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death, autocvar_g_spawn_near_teammate_ignore_spawnpoint_max, CONTENT_EMPTY, CS_CVAR, DIFF_TEAM, entity(), FIXED_MAKE_VECTORS, FLOAT_MAX, FOREACH_CLIENT, FOREACH_CLIENT_RANDOM, g_projectiles, GetResource(), if(), IL_EACH, IS_DEAD, IS_PLAYER, LABEL, M_ARGV, MOVE_NOMONSTERS, MOVE_NORMAL, NULL, PHYS_INPUT_BUTTON_CHAT, Q3SURFACEFLAG_SKY, RandomSelection_Add(), RandomSelection_chosen_ent, RandomSelection_chosen_vec, RandomSelection_Init(), RES_HEALTH, setorigin(), string_null, teamplay, time, trace_dphitq3surfaceflags, trace_endpos, trace_fraction, trace_startsolid, vdist, vec2, vectoangles(), vector(), vlen2, and weaponLocked().

59 {
60  if (!teamplay) return;
61 
62  entity player = M_ARGV(0, entity);
63  entity spawn_spot = M_ARGV(1, entity);
64 
65  int num_red = 0, num_blue = 0, num_yellow = 0, num_pink = 0;
67  {
68  switch(it.team)
69  {
70  case NUM_TEAM_1: ++num_red; break;
71  case NUM_TEAM_2: ++num_blue; break;
72  case NUM_TEAM_3: ++num_yellow; break;
73  case NUM_TEAM_4: ++num_pink; break;
74  }
75  });
76 
77  if(num_red == 1 || num_blue == 1 || num_yellow == 1 || num_pink == 1)
78  return; // at least 1 team has only 1 player, let's not give the bigger team too much of an advantage!
79 
80  // Note: when entering this, fixangle is already set.
82  {
85 
86  entity best_mate = NULL;
87  vector best_pos = '0 0 0';
88  float best_dist2 = FLOAT_MAX;
89  int tested = 0;
92 
93  if (PHYS_INPUT_BUTTON_CHAT(it)) continue;
94  if (DIFF_TEAM(player, it)) continue;
96  if (IS_DEAD(it)) continue;
97  if (time < it.msnt_timer) continue;
98  if (StatusEffects_active(STATUSEFFECT_SpawnShield, it)) continue;
99  if (weaponLocked(it)) continue;
100  if (it == player) continue;
101 
102  tested++; // i consider a teammate to be available when he passes the checks above
103 
104  vector horiz_vel = vec2(it.velocity);
105  // when walking slowly sideways, we assume the player wants a clear shot ahead - spawn behind him according to where he's looking
106  // when running fast, spawn behind him according to his direction of movement to prevent colliding with the newly spawned player
107  vector forward = '0 0 0'; vector right = '0 0 0'; vector up = '0 0 0';
108  if (vdist(horiz_vel, >, autocvar_sv_maxspeed + 50))
109  {
110  FIXED_MAKE_VECTORS(vectoangles(horiz_vel), forward, right, up);
111  }
112  else
113  {
114  FIXED_MAKE_VECTORS(it.angles, forward, right, up);
115  }
116 
117  // test different spots close to mate - trace upwards so it works on uneven surfaces
118  // don't spawn in front of player or directly behind to avoid players shooting each other
119  // test the potential spots in pairs (first pair is better than second and so on) but don't prefer one side
120  snt_ofs[0] = up * 64 + right * 128 - forward * 64;
121  snt_ofs[1] = up * 64 - right * 128 - forward * 64;
122  snt_ofs[2] = up * 64 + right * 192;
123  snt_ofs[3] = up * 64 - right * 192;
124  snt_ofs[4] = up * 64 + right * 64 - forward * 128;
125  snt_ofs[5] = up * 64 - right * 64 - forward * 128;
127  for(int i = 0; i < 6; ++i)
128  {
129  tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin + snt_ofs[i], MOVE_NOMONSTERS, it);
130 
131  vector horizontal_trace_endpos = trace_endpos;
132  //te_lightning1(NULL, it.origin, horizontal_trace_endpos);
133  if (trace_fraction != 1.0) goto skip;
134 
135  // 400 is about the height of a typical laser jump (in overkill)
136  // not traceline because we need space for the whole player, not just his origin
137  tracebox(horizontal_trace_endpos, STAT(PL_MIN, player), STAT(PL_MAX, player), horizontal_trace_endpos - 400 * up, MOVE_NORMAL, it);
138  vector vectical_trace_endpos = trace_endpos;
139  //te_lightning1(NULL, horizontal_trace_endpos, vectical_trace_endpos);
140  if (trace_startsolid) goto skip; // inside another player
141  if (trace_fraction == 1.0) goto skip; // above void or too high
143  if (pointcontents(vectical_trace_endpos) != CONTENT_EMPTY) goto skip; // no lava or slime (or water which i assume would be annoying anyway)
144  if (tracebox_hits_trigger_hurt(horizontal_trace_endpos, STAT(PL_MIN, player), STAT(PL_MAX, player), vectical_trace_endpos)) goto skip;
145 
146  // make sure the spawned player will have floor ahead (or at least a wall - he shouldn't fall as soon as he starts moving)
147  // top front of player's bbox - highest point we know is not inside solid
148  vector floor_test_start = vectical_trace_endpos + up * STAT(PL_MAX, player).z + forward * STAT(PL_MAX, player).x;
149  traceline(floor_test_start, floor_test_start + forward * 100 - up * 128, MOVE_NOMONSTERS, it);
150  //te_beam(NULL, floor_test_start, trace_endpos);
151  if (trace_fraction == 1.0) goto skip;
152 
153  if (autocvar_g_nades) {
154  bool nade_in_range = false;
155  IL_EACH(g_projectiles, it.classname == "nade",
156  {
157  if (vdist(it.origin - vectical_trace_endpos, <, autocvar_g_nades_nade_radius)) {
158  nade_in_range = true;
159  goto skip;
160  }
161  });
162  if (nade_in_range) goto skip;
163  }
164 
165  // here, we know we found a good spot
166  RandomSelection_Add(it, 0, string_null, vectical_trace_endpos, 1, 1);
167  //te_lightning1(NULL, vectical_trace_endpos, vectical_trace_endpos + forward * 10);
168 
169  LABEL(skip)
170  if (i % 2 == 1 && RandomSelection_chosen_ent)
171  {
173  {
174  float dist2 = vlen2(RandomSelection_chosen_ent.origin - player.death_origin);
175  if (dist2 < best_dist2)
176  {
177  best_dist2 = dist2;
178  best_pos = RandomSelection_chosen_vec;
179  best_mate = RandomSelection_chosen_ent;
180  }
181  }
182  else
183  {
185  player.angles = RandomSelection_chosen_ent.angles;
186  player.angles_z = 0; // never spawn tilted even if the spot says to
188  return;
189  }
190  break; // don't test the other spots near this teammate, go to the next one
191  }
192  }
193  });
194 
196  if(best_mate)
197  {
198  setorigin(player, best_pos);
199  player.angles = best_mate.angles;
200  player.angles_z = 0; // never spawn tilted even if the spot says to
202  }
203  }
204  else if(spawn_spot.msnt_lookat)
205  {
206  player.angles = vectoangles(spawn_spot.msnt_lookat.origin - player.origin);
207  player.angles_x = -player.angles.x;
208  player.angles_z = 0; // never spawn tilted even if the spot says to
209  /*
210  sprint(player, "You should be looking at ", spawn_spot.msnt_lookat.netname, "^7.\n");
211  sprint(player, "distance: ", vtos(spawn_spot.msnt_lookat.origin - player.origin), "\n");
212  sprint(player, "angles: ", vtos(player.angles), "\n");
213  */
214  }
215 }
#define IL_EACH(this, cond, body)
#define PHYS_INPUT_BUTTON_CHAT(s)
Definition: player.qh:155
string string_null
Definition: nil.qh:9
vector RandomSelection_chosen_vec
Definition: random.qh:8
float trace_dphitq3surfaceflags
ERASEABLE void RandomSelection_Init()
Definition: random.qc:4
bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health
entity() spawn
const float MOVE_NORMAL
Definition: csprogsdefs.qc:252
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
#define CS_CVAR(this)
Definition: state.qh:51
bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath
#define DIFF_TEAM(a, b)
Definition: teams.qh:240
float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death
float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay
RES_HEALTH
Definition: ent_cs.qc:126
float autocvar_g_balance_health_regenstable
Definition: sv_resources.qh:28
const float CONTENT_EMPTY
Definition: csprogsdefs.qc:236
bool weaponLocked(entity player)
float Q3SURFACEFLAG_SKY
const float MOVE_NOMONSTERS
Definition: csprogsdefs.qc:253
#define vlen2(v)
Definition: vector.qh:4
entity RandomSelection_chosen_ent
Definition: random.qh:5
vector snt_ofs[6]
#define NULL
Definition: post.qh:17
vector trace_endpos
Definition: csprogsdefs.qc:37
#define FIXED_MAKE_VECTORS
float teamplay
Definition: progsdefs.qc:31
#define M_ARGV(x, type)
Definition: events.qh:17
#define IS_DEAD(s)
Definition: utils.qh:26
vector(float skel, float bonenum) _skel_get_boneabs_hidden
IntrusiveList g_projectiles
Definition: common.qh:46
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
#define FOREACH_CLIENT_RANDOM(cond, body)
Definition: utils.qh:55
#define vec2(...)
Definition: vector.qh:90
#define LABEL(id)
Definition: compiler.qh:36
setorigin(ent, v)
float trace_startsolid
Definition: csprogsdefs.qc:35
if(IS_DEAD(this))
Definition: impulse.qc:92
float time
Definition: csprogsdefs.qc:16
int autocvar_g_spawn_near_teammate_ignore_spawnpoint_max
float trace_fraction
Definition: csprogsdefs.qc:36
#define IS_PLAYER(v)
Definition: utils.qh:9
const float FLOAT_MAX
Definition: float.qh:3
ERASEABLE void RandomSelection_Add(entity e, float f, string s, vector v, float weight, float priority)
Definition: random.qc:14
int autocvar_g_spawn_near_teammate_ignore_spawnpoint
+ Here is the call graph for this function:

◆ REGISTER_MUTATOR()

REGISTER_MUTATOR ( spawn_near_teammate  ,
expr_evaluate(autocvar_g_spawn_near_teammate  
)

Variable Documentation

◆ autocvar_g_spawn_near_teammate

string autocvar_g_spawn_near_teammate

Definition at line 7 of file sv_spawn_near_teammate.qc.

◆ autocvar_g_spawn_near_teammate_distance

float autocvar_g_spawn_near_teammate_distance

Definition at line 8 of file sv_spawn_near_teammate.qc.

Referenced by MUTATOR_HOOKFUNCTION().

◆ autocvar_g_spawn_near_teammate_ignore_spawnpoint

int autocvar_g_spawn_near_teammate_ignore_spawnpoint

Definition at line 9 of file sv_spawn_near_teammate.qc.

Referenced by MUTATOR_HOOKFUNCTION().

◆ autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health

bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health

Definition at line 13 of file sv_spawn_near_teammate.qc.

Referenced by MUTATOR_HOOKFUNCTION().

◆ autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath

bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath

Definition at line 14 of file sv_spawn_near_teammate.qc.

Referenced by MUTATOR_HOOKFUNCTION().

◆ autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay

float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay

Definition at line 11 of file sv_spawn_near_teammate.qc.

Referenced by MUTATOR_HOOKFUNCTION().

◆ autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death

float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death

Definition at line 12 of file sv_spawn_near_teammate.qc.

Referenced by MUTATOR_HOOKFUNCTION().

◆ autocvar_g_spawn_near_teammate_ignore_spawnpoint_max

int autocvar_g_spawn_near_teammate_ignore_spawnpoint_max

Definition at line 10 of file sv_spawn_near_teammate.qc.

Referenced by MUTATOR_HOOKFUNCTION().

◆ msnt_lookat

entity msnt_lookat

Definition at line 18 of file sv_spawn_near_teammate.qc.

◆ msnt_timer

float msnt_timer

Definition at line 20 of file sv_spawn_near_teammate.qc.

◆ snt_ofs

vector snt_ofs[6]

Definition at line 57 of file sv_spawn_near_teammate.qc.