healthbars for sprites (currently unused)
[divverent/nexuiz.git] / data / qcsrc / server / waypointsprites.qc
1 ..entity owned_by_field;
2 .float rule;
3 .string model1;
4 .string model2;
5 .string model3;
6
7 .float(entity) waypointsprite_visible_for_player;
8
9 void WaypointSprite_UpdateSprites(entity e, string m1, string m2, string m3)
10 {
11         if(m1 != e.model1)
12         {
13                 e.model1 = m1;
14                 e.SendFlags |= 2;
15         }
16         if(m2 != e.model2)
17         {
18                 e.model2 = m2;
19                 e.SendFlags |= 4;
20         }
21         if(m3 != e.model3)
22         {
23                 e.model3 = m3;
24                 e.SendFlags |= 8;
25         }
26 }
27
28 void WaypointSprite_UpdateHealth(entity e, float f)
29 {
30         if(f != e.health)
31         {
32                 e.health = f;
33                 e.SendFlags |= 0x80;
34         }
35 }
36
37 void WaypointSprite_UpdateMaxHealth(entity e, float f)
38 {
39         if(f != e.max_health)
40         {
41                 e.max_health = f;
42                 e.SendFlags |= 0x80;
43         }
44 }
45
46 void WaypointSprite_UpdateOrigin(entity e, vector o)
47 {
48         if(o != e.origin)
49         {
50                 setorigin(e, o);
51                 e.SendFlags |= 64;
52         }
53 }
54
55 void WaypointSprite_UpdateRule(entity e, float t, float r)
56 {
57         // no check, as this is never called without doing an actual change (usually only once)
58         e.rule = r;
59         e.team = t;
60         e.SendFlags |= 1;
61 }
62
63 void WaypointSprite_UpdateTeamRadar(entity e, float icon, vector col)
64 {
65         // no check, as this is never called without doing an actual change (usually only once)
66         e.cnt = (icon & 0x7F) | (e.cnt & 0x80);
67         e.colormod = col;
68         e.SendFlags |= 32;
69 }
70
71 void WaypointSprite_Ping(entity e)
72 {
73         // ALWAYS sends (this causes a radar circle), thus no check
74         e.cnt |= 0x80;
75         e.SendFlags |= 32;
76 }
77
78 void WaypointSprite_FadeOutIn(entity e, float t)
79 {
80         if(!e.fade_time)
81         {
82                 e.fade_time = t;
83                 e.teleport_time = time + t;
84         }
85         else if(t < (e.teleport_time - time))
86         {
87                 // accelerate the waypoint's dying
88                 // ensure:
89                 //   (e.teleport_time - time) / wp.fade_time stays
90                 //   e.teleport_time = time + fadetime
91                 float current_fadetime;
92                 current_fadetime = e.teleport_time - time;
93                 e.teleport_time = time + t;
94                 e.fade_time = e.fade_time * t / current_fadetime;
95         }
96
97         e.SendFlags |= 16;
98 }
99
100 float waypointsprite_limitedrange, waypointsprite_deployed_lifetime, waypointsprite_deadlifetime;
101 void WaypointSprite_Init()
102 {
103         waypointsprite_limitedrange = cvar("g_waypointsprite_limitedrange");
104         waypointsprite_deployed_lifetime = cvar("g_waypointsprite_deployed_lifetime");
105         waypointsprite_deadlifetime = cvar("g_waypointsprite_deadlifetime");
106 }
107 void WaypointSprite_InitClient(entity e)
108 {
109 }
110
111 void WaypointSprite_Kill(entity wp)
112 {
113         if(!wp)
114                 return;
115         if(wp.owner)
116                 wp.owner.(wp.owned_by_field) = world;
117         remove(wp);
118 }
119
120 void WaypointSprite_Disown(entity wp, float fadetime)
121 {
122         if(!wp)
123                 return;
124         if(wp.classname != "sprite_waypoint")
125         {
126                 backtrace("Trying to disown a non-waypointsprite");
127                 return;
128         }
129         if(wp.owner)
130         {
131                 if(wp.exteriormodeltoclient == wp.owner)
132                         wp.exteriormodeltoclient = world;
133                 wp.owner.(wp.owned_by_field) = world;
134                 wp.owner = world;
135
136                 WaypointSprite_FadeOutIn(wp, fadetime);
137         }
138 }
139
140 void WaypointSprite_Think()
141 {
142         float doremove;
143
144         doremove = FALSE;
145
146         if(self.fade_time)
147         {
148                 if(time >= self.teleport_time)
149                         doremove = TRUE;
150         }
151
152         if(self.exteriormodeltoclient)
153                 WaypointSprite_UpdateOrigin(self, self.exteriormodeltoclient.origin + self.view_ofs);
154
155         if(doremove)
156                 WaypointSprite_Kill(self);
157         else
158                 self.nextthink = time; // WHY?!?
159 }
160
161 float WaypointSprite_visible_for_player(entity e)
162 {
163         // personal waypoints
164         if(self.enemy)
165                 if(self.enemy != other)
166                         return FALSE;
167
168         // team waypoints
169         if(self.team && self.rule == SPRITERULE_DEFAULT)
170         {
171                 if(self.team != other.team)
172                         return FALSE;
173                 if(other.classname != "player")
174                         return FALSE;
175         }
176
177         return TRUE;
178 }
179
180 float WaypointSprite_Customize()
181 {
182         // this is not in SendEntity because it shall run every frame, not just every update
183
184         // make spectators see what the player would see
185         entity e;
186         e = other;
187         if(e.classname == "spectator")
188                 e = e.enemy;
189
190         return self.waypointsprite_visible_for_player(e);
191 }
192
193 float WaypointSprite_SendEntity(entity to, float sendflags)
194 {
195         WriteByte(MSG_ENTITY, ENT_CLIENT_WAYPOINT);
196
197         sendflags = sendflags & 0x7F;
198         
199         if(self.max_health)
200                 sendflags |= 0x80;
201
202         WriteByte(MSG_ENTITY, sendflags);
203
204         if(self.max_health)
205                 WriteByte(MSG_ENTITY, (self.health / self.max_health) * 255.0);
206
207         if(sendflags & 64)
208         {
209                 WriteCoord(MSG_ENTITY, self.origin_x);
210                 WriteCoord(MSG_ENTITY, self.origin_y);
211                 WriteCoord(MSG_ENTITY, self.origin_z);
212         }
213
214         if(sendflags & 1)
215         {
216                 WriteByte(MSG_ENTITY, self.team);
217                 WriteByte(MSG_ENTITY, self.rule);
218         }
219
220         if(sendflags & 2)
221                 WriteString(MSG_ENTITY, self.model1);
222
223         if(sendflags & 4)
224                 WriteString(MSG_ENTITY, self.model2);
225
226         if(sendflags & 8)
227                 WriteString(MSG_ENTITY, self.model3);
228
229         if(sendflags & 16)
230         {
231                 WriteCoord(MSG_ENTITY, self.fade_time);
232                 WriteCoord(MSG_ENTITY, self.teleport_time);
233                 WriteShort(MSG_ENTITY, self.fade_rate); // maxdist
234                 float f;
235                 f = 0;
236                 if(self.currentammo)
237                         f |= 1; // hideable
238                 if(self.exteriormodeltoclient == to)
239                         f |= 2; // my own
240                 WriteByte(MSG_ENTITY, f);
241         }
242
243         if(sendflags & 32)
244         {
245                 WriteByte(MSG_ENTITY, self.cnt); // icon on radar
246                 WriteByte(MSG_ENTITY, self.colormod_x * 255.0);
247                 WriteByte(MSG_ENTITY, self.colormod_y * 255.0);
248                 WriteByte(MSG_ENTITY, self.colormod_z * 255.0);
249         }
250
251         return TRUE;
252 }
253
254 void WaypointSprite_Reset()
255 {
256         // if a WP wants to time out, let it time out immediately; other WPs ought to be reset/killed by their owners
257
258         if(self.fade_time) // there was there before: || g_keyhunt, do we really need this?
259                 WaypointSprite_Kill(self);
260 }
261
262 entity WaypointSprite_Spawn(
263         string spr, // sprite
264         float lifetime, float maxdistance, // lifetime, max distance
265         entity ref, vector ofs, // position
266         entity showto, float t, // show to whom? Use a flag to indicate a team
267         entity own, .entity ownfield, // remove when own gets killed
268         float hideable // true when it should be controlled by cl_hidewaypoints
269 )
270 {
271         entity wp;
272         wp = spawn();
273         wp.classname = "sprite_waypoint";
274         wp.teleport_time = time + lifetime;
275         wp.fade_time = lifetime;
276         wp.exteriormodeltoclient = ref;
277         if(ref)
278         {
279                 wp.view_ofs = ofs;
280                 setorigin(wp, ref.origin + ofs);
281         }
282         else
283                 setorigin(wp, ofs);
284         wp.enemy = showto;
285         wp.team = t;
286         wp.owner = own;
287         wp.currentammo = hideable;
288         if(own)
289         {
290                 if(own.ownfield)
291                         remove(own.ownfield);
292                 own.ownfield = wp;
293                 wp.owned_by_field = ownfield;
294         }
295         wp.fade_rate = maxdistance;
296         wp.think = WaypointSprite_Think;
297         wp.nextthink = time;
298         wp.model1 = spr;
299         wp.customizeentityforclient = WaypointSprite_Customize;
300         wp.waypointsprite_visible_for_player = WaypointSprite_visible_for_player;
301         wp.reset2 = WaypointSprite_Reset;
302         Net_LinkEntity(wp, FALSE, 0, WaypointSprite_SendEntity);
303         return wp;
304 }
305
306 entity WaypointSprite_SpawnFixed(
307         string spr,
308         vector ofs,
309         entity own,
310         .entity ownfield
311 )
312 {
313         return WaypointSprite_Spawn(spr, 0, 0, world, ofs, world, 0, own, ownfield, TRUE);
314 }
315
316 .entity waypointsprite_deployed_fixed;
317 entity WaypointSprite_DeployFixed(
318         string spr,
319         float limited_range,
320         vector ofs
321 )
322 {
323         float t, maxdistance;
324         if(teams_matter)
325                 t = self.team;
326         else
327                 t = 0;
328         if(limited_range)
329                 maxdistance = waypointsprite_limitedrange;
330         else
331                 maxdistance = 0;
332         return WaypointSprite_Spawn(spr, waypointsprite_deployed_lifetime, maxdistance, world, ofs, world, t, self, waypointsprite_deployed_fixed, FALSE);
333 }
334
335 .entity waypointsprite_deployed_personal;
336 entity WaypointSprite_DeployPersonal(
337         string spr,
338         vector ofs
339 )
340 {
341         return WaypointSprite_Spawn(spr, 0, 0, world, ofs, world, 0, self, waypointsprite_deployed_personal, FALSE);
342 }
343
344 .entity waypointsprite_attached;
345 .entity waypointsprite_attachedforcarrier;
346 entity WaypointSprite_Attach(
347         string spr,
348         float limited_range
349 )
350 {
351         float t, maxdistance;
352         if(self.waypointsprite_attachedforcarrier)
353                 return world; // can't attach to FC
354         if(teams_matter)
355                 t = self.team;
356         else
357                 t = 0;
358         if(limited_range)
359                 maxdistance = waypointsprite_limitedrange;
360         else
361                 maxdistance = 0;
362         return WaypointSprite_Spawn(spr, waypointsprite_deployed_lifetime, maxdistance, self, '0 0 64', world, t, self, waypointsprite_attached, FALSE);
363 }
364
365 entity WaypointSprite_AttachCarrier(
366         string spr,
367         entity carrier
368 )
369 {
370         WaypointSprite_Kill(carrier.waypointsprite_attached); // FC overrides attached
371         return WaypointSprite_Spawn(spr, 0, 0, carrier, '0 0 64', world, carrier.team, carrier, waypointsprite_attachedforcarrier, FALSE);
372 }
373
374 void WaypointSprite_DetachCarrier(entity carrier)
375 {
376         WaypointSprite_Disown(carrier.waypointsprite_attachedforcarrier, waypointsprite_deadlifetime);
377 }
378
379 void WaypointSprite_ClearPersonal()
380 {
381         WaypointSprite_Kill(self.waypointsprite_deployed_personal);
382 }
383
384 void WaypointSprite_ClearOwned()
385 {
386         WaypointSprite_Kill(self.waypointsprite_deployed_fixed);
387         WaypointSprite_Kill(self.waypointsprite_deployed_personal);
388         WaypointSprite_Kill(self.waypointsprite_attached);
389 }
390
391 void WaypointSprite_PlayerDead()
392 {
393         WaypointSprite_Disown(self.waypointsprite_attached, waypointsprite_deadlifetime);
394         WaypointSprite_DetachCarrier(self);
395 }
396
397 void WaypointSprite_PlayerGone()
398 {
399         WaypointSprite_Disown(self.waypointsprite_deployed_fixed, waypointsprite_deadlifetime);
400         WaypointSprite_Kill(self.waypointsprite_deployed_personal);
401         WaypointSprite_Disown(self.waypointsprite_attached, waypointsprite_deadlifetime);
402         WaypointSprite_DetachCarrier(self);
403 }