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