attachment + EF_NODEPTHTEST is a notwork. Once fixed, #define ATTACHMENT_WORKS_WITH_E...
[divverent/nexuiz.git] / data / qcsrc / server / waypointsprites.qc
1 float waypointsprite_normdistance;
2 float waypointsprite_minscale;
3 float waypointsprite_fadedistance;
4 float waypointsprite_minalpha;
5 float waypointsprite_distancealphaexponent;
6 float waypointsprite_timealphaexponent;
7 float waypointsprite_deployed_lifetime;
8 float waypointsprite_deadlifetime;
9 float waypointsprite_limitedrange;
10
11 ..entity owned_by_field;
12
13 void WaypointSprite_Init()
14 {
15         waypointsprite_fadedistance = vlen(world.maxs - world.mins);
16         waypointsprite_normdistance = cvar("g_waypointsprite_normdistance");
17         waypointsprite_minscale = cvar("g_waypointsprite_minscale");
18         waypointsprite_minalpha = cvar("g_waypointsprite_minalpha");
19         waypointsprite_distancealphaexponent = cvar("g_waypointsprite_distancealphaexponent");
20         waypointsprite_timealphaexponent = cvar("g_waypointsprite_timealphaexponent");
21         waypointsprite_deployed_lifetime = cvar("g_waypointsprite_deployed_lifetime");
22         waypointsprite_deadlifetime = cvar("g_waypointsprite_deadlifetime");
23         waypointsprite_limitedrange = cvar("g_waypointsprite_limitedrange");
24
25         precache_model("models/sprites/bluebase.sp2");
26         precache_model("models/sprites/flagcarrier.sp2");
27         precache_model("models/sprites/here.sp2");
28         precache_model("models/sprites/helpme.sp2");
29         precache_model("models/sprites/redbase.sp2");
30         precache_model("models/sprites/waypoint.sp2");
31         precache_model("models/sprites/danger.sp2");
32 }
33
34 void WaypointSprite_InitClient(entity e)
35 {
36         stuffcmd(e, "\nalias \"g_waypointsprite_personal\" \"impulse 30\"\n alias \"g_waypointsprite_personal_p\" \"impulse 31\"\n alias \"g_waypointsprite_personal_d\" \"impulse 32\"\n alias \"g_waypointsprite_team_helpme\" \"impulse 33\"\n alias \"g_waypointsprite_team_here\" \"impulse 34\"\n alias \"g_waypointsprite_team_here_p\" \"impulse 35\"\n alias \"g_waypointsprite_team_here_d\" \"impulse 36\"\n alias \"g_waypointsprite_team_danger\" \"impulse 37\"\n alias \"g_waypointsprite_team_danger_p\" \"impulse 38\"\n alias \"g_waypointsprite_team_danger_d\" \"impulse 39\"\n alias \"g_waypointsprite_clear_personal\" \"impulse 47\"\n alias \"g_waypointsprite_clear\" \"impulse 48\"\n alias \"g_waypointsprite_toggle\" \"impulse 49\"\n");
37 }
38
39 void WaypointSprite_Kill(entity wp)
40 {
41         if(!wp)
42                 return;
43         if(wp.owner)
44                 wp.owner.(wp.owned_by_field) = world;
45         remove(wp);
46 }
47
48 void WaypointSprite_Disown(entity wp, float fadetime)
49 {
50         if(!wp)
51                 return;
52         if(wp.owner)
53         {
54                 if(wp.exteriormodeltoclient == wp.owner)
55                 {
56 #ifdef ATTACHMENT_WORKS_WITH_EF_NODEPTHTEST
57                         setattachment(wp, world, "");
58                         setorigin(wp, wp.origin + wp.exteriormodeltoclient.origin);
59 #else
60                         // setorigin(wp, wp.view_ofs + wp.exteriormodeltoclient.origin);
61                         // has been done already by customizeentityforclient!
62 #endif
63                         wp.exteriormodeltoclient = world;
64                 }
65                 wp.owner.(wp.owned_by_field) = world;
66                 wp.owner = world;
67
68                 if(!wp.health)
69                 {
70                         wp.health = fadetime;
71                         wp.teleport_time = time + fadetime;
72                 }
73                 else if(fadetime < (wp.teleport_time - time))
74                 {
75                         // accelerate the waypoint's dying
76                         // ensure:
77                         //   (wp.teleport_time - time) / wp.health stays
78                         //   wp.teleport_time = time + fadetime
79                         float current_fadetime;
80                         current_fadetime = wp.teleport_time - time;
81                         wp.teleport_time = time + fadetime;
82                         wp.health = wp.health * fadetime / current_fadetime;
83                 }
84         }
85 }
86
87 void WaypointSprite_Think()
88 {
89         float doremove;
90
91         doremove = FALSE;
92
93         if(self.health)
94                 if(time >= self.teleport_time)
95                         doremove = TRUE;
96
97 #ifndef ATTACHMENT_WORKS_WITH_EF_NODEPTHTEST
98         if(self.exteriormodeltoclient)
99                 setorigin(self, self.exteriormodeltoclient.origin + self.view_ofs);
100 #endif
101
102         if(doremove)
103                 WaypointSprite_Kill(self);
104         else
105                 self.nextthink = time;
106 }
107
108 float WaypointSprite_CustomizeEntityForClient()
109 {
110         vector realorigin, porigin;
111         float distancealpha, timealpha;
112         float distance;
113
114         if(self.health)
115         {
116                 timealpha = bound(0, (self.teleport_time - time) / self.health, 1);
117                 if(timealpha == 0)
118                         return FALSE;
119                 timealpha = pow(timealpha, waypointsprite_timealphaexponent);
120         }
121         else
122                 timealpha = 1;
123
124         if(self.enemy)
125                 if(self.enemy != other)
126                         return FALSE;
127         if(self.team)
128         {
129                 if(self.team != other.team)
130                         return FALSE;
131                 if(other.classname != "player")
132                         return FALSE;
133         }
134
135         if(self.currentammo) // hidable?
136                 if(other.cvar_cl_hidewaypoints) // wants to hide;
137                         return FALSE;
138
139         porigin = other.origin + other.view_ofs_z * '0 0 1';
140
141 #ifdef ATTACHMENT_WORKS_WITH_EF_NODEPTHTEST
142         realorigin = self.exteriormodeltoclient.origin + self.origin;
143 #else
144         realorigin = self.origin;
145 #endif
146
147         distance = vlen(realorigin - porigin);
148
149         if(self.max_health)
150                 if(distance >= self.max_health)
151                         return FALSE;
152
153         self.scale = max(1, distance / waypointsprite_normdistance) * waypointsprite_minscale;
154
155         if(self.max_health > waypointsprite_normdistance)
156         {
157                 // alpha 1 at normdistance, alpha 0 at maxdistance
158                 distancealpha = bound(0, (self.max_health - distance) / (self.max_health - waypointsprite_normdistance), 1);
159                 distancealpha = pow(distancealpha, waypointsprite_distancealphaexponent);
160         }
161         else if(self.max_health)
162         {
163                 // alpha 1 if visible
164                 distancealpha = 1;
165         }
166         else
167         {
168                 // alpha 1 at normdistance, alpha minalpha at fadedistance
169                 distancealpha = bound(0, (waypointsprite_fadedistance - distance) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1);
170                 distancealpha = pow(distancealpha, waypointsprite_distancealphaexponent);
171                 distancealpha = distancealpha * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
172         }
173
174         self.alpha = timealpha * distancealpha;
175
176         return TRUE;
177 }
178
179 entity WaypointSprite_Spawn(
180         string spr, // sprite
181         float lifetime, float maxdistance, // lifetime, max distance
182         entity ref, vector ofs, // position
183         entity showto, float t, // show to whom? Use a flag to indicate a team
184         entity own, .entity ownfield, // remove when own gets killed
185         float hideable // true when it should be controlled by cl_hidewaypoints
186 )
187 {
188         entity wp;
189         wp = spawn();
190         wp.classname = "sprite_waypoint";
191         wp.teleport_time = time + lifetime;
192         wp.health = lifetime;
193         wp.exteriormodeltoclient = ref;
194         if(ref)
195         {
196 #ifdef ATTACHMENT_WORKS_WITH_EF_NODEPTHTEST
197                 setattachment(wp, ref, "");
198                 setorigin(wp, ofs);
199 #else
200                 wp.view_ofs = ofs;
201                 setorigin(wp, ref.origin + ofs);
202 #endif
203         }
204         else
205                 setorigin(wp, ofs);
206         wp.enemy = showto;
207         wp.team = t;
208         wp.owner = own;
209         wp.currentammo = hideable;
210         if(own)
211         {
212                 if(own.ownfield)
213                         remove(own.ownfield);
214                 own.ownfield = wp;
215                 wp.owned_by_field = ownfield;
216         }
217         wp.max_health = maxdistance;
218         wp.customizeentityforclient = WaypointSprite_CustomizeEntityForClient;
219         wp.think = WaypointSprite_Think;
220         wp.nextthink = time;
221         wp.effects = EF_NODEPTHTEST;
222         setmodel(wp, strcat("models/sprites/", spr, ".sp2"));
223         return wp;
224 }
225
226 entity WaypointSprite_SpawnFixed(
227         string spr,
228         vector ofs
229 )
230 {
231         return WaypointSprite_Spawn(spr, 0, 0, world, ofs, world, 0, world, enemy, TRUE);
232 }
233
234 .entity waypointsprite_deployed_fixed;
235 entity WaypointSprite_DeployFixed(
236         string spr,
237         float limited_range,
238         vector ofs
239 )
240 {
241         float t, maxdistance;
242         if(teams_matter)
243                 t = self.team;
244         else
245                 t = 0;
246         if(limited_range)
247                 maxdistance = waypointsprite_limitedrange;
248         else
249                 maxdistance = 0;
250         return WaypointSprite_Spawn(spr, waypointsprite_deployed_lifetime, maxdistance, world, ofs, world, t, self, waypointsprite_deployed_fixed, FALSE);
251 }
252
253 .entity waypointsprite_deployed_personal;
254 entity WaypointSprite_DeployPersonal(
255         string spr,
256         vector ofs
257 )
258 {
259         return WaypointSprite_Spawn(spr, 0, 0, world, ofs, self, 0, self, waypointsprite_deployed_personal, FALSE);
260 }
261
262 .entity waypointsprite_attached;
263 .entity waypointsprite_attachedforcarrier;
264 entity WaypointSprite_Attach(
265         string spr,
266         float limited_range
267 )
268 {
269         float t, maxdistance;
270         if(self.waypointsprite_attachedforcarrier)
271                 return world; // can't attach to FC
272         if(teams_matter)
273                 t = self.team;
274         else
275                 t = 0;
276         if(limited_range)
277                 maxdistance = waypointsprite_limitedrange;
278         else
279                 maxdistance = 0;
280         return WaypointSprite_Spawn(spr, waypointsprite_deployed_lifetime, maxdistance, self, '0 0 64', world, t, self, waypointsprite_attached, FALSE);
281 }
282
283 entity WaypointSprite_AttachCarrier(
284         string spr,
285         entity carrier
286 )
287 {
288         WaypointSprite_Kill(carrier.waypointsprite_attached); // FC overrides attached
289         return WaypointSprite_Spawn(spr, 0, 0, carrier, '0 0 64', world, carrier.team, carrier, waypointsprite_attachedforcarrier, FALSE);
290 }
291
292 void WaypointSprite_DetachCarrier(entity carrier)
293 {
294         WaypointSprite_Disown(carrier.waypointsprite_attachedforcarrier, waypointsprite_deadlifetime);
295 }
296
297 void WaypointSprite_ClearPersonal()
298 {
299         WaypointSprite_Kill(self.waypointsprite_deployed_personal);
300 }
301
302 void WaypointSprite_ClearOwned()
303 {
304         WaypointSprite_Kill(self.waypointsprite_deployed_fixed);
305         WaypointSprite_Kill(self.waypointsprite_deployed_personal);
306         WaypointSprite_Kill(self.waypointsprite_attached);
307 }
308
309 void WaypointSprite_PlayerDead()
310 {
311         WaypointSprite_Disown(self.waypointsprite_attached, waypointsprite_deadlifetime);
312         WaypointSprite_DetachCarrier(self);
313 }
314
315 void WaypointSprite_PlayerGone()
316 {
317         WaypointSprite_Disown(self.waypointsprite_deployed_fixed, waypointsprite_deadlifetime);
318         WaypointSprite_Kill(self.waypointsprite_deployed_personal);
319         WaypointSprite_Disown(self.waypointsprite_attached, waypointsprite_deadlifetime);
320         WaypointSprite_DetachCarrier(self);
321 }