]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mapobjects/trigger/teleport.qc
Wrap some statuses with parentesis to avoid possible obscure bugs
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mapobjects / trigger / teleport.qc
1 #include "teleport.qh"
2 REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_TELEPORT)
3
4 #ifdef SVQC
5 void trigger_teleport_use(entity this, entity actor, entity trigger)
6 {
7         if(teamplay)
8                 this.team = actor.team;
9 #ifdef SVQC
10         this.SendFlags |= SF_TRIGGER_UPDATE;
11 #endif
12 }
13 #endif
14
15 bool Teleport_Active(entity this, entity player)
16 {
17         if (this.active != ACTIVE_ACTIVE)
18                 return false;
19
20 #ifdef SVQC
21         if (!player.teleportable)
22                 return false;
23
24         if(player.vehicle)
25         if(!player.vehicle.teleportable)
26                 return false;
27
28         if(IS_TURRET(player))
29                 return false;
30 #elif defined(CSQC)
31         if(!IS_PLAYER(player))
32                 return false;
33 #endif
34
35         if(IS_DEAD(player))
36                 return false;
37
38         if(this.team)
39                 if(((this.spawnflags & INVERT_TEAMS) == 0) == (DIFF_TEAM(this, player)))
40                         return false;
41
42         // no need to call IS_OBSERVER(), observers never call use/touch functions which means this is never an observer
43         if(this.classname == "trigger_teleport" && (this.spawnflags & TELEPORT_OBSERVERS_ONLY))
44                 return false;
45
46         return true;
47 }
48
49 void Teleport_Touch(entity this, entity toucher)
50 {
51         entity player = toucher;
52
53         if(!Teleport_Active(this, player))
54                 return;
55
56         EXACTTRIGGER_TOUCH(this, player);
57
58 #ifdef SVQC
59         if(IS_PLAYER(player))
60                 RemoveGrapplingHooks(player);
61 #endif
62
63         entity e;
64         e = Simple_TeleportPlayer(this, player);
65
66 #ifdef SVQC
67         string s = this.target; this.target = string_null;
68         SUB_UseTargets(this, player, player); // TODO: should we be using toucher for trigger too?
69         if (!this.target) this.target = s;
70
71         SUB_UseTargets(e, player, player);
72 #endif
73 }
74
75 #ifdef SVQC
76 void target_teleport_use(entity this, entity actor, entity trigger)
77 {
78         entity player = actor;
79
80         if(!Teleport_Active(this, player))
81                 return;
82
83         if(IS_PLAYER(player))
84                 RemoveGrapplingHooks(player);
85
86         entity e = Simple_TeleportPlayer(this, player);
87
88         string s = this.target; this.target = string_null;
89         SUB_UseTargets(this, player, player); // TODO: should we be using toucher for trigger too?
90         if (!this.target)
91         {
92                 this.target = s;
93         }
94
95         if(e != this) // only activate the target teleporter if target is different
96                 SUB_UseTargets(e, player, player);
97 }
98 #endif
99
100 #ifdef SVQC
101 float trigger_teleport_send(entity this, entity to, float sf)
102 {
103         WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_TELEPORT);
104
105         WriteByte(MSG_ENTITY, this.team);
106         WriteInt24_t(MSG_ENTITY, this.spawnflags);
107         WriteByte(MSG_ENTITY, this.active);
108         WriteCoord(MSG_ENTITY, this.speed);
109
110         trigger_common_write(this, true);
111
112         return true;
113 }
114
115 void trigger_teleport_link(entity this)
116 {
117         //trigger_link(this, trigger_teleport_send);
118 }
119
120 spawnfunc(trigger_teleport)
121 {
122         this.angles = '0 0 0';
123
124         this.active = ACTIVE_ACTIVE;
125         EXACTTRIGGER_INIT;
126         this.use = trigger_teleport_use;
127
128         if(this.noise != "")
129                 FOREACH_WORD(this.noise, true, precache_sound(it));
130
131         // this must be called to spawn the teleport waypoints for bots
132         InitializeEntity(this, teleport_findtarget, INITPRIO_FINDTARGET);
133
134         if (!this.target || this.target == "")
135         {
136                 objerror (this, "Teleporter with no target");
137                 return;
138         }
139
140         IL_PUSH(g_teleporters, this);
141 }
142
143 void target_teleporter_checktarget(entity this)
144 {
145         // target_teleporter is used in many strange ways
146         // we must attempt to figure out which way it is being used for in this instance
147
148         if(!this.target || this.target == "")
149         {
150                 // this target_teleporter has no target
151                 // so it must be either a destination for a teleporter or a teleporter itself
152                 bool is_teleporter_target = false;
153                 // NOTE: target2, target3, target4 unsupported, this may not be necessary as DeFrag maps have no such targets
154                 FOREACH_ENTITY_STRING(target, this.targetname,
155                 {
156                         if(it.classname == "trigger_teleport" || it.classname == "target_teleporter")
157                         {
158                                 is_teleporter_target = true;
159                                 break; // no need to keep looping once a valid target is found
160                         }
161                 });
162
163                 if(is_teleporter_target)
164                 {
165                         // there were teleporters found targeting this, so it must be a destination!
166                         spawnfunc_info_teleport_destination(this);
167                         return;
168                 }
169
170                 // set this entity up to be a teleporter, since it can be activated as one
171                 this.enemy = this;
172                 this.mangle = this.angles;
173                 this.angles = '0 0 0';
174         }
175
176         // seeing as this entity isn't targeted by a teleporter, it must be a teleporter itself
177
178         this.active = ACTIVE_ACTIVE;
179         this.use = target_teleport_use;
180
181         if(this.noise && this.noise != "")
182                 FOREACH_WORD(this.noise, true, precache_sound(it));
183
184         if(this.target && this.target != "") // no need to find a target on this entity, as it does not have one and .enemy is already set as required
185                 teleport_findtarget(this);
186 }
187
188 spawnfunc(target_teleporter)
189 {
190         InitializeEntity(this, target_teleporter_checktarget, INITPRIO_FINDTARGET);
191 }
192 #elif defined(CSQC)
193 NET_HANDLE(ENT_CLIENT_TRIGGER_TELEPORT, bool isnew)
194 {
195         this.classname = "trigger_teleport";
196         if(isnew)
197                 IL_PUSH(g_teleporters, this);
198         int mytm = ReadByte();
199         if(mytm)
200         {
201                 this.team = mytm - 1;
202         }
203         this.spawnflags = ReadInt24_t();
204         this.active = ReadByte();
205         this.speed = ReadCoord();
206
207         trigger_common_read(this, true);
208
209         this.entremove = trigger_remove_generic;
210         this.solid = SOLID_TRIGGER;
211         //settouch(this, trigger_push_touch);
212         this.move_time = time;
213         defer(this, 0.25, teleport_findtarget);
214
215         return true;
216 }
217
218 #endif