1 var void remove(entity e);
\r
2 void objerror(string s);
\r
4 .vector dropped_origin;
\r
6 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
\r
7 void crosshair_trace(entity pl)
\r
9 traceline_antilag(pl, pl.cursor_trace_start, pl.cursor_trace_start + normalize(pl.cursor_trace_endpos - pl.cursor_trace_start) * MAX_SHOT_DISTANCE, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
\r
11 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
\r
12 void WarpZone_crosshair_trace(entity pl)
\r
14 WarpZone_traceline_antilag(pl, pl.cursor_trace_start, pl.cursor_trace_start + normalize(pl.cursor_trace_endpos - pl.cursor_trace_start) * MAX_SHOT_DISTANCE, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
\r
17 void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
\r
18 void() spawnpoint_use;
\r
19 float race_GetTime(float pos);
\r
20 string race_GetName(float pos);
\r
21 string race_PlaceName(float pos);
\r
22 string GetMapname();
\r
23 string ColoredTeamName(float t);
\r
25 string admin_name(void)
\r
27 if(cvar_string("sv_adminnick") != "")
\r
28 return cvar_string("sv_adminnick");
\r
30 return "SERVER ADMIN";
\r
33 float DistributeEvenly_amount;
\r
34 float DistributeEvenly_totalweight;
\r
35 void DistributeEvenly_Init(float amount, float totalweight)
\r
37 if (DistributeEvenly_amount)
\r
39 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
\r
40 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
\r
42 if (totalweight == 0)
\r
43 DistributeEvenly_amount = 0;
\r
45 DistributeEvenly_amount = amount;
\r
46 DistributeEvenly_totalweight = totalweight;
\r
48 float DistributeEvenly_Get(float weight)
\r
53 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
\r
54 DistributeEvenly_totalweight -= weight;
\r
55 DistributeEvenly_amount -= f;
\r
59 #define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
\r
62 string STR_PLAYER = "player";
\r
63 string STR_SPECTATOR = "spectator";
\r
64 string STR_OBSERVER = "observer";
\r
67 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
\r
68 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
\r
69 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
\r
70 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
\r
72 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
\r
73 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
\r
74 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
\r
75 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
\r
76 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
\r
79 // copies a string to a tempstring (so one can strunzone it)
\r
80 string strcat1(string s) = #115; // FRIK_FILE
\r
85 string GetAdvancedDeathReports(entity enPlayer) // Extra fragmessage information
\r
87 local float nPlayerHealth = rint(enPlayer.health);
\r
88 local float nPlayerArmor = rint(enPlayer.armorvalue);
\r
89 local float nPlayerHandicap = enPlayer.cvar_cl_handicap;
\r
90 local float nPlayerPing = rint(enPlayer.ping);
\r
91 local string strPlayerPingColor;
\r
92 local string strMessage;
\r
93 if(nPlayerPing >= 150)
\r
94 strPlayerPingColor = "^1";
\r
96 strPlayerPingColor = "^2";
\r
98 if((cvar("sv_fragmessage_information_stats")) && (enPlayer.health >= 1))
\r
99 strMessage = strcat(strMessage, "\n^7(Health ^1", ftos(nPlayerHealth), "^7 / Armor ^2", ftos(nPlayerArmor), "^7)");
\r
101 if(cvar("sv_fragmessage_information_ping")) {
\r
102 if(clienttype(enPlayer) == CLIENTTYPE_BOT) // Bots have no ping
\r
103 strMessage = strcat(strMessage, "\n^7(^2Bot");
\r
105 strMessage = strcat(strMessage, "\n^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms");
\r
106 if(cvar("sv_fragmessage_information_handicap"))
\r
107 if(cvar("sv_fragmessage_information_handicap") == 2)
\r
108 if(nPlayerHandicap <= 1)
\r
109 strMessage = strcat(strMessage, "^7 / Handicap ^2Off^7)");
\r
111 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
112 else if not(nPlayerHandicap <= 1)
\r
113 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
115 strMessage = strcat(strMessage, "^7)");
\r
116 } else if(cvar("sv_fragmessage_information_handicap")) {
\r
117 if(cvar("sv_fragmessage_information_handicap") == 2)
\r
118 if(nPlayerHandicap <= 1)
\r
119 strMessage = strcat(strMessage, "\n^7(Handicap ^2Off^7)");
\r
121 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
122 else if(nPlayerHandicap > 1)
\r
123 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
127 void bcenterprint(string s)
\r
129 // TODO replace by MSG_ALL (would show it to spectators too, though)?
\r
131 FOR_EACH_PLAYER(head)
\r
132 if (clienttype(head) == CLIENTTYPE_REAL)
\r
133 centerprint(head, s);
\r
136 void GameLogEcho(string s)
\r
141 if (cvar("sv_eventlog_files"))
\r
145 logfile_open = TRUE;
\r
146 matches = cvar("sv_eventlog_files_counter") + 1;
\r
147 cvar_set("sv_eventlog_files_counter", ftos(matches));
\r
148 fn = ftos(matches);
\r
149 if (strlen(fn) < 8)
\r
150 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
\r
151 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
\r
152 logfile = fopen(fn, FILE_APPEND);
\r
153 fputs(logfile, ":logversion:3\n");
\r
157 if (cvar("sv_eventlog_files_timestamps"))
\r
158 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
\r
160 fputs(logfile, strcat(s, "\n"));
\r
163 if (cvar("sv_eventlog_console"))
\r
172 // will be opened later
\r
175 void GameLogClose()
\r
177 if (logfile_open && logfile >= 0)
\r
184 vector PL_VIEW_OFS;
\r
187 vector PL_CROUCH_VIEW_OFS;
\r
188 vector PL_CROUCH_MIN;
\r
189 vector PL_CROUCH_MAX;
\r
191 float spawnpoint_nag;
\r
192 void relocate_spawnpoint()
\r
194 PL_VIEW_OFS = stov(cvar_string("sv_player_viewoffset"));
\r
195 PL_MIN = stov(cvar_string("sv_player_mins"));
\r
196 PL_MAX = stov(cvar_string("sv_player_maxs"));
\r
197 PL_CROUCH_VIEW_OFS = stov(cvar_string("sv_player_crouch_viewoffset"));
\r
198 PL_CROUCH_MIN = stov(cvar_string("sv_player_crouch_mins"));
\r
199 PL_CROUCH_MAX = stov(cvar_string("sv_player_crouch_maxs"));
\r
201 // nudge off the floor
\r
202 setorigin(self, self.origin + '0 0 1');
\r
204 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
\r
205 if (trace_startsolid)
\r
209 self.mins = PL_MIN;
\r
210 self.maxs = PL_MAX;
\r
211 if (!move_out_of_solid(self))
\r
212 objerror("could not get out of solid at all!");
\r
213 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
\r
214 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
\r
215 print(" ", ftos(self.origin_y - o_y));
\r
216 print(" ", ftos(self.origin_z - o_z), "'\n");
\r
217 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
\r
219 if (!spawnpoint_nag)
\r
220 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
\r
221 spawnpoint_nag = 1;
\r
225 setorigin(self, o);
\r
226 self.mins = self.maxs = '0 0 0';
\r
227 objerror("player spawn point in solid, mapper sucks!\n");
\r
232 if (cvar("g_spawnpoints_autodrop"))
\r
234 setsize(self, PL_MIN, PL_MAX);
\r
238 self.use = spawnpoint_use;
\r
239 self.team_saved = self.team;
\r
243 if (have_team_spawns != 0)
\r
245 have_team_spawns = 1;
\r
247 if (cvar("r_showbboxes"))
\r
249 // show where spawnpoints point at too
\r
250 makevectors(self.angles);
\r
253 e.classname = "info_player_foo";
\r
254 setorigin(e, self.origin + v_forward * 24);
\r
255 setsize(e, '-8 -8 -8', '8 8 8');
\r
256 e.solid = SOLID_TRIGGER;
\r
260 #define strstr strstrofs
\r
262 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
\r
263 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
\r
264 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
\r
265 // BE CONSTANT OR strzoneD!
\r
266 float strstr(string haystack, string needle, float offset)
\r
270 len = strlen(needle);
\r
271 endpos = strlen(haystack) - len;
\r
272 while(offset <= endpos)
\r
274 found = substring(haystack, offset, len);
\r
275 if(found == needle)
\r
277 offset = offset + 1;
\r
283 float NUM_NEAREST_ENTITIES = 4;
\r
284 entity nearest_entity[NUM_NEAREST_ENTITIES];
\r
285 float nearest_length[NUM_NEAREST_ENTITIES];
\r
286 entity findnearest(vector point, .string field, string value, vector axismod)
\r
297 localhead = find(world, field, value);
\r
300 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
\r
301 dist = localhead.oldorigin;
\r
303 dist = localhead.origin;
\r
304 dist = dist - point;
\r
305 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
\r
308 for (i = 0; i < num_nearest; ++i)
\r
310 if (len < nearest_length[i])
\r
314 // now i tells us where to insert at
\r
315 // INSERTION SORT! YOU'VE SEEN IT! RUN!
\r
316 if (i < NUM_NEAREST_ENTITIES)
\r
318 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
\r
320 nearest_length[j + 1] = nearest_length[j];
\r
321 nearest_entity[j + 1] = nearest_entity[j];
\r
323 nearest_length[i] = len;
\r
324 nearest_entity[i] = localhead;
\r
325 if (num_nearest < NUM_NEAREST_ENTITIES)
\r
326 num_nearest = num_nearest + 1;
\r
329 localhead = find(localhead, field, value);
\r
332 // now use the first one from our list that we can see
\r
333 for (i = 0; i < num_nearest; ++i)
\r
335 traceline(point, nearest_entity[i].origin, TRUE, world);
\r
336 if (trace_fraction == 1)
\r
340 dprint("Nearest point (");
\r
341 dprint(nearest_entity[0].netname);
\r
342 dprint(") is not visible, using a visible one.\n");
\r
344 return nearest_entity[i];
\r
348 if (num_nearest == 0)
\r
351 dprint("Not seeing any location point, using nearest as fallback.\n");
\r
353 dprint("Candidates were: ");
\r
354 for(j = 0; j < num_nearest; ++j)
\r
358 dprint(nearest_entity[j].netname);
\r
363 return nearest_entity[0];
\r
366 void spawnfunc_target_location()
\r
368 self.classname = "target_location";
\r
369 // location name in netname
\r
370 // eventually support: count, teamgame selectors, line of sight?
\r
373 void spawnfunc_info_location()
\r
375 self.classname = "target_location";
\r
376 self.message = self.netname;
\r
379 string NearestLocation(vector p)
\r
384 loc = findnearest(p, classname, "target_location", '1 1 1');
\r
391 loc = findnearest(p, target, "###item###", '1 1 4');
\r
398 string formatmessage(string msg)
\r
405 string replacement;
\r
409 WarpZone_crosshair_trace(self);
\r
410 cursor = trace_endpos;
\r
411 cursor_ent = trace_ent;
\r
415 break; // too many replacements
\r
418 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
\r
419 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
\r
432 replacement = substring(msg, p, 2);
\r
433 escape = substring(msg, p + 1, 1);
\r
437 else if (escape == "\\")
\r
438 replacement = "\\";
\r
439 else if (escape == "n")
\r
440 replacement = "\n";
\r
441 else if (escape == "a")
\r
442 replacement = ftos(floor(self.armorvalue));
\r
443 else if (escape == "h")
\r
444 replacement = ftos(floor(self.health));
\r
445 else if (escape == "l")
\r
446 replacement = NearestLocation(self.origin);
\r
447 else if (escape == "y")
\r
448 replacement = NearestLocation(cursor);
\r
449 else if (escape == "d")
\r
450 replacement = NearestLocation(self.death_origin);
\r
451 else if (escape == "w") {
\r
455 wep = self.switchweapon;
\r
458 replacement = W_Name(wep);
\r
459 } else if (escape == "W") {
\r
460 replacement = "batteries"; // ;)
\r
461 } else if (escape == "x") {
\r
462 replacement = cursor_ent.netname;
\r
463 if (!replacement || !cursor_ent)
\r
464 replacement = "nothing";
\r
465 } else if (escape == "p") {
\r
466 if (self.last_selected_player)
\r
467 replacement = self.last_selected_player.netname;
\r
469 replacement = "(nobody)";
\r
470 } else if (escape == "s")
\r
471 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
\r
472 else if (escape == "S")
\r
473 replacement = ftos(vlen(self.velocity));
\r
474 else if (escape == "v") {
\r
475 float weapon_number;
\r
476 local entity stats;
\r
478 if(self.classname == "spectator")
\r
479 stats = self.enemy;
\r
483 weapon_number = stats.weapon;
\r
485 if (!weapon_number)
\r
486 weapon_number = stats.switchweapon;
\r
488 if (!weapon_number)
\r
489 weapon_number = stats.cnt;
\r
491 if(stats.cvar_cl_accuracy_data_share && stats.stats_fired[weapon_number - 1])
\r
492 replacement = ftos(bound(0, floor(100 * stats.stats_hit[weapon_number - 1] / stats.stats_fired[weapon_number - 1]), 100));
\r
494 replacement = "~"; // or something to indicate NULL, not available
\r
497 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
\r
498 p = p + strlen(replacement);
\r
503 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
\r
504 return (value == 0) ? FALSE : TRUE;
\r
512 0: sends the request
\r
513 >0: receives a cvar from name=argv(f) value=argv(f+1)
\r
515 void GetCvars_handleString(string thisname, float f, .string field, string name)
\r
520 strunzone(self.field);
\r
521 self.field = string_null;
\r
525 if (thisname == name)
\r
528 strunzone(self.field);
\r
529 self.field = strzone(argv(f + 1));
\r
533 stuffcmd(self, strcat("sendcvar ", name, "\n"));
\r
535 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
\r
537 GetCvars_handleString(thisname, f, field, name);
\r
538 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
\r
539 if (thisname == name)
\r
542 s = func(strcat1(self.field));
\r
543 if (s != self.field)
\r
545 strunzone(self.field);
\r
546 self.field = strzone(s);
\r
550 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
\r
557 if (thisname == name)
\r
558 self.field = stof(argv(f + 1));
\r
561 stuffcmd(self, strcat("sendcvar ", name, "\n"));
\r
563 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
\r
570 if (thisname == name)
\r
574 self.field = stof(argv(f + 1));
\r
583 stuffcmd(self, strcat("sendcvar ", name, "\n"));
\r
586 string W_FixWeaponOrder_ForceComplete(string s);
\r
587 string W_FixWeaponOrder_AllowIncomplete(string s);
\r
588 float w_getbestweapon(entity e);
\r
589 void GetCvars(float f)
\r
593 s = strcat1(argv(f));
\r
594 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
\r
595 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
\r
596 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
\r
597 GetCvars_handleString(s, f, cvar_g_voretournamentversion, "g_voretournamentversion");
\r
598 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
\r
599 GetCvars_handleFloat(s, f, cvar_cl_clippedspectating, "cl_clippedspectating");
\r
600 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
\r
601 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
\r
602 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
\r
603 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
\r
604 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
\r
605 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
\r
606 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
\r
607 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
\r
608 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
\r
609 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
\r
610 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
\r
611 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
\r
612 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
\r
613 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
\r
614 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
\r
615 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
\r
616 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
\r
617 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
\r
618 GetCvars_handleFloat(s, f, cvar_chase_active, "chase_active");
\r
619 GetCvars_handleFloat(s, f, cvar_cl_vore_stomachmodel, "cl_vore_stomachmodel");
\r
620 GetCvars_handleFloat(s, f, cvar_cl_vore_swallowmodel, "cl_vore_swallowmodel");
\r
621 GetCvars_handleFloat(s, f, cvar_cl_vore_autodigest, "cl_vore_autodigest");
\r
623 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
\r
624 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
\r
626 #ifdef ALLOW_FORCEMODELS
\r
627 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
\r
628 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromvoretournament, "cl_forceplayermodelsfromvoretournament");
\r
630 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
\r
632 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
\r
635 if (s == "cl_weaponpriority")
\r
636 self.switchweapon = w_getbestweapon(self);
\r
640 float fexists(string f)
\r
643 fh = fopen(f, FILE_READ);
\r
650 void backtrace(string msg)
\r
653 dev = cvar("developer");
\r
654 war = cvar("prvm_backtraceforwarnings");
\r
655 cvar_set("developer", "1");
\r
656 cvar_set("prvm_backtraceforwarnings", "1");
\r
658 print("--- CUT HERE ---\nWARNING: ");
\r
661 remove(world); // isn't there any better way to cause a backtrace?
\r
662 print("\n--- CUT UNTIL HERE ---\n");
\r
663 cvar_set("developer", ftos(dev));
\r
664 cvar_set("prvm_backtraceforwarnings", ftos(war));
\r
667 string Team_ColorCode(float teamid)
\r
669 if (teamid == COLOR_TEAM1)
\r
671 else if (teamid == COLOR_TEAM2)
\r
673 else if (teamid == COLOR_TEAM3)
\r
675 else if (teamid == COLOR_TEAM4)
\r
681 string Team_ColorName(float t)
\r
683 // fixme: Search for team entities and get their .netname's!
\r
684 if (t == COLOR_TEAM1)
\r
686 if (t == COLOR_TEAM2)
\r
688 if (t == COLOR_TEAM3)
\r
690 if (t == COLOR_TEAM4)
\r
695 string Team_ColorNameLowerCase(float t)
\r
697 // fixme: Search for team entities and get their .netname's!
\r
698 if (t == COLOR_TEAM1)
\r
700 if (t == COLOR_TEAM2)
\r
702 if (t == COLOR_TEAM3)
\r
704 if (t == COLOR_TEAM4)
\r
709 float ColourToNumber(string team_colour)
\r
711 if (team_colour == "red")
\r
712 return COLOR_TEAM1;
\r
714 if (team_colour == "blue")
\r
715 return COLOR_TEAM2;
\r
717 if (team_colour == "yellow")
\r
718 return COLOR_TEAM3;
\r
720 if (team_colour == "pink")
\r
721 return COLOR_TEAM4;
\r
723 if (team_colour == "auto")
\r
729 float NumberToTeamNumber(float number)
\r
732 return COLOR_TEAM1;
\r
735 return COLOR_TEAM2;
\r
738 return COLOR_TEAM3;
\r
741 return COLOR_TEAM4;
\r
746 #define CENTERPRIO_POINT 1
\r
747 #define CENTERPRIO_SPAM 2
\r
748 #define CENTERPRIO_VOTE 4
\r
749 #define CENTERPRIO_NORMAL 5
\r
750 #define CENTERPRIO_SHIELDING 7
\r
751 #define CENTERPRIO_MAPVOTE 9
\r
752 #define CENTERPRIO_IDLEKICK 50
\r
753 #define CENTERPRIO_ADMIN 99
\r
754 .float centerprint_priority;
\r
755 .float centerprint_expires;
\r
756 void centerprint_atprio(entity e, float prio, string s)
\r
758 if (intermission_running)
\r
759 if (prio < CENTERPRIO_MAPVOTE)
\r
761 if (time > e.centerprint_expires)
\r
762 e.centerprint_priority = 0;
\r
763 if (prio >= e.centerprint_priority)
\r
765 e.centerprint_priority = prio;
\r
766 if (timeoutStatus == 2)
\r
767 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
\r
769 e.centerprint_expires = time + e.cvar_scr_centertime;
\r
770 centerprint_builtin(e, s);
\r
773 void centerprint_expire(entity e, float prio)
\r
775 if (prio == e.centerprint_priority)
\r
777 e.centerprint_priority = 0;
\r
778 centerprint_builtin(e, "");
\r
781 void centerprint(entity e, string s)
\r
783 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
\r
786 // decolorizes and team colors the player name when needed
\r
787 string playername(entity p)
\r
790 if (teams_matter && !intermission_running && p.classname == "player")
\r
792 t = Team_ColorCode(p.team);
\r
793 return strcat(t, strdecolorize(p.netname));
\r
799 vector randompos(vector m1, vector m2)
\r
803 v_x = m2_x * random() + m1_x;
\r
804 v_y = m2_y * random() + m1_y;
\r
805 v_z = m2_z * random() + m1_z;
\r
809 float g_pickup_fuel;
\r
810 float g_pickup_fuel_jetpack;
\r
811 float g_pickup_fuel_max;
\r
812 float g_pickup_armorsmall;
\r
813 float g_pickup_armorsmall_max;
\r
814 float g_pickup_armormedium;
\r
815 float g_pickup_armormedium_max;
\r
816 float g_pickup_armorbig;
\r
817 float g_pickup_armorbig_max;
\r
818 float g_pickup_armorlarge;
\r
819 float g_pickup_armorlarge_max;
\r
820 float g_pickup_healthsmall;
\r
821 float g_pickup_healthsmall_max;
\r
822 float g_pickup_healthsmall_consumable;
\r
823 float g_pickup_healthmedium;
\r
824 float g_pickup_healthmedium_max;
\r
825 float g_pickup_healthmedium_consumable;
\r
826 float g_pickup_healthlarge;
\r
827 float g_pickup_healthlarge_max;
\r
828 float g_pickup_healthlarge_consumable;
\r
829 float g_pickup_healthmega;
\r
830 float g_pickup_healthmega_max;
\r
831 float g_pickup_healthmega_consumable;
\r
832 float g_weaponspeedfactor;
\r
833 float g_weaponratefactor;
\r
834 float g_weapondamagefactor;
\r
835 float g_weaponforcefactor;
\r
836 float g_weaponspreadfactor;
\r
838 float start_weapons;
\r
840 float start_ammo_fuel;
\r
841 float start_health;
\r
842 float start_armorvalue;
\r
843 float warmup_start_weapons;
\r
844 float warmup_start_ammo_fuel;
\r
845 float warmup_start_health;
\r
846 float warmup_start_armorvalue;
\r
847 float g_weapon_stay;
\r
848 float g_ghost_items;
\r
850 entity get_weaponinfo(float w);
\r
852 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
\r
854 var float i = weaponinfo.weapon;
\r
859 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
\r
861 if (t < 0) // "default" weapon selection
\r
863 if(g_rpg) // no start weapons in RPG by default
\r
866 t = (i == WEP_GRABBER);
\r
872 void readplayerstartcvars()
\r
877 // initialize starting values for players
\r
880 start_health = cvar("g_balance_health_start");
\r
881 start_armorvalue = cvar("g_balance_armor_start");
\r
885 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
\r
886 start_health = cvar("g_lms_start_health");
\r
887 start_armorvalue = cvar("g_lms_start_armor");
\r
889 else if (cvar("g_use_ammunition"))
\r
891 start_ammo_fuel = cvar("g_start_ammo_fuel");
\r
895 start_ammo_fuel = cvar("g_pickup_fuel_max");
\r
896 start_items |= IT_UNLIMITED_AMMO;
\r
899 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
901 e = get_weaponinfo(i);
\r
902 if(want_weapon("g_start_weapon_", e, FALSE))
\r
904 start_weapons |= e.weapons;
\r
905 weapon_action(e.weapon, WR_PRECACHE);
\r
911 warmup_start_ammo_fuel = start_ammo_fuel;
\r
912 warmup_start_health = start_health;
\r
913 warmup_start_armorvalue = start_armorvalue;
\r
914 warmup_start_weapons = start_weapons;
\r
916 if (cvar("g_use_ammunition"))
\r
918 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
\r
920 warmup_start_health = cvar("g_warmup_start_health");
\r
921 warmup_start_armorvalue = cvar("g_warmup_start_armor");
\r
922 warmup_start_weapons = 0;
\r
923 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
925 e = get_weaponinfo(i);
\r
926 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
\r
928 warmup_start_weapons |= e.weapons;
\r
929 weapon_action(e.weapon, WR_PRECACHE);
\r
936 start_items |= IT_FUEL_REGEN;
\r
937 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
938 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
942 start_items |= IT_JETPACK;
\r
944 if (g_weapon_stay == 2)
\r
946 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
\r
947 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
\r
950 start_ammo_fuel = max(0, start_ammo_fuel);
\r
952 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
\r
956 float g_bugrigs_planar_movement;
\r
957 float g_bugrigs_planar_movement_car_jumping;
\r
958 float g_bugrigs_reverse_spinning;
\r
959 float g_bugrigs_reverse_speeding;
\r
960 float g_bugrigs_reverse_stopping;
\r
961 float g_bugrigs_air_steering;
\r
962 float g_bugrigs_angle_smoothing;
\r
963 float g_bugrigs_friction_floor;
\r
964 float g_bugrigs_friction_brake;
\r
965 float g_bugrigs_friction_air;
\r
966 float g_bugrigs_accel;
\r
967 float g_bugrigs_speed_ref;
\r
968 float g_bugrigs_speed_pow;
\r
969 float g_bugrigs_steer;
\r
971 float g_touchexplode;
\r
972 float g_touchexplode_radius;
\r
973 float g_touchexplode_damage;
\r
974 float g_touchexplode_edgedamage;
\r
975 float g_touchexplode_force;
\r
977 float sv_autotaunt;
\r
980 float sv_pitch_min;
\r
981 float sv_pitch_max;
\r
982 float sv_pitch_fixyaw;
\r
984 float sv_accuracy_data_share;
\r
986 void readlevelcvars(void)
\r
988 g_bugrigs = cvar("g_bugrigs");
\r
989 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
\r
990 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
\r
991 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
\r
992 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
\r
993 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
\r
994 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
\r
995 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
\r
996 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
\r
997 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
\r
998 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
\r
999 g_bugrigs_accel = cvar("g_bugrigs_accel");
\r
1000 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
\r
1001 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
\r
1002 g_bugrigs_steer = cvar("g_bugrigs_steer");
\r
1004 g_touchexplode = cvar("g_touchexplode");
\r
1005 g_touchexplode_radius = cvar("g_touchexplode_radius");
\r
1006 g_touchexplode_damage = cvar("g_touchexplode_damage");
\r
1007 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
\r
1008 g_touchexplode_force = cvar("g_touchexplode_force");
\r
1010 #ifdef ALLOW_FORCEMODELS
\r
1011 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
\r
1014 sv_clones = cvar("sv_clones");
\r
1015 sv_gentle = cvar("sv_gentle");
\r
1016 sv_foginterval = cvar("sv_foginterval");
\r
1017 g_cloaked = cvar("g_cloaked");
\r
1018 g_jump_grunt = cvar("g_jump_grunt");
\r
1019 g_footsteps = cvar("g_footsteps");
\r
1020 g_jetpack = cvar("g_jetpack");
\r
1021 g_midair = cvar("g_midair");
\r
1022 g_norecoil = cvar("g_norecoil");
\r
1023 g_vampire = cvar("g_vampire");
\r
1024 g_bloodloss = cvar("g_bloodloss");
\r
1025 sv_maxidle = cvar("sv_maxidle");
\r
1026 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
\r
1027 sv_pogostick = cvar("sv_pogostick");
\r
1028 sv_doublejump = cvar("sv_doublejump");
\r
1029 g_ctf_reverse = cvar("g_ctf_reverse");
\r
1030 sv_autotaunt = cvar("sv_autotaunt");
\r
1031 sv_taunt = cvar("sv_taunt");
\r
1033 inWarmupStage = cvar("g_warmup");
\r
1034 g_warmup_limit = cvar("g_warmup_limit");
\r
1035 g_warmup_allguns = cvar("g_warmup_allguns");
\r
1036 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
\r
1038 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || g_rpg || cvar("g_campaign"))
\r
1039 inWarmupStage = 0; // these modes cannot work together, sorry
\r
1041 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
\r
1042 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
\r
1043 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
\r
1044 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
\r
1045 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
\r
1046 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
\r
1047 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
\r
1048 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
\r
1049 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
\r
1050 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
\r
1051 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
\r
1052 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
\r
1054 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
\r
1055 g_weaponratefactor = cvar("g_weaponratefactor");
\r
1056 g_weapondamagefactor = cvar("g_weapondamagefactor");
\r
1057 g_weaponforcefactor = cvar("g_weaponforcefactor");
\r
1058 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
\r
1060 g_pickup_fuel = cvar("g_pickup_fuel");
\r
1061 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
\r
1062 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
\r
1063 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
\r
1064 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
\r
1065 g_pickup_armormedium = cvar("g_pickup_armormedium");
\r
1066 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
\r
1067 g_pickup_armorbig = cvar("g_pickup_armorbig");
\r
1068 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
\r
1069 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
\r
1070 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
\r
1071 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
\r
1072 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
\r
1073 g_pickup_healthsmall_consumable = cvar("g_pickup_healthsmall_consumable");
\r
1074 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
\r
1075 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
\r
1076 g_pickup_healthmedium_consumable = cvar("g_pickup_healthmedium_consumable");
\r
1077 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
\r
1078 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
\r
1079 g_pickup_healthlarge_consumable = cvar("g_pickup_healthlarge_consumable");
\r
1080 g_pickup_healthmega = cvar("g_pickup_healthmega");
\r
1081 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
\r
1082 g_pickup_healthmega_consumable = cvar("g_pickup_healthmega_consumable");
\r
1084 g_weapon_stay = cvar("g_weapon_stay");
\r
1086 if (!g_weapon_stay && (cvar("deathmatch") == 2))
\r
1087 g_weapon_stay = 1;
\r
1089 g_ghost_items = cvar("g_ghost_items");
\r
1091 if(g_ghost_items >= 1)
\r
1092 g_ghost_items = 0.25; // default alpha value
\r
1094 if not(inWarmupStage && !g_ca && !g_rpg)
\r
1095 game_starttime = cvar("g_start_delay");
\r
1097 sv_pitch_min = cvar("sv_pitch_min");
\r
1098 sv_pitch_max = cvar("sv_pitch_max");
\r
1099 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
\r
1101 sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share"));
\r
1103 readplayerstartcvars();
\r
1107 // TODO sound pack system
\r
1110 string precache_sound_builtin (string s) = #19;
\r
1111 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1112 string precache_sound(string s)
\r
1114 return precache_sound_builtin(strcat(soundpack, s));
\r
1116 void play2(entity e, string filename)
\r
1118 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
\r
1120 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1122 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
\r
1126 // Sound functions
\r
1127 string precache_sound (string s) = #19;
\r
1128 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1129 float precache_sound_index (string s) = #19;
\r
1131 #define SND_VOLUME 1
\r
1132 #define SND_ATTENUATION 2
\r
1133 #define SND_LARGEENTITY 8
\r
1134 #define SND_LARGESOUND 16
\r
1135 #define SND_SPEEDUSHORT4000 32
\r
1137 float sound_allowed(float dest, entity e)
\r
1139 // sounds from world may always pass
\r
1142 if (e.classname == "body")
\r
1144 if (e.owner && e.owner != e)
\r
1149 // sounds to self may always pass
\r
1150 if (dest == MSG_ONE)
\r
1151 if (e == msg_entity)
\r
1153 // sounds by players can be removed
\r
1154 if (cvar("bot_sound_monopoly"))
\r
1155 if (clienttype(e) == CLIENTTYPE_REAL)
\r
1157 // anything else may pass
\r
1161 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1163 if (!sound_allowed(MSG_BROADCAST, e))
\r
1165 sound_builtin(e, chan, samp, vol, atten);
\r
1167 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten, float spd)
\r
1171 if (!sound_allowed(dest, e))
\r
1174 entno = num_for_edict(e);
\r
1175 idx = precache_sound_index(samp);
\r
1180 atten = floor(atten * 64);
\r
1181 vol = floor(vol * 255);
\r
1184 sflags |= SND_VOLUME;
\r
1186 sflags |= SND_ATTENUATION;
\r
1188 sflags |= SND_SPEEDUSHORT4000;
\r
1189 if (entno >= 8192)
\r
1190 sflags |= SND_LARGEENTITY;
\r
1192 sflags |= SND_LARGESOUND;
\r
1194 WriteByte(dest, SVC_SOUND);
\r
1195 WriteByte(dest, sflags);
\r
1196 if (sflags & SND_VOLUME)
\r
1197 WriteByte(dest, vol);
\r
1198 if (sflags & SND_ATTENUATION)
\r
1199 WriteByte(dest, atten);
\r
1200 if(sflags & SND_SPEEDUSHORT4000)
\r
1201 WriteShort(dest, spd * 4000);
\r
1202 if (sflags & SND_LARGEENTITY)
\r
1204 WriteShort(dest, entno);
\r
1205 WriteByte(dest, chan);
\r
1209 WriteShort(dest, entno * 8 + chan);
\r
1211 if (sflags & SND_LARGESOUND)
\r
1212 WriteShort(dest, idx);
\r
1214 WriteByte(dest, idx);
\r
1216 WriteCoord(dest, o_x);
\r
1217 WriteCoord(dest, o_y);
\r
1218 WriteCoord(dest, o_z);
\r
1220 void soundto(float dest, entity e, float chan, string samp, float vol, float atten, float spd)
\r
1224 if (!sound_allowed(dest, e))
\r
1227 o = e.origin + 0.5 * (e.mins + e.maxs);
\r
1228 soundtoat(dest, e, o, chan, samp, vol, atten, spd);
\r
1230 void soundat(entity e, vector o, float chan, string samp, float vol, float atten, float spd)
\r
1232 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten, spd);
\r
1234 void stopsoundto(float dest, entity e, float chan)
\r
1238 if (!sound_allowed(dest, e))
\r
1241 entno = num_for_edict(e);
\r
1243 if (entno >= 8192)
\r
1245 float idx, sflags;
\r
1246 idx = precache_sound_index("misc/null.wav");
\r
1247 sflags = SND_LARGEENTITY;
\r
1249 sflags |= SND_LARGESOUND;
\r
1250 WriteByte(dest, SVC_SOUND);
\r
1251 WriteByte(dest, sflags);
\r
1252 WriteShort(dest, entno);
\r
1253 WriteByte(dest, chan);
\r
1254 if (sflags & SND_LARGESOUND)
\r
1255 WriteShort(dest, idx);
\r
1257 WriteByte(dest, idx);
\r
1258 WriteCoord(dest, e.origin_x);
\r
1259 WriteCoord(dest, e.origin_y);
\r
1260 WriteCoord(dest, e.origin_z);
\r
1264 WriteByte(dest, SVC_STOPSOUND);
\r
1265 WriteShort(dest, entno * 8 + chan);
\r
1268 void stopsound(entity e, float chan)
\r
1270 if (!sound_allowed(MSG_BROADCAST, e))
\r
1273 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
\r
1274 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
\r
1277 void play2(entity e, string filename)
\r
1279 //stuffcmd(e, strcat("play2 ", filename, "\n"));
\r
1280 if (clienttype(e) == CLIENTTYPE_REAL)
\r
1283 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE, 0);
\r
1287 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
\r
1289 float spamsound(entity e, float chan, string samp, float vol, float atten)
\r
1291 if (!sound_allowed(MSG_BROADCAST, e))
\r
1294 if (time > e.spamtime)
\r
1296 e.spamtime = time;
\r
1297 sound(e, chan, samp, vol, atten);
\r
1303 void play2team(float t, string filename)
\r
1305 local entity head;
\r
1307 if (cvar("bot_sound_monopoly"))
\r
1310 FOR_EACH_REALPLAYER(head)
\r
1312 if (head.team == t)
\r
1313 play2(head, filename);
\r
1317 void play2all(string samp)
\r
1319 if (cvar("bot_sound_monopoly"))
\r
1322 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
\r
1325 void PrecachePlayerSounds(string f);
\r
1326 void precache_all_models(string pattern)
\r
1328 float globhandle, i, n;
\r
1331 globhandle = search_begin(pattern, TRUE, FALSE);
\r
1332 if (globhandle < 0)
\r
1334 n = search_getsize(globhandle);
\r
1335 for (i = 0; i < n; ++i)
\r
1337 //print(search_getfilename(globhandle, i), "\n");
\r
1338 f = search_getfilename(globhandle, i);
\r
1339 precache_model(f);
\r
1340 PrecachePlayerSounds(strcat(f, ".sounds"));
\r
1342 search_end(globhandle);
\r
1347 // gamemode related things
\r
1348 precache_model ("models/misc/chatbubble.spr");
\r
1350 // used by the waypoint editor
\r
1351 precache_model ("models/rune.mdl");
\r
1353 #ifdef TTURRETS_ENABLED
\r
1354 if (cvar("g_turrets"))
\r
1355 turrets_precash();
\r
1358 // Precache all player models if desired
\r
1359 if (cvar("sv_precacheplayermodels"))
\r
1361 PrecachePlayerSounds("sound/player/default.sounds");
\r
1362 precache_all_models("models/player/*.zym");
\r
1363 precache_all_models("models/player/*.dpm");
\r
1364 precache_all_models("models/player/*.md3");
\r
1365 precache_all_models("models/player/*.psk");
\r
1366 precache_all_models("models/player/*.iqm");
\r
1369 if (cvar("sv_defaultcharacter"))
\r
1372 s = cvar_string("sv_defaultplayermodel_red");
\r
1375 precache_model(s);
\r
1376 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1378 s = cvar_string("sv_defaultplayermodel_blue");
\r
1381 precache_model(s);
\r
1382 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1384 s = cvar_string("sv_defaultplayermodel_yellow");
\r
1387 precache_model(s);
\r
1388 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1390 s = cvar_string("sv_defaultplayermodel_pink");
\r
1393 precache_model(s);
\r
1394 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1396 s = cvar_string("sv_defaultplayermodel");
\r
1399 precache_model(s);
\r
1400 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1406 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
\r
1407 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
\r
1408 if(cvar("g_healthsize"))
\r
1409 precache_sound("misc/macro_footstep.wav");
\r
1412 // gore and miscellaneous sounds
\r
1413 //precache_sound ("misc/h2ohit.wav");
\r
1414 precache_model ("models/grabber.md3");
\r
1415 precache_sound ("misc/armorimpact.wav");
\r
1416 precache_sound ("misc/bodyimpact1.wav");
\r
1417 precache_sound ("misc/bodyimpact2.wav");
\r
1418 precache_sound ("misc/gib.wav");
\r
1419 precache_sound ("misc/gib_splat01.wav");
\r
1420 precache_sound ("misc/gib_splat02.wav");
\r
1421 precache_sound ("misc/gib_splat03.wav");
\r
1422 precache_sound ("misc/gib_splat04.wav");
\r
1423 precache_sound ("misc/hit.wav");
\r
1424 precache_sound ("misc/typehit.wav");
\r
1425 precache_sound ("misc/unavailable.wav");
\r
1426 precache_sound ("misc/forbidden.wav");
\r
1427 precache_sound ("misc/beep.wav");
\r
1428 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
\r
1429 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
\r
1430 if(cvar("g_healthsize"))
\r
1431 precache_sound("misc/macro_hitground.wav");
\r
1432 precache_sound ("misc/null.wav");
\r
1433 precache_sound ("misc/spawn.wav");
\r
1434 precache_sound ("misc/talk.wav");
\r
1435 precache_sound ("misc/teleport.wav");
\r
1436 precache_sound ("misc/poweroff.wav");
\r
1437 precache_sound ("player/lava.wav");
\r
1438 precache_sound ("player/slime.wav");
\r
1439 precache_sound ("player/digest.wav");
\r
1440 precache_sound ("misc/health_regen.wav");
\r
1441 precache_sound ("misc/armor_regen.wav");
\r
1442 precache_sound ("misc/power_fail.wav");
\r
1445 precache_sound ("misc/jetpack_fly.wav");
\r
1447 precache_model ("models/sprites/0.spr32");
\r
1448 precache_model ("models/sprites/1.spr32");
\r
1449 precache_model ("models/sprites/2.spr32");
\r
1450 precache_model ("models/sprites/3.spr32");
\r
1451 precache_model ("models/sprites/4.spr32");
\r
1452 precache_model ("models/sprites/5.spr32");
\r
1453 precache_model ("models/sprites/6.spr32");
\r
1454 precache_model ("models/sprites/7.spr32");
\r
1455 precache_model ("models/sprites/8.spr32");
\r
1456 precache_model ("models/sprites/9.spr32");
\r
1457 precache_model ("models/sprites/10.spr32");
\r
1459 // common weapon precaches
\r
1460 precache_sound ("weapons/weapon_switch.wav");
\r
1461 precache_sound ("weapons/weaponpickup.wav");
\r
1462 precache_model ("models/weapons/w_displaydigit.md3");
\r
1465 for(i = 0; i < 8; i += 1)
\r
1466 precache_sound (strcat("weapons/hit", ftos(i), ".wav"));
\r
1468 if (cvar("sv_precacheweapons"))
\r
1470 //precache weapon models/sounds
\r
1473 while (wep <= WEP_LAST)
\r
1475 weapon_action(wep, WR_PRECACHE);
\r
1480 precache_model("models/elaser.mdl");
\r
1481 precache_model("models/laser.mdl");
\r
1482 precache_model("models/ebomb.mdl");
\r
1485 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
\r
1487 if (!self.noise && self.music) // quake 3 uses the music field
\r
1488 self.noise = self.music;
\r
1490 // plays music for the level if there is any
\r
1493 precache_sound (self.noise);
\r
1494 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
\r
1499 // sorry, but using \ in macros breaks line numbers
\r
1500 #define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname
\r
1501 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
\r
1502 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
\r
1504 // WARNING: this kills the trace globals
\r
1505 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
\r
1506 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
\r
1508 #define INITPRIO_FIRST 0
\r
1509 #define INITPRIO_GAMETYPE 0
\r
1510 #define INITPRIO_GAMETYPE_FALLBACK 1
\r
1511 #define INITPRIO_CVARS 5
\r
1512 #define INITPRIO_FINDTARGET 10
\r
1513 #define INITPRIO_DROPTOFLOOR 20
\r
1514 #define INITPRIO_SETLOCATION 90
\r
1515 #define INITPRIO_LINKDOORS 91
\r
1516 #define INITPRIO_LAST 99
\r
1518 .void(void) initialize_entity;
\r
1519 .float initialize_entity_order;
\r
1520 .entity initialize_entity_next;
\r
1521 entity initialize_entity_first;
\r
1523 void make_safe_for_remove(entity e)
\r
1525 if (e.initialize_entity)
\r
1528 for (ent = initialize_entity_first; ent; )
\r
1530 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
\r
1532 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
\r
1533 // skip it in linked list
\r
1536 prev.initialize_entity_next = ent.initialize_entity_next;
\r
1537 ent = prev.initialize_entity_next;
\r
1541 initialize_entity_first = ent.initialize_entity_next;
\r
1542 ent = initialize_entity_first;
\r
1548 ent = ent.initialize_entity_next;
\r
1554 void objerror(string s)
\r
1556 make_safe_for_remove(self);
\r
1557 objerror_builtin(s);
\r
1560 void remove_unsafely(entity e)
\r
1562 remove_builtin(e);
\r
1565 void remove_safely(entity e)
\r
1567 make_safe_for_remove(e);
\r
1568 remove_builtin(e);
\r
1571 void InitializeEntity(entity e, void(void) func, float order)
\r
1575 if (!e || e.initialize_entity)
\r
1577 // make a proxy initializer entity
\r
1581 e.classname = "initialize_entity";
\r
1585 e.initialize_entity = func;
\r
1586 e.initialize_entity_order = order;
\r
1588 cur = initialize_entity_first;
\r
1591 if (!cur || cur.initialize_entity_order > order)
\r
1593 // insert between prev and cur
\r
1595 prev.initialize_entity_next = e;
\r
1597 initialize_entity_first = e;
\r
1598 e.initialize_entity_next = cur;
\r
1602 cur = cur.initialize_entity_next;
\r
1605 void InitializeEntitiesRun()
\r
1607 entity startoflist;
\r
1608 startoflist = initialize_entity_first;
\r
1609 initialize_entity_first = world;
\r
1610 for (self = startoflist; self; )
\r
1613 var void(void) func;
\r
1614 e = self.initialize_entity_next;
\r
1615 func = self.initialize_entity;
\r
1616 self.initialize_entity_order = 0;
\r
1617 self.initialize_entity = func_null;
\r
1618 self.initialize_entity_next = world;
\r
1619 if (self.classname == "initialize_entity")
\r
1622 e_old = self.enemy;
\r
1623 remove_builtin(self);
\r
1626 //dprint("Delayed initialization: ", self.classname, "\n");
\r
1632 .float uncustomizeentityforclient_set;
\r
1633 .void(void) uncustomizeentityforclient;
\r
1634 void(void) SUB_Nullpointer = #0;
\r
1635 void UncustomizeEntitiesRun()
\r
1639 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
\r
1640 self.uncustomizeentityforclient();
\r
1643 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
\r
1645 e.customizeentityforclient = customizer;
\r
1646 e.uncustomizeentityforclient = uncustomizer;
\r
1647 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
\r
1650 .float nottargeted;
\r
1651 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
\r
1653 void() SUB_Remove;
\r
1654 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
\r
1658 if (e.classname == "")
\r
1659 e.classname = "net_linked";
\r
1661 if (e.model == "" || self.modelindex == 0)
\r
1665 setmodel(e, "null");
\r
1666 setsize(e, mi, ma);
\r
1669 e.SendEntity = sendfunc;
\r
1670 e.SendFlags = 0xFFFFFF;
\r
1673 e.effects |= EF_NODEPTHTEST;
\r
1677 e.nextthink = time + dt;
\r
1678 e.think = SUB_Remove;
\r
1682 void adaptor_think2touch()
\r
1691 void adaptor_think2use()
\r
1696 activator = world;
\r
1703 // deferred dropping
\r
1704 void DropToFloor_Handler()
\r
1706 droptofloor_builtin();
\r
1707 self.dropped_origin = self.origin;
\r
1710 void droptofloor()
\r
1712 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
\r
1717 float trace_hits_box_a0, trace_hits_box_a1;
\r
1719 float trace_hits_box_1d(float end, float thmi, float thma)
\r
1723 // just check if x is in range
\r
1731 // do the trace with respect to x
\r
1732 // 0 -> end has to stay in thmi -> thma
\r
1733 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
\r
1734 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
\r
1735 if (trace_hits_box_a0 > trace_hits_box_a1)
\r
1741 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
\r
1746 // now it is a trace from 0 to end
\r
1748 trace_hits_box_a0 = 0;
\r
1749 trace_hits_box_a1 = 1;
\r
1751 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
\r
1753 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
\r
1755 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
\r
1761 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
\r
1763 return trace_hits_box(start, end, thmi - ma, thma - mi);
\r
1766 float SUB_NoImpactCheck()
\r
1768 // zero hitcontents = this is not the real impact, but either the
\r
1769 // mirror-impact of something hitting the projectile instead of the
\r
1770 // projectile hitting the something, or a touchareagrid one. Neither of
\r
1771 // these stop the projectile from moving, so...
\r
1772 if(trace_dphitcontents == 0)
\r
1774 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
\r
1777 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1779 if (other == world && self.size != '0 0 0')
\r
1782 tic = self.velocity * sys_frametime;
\r
1783 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
\r
1784 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
\r
1785 if (trace_fraction >= 1)
\r
1787 dprint("Odd... did not hit...?\n");
\r
1789 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1791 dprint("Detected and prevented the sky-grapple bug.\n");
\r
1799 #define SUB_OwnerCheck() (other && (other == self.owner))
\r
1801 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
\r
1803 if(SUB_OwnerCheck())
\r
1805 if(SUB_NoImpactCheck())
\r
1810 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
\r
1811 UpdateCSQCProjectileNextFrame(self);
\r
1814 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
\r
1816 float MAX_IPBAN_URIS = 16;
\r
1818 float URI_GET_DISCARD = 0;
\r
1819 float URI_GET_IPBAN = 1;
\r
1820 float URI_GET_IPBAN_END = 16;
\r
1822 void URI_Get_Callback(float id, float status, string data)
\r
1824 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
\r
1826 dprint("\nEnd of data.\n");
\r
1828 if (id == URI_GET_DISCARD)
\r
1832 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
\r
1834 // online ban list
\r
1835 OnlineBanList_URI_Get_Callback(id, status, data);
\r
1839 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
\r
1843 void print_to(entity e, string s)
\r
1846 sprint(e, strcat(s, "\n"));
\r
1851 string getrecords(float page) // 50 records per page
\r
1865 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1867 if (MapInfo_Get_ByID(i))
\r
1869 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
\r
1872 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
\r
1873 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
\r
1881 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1883 if (MapInfo_Get_ByID(i))
\r
1885 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
\r
1888 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
\r
1889 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1897 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1899 if (MapInfo_Get_ByID(i))
\r
1901 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
\r
1904 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
\r
1905 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1911 MapInfo_ClearTemps();
\r
1913 if (s == "" && page == 0)
\r
1914 return "No records are available on this server.\n";
\r
1919 string getrankings()
\r
1930 map = GetMapname();
\r
1932 for (i = 1; i <= RANKINGS_CNT; ++i)
\r
1934 t = race_GetTime(i);
\r
1937 n = race_GetName(i);
\r
1938 p = race_PlaceName(i);
\r
1939 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
\r
1942 MapInfo_ClearTemps();
\r
1945 return strcat("No records are available for the map: ", map, "\n");
\r
1947 return strcat("Records for ", map, ":\n", s);
\r
1950 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
\r
1953 vector start, org, delta, end, enddown, mstart;
\r
1955 m = e.dphitcontentsmask;
\r
1956 e.dphitcontentsmask = goodcontents | badcontents;
\r
1959 delta = world.maxs - world.mins;
\r
1961 for (i = 0; i < attempts; ++i)
\r
1963 start_x = org_x + random() * delta_x;
\r
1964 start_y = org_y + random() * delta_y;
\r
1965 start_z = org_z + random() * delta_z;
\r
1967 // rule 1: start inside world bounds, and outside
\r
1968 // solid, and don't start from somewhere where you can
\r
1969 // fall down to evil
\r
1970 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
1971 if (trace_fraction >= 1)
\r
1973 if (trace_startsolid)
\r
1975 if (trace_dphitcontents & badcontents)
\r
1977 if (trace_dphitq3surfaceflags & badsurfaceflags)
\r
1980 // rule 2: if we are too high, lower the point
\r
1981 if (trace_fraction * delta_z > maxaboveground)
\r
1982 start = trace_endpos + '0 0 1' * maxaboveground;
\r
1983 enddown = trace_endpos;
\r
1985 // rule 3: make sure we aren't outside the map. This only works
\r
1986 // for somewhat well formed maps. A good rule of thumb is that
\r
1987 // the map should have a convex outside hull.
\r
1988 // these can be traceLINES as we already verified the starting box
\r
1989 mstart = start + 0.5 * (e.mins + e.maxs);
\r
1990 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1991 if (trace_fraction >= 1)
\r
1993 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1994 if (trace_fraction >= 1)
\r
1996 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
\r
1997 if (trace_fraction >= 1)
\r
1999 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
\r
2000 if (trace_fraction >= 1)
\r
2002 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
2003 if (trace_fraction >= 1)
\r
2006 // find a random vector to "look at"
\r
2007 end_x = org_x + random() * delta_x;
\r
2008 end_y = org_y + random() * delta_y;
\r
2009 end_z = org_z + random() * delta_z;
\r
2010 end = start + normalize(end - start) * vlen(delta);
\r
2012 // rule 4: start TO end must not be too short
\r
2013 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
\r
2014 if (trace_startsolid)
\r
2016 if (trace_fraction < minviewdistance / vlen(delta))
\r
2019 // rule 5: don't want to look at sky
\r
2020 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
\r
2023 // rule 6: we must not end up in trigger_hurt
\r
2024 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
\r
2026 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
\r
2033 e.dphitcontentsmask = m;
\r
2037 setorigin(e, start);
\r
2038 e.angles = vectoangles(end - start);
\r
2039 dprint("Needed ", ftos(i + 1), " attempts\n");
\r
2046 float zcurveparticles_effectno;
\r
2047 vector zcurveparticles_start;
\r
2048 float zcurveparticles_spd;
\r
2050 void endzcurveparticles()
\r
2052 if(zcurveparticles_effectno)
\r
2055 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
\r
2057 zcurveparticles_effectno = 0;
\r
2060 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
\r
2062 spd = bound(0, floor(spd / 16), 32767);
\r
2063 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
\r
2065 endzcurveparticles();
\r
2066 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
\r
2067 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
\r
2068 WriteShort(MSG_BROADCAST, effectno);
\r
2069 WriteCoord(MSG_BROADCAST, start_x);
\r
2070 WriteCoord(MSG_BROADCAST, start_y);
\r
2071 WriteCoord(MSG_BROADCAST, start_z);
\r
2072 zcurveparticles_effectno = effectno;
\r
2073 zcurveparticles_start = start;
\r
2076 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
\r
2077 WriteCoord(MSG_BROADCAST, end_x);
\r
2078 WriteCoord(MSG_BROADCAST, end_y);
\r
2079 WriteCoord(MSG_BROADCAST, end_z);
\r
2080 WriteCoord(MSG_BROADCAST, end_dz);
\r
2081 zcurveparticles_spd = spd;
\r
2084 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
\r
2087 vector vecxy, velxy;
\r
2089 vecxy = end - start;
\r
2094 if (vlen(velxy) < 0.000001 * fabs(vel_z))
\r
2096 endzcurveparticles();
\r
2097 trailparticles(world, effectno, start, end);
\r
2101 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
\r
2102 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
\r
2105 string GetGametype(); // g_world.qc
\r
2106 void write_recordmarker(entity pl, float tstart, float dt)
\r
2108 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
\r
2110 // also write a marker into demo files for demotc-race-record-extractor to find
\r
2113 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
\r
2114 " ", ftos(tstart), " ", ftos(dt), "\n"));
\r
2117 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
\r
2119 switch(self.owner.cvar_cl_gunalign)
\r
2130 if(allowcenter) // 2: allow center handedness
\r
2143 if(allowcenter) // 2: allow center handedness
\r
2159 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
\r
2164 if (cvar("g_shootfromeye"))
\r
2168 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2176 else if (cvar("g_shootfromcenter"))
\r
2180 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2188 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
\r
2198 else if (cvar("g_shootfromclient"))
\r
2200 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
\r
2207 void attach_sameorigin(entity e, entity to, string tag)
\r
2209 vector org, t_forward, t_left, t_up, e_forward, e_up;
\r
2210 vector org0, ang0;
\r
2216 org = e.origin - gettaginfo(to, gettagindex(to, tag));
\r
2217 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
\r
2218 t_forward = v_forward * tagscale;
\r
2219 t_left = v_right * -tagscale;
\r
2220 t_up = v_up * tagscale;
\r
2222 e.origin_x = org * t_forward;
\r
2223 e.origin_y = org * t_left;
\r
2224 e.origin_z = org * t_up;
\r
2226 // current forward and up directions
\r
2227 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2228 e.angles = AnglesTransform_FromVAngles(e.angles);
\r
2230 e.angles = AnglesTransform_FromAngles(e.angles);
\r
2231 fixedmakevectors(e.angles);
\r
2233 // untransform forward, up!
\r
2234 e_forward_x = v_forward * t_forward;
\r
2235 e_forward_y = v_forward * t_left;
\r
2236 e_forward_z = v_forward * t_up;
\r
2237 e_up_x = v_up * t_forward;
\r
2238 e_up_y = v_up * t_left;
\r
2239 e_up_z = v_up * t_up;
\r
2241 e.angles = fixedvectoangles2(e_forward, e_up);
\r
2242 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2243 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2245 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2247 setattachment(e, to, tag);
\r
2248 setorigin(e, e.origin);
\r
2251 void detach_sameorigin(entity e)
\r
2254 org = gettaginfo(e, 0);
\r
2255 e.angles = fixedvectoangles2(v_forward, v_up);
\r
2256 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2257 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2259 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2260 setorigin(e, org);
\r
2261 setattachment(e, world, "");
\r
2262 setorigin(e, e.origin);
\r
2265 void follow_sameorigin(entity e, entity to)
\r
2267 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
\r
2268 e.aiment = to; // make the hole follow bmodel
\r
2269 e.punchangle = to.angles; // the original angles of bmodel
\r
2270 e.view_ofs = e.origin - to.origin; // relative origin
\r
2271 e.v_angle = e.angles - to.angles; // relative angles
\r
2274 void unfollow_sameorigin(entity e)
\r
2276 e.movetype = MOVETYPE_NONE;
\r
2279 entity gettaginfo_relative_ent;
\r
2280 vector gettaginfo_relative(entity e, float tag)
\r
2282 if (!gettaginfo_relative_ent)
\r
2284 gettaginfo_relative_ent = spawn();
\r
2285 gettaginfo_relative_ent.effects = EF_NODRAW;
\r
2287 gettaginfo_relative_ent.model = e.model;
\r
2288 gettaginfo_relative_ent.modelindex = e.modelindex;
\r
2289 gettaginfo_relative_ent.frame = e.frame;
\r
2290 return gettaginfo(gettaginfo_relative_ent, tag);
\r
2293 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
\r
2297 if (pl.soundentity.cnt & p)
\r
2299 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn, 0);
\r
2300 pl.soundentity.cnt |= p;
\r
2303 void SoundEntity_StopSound(entity pl, float chan)
\r
2307 if (pl.soundentity.cnt & p)
\r
2309 stopsoundto(MSG_ALL, pl.soundentity, chan);
\r
2310 pl.soundentity.cnt &~= p;
\r
2314 void SoundEntity_Attach(entity pl)
\r
2316 pl.soundentity = spawn();
\r
2317 pl.soundentity.classname = "soundentity";
\r
2318 pl.soundentity.owner = pl;
\r
2319 setattachment(pl.soundentity, pl, "");
\r
2320 setmodel(pl.soundentity, "null");
\r
2323 void SoundEntity_Detach(entity pl)
\r
2326 for (i = 0; i <= 7; ++i)
\r
2327 SoundEntity_StopSound(pl, i);
\r
2331 float ParseCommandPlayerSlotTarget_firsttoken;
\r
2332 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
\r
2340 ParseCommandPlayerSlotTarget_firsttoken = -1;
\r
2344 if (substring(argv(idx), 0, 1) == "#")
\r
2346 s = substring(argv(idx), 1, -1);
\r
2354 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2355 if (s == ftos(stof(s)))
\r
2357 e = edict_num(stof(s));
\r
2358 if (e.flags & FL_CLIENT)
\r
2364 // it must be a nick name
\r
2367 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2370 FOR_EACH_CLIENT(head)
\r
2371 if (head.netname == s)
\r
2379 s = strdecolorize(s);
\r
2381 FOR_EACH_CLIENT(head)
\r
2382 if (strdecolorize(head.netname) == s)
\r
2397 float modeleffect_SendEntity(entity to, float sf)
\r
2400 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
\r
2403 if(self.velocity != '0 0 0')
\r
2405 if(self.angles != '0 0 0')
\r
2407 if(self.avelocity != '0 0 0')
\r
2410 WriteByte(MSG_ENTITY, f);
\r
2411 WriteShort(MSG_ENTITY, self.modelindex);
\r
2412 WriteByte(MSG_ENTITY, self.skin);
\r
2413 WriteByte(MSG_ENTITY, self.frame);
\r
2414 WriteCoord(MSG_ENTITY, self.origin_x);
\r
2415 WriteCoord(MSG_ENTITY, self.origin_y);
\r
2416 WriteCoord(MSG_ENTITY, self.origin_z);
\r
2419 WriteCoord(MSG_ENTITY, self.velocity_x);
\r
2420 WriteCoord(MSG_ENTITY, self.velocity_y);
\r
2421 WriteCoord(MSG_ENTITY, self.velocity_z);
\r
2425 WriteCoord(MSG_ENTITY, self.angles_x);
\r
2426 WriteCoord(MSG_ENTITY, self.angles_y);
\r
2427 WriteCoord(MSG_ENTITY, self.angles_z);
\r
2431 WriteCoord(MSG_ENTITY, self.avelocity_x);
\r
2432 WriteCoord(MSG_ENTITY, self.avelocity_y);
\r
2433 WriteCoord(MSG_ENTITY, self.avelocity_z);
\r
2435 WriteShort(MSG_ENTITY, self.scale * 256.0);
\r
2436 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
\r
2437 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
\r
2438 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
\r
2439 WriteByte(MSG_ENTITY, self.alpha * 255.0);
\r
2444 void modeleffect_spawn(string m, float s, float f, vector o, vector v, vector ang, vector angv, float s0, float s2, float a, float t1, float t2)
\r
2449 e.classname = "modeleffect";
\r
2455 e.avelocity = angv;
\r
2457 e.teleport_time = t1;
\r
2461 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2465 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2468 sz = max(e.scale, e.scale2);
\r
2469 setsize(e, e.mins * sz, e.maxs * sz);
\r
2470 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
\r
2473 float portrait_SendEntity(entity to, float sf)
\r
2475 if(to != self.enemy)
\r
2478 WriteByte(MSG_ENTITY, ENT_CLIENT_PORTRAIT);
\r
2480 WriteString(MSG_ENTITY, self.owner.playermodel);
\r
2481 WriteByte(MSG_ENTITY, stof(self.owner.playerskin));
\r
2482 WriteString(MSG_ENTITY, self.owner.netname);
\r
2487 void portrait(entity pl, entity targ)
\r
2491 e.classname = "portrait";
\r
2495 Net_LinkEntity(e, FALSE, 0, portrait_SendEntity);
\r
2498 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
\r
2500 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
\r
2503 float randombit(float bits)
\r
2505 if not(bits & (bits-1)) // this ONLY holds for powers of two!
\r
2514 for(f = 1; f <= bits; f *= 2)
\r
2523 r = (r - 1) / (n - 1);
\r
2530 float randombits(float bits, float k, float error_return)
\r
2534 while(k > 0 && bits != r)
\r
2536 r += randombit(bits - r);
\r
2545 void randombit_test(float bits, float iter)
\r
2549 print(ftos(randombit(bits)), "\n");
\r
2554 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
\r
2556 if(halflifedist > 0)
\r
2557 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
\r
2558 else if(halflifedist < 0)
\r
2559 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
\r
2568 #define cvar_string_normal cvar_string_builtin
\r
2569 #define cvar_normal cvar_builtin
\r
2571 string cvar_string_normal(string n)
\r
2573 if not(cvar_type(n) & 1)
\r
2574 backtrace(strcat("Attempt to access undefined cvar: ", n));
\r
2575 return cvar_string_builtin(n);
\r
2578 float cvar_normal(string n)
\r
2580 return stof(cvar_string_normal(n));
\r
2583 #define cvar_set_normal cvar_set_builtin
\r
2585 void defer_think()
\r
2590 self = self.owner;
\r
2591 oself.think = SUB_Remove;
\r
2592 oself.nextthink = time;
\r
2598 Execute func() after time + fdelay.
\r
2599 self when func is executed = self when defer is called
\r
2601 void defer(float fdelay, void() func)
\r
2608 e.think = defer_think;
\r
2609 e.nextthink = time + fdelay;
\r
2612 // returns 1 if player is at minimum size and 0 if player is at normal size
\r
2613 float playersize_micro(entity e)
\r
2615 if(!cvar("g_healthsize"))
\r
2617 return bound(0, (e.health / cvar("g_healthsize_center") - 1) / (cvar("g_healthsize_min") / cvar("g_healthsize_center") - 1), 1);
\r
2619 // returns 0 if player is at normal size and 1 if player is at maximum size
\r
2620 float playersize_macro(entity e)
\r
2622 if(!cvar("g_healthsize"))
\r
2624 return 1 - bound(0, (e.health / cvar("g_healthsize_max") - 1) / (cvar("g_healthsize_center") / cvar("g_healthsize_max") - 1), 1);
\r