sorry, forgot this file
[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.aiment == wp.owner)
55                 {
56                         wp.view_ofs = wp.view_ofs + wp.aiment.origin;
57                         wp.aiment = world;
58                 }
59                 wp.owner.(wp.owned_by_field) = world;
60                 wp.owner = world;
61
62                 if(!wp.health)
63                 {
64                         wp.health = fadetime;
65                         wp.teleport_time = time + fadetime;
66                 }
67                 else if(fadetime < (wp.teleport_time - time))
68                 {
69                         // accelerate the waypoint's dying
70                         // ensure:
71                         //   (wp.teleport_time - time) / wp.health stays
72                         //   wp.teleport_time = time + fadetime
73                         float current_fadetime;
74                         current_fadetime = wp.teleport_time - time;
75                         wp.teleport_time = time + fadetime;
76                         wp.health = wp.health * fadetime / current_fadetime;
77                 }
78         }
79 }
80
81 void WaypointSprite_Think()
82 {
83         float doremove;
84
85         doremove = FALSE;
86
87         if(self.health)
88                 if(time >= self.teleport_time)
89                         doremove = TRUE;
90
91         if(doremove)
92                 WaypointSprite_Kill(self);
93         else
94                 self.nextthink = time;
95 }
96
97 float WaypointSprite_CustomizeEntityForClient()
98 {
99         vector realorigin, porigin;
100         float distancealpha, timealpha;
101         float distance;
102
103         if(self.health)
104         {
105                 timealpha = bound(0, (self.teleport_time - time) / self.health, 1);
106                 if(timealpha == 0)
107                         return FALSE;
108                 timealpha = pow(timealpha, waypointsprite_timealphaexponent);
109         }
110         else
111                 timealpha = 1;
112
113         if(self.enemy)
114                 if(self.enemy != other)
115                         return FALSE;
116         if(self.team)
117         {
118                 if(self.team != other.team)
119                         return FALSE;
120                 if(other.classname != "player")
121                         return FALSE;
122         }
123
124         // do not draw to yourself when attached
125         if(self.aiment)
126                 if(other == self.aiment)
127                         return FALSE;
128
129         if(self.currentammo) // hidable?
130                 if(other.cvar_cl_hidewaypoints) // wants to hide;
131                         return FALSE;
132
133         porigin = other.origin + other.view_ofs_z * '0 0 1';
134         realorigin = self.aiment.origin + self.view_ofs;
135         self.origin = realorigin;
136
137         distance = vlen(realorigin - porigin);
138
139         if(self.max_health)
140                 if(distance >= self.max_health)
141                         return FALSE;
142
143         self.scale = max(1, distance / waypointsprite_normdistance) * waypointsprite_minscale;
144
145         if(self.max_health > waypointsprite_normdistance)
146         {
147                 // alpha 1 at normdistance, alpha 0 at maxdistance
148                 distancealpha = bound(0, (self.max_health - distance) / (self.max_health - waypointsprite_normdistance), 1);
149                 distancealpha = pow(distancealpha, waypointsprite_distancealphaexponent);
150         }
151         else if(self.max_health)
152         {
153                 // alpha 1 if visible
154                 distancealpha = 1;
155         }
156         else
157         {
158                 // alpha 1 at normdistance, alpha minalpha at fadedistance
159                 distancealpha = bound(0, (waypointsprite_fadedistance - distance) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1);
160                 distancealpha = pow(distancealpha, waypointsprite_distancealphaexponent);
161                 distancealpha = distancealpha * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
162         }
163
164         self.alpha = timealpha * distancealpha;
165
166         return TRUE;
167 }
168
169 entity WaypointSprite_Spawn(
170         string spr, // sprite
171         float lifetime, float maxdistance, // lifetime, max distance
172         entity ref, vector ofs, // position
173         entity showto, float t, // show to whom? Use a flag to indicate a team
174         entity own, .entity ownfield, // remove when own gets killed
175         float hideable // true when it should be controlled by cl_hidewaypoints
176 )
177 {
178         entity wp;
179         wp = spawn();
180         wp.classname = "sprite_waypoint";
181         wp.teleport_time = time + lifetime;
182         wp.health = lifetime;
183         wp.view_ofs = ofs;
184         wp.aiment = ref;
185         wp.enemy = showto;
186         wp.team = t;
187         wp.owner = own;
188         wp.currentammo = hideable;
189         if(own)
190         {
191                 if(own.ownfield)
192                         remove(own.ownfield);
193                 own.ownfield = wp;
194                 wp.owned_by_field = ownfield;
195         }
196         wp.max_health = maxdistance;
197         wp.customizeentityforclient = WaypointSprite_CustomizeEntityForClient;
198         wp.think = WaypointSprite_Think;
199         wp.nextthink = time;
200         wp.effects = EF_NODEPTHTEST;
201         setmodel(wp, strcat("models/sprites/", spr, ".sp2"));
202         return wp;
203 }
204
205 entity WaypointSprite_SpawnFixed(
206         string spr,
207         vector ofs
208 )
209 {
210         return WaypointSprite_Spawn(spr, 0, 0, world, ofs, world, 0, world, enemy, TRUE);
211 }
212
213 .entity waypointsprite_deployed_fixed;
214 entity WaypointSprite_DeployFixed(
215         string spr,
216         float limited_range,
217         vector ofs
218 )
219 {
220         float t, maxdistance;
221         if(teams_matter)
222                 t = self.team;
223         else
224                 t = 0;
225         if(limited_range)
226                 maxdistance = waypointsprite_limitedrange;
227         else
228                 maxdistance = 0;
229         return WaypointSprite_Spawn(spr, waypointsprite_deployed_lifetime, maxdistance, world, ofs, world, t, self, waypointsprite_deployed_fixed, FALSE);
230 }
231
232 .entity waypointsprite_deployed_personal;
233 entity WaypointSprite_DeployPersonal(
234         string spr,
235         vector ofs
236 )
237 {
238         return WaypointSprite_Spawn(spr, 0, 0, world, ofs, self, 0, self, waypointsprite_deployed_personal, FALSE);
239 }
240
241 .entity waypointsprite_attached;
242 .entity waypointsprite_attachedforcarrier;
243 entity WaypointSprite_Attach(
244         string spr,
245         float limited_range
246 )
247 {
248         float t, maxdistance;
249         if(self.waypointsprite_attachedforcarrier)
250                 return world; // can't attach to FC
251         if(teams_matter)
252                 t = self.team;
253         else
254                 t = 0;
255         if(limited_range)
256                 maxdistance = waypointsprite_limitedrange;
257         else
258                 maxdistance = 0;
259         return WaypointSprite_Spawn(spr, waypointsprite_deployed_lifetime, maxdistance, self, '0 0 64', world, t, self, waypointsprite_attached, FALSE);
260 }
261
262 entity WaypointSprite_AttachCarrier(
263         string spr,
264         entity carrier
265 )
266 {
267         WaypointSprite_Kill(carrier.waypointsprite_attached); // FC overrides attached
268         return WaypointSprite_Spawn(spr, 0, 0, carrier, '0 0 64', world, carrier.team, carrier, waypointsprite_attachedforcarrier, FALSE);
269 }
270
271 void WaypointSprite_DetachCarrier(entity carrier)
272 {
273         WaypointSprite_Disown(carrier.waypointsprite_attachedforcarrier, 1);
274 }
275
276 void WaypointSprite_ClearPersonal()
277 {
278         WaypointSprite_Kill(self.waypointsprite_deployed_personal);
279 }
280
281 void WaypointSprite_ClearOwned()
282 {
283         WaypointSprite_Kill(self.waypointsprite_deployed_fixed);
284         WaypointSprite_Kill(self.waypointsprite_deployed_personal);
285         WaypointSprite_Kill(self.waypointsprite_attached);
286 }
287
288 void WaypointSprite_PlayerDead()
289 {
290         WaypointSprite_Disown(self.waypointsprite_attached, waypointsprite_deadlifetime);
291         WaypointSprite_DetachCarrier(self);
292 }
293
294 void WaypointSprite_PlayerGone()
295 {
296         WaypointSprite_Disown(self.waypointsprite_deployed_fixed, waypointsprite_deadlifetime);
297         WaypointSprite_Kill(self.waypointsprite_deployed_personal);
298         WaypointSprite_Disown(self.waypointsprite_attached, waypointsprite_deadlifetime);
299         WaypointSprite_DetachCarrier(self);
300 }