]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mapobjects/trigger/teleport.qc
0ac4559ccb4a80228ca88102ef1c5f1c833e11c9
[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         //trigger_init(this); // only for predicted triggers?
126         EXACTTRIGGER_INIT;
127         this.use = trigger_teleport_use;
128
129         if(this.noise != "")
130                 FOREACH_WORD(this.noise, true, precache_sound(it));
131
132         // this must be called to spawn the teleport waypoints for bots
133         InitializeEntity(this, teleport_findtarget, INITPRIO_FINDTARGET);
134
135         if (!this.target || this.target == "")
136         {
137                 objerror (this, "Teleporter with no target");
138                 return;
139         }
140
141         IL_PUSH(g_teleporters, this);
142 }
143
144 void target_teleporter_checktarget(entity this)
145 {
146         // target_teleporter is used in many strange ways
147         // we must attempt to figure out which way it is being used for in this instance
148
149         if(!this.target || this.target == "")
150         {
151                 // this target_teleporter has no target
152                 // so it must be either a destination for a teleporter or a teleporter itself
153                 bool is_teleporter_target = false;
154                 // NOTE: target2, target3, target4 unsupported, this may not be necessary as DeFrag maps have no such targets
155                 FOREACH_ENTITY_STRING(target, this.targetname,
156                 {
157                         if(it.classname == "trigger_teleport" || it.classname == "target_teleporter")
158                         {
159                                 is_teleporter_target = true;
160                                 break; // no need to keep looping once a valid target is found
161                         }
162                 });
163
164                 if(is_teleporter_target)
165                 {
166                         // there were teleporters found targeting this, so it must be a destination!
167                         spawnfunc_info_teleport_destination(this);
168                         return;
169                 }
170
171                 // set this entity up to be a teleporter, since it can be activated as one
172                 this.enemy = this;
173                 this.mangle = this.angles;
174                 this.angles = '0 0 0';
175         }
176
177         // seeing as this entity isn't targeted by a teleporter, it must be a teleporter itself
178
179         this.active = ACTIVE_ACTIVE;
180         this.use = target_teleport_use;
181
182         if(this.noise && this.noise != "")
183                 FOREACH_WORD(this.noise, true, precache_sound(it));
184
185         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
186                 teleport_findtarget(this);
187 }
188
189 spawnfunc(target_teleporter)
190 {
191         InitializeEntity(this, target_teleporter_checktarget, INITPRIO_FINDTARGET);
192 }
193 #elif defined(CSQC)
194 NET_HANDLE(ENT_CLIENT_TRIGGER_TELEPORT, bool isnew)
195 {
196         this.classname = "trigger_teleport";
197         if(isnew)
198                 IL_PUSH(g_teleporters, this);
199         int mytm = ReadByte();
200         if(mytm)
201         {
202                 this.team = mytm - 1;
203         }
204         this.spawnflags = ReadInt24_t();
205         this.active = ReadByte();
206         this.speed = ReadCoord();
207
208         trigger_common_read(this, true);
209
210         this.entremove = trigger_remove_generic;
211         this.solid = SOLID_TRIGGER;
212         //settouch(this, trigger_push_touch);
213         this.move_time = time;
214         defer(this, 0.25, teleport_findtarget);
215
216         return true;
217 }
218
219 #endif