]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/warpzonelib/server.qc
make warpzonelib depend less on Nexuiz
[divverent/nexuiz.git] / data / qcsrc / warpzonelib / server.qc
1 void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
2 {
3         vector from;
4
5         makevectors (to_angles);
6
7         from = player.origin;
8         setorigin (player, to);
9         player.oldorigin = to; // for DP's unsticking
10         player.angles = to_angles;
11         player.fixangle = TRUE;
12         player.velocity = to_velocity;
13
14         if(player.effects & EF_TELEPORT_BIT)
15                 player.effects &~= EF_TELEPORT_BIT;
16         else
17                 player.effects |= EF_TELEPORT_BIT;
18
19         if(player.classname == "player")
20                 player.flags &~= FL_ONGROUND;
21
22         WarpZone_PostTeleportPlayer(player);
23 }
24
25 // the transform
26 .vector warpzone_origin, warpzone_angles;
27 .vector warpzone_forward;
28 .vector warpzone_transform;
29
30 float WarpZone_Teleport(entity player)
31 {
32         vector o0, a0, v0, o1, a1, v1;
33
34         o0 = player.origin + player.view_ofs;
35         v0 = player.velocity;
36         a0 = player.angles;
37
38         if((o0 - self.warpzone_origin) * self.warpzone_forward >= 0) // wrong side of the portal
39                 return 2;
40         // no failure, we simply don't want to teleport yet; TODO in
41         // this situation we may want to create a temporary clone
42         // entity of the player to fix graphics glitch
43
44         o1 = AnglesTransform_Apply(self.warpzone_transform, o0 - self.warpzone_origin) + self.enemy.warpzone_origin;
45         v1 = AnglesTransform_Apply(self.warpzone_transform, v0);
46         if(player.classname == "player")
47                 a1 = WarpZone_TransformVAngles(self.warpzone_transform, player.v_angle);
48         else
49                 a1 = AnglesTransform_ApplyToAngles(self.warpzone_transform, a0);
50
51         // put him inside solid
52         tracebox(o1 - player.view_ofs, player.mins, player.maxs, o1 - player.view_ofs, MOVE_NOMONSTERS, player);
53         if(trace_startsolid)
54         {
55                 setorigin(player, o1 - player.view_ofs);
56                 if(WarpZoneLib_MoveOutOfSolid(player))
57                 {
58                         setorigin(player, o0);
59                         o1 = player.origin + player.view_ofs;
60                 }
61                 else
62                 {
63                         setorigin(player, o0 - player.view_ofs);
64                         return 0; // cannot fix
65                 }
66         }
67
68         if((o1 - self.enemy.warpzone_origin) * self.enemy.warpzone_forward <= 0) // wrong side of the portal post-teleport
69         {
70                 print("inconsistent warp zones or evil roundoff error\n");
71                 return 0;
72         }
73
74         //print(sprintf("warpzone: %f %f %f -> %f %f %f\n", o0_x, o0_y, o0_z, o1_x, o1_y, o1_z));
75
76         //o1 = trace_endpos;
77         TeleportPlayer(self, other, o1 - player.view_ofs, a1, v1, '0 0 0', '0 0 0', TELEPORT_FLAGS_WARPZONE);
78
79         return 1;
80 }
81
82 void WarpZone_Touch (void)
83 {
84         entity oldself, e;
85
86         // FIXME needs a better check to know what is safe to teleport and what not
87         if(other.movetype == MOVETYPE_NONE)
88                 return;
89
90         EXACTTRIGGER_TOUCH;
91
92         e = self.enemy;
93         if(WarpZone_Teleport(other))
94         {
95                 if(self.aiment.target)
96                 {
97                         oldself = self;
98                         activator = other;
99                         self = self.aiment;
100                         SUB_UseTargets();
101                         self = oldself;
102                 }
103         }
104         else
105         {
106                 dprint("WARPZONE FAIL AHAHAHAHAH))\n");
107         }
108 }
109
110 float WarpZone_Send(entity to, float sendflags)
111 {
112         WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE);
113
114         // we need THESE to render the warpzone (and cull properly)...
115         WriteCoord(MSG_ENTITY, self.origin_x);
116         WriteCoord(MSG_ENTITY, self.origin_y);
117         WriteCoord(MSG_ENTITY, self.origin_z);
118
119         WriteShort(MSG_ENTITY, self.modelindex);
120         WriteCoord(MSG_ENTITY, self.mins_x);
121         WriteCoord(MSG_ENTITY, self.mins_y);
122         WriteCoord(MSG_ENTITY, self.mins_z);
123         WriteCoord(MSG_ENTITY, self.maxs_x);
124         WriteCoord(MSG_ENTITY, self.maxs_y);
125         WriteCoord(MSG_ENTITY, self.maxs_z);
126
127         // we need THESE to calculate the proper transform
128         WriteCoord(MSG_ENTITY, self.warpzone_origin_x);
129         WriteCoord(MSG_ENTITY, self.warpzone_origin_y);
130         WriteCoord(MSG_ENTITY, self.warpzone_origin_z);
131         WriteCoord(MSG_ENTITY, self.warpzone_angles_x);
132         WriteCoord(MSG_ENTITY, self.warpzone_angles_y);
133         WriteCoord(MSG_ENTITY, self.warpzone_angles_z);
134         WriteCoord(MSG_ENTITY, self.enemy.warpzone_origin_x);
135         WriteCoord(MSG_ENTITY, self.enemy.warpzone_origin_y);
136         WriteCoord(MSG_ENTITY, self.enemy.warpzone_origin_z);
137         WriteCoord(MSG_ENTITY, self.enemy.warpzone_angles_x);
138         WriteCoord(MSG_ENTITY, self.enemy.warpzone_angles_y);
139         WriteCoord(MSG_ENTITY, self.enemy.warpzone_angles_z);
140
141         return TRUE;
142 }
143
144 void WarpZone_InitStep_SpawnFunc()
145 {
146         // warp zone entities must have:
147         // "killtarget" pointing to a target_position with a direction arrow
148         //              that points AWAY from the warp zone, and that is inside
149         //              the warp zone trigger
150         // "target"     pointing to an identical warp zone at another place in
151         //              the map, with another killtarget to designate its
152         //              orientation
153
154         string m;
155         m = self.model;
156         WarpZoneLib_ExactTrigger_Init();
157         setmodel(self, m);
158         self.SendEntity = WarpZone_Send;
159         self.SendFlags = 0xFFFFFF;
160         self.effects |= EF_NODEPTHTEST;
161 }
162
163 void WarpZone_InitStep_FindTarget()
164 {
165         entity e;
166
167         if(self.killtarget == "")
168         {
169                 objerror("Warp zone with no killtarget");
170                 return;
171         }
172         self.aiment = find(world, targetname, self.killtarget);
173         if(self.aiment == world)
174         {
175                 objerror("Warp zone with nonexisting killtarget");
176                 return;
177         }
178
179         // this way only one of the two ents needs to target
180         if(self.target != "")
181         {
182                 e = find(world, targetname, self.target);
183                 if(e)
184                 {
185                         self.enemy = e;
186                         self.enemy.enemy = self;
187                 }
188         }
189
190         // now enable touch
191         self.touch = WarpZone_Touch;
192 }
193
194 void WarpZone_InitStep_UpdateTransform()
195 {
196         if(!self.enemy || self.enemy.enemy != self)
197         {
198                 objerror("Invalid warp zone detected. Killed.");
199                 return;
200         }
201
202         // 1. update this, and the enemy, warp zone
203         self.warpzone_origin = self.aiment.origin;
204         self.warpzone_angles = self.aiment.angles;
205         self.enemy.warpzone_origin = self.enemy.aiment.origin;
206         self.enemy.warpzone_angles = self.enemy.aiment.angles;
207
208         // 2. combine the angle transforms
209         //    current forward must be turned into previous backward
210         self.warpzone_transform = AnglesTransform_Divide(AnglesTransform_TurnDirectionFR(self.enemy.warpzone_angles), self.warpzone_angles);
211
212         // 3. store off a saved forward vector for plane hit decisions
213         fixedmakevectors(self.warpzone_angles);
214         self.warpzone_forward = v_forward;
215 }