Xonotic
teleporters.qc
Go to the documentation of this file.
1 #include "teleporters.qh"
2 
3 #if defined(CSQC)
4 #elif defined(MENUQC)
5 #elif defined(SVQC)
6  #include <common/constants.qh>
7  #include <common/deathtypes/all.qh>
8  #include <common/gamemodes/_mod.qh>
10  #include <common/stats.qh>
12  #include <common/util.qh>
13  #include <common/vehicles/all.qh>
14  #include <common/weapons/_all.qh>
15  #include <lib/warpzone/common.qh>
16  #include <lib/warpzone/server.qh>
18  #include <server/anticheat.qh>
20 #endif
21 
22 #ifdef SVQC
23 float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax)
24 {
25  if (IS_PLAYER(player) && !IS_DEAD(player))
26  {
27  TDEATHLOOP(org)
28  {
29  #ifdef SVQC
30  if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
31  #endif
32  if(IS_PLAYER(head))
33  if(!IS_DEAD(head))
34  return 1;
35  }
36  }
37  return 0;
38 }
39 
40 void trigger_teleport_link(entity this);
41 
42 void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax)
43 {
44  TDEATHLOOP(player.origin)
45  {
46  if (IS_PLAYER(player) && GetResource(player, RES_HEALTH) >= 1)
47  {
48  if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
49  {
50  if(IS_PLAYER(head))
51  if(GetResource(head, RES_HEALTH) >= 1)
52  ++tdeath_hit;
53  Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG.m_id, DMG_NOWEP, head.origin, '0 0 0');
54  }
55  }
56  else // dead bodies and monsters gib themselves instead of telefragging
57  Damage (telefragger, teleporter, telefragger, 10000, DEATH_TELEFRAG.m_id, DMG_NOWEP, telefragger.origin, '0 0 0');
58  }
59 }
60 
61 void spawn_tdeath(vector v0, entity e, vector v)
62 {
63  tdeath(e, e, e, '0 0 0', '0 0 0');
64 }
65 #endif
66 
67 void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
68 {
69  entity telefragger;
70  vector from;
71 
72  if(teleporter.owner)
73  telefragger = teleporter.owner;
74  else
75  telefragger = player;
76 
77  makevectors (to_angles);
78 
79 #ifdef SVQC
80  if(player.teleportable == TELEPORT_NORMAL) // don't play sounds or show particles for anything that isn't a player, maybe change later to block only observers
81  {
82  if(teleporter.pushltime < time) // only show one teleport effect per teleporter per 0.2 seconds, for better fps
83  {
84  if(tflags & TELEPORT_FLAG_SOUND)
85  {
86  string thesound = SND(TELEPORT);
87  if(teleporter.noise != "")
88  {
90  FOREACH_WORD(teleporter.noise, true,
91  {
92  RandomSelection_AddString(it, 1, 1);
93  });
95  }
96  _sound (player, CH_TRIGGER, thesound, VOL_BASE, ATTEN_NORM);
97  }
98  if(tflags & TELEPORT_FLAG_PARTICLES)
99  {
100  Send_Effect(EFFECT_TELEPORT, player.origin, '0 0 0', 1);
101  Send_Effect(EFFECT_TELEPORT, to + v_forward * 32, '0 0 0', 1);
102  }
103  teleporter.pushltime = time + 0.2;
104  }
105  }
106 #endif
107 
108  // Relocate the player
109  // assuming to allows PL_MIN to PL_MAX box and some more
110 #ifdef SVQC
111  from = player.origin;
112  setorigin(player, to);
113  player.oldorigin = to; // don't undo the teleport by unsticking
114  player.angles = to_angles;
115  if (IS_BOT_CLIENT(player))
116  {
117  player.v_angle = player.angles;
118  bot_aim_reset(player);
119  }
120  player.fixangle = true;
121  player.velocity = to_velocity;
122  BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
123 
124  makevectors(player.angles);
125  Reset_ArcBeam(player, v_forward);
127  UpdateItemAfterTeleport(player);
128 #elif defined(CSQC)
129  from = player.origin;
130  setorigin(player, to);
131  player.angles = to_angles;
132  player.velocity = to_velocity;
133  UNSET_ONGROUND(player);
134  player.iflags |= IFLAG_TELEPORTED | IFLAG_V_ANGLE | IFLAG_ANGLES;
135  player.csqcmodel_teleported = 1;
136  player.v_angle = to_angles;
137 
138  if(player == csqcplayer) // not for anything but the main player
139  {
140  setproperty(VF_ANGLES, player.angles);
141  setproperty(VF_CL_VIEWANGLES, player.angles);
142  }
143 #endif
144 
145 #ifdef SVQC
146  if(IS_PLAYER(player))
147  {
148  if((tflags & TELEPORT_FLAG_TDEATH) && player.takedamage && !IS_DEAD(player)
149  && !g_race && !g_cts && (autocvar_g_telefrags || (tflags & TELEPORT_FLAG_FORCE_TDEATH))
151  {
152  tdeath(player, teleporter, telefragger, telefragmin, telefragmax);
153  }
154 
155  // player no longer is on ground
156  UNSET_ONGROUND(player);
157 
158  // reset tracking of oldvelocity for impact damage (sudden velocity changes)
159  player.oldvelocity = player.velocity;
160 
161  // reset tracking of who pushed you into a hazard (for kill credit)
162  if(teleporter.owner)
163  {
164  player.pusher = teleporter.owner;
165  player.pushltime = time + autocvar_g_maxpushtime;
166  player.istypefrag = PHYS_INPUT_BUTTON_CHAT(player);
167  }
168  else
169  {
170  player.pushltime = 0;
171  player.istypefrag = 0;
172  }
173 
174  player.lastteleporttime = time;
175  player.lastteleport_origin = from;
176  }
177 #endif
178 }
179 
181 {
182  vector locout;
183  entity e = NULL;
184 
185  // Find the output teleporter
186  if(teleporter.enemy)
187  {
188  e = teleporter.enemy;
189  }
190  else
191  {
192  // sorry CSQC, random stuff ain't gonna happen
193 #ifdef SVQC
195  FOREACH_ENTITY_STRING(targetname, teleporter.target,
196  {
197  bool p = true;
198  if(STAT(TELEPORT_TELEFRAG_AVOID, player))
199  {
200  #ifdef SVQC
201  locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
202  #elif defined(CSQC)
203  locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
204  #endif
205  if(check_tdeath(player, locout, '0 0 0', '0 0 0'))
206  p = false;
207  }
208  RandomSelection_AddEnt(it, (it.cnt ? it.cnt : 1), p);
209  });
211 #endif
212  }
213 
214 #ifdef SVQC
215  if(!e) { sprint(player, "Teleport destination vanished. Sorry... please complain to the mapper.\n"); }
216 #elif defined(CSQC)
217  if(!e) { LOG_INFO("Teleport destination could not be found from CSQC."); }
218 #endif
219 
220  makevectors(e.mangle);
221 
222  if(e.speed)
223  if(vdist(player.velocity, >, e.speed))
224  player.velocity = normalize(player.velocity) * max(0, e.speed);
225 
226  if(STAT(TELEPORT_MAXSPEED, player))
227  if(vdist(player.velocity, >, STAT(TELEPORT_MAXSPEED, player)))
228  player.velocity = normalize(player.velocity) * max(0, STAT(TELEPORT_MAXSPEED, player));
229 
230  locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
231 
232  TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
233 
234  return e;
235 }
236 
238 {
239  bool istrigger = (this.solid == SOLID_TRIGGER);
240 
241  int n = 0;
242  for(entity e = NULL; (e = find(e, targetname, this.target)); )
243  {
244  ++n;
245 #ifdef SVQC
246  if(e.move_movetype == MOVETYPE_NONE)
247  {
248  entity tracetest_ent = spawn();
249  setsize(tracetest_ent, PL_MIN_CONST, PL_MAX_CONST);
250  tracetest_ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
251  waypoint_spawnforteleporter(this, e.origin, 0, tracetest_ent);
252  delete(tracetest_ent);
253  }
254  if(e.classname != "info_teleport_destination")
255  LOG_INFO("^3MAPPER ERROR: teleporter does target an invalid teleport destination entity. Angles will not work.");
256 #endif
257  }
258 
259  if(n == 0)
260  {
261  // no dest!
262  objerror (this, "Teleporter with nonexistent target");
263  return;
264  }
265  else if(n == 1)
266  {
267  // exactly one dest - bots love that
268  this.enemy = find(NULL, targetname, this.target);
269  }
270  else
271  {
272  // have to use random selection every single time
273  this.enemy = NULL;
274  }
275 
276  // now enable touch
277  if(istrigger)
278  settouch(this, Teleport_Touch);
279 #ifdef SVQC
280  if(istrigger)
281  trigger_teleport_link(this);
282 #endif
283 }
284 
286 {
288  {
289  return it;
290  });
291  return NULL;
292 }
293 
295 {
296 #ifdef SVQC
297  makevectors(pl.angles);
301  if (IS_PLAYER(pl)) anticheat_fixangle(pl);
302 #endif
303  // "disown" projectiles after teleport
304  if(pl.owner)
305  if(pl.owner == pl.realowner)
306  {
307  #ifdef SVQC
308  if(!(pl.flags & FL_PROJECTILE))
309  #elif defined(CSQC)
310  if(!(pl.flags & BIT(15))) // FL_PROJECTILE
311  #endif
312  LOG_INFO("A non-projectile got through a warpzone and its owner cleared. It's a ", pl.classname, ".");
313  pl.owner = NULL;
314  }
315  if(IS_PLAYER(pl))
316  {
317  // reset tracking of oldvelocity for impact damage (sudden velocity changes)
318  #ifdef SVQC
319  pl.oldvelocity = pl.velocity;
320  #endif
321  }
322 }
#define round_handler_IsActive()
#define IL_EACH(this, cond, body)
float MOVETYPE_NONE
Definition: progsdefs.qc:246
#define PHYS_INPUT_BUTTON_CHAT(s)
Definition: player.qh:155
const int TELEPORT_FLAG_TDEATH
Definition: teleporters.qh:17
string RandomSelection_chosen_string
Definition: random.qh:7
#define SND(id)
Definition: all.qh:35
void teleport_findtarget(entity this)
Definition: teleporters.qc:237
const float VF_CL_VIEWANGLES
Definition: csprogsdefs.qc:194
const int TELEPORT_NORMAL
Definition: teleporters.qh:26
void bot_aim_reset(entity this)
Definition: aim.qc:170
ERASEABLE void RandomSelection_Init()
Definition: random.qc:4
IntrusiveList g_teleporters
Definition: teleporters.qh:10
entity() spawn
float DPCONTENTS_BOTCLIP
entity Teleport_Find(vector mi, vector ma)
Definition: teleporters.qc:285
float DPCONTENTS_PLAYERCLIP
entity to
Definition: self.qh:96
#define round_handler_IsRoundStarted()
const int IFLAG_V_ANGLE
Definition: interpolate.qh:34
#define UNSET_ONGROUND(s)
Definition: movetypes.qh:18
#define DMG_NOWEP
Definition: damage.qh:126
float autocvar_g_maxpushtime
Definition: damage.qh:17
#define FOREACH_WORD(words, cond, body)
Definition: iter.qh:33
const int EF_TELEPORT_BIT
void Reset_ArcBeam()
#define FOREACH_ENTITY_STRING(fld, match, body)
Definition: iter.qh:184
RES_HEALTH
Definition: ent_cs.qc:126
#define RandomSelection_AddEnt(e, weight, priority)
Definition: random.qh:14
entity Simple_TeleportPlayer(entity teleporter, entity player)
Definition: teleporters.qc:180
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition: bits.qh:8
entity enemy
Definition: sv_ctf.qh:143
#define g_cts
Definition: cts.qh:36
#define g_race
Definition: race.qh:46
void anticheat_fixangle(entity this)
Definition: anticheat.qc:229
const int CH_TRIGGER
Definition: sound.qh:12
float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
Definition: common.qc:138
entity RandomSelection_chosen_ent
Definition: random.qh:5
#define NULL
Definition: post.qh:17
#define TELEPORT_FLAGS_TELEPORTER
Definition: teleporters.qh:22
#define LOG_INFO(...)
Definition: log.qh:70
float DPCONTENTS_SOLID
const float VOL_BASE
Definition: sound.qh:36
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition: damage.qc:583
void UpdateItemAfterTeleport(entity this)
Definition: items.qc:92
float teamplay
Definition: progsdefs.qc:31
#define IS_DEAD(s)
Definition: utils.qh:26
const float ATTEN_NORM
Definition: sound.qh:30
void waypoint_spawnforteleporter(entity e, vector destination, float timetaken, entity tracetest_ent)
Definition: waypoints.qc:2069
vector(float skel, float bonenum) _skel_get_boneabs_hidden
const int IFLAG_TELEPORTED
Definition: interpolate.qh:32
vector v
Definition: ent_cs.qc:116
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
const float VF_ANGLES
Definition: csprogsdefs.qc:186
float DPCONTENTS_BODY
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
void WarpZone_PostTeleportPlayer_Callback(entity pl)
Definition: teleporters.qc:294
#define _sound(e, c, s, v, a)
Definition: sound.qh:50
const float SOLID_TRIGGER
Definition: csprogsdefs.qc:245
const int TELEPORT_FLAG_SOUND
Definition: teleporters.qh:15
string targetname
Definition: progsdefs.qc:194
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
setorigin(ent, v)
void UpdateCSQCProjectileAfterTeleport(entity e)
entity csqcplayer
Definition: cl_player.qh:26
string target
Definition: progsdefs.qc:193
#define BITXOR_ASSIGN(a, b)
Definition: common.qh:107
const int TELEPORT_FLAG_PARTICLES
Definition: teleporters.qh:16
const int TELEPORT_FLAG_FORCE_TDEATH
Definition: teleporters.qh:18
float time
Definition: csprogsdefs.qc:16
void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
Definition: teleporters.qc:67
#define makevectors
Definition: post.qh:21
const int IFLAG_ANGLES
Definition: interpolate.qh:28
#define IS_PLAYER(v)
Definition: utils.qh:9
void Teleport_Touch(entity this, entity toucher)
Definition: teleport.qc:45
vector v_forward
Definition: csprogsdefs.qc:31
float solid
Definition: csprogsdefs.qc:99