]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/warpzonelib/server.qc
warpzonelib - the beginning
[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 = AnglesTransform_Normalize(AnglesTransform_ApplyToVAngles(self.warpzone_transform, player.v_angle), TRUE);
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         // TODO nexuiz specific
155         string m;
156         m = self.model;
157         EXACTTRIGGER_INIT;
158         setmodel(self, m);
159         Net_LinkEntity(self, FALSE, 0, WarpZone_Send);
160 }
161
162 void WarpZone_InitStep_FindTarget()
163 {
164         entity e;
165
166         if(self.killtarget == "")
167         {
168                 objerror("Warp zone with no killtarget");
169                 return;
170         }
171         self.aiment = find(world, targetname, self.killtarget);
172         if(self.aiment == world)
173         {
174                 objerror("Warp zone with nonexisting killtarget");
175                 return;
176         }
177
178         // this way only one of the two ents needs to target
179         if(self.target != "")
180         {
181                 e = find(world, targetname, self.target);
182                 if(e)
183                 {
184                         self.enemy = e;
185                         self.enemy.enemy = self;
186                 }
187         }
188
189         // now enable touch
190         self.touch = WarpZone_Touch;
191 }
192
193 void WarpZone_InitStep_UpdateTransform()
194 {
195         if(!self.enemy || self.enemy.enemy != self)
196         {
197                 objerror("Invalid warp zone detected. Killed.");
198                 return;
199         }
200
201         // 1. update this, and the enemy, warp zone
202         self.warpzone_origin = self.aiment.origin;
203         self.warpzone_angles = self.aiment.angles;
204         self.enemy.warpzone_origin = self.enemy.aiment.origin;
205         self.enemy.warpzone_angles = self.enemy.aiment.angles;
206
207         // 2. combine the angle transforms
208         //    current forward must be turned into previous backward
209         self.warpzone_transform = AnglesTransform_Divide(AnglesTransform_TurnDirectionFR(self.enemy.warpzone_angles), self.warpzone_angles);
210
211         // 3. store off a saved forward vector for plane hit decisions
212         fixedmakevectors(self.warpzone_angles);
213         self.warpzone_forward = v_forward;
214 }