Properly calculate falling damage based on player scale. Don't just offset the damage...
[voretournament/voretournament.git] / data / qcsrc / server / sv_main.qc
1 \r
2 void CreatureFrame (void)\r
3 {\r
4         local entity oldself;\r
5         local float dm;\r
6         oldself = self;\r
7         self = findfloat(world, iscreature, TRUE);\r
8         while (self)\r
9         {\r
10                 if (self.movetype != MOVETYPE_NOCLIP)\r
11                 {\r
12                         if (self.waterlevel)\r
13                         {\r
14                                 if (!(self.flags & FL_INWATER))\r
15                                 {\r
16                                         self.flags |= FL_INWATER;\r
17                                         self.dmgtime = 0;\r
18                                 }\r
19                                 if (self.waterlevel != WATERLEVEL_SUBMERGED)\r
20                                 {\r
21                                         if(self.air_finished < time + 9)\r
22                                                 PlayerSound(self, playersound_gasp, CHAN_PLAYER, VOICETYPE_PLAYERSOUND);\r
23                                         self.air_finished = time + 12;\r
24                                         self.dmg = 2;\r
25                                 }\r
26                                 else if (self.air_finished < time)\r
27                                 {       // drown!\r
28                                         if (!self.deadflag)\r
29                                         if (self.pain_finished < time)\r
30                                         {\r
31                                                 Damage (self, world, world, 5, DEATH_DROWN, self.origin, '0 0 0');\r
32                                                 self.pain_finished = time + 0.5;\r
33                                         }\r
34                                 }\r
35                                 if (self.dmgtime < time)\r
36                                 {\r
37                                         self.dmgtime = time + 0.1;\r
38                                         if (self.watertype == CONTENT_LAVA)\r
39                                         {\r
40                                                 if (self.watersound_finished < time)\r
41                                                 {\r
42                                                         self.watersound_finished = time + 0.5;\r
43                                                         sound (self, CHAN_PLAYER, "player/lava.wav", VOL_BASE, ATTN_NORM);\r
44                                                 }\r
45                                                 Damage (self, world, world, 6 * self.waterlevel, DEATH_LAVA, self.origin, '0 0 0');\r
46                                         }\r
47                                         else if (self.watertype == CONTENT_SLIME)\r
48                                         {\r
49                                                 if (self.watersound_finished < time)\r
50                                                 {\r
51                                                         self.watersound_finished = time + 0.5;\r
52                                                         sound (self, CHAN_PLAYER, "player/slime.wav", VOL_BASE, ATTN_NORM);\r
53                                                 }\r
54                                                 Damage (self, world, world, 2 * self.waterlevel, DEATH_SLIME, self.origin, '0 0 0');\r
55                                         }\r
56                                 }\r
57                         }\r
58                         else\r
59                         {\r
60                                 if (self.flags & FL_INWATER)\r
61                                 {\r
62                                         // play leave water sound\r
63                                         self.flags &~= FL_INWATER;\r
64                                         self.dmgtime = 0;\r
65                                 }\r
66                                 self.air_finished = time + 12;\r
67                                 self.dmg = 2;\r
68                         }\r
69                         // check for falling damage\r
70                         if(!(g_cts && !cvar("g_cts_selfdamage")))\r
71                         {\r
72                                 // if we are smaller or larger, take more or less falling damage\r
73                                 float scalefac;\r
74                                 scalefac = cvar("g_healthsize") ? pow(self.scale, cvar("g_healthsize_falldamagefactor")) : 1;\r
75 \r
76                                 dm = vlen(self.oldvelocity) - vlen(self.velocity); // dm is now the velocity DECREASE. Velocity INCREASE should never cause a sound or any damage.\r
77                                 if (self.deadflag)\r
78                                         dm = (dm - cvar("g_balance_falldamage_deadminspeed") * scalefac) * cvar("g_balance_falldamage_factor");\r
79                                 else\r
80                                         dm = min((dm - cvar("g_balance_falldamage_minspeed") * scalefac) * cvar("g_balance_falldamage_factor"), cvar("g_balance_falldamage_maxdamage"));\r
81                                 dm /= scalefac;\r
82                                 if (dm > 0)\r
83                                         Damage (self, world, world, dm, DEATH_FALL, self.origin, '0 0 0');\r
84                                 else if(vlen(self.velocity) > 100000 && cvar("developer"))\r
85                                 {\r
86                                         dprint(strcat(self.netname, " became too fast, please investigate: ", vtos(self.spawnorigin), "\n"));\r
87                                         Damage (self, world, world, 50000, DEATH_SHOOTING_STAR, self.origin, '0 0 0');\r
88                                 }\r
89                         }\r
90 \r
91                         // play stupid sounds\r
92                         if (g_footsteps)\r
93                         if (!gameover)\r
94                         if (self.flags & FL_ONGROUND)\r
95                         if (vlen(self.velocity) > sv_maxspeed * 0.6)\r
96                         if (!self.deadflag)\r
97                         if (time < self.lastground + 0.2)\r
98                         {\r
99                                 if((time > self.nextstep) || (time < (self.nextstep - 10.0)))\r
100                                 {\r
101                                         self.nextstep = time + 0.3 + random() * 0.1;\r
102                                         trace_dphitq3surfaceflags = 0;\r
103                                         tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self);\r
104                                         /*\r
105                                         if(trace_fraction == 1)\r
106                                                 dprint("nohit\n");\r
107                                         else\r
108                                                 dprint(ftos(trace_dphitq3surfaceflags), "\n");\r
109                                         */\r
110                                         if not(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS)\r
111                                         {\r
112                                                 // if healthsize is enabled, play effects based on player size\r
113                                                 if(cvar("g_healthsize"))\r
114                                                 {\r
115                                                         if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)\r
116                                                                 GlobalSound(globalsound_metalstep, CHAN_PLAYER, VOICETYPE_PLAYERSOUND, bound(0, VOL_BASE * (1 - playersize_micro(self)), 1));\r
117                                                         else\r
118                                                                 GlobalSound(globalsound_step, CHAN_PLAYER, VOICETYPE_PLAYERSOUND, bound(0, VOL_BASE * (1 - playersize_micro(self)), 1));\r
119                                                         sound(self, CHAN_AUTO, "misc/macro_footstep.wav", bound(0, VOL_BASE * playersize_macro(self), 1), ATTN_NORM);\r
120 \r
121                                                         // earthquake effect for nearby players when a macro walks by\r
122                                                         if(cvar("g_healthsize_quake_step"))\r
123                                                         {\r
124                                                                 entity head;\r
125                                                                 for(head = findradius(self.origin, cvar("g_healthsize_quake_step_radius")); head; head = head.chain)\r
126                                                                 {\r
127                                                                         if not(head.classname == "player" || head.classname == "spectator")\r
128                                                                                 continue;\r
129                                                                         if(head == self || head.spectatee_status == num_for_edict(self))\r
130                                                                                 continue; // not for self\r
131                                                                         if not(head.flags & FL_ONGROUND)\r
132                                                                                 continue; // we only feel the ground shaking if we are sitting on it\r
133                                                                         if(head.stat_eaten)\r
134                                                                                 continue; // not for prey\r
135 \r
136                                                                         float shake;\r
137                                                                         shake = vlen(head.origin - self.origin);\r
138                                                                         if(shake)\r
139                                                                                 shake = 1 - bound(0, shake / cvar("g_healthsize_quake_step_radius"), 1);\r
140                                                                         shake *= playersize_macro(self) * cvar("g_healthsize_quake_step");\r
141 \r
142                                                                         head.punchvector_x += crandom() * shake;\r
143                                                                         head.punchvector_y += crandom() * shake;\r
144                                                                         head.punchvector_z += crandom() * shake;\r
145                                                                 }\r
146                                                         }\r
147                                                 }\r
148                                                 else\r
149                                                 {\r
150                                                         if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)\r
151                                                                 GlobalSound(globalsound_metalstep, CHAN_PLAYER, VOICETYPE_PLAYERSOUND, VOL_BASE);\r
152                                                         else\r
153                                                                 GlobalSound(globalsound_step, CHAN_PLAYER, VOICETYPE_PLAYERSOUND, VOL_BASE);\r
154                                                 }\r
155                                         }\r
156                                 }\r
157                         }\r
158                         self.oldvelocity = self.velocity;\r
159                 }\r
160                 self = findfloat(self, iscreature, TRUE);\r
161         }\r
162         self = oldself;\r
163 }\r
164 \r
165 \r
166 /*\r
167 =============\r
168 StartFrame\r
169 \r
170 Called before each frame by the server\r
171 =============\r
172 */\r
173 \r
174 float game_delay;\r
175 float game_delay_last;\r
176 \r
177 float RedirectionThink();\r
178 entity SelectSpawnPoint (float anypoint);\r
179 void StartFrame (void)\r
180 {\r
181         remove = remove_unsafely; // not during spawning!\r
182         serverprevtime = servertime;\r
183         servertime = time;\r
184         serverframetime = frametime;\r
185 \r
186 #ifdef PROFILING\r
187         if(time > client_cefc_accumulatortime + 1)\r
188         {\r
189                 float t, pp, c_seeing, c_seen;\r
190                 entity cl;\r
191                 t = client_cefc_accumulator / (time - client_cefc_accumulatortime);\r
192                 print("CEFC time: ", ftos(t * 1000), "ms; ");\r
193                 c_seeing = 0;\r
194                 c_seen = 0;\r
195                 FOR_EACH_CLIENT(cl)\r
196                 {\r
197                         if(clienttype(cl) == CLIENTTYPE_REAL)\r
198                                 ++c_seeing;\r
199                         if(cl.classname == "player")\r
200                                 ++c_seen;\r
201                 }\r
202                 print("CEFC calls per second: ", ftos(c_seeing * (c_seen - 1) / t), "; ");\r
203                 print("CEFC 100% load at: ", ftos(solve_quadratic(t, -t, -1) * '0 1 0'), "\n");\r
204 \r
205                 client_cefc_accumulatortime = time;\r
206                 client_cefc_accumulator = 0;\r
207         }\r
208 #endif\r
209 \r
210         entity e;\r
211         for(e = world; (e = findfloat(e, csqcprojectile_clientanimate, 1)); )\r
212                 CSQCProjectile_Check(e);\r
213 \r
214         if(RedirectionThink())\r
215                 return;\r
216 \r
217         UncustomizeEntitiesRun();\r
218         InitializeEntitiesRun();\r
219 \r
220         WarpZone_StartFrame();\r
221 \r
222         sv_gravity = cvar("sv_gravity");\r
223         sv_maxairspeed = cvar("sv_maxairspeed");\r
224         sv_maxspeed = cvar ("sv_maxspeed");\r
225         sv_friction = cvar ("sv_friction");\r
226         sv_accelerate = cvar ("sv_accelerate");\r
227         sv_airaccelerate = cvar("sv_airaccelerate");\r
228         sv_airaccel_sideways_friction = cvar("sv_airaccel_sideways_friction");\r
229         sv_airaccel_qw = cvar("sv_airaccel_qw");\r
230         sv_stopspeed = cvar ("sv_stopspeed");\r
231         sv_airstopaccelerate = cvar("sv_airstopaccelerate");\r
232         sv_airstrafeaccelerate = cvar("sv_airstrafeaccelerate");\r
233         sv_maxairstrafespeed = cvar("sv_maxairstrafespeed");\r
234         sv_aircontrol = cvar("sv_aircontrol");\r
235         sv_warsowbunny_airforwardaccel = cvar("sv_warsowbunny_airforwardaccel");\r
236         sv_warsowbunny_accel = cvar("sv_warsowbunny_accel");\r
237         sv_warsowbunny_topspeed = cvar("sv_warsowbunny_topspeed");\r
238         sv_warsowbunny_turnaccel = cvar("sv_warsowbunny_turnaccel");\r
239         sv_warsowbunny_backtosideratio = cvar("sv_warsowbunny_backtosideratio");\r
240         teamplay = cvar ("teamplay");\r
241         sys_frametime = cvar("sys_ticrate") * cvar("slowmo");\r
242 \r
243         if (timeoutStatus == 1) // just before the timeout (when timeoutStatus will be 2)\r
244                 orig_slowmo = cvar("slowmo"); // slowmo will be restored after the timeout\r
245 \r
246         if(teams_matter && !teamplay)\r
247                 teamplay = 3;\r
248         if(!teams_matter && teamplay)\r
249                 teamplay = 0;\r
250 \r
251         skill = cvar("skill");\r
252 \r
253         Spawnqueue_Check();\r
254 \r
255 \r
256         // detect when the pre-game countdown (if any) has ended and the game has started\r
257         game_delay = (time < game_starttime) ? TRUE : FALSE;\r
258 \r
259         if(game_delay_last == TRUE)\r
260         if(game_delay == FALSE)\r
261         if(cvar("sv_eventlog"))\r
262                         GameLogEcho(":startdelay_ended");\r
263 \r
264         game_delay_last = game_delay;\r
265 \r
266         // if in warmup stage and limit for warmup is hit start match\r
267         if (inWarmupStage)\r
268         if ((g_warmup_limit > 0 && time >= g_warmup_limit)\r
269          || (g_warmup_limit == 0 && cvar("timelimit") != 0 && time >= cvar("timelimit") * 60))\r
270         {\r
271                 ReadyRestart();\r
272                 return;\r
273         }\r
274 \r
275         CreatureFrame ();\r
276         CheckRules_World ();\r
277 \r
278         AuditTeams();\r
279 \r
280         bot_serverframe();\r
281 \r
282         if(cvar("spawn_debugview"))\r
283         {\r
284                 RandomSelection_Init();\r
285                 for(self = world; (self = find(self, classname, "player")); )\r
286                         RandomSelection_Add(self, 0, string_null, 1, 0);\r
287                 self = RandomSelection_chosen_ent;\r
288                 SelectSpawnPoint(0);\r
289         }\r
290 \r
291         FOR_EACH_PLAYER(self)\r
292                 self.porto_forbidden = max(0, self.porto_forbidden - 1);\r
293 }\r
294 \r
295 .vector originjitter;\r
296 .vector anglesjitter;\r
297 .float anglejitter;\r
298 .string gametypefilter;\r
299 .string cvarfilter;\r
300 void SV_OnEntityPreSpawnFunction()\r
301 {\r
302         if(self.gametypefilter != "")\r
303         if not(isGametypeInFilter(game, teams_matter, self.gametypefilter))\r
304         {\r
305                 remove(self);\r
306                 return;\r
307         }\r
308         if(self.cvarfilter != "")\r
309         {\r
310                 float n, i, o, inv;\r
311                 string s, k, v;\r
312                 inv = 0;\r
313 \r
314                 s = self.cvarfilter;\r
315                 if(substring(s, 0, 1) == "+")\r
316                 {\r
317                         s = substring(s, 1, -1);\r
318                 }\r
319                 else if(substring(s, 0, 1) == "-")\r
320                 {\r
321                         inv = 1;\r
322                         s = substring(s, 1, -1);\r
323                 }\r
324 \r
325                 n = tokenize(s);\r
326                 for(i = 0; i < n; ++i)\r
327                 {\r
328                         s = argv(i);\r
329                         // syntax:\r
330                         // var>x\r
331                         // var<x\r
332                         // var>=x\r
333                         // var<=x\r
334                         // var==x\r
335                         // var!=x\r
336                         // var===x\r
337                         // var!==x\r
338                         if((o = strstrofs(s, ">=", 0)) >= 0)\r
339                         {\r
340                                 k = substring(s, 0, o);\r
341                                 v = substring(s, o+2, -1);\r
342                                 if(cvar(k) < stof(v))\r
343                                         goto cvar_fail;\r
344                         }\r
345                         else if((o = strstrofs(s, "<=", 0)) >= 0)\r
346                         {\r
347                                 k = substring(s, 0, o);\r
348                                 v = substring(s, o+2, -1);\r
349                                 if(cvar(k) > stof(v))\r
350                                         goto cvar_fail;\r
351                         }\r
352                         else if((o = strstrofs(s, ">", 0)) >= 0)\r
353                         {\r
354                                 k = substring(s, 0, o);\r
355                                 v = substring(s, o+1, -1);\r
356                                 if(cvar(k) <= stof(v))\r
357                                         goto cvar_fail;\r
358                         }\r
359                         else if((o = strstrofs(s, "<", 0)) >= 0)\r
360                         {\r
361                                 k = substring(s, 0, o);\r
362                                 v = substring(s, o+1, -1);\r
363                                 if(cvar(k) >= stof(v))\r
364                                         goto cvar_fail;\r
365                         }\r
366                         else if((o = strstrofs(s, "==", 0)) >= 0)\r
367                         {\r
368                                 k = substring(s, 0, o);\r
369                                 v = substring(s, o+2, -1);\r
370                                 if(cvar(k) != stof(v))\r
371                                         goto cvar_fail;\r
372                         }\r
373                         else if((o = strstrofs(s, "!=", 0)) >= 0)\r
374                         {\r
375                                 k = substring(s, 0, o);\r
376                                 v = substring(s, o+2, -1);\r
377                                 if(cvar(k) == stof(v))\r
378                                         goto cvar_fail;\r
379                         }\r
380                         else if((o = strstrofs(s, "===", 0)) >= 0)\r
381                         {\r
382                                 k = substring(s, 0, o);\r
383                                 v = substring(s, o+2, -1);\r
384                                 if(cvar_string(k) != v)\r
385                                         goto cvar_fail;\r
386                         }\r
387                         else if((o = strstrofs(s, "!==", 0)) >= 0)\r
388                         {\r
389                                 k = substring(s, 0, o);\r
390                                 v = substring(s, o+2, -1);\r
391                                 if(cvar_string(k) == v)\r
392                                         goto cvar_fail;\r
393                         }\r
394                         else if(substring(s, 0, 1) == "!")\r
395                         {\r
396                                 k = substring(s, 1, -1);\r
397                                 if(cvar(k))\r
398                                         goto cvar_fail;\r
399                         }\r
400                         else\r
401                         {\r
402                                 k = s;\r
403                                 if not(cvar(k))\r
404                                         goto cvar_fail;\r
405                         }\r
406                 }\r
407                 inv = !inv;\r
408 :cvar_fail\r
409                 // now inv is 1 if we want to keep the item, and 0 if we want to get rid of it\r
410                 if not(inv)\r
411                 {\r
412                         //print("cvarfilter fail\n");\r
413                         remove(self);\r
414                         return;\r
415                 }\r
416         }\r
417 \r
418         // support special -1 and -2 angle from radiant\r
419         if (self.angles == '0 -1 0')\r
420                 self.angles = '-90 0 0';\r
421         else if (self.angles == '0 -2 0')\r
422                 self.angles = '+90 0 0';\r
423 \r
424         if(self.originjitter_x != 0)\r
425                 self.origin_x = self.origin_x + (random() * 2 - 1) * self.originjitter_x;\r
426         if(self.originjitter_y != 0)\r
427                 self.origin_y = self.origin_y + (random() * 2 - 1) * self.originjitter_y;\r
428         if(self.originjitter_z != 0)\r
429                 self.origin_z = self.origin_z + (random() * 2 - 1) * self.originjitter_z;\r
430         if(self.anglesjitter_x != 0)\r
431                 self.angles_x = self.angles_x + (random() * 2 - 1) * self.anglesjitter_x;\r
432         if(self.anglesjitter_y != 0)\r
433                 self.angles_y = self.angles_y + (random() * 2 - 1) * self.anglesjitter_y;\r
434         if(self.anglesjitter_z != 0)\r
435                 self.angles_z = self.angles_z + (random() * 2 - 1) * self.anglesjitter_z;\r
436         if(self.anglejitter != 0)\r
437                 self.angles_y = self.angles_y + (random() * 2 - 1) * self.anglejitter;\r
438 }\r