if [ x"$mode" = x"txt" ]; then
{
- echo "en English \"English\""
+ item=`grep "^en " languages.txt`
+ echo "$item"
for X in common.*.po; do
[ -f "$X" ] || continue
if [ -n "$language" ]; then
if [ "$p" -lt 50 ]; then
continue
fi
- item="$l $l \"$l (0%)\""
+ item="$l $l \"$l\" 0%"
fi
- printf "%s\n" "$item" | sed -e "s/([0-9][0-9]*%)/($p%)/"
+ printf "%s\n" "$item" | sed -e "s/[0-9][0-9]*%/$p%/"
done
} | tr '"' '\t' | sort -k3 | tr '\t' '"'
fi
-ast Asturian "Asturianu (60%)"
-de German "Deutsch (90%)"
-de_CH German "Deutsch (Schweiz) (90%)"
-en_AU en_AU "en_AU (77%)"
-en English "English"
-es Spanish "Español (68%)"
-fr French "Français (98%)"
-it Italian "Italiano (97%)"
-hu Hungarian "Magyar (50%)"
-nl Dutch "Nederlands (45%)"
-pl Polish "Polski (60%)"
-pt Portuguese "Português (42%)"
-ro Romanian "Romana (90%)"
-fi Finnish "Suomi (35%)"
-el Greek "Ελληνική (25%)"
-be Belarusian "Беларуская (65%)"
-bg Bulgarian "Български (65%)"
-ru Russian "Русский (93%)"
-uk Ukrainian "Українська (60%)"
+ast Asturian "Asturianu" 60%
+de German "Deutsch" 90%
+de_CH German "Deutsch (Schweiz)" 90%
+en English "English"
+en_AU English "English (Australia)" 77%
+es Spanish "Español" 68%
+fr French "Français" 98%
+it Italian "Italiano" 97%
+hu Hungarian "Magyar" 50%
+nl Dutch "Nederlands" 45%
+pl Polish "Polski" 60%
+pt Portuguese "Português" 42%
+ro Romanian "Romana" 90%
+fi Finnish "Suomi" 35%
+el Greek "Ελληνική" 25%
+be Belarusian "Беларуская" 65%
+bg Bulgarian "Български" 65%
+ru Russian "Русский" 93%
+uk Ukrainian "Українська" 60%
\ No newline at end of file
#include "announcer.qh"
+#include "mutators/events.qh"
+
#include "../common/notifications.qh"
#include "../common/stats.qh"
bool announcer_1min;
bool announcer_5min;
+string AnnouncerOption()
+{
+ string ret = autocvar_cl_announcer;
+ MUTATOR_CALLHOOK(AnnouncerOption, ret);
+ ret = ret_string;
+ return ret;
+}
+
void Announcer_Countdown()
{
SELFPARAM();
- float starttime = getstatf(STAT_GAMESTARTTIME);
+ float starttime = STAT(GAMESTARTTIME);
float roundstarttime = getstatf(STAT_ROUNDSTARTTIME);
if(roundstarttime == -1)
{
float previous_game_starttime;
void Announcer_Gamestart()
{
- float startTime = getstatf(STAT_GAMESTARTTIME);
+ float startTime = STAT(GAMESTARTTIME);
float roundstarttime = getstatf(STAT_ROUNDSTARTTIME);
if(roundstarttime > startTime)
startTime = roundstarttime;
{
if(time < startTime)
{
- entity e = find(world, classname, "announcer_countdown");
- if (!e)
+ static entity announcer_countdown;
+ if (!announcer_countdown)
{
- e = spawn();
- e.classname = "announcer_countdown";
- e.think = Announcer_Countdown;
+ announcer_countdown = new(announcer_countdown);
+ announcer_countdown.think = Announcer_Countdown;
}
if(time + 5.0 < startTime) // if connecting to server while restart was active don't always play prepareforbattle
- if(time > e.nextthink) // don't play it again if countdown was already going
+ if(time > announcer_countdown.nextthink) // don't play it again if countdown was already going
Local_Notification(MSG_ANNCE, ANNCE_PREPARE);
- e.nextthink = startTime - floor(startTime - time); //synchronize nextthink to startTime
+ announcer_countdown.nextthink = startTime - floor(startTime - time); //synchronize nextthink to startTime
}
}
void Announcer_Time()
{
float timelimit = getstatf(STAT_TIMELIMIT);
- float timeleft = max(0, timelimit * 60 + getstatf(STAT_GAMESTARTTIME) - time);
+ float timeleft = max(0, timelimit * 60 + STAT(GAMESTARTTIME) - time);
float warmup_timeleft = 0;
if(warmup_stage)
if(autocvar_g_warmup_limit > 0)
- warmup_timeleft = max(0, autocvar_g_warmup_limit + getstatf(STAT_GAMESTARTTIME) - time);
+ warmup_timeleft = max(0, autocvar_g_warmup_limit + STAT(GAMESTARTTIME) - time);
// 5 minute check
if(autocvar_cl_announcer_maptime >= 2)
void Announcer();
+string AnnouncerOption();
+
#endif
#include "../autocvars.qh"
#include "../defs.qh"
-#include "../hud.qh"
-#include "../hud_config.qh"
+#include "../hud/all.qh"
#include "../main.qh"
#include "../mapvoting.qh"
#include "../miscfunctions.qh"
void DrawDebugModel(entity this)
{
- if(time - floor(time) > 0.5)
+ if (time - floor(time) > 0.5)
{
PolyDrawModel(self);
self.drawmask = 0;
// Anyway, to enable it, just compile the client with -DBLURTEST and then you can use the command.
#ifdef BLURTEST
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
}
}
#else
- if(request)
+ if (request)
{
LOG_INFO("Blurtest is not enabled on this client.\n");
return;
void LocalCommand_boxparticles(int request, int argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
{
int index = stoi(argv(2));
entity own;
- if(index <= 0)
+ if (index <= 0)
own = entitybyindex(-index);
else
own = findfloat(world, entnum, index);
}
default:
+ {
LOG_INFO("Incorrect parameters for ^2boxparticles^7\n");
+ }
case CMD_REQUEST_USAGE:
{
LOG_INFO("\nUsage:^3 lv_cmd boxparticles effectname own org_from org_to, dir_from, dir_to, countmultiplier, flags\n");
void LocalCommand_create_scrshot_ent(int request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
string filename = strcat(MapInfo_Map_bspname, "_scrshot_ent.txt");
int fh = fopen(filename, FILE_WRITE);
- if(fh >= 0)
+ if (fh >= 0)
{
fputs(fh, "{\n");
fputs(fh, strcat("\"classname\" \"info_autoscreenshot\"\n"));
void LocalCommand_debugmodel(int request, int argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
string modelname = argv(1);
- entity debugmodel_entity;
- debugmodel_entity = spawn();
+ entity debugmodel_entity = new(debugmodel);
precache_model(modelname);
_setmodel(debugmodel_entity, modelname);
setorigin(debugmodel_entity, view_origin);
debugmodel_entity.angles = view_angles;
debugmodel_entity.draw = DrawDebugModel;
- debugmodel_entity.classname = "debugmodel";
return;
}
void LocalCommand_handlevote(int request, int argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
int vote_selection;
string vote_string;
- if(InterpretBoolean(argv(1)))
+ if (InterpretBoolean(argv(1)))
{
vote_selection = 2;
vote_string = "yes";
vote_string = "no";
}
- if(vote_selection)
+ if (vote_selection)
{
- if(uid2name_dialog) // handled by "uid2name" option
+ if (uid2name_dialog) // handled by "uid2name" option
{
vote_active = 0;
vote_prev = 0;
}
default:
+ {
LOG_INFO("Incorrect parameters for ^2handlevote^7\n");
+ }
case CMD_REQUEST_USAGE:
{
LOG_INFO("\nUsage:^3 cl_cmd handlevote vote\n");
void LocalCommand_hud(int request, int argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- switch(argv(1))
+ switch (argv(1))
{
case "configure":
{
case "quickmenu":
{
- if(QuickMenu_IsOpened())
+ if (argv(2) == "help")
+ {
+ LOG_INFO(" quickmenu [[default | file | \"\"] submenu]\n");
+ LOG_INFO("Called without options (or with \"\") loads either the default quickmenu or a quickmenu file if hud_panel_quickmenu_file is set to a valid filename.\n");
+ LOG_INFO("A submenu name can be given to open the quickmenu directly in a submenu; it requires to specify 'default', 'file' or '\"\"' option.\n");
+ return;
+ }
+ if (QuickMenu_IsOpened())
QuickMenu_Close();
else
- QuickMenu_Open(argv(2), argv(3)); // mode, submenu
+ QuickMenu_Open(argv(2), argv(3)); // mode, submenu
return;
}
case "minigame":
{
- if(HUD_MinigameMenu_IsOpened())
+ if (HUD_MinigameMenu_IsOpened())
HUD_MinigameMenu_Close();
else
HUD_MinigameMenu_Open();
case "save":
{
- if(argv(2))
+ if (argv(2))
{
HUD_Panel_ExportCfg(argv(2));
return;
}
else
{
- break; // go to usage, we're missing the paramater needed here.
+ break; // go to usage, we're missing the paramater needed here.
}
}
case "radar":
{
- if(argv(2))
- HUD_Radar_Show_Maximized(InterpretBoolean(argv(2)),0);
+ if (argv(2))
+ HUD_Radar_Show_Maximized(InterpretBoolean(argv(2)), 0);
else
- HUD_Radar_Show_Maximized(!hud_panel_radar_maximized,0);
+ HUD_Radar_Show_Maximized(!hud_panel_radar_maximized, 0);
return;
}
case "clickradar":
{
- HUD_Radar_Show_Maximized(!hud_panel_radar_mouse,1);
+ HUD_Radar_Show_Maximized(!hud_panel_radar_mouse, 1);
return;
}
}
}
default:
+ {
LOG_INFO("Incorrect parameters for ^2hud^7\n");
+ }
case CMD_REQUEST_USAGE:
{
LOG_INFO("\nUsage:^3 cl_cmd hud action [configname | radartoggle | layout]\n");
LOG_INFO(" 'configname' is the name to save to for \"save\" action,\n");
LOG_INFO(" 'radartoggle' is to control hud_panel_radar_maximized for \"radar\" action,\n");
LOG_INFO(" and 'layout' is how to organize the scoreboard columns for the set action.\n");
- LOG_INFO(" quickmenu [[default | file | \"\"] submenu]\n");
- LOG_INFO(" Called without options (or with "") loads either the default quickmenu or a quickmenu file if hud_panel_quickmenu_file is set to a valid filename.\n");
- LOG_INFO(" Submenu option allows to open quickmenu directly in a submenu, it requires to specify 'default', 'file' or '\"\"' option.\n");
- LOG_INFO(" Full list of commands here: \"configure, minigame, save, scoreboard_columns_help, scoreboard_columns_set, radar.\"\n");
+ LOG_INFO(" Full list of commands here: \"configure, quickmenu, minigame, save, scoreboard_columns_help, scoreboard_columns_set, radar.\"\n");
return;
}
}
void LocalCommand_localprint(int request, int argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1))
+ if (argv(1))
{
centerprint_hud(argv(1));
return;
}
default:
+ {
LOG_INFO("Incorrect parameters for ^2localprint^7\n");
+ }
case CMD_REQUEST_USAGE:
{
LOG_INFO("\nUsage:^3 cl_cmd localprint \"message\"\n");
void LocalCommand_mv_download(int request, int argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1))
+ if (argv(1))
{
Cmd_MapVote_MapDownload(argc);
return;
}
default:
+ {
LOG_INFO("Incorrect parameters for ^2mv_download^7\n");
+ }
case CMD_REQUEST_USAGE:
{
LOG_INFO("\nUsage:^3 cl_cmd mv_download mapid\n");
void LocalCommand_find(int request, int argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
entity client;
- for(client = world; (client = find(client, classname, argv(1))); )
+ for (client = world; (client = find(client, classname, argv(1))); )
LOG_INFO(etos(client), "\n");
return;
}
default:
+ {
LOG_INFO("Incorrect parameters for ^2find^7\n");
+ }
case CMD_REQUEST_USAGE:
{
LOG_INFO("\nUsage:^3 cl_cmd find classname\n");
void LocalCommand_sendcvar(int request, int argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1))
+ if (argv(1))
{
// W_FixWeaponOrder will trash argv, so save what we need.
string thiscvar = strzone(argv(1));
string s = cvar_string(thiscvar);
- if(thiscvar == "cl_weaponpriority")
+ if (thiscvar == "cl_weaponpriority")
s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 1);
- else if(substring(thiscvar, 0, 17) == "cl_weaponpriority" && strlen(thiscvar) == 18)
+ else if (substring(thiscvar, 0, 17) == "cl_weaponpriority" && strlen(thiscvar) == 18)
s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 0);
localcmd("cmd sentcvar ", thiscvar, " \"", s, "\"\n");
}
default:
+ {
LOG_INFO("Incorrect parameters for ^2sendcvar^7\n");
+ }
case CMD_REQUEST_USAGE:
{
LOG_INFO("\nUsage:^3 cl_cmd sendcvar <cvar>\n");
** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
void LocalCommand_(int request)
{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
-
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- print("\nUsage:^3 cl_cmd \n");
- print(" No arguments required.\n");
- return;
- }
- }
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ print("\nUsage:^3 cl_cmd \n");
+ print(" No arguments required.\n");
+ return;
+ }
+ }
}
*/
// ==================================
// Normally do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define CLIENT_COMMANDS(request,arguments) \
+#define CLIENT_COMMANDS(request, arguments) \
CLIENT_COMMAND("blurtest", LocalCommand_blurtest(request), "Feature for testing blur postprocessing") \
CLIENT_COMMAND("boxparticles", LocalCommand_boxparticles(request, arguments), "Spawn particles manually") \
CLIENT_COMMAND("create_scrshot_ent", LocalCommand_create_scrshot_ent(request), "Create an entity at this location for automatic screenshots") \
void LocalCommand_macro_help()
{
- #define CLIENT_COMMAND(name,function,description) \
- { if(strtolower(description) != "") { LOG_INFO(" ^2", name, "^7: ", description, "\n"); } }
+ #define CLIENT_COMMAND(name, function, description) \
+ { if (strtolower(description) != "") { LOG_INFO(" ^2", name, "^7: ", description, "\n"); } }
CLIENT_COMMANDS(0, 0);
#undef CLIENT_COMMAND
-
- return;
}
bool LocalCommand_macro_command(int argc)
{
- #define CLIENT_COMMAND(name,function,description) \
- { if(name == strtolower(argv(0))) { function; return true; } }
+ #define CLIENT_COMMAND(name, function, description) \
+ { if (name == strtolower(argv(0))) { function; return true; } }
CLIENT_COMMANDS(CMD_REQUEST_COMMAND, argc);
#undef CLIENT_COMMAND
bool LocalCommand_macro_usage(int argc)
{
- #define CLIENT_COMMAND(name,function,description) \
- { if(name == strtolower(argv(1))) { function; return true; } }
+ #define CLIENT_COMMAND(name, function, description) \
+ { if (name == strtolower(argv(1))) { function; return true; } }
CLIENT_COMMANDS(CMD_REQUEST_USAGE, argc);
#undef CLIENT_COMMAND
void LocalCommand_macro_write_aliases(int fh)
{
- #define CLIENT_COMMAND(name,function,description) \
- { if(strtolower(description) != "") { CMD_Write_Alias("qc_cmd_cl", name, description); } }
+ #define CLIENT_COMMAND(name, function, description) \
+ { if (strtolower(description) != "") { CMD_Write_Alias("qc_cmd_cl", name, description); } }
CLIENT_COMMANDS(0, 0);
#undef CLIENT_COMMAND
-
- return;
}
string s = strtolower(argv(0));
if (s == "help")
{
- if(argc == 1)
+ if (argc == 1)
{
LOG_INFO("\nClient console commands:\n");
LocalCommand_macro_help();
return;
}
- else if(GenericCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
+ else if (GenericCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
{
return;
}
- else if(LocalCommand_macro_usage(argc)) // now try for normal commands too
+ else if (LocalCommand_macro_usage(argc)) // now try for normal commands too
{
return;
}
}
// continue as usual and scan for normal commands
- if (GenericCommand(command)// handled by common/command/generic.qc
- || LocalCommand_macro_command(argc) // handled by one of the above LocalCommand_* functions
- || MUTATOR_CALLHOOK(CSQC_ConsoleCommand, s, argc, command) // handled by a mutator
- ) return;
+ if (GenericCommand(command) // handled by common/command/generic.qc
+ || LocalCommand_macro_command(argc) // handled by one of the above LocalCommand_* functions
+ || MUTATOR_CALLHOOK(CSQC_ConsoleCommand, s, argc, command) // handled by a mutator
+ ) return;
// nothing above caught the command, must be invalid
LOG_INFO(((command != "") ? strcat("Unknown client command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try cl_cmd help.\n");
-
- return;
}
void ConsoleCommand_macro_init()
{
// first init normal commands
- #define CONSOLE_COMMAND(name,execution) \
+ #define CONSOLE_COMMAND(name, execution) \
{ registercommand(name); }
CONSOLE_COMMANDS_NORMAL();
// then init movement commands
#ifndef CAMERATEST
- if(isdemo())
+ if (isdemo())
{
#endif
- #define CONSOLE_COMMAND(name,execution) \
- { registercommand(name); }
+ #define CONSOLE_COMMAND(name, execution) \
+ registercommand(name);
- CONSOLE_COMMANDS_MOVEMENT();
+ CONSOLE_COMMANDS_MOVEMENT();
#undef CONSOLE_COMMAND
#ifndef CAMERATEST
- }
+}
#endif
}
bool ConsoleCommand_macro_normal(string s, int argc)
{
- #define CONSOLE_COMMAND(name,execution) \
+ #define CONSOLE_COMMAND(name, execution) \
{ if (name == s) { { execution } return true; } }
CONSOLE_COMMANDS_NORMAL();
bool ConsoleCommand_macro_movement(string s, int argc)
{
- if(camera_active)
+ if (camera_active)
{
- #define CONSOLE_COMMAND(name,execution) \
+ #define CONSOLE_COMMAND(name, execution) \
{ if (name == s) { { execution } return true; } }
CONSOLE_COMMANDS_MOVEMENT();
int argc = tokenize_console(command);
string s = strtolower(argv(0));
// Return value should be true if CSQC handled the command, otherwise return false to have the engine handle it.
- return (ConsoleCommand_macro_normal(s, argc)
- || ConsoleCommand_macro_movement(s, argc)
- );
+ return ConsoleCommand_macro_normal(s, argc)
+ || ConsoleCommand_macro_movement(s, argc)
+ ;
}
+++ /dev/null
-#include "controlpoint.qh"
-
-#include "teamradar.qh"
-#include "../common/movetypes/movetypes.qh"
-
-.vector colormod;
-.float alpha;
-.int count;
-.float pain_finished;
-
-.bool iscaptured;
-
-.vector cp_origin, cp_bob_origin;
-.float cp_bob_spd;
-
-.vector cp_bob_dmg;
-
-.vector punchangle;
-
-.float max_health;
-
-.entity icon_realmodel;
-
-void cpicon_draw(entity this)
-{
- if(time < this.move_time) { return; }
-
- if(this.cp_bob_dmg_z > 0)
- this.cp_bob_dmg_z = this.cp_bob_dmg_z - 3 * frametime;
- else
- this.cp_bob_dmg_z = 0;
- this.cp_bob_origin_z = 4 * PI * (1 - cos(this.cp_bob_spd));
- this.cp_bob_spd = this.cp_bob_spd + 1.875 * frametime;
- this.colormod = '1 1 1' * (2 - bound(0, (this.pain_finished - time) / 10, 1));
-
- if(!this.iscaptured) this.alpha = this.health / this.max_health;
-
- if(this.iscaptured)
- {
- if (this.punchangle_x > 0)
- {
- this.punchangle_x = this.punchangle_x - 60 * frametime;
- if (this.punchangle_x < 0)
- this.punchangle_x = 0;
- }
- else if (this.punchangle_x < 0)
- {
- this.punchangle_x = this.punchangle_x + 60 * frametime;
- if (this.punchangle_x > 0)
- this.punchangle_x = 0;
- }
-
- if (this.punchangle_y > 0)
- {
- this.punchangle_y = this.punchangle_y - 60 * frametime;
- if (this.punchangle_y < 0)
- this.punchangle_y = 0;
- }
- else if (this.punchangle_y < 0)
- {
- this.punchangle_y = this.punchangle_y + 60 * frametime;
- if (this.punchangle_y > 0)
- this.punchangle_y = 0;
- }
-
- if (this.punchangle_z > 0)
- {
- this.punchangle_z = this.punchangle_z - 60 * frametime;
- if (this.punchangle_z < 0)
- this.punchangle_z = 0;
- }
- else if (this.punchangle_z < 0)
- {
- this.punchangle_z = this.punchangle_z + 60 * frametime;
- if (this.punchangle_z > 0)
- this.punchangle_z = 0;
- }
-
- this.angles_x = this.punchangle_x;
- this.angles_y = this.punchangle_y + this.move_angles_y;
- this.angles_z = this.punchangle_z;
- this.move_angles_y = this.move_angles_y + 45 * frametime;
- }
-
- setorigin(this, this.cp_origin + this.cp_bob_origin + this.cp_bob_dmg);
-}
-
-void cpicon_damage(entity this, float hp)
-{
- if(!this.iscaptured) { return; }
-
- if(hp < this.max_health * 0.25)
- setmodel(this, MDL_ONS_CP3);
- else if(hp < this.max_health * 0.50)
- setmodel(this, MDL_ONS_CP2);
- else if(hp < this.max_health * 0.75)
- setmodel(this, MDL_ONS_CP1);
- else if(hp <= this.max_health || hp >= this.max_health)
- setmodel(this, MDL_ONS_CP);
-
- this.punchangle = (2 * randomvec() - '1 1 1') * 45;
-
- this.cp_bob_dmg_z = (2 * random() - 1) * 15;
- this.pain_finished = time + 1;
- this.colormod = '2 2 2';
-
- setsize(this, CPICON_MIN, CPICON_MAX);
-}
-
-void cpicon_construct(entity this)
-{
- this.netname = "Control Point Icon";
-
- setmodel(this, MDL_ONS_CP);
- setsize(this, CPICON_MIN, CPICON_MAX);
-
- if(this.icon_realmodel == world)
- {
- this.icon_realmodel = spawn();
- setmodel(this.icon_realmodel, MDL_Null);
- setorigin(this.icon_realmodel, this.origin);
- setsize(this.icon_realmodel, CPICON_MIN, CPICON_MAX);
- this.icon_realmodel.movetype = MOVETYPE_NOCLIP;
- this.icon_realmodel.solid = SOLID_NOT;
- this.icon_realmodel.move_origin = this.icon_realmodel.origin;
- }
-
- if(this.iscaptured) { this.icon_realmodel.solid = SOLID_BBOX; }
-
- this.move_movetype = MOVETYPE_NOCLIP;
- this.solid = SOLID_NOT;
- this.movetype = MOVETYPE_NOCLIP;
- this.move_origin = this.origin;
- this.move_time = time;
- this.drawmask = MASK_NORMAL;
- this.alpha = 1;
- this.draw = cpicon_draw;
- this.cp_origin = this.origin;
- this.cp_bob_origin = '0 0 0.1';
- this.cp_bob_spd = 0;
-}
-
-.vector glowmod;
-void cpicon_changeteam(entity this)
-{
- if(this.team)
- {
- this.glowmod = Team_ColorRGB(this.team - 1);
- this.teamradar_color = Team_ColorRGB(this.team - 1);
- this.colormap = 1024 + (this.team - 1) * 17;
- }
- else
- {
- this.colormap = 1024;
- this.glowmod = '1 1 0';
- this.teamradar_color = '1 1 0';
- }
-}
-
-void ent_cpicon(entity this)
-{
- int sf = ReadByte();
-
- if(sf & CPSF_SETUP)
- {
- this.origin_x = ReadCoord();
- this.origin_y = ReadCoord();
- this.origin_z = ReadCoord();
- setorigin(this, this.origin);
-
- this.health = ReadByte();
- this.max_health = ReadByte();
- this.count = ReadByte();
- this.team = ReadByte();
- this.iscaptured = ReadByte();
-
- if(!this.count)
- this.count = (this.health - this.max_health) * frametime;
-
- cpicon_changeteam(this);
- cpicon_construct(this);
- }
-
- if(sf & CPSF_STATUS)
- {
- int _tmp = ReadByte();
- if(_tmp != this.team)
- {
- this.team = _tmp;
- cpicon_changeteam(this);
- }
-
- _tmp = ReadByte();
-
- if(_tmp != this.health)
- cpicon_damage(this, _tmp);
-
- this.health = _tmp;
- }
-}
+++ /dev/null
-#ifndef CLIENT_CONTROLPOINT_H
-#define CLIENT_CONTROLPOINT_H
-
-const vector CPICON_MIN = '-32 -32 -9';
-const vector CPICON_MAX = '32 32 25';
-
-const int CPSF_STATUS = 4;
-const int CPSF_SETUP = 8;
-
-void ent_cpicon(entity this);
-
-#endif
.int lodmodelindex0;
.int lodmodelindex1;
.int lodmodelindex2;
-void CSQCPlayer_LOD_Apply(void)
+void CSQCPlayer_LOD_Apply()
{SELFPARAM();
// LOD model loading
if(self.lodmodelindex0 != self.modelindex)
.vector glowmod;
.vector old_glowmod;
-void CSQCPlayer_ModelAppearance_PreUpdate(void)
+void CSQCPlayer_ModelAppearance_PreUpdate()
{SELFPARAM();
self.model = self.forceplayermodels_savemodel;
self.modelindex = self.forceplayermodels_savemodelindex;
self.skin = self.forceplayermodels_saveskin;
self.colormap = self.forceplayermodels_savecolormap;
}
-void CSQCPlayer_ModelAppearance_PostUpdate(void)
+void CSQCPlayer_ModelAppearance_PostUpdate()
{SELFPARAM();
self.forceplayermodels_savemodel = self.model;
self.forceplayermodels_savemodelindex = self.modelindex;
// which one is ALWAYS good?
if (!forceplayermodels_goodmodel)
{
- entity e;
- e = spawn();
+ entity e = spawn();
precache_model(cvar_defstring("_cl_playermodel"));
_setmodel(e, cvar_defstring("_cl_playermodel"));
forceplayermodels_goodmodel = e.model;
forceplayermodels_attempted = 1;
// only if this failed, find it out on our own
- entity e;
- e = spawn();
+ entity e = spawn();
_setmodel(e, autocvar__cl_playermodel); // this is harmless, see below
forceplayermodels_modelisgoodmodel = fexists(e.model);
forceplayermodels_model = e.model;
if(autocvar_cl_forcemyplayermodel != "" && autocvar_cl_forcemyplayermodel != forceplayermodels_mymodel)
{
- entity e;
- e = spawn();
+ entity e = spawn();
_setmodel(e, autocvar_cl_forcemyplayermodel); // this is harmless, see below
forceplayermodels_myisgoodmodel = fexists(e.model);
forceplayermodels_mymodel = e.model;
.int csqcmodel_framecount;
#define IS_DEAD_FRAME(f) ((f) == 0 || (f) == 1)
-void CSQCPlayer_FallbackFrame_PreUpdate(void)
+void CSQCPlayer_FallbackFrame_PreUpdate()
{SELFPARAM();
self.frame = self.csqcmodel_saveframe;
self.frame2 = self.csqcmodel_saveframe2;
LOG_INFOF("Frame %d missing in model %s, and we have no fallback - FAIL!\n", f, self.model);
return f;
}
-void CSQCPlayer_FallbackFrame_Apply(void)
+void CSQCPlayer_FallbackFrame_Apply()
{SELFPARAM();
self.frame = CSQCPlayer_FallbackFrame(self.frame);
self.frame2 = CSQCPlayer_FallbackFrame(self.frame2);
.entity tag_entity;
.int tag_entity_lastmodelindex;
.int tag_index;
-void CSQCModel_AutoTagIndex_Apply(void)
+void CSQCModel_AutoTagIndex_Apply()
{SELFPARAM();
if(self.tag_entity && wasfreed(self.tag_entity))
self.tag_entity = world;
.int csqcmodel_effects;
.int csqcmodel_modelflags;
.int csqcmodel_traileffect;
-void CSQCModel_Effects_PreUpdate(void)
+void CSQCModel_Effects_PreUpdate()
{SELFPARAM();
self.effects = self.csqcmodel_effects;
self.modelflags = self.csqcmodel_modelflags;
self.traileffect = self.csqcmodel_traileffect;
}
-void Reset_ArcBeam(void);
-void CSQCModel_Effects_PostUpdate(void)
+void Reset_ArcBeam();
+void CSQCModel_Effects_PostUpdate()
{SELFPARAM();
if (self == csqcplayer) {
if (self.csqcmodel_teleported) {
Projectile_ResetTrail(self, self.origin);
}
.int snd_looping;
-void CSQCModel_Effects_Apply(void)
+void CSQCModel_Effects_Apply()
{SELFPARAM();
int eff = self.csqcmodel_effects & ~CSQCMODEL_EF_RESPAWNGHOST;
int tref = self.csqcmodel_traileffect;
if(eff & EF_FULLBRIGHT)
self.renderflags |= RF_FULLBRIGHT;
if(eff & EF_FLAME)
- pointparticles(particleeffectnum(EFFECT_EF_FLAME), self.origin, '0 0 0', bound(0, frametime, 0.1));
+ pointparticles(EFFECT_EF_FLAME, self.origin, '0 0 0', bound(0, frametime, 0.1));
if(eff & EF_STARDUST)
- pointparticles(particleeffectnum(EFFECT_EF_STARDUST), self.origin, '0 0 0', bound(0, frametime, 0.1));
+ pointparticles(EFFECT_EF_STARDUST, self.origin, '0 0 0', bound(0, frametime, 0.1));
if(eff & EF_NOSHADOW)
self.renderflags |= RF_NOSHADOW;
if(eff & EF_NODEPTHTEST)
+++ /dev/null
-#include "damage.qh"
-
-#include "gibs.qh"
-#include "../common/deathtypes/all.qh"
-#include "../common/movetypes/movetypes.qh"
-#include "../common/vehicles/all.qh"
-#include "../common/weapons/all.qh"
-
-.entity tag_entity;
-
-.float cnt;
-.int state;
-.bool isplayermodel;
-
-void DamageEffect_Think()
-{SELFPARAM();
- // if particle distribution is enabled, slow ticrate by total number of damages
- if(autocvar_cl_damageeffect_distribute)
- self.nextthink = time + autocvar_cl_damageeffect_ticrate * self.owner.total_damages;
- else
- self.nextthink = time + autocvar_cl_damageeffect_ticrate;
-
- if(time >= self.cnt || !self.owner || !self.owner.modelindex || !self.owner.drawmask)
- {
- // time is up or the player got gibbed / disconnected
- self.owner.total_damages = max(0, self.owner.total_damages - 1);
- remove(self);
- return;
- }
- if(self.state && !self.owner.csqcmodel_isdead)
- {
- // if the player was dead but is now alive, it means he respawned
- // if so, clear his damage effects, or damages from his dead body will be copied back
- self.owner.total_damages = max(0, self.owner.total_damages - 1);
- remove(self);
- return;
- }
- self.state = self.owner.csqcmodel_isdead;
- if(self.owner.isplayermodel && (self.owner.entnum == player_localentnum) && !autocvar_chase_active)
- return; // if we aren't using a third person camera, hide our own effects
-
- // now generate the particles
- vector org;
- org = gettaginfo(self, 0); // origin at attached location
- pointparticles(self.team, org, '0 0 0', 1);
-}
-
-void DamageEffect(vector hitorg, float thedamage, int type, int specnum)
-{SELFPARAM();
- // particle effects for players and objects damaged by weapons (eg: flames coming out of victims shot with rockets)
-
- int nearestbone = 0;
- float life;
- string specstr, effectname;
- entity e;
-
- if(!autocvar_cl_damageeffect || autocvar_cl_gentle || autocvar_cl_gentle_damage)
- return;
- if(!self || !self.modelindex || !self.drawmask)
- return;
-
- // if this is a rigged mesh, the effect will show on the bone where damage was dealt
- // we do this by choosing the skeletal bone closest to the impact, and attaching our entity to it
- // if there's no skeleton, object origin will automatically be selected
- FOR_EACH_TAG(self)
- {
- if(!tagnum)
- continue; // skip empty bones
- // blacklist bones positioned outside the mesh, or the effect will be floating
- // TODO: Do we have to do it this way? Why do these bones exist at all?
- if(gettaginfo_name == "master" || gettaginfo_name == "knee_L" || gettaginfo_name == "knee_R" || gettaginfo_name == "leg_L" || gettaginfo_name == "leg_R")
- continue; // player model bone blacklist
-
- // now choose the bone closest to impact origin
- if(nearestbone == 0 || vlen(hitorg - gettaginfo(self, tagnum)) <= vlen(hitorg - gettaginfo(self, nearestbone)))
- nearestbone = tagnum;
- }
- gettaginfo(self, nearestbone); // set gettaginfo_name
-
- // return if we reached our damage effect limit or damages are disabled
- // TODO: When the limit is reached, it would be better if the oldest damage was removed instead of not adding a new one
- if(nearestbone)
- {
- if(self.total_damages >= autocvar_cl_damageeffect_bones)
- return; // allow multiple damages on skeletal models
- }
- else
- {
- if(autocvar_cl_damageeffect < 2 || self.total_damages)
- return; // allow a single damage on non-skeletal models
- }
-
- life = bound(autocvar_cl_damageeffect_lifetime_min, thedamage * autocvar_cl_damageeffect_lifetime, autocvar_cl_damageeffect_lifetime_max);
-
- effectname = DEATH_WEAPONOF(type).netname;
-
- if(substring(effectname, strlen(effectname) - 5, 5) == "BLOOD")
- {
- if(self.isplayermodel)
- {
- specstr = species_prefix(specnum);
- specstr = substring(specstr, 0, strlen(specstr) - 1);
- effectname = strreplace("BLOOD", specstr, effectname);
- }
- else { return; } // objects don't bleed
- }
-
- e = spawn();
- setmodel(e, MDL_Null); // necessary to attach and read origin
- setattachment(e, self, gettaginfo_name); // attach to the given bone
- e.classname = "damage";
- e.owner = self;
- e.cnt = time + life;
- e.team = _particleeffectnum(effectname);
- e.think = DamageEffect_Think;
- e.nextthink = time;
- self.total_damages += 1;
-}
-
-void Ent_DamageInfo(float isNew)
-{SELFPARAM();
- float thedamage, rad, edge, thisdmg;
- bool hitplayer = false;
- int species, forcemul;
- vector force, thisforce;
-
- w_deathtype = ReadShort();
- w_issilent = (w_deathtype & 0x8000);
- w_deathtype = (w_deathtype & 0x7FFF);
-
- w_org.x = ReadCoord();
- w_org.y = ReadCoord();
- w_org.z = ReadCoord();
-
- thedamage = ReadByte();
- rad = ReadByte();
- edge = ReadByte();
- force = decompressShortVector(ReadShort());
- species = ReadByte();
-
- if (!isNew)
- return;
-
- if(rad < 0)
- {
- rad = -rad;
- forcemul = -1;
- }
- else
- forcemul = 1;
-
- for(entity e = findradius(w_org, rad + MAX_DAMAGEEXTRARADIUS); e; e = e.chain)
- {
- setself(e);
- // attached ents suck
- if(self.tag_entity)
- continue;
-
- vector nearest = NearestPointOnBox(self, w_org);
- if(rad)
- {
- thisdmg = ((vlen (nearest - w_org) - bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
- if(thisdmg >= 1)
- continue;
- if(thisdmg < 0)
- thisdmg = 0;
- if(thedamage)
- {
- thisdmg = thedamage + (edge - thedamage) * thisdmg;
- thisforce = forcemul * vlen(force) * (thisdmg / thedamage) * normalize(self.origin - w_org);
- }
- else
- {
- thisdmg = 0;
- thisforce = forcemul * vlen(force) * normalize(self.origin - w_org);
- }
- }
- else
- {
- if(vlen(nearest - w_org) > bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS))
- continue;
-
- thisdmg = thedamage;
- thisforce = forcemul * force;
- }
-
- if(self.damageforcescale)
- if(vlen(thisforce))
- {
- self.move_velocity = self.move_velocity + damage_explosion_calcpush(self.damageforcescale * thisforce, self.move_velocity, autocvar_g_balance_damagepush_speedfactor);
- self.move_flags &= ~FL_ONGROUND;
- }
-
- if(w_issilent)
- self.silent = 1;
-
- if(self.event_damage)
- self.event_damage(thisdmg, w_deathtype, w_org, thisforce);
-
- DamageEffect(w_org, thisdmg, w_deathtype, species);
-
- if(self.isplayermodel)
- hitplayer = true; // this impact damaged a player
- }
- setself(this);
-
- if(DEATH_ISVEHICLE(w_deathtype))
- {
- traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
- if(trace_plane_normal != '0 0 0')
- w_backoff = trace_plane_normal;
- else
- w_backoff = -1 * normalize(w_org - (w_org + normalize(force) * 16));
-
- setorigin(self, w_org + w_backoff * 2); // for sound() calls
-
- switch(DEATH_ENT(w_deathtype))
- {
- case DEATH_VH_CRUSH:
- break;
-
- // spiderbot
- case DEATH_VH_SPID_MINIGUN:
- sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_SPIDERBOT_MINIGUN_IMPACT), self.origin, w_backoff * 1000, 1);
- break;
- case DEATH_VH_SPID_ROCKET:
- sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_SPIDERBOT_ROCKET_EXPLODE), self.origin, w_backoff * 1000, 1);
- break;
- case DEATH_VH_SPID_DEATH:
- sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
- pointparticles(particleeffectnum(EFFECT_EXPLOSION_BIG), self.origin, w_backoff * 1000, 1);
- break;
-
- case DEATH_VH_WAKI_GUN:
- sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_RACER_IMPACT), self.origin, w_backoff * 1000, 1);
- break;
- case DEATH_VH_WAKI_ROCKET:
- sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_RACER_ROCKET_EXPLODE), self.origin, w_backoff * 1000, 1);
- break;
- case DEATH_VH_WAKI_DEATH:
- sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
- pointparticles(particleeffectnum(EFFECT_EXPLOSION_BIG), self.origin, w_backoff * 1000, 1);
- break;
-
- case DEATH_VH_RAPT_CANNON:
- sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_RAPTOR_CANNON_IMPACT), self.origin, w_backoff * 1000, 1);
- break;
- case DEATH_VH_RAPT_FRAGMENT:
- float i;
- vector ang, vel;
- for(i = 1; i < 4; ++i)
- {
- vel = normalize(w_org - (w_org + normalize(force) * 16)) + randomvec() * 128;
- ang = vectoangles(vel);
- RaptorCBShellfragToss(w_org, vel, ang + '0 0 1' * (120 * i));
- }
- sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_RAPTOR_BOMB_SPREAD), self.origin, w_backoff * 1000, 1);
- break;
- case DEATH_VH_RAPT_BOMB:
- sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_RAPTOR_BOMB_IMPACT), self.origin, w_backoff * 1000, 1);
- break;
- case DEATH_VH_RAPT_DEATH:
- sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_MIN);
- pointparticles(particleeffectnum(EFFECT_EXPLOSION_BIG), self.origin, w_backoff * 1000, 1);
- break;
- case DEATH_VH_BUMB_GUN:
- sound(self, CH_SHOTS, SND_FIREBALL_IMPACT2, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_BIGPLASMA_IMPACT), self.origin, w_backoff * 1000, 1);
- break;
- }
- }
-
-
- if(DEATH_ISTURRET(w_deathtype))
- {
- traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
- if(trace_plane_normal != '0 0 0')
- w_backoff = trace_plane_normal;
- else
- w_backoff = -1 * normalize(w_org - (w_org + normalize(force) * 16));
-
- setorigin(self, w_org + w_backoff * 2); // for sound() calls
-
- switch(DEATH_ENT(w_deathtype))
- {
- case DEATH_TURRET_EWHEEL:
- sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_MIN);
- pointparticles(particleeffectnum(EFFECT_BLASTER_IMPACT), self.origin, w_backoff * 1000, 1);
- break;
-
- case DEATH_TURRET_FLAC:
- pointparticles(particleeffectnum(EFFECT_HAGAR_EXPLODE), w_org, '0 0 0', 1);
- sound(self, CH_SHOTS, SND_HAGEXP_RANDOM(), VOL_BASE, ATTEN_NORM);
- break;
-
- case DEATH_TURRET_MLRS:
- case DEATH_TURRET_HK:
- case DEATH_TURRET_WALK_ROCKET:
- case DEATH_TURRET_HELLION:
- sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
- pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), self.origin, w_backoff * 1000, 1);
- break;
-
- case DEATH_TURRET_MACHINEGUN:
- case DEATH_TURRET_WALK_GUN:
- sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_MACHINEGUN_IMPACT), self.origin, w_backoff * 1000, 1);
- break;
-
- case DEATH_TURRET_PLASMA:
- sound(self, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_MIN);
- pointparticles(particleeffectnum(EFFECT_ELECTRO_IMPACT), self.origin, w_backoff * 1000, 1);
- break;
-
- case DEATH_TURRET_WALK_MELEE:
- sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTEN_MIN);
- pointparticles(particleeffectnum(EFFECT_TE_SPARK), self.origin, w_backoff * 1000, 1);
- break;
-
- case DEATH_TURRET_PHASER:
- break;
-
- case DEATH_TURRET_TESLA:
- te_smallflash(self.origin);
- break;
-
- }
- }
-
- // TODO spawn particle effects and sounds based on w_deathtype
- if(!DEATH_ISSPECIAL(w_deathtype))
- if(!hitplayer || rad) // don't show ground impacts for hitscan weapons if a player was hit
- {
- Weapon hitwep = DEATH_WEAPONOF(w_deathtype);
- w_random = prandom();
-
- traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
- if(trace_fraction < 1 && hitwep != WEP_VORTEX && hitwep != WEP_VAPORIZER)
- w_backoff = trace_plane_normal;
- else
- w_backoff = -1 * normalize(force);
- setorigin(self, w_org + w_backoff * 2); // for sound() calls
-
- if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)) {
- hitwep.wr_impacteffect(hitwep);
- }
- }
-}
+++ /dev/null
-#ifndef CLIENT_DAMAGE_H
-#define CLIENT_DAMAGE_H
-
-.float total_damages; // number of effects which currently are attached to a player
-
-void Ent_DamageInfo(float isNew);
-
-#endif
#endif
// Basic variables
-.float enttype; // entity type sent from server
-.int sv_entnum; // entity number sent from server
+.int enttype; // entity type sent from server
+.int sv_entnum; // entity number sent from server
.int team;
.int team_size;
+++ /dev/null
-#include "effects.qh"
-
-/*
-.vector fx_start;
-.vector fx_end;
-.float fx_with;
-.string fx_texture;
-.float fx_lifetime;
-
-void b_draw()
-{
- //Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, 0, time * 3, '1 1 1', 0.7, DRAWFLAG_ADDITIVE, view_origin);
- Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, (self.fx_with/256), 0, '1 1 1', 1, DRAWFLAG_ADDITIVE, view_origin);
-
-}
-void b_make(vector s,vector e, string t,float l,float z)
-{
- entity b;
- b = spawn();
- b.fx_texture = t;
- b.fx_start = s;
- b.fx_end = e;
- b.fx_with = z;
- b.think = SUB_Remove;
- b.nextthink = time + l;
- b.draw = b_draw;
-
- //b.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
-}
-*/
-
-void cl_effects_lightningarc(vector from, vector to,float seglength,float drifts,float drifte,float branchfactor,float branchfactor_add)
-{
- vector direction,dirnew, pos, pos_l;
- float length, steps, steplength, i,drift;
-
- length = vlen(from - to);
- if(length < 1)
- return;
-
- // Use at most 16 te_lightning1 segments, as these eat up beam list segments.
- // TODO: Change this to R_BeginPolygon code, then we no longer have this limit.
- steps = min(16, floor(length / seglength));
- if(steps < 1)
- {
- te_lightning1(world,from,to);
- return;
- }
-
- steplength = length / steps;
- direction = normalize(to - from);
- pos_l = from;
- if(length > seglength)
- {
- for(i = 1; i < steps; i += 1)
- {
- drift = drifts * (1 - (i / steps)) + drifte * (i / steps);
- dirnew = normalize(direction * (1 - drift) + randomvec() * drift);
- pos = pos_l + dirnew * steplength;
- te_lightning1(world,pos_l,pos);
- // WTF endless recursion if branchfactor is 1.0 (possibly due to adding branchfactor_add). FIXME
- // if(random() < branchfactor)
- // cl_effects_lightningarc(pos, pos + (dirnew * length * 0.25),seglength,drifts,drifte,min(branchfactor + branchfactor_add,1),branchfactor_add);
-
- pos_l = pos;
- }
- te_lightning1(world,pos_l,to);
-
- }
- else
- te_lightning1(world,from,to);
-
-}
-
-void Net_ReadLightningarc()
-{
- vector from, to;
-
- from.x = ReadCoord(); from.y = ReadCoord(); from.z = ReadCoord();
- to.x = ReadCoord(); to.y = ReadCoord(); to.z = ReadCoord();
-
- if(autocvar_cl_effects_lightningarc_simple)
- {
- te_lightning1(world,from,to);
- }
- else
- {
- float seglength, drifts, drifte, branchfactor, branchfactor_add;
-
- seglength = autocvar_cl_effects_lightningarc_segmentlength;
- drifts = autocvar_cl_effects_lightningarc_drift_start;
- drifte = autocvar_cl_effects_lightningarc_drift_end;
- branchfactor = autocvar_cl_effects_lightningarc_branchfactor_start;
- branchfactor_add = autocvar_cl_effects_lightningarc_branchfactor_add;
-
- cl_effects_lightningarc(from,to,seglength,drifts,drifte,branchfactor,branchfactor_add);
- }
-
-}
-void Net_ReadArc() { Net_ReadLightningarc(); }
+++ /dev/null
-#ifndef CLIENT_EFFECTS_H
-#define CLIENT_EFFECTS_H
-
-void Net_ReadArc();
-
-#endif
+++ /dev/null
-#include "generator.qh"
-
-#include "teamradar.qh"
-#include "../common/movetypes/movetypes.qh"
-
-.float alpha;
-.float scale;
-.int count;
-.float max_health;
-
-void ons_generator_ray_draw(entity this)
-{
- if(time < self.move_time)
- return;
-
- self.move_time = time + 0.05;
-
- if(self.count > 10)
- {
- remove(self);
- return;
- }
-
- if(self.count > 5)
- self.alpha -= 0.1;
- else
- self.alpha += 0.1;
-
- self.scale += 0.2;
- self.count +=1;
-}
-
-void ons_generator_ray_spawn(vector org)
-{
- entity e;
- e = spawn();
- e.classname = "ons_ray";
- setmodel(e, MDL_ONS_RAY);
- setorigin(e, org);
- e.angles = randomvec() * 360;
- e.move_origin = org;
- e.movetype = MOVETYPE_NONE;
- e.alpha = 0;
- e.scale = random() * 5 + 8;
- e.move_time = time + 0.05;
- e.drawmask = MASK_NORMAL;
- e.draw = ons_generator_ray_draw;
-}
-
-void generator_draw(entity this)
-{
- if(time < self.move_time)
- return;
-
- if(self.health > 0)
- {
- // damaged fx (less probable the more damaged is the generator)
- if(random() < 0.9 - self.health / self.max_health)
- if(random() < 0.01)
- {
- pointparticles(particleeffectnum(EFFECT_ELECTRO_BALLEXPLODE), self.origin + randompos('-50 -50 -20', '50 50 50'), '0 0 0', 1);
- sound(self, CH_TRIGGER, SND_ONS_ELECTRICITY_EXPLODE, VOL_BASE, ATTEN_NORM);
- }
- else
- pointparticles(particleeffectnum(EFFECT_ONS_GENERATOR_DAMAGED), self.origin + randompos('-60 -60 -20', '60 60 60'), '0 0 0', 1);
-
- self.move_time = time + 0.1;
-
- return;
- }
-
- if(self.count <= 0)
- return;
-
- vector org;
- int i;
-
- // White shockwave
- if(self.count==40||self.count==20)
- {
- sound(self, CH_TRIGGER, SND_ONS_SHOCKWAVE, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_ELECTRO_COMBO), self.origin, '0 0 0', 6);
- }
-
- // rays
- if(random() > 0.25)
- {
- ons_generator_ray_spawn(self.origin);
- }
-
- // Spawn fire balls
- for(i=0;i < 10;++i)
- {
- org = self.origin + randompos('-30 -30 -30' * i + '0 0 -20', '30 30 30' * i + '0 0 20');
- pointparticles(particleeffectnum(EFFECT_ONS_GENERATOR_GIB), org, '0 0 0', 1);
- }
-
- // Short explosion sound + small explosion
- if(random() < 0.25)
- {
- te_explosion(self.origin);
- sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
- }
-
- // Particles
- org = self.origin + randompos(self.mins + '8 8 8', self.maxs + '-8 -8 -8');
- pointparticles(particleeffectnum(EFFECT_ONS_GENERATOR_EXPLODE), org, '0 0 0', 1);
-
- // Final explosion
- if(self.count==1)
- {
- org = self.origin;
- te_explosion(org);
- pointparticles(particleeffectnum(EFFECT_ONS_GENERATOR_EXPLODE2), org, '0 0 0', 1);
- sound(self, CH_TRIGGER, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
- }
-
- self.move_time = time + 0.05;
-
- self.count -= 1;
-}
-
-void generator_damage(float hp)
-{SELFPARAM();
- if(hp <= 0)
- setmodel(self, MDL_ONS_GEN_DEAD);
- else if(hp < self.max_health * 0.10)
- setmodel(self, MDL_ONS_GEN9);
- else if(hp < self.max_health * 0.20)
- setmodel(self, MDL_ONS_GEN8);
- else if(hp < self.max_health * 0.30)
- setmodel(self, MDL_ONS_GEN7);
- else if(hp < self.max_health * 0.40)
- setmodel(self, MDL_ONS_GEN6);
- else if(hp < self.max_health * 0.50)
- setmodel(self, MDL_ONS_GEN5);
- else if(hp < self.max_health * 0.60)
- setmodel(self, MDL_ONS_GEN4);
- else if(hp < self.max_health * 0.70)
- setmodel(self, MDL_ONS_GEN3);
- else if(hp < self.max_health * 0.80)
- setmodel(self, MDL_ONS_GEN2);
- else if(hp < self.max_health * 0.90)
- setmodel(self, MDL_ONS_GEN1);
- else if(hp <= self.max_health || hp >= self.max_health)
- setmodel(self, MDL_ONS_GEN);
-
- setsize(self, GENERATOR_MIN, GENERATOR_MAX);
-}
-
-void generator_construct()
-{SELFPARAM();
- self.netname = "Generator";
- self.classname = "onslaught_generator";
-
- setorigin(self, self.origin);
- setmodel(self, MDL_ONS_GEN);
- setsize(self, GENERATOR_MIN, GENERATOR_MAX);
-
- self.move_movetype = MOVETYPE_NOCLIP;
- self.solid = SOLID_BBOX;
- self.movetype = MOVETYPE_NOCLIP;
- self.move_origin = self.origin;
- self.move_time = time;
- self.drawmask = MASK_NORMAL;
- self.alpha = 1;
- self.draw = generator_draw;
-}
-
-.vector glowmod;
-void generator_changeteam()
-{SELFPARAM();
- if(self.team)
- {
- self.glowmod = Team_ColorRGB(self.team - 1);
- self.teamradar_color = Team_ColorRGB(self.team - 1);
- self.colormap = 1024 + (self.team - 1) * 17;
- }
- else
- {
- self.colormap = 1024;
- self.glowmod = '1 1 0';
- self.teamradar_color = '1 1 0';
- }
-}
-
-void ent_generator()
-{SELFPARAM();
- int sf = ReadByte();
-
- if(sf & GSF_SETUP)
- {
- self.origin_x = ReadCoord();
- self.origin_y = ReadCoord();
- self.origin_z = ReadCoord();
- setorigin(self, self.origin);
-
- self.health = ReadByte();
- self.max_health = ReadByte();
- self.count = ReadByte();
- self.team = ReadByte();
-
- if(!self.count)
- self.count = 40;
-
- generator_changeteam();
- generator_construct();
- }
-
- if(sf & GSF_STATUS)
- {
- int _tmp;
- _tmp = ReadByte();
- if(_tmp != self.team)
- {
- self.team = _tmp;
- generator_changeteam();
- }
-
- _tmp = ReadByte();
-
- if(_tmp != self.health)
- generator_damage(_tmp);
-
- self.health = _tmp;
- }
-}
+++ /dev/null
-#ifndef CLIENT_GENERATOR_H
-#define CLIENT_GENERATOR_H
-const vector GENERATOR_MIN = '-52 -52 -14';
-const vector GENERATOR_MAX = '52 52 75';
-
-const int GSF_STATUS = 4;
-const int GSF_SETUP = 8;
-
-void ent_generator();
-#endif
+++ /dev/null
-#include "gibs.qh"
-
-#include "rubble.qh"
-#include "../common/movetypes/movetypes.qh"
-
-.float scale;
-.float alpha;
-.float cnt;
-.float gravity;
-
-void Gib_Delete()
-{SELFPARAM();
- remove(self);
-}
-
-string species_prefix(int specnum)
-{
- switch(specnum)
- {
- case SPECIES_HUMAN: return "";
- case SPECIES_ALIEN: return "alien_";
- case SPECIES_ROBOT_SHINY: return "robot_";
- case SPECIES_ROBOT_RUSTY: return "robot_"; // use the same effects, only different gibs
- case SPECIES_ROBOT_SOLID: return "robot_"; // use the same effects, only different gibs
- case SPECIES_ANIMAL: return "animal_";
- case SPECIES_RESERVED: return "reserved_";
- default: return "";
- }
-}
-
-void Gib_setmodel(entity gib, string mdlname, int specnum)
-{
- switch(specnum)
- {
- case SPECIES_ROBOT_RUSTY:
- case SPECIES_ROBOT_SHINY:
- case SPECIES_ROBOT_SOLID:
- if(specnum != SPECIES_ROBOT_SOLID || mdlname == "models/gibs/chunk.mdl")
- {
- if(mdlname == "models/gibs/bloodyskull.md3")
- setmodel(gib, MDL_GIB_ROBO);
- else
- setmodel(gib, MDL_GIB_ROBO_RANDOM());
- if(specnum == SPECIES_ROBOT_SHINY)
- {
- gib.skin = 1;
- gib.colormod = '2 2 2';
- }
- gib.scale = 1;
- break;
- }
- default:
- _setmodel(gib, mdlname);
- gib.skin = specnum;
- break;
- }
-}
-
-void new_te_bloodshower (int ef, vector org, float explosionspeed, int howmany)
-{
- float i, pmod;
- pmod = autocvar_cl_particles_quality;
- for (i = 0; i < 50 * pmod; ++i)
- pointparticles(ef, org, randomvec() * explosionspeed, howmany / 50);
-}
-
-void SUB_RemoveOnNoImpact()
-{
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
- Gib_Delete();
-}
-
-void Gib_Touch()
-{SELFPARAM();
- // TODO maybe bounce of walls, make more gibs, etc.
-
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
- {
- Gib_Delete();
- return;
- }
-
- if(!self.silent)
- sound(self, CH_PAIN, SND_GIB_SPLAT_RANDOM(), VOL_BASE, ATTEN_NORM);
- pointparticles(_particleeffectnum(strcat(species_prefix(self.cnt), "blood")), self.origin + '0 0 1', '0 0 30', 10);
-
- Gib_Delete();
-}
-
-void Gib_Draw(entity this)
-{
- vector oldorg;
- oldorg = self.origin;
-
- Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
- if(wasfreed(self))
- return;
-
- if(self.touch == Gib_Touch) // don't do this for the "chunk" thingie...
- // TODO somehow make it spray in a direction dependent on self.angles
- trailparticles(self, _particleeffectnum(strcat(species_prefix(self.cnt), EFFECT_TR_SLIGHTBLOOD.eent_eff_name)), oldorg, self.origin);
- else
- trailparticles(self, _particleeffectnum(strcat(species_prefix(self.cnt), EFFECT_TR_BLOOD.eent_eff_name)), oldorg, self.origin);
-
- self.renderflags = 0;
-
- // make gibs die faster at low view quality
- // if view_quality is 0.5, we want to have them die twice as fast
- self.nextthink -= frametime * (1 / bound(0.01, view_quality, 1.00) - 1);
-
- self.alpha = bound(0, self.nextthink - time, 1);
-
- if(self.alpha < ALPHA_MIN_VISIBLE)
- {
- self.drawmask = 0;
- Gib_Delete();
- }
-}
-
-void TossGib (string mdlname, vector safeorg, vector org, vector vconst, vector vrand, int specnum, bool destroyontouch, bool issilent)
-{
- entity gib;
-
- // TODO remove some gibs according to cl_nogibs
- gib = RubbleNew("gib");
- gib.classname = "gib";
- gib.move_movetype = MOVETYPE_BOUNCE;
- gib.gravity = 1;
- gib.solid = SOLID_CORPSE;
- gib.cnt = specnum;
- gib.silent = issilent;
- Gib_setmodel(gib, mdlname, specnum);
-
- setsize (gib, '-8 -8 -8', '8 8 8');
-
- gib.draw = Gib_Draw;
- if(destroyontouch)
- gib.move_touch = Gib_Touch;
- else
- gib.move_touch = SUB_RemoveOnNoImpact;
-
- // don't spawn gibs inside solid - just don't
- if(org != safeorg)
- {
- tracebox(safeorg, gib.mins, gib.maxs, org, MOVE_NOMONSTERS, gib);
- org = trace_endpos;
- }
-
- gib.move_origin = org;
- setorigin(gib, org);
- gib.move_velocity = vconst * autocvar_cl_gibs_velocity_scale + vrand * autocvar_cl_gibs_velocity_random + '0 0 1' * autocvar_cl_gibs_velocity_up;
- gib.move_avelocity = prandomvec() * vlen(gib.move_velocity) * autocvar_cl_gibs_avelocity_scale;
- gib.move_time = time;
- gib.damageforcescale = autocvar_cl_gibs_damageforcescale;
-
- gib.nextthink = time + autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15);
- gib.drawmask = MASK_NORMAL;
-
- RubbleLimit("gib", autocvar_cl_gibs_maxcount, Gib_Delete);
-}
-
-void Ent_GibSplash(bool isNew)
-{SELFPARAM();
- int amount, type, specnum;
- vector org, vel;
- string specstr;
- bool issilent;
- string gentle_prefix = "morphed_";
-
- float randomvalue;
- int c;
-
- type = ReadByte(); // gibbage type
- amount = ReadByte() / 16.0; // gibbage amount
- org.x = ReadShort() * 4 + 2;
- org.y = ReadShort() * 4 + 2;
- org.z = ReadShort() * 4 + 2;
- vel = decompressShortVector(ReadShort());
-
- float cl_gentle_gibs = autocvar_cl_gentle_gibs;
- if(cl_gentle_gibs || autocvar_cl_gentle)
- type |= 0x80; // set gentle bit
-
- if(type & 0x80)
- {
- if(cl_gentle_gibs == 2)
- gentle_prefix = "";
- else if(cl_gentle_gibs == 3)
- gentle_prefix = "happy_";
- }
- else if(autocvar_cl_particlegibs)
- {
- type |= 0x80;
- gentle_prefix = "particlegibs_";
- }
-
- if (!(cl_gentle_gibs || autocvar_cl_gentle))
- amount *= 1 - autocvar_cl_nogibs;
-
- if(autocvar_ekg)
- amount *= 5;
-
- if(amount <= 0 || !isNew)
- return;
-
- setorigin(self, org); // for the sounds
-
- specnum = (type & 0x78) / 8; // blood/gibmodel type: using four bits (0..7, bit indexes 3,4,5)
- issilent = (type & 0x40);
- type = type & 0x87; // remove the species bits: bit 7 = gentle, bit 0,1,2 = kind of gib
- specstr = species_prefix(specnum);
-
- switch(type)
- {
- case 0x01:
- if(!issilent)
- sound (self, CH_PAIN, SND_GIB, VOL_BASE, ATTEN_NORM);
-
- if(prandom() < amount)
- TossGib ("models/gibs/eye.md3", org, org, vel, prandomvec() * 150, specnum, 0, issilent);
- new_te_bloodshower(_particleeffectnum(strcat(specstr, "bloodshower")), org, 1200, amount);
- if(prandom() < amount)
- TossGib ("models/gibs/bloodyskull.md3", org, org + 16 * prandomvec(), vel, prandomvec() * 100, specnum, 0, issilent);
-
- for(c = 0; c < amount; ++c)
- {
- randomvalue = amount - c;
-
- if(prandom() < randomvalue)
- TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
- if(prandom() < randomvalue)
- TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
- if(prandom() < randomvalue)
- TossGib ("models/gibs/chest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
- if(prandom() < randomvalue)
- TossGib ("models/gibs/smallchest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
- if(prandom() < randomvalue)
- TossGib ("models/gibs/leg1.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
- if(prandom() < randomvalue)
- TossGib ("models/gibs/leg2.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
-
- // these splat on impact
- if(prandom() < randomvalue)
- TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
- if(prandom() < randomvalue)
- TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
- if(prandom() < randomvalue)
- TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
- if(prandom() < randomvalue)
- TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
- }
- break;
- case 0x02:
- pointparticles(_particleeffectnum(strcat(specstr, "blood")), org, vel, amount * 16);
- break;
- case 0x03:
- if(prandom() < amount)
- TossGib ("models/gibs/chunk.mdl", org, org, vel, prandomvec() * (prandom() * 30 + 20), specnum, 1, issilent); // TODO maybe adjust to more randomization?
- break;
- case 0x81:
- pointparticles(_particleeffectnum(strcat(gentle_prefix, "damage_dissolve")), org, vel, amount);
- break;
- case 0x82:
- pointparticles(_particleeffectnum(strcat(gentle_prefix, "damage_hit")), org, vel, amount * 16);
- break;
- case 0x83:
- // no gibs in gentle mode, sorry
- break;
- }
-}
+++ /dev/null
-#ifndef CLIENT_GIBS_H
-#define CLIENT_GIBS_H
-
-.vector colormod;
-
-.bool silent;
-
-void Gib_Delete();
-
-string species_prefix(int specnum);
-
-void Gib_setmodel(entity gib, string mdlname, int specnum);
-
-void new_te_bloodshower (int ef, vector org, float explosionspeed, int howmany);
-
-void SUB_RemoveOnNoImpact();
-
-void Gib_Touch();
-
-void Gib_Draw(entity this);
-
-void TossGib (string mdlname, vector safeorg, vector org, vector vconst, vector vrand, int specnum, bool destroyontouch, bool issilent);
-
-void Ent_GibSplash(bool isNew);
-
-#endif
#include "../lib/warpzone/common.qh"
entityclass(Hook);
-class(Hook) .float HookType; // ENT_CLIENT_*
+class(Hook) .entity HookType; // ENT_CLIENT_*
class(Hook) .vector origin;
class(Hook) .vector velocity;
class(Hook) .float HookSilent;
switch(self.HookType)
{
default:
- case ENT_CLIENT_HOOK:
+ case NET_ENT_CLIENT_HOOK:
vs = hook_shotorigin[s];
break;
- case ENT_CLIENT_ARC_BEAM:
+ case NET_ENT_CLIENT_ARC_BEAM:
vs = lightning_shotorigin[s];
break;
}
switch(self.HookType)
{
default:
- case ENT_CLIENT_HOOK:
+ case NET_ENT_CLIENT_HOOK:
a = view_origin + view_forward * vs.x + view_right * -vs.y + view_up * vs.z;
b = self.origin;
break;
- case ENT_CLIENT_ARC_BEAM:
+ case NET_ENT_CLIENT_ARC_BEAM:
if(self.HookRange)
b = view_origin + view_forward * self.HookRange;
else
switch(self.HookType)
{
default:
- case ENT_CLIENT_HOOK:
+ case NET_ENT_CLIENT_HOOK:
a = self.velocity;
b = self.origin;
break;
- case ENT_CLIENT_ARC_BEAM:
+ case NET_ENT_CLIENT_ARC_BEAM:
a = self.origin;
b = self.velocity;
break;
switch(self.HookType)
{
default:
- case ENT_CLIENT_HOOK:
+ case NET_ENT_CLIENT_HOOK:
intensity = 1;
offset = 0;
switch(t)
default: tex = "particles/hook_white"; rgb = getcsqcplayercolor(self.sv_entnum); break;
}
break;
- case ENT_CLIENT_ARC_BEAM: // todo
+ case NET_ENT_CLIENT_ARC_BEAM: // todo
intensity = bound(0.2, 1 + Noise_Pink(self, frametime) * 1 + Noise_Burst(self, frametime, 0.03) * 0.3, 2);
offset = Noise_Brown(self, frametime) * 10;
tex = "particles/lgbeam";
Draw_GrapplingHook_trace_callback_rnd = offset;
Draw_GrapplingHook_trace_callback_rgb = rgb;
Draw_GrapplingHook_trace_callback_a = intensity;
- WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, ((self.HookType == ENT_CLIENT_HOOK) ? MOVE_NOTHING : MOVE_NORMAL), world, world, Draw_GrapplingHook_trace_callback);
+ WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, ((self.HookType == NET_ENT_CLIENT_HOOK) ? MOVE_NOTHING : MOVE_NORMAL), world, world, Draw_GrapplingHook_trace_callback);
Draw_GrapplingHook_trace_callback_tex = string_null;
atrans = WarpZone_TransformOrigin(WarpZone_trace_transform, a);
switch(self.HookType)
{
default:
- case ENT_CLIENT_HOOK:
+ case NET_ENT_CLIENT_HOOK:
if(vlen(trace_endpos - atrans) > 0.5)
{
setorigin(self, trace_endpos); // hook endpoint!
self.drawmask = 0;
}
break;
- case ENT_CLIENT_ARC_BEAM:
+ case NET_ENT_CLIENT_ARC_BEAM:
setorigin(self, a); // beam origin!
break;
}
switch(self.HookType)
{
default:
- case ENT_CLIENT_HOOK:
+ case NET_ENT_CLIENT_HOOK:
break;
- case ENT_CLIENT_ARC_BEAM:
- pointparticles(particleeffectnum(EFFECT_ARC_LIGHTNING2), trace_endpos, normalize(atrans - trace_endpos), frametime * intensity); // todo: new effect
+ case NET_ENT_CLIENT_ARC_BEAM:
+ pointparticles(EFFECT_ARC_LIGHTNING2, trace_endpos, normalize(atrans - trace_endpos), frametime * intensity); // todo: new effect
break;
}
}
sound (self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
}
-void Ent_ReadHook(float bIsNew, float type)
-{SELFPARAM();
- self.HookType = type;
+NET_HANDLE(ENT_CLIENT_HOOK, bool bIsNew)
+{
+ self.HookType = NET_ENT_CLIENT_HOOK;
int sf = ReadByte();
switch(self.HookType)
{
default:
- case ENT_CLIENT_HOOK:
+ case NET_ENT_CLIENT_HOOK:
self.HookRange = 0;
break;
- case ENT_CLIENT_ARC_BEAM:
+ case NET_ENT_CLIENT_ARC_BEAM:
self.HookRange = ReadCoord();
break;
}
switch(self.HookType)
{
default:
- case ENT_CLIENT_HOOK:
+ case NET_ENT_CLIENT_HOOK:
// for the model
setmodel(self, MDL_HOOK);
self.drawmask = MASK_NORMAL;
break;
- case ENT_CLIENT_ARC_BEAM:
+ case NET_ENT_CLIENT_ARC_BEAM:
sound (self, CH_SHOTS_SINGLE, SND_LGBEAM_FLY, VOL_BASE, ATTEN_NORM);
break;
}
}
self.teleport_time = time + 10;
+ return true;
}
// TODO: hook: temporarily transform self.origin for drawing the model along warpzones!
void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg);
-void Ent_ReadHook(float bIsNew, float type);
-
#endif
+++ /dev/null
-#include "hud.qh"
-
-#include "hud_config.qh"
-#include "mapvoting.qh"
-#include "scoreboard.qh"
-#include "teamradar.qh"
-#include "t_items.qh"
-#include "../common/buffs/all.qh"
-#include "../common/deathtypes/all.qh"
-#include "../common/items/all.qc"
-#include "../common/mapinfo.qh"
-#include "../common/mutators/mutator/waypoints/all.qh"
-#include "../common/nades/all.qh"
-#include "../common/stats.qh"
-#include "../lib/csqcmodel/cl_player.qh"
-// TODO: remove
-#include "../server/mutators/mutator/gamemode_ctf.qc"
-
-
-/*
-==================
-Misc HUD functions
-==================
-*/
-
-vector HUD_Get_Num_Color (float x, float maxvalue)
-{
- float blinkingamt;
- vector color;
- if(x >= maxvalue) {
- color.x = sin(2*M_PI*time);
- color.y = 1;
- color.z = sin(2*M_PI*time);
- }
- else if(x > maxvalue * 0.75) {
- color.x = 0.4 - (x-150)*0.02 * 0.4; //red value between 0.4 -> 0
- color.y = 0.9 + (x-150)*0.02 * 0.1; // green value between 0.9 -> 1
- color.z = 0;
- }
- else if(x > maxvalue * 0.5) {
- color.x = 1 - (x-100)*0.02 * 0.6; //red value between 1 -> 0.4
- color.y = 1 - (x-100)*0.02 * 0.1; // green value between 1 -> 0.9
- color.z = 1 - (x-100)*0.02; // blue value between 1 -> 0
- }
- else if(x > maxvalue * 0.25) {
- color.x = 1;
- color.y = 1;
- color.z = 0.2 + (x-50)*0.02 * 0.8; // blue value between 0.2 -> 1
- }
- else if(x > maxvalue * 0.1) {
- color.x = 1;
- color.y = (x-20)*90/27/100; // green value between 0 -> 1
- color.z = (x-20)*90/27/100 * 0.2; // blue value between 0 -> 0.2
- }
- else {
- color.x = 1;
- color.y = 0;
- color.z = 0;
- }
-
- blinkingamt = (1 - x/maxvalue/0.25);
- if(blinkingamt > 0)
- {
- color.x = color.x - color.x * blinkingamt * sin(2*M_PI*time);
- color.y = color.y - color.y * blinkingamt * sin(2*M_PI*time);
- color.z = color.z - color.z * blinkingamt * sin(2*M_PI*time);
- }
- return color;
-}
-
-float HUD_GetRowCount(int item_count, vector size, float item_aspect)
-{
- float aspect = size_y / size_x;
- return bound(1, floor((sqrt(4 * item_aspect * aspect * item_count + aspect * aspect) + aspect + 0.5) / 2), item_count);
-}
-
-vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect)
-{
- float columns, rows;
- float ratio, best_ratio = 0;
- float best_columns = 1, best_rows = 1;
- bool vertical = (psize.x / psize.y >= item_aspect);
- if(vertical)
- {
- psize = eX * psize.y + eY * psize.x;
- item_aspect = 1 / item_aspect;
- }
-
- rows = ceil(sqrt(item_count));
- columns = ceil(item_count/rows);
- while(columns >= 1)
- {
- ratio = (psize.x/columns) / (psize.y/rows);
- if(ratio > item_aspect)
- ratio = item_aspect * item_aspect / ratio;
-
- if(ratio <= best_ratio)
- break; // ratio starts decreasing by now, skip next configurations
-
- best_columns = columns;
- best_rows = rows;
- best_ratio = ratio;
-
- if(columns == 1)
- break;
-
- --columns;
- rows = ceil(item_count/columns);
- }
-
- if(vertical)
- return eX * best_rows + eY * best_columns;
- else
- return eX * best_columns + eY * best_rows;
-}
-
-// return the string of the onscreen race timer
-string MakeRaceString(int cp, float mytime, float theirtime, float lapdelta, string theirname)
-{
- string col;
- string timestr;
- string cpname;
- string lapstr;
- lapstr = "";
-
- if(theirtime == 0) // goal hit
- {
- if(mytime > 0)
- {
- timestr = strcat("+", ftos_decimals(+mytime, TIME_DECIMALS));
- col = "^1";
- }
- else if(mytime == 0)
- {
- timestr = "+0.0";
- col = "^3";
- }
- else
- {
- timestr = strcat("-", ftos_decimals(-mytime, TIME_DECIMALS));
- col = "^2";
- }
-
- if(lapdelta > 0)
- {
- lapstr = sprintf(_(" (-%dL)"), lapdelta);
- col = "^2";
- }
- else if(lapdelta < 0)
- {
- lapstr = sprintf(_(" (+%dL)"), -lapdelta);
- col = "^1";
- }
- }
- else if(theirtime > 0) // anticipation
- {
- if(mytime >= theirtime)
- timestr = strcat("+", ftos_decimals(mytime - theirtime, TIME_DECIMALS));
- else
- timestr = TIME_ENCODED_TOSTRING(TIME_ENCODE(theirtime));
- col = "^3";
- }
- else
- {
- col = "^7";
- timestr = "";
- }
-
- if(cp == 254)
- cpname = _("Start line");
- else if(cp == 255)
- cpname = _("Finish line");
- else if(cp)
- cpname = sprintf(_("Intermediate %d"), cp);
- else
- cpname = _("Finish line");
-
- if(theirtime < 0)
- return strcat(col, cpname);
- else if(theirname == "")
- return strcat(col, sprintf("%s (%s)", cpname, timestr));
- else
- return strcat(col, sprintf("%s (%s %s)", cpname, timestr, strcat(theirname, col, lapstr)));
-}
-
-// Check if the given name already exist in race rankings? In that case, where? (otherwise return 0)
-int race_CheckName(string net_name)
-{
- int i;
- for (i=RANKINGS_CNT-1;i>=0;--i)
- if(grecordholder[i] == net_name)
- return i+1;
- return 0;
-}
-
-/*
-==================
-HUD panels
-==================
-*/
-
-//basically the same code of draw_ButtonPicture and draw_VertButtonPicture for the menu
-void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag)
-{
- if(!length_ratio || !theAlpha)
- return;
- if(length_ratio > 1)
- length_ratio = 1;
- if (baralign == 3)
- {
- if(length_ratio < -1)
- length_ratio = -1;
- }
- else if(length_ratio < 0)
- return;
-
- vector square;
- vector width, height;
- if(vertical) {
- pic = strcat(hud_skin_path, "/", pic, "_vertical");
- if(precache_pic(pic) == "") {
- pic = "gfx/hud/default/progressbar_vertical";
- }
-
- if (baralign == 1) // bottom align
- theOrigin.y += (1 - length_ratio) * theSize.y;
- else if (baralign == 2) // center align
- theOrigin.y += 0.5 * (1 - length_ratio) * theSize.y;
- else if (baralign == 3) // center align, positive values down, negative up
- {
- theSize.y *= 0.5;
- if (length_ratio > 0)
- theOrigin.y += theSize.y;
- else
- {
- theOrigin.y += (1 + length_ratio) * theSize.y;
- length_ratio = -length_ratio;
- }
- }
- theSize.y *= length_ratio;
-
- vector bH;
- width = eX * theSize.x;
- height = eY * theSize.y;
- if(theSize.y <= theSize.x * 2)
- {
- // button not high enough
- // draw just upper and lower part then
- square = eY * theSize.y * 0.5;
- bH = eY * (0.25 * theSize.y / (theSize.x * 2));
- drawsubpic(theOrigin, square + width, pic, '0 0 0', eX + bH, theColor, theAlpha, drawflag);
- drawsubpic(theOrigin + square, square + width, pic, eY - bH, eX + bH, theColor, theAlpha, drawflag);
- }
- else
- {
- square = eY * theSize.x;
- drawsubpic(theOrigin, width + square, pic, '0 0 0', '1 0.25 0', theColor, theAlpha, drawflag);
- drawsubpic(theOrigin + square, theSize - 2 * square, pic, '0 0.25 0', '1 0.5 0', theColor, theAlpha, drawflag);
- drawsubpic(theOrigin + height - square, width + square, pic, '0 0.75 0', '1 0.25 0', theColor, theAlpha, drawflag);
- }
- } else {
- pic = strcat(hud_skin_path, "/", pic);
- if(precache_pic(pic) == "") {
- pic = "gfx/hud/default/progressbar";
- }
-
- if (baralign == 1) // right align
- theOrigin.x += (1 - length_ratio) * theSize.x;
- else if (baralign == 2) // center align
- theOrigin.x += 0.5 * (1 - length_ratio) * theSize.x;
- else if (baralign == 3) // center align, positive values on the right, negative on the left
- {
- theSize.x *= 0.5;
- if (length_ratio > 0)
- theOrigin.x += theSize.x;
- else
- {
- theOrigin.x += (1 + length_ratio) * theSize.x;
- length_ratio = -length_ratio;
- }
- }
- theSize.x *= length_ratio;
-
- vector bW;
- width = eX * theSize.x;
- height = eY * theSize.y;
- if(theSize.x <= theSize.y * 2)
- {
- // button not wide enough
- // draw just left and right part then
- square = eX * theSize.x * 0.5;
- bW = eX * (0.25 * theSize.x / (theSize.y * 2));
- drawsubpic(theOrigin, square + height, pic, '0 0 0', eY + bW, theColor, theAlpha, drawflag);
- drawsubpic(theOrigin + square, square + height, pic, eX - bW, eY + bW, theColor, theAlpha, drawflag);
- }
- else
- {
- square = eX * theSize.y;
- drawsubpic(theOrigin, height + square, pic, '0 0 0', '0.25 1 0', theColor, theAlpha, drawflag);
- drawsubpic(theOrigin + square, theSize - 2 * square, pic, '0.25 0 0', '0.5 1 0', theColor, theAlpha, drawflag);
- drawsubpic(theOrigin + width - square, height + square, pic, '0.75 0 0', '0.25 1 0', theColor, theAlpha, drawflag);
- }
- }
-}
-
-void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theAlpha, int drawflag)
-{
- if(!theAlpha)
- return;
-
- string pic;
- pic = strcat(hud_skin_path, "/num_leading");
- if(precache_pic(pic) == "") {
- pic = "gfx/hud/default/num_leading";
- }
-
- drawsubpic(pos, eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0 0 0', '0.25 1 0', color, theAlpha, drawflag);
- if(mySize.x/mySize.y > 2)
- drawsubpic(pos + eX * mySize.y, eX * (mySize.x - 2 * mySize.y) + eY * mySize.y, pic, '0.25 0 0', '0.5 1 0', color, theAlpha, drawflag);
- drawsubpic(pos + eX * mySize.x - eX * min(mySize.x * 0.5, mySize.y), eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0.75 0 0', '0.25 1 0', color, theAlpha, drawflag);
-}
-
-// Weapon icons (#0)
-//
-entity weaponorder[Weapons_MAX];
-void weaponorder_swap(int i, int j, entity pass)
-{
- entity h = weaponorder[i];
- weaponorder[i] = weaponorder[j];
- weaponorder[j] = h;
-}
-
-string weaponorder_cmp_str;
-int weaponorder_cmp(int i, int j, entity pass)
-{
- int ai, aj;
- ai = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[i].weapon), 0);
- aj = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[j].weapon), 0);
- return aj - ai; // the string is in REVERSE order (higher prio at the right is what we want, but higher prio first is the string)
-}
-
-void HUD_Weapons(void)
-{SELFPARAM();
- // declarations
- WepSet weapons_stat = WepSet_GetFromStat();
- int i;
- float f, a;
- float screen_ar;
- vector center = '0 0 0';
- int weapon_count, weapon_id;
- int row, column, rows = 0, columns = 0;
- bool vertical_order = true;
- float aspect = autocvar_hud_panel_weapons_aspect;
-
- float timeout = autocvar_hud_panel_weapons_timeout;
- float timein_effect_length = autocvar_hud_panel_weapons_timeout_speed_in; //? 0.375 : 0);
- float timeout_effect_length = autocvar_hud_panel_weapons_timeout_speed_out; //? 0.75 : 0);
-
- vector barsize = '0 0 0', baroffset = '0 0 0';
- vector ammo_color = '1 0 1';
- float ammo_alpha = 1;
-
- float when = max(1, autocvar_hud_panel_weapons_complainbubble_time);
- float fadetime = max(0, autocvar_hud_panel_weapons_complainbubble_fadetime);
-
- vector weapon_pos, weapon_size = '0 0 0';
- vector color;
-
- // check to see if we want to continue
- if(hud != HUD_NORMAL) return;
-
- if(!autocvar__hud_configure)
- {
- if((!autocvar_hud_panel_weapons) || (spectatee_status == -1))
- return;
- if(timeout && time >= weapontime + timeout + timeout_effect_length)
- if(autocvar_hud_panel_weapons_timeout_effect == 3 || (autocvar_hud_panel_weapons_timeout_effect == 1 && !(autocvar_hud_panel_weapons_timeout_fadebgmin + autocvar_hud_panel_weapons_timeout_fadefgmin)))
- {
- weaponprevtime = time;
- return;
- }
- }
-
- // update generic hud functions
- HUD_Panel_UpdateCvars();
-
- // figure out weapon order (how the weapons are sorted) // TODO make this configurable
- if(weaponorder_bypriority != autocvar_cl_weaponpriority || !weaponorder[0])
- {
- int weapon_cnt;
- if(weaponorder_bypriority)
- strunzone(weaponorder_bypriority);
- if(weaponorder_byimpulse)
- strunzone(weaponorder_byimpulse);
-
- weaponorder_bypriority = strzone(autocvar_cl_weaponpriority);
- weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(W_FixWeaponOrder_ForceComplete(W_NumberWeaponOrder(weaponorder_bypriority))));
- weaponorder_cmp_str = strcat(" ", weaponorder_byimpulse, " ");
-
- weapon_cnt = 0;
- for(i = WEP_FIRST; i <= WEP_LAST; ++i)
- {
- setself(get_weaponinfo(i));
- if(self.impulse >= 0)
- {
- weaponorder[weapon_cnt] = self;
- ++weapon_cnt;
- }
- }
- for(i = weapon_cnt; i < Weapons_MAX; ++i)
- weaponorder[i] = world;
- heapsort(weapon_cnt, weaponorder_swap, weaponorder_cmp, world);
-
- weaponorder_cmp_str = string_null;
- }
-
- if(!autocvar_hud_panel_weapons_complainbubble || autocvar__hud_configure || time - complain_weapon_time >= when + fadetime)
- complain_weapon = 0;
-
- if(autocvar__hud_configure)
- {
- if(!weapons_stat)
- for(i = WEP_FIRST; i <= WEP_LAST; i += floor((WEP_LAST-WEP_FIRST)/5))
- weapons_stat |= WepSet_FromWeapon(i);
-
- #if 0
- /// debug code
- if(cvar("wep_add"))
- {
- weapons_stat = '0 0 0';
- float countw = 1 + floor((floor(time * cvar("wep_add"))) % (Weapons_COUNT - 1));
- for(i = WEP_FIRST; i <= countw; ++i)
- weapons_stat |= WepSet_FromWeapon(i);
- }
- #endif
- }
-
- // determine which weapons are going to be shown
- if (autocvar_hud_panel_weapons_onlyowned)
- {
- if(autocvar__hud_configure)
- {
- if(menu_enabled != 2)
- HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
- }
-
- // do we own this weapon?
- weapon_count = 0;
- for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
- if((weapons_stat & WepSet_FromWeapon(weaponorder[i].weapon)) || (weaponorder[i].weapon == complain_weapon))
- ++weapon_count;
-
-
- // might as well commit suicide now, no reason to live ;)
- if (weapon_count == 0)
- return;
-
- vector old_panel_size = panel_size;
- vector padded_panel_size = panel_size - '2 2 0' * panel_bg_padding;
-
- // get the all-weapons layout
- int nHidden = 0;
- WepSet weapons_stat = WepSet_GetFromStat();
- for (int i = WEP_FIRST; i <= WEP_LAST; ++i) {
- WepSet weapons_wep = WepSet_FromWeapon(i);
- if (weapons_stat & weapons_wep) continue;
- Weapon w = get_weaponinfo(i);
- if (w.spawnflags & WEP_FLAG_MUTATORBLOCKED) nHidden += 1;
- }
- vector table_size = HUD_GetTableSize_BestItemAR((Weapons_COUNT - 1) - nHidden, padded_panel_size, aspect);
- columns = table_size.x;
- rows = table_size.y;
- weapon_size.x = padded_panel_size.x / columns;
- weapon_size.y = padded_panel_size.y / rows;
-
- // NOTE: although weapons should aways look the same even if onlyowned is enabled,
- // we enlarge them a bit when possible to better match the desired aspect ratio
- if(padded_panel_size.x / padded_panel_size.y < aspect)
- {
- // maximum number of rows that allows to display items with the desired aspect ratio
- int max_rows = floor(padded_panel_size.y / (weapon_size.x / aspect));
- columns = min(columns, ceil(weapon_count / max_rows));
- rows = ceil(weapon_count / columns);
- weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
- weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
- vertical_order = false;
- }
- else
- {
- int max_columns = floor(padded_panel_size.x / (weapon_size.y * aspect));
- rows = min(rows, ceil(weapon_count / max_columns));
- columns = ceil(weapon_count / rows);
- weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
- weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
- vertical_order = true;
- }
-
- // reduce size of the panel
- panel_size.x = columns * weapon_size.x;
- panel_size.y = rows * weapon_size.y;
- panel_size += '2 2 0' * panel_bg_padding;
-
- // center the resized panel, or snap it to the screen edge when close enough
- if(panel_pos.x > vid_conwidth * 0.001)
- {
- if(panel_pos.x + old_panel_size.x > vid_conwidth * 0.999)
- panel_pos.x += old_panel_size.x - panel_size.x;
- else
- panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
- }
- else if(old_panel_size.x > vid_conwidth * 0.999)
- panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
-
- if(panel_pos.y > vid_conheight * 0.001)
- {
- if(panel_pos.y + old_panel_size.y > vid_conheight * 0.999)
- panel_pos.y += old_panel_size.y - panel_size.y;
- else
- panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
- }
- else if(old_panel_size.y > vid_conheight * 0.999)
- panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
- }
- else
- weapon_count = (Weapons_COUNT - 1);
-
- // animation for fading in/out the panel respectively when not in use
- if(!autocvar__hud_configure)
- {
- if (timeout && time >= weapontime + timeout) // apply timeout effect if needed
- {
- f = bound(0, (time - (weapontime + timeout)) / timeout_effect_length, 1);
-
- // fade the panel alpha
- if(autocvar_hud_panel_weapons_timeout_effect == 1)
- {
- panel_bg_alpha *= (autocvar_hud_panel_weapons_timeout_fadebgmin * f + (1 - f));
- panel_fg_alpha *= (autocvar_hud_panel_weapons_timeout_fadefgmin * f + (1 - f));
- }
- else if(autocvar_hud_panel_weapons_timeout_effect == 3)
- {
- panel_bg_alpha *= (1 - f);
- panel_fg_alpha *= (1 - f);
- }
-
- // move the panel off the screen
- if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
- {
- f *= f; // for a cooler movement
- center.x = panel_pos.x + panel_size.x/2;
- center.y = panel_pos.y + panel_size.y/2;
- screen_ar = vid_conwidth/vid_conheight;
- if (center.x/center.y < screen_ar) //bottom left
- {
- if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
- panel_pos.y += f * (vid_conheight - panel_pos.y);
- else //left
- panel_pos.x -= f * (panel_pos.x + panel_size.x);
- }
- else //top right
- {
- if ((vid_conwidth - center.x)/center.y < screen_ar) //right
- panel_pos.x += f * (vid_conwidth - panel_pos.x);
- else //top
- panel_pos.y -= f * (panel_pos.y + panel_size.y);
- }
- if(f == 1)
- center.x = -1; // mark the panel as off screen
- }
- weaponprevtime = time - (1 - f) * timein_effect_length;
- }
- else if (timeout && time < weaponprevtime + timein_effect_length) // apply timein effect if needed
- {
- f = bound(0, (time - weaponprevtime) / timein_effect_length, 1);
-
- // fade the panel alpha
- if(autocvar_hud_panel_weapons_timeout_effect == 1)
- {
- panel_bg_alpha *= (autocvar_hud_panel_weapons_timeout_fadebgmin * (1 - f) + f);
- panel_fg_alpha *= (autocvar_hud_panel_weapons_timeout_fadefgmin * (1 - f) + f);
- }
- else if(autocvar_hud_panel_weapons_timeout_effect == 3)
- {
- panel_bg_alpha *= (f);
- panel_fg_alpha *= (f);
- }
-
- // move the panel back on screen
- if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
- {
- f *= f; // for a cooler movement
- f = 1 - f;
- center.x = panel_pos.x + panel_size.x/2;
- center.y = panel_pos.y + panel_size.y/2;
- screen_ar = vid_conwidth/vid_conheight;
- if (center.x/center.y < screen_ar) //bottom left
- {
- if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
- panel_pos.y += f * (vid_conheight - panel_pos.y);
- else //left
- panel_pos.x -= f * (panel_pos.x + panel_size.x);
- }
- else //top right
- {
- if ((vid_conwidth - center.x)/center.y < screen_ar) //right
- panel_pos.x += f * (vid_conwidth - panel_pos.x);
- else //top
- panel_pos.y -= f * (panel_pos.y + panel_size.y);
- }
- }
- }
- }
-
- // draw the background, then change the virtual size of it to better fit other items inside
- HUD_Panel_DrawBg(1);
-
- if(center.x == -1)
- return;
-
- if(panel_bg_padding)
- {
- panel_pos += '1 1 0' * panel_bg_padding;
- panel_size -= '2 2 0' * panel_bg_padding;
- }
-
- // after the sizing and animations are done, update the other values
-
- if(!rows) // if rows is > 0 onlyowned code has already updated these vars
- {
- vector table_size = HUD_GetTableSize_BestItemAR((Weapons_COUNT - 1), panel_size, aspect);
- columns = table_size.x;
- rows = table_size.y;
- weapon_size.x = panel_size.x / columns;
- weapon_size.y = panel_size.y / rows;
- vertical_order = (panel_size.x / panel_size.y >= aspect);
- }
-
- // calculate position/size for visual bar displaying ammount of ammo status
- if (autocvar_hud_panel_weapons_ammo)
- {
- ammo_color = stov(autocvar_hud_panel_weapons_ammo_color);
- ammo_alpha = panel_fg_alpha * autocvar_hud_panel_weapons_ammo_alpha;
-
- if(weapon_size.x/weapon_size.y > aspect)
- {
- barsize.x = aspect * weapon_size.y;
- barsize.y = weapon_size.y;
- baroffset.x = (weapon_size.x - barsize.x) / 2;
- }
- else
- {
- barsize.y = 1/aspect * weapon_size.x;
- barsize.x = weapon_size.x;
- baroffset.y = (weapon_size.y - barsize.y) / 2;
- }
- }
- if(autocvar_hud_panel_weapons_accuracy)
- Accuracy_LoadColors();
-
- // draw items
- row = column = 0;
- vector label_size = '1 1 0' * min(weapon_size.x, weapon_size.y) * bound(0, autocvar_hud_panel_weapons_label_scale, 1);
- vector noncurrent_pos = '0 0 0';
- vector noncurrent_size = weapon_size * bound(0, autocvar_hud_panel_weapons_noncurrent_scale, 1);
- float noncurrent_alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_weapons_noncurrent_alpha, 1);
- bool isCurrent;
-
- for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
- {
- // retrieve information about the current weapon to be drawn
- setself(weaponorder[i]);
- weapon_id = self.impulse;
- isCurrent = (self.weapon == switchweapon);
-
- // skip if this weapon doesn't exist
- if(!self || weapon_id < 0) { continue; }
-
- // skip this weapon if we don't own it (and onlyowned is enabled)-- or if weapons_complainbubble is showing for this weapon
- if(autocvar_hud_panel_weapons_onlyowned)
- if (!((weapons_stat & WepSet_FromWeapon(self.weapon)) || (self.weapon == complain_weapon)))
- continue;
-
- // figure out the drawing position of weapon
- weapon_pos = (panel_pos + eX * column * weapon_size.x + eY * row * weapon_size.y);
- noncurrent_pos.x = weapon_pos.x + (weapon_size.x - noncurrent_size.x) / 2;
- noncurrent_pos.y = weapon_pos.y + (weapon_size.y - noncurrent_size.y) / 2;
-
- // draw background behind currently selected weapon
- if(isCurrent)
- drawpic_aspect_skin(weapon_pos, "weapon_current_bg", weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-
- // draw the weapon accuracy
- if(autocvar_hud_panel_weapons_accuracy)
- {
- float panel_weapon_accuracy = weapon_accuracy[self.weapon-WEP_FIRST];
- if(panel_weapon_accuracy >= 0)
- {
- color = Accuracy_GetColor(panel_weapon_accuracy);
- drawpic_aspect_skin(weapon_pos, "weapon_accuracy", weapon_size, color, panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- }
-
- // drawing all the weapon items
- if(weapons_stat & WepSet_FromWeapon(self.weapon))
- {
- // draw the weapon image
- if(isCurrent)
- drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- else
- drawpic_aspect_skin(noncurrent_pos, self.model2, noncurrent_size, '1 1 1', noncurrent_alpha, DRAWFLAG_NORMAL);
-
- // draw weapon label string
- switch(autocvar_hud_panel_weapons_label)
- {
- case 1: // weapon number
- drawstring(weapon_pos, ftos(weapon_id), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- break;
-
- case 2: // bind
- drawstring(weapon_pos, getcommandkey(ftos(weapon_id), strcat("weapon_group_", ftos(weapon_id))), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- break;
-
- case 3: // weapon name
- drawstring(weapon_pos, strtolower(self.message), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- break;
-
- default: // nothing
- break;
- }
-
- // draw ammo status bar
- if(autocvar_hud_panel_weapons_ammo && (self.ammo_field != ammo_none))
- {
- float ammo_full;
- a = getstati(GetAmmoStat(self.ammo_field)); // how much ammo do we have?
-
- if(a > 0)
- {
- switch(self.ammo_field)
- {
- case ammo_shells: ammo_full = autocvar_hud_panel_weapons_ammo_full_shells; break;
- case ammo_nails: ammo_full = autocvar_hud_panel_weapons_ammo_full_nails; break;
- case ammo_rockets: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
- case ammo_cells: ammo_full = autocvar_hud_panel_weapons_ammo_full_cells; break;
- case ammo_plasma: ammo_full = autocvar_hud_panel_weapons_ammo_full_plasma; break;
- case ammo_fuel: ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel; break;
- default: ammo_full = 60;
- }
-
- drawsetcliparea(
- weapon_pos.x + baroffset.x,
- weapon_pos.y + baroffset.y,
- barsize.x * bound(0, a/ammo_full, 1),
- barsize.y
- );
-
- drawpic_aspect_skin(
- weapon_pos,
- "weapon_ammo",
- weapon_size,
- ammo_color,
- ammo_alpha,
- DRAWFLAG_NORMAL
- );
-
- drawresetcliparea();
- }
- }
- }
- else // draw a "ghost weapon icon" if you don't have the weapon
- {
- drawpic_aspect_skin(noncurrent_pos, self.model2, noncurrent_size, '0.2 0.2 0.2', panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
- }
-
- // draw the complain message
- if(self.weapon == complain_weapon)
- {
- if(fadetime)
- a = ((complain_weapon_time + when > time) ? 1 : bound(0, (complain_weapon_time + when + fadetime - time) / fadetime, 1));
- else
- a = ((complain_weapon_time + when > time) ? 1 : 0);
-
- string s;
- if(complain_weapon_type == 0) {
- s = _("Out of ammo");
- color = stov(autocvar_hud_panel_weapons_complainbubble_color_outofammo);
- }
- else if(complain_weapon_type == 1) {
- s = _("Don't have");
- color = stov(autocvar_hud_panel_weapons_complainbubble_color_donthave);
- }
- else {
- s = _("Unavailable");
- color = stov(autocvar_hud_panel_weapons_complainbubble_color_unavailable);
- }
- float padding = autocvar_hud_panel_weapons_complainbubble_padding;
- drawpic_aspect_skin(weapon_pos + '1 1 0' * padding, "weapon_complainbubble", weapon_size - '2 2 0' * padding, color, a * panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(weapon_pos + '1 1 0' * padding, s, weapon_size - '2 2 0' * padding, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- }
-
- #if 0
- /// debug code
- if(!autocvar_hud_panel_weapons_onlyowned)
- {
- drawfill(weapon_pos + '1 1 0', weapon_size - '2 2 0', '1 1 1', panel_fg_alpha * 0.2, DRAWFLAG_NORMAL);
- drawstring(weapon_pos, ftos(i + 1), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- #endif
-
- // continue with new position for the next weapon
- if(vertical_order)
- {
- ++column;
- if(column >= columns)
- {
- column = 0;
- ++row;
- }
- }
- else
- {
- ++row;
- if(row >= rows)
- {
- row = 0;
- ++column;
- }
- }
- }
-}
-
-// Ammo (#1)
-void DrawNadeProgressBar(vector myPos, vector mySize, float progress, vector color)
-{
- HUD_Panel_DrawProgressBar(
- myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x,
- mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x,
- autocvar_hud_panel_ammo_progressbar_name,
- progress, 0, 0, color,
- autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
-void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time)
-{
- float bonusNades = getstatf(STAT_NADE_BONUS);
- float bonusProgress = getstatf(STAT_NADE_BONUS_SCORE);
- float bonusType = getstati(STAT_NADE_BONUS_TYPE);
- vector nadeColor = Nades[bonusType].m_color;
- string nadeIcon = Nades[bonusType].m_icon;
-
- vector iconPos, textPos;
-
- if(autocvar_hud_panel_ammo_iconalign)
- {
- iconPos = myPos + eX * 2 * mySize.y;
- textPos = myPos;
- }
- else
- {
- iconPos = myPos;
- textPos = myPos + eX * mySize.y;
- }
-
- if(bonusNades > 0 || bonusProgress > 0)
- {
- DrawNadeProgressBar(myPos, mySize, bonusProgress, nadeColor);
-
- if(autocvar_hud_panel_ammo_text)
- drawstring_aspect(textPos, ftos(bonusNades), eX * (2/3) * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-
- if(draw_expanding)
- drawpic_aspect_skin_expanding(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, expand_time);
-
- drawpic_aspect_skin(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- }
-}
-
-void DrawAmmoItem(vector myPos, vector mySize, .int ammoType, bool isCurrent, bool isInfinite)
-{
- if(ammoType == ammo_none)
- return;
-
- // Initialize variables
-
- int ammo;
- if(autocvar__hud_configure)
- {
- isCurrent = (ammoType == ammo_rockets); // Rockets always current
- ammo = 60;
- }
- else
- ammo = getstati(GetAmmoStat(ammoType));
-
- if(!isCurrent)
- {
- float scale = bound(0, autocvar_hud_panel_ammo_noncurrent_scale, 1);
- myPos = myPos + (mySize - mySize * scale) * 0.5;
- mySize = mySize * scale;
- }
-
- vector iconPos, textPos;
- if(autocvar_hud_panel_ammo_iconalign)
- {
- iconPos = myPos + eX * 2 * mySize.y;
- textPos = myPos;
- }
- else
- {
- iconPos = myPos;
- textPos = myPos + eX * mySize.y;
- }
-
- bool isShadowed = (ammo <= 0 && !isCurrent && !isInfinite);
-
- vector iconColor = isShadowed ? '0 0 0' : '1 1 1';
- vector textColor;
- if(isInfinite)
- textColor = '0.2 0.95 0';
- else if(isShadowed)
- textColor = '0 0 0';
- else if(ammo < 10)
- textColor = '0.8 0.04 0';
- else
- textColor = '1 1 1';
-
- float alpha;
- if(isCurrent)
- alpha = panel_fg_alpha;
- else if(isShadowed)
- alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_ammo_noncurrent_alpha, 1) * 0.5;
- else
- alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_ammo_noncurrent_alpha, 1);
-
- string text = isInfinite ? "\xE2\x88\x9E" : ftos(ammo); // Use infinity symbol (U+221E)
-
- // Draw item
-
- if(isCurrent)
- drawpic_aspect_skin(myPos, "ammo_current_bg", mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-
- if(ammo > 0 && autocvar_hud_panel_ammo_progressbar)
- HUD_Panel_DrawProgressBar(myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x, mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x, autocvar_hud_panel_ammo_progressbar_name, ammo/autocvar_hud_panel_ammo_maxammo, 0, 0, textColor, autocvar_hud_progressbar_alpha * alpha, DRAWFLAG_NORMAL);
-
- if(autocvar_hud_panel_ammo_text)
- drawstring_aspect(textPos, text, eX * (2/3) * mySize.x + eY * mySize.y, textColor, alpha, DRAWFLAG_NORMAL);
-
- drawpic_aspect_skin(iconPos, GetAmmoPicture(ammoType), '1 1 0' * mySize.y, iconColor, alpha, DRAWFLAG_NORMAL);
-}
-
-int nade_prevstatus;
-int nade_prevframe;
-float nade_statuschange_time;
-void HUD_Ammo(void)
-{
- if(hud != HUD_NORMAL) return;
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_ammo) return;
- if(spectatee_status == -1) return;
- }
-
- HUD_Panel_UpdateCvars();
-
- draw_beginBoldFont();
-
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- int rows = 0, columns, row, column;
- float nade_cnt = getstatf(STAT_NADE_BONUS), nade_score = getstatf(STAT_NADE_BONUS_SCORE);
- bool draw_nades = (nade_cnt > 0 || nade_score > 0);
- float nade_statuschange_elapsedtime;
- int total_ammo_count;
-
- vector ammo_size;
- if (autocvar_hud_panel_ammo_onlycurrent)
- total_ammo_count = 1;
- else
- total_ammo_count = AMMO_COUNT;
-
- if(draw_nades)
- {
- ++total_ammo_count;
- if (nade_cnt != nade_prevframe)
- {
- nade_statuschange_time = time;
- nade_prevstatus = nade_prevframe;
- nade_prevframe = nade_cnt;
- }
- }
- else
- nade_prevstatus = nade_prevframe = nade_statuschange_time = 0;
-
- rows = HUD_GetRowCount(total_ammo_count, mySize, 3);
- columns = ceil((total_ammo_count)/rows);
- ammo_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
-
- vector offset = '0 0 0'; // fteqcc sucks
- float newSize;
- if(ammo_size.x/ammo_size.y > 3)
- {
- newSize = 3 * ammo_size.y;
- offset.x = ammo_size.x - newSize;
- pos.x += offset.x/2;
- ammo_size.x = newSize;
- }
- else
- {
- newSize = 1/3 * ammo_size.x;
- offset.y = ammo_size.y - newSize;
- pos.y += offset.y/2;
- ammo_size.y = newSize;
- }
-
- int i;
- bool infinite_ammo = (getstati(STAT_ITEMS, 0, 24) & IT_UNLIMITED_WEAPON_AMMO);
- row = column = 0;
- if(autocvar_hud_panel_ammo_onlycurrent)
- {
- if(autocvar__hud_configure)
- {
- DrawAmmoItem(pos, ammo_size, ammo_rockets, true, false);
- }
- else
- {
- DrawAmmoItem(
- pos,
- ammo_size,
- (get_weaponinfo(switchweapon)).ammo_field,
- true,
- infinite_ammo
- );
- }
-
- ++row;
- if(row >= rows)
- {
- row = 0;
- column = column + 1;
- }
- }
- else
- {
- .int ammotype;
- row = column = 0;
- for(i = 0; i < AMMO_COUNT; ++i)
- {
- ammotype = GetAmmoFieldFromNum(i);
- DrawAmmoItem(
- pos + eX * column * (ammo_size.x + offset.x) + eY * row * (ammo_size.y + offset.y),
- ammo_size,
- ammotype,
- ((get_weaponinfo(switchweapon)).ammo_field == ammotype),
- infinite_ammo
- );
-
- ++row;
- if(row >= rows)
- {
- row = 0;
- column = column + 1;
- }
- }
- }
-
- if (draw_nades)
- {
- nade_statuschange_elapsedtime = time - nade_statuschange_time;
-
- float f = bound(0, nade_statuschange_elapsedtime*2, 1);
-
- DrawAmmoNades(pos + eX * column * (ammo_size.x + offset.x) + eY * row * (ammo_size.y + offset.y), ammo_size, nade_prevstatus < nade_cnt && nade_cnt != 0 && f < 1, f);
- }
-
- draw_endBoldFont();
-}
-
-void DrawNumIcon_expanding(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha, float fadelerp)
-{
- vector newPos = '0 0 0', newSize = '0 0 0';
- vector picpos, numpos;
-
- if (vertical)
- {
- if(mySize.y/mySize.x > 2)
- {
- newSize.y = 2 * mySize.x;
- newSize.x = mySize.x;
-
- newPos.y = myPos.y + (mySize.y - newSize.y) / 2;
- newPos.x = myPos.x;
- }
- else
- {
- newSize.x = 1/2 * mySize.y;
- newSize.y = mySize.y;
-
- newPos.x = myPos.x + (mySize.x - newSize.x) / 2;
- newPos.y = myPos.y;
- }
-
- if(icon_right_align)
- {
- numpos = newPos;
- picpos = newPos + eY * newSize.x;
- }
- else
- {
- picpos = newPos;
- numpos = newPos + eY * newSize.x;
- }
-
- newSize.y /= 2;
- drawpic_aspect_skin(picpos, icon, newSize, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
- // make number smaller than icon, it looks better
- // reduce only y to draw numbers with different number of digits with the same y size
- numpos.y += newSize.y * ((1 - 0.7) / 2);
- newSize.y *= 0.7;
- drawstring_aspect(numpos, ftos(x), newSize, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
- return;
- }
-
- if(mySize.x/mySize.y > 3)
- {
- newSize.x = 3 * mySize.y;
- newSize.y = mySize.y;
-
- newPos.x = myPos.x + (mySize.x - newSize.x) / 2;
- newPos.y = myPos.y;
- }
- else
- {
- newSize.y = 1/3 * mySize.x;
- newSize.x = mySize.x;
-
- newPos.y = myPos.y + (mySize.y - newSize.y) / 2;
- newPos.x = myPos.x;
- }
-
- if(icon_right_align) // right align
- {
- numpos = newPos;
- picpos = newPos + eX * 2 * newSize.y;
- }
- else // left align
- {
- numpos = newPos + eX * newSize.y;
- picpos = newPos;
- }
-
- // NOTE: newSize_x is always equal to 3 * mySize_y so we can use
- // '2 1 0' * newSize_y instead of eX * (2/3) * newSize_x + eY * newSize_y
- drawstring_aspect_expanding(numpos, ftos(x), '2 1 0' * newSize.y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
- drawpic_aspect_skin_expanding(picpos, icon, '1 1 0' * newSize.y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
-}
-
-void DrawNumIcon(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha)
-{
- DrawNumIcon_expanding(myPos, mySize, x, icon, vertical, icon_right_align, color, theAlpha, 0);
-}
-
-// Powerups (#2)
-//
-
-// Powerup item fields (reusing existing fields)
-.string message; // Human readable name
-.string netname; // Icon name
-.vector colormod; // Color
-.float count; // Time left
-.float lifetime; // Maximum time
-
-entity powerupItems;
-int powerupItemsCount;
-
-void resetPowerupItems()
-{
- entity item;
- for(item = powerupItems; item; item = item.chain)
- item.count = 0;
-
- powerupItemsCount = 0;
-}
-
-void addPowerupItem(string name, string icon, vector color, float currentTime, float lifeTime)
-{
- if(!powerupItems)
- powerupItems = spawn();
-
- entity item;
- for(item = powerupItems; item.count; item = item.chain)
- if(!item.chain)
- item.chain = spawn();
-
- item.message = name;
- item.netname = icon;
- item.colormod = color;
- item.count = currentTime;
- item.lifetime = lifeTime;
-
- ++powerupItemsCount;
-}
-
-int getPowerupItemAlign(int align, int column, int row, int columns, int rows, bool isVertical)
-{
- if(align < 2)
- return align;
-
- bool isTop = isVertical && rows > 1 && row == 0;
- bool isBottom = isVertical && rows > 1 && row == rows-1;
- bool isLeft = !isVertical && columns > 1 && column == 0;
- bool isRight = !isVertical && columns > 1 && column == columns-1;
-
- if(isTop || isLeft) return (align == 2) ? 1 : 0;
- if(isBottom || isRight) return (align == 2) ? 0 : 1;
-
- return 2;
-}
-
-void HUD_Powerups()
-{
- int allItems = getstati(STAT_ITEMS, 0, 24);
- int allBuffs = getstati(STAT_BUFFS, 0, 24);
- int strengthTime, shieldTime, superTime;
-
- // Initialize items
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_powerups) return;
- if(spectatee_status == -1) return;
- if(getstati(STAT_HEALTH) <= 0) return;
- if(!(allItems & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON)) && !allBuffs) return;
-
- strengthTime = bound(0, getstatf(STAT_STRENGTH_FINISHED) - time, 99);
- shieldTime = bound(0, getstatf(STAT_INVINCIBLE_FINISHED) - time, 99);
- superTime = bound(0, getstatf(STAT_SUPERWEAPONS_FINISHED) - time, 99);
-
- if(allItems & IT_UNLIMITED_SUPERWEAPONS)
- superTime = 99;
-
- // Prevent stuff to show up on mismatch that will be fixed next frame
- if(!(allItems & IT_SUPERWEAPON))
- superTime = 0;
- }
- else
- {
- strengthTime = 15;
- shieldTime = 27;
- superTime = 13;
- allBuffs = 0;
- }
-
- // Add items to linked list
- resetPowerupItems();
-
- if(strengthTime)
- addPowerupItem("Strength", "strength", autocvar_hud_progressbar_strength_color, strengthTime, 30);
- if(shieldTime)
- addPowerupItem("Shield", "shield", autocvar_hud_progressbar_shield_color, shieldTime, 30);
- if(superTime)
- addPowerupItem("Superweapons", "superweapons", autocvar_hud_progressbar_superweapons_color, superTime, 30);
-
- FOREACH(Buffs, it.m_itemid & allBuffs, LAMBDA(
- addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, getstatf(STAT_BUFF_TIME) - time, 99), 60);
- ));
-
- if(!powerupItemsCount)
- return;
-
- // Draw panel background
- HUD_Panel_UpdateCvars();
- HUD_Panel_DrawBg(1);
-
- // Set drawing area
- vector pos = panel_pos;
- vector size = panel_size;
- bool isVertical = size.y > size.x;
-
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- size -= '2 2 0' * panel_bg_padding;
- }
-
- // Find best partitioning of the drawing area
- const float DESIRED_ASPECT = 6;
- float aspect = 0, a;
- int columns = 0, c;
- int rows = 0, r;
- int i = 1;
-
- do
- {
- c = floor(powerupItemsCount / i);
- r = ceil(powerupItemsCount / c);
- a = isVertical ? (size.y/r) / (size.x/c) : (size.x/c) / (size.y/r);
-
- if(i == 1 || fabs(DESIRED_ASPECT - a) < fabs(DESIRED_ASPECT - aspect))
- {
- aspect = a;
- columns = c;
- rows = r;
- }
- }
- while(++i <= powerupItemsCount);
-
- // Prevent single items from getting too wide
- if(powerupItemsCount == 1 && aspect > DESIRED_ASPECT)
- {
- if(isVertical)
- {
- size.y *= 0.5;
- pos.y += size.y * 0.5;
- }
- else
- {
- size.x *= 0.5;
- pos.x += size.x * 0.5;
- }
- }
-
- // Draw items from linked list
- vector itemPos = pos;
- vector itemSize = eX * (size.x / columns) + eY * (size.y / rows);
- vector textColor = '1 1 1';
-
- int fullSeconds = 0;
- int align = 0;
- int column = 0;
- int row = 0;
-
- draw_beginBoldFont();
- for(entity item = powerupItems; item.count; item = item.chain)
- {
- itemPos = eX * (pos.x + column * itemSize.x) + eY * (pos.y + row * itemSize.y);
-
- // Draw progressbar
- if(autocvar_hud_panel_powerups_progressbar)
- {
- align = getPowerupItemAlign(autocvar_hud_panel_powerups_baralign, column, row, columns, rows, isVertical);
- HUD_Panel_DrawProgressBar(itemPos, itemSize, "progressbar", item.count / item.lifetime, isVertical, align, item.colormod, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- }
-
- // Draw icon and text
- if(autocvar_hud_panel_powerups_text)
- {
- align = getPowerupItemAlign(autocvar_hud_panel_powerups_iconalign, column, row, columns, rows, isVertical);
- fullSeconds = ceil(item.count);
- textColor = '0.6 0.6 0.6' + (item.colormod * 0.4);
-
- if(item.count > 1)
- DrawNumIcon(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha);
- if(item.count <= 5)
- DrawNumIcon_expanding(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha, bound(0, (fullSeconds - item.count) / 0.5, 1));
- }
-
- // Determine next section
- if(isVertical)
- {
- if(++column >= columns)
- {
- column = 0;
- ++row;
- }
- }
- else
- {
- if(++row >= rows)
- {
- row = 0;
- ++column;
- }
- }
- }
- draw_endBoldFont();
-}
-
-// Health/armor (#3)
-//
-
-
-void HUD_HealthArmor(void)
-{
- int armor, health, fuel;
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_healtharmor) return;
- if(hud != HUD_NORMAL) return;
- if(spectatee_status == -1) return;
-
- health = getstati(STAT_HEALTH);
- if(health <= 0)
- {
- prev_health = -1;
- return;
- }
- armor = getstati(STAT_ARMOR);
-
- // code to check for spectatee_status changes is in Ent_ClientData()
- // prev_p_health and prev_health can be set to -1 there
-
- if (prev_p_health == -1)
- {
- // no effect
- health_beforedamage = 0;
- armor_beforedamage = 0;
- health_damagetime = 0;
- armor_damagetime = 0;
- prev_health = health;
- prev_armor = armor;
- old_p_health = health;
- old_p_armor = armor;
- prev_p_health = health;
- prev_p_armor = armor;
- }
- else if (prev_health == -1)
- {
- //start the load effect
- health_damagetime = 0;
- armor_damagetime = 0;
- prev_health = 0;
- prev_armor = 0;
- }
- fuel = getstati(STAT_FUEL);
- }
- else
- {
- health = 150;
- armor = 75;
- fuel = 20;
- }
-
- HUD_Panel_UpdateCvars();
-
- draw_beginBoldFont();
-
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- int baralign = autocvar_hud_panel_healtharmor_baralign;
- int iconalign = autocvar_hud_panel_healtharmor_iconalign;
-
- int maxhealth = autocvar_hud_panel_healtharmor_maxhealth;
- int maxarmor = autocvar_hud_panel_healtharmor_maxarmor;
- if(autocvar_hud_panel_healtharmor == 2) // combined health and armor display
- {
- vector v;
- v = healtharmor_maxdamage(health, armor, armorblockpercent, DEATH_WEAPON.m_id);
-
- float x;
- x = floor(v.x + 1);
-
- float maxtotal = maxhealth + maxarmor;
- string biggercount;
- if(v.z) // NOT fully armored
- {
- biggercount = "health";
- if(autocvar_hud_panel_healtharmor_progressbar)
- HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_health, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- if(armor)
- if(autocvar_hud_panel_healtharmor_text)
- drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "armor", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha * armor / health, DRAWFLAG_NORMAL);
- }
- else
- {
- biggercount = "armor";
- if(autocvar_hud_panel_healtharmor_progressbar)
- HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- if(health)
- if(autocvar_hud_panel_healtharmor_text)
- drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "health", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- if(autocvar_hud_panel_healtharmor_text)
- DrawNumIcon(pos, mySize, x, biggercount, 0, iconalign, HUD_Get_Num_Color(x, maxtotal), 1);
-
- if(fuel)
- HUD_Panel_DrawProgressBar(pos, eX * mySize.x + eY * 0.2 * mySize.y, "progressbar", fuel/100, 0, (baralign == 1 || baralign == 3), autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
- }
- else
- {
- float panel_ar = mySize.x/mySize.y;
- bool is_vertical = (panel_ar < 1);
- vector health_offset = '0 0 0', armor_offset = '0 0 0';
- if (panel_ar >= 4 || (panel_ar >= 1/4 && panel_ar < 1))
- {
- mySize.x *= 0.5;
- if (autocvar_hud_panel_healtharmor_flip)
- health_offset.x = mySize.x;
- else
- armor_offset.x = mySize.x;
- }
- else
- {
- mySize.y *= 0.5;
- if (autocvar_hud_panel_healtharmor_flip)
- health_offset.y = mySize.y;
- else
- armor_offset.y = mySize.y;
- }
-
- bool health_baralign, armor_baralign, fuel_baralign;
- bool health_iconalign, armor_iconalign;
- if (autocvar_hud_panel_healtharmor_flip)
- {
- armor_baralign = (autocvar_hud_panel_healtharmor_baralign == 2 || autocvar_hud_panel_healtharmor_baralign == 1);
- health_baralign = (autocvar_hud_panel_healtharmor_baralign == 3 || autocvar_hud_panel_healtharmor_baralign == 1);
- fuel_baralign = health_baralign;
- armor_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 2 || autocvar_hud_panel_healtharmor_iconalign == 1);
- health_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 3 || autocvar_hud_panel_healtharmor_iconalign == 1);
- }
- else
- {
- health_baralign = (autocvar_hud_panel_healtharmor_baralign == 2 || autocvar_hud_panel_healtharmor_baralign == 1);
- armor_baralign = (autocvar_hud_panel_healtharmor_baralign == 3 || autocvar_hud_panel_healtharmor_baralign == 1);
- fuel_baralign = armor_baralign;
- health_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 2 || autocvar_hud_panel_healtharmor_iconalign == 1);
- armor_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 3 || autocvar_hud_panel_healtharmor_iconalign == 1);
- }
-
- //if(health)
- {
- if(autocvar_hud_panel_healtharmor_progressbar)
- {
- float p_health, pain_health_alpha;
- p_health = health;
- pain_health_alpha = 1;
- if (autocvar_hud_panel_healtharmor_progressbar_gfx)
- {
- if (autocvar_hud_panel_healtharmor_progressbar_gfx_smooth > 0)
- {
- if (fabs(prev_health - health) >= autocvar_hud_panel_healtharmor_progressbar_gfx_smooth)
- {
- if (time - old_p_healthtime < 1)
- old_p_health = prev_p_health;
- else
- old_p_health = prev_health;
- old_p_healthtime = time;
- }
- if (time - old_p_healthtime < 1)
- {
- p_health += (old_p_health - health) * (1 - (time - old_p_healthtime));
- prev_p_health = p_health;
- }
- }
- if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0)
- {
- if (prev_health - health >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
- {
- if (time - health_damagetime >= 1)
- health_beforedamage = prev_health;
- health_damagetime = time;
- }
- if (time - health_damagetime < 1)
- {
- float health_damagealpha = 1 - (time - health_damagetime)*(time - health_damagetime);
- HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, health_beforedamage/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * health_damagealpha, DRAWFLAG_NORMAL);
- }
- }
- prev_health = health;
-
- if (health <= autocvar_hud_panel_healtharmor_progressbar_gfx_lowhealth)
- {
- float BLINK_FACTOR = 0.15;
- float BLINK_BASE = 0.85;
- float BLINK_FREQ = 9;
- pain_health_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
- }
- }
- HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, p_health/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * pain_health_alpha, DRAWFLAG_NORMAL);
- }
- if(autocvar_hud_panel_healtharmor_text)
- DrawNumIcon(pos + health_offset, mySize, health, "health", is_vertical, health_iconalign, HUD_Get_Num_Color(health, maxhealth), 1);
- }
-
- if(armor)
- {
- if(autocvar_hud_panel_healtharmor_progressbar)
- {
- float p_armor;
- p_armor = armor;
- if (autocvar_hud_panel_healtharmor_progressbar_gfx)
- {
- if (autocvar_hud_panel_healtharmor_progressbar_gfx_smooth > 0)
- {
- if (fabs(prev_armor - armor) >= autocvar_hud_panel_healtharmor_progressbar_gfx_smooth)
- {
- if (time - old_p_armortime < 1)
- old_p_armor = prev_p_armor;
- else
- old_p_armor = prev_armor;
- old_p_armortime = time;
- }
- if (time - old_p_armortime < 1)
- {
- p_armor += (old_p_armor - armor) * (1 - (time - old_p_armortime));
- prev_p_armor = p_armor;
- }
- }
- if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0)
- {
- if (prev_armor - armor >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
- {
- if (time - armor_damagetime >= 1)
- armor_beforedamage = prev_armor;
- armor_damagetime = time;
- }
- if (time - armor_damagetime < 1)
- {
- float armor_damagealpha = 1 - (time - armor_damagetime)*(time - armor_damagetime);
- HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, armor_beforedamage/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * armor_damagealpha, DRAWFLAG_NORMAL);
- }
- }
- prev_armor = armor;
- }
- HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, p_armor/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- if(autocvar_hud_panel_healtharmor_text)
- DrawNumIcon(pos + armor_offset, mySize, armor, "armor", is_vertical, armor_iconalign, HUD_Get_Num_Color(armor, maxarmor), 1);
- }
-
- if(fuel)
- {
- if (is_vertical)
- mySize.x *= 0.2 / 2; //if vertical always halve x to not cover too much numbers with 3 digits
- else
- mySize.y *= 0.2;
- if (panel_ar >= 4)
- mySize.x *= 2; //restore full panel size
- else if (panel_ar < 1/4)
- mySize.y *= 2; //restore full panel size
- HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", fuel/100, is_vertical, fuel_baralign, autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
- }
- }
-
- draw_endBoldFont();
-}
-
-// Notification area (#4)
-//
-
-void HUD_Notify_Push(string icon, string attacker, string victim)
-{
- if (icon == "")
- return;
-
- ++notify_count;
- --notify_index;
-
- if (notify_index == -1)
- notify_index = NOTIFY_MAX_ENTRIES-1;
-
- // Free old strings
- if (notify_attackers[notify_index])
- strunzone(notify_attackers[notify_index]);
-
- if (notify_victims[notify_index])
- strunzone(notify_victims[notify_index]);
-
- if (notify_icons[notify_index])
- strunzone(notify_icons[notify_index]);
-
- // Allocate new strings
- if (victim != "")
- {
- notify_attackers[notify_index] = strzone(attacker);
- notify_victims[notify_index] = strzone(victim);
- }
- else
- {
- // In case of a notification without a victim, the attacker
- // is displayed on the victim's side. Instead of special
- // treatment later on, we can simply switch them here.
- notify_attackers[notify_index] = string_null;
- notify_victims[notify_index] = strzone(attacker);
- }
-
- notify_icons[notify_index] = strzone(icon);
- notify_times[notify_index] = time;
-}
-
-void HUD_Notify(void)
-{
- if (!autocvar__hud_configure)
- if (!autocvar_hud_panel_notify)
- return;
-
- HUD_Panel_UpdateCvars();
- HUD_Panel_DrawBg(1);
-
- if (!autocvar__hud_configure)
- if (notify_count == 0)
- return;
-
- vector pos, size;
- pos = panel_pos;
- size = panel_size;
-
- if (panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- size -= '2 2 0' * panel_bg_padding;
- }
-
- float fade_start = max(0, autocvar_hud_panel_notify_time);
- float fade_time = max(0, autocvar_hud_panel_notify_fadetime);
- float icon_aspect = max(1, autocvar_hud_panel_notify_icon_aspect);
-
- int entry_count = bound(1, floor(NOTIFY_MAX_ENTRIES * size.y / size.x), NOTIFY_MAX_ENTRIES);
- float entry_height = size.y / entry_count;
-
- float panel_width_half = size.x * 0.5;
- float icon_width_half = entry_height * icon_aspect / 2;
- float name_maxwidth = panel_width_half - icon_width_half - size.x * NOTIFY_ICON_MARGIN;
-
- vector font_size = '0.5 0.5 0' * entry_height * autocvar_hud_panel_notify_fontsize;
- vector icon_size = (eX * icon_aspect + eY) * entry_height;
- vector icon_left = eX * (panel_width_half - icon_width_half);
- vector attacker_right = eX * name_maxwidth;
- vector victim_left = eX * (size.x - name_maxwidth);
-
- vector attacker_pos, victim_pos, icon_pos;
- string attacker, victim, icon;
- int i, j, count, step, limit;
- float alpha;
-
- if (autocvar_hud_panel_notify_flip)
- {
- // Order items from the top down
- i = 0;
- step = +1;
- limit = entry_count;
- }
- else
- {
- // Order items from the bottom up
- i = entry_count - 1;
- step = -1;
- limit = -1;
- }
-
- for (j = notify_index, count = 0; i != limit; i += step, ++j, ++count)
- {
- if(autocvar__hud_configure)
- {
- attacker = sprintf(_("Player %d"), count + 1);
- victim = sprintf(_("Player %d"), count + 2);
- icon = get_weaponinfo(min(WEP_FIRST + count * 2, WEP_LAST)).model2;
- alpha = bound(0, 1.2 - count / entry_count, 1);
- }
- else
- {
- if (j == NOTIFY_MAX_ENTRIES)
- j = 0;
-
- if (notify_times[j] + fade_start > time)
- alpha = 1;
- else if (fade_time != 0)
- {
- alpha = bound(0, (notify_times[j] + fade_start + fade_time - time) / fade_time, 1);
- if (alpha == 0)
- break;
- }
- else
- break;
-
- attacker = notify_attackers[j];
- victim = notify_victims[j];
- icon = notify_icons[j];
- }
-
- if (icon != "" && victim != "")
- {
- vector name_top = eY * (i * entry_height + 0.5 * (entry_height - font_size.y));
-
- icon_pos = pos + icon_left + eY * i * entry_height;
- drawpic_aspect_skin(icon_pos, icon, icon_size, '1 1 1', panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
-
- victim = textShortenToWidth(victim, name_maxwidth, font_size, stringwidth_colors);
- victim_pos = pos + victim_left + name_top;
- drawcolorcodedstring(victim_pos, victim, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
-
- if (attacker != "")
- {
- attacker = textShortenToWidth(attacker, name_maxwidth, font_size, stringwidth_colors);
- attacker_pos = pos + attacker_right - eX * stringwidth(attacker, true, font_size) + name_top;
- drawcolorcodedstring(attacker_pos, attacker, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
- }
- }
- }
-
- notify_count = count;
-}
-
-void HUD_Timer(void)
-{
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_timer) return;
- }
-
- HUD_Panel_UpdateCvars();
-
- draw_beginBoldFont();
-
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- string timer;
- float timelimit, elapsedTime, timeleft, minutesLeft;
-
- timelimit = getstatf(STAT_TIMELIMIT);
-
- timeleft = max(0, timelimit * 60 + getstatf(STAT_GAMESTARTTIME) - time);
- timeleft = ceil(timeleft);
-
- minutesLeft = floor(timeleft / 60);
-
- vector timer_color;
- if(minutesLeft >= 5 || warmup_stage || timelimit == 0) //don't use red or yellow in warmup or when there is no timelimit
- timer_color = '1 1 1'; //white
- else if(minutesLeft >= 1)
- timer_color = '1 1 0'; //yellow
- else
- timer_color = '1 0 0'; //red
-
- if (autocvar_hud_panel_timer_increment || timelimit == 0 || warmup_stage) {
- if (time < getstatf(STAT_GAMESTARTTIME)) {
- //while restart is still active, show 00:00
- timer = seconds_tostring(0);
- } else {
- elapsedTime = floor(time - getstatf(STAT_GAMESTARTTIME)); //127
- timer = seconds_tostring(elapsedTime);
- }
- } else {
- timer = seconds_tostring(timeleft);
- }
-
- drawstring_aspect(pos, timer, mySize, timer_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-
- draw_endBoldFont();
-}
-
-// Radar (#6)
-//
-
-float HUD_Radar_Clickable()
-{
- return hud_panel_radar_mouse && !hud_panel_radar_temp_hidden;
-}
-
-void HUD_Radar_Show_Maximized(bool doshow,float clickable)
-{
- hud_panel_radar_maximized = doshow;
- hud_panel_radar_temp_hidden = 0;
-
- if ( doshow )
- {
- if (clickable)
- {
- if(autocvar_hud_cursormode)
- setcursormode(1);
- hud_panel_radar_mouse = 1;
- }
- }
- else if ( hud_panel_radar_mouse )
- {
- hud_panel_radar_mouse = 0;
- mouseClicked = 0;
- if(autocvar_hud_cursormode)
- if(!mv_active)
- setcursormode(0);
- }
-}
-void HUD_Radar_Hide_Maximized()
-{
- HUD_Radar_Show_Maximized(false,false);
-}
-
-
-float HUD_Radar_InputEvent(float bInputType, float nPrimary, float nSecondary)
-{
- if(!hud_panel_radar_maximized || !hud_panel_radar_mouse ||
- autocvar__hud_configure || mv_active)
- return false;
-
- if(bInputType == 3)
- {
- mousepos_x = nPrimary;
- mousepos_y = nSecondary;
- return true;
- }
-
- if(nPrimary == K_MOUSE1)
- {
- if(bInputType == 0) // key pressed
- mouseClicked |= S_MOUSE1;
- else if(bInputType == 1) // key released
- mouseClicked -= (mouseClicked & S_MOUSE1);
- }
- else if(nPrimary == K_MOUSE2)
- {
- if(bInputType == 0) // key pressed
- mouseClicked |= S_MOUSE2;
- else if(bInputType == 1) // key released
- mouseClicked -= (mouseClicked & S_MOUSE2);
- }
- else if ( nPrimary == K_ESCAPE && bInputType == 0 )
- {
- HUD_Radar_Hide_Maximized();
- }
- else
- {
- // allow console/use binds to work without hiding the map
- string con_keys;
- float keys;
- float i;
- con_keys = strcat(findkeysforcommand("toggleconsole", 0)," ",findkeysforcommand("+use", 0)) ;
- keys = tokenize(con_keys); // findkeysforcommand returns data for this
- for (i = 0; i < keys; ++i)
- {
- if(nPrimary == stof(argv(i)))
- return false;
- }
-
- if ( getstati(STAT_HEALTH) <= 0 )
- {
- // Show scoreboard
- if ( bInputType < 2 )
- {
- con_keys = findkeysforcommand("+showscores", 0);
- keys = tokenize(con_keys);
- for (i = 0; i < keys; ++i)
- {
- if ( nPrimary == stof(argv(i)) )
- {
- hud_panel_radar_temp_hidden = bInputType == 0;
- return false;
- }
- }
- }
- }
- else if ( bInputType == 0 )
- HUD_Radar_Hide_Maximized();
-
- return false;
- }
-
- return true;
-}
-
-void HUD_Radar_Mouse()
-{
- if ( !hud_panel_radar_mouse ) return;
- if(mv_active) return;
-
- if ( intermission )
- {
- HUD_Radar_Hide_Maximized();
- return;
- }
-
- if(mouseClicked & S_MOUSE2)
- {
- HUD_Radar_Hide_Maximized();
- return;
- }
-
- if(!autocvar_hud_cursormode)
- {
- mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
-
- mousepos_x = bound(0, mousepos_x, vid_conwidth);
- mousepos_y = bound(0, mousepos_y, vid_conheight);
- }
-
- HUD_Panel_UpdateCvars();
-
-
- panel_size = autocvar_hud_panel_radar_maximized_size;
- panel_size_x = bound(0.2, panel_size_x, 1) * vid_conwidth;
- panel_size_y = bound(0.2, panel_size_y, 1) * vid_conheight;
- panel_pos_x = (vid_conwidth - panel_size_x) / 2;
- panel_pos_y = (vid_conheight - panel_size_y) / 2;
-
- if(mouseClicked & S_MOUSE1)
- {
- // click outside
- if ( mousepos_x < panel_pos_x || mousepos_x > panel_pos_x + panel_size_x ||
- mousepos_y < panel_pos_y || mousepos_y > panel_pos_y + panel_size_y )
- {
- HUD_Radar_Hide_Maximized();
- return;
- }
- vector pos = teamradar_texcoord_to_3dcoord(teamradar_2dcoord_to_texcoord(mousepos),view_origin_z);
- localcmd(sprintf("cmd ons_spawn %f %f %f",pos_x,pos_y,pos_z));
-
- HUD_Radar_Hide_Maximized();
- return;
- }
-
-
- const vector cursor_size = '32 32 0';
- drawpic(mousepos-'8 4 0', strcat("gfx/menu/", autocvar_menu_skin, "/cursor.tga"), cursor_size, '1 1 1', 0.8, DRAWFLAG_NORMAL);
-}
-
-void HUD_Radar(void)
-{
- if (!autocvar__hud_configure)
- {
- if (hud_panel_radar_maximized)
- {
- if (!hud_draw_maximized) return;
- }
- else
- {
- if (autocvar_hud_panel_radar == 0) return;
- if (autocvar_hud_panel_radar != 2 && !teamplay) return;
- if(radar_panel_modified)
- {
- panel.update_time = time; // forces reload of panel attributes
- radar_panel_modified = false;
- }
- }
- }
-
- if ( hud_panel_radar_temp_hidden )
- return;
-
- HUD_Panel_UpdateCvars();
-
- float f = 0;
-
- if (hud_panel_radar_maximized && !autocvar__hud_configure)
- {
- panel_size = autocvar_hud_panel_radar_maximized_size;
- panel_size.x = bound(0.2, panel_size.x, 1) * vid_conwidth;
- panel_size.y = bound(0.2, panel_size.y, 1) * vid_conheight;
- panel_pos.x = (vid_conwidth - panel_size.x) / 2;
- panel_pos.y = (vid_conheight - panel_size.y) / 2;
-
- string panel_bg;
- panel_bg = strcat(hud_skin_path, "/border_default"); // always use the default border when maximized
- if(precache_pic(panel_bg) == "")
- panel_bg = "gfx/hud/default/border_default"; // fallback
- if(!radar_panel_modified && panel_bg != panel.current_panel_bg)
- radar_panel_modified = true;
- if(panel.current_panel_bg)
- strunzone(panel.current_panel_bg);
- panel.current_panel_bg = strzone(panel_bg);
-
- switch(hud_panel_radar_maximized_zoommode)
- {
- default:
- case 0:
- f = current_zoomfraction;
- break;
- case 1:
- f = 1 - current_zoomfraction;
- break;
- case 2:
- f = 0;
- break;
- case 3:
- f = 1;
- break;
- }
-
- switch(hud_panel_radar_maximized_rotation)
- {
- case 0:
- teamradar_angle = view_angles.y - 90;
- break;
- default:
- teamradar_angle = 90 * hud_panel_radar_maximized_rotation;
- break;
- }
- }
- if (!hud_panel_radar_maximized && !autocvar__hud_configure)
- {
- switch(hud_panel_radar_zoommode)
- {
- default:
- case 0:
- f = current_zoomfraction;
- break;
- case 1:
- f = 1 - current_zoomfraction;
- break;
- case 2:
- f = 0;
- break;
- case 3:
- f = 1;
- break;
- }
-
- switch(hud_panel_radar_rotation)
- {
- case 0:
- teamradar_angle = view_angles.y - 90;
- break;
- default:
- teamradar_angle = 90 * hud_panel_radar_rotation;
- break;
- }
- }
-
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- int color2;
- entity tm;
- float scale2d, normalsize, bigsize;
-
- teamradar_origin2d = pos + 0.5 * mySize;
- teamradar_size2d = mySize;
-
- if(minimapname == "")
- return;
-
- teamradar_loadcvars();
-
- scale2d = vlen_maxnorm2d(mi_picmax - mi_picmin);
- teamradar_size2d = mySize;
-
- teamradar_extraclip_mins = teamradar_extraclip_maxs = '0 0 0'; // we always center
-
- // pixels per world qu to match the teamradar_size2d_x range in the longest dimension
- if((hud_panel_radar_rotation == 0 && !hud_panel_radar_maximized) || (hud_panel_radar_maximized_rotation == 0 && hud_panel_radar_maximized))
- {
- // max-min distance must fit the radar in any rotation
- bigsize = vlen_minnorm2d(teamradar_size2d) * scale2d / (1.05 * vlen2d(mi_scale));
- }
- else
- {
- vector c0, c1, c2, c3, span;
- c0 = rotate(mi_min, teamradar_angle * DEG2RAD);
- c1 = rotate(mi_max, teamradar_angle * DEG2RAD);
- c2 = rotate('1 0 0' * mi_min.x + '0 1 0' * mi_max.y, teamradar_angle * DEG2RAD);
- c3 = rotate('1 0 0' * mi_max.x + '0 1 0' * mi_min.y, teamradar_angle * DEG2RAD);
- span = '0 0 0';
- span.x = max(c0_x, c1_x, c2_x, c3_x) - min(c0_x, c1_x, c2_x, c3_x);
- span.y = max(c0_y, c1_y, c2_y, c3_y) - min(c0_y, c1_y, c2_y, c3_y);
-
- // max-min distance must fit the radar in x=x, y=y
- bigsize = min(
- teamradar_size2d.x * scale2d / (1.05 * span.x),
- teamradar_size2d.y * scale2d / (1.05 * span.y)
- );
- }
-
- normalsize = vlen_maxnorm2d(teamradar_size2d) * scale2d / hud_panel_radar_scale;
- if(bigsize > normalsize)
- normalsize = bigsize;
-
- teamradar_size =
- f * bigsize
- + (1 - f) * normalsize;
- teamradar_origin3d_in_texcoord = teamradar_3dcoord_to_texcoord(
- f * mi_center
- + (1 - f) * view_origin);
-
- drawsetcliparea(
- pos.x,
- pos.y,
- mySize.x,
- mySize.y
- );
-
- draw_teamradar_background(hud_panel_radar_foreground_alpha);
-
- for(tm = world; (tm = find(tm, classname, "radarlink")); )
- draw_teamradar_link(tm.origin, tm.velocity, tm.team);
-
- vector coord;
- vector brightcolor;
- for(tm = world; (tm = findflags(tm, teamradar_icon, 0xFFFFFF)); )
- {
- if ( hud_panel_radar_mouse )
- if ( tm.health > 0 )
- if ( tm.team == myteam+1 )
- {
- coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(tm.origin));
- if ( vlen(mousepos-coord) < 8 )
- {
- brightcolor_x = min(1,tm.teamradar_color_x*1.5);
- brightcolor_y = min(1,tm.teamradar_color_y*1.5);
- brightcolor_z = min(1,tm.teamradar_color_z*1.5);
- drawpic(coord - '8 8 0', "gfx/teamradar_icon_glow", '16 16 0', brightcolor, panel_fg_alpha, 0);
- }
- }
- entity icon = RadarIcons[tm.teamradar_icon];
- draw_teamradar_icon(tm.origin, icon, tm, spritelookupcolor(tm, icon.netname, tm.teamradar_color), panel_fg_alpha);
- }
- for(tm = world; (tm = find(tm, classname, "entcs_receiver")); )
- {
- color2 = GetPlayerColor(tm.sv_entnum);
- //if(color == NUM_SPECTATOR || color == color2)
- draw_teamradar_player(tm.origin, tm.angles, Team_ColorRGB(color2));
- }
- draw_teamradar_player(view_origin, view_angles, '1 1 1');
-
- drawresetcliparea();
-
- if ( hud_panel_radar_mouse )
- {
- string message = "Click to select teleport destination";
-
- if ( getstati(STAT_HEALTH) <= 0 )
- {
- message = "Click to select spawn location";
- }
-
- drawcolorcodedstring(pos + '0.5 0 0' * (mySize_x - stringwidth(message, true, hud_fontsize)) - '0 1 0' * hud_fontsize_y * 2,
- message, hud_fontsize, hud_panel_radar_foreground_alpha, DRAWFLAG_NORMAL);
-
- hud_panel_radar_bottom = pos_y + mySize_y + hud_fontsize_y;
- }
-}
-
-// Score (#7)
-//
-void HUD_UpdatePlayerTeams();
-void HUD_Score_Rankings(vector pos, vector mySize, entity me)
-{
- float score;
- entity tm = world, pl;
- int SCOREPANEL_MAX_ENTRIES = 6;
- float SCOREPANEL_ASPECTRATIO = 2;
- int entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize.y/mySize.x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
- vector fontsize = '1 1 0' * (mySize.y/entries);
-
- vector rgb, score_color;
- rgb = '1 1 1';
- score_color = '1 1 1';
-
- float name_size = mySize.x*0.75;
- float spacing_size = mySize.x*0.04;
- const float highlight_alpha = 0.2;
- int i = 0, first_pl = 0;
- bool me_printed = false;
- string s;
- if (autocvar__hud_configure)
- {
- float players_per_team = 0;
- if (team_count)
- {
- // show team scores in the first line
- float score_size = mySize.x / team_count;
- players_per_team = max(2, ceil((entries - 1) / team_count));
- for(i=0; i<team_count; ++i) {
- if (i == floor((entries - 2) / players_per_team) || (entries == 1 && i == 0))
- HUD_Panel_DrawHighlight(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(pos + eX * score_size * i, ftos(175 - 23*i), eX * score_size + eY * fontsize.y, Team_ColorRGB(ColorByTeam(i)) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- first_pl = 1;
- pos.y += fontsize.y;
- }
- score = 10 + SCOREPANEL_MAX_ENTRIES * 3;
- for (i=first_pl; i<entries; ++i)
- {
- //simulate my score is lower than all displayed players,
- //so that I don't appear at all showing pure rankings.
- //This is to better show the difference between the 2 ranking views
- if (i == entries-1 && autocvar_hud_panel_score_rankings == 1)
- {
- rgb = '1 1 0';
- drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- s = GetPlayerName(player_localnum);
- score = 7;
- }
- else
- {
- s = sprintf(_("Player %d"), i + 1 - first_pl);
- score -= 3;
- }
-
- if (team_count)
- score_color = Team_ColorRGB(ColorByTeam(floor((i - first_pl) / players_per_team))) * 0.8;
- s = textShortenToWidth(s, name_size, fontsize, stringwidth_colors);
- drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring(pos + eX * (name_size + spacing_size), ftos(score), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
- pos.y += fontsize.y;
- }
- return;
- }
-
- if (!scoreboard_fade_alpha) // the scoreboard too calls HUD_UpdatePlayerTeams
- HUD_UpdatePlayerTeams();
- if (team_count)
- {
- // show team scores in the first line
- float score_size = mySize.x / team_count;
- for(tm = teams.sort_next; tm; tm = tm.sort_next) {
- if(tm.team == NUM_SPECTATOR)
- continue;
- if (tm.team == myteam)
- drawfill(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores[ts_primary])), eX * score_size + eY * fontsize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
- ++i;
- }
- first_pl = 1;
- pos.y += fontsize.y;
- tm = teams.sort_next;
- }
- i = first_pl;
-
- do
- for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
- {
- if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
- continue;
-
- if (i == entries-1 && !me_printed && pl != me)
- if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
- {
- for (pl = me.sort_next; pl; pl = pl.sort_next)
- if (pl.team != NUM_SPECTATOR)
- break;
-
- if (pl)
- rgb = '1 1 0'; //not last but not among the leading players: yellow
- else
- rgb = '1 0 0'; //last: red
- pl = me;
- }
-
- if (pl == me)
- {
- if (i == first_pl)
- rgb = '0 1 0'; //first: green
- me_printed = true;
- drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- if (team_count)
- score_color = Team_ColorRGB(pl.team) * 0.8;
- s = textShortenToWidth(GetPlayerName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
- drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores[ps_primary])), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
- pos.y += fontsize.y;
- ++i;
- }
- while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
-}
-
-void HUD_Score(void)
-{
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_score) return;
- if(spectatee_status == -1 && (gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
- }
-
- HUD_Panel_UpdateCvars();
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- float score, distribution = 0;
- string sign;
- vector distribution_color;
- entity tm, pl, me;
-
- me = playerslots[current_player];
-
- if((scores_flags[ps_primary] & SFL_TIME) && !teamplay) { // race/cts record display on HUD
- string timer, distrtimer;
-
- pl = players.sort_next;
- if(pl == me)
- pl = pl.sort_next;
- if(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)
- if(pl.scores[ps_primary] == 0)
- pl = world;
-
- score = me.(scores[ps_primary]);
- timer = TIME_ENCODED_TOSTRING(score);
-
- draw_beginBoldFont();
- if (pl && ((!(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)) || score)) {
- // distribution display
- distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
-
- distrtimer = ftos_decimals(fabs(distribution/pow(10, TIME_DECIMALS)), TIME_DECIMALS);
-
- if (distribution <= 0) {
- distribution_color = '0 1 0';
- sign = "-";
- }
- else {
- distribution_color = '1 0 0';
- sign = "+";
- }
- drawstring_aspect(pos + eX * 0.75 * mySize.x, strcat(sign, distrtimer), eX * 0.25 * mySize.x + eY * (1/3) * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- // race record display
- if (distribution <= 0)
- HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(pos, timer, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- draw_endBoldFont();
- } else if (!teamplay) { // non-teamgames
- if ((spectatee_status == -1 && !autocvar__hud_configure) || autocvar_hud_panel_score_rankings)
- {
- HUD_Score_Rankings(pos, mySize, me);
- return;
- }
- // me vector := [team/connected frags id]
- pl = players.sort_next;
- if(pl == me)
- pl = pl.sort_next;
-
- if(autocvar__hud_configure)
- distribution = 42;
- else if(pl)
- distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
- else
- distribution = 0;
-
- score = me.(scores[ps_primary]);
- if(autocvar__hud_configure)
- score = 123;
-
- if(distribution >= 5)
- distribution_color = eY;
- else if(distribution >= 0)
- distribution_color = '1 1 1';
- else if(distribution >= -5)
- distribution_color = '1 1 0';
- else
- distribution_color = eX;
-
- string distribution_str;
- distribution_str = ftos(distribution);
- draw_beginBoldFont();
- if (distribution >= 0)
- {
- if (distribution > 0)
- distribution_str = strcat("+", distribution_str);
- HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(pos + eX * 0.75 * mySize.x, distribution_str, eX * 0.25 * mySize.x + eY * (1/3) * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
- draw_endBoldFont();
- } else { // teamgames
- float row, column, rows = 0, columns = 0;
- vector offset = '0 0 0';
- vector score_pos, score_size; //for scores other than myteam
- if(autocvar_hud_panel_score_rankings)
- {
- HUD_Score_Rankings(pos, mySize, me);
- return;
- }
- if(spectatee_status == -1)
- {
- rows = HUD_GetRowCount(team_count, mySize, 3);
- columns = ceil(team_count/rows);
- score_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
-
- float newSize;
- if(score_size.x/score_size.y > 3)
- {
- newSize = 3 * score_size.y;
- offset.x = score_size.x - newSize;
- pos.x += offset.x/2;
- score_size.x = newSize;
- }
- else
- {
- newSize = 1/3 * score_size.x;
- offset.y = score_size.y - newSize;
- pos.y += offset.y/2;
- score_size.y = newSize;
- }
- }
- else
- score_size = eX * mySize.x*(1/4) + eY * mySize.y*(1/3);
-
- float max_fragcount;
- max_fragcount = -99;
- draw_beginBoldFont();
- row = column = 0;
- for(tm = teams.sort_next; tm; tm = tm.sort_next) {
- if(tm.team == NUM_SPECTATOR)
- continue;
- score = tm.(teamscores[ts_primary]);
- if(autocvar__hud_configure)
- score = 123;
-
- if (score > max_fragcount)
- max_fragcount = score;
-
- if (spectatee_status == -1)
- {
- score_pos = pos + eX * column * (score_size.x + offset.x) + eY * row * (score_size.y + offset.y);
- if (max_fragcount == score)
- HUD_Panel_DrawHighlight(score_pos, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(score_pos, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
- ++row;
- if(row >= rows)
- {
- row = 0;
- ++column;
- }
- }
- else if(tm.team == myteam) {
- if (max_fragcount == score)
- HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
- } else {
- if (max_fragcount == score)
- HUD_Panel_DrawHighlight(pos + eX * 0.75 * mySize.x + eY * (1/3) * rows * mySize.y, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(pos + eX * 0.75 * mySize.x + eY * (1/3) * rows * mySize.y, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
- ++rows;
- }
- }
- draw_endBoldFont();
- }
-}
-
-// Race timer (#8)
-//
-void HUD_RaceTimer (void)
-{
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_racetimer) return;
- if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
- if(spectatee_status == -1) return;
- }
-
- HUD_Panel_UpdateCvars();
-
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- // always force 4:1 aspect
- vector newSize = '0 0 0';
- if(mySize.x/mySize.y > 4)
- {
- newSize.x = 4 * mySize.y;
- newSize.y = mySize.y;
-
- pos.x = pos.x + (mySize.x - newSize.x) / 2;
- }
- else
- {
- newSize.y = 1/4 * mySize.x;
- newSize.x = mySize.x;
-
- pos.y = pos.y + (mySize.y - newSize.y) / 2;
- }
- mySize = newSize;
-
- float a, t;
- string s, forcetime;
-
- if(autocvar__hud_configure)
- {
- s = "0:13:37";
- draw_beginBoldFont();
- drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.60 0.60 0' * mySize.y), s, '0.60 0.60 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- draw_endBoldFont();
- s = _("^1Intermediate 1 (+15.42)");
- drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.60 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
- s = sprintf(_("^1PENALTY: %.1f (%s)"), 2, "missing a checkpoint");
- drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.80 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- else if(race_checkpointtime)
- {
- a = bound(0, 2 - (time - race_checkpointtime), 1);
- s = "";
- forcetime = "";
- if(a > 0) // just hit a checkpoint?
- {
- if(race_checkpoint != 254)
- {
- if(race_time && race_previousbesttime)
- s = MakeRaceString(race_checkpoint, TIME_DECODE(race_time) - TIME_DECODE(race_previousbesttime), 0, 0, race_previousbestname);
- else
- s = MakeRaceString(race_checkpoint, 0, -1, 0, race_previousbestname);
- if(race_time)
- forcetime = TIME_ENCODED_TOSTRING(race_time);
- }
- }
- else
- {
- if(race_laptime && race_nextbesttime && race_nextcheckpoint != 254)
- {
- a = bound(0, 2 - ((race_laptime + TIME_DECODE(race_nextbesttime)) - (time + TIME_DECODE(race_penaltyaccumulator))), 1);
- if(a > 0) // next one?
- {
- s = MakeRaceString(race_nextcheckpoint, (time + TIME_DECODE(race_penaltyaccumulator)) - race_laptime, TIME_DECODE(race_nextbesttime), 0, race_nextbestname);
- }
- }
- }
-
- if(s != "" && a > 0)
- {
- drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
- }
-
- if(race_penaltytime)
- {
- a = bound(0, 2 - (time - race_penaltyeventtime), 1);
- if(a > 0)
- {
- s = sprintf(_("^1PENALTY: %.1f (%s)"), race_penaltytime * 0.1, race_penaltyreason);
- drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.8 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
- }
- }
-
- draw_beginBoldFont();
-
- if(forcetime != "")
- {
- a = bound(0, (time - race_checkpointtime) / 0.5, 1);
- drawstring_expanding(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(forcetime, false, '1 1 0' * 0.6 * mySize.y), forcetime, '1 1 0' * 0.6 * mySize.y, '1 1 1', panel_fg_alpha, 0, a);
- }
- else
- a = 1;
-
- if(race_laptime && race_checkpoint != 255)
- {
- s = TIME_ENCODED_TOSTRING(TIME_ENCODE(time + TIME_DECODE(race_penaltyaccumulator) - race_laptime));
- drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.6 0.6 0' * mySize.y), s, '0.6 0.6 0' * mySize.y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- }
-
- draw_endBoldFont();
- }
- else
- {
- if(race_mycheckpointtime)
- {
- a = bound(0, 2 - (time - race_mycheckpointtime), 1);
- s = MakeRaceString(race_mycheckpoint, TIME_DECODE(race_mycheckpointdelta), -(race_mycheckpointenemy == ""), race_mycheckpointlapsdelta, race_mycheckpointenemy);
- drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
- }
- if(race_othercheckpointtime && race_othercheckpointenemy != "")
- {
- a = bound(0, 2 - (time - race_othercheckpointtime), 1);
- s = MakeRaceString(race_othercheckpoint, -TIME_DECODE(race_othercheckpointdelta), -(race_othercheckpointenemy == ""), race_othercheckpointlapsdelta, race_othercheckpointenemy);
- drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
- }
-
- if(race_penaltytime && !race_penaltyaccumulator)
- {
- t = race_penaltytime * 0.1 + race_penaltyeventtime;
- a = bound(0, (1 + t - time), 1);
- if(a > 0)
- {
- if(time < t)
- s = sprintf(_("^1PENALTY: %.1f (%s)"), (t - time) * 0.1, race_penaltyreason);
- else
- s = sprintf(_("^2PENALTY: %.1f (%s)"), 0, race_penaltyreason);
- drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
- }
- }
- }
-}
-
-// Vote window (#9)
-//
-
-void HUD_Vote(void)
-{
- if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
- {
- vote_active = 1;
- if (autocvar__hud_configure)
- {
- vote_yescount = 0;
- vote_nocount = 0;
- LOG_INFO(_("^1You must answer before entering hud configure mode\n"));
- cvar_set("_hud_configure", "0");
- }
- if(vote_called_vote)
- strunzone(vote_called_vote);
- vote_called_vote = strzone(_("^2Name ^7instead of \"^1Anonymous player^7\" in stats"));
- uid2name_dialog = 1;
- }
-
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_vote) return;
-
- panel_fg_alpha = autocvar_hud_panel_fg_alpha;
- panel_bg_alpha_str = autocvar_hud_panel_vote_bg_alpha;
-
- if(panel_bg_alpha_str == "") {
- panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha);
- }
- panel_bg_alpha = stof(panel_bg_alpha_str);
- }
- else
- {
- vote_yescount = 3;
- vote_nocount = 2;
- vote_needed = 4;
- }
-
- string s;
- float a;
- if(vote_active != vote_prev) {
- vote_change = time;
- vote_prev = vote_active;
- }
-
- if(vote_active || autocvar__hud_configure)
- vote_alpha = bound(0, (time - vote_change) * 2, 1);
- else
- vote_alpha = bound(0, 1 - (time - vote_change) * 2, 1);
-
- if(!vote_alpha)
- return;
-
- HUD_Panel_UpdateCvars();
-
- if(uid2name_dialog)
- {
- panel_pos = eX * 0.3 * vid_conwidth + eY * 0.1 * vid_conheight;
- panel_size = eX * 0.4 * vid_conwidth + eY * 0.3 * vid_conheight;
- }
-
- // these must be below above block
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- a = vote_alpha * (vote_highlighted ? autocvar_hud_panel_vote_alreadyvoted_alpha : 1);
- HUD_Panel_DrawBg(a);
- a = panel_fg_alpha * a;
-
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- // always force 3:1 aspect
- vector newSize = '0 0 0';
- if(mySize.x/mySize.y > 3)
- {
- newSize.x = 3 * mySize.y;
- newSize.y = mySize.y;
-
- pos.x = pos.x + (mySize.x - newSize.x) / 2;
- }
- else
- {
- newSize.y = 1/3 * mySize.x;
- newSize.x = mySize.x;
-
- pos.y = pos.y + (mySize.y - newSize.y) / 2;
- }
- mySize = newSize;
-
- s = _("A vote has been called for:");
- if(uid2name_dialog)
- s = _("Allow servers to store and display your name?");
- drawstring_aspect(pos, s, eX * mySize.x + eY * (2/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
- s = textShortenToWidth(vote_called_vote, mySize.x, '1 1 0' * mySize.y * (1/8), stringwidth_colors);
- if(autocvar__hud_configure)
- s = _("^1Configure the HUD");
- drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize.y, s, eX * mySize.x + eY * (1.75/8) * mySize.y, a, DRAWFLAG_NORMAL);
-
- // print the yes/no counts
- s = sprintf(_("Yes (%s): %d"), getcommandkey("vyes", "vyes"), vote_yescount);
- drawstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '0 1 0', a, DRAWFLAG_NORMAL);
- s = sprintf(_("No (%s): %d"), getcommandkey("vno", "vno"), vote_nocount);
- drawstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '1 0 0', a, DRAWFLAG_NORMAL);
-
- // draw the progress bar backgrounds
- drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_back", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
-
- // draw the highlights
- if(vote_highlighted == 1) {
- drawsetcliparea(pos.x, pos.y, mySize.x * 0.5, mySize.y);
- drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
- }
- else if(vote_highlighted == -1) {
- drawsetcliparea(pos.x + 0.5 * mySize.x, pos.y, mySize.x * 0.5, mySize.y);
- drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
- }
-
- // draw the progress bars
- if(vote_yescount && vote_needed)
- {
- drawsetcliparea(pos.x, pos.y, mySize.x * 0.5 * (vote_yescount/vote_needed), mySize.y);
- drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
- }
-
- if(vote_nocount && vote_needed)
- {
- drawsetcliparea(pos.x + mySize.x - mySize.x * 0.5 * (vote_nocount/vote_needed), pos.y, mySize.x * 0.5, mySize.y);
- drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
- }
-
- drawresetcliparea();
-}
-
-// Mod icons panel (#10)
-//
-
-bool mod_active; // is there any active mod icon?
-
-void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
-{
- int stat = -1;
- string pic = "";
- vector color = '0 0 0';
- switch(i)
- {
- case 0:
- stat = getstati(STAT_REDALIVE);
- pic = "player_red.tga";
- color = '1 0 0';
- break;
- case 1:
- stat = getstati(STAT_BLUEALIVE);
- pic = "player_blue.tga";
- color = '0 0 1';
- break;
- case 2:
- stat = getstati(STAT_YELLOWALIVE);
- pic = "player_yellow.tga";
- color = '1 1 0';
- break;
- default:
- case 3:
- stat = getstati(STAT_PINKALIVE);
- pic = "player_pink.tga";
- color = '1 0 1';
- break;
- }
-
- if(mySize.x/mySize.y > aspect_ratio)
- {
- i = aspect_ratio * mySize.y;
- myPos.x = myPos.x + (mySize.x - i) / 2;
- mySize.x = i;
- }
- else
- {
- i = 1/aspect_ratio * mySize.x;
- myPos.y = myPos.y + (mySize.y - i) / 2;
- mySize.y = i;
- }
-
- if(layout)
- {
- drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(myPos + eX * 0.7 * mySize.x, ftos(stat), eX * 0.3 * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- else
- drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
-// Clan Arena and Freeze Tag HUD modicons
-void HUD_Mod_CA(vector myPos, vector mySize)
-{
- mod_active = 1; // required in each mod function that always shows something
-
- int layout;
- if(gametype == MAPINFO_TYPE_CA)
- layout = autocvar_hud_panel_modicons_ca_layout;
- else //if(gametype == MAPINFO_TYPE_FREEZETAG)
- layout = autocvar_hud_panel_modicons_freezetag_layout;
- int rows, columns;
- float aspect_ratio;
- aspect_ratio = (layout) ? 2 : 1;
- rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
- columns = ceil(team_count/rows);
-
- int i;
- float row = 0, column = 0;
- vector pos, itemSize;
- itemSize = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
- for(i=0; i<team_count; ++i)
- {
- pos = myPos + eX * column * itemSize.x + eY * row * itemSize.y;
-
- DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
-
- ++row;
- if(row >= rows)
- {
- row = 0;
- ++column;
- }
- }
-}
-
-// CTF HUD modicon section
-int redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe, neutralflag_prevframe; // status during previous frame
-int redflag_prevstatus, blueflag_prevstatus, yellowflag_prevstatus, pinkflag_prevstatus, neutralflag_prevstatus; // last remembered status
-float redflag_statuschange_time, blueflag_statuschange_time, yellowflag_statuschange_time, pinkflag_statuschange_time, neutralflag_statuschange_time; // time when the status changed
-
-void HUD_Mod_CTF_Reset(void)
-{
- redflag_prevstatus = blueflag_prevstatus = yellowflag_prevstatus = pinkflag_prevstatus = neutralflag_prevstatus = 0;
- redflag_prevframe = blueflag_prevframe = yellowflag_prevframe = pinkflag_prevframe = neutralflag_prevframe = 0;
- redflag_statuschange_time = blueflag_statuschange_time = yellowflag_statuschange_time = pinkflag_statuschange_time = neutralflag_statuschange_time = 0;
-}
-
-void HUD_Mod_CTF(vector pos, vector mySize)
-{
- vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos, neutralflag_pos;
- vector flag_size;
- float f; // every function should have that
-
- int redflag, blueflag, yellowflag, pinkflag, neutralflag; // current status
- float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime, yellowflag_statuschange_elapsedtime, pinkflag_statuschange_elapsedtime, neutralflag_statuschange_elapsedtime; // time since the status changed
- bool ctf_oneflag; // one-flag CTF mode enabled/disabled
- int stat_items = getstati(STAT_CTF_FLAGSTATUS, 0, 24);
- float fs, fs2, fs3, size1, size2;
- vector e1, e2;
-
- redflag = (stat_items/CTF_RED_FLAG_TAKEN) & 3;
- blueflag = (stat_items/CTF_BLUE_FLAG_TAKEN) & 3;
- yellowflag = (stat_items/CTF_YELLOW_FLAG_TAKEN) & 3;
- pinkflag = (stat_items/CTF_PINK_FLAG_TAKEN) & 3;
- neutralflag = (stat_items/CTF_NEUTRAL_FLAG_TAKEN) & 3;
-
- ctf_oneflag = (stat_items & CTF_FLAG_NEUTRAL);
-
- mod_active = (redflag || blueflag || yellowflag || pinkflag || neutralflag);
-
- if (autocvar__hud_configure) {
- redflag = 1;
- blueflag = 2;
- if (team_count >= 3)
- yellowflag = 2;
- if (team_count >= 4)
- pinkflag = 3;
- ctf_oneflag = neutralflag = 0; // disable neutral flag in hud editor?
- }
-
- // when status CHANGES, set old status into prevstatus and current status into status
- #define X(team) do { \
- if (team##flag != team##flag_prevframe) { \
- team##flag_statuschange_time = time; \
- team##flag_prevstatus = team##flag_prevframe; \
- team##flag_prevframe = team##flag; \
- } \
- team##flag_statuschange_elapsedtime = time - team##flag_statuschange_time; \
- } while (0)
- X(red);
- X(blue);
- X(yellow);
- X(pink);
- X(neutral);
- #undef X
-
- const float BLINK_FACTOR = 0.15;
- const float BLINK_BASE = 0.85;
- // note:
- // RMS = sqrt(BLINK_BASE^2 + 0.5 * BLINK_FACTOR^2)
- // thus
- // BLINK_BASE = sqrt(RMS^2 - 0.5 * BLINK_FACTOR^2)
- // ensure RMS == 1
- const float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
-
- #define X(team, cond) \
- string team##_icon, team##_icon_prevstatus; \
- int team##_alpha, team##_alpha_prevstatus; \
- team##_alpha = team##_alpha_prevstatus = 1; \
- do { \
- switch (team##flag) { \
- case 1: team##_icon = "flag_" #team "_taken"; break; \
- case 2: team##_icon = "flag_" #team "_lost"; break; \
- case 3: team##_icon = "flag_" #team "_carrying"; team##_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
- default: \
- if ((stat_items & CTF_SHIELDED) && (cond)) { \
- team##_icon = "flag_" #team "_shielded"; \
- } else { \
- team##_icon = string_null; \
- } \
- break; \
- } \
- switch (team##flag_prevstatus) { \
- case 1: team##_icon_prevstatus = "flag_" #team "_taken"; break; \
- case 2: team##_icon_prevstatus = "flag_" #team "_lost"; break; \
- case 3: team##_icon_prevstatus = "flag_" #team "_carrying"; team##_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
- default: \
- if (team##flag == 3) { \
- team##_icon_prevstatus = "flag_" #team "_carrying"; /* make it more visible */\
- } else if((stat_items & CTF_SHIELDED) && (cond)) { \
- team##_icon_prevstatus = "flag_" #team "_shielded"; \
- } else { \
- team##_icon_prevstatus = string_null; \
- } \
- break; \
- } \
- } while (0)
- X(red, myteam != NUM_TEAM_1);
- X(blue, myteam != NUM_TEAM_2);
- X(yellow, myteam != NUM_TEAM_3);
- X(pink, myteam != NUM_TEAM_4);
- X(neutral, true);
- #undef X
-
- if (ctf_oneflag) {
- // hacky, but these aren't needed
- red_icon = red_icon_prevstatus = blue_icon = blue_icon_prevstatus = yellow_icon = yellow_icon_prevstatus = pink_icon = pink_icon_prevstatus = string_null;
- fs = fs2 = fs3 = 1;
- } else switch (team_count) {
- default:
- case 2: fs = 0.5; fs2 = 0.5; fs3 = 0.5; break;
- case 3: fs = 1; fs2 = 0.35; fs3 = 0.35; break;
- case 4: fs = 0.75; fs2 = 0.25; fs3 = 0.5; break;
- }
-
- if (mySize_x > mySize_y) {
- size1 = mySize_x;
- size2 = mySize_y;
- e1 = eX;
- e2 = eY;
- } else {
- size1 = mySize_y;
- size2 = mySize_x;
- e1 = eY;
- e2 = eX;
- }
-
- switch (myteam) {
- default:
- case NUM_TEAM_1: {
- redflag_pos = pos;
- blueflag_pos = pos + eX * fs2 * size1;
- yellowflag_pos = pos - eX * fs2 * size1;
- pinkflag_pos = pos + eX * fs3 * size1;
- break;
- }
- case NUM_TEAM_2: {
- redflag_pos = pos + eX * fs2 * size1;
- blueflag_pos = pos;
- yellowflag_pos = pos - eX * fs2 * size1;
- pinkflag_pos = pos + eX * fs3 * size1;
- break;
- }
- case NUM_TEAM_3: {
- redflag_pos = pos + eX * fs3 * size1;
- blueflag_pos = pos - eX * fs2 * size1;
- yellowflag_pos = pos;
- pinkflag_pos = pos + eX * fs2 * size1;
- break;
- }
- case NUM_TEAM_4: {
- redflag_pos = pos - eX * fs2 * size1;
- blueflag_pos = pos + eX * fs3 * size1;
- yellowflag_pos = pos + eX * fs2 * size1;
- pinkflag_pos = pos;
- break;
- }
- }
- neutralflag_pos = pos;
- flag_size = e1 * fs * size1 + e2 * size2;
-
- #define X(team) do { \
- f = bound(0, team##flag_statuschange_elapsedtime * 2, 1); \
- if (team##_icon_prevstatus && f < 1) \
- drawpic_aspect_skin_expanding(team##flag_pos, team##_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * team##_alpha_prevstatus, DRAWFLAG_NORMAL, f); \
- if (team##_icon) \
- drawpic_aspect_skin(team##flag_pos, team##_icon, flag_size, '1 1 1', panel_fg_alpha * team##_alpha * f, DRAWFLAG_NORMAL); \
- } while (0)
- X(red);
- X(blue);
- X(yellow);
- X(pink);
- X(neutral);
- #undef X
-}
-
-// Keyhunt HUD modicon section
-vector KH_SLOTS[4];
-
-void HUD_Mod_KH(vector pos, vector mySize)
-{
- mod_active = 1; // keyhunt should never hide the mod icons panel
-
- // Read current state
-
- int state = getstati(STAT_KH_KEYS);
- int i, key_state;
- int all_keys, team1_keys, team2_keys, team3_keys, team4_keys, dropped_keys, carrying_keys;
- all_keys = team1_keys = team2_keys = team3_keys = team4_keys = dropped_keys = carrying_keys = 0;
-
- for(i = 0; i < 4; ++i)
- {
- key_state = (bitshift(state, i * -5) & 31) - 1;
-
- if(key_state == -1)
- continue;
-
- if(key_state == 30)
- {
- ++carrying_keys;
- key_state = myteam;
- }
-
- switch(key_state)
- {
- case NUM_TEAM_1: ++team1_keys; break;
- case NUM_TEAM_2: ++team2_keys; break;
- case NUM_TEAM_3: ++team3_keys; break;
- case NUM_TEAM_4: ++team4_keys; break;
- case 29: ++dropped_keys; break;
- }
-
- ++all_keys;
- }
-
- // Calculate slot measurements
-
- vector slot_size;
-
- if(all_keys == 4 && mySize.x * 0.5 < mySize.y && mySize.y * 0.5 < mySize.x)
- {
- // Quadratic arrangement
- slot_size = eX * mySize.x * 0.5 + eY * mySize.y * 0.5;
- KH_SLOTS[0] = pos;
- KH_SLOTS[1] = pos + eX * slot_size.x;
- KH_SLOTS[2] = pos + eY * slot_size.y;
- KH_SLOTS[3] = pos + eX * slot_size.x + eY * slot_size.y;
- }
- else
- {
- if(mySize.x > mySize.y)
- {
- // Horizontal arrangement
- slot_size = eX * mySize.x / all_keys + eY * mySize.y;
- for(i = 0; i < all_keys; ++i)
- KH_SLOTS[i] = pos + eX * slot_size.x * i;
- }
- else
- {
- // Vertical arrangement
- slot_size = eX * mySize.x + eY * mySize.y / all_keys;
- for(i = 0; i < all_keys; ++i)
- KH_SLOTS[i] = pos + eY * slot_size.y * i;
- }
- }
-
- // Make icons blink in case of RUN HERE
-
- float blink = 0.6 + sin(2*M_PI*time) / 2.5; // Oscillate between 0.2 and 1
- float alpha;
- alpha = 1;
-
- if(carrying_keys)
- switch(myteam)
- {
- case NUM_TEAM_1: if(team1_keys == all_keys) alpha = blink; break;
- case NUM_TEAM_2: if(team2_keys == all_keys) alpha = blink; break;
- case NUM_TEAM_3: if(team3_keys == all_keys) alpha = blink; break;
- case NUM_TEAM_4: if(team4_keys == all_keys) alpha = blink; break;
- }
-
- // Draw icons
-
- i = 0;
-
- while(team1_keys--)
- if(myteam == NUM_TEAM_1 && carrying_keys)
- {
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
- --carrying_keys;
- }
- else
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
- while(team2_keys--)
- if(myteam == NUM_TEAM_2 && carrying_keys)
- {
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
- --carrying_keys;
- }
- else
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
- while(team3_keys--)
- if(myteam == NUM_TEAM_3 && carrying_keys)
- {
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
- --carrying_keys;
- }
- else
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
- while(team4_keys--)
- if(myteam == NUM_TEAM_4 && carrying_keys)
- {
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
- --carrying_keys;
- }
- else
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
- while(dropped_keys--)
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_dropped", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-}
-
-// Keepaway HUD mod icon
-int kaball_prevstatus; // last remembered status
-float kaball_statuschange_time; // time when the status changed
-
-// we don't need to reset for keepaway since it immediately
-// autocorrects prevstatus as to if the player has the ball or not
-
-void HUD_Mod_Keepaway(vector pos, vector mySize)
-{
- mod_active = 1; // keepaway should always show the mod HUD
-
- float BLINK_FACTOR = 0.15;
- float BLINK_BASE = 0.85;
- float BLINK_FREQ = 5;
- float kaball_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
-
- int stat_items = getstati(STAT_ITEMS, 0, 24);
- int kaball = (stat_items/IT_KEY1) & 1;
-
- if(kaball != kaball_prevstatus)
- {
- kaball_statuschange_time = time;
- kaball_prevstatus = kaball;
- }
-
- vector kaball_pos, kaball_size;
-
- if(mySize.x > mySize.y) {
- kaball_pos = pos + eX * 0.25 * mySize.x;
- kaball_size = eX * 0.5 * mySize.x + eY * mySize.y;
- } else {
- kaball_pos = pos + eY * 0.25 * mySize.y;
- kaball_size = eY * 0.5 * mySize.y + eX * mySize.x;
- }
-
- float kaball_statuschange_elapsedtime = time - kaball_statuschange_time;
- float f = bound(0, kaball_statuschange_elapsedtime*2, 1);
-
- if(kaball_prevstatus && f < 1)
- drawpic_aspect_skin_expanding(kaball_pos, "keepawayball_carrying", kaball_size, '1 1 1', panel_fg_alpha * kaball_alpha, DRAWFLAG_NORMAL, f);
-
- if(kaball)
- drawpic_aspect_skin(pos, "keepawayball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha * kaball_alpha * f, DRAWFLAG_NORMAL);
-}
-
-
-// Nexball HUD mod icon
-void HUD_Mod_NexBall(vector pos, vector mySize)
-{
- float nb_pb_starttime, dt, p;
- int stat_items;
-
- stat_items = getstati(STAT_ITEMS, 0, 24);
- nb_pb_starttime = getstatf(STAT_NB_METERSTART);
-
- if (stat_items & IT_KEY1)
- mod_active = 1;
- else
- mod_active = 0;
-
- //Manage the progress bar if any
- if (nb_pb_starttime > 0)
- {
- dt = (time - nb_pb_starttime) % nb_pb_period;
- // one period of positive triangle
- p = 2 * dt / nb_pb_period;
- if (p > 1)
- p = 2 - p;
-
- HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, (mySize.x <= mySize.y), 0, autocvar_hud_progressbar_nexball_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- }
-
- if (stat_items & IT_KEY1)
- drawpic_aspect_skin(pos, "nexball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
-// Race/CTS HUD mod icons
-float crecordtime_prev; // last remembered crecordtime
-float crecordtime_change_time; // time when crecordtime last changed
-float srecordtime_prev; // last remembered srecordtime
-float srecordtime_change_time; // time when srecordtime last changed
-
-float race_status_time;
-int race_status_prev;
-string race_status_name_prev;
-void HUD_Mod_Race(vector pos, vector mySize)
-{
- mod_active = 1; // race should never hide the mod icons panel
- entity me;
- me = playerslots[player_localnum];
- float t, score;
- float f; // yet another function has this
- score = me.(scores[ps_primary]);
-
- if(!(scores_flags[ps_primary] & SFL_TIME) || teamplay) // race/cts record display on HUD
- return; // no records in the actual race
-
- // clientside personal record
- string rr;
- if(gametype == MAPINFO_TYPE_CTS)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
- t = stof(db_get(ClientProgsDB, strcat(shortmapname, rr, "time")));
-
- if(score && (score < t || !t)) {
- db_put(ClientProgsDB, strcat(shortmapname, rr, "time"), ftos(score));
- if(autocvar_cl_autodemo_delete_keeprecords)
- {
- f = autocvar_cl_autodemo_delete;
- f &= ~1;
- cvar_set("cl_autodemo_delete", ftos(f)); // don't delete demo with new record!
- }
- }
-
- if(t != crecordtime_prev) {
- crecordtime_prev = t;
- crecordtime_change_time = time;
- }
-
- vector textPos, medalPos;
- float squareSize;
- if(mySize.x > mySize.y) {
- // text on left side
- squareSize = min(mySize.y, mySize.x/2);
- textPos = pos + eX * 0.5 * max(0, mySize.x/2 - squareSize) + eY * 0.5 * (mySize.y - squareSize);
- medalPos = pos + eX * 0.5 * max(0, mySize.x/2 - squareSize) + eX * 0.5 * mySize.x + eY * 0.5 * (mySize.y - squareSize);
- } else {
- // text on top
- squareSize = min(mySize.x, mySize.y/2);
- textPos = pos + eY * 0.5 * max(0, mySize.y/2 - squareSize) + eX * 0.5 * (mySize.x - squareSize);
- medalPos = pos + eY * 0.5 * max(0, mySize.y/2 - squareSize) + eY * 0.5 * mySize.y + eX * 0.5 * (mySize.x - squareSize);
- }
-
- f = time - crecordtime_change_time;
-
- if (f > 1) {
- drawstring_aspect(textPos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(textPos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- } else {
- drawstring_aspect(textPos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(textPos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect_expanding(pos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
- drawstring_aspect_expanding(pos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
- }
-
- // server record
- t = race_server_record;
- if(t != srecordtime_prev) {
- srecordtime_prev = t;
- srecordtime_change_time = time;
- }
- f = time - srecordtime_change_time;
-
- if (f > 1) {
- drawstring_aspect(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- } else {
- drawstring_aspect(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect_expanding(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
- drawstring_aspect_expanding(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
- }
-
- if (race_status != race_status_prev || race_status_name != race_status_name_prev) {
- race_status_time = time + 5;
- race_status_prev = race_status;
- if (race_status_name_prev)
- strunzone(race_status_name_prev);
- race_status_name_prev = strzone(race_status_name);
- }
-
- // race "awards"
- float a;
- a = bound(0, race_status_time - time, 1);
-
- string s;
- s = textShortenToWidth(race_status_name, squareSize, '1 1 0' * 0.1 * squareSize, stringwidth_colors);
-
- float rank;
- if(race_status > 0)
- rank = race_CheckName(race_status_name);
- else
- rank = 0;
- string rankname;
- rankname = count_ordinal(rank);
-
- vector namepos;
- namepos = medalPos + '0 0.8 0' * squareSize;
- vector rankpos;
- rankpos = medalPos + '0 0.15 0' * squareSize;
-
- if(race_status == 0)
- drawpic_aspect_skin(medalPos, "race_newfail", '1 1 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- else if(race_status == 1) {
- drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newtime", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
- drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- } else if(race_status == 2) {
- if(race_status_name == GetPlayerName(player_localnum) || !race_myrank || race_myrank < rank)
- drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankgreen", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- else
- drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankyellow", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
- drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- } else if(race_status == 3) {
- drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrecordserver", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
- drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- }
-
- if (race_status_time - time <= 0) {
- race_status_prev = -1;
- race_status = -1;
- if(race_status_name)
- strunzone(race_status_name);
- race_status_name = string_null;
- if(race_status_name_prev)
- strunzone(race_status_name_prev);
- race_status_name_prev = string_null;
- }
-}
-
-void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
-{
- float stat = -1;
- string pic = "";
- vector color = '0 0 0';
- switch(i)
- {
- case 0:
- stat = getstatf(STAT_DOM_PPS_RED);
- pic = "dom_icon_red";
- color = '1 0 0';
- break;
- case 1:
- stat = getstatf(STAT_DOM_PPS_BLUE);
- pic = "dom_icon_blue";
- color = '0 0 1';
- break;
- case 2:
- stat = getstatf(STAT_DOM_PPS_YELLOW);
- pic = "dom_icon_yellow";
- color = '1 1 0';
- break;
- default:
- case 3:
- stat = getstatf(STAT_DOM_PPS_PINK);
- pic = "dom_icon_pink";
- color = '1 0 1';
- break;
- }
- float pps_ratio = stat / getstatf(STAT_DOM_TOTAL_PPS);
-
- if(mySize.x/mySize.y > aspect_ratio)
- {
- i = aspect_ratio * mySize.y;
- myPos.x = myPos.x + (mySize.x - i) / 2;
- mySize.x = i;
- }
- else
- {
- i = 1/aspect_ratio * mySize.x;
- myPos.y = myPos.y + (mySize.y - i) / 2;
- mySize.y = i;
- }
-
- if (layout) // show text too
- {
- //draw the text
- color *= 0.5 + pps_ratio * (1 - 0.5); // half saturated color at min, full saturated at max
- if (layout == 2) // average pps
- drawstring_aspect(myPos + eX * mySize.y, ftos_decimals(stat, 2), eX * (2/3) * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
- else // percentage of average pps
- drawstring_aspect(myPos + eX * mySize.y, strcat( ftos(floor(pps_ratio*100 + 0.5)), "%" ), eX * (2/3) * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
- }
-
- //draw the icon
- drawpic_aspect_skin(myPos, pic, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- if (stat > 0)
- {
- drawsetcliparea(myPos.x, myPos.y + mySize.y * (1 - pps_ratio), mySize.y, mySize.y * pps_ratio);
- drawpic_aspect_skin(myPos, strcat(pic, "-highlighted"), '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawresetcliparea();
- }
-}
-
-void HUD_Mod_Dom(vector myPos, vector mySize)
-{
- mod_active = 1; // required in each mod function that always shows something
-
- int layout = autocvar_hud_panel_modicons_dom_layout;
- int rows, columns;
- float aspect_ratio;
- aspect_ratio = (layout) ? 3 : 1;
- rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
- columns = ceil(team_count/rows);
-
- int i;
- float row = 0, column = 0;
- vector pos, itemSize;
- itemSize = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
- for(i=0; i<team_count; ++i)
- {
- pos = myPos + eX * column * itemSize.x + eY * row * itemSize.y;
-
- DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
-
- ++row;
- if(row >= rows)
- {
- row = 0;
- ++column;
- }
- }
-}
-
-void HUD_ModIcons_SetFunc()
-{
- switch(gametype)
- {
- case MAPINFO_TYPE_KEYHUNT: HUD_ModIcons_GameType = HUD_Mod_KH; break;
- case MAPINFO_TYPE_CTF: HUD_ModIcons_GameType = HUD_Mod_CTF; break;
- case MAPINFO_TYPE_NEXBALL: HUD_ModIcons_GameType = HUD_Mod_NexBall; break;
- case MAPINFO_TYPE_CTS:
- case MAPINFO_TYPE_RACE: HUD_ModIcons_GameType = HUD_Mod_Race; break;
- case MAPINFO_TYPE_CA:
- case MAPINFO_TYPE_FREEZETAG: HUD_ModIcons_GameType = HUD_Mod_CA; break;
- case MAPINFO_TYPE_DOMINATION: HUD_ModIcons_GameType = HUD_Mod_Dom; break;
- case MAPINFO_TYPE_KEEPAWAY: HUD_ModIcons_GameType = HUD_Mod_Keepaway; break;
- }
-}
-
-int mod_prev; // previous state of mod_active to check for a change
-float mod_alpha;
-float mod_change; // "time" when mod_active changed
-
-void HUD_ModIcons(void)
-{
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_modicons) return;
- if(!HUD_ModIcons_GameType) return;
- }
-
- HUD_Panel_UpdateCvars();
-
- draw_beginBoldFont();
-
- if(mod_active != mod_prev) {
- mod_change = time;
- mod_prev = mod_active;
- }
-
- if(mod_active || autocvar__hud_configure)
- mod_alpha = bound(0, (time - mod_change) * 2, 1);
- else
- mod_alpha = bound(0, 1 - (time - mod_change) * 2, 1);
-
- if(mod_alpha)
- HUD_Panel_DrawBg(mod_alpha);
-
- if(panel_bg_padding)
- {
- panel_pos += '1 1 0' * panel_bg_padding;
- panel_size -= '2 2 0' * panel_bg_padding;
- }
-
- if(autocvar__hud_configure)
- HUD_Mod_CTF(panel_pos, panel_size);
- else
- HUD_ModIcons_GameType(panel_pos, panel_size);
-
- draw_endBoldFont();
-}
-
-// Draw pressed keys (#11)
-//
-void HUD_PressedKeys(void)
-{
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_pressedkeys) return;
- if(spectatee_status <= 0 && autocvar_hud_panel_pressedkeys < 2) return;
- }
-
- HUD_Panel_UpdateCvars();
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- // force custom aspect
- float aspect = autocvar_hud_panel_pressedkeys_aspect;
- if(aspect)
- {
- vector newSize = '0 0 0';
- if(mySize.x/mySize.y > aspect)
- {
- newSize.x = aspect * mySize.y;
- newSize.y = mySize.y;
-
- pos.x = pos.x + (mySize.x - newSize.x) / 2;
- }
- else
- {
- newSize.y = 1/aspect * mySize.x;
- newSize.x = mySize.x;
-
- pos.y = pos.y + (mySize.y - newSize.y) / 2;
- }
- mySize = newSize;
- }
-
- vector keysize;
- keysize = eX * mySize.x * (1/3.0) + eY * mySize.y * (1/(3.0 - !autocvar_hud_panel_pressedkeys_attack));
- float pressedkeys;
- pressedkeys = getstatf(STAT_PRESSED_KEYS);
-
- if(autocvar_hud_panel_pressedkeys_attack)
- {
- drawpic_aspect_skin(pos + eX * keysize.x * 0.5, ((pressedkeys & KEY_ATCK) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawpic_aspect_skin(pos + eX * keysize.x * 1.5, ((pressedkeys & KEY_ATCK2) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- pos.y += keysize.y;
- }
-
- drawpic_aspect_skin(pos, ((pressedkeys & KEY_CROUCH) ? "key_crouch_inv.tga" : "key_crouch.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawpic_aspect_skin(pos + eX * keysize.x, ((pressedkeys & KEY_FORWARD) ? "key_forward_inv.tga" : "key_forward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawpic_aspect_skin(pos + eX * keysize.x * 2, ((pressedkeys & KEY_JUMP) ? "key_jump_inv.tga" : "key_jump.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- pos.y += keysize.y;
- drawpic_aspect_skin(pos, ((pressedkeys & KEY_LEFT) ? "key_left_inv.tga" : "key_left.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawpic_aspect_skin(pos + eX * keysize.x, ((pressedkeys & KEY_BACKWARD) ? "key_backward_inv.tga" : "key_backward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawpic_aspect_skin(pos + eX * keysize.x * 2, ((pressedkeys & KEY_RIGHT) ? "key_right_inv.tga" : "key_right.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
-// Handle chat as a panel (#12)
-//
-void HUD_Chat(void)
-{
- if(!autocvar__hud_configure)
- {
- if (!autocvar_hud_panel_chat)
- {
- if (!autocvar_con_chatrect)
- cvar_set("con_chatrect", "0");
- return;
- }
- if(autocvar__con_chat_maximized)
- {
- if(!hud_draw_maximized) return;
- }
- else if(chat_panel_modified)
- {
- panel.update_time = time; // forces reload of panel attributes
- chat_panel_modified = false;
- }
- }
-
- HUD_Panel_UpdateCvars();
-
- if(intermission == 2)
- {
- // reserve some more space to the mapvote panel
- // by resizing and moving chat panel to the bottom
- panel_size.y = min(panel_size.y, vid_conheight * 0.2);
- panel_pos.y = vid_conheight - panel_size.y - panel_bg_border * 2;
- chat_posy = panel_pos.y;
- chat_sizey = panel_size.y;
- }
- if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
- {
- panel_pos.y = panel_bg_border;
- panel_size.y = vid_conheight - panel_bg_border * 2;
- if(panel.current_panel_bg == "0") // force a border when maximized
- {
- string panel_bg;
- panel_bg = strcat(hud_skin_path, "/border_default");
- if(precache_pic(panel_bg) == "")
- panel_bg = "gfx/hud/default/border_default";
- if(panel.current_panel_bg)
- strunzone(panel.current_panel_bg);
- panel.current_panel_bg = strzone(panel_bg);
- chat_panel_modified = true;
- }
- panel_bg_alpha = max(0.75, panel_bg_alpha); // force an theAlpha of at least 0.75
- }
-
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- HUD_Panel_DrawBg(1);
-
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- if (!autocvar_con_chatrect)
- cvar_set("con_chatrect", "1");
-
- cvar_set("con_chatrect_x", ftos(pos.x/vid_conwidth));
- cvar_set("con_chatrect_y", ftos(pos.y/vid_conheight));
-
- cvar_set("con_chatwidth", ftos(mySize.x/vid_conwidth));
- cvar_set("con_chat", ftos(floor(mySize.y/autocvar_con_chatsize - 0.5)));
-
- if(autocvar__hud_configure)
- {
- vector chatsize;
- chatsize = '1 1 0' * autocvar_con_chatsize;
- cvar_set("con_chatrect_x", "9001"); // over 9000, we'll fake it instead for more control over theAlpha and such
- float i, a;
- for(i = 0; i < autocvar_con_chat; ++i)
- {
- if(i == autocvar_con_chat - 1)
- a = panel_fg_alpha;
- else
- a = panel_fg_alpha * floor(((i + 1) * 7 + autocvar_con_chattime)/45);
- drawcolorcodedstring(pos, textShortenToWidth(_("^3Player^7: This is the chat area."), mySize.x, chatsize, stringwidth_colors), chatsize, a, DRAWFLAG_NORMAL);
- pos.y += chatsize.y;
- }
- }
-}
-
-// Engine info panel (#13)
-//
-float prevfps;
-float prevfps_time;
-int framecounter;
-
-float frametimeavg;
-float frametimeavg1; // 1 frame ago
-float frametimeavg2; // 2 frames ago
-void HUD_EngineInfo(void)
-{
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_engineinfo) return;
- }
-
- HUD_Panel_UpdateCvars();
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- float currentTime = gettime(GETTIME_REALTIME);
- if(cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage"))
- {
- float currentframetime = currentTime - prevfps_time;
- frametimeavg = (frametimeavg + frametimeavg1 + frametimeavg2 + currentframetime)/4; // average three frametimes into framecounter for slightly more stable fps readings :P
- frametimeavg2 = frametimeavg1;
- frametimeavg1 = frametimeavg;
-
- float weight;
- weight = cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_new_weight");
- if(currentframetime > 0.0001) // filter out insane values which sometimes seem to occur and throw off the average? If you are getting 10,000 fps or more, then you don't need a framerate counter.
- {
- if(fabs(prevfps - (1/frametimeavg)) > prevfps * cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_instantupdate_change_threshold")) // if there was a big jump in fps, just force prevfps at current (1/currentframetime) to make big updates instant
- prevfps = (1/currentframetime);
- prevfps = (1 - weight) * prevfps + weight * (1/frametimeavg); // framecounter just used so there's no need for a new variable, think of it as "frametime average"
- }
- prevfps_time = currentTime;
- }
- else
- {
- framecounter += 1;
- if(currentTime - prevfps_time > autocvar_hud_panel_engineinfo_framecounter_time)
- {
- prevfps = framecounter/(currentTime - prevfps_time);
- framecounter = 0;
- prevfps_time = currentTime;
- }
- }
-
- vector color;
- color = HUD_Get_Num_Color (prevfps, 100);
- drawstring_aspect(pos, sprintf(_("FPS: %.*f"), autocvar_hud_panel_engineinfo_framecounter_decimals, prevfps), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
-// Info messages panel (#14)
-//
-#define drawInfoMessage(s) do { \
- if(autocvar_hud_panel_infomessages_flip) \
- o.x = pos.x + mySize.x - stringwidth(s, true, fontsize); \
- drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL); \
- o.y += fontsize.y; \
-} while(0)
-void HUD_InfoMessages(void)
-{
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_infomessages) return;
- }
-
- HUD_Panel_UpdateCvars();
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
- HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
- {
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
- }
-
- // always force 5:1 aspect
- vector newSize = '0 0 0';
- if(mySize.x/mySize.y > 5)
- {
- newSize.x = 5 * mySize.y;
- newSize.y = mySize.y;
-
- pos.x = pos.x + (mySize.x - newSize.x) / 2;
- }
- else
- {
- newSize.y = 1/5 * mySize.x;
- newSize.x = mySize.x;
-
- pos.y = pos.y + (mySize.y - newSize.y) / 2;
- }
-
- mySize = newSize;
- entity tm;
- vector o;
- o = pos;
-
- vector fontsize;
- fontsize = '0.20 0.20 0' * mySize.y;
-
- float a;
- a = panel_fg_alpha;
-
- string s;
- if(!autocvar__hud_configure)
- {
- if(spectatee_status && !intermission)
- {
- a = 1;
- if(spectatee_status == -1)
- s = _("^1Observing");
- else
- s = sprintf(_("^1Spectating: ^7%s"), GetPlayerName(current_player));
- drawInfoMessage(s);
-
- if(spectatee_status == -1)
- s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey("primary fire", "+fire"));
- else
- s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
- drawInfoMessage(s);
-
- if(spectatee_status == -1)
- s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
- else
- s = sprintf(_("^1Press ^3%s^1 to observe"), getcommandkey("secondary fire", "+fire2"));
- drawInfoMessage(s);
-
- s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey("server info", "+show_info"));
- drawInfoMessage(s);
-
- if(gametype == MAPINFO_TYPE_LMS)
- {
- entity sk;
- sk = playerslots[player_localnum];
- if(sk.(scores[ps_primary]) >= 666)
- s = _("^1Match has already begun");
- else if(sk.(scores[ps_primary]) > 0)
- s = _("^1You have no more lives left");
- else
- s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
- }
- else
- s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
- drawInfoMessage(s);
-
- //show restart countdown:
- if (time < getstatf(STAT_GAMESTARTTIME)) {
- float countdown;
- //we need to ceil, otherwise the countdown would be off by .5 when using round()
- countdown = ceil(getstatf(STAT_GAMESTARTTIME) - time);
- s = sprintf(_("^1Game starts in ^3%d^1 seconds"), countdown);
- drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL);
- o.y += fontsize.y;
- }
- }
- if(warmup_stage && !intermission)
- {
- s = _("^2Currently in ^1warmup^2 stage!");
- drawInfoMessage(s);
- }
-
- string blinkcolor;
- if(time % 1 >= 0.5)
- blinkcolor = "^1";
- else
- blinkcolor = "^3";
-
- if(ready_waiting && !intermission && !spectatee_status)
- {
- if(ready_waiting_for_me)
- {
- if(warmup_stage)
- s = sprintf(_("%sPress ^3%s%s to end warmup"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
- else
- s = sprintf(_("%sPress ^3%s%s once you are ready"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
- }
- else
- {
- if(warmup_stage)
- s = _("^2Waiting for others to ready up to end warmup...");
- else
- s = _("^2Waiting for others to ready up...");
- }
- drawInfoMessage(s);
- }
- else if(warmup_stage && !intermission && !spectatee_status)
- {
- s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey("ready", "ready"));
- drawInfoMessage(s);
- }
-
- if(teamplay && !intermission && !spectatee_status && gametype != MAPINFO_TYPE_CA && teamnagger)
- {
- float ts_min = 0, ts_max = 0;
- tm = teams.sort_next;
- if (tm)
- {
- for (; tm.sort_next; tm = tm.sort_next)
- {
- if(!tm.team_size || tm.team == NUM_SPECTATOR)
- continue;
- if(!ts_min) ts_min = tm.team_size;
- else ts_min = min(ts_min, tm.team_size);
- if(!ts_max) ts_max = tm.team_size;
- else ts_max = max(ts_max, tm.team_size);
- }
- if ((ts_max - ts_min) > 1)
- {
- s = strcat(blinkcolor, _("Teamnumbers are unbalanced!"));
- tm = GetTeam(myteam, false);
- if (tm)
- if (tm.team != NUM_SPECTATOR)
- if (tm.team_size == ts_max)
- s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey("team menu", "menu_showteamselect"), blinkcolor));
- drawInfoMessage(s);
- }
- }
- }
- }
- else
- {
- s = _("^7Press ^3ESC ^7to show HUD options.");
- drawInfoMessage(s);
- s = _("^3Doubleclick ^7a panel for panel-specific options.");
- drawInfoMessage(s);
- s = _("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and");
- drawInfoMessage(s);
- s = _("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments.");
- drawInfoMessage(s);
- }
-}
-
-// Physics panel (#15)
-//
-vector acc_prevspeed;
-float acc_prevtime, acc_avg, top_speed, top_speed_time;
-float physics_update_time, discrete_speed, discrete_acceleration;
-void HUD_Physics(void)
-{
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_physics) return;
- if(spectatee_status == -1 && (autocvar_hud_panel_physics == 1 || autocvar_hud_panel_physics == 3)) return;
- if(autocvar_hud_panel_physics == 3 && !(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
- }
-
- HUD_Panel_UpdateCvars();
-
- draw_beginBoldFont();
-
- HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
- {
- panel_pos += '1 1 0' * panel_bg_padding;
- panel_size -= '2 2 0' * panel_bg_padding;
- }
-
- float acceleration_progressbar_scale = 0;
- if(autocvar_hud_panel_physics_progressbar && autocvar_hud_panel_physics_acceleration_progressbar_scale > 1)
- acceleration_progressbar_scale = autocvar_hud_panel_physics_acceleration_progressbar_scale;
-
- float text_scale;
- if (autocvar_hud_panel_physics_text_scale <= 0)
- text_scale = 1;
- else
- text_scale = min(autocvar_hud_panel_physics_text_scale, 1);
-
- //compute speed
- float speed, conversion_factor;
- string unit;
-
- switch(autocvar_hud_panel_physics_speed_unit)
- {
- default:
- case 1:
- unit = _(" qu/s");
- conversion_factor = 1.0;
- break;
- case 2:
- unit = _(" m/s");
- conversion_factor = 0.0254;
- break;
- case 3:
- unit = _(" km/h");
- conversion_factor = 0.0254 * 3.6;
- break;
- case 4:
- unit = _(" mph");
- conversion_factor = 0.0254 * 3.6 * 0.6213711922;
- break;
- case 5:
- unit = _(" knots");
- conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
- break;
- }
-
- vector vel = (csqcplayer ? csqcplayer.velocity : pmove_vel);
-
- float max_speed = floor( autocvar_hud_panel_physics_speed_max * conversion_factor + 0.5 );
- if (autocvar__hud_configure)
- speed = floor( max_speed * 0.65 + 0.5 );
- else if(autocvar_hud_panel_physics_speed_vertical)
- speed = floor( vlen(vel) * conversion_factor + 0.5 );
- else
- speed = floor( vlen(vel - vel.z * '0 0 1') * conversion_factor + 0.5 );
-
- //compute acceleration
- float acceleration, f;
- if (autocvar__hud_configure)
- acceleration = autocvar_hud_panel_physics_acceleration_max * 0.3;
- else
- {
- // 1 m/s = 0.0254 qu/s; 1 g = 9.80665 m/s^2
- f = time - acc_prevtime;
- if(autocvar_hud_panel_physics_acceleration_vertical)
- acceleration = (vlen(vel) - vlen(acc_prevspeed));
- else
- acceleration = (vlen(vel - '0 0 1' * vel.z) - vlen(acc_prevspeed - '0 0 1' * acc_prevspeed.z));
-
- acceleration = acceleration * (1 / max(0.0001, f)) * (0.0254 / 9.80665);
-
- acc_prevspeed = vel;
- acc_prevtime = time;
-
- if(autocvar_hud_panel_physics_acceleration_movingaverage)
- {
- f = bound(0, f * 10, 1);
- acc_avg = acc_avg * (1 - f) + acceleration * f;
- acceleration = acc_avg;
- }
- }
-
- int acc_decimals = 2;
- if(time > physics_update_time)
- {
- // workaround for ftos_decimals returning a negative 0
- if(discrete_acceleration > -1 / pow(10, acc_decimals) && discrete_acceleration < 0)
- discrete_acceleration = 0;
- discrete_acceleration = acceleration;
- discrete_speed = speed;
- physics_update_time += autocvar_hud_panel_physics_update_interval;
- }
-
- //compute layout
- float panel_ar = panel_size.x/panel_size.y;
- vector speed_offset = '0 0 0', acceleration_offset = '0 0 0';
- if (panel_ar >= 5 && !acceleration_progressbar_scale)
- {
- panel_size.x *= 0.5;
- if (autocvar_hud_panel_physics_flip)
- speed_offset.x = panel_size.x;
- else
- acceleration_offset.x = panel_size.x;
- }
- else
- {
- panel_size.y *= 0.5;
- if (autocvar_hud_panel_physics_flip)
- speed_offset.y = panel_size.y;
- else
- acceleration_offset.y = panel_size.y;
- }
- int speed_baralign, acceleration_baralign;
- if (autocvar_hud_panel_physics_baralign == 1)
- acceleration_baralign = speed_baralign = 1;
- else if(autocvar_hud_panel_physics_baralign == 4)
- acceleration_baralign = speed_baralign = 2;
- else if (autocvar_hud_panel_physics_flip)
- {
- acceleration_baralign = (autocvar_hud_panel_physics_baralign == 2);
- speed_baralign = (autocvar_hud_panel_physics_baralign == 3);
- }
- else
- {
- speed_baralign = (autocvar_hud_panel_physics_baralign == 2);
- acceleration_baralign = (autocvar_hud_panel_physics_baralign == 3);
- }
- if (autocvar_hud_panel_physics_acceleration_progressbar_mode == 0)
- acceleration_baralign = 3; //override hud_panel_physics_baralign value for acceleration
-
- //draw speed
- if(speed)
- if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
- HUD_Panel_DrawProgressBar(panel_pos + speed_offset, panel_size, "progressbar", speed/max_speed, 0, speed_baralign, autocvar_hud_progressbar_speed_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- vector tmp_offset = '0 0 0', tmp_size = '0 0 0';
- if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
- {
- tmp_size.x = panel_size.x * 0.75;
- tmp_size.y = panel_size.y * text_scale;
- if (speed_baralign)
- tmp_offset.x = panel_size.x - tmp_size.x;
- //else
- //tmp_offset_x = 0;
- tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
- drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(discrete_speed), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-
- //draw speed unit
- if (speed_baralign)
- tmp_offset.x = 0;
- else
- tmp_offset.x = tmp_size.x;
- if (autocvar_hud_panel_physics_speed_unit_show)
- {
- //tmp_offset_y = 0;
- tmp_size.x = panel_size.x * (1 - 0.75);
- tmp_size.y = panel_size.y * 0.4 * text_scale;
- tmp_offset.y = (panel_size.y * 0.4 - tmp_size.y) / 2;
- drawstring_aspect(panel_pos + speed_offset + tmp_offset, unit, tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- }
-
- //compute and draw top speed
- if (autocvar_hud_panel_physics_topspeed)
- if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
- {
- if (autocvar__hud_configure)
- {
- top_speed = floor( max_speed * 0.75 + 0.5 );
- f = 1;
- }
- else
- {
- if (speed >= top_speed)
- {
- top_speed = speed;
- top_speed_time = time;
- }
- if (top_speed != 0)
- {
- f = max(1, autocvar_hud_panel_physics_topspeed_time);
- // divide by f to make it start from 1
- f = cos( ((time - top_speed_time) / f) * PI/2 );
- }
- else //hide top speed 0, it would be stupid
- f = 0;
- }
- if (f > 0)
- {
- //top speed progressbar peak
- if(speed < top_speed)
- if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
- {
- float peak_offsetX;
- vector peak_size = '0 0 0';
- if (speed_baralign == 0)
- peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x;
- else if (speed_baralign == 1)
- peak_offsetX = (1 - min(top_speed, max_speed)/max_speed) * panel_size.x;
- else // if (speed_baralign == 2)
- peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x * 0.5;
- peak_size.x = floor(panel_size.x * 0.01 + 1.5);
- peak_size.y = panel_size.y;
- if (speed_baralign == 2) // draw two peaks, on both sides
- {
- drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x + peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x - peak_offsetX + peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- else
- drawfill(panel_pos + speed_offset + eX * (peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- }
-
- //top speed
- tmp_offset.y = panel_size.y * 0.4;
- tmp_size.x = panel_size.x * (1 - 0.75);
- tmp_size.y = (panel_size.y - tmp_offset.y) * text_scale;
- tmp_offset.y += (panel_size.y - tmp_offset.y - tmp_size.y) / 2;
- drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(top_speed), tmp_size, '1 0 0', f * panel_fg_alpha, DRAWFLAG_NORMAL);
- }
- else
- top_speed = 0;
- }
-
- //draw acceleration
- if(acceleration)
- if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 3)
- {
- vector progressbar_color;
- if(acceleration < 0)
- progressbar_color = autocvar_hud_progressbar_acceleration_neg_color;
- else
- progressbar_color = autocvar_hud_progressbar_acceleration_color;
-
- f = acceleration/autocvar_hud_panel_physics_acceleration_max;
- if (autocvar_hud_panel_physics_acceleration_progressbar_nonlinear)
- f = (f >= 0 ? sqrt(f) : -sqrt(-f));
-
- if (acceleration_progressbar_scale) // allow progressbar to go out of panel bounds
- {
- tmp_size = acceleration_progressbar_scale * panel_size.x * eX + panel_size.y * eY;
-
- if (acceleration_baralign == 1)
- tmp_offset.x = panel_size.x - tmp_size.x;
- else if (acceleration_baralign == 2 || acceleration_baralign == 3)
- tmp_offset.x = (panel_size.x - tmp_size.x) / 2;
- else
- tmp_offset.x = 0;
- tmp_offset.y = 0;
- }
- else
- {
- tmp_size = panel_size;
- tmp_offset = '0 0 0';
- }
-
- HUD_Panel_DrawProgressBar(panel_pos + acceleration_offset + tmp_offset, tmp_size, "accelbar", f, 0, acceleration_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- }
-
- if(autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 3)
- {
- tmp_size.x = panel_size.x;
- tmp_size.y = panel_size.y * text_scale;
- tmp_offset.x = 0;
- tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
-
- drawstring_aspect(panel_pos + acceleration_offset + tmp_offset, strcat(ftos_decimals(discrete_acceleration, acc_decimals), "g"), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- }
-
- draw_endBoldFont();
-}
-
-// CenterPrint (#16)
-//
-const int CENTERPRINT_MAX_MSGS = 10;
-const int CENTERPRINT_MAX_ENTRIES = 50;
-const float CENTERPRINT_SPACING = 0.7;
-int cpm_index;
-string centerprint_messages[CENTERPRINT_MAX_MSGS];
-int centerprint_msgID[CENTERPRINT_MAX_MSGS];
-float centerprint_time[CENTERPRINT_MAX_MSGS];
-float centerprint_expire_time[CENTERPRINT_MAX_MSGS];
-int centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
-bool centerprint_showing;
-
-void centerprint_generic(int new_id, string strMessage, float duration, int countdown_num)
-{
- //printf("centerprint_generic(%d, '%s^7', %d, %d);\n", new_id, strMessage, duration, countdown_num);
- int i, j;
-
- if(strMessage == "" && new_id == 0)
- return;
-
- // strip trailing newlines
- j = strlen(strMessage) - 1;
- while(substring(strMessage, j, 1) == "\n" && j >= 0)
- --j;
- if (j < strlen(strMessage) - 1)
- strMessage = substring(strMessage, 0, j + 1);
-
- if(strMessage == "" && new_id == 0)
- return;
-
- // strip leading newlines
- j = 0;
- while(substring(strMessage, j, 1) == "\n" && j < strlen(strMessage))
- ++j;
- if (j > 0)
- strMessage = substring(strMessage, j, strlen(strMessage) - j);
-
- if(strMessage == "" && new_id == 0)
- return;
-
- if (!centerprint_showing)
- centerprint_showing = true;
-
- for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
- {
- if (j == CENTERPRINT_MAX_MSGS)
- j = 0;
- if (new_id && new_id == centerprint_msgID[j])
- {
- if (strMessage == "" && centerprint_messages[j] != "" && centerprint_countdown_num[j] == 0)
- {
- // fade out the current msg (duration and countdown_num are ignored)
- centerprint_time[j] = min(5, autocvar_hud_panel_centerprint_fade_out);
- if (centerprint_expire_time[j] > time + min(5, autocvar_hud_panel_centerprint_fade_out) || centerprint_expire_time[j] < time)
- centerprint_expire_time[j] = time + min(5, autocvar_hud_panel_centerprint_fade_out);
- return;
- }
- break; // found a msg with the same id, at position j
- }
- }
-
- if (i == CENTERPRINT_MAX_MSGS)
- {
- // a msg with the same id was not found, add the msg at the next position
- --cpm_index;
- if (cpm_index == -1)
- cpm_index = CENTERPRINT_MAX_MSGS - 1;
- j = cpm_index;
- }
- if(centerprint_messages[j])
- strunzone(centerprint_messages[j]);
- centerprint_messages[j] = strzone(strMessage);
- centerprint_msgID[j] = new_id;
- if (duration < 0)
- {
- centerprint_time[j] = -1;
- centerprint_expire_time[j] = time;
- }
- else
- {
- if(duration == 0)
- duration = max(1, autocvar_hud_panel_centerprint_time);
- centerprint_time[j] = duration;
- centerprint_expire_time[j] = time + duration;
- }
- centerprint_countdown_num[j] = countdown_num;
-}
-
-void centerprint_hud(string strMessage)
-{
- centerprint_generic(0, strMessage, autocvar_hud_panel_centerprint_time, 0);
-}
-
-void reset_centerprint_messages(void)
-{
- int i;
- for (i=0; i<CENTERPRINT_MAX_MSGS; ++i)
- {
- centerprint_expire_time[i] = 0;
- centerprint_time[i] = 1;
- centerprint_msgID[i] = 0;
- if(centerprint_messages[i])
- strunzone(centerprint_messages[i]);
- centerprint_messages[i] = string_null;
- }
-}
-float hud_configure_cp_generation_time;
-void HUD_CenterPrint (void)
-{
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_centerprint) return;
-
- if(hud_configure_prev)
- reset_centerprint_messages();
- }
- else
- {
- if(!hud_configure_prev)
- reset_centerprint_messages();
- if (time > hud_configure_cp_generation_time)
- {
- if(highlightedPanel == HUD_PANEL(CENTERPRINT))
- {
- float r;
- r = random();
- if (r > 0.8)
- centerprint_generic(floor(r*1000), strcat(sprintf("^3Countdown message at time %s", seconds_tostring(time)), ", seconds left: ^COUNT"), 1, 10);
- else if (r > 0.55)
- centerprint_generic(0, sprintf("^1Multiline message at time %s that\n^1lasts longer than normal", seconds_tostring(time)), 20, 0);
- else
- centerprint_hud(sprintf("Message at time %s", seconds_tostring(time)));
- hud_configure_cp_generation_time = time + 1 + random()*4;
- }
- else
- {
- centerprint_generic(0, sprintf("Centerprint message", seconds_tostring(time)), 10, 0);
- hud_configure_cp_generation_time = time + 10 - random()*3;
- }
- }
- }
-
- // this panel fades only when the menu does
- float hud_fade_alpha_save = 0;
- if(scoreboard_fade_alpha)
- {
- hud_fade_alpha_save = hud_fade_alpha;
- hud_fade_alpha = 1 - autocvar__menu_alpha;
- }
- HUD_Panel_UpdateCvars();
-
- if ( HUD_Radar_Clickable() )
- {
- if (hud_panel_radar_bottom >= 0.96 * vid_conheight)
- return;
-
- panel_pos = eY * hud_panel_radar_bottom + eX * 0.5 * (vid_conwidth - panel_size_x);
- panel_size_y = min(panel_size_y, vid_conheight - hud_panel_radar_bottom);
- }
- else if(scoreboard_fade_alpha)
- {
- hud_fade_alpha = hud_fade_alpha_save;
-
- // move the panel below the scoreboard
- if (scoreboard_bottom >= 0.96 * vid_conheight)
- return;
- vector target_pos;
-
- target_pos = eY * scoreboard_bottom + eX * 0.5 * (vid_conwidth - panel_size.x);
-
- if(target_pos.y > panel_pos.y)
- {
- panel_pos = panel_pos + (target_pos - panel_pos) * sqrt(scoreboard_fade_alpha);
- panel_size.y = min(panel_size.y, vid_conheight - scoreboard_bottom);
- }
- }
-
- HUD_Panel_DrawBg(1);
-
- if (!centerprint_showing)
- return;
-
- if(panel_bg_padding)
- {
- panel_pos += '1 1 0' * panel_bg_padding;
- panel_size -= '2 2 0' * panel_bg_padding;
- }
-
- int entries;
- float height;
- vector fontsize;
- // entries = bound(1, floor(CENTERPRINT_MAX_ENTRIES * 4 * panel_size_y/panel_size_x), CENTERPRINT_MAX_ENTRIES);
- // height = panel_size_y/entries;
- // fontsize = '1 1 0' * height;
- height = vid_conheight/50 * autocvar_hud_panel_centerprint_fontscale;
- fontsize = '1 1 0' * height;
- entries = bound(1, floor(panel_size.y/height), CENTERPRINT_MAX_ENTRIES);
-
- int i, j, k, n, g;
- float a, sz, align, current_msg_posY = 0, msg_size;
- vector pos;
- string ts;
- bool all_messages_expired = true;
-
- pos = panel_pos;
- if (autocvar_hud_panel_centerprint_flip)
- pos.y += panel_size.y;
- align = bound(0, autocvar_hud_panel_centerprint_align, 1);
- for (g=0, i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
- {
- if (j == CENTERPRINT_MAX_MSGS)
- j = 0;
- if (centerprint_expire_time[j] <= time)
- {
- if (centerprint_countdown_num[j] && centerprint_time[j] > 0)
- {
- centerprint_countdown_num[j] = centerprint_countdown_num[j] - 1;
- if (centerprint_countdown_num[j] == 0)
- continue;
- centerprint_expire_time[j] = centerprint_expire_time[j] + centerprint_time[j];
- }
- else if(centerprint_time[j] != -1)
- continue;
- }
-
- all_messages_expired = false;
-
- // fade the centerprint_hud in/out
- if(centerprint_time[j] < 0) // Expired but forced. Expire time is the fade-in time.
- a = (time - centerprint_expire_time[j]) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
- else if(centerprint_expire_time[j] - autocvar_hud_panel_centerprint_fade_out > time) // Regularily printed. Not fading out yet.
- a = (time - (centerprint_expire_time[j] - centerprint_time[j])) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
- else // Expiring soon, so fade it out.
- a = (centerprint_expire_time[j] - time) / max(0.0001, autocvar_hud_panel_centerprint_fade_out);
-
- // while counting down show it anyway in order to hold the current message position
- if (a <= 0.5/255.0 && centerprint_countdown_num[j] == 0) // Guaranteed invisible - don't show.
- continue;
- if (a > 1)
- a = 1;
-
- // set the size from fading in/out before subsequent fading
- sz = autocvar_hud_panel_centerprint_fade_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_minfontsize);
-
- // also fade it based on positioning
- if(autocvar_hud_panel_centerprint_fade_subsequent)
- {
- a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1); // pass one: all messages after the first have half theAlpha
- a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1); // pass two: after that, gradually lower theAlpha even more for each message
- }
- a *= panel_fg_alpha;
-
- // finally set the size based on the new theAlpha from subsequent fading
- sz = sz * (autocvar_hud_panel_centerprint_fade_subsequent_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_subsequent_minfontsize));
- drawfontscale = sz * '1 1 0';
-
- if (centerprint_countdown_num[j])
- n = tokenizebyseparator(strreplace("^COUNT", count_seconds(centerprint_countdown_num[j]), centerprint_messages[j]), "\n");
- else
- n = tokenizebyseparator(centerprint_messages[j], "\n");
-
- if (autocvar_hud_panel_centerprint_flip)
- {
- // check if the message can be entirely shown
- for(k = 0; k < n; ++k)
- {
- getWrappedLine_remaining = argv(k);
- while(getWrappedLine_remaining)
- {
- ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
- if (ts != "")
- pos.y -= fontsize.y;
- else
- pos.y -= fontsize.y * CENTERPRINT_SPACING/2;
- }
- }
- current_msg_posY = pos.y; // save starting pos (first line) of the current message
- }
-
- msg_size = pos.y;
- for(k = 0; k < n; ++k)
- {
- getWrappedLine_remaining = argv(k);
- while(getWrappedLine_remaining)
- {
- ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
- if (ts != "")
- {
- if (align)
- pos.x = panel_pos.x + (panel_size.x - stringwidth(ts, true, fontsize)) * align;
- if (a > 0.5/255.0) // Otherwise guaranteed invisible - don't show. This is checked a second time after some multiplications with other factors were done so temporary changes of these cannot cause flicker.
- drawcolorcodedstring(pos + eY * 0.5 * (1 - sz) * fontsize.y, ts, fontsize, a, DRAWFLAG_NORMAL);
- pos.y += fontsize.y;
- }
- else
- pos.y += fontsize.y * CENTERPRINT_SPACING/2;
- }
- }
-
- ++g; // move next position number up
-
- msg_size = pos.y - msg_size;
- if (autocvar_hud_panel_centerprint_flip)
- {
- pos.y = current_msg_posY - CENTERPRINT_SPACING * fontsize.y;
- if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
- pos.y += (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
-
- if (pos.y < panel_pos.y) // check if the next message can be shown
- {
- drawfontscale = '1 1 0';
- return;
- }
- }
- else
- {
- pos.y += CENTERPRINT_SPACING * fontsize.y;
- if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
- pos.y -= (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
-
- if(pos.y > panel_pos.y + panel_size.y - fontsize.y) // check if the next message can be shown
- {
- drawfontscale = '1 1 0';
- return;
- }
- }
- }
- drawfontscale = '1 1 0';
- if (all_messages_expired)
- {
- centerprint_showing = false;
- reset_centerprint_messages();
- }
-}
-
-
-// Minigame
-//
-#include "../common/minigames/cl_minigames_hud.qc"
-
-
-// QuickMenu (#23)
-//
-#include "quickmenu.qc"
-
-
-/*
-==================
-Main HUD system
-==================
-*/
-
-void HUD_Vehicle()
-{
- if(autocvar__hud_configure) return;
- if(intermission == 2) return;
-
- if(hud == HUD_BUMBLEBEE_GUN)
- CSQC_BUMBLE_GUN_HUD();
- else {
- Vehicle info = get_vehicleinfo(hud);
- info.vr_hud(info);
- }
-}
-
-bool HUD_Panel_CheckFlags(int showflags)
-{
- if ( HUD_Minigame_Showpanels() )
- return showflags & PANEL_SHOW_MINIGAME;
- if(intermission == 2)
- return showflags & PANEL_SHOW_MAPVOTE;
- return showflags & PANEL_SHOW_MAINGAME;
-}
-
-void HUD_Panel_Draw(entity panent)
-{
- panel = panent;
- if(autocvar__hud_configure)
- {
- if(panel.panel_configflags & PANEL_CONFIG_MAIN)
- panel.panel_draw();
- }
- else if(HUD_Panel_CheckFlags(panel.panel_showflags))
- panel.panel_draw();
-}
-
-void HUD_Reset(void)
-{
- // reset gametype specific icons
- if(gametype == MAPINFO_TYPE_CTF)
- HUD_Mod_CTF_Reset();
-}
-
-void HUD_Main(void)
-{
- int i;
- // global hud theAlpha fade
- if(menu_enabled == 1)
- hud_fade_alpha = 1;
- else
- hud_fade_alpha = (1 - autocvar__menu_alpha);
-
- if(scoreboard_fade_alpha)
- hud_fade_alpha = (1 - scoreboard_fade_alpha);
-
- HUD_Configure_Frame();
-
- // panels that we want to be active together with the scoreboard
- // they must fade only when the menu does
- if(scoreboard_fade_alpha == 1)
- {
- HUD_Panel_Draw(HUD_PANEL(CENTERPRINT));
- return;
- }
-
- if(!autocvar__hud_configure && !hud_fade_alpha)
- {
- hud_fade_alpha = 1;
- HUD_Panel_Draw(HUD_PANEL(VOTE));
- hud_fade_alpha = 0;
- return;
- }
-
- // Drawing stuff
- if (hud_skin_prev != autocvar_hud_skin)
- {
- if (hud_skin_path)
- strunzone(hud_skin_path);
- hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
- if (hud_skin_prev)
- strunzone(hud_skin_prev);
- hud_skin_prev = strzone(autocvar_hud_skin);
- }
-
- // draw the dock
- if(autocvar_hud_dock != "" && autocvar_hud_dock != "0")
- {
- int f;
- vector color;
- float hud_dock_color_team = autocvar_hud_dock_color_team;
- if((teamplay) && hud_dock_color_team) {
- if(autocvar__hud_configure && myteam == NUM_SPECTATOR)
- color = '1 0 0' * hud_dock_color_team;
- else
- color = myteamcolors * hud_dock_color_team;
- }
- else if(autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && hud_dock_color_team) {
- color = '1 0 0' * hud_dock_color_team;
- }
- else
- {
- string hud_dock_color = autocvar_hud_dock_color;
- if(hud_dock_color == "shirt") {
- f = stof(getplayerkeyvalue(current_player, "colors"));
- color = colormapPaletteColor(floor(f / 16), 0);
- }
- else if(hud_dock_color == "pants") {
- f = stof(getplayerkeyvalue(current_player, "colors"));
- color = colormapPaletteColor(f % 16, 1);
- }
- else
- color = stov(hud_dock_color);
- }
-
- string pic;
- pic = strcat(hud_skin_path, "/", autocvar_hud_dock);
- if(precache_pic(pic) == "") {
- pic = strcat(hud_skin_path, "/dock_medium");
- if(precache_pic(pic) == "") {
- pic = "gfx/hud/default/dock_medium";
- }
- }
- drawpic('0 0 0', pic, eX * vid_conwidth + eY * vid_conheight, color, autocvar_hud_dock_alpha * hud_fade_alpha, DRAWFLAG_NORMAL); // no aspect ratio forcing on dock...
- }
-
- // cache the panel order into the panel_order array
- if(autocvar__hud_panelorder != hud_panelorder_prev) {
- for(i = 0; i < hud_panels_COUNT; ++i)
- panel_order[i] = -1;
- string s = "";
- int p_num;
- bool warning = false;
- int argc = tokenize_console(autocvar__hud_panelorder);
- if (argc > hud_panels_COUNT)
- warning = true;
- //first detect wrong/missing panel numbers
- for(i = 0; i < hud_panels_COUNT; ++i) {
- p_num = stoi(argv(i));
- if (p_num >= 0 && p_num < hud_panels_COUNT) { //correct panel number?
- if (panel_order[p_num] == -1) //found for the first time?
- s = strcat(s, ftos(p_num), " ");
- panel_order[p_num] = 1; //mark as found
- }
- else
- warning = true;
- }
- for(i = 0; i < hud_panels_COUNT; ++i) {
- if (panel_order[i] == -1) {
- warning = true;
- s = strcat(s, ftos(i), " "); //add missing panel number
- }
- }
- if (warning)
- LOG_TRACE("Automatically fixed wrong/missing panel numbers in _hud_panelorder\n");
-
- cvar_set("_hud_panelorder", s);
- if(hud_panelorder_prev)
- strunzone(hud_panelorder_prev);
- hud_panelorder_prev = strzone(s);
-
- //now properly set panel_order
- tokenize_console(s);
- for(i = 0; i < hud_panels_COUNT; ++i) {
- panel_order[i] = stof(argv(i));
- }
- }
-
- hud_draw_maximized = 0;
- // draw panels in the order specified by panel_order array
- for(i = hud_panels_COUNT - 1; i >= 0; --i)
- HUD_Panel_Draw(hud_panels[panel_order[i]]);
-
- HUD_Vehicle();
-
- hud_draw_maximized = 1; // panels that may be maximized must check this var
- // draw maximized panels on top
- if(hud_panel_radar_maximized)
- HUD_Panel_Draw(HUD_PANEL(RADAR));
- if(autocvar__con_chat_maximized)
- HUD_Panel_Draw(HUD_PANEL(CHAT));
- if(hud_panel_quickmenu)
- HUD_Panel_Draw(HUD_PANEL(QUICKMENU));
-
- if (scoreboard_active || intermission == 2)
- HUD_Reset();
-
- HUD_Configure_PostDraw();
-
- hud_configure_prev = autocvar__hud_configure;
-}
+++ /dev/null
-#ifndef CLIENT_HUD_H
-#define CLIENT_HUD_H
-
-#include "../common/weapons/all.qh"
-
-bool HUD_Radar_Clickable();
-void HUD_Radar_Mouse();
-
-REGISTRY(hud_panels, 24)
-REGISTER_REGISTRY(Registerhud_panels)
-
-#define REGISTER_HUD_PANEL(id, draw_func, name, configflags, showflags) \
- void draw_func(); \
- REGISTER(Registerhud_panels, HUD_PANEL, hud_panels, id, m_id, new(hud_panel)) { \
- this.panel_id = this.m_id; \
- this.panel_draw = draw_func; \
- this.panel_name = #name; \
- this.panel_configflags = configflags; \
- this.panel_showflags = showflags; \
- }
-
-#define HUD_PANEL(NAME) HUD_PANEL_##NAME
-
-// draw the background/borders
-#define HUD_Panel_DrawBg(theAlpha) do { \
- if(panel.current_panel_bg != "0" && panel.current_panel_bg != "") \
- draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel.current_panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER));\
-} while(0)
-
-int panel_order[hud_panels_MAX];
-string hud_panelorder_prev;
-
-bool hud_draw_maximized;
-bool hud_panel_radar_maximized;
-bool hud_panel_radar_mouse;
-float hud_panel_radar_bottom;
-bool hud_panel_radar_temp_hidden;
-bool chat_panel_modified;
-bool radar_panel_modified;
-
-float HUD_Radar_InputEvent(float bInputType, float nPrimary, float nSecondary);
-void HUD_Radar_Hide_Maximized();
-
-void HUD_Reset (void);
-void HUD_Main (void);
-
-int vote_yescount;
-int vote_nocount;
-int vote_needed;
-int vote_highlighted; // currently selected vote
-
-int vote_active; // is there an active vote?
-int vote_prev; // previous state of vote_active to check for a change
-float vote_alpha;
-float vote_change; // "time" when vote_active changed
-
-float hud_panel_quickmenu;
-
-vector mousepos;
-vector panel_click_distance; // mouse cursor distance from the top left corner of the panel (saved only upon a click)
-vector panel_click_resizeorigin; // coordinates for opposite point when resizing
-float resizeCorner; // 1 = topleft, 2 = topright, 3 = bottomleft, 4 = bottomright
-entity highlightedPanel;
-float highlightedAction; // 0 = nothing, 1 = move, 2 = resize
-
-const float BORDER_MULTIPLIER = 0.25;
-float scoreboard_bottom;
-int weapon_accuracy[Weapons_MAX];
-
-int complain_weapon;
-string complain_weapon_name;
-float complain_weapon_type;
-float complain_weapon_time;
-
-int ps_primary, ps_secondary;
-int ts_primary, ts_secondary;
-
-int last_switchweapon;
-int last_activeweapon;
-float weapontime;
-float weaponprevtime;
-
-float teamnagger;
-
-float hud_configure_checkcollisions;
-float hud_configure_prev;
-vector hud_configure_gridSize;
-vector hud_configure_realGridSize;
-
-int hudShiftState;
-const int S_SHIFT = 1;
-const int S_CTRL = 2;
-const int S_ALT = 4;
-
-float menu_enabled; // 1 showing the entire HUD, 2 showing only the clicked panel
-
-float hud_fade_alpha;
-
-string hud_skin_path;
-string hud_skin_prev;
-
-vector myteamcolors;
-
-entity highlightedPanel_backup;
-vector panel_pos_backup;
-vector panel_size_backup;
-
-vector panel_size_copied;
-
-entity panel;
-entityclass(HUDPanel);
-class(HUDPanel) .string panel_name;
-class(HUDPanel) .int panel_id;
-class(HUDPanel) .vector current_panel_pos;
-class(HUDPanel) .vector current_panel_size;
-class(HUDPanel) .string current_panel_bg;
-class(HUDPanel) .float current_panel_bg_alpha;
-class(HUDPanel) .float current_panel_bg_border;
-class(HUDPanel) .vector current_panel_bg_color;
-class(HUDPanel) .float current_panel_bg_color_team;
-class(HUDPanel) .float current_panel_bg_padding;
-class(HUDPanel) .float current_panel_fg_alpha;
-class(HUDPanel) .float update_time;
-float panel_enabled;
-vector panel_pos;
-vector panel_size;
-string panel_bg_str; // "_str" vars contain the raw value of the cvar, non-"_str" contains what hud.qc code should use
-vector panel_bg_color;
-string panel_bg_color_str;
-float panel_bg_color_team;
-string panel_bg_color_team_str;
-float panel_fg_alpha;
-float panel_bg_alpha;
-string panel_bg_alpha_str;
-float panel_bg_border;
-string panel_bg_border_str;
-float panel_bg_padding;
-string panel_bg_padding_str;
-
-class(HUDPanel) .void() panel_draw;
-
-// chat panel can be reduced / moved while the mapvote is active
-// let know the mapvote panel about chat pos and size
-float chat_posy;
-float chat_sizey;
-
-float current_player;
-
-float stringwidth_colors(string s, vector theSize);
-float stringwidth_nocolors(string s, vector theSize);
-float GetPlayerColorForce(int i);
-int GetPlayerColor(int i);
-string GetPlayerName(int i);
-void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag);
-
-.int panel_showflags;
-const int PANEL_SHOW_NEVER = 0x00;
-const int PANEL_SHOW_MAINGAME = 0x01;
-const int PANEL_SHOW_MINIGAME = 0x02;
-const int PANEL_SHOW_MAPVOTE = 0x04;
-const int PANEL_SHOW_ALWAYS = 0xff;
-bool HUD_Panel_CheckFlags(int showflags);
-
-.int panel_configflags;
-const int PANEL_CONFIG_NO = 0x00;
-const int PANEL_CONFIG_MAIN = 0x01;
-
-
-// prev_* vars contain the health/armor at the previous FRAME
-// set to -1 when player is dead or was not playing
-int prev_health, prev_armor;
-float health_damagetime, armor_damagetime;
-int health_beforedamage, armor_beforedamage;
-// old_p_* vars keep track of previous values when smoothing value changes of the progressbar
-int old_p_health, old_p_armor;
-float old_p_healthtime, old_p_armortime;
-// prev_p_* vars contain the health/armor progressbar value at the previous FRAME
-// set to -1 to forcedly stop effects when we switch spectated player (e.g. from playerX: 70h to playerY: 50h)
-int prev_p_health, prev_p_armor;
-
-void HUD_ItemsTime();
-
-REGISTER_HUD_PANEL(WEAPONS, HUD_Weapons, weapons, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(AMMO, HUD_Ammo, ammo, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(POWERUPS, HUD_Powerups, powerups, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(HEALTHARMOR, HUD_HealthArmor, healtharmor, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(NOTIFY, HUD_Notify, notify, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
-REGISTER_HUD_PANEL(TIMER, HUD_Timer, timer, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
-REGISTER_HUD_PANEL(RADAR, HUD_Radar, radar, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(SCORE, HUD_Score, score, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
-REGISTER_HUD_PANEL(RACETIMER, HUD_RaceTimer, racetimer, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(VOTE, HUD_Vote, vote, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS )
-REGISTER_HUD_PANEL(MODICONS, HUD_ModIcons, modicons, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(PRESSEDKEYS, HUD_PressedKeys, pressedkeys, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(CHAT, HUD_Chat, chat, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS )
-REGISTER_HUD_PANEL(ENGINEINFO, HUD_EngineInfo, engineinfo, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS )
-REGISTER_HUD_PANEL(INFOMESSAGES, HUD_InfoMessages, infomessages, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(PHYSICS, HUD_Physics, physics, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(CENTERPRINT, HUD_CenterPrint, centerprint, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(MINIGAME_BOARD, HUD_MinigameBoard, minigameboard, PANEL_CONFIG_NO , PANEL_SHOW_MINIGAME)
-REGISTER_HUD_PANEL(MINIGAME_STATUS, HUD_MinigameStatus, minigamestatus, PANEL_CONFIG_NO , PANEL_SHOW_MINIGAME)
-REGISTER_HUD_PANEL(MINIGAME_HELP, HUD_MinigameHelp, minigamehelp, PANEL_CONFIG_NO , PANEL_SHOW_MINIGAME)
-REGISTER_HUD_PANEL(MINIGAME_MENU, HUD_MinigameMenu, minigamemenu, PANEL_CONFIG_NO , PANEL_SHOW_ALWAYS )
-REGISTER_HUD_PANEL(MAPVOTE, MapVote_Draw, mapvote, PANEL_CONFIG_NO , PANEL_SHOW_MAPVOTE )
-REGISTER_HUD_PANEL(ITEMSTIME, HUD_ItemsTime, itemstime, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(QUICKMENU, HUD_QuickMenu, quickmenu, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-// always add new panels to the end of list
-
-// Because calling lots of functions in QC apparently cuts fps in half on many machines:
-// ----------------------
-// MACRO HELL STARTS HERE
-// ----------------------
-// Little help for the poor people who have to make sense of this: Start from the bottom ;)
-
-// Get value for panel.current_panel_bg: if "" fetch default, else use panel_bg_str
-// comment on last line of macro: // we probably want to see a background in config mode at all times...
-#define HUD_Panel_GetBg() do { \
- string panel_bg; \
- if (!autocvar__hud_configure && panel_bg_str == "0") { \
- panel_bg = "0"; \
- } else { \
- if (panel_bg_str == "") { \
- panel_bg_str = autocvar_hud_panel_bg; \
- } \
- if (panel_bg_str == "0" && !autocvar__hud_configure) { \
- panel_bg = "0"; \
- } else { \
- if (panel_bg_str == "0" && autocvar__hud_configure) \
- panel_bg_alpha_str = "0"; \
- panel_bg = strcat(hud_skin_path, "/", panel_bg_str); \
- if (precache_pic(panel_bg) == "") { \
- panel_bg = strcat(hud_skin_path, "/", "border_default"); \
- if (precache_pic(panel_bg) == "") { \
- panel_bg = strcat("gfx/hud/default/", "border_default"); \
- } \
- } \
- } \
- } \
- if (panel.current_panel_bg) \
- strunzone(panel.current_panel_bg); \
- panel.current_panel_bg = strzone(panel_bg); \
-} while(0)
-
-// Get value for panel_bg_color: if "" fetch default, else use panel_bg_color. Convert pants, shirt or teamcolor into a vector.
-#define HUD_Panel_GetColor() do { \
- if ((teamplay) && panel_bg_color_team) { \
- if (autocvar__hud_configure && myteam == NUM_SPECTATOR) \
- panel_bg_color = '1 0 0' * panel_bg_color_team; \
- else \
- panel_bg_color = myteamcolors * panel_bg_color_team; \
- } else if (autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && panel_bg_color_team) { \
- panel_bg_color = '1 0 0' * panel_bg_color_team; \
- } else { \
- if (panel_bg_color_str == "") { \
- panel_bg_color = autocvar_hud_panel_bg_color; \
- } else { \
- if (panel_bg_color_str == "shirt") { \
- panel_bg_color = colormapPaletteColor(floor(stof(getplayerkeyvalue(current_player, "colors")) / 16), 0); \
- } else if (panel_bg_color_str == "pants") { \
- panel_bg_color = colormapPaletteColor(stof(getplayerkeyvalue(current_player, "colors")) % 16, 1); \
- } else { \
- panel_bg_color = stov(panel_bg_color_str); \
- } \
- } \
- } \
-} while(0)
-
-// Get value for panel_bg_color_team: if "" fetch default, else use panel_bg_color_team_str
-#define HUD_Panel_GetColorTeam() do { \
- if (panel_bg_color_team_str == "") { \
- panel_bg_color_team = autocvar_hud_panel_bg_color_team; \
- } else { \
- panel_bg_color_team = stof(panel_bg_color_team_str); \
- } \
-} while(0)
-
-// Get value for panel_bg_alpha: if "" fetch default, else use panel_bg_alpha. Also do various menu dialog fadeout/in checks, and minalpha checks
-// comment on line 3 of macro: // do not set a minalpha cap when showing the config dialog for this panel
-#define HUD_Panel_GetBgAlpha() do { \
- if (panel_bg_alpha_str == "") { \
- panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha); \
- } \
- panel_bg_alpha = stof(panel_bg_alpha_str); \
- if (autocvar__hud_configure) { \
- if (!panel_enabled) \
- panel_bg_alpha = 0.25; \
- else if (menu_enabled == 2 && panel == highlightedPanel) \
- panel_bg_alpha = (1 - autocvar__menu_alpha) * max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha) + autocvar__menu_alpha * panel_bg_alpha;\
- else \
- panel_bg_alpha = max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha); \
- } \
-} while(0)
-
-// Get value for panel_fg_alpha. Also do various minalpha checks
-// comment on line 2 of macro: // ALWAYS show disabled panels at 0.25 alpha when in config mode
-#define HUD_Panel_GetFgAlpha() do { \
- panel_fg_alpha = autocvar_hud_panel_fg_alpha; \
- if (autocvar__hud_configure && !panel_enabled) \
- panel_fg_alpha = 0.25; \
-} while(0)
-
-// Get border. See comments above, it's similar.
-#define HUD_Panel_GetBorder() do { \
- if (panel_bg_border_str == "") { \
- panel_bg_border = autocvar_hud_panel_bg_border; \
- } else { \
- panel_bg_border = stof(panel_bg_border_str); \
- } \
-} while(0)
-
-// Get padding. See comments above, it's similar.
-// last line is a port of the old function, basically always make sure the panel contents are at least 5 pixels tall/wide, to disallow extreme padding values
-#define HUD_Panel_GetPadding() do { \
- if (panel_bg_padding_str == "") { \
- panel_bg_padding = autocvar_hud_panel_bg_padding; \
- } else { \
- panel_bg_padding = stof(panel_bg_padding_str); \
- } \
- panel_bg_padding = min(min(panel_size.x, panel_size.y)/2 - 5, panel_bg_padding); \
-} while(0)
-
-// return smoothly faded pos and size of given panel when a dialog is active
-// don't center too wide panels, it doesn't work with different resolutions
-#define HUD_Panel_UpdatePosSize_ForMenu() do { \
- vector menu_enable_size = panel_size; \
- float max_panel_width = 0.52 * vid_conwidth; \
- if(panel_size.x > max_panel_width) \
- { \
- menu_enable_size.x = max_panel_width; \
- menu_enable_size.y = panel_size.y * (menu_enable_size.x / panel_size.x); \
- } \
- vector menu_enable_pos = eX * (panel_bg_border + 0.5 * max_panel_width) + eY * 0.5 * vid_conheight - 0.5 * menu_enable_size; \
- panel_pos = (1 - autocvar__menu_alpha) * panel_pos + (autocvar__menu_alpha) * menu_enable_pos; \
- panel_size = (1 - autocvar__menu_alpha) * panel_size + (autocvar__menu_alpha) * menu_enable_size; \
-} while(0)
-
-// Scale the pos and size vectors to absolute coordinates
-#define HUD_Panel_ScalePosSize() do { \
- panel_pos.x *= vid_conwidth; panel_pos.y *= vid_conheight; \
- panel_size.x *= vid_conwidth; panel_size.y *= vid_conheight; \
-} while(0)
-
-// NOTE: in hud_configure mode cvars must be reloaded every frame
-#define HUD_Panel_UpdateCvars() do { \
- if (panel.update_time <= time) { \
- if (autocvar__hud_configure) panel_enabled = cvar(strcat("hud_panel_", panel.panel_name)); \
- panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos"))); \
- panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size"))); \
- HUD_Panel_ScalePosSize(); \
- panel_bg_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg")); \
- panel_bg_color_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color")); \
- panel_bg_color_team_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color_team")); \
- panel_bg_alpha_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_alpha")); \
- panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border")); \
- panel_bg_padding_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_padding")); \
- HUD_Panel_GetBg(); \
- if (panel.current_panel_bg != "0") { \
- HUD_Panel_GetColorTeam(); \
- HUD_Panel_GetColor(); \
- HUD_Panel_GetBgAlpha(); \
- HUD_Panel_GetBorder(); \
- } \
- HUD_Panel_GetFgAlpha(); \
- HUD_Panel_GetPadding(); \
- panel.current_panel_bg_alpha = panel_bg_alpha; \
- panel.current_panel_fg_alpha = panel_fg_alpha; \
- if (menu_enabled == 2 && panel == highlightedPanel) { \
- HUD_Panel_UpdatePosSize_ForMenu(); \
- } else { \
- panel_bg_alpha *= hud_fade_alpha; \
- panel_fg_alpha *= hud_fade_alpha; \
- } \
- panel.current_panel_pos = panel_pos; \
- panel.current_panel_size = panel_size; \
- panel.current_panel_bg_border = panel_bg_border; \
- panel.current_panel_bg_color = panel_bg_color; \
- panel.current_panel_bg_color_team = panel_bg_color_team; \
- panel.current_panel_bg_padding = panel_bg_padding; \
- panel.update_time = (autocvar__hud_configure) ? time : time + autocvar_hud_panel_update_interval; \
- } else { \
- panel_pos = panel.current_panel_pos; \
- panel_size = panel.current_panel_size; \
- panel_bg_alpha = panel.current_panel_bg_alpha * hud_fade_alpha; \
- panel_bg_border = panel.current_panel_bg_border; \
- panel_bg_color = panel.current_panel_bg_color; \
- panel_bg_color_team = panel.current_panel_bg_color_team; \
- panel_bg_padding = panel.current_panel_bg_padding; \
- panel_fg_alpha = panel.current_panel_fg_alpha * hud_fade_alpha; \
- } \
-} while(0)
-
-#define HUD_Panel_UpdatePosSize() do { \
- panel_enabled = cvar(strcat("hud_panel_", panel.panel_name)); \
- panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos"))); \
- panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size"))); \
- HUD_Panel_ScalePosSize(); \
- if (menu_enabled == 2 && panel == highlightedPanel) { \
- HUD_Panel_UpdatePosSize_ForMenu(); \
- } \
- panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border")); \
- HUD_Panel_GetBorder(); \
-} while(0)
-
-const int NOTIFY_MAX_ENTRIES = 10;
-const float NOTIFY_ICON_MARGIN = 0.02;
-
-int notify_index;
-int notify_count;
-float notify_times[NOTIFY_MAX_ENTRIES];
-string notify_attackers[NOTIFY_MAX_ENTRIES];
-string notify_victims[NOTIFY_MAX_ENTRIES];
-string notify_icons[NOTIFY_MAX_ENTRIES];
-
-void HUD_Notify_Push(string icon, string attacker, string victim);
-
-var void HUD_ModIcons_GameType(vector pos, vector size);
-void HUD_ModIcons_SetFunc();
-#endif
--- /dev/null
+#include "panel/weapons.qc"
+#include "panel/ammo.qc"
+#include "panel/powerups.qc"
+#include "panel/healtharmor.qc"
+#include "panel/notify.qc"
+#include "panel/timer.qc"
+#include "panel/radar.qc"
+#include "panel/score.qc"
+#include "panel/racetimer.qc"
+#include "panel/vote.qc"
+#include "panel/modicons.qc"
+#include "panel/pressedkeys.qc"
+#include "panel/chat.qc"
+#include "panel/engineinfo.qc"
+#include "panel/infomessages.qc"
+#include "panel/physics.qc"
+#include "panel/centerprint.qc"
+#include "panel/minigame.qc"
+// #include "panel/mapvote.qc"
+// #include "panel/itemstime.qc"
+#include "panel/quickmenu.qc"
--- /dev/null
+#include "hud.qc"
+#include "hud_config.qc"
--- /dev/null
+#include "hud.qh"
+#include "hud_config.qh"
--- /dev/null
+#include "hud.qh"
+
+#include "hud_config.qh"
+#include "mapvoting.qh"
+#include "scoreboard.qh"
+#include "teamradar.qh"
+#include "t_items.qh"
+#include "../common/deathtypes/all.qh"
+#include "../common/items/all.qc"
+#include "../common/mapinfo.qh"
+#include "../common/mutators/mutator/waypoints/all.qh"
+#include "../common/stats.qh"
+#include "../lib/csqcmodel/cl_player.qh"
+// TODO: remove
+#include "../server/mutators/mutator/gamemode_ctf.qc"
+
+
+/*
+==================
+Misc HUD functions
+==================
+*/
+
+vector HUD_Get_Num_Color (float x, float maxvalue)
+{
+ float blinkingamt;
+ vector color;
+ if(x >= maxvalue) {
+ color.x = sin(2*M_PI*time);
+ color.y = 1;
+ color.z = sin(2*M_PI*time);
+ }
+ else if(x > maxvalue * 0.75) {
+ color.x = 0.4 - (x-150)*0.02 * 0.4; //red value between 0.4 -> 0
+ color.y = 0.9 + (x-150)*0.02 * 0.1; // green value between 0.9 -> 1
+ color.z = 0;
+ }
+ else if(x > maxvalue * 0.5) {
+ color.x = 1 - (x-100)*0.02 * 0.6; //red value between 1 -> 0.4
+ color.y = 1 - (x-100)*0.02 * 0.1; // green value between 1 -> 0.9
+ color.z = 1 - (x-100)*0.02; // blue value between 1 -> 0
+ }
+ else if(x > maxvalue * 0.25) {
+ color.x = 1;
+ color.y = 1;
+ color.z = 0.2 + (x-50)*0.02 * 0.8; // blue value between 0.2 -> 1
+ }
+ else if(x > maxvalue * 0.1) {
+ color.x = 1;
+ color.y = (x-20)*90/27/100; // green value between 0 -> 1
+ color.z = (x-20)*90/27/100 * 0.2; // blue value between 0 -> 0.2
+ }
+ else {
+ color.x = 1;
+ color.y = 0;
+ color.z = 0;
+ }
+
+ blinkingamt = (1 - x/maxvalue/0.25);
+ if(blinkingamt > 0)
+ {
+ color.x = color.x - color.x * blinkingamt * sin(2*M_PI*time);
+ color.y = color.y - color.y * blinkingamt * sin(2*M_PI*time);
+ color.z = color.z - color.z * blinkingamt * sin(2*M_PI*time);
+ }
+ return color;
+}
+
+float HUD_GetRowCount(int item_count, vector size, float item_aspect)
+{
+ float aspect = size_y / size_x;
+ return bound(1, floor((sqrt(4 * item_aspect * aspect * item_count + aspect * aspect) + aspect + 0.5) / 2), item_count);
+}
+
+vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect)
+{
+ float columns, rows;
+ float ratio, best_ratio = 0;
+ float best_columns = 1, best_rows = 1;
+ bool vertical = (psize.x / psize.y >= item_aspect);
+ if(vertical)
+ {
+ psize = eX * psize.y + eY * psize.x;
+ item_aspect = 1 / item_aspect;
+ }
+
+ rows = ceil(sqrt(item_count));
+ columns = ceil(item_count/rows);
+ while(columns >= 1)
+ {
+ ratio = (psize.x/columns) / (psize.y/rows);
+ if(ratio > item_aspect)
+ ratio = item_aspect * item_aspect / ratio;
+
+ if(ratio <= best_ratio)
+ break; // ratio starts decreasing by now, skip next configurations
+
+ best_columns = columns;
+ best_rows = rows;
+ best_ratio = ratio;
+
+ if(columns == 1)
+ break;
+
+ --columns;
+ rows = ceil(item_count/columns);
+ }
+
+ if(vertical)
+ return eX * best_rows + eY * best_columns;
+ else
+ return eX * best_columns + eY * best_rows;
+}
+
+// return the string of the onscreen race timer
+string MakeRaceString(int cp, float mytime, float theirtime, float lapdelta, string theirname)
+{
+ string col;
+ string timestr;
+ string cpname;
+ string lapstr;
+ lapstr = "";
+
+ if(theirtime == 0) // goal hit
+ {
+ if(mytime > 0)
+ {
+ timestr = strcat("+", ftos_decimals(+mytime, TIME_DECIMALS));
+ col = "^1";
+ }
+ else if(mytime == 0)
+ {
+ timestr = "+0.0";
+ col = "^3";
+ }
+ else
+ {
+ timestr = strcat("-", ftos_decimals(-mytime, TIME_DECIMALS));
+ col = "^2";
+ }
+
+ if(lapdelta > 0)
+ {
+ lapstr = sprintf(_(" (-%dL)"), lapdelta);
+ col = "^2";
+ }
+ else if(lapdelta < 0)
+ {
+ lapstr = sprintf(_(" (+%dL)"), -lapdelta);
+ col = "^1";
+ }
+ }
+ else if(theirtime > 0) // anticipation
+ {
+ if(mytime >= theirtime)
+ timestr = strcat("+", ftos_decimals(mytime - theirtime, TIME_DECIMALS));
+ else
+ timestr = TIME_ENCODED_TOSTRING(TIME_ENCODE(theirtime));
+ col = "^3";
+ }
+ else
+ {
+ col = "^7";
+ timestr = "";
+ }
+
+ if(cp == 254)
+ cpname = _("Start line");
+ else if(cp == 255)
+ cpname = _("Finish line");
+ else if(cp)
+ cpname = sprintf(_("Intermediate %d"), cp);
+ else
+ cpname = _("Finish line");
+
+ if(theirtime < 0)
+ return strcat(col, cpname);
+ else if(theirname == "")
+ return strcat(col, sprintf("%s (%s)", cpname, timestr));
+ else
+ return strcat(col, sprintf("%s (%s %s)", cpname, timestr, strcat(theirname, col, lapstr)));
+}
+
+// Check if the given name already exist in race rankings? In that case, where? (otherwise return 0)
+int race_CheckName(string net_name)
+{
+ int i;
+ for (i=RANKINGS_CNT-1;i>=0;--i)
+ if(grecordholder[i] == net_name)
+ return i+1;
+ return 0;
+}
+
+/*
+==================
+HUD panels
+==================
+*/
+
+//basically the same code of draw_ButtonPicture and draw_VertButtonPicture for the menu
+void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag)
+{
+ if(!length_ratio || !theAlpha)
+ return;
+ if(length_ratio > 1)
+ length_ratio = 1;
+ if (baralign == 3)
+ {
+ if(length_ratio < -1)
+ length_ratio = -1;
+ }
+ else if(length_ratio < 0)
+ return;
+
+ vector square;
+ vector width, height;
+ if(vertical) {
+ pic = strcat(hud_skin_path, "/", pic, "_vertical");
+ if(precache_pic(pic) == "") {
+ pic = "gfx/hud/default/progressbar_vertical";
+ }
+
+ if (baralign == 1) // bottom align
+ theOrigin.y += (1 - length_ratio) * theSize.y;
+ else if (baralign == 2) // center align
+ theOrigin.y += 0.5 * (1 - length_ratio) * theSize.y;
+ else if (baralign == 3) // center align, positive values down, negative up
+ {
+ theSize.y *= 0.5;
+ if (length_ratio > 0)
+ theOrigin.y += theSize.y;
+ else
+ {
+ theOrigin.y += (1 + length_ratio) * theSize.y;
+ length_ratio = -length_ratio;
+ }
+ }
+ theSize.y *= length_ratio;
+
+ vector bH;
+ width = eX * theSize.x;
+ height = eY * theSize.y;
+ if(theSize.y <= theSize.x * 2)
+ {
+ // button not high enough
+ // draw just upper and lower part then
+ square = eY * theSize.y * 0.5;
+ bH = eY * (0.25 * theSize.y / (theSize.x * 2));
+ drawsubpic(theOrigin, square + width, pic, '0 0 0', eX + bH, theColor, theAlpha, drawflag);
+ drawsubpic(theOrigin + square, square + width, pic, eY - bH, eX + bH, theColor, theAlpha, drawflag);
+ }
+ else
+ {
+ square = eY * theSize.x;
+ drawsubpic(theOrigin, width + square, pic, '0 0 0', '1 0.25 0', theColor, theAlpha, drawflag);
+ drawsubpic(theOrigin + square, theSize - 2 * square, pic, '0 0.25 0', '1 0.5 0', theColor, theAlpha, drawflag);
+ drawsubpic(theOrigin + height - square, width + square, pic, '0 0.75 0', '1 0.25 0', theColor, theAlpha, drawflag);
+ }
+ } else {
+ pic = strcat(hud_skin_path, "/", pic);
+ if(precache_pic(pic) == "") {
+ pic = "gfx/hud/default/progressbar";
+ }
+
+ if (baralign == 1) // right align
+ theOrigin.x += (1 - length_ratio) * theSize.x;
+ else if (baralign == 2) // center align
+ theOrigin.x += 0.5 * (1 - length_ratio) * theSize.x;
+ else if (baralign == 3) // center align, positive values on the right, negative on the left
+ {
+ theSize.x *= 0.5;
+ if (length_ratio > 0)
+ theOrigin.x += theSize.x;
+ else
+ {
+ theOrigin.x += (1 + length_ratio) * theSize.x;
+ length_ratio = -length_ratio;
+ }
+ }
+ theSize.x *= length_ratio;
+
+ vector bW;
+ width = eX * theSize.x;
+ height = eY * theSize.y;
+ if(theSize.x <= theSize.y * 2)
+ {
+ // button not wide enough
+ // draw just left and right part then
+ square = eX * theSize.x * 0.5;
+ bW = eX * (0.25 * theSize.x / (theSize.y * 2));
+ drawsubpic(theOrigin, square + height, pic, '0 0 0', eY + bW, theColor, theAlpha, drawflag);
+ drawsubpic(theOrigin + square, square + height, pic, eX - bW, eY + bW, theColor, theAlpha, drawflag);
+ }
+ else
+ {
+ square = eX * theSize.y;
+ drawsubpic(theOrigin, height + square, pic, '0 0 0', '0.25 1 0', theColor, theAlpha, drawflag);
+ drawsubpic(theOrigin + square, theSize - 2 * square, pic, '0.25 0 0', '0.5 1 0', theColor, theAlpha, drawflag);
+ drawsubpic(theOrigin + width - square, height + square, pic, '0.75 0 0', '0.25 1 0', theColor, theAlpha, drawflag);
+ }
+ }
+}
+
+void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theAlpha, int drawflag)
+{
+ if(!theAlpha)
+ return;
+
+ string pic;
+ pic = strcat(hud_skin_path, "/num_leading");
+ if(precache_pic(pic) == "") {
+ pic = "gfx/hud/default/num_leading";
+ }
+
+ drawsubpic(pos, eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0 0 0', '0.25 1 0', color, theAlpha, drawflag);
+ if(mySize.x/mySize.y > 2)
+ drawsubpic(pos + eX * mySize.y, eX * (mySize.x - 2 * mySize.y) + eY * mySize.y, pic, '0.25 0 0', '0.5 1 0', color, theAlpha, drawflag);
+ drawsubpic(pos + eX * mySize.x - eX * min(mySize.x * 0.5, mySize.y), eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0.75 0 0', '0.25 1 0', color, theAlpha, drawflag);
+}
+
+void DrawNumIcon_expanding(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha, float fadelerp)
+{
+ vector newPos = '0 0 0', newSize = '0 0 0';
+ vector picpos, numpos;
+
+ if (vertical)
+ {
+ if(mySize.y/mySize.x > 2)
+ {
+ newSize.y = 2 * mySize.x;
+ newSize.x = mySize.x;
+
+ newPos.y = myPos.y + (mySize.y - newSize.y) / 2;
+ newPos.x = myPos.x;
+ }
+ else
+ {
+ newSize.x = 1/2 * mySize.y;
+ newSize.y = mySize.y;
+
+ newPos.x = myPos.x + (mySize.x - newSize.x) / 2;
+ newPos.y = myPos.y;
+ }
+
+ if(icon_right_align)
+ {
+ numpos = newPos;
+ picpos = newPos + eY * newSize.x;
+ }
+ else
+ {
+ picpos = newPos;
+ numpos = newPos + eY * newSize.x;
+ }
+
+ newSize.y /= 2;
+ drawpic_aspect_skin(picpos, icon, newSize, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+ // make number smaller than icon, it looks better
+ // reduce only y to draw numbers with different number of digits with the same y size
+ numpos.y += newSize.y * ((1 - 0.7) / 2);
+ newSize.y *= 0.7;
+ drawstring_aspect(numpos, ftos(x), newSize, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+ return;
+ }
+
+ if(mySize.x/mySize.y > 3)
+ {
+ newSize.x = 3 * mySize.y;
+ newSize.y = mySize.y;
+
+ newPos.x = myPos.x + (mySize.x - newSize.x) / 2;
+ newPos.y = myPos.y;
+ }
+ else
+ {
+ newSize.y = 1/3 * mySize.x;
+ newSize.x = mySize.x;
+
+ newPos.y = myPos.y + (mySize.y - newSize.y) / 2;
+ newPos.x = myPos.x;
+ }
+
+ if(icon_right_align) // right align
+ {
+ numpos = newPos;
+ picpos = newPos + eX * 2 * newSize.y;
+ }
+ else // left align
+ {
+ numpos = newPos + eX * newSize.y;
+ picpos = newPos;
+ }
+
+ // NOTE: newSize_x is always equal to 3 * mySize_y so we can use
+ // '2 1 0' * newSize_y instead of eX * (2/3) * newSize_x + eY * newSize_y
+ drawstring_aspect_expanding(numpos, ftos(x), '2 1 0' * newSize.y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
+ drawpic_aspect_skin_expanding(picpos, icon, '1 1 0' * newSize.y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
+}
+
+void DrawNumIcon(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha)
+{
+ DrawNumIcon_expanding(myPos, mySize, x, icon, vertical, icon_right_align, color, theAlpha, 0);
+}
+
+#include "all.inc"
+
+/*
+==================
+Main HUD system
+==================
+*/
+
+void HUD_Vehicle()
+{
+ if(autocvar__hud_configure) return;
+ if(intermission == 2) return;
+
+ if(hud == HUD_BUMBLEBEE_GUN)
+ CSQC_BUMBLE_GUN_HUD();
+ else {
+ Vehicle info = get_vehicleinfo(hud);
+ info.vr_hud(info);
+ }
+}
+
+bool HUD_Panel_CheckFlags(int showflags)
+{
+ if ( HUD_Minigame_Showpanels() )
+ return showflags & PANEL_SHOW_MINIGAME;
+ if(intermission == 2)
+ return showflags & PANEL_SHOW_MAPVOTE;
+ return showflags & PANEL_SHOW_MAINGAME;
+}
+
+void HUD_Panel_Draw(entity panent)
+{
+ panel = panent;
+ if(autocvar__hud_configure)
+ {
+ if(panel.panel_configflags & PANEL_CONFIG_MAIN)
+ panel.panel_draw();
+ }
+ else if(HUD_Panel_CheckFlags(panel.panel_showflags))
+ panel.panel_draw();
+}
+
+void HUD_Reset()
+{
+ // reset gametype specific icons
+ if(gametype == MAPINFO_TYPE_CTF)
+ HUD_Mod_CTF_Reset();
+}
+
+void HUD_Main()
+{
+ int i;
+ // global hud theAlpha fade
+ if(menu_enabled == 1)
+ hud_fade_alpha = 1;
+ else
+ hud_fade_alpha = (1 - autocvar__menu_alpha);
+
+ if(scoreboard_fade_alpha)
+ hud_fade_alpha = (1 - scoreboard_fade_alpha);
+
+ HUD_Configure_Frame();
+
+ // panels that we want to be active together with the scoreboard
+ // they must fade only when the menu does
+ if(scoreboard_fade_alpha == 1)
+ {
+ HUD_Panel_Draw(HUD_PANEL(CENTERPRINT));
+ return;
+ }
+
+ if(!autocvar__hud_configure && !hud_fade_alpha)
+ {
+ hud_fade_alpha = 1;
+ HUD_Panel_Draw(HUD_PANEL(VOTE));
+ hud_fade_alpha = 0;
+ return;
+ }
+
+ // Drawing stuff
+ if (hud_skin_prev != autocvar_hud_skin)
+ {
+ if (hud_skin_path)
+ strunzone(hud_skin_path);
+ hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
+ if (hud_skin_prev)
+ strunzone(hud_skin_prev);
+ hud_skin_prev = strzone(autocvar_hud_skin);
+ }
+
+ // draw the dock
+ if(autocvar_hud_dock != "" && autocvar_hud_dock != "0")
+ {
+ int f;
+ vector color;
+ float hud_dock_color_team = autocvar_hud_dock_color_team;
+ if((teamplay) && hud_dock_color_team) {
+ if(autocvar__hud_configure && myteam == NUM_SPECTATOR)
+ color = '1 0 0' * hud_dock_color_team;
+ else
+ color = myteamcolors * hud_dock_color_team;
+ }
+ else if(autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && hud_dock_color_team) {
+ color = '1 0 0' * hud_dock_color_team;
+ }
+ else
+ {
+ string hud_dock_color = autocvar_hud_dock_color;
+ if(hud_dock_color == "shirt") {
+ f = stof(getplayerkeyvalue(current_player, "colors"));
+ color = colormapPaletteColor(floor(f / 16), 0);
+ }
+ else if(hud_dock_color == "pants") {
+ f = stof(getplayerkeyvalue(current_player, "colors"));
+ color = colormapPaletteColor(f % 16, 1);
+ }
+ else
+ color = stov(hud_dock_color);
+ }
+
+ string pic;
+ pic = strcat(hud_skin_path, "/", autocvar_hud_dock);
+ if(precache_pic(pic) == "") {
+ pic = strcat(hud_skin_path, "/dock_medium");
+ if(precache_pic(pic) == "") {
+ pic = "gfx/hud/default/dock_medium";
+ }
+ }
+ drawpic('0 0 0', pic, eX * vid_conwidth + eY * vid_conheight, color, autocvar_hud_dock_alpha * hud_fade_alpha, DRAWFLAG_NORMAL); // no aspect ratio forcing on dock...
+ }
+
+ // cache the panel order into the panel_order array
+ if(autocvar__hud_panelorder != hud_panelorder_prev) {
+ for(i = 0; i < hud_panels_COUNT; ++i)
+ panel_order[i] = -1;
+ string s = "";
+ int p_num;
+ bool warning = false;
+ int argc = tokenize_console(autocvar__hud_panelorder);
+ if (argc > hud_panels_COUNT)
+ warning = true;
+ //first detect wrong/missing panel numbers
+ for(i = 0; i < hud_panels_COUNT; ++i) {
+ p_num = stoi(argv(i));
+ if (p_num >= 0 && p_num < hud_panels_COUNT) { //correct panel number?
+ if (panel_order[p_num] == -1) //found for the first time?
+ s = strcat(s, ftos(p_num), " ");
+ panel_order[p_num] = 1; //mark as found
+ }
+ else
+ warning = true;
+ }
+ for(i = 0; i < hud_panels_COUNT; ++i) {
+ if (panel_order[i] == -1) {
+ warning = true;
+ s = strcat(s, ftos(i), " "); //add missing panel number
+ }
+ }
+ if (warning)
+ LOG_TRACE("Automatically fixed wrong/missing panel numbers in _hud_panelorder\n");
+
+ cvar_set("_hud_panelorder", s);
+ if(hud_panelorder_prev)
+ strunzone(hud_panelorder_prev);
+ hud_panelorder_prev = strzone(s);
+
+ //now properly set panel_order
+ tokenize_console(s);
+ for(i = 0; i < hud_panels_COUNT; ++i) {
+ panel_order[i] = stof(argv(i));
+ }
+ }
+
+ hud_draw_maximized = 0;
+ // draw panels in the order specified by panel_order array
+ for(i = hud_panels_COUNT - 1; i >= 0; --i)
+ HUD_Panel_Draw(hud_panels_from(panel_order[i]));
+
+ HUD_Vehicle();
+
+ hud_draw_maximized = 1; // panels that may be maximized must check this var
+ // draw maximized panels on top
+ if(hud_panel_radar_maximized)
+ HUD_Panel_Draw(HUD_PANEL(RADAR));
+ if(autocvar__con_chat_maximized)
+ HUD_Panel_Draw(HUD_PANEL(CHAT));
+ if(hud_panel_quickmenu)
+ HUD_Panel_Draw(HUD_PANEL(QUICKMENU));
+
+ if (scoreboard_active || intermission == 2)
+ HUD_Reset();
+
+ HUD_Configure_PostDraw();
+
+ hud_configure_prev = autocvar__hud_configure;
+}
--- /dev/null
+#ifndef CLIENT_HUD_H
+#define CLIENT_HUD_H
+
+#include "../common/weapons/all.qh"
+
+bool HUD_Radar_Clickable();
+void HUD_Radar_Mouse();
+
+REGISTRY(hud_panels, BITS(6))
+#define hud_panels_from(i) _hud_panels_from(i, NULL)
+REGISTER_REGISTRY(hud_panels)
+
+#define REGISTER_HUD_PANEL(id, draw_func, name, configflags, showflags) \
+ void draw_func(); \
+ REGISTER(hud_panels, HUD_PANEL, id, m_id, new(hud_panel)) { \
+ make_pure(this); \
+ this.panel_id = this.m_id; \
+ this.panel_draw = draw_func; \
+ this.panel_name = #name; \
+ this.panel_configflags = configflags; \
+ this.panel_showflags = showflags; \
+ }
+
+#define HUD_PANEL(NAME) HUD_PANEL_##NAME
+
+// draw the background/borders
+#define HUD_Panel_DrawBg(theAlpha) do { \
+ if(panel.current_panel_bg != "0" && panel.current_panel_bg != "") \
+ draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel.current_panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER));\
+} while(0)
+
+int panel_order[hud_panels_MAX];
+string hud_panelorder_prev;
+
+bool hud_draw_maximized;
+bool hud_panel_radar_maximized;
+bool hud_panel_radar_mouse;
+float hud_panel_radar_bottom;
+bool hud_panel_radar_temp_hidden;
+bool chat_panel_modified;
+bool radar_panel_modified;
+
+float HUD_Radar_InputEvent(float bInputType, float nPrimary, float nSecondary);
+void HUD_Radar_Hide_Maximized();
+
+void HUD_Reset ();
+void HUD_Main ();
+
+int vote_yescount;
+int vote_nocount;
+int vote_needed;
+int vote_highlighted; // currently selected vote
+
+int vote_active; // is there an active vote?
+int vote_prev; // previous state of vote_active to check for a change
+float vote_alpha;
+float vote_change; // "time" when vote_active changed
+
+float hud_panel_quickmenu;
+
+vector mousepos;
+vector panel_click_distance; // mouse cursor distance from the top left corner of the panel (saved only upon a click)
+vector panel_click_resizeorigin; // coordinates for opposite point when resizing
+float resizeCorner; // 1 = topleft, 2 = topright, 3 = bottomleft, 4 = bottomright
+entity highlightedPanel;
+float highlightedAction; // 0 = nothing, 1 = move, 2 = resize
+
+const float BORDER_MULTIPLIER = 0.25;
+float scoreboard_bottom;
+int weapon_accuracy[Weapons_MAX];
+
+int complain_weapon;
+string complain_weapon_name;
+float complain_weapon_type;
+float complain_weapon_time;
+
+int ps_primary, ps_secondary;
+int ts_primary, ts_secondary;
+
+int last_switchweapon;
+int last_activeweapon;
+float weapontime;
+float weaponprevtime;
+
+float teamnagger;
+
+float hud_configure_checkcollisions;
+float hud_configure_prev;
+vector hud_configure_gridSize;
+vector hud_configure_realGridSize;
+
+int hudShiftState;
+const int S_SHIFT = 1;
+const int S_CTRL = 2;
+const int S_ALT = 4;
+
+float menu_enabled; // 1 showing the entire HUD, 2 showing only the clicked panel
+
+float hud_fade_alpha;
+
+string hud_skin_path;
+string hud_skin_prev;
+
+vector myteamcolors;
+
+entity highlightedPanel_backup;
+vector panel_pos_backup;
+vector panel_size_backup;
+
+vector panel_size_copied;
+
+entity panel;
+entityclass(HUDPanel);
+class(HUDPanel) .string panel_name;
+class(HUDPanel) .int panel_id;
+class(HUDPanel) .vector current_panel_pos;
+class(HUDPanel) .vector current_panel_size;
+class(HUDPanel) .string current_panel_bg;
+class(HUDPanel) .float current_panel_bg_alpha;
+class(HUDPanel) .float current_panel_bg_border;
+class(HUDPanel) .vector current_panel_bg_color;
+class(HUDPanel) .float current_panel_bg_color_team;
+class(HUDPanel) .float current_panel_bg_padding;
+class(HUDPanel) .float current_panel_fg_alpha;
+class(HUDPanel) .float update_time;
+float panel_enabled;
+vector panel_pos;
+vector panel_size;
+string panel_bg_str; // "_str" vars contain the raw value of the cvar, non-"_str" contains what hud.qc code should use
+vector panel_bg_color;
+string panel_bg_color_str;
+float panel_bg_color_team;
+string panel_bg_color_team_str;
+float panel_fg_alpha;
+float panel_bg_alpha;
+string panel_bg_alpha_str;
+float panel_bg_border;
+string panel_bg_border_str;
+float panel_bg_padding;
+string panel_bg_padding_str;
+
+class(HUDPanel) .void() panel_draw;
+
+// chat panel can be reduced / moved while the mapvote is active
+// let know the mapvote panel about chat pos and size
+float chat_posy;
+float chat_sizey;
+
+float current_player;
+
+float stringwidth_colors(string s, vector theSize);
+float stringwidth_nocolors(string s, vector theSize);
+float GetPlayerColorForce(int i);
+int GetPlayerColor(int i);
+string GetPlayerName(int i);
+void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag);
+
+.int panel_showflags;
+const int PANEL_SHOW_NEVER = 0x00;
+const int PANEL_SHOW_MAINGAME = 0x01;
+const int PANEL_SHOW_MINIGAME = 0x02;
+const int PANEL_SHOW_MAPVOTE = 0x04;
+const int PANEL_SHOW_ALWAYS = 0xff;
+bool HUD_Panel_CheckFlags(int showflags);
+
+.int panel_configflags;
+const int PANEL_CONFIG_NO = 0x00;
+const int PANEL_CONFIG_MAIN = 0x01;
+
+
+// prev_* vars contain the health/armor at the previous FRAME
+// set to -1 when player is dead or was not playing
+int prev_health, prev_armor;
+float health_damagetime, armor_damagetime;
+int health_beforedamage, armor_beforedamage;
+// old_p_* vars keep track of previous values when smoothing value changes of the progressbar
+int old_p_health, old_p_armor;
+float old_p_healthtime, old_p_armortime;
+// prev_p_* vars contain the health/armor progressbar value at the previous FRAME
+// set to -1 to forcedly stop effects when we switch spectated player (e.g. from playerX: 70h to playerY: 50h)
+int prev_p_health, prev_p_armor;
+
+void HUD_ItemsTime();
+
+REGISTER_HUD_PANEL(WEAPONS, HUD_Weapons, weapons, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(AMMO, HUD_Ammo, ammo, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(POWERUPS, HUD_Powerups, powerups, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(HEALTHARMOR, HUD_HealthArmor, healtharmor, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(NOTIFY, HUD_Notify, notify, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
+REGISTER_HUD_PANEL(TIMER, HUD_Timer, timer, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
+REGISTER_HUD_PANEL(RADAR, HUD_Radar, radar, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(SCORE, HUD_Score, score, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
+REGISTER_HUD_PANEL(RACETIMER, HUD_RaceTimer, racetimer, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(VOTE, HUD_Vote, vote, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(MODICONS, HUD_ModIcons, modicons, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(PRESSEDKEYS, HUD_PressedKeys, pressedkeys, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(CHAT, HUD_Chat, chat, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(ENGINEINFO, HUD_EngineInfo, engineinfo, PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(INFOMESSAGES, HUD_InfoMessages, infomessages, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(PHYSICS, HUD_Physics, physics, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(CENTERPRINT, HUD_CenterPrint, centerprint, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(MINIGAME_BOARD, HUD_MinigameBoard, minigameboard, PANEL_CONFIG_NO , PANEL_SHOW_MINIGAME)
+REGISTER_HUD_PANEL(MINIGAME_STATUS, HUD_MinigameStatus, minigamestatus, PANEL_CONFIG_NO , PANEL_SHOW_MINIGAME)
+REGISTER_HUD_PANEL(MINIGAME_HELP, HUD_MinigameHelp, minigamehelp, PANEL_CONFIG_NO , PANEL_SHOW_MINIGAME)
+REGISTER_HUD_PANEL(MINIGAME_MENU, HUD_MinigameMenu, minigamemenu, PANEL_CONFIG_NO , PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(MAPVOTE, MapVote_Draw, mapvote, PANEL_CONFIG_NO , PANEL_SHOW_MAPVOTE )
+REGISTER_HUD_PANEL(ITEMSTIME, HUD_ItemsTime, itemstime, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(QUICKMENU, HUD_QuickMenu, quickmenu, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+// always add new panels to the end of list
+
+// Because calling lots of functions in QC apparently cuts fps in half on many machines:
+// ----------------------
+// MACRO HELL STARTS HERE
+// ----------------------
+// Little help for the poor people who have to make sense of this: Start from the bottom ;)
+
+// Get value for panel.current_panel_bg: if "" fetch default, else use panel_bg_str
+// comment on last line of macro: // we probably want to see a background in config mode at all times...
+#define HUD_Panel_GetBg() do { \
+ string panel_bg; \
+ if (!autocvar__hud_configure && panel_bg_str == "0") { \
+ panel_bg = "0"; \
+ } else { \
+ if (panel_bg_str == "") { \
+ panel_bg_str = autocvar_hud_panel_bg; \
+ } \
+ if (panel_bg_str == "0" && !autocvar__hud_configure) { \
+ panel_bg = "0"; \
+ } else { \
+ if (panel_bg_str == "0" && autocvar__hud_configure) \
+ panel_bg_alpha_str = "0"; \
+ panel_bg = strcat(hud_skin_path, "/", panel_bg_str); \
+ if (precache_pic(panel_bg) == "") { \
+ panel_bg = strcat(hud_skin_path, "/", "border_default"); \
+ if (precache_pic(panel_bg) == "") { \
+ panel_bg = strcat("gfx/hud/default/", "border_default"); \
+ } \
+ } \
+ } \
+ } \
+ if (panel.current_panel_bg) \
+ strunzone(panel.current_panel_bg); \
+ panel.current_panel_bg = strzone(panel_bg); \
+} while(0)
+
+// Get value for panel_bg_color: if "" fetch default, else use panel_bg_color. Convert pants, shirt or teamcolor into a vector.
+#define HUD_Panel_GetColor() do { \
+ if ((teamplay) && panel_bg_color_team) { \
+ if (autocvar__hud_configure && myteam == NUM_SPECTATOR) \
+ panel_bg_color = '1 0 0' * panel_bg_color_team; \
+ else \
+ panel_bg_color = myteamcolors * panel_bg_color_team; \
+ } else if (autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && panel_bg_color_team) { \
+ panel_bg_color = '1 0 0' * panel_bg_color_team; \
+ } else { \
+ if (panel_bg_color_str == "") { \
+ panel_bg_color = autocvar_hud_panel_bg_color; \
+ } else { \
+ if (panel_bg_color_str == "shirt") { \
+ panel_bg_color = colormapPaletteColor(floor(stof(getplayerkeyvalue(current_player, "colors")) / 16), 0); \
+ } else if (panel_bg_color_str == "pants") { \
+ panel_bg_color = colormapPaletteColor(stof(getplayerkeyvalue(current_player, "colors")) % 16, 1); \
+ } else { \
+ panel_bg_color = stov(panel_bg_color_str); \
+ } \
+ } \
+ } \
+} while(0)
+
+// Get value for panel_bg_color_team: if "" fetch default, else use panel_bg_color_team_str
+#define HUD_Panel_GetColorTeam() do { \
+ if (panel_bg_color_team_str == "") { \
+ panel_bg_color_team = autocvar_hud_panel_bg_color_team; \
+ } else { \
+ panel_bg_color_team = stof(panel_bg_color_team_str); \
+ } \
+} while(0)
+
+// Get value for panel_bg_alpha: if "" fetch default, else use panel_bg_alpha. Also do various menu dialog fadeout/in checks, and minalpha checks
+// comment on line 3 of macro: // do not set a minalpha cap when showing the config dialog for this panel
+#define HUD_Panel_GetBgAlpha() do { \
+ if (panel_bg_alpha_str == "") { \
+ panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha); \
+ } \
+ panel_bg_alpha = stof(panel_bg_alpha_str); \
+ if (autocvar__hud_configure) { \
+ if (!panel_enabled) \
+ panel_bg_alpha = 0.25; \
+ else if (menu_enabled == 2 && panel == highlightedPanel) \
+ panel_bg_alpha = (1 - autocvar__menu_alpha) * max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha) + autocvar__menu_alpha * panel_bg_alpha;\
+ else \
+ panel_bg_alpha = max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha); \
+ } \
+} while(0)
+
+// Get value for panel_fg_alpha. Also do various minalpha checks
+// comment on line 2 of macro: // ALWAYS show disabled panels at 0.25 alpha when in config mode
+#define HUD_Panel_GetFgAlpha() do { \
+ panel_fg_alpha = autocvar_hud_panel_fg_alpha; \
+ if (autocvar__hud_configure && !panel_enabled) \
+ panel_fg_alpha = 0.25; \
+} while(0)
+
+// Get border. See comments above, it's similar.
+#define HUD_Panel_GetBorder() do { \
+ if (panel_bg_border_str == "") { \
+ panel_bg_border = autocvar_hud_panel_bg_border; \
+ } else { \
+ panel_bg_border = stof(panel_bg_border_str); \
+ } \
+} while(0)
+
+// Get padding. See comments above, it's similar.
+// last line is a port of the old function, basically always make sure the panel contents are at least 5 pixels tall/wide, to disallow extreme padding values
+#define HUD_Panel_GetPadding() do { \
+ if (panel_bg_padding_str == "") { \
+ panel_bg_padding = autocvar_hud_panel_bg_padding; \
+ } else { \
+ panel_bg_padding = stof(panel_bg_padding_str); \
+ } \
+ panel_bg_padding = min(min(panel_size.x, panel_size.y)/2 - 5, panel_bg_padding); \
+} while(0)
+
+// return smoothly faded pos and size of given panel when a dialog is active
+// don't center too wide panels, it doesn't work with different resolutions
+#define HUD_Panel_UpdatePosSize_ForMenu() do { \
+ vector menu_enable_size = panel_size; \
+ float max_panel_width = 0.52 * vid_conwidth; \
+ if(panel_size.x > max_panel_width) \
+ { \
+ menu_enable_size.x = max_panel_width; \
+ menu_enable_size.y = panel_size.y * (menu_enable_size.x / panel_size.x); \
+ } \
+ vector menu_enable_pos = eX * (panel_bg_border + 0.5 * max_panel_width) + eY * 0.5 * vid_conheight - 0.5 * menu_enable_size; \
+ panel_pos = (1 - autocvar__menu_alpha) * panel_pos + (autocvar__menu_alpha) * menu_enable_pos; \
+ panel_size = (1 - autocvar__menu_alpha) * panel_size + (autocvar__menu_alpha) * menu_enable_size; \
+} while(0)
+
+// Scale the pos and size vectors to absolute coordinates
+#define HUD_Panel_ScalePosSize() do { \
+ panel_pos.x *= vid_conwidth; panel_pos.y *= vid_conheight; \
+ panel_size.x *= vid_conwidth; panel_size.y *= vid_conheight; \
+} while(0)
+
+// NOTE: in hud_configure mode cvars must be reloaded every frame
+#define HUD_Panel_UpdateCvars() do { \
+ if (panel.update_time <= time) { \
+ if (autocvar__hud_configure) panel_enabled = cvar(strcat("hud_panel_", panel.panel_name)); \
+ panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos"))); \
+ panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size"))); \
+ HUD_Panel_ScalePosSize(); \
+ panel_bg_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg")); \
+ panel_bg_color_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color")); \
+ panel_bg_color_team_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color_team")); \
+ panel_bg_alpha_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_alpha")); \
+ panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border")); \
+ panel_bg_padding_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_padding")); \
+ HUD_Panel_GetBg(); \
+ if (panel.current_panel_bg != "0") { \
+ HUD_Panel_GetColorTeam(); \
+ HUD_Panel_GetColor(); \
+ HUD_Panel_GetBgAlpha(); \
+ HUD_Panel_GetBorder(); \
+ } \
+ HUD_Panel_GetFgAlpha(); \
+ HUD_Panel_GetPadding(); \
+ panel.current_panel_bg_alpha = panel_bg_alpha; \
+ panel.current_panel_fg_alpha = panel_fg_alpha; \
+ if (menu_enabled == 2 && panel == highlightedPanel) { \
+ HUD_Panel_UpdatePosSize_ForMenu(); \
+ } else { \
+ panel_bg_alpha *= hud_fade_alpha; \
+ panel_fg_alpha *= hud_fade_alpha; \
+ } \
+ panel.current_panel_pos = panel_pos; \
+ panel.current_panel_size = panel_size; \
+ panel.current_panel_bg_border = panel_bg_border; \
+ panel.current_panel_bg_color = panel_bg_color; \
+ panel.current_panel_bg_color_team = panel_bg_color_team; \
+ panel.current_panel_bg_padding = panel_bg_padding; \
+ panel.update_time = (autocvar__hud_configure) ? time : time + autocvar_hud_panel_update_interval; \
+ } else { \
+ panel_pos = panel.current_panel_pos; \
+ panel_size = panel.current_panel_size; \
+ panel_bg_alpha = panel.current_panel_bg_alpha * hud_fade_alpha; \
+ panel_bg_border = panel.current_panel_bg_border; \
+ panel_bg_color = panel.current_panel_bg_color; \
+ panel_bg_color_team = panel.current_panel_bg_color_team; \
+ panel_bg_padding = panel.current_panel_bg_padding; \
+ panel_fg_alpha = panel.current_panel_fg_alpha * hud_fade_alpha; \
+ } \
+} while(0)
+
+#define HUD_Panel_UpdatePosSize() do { \
+ panel_enabled = cvar(strcat("hud_panel_", panel.panel_name)); \
+ panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos"))); \
+ panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size"))); \
+ HUD_Panel_ScalePosSize(); \
+ if (menu_enabled == 2 && panel == highlightedPanel) { \
+ HUD_Panel_UpdatePosSize_ForMenu(); \
+ } \
+ panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border")); \
+ HUD_Panel_GetBorder(); \
+} while(0)
+
+const int NOTIFY_MAX_ENTRIES = 10;
+const float NOTIFY_ICON_MARGIN = 0.02;
+
+int notify_index;
+int notify_count;
+float notify_times[NOTIFY_MAX_ENTRIES];
+string notify_attackers[NOTIFY_MAX_ENTRIES];
+string notify_victims[NOTIFY_MAX_ENTRIES];
+string notify_icons[NOTIFY_MAX_ENTRIES];
+
+void HUD_Notify_Push(string icon, string attacker, string victim);
+
+var void HUD_ModIcons_GameType(vector pos, vector size);
+void HUD_ModIcons_SetFunc();
+#endif
--- /dev/null
+#include "hud_config.qh"
+
+#include "hud.qh"
+
+#define HUD_Write(s) fputs(fh, s)
+// q: quoted, n: not quoted
+#define HUD_Write_Cvar_n(cvar) HUD_Write(strcat("seta ", cvar, " ", cvar_string(cvar), "\n"))
+#define HUD_Write_Cvar_q(cvar) HUD_Write(strcat("seta ", cvar, " \"", cvar_string(cvar), "\"\n"))
+#define HUD_Write_PanelCvar_n(cvar_suf) HUD_Write_Cvar_n(strcat("hud_panel_", panel.panel_name, cvar_suf))
+#define HUD_Write_PanelCvar_q(cvar_suf) HUD_Write_Cvar_q(strcat("hud_panel_", panel.panel_name, cvar_suf))
+// Save the config
+void HUD_Panel_ExportCfg(string cfgname)
+{
+ float fh;
+ string filename = strcat("hud_", autocvar_hud_skin, "_", cfgname, ".cfg");
+ fh = fopen(filename, FILE_WRITE);
+ if(fh >= 0)
+ {
+ HUD_Write_Cvar_q("hud_skin");
+ HUD_Write_Cvar_q("hud_panel_bg");
+ HUD_Write_Cvar_q("hud_panel_bg_color");
+ HUD_Write_Cvar_q("hud_panel_bg_color_team");
+ HUD_Write_Cvar_q("hud_panel_bg_alpha");
+ HUD_Write_Cvar_q("hud_panel_bg_border");
+ HUD_Write_Cvar_q("hud_panel_bg_padding");
+ HUD_Write_Cvar_q("hud_panel_fg_alpha");
+ HUD_Write("\n");
+
+ HUD_Write_Cvar_q("hud_dock");
+ HUD_Write_Cvar_q("hud_dock_color");
+ HUD_Write_Cvar_q("hud_dock_color_team");
+ HUD_Write_Cvar_q("hud_dock_alpha");
+ HUD_Write("\n");
+
+ HUD_Write_Cvar_q("hud_progressbar_alpha");
+ HUD_Write_Cvar_q("hud_progressbar_strength_color");
+ HUD_Write_Cvar_q("hud_progressbar_shield_color");
+ HUD_Write_Cvar_q("hud_progressbar_health_color");
+ HUD_Write_Cvar_q("hud_progressbar_armor_color");
+ HUD_Write_Cvar_q("hud_progressbar_fuel_color");
+ HUD_Write_Cvar_q("hud_progressbar_nexball_color");
+ HUD_Write_Cvar_q("hud_progressbar_speed_color");
+ HUD_Write_Cvar_q("hud_progressbar_acceleration_color");
+ HUD_Write_Cvar_q("hud_progressbar_acceleration_neg_color");
+ HUD_Write("\n");
+
+ HUD_Write_Cvar_q("_hud_panelorder");
+ HUD_Write("\n");
+
+ HUD_Write_Cvar_q("hud_configure_grid");
+ HUD_Write_Cvar_q("hud_configure_grid_xsize");
+ HUD_Write_Cvar_q("hud_configure_grid_ysize");
+ HUD_Write("\n");
+
+ // common cvars for all panels
+ for (int i = 0; i < hud_panels_COUNT; ++i)
+ {
+ panel = hud_panels_from(i);
+
+ HUD_Write_PanelCvar_n("");
+ HUD_Write_PanelCvar_q("_pos");
+ HUD_Write_PanelCvar_q("_size");
+ HUD_Write_PanelCvar_q("_bg");
+ HUD_Write_PanelCvar_q("_bg_color");
+ HUD_Write_PanelCvar_q("_bg_color_team");
+ HUD_Write_PanelCvar_q("_bg_alpha");
+ HUD_Write_PanelCvar_q("_bg_border");
+ HUD_Write_PanelCvar_q("_bg_padding");
+ switch(panel) {
+ case HUD_PANEL_WEAPONS:
+ HUD_Write_PanelCvar_q("_accuracy");
+ HUD_Write_PanelCvar_q("_label");
+ HUD_Write_PanelCvar_q("_label_scale");
+ HUD_Write_PanelCvar_q("_complainbubble");
+ HUD_Write_PanelCvar_q("_complainbubble_padding");
+ HUD_Write_PanelCvar_q("_complainbubble_time");
+ HUD_Write_PanelCvar_q("_complainbubble_fadetime");
+ HUD_Write_PanelCvar_q("_complainbubble_color_outofammo");
+ HUD_Write_PanelCvar_q("_complainbubble_color_donthave");
+ HUD_Write_PanelCvar_q("_complainbubble_color_unavailable");
+ HUD_Write_PanelCvar_q("_ammo");
+ HUD_Write_PanelCvar_q("_ammo_color");
+ HUD_Write_PanelCvar_q("_ammo_alpha");
+ HUD_Write_PanelCvar_q("_aspect");
+ HUD_Write_PanelCvar_q("_timeout");
+ HUD_Write_PanelCvar_q("_timeout_effect");
+ HUD_Write_PanelCvar_q("_timeout_fadebgmin");
+ HUD_Write_PanelCvar_q("_timeout_fadefgmin");
+ HUD_Write_PanelCvar_q("_timeout_speed_in");
+ HUD_Write_PanelCvar_q("_timeout_speed_out");
+ HUD_Write_PanelCvar_q("_onlyowned");
+ HUD_Write_PanelCvar_q("_noncurrent_alpha");
+ HUD_Write_PanelCvar_q("_noncurrent_scale");
+ break;
+ case HUD_PANEL_AMMO:
+ HUD_Write_PanelCvar_q("_onlycurrent");
+ HUD_Write_PanelCvar_q("_noncurrent_alpha");
+ HUD_Write_PanelCvar_q("_noncurrent_scale");
+ HUD_Write_PanelCvar_q("_iconalign");
+ HUD_Write_PanelCvar_q("_progressbar");
+ HUD_Write_PanelCvar_q("_progressbar_name");
+ HUD_Write_PanelCvar_q("_progressbar_xoffset");
+ HUD_Write_PanelCvar_q("_text");
+ break;
+ case HUD_PANEL_POWERUPS:
+ HUD_Write_PanelCvar_q("_iconalign");
+ HUD_Write_PanelCvar_q("_baralign");
+ HUD_Write_PanelCvar_q("_progressbar");
+ HUD_Write_PanelCvar_q("_text");
+ break;
+ case HUD_PANEL_HEALTHARMOR:
+ HUD_Write_PanelCvar_q("_flip");
+ HUD_Write_PanelCvar_q("_iconalign");
+ HUD_Write_PanelCvar_q("_baralign");
+ HUD_Write_PanelCvar_q("_progressbar");
+ HUD_Write_PanelCvar_q("_progressbar_health");
+ HUD_Write_PanelCvar_q("_progressbar_armor");
+ HUD_Write_PanelCvar_q("_progressbar_gfx");
+ HUD_Write_PanelCvar_q("_progressbar_gfx_smooth");
+ HUD_Write_PanelCvar_q("_text");
+ break;
+ case HUD_PANEL_NOTIFY:
+ HUD_Write_PanelCvar_q("_flip");
+ HUD_Write_PanelCvar_q("_fontsize");
+ HUD_Write_PanelCvar_q("_time");
+ HUD_Write_PanelCvar_q("_fadetime");
+ HUD_Write_PanelCvar_q("_icon_aspect");
+ break;
+ case HUD_PANEL_TIMER:
+ HUD_Write_PanelCvar_q("_increment");
+ break;
+ case HUD_PANEL_RADAR:
+ HUD_Write_PanelCvar_q("_foreground_alpha");
+ HUD_Write_PanelCvar_q("_rotation");
+ HUD_Write_PanelCvar_q("_zoommode");
+ HUD_Write_PanelCvar_q("_scale");
+ HUD_Write_PanelCvar_q("_maximized_scale");
+ HUD_Write_PanelCvar_q("_maximized_size");
+ HUD_Write_PanelCvar_q("_maximized_rotation");
+ HUD_Write_PanelCvar_q("_maximized_zoommode");
+ break;
+ case HUD_PANEL_SCORE:
+ HUD_Write_PanelCvar_q("_rankings");
+ break;
+ case HUD_PANEL_VOTE:
+ HUD_Write_PanelCvar_q("_alreadyvoted_alpha");
+ break;
+ case HUD_PANEL_MODICONS:
+ HUD_Write_PanelCvar_q("_ca_layout");
+ HUD_Write_PanelCvar_q("_dom_layout");
+ HUD_Write_PanelCvar_q("_freezetag_layout");
+ break;
+ case HUD_PANEL_PRESSEDKEYS:
+ HUD_Write_PanelCvar_q("_aspect");
+ HUD_Write_PanelCvar_q("_attack");
+ break;
+ case HUD_PANEL_ENGINEINFO:
+ HUD_Write_PanelCvar_q("_framecounter_time");
+ HUD_Write_PanelCvar_q("_framecounter_decimals");
+ break;
+ case HUD_PANEL_INFOMESSAGES:
+ HUD_Write_PanelCvar_q("_flip");
+ break;
+ case HUD_PANEL_PHYSICS:
+ HUD_Write_PanelCvar_q("_speed_unit");
+ HUD_Write_PanelCvar_q("_speed_unit_show");
+ HUD_Write_PanelCvar_q("_speed_max");
+ HUD_Write_PanelCvar_q("_speed_vertical");
+ HUD_Write_PanelCvar_q("_topspeed");
+ HUD_Write_PanelCvar_q("_topspeed_time");
+ HUD_Write_PanelCvar_q("_acceleration_max");
+ HUD_Write_PanelCvar_q("_acceleration_vertical");
+ HUD_Write_PanelCvar_q("_flip");
+ HUD_Write_PanelCvar_q("_baralign");
+ HUD_Write_PanelCvar_q("_progressbar");
+ HUD_Write_PanelCvar_q("_progressbar_acceleration_mode");
+ HUD_Write_PanelCvar_q("_progressbar_acceleration_scale");
+ HUD_Write_PanelCvar_q("_progressbar_acceleration_nonlinear");
+ HUD_Write_PanelCvar_q("_text");
+ HUD_Write_PanelCvar_q("_text_scale");
+ break;
+ case HUD_PANEL_CENTERPRINT:
+ HUD_Write_PanelCvar_q("_align");
+ HUD_Write_PanelCvar_q("_flip");
+ HUD_Write_PanelCvar_q("_fontscale");
+ HUD_Write_PanelCvar_q("_time");
+ HUD_Write_PanelCvar_q("_fade_in");
+ HUD_Write_PanelCvar_q("_fade_out");
+ HUD_Write_PanelCvar_q("_fade_subsequent");
+ HUD_Write_PanelCvar_q("_fade_subsequent_passone");
+ HUD_Write_PanelCvar_q("_fade_subsequent_passone_minalpha");
+ HUD_Write_PanelCvar_q("_fade_subsequent_passtwo");
+ HUD_Write_PanelCvar_q("_fade_subsequent_passtwo_minalpha");
+ HUD_Write_PanelCvar_q("_fade_subsequent_minfontsize");
+ HUD_Write_PanelCvar_q("_fade_minfontsize");
+ break;
+ case HUD_PANEL_ITEMSTIME:
+ HUD_Write_PanelCvar_q("_iconalign");
+ HUD_Write_PanelCvar_q("_progressbar");
+ HUD_Write_PanelCvar_q("_progressbar_name");
+ HUD_Write_PanelCvar_q("_progressbar_reduced");
+ HUD_Write_PanelCvar_q("_text");
+ HUD_Write_PanelCvar_q("_ratio");
+ HUD_Write_PanelCvar_q("_dynamicsize");
+ case HUD_PANEL_QUICKMENU:
+ HUD_Write_PanelCvar_q("_align");
+ break;
+ }
+ HUD_Write("\n");
+ }
+ HUD_Write("menu_sync\n"); // force the menu to reread the cvars, so that the dialogs are updated
+
+ LOG_INFOF(_("^2Successfully exported to %s! (Note: It's saved in data/data/)\n"), filename);
+ fclose(fh);
+ }
+ else
+ LOG_INFOF(_("^1Couldn't write to %s\n"), filename);
+}
+
+void HUD_Configure_Exit_Force()
+{
+ if (menu_enabled)
+ {
+ menu_enabled = 0;
+ localcmd("togglemenu\n");
+ }
+ cvar_set("_hud_configure", "0");
+}
+
+// check if move will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
+vector HUD_Panel_CheckMove(vector myPos, vector mySize)
+{
+ vector myCenter, targCenter;
+ vector myTarget = myPos;
+ int i;
+ for (i = 0; i < hud_panels_COUNT; ++i) {
+ panel = hud_panels_from(i);
+ if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
+ if(panel == highlightedPanel) continue;
+ HUD_Panel_UpdatePosSize();
+ if(!panel_enabled) continue;
+
+ panel_pos -= '1 1 0' * panel_bg_border;
+ panel_size += '2 2 0' * panel_bg_border;
+
+ if(myPos.y + mySize.y < panel_pos.y)
+ continue;
+ if(myPos.y > panel_pos.y + panel_size.y)
+ continue;
+
+ if(myPos.x + mySize.x < panel_pos.x)
+ continue;
+ if(myPos.x > panel_pos.x + panel_size.x)
+ continue;
+
+ // OK, there IS a collision.
+
+ myCenter.x = myPos.x + 0.5 * mySize.x;
+ myCenter.y = myPos.y + 0.5 * mySize.y;
+
+ targCenter.x = panel_pos.x + 0.5 * panel_size.x;
+ targCenter.y = panel_pos.y + 0.5 * panel_size.y;
+
+ if(myCenter.x < targCenter.x && myCenter.y < targCenter.y) // top left (of the target panel)
+ {
+ if(myPos.x + mySize.x - panel_pos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
+ myTarget.x = panel_pos.x - mySize.x;
+ else // push it upwards
+ myTarget.y = panel_pos.y - mySize.y;
+ }
+ else if(myCenter.x > targCenter.x && myCenter.y < targCenter.y) // top right
+ {
+ if(panel_pos.x + panel_size.x - myPos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
+ myTarget.x = panel_pos.x + panel_size.x;
+ else // push it upwards
+ myTarget.y = panel_pos.y - mySize.y;
+ }
+ else if(myCenter.x < targCenter.x && myCenter.y > targCenter.y) // bottom left
+ {
+ if(myPos.x + mySize.x - panel_pos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
+ myTarget.x = panel_pos.x - mySize.x;
+ else // push it downwards
+ myTarget.y = panel_pos.y + panel_size.y;
+ }
+ else if(myCenter.x > targCenter.x && myCenter.y > targCenter.y) // bottom right
+ {
+ if(panel_pos.x + panel_size.x - myPos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
+ myTarget.x = panel_pos.x + panel_size.x;
+ else // push it downwards
+ myTarget.y = panel_pos.y + panel_size.y;
+ }
+ //if(cvar("hud_configure_checkcollisions_debug"))
+ //drawfill(panel_pos, panel_size, '1 1 0', .3, DRAWFLAG_NORMAL);
+ }
+
+ return myTarget;
+}
+
+void HUD_Panel_SetPos(vector pos)
+{
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize();
+ vector mySize;
+ mySize = panel_size;
+
+ //if(cvar("hud_configure_checkcollisions_debug"))
+ //drawfill(pos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
+
+ if(autocvar_hud_configure_grid)
+ {
+ pos.x = floor((pos.x/vid_conwidth)/hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
+ pos.y = floor((pos.y/vid_conheight)/hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
+ }
+
+ if(hud_configure_checkcollisions)
+ pos = HUD_Panel_CheckMove(pos, mySize);
+
+ pos.x = bound(0, pos.x, vid_conwidth - mySize.x);
+ pos.y = bound(0, pos.y, vid_conheight - mySize.y);
+
+ string s;
+ s = strcat(ftos(pos.x/vid_conwidth), " ", ftos(pos.y/vid_conheight));
+
+ cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
+}
+
+// check if resize will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
+vector HUD_Panel_CheckResize(vector mySize, vector resizeorigin) {
+ vector targEndPos;
+ vector dist;
+ float ratio = mySize.x/mySize.y;
+ int i;
+ for (i = 0; i < hud_panels_COUNT; ++i) {
+ panel = hud_panels_from(i);
+ if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
+ if(panel == highlightedPanel) continue;
+ HUD_Panel_UpdatePosSize();
+ if(!panel_enabled) continue;
+
+ panel_pos -= '1 1 0' * panel_bg_border;
+ panel_size += '2 2 0' * panel_bg_border;
+
+ targEndPos = panel_pos + panel_size;
+
+ // resizeorigin is WITHIN target panel, just abort any collision testing against that particular panel to produce expected behaviour!
+ if(resizeorigin.x > panel_pos.x && resizeorigin.x < targEndPos.x && resizeorigin.y > panel_pos.y && resizeorigin.y < targEndPos.y)
+ continue;
+
+ if (resizeCorner == 1)
+ {
+ // check if this panel is on our way
+ if (resizeorigin.x <= panel_pos.x)
+ continue;
+ if (resizeorigin.y <= panel_pos.y)
+ continue;
+ if (targEndPos.x <= resizeorigin.x - mySize.x)
+ continue;
+ if (targEndPos.y <= resizeorigin.y - mySize.y)
+ continue;
+
+ // there is a collision:
+ // detect which side of the panel we are facing is actually limiting the resizing
+ // (which side the resize direction finds for first) and reduce the size up to there
+ //
+ // dist is the distance between resizeorigin and the "analogous" point of the panel
+ // in this case between resizeorigin (bottom-right point) and the bottom-right point of the panel
+ dist.x = resizeorigin.x - targEndPos.x;
+ dist.y = resizeorigin.y - targEndPos.y;
+ if (dist.y <= 0 || dist.x / dist.y > ratio)
+ mySize.x = min(mySize.x, dist.x);
+ else
+ mySize.y = min(mySize.y, dist.y);
+ }
+ else if (resizeCorner == 2)
+ {
+ if (resizeorigin.x >= targEndPos.x)
+ continue;
+ if (resizeorigin.y <= panel_pos.y)
+ continue;
+ if (panel_pos.x >= resizeorigin.x + mySize.x)
+ continue;
+ if (targEndPos.y <= resizeorigin.y - mySize.y)
+ continue;
+
+ dist.x = panel_pos.x - resizeorigin.x;
+ dist.y = resizeorigin.y - targEndPos.y;
+ if (dist.y <= 0 || dist.x / dist.y > ratio)
+ mySize.x = min(mySize.x, dist.x);
+ else
+ mySize.y = min(mySize.y, dist.y);
+ }
+ else if (resizeCorner == 3)
+ {
+ if (resizeorigin.x <= panel_pos.x)
+ continue;
+ if (resizeorigin.y >= targEndPos.y)
+ continue;
+ if (targEndPos.x <= resizeorigin.x - mySize.x)
+ continue;
+ if (panel_pos.y >= resizeorigin.y + mySize.y)
+ continue;
+
+ dist.x = resizeorigin.x - targEndPos.x;
+ dist.y = panel_pos.y - resizeorigin.y;
+ if (dist.y <= 0 || dist.x / dist.y > ratio)
+ mySize.x = min(mySize.x, dist.x);
+ else
+ mySize.y = min(mySize.y, dist.y);
+ }
+ else if (resizeCorner == 4)
+ {
+ if (resizeorigin.x >= targEndPos.x)
+ continue;
+ if (resizeorigin.y >= targEndPos.y)
+ continue;
+ if (panel_pos.x >= resizeorigin.x + mySize.x)
+ continue;
+ if (panel_pos.y >= resizeorigin.y + mySize.y)
+ continue;
+
+ dist.x = panel_pos.x - resizeorigin.x;
+ dist.y = panel_pos.y - resizeorigin.y;
+ if (dist.y <= 0 || dist.x / dist.y > ratio)
+ mySize.x = min(mySize.x, dist.x);
+ else
+ mySize.y = min(mySize.y, dist.y);
+ }
+ //if(cvar("hud_configure_checkcollisions_debug"))
+ //drawfill(panel_pos, panel_size, '1 1 0', .3, DRAWFLAG_NORMAL);
+ }
+
+ return mySize;
+}
+
+void HUD_Panel_SetPosSize(vector mySize)
+{
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize();
+ vector resizeorigin = panel_click_resizeorigin;
+ vector myPos;
+
+ // minimum panel size cap
+ mySize.x = max(0.025 * vid_conwidth, mySize.x);
+ mySize.y = max(0.025 * vid_conheight, mySize.y);
+
+ if(highlightedPanel == HUD_PANEL(CHAT)) // some panels have their own restrictions, like the chat panel (which actually only moves the engine chat print around). Looks bad if it's too small.
+ {
+ mySize.x = max(17 * autocvar_con_chatsize, mySize.x);
+ mySize.y = max(2 * autocvar_con_chatsize + 2 * panel_bg_padding, mySize.y);
+ }
+
+ // collision testing|
+ // -----------------+
+
+ // we need to know pos at this stage, but it might still change later if we hit a screen edge/other panel (?)
+ if(resizeCorner == 1) {
+ myPos.x = resizeorigin.x - mySize.x;
+ myPos.y = resizeorigin.y - mySize.y;
+ } else if(resizeCorner == 2) {
+ myPos.x = resizeorigin.x;
+ myPos.y = resizeorigin.y - mySize.y;
+ } else if(resizeCorner == 3) {
+ myPos.x = resizeorigin.x - mySize.x;
+ myPos.y = resizeorigin.y;
+ } else { // resizeCorner == 4
+ myPos.x = resizeorigin.x;
+ myPos.y = resizeorigin.y;
+ }
+
+ // left/top screen edges
+ if(myPos.x < 0)
+ mySize.x = mySize.x + myPos.x;
+ if(myPos.y < 0)
+ mySize.y = mySize.y + myPos.y;
+
+ // bottom/right screen edges
+ if(myPos.x + mySize.x > vid_conwidth)
+ mySize.x = vid_conwidth - myPos.x;
+ if(myPos.y + mySize.y > vid_conheight)
+ mySize.y = vid_conheight - myPos.y;
+
+ //if(cvar("hud_configure_checkcollisions_debug"))
+ //drawfill(myPos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
+
+ // before checkresize, otherwise panel can be snapped partially inside another panel or panel aspect ratio can be broken
+ if(autocvar_hud_configure_grid)
+ {
+ mySize.x = floor((mySize.x/vid_conwidth)/hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
+ mySize.y = floor((mySize.y/vid_conheight)/hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
+ }
+
+ if(hud_configure_checkcollisions)
+ mySize = HUD_Panel_CheckResize(mySize, resizeorigin);
+
+ // minimum panel size cap, do this once more so we NEVER EVER EVER have a panel smaller than this, JUST IN CASE above code still makes the panel eg negative (impossible to resize back without changing cvars manually then)
+ mySize.x = max(0.025 * vid_conwidth, mySize.x);
+ mySize.y = max(0.025 * vid_conheight, mySize.y);
+
+ // do another pos check, as size might have changed by now
+ if(resizeCorner == 1) {
+ myPos.x = resizeorigin.x - mySize.x;
+ myPos.y = resizeorigin.y - mySize.y;
+ } else if(resizeCorner == 2) {
+ myPos.x = resizeorigin.x;
+ myPos.y = resizeorigin.y - mySize.y;
+ } else if(resizeCorner == 3) {
+ myPos.x = resizeorigin.x - mySize.x;
+ myPos.y = resizeorigin.y;
+ } else { // resizeCorner == 4
+ myPos.x = resizeorigin.x;
+ myPos.y = resizeorigin.y;
+ }
+
+ //if(cvar("hud_configure_checkcollisions_debug"))
+ //drawfill(myPos, mySize, '0 1 0', .3, DRAWFLAG_NORMAL);
+
+ string s;
+ s = strcat(ftos(mySize.x/vid_conwidth), " ", ftos(mySize.y/vid_conheight));
+ cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
+
+ s = strcat(ftos(myPos.x/vid_conwidth), " ", ftos(myPos.y/vid_conheight));
+ cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
+}
+
+float pressed_key_time;
+vector highlightedPanel_initial_pos, highlightedPanel_initial_size;
+void HUD_Panel_Arrow_Action(float nPrimary)
+{
+ if(!highlightedPanel)
+ return;
+
+ hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
+
+ float step;
+ if(autocvar_hud_configure_grid)
+ {
+ if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
+ {
+ if (hudShiftState & S_SHIFT)
+ step = hud_configure_realGridSize.y;
+ else
+ step = 2 * hud_configure_realGridSize.y;
+ }
+ else
+ {
+ if (hudShiftState & S_SHIFT)
+ step = hud_configure_realGridSize.x;
+ else
+ step = 2 * hud_configure_realGridSize.x;
+ }
+ }
+ else
+ {
+ if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
+ step = vid_conheight;
+ else
+ step = vid_conwidth;
+ if (hudShiftState & S_SHIFT)
+ step = (step / 256); // more precision
+ else
+ step = (step / 64) * (1 + 2 * (time - pressed_key_time));
+ }
+
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize();
+
+ highlightedPanel_initial_pos = panel_pos;
+ highlightedPanel_initial_size = panel_size;
+
+ if (hudShiftState & S_ALT) // resize
+ {
+ if(nPrimary == K_UPARROW)
+ resizeCorner = 1;
+ else if(nPrimary == K_RIGHTARROW)
+ resizeCorner = 2;
+ else if(nPrimary == K_LEFTARROW)
+ resizeCorner = 3;
+ else // if(nPrimary == K_DOWNARROW)
+ resizeCorner = 4;
+
+ // ctrl+arrow reduces the size, instead of increasing it
+ // Note that ctrl disables collisions check too, but it's fine
+ // since we don't collide with anything reducing the size
+ if (hudShiftState & S_CTRL) {
+ step = -step;
+ resizeCorner = 5 - resizeCorner;
+ }
+
+ vector mySize;
+ mySize = panel_size;
+ panel_click_resizeorigin = panel_pos;
+ if(resizeCorner == 1) {
+ panel_click_resizeorigin += mySize;
+ mySize.y += step;
+ } else if(resizeCorner == 2) {
+ panel_click_resizeorigin.y += mySize.y;
+ mySize.x += step;
+ } else if(resizeCorner == 3) {
+ panel_click_resizeorigin.x += mySize.x;
+ mySize.x += step;
+ } else { // resizeCorner == 4
+ mySize.y += step;
+ }
+ HUD_Panel_SetPosSize(mySize);
+ }
+ else // move
+ {
+ vector pos;
+ pos = panel_pos;
+ if(nPrimary == K_UPARROW)
+ pos.y -= step;
+ else if(nPrimary == K_DOWNARROW)
+ pos.y += step;
+ else if(nPrimary == K_LEFTARROW)
+ pos.x -= step;
+ else // if(nPrimary == K_RIGHTARROW)
+ pos.x += step;
+
+ HUD_Panel_SetPos(pos);
+ }
+
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize();
+
+ if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
+ {
+ // backup!
+ panel_pos_backup = highlightedPanel_initial_pos;
+ panel_size_backup = highlightedPanel_initial_size;
+ highlightedPanel_backup = highlightedPanel;
+ }
+}
+
+void HUD_Panel_EnableMenu();
+entity tab_panels[hud_panels_MAX];
+entity tab_panel;
+vector tab_panel_pos;
+float tab_backward;
+void HUD_Panel_FirstInDrawQ(float id);
+void reset_tab_panels()
+{
+ int i;
+ for(i = 0; i < hud_panels_COUNT; ++i)
+ tab_panels[i] = world;
+}
+float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
+{
+ string s;
+
+ if(bInputType == 2)
+ return false;
+
+ if(!autocvar__hud_configure)
+ return false;
+
+ if(bInputType == 3)
+ {
+ mousepos.x = nPrimary;
+ mousepos.y = nSecondary;
+ return true;
+ }
+
+ // block any input while a menu dialog is fading
+ // don't block mousepos read as it leads to cursor jumps in the interaction with the menu
+ if(autocvar__menu_alpha)
+ {
+ hudShiftState = 0;
+ mouseClicked = 0;
+ return true;
+ }
+
+ // allow console bind to work
+ string con_keys;
+ float keys;
+ con_keys = findkeysforcommand("toggleconsole", 0);
+ keys = tokenize(con_keys); // findkeysforcommand returns data for this
+
+ bool hit_con_bind = false;
+ int i;
+ for (i = 0; i < keys; ++i)
+ {
+ if(nPrimary == stof(argv(i)))
+ hit_con_bind = true;
+ }
+
+ if(bInputType == 0) {
+ if(nPrimary == K_ALT) hudShiftState |= S_ALT;
+ if(nPrimary == K_CTRL) hudShiftState |= S_CTRL;
+ if(nPrimary == K_SHIFT) hudShiftState |= S_SHIFT;
+ }
+ else if(bInputType == 1) {
+ if(nPrimary == K_ALT) hudShiftState -= (hudShiftState & S_ALT);
+ if(nPrimary == K_CTRL) hudShiftState -= (hudShiftState & S_CTRL);
+ if(nPrimary == K_SHIFT) hudShiftState -= (hudShiftState & S_SHIFT);
+ }
+
+ if(nPrimary == K_CTRL)
+ {
+ if (bInputType == 1) //ctrl has been released
+ {
+ if (tab_panel)
+ {
+ //switch to selected panel
+ highlightedPanel = tab_panel;
+ highlightedAction = 0;
+ HUD_Panel_FirstInDrawQ(highlightedPanel.panel_id);
+ }
+ tab_panel = world;
+ reset_tab_panels();
+ }
+ }
+
+ if(nPrimary == K_MOUSE1)
+ {
+ if(bInputType == 0) // key pressed
+ mouseClicked |= S_MOUSE1;
+ else if(bInputType == 1) // key released
+ mouseClicked -= (mouseClicked & S_MOUSE1);
+ }
+ else if(nPrimary == K_MOUSE2)
+ {
+ if(bInputType == 0) // key pressed
+ mouseClicked |= S_MOUSE2;
+ else if(bInputType == 1) // key released
+ mouseClicked -= (mouseClicked & S_MOUSE2);
+ }
+ else if(nPrimary == K_ESCAPE)
+ {
+ if (bInputType == 1)
+ return true;
+ menu_enabled = 1;
+ localcmd("menu_showhudexit\n");
+ }
+ else if(nPrimary == K_BACKSPACE && hudShiftState & S_CTRL)
+ {
+ if (bInputType == 1)
+ return true;
+ if (!menu_enabled)
+ cvar_set("_hud_configure", "0");
+ }
+ else if(nPrimary == K_TAB && hudShiftState & S_CTRL) // switch panel
+ {
+ if (bInputType == 1 || mouseClicked)
+ return true;
+
+ // FIXME minor bug: if a panel is highlighted, has the same pos_x and
+ // lays in the same level of another panel then the next consecutive
+ // CTRL TAB presses will reselect once more the highlighted panel
+
+ entity starting_panel;
+ entity old_tab_panel = tab_panel;
+ if (!tab_panel) //first press of TAB
+ {
+ if (highlightedPanel)
+ {
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize();
+ }
+ else
+ panel_pos = '0 0 0';
+ starting_panel = highlightedPanel;
+ tab_panel_pos = panel_pos; //to compute level
+ }
+ else
+ {
+ if ( ((!tab_backward) && (hudShiftState & S_SHIFT)) || (tab_backward && !(hudShiftState & S_SHIFT)) ) //tab direction changed?
+ reset_tab_panels();
+ starting_panel = tab_panel;
+ }
+ tab_backward = (hudShiftState & S_SHIFT);
+
+ float k, level = 0, start_posX;
+ vector candidate_pos = '0 0 0';
+ const float LEVELS_NUM = 4;
+ float level_height = vid_conheight / LEVELS_NUM;
+:find_tab_panel
+ level = floor(tab_panel_pos.y / level_height) * level_height; //starting level
+ candidate_pos.x = (!tab_backward) ? vid_conwidth : 0;
+ start_posX = tab_panel_pos.x;
+ tab_panel = world;
+ k=0;
+ while(++k)
+ {
+ for(i = 0; i < hud_panels_COUNT; ++i)
+ {
+ panel = hud_panels_from(i);
+ if(!(panel.panel_configflags & PANEL_CONFIG_MAIN))
+ continue;
+ if (panel == tab_panels[i] || panel == starting_panel)
+ continue;
+ HUD_Panel_UpdatePosSize();
+ if (panel_pos.y >= level && (panel_pos.y - level) < level_height)
+ if ( ( !tab_backward && panel_pos.x >= start_posX && (panel_pos.x < candidate_pos.x || (panel_pos.x == candidate_pos.x && panel_pos.y <= candidate_pos.y)) )
+ || ( tab_backward && panel_pos.x <= start_posX && (panel_pos.x > candidate_pos.x || (panel_pos.x == candidate_pos.x && panel_pos.y >= candidate_pos.y)) ) )
+ {
+ tab_panel = panel;
+ tab_panel_pos = candidate_pos = panel_pos;
+ }
+ }
+ if (tab_panel)
+ break;
+ if (k == LEVELS_NUM) //tab_panel not found
+ {
+ reset_tab_panels();
+ if (!old_tab_panel)
+ {
+ tab_panel = world;
+ return true;
+ }
+ starting_panel = old_tab_panel;
+ old_tab_panel = world;
+ goto find_tab_panel; //u must find tab_panel!
+ }
+ if (!tab_backward)
+ {
+ level = (level + level_height) % vid_conheight;
+ start_posX = 0;
+ candidate_pos.x = vid_conwidth;
+ }
+ else
+ {
+ level = (level - level_height) % vid_conheight;
+ start_posX = vid_conwidth;
+ candidate_pos.x = 0;
+ }
+ }
+
+ tab_panels[tab_panel.panel_id] = tab_panel;
+ }
+ else if(nPrimary == K_SPACE && hudShiftState & S_CTRL) // enable/disable highlighted panel or dock
+ {
+ if (bInputType == 1 || mouseClicked)
+ return true;
+
+ if (highlightedPanel)
+ cvar_set(strcat("hud_panel_", highlightedPanel.panel_name), ftos(!cvar(strcat("hud_panel_", highlightedPanel.panel_name))));
+ else
+ cvar_set(strcat("hud_dock"), (autocvar_hud_dock == "") ? "dock" : "");
+ }
+ else if(nPrimary == 'c' && hudShiftState & S_CTRL) // copy highlighted panel size
+ {
+ if (bInputType == 1 || mouseClicked)
+ return true;
+
+ if (highlightedPanel)
+ {
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize();
+ panel_size_copied = panel_size;
+ }
+ }
+ else if(nPrimary == 'v' && hudShiftState & S_CTRL) // past copied size on the highlighted panel
+ {
+ if (bInputType == 1 || mouseClicked)
+ return true;
+
+ if (panel_size_copied == '0 0 0' || !highlightedPanel)
+ return true;
+
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize();
+
+ // reduce size if it'd go beyond screen boundaries
+ vector tmp_size = panel_size_copied;
+ if (panel_pos.x + panel_size_copied.x > vid_conwidth)
+ tmp_size.x = vid_conwidth - panel_pos.x;
+ if (panel_pos.y + panel_size_copied.y > vid_conheight)
+ tmp_size.y = vid_conheight - panel_pos.y;
+
+ if (panel_size == tmp_size)
+ return true;
+
+ // backup first!
+ panel_pos_backup = panel_pos;
+ panel_size_backup = panel_size;
+ highlightedPanel_backup = highlightedPanel;
+
+ s = strcat(ftos(tmp_size.x/vid_conwidth), " ", ftos(tmp_size.y/vid_conheight));
+ cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
+ }
+ else if(nPrimary == 'z' && hudShiftState & S_CTRL) // undo last action
+ {
+ if (bInputType == 1 || mouseClicked)
+ return true;
+ //restore previous values
+ if (highlightedPanel_backup)
+ {
+ s = strcat(ftos(panel_pos_backup.x/vid_conwidth), " ", ftos(panel_pos_backup.y/vid_conheight));
+ cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_pos"), s);
+ s = strcat(ftos(panel_size_backup.x/vid_conwidth), " ", ftos(panel_size_backup.y/vid_conheight));
+ cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_size"), s);
+ highlightedPanel_backup = world;
+ }
+ }
+ else if(nPrimary == 's' && hudShiftState & S_CTRL) // save config
+ {
+ if (bInputType == 1 || mouseClicked)
+ return true;
+ localcmd("hud save myconfig\n");
+ }
+ else if(nPrimary == K_UPARROW || nPrimary == K_DOWNARROW || nPrimary == K_LEFTARROW || nPrimary == K_RIGHTARROW)
+ {
+ if (bInputType == 1)
+ {
+ pressed_key_time = 0;
+ return true;
+ }
+ else if (pressed_key_time == 0)
+ pressed_key_time = time;
+
+ if (!mouseClicked)
+ HUD_Panel_Arrow_Action(nPrimary); //move or resize panel
+ }
+ else if(nPrimary == K_ENTER || nPrimary == K_SPACE || nPrimary == K_KP_ENTER)
+ {
+ if (bInputType == 1)
+ return true;
+ if (highlightedPanel)
+ HUD_Panel_EnableMenu();
+ }
+ else if(hit_con_bind || nPrimary == K_PAUSE)
+ return false;
+
+ return true;
+}
+
+float HUD_Panel_Check_Mouse_Pos(float allow_move)
+{
+ int i, j = 0;
+ while(j < hud_panels_COUNT)
+ {
+ i = panel_order[j];
+ j += 1;
+
+ panel = hud_panels_from(i);
+ if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
+ HUD_Panel_UpdatePosSize();
+
+ float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
+
+ // move
+ if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
+ {
+ return 1;
+ }
+ // resize from topleft border
+ else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
+ {
+ return 2;
+ }
+ // resize from topright border
+ else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
+ {
+ return 3;
+ }
+ // resize from bottomleft border
+ else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
+ {
+ return 3;
+ }
+ // resize from bottomright border
+ else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
+ {
+ return 2;
+ }
+ }
+ return 0;
+}
+
+// move a panel to the beginning of the panel order array (which means it gets drawn last, on top of everything else)
+void HUD_Panel_FirstInDrawQ(float id)
+{
+ int i;
+ int place = -1;
+ // find out where in the array our current id is, save into place
+ for(i = 0; i < hud_panels_COUNT; ++i)
+ {
+ if(panel_order[i] == id)
+ {
+ place = i;
+ break;
+ }
+ }
+ // place last if we didn't find a place for it yet (probably new panel, or screwed up cvar)
+ if(place == -1)
+ place = hud_panels_COUNT - 1;
+
+ // move all ids up by one step in the array until "place"
+ for(i = place; i > 0; --i)
+ {
+ panel_order[i] = panel_order[i-1];
+ }
+ // now save the new top id
+ panel_order[0] = id;
+
+ // let's save them into the cvar by some strcat trickery
+ string s = "";
+ for(i = 0; i < hud_panels_COUNT; ++i)
+ {
+ s = strcat(s, ftos(panel_order[i]), " ");
+ }
+ cvar_set("_hud_panelorder", s);
+ if(hud_panelorder_prev)
+ strunzone(hud_panelorder_prev);
+ hud_panelorder_prev = strzone(autocvar__hud_panelorder); // prevent HUD_Main from doing useless update, we already updated here
+}
+
+void HUD_Panel_Highlight(float allow_move)
+{
+ int i, j = 0;
+
+ while(j < hud_panels_COUNT)
+ {
+ i = panel_order[j];
+ j += 1;
+
+ panel = hud_panels_from(i);
+ if(!(panel.panel_configflags & PANEL_CONFIG_MAIN))
+ continue;
+ HUD_Panel_UpdatePosSize();
+
+ float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
+
+ // move
+ if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
+ {
+ highlightedPanel = hud_panels_from(i);
+ HUD_Panel_FirstInDrawQ(i);
+ highlightedAction = 1;
+ panel_click_distance = mousepos - panel_pos;
+ return;
+ }
+ // resize from topleft border
+ else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
+ {
+ highlightedPanel = hud_panels_from(i);
+ HUD_Panel_FirstInDrawQ(i);
+ highlightedAction = 2;
+ resizeCorner = 1;
+ panel_click_distance = mousepos - panel_pos;
+ panel_click_resizeorigin = panel_pos + panel_size;
+ return;
+ }
+ // resize from topright border
+ else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
+ {
+ highlightedPanel = hud_panels_from(i);
+ HUD_Panel_FirstInDrawQ(i);
+ highlightedAction = 2;
+ resizeCorner = 2;
+ panel_click_distance.x = panel_size.x - mousepos.x + panel_pos.x;
+ panel_click_distance.y = mousepos.y - panel_pos.y;
+ panel_click_resizeorigin = panel_pos + eY * panel_size.y;
+ return;
+ }
+ // resize from bottomleft border
+ else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
+ {
+ highlightedPanel = hud_panels_from(i);
+ HUD_Panel_FirstInDrawQ(i);
+ highlightedAction = 2;
+ resizeCorner = 3;
+ panel_click_distance.x = mousepos.x - panel_pos.x;
+ panel_click_distance.y = panel_size.y - mousepos.y + panel_pos.y;
+ panel_click_resizeorigin = panel_pos + eX * panel_size.x;
+ return;
+ }
+ // resize from bottomright border
+ else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
+ {
+ highlightedPanel = hud_panels_from(i);
+ HUD_Panel_FirstInDrawQ(i);
+ highlightedAction = 2;
+ resizeCorner = 4;
+ panel_click_distance = panel_size - mousepos + panel_pos;
+ panel_click_resizeorigin = panel_pos;
+ return;
+ }
+ }
+ highlightedPanel = world;
+ highlightedAction = 0;
+}
+
+void HUD_Panel_EnableMenu()
+{
+ menu_enabled = 2;
+ localcmd("menu_showhudoptions ", highlightedPanel.panel_name, "\n");
+}
+float mouse_over_panel;
+void HUD_Panel_Mouse()
+{
+ if(autocvar__menu_alpha == 1)
+ return;
+
+ if (!autocvar_hud_cursormode)
+ {
+ mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
+
+ mousepos.x = bound(0, mousepos.x, vid_conwidth);
+ mousepos.y = bound(0, mousepos.y, vid_conheight);
+ }
+
+ if(mouseClicked)
+ {
+ if(prevMouseClicked == 0)
+ {
+ if (tab_panel)
+ {
+ //stop ctrl-tab selection
+ tab_panel = world;
+ reset_tab_panels();
+ }
+ HUD_Panel_Highlight(mouseClicked & S_MOUSE1); // sets highlightedPanel, highlightedAction, panel_click_distance, panel_click_resizeorigin
+ // and calls HUD_Panel_UpdatePosSize() for the highlighted panel
+ if (highlightedPanel)
+ {
+ highlightedPanel_initial_pos = panel_pos;
+ highlightedPanel_initial_size = panel_size;
+ }
+ // doubleclick check
+ if ((mouseClicked & S_MOUSE1) && time - prevMouseClickedTime < 0.4 && highlightedPanel && prevMouseClickedPos == mousepos)
+ {
+ mouseClicked = 0; // to prevent spam, I guess.
+ HUD_Panel_EnableMenu();
+ }
+ else
+ {
+ if (mouseClicked & S_MOUSE1)
+ {
+ prevMouseClickedTime = time;
+ prevMouseClickedPos = mousepos;
+ }
+ mouse_over_panel = HUD_Panel_Check_Mouse_Pos(mouseClicked & S_MOUSE1);
+ }
+ }
+ else
+ {
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize();
+ }
+
+ if (highlightedPanel)
+ {
+ drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
+ if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
+ {
+ hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
+ // backup!
+ panel_pos_backup = highlightedPanel_initial_pos;
+ panel_size_backup = highlightedPanel_initial_size;
+ highlightedPanel_backup = highlightedPanel;
+ }
+ else
+ // in case the clicked panel is inside another panel and we aren't
+ // moving it, avoid the immediate "fix" of its position/size
+ // (often unwanted and hateful) by disabling collisions check
+ hud_configure_checkcollisions = false;
+ }
+
+ if(highlightedAction == 1)
+ HUD_Panel_SetPos(mousepos - panel_click_distance);
+ else if(highlightedAction == 2)
+ {
+ vector mySize = '0 0 0';
+ if(resizeCorner == 1) {
+ mySize.x = panel_click_resizeorigin.x - (mousepos.x - panel_click_distance.x);
+ mySize.y = panel_click_resizeorigin.y - (mousepos.y - panel_click_distance.y);
+ } else if(resizeCorner == 2) {
+ mySize.x = mousepos.x + panel_click_distance.x - panel_click_resizeorigin.x;
+ mySize.y = panel_click_distance.y + panel_click_resizeorigin.y - mousepos.y;
+ } else if(resizeCorner == 3) {
+ mySize.x = panel_click_resizeorigin.x + panel_click_distance.x - mousepos.x;
+ mySize.y = mousepos.y + panel_click_distance.y - panel_click_resizeorigin.y;
+ } else { // resizeCorner == 4
+ mySize.x = mousepos.x - (panel_click_resizeorigin.x - panel_click_distance.x);
+ mySize.y = mousepos.y - (panel_click_resizeorigin.y - panel_click_distance.y);
+ }
+ HUD_Panel_SetPosSize(mySize);
+ }
+ }
+ else
+ {
+ if(prevMouseClicked)
+ highlightedAction = 0;
+ if(menu_enabled == 2)
+ mouse_over_panel = 0;
+ else
+ mouse_over_panel = HUD_Panel_Check_Mouse_Pos(true);
+ if (mouse_over_panel && !tab_panel)
+ drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
+ }
+ // draw cursor after performing move/resize to have the panel pos/size updated before mouse_over_panel
+ const vector cursorsize = '32 32 0';
+ float cursor_alpha = 1 - autocvar__menu_alpha;
+
+ if(!mouse_over_panel)
+ drawpic(mousepos, strcat("gfx/menu/", autocvar_menu_skin, "/cursor.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
+ else if(mouse_over_panel == 1)
+ drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_move.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
+ else if(mouse_over_panel == 2)
+ drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_resize.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
+ else
+ drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_resize2.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
+
+ prevMouseClicked = mouseClicked;
+}
+void HUD_Configure_DrawGrid()
+{
+ float i;
+ if(autocvar_hud_configure_grid && autocvar_hud_configure_grid_alpha)
+ {
+ hud_configure_gridSize.x = bound(0.005, cvar("hud_configure_grid_xsize"), 0.2);
+ hud_configure_gridSize.y = bound(0.005, cvar("hud_configure_grid_ysize"), 0.2);
+ hud_configure_realGridSize.x = hud_configure_gridSize.x * vid_conwidth;
+ hud_configure_realGridSize.y = hud_configure_gridSize.y * vid_conheight;
+ vector s;
+ // x-axis
+ s = eX + eY * vid_conheight;
+ for(i = 1; i < 1/hud_configure_gridSize.x; ++i)
+ drawfill(eX * i * hud_configure_realGridSize.x, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
+ // y-axis
+ s = eY + eX * vid_conwidth;
+ for(i = 1; i < 1/hud_configure_gridSize.y; ++i)
+ drawfill(eY * i * hud_configure_realGridSize.y, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
+ }
+}
+
+float _menu_alpha_prev;
+void HUD_Configure_Frame()
+{
+ int i;
+ if(autocvar__hud_configure)
+ {
+ if(isdemo() || intermission == 2)
+ {
+ HUD_Configure_Exit_Force();
+ return;
+ }
+
+ if(!hud_configure_prev)
+ {
+ if(autocvar_hud_cursormode)
+ setcursormode(1);
+ hudShiftState = 0;
+ for(i = hud_panels_COUNT - 1; i >= 0; --i)
+ hud_panels_from(panel_order[i]).update_time = time;
+ }
+
+ // NOTE this check is necessary because _menu_alpha isn't updated the frame the menu gets enabled
+ if(autocvar__menu_alpha != _menu_alpha_prev)
+ {
+ if(autocvar__menu_alpha == 0)
+ menu_enabled = 0;
+ _menu_alpha_prev = autocvar__menu_alpha;
+ }
+
+ HUD_Configure_DrawGrid();
+ }
+ else if(hud_configure_prev)
+ {
+ if(menu_enabled)
+ menu_enabled = 0;
+ if(autocvar_hud_cursormode)
+ setcursormode(0);
+ }
+}
+
+const float hlBorderSize = 2;
+const string hlBorder = "gfx/hud/default/border_highlighted";
+const string hlBorder2 = "gfx/hud/default/border_highlighted2";
+void HUD_Panel_HlBorder(float myBorder, vector color, float theAlpha)
+{
+ drawfill(panel_pos - '1 1 0' * myBorder, panel_size + '2 2 0' * myBorder, '0 0.5 1', .5 * theAlpha, DRAWFLAG_NORMAL);
+ drawpic_tiled(panel_pos - '1 1 0' * myBorder, hlBorder, '8 1 0' * hlBorderSize, eX * (panel_size.x + 2 * myBorder) + eY * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
+ drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * (panel_size.y + 2 * myBorder - hlBorderSize), hlBorder, '8 1 0' * hlBorderSize, eX * (panel_size.x + 2 * myBorder) + eY * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
+ drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * hlBorderSize, hlBorder2, '1 8 0' * hlBorderSize, eY * (panel_size.y + 2 * myBorder - 2 * hlBorderSize) + eX * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
+ drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * hlBorderSize + eX * (panel_size.x + 2 * myBorder - hlBorderSize), hlBorder2, '1 8 0' * hlBorderSize, eY * (panel_size.y + 2 * myBorder - 2 * hlBorderSize) + eX * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
+}
+
+void HUD_Configure_PostDraw()
+{
+ if(autocvar__hud_configure)
+ {
+ if(tab_panel)
+ {
+ panel = tab_panel;
+ HUD_Panel_UpdatePosSize();
+ drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .2, DRAWFLAG_NORMAL);
+ }
+ if(highlightedPanel)
+ {
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize();
+ HUD_Panel_HlBorder(panel_bg_border * hlBorderSize, '0 0.5 1', 0.4 * (1 - autocvar__menu_alpha));
+ }
+ }
+}
--- /dev/null
+#ifndef CLIENT_HUD_CONFIG_H
+#define CLIENT_HUD_CONFIG_H
+
+const int S_MOUSE1 = 1;
+const int S_MOUSE2 = 2;
+const int S_MOUSE3 = 4;
+int mouseClicked;
+int prevMouseClicked; // previous state
+float prevMouseClickedTime; // time during previous left mouse click, to check for doubleclicks
+vector prevMouseClickedPos; // pos during previous left mouse click, to check for doubleclicks
+
+void HUD_Panel_ExportCfg(string cfgname);
+
+void HUD_Panel_Mouse();
+
+void HUD_Configure_Frame();
+
+void HUD_Configure_PostDraw();
+
+float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary);
+
+#endif
--- /dev/null
+// Ammo (#1)
+
+void DrawNadeProgressBar(vector myPos, vector mySize, float progress, vector color)
+{
+ HUD_Panel_DrawProgressBar(
+ myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x,
+ mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x,
+ autocvar_hud_panel_ammo_progressbar_name,
+ progress, 0, 0, color,
+ autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time); // TODO: mutator
+
+void DrawAmmoItem(vector myPos, vector mySize, .int ammoType, bool isCurrent, bool isInfinite)
+{
+ if(ammoType == ammo_none)
+ return;
+
+ // Initialize variables
+
+ int ammo;
+ if(autocvar__hud_configure)
+ {
+ isCurrent = (ammoType == ammo_rockets); // Rockets always current
+ ammo = 60;
+ }
+ else
+ ammo = getstati(GetAmmoStat(ammoType));
+
+ if(!isCurrent)
+ {
+ float scale = bound(0, autocvar_hud_panel_ammo_noncurrent_scale, 1);
+ myPos = myPos + (mySize - mySize * scale) * 0.5;
+ mySize = mySize * scale;
+ }
+
+ vector iconPos, textPos;
+ if(autocvar_hud_panel_ammo_iconalign)
+ {
+ iconPos = myPos + eX * 2 * mySize.y;
+ textPos = myPos;
+ }
+ else
+ {
+ iconPos = myPos;
+ textPos = myPos + eX * mySize.y;
+ }
+
+ bool isShadowed = (ammo <= 0 && !isCurrent && !isInfinite);
+
+ vector iconColor = isShadowed ? '0 0 0' : '1 1 1';
+ vector textColor;
+ if(isInfinite)
+ textColor = '0.2 0.95 0';
+ else if(isShadowed)
+ textColor = '0 0 0';
+ else if(ammo < 10)
+ textColor = '0.8 0.04 0';
+ else
+ textColor = '1 1 1';
+
+ float alpha;
+ if(isCurrent)
+ alpha = panel_fg_alpha;
+ else if(isShadowed)
+ alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_ammo_noncurrent_alpha, 1) * 0.5;
+ else
+ alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_ammo_noncurrent_alpha, 1);
+
+ string text = isInfinite ? "\xE2\x88\x9E" : ftos(ammo); // Use infinity symbol (U+221E)
+
+ // Draw item
+
+ if(isCurrent)
+ drawpic_aspect_skin(myPos, "ammo_current_bg", mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ if(ammo > 0 && autocvar_hud_panel_ammo_progressbar)
+ HUD_Panel_DrawProgressBar(myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x, mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x, autocvar_hud_panel_ammo_progressbar_name, ammo/autocvar_hud_panel_ammo_maxammo, 0, 0, textColor, autocvar_hud_progressbar_alpha * alpha, DRAWFLAG_NORMAL);
+
+ if(autocvar_hud_panel_ammo_text)
+ drawstring_aspect(textPos, text, eX * (2/3) * mySize.x + eY * mySize.y, textColor, alpha, DRAWFLAG_NORMAL);
+
+ drawpic_aspect_skin(iconPos, GetAmmoPicture(ammoType), '1 1 0' * mySize.y, iconColor, alpha, DRAWFLAG_NORMAL);
+}
+
+int nade_prevstatus;
+int nade_prevframe;
+float nade_statuschange_time;
+
+void HUD_Ammo()
+{
+ if(hud != HUD_NORMAL) return;
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_ammo) return;
+ if(spectatee_status == -1) return;
+ }
+
+ HUD_Panel_UpdateCvars();
+
+ draw_beginBoldFont();
+
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(1);
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ int rows = 0, columns, row, column;
+ float nade_cnt = getstatf(STAT_NADE_BONUS), nade_score = getstatf(STAT_NADE_BONUS_SCORE);
+ bool draw_nades = (nade_cnt > 0 || nade_score > 0);
+ float nade_statuschange_elapsedtime;
+ int total_ammo_count;
+
+ vector ammo_size;
+ if (autocvar_hud_panel_ammo_onlycurrent)
+ total_ammo_count = 1;
+ else
+ total_ammo_count = AMMO_COUNT;
+
+ if(draw_nades)
+ {
+ ++total_ammo_count;
+ if (nade_cnt != nade_prevframe)
+ {
+ nade_statuschange_time = time;
+ nade_prevstatus = nade_prevframe;
+ nade_prevframe = nade_cnt;
+ }
+ }
+ else
+ nade_prevstatus = nade_prevframe = nade_statuschange_time = 0;
+
+ rows = HUD_GetRowCount(total_ammo_count, mySize, 3);
+ columns = ceil((total_ammo_count)/rows);
+ ammo_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+
+ vector offset = '0 0 0'; // fteqcc sucks
+ float newSize;
+ if(ammo_size.x/ammo_size.y > 3)
+ {
+ newSize = 3 * ammo_size.y;
+ offset.x = ammo_size.x - newSize;
+ pos.x += offset.x/2;
+ ammo_size.x = newSize;
+ }
+ else
+ {
+ newSize = 1/3 * ammo_size.x;
+ offset.y = ammo_size.y - newSize;
+ pos.y += offset.y/2;
+ ammo_size.y = newSize;
+ }
+
+ int i;
+ bool infinite_ammo = (getstati(STAT_ITEMS, 0, 24) & IT_UNLIMITED_WEAPON_AMMO);
+ row = column = 0;
+ if(autocvar_hud_panel_ammo_onlycurrent)
+ {
+ if(autocvar__hud_configure)
+ {
+ DrawAmmoItem(pos, ammo_size, ammo_rockets, true, false);
+ }
+ else
+ {
+ DrawAmmoItem(
+ pos,
+ ammo_size,
+ (get_weaponinfo(switchweapon)).ammo_field,
+ true,
+ infinite_ammo
+ );
+ }
+
+ ++row;
+ if(row >= rows)
+ {
+ row = 0;
+ column = column + 1;
+ }
+ }
+ else
+ {
+ .int ammotype;
+ row = column = 0;
+ for(i = 0; i < AMMO_COUNT; ++i)
+ {
+ ammotype = GetAmmoFieldFromNum(i);
+ DrawAmmoItem(
+ pos + eX * column * (ammo_size.x + offset.x) + eY * row * (ammo_size.y + offset.y),
+ ammo_size,
+ ammotype,
+ ((get_weaponinfo(switchweapon)).ammo_field == ammotype),
+ infinite_ammo
+ );
+
+ ++row;
+ if(row >= rows)
+ {
+ row = 0;
+ column = column + 1;
+ }
+ }
+ }
+
+ if (draw_nades)
+ {
+ nade_statuschange_elapsedtime = time - nade_statuschange_time;
+
+ float f = bound(0, nade_statuschange_elapsedtime*2, 1);
+
+ DrawAmmoNades(pos + eX * column * (ammo_size.x + offset.x) + eY * row * (ammo_size.y + offset.y), ammo_size, nade_prevstatus < nade_cnt && nade_cnt != 0 && f < 1, f);
+ }
+
+ draw_endBoldFont();
+}
--- /dev/null
+// CenterPrint (#16)
+
+const int CENTERPRINT_MAX_MSGS = 10;
+const int CENTERPRINT_MAX_ENTRIES = 50;
+const float CENTERPRINT_SPACING = 0.7;
+int cpm_index;
+string centerprint_messages[CENTERPRINT_MAX_MSGS];
+int centerprint_msgID[CENTERPRINT_MAX_MSGS];
+float centerprint_time[CENTERPRINT_MAX_MSGS];
+float centerprint_expire_time[CENTERPRINT_MAX_MSGS];
+int centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
+bool centerprint_showing;
+
+void centerprint_generic(int new_id, string strMessage, float duration, int countdown_num)
+{
+ //printf("centerprint_generic(%d, '%s^7', %d, %d);\n", new_id, strMessage, duration, countdown_num);
+ int i, j;
+
+ if(strMessage == "" && new_id == 0)
+ return;
+
+ // strip trailing newlines
+ j = strlen(strMessage) - 1;
+ while(substring(strMessage, j, 1) == "\n" && j >= 0)
+ --j;
+ if (j < strlen(strMessage) - 1)
+ strMessage = substring(strMessage, 0, j + 1);
+
+ if(strMessage == "" && new_id == 0)
+ return;
+
+ // strip leading newlines
+ j = 0;
+ while(substring(strMessage, j, 1) == "\n" && j < strlen(strMessage))
+ ++j;
+ if (j > 0)
+ strMessage = substring(strMessage, j, strlen(strMessage) - j);
+
+ if(strMessage == "" && new_id == 0)
+ return;
+
+ if (!centerprint_showing)
+ centerprint_showing = true;
+
+ for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
+ {
+ if (j == CENTERPRINT_MAX_MSGS)
+ j = 0;
+ if (new_id && new_id == centerprint_msgID[j])
+ {
+ if (strMessage == "" && centerprint_messages[j] != "" && centerprint_countdown_num[j] == 0)
+ {
+ // fade out the current msg (duration and countdown_num are ignored)
+ centerprint_time[j] = min(5, autocvar_hud_panel_centerprint_fade_out);
+ if (centerprint_expire_time[j] > time + min(5, autocvar_hud_panel_centerprint_fade_out) || centerprint_expire_time[j] < time)
+ centerprint_expire_time[j] = time + min(5, autocvar_hud_panel_centerprint_fade_out);
+ return;
+ }
+ break; // found a msg with the same id, at position j
+ }
+ }
+
+ if (i == CENTERPRINT_MAX_MSGS)
+ {
+ // a msg with the same id was not found, add the msg at the next position
+ --cpm_index;
+ if (cpm_index == -1)
+ cpm_index = CENTERPRINT_MAX_MSGS - 1;
+ j = cpm_index;
+ }
+ if(centerprint_messages[j])
+ strunzone(centerprint_messages[j]);
+ centerprint_messages[j] = strzone(strMessage);
+ centerprint_msgID[j] = new_id;
+ if (duration < 0)
+ {
+ centerprint_time[j] = -1;
+ centerprint_expire_time[j] = time;
+ }
+ else
+ {
+ if(duration == 0)
+ duration = max(1, autocvar_hud_panel_centerprint_time);
+ centerprint_time[j] = duration;
+ centerprint_expire_time[j] = time + duration;
+ }
+ centerprint_countdown_num[j] = countdown_num;
+}
+
+void centerprint_hud(string strMessage)
+{
+ centerprint_generic(0, strMessage, autocvar_hud_panel_centerprint_time, 0);
+}
+
+void reset_centerprint_messages()
+{
+ int i;
+ for (i=0; i<CENTERPRINT_MAX_MSGS; ++i)
+ {
+ centerprint_expire_time[i] = 0;
+ centerprint_time[i] = 1;
+ centerprint_msgID[i] = 0;
+ if(centerprint_messages[i])
+ strunzone(centerprint_messages[i]);
+ centerprint_messages[i] = string_null;
+ }
+}
+float hud_configure_cp_generation_time;
+void HUD_CenterPrint ()
+{
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_centerprint) return;
+
+ if(hud_configure_prev)
+ reset_centerprint_messages();
+ }
+ else
+ {
+ if(!hud_configure_prev)
+ reset_centerprint_messages();
+ if (time > hud_configure_cp_generation_time)
+ {
+ if(highlightedPanel == HUD_PANEL(CENTERPRINT))
+ {
+ float r;
+ r = random();
+ if (r > 0.8)
+ centerprint_generic(floor(r*1000), strcat(sprintf("^3Countdown message at time %s", seconds_tostring(time)), ", seconds left: ^COUNT"), 1, 10);
+ else if (r > 0.55)
+ centerprint_generic(0, sprintf("^1Multiline message at time %s that\n^1lasts longer than normal", seconds_tostring(time)), 20, 0);
+ else
+ centerprint_hud(sprintf("Message at time %s", seconds_tostring(time)));
+ hud_configure_cp_generation_time = time + 1 + random()*4;
+ }
+ else
+ {
+ centerprint_generic(0, sprintf("Centerprint message", seconds_tostring(time)), 10, 0);
+ hud_configure_cp_generation_time = time + 10 - random()*3;
+ }
+ }
+ }
+
+ // this panel fades only when the menu does
+ float hud_fade_alpha_save = 0;
+ if(scoreboard_fade_alpha)
+ {
+ hud_fade_alpha_save = hud_fade_alpha;
+ hud_fade_alpha = 1 - autocvar__menu_alpha;
+ }
+ HUD_Panel_UpdateCvars();
+
+ if ( HUD_Radar_Clickable() )
+ {
+ if (hud_panel_radar_bottom >= 0.96 * vid_conheight)
+ return;
+
+ panel_pos = eY * hud_panel_radar_bottom + eX * 0.5 * (vid_conwidth - panel_size_x);
+ panel_size_y = min(panel_size_y, vid_conheight - hud_panel_radar_bottom);
+ }
+ else if(scoreboard_fade_alpha)
+ {
+ hud_fade_alpha = hud_fade_alpha_save;
+
+ // move the panel below the scoreboard
+ if (scoreboard_bottom >= 0.96 * vid_conheight)
+ return;
+ vector target_pos;
+
+ target_pos = eY * scoreboard_bottom + eX * 0.5 * (vid_conwidth - panel_size.x);
+
+ if(target_pos.y > panel_pos.y)
+ {
+ panel_pos = panel_pos + (target_pos - panel_pos) * sqrt(scoreboard_fade_alpha);
+ panel_size.y = min(panel_size.y, vid_conheight - scoreboard_bottom);
+ }
+ }
+
+ HUD_Panel_DrawBg(1);
+
+ if (!centerprint_showing)
+ return;
+
+ if(panel_bg_padding)
+ {
+ panel_pos += '1 1 0' * panel_bg_padding;
+ panel_size -= '2 2 0' * panel_bg_padding;
+ }
+
+ int entries;
+ float height;
+ vector fontsize;
+ // entries = bound(1, floor(CENTERPRINT_MAX_ENTRIES * 4 * panel_size_y/panel_size_x), CENTERPRINT_MAX_ENTRIES);
+ // height = panel_size_y/entries;
+ // fontsize = '1 1 0' * height;
+ height = vid_conheight/50 * autocvar_hud_panel_centerprint_fontscale;
+ fontsize = '1 1 0' * height;
+ entries = bound(1, floor(panel_size.y/height), CENTERPRINT_MAX_ENTRIES);
+
+ int i, j, k, n, g;
+ float a, sz, align, current_msg_posY = 0, msg_size;
+ vector pos;
+ string ts;
+ bool all_messages_expired = true;
+
+ pos = panel_pos;
+ if (autocvar_hud_panel_centerprint_flip)
+ pos.y += panel_size.y;
+ align = bound(0, autocvar_hud_panel_centerprint_align, 1);
+ for (g=0, i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
+ {
+ if (j == CENTERPRINT_MAX_MSGS)
+ j = 0;
+ if (centerprint_expire_time[j] <= time)
+ {
+ if (centerprint_countdown_num[j] && centerprint_time[j] > 0)
+ {
+ centerprint_countdown_num[j] = centerprint_countdown_num[j] - 1;
+ if (centerprint_countdown_num[j] == 0)
+ continue;
+ centerprint_expire_time[j] = centerprint_expire_time[j] + centerprint_time[j];
+ }
+ else if(centerprint_time[j] != -1)
+ continue;
+ }
+
+ all_messages_expired = false;
+
+ // fade the centerprint_hud in/out
+ if(centerprint_time[j] < 0) // Expired but forced. Expire time is the fade-in time.
+ a = (time - centerprint_expire_time[j]) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
+ else if(centerprint_expire_time[j] - autocvar_hud_panel_centerprint_fade_out > time) // Regularily printed. Not fading out yet.
+ a = (time - (centerprint_expire_time[j] - centerprint_time[j])) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
+ else // Expiring soon, so fade it out.
+ a = (centerprint_expire_time[j] - time) / max(0.0001, autocvar_hud_panel_centerprint_fade_out);
+
+ // while counting down show it anyway in order to hold the current message position
+ if (a <= 0.5/255.0 && centerprint_countdown_num[j] == 0) // Guaranteed invisible - don't show.
+ continue;
+ if (a > 1)
+ a = 1;
+
+ // set the size from fading in/out before subsequent fading
+ sz = autocvar_hud_panel_centerprint_fade_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_minfontsize);
+
+ // also fade it based on positioning
+ if(autocvar_hud_panel_centerprint_fade_subsequent)
+ {
+ a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1); // pass one: all messages after the first have half theAlpha
+ a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1); // pass two: after that, gradually lower theAlpha even more for each message
+ }
+ a *= panel_fg_alpha;
+
+ // finally set the size based on the new theAlpha from subsequent fading
+ sz = sz * (autocvar_hud_panel_centerprint_fade_subsequent_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_subsequent_minfontsize));
+ drawfontscale = sz * '1 1 0';
+
+ if (centerprint_countdown_num[j])
+ n = tokenizebyseparator(strreplace("^COUNT", count_seconds(centerprint_countdown_num[j]), centerprint_messages[j]), "\n");
+ else
+ n = tokenizebyseparator(centerprint_messages[j], "\n");
+
+ if (autocvar_hud_panel_centerprint_flip)
+ {
+ // check if the message can be entirely shown
+ for(k = 0; k < n; ++k)
+ {
+ getWrappedLine_remaining = argv(k);
+ while(getWrappedLine_remaining)
+ {
+ ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
+ if (ts != "")
+ pos.y -= fontsize.y;
+ else
+ pos.y -= fontsize.y * CENTERPRINT_SPACING/2;
+ }
+ }
+ current_msg_posY = pos.y; // save starting pos (first line) of the current message
+ }
+
+ msg_size = pos.y;
+ for(k = 0; k < n; ++k)
+ {
+ getWrappedLine_remaining = argv(k);
+ while(getWrappedLine_remaining)
+ {
+ ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
+ if (ts != "")
+ {
+ if (align)
+ pos.x = panel_pos.x + (panel_size.x - stringwidth(ts, true, fontsize)) * align;
+ if (a > 0.5/255.0) // Otherwise guaranteed invisible - don't show. This is checked a second time after some multiplications with other factors were done so temporary changes of these cannot cause flicker.
+ drawcolorcodedstring(pos + eY * 0.5 * (1 - sz) * fontsize.y, ts, fontsize, a, DRAWFLAG_NORMAL);
+ pos.y += fontsize.y;
+ }
+ else
+ pos.y += fontsize.y * CENTERPRINT_SPACING/2;
+ }
+ }
+
+ ++g; // move next position number up
+
+ msg_size = pos.y - msg_size;
+ if (autocvar_hud_panel_centerprint_flip)
+ {
+ pos.y = current_msg_posY - CENTERPRINT_SPACING * fontsize.y;
+ if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
+ pos.y += (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
+
+ if (pos.y < panel_pos.y) // check if the next message can be shown
+ {
+ drawfontscale = '1 1 0';
+ return;
+ }
+ }
+ else
+ {
+ pos.y += CENTERPRINT_SPACING * fontsize.y;
+ if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
+ pos.y -= (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
+
+ if(pos.y > panel_pos.y + panel_size.y - fontsize.y) // check if the next message can be shown
+ {
+ drawfontscale = '1 1 0';
+ return;
+ }
+ }
+ }
+ drawfontscale = '1 1 0';
+ if (all_messages_expired)
+ {
+ centerprint_showing = false;
+ reset_centerprint_messages();
+ }
+}
--- /dev/null
+/** Handle chat as a panel (#12) */
+void HUD_Chat()
+{
+ if(!autocvar__hud_configure)
+ {
+ if (!autocvar_hud_panel_chat)
+ {
+ if (!autocvar_con_chatrect)
+ cvar_set("con_chatrect", "0");
+ return;
+ }
+ if(autocvar__con_chat_maximized)
+ {
+ if(!hud_draw_maximized) return;
+ }
+ else if(chat_panel_modified)
+ {
+ panel.update_time = time; // forces reload of panel attributes
+ chat_panel_modified = false;
+ }
+ }
+
+ HUD_Panel_UpdateCvars();
+
+ if(intermission == 2)
+ {
+ // reserve some more space to the mapvote panel
+ // by resizing and moving chat panel to the bottom
+ panel_size.y = min(panel_size.y, vid_conheight * 0.2);
+ panel_pos.y = vid_conheight - panel_size.y - panel_bg_border * 2;
+ chat_posy = panel_pos.y;
+ chat_sizey = panel_size.y;
+ }
+ if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
+ {
+ panel_pos.y = panel_bg_border;
+ panel_size.y = vid_conheight - panel_bg_border * 2;
+ if(panel.current_panel_bg == "0") // force a border when maximized
+ {
+ string panel_bg;
+ panel_bg = strcat(hud_skin_path, "/border_default");
+ if(precache_pic(panel_bg) == "")
+ panel_bg = "gfx/hud/default/border_default";
+ if(panel.current_panel_bg)
+ strunzone(panel.current_panel_bg);
+ panel.current_panel_bg = strzone(panel_bg);
+ chat_panel_modified = true;
+ }
+ panel_bg_alpha = max(0.75, panel_bg_alpha); // force an theAlpha of at least 0.75
+ }
+
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(1);
+
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ if (!autocvar_con_chatrect)
+ cvar_set("con_chatrect", "1");
+
+ cvar_set("con_chatrect_x", ftos(pos.x/vid_conwidth));
+ cvar_set("con_chatrect_y", ftos(pos.y/vid_conheight));
+
+ cvar_set("con_chatwidth", ftos(mySize.x/vid_conwidth));
+ cvar_set("con_chat", ftos(floor(mySize.y/autocvar_con_chatsize - 0.5)));
+
+ if(autocvar__hud_configure)
+ {
+ vector chatsize;
+ chatsize = '1 1 0' * autocvar_con_chatsize;
+ cvar_set("con_chatrect_x", "9001"); // over 9000, we'll fake it instead for more control over theAlpha and such
+ float i, a;
+ for(i = 0; i < autocvar_con_chat; ++i)
+ {
+ if(i == autocvar_con_chat - 1)
+ a = panel_fg_alpha;
+ else
+ a = panel_fg_alpha * floor(((i + 1) * 7 + autocvar_con_chattime)/45);
+ drawcolorcodedstring(pos, textShortenToWidth(_("^3Player^7: This is the chat area."), mySize.x, chatsize, stringwidth_colors), chatsize, a, DRAWFLAG_NORMAL);
+ pos.y += chatsize.y;
+ }
+ }
+}
--- /dev/null
+// Engine info panel (#13)
+
+float prevfps;
+float prevfps_time;
+int framecounter;
+
+float frametimeavg;
+float frametimeavg1; // 1 frame ago
+float frametimeavg2; // 2 frames ago
+void HUD_EngineInfo()
+{
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_engineinfo) return;
+ }
+
+ HUD_Panel_UpdateCvars();
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(1);
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ float currentTime = gettime(GETTIME_REALTIME);
+ if(cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage"))
+ {
+ float currentframetime = currentTime - prevfps_time;
+ frametimeavg = (frametimeavg + frametimeavg1 + frametimeavg2 + currentframetime)/4; // average three frametimes into framecounter for slightly more stable fps readings :P
+ frametimeavg2 = frametimeavg1;
+ frametimeavg1 = frametimeavg;
+
+ float weight;
+ weight = cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_new_weight");
+ if(currentframetime > 0.0001) // filter out insane values which sometimes seem to occur and throw off the average? If you are getting 10,000 fps or more, then you don't need a framerate counter.
+ {
+ if(fabs(prevfps - (1/frametimeavg)) > prevfps * cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_instantupdate_change_threshold")) // if there was a big jump in fps, just force prevfps at current (1/currentframetime) to make big updates instant
+ prevfps = (1/currentframetime);
+ prevfps = (1 - weight) * prevfps + weight * (1/frametimeavg); // framecounter just used so there's no need for a new variable, think of it as "frametime average"
+ }
+ prevfps_time = currentTime;
+ }
+ else
+ {
+ framecounter += 1;
+ if(currentTime - prevfps_time > autocvar_hud_panel_engineinfo_framecounter_time)
+ {
+ prevfps = framecounter/(currentTime - prevfps_time);
+ framecounter = 0;
+ prevfps_time = currentTime;
+ }
+ }
+
+ vector color;
+ color = HUD_Get_Num_Color (prevfps, 100);
+ drawstring_aspect(pos, sprintf(_("FPS: %.*f"), autocvar_hud_panel_engineinfo_framecounter_decimals, prevfps), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
--- /dev/null
+/** Health/armor (#3) */
+void HUD_HealthArmor()
+{
+ int armor, health, fuel;
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_healtharmor) return;
+ if(hud != HUD_NORMAL) return;
+ if(spectatee_status == -1) return;
+
+ health = getstati(STAT_HEALTH);
+ if(health <= 0)
+ {
+ prev_health = -1;
+ return;
+ }
+ armor = getstati(STAT_ARMOR);
+
+ // code to check for spectatee_status changes is in Ent_ClientData()
+ // prev_p_health and prev_health can be set to -1 there
+
+ if (prev_p_health == -1)
+ {
+ // no effect
+ health_beforedamage = 0;
+ armor_beforedamage = 0;
+ health_damagetime = 0;
+ armor_damagetime = 0;
+ prev_health = health;
+ prev_armor = armor;
+ old_p_health = health;
+ old_p_armor = armor;
+ prev_p_health = health;
+ prev_p_armor = armor;
+ }
+ else if (prev_health == -1)
+ {
+ //start the load effect
+ health_damagetime = 0;
+ armor_damagetime = 0;
+ prev_health = 0;
+ prev_armor = 0;
+ }
+ fuel = getstati(STAT_FUEL);
+ }
+ else
+ {
+ health = 150;
+ armor = 75;
+ fuel = 20;
+ }
+
+ HUD_Panel_UpdateCvars();
+
+ draw_beginBoldFont();
+
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(1);
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ int baralign = autocvar_hud_panel_healtharmor_baralign;
+ int iconalign = autocvar_hud_panel_healtharmor_iconalign;
+
+ int maxhealth = autocvar_hud_panel_healtharmor_maxhealth;
+ int maxarmor = autocvar_hud_panel_healtharmor_maxarmor;
+ if(autocvar_hud_panel_healtharmor == 2) // combined health and armor display
+ {
+ vector v;
+ v = healtharmor_maxdamage(health, armor, armorblockpercent, DEATH_WEAPON.m_id);
+
+ float x;
+ x = floor(v.x + 1);
+
+ float maxtotal = maxhealth + maxarmor;
+ string biggercount;
+ if(v.z) // NOT fully armored
+ {
+ biggercount = "health";
+ if(autocvar_hud_panel_healtharmor_progressbar)
+ HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_health, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ if(armor)
+ if(autocvar_hud_panel_healtharmor_text)
+ drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "armor", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha * armor / health, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ biggercount = "armor";
+ if(autocvar_hud_panel_healtharmor_progressbar)
+ HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ if(health)
+ if(autocvar_hud_panel_healtharmor_text)
+ drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "health", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ if(autocvar_hud_panel_healtharmor_text)
+ DrawNumIcon(pos, mySize, x, biggercount, 0, iconalign, HUD_Get_Num_Color(x, maxtotal), 1);
+
+ if(fuel)
+ HUD_Panel_DrawProgressBar(pos, eX * mySize.x + eY * 0.2 * mySize.y, "progressbar", fuel/100, 0, (baralign == 1 || baralign == 3), autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ float panel_ar = mySize.x/mySize.y;
+ bool is_vertical = (panel_ar < 1);
+ vector health_offset = '0 0 0', armor_offset = '0 0 0';
+ if (panel_ar >= 4 || (panel_ar >= 1/4 && panel_ar < 1))
+ {
+ mySize.x *= 0.5;
+ if (autocvar_hud_panel_healtharmor_flip)
+ health_offset.x = mySize.x;
+ else
+ armor_offset.x = mySize.x;
+ }
+ else
+ {
+ mySize.y *= 0.5;
+ if (autocvar_hud_panel_healtharmor_flip)
+ health_offset.y = mySize.y;
+ else
+ armor_offset.y = mySize.y;
+ }
+
+ bool health_baralign, armor_baralign, fuel_baralign;
+ bool health_iconalign, armor_iconalign;
+ if (autocvar_hud_panel_healtharmor_flip)
+ {
+ armor_baralign = (autocvar_hud_panel_healtharmor_baralign == 2 || autocvar_hud_panel_healtharmor_baralign == 1);
+ health_baralign = (autocvar_hud_panel_healtharmor_baralign == 3 || autocvar_hud_panel_healtharmor_baralign == 1);
+ fuel_baralign = health_baralign;
+ armor_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 2 || autocvar_hud_panel_healtharmor_iconalign == 1);
+ health_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 3 || autocvar_hud_panel_healtharmor_iconalign == 1);
+ }
+ else
+ {
+ health_baralign = (autocvar_hud_panel_healtharmor_baralign == 2 || autocvar_hud_panel_healtharmor_baralign == 1);
+ armor_baralign = (autocvar_hud_panel_healtharmor_baralign == 3 || autocvar_hud_panel_healtharmor_baralign == 1);
+ fuel_baralign = armor_baralign;
+ health_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 2 || autocvar_hud_panel_healtharmor_iconalign == 1);
+ armor_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 3 || autocvar_hud_panel_healtharmor_iconalign == 1);
+ }
+
+ //if(health)
+ {
+ if(autocvar_hud_panel_healtharmor_progressbar)
+ {
+ float p_health, pain_health_alpha;
+ p_health = health;
+ pain_health_alpha = 1;
+ if (autocvar_hud_panel_healtharmor_progressbar_gfx)
+ {
+ if (autocvar_hud_panel_healtharmor_progressbar_gfx_smooth > 0)
+ {
+ if (fabs(prev_health - health) >= autocvar_hud_panel_healtharmor_progressbar_gfx_smooth)
+ {
+ if (time - old_p_healthtime < 1)
+ old_p_health = prev_p_health;
+ else
+ old_p_health = prev_health;
+ old_p_healthtime = time;
+ }
+ if (time - old_p_healthtime < 1)
+ {
+ p_health += (old_p_health - health) * (1 - (time - old_p_healthtime));
+ prev_p_health = p_health;
+ }
+ }
+ if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0)
+ {
+ if (prev_health - health >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
+ {
+ if (time - health_damagetime >= 1)
+ health_beforedamage = prev_health;
+ health_damagetime = time;
+ }
+ if (time - health_damagetime < 1)
+ {
+ float health_damagealpha = 1 - (time - health_damagetime)*(time - health_damagetime);
+ HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, health_beforedamage/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * health_damagealpha, DRAWFLAG_NORMAL);
+ }
+ }
+ prev_health = health;
+
+ if (health <= autocvar_hud_panel_healtharmor_progressbar_gfx_lowhealth)
+ {
+ float BLINK_FACTOR = 0.15;
+ float BLINK_BASE = 0.85;
+ float BLINK_FREQ = 9;
+ pain_health_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
+ }
+ }
+ HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, p_health/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * pain_health_alpha, DRAWFLAG_NORMAL);
+ }
+ if(autocvar_hud_panel_healtharmor_text)
+ DrawNumIcon(pos + health_offset, mySize, health, "health", is_vertical, health_iconalign, HUD_Get_Num_Color(health, maxhealth), 1);
+ }
+
+ if(armor)
+ {
+ if(autocvar_hud_panel_healtharmor_progressbar)
+ {
+ float p_armor;
+ p_armor = armor;
+ if (autocvar_hud_panel_healtharmor_progressbar_gfx)
+ {
+ if (autocvar_hud_panel_healtharmor_progressbar_gfx_smooth > 0)
+ {
+ if (fabs(prev_armor - armor) >= autocvar_hud_panel_healtharmor_progressbar_gfx_smooth)
+ {
+ if (time - old_p_armortime < 1)
+ old_p_armor = prev_p_armor;
+ else
+ old_p_armor = prev_armor;
+ old_p_armortime = time;
+ }
+ if (time - old_p_armortime < 1)
+ {
+ p_armor += (old_p_armor - armor) * (1 - (time - old_p_armortime));
+ prev_p_armor = p_armor;
+ }
+ }
+ if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0)
+ {
+ if (prev_armor - armor >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
+ {
+ if (time - armor_damagetime >= 1)
+ armor_beforedamage = prev_armor;
+ armor_damagetime = time;
+ }
+ if (time - armor_damagetime < 1)
+ {
+ float armor_damagealpha = 1 - (time - armor_damagetime)*(time - armor_damagetime);
+ HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, armor_beforedamage/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * armor_damagealpha, DRAWFLAG_NORMAL);
+ }
+ }
+ prev_armor = armor;
+ }
+ HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, p_armor/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ if(autocvar_hud_panel_healtharmor_text)
+ DrawNumIcon(pos + armor_offset, mySize, armor, "armor", is_vertical, armor_iconalign, HUD_Get_Num_Color(armor, maxarmor), 1);
+ }
+
+ if(fuel)
+ {
+ if (is_vertical)
+ mySize.x *= 0.2 / 2; //if vertical always halve x to not cover too much numbers with 3 digits
+ else
+ mySize.y *= 0.2;
+ if (panel_ar >= 4)
+ mySize.x *= 2; //restore full panel size
+ else if (panel_ar < 1/4)
+ mySize.y *= 2; //restore full panel size
+ HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", fuel/100, is_vertical, fuel_baralign, autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
+ }
+ }
+
+ draw_endBoldFont();
+}
--- /dev/null
+// Info messages panel (#14)
+
+#define drawInfoMessage(s) do { \
+ if(autocvar_hud_panel_infomessages_flip) \
+ o.x = pos.x + mySize.x - stringwidth(s, true, fontsize); \
+ drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL); \
+ o.y += fontsize.y; \
+} while(0)
+void HUD_InfoMessages()
+{
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_infomessages) return;
+ }
+
+ HUD_Panel_UpdateCvars();
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(1);
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ // always force 5:1 aspect
+ vector newSize = '0 0 0';
+ if(mySize.x/mySize.y > 5)
+ {
+ newSize.x = 5 * mySize.y;
+ newSize.y = mySize.y;
+
+ pos.x = pos.x + (mySize.x - newSize.x) / 2;
+ }
+ else
+ {
+ newSize.y = 1/5 * mySize.x;
+ newSize.x = mySize.x;
+
+ pos.y = pos.y + (mySize.y - newSize.y) / 2;
+ }
+
+ mySize = newSize;
+ entity tm;
+ vector o;
+ o = pos;
+
+ vector fontsize;
+ fontsize = '0.20 0.20 0' * mySize.y;
+
+ float a;
+ a = panel_fg_alpha;
+
+ string s;
+ if(!autocvar__hud_configure)
+ {
+ if(spectatee_status && !intermission)
+ {
+ a = 1;
+ if(spectatee_status == -1)
+ s = _("^1Observing");
+ else
+ s = sprintf(_("^1Spectating: ^7%s"), GetPlayerName(current_player));
+ drawInfoMessage(s);
+
+ if(spectatee_status == -1)
+ s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey("primary fire", "+fire"));
+ else
+ s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
+ drawInfoMessage(s);
+
+ if(spectatee_status == -1)
+ s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
+ else
+ s = sprintf(_("^1Press ^3%s^1 to observe"), getcommandkey("secondary fire", "+fire2"));
+ drawInfoMessage(s);
+
+ s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey("server info", "+show_info"));
+ drawInfoMessage(s);
+
+ if(gametype == MAPINFO_TYPE_LMS)
+ {
+ entity sk;
+ sk = playerslots[player_localnum];
+ if(sk.(scores[ps_primary]) >= 666)
+ s = _("^1Match has already begun");
+ else if(sk.(scores[ps_primary]) > 0)
+ s = _("^1You have no more lives left");
+ else
+ s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
+ }
+ else
+ s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
+ drawInfoMessage(s);
+
+ //show restart countdown:
+ if (time < STAT(GAMESTARTTIME)) {
+ float countdown;
+ //we need to ceil, otherwise the countdown would be off by .5 when using round()
+ countdown = ceil(STAT(GAMESTARTTIME) - time);
+ s = sprintf(_("^1Game starts in ^3%d^1 seconds"), countdown);
+ drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL);
+ o.y += fontsize.y;
+ }
+ }
+ if(warmup_stage && !intermission)
+ {
+ s = _("^2Currently in ^1warmup^2 stage!");
+ drawInfoMessage(s);
+ }
+
+ string blinkcolor;
+ if(time % 1 >= 0.5)
+ blinkcolor = "^1";
+ else
+ blinkcolor = "^3";
+
+ if(ready_waiting && !intermission && !spectatee_status)
+ {
+ if(ready_waiting_for_me)
+ {
+ if(warmup_stage)
+ s = sprintf(_("%sPress ^3%s%s to end warmup"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
+ else
+ s = sprintf(_("%sPress ^3%s%s once you are ready"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
+ }
+ else
+ {
+ if(warmup_stage)
+ s = _("^2Waiting for others to ready up to end warmup...");
+ else
+ s = _("^2Waiting for others to ready up...");
+ }
+ drawInfoMessage(s);
+ }
+ else if(warmup_stage && !intermission && !spectatee_status)
+ {
+ s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey("ready", "ready"));
+ drawInfoMessage(s);
+ }
+
+ if(teamplay && !intermission && !spectatee_status && gametype != MAPINFO_TYPE_CA && teamnagger)
+ {
+ float ts_min = 0, ts_max = 0;
+ tm = teams.sort_next;
+ if (tm)
+ {
+ for (; tm.sort_next; tm = tm.sort_next)
+ {
+ if(!tm.team_size || tm.team == NUM_SPECTATOR)
+ continue;
+ if(!ts_min) ts_min = tm.team_size;
+ else ts_min = min(ts_min, tm.team_size);
+ if(!ts_max) ts_max = tm.team_size;
+ else ts_max = max(ts_max, tm.team_size);
+ }
+ if ((ts_max - ts_min) > 1)
+ {
+ s = strcat(blinkcolor, _("Teamnumbers are unbalanced!"));
+ tm = GetTeam(myteam, false);
+ if (tm)
+ if (tm.team != NUM_SPECTATOR)
+ if (tm.team_size == ts_max)
+ s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey("team menu", "menu_showteamselect"), blinkcolor));
+ drawInfoMessage(s);
+ }
+ }
+ }
+ }
+ else
+ {
+ s = _("^7Press ^3ESC ^7to show HUD options.");
+ drawInfoMessage(s);
+ s = _("^3Doubleclick ^7a panel for panel-specific options.");
+ drawInfoMessage(s);
+ s = _("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and");
+ drawInfoMessage(s);
+ s = _("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments.");
+ drawInfoMessage(s);
+ }
+}
--- /dev/null
+// Minigame
+
+#include "../../../common/minigames/cl_minigames_hud.qc"
--- /dev/null
+// Mod icons panel (#10)
+
+bool mod_active; // is there any active mod icon?
+
+void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
+{
+ int stat = -1;
+ string pic = "";
+ vector color = '0 0 0';
+ switch(i)
+ {
+ case 0:
+ stat = getstati(STAT_REDALIVE);
+ pic = "player_red.tga";
+ color = '1 0 0';
+ break;
+ case 1:
+ stat = getstati(STAT_BLUEALIVE);
+ pic = "player_blue.tga";
+ color = '0 0 1';
+ break;
+ case 2:
+ stat = getstati(STAT_YELLOWALIVE);
+ pic = "player_yellow.tga";
+ color = '1 1 0';
+ break;
+ default:
+ case 3:
+ stat = getstati(STAT_PINKALIVE);
+ pic = "player_pink.tga";
+ color = '1 0 1';
+ break;
+ }
+
+ if(mySize.x/mySize.y > aspect_ratio)
+ {
+ i = aspect_ratio * mySize.y;
+ myPos.x = myPos.x + (mySize.x - i) / 2;
+ mySize.x = i;
+ }
+ else
+ {
+ i = 1/aspect_ratio * mySize.x;
+ myPos.y = myPos.y + (mySize.y - i) / 2;
+ mySize.y = i;
+ }
+
+ if(layout)
+ {
+ drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(myPos + eX * 0.7 * mySize.x, ftos(stat), eX * 0.3 * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ else
+ drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+// Clan Arena and Freeze Tag HUD modicons
+void HUD_Mod_CA(vector myPos, vector mySize)
+{
+ mod_active = 1; // required in each mod function that always shows something
+
+ int layout;
+ if(gametype == MAPINFO_TYPE_CA)
+ layout = autocvar_hud_panel_modicons_ca_layout;
+ else //if(gametype == MAPINFO_TYPE_FREEZETAG)
+ layout = autocvar_hud_panel_modicons_freezetag_layout;
+ int rows, columns;
+ float aspect_ratio;
+ aspect_ratio = (layout) ? 2 : 1;
+ rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
+ columns = ceil(team_count/rows);
+
+ int i;
+ float row = 0, column = 0;
+ vector pos, itemSize;
+ itemSize = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+ for(i=0; i<team_count; ++i)
+ {
+ pos = myPos + eX * column * itemSize.x + eY * row * itemSize.y;
+
+ DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
+
+ ++row;
+ if(row >= rows)
+ {
+ row = 0;
+ ++column;
+ }
+ }
+}
+
+// CTF HUD modicon section
+int redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe, neutralflag_prevframe; // status during previous frame
+int redflag_prevstatus, blueflag_prevstatus, yellowflag_prevstatus, pinkflag_prevstatus, neutralflag_prevstatus; // last remembered status
+float redflag_statuschange_time, blueflag_statuschange_time, yellowflag_statuschange_time, pinkflag_statuschange_time, neutralflag_statuschange_time; // time when the status changed
+
+void HUD_Mod_CTF_Reset()
+{
+ redflag_prevstatus = blueflag_prevstatus = yellowflag_prevstatus = pinkflag_prevstatus = neutralflag_prevstatus = 0;
+ redflag_prevframe = blueflag_prevframe = yellowflag_prevframe = pinkflag_prevframe = neutralflag_prevframe = 0;
+ redflag_statuschange_time = blueflag_statuschange_time = yellowflag_statuschange_time = pinkflag_statuschange_time = neutralflag_statuschange_time = 0;
+}
+
+void HUD_Mod_CTF(vector pos, vector mySize)
+{
+ vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos, neutralflag_pos;
+ vector flag_size;
+ float f; // every function should have that
+
+ int redflag, blueflag, yellowflag, pinkflag, neutralflag; // current status
+ float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime, yellowflag_statuschange_elapsedtime, pinkflag_statuschange_elapsedtime, neutralflag_statuschange_elapsedtime; // time since the status changed
+ bool ctf_oneflag; // one-flag CTF mode enabled/disabled
+ int stat_items = getstati(STAT_CTF_FLAGSTATUS, 0, 24);
+ float fs, fs2, fs3, size1, size2;
+ vector e1, e2;
+
+ redflag = (stat_items/CTF_RED_FLAG_TAKEN) & 3;
+ blueflag = (stat_items/CTF_BLUE_FLAG_TAKEN) & 3;
+ yellowflag = (stat_items/CTF_YELLOW_FLAG_TAKEN) & 3;
+ pinkflag = (stat_items/CTF_PINK_FLAG_TAKEN) & 3;
+ neutralflag = (stat_items/CTF_NEUTRAL_FLAG_TAKEN) & 3;
+
+ ctf_oneflag = (stat_items & CTF_FLAG_NEUTRAL);
+
+ mod_active = (redflag || blueflag || yellowflag || pinkflag || neutralflag);
+
+ if (autocvar__hud_configure) {
+ redflag = 1;
+ blueflag = 2;
+ if (team_count >= 3)
+ yellowflag = 2;
+ if (team_count >= 4)
+ pinkflag = 3;
+ ctf_oneflag = neutralflag = 0; // disable neutral flag in hud editor?
+ }
+
+ // when status CHANGES, set old status into prevstatus and current status into status
+ #define X(team) do { \
+ if (team##flag != team##flag_prevframe) { \
+ team##flag_statuschange_time = time; \
+ team##flag_prevstatus = team##flag_prevframe; \
+ team##flag_prevframe = team##flag; \
+ } \
+ team##flag_statuschange_elapsedtime = time - team##flag_statuschange_time; \
+ } while (0)
+ X(red);
+ X(blue);
+ X(yellow);
+ X(pink);
+ X(neutral);
+ #undef X
+
+ const float BLINK_FACTOR = 0.15;
+ const float BLINK_BASE = 0.85;
+ // note:
+ // RMS = sqrt(BLINK_BASE^2 + 0.5 * BLINK_FACTOR^2)
+ // thus
+ // BLINK_BASE = sqrt(RMS^2 - 0.5 * BLINK_FACTOR^2)
+ // ensure RMS == 1
+ const float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
+
+ #define X(team, cond) \
+ string team##_icon, team##_icon_prevstatus; \
+ int team##_alpha, team##_alpha_prevstatus; \
+ team##_alpha = team##_alpha_prevstatus = 1; \
+ do { \
+ switch (team##flag) { \
+ case 1: team##_icon = "flag_" #team "_taken"; break; \
+ case 2: team##_icon = "flag_" #team "_lost"; break; \
+ case 3: team##_icon = "flag_" #team "_carrying"; team##_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
+ default: \
+ if ((stat_items & CTF_SHIELDED) && (cond)) { \
+ team##_icon = "flag_" #team "_shielded"; \
+ } else { \
+ team##_icon = string_null; \
+ } \
+ break; \
+ } \
+ switch (team##flag_prevstatus) { \
+ case 1: team##_icon_prevstatus = "flag_" #team "_taken"; break; \
+ case 2: team##_icon_prevstatus = "flag_" #team "_lost"; break; \
+ case 3: team##_icon_prevstatus = "flag_" #team "_carrying"; team##_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
+ default: \
+ if (team##flag == 3) { \
+ team##_icon_prevstatus = "flag_" #team "_carrying"; /* make it more visible */\
+ } else if((stat_items & CTF_SHIELDED) && (cond)) { \
+ team##_icon_prevstatus = "flag_" #team "_shielded"; \
+ } else { \
+ team##_icon_prevstatus = string_null; \
+ } \
+ break; \
+ } \
+ } while (0)
+ X(red, myteam != NUM_TEAM_1);
+ X(blue, myteam != NUM_TEAM_2);
+ X(yellow, myteam != NUM_TEAM_3);
+ X(pink, myteam != NUM_TEAM_4);
+ X(neutral, true);
+ #undef X
+
+ if (ctf_oneflag) {
+ // hacky, but these aren't needed
+ red_icon = red_icon_prevstatus = blue_icon = blue_icon_prevstatus = yellow_icon = yellow_icon_prevstatus = pink_icon = pink_icon_prevstatus = string_null;
+ fs = fs2 = fs3 = 1;
+ } else switch (team_count) {
+ default:
+ case 2: fs = 0.5; fs2 = 0.5; fs3 = 0.5; break;
+ case 3: fs = 1; fs2 = 0.35; fs3 = 0.35; break;
+ case 4: fs = 0.75; fs2 = 0.25; fs3 = 0.5; break;
+ }
+
+ if (mySize_x > mySize_y) {
+ size1 = mySize_x;
+ size2 = mySize_y;
+ e1 = eX;
+ e2 = eY;
+ } else {
+ size1 = mySize_y;
+ size2 = mySize_x;
+ e1 = eY;
+ e2 = eX;
+ }
+
+ switch (myteam) {
+ default:
+ case NUM_TEAM_1: {
+ redflag_pos = pos;
+ blueflag_pos = pos + eX * fs2 * size1;
+ yellowflag_pos = pos - eX * fs2 * size1;
+ pinkflag_pos = pos + eX * fs3 * size1;
+ break;
+ }
+ case NUM_TEAM_2: {
+ redflag_pos = pos + eX * fs2 * size1;
+ blueflag_pos = pos;
+ yellowflag_pos = pos - eX * fs2 * size1;
+ pinkflag_pos = pos + eX * fs3 * size1;
+ break;
+ }
+ case NUM_TEAM_3: {
+ redflag_pos = pos + eX * fs3 * size1;
+ blueflag_pos = pos - eX * fs2 * size1;
+ yellowflag_pos = pos;
+ pinkflag_pos = pos + eX * fs2 * size1;
+ break;
+ }
+ case NUM_TEAM_4: {
+ redflag_pos = pos - eX * fs2 * size1;
+ blueflag_pos = pos + eX * fs3 * size1;
+ yellowflag_pos = pos + eX * fs2 * size1;
+ pinkflag_pos = pos;
+ break;
+ }
+ }
+ neutralflag_pos = pos;
+ flag_size = e1 * fs * size1 + e2 * size2;
+
+ #define X(team) do { \
+ f = bound(0, team##flag_statuschange_elapsedtime * 2, 1); \
+ if (team##_icon_prevstatus && f < 1) \
+ drawpic_aspect_skin_expanding(team##flag_pos, team##_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * team##_alpha_prevstatus, DRAWFLAG_NORMAL, f); \
+ if (team##_icon) \
+ drawpic_aspect_skin(team##flag_pos, team##_icon, flag_size, '1 1 1', panel_fg_alpha * team##_alpha * f, DRAWFLAG_NORMAL); \
+ } while (0)
+ X(red);
+ X(blue);
+ X(yellow);
+ X(pink);
+ X(neutral);
+ #undef X
+}
+
+// Keyhunt HUD modicon section
+vector KH_SLOTS[4];
+
+void HUD_Mod_KH(vector pos, vector mySize)
+{
+ mod_active = 1; // keyhunt should never hide the mod icons panel
+
+ // Read current state
+
+ int state = STAT(KH_KEYS);
+ int i, key_state;
+ int all_keys, team1_keys, team2_keys, team3_keys, team4_keys, dropped_keys, carrying_keys;
+ all_keys = team1_keys = team2_keys = team3_keys = team4_keys = dropped_keys = carrying_keys = 0;
+
+ for(i = 0; i < 4; ++i)
+ {
+ key_state = (bitshift(state, i * -5) & 31) - 1;
+
+ if(key_state == -1)
+ continue;
+
+ if(key_state == 30)
+ {
+ ++carrying_keys;
+ key_state = myteam;
+ }
+
+ switch(key_state)
+ {
+ case NUM_TEAM_1: ++team1_keys; break;
+ case NUM_TEAM_2: ++team2_keys; break;
+ case NUM_TEAM_3: ++team3_keys; break;
+ case NUM_TEAM_4: ++team4_keys; break;
+ case 29: ++dropped_keys; break;
+ }
+
+ ++all_keys;
+ }
+
+ // Calculate slot measurements
+
+ vector slot_size;
+
+ if(all_keys == 4 && mySize.x * 0.5 < mySize.y && mySize.y * 0.5 < mySize.x)
+ {
+ // Quadratic arrangement
+ slot_size = eX * mySize.x * 0.5 + eY * mySize.y * 0.5;
+ KH_SLOTS[0] = pos;
+ KH_SLOTS[1] = pos + eX * slot_size.x;
+ KH_SLOTS[2] = pos + eY * slot_size.y;
+ KH_SLOTS[3] = pos + eX * slot_size.x + eY * slot_size.y;
+ }
+ else
+ {
+ if(mySize.x > mySize.y)
+ {
+ // Horizontal arrangement
+ slot_size = eX * mySize.x / all_keys + eY * mySize.y;
+ for(i = 0; i < all_keys; ++i)
+ KH_SLOTS[i] = pos + eX * slot_size.x * i;
+ }
+ else
+ {
+ // Vertical arrangement
+ slot_size = eX * mySize.x + eY * mySize.y / all_keys;
+ for(i = 0; i < all_keys; ++i)
+ KH_SLOTS[i] = pos + eY * slot_size.y * i;
+ }
+ }
+
+ // Make icons blink in case of RUN HERE
+
+ float blink = 0.6 + sin(2*M_PI*time) / 2.5; // Oscillate between 0.2 and 1
+ float alpha;
+ alpha = 1;
+
+ if(carrying_keys)
+ switch(myteam)
+ {
+ case NUM_TEAM_1: if(team1_keys == all_keys) alpha = blink; break;
+ case NUM_TEAM_2: if(team2_keys == all_keys) alpha = blink; break;
+ case NUM_TEAM_3: if(team3_keys == all_keys) alpha = blink; break;
+ case NUM_TEAM_4: if(team4_keys == all_keys) alpha = blink; break;
+ }
+
+ // Draw icons
+
+ i = 0;
+
+ while(team1_keys--)
+ if(myteam == NUM_TEAM_1 && carrying_keys)
+ {
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ --carrying_keys;
+ }
+ else
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+ while(team2_keys--)
+ if(myteam == NUM_TEAM_2 && carrying_keys)
+ {
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ --carrying_keys;
+ }
+ else
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+ while(team3_keys--)
+ if(myteam == NUM_TEAM_3 && carrying_keys)
+ {
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ --carrying_keys;
+ }
+ else
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+ while(team4_keys--)
+ if(myteam == NUM_TEAM_4 && carrying_keys)
+ {
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ --carrying_keys;
+ }
+ else
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+ while(dropped_keys--)
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_dropped", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+}
+
+// Keepaway HUD mod icon
+int kaball_prevstatus; // last remembered status
+float kaball_statuschange_time; // time when the status changed
+
+// we don't need to reset for keepaway since it immediately
+// autocorrects prevstatus as to if the player has the ball or not
+
+void HUD_Mod_Keepaway(vector pos, vector mySize)
+{
+ mod_active = 1; // keepaway should always show the mod HUD
+
+ float BLINK_FACTOR = 0.15;
+ float BLINK_BASE = 0.85;
+ float BLINK_FREQ = 5;
+ float kaball_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
+
+ int stat_items = getstati(STAT_ITEMS, 0, 24);
+ int kaball = (stat_items/IT_KEY1) & 1;
+
+ if(kaball != kaball_prevstatus)
+ {
+ kaball_statuschange_time = time;
+ kaball_prevstatus = kaball;
+ }
+
+ vector kaball_pos, kaball_size;
+
+ if(mySize.x > mySize.y) {
+ kaball_pos = pos + eX * 0.25 * mySize.x;
+ kaball_size = eX * 0.5 * mySize.x + eY * mySize.y;
+ } else {
+ kaball_pos = pos + eY * 0.25 * mySize.y;
+ kaball_size = eY * 0.5 * mySize.y + eX * mySize.x;
+ }
+
+ float kaball_statuschange_elapsedtime = time - kaball_statuschange_time;
+ float f = bound(0, kaball_statuschange_elapsedtime*2, 1);
+
+ if(kaball_prevstatus && f < 1)
+ drawpic_aspect_skin_expanding(kaball_pos, "keepawayball_carrying", kaball_size, '1 1 1', panel_fg_alpha * kaball_alpha, DRAWFLAG_NORMAL, f);
+
+ if(kaball)
+ drawpic_aspect_skin(pos, "keepawayball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha * kaball_alpha * f, DRAWFLAG_NORMAL);
+}
+
+
+// Nexball HUD mod icon
+void HUD_Mod_NexBall(vector pos, vector mySize)
+{
+ float nb_pb_starttime, dt, p;
+ int stat_items;
+
+ stat_items = getstati(STAT_ITEMS, 0, 24);
+ nb_pb_starttime = getstatf(STAT_NB_METERSTART);
+
+ if (stat_items & IT_KEY1)
+ mod_active = 1;
+ else
+ mod_active = 0;
+
+ //Manage the progress bar if any
+ if (nb_pb_starttime > 0)
+ {
+ dt = (time - nb_pb_starttime) % nb_pb_period;
+ // one period of positive triangle
+ p = 2 * dt / nb_pb_period;
+ if (p > 1)
+ p = 2 - p;
+
+ HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, (mySize.x <= mySize.y), 0, autocvar_hud_progressbar_nexball_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ if (stat_items & IT_KEY1)
+ drawpic_aspect_skin(pos, "nexball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+// Race/CTS HUD mod icons
+float crecordtime_prev; // last remembered crecordtime
+float crecordtime_change_time; // time when crecordtime last changed
+float srecordtime_prev; // last remembered srecordtime
+float srecordtime_change_time; // time when srecordtime last changed
+
+float race_status_time;
+int race_status_prev;
+string race_status_name_prev;
+void HUD_Mod_Race(vector pos, vector mySize)
+{
+ mod_active = 1; // race should never hide the mod icons panel
+ entity me;
+ me = playerslots[player_localnum];
+ float t, score;
+ float f; // yet another function has this
+ score = me.(scores[ps_primary]);
+
+ if(!(scores_flags[ps_primary] & SFL_TIME) || teamplay) // race/cts record display on HUD
+ return; // no records in the actual race
+
+ // clientside personal record
+ string rr;
+ if(gametype == MAPINFO_TYPE_CTS)
+ rr = CTS_RECORD;
+ else
+ rr = RACE_RECORD;
+ t = stof(db_get(ClientProgsDB, strcat(shortmapname, rr, "time")));
+
+ if(score && (score < t || !t)) {
+ db_put(ClientProgsDB, strcat(shortmapname, rr, "time"), ftos(score));
+ if(autocvar_cl_autodemo_delete_keeprecords)
+ {
+ f = autocvar_cl_autodemo_delete;
+ f &= ~1;
+ cvar_set("cl_autodemo_delete", ftos(f)); // don't delete demo with new record!
+ }
+ }
+
+ if(t != crecordtime_prev) {
+ crecordtime_prev = t;
+ crecordtime_change_time = time;
+ }
+
+ vector textPos, medalPos;
+ float squareSize;
+ if(mySize.x > mySize.y) {
+ // text on left side
+ squareSize = min(mySize.y, mySize.x/2);
+ textPos = pos + eX * 0.5 * max(0, mySize.x/2 - squareSize) + eY * 0.5 * (mySize.y - squareSize);
+ medalPos = pos + eX * 0.5 * max(0, mySize.x/2 - squareSize) + eX * 0.5 * mySize.x + eY * 0.5 * (mySize.y - squareSize);
+ } else {
+ // text on top
+ squareSize = min(mySize.x, mySize.y/2);
+ textPos = pos + eY * 0.5 * max(0, mySize.y/2 - squareSize) + eX * 0.5 * (mySize.x - squareSize);
+ medalPos = pos + eY * 0.5 * max(0, mySize.y/2 - squareSize) + eY * 0.5 * mySize.y + eX * 0.5 * (mySize.x - squareSize);
+ }
+
+ f = time - crecordtime_change_time;
+
+ if (f > 1) {
+ drawstring_aspect(textPos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(textPos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ } else {
+ drawstring_aspect(textPos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(textPos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect_expanding(pos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
+ drawstring_aspect_expanding(pos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
+ }
+
+ // server record
+ t = race_server_record;
+ if(t != srecordtime_prev) {
+ srecordtime_prev = t;
+ srecordtime_change_time = time;
+ }
+ f = time - srecordtime_change_time;
+
+ if (f > 1) {
+ drawstring_aspect(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ } else {
+ drawstring_aspect(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect_expanding(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
+ drawstring_aspect_expanding(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
+ }
+
+ if (race_status != race_status_prev || race_status_name != race_status_name_prev) {
+ race_status_time = time + 5;
+ race_status_prev = race_status;
+ if (race_status_name_prev)
+ strunzone(race_status_name_prev);
+ race_status_name_prev = strzone(race_status_name);
+ }
+
+ // race "awards"
+ float a;
+ a = bound(0, race_status_time - time, 1);
+
+ string s;
+ s = textShortenToWidth(race_status_name, squareSize, '1 1 0' * 0.1 * squareSize, stringwidth_colors);
+
+ float rank;
+ if(race_status > 0)
+ rank = race_CheckName(race_status_name);
+ else
+ rank = 0;
+ string rankname;
+ rankname = count_ordinal(rank);
+
+ vector namepos;
+ namepos = medalPos + '0 0.8 0' * squareSize;
+ vector rankpos;
+ rankpos = medalPos + '0 0.15 0' * squareSize;
+
+ if(race_status == 0)
+ drawpic_aspect_skin(medalPos, "race_newfail", '1 1 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ else if(race_status == 1) {
+ drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newtime", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ } else if(race_status == 2) {
+ if(race_status_name == GetPlayerName(player_localnum) || !race_myrank || race_myrank < rank)
+ drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankgreen", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ else
+ drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankyellow", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ } else if(race_status == 3) {
+ drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrecordserver", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ }
+
+ if (race_status_time - time <= 0) {
+ race_status_prev = -1;
+ race_status = -1;
+ if(race_status_name)
+ strunzone(race_status_name);
+ race_status_name = string_null;
+ if(race_status_name_prev)
+ strunzone(race_status_name_prev);
+ race_status_name_prev = string_null;
+ }
+}
+
+void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
+{
+ float stat = -1;
+ string pic = "";
+ vector color = '0 0 0';
+ switch(i)
+ {
+ case 0:
+ stat = getstatf(STAT_DOM_PPS_RED);
+ pic = "dom_icon_red";
+ color = '1 0 0';
+ break;
+ case 1:
+ stat = getstatf(STAT_DOM_PPS_BLUE);
+ pic = "dom_icon_blue";
+ color = '0 0 1';
+ break;
+ case 2:
+ stat = getstatf(STAT_DOM_PPS_YELLOW);
+ pic = "dom_icon_yellow";
+ color = '1 1 0';
+ break;
+ default:
+ case 3:
+ stat = getstatf(STAT_DOM_PPS_PINK);
+ pic = "dom_icon_pink";
+ color = '1 0 1';
+ break;
+ }
+ float pps_ratio = stat / getstatf(STAT_DOM_TOTAL_PPS);
+
+ if(mySize.x/mySize.y > aspect_ratio)
+ {
+ i = aspect_ratio * mySize.y;
+ myPos.x = myPos.x + (mySize.x - i) / 2;
+ mySize.x = i;
+ }
+ else
+ {
+ i = 1/aspect_ratio * mySize.x;
+ myPos.y = myPos.y + (mySize.y - i) / 2;
+ mySize.y = i;
+ }
+
+ if (layout) // show text too
+ {
+ //draw the text
+ color *= 0.5 + pps_ratio * (1 - 0.5); // half saturated color at min, full saturated at max
+ if (layout == 2) // average pps
+ drawstring_aspect(myPos + eX * mySize.y, ftos_decimals(stat, 2), eX * (2/3) * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ else // percentage of average pps
+ drawstring_aspect(myPos + eX * mySize.y, strcat( ftos(floor(pps_ratio*100 + 0.5)), "%" ), eX * (2/3) * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ //draw the icon
+ drawpic_aspect_skin(myPos, pic, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ if (stat > 0)
+ {
+ drawsetcliparea(myPos.x, myPos.y + mySize.y * (1 - pps_ratio), mySize.y, mySize.y * pps_ratio);
+ drawpic_aspect_skin(myPos, strcat(pic, "-highlighted"), '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+ }
+}
+
+void HUD_Mod_Dom(vector myPos, vector mySize)
+{
+ mod_active = 1; // required in each mod function that always shows something
+
+ int layout = autocvar_hud_panel_modicons_dom_layout;
+ int rows, columns;
+ float aspect_ratio;
+ aspect_ratio = (layout) ? 3 : 1;
+ rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
+ columns = ceil(team_count/rows);
+
+ int i;
+ float row = 0, column = 0;
+ vector pos, itemSize;
+ itemSize = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+ for(i=0; i<team_count; ++i)
+ {
+ pos = myPos + eX * column * itemSize.x + eY * row * itemSize.y;
+
+ DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
+
+ ++row;
+ if(row >= rows)
+ {
+ row = 0;
+ ++column;
+ }
+ }
+}
+
+void HUD_ModIcons_SetFunc()
+{
+ switch(gametype)
+ {
+ case MAPINFO_TYPE_KEYHUNT: HUD_ModIcons_GameType = HUD_Mod_KH; break;
+ case MAPINFO_TYPE_CTF: HUD_ModIcons_GameType = HUD_Mod_CTF; break;
+ case MAPINFO_TYPE_NEXBALL: HUD_ModIcons_GameType = HUD_Mod_NexBall; break;
+ case MAPINFO_TYPE_CTS:
+ case MAPINFO_TYPE_RACE: HUD_ModIcons_GameType = HUD_Mod_Race; break;
+ case MAPINFO_TYPE_CA:
+ case MAPINFO_TYPE_FREEZETAG: HUD_ModIcons_GameType = HUD_Mod_CA; break;
+ case MAPINFO_TYPE_DOMINATION: HUD_ModIcons_GameType = HUD_Mod_Dom; break;
+ case MAPINFO_TYPE_KEEPAWAY: HUD_ModIcons_GameType = HUD_Mod_Keepaway; break;
+ }
+}
+
+int mod_prev; // previous state of mod_active to check for a change
+float mod_alpha;
+float mod_change; // "time" when mod_active changed
+
+void HUD_ModIcons()
+{
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_modicons) return;
+ if(!HUD_ModIcons_GameType) return;
+ }
+
+ HUD_Panel_UpdateCvars();
+
+ draw_beginBoldFont();
+
+ if(mod_active != mod_prev) {
+ mod_change = time;
+ mod_prev = mod_active;
+ }
+
+ if(mod_active || autocvar__hud_configure)
+ mod_alpha = bound(0, (time - mod_change) * 2, 1);
+ else
+ mod_alpha = bound(0, 1 - (time - mod_change) * 2, 1);
+
+ if(mod_alpha)
+ HUD_Panel_DrawBg(mod_alpha);
+
+ if(panel_bg_padding)
+ {
+ panel_pos += '1 1 0' * panel_bg_padding;
+ panel_size -= '2 2 0' * panel_bg_padding;
+ }
+
+ if(autocvar__hud_configure)
+ HUD_Mod_CTF(panel_pos, panel_size);
+ else
+ HUD_ModIcons_GameType(panel_pos, panel_size);
+
+ draw_endBoldFont();
+}
--- /dev/null
+// Notification area (#4)
+
+void HUD_Notify_Push(string icon, string attacker, string victim)
+{
+ if (icon == "")
+ return;
+
+ ++notify_count;
+ --notify_index;
+
+ if (notify_index == -1)
+ notify_index = NOTIFY_MAX_ENTRIES-1;
+
+ // Free old strings
+ if (notify_attackers[notify_index])
+ strunzone(notify_attackers[notify_index]);
+
+ if (notify_victims[notify_index])
+ strunzone(notify_victims[notify_index]);
+
+ if (notify_icons[notify_index])
+ strunzone(notify_icons[notify_index]);
+
+ // Allocate new strings
+ if (victim != "")
+ {
+ notify_attackers[notify_index] = strzone(attacker);
+ notify_victims[notify_index] = strzone(victim);
+ }
+ else
+ {
+ // In case of a notification without a victim, the attacker
+ // is displayed on the victim's side. Instead of special
+ // treatment later on, we can simply switch them here.
+ notify_attackers[notify_index] = string_null;
+ notify_victims[notify_index] = strzone(attacker);
+ }
+
+ notify_icons[notify_index] = strzone(icon);
+ notify_times[notify_index] = time;
+}
+
+void HUD_Notify()
+{
+ if (!autocvar__hud_configure)
+ if (!autocvar_hud_panel_notify)
+ return;
+
+ HUD_Panel_UpdateCvars();
+ HUD_Panel_DrawBg(1);
+
+ if (!autocvar__hud_configure)
+ if (notify_count == 0)
+ return;
+
+ vector pos, size;
+ pos = panel_pos;
+ size = panel_size;
+
+ if (panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ size -= '2 2 0' * panel_bg_padding;
+ }
+
+ float fade_start = max(0, autocvar_hud_panel_notify_time);
+ float fade_time = max(0, autocvar_hud_panel_notify_fadetime);
+ float icon_aspect = max(1, autocvar_hud_panel_notify_icon_aspect);
+
+ int entry_count = bound(1, floor(NOTIFY_MAX_ENTRIES * size.y / size.x), NOTIFY_MAX_ENTRIES);
+ float entry_height = size.y / entry_count;
+
+ float panel_width_half = size.x * 0.5;
+ float icon_width_half = entry_height * icon_aspect / 2;
+ float name_maxwidth = panel_width_half - icon_width_half - size.x * NOTIFY_ICON_MARGIN;
+
+ vector font_size = '0.5 0.5 0' * entry_height * autocvar_hud_panel_notify_fontsize;
+ vector icon_size = (eX * icon_aspect + eY) * entry_height;
+ vector icon_left = eX * (panel_width_half - icon_width_half);
+ vector attacker_right = eX * name_maxwidth;
+ vector victim_left = eX * (size.x - name_maxwidth);
+
+ vector attacker_pos, victim_pos, icon_pos;
+ string attacker, victim, icon;
+ int i, j, count, step, limit;
+ float alpha;
+
+ if (autocvar_hud_panel_notify_flip)
+ {
+ // Order items from the top down
+ i = 0;
+ step = +1;
+ limit = entry_count;
+ }
+ else
+ {
+ // Order items from the bottom up
+ i = entry_count - 1;
+ step = -1;
+ limit = -1;
+ }
+
+ for (j = notify_index, count = 0; i != limit; i += step, ++j, ++count)
+ {
+ if(autocvar__hud_configure)
+ {
+ attacker = sprintf(_("Player %d"), count + 1);
+ victim = sprintf(_("Player %d"), count + 2);
+ icon = get_weaponinfo(min(WEP_FIRST + count * 2, WEP_LAST)).model2;
+ alpha = bound(0, 1.2 - count / entry_count, 1);
+ }
+ else
+ {
+ if (j == NOTIFY_MAX_ENTRIES)
+ j = 0;
+
+ if (notify_times[j] + fade_start > time)
+ alpha = 1;
+ else if (fade_time != 0)
+ {
+ alpha = bound(0, (notify_times[j] + fade_start + fade_time - time) / fade_time, 1);
+ if (alpha == 0)
+ break;
+ }
+ else
+ break;
+
+ attacker = notify_attackers[j];
+ victim = notify_victims[j];
+ icon = notify_icons[j];
+ }
+
+ if (icon != "" && victim != "")
+ {
+ vector name_top = eY * (i * entry_height + 0.5 * (entry_height - font_size.y));
+
+ icon_pos = pos + icon_left + eY * i * entry_height;
+ drawpic_aspect_skin(icon_pos, icon, icon_size, '1 1 1', panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+
+ victim = textShortenToWidth(victim, name_maxwidth, font_size, stringwidth_colors);
+ victim_pos = pos + victim_left + name_top;
+ drawcolorcodedstring(victim_pos, victim, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+
+ if (attacker != "")
+ {
+ attacker = textShortenToWidth(attacker, name_maxwidth, font_size, stringwidth_colors);
+ attacker_pos = pos + attacker_right - eX * stringwidth(attacker, true, font_size) + name_top;
+ drawcolorcodedstring(attacker_pos, attacker, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+ }
+ }
+ }
+
+ notify_count = count;
+}
--- /dev/null
+// Physics panel (#15)
+
+vector acc_prevspeed;
+float acc_prevtime, acc_avg, top_speed, top_speed_time;
+float physics_update_time, discrete_speed, discrete_acceleration;
+void HUD_Physics()
+{
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_physics) return;
+ if(spectatee_status == -1 && (autocvar_hud_panel_physics == 1 || autocvar_hud_panel_physics == 3)) return;
+ if(autocvar_hud_panel_physics == 3 && !(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
+ }
+
+ HUD_Panel_UpdateCvars();
+
+ draw_beginBoldFont();
+
+ HUD_Panel_DrawBg(1);
+ if(panel_bg_padding)
+ {
+ panel_pos += '1 1 0' * panel_bg_padding;
+ panel_size -= '2 2 0' * panel_bg_padding;
+ }
+
+ float acceleration_progressbar_scale = 0;
+ if(autocvar_hud_panel_physics_progressbar && autocvar_hud_panel_physics_acceleration_progressbar_scale > 1)
+ acceleration_progressbar_scale = autocvar_hud_panel_physics_acceleration_progressbar_scale;
+
+ float text_scale;
+ if (autocvar_hud_panel_physics_text_scale <= 0)
+ text_scale = 1;
+ else
+ text_scale = min(autocvar_hud_panel_physics_text_scale, 1);
+
+ //compute speed
+ float speed, conversion_factor;
+ string unit;
+
+ switch(autocvar_hud_panel_physics_speed_unit)
+ {
+ default:
+ case 1:
+ unit = _(" qu/s");
+ conversion_factor = 1.0;
+ break;
+ case 2:
+ unit = _(" m/s");
+ conversion_factor = 0.0254;
+ break;
+ case 3:
+ unit = _(" km/h");
+ conversion_factor = 0.0254 * 3.6;
+ break;
+ case 4:
+ unit = _(" mph");
+ conversion_factor = 0.0254 * 3.6 * 0.6213711922;
+ break;
+ case 5:
+ unit = _(" knots");
+ conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
+ break;
+ }
+
+ vector vel = (csqcplayer ? csqcplayer.velocity : pmove_vel);
+
+ float max_speed = floor( autocvar_hud_panel_physics_speed_max * conversion_factor + 0.5 );
+ if (autocvar__hud_configure)
+ speed = floor( max_speed * 0.65 + 0.5 );
+ else if(autocvar_hud_panel_physics_speed_vertical)
+ speed = floor( vlen(vel) * conversion_factor + 0.5 );
+ else
+ speed = floor( vlen(vel - vel.z * '0 0 1') * conversion_factor + 0.5 );
+
+ //compute acceleration
+ float acceleration, f;
+ if (autocvar__hud_configure)
+ acceleration = autocvar_hud_panel_physics_acceleration_max * 0.3;
+ else
+ {
+ // 1 m/s = 0.0254 qu/s; 1 g = 9.80665 m/s^2
+ f = time - acc_prevtime;
+ if(autocvar_hud_panel_physics_acceleration_vertical)
+ acceleration = (vlen(vel) - vlen(acc_prevspeed));
+ else
+ acceleration = (vlen(vel - '0 0 1' * vel.z) - vlen(acc_prevspeed - '0 0 1' * acc_prevspeed.z));
+
+ acceleration = acceleration * (1 / max(0.0001, f)) * (0.0254 / 9.80665);
+
+ acc_prevspeed = vel;
+ acc_prevtime = time;
+
+ if(autocvar_hud_panel_physics_acceleration_movingaverage)
+ {
+ f = bound(0, f * 10, 1);
+ acc_avg = acc_avg * (1 - f) + acceleration * f;
+ acceleration = acc_avg;
+ }
+ }
+
+ int acc_decimals = 2;
+ if(time > physics_update_time)
+ {
+ // workaround for ftos_decimals returning a negative 0
+ if(discrete_acceleration > -1 / pow(10, acc_decimals) && discrete_acceleration < 0)
+ discrete_acceleration = 0;
+ discrete_acceleration = acceleration;
+ discrete_speed = speed;
+ physics_update_time += autocvar_hud_panel_physics_update_interval;
+ }
+
+ //compute layout
+ float panel_ar = panel_size.x/panel_size.y;
+ vector speed_offset = '0 0 0', acceleration_offset = '0 0 0';
+ if (panel_ar >= 5 && !acceleration_progressbar_scale)
+ {
+ panel_size.x *= 0.5;
+ if (autocvar_hud_panel_physics_flip)
+ speed_offset.x = panel_size.x;
+ else
+ acceleration_offset.x = panel_size.x;
+ }
+ else
+ {
+ panel_size.y *= 0.5;
+ if (autocvar_hud_panel_physics_flip)
+ speed_offset.y = panel_size.y;
+ else
+ acceleration_offset.y = panel_size.y;
+ }
+ int speed_baralign, acceleration_baralign;
+ if (autocvar_hud_panel_physics_baralign == 1)
+ acceleration_baralign = speed_baralign = 1;
+ else if(autocvar_hud_panel_physics_baralign == 4)
+ acceleration_baralign = speed_baralign = 2;
+ else if (autocvar_hud_panel_physics_flip)
+ {
+ acceleration_baralign = (autocvar_hud_panel_physics_baralign == 2);
+ speed_baralign = (autocvar_hud_panel_physics_baralign == 3);
+ }
+ else
+ {
+ speed_baralign = (autocvar_hud_panel_physics_baralign == 2);
+ acceleration_baralign = (autocvar_hud_panel_physics_baralign == 3);
+ }
+ if (autocvar_hud_panel_physics_acceleration_progressbar_mode == 0)
+ acceleration_baralign = 3; //override hud_panel_physics_baralign value for acceleration
+
+ //draw speed
+ if(speed)
+ if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
+ HUD_Panel_DrawProgressBar(panel_pos + speed_offset, panel_size, "progressbar", speed/max_speed, 0, speed_baralign, autocvar_hud_progressbar_speed_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ vector tmp_offset = '0 0 0', tmp_size = '0 0 0';
+ if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
+ {
+ tmp_size.x = panel_size.x * 0.75;
+ tmp_size.y = panel_size.y * text_scale;
+ if (speed_baralign)
+ tmp_offset.x = panel_size.x - tmp_size.x;
+ //else
+ //tmp_offset_x = 0;
+ tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
+ drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(discrete_speed), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ //draw speed unit
+ if (speed_baralign)
+ tmp_offset.x = 0;
+ else
+ tmp_offset.x = tmp_size.x;
+ if (autocvar_hud_panel_physics_speed_unit_show)
+ {
+ //tmp_offset_y = 0;
+ tmp_size.x = panel_size.x * (1 - 0.75);
+ tmp_size.y = panel_size.y * 0.4 * text_scale;
+ tmp_offset.y = (panel_size.y * 0.4 - tmp_size.y) / 2;
+ drawstring_aspect(panel_pos + speed_offset + tmp_offset, unit, tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ }
+
+ //compute and draw top speed
+ if (autocvar_hud_panel_physics_topspeed)
+ if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
+ {
+ if (autocvar__hud_configure)
+ {
+ top_speed = floor( max_speed * 0.75 + 0.5 );
+ f = 1;
+ }
+ else
+ {
+ if (speed >= top_speed)
+ {
+ top_speed = speed;
+ top_speed_time = time;
+ }
+ if (top_speed != 0)
+ {
+ f = max(1, autocvar_hud_panel_physics_topspeed_time);
+ // divide by f to make it start from 1
+ f = cos( ((time - top_speed_time) / f) * PI/2 );
+ }
+ else //hide top speed 0, it would be stupid
+ f = 0;
+ }
+ if (f > 0)
+ {
+ //top speed progressbar peak
+ if(speed < top_speed)
+ if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
+ {
+ float peak_offsetX;
+ vector peak_size = '0 0 0';
+ if (speed_baralign == 0)
+ peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x;
+ else if (speed_baralign == 1)
+ peak_offsetX = (1 - min(top_speed, max_speed)/max_speed) * panel_size.x;
+ else // if (speed_baralign == 2)
+ peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x * 0.5;
+ peak_size.x = floor(panel_size.x * 0.01 + 1.5);
+ peak_size.y = panel_size.y;
+ if (speed_baralign == 2) // draw two peaks, on both sides
+ {
+ drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x + peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x - peak_offsetX + peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ else
+ drawfill(panel_pos + speed_offset + eX * (peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ //top speed
+ tmp_offset.y = panel_size.y * 0.4;
+ tmp_size.x = panel_size.x * (1 - 0.75);
+ tmp_size.y = (panel_size.y - tmp_offset.y) * text_scale;
+ tmp_offset.y += (panel_size.y - tmp_offset.y - tmp_size.y) / 2;
+ drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(top_speed), tmp_size, '1 0 0', f * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ else
+ top_speed = 0;
+ }
+
+ //draw acceleration
+ if(acceleration)
+ if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 3)
+ {
+ vector progressbar_color;
+ if(acceleration < 0)
+ progressbar_color = autocvar_hud_progressbar_acceleration_neg_color;
+ else
+ progressbar_color = autocvar_hud_progressbar_acceleration_color;
+
+ f = acceleration/autocvar_hud_panel_physics_acceleration_max;
+ if (autocvar_hud_panel_physics_acceleration_progressbar_nonlinear)
+ f = (f >= 0 ? sqrt(f) : -sqrt(-f));
+
+ if (acceleration_progressbar_scale) // allow progressbar to go out of panel bounds
+ {
+ tmp_size = acceleration_progressbar_scale * panel_size.x * eX + panel_size.y * eY;
+
+ if (acceleration_baralign == 1)
+ tmp_offset.x = panel_size.x - tmp_size.x;
+ else if (acceleration_baralign == 2 || acceleration_baralign == 3)
+ tmp_offset.x = (panel_size.x - tmp_size.x) / 2;
+ else
+ tmp_offset.x = 0;
+ tmp_offset.y = 0;
+ }
+ else
+ {
+ tmp_size = panel_size;
+ tmp_offset = '0 0 0';
+ }
+
+ HUD_Panel_DrawProgressBar(panel_pos + acceleration_offset + tmp_offset, tmp_size, "accelbar", f, 0, acceleration_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ if(autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 3)
+ {
+ tmp_size.x = panel_size.x;
+ tmp_size.y = panel_size.y * text_scale;
+ tmp_offset.x = 0;
+ tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
+
+ drawstring_aspect(panel_pos + acceleration_offset + tmp_offset, strcat(ftos_decimals(discrete_acceleration, acc_decimals), "g"), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ draw_endBoldFont();
+}
--- /dev/null
+// Powerups (#2)
+
+// Powerup item fields (reusing existing fields)
+.string message; // Human readable name
+.string netname; // Icon name
+.vector colormod; // Color
+.float count; // Time left
+.float lifetime; // Maximum time
+
+entity powerupItems;
+int powerupItemsCount;
+
+void resetPowerupItems()
+{
+ entity item;
+ for(item = powerupItems; item; item = item.chain)
+ item.count = 0;
+
+ powerupItemsCount = 0;
+}
+
+void addPowerupItem(string name, string icon, vector color, float currentTime, float lifeTime)
+{
+ if(!powerupItems)
+ powerupItems = spawn();
+
+ entity item;
+ for(item = powerupItems; item.count; item = item.chain)
+ if(!item.chain)
+ item.chain = spawn();
+
+ item.message = name;
+ item.netname = icon;
+ item.colormod = color;
+ item.count = currentTime;
+ item.lifetime = lifeTime;
+
+ ++powerupItemsCount;
+}
+
+int getPowerupItemAlign(int align, int column, int row, int columns, int rows, bool isVertical)
+{
+ if(align < 2)
+ return align;
+
+ bool isTop = isVertical && rows > 1 && row == 0;
+ bool isBottom = isVertical && rows > 1 && row == rows-1;
+ bool isLeft = !isVertical && columns > 1 && column == 0;
+ bool isRight = !isVertical && columns > 1 && column == columns-1;
+
+ if(isTop || isLeft) return (align == 2) ? 1 : 0;
+ if(isBottom || isRight) return (align == 2) ? 0 : 1;
+
+ return 2;
+}
+
+void HUD_Powerups()
+{
+ int allItems = getstati(STAT_ITEMS, 0, 24);
+ int allBuffs = getstati(STAT_BUFFS, 0, 24);
+ int strengthTime, shieldTime, superTime;
+
+ // Initialize items
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_powerups) return;
+ if(spectatee_status == -1) return;
+ if(getstati(STAT_HEALTH) <= 0) return;
+ if(!(allItems & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON)) && !allBuffs) return;
+
+ strengthTime = bound(0, STAT(STRENGTH_FINISHED) - time, 99);
+ shieldTime = bound(0, STAT(INVINCIBLE_FINISHED) - time, 99);
+ superTime = bound(0, getstatf(STAT_SUPERWEAPONS_FINISHED) - time, 99);
+
+ if(allItems & IT_UNLIMITED_SUPERWEAPONS)
+ superTime = 99;
+
+ // Prevent stuff to show up on mismatch that will be fixed next frame
+ if(!(allItems & IT_SUPERWEAPON))
+ superTime = 0;
+ }
+ else
+ {
+ strengthTime = 15;
+ shieldTime = 27;
+ superTime = 13;
+ allBuffs = 0;
+ }
+
+ // Add items to linked list
+ resetPowerupItems();
+
+ if(strengthTime)
+ addPowerupItem("Strength", "strength", autocvar_hud_progressbar_strength_color, strengthTime, 30);
+ if(shieldTime)
+ addPowerupItem("Shield", "shield", autocvar_hud_progressbar_shield_color, shieldTime, 30);
+ if(superTime)
+ addPowerupItem("Superweapons", "superweapons", autocvar_hud_progressbar_superweapons_color, superTime, 30);
+
+ MUTATOR_CALLHOOK(HUD_Powerups_add);
+
+ if(!powerupItemsCount)
+ return;
+
+ // Draw panel background
+ HUD_Panel_UpdateCvars();
+ HUD_Panel_DrawBg(1);
+
+ // Set drawing area
+ vector pos = panel_pos;
+ vector size = panel_size;
+ bool isVertical = size.y > size.x;
+
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ size -= '2 2 0' * panel_bg_padding;
+ }
+
+ // Find best partitioning of the drawing area
+ const float DESIRED_ASPECT = 6;
+ float aspect = 0, a;
+ int columns = 0, c;
+ int rows = 0, r;
+ int i = 1;
+
+ do
+ {
+ c = floor(powerupItemsCount / i);
+ r = ceil(powerupItemsCount / c);
+ a = isVertical ? (size.y/r) / (size.x/c) : (size.x/c) / (size.y/r);
+
+ if(i == 1 || fabs(DESIRED_ASPECT - a) < fabs(DESIRED_ASPECT - aspect))
+ {
+ aspect = a;
+ columns = c;
+ rows = r;
+ }
+ }
+ while(++i <= powerupItemsCount);
+
+ // Prevent single items from getting too wide
+ if(powerupItemsCount == 1 && aspect > DESIRED_ASPECT)
+ {
+ if(isVertical)
+ {
+ size.y *= 0.5;
+ pos.y += size.y * 0.5;
+ }
+ else
+ {
+ size.x *= 0.5;
+ pos.x += size.x * 0.5;
+ }
+ }
+
+ // Draw items from linked list
+ vector itemPos = pos;
+ vector itemSize = eX * (size.x / columns) + eY * (size.y / rows);
+ vector textColor = '1 1 1';
+
+ int fullSeconds = 0;
+ int align = 0;
+ int column = 0;
+ int row = 0;
+
+ draw_beginBoldFont();
+ for(entity item = powerupItems; item.count; item = item.chain)
+ {
+ itemPos = eX * (pos.x + column * itemSize.x) + eY * (pos.y + row * itemSize.y);
+
+ // Draw progressbar
+ if(autocvar_hud_panel_powerups_progressbar)
+ {
+ align = getPowerupItemAlign(autocvar_hud_panel_powerups_baralign, column, row, columns, rows, isVertical);
+ HUD_Panel_DrawProgressBar(itemPos, itemSize, "progressbar", item.count / item.lifetime, isVertical, align, item.colormod, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ // Draw icon and text
+ if(autocvar_hud_panel_powerups_text)
+ {
+ align = getPowerupItemAlign(autocvar_hud_panel_powerups_iconalign, column, row, columns, rows, isVertical);
+ fullSeconds = ceil(item.count);
+ textColor = '0.6 0.6 0.6' + (item.colormod * 0.4);
+
+ if(item.count > 1)
+ DrawNumIcon(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha);
+ if(item.count <= 5)
+ DrawNumIcon_expanding(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha, bound(0, (fullSeconds - item.count) / 0.5, 1));
+ }
+
+ // Determine next section
+ if(isVertical)
+ {
+ if(++column >= columns)
+ {
+ column = 0;
+ ++row;
+ }
+ }
+ else
+ {
+ if(++row >= rows)
+ {
+ row = 0;
+ ++column;
+ }
+ }
+ }
+ draw_endBoldFont();
+}
--- /dev/null
+/** Draw pressed keys (#11) */
+void HUD_PressedKeys()
+{
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_pressedkeys) return;
+ if(spectatee_status <= 0 && autocvar_hud_panel_pressedkeys < 2) return;
+ }
+
+ HUD_Panel_UpdateCvars();
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(1);
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ // force custom aspect
+ float aspect = autocvar_hud_panel_pressedkeys_aspect;
+ if(aspect)
+ {
+ vector newSize = '0 0 0';
+ if(mySize.x/mySize.y > aspect)
+ {
+ newSize.x = aspect * mySize.y;
+ newSize.y = mySize.y;
+
+ pos.x = pos.x + (mySize.x - newSize.x) / 2;
+ }
+ else
+ {
+ newSize.y = 1/aspect * mySize.x;
+ newSize.x = mySize.x;
+
+ pos.y = pos.y + (mySize.y - newSize.y) / 2;
+ }
+ mySize = newSize;
+ }
+
+ vector keysize;
+ keysize = eX * mySize.x * (1/3.0) + eY * mySize.y * (1/(3.0 - !autocvar_hud_panel_pressedkeys_attack));
+ float pressedkeys;
+ pressedkeys = getstatf(STAT_PRESSED_KEYS);
+
+ if(autocvar_hud_panel_pressedkeys_attack)
+ {
+ drawpic_aspect_skin(pos + eX * keysize.x * 0.5, ((pressedkeys & KEY_ATCK) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawpic_aspect_skin(pos + eX * keysize.x * 1.5, ((pressedkeys & KEY_ATCK2) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += keysize.y;
+ }
+
+ drawpic_aspect_skin(pos, ((pressedkeys & KEY_CROUCH) ? "key_crouch_inv.tga" : "key_crouch.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawpic_aspect_skin(pos + eX * keysize.x, ((pressedkeys & KEY_FORWARD) ? "key_forward_inv.tga" : "key_forward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawpic_aspect_skin(pos + eX * keysize.x * 2, ((pressedkeys & KEY_JUMP) ? "key_jump_inv.tga" : "key_jump.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += keysize.y;
+ drawpic_aspect_skin(pos, ((pressedkeys & KEY_LEFT) ? "key_left_inv.tga" : "key_left.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawpic_aspect_skin(pos + eX * keysize.x, ((pressedkeys & KEY_BACKWARD) ? "key_backward_inv.tga" : "key_backward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawpic_aspect_skin(pos + eX * keysize.x * 2, ((pressedkeys & KEY_RIGHT) ? "key_right_inv.tga" : "key_right.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+}
--- /dev/null
+// QuickMenu (#23)
+
+#include "../../quickmenu.qc"
--- /dev/null
+/** Race timer (#8) */
+void HUD_RaceTimer ()
+{
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_racetimer) return;
+ if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
+ if(spectatee_status == -1) return;
+ }
+
+ HUD_Panel_UpdateCvars();
+
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(1);
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ // always force 4:1 aspect
+ vector newSize = '0 0 0';
+ if(mySize.x/mySize.y > 4)
+ {
+ newSize.x = 4 * mySize.y;
+ newSize.y = mySize.y;
+
+ pos.x = pos.x + (mySize.x - newSize.x) / 2;
+ }
+ else
+ {
+ newSize.y = 1/4 * mySize.x;
+ newSize.x = mySize.x;
+
+ pos.y = pos.y + (mySize.y - newSize.y) / 2;
+ }
+ mySize = newSize;
+
+ float a, t;
+ string s, forcetime;
+
+ if(autocvar__hud_configure)
+ {
+ s = "0:13:37";
+ draw_beginBoldFont();
+ drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.60 0.60 0' * mySize.y), s, '0.60 0.60 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ draw_endBoldFont();
+ s = _("^1Intermediate 1 (+15.42)");
+ drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.60 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
+ s = sprintf(_("^1PENALTY: %.1f (%s)"), 2, "missing a checkpoint");
+ drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.80 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ else if(race_checkpointtime)
+ {
+ a = bound(0, 2 - (time - race_checkpointtime), 1);
+ s = "";
+ forcetime = "";
+ if(a > 0) // just hit a checkpoint?
+ {
+ if(race_checkpoint != 254)
+ {
+ if(race_time && race_previousbesttime)
+ s = MakeRaceString(race_checkpoint, TIME_DECODE(race_time) - TIME_DECODE(race_previousbesttime), 0, 0, race_previousbestname);
+ else
+ s = MakeRaceString(race_checkpoint, 0, -1, 0, race_previousbestname);
+ if(race_time)
+ forcetime = TIME_ENCODED_TOSTRING(race_time);
+ }
+ }
+ else
+ {
+ if(race_laptime && race_nextbesttime && race_nextcheckpoint != 254)
+ {
+ a = bound(0, 2 - ((race_laptime + TIME_DECODE(race_nextbesttime)) - (time + TIME_DECODE(race_penaltyaccumulator))), 1);
+ if(a > 0) // next one?
+ {
+ s = MakeRaceString(race_nextcheckpoint, (time + TIME_DECODE(race_penaltyaccumulator)) - race_laptime, TIME_DECODE(race_nextbesttime), 0, race_nextbestname);
+ }
+ }
+ }
+
+ if(s != "" && a > 0)
+ {
+ drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ }
+
+ if(race_penaltytime)
+ {
+ a = bound(0, 2 - (time - race_penaltyeventtime), 1);
+ if(a > 0)
+ {
+ s = sprintf(_("^1PENALTY: %.1f (%s)"), race_penaltytime * 0.1, race_penaltyreason);
+ drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.8 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ }
+ }
+
+ draw_beginBoldFont();
+
+ if(forcetime != "")
+ {
+ a = bound(0, (time - race_checkpointtime) / 0.5, 1);
+ drawstring_expanding(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(forcetime, false, '1 1 0' * 0.6 * mySize.y), forcetime, '1 1 0' * 0.6 * mySize.y, '1 1 1', panel_fg_alpha, 0, a);
+ }
+ else
+ a = 1;
+
+ if(race_laptime && race_checkpoint != 255)
+ {
+ s = TIME_ENCODED_TOSTRING(TIME_ENCODE(time + TIME_DECODE(race_penaltyaccumulator) - race_laptime));
+ drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.6 0.6 0' * mySize.y), s, '0.6 0.6 0' * mySize.y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ }
+
+ draw_endBoldFont();
+ }
+ else
+ {
+ if(race_mycheckpointtime)
+ {
+ a = bound(0, 2 - (time - race_mycheckpointtime), 1);
+ s = MakeRaceString(race_mycheckpoint, TIME_DECODE(race_mycheckpointdelta), -(race_mycheckpointenemy == ""), race_mycheckpointlapsdelta, race_mycheckpointenemy);
+ drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ }
+ if(race_othercheckpointtime && race_othercheckpointenemy != "")
+ {
+ a = bound(0, 2 - (time - race_othercheckpointtime), 1);
+ s = MakeRaceString(race_othercheckpoint, -TIME_DECODE(race_othercheckpointdelta), -(race_othercheckpointenemy == ""), race_othercheckpointlapsdelta, race_othercheckpointenemy);
+ drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ }
+
+ if(race_penaltytime && !race_penaltyaccumulator)
+ {
+ t = race_penaltytime * 0.1 + race_penaltyeventtime;
+ a = bound(0, (1 + t - time), 1);
+ if(a > 0)
+ {
+ if(time < t)
+ s = sprintf(_("^1PENALTY: %.1f (%s)"), (t - time) * 0.1, race_penaltyreason);
+ else
+ s = sprintf(_("^2PENALTY: %.1f (%s)"), 0, race_penaltyreason);
+ drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ }
+ }
+ }
+}
--- /dev/null
+// Radar (#6)
+
+float HUD_Radar_Clickable()
+{
+ return hud_panel_radar_mouse && !hud_panel_radar_temp_hidden;
+}
+
+void HUD_Radar_Show_Maximized(bool doshow,float clickable)
+{
+ hud_panel_radar_maximized = doshow;
+ hud_panel_radar_temp_hidden = 0;
+
+ if ( doshow )
+ {
+ if (clickable)
+ {
+ if(autocvar_hud_cursormode)
+ setcursormode(1);
+ hud_panel_radar_mouse = 1;
+ }
+ }
+ else if ( hud_panel_radar_mouse )
+ {
+ hud_panel_radar_mouse = 0;
+ mouseClicked = 0;
+ if(autocvar_hud_cursormode)
+ if(!mv_active)
+ setcursormode(0);
+ }
+}
+void HUD_Radar_Hide_Maximized()
+{
+ HUD_Radar_Show_Maximized(false,false);
+}
+
+
+float HUD_Radar_InputEvent(float bInputType, float nPrimary, float nSecondary)
+{
+ if(!hud_panel_radar_maximized || !hud_panel_radar_mouse ||
+ autocvar__hud_configure || mv_active)
+ return false;
+
+ if(bInputType == 3)
+ {
+ mousepos_x = nPrimary;
+ mousepos_y = nSecondary;
+ return true;
+ }
+
+ if(nPrimary == K_MOUSE1)
+ {
+ if(bInputType == 0) // key pressed
+ mouseClicked |= S_MOUSE1;
+ else if(bInputType == 1) // key released
+ mouseClicked -= (mouseClicked & S_MOUSE1);
+ }
+ else if(nPrimary == K_MOUSE2)
+ {
+ if(bInputType == 0) // key pressed
+ mouseClicked |= S_MOUSE2;
+ else if(bInputType == 1) // key released
+ mouseClicked -= (mouseClicked & S_MOUSE2);
+ }
+ else if ( nPrimary == K_ESCAPE && bInputType == 0 )
+ {
+ HUD_Radar_Hide_Maximized();
+ }
+ else
+ {
+ // allow console/use binds to work without hiding the map
+ string con_keys;
+ float keys;
+ float i;
+ con_keys = strcat(findkeysforcommand("toggleconsole", 0)," ",findkeysforcommand("+use", 0)) ;
+ keys = tokenize(con_keys); // findkeysforcommand returns data for this
+ for (i = 0; i < keys; ++i)
+ {
+ if(nPrimary == stof(argv(i)))
+ return false;
+ }
+
+ if ( getstati(STAT_HEALTH) <= 0 )
+ {
+ // Show scoreboard
+ if ( bInputType < 2 )
+ {
+ con_keys = findkeysforcommand("+showscores", 0);
+ keys = tokenize(con_keys);
+ for (i = 0; i < keys; ++i)
+ {
+ if ( nPrimary == stof(argv(i)) )
+ {
+ hud_panel_radar_temp_hidden = bInputType == 0;
+ return false;
+ }
+ }
+ }
+ }
+ else if ( bInputType == 0 )
+ HUD_Radar_Hide_Maximized();
+
+ return false;
+ }
+
+ return true;
+}
+
+void HUD_Radar_Mouse()
+{
+ if ( !hud_panel_radar_mouse ) return;
+ if(mv_active) return;
+
+ if ( intermission )
+ {
+ HUD_Radar_Hide_Maximized();
+ return;
+ }
+
+ if(mouseClicked & S_MOUSE2)
+ {
+ HUD_Radar_Hide_Maximized();
+ return;
+ }
+
+ if(!autocvar_hud_cursormode)
+ {
+ mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
+
+ mousepos_x = bound(0, mousepos_x, vid_conwidth);
+ mousepos_y = bound(0, mousepos_y, vid_conheight);
+ }
+
+ HUD_Panel_UpdateCvars();
+
+
+ panel_size = autocvar_hud_panel_radar_maximized_size;
+ panel_size_x = bound(0.2, panel_size_x, 1) * vid_conwidth;
+ panel_size_y = bound(0.2, panel_size_y, 1) * vid_conheight;
+ panel_pos_x = (vid_conwidth - panel_size_x) / 2;
+ panel_pos_y = (vid_conheight - panel_size_y) / 2;
+
+ if(mouseClicked & S_MOUSE1)
+ {
+ // click outside
+ if ( mousepos_x < panel_pos_x || mousepos_x > panel_pos_x + panel_size_x ||
+ mousepos_y < panel_pos_y || mousepos_y > panel_pos_y + panel_size_y )
+ {
+ HUD_Radar_Hide_Maximized();
+ return;
+ }
+ vector pos = teamradar_texcoord_to_3dcoord(teamradar_2dcoord_to_texcoord(mousepos),view_origin_z);
+ localcmd(sprintf("cmd ons_spawn %f %f %f",pos_x,pos_y,pos_z));
+
+ HUD_Radar_Hide_Maximized();
+ return;
+ }
+
+
+ const vector cursor_size = '32 32 0';
+ drawpic(mousepos-'8 4 0', strcat("gfx/menu/", autocvar_menu_skin, "/cursor.tga"), cursor_size, '1 1 1', 0.8, DRAWFLAG_NORMAL);
+}
+
+void HUD_Radar()
+{
+ if (!autocvar__hud_configure)
+ {
+ if (hud_panel_radar_maximized)
+ {
+ if (!hud_draw_maximized) return;
+ }
+ else
+ {
+ if (autocvar_hud_panel_radar == 0) return;
+ if (autocvar_hud_panel_radar != 2 && !teamplay) return;
+ if(radar_panel_modified)
+ {
+ panel.update_time = time; // forces reload of panel attributes
+ radar_panel_modified = false;
+ }
+ }
+ }
+
+ if ( hud_panel_radar_temp_hidden )
+ return;
+
+ HUD_Panel_UpdateCvars();
+
+ float f = 0;
+
+ if (hud_panel_radar_maximized && !autocvar__hud_configure)
+ {
+ panel_size = autocvar_hud_panel_radar_maximized_size;
+ panel_size.x = bound(0.2, panel_size.x, 1) * vid_conwidth;
+ panel_size.y = bound(0.2, panel_size.y, 1) * vid_conheight;
+ panel_pos.x = (vid_conwidth - panel_size.x) / 2;
+ panel_pos.y = (vid_conheight - panel_size.y) / 2;
+
+ string panel_bg;
+ panel_bg = strcat(hud_skin_path, "/border_default"); // always use the default border when maximized
+ if(precache_pic(panel_bg) == "")
+ panel_bg = "gfx/hud/default/border_default"; // fallback
+ if(!radar_panel_modified && panel_bg != panel.current_panel_bg)
+ radar_panel_modified = true;
+ if(panel.current_panel_bg)
+ strunzone(panel.current_panel_bg);
+ panel.current_panel_bg = strzone(panel_bg);
+
+ switch(hud_panel_radar_maximized_zoommode)
+ {
+ default:
+ case 0:
+ f = current_zoomfraction;
+ break;
+ case 1:
+ f = 1 - current_zoomfraction;
+ break;
+ case 2:
+ f = 0;
+ break;
+ case 3:
+ f = 1;
+ break;
+ }
+
+ switch(hud_panel_radar_maximized_rotation)
+ {
+ case 0:
+ teamradar_angle = view_angles.y - 90;
+ break;
+ default:
+ teamradar_angle = 90 * hud_panel_radar_maximized_rotation;
+ break;
+ }
+ }
+ if (!hud_panel_radar_maximized && !autocvar__hud_configure)
+ {
+ switch(hud_panel_radar_zoommode)
+ {
+ default:
+ case 0:
+ f = current_zoomfraction;
+ break;
+ case 1:
+ f = 1 - current_zoomfraction;
+ break;
+ case 2:
+ f = 0;
+ break;
+ case 3:
+ f = 1;
+ break;
+ }
+
+ switch(hud_panel_radar_rotation)
+ {
+ case 0:
+ teamradar_angle = view_angles.y - 90;
+ break;
+ default:
+ teamradar_angle = 90 * hud_panel_radar_rotation;
+ break;
+ }
+ }
+
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(1);
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ int color2;
+ entity tm;
+ float scale2d, normalsize, bigsize;
+
+ teamradar_origin2d = pos + 0.5 * mySize;
+ teamradar_size2d = mySize;
+
+ if(minimapname == "")
+ return;
+
+ teamradar_loadcvars();
+
+ scale2d = vlen_maxnorm2d(mi_picmax - mi_picmin);
+ teamradar_size2d = mySize;
+
+ teamradar_extraclip_mins = teamradar_extraclip_maxs = '0 0 0'; // we always center
+
+ // pixels per world qu to match the teamradar_size2d_x range in the longest dimension
+ if((hud_panel_radar_rotation == 0 && !hud_panel_radar_maximized) || (hud_panel_radar_maximized_rotation == 0 && hud_panel_radar_maximized))
+ {
+ // max-min distance must fit the radar in any rotation
+ bigsize = vlen_minnorm2d(teamradar_size2d) * scale2d / (1.05 * vlen2d(mi_scale));
+ }
+ else
+ {
+ vector c0, c1, c2, c3, span;
+ c0 = rotate(mi_min, teamradar_angle * DEG2RAD);
+ c1 = rotate(mi_max, teamradar_angle * DEG2RAD);
+ c2 = rotate('1 0 0' * mi_min.x + '0 1 0' * mi_max.y, teamradar_angle * DEG2RAD);
+ c3 = rotate('1 0 0' * mi_max.x + '0 1 0' * mi_min.y, teamradar_angle * DEG2RAD);
+ span = '0 0 0';
+ span.x = max(c0_x, c1_x, c2_x, c3_x) - min(c0_x, c1_x, c2_x, c3_x);
+ span.y = max(c0_y, c1_y, c2_y, c3_y) - min(c0_y, c1_y, c2_y, c3_y);
+
+ // max-min distance must fit the radar in x=x, y=y
+ bigsize = min(
+ teamradar_size2d.x * scale2d / (1.05 * span.x),
+ teamradar_size2d.y * scale2d / (1.05 * span.y)
+ );
+ }
+
+ normalsize = vlen_maxnorm2d(teamradar_size2d) * scale2d / hud_panel_radar_scale;
+ if(bigsize > normalsize)
+ normalsize = bigsize;
+
+ teamradar_size =
+ f * bigsize
+ + (1 - f) * normalsize;
+ teamradar_origin3d_in_texcoord = teamradar_3dcoord_to_texcoord(
+ f * mi_center
+ + (1 - f) * view_origin);
+
+ drawsetcliparea(
+ pos.x,
+ pos.y,
+ mySize.x,
+ mySize.y
+ );
+
+ draw_teamradar_background(hud_panel_radar_foreground_alpha);
+
+ for(tm = world; (tm = find(tm, classname, "radarlink")); )
+ draw_teamradar_link(tm.origin, tm.velocity, tm.team);
+
+ vector coord;
+ vector brightcolor;
+ for(tm = world; (tm = findflags(tm, teamradar_icon, 0xFFFFFF)); )
+ {
+ if ( hud_panel_radar_mouse )
+ if ( tm.health > 0 )
+ if ( tm.team == myteam+1 )
+ {
+ coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(tm.origin));
+ if ( vlen(mousepos-coord) < 8 )
+ {
+ brightcolor_x = min(1,tm.teamradar_color_x*1.5);
+ brightcolor_y = min(1,tm.teamradar_color_y*1.5);
+ brightcolor_z = min(1,tm.teamradar_color_z*1.5);
+ drawpic(coord - '8 8 0', "gfx/teamradar_icon_glow", '16 16 0', brightcolor, panel_fg_alpha, 0);
+ }
+ }
+ entity icon = RadarIcons_from(tm.teamradar_icon);
+ draw_teamradar_icon(tm.origin, icon, tm, spritelookupcolor(tm, icon.netname, tm.teamradar_color), panel_fg_alpha);
+ }
+ for(tm = world; (tm = find(tm, classname, "entcs_receiver")); )
+ {
+ color2 = GetPlayerColor(tm.sv_entnum);
+ //if(color == NUM_SPECTATOR || color == color2)
+ draw_teamradar_player(tm.origin, tm.angles, Team_ColorRGB(color2));
+ }
+ draw_teamradar_player(view_origin, view_angles, '1 1 1');
+
+ drawresetcliparea();
+
+ if ( hud_panel_radar_mouse )
+ {
+ string message = "Click to select teleport destination";
+
+ if ( getstati(STAT_HEALTH) <= 0 )
+ {
+ message = "Click to select spawn location";
+ }
+
+ drawcolorcodedstring(pos + '0.5 0 0' * (mySize_x - stringwidth(message, true, hud_fontsize)) - '0 1 0' * hud_fontsize_y * 2,
+ message, hud_fontsize, hud_panel_radar_foreground_alpha, DRAWFLAG_NORMAL);
+
+ hud_panel_radar_bottom = pos_y + mySize_y + hud_fontsize_y;
+ }
+}
--- /dev/null
+// Score (#7)
+
+void HUD_UpdatePlayerTeams();
+void HUD_Score_Rankings(vector pos, vector mySize, entity me)
+{
+ float score;
+ entity tm = world, pl;
+ int SCOREPANEL_MAX_ENTRIES = 6;
+ float SCOREPANEL_ASPECTRATIO = 2;
+ int entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize.y/mySize.x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
+ vector fontsize = '1 1 0' * (mySize.y/entries);
+
+ vector rgb, score_color;
+ rgb = '1 1 1';
+ score_color = '1 1 1';
+
+ float name_size = mySize.x*0.75;
+ float spacing_size = mySize.x*0.04;
+ const float highlight_alpha = 0.2;
+ int i = 0, first_pl = 0;
+ bool me_printed = false;
+ string s;
+ if (autocvar__hud_configure)
+ {
+ float players_per_team = 0;
+ if (team_count)
+ {
+ // show team scores in the first line
+ float score_size = mySize.x / team_count;
+ players_per_team = max(2, ceil((entries - 1) / team_count));
+ for(i=0; i<team_count; ++i) {
+ if (i == floor((entries - 2) / players_per_team) || (entries == 1 && i == 0))
+ HUD_Panel_DrawHighlight(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(pos + eX * score_size * i, ftos(175 - 23*i), eX * score_size + eY * fontsize.y, Team_ColorRGB(ColorByTeam(i)) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ first_pl = 1;
+ pos.y += fontsize.y;
+ }
+ score = 10 + SCOREPANEL_MAX_ENTRIES * 3;
+ for (i=first_pl; i<entries; ++i)
+ {
+ //simulate my score is lower than all displayed players,
+ //so that I don't appear at all showing pure rankings.
+ //This is to better show the difference between the 2 ranking views
+ if (i == entries-1 && autocvar_hud_panel_score_rankings == 1)
+ {
+ rgb = '1 1 0';
+ drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ s = GetPlayerName(player_localnum);
+ score = 7;
+ }
+ else
+ {
+ s = sprintf(_("Player %d"), i + 1 - first_pl);
+ score -= 3;
+ }
+
+ if (team_count)
+ score_color = Team_ColorRGB(ColorByTeam(floor((i - first_pl) / players_per_team))) * 0.8;
+ s = textShortenToWidth(s, name_size, fontsize, stringwidth_colors);
+ drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(pos + eX * (name_size + spacing_size), ftos(score), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += fontsize.y;
+ }
+ return;
+ }
+
+ if (!scoreboard_fade_alpha) // the scoreboard too calls HUD_UpdatePlayerTeams
+ HUD_UpdatePlayerTeams();
+ if (team_count)
+ {
+ // show team scores in the first line
+ float score_size = mySize.x / team_count;
+ for(tm = teams.sort_next; tm; tm = tm.sort_next) {
+ if(tm.team == NUM_SPECTATOR)
+ continue;
+ if (tm.team == myteam)
+ drawfill(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores[ts_primary])), eX * score_size + eY * fontsize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+ ++i;
+ }
+ first_pl = 1;
+ pos.y += fontsize.y;
+ tm = teams.sort_next;
+ }
+ i = first_pl;
+
+ do
+ for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
+ {
+ if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
+ continue;
+
+ if (i == entries-1 && !me_printed && pl != me)
+ if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
+ {
+ for (pl = me.sort_next; pl; pl = pl.sort_next)
+ if (pl.team != NUM_SPECTATOR)
+ break;
+
+ if (pl)
+ rgb = '1 1 0'; //not last but not among the leading players: yellow
+ else
+ rgb = '1 0 0'; //last: red
+ pl = me;
+ }
+
+ if (pl == me)
+ {
+ if (i == first_pl)
+ rgb = '0 1 0'; //first: green
+ me_printed = true;
+ drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ if (team_count)
+ score_color = Team_ColorRGB(pl.team) * 0.8;
+ s = textShortenToWidth(GetPlayerName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
+ drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores[ps_primary])), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += fontsize.y;
+ ++i;
+ }
+ while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
+}
+
+void HUD_Score()
+{
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_score) return;
+ if(spectatee_status == -1 && (gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
+ }
+
+ HUD_Panel_UpdateCvars();
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(1);
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ float score, distribution = 0;
+ string sign;
+ vector distribution_color;
+ entity tm, pl, me;
+
+ me = playerslots[current_player];
+
+ if((scores_flags[ps_primary] & SFL_TIME) && !teamplay) { // race/cts record display on HUD
+ string timer, distrtimer;
+
+ pl = players.sort_next;
+ if(pl == me)
+ pl = pl.sort_next;
+ if(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)
+ if(pl.scores[ps_primary] == 0)
+ pl = world;
+
+ score = me.(scores[ps_primary]);
+ timer = TIME_ENCODED_TOSTRING(score);
+
+ draw_beginBoldFont();
+ if (pl && ((!(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)) || score)) {
+ // distribution display
+ distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
+
+ distrtimer = ftos_decimals(fabs(distribution/pow(10, TIME_DECIMALS)), TIME_DECIMALS);
+
+ if (distribution <= 0) {
+ distribution_color = '0 1 0';
+ sign = "-";
+ }
+ else {
+ distribution_color = '1 0 0';
+ sign = "+";
+ }
+ drawstring_aspect(pos + eX * 0.75 * mySize.x, strcat(sign, distrtimer), eX * 0.25 * mySize.x + eY * (1/3) * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ // race record display
+ if (distribution <= 0)
+ HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(pos, timer, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ draw_endBoldFont();
+ } else if (!teamplay) { // non-teamgames
+ if ((spectatee_status == -1 && !autocvar__hud_configure) || autocvar_hud_panel_score_rankings)
+ {
+ HUD_Score_Rankings(pos, mySize, me);
+ return;
+ }
+ // me vector := [team/connected frags id]
+ pl = players.sort_next;
+ if(pl == me)
+ pl = pl.sort_next;
+
+ if(autocvar__hud_configure)
+ distribution = 42;
+ else if(pl)
+ distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
+ else
+ distribution = 0;
+
+ score = me.(scores[ps_primary]);
+ if(autocvar__hud_configure)
+ score = 123;
+
+ if(distribution >= 5)
+ distribution_color = eY;
+ else if(distribution >= 0)
+ distribution_color = '1 1 1';
+ else if(distribution >= -5)
+ distribution_color = '1 1 0';
+ else
+ distribution_color = eX;
+
+ string distribution_str;
+ distribution_str = ftos(distribution);
+ draw_beginBoldFont();
+ if (distribution >= 0)
+ {
+ if (distribution > 0)
+ distribution_str = strcat("+", distribution_str);
+ HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(pos + eX * 0.75 * mySize.x, distribution_str, eX * 0.25 * mySize.x + eY * (1/3) * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ draw_endBoldFont();
+ } else { // teamgames
+ float row, column, rows = 0, columns = 0;
+ vector offset = '0 0 0';
+ vector score_pos, score_size; //for scores other than myteam
+ if(autocvar_hud_panel_score_rankings)
+ {
+ HUD_Score_Rankings(pos, mySize, me);
+ return;
+ }
+ if(spectatee_status == -1)
+ {
+ rows = HUD_GetRowCount(team_count, mySize, 3);
+ columns = ceil(team_count/rows);
+ score_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+
+ float newSize;
+ if(score_size.x/score_size.y > 3)
+ {
+ newSize = 3 * score_size.y;
+ offset.x = score_size.x - newSize;
+ pos.x += offset.x/2;
+ score_size.x = newSize;
+ }
+ else
+ {
+ newSize = 1/3 * score_size.x;
+ offset.y = score_size.y - newSize;
+ pos.y += offset.y/2;
+ score_size.y = newSize;
+ }
+ }
+ else
+ score_size = eX * mySize.x*(1/4) + eY * mySize.y*(1/3);
+
+ float max_fragcount;
+ max_fragcount = -99;
+ draw_beginBoldFont();
+ row = column = 0;
+ for(tm = teams.sort_next; tm; tm = tm.sort_next) {
+ if(tm.team == NUM_SPECTATOR)
+ continue;
+ score = tm.(teamscores[ts_primary]);
+ if(autocvar__hud_configure)
+ score = 123;
+
+ if (score > max_fragcount)
+ max_fragcount = score;
+
+ if (spectatee_status == -1)
+ {
+ score_pos = pos + eX * column * (score_size.x + offset.x) + eY * row * (score_size.y + offset.y);
+ if (max_fragcount == score)
+ HUD_Panel_DrawHighlight(score_pos, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(score_pos, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+ ++row;
+ if(row >= rows)
+ {
+ row = 0;
+ ++column;
+ }
+ }
+ else if(tm.team == myteam) {
+ if (max_fragcount == score)
+ HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+ } else {
+ if (max_fragcount == score)
+ HUD_Panel_DrawHighlight(pos + eX * 0.75 * mySize.x + eY * (1/3) * rows * mySize.y, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(pos + eX * 0.75 * mySize.x + eY * (1/3) * rows * mySize.y, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+ ++rows;
+ }
+ }
+ draw_endBoldFont();
+ }
+}
--- /dev/null
+void HUD_Timer()
+{
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_timer) return;
+ }
+
+ HUD_Panel_UpdateCvars();
+
+ draw_beginBoldFont();
+
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(1);
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ string timer;
+ float timelimit, elapsedTime, timeleft, minutesLeft;
+
+ timelimit = getstatf(STAT_TIMELIMIT);
+
+ timeleft = max(0, timelimit * 60 + STAT(GAMESTARTTIME) - time);
+ timeleft = ceil(timeleft);
+
+ minutesLeft = floor(timeleft / 60);
+
+ vector timer_color;
+ if(minutesLeft >= 5 || warmup_stage || timelimit == 0) //don't use red or yellow in warmup or when there is no timelimit
+ timer_color = '1 1 1'; //white
+ else if(minutesLeft >= 1)
+ timer_color = '1 1 0'; //yellow
+ else
+ timer_color = '1 0 0'; //red
+
+ if (autocvar_hud_panel_timer_increment || timelimit == 0 || warmup_stage) {
+ if (time < STAT(GAMESTARTTIME)) {
+ //while restart is still active, show 00:00
+ timer = seconds_tostring(0);
+ } else {
+ elapsedTime = floor(time - STAT(GAMESTARTTIME)); //127
+ timer = seconds_tostring(elapsedTime);
+ }
+ } else {
+ timer = seconds_tostring(timeleft);
+ }
+
+ drawstring_aspect(pos, timer, mySize, timer_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ draw_endBoldFont();
+}
--- /dev/null
+/** Vote window (#9) */
+void HUD_Vote()
+{
+ if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
+ {
+ vote_active = 1;
+ if (autocvar__hud_configure)
+ {
+ vote_yescount = 0;
+ vote_nocount = 0;
+ LOG_INFO(_("^1You must answer before entering hud configure mode\n"));
+ cvar_set("_hud_configure", "0");
+ }
+ if(vote_called_vote)
+ strunzone(vote_called_vote);
+ vote_called_vote = strzone(_("^2Name ^7instead of \"^1Anonymous player^7\" in stats"));
+ uid2name_dialog = 1;
+ }
+
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_vote) return;
+
+ panel_fg_alpha = autocvar_hud_panel_fg_alpha;
+ panel_bg_alpha_str = autocvar_hud_panel_vote_bg_alpha;
+
+ if(panel_bg_alpha_str == "") {
+ panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha);
+ }
+ panel_bg_alpha = stof(panel_bg_alpha_str);
+ }
+ else
+ {
+ vote_yescount = 3;
+ vote_nocount = 2;
+ vote_needed = 4;
+ }
+
+ string s;
+ float a;
+ if(vote_active != vote_prev) {
+ vote_change = time;
+ vote_prev = vote_active;
+ }
+
+ if(vote_active || autocvar__hud_configure)
+ vote_alpha = bound(0, (time - vote_change) * 2, 1);
+ else
+ vote_alpha = bound(0, 1 - (time - vote_change) * 2, 1);
+
+ if(!vote_alpha)
+ return;
+
+ HUD_Panel_UpdateCvars();
+
+ if(uid2name_dialog)
+ {
+ panel_pos = eX * 0.3 * vid_conwidth + eY * 0.1 * vid_conheight;
+ panel_size = eX * 0.4 * vid_conwidth + eY * 0.3 * vid_conheight;
+ }
+
+ // these must be below above block
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ a = vote_alpha * (vote_highlighted ? autocvar_hud_panel_vote_alreadyvoted_alpha : 1);
+ HUD_Panel_DrawBg(a);
+ a = panel_fg_alpha * a;
+
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ // always force 3:1 aspect
+ vector newSize = '0 0 0';
+ if(mySize.x/mySize.y > 3)
+ {
+ newSize.x = 3 * mySize.y;
+ newSize.y = mySize.y;
+
+ pos.x = pos.x + (mySize.x - newSize.x) / 2;
+ }
+ else
+ {
+ newSize.y = 1/3 * mySize.x;
+ newSize.x = mySize.x;
+
+ pos.y = pos.y + (mySize.y - newSize.y) / 2;
+ }
+ mySize = newSize;
+
+ s = _("A vote has been called for:");
+ if(uid2name_dialog)
+ s = _("Allow servers to store and display your name?");
+ drawstring_aspect(pos, s, eX * mySize.x + eY * (2/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+ s = textShortenToWidth(vote_called_vote, mySize.x, '1 1 0' * mySize.y * (1/8), stringwidth_colors);
+ if(autocvar__hud_configure)
+ s = _("^1Configure the HUD");
+ drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize.y, s, eX * mySize.x + eY * (1.75/8) * mySize.y, a, DRAWFLAG_NORMAL);
+
+ // print the yes/no counts
+ s = sprintf(_("Yes (%s): %d"), getcommandkey("vyes", "vyes"), vote_yescount);
+ drawstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '0 1 0', a, DRAWFLAG_NORMAL);
+ s = sprintf(_("No (%s): %d"), getcommandkey("vno", "vno"), vote_nocount);
+ drawstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '1 0 0', a, DRAWFLAG_NORMAL);
+
+ // draw the progress bar backgrounds
+ drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_back", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+
+ // draw the highlights
+ if(vote_highlighted == 1) {
+ drawsetcliparea(pos.x, pos.y, mySize.x * 0.5, mySize.y);
+ drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+ }
+ else if(vote_highlighted == -1) {
+ drawsetcliparea(pos.x + 0.5 * mySize.x, pos.y, mySize.x * 0.5, mySize.y);
+ drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+ }
+
+ // draw the progress bars
+ if(vote_yescount && vote_needed)
+ {
+ drawsetcliparea(pos.x, pos.y, mySize.x * 0.5 * (vote_yescount/vote_needed), mySize.y);
+ drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+ }
+
+ if(vote_nocount && vote_needed)
+ {
+ drawsetcliparea(pos.x + mySize.x - mySize.x * 0.5 * (vote_nocount/vote_needed), pos.y, mySize.x * 0.5, mySize.y);
+ drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+ }
+
+ drawresetcliparea();
+}
--- /dev/null
+// Weapon icons (#0)
+
+entity weaponorder[Weapons_MAX];
+void weaponorder_swap(int i, int j, entity pass)
+{
+ entity h = weaponorder[i];
+ weaponorder[i] = weaponorder[j];
+ weaponorder[j] = h;
+}
+
+string weaponorder_cmp_str;
+int weaponorder_cmp(int i, int j, entity pass)
+{
+ int ai, aj;
+ ai = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[i].weapon), 0);
+ aj = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[j].weapon), 0);
+ return aj - ai; // the string is in REVERSE order (higher prio at the right is what we want, but higher prio first is the string)
+}
+
+void HUD_Weapons()
+{
+ SELFPARAM();
+ // declarations
+ WepSet weapons_stat = WepSet_GetFromStat();
+ int i;
+ float f, a;
+ float screen_ar;
+ vector center = '0 0 0';
+ int weapon_count, weapon_id;
+ int row, column, rows = 0, columns = 0;
+ bool vertical_order = true;
+ float aspect = autocvar_hud_panel_weapons_aspect;
+
+ float timeout = autocvar_hud_panel_weapons_timeout;
+ float timein_effect_length = autocvar_hud_panel_weapons_timeout_speed_in; //? 0.375 : 0);
+ float timeout_effect_length = autocvar_hud_panel_weapons_timeout_speed_out; //? 0.75 : 0);
+
+ vector barsize = '0 0 0', baroffset = '0 0 0';
+ vector ammo_color = '1 0 1';
+ float ammo_alpha = 1;
+
+ float when = max(1, autocvar_hud_panel_weapons_complainbubble_time);
+ float fadetime = max(0, autocvar_hud_panel_weapons_complainbubble_fadetime);
+
+ vector weapon_pos, weapon_size = '0 0 0';
+ vector color;
+
+ // check to see if we want to continue
+ if(hud != HUD_NORMAL) return;
+
+ if(!autocvar__hud_configure)
+ {
+ if((!autocvar_hud_panel_weapons) || (spectatee_status == -1))
+ return;
+ if(timeout && time >= weapontime + timeout + timeout_effect_length)
+ if(autocvar_hud_panel_weapons_timeout_effect == 3 || (autocvar_hud_panel_weapons_timeout_effect == 1 && !(autocvar_hud_panel_weapons_timeout_fadebgmin + autocvar_hud_panel_weapons_timeout_fadefgmin)))
+ {
+ weaponprevtime = time;
+ return;
+ }
+ }
+
+ // update generic hud functions
+ HUD_Panel_UpdateCvars();
+
+ // figure out weapon order (how the weapons are sorted) // TODO make this configurable
+ if(weaponorder_bypriority != autocvar_cl_weaponpriority || !weaponorder[0])
+ {
+ int weapon_cnt;
+ if(weaponorder_bypriority)
+ strunzone(weaponorder_bypriority);
+ if(weaponorder_byimpulse)
+ strunzone(weaponorder_byimpulse);
+
+ weaponorder_bypriority = strzone(autocvar_cl_weaponpriority);
+ weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(W_FixWeaponOrder_ForceComplete(W_NumberWeaponOrder(weaponorder_bypriority))));
+ weaponorder_cmp_str = strcat(" ", weaponorder_byimpulse, " ");
+
+ weapon_cnt = 0;
+ for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+ {
+ setself(get_weaponinfo(i));
+ if(self.impulse >= 0)
+ {
+ weaponorder[weapon_cnt] = self;
+ ++weapon_cnt;
+ }
+ }
+ for(i = weapon_cnt; i < Weapons_MAX; ++i)
+ weaponorder[i] = world;
+ heapsort(weapon_cnt, weaponorder_swap, weaponorder_cmp, world);
+
+ weaponorder_cmp_str = string_null;
+ }
+
+ if(!autocvar_hud_panel_weapons_complainbubble || autocvar__hud_configure || time - complain_weapon_time >= when + fadetime)
+ complain_weapon = 0;
+
+ if(autocvar__hud_configure)
+ {
+ if(!weapons_stat)
+ for(i = WEP_FIRST; i <= WEP_LAST; i += floor((WEP_LAST-WEP_FIRST)/5))
+ weapons_stat |= WepSet_FromWeapon(i);
+
+ #if 0
+ /// debug code
+ if(cvar("wep_add"))
+ {
+ weapons_stat = '0 0 0';
+ float countw = 1 + floor((floor(time * cvar("wep_add"))) % (Weapons_COUNT - 1));
+ for(i = WEP_FIRST; i <= countw; ++i)
+ weapons_stat |= WepSet_FromWeapon(i);
+ }
+ #endif
+ }
+
+ // determine which weapons are going to be shown
+ if (autocvar_hud_panel_weapons_onlyowned)
+ {
+ if(autocvar__hud_configure)
+ {
+ if(menu_enabled != 2)
+ HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
+ }
+
+ // do we own this weapon?
+ weapon_count = 0;
+ for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
+ if((weapons_stat & WepSet_FromWeapon(weaponorder[i].weapon)) || (weaponorder[i].weapon == complain_weapon))
+ ++weapon_count;
+
+
+ // might as well commit suicide now, no reason to live ;)
+ if (weapon_count == 0)
+ return;
+
+ vector old_panel_size = panel_size;
+ vector padded_panel_size = panel_size - '2 2 0' * panel_bg_padding;
+
+ // get the all-weapons layout
+ int nHidden = 0;
+ WepSet weapons_stat = WepSet_GetFromStat();
+ for (int i = WEP_FIRST; i <= WEP_LAST; ++i) {
+ WepSet weapons_wep = WepSet_FromWeapon(i);
+ if (weapons_stat & weapons_wep) continue;
+ Weapon w = get_weaponinfo(i);
+ if (w.spawnflags & WEP_FLAG_MUTATORBLOCKED) nHidden += 1;
+ }
+ vector table_size = HUD_GetTableSize_BestItemAR((Weapons_COUNT - 1) - nHidden, padded_panel_size, aspect);
+ columns = table_size.x;
+ rows = table_size.y;
+ weapon_size.x = padded_panel_size.x / columns;
+ weapon_size.y = padded_panel_size.y / rows;
+
+ // NOTE: although weapons should aways look the same even if onlyowned is enabled,
+ // we enlarge them a bit when possible to better match the desired aspect ratio
+ if(padded_panel_size.x / padded_panel_size.y < aspect)
+ {
+ // maximum number of rows that allows to display items with the desired aspect ratio
+ int max_rows = floor(padded_panel_size.y / (weapon_size.x / aspect));
+ columns = min(columns, ceil(weapon_count / max_rows));
+ rows = ceil(weapon_count / columns);
+ weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
+ weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
+ vertical_order = false;
+ }
+ else
+ {
+ int max_columns = floor(padded_panel_size.x / (weapon_size.y * aspect));
+ rows = min(rows, ceil(weapon_count / max_columns));
+ columns = ceil(weapon_count / rows);
+ weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
+ weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
+ vertical_order = true;
+ }
+
+ // reduce size of the panel
+ panel_size.x = columns * weapon_size.x;
+ panel_size.y = rows * weapon_size.y;
+ panel_size += '2 2 0' * panel_bg_padding;
+
+ // center the resized panel, or snap it to the screen edge when close enough
+ if(panel_pos.x > vid_conwidth * 0.001)
+ {
+ if(panel_pos.x + old_panel_size.x > vid_conwidth * 0.999)
+ panel_pos.x += old_panel_size.x - panel_size.x;
+ else
+ panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
+ }
+ else if(old_panel_size.x > vid_conwidth * 0.999)
+ panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
+
+ if(panel_pos.y > vid_conheight * 0.001)
+ {
+ if(panel_pos.y + old_panel_size.y > vid_conheight * 0.999)
+ panel_pos.y += old_panel_size.y - panel_size.y;
+ else
+ panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
+ }
+ else if(old_panel_size.y > vid_conheight * 0.999)
+ panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
+ }
+ else
+ weapon_count = (Weapons_COUNT - 1);
+
+ // animation for fading in/out the panel respectively when not in use
+ if(!autocvar__hud_configure)
+ {
+ if (timeout && time >= weapontime + timeout) // apply timeout effect if needed
+ {
+ f = bound(0, (time - (weapontime + timeout)) / timeout_effect_length, 1);
+
+ // fade the panel alpha
+ if(autocvar_hud_panel_weapons_timeout_effect == 1)
+ {
+ panel_bg_alpha *= (autocvar_hud_panel_weapons_timeout_fadebgmin * f + (1 - f));
+ panel_fg_alpha *= (autocvar_hud_panel_weapons_timeout_fadefgmin * f + (1 - f));
+ }
+ else if(autocvar_hud_panel_weapons_timeout_effect == 3)
+ {
+ panel_bg_alpha *= (1 - f);
+ panel_fg_alpha *= (1 - f);
+ }
+
+ // move the panel off the screen
+ if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
+ {
+ f *= f; // for a cooler movement
+ center.x = panel_pos.x + panel_size.x/2;
+ center.y = panel_pos.y + panel_size.y/2;
+ screen_ar = vid_conwidth/vid_conheight;
+ if (center.x/center.y < screen_ar) //bottom left
+ {
+ if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
+ panel_pos.y += f * (vid_conheight - panel_pos.y);
+ else //left
+ panel_pos.x -= f * (panel_pos.x + panel_size.x);
+ }
+ else //top right
+ {
+ if ((vid_conwidth - center.x)/center.y < screen_ar) //right
+ panel_pos.x += f * (vid_conwidth - panel_pos.x);
+ else //top
+ panel_pos.y -= f * (panel_pos.y + panel_size.y);
+ }
+ if(f == 1)
+ center.x = -1; // mark the panel as off screen
+ }
+ weaponprevtime = time - (1 - f) * timein_effect_length;
+ }
+ else if (timeout && time < weaponprevtime + timein_effect_length) // apply timein effect if needed
+ {
+ f = bound(0, (time - weaponprevtime) / timein_effect_length, 1);
+
+ // fade the panel alpha
+ if(autocvar_hud_panel_weapons_timeout_effect == 1)
+ {
+ panel_bg_alpha *= (autocvar_hud_panel_weapons_timeout_fadebgmin * (1 - f) + f);
+ panel_fg_alpha *= (autocvar_hud_panel_weapons_timeout_fadefgmin * (1 - f) + f);
+ }
+ else if(autocvar_hud_panel_weapons_timeout_effect == 3)
+ {
+ panel_bg_alpha *= (f);
+ panel_fg_alpha *= (f);
+ }
+
+ // move the panel back on screen
+ if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
+ {
+ f *= f; // for a cooler movement
+ f = 1 - f;
+ center.x = panel_pos.x + panel_size.x/2;
+ center.y = panel_pos.y + panel_size.y/2;
+ screen_ar = vid_conwidth/vid_conheight;
+ if (center.x/center.y < screen_ar) //bottom left
+ {
+ if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
+ panel_pos.y += f * (vid_conheight - panel_pos.y);
+ else //left
+ panel_pos.x -= f * (panel_pos.x + panel_size.x);
+ }
+ else //top right
+ {
+ if ((vid_conwidth - center.x)/center.y < screen_ar) //right
+ panel_pos.x += f * (vid_conwidth - panel_pos.x);
+ else //top
+ panel_pos.y -= f * (panel_pos.y + panel_size.y);
+ }
+ }
+ }
+ }
+
+ // draw the background, then change the virtual size of it to better fit other items inside
+ HUD_Panel_DrawBg(1);
+
+ if(center.x == -1)
+ return;
+
+ if(panel_bg_padding)
+ {
+ panel_pos += '1 1 0' * panel_bg_padding;
+ panel_size -= '2 2 0' * panel_bg_padding;
+ }
+
+ // after the sizing and animations are done, update the other values
+
+ if(!rows) // if rows is > 0 onlyowned code has already updated these vars
+ {
+ vector table_size = HUD_GetTableSize_BestItemAR((Weapons_COUNT - 1), panel_size, aspect);
+ columns = table_size.x;
+ rows = table_size.y;
+ weapon_size.x = panel_size.x / columns;
+ weapon_size.y = panel_size.y / rows;
+ vertical_order = (panel_size.x / panel_size.y >= aspect);
+ }
+
+ // calculate position/size for visual bar displaying ammount of ammo status
+ if (autocvar_hud_panel_weapons_ammo)
+ {
+ ammo_color = stov(autocvar_hud_panel_weapons_ammo_color);
+ ammo_alpha = panel_fg_alpha * autocvar_hud_panel_weapons_ammo_alpha;
+
+ if(weapon_size.x/weapon_size.y > aspect)
+ {
+ barsize.x = aspect * weapon_size.y;
+ barsize.y = weapon_size.y;
+ baroffset.x = (weapon_size.x - barsize.x) / 2;
+ }
+ else
+ {
+ barsize.y = 1/aspect * weapon_size.x;
+ barsize.x = weapon_size.x;
+ baroffset.y = (weapon_size.y - barsize.y) / 2;
+ }
+ }
+ if(autocvar_hud_panel_weapons_accuracy)
+ Accuracy_LoadColors();
+
+ // draw items
+ row = column = 0;
+ vector label_size = '1 1 0' * min(weapon_size.x, weapon_size.y) * bound(0, autocvar_hud_panel_weapons_label_scale, 1);
+ vector noncurrent_pos = '0 0 0';
+ vector noncurrent_size = weapon_size * bound(0, autocvar_hud_panel_weapons_noncurrent_scale, 1);
+ float noncurrent_alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_weapons_noncurrent_alpha, 1);
+ bool isCurrent;
+
+ for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
+ {
+ // retrieve information about the current weapon to be drawn
+ setself(weaponorder[i]);
+ weapon_id = self.impulse;
+ isCurrent = (self.weapon == switchweapon);
+
+ // skip if this weapon doesn't exist
+ if(!self || weapon_id < 0) { continue; }
+
+ // skip this weapon if we don't own it (and onlyowned is enabled)-- or if weapons_complainbubble is showing for this weapon
+ if(autocvar_hud_panel_weapons_onlyowned)
+ if (!((weapons_stat & WepSet_FromWeapon(self.weapon)) || (self.weapon == complain_weapon)))
+ continue;
+
+ // figure out the drawing position of weapon
+ weapon_pos = (panel_pos + eX * column * weapon_size.x + eY * row * weapon_size.y);
+ noncurrent_pos.x = weapon_pos.x + (weapon_size.x - noncurrent_size.x) / 2;
+ noncurrent_pos.y = weapon_pos.y + (weapon_size.y - noncurrent_size.y) / 2;
+
+ // draw background behind currently selected weapon
+ if(isCurrent)
+ drawpic_aspect_skin(weapon_pos, "weapon_current_bg", weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ // draw the weapon accuracy
+ if(autocvar_hud_panel_weapons_accuracy)
+ {
+ float panel_weapon_accuracy = weapon_accuracy[self.weapon-WEP_FIRST];
+ if(panel_weapon_accuracy >= 0)
+ {
+ color = Accuracy_GetColor(panel_weapon_accuracy);
+ drawpic_aspect_skin(weapon_pos, "weapon_accuracy", weapon_size, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ }
+
+ // drawing all the weapon items
+ if(weapons_stat & WepSet_FromWeapon(self.weapon))
+ {
+ // draw the weapon image
+ if(isCurrent)
+ drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ else
+ drawpic_aspect_skin(noncurrent_pos, self.model2, noncurrent_size, '1 1 1', noncurrent_alpha, DRAWFLAG_NORMAL);
+
+ // draw weapon label string
+ switch(autocvar_hud_panel_weapons_label)
+ {
+ case 1: // weapon number
+ drawstring(weapon_pos, ftos(weapon_id), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ break;
+
+ case 2: // bind
+ drawstring(weapon_pos, getcommandkey(ftos(weapon_id), strcat("weapon_group_", ftos(weapon_id))), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ break;
+
+ case 3: // weapon name
+ drawstring(weapon_pos, strtolower(self.m_name), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ break;
+
+ default: // nothing
+ break;
+ }
+
+ // draw ammo status bar
+ if(autocvar_hud_panel_weapons_ammo && (self.ammo_field != ammo_none))
+ {
+ float ammo_full;
+ a = getstati(GetAmmoStat(self.ammo_field)); // how much ammo do we have?
+
+ if(a > 0)
+ {
+ switch(self.ammo_field)
+ {
+ case ammo_shells: ammo_full = autocvar_hud_panel_weapons_ammo_full_shells; break;
+ case ammo_nails: ammo_full = autocvar_hud_panel_weapons_ammo_full_nails; break;
+ case ammo_rockets: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
+ case ammo_cells: ammo_full = autocvar_hud_panel_weapons_ammo_full_cells; break;
+ case ammo_plasma: ammo_full = autocvar_hud_panel_weapons_ammo_full_plasma; break;
+ case ammo_fuel: ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel; break;
+ default: ammo_full = 60;
+ }
+
+ drawsetcliparea(
+ weapon_pos.x + baroffset.x,
+ weapon_pos.y + baroffset.y,
+ barsize.x * bound(0, a/ammo_full, 1),
+ barsize.y
+ );
+
+ drawpic_aspect_skin(
+ weapon_pos,
+ "weapon_ammo",
+ weapon_size,
+ ammo_color,
+ ammo_alpha,
+ DRAWFLAG_NORMAL
+ );
+
+ drawresetcliparea();
+ }
+ }
+ }
+ else // draw a "ghost weapon icon" if you don't have the weapon
+ {
+ drawpic_aspect_skin(noncurrent_pos, self.model2, noncurrent_size, '0.2 0.2 0.2', panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
+ }
+
+ // draw the complain message
+ if(self.weapon == complain_weapon)
+ {
+ if(fadetime)
+ a = ((complain_weapon_time + when > time) ? 1 : bound(0, (complain_weapon_time + when + fadetime - time) / fadetime, 1));
+ else
+ a = ((complain_weapon_time + when > time) ? 1 : 0);
+
+ string s;
+ if(complain_weapon_type == 0) {
+ s = _("Out of ammo");
+ color = stov(autocvar_hud_panel_weapons_complainbubble_color_outofammo);
+ }
+ else if(complain_weapon_type == 1) {
+ s = _("Don't have");
+ color = stov(autocvar_hud_panel_weapons_complainbubble_color_donthave);
+ }
+ else {
+ s = _("Unavailable");
+ color = stov(autocvar_hud_panel_weapons_complainbubble_color_unavailable);
+ }
+ float padding = autocvar_hud_panel_weapons_complainbubble_padding;
+ drawpic_aspect_skin(weapon_pos + '1 1 0' * padding, "weapon_complainbubble", weapon_size - '2 2 0' * padding, color, a * panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(weapon_pos + '1 1 0' * padding, s, weapon_size - '2 2 0' * padding, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ }
+
+ #if 0
+ /// debug code
+ if(!autocvar_hud_panel_weapons_onlyowned)
+ {
+ drawfill(weapon_pos + '1 1 0', weapon_size - '2 2 0', '1 1 1', panel_fg_alpha * 0.2, DRAWFLAG_NORMAL);
+ drawstring(weapon_pos, ftos(i + 1), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ #endif
+
+ // continue with new position for the next weapon
+ if(vertical_order)
+ {
+ ++column;
+ if(column >= columns)
+ {
+ column = 0;
+ ++row;
+ }
+ }
+ else
+ {
+ ++row;
+ if(row >= rows)
+ {
+ row = 0;
+ ++column;
+ }
+ }
+ }
+}
+++ /dev/null
-#include "hud_config.qh"
-
-#include "hud.qh"
-
-#define HUD_Write(s) fputs(fh, s)
-// q: quoted, n: not quoted
-#define HUD_Write_Cvar_n(cvar) HUD_Write(strcat("seta ", cvar, " ", cvar_string(cvar), "\n"))
-#define HUD_Write_Cvar_q(cvar) HUD_Write(strcat("seta ", cvar, " \"", cvar_string(cvar), "\"\n"))
-#define HUD_Write_PanelCvar_n(cvar_suf) HUD_Write_Cvar_n(strcat("hud_panel_", panel.panel_name, cvar_suf))
-#define HUD_Write_PanelCvar_q(cvar_suf) HUD_Write_Cvar_q(strcat("hud_panel_", panel.panel_name, cvar_suf))
-// Save the config
-void HUD_Panel_ExportCfg(string cfgname)
-{
- float fh;
- string filename = strcat("hud_", autocvar_hud_skin, "_", cfgname, ".cfg");
- fh = fopen(filename, FILE_WRITE);
- if(fh >= 0)
- {
- HUD_Write_Cvar_q("hud_skin");
- HUD_Write_Cvar_q("hud_panel_bg");
- HUD_Write_Cvar_q("hud_panel_bg_color");
- HUD_Write_Cvar_q("hud_panel_bg_color_team");
- HUD_Write_Cvar_q("hud_panel_bg_alpha");
- HUD_Write_Cvar_q("hud_panel_bg_border");
- HUD_Write_Cvar_q("hud_panel_bg_padding");
- HUD_Write_Cvar_q("hud_panel_fg_alpha");
- HUD_Write("\n");
-
- HUD_Write_Cvar_q("hud_dock");
- HUD_Write_Cvar_q("hud_dock_color");
- HUD_Write_Cvar_q("hud_dock_color_team");
- HUD_Write_Cvar_q("hud_dock_alpha");
- HUD_Write("\n");
-
- HUD_Write_Cvar_q("hud_progressbar_alpha");
- HUD_Write_Cvar_q("hud_progressbar_strength_color");
- HUD_Write_Cvar_q("hud_progressbar_shield_color");
- HUD_Write_Cvar_q("hud_progressbar_health_color");
- HUD_Write_Cvar_q("hud_progressbar_armor_color");
- HUD_Write_Cvar_q("hud_progressbar_fuel_color");
- HUD_Write_Cvar_q("hud_progressbar_nexball_color");
- HUD_Write_Cvar_q("hud_progressbar_speed_color");
- HUD_Write_Cvar_q("hud_progressbar_acceleration_color");
- HUD_Write_Cvar_q("hud_progressbar_acceleration_neg_color");
- HUD_Write("\n");
-
- HUD_Write_Cvar_q("_hud_panelorder");
- HUD_Write("\n");
-
- HUD_Write_Cvar_q("hud_configure_grid");
- HUD_Write_Cvar_q("hud_configure_grid_xsize");
- HUD_Write_Cvar_q("hud_configure_grid_ysize");
- HUD_Write("\n");
-
- // common cvars for all panels
- for (int i = 0; i < hud_panels_COUNT; ++i)
- {
- panel = hud_panels[i];
-
- HUD_Write_PanelCvar_n("");
- HUD_Write_PanelCvar_q("_pos");
- HUD_Write_PanelCvar_q("_size");
- HUD_Write_PanelCvar_q("_bg");
- HUD_Write_PanelCvar_q("_bg_color");
- HUD_Write_PanelCvar_q("_bg_color_team");
- HUD_Write_PanelCvar_q("_bg_alpha");
- HUD_Write_PanelCvar_q("_bg_border");
- HUD_Write_PanelCvar_q("_bg_padding");
- switch(panel) {
- case HUD_PANEL_WEAPONS:
- HUD_Write_PanelCvar_q("_accuracy");
- HUD_Write_PanelCvar_q("_label");
- HUD_Write_PanelCvar_q("_label_scale");
- HUD_Write_PanelCvar_q("_complainbubble");
- HUD_Write_PanelCvar_q("_complainbubble_padding");
- HUD_Write_PanelCvar_q("_complainbubble_time");
- HUD_Write_PanelCvar_q("_complainbubble_fadetime");
- HUD_Write_PanelCvar_q("_complainbubble_color_outofammo");
- HUD_Write_PanelCvar_q("_complainbubble_color_donthave");
- HUD_Write_PanelCvar_q("_complainbubble_color_unavailable");
- HUD_Write_PanelCvar_q("_ammo");
- HUD_Write_PanelCvar_q("_ammo_color");
- HUD_Write_PanelCvar_q("_ammo_alpha");
- HUD_Write_PanelCvar_q("_aspect");
- HUD_Write_PanelCvar_q("_timeout");
- HUD_Write_PanelCvar_q("_timeout_effect");
- HUD_Write_PanelCvar_q("_timeout_fadebgmin");
- HUD_Write_PanelCvar_q("_timeout_fadefgmin");
- HUD_Write_PanelCvar_q("_timeout_speed_in");
- HUD_Write_PanelCvar_q("_timeout_speed_out");
- HUD_Write_PanelCvar_q("_onlyowned");
- HUD_Write_PanelCvar_q("_noncurrent_alpha");
- HUD_Write_PanelCvar_q("_noncurrent_scale");
- break;
- case HUD_PANEL_AMMO:
- HUD_Write_PanelCvar_q("_onlycurrent");
- HUD_Write_PanelCvar_q("_noncurrent_alpha");
- HUD_Write_PanelCvar_q("_noncurrent_scale");
- HUD_Write_PanelCvar_q("_iconalign");
- HUD_Write_PanelCvar_q("_progressbar");
- HUD_Write_PanelCvar_q("_progressbar_name");
- HUD_Write_PanelCvar_q("_progressbar_xoffset");
- HUD_Write_PanelCvar_q("_text");
- break;
- case HUD_PANEL_POWERUPS:
- HUD_Write_PanelCvar_q("_iconalign");
- HUD_Write_PanelCvar_q("_baralign");
- HUD_Write_PanelCvar_q("_progressbar");
- HUD_Write_PanelCvar_q("_text");
- break;
- case HUD_PANEL_HEALTHARMOR:
- HUD_Write_PanelCvar_q("_flip");
- HUD_Write_PanelCvar_q("_iconalign");
- HUD_Write_PanelCvar_q("_baralign");
- HUD_Write_PanelCvar_q("_progressbar");
- HUD_Write_PanelCvar_q("_progressbar_health");
- HUD_Write_PanelCvar_q("_progressbar_armor");
- HUD_Write_PanelCvar_q("_progressbar_gfx");
- HUD_Write_PanelCvar_q("_progressbar_gfx_smooth");
- HUD_Write_PanelCvar_q("_text");
- break;
- case HUD_PANEL_NOTIFY:
- HUD_Write_PanelCvar_q("_flip");
- HUD_Write_PanelCvar_q("_fontsize");
- HUD_Write_PanelCvar_q("_time");
- HUD_Write_PanelCvar_q("_fadetime");
- HUD_Write_PanelCvar_q("_icon_aspect");
- break;
- case HUD_PANEL_TIMER:
- HUD_Write_PanelCvar_q("_increment");
- break;
- case HUD_PANEL_RADAR:
- HUD_Write_PanelCvar_q("_foreground_alpha");
- HUD_Write_PanelCvar_q("_rotation");
- HUD_Write_PanelCvar_q("_zoommode");
- HUD_Write_PanelCvar_q("_scale");
- HUD_Write_PanelCvar_q("_maximized_scale");
- HUD_Write_PanelCvar_q("_maximized_size");
- HUD_Write_PanelCvar_q("_maximized_rotation");
- HUD_Write_PanelCvar_q("_maximized_zoommode");
- break;
- case HUD_PANEL_SCORE:
- HUD_Write_PanelCvar_q("_rankings");
- break;
- case HUD_PANEL_VOTE:
- HUD_Write_PanelCvar_q("_alreadyvoted_alpha");
- break;
- case HUD_PANEL_MODICONS:
- HUD_Write_PanelCvar_q("_ca_layout");
- HUD_Write_PanelCvar_q("_dom_layout");
- HUD_Write_PanelCvar_q("_freezetag_layout");
- break;
- case HUD_PANEL_PRESSEDKEYS:
- HUD_Write_PanelCvar_q("_aspect");
- HUD_Write_PanelCvar_q("_attack");
- break;
- case HUD_PANEL_ENGINEINFO:
- HUD_Write_PanelCvar_q("_framecounter_time");
- HUD_Write_PanelCvar_q("_framecounter_decimals");
- break;
- case HUD_PANEL_INFOMESSAGES:
- HUD_Write_PanelCvar_q("_flip");
- break;
- case HUD_PANEL_PHYSICS:
- HUD_Write_PanelCvar_q("_speed_unit");
- HUD_Write_PanelCvar_q("_speed_unit_show");
- HUD_Write_PanelCvar_q("_speed_max");
- HUD_Write_PanelCvar_q("_speed_vertical");
- HUD_Write_PanelCvar_q("_topspeed");
- HUD_Write_PanelCvar_q("_topspeed_time");
- HUD_Write_PanelCvar_q("_acceleration_max");
- HUD_Write_PanelCvar_q("_acceleration_vertical");
- HUD_Write_PanelCvar_q("_flip");
- HUD_Write_PanelCvar_q("_baralign");
- HUD_Write_PanelCvar_q("_progressbar");
- HUD_Write_PanelCvar_q("_progressbar_acceleration_mode");
- HUD_Write_PanelCvar_q("_progressbar_acceleration_scale");
- HUD_Write_PanelCvar_q("_progressbar_acceleration_nonlinear");
- HUD_Write_PanelCvar_q("_text");
- HUD_Write_PanelCvar_q("_text_scale");
- break;
- case HUD_PANEL_CENTERPRINT:
- HUD_Write_PanelCvar_q("_align");
- HUD_Write_PanelCvar_q("_flip");
- HUD_Write_PanelCvar_q("_fontscale");
- HUD_Write_PanelCvar_q("_time");
- HUD_Write_PanelCvar_q("_fade_in");
- HUD_Write_PanelCvar_q("_fade_out");
- HUD_Write_PanelCvar_q("_fade_subsequent");
- HUD_Write_PanelCvar_q("_fade_subsequent_passone");
- HUD_Write_PanelCvar_q("_fade_subsequent_passone_minalpha");
- HUD_Write_PanelCvar_q("_fade_subsequent_passtwo");
- HUD_Write_PanelCvar_q("_fade_subsequent_passtwo_minalpha");
- HUD_Write_PanelCvar_q("_fade_subsequent_minfontsize");
- HUD_Write_PanelCvar_q("_fade_minfontsize");
- break;
- case HUD_PANEL_ITEMSTIME:
- HUD_Write_PanelCvar_q("_iconalign");
- HUD_Write_PanelCvar_q("_progressbar");
- HUD_Write_PanelCvar_q("_progressbar_name");
- HUD_Write_PanelCvar_q("_progressbar_reduced");
- HUD_Write_PanelCvar_q("_text");
- HUD_Write_PanelCvar_q("_ratio");
- HUD_Write_PanelCvar_q("_dynamicsize");
- case HUD_PANEL_QUICKMENU:
- HUD_Write_PanelCvar_q("_align");
- break;
- }
- HUD_Write("\n");
- }
- HUD_Write("menu_sync\n"); // force the menu to reread the cvars, so that the dialogs are updated
-
- LOG_INFOF(_("^2Successfully exported to %s! (Note: It's saved in data/data/)\n"), filename);
- fclose(fh);
- }
- else
- LOG_INFOF(_("^1Couldn't write to %s\n"), filename);
-}
-
-void HUD_Configure_Exit_Force()
-{
- if (menu_enabled)
- {
- menu_enabled = 0;
- localcmd("togglemenu\n");
- }
- cvar_set("_hud_configure", "0");
-}
-
-// check if move will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
-vector HUD_Panel_CheckMove(vector myPos, vector mySize)
-{
- vector myCenter, targCenter;
- vector myTarget = myPos;
- int i;
- for (i = 0; i < hud_panels_COUNT; ++i) {
- panel = hud_panels[i];
- if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
- if(panel == highlightedPanel) continue;
- HUD_Panel_UpdatePosSize();
- if(!panel_enabled) continue;
-
- panel_pos -= '1 1 0' * panel_bg_border;
- panel_size += '2 2 0' * panel_bg_border;
-
- if(myPos.y + mySize.y < panel_pos.y)
- continue;
- if(myPos.y > panel_pos.y + panel_size.y)
- continue;
-
- if(myPos.x + mySize.x < panel_pos.x)
- continue;
- if(myPos.x > panel_pos.x + panel_size.x)
- continue;
-
- // OK, there IS a collision.
-
- myCenter.x = myPos.x + 0.5 * mySize.x;
- myCenter.y = myPos.y + 0.5 * mySize.y;
-
- targCenter.x = panel_pos.x + 0.5 * panel_size.x;
- targCenter.y = panel_pos.y + 0.5 * panel_size.y;
-
- if(myCenter.x < targCenter.x && myCenter.y < targCenter.y) // top left (of the target panel)
- {
- if(myPos.x + mySize.x - panel_pos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
- myTarget.x = panel_pos.x - mySize.x;
- else // push it upwards
- myTarget.y = panel_pos.y - mySize.y;
- }
- else if(myCenter.x > targCenter.x && myCenter.y < targCenter.y) // top right
- {
- if(panel_pos.x + panel_size.x - myPos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
- myTarget.x = panel_pos.x + panel_size.x;
- else // push it upwards
- myTarget.y = panel_pos.y - mySize.y;
- }
- else if(myCenter.x < targCenter.x && myCenter.y > targCenter.y) // bottom left
- {
- if(myPos.x + mySize.x - panel_pos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
- myTarget.x = panel_pos.x - mySize.x;
- else // push it downwards
- myTarget.y = panel_pos.y + panel_size.y;
- }
- else if(myCenter.x > targCenter.x && myCenter.y > targCenter.y) // bottom right
- {
- if(panel_pos.x + panel_size.x - myPos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
- myTarget.x = panel_pos.x + panel_size.x;
- else // push it downwards
- myTarget.y = panel_pos.y + panel_size.y;
- }
- //if(cvar("hud_configure_checkcollisions_debug"))
- //drawfill(panel_pos, panel_size, '1 1 0', .3, DRAWFLAG_NORMAL);
- }
-
- return myTarget;
-}
-
-void HUD_Panel_SetPos(vector pos)
-{
- panel = highlightedPanel;
- HUD_Panel_UpdatePosSize();
- vector mySize;
- mySize = panel_size;
-
- //if(cvar("hud_configure_checkcollisions_debug"))
- //drawfill(pos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
-
- if(autocvar_hud_configure_grid)
- {
- pos.x = floor((pos.x/vid_conwidth)/hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
- pos.y = floor((pos.y/vid_conheight)/hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
- }
-
- if(hud_configure_checkcollisions)
- pos = HUD_Panel_CheckMove(pos, mySize);
-
- pos.x = bound(0, pos.x, vid_conwidth - mySize.x);
- pos.y = bound(0, pos.y, vid_conheight - mySize.y);
-
- string s;
- s = strcat(ftos(pos.x/vid_conwidth), " ", ftos(pos.y/vid_conheight));
-
- cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
-}
-
-// check if resize will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
-vector HUD_Panel_CheckResize(vector mySize, vector resizeorigin) {
- vector targEndPos;
- vector dist;
- float ratio = mySize.x/mySize.y;
- int i;
- for (i = 0; i < hud_panels_COUNT; ++i) {
- panel = hud_panels[i];
- if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
- if(panel == highlightedPanel) continue;
- HUD_Panel_UpdatePosSize();
- if(!panel_enabled) continue;
-
- panel_pos -= '1 1 0' * panel_bg_border;
- panel_size += '2 2 0' * panel_bg_border;
-
- targEndPos = panel_pos + panel_size;
-
- // resizeorigin is WITHIN target panel, just abort any collision testing against that particular panel to produce expected behaviour!
- if(resizeorigin.x > panel_pos.x && resizeorigin.x < targEndPos.x && resizeorigin.y > panel_pos.y && resizeorigin.y < targEndPos.y)
- continue;
-
- if (resizeCorner == 1)
- {
- // check if this panel is on our way
- if (resizeorigin.x <= panel_pos.x)
- continue;
- if (resizeorigin.y <= panel_pos.y)
- continue;
- if (targEndPos.x <= resizeorigin.x - mySize.x)
- continue;
- if (targEndPos.y <= resizeorigin.y - mySize.y)
- continue;
-
- // there is a collision:
- // detect which side of the panel we are facing is actually limiting the resizing
- // (which side the resize direction finds for first) and reduce the size up to there
- //
- // dist is the distance between resizeorigin and the "analogous" point of the panel
- // in this case between resizeorigin (bottom-right point) and the bottom-right point of the panel
- dist.x = resizeorigin.x - targEndPos.x;
- dist.y = resizeorigin.y - targEndPos.y;
- if (dist.y <= 0 || dist.x / dist.y > ratio)
- mySize.x = min(mySize.x, dist.x);
- else
- mySize.y = min(mySize.y, dist.y);
- }
- else if (resizeCorner == 2)
- {
- if (resizeorigin.x >= targEndPos.x)
- continue;
- if (resizeorigin.y <= panel_pos.y)
- continue;
- if (panel_pos.x >= resizeorigin.x + mySize.x)
- continue;
- if (targEndPos.y <= resizeorigin.y - mySize.y)
- continue;
-
- dist.x = panel_pos.x - resizeorigin.x;
- dist.y = resizeorigin.y - targEndPos.y;
- if (dist.y <= 0 || dist.x / dist.y > ratio)
- mySize.x = min(mySize.x, dist.x);
- else
- mySize.y = min(mySize.y, dist.y);
- }
- else if (resizeCorner == 3)
- {
- if (resizeorigin.x <= panel_pos.x)
- continue;
- if (resizeorigin.y >= targEndPos.y)
- continue;
- if (targEndPos.x <= resizeorigin.x - mySize.x)
- continue;
- if (panel_pos.y >= resizeorigin.y + mySize.y)
- continue;
-
- dist.x = resizeorigin.x - targEndPos.x;
- dist.y = panel_pos.y - resizeorigin.y;
- if (dist.y <= 0 || dist.x / dist.y > ratio)
- mySize.x = min(mySize.x, dist.x);
- else
- mySize.y = min(mySize.y, dist.y);
- }
- else if (resizeCorner == 4)
- {
- if (resizeorigin.x >= targEndPos.x)
- continue;
- if (resizeorigin.y >= targEndPos.y)
- continue;
- if (panel_pos.x >= resizeorigin.x + mySize.x)
- continue;
- if (panel_pos.y >= resizeorigin.y + mySize.y)
- continue;
-
- dist.x = panel_pos.x - resizeorigin.x;
- dist.y = panel_pos.y - resizeorigin.y;
- if (dist.y <= 0 || dist.x / dist.y > ratio)
- mySize.x = min(mySize.x, dist.x);
- else
- mySize.y = min(mySize.y, dist.y);
- }
- //if(cvar("hud_configure_checkcollisions_debug"))
- //drawfill(panel_pos, panel_size, '1 1 0', .3, DRAWFLAG_NORMAL);
- }
-
- return mySize;
-}
-
-void HUD_Panel_SetPosSize(vector mySize)
-{
- panel = highlightedPanel;
- HUD_Panel_UpdatePosSize();
- vector resizeorigin = panel_click_resizeorigin;
- vector myPos;
-
- // minimum panel size cap
- mySize.x = max(0.025 * vid_conwidth, mySize.x);
- mySize.y = max(0.025 * vid_conheight, mySize.y);
-
- if(highlightedPanel == HUD_PANEL(CHAT)) // some panels have their own restrictions, like the chat panel (which actually only moves the engine chat print around). Looks bad if it's too small.
- {
- mySize.x = max(17 * autocvar_con_chatsize, mySize.x);
- mySize.y = max(2 * autocvar_con_chatsize + 2 * panel_bg_padding, mySize.y);
- }
-
- // collision testing|
- // -----------------+
-
- // we need to know pos at this stage, but it might still change later if we hit a screen edge/other panel (?)
- if(resizeCorner == 1) {
- myPos.x = resizeorigin.x - mySize.x;
- myPos.y = resizeorigin.y - mySize.y;
- } else if(resizeCorner == 2) {
- myPos.x = resizeorigin.x;
- myPos.y = resizeorigin.y - mySize.y;
- } else if(resizeCorner == 3) {
- myPos.x = resizeorigin.x - mySize.x;
- myPos.y = resizeorigin.y;
- } else { // resizeCorner == 4
- myPos.x = resizeorigin.x;
- myPos.y = resizeorigin.y;
- }
-
- // left/top screen edges
- if(myPos.x < 0)
- mySize.x = mySize.x + myPos.x;
- if(myPos.y < 0)
- mySize.y = mySize.y + myPos.y;
-
- // bottom/right screen edges
- if(myPos.x + mySize.x > vid_conwidth)
- mySize.x = vid_conwidth - myPos.x;
- if(myPos.y + mySize.y > vid_conheight)
- mySize.y = vid_conheight - myPos.y;
-
- //if(cvar("hud_configure_checkcollisions_debug"))
- //drawfill(myPos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
-
- // before checkresize, otherwise panel can be snapped partially inside another panel or panel aspect ratio can be broken
- if(autocvar_hud_configure_grid)
- {
- mySize.x = floor((mySize.x/vid_conwidth)/hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
- mySize.y = floor((mySize.y/vid_conheight)/hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
- }
-
- if(hud_configure_checkcollisions)
- mySize = HUD_Panel_CheckResize(mySize, resizeorigin);
-
- // minimum panel size cap, do this once more so we NEVER EVER EVER have a panel smaller than this, JUST IN CASE above code still makes the panel eg negative (impossible to resize back without changing cvars manually then)
- mySize.x = max(0.025 * vid_conwidth, mySize.x);
- mySize.y = max(0.025 * vid_conheight, mySize.y);
-
- // do another pos check, as size might have changed by now
- if(resizeCorner == 1) {
- myPos.x = resizeorigin.x - mySize.x;
- myPos.y = resizeorigin.y - mySize.y;
- } else if(resizeCorner == 2) {
- myPos.x = resizeorigin.x;
- myPos.y = resizeorigin.y - mySize.y;
- } else if(resizeCorner == 3) {
- myPos.x = resizeorigin.x - mySize.x;
- myPos.y = resizeorigin.y;
- } else { // resizeCorner == 4
- myPos.x = resizeorigin.x;
- myPos.y = resizeorigin.y;
- }
-
- //if(cvar("hud_configure_checkcollisions_debug"))
- //drawfill(myPos, mySize, '0 1 0', .3, DRAWFLAG_NORMAL);
-
- string s;
- s = strcat(ftos(mySize.x/vid_conwidth), " ", ftos(mySize.y/vid_conheight));
- cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
-
- s = strcat(ftos(myPos.x/vid_conwidth), " ", ftos(myPos.y/vid_conheight));
- cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
-}
-
-float pressed_key_time;
-vector highlightedPanel_initial_pos, highlightedPanel_initial_size;
-void HUD_Panel_Arrow_Action(float nPrimary)
-{
- if(!highlightedPanel)
- return;
-
- hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
-
- float step;
- if(autocvar_hud_configure_grid)
- {
- if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
- {
- if (hudShiftState & S_SHIFT)
- step = hud_configure_realGridSize.y;
- else
- step = 2 * hud_configure_realGridSize.y;
- }
- else
- {
- if (hudShiftState & S_SHIFT)
- step = hud_configure_realGridSize.x;
- else
- step = 2 * hud_configure_realGridSize.x;
- }
- }
- else
- {
- if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
- step = vid_conheight;
- else
- step = vid_conwidth;
- if (hudShiftState & S_SHIFT)
- step = (step / 256); // more precision
- else
- step = (step / 64) * (1 + 2 * (time - pressed_key_time));
- }
-
- panel = highlightedPanel;
- HUD_Panel_UpdatePosSize();
-
- highlightedPanel_initial_pos = panel_pos;
- highlightedPanel_initial_size = panel_size;
-
- if (hudShiftState & S_ALT) // resize
- {
- if(nPrimary == K_UPARROW)
- resizeCorner = 1;
- else if(nPrimary == K_RIGHTARROW)
- resizeCorner = 2;
- else if(nPrimary == K_LEFTARROW)
- resizeCorner = 3;
- else // if(nPrimary == K_DOWNARROW)
- resizeCorner = 4;
-
- // ctrl+arrow reduces the size, instead of increasing it
- // Note that ctrl disables collisions check too, but it's fine
- // since we don't collide with anything reducing the size
- if (hudShiftState & S_CTRL) {
- step = -step;
- resizeCorner = 5 - resizeCorner;
- }
-
- vector mySize;
- mySize = panel_size;
- panel_click_resizeorigin = panel_pos;
- if(resizeCorner == 1) {
- panel_click_resizeorigin += mySize;
- mySize.y += step;
- } else if(resizeCorner == 2) {
- panel_click_resizeorigin.y += mySize.y;
- mySize.x += step;
- } else if(resizeCorner == 3) {
- panel_click_resizeorigin.x += mySize.x;
- mySize.x += step;
- } else { // resizeCorner == 4
- mySize.y += step;
- }
- HUD_Panel_SetPosSize(mySize);
- }
- else // move
- {
- vector pos;
- pos = panel_pos;
- if(nPrimary == K_UPARROW)
- pos.y -= step;
- else if(nPrimary == K_DOWNARROW)
- pos.y += step;
- else if(nPrimary == K_LEFTARROW)
- pos.x -= step;
- else // if(nPrimary == K_RIGHTARROW)
- pos.x += step;
-
- HUD_Panel_SetPos(pos);
- }
-
- panel = highlightedPanel;
- HUD_Panel_UpdatePosSize();
-
- if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
- {
- // backup!
- panel_pos_backup = highlightedPanel_initial_pos;
- panel_size_backup = highlightedPanel_initial_size;
- highlightedPanel_backup = highlightedPanel;
- }
-}
-
-void HUD_Panel_EnableMenu();
-entity tab_panels[hud_panels_MAX];
-entity tab_panel;
-vector tab_panel_pos;
-float tab_backward;
-void HUD_Panel_FirstInDrawQ(float id);
-void reset_tab_panels()
-{
- int i;
- for(i = 0; i < hud_panels_COUNT; ++i)
- tab_panels[i] = world;
-}
-float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
-{
- string s;
-
- if(bInputType == 2)
- return false;
-
- if(!autocvar__hud_configure)
- return false;
-
- if(bInputType == 3)
- {
- mousepos.x = nPrimary;
- mousepos.y = nSecondary;
- return true;
- }
-
- // block any input while a menu dialog is fading
- // don't block mousepos read as it leads to cursor jumps in the interaction with the menu
- if(autocvar__menu_alpha)
- {
- hudShiftState = 0;
- mouseClicked = 0;
- return true;
- }
-
- // allow console bind to work
- string con_keys;
- float keys;
- con_keys = findkeysforcommand("toggleconsole", 0);
- keys = tokenize(con_keys); // findkeysforcommand returns data for this
-
- bool hit_con_bind = false;
- int i;
- for (i = 0; i < keys; ++i)
- {
- if(nPrimary == stof(argv(i)))
- hit_con_bind = true;
- }
-
- if(bInputType == 0) {
- if(nPrimary == K_ALT) hudShiftState |= S_ALT;
- if(nPrimary == K_CTRL) hudShiftState |= S_CTRL;
- if(nPrimary == K_SHIFT) hudShiftState |= S_SHIFT;
- }
- else if(bInputType == 1) {
- if(nPrimary == K_ALT) hudShiftState -= (hudShiftState & S_ALT);
- if(nPrimary == K_CTRL) hudShiftState -= (hudShiftState & S_CTRL);
- if(nPrimary == K_SHIFT) hudShiftState -= (hudShiftState & S_SHIFT);
- }
-
- if(nPrimary == K_CTRL)
- {
- if (bInputType == 1) //ctrl has been released
- {
- if (tab_panel)
- {
- //switch to selected panel
- highlightedPanel = tab_panel;
- highlightedAction = 0;
- HUD_Panel_FirstInDrawQ(highlightedPanel.panel_id);
- }
- tab_panel = world;
- reset_tab_panels();
- }
- }
-
- if(nPrimary == K_MOUSE1)
- {
- if(bInputType == 0) // key pressed
- mouseClicked |= S_MOUSE1;
- else if(bInputType == 1) // key released
- mouseClicked -= (mouseClicked & S_MOUSE1);
- }
- else if(nPrimary == K_MOUSE2)
- {
- if(bInputType == 0) // key pressed
- mouseClicked |= S_MOUSE2;
- else if(bInputType == 1) // key released
- mouseClicked -= (mouseClicked & S_MOUSE2);
- }
- else if(nPrimary == K_ESCAPE)
- {
- if (bInputType == 1)
- return true;
- menu_enabled = 1;
- localcmd("menu_showhudexit\n");
- }
- else if(nPrimary == K_BACKSPACE && hudShiftState & S_CTRL)
- {
- if (bInputType == 1)
- return true;
- if (!menu_enabled)
- cvar_set("_hud_configure", "0");
- }
- else if(nPrimary == K_TAB && hudShiftState & S_CTRL) // switch panel
- {
- if (bInputType == 1 || mouseClicked)
- return true;
-
- // FIXME minor bug: if a panel is highlighted, has the same pos_x and
- // lays in the same level of another panel then the next consecutive
- // CTRL TAB presses will reselect once more the highlighted panel
-
- entity starting_panel;
- entity old_tab_panel = tab_panel;
- if (!tab_panel) //first press of TAB
- {
- if (highlightedPanel)
- {
- panel = highlightedPanel;
- HUD_Panel_UpdatePosSize();
- }
- else
- panel_pos = '0 0 0';
- starting_panel = highlightedPanel;
- tab_panel_pos = panel_pos; //to compute level
- }
- else
- {
- if ( ((!tab_backward) && (hudShiftState & S_SHIFT)) || (tab_backward && !(hudShiftState & S_SHIFT)) ) //tab direction changed?
- reset_tab_panels();
- starting_panel = tab_panel;
- }
- tab_backward = (hudShiftState & S_SHIFT);
-
- float k, level = 0, start_posX;
- vector candidate_pos = '0 0 0';
- const float LEVELS_NUM = 4;
- float level_height = vid_conheight / LEVELS_NUM;
-:find_tab_panel
- level = floor(tab_panel_pos.y / level_height) * level_height; //starting level
- candidate_pos.x = (!tab_backward) ? vid_conwidth : 0;
- start_posX = tab_panel_pos.x;
- tab_panel = world;
- k=0;
- while(++k)
- {
- for(i = 0; i < hud_panels_COUNT; ++i)
- {
- panel = hud_panels[i];
- if(!(panel.panel_configflags & PANEL_CONFIG_MAIN))
- continue;
- if (panel == tab_panels[i] || panel == starting_panel)
- continue;
- HUD_Panel_UpdatePosSize();
- if (panel_pos.y >= level && (panel_pos.y - level) < level_height)
- if ( ( !tab_backward && panel_pos.x >= start_posX && (panel_pos.x < candidate_pos.x || (panel_pos.x == candidate_pos.x && panel_pos.y <= candidate_pos.y)) )
- || ( tab_backward && panel_pos.x <= start_posX && (panel_pos.x > candidate_pos.x || (panel_pos.x == candidate_pos.x && panel_pos.y >= candidate_pos.y)) ) )
- {
- tab_panel = panel;
- tab_panel_pos = candidate_pos = panel_pos;
- }
- }
- if (tab_panel)
- break;
- if (k == LEVELS_NUM) //tab_panel not found
- {
- reset_tab_panels();
- if (!old_tab_panel)
- {
- tab_panel = world;
- return true;
- }
- starting_panel = old_tab_panel;
- old_tab_panel = world;
- goto find_tab_panel; //u must find tab_panel!
- }
- if (!tab_backward)
- {
- level = (level + level_height) % vid_conheight;
- start_posX = 0;
- candidate_pos.x = vid_conwidth;
- }
- else
- {
- level = (level - level_height) % vid_conheight;
- start_posX = vid_conwidth;
- candidate_pos.x = 0;
- }
- }
-
- tab_panels[tab_panel.panel_id] = tab_panel;
- }
- else if(nPrimary == K_SPACE && hudShiftState & S_CTRL) // enable/disable highlighted panel or dock
- {
- if (bInputType == 1 || mouseClicked)
- return true;
-
- if (highlightedPanel)
- cvar_set(strcat("hud_panel_", highlightedPanel.panel_name), ftos(!cvar(strcat("hud_panel_", highlightedPanel.panel_name))));
- else
- cvar_set(strcat("hud_dock"), (autocvar_hud_dock == "") ? "dock" : "");
- }
- else if(nPrimary == 'c' && hudShiftState & S_CTRL) // copy highlighted panel size
- {
- if (bInputType == 1 || mouseClicked)
- return true;
-
- if (highlightedPanel)
- {
- panel = highlightedPanel;
- HUD_Panel_UpdatePosSize();
- panel_size_copied = panel_size;
- }
- }
- else if(nPrimary == 'v' && hudShiftState & S_CTRL) // past copied size on the highlighted panel
- {
- if (bInputType == 1 || mouseClicked)
- return true;
-
- if (panel_size_copied == '0 0 0' || !highlightedPanel)
- return true;
-
- panel = highlightedPanel;
- HUD_Panel_UpdatePosSize();
-
- // reduce size if it'd go beyond screen boundaries
- vector tmp_size = panel_size_copied;
- if (panel_pos.x + panel_size_copied.x > vid_conwidth)
- tmp_size.x = vid_conwidth - panel_pos.x;
- if (panel_pos.y + panel_size_copied.y > vid_conheight)
- tmp_size.y = vid_conheight - panel_pos.y;
-
- if (panel_size == tmp_size)
- return true;
-
- // backup first!
- panel_pos_backup = panel_pos;
- panel_size_backup = panel_size;
- highlightedPanel_backup = highlightedPanel;
-
- s = strcat(ftos(tmp_size.x/vid_conwidth), " ", ftos(tmp_size.y/vid_conheight));
- cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
- }
- else if(nPrimary == 'z' && hudShiftState & S_CTRL) // undo last action
- {
- if (bInputType == 1 || mouseClicked)
- return true;
- //restore previous values
- if (highlightedPanel_backup)
- {
- s = strcat(ftos(panel_pos_backup.x/vid_conwidth), " ", ftos(panel_pos_backup.y/vid_conheight));
- cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_pos"), s);
- s = strcat(ftos(panel_size_backup.x/vid_conwidth), " ", ftos(panel_size_backup.y/vid_conheight));
- cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_size"), s);
- highlightedPanel_backup = world;
- }
- }
- else if(nPrimary == 's' && hudShiftState & S_CTRL) // save config
- {
- if (bInputType == 1 || mouseClicked)
- return true;
- localcmd("hud save myconfig\n");
- }
- else if(nPrimary == K_UPARROW || nPrimary == K_DOWNARROW || nPrimary == K_LEFTARROW || nPrimary == K_RIGHTARROW)
- {
- if (bInputType == 1)
- {
- pressed_key_time = 0;
- return true;
- }
- else if (pressed_key_time == 0)
- pressed_key_time = time;
-
- if (!mouseClicked)
- HUD_Panel_Arrow_Action(nPrimary); //move or resize panel
- }
- else if(nPrimary == K_ENTER || nPrimary == K_SPACE || nPrimary == K_KP_ENTER)
- {
- if (bInputType == 1)
- return true;
- if (highlightedPanel)
- HUD_Panel_EnableMenu();
- }
- else if(hit_con_bind || nPrimary == K_PAUSE)
- return false;
-
- return true;
-}
-
-float HUD_Panel_Check_Mouse_Pos(float allow_move)
-{
- int i, j = 0;
- while(j < hud_panels_COUNT)
- {
- i = panel_order[j];
- j += 1;
-
- panel = hud_panels[i];
- if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
- HUD_Panel_UpdatePosSize();
-
- float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
-
- // move
- if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
- {
- return 1;
- }
- // resize from topleft border
- else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
- {
- return 2;
- }
- // resize from topright border
- else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
- {
- return 3;
- }
- // resize from bottomleft border
- else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
- {
- return 3;
- }
- // resize from bottomright border
- else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
- {
- return 2;
- }
- }
- return 0;
-}
-
-// move a panel to the beginning of the panel order array (which means it gets drawn last, on top of everything else)
-void HUD_Panel_FirstInDrawQ(float id)
-{
- int i;
- int place = -1;
- // find out where in the array our current id is, save into place
- for(i = 0; i < hud_panels_COUNT; ++i)
- {
- if(panel_order[i] == id)
- {
- place = i;
- break;
- }
- }
- // place last if we didn't find a place for it yet (probably new panel, or screwed up cvar)
- if(place == -1)
- place = hud_panels_COUNT - 1;
-
- // move all ids up by one step in the array until "place"
- for(i = place; i > 0; --i)
- {
- panel_order[i] = panel_order[i-1];
- }
- // now save the new top id
- panel_order[0] = id;
-
- // let's save them into the cvar by some strcat trickery
- string s = "";
- for(i = 0; i < hud_panels_COUNT; ++i)
- {
- s = strcat(s, ftos(panel_order[i]), " ");
- }
- cvar_set("_hud_panelorder", s);
- if(hud_panelorder_prev)
- strunzone(hud_panelorder_prev);
- hud_panelorder_prev = strzone(autocvar__hud_panelorder); // prevent HUD_Main from doing useless update, we already updated here
-}
-
-void HUD_Panel_Highlight(float allow_move)
-{
- int i, j = 0;
-
- while(j < hud_panels_COUNT)
- {
- i = panel_order[j];
- j += 1;
-
- panel = hud_panels[i];
- if(!(panel.panel_configflags & PANEL_CONFIG_MAIN))
- continue;
- HUD_Panel_UpdatePosSize();
-
- float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
-
- // move
- if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
- {
- highlightedPanel = hud_panels[i];
- HUD_Panel_FirstInDrawQ(i);
- highlightedAction = 1;
- panel_click_distance = mousepos - panel_pos;
- return;
- }
- // resize from topleft border
- else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
- {
- highlightedPanel = hud_panels[i];
- HUD_Panel_FirstInDrawQ(i);
- highlightedAction = 2;
- resizeCorner = 1;
- panel_click_distance = mousepos - panel_pos;
- panel_click_resizeorigin = panel_pos + panel_size;
- return;
- }
- // resize from topright border
- else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
- {
- highlightedPanel = hud_panels[i];
- HUD_Panel_FirstInDrawQ(i);
- highlightedAction = 2;
- resizeCorner = 2;
- panel_click_distance.x = panel_size.x - mousepos.x + panel_pos.x;
- panel_click_distance.y = mousepos.y - panel_pos.y;
- panel_click_resizeorigin = panel_pos + eY * panel_size.y;
- return;
- }
- // resize from bottomleft border
- else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
- {
- highlightedPanel = hud_panels[i];
- HUD_Panel_FirstInDrawQ(i);
- highlightedAction = 2;
- resizeCorner = 3;
- panel_click_distance.x = mousepos.x - panel_pos.x;
- panel_click_distance.y = panel_size.y - mousepos.y + panel_pos.y;
- panel_click_resizeorigin = panel_pos + eX * panel_size.x;
- return;
- }
- // resize from bottomright border
- else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
- {
- highlightedPanel = hud_panels[i];
- HUD_Panel_FirstInDrawQ(i);
- highlightedAction = 2;
- resizeCorner = 4;
- panel_click_distance = panel_size - mousepos + panel_pos;
- panel_click_resizeorigin = panel_pos;
- return;
- }
- }
- highlightedPanel = world;
- highlightedAction = 0;
-}
-
-void HUD_Panel_EnableMenu()
-{
- menu_enabled = 2;
- localcmd("menu_showhudoptions ", highlightedPanel.panel_name, "\n");
-}
-float mouse_over_panel;
-void HUD_Panel_Mouse()
-{
- if(autocvar__menu_alpha == 1)
- return;
-
- if (!autocvar_hud_cursormode)
- {
- mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
-
- mousepos.x = bound(0, mousepos.x, vid_conwidth);
- mousepos.y = bound(0, mousepos.y, vid_conheight);
- }
-
- if(mouseClicked)
- {
- if(prevMouseClicked == 0)
- {
- if (tab_panel)
- {
- //stop ctrl-tab selection
- tab_panel = world;
- reset_tab_panels();
- }
- HUD_Panel_Highlight(mouseClicked & S_MOUSE1); // sets highlightedPanel, highlightedAction, panel_click_distance, panel_click_resizeorigin
- // and calls HUD_Panel_UpdatePosSize() for the highlighted panel
- if (highlightedPanel)
- {
- highlightedPanel_initial_pos = panel_pos;
- highlightedPanel_initial_size = panel_size;
- }
- // doubleclick check
- if ((mouseClicked & S_MOUSE1) && time - prevMouseClickedTime < 0.4 && highlightedPanel && prevMouseClickedPos == mousepos)
- {
- mouseClicked = 0; // to prevent spam, I guess.
- HUD_Panel_EnableMenu();
- }
- else
- {
- if (mouseClicked & S_MOUSE1)
- {
- prevMouseClickedTime = time;
- prevMouseClickedPos = mousepos;
- }
- mouse_over_panel = HUD_Panel_Check_Mouse_Pos(mouseClicked & S_MOUSE1);
- }
- }
- else
- {
- panel = highlightedPanel;
- HUD_Panel_UpdatePosSize();
- }
-
- if (highlightedPanel)
- {
- drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
- if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
- {
- hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
- // backup!
- panel_pos_backup = highlightedPanel_initial_pos;
- panel_size_backup = highlightedPanel_initial_size;
- highlightedPanel_backup = highlightedPanel;
- }
- else
- // in case the clicked panel is inside another panel and we aren't
- // moving it, avoid the immediate "fix" of its position/size
- // (often unwanted and hateful) by disabling collisions check
- hud_configure_checkcollisions = false;
- }
-
- if(highlightedAction == 1)
- HUD_Panel_SetPos(mousepos - panel_click_distance);
- else if(highlightedAction == 2)
- {
- vector mySize = '0 0 0';
- if(resizeCorner == 1) {
- mySize.x = panel_click_resizeorigin.x - (mousepos.x - panel_click_distance.x);
- mySize.y = panel_click_resizeorigin.y - (mousepos.y - panel_click_distance.y);
- } else if(resizeCorner == 2) {
- mySize.x = mousepos.x + panel_click_distance.x - panel_click_resizeorigin.x;
- mySize.y = panel_click_distance.y + panel_click_resizeorigin.y - mousepos.y;
- } else if(resizeCorner == 3) {
- mySize.x = panel_click_resizeorigin.x + panel_click_distance.x - mousepos.x;
- mySize.y = mousepos.y + panel_click_distance.y - panel_click_resizeorigin.y;
- } else { // resizeCorner == 4
- mySize.x = mousepos.x - (panel_click_resizeorigin.x - panel_click_distance.x);
- mySize.y = mousepos.y - (panel_click_resizeorigin.y - panel_click_distance.y);
- }
- HUD_Panel_SetPosSize(mySize);
- }
- }
- else
- {
- if(prevMouseClicked)
- highlightedAction = 0;
- if(menu_enabled == 2)
- mouse_over_panel = 0;
- else
- mouse_over_panel = HUD_Panel_Check_Mouse_Pos(true);
- if (mouse_over_panel && !tab_panel)
- drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
- }
- // draw cursor after performing move/resize to have the panel pos/size updated before mouse_over_panel
- const vector cursorsize = '32 32 0';
- float cursor_alpha = 1 - autocvar__menu_alpha;
-
- if(!mouse_over_panel)
- drawpic(mousepos, strcat("gfx/menu/", autocvar_menu_skin, "/cursor.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
- else if(mouse_over_panel == 1)
- drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_move.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
- else if(mouse_over_panel == 2)
- drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_resize.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
- else
- drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_resize2.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
-
- prevMouseClicked = mouseClicked;
-}
-void HUD_Configure_DrawGrid()
-{
- float i;
- if(autocvar_hud_configure_grid && autocvar_hud_configure_grid_alpha)
- {
- hud_configure_gridSize.x = bound(0.005, cvar("hud_configure_grid_xsize"), 0.2);
- hud_configure_gridSize.y = bound(0.005, cvar("hud_configure_grid_ysize"), 0.2);
- hud_configure_realGridSize.x = hud_configure_gridSize.x * vid_conwidth;
- hud_configure_realGridSize.y = hud_configure_gridSize.y * vid_conheight;
- vector s;
- // x-axis
- s = eX + eY * vid_conheight;
- for(i = 1; i < 1/hud_configure_gridSize.x; ++i)
- drawfill(eX * i * hud_configure_realGridSize.x, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
- // y-axis
- s = eY + eX * vid_conwidth;
- for(i = 1; i < 1/hud_configure_gridSize.y; ++i)
- drawfill(eY * i * hud_configure_realGridSize.y, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
- }
-}
-
-float _menu_alpha_prev;
-void HUD_Configure_Frame()
-{
- int i;
- if(autocvar__hud_configure)
- {
- if(isdemo() || intermission == 2)
- {
- HUD_Configure_Exit_Force();
- return;
- }
-
- if(!hud_configure_prev)
- {
- if(autocvar_hud_cursormode)
- setcursormode(1);
- hudShiftState = 0;
- for(i = hud_panels_COUNT - 1; i >= 0; --i)
- hud_panels[panel_order[i]].update_time = time;
- }
-
- // NOTE this check is necessary because _menu_alpha isn't updated the frame the menu gets enabled
- if(autocvar__menu_alpha != _menu_alpha_prev)
- {
- if(autocvar__menu_alpha == 0)
- menu_enabled = 0;
- _menu_alpha_prev = autocvar__menu_alpha;
- }
-
- HUD_Configure_DrawGrid();
- }
- else if(hud_configure_prev)
- {
- if(menu_enabled)
- menu_enabled = 0;
- if(autocvar_hud_cursormode)
- setcursormode(0);
- }
-}
-
-const float hlBorderSize = 2;
-const string hlBorder = "gfx/hud/default/border_highlighted";
-const string hlBorder2 = "gfx/hud/default/border_highlighted2";
-void HUD_Panel_HlBorder(float myBorder, vector color, float theAlpha)
-{
- drawfill(panel_pos - '1 1 0' * myBorder, panel_size + '2 2 0' * myBorder, '0 0.5 1', .5 * theAlpha, DRAWFLAG_NORMAL);
- drawpic_tiled(panel_pos - '1 1 0' * myBorder, hlBorder, '8 1 0' * hlBorderSize, eX * (panel_size.x + 2 * myBorder) + eY * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
- drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * (panel_size.y + 2 * myBorder - hlBorderSize), hlBorder, '8 1 0' * hlBorderSize, eX * (panel_size.x + 2 * myBorder) + eY * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
- drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * hlBorderSize, hlBorder2, '1 8 0' * hlBorderSize, eY * (panel_size.y + 2 * myBorder - 2 * hlBorderSize) + eX * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
- drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * hlBorderSize + eX * (panel_size.x + 2 * myBorder - hlBorderSize), hlBorder2, '1 8 0' * hlBorderSize, eY * (panel_size.y + 2 * myBorder - 2 * hlBorderSize) + eX * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
-}
-
-void HUD_Configure_PostDraw()
-{
- if(autocvar__hud_configure)
- {
- if(tab_panel)
- {
- panel = tab_panel;
- HUD_Panel_UpdatePosSize();
- drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .2, DRAWFLAG_NORMAL);
- }
- if(highlightedPanel)
- {
- panel = highlightedPanel;
- HUD_Panel_UpdatePosSize();
- HUD_Panel_HlBorder(panel_bg_border * hlBorderSize, '0 0.5 1', 0.4 * (1 - autocvar__menu_alpha));
- }
- }
-}
+++ /dev/null
-#ifndef CLIENT_HUD_CONFIG_H
-#define CLIENT_HUD_CONFIG_H
-
-const int S_MOUSE1 = 1;
-const int S_MOUSE2 = 2;
-const int S_MOUSE3 = 4;
-int mouseClicked;
-int prevMouseClicked; // previous state
-float prevMouseClickedTime; // time during previous left mouse click, to check for doubleclicks
-vector prevMouseClickedPos; // pos during previous left mouse click, to check for doubleclicks
-
-void HUD_Panel_ExportCfg(string cfgname);
-
-void HUD_Panel_Mouse();
-
-void HUD_Configure_Frame();
-
-void HUD_Configure_PostDraw();
-
-float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary);
-
-#endif
+++ /dev/null
-#include "laser.qh"
-
-#include "../lib/csqcmodel/interpolate.qh"
-
-// a laser goes from origin in direction angles
-// it has color 'colormod'
-// and stops when something is in the way
-entityclass(Laser);
-class(Laser) .int cnt; // end effect
-class(Laser) .vector colormod;
-class(Laser) .int state; // on-off
-class(Laser) .int count; // flags for the laser
-class(Laser) .vector velocity;
-class(Laser) .float alpha;
-class(Laser) .float scale; // scaling factor of the thickness
-class(Laser) .float modelscale; // scaling factor of the dlight
-
-void Draw_Laser(entity this)
-{
- if(!self.state)
- return;
- InterpolateOrigin_Do();
- if(self.count & 0x80)
- {
- if(self.count & 0x10)
- {
- trace_endpos = self.velocity;
- trace_dphitq3surfaceflags = 0;
- }
- else
- traceline(self.origin, self.velocity, 0, self);
- }
- else
- {
- if(self.count & 0x10)
- {
- makevectors(self.angles);
- trace_endpos = self.origin + v_forward * 1048576;
- trace_dphitq3surfaceflags = Q3SURFACEFLAG_SKY;
- }
- else
- {
- makevectors(self.angles);
- traceline(self.origin, self.origin + v_forward * 32768, 0, self);
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
- trace_endpos = self.origin + v_forward * 1048576;
- }
- }
- if(self.scale != 0)
- {
- if(self.alpha)
- {
- Draw_CylindricLine(self.origin, trace_endpos, self.scale, "particles/laserbeam", 0, time * 3, self.colormod, self.alpha, DRAWFLAG_NORMAL, view_origin);
- }
- else
- {
- Draw_CylindricLine(self.origin, trace_endpos, self.scale, "particles/laserbeam", 0, time * 3, self.colormod, 0.5, DRAWFLAG_ADDITIVE, view_origin);
- }
- }
- if (!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
- {
- if(self.cnt >= 0)
- pointparticles(self.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
- if(self.colormod != '0 0 0' && self.modelscale != 0)
- adddynamiclight(trace_endpos + trace_plane_normal * 1, self.modelscale, self.colormod * 5);
- }
-}
-
-void Ent_Laser()
-{
- InterpolateOrigin_Undo();
-
- // 30 bytes, or 13 bytes for just moving
- int f = ReadByte();
- self.count = (f & 0xF0);
-
- if(self.count & 0x80)
- self.iflags = IFLAG_VELOCITY | IFLAG_ORIGIN;
- else
- self.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
-
- if(f & 1)
- {
- self.origin_x = ReadCoord();
- self.origin_y = ReadCoord();
- self.origin_z = ReadCoord();
- setorigin(self, self.origin);
- }
- if(f & 8)
- {
- self.colormod_x = ReadByte() / 255.0;
- self.colormod_y = ReadByte() / 255.0;
- self.colormod_z = ReadByte() / 255.0;
- if(f & 0x40)
- self.alpha = ReadByte() / 255.0;
- else
- self.alpha = 0;
- self.scale = 2;
- self.modelscale = 50;
- if(f & 0x20)
- {
- self.scale *= ReadByte() / 16.0; // beam radius
- self.modelscale *= ReadByte() / 16.0; // dlight radius
- }
- if((f & 0x80) || !(f & 0x10))
- self.cnt = ReadShort() - 1; // effect number
- else
- self.cnt = 0;
- }
- if(f & 2)
- {
- if(f & 0x80)
- {
- self.velocity_x = ReadCoord();
- self.velocity_y = ReadCoord();
- self.velocity_z = ReadCoord();
- }
- else
- {
- self.angles_x = ReadAngle();
- self.angles_y = ReadAngle();
- }
- }
- if(f & 4)
- self.state = ReadByte();
- InterpolateOrigin_Note();
- self.draw = Draw_Laser;
-}
+++ /dev/null
-#ifndef CLIENT_LASER_H
-#define CLIENT_LASER_H
-
-void Ent_Laser();
-
-#endif
#include "main.qh"
-#include "controlpoint.qh"
-#include "damage.qh"
-#include "effects.qh"
-#include "generator.qh"
-#include "gibs.qh"
+#include "../common/effects/qc/all.qh"
#include "hook.qh"
-#include "hud.qh"
-#include "hud_config.qh"
-#include "laser.qh"
+#include "hud/all.qh"
#include "mapvoting.qh"
-#include "modeleffects.qh"
#include "mutators/events.qh"
-#include "particles.qh"
#include "quickmenu.qh"
#include "scoreboard.qh"
#include "shownames.qh"
#include "../common/minigames/cl_minigames_hud.qh"
#include "../common/net_notice.qh"
#include "../common/triggers/include.qh"
-#include "../common/turrets/cl_turrets.qh"
#include "../common/vehicles/all.qh"
#include "../lib/csqcmodel/cl_model.qh"
#include "../lib/csqcmodel/interpolate.qh"
// BEGIN REQUIRED CSQC FUNCTIONS
//include "main.qh"
-entity clearentity_ent;
-void clearentity(entity e)
-{
- if (!clearentity_ent)
- {
- clearentity_ent = spawn();
- clearentity_ent.classname = "clearentity";
- }
- int n = e.entnum;
- copyentity(clearentity_ent, e);
- e.entnum = n;
-}
-
#define DP_CSQC_ENTITY_REMOVE_IS_B0RKED
-void menu_show_error()
-{
- drawstring('0 200 0', _("ERROR - MENU IS VISIBLE BUT NO MENU WAS DEFINED!"), '8 8 0', '1 0 0', 1, 0);
-}
// CSQC_Init : Called every time the CSQC code is initialized (essentially at map load)
// Useful for precaching things
-void menu_sub_null()
-{
-}
-
-void draw_null(entity this) { }
-
-string forcefog;
void ConsoleCommand_macro_init();
-void CSQC_Init(void)
+void CSQC_Init()
{
prvm_language = strzone(cvar_string("prvm_language"));
#ifdef WATERMARK
- LOG_TRACEF("^4CSQC Build information: ^1%s\n", WATERMARK);
+ LOG_INFOF("^4CSQC Build information: ^1%s\n", WATERMARK);
#endif
- int i;
-
binddb = db_create();
tempdb = db_create();
ClientProgsDB = db_load("client.db");
compressShortVector_init();
draw_endBoldFont();
- menu_visible = false;
- menu_show = menu_show_error;
- menu_action = func_null;
- for(i = 0; i < 255; ++i)
- if(getplayerkeyvalue(i, "viewentity") == "")
- break;
- maxclients = i;
+ {
+ int i = 0;
+ for ( ; i < 255; ++i)
+ if (getplayerkeyvalue(i, "viewentity") == "")
+ break;
+ maxclients = i;
+ }
//registercommand("hud_configure");
//registercommand("hud_save");
gametype = 0;
// hud_fields uses strunzone on the titles!
- for(i = 0; i < MAX_HUD_FIELDS; ++i)
+ for(int i = 0; i < MAX_HUD_FIELDS; ++i)
hud_title[i] = strzone("(null)");
Cmd_HUD_SetFields(0);
// needs to be done so early because of the constants they create
static_init();
static_init_late();
+ static_init_precache();
// precaches
- Projectile_Precache();
- Tuba_Precache();
-
if(autocvar_cl_reticle)
{
precache_pic("gfx/reticle_normal");
// weapon reticles are precached in weapon files
}
- get_mi_min_max_texcoords(1); // try the CLEVER way first
- minimapname = strcat("gfx/", mi_shortname, "_radar.tga");
- shortmapname = mi_shortname;
-
- if(precache_pic(minimapname) == "")
{
- // but maybe we have a non-clever minimap
- minimapname = strcat("gfx/", mi_shortname, "_mini.tga");
- if(precache_pic(minimapname) == "")
- minimapname = ""; // FAIL
- else
- get_mi_min_max_texcoords(0); // load new texcoords
- }
+ get_mi_min_max_texcoords(1); // try the CLEVER way first
+ minimapname = strcat("gfx/", mi_shortname, "_radar.tga");
+ shortmapname = mi_shortname;
- mi_center = (mi_min + mi_max) * 0.5;
- mi_scale = mi_max - mi_min;
- minimapname = strzone(minimapname);
+ if (precache_pic(minimapname) == "")
+ {
+ // but maybe we have a non-clever minimap
+ minimapname = strcat("gfx/", mi_shortname, "_mini.tga");
+ if (precache_pic(minimapname) == "")
+ minimapname = ""; // FAIL
+ else
+ get_mi_min_max_texcoords(0); // load new texcoords
+ }
- WarpZone_Init();
+ mi_center = (mi_min + mi_max) * 0.5;
+ mi_scale = mi_max - mi_min;
+ minimapname = strzone(minimapname);
+ }
hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
draw_currentSkin = strzone(strcat("gfx/menu/", cvar_string("menu_skin")));
}
// CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc)
-void Shutdown(void)
+void Shutdown()
{
WarpZone_Shutdown();
}
void Playerchecker_Think()
-{SELFPARAM();
+{
+ SELFPARAM();
int i;
entity e;
for(i = 0; i < maxclients; ++i)
{
// player connected
if (!e)
- playerslots[i] = e = spawn();
+ {
+ playerslots[i] = e = new(playerslot);
+ make_pure(e);
+ }
e.sv_entnum = i;
e.ping = 0;
e.ping_packetloss = 0;
}
}
}
- self.nextthink = time + 0.2;
+ this.nextthink = time + 0.2;
}
void Porto_Init();
void TrueAim_Init();
-void PostInit(void)
+void PostInit()
{
- entity playerchecker;
- playerchecker = spawn();
+ entity playerchecker = new(playerchecker);
+ make_pure(playerchecker);
playerchecker.think = Playerchecker_Think;
playerchecker.nextthink = time + 0.2;
// In the case of mouse input after a setcursormode(1) call, nPrimary is xpos, nSecondary is ypos.
float CSQC_InputEvent(float bInputType, float nPrimary, float nSecondary)
{
- float bSkipKey;
- bSkipKey = false;
-
if (HUD_Panel_InputEvent(bInputType, nPrimary, nSecondary))
return true;
if (QuickMenu_InputEvent(bInputType, nPrimary, nSecondary))
return true;
- if ( HUD_Radar_InputEvent(bInputType, nPrimary, nSecondary) )
+ if (HUD_Radar_InputEvent(bInputType, nPrimary, nSecondary))
return true;
if (MapVote_InputEvent(bInputType, nPrimary, nSecondary))
if (HUD_Minigame_InputEvent(bInputType, nPrimary, nSecondary))
return true;
- if(menu_visible && menu_action)
- if(menu_action(bInputType, nPrimary, nSecondary))
- return true;
-
- return bSkipKey;
+ return false;
}
// END REQUIRED CSQC FUNCTIONS
// BEGIN OPTIONAL CSQC FUNCTIONS
void Ent_RemoveEntCS()
-{SELFPARAM();
- entcs_receiver[self.sv_entnum] = NULL;
+{
+ SELFPARAM();
+ entcs_receiver[this.sv_entnum] = NULL;
}
-void Ent_ReadEntCS()
-{SELFPARAM();
+
+NET_HANDLE(ENT_CLIENT_ENTCS, bool isnew)
+{
+ make_pure(this);
+ this.classname = "entcs_receiver";
InterpolateOrigin_Undo();
- self.classname = "entcs_receiver";
int sf = ReadByte();
if(sf & BIT(0))
- self.sv_entnum = ReadByte();
+ this.sv_entnum = ReadByte();
if (sf & BIT(1))
{
- self.origin_x = ReadShort();
- self.origin_y = ReadShort();
- self.origin_z = ReadShort();
- setorigin(self, self.origin);
+ this.origin_x = ReadShort();
+ this.origin_y = ReadShort();
+ this.origin_z = ReadShort();
+ setorigin(this, this.origin);
}
if (sf & BIT(2))
{
- self.angles_y = ReadByte() * 360.0 / 256;
- self.angles_x = self.angles_z = 0;
+ this.angles_y = ReadByte() * 360.0 / 256;
+ this.angles_x = this.angles_z = 0;
}
if (sf & BIT(3))
- self.healthvalue = ReadByte() * 10;
+ this.healthvalue = ReadByte() * 10;
if (sf & BIT(4))
- self.armorvalue = ReadByte() * 10;
+ this.armorvalue = ReadByte() * 10;
- entcs_receiver[self.sv_entnum] = self;
- self.entremove = Ent_RemoveEntCS;
- self.iflags |= IFLAG_ORIGIN;
+ return = true;
+
+ entcs_receiver[this.sv_entnum] = this;
+ this.entremove = Ent_RemoveEntCS;
+ this.iflags |= IFLAG_ORIGIN;
InterpolateOrigin_Note();
}
void Ent_Remove();
void Ent_RemovePlayerScore()
-{SELFPARAM();
- if(self.owner) {
- SetTeam(self.owner, -1);
- self.owner.gotscores = 0;
+{
+ SELFPARAM();
+ if(this.owner) {
+ SetTeam(this.owner, -1);
+ this.owner.gotscores = 0;
for(int i = 0; i < MAX_SCORE; ++i) {
- self.owner.(scores[i]) = 0; // clear all scores
+ this.owner.(scores[i]) = 0; // clear all scores
}
}
}
-void Ent_ReadPlayerScore()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_SCORES, bool isnew)
+{
+ make_pure(this);
int i, n;
bool isNew;
entity o;
// damnit -.- don't want to go change every single .sv_entnum in hud.qc AGAIN
// (no I've never heard of M-x replace-string, sed, or anything like that)
- isNew = !self.owner; // workaround for DP bug
+ isNew = !this.owner; // workaround for DP bug
n = ReadByte()-1;
#ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED
- if(!isNew && n != self.sv_entnum)
+ if(!isNew && n != this.sv_entnum)
{
//print("A CSQC entity changed its owner!\n");
- LOG_INFOF("A CSQC entity changed its owner! (edict: %d, classname: %s)\n", num_for_edict(self), self.classname);
+ LOG_INFOF("A CSQC entity changed its owner! (edict: %d, classname: %s)\n", num_for_edict(this), this.classname);
isNew = true;
Ent_Remove();
- self.enttype = ENT_CLIENT_SCORES;
}
#endif
- self.sv_entnum = n;
+ this.sv_entnum = n;
- if (!(playerslots[self.sv_entnum]))
- playerslots[self.sv_entnum] = spawn();
- o = self.owner = playerslots[self.sv_entnum];
- o.sv_entnum = self.sv_entnum;
+ o = playerslots[this.sv_entnum];
+ if (!o)
+ {
+ o = playerslots[this.sv_entnum] = new(playerslot);
+ make_pure(o);
+ }
+ this.owner = o;
+ o.sv_entnum = this.sv_entnum;
o.gotscores = 1;
//if (!o.sort_prev)
o.(scores[i]) = ReadChar();
}
+ return = true;
+
if(o.sort_prev)
HUD_UpdatePlayerPos(o); // if not registered, we cannot do this yet!
- self.entremove = Ent_RemovePlayerScore;
+ this.entremove = Ent_RemovePlayerScore;
}
-void Ent_ReadTeamScore()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TEAMSCORES, bool isnew)
+{
+ make_pure(this);
int i;
entity o;
- self.team = ReadByte();
- o = self.owner = GetTeam(self.team, true); // these team numbers can always be trusted
+ this.team = ReadByte();
+ o = this.owner = GetTeam(this.team, true); // these team numbers can always be trusted
int sf, lf;
#if MAX_TEAMSCORE <= 8
o.(teamscores[i]) = ReadChar();
}
+ return = true;
+
HUD_UpdateTeamPos(o);
}
-void Ent_ClientData()
+NET_HANDLE(ENT_CLIENT_CLIENTDATA, bool isnew)
{
+ make_pure(this);
float newspectatee_status;
int f = ReadByte();
else
angles_held_status = 0;
+ return = true;
+
if(newspectatee_status != spectatee_status)
{
// clear race stuff
// we could get rid of spectatee_status, and derive it from player_localentnum and player_localnum
}
-void Ent_Nagger()
+NET_HANDLE(ENT_CLIENT_NAGGER, bool isnew)
{
+ make_pure(this);
int i, j, b, f;
int nags = ReadByte(); // NAGS NAGS NAGS NAGS NAGS NAGS NADZ NAGS NAGS NAGS
}
}
+ return = true;
+
ready_waiting = (nags & BIT(0));
ready_waiting_for_me = (nags & BIT(1));
vote_waiting = (nags & BIT(2));
warmup_stage = (nags & BIT(4));
}
-void Ent_EliminatedPlayers()
+NET_HANDLE(ENT_CLIENT_ELIMINATEDPLAYERS, bool isnew)
{
+ make_pure(this);
int i, j, b, f;
int sf = ReadByte();
playerslots[j].eliminated = 0;
}
}
+ return true;
}
-void Ent_RandomSeed()
+NET_HANDLE(ENT_CLIENT_RANDOMSEED, bool isnew)
{
- float s;
+ make_pure(this);
prandom_debug();
- s = ReadShort();
+ float s = ReadShort();
psrandom(s);
+ return true;
}
-void Ent_ReadAccuracy(void)
+NET_HANDLE(ENT_CLIENT_ACCURACY, bool isnew)
{
- int f, w;
+ make_pure(this);
int sf = ReadInt24_t();
- if(sf == 0)
- {
- for(w = 0; w <= WEP_LAST - WEP_FIRST; ++w)
+ if (sf == 0) {
+ for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w)
weapon_accuracy[w] = -1;
- return;
+ return true;
}
- for(w = 0, f = 1; w <= WEP_LAST - WEP_FIRST; ++w)
- {
- if(sf & f)
- {
+ int f = 1;
+ for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w) {
+ if (sf & f) {
int b = ReadByte();
- if(b == 0)
+ if (b == 0)
weapon_accuracy[w] = -1;
- else if(b == 255)
+ else if (b == 255)
weapon_accuracy[w] = 1.0; // no better error handling yet, sorry
else
weapon_accuracy[w] = (b - 1.0) / 100.0;
}
- if(f == 0x800000)
- f = 1;
- else
- f *= 2;
+ f = (f == 0x800000) ? 1 : f * 2;
}
+ return true;
}
void Spawn_Draw(entity this)
{
- pointparticles(this.cnt, this.origin + '0 0 28', '0 0 2', bound(0, frametime, 0.1));
+ __pointparticles(this.cnt, this.origin + '0 0 28', '0 0 2', bound(0, frametime, 0.1));
}
-void Ent_ReadSpawnPoint(float is_new) // entity for spawnpoint
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_SPAWNPOINT, bool is_new)
+{
float teamnum = (ReadByte() - 1);
vector spn_origin;
spn_origin.x = ReadShort();
//if(is_new)
//{
- self.origin = spn_origin;
- setsize(self, PL_MIN_CONST, PL_MAX_CONST);
+ this.origin = spn_origin;
+ setsize(this, PL_MIN_CONST, PL_MAX_CONST);
//droptofloor();
/*if(autocvar_cl_spawn_point_model) // needs a model first
{
- self.mdl = "models/spawnpoint.md3";
- self.colormod = Team_ColorRGB(teamnum);
- precache_model(self.mdl);
- setmodel(self, self.mdl);
- self.drawmask = MASK_NORMAL;
- //self.movetype = MOVETYPE_NOCLIP;
- //self.draw = Spawn_Draw;
+ this.mdl = "models/spawnpoint.md3";
+ this.colormod = Team_ColorRGB(teamnum);
+ precache_model(this.mdl);
+ setmodel(this, this.mdl);
+ this.drawmask = MASK_NORMAL;
+ //this.movetype = MOVETYPE_NOCLIP;
+ //this.draw = Spawn_Draw;
}*/
if(autocvar_cl_spawn_point_particles)
{
{
switch(teamnum)
{
- case NUM_TEAM_1: self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_RED); break;
- case NUM_TEAM_2: self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_BLUE); break;
- case NUM_TEAM_3: self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_YELLOW); break;
- case NUM_TEAM_4: self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_PINK); break;
- default: self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_NEUTRAL); break;
+ case NUM_TEAM_1: this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_RED); break;
+ case NUM_TEAM_2: this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_BLUE); break;
+ case NUM_TEAM_3: this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_YELLOW); break;
+ case NUM_TEAM_4: this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_PINK); break;
+ default: this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_NEUTRAL); break;
}
}
- else { self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_NEUTRAL); }
+ else { this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_NEUTRAL); }
- self.draw = Spawn_Draw;
+ this.draw = Spawn_Draw;
}
//}
- //printf("Ent_ReadSpawnPoint(is_new = %d); origin = %s, team = %d, effect = %d\n", is_new, vtos(self.origin), teamnum, self.cnt);
+ //printf("Ent_ReadSpawnPoint(is_new = %d); origin = %s, team = %d, effect = %d\n", is_new, vtos(this.origin), teamnum, this.cnt);
+ return true;
}
-void Ent_ReadSpawnEvent(float is_new)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_SPAWNEVENT, bool is_new)
+{
// If entnum is 0, ONLY do the local spawn actions
// this way the server can disable the sending of
// spawn origin or such to clients if wanted.
if(entnum)
{
- self.origin_x = ReadShort();
- self.origin_y = ReadShort();
- self.origin_z = ReadShort();
+ this.origin_x = ReadShort();
+ this.origin_y = ReadShort();
+ this.origin_z = ReadShort();
if(is_new)
{
{
switch(teamnum)
{
- case NUM_TEAM_1: pointparticles(particleeffectnum(EFFECT_SPAWN_RED), self.origin, '0 0 0', 1); break;
- case NUM_TEAM_2: pointparticles(particleeffectnum(EFFECT_SPAWN_BLUE), self.origin, '0 0 0', 1); break;
- case NUM_TEAM_3: pointparticles(particleeffectnum(EFFECT_SPAWN_YELLOW), self.origin, '0 0 0', 1); break;
- case NUM_TEAM_4: pointparticles(particleeffectnum(EFFECT_SPAWN_PINK), self.origin, '0 0 0', 1); break;
- default: pointparticles(particleeffectnum(EFFECT_SPAWN_NEUTRAL), self.origin, '0 0 0', 1); break;
+ case NUM_TEAM_1: pointparticles(EFFECT_SPAWN_RED, this.origin, '0 0 0', 1); break;
+ case NUM_TEAM_2: pointparticles(EFFECT_SPAWN_BLUE, this.origin, '0 0 0', 1); break;
+ case NUM_TEAM_3: pointparticles(EFFECT_SPAWN_YELLOW, this.origin, '0 0 0', 1); break;
+ case NUM_TEAM_4: pointparticles(EFFECT_SPAWN_PINK, this.origin, '0 0 0', 1); break;
+ default: pointparticles(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1); break;
}
}
if(autocvar_cl_spawn_event_sound)
{
- sound(self, CH_TRIGGER, SND_SPAWN, VOL_BASE, ATTEN_NORM);
+ sound(this, CH_TRIGGER, SND_SPAWN, VOL_BASE, ATTEN_NORM);
}
}
}
+ return = true;
// local spawn actions
if(is_new && (!entnum || (entnum == player_localentnum)))
}
}
HUD_Radar_Hide_Maximized();
- //printf("Ent_ReadSpawnEvent(is_new = %d); origin = %s, entnum = %d, localentnum = %d\n", is_new, vtos(self.origin), entnum, player_localentnum);
+ //printf("Ent_ReadSpawnEvent(is_new = %d); origin = %s, entnum = %d, localentnum = %d\n", is_new, vtos(this.origin), entnum, player_localentnum);
}
// CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured.
// The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS.
-void Ent_RadarLink();
-void Ent_Init();
-void Ent_ScoresInfo();
-void CSQC_Ent_Update(float bIsNewEntity)
-{SELFPARAM();
+void CSQC_Ent_Update(bool isnew)
+{
+ SELFPARAM();
+ this.sourceLocLine = __LINE__;
+ this.sourceLocFile = __FILE__;
int t = ReadByte();
- if(autocvar_developer_csqcentities)
- LOG_INFOF("CSQC_Ent_Update(%d) with self=%i self.entnum=%d self.enttype=%d t=%d\n", bIsNewEntity, self, self.entnum, self.enttype, t);
-
// set up the "time" global for received entities to be correct for interpolation purposes
float savetime = time;
if(servertime)
}
#ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED
- if(self.enttype)
+ if (this.enttype)
{
- if(t != self.enttype || bIsNewEntity)
+ if (t != this.enttype || isnew)
{
- LOG_INFOF("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n", num_for_edict(self), self.entnum, self.enttype, t);
+ LOG_INFOF("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n", num_for_edict(this), this.entnum, this.enttype, t);
Ent_Remove();
- clearentity(self);
- bIsNewEntity = 1;
+ clearentity(this);
+ isnew = true;
}
}
else
{
- if(!bIsNewEntity)
+ if (!isnew)
{
- LOG_INFOF("A CSQC entity appeared out of nowhere! (edict: %d, server: %d, type: %d)\n", num_for_edict(self), self.entnum, t);
- bIsNewEntity = 1;
+ LOG_INFOF("A CSQC entity appeared out of nowhere! (edict: %d, server: %d, type: %d)\n", num_for_edict(this), this.entnum, t);
+ isnew = true;
}
}
#endif
- self.enttype = t;
+ this.enttype = t;
bool done = false;
FOREACH(LinkedEntities, it.m_id == t, LAMBDA(
- it.m_read(self, bIsNewEntity);
- done = true;
+ if (isnew) this.classname = it.netname;
+ if (autocvar_developer_csqcentities)
+ LOG_INFOF("CSQC_Ent_Update(%d) at %f with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", isnew, savetime, this, this.entnum, this.enttype, this.classname, t);
+ done = it.m_read(this, isnew);
break;
));
+ time = savetime;
if (!done)
- switch(t)
{
- case ENT_CLIENT_MUTATOR: {
- int mutID = ReadMutator();
- if (!MUTATOR_CALLHOOK(CSQC_Ent_Update, mutID, bIsNewEntity))
- error(sprintf("Unknown mutator type in CSQC_Ent_Update (mutID: %d, edict: %d, classname: %s)\n", mutID, num_for_edict(self), self.classname));
- break;
- }
- case ENT_CLIENT_ENTCS: Ent_ReadEntCS(); break;
- case ENT_CLIENT_SCORES: Ent_ReadPlayerScore(); break;
- case ENT_CLIENT_TEAMSCORES: Ent_ReadTeamScore(); break;
- case ENT_CLIENT_POINTPARTICLES: Ent_PointParticles(); break;
- case ENT_CLIENT_RAINSNOW: Ent_RainOrSnow(); break;
- case ENT_CLIENT_LASER: Ent_Laser(); break;
- case ENT_CLIENT_NAGGER: Ent_Nagger(); break;
- case ENT_CLIENT_ELIMINATEDPLAYERS: Ent_EliminatedPlayers(); break;
- case ENT_CLIENT_RADARLINK: Ent_RadarLink(); break;
- case ENT_CLIENT_PROJECTILE: Ent_Projectile(); break;
- case ENT_CLIENT_GIBSPLASH: Ent_GibSplash(bIsNewEntity); break;
- case ENT_CLIENT_DAMAGEINFO: Ent_DamageInfo(bIsNewEntity); break;
- case ENT_CLIENT_INIT: Ent_Init(); break;
- case ENT_CLIENT_SCORES_INFO: Ent_ScoresInfo(); break;
- case ENT_CLIENT_MAPVOTE: Ent_MapVote(); break;
- case ENT_CLIENT_CLIENTDATA: Ent_ClientData(); break;
- case ENT_CLIENT_RANDOMSEED: Ent_RandomSeed(); break;
- case ENT_CLIENT_WALL: Ent_Wall(); break;
- case ENT_CLIENT_MODELEFFECT: Ent_ModelEffect(bIsNewEntity); break;
- case ENT_CLIENT_TUBANOTE: Ent_TubaNote(bIsNewEntity); break;
- case ENT_CLIENT_WARPZONE: WarpZone_Read(bIsNewEntity); break;
- case ENT_CLIENT_WARPZONE_CAMERA: WarpZone_Camera_Read(bIsNewEntity); break;
- case ENT_CLIENT_WARPZONE_TELEPORTED: WarpZone_Teleported_Read(bIsNewEntity); break;
- case ENT_CLIENT_TRIGGER_MUSIC: Ent_ReadTriggerMusic(); break;
- case ENT_CLIENT_HOOK: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_HOOK); break;
- case ENT_CLIENT_INVENTORY: Inventory_Read(self); break;
- case ENT_CLIENT_ARC_BEAM: Ent_ReadArcBeam(bIsNewEntity); break;
- case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break;
- case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break;
- case ENT_CLIENT_TURRET: ent_turret(); break;
- case ENT_CLIENT_GENERATOR: ent_generator(); break;
- case ENT_CLIENT_CONTROLPOINT_ICON: ent_cpicon(this); break;
- case ENT_CLIENT_MODEL: CSQCModel_Read(bIsNewEntity); break;
- case ENT_CLIENT_ITEM: ItemRead(bIsNewEntity); break;
- case ENT_CLIENT_BUMBLE_RAYGUN: bumble_raygun_read(bIsNewEntity); break;
- case ENT_CLIENT_SPAWNPOINT: Ent_ReadSpawnPoint(bIsNewEntity); break;
- case ENT_CLIENT_SPAWNEVENT: Ent_ReadSpawnEvent(bIsNewEntity); break;
- case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break;
- case ENT_CLIENT_MINIGAME: ent_read_minigame(); break;
- case ENT_CLIENT_VIEWLOC: ent_viewloc(); break;
- case ENT_CLIENT_VIEWLOC_TRIGGER: ent_viewloc_trigger(); break;
- case ENT_CLIENT_LADDER: ent_func_ladder(); break;
- case ENT_CLIENT_TRIGGER_PUSH: ent_trigger_push(); break;
- case ENT_CLIENT_TARGET_PUSH: ent_target_push(); break;
- case ENT_CLIENT_CONVEYOR: ent_conveyor(); break;
- case ENT_CLIENT_DOOR: ent_door(); break;
- case ENT_CLIENT_PLAT: ent_plat(); break;
- case ENT_CLIENT_SWAMP: ent_swamp(); break;
- case ENT_CLIENT_CORNER: ent_corner(); break;
- case ENT_CLIENT_KEYLOCK: ent_keylock(); break;
- case ENT_CLIENT_TRAIN: ent_train(); break;
- case ENT_CLIENT_TRIGGER_IMPULSE: ent_trigger_impulse(); break;
- case ENT_CLIENT_EFFECT: Read_Effect(bIsNewEntity); break;
-
- default:
- //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype));
- error(sprintf("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n", self.enttype, num_for_edict(self), self.classname));
- break;
+ LOG_FATALF("CSQC_Ent_Update(%d) at %f with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", isnew, savetime, this, this.entnum, this.enttype, this.classname, t);
}
-
- time = savetime;
}
+
// Destructor, but does NOT deallocate the entity by calling remove(). Also
// used when an entity changes its type. For an entity that someone interacts
// with others, make sure it can no longer do so.
void Ent_Remove()
-{SELFPARAM();
- if(self.entremove)
- self.entremove();
+{
+ SELFPARAM();
+ if(this.entremove) this.entremove();
- if(self.skeletonindex)
+ if(this.skeletonindex)
{
- skel_delete(self.skeletonindex);
- self.skeletonindex = 0;
+ skel_delete(this.skeletonindex);
+ this.skeletonindex = 0;
}
- if(self.snd_looping > 0)
+ if(this.snd_looping > 0)
{
- sound(self, self.snd_looping, SND_Null, VOL_BASE, autocvar_g_jetpack_attenuation);
- self.snd_looping = 0;
+ sound(this, this.snd_looping, SND_Null, VOL_BASE, autocvar_g_jetpack_attenuation);
+ this.snd_looping = 0;
}
- self.enttype = 0;
- self.classname = "";
- self.draw = draw_null;
- self.entremove = menu_sub_null;
+ this.enttype = 0;
+ this.classname = "";
+ this.draw = func_null;
+ this.entremove = func_null;
// TODO possibly set more stuff to defaults
}
-// CSQC_Ent_Remove : Called when the server requests a SSQC / CSQC entity to be removed. Essentially call remove(self) as well.
+// CSQC_Ent_Remove : Called when the server requests a SSQC / CSQC entity to be removed. Essentially call remove(this) as well.
void CSQC_Ent_Remove()
-{SELFPARAM();
- if(autocvar_developer_csqcentities)
- LOG_INFOF("CSQC_Ent_Remove() with self=%i self.entnum=%d self.enttype=%d\n", self, self.entnum, self.enttype);
-
- if(wasfreed(self))
+{
+ SELFPARAM();
+ if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Ent_Remove() with this=%i {.entnum=%d, .enttype=%d}\n", this, this.entnum, this.enttype);
+ if (wasfreed(this))
{
- LOG_INFO("WARNING: CSQC_Ent_Remove called for already removed entity. Packet loss?\n");
+ LOG_WARNING("CSQC_Ent_Remove called for already removed entity. Packet loss?\n");
return;
}
- if(self.enttype)
- Ent_Remove();
- remove(self);
+ if (this.enttype) Ent_Remove();
+ remove(this);
}
void Gamemode_Init()
// CSQC_Parse_StuffCmd : Provides the stuffcmd string in the first parameter that the server provided. To execute standard behavior, simply execute localcmd with the string.
void CSQC_Parse_StuffCmd(string strMessage)
{
- if(autocvar_developer_csqcentities)
- LOG_INFOF("CSQC_Parse_StuffCmd(\"%s\")\n", strMessage);
-
+ if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Parse_StuffCmd(\"%s\")\n", strMessage);
localcmd(strMessage);
}
// CSQC_Parse_Print : Provides the print string in the first parameter that the server provided. To execute standard behavior, simply execute print with the string.
void CSQC_Parse_Print(string strMessage)
{
- if(autocvar_developer_csqcentities)
- LOG_INFOF("CSQC_Parse_Print(\"%s\")\n", strMessage);
-
+ if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Parse_Print(\"%s\")\n", strMessage);
print(ColorTranslateRGB(strMessage));
}
// CSQC_Parse_CenterPrint : Provides the centerprint_hud string in the first parameter that the server provided.
void CSQC_Parse_CenterPrint(string strMessage)
{
- if(autocvar_developer_csqcentities)
- LOG_INFOF("CSQC_Parse_CenterPrint(\"%s\")\n", strMessage);
-
+ if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Parse_CenterPrint(\"%s\")\n", strMessage);
centerprint_hud(strMessage);
}
-string notranslate_fogcmd1 = "\nfog ";
-string notranslate_fogcmd2 = "\nr_fog_exp2 0\nr_drawfog 1\n";
-void Fog_Force()
+// CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer.
+// You must ALWAYS first acquire the temporary ID, which is sent as a byte.
+// Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event.
+bool CSQC_Parse_TempEntity()
{
- // TODO somehow thwart prvm_globalset client ...
+ // Acquire TE ID
+ int nTEID = ReadByte();
+
+ FOREACH(TempEntities, it.m_id == nTEID, LAMBDA(
+ if (autocvar_developer_csqcentities)
+ LOG_INFOF("CSQC_Parse_TempEntity() nTEID=%s (%d)\n", it.netname, nTEID);
+ return it.m_read(NULL, true);
+ ));
- if(autocvar_cl_orthoview && autocvar_cl_orthoview_nofog)
- { localcmd("\nr_drawfog 0\n"); }
- else if(forcefog != "")
- { localcmd(strcat(notranslate_fogcmd1, forcefog, notranslate_fogcmd2)); }
+ if (autocvar_developer_csqcentities)
+ LOG_INFOF("CSQC_Parse_TempEntity() with nTEID=%d\n", nTEID);
+
+ // No special logic for this temporary entity; return 0 so the engine can handle it
+ return false;
+}
+
+/** TODO somehow thwart prvm_globalset client ... */
+string forcefog;
+void Fog_Force()
+{
+ if (autocvar_cl_orthoview && autocvar_cl_orthoview_nofog)
+ localcmd("\nr_drawfog 0\n");
+ else if (forcefog != "")
+ localcmd(sprintf("\nfog %s\nr_fog_exp2 0\nr_drawfog 1\n", forcefog));
}
void Gamemode_Init();
-void Ent_ScoresInfo()
-{SELFPARAM();
- int i;
- self.classname = "ent_client_scores_info";
+NET_HANDLE(ENT_CLIENT_SCORES_INFO, bool isnew)
+{
+ make_pure(this);
gametype = ReadInt24_t();
HUD_ModIcons_SetFunc();
- for(i = 0; i < MAX_SCORE; ++i)
+ for (int i = 0; i < MAX_SCORE; ++i)
{
- if(scores_label[i])
- strunzone(scores_label[i]);
+ if (scores_label[i]) strunzone(scores_label[i]);
scores_label[i] = strzone(ReadString());
scores_flags[i] = ReadByte();
}
- for(i = 0; i < MAX_TEAMSCORE; ++i)
+ for (int i = 0; i < MAX_TEAMSCORE; ++i)
{
- if(teamscores_label[i])
- strunzone(teamscores_label[i]);
+ if (teamscores_label[i]) strunzone(teamscores_label[i]);
teamscores_label[i] = strzone(ReadString());
teamscores_flags[i] = ReadByte();
}
+ return = true;
HUD_InitScores();
Gamemode_Init();
}
-void Ent_Init()
-{SELFPARAM();
- self.classname = "ent_client_init";
-
+NET_HANDLE(ENT_CLIENT_INIT, bool isnew)
+{
nb_pb_period = ReadByte() / 32; //Accuracy of 1/32th
hook_shotorigin[0] = decompressShotOrigin(ReadInt24_t());
arc_shotorigin[2] = decompressShotOrigin(ReadInt24_t());
arc_shotorigin[3] = decompressShotOrigin(ReadInt24_t());
- if(forcefog)
- strunzone(forcefog);
+ if (forcefog) strunzone(forcefog);
forcefog = strzone(ReadString());
armorblockpercent = ReadByte() / 255.0;
g_trueaim_minrange = ReadCoord();
g_balance_porto_secondary = ReadByte();
+ return = true;
+
+ MUTATOR_CALLHOOK(Ent_Init);
- if(!postinit)
- PostInit();
+ if (!postinit) PostInit();
}
-void Net_ReadRace()
+NET_HANDLE(TE_CSQC_RACE, bool isNew)
{
- float b;
+ int b = ReadByte();
- b = ReadByte();
-
- switch(b)
+ switch (b)
{
case RACE_NET_CHECKPOINT_HIT_QUALIFYING:
race_checkpoint = ReadByte();
strunzone(race_status_name);
race_status_name = strzone(ReadString());
}
+ return true;
}
-void Net_TeamNagger()
+NET_HANDLE(TE_CSQC_TEAMNAGGER, bool isNew)
{
teamnagger = 1;
+ return true;
}
-void Net_ReadPingPLReport()
+NET_HANDLE(TE_CSQC_PINGPLREPORT, bool isNew)
{
- int e, pi, pl, ml;
- e = ReadByte();
- pi = ReadShort();
- pl = ReadByte();
- ml = ReadByte();
- if (!(playerslots[e]))
- return;
- playerslots[e].ping = pi;
- playerslots[e].ping_packetloss = pl / 255.0;
- playerslots[e].ping_movementloss = ml / 255.0;
+ int i = ReadByte();
+ int pi = ReadShort();
+ int pl = ReadByte();
+ int ml = ReadByte();
+ return = true;
+ entity e = playerslots[i];
+ if (!e) return;
+ e.ping = pi;
+ e.ping_packetloss = pl / 255.0;
+ e.ping_movementloss = ml / 255.0;
}
-void Net_WeaponComplain()
+NET_HANDLE(TE_CSQC_WEAPONCOMPLAIN, bool isNew)
{
complain_weapon = ReadByte();
-
- if(complain_weapon_name)
- strunzone(complain_weapon_name);
+ if (complain_weapon_name) strunzone(complain_weapon_name);
complain_weapon_name = strzone(WEP_NAME(complain_weapon));
-
complain_weapon_type = ReadByte();
+ return = true;
complain_weapon_time = time;
weapontime = time; // ping the weapon panel
}
}
-// CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer.
-// You must ALWAYS first acquire the temporary ID, which is sent as a byte.
-// Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event.
-bool CSQC_Parse_TempEntity()
-{
- // Acquire TE ID
- int nTEID = ReadByte();
-
- if (autocvar_developer_csqcentities)
- LOG_INFOF("CSQC_Parse_TempEntity() with nTEID=%d\n", nTEID);
-
- FOREACH(TempEntities, it.m_id == nTEID, LAMBDA(
- it.m_read(NULL, true);
- return true;
- ));
- switch (nTEID)
- {
- case TE_CSQC_MUTATOR:
- int mutID = ReadMutator();
- if (MUTATOR_CALLHOOK(CSQC_Parse_TempEntity, mutID))
- return true;
- case TE_CSQC_TARGET_MUSIC:
- Net_TargetMusic();
- return true;
- case TE_CSQC_PICTURE:
- Net_MapVote_Picture();
- return true;
- case TE_CSQC_RACE:
- Net_ReadRace();
- return true;
- case TE_CSQC_VORTEXBEAMPARTICLE:
- Net_ReadVortexBeamParticle();
- return true;
- case TE_CSQC_TEAMNAGGER:
- Net_TeamNagger();
- return true;
- case TE_CSQC_ARC:
- Net_ReadArc();
- return true;
- case TE_CSQC_PINGPLREPORT:
- Net_ReadPingPLReport();
- return true;
- case TE_CSQC_WEAPONCOMPLAIN:
- Net_WeaponComplain();
- return true;
- case TE_CSQC_VEHICLESETUP:
- Net_VehicleSetup();
- return true;
- case TE_CSQC_SVNOTICE:
- cl_notice_read();
- return true;
- case TE_CSQC_SHOCKWAVEPARTICLE:
- Net_ReadShockwaveParticle();
- return true;
- default:
- // No special logic for this temporary entity; return 0 so the engine can handle it
- return false;
- }
-}
-
string getcommandkey(string text, string command)
{
string keys;
#define DATABUF_NEXT (5*maxclients)
-void() menu_show_error;
-void() menu_sub_null;
-
-float menu_visible;
-var void() menu_show;
-var float(float bInputType, float nPrimary, float nSecondary) menu_action;
-
// --------------------------------------------------------------------------
// Onslaught
.void(entity) draw;
.void(entity) draw2d;
-.void(void) entremove;
+.void() entremove;
float drawframetime;
vector view_origin, view_forward, view_right, view_up;
int activeweapon;
int switchingweapon;
-int switchweapon;
+#define switchweapon STAT(SWITCHWEAPON)
float current_viewzoom;
float zoomin_effect;
float warmup_stage;
#include "mapvoting.qh"
-#include "hud.qh"
+#include "hud/all.qh"
#include "scoreboard.qh"
#include "../common/mapinfo.qh"
mv_ownvote = ReadByte()-1;
}
-void Ent_MapVote()
+NET_HANDLE(ENT_CLIENT_MAPVOTE, bool isnew)
{
+ make_pure(self);
int sf = ReadByte();
+ return = true;
if(sf & 1)
MapVote_Init();
MapVote_UpdateVotes();
}
+NET_HANDLE(TE_CSQC_PICTURE, bool isNew)
+{
+ Net_MapVote_Picture();
+ return true;
+}
+
void Net_MapVote_Picture()
{
int type = ReadByte();
float MapVote_InputEvent(float bInputType, float nPrimary, float nSecondary);
-void Ent_MapVote();
-
void Net_MapVote_Picture();
float mv_active;
#include "miscfunctions.qh"
-#include "hud.qh"
+#include "hud/all.qh"
#include "../common/command/generic.qh"
return teamslots[num];
if (!add)
return world;
- entity tm = spawn();
+ entity tm = new(team);
+ make_pure(tm);
tm.team = Team;
teamslots[num] = tm;
RegisterTeam(tm);
return false;
}
-vector rotate(vector v, float a)
-{
- vector w = '0 0 0';
- // FTEQCC SUCKS AGAIN
- w.x = v.x * cos(a) + v.y * sin(a);
- w.y = -1 * v.x * sin(a) + v.y * cos(a);
- return w;
-}
-
// decolorizes and team colors the player name when needed
string playername(string thename, float teamid)
{
return vec;
}
-void dummyfunction(float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8)
-{
-}
-
float expandingbox_sizefactor_from_fadelerp(float fadelerp)
{
return 1.2 / (1.2 - fadelerp);
sz = expandingbox_sizefactor_from_fadelerp(fadelerp);
drawfontscale = sz * '1 1 0';
- dummyfunction(0, 0, 0, 0, 0, 0, 0, 0);
drawstring(position + expandingbox_resize_centered_box_offset(sz, theScale, stringwidth(text, false, theScale * (sz / drawfontscale.x)) / (theScale.x * sz)), text, theScale * (sz / drawfontscale.x), rgb, theAlpha * (1 - fadelerp), flag);
// width parameter:
// (scale_x * sz / drawfontscale_x) * drawfontscale_x * SIZE1 / (scale_x * sz)
sz = expandingbox_sizefactor_from_fadelerp(fadelerp);
drawfontscale = sz * '1 1 0';
- dummyfunction(0, 0, 0, 0, 0, 0, 0, 0);
drawcolorcodedstring(position + expandingbox_resize_centered_box_offset(sz, theScale, stringwidth(text, true, theScale * (sz / drawfontscale.x)) / (theScale.x * sz)), text, theScale * (sz / drawfontscale.x), theAlpha * (1 - fadelerp), flag);
drawfontscale = '1 1 0';
}
return false;
}
+/** engine callback */
void URI_Get_Callback(int id, float status, string data)
{
if(url_URI_Get_Callback(id, status, data))
}
}
-void draw_beginBoldFont()
-{
- drawfont = FONT_USER+2;
-}
-
-void draw_endBoldFont()
-{
- drawfont = FONT_USER+1;
-}
-
void Accuracy_LoadLevels()
{
if(autocvar_accuracy_color_levels != acc_color_levels)
vector project_3d_to_2d(vector vec);
-void dummyfunction(float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8);
+#define draw_beginBoldFont() do { drawfont = FONT_USER + 2; } while (0)
+#define draw_endBoldFont() do { drawfont = FONT_USER + 1; } while (0)
float expandingbox_sizefactor_from_fadelerp(float fadelerp);
float getplayerisdead(float pl);
-void URI_Get_Callback(int id, float status, string data);
-
-void draw_beginBoldFont();
-
-void draw_endBoldFont();
-
-
const int MAX_ACCURACY_LEVELS = 10;
float acc_lev[MAX_ACCURACY_LEVELS];
vector acc_col[MAX_ACCURACY_LEVELS];
+++ /dev/null
-#include "modeleffects.qh"
-
-.float cnt;
-.float scale;
-.float alpha;
-
-void ModelEffect_Draw(entity this)
-{
- self.angles = self.angles + frametime * self.avelocity;
- setorigin(self, self.origin + frametime * self.velocity);
- self.scale = self.scale1 + (self.scale2 - self.scale1) * (time - self.teleport_time) / (self.lifetime + self.fadetime - self.teleport_time);
- self.alpha = self.cnt * bound(0, 1 - (time - self.lifetime) / self.fadetime, 1);
- if(self.alpha < ALPHA_MIN_VISIBLE)
- {
- remove(self);
- return;
- }
- self.drawmask = MASK_NORMAL;
- if(self.scale <= 0)
- {
- self.drawmask = 0;
- return;
- }
-}
-
-void Ent_ModelEffect(bool isNew)
-{SELFPARAM();
- self.classname = "modeleffect_spawner";
-
- int f = ReadByte();
-
- entity e = spawn();
- e.classname = "modeleffect";
- e.model = "from network";
- e.modelindex = ReadShort();
- e.skin = ReadByte();
- e.frame = ReadByte();
- e.frame1time = time;
- e.origin_x = ReadCoord();
- e.origin_y = ReadCoord();
- e.origin_z = ReadCoord();
- setorigin(e, e.origin);
- if(f & 1)
- {
- e.velocity_x = ReadCoord();
- e.velocity_y = ReadCoord();
- e.velocity_z = ReadCoord();
- }
- if(f & 2)
- {
- e.angles_x = ReadAngle();
- e.angles_y = ReadAngle();
- e.angles_z = ReadAngle();
- }
- if(f & 4)
- {
- e.avelocity_x = ReadAngle();
- e.avelocity_y = ReadAngle();
- e.avelocity_z = ReadAngle();
- }
- e.scale1 = ReadShort() / 256.0;
- e.scale2 = ReadShort() / 256.0;
- e.lifetime = time + ReadByte() * 0.01;
- e.fadetime = ReadByte() * 0.01;
- e.teleport_time = time;
- e.cnt = ReadByte() / 255.0; // actually alpha
-
- e.draw = ModelEffect_Draw;
-
- if(!isNew)
- remove(e); // yes, this IS stupid, but I don't need to duplicate all the read* stuff then
-}
+++ /dev/null
-#ifndef CLIENT_MODELEFFECTS_H
-#define CLIENT_MODELEFFECTS_H
-
-entityclass(ModelEffect);
-class(ModelEffect) .float frame1time;
-class(ModelEffect) .float lifetime, fadetime;
-class(ModelEffect) .float teleport_time;
-class(ModelEffect) .float scale1, scale2;
-
-void ModelEffect_Draw(entity this);
-
-void Ent_ModelEffect(bool isNew);
-#endif
* }
*/
#define EV_CSQC_ConsoleCommand(i, o) \
- /** command name */ i(string, cmd_name) \
- /** also, argv() can be used */ i(int, cmd_argc) \
- /** whole command, use only if you really have to */ i(string, cmd_string) \
- /**/
+ /** command name */ i(string, cmd_name) \
+ /** also, argv() can be used */ i(int, cmd_argc) \
+ /** whole command, use only if you really have to */ i(string, cmd_string) \
+ /**/
MUTATOR_HOOKABLE(CSQC_ConsoleCommand, EV_CSQC_ConsoleCommand);
/* Called when the crosshair is being updated */
MUTATOR_HOOKABLE(UpdateCrosshair, EV_NO_ARGS);
-/**
- * Called when a temp entity is parsed
- * NOTE: hooks MUST start with:
- * if (MUTATOR_RETURNVALUE) return;
- * if (!ReadMutatorEquals(mutator_argv_int_0, name_of_mutator)) return;
- * return = true;
- */
-#define EV_CSQC_Parse_TempEntity(i, o) \
- /** mutator id */ i(int, mutator_argv_int_0) \
- /**/
-MUTATOR_HOOKABLE(CSQC_Parse_TempEntity, EV_CSQC_Parse_TempEntity);
-
-/**
- * Called when a shared entity is updated
- * if (MUTATOR_RETURNVALUE) return;
- * if (!ReadMutatorEquals(mutator_argv_int_0, name_of_mutator)) return;
- * return = true;
- */
-#define EV_CSQC_Ent_Update(i, o) \
- /** mutator id */ i(int, mutator_argv_int_0) \
- /** bIsNewEntity */ i(bool, mutator_argv_bool_0) \
- /**/
-MUTATOR_HOOKABLE(CSQC_Ent_Update, EV_CSQC_Ent_Update);
-
/** Called when a projectile is linked with CSQC */
#define EV_Ent_Projectile(i, o) \
- /** entity id */ i(entity, __self) \
- /**/
+ /** entity id */ i(entity, __self) \
+ /**/
MUTATOR_HOOKABLE(Ent_Projectile, EV_Ent_Projectile);
/** Called when a projectile's properties are being modified */
#define EV_EditProjectile(i, o) \
- /** entity id */ i(entity, __self) \
- /**/
+ /** entity id */ i(entity, __self) \
+ /**/
MUTATOR_HOOKABLE(EditProjectile, EV_EditProjectile);
/* Called when projectiles are precached */
/** Called when updating the attached tags index */
#define EV_TagIndex_Update(i, o) \
- /** entity id */ i(entity, __self) \
- /**/
+ /** entity id */ i(entity, __self) \
+ /**/
MUTATOR_HOOKABLE(TagIndex_Update, EV_TagIndex_Update);
/** Called when setting the attached tags */
#define EV_TagIndex_Apply(i, o) \
- /** entity id */ i(entity, __self) \
- /**/
+ /** entity id */ i(entity, __self) \
+ /**/
MUTATOR_HOOKABLE(TagIndex_Apply, EV_TagIndex_Apply);
/** Called when setting up skeleton bones */
#define EV_Skeleton_CheckBones(i, o) \
- /** entity id */ i(entity, __self) \
- /**/
+ /** entity id */ i(entity, __self) \
+ /**/
MUTATOR_HOOKABLE(Skeleton_CheckBones, EV_Skeleton_CheckBones);
/** Called when setting up bones from the loaded model */
#define EV_Skeleton_CheckModel(i, o) \
- /** entity id */ i(entity, __self) \
- /**/
+ /** entity id */ i(entity, __self) \
+ /**/
MUTATOR_HOOKABLE(Skeleton_CheckModel, EV_Skeleton_CheckModel);
/** Called when clearing the global parameters for a model */
/** Called when getting the global parameters for a model */
#define EV_GetModelParams(i, o) \
- /** entity id */ i(string, checkmodel_input) \
- /** entity id */ i(string, checkmodel_command) \
- /**/
+ /** entity id */ i(string, checkmodel_input) \
+ /** entity id */ i(string, checkmodel_command) \
+ /**/
string checkmodel_input, checkmodel_command;
MUTATOR_HOOKABLE(GetModelParams, EV_GetModelParams);
/** called when a player presses the jump key */
#define EV_PlayerJump(i, o) \
- /**/ i(float, player_multijump) \
- /**/ i(float, player_jumpheight) \
- /**/ o(float, player_multijump) \
- /**/ o(float, player_jumpheight) \
- /**/
+ /**/ i(float, player_multijump) \
+ /**/ i(float, player_jumpheight) \
+ /**/ o(float, player_multijump) \
+ /**/ o(float, player_jumpheight) \
+ /**/
float player_multijump;
float player_jumpheight;
MUTATOR_HOOKABLE(PlayerJump, EV_PlayerJump);
/** Called checking if 3rd person mode should be forced on */
#define EV_WantEventchase(i, o) \
- /** entity id */ i(entity, __self) \
- /**/
+ /** entity id */ i(entity, __self) \
+ /**/
MUTATOR_HOOKABLE(WantEventchase, EV_WantEventchase);
+#define EV_AnnouncerOption(i, o) \
+ /**/ i(string, ret_string) \
+ /**/ o(string, ret_string) \
+ /**/
+MUTATOR_HOOKABLE(AnnouncerOption, EV_AnnouncerOption);
+
+MUTATOR_HOOKABLE(Ent_Init, EV_NO_ARGS);
+
+#define EV_HUD_Draw_overlay(i, o) \
+ /**/ o(vector, MUTATOR_ARGV_0_vector) \
+ /**/ o(float, MUTATOR_ARGV_0_float) \
+ /**/
+MUTATOR_HOOKABLE(HUD_Draw_overlay, EV_HUD_Draw_overlay);
+
+MUTATOR_HOOKABLE(HUD_Powerups_add, EV_NO_ARGS);
+
+/** Return true to not draw any vortex beam */
+#define EV_Particles_VortexBeam(i, o) \
+ /**/ i(vector, vbeam_shotorg) \
+ /**/ i(vector, vbeam_endpos) \
+ /**/
+vector vbeam_shotorg;
+vector vbeam_endpos;
+MUTATOR_HOOKABLE(Particles_VortexBeam, EV_Particles_VortexBeam);
+
+/** Return true to not draw any impact effect */
+#define EV_Weapon_ImpactEffect(i, o) \
+ /**/ i(entity, w_hitwep) \
+ /**/
+entity w_hitwep;
+MUTATOR_HOOKABLE(Weapon_ImpactEffect, EV_Weapon_ImpactEffect);
+
#endif
+++ /dev/null
-#include "particles.qh"
-
-#include "../common/stats.qh"
-
-#include "../lib/warpzone/common.qh"
-
-void Net_ReadVortexBeamParticle()
-{
- vector shotorg, endpos;
- float charge;
- shotorg.x = ReadCoord(); shotorg.y = ReadCoord(); shotorg.z = ReadCoord();
- endpos.x = ReadCoord(); endpos.y = ReadCoord(); endpos.z = ReadCoord();
- charge = ReadByte() / 255.0;
-
- pointparticles(particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH), shotorg, normalize(endpos - shotorg) * 1000, 1);
-
- //draw either the old v2.3 beam or the new beam
- charge = sqrt(charge); // divide evenly among trail spacing and alpha
- particles_alphamin = particles_alphamax = particles_fade = charge;
-
- if (autocvar_cl_particles_oldvortexbeam && (getstati(STAT_ALLOW_OLDVORTEXBEAM) || isdemo()))
- WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM_OLD), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
- else
- WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
-}
+++ /dev/null
-#ifndef CLIENT_PARTICLES_H
-#define CLIENT_PARTICLES_H
-.int dphitcontentsmask;
-
-entityclass(PointParticles);
-class(PointParticles) .int cnt; // effect number
-class(PointParticles) .vector velocity; // particle velocity
-class(PointParticles) .float waterlevel; // direction jitter
-class(PointParticles) .int count; // count multiplier
-class(PointParticles) .int impulse; // density
-class(PointParticles) .string noise; // sound
-class(PointParticles) .float atten;
-class(PointParticles) .float volume;
-class(PointParticles) .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
-class(PointParticles) .vector movedir; // trace direction
-
-void Draw_PointParticles(entity this);
-
-void Ent_PointParticles_Remove();
-
-void Ent_PointParticles();
-
-class(PointParticles) .float glow_color; // palette index
-
-void Net_ReadVortexBeamParticle();
-#endif
#include "../lib/_all.inc"
#include "_all.qh"
+#include "../common/effects/qc/all.qc"
+
#include "announcer.qc"
#include "bgmscript.qc"
-#include "controlpoint.qc"
#include "csqcmodel_hooks.qc"
-#include "damage.qc"
-#include "effects.qc"
-#include "generator.qc"
-#include "gibs.qc"
#include "hook.qc"
-#include "hud.qc"
-#include "hud_config.qc"
+#include "hud/all.qc"
#include "main.qc"
#include "mapvoting.qc"
#include "miscfunctions.qc"
-#include "modeleffects.qc"
#include "movelib.qc"
-#include "particles.qc"
#include "player_skeleton.qc"
-#include "rubble.qc"
#include "scoreboard.qc"
#include "shownames.qc"
#include "teamradar.qc"
#include "../common/minigames/minigames.qc"
#include "../common/minigames/cl_minigames.qc"
-#include "../common/buffs/all.qc"
#include "../common/deathtypes/all.qc"
#include "../common/effects/all.qc"
#include "../common/gamemodes/all.qc"
#include "../common/items/all.qc"
#include "../common/monsters/all.qc"
#include "../common/mutators/all.qc"
-#include "../common/nades/all.qc"
#include "../common/turrets/all.qc"
#include "../common/vehicles/all.qc"
#include "../common/weapons/all.qc"
#include "../lib/csqcmodel/cl_player.qc"
#include "../lib/csqcmodel/interpolate.qc"
-// TODO: move to common
-#include "../server/mutators/mutator/mutator_multijump.qc"
-#define IMPLEMENTATION
-#include "../server/mutators/mutator/mutator_multijump.qc"
-#undef IMPLEMENTATION
-
#include "../lib/warpzone/anglestransform.qc"
#include "../lib/warpzone/client.qc"
#include "../lib/warpzone/common.qc"
#include "quickmenu.qh"
-#include "hud.qh"
-#include "hud_config.qh"
+#include "hud/all.qh"
#include "mapvoting.qh"
// QUICKMENU_MAXLINES must be <= 10
if(mode == "file")
{
if(autocvar_hud_panel_quickmenu_file == "" || autocvar_hud_panel_quickmenu_file == "0")
- printf("No file name is set in hud_panel_quickmenu_file, loading default quickmenu\n");
+ LOG_INFO("No file name is set in hud_panel_quickmenu_file, loading default quickmenu\n");
else
{
fh = fopen(autocvar_hud_panel_quickmenu_file, FILE_READ);
if(fh < 0)
- printf("Couldn't open file \"%s\", loading default quickmenu\n", autocvar_hud_panel_quickmenu_file);
+ LOG_INFOF("Couldn't open file \"%s\", loading default quickmenu\n", autocvar_hud_panel_quickmenu_file);
}
if(fh < 0)
mode = "default";
}
else
{
- printf("Unrecognized mode %s\n", mode);
+ LOG_WARNINGF("Unrecognized mode %s\n", mode);
return false;
}
// printf("^1 skipping %s\n", s);
}
if(QuickMenu_Buffer_Index == QuickMenu_Buffer_Size)
- printf("Couldn't find submenu \"%s\"\n", z_submenu);
+ LOG_WARNINGF("Couldn't find submenu \"%s\"\n", z_submenu);
}
// only the last page can contain up to QUICKMENU_MAXLINES entries
drawcolorcodedstring(pos, entry, fontsize, panel_fg_alpha, DRAWFLAG_ADDITIVE);
}
-void HUD_QuickMenu(void)
+void HUD_QuickMenu()
{
if(!autocvar__hud_configure)
{
if(target_submenu != "" && !target_submenu_found)
{
- printf("Couldn't find submenu \"%s\"\n", target_submenu);
+ LOG_WARNINGF("Couldn't find submenu \"%s\"\n", target_submenu);
if(prvm_language != "en")
- printf("^3Warning: submenu must be in English\n", target_submenu);
+ LOG_WARNINGF("^3Warning: submenu must be in English\n", target_submenu);
QuickMenu_Buffer_Size = 0;
}
}
+++ /dev/null
-#include "rubble.qh"
-
-// LordHavoc: rewrote this file, it was really bad code
-
-void RubbleLimit(string cname, float limit, void() deleteproc)
-{SELFPARAM();
- entity e;
- entity oldest;
- float c;
- float oldesttime;
-
- // remove rubble of the same type if it's at the limit
- // remove multiple rubble if the limit has been decreased
- while(1)
- {
- e = findchain(classname,cname);
- if (e == world)
- break;
- // walk the list and count the entities, find the oldest
- // initialize our search with the first entity
- c = 1;
- oldest = e;
- oldesttime = e.creationtime;
- e = e.chain;
- // compare to all other matching entities
- while (e)
- {
- c = c + 1;
- if (oldesttime > e.creationtime)
- {
- oldesttime = e.creationtime;
- oldest = e;
- }
- e = e.chain;
- }
-
- // stop if there are less than the limit already
- if (c <= limit)
- break;
-
- // delete this oldest one and search again
- WITH(entity, self, oldest, deleteproc());
- }
-}
-
-entity RubbleNew(string cname)
-{
- entity e;
- // spawn a new entity and return it
- e = spawn();
- e.classname = cname;
- e.creationtime = time;
- return e;
-}
+++ /dev/null
-#ifndef CLIENT_RUBBLE_H
-#define CLIENT_RUBBLE_H
-entityclass(Rubble);
-class(Rubble) .float creationtime;
-void RubbleLimit(string cname, float limit, void() deleteproc);
-entity RubbleNew(string cname);
-#endif
#include "scoreboard.qh"
#include "quickmenu.qh"
-#include "hud.qh"
+#include "hud/all.qh"
#include "../common/constants.qh"
#include "../common/mapinfo.qh"
case "captime": return CTX(_("SCO^captime"));
case "deaths": return CTX(_("SCO^deaths"));
case "destroyed": return CTX(_("SCO^destroyed"));
+ case "dmg": return CTX(_("SCO^dmg"));
+ case "dmgtaken": return CTX(_("SCO^dmgtaken"));
case "drops": return CTX(_("SCO^drops"));
case "faults": return CTX(_("SCO^faults"));
case "fckills": return CTX(_("SCO^fckills"));
LOG_INFO(_("^3suicides^7 Number of suicides\n"));
LOG_INFO(_("^3frags^7 kills - suicides\n"));
LOG_INFO(_("^3kd^7 The kill-death ratio\n"));
+ LOG_INFO(_("^3dmg^7 The total damage done\n"));
+ LOG_INFO(_("^3dmgtaken^7 The total damage taken\n"));
LOG_INFO(_("^3sum^7 frags - deaths\n"));
LOG_INFO(_("^3caps^7 How often a flag (CTF) or a key (KeyHunt) was captured\n"));
LOG_INFO(_("^3pickups^7 How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
#define HUD_DefaultColumnLayout() \
"ping pl name | " \
"-teams,rc,lms/kills +ft,tdm/kills -teams,lms/deaths +ft,tdm/deaths -teams,lms,rc,ka/suicides +ft,tdm/suicides -rc,dm,tdm,ka,ft/frags " /* tdm already has this in "score" */ \
+"dmg dmgtaken " \
"+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns +ons/caps +ons/takes " \
"+lms/lives +lms/rank " \
"+kh/caps +kh/pushes +kh/destroyed " \
case "sum": case "diff": case "k-d": hud_field[hud_num_fields] = SP_SUM; break;
case "name": case "nick": hud_field[hud_num_fields] = SP_NAME; have_name = true; break;
case "|": hud_field[hud_num_fields] = SP_SEPARATOR; have_separator = true; break;
+ case "dmg": hud_field[hud_num_fields] = SP_DMG; break;
+ case "dmgtaken": hud_field[hud_num_fields] = SP_DMGTAKEN; break;
default:
{
for(j = 0; j < MAX_SCORE; ++j)
}
return ftos(f);
+ case SP_DMG:
+ num = pl.(scores[SP_DMG]);
+ denom = 1000;
+
+ str = sprintf("%.1f k", num/denom);
+ return str;
+
+ case SP_DMGTAKEN:
+ num = pl.(scores[SP_DMGTAKEN]);
+ denom = 1000;
+
+ str = sprintf("%.1f k", num/denom);
+ return str;
+
default:
tmp = pl.(scores[field]);
f = scores_flags[field];
float average_accuracy;
vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
-{SELFPARAM();
+{
+ SELFPARAM();
WepSet weapons_stat = WepSet_GetFromStat();
WepSet weapons_inmap = WepSet_GetFromStat_InMap();
float initial_posx = pos.x;
- int i;
- float weapon_stats;
int disownedcnt = 0;
- for(i = WEP_FIRST; i <= WEP_LAST; ++i)
- {
+ for (int i = WEP_FIRST; i <= WEP_LAST; ++i) {
setself(get_weaponinfo(i));
- if(!self.weapon)
- continue;
+ if (!self.weapon) continue;
- weapon_stats = weapon_accuracy[i-WEP_FIRST];
+ int weapon_stats = weapon_accuracy[i - WEP_FIRST];
- if(weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
+ if (weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
++disownedcnt;
}
int weapon_cnt = (Weapons_COUNT - 1) - disownedcnt;
+ if (weapon_cnt <= 0) return pos;
- if(weapon_cnt <= 0)
- return pos;
-
- int rows;
- if(autocvar_scoreboard_accuracy_doublerows && weapon_cnt >= floor((Weapons_COUNT - 1) * 0.5))
+ int rows = 1;
+ if (autocvar_scoreboard_accuracy_doublerows && weapon_cnt >= floor((Weapons_COUNT - 1) * 0.5))
rows = 2;
- else
- rows = 1;
int columnns = ceil(weapon_cnt / rows);
float height = 40;
drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
// column highlighting
- for(i = 0; i < columnns; ++i)
+ for (int i = 0; i < columnns; ++i)
{
- if(!(i % 2))
+ if ((i % 2) == 0)
drawfill(pos + '1 0 0' * weapon_width * rows * i, '0 1 0' * height * rows + '1 0 0' * weapon_width * rows, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
}
// row highlighting
- for(i = 0; i < rows; ++i)
+ for (int i = 0; i < rows; ++i)
{
drawfill(pos + '0 1 0' * weapon_height + '0 1 0' * height * i, '1 0 0' * sbwidth + '0 1 0' * fontsize, '1 1 1', scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
}
average_accuracy = 0;
int weapons_with_stats = 0;
- if(rows == 2)
+ if (rows == 2)
pos.x += weapon_width / 2;
- if(autocvar_scoreboard_accuracy_nocolors)
+ if (autocvar_scoreboard_accuracy_nocolors)
rgb = '1 1 1';
else
Accuracy_LoadColors();
float oldposx = pos.x;
vector tmpos = pos;
- int column;
- for(i = WEP_FIRST, column = 0; i <= WEP_LAST; ++i)
- {
+ int column = 0;
+ for (int i = WEP_FIRST; i <= WEP_LAST; ++i) {
setself(get_weaponinfo(i));
- if (!self.weapon)
- continue;
- weapon_stats = weapon_accuracy[i-WEP_FIRST];
+ if (!self.weapon) continue;
+ int weapon_stats = weapon_accuracy[i - WEP_FIRST];
- if(weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
+ if (weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
continue;
float weapon_alpha;
- if(weapon_stats >= 0)
+ if (weapon_stats >= 0)
weapon_alpha = scoreboard_alpha_fg;
else
weapon_alpha = 0.2 * scoreboard_alpha_fg;
// weapon icon
drawpic_aspect_skin(tmpos, self.model2, '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
// the accuracy
- if(weapon_stats >= 0) {
+ if (weapon_stats >= 0) {
weapons_with_stats += 1;
average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
}
tmpos.x += weapon_width * rows;
pos.x += weapon_width * rows;
- if(rows == 2 && column == columnns - 1) {
+ if (rows == 2 && column == columnns - 1) {
tmpos.x = oldposx;
tmpos.y += height;
pos.y += height;
++column;
}
- if(weapons_with_stats)
+ if (weapons_with_stats)
average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
pos.y += height;
}
pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
}
- else if(autocvar_scoreboard_accuracy && spectatee_status == 0 && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL) {
+ else if (autocvar_scoreboard_accuracy && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL) {
if(teamplay)
pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
else
void HUD_InitScores();
void HUD_UpdatePlayerPos(entity pl);
void HUD_UpdateTeamPos(entity Team);
-float HUD_WouldDrawScoreboard(void);
+float HUD_WouldDrawScoreboard();
#endif
#include "shownames.qh"
-#include "hud.qh"
+#include "hud/all.qh"
#include "../common/constants.qh"
#include "../common/mapinfo.qh"
e = shownames_ent[i];
if(!e)
{
- e = spawn();
- e.classname = "shownames_tag";
+ e = new(shownames_tag);
e.sv_entnum = i+1;
shownames_ent[i] = e;
}
-#include "../common/buffs/all.qh"
#include "../common/movetypes/movetypes.qh"
#include "../common/weapons/all.qh"
#include "../lib/csqcmodel/cl_model.qh"
#include "teamradar.qh"
-#include "hud.qh"
+#include "hud/all.qh"
#include "../common/mutators/mutator/waypoints/all.qh"
return out;
}
-vector yinvert(vector v)
-{
- v.y = 1 - v.y;
- return v;
-}
-
void draw_teamradar_background(float fg)
{
float fga;
// radar links
-void Ent_RadarLink()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_RADARLINK, bool isnew)
+{
int sendflags = ReadByte();
InterpolateOrigin_Undo();
self.team = ReadByte();
}
+ return = true;
+
InterpolateOrigin_Note();
}
vector teamradar_texcoord_to_3dcoord(vector in,float z);
-vector yinvert(vector v);
-
void draw_teamradar_background(float fg);
void draw_teamradar_player(vector coord3d, vector pangles, vector rgb);
void teamradar_loadcvars();
-// radar links
-
-void Ent_RadarLink();
-
#endif
#include "../common/constants.qh"
-#define TUBA_STARTNOTE(i, n) W_Sound(strcat("tuba", (i ? ftos(i) : ""), "_loopnote", ftos(n)))
+#define TUBA_STARTNOTE(i, n) _Sound_fixpath(W_Sound(strcat("tuba", (i ? ftos(i) : ""), "_loopnote", ftos(n))))
const int TUBA_MIN = -18;
const int TUBA_MAX = 27;
self.enemy = world;
}
-void Ent_TubaNote(bool isNew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TUBANOTE, bool isNew)
+{
bool upd = false;
int f = ReadByte();
if (f & 1) {
Ent_TubaNote_StopSound();
}
} else {
- self.enemy = spawn();
- self.enemy.classname = "tuba_note";
+ self.enemy = new(tuba_note);
if (Tuba_PitchStep) {
- self.enemy.enemy = spawn();
- self.enemy.enemy.classname = "tuba_note_2";
+ self.enemy.enemy = new(tuba_note_2);
}
isNew = true;
}
if (upd) {
Ent_TubaNote_UpdateSound();
}
+ return true;
}
-void Tuba_Precache()
+PRECACHE(Tuba)
{
Tuba_PitchStep = autocvar_g_balance_tuba_pitchstep;
if (Tuba_PitchStep) {
#ifndef CLIENT_TUBA_H
#define CLIENT_TUBA_H
-void Ent_TubaNote(bool isNew);
-void Tuba_Precache();
entityclass(Tuba);
#include "announcer.qh"
#include "hook.qh"
-#include "hud.qh"
-#include "hud_config.qh"
+#include "hud/all.qh"
#include "mapvoting.qh"
#include "scoreboard.qh"
#include "shownames.qh"
#include "mutators/events.qh"
#include "../common/constants.qh"
+#include "../common/debug.qh"
#include "../common/mapinfo.qh"
#include "../common/gamemodes/all.qh"
-#include "../common/nades/all.qh"
#include "../common/stats.qh"
#include "../common/triggers/target/music.qh"
#include "../common/teams.qh"
void Porto_Init()
{
- porto = spawn();
- porto.classname = "porto";
+ porto = new(porto);
+ make_pure(porto);
porto.draw = Porto_Draw;
porto.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
}
void TrueAim_Init()
{
- trueaim = spawn();
- trueaim.classname = "trueaim";
+ trueaim = new(trueaim);
+ make_pure(trueaim);
trueaim.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
- trueaim_rifle = spawn();
- trueaim_rifle.classname = "trueaim_rifle";
+ trueaim_rifle = new(trueaim_rifle);
+ make_pure(trueaim_rifle);
trueaim_rifle.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_CORPSE;
}
return SHOTTYPE_HITWORLD;
}
-void PostInit(void);
+void PostInit();
void CSQC_Demo_Camera();
float HUD_WouldDrawScoreboard();
float camera_mode;
vortex_charge = getstatf(STAT_VORTEX_CHARGE);
vortex_chargepool = getstatf(STAT_VORTEX_CHARGEPOOL);
- float arc_heat = getstatf(STAT_ARC_HEAT);
+ float arc_heat = STAT(ARC_HEAT);
if(vortex_charge_movingavg == 0) // this should only happen if we have just loaded up the game
vortex_charge_movingavg = vortex_charge;
void HUD_Draw()
{
- if(getstati(STAT_FROZEN))
- drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1'), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
- else if (getstatf(STAT_HEALING_ORB)>time)
- drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, NADE_TYPE_HEAL.m_color, autocvar_hud_colorflash_alpha*getstatf(STAT_HEALING_ORB_ALPHA), DRAWFLAG_ADDITIVE);
+ vector rgb = '0 0 0';
+ float a = 1;
+ if (MUTATOR_CALLHOOK(HUD_Draw_overlay))
+ {
+ rgb = MUTATOR_ARGV(0, vector);
+ a = MUTATOR_ARGV(0, float);
+ }
+ else if(getstati(STAT_FROZEN))
+ {
+ rgb = ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1');
+ }
+ drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, rgb, autocvar_hud_colorflash_alpha * a, DRAWFLAG_ADDITIVE);
if(!intermission)
if(getstatf(STAT_NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
{
++framecount;
+ stats_get();
hud = getstati(STAT_HUD);
if(hud != HUD_NORMAL && lasthud == HUD_NORMAL)
ColorTranslateMode = autocvar_cl_stripcolorcodes;
- // next WANTED weapon (for HUD)
- switchweapon = getstati(STAT_SWITCHWEAPON);
-
// currently switching-to weapon (for crosshair)
switchingweapon = getstati(STAT_SWITCHINGWEAPON);
if(!nightvision_noise)
{
- nightvision_noise = spawn();
- nightvision_noise.classname = "nightvision_noise";
+ nightvision_noise = new(nightvision_noise);
}
if(!nightvision_noise2)
{
- nightvision_noise2 = spawn();
- nightvision_noise2.classname = "nightvision_noise2";
+ nightvision_noise2 = new(nightvision_noise2);
}
// color tint in yellow
}
// edge detection postprocess handling done second (used by hud_powerup)
- float sharpen_intensity = 0, strength_finished = getstatf(STAT_STRENGTH_FINISHED), invincible_finished = getstatf(STAT_INVINCIBLE_FINISHED);
+ float sharpen_intensity = 0, strength_finished = STAT(STRENGTH_FINISHED), invincible_finished = STAT(INVINCIBLE_FINISHED);
if (strength_finished - time > 0) { sharpen_intensity += (strength_finished - time); }
if (invincible_finished - time > 0) { sharpen_intensity += (invincible_finished - time); }
else if(cvar("r_glsl_postprocess") == 2)
cvar_set("r_glsl_postprocess", "0");
- if(menu_visible)
- menu_show();
-
/*if(gametype == MAPINFO_TYPE_CTF)
{
ctf_view();
WITH(entity, self, e, e.draw2d(e));
}
Draw_ShowNames_All();
+ Debug_Draw();
scoreboard_active = HUD_WouldDrawScoreboard();
self.bgmscript = string_null;
}
-void Ent_Wall()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_WALL, bool isnew)
+{
int f;
var .vector fld;
BGMScript_InitEntity(self);
}
+ return = true;
+
InterpolateOrigin_Note();
self.saved = self.(fld);
void Ent_Wall_Remove();
-void Ent_Wall();
#endif
#include "../mutators/events.qh"
#include "../../common/constants.qh"
-#include "../../common/nades/all.qh"
#include "../../common/movetypes/movetypes.qh"
#include "../../lib/csqcmodel/interpolate.qh"
.vector colormod;
void SUB_Stop()
-{SELFPARAM();
+{
+ SELFPARAM();
self.move_velocity = self.move_avelocity = '0 0 0';
self.move_movetype = MOVETYPE_NONE;
}
this.trail_oldtime = time;
// force the effect even for stationary firemine
- if(this.cnt == PROJECTILE_FIREMINE)
- if(from == to)
+ if (this.cnt == PROJECTILE_FIREMINE)
+ if (from == to)
from.z += 1;
if (this.traileffect)
{
particles_alphamin = particles_alphamax = particles_fade = sqrt(this.alpha);
- boxparticles(particleeffectnum(Effects[this.traileffect]), this, from, to, this.velocity, this.velocity, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE | PARTICLES_DRAWASTRAIL);
+ boxparticles(particleeffectnum(Effects_from(this.traileffect)), this, from, to, this.velocity, this.velocity, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE | PARTICLES_DRAWASTRAIL);
}
}
+bool Projectile_isnade(int proj); // TODO: remove
+
void Projectile_Draw(entity this)
{
vector rot;
f = self.move_flags;
- if(self.count & 0x80)
+ if (self.count & 0x80)
{
- //self.move_flags &= ~FL_ONGROUND;
- if(self.move_movetype == MOVETYPE_NONE || self.move_movetype == MOVETYPE_FLY)
+ // self.move_flags &= ~FL_ONGROUND;
+ if (self.move_movetype == MOVETYPE_NONE || self.move_movetype == MOVETYPE_FLY)
Movetype_Physics_NoMatchServer();
- // the trivial movetypes do not have to match the
- // server's ticrate as they are ticrate independent
- // NOTE: this assumption is only true if MOVETYPE_FLY
- // projectiles detonate on impact. If they continue
- // moving, we might still be ticrate dependent.
+ // the trivial movetypes do not have to match the
+ // server's ticrate as they are ticrate independent
+ // NOTE: this assumption is only true if MOVETYPE_FLY
+ // projectiles detonate on impact. If they continue
+ // moving, we might still be ticrate dependent.
else
Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
- if(!(self.move_flags & FL_ONGROUND))
- if(self.velocity != '0 0 0')
+ if (!(self.move_flags & FL_ONGROUND))
+ if (self.velocity != '0 0 0')
self.move_angles = self.angles = vectoangles(self.velocity);
}
else
InterpolateOrigin_Do();
}
- if(self.count & 0x80)
+ if (self.count & 0x80)
{
drawn = (time >= self.spawntime - 0.02);
t = max(time, self.spawntime);
t = time;
}
- if(!(f & FL_ONGROUND))
+ if (!(f & FL_ONGROUND))
{
rot = '0 0 0';
- switch(self.cnt)
+ switch (self.cnt)
{
/*
case PROJECTILE_GRENADE:
- rot = '-2000 0 0'; // forward
- break;
+ rot = '-2000 0 0'; // forward
+ break;
*/
case PROJECTILE_GRENADE_BOUNCING:
rot = '0 -1000 0'; // sideways
break;
case PROJECTILE_HOOKBOMB:
- rot = '1000 0 0'; // forward
+ rot = '1000 0 0'; // forward
break;
default:
break;
}
- if(Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
+ if (Projectile_isnade(self.cnt))
rot = self.avelocity;
self.angles = AnglesTransform_ToAngles(AnglesTransform_Multiply(AnglesTransform_FromAngles(self.angles), rot * (t - self.spawntime)));
a = 1 - (time - self.fade_time) * self.fade_rate;
self.alpha = bound(0, self.alphamod * a, 1);
- if(self.alpha <= 0)
+ if (self.alpha <= 0)
drawn = 0;
self.renderflags = 0;
trailorigin = self.origin;
- switch(self.cnt)
+ switch (self.cnt)
{
case PROJECTILE_GRENADE:
case PROJECTILE_GRENADE_BOUNCING:
break;
}
- if(Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
+ if (Projectile_isnade(self.cnt))
trailorigin += v_up * 4;
- if(drawn)
+ if (drawn)
Projectile_DrawTrail(self, trailorigin);
else
Projectile_ResetTrail(self, trailorigin);
self.drawmask = 0;
- if(!drawn)
+ if (!drawn)
return;
- switch(self.cnt)
+ switch (self.cnt)
{
// Possibly add dlights here.
default:
}
void loopsound(entity e, int ch, string samp, float vol, float attn)
-{SELFPARAM();
- if(self.silent)
+{
+ SELFPARAM();
+ if (self.silent)
return;
_sound(e, ch, samp, vol, attn);
}
void Ent_RemoveProjectile()
-{SELFPARAM();
- if(self.count & 0x80)
+{
+ SELFPARAM();
+ if (self.count & 0x80)
{
tracebox(self.origin, self.mins, self.maxs, self.origin + self.velocity * 0.05, MOVE_NORMAL, self);
Projectile_DrawTrail(self, trace_endpos);
}
}
-void Ent_Projectile()
-{SELFPARAM();
- int f;
-
+NET_HANDLE(ENT_CLIENT_PROJECTILE, bool isnew)
+{
// projectile properties:
// kind (interpolated, or clientside)
//
//
// projectiles don't send angles, because they always follow the velocity
- f = ReadByte();
+ int f = ReadByte();
self.count = (f & 0x80);
self.iflags = (self.iflags & IFLAG_INTERNALMASK) | IFLAG_AUTOANGLES | IFLAG_ANGLES | IFLAG_ORIGIN;
self.solid = SOLID_TRIGGER;
- //self.effects = EF_NOMODELFLAGS;
+ // self.effects = EF_NOMODELFLAGS;
// this should make collisions with bmodels more exact, but it leads to
// projectiles no longer being able to lie on a bmodel
self.move_nomonsters = MOVE_WORLDONLY;
- if(f & 0x40)
+ if (f & 0x40)
self.move_flags |= FL_ONGROUND;
else
self.move_flags &= ~FL_ONGROUND;
- if(!self.move_time)
+ if (!self.move_time)
{
// for some unknown reason, we don't need to care for
// sv_gameplayfix_delayprojectiles here.
self.spawntime = time;
}
else
+ {
self.move_time = max(self.move_time, time);
+ }
- if(!(self.count & 0x80))
+ if (!(self.count & 0x80))
InterpolateOrigin_Undo();
- if(f & 1)
+ if (f & 1)
{
self.origin_x = ReadCoord();
self.origin_y = ReadCoord();
self.origin_z = ReadCoord();
setorigin(self, self.origin);
- if(self.count & 0x80)
+ if (self.count & 0x80)
{
self.velocity_x = ReadCoord();
self.velocity_y = ReadCoord();
self.velocity_z = ReadCoord();
- if(f & 0x10)
+ if (f & 0x10)
self.gravity = ReadCoord();
else
- self.gravity = 0; // none
+ self.gravity = 0; // none
self.move_origin = self.origin;
self.move_velocity = self.velocity;
}
- if(time == self.spawntime || (self.count & 0x80) || (f & 0x08))
+ if (time == self.spawntime || (self.count & 0x80) || (f & 0x08))
{
self.trail_oldorigin = self.origin;
- if(!(self.count & 0x80))
+ if (!(self.count & 0x80))
InterpolateOrigin_Reset();
}
- if(f & 0x20)
+ if (f & 0x20)
{
self.fade_time = time + ReadByte() * ticrate;
self.fade_rate = 1 / (ReadByte() * ticrate);
self.team = ReadByte() - 1;
}
- if(f & 2)
+ if (f & 2)
{
self.cnt = ReadByte();
self.scale = 1;
self.traileffect = 0;
- switch (self.cnt) {
-#define CASE(id) case PROJECTILE_##id: setmodel(self, MDL_PROJECTILE_##id);
+ switch (self.cnt)
+ {
+ #define CASE(id) case PROJECTILE_##id: setmodel(self, MDL_PROJECTILE_##id);
CASE(ELECTRO) self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
CASE(ROCKET) self.traileffect = EFFECT_TR_ROCKET.m_id; self.scale = 2; break;
CASE(CRYLINK) self.traileffect = EFFECT_TR_CRYLINKPLASMA.m_id; break;
CASE(HOOKBOMB) self.traileffect = EFFECT_TR_KNIGHTSPIKE.m_id; break;
CASE(HAGAR) self.traileffect = EFFECT_HAGAR_ROCKET.m_id; self.scale = 0.75; break;
CASE(HAGAR_BOUNCING) self.traileffect = EFFECT_HAGAR_ROCKET.m_id; self.scale = 0.75; break;
- CASE(NAPALM_FOUNTAIN) // fallthrough // sself.modelindex = 0; self.traileffect = _particleeffectnum("torch_small"); break;
CASE(FIREBALL) self.modelindex = 0; self.traileffect = EFFECT_FIREBALL.m_id; break; // particle effect is good enough
CASE(FIREMINE) self.modelindex = 0; self.traileffect = EFFECT_FIREMINE.m_id; break; // particle effect is good enough
CASE(TAG) self.traileffect = EFFECT_TR_ROCKET.m_id; break;
CASE(ROCKETMINSTA_LASER) self.traileffect = EFFECT_ROCKETMINSTA_LASER(self.team).m_id; break;
#undef CASE
default:
- if(MUTATOR_CALLHOOK(Ent_Projectile, self))
+ if (MUTATOR_CALLHOOK(Ent_Projectile, self))
break;
- if (Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
- {
- setmodel(self, MDL_PROJECTILE_NADE);
- entity trail = Nade_TrailEffect(self.cnt, self.team);
- if (trail.eent_eff_name) self.traileffect = trail.m_id;
- break;
- }
error("Received invalid CSQC projectile, can't work with this!");
break;
}
self.move_movetype = MOVETYPE_TOSS;
self.alphamod = 1;
- switch(self.cnt)
+ switch (self.cnt)
{
case PROJECTILE_ELECTRO:
// only new engines support sound moving with object
self.move_movetype = MOVETYPE_BOUNCE;
self.move_touch = func_null;
break;
- case PROJECTILE_NAPALM_FOUNTAIN:
case PROJECTILE_FIREBALL:
loopsound(self, CH_SHOTS_SINGLE, SND(FIREBALL_FLY2), VOL_BASE, ATTEN_NORM);
self.mins = '-16 -16 -16';
self.mins = '-4 -4 -4';
self.maxs = '4 4 4';
break;
- case PROJECTILE_RAPTORBOMB:
+ case PROJECTILE_RAPTORBOMB:
self.mins = '-3 -3 -3';
self.maxs = '3 3 3';
break;
- case PROJECTILE_RAPTORBOMBLET:
+ case PROJECTILE_RAPTORBOMBLET:
break;
- case PROJECTILE_RAPTORCANNON:
+ case PROJECTILE_RAPTORCANNON:
break;
- case PROJECTILE_SPIDERROCKET:
- loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
- break;
- case PROJECTILE_WAKIROCKET:
- loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
+ case PROJECTILE_SPIDERROCKET:
+ loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
break;
- /*
- case PROJECTILE_WAKICANNON:
+ case PROJECTILE_WAKIROCKET:
+ loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
break;
+ /*
+ case PROJECTILE_WAKICANNON:
+ break;
case PROJECTILE_BUMBLE_GUN:
- // only new engines support sound moving with object
- loopsound(self, CH_SHOTS_SINGLE, SND(ELECTRO_FLY), VOL_BASE, ATTEN_NORM);
- self.mins = '0 0 -4';
- self.maxs = '0 0 -4';
- self.move_movetype = MOVETYPE_BOUNCE;
- self.move_touch = func_null;
- self.move_bounce_factor = g_balance_electro_secondary_bouncefactor;
- self.move_bounce_stopspeed = g_balance_electro_secondary_bouncestop;
- break;
+ // only new engines support sound moving with object
+ loopsound(self, CH_SHOTS_SINGLE, SND(ELECTRO_FLY), VOL_BASE, ATTEN_NORM);
+ self.mins = '0 0 -4';
+ self.maxs = '0 0 -4';
+ self.move_movetype = MOVETYPE_BOUNCE;
+ self.move_touch = func_null;
+ self.move_bounce_factor = g_balance_electro_secondary_bouncefactor;
+ self.move_bounce_stopspeed = g_balance_electro_secondary_bouncestop;
+ break;
*/
default:
break;
}
- if(Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
- {
- entity nade_type = Nade_FromProjectile(self.cnt);
- self.mins = '-16 -16 -16';
- self.maxs = '16 16 16';
- self.colormod = nade_type.m_color;
- self.move_movetype = MOVETYPE_BOUNCE;
- self.move_touch = func_null;
- self.scale = 1.5;
- self.avelocity = randomvec() * 720;
-
- if(nade_type == NADE_TYPE_TRANSLOCATE || nade_type == NADE_TYPE_SPAWN)
- self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
- else
- self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
- }
-
MUTATOR_CALLHOOK(EditProjectile, self);
setsize(self, self.mins, self.maxs);
}
- if(self.gravity)
+ return = true;
+
+ if (self.gravity)
{
- if(self.move_movetype == MOVETYPE_FLY)
+ if (self.move_movetype == MOVETYPE_FLY)
self.move_movetype = MOVETYPE_TOSS;
- if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
+ if (self.move_movetype == MOVETYPE_BOUNCEMISSILE)
self.move_movetype = MOVETYPE_BOUNCE;
}
else
{
- if(self.move_movetype == MOVETYPE_TOSS)
+ if (self.move_movetype == MOVETYPE_TOSS)
self.move_movetype = MOVETYPE_FLY;
- if(self.move_movetype == MOVETYPE_BOUNCE)
+ if (self.move_movetype == MOVETYPE_BOUNCE)
self.move_movetype = MOVETYPE_BOUNCEMISSILE;
}
- if(!(self.count & 0x80))
+ if (!(self.count & 0x80))
InterpolateOrigin_Note();
self.classname = "csqcprojectile";
self.entremove = Ent_RemoveProjectile;
}
-void Projectile_Precache()
+PRECACHE(Projectiles)
{
MUTATOR_CALLHOOK(PrecacheProjectiles);
}
#define CLIENT_WEAPONS_PROJECTILE_H
entityclass(Projectile);
-class(Projectile) .int traileffect;
+class(Projectile).int traileffect;
-class(Projectile) .vector iorigin1, iorigin2;
-class(Projectile) .float spawntime;
-class(Projectile) .vector trail_oldorigin;
-class(Projectile) .float trail_oldtime;
-class(Projectile) .float fade_time, fade_rate;
+class(Projectile).vector iorigin1, iorigin2;
+class(Projectile).float spawntime;
+class(Projectile).vector trail_oldorigin;
+class(Projectile).float trail_oldtime;
+class(Projectile).float fade_time, fade_rate;
-class(Projectile) .float alphamod;
-class(Projectile) .int count; // set if clientside projectile
-class(Projectile) .int cnt; // sound index
-class(Projectile) .float gravity;
-class(Projectile) .int snd_looping;
-class(Projectile) .bool silent;
+class(Projectile).float alphamod;
+class(Projectile).int count; // set if clientside projectile
+class(Projectile).int cnt; // sound index
+class(Projectile).float gravity;
+class(Projectile).int snd_looping;
+class(Projectile).bool silent;
void SUB_Stop();
void Ent_RemoveProjectile();
-void Ent_Projectile();
-
-void Projectile_Precache();
-
#endif
+++ /dev/null
-REGISTER_BUFF(AMMO) {
- this.m_prettyName = _("Ammo");
- this.m_name = "ammo";
- this.m_skin = 3;
- this.m_color = '0.76 1 0.1';
-}
-BUFF_SPAWNFUNCS(ammo, BUFF_AMMO)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(ammoregen, BUFF_AMMO)
-
-REGISTER_BUFF(RESISTANCE) {
- this.m_prettyName = _("Resistance");
- this.m_name = "resistance";
- this.m_skin = 0;
- this.m_color = '0.36 1 0.07';
-}
-BUFF_SPAWNFUNCS(resistance, BUFF_RESISTANCE)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(resistance, BUFF_RESISTANCE)
-
-REGISTER_BUFF(SPEED) {
- this.m_prettyName = _("Speed");
- this.m_name = "speed";
- this.m_skin = 9;
- this.m_color = '0.1 1 0.84';
-}
-BUFF_SPAWNFUNCS(speed, BUFF_SPEED)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(haste, BUFF_SPEED)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(scout, BUFF_SPEED)
-
-REGISTER_BUFF(MEDIC) {
- this.m_prettyName = _("Medic");
- this.m_name = "medic";
- this.m_skin = 1;
- this.m_color = '1 0.12 0';
-}
-BUFF_SPAWNFUNCS(medic, BUFF_MEDIC)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(doubler, BUFF_MEDIC)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(medic, BUFF_MEDIC)
-
-REGISTER_BUFF(BASH) {
- this.m_prettyName = _("Bash");
- this.m_name = "bash";
- this.m_skin = 5;
- this.m_color = '1 0.39 0';
-}
-BUFF_SPAWNFUNCS(bash, BUFF_BASH)
-
-REGISTER_BUFF(VAMPIRE) {
- this.m_prettyName = _("Vampire");
- this.m_name = "vampire";
- this.m_skin = 2;
- this.m_color = '1 0 0.24';
-}
-BUFF_SPAWNFUNCS(vampire, BUFF_VAMPIRE)
-
-REGISTER_BUFF(DISABILITY) {
- this.m_prettyName = _("Disability");
- this.m_name = "disability";
- this.m_skin = 7;
- this.m_color = '0.94 0.3 1';
-}
-BUFF_SPAWNFUNCS(disability, BUFF_DISABILITY)
-
-REGISTER_BUFF(VENGEANCE) {
- this.m_prettyName = _("Vengeance");
- this.m_name = "vengeance";
- this.m_skin = 15;
- this.m_color = '1 0.23 0.61';
-}
-BUFF_SPAWNFUNCS(vengeance, BUFF_VENGEANCE)
-
-REGISTER_BUFF(JUMP) {
- this.m_prettyName = _("Jump");
- this.m_name = "jump";
- this.m_skin = 10;
- this.m_color = '0.24 0.78 1';
-}
-BUFF_SPAWNFUNCS(jump, BUFF_JUMP)
-
-REGISTER_BUFF(FLIGHT) {
- this.m_prettyName = _("Flight");
- this.m_name = "flight";
- this.m_skin = 11;
- this.m_color = '0.33 0.56 1';
-}
-BUFF_SPAWNFUNCS(flight, BUFF_FLIGHT)
-
-REGISTER_BUFF(INVISIBLE) {
- this.m_prettyName = _("Invisible");
- this.m_name = "invisible";
- this.m_skin = 12;
- this.m_color = '0.5 0.5 1';
-}
-BUFF_SPAWNFUNCS(invisible, BUFF_INVISIBLE)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(invis, BUFF_INVISIBLE)
-
-REGISTER_BUFF(INFERNO) {
- this.m_prettyName = _("Inferno");
- this.m_name = "inferno";
- this.m_skin = 16;
- this.m_color = '1 0.62 0';
-}
-BUFF_SPAWNFUNCS(inferno, BUFF_INFERNO)
-
-REGISTER_BUFF(SWAPPER) {
- this.m_prettyName = _("Swapper");
- this.m_name = "swapper";
- this.m_skin = 17;
- this.m_color = '0.63 0.36 1';
-}
-BUFF_SPAWNFUNCS(swapper, BUFF_SWAPPER)
-
-REGISTER_BUFF(MAGNET) {
- this.m_prettyName = _("Magnet");
- this.m_name = "magnet";
- this.m_skin = 18;
- this.m_color = '1 0.95 0.18';
-}
-BUFF_SPAWNFUNCS(magnet, BUFF_MAGNET)
+++ /dev/null
-#if defined(CSQC)
- #include "../../client/defs.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-#include "all.qh"
-
+++ /dev/null
-#ifndef BUFFS_ALL_H
-#define BUFFS_ALL_H
-// Welcome to the stuff behind the scenes
-// Below, you will find the list of buffs
-// Add new buffs here!
-// Note: Buffs also need spawnfuncs, which are set below
-
-#include "../teams.qh"
-#include "../util.qh"
-
-REGISTRY(Buffs, BIT(4))
-REGISTER_REGISTRY(RegisterBuffs)
-
-#define REGISTER_BUFF(id) \
- REGISTER(RegisterBuffs, BUFF, Buffs, id, m_id, NEW(Buff)); \
- REGISTER_INIT_POST(BUFF, id) { \
- this.netname = this.m_name; \
- this.m_itemid = BIT(this.m_id - 1); \
- this.m_sprite = strzone(strcat("buff-", this.m_name)); \
- } \
- REGISTER_INIT(BUFF, id)
-
-#include "../items/item/pickup.qh"
-CLASS(Buff, Pickup)
- /** bit index */
- ATTRIB(Buff, m_itemid, int, 0)
- ATTRIB(Buff, m_name, string, "buff")
- ATTRIB(Buff, m_color, vector, '1 1 1')
- ATTRIB(Buff, m_prettyName, string, "Buff")
- ATTRIB(Buff, m_skin, int, 0)
- ATTRIB(Buff, m_sprite, string, "")
- METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) {
- returns(this.m_prettyName, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.m_name));
- }
-#ifdef SVQC
- METHOD(Buff, m_time, float(entity));
- float Buff_m_time(entity this) { return cvar(strcat("g_buffs_", this.netname, "_time")); }
-#endif
-ENDCLASS(Buff)
-
-#ifdef SVQC
- .int buffs;
- void buff_Init(entity ent);
- void buff_Init_Compat(entity ent, entity replacement);
- #define BUFF_SPAWNFUNC(e, b, t) spawnfunc(item_buff_##e) { \
- self.buffs = b.m_itemid; \
- self.team = t; \
- buff_Init(self); \
- }
- #define BUFF_SPAWNFUNCS(e, b) \
- BUFF_SPAWNFUNC(e, b, 0) \
- BUFF_SPAWNFUNC(e##_team1, b, NUM_TEAM_1) \
- BUFF_SPAWNFUNC(e##_team2, b, NUM_TEAM_2) \
- BUFF_SPAWNFUNC(e##_team3, b, NUM_TEAM_3) \
- BUFF_SPAWNFUNC(e##_team4, b, NUM_TEAM_4)
- #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r) spawnfunc(item_##o) { buff_Init_Compat(self, r); }
-#else
- #define BUFF_SPAWNFUNC(e, b, t)
- #define BUFF_SPAWNFUNCS(e, b)
- #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r)
-#endif
-
-REGISTER_BUFF(Null);
-BUFF_SPAWNFUNCS(random, BUFF_Null)
-
-#include "all.inc"
-
-#endif
#define COMMON_COMMANDS_ALL_H
#include "command.qh"
-REGISTRY(GENERIC_COMMANDS, 50)
-REGISTER_REGISTRY(RegisterGENERIC_COMMANDS)
-REGISTRY_SORT(GENERIC_COMMANDS, m_name, 0)
+REGISTRY(GENERIC_COMMANDS, BITS(7))
+#define GENERIC_COMMANDS_from(i) _GENERIC_COMMANDS_from(i, NULL)
+REGISTER_REGISTRY(GENERIC_COMMANDS)
+REGISTRY_SORT(GENERIC_COMMANDS, 0)
#define GENERIC_COMMAND(id, description) \
CLASS(genericcommand_##id, Command) \
ATTRIB(genericcommand_##id, m_name, string, #id); \
ATTRIB(genericcommand_##id, m_description, string, description); \
ENDCLASS(genericcommand_##id) \
- REGISTER(RegisterGENERIC_COMMANDS, CMD_G, GENERIC_COMMANDS, id, m_id, NEW(genericcommand_##id)); \
+ REGISTER(GENERIC_COMMANDS, CMD_G, id, m_id, NEW(genericcommand_##id)); \
METHOD(genericcommand_##id, m_invokecmd, void(int request, int arguments, string command))
STATIC_INIT(GENERIC_COMMANDS_aliases) {
// =========================================================
// used by generic commands for better help/usage information
-string GetProgramCommandPrefix(void)
+string GetProgramCommandPrefix()
{
#ifdef SVQC
return "sv_cmd";
float GenericCommand(string command);
// Returns command prefix specific for whatever program it is compiled in
-string GetProgramCommandPrefix(void);
+string GetProgramCommandPrefix();
// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
#define CMD_Write(s) fputs(fh, s)
// Revision 22: hook shot origin
#define CSQC_REVISION 22
-const int AS_STRING = 1;
-const int AS_INT = 2;
-const int AS_FLOAT_TRUNCATED = 2;
-const int AS_FLOAT = 8;
-
-const int TE_CSQC_MUTATOR = 99;
-#define MUTATOR_HASH(s) crc16(true, s)
-#define WriteMutator(to, s) do { \
- WriteByte(to, TE_CSQC_MUTATOR); \
- WriteLong(to, MUTATOR_HASH(#s)); \
-} while (0)
-#define ReadMutator() ReadLong()
-#define ReadMutatorEquals(read, s) (read == MUTATOR_HASH(#s))
-const int TE_CSQC_PICTURE = 100;
-const int TE_CSQC_RACE = 101;
-const int TE_CSQC_VORTEXBEAMPARTICLE = 103;
-const int TE_CSQC_ARC = 104;
-const int TE_CSQC_TEAMNAGGER = 105;
-const int TE_CSQC_PINGPLREPORT = 106;
-const int TE_CSQC_TARGET_MUSIC = 107;
-const int TE_CSQC_WEAPONCOMPLAIN = 108;
-const int TE_CSQC_VORTEX_SCOPE = 109;
-const int TE_CSQC_MINELAYER_MAXMINES = 110;
-const int TE_CSQC_HAGAR_MAXROCKETS = 111;
-const int TE_CSQC_VEHICLESETUP = 112;
-const int TE_CSQC_SVNOTICE = 113;
-const int TE_CSQC_SHOCKWAVEPARTICLE = 114;
+REGISTER_NET_TEMP(TE_CSQC_PICTURE)
+REGISTER_NET_TEMP(TE_CSQC_RACE)
+REGISTER_NET_TEMP(TE_CSQC_TEAMNAGGER)
+REGISTER_NET_TEMP(TE_CSQC_PINGPLREPORT)
+REGISTER_NET_TEMP(TE_CSQC_WEAPONCOMPLAIN)
+REGISTER_NET_TEMP(TE_CSQC_VEHICLESETUP)
const int RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
const int RACE_NET_CHECKPOINT_CLEAR = 1;
const int RACE_NET_SERVER_STATUS = 12;
const int RANKINGS_CNT = 15;
-const int ENT_CLIENT = 0;
-const int ENT_CLIENT_DEAD = 1;
-const int ENT_CLIENT_ENTCS = 2;
-const int ENT_CLIENT_SCORES_INFO = 3;
-const int ENT_CLIENT_SCORES = 4;
-const int ENT_CLIENT_TEAMSCORES = 5;
-const int ENT_CLIENT_POINTPARTICLES = 6;
-const int ENT_CLIENT_RAINSNOW = 7;
-const int ENT_CLIENT_LASER = 8;
-const int ENT_CLIENT_NAGGER = 9; // flags [votecalledvote]
-const int ENT_CLIENT_RADARLINK = 11; // flags [startorigin] [endorigin] [startcolor+16*endcolor]
-const int ENT_CLIENT_PROJECTILE = 12;
-const int ENT_CLIENT_GIBSPLASH = 13;
-const int ENT_CLIENT_DAMAGEINFO = 14;
-const int ENT_CLIENT_INIT = 16;
-const int ENT_CLIENT_MAPVOTE = 17;
-const int ENT_CLIENT_CLIENTDATA = 18;
-const int ENT_CLIENT_RANDOMSEED = 19;
-const int ENT_CLIENT_WALL = 20;
-const int ENT_CLIENT_SPIDERBOT = 21;
-const int ENT_CLIENT_MODELEFFECT = 22;
-const int ENT_CLIENT_TUBANOTE = 23;
-const int ENT_CLIENT_WARPZONE = 24;
-const int ENT_CLIENT_WARPZONE_CAMERA = 25;
-const int ENT_CLIENT_TRIGGER_MUSIC = 26;
-const int ENT_CLIENT_HOOK = 27;
-const int ENT_CLIENT_INVENTORY = 28;
-const int ENT_CLIENT_ARC_BEAM = 29; // WEAPONTODO: fix numbers
-const int ENT_CLIENT_ACCURACY = 30;
-const int ENT_CLIENT_SHOWNAMES = 31;
-const int ENT_CLIENT_WARPZONE_TELEPORTED = 32;
-const int ENT_CLIENT_MODEL = 33;
-const int ENT_CLIENT_ITEM = 34;
-const int ENT_CLIENT_BUMBLE_RAYGUN = 35;
-const int ENT_CLIENT_SPAWNPOINT = 36;
-const int ENT_CLIENT_SPAWNEVENT = 37;
-const int ENT_CLIENT_NOTIFICATION = 38;
-const int ENT_CLIENT_ELIMINATEDPLAYERS = 39;
-const int ENT_CLIENT_TURRET = 40;
-const int ENT_CLIENT_AUXILIARYXHAIR = 50;
-const int ENT_CLIENT_VEHICLE = 60;
-const int ENT_CLIENT_LADDER = 61;
-const int ENT_CLIENT_TRIGGER_PUSH = 62;
-const int ENT_CLIENT_TARGET_PUSH = 63;
-const int ENT_CLIENT_CONVEYOR = 64;
-const int ENT_CLIENT_DOOR = 65;
-const int ENT_CLIENT_TRAIN = 66;
-const int ENT_CLIENT_PLAT = 67;
-const int ENT_CLIENT_TRIGGER_IMPULSE = 68;
-const int ENT_CLIENT_SWAMP = 69;
-const int ENT_CLIENT_CORNER = 70;
-const int ENT_CLIENT_KEYLOCK = 71;
-const int ENT_CLIENT_GENERATOR = 72;
-const int ENT_CLIENT_CONTROLPOINT_ICON = 73;
-const int ENT_CLIENT_EFFECT = 74;
-const int ENT_CLIENT_MINIGAME = 75;
-const int ENT_CLIENT_VIEWLOC = 78;
-const int ENT_CLIENT_VIEWLOC_TRIGGER = 79;
-
-const int ENT_CLIENT_MUTATOR = TE_CSQC_MUTATOR; // 99
+REGISTER_NET_LINKED(_ENT_CLIENT_INIT)
+#ifdef CSQC
+NET_HANDLE(_ENT_CLIENT_INIT, bool isnew) { return true; }
+#endif
+/** Sent as a temp entity from a persistent linked entity */
+REGISTER_NET_TEMP(ENT_CLIENT_INIT)
+
+REGISTER_NET_LINKED(ENT_CLIENT_ENTCS)
+REGISTER_NET_LINKED(ENT_CLIENT_SCORES_INFO)
+REGISTER_NET_LINKED(ENT_CLIENT_SCORES)
+REGISTER_NET_LINKED(ENT_CLIENT_TEAMSCORES)
+REGISTER_NET_LINKED(ENT_CLIENT_NAGGER) // flags [votecalledvote]
+REGISTER_NET_LINKED(ENT_CLIENT_RADARLINK) // flags [startorigin] [endorigin] [startcolor+16*endcolor]
+REGISTER_NET_LINKED(ENT_CLIENT_PROJECTILE)
+REGISTER_NET_LINKED(ENT_CLIENT_MAPVOTE)
+REGISTER_NET_LINKED(ENT_CLIENT_CLIENTDATA)
+REGISTER_NET_LINKED(ENT_CLIENT_RANDOMSEED)
+REGISTER_NET_LINKED(ENT_CLIENT_ACCURACY)
+REGISTER_NET_LINKED(ENT_CLIENT_ELIMINATEDPLAYERS)
+
+REGISTER_NET_LINKED(ENT_CLIENT_MODEL)
+
+REGISTER_NET_LINKED(ENT_CLIENT_WARPZONE)
+REGISTER_NET_LINKED(ENT_CLIENT_WARPZONE_CAMERA)
+REGISTER_NET_LINKED(ENT_CLIENT_WARPZONE_TELEPORTED)
+
+REGISTER_NET_LINKED(ENT_CLIENT_ARC_BEAM)
+REGISTER_NET_LINKED(ENT_CLIENT_HOOK)
+REGISTER_NET_LINKED(ENT_CLIENT_TUBANOTE)
+
+REGISTER_NET_LINKED(ENT_CLIENT_SPAWNPOINT)
+REGISTER_NET_LINKED(ENT_CLIENT_SPAWNEVENT)
+REGISTER_NET_LINKED(ENT_CLIENT_WALL)
const int SPRITERULE_DEFAULT = 0;
const int SPRITERULE_TEAMPLAY = 1;
///////////////////////////
// csqc communication stuff
-const int CTF_STATE_ATTACK = 1;
-const int CTF_STATE_DEFEND = 2;
-const int CTF_STATE_COMMANDER = 3;
-
const int HUD_NORMAL = 0;
const int HUD_BUMBLEBEE_GUN = 25;
/**
* Score indices
*/
-#define MAX_SCORE 10
+#define MAX_SCORE 12
#define MAX_TEAMSCORE 2
const int ST_SCORE = 0;
const int SP_DEATHS = 1;
const int SP_SUICIDES = 2;
const int SP_SCORE = 3;
+const int SP_DMG = 10;
+const int SP_DMGTAKEN = 11;
// game mode specific indices are not in common/, but in server/scores_rules.qc!
-const int CH_INFO = 0;
-const int CH_TRIGGER = -3;
-const int CH_WEAPON_A = -1;
-const int CH_WEAPON_SINGLE = 1;
-const int CH_VOICE = -2;
-const int CH_BGM_SINGLE = 8;
-const int CH_AMBIENT = -9;
-const int CH_TRIGGER_SINGLE = 3;
-const int CH_SHOTS = -4;
-const int CH_SHOTS_SINGLE = 4;
-const int CH_WEAPON_B = -1;
-const int CH_PAIN = -6;
-const int CH_PAIN_SINGLE = 6;
-const int CH_PLAYER = -7;
-const int CH_PLAYER_SINGLE = 7;
-const int CH_TUBA_SINGLE = 5;
-
-const float ATTEN_NONE = 0;
-const float ATTEN_MIN = 0.015625;
-const float ATTEN_NORM = 0.5;
-const float ATTEN_LARGE = 1;
-const float ATTEN_IDLE = 2;
-const float ATTEN_STATIC = 3;
-const float ATTEN_MAX = 3.984375;
-
-const float VOL_BASE = 0.7;
-const float VOL_BASEVOICE = 1.0;
-
// WEAPONTODO: move this into separate/new projectile handling code // this sets sounds and other properties of the projectiles in csqc
const int PROJECTILE_ELECTRO = 1;
const int PROJECTILE_ROCKET = 2;
CSQCPlayer_SetViewLocation();
// force updates of player entities that often even if unchanged
+#ifndef CSQCPLAYER_FORCE_UPDATES
#define CSQCPLAYER_FORCE_UPDATES 0.25
+#endif
// mod must define:
//vector PL_MIN = ...;
string Deathtype_Name(int deathtype)
{
if (DEATH_ISSPECIAL(deathtype)) {
- entity deathent = Deathtypes[deathtype - DT_FIRST];
+ entity deathent = Deathtypes_from(deathtype - DT_FIRST);
if (!deathent) { backtrace("Deathtype_Name: Could not find deathtype entity!\n"); return ""; }
return deathent.nent_name;
}
#include "../notifications.qh"
-REGISTRY(Deathtypes, BIT(6))
-REGISTER_REGISTRY(RegisterDeathtypes)
+REGISTRY(Deathtypes, BITS(8))
+#define Deathtypes_from(i) _Deathtypes_from(i, NULL)
+REGISTER_REGISTRY(Deathtypes)
+REGISTRY_CHECK(Deathtypes)
.entity death_msgself;
.entity death_msgmurder;
.string death_msgextra;
#define REGISTER_DEATHTYPE(id, msg_death, msg_death_by, extra) \
- REGISTER(RegisterDeathtypes, DEATH, Deathtypes, id, m_id, new(deathtype)) { \
+ REGISTER(Deathtypes, DEATH, id, m_id, new(deathtype)) { \
+ make_pure(this); \
this.m_id += DT_FIRST; \
this.nent_name = #id; \
this.death_msgextra = extra; \
const int DT_FIRST = BIT(13);
#define DEATH_ISSPECIAL(t) (t >= DT_FIRST)
-#define DEATH_IS(t, dt) (DEATH_ISSPECIAL(t) && (Deathtypes[t - DT_FIRST]) == dt)
-#define DEATH_ENT(t) (DEATH_ISSPECIAL(t) ? (Deathtypes[t - DT_FIRST]) : NULL)
-#define DEATH_ISVEHICLE(t) (DEATH_ISSPECIAL(t) && (Deathtypes[t - DT_FIRST]).death_msgextra == "vehicle")
-#define DEATH_ISTURRET(t) (DEATH_ISSPECIAL(t) && (Deathtypes[t - DT_FIRST]).death_msgextra == "turret")
-#define DEATH_ISMONSTER(t) (DEATH_ISSPECIAL(t) && (Deathtypes[t - DT_FIRST]).death_msgextra == "monster")
+#define DEATH_IS(t, dt) (DEATH_ISSPECIAL(t) && (Deathtypes_from(t - DT_FIRST)) == dt)
+#define DEATH_ENT(t) (DEATH_ISSPECIAL(t) ? (Deathtypes_from(t - DT_FIRST)) : NULL)
+#define DEATH_ISVEHICLE(t) (DEATH_ISSPECIAL(t) && (Deathtypes_from(t - DT_FIRST)).death_msgextra == "vehicle")
+#define DEATH_ISTURRET(t) (DEATH_ISSPECIAL(t) && (Deathtypes_from(t - DT_FIRST)).death_msgextra == "turret")
+#define DEATH_ISMONSTER(t) (DEATH_ISSPECIAL(t) && (Deathtypes_from(t - DT_FIRST)).death_msgextra == "monster")
#define DEATH_WEAPONOF(t) (DEATH_ISSPECIAL(t) ? WEP_Null : get_weaponinfo((t) & DEATH_WEAPONMASK))
#define DEATH_ISWEAPON(t, w) (DEATH_WEAPONOF(t) == (w))
--- /dev/null
+#ifndef DEBUG_H
+#define DEBUG_H
+
+.bool debug;
+.int sv_entnum;
+REGISTER_NET_TEMP(net_debug)
+#ifdef CSQC
+ NET_HANDLE(net_debug, bool isNew)
+ {
+ Net_Accept(net_debug);
+ this.sv_entnum = ReadShort();
+ if (ReadByte()) make_pure(this);
+ this.origin_x = ReadCoord();
+ this.origin_y = ReadCoord();
+ this.origin_z = ReadCoord();
+ setorigin(this, this.origin);
+ this.debug = true; // identify server entities by this
+ this.classname = strzone(ReadString());
+ this.sourceLocFile = strzone(ReadString());
+ this.sourceLocLine = ReadInt24_t();
+ return true;
+ }
+#endif
+
+#ifdef SVQC
+ bool debug_send(entity this, entity to, int sf)
+ {
+ int channel = MSG_ONE;
+ msg_entity = to;
+ WriteHeader(channel, net_debug);
+ WriteShort(channel, num_for_edict(this));
+ WriteByte(channel, is_pure(this));
+ WriteCoord(channel, this.origin.x);
+ WriteCoord(channel, this.origin.y);
+ WriteCoord(channel, this.origin.z);
+ WriteString(channel, this.classname);
+ WriteString(channel, this.sourceLocFile);
+ WriteInt24_t(channel, this.sourceLocLine);
+ return true;
+ }
+#endif
+
+bool autocvar_debugdraw;
+
+#ifdef CSQC
+ .int debugdraw_last;
+ vector project_3d_to_2d(vector vec);
+ void Debug_Draw()
+ {
+ if (!autocvar_debugdraw) return;
+ static int debugdraw_frame;
+ ++debugdraw_frame;
+ const int size = 8;
+ for (entity e1 = NULL; (e1 = nextent(e1)); )
+ {
+ if (e1.debugdraw_last == debugdraw_frame) continue;
+ int ofs = 0;
+ for (entity e = findradius(e1.origin, 100); e; e = e.chain)
+ {
+ if (e.debugdraw_last == debugdraw_frame) continue;
+ e.debugdraw_last = debugdraw_frame;
+ vector rgb = (e.debug) ? '0 0 1' : '1 0 0';
+ if (is_pure(e))
+ {
+ if (autocvar_debugdraw < 2) continue;
+ rgb.y = 1;
+ }
+ vector pos = project_3d_to_2d(e.origin);
+ if (pos.z < 0) continue;
+ pos.z = 0;
+ pos.y += ofs * size;
+ drawcolorcodedstring2(pos,
+ sprintf("%d: '%s'@%s:%d", (e.debug ? e.sv_entnum : num_for_edict(e)),
+ e.classname, e.sourceLocFile, e.sourceLocLine),
+ size * '1 1 0', rgb, 0.5, DRAWFLAG_NORMAL);
+ ++ofs;
+ }
+ }
+ }
+#endif
+
+#ifdef SVQC
+ GENERIC_COMMAND(debugdraw_sv, "Dump all server entities")
+ {
+ switch (request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ if (!autocvar_debugdraw) return;
+ int n = 1000;
+ int rem = n;
+ for (entity e = NULL; (e = findfloat(e, debug, 0)) && rem > 0; )
+ {
+ if (autocvar_debugdraw < 2 && is_pure(e)) continue;
+ debug_send(e, nextent(NULL), 0);
+ e.debug = true;
+ --rem;
+ }
+ LOG_INFOF("%d server entities sent\n", n - rem);
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " debugdraw_sv"));
+ return;
+ }
+ }
+ }
+#endif
+
+#endif
EFFECT(0, ARC_BEAM_HEAL, "arc_beam_heal")
EFFECT(0, ARC_BEAM_HEAL_IMPACT, "arc_beam_healimpact")
EFFECT(0, ARC_BEAM_HEAL_IMPACT2, "healray_impact")
+EFFECT(0, ARC_OVERHEAT, "arc_overheat")
+EFFECT(0, ARC_OVERHEAT_FIRE, "arc_overheat_fire")
+EFFECT(0, ARC_SMOKE, "arc_smoke")
EFFECT(0, ARC_LIGHTNING, "arc_lightning")
EFFECT(0, ARC_LIGHTNING2, "electro_lightning")
EFFECT(0, SEEKER_MUZZLEFLASH, "seeker_muzzleflash")
-EFFECT(0, FLAK_BOUNCE, "flak_bounce")
-
EFFECT(1, FIREBALL, "fireball")
EFFECT(0, FIREBALL_BFGDAMAGE, "fireball_bfgdamage")
EFFECT(0, FIREBALL_EXPLODE, "fireball_explode")
EFFECT(0, SPAWNPOINT_NEUTRAL, "spawn_point_neutral")
EFFECT(0, SPAWN_NEUTRAL, "spawn_event_neutral")
-EFFECT(0, NADE_EXPLODE_RED, "nade_red_explode")
-EFFECT(0, NADE_EXPLODE_BLUE, "nade_blue_explode")
-EFFECT(0, NADE_EXPLODE_YELLOW, "nade_yellow_explode")
-EFFECT(0, NADE_EXPLODE_PINK, "nade_pink_explode")
-EFFECT(0, NADE_EXPLODE_NEUTRAL, "nade_neutral_explode")
-entity EFFECT_NADE_EXPLODE(int teamid)
-{
- switch (teamid) {
- case NUM_TEAM_1: return EFFECT_NADE_EXPLODE_RED;
- case NUM_TEAM_2: return EFFECT_NADE_EXPLODE_BLUE;
- case NUM_TEAM_3: return EFFECT_NADE_EXPLODE_YELLOW;
- case NUM_TEAM_4: return EFFECT_NADE_EXPLODE_PINK;
- default: return EFFECT_NADE_EXPLODE_NEUTRAL;
- }
-}
-
-EFFECT(1, NADE_TRAIL_RED, "nade_red")
-EFFECT(1, NADE_TRAIL_BLUE, "nade_blue")
-EFFECT(1, NADE_TRAIL_YELLOW, "nade_yellow")
-EFFECT(1, NADE_TRAIL_PINK, "nade_pink")
-EFFECT(1, NADE_TRAIL_NEUTRAL, "nade_neutral")
-entity EFFECT_NADE_TRAIL(int teamid)
-{
- switch (teamid) {
- case NUM_TEAM_1: return EFFECT_NADE_TRAIL_RED;
- case NUM_TEAM_2: return EFFECT_NADE_TRAIL_BLUE;
- case NUM_TEAM_3: return EFFECT_NADE_TRAIL_YELLOW;
- case NUM_TEAM_4: return EFFECT_NADE_TRAIL_PINK;
- default: return EFFECT_NADE_TRAIL_NEUTRAL;
- }
-}
-
-EFFECT(1, NADE_TRAIL_BURN_RED, "nade_red_burn")
-EFFECT(1, NADE_TRAIL_BURN_BLUE, "nade_blue_burn")
-EFFECT(1, NADE_TRAIL_BURN_YELLOW, "nade_yellow_burn")
-EFFECT(1, NADE_TRAIL_BURN_PINK, "nade_pink_burn")
-EFFECT(1, NADE_TRAIL_BURN_NEUTRAL, "nade_neutral_burn")
-entity EFFECT_NADE_TRAIL_BURN(int teamid)
-{
- switch (teamid) {
- case NUM_TEAM_1: return EFFECT_NADE_TRAIL_BURN_RED;
- case NUM_TEAM_2: return EFFECT_NADE_TRAIL_BURN_BLUE;
- case NUM_TEAM_3: return EFFECT_NADE_TRAIL_BURN_YELLOW;
- case NUM_TEAM_4: return EFFECT_NADE_TRAIL_BURN_PINK;
- default: return EFFECT_NADE_TRAIL_BURN_NEUTRAL;
- }
-}
-
EFFECT(0, ICEORGLASS, "iceorglass")
EFFECT(0, ICEFIELD, "icefield")
EFFECT(0, FIREFIELD, "firefield")
EFFECT(1, PASS_YELLOW, "yellow_pass")
EFFECT(1, PASS_PINK, "pink_pass")
EFFECT(1, PASS_NEUTRAL, "neutral_pass")
+entity EFFECT_PASS(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_PASS_RED;
+ case NUM_TEAM_2: return EFFECT_PASS_BLUE;
+ case NUM_TEAM_3: return EFFECT_PASS_YELLOW;
+ case NUM_TEAM_4: return EFFECT_PASS_PINK;
+ default: return EFFECT_PASS_NEUTRAL;
+ }
+}
EFFECT(0, CAP_RED, "red_cap")
EFFECT(0, CAP_BLUE, "blue_cap")
#include "all.qh"
+REGISTER_NET_TEMP(net_effect)
#ifdef CSQC
-void Read_Effect(bool is_new)
+NET_HANDLE(net_effect, bool isNew)
{
int net_name = (Effects_COUNT >= 255) ? ReadShort() : ReadByte();
- entity eff = Effects[net_name];
+ entity eff = Effects_from(net_name);
- vector v, vel = '0 0 0';
+ vector vel = '0 0 0';
int eff_cnt = 1;
bool eff_trail = eff.eent_eff_trail;
+ vector v;
v_x = ReadCoord();
v_y = ReadCoord();
v_z = ReadCoord();
if(!eff_trail)
eff_cnt = ReadByte();
- if(is_new)
- {
- if(eff_trail)
- WarpZone_TrailParticles(world, particleeffectnum(eff), v, vel);
- else
- pointparticles(particleeffectnum(eff), v, vel, eff_cnt);
- }
+ if(eff_trail)
+ WarpZone_TrailParticles(world, particleeffectnum(eff), v, vel);
+ else
+ pointparticles(eff, v, vel, eff_cnt);
+ return true;
}
#endif
#ifdef SVQC
bool Net_Write_Effect(entity this, entity client, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_EFFECT);
+ int channel = MSG_ONE;
+ msg_entity = client;
+ WriteHeader(channel, net_effect);
(Effects_COUNT >= 255)
- ? WriteShort(MSG_ENTITY, self.m_id)
- : WriteByte(MSG_ENTITY, self.m_id);
- WriteCoord(MSG_ENTITY, self.eent_net_location_x);
- WriteCoord(MSG_ENTITY, self.eent_net_location_y);
- WriteCoord(MSG_ENTITY, self.eent_net_location_z);
+ ? WriteShort(channel, this.m_id)
+ : WriteByte(channel, this.m_id);
+ WriteCoord(channel, this.eent_net_location_x);
+ WriteCoord(channel, this.eent_net_location_y);
+ WriteCoord(channel, this.eent_net_location_z);
// attempt to save a tiny bit more bandwidth by not sending velocity if it isn't set
- if(self.eent_net_velocity)
+ if(this.eent_net_velocity)
{
- WriteByte(MSG_ENTITY, true);
- WriteCoord(MSG_ENTITY, self.eent_net_velocity_x);
- WriteCoord(MSG_ENTITY, self.eent_net_velocity_y);
- WriteCoord(MSG_ENTITY, self.eent_net_velocity_z);
+ WriteByte(channel, true);
+ WriteCoord(channel, this.eent_net_velocity_x);
+ WriteCoord(channel, this.eent_net_velocity_y);
+ WriteCoord(channel, this.eent_net_velocity_z);
}
- else { WriteByte(MSG_ENTITY, false); }
+ else { WriteByte(channel, false); }
- if(!self.eent_eff_trail) { WriteByte(MSG_ENTITY, self.eent_net_count); }
+ if(!this.eent_eff_trail) { WriteByte(channel, this.eent_net_count); }
return true;
}
{
if(!eff) { return; }
if(!eff.eent_eff_trail && !eff_cnt) { return; } // effect has no count!
- entity net_eff = spawn();
+ entity net_eff = new(net_effect);
+ make_pure(net_eff);
net_eff.owner = eff;
- net_eff.classname = "net_effect";
//net_eff.eent_broadcast = broadcast;
net_eff.m_id = eff.m_id;
net_eff.eent_net_velocity = eff_vel;
net_eff.eent_net_count = eff_cnt;
net_eff.eent_eff_trail = eff.eent_eff_trail;
- net_eff.think = SUB_Remove;
- net_eff.nextthink = time + 0.2; // don't need to keep this long
-
- Net_LinkEntity(net_eff, false, 0, Net_Write_Effect);
+ entity e; FOR_EACH_REALCLIENT(e) Net_Write_Effect(net_eff, e, 0);
+ remove(net_eff);
}
void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt)
return;
));
// revert to engine handling
- pointparticles(_particleeffectnum(eff_name), eff_loc, eff_vel, eff_cnt);
+ __pointparticles(_particleeffectnum(eff_name), eff_loc, eff_vel, eff_cnt);
}
#endif
#include "effect.qh"
-#ifdef CSQC
-void Read_Effect(bool is_new);
-#elif defined(SVQC)
+#ifdef SVQC
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt);
void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt);
#endif
-REGISTRY(Effects, BIT(8))
-REGISTER_REGISTRY(RegisterEffects)
+REGISTRY(Effects, BITS(8))
+#define Effects_from(i) _Effects_from(i, EFFECT_Null)
+REGISTER_REGISTRY(Effects)
+REGISTRY_CHECK(Effects)
#define EFFECT(istrail, name, realname) \
- REGISTER(RegisterEffects, EFFECT, Effects, name, m_id, Create_Effect_Entity(realname, istrail));
+ REGISTER(Effects, EFFECT, name, m_id, Create_Effect_Entity(realname, istrail));
-void RegisterEffects_First()
-{
- #ifdef SVQC
- #define dedi (server_is_dedicated ? "a dedicated " : "")
- #else
- #define dedi ""
- #endif
-
- LOG_TRACEF("Beginning effect initialization on %s%s program...\n", dedi, PROGNAME);
- #undef dedi
-}
-
-void RegisterEffects_Done()
-{
- LOG_TRACE("Effects initialization successful!\n");
-}
-
-// NOW we actually activate the declarations
-ACCUMULATE_FUNCTION(RegisterEffects, RegisterEffects_First)
EFFECT(0, Null, string_null)
#include "all.inc"
-ACCUMULATE_FUNCTION(RegisterEffects, RegisterEffects_Done)
#endif
#ifndef EFFECT_H
#define EFFECT_H
-#define particleeffectnum(e) _particleeffectnum(e.eent_eff_name)
+#define particleeffectnum(e) \
+ _particleeffectnum(e.eent_eff_name)
+
+#if defined(SVQC)
+ #define pointparticles(effect, org, vel, howmany) \
+ Send_Effect(effect, org, vel, howmany)
+ #define trailparticles(e, effect, org, vel) \
+ ((!e) ? Send_Effect(effect, org, vel, 0) \
+ : __trailparticles(e, particleeffectnum(effect), org, vel))
+#elif defined(CSQC)
+ #define pointparticles(effect, org, vel, howmany) \
+ __pointparticles(particleeffectnum(effect), org, vel, howmany)
+ #define trailparticles(e, effect, org, vel) \
+ __trailparticles(e, particleeffectnum(effect), org, vel)
+#endif
.int m_id;
.string eent_eff_name;
entity Create_Effect_Entity(string eff_name, bool eff_trail)
{
entity this = new(effect_entity);
+ make_pure(this);
this.eent_eff_name = eff_name;
this.eent_eff_trail = eff_trail;
return this;
}
-REGISTRY(EffectInfos, BIT(9))
-REGISTER_REGISTRY(RegisterEffectInfos)
+REGISTRY(EffectInfos, BITS(9))
+#define EffectInfos_from(i) _EffectInfos_from(i, NULL)
+REGISTER_REGISTRY(EffectInfos)
#define EFFECTINFO(name) \
[[accumulate]] void effectinfo_##name(EffectInfoGroup parent, EffectInfo this) { } \
- REGISTER(RegisterEffectInfos, EFFECTINFO, EffectInfos, name, m_id, NEW(EffectInfoGroup)) { \
+ REGISTER(EffectInfos, EFFECTINFO, name, m_id, NEW(EffectInfoGroup)) { \
effectinfo_##name(this, NULL); \
}
--- /dev/null
+#include "casings.qc"
+#include "damageeffects.qc"
+#include "gibs.qc"
+#include "lightningarc.qc"
+#include "modeleffects.qc"
--- /dev/null
+#include "all.qh"
+
+#define IMPLEMENTATION
+#include "all.inc"
+#undef IMPLEMENTATION
--- /dev/null
+#ifndef EFFECTS_QC
+#define EFFECTS_QC
+#include "all.inc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+
+#include "../../util.qh"
+
+#ifdef CSQC
+#include "../../movetypes/movetypes.qh"
+#include "rubble.qh"
+#endif
+
+REGISTER_NET_TEMP(casings)
+
+#ifdef SVQC
+void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner)
+{SELFPARAM();
+ .entity weaponentity = weaponentities[0]; // TODO: parameter
+ entity wep = self.(weaponentity);
+ vector org = self.origin + self.view_ofs + wep.spawnorigin.x * v_forward - wep.spawnorigin.y * v_right + wep.spawnorigin.z * v_up;
+
+ if (!sound_allowed(MSG_BROADCAST, casingowner))
+ casingtype |= 0x80;
+
+ WriteHeader(MSG_ALL, casings);
+ WriteByte(MSG_ALL, casingtype);
+ WriteCoord(MSG_ALL, org.x);
+ WriteCoord(MSG_ALL, org.y);
+ WriteCoord(MSG_ALL, org.z);
+ WriteShort(MSG_ALL, compressShortVector(vel)); // actually compressed velocity
+ WriteByte(MSG_ALL, ang.x * 256 / 360);
+ WriteByte(MSG_ALL, ang.y * 256 / 360);
+ WriteByte(MSG_ALL, ang.z * 256 / 360);
+}
+#endif
+
+#ifdef CSQC
+entityclass(Casing);
+class(Casing) .float alpha;
+class(Casing) .bool silent;
+class(Casing) .int state;
+class(Casing) .float cnt;
+
+void Casing_Delete()
+{SELFPARAM();
+ remove(self);
+}
+
+void Casing_Draw(entity this)
+{
+ if (self.move_flags & FL_ONGROUND)
+ {
+ self.move_angles_x = 0;
+ self.move_angles_z = 0;
+ self.flags &= ~FL_ONGROUND;
+ }
+
+ Movetype_Physics_MatchTicrate(autocvar_cl_casings_ticrate, autocvar_cl_casings_sloppy);
+ if (wasfreed(self))
+ return; // deleted by touch function
+
+ self.renderflags = 0;
+ self.alpha = bound(0, self.cnt - time, 1);
+
+ if (self.alpha < ALPHA_MIN_VISIBLE)
+ {
+ Casing_Delete();
+ self.drawmask = 0;
+ }
+}
+
+SOUND(BRASS1, W_Sound("brass1"));
+SOUND(BRASS2, W_Sound("brass2"));
+SOUND(BRASS3, W_Sound("brass3"));
+Sound SND_BRASS_RANDOM() {
+ return Sounds_from(SND_BRASS1.m_id + floor(prandom() * 3));
+}
+SOUND(CASINGS1, W_Sound("casings1"));
+SOUND(CASINGS2, W_Sound("casings2"));
+SOUND(CASINGS3, W_Sound("casings3"));
+Sound SND_CASINGS_RANDOM() {
+ return Sounds_from(SND_CASINGS1.m_id + floor(prandom() * 3));
+}
+
+void Casing_Touch()
+{SELFPARAM();
+ if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+ {
+ Casing_Delete();
+ return;
+ }
+
+ if (!self.silent)
+ if (!trace_ent || trace_ent.solid == SOLID_BSP)
+ {
+ if (vlen(self.velocity) > 50)
+ {
+ if (time >= self.nextthink)
+ {
+ Sound s;
+ switch (self.state)
+ {
+ case 1:
+ s = SND_CASINGS_RANDOM();
+ break;
+ default:
+ s = SND_BRASS_RANDOM();
+ break;
+ }
+
+ sound (self, CH_SHOTS, s, VOL_BASE, ATTEN_LARGE);
+ }
+ }
+ }
+
+ self.nextthink = time + 0.2;
+}
+
+void Casing_Damage(float thisdmg, int hittype, vector org, vector thisforce)
+{SELFPARAM();
+ if (thisforce.z < 0)
+ thisforce.z = 0;
+ self.move_velocity = self.move_velocity + thisforce + '0 0 100';
+ self.move_flags &= ~FL_ONGROUND;
+}
+
+NET_HANDLE(casings, bool isNew)
+{
+ int _state = ReadByte();
+ vector org;
+ org_x = ReadCoord();
+ org_y = ReadCoord();
+ org_z = ReadCoord();
+ vector vel = decompressShortVector(ReadShort());
+ vector ang;
+ ang_x = ReadByte() * 360 / 256;
+ ang_y = ReadByte() * 360 / 256;
+ ang_z = ReadByte() * 360 / 256;
+ return = true;
+
+ if (!autocvar_cl_casings) return;
+
+ Casing casing = RubbleNew("casing");
+ casing.silent = (_state & 0x80);
+ casing.state = (_state & 0x7F);
+ casing.origin = org;
+ setorigin(casing, casing.origin);
+ casing.velocity = vel;
+ casing.angles = ang;
+ casing.drawmask = MASK_NORMAL;
+
+ casing.draw = Casing_Draw;
+ casing.move_origin = casing.origin;
+ casing.move_velocity = casing.velocity + 2 * prandomvec();
+ casing.move_angles = casing.angles;
+ casing.move_avelocity = '0 250 0' + 100 * prandomvec();
+ casing.move_movetype = MOVETYPE_BOUNCE;
+ casing.move_touch = Casing_Touch;
+ casing.move_time = time;
+ casing.event_damage = Casing_Damage;
+ casing.solid = SOLID_TRIGGER;
+
+ switch (casing.state)
+ {
+ case 1:
+ setmodel(casing, MDL_CASING_SHELL);
+ casing.cnt = time + autocvar_cl_casings_shell_time;
+ break;
+ default:
+ setmodel(casing, MDL_CASING_BULLET);
+ casing.cnt = time + autocvar_cl_casings_bronze_time;
+ break;
+ }
+
+ setsize(casing, '0 0 -1', '0 0 -1');
+
+ RubbleLimit("casing", autocvar_cl_casings_maxcount, Casing_Delete);
+}
+
+#endif
+#endif
--- /dev/null
+#ifndef DAMAGEEFFECTS_H
+#define DAMAGEEFFECTS_H
+
+#ifdef CSQC
+#include "../../deathtypes/all.qh"
+#include "../../movetypes/movetypes.qh"
+#include "../../../client/mutators/events.qh"
+#include "../../vehicles/all.qh"
+#include "../../weapons/all.qh"
+#endif
+
+#endif
+
+#ifdef IMPLEMENTATION
+
+REGISTER_NET_LINKED(ENT_CLIENT_DAMAGEINFO)
+
+#ifdef SVQC
+
+bool Damage_DamageInfo_SendEntity(entity this, entity to, int sf)
+{
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_DAMAGEINFO);
+ WriteShort(MSG_ENTITY, self.projectiledeathtype);
+ WriteCoord(MSG_ENTITY, floor(self.origin.x));
+ WriteCoord(MSG_ENTITY, floor(self.origin.y));
+ WriteCoord(MSG_ENTITY, floor(self.origin.z));
+ WriteByte(MSG_ENTITY, bound(1, self.dmg, 255));
+ WriteByte(MSG_ENTITY, bound(0, self.dmg_radius, 255));
+ WriteByte(MSG_ENTITY, bound(1, self.dmg_edge, 255));
+ WriteShort(MSG_ENTITY, self.oldorigin.x);
+ WriteByte(MSG_ENTITY, self.species);
+ return true;
+}
+
+void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, int deathtype, float bloodtype, entity dmgowner)
+{
+ // TODO maybe call this from non-edgedamage too?
+ // TODO maybe make the client do the particle effects for the weapons and the impact sounds using this info?
+
+ entity e;
+
+ if(!sound_allowed(MSG_BROADCAST, dmgowner))
+ deathtype |= 0x8000;
+
+ e = new(damageinfo);
+ make_pure(e);
+ setorigin(e, org);
+ e.projectiledeathtype = deathtype;
+ e.dmg = coredamage;
+ e.dmg_edge = edgedamage;
+ e.dmg_radius = rad;
+ e.dmg_force = vlen(force);
+ e.velocity = force;
+ e.oldorigin_x = compressShortVector(e.velocity);
+ e.species = bloodtype;
+
+ Net_LinkEntity(e, false, 0.2, Damage_DamageInfo_SendEntity);
+}
+
+#endif
+
+#ifdef CSQC
+
+/** number of effects which currently are attached to a player */
+.int total_damages;
+
+.entity tag_entity;
+
+.float cnt;
+.int state;
+.bool isplayermodel;
+
+void DamageEffect_Think()
+{SELFPARAM();
+ // if particle distribution is enabled, slow ticrate by total number of damages
+ if(autocvar_cl_damageeffect_distribute)
+ self.nextthink = time + autocvar_cl_damageeffect_ticrate * self.owner.total_damages;
+ else
+ self.nextthink = time + autocvar_cl_damageeffect_ticrate;
+
+ if(time >= self.cnt || !self.owner || !self.owner.modelindex || !self.owner.drawmask)
+ {
+ // time is up or the player got gibbed / disconnected
+ self.owner.total_damages = max(0, self.owner.total_damages - 1);
+ remove(self);
+ return;
+ }
+ if(self.state && !self.owner.csqcmodel_isdead)
+ {
+ // if the player was dead but is now alive, it means he respawned
+ // if so, clear his damage effects, or damages from his dead body will be copied back
+ self.owner.total_damages = max(0, self.owner.total_damages - 1);
+ remove(self);
+ return;
+ }
+ self.state = self.owner.csqcmodel_isdead;
+ if(self.owner.isplayermodel && (self.owner.entnum == player_localentnum) && !autocvar_chase_active)
+ return; // if we aren't using a third person camera, hide our own effects
+
+ // now generate the particles
+ vector org;
+ org = gettaginfo(self, 0); // origin at attached location
+ __pointparticles(self.team, org, '0 0 0', 1);
+}
+
+string species_prefix(int specnum)
+{
+ switch(specnum)
+ {
+ case SPECIES_HUMAN: return "";
+ case SPECIES_ALIEN: return "alien_";
+ case SPECIES_ROBOT_SHINY: return "robot_";
+ case SPECIES_ROBOT_RUSTY: return "robot_"; // use the same effects, only different gibs
+ case SPECIES_ROBOT_SOLID: return "robot_"; // use the same effects, only different gibs
+ case SPECIES_ANIMAL: return "animal_";
+ case SPECIES_RESERVED: return "reserved_";
+ default: return "";
+ }
+}
+
+void DamageEffect(vector hitorg, float thedamage, int type, int specnum)
+{SELFPARAM();
+ // particle effects for players and objects damaged by weapons (eg: flames coming out of victims shot with rockets)
+
+ int nearestbone = 0;
+ float life;
+ string specstr, effectname;
+ entity e;
+
+ if(!autocvar_cl_damageeffect || autocvar_cl_gentle || autocvar_cl_gentle_damage)
+ return;
+ if(!self || !self.modelindex || !self.drawmask)
+ return;
+
+ // if this is a rigged mesh, the effect will show on the bone where damage was dealt
+ // we do this by choosing the skeletal bone closest to the impact, and attaching our entity to it
+ // if there's no skeleton, object origin will automatically be selected
+ FOR_EACH_TAG(self)
+ {
+ if(!tagnum)
+ continue; // skip empty bones
+ // blacklist bones positioned outside the mesh, or the effect will be floating
+ // TODO: Do we have to do it this way? Why do these bones exist at all?
+ if(gettaginfo_name == "master" || gettaginfo_name == "knee_L" || gettaginfo_name == "knee_R" || gettaginfo_name == "leg_L" || gettaginfo_name == "leg_R")
+ continue; // player model bone blacklist
+
+ // now choose the bone closest to impact origin
+ if(nearestbone == 0 || vlen(hitorg - gettaginfo(self, tagnum)) <= vlen(hitorg - gettaginfo(self, nearestbone)))
+ nearestbone = tagnum;
+ }
+ gettaginfo(self, nearestbone); // set gettaginfo_name
+
+ // return if we reached our damage effect limit or damages are disabled
+ // TODO: When the limit is reached, it would be better if the oldest damage was removed instead of not adding a new one
+ if(nearestbone)
+ {
+ if(self.total_damages >= autocvar_cl_damageeffect_bones)
+ return; // allow multiple damages on skeletal models
+ }
+ else
+ {
+ if(autocvar_cl_damageeffect < 2 || self.total_damages)
+ return; // allow a single damage on non-skeletal models
+ }
+
+ life = bound(autocvar_cl_damageeffect_lifetime_min, thedamage * autocvar_cl_damageeffect_lifetime, autocvar_cl_damageeffect_lifetime_max);
+
+ effectname = DEATH_WEAPONOF(type).netname;
+
+ if(substring(effectname, strlen(effectname) - 5, 5) == "BLOOD")
+ {
+ if(self.isplayermodel)
+ {
+ specstr = species_prefix(specnum);
+ specstr = substring(specstr, 0, strlen(specstr) - 1);
+ effectname = strreplace("BLOOD", specstr, effectname);
+ }
+ else { return; } // objects don't bleed
+ }
+
+ e = new(damage);
+ make_pure(e);
+ setmodel(e, MDL_Null); // necessary to attach and read origin
+ setattachment(e, self, gettaginfo_name); // attach to the given bone
+ e.owner = self;
+ e.cnt = time + life;
+ e.team = _particleeffectnum(effectname);
+ e.think = DamageEffect_Think;
+ e.nextthink = time;
+ self.total_damages += 1;
+}
+
+NET_HANDLE(ENT_CLIENT_DAMAGEINFO, bool isNew)
+{
+ make_pure(this);
+ float thedamage, rad, edge, thisdmg;
+ bool hitplayer = false;
+ int species, forcemul;
+ vector force, thisforce;
+
+ w_deathtype = ReadShort();
+ w_issilent = (w_deathtype & 0x8000);
+ w_deathtype = (w_deathtype & 0x7FFF);
+
+ w_org.x = ReadCoord();
+ w_org.y = ReadCoord();
+ w_org.z = ReadCoord();
+
+ thedamage = ReadByte();
+ rad = ReadByte();
+ edge = ReadByte();
+ force = decompressShortVector(ReadShort());
+ species = ReadByte();
+
+ return = true;
+
+ if (!isNew)
+ return;
+
+ if(rad < 0)
+ {
+ rad = -rad;
+ forcemul = -1;
+ }
+ else
+ forcemul = 1;
+
+ for(entity e = findradius(w_org, rad + MAX_DAMAGEEXTRARADIUS); e; e = e.chain)
+ {
+ setself(e);
+ // attached ents suck
+ if(self.tag_entity)
+ continue;
+
+ vector nearest = NearestPointOnBox(self, w_org);
+ if(rad)
+ {
+ thisdmg = ((vlen (nearest - w_org) - bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
+ if(thisdmg >= 1)
+ continue;
+ if(thisdmg < 0)
+ thisdmg = 0;
+ if(thedamage)
+ {
+ thisdmg = thedamage + (edge - thedamage) * thisdmg;
+ thisforce = forcemul * vlen(force) * (thisdmg / thedamage) * normalize(self.origin - w_org);
+ }
+ else
+ {
+ thisdmg = 0;
+ thisforce = forcemul * vlen(force) * normalize(self.origin - w_org);
+ }
+ }
+ else
+ {
+ if(vlen(nearest - w_org) > bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS))
+ continue;
+
+ thisdmg = thedamage;
+ thisforce = forcemul * force;
+ }
+
+ if(self.damageforcescale)
+ if(vlen(thisforce))
+ {
+ self.move_velocity = self.move_velocity + damage_explosion_calcpush(self.damageforcescale * thisforce, self.move_velocity, autocvar_g_balance_damagepush_speedfactor);
+ self.move_flags &= ~FL_ONGROUND;
+ }
+
+ if(w_issilent)
+ self.silent = 1;
+
+ if(self.event_damage)
+ self.event_damage(thisdmg, w_deathtype, w_org, thisforce);
+
+ DamageEffect(w_org, thisdmg, w_deathtype, species);
+
+ if(self.isplayermodel)
+ hitplayer = true; // this impact damaged a player
+ }
+ setself(this);
+
+ if(DEATH_ISVEHICLE(w_deathtype))
+ {
+ traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
+ if(trace_plane_normal != '0 0 0')
+ w_backoff = trace_plane_normal;
+ else
+ w_backoff = -1 * normalize(w_org - (w_org + normalize(force) * 16));
+
+ setorigin(self, w_org + w_backoff * 2); // for sound() calls
+
+ switch(DEATH_ENT(w_deathtype))
+ {
+ case DEATH_VH_CRUSH:
+ break;
+
+ // spiderbot
+ case DEATH_VH_SPID_MINIGUN:
+ sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_SPIDERBOT_MINIGUN_IMPACT, self.origin, w_backoff * 1000, 1);
+ break;
+ case DEATH_VH_SPID_ROCKET:
+ sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_SPIDERBOT_ROCKET_EXPLODE, self.origin, w_backoff * 1000, 1);
+ break;
+ case DEATH_VH_SPID_DEATH:
+ sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
+ pointparticles(EFFECT_EXPLOSION_BIG, self.origin, w_backoff * 1000, 1);
+ break;
+
+ case DEATH_VH_WAKI_GUN:
+ sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_RACER_IMPACT, self.origin, w_backoff * 1000, 1);
+ break;
+ case DEATH_VH_WAKI_ROCKET:
+ sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_RACER_ROCKET_EXPLODE, self.origin, w_backoff * 1000, 1);
+ break;
+ case DEATH_VH_WAKI_DEATH:
+ sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
+ pointparticles(EFFECT_EXPLOSION_BIG, self.origin, w_backoff * 1000, 1);
+ break;
+
+ case DEATH_VH_RAPT_CANNON:
+ sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_RAPTOR_CANNON_IMPACT, self.origin, w_backoff * 1000, 1);
+ break;
+ case DEATH_VH_RAPT_FRAGMENT:
+ float i;
+ vector ang, vel;
+ for(i = 1; i < 4; ++i)
+ {
+ vel = normalize(w_org - (w_org + normalize(force) * 16)) + randomvec() * 128;
+ ang = vectoangles(vel);
+ RaptorCBShellfragToss(w_org, vel, ang + '0 0 1' * (120 * i));
+ }
+ sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_RAPTOR_BOMB_SPREAD, self.origin, w_backoff * 1000, 1);
+ break;
+ case DEATH_VH_RAPT_BOMB:
+ sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_RAPTOR_BOMB_IMPACT, self.origin, w_backoff * 1000, 1);
+ break;
+ case DEATH_VH_RAPT_DEATH:
+ sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_MIN);
+ pointparticles(EFFECT_EXPLOSION_BIG, self.origin, w_backoff * 1000, 1);
+ break;
+ case DEATH_VH_BUMB_GUN:
+ sound(self, CH_SHOTS, SND_FIREBALL_IMPACT2, VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_BIGPLASMA_IMPACT, self.origin, w_backoff * 1000, 1);
+ break;
+ }
+ }
+
+
+ if(DEATH_ISTURRET(w_deathtype))
+ {
+ traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
+ if(trace_plane_normal != '0 0 0')
+ w_backoff = trace_plane_normal;
+ else
+ w_backoff = -1 * normalize(w_org - (w_org + normalize(force) * 16));
+
+ setorigin(self, w_org + w_backoff * 2); // for sound() calls
+
+ switch(DEATH_ENT(w_deathtype))
+ {
+ case DEATH_TURRET_EWHEEL:
+ sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_MIN);
+ pointparticles(EFFECT_BLASTER_IMPACT, self.origin, w_backoff * 1000, 1);
+ break;
+
+ case DEATH_TURRET_FLAC:
+ pointparticles(EFFECT_HAGAR_EXPLODE, w_org, '0 0 0', 1);
+ sound(self, CH_SHOTS, SND_HAGEXP_RANDOM(), VOL_BASE, ATTEN_NORM);
+ break;
+
+ case DEATH_TURRET_MLRS:
+ case DEATH_TURRET_HK:
+ case DEATH_TURRET_WALK_ROCKET:
+ case DEATH_TURRET_HELLION:
+ sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
+ pointparticles(EFFECT_ROCKET_EXPLODE, self.origin, w_backoff * 1000, 1);
+ break;
+
+ case DEATH_TURRET_MACHINEGUN:
+ case DEATH_TURRET_WALK_GUN:
+ sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_MACHINEGUN_IMPACT, self.origin, w_backoff * 1000, 1);
+ break;
+
+ case DEATH_TURRET_PLASMA:
+ sound(self, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_MIN);
+ pointparticles(EFFECT_ELECTRO_IMPACT, self.origin, w_backoff * 1000, 1);
+ break;
+
+ case DEATH_TURRET_WALK_MELEE:
+ sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_MIN);
+ pointparticles(EFFECT_TE_SPARK, self.origin, w_backoff * 1000, 1);
+ break;
+
+ case DEATH_TURRET_PHASER:
+ break;
+
+ case DEATH_TURRET_TESLA:
+ te_smallflash(self.origin);
+ break;
+
+ }
+ }
+
+ // TODO spawn particle effects and sounds based on w_deathtype
+ if(!DEATH_ISSPECIAL(w_deathtype))
+ if(!hitplayer || rad) // don't show ground impacts for hitscan weapons if a player was hit
+ {
+ Weapon hitwep = DEATH_WEAPONOF(w_deathtype);
+ w_random = prandom();
+
+ traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
+ if(trace_fraction < 1 && hitwep != WEP_VORTEX && hitwep != WEP_VAPORIZER)
+ w_backoff = trace_plane_normal;
+ else
+ w_backoff = -1 * normalize(force);
+ setorigin(self, w_org + w_backoff * 2); // for sound() calls
+
+ if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
+ {
+ if(!MUTATOR_CALLHOOK(Weapon_ImpactEffect, hitwep))
+ hitwep.wr_impacteffect(hitwep);
+ }
+ }
+}
+
+#endif
+
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+REGISTER_NET_TEMP(net_gibsplash)
+
+#ifdef SVQC
+
+.int state;
+
+bool Violence_GibSplash_SendEntity(entity this, entity to, int sf)
+{
+ int channel = MSG_ONE;
+ msg_entity = to;
+ WriteHeader(channel, net_gibsplash);
+ WriteByte(channel, this.state); // actually type
+ WriteByte(channel, bound(1, this.cnt * 16, 255)); // gibbage amount multiplier
+ WriteShort(channel, floor(this.origin.x / 4)); // not using a coord here, as gibs don't need this accuracy
+ WriteShort(channel, floor(this.origin.y / 4)); // not using a coord here, as gibs don't need this accuracy
+ WriteShort(channel, floor(this.origin.z / 4)); // not using a coord here, as gibs don't need this accuracy
+ WriteShort(channel, this.oldorigin.x); // acrually compressed velocity
+ return true;
+}
+
+void Violence_GibSplash_At(vector org, vector dir, float type, float amount, entity gibowner, entity attacker)
+{SELFPARAM();
+ if(g_cts) // no gibs in CTS
+ return;
+
+ entity e = new(gibsplash);
+ e.cnt = amount;
+ e.state = type; // should stay smaller than 15
+ if(!sound_allowed(MSG_BROADCAST, gibowner) || !sound_allowed(MSG_BROADCAST, attacker))
+ e.state |= 0x40; // "silence" bit
+ e.state |= 8 * self.species; // gib type, ranges from 0 to 15
+
+ // if this is a copied dead body, send the num of its player instead
+ // TODO: remove this field, read from model txt files
+ if(self.classname == "body")
+ e.team = num_for_edict(self.enemy);
+ else
+ e.team = num_for_edict(self);
+
+ setorigin(e, org);
+ e.velocity = dir;
+
+ e.oldorigin_x = compressShortVector(e.velocity);
+
+ entity cl; FOR_EACH_REALCLIENT(cl) Violence_GibSplash_SendEntity(e, cl, 0);
+ remove(e);
+}
+
+void Violence_GibSplash(entity source, float type, float amount, entity attacker)
+{
+ Violence_GibSplash_At(source.origin + source.view_ofs, source.velocity, type, amount, source, attacker);
+}
+#endif
+
+#ifdef CSQC
+
+.vector colormod;
+.bool silent;
+
+#include "rubble.qh"
+#include "../common/movetypes/movetypes.qh"
+
+.float scale;
+.float alpha;
+.float cnt;
+.float gravity;
+
+void Gib_Delete()
+{SELFPARAM();
+ remove(self);
+}
+
+string species_prefix(int specnum);
+
+void Gib_setmodel(entity gib, string mdlname, int specnum)
+{
+ switch(specnum)
+ {
+ case SPECIES_ROBOT_RUSTY:
+ case SPECIES_ROBOT_SHINY:
+ case SPECIES_ROBOT_SOLID:
+ if(specnum != SPECIES_ROBOT_SOLID || mdlname == "models/gibs/chunk.mdl")
+ {
+ if(mdlname == "models/gibs/bloodyskull.md3")
+ setmodel(gib, MDL_GIB_ROBO);
+ else
+ setmodel(gib, MDL_GIB_ROBO_RANDOM());
+ if(specnum == SPECIES_ROBOT_SHINY)
+ {
+ gib.skin = 1;
+ gib.colormod = '2 2 2';
+ }
+ gib.scale = 1;
+ break;
+ }
+ default:
+ _setmodel(gib, mdlname);
+ gib.skin = specnum;
+ break;
+ }
+}
+
+void new_te_bloodshower (int ef, vector org, float explosionspeed, int howmany)
+{
+ float i, pmod;
+ pmod = autocvar_cl_particles_quality;
+ for (i = 0; i < 50 * pmod; ++i)
+ __pointparticles(ef, org, randomvec() * explosionspeed, howmany / 50);
+}
+
+void SUB_RemoveOnNoImpact()
+{
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+ Gib_Delete();
+}
+
+void Gib_Touch()
+{SELFPARAM();
+ // TODO maybe bounce of walls, make more gibs, etc.
+
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+ {
+ Gib_Delete();
+ return;
+ }
+
+ if(!self.silent)
+ sound(self, CH_PAIN, SND_GIB_SPLAT_RANDOM(), VOL_BASE, ATTEN_NORM);
+ __pointparticles(_particleeffectnum(strcat(species_prefix(self.cnt), "blood")), self.origin + '0 0 1', '0 0 30', 10);
+
+ Gib_Delete();
+}
+
+void Gib_Draw(entity this)
+{
+ vector oldorg;
+ oldorg = self.origin;
+
+ Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
+ if(wasfreed(self))
+ return;
+
+ if(self.touch == Gib_Touch) // don't do this for the "chunk" thingie...
+ // TODO somehow make it spray in a direction dependent on self.angles
+ __trailparticles(self, _particleeffectnum(strcat(species_prefix(self.cnt), EFFECT_TR_SLIGHTBLOOD.eent_eff_name)), oldorg, self.origin);
+ else
+ __trailparticles(self, _particleeffectnum(strcat(species_prefix(self.cnt), EFFECT_TR_BLOOD.eent_eff_name)), oldorg, self.origin);
+
+ self.renderflags = 0;
+
+ // make gibs die faster at low view quality
+ // if view_quality is 0.5, we want to have them die twice as fast
+ self.nextthink -= frametime * (1 / bound(0.01, view_quality, 1.00) - 1);
+
+ self.alpha = bound(0, self.nextthink - time, 1);
+
+ if(self.alpha < ALPHA_MIN_VISIBLE)
+ {
+ self.drawmask = 0;
+ Gib_Delete();
+ }
+}
+
+void TossGib (string mdlname, vector safeorg, vector org, vector vconst, vector vrand, int specnum, bool destroyontouch, bool issilent)
+{
+ entity gib;
+
+ // TODO remove some gibs according to cl_nogibs
+ gib = RubbleNew("gib");
+ gib.move_movetype = MOVETYPE_BOUNCE;
+ gib.gravity = 1;
+ gib.solid = SOLID_CORPSE;
+ gib.cnt = specnum;
+ gib.silent = issilent;
+ Gib_setmodel(gib, mdlname, specnum);
+
+ setsize (gib, '-8 -8 -8', '8 8 8');
+
+ gib.draw = Gib_Draw;
+ if(destroyontouch)
+ gib.move_touch = Gib_Touch;
+ else
+ gib.move_touch = SUB_RemoveOnNoImpact;
+
+ // don't spawn gibs inside solid - just don't
+ if(org != safeorg)
+ {
+ tracebox(safeorg, gib.mins, gib.maxs, org, MOVE_NOMONSTERS, gib);
+ org = trace_endpos;
+ }
+
+ gib.move_origin = org;
+ setorigin(gib, org);
+ gib.move_velocity = vconst * autocvar_cl_gibs_velocity_scale + vrand * autocvar_cl_gibs_velocity_random + '0 0 1' * autocvar_cl_gibs_velocity_up;
+ gib.move_avelocity = prandomvec() * vlen(gib.move_velocity) * autocvar_cl_gibs_avelocity_scale;
+ gib.move_time = time;
+ gib.damageforcescale = autocvar_cl_gibs_damageforcescale;
+
+ gib.nextthink = time + autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15);
+ gib.drawmask = MASK_NORMAL;
+
+ RubbleLimit("gib", autocvar_cl_gibs_maxcount, Gib_Delete);
+}
+
+NET_HANDLE(net_gibsplash, bool isNew)
+{
+ Net_Accept(net_gibsplash);
+
+ string gentle_prefix = "morphed_";
+
+ int type = ReadByte(); // gibbage type
+ int amount = ReadByte() / 16.0; // gibbage amount
+ vector org;
+ org.x = ReadShort() * 4 + 2;
+ org.y = ReadShort() * 4 + 2;
+ org.z = ReadShort() * 4 + 2;
+ vector vel = decompressShortVector(ReadShort());
+
+ return = true;
+
+ float cl_gentle_gibs = autocvar_cl_gentle_gibs;
+ if(cl_gentle_gibs || autocvar_cl_gentle)
+ type |= 0x80; // set gentle bit
+
+ if(type & 0x80)
+ {
+ if(cl_gentle_gibs == 2)
+ gentle_prefix = "";
+ else if(cl_gentle_gibs == 3)
+ gentle_prefix = "happy_";
+ }
+ else if(autocvar_cl_particlegibs)
+ {
+ type |= 0x80;
+ gentle_prefix = "particlegibs_";
+ }
+
+ if (!(cl_gentle_gibs || autocvar_cl_gentle))
+ amount *= 1 - autocvar_cl_nogibs;
+
+ if(autocvar_ekg)
+ amount *= 5;
+
+ if(amount <= 0 || !isNew)
+ return;
+
+ setorigin(this, org); // for the sounds
+
+ int specnum = (type & 0x78) / 8; // blood/gibmodel type: using four bits (0..7, bit indexes 3,4,5)
+ bool issilent = (type & 0x40);
+ type = type & 0x87; // remove the species bits: bit 7 = gentle, bit 0,1,2 = kind of gib
+ string specstr = species_prefix(specnum);
+
+ switch(type)
+ {
+ case 0x01:
+ if(!issilent)
+ sound (this, CH_PAIN, SND_GIB, VOL_BASE, ATTEN_NORM);
+
+ if(prandom() < amount)
+ TossGib ("models/gibs/eye.md3", org, org, vel, prandomvec() * 150, specnum, 0, issilent);
+ new_te_bloodshower(_particleeffectnum(strcat(specstr, "bloodshower")), org, 1200, amount);
+ if(prandom() < amount)
+ TossGib ("models/gibs/bloodyskull.md3", org, org + 16 * prandomvec(), vel, prandomvec() * 100, specnum, 0, issilent);
+
+ for(int c = 0; c < amount; ++c)
+ {
+ int randomvalue = amount - c;
+
+ if(prandom() < randomvalue)
+ TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
+ if(prandom() < randomvalue)
+ TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
+ if(prandom() < randomvalue)
+ TossGib ("models/gibs/chest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
+ if(prandom() < randomvalue)
+ TossGib ("models/gibs/smallchest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
+ if(prandom() < randomvalue)
+ TossGib ("models/gibs/leg1.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
+ if(prandom() < randomvalue)
+ TossGib ("models/gibs/leg2.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
+
+ // these splat on impact
+ if(prandom() < randomvalue)
+ TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+ if(prandom() < randomvalue)
+ TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+ if(prandom() < randomvalue)
+ TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+ if(prandom() < randomvalue)
+ TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+ }
+ break;
+ case 0x02:
+ __pointparticles(_particleeffectnum(strcat(specstr, "blood")), org, vel, amount * 16);
+ break;
+ case 0x03:
+ if(prandom() < amount)
+ TossGib ("models/gibs/chunk.mdl", org, org, vel, prandomvec() * (prandom() * 30 + 20), specnum, 1, issilent); // TODO maybe adjust to more randomization?
+ break;
+ case 0x81:
+ __pointparticles(_particleeffectnum(strcat(gentle_prefix, "damage_dissolve")), org, vel, amount);
+ break;
+ case 0x82:
+ __pointparticles(_particleeffectnum(strcat(gentle_prefix, "damage_hit")), org, vel, amount * 16);
+ break;
+ case 0x83:
+ // no gibs in gentle mode, sorry
+ break;
+ }
+ remove(this);
+}
+#endif
+
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+REGISTER_NET_TEMP(TE_CSQC_ARC)
+
+#if defined(SVQC)
+
+ void te_csqc_lightningarc(vector from, vector to)
+ {
+ WriteHeader(MSG_BROADCAST, TE_CSQC_ARC);
+
+ WriteCoord(MSG_BROADCAST, from.x);
+ WriteCoord(MSG_BROADCAST, from.y);
+ WriteCoord(MSG_BROADCAST, from.z);
+ WriteCoord(MSG_BROADCAST, to.x);
+ WriteCoord(MSG_BROADCAST, to.y);
+ WriteCoord(MSG_BROADCAST, to.z);
+ }
+
+#elif defined(CSQC)
+
+/*
+.vector fx_start;
+.vector fx_end;
+.float fx_with;
+.string fx_texture;
+.float fx_lifetime;
+
+void b_draw()
+{
+ //Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, 0, time * 3, '1 1 1', 0.7, DRAWFLAG_ADDITIVE, view_origin);
+ Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, (self.fx_with/256), 0, '1 1 1', 1, DRAWFLAG_ADDITIVE, view_origin);
+
+}
+void b_make(vector s,vector e, string t,float l,float z)
+{
+ entity b;
+ b = spawn();
+ b.fx_texture = t;
+ b.fx_start = s;
+ b.fx_end = e;
+ b.fx_with = z;
+ b.think = SUB_Remove;
+ b.nextthink = time + l;
+ b.draw = b_draw;
+
+ //b.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
+}
+*/
+
+ void cl_effects_lightningarc(vector from, vector to, float seglength, float drifts, float drifte,
+ float branchfactor, float branchfactor_add)
+ {
+ float length = vlen(from - to);
+ if (length < 1) return;
+
+ // Use at most 16 te_lightning1 segments, as these eat up beam list segments.
+ // TODO: Change this to R_BeginPolygon code, then we no longer have this limit.
+ int steps = min(16, floor(length / seglength));
+ if (steps < 1)
+ {
+ te_lightning1(world, from, to);
+ return;
+ }
+
+ float steplength = length / steps;
+ vector direction = normalize(to - from);
+ vector pos_l = from;
+ if (length > seglength)
+ {
+ for (int i = 1; i < steps; i += 1)
+ {
+ float drift = drifts * (1 - (i / steps)) + drifte * (i / steps);
+ vector dirnew = normalize(direction * (1 - drift) + randomvec() * drift);
+ vector pos = pos_l + dirnew * steplength;
+ te_lightning1(world, pos_l, pos);
+ // WTF endless recursion if branchfactor is 1.0 (possibly due to adding branchfactor_add). FIXME
+ // if(random() < branchfactor)
+ // cl_effects_lightningarc(pos, pos + (dirnew * length * 0.25),seglength,drifts,drifte,min(branchfactor + branchfactor_add,1),branchfactor_add);
+
+ pos_l = pos;
+ }
+ te_lightning1(world, pos_l, to);
+ }
+ else
+ {
+ te_lightning1(world, from, to);
+ }
+ }
+
+ NET_HANDLE(TE_CSQC_ARC, bool isNew)
+ {
+ vector from;
+ from.x = ReadCoord();
+ from.y = ReadCoord();
+ from.z = ReadCoord();
+ vector to;
+ to.x = ReadCoord();
+ to.y = ReadCoord();
+ to.z = ReadCoord();
+ return = true;
+
+ if (autocvar_cl_effects_lightningarc_simple)
+ {
+ te_lightning1(world, from, to);
+ }
+ else
+ {
+ float seglength = autocvar_cl_effects_lightningarc_segmentlength;
+ float drifts = autocvar_cl_effects_lightningarc_drift_start;
+ float drifte = autocvar_cl_effects_lightningarc_drift_end;
+ float branchfactor = autocvar_cl_effects_lightningarc_branchfactor_start;
+ float branchfactor_add = autocvar_cl_effects_lightningarc_branchfactor_add;
+
+ cl_effects_lightningarc(from, to, seglength, drifts, drifte, branchfactor, branchfactor_add);
+ }
+ }
+
+#endif
+
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+
+REGISTER_NET_LINKED(ENT_CLIENT_MODELEFFECT)
+
+#ifdef SVQC
+
+.float scale2;
+
+bool modeleffect_SendEntity(entity this, entity to, int sf)
+{
+ float f;
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
+
+ f = 0;
+ if(self.velocity != '0 0 0')
+ f |= 1;
+ if(self.angles != '0 0 0')
+ f |= 2;
+ if(self.avelocity != '0 0 0')
+ f |= 4;
+
+ WriteByte(MSG_ENTITY, f);
+ WriteShort(MSG_ENTITY, self.modelindex);
+ WriteByte(MSG_ENTITY, self.skin);
+ WriteByte(MSG_ENTITY, self.frame);
+ WriteCoord(MSG_ENTITY, self.origin.x);
+ WriteCoord(MSG_ENTITY, self.origin.y);
+ WriteCoord(MSG_ENTITY, self.origin.z);
+ if(f & 1)
+ {
+ WriteCoord(MSG_ENTITY, self.velocity.x);
+ WriteCoord(MSG_ENTITY, self.velocity.y);
+ WriteCoord(MSG_ENTITY, self.velocity.z);
+ }
+ if(f & 2)
+ {
+ WriteCoord(MSG_ENTITY, self.angles.x);
+ WriteCoord(MSG_ENTITY, self.angles.y);
+ WriteCoord(MSG_ENTITY, self.angles.z);
+ }
+ if(f & 4)
+ {
+ WriteCoord(MSG_ENTITY, self.avelocity.x);
+ WriteCoord(MSG_ENTITY, self.avelocity.y);
+ WriteCoord(MSG_ENTITY, self.avelocity.z);
+ }
+ WriteShort(MSG_ENTITY, self.scale * 256.0);
+ WriteShort(MSG_ENTITY, self.scale2 * 256.0);
+ WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
+ WriteByte(MSG_ENTITY, self.fade_time * 100.0);
+ WriteByte(MSG_ENTITY, self.alpha * 255.0);
+
+ return true;
+}
+
+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)
+{
+ entity e = new(modeleffect);
+ _setmodel(e, m);
+ e.frame = f;
+ setorigin(e, o);
+ e.velocity = v;
+ e.angles = ang;
+ e.avelocity = angv;
+ e.alpha = a;
+ e.teleport_time = t1;
+ e.fade_time = t2;
+ e.skin = s;
+ if(s0 >= 0)
+ e.scale = s0 / max6(-e.mins.x, -e.mins.y, -e.mins.z, e.maxs.x, e.maxs.y, e.maxs.z);
+ else
+ e.scale = -s0;
+ if(s2 >= 0)
+ e.scale2 = s2 / max6(-e.mins.x, -e.mins.y, -e.mins.z, e.maxs.x, e.maxs.y, e.maxs.z);
+ else
+ e.scale2 = -s2;
+ float sz = max(e.scale, e.scale2);
+ setsize(e, e.mins * sz, e.maxs * sz);
+ Net_LinkEntity(e, false, 0.1, modeleffect_SendEntity);
+}
+
+#endif
+
+#ifdef CSQC
+
+entityclass(ModelEffect);
+class(ModelEffect) .float frame1time;
+class(ModelEffect) .float lifetime, fadetime;
+class(ModelEffect) .float teleport_time;
+class(ModelEffect) .float scale1, scale2;
+
+.float cnt;
+.float scale;
+.float alpha;
+
+void ModelEffect_Draw(entity this)
+{
+ self.angles = self.angles + frametime * self.avelocity;
+ setorigin(self, self.origin + frametime * self.velocity);
+ self.scale = self.scale1 + (self.scale2 - self.scale1) * (time - self.teleport_time) / (self.lifetime + self.fadetime - self.teleport_time);
+ self.alpha = self.cnt * bound(0, 1 - (time - self.lifetime) / self.fadetime, 1);
+ if(self.alpha < ALPHA_MIN_VISIBLE)
+ {
+ remove(self);
+ return;
+ }
+ self.drawmask = MASK_NORMAL;
+ if(self.scale <= 0)
+ {
+ self.drawmask = 0;
+ return;
+ }
+}
+
+NET_HANDLE(ENT_CLIENT_MODELEFFECT, bool isnew)
+{
+ make_pure(self);
+
+ int f = ReadByte();
+
+ entity e = new(modeleffect);
+ e.model = "from network";
+ e.modelindex = ReadShort();
+ e.skin = ReadByte();
+ e.frame = ReadByte();
+ e.frame1time = time;
+ e.origin_x = ReadCoord();
+ e.origin_y = ReadCoord();
+ e.origin_z = ReadCoord();
+ setorigin(e, e.origin);
+ if(f & 1)
+ {
+ e.velocity_x = ReadCoord();
+ e.velocity_y = ReadCoord();
+ e.velocity_z = ReadCoord();
+ }
+ if(f & 2)
+ {
+ e.angles_x = ReadAngle();
+ e.angles_y = ReadAngle();
+ e.angles_z = ReadAngle();
+ }
+ if(f & 4)
+ {
+ e.avelocity_x = ReadAngle();
+ e.avelocity_y = ReadAngle();
+ e.avelocity_z = ReadAngle();
+ }
+ e.scale1 = ReadShort() / 256.0;
+ e.scale2 = ReadShort() / 256.0;
+ e.lifetime = time + ReadByte() * 0.01;
+ e.fadetime = ReadByte() * 0.01;
+ e.teleport_time = time;
+ e.cnt = ReadByte() / 255.0; // actually alpha
+
+ e.draw = ModelEffect_Draw;
+
+ if (!isnew) remove(e); // yes, this IS stupid, but I don't need to duplicate all the read* stuff then
+ return true;
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef RUBBLE_H
+#define RUBBLE_H
+
+#ifdef CSQC
+
+entityclass(Rubble);
+class(Rubble).float creationtime;
+
+void RubbleLimit(string cname, float limit, void() deleteproc)
+{
+ SELFPARAM();
+ entity e;
+ entity oldest;
+ float c;
+ float oldesttime;
+
+ // remove rubble of the same type if it's at the limit
+ // remove multiple rubble if the limit has been decreased
+ while (1)
+ {
+ e = findchain(classname, cname);
+ if (e == world) break;
+ // walk the list and count the entities, find the oldest
+ // initialize our search with the first entity
+ c = 1;
+ oldest = e;
+ oldesttime = e.creationtime;
+ e = e.chain;
+ // compare to all other matching entities
+ while (e)
+ {
+ c = c + 1;
+ if (oldesttime > e.creationtime)
+ {
+ oldesttime = e.creationtime;
+ oldest = e;
+ }
+ e = e.chain;
+ }
+
+ // stop if there are less than the limit already
+ if (c <= limit) break;
+
+ // delete this oldest one and search again
+ WITH(entity, self, oldest, deleteproc());
+ }
+}
+
+entity RubbleNew(string cname)
+{
+ // spawn a new entity and return it
+ entity e = spawn();
+ e.classname = cname;
+ e.creationtime = time;
+ return e;
+}
+
+#endif
+
+#endif
-#include "gamemode/nexball/nexball.qc"
+#include "gamemode/nexball/module.inc"
+#include "gamemode/onslaught/module.inc"
--- /dev/null
+#include "nexball.qc"
+#include "weapon.qc"
GameLogEcho(s);
}
-void ball_restart(void)
+void ball_restart()
{SELFPARAM();
if(self.owner)
DropBall(self, self.owner.origin, '0 0 0');
ResetBall();
}
-void nexball_setstatus(void)
+void nexball_setstatus()
{SELFPARAM();
self.items &= ~IT_KEY1;
if(self.ballcarried)
}
}
-void relocate_nexball(void)
+void relocate_nexball()
{SELFPARAM();
tracebox(self.origin, BALL_MINS, BALL_MAXS, self.origin, true, self);
if(trace_startsolid)
}
}
-void DropOwner(void)
+void DropOwner()
{SELFPARAM();
entity ownr;
ownr = self.owner;
void GiveBall(entity plyr, entity ball)
{SELFPARAM();
- entity ownr;
-
- if((ownr = ball.owner))
+ .entity weaponentity = weaponentities[0]; // TODO: find ballstealer
+ entity ownr = ball.owner;
+ if(ownr)
{
ownr.effects &= ~autocvar_g_nexball_basketball_effects_default;
ownr.ballcarried = world;
if(ownr.metertime)
{
ownr.metertime = 0;
- ownr.weaponentity.state = WS_READY;
+ ownr.(weaponentity).state = WS_READY;
}
WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
}
ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
}
- plyr.weaponentity.weapons = plyr.weapons;
- plyr.weaponentity.switchweapon = plyr.weapon;
+ plyr.(weaponentity).weapons = plyr.weapons;
+ plyr.(weaponentity).switchweapon = plyr.weapon;
plyr.weapons = WEPSET(NEXBALL);
setself(plyr);
Weapon w = WEP_NEXBALL;
if(ball.owner.metertime)
{
ball.owner.metertime = 0;
- ball.owner.weaponentity.state = WS_READY;
+ .entity weaponentity = weaponentities[0]; // TODO: find ballstealer
+ ball.owner.(weaponentity).state = WS_READY;
}
WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
ball.owner = world;
}
-void InitBall(void)
+void InitBall()
{SELFPARAM();
if(gameover) return;
self.flags &= ~FL_ONGROUND;
LogNB("init", world);
}
-void ResetBall(void)
+void ResetBall()
{SELFPARAM();
if(self.cnt < 2) // step 1
{
}
}
-void football_touch(void)
+void football_touch()
{SELFPARAM();
if(other.solid == SOLID_BSP)
{
self.avelocity = -250 * v_forward; // maybe there is a way to make it look better?
}
-void basketball_touch(void)
+void basketball_touch()
{SELFPARAM();
if(other.ballcarried)
{
}
}
-void GoalTouch(void)
+void GoalTouch()
{SELFPARAM();
entity ball;
float isclient, pscore, otherteam;
void nb_spawnteam(string teamname, float teamcolor)
{
LOG_TRACE("^2spawned team ", teamname, "\n");
- entity e;
- e = spawn();
- e.classname = "nexball_team";
+ entity e = new(nexball_team);
e.netname = teamname;
e.cnt = teamcolor;
e.team = e.cnt + 1;
nb_teams += 1;
}
-void nb_spawnteams(void)
+void nb_spawnteams()
{
bool t_red = false, t_blue = false, t_yellow = false, t_pink = false;
entity e;
}
}
-void nb_delayedinit(void)
+void nb_delayedinit()
{
if(find(world, classname, "nexball_team") == world)
nb_spawnteams();
// spawnfuncs //
//=======================//
-void SpawnBall(void)
+void SpawnBall()
{SELFPARAM();
if(!g_nexball) { remove(self); return; }
if(!autocvar_g_nexball_sound_bounce)
self.noise = "";
else if(self.noise == "")
- self.noise = SND(NB_BOUNCE);
+ self.noise = strzone(SND(NB_BOUNCE));
//bounce sound placeholder (FIXME)
if(self.noise1 == "")
- self.noise1 = SND(NB_DROP);
+ self.noise1 = strzone(SND(NB_DROP));
//ball drop sound placeholder (FIXME)
if(self.noise2 == "")
- self.noise2 = SND(NB_STEAL);
+ self.noise2 = strzone(SND(NB_STEAL));
//stealing sound placeholder (FIXME)
if(self.noise) precache_sound(self.noise);
precache_sound(self.noise1);
return true;
}
-void SpawnGoal(void)
+void SpawnGoal()
{SELFPARAM();
if(!g_nexball) { remove(self); return; }
{
self.team = GOAL_FAULT;
if(self.noise == "")
- self.noise = SND(TYPEHIT);
+ self.noise = strzone(SND(TYPEHIT));
SpawnGoal();
}
{
self.team = GOAL_OUT;
if(self.noise == "")
- self.noise = SND(TYPEHIT);
+ self.noise = strzone(SND(TYPEHIT));
SpawnGoal();
}
self.nextthink = time;
}
-void W_Nexball_Touch(void)
+void W_Nexball_Touch()
{SELFPARAM();
entity ball, attacker;
attacker = self.owner;
vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
-void W_Nexball_Attack2(void)
+void W_Nexball_Attack2()
{SELFPARAM();
if(self.ballcarried.enemy)
{
return;
W_SetupShot(self, false, 2, SND(NB_SHOOT2), CH_WEAPON_A, 0);
- entity missile = spawn();
+ entity missile = new(ballstealer);
missile.owner = self;
- missile.classname = "ballstealer";
missile.movetype = MOVETYPE_FLY;
PROJECTILE_MAKETRIGGER(missile);
return true;
}
- METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, .entity weaponentity, int fire))
{
- if(fire1)
- if(weapon_prepareattack(thiswep, actor, false, autocvar_g_balance_nexball_primary_refire))
+ if(fire & 1)
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_balance_nexball_primary_refire))
if(autocvar_g_nexball_basketball_meter)
{
if(self.ballcarried && !self.metertime)
self.metertime = time;
else
- weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
}
else
{
W_Nexball_Attack(-1);
- weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
}
- if(fire2)
- if(weapon_prepareattack(thiswep, actor, true, autocvar_g_balance_nexball_secondary_refire))
+ if(fire & 2)
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_nexball_secondary_refire))
{
W_Nexball_Attack2();
- weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
}
- if(!fire1 && self.metertime && self.ballcarried)
+ if(!(fire & 1) && self.metertime && self.ballcarried)
{
W_Nexball_Attack(time - self.metertime);
// DropBall or stealing will set metertime back to 0
- weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
}
}
METHOD(BallStealer, wr_setup, void(BallStealer thiswep))
}
else
{
- if(self.weaponentity.weapons)
+ .entity weaponentity = weaponentities[0]; // TODO
+ if(self.(weaponentity).weapons)
{
- self.weapons = self.weaponentity.weapons;
+ self.weapons = self.(weaponentity).weapons;
Weapon w = WEP_NEXBALL;
w.wr_resetplayer(w);
- self.switchweapon = self.weaponentity.switchweapon;
+ self.switchweapon = self.(weaponentity).switchweapon;
W_SwitchWeapon(self.switchweapon);
- self.weaponentity.weapons = '0 0 0';
+ self.(weaponentity).weapons = '0 0 0';
}
}
{
SELFPARAM();
this.metertime = 0;
- this.weaponentity.weapons = '0 0 0';
+ .entity weaponentity = weaponentities[0];
+ this.(weaponentity).weapons = '0 0 0';
if (nexball_mode & NBM_BASKETBALL)
this.weapons |= WEPSET(NEXBALL);
REGISTER_MUTATOR(nb, g_nexball)
{
- ActivateTeamplay();
- SetLimits(autocvar_g_nexball_goallimit, autocvar_g_nexball_goalleadlimit, -1, -1);
- have_team_spawns = -1; // request team spawns
-
MUTATOR_ONADD
{
g_nexball_meter_period = autocvar_g_nexball_meter_period;
InitializeEntity(world, nb_delayedinit, INITPRIO_GAMETYPE);
WEP_NEXBALL.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+
+ ActivateTeamplay();
+ SetLimits(autocvar_g_nexball_goallimit, autocvar_g_nexball_goalleadlimit, -1, -1);
+ have_team_spawns = -1; // request team spawns
}
MUTATOR_ONROLLBACK_OR_REMOVE
#ifndef GAMEMODE_NEXBALL_H
#define GAMEMODE_NEXBALL_H
-#include "weapon.qc"
-
#ifdef SVQC
//EF_BRIGHTFIELD|EF_BRIGHTLIGHT|EF_DIMLIGHT|EF_BLUE|EF_RED|EF_FLAME
const float BALL_EFFECTMASK = 1229;
/* flags */ ATTRIB(BallStealer, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(BallStealer, impulse, int, 0);
/* refname */ ATTRIB(BallStealer, netname, string, "ballstealer");
-/* wepname */ ATTRIB(BallStealer, message, string, _("Ball Stealer"));
+/* wepname */ ATTRIB(BallStealer, m_name, string, _("Ball Stealer"));
ENDCLASS(BallStealer)
REGISTER_WEAPON(NEXBALL, NEW(BallStealer));
--- /dev/null
+#include "cl_controlpoint.qh"
+
+.vector colormod;
+.float alpha;
+.int count;
+.float pain_finished;
+
+.bool iscaptured;
+
+.vector cp_origin, cp_bob_origin;
+.float cp_bob_spd;
+
+.vector cp_bob_dmg;
+
+.vector punchangle;
+
+.float max_health;
+
+.entity icon_realmodel;
+
+void cpicon_draw(entity this)
+{
+ if(time < this.move_time) { return; }
+
+ if(this.cp_bob_dmg_z > 0)
+ this.cp_bob_dmg_z = this.cp_bob_dmg_z - 3 * frametime;
+ else
+ this.cp_bob_dmg_z = 0;
+ this.cp_bob_origin_z = 4 * PI * (1 - cos(this.cp_bob_spd));
+ this.cp_bob_spd = this.cp_bob_spd + 1.875 * frametime;
+ this.colormod = '1 1 1' * (2 - bound(0, (this.pain_finished - time) / 10, 1));
+
+ if(!this.iscaptured) this.alpha = this.health / this.max_health;
+
+ if(this.iscaptured)
+ {
+ if (this.punchangle_x > 0)
+ {
+ this.punchangle_x = this.punchangle_x - 60 * frametime;
+ if (this.punchangle_x < 0)
+ this.punchangle_x = 0;
+ }
+ else if (this.punchangle_x < 0)
+ {
+ this.punchangle_x = this.punchangle_x + 60 * frametime;
+ if (this.punchangle_x > 0)
+ this.punchangle_x = 0;
+ }
+
+ if (this.punchangle_y > 0)
+ {
+ this.punchangle_y = this.punchangle_y - 60 * frametime;
+ if (this.punchangle_y < 0)
+ this.punchangle_y = 0;
+ }
+ else if (this.punchangle_y < 0)
+ {
+ this.punchangle_y = this.punchangle_y + 60 * frametime;
+ if (this.punchangle_y > 0)
+ this.punchangle_y = 0;
+ }
+
+ if (this.punchangle_z > 0)
+ {
+ this.punchangle_z = this.punchangle_z - 60 * frametime;
+ if (this.punchangle_z < 0)
+ this.punchangle_z = 0;
+ }
+ else if (this.punchangle_z < 0)
+ {
+ this.punchangle_z = this.punchangle_z + 60 * frametime;
+ if (this.punchangle_z > 0)
+ this.punchangle_z = 0;
+ }
+
+ this.angles_x = this.punchangle_x;
+ this.angles_y = this.punchangle_y + this.move_angles_y;
+ this.angles_z = this.punchangle_z;
+ this.move_angles_y = this.move_angles_y + 45 * frametime;
+ }
+
+ setorigin(this, this.cp_origin + this.cp_bob_origin + this.cp_bob_dmg);
+}
+
+void cpicon_damage(entity this, float hp)
+{
+ if(!this.iscaptured) { return; }
+
+ if(hp < this.max_health * 0.25)
+ setmodel(this, MDL_ONS_CP3);
+ else if(hp < this.max_health * 0.50)
+ setmodel(this, MDL_ONS_CP2);
+ else if(hp < this.max_health * 0.75)
+ setmodel(this, MDL_ONS_CP1);
+ else if(hp <= this.max_health || hp >= this.max_health)
+ setmodel(this, MDL_ONS_CP);
+
+ this.punchangle = (2 * randomvec() - '1 1 1') * 45;
+
+ this.cp_bob_dmg_z = (2 * random() - 1) * 15;
+ this.pain_finished = time + 1;
+ this.colormod = '2 2 2';
+
+ setsize(this, CPICON_MIN, CPICON_MAX);
+}
+
+void cpicon_construct(entity this)
+{
+ this.netname = "Control Point Icon";
+
+ setmodel(this, MDL_ONS_CP);
+ setsize(this, CPICON_MIN, CPICON_MAX);
+
+ if(this.icon_realmodel == world)
+ {
+ this.icon_realmodel = spawn();
+ setmodel(this.icon_realmodel, MDL_Null);
+ setorigin(this.icon_realmodel, this.origin);
+ setsize(this.icon_realmodel, CPICON_MIN, CPICON_MAX);
+ this.icon_realmodel.movetype = MOVETYPE_NOCLIP;
+ this.icon_realmodel.solid = SOLID_NOT;
+ this.icon_realmodel.move_origin = this.icon_realmodel.origin;
+ }
+
+ if(this.iscaptured) { this.icon_realmodel.solid = SOLID_BBOX; }
+
+ this.move_movetype = MOVETYPE_NOCLIP;
+ this.solid = SOLID_NOT;
+ this.movetype = MOVETYPE_NOCLIP;
+ this.move_origin = this.origin;
+ this.move_time = time;
+ this.drawmask = MASK_NORMAL;
+ this.alpha = 1;
+ this.draw = cpicon_draw;
+ this.cp_origin = this.origin;
+ this.cp_bob_origin = '0 0 0.1';
+ this.cp_bob_spd = 0;
+}
+
+.vector glowmod;
+void cpicon_changeteam(entity this)
+{
+ if(this.team)
+ {
+ this.glowmod = Team_ColorRGB(this.team - 1);
+ this.teamradar_color = Team_ColorRGB(this.team - 1);
+ this.colormap = 1024 + (this.team - 1) * 17;
+ }
+ else
+ {
+ this.colormap = 1024;
+ this.glowmod = '1 1 0';
+ this.teamradar_color = '1 1 0';
+ }
+}
+
+NET_HANDLE(ENT_CLIENT_CONTROLPOINT_ICON, bool isnew)
+{
+ return = true;
+ int sf = ReadByte();
+
+ if(sf & CPSF_SETUP)
+ {
+ this.origin_x = ReadCoord();
+ this.origin_y = ReadCoord();
+ this.origin_z = ReadCoord();
+ setorigin(this, this.origin);
+
+ this.health = ReadByte();
+ this.max_health = ReadByte();
+ this.count = ReadByte();
+ this.team = ReadByte();
+ this.iscaptured = ReadByte();
+
+ if(!this.count)
+ this.count = (this.health - this.max_health) * frametime;
+
+ cpicon_changeteam(this);
+ cpicon_construct(this);
+ }
+
+ if(sf & CPSF_STATUS)
+ {
+ int _tmp = ReadByte();
+ if(_tmp != this.team)
+ {
+ this.team = _tmp;
+ cpicon_changeteam(this);
+ }
+
+ _tmp = ReadByte();
+
+ if(_tmp != this.health)
+ cpicon_damage(this, _tmp);
+
+ this.health = _tmp;
+ }
+}
--- /dev/null
+#ifndef CLIENT_CONTROLPOINT_H
+#define CLIENT_CONTROLPOINT_H
+
+const vector CPICON_MIN = '-32 -32 -9';
+const vector CPICON_MAX = '32 32 25';
+
+const int CPSF_STATUS = 4;
+const int CPSF_SETUP = 8;
+
+#endif
--- /dev/null
+#include "cl_generator.qh"
+
+.float alpha;
+.float scale;
+.int count;
+.float max_health;
+
+void ons_generator_ray_draw(entity this)
+{
+ if(time < self.move_time)
+ return;
+
+ self.move_time = time + 0.05;
+
+ if(self.count > 10)
+ {
+ remove(self);
+ return;
+ }
+
+ if(self.count > 5)
+ self.alpha -= 0.1;
+ else
+ self.alpha += 0.1;
+
+ self.scale += 0.2;
+ self.count +=1;
+}
+
+void ons_generator_ray_spawn(vector org)
+{
+ entity e = new(ons_ray);
+ setmodel(e, MDL_ONS_RAY);
+ setorigin(e, org);
+ e.angles = randomvec() * 360;
+ e.move_origin = org;
+ e.movetype = MOVETYPE_NONE;
+ e.alpha = 0;
+ e.scale = random() * 5 + 8;
+ e.move_time = time + 0.05;
+ e.drawmask = MASK_NORMAL;
+ e.draw = ons_generator_ray_draw;
+}
+
+void generator_draw(entity this)
+{
+ if(time < self.move_time)
+ return;
+
+ if(self.health > 0)
+ {
+ // damaged fx (less probable the more damaged is the generator)
+ if(random() < 0.9 - self.health / self.max_health)
+ if(random() < 0.01)
+ {
+ pointparticles(EFFECT_ELECTRO_BALLEXPLODE, self.origin + randompos('-50 -50 -20', '50 50 50'), '0 0 0', 1);
+ sound(self, CH_TRIGGER, SND_ONS_ELECTRICITY_EXPLODE, VOL_BASE, ATTEN_NORM);
+ }
+ else
+ pointparticles(EFFECT_ONS_GENERATOR_DAMAGED, self.origin + randompos('-60 -60 -20', '60 60 60'), '0 0 0', 1);
+
+ self.move_time = time + 0.1;
+
+ return;
+ }
+
+ if(self.count <= 0)
+ return;
+
+ vector org;
+ int i;
+
+ // White shockwave
+ if(self.count==40||self.count==20)
+ {
+ sound(self, CH_TRIGGER, SND_ONS_SHOCKWAVE, VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_ELECTRO_COMBO, self.origin, '0 0 0', 6);
+ }
+
+ // rays
+ if(random() > 0.25)
+ {
+ ons_generator_ray_spawn(self.origin);
+ }
+
+ // Spawn fire balls
+ for(i=0;i < 10;++i)
+ {
+ org = self.origin + randompos('-30 -30 -30' * i + '0 0 -20', '30 30 30' * i + '0 0 20');
+ pointparticles(EFFECT_ONS_GENERATOR_GIB, org, '0 0 0', 1);
+ }
+
+ // Short explosion sound + small explosion
+ if(random() < 0.25)
+ {
+ te_explosion(self.origin);
+ sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
+ }
+
+ // Particles
+ org = self.origin + randompos(self.mins + '8 8 8', self.maxs + '-8 -8 -8');
+ pointparticles(EFFECT_ONS_GENERATOR_EXPLODE, org, '0 0 0', 1);
+
+ // Final explosion
+ if(self.count==1)
+ {
+ org = self.origin;
+ te_explosion(org);
+ pointparticles(EFFECT_ONS_GENERATOR_EXPLODE2, org, '0 0 0', 1);
+ sound(self, CH_TRIGGER, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+ }
+
+ self.move_time = time + 0.05;
+
+ self.count -= 1;
+}
+
+void generator_damage(float hp)
+{SELFPARAM();
+ if(hp <= 0)
+ setmodel(self, MDL_ONS_GEN_DEAD);
+ else if(hp < self.max_health * 0.10)
+ setmodel(self, MDL_ONS_GEN9);
+ else if(hp < self.max_health * 0.20)
+ setmodel(self, MDL_ONS_GEN8);
+ else if(hp < self.max_health * 0.30)
+ setmodel(self, MDL_ONS_GEN7);
+ else if(hp < self.max_health * 0.40)
+ setmodel(self, MDL_ONS_GEN6);
+ else if(hp < self.max_health * 0.50)
+ setmodel(self, MDL_ONS_GEN5);
+ else if(hp < self.max_health * 0.60)
+ setmodel(self, MDL_ONS_GEN4);
+ else if(hp < self.max_health * 0.70)
+ setmodel(self, MDL_ONS_GEN3);
+ else if(hp < self.max_health * 0.80)
+ setmodel(self, MDL_ONS_GEN2);
+ else if(hp < self.max_health * 0.90)
+ setmodel(self, MDL_ONS_GEN1);
+ else if(hp <= self.max_health || hp >= self.max_health)
+ setmodel(self, MDL_ONS_GEN);
+
+ setsize(self, GENERATOR_MIN, GENERATOR_MAX);
+}
+
+void generator_construct()
+{SELFPARAM();
+ self.netname = "Generator";
+ self.classname = "onslaught_generator";
+
+ setorigin(self, self.origin);
+ setmodel(self, MDL_ONS_GEN);
+ setsize(self, GENERATOR_MIN, GENERATOR_MAX);
+
+ self.move_movetype = MOVETYPE_NOCLIP;
+ self.solid = SOLID_BBOX;
+ self.movetype = MOVETYPE_NOCLIP;
+ self.move_origin = self.origin;
+ self.move_time = time;
+ self.drawmask = MASK_NORMAL;
+ self.alpha = 1;
+ self.draw = generator_draw;
+}
+
+.vector glowmod;
+void generator_changeteam()
+{SELFPARAM();
+ if(self.team)
+ {
+ self.glowmod = Team_ColorRGB(self.team - 1);
+ self.teamradar_color = Team_ColorRGB(self.team - 1);
+ self.colormap = 1024 + (self.team - 1) * 17;
+ }
+ else
+ {
+ self.colormap = 1024;
+ self.glowmod = '1 1 0';
+ self.teamradar_color = '1 1 0';
+ }
+}
+
+NET_HANDLE(ENT_CLIENT_GENERATOR, bool isnew)
+{
+ return = true;
+ int sf = ReadByte();
+
+ if(sf & GSF_SETUP)
+ {
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ setorigin(self, self.origin);
+
+ self.health = ReadByte();
+ self.max_health = ReadByte();
+ self.count = ReadByte();
+ self.team = ReadByte();
+
+ if(!self.count)
+ self.count = 40;
+
+ generator_changeteam();
+ generator_construct();
+ }
+
+ if(sf & GSF_STATUS)
+ {
+ int _tmp;
+ _tmp = ReadByte();
+ if(_tmp != self.team)
+ {
+ self.team = _tmp;
+ generator_changeteam();
+ }
+
+ _tmp = ReadByte();
+
+ if(_tmp != self.health)
+ generator_damage(_tmp);
+
+ self.health = _tmp;
+ }
+}
--- /dev/null
+#ifndef CLIENT_GENERATOR_H
+#define CLIENT_GENERATOR_H
+const vector GENERATOR_MIN = '-52 -52 -14';
+const vector GENERATOR_MAX = '52 52 75';
+
+const int GSF_STATUS = 4;
+const int GSF_SETUP = 8;
+
+#endif
--- /dev/null
+#ifndef ONS_CONSTANTS
+ #define ONS_CONSTANTS
+ REGISTER_NET_LINKED(ENT_CLIENT_GENERATOR)
+ REGISTER_NET_LINKED(ENT_CLIENT_CONTROLPOINT_ICON)
+#endif
+
+#if defined(SVQC)
+ #include "onslaught.qc"
+ #ifndef IMPLEMENTATION
+ #include "sv_controlpoint.qh"
+ #include "sv_generator.qh"
+ #else
+ #include "sv_controlpoint.qc"
+ #include "sv_generator.qc"
+ #endif
+#elif defined(CSQC)
+ #ifndef IMPLEMENTATION
+ #include "cl_controlpoint.qh"
+ #include "cl_generator.qh"
+ #else
+ #include "cl_controlpoint.qc"
+ #include "cl_generator.qc"
+ #endif
+#endif
--- /dev/null
+#ifndef GAMEMODE_ONSLAUGHT_H
+#define GAMEMODE_ONSLAUGHT_H
+
+float autocvar_g_onslaught_point_limit;
+void ons_Initialize();
+
+REGISTER_MUTATOR(ons, false)
+{
+ MUTATOR_ONADD
+ {
+ if (time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ ons_Initialize();
+
+ ActivateTeamplay();
+ SetLimits(autocvar_g_onslaught_point_limit, -1, -1, -1);
+ have_team_spawns = -1; // request team spawns
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // we actually cannot roll back ons_Initialize here
+ // BUT: we don't need to! If this gets called, adding always
+ // succeeds.
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ LOG_INFO("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return false;
+}
+
+#ifdef SVQC
+
+.entity ons_toucher; // player who touched the control point
+
+// control point / generator constants
+const float ONS_CP_THINKRATE = 0.2;
+const float GEN_THINKRATE = 1;
+#define CPGEN_SPAWN_OFFSET ('0 0 1' * (PL_MAX_CONST.z - 13))
+const vector CPGEN_WAYPOINT_OFFSET = ('0 0 128');
+const vector CPICON_OFFSET = ('0 0 96');
+
+// list of generators on the map
+entity ons_worldgeneratorlist;
+.entity ons_worldgeneratornext;
+.entity ons_stalegeneratornext;
+
+// list of control points on the map
+entity ons_worldcplist;
+.entity ons_worldcpnext;
+.entity ons_stalecpnext;
+
+// list of links on the map
+entity ons_worldlinklist;
+.entity ons_worldlinknext;
+.entity ons_stalelinknext;
+
+// definitions
+.entity sprite;
+.string target2;
+.int iscaptured;
+.int islinked;
+.int isshielded;
+.float lasthealth;
+.int lastteam;
+.int lastshielded;
+.int lastcaptured;
+
+.bool waslinked;
+
+bool ons_stalemate;
+
+.float teleport_antispam;
+
+.bool ons_roundlost;
+
+// waypoint sprites
+.entity bot_basewaypoint; // generator waypointsprite
+
+.bool isgenneighbor[17];
+.bool iscpneighbor[17];
+float ons_notification_time[17];
+
+.float ons_overtime_damagedelay;
+
+.vector ons_deathloc;
+
+.entity ons_spawn_by;
+
+// declarations for functions used outside gamemode_onslaught.qc
+void ons_Generator_UpdateSprite(entity e);
+void ons_ControlPoint_UpdateSprite(entity e);
+bool ons_ControlPoint_Attackable(entity cp, int teamnumber);
+
+// CaptureShield: Prevent capturing or destroying control point/generator if it is not available yet
+float ons_captureshield_force; // push force of the shield
+
+// bot player logic
+const int HAVOCBOT_ONS_ROLE_NONE = 0;
+const int HAVOCBOT_ONS_ROLE_DEFENSE = 2;
+const int HAVOCBOT_ONS_ROLE_ASSISTANT = 4;
+const int HAVOCBOT_ONS_ROLE_OFFENSE = 8;
+
+.entity havocbot_ons_target;
+
+.int havocbot_role_flags;
+.float havocbot_attack_time;
+
+void havocbot_role_ons_defense();
+void havocbot_role_ons_offense();
+void havocbot_role_ons_assistant();
+
+void havocbot_ons_reset_role(entity bot);
+void havocbot_goalrating_items(float ratingscale, vector org, float sradius);
+void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius);
+
+// score rule declarations
+const int ST_ONS_CAPS = 1;
+const int SP_ONS_CAPS = 4;
+const int SP_ONS_TAKES = 6;
+
+#endif
+#endif
+
+#ifdef IMPLEMENTATION
+
+#include "sv_controlpoint.qh"
+#include "sv_generator.qh"
+
+bool g_onslaught;
+
+float autocvar_g_onslaught_debug;
+float autocvar_g_onslaught_teleport_wait;
+bool autocvar_g_onslaught_spawn_at_controlpoints;
+bool autocvar_g_onslaught_spawn_at_generator;
+float autocvar_g_onslaught_cp_proxydecap;
+float autocvar_g_onslaught_cp_proxydecap_distance = 512;
+float autocvar_g_onslaught_cp_proxydecap_dps = 100;
+float autocvar_g_onslaught_spawn_at_controlpoints_chance = 0.5;
+float autocvar_g_onslaught_spawn_at_controlpoints_random;
+float autocvar_g_onslaught_spawn_at_generator_chance;
+float autocvar_g_onslaught_spawn_at_generator_random;
+float autocvar_g_onslaught_cp_buildhealth;
+float autocvar_g_onslaught_cp_buildtime;
+float autocvar_g_onslaught_cp_health;
+float autocvar_g_onslaught_cp_regen;
+float autocvar_g_onslaught_gen_health;
+float autocvar_g_onslaught_shield_force = 100;
+float autocvar_g_onslaught_allow_vehicle_touch;
+float autocvar_g_onslaught_round_timelimit;
+float autocvar_g_onslaught_warmup;
+float autocvar_g_onslaught_teleport_radius;
+float autocvar_g_onslaught_spawn_choose;
+float autocvar_g_onslaught_click_radius;
+
+void FixSize(entity e);
+
+// =======================
+// CaptureShield Functions
+// =======================
+
+bool ons_CaptureShield_Customize()
+{SELFPARAM();
+ entity e = WaypointSprite_getviewentity(other);
+
+ if(!self.enemy.isshielded && (ons_ControlPoint_Attackable(self.enemy, e.team) > 0 || self.enemy.classname != "onslaught_controlpoint")) { return false; }
+ if(SAME_TEAM(self, e)) { return false; }
+
+ return true;
+}
+
+void ons_CaptureShield_Touch()
+{SELFPARAM();
+ if(!self.enemy.isshielded && (ons_ControlPoint_Attackable(self.enemy, other.team) > 0 || self.enemy.classname != "onslaught_controlpoint")) { return; }
+ if(!IS_PLAYER(other)) { return; }
+ if(SAME_TEAM(other, self)) { return; }
+
+ vector mymid = (self.absmin + self.absmax) * 0.5;
+ vector othermid = (other.absmin + other.absmax) * 0.5;
+
+ Damage(other, self, self, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(othermid - mymid) * ons_captureshield_force);
+
+ if(IS_REAL_CLIENT(other))
+ {
+ play2(other, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
+
+ if(self.enemy.classname == "onslaught_generator")
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_GENERATOR_SHIELDED);
+ else
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_CONTROLPOINT_SHIELDED);
+ }
+}
+
+void ons_CaptureShield_Reset()
+{SELFPARAM();
+ self.colormap = self.enemy.colormap;
+ self.team = self.enemy.team;
+}
+
+void ons_CaptureShield_Spawn(entity generator, bool is_generator)
+{
+ entity shield = new(ons_captureshield);
+
+ shield.enemy = generator;
+ shield.team = generator.team;
+ shield.colormap = generator.colormap;
+ shield.reset = ons_CaptureShield_Reset;
+ shield.touch = ons_CaptureShield_Touch;
+ shield.customizeentityforclient = ons_CaptureShield_Customize;
+ shield.effects = EF_ADDITIVE;
+ shield.movetype = MOVETYPE_NOCLIP;
+ shield.solid = SOLID_TRIGGER;
+ shield.avelocity = '7 0 11';
+ shield.scale = 1;
+ shield.model = ((is_generator) ? "models/onslaught/generator_shield.md3" : "models/onslaught/controlpoint_shield.md3");
+
+ precache_model(shield.model);
+ setorigin(shield, generator.origin);
+ _setmodel(shield, shield.model);
+ setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
+}
+
+
+// ==========
+// Junk Pile
+// ==========
+
+void ons_debug(string input)
+{
+ switch(autocvar_g_onslaught_debug)
+ {
+ case 1: LOG_TRACE(input); break;
+ case 2: LOG_INFO(input); break;
+ }
+}
+
+void setmodel_fixsize(entity e, Model m)
+{
+ setmodel(e, m);
+ FixSize(e);
+}
+
+void onslaught_updatelinks()
+{
+ entity l;
+ // first check if the game has ended
+ ons_debug("--- updatelinks ---\n");
+ // mark generators as being shielded and networked
+ for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+ {
+ if (l.iscaptured)
+ ons_debug(strcat(etos(l), " (generator) belongs to team ", ftos(l.team), "\n"));
+ else
+ ons_debug(strcat(etos(l), " (generator) is destroyed\n"));
+ l.islinked = l.iscaptured;
+ l.isshielded = l.iscaptured;
+ l.sprite.SendFlags |= 16;
+ }
+ // mark points as shielded and not networked
+ for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+ {
+ l.islinked = false;
+ l.isshielded = true;
+ int i;
+ for(i = 0; i < 17; ++i) { l.isgenneighbor[i] = false; l.iscpneighbor[i] = false; }
+ ons_debug(strcat(etos(l), " (point) belongs to team ", ftos(l.team), "\n"));
+ l.sprite.SendFlags |= 16;
+ }
+ // flow power outward from the generators through the network
+ bool stop = false;
+ while (!stop)
+ {
+ stop = true;
+ for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
+ {
+ // if both points are captured by the same team, and only one of
+ // them is powered, mark the other one as powered as well
+ if (l.enemy.iscaptured && l.goalentity.iscaptured)
+ if (l.enemy.islinked != l.goalentity.islinked)
+ if(SAME_TEAM(l.enemy, l.goalentity))
+ {
+ if (!l.goalentity.islinked)
+ {
+ stop = false;
+ l.goalentity.islinked = true;
+ ons_debug(strcat(etos(l), " (link) is marking ", etos(l.goalentity), " (point) because its team matches ", etos(l.enemy), " (point)\n"));
+ }
+ else if (!l.enemy.islinked)
+ {
+ stop = false;
+ l.enemy.islinked = true;
+ ons_debug(strcat(etos(l), " (link) is marking ", etos(l.enemy), " (point) because its team matches ", etos(l.goalentity), " (point)\n"));
+ }
+ }
+ }
+ }
+ // now that we know which points are powered we can mark their neighbors
+ // as unshielded if team differs
+ for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
+ {
+ if (l.goalentity.islinked)
+ {
+ if(DIFF_TEAM(l.goalentity, l.enemy))
+ {
+ ons_debug(strcat(etos(l), " (link) is unshielding ", etos(l.enemy), " (point) because its team does not match ", etos(l.goalentity), " (point)\n"));
+ l.enemy.isshielded = false;
+ }
+ if(l.goalentity.classname == "onslaught_generator")
+ l.enemy.isgenneighbor[l.goalentity.team] = true;
+ else
+ l.enemy.iscpneighbor[l.goalentity.team] = true;
+ }
+ if (l.enemy.islinked)
+ {
+ if(DIFF_TEAM(l.goalentity, l.enemy))
+ {
+ ons_debug(strcat(etos(l), " (link) is unshielding ", etos(l.goalentity), " (point) because its team does not match ", etos(l.enemy), " (point)\n"));
+ l.goalentity.isshielded = false;
+ }
+ if(l.enemy.classname == "onslaught_generator")
+ l.goalentity.isgenneighbor[l.enemy.team] = true;
+ else
+ l.goalentity.iscpneighbor[l.enemy.team] = true;
+ }
+ }
+ // now update the generators
+ for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+ {
+ if (l.isshielded)
+ {
+ ons_debug(strcat(etos(l), " (generator) is shielded\n"));
+ l.takedamage = DAMAGE_NO;
+ l.bot_attack = false;
+ }
+ else
+ {
+ ons_debug(strcat(etos(l), " (generator) is not shielded\n"));
+ l.takedamage = DAMAGE_AIM;
+ l.bot_attack = true;
+ }
+
+ ons_Generator_UpdateSprite(l);
+ }
+ // now update the takedamage and alpha variables on control point icons
+ for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+ {
+ if (l.isshielded)
+ {
+ ons_debug(strcat(etos(l), " (point) is shielded\n"));
+ if (l.goalentity)
+ {
+ l.goalentity.takedamage = DAMAGE_NO;
+ l.goalentity.bot_attack = false;
+ }
+ }
+ else
+ {
+ ons_debug(strcat(etos(l), " (point) is not shielded\n"));
+ if (l.goalentity)
+ {
+ l.goalentity.takedamage = DAMAGE_AIM;
+ l.goalentity.bot_attack = true;
+ }
+ }
+ ons_ControlPoint_UpdateSprite(l);
+ }
+ l = findchain(classname, "ons_captureshield");
+ while(l)
+ {
+ l.team = l.enemy.team;
+ l.colormap = l.enemy.colormap;
+ l = l.chain;
+ }
+}
+
+
+// ===================
+// Main Link Functions
+// ===================
+
+bool ons_Link_Send(entity this, entity to, int sendflags)
+{
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_RADARLINK);
+ WriteByte(MSG_ENTITY, sendflags);
+ if(sendflags & 1)
+ {
+ WriteCoord(MSG_ENTITY, self.goalentity.origin_x);
+ WriteCoord(MSG_ENTITY, self.goalentity.origin_y);
+ WriteCoord(MSG_ENTITY, self.goalentity.origin_z);
+ }
+ if(sendflags & 2)
+ {
+ WriteCoord(MSG_ENTITY, self.enemy.origin_x);
+ WriteCoord(MSG_ENTITY, self.enemy.origin_y);
+ WriteCoord(MSG_ENTITY, self.enemy.origin_z);
+ }
+ if(sendflags & 4)
+ {
+ WriteByte(MSG_ENTITY, self.clientcolors); // which is goalentity's color + enemy's color * 16
+ }
+ return true;
+}
+
+void ons_Link_CheckUpdate()
+{SELFPARAM();
+ // TODO check if the two sides have moved (currently they won't move anyway)
+ float cc = 0, cc1 = 0, cc2 = 0;
+
+ if(self.goalentity.islinked || self.goalentity.iscaptured) { cc1 = (self.goalentity.team - 1) * 0x01; }
+ if(self.enemy.islinked || self.enemy.iscaptured) { cc2 = (self.enemy.team - 1) * 0x10; }
+
+ cc = cc1 + cc2;
+
+ if(cc != self.clientcolors)
+ {
+ self.clientcolors = cc;
+ self.SendFlags |= 4;
+ }
+
+ self.nextthink = time;
+}
+
+void ons_DelayedLinkSetup()
+{SELFPARAM();
+ self.goalentity = find(world, targetname, self.target);
+ self.enemy = find(world, targetname, self.target2);
+ if(!self.goalentity) { objerror("can not find target\n"); }
+ if(!self.enemy) { objerror("can not find target2\n"); }
+
+ ons_debug(strcat(etos(self.goalentity), " linked with ", etos(self.enemy), "\n"));
+ self.SendFlags |= 3;
+ self.think = ons_Link_CheckUpdate;
+ self.nextthink = time;
+}
+
+
+// =============================
+// Main Control Point Functions
+// =============================
+
+int ons_ControlPoint_CanBeLinked(entity cp, int teamnumber)
+{
+ if(cp.isgenneighbor[teamnumber]) { return 2; }
+ if(cp.iscpneighbor[teamnumber]) { return 1; }
+
+ return 0;
+}
+
+int ons_ControlPoint_Attackable(entity cp, int teamnumber)
+ // -2: SAME TEAM, attackable by enemy!
+ // -1: SAME TEAM!
+ // 0: off limits
+ // 1: attack it
+ // 2: touch it
+ // 3: attack it (HIGH PRIO)
+ // 4: touch it (HIGH PRIO)
+{
+ int a;
+
+ if(cp.isshielded)
+ {
+ return 0;
+ }
+ else if(cp.goalentity)
+ {
+ // if there's already an icon built, nothing happens
+ if(cp.team == teamnumber)
+ {
+ a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
+ if(a) // attackable by enemy?
+ return -2; // EMERGENCY!
+ return -1;
+ }
+ // we know it can be linked, so no need to check
+ // but...
+ a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
+ if(a == 2) // near our generator?
+ return 3; // EMERGENCY!
+ return 1;
+ }
+ else
+ {
+ // free point
+ if(ons_ControlPoint_CanBeLinked(cp, teamnumber))
+ {
+ a = ons_ControlPoint_CanBeLinked(cp, teamnumber); // why was this here NUM_TEAM_1 + NUM_TEAM_2 - t
+ if(a == 2)
+ return 4; // GET THIS ONE NOW!
+ else
+ return 2; // TOUCH ME
+ }
+ }
+ return 0;
+}
+
+void ons_ControlPoint_Icon_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+ if(damage <= 0) { return; }
+
+ if (self.owner.isshielded)
+ {
+ // this is protected by a shield, so ignore the damage
+ if (time > self.pain_finished)
+ if (IS_PLAYER(attacker))
+ {
+ play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
+ self.pain_finished = time + 1;
+ attacker.typehitsound += 1; // play both sounds (shield is way too quiet)
+ }
+
+ return;
+ }
+
+ if(IS_PLAYER(attacker))
+ if(time - ons_notification_time[self.team] > 10)
+ {
+ play2team(self.team, SND(ONS_CONTROLPOINT_UNDERATTACK));
+ ons_notification_time[self.team] = time;
+ }
+
+ self.health = self.health - damage;
+ if(self.owner.iscaptured)
+ WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
+ else
+ WaypointSprite_UpdateBuildFinished(self.owner.sprite, time + (self.max_health - self.health) / (self.count / ONS_CP_THINKRATE));
+ self.pain_finished = time + 1;
+ // particles on every hit
+ pointparticles(EFFECT_SPARKS, hitloc, force*-1, 1);
+ //sound on every hit
+ if (random() < 0.5)
+ sound(self, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE+0.3, ATTEN_NORM);
+ else
+ sound(self, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE+0.3, ATTEN_NORM);
+
+ if (self.health < 0)
+ {
+ sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
+ pointparticles(EFFECT_ROCKET_EXPLODE, self.origin, '0 0 0', 1);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_CPDESTROYED_), self.owner.message, attacker.netname);
+
+ PlayerScore_Add(attacker, SP_ONS_TAKES, 1);
+ PlayerScore_Add(attacker, SP_SCORE, 10);
+
+ self.owner.goalentity = world;
+ self.owner.islinked = false;
+ self.owner.iscaptured = false;
+ self.owner.team = 0;
+ self.owner.colormap = 1024;
+
+ WaypointSprite_UpdateMaxHealth(self.owner.sprite, 0);
+
+ onslaught_updatelinks();
+
+ // Use targets now (somebody make sure this is in the right place..)
+ setself(self.owner);
+ activator = self;
+ SUB_UseTargets ();
+ setself(this);
+
+ self.owner.waslinked = self.owner.islinked;
+ if(self.owner.model != "models/onslaught/controlpoint_pad.md3")
+ setmodel_fixsize(self.owner, MDL_ONS_CP_PAD1);
+ //setsize(self, '-32 -32 0', '32 32 8');
+
+ remove(self);
+ }
+
+ self.SendFlags |= CPSF_STATUS;
+}
+
+void ons_ControlPoint_Icon_Think()
+{SELFPARAM();
+ self.nextthink = time + ONS_CP_THINKRATE;
+
+ if(autocvar_g_onslaught_cp_proxydecap)
+ {
+ int _enemy_count = 0;
+ int _friendly_count = 0;
+ float _dist;
+ entity _player;
+
+ FOR_EACH_PLAYER(_player)
+ {
+ if(!_player.deadflag)
+ {
+ _dist = vlen(_player.origin - self.origin);
+ if(_dist < autocvar_g_onslaught_cp_proxydecap_distance)
+ {
+ if(SAME_TEAM(_player, self))
+ ++_friendly_count;
+ else
+ ++_enemy_count;
+ }
+ }
+ }
+
+ _friendly_count = _friendly_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
+ _enemy_count = _enemy_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
+
+ self.health = bound(0, self.health + (_friendly_count - _enemy_count), self.max_health);
+ self.SendFlags |= CPSF_STATUS;
+ if(self.health <= 0)
+ {
+ ons_ControlPoint_Icon_Damage(self, self, 1, 0, self.origin, '0 0 0');
+ return;
+ }
+ }
+
+ if (time > self.pain_finished + 5)
+ {
+ if(self.health < self.max_health)
+ {
+ self.health = self.health + self.count;
+ if (self.health >= self.max_health)
+ self.health = self.max_health;
+ WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
+ }
+ }
+
+ if(self.owner.islinked != self.owner.waslinked)
+ {
+ // unteam the spawnpoint if needed
+ int t = self.owner.team;
+ if(!self.owner.islinked)
+ self.owner.team = 0;
+
+ setself(self.owner);
+ activator = self;
+ SUB_UseTargets ();
+ setself(this);
+
+ self.owner.team = t;
+
+ self.owner.waslinked = self.owner.islinked;
+ }
+
+ // damaged fx
+ if(random() < 0.6 - self.health / self.max_health)
+ {
+ Send_Effect(EFFECT_ELECTRIC_SPARKS, self.origin + randompos('-10 -10 -20', '10 10 20'), '0 0 0', 1);
+
+ if(random() > 0.8)
+ sound(self, CH_PAIN, SND_ONS_SPARK1, VOL_BASE, ATTEN_NORM);
+ else if (random() > 0.5)
+ sound(self, CH_PAIN, SND_ONS_SPARK2, VOL_BASE, ATTEN_NORM);
+ }
+}
+
+void ons_ControlPoint_Icon_BuildThink()
+{SELFPARAM();
+ int a;
+
+ self.nextthink = time + ONS_CP_THINKRATE;
+
+ // only do this if there is power
+ a = ons_ControlPoint_CanBeLinked(self.owner, self.owner.team);
+ if(!a)
+ return;
+
+ self.health = self.health + self.count;
+
+ self.SendFlags |= CPSF_STATUS;
+
+ if (self.health >= self.max_health)
+ {
+ self.health = self.max_health;
+ self.count = autocvar_g_onslaught_cp_regen * ONS_CP_THINKRATE; // slow repair rate from now on
+ self.think = ons_ControlPoint_Icon_Think;
+ sound(self, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILT, VOL_BASE, ATTEN_NORM);
+ self.owner.iscaptured = true;
+ self.solid = SOLID_BBOX;
+
+ Send_Effect(EFFECT_CAP(self.owner.team), self.owner.origin, '0 0 0', 1);
+
+ WaypointSprite_UpdateMaxHealth(self.owner.sprite, self.max_health);
+ WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
+
+ if(IS_PLAYER(self.owner.ons_toucher))
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ONSLAUGHT_CAPTURE, self.owner.ons_toucher.netname, self.owner.message);
+ Send_Notification(NOTIF_ALL_EXCEPT, self.owner.ons_toucher, MSG_CENTER, APP_TEAM_ENT_4(self.owner.ons_toucher, CENTER_ONS_CAPTURE_), self.owner.message);
+ Send_Notification(NOTIF_ONE, self.owner.ons_toucher, MSG_CENTER, CENTER_ONS_CAPTURE, self.owner.message);
+ PlayerScore_Add(self.owner.ons_toucher, SP_ONS_CAPS, 1);
+ PlayerTeamScore_AddScore(self.owner.ons_toucher, 10);
+ }
+
+ self.owner.ons_toucher = world;
+
+ onslaught_updatelinks();
+
+ // Use targets now (somebody make sure this is in the right place..)
+ setself(self.owner);
+ activator = self;
+ SUB_UseTargets ();
+ setself(this);
+
+ self.SendFlags |= CPSF_SETUP;
+ }
+ if(self.owner.model != MDL_ONS_CP_PAD2.model_str())
+ setmodel_fixsize(self.owner, MDL_ONS_CP_PAD2);
+
+ if(random() < 0.9 - self.health / self.max_health)
+ Send_Effect(EFFECT_RAGE, self.origin + 10 * randomvec(), '0 0 -1', 1);
+}
+
+void onslaught_controlpoint_icon_link(entity e, void() spawnproc);
+
+void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
+{
+ entity e = new(onslaught_controlpoint_icon);
+
+ setsize(e, CPICON_MIN, CPICON_MAX);
+ setorigin(e, cp.origin + CPICON_OFFSET);
+
+ e.owner = cp;
+ e.max_health = autocvar_g_onslaught_cp_health;
+ e.health = autocvar_g_onslaught_cp_buildhealth;
+ e.solid = SOLID_NOT;
+ e.takedamage = DAMAGE_AIM;
+ e.bot_attack = true;
+ e.event_damage = ons_ControlPoint_Icon_Damage;
+ e.team = player.team;
+ e.colormap = 1024 + (e.team - 1) * 17;
+ e.count = (e.max_health - e.health) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
+
+ sound(e, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILD, VOL_BASE, ATTEN_NORM);
+
+ cp.goalentity = e;
+ cp.team = e.team;
+ cp.colormap = e.colormap;
+
+ Send_Effect(EFFECT_FLAG_TOUCH(player.team), e.origin, '0 0 0', 1);
+
+ WaypointSprite_UpdateBuildFinished(cp.sprite, time + (e.max_health - e.health) / (e.count / ONS_CP_THINKRATE));
+ WaypointSprite_UpdateRule(cp.sprite,cp.team,SPRITERULE_TEAMPLAY);
+ cp.sprite.SendFlags |= 16;
+
+ onslaught_controlpoint_icon_link(e, ons_ControlPoint_Icon_BuildThink);
+}
+
+entity ons_ControlPoint_Waypoint(entity e)
+{
+ if(e.team)
+ {
+ int a = ons_ControlPoint_Attackable(e, e.team);
+
+ if(a == -2) { return WP_OnsCPDefend; } // defend now
+ if(a == -1 || a == 1 || a == 2) { return WP_OnsCP; } // touch
+ if(a == 3 || a == 4) { return WP_OnsCPAttack; } // attack
+ }
+ else
+ return WP_OnsCP;
+
+ return WP_Null;
+}
+
+void ons_ControlPoint_UpdateSprite(entity e)
+{
+ entity s1 = ons_ControlPoint_Waypoint(e);
+ WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
+
+ bool sh;
+ sh = !(ons_ControlPoint_CanBeLinked(e, NUM_TEAM_1) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_2) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_3) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_4));
+
+ if(e.lastteam != e.team + 2 || e.lastshielded != sh || e.iscaptured != e.lastcaptured)
+ {
+ if(e.iscaptured) // don't mess up build bars!
+ {
+ if(sh)
+ {
+ WaypointSprite_UpdateMaxHealth(e.sprite, 0);
+ }
+ else
+ {
+ WaypointSprite_UpdateMaxHealth(e.sprite, e.goalentity.max_health);
+ WaypointSprite_UpdateHealth(e.sprite, e.goalentity.health);
+ }
+ }
+ if(e.lastshielded)
+ {
+ if(e.team)
+ WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, 0.5 * colormapPaletteColor(e.team - 1, false));
+ else
+ WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.5 0.5 0.5');
+ }
+ else
+ {
+ if(e.team)
+ WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, colormapPaletteColor(e.team - 1, false));
+ else
+ WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.75 0.75 0.75');
+ }
+ WaypointSprite_Ping(e.sprite);
+
+ e.lastteam = e.team + 2;
+ e.lastshielded = sh;
+ e.lastcaptured = e.iscaptured;
+ }
+}
+
+void ons_ControlPoint_Touch()
+{SELFPARAM();
+ entity toucher = other;
+ int attackable;
+
+ if(IS_VEHICLE(toucher) && toucher.owner)
+ if(autocvar_g_onslaught_allow_vehicle_touch)
+ toucher = toucher.owner;
+ else
+ return;
+
+ if(!IS_PLAYER(toucher)) { return; }
+ if(toucher.frozen) { return; }
+ if(toucher.deadflag != DEAD_NO) { return; }
+
+ if ( SAME_TEAM(self,toucher) )
+ if ( self.iscaptured )
+ {
+ if(time <= toucher.teleport_antispam)
+ Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT_ANTISPAM, rint(toucher.teleport_antispam - time));
+ else
+ Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT);
+ }
+
+ attackable = ons_ControlPoint_Attackable(self, toucher.team);
+ if(attackable != 2 && attackable != 4)
+ return;
+ // we've verified that this player has a legitimate claim to this point,
+ // so start building the captured point icon (which only captures this
+ // point if it successfully builds without being destroyed first)
+ ons_ControlPoint_Icon_Spawn(self, toucher);
+
+ self.ons_toucher = toucher;
+
+ onslaught_updatelinks();
+}
+
+void ons_ControlPoint_Think()
+{SELFPARAM();
+ self.nextthink = time + ONS_CP_THINKRATE;
+ CSQCMODEL_AUTOUPDATE(self);
+}
+
+void ons_ControlPoint_Reset()
+{SELFPARAM();
+ if(self.goalentity)
+ remove(self.goalentity);
+
+ self.goalentity = world;
+ self.team = 0;
+ self.colormap = 1024;
+ self.iscaptured = false;
+ self.islinked = false;
+ self.isshielded = true;
+ self.think = ons_ControlPoint_Think;
+ self.ons_toucher = world;
+ self.nextthink = time + ONS_CP_THINKRATE;
+ setmodel_fixsize(self, MDL_ONS_CP_PAD1);
+
+ WaypointSprite_UpdateMaxHealth(self.sprite, 0);
+ WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
+
+ onslaught_updatelinks();
+
+ activator = self;
+ SUB_UseTargets(); // to reset the structures, playerspawns etc.
+
+ CSQCMODEL_AUTOUPDATE(self);
+}
+
+void ons_DelayedControlPoint_Setup()
+{SELFPARAM();
+ onslaught_updatelinks();
+
+ // captureshield setup
+ ons_CaptureShield_Spawn(self, false);
+
+ CSQCMODEL_AUTOINIT(self);
+}
+
+void ons_ControlPoint_Setup(entity cp)
+{SELFPARAM();
+ // declarations
+ setself(cp); // for later usage with droptofloor()
+
+ // main setup
+ cp.ons_worldcpnext = ons_worldcplist; // link control point into ons_worldcplist
+ ons_worldcplist = cp;
+
+ cp.netname = "Control point";
+ cp.team = 0;
+ cp.solid = SOLID_BBOX;
+ cp.movetype = MOVETYPE_NONE;
+ cp.touch = ons_ControlPoint_Touch;
+ cp.think = ons_ControlPoint_Think;
+ cp.nextthink = time + ONS_CP_THINKRATE;
+ cp.reset = ons_ControlPoint_Reset;
+ cp.colormap = 1024;
+ cp.iscaptured = false;
+ cp.islinked = false;
+ cp.isshielded = true;
+
+ if(cp.message == "") { cp.message = "a"; }
+
+ // appearence
+ setmodel_fixsize(cp, MDL_ONS_CP_PAD1);
+
+ // control point placement
+ if((cp.spawnflags & 1) || cp.noalign) // don't drop to floor, just stay at fixed location
+ {
+ cp.noalign = true;
+ cp.movetype = MOVETYPE_NONE;
+ }
+ else // drop to floor, automatically find a platform and set that as spawn origin
+ {
+ setorigin(cp, cp.origin + '0 0 20');
+ cp.noalign = false;
+ setself(cp);
+ droptofloor();
+ cp.movetype = MOVETYPE_TOSS;
+ }
+
+ // waypointsprites
+ WaypointSprite_SpawnFixed(WP_Null, self.origin + CPGEN_WAYPOINT_OFFSET, self, sprite, RADARICON_NONE);
+ WaypointSprite_UpdateRule(self.sprite, self.team, SPRITERULE_TEAMPLAY);
+
+ InitializeEntity(cp, ons_DelayedControlPoint_Setup, INITPRIO_SETLOCATION);
+}
+
+
+// =========================
+// Main Generator Functions
+// =========================
+
+entity ons_Generator_Waypoint(entity e)
+{
+ if (e.isshielded)
+ return WP_OnsGenShielded;
+ return WP_OnsGen;
+}
+
+void ons_Generator_UpdateSprite(entity e)
+{
+ entity s1 = ons_Generator_Waypoint(e);
+ WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
+
+ if(e.lastteam != e.team + 2 || e.lastshielded != e.isshielded)
+ {
+ e.lastteam = e.team + 2;
+ e.lastshielded = e.isshielded;
+ if(e.lastshielded)
+ {
+ if(e.team)
+ WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, 0.5 * colormapPaletteColor(e.team - 1, false));
+ else
+ WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.5 0.5 0.5');
+ }
+ else
+ {
+ if(e.team)
+ WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, colormapPaletteColor(e.team - 1, false));
+ else
+ WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.75 0.75 0.75');
+ }
+ WaypointSprite_Ping(e.sprite);
+ }
+}
+
+void ons_GeneratorDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+ if(damage <= 0) { return; }
+ if(warmup_stage || gameover) { return; }
+ if(!round_handler_IsRoundStarted()) { return; }
+
+ if (attacker != self)
+ {
+ if (self.isshielded)
+ {
+ // this is protected by a shield, so ignore the damage
+ if (time > self.pain_finished)
+ if (IS_PLAYER(attacker))
+ {
+ play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
+ attacker.typehitsound += 1;
+ self.pain_finished = time + 1;
+ }
+ return;
+ }
+ if (time > self.pain_finished)
+ {
+ self.pain_finished = time + 10;
+ entity head;
+ FOR_EACH_REALPLAYER(head) if(SAME_TEAM(head, self)) { Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_GENERATOR_UNDERATTACK); }
+ play2team(self.team, SND(ONS_GENERATOR_UNDERATTACK));
+ }
+ }
+ self.health = self.health - damage;
+ WaypointSprite_UpdateHealth(self.sprite, self.health);
+ // choose an animation frame based on health
+ self.frame = 10 * bound(0, (1 - self.health / self.max_health), 1);
+ // see if the generator is still functional, or dying
+ if (self.health > 0)
+ {
+ self.lasthealth = self.health;
+ }
+ else
+ {
+ if (attacker == self)
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_GENDESTROYED_OVERTIME_));
+ else
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_GENDESTROYED_));
+ PlayerScore_Add(attacker, SP_SCORE, 100);
+ }
+ self.iscaptured = false;
+ self.islinked = false;
+ self.isshielded = false;
+ self.takedamage = DAMAGE_NO; // can't be hurt anymore
+ self.event_damage = func_null; // won't do anything if hurt
+ self.count = 0; // reset counter
+ self.think = func_null;
+ self.nextthink = 0;
+ //self.think(); // do the first explosion now
+
+ WaypointSprite_UpdateMaxHealth(self.sprite, 0);
+ WaypointSprite_Ping(self.sprite);
+ //WaypointSprite_Kill(self.sprite); // can't do this yet, code too poor
+
+ onslaught_updatelinks();
+ }
+
+ // Throw some flaming gibs on damage, more damage = more chance for gib
+ if(random() < damage/220)
+ {
+ sound(self, CH_TRIGGER, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+ }
+ else
+ {
+ // particles on every hit
+ Send_Effect(EFFECT_SPARKS, hitloc, force * -1, 1);
+
+ //sound on every hit
+ if (random() < 0.5)
+ sound(self, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE, ATTEN_NORM);
+ else
+ sound(self, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE, ATTEN_NORM);
+ }
+
+ self.SendFlags |= GSF_STATUS;
+}
+
+void ons_GeneratorThink()
+{SELFPARAM();
+ entity e;
+ self.nextthink = time + GEN_THINKRATE;
+ if (!gameover)
+ {
+ if(!self.isshielded && self.wait < time)
+ {
+ self.wait = time + 5;
+ FOR_EACH_REALPLAYER(e)
+ {
+ if(SAME_TEAM(e, self))
+ {
+ Send_Notification(NOTIF_ONE, e, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
+ soundto(MSG_ONE, e, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE); // FIXME: unique sound?
+ }
+ else
+ Send_Notification(NOTIF_ONE, e, MSG_CENTER, APP_TEAM_NUM_4(self.team, CENTER_ONS_NOTSHIELDED_));
+ }
+ }
+ }
+}
+
+void ons_GeneratorReset()
+{SELFPARAM();
+ self.team = self.team_saved;
+ self.lasthealth = self.max_health = self.health = autocvar_g_onslaught_gen_health;
+ self.takedamage = DAMAGE_AIM;
+ self.bot_attack = true;
+ self.iscaptured = true;
+ self.islinked = true;
+ self.isshielded = true;
+ self.event_damage = ons_GeneratorDamage;
+ self.think = ons_GeneratorThink;
+ self.nextthink = time + GEN_THINKRATE;
+
+ Net_LinkEntity(self, false, 0, generator_send);
+
+ self.SendFlags = GSF_SETUP; // just incase
+ self.SendFlags |= GSF_STATUS;
+
+ WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
+ WaypointSprite_UpdateHealth(self.sprite, self.health);
+ WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
+
+ onslaught_updatelinks();
+}
+
+void ons_DelayedGeneratorSetup()
+{SELFPARAM();
+ // bot waypoints
+ waypoint_spawnforitem_force(self, self.origin);
+ self.nearestwaypointtimeout = 0; // activate waypointing again
+ self.bot_basewaypoint = self.nearestwaypoint;
+
+ // captureshield setup
+ ons_CaptureShield_Spawn(self, true);
+
+ onslaught_updatelinks();
+
+ Net_LinkEntity(self, false, 0, generator_send);
+}
+
+
+void onslaught_generator_touch()
+{SELFPARAM();
+ if ( IS_PLAYER(other) )
+ if ( SAME_TEAM(self,other) )
+ if ( self.iscaptured )
+ {
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_TELEPORT);
+ }
+}
+
+void ons_GeneratorSetup(entity gen) // called when spawning a generator entity on the map as a spawnfunc
+{SELFPARAM();
+ // declarations
+ int teamnumber = gen.team;
+ setself(gen); // for later usage with droptofloor()
+
+ // main setup
+ gen.ons_worldgeneratornext = ons_worldgeneratorlist; // link generator into ons_worldgeneratorlist
+ ons_worldgeneratorlist = gen;
+
+ gen.netname = sprintf("%s generator", Team_ColoredFullName(teamnumber));
+ gen.classname = "onslaught_generator";
+ gen.solid = SOLID_BBOX;
+ gen.team_saved = teamnumber;
+ gen.movetype = MOVETYPE_NONE;
+ gen.lasthealth = gen.max_health = gen.health = autocvar_g_onslaught_gen_health;
+ gen.takedamage = DAMAGE_AIM;
+ gen.bot_attack = true;
+ gen.event_damage = ons_GeneratorDamage;
+ gen.reset = ons_GeneratorReset;
+ gen.think = ons_GeneratorThink;
+ gen.nextthink = time + GEN_THINKRATE;
+ gen.iscaptured = true;
+ gen.islinked = true;
+ gen.isshielded = true;
+ gen.touch = onslaught_generator_touch;
+
+ // appearence
+ // model handled by CSQC
+ setsize(gen, GENERATOR_MIN, GENERATOR_MAX);
+ setorigin(gen, (gen.origin + CPGEN_SPAWN_OFFSET));
+ gen.colormap = 1024 + (teamnumber - 1) * 17;
+
+ // generator placement
+ setself(gen);
+ droptofloor();
+
+ // waypointsprites
+ WaypointSprite_SpawnFixed(WP_Null, self.origin + CPGEN_WAYPOINT_OFFSET, self, sprite, RADARICON_NONE);
+ WaypointSprite_UpdateRule(self.sprite, self.team, SPRITERULE_TEAMPLAY);
+ WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
+ WaypointSprite_UpdateHealth(self.sprite, self.health);
+
+ InitializeEntity(gen, ons_DelayedGeneratorSetup, INITPRIO_SETLOCATION);
+}
+
+
+// ===============
+// Round Handler
+// ===============
+
+int total_generators;
+void Onslaught_count_generators()
+{
+ entity e;
+ total_generators = redowned = blueowned = yellowowned = pinkowned = 0;
+ for(e = ons_worldgeneratorlist; e; e = e.ons_worldgeneratornext)
+ {
+ ++total_generators;
+ redowned += (e.team == NUM_TEAM_1 && e.health > 0);
+ blueowned += (e.team == NUM_TEAM_2 && e.health > 0);
+ yellowowned += (e.team == NUM_TEAM_3 && e.health > 0);
+ pinkowned += (e.team == NUM_TEAM_4 && e.health > 0);
+ }
+}
+
+int Onslaught_GetWinnerTeam()
+{
+ int winner_team = 0;
+ if(redowned > 0)
+ winner_team = NUM_TEAM_1;
+ if(blueowned > 0)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_2;
+ }
+ if(yellowowned > 0)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_3;
+ }
+ if(pinkowned > 0)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_4;
+ }
+ if(winner_team)
+ return winner_team;
+ return -1; // no generators left?
+}
+
+void nades_Clear(entity e);
+
+#define ONS_OWNED_GENERATORS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
+#define ONS_OWNED_GENERATORS_OK() (ONS_OWNED_GENERATORS() > 1)
+bool Onslaught_CheckWinner()
+{
+ entity e;
+
+ if ((autocvar_timelimit && time > game_starttime + autocvar_timelimit * 60) || (round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0))
+ {
+ ons_stalemate = true;
+
+ if (!wpforenemy_announced)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT);
+ sound(world, CH_INFO, SND_ONS_GENERATOR_DECAY, VOL_BASE, ATTEN_NONE);
+
+ wpforenemy_announced = true;
+ }
+
+ entity tmp_entity; // temporary entity
+ float d;
+ for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext) if(time >= tmp_entity.ons_overtime_damagedelay)
+ {
+ // tmp_entity.max_health / 300 gives 5 minutes of overtime.
+ // control points reduce the overtime duration.
+ d = 1;
+ for(e = ons_worldcplist; e; e = e.ons_worldcpnext)
+ {
+ if(DIFF_TEAM(e, tmp_entity))
+ if(e.islinked)
+ d = d + 1;
+ }
+
+ if(autocvar_g_campaign && autocvar__campaign_testrun)
+ d = d * tmp_entity.max_health;
+ else
+ d = d * tmp_entity.max_health / max(30, 60 * autocvar_timelimit_suddendeath);
+
+ Damage(tmp_entity, tmp_entity, tmp_entity, d, DEATH_HURTTRIGGER.m_id, tmp_entity.origin, '0 0 0');
+
+ tmp_entity.sprite.SendFlags |= 16;
+
+ tmp_entity.ons_overtime_damagedelay = time + 1;
+ }
+ }
+ else { wpforenemy_announced = false; ons_stalemate = false; }
+
+ Onslaught_count_generators();
+
+ if(ONS_OWNED_GENERATORS_OK())
+ return 0;
+
+ int winner_team = Onslaught_GetWinnerTeam();
+
+ if(winner_team > 0)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner_team, CENTER_ROUND_TEAM_WIN_));
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner_team, INFO_ROUND_TEAM_WIN_));
+ TeamScore_AddToTeam(winner_team, ST_ONS_CAPS, +1);
+ }
+ else if(winner_team == -1)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
+ }
+
+ ons_stalemate = false;
+
+ play2all(SND(CTF_CAPTURE(winner_team)));
+
+ round_handler_Init(7, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
+
+ FOR_EACH_PLAYER(e)
+ {
+ e.ons_roundlost = true;
+ e.player_blocked = true;
+
+ nades_Clear(e);
+ }
+
+ return 1;
+}
+
+bool Onslaught_CheckPlayers()
+{
+ return 1;
+}
+
+void Onslaught_RoundStart()
+{
+ entity tmp_entity;
+ FOR_EACH_PLAYER(tmp_entity) { tmp_entity.player_blocked = false; }
+
+ for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
+ tmp_entity.sprite.SendFlags |= 16;
+
+ for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
+ tmp_entity.sprite.SendFlags |= 16;
+}
+
+
+// ================
+// Bot player logic
+// ================
+
+// NOTE: LEGACY CODE, needs to be re-written!
+
+void havocbot_goalrating_ons_offenseitems(float ratingscale, vector org, float sradius)
+{SELFPARAM();
+ entity head;
+ float t, c;
+ int i;
+ bool needarmor = false, needweapons = false;
+
+ // Needs armor/health?
+ if(self.health<100)
+ needarmor = true;
+
+ // Needs weapons?
+ c = 0;
+ for(i = WEP_FIRST; i <= WEP_LAST ; ++i)
+ {
+ // Find weapon
+ if(self.weapons & WepSet_FromWeapon(i))
+ if(++c>=4)
+ break;
+ }
+
+ if(c<4)
+ needweapons = true;
+
+ if(!needweapons && !needarmor)
+ return;
+
+ ons_debug(strcat(self.netname, " needs weapons ", ftos(needweapons) , "\n"));
+ ons_debug(strcat(self.netname, " needs armor ", ftos(needarmor) , "\n"));
+
+ // See what is around
+ head = findchainfloat(bot_pickup, true);
+ while (head)
+ {
+ // gather health and armor only
+ if (head.solid)
+ if ( ((head.health || head.armorvalue) && needarmor) || (head.weapons && needweapons ) )
+ if (vlen(head.origin - org) < sradius)
+ {
+ t = head.bot_pickupevalfunc(self, head);
+ if (t > 0)
+ navigation_routerating(head, t * ratingscale, 500);
+ }
+ head = head.chain;
+ }
+}
+
+void havocbot_role_ons_setrole(entity bot, int role)
+{
+ ons_debug(strcat(bot.netname," switched to "));
+ switch(role)
+ {
+ case HAVOCBOT_ONS_ROLE_DEFENSE:
+ ons_debug("defense");
+ bot.havocbot_role = havocbot_role_ons_defense;
+ bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
+ bot.havocbot_role_timeout = 0;
+ break;
+ case HAVOCBOT_ONS_ROLE_ASSISTANT:
+ ons_debug("assistant");
+ bot.havocbot_role = havocbot_role_ons_assistant;
+ bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
+ bot.havocbot_role_timeout = 0;
+ break;
+ case HAVOCBOT_ONS_ROLE_OFFENSE:
+ ons_debug("offense");
+ bot.havocbot_role = havocbot_role_ons_offense;
+ bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
+ bot.havocbot_role_timeout = 0;
+ break;
+ }
+ ons_debug("\n");
+}
+
+int havocbot_ons_teamcount(entity bot, int role)
+{SELFPARAM();
+ int c = 0;
+ entity head;
+
+ FOR_EACH_PLAYER(head)
+ if(SAME_TEAM(head, self))
+ if(head.havocbot_role_flags & role)
+ ++c;
+
+ return c;
+}
+
+void havocbot_goalrating_ons_controlpoints_attack(float ratingscale)
+{SELFPARAM();
+ entity cp, cp1, cp2, best, pl, wp;
+ float radius, bestvalue;
+ int c;
+ bool found;
+
+ // Filter control points
+ for(cp2 = ons_worldcplist; cp2; cp2 = cp2.ons_worldcpnext)
+ {
+ cp2.wpcost = c = 0;
+ cp2.wpconsidered = false;
+
+ if(cp2.isshielded)
+ continue;
+
+ // Ignore owned controlpoints
+ if(!(cp2.isgenneighbor[self.team] || cp2.iscpneighbor[self.team]))
+ continue;
+
+ // Count team mates interested in this control point
+ // (easier and cleaner than keeping counters per cp and teams)
+ FOR_EACH_PLAYER(pl)
+ if(SAME_TEAM(pl, self))
+ if(pl.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
+ if(pl.havocbot_ons_target==cp2)
+ ++c;
+
+ // NOTE: probably decrease the cost of attackable control points
+ cp2.wpcost = c;
+ cp2.wpconsidered = true;
+ }
+
+ // We'll consider only the best case
+ bestvalue = 99999999999;
+ cp = world;
+ for(cp1 = ons_worldcplist; cp1; cp1 = cp1.ons_worldcpnext)
+ {
+ if (!cp1.wpconsidered)
+ continue;
+
+ if(cp1.wpcost<bestvalue)
+ {
+ bestvalue = cp1.wpcost;
+ cp = cp1;
+ self.havocbot_ons_target = cp1;
+ }
+ }
+
+ if (!cp)
+ return;
+
+ ons_debug(strcat(self.netname, " chose cp ranked ", ftos(bestvalue), "\n"));
+
+ if(cp.goalentity)
+ {
+ // Should be attacked
+ // Rate waypoints near it
+ found = false;
+ best = world;
+ bestvalue = 99999999999;
+ for(radius=0; radius<1000 && !found; radius+=500)
+ {
+ for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
+ {
+ if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
+ if(wp.classname=="waypoint")
+ if(checkpvs(wp.origin,cp))
+ {
+ found = true;
+ if(wp.cnt<bestvalue)
+ {
+ best = wp;
+ bestvalue = wp.cnt;
+ }
+ }
+ }
+ }
+
+ if(best)
+ {
+ navigation_routerating(best, ratingscale, 10000);
+ best.cnt += 1;
+
+ self.havocbot_attack_time = 0;
+ if(checkpvs(self.view_ofs,cp))
+ if(checkpvs(self.view_ofs,best))
+ self.havocbot_attack_time = time + 2;
+ }
+ else
+ {
+ navigation_routerating(cp, ratingscale, 10000);
+ }
+ ons_debug(strcat(self.netname, " found an attackable controlpoint at ", vtos(cp.origin) ,"\n"));
+ }
+ else
+ {
+ // Should be touched
+ ons_debug(strcat(self.netname, " found a touchable controlpoint at ", vtos(cp.origin) ,"\n"));
+ found = false;
+
+ // Look for auto generated waypoint
+ if (!bot_waypoints_for_items)
+ for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
+ {
+ if(wp.classname=="waypoint")
+ {
+ navigation_routerating(wp, ratingscale, 10000);
+ found = true;
+ }
+ }
+
+ // Nothing found, rate the controlpoint itself
+ if (!found)
+ navigation_routerating(cp, ratingscale, 10000);
+ }
+}
+
+bool havocbot_goalrating_ons_generator_attack(float ratingscale)
+{SELFPARAM();
+ entity g, wp, bestwp;
+ bool found;
+ int best;
+
+ for(g = ons_worldgeneratorlist; g; g = g.ons_worldgeneratornext)
+ {
+ if(SAME_TEAM(g, self) || g.isshielded)
+ continue;
+
+ // Should be attacked
+ // Rate waypoints near it
+ found = false;
+ bestwp = world;
+ best = 99999999999;
+
+ for(wp=findradius(g.origin,400); wp; wp=wp.chain)
+ {
+ if(wp.classname=="waypoint")
+ if(checkpvs(wp.origin,g))
+ {
+ found = true;
+ if(wp.cnt<best)
+ {
+ bestwp = wp;
+ best = wp.cnt;
+ }
+ }
+ }
+
+ if(bestwp)
+ {
+ ons_debug("waypoints found around generator\n");
+ navigation_routerating(bestwp, ratingscale, 10000);
+ bestwp.cnt += 1;
+
+ self.havocbot_attack_time = 0;
+ if(checkpvs(self.view_ofs,g))
+ if(checkpvs(self.view_ofs,bestwp))
+ self.havocbot_attack_time = time + 5;
+
+ return true;
+ }
+ else
+ {
+ ons_debug("generator found without waypoints around\n");
+ // if there aren't waypoints near the generator go straight to it
+ navigation_routerating(g, ratingscale, 10000);
+ self.havocbot_attack_time = 0;
+ return true;
+ }
+ }
+ return false;
+}
+
+void havocbot_role_ons_offense()
+{SELFPARAM();
+ if(self.deadflag != DEAD_NO)
+ {
+ self.havocbot_attack_time = 0;
+ havocbot_ons_reset_role(self);
+ return;
+ }
+
+ // Set the role timeout if necessary
+ if (!self.havocbot_role_timeout)
+ self.havocbot_role_timeout = time + 120;
+
+ if (time > self.havocbot_role_timeout)
+ {
+ havocbot_ons_reset_role(self);
+ return;
+ }
+
+ if(self.havocbot_attack_time>time)
+ return;
+
+ if (self.bot_strategytime < time)
+ {
+ navigation_goalrating_start();
+ havocbot_goalrating_enemyplayers(20000, self.origin, 650);
+ if(!havocbot_goalrating_ons_generator_attack(20000))
+ havocbot_goalrating_ons_controlpoints_attack(20000);
+ havocbot_goalrating_ons_offenseitems(10000, self.origin, 10000);
+ navigation_goalrating_end();
+
+ self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ }
+}
+
+void havocbot_role_ons_assistant()
+{SELFPARAM();
+ havocbot_ons_reset_role(self);
+}
+
+void havocbot_role_ons_defense()
+{SELFPARAM();
+ havocbot_ons_reset_role(self);
+}
+
+void havocbot_ons_reset_role(entity bot)
+{SELFPARAM();
+ entity head;
+ int c = 0;
+
+ if(self.deadflag != DEAD_NO)
+ return;
+
+ bot.havocbot_ons_target = world;
+
+ // TODO: Defend control points or generator if necessary
+
+ // if there is only me on the team switch to offense
+ c = 0;
+ FOR_EACH_PLAYER(head)
+ if(SAME_TEAM(head, self))
+ ++c;
+
+ if(c==1)
+ {
+ havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
+ return;
+ }
+
+ havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
+}
+
+
+/*
+ * Find control point or generator owned by the same team self which is nearest to pos
+ * if max_dist is positive, only control points within this range will be considered
+ */
+entity ons_Nearest_ControlPoint(vector pos, float max_dist)
+{SELFPARAM();
+ entity tmp_entity, closest_target = world;
+ tmp_entity = findchain(classname, "onslaught_controlpoint");
+ while(tmp_entity)
+ {
+ if(SAME_TEAM(tmp_entity, self))
+ if(tmp_entity.iscaptured)
+ if(max_dist <= 0 || vlen(tmp_entity.origin - pos) <= max_dist)
+ if(vlen(tmp_entity.origin - pos) <= vlen(closest_target.origin - pos) || closest_target == world)
+ closest_target = tmp_entity;
+ tmp_entity = tmp_entity.chain;
+ }
+ tmp_entity = findchain(classname, "onslaught_generator");
+ while(tmp_entity)
+ {
+ if(SAME_TEAM(tmp_entity, self))
+ if(max_dist <= 0 || vlen(tmp_entity.origin - pos) < max_dist)
+ if(vlen(tmp_entity.origin - pos) <= vlen(closest_target.origin - pos) || closest_target == world)
+ closest_target = tmp_entity;
+ tmp_entity = tmp_entity.chain;
+ }
+
+ return closest_target;
+}
+
+/*
+ * Find control point or generator owned by the same team self which is nearest to pos
+ * if max_dist is positive, only control points within this range will be considered
+ * This function only check distances on the XY plane, disregarding Z
+ */
+entity ons_Nearest_ControlPoint_2D(vector pos, float max_dist)
+{SELFPARAM();
+ entity tmp_entity, closest_target = world;
+ vector delta;
+ float smallest_distance = 0, distance;
+
+ tmp_entity = findchain(classname, "onslaught_controlpoint");
+ while(tmp_entity)
+ {
+ delta = tmp_entity.origin - pos;
+ delta_z = 0;
+ distance = vlen(delta);
+
+ if(SAME_TEAM(tmp_entity, self))
+ if(tmp_entity.iscaptured)
+ if(max_dist <= 0 || distance <= max_dist)
+ if(closest_target == world || distance <= smallest_distance )
+ {
+ closest_target = tmp_entity;
+ smallest_distance = distance;
+ }
+
+ tmp_entity = tmp_entity.chain;
+ }
+ tmp_entity = findchain(classname, "onslaught_generator");
+ while(tmp_entity)
+ {
+ delta = tmp_entity.origin - pos;
+ delta_z = 0;
+ distance = vlen(delta);
+
+ if(SAME_TEAM(tmp_entity, self))
+ if(max_dist <= 0 || distance <= max_dist)
+ if(closest_target == world || distance <= smallest_distance )
+ {
+ closest_target = tmp_entity;
+ smallest_distance = distance;
+ }
+
+ tmp_entity = tmp_entity.chain;
+ }
+
+ return closest_target;
+}
+/**
+ * find the number of control points and generators in the same team as self
+ */
+int ons_Count_SelfControlPoints()
+{SELFPARAM();
+ entity tmp_entity;
+ tmp_entity = findchain(classname, "onslaught_controlpoint");
+ int n = 0;
+ while(tmp_entity)
+ {
+ if(SAME_TEAM(tmp_entity, self))
+ if(tmp_entity.iscaptured)
+ n++;
+ tmp_entity = tmp_entity.chain;
+ }
+ tmp_entity = findchain(classname, "onslaught_generator");
+ while(tmp_entity)
+ {
+ if(SAME_TEAM(tmp_entity, self))
+ n++;
+ tmp_entity = tmp_entity.chain;
+ }
+ return n;
+}
+
+/**
+ * Teleport player to a random position near tele_target
+ * if tele_effects is true, teleport sound+particles are created
+ * return false on failure
+ */
+bool ons_Teleport(entity player, entity tele_target, float range, bool tele_effects)
+{
+ if ( !tele_target )
+ return false;
+
+ int i;
+ vector loc;
+ float theta;
+ // narrow the range for each iteration to increase chances that a spawnpoint
+ // can be found even if there's little room around the control point
+ float iteration_scale = 1;
+ for(i = 0; i < 16; ++i)
+ {
+ iteration_scale -= i / 16;
+ theta = random() * 2 * M_PI;
+ loc_y = sin(theta);
+ loc_x = cos(theta);
+ loc_z = 0;
+ loc *= random() * range * iteration_scale;
+
+ loc += tele_target.origin + '0 0 128' * iteration_scale;
+
+ tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, player);
+ if(trace_fraction == 1.0 && !trace_startsolid)
+ {
+ traceline(tele_target.origin, loc, MOVE_NOMONSTERS, tele_target); // double check to make sure we're not spawning outside the world
+ if(trace_fraction == 1.0 && !trace_startsolid)
+ {
+ if ( tele_effects )
+ {
+ Send_Effect(EFFECT_TELEPORT, player.origin, '0 0 0', 1);
+ sound (player, CH_TRIGGER, SND_TELEPORT, VOL_BASE, ATTEN_NORM);
+ }
+ setorigin(player, loc);
+ player.angles = '0 1 0' * ( theta * RAD2DEG + 180 );
+ makevectors(player.angles);
+ player.fixangle = true;
+ player.teleport_antispam = time + autocvar_g_onslaught_teleport_wait;
+
+ if ( tele_effects )
+ Send_Effect(EFFECT_TELEPORT, player.origin + v_forward * 32, '0 0 0', 1);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// ==============
+// Hook Functions
+// ==============
+
+MUTATOR_HOOKFUNCTION(ons, reset_map_global)
+{SELFPARAM();
+ entity e;
+ FOR_EACH_PLAYER(e)
+ {
+ e.ons_roundlost = false;
+ e.ons_deathloc = '0 0 0';
+ WITH(entity, self, e, PutClientInServer());
+ }
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, ClientDisconnect)
+{SELFPARAM();
+ self.ons_deathloc = '0 0 0';
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, MakePlayerObserver)
+{SELFPARAM();
+ self.ons_deathloc = '0 0 0';
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayerSpawn)
+{SELFPARAM();
+ if(!round_handler_IsRoundStarted())
+ {
+ self.player_blocked = true;
+ return false;
+ }
+
+ entity l;
+ for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+ {
+ l.sprite.SendFlags |= 16;
+ }
+ for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+ {
+ l.sprite.SendFlags |= 16;
+ }
+
+ if(ons_stalemate) { Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT); }
+
+ if ( autocvar_g_onslaught_spawn_choose )
+ if ( self.ons_spawn_by )
+ if ( ons_Teleport(self,self.ons_spawn_by,autocvar_g_onslaught_teleport_radius,false) )
+ {
+ self.ons_spawn_by = world;
+ return false;
+ }
+
+ if(autocvar_g_onslaught_spawn_at_controlpoints)
+ if(random() <= autocvar_g_onslaught_spawn_at_controlpoints_chance)
+ {
+ float random_target = autocvar_g_onslaught_spawn_at_controlpoints_random;
+ entity tmp_entity, closest_target = world;
+ vector spawn_loc = self.ons_deathloc;
+
+ // new joining player or round reset, don't bother checking
+ if(spawn_loc == '0 0 0') { return false; }
+
+ if(random_target) { RandomSelection_Init(); }
+
+ for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
+ {
+ if(SAME_TEAM(tmp_entity, self))
+ if(random_target)
+ RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
+ else if(vlen(tmp_entity.origin - spawn_loc) <= vlen(closest_target.origin - spawn_loc) || closest_target == world)
+ closest_target = tmp_entity;
+ }
+
+ if(random_target) { closest_target = RandomSelection_chosen_ent; }
+
+ if(closest_target)
+ {
+ float i;
+ vector loc;
+ float iteration_scale = 1;
+ for(i = 0; i < 10; ++i)
+ {
+ iteration_scale -= i / 10;
+ loc = closest_target.origin + '0 0 96' * iteration_scale;
+ loc += ('0 1 0' * random()) * 128 * iteration_scale;
+ tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, self);
+ if(trace_fraction == 1.0 && !trace_startsolid)
+ {
+ traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the world
+ if(trace_fraction == 1.0 && !trace_startsolid)
+ {
+ setorigin(self, loc);
+ self.angles = normalize(loc - closest_target.origin) * RAD2DEG;
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if(autocvar_g_onslaught_spawn_at_generator)
+ if(random() <= autocvar_g_onslaught_spawn_at_generator_chance)
+ {
+ float random_target = autocvar_g_onslaught_spawn_at_generator_random;
+ entity tmp_entity, closest_target = world;
+ vector spawn_loc = self.ons_deathloc;
+
+ // new joining player or round reset, don't bother checking
+ if(spawn_loc == '0 0 0') { return false; }
+
+ if(random_target) { RandomSelection_Init(); }
+
+ for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
+ {
+ if(random_target)
+ RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
+ else
+ {
+ if(SAME_TEAM(tmp_entity, self))
+ if(vlen(tmp_entity.origin - spawn_loc) <= vlen(closest_target.origin - spawn_loc) || closest_target == world)
+ closest_target = tmp_entity;
+ }
+ }
+
+ if(random_target) { closest_target = RandomSelection_chosen_ent; }
+
+ if(closest_target)
+ {
+ float i;
+ vector loc;
+ float iteration_scale = 1;
+ for(i = 0; i < 10; ++i)
+ {
+ iteration_scale -= i / 10;
+ loc = closest_target.origin + '0 0 128' * iteration_scale;
+ loc += ('0 1 0' * random()) * 256 * iteration_scale;
+ tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, self);
+ if(trace_fraction == 1.0 && !trace_startsolid)
+ {
+ traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the world
+ if(trace_fraction == 1.0 && !trace_startsolid)
+ {
+ setorigin(self, loc);
+ self.angles = normalize(loc - closest_target.origin) * RAD2DEG;
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayerDies)
+{SELFPARAM();
+ frag_target.ons_deathloc = frag_target.origin;
+ entity l;
+ for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+ {
+ l.sprite.SendFlags |= 16;
+ }
+ for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+ {
+ l.sprite.SendFlags |= 16;
+ }
+
+ if ( autocvar_g_onslaught_spawn_choose )
+ if ( ons_Count_SelfControlPoints() > 1 )
+ stuffcmd(self, "qc_cmd_cl hud clickradar\n");
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, MonsterMove)
+{SELFPARAM();
+ entity e = find(world, targetname, self.target);
+ if (e != world)
+ self.team = e.team;
+
+ return false;
+}
+
+void ons_MonsterSpawn_Delayed()
+{SELFPARAM();
+ entity e, own = self.owner;
+
+ if(!own) { remove(self); return; }
+
+ if(own.targetname)
+ {
+ e = find(world, target, own.targetname);
+ if(e != world)
+ {
+ own.team = e.team;
+
+ activator = e;
+ own.use();
+ }
+ }
+
+ remove(self);
+}
+
+MUTATOR_HOOKFUNCTION(ons, MonsterSpawn)
+{SELFPARAM();
+ entity e = spawn();
+ e.owner = self;
+ InitializeEntity(e, ons_MonsterSpawn_Delayed, INITPRIO_FINDTARGET);
+
+ return false;
+}
+
+void ons_TurretSpawn_Delayed()
+{SELFPARAM();
+ entity e, own = self.owner;
+
+ if(!own) { remove(self); return; }
+
+ if(own.targetname)
+ {
+ e = find(world, target, own.targetname);
+ if(e != world)
+ {
+ own.team = e.team;
+ own.active = ACTIVE_NOT;
+
+ activator = e;
+ own.use();
+ }
+ }
+
+ remove(self);
+}
+
+MUTATOR_HOOKFUNCTION(ons, TurretSpawn)
+{SELFPARAM();
+ entity e = spawn();
+ e.owner = self;
+ InitializeEntity(e, ons_TurretSpawn_Delayed, INITPRIO_FINDTARGET);
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, HavocBot_ChooseRole)
+{SELFPARAM();
+ havocbot_ons_reset_role(self);
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ons, GetTeamCount)
+{
+ // onslaught is special
+ for(entity tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
+ {
+ switch(tmp_entity.team)
+ {
+ case NUM_TEAM_1: c1 = 0; break;
+ case NUM_TEAM_2: c2 = 0; break;
+ case NUM_TEAM_3: c3 = 0; break;
+ case NUM_TEAM_4: c4 = 0; break;
+ }
+ }
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ons, SpectateCopy)
+{SELFPARAM();
+ self.ons_roundlost = other.ons_roundlost; // make spectators see it too
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, SV_ParseClientCommand)
+{SELFPARAM();
+ if(MUTATOR_RETURNVALUE) // command was already handled?
+ return false;
+
+ if ( cmd_name == "ons_spawn" )
+ {
+ vector pos = self.origin;
+ if(cmd_argc > 1)
+ pos_x = stof(argv(1));
+ if(cmd_argc > 2)
+ pos_y = stof(argv(2));
+ if(cmd_argc > 3)
+ pos_z = stof(argv(3));
+
+ if ( IS_PLAYER(self) )
+ {
+ if ( !self.frozen )
+ {
+ entity source_point = ons_Nearest_ControlPoint(self.origin, autocvar_g_onslaught_teleport_radius);
+
+ if ( !source_point && self.health > 0 )
+ {
+ sprint(self, "\nYou need to be next to a control point\n");
+ return 1;
+ }
+
+
+ entity closest_target = ons_Nearest_ControlPoint_2D(pos, autocvar_g_onslaught_click_radius);
+
+ if ( closest_target == world )
+ {
+ sprint(self, "\nNo control point found\n");
+ return 1;
+ }
+
+ if ( self.health <= 0 )
+ {
+ self.ons_spawn_by = closest_target;
+ self.respawn_flags = self.respawn_flags | RESPAWN_FORCE;
+ }
+ else
+ {
+ if ( source_point == closest_target )
+ {
+ sprint(self, "\nTeleporting to the same point\n");
+ return 1;
+ }
+
+ if ( !ons_Teleport(self,closest_target,autocvar_g_onslaught_teleport_radius,true) )
+ sprint(self, "\nUnable to teleport there\n");
+ }
+
+ return 1;
+ }
+
+ sprint(self, "\nNo teleportation for you\n");
+ }
+
+ return 1;
+ }
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayerUseKey)
+{SELFPARAM();
+ if(MUTATOR_RETURNVALUE || gameover) { return false; }
+
+ if((time > self.teleport_antispam) && (self.deadflag == DEAD_NO) && !self.vehicle)
+ {
+ entity source_point = ons_Nearest_ControlPoint(self.origin, autocvar_g_onslaught_teleport_radius);
+ if ( source_point )
+ {
+ stuffcmd(self, "qc_cmd_cl hud clickradar\n");
+ return true;
+ }
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayHitsound)
+{
+ return (frag_victim.classname == "onslaught_generator" && !frag_victim.isshielded)
+ || (frag_victim.classname == "onslaught_controlpoint_icon" && !frag_victim.owner.isshielded);
+}
+
+MUTATOR_HOOKFUNCTION(ons, SendWaypoint)
+{
+ if(wp_sendflags & 16)
+ {
+ if(self.owner.classname == "onslaught_controlpoint")
+ {
+ entity wp_owner = self.owner;
+ entity e = WaypointSprite_getviewentity(wp_sendto);
+ if(SAME_TEAM(e, wp_owner) && wp_owner.goalentity.health >= wp_owner.goalentity.max_health) { wp_flag |= 2; }
+ if(!ons_ControlPoint_Attackable(wp_owner, e.team)) { wp_flag |= 2; }
+ }
+ if(self.owner.classname == "onslaught_generator")
+ {
+ entity wp_owner = self.owner;
+ if(wp_owner.isshielded && wp_owner.health >= wp_owner.max_health) { wp_flag |= 2; }
+ if(wp_owner.health <= 0) { wp_flag |= 2; }
+ }
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, TurretValidateTarget)
+{
+ if(substring(turret_target.classname, 0, 10) == "onslaught_") // don't attack onslaught targets, that's the player's job!
+ {
+ ret_float = -3;
+ return true;
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, TurretThink)
+{
+ // ONS uses somewhat backwards linking.
+ if(self.target)
+ {
+ entity e = find(world, targetname, self.target);
+ if (e != world)
+ self.team = e.team;
+ }
+
+ if(self.team != self.tur_head.team)
+ turret_respawn();
+
+ return false;
+}
+
+
+// ==========
+// Spawnfuncs
+// ==========
+
+/*QUAKED spawnfunc_onslaught_link (0 .5 .8) (-16 -16 -16) (16 16 16)
+ Link between control points.
+
+ This entity targets two different spawnfunc_onslaught_controlpoint or spawnfunc_onslaught_generator entities, and suppresses shielding on both if they are owned by different teams.
+
+keys:
+"target" - first control point.
+"target2" - second control point.
+ */
+spawnfunc(onslaught_link)
+{
+ if(!g_onslaught) { remove(self); return; }
+
+ if (self.target == "" || self.target2 == "")
+ objerror("target and target2 must be set\n");
+
+ self.ons_worldlinknext = ons_worldlinklist; // link into ons_worldlinklist
+ ons_worldlinklist = self;
+
+ InitializeEntity(self, ons_DelayedLinkSetup, INITPRIO_FINDTARGET);
+ Net_LinkEntity(self, false, 0, ons_Link_Send);
+}
+
+/*QUAKED spawnfunc_onslaught_controlpoint (0 .5 .8) (-32 -32 0) (32 32 128)
+ Control point. Be sure to give this enough clearance so that the shootable part has room to exist
+
+ This should link to an spawnfunc_onslaught_controlpoint entity or spawnfunc_onslaught_generator entity.
+
+keys:
+"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
+"target" - target any entities that are tied to this control point, such as vehicles and buildable structure entities.
+"message" - name of this control point (should reflect the location in the map, such as "center bridge", "north tower", etc)
+ */
+
+spawnfunc(onslaught_controlpoint)
+{
+ if(!g_onslaught) { remove(self); return; }
+
+ ons_ControlPoint_Setup(self);
+}
+
+/*QUAKED spawnfunc_onslaught_generator (0 .5 .8) (-32 -32 -24) (32 32 64)
+ Base generator.
+
+ spawnfunc_onslaught_link entities can target this.
+
+keys:
+"team" - team that owns this generator (5 = red, 14 = blue, etc), MUST BE SET.
+"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
+ */
+spawnfunc(onslaught_generator)
+{
+ if(!g_onslaught) { remove(self); return; }
+ if(!self.team) { objerror("team must be set"); }
+
+ ons_GeneratorSetup(self);
+}
+
+// scoreboard setup
+void ons_ScoreRules()
+{
+ CheckAllowedTeams(world);
+ ScoreRules_basics(((c4>=0) ? 4 : (c3>=0) ? 3 : 2), SFL_SORT_PRIO_PRIMARY, 0, true);
+ ScoreInfo_SetLabel_TeamScore (ST_ONS_CAPS, "destroyed", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_ONS_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_ONS_TAKES, "takes", 0);
+ ScoreRules_basics_end();
+}
+
+void ons_DelayedInit() // Do this check with a delay so we can wait for teams to be set up
+{
+ ons_ScoreRules();
+
+ round_handler_Spawn(Onslaught_CheckPlayers, Onslaught_CheckWinner, Onslaught_RoundStart);
+ round_handler_Init(5, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
+}
+
+void ons_Initialize()
+{
+ g_onslaught = true;
+ ons_captureshield_force = autocvar_g_onslaught_shield_force;
+
+ addstat(STAT_ROUNDLOST, AS_INT, ons_roundlost);
+
+ InitializeEntity(world, ons_DelayedInit, INITPRIO_GAMETYPE);
+}
+
+#endif
--- /dev/null
+#include "sv_controlpoint.qh"
+
+.bool iscaptured;
+
+bool cpicon_send(entity this, entity to, int sf)
+{
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_CONTROLPOINT_ICON);
+ WriteByte(MSG_ENTITY, sf);
+ if(sf & CPSF_SETUP)
+ {
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+
+ WriteByte(MSG_ENTITY, self.health);
+ WriteByte(MSG_ENTITY, self.max_health);
+ WriteByte(MSG_ENTITY, self.count);
+ WriteByte(MSG_ENTITY, self.team);
+ WriteByte(MSG_ENTITY, self.owner.iscaptured);
+ }
+
+ if(sf & CPSF_STATUS)
+ {
+ WriteByte(MSG_ENTITY, self.team);
+
+ if(self.health <= 0)
+ WriteByte(MSG_ENTITY, 0);
+ else
+ WriteByte(MSG_ENTITY, ceil((self.health / self.max_health) * 255));
+ }
+
+ return true;
+}
+
+void onslaught_controlpoint_icon_link(entity e, void() spawnproc)
+{
+ Net_LinkEntity(e, true, 0, cpicon_send);
+ e.think = spawnproc;
+ e.nextthink = time * sys_frametime;
+}
--- /dev/null
+#ifndef CONTROLPOINT_H
+#define CONTROLPOINT_H
+
+const vector CPICON_MIN = '-32 -32 -9';
+const vector CPICON_MAX = '32 32 25';
+
+const int CPSF_STATUS = 4;
+const int CPSF_SETUP = 8;
+
+#endif
--- /dev/null
+#include "sv_generator.qh"
+
+bool generator_send(entity this, entity to, int sf)
+{
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_GENERATOR);
+ WriteByte(MSG_ENTITY, sf);
+ if(sf & GSF_SETUP)
+ {
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+
+ WriteByte(MSG_ENTITY, self.health);
+ WriteByte(MSG_ENTITY, self.max_health);
+ WriteByte(MSG_ENTITY, self.count);
+ WriteByte(MSG_ENTITY, self.team);
+ }
+
+ if(sf & GSF_STATUS)
+ {
+ WriteByte(MSG_ENTITY, self.team);
+
+ if(self.health <= 0)
+ WriteByte(MSG_ENTITY, 0);
+ else
+ WriteByte(MSG_ENTITY, ceil((self.health / self.max_health) * 255));
+ }
+
+ return true;
+}
+
+void generator_link(void() spawnproc)
+{SELFPARAM();
+ Net_LinkEntity(self, true, 0, generator_send);
+ self.think = spawnproc;
+ self.nextthink = time;
+}
--- /dev/null
+#ifndef GENERATOR_H
+#define GENERATOR_H
+const vector GENERATOR_MIN = '-52 -52 -14';
+const vector GENERATOR_MAX = '52 52 75';
+
+const int GSF_STATUS = 4;
+const int GSF_SETUP = 8;
+
+bool generator_send(entity this, entity to, int sf);
+#endif
#include "item.qh"
-REGISTRY(Items, BIT(5))
-REGISTER_REGISTRY(RegisterItems)
+REGISTRY(Items, BITS(5))
+#define Items_from(i) _Items_from(i, NULL)
+REGISTER_REGISTRY(Items)
/** If you register a new item, make sure to add it to all.inc */
-#define REGISTER_ITEM(id, class) REGISTER(RegisterItems, ITEM, Items, id, m_id, NEW(class))
+#define REGISTER_ITEM(id, class) REGISTER(Items, ITEM, id, m_id, NEW(class))
-REGISTRY_SORT(Items, m_name, 0)
+REGISTRY_SORT(Items, 0)
+REGISTRY_CHECK(Items)
STATIC_INIT(Items) { FOREACH(Items, true, LAMBDA(it.m_id = i)); }
void Dump_Items();
#endif
#endif
-
-#include "inventory.qh"
/** Player inventory; Inventories also have one inventory for storing the previous state */
.Inventory inventory;
+REGISTER_NET_LINKED(ENT_CLIENT_INVENTORY)
+
#ifdef CSQC
-void Inventory_Read(Inventory data)
+NET_HANDLE(ENT_CLIENT_INVENTORY, bool isnew)
{
+ make_pure(this);
const int bits = ReadInt24_t();
FOREACH(Items, bits & BIT(it.m_id), LAMBDA(
.int fld = inv_items[it.m_id];
- int prev = data.(fld);
- int next = data.(fld) = ReadByte();
+ int prev = this.(fld);
+ int next = this.(fld) = ReadByte();
LOG_TRACEF("%s: %.0f -> %.0f\n", it.m_name, prev, next);
));
+ return true;
}
#endif
#ifdef SVQC
bool Inventory_Send(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_INVENTORY);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_INVENTORY);
entity e = self.owner;
if (IS_SPEC(e)) e = e.enemy;
Inventory data = e.inventory;
void Inventory_new(entity e)
{
Inventory inv = new(Inventory), bak = new(Inventory);
- inv.classname = "inventory", bak.classname = "inventory";
+ make_pure(inv); make_pure(bak);
inv.inventory = bak;
inv.drawonlytoclient = e;
Net_LinkEntity((inv.owner = e).inventory = inv, false, 0, Inventory_Send);
#ifndef MENUQC
MODEL(ArmorSmall_ITEM, Item_Model("item_armor_small.md3"));
+SOUND(ArmorSmall, "misc/armor1");
#endif
REGISTER_ITEM(ArmorSmall, Armor) {
#ifndef MENUQC
this.m_model = MDL_ArmorSmall_ITEM;
+ this.m_sound = SND_ArmorSmall;
#endif
- this.m_sound = "misc/armor1.wav";
this.m_name = "5 Armor";
this.m_icon = "armor";
#ifdef SVQC
#ifndef MENUQC
MODEL(ArmorMedium_ITEM, Item_Model("item_armor_medium.md3"));
+SOUND(ArmorMedium, "misc/armor10");
#endif
REGISTER_ITEM(ArmorMedium, Armor) {
#ifndef MENUQC
this.m_model = MDL_ArmorMedium_ITEM;
+ this.m_sound = SND_ArmorMedium;
#endif
- this.m_sound = "misc/armor10.wav";
this.m_name = "25 Armor";
this.m_icon = "armor";
#ifdef SVQC
#ifndef MENUQC
MODEL(ArmorLarge_ITEM, Item_Model("item_armor_big.md3"));
+SOUND(ArmorLarge, "misc/armor17_5");
#endif
REGISTER_ITEM(ArmorLarge, Armor) {
#ifndef MENUQC
this.m_model = MDL_ArmorLarge_ITEM;
+ this.m_sound = SND_ArmorLarge;
#endif
- this.m_sound = "misc/armor17_5.wav";
this.m_name = "50 Armor";
this.m_icon = "armor";
this.m_color = '0 1 0';
#ifndef MENUQC
MODEL(ArmorMega_ITEM, Item_Model("item_armor_large.md3"));
+SOUND(ArmorMega, "misc/armor25");
#endif
REGISTER_ITEM(ArmorMega, Armor) {
#ifndef MENUQC
this.m_model = MDL_ArmorMega_ITEM;
+ this.m_sound = SND_ArmorMega;
#endif
- this.m_sound = "misc/armor25.wav";
this.m_name = "100 Armor";
this.m_icon = "item_large_armor";
this.m_color = '0 1 0';
#include "pickup.qh"
CLASS(Armor, Pickup)
#ifdef SVQC
+ ATTRIB(Armor, m_mins, vector, '-16 -16 0')
+ ATTRIB(Armor, m_maxs, vector, '16 16 48')
ATTRIB(Armor, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
#endif
ENDCLASS(Armor)
#ifndef MENUQC
MODEL(HealthSmall_ITEM, Item_Model("g_h1.md3"));
+SOUND(HealthSmall, "misc/minihealth");
#endif
REGISTER_ITEM(HealthSmall, Health) {
#ifndef MENUQC
this.m_model = MDL_HealthSmall_ITEM;
+ this.m_sound = SND_HealthSmall;
#endif
- this.m_sound = "misc/minihealth.wav";
this.m_name = "5 Health";
this.m_icon = "health";
#ifdef SVQC
#ifndef MENUQC
MODEL(HealthMedium_ITEM, Item_Model("g_h25.md3"));
+SOUND(HealthMedium, "misc/mediumhealth");
#endif
REGISTER_ITEM(HealthMedium, Health) {
#ifndef MENUQC
this.m_model = MDL_HealthMedium_ITEM;
+ this.m_sound = SND_HealthMedium;
#endif
- this.m_sound = "misc/mediumhealth.wav";
this.m_name = "25 Health";
this.m_icon = "health";
#ifdef SVQC
#ifndef MENUQC
MODEL(HealthLarge_ITEM, Item_Model("g_h50.md3"));
+SOUND(HealthLarge, "misc/mediumhealth");
#endif
REGISTER_ITEM(HealthLarge, Health) {
#ifndef MENUQC
this.m_model = MDL_HealthLarge_ITEM;
+ this.m_sound = SND_HealthLarge;
#endif
- this.m_sound = "misc/mediumhealth.wav";
this.m_name = "50 Health";
this.m_icon = "health";
this.m_color = '1 0 0';
#ifndef MENUQC
MODEL(HealthMega_ITEM, Item_Model("g_h100.md3"));
+SOUND(HealthMega, "misc/megahealth");
#endif
REGISTER_ITEM(HealthMega, Health) {
#ifndef MENUQC
this.m_model = MDL_HealthMega_ITEM;
+ this.m_sound = SND_HealthMega;
#endif
- this.m_sound = "misc/megahealth.wav";
this.m_name = "100 Health";
this.m_icon = "item_mega_health";
this.m_color = '1 0 0';
#include "pickup.qh"
CLASS(Health, Pickup)
#ifdef SVQC
+ ATTRIB(Health, m_mins, vector, '-16 -16 0')
+ ATTRIB(Health, m_maxs, vector, '16 16 48')
ATTRIB(Health, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
#endif
ENDCLASS(Health)
#ifdef SVQC
bool ITEM_HANDLE(Pickup, entity this, entity item, entity player) {
- bool b = this.giveTo(this, item, player);
- if (b) {
- LOG_TRACEF("entity %i picked up %s\n", player, this.m_name);
- player.inventory.inv_items[this.m_id]++;
- Inventory_update(player);
- }
- return b;
+ return this.giveTo(this, item, player);
}
#endif
#ifndef PICKUP_H
#define PICKUP_H
+#include "../inventory.qh"
#include "../item.qh"
CLASS(Pickup, GameItem)
#ifndef MENUQC
ATTRIB(Pickup, m_model, Model, NULL)
+ ATTRIB(Pickup, m_sound, Sound, SND_ITEMPICKUP)
#endif
- ATTRIB(Pickup, m_sound, string, "misc/itempickup.wav")
ATTRIB(Pickup, m_name, string, string_null)
METHOD(Pickup, show, void(entity this));
void Pickup_show(entity this) { LOG_INFOF("%s: %s\n", etos(this), this.m_name); }
#ifdef SVQC
+ ATTRIB(Pickup, m_mins, vector, '-16 -16 0')
+ ATTRIB(Pickup, m_maxs, vector, '16 16 32')
ATTRIB(Pickup, m_botvalue, int, 0)
ATTRIB(Pickup, m_itemflags, int, 0)
ATTRIB(Pickup, m_itemid, int, 0)
+ float generic_pickupevalfunc(entity player, entity item);
ATTRIB(Pickup, m_pickupevalfunc, float(entity player, entity item), generic_pickupevalfunc)
ATTRIB(Pickup, m_respawntime, float(), func_null)
ATTRIB(Pickup, m_respawntimejitter, float(), func_null)
- METHOD(Pickup, giveTo, bool(entity this, entity item, entity player));
- bool Pickup_giveTo(entity this, entity item, entity player) { return Item_GiveTo(item, player); }
+ float Item_GiveTo(entity item, entity player);
+ METHOD(Pickup, giveTo, bool(entity this, entity item, entity player))
+ {
+ bool b = Item_GiveTo(item, player);
+ if (b) {
+ LOG_TRACEF("entity %i picked up %s\n", player, this.m_name);
+ player.inventory.inv_items[this.m_id]++;
+ Inventory_update(player);
+ }
+ return b;
+ }
bool ITEM_HANDLE(Pickup, entity this, entity item, entity player);
#endif
ENDCLASS(Pickup)
-#ifdef SVQC
-// For g_pickup_respawntime
-#include "../../../server/defs.qh"
-// Getters to dynamically retrieve the values of g_pickup_respawntime*
-GETTER(float, g_pickup_respawntime_weapon)
-GETTER(float, g_pickup_respawntime_superweapon)
-GETTER(float, g_pickup_respawntime_ammo)
-GETTER(float, g_pickup_respawntime_short)
-GETTER(float, g_pickup_respawntime_medium)
-GETTER(float, g_pickup_respawntime_long)
-GETTER(float, g_pickup_respawntime_powerup)
-GETTER(float, g_pickup_respawntimejitter_weapon)
-GETTER(float, g_pickup_respawntimejitter_superweapon)
-GETTER(float, g_pickup_respawntimejitter_ammo)
-GETTER(float, g_pickup_respawntimejitter_short)
-GETTER(float, g_pickup_respawntimejitter_medium)
-GETTER(float, g_pickup_respawntimejitter_long)
-GETTER(float, g_pickup_respawntimejitter_powerup)
-
-#endif
-
#endif
#ifndef MENUQC
MODEL(Strength_ITEM, Item_Model("g_strength.md3"));
+SOUND(Strength, "misc/powerup");
#endif
REGISTER_ITEM(Strength, Powerup) {
#ifndef MENUQC
this.m_model = MDL_Strength_ITEM;
+ this.m_sound = SND_Strength;
#endif
- this.m_sound = "misc/powerup.wav";
this.m_name = "Strength Powerup";
this.m_icon = "strength";
this.m_color = '0 0 1';
#ifndef MENUQC
MODEL(Shield_ITEM, Item_Model("g_invincible.md3"));
+SOUND(Shield, "misc/powerup_shield");
#endif
REGISTER_ITEM(Shield, Powerup) {
#ifndef MENUQC
this.m_model = MDL_Shield_ITEM;
+ this.m_sound = SND_Shield;
#endif
- this.m_sound = "misc/powerup_shield.wav";
this.m_name = "Shield";
this.m_icon = "shield";
this.m_color = '1 0 1';
#include "pickup.qh"
CLASS(Powerup, Pickup)
#ifdef SVQC
+ ATTRIB(Powerup, m_mins, vector, '-16 -16 0')
+ ATTRIB(Powerup, m_maxs, vector, '16 16 48')
ATTRIB(Powerup, m_botvalue, int, 100000)
ATTRIB(Powerup, m_itemflags, int, FL_POWERUP)
ATTRIB(Powerup, m_respawntime, float(), GET(g_pickup_respawntime_powerup))
#if defined(CSQC)
#include "../client/defs.qh"
#include "util.qh"
- #include "buffs/all.qh"
#include "weapons/all.qh"
#include "mapinfo.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
#include "util.qh"
- #include "buffs/all.qh"
#include "monsters/all.qh"
#include "mapinfo.qh"
#endif
{
MapInfo_Map_flags |= MAPINFO_FLAG_NOAUTOMAPLIST;
}
+ else if(t == "gameversion_min")
+ {
+ if (cvar("gameversion") < stof(s))
+ MapInfo_Map_flags |= MAPINFO_FLAG_NOAUTOMAPLIST;
+ }
else if(t == "type")
{
t = car(s); s = cdr(s);
}
ENDCLASS(Gametype)
-REGISTRY(Gametypes, BIT(4))
-REGISTER_REGISTRY(RegisterGametypes)
+REGISTRY(Gametypes, BITS(4))
+#define Gametypes_from(i) _Gametypes_from(i, NULL)
+REGISTER_REGISTRY(Gametypes)
+REGISTRY_CHECK(Gametypes)
int MAPINFO_TYPE_ALL;
#define REGISTER_GAMETYPE(hname, sname, g_name, NAME, gteamplay, mutators, defaults, gdescription) \
int MAPINFO_TYPE_##NAME; \
bool NAME##_mapinfo(string k, string v) { return = false; } \
- REGISTER(RegisterGametypes, MAPINFO_TYPE, Gametypes, g_name, m_id, \
+ REGISTER(Gametypes, MAPINFO_TYPE, g_name, m_id, \
NEW(Gametype, hname, #sname, #g_name, gteamplay, #sname " " mutators, defaults, gdescription) \
) { \
/* same as `1 << m_id` */ \
}
#define g_race IS_GAMETYPE(RACE)
-REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,false,"","timelimit=20",_("Race for fastest time."));
+REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,false,"cloaked","timelimit=20",_("Race for fastest time."));
#define g_cts IS_GAMETYPE(CTS)
REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,true,"","timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team"))
deactivate_minigame();
}
-vector ReadVector2D() { vector v; v_x = ReadCoord(); v_y = ReadCoord(); v_z = 0; return v; }
-vector ReadVector() { vector v; v_x = ReadCoord(); v_y = ReadCoord(); v_z = ReadCoord(); return v; }
string() ReadString_Raw = #366;
string ReadString_Zoned() { return strzone(ReadString_Raw()); }
#define ReadString ReadString_Zoned
if ( !self.owner )
LOG_TRACE("Got a minigame entity without a minigame!\n");
}
-void ent_read_minigame()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_MINIGAME, bool isnew)
+{
float sf = ReadByte();
if ( sf & MINIG_SF_CREATE )
{
" classname:",self.classname," enttype:",ftos(self.enttype) );
LOG_DEBUG(" sf:",ftos(sf)," netname:",self.netname,"\n\n");
}
+ return true;
}
#undef ReadString
#undef FIELD
#define minigame_cmd(...) minigame_cmd_workaround(0,__VA_ARGS__)
void minigame_cmd_workaround(float dummy, string...cmdargc);
-// Read a minigame entity from the server
-void ent_read_minigame();
-
// Prompt the player to play in the current minigame
// (ie: it's their turn and they should get back to the minigame)
void minigame_prompt();
while( (entityvar = findentity(entityvar,owner,active_minigame)) )
-REGISTRY(Minigames, BIT(3))
-REGISTER_REGISTRY(RegisterMinigames)
+REGISTRY(Minigames, BITS(3))
+#define Minigames_from(i) _Minigames_from(i, NULL)
+REGISTER_REGISTRY(Minigames)
+REGISTRY_CHECK(Minigames)
#define REGISTER_MINIGAME(name,nicename) \
- REGISTER(RegisterMinigames, MINIGAME, Minigames, name, m_id, spawn()); \
+ REGISTER(Minigames, MINIGAME, name, m_id, new(minigame_descriptor)); \
void name##_hud_board(vector, vector); \
void name##_hud_status(vector, vector); \
int name##_client_event(entity, string, ...); \
REGISTER_INIT_POST(MINIGAME, name) { \
- this.classname = "minigame_descriptor"; \
+ make_pure(this); \
this.netname = strzone(strtolower(#name)); \
this.message = nicename; \
this.minigame_hud_board = name##_hud_board; \
void nmm_spawn_tile(string id, entity minig, int distance)
{
// TODO global variable + list_next for simpler tile loops
- entity e = spawn();
+ entity e = new(minigame_nmm_tile);
e.origin = minigame_tile_pos(id,7,7);
- e.classname = "minigame_nmm_tile";
e.netname = id;
e.owner = minig;
e.team = 0;
if ( spawnai )
{
- entity aiplayer = spawn();
- aiplayer.classname = "minigame_player";
+ entity aiplayer = new(minigame_player);
aiplayer.owner = minigame;
aiplayer.team = ai;
aiplayer.minigame_playerslot = 0;
#include "minigames.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_MINIGAME)
+
entity minigame_get_descriptor(string id)
{
FOREACH(Minigames, true, LAMBDA(
#define FIELD(Flags, Type,Name) if ( sf & (Flags) ) Write##Type(MSG_ENTITY, self.Name);
-#define WriteVector(to,Name) WriteCoord(to,Name##_x); WriteCoord(to,Name##_y); WriteCoord(to,Name##_z)
-#define WriteVector2D(to,Name) WriteCoord(to,Name##_x); WriteCoord(to,Name##_y)
#define MSLE(Name,Fields) \
else if ( self.classname == #Name ) { \
if ( sf & MINIG_SF_CREATE ) WriteString(MSG_ENTITY,self.owner.netname); \
// only use on minigame entities or entities with a minigame owner
bool minigame_SendEntity(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_MINIGAME);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_MINIGAME);
WriteByte(MSG_ENTITY, sf);
if ( sf & MINIG_SF_CREATE )
return 0;
minigame_rmplayer(player.active_minigame,player);
}
- entity player_pointer = spawn();
+ entity player_pointer = new(minigame_player);
int mgteam = minigame_session.minigame_event(minigame_session,"join",player,player_pointer);
if ( mgteam )
{
- player_pointer.classname = "minigame_player";
player_pointer.owner = minigame_session;
player_pointer.minigame_players = player;
player_pointer.team = mgteam;
entity e = minigame_get_descriptor(minigame);
if ( e )
{
- entity minig = spawn();
- minig.classname = "minigame";
+ entity minig = new(minigame);
minig.netname = strzone(strcat(e.netname,"_",ftos(num_for_edict(minig))));
minig.descriptor = e;
minig.minigame_event = e.minigame_event;
bool minigame_SendEntity(entity this, entity to, int sf);
-REGISTRY(Minigames, BIT(3))
-REGISTER_REGISTRY(RegisterMinigames)
+REGISTRY(Minigames, BITS(3))
+#define Minigames_from(i) _Minigames_from(i, NULL)
+REGISTER_REGISTRY(Minigames)
+REGISTRY_CHECK(Minigames)
#define REGISTER_MINIGAME(name,nicename) \
- REGISTER(RegisterMinigames, MINIGAME, Minigames, name, m_id, spawn()); \
+ REGISTER(Minigames, MINIGAME, name, m_id, new(minigame_descriptor)); \
int name##_server_event(entity, string, ...); \
REGISTER_INIT_POST(MINIGAME, name) { \
- this.classname = "minigame_descriptor"; \
+ make_pure(this); \
this.netname = strzone(strtolower(#name)); \
this.message = nicename; \
this.minigame_event = name##_server_event; \
MODEL(CTF_SHIELD, "models/ctf/shield.md3");
MODEL(CTF_CAPTURE, "models/ctf/shockwavetransring.md3");
+MODEL(CTF_FLAG, "models/ctf/flags.md3");
MODEL(DOM_NEUTRAL, "models/domination/dom_unclaimed.md3");
MODEL(DOM_RED, "models/domination/dom_red.md3");
MODEL(GIB_ROBO_8, "models/gibs/robo8.md3");
Model MDL_GIB_ROBO_RANDOM() {
int i = floor(random() * 8);
- return Models[MDL_GIB_ROBO_1.m_id + i];
+ return Models_from(MDL_GIB_ROBO_1.m_id + i);
}
MODEL(CASING_SHELL, "models/casing_shell.mdl");
MODEL(10, "models/sprites/10.spr32");
Model MDL_NUM(int i) {
if ((i >= 0 && i <= 10))
- return Models[MDL_0.m_id + i];
+ return Models_from(MDL_0.m_id + i);
return MDL_Null;
}
#include "model.qh"
-REGISTRY(Models, BIT(9))
-REGISTER_REGISTRY(RegisterModels)
+REGISTRY(Models, BITS(9))
+#define Models_from(i) _Models_from(i, MDL_Null)
+REGISTER_REGISTRY(Models)
#define MODEL(name, path) \
string MDL_##name##_get() { return path; } \
- REGISTER(RegisterModels, MDL, Models, name, m_id, NEW(Model, MDL_##name##_get))
+ REGISTER(Models, MDL, name, m_id, NEW(Model, MDL_##name##_get))
-STATIC_INIT(RegisterModels_precache) {
+PRECACHE(Models) {
FOREACH(Models, true, LAMBDA({
it.model_precache(it);
}));
#ifndef MONSTERS_ALL_C
#define MONSTERS_ALL_C
+string M_Model(string m_mdl)
+{
+ string output = strcat("models/monsters/", m_mdl);
+#ifdef SVQC
+ MUTATOR_CALLHOOK(MonsterModel, m_mdl, output);
+ return monster_model_output;
+#else
+ return output;
+#endif
+}
+
#include "all.qh"
#define IMPLEMENTATION
#include "monster.qh"
-REGISTRY(Monsters, BIT(4))
-REGISTER_REGISTRY(RegisterMonsters)
+string M_Model(string m_mdl);
+
+REGISTRY(Monsters, BITS(5))
+#define Monsters_from(i) _Monsters_from(i, MON_Null)
+#define get_monsterinfo(i) Monsters_from(i)
+REGISTER_REGISTRY(Monsters)
+REGISTRY_CHECK(Monsters)
const int MON_FIRST = 1;
#define MON_LAST (Monsters_COUNT - 1)
/** If you register a new monster, make sure to add it to all.inc */
-#define REGISTER_MONSTER(id, inst) REGISTER(RegisterMonsters, MON, Monsters, id, monsterid, inst)
+#define REGISTER_MONSTER(id, inst) REGISTER(Monsters, MON, id, monsterid, inst)
REGISTER_MONSTER(Null, NEW(Monster));
-Monster get_monsterinfo(int id)
-{
- if (id >= MON_FIRST && id <= MON_LAST) {
- Monster m = Monsters[id];
- if (m) return m;
- }
- return MON_Null;
-}
#include "all.inc"
const int MON_FLAG_MELEE = 1024;
const int MON_FLAG_CRUSH = 2048; // monster can be stomped in special modes
const int MON_FLAG_RIDE = 4096; // monster can be ridden in special modes
+const int MONSTER_SIZE_QUAKE = 8192;
// entity properties of monsterinfo:
.bool(int, entity targ) monster_attackfunc;
#define MAGE_H
#ifndef MENUQC
-MODEL(MON_MAGE, "models/monsters/mage.dpm");
+MODEL(MON_MAGE, M_Model("mage.dpm"));
#endif
CLASS(Mage, Monster)
/* flags */ ATTRIB(MageSpike, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(MageSpike, impulse, int, 9);
/* refname */ ATTRIB(MageSpike, netname, string, "magespike");
-/* wepname */ ATTRIB(MageSpike, message, string, _("Mage spike"));
+/* wepname */ ATTRIB(MageSpike, m_name, string, _("Mage spike"));
ENDCLASS(MageSpike)
REGISTER_WEAPON(MAGE_SPIKE, NEW(MageSpike));
#ifdef SVQC
+SOUND(MageSpike_FIRE, W_Sound("electro_fire"));
void M_Mage_Attack_Spike(vector dir);
void M_Mage_Attack_Push();
-METHOD(MageSpike, wr_think, void(MageSpike thiswep, entity actor, bool fire1, bool fire2)) {
- if (fire1)
- if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, false, 0.2)) {
+METHOD(MageSpike, wr_think, void(MageSpike thiswep, entity actor, .entity weaponentity, int fire)) {
+ if (fire & 1)
+ if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) {
if (!actor.target_range) actor.target_range = autocvar_g_monsters_target_range;
actor.enemy = Monster_FindTarget(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(MageSpike_FIRE), CH_WEAPON_B, 0);
if (!IS_PLAYER(actor)) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
M_Mage_Attack_Spike(w_shotdir);
- weapon_thinkf(actor, WFRAME_FIRE1, 0, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
}
- if (fire2)
- if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, true, 0.5)) {
+ if (fire & 2)
+ if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, weaponentity, true, 0.5)) {
M_Mage_Attack_Push();
- weapon_thinkf(actor, WFRAME_FIRE2, 0, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
}
}
if(washealed)
{
setanim(self, self.anim_shoot, true, true, true);
- self.attack_finished_single = time + (autocvar_g_monster_mage_heal_delay);
+ self.attack_finished_single[0] = time + (autocvar_g_monster_mage_heal_delay);
self.anim_finished = time + 1.5;
}
}
Send_Effect(EFFECT_TE_EXPLOSION, self.origin, '0 0 0', 1);
setanim(self, self.anim_shoot, true, true, true);
- self.attack_finished_single = time + (autocvar_g_monster_mage_attack_push_delay);
+ self.attack_finished_single[0] = time + (autocvar_g_monster_mage_attack_push_delay);
}
void M_Mage_Attack_Teleport()
self.fixangle = true;
self.velocity *= 0.5;
- self.attack_finished_single = time + 0.2;
+ self.attack_finished_single[0] = time + 0.2;
}
void M_Mage_Defend_Shield_Remove()
self.armorvalue = (autocvar_g_monster_mage_shield_blockpercent);
self.mage_shield_time = time + (autocvar_g_monster_mage_shield_time);
setanim(self, self.anim_shoot, true, true, true);
- self.attack_finished_single = time + 1;
+ self.attack_finished_single[0] = time + 1;
self.anim_finished = time + 1;
}
float M_Mage_Attack(float attack_type, entity targ)
{SELFPARAM();
+ .entity weaponentity = weaponentities[0];
switch(attack_type)
{
case MONSTER_ATTACK_MELEE:
if(random() <= 0.7)
{
Weapon wep = WEP_MAGE_SPIKE;
- wep.wr_think(wep, self, false, true);
+
+ wep.wr_think(wep, self, weaponentity, 2);
return true;
}
else
{
setanim(self, self.anim_shoot, true, true, true);
- self.attack_finished_single = time + (autocvar_g_monster_mage_attack_spike_delay);
+ self.attack_finished_single[0] = time + (autocvar_g_monster_mage_attack_spike_delay);
self.anim_finished = time + 1;
Weapon wep = WEP_MAGE_SPIKE;
- wep.wr_think(wep, self, true, false);
+ wep.wr_think(wep, self, weaponentity, 1);
return true;
}
}
}
if(self.health < (autocvar_g_monster_mage_heal_minhealth) || need_help)
- if(time >= self.attack_finished_single)
+ if(time >= self.attack_finished_single[0])
if(random() < 0.5)
M_Mage_Defend_Heal();
#define SHAMBLER_H
#ifndef MENUQC
-MODEL(MON_SHAMBLER, "models/monsters/shambler.mdl");
+MODEL(MON_SHAMBLER, M_Model("shambler.mdl"));
#endif
CLASS(Shambler, Monster)
if(r && Monster_Attack_Melee(self.enemy, (autocvar_g_monster_shambler_attack_claw_damage), ((r) ? self.anim_melee2 : self.anim_melee3), self.attack_range, 0.8, DEATH_MONSTER_SHAMBLER_CLAW.m_id, true))
{
Monster_Delay(1, 0, 0.5, M_Shambler_Attack_Swing);
- self.attack_finished_single += 0.5;
- self.anim_finished = self.attack_finished_single;
+ self.attack_finished_single[0] += 0.5;
+ self.anim_finished = self.attack_finished_single[0];
}
}
-#include "../../../server/csqceffects.qh"
+#include "../../effects/qc/all.qh"
void M_Shambler_Attack_Lightning_Explode()
{SELFPARAM();
monster_makevectors(self.enemy);
- gren = spawn ();
+ gren = new(grenade);
gren.owner = gren.realowner = self;
- gren.classname = "grenade";
gren.bot_dodge = true;
gren.bot_dodgerating = (autocvar_g_monster_shambler_attack_lightning_damage);
gren.movetype = MOVETYPE_BOUNCE;
{
setanim(self, self.anim_melee2, true, true, false);
Monster_Delay(1, 0, 0.7, M_Shambler_Attack_Smash);
- self.attack_finished_single = time + 1.1;
+ self.attack_finished_single[0] = time + 1.1;
self.anim_finished = time + 1.1;
self.state = MONSTER_ATTACK_MELEE; // kinda a melee attack
self.shambler_lastattack = time + 3 + random() * 1.5;
{
setanim(self, self.anim_shoot, true, true, false);
self.state = MONSTER_ATTACK_MELEE; // maybe we should rename this to something more general
- self.attack_finished_single = time + 1.1;
+ self.attack_finished_single[0] = time + 1.1;
self.anim_finished = 1.1;
self.shambler_lastattack = time + 3 + random() * 1.5;
Monster_Delay(1, 0, 0.6, M_Shambler_Attack_Lightning);
#define SPIDER_H
#ifndef MENUQC
-MODEL(MON_SPIDER, "models/monsters/spider.dpm");
+MODEL(MON_SPIDER, M_Model("spider.dpm"));
#endif
CLASS(Spider, Monster)
/* flags */ ATTRIB(SpiderAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(SpiderAttack, impulse, int, 9);
/* refname */ ATTRIB(SpiderAttack, netname, string, "spider");
-/* wepname */ ATTRIB(SpiderAttack, message, string, _("Spider attack"));
+/* wepname */ ATTRIB(SpiderAttack, m_name, string, _("Spider attack"));
ENDCLASS(SpiderAttack)
REGISTER_WEAPON(SPIDER_ATTACK, NEW(SpiderAttack));
void M_Spider_Attack_Web();
-METHOD(SpiderAttack, wr_think, void(SpiderAttack thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(SpiderAttack_FIRE, W_Sound("electro_fire"));
+METHOD(SpiderAttack, wr_think, void(SpiderAttack thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if ((!isPlayer && time >= actor.spider_web_delay) || weapon_prepareattack(thiswep, actor, false, autocvar_g_monster_spider_attack_web_delay)) {
+ if (fire & 1)
+ if ((!isPlayer && time >= actor.spider_web_delay) || weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_monster_spider_attack_web_delay)) {
if (!isPlayer) {
actor.spider_web_delay = time + 3;
setanim(actor, actor.anim_shoot, true, true, true);
- actor.attack_finished_single = time + (autocvar_g_monster_spider_attack_web_delay);
+ actor.attack_finished_single[0] = time + (autocvar_g_monster_spider_attack_web_delay);
actor.anim_finished = time + 1;
}
if (isPlayer) actor.enemy = Monster_FindTarget(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(SpiderAttack_FIRE), CH_WEAPON_B, 0);
if (!isPlayer) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
M_Spider_Attack_Web();
- weapon_thinkf(actor, WFRAME_FIRE1, 0, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
return;
}
- if (fire2)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, true, 0.5)) {
+ if (fire & 2)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, true, 0.5)) {
if (isPlayer) {
actor.enemy = Monster_FindTarget(actor);
actor.attack_range = 60;
}
Monster_Attack_Melee(actor.enemy, (autocvar_g_monster_spider_attack_bite_damage), ((random() > 0.5) ? self.anim_melee : self.anim_shoot), self.attack_range, (autocvar_g_monster_spider_attack_bite_delay), DEATH_MONSTER_SPIDER.m_id, true);
- weapon_thinkf(actor, WFRAME_FIRE2, 0, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
}
}
sound(self, CH_SHOTS, SND_ELECTRO_FIRE2, VOL_BASE, ATTEN_NORM);
- entity proj = spawn ();
- proj.classname = "plasma";
+ entity proj = new(plasma);
proj.owner = proj.realowner = self;
proj.use = M_Spider_Attack_Web_Explode;
proj.think = adaptor_think2use_hittype_splash;
bool M_Spider_Attack(int attack_type, entity targ)
{SELFPARAM();
+ .entity weaponentity = weaponentities[0];
switch(attack_type)
{
Weapon wep = WEP_SPIDER_ATTACK;
case MONSTER_ATTACK_MELEE:
{
- wep.wr_think(wep, self, false, true);
+ wep.wr_think(wep, self, weaponentity, 2);
return true;
}
case MONSTER_ATTACK_RANGED:
{
- wep.wr_think(wep, self, true, false);
+ wep.wr_think(wep, self, weaponentity, 1);
return true;
}
}
#define WYVERN_H
#ifndef MENUQC
-MODEL(MON_WYVERN, "models/monsters/wizard.mdl");
+MODEL(MON_WYVERN, M_Model("wizard.mdl"));
#endif
CLASS(Wyvern, Monster)
/* flags */ ATTRIB(WyvernAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(WyvernAttack, impulse, int, 9);
/* refname */ ATTRIB(WyvernAttack, netname, string, "wyvern");
-/* wepname */ ATTRIB(WyvernAttack, message, string, _("Wyvern attack"));
+/* wepname */ ATTRIB(WyvernAttack, m_name, string, _("Wyvern attack"));
ENDCLASS(WyvernAttack)
REGISTER_WEAPON(WYVERN_ATTACK, NEW(WyvernAttack));
void M_Wyvern_Attack_Fireball_Explode();
void M_Wyvern_Attack_Fireball_Touch();
-METHOD(WyvernAttack, wr_think, void(WyvernAttack thiswep, entity actor, bool fire1, bool fire2)) {
- if (fire1)
- if (time > actor.attack_finished_single || weapon_prepareattack(thiswep, actor, false, 1.2)) {
- if (IS_PLAYER(actor)) W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+SOUND(WyvernAttack_FIRE, W_Sound("electro_fire"));
+METHOD(WyvernAttack, wr_think, void(WyvernAttack thiswep, entity actor, .entity weaponentity, int fire)) {
+ if (fire & 1)
+ if (time > actor.attack_finished_single[0] || weapon_prepareattack(thiswep, actor, weaponentity, false, 1.2)) {
+ if (IS_PLAYER(actor)) W_SetupShot_Dir(actor, v_forward, false, 0, SND(WyvernAttack_FIRE), CH_WEAPON_B, 0);
if (IS_MONSTER(actor)) {
- actor.attack_finished_single = time + 1.2;
+ actor.attack_finished_single[0] = time + 1.2;
actor.anim_finished = time + 1.2;
monster_makevectors(actor.enemy);
}
missile.touch = M_Wyvern_Attack_Fireball_Touch;
CSQCProjectile(missile, true, PROJECTILE_FIREMINE, true);
- weapon_thinkf(actor, WFRAME_FIRE1, 0, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
}
}
float M_Wyvern_Attack(float attack_type, entity targ)
{
SELFPARAM();
+ .entity weaponentity = weaponentities[0];
switch(attack_type)
{
case MONSTER_ATTACK_MELEE:
{
w_shotdir = normalize((self.enemy.origin + '0 0 10') - self.origin);
Weapon wep = WEP_WYVERN_ATTACK;
- wep.wr_think(wep, self, true, false);
+ wep.wr_think(wep, self, weaponentity, 1);
return true;
}
}
#define ZOMBIE_H
#ifndef MENUQC
-MODEL(MON_ZOMBIE, "models/monsters/zombie.dpm");
+MODEL(MON_ZOMBIE, M_Model("zombie.dpm"));
#endif
CLASS(Zombie, Monster)
{SELFPARAM();
self.armorvalue = 0.9;
self.state = MONSTER_ATTACK_MELEE; // freeze monster
- self.attack_finished_single = time + 2.1;
- self.anim_finished = self.attack_finished_single;
+ self.attack_finished_single[0] = time + 2.1;
+ self.anim_finished = self.attack_finished_single[0];
setanim(self, self.anim_blockstart, false, true, true);
Monster_Delay(1, 0, 2, M_Zombie_Defend_Block_End);
return;
vector org = self.origin + ((self.mins + self.maxs) * 0.5);
- entity e = spawn();
+ entity e = new(droppedweapon); // use weapon handling to remove it on touch
e.spawnfunc_checked = true;
e.monster_loot = self.monster_loot;
setorigin(e, org);
e.velocity = randomvec() * 175 + '0 0 325';
e.item_spawnshieldtime = time + 0.7;
- e.classname = "droppedweapon"; // use weapon handling to remove it on touch
SUB_SetFade(e, time + autocvar_g_monsters_drop_time, 1);
setself(this);
}
if(delaytoo)
if(time < self.msound_delay)
return; // too early
- GlobalSound(self.(samplefield), chan, VOICETYPE_PLAYERSOUND);
+ _GlobalSound(self.(samplefield), chan, VOICETYPE_PLAYERSOUND, false);
self.msound_delay = time + sound_delay;
}
setanim(self, anim, false, true, false);
if(self.animstate_endtime > time && (self.flags & FL_MONSTER))
- self.attack_finished_single = self.anim_finished = self.animstate_endtime;
+ self.attack_finished_single[0] = self.anim_finished = self.animstate_endtime;
else
- self.attack_finished_single = self.anim_finished = time + animtime;
+ self.attack_finished_single[0] = self.anim_finished = time + animtime;
monster_makevectors(targ);
return false; // not on the ground
if(self.health <= 0)
return false; // called when dead?
- if(time < self.attack_finished_single)
+ if(time < self.attack_finished_single[0])
return false; // still attacking
vector old = self.velocity;
setanim(self, anm, false, true, false);
if(self.animstate_endtime > time && (self.flags & FL_MONSTER))
- self.attack_finished_single = self.anim_finished = self.animstate_endtime;
+ self.attack_finished_single[0] = self.anim_finished = self.animstate_endtime;
else
- self.attack_finished_single = self.anim_finished = time + animtime;
+ self.attack_finished_single[0] = self.anim_finished = time + animtime;
if(self.flags & FL_MONSTER)
self.state = MONSTER_ATTACK_RANGED;
{
if((e == world || targ == world)
|| (!e.monster_attackfunc)
- || (time < e.attack_finished_single)
+ || (time < e.attack_finished_single[0])
) { return; }
float targ_vlen = vlen(targ.origin - e.origin);
self.touch = Monster_Touch;
}
- if(self.state && time >= self.attack_finished_single)
+ if(self.state && time >= self.attack_finished_single[0])
self.state = 0; // attack is over
if(self.state != MONSTER_ATTACK_MELEE) // don't move if set
void Monster_Remove(entity mon)
{
+ .entity weaponentity = weaponentities[0];
if(!mon) { return; }
if(!MUTATOR_CALLHOOK(MonsterRemove, mon))
Send_Effect(EFFECT_ITEM_PICKUP, mon.origin, '0 0 0', 1);
- if(mon.weaponentity) { remove(mon.weaponentity); }
+ if(mon.(weaponentity)) { remove(mon.(weaponentity)); }
if(mon.iceblock) { remove(mon.iceblock); }
WaypointSprite_Kill(mon.sprite);
remove(mon);
self.velocity = '0 0 0';
self.enemy = world;
self.goalentity = world;
- self.attack_finished_single = 0;
+ self.attack_finished_single[0] = 0;
self.moveto = self.origin;
}
self.touch = Monster_Touch; // reset incase monster was pouncing
self.reset = func_null;
self.state = 0;
- self.attack_finished_single = 0;
+ self.attack_finished_single[0] = 0;
self.effects = 0;
if(!((self.flags & FL_FLY) || (self.flags & FL_SWIM)))
movelib_move_simple_gravity(v_forward, mspeed, 1);
if(time > self.pain_finished)
- if(time > self.attack_finished_single)
+ if(time > self.attack_finished_single[0])
if(vlen(self.velocity) > 10)
setanim(self, self.anim_walk, true, false, false);
else
self.movetype = MOVETYPE_FLY;
}
- if(mon.spawnflags & MONSTER_SIZE_BROKEN)
if(!(self.spawnflags & MONSTERFLAG_RESPAWNED))
- self.scale *= 1.3;
+ {
+ if(mon.spawnflags & MONSTER_SIZE_BROKEN)
+ self.scale *= 1.3;
+
+ if(mon.spawnflags & MONSTER_SIZE_QUAKE)
+ if(autocvar_g_monsters_quake_resize)
+ self.scale *= 1.3;
+ }
setsize(self, mon.mins * self.scale, mon.maxs * self.scale);
#define MOVETYPES_H
.float move_ltime;
-.void(void)move_think;
+.void()move_think;
.float move_nextthink;
-.void(void)move_blocked;
+.void()move_blocked;
.float move_movetype;
.float move_time;
.int move_flags;
.int move_watertype;
.int move_waterlevel;
-.void(void)move_touch;
+.void()move_touch;
.void(float, float)contentstransition;
.float move_bounce_factor;
.float move_bounce_stopspeed;
-#include "mutator/casings.qc"
-#include "mutator/damagetext.qc"
-#include "mutator/instagib/instagib.qc"
+#include "mutator/waypoints/module.inc"
+
#include "mutator/itemstime.qc"
-#include "mutator/waypoints/waypointsprites.qc"
+#include "mutator/multijump/module.inc"
+#include "mutator/nades/module.inc"
+#include "mutator/superspec/module.inc"
+
+// completely self contained
+
+#include "mutator/bloodloss/module.inc"
+#include "mutator/breakablehook/module.inc"
+#include "mutator/buffs/module.inc"
+#include "mutator/campcheck/module.inc"
+#include "mutator/cloaked/module.inc"
+#include "mutator/damagetext/module.inc"
+#include "mutator/dodging/module.inc"
+#include "mutator/hook/module.inc"
+#include "mutator/instagib/module.inc"
+#include "mutator/invincibleproj/module.inc"
+#include "mutator/melee_only/module.inc"
+#include "mutator/midair/module.inc"
+#include "mutator/new_toys/module.inc"
+#include "mutator/nix/module.inc"
+#include "mutator/overkill/module.inc"
+#include "mutator/physical_items/module.inc"
+#include "mutator/pinata/module.inc"
+#include "mutator/random_gravity/module.inc"
+#include "mutator/rocketflying/module.inc"
+#include "mutator/rocketminsta/module.inc"
+#include "mutator/running_guns/module.inc"
+#include "mutator/sandbox/module.inc"
+#include "mutator/spawn_near_teammate/module.inc"
+#include "mutator/touchexplode/module.inc"
+#include "mutator/vampirehook/module.inc"
+#include "mutator/vampire/module.inc"
+#include "mutator/weaponarena_random/module.inc"
}
ENDCLASS(Mutator)
-REGISTRY(Mutators, BITS(6))
+REGISTRY(Mutators, BITS(7))
+#define Mutators_from(i) _Mutators_from(i, NULL)
Mutator loaded_mutators[Mutators_MAX];
bool Mutator_Add(Mutator mut)
bool ret = MUTATORFUNCTION_##id##_hooks(mode); if (ret) return ret; \
} \
bool MUTATOR_##id##_check() { return dependence; } \
- REGISTER(RegisterMutators, MUTATOR, Mutators, id, m_id, NEW(Mutator, #id, MUTATORFUNCTION_##id)) \
+ REGISTER(Mutators, MUTATOR, id, m_id, NEW(Mutator, #id, MUTATORFUNCTION_##id)) \
{ this.mutatorcheck = MUTATOR_##id##_check; } \
[[accumulate]] bool MUTATORFUNCTION_##id(int mode)
_(x, string) \
/**/
-#define MUTATOR_NEWGLOBAL(x, type) type mutator_argv_##type##_##x;
+#define MUTATOR_ARGV(x, type) MUTATOR_ARGV_##x##_##type
+#define MUTATOR_NEWGLOBAL(x, type) type MUTATOR_ARGV(x, type);
MUTATOR_TYPES(MUTATOR_NEWGLOBAL, 0)
MUTATOR_TYPES(MUTATOR_NEWGLOBAL, 1)
/**/
MUTATOR_HOOKABLE(BuildGameplayTipsString, EV_BuildGameplayTipsString);
+#define EV_IsFlying(i, o) \
+ /**/ i(entity, MUTATOR_ARGV_0_entity) \
+ /**/
+MUTATOR_HOOKABLE(IsFlying, EV_IsFlying);
+
+#define EV_WP_Format(i, o) \
+ /**/ i(entity, MUTATOR_ARGV_0_entity) \
+ /**/ i(string, MUTATOR_ARGV_0_string) \
+ /**/ o(vector, MUTATOR_ARGV_0_vector) \
+ /**/ o(string, MUTATOR_ARGV_0_string) \
+ /**/
+MUTATOR_HOOKABLE(WP_Format, EV_WP_Format);
+
#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(bloodloss, cvar("g_bloodloss"));
+
+.float bloodloss_timer;
+
+MUTATOR_HOOKFUNCTION(bloodloss, PlayerPreThink)
+{SELFPARAM();
+ if(IS_PLAYER(self))
+ if(self.health <= autocvar_g_bloodloss && self.deadflag == DEAD_NO)
+ {
+ self.BUTTON_CROUCH = true;
+
+ if(time >= self.bloodloss_timer)
+ {
+ if(self.vehicle)
+ vehicles_exit(VHEF_RELEASE);
+ if(self.event_damage)
+ self.event_damage(self, self, 1, DEATH_ROT.m_id, self.origin, '0 0 0');
+ self.bloodloss_timer = time + 0.5 + random() * 0.5;
+ }
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(bloodloss, PlayerJump)
+{SELFPARAM();
+ if(self.health <= autocvar_g_bloodloss)
+ return true;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":bloodloss");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Blood loss");
+ return false;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "bloodloss.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+#include "../../../deathtypes/all.qh"
+#include "../../../../server/g_hook.qh"
+
+REGISTER_MUTATOR(breakablehook, cvar("g_breakablehook"));
+
+bool autocvar_g_breakablehook; // allow toggling mid match?
+bool autocvar_g_breakablehook_owner;
+
+MUTATOR_HOOKFUNCTION(breakablehook, PlayerDamage_Calculate)
+{
+ if(frag_target.classname == "grapplinghook")
+ {
+ if((!autocvar_g_breakablehook)
+ || (!autocvar_g_breakablehook_owner && frag_attacker == frag_target.realowner)
+ ) { frag_damage = 0; }
+
+ // hurt the owner of the hook
+ if(DIFF_TEAM(frag_attacker, frag_target.realowner))
+ {
+ Damage (frag_target.realowner, frag_attacker, frag_attacker, 5, WEP_HOOK.m_id | HITTYPE_SPLASH, frag_target.realowner.origin, '0 0 0');
+ RemoveGrapplingHook(frag_target.realowner);
+ return false; // dead
+ }
+ }
+
+ return false;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "breakablehook.qc"
+#endif
--- /dev/null
+REGISTER_BUFF(AMMO) {
+ this.m_prettyName = _("Ammo");
+ this.m_name = "ammo";
+ this.m_skin = 3;
+ this.m_color = '0.76 1 0.1';
+}
+BUFF_SPAWNFUNCS(ammo, BUFF_AMMO)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(ammoregen, BUFF_AMMO)
+
+REGISTER_BUFF(RESISTANCE) {
+ this.m_prettyName = _("Resistance");
+ this.m_name = "resistance";
+ this.m_skin = 0;
+ this.m_color = '0.36 1 0.07';
+}
+BUFF_SPAWNFUNCS(resistance, BUFF_RESISTANCE)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(resistance, BUFF_RESISTANCE)
+
+REGISTER_BUFF(SPEED) {
+ this.m_prettyName = _("Speed");
+ this.m_name = "speed";
+ this.m_skin = 9;
+ this.m_color = '0.1 1 0.84';
+}
+BUFF_SPAWNFUNCS(speed, BUFF_SPEED)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(haste, BUFF_SPEED)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(scout, BUFF_SPEED)
+
+REGISTER_BUFF(MEDIC) {
+ this.m_prettyName = _("Medic");
+ this.m_name = "medic";
+ this.m_skin = 1;
+ this.m_color = '1 0.12 0';
+}
+BUFF_SPAWNFUNCS(medic, BUFF_MEDIC)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(doubler, BUFF_MEDIC)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(medic, BUFF_MEDIC)
+
+REGISTER_BUFF(BASH) {
+ this.m_prettyName = _("Bash");
+ this.m_name = "bash";
+ this.m_skin = 5;
+ this.m_color = '1 0.39 0';
+}
+BUFF_SPAWNFUNCS(bash, BUFF_BASH)
+
+REGISTER_BUFF(VAMPIRE) {
+ this.m_prettyName = _("Vampire");
+ this.m_name = "vampire";
+ this.m_skin = 2;
+ this.m_color = '1 0 0.24';
+}
+BUFF_SPAWNFUNCS(vampire, BUFF_VAMPIRE)
+
+REGISTER_BUFF(DISABILITY) {
+ this.m_prettyName = _("Disability");
+ this.m_name = "disability";
+ this.m_skin = 7;
+ this.m_color = '0.94 0.3 1';
+}
+BUFF_SPAWNFUNCS(disability, BUFF_DISABILITY)
+
+REGISTER_BUFF(VENGEANCE) {
+ this.m_prettyName = _("Vengeance");
+ this.m_name = "vengeance";
+ this.m_skin = 15;
+ this.m_color = '1 0.23 0.61';
+}
+BUFF_SPAWNFUNCS(vengeance, BUFF_VENGEANCE)
+
+REGISTER_BUFF(JUMP) {
+ this.m_prettyName = _("Jump");
+ this.m_name = "jump";
+ this.m_skin = 10;
+ this.m_color = '0.24 0.78 1';
+}
+BUFF_SPAWNFUNCS(jump, BUFF_JUMP)
+
+REGISTER_BUFF(FLIGHT) {
+ this.m_prettyName = _("Flight");
+ this.m_name = "flight";
+ this.m_skin = 11;
+ this.m_color = '0.33 0.56 1';
+}
+BUFF_SPAWNFUNCS(flight, BUFF_FLIGHT)
+
+REGISTER_BUFF(INVISIBLE) {
+ this.m_prettyName = _("Invisible");
+ this.m_name = "invisible";
+ this.m_skin = 12;
+ this.m_color = '0.5 0.5 1';
+}
+BUFF_SPAWNFUNCS(invisible, BUFF_INVISIBLE)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(invis, BUFF_INVISIBLE)
+
+REGISTER_BUFF(INFERNO) {
+ this.m_prettyName = _("Inferno");
+ this.m_name = "inferno";
+ this.m_skin = 16;
+ this.m_color = '1 0.62 0';
+}
+BUFF_SPAWNFUNCS(inferno, BUFF_INFERNO)
+
+REGISTER_BUFF(SWAPPER) {
+ this.m_prettyName = _("Swapper");
+ this.m_name = "swapper";
+ this.m_skin = 17;
+ this.m_color = '0.63 0.36 1';
+}
+BUFF_SPAWNFUNCS(swapper, BUFF_SWAPPER)
+
+REGISTER_BUFF(MAGNET) {
+ this.m_prettyName = _("Magnet");
+ this.m_name = "magnet";
+ this.m_skin = 18;
+ this.m_color = '1 0.95 0.18';
+}
+BUFF_SPAWNFUNCS(magnet, BUFF_MAGNET)
--- /dev/null
+#include "all.qh"
--- /dev/null
+#ifndef BUFFS_ALL_H
+#define BUFFS_ALL_H
+// Welcome to the stuff behind the scenes
+// Below, you will find the list of buffs
+// Add new buffs here!
+// Note: Buffs also need spawnfuncs, which are set below
+
+#include "../../../teams.qh"
+#include "../../../util.qh"
+
+REGISTER_WAYPOINT(Buff, _("Buff"), '1 0.5 0', 1);
+REGISTER_RADARICON(Buff, 1);
+
+REGISTRY(Buffs, BITS(4))
+#define Buffs_from(i) _Buffs_from(i, BUFF_Null)
+REGISTER_REGISTRY(Buffs)
+REGISTRY_CHECK(Buffs)
+
+#define REGISTER_BUFF(id) \
+ REGISTER(Buffs, BUFF, id, m_id, NEW(Buff)); \
+ REGISTER_INIT_POST(BUFF, id) { \
+ this.netname = this.m_name; \
+ this.m_itemid = BIT(this.m_id - 1); \
+ this.m_sprite = strzone(strcat("buff-", this.m_name)); \
+ } \
+ REGISTER_INIT(BUFF, id)
+
+#include "../../../items/item/pickup.qh"
+CLASS(Buff, Pickup)
+ /** bit index */
+ ATTRIB(Buff, m_itemid, int, 0)
+ ATTRIB(Buff, m_name, string, "buff")
+ ATTRIB(Buff, m_color, vector, '1 1 1')
+ ATTRIB(Buff, m_prettyName, string, "Buff")
+ ATTRIB(Buff, m_skin, int, 0)
+ ATTRIB(Buff, m_sprite, string, "")
+ METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) {
+ returns(this.m_prettyName, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.m_name));
+ }
+#ifdef SVQC
+ METHOD(Buff, m_time, float(Buff this))
+ { return cvar(strcat("g_buffs_", this.netname, "_time")); }
+#endif
+ENDCLASS(Buff)
+
+#ifdef SVQC
+ .int buffs;
+ void buff_Init(entity ent);
+ void buff_Init_Compat(entity ent, entity replacement);
+ #define BUFF_SPAWNFUNC(e, b, t) spawnfunc(item_buff_##e) { \
+ self.buffs = b.m_itemid; \
+ self.team = t; \
+ buff_Init(self); \
+ }
+ #define BUFF_SPAWNFUNCS(e, b) \
+ BUFF_SPAWNFUNC(e, b, 0) \
+ BUFF_SPAWNFUNC(e##_team1, b, NUM_TEAM_1) \
+ BUFF_SPAWNFUNC(e##_team2, b, NUM_TEAM_2) \
+ BUFF_SPAWNFUNC(e##_team3, b, NUM_TEAM_3) \
+ BUFF_SPAWNFUNC(e##_team4, b, NUM_TEAM_4)
+ #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r) spawnfunc(item_##o) { buff_Init_Compat(self, r); }
+#else
+ #define BUFF_SPAWNFUNC(e, b, t)
+ #define BUFF_SPAWNFUNCS(e, b)
+ #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r)
+#endif
+
+REGISTER_BUFF(Null);
+BUFF_SPAWNFUNCS(random, BUFF_Null)
+
+#include "all.inc"
+
+#endif
--- /dev/null
+#ifndef MUTATOR_BUFFS_H
+#define MUTATOR_BUFFS_H
+
+#include "../instagib/module.inc"
+
+bool autocvar_g_buffs_effects;
+float autocvar_g_buffs_waypoint_distance;
+bool autocvar_g_buffs_randomize;
+float autocvar_g_buffs_random_lifetime;
+bool autocvar_g_buffs_random_location;
+int autocvar_g_buffs_random_location_attempts;
+int autocvar_g_buffs_spawn_count;
+bool autocvar_g_buffs_replace_powerups;
+float autocvar_g_buffs_cooldown_activate;
+float autocvar_g_buffs_cooldown_respawn;
+float autocvar_g_buffs_resistance_blockpercent;
+float autocvar_g_buffs_medic_survive_chance;
+float autocvar_g_buffs_medic_survive_health;
+float autocvar_g_buffs_medic_rot;
+float autocvar_g_buffs_medic_max;
+float autocvar_g_buffs_medic_regen;
+float autocvar_g_buffs_vengeance_damage_multiplier;
+float autocvar_g_buffs_bash_force;
+float autocvar_g_buffs_bash_force_self;
+float autocvar_g_buffs_disability_slowtime;
+float autocvar_g_buffs_disability_speed;
+float autocvar_g_buffs_disability_rate;
+float autocvar_g_buffs_disability_weaponspeed;
+float autocvar_g_buffs_speed_speed;
+float autocvar_g_buffs_speed_rate;
+float autocvar_g_buffs_speed_weaponspeed;
+float autocvar_g_buffs_speed_damage_take;
+float autocvar_g_buffs_speed_regen;
+float autocvar_g_buffs_vampire_damage_steal;
+float autocvar_g_buffs_invisible_alpha;
+float autocvar_g_buffs_flight_gravity;
+float autocvar_g_buffs_jump_height;
+float autocvar_g_buffs_inferno_burntime_factor;
+float autocvar_g_buffs_inferno_burntime_min_time;
+float autocvar_g_buffs_inferno_burntime_target_damage;
+float autocvar_g_buffs_inferno_burntime_target_time;
+float autocvar_g_buffs_inferno_damagemultiplier;
+float autocvar_g_buffs_swapper_range;
+float autocvar_g_buffs_magnet_range_item;
+
+// ammo
+.float buff_ammo_prev_infitems;
+.int buff_ammo_prev_clipload;
+// invisible
+.float buff_invisible_prev_alpha;
+// flight
+.float buff_flight_prev_gravity;
+// disability
+.float buff_disability_time;
+.float buff_disability_effect_time;
+// common buff variables
+.float buff_effect_delay;
+
+// buff definitions
+.float buff_active;
+.float buff_activetime;
+.float buff_activetime_updated;
+.entity buff_waypoint;
+.int oldbuffs; // for updating effects
+.entity buff_model; // controls effects (TODO: make csqc)
+
+const vector BUFF_MIN = ('-16 -16 -20');
+const vector BUFF_MAX = ('16 16 20');
+
+// client side options
+.float cvar_cl_buffs_autoreplace;
+#endif
+
+#ifdef IMPLEMENTATION
+
+#include "../../../triggers/target/music.qh"
+#include "../../../gamemodes/all.qh"
+
+.float buff_time;
+void buffs_DelayedInit();
+
+REGISTER_MUTATOR(buffs, cvar("g_buffs"))
+{
+ MUTATOR_ONADD
+ {
+ addstat(STAT_BUFFS, AS_INT, buffs);
+ addstat(STAT_BUFF_TIME, AS_FLOAT, buff_time);
+
+ InitializeEntity(world, buffs_DelayedInit, INITPRIO_FINDTARGET);
+ }
+}
+
+entity buff_FirstFromFlags(int _buffs)
+{
+ if (flags)
+ {
+ FOREACH(Buffs, it.m_itemid & _buffs, LAMBDA(return it));
+ }
+ return BUFF_Null;
+}
+
+bool buffs_BuffModel_Customize()
+{SELFPARAM();
+ entity player, myowner;
+ bool same_team;
+
+ player = WaypointSprite_getviewentity(other);
+ myowner = self.owner;
+ same_team = (SAME_TEAM(player, myowner) || SAME_TEAM(player, myowner));
+
+ if(myowner.alpha <= 0.5 && !same_team && myowner.alpha != 0)
+ return false;
+
+ if(MUTATOR_CALLHOOK(BuffModel_Customize, self, player))
+ return false;
+
+ if(player == myowner || (IS_SPEC(other) && other.enemy == myowner))
+ {
+ // somewhat hide the model, but keep the glow
+ self.effects = 0;
+ self.alpha = -1;
+ }
+ else
+ {
+ self.effects = EF_FULLBRIGHT | EF_LOWPRECISION;
+ self.alpha = 1;
+ }
+ return true;
+}
+
+void buffs_BuffModel_Spawn(entity player)
+{
+ player.buff_model = spawn();
+ setmodel(player.buff_model, MDL_BUFF);
+ setsize(player.buff_model, '0 0 -40', '0 0 40');
+ setattachment(player.buff_model, player, "");
+ setorigin(player.buff_model, '0 0 1' * (player.buff_model.maxs.z * 1));
+ player.buff_model.owner = player;
+ player.buff_model.scale = 0.7;
+ player.buff_model.pflags = PFLAGS_FULLDYNAMIC;
+ player.buff_model.light_lev = 200;
+ player.buff_model.customizeentityforclient = buffs_BuffModel_Customize;
+}
+
+vector buff_GlowColor(entity buff)
+{
+ //if(buff.team) { return Team_ColorRGB(buff.team); }
+ return buff.m_color;
+}
+
+void buff_Effect(entity player, string eff)
+{SELFPARAM();
+ if(!autocvar_g_buffs_effects) { return; }
+
+ if(time >= self.buff_effect_delay)
+ {
+ Send_Effect_(eff, player.origin + ((player.mins + player.maxs) * 0.5), '0 0 0', 1);
+ self.buff_effect_delay = time + 0.05; // prevent spam
+ }
+}
+
+// buff item
+float buff_Waypoint_visible_for_player(entity plr)
+{SELFPARAM();
+ if(!self.owner.buff_active && !self.owner.buff_activetime)
+ return false;
+
+ if (plr.buffs)
+ {
+ return plr.cvar_cl_buffs_autoreplace == false || plr.buffs != self.owner.buffs;
+ }
+
+ return WaypointSprite_visible_for_player(plr);
+}
+
+void buff_Waypoint_Spawn(entity e)
+{
+ entity buff = buff_FirstFromFlags(e.buffs);
+ entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, world, e.team, e, buff_waypoint, true, RADARICON_Buff);
+ wp.wp_extra = buff.m_id;
+ WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_Buff, e.glowmod);
+ e.buff_waypoint.waypointsprite_visible_for_player = buff_Waypoint_visible_for_player;
+}
+
+void buff_SetCooldown(float cd)
+{SELFPARAM();
+ cd = max(0, cd);
+
+ if(!self.buff_waypoint)
+ buff_Waypoint_Spawn(self);
+
+ WaypointSprite_UpdateBuildFinished(self.buff_waypoint, time + cd);
+ self.buff_activetime = cd;
+ self.buff_active = !cd;
+}
+
+void buff_Respawn(entity ent)
+{SELFPARAM();
+ if(gameover) { return; }
+
+ vector oldbufforigin = ent.origin;
+
+ if(!MoveToRandomMapLocation(ent, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, ((autocvar_g_buffs_random_location_attempts > 0) ? autocvar_g_buffs_random_location_attempts : 10), 1024, 256))
+ {
+ entity spot = SelectSpawnPoint(true);
+ setorigin(ent, spot.origin + '0 0 200');
+ ent.angles = spot.angles;
+ }
+
+ tracebox(ent.origin, ent.mins * 1.5, self.maxs * 1.5, ent.origin, MOVE_NOMONSTERS, ent);
+
+ setorigin(ent, trace_endpos); // attempt to unstick
+
+ ent.movetype = MOVETYPE_TOSS;
+
+ makevectors(ent.angles);
+ ent.velocity = '0 0 200';
+ ent.angles = '0 0 0';
+ if(autocvar_g_buffs_random_lifetime > 0)
+ ent.lifetime = time + autocvar_g_buffs_random_lifetime;
+
+ Send_Effect(EFFECT_ELECTRO_COMBO, oldbufforigin + ((ent.mins + ent.maxs) * 0.5), '0 0 0', 1);
+ Send_Effect(EFFECT_ELECTRO_COMBO, CENTER_OR_VIEWOFS(ent), '0 0 0', 1);
+
+ WaypointSprite_Ping(ent.buff_waypoint);
+
+ sound(ent, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
+}
+
+void buff_Touch()
+{SELFPARAM();
+ if(gameover) { return; }
+
+ if(ITEM_TOUCH_NEEDKILL())
+ {
+ buff_Respawn(self);
+ return;
+ }
+
+ if((self.team && DIFF_TEAM(other, self))
+ || (other.frozen)
+ || (other.vehicle)
+ || (!self.buff_active)
+ )
+ {
+ // can't touch this
+ return;
+ }
+
+ if(MUTATOR_CALLHOOK(BuffTouch, self, other))
+ return;
+
+ if(!IS_PLAYER(other))
+ return; // incase mutator changed other
+
+ if (other.buffs)
+ {
+ if (other.cvar_cl_buffs_autoreplace && other.buffs != self.buffs)
+ {
+ int buffid = buff_FirstFromFlags(other.buffs).m_id;
+ //Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_DROP, other.buffs);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ITEM_BUFF_LOST, other.netname, buffid);
+
+ other.buffs = 0;
+ //sound(other, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+ }
+ else { return; } // do nothing
+ }
+
+ self.owner = other;
+ self.buff_active = false;
+ self.lifetime = 0;
+ int buffid = buff_FirstFromFlags(self.buffs).m_id;
+ Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_GOT, buffid);
+ Send_Notification(NOTIF_ALL_EXCEPT, other, MSG_INFO, INFO_ITEM_BUFF, other.netname, buffid);
+
+ Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
+ sound(other, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
+ other.buffs |= (self.buffs);
+}
+
+float buff_Available(entity buff)
+{
+ if (buff == BUFF_Null)
+ return false;
+ if (buff == BUFF_AMMO && ((start_items & IT_UNLIMITED_WEAPON_AMMO) || (start_items & IT_UNLIMITED_AMMO) || (cvar("g_melee_only"))))
+ return false;
+ if (buff == BUFF_VAMPIRE && cvar("g_vampire"))
+ return false;
+ return cvar(strcat("g_buffs_", buff.m_name));
+}
+
+.int buff_seencount;
+
+void buff_NewType(entity ent, float cb)
+{
+ RandomSelection_Init();
+ FOREACH(Buffs, buff_Available(it), LAMBDA(
+ it.buff_seencount += 1;
+ // if it's already been chosen, give it a lower priority
+ RandomSelection_Add(world, it.m_itemid, string_null, 1, max(0.2, 1 / it.buff_seencount));
+ ));
+ ent.buffs = RandomSelection_chosen_float;
+}
+
+void buff_Think()
+{SELFPARAM();
+ if(self.buffs != self.oldbuffs)
+ {
+ entity buff = buff_FirstFromFlags(self.buffs);
+ self.color = buff.m_color;
+ self.glowmod = buff_GlowColor(buff);
+ self.skin = buff.m_skin;
+
+ setmodel(self, MDL_BUFF);
+
+ if(self.buff_waypoint)
+ {
+ //WaypointSprite_Disown(self.buff_waypoint, 1);
+ WaypointSprite_Kill(self.buff_waypoint);
+ buff_Waypoint_Spawn(self);
+ if(self.buff_activetime)
+ WaypointSprite_UpdateBuildFinished(self.buff_waypoint, time + self.buff_activetime - frametime);
+ }
+
+ self.oldbuffs = self.buffs;
+ }
+
+ if(!gameover)
+ if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
+ if(!self.buff_activetime_updated)
+ {
+ buff_SetCooldown(self.buff_activetime);
+ self.buff_activetime_updated = true;
+ }
+
+ if(!self.buff_active && !self.buff_activetime)
+ if(!self.owner || self.owner.frozen || self.owner.deadflag != DEAD_NO || !self.owner.iscreature || !(self.owner.buffs & self.buffs))
+ {
+ buff_SetCooldown(autocvar_g_buffs_cooldown_respawn + frametime);
+ self.owner = world;
+ if(autocvar_g_buffs_randomize)
+ buff_NewType(self, self.buffs);
+
+ if(autocvar_g_buffs_random_location || (self.spawnflags & 64))
+ buff_Respawn(self);
+ }
+
+ if(self.buff_activetime)
+ if(!gameover)
+ if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
+ {
+ self.buff_activetime = max(0, self.buff_activetime - frametime);
+
+ if(!self.buff_activetime)
+ {
+ self.buff_active = true;
+ sound(self, CH_TRIGGER, SND_STRENGTH_RESPAWN, VOL_BASE, ATTN_NORM);
+ Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
+ }
+ }
+
+ if(self.buff_active)
+ {
+ if(self.team && !self.buff_waypoint)
+ buff_Waypoint_Spawn(self);
+
+ if(self.lifetime)
+ if(time >= self.lifetime)
+ buff_Respawn(self);
+ }
+
+ self.nextthink = time;
+ //self.angles_y = time * 110.1;
+}
+
+void buff_Waypoint_Reset()
+{SELFPARAM();
+ WaypointSprite_Kill(self.buff_waypoint);
+
+ if(self.buff_activetime) { buff_Waypoint_Spawn(self); }
+}
+
+void buff_Reset()
+{SELFPARAM();
+ if(autocvar_g_buffs_randomize)
+ buff_NewType(self, self.buffs);
+ self.owner = world;
+ buff_SetCooldown(autocvar_g_buffs_cooldown_activate);
+ buff_Waypoint_Reset();
+ self.buff_activetime_updated = false;
+
+ if(autocvar_g_buffs_random_location || (self.spawnflags & 64))
+ buff_Respawn(self);
+}
+
+float buff_Customize()
+{SELFPARAM();
+ entity player = WaypointSprite_getviewentity(other);
+ if(!self.buff_active || (self.team && DIFF_TEAM(player, self)))
+ {
+ self.alpha = 0.3;
+ if(self.effects & EF_FULLBRIGHT) { self.effects &= ~(EF_FULLBRIGHT); }
+ self.pflags = 0;
+ }
+ else
+ {
+ self.alpha = 1;
+ if(!(self.effects & EF_FULLBRIGHT)) { self.effects |= EF_FULLBRIGHT; }
+ self.light_lev = 220 + 36 * sin(time);
+ self.pflags = PFLAGS_FULLDYNAMIC;
+ }
+ return true;
+}
+
+void buff_Init(entity ent)
+{SELFPARAM();
+ if(!cvar("g_buffs")) { remove(ent); return; }
+
+ if(!teamplay && ent.team) { ent.team = 0; }
+
+ entity buff = buff_FirstFromFlags(self.buffs);
+
+ setself(ent);
+ if(!self.buffs || buff_Available(buff))
+ buff_NewType(self, 0);
+
+ self.classname = "item_buff";
+ self.solid = SOLID_TRIGGER;
+ self.flags = FL_ITEM;
+ self.think = buff_Think;
+ self.touch = buff_Touch;
+ self.reset = buff_Reset;
+ self.nextthink = time + 0.1;
+ self.gravity = 1;
+ self.movetype = MOVETYPE_TOSS;
+ self.scale = 1;
+ self.skin = buff.m_skin;
+ self.effects = EF_FULLBRIGHT | EF_STARDUST | EF_NOSHADOW;
+ self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
+ self.customizeentityforclient = buff_Customize;
+ //self.gravity = 100;
+ self.color = buff.m_color;
+ self.glowmod = buff_GlowColor(self);
+ buff_SetCooldown(autocvar_g_buffs_cooldown_activate + game_starttime);
+ self.buff_active = !self.buff_activetime;
+ self.pflags = PFLAGS_FULLDYNAMIC;
+
+ if(self.spawnflags & 1)
+ self.noalign = true;
+
+ if(self.noalign)
+ self.movetype = MOVETYPE_NONE; // reset by random location
+
+ setmodel(self, MDL_BUFF);
+ setsize(self, BUFF_MIN, BUFF_MAX);
+
+ if(cvar("g_buffs_random_location") || (self.spawnflags & 64))
+ buff_Respawn(self);
+
+ setself(this);
+}
+
+void buff_Init_Compat(entity ent, entity replacement)
+{
+ if (ent.spawnflags & 2)
+ ent.team = NUM_TEAM_1;
+ else if (ent.spawnflags & 4)
+ ent.team = NUM_TEAM_2;
+
+ ent.buffs = replacement.m_itemid;
+
+ buff_Init(ent);
+}
+
+void buff_SpawnReplacement(entity ent, entity old)
+{
+ setorigin(ent, old.origin);
+ ent.angles = old.angles;
+ ent.noalign = (old.noalign || (old.spawnflags & 1));
+
+ buff_Init(ent);
+}
+
+void buff_Vengeance_DelayedDamage()
+{SELFPARAM();
+ if(self.enemy)
+ Damage(self.enemy, self.owner, self.owner, self.dmg, DEATH_BUFF.m_id, self.enemy.origin, '0 0 0');
+
+ remove(self);
+ return;
+}
+
+float buff_Inferno_CalculateTime(float x, float offset_x, float offset_y, float intersect_x, float intersect_y, float base)
+{
+ return offset_y + (intersect_y - offset_y) * logn(((x - offset_x) * ((base - 1) / intersect_x)) + 1, base);
+}
+
+// mutator hooks
+MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_SplitHealthArmor)
+{
+ if(frag_deathtype == DEATH_BUFF.m_id) { return false; }
+
+ if(frag_target.buffs & BUFF_RESISTANCE.m_itemid)
+ {
+ vector v = healtharmor_applydamage(50, autocvar_g_buffs_resistance_blockpercent, frag_deathtype, frag_damage);
+ damage_take = v.x;
+ damage_save = v.y;
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_Calculate)
+{
+ if(frag_deathtype == DEATH_BUFF.m_id) { return false; }
+
+ if(frag_target.buffs & BUFF_SPEED.m_itemid)
+ if(frag_target != frag_attacker)
+ frag_damage *= autocvar_g_buffs_speed_damage_take;
+
+ if(frag_target.buffs & BUFF_MEDIC.m_itemid)
+ if((frag_target.health - frag_damage) <= 0)
+ if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+ if(frag_attacker)
+ if(random() <= autocvar_g_buffs_medic_survive_chance)
+ frag_damage = max(5, frag_target.health - autocvar_g_buffs_medic_survive_health);
+
+ if(frag_target.buffs & BUFF_JUMP.m_itemid)
+ if(frag_deathtype == DEATH_FALL.m_id)
+ frag_damage = 0;
+
+ if(frag_target.buffs & BUFF_VENGEANCE.m_itemid)
+ if(frag_attacker)
+ if(frag_attacker != frag_target)
+ if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+ {
+ entity dmgent = spawn();
+
+ dmgent.dmg = frag_damage * autocvar_g_buffs_vengeance_damage_multiplier;
+ dmgent.enemy = frag_attacker;
+ dmgent.owner = frag_target;
+ dmgent.think = buff_Vengeance_DelayedDamage;
+ dmgent.nextthink = time + 0.1;
+ }
+
+ if(frag_target.buffs & BUFF_BASH.m_itemid)
+ if(frag_attacker != frag_target)
+ if(vlen(frag_force))
+ frag_force = '0 0 0';
+
+ if(frag_attacker.buffs & BUFF_BASH.m_itemid)
+ if(vlen(frag_force))
+ if(frag_attacker == frag_target)
+ frag_force *= autocvar_g_buffs_bash_force_self;
+ else
+ frag_force *= autocvar_g_buffs_bash_force;
+
+ if(frag_attacker.buffs & BUFF_DISABILITY.m_itemid)
+ if(frag_target != frag_attacker)
+ frag_target.buff_disability_time = time + autocvar_g_buffs_disability_slowtime;
+
+ if(frag_attacker.buffs & BUFF_MEDIC.m_itemid)
+ if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC)
+ if(SAME_TEAM(frag_attacker, frag_target))
+ if(frag_attacker != frag_target)
+ {
+ frag_target.health = min(g_pickup_healthmega_max, frag_target.health + frag_damage);
+ frag_damage = 0;
+ }
+
+ if(frag_attacker.buffs & BUFF_INFERNO.m_itemid)
+ if(frag_target != frag_attacker) {
+ float time = buff_Inferno_CalculateTime(
+ frag_damage,
+ 0,
+ autocvar_g_buffs_inferno_burntime_min_time,
+ autocvar_g_buffs_inferno_burntime_target_damage,
+ autocvar_g_buffs_inferno_burntime_target_time,
+ autocvar_g_buffs_inferno_burntime_factor
+ );
+ Fire_AddDamage(frag_target, frag_attacker, (frag_damage * autocvar_g_buffs_inferno_damagemultiplier) * time, time, DEATH_BUFF.m_id);
+ }
+
+ // this... is ridiculous (TODO: fix!)
+ if(frag_attacker.buffs & BUFF_VAMPIRE.m_itemid)
+ if(!frag_target.vehicle)
+ if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC)
+ if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+ if(frag_target.deadflag == DEAD_NO)
+ if(IS_PLAYER(frag_target) || IS_MONSTER(frag_target))
+ if(frag_attacker != frag_target)
+ if(!frag_target.frozen)
+ if(frag_target.takedamage)
+ if(DIFF_TEAM(frag_attacker, frag_target))
+ {
+ frag_attacker.health = bound(0, frag_attacker.health + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.health), g_pickup_healthsmall_max);
+ if(frag_target.armorvalue)
+ frag_attacker.armorvalue = bound(0, frag_attacker.armorvalue + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.armorvalue), g_pickup_armorsmall_max);
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs,PlayerSpawn)
+{SELFPARAM();
+ self.buffs = 0;
+ // reset timers here to prevent them continuing after re-spawn
+ self.buff_disability_time = 0;
+ self.buff_disability_effect_time = 0;
+ return false;
+}
+
+.float stat_sv_maxspeed;
+.float stat_sv_airspeedlimit_nonqw;
+.float stat_sv_jumpvelocity;
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
+{SELFPARAM();
+ if(self.buffs & BUFF_SPEED.m_itemid)
+ {
+ self.stat_sv_maxspeed *= autocvar_g_buffs_speed_speed;
+ self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_speed_speed;
+ }
+
+ if(time < self.buff_disability_time)
+ {
+ self.stat_sv_maxspeed *= autocvar_g_buffs_disability_speed;
+ self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_disability_speed;
+ }
+
+ if(self.buffs & BUFF_JUMP.m_itemid)
+ {
+ // automatically reset, no need to worry
+ self.stat_sv_jumpvelocity = autocvar_g_buffs_jump_height;
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerJump)
+{SELFPARAM();
+ if(self.buffs & BUFF_JUMP.m_itemid)
+ player_jumpheight = autocvar_g_buffs_jump_height;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, MonsterMove)
+{SELFPARAM();
+ if(time < self.buff_disability_time)
+ {
+ monster_speed_walk *= autocvar_g_buffs_disability_speed;
+ monster_speed_run *= autocvar_g_buffs_disability_speed;
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerDies)
+{SELFPARAM();
+ if(self.buffs)
+ {
+ int buffid = buff_FirstFromFlags(self.buffs).m_id;
+ Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
+ self.buffs = 0;
+
+ if(self.buff_model)
+ {
+ remove(self.buff_model);
+ self.buff_model = world;
+ }
+ }
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerUseKey, CBC_ORDER_FIRST)
+{SELFPARAM();
+ if(MUTATOR_RETURNVALUE || gameover) { return false; }
+ if(self.buffs)
+ {
+ int buffid = buff_FirstFromFlags(self.buffs).m_id;
+ Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, buffid);
+ Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
+
+ self.buffs = 0;
+ sound(self, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+ return true;
+ }
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
+{SELFPARAM();
+ if(MUTATOR_RETURNVALUE || gameover) { return false; }
+
+ if(self.buffs & BUFF_SWAPPER.m_itemid)
+ {
+ float best_distance = autocvar_g_buffs_swapper_range;
+ entity closest = world;
+ entity player;
+ FOR_EACH_PLAYER(player)
+ if(DIFF_TEAM(self, player))
+ if(player.deadflag == DEAD_NO && !player.frozen && !player.vehicle)
+ if(vlen(self.origin - player.origin) <= best_distance)
+ {
+ best_distance = vlen(self.origin - player.origin);
+ closest = player;
+ }
+
+ if(closest)
+ {
+ vector my_org, my_vel, my_ang, their_org, their_vel, their_ang;
+
+ my_org = self.origin;
+ my_vel = self.velocity;
+ my_ang = self.angles;
+ their_org = closest.origin;
+ their_vel = closest.velocity;
+ their_ang = closest.angles;
+
+ Drop_Special_Items(closest);
+
+ MUTATOR_CALLHOOK(PortalTeleport, self); // initiate flag dropper
+
+ setorigin(self, their_org);
+ setorigin(closest, my_org);
+
+ closest.velocity = my_vel;
+ closest.angles = my_ang;
+ closest.fixangle = true;
+ closest.oldorigin = my_org;
+ closest.oldvelocity = my_vel;
+ self.velocity = their_vel;
+ self.angles = their_ang;
+ self.fixangle = true;
+ self.oldorigin = their_org;
+ self.oldvelocity = their_vel;
+
+ // set pusher so self gets the kill if they fall into void
+ closest.pusher = self;
+ closest.pushltime = time + autocvar_g_maxpushtime;
+ closest.istypefrag = closest.BUTTON_CHAT;
+
+ Send_Effect(EFFECT_ELECTRO_COMBO, their_org, '0 0 0', 1);
+ Send_Effect(EFFECT_ELECTRO_COMBO, my_org, '0 0 0', 1);
+
+ sound(self, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
+ sound(closest, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
+
+ // TODO: add a counter to handle how many times one can teleport, and a delay to prevent spam
+ self.buffs = 0;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool buffs_RemovePlayer(entity player)
+{
+ if(player.buff_model)
+ {
+ remove(player.buff_model);
+ player.buff_model = world;
+ }
+
+ // also reset timers here to prevent them continuing after spectating
+ player.buff_disability_time = 0;
+ player.buff_disability_effect_time = 0;
+
+ return false;
+}
+MUTATOR_HOOKFUNCTION(buffs, MakePlayerObserver) { return buffs_RemovePlayer(self); }
+MUTATOR_HOOKFUNCTION(buffs, ClientDisconnect) { return buffs_RemovePlayer(self); }
+
+MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint)
+{SELFPARAM();
+ entity e = WaypointSprite_getviewentity(other);
+
+ // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
+ // but only apply this to real players, not to spectators
+ if((self.owner.flags & FL_CLIENT) && (self.owner.buffs & BUFF_INVISIBLE.m_itemid) && (e == other))
+ if(DIFF_TEAM(self.owner, e))
+ return true;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, OnEntityPreSpawn, CBC_ORDER_LAST)
+{SELFPARAM();
+ if (self.classname == "item_flight" && cvar("g_buffs") && cvar("g_buffs_flight"))
+ {
+ buff_Init_Compat(self, BUFF_FLIGHT);
+ return true;
+ }
+ if(autocvar_g_buffs_replace_powerups)
+ switch(self.classname)
+ {
+ case "item_strength":
+ case "item_invincible":
+ {
+ entity e = spawn();
+ buff_SpawnReplacement(e, self);
+ return true;
+ }
+ }
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, WeaponRateFactor)
+{SELFPARAM();
+ if(self.buffs & BUFF_SPEED.m_itemid)
+ weapon_rate *= autocvar_g_buffs_speed_rate;
+
+ if(time < self.buff_disability_time)
+ weapon_rate *= autocvar_g_buffs_disability_rate;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, WeaponSpeedFactor)
+{SELFPARAM();
+ if(self.buffs & BUFF_SPEED.m_itemid)
+ ret_float *= autocvar_g_buffs_speed_weaponspeed;
+
+ if(time < self.buff_disability_time)
+ ret_float *= autocvar_g_buffs_disability_weaponspeed;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
+{SELFPARAM();
+ if(gameover || self.deadflag != DEAD_NO) { return false; }
+
+ if(time < self.buff_disability_time)
+ if(time >= self.buff_disability_effect_time)
+ {
+ Send_Effect(EFFECT_SMOKING, self.origin + ((self.mins + self.maxs) * 0.5), '0 0 0', 1);
+ self.buff_disability_effect_time = time + 0.5;
+ }
+
+ // handle buff lost status
+ // 1: notify everyone else
+ // 2: notify carrier as well
+ int buff_lost = 0;
+
+ if(self.buff_time)
+ if(time >= self.buff_time)
+ buff_lost = 2;
+
+ if(self.frozen) { buff_lost = 1; }
+
+ if(buff_lost)
+ {
+ if(self.buffs)
+ {
+ int buffid = buff_FirstFromFlags(self.buffs).m_id;
+ Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
+ if(buff_lost >= 2)
+ {
+ Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
+ sound(self, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+ }
+ self.buffs = 0;
+ }
+ }
+
+ if(self.buffs & BUFF_MAGNET.m_itemid)
+ {
+ vector pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item;
+ for(other = world; (other = findflags(other, flags, FL_ITEM)); )
+ if(boxesoverlap(self.absmin - pickup_size, self.absmax + pickup_size, other.absmin, other.absmax))
+ {
+ setself(other);
+ other = this;
+ if(self.touch)
+ self.touch();
+ other = self;
+ setself(this);
+ }
+ }
+
+ if(self.buffs & BUFF_AMMO.m_itemid)
+ if(self.clip_size)
+ self.clip_load = self.(weapon_load[self.switchweapon]) = self.clip_size;
+
+ if((self.buffs & BUFF_INVISIBLE.m_itemid) && (self.oldbuffs & BUFF_INVISIBLE.m_itemid))
+ if(self.alpha != autocvar_g_buffs_invisible_alpha)
+ self.alpha = autocvar_g_buffs_invisible_alpha; // powerups reset alpha, so we must enforce this (TODO)
+
+#define BUFF_ONADD(b) if ( (self.buffs & (b).m_itemid) && !(self.oldbuffs & (b).m_itemid))
+#define BUFF_ONREM(b) if (!(self.buffs & (b).m_itemid) && (self.oldbuffs & (b).m_itemid))
+
+ if(self.buffs != self.oldbuffs)
+ {
+ entity buff = buff_FirstFromFlags(self.buffs);
+ float bufftime = buff != BUFF_Null ? buff.m_time(buff) : 0;
+ self.buff_time = (bufftime) ? time + bufftime : 0;
+
+ BUFF_ONADD(BUFF_AMMO)
+ {
+ self.buff_ammo_prev_infitems = (self.items & IT_UNLIMITED_WEAPON_AMMO);
+ self.items |= IT_UNLIMITED_WEAPON_AMMO;
+
+ if(self.clip_load)
+ self.buff_ammo_prev_clipload = self.clip_load;
+ self.clip_load = self.(weapon_load[self.switchweapon]) = self.clip_size;
+ }
+
+ BUFF_ONREM(BUFF_AMMO)
+ {
+ if(self.buff_ammo_prev_infitems)
+ self.items |= IT_UNLIMITED_WEAPON_AMMO;
+ else
+ self.items &= ~IT_UNLIMITED_WEAPON_AMMO;
+
+ if(self.buff_ammo_prev_clipload)
+ self.clip_load = self.buff_ammo_prev_clipload;
+ }
+
+ BUFF_ONADD(BUFF_INVISIBLE)
+ {
+ if(time < self.strength_finished && g_instagib)
+ self.alpha = autocvar_g_instagib_invis_alpha;
+ else
+ self.alpha = self.buff_invisible_prev_alpha;
+ self.alpha = autocvar_g_buffs_invisible_alpha;
+ }
+
+ BUFF_ONREM(BUFF_INVISIBLE)
+ self.alpha = self.buff_invisible_prev_alpha;
+
+ BUFF_ONADD(BUFF_FLIGHT)
+ {
+ self.buff_flight_prev_gravity = self.gravity;
+ self.gravity = autocvar_g_buffs_flight_gravity;
+ }
+
+ BUFF_ONREM(BUFF_FLIGHT)
+ self.gravity = self.buff_flight_prev_gravity;
+
+ self.oldbuffs = self.buffs;
+ if(self.buffs)
+ {
+ if(!self.buff_model)
+ buffs_BuffModel_Spawn(self);
+
+ self.buff_model.color = buff.m_color;
+ self.buff_model.glowmod = buff_GlowColor(self.buff_model);
+ self.buff_model.skin = buff.m_skin;
+
+ self.effects |= EF_NOSHADOW;
+ }
+ else
+ {
+ remove(self.buff_model);
+ self.buff_model = world;
+
+ self.effects &= ~(EF_NOSHADOW);
+ }
+ }
+
+ if(self.buff_model)
+ {
+ self.buff_model.effects = self.effects;
+ self.buff_model.effects |= EF_LOWPRECISION;
+ self.buff_model.effects = self.buff_model.effects & EFMASK_CHEAP; // eat performance
+
+ self.buff_model.alpha = self.alpha;
+ }
+
+#undef BUFF_ONADD
+#undef BUFF_ONREM
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, SpectateCopy)
+{SELFPARAM();
+ self.buffs = other.buffs;
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, VehicleEnter)
+{
+ vh_vehicle.buffs = vh_player.buffs;
+ vh_player.buffs = 0;
+ vh_vehicle.buff_time = vh_player.buff_time - time;
+ vh_player.buff_time = 0;
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, VehicleExit)
+{
+ vh_player.buffs = vh_player.oldbuffs = vh_vehicle.buffs;
+ vh_vehicle.buffs = 0;
+ vh_player.buff_time = time + vh_vehicle.buff_time;
+ vh_vehicle.buff_time = 0;
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerRegen)
+{SELFPARAM();
+ if(self.buffs & BUFF_MEDIC.m_itemid)
+ {
+ regen_mod_rot = autocvar_g_buffs_medic_rot;
+ regen_mod_limit = regen_mod_max = autocvar_g_buffs_medic_max;
+ regen_mod_regen = autocvar_g_buffs_medic_regen;
+ }
+
+ if(self.buffs & BUFF_SPEED.m_itemid)
+ regen_mod_regen = autocvar_g_buffs_speed_regen;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, GetCvars)
+{
+ GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_buffs_autoreplace, "cl_buffs_autoreplace");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":Buffs");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Buffs");
+ return false;
+}
+
+void buffs_DelayedInit()
+{
+ if(autocvar_g_buffs_spawn_count > 0)
+ if(find(world, classname, "item_buff") == world)
+ {
+ float i;
+ for(i = 0; i < autocvar_g_buffs_spawn_count; ++i)
+ {
+ entity e = spawn();
+ e.spawnflags |= 64; // always randomize
+ e.velocity = randomvec() * 250; // this gets reset anyway if random location works
+ buff_Init(e);
+ }
+ }
+}
+#endif
--- /dev/null
+#include "all.qc"
+#ifdef SVQC
+#include "buffs.qc"
+#endif
+
+#ifdef IMPLEMENTATION
+
+string BUFF_NAME(int i)
+{
+ Buff b = Buffs_from(i);
+ return sprintf("%s%s", rgb_to_hexcolor(b.m_color), b.m_prettyName);
+}
+
+#ifndef MENUQC
+REGISTER_MUTATOR(buffs_flight, true);
+MUTATOR_HOOKFUNCTION(buffs_flight, IsFlying)
+{
+ noref entity e = MUTATOR_ARGV(0, entity);
+ return BUFFS_STAT(e) & BUFF_FLIGHT.m_itemid;
+}
+#endif
+
+#ifdef CSQC
+REGISTER_MUTATOR(cl_buffs, true);
+MUTATOR_HOOKFUNCTION(cl_buffs, HUD_Powerups_add)
+{
+ int allBuffs = getstati(STAT_BUFFS, 0, 24);
+ FOREACH(Buffs, it.m_itemid & allBuffs, LAMBDA(
+ addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, getstatf(STAT_BUFF_TIME) - time, 99), 60);
+ ));
+}
+MUTATOR_HOOKFUNCTION(cl_buffs, WP_Format)
+{
+ entity this = MUTATOR_ARGV(0, entity);
+ string s = MUTATOR_ARGV(0, string);
+ if (s == WP_Buff.netname || s == RADARICON_Buff.netname)
+ {
+ Buff b = Buffs_from(this.wp_extra);
+ MUTATOR_ARGV(0, vector) = b.m_color;
+ MUTATOR_ARGV(0, string) = b.m_prettyName;
+ return true;
+ }
+}
+
+#endif
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+float autocvar_g_campcheck_damage;
+float autocvar_g_campcheck_distance;
+float autocvar_g_campcheck_interval;
+
+REGISTER_MUTATOR(campcheck, cvar("g_campcheck"));
+
+.float campcheck_nextcheck;
+.float campcheck_traveled_distance;
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerDies)
+{SELFPARAM();
+ Kill_Notification(NOTIF_ONE, self, MSG_CENTER_CPID, CPID_CAMPCHECK);
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerDamage_Calculate)
+{
+ if(IS_PLAYER(frag_target))
+ if(IS_PLAYER(frag_attacker))
+ if(frag_attacker != frag_target)
+ {
+ frag_target.campcheck_traveled_distance = autocvar_g_campcheck_distance;
+ frag_attacker.campcheck_traveled_distance = autocvar_g_campcheck_distance;
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerPreThink)
+{SELFPARAM();
+ if(!gameover)
+ if(!warmup_stage) // don't consider it camping during warmup?
+ if(time >= game_starttime)
+ if(IS_PLAYER(self))
+ if(IS_REAL_CLIENT(self)) // bots may camp, but that's no reason to constantly kill them
+ if(self.deadflag == DEAD_NO)
+ if(!self.frozen)
+ if(!self.BUTTON_CHAT)
+ if(autocvar_g_campcheck_interval)
+ {
+ vector dist;
+
+ // calculate player movement (in 2 dimensions only, so jumping on one spot doesn't count as movement)
+ dist = self.prevorigin - self.origin;
+ dist.z = 0;
+ self.campcheck_traveled_distance += fabs(vlen(dist));
+
+ if((autocvar_g_campaign && !campaign_bots_may_start) || (time < game_starttime) || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
+ {
+ self.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
+ self.campcheck_traveled_distance = 0;
+ }
+
+ if(time > self.campcheck_nextcheck)
+ {
+ if(self.campcheck_traveled_distance < autocvar_g_campcheck_distance)
+ {
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_CAMPCHECK);
+ if(self.vehicle)
+ Damage(self.vehicle, self, self, autocvar_g_campcheck_damage * 2, DEATH_CAMP.m_id, self.vehicle.origin, '0 0 0');
+ else
+ Damage(self, self, self, bound(0, autocvar_g_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP.m_id, self.origin, '0 0 0');
+ }
+ self.campcheck_nextcheck = time + autocvar_g_campcheck_interval;
+ self.campcheck_traveled_distance = 0;
+ }
+
+ return false;
+ }
+
+ self.campcheck_nextcheck = time + autocvar_g_campcheck_interval; // one of the above checks failed, so keep the timer up to date
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerSpawn)
+{SELFPARAM();
+ self.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
+ self.campcheck_traveled_distance = 0;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":CampCheck");
+ return false;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "campcheck.qc"
+#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-
-#include "../../util.qh"
-
-#ifdef CSQC
-#include "../../movetypes/movetypes.qh"
-#include "../../../client/rubble.qh"
-#endif
-
-REGISTER_MUTATOR(casings, true);
-
-#ifdef SVQC
-void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner)
-{SELFPARAM();
- vector org = self.origin + self.view_ofs + self.weaponentity.spawnorigin.x * v_forward - self.weaponentity.spawnorigin.y * v_right + self.weaponentity.spawnorigin.z * v_up;
-
- if (!sound_allowed(MSG_BROADCAST, casingowner))
- casingtype |= 0x80;
-
- WriteByte(MSG_ALL, SVC_TEMPENTITY);
- WriteMutator(MSG_ALL, casings);
- WriteByte(MSG_ALL, casingtype);
- WriteCoord(MSG_ALL, org.x);
- WriteCoord(MSG_ALL, org.y);
- WriteCoord(MSG_ALL, org.z);
- WriteShort(MSG_ALL, compressShortVector(vel)); // actually compressed velocity
- WriteByte(MSG_ALL, ang.x * 256 / 360);
- WriteByte(MSG_ALL, ang.y * 256 / 360);
- WriteByte(MSG_ALL, ang.z * 256 / 360);
-}
-#endif
-
-#ifdef CSQC
-entityclass(Casing);
-class(Casing) .float alpha;
-class(Casing) .bool silent;
-class(Casing) .int state;
-class(Casing) .float cnt;
-
-void Casing_Delete()
-{SELFPARAM();
- remove(self);
-}
-
-void Casing_Draw(entity this)
-{
- if (self.move_flags & FL_ONGROUND)
- {
- self.move_angles_x = 0;
- self.move_angles_z = 0;
- self.flags &= ~FL_ONGROUND;
- }
-
- Movetype_Physics_MatchTicrate(autocvar_cl_casings_ticrate, autocvar_cl_casings_sloppy);
- if (wasfreed(self))
- return; // deleted by touch function
-
- self.renderflags = 0;
- self.alpha = bound(0, self.cnt - time, 1);
-
- if (self.alpha < ALPHA_MIN_VISIBLE)
- {
- Casing_Delete();
- self.drawmask = 0;
- }
-}
-
-SOUND(BRASS1, W_Sound("brass1"));
-SOUND(BRASS2, W_Sound("brass2"));
-SOUND(BRASS3, W_Sound("brass3"));
-Sound SND_BRASS_RANDOM() {
- return Sounds[SND_BRASS1.m_id + floor(prandom() * 3)];
-}
-SOUND(CASINGS1, W_Sound("casings1"));
-SOUND(CASINGS2, W_Sound("casings2"));
-SOUND(CASINGS3, W_Sound("casings3"));
-Sound SND_CASINGS_RANDOM() {
- return Sounds[SND_CASINGS1.m_id + floor(prandom() * 3)];
-}
-
-void Casing_Touch()
-{SELFPARAM();
- if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
- {
- Casing_Delete();
- return;
- }
-
- if (!self.silent)
- if (!trace_ent || trace_ent.solid == SOLID_BSP)
- {
- if (vlen(self.velocity) > 50)
- {
- if (time >= self.nextthink)
- {
- Sound s;
- switch (self.state)
- {
- case 1:
- s = SND_CASINGS_RANDOM();
- break;
- default:
- s = SND_BRASS_RANDOM();
- break;
- }
-
- sound (self, CH_SHOTS, s, VOL_BASE, ATTEN_LARGE);
- }
- }
- }
-
- self.nextthink = time + 0.2;
-}
-
-void Casing_Damage(float thisdmg, int hittype, vector org, vector thisforce)
-{SELFPARAM();
- if (thisforce.z < 0)
- thisforce.z = 0;
- self.move_velocity = self.move_velocity + thisforce + '0 0 100';
- self.move_flags &= ~FL_ONGROUND;
-}
-
-MUTATOR_HOOKFUNCTION(casings, CSQC_Parse_TempEntity)
-{
- if (MUTATOR_RETURNVALUE) return;
- if (!ReadMutatorEquals(mutator_argv_int_0, casings)) return;
- return = true;
-
- int _state = ReadByte();
- vector org;
- org_x = ReadCoord();
- org_y = ReadCoord();
- org_z = ReadCoord();
- vector vel = decompressShortVector(ReadShort());
- vector ang;
- ang_x = ReadByte() * 360 / 256;
- ang_y = ReadByte() * 360 / 256;
- ang_z = ReadByte() * 360 / 256;
-
- if (!autocvar_cl_casings) return;
-
- Casing casing = RubbleNew("casing");
- casing.silent = (_state & 0x80);
- casing.state = (_state & 0x7F);
- casing.origin = org;
- setorigin(casing, casing.origin);
- casing.velocity = vel;
- casing.angles = ang;
- casing.drawmask = MASK_NORMAL;
-
- casing.draw = Casing_Draw;
- casing.move_origin = casing.origin;
- casing.move_velocity = casing.velocity + 2 * prandomvec();
- casing.move_angles = casing.angles;
- casing.move_avelocity = '0 250 0' + 100 * prandomvec();
- casing.move_movetype = MOVETYPE_BOUNCE;
- casing.move_touch = Casing_Touch;
- casing.move_time = time;
- casing.event_damage = Casing_Damage;
- casing.solid = SOLID_TRIGGER;
-
- switch (casing.state)
- {
- case 1:
- setmodel(casing, MDL_CASING_SHELL);
- casing.cnt = time + autocvar_cl_casings_shell_time;
- break;
- default:
- setmodel(casing, MDL_CASING_BULLET);
- casing.cnt = time + autocvar_cl_casings_bronze_time;
- break;
- }
-
- setsize(casing, '0 0 -1', '0 0 -1');
-
- RubbleLimit("casing", autocvar_cl_casings_maxcount, Casing_Delete);
-}
-
-#endif
-#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+
+REGISTER_MUTATOR(cloaked, cvar("g_cloaked"));
+
+float autocvar_g_balance_cloaked_alpha;
+
+MUTATOR_HOOKFUNCTION(cloaked, SetDefaultAlpha)
+{
+ default_player_alpha = autocvar_g_balance_cloaked_alpha;
+ default_weapon_alpha = default_player_alpha;
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(cloaked, BuildMutatorsPrettyString)
+{
+ if (!g_cts) ret_string = strcat(ret_string, ", Cloaked");
+}
+
+#endif
--- /dev/null
+#ifdef SVQC
+#include "cloaked.qc"
+#endif
+++ /dev/null
-#ifndef MUTATOR_DAMAGETEXT_H
-#define MUTATOR_DAMAGETEXT_H
-
-#ifdef MENUQC
-#include "../../../menu/xonotic/tab.qc"
-#endif
-
-#endif
-
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(damagetext, true);
-
-#if defined(CSQC) || defined(MENUQC)
-AUTOCVAR_SAVE(cl_damagetext, bool, false, _("Draw damage dealt. 0: disabled, 1: enabled"));
-AUTOCVAR_SAVE(cl_damagetext_format, string, "-%3$d", _("How to format the damage text. 1$ is health, 2$ is armor, 3$ is both"));
-AUTOCVAR_SAVE(cl_damagetext_color, vector, '1 1 0', _("Default damage text color"));
-AUTOCVAR_SAVE(cl_damagetext_color_per_weapon, bool, false, _("Damage text uses weapon color"));
-AUTOCVAR_SAVE(cl_damagetext_size, float, 8, _("Damage text font size"));
-AUTOCVAR_SAVE(cl_damagetext_alpha_start, float, 1, _("Damage text initial alpha"));
-AUTOCVAR_SAVE(cl_damagetext_alpha_lifetime, float, 3, _("Damage text lifetime in seconds"));
-AUTOCVAR_SAVE(cl_damagetext_velocity, vector, '0 0 20', _("Damage text move direction"));
-AUTOCVAR_SAVE(cl_damagetext_offset, vector, '0 -40 0', _("Damage text offset"));
-AUTOCVAR_SAVE(cl_damagetext_accumulate_range, float, 30, _("Damage text spawned within this range is accumulated"));
-#endif
-
-#ifdef CSQC
-CLASS(DamageText, Object)
- ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color)
- ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size)
- ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start)
- ATTRIB(DamageText, fade_rate, float, 1 / autocvar_cl_damagetext_alpha_lifetime)
- ATTRIB(DamageText, velocity, vector, autocvar_cl_damagetext_velocity)
- ATTRIB(DamageText, m_group, int, 0)
- ATTRIB(DamageText, m_damage, int, 0)
- ATTRIB(DamageText, m_armordamage, int, 0)
- ATTRIB(DamageText, m_deathtype, int, 0)
- ATTRIB(DamageText, time_prev, float, time)
-
- void DamageText_draw2d(DamageText this) {
- float dt = time - this.time_prev;
- this.time_prev = time;
- setorigin(this, this.origin + dt * this.velocity);
- this.alpha -= dt * this.fade_rate;
- if (this.alpha < 0) remove(this);
- vector pos = project_3d_to_2d(this.origin) + autocvar_cl_damagetext_offset;
- if (pos.z >= 0 && this.m_size > 0) {
- pos.z = 0;
- vector rgb = this.m_color;
- if (autocvar_cl_damagetext_color_per_weapon) {
- Weapon w = DEATH_WEAPONOF(this.m_deathtype);
- if (w != WEP_Null) rgb = w.wpcolor;
- }
- string s = sprintf(autocvar_cl_damagetext_format, this.m_damage, this.m_armordamage, this.m_damage + this.m_armordamage);
- drawcolorcodedstring2(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
- }
- }
- ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d)
-
- void DamageText_update(DamageText this, vector _origin, int _health, int _armor, int _deathtype) {
- this.m_damage = _health;
- this.m_armordamage = _armor;
- this.m_deathtype = _deathtype;
- setorigin(this, _origin);
- this.alpha = 1;
- }
-
- CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _deathtype) {
- CONSTRUCT(DamageText);
- this.m_group = _group;
- DamageText_update(this, _origin, _health, _armor, _deathtype);
- }
-ENDCLASS(DamageText)
-#endif
-
-#ifdef SVQC
-AUTOCVAR(sv_damagetext, int, 2, _("<= 0: disabled, >= 1: spectators, >= 2: players, >= 3: all players"));
-#define SV_DAMAGETEXT_DISABLED() (autocvar_sv_damagetext <= 0 /* disabled */)
-#define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1 /* spectators only */)
-#define SV_DAMAGETEXT_PLAYERS() (autocvar_sv_damagetext >= 2 /* players */)
-#define SV_DAMAGETEXT_ALL() (autocvar_sv_damagetext >= 3 /* all players */)
-MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
- if (SV_DAMAGETEXT_DISABLED()) return;
- const entity attacker = mutator_argv_entity_0;
- const entity hit = mutator_argv_entity_1; if (hit == attacker) return;
- const int health = mutator_argv_int_0;
- const int armor = mutator_argv_int_1;
- const int deathtype = mutator_argv_int_2;
- const vector location = hit.origin;
- entity e;
- FOR_EACH_REALCLIENT(e) if (
- (SV_DAMAGETEXT_ALL()) ||
- (SV_DAMAGETEXT_PLAYERS() && e == attacker) ||
- (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(e) && e.enemy == attacker) ||
- (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(e))
- ) {
- msg_entity = e;
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteMutator(MSG_ONE, damagetext);
- WriteShort(MSG_ONE, health);
- WriteShort(MSG_ONE, armor);
- WriteEntity(MSG_ONE, hit);
- WriteCoord(MSG_ONE, location.x);
- WriteCoord(MSG_ONE, location.y);
- WriteCoord(MSG_ONE, location.z);
- WriteInt24_t(MSG_ONE, deathtype);
- }
-}
-#endif
-
-#ifdef CSQC
-MUTATOR_HOOKFUNCTION(damagetext, CSQC_Parse_TempEntity) {
- if (MUTATOR_RETURNVALUE) return false;
- if (!ReadMutatorEquals(mutator_argv_int_0, damagetext)) return false;
- int health = ReadShort();
- int armor = ReadShort();
- int group = ReadShort();
- vector location = vec3(ReadCoord(), ReadCoord(), ReadCoord());
- int deathtype = ReadInt24_t();
- if (autocvar_cl_damagetext) {
- if (autocvar_cl_damagetext_accumulate_range) {
- for (entity e = findradius(location, autocvar_cl_damagetext_accumulate_range); e; e = e.chain) {
- if (e.instanceOfDamageText && e.m_group == group) {
- DamageText_update(e, location, e.m_damage + health, e.m_armordamage + armor, deathtype);
- return true;
- }
- }
- }
- NEW(DamageText, group, location, health, armor, deathtype);
- }
- return true;
-}
-#endif
-
-#ifdef MENUQC
-CLASS(XonoticDamageTextSettings, XonoticTab)
- #include "../../../menu/gamesettings.qh"
- REGISTER_SETTINGS(damagetext, NEW(XonoticDamageTextSettings));
- ATTRIB(XonoticDamageTextSettings, title, string, _("Damage text"))
- ATTRIB(XonoticDamageTextSettings, intendedWidth, float, 0.9)
- ATTRIB(XonoticDamageTextSettings, rows, float, 13)
- ATTRIB(XonoticDamageTextSettings, columns, float, 5)
- INIT(XonoticDamageTextSettings) { this.configureDialog(this); }
- METHOD(XonoticDamageTextSettings, showNotify, void(entity this)) { loadAllCvars(this); }
- METHOD(XonoticDamageTextSettings, fill, void(entity this))
- {
- this.gotoRC(this, 0, 1); this.setFirstColumn(this, this.currentColumn);
- this.TD(this, 1, 3, makeXonoticCheckBox(0, "cl_damagetext", _("Draw damage numbers")));
- this.TR(this);
- this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Font size:")));
- this.TD(this, 1, 2, makeXonoticSlider(0, 50, 1, "cl_damagetext_size"));
- this.TR(this);
- this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Accumulate range:")));
- this.TD(this, 1, 2, makeXonoticSlider(0, 500, 1, "cl_damagetext_accumulate_range"));
- this.TR(this);
- this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Lifetime:")));
- this.TD(this, 1, 2, makeXonoticSlider(0, 10, 1, "cl_damagetext_alpha_lifetime"));
- this.TR(this);
- this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Color:")));
- this.TD(this, 2, 2, makeXonoticColorpickerString("cl_damagetext_color", "cl_damagetext_color"));
- }
-ENDCLASS(XonoticDamageTextSettings)
-#endif
-#endif
--- /dev/null
+#ifndef MUTATOR_DAMAGETEXT_H
+#define MUTATOR_DAMAGETEXT_H
+
+#ifdef MENUQC
+#include "../../../../menu/xonotic/tab.qc"
+#endif
+
+#endif
+
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(damagetext, true);
+
+#if defined(CSQC) || defined(MENUQC)
+AUTOCVAR_SAVE(cl_damagetext, bool, false, _("Draw damage dealt. 0: disabled, 1: enabled"));
+AUTOCVAR_SAVE(cl_damagetext_format, string, "-%3$d", _("How to format the damage text. 1$ is health, 2$ is armor, 3$ is both"));
+AUTOCVAR_SAVE(cl_damagetext_color, vector, '1 1 0', _("Default damage text color"));
+AUTOCVAR_SAVE(cl_damagetext_color_per_weapon, bool, false, _("Damage text uses weapon color"));
+AUTOCVAR_SAVE(cl_damagetext_size, float, 8, _("Damage text font size"));
+AUTOCVAR_SAVE(cl_damagetext_alpha_start, float, 1, _("Damage text initial alpha"));
+AUTOCVAR_SAVE(cl_damagetext_alpha_lifetime, float, 3, _("Damage text lifetime in seconds"));
+AUTOCVAR_SAVE(cl_damagetext_velocity, vector, '0 0 20', _("Damage text move direction"));
+AUTOCVAR_SAVE(cl_damagetext_offset, vector, '0 -40 0', _("Damage text offset"));
+AUTOCVAR_SAVE(cl_damagetext_accumulate_range, float, 30, _("Damage text spawned within this range is accumulated"));
+#endif
+
+#ifdef CSQC
+CLASS(DamageText, Object)
+ ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color)
+ ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size)
+ ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start)
+ ATTRIB(DamageText, fade_rate, float, 1 / autocvar_cl_damagetext_alpha_lifetime)
+ ATTRIB(DamageText, velocity, vector, autocvar_cl_damagetext_velocity)
+ ATTRIB(DamageText, m_group, int, 0)
+ ATTRIB(DamageText, m_damage, int, 0)
+ ATTRIB(DamageText, m_armordamage, int, 0)
+ ATTRIB(DamageText, m_deathtype, int, 0)
+ ATTRIB(DamageText, time_prev, float, time)
+
+ void DamageText_draw2d(DamageText this) {
+ float dt = time - this.time_prev;
+ this.time_prev = time;
+ setorigin(this, this.origin + dt * this.velocity);
+ this.alpha -= dt * this.fade_rate;
+ if (this.alpha < 0) remove(this);
+ vector pos = project_3d_to_2d(this.origin) + autocvar_cl_damagetext_offset;
+ if (pos.z >= 0 && this.m_size > 0) {
+ pos.z = 0;
+ vector rgb = this.m_color;
+ if (autocvar_cl_damagetext_color_per_weapon) {
+ Weapon w = DEATH_WEAPONOF(this.m_deathtype);
+ if (w != WEP_Null) rgb = w.wpcolor;
+ }
+ string s = sprintf(autocvar_cl_damagetext_format, this.m_damage, this.m_armordamage, this.m_damage + this.m_armordamage);
+ drawcolorcodedstring2(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
+ }
+ }
+ ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d)
+
+ void DamageText_update(DamageText this, vector _origin, int _health, int _armor, int _deathtype) {
+ this.m_damage = _health;
+ this.m_armordamage = _armor;
+ this.m_deathtype = _deathtype;
+ setorigin(this, _origin);
+ this.alpha = 1;
+ }
+
+ CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _deathtype) {
+ CONSTRUCT(DamageText);
+ this.m_group = _group;
+ DamageText_update(this, _origin, _health, _armor, _deathtype);
+ }
+ENDCLASS(DamageText)
+#endif
+
+REGISTER_NET_TEMP(damagetext)
+
+#ifdef SVQC
+AUTOCVAR(sv_damagetext, int, 2, _("<= 0: disabled, >= 1: spectators, >= 2: players, >= 3: all players"));
+#define SV_DAMAGETEXT_DISABLED() (autocvar_sv_damagetext <= 0 /* disabled */)
+#define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1 /* spectators only */)
+#define SV_DAMAGETEXT_PLAYERS() (autocvar_sv_damagetext >= 2 /* players */)
+#define SV_DAMAGETEXT_ALL() (autocvar_sv_damagetext >= 3 /* all players */)
+MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
+ if (SV_DAMAGETEXT_DISABLED()) return;
+ const entity attacker = MUTATOR_ARGV(0, entity);
+ const entity hit = MUTATOR_ARGV(1, entity); if (hit == attacker) return;
+ const int health = MUTATOR_ARGV(0, int);
+ const int armor = MUTATOR_ARGV(1, int);
+ const int deathtype = MUTATOR_ARGV(2, int);
+ const vector location = hit.origin;
+ entity e;
+ FOR_EACH_REALCLIENT(e) if (
+ (SV_DAMAGETEXT_ALL()) ||
+ (SV_DAMAGETEXT_PLAYERS() && e == attacker) ||
+ (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(e) && e.enemy == attacker) ||
+ (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(e))
+ ) {
+ msg_entity = e;
+ WriteHeader(MSG_ONE, damagetext);
+ WriteShort(MSG_ONE, health);
+ WriteShort(MSG_ONE, armor);
+ WriteEntity(MSG_ONE, hit);
+ WriteCoord(MSG_ONE, location.x);
+ WriteCoord(MSG_ONE, location.y);
+ WriteCoord(MSG_ONE, location.z);
+ WriteInt24_t(MSG_ONE, deathtype);
+ }
+}
+#endif
+
+#ifdef CSQC
+NET_HANDLE(damagetext, bool isNew)
+{
+ int health = ReadShort();
+ int armor = ReadShort();
+ int group = ReadShort();
+ vector location = vec3(ReadCoord(), ReadCoord(), ReadCoord());
+ int deathtype = ReadInt24_t();
+ return = true;
+ if (autocvar_cl_damagetext) {
+ if (autocvar_cl_damagetext_accumulate_range) {
+ for (entity e = findradius(location, autocvar_cl_damagetext_accumulate_range); e; e = e.chain) {
+ if (e.instanceOfDamageText && e.m_group == group) {
+ DamageText_update(e, location, e.m_damage + health, e.m_armordamage + armor, deathtype);
+ return;
+ }
+ }
+ }
+ NEW(DamageText, group, location, health, armor, deathtype);
+ }
+}
+#endif
+
+#ifdef MENUQC
+CLASS(XonoticDamageTextSettings, XonoticTab)
+ #include "../../../../menu/gamesettings.qh"
+ REGISTER_SETTINGS(damagetext, NEW(XonoticDamageTextSettings));
+ ATTRIB(XonoticDamageTextSettings, title, string, _("Damage text"))
+ ATTRIB(XonoticDamageTextSettings, intendedWidth, float, 0.9)
+ ATTRIB(XonoticDamageTextSettings, rows, float, 13)
+ ATTRIB(XonoticDamageTextSettings, columns, float, 5)
+ INIT(XonoticDamageTextSettings) { this.configureDialog(this); }
+ METHOD(XonoticDamageTextSettings, showNotify, void(entity this)) { loadAllCvars(this); }
+ METHOD(XonoticDamageTextSettings, fill, void(entity this))
+ {
+ this.gotoRC(this, 0, 1); this.setFirstColumn(this, this.currentColumn);
+ this.TD(this, 1, 3, makeXonoticCheckBox(0, "cl_damagetext", _("Draw damage numbers")));
+ this.TR(this);
+ this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Font size:")));
+ this.TD(this, 1, 2, makeXonoticSlider(0, 50, 1, "cl_damagetext_size"));
+ this.TR(this);
+ this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Accumulate range:")));
+ this.TD(this, 1, 2, makeXonoticSlider(0, 500, 1, "cl_damagetext_accumulate_range"));
+ this.TR(this);
+ this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Lifetime:")));
+ this.TD(this, 1, 2, makeXonoticSlider(0, 10, 1, "cl_damagetext_alpha_lifetime"));
+ this.TR(this);
+ this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Color:")));
+ this.TD(this, 2, 2, makeXonoticColorpickerString("cl_damagetext_color", "cl_damagetext_color"));
+ }
+ENDCLASS(XonoticDamageTextSettings)
+#endif
+#endif
--- /dev/null
+#include "damagetext.qc"
--- /dev/null
+#ifdef IMPLEMENTATION
+
+#ifdef CSQC
+ #define PHYS_DODGING_FRAMETIME (1 / (frametime <= 0 ? 60 : frametime))
+ #define PHYS_DODGING getstati(STAT_DODGING)
+ #define PHYS_DODGING_DELAY getstatf(STAT_DODGING_DELAY)
+ #define PHYS_DODGING_TIMEOUT(s) getstatf(STAT_DODGING_TIMEOUT)
+ #define PHYS_DODGING_HORIZ_SPEED_FROZEN getstatf(STAT_DODGING_HORIZ_SPEED_FROZEN)
+ #define PHYS_DODGING_FROZEN_NODOUBLETAP getstati(STAT_DODGING_FROZEN_NO_DOUBLETAP)
+ #define PHYS_DODGING_HORIZ_SPEED getstatf(STAT_DODGING_HORIZ_SPEED)
+ #define PHYS_DODGING_PRESSED_KEYS(s) s.pressedkeys
+ #define PHYS_DODGING_HEIGHT_THRESHOLD getstatf(STAT_DODGING_HEIGHT_THRESHOLD)
+ #define PHYS_DODGING_DISTANCE_THRESHOLD getstatf(STAT_DODGING_DISTANCE_THRESHOLD)
+ #define PHYS_DODGING_RAMP_TIME getstatf(STAT_DODGING_RAMP_TIME)
+ #define PHYS_DODGING_UP_SPEED getstatf(STAT_DODGING_UP_SPEED)
+ #define PHYS_DODGING_WALL getstatf(STAT_DODGING_WALL)
+#elif defined(SVQC)
+ #define PHYS_DODGING_FRAMETIME sys_frametime
+ #define PHYS_DODGING g_dodging
+ #define PHYS_DODGING_DELAY autocvar_sv_dodging_delay
+ #define PHYS_DODGING_TIMEOUT(s) s.cvar_cl_dodging_timeout
+ #define PHYS_DODGING_HORIZ_SPEED_FROZEN autocvar_sv_dodging_horiz_speed_frozen
+ #define PHYS_DODGING_FROZEN_NODOUBLETAP autocvar_sv_dodging_frozen_doubletap
+ #define PHYS_DODGING_HORIZ_SPEED autocvar_sv_dodging_horiz_speed
+ #define PHYS_DODGING_PRESSED_KEYS(s) s.pressedkeys
+ #define PHYS_DODGING_HEIGHT_THRESHOLD autocvar_sv_dodging_height_threshold
+ #define PHYS_DODGING_DISTANCE_THRESHOLD autocvar_sv_dodging_wall_distance_threshold
+ #define PHYS_DODGING_RAMP_TIME autocvar_sv_dodging_ramp_time
+ #define PHYS_DODGING_UP_SPEED autocvar_sv_dodging_up_speed
+ #define PHYS_DODGING_WALL autocvar_sv_dodging_wall_dodging
+
+ float autocvar_sv_dodging_delay;
+ float autocvar_sv_dodging_height_threshold;
+ float autocvar_sv_dodging_horiz_speed;
+ float autocvar_sv_dodging_horiz_speed_frozen;
+ float autocvar_sv_dodging_ramp_time;
+ bool autocvar_sv_dodging_sound;
+ float autocvar_sv_dodging_up_speed;
+ float autocvar_sv_dodging_wall_distance_threshold;
+ bool autocvar_sv_dodging_wall_dodging;
+ bool autocvar_sv_dodging_frozen_doubletap;
+#endif
+
+#ifdef SVQC
+
+float g_dodging;
+
+// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
+.float dodging_action;
+
+// the jump part of the dodge cannot be ramped
+.float dodging_single_action;
+
+#include "../../../animdecide.qh"
+#include "../../../physics.qh"
+
+.float cvar_cl_dodging_timeout;
+
+.float stat_dodging;
+.float stat_dodging_delay;
+.float stat_dodging_horiz_speed_frozen;
+.float stat_dodging_frozen_nodoubletap;
+.float stat_dodging_frozen;
+.float stat_dodging_horiz_speed;
+.float stat_dodging_height_threshold;
+.float stat_dodging_distance_threshold;
+.float stat_dodging_ramp_time;
+.float stat_dodging_up_speed;
+.float stat_dodging_wall;
+
+REGISTER_MUTATOR(dodging, cvar("g_dodging"))
+{
+ // this just turns on the cvar.
+ MUTATOR_ONADD
+ {
+ g_dodging = cvar("g_dodging");
+ addstat(STAT_DODGING, AS_INT, stat_dodging);
+ addstat(STAT_DODGING_DELAY, AS_FLOAT, stat_dodging_delay);
+ addstat(STAT_DODGING_TIMEOUT, AS_FLOAT, cvar_cl_dodging_timeout); // we stat this, so it is updated on the client when updated on server (otherwise, chaos)
+ addstat(STAT_DODGING_FROZEN_NO_DOUBLETAP, AS_INT, stat_dodging_frozen_nodoubletap);
+ addstat(STAT_DODGING_HORIZ_SPEED_FROZEN, AS_FLOAT, stat_dodging_horiz_speed_frozen);
+ addstat(STAT_DODGING_FROZEN, AS_INT, stat_dodging_frozen);
+ addstat(STAT_DODGING_HORIZ_SPEED, AS_FLOAT, stat_dodging_horiz_speed);
+ addstat(STAT_DODGING_HEIGHT_THRESHOLD, AS_FLOAT, stat_dodging_height_threshold);
+ addstat(STAT_DODGING_DISTANCE_THRESHOLD, AS_FLOAT, stat_dodging_distance_threshold);
+ addstat(STAT_DODGING_RAMP_TIME, AS_FLOAT, stat_dodging_ramp_time);
+ addstat(STAT_DODGING_UP_SPEED, AS_FLOAT, stat_dodging_up_speed);
+ addstat(STAT_DODGING_WALL, AS_FLOAT, stat_dodging_wall);
+ }
+
+ // this just turns off the cvar.
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ g_dodging = 0;
+ }
+
+ return false;
+}
+
+#endif
+
+// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
+.float dodging_action;
+
+// the jump part of the dodge cannot be ramped
+.float dodging_single_action;
+
+
+// these are used to store the last key press time for each of the keys..
+.float last_FORWARD_KEY_time;
+.float last_BACKWARD_KEY_time;
+.float last_LEFT_KEY_time;
+.float last_RIGHT_KEY_time;
+
+// these store the movement direction at the time of the dodge action happening.
+.vector dodging_direction;
+
+// this indicates the last time a dodge was executed. used to check if another one is allowed
+// and to ramp up the dodge acceleration in the physics hook.
+.float last_dodging_time;
+
+// This is the velocity gain to be added over the ramp time.
+// It will decrease from frame to frame during dodging_action = 1
+// until it's 0.
+.float dodging_velocity_gain;
+
+#ifdef CSQC
+.int pressedkeys;
+
+#elif defined(SVQC)
+
+void dodging_UpdateStats()
+{SELFPARAM();
+ self.stat_dodging = PHYS_DODGING;
+ self.stat_dodging_delay = PHYS_DODGING_DELAY;
+ self.stat_dodging_horiz_speed_frozen = PHYS_DODGING_HORIZ_SPEED_FROZEN;
+ self.stat_dodging_frozen = PHYS_DODGING_FROZEN;
+ self.stat_dodging_frozen_nodoubletap = PHYS_DODGING_FROZEN_NODOUBLETAP;
+ self.stat_dodging_height_threshold = PHYS_DODGING_HEIGHT_THRESHOLD;
+ self.stat_dodging_distance_threshold = PHYS_DODGING_DISTANCE_THRESHOLD;
+ self.stat_dodging_ramp_time = PHYS_DODGING_RAMP_TIME;
+ self.stat_dodging_up_speed = PHYS_DODGING_UP_SPEED;
+ self.stat_dodging_wall = PHYS_DODGING_WALL;
+}
+
+#endif
+
+// returns 1 if the player is close to a wall
+bool check_close_to_wall(float threshold)
+{SELFPARAM();
+ if (PHYS_DODGING_WALL == 0) { return false; }
+
+ #define X(OFFSET) \
+ tracebox(self.origin, self.mins, self.maxs, self.origin + OFFSET, true, self); \
+ if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold) \
+ return true;
+ X(1000*v_right);
+ X(-1000*v_right);
+ X(1000*v_forward);
+ X(-1000*v_forward);
+ #undef X
+
+ return false;
+}
+
+bool check_close_to_ground(float threshold)
+{SELFPARAM();
+ return IS_ONGROUND(self) ? true : false;
+}
+
+float PM_dodging_checkpressedkeys()
+{SELFPARAM();
+ if(!PHYS_DODGING)
+ return false;
+
+ float frozen_dodging = (PHYS_FROZEN(self) && PHYS_DODGING_FROZEN);
+ float frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
+
+ // first check if the last dodge is far enough back in time so we can dodge again
+ if ((time - self.last_dodging_time) < PHYS_DODGING_DELAY)
+ return false;
+
+ makevectors(self.angles);
+
+ if (check_close_to_ground(PHYS_DODGING_HEIGHT_THRESHOLD) != 1
+ && check_close_to_wall(PHYS_DODGING_DISTANCE_THRESHOLD) != 1)
+ return true;
+
+ float tap_direction_x = 0;
+ float tap_direction_y = 0;
+ float dodge_detected = 0;
+
+ #define X(COND,BTN,RESULT) \
+ if (self.movement_##COND) \
+ /* is this a state change? */ \
+ if(!(PHYS_DODGING_PRESSED_KEYS(self) & KEY_##BTN) || frozen_no_doubletap) { \
+ tap_direction_##RESULT; \
+ if ((time - self.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(self)) \
+ dodge_detected = 1; \
+ self.last_##BTN##_KEY_time = time; \
+ }
+ X(x < 0, BACKWARD, x--);
+ X(x > 0, FORWARD, x++);
+ X(y < 0, LEFT, y--);
+ X(y > 0, RIGHT, y++);
+ #undef X
+
+ if (dodge_detected == 1)
+ {
+ self.last_dodging_time = time;
+
+ self.dodging_action = 1;
+ self.dodging_single_action = 1;
+
+ self.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
+
+ self.dodging_direction_x = tap_direction_x;
+ self.dodging_direction_y = tap_direction_y;
+
+ // normalize the dodging_direction vector.. (unlike UT99) XD
+ float length = self.dodging_direction_x * self.dodging_direction_x
+ + self.dodging_direction_y * self.dodging_direction_y;
+ length = sqrt(length);
+
+ self.dodging_direction_x = self.dodging_direction_x * 1.0 / length;
+ self.dodging_direction_y = self.dodging_direction_y * 1.0 / length;
+ return true;
+ }
+ return false;
+}
+
+void PM_dodging()
+{SELFPARAM();
+ if (!PHYS_DODGING)
+ return;
+
+#ifdef SVQC
+ dodging_UpdateStats();
+#endif
+
+ if (PHYS_DEAD(self))
+ return;
+
+ // when swimming, no dodging allowed..
+ if (self.waterlevel >= WATERLEVEL_SWIMMING)
+ {
+ self.dodging_action = 0;
+ self.dodging_direction_x = 0;
+ self.dodging_direction_y = 0;
+ return;
+ }
+
+ // make sure v_up, v_right and v_forward are sane
+ makevectors(self.angles);
+
+ // if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
+ // will be called ramp_time/frametime times = 2 times. so, we need to
+ // add 0.5 * the total speed each frame until the dodge action is done..
+ float common_factor = PHYS_DODGING_FRAMETIME / PHYS_DODGING_RAMP_TIME;
+
+ // if ramp time is smaller than frametime we get problems ;D
+ common_factor = min(common_factor, 1);
+
+ float horiz_speed = PHYS_FROZEN(self) ? PHYS_DODGING_HORIZ_SPEED_FROZEN : PHYS_DODGING_HORIZ_SPEED;
+ float new_velocity_gain = self.dodging_velocity_gain - (common_factor * horiz_speed);
+ new_velocity_gain = max(0, new_velocity_gain);
+
+ float velocity_difference = self.dodging_velocity_gain - new_velocity_gain;
+
+ // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
+ if (self.dodging_action == 1)
+ {
+ //disable jump key during dodge accel phase
+ if(self.movement_z > 0) { self.movement_z = 0; }
+
+ self.velocity += ((self.dodging_direction_y * velocity_difference) * v_right)
+ + ((self.dodging_direction_x * velocity_difference) * v_forward);
+
+ self.dodging_velocity_gain = self.dodging_velocity_gain - velocity_difference;
+ }
+
+ // the up part of the dodge is a single shot action
+ if (self.dodging_single_action == 1)
+ {
+ UNSET_ONGROUND(self);
+
+ self.velocity += PHYS_DODGING_UP_SPEED * v_up;
+
+#ifdef SVQC
+ if (autocvar_sv_dodging_sound)
+ PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+
+ animdecide_setaction(self, ANIMACTION_JUMP, true);
+#endif
+
+ self.dodging_single_action = 0;
+ }
+
+ // are we done with the dodging ramp yet?
+ if((self.dodging_action == 1) && ((time - self.last_dodging_time) > PHYS_DODGING_RAMP_TIME))
+ {
+ // reset state so next dodge can be done correctly
+ self.dodging_action = 0;
+ self.dodging_direction_x = 0;
+ self.dodging_direction_y = 0;
+ }
+}
+
+#ifdef SVQC
+
+MUTATOR_HOOKFUNCTION(dodging, GetCvars)
+{
+ GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(dodging, PlayerPhysics)
+{
+ // print("dodging_PlayerPhysics\n");
+ PM_dodging();
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(dodging, GetPressedKeys)
+{
+ PM_dodging_checkpressedkeys();
+
+ return false;
+}
+
+#endif
+
+#endif
--- /dev/null
+#ifdef SVQC
+#include "dodging.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+AUTOCVAR(g_grappling_hook, bool, false, _("let players spawn with the grappling hook which allows them to pull themselves up"));
+#ifdef SVQC
+REGISTER_MUTATOR(hook, autocvar_g_grappling_hook) {
+ MUTATOR_ONADD {
+ g_grappling_hook = true;
+ WEP_HOOK.ammo_factor = 0;
+ }
+ MUTATOR_ONROLLBACK_OR_REMOVE {
+ g_grappling_hook = false;
+ WEP_HOOK.ammo_factor = 1;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(hook, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":grappling_hook");
+}
+
+MUTATOR_HOOKFUNCTION(hook, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Hook");
+}
+
+MUTATOR_HOOKFUNCTION(hook, BuildGameplayTipsString)
+{
+ ret_string = strcat(ret_string, "\n\n^3grappling hook^8 is enabled, press 'e' to use it\n");
+}
+
+MUTATOR_HOOKFUNCTION(hook, PlayerSpawn)
+{
+ SELFPARAM();
+ self.offhand = OFFHAND_HOOK;
+}
+
+MUTATOR_HOOKFUNCTION(hook, FilterItem)
+{
+ return self.weapon == WEP_HOOK.m_id;
+}
+
+#endif
+#endif
--- /dev/null
+#ifdef SVQC
+#include "hook.qc"
+#endif
#include "items.qc"
+#ifdef SVQC
+float autocvar_g_instagib_invis_alpha;
+#endif
+
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
+int autocvar_g_instagib_ammo_drop;
+int autocvar_g_instagib_extralives;
+float autocvar_g_instagib_speed_highspeed;
+
#include "../../../../server/cl_client.qh"
-#include "../../../buffs/all.qh"
#include "../../../items/all.qc"
{
if (!g_instagib) { remove(self); return; }
if (!self.ammo_cells) self.ammo_cells = autocvar_g_instagib_ammo_drop;
- StartItemA(ITEM_VaporizerCells);
+ StartItem(this, ITEM_VaporizerCells);
}
void instagib_invisibility()
{SELFPARAM();
self.strength_finished = autocvar_g_balance_powerup_strength_time;
- StartItemA(ITEM_Invisibility);
+ StartItem(this, ITEM_Invisibility);
}
void instagib_extralife()
{SELFPARAM();
self.max_health = 1;
- StartItemA(ITEM_ExtraLife);
+ StartItem(this, ITEM_ExtraLife);
}
void instagib_speed()
{SELFPARAM();
self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
- StartItemA(ITEM_Speed);
+ StartItem(this, ITEM_Speed);
}
.float instagib_nextthink;
frag_mirrordamage = 0;
}
- if((frag_target.buffs & BUFF_INVISIBLE.m_itemid) || (frag_target.items & ITEM_Invisibility.m_itemid))
+ if(frag_target.alpha && frag_target.alpha < 1)
yoda = 1;
return false;
e.noalign = self.noalign;
e.cnt = self.cnt;
e.team = self.team;
+ e.spawnfunc_checked = true;
WITH(entity, self, e, spawnfunc_item_minst_cells(e));
return true;
}
#ifndef MENUQC
MODEL(VaporizerCells_ITEM, Item_Model("a_cells.md3"));
+SOUND(VaporizerCells, "misc/itempickup");
#endif
REGISTER_ITEM(VaporizerCells, Ammo) {
#ifndef MENUQC
this.m_model = MDL_VaporizerCells_ITEM;
+ this.m_sound = SND_VaporizerCells;
#endif
- this.m_sound = "misc/itempickup.wav";
this.m_name = "Vaporizer Ammo";
this.m_icon = "ammo_supercells";
#ifdef SVQC
#ifndef MENUQC
MODEL(ExtraLife_ITEM, Item_Model("g_h100.md3"));
+SOUND(ExtraLife, "misc/megahealth");
#endif
REGISTER_ITEM(ExtraLife, Powerup) {
#ifndef MENUQC
this.m_model = MDL_ExtraLife_ITEM;
+ this.m_sound = SND_ExtraLife;
#endif
- this.m_sound = "misc/megahealth.wav";
this.m_name = "Extra life";
this.m_icon = "item_mega_health";
this.m_color = '1 0 0';
#ifndef MENUQC
MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
+SOUND(Invisibility, "misc/powerup");
#endif
REGISTER_ITEM(Invisibility, Powerup) {
#ifndef MENUQC
this.m_model = MDL_Invisibility_ITEM;
+ this.m_sound = SND_Invisibility;
#endif
- this.m_sound = "misc/powerup.wav";
this.m_name = "Invisibility";
this.m_icon = "strength";
this.m_color = '0 0 1';
#ifndef MENUQC
MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
+SOUND(Speed, "misc/powerup_shield");
#endif
REGISTER_ITEM(Speed, Powerup) {
#ifndef MENUQC
this.m_model = MDL_Speed_ITEM;
+ this.m_sound = SND_Speed;
#endif
- this.m_sound = "misc/powerup_shield.wav";
this.m_name = "Speed";
this.m_icon = "shield";
this.m_color = '1 0 1';
--- /dev/null
+#include "instagib.qc"
--- /dev/null
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(invincibleprojectiles, cvar("g_invincible_projectiles"));
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles, EditProjectile)
+{
+ if(other.health)
+ {
+ // disable health which in effect disables damage calculations
+ other.health = 0;
+ }
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":InvincibleProjectiles");
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Invincible Projectiles");
+ return 0;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "invincibleproj.qc"
+#endif
#ifdef IMPLEMENTATION
REGISTER_MUTATOR(itemstime, true);
+REGISTER_NET_TEMP(itemstime)
+
#ifdef SVQC
void IT_Write(entity e, int i, float f) {
if (!IS_REAL_CLIENT(e)) return;
msg_entity = e;
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteMutator(MSG_ONE, itemstime);
+ WriteHeader(MSG_ONE, itemstime);
WriteByte(MSG_ONE, i);
WriteFloat(MSG_ONE, f);
}
#ifdef CSQC
float ItemsTime_time[Items_MAX];
float ItemsTime_availableTime[Items_MAX];
-MUTATOR_HOOKFUNCTION(itemstime, CSQC_Parse_TempEntity) {
- if (MUTATOR_RETURNVALUE) return false;
- if (!ReadMutatorEquals(mutator_argv_int_0, itemstime)) return false;
+NET_HANDLE(itemstime, bool isNew)
+{
int i = ReadByte();
float f = ReadFloat();
+ return = true;
ItemsTime_time[i] = f;
- return true;
}
#endif
return;
GameItem item = e.itemdef;
- it_times[item.m_id] = t;
+ if (item.instanceOfGameItem && !item.instanceOfWeaponPickup)
+ {
+ it_times[item.m_id] = t;
+ }
}
void Item_ItemsTime_SetTimesForAllPlayers()
--- /dev/null
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(melee_only, cvar("g_melee_only") && !cvar("g_instagib") && !g_nexball);
+
+MUTATOR_HOOKFUNCTION(melee_only, SetStartItems)
+{
+ start_ammo_shells = warmup_start_ammo_shells = 0;
+ start_weapons = warmup_start_weapons = WEPSET(SHOTGUN);
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, ForbidThrowCurrentWeapon)
+{
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, FilterItem)
+{SELFPARAM();
+ switch (self.items)
+ {
+ case ITEM_HealthSmall.m_itemid:
+ case ITEM_ArmorSmall.m_itemid:
+ return false;
+ }
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":MeleeOnly");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Melee Only Arena");
+ return false;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "melee_only.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+
+float autocvar_g_midair_shieldtime;
+
+REGISTER_MUTATOR(midair, cvar("g_midair"));
+
+.float midair_shieldtime;
+
+MUTATOR_HOOKFUNCTION(midair, PlayerDamage_Calculate)
+{SELFPARAM();
+ if(IS_PLAYER(frag_attacker))
+ if(IS_PLAYER(frag_target))
+ if(time < self.midair_shieldtime)
+ frag_damage = false;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(midair, PlayerPowerups)
+{SELFPARAM();
+ if(time >= game_starttime)
+ if(self.flags & FL_ONGROUND)
+ {
+ self.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
+ self.midair_shieldtime = max(self.midair_shieldtime, time + autocvar_g_midair_shieldtime);
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(midair, PlayerSpawn)
+{SELFPARAM();
+ if(IS_BOT_CLIENT(self))
+ self.bot_moveskill = 0; // disable bunnyhopping
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(midair, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":midair");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(midair, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Midair");
+ return false;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "midair.qc"
+#endif
--- /dev/null
+#ifndef MENUQC
+#include "multijump.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+ #include "../../../../server/antilag.qh"
+#endif
+#include "../../../physics.qh"
+
+.int multijump_count;
+.bool multijump_ready;
+.bool cvar_cl_multijump;
+
+#ifdef CSQC
+
+#define PHYS_MULTIJUMP getstati(STAT_MULTIJUMP)
+#define PHYS_MULTIJUMP_SPEED getstatf(STAT_MULTIJUMP_SPEED)
+#define PHYS_MULTIJUMP_ADD getstati(STAT_MULTIJUMP_ADD)
+#define PHYS_MULTIJUMP_MAXSPEED getstatf(STAT_MULTIJUMP_MAXSPEED)
+#define PHYS_MULTIJUMP_DODGING getstati(STAT_MULTIJUMP_DODGING)
+
+#elif defined(SVQC)
+
+int autocvar_g_multijump;
+float autocvar_g_multijump_add;
+float autocvar_g_multijump_speed;
+float autocvar_g_multijump_maxspeed;
+float autocvar_g_multijump_dodging = 1;
+
+#define PHYS_MULTIJUMP autocvar_g_multijump
+#define PHYS_MULTIJUMP_SPEED autocvar_g_multijump_speed
+#define PHYS_MULTIJUMP_ADD autocvar_g_multijump_add
+#define PHYS_MULTIJUMP_MAXSPEED autocvar_g_multijump_maxspeed
+#define PHYS_MULTIJUMP_DODGING autocvar_g_multijump_dodging
+
+.float stat_multijump;
+.float stat_multijump_speed;
+.float stat_multijump_add;
+.float stat_multijump_maxspeed;
+.float stat_multijump_dodging;
+
+void multijump_UpdateStats()
+{SELFPARAM();
+ self.stat_multijump = PHYS_MULTIJUMP;
+ self.stat_multijump_speed = PHYS_MULTIJUMP_SPEED;
+ self.stat_multijump_add = PHYS_MULTIJUMP_ADD;
+ self.stat_multijump_maxspeed = PHYS_MULTIJUMP_MAXSPEED;
+ self.stat_multijump_dodging = PHYS_MULTIJUMP_DODGING;
+}
+
+void multijump_AddStats()
+{
+ addstat(STAT_MULTIJUMP, AS_INT, stat_multijump);
+ addstat(STAT_MULTIJUMP_SPEED, AS_FLOAT, stat_multijump_speed);
+ addstat(STAT_MULTIJUMP_ADD, AS_INT, stat_multijump_add);
+ addstat(STAT_MULTIJUMP_MAXSPEED, AS_FLOAT, stat_multijump_maxspeed);
+ addstat(STAT_MULTIJUMP_DODGING, AS_INT, stat_multijump_dodging);
+}
+
+#endif
+
+void PM_multijump()
+{SELFPARAM();
+ if(!PHYS_MULTIJUMP) { return; }
+
+ if(IS_ONGROUND(self))
+ {
+ self.multijump_count = 0;
+ }
+}
+
+bool PM_multijump_checkjump()
+{SELFPARAM();
+ if(!PHYS_MULTIJUMP) { return false; }
+
+#ifdef SVQC
+ bool client_multijump = self.cvar_cl_multijump;
+#elif defined(CSQC)
+ bool client_multijump = cvar("cl_multijump");
+
+ if(cvar("cl_multijump") > 1)
+ return false; // nope
+#endif
+
+ if (!IS_JUMP_HELD(self) && !IS_ONGROUND(self) && client_multijump) // jump button pressed this frame and we are in midair
+ self.multijump_ready = true; // this is necessary to check that we released the jump button and pressed it again
+ else
+ self.multijump_ready = false;
+
+ int phys_multijump = PHYS_MULTIJUMP;
+
+#ifdef CSQC
+ phys_multijump = (PHYS_MULTIJUMP) ? -1 : 0;
+#endif
+
+ if(!player_multijump && self.multijump_ready && (self.multijump_count < phys_multijump || phys_multijump == -1) && self.velocity_z > PHYS_MULTIJUMP_SPEED && (!PHYS_MULTIJUMP_MAXSPEED || vlen(self.velocity) <= PHYS_MULTIJUMP_MAXSPEED))
+ {
+ if (PHYS_MULTIJUMP)
+ {
+ if (!PHYS_MULTIJUMP_ADD) // in this case we make the z velocity == jumpvelocity
+ {
+ if (self.velocity_z < PHYS_JUMPVELOCITY)
+ {
+ player_multijump = true;
+ self.velocity_z = 0;
+ }
+ }
+ else
+ player_multijump = true;
+
+ if(player_multijump)
+ {
+ if(PHYS_MULTIJUMP_DODGING)
+ if(self.movement_x != 0 || self.movement_y != 0) // don't remove all speed if player isnt pressing any movement keys
+ {
+ float curspeed;
+ vector wishvel, wishdir;
+
+/*#ifdef SVQC
+ curspeed = max(
+ vlen(vec2(self.velocity)), // current xy speed
+ vlen(vec2(antilag_takebackavgvelocity(self, max(self.lastteleporttime + sys_frametime, time - 0.25), time))) // average xy topspeed over the last 0.25 secs
+ );
+#elif defined(CSQC)*/
+ curspeed = vlen(vec2(self.velocity));
+//#endif
+
+ makevectors(self.v_angle_y * '0 1 0');
+ wishvel = v_forward * self.movement_x + v_right * self.movement_y;
+ wishdir = normalize(wishvel);
+
+ self.velocity_x = wishdir_x * curspeed; // allow "dodging" at a multijump
+ self.velocity_y = wishdir_y * curspeed;
+ // keep velocity_z unchanged!
+ }
+ if (PHYS_MULTIJUMP > 0)
+ {
+ self.multijump_count += 1;
+ }
+ }
+ }
+ self.multijump_ready = false; // require releasing and pressing the jump button again for the next jump
+ }
+
+ return false;
+}
+
+#ifdef SVQC
+REGISTER_MUTATOR(multijump, cvar("g_multijump"))
+{
+ MUTATOR_ONADD
+ {
+ multijump_AddStats();
+ }
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(multijump, PlayerPhysics)
+{
+ multijump_UpdateStats();
+ PM_multijump();
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(multijump, PlayerJump)
+{
+ return PM_multijump_checkjump();
+}
+
+MUTATOR_HOOKFUNCTION(multijump, GetCvars)
+{
+ GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_multijump, "cl_multijump");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":multijump");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Multi jump");
+ return false;
+}
+
+#endif
+#endif
--- /dev/null
+EFFECT(0, NADE_EXPLODE_RED, "nade_red_explode")
+EFFECT(0, NADE_EXPLODE_BLUE, "nade_blue_explode")
+EFFECT(0, NADE_EXPLODE_YELLOW, "nade_yellow_explode")
+EFFECT(0, NADE_EXPLODE_PINK, "nade_pink_explode")
+EFFECT(0, NADE_EXPLODE_NEUTRAL, "nade_neutral_explode")
+entity EFFECT_NADE_EXPLODE(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_NADE_EXPLODE_RED;
+ case NUM_TEAM_2: return EFFECT_NADE_EXPLODE_BLUE;
+ case NUM_TEAM_3: return EFFECT_NADE_EXPLODE_YELLOW;
+ case NUM_TEAM_4: return EFFECT_NADE_EXPLODE_PINK;
+ default: return EFFECT_NADE_EXPLODE_NEUTRAL;
+ }
+}
+
+EFFECT(1, NADE_TRAIL_RED, "nade_red")
+EFFECT(1, NADE_TRAIL_BLUE, "nade_blue")
+EFFECT(1, NADE_TRAIL_YELLOW, "nade_yellow")
+EFFECT(1, NADE_TRAIL_PINK, "nade_pink")
+EFFECT(1, NADE_TRAIL_NEUTRAL, "nade_neutral")
+entity EFFECT_NADE_TRAIL(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_NADE_TRAIL_RED;
+ case NUM_TEAM_2: return EFFECT_NADE_TRAIL_BLUE;
+ case NUM_TEAM_3: return EFFECT_NADE_TRAIL_YELLOW;
+ case NUM_TEAM_4: return EFFECT_NADE_TRAIL_PINK;
+ default: return EFFECT_NADE_TRAIL_NEUTRAL;
+ }
+}
+
+EFFECT(1, NADE_TRAIL_BURN_RED, "nade_red_burn")
+EFFECT(1, NADE_TRAIL_BURN_BLUE, "nade_blue_burn")
+EFFECT(1, NADE_TRAIL_BURN_YELLOW, "nade_yellow_burn")
+EFFECT(1, NADE_TRAIL_BURN_PINK, "nade_pink_burn")
+EFFECT(1, NADE_TRAIL_BURN_NEUTRAL, "nade_neutral_burn")
+entity EFFECT_NADE_TRAIL_BURN(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_NADE_TRAIL_BURN_RED;
+ case NUM_TEAM_2: return EFFECT_NADE_TRAIL_BURN_BLUE;
+ case NUM_TEAM_3: return EFFECT_NADE_TRAIL_BURN_YELLOW;
+ case NUM_TEAM_4: return EFFECT_NADE_TRAIL_BURN_PINK;
+ default: return EFFECT_NADE_TRAIL_BURN_NEUTRAL;
+ }
+}
--- /dev/null
+#include "nades.qc"
+#ifndef MENUQC
+#include "net.qc"
+#endif
--- /dev/null
+#ifndef MENUQC
+#define NADE_PROJECTILE(i, projectile, trail) do { \
+ this.m_projectile[i] = projectile; \
+ this.m_trail[i] = trail; \
+} while (0)
+#else
+#define NADE_PROJECTILE(i, projectile, trail)
+#endif
+
+REGISTER_NADE(NORMAL) {
+ this.m_color = '1 1 1';
+ NADE_PROJECTILE(0, PROJECTILE_NADE, EFFECT_Null);
+ NADE_PROJECTILE(1, PROJECTILE_NADE_BURN, EFFECT_Null);
+}
+
+REGISTER_NADE(NAPALM) {
+ this.m_color = '2 0.5 0';
+ this.m_name = _("Napalm grenade");
+ this.m_icon = "nade_napalm";
+ NADE_PROJECTILE(0, PROJECTILE_NADE_NAPALM, EFFECT_TR_ROCKET);
+ NADE_PROJECTILE(1, PROJECTILE_NADE_NAPALM_BURN, EFFECT_SPIDERBOT_ROCKET_TRAIL);
+}
+
+REGISTER_NADE(ICE) {
+ this.m_color = '0 0.5 2';
+ this.m_name = _("Ice grenade");
+ this.m_icon = "nade_ice";
+ NADE_PROJECTILE(0, PROJECTILE_NADE_ICE, EFFECT_TR_NEXUIZPLASMA);
+ NADE_PROJECTILE(1, PROJECTILE_NADE_ICE_BURN, EFFECT_RACER_ROCKET_TRAIL);
+}
+
+REGISTER_NADE(TRANSLOCATE) {
+ this.m_color = '1 0 1';
+ this.m_name = _("Translocate grenade");
+ this.m_icon = "nade_translocate";
+ NADE_PROJECTILE(0, PROJECTILE_NADE_TRANSLOCATE, EFFECT_TR_CRYLINKPLASMA);
+ NADE_PROJECTILE(1, PROJECTILE_NADE_TRANSLOCATE, EFFECT_TR_CRYLINKPLASMA);
+}
+
+REGISTER_NADE(SPAWN) {
+ this.m_color = '1 0.9 0';
+ this.m_name = _("Spawn grenade");
+ this.m_icon = "nade_spawn";
+ NADE_PROJECTILE(0, PROJECTILE_NADE_SPAWN, EFFECT_NADE_TRAIL_YELLOW);
+ NADE_PROJECTILE(1, PROJECTILE_NADE_SPAWN, EFFECT_NADE_TRAIL_YELLOW);
+}
+
+REGISTER_NADE(HEAL) {
+ this.m_color = '1 0 0';
+ this.m_name = _("Heal grenade");
+ this.m_icon = "nade_heal";
+ NADE_PROJECTILE(0, PROJECTILE_NADE_HEAL, EFFECT_NADE_TRAIL_RED);
+ NADE_PROJECTILE(1, PROJECTILE_NADE_HEAL_BURN, EFFECT_NADE_TRAIL_BURN_RED);
+}
+
+REGISTER_NADE(MONSTER) {
+ this.m_color = '0.25 0.75 0';
+ this.m_name = _("Monster grenade");
+ this.m_icon = "nade_monster";
+ NADE_PROJECTILE(0, PROJECTILE_NADE_MONSTER, EFFECT_NADE_TRAIL_RED);
+ NADE_PROJECTILE(1, PROJECTILE_NADE_MONSTER_BURN, EFFECT_NADE_TRAIL_BURN_RED);
+}
--- /dev/null
+#include "nades.qh"
+
+#ifdef IMPLEMENTATION
+
+#ifndef MENUQC
+entity Nade_TrailEffect(int proj, int nade_team)
+{
+ switch (proj)
+ {
+ case PROJECTILE_NADE: return EFFECT_NADE_TRAIL(nade_team);
+ case PROJECTILE_NADE_BURN: return EFFECT_NADE_TRAIL_BURN(nade_team);
+ }
+
+ FOREACH(Nades, true, LAMBDA(
+ for (int j = 0; j < 2; j++)
+ {
+ if (it.m_projectile[j] == proj)
+ {
+ string trail = it.m_trail[j].eent_eff_name;
+ if (trail) return it.m_trail[j];
+ break;
+ }
+ }
+ ));
+
+ return EFFECT_Null;
+}
+#endif
+
+#ifdef CSQC
+REGISTER_MUTATOR(cl_nades, true);
+MUTATOR_HOOKFUNCTION(cl_nades, HUD_Draw_overlay)
+{
+ if (getstatf(STAT_HEALING_ORB) <= time) return false;
+ MUTATOR_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
+ MUTATOR_ARGV(0, float) = getstatf(STAT_HEALING_ORB_ALPHA);
+ return true;
+}
+MUTATOR_HOOKFUNCTION(cl_nades, Ent_Projectile)
+{
+ if (self.cnt == PROJECTILE_NAPALM_FOUNTAIN)
+ {
+ self.modelindex = 0;
+ self.traileffect = EFFECT_FIREBALL.m_id;
+ return true;
+ }
+ if (Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
+ {
+ setmodel(self, MDL_PROJECTILE_NADE);
+ entity trail = Nade_TrailEffect(self.cnt, self.team);
+ if (trail.eent_eff_name) self.traileffect = trail.m_id;
+ return true;
+ }
+}
+MUTATOR_HOOKFUNCTION(cl_nades, EditProjectile)
+{
+ if (self.cnt == PROJECTILE_NAPALM_FOUNTAIN)
+ {
+ loopsound(self, CH_SHOTS_SINGLE, SND(FIREBALL_FLY2), VOL_BASE, ATTEN_NORM);
+ self.mins = '-16 -16 -16';
+ self.maxs = '16 16 16';
+ }
+
+ entity nade_type = Nade_FromProjectile(self.cnt);
+ if (nade_type == NADE_TYPE_Null) return;
+ self.mins = '-16 -16 -16';
+ self.maxs = '16 16 16';
+ self.colormod = nade_type.m_color;
+ self.move_movetype = MOVETYPE_BOUNCE;
+ self.move_touch = func_null;
+ self.scale = 1.5;
+ self.avelocity = randomvec() * 720;
+
+ if (nade_type == NADE_TYPE_TRANSLOCATE || nade_type == NADE_TYPE_SPAWN)
+ self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+ else
+ self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
+}
+bool Projectile_isnade(int p)
+{
+ return Nade_FromProjectile(p) != NADE_TYPE_Null;
+}
+void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time)
+{
+ float bonusNades = getstatf(STAT_NADE_BONUS);
+ float bonusProgress = getstatf(STAT_NADE_BONUS_SCORE);
+ float bonusType = getstati(STAT_NADE_BONUS_TYPE);
+ Nade def = Nades_from(bonusType);
+ vector nadeColor = def.m_color;
+ string nadeIcon = def.m_icon;
+
+ vector iconPos, textPos;
+
+ if(autocvar_hud_panel_ammo_iconalign)
+ {
+ iconPos = myPos + eX * 2 * mySize.y;
+ textPos = myPos;
+ }
+ else
+ {
+ iconPos = myPos;
+ textPos = myPos + eX * mySize.y;
+ }
+
+ if(bonusNades > 0 || bonusProgress > 0)
+ {
+ DrawNadeProgressBar(myPos, mySize, bonusProgress, nadeColor);
+
+ if(autocvar_hud_panel_ammo_text)
+ drawstring_aspect(textPos, ftos(bonusNades), eX * (2/3) * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ if(draw_expanding)
+ drawpic_aspect_skin_expanding(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, expand_time);
+
+ drawpic_aspect_skin(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+}
+#endif
+
+#ifdef SVQC
+
+#include "../../../gamemodes/all.qh"
+#include "../../../monsters/spawn.qh"
+#include "../../../monsters/sv_monsters.qh"
+#include "../../../../server/g_subs.qh"
+
+REGISTER_MUTATOR(nades, cvar("g_nades"))
+{
+ MUTATOR_ONADD
+ {
+ addstat(STAT_NADE_TIMER, AS_FLOAT, nade_timer);
+ addstat(STAT_NADE_BONUS, AS_FLOAT, bonus_nades);
+ addstat(STAT_NADE_BONUS_TYPE, AS_INT, nade_type);
+ addstat(STAT_NADE_BONUS_SCORE, AS_FLOAT, bonus_nade_score);
+ addstat(STAT_HEALING_ORB, AS_FLOAT, stat_healing_orb);
+ addstat(STAT_HEALING_ORB_ALPHA, AS_FLOAT, stat_healing_orb_alpha);
+ }
+
+ return false;
+}
+
+.float nade_time_primed;
+
+.entity nade_spawnloc;
+
+void nade_timer_think()
+{SELFPARAM();
+ self.skin = 8 - (self.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10);
+ self.nextthink = time;
+ if(!self.owner || wasfreed(self.owner))
+ remove(self);
+}
+
+void nade_burn_spawn(entity _nade)
+{
+ CSQCProjectile(_nade, true, Nades_from(_nade.nade_type).m_projectile[true], true);
+}
+
+void nade_spawn(entity _nade)
+{
+ entity timer = new(nade_timer);
+ setmodel(timer, MDL_NADE_TIMER);
+ setattachment(timer, _nade, "");
+ timer.colormap = _nade.colormap;
+ timer.glowmod = _nade.glowmod;
+ timer.think = nade_timer_think;
+ timer.nextthink = time;
+ timer.wait = _nade.wait;
+ timer.owner = _nade;
+ timer.skin = 10;
+
+ _nade.effects |= EF_LOWPRECISION;
+
+ CSQCProjectile(_nade, true, Nades_from(_nade.nade_type).m_projectile[false], true);
+}
+
+void napalm_damage(float dist, float damage, float edgedamage, float burntime)
+{SELFPARAM();
+ entity e;
+ float d;
+ vector p;
+
+ if ( damage < 0 )
+ return;
+
+ RandomSelection_Init();
+ for(e = WarpZone_FindRadius(self.origin, dist, true); e; e = e.chain)
+ if(e.takedamage == DAMAGE_AIM)
+ if(self.realowner != e || autocvar_g_nades_napalm_selfdamage)
+ if(!IS_PLAYER(e) || !self.realowner || DIFF_TEAM(e, self))
+ if(!e.frozen)
+ {
+ p = e.origin;
+ p.x += e.mins.x + random() * (e.maxs.x - e.mins.x);
+ p.y += e.mins.y + random() * (e.maxs.y - e.mins.y);
+ p.z += e.mins.z + random() * (e.maxs.z - e.mins.z);
+ d = vlen(WarpZone_UnTransformOrigin(e, self.origin) - p);
+ if(d < dist)
+ {
+ e.fireball_impactvec = p;
+ RandomSelection_Add(e, 0, string_null, 1 / (1 + d), !Fire_IsBurning(e));
+ }
+ }
+ if(RandomSelection_chosen_ent)
+ {
+ d = vlen(WarpZone_UnTransformOrigin(RandomSelection_chosen_ent, self.origin) - RandomSelection_chosen_ent.fireball_impactvec);
+ d = damage + (edgedamage - damage) * (d / dist);
+ Fire_AddDamage(RandomSelection_chosen_ent, self.realowner, d * burntime, burntime, self.projectiledeathtype | HITTYPE_BOUNCE);
+ //trailparticles(self, particleeffectnum(EFFECT_FIREBALL_LASER), self.origin, RandomSelection_chosen_ent.fireball_impactvec);
+ Send_Effect(EFFECT_FIREBALL_LASER, self.origin, RandomSelection_chosen_ent.fireball_impactvec - self.origin, 1);
+ }
+}
+
+
+void napalm_ball_think()
+{SELFPARAM();
+ if(round_handler_IsActive())
+ if(!round_handler_IsRoundStarted())
+ {
+ remove(self);
+ return;
+ }
+
+ if(time > self.pushltime)
+ {
+ remove(self);
+ return;
+ }
+
+ vector midpoint = ((self.absmin + self.absmax) * 0.5);
+ if(pointcontents(midpoint) == CONTENT_WATER)
+ {
+ self.velocity = self.velocity * 0.5;
+
+ if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
+ { self.velocity_z = 200; }
+ }
+
+ self.angles = vectoangles(self.velocity);
+
+ napalm_damage(autocvar_g_nades_napalm_ball_radius,autocvar_g_nades_napalm_ball_damage,
+ autocvar_g_nades_napalm_ball_damage,autocvar_g_nades_napalm_burntime);
+
+ self.nextthink = time + 0.1;
+}
+
+
+void nade_napalm_ball()
+{SELFPARAM();
+ entity proj;
+ vector kick;
+
+ spamsound(self, CH_SHOTS, SND(FIREBALL_FIRE), VOL_BASE, ATTEN_NORM);
+
+ proj = new(grenade);
+ proj.owner = self.owner;
+ proj.realowner = self.realowner;
+ proj.team = self.owner.team;
+ proj.bot_dodge = true;
+ proj.bot_dodgerating = autocvar_g_nades_napalm_ball_damage;
+ proj.movetype = MOVETYPE_BOUNCE;
+ proj.projectiledeathtype = DEATH_NADE_NAPALM.m_id;
+ PROJECTILE_MAKETRIGGER(proj);
+ setmodel(proj, MDL_Null);
+ proj.scale = 1;//0.5;
+ setsize(proj, '-4 -4 -4', '4 4 4');
+ setorigin(proj, self.origin);
+ proj.think = napalm_ball_think;
+ proj.nextthink = time;
+ proj.damageforcescale = autocvar_g_nades_napalm_ball_damageforcescale;
+ proj.effects = EF_LOWPRECISION | EF_FLAME;
+
+ kick.x =(random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread;
+ kick.y = (random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread;
+ kick.z = (random()/2+0.5) * autocvar_g_nades_napalm_ball_spread;
+ proj.velocity = kick;
+
+ proj.pushltime = time + autocvar_g_nades_napalm_ball_lifetime;
+
+ proj.angles = vectoangles(proj.velocity);
+ proj.flags = FL_PROJECTILE;
+ proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
+
+ //CSQCProjectile(proj, true, PROJECTILE_NAPALM_FIRE, true);
+}
+
+
+void napalm_fountain_think()
+{SELFPARAM();
+
+ if(round_handler_IsActive())
+ if(!round_handler_IsRoundStarted())
+ {
+ remove(self);
+ return;
+ }
+
+ if(time >= self.ltime)
+ {
+ remove(self);
+ return;
+ }
+
+ vector midpoint = ((self.absmin + self.absmax) * 0.5);
+ if(pointcontents(midpoint) == CONTENT_WATER)
+ {
+ self.velocity = self.velocity * 0.5;
+
+ if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
+ { self.velocity_z = 200; }
+
+ UpdateCSQCProjectile(self);
+ }
+
+ napalm_damage(autocvar_g_nades_napalm_fountain_radius, autocvar_g_nades_napalm_fountain_damage,
+ autocvar_g_nades_napalm_fountain_edgedamage, autocvar_g_nades_napalm_burntime);
+
+ self.nextthink = time + 0.1;
+ if(time >= self.nade_special_time)
+ {
+ self.nade_special_time = time + autocvar_g_nades_napalm_fountain_delay;
+ nade_napalm_ball();
+ }
+}
+
+void nade_napalm_boom()
+{SELFPARAM();
+ entity fountain;
+ int c;
+ for (c = 0; c < autocvar_g_nades_napalm_ball_count; c++)
+ nade_napalm_ball();
+
+
+ fountain = spawn();
+ fountain.owner = self.owner;
+ fountain.realowner = self.realowner;
+ fountain.origin = self.origin;
+ setorigin(fountain, fountain.origin);
+ fountain.think = napalm_fountain_think;
+ fountain.nextthink = time;
+ fountain.ltime = time + autocvar_g_nades_napalm_fountain_lifetime;
+ fountain.pushltime = fountain.ltime;
+ fountain.team = self.team;
+ fountain.movetype = MOVETYPE_TOSS;
+ fountain.projectiledeathtype = DEATH_NADE_NAPALM.m_id;
+ fountain.bot_dodge = true;
+ fountain.bot_dodgerating = autocvar_g_nades_napalm_fountain_damage;
+ fountain.nade_special_time = time;
+ setsize(fountain, '-16 -16 -16', '16 16 16');
+ CSQCProjectile(fountain, true, PROJECTILE_NAPALM_FOUNTAIN, true);
+}
+
+void nade_ice_freeze(entity freezefield, entity frost_target, float freeze_time)
+{
+ frost_target.frozen_by = freezefield.realowner;
+ Send_Effect(EFFECT_ELECTRO_IMPACT, frost_target.origin, '0 0 0', 1);
+ Freeze(frost_target, 1/freeze_time, 3, false);
+
+ Drop_Special_Items(frost_target);
+}
+
+void nade_ice_think()
+{SELFPARAM();
+
+ if(round_handler_IsActive())
+ if(!round_handler_IsRoundStarted())
+ {
+ remove(self);
+ return;
+ }
+
+ if(time >= self.ltime)
+ {
+ if ( autocvar_g_nades_ice_explode )
+ {
+ entity expef = EFFECT_NADE_EXPLODE(self.realowner.team);
+ Send_Effect(expef, self.origin + '0 0 1', '0 0 0', 1);
+ sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+
+ RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
+ autocvar_g_nades_nade_radius, self, world, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
+ Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
+ autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
+ }
+ remove(self);
+ return;
+ }
+
+
+ self.nextthink = time+0.1;
+
+ // gaussian
+ float randomr;
+ randomr = random();
+ randomr = exp(-5*randomr*randomr)*autocvar_g_nades_nade_radius;
+ float randomw;
+ randomw = random()*M_PI*2;
+ vector randomp;
+ randomp.x = randomr*cos(randomw);
+ randomp.y = randomr*sin(randomw);
+ randomp.z = 1;
+ Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, self.origin + randomp, '0 0 0', 1);
+
+ if(time >= self.nade_special_time)
+ {
+ self.nade_special_time = time+0.7;
+
+ Send_Effect(EFFECT_ELECTRO_IMPACT, self.origin, '0 0 0', 1);
+ Send_Effect(EFFECT_ICEFIELD, self.origin, '0 0 0', 1);
+ }
+
+
+ float current_freeze_time = self.ltime - time - 0.1;
+
+ entity e;
+ for(e = findradius(self.origin, autocvar_g_nades_nade_radius); e; e = e.chain)
+ if(e != self)
+ if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(e, self.realowner) || e == self.realowner))
+ if(e.takedamage && e.deadflag == DEAD_NO)
+ if(e.health > 0)
+ if(!e.revival_time || ((time - e.revival_time) >= 1.5))
+ if(!e.frozen)
+ if(current_freeze_time > 0)
+ nade_ice_freeze(self, e, current_freeze_time);
+}
+
+void nade_ice_boom()
+{SELFPARAM();
+ entity fountain;
+ fountain = spawn();
+ fountain.owner = self.owner;
+ fountain.realowner = self.realowner;
+ fountain.origin = self.origin;
+ setorigin(fountain, fountain.origin);
+ fountain.think = nade_ice_think;
+ fountain.nextthink = time;
+ fountain.ltime = time + autocvar_g_nades_ice_freeze_time;
+ fountain.pushltime = fountain.wait = fountain.ltime;
+ fountain.team = self.team;
+ fountain.movetype = MOVETYPE_TOSS;
+ fountain.projectiledeathtype = DEATH_NADE_ICE.m_id;
+ fountain.bot_dodge = false;
+ setsize(fountain, '-16 -16 -16', '16 16 16');
+ fountain.nade_special_time = time+0.3;
+ fountain.angles = self.angles;
+
+ if ( autocvar_g_nades_ice_explode )
+ {
+ setmodel(fountain, MDL_PROJECTILE_GRENADE);
+ entity timer = new(nade_timer);
+ setmodel(timer, MDL_NADE_TIMER);
+ setattachment(timer, fountain, "");
+ timer.colormap = self.colormap;
+ timer.glowmod = self.glowmod;
+ timer.think = nade_timer_think;
+ timer.nextthink = time;
+ timer.wait = fountain.ltime;
+ timer.owner = fountain;
+ timer.skin = 10;
+ }
+ else
+ setmodel(fountain, MDL_Null);
+}
+
+void nade_translocate_boom()
+{SELFPARAM();
+ if(self.realowner.vehicle)
+ return;
+
+ vector locout = self.origin + '0 0 1' * (1 - self.realowner.mins.z - 24);
+ tracebox(locout, self.realowner.mins, self.realowner.maxs, locout, MOVE_NOMONSTERS, self.realowner);
+ locout = trace_endpos;
+
+ makevectors(self.realowner.angles);
+
+ MUTATOR_CALLHOOK(PortalTeleport, self.realowner);
+
+ TeleportPlayer(self, self.realowner, locout, self.realowner.angles, v_forward * vlen(self.realowner.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
+}
+
+void nade_spawn_boom()
+{SELFPARAM();
+ entity spawnloc = spawn();
+ setorigin(spawnloc, self.origin);
+ setsize(spawnloc, self.realowner.mins, self.realowner.maxs);
+ spawnloc.movetype = MOVETYPE_NONE;
+ spawnloc.solid = SOLID_NOT;
+ spawnloc.drawonlytoclient = self.realowner;
+ spawnloc.effects = EF_STARDUST;
+ spawnloc.cnt = autocvar_g_nades_spawn_count;
+
+ if(self.realowner.nade_spawnloc)
+ {
+ remove(self.realowner.nade_spawnloc);
+ self.realowner.nade_spawnloc = world;
+ }
+
+ self.realowner.nade_spawnloc = spawnloc;
+}
+
+void nade_heal_think()
+{SELFPARAM();
+ if(time >= self.ltime)
+ {
+ remove(self);
+ return;
+ }
+
+ self.nextthink = time;
+
+ if(time >= self.nade_special_time)
+ {
+ self.nade_special_time = time+0.25;
+ self.nade_show_particles = 1;
+ }
+ else
+ self.nade_show_particles = 0;
+}
+
+void nade_heal_touch()
+{SELFPARAM();
+ float maxhealth;
+ float health_factor;
+ if(IS_PLAYER(other) || IS_MONSTER(other))
+ if(other.deadflag == DEAD_NO)
+ if(!other.frozen)
+ {
+ health_factor = autocvar_g_nades_heal_rate*frametime/2;
+ if ( other != self.realowner )
+ {
+ if ( SAME_TEAM(other,self) )
+ health_factor *= autocvar_g_nades_heal_friend;
+ else
+ health_factor *= autocvar_g_nades_heal_foe;
+ }
+ if ( health_factor > 0 )
+ {
+ maxhealth = (IS_MONSTER(other)) ? other.max_health : g_pickup_healthmega_max;
+ if ( other.health < maxhealth )
+ {
+ if ( self.nade_show_particles )
+ Send_Effect(EFFECT_HEALING, other.origin, '0 0 0', 1);
+ other.health = min(other.health+health_factor, maxhealth);
+ }
+ other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
+ }
+ else if ( health_factor < 0 )
+ {
+ Damage(other,self,self.realowner,-health_factor,DEATH_NADE_HEAL.m_id,other.origin,'0 0 0');
+ }
+
+ }
+
+ if ( IS_REAL_CLIENT(other) || IS_VEHICLE(other) )
+ {
+ entity show_red = (IS_VEHICLE(other)) ? other.owner : other;
+ show_red.stat_healing_orb = time+0.1;
+ show_red.stat_healing_orb_alpha = 0.75 * (self.ltime - time) / self.healer_lifetime;
+ }
+}
+
+void nade_heal_boom()
+{SELFPARAM();
+ entity healer;
+ healer = spawn();
+ healer.owner = self.owner;
+ healer.realowner = self.realowner;
+ setorigin(healer, self.origin);
+ healer.healer_lifetime = autocvar_g_nades_heal_time; // save the cvar
+ healer.ltime = time + healer.healer_lifetime;
+ healer.team = self.realowner.team;
+ healer.bot_dodge = false;
+ healer.solid = SOLID_TRIGGER;
+ healer.touch = nade_heal_touch;
+
+ setmodel(healer, MDL_NADE_HEAL);
+ healer.healer_radius = autocvar_g_nades_nade_radius;
+ vector size = '1 1 1' * healer.healer_radius / 2;
+ setsize(healer,-size,size);
+
+ Net_LinkEntity(healer, true, 0, healer_send);
+
+ healer.think = nade_heal_think;
+ healer.nextthink = time;
+ healer.SendFlags |= 1;
+}
+
+void nade_monster_boom()
+{SELFPARAM();
+ entity e = spawnmonster(self.pokenade_type, 0, self.realowner, self.realowner, self.origin, false, false, 1);
+
+ if(autocvar_g_nades_pokenade_monster_lifetime > 0)
+ e.monster_lifetime = time + autocvar_g_nades_pokenade_monster_lifetime;
+ e.monster_skill = MONSTER_SKILL_INSANE;
+}
+
+void nade_boom()
+{SELFPARAM();
+ entity expef = NULL;
+ bool nade_blast = true;
+
+ switch ( Nades_from(self.nade_type) )
+ {
+ case NADE_TYPE_NAPALM:
+ nade_blast = autocvar_g_nades_napalm_blast;
+ expef = EFFECT_EXPLOSION_MEDIUM;
+ break;
+ case NADE_TYPE_ICE:
+ nade_blast = false;
+ expef = EFFECT_ELECTRO_COMBO; // hookbomb_explode electro_combo bigplasma_impact
+ break;
+ case NADE_TYPE_TRANSLOCATE:
+ nade_blast = false;
+ break;
+ case NADE_TYPE_MONSTER:
+ case NADE_TYPE_SPAWN:
+ nade_blast = false;
+ switch(self.realowner.team)
+ {
+ case NUM_TEAM_1: expef = EFFECT_SPAWN_RED; break;
+ case NUM_TEAM_2: expef = EFFECT_SPAWN_BLUE; break;
+ case NUM_TEAM_3: expef = EFFECT_SPAWN_YELLOW; break;
+ case NUM_TEAM_4: expef = EFFECT_SPAWN_PINK; break;
+ default: expef = EFFECT_SPAWN_NEUTRAL; break;
+ }
+ break;
+ case NADE_TYPE_HEAL:
+ nade_blast = false;
+ expef = EFFECT_SPAWN_RED;
+ break;
+
+ default:
+ case NADE_TYPE_NORMAL:
+ expef = EFFECT_NADE_EXPLODE(self.realowner.team);
+ break;
+ }
+
+ if(expef)
+ Send_Effect(expef, findbetterlocation(self.origin, 8), '0 0 0', 1);
+
+ sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
+ sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+
+ self.event_damage = func_null; // prevent somehow calling damage in the next call
+
+ if(nade_blast)
+ {
+ RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
+ autocvar_g_nades_nade_radius, self, world, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
+ Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
+ }
+
+ if(self.takedamage)
+ switch ( Nades_from(self.nade_type) )
+ {
+ case NADE_TYPE_NAPALM: nade_napalm_boom(); break;
+ case NADE_TYPE_ICE: nade_ice_boom(); break;
+ case NADE_TYPE_TRANSLOCATE: nade_translocate_boom(); break;
+ case NADE_TYPE_SPAWN: nade_spawn_boom(); break;
+ case NADE_TYPE_HEAL: nade_heal_boom(); break;
+ case NADE_TYPE_MONSTER: nade_monster_boom(); break;
+ }
+
+ entity head;
+ for(head = world; (head = find(head, classname, "grapplinghook")); )
+ if(head.aiment == self)
+ RemoveGrapplingHook(head.realowner);
+
+ remove(self);
+}
+
+void nade_touch()
+{SELFPARAM();
+ /*float is_weapclip = 0;
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW)
+ if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID))
+ if (!(trace_dphitcontents & DPCONTENTS_OPAQUE))
+ is_weapclip = 1;*/
+ if(ITEM_TOUCH_NEEDKILL()) // || is_weapclip)
+ {
+ entity head;
+ for(head = world; (head = find(head, classname, "grapplinghook")); )
+ if(head.aiment == self)
+ RemoveGrapplingHook(head.realowner);
+ remove(self);
+ return;
+ }
+
+ PROJECTILE_TOUCH;
+
+ //setsize(self, '-2 -2 -2', '2 2 2');
+ //UpdateCSQCProjectile(self);
+ if(self.health == self.max_health)
+ {
+ spamsound(self, CH_SHOTS, SND(GRENADE_BOUNCE_RANDOM()), VOL_BASE, ATTEN_NORM);
+ return;
+ }
+
+ self.enemy = other;
+ nade_boom();
+}
+
+void nade_beep()
+{SELFPARAM();
+ sound(self, CH_SHOTS_SINGLE, SND_NADE_BEEP, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
+ self.think = nade_boom;
+ self.nextthink = max(self.wait, time);
+}
+
+void nade_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+ if(ITEM_DAMAGE_NEEDKILL(deathtype))
+ {
+ self.takedamage = DAMAGE_NO;
+ nade_boom();
+ return;
+ }
+
+ if(self.nade_type == NADE_TYPE_TRANSLOCATE.m_id || self.nade_type == NADE_TYPE_SPAWN.m_id)
+ return;
+
+ if (MUTATOR_CALLHOOK(Nade_Damage, DEATH_WEAPONOF(deathtype), force, damage)) {}
+ else if(DEATH_ISWEAPON(deathtype, WEP_BLASTER))
+ {
+ force *= 1.5;
+ damage = 0;
+ }
+ else if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER) && (deathtype & HITTYPE_SECONDARY))
+ {
+ force *= 0.5; // too much
+ damage = 0;
+ }
+ else if(DEATH_ISWEAPON(deathtype, WEP_VORTEX) || DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
+ {
+ force *= 6;
+ damage = self.max_health * 0.55;
+ }
+ else if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN))
+ damage = self.max_health * 0.1;
+ else if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE) || DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) // WEAPONTODO
+ {
+ if(deathtype & HITTYPE_SECONDARY)
+ {
+ damage = self.max_health * 0.1;
+ force *= 10;
+ }
+ else
+ damage = self.max_health * 1.15;
+ }
+
+ self.velocity += force;
+ UpdateCSQCProjectile(self);
+
+ if(damage <= 0 || ((self.flags & FL_ONGROUND) && IS_PLAYER(attacker)))
+ return;
+
+ if(self.health == self.max_health)
+ {
+ sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
+ self.nextthink = max(time + autocvar_g_nades_nade_lifetime, time);
+ self.think = nade_beep;
+ }
+
+ self.health -= damage;
+
+ if ( self.nade_type != NADE_TYPE_HEAL.m_id || IS_PLAYER(attacker) )
+ self.realowner = attacker;
+
+ if(self.health <= 0)
+ W_PrepareExplosionByDamage(attacker, nade_boom);
+ else
+ nade_burn_spawn(self);
+}
+
+void toss_nade(entity e, vector _velocity, float _time)
+{SELFPARAM();
+ if(e.nade == world)
+ return;
+
+ entity _nade = e.nade;
+ e.nade = world;
+
+ remove(e.fake_nade);
+ e.fake_nade = world;
+
+ makevectors(e.v_angle);
+
+ W_SetupShot(e, false, false, "", CH_WEAPON_A, 0);
+
+ Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_NADES);
+
+ vector offset = (v_forward * autocvar_g_nades_throw_offset.x)
+ + (v_right * autocvar_g_nades_throw_offset.y)
+ + (v_up * autocvar_g_nades_throw_offset.z);
+ if(autocvar_g_nades_throw_offset == '0 0 0')
+ offset = '0 0 0';
+
+ setorigin(_nade, w_shotorg + offset + (v_right * 25) * -1);
+ //setmodel(_nade, MDL_PROJECTILE_NADE);
+ //setattachment(_nade, world, "");
+ PROJECTILE_MAKETRIGGER(_nade);
+ setsize(_nade, '-16 -16 -16', '16 16 16');
+ _nade.movetype = MOVETYPE_BOUNCE;
+
+ tracebox(_nade.origin, _nade.mins, _nade.maxs, _nade.origin, false, _nade);
+ if (trace_startsolid)
+ setorigin(_nade, e.origin);
+
+ if(self.v_angle.x >= 70 && self.v_angle.x <= 110 && self.BUTTON_CROUCH)
+ _nade.velocity = '0 0 100';
+ else if(autocvar_g_nades_nade_newton_style == 1)
+ _nade.velocity = e.velocity + _velocity;
+ else if(autocvar_g_nades_nade_newton_style == 2)
+ _nade.velocity = _velocity;
+ else
+ _nade.velocity = W_CalculateProjectileVelocity(e.velocity, _velocity, true);
+
+ _nade.touch = nade_touch;
+ _nade.health = autocvar_g_nades_nade_health;
+ _nade.max_health = _nade.health;
+ _nade.takedamage = DAMAGE_AIM;
+ _nade.event_damage = nade_damage;
+ _nade.customizeentityforclient = func_null;
+ _nade.exteriormodeltoclient = world;
+ _nade.traileffectnum = 0;
+ _nade.teleportable = true;
+ _nade.pushable = true;
+ _nade.gravity = 1;
+ _nade.missile_flags = MIF_SPLASH | MIF_ARC;
+ _nade.damagedbycontents = true;
+ _nade.angles = vectoangles(_nade.velocity);
+ _nade.flags = FL_PROJECTILE;
+ _nade.projectiledeathtype = DEATH_NADE.m_id;
+ _nade.toss_time = time;
+ _nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
+
+ if(_nade.nade_type == NADE_TYPE_TRANSLOCATE.m_id || _nade.nade_type == NADE_TYPE_SPAWN.m_id)
+ _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+ else
+ _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
+
+ nade_spawn(_nade);
+
+ if(_time)
+ {
+ _nade.think = nade_boom;
+ _nade.nextthink = _time;
+ }
+
+ e.nade_refire = time + autocvar_g_nades_nade_refire;
+ e.nade_timer = 0;
+}
+
+void nades_GiveBonus(entity player, float score)
+{
+ if (autocvar_g_nades)
+ if (autocvar_g_nades_bonus)
+ if (IS_REAL_CLIENT(player))
+ if (IS_PLAYER(player) && player.bonus_nades < autocvar_g_nades_bonus_max)
+ if (player.frozen == 0)
+ if (player.deadflag == DEAD_NO)
+ {
+ if ( player.bonus_nade_score < 1 )
+ player.bonus_nade_score += score/autocvar_g_nades_bonus_score_max;
+
+ if ( player.bonus_nade_score >= 1 )
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_BONUS);
+ play2(player, SND(KH_ALARM));
+ player.bonus_nades++;
+ player.bonus_nade_score -= 1;
+ }
+ }
+}
+
+/** Remove all bonus nades from a player */
+void nades_RemoveBonus(entity player)
+{
+ player.bonus_nades = player.bonus_nade_score = 0;
+}
+
+MUTATOR_HOOKFUNCTION(nades, PutClientInServer)
+{
+ nades_RemoveBonus(self);
+}
+
+float nade_customize()
+{SELFPARAM();
+ //if(IS_SPEC(other)) { return false; }
+ if(other == self.realowner || (IS_SPEC(other) && other.enemy == self.realowner))
+ {
+ // somewhat hide the model, but keep the glow
+ //self.effects = 0;
+ if(self.traileffectnum)
+ self.traileffectnum = 0;
+ self.alpha = -1;
+ }
+ else
+ {
+ //self.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+ if(!self.traileffectnum)
+ self.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(self.nade_type).m_projectile[false], self.team).eent_eff_name);
+ self.alpha = 1;
+ }
+
+ return true;
+}
+
+void nade_prime()
+{SELFPARAM();
+ if(autocvar_g_nades_bonus_only)
+ if(!self.bonus_nades)
+ return; // only allow bonus nades
+
+ if(self.nade)
+ remove(self.nade);
+
+ if(self.fake_nade)
+ remove(self.fake_nade);
+
+ entity n = new(nade), fn = new(fake_nade);
+
+ if(self.items & ITEM_Strength.m_itemid && autocvar_g_nades_bonus_onstrength)
+ n.nade_type = self.nade_type;
+ else if (self.bonus_nades >= 1)
+ {
+ n.nade_type = self.nade_type;
+ n.pokenade_type = self.pokenade_type;
+ self.bonus_nades -= 1;
+ }
+ else
+ {
+ n.nade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_nade_type : autocvar_g_nades_nade_type);
+ n.pokenade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_pokenade_type : autocvar_g_nades_pokenade_monster_type);
+ }
+
+ n.nade_type = bound(1, n.nade_type, Nades_COUNT);
+
+ setmodel(n, MDL_PROJECTILE_NADE);
+ //setattachment(n, self, "bip01 l hand");
+ n.exteriormodeltoclient = self;
+ n.customizeentityforclient = nade_customize;
+ n.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(n.nade_type).m_projectile[false], self.team).eent_eff_name);
+ n.colormod = Nades_from(n.nade_type).m_color;
+ n.realowner = self;
+ n.colormap = self.colormap;
+ n.glowmod = self.glowmod;
+ n.wait = time + autocvar_g_nades_nade_lifetime;
+ n.nade_time_primed = time;
+ n.think = nade_beep;
+ n.nextthink = max(n.wait - 3, time);
+ n.projectiledeathtype = DEATH_NADE.m_id;
+
+ setmodel(fn, MDL_NADE_VIEW);
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+ setattachment(fn, self.(weaponentity), "");
+ fn.realowner = fn.owner = self;
+ fn.colormod = Nades_from(n.nade_type).m_color;
+ fn.colormap = self.colormap;
+ fn.glowmod = self.glowmod;
+ fn.think = SUB_Remove;
+ fn.nextthink = n.wait;
+
+ self.nade = n;
+ self.fake_nade = fn;
+}
+
+float CanThrowNade()
+{SELFPARAM();
+ if(self.vehicle)
+ return false;
+
+ if(gameover)
+ return false;
+
+ if(self.deadflag != DEAD_NO)
+ return false;
+
+ if (!autocvar_g_nades)
+ return false; // allow turning them off mid match
+
+ if(forbidWeaponUse(self))
+ return false;
+
+ if (!IS_PLAYER(self))
+ return false;
+
+ return true;
+}
+
+.bool nade_altbutton;
+
+void nades_CheckThrow()
+{SELFPARAM();
+ if(!CanThrowNade())
+ return;
+
+ entity held_nade = self.nade;
+ if (!held_nade)
+ {
+ self.nade_altbutton = true;
+ if(time > self.nade_refire)
+ {
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_NADE_THROW);
+ nade_prime();
+ self.nade_refire = time + autocvar_g_nades_nade_refire;
+ }
+ }
+ else
+ {
+ self.nade_altbutton = false;
+ if (time >= held_nade.nade_time_primed + 1) {
+ makevectors(self.v_angle);
+ float _force = time - held_nade.nade_time_primed;
+ _force /= autocvar_g_nades_nade_lifetime;
+ _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
+ toss_nade(self, (v_forward * 0.75 + v_up * 0.2 + v_right * 0.05) * _force, 0);
+ }
+ }
+}
+
+void nades_Clear(entity player)
+{
+ if(player.nade)
+ remove(player.nade);
+ if(player.fake_nade)
+ remove(player.fake_nade);
+
+ player.nade = player.fake_nade = world;
+ player.nade_timer = 0;
+}
+
+MUTATOR_HOOKFUNCTION(nades, VehicleEnter)
+{
+ if(vh_player.nade)
+ toss_nade(vh_player, '0 0 100', max(vh_player.nade.wait, time + 0.05));
+
+ return false;
+}
+
+CLASS(NadeOffhand, OffhandWeapon)
+ METHOD(NadeOffhand, offhand_think, void(NadeOffhand this, entity player, bool key_pressed))
+ {
+ entity held_nade = player.nade;
+ if (held_nade)
+ {
+ player.nade_timer = bound(0, (time - held_nade.nade_time_primed) / autocvar_g_nades_nade_lifetime, 1);
+ // LOG_TRACEF("%d %d\n", player.nade_timer, time - held_nade.nade_time_primed);
+ makevectors(player.angles);
+ held_nade.velocity = player.velocity;
+ setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
+ held_nade.angles_y = player.angles.y;
+
+ if (time + 0.1 >= held_nade.wait)
+ toss_nade(player, '0 0 0', time + 0.05);
+ }
+
+ if (!CanThrowNade()) return;
+ if (!(time > player.nade_refire)) return;
+ if (key_pressed) {
+ if (!held_nade) {
+ nade_prime();
+ held_nade = player.nade;
+ }
+ } else if (time >= held_nade.nade_time_primed + 1) {
+ if (held_nade) {
+ makevectors(player.v_angle);
+ float _force = time - held_nade.nade_time_primed;
+ _force /= autocvar_g_nades_nade_lifetime;
+ _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
+ toss_nade(player, (v_forward * 0.7 + v_up * 0.2 + v_right * 0.1) * _force, 0);
+ }
+ }
+ }
+ENDCLASS(NadeOffhand)
+NadeOffhand OFFHAND_NADE; STATIC_INIT(OFFHAND_NADE) { OFFHAND_NADE = NEW(NadeOffhand); }
+
+MUTATOR_HOOKFUNCTION(nades, ForbidThrowCurrentWeapon, CBC_ORDER_LAST)
+{
+ if (self.offhand != OFFHAND_NADE || (self.weapons & WEPSET(HOOK)) || autocvar_g_nades_override_dropweapon) {
+ nades_CheckThrow();
+ return true;
+ }
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
+{SELFPARAM();
+ if (!IS_PLAYER(self)) { return false; }
+
+ if (self.nade && (self.offhand != OFFHAND_NADE || (self.weapons & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, self, self.nade_altbutton);
+
+ if(IS_PLAYER(self))
+ {
+ if ( autocvar_g_nades_bonus && autocvar_g_nades )
+ {
+ entity key;
+ float key_count = 0;
+ FOR_EACH_KH_KEY(key) if(key.owner == self) { ++key_count; }
+
+ float time_score;
+ if(self.flagcarried || self.ballcarried) // this player is important
+ time_score = autocvar_g_nades_bonus_score_time_flagcarrier;
+ else
+ time_score = autocvar_g_nades_bonus_score_time;
+
+ if(key_count)
+ time_score = autocvar_g_nades_bonus_score_time_flagcarrier * key_count; // multiply by the number of keys the player is holding
+
+ if(autocvar_g_nades_bonus_client_select)
+ {
+ self.nade_type = self.cvar_cl_nade_type;
+ self.pokenade_type = self.cvar_cl_pokenade_type;
+ }
+ else
+ {
+ self.nade_type = autocvar_g_nades_bonus_type;
+ self.pokenade_type = autocvar_g_nades_pokenade_monster_type;
+ }
+
+ self.nade_type = bound(1, self.nade_type, Nades_COUNT);
+
+ if(self.bonus_nade_score >= 0 && autocvar_g_nades_bonus_score_max)
+ nades_GiveBonus(self, time_score / autocvar_g_nades_bonus_score_max);
+ }
+ else
+ {
+ self.bonus_nades = self.bonus_nade_score = 0;
+ }
+ }
+
+ float n = 0;
+ entity o = world;
+ if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
+ n = -1;
+ else
+ {
+ vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
+ n = 0;
+ FOR_EACH_PLAYER(other) if(self != other)
+ {
+ if(other.deadflag == DEAD_NO)
+ if(other.frozen == 0)
+ if(SAME_TEAM(other, self))
+ if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
+ {
+ if(!o)
+ o = other;
+ if(self.frozen == 1)
+ other.reviving = true;
+ ++n;
+ }
+ }
+ }
+
+ if(n && self.frozen == 3) // OK, there is at least one teammate reviving us
+ {
+ self.revive_progress = bound(0, self.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
+ self.health = max(1, self.revive_progress * start_health);
+
+ if(self.revive_progress >= 1)
+ {
+ Unfreeze(self);
+
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
+ Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname);
+ }
+
+ FOR_EACH_PLAYER(other) if(other.reviving)
+ {
+ other.revive_progress = self.revive_progress;
+ other.reviving = false;
+ }
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, PlayerSpawn)
+{SELFPARAM();
+ if(autocvar_g_nades_spawn)
+ self.nade_refire = time + autocvar_g_spawnshieldtime;
+ else
+ self.nade_refire = time + autocvar_g_nades_nade_refire;
+
+ if(autocvar_g_nades_bonus_client_select)
+ self.nade_type = self.cvar_cl_nade_type;
+
+ self.nade_timer = 0;
+
+ if (!self.offhand) self.offhand = OFFHAND_NADE;
+
+ if(self.nade_spawnloc)
+ {
+ setorigin(self, self.nade_spawnloc.origin);
+ self.nade_spawnloc.cnt -= 1;
+
+ if(self.nade_spawnloc.cnt <= 0)
+ {
+ remove(self.nade_spawnloc);
+ self.nade_spawnloc = world;
+ }
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, PlayerDies, CBC_ORDER_LAST)
+{
+ if(frag_target.nade)
+ if(!frag_target.frozen || !autocvar_g_freezetag_revive_nade)
+ toss_nade(frag_target, '0 0 100', max(frag_target.nade.wait, time + 0.05));
+
+ float killcount_bonus = ((frag_attacker.killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * frag_attacker.killcount, autocvar_g_nades_bonus_score_medium) : autocvar_g_nades_bonus_score_minor);
+
+ if(IS_PLAYER(frag_attacker))
+ {
+ if (SAME_TEAM(frag_attacker, frag_target) || frag_attacker == frag_target)
+ nades_RemoveBonus(frag_attacker);
+ else if(frag_target.flagcarried)
+ nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_medium);
+ else if(autocvar_g_nades_bonus_score_spree && frag_attacker.killcount > 1)
+ {
+ #define SPREE_ITEM(counta,countb,center,normal,gentle) \
+ case counta: { nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_spree); break; }
+ switch(frag_attacker.killcount)
+ {
+ KILL_SPREE_LIST
+ default: nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor); break;
+ }
+ #undef SPREE_ITEM
+ }
+ else
+ nades_GiveBonus(frag_attacker, killcount_bonus);
+ }
+
+ nades_RemoveBonus(frag_target);
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, PlayerDamage_Calculate)
+{
+ if(frag_target.frozen)
+ if(autocvar_g_freezetag_revive_nade)
+ if(frag_attacker == frag_target)
+ if(frag_deathtype == DEATH_NADE.m_id)
+ if(time - frag_inflictor.toss_time <= 0.1)
+ {
+ Unfreeze(frag_target);
+ frag_target.health = autocvar_g_freezetag_revive_nade_health;
+ Send_Effect(EFFECT_ICEORGLASS, frag_target.origin, '0 0 0', 3);
+ frag_damage = 0;
+ frag_force = '0 0 0';
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_NADE, frag_target.netname);
+ Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF);
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, MonsterDies)
+{SELFPARAM();
+ if(IS_PLAYER(frag_attacker))
+ if(DIFF_TEAM(frag_attacker, self))
+ if(!(self.spawnflags & MONSTERFLAG_SPAWNED))
+ nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor);
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, DropSpecialItems)
+{
+ if(frag_target.nade)
+ toss_nade(frag_target, '0 0 0', time + 0.05);
+
+ return false;
+}
+
+bool nades_RemovePlayer()
+{SELFPARAM();
+ nades_Clear(self);
+ nades_RemoveBonus(self);
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, MakePlayerObserver) { nades_RemovePlayer(); }
+MUTATOR_HOOKFUNCTION(nades, ClientDisconnect) { nades_RemovePlayer(); }
+MUTATOR_HOOKFUNCTION(nades, reset_map_global) { nades_RemovePlayer(); }
+
+MUTATOR_HOOKFUNCTION(nades, SpectateCopy)
+{SELFPARAM();
+ self.nade_timer = other.nade_timer;
+ self.nade_type = other.nade_type;
+ self.pokenade_type = other.pokenade_type;
+ self.bonus_nades = other.bonus_nades;
+ self.bonus_nade_score = other.bonus_nade_score;
+ self.stat_healing_orb = other.stat_healing_orb;
+ self.stat_healing_orb_alpha = other.stat_healing_orb_alpha;
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, GetCvars)
+{
+ GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_nade_type, "cl_nade_type");
+ GetCvars_handleString(get_cvars_s, get_cvars_f, cvar_cl_pokenade_type, "cl_pokenade_type");
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":Nades");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Nades");
+ return false;
+}
+#endif
+#endif
--- /dev/null
+#ifndef NADES_ALL_H
+#define NADES_ALL_H
+
+#include "../../../teams.qh"
+
+// use slots 70-100
+const int PROJECTILE_NADE = 71;
+const int PROJECTILE_NADE_BURN = 72;
+const int PROJECTILE_NADE_NAPALM = 73;
+const int PROJECTILE_NADE_NAPALM_BURN = 74;
+const int PROJECTILE_NAPALM_FOUNTAIN = 75;
+const int PROJECTILE_NADE_ICE = 76;
+const int PROJECTILE_NADE_ICE_BURN = 77;
+const int PROJECTILE_NADE_TRANSLOCATE = 78;
+const int PROJECTILE_NADE_SPAWN = 79;
+const int PROJECTILE_NADE_HEAL = 80;
+const int PROJECTILE_NADE_HEAL_BURN = 81;
+const int PROJECTILE_NADE_MONSTER = 82;
+const int PROJECTILE_NADE_MONSTER_BURN = 83;
+
+REGISTRY(Nades, BITS(4))
+#define Nades_from(i) _Nades_from(i, NADE_TYPE_Null)
+REGISTER_REGISTRY(Nades)
+REGISTRY_CHECK(Nades)
+
+#define REGISTER_NADE(id) REGISTER(Nades, NADE_TYPE, id, m_id, NEW(Nade))
+
+CLASS(Nade, Object)
+ ATTRIB(Nade, m_id, int, 0)
+ ATTRIB(Nade, m_color, vector, '0 0 0')
+ ATTRIB(Nade, m_name, string, _("Grenade"))
+ ATTRIB(Nade, m_icon, string, "nade_normal")
+ ATTRIBARRAY(Nade, m_projectile, int, 2)
+ ATTRIBARRAY(Nade, m_trail, entity, 2)
+ METHOD(Nade, display, void(entity this, void(string name, string icon) returns)) {
+ returns(this.m_name, sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.m_icon));
+ }
+ENDCLASS(Nade)
+
+REGISTER_NADE(Null);
+
+Nade Nade_FromProjectile(int proj)
+{
+ FOREACH(Nades, true, LAMBDA(
+ for (int j = 0; j < 2; j++)
+ {
+ if (it.m_projectile[j] == proj) return it;
+ }
+ ));
+ return NADE_TYPE_Null;
+}
+
+#ifndef MENUQC
+#include "effects.inc"
+#endif
+
+#include "nades.inc"
+
+.float healer_lifetime;
+.float healer_radius;
+
+#ifdef SVQC
+
+.entity nade;
+.entity fake_nade;
+.float nade_timer;
+.float nade_refire;
+.float bonus_nades;
+.float nade_special_time;
+.float bonus_nade_score;
+.float nade_type;
+.string pokenade_type;
+.entity nade_damage_target;
+.float cvar_cl_nade_type;
+.string cvar_cl_pokenade_type;
+.float toss_time;
+.float stat_healing_orb;
+.float stat_healing_orb_alpha;
+.float nade_show_particles;
+
+bool healer_send(entity this, entity to, int sf);
+
+// Remove nades that are being thrown
+void nades_Clear(entity player);
+
+// Give a bonus grenade to a player
+void(entity player, float score) nades_GiveBonus;
+
+/**
+ * called to adjust nade damage and force on hit
+ */
+#define EV_Nade_Damage(i, o) \
+ /** weapon */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** force */ i(vector, MUTATOR_ARGV_0_vector) \
+ /**/ o(vector, MUTATOR_ARGV_0_vector) \
+ /** damage */ i(float, MUTATOR_ARGV_0_float) \
+ /**/ o(float, MUTATOR_ARGV_0_float) \
+ /**/
+MUTATOR_HOOKABLE(Nade_Damage, EV_Nade_Damage);
+
+#endif
+
+#endif
--- /dev/null
+#include "nades.qh"
+
+#ifdef IMPLEMENTATION
+
+#ifdef CSQC
+.float ltime;
+void healer_draw(entity this)
+{
+ float dt = time - self.move_time;
+ self.move_time = time;
+ if(dt <= 0)
+ return;
+
+ self.alpha = (self.ltime - time) / self.healer_lifetime;
+ self.scale = min((1 - self.alpha)*self.healer_lifetime*4,1)*self.healer_radius;
+}
+
+void healer_setup(entity e)
+{
+ setmodel(e, MDL_NADE_HEAL);
+
+ setorigin(e, e.origin);
+
+ float model_radius = e.maxs.x;
+ vector size = '1 1 1' * e.healer_radius / 2;
+ setsize(e,-size,size);
+ e.healer_radius = e.healer_radius/model_radius*0.6;
+
+ e.draw = healer_draw;
+ e.health = 255;
+ e.movetype = MOVETYPE_NONE;
+ e.solid = SOLID_NOT;
+ e.drawmask = MASK_NORMAL;
+ e.scale = 0.01;
+ e.avelocity = e.move_avelocity = '7 0 11';
+ e.colormod = '1 0 0';
+ e.renderflags |= RF_ADDITIVE;
+}
+#endif
+
+REGISTER_NET_LINKED(Nade_Heal)
+
+#ifdef CSQC
+NET_HANDLE(Nade_Heal, bool isNew)
+{
+ Net_Accept(Nade_Heal);
+ int sf = ReadByte();
+ if (sf & 1) {
+ this.origin_x = ReadCoord();
+ this.origin_y = ReadCoord();
+ this.origin_z = ReadCoord();
+ setorigin(this, this.origin);
+ this.healer_lifetime = ReadByte();
+ this.healer_radius = ReadShort();
+ this.ltime = time + ReadByte()/10.0;
+ // this.ltime = time + this.healer_lifetime;
+ healer_setup(this);
+ }
+ return true;
+}
+#endif
+
+#ifdef SVQC
+bool healer_send(entity this, entity to, int sf)
+{
+ int channel = MSG_ENTITY;
+ WriteHeader(channel, Nade_Heal);
+ WriteByte(channel, sf);
+ if (sf & 1) {
+ WriteCoord(channel, this.origin.x);
+ WriteCoord(channel, this.origin.y);
+ WriteCoord(channel, this.origin.z);
+
+ WriteByte(channel, this.healer_lifetime);
+ //WriteByte(MSG_ENTITY, this.ltime - time + 1);
+ WriteShort(channel, this.healer_radius);
+ // round time delta to a 1/10th of a second
+ WriteByte(channel, (this.ltime - time)*10.0+0.5);
+ }
+ return true;
+}
+#endif
+
+#endif
--- /dev/null
+#ifdef SVQC
+#include "new_toys.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+/*
+
+CORE laser vortex lg rl cry gl elec hagar fireb hook
+ vaporizer porto
+ tuba
+
+NEW rifle hlac minel seeker
+IDEAS OPEN flak OPEN FUN FUN FUN FUN
+
+
+
+How this mutator works:
+ =======================
+
+When a gun tries to spawn, this mutator is called. It will provide alternate
+weaponreplace lists.
+
+Entity:
+
+{
+"classname" "weapon_vortex"
+"new_toys" "rifle"
+}
+-> This will spawn as Rifle in this mutator ONLY, and as Vortex otherwise.
+
+{
+"classname" "weapon_vortext"
+"new_toys" "vortex rifle"
+}
+-> This will spawn as either Vortex or Rifle in this mutator ONLY, and as Vortex otherwise.
+
+{
+"classname" "weapon_vortex"
+"new_toys" "vortex"
+}
+-> This is always a Vortex.
+
+If the map specifies no "new_toys" argument
+
+There will be two default replacements selectable: "replace all" and "replace random".
+In "replace all" mode, e.g. Vortex will have the default replacement "rifle".
+In "replace random" mode, Vortex will have the default replacement "vortex rifle".
+
+This mutator's replacements run BEFORE regular weaponreplace!
+
+The New Toys guns do NOT get a spawn function, so they can only ever be spawned
+when this mutator is active.
+
+Likewise, warmup, give all, give ALL and impulse 99 will not give them unless
+this mutator is active.
+
+Outside this mutator, they still can be spawned by:
+- setting their start weapon cvar to 1
+- give weaponname
+- weaponreplace
+- weaponarena (but all and most weapons arena again won't include them)
+
+This mutator performs the default replacements on the DEFAULTS of the
+start weapon selection.
+
+These weapons appear in the menu's priority list, BUT get a suffix
+"(Mutator weapon)".
+
+Picking up a "new toys" weapon will not play standard weapon pickup sound, but
+roflsound "New toys, new toys!" sound.
+
+*/
+
+bool nt_IsNewToy(int w);
+
+REGISTER_MUTATOR(nt, cvar("g_new_toys") && !cvar("g_instagib") && !cvar("g_overkill"))
+{
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This cannot be added at runtime\n");
+
+ // mark the guns as ok to use by e.g. impulse 99
+ for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
+ if(nt_IsNewToy(i))
+ get_weaponinfo(i).spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
+ if(nt_IsNewToy(i))
+ get_weaponinfo(i).spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ LOG_INFO("This cannot be removed at runtime\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+.string new_toys;
+
+float autocvar_g_new_toys_autoreplace;
+bool autocvar_g_new_toys_use_pickupsound = true;
+const float NT_AUTOREPLACE_NEVER = 0;
+const float NT_AUTOREPLACE_ALWAYS = 1;
+const float NT_AUTOREPLACE_RANDOM = 2;
+
+MUTATOR_HOOKFUNCTION(nt, SetModname)
+{
+ modname = "NewToys";
+ return 0;
+}
+
+bool nt_IsNewToy(int w)
+{
+ switch(w)
+ {
+ case WEP_SEEKER.m_id:
+ case WEP_MINE_LAYER.m_id:
+ case WEP_HLAC.m_id:
+ case WEP_RIFLE.m_id:
+ case WEP_SHOCKWAVE.m_id:
+ return true;
+ default:
+ return false;
+ }
+}
+
+string nt_GetFullReplacement(string w)
+{
+ switch(w)
+ {
+ case "hagar": return "seeker";
+ case "devastator": return "minelayer";
+ case "machinegun": return "hlac";
+ case "vortex": return "rifle";
+ //case "shotgun": return "shockwave";
+ default: return string_null;
+ }
+}
+
+string nt_GetReplacement(string w, float m)
+{
+ if(m == NT_AUTOREPLACE_NEVER)
+ return w;
+ string s = nt_GetFullReplacement(w);
+ if (!s)
+ return w;
+ if(m == NT_AUTOREPLACE_RANDOM)
+ s = strcat(w, " ", s);
+ return s;
+}
+
+MUTATOR_HOOKFUNCTION(nt, SetStartItems)
+{
+ // rearrange start_weapon_default
+ // apply those bits that are set by start_weapon_defaultmask
+ // same for warmup
+
+ float i, j, k, n;
+
+ WepSet newdefault;
+ WepSet warmup_newdefault;
+
+ newdefault = '0 0 0';
+ warmup_newdefault = '0 0 0';
+
+ for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+ {
+ entity e = get_weaponinfo(i);
+ if(!e.weapon)
+ continue;
+
+ n = tokenize_console(nt_GetReplacement(e.netname, autocvar_g_new_toys_autoreplace));
+
+ for(j = 0; j < n; ++j)
+ for(k = WEP_FIRST; k <= WEP_LAST; ++k)
+ if(get_weaponinfo(k).netname == argv(j))
+ {
+ if(start_weapons & WepSet_FromWeapon(i))
+ newdefault |= WepSet_FromWeapon(k);
+ if(warmup_start_weapons & WepSet_FromWeapon(i))
+ warmup_newdefault |= WepSet_FromWeapon(k);
+ }
+ }
+
+ newdefault &= start_weapons_defaultmask;
+ start_weapons &= ~start_weapons_defaultmask;
+ start_weapons |= newdefault;
+
+ warmup_newdefault &= warmup_start_weapons_defaultmask;
+ warmup_start_weapons &= ~warmup_start_weapons_defaultmask;
+ warmup_start_weapons |= warmup_newdefault;
+
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nt, SetWeaponreplace)
+{SELFPARAM();
+ // otherwise, we do replace
+ if(self.new_toys)
+ {
+ // map defined replacement:
+ ret_string = self.new_toys;
+ }
+ else
+ {
+ // auto replacement:
+ ret_string = nt_GetReplacement(other.netname, autocvar_g_new_toys_autoreplace);
+ }
+
+ // apply regular weaponreplace
+ ret_string = W_Apply_Weaponreplace(ret_string);
+
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nt, FilterItem)
+{SELFPARAM();
+ if(nt_IsNewToy(self.weapon) && autocvar_g_new_toys_use_pickupsound) {
+ self.item_pickupsound = string_null;
+ self.item_pickupsound_ent = SND_WEAPONPICKUP_NEW_TOYS;
+ }
+ return 0;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "nix.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+int autocvar_g_balance_nix_ammo_cells;
+int autocvar_g_balance_nix_ammo_plasma;
+int autocvar_g_balance_nix_ammo_fuel;
+int autocvar_g_balance_nix_ammo_nails;
+int autocvar_g_balance_nix_ammo_rockets;
+int autocvar_g_balance_nix_ammo_shells;
+int autocvar_g_balance_nix_ammoincr_cells;
+int autocvar_g_balance_nix_ammoincr_plasma;
+int autocvar_g_balance_nix_ammoincr_fuel;
+int autocvar_g_balance_nix_ammoincr_nails;
+int autocvar_g_balance_nix_ammoincr_rockets;
+int autocvar_g_balance_nix_ammoincr_shells;
+float autocvar_g_balance_nix_incrtime;
+float autocvar_g_balance_nix_roundtime;
+bool autocvar_g_nix_with_healtharmor;
+bool autocvar_g_nix_with_blaster;
+bool autocvar_g_nix_with_powerups;
+int autocvar_g_pickup_cells_max;
+int autocvar_g_pickup_plasma_max;
+int autocvar_g_pickup_fuel_max;
+int autocvar_g_pickup_nails_max;
+int autocvar_g_pickup_rockets_max;
+int autocvar_g_pickup_shells_max;
+
+float g_nix_with_blaster;
+// WEAPONTODO
+int nix_weapon;
+float nix_nextchange;
+float nix_nextweapon;
+.float nix_lastchange_id;
+.float nix_lastinfotime;
+.float nix_nextincr;
+
+bool NIX_CanChooseWeapon(int wpn);
+
+REGISTER_MUTATOR(nix, cvar("g_nix") && !cvar("g_instagib") && !cvar("g_overkill"))
+{
+ MUTATOR_ONADD
+ {
+ g_nix_with_blaster = autocvar_g_nix_with_blaster;
+
+ nix_nextchange = 0;
+ nix_nextweapon = 0;
+
+ for (int i = WEP_FIRST; i <= WEP_LAST; ++i)
+ if (NIX_CanChooseWeapon(i)) {
+ Weapon w = get_weaponinfo(i);
+ w.wr_init(w);
+ }
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // nothing to roll back
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
+ entity e;
+ FOR_EACH_PLAYER(e) if(e.deadflag == DEAD_NO)
+ {
+ e.ammo_cells = start_ammo_cells;
+ e.ammo_plasma = start_ammo_plasma;
+ e.ammo_shells = start_ammo_shells;
+ e.ammo_nails = start_ammo_nails;
+ e.ammo_rockets = start_ammo_rockets;
+ e.ammo_fuel = start_ammo_fuel;
+ e.weapons = start_weapons;
+ if(!client_hasweapon(e, e.weapon, true, false))
+ e.switchweapon = w_getbestweapon(self);
+ }
+ }
+
+ return 0;
+}
+
+bool NIX_CanChooseWeapon(int wpn)
+{
+ entity e = get_weaponinfo(wpn);
+ if(!e.weapon) // skip dummies
+ return false;
+ if(g_weaponarena)
+ {
+ if(!(g_weaponarena_weapons & WepSet_FromWeapon(wpn)))
+ return false;
+ }
+ else
+ {
+ if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
+ return false;
+ if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
+ return false;
+ if (!(e.spawnflags & WEP_FLAG_NORMAL))
+ return false;
+ }
+ return true;
+}
+void NIX_ChooseNextWeapon()
+{
+ float j;
+ RandomSelection_Init();
+ for(j = WEP_FIRST; j <= WEP_LAST; ++j)
+ if(NIX_CanChooseWeapon(j))
+ RandomSelection_Add(world, j, string_null, 1, (j != nix_weapon));
+ nix_nextweapon = RandomSelection_chosen_float;
+}
+
+void NIX_GiveCurrentWeapon()
+{SELFPARAM();
+ float dt;
+
+ if(!nix_nextweapon)
+ NIX_ChooseNextWeapon();
+
+ dt = ceil(nix_nextchange - time);
+
+ if(dt <= 0)
+ {
+ nix_weapon = nix_nextweapon;
+ nix_nextweapon = 0;
+ if (!nix_nextchange) // no round played yet?
+ nix_nextchange = time; // start the first round now!
+ else
+ nix_nextchange = time + autocvar_g_balance_nix_roundtime;
+ // Weapon w = get_weaponinfo(nix_weapon);
+ // w.wr_init(w); // forget it, too slow
+ }
+
+ // get weapon info
+ entity e = get_weaponinfo(nix_weapon);
+
+ if(nix_nextchange != self.nix_lastchange_id) // this shall only be called once per round!
+ {
+ self.ammo_shells = self.ammo_nails = self.ammo_rockets = self.ammo_cells = self.ammo_plasma = self.ammo_fuel = 0;
+
+ if(self.items & IT_UNLIMITED_WEAPON_AMMO)
+ {
+ switch(e.ammo_field)
+ {
+ case ammo_shells: self.ammo_shells = autocvar_g_pickup_shells_max; break;
+ case ammo_nails: self.ammo_nails = autocvar_g_pickup_nails_max; break;
+ case ammo_rockets: self.ammo_rockets = autocvar_g_pickup_rockets_max; break;
+ case ammo_cells: self.ammo_cells = autocvar_g_pickup_cells_max; break;
+ case ammo_plasma: self.ammo_plasma = autocvar_g_pickup_plasma_max; break;
+ case ammo_fuel: self.ammo_fuel = autocvar_g_pickup_fuel_max; break;
+ }
+ }
+ else
+ {
+ switch(e.ammo_field)
+ {
+ case ammo_shells: self.ammo_shells = autocvar_g_balance_nix_ammo_shells; break;
+ case ammo_nails: self.ammo_nails = autocvar_g_balance_nix_ammo_nails; break;
+ case ammo_rockets: self.ammo_rockets = autocvar_g_balance_nix_ammo_rockets; break;
+ case ammo_cells: self.ammo_cells = autocvar_g_balance_nix_ammo_cells; break;
+ case ammo_plasma: self.ammo_plasma = autocvar_g_balance_nix_ammo_plasma; break;
+ case ammo_fuel: self.ammo_fuel = autocvar_g_balance_nix_ammo_fuel; break;
+ }
+ }
+
+ self.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
+ if(dt >= 1 && dt <= 5)
+ self.nix_lastinfotime = -42;
+ else
+ Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
+
+ Weapon w = get_weaponinfo(nix_weapon);
+ w.wr_resetplayer(w);
+
+ // all weapons must be fully loaded when we spawn
+ if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
+ self.(weapon_load[nix_weapon]) = e.reloading_ammo;
+
+ // vortex too
+ if(WEP_CVAR(vortex, charge))
+ {
+ if(WEP_CVAR_SEC(vortex, chargepool))
+ self.vortex_chargepool_ammo = 1;
+ self.vortex_charge = WEP_CVAR(vortex, charge_start);
+ }
+
+ // set last change info
+ self.nix_lastchange_id = nix_nextchange;
+ }
+ if(self.nix_lastinfotime != dt)
+ {
+ self.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
+ if(dt >= 1 && dt <= 5)
+ Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
+ }
+
+ if(!(self.items & IT_UNLIMITED_WEAPON_AMMO) && time > self.nix_nextincr)
+ {
+ switch(e.ammo_field)
+ {
+ case ammo_shells: self.ammo_shells += autocvar_g_balance_nix_ammoincr_shells; break;
+ case ammo_nails: self.ammo_nails += autocvar_g_balance_nix_ammoincr_nails; break;
+ case ammo_rockets: self.ammo_rockets += autocvar_g_balance_nix_ammoincr_rockets; break;
+ case ammo_cells: self.ammo_cells += autocvar_g_balance_nix_ammoincr_cells; break;
+ case ammo_plasma: self.ammo_plasma += autocvar_g_balance_nix_ammoincr_plasma; break;
+ case ammo_fuel: self.ammo_fuel += autocvar_g_balance_nix_ammoincr_fuel; break;
+ }
+
+ self.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
+ }
+
+ self.weapons = '0 0 0';
+ if(g_nix_with_blaster)
+ self.weapons |= WEPSET(BLASTER);
+ self.weapons |= WepSet_FromWeapon(nix_weapon);
+
+ if(self.switchweapon != nix_weapon)
+ if(!client_hasweapon(self, self.switchweapon, true, false))
+ if(client_hasweapon(self, nix_weapon, true, false))
+ W_SwitchWeapon(nix_weapon);
+}
+
+MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
+{
+ return 1; // no throwing in NIX
+}
+
+MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":NIX");
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", NIX");
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nix, FilterItem)
+{SELFPARAM();
+ switch (self.items)
+ {
+ case ITEM_HealthSmall.m_itemid:
+ case ITEM_HealthMedium.m_itemid:
+ case ITEM_HealthLarge.m_itemid:
+ case ITEM_HealthMega.m_itemid:
+ case ITEM_ArmorSmall.m_itemid:
+ case ITEM_ArmorMedium.m_itemid:
+ case ITEM_ArmorLarge.m_itemid:
+ case ITEM_ArmorMega.m_itemid:
+ if (autocvar_g_nix_with_healtharmor)
+ return 0;
+ break;
+ case ITEM_Strength.m_itemid:
+ case ITEM_Shield.m_itemid:
+ if (autocvar_g_nix_with_powerups)
+ return 0;
+ break;
+ }
+
+ return 1; // delete all other items
+}
+
+MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
+{SELFPARAM();
+ if(self.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
+ return 1;
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
+{SELFPARAM();
+ if(!intermission_running)
+ if(self.deadflag == DEAD_NO)
+ if(IS_PLAYER(self))
+ NIX_GiveCurrentWeapon();
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
+{SELFPARAM();
+ self.nix_lastchange_id = -1;
+ NIX_GiveCurrentWeapon(); // overrides the weapons you got when spawning
+ self.items |= IT_UNLIMITED_SUPERWEAPONS;
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
+{
+ modname = "NIX";
+ return 0;
+}
+#endif
--- /dev/null
+#ifndef IMPLEMENTATION
+CLASS(HeavyMachineGun, Weapon)
+/* ammotype */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails)
+/* impulse */ ATTRIB(HeavyMachineGun, impulse, int, 3)
+/* flags */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
+/* rating */ ATTRIB(HeavyMachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
+/* color */ ATTRIB(HeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
+/* modelname */ ATTRIB(HeavyMachineGun, mdl, string, "ok_hmg");
+#ifndef MENUQC
+/* model */ ATTRIB(HeavyMachineGun, m_model, Model, MDL_HMG_ITEM);
+#endif
+/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair, string, "gfx/crosshairuzi");
+/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair_size, float, 0.6);
+/* wepimg */ ATTRIB(HeavyMachineGun, model2, string, "weaponhmg");
+/* refname */ ATTRIB(HeavyMachineGun, netname, string, "hmg");
+/* wepname */ ATTRIB(HeavyMachineGun, m_name, string, _("Heavy Machine Gun"));
+ENDCLASS(HeavyMachineGun)
+REGISTER_WEAPON(HMG, NEW(HeavyMachineGun));
+
+#define HMG_SETTINGS(w_cvar,w_prop) HMG_SETTINGS_LIST(w_cvar, w_prop, HMG, hmg)
+#define HMG_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
+ w_cvar(id, sn, NONE, spread_min) \
+ w_cvar(id, sn, NONE, spread_max) \
+ w_cvar(id, sn, NONE, spread_add) \
+ w_cvar(id, sn, NONE, solidpenetration) \
+ w_cvar(id, sn, NONE, damage) \
+ w_cvar(id, sn, NONE, force) \
+ w_cvar(id, sn, NONE, refire) \
+ w_cvar(id, sn, NONE, ammo) \
+ w_prop(id, sn, float, reloading_ammo, reload_ammo) \
+ w_prop(id, sn, float, reloading_time, reload_time) \
+ w_prop(id, sn, float, switchdelay_raise, switchdelay_raise) \
+ w_prop(id, sn, float, switchdelay_drop, switchdelay_drop) \
+ w_prop(id, sn, string, weaponreplace, weaponreplace) \
+ w_prop(id, sn, float, weaponstart, weaponstart) \
+ w_prop(id, sn, float, weaponstartoverride, weaponstartoverride) \
+ w_prop(id, sn, float, weaponthrowable, weaponthrowable)
+
+#ifdef SVQC
+HMG_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
+#endif
+#endif
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+
+REGISTER_MUTATOR(hmg_nadesupport, true);
+MUTATOR_HOOKFUNCTION(hmg_nadesupport, Nade_Damage)
+{
+ if (MUTATOR_ARGV(0, entity) != WEP_HMG) return;
+ return = true;
+ MUTATOR_ARGV(0, float) /* damage */ = self.max_health * 0.1;
+}
+
+spawnfunc(weapon_hmg) { weapon_defaultspawnfunc(this, WEP_HMG); }
+
+void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
+{
+ if (!actor.BUTTON_ATCK)
+ {
+ w_ready(thiswep, actor, weaponentity, fire);
+ return;
+ }
+
+ Weapon w = get_weaponinfo(actor.weapon);
+ if(!w.wr_checkammo1(w))
+ if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+ {
+ W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
+ w_ready(thiswep, actor, weaponentity, fire);
+ return;
+ }
+
+ W_DecreaseAmmo(WEP_HMG, self, WEP_CVAR(hmg, ammo));
+
+ W_SetupShot (actor, true, 0, SND(UZI_FIRE), CH_WEAPON_A, WEP_CVAR(hmg, damage));
+
+ if(!autocvar_g_norecoil)
+ {
+ actor.punchangle_x = random () - 0.5;
+ actor.punchangle_y = random () - 0.5;
+ }
+
+ float hmg_spread = bound(WEP_CVAR(hmg, spread_min), WEP_CVAR(hmg, spread_min) + (WEP_CVAR(hmg, spread_add) * actor.misc_bulletcounter), WEP_CVAR(hmg, spread_max));
+ fireBullet(w_shotorg, w_shotdir, hmg_spread, WEP_CVAR(hmg, solidpenetration), WEP_CVAR(hmg, damage), WEP_CVAR(hmg, force), WEP_HMG.m_id, 0);
+
+ actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
+
+ Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+
+ W_MachineGun_MuzzleFlash();
+ W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
+
+ if (autocvar_g_casings >= 2) // casing code
+ SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+
+ int slot = weaponslot(weaponentity);
+ ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(hmg, refire) * W_WeaponRateFactor();
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(hmg, refire), W_HeavyMachineGun_Attack_Auto);
+}
+
+ METHOD(HeavyMachineGun, wr_aim, void(entity thiswep))
+ {
+ if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200)
+ self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, false);
+ else
+ self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, false);
+ }
+ METHOD(HeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+ {
+ if(WEP_CVAR(hmg, reload_ammo) && actor.clip_load < WEP_CVAR(hmg, ammo)) { // forced reload
+ Weapon w = get_weaponinfo(actor.weapon);
+ w.wr_reload(w);
+ } else
+ {
+ if (fire & 1)
+ if (weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
+ {
+ actor.misc_bulletcounter = 0;
+ W_HeavyMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
+ }
+ }
+ }
+ METHOD(HeavyMachineGun, wr_init, void(entity thiswep))
+ {
+ HMG_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
+ }
+ METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep))
+ {
+ float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
+
+ if(autocvar_g_balance_hmg_reload_ammo)
+ ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
+
+ return ammo_amount;
+ }
+ METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep))
+ {
+ float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
+
+ if(autocvar_g_balance_hmg_reload_ammo)
+ ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
+
+ return ammo_amount;
+ }
+ METHOD(HeavyMachineGun, wr_config, void(entity thiswep))
+ {
+ HMG_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
+ }
+ METHOD(HeavyMachineGun, wr_reload, void(entity thiswep))
+ {
+ W_Reload(self, WEP_CVAR(hmg, ammo), SND(RELOAD));
+ }
+ METHOD(HeavyMachineGun, wr_suicidemessage, int(entity thiswep))
+ {
+ return WEAPON_THINKING_WITH_PORTALS;
+ }
+ METHOD(HeavyMachineGun, wr_killmessage, int(entity thiswep))
+ {
+ if(w_deathtype & HITTYPE_SECONDARY)
+ return WEAPON_HMG_MURDER_SNIPE;
+ else
+ return WEAPON_HMG_MURDER_SPRAY;
+ }
+
+#endif
+#ifdef CSQC
+
+ METHOD(HeavyMachineGun, wr_impacteffect, void(entity thiswep))
+ {
+ vector org2;
+ org2 = w_org + w_backoff * 2;
+ pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
+ if(!w_issilent)
+ sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+ }
+
+#endif
+#endif
--- /dev/null
+#include "hmg.qc"
+#include "rpc.qc"
+
+#ifdef SVQC
+ #include "overkill.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+bool autocvar_g_overkill_powerups_replace;
+float autocvar_g_overkill_superguns_respawn_time;
+bool autocvar_g_overkill_100h_anyway;
+bool autocvar_g_overkill_100a_anyway;
+bool autocvar_g_overkill_ammo_charge;
+float autocvar_g_overkill_ammo_charge_notice;
+float autocvar_g_overkill_ammo_charge_limit;
+
+.vector ok_deathloc;
+.float ok_spawnsys_timer;
+.float ok_lastwep;
+.float ok_item;
+
+.float ok_notice_time;
+.float ammo_charge[Weapons_MAX];
+.float ok_use_ammocharge;
+.float ok_ammo_charge;
+
+.float ok_pauseregen_finished;
+
+void(entity ent, float wep) ok_DecreaseCharge;
+
+void ok_Initialize();
+
+REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
+{
+ MUTATOR_ONADD
+ {
+ ok_Initialize();
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+ WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, W_DecreaseAmmo)
+{
+ entity actor = MUTATOR_ARGV(0, entity);
+ if (actor.ok_use_ammocharge)
+ {
+ ok_DecreaseCharge(actor, actor.weapon);
+ return true;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ok, W_Reload)
+{
+ entity actor = MUTATOR_ARGV(0, entity);
+ return actor.ok_use_ammocharge;
+}
+
+void W_Blaster_Attack(entity, float, float, float, float, float, float, float, float, float, float);
+spawnfunc(weapon_hmg);
+spawnfunc(weapon_rpc);
+
+void ok_DecreaseCharge(entity ent, int wep)
+{
+ if(!ent.ok_use_ammocharge) return;
+
+ entity wepent = get_weaponinfo(wep);
+
+ if(wepent.weapon == 0)
+ return; // dummy
+
+ ent.ammo_charge[wep] -= max(0, cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
+}
+
+void ok_IncreaseCharge(entity ent, int wep)
+{
+ entity wepent = get_weaponinfo(wep);
+
+ if(wepent.weapon == 0)
+ return; // dummy
+
+ if(ent.ok_use_ammocharge)
+ if(!ent.BUTTON_ATCK) // not while attacking?
+ ent.ammo_charge[wep] = min(autocvar_g_overkill_ammo_charge_limit, ent.ammo_charge[wep] + cvar(sprintf("g_overkill_ammo_charge_rate_%s", wepent.netname)) * frametime / W_TICSPERFRAME);
+}
+
+float ok_CheckWeaponCharge(entity ent, int wep)
+{
+ if(!ent.ok_use_ammocharge) return true;
+
+ entity wepent = get_weaponinfo(wep);
+
+ if(wepent.weapon == 0)
+ return 0; // dummy
+
+ return (ent.ammo_charge[wep] >= cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDamage_Calculate, CBC_ORDER_LAST)
+{
+ if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target))
+ if(DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
+ {
+ frag_damage = 0;
+
+ if(frag_attacker != frag_target)
+ if(frag_target.health > 0)
+ if(frag_target.frozen == 0)
+ if(frag_target.deadflag == DEAD_NO)
+ {
+ Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE);
+ frag_force = '0 0 0';
+ }
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDamage_SplitHealthArmor)
+{SELFPARAM();
+ if(damage_take)
+ self.ok_pauseregen_finished = max(self.ok_pauseregen_finished, time + 2);
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDies)
+{SELFPARAM();
+ entity targ = ((frag_attacker) ? frag_attacker : frag_target);
+
+ if(IS_MONSTER(self))
+ {
+ remove(other); // remove default item
+ other = world;
+ }
+
+ setself(new(droppedweapon)); // hax
+ self.ok_item = true;
+ self.noalign = true;
+ self.pickup_anyway = true;
+ spawnfunc_item_armor_small(this);
+ self.movetype = MOVETYPE_TOSS;
+ self.gravity = 1;
+ self.reset = SUB_Remove;
+ setorigin(self, frag_target.origin + '0 0 32');
+ self.velocity = '0 0 200' + normalize(targ.origin - self.origin) * 500;
+ SUB_SetFade(self, time + 5, 1);
+ setself(this);
+
+ self.ok_lastwep = self.switchweapon;
+
+ return false;
+}
+MUTATOR_HOOKFUNCTION(ok, MonsterDropItem) { ok_PlayerDies(); }
+
+MUTATOR_HOOKFUNCTION(ok, PlayerRegen)
+{SELFPARAM();
+ // overkill's values are different, so use custom regen
+ if(!self.frozen)
+ {
+ self.armorvalue = CalcRotRegen(self.armorvalue, autocvar_g_balance_armor_regenstable, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, 1 * frametime * (time > self.ok_pauseregen_finished), 0, 0, 1, 1 * frametime * (time > self.pauserotarmor_finished), autocvar_g_balance_armor_limit);
+ self.health = CalcRotRegen(self.health, autocvar_g_balance_health_regenstable, 0, 100, 1 * frametime * (time > self.ok_pauseregen_finished), 200, 0, autocvar_g_balance_health_rotlinear, 1 * frametime * (time > self.pauserothealth_finished), autocvar_g_balance_health_limit);
+
+ float minf, maxf, limitf;
+
+ maxf = autocvar_g_balance_fuel_rotstable;
+ minf = autocvar_g_balance_fuel_regenstable;
+ limitf = autocvar_g_balance_fuel_limit;
+
+ self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > self.pauseregen_finished) * ((self.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > self.pauserotfuel_finished), limitf);
+ }
+ return true; // return true anyway, as frozen uses no regen
+}
+
+MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
+{
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
+{SELFPARAM();
+ if(intermission_running || gameover)
+ return false;
+
+ if(self.deadflag != DEAD_NO || !IS_PLAYER(self) || self.frozen)
+ return false;
+
+ if(self.ok_lastwep)
+ {
+ self.switchweapon = self.ok_lastwep;
+ self.ok_lastwep = 0;
+ }
+
+ ok_IncreaseCharge(self, self.weapon);
+
+ if(self.BUTTON_ATCK2)
+ if(!forbidWeaponUse(self) || self.weapon_blocked) // allow if weapon is blocked
+ if(time >= self.jump_interval)
+ {
+ self.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor();
+ makevectors(self.v_angle);
+
+ int oldwep = self.weapon;
+ self.weapon = WEP_BLASTER.m_id;
+ W_Blaster_Attack(
+ self,
+ WEP_BLASTER.m_id | HITTYPE_SECONDARY,
+ WEP_CVAR_SEC(vaporizer, shotangle),
+ WEP_CVAR_SEC(vaporizer, damage),
+ WEP_CVAR_SEC(vaporizer, edgedamage),
+ WEP_CVAR_SEC(vaporizer, radius),
+ WEP_CVAR_SEC(vaporizer, force),
+ WEP_CVAR_SEC(vaporizer, speed),
+ WEP_CVAR_SEC(vaporizer, spread),
+ WEP_CVAR_SEC(vaporizer, delay),
+ WEP_CVAR_SEC(vaporizer, lifetime)
+ );
+ self.weapon = oldwep;
+ }
+
+ self.weapon_blocked = false;
+
+ self.ok_ammo_charge = self.ammo_charge[self.weapon];
+
+ if(self.ok_use_ammocharge)
+ if(!ok_CheckWeaponCharge(self, self.weapon))
+ {
+ if(autocvar_g_overkill_ammo_charge_notice && time > self.ok_notice_time && self.BUTTON_ATCK && IS_REAL_CLIENT(self) && self.weapon == self.switchweapon)
+ {
+ //Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_OVERKILL_CHARGE);
+ self.ok_notice_time = time + 2;
+ play2(self, SND(DRYFIRE));
+ }
+ Weapon wpn = get_weaponinfo(self.weapon);
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+ if(self.(weaponentity).state != WS_CLEAR)
+ w_ready(wpn, self, weaponentity, (self.BUTTON_ATCK ? 1 : 0) | (self.BUTTON_ATCK2 ? 2 : 0));
+
+ self.weapon_blocked = true;
+ }
+
+ self.BUTTON_ATCK2 = 0;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerSpawn)
+{SELFPARAM();
+ if(autocvar_g_overkill_ammo_charge)
+ {
+ for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
+ self.ammo_charge[i] = autocvar_g_overkill_ammo_charge_limit;
+
+ self.ok_use_ammocharge = 1;
+ self.ok_notice_time = time;
+ }
+ else
+ self.ok_use_ammocharge = 0;
+
+ self.ok_pauseregen_finished = time + 2;
+
+ return false;
+}
+
+void _spawnfunc_weapon_hmg() { SELFPARAM(); spawnfunc_weapon_hmg(this); }
+void _spawnfunc_weapon_rpc() { SELFPARAM(); spawnfunc_weapon_rpc(this); }
+
+MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
+{SELFPARAM();
+ if(autocvar_g_powerups)
+ if(autocvar_g_overkill_powerups_replace)
+ {
+ if(self.classname == "item_strength")
+ {
+ entity wep = new(weapon_hmg);
+ setorigin(wep, self.origin);
+ setmodel(wep, MDL_OK_HMG);
+ wep.ok_item = true;
+ wep.noalign = self.noalign;
+ wep.cnt = self.cnt;
+ wep.team = self.team;
+ wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
+ wep.pickup_anyway = true;
+ wep.think = _spawnfunc_weapon_hmg;
+ wep.nextthink = time + 0.1;
+ return true;
+ }
+
+ if(self.classname == "item_invincible")
+ {
+ entity wep = new(weapon_rpc);
+ setorigin(wep, self.origin);
+ setmodel(wep, MDL_OK_RPC);
+ wep.ok_item = true;
+ wep.noalign = self.noalign;
+ wep.cnt = self.cnt;
+ wep.team = self.team;
+ wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
+ wep.pickup_anyway = true;
+ wep.think = _spawnfunc_weapon_rpc;
+ wep.nextthink = time + 0.1;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, FilterItem)
+{SELFPARAM();
+ if(self.ok_item)
+ return false;
+
+ switch(self.items)
+ {
+ case ITEM_HealthMega.m_itemid: return !(autocvar_g_overkill_100h_anyway);
+ case ITEM_ArmorMega.m_itemid: return !(autocvar_g_overkill_100a_anyway);
+ }
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SpectateCopy)
+{SELFPARAM();
+ self.ammo_charge[self.weapon] = other.ammo_charge[other.weapon];
+ self.ok_use_ammocharge = other.ok_use_ammocharge;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SetStartItems)
+{
+ WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
+
+ if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
+ if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
+
+ start_items |= IT_UNLIMITED_WEAPON_AMMO;
+ start_weapons = warmup_start_weapons = ok_start_items;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":OK");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Overkill");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SetModname)
+{
+ modname = "Overkill";
+ return true;
+}
+
+void ok_SetCvars()
+{
+ // hack to force overkill playermodels
+ cvar_settemp("sv_defaultcharacter", "1");
+ cvar_settemp("sv_defaultplayermodel", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
+ cvar_settemp("sv_defaultplayermodel_red", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm");
+ cvar_settemp("sv_defaultplayermodel_blue", "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
+}
+
+void ok_Initialize()
+{
+ ok_SetCvars();
+
+ precache_all_playermodels("models/ok_player/*.dpm");
+
+ addstat(STAT_OK_AMMO_CHARGE, AS_FLOAT, ok_use_ammocharge);
+ addstat(STAT_OK_AMMO_CHARGEPOOL, AS_FLOAT, ok_ammo_charge);
+
+ WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+ WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+
+ WEP_SHOTGUN.mdl = "ok_shotgun";
+ WEP_MACHINEGUN.mdl = "ok_mg";
+ WEP_VORTEX.mdl = "ok_sniper";
+}
+#endif
--- /dev/null
+#ifndef IMPLEMENTATION
+CLASS(RocketPropelledChainsaw, Weapon)
+/* ammotype */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets)
+/* impulse */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7)
+/* flags */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
+/* rating */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
+/* color */ ATTRIB(RocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
+/* modelname */ ATTRIB(RocketPropelledChainsaw, mdl, string, "ok_rl");
+#ifndef MENUQC
+/* model */ ATTRIB(RocketPropelledChainsaw, m_model, Model, MDL_RPC_ITEM);
+#endif
+/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair, string, "gfx/crosshairrocketlauncher");
+/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair_size, float, 0.6);
+/* wepimg */ ATTRIB(RocketPropelledChainsaw, model2, string, "weaponrpc");
+/* refname */ ATTRIB(RocketPropelledChainsaw, netname, string, "rpc");
+/* wepname */ ATTRIB(RocketPropelledChainsaw, m_name, string, _("Rocket Propelled Chainsaw"));
+ENDCLASS(RocketPropelledChainsaw)
+REGISTER_WEAPON(RPC, NEW(RocketPropelledChainsaw));
+
+#define RPC_SETTINGS(w_cvar,w_prop) RPC_SETTINGS_LIST(w_cvar, w_prop, RPC, rpc)
+#define RPC_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
+ w_cvar(id, sn, NONE, ammo) \
+ w_cvar(id, sn, NONE, animtime) \
+ w_cvar(id, sn, NONE, damage) \
+ w_cvar(id, sn, NONE, damage2) \
+ w_cvar(id, sn, NONE, damageforcescale) \
+ w_cvar(id, sn, NONE, edgedamage) \
+ w_cvar(id, sn, NONE, force) \
+ w_cvar(id, sn, NONE, health) \
+ w_cvar(id, sn, NONE, lifetime) \
+ w_cvar(id, sn, NONE, radius) \
+ w_cvar(id, sn, NONE, refire) \
+ w_cvar(id, sn, NONE, speed) \
+ w_cvar(id, sn, NONE, speedaccel) \
+ w_prop(id, sn, float, reloading_ammo, reload_ammo) \
+ w_prop(id, sn, float, reloading_time, reload_time) \
+ w_prop(id, sn, float, switchdelay_raise, switchdelay_raise) \
+ w_prop(id, sn, float, switchdelay_drop, switchdelay_drop) \
+ w_prop(id, sn, string, weaponreplace, weaponreplace) \
+ w_prop(id, sn, float, weaponstart, weaponstart) \
+ w_prop(id, sn, float, weaponstartoverride, weaponstartoverride) \
+ w_prop(id, sn, float, weaponthrowable, weaponthrowable)
+
+#ifdef SVQC
+RPC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
+#endif
+#endif
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+spawnfunc(weapon_rpc) { weapon_defaultspawnfunc(this, WEP_RPC); }
+
+void W_RocketPropelledChainsaw_Explode()
+{SELFPARAM();
+ self.event_damage = func_null;
+ self.takedamage = DAMAGE_NO;
+
+ RadiusDamage (self, self.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), world, world, WEP_CVAR(rpc, force), self.projectiledeathtype, other);
+
+ remove (self);
+}
+
+void W_RocketPropelledChainsaw_Touch ()
+{SELFPARAM();
+ if(WarpZone_Projectile_Touch())
+ if(wasfreed(self))
+ return;
+
+ W_RocketPropelledChainsaw_Explode();
+}
+
+void W_RocketPropelledChainsaw_Damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+ if (self.health <= 0)
+ return;
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
+ return; // g_projectiles_damage says to halt
+
+ self.health = self.health - damage;
+
+ if (self.health <= 0)
+ W_PrepareExplosionByDamage(attacker, W_RocketPropelledChainsaw_Explode);
+}
+
+void W_RocketPropelledChainsaw_Think()
+{SELFPARAM();
+ if(self.cnt <= time)
+ {
+ remove(self);
+ return;
+ }
+
+ self.cnt = vlen(self.velocity);
+ self.wait = self.cnt * sys_frametime;
+ self.pos1 = normalize(self.velocity);
+
+ tracebox(self.origin, self.mins, self.maxs, self.origin + self.pos1 * (2 * self.wait), MOVE_NORMAL, self);
+ if(IS_PLAYER(trace_ent))
+ Damage (trace_ent, self, self.realowner, WEP_CVAR(rpc, damage2), self.projectiledeathtype, self.origin, normalize(self.origin - other.origin) * WEP_CVAR(rpc, force));
+
+ self.velocity = self.pos1 * (self.cnt + (WEP_CVAR(rpc, speedaccel) * sys_frametime));
+
+ UpdateCSQCProjectile(self);
+ self.nextthink = time;
+}
+
+void W_RocketPropelledChainsaw_Attack (Weapon thiswep)
+{SELFPARAM();
+ entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(self);
+ entity flash = spawn ();
+
+ W_DecreaseAmmo(thiswep, self, WEP_CVAR(rpc, ammo));
+ W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', false, 5, SND(ROCKET_FIRE), CH_WEAPON_A, WEP_CVAR(rpc, damage));
+ Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+ PROJECTILE_MAKETRIGGER(missile);
+
+ missile.owner = missile.realowner = self;
+ missile.bot_dodge = true;
+ missile.bot_dodgerating = WEP_CVAR(rpc, damage) * 2;
+
+ missile.takedamage = DAMAGE_YES;
+ missile.damageforcescale = WEP_CVAR(rpc, damageforcescale);
+ missile.health = WEP_CVAR(rpc, health);
+ missile.event_damage = W_RocketPropelledChainsaw_Damage;
+ missile.damagedbycontents = true;
+ missile.movetype = MOVETYPE_FLY;
+
+ missile.projectiledeathtype = WEP_RPC.m_id;
+ setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
+
+ setorigin (missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
+ W_SetupProjVelocity_Basic(missile, WEP_CVAR(rpc, speed), 0);
+
+ missile.touch = W_RocketPropelledChainsaw_Touch;
+
+ missile.think = W_RocketPropelledChainsaw_Think;
+ missile.cnt = time + WEP_CVAR(rpc, lifetime);
+ missile.nextthink = time;
+ missile.flags = FL_PROJECTILE;
+
+ CSQCProjectile(missile, true, PROJECTILE_RPC, false);
+
+ setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
+ SUB_SetFade (flash, time, 0.1);
+ flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+ W_AttachToShotorg(self, flash, '5 0 0');
+ missile.pos1 = missile.velocity;
+
+ MUTATOR_CALLHOOK(EditProjectile, self, missile);
+}
+
+ METHOD(RocketPropelledChainsaw, wr_aim, void(entity thiswep))
+ {
+ self.BUTTON_ATCK = bot_aim(WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false);
+ }
+ METHOD(RocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+ {
+ if(WEP_CVAR(rpc, reload_ammo) && actor.clip_load < WEP_CVAR(rpc, ammo)) {
+ Weapon w = get_weaponinfo(actor.weapon);
+ w.wr_reload(w);
+ } else
+ {
+ if (fire & 1)
+ {
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(rpc, refire)))
+ {
+ W_RocketPropelledChainsaw_Attack(thiswep);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(rpc, animtime), w_ready);
+ }
+ }
+
+ if (fire & 2)
+ {
+ // to-do
+ }
+ }
+ }
+ METHOD(RocketPropelledChainsaw, wr_init, void(entity thiswep))
+ {
+ RPC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
+ }
+ METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep))
+ {
+ float ammo_amount = self.WEP_AMMO(RPC) >= WEP_CVAR(rpc, ammo);
+ ammo_amount += self.(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo);
+ return ammo_amount;
+ }
+ METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep))
+ {
+ return false;
+ }
+ METHOD(RocketPropelledChainsaw, wr_config, void(entity thiswep))
+ {
+ RPC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
+ }
+ METHOD(RocketPropelledChainsaw, wr_reload, void(entity thiswep))
+ {
+ W_Reload(self, WEP_CVAR(rpc, ammo), SND(RELOAD));
+ }
+ METHOD(RocketPropelledChainsaw, wr_suicidemessage, int(entity thiswep))
+ {
+ if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+ return WEAPON_RPC_SUICIDE_SPLASH;
+ else
+ return WEAPON_RPC_SUICIDE_DIRECT;
+ }
+ METHOD(RocketPropelledChainsaw, wr_killmessage, int(entity thiswep))
+ {
+ if(w_deathtype & HITTYPE_SECONDARY)
+ return WEAPON_BLASTER_MURDER;
+ else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+ return WEAPON_RPC_MURDER_SPLASH;
+ else
+ return WEAPON_RPC_MURDER_DIRECT;
+ }
+
+#endif
+
+#ifdef CSQC
+
+ METHOD(RocketPropelledChainsaw, wr_impacteffect, void(entity thiswep))
+ {
+ vector org2;
+ org2 = w_org + w_backoff * 12;
+ pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
+ if(!w_issilent)
+ sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+ }
+
+#endif
+#endif
--- /dev/null
+#ifdef SVQC
+#include "physical_items.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+int autocvar_g_physical_items;
+float autocvar_g_physical_items_damageforcescale;
+float autocvar_g_physical_items_reset;
+
+REGISTER_MUTATOR(physical_items, cvar("g_physical_items"))
+{
+ // check if we have a physics engine
+ MUTATOR_ONADD
+ {
+ if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
+ {
+ LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.\n");
+ return -1;
+ }
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // nothing to roll back
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ LOG_INFO("This cannot be removed at runtime\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+.vector spawn_origin, spawn_angles;
+
+void physical_item_think()
+{SELFPARAM();
+ self.nextthink = time;
+
+ self.alpha = self.owner.alpha; // apply fading and ghosting
+
+ if(!self.cnt) // map item, not dropped
+ {
+ // copy ghost item properties
+ self.colormap = self.owner.colormap;
+ self.colormod = self.owner.colormod;
+ self.glowmod = self.owner.glowmod;
+
+ // if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
+ if(autocvar_g_physical_items_reset)
+ {
+ if(self.owner.wait > time) // awaiting respawn
+ {
+ setorigin(self, self.spawn_origin);
+ self.angles = self.spawn_angles;
+ self.solid = SOLID_NOT;
+ self.alpha = -1;
+ self.movetype = MOVETYPE_NONE;
+ }
+ else
+ {
+ self.alpha = 1;
+ self.solid = SOLID_CORPSE;
+ self.movetype = MOVETYPE_PHYSICS;
+ }
+ }
+ }
+
+ if(!self.owner.modelindex)
+ remove(self); // the real item is gone, remove this
+}
+
+void physical_item_touch()
+{SELFPARAM();
+ if(!self.cnt) // not for dropped items
+ if (ITEM_TOUCH_NEEDKILL())
+ {
+ setorigin(self, self.spawn_origin);
+ self.angles = self.spawn_angles;
+ }
+}
+
+void physical_item_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+ if(!self.cnt) // not for dropped items
+ if(ITEM_DAMAGE_NEEDKILL(deathtype))
+ {
+ setorigin(self, self.spawn_origin);
+ self.angles = self.spawn_angles;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(physical_items, Item_Spawn)
+{SELFPARAM();
+ if(self.owner == world && autocvar_g_physical_items <= 1)
+ return false;
+ if (self.spawnflags & 1) // floating item
+ return false;
+
+ // The actual item can't be physical and trigger at the same time, so make it invisible and use a second entity for physics.
+ // Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
+ entity wep;
+ wep = spawn();
+ _setmodel(wep, self.model);
+ setsize(wep, self.mins, self.maxs);
+ setorigin(wep, self.origin);
+ wep.angles = self.angles;
+ wep.velocity = self.velocity;
+
+ wep.owner = self;
+ wep.solid = SOLID_CORPSE;
+ wep.movetype = MOVETYPE_PHYSICS;
+ wep.takedamage = DAMAGE_AIM;
+ wep.effects |= EF_NOMODELFLAGS; // disable the spinning
+ wep.colormap = self.owner.colormap;
+ wep.glowmod = self.owner.glowmod;
+ wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
+ wep.dphitcontentsmask = self.dphitcontentsmask;
+ wep.cnt = (self.owner != world);
+
+ wep.think = physical_item_think;
+ wep.nextthink = time;
+ wep.touch = physical_item_touch;
+ wep.event_damage = physical_item_damage;
+
+ if(!wep.cnt)
+ {
+ // fix the spawn origin
+ setorigin(wep, wep.origin + '0 0 1');
+ entity oldself;
+ oldself = self;
+ WITH(entity, self, wep, builtin_droptofloor());
+ }
+
+ wep.spawn_origin = wep.origin;
+ wep.spawn_angles = self.angles;
+
+ self.effects |= EF_NODRAW; // hide the original weapon
+ self.movetype = MOVETYPE_FOLLOW;
+ self.aiment = wep; // attach the original weapon
+ self.SendEntity = func_null;
+
+ return false;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "pinata.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(pinata, cvar("g_pinata") && !cvar("g_instagib") && !cvar("g_overkill"));
+
+MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
+{SELFPARAM();
+ for(int j = WEP_FIRST; j <= WEP_LAST; ++j)
+ if(self.weapons & WepSet_FromWeapon(j))
+ if(self.switchweapon != j)
+ if(W_IsWeaponThrowable(j))
+ W_ThrowNewWeapon(self, j, false, self.origin + (self.mins + self.maxs) * 0.5, randomvec() * 175 + '0 0 325');
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":Pinata");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Piñata");
+ return false;
+}
+
+#endif
--- /dev/null
+#ifdef SVQC
+#include "random_gravity.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+// Random Gravity
+//
+// Mutator by Mario
+// Inspired by Player 2
+
+float autocvar_g_random_gravity_negative_chance;
+float autocvar_g_random_gravity_min;
+float autocvar_g_random_gravity_max;
+float autocvar_g_random_gravity_positive;
+float autocvar_g_random_gravity_negative;
+float autocvar_g_random_gravity_delay;
+
+REGISTER_MUTATOR(random_gravity, cvar("g_random_gravity"))
+{
+ MUTATOR_ONADD
+ {
+ cvar_settemp("sv_gravity", cvar_string("sv_gravity")); // settemp current gravity so it's restored on match end
+ }
+
+ return false;
+}
+
+float gravity_delay;
+
+MUTATOR_HOOKFUNCTION(random_gravity, SV_StartFrame)
+{
+ if(gameover || !cvar("g_random_gravity")) return false;
+ if(time < gravity_delay) return false;
+ if(time < game_starttime) return false;
+ if(round_handler_IsActive() && !round_handler_IsRoundStarted()) return false;
+
+ if(random() >= autocvar_g_random_gravity_negative_chance)
+ cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() - random() * -autocvar_g_random_gravity_negative, autocvar_g_random_gravity_max)));
+ else
+ cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() * autocvar_g_random_gravity_positive, autocvar_g_random_gravity_max)));
+
+ gravity_delay = time + autocvar_g_random_gravity_delay;
+
+ LOG_TRACE("Gravity is now: ", ftos(autocvar_sv_gravity), "\n");
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":RandomGravity");
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Random gravity");
+ return 0;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "rocketflying.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(rocketflying, cvar("g_rocket_flying"));
+
+MUTATOR_HOOKFUNCTION(rocketflying, EditProjectile)
+{
+ if(other.classname == "rocket" || other.classname == "mine")
+ {
+ // kill detonate delay of rockets
+ other.spawnshieldtime = time;
+ }
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":RocketFlying");
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Rocket Flying");
+ return 0;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "rocketminsta.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+#include "../../../deathtypes/all.qh"
+#include "../../../../server/round_handler.qh"
+
+REGISTER_MUTATOR(rm, cvar("g_instagib"));
+
+MUTATOR_HOOKFUNCTION(rm, PlayerDamage_Calculate)
+{
+ // we do it this way, so rm can be toggled during the match
+ if(!autocvar_g_rm) { return false; }
+
+ if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR))
+ if(frag_attacker == frag_target || frag_target.classname == "nade")
+ frag_damage = 0;
+
+ if(autocvar_g_rm_laser)
+ if(DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
+ if(frag_attacker == frag_target || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
+ frag_damage = 0;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(rm, PlayerDies)
+{
+ // we do it this way, so rm can be toggled during the match
+ if(!autocvar_g_rm) { return false; }
+
+ if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR) || DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
+ frag_damage = 1000; // always gib if it was a vaporizer death
+
+ return false;
+}
+
+#endif
--- /dev/null
+#ifdef SVQC
+#include "running_guns.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+
+bool autocvar_g_running_guns;
+
+REGISTER_MUTATOR(running_guns, autocvar_g_running_guns);
+
+MUTATOR_HOOKFUNCTION(running_guns, SetDefaultAlpha)
+{
+ default_player_alpha = -1;
+ default_weapon_alpha = +1;
+ return true;
+}
+
+#endif
--- /dev/null
+#ifdef SVQC
+#include "sandbox.qc"
+
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+int autocvar_g_sandbox_info;
+bool autocvar_g_sandbox_readonly;
+string autocvar_g_sandbox_storage_name;
+float autocvar_g_sandbox_storage_autosave;
+bool autocvar_g_sandbox_storage_autoload;
+float autocvar_g_sandbox_editor_flood;
+int autocvar_g_sandbox_editor_maxobjects;
+int autocvar_g_sandbox_editor_free;
+float autocvar_g_sandbox_editor_distance_spawn;
+float autocvar_g_sandbox_editor_distance_edit;
+float autocvar_g_sandbox_object_scale_min;
+float autocvar_g_sandbox_object_scale_max;
+float autocvar_g_sandbox_object_material_velocity_min;
+float autocvar_g_sandbox_object_material_velocity_factor;
+
+float autosave_time;
+void sandbox_Database_Load();
+
+REGISTER_MUTATOR(sandbox, cvar("g_sandbox"))
+{
+ MUTATOR_ONADD
+ {
+ autosave_time = time + autocvar_g_sandbox_storage_autosave; // don't save the first server frame
+ if(autocvar_g_sandbox_storage_autoload)
+ sandbox_Database_Load();
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // nothing to roll back
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ // nothing to remove
+ }
+
+ return false;
+}
+
+const float MAX_STORAGE_ATTACHMENTS = 16;
+float object_count;
+.float object_flood;
+.entity object_attach;
+.string material;
+
+.float touch_timer;
+void sandbox_ObjectFunction_Touch()
+{SELFPARAM();
+ // apply material impact effects
+
+ if(!self.material)
+ return;
+ if(self.touch_timer > time)
+ return; // don't execute each frame
+ self.touch_timer = time + 0.1;
+
+ // make particle count and sound volume depend on impact speed
+ float intensity;
+ intensity = vlen(self.velocity) + vlen(other.velocity);
+ if(intensity) // avoid divisions by 0
+ intensity /= 2; // average the two velocities
+ if (!(intensity >= autocvar_g_sandbox_object_material_velocity_min))
+ return; // impact not strong enough to do anything
+ // now offset intensity and apply it to the effects
+ intensity -= autocvar_g_sandbox_object_material_velocity_min; // start from minimum velocity, not actual velocity
+ intensity = bound(0, intensity * autocvar_g_sandbox_object_material_velocity_factor, 1);
+
+ _sound(self, CH_TRIGGER, strcat("object/impact_", self.material, "_", ftos(ceil(random() * 5)) , ".wav"), VOL_BASE * intensity, ATTEN_NORM);
+ Send_Effect_(strcat("impact_", self.material), self.origin, '0 0 0', ceil(intensity * 10)); // allow a count from 1 to 10
+}
+
+void sandbox_ObjectFunction_Think()
+{SELFPARAM();
+ entity e;
+
+ // decide if and how this object can be grabbed
+ if(autocvar_g_sandbox_readonly)
+ self.grab = 0; // no grabbing
+ else if(autocvar_g_sandbox_editor_free < 2 && self.crypto_idfp)
+ self.grab = 1; // owner only
+ else
+ self.grab = 3; // anyone
+
+ // Object owner is stored via player UID, but we also need the owner as an entity (if the player is available on the server).
+ // Therefore, scan for all players, and update the owner as long as the player is present. We must always do this,
+ // since if the owning player disconnects, the object's owner should also be reset.
+ FOR_EACH_REALPLAYER(e) // bots can't have objects
+ {
+ if(self.crypto_idfp == e.crypto_idfp)
+ {
+ self.realowner = e;
+ break;
+ }
+ self.realowner = world;
+ }
+
+ self.nextthink = time;
+
+ CSQCMODEL_AUTOUPDATE(self);
+}
+
+.float old_solid, old_movetype;
+entity sandbox_ObjectEdit_Get(float permissions)
+{SELFPARAM();
+ // Returns the traced entity if the player can edit it, and world if not.
+ // If permissions if false, the object is returned regardless of editing rights.
+ // Attached objects are SOLID_NOT and do not get traced.
+
+ crosshair_trace_plusvisibletriggers(self);
+ if(vlen(self.origin - trace_ent.origin) > autocvar_g_sandbox_editor_distance_edit)
+ return world; // out of trace range
+ if(trace_ent.classname != "object")
+ return world; // entity is not an object
+ if(!permissions)
+ return trace_ent; // don't check permissions, anyone can edit this object
+ if(trace_ent.crypto_idfp == "")
+ return trace_ent; // the player who spawned this object did not have an UID, so anyone can edit it
+ if (!(trace_ent.realowner != self && autocvar_g_sandbox_editor_free < 2))
+ return trace_ent; // object does not belong to the player, and players can only edit their own objects on this server
+ return world;
+}
+
+void sandbox_ObjectEdit_Scale(entity e, float f)
+{
+ e.scale = f;
+ if(e.scale)
+ {
+ e.scale = bound(autocvar_g_sandbox_object_scale_min, e.scale, autocvar_g_sandbox_object_scale_max);
+ _setmodel(e, e.model); // reset mins and maxs based on mesh
+ setsize(e, e.mins * e.scale, e.maxs * e.scale); // adapt bounding box size to model size
+ }
+}
+
+void sandbox_ObjectAttach_Remove(entity e);
+void sandbox_ObjectAttach_Set(entity e, entity parent, string s)
+{
+ // attaches e to parent on string s
+
+ // we can't attach to an attachment, for obvious reasons
+ sandbox_ObjectAttach_Remove(e);
+
+ e.old_solid = e.solid; // persist solidity
+ e.old_movetype = e.movetype; // persist physics
+ e.movetype = MOVETYPE_FOLLOW;
+ e.solid = SOLID_NOT;
+ e.takedamage = DAMAGE_NO;
+
+ setattachment(e, parent, s);
+ e.owner = parent;
+}
+
+void sandbox_ObjectAttach_Remove(entity e)
+{
+ // detaches any object attached to e
+
+ entity head;
+ for(head = world; (head = find(head, classname, "object")); )
+ {
+ if(head.owner == e)
+ {
+ vector org;
+ org = gettaginfo(head, 0);
+ setattachment(head, world, "");
+ head.owner = world;
+
+ // objects change origin and angles when detached, so apply previous position
+ setorigin(head, org);
+ head.angles = e.angles; // don't allow detached objects to spin or roll
+
+ head.solid = head.old_solid; // restore persisted solidity
+ head.movetype = head.old_movetype; // restore persisted physics
+ head.takedamage = DAMAGE_AIM;
+ }
+ }
+}
+
+entity sandbox_ObjectSpawn(float database)
+{SELFPARAM();
+ // spawn a new object with default properties
+
+ entity e = new(object);
+ e.takedamage = DAMAGE_AIM;
+ e.damageforcescale = 1;
+ e.solid = SOLID_BBOX; // SOLID_BSP would be best, but can lag the server badly
+ e.movetype = MOVETYPE_TOSS;
+ e.frame = 0;
+ e.skin = 0;
+ e.material = string_null;
+ e.touch = sandbox_ObjectFunction_Touch;
+ e.think = sandbox_ObjectFunction_Think;
+ e.nextthink = time;
+ //e.effects |= EF_SELECTABLE; // don't do this all the time, maybe just when editing objects?
+
+ if(!database)
+ {
+ // set the object's owner via player UID
+ // if the player does not have an UID, the owner cannot be stored and his objects may be edited by anyone
+ if(self.crypto_idfp != "")
+ e.crypto_idfp = strzone(self.crypto_idfp);
+ else
+ print_to(self, "^1SANDBOX - WARNING: ^7You spawned an object, but lack a player UID. ^1Your objects are not secured and can be edited by any player!");
+
+ // set public object information
+ e.netname = strzone(self.netname); // name of the owner
+ e.message = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // creation time
+ e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // last editing time
+
+ // set origin and direction based on player position and view angle
+ makevectors(self.v_angle);
+ WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * autocvar_g_sandbox_editor_distance_spawn, MOVE_NORMAL, self);
+ setorigin(e, trace_endpos);
+ e.angles_y = self.v_angle.y;
+ }
+
+ WITH(entity, self, e, CSQCMODEL_AUTOINIT(e));
+
+ object_count += 1;
+ return e;
+}
+
+void sandbox_ObjectRemove(entity e)
+{
+ sandbox_ObjectAttach_Remove(e); // detach child objects
+
+ // if the object being removed has been selected for attachment by a player, unset it
+ entity head;
+ FOR_EACH_REALPLAYER(head) // bots can't have objects
+ {
+ if(head.object_attach == e)
+ head.object_attach = world;
+ }
+
+ if(e.material) { strunzone(e.material); e.material = string_null; }
+ if(e.crypto_idfp) { strunzone(e.crypto_idfp); e.crypto_idfp = string_null; }
+ if(e.netname) { strunzone(e.netname); e.netname = string_null; }
+ if(e.message) { strunzone(e.message); e.message = string_null; }
+ if(e.message2) { strunzone(e.message2); e.message2 = string_null; }
+ remove(e);
+ e = world;
+
+ object_count -= 1;
+}
+
+string port_string[MAX_STORAGE_ATTACHMENTS]; // fteqcc crashes if this isn't defined as a global
+
+string sandbox_ObjectPort_Save(entity e, float database)
+{
+ // save object properties, and return them as a string
+ float i = 0;
+ string s;
+ entity head;
+
+ for(head = world; (head = find(head, classname, "object")); )
+ {
+ // the main object needs to be first in the array [0] with attached objects following
+ float slot, physics, solidity;
+ if(head == e) // this is the main object, place it first
+ {
+ slot = 0;
+ solidity = head.solid; // applied solidity is normal solidity for children
+ physics = head.movetype; // applied physics are normal physics for parents
+ }
+ else if(head.owner == e) // child object, list them in order
+ {
+ i += 1; // children start from 1
+ slot = i;
+ solidity = head.old_solid; // persisted solidity is normal solidity for children
+ physics = head.old_movetype; // persisted physics are normal physics for children
+ gettaginfo(head.owner, head.tag_index); // get the name of the tag our object is attached to, used further below
+ }
+ else
+ continue;
+
+ // ---------------- OBJECT PROPERTY STORAGE: SAVE ----------------
+ if(slot)
+ {
+ // properties stored only for child objects
+ if(gettaginfo_name) port_string[slot] = strcat(port_string[slot], "\"", gettaginfo_name, "\" "); else port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+ }
+ else
+ {
+ // properties stored only for parent objects
+ if(database)
+ {
+ port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.origin), " ");
+ port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.angles), " ");
+ }
+ }
+ // properties stored for all objects
+ port_string[slot] = strcat(port_string[slot], "\"", head.model, "\" ");
+ port_string[slot] = strcat(port_string[slot], ftos(head.skin), " ");
+ port_string[slot] = strcat(port_string[slot], ftos(head.alpha), " ");
+ port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.colormod), " ");
+ port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.glowmod), " ");
+ port_string[slot] = strcat(port_string[slot], ftos(head.frame), " ");
+ port_string[slot] = strcat(port_string[slot], ftos(head.scale), " ");
+ port_string[slot] = strcat(port_string[slot], ftos(solidity), " ");
+ port_string[slot] = strcat(port_string[slot], ftos(physics), " ");
+ port_string[slot] = strcat(port_string[slot], ftos(head.damageforcescale), " ");
+ if(head.material) port_string[slot] = strcat(port_string[slot], "\"", head.material, "\" "); else port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+ if(database)
+ {
+ // properties stored only for the database
+ if(head.crypto_idfp) port_string[slot] = strcat(port_string[slot], "\"", head.crypto_idfp, "\" "); else port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+ port_string[slot] = strcat(port_string[slot], "\"", e.netname, "\" ");
+ port_string[slot] = strcat(port_string[slot], "\"", e.message, "\" ");
+ port_string[slot] = strcat(port_string[slot], "\"", e.message2, "\" ");
+ }
+ }
+
+ // now apply the array to a simple string, with the ; symbol separating objects
+ s = "";
+ for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
+ {
+ if(port_string[i])
+ s = strcat(s, port_string[i], "; ");
+ port_string[i] = string_null; // fully clear the string
+ }
+
+ return s;
+}
+
+entity sandbox_ObjectPort_Load(string s, float database)
+{
+ // load object properties, and spawn a new object with them
+ float n, i;
+ entity e = world, parent = world;
+
+ // separate objects between the ; symbols
+ n = tokenizebyseparator(s, "; ");
+ for(i = 0; i < n; ++i)
+ port_string[i] = argv(i);
+
+ // now separate and apply the properties of each object
+ for(i = 0; i < n; ++i)
+ {
+ float argv_num;
+ string tagname = string_null;
+ argv_num = 0;
+ tokenize_console(port_string[i]);
+ e = sandbox_ObjectSpawn(database);
+
+ // ---------------- OBJECT PROPERTY STORAGE: LOAD ----------------
+ if(i)
+ {
+ // properties stored only for child objects
+ if(argv(argv_num) != "") tagname = argv(argv_num); else tagname = string_null; ++argv_num;
+ }
+ else
+ {
+ // properties stored only for parent objects
+ if(database)
+ {
+ setorigin(e, stov(argv(argv_num))); ++argv_num;
+ e.angles = stov(argv(argv_num)); ++argv_num;
+ }
+ parent = e; // mark parent objects as such
+ }
+ // properties stored for all objects
+ _setmodel(e, argv(argv_num)); ++argv_num;
+ e.skin = stof(argv(argv_num)); ++argv_num;
+ e.alpha = stof(argv(argv_num)); ++argv_num;
+ e.colormod = stov(argv(argv_num)); ++argv_num;
+ e.glowmod = stov(argv(argv_num)); ++argv_num;
+ e.frame = stof(argv(argv_num)); ++argv_num;
+ sandbox_ObjectEdit_Scale(e, stof(argv(argv_num))); ++argv_num;
+ e.solid = e.old_solid = stof(argv(argv_num)); ++argv_num;
+ e.movetype = e.old_movetype = stof(argv(argv_num)); ++argv_num;
+ e.damageforcescale = stof(argv(argv_num)); ++argv_num;
+ if(e.material) strunzone(e.material); if(argv(argv_num) != "") e.material = strzone(argv(argv_num)); else e.material = string_null; ++argv_num;
+ if(database)
+ {
+ // properties stored only for the database
+ if(e.crypto_idfp) strunzone(e.crypto_idfp); if(argv(argv_num) != "") e.crypto_idfp = strzone(argv(argv_num)); else e.crypto_idfp = string_null; ++argv_num;
+ if(e.netname) strunzone(e.netname); e.netname = strzone(argv(argv_num)); ++argv_num;
+ if(e.message) strunzone(e.message); e.message = strzone(argv(argv_num)); ++argv_num;
+ if(e.message2) strunzone(e.message2); e.message2 = strzone(argv(argv_num)); ++argv_num;
+ }
+
+ // attach last
+ if(i)
+ sandbox_ObjectAttach_Set(e, parent, tagname);
+ }
+
+ for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
+ port_string[i] = string_null; // fully clear the string
+
+ return e;
+}
+
+void sandbox_Database_Save()
+{
+ // saves all objects to the database file
+ entity head;
+ string file_name;
+ float file_get;
+
+ file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
+ file_get = fopen(file_name, FILE_WRITE);
+ fputs(file_get, strcat("// sandbox storage \"", autocvar_g_sandbox_storage_name, "\" for map \"", GetMapname(), "\" last updated ", strftime(true, "%d-%m-%Y %H:%M:%S")));
+ fputs(file_get, strcat(" containing ", ftos(object_count), " objects\n"));
+
+ for(head = world; (head = find(head, classname, "object")); )
+ {
+ // attached objects are persisted separately, ignore them here
+ if(head.owner != world)
+ continue;
+
+ // use a line of text for each object, listing all properties
+ fputs(file_get, strcat(sandbox_ObjectPort_Save(head, true), "\n"));
+ }
+ fclose(file_get);
+}
+
+void sandbox_Database_Load()
+{
+ // loads all objects from the database file
+ string file_read, file_name;
+ float file_get, i;
+
+ file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
+ file_get = fopen(file_name, FILE_READ);
+ if(file_get < 0)
+ {
+ if(autocvar_g_sandbox_info > 0)
+ LOG_INFO(strcat("^3SANDBOX - SERVER: ^7could not find storage file ^3", file_name, "^7, no objects were loaded\n"));
+ }
+ else
+ {
+ for (;;)
+ {
+ file_read = fgets(file_get);
+ if(file_read == "")
+ break;
+ if(substring(file_read, 0, 2) == "//")
+ continue;
+ if(substring(file_read, 0, 1) == "#")
+ continue;
+
+ entity e;
+ e = sandbox_ObjectPort_Load(file_read, true);
+
+ if(e.material)
+ {
+ // since objects are being loaded for the first time, precache material sounds for each
+ for (i = 1; i <= 5; i++) // 5 sounds in total
+ precache_sound(strcat("object/impact_", e.material, "_", ftos(i), ".wav"));
+ }
+ }
+ if(autocvar_g_sandbox_info > 0)
+ LOG_INFO(strcat("^3SANDBOX - SERVER: ^7successfully loaded storage file ^3", file_name, "\n"));
+ }
+ fclose(file_get);
+}
+
+MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
+{SELFPARAM();
+ if(MUTATOR_RETURNVALUE) // command was already handled?
+ return false;
+ if(cmd_name == "g_sandbox")
+ {
+ if(autocvar_g_sandbox_readonly)
+ {
+ print_to(self, "^2SANDBOX - INFO: ^7Sandbox mode is active, but in read-only mode. Sandbox commands cannot be used");
+ return true;
+ }
+ if(cmd_argc < 2)
+ {
+ print_to(self, "^2SANDBOX - INFO: ^7Sandbox mode is active. For usage information, type 'sandbox help'");
+ return true;
+ }
+
+ switch(argv(1))
+ {
+ entity e;
+ float i;
+ string s;
+
+ // ---------------- COMMAND: HELP ----------------
+ case "help":
+ print_to(self, "You can use the following sandbox commands:");
+ print_to(self, "^7\"^2object_spawn ^3models/foo/bar.md3^7\" spawns a new object in front of the player, and gives it the specified model");
+ print_to(self, "^7\"^2object_remove^7\" removes the object the player is looking at. Players can only remove their own objects");
+ print_to(self, "^7\"^2object_duplicate ^3value^7\" duplicates the object, if the player has copying rights over the original");
+ print_to(self, "^3copy value ^7- copies the properties of the object to the specified client cvar");
+ print_to(self, "^3paste value ^7- spawns an object with the given properties. Properties or cvars must be specified as follows; eg1: \"0 1 2 ...\", eg2: \"$cl_cvar\"");
+ print_to(self, "^7\"^2object_attach ^3property value^7\" attaches one object to another. Players can only attach their own objects");
+ print_to(self, "^3get ^7- selects the object you are facing as the object to be attached");
+ print_to(self, "^3set value ^7- attaches the previously selected object to the object you are facing, on the specified bone");
+ print_to(self, "^3remove ^7- detaches all objects from the object you are facing");
+ print_to(self, "^7\"^2object_edit ^3property value^7\" edits the given property of the object. Players can only edit their own objects");
+ print_to(self, "^3skin value ^7- changes the skin of the object");
+ print_to(self, "^3alpha value ^7- sets object transparency");
+ print_to(self, "^3colormod \"value_x value_y value_z\" ^7- main object color");
+ print_to(self, "^3glowmod \"value_x value_y value_z\" ^7- glow object color");
+ print_to(self, "^3frame value ^7- object animation frame, for self-animated models");
+ print_to(self, "^3scale value ^7- changes object scale. 0.5 is half size and 2 is double size");
+ print_to(self, "^3solidity value ^7- object collisions, 0 = non-solid, 1 = solid");
+ print_to(self, "^3physics value ^7- object physics, 0 = static, 1 = movable, 2 = physical");
+ print_to(self, "^3force value ^7- amount of force applied to objects that are shot");
+ print_to(self, "^3material value ^7- sets the material of the object. Default materials are: metal, stone, wood, flesh");
+ print_to(self, "^7\"^2object_claim^7\" sets the player as the owner of the object, if he has the right to edit it");
+ print_to(self, "^7\"^2object_info ^3value^7\" shows public information about the object");
+ print_to(self, "^3object ^7- prints general information about the object, such as owner and creation / editing date");
+ print_to(self, "^3mesh ^7- prints information about the object's mesh, including skeletal bones");
+ print_to(self, "^3attachments ^7- prints information about the object's attachments");
+ print_to(self, "^7The ^1drag object ^7key can be used to grab and carry objects. Players can only grab their own objects");
+ return true;
+
+ // ---------------- COMMAND: OBJECT, SPAWN ----------------
+ case "object_spawn":
+ if(time < self.object_flood)
+ {
+ print_to(self, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(self.object_flood - time), " ^7seconds beofore spawning another object"));
+ return true;
+ }
+ self.object_flood = time + autocvar_g_sandbox_editor_flood;
+ if(object_count >= autocvar_g_sandbox_editor_maxobjects)
+ {
+ print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
+ return true;
+ }
+ if(cmd_argc < 3)
+ {
+ print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object without specifying a model. Please specify the path to your model file after the 'object_spawn' command");
+ return true;
+ }
+ if (!(fexists(argv(2))))
+ {
+ print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object with a non-existent model. Make sure the path to your model file is correct");
+ return true;
+ }
+
+ e = sandbox_ObjectSpawn(false);
+ _setmodel(e, argv(2));
+
+ if(autocvar_g_sandbox_info > 0)
+ LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " spawned an object at origin ^3", vtos(e.origin), "\n"));
+ return true;
+
+ // ---------------- COMMAND: OBJECT, REMOVE ----------------
+ case "object_remove":
+ e = sandbox_ObjectEdit_Get(true);
+ if(e != world)
+ {
+ if(autocvar_g_sandbox_info > 0)
+ LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " removed an object at origin ^3", vtos(e.origin), "\n"));
+ sandbox_ObjectRemove(e);
+ return true;
+ }
+
+ print_to(self, "^1SANDBOX - WARNING: ^7Object could not be removed. Make sure you are facing an object that you have edit rights over");
+ return true;
+
+ // ---------------- COMMAND: OBJECT, DUPLICATE ----------------
+ case "object_duplicate":
+ switch(argv(2))
+ {
+ case "copy":
+ // copies customizable properties of the selected object to the clipboard cvar
+ e = sandbox_ObjectEdit_Get(autocvar_g_sandbox_editor_free); // can we copy objects we can't edit?
+ if(e != world)
+ {
+ s = sandbox_ObjectPort_Save(e, false);
+ s = strreplace("\"", "\\\"", s);
+ stuffcmd(self, strcat("set ", argv(3), " \"", s, "\""));
+
+ print_to(self, "^2SANDBOX - INFO: ^7Object copied to clipboard");
+ return true;
+ }
+ print_to(self, "^1SANDBOX - WARNING: ^7Object could not be copied. Make sure you are facing an object that you have copy rights over");
+ return true;
+
+ case "paste":
+ // spawns a new object using the properties in the player's clipboard cvar
+ if(time < self.object_flood)
+ {
+ print_to(self, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(self.object_flood - time), " ^7seconds beofore spawning another object"));
+ return true;
+ }
+ self.object_flood = time + autocvar_g_sandbox_editor_flood;
+ if(argv(3) == "") // no object in clipboard
+ {
+ print_to(self, "^1SANDBOX - WARNING: ^7No object in clipboard. You must copy an object before you can paste it");
+ return true;
+ }
+ if(object_count >= autocvar_g_sandbox_editor_maxobjects)
+ {
+ print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
+ return true;
+ }
+ e = sandbox_ObjectPort_Load(argv(3), false);
+
+ print_to(self, "^2SANDBOX - INFO: ^7Object pasted successfully");
+ if(autocvar_g_sandbox_info > 0)
+ LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " pasted an object at origin ^3", vtos(e.origin), "\n"));
+ return true;
+ }
+ return true;
+
+ // ---------------- COMMAND: OBJECT, ATTACH ----------------
+ case "object_attach":
+ switch(argv(2))
+ {
+ case "get":
+ // select e as the object as meant to be attached
+ e = sandbox_ObjectEdit_Get(true);
+ if(e != world)
+ {
+ self.object_attach = e;
+ print_to(self, "^2SANDBOX - INFO: ^7Object selected for attachment");
+ return true;
+ }
+ print_to(self, "^1SANDBOX - WARNING: ^7Object could not be selected for attachment. Make sure you are facing an object that you have edit rights over");
+ return true;
+ case "set":
+ if(self.object_attach == world)
+ {
+ print_to(self, "^1SANDBOX - WARNING: ^7No object selected for attachment. Please select an object to be attached first.");
+ return true;
+ }
+
+ // attaches the previously selected object to e
+ e = sandbox_ObjectEdit_Get(true);
+ if(e != world)
+ {
+ sandbox_ObjectAttach_Set(self.object_attach, e, argv(3));
+ self.object_attach = world; // object was attached, no longer keep it scheduled for attachment
+ print_to(self, "^2SANDBOX - INFO: ^7Object attached successfully");
+ if(autocvar_g_sandbox_info > 1)
+ LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " attached objects at origin ^3", vtos(e.origin), "\n"));
+ return true;
+ }
+ print_to(self, "^1SANDBOX - WARNING: ^7Object could not be attached to the parent. Make sure you are facing an object that you have edit rights over");
+ return true;
+ case "remove":
+ // removes e if it was attached
+ e = sandbox_ObjectEdit_Get(true);
+ if(e != world)
+ {
+ sandbox_ObjectAttach_Remove(e);
+ print_to(self, "^2SANDBOX - INFO: ^7Child objects detached successfully");
+ if(autocvar_g_sandbox_info > 1)
+ LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " detached objects at origin ^3", vtos(e.origin), "\n"));
+ return true;
+ }
+ print_to(self, "^1SANDBOX - WARNING: ^7Child objects could not be detached. Make sure you are facing an object that you have edit rights over");
+ return true;
+ }
+ return true;
+
+ // ---------------- COMMAND: OBJECT, EDIT ----------------
+ case "object_edit":
+ if(argv(2) == "")
+ {
+ print_to(self, "^1SANDBOX - WARNING: ^7Too few parameters. You must specify a property to edit");
+ return true;
+ }
+
+ e = sandbox_ObjectEdit_Get(true);
+ if(e != world)
+ {
+ switch(argv(2))
+ {
+ case "skin":
+ e.skin = stof(argv(3));
+ break;
+ case "alpha":
+ e.alpha = stof(argv(3));
+ break;
+ case "color_main":
+ e.colormod = stov(argv(3));
+ break;
+ case "color_glow":
+ e.glowmod = stov(argv(3));
+ break;
+ case "frame":
+ e.frame = stof(argv(3));
+ break;
+ case "scale":
+ sandbox_ObjectEdit_Scale(e, stof(argv(3)));
+ break;
+ case "solidity":
+ switch(argv(3))
+ {
+ case "0": // non-solid
+ e.solid = SOLID_TRIGGER;
+ break;
+ case "1": // solid
+ e.solid = SOLID_BBOX;
+ break;
+ default:
+ break;
+ }
+ case "physics":
+ switch(argv(3))
+ {
+ case "0": // static
+ e.movetype = MOVETYPE_NONE;
+ break;
+ case "1": // movable
+ e.movetype = MOVETYPE_TOSS;
+ break;
+ case "2": // physical
+ e.movetype = MOVETYPE_PHYSICS;
+ break;
+ default:
+ break;
+ }
+ break;
+ case "force":
+ e.damageforcescale = stof(argv(3));
+ break;
+ case "material":
+ if(e.material) strunzone(e.material);
+ if(argv(3))
+ {
+ for (i = 1; i <= 5; i++) // precache material sounds, 5 in total
+ precache_sound(strcat("object/impact_", argv(3), "_", ftos(i), ".wav"));
+ e.material = strzone(argv(3));
+ }
+ else
+ e.material = string_null; // no material
+ break;
+ default:
+ print_to(self, "^1SANDBOX - WARNING: ^7Invalid object property. For usage information, type 'sandbox help'");
+ return true;
+ }
+
+ // update last editing time
+ if(e.message2) strunzone(e.message2);
+ e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S"));
+
+ if(autocvar_g_sandbox_info > 1)
+ LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " edited property ^3", argv(2), " ^7of an object at origin ^3", vtos(e.origin), "\n"));
+ return true;
+ }
+
+ print_to(self, "^1SANDBOX - WARNING: ^7Object could not be edited. Make sure you are facing an object that you have edit rights over");
+ return true;
+
+ // ---------------- COMMAND: OBJECT, CLAIM ----------------
+ case "object_claim":
+ // if the player can edit an object but is not its owner, this can be used to claim that object
+ if(self.crypto_idfp == "")
+ {
+ print_to(self, "^1SANDBOX - WARNING: ^7You do not have a player UID, and cannot claim objects");
+ return true;
+ }
+ e = sandbox_ObjectEdit_Get(true);
+ if(e != world)
+ {
+ // update the owner's name
+ // Do this before checking if you're already the owner and skipping if such, so we
+ // also update the player's nickname if he changed it (but has the same player UID)
+ if(e.netname != self.netname)
+ {
+ if(e.netname) strunzone(e.netname);
+ e.netname = strzone(self.netname);
+ print_to(self, "^2SANDBOX - INFO: ^7Object owner name updated");
+ }
+
+ if(e.crypto_idfp == self.crypto_idfp)
+ {
+ print_to(self, "^2SANDBOX - INFO: ^7Object is already yours, nothing to claim");
+ return true;
+ }
+
+ if(e.crypto_idfp) strunzone(e.crypto_idfp);
+ e.crypto_idfp = strzone(self.crypto_idfp);
+
+ print_to(self, "^2SANDBOX - INFO: ^7Object claimed successfully");
+ }
+ print_to(self, "^1SANDBOX - WARNING: ^7Object could not be claimed. Make sure you are facing an object that you have edit rights over");
+ return true;
+
+ // ---------------- COMMAND: OBJECT, INFO ----------------
+ case "object_info":
+ // prints public information about the object to the player
+ e = sandbox_ObjectEdit_Get(false);
+ if(e != world)
+ {
+ switch(argv(2))
+ {
+ case "object":
+ print_to(self, strcat("^2SANDBOX - INFO: ^7Object is owned by \"^7", e.netname, "^7\", created \"^3", e.message, "^7\", last edited \"^3", e.message2, "^7\""));
+ return true;
+ case "mesh":
+ s = "";
+ FOR_EACH_TAG(e)
+ s = strcat(s, "^7\"^5", gettaginfo_name, "^7\", ");
+ print_to(self, strcat("^2SANDBOX - INFO: ^7Object mesh is \"^3", e.model, "^7\" at animation frame ^3", ftos(e.frame), " ^7containing the following tags: ", s));
+ return true;
+ case "attachments":
+ // this should show the same info as 'mesh' but for attachments
+ s = "";
+ entity head;
+ i = 0;
+ for(head = world; (head = find(head, classname, "object")); )
+ {
+ if(head.owner == e)
+ {
+ ++i; // start from 1
+ gettaginfo(e, head.tag_index);
+ s = strcat(s, "^1attachment ", ftos(i), "^7 has mesh \"^3", head.model, "^7\" at animation frame ^3", ftos(head.frame));
+ s = strcat(s, "^7 and is attached to bone \"^5", gettaginfo_name, "^7\", ");
+ }
+ }
+ if(i) // object contains attachments
+ print_to(self, strcat("^2SANDBOX - INFO: ^7Object contains the following ^1", ftos(i), "^7 attachment(s): ", s));
+ else
+ print_to(self, "^2SANDBOX - INFO: ^7Object contains no attachments");
+ return true;
+ }
+ }
+ print_to(self, "^1SANDBOX - WARNING: ^7No information could be found. Make sure you are facing an object");
+ return true;
+
+ // ---------------- COMMAND: DEFAULT ----------------
+ default:
+ print_to(self, "Invalid command. For usage information, type 'sandbox help'");
+ return true;
+ }
+ }
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(sandbox, SV_StartFrame)
+{
+ if(!autocvar_g_sandbox_storage_autosave)
+ return false;
+ if(time < autosave_time)
+ return false;
+ autosave_time = time + autocvar_g_sandbox_storage_autosave;
+
+ sandbox_Database_Save();
+
+ return true;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "spawn_near_teammate.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+
+float autocvar_g_spawn_near_teammate_distance;
+int autocvar_g_spawn_near_teammate_ignore_spawnpoint;
+float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
+float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
+int autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
+bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
+
+REGISTER_MUTATOR(spawn_near_teammate, cvar("g_spawn_near_teammate") && teamplay);
+
+.entity msnt_lookat;
+
+.float msnt_timer;
+.vector msnt_deathloc;
+
+.float cvar_cl_spawn_near_teammate;
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, Spawn_Score)
+{SELFPARAM();
+ if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && self.cvar_cl_spawn_near_teammate))
+ return 0;
+
+ entity p;
+
+ spawn_spot.msnt_lookat = world;
+
+ if(!teamplay)
+ return 0;
+
+ RandomSelection_Init();
+ FOR_EACH_PLAYER(p) if(p != self) if(p.team == self.team) if(!p.deadflag)
+ {
+ float l = vlen(spawn_spot.origin - p.origin);
+ if(l > autocvar_g_spawn_near_teammate_distance)
+ continue;
+ if(l < 48)
+ continue;
+ if(!checkpvs(spawn_spot.origin, p))
+ continue;
+ RandomSelection_Add(p, 0, string_null, 1, 1);
+ }
+
+ if(RandomSelection_chosen_ent)
+ {
+ spawn_spot.msnt_lookat = RandomSelection_chosen_ent;
+ spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_FOUND;
+ }
+ else if(self.team == spawn_spot.team)
+ spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM; // prefer same team, if we can't find a spawn near teammate
+
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
+{SELFPARAM();
+ // Note: when entering this, fixangle is already set.
+ if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && self.cvar_cl_spawn_near_teammate))
+ {
+ if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death)
+ self.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
+
+ entity team_mate, best_mate = world;
+ vector best_spot = '0 0 0';
+ float pc = 0, best_dist = 0, dist = 0;
+ FOR_EACH_PLAYER(team_mate)
+ {
+ if((autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health >= 0 && team_mate.health >= autocvar_g_balance_health_regenstable) || autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health == 0)
+ if(team_mate.deadflag == DEAD_NO)
+ if(team_mate.msnt_timer < time)
+ if(SAME_TEAM(self, team_mate))
+ if(time > team_mate.spawnshieldtime) // spawn shielding
+ if(team_mate.frozen == 0)
+ if(team_mate != self)
+ {
+ tracebox(team_mate.origin, PL_MIN, PL_MAX, team_mate.origin - '0 0 100', MOVE_WORLDONLY, team_mate);
+ if(trace_fraction != 1.0)
+ if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
+ {
+ pc = pointcontents(trace_endpos + '0 0 1');
+ if(pc == CONTENT_EMPTY)
+ {
+ if(vlen(team_mate.velocity) > 5)
+ fixedmakevectors(vectoangles(team_mate.velocity));
+ else
+ fixedmakevectors(team_mate.angles);
+
+ for(pc = 0; pc != 5; ++pc) // test 5 diffrent spots close to mate
+ {
+ switch(pc)
+ {
+ case 0:
+ tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin + v_right * 128, MOVE_NORMAL, team_mate);
+ break;
+ case 1:
+ tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_right * 128 , MOVE_NORMAL, team_mate);
+ break;
+ case 2:
+ tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin + v_right * 64 - v_forward * 64, MOVE_NORMAL, team_mate);
+ break;
+ case 3:
+ tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_right * 64 - v_forward * 64, MOVE_NORMAL, team_mate);
+ break;
+ case 4:
+ tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_forward * 128, MOVE_NORMAL, team_mate);
+ break;
+ }
+
+ if(trace_fraction == 1.0)
+ {
+ traceline(trace_endpos + '0 0 4', trace_endpos - '0 0 100', MOVE_NORMAL, team_mate);
+ if(trace_fraction != 1.0)
+ {
+ if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
+ {
+ dist = vlen(trace_endpos - self.msnt_deathloc);
+ if(dist < best_dist || best_dist == 0)
+ {
+ best_dist = dist;
+ best_spot = trace_endpos;
+ best_mate = team_mate;
+ }
+ }
+ else
+ {
+ setorigin(self, trace_endpos);
+ self.angles = team_mate.angles;
+ self.angles_z = 0; // never spawn tilted even if the spot says to
+ team_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
+ if(best_dist)
+ {
+ setorigin(self, best_spot);
+ self.angles = best_mate.angles;
+ self.angles_z = 0; // never spawn tilted even if the spot says to
+ best_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
+ }
+ }
+ else if(spawn_spot.msnt_lookat)
+ {
+ self.angles = vectoangles(spawn_spot.msnt_lookat.origin - self.origin);
+ self.angles_x = -self.angles.x;
+ self.angles_z = 0; // never spawn tilted even if the spot says to
+ /*
+ sprint(self, "You should be looking at ", spawn_spot.msnt_lookat.netname, "^7.\n");
+ sprint(self, "distance: ", vtos(spawn_spot.msnt_lookat.origin - self.origin), "\n");
+ sprint(self, "angles: ", vtos(self.angles), "\n");
+ */
+ }
+
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerDies)
+{SELFPARAM();
+ self.msnt_deathloc = self.origin;
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, GetCvars)
+{
+ GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_spawn_near_teammate, "cl_spawn_near_teammate");
+ return false;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "superspec.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(superspec, cvar("g_superspectate"));
+
+#define _SSMAGIX "SUPERSPEC_OPTIONSFILE_V1"
+#define _ISLOCAL ((edict_num(1) == self) ? true : false)
+
+const float ASF_STRENGTH = BIT(0);
+const float ASF_SHIELD = BIT(1);
+const float ASF_MEGA_AR = BIT(2);
+const float ASF_MEGA_HP = BIT(3);
+const float ASF_FLAG_GRAB = BIT(4);
+const float ASF_OBSERVER_ONLY = BIT(5);
+const float ASF_SHOWWHAT = BIT(6);
+const float ASF_SSIM = BIT(7);
+const float ASF_FOLLOWKILLER = BIT(8);
+const float ASF_ALL = 0xFFFFFF;
+.float autospec_flags;
+
+const float SSF_SILENT = 1;
+const float SSF_VERBOSE = 2;
+const float SSF_ITEMMSG = 4;
+.float superspec_flags;
+
+.string superspec_itemfilter; //"classname1 classname2 ..."
+
+bool superspec_Spectate(entity _player)
+{SELFPARAM();
+ if(Spectate(_player) == 1)
+ self.classname = STR_SPECTATOR;
+
+ return true;
+}
+
+void superspec_save_client_conf()
+{SELFPARAM();
+ string fn = "superspec-local.options";
+ float fh;
+
+ if (!_ISLOCAL)
+ {
+ if(self.crypto_idfp == "")
+ return;
+
+ fn = sprintf("superspec-%s.options", uri_escape(self.crypto_idfp));
+ }
+
+ fh = fopen(fn, FILE_WRITE);
+ if(fh < 0)
+ {
+ LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for writing.\n");
+ }
+ else
+ {
+ fputs(fh, _SSMAGIX);
+ fputs(fh, "\n");
+ fputs(fh, ftos(self.autospec_flags));
+ fputs(fh, "\n");
+ fputs(fh, ftos(self.superspec_flags));
+ fputs(fh, "\n");
+ fputs(fh, self.superspec_itemfilter);
+ fputs(fh, "\n");
+ fclose(fh);
+ }
+}
+
+void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel)
+{
+ sprint(_to, strcat(_con_title, _msg));
+
+ if(_to.superspec_flags & SSF_SILENT)
+ return;
+
+ if(_spamlevel > 1)
+ if (!(_to.superspec_flags & SSF_VERBOSE))
+ return;
+
+ centerprint(_to, strcat(_center_title, _msg));
+}
+
+float superspec_filteritem(entity _for, entity _item)
+{
+ float i;
+
+ if(_for.superspec_itemfilter == "")
+ return true;
+
+ if(_for.superspec_itemfilter == "")
+ return true;
+
+ float l = tokenize_console(_for.superspec_itemfilter);
+ for(i = 0; i < l; ++i)
+ {
+ if(argv(i) == _item.classname)
+ return true;
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, ItemTouch)
+{SELFPARAM();
+ entity _item = self;
+
+ entity e;
+ FOR_EACH_CLIENT(e) if (IS_SPEC(e) || IS_OBSERVER(e))
+ {
+ setself(e);
+ if(self.superspec_flags & SSF_ITEMMSG)
+ if(superspec_filteritem(self, _item))
+ {
+ if(self.superspec_flags & SSF_VERBOSE)
+ superspec_msg("", "", self, sprintf("Player %s^7 just picked up ^3%s\n", other.netname, _item.netname), 1);
+ else
+ superspec_msg("", "", self, sprintf("Player %s^7 just picked up ^3%s\n^8(%s^8)\n", other.netname, _item.netname, _item.classname), 1);
+ if((self.autospec_flags & ASF_SSIM) && self.enemy != other)
+ {
+ superspec_Spectate(other);
+
+ setself(this);
+ return MUT_ITEMTOUCH_CONTINUE;
+ }
+ }
+
+ if((self.autospec_flags & ASF_SHIELD && _item.invincible_finished) ||
+ (self.autospec_flags & ASF_STRENGTH && _item.strength_finished) ||
+ (self.autospec_flags & ASF_MEGA_AR && _item.itemdef == ITEM_ArmorMega) ||
+ (self.autospec_flags & ASF_MEGA_HP && _item.itemdef == ITEM_HealthMega) ||
+ (self.autospec_flags & ASF_FLAG_GRAB && _item.classname == "item_flag_team"))
+ {
+
+ if((self.enemy != other) || IS_OBSERVER(self))
+ {
+ if(self.autospec_flags & ASF_OBSERVER_ONLY && !IS_OBSERVER(self))
+ {
+ if(self.superspec_flags & SSF_VERBOSE)
+ superspec_msg("", "", self, sprintf("^8Ignored that ^7%s^8 grabbed %s^8 since the observer_only option is ON\n", other.netname, _item.netname), 2);
+ }
+ else
+ {
+ if(self.autospec_flags & ASF_SHOWWHAT)
+ superspec_msg("", "", self, sprintf("^7Following %s^7 due to picking up %s\n", other.netname, _item.netname), 2);
+
+ superspec_Spectate(other);
+ }
+ }
+ }
+ }
+
+ setself(this);
+
+ return MUT_ITEMTOUCH_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, SV_ParseClientCommand)
+{SELFPARAM();
+#define OPTIONINFO(flag,var,test,text,long,short) \
+ var = strcat(var, ((flag & test) ? "^2[ON] ^7" : "^1[OFF] ^7")); \
+ var = strcat(var, text," ^7(^3 ", long, "^7 | ^3", short, " ^7)\n")
+
+ if(MUTATOR_RETURNVALUE) // command was already handled?
+ return false;
+
+ if(IS_PLAYER(self))
+ return false;
+
+ if(cmd_name == "superspec_itemfilter")
+ {
+ if(argv(1) == "help")
+ {
+ string _aspeco;
+ _aspeco = "^7 superspec_itemfilter ^3\"item_classname1 item_classname2\"^7 only show thise items when ^2superspec ^3item_message^7 is on\n";
+ _aspeco = strcat(_aspeco, "^3 clear^7 Remove the filter (show all pickups)\n");
+ _aspeco = strcat(_aspeco, "^3 show ^7 Display current filter\n");
+ superspec_msg("^3superspec_itemfilter help:\n\n\n", "\n^3superspec_itemfilter help:\n", self, _aspeco, 1);
+ }
+ else if(argv(1) == "clear")
+ {
+ if(self.superspec_itemfilter != "")
+ strunzone(self.superspec_itemfilter);
+
+ self.superspec_itemfilter = "";
+ }
+ else if(argv(1) == "show" || argv(1) == "")
+ {
+ if(self.superspec_itemfilter == "")
+ {
+ superspec_msg("^3superspec_itemfilter^7 is ^1not^7 set", "\n^3superspec_itemfilter^7 is ^1not^7 set\n", self, "", 1);
+ return true;
+ }
+ float i;
+ float l = tokenize_console(self.superspec_itemfilter);
+ string _msg = "";
+ for(i = 0; i < l; ++i)
+ _msg = strcat(_msg, "^3#", ftos(i), " ^7", argv(i), "\n");
+ //_msg = sprintf("^3#%d^7 %s\n%s", i, _msg, argv(i));
+
+ _msg = strcat(_msg,"\n");
+
+ superspec_msg("^3superspec_itemfilter is:\n\n\n", "\n^3superspec_itemfilter is:\n", self, _msg, 1);
+ }
+ else
+ {
+ if(self.superspec_itemfilter != "")
+ strunzone(self.superspec_itemfilter);
+
+ self.superspec_itemfilter = strzone(argv(1));
+ }
+
+ return true;
+ }
+
+ if(cmd_name == "superspec")
+ {
+ string _aspeco;
+
+ if(cmd_argc > 1)
+ {
+ float i, _bits = 0, _start = 1;
+ if(argv(1) == "help")
+ {
+ _aspeco = "use cmd superspec [option] [on|off] to set options\n\n";
+ _aspeco = strcat(_aspeco, "^3 silent ^7(short^5 si^7) supresses ALL messages from superspectate.\n");
+ _aspeco = strcat(_aspeco, "^3 verbose ^7(short^5 ve^7) makes superspectate print some additional information.\n");
+ _aspeco = strcat(_aspeco, "^3 item_message ^7(short^5 im^7) makes superspectate print items that were picked up.\n");
+ _aspeco = strcat(_aspeco, "^7 Use cmd superspec_itemfilter \"item_class1 item_class2\" to set up a filter of what to show with ^3item_message.\n");
+ superspec_msg("^2Available Super Spectate ^3options:\n\n\n", "\n^2Available Super Spectate ^3options:\n", self, _aspeco, 1);
+ return true;
+ }
+
+ if(argv(1) == "clear")
+ {
+ self.superspec_flags = 0;
+ _start = 2;
+ }
+
+ for(i = _start; i < cmd_argc; ++i)
+ {
+ if(argv(i) == "on" || argv(i) == "1")
+ {
+ self.superspec_flags |= _bits;
+ _bits = 0;
+ }
+ else if(argv(i) == "off" || argv(i) == "0")
+ {
+ if(_start == 1)
+ self.superspec_flags &= ~_bits;
+
+ _bits = 0;
+ }
+ else
+ {
+ if((argv(i) == "silent") || (argv(i) == "si")) _bits |= SSF_SILENT ;
+ if((argv(i) == "verbose") || (argv(i) == "ve")) _bits |= SSF_VERBOSE;
+ if((argv(i) == "item_message") || (argv(i) == "im")) _bits |= SSF_ITEMMSG;
+ }
+ }
+ }
+
+ _aspeco = "";
+ OPTIONINFO(self.superspec_flags, _aspeco, SSF_SILENT, "Silent", "silent", "si");
+ OPTIONINFO(self.superspec_flags, _aspeco, SSF_VERBOSE, "Verbose", "verbose", "ve");
+ OPTIONINFO(self.superspec_flags, _aspeco, SSF_ITEMMSG, "Item pickup messages", "item_message", "im");
+
+ superspec_msg("^3Current Super Spectate options are:\n\n\n\n\n", "\n^3Current Super Spectate options are:\n", self, _aspeco, 1);
+
+ return true;
+ }
+
+/////////////////////
+
+ if(cmd_name == "autospec")
+ {
+ string _aspeco;
+ if(cmd_argc > 1)
+ {
+ if(argv(1) == "help")
+ {
+ _aspeco = "use cmd autospec [option] [on|off] to set options\n\n";
+ _aspeco = strcat(_aspeco, "^3 strength ^7(short^5 st^7) for automatic spectate on strength powerup\n");
+ _aspeco = strcat(_aspeco, "^3 shield ^7(short^5 sh^7) for automatic spectate on shield powerup\n");
+ _aspeco = strcat(_aspeco, "^3 mega_health ^7(short^5 mh^7) for automatic spectate on mega health\n");
+ _aspeco = strcat(_aspeco, "^3 mega_armor ^7(short^5 ma^7) for automatic spectate on mega armor\n");
+ _aspeco = strcat(_aspeco, "^3 flag_grab ^7(short^5 fg^7) for automatic spectate on CTF flag grab\n");
+ _aspeco = strcat(_aspeco, "^3 observer_only ^7(short^5 oo^7) for automatic spectate only if in observer mode\n");
+ _aspeco = strcat(_aspeco, "^3 show_what ^7(short^5 sw^7) to display what event triggered autospectate\n");
+ _aspeco = strcat(_aspeco, "^3 item_msg ^7(short^5 im^7) to autospec when item_message in superspectate is triggered\n");
+ _aspeco = strcat(_aspeco, "^3 followkiller ^7(short ^5fk^7) to autospec the killer/off\n");
+ _aspeco = strcat(_aspeco, "^3 all ^7(short ^5aa^7) to turn everything on/off\n");
+ superspec_msg("^2Available Auto Spectate ^3options:\n\n\n", "\n^2Available Auto Spectate ^3options:\n", self, _aspeco, 1);
+ return true;
+ }
+
+ float i, _bits = 0, _start = 1;
+ if(argv(1) == "clear")
+ {
+ self.autospec_flags = 0;
+ _start = 2;
+ }
+
+ for(i = _start; i < cmd_argc; ++i)
+ {
+ if(argv(i) == "on" || argv(i) == "1")
+ {
+ self.autospec_flags |= _bits;
+ _bits = 0;
+ }
+ else if(argv(i) == "off" || argv(i) == "0")
+ {
+ if(_start == 1)
+ self.autospec_flags &= ~_bits;
+
+ _bits = 0;
+ }
+ else
+ {
+ if((argv(i) == "strength") || (argv(i) == "st")) _bits |= ASF_STRENGTH;
+ if((argv(i) == "shield") || (argv(i) == "sh")) _bits |= ASF_SHIELD;
+ if((argv(i) == "mega_health") || (argv(i) == "mh")) _bits |= ASF_MEGA_HP;
+ if((argv(i) == "mega_armor") || (argv(i) == "ma")) _bits |= ASF_MEGA_AR;
+ if((argv(i) == "flag_grab") || (argv(i) == "fg")) _bits |= ASF_FLAG_GRAB;
+ if((argv(i) == "observer_only") || (argv(i) == "oo")) _bits |= ASF_OBSERVER_ONLY;
+ if((argv(i) == "show_what") || (argv(i) == "sw")) _bits |= ASF_SHOWWHAT;
+ if((argv(i) == "item_msg") || (argv(i) == "im")) _bits |= ASF_SSIM;
+ if((argv(i) == "followkiller") || (argv(i) == "fk")) _bits |= ASF_FOLLOWKILLER;
+ if((argv(i) == "all") || (argv(i) == "aa")) _bits |= ASF_ALL;
+ }
+ }
+ }
+
+ _aspeco = "";
+ OPTIONINFO(self.autospec_flags, _aspeco, ASF_STRENGTH, "Strength", "strength", "st");
+ OPTIONINFO(self.autospec_flags, _aspeco, ASF_SHIELD, "Shield", "shield", "sh");
+ OPTIONINFO(self.autospec_flags, _aspeco, ASF_MEGA_HP, "Mega Health", "mega_health", "mh");
+ OPTIONINFO(self.autospec_flags, _aspeco, ASF_MEGA_AR, "Mega Armor", "mega_armor", "ma");
+ OPTIONINFO(self.autospec_flags, _aspeco, ASF_FLAG_GRAB, "Flag grab", "flag_grab","fg");
+ OPTIONINFO(self.autospec_flags, _aspeco, ASF_OBSERVER_ONLY, "Only switch if observer", "observer_only", "oo");
+ OPTIONINFO(self.autospec_flags, _aspeco, ASF_SHOWWHAT, "Show what item triggered spectate", "show_what", "sw");
+ OPTIONINFO(self.autospec_flags, _aspeco, ASF_SSIM, "Switch on superspec item message", "item_msg", "im");
+ OPTIONINFO(self.autospec_flags, _aspeco, ASF_FOLLOWKILLER, "Followkiller", "followkiller", "fk");
+
+ superspec_msg("^3Current auto spectate options are:\n\n\n\n\n", "\n^3Current auto spectate options are:\n", self, _aspeco, 1);
+ return true;
+ }
+
+ if(cmd_name == "followpowerup")
+ {
+ entity _player;
+ FOR_EACH_PLAYER(_player)
+ {
+ if(_player.strength_finished > time || _player.invincible_finished > time)
+ return superspec_Spectate(_player);
+ }
+
+ superspec_msg("", "", self, "No active powerup\n", 1);
+ return true;
+ }
+
+ if(cmd_name == "followstrength")
+ {
+ entity _player;
+ FOR_EACH_PLAYER(_player)
+ {
+ if(_player.strength_finished > time)
+ return superspec_Spectate(_player);
+ }
+
+ superspec_msg("", "", self, "No active Strength\n", 1);
+ return true;
+ }
+
+ if(cmd_name == "followshield")
+ {
+ entity _player;
+ FOR_EACH_PLAYER(_player)
+ {
+ if(_player.invincible_finished > time)
+ return superspec_Spectate(_player);
+ }
+
+ superspec_msg("", "", self, "No active Shield\n", 1);
+ return true;
+ }
+
+ return false;
+#undef OPTIONINFO
+}
+
+MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":SS");
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Super Spectators");
+ return 0;
+}
+
+void superspec_hello()
+{SELFPARAM();
+ if(self.enemy.crypto_idfp == "")
+ Send_Notification(NOTIF_ONE_ONLY, self.enemy, MSG_INFO, INFO_SUPERSPEC_MISSING_UID);
+
+ remove(self);
+}
+
+MUTATOR_HOOKFUNCTION(superspec, ClientConnect)
+{SELFPARAM();
+ if(!IS_REAL_CLIENT(self))
+ return false;
+
+ string fn = "superspec-local.options";
+ float fh;
+
+ self.superspec_flags = SSF_VERBOSE;
+ self.superspec_itemfilter = "";
+
+ entity _hello = spawn();
+ _hello.enemy = self;
+ _hello.think = superspec_hello;
+ _hello.nextthink = time + 5;
+
+ if (!_ISLOCAL)
+ {
+ if(self.crypto_idfp == "")
+ return false;
+
+ fn = sprintf("superspec-%s.options", uri_escape(self.crypto_idfp));
+ }
+
+ fh = fopen(fn, FILE_READ);
+ if(fh < 0)
+ {
+ LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for reading.\n");
+ }
+ else
+ {
+ string _magic = fgets(fh);
+ if(_magic != _SSMAGIX)
+ {
+ LOG_TRACE("^1ERROR^7 While reading superspec options file: unknown magic\n");
+ }
+ else
+ {
+ self.autospec_flags = stof(fgets(fh));
+ self.superspec_flags = stof(fgets(fh));
+ self.superspec_itemfilter = strzone(fgets(fh));
+ }
+ fclose(fh);
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, PlayerDies)
+{SELFPARAM();
+ entity e;
+ FOR_EACH_SPEC(e)
+ {
+ setself(e);
+ if(self.autospec_flags & ASF_FOLLOWKILLER && IS_PLAYER(frag_attacker) && self.enemy == this)
+ {
+ if(self.autospec_flags & ASF_SHOWWHAT)
+ superspec_msg("", "", self, sprintf("^7Following %s^7 due to followkiller\n", frag_attacker.netname), 2);
+
+ superspec_Spectate(frag_attacker);
+ }
+ }
+
+ setself(this);
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, ClientDisconnect)
+{
+ superspec_save_client_conf();
+ return false;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "touchexplode.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+float autocvar_g_touchexplode_radius;
+float autocvar_g_touchexplode_damage;
+float autocvar_g_touchexplode_edgedamage;
+float autocvar_g_touchexplode_force;
+
+REGISTER_MUTATOR(touchexplode, cvar("g_touchexplode"));
+
+.float touchexplode_time;
+
+void PlayerTouchExplode(entity p1, entity p2)
+{SELFPARAM();
+ vector org = (p1.origin + p2.origin) * 0.5;
+ org.z += (p1.mins.z + p2.mins.z) * 0.5;
+
+ sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
+ Send_Effect(EFFECT_EXPLOSION_SMALL, org, '0 0 0', 1);
+
+ entity e = spawn();
+ setorigin(e, org);
+ RadiusDamage(e, world, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, world, world, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE.m_id, world);
+ remove(e);
+}
+
+MUTATOR_HOOKFUNCTION(touchexplode, PlayerPreThink)
+{SELFPARAM();
+ if(time > self.touchexplode_time)
+ if(!gameover)
+ if(!self.frozen)
+ if(IS_PLAYER(self))
+ if(self.deadflag == DEAD_NO)
+ if (!IS_INDEPENDENT_PLAYER(self))
+ FOR_EACH_PLAYER(other) if(self != other)
+ {
+ if(time > other.touchexplode_time)
+ if(!other.frozen)
+ if(other.deadflag == DEAD_NO)
+ if (!IS_INDEPENDENT_PLAYER(other))
+ if(boxesoverlap(self.absmin, self.absmax, other.absmin, other.absmax))
+ {
+ PlayerTouchExplode(self, other);
+ self.touchexplode_time = other.touchexplode_time = time + 0.2;
+ }
+ }
+
+ return false;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "vampire.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(vampire, cvar("g_vampire") && !cvar("g_instagib"));
+
+MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
+{
+ if(time >= frag_target.spawnshieldtime)
+ if(frag_target != frag_attacker)
+ if(frag_target.deadflag == DEAD_NO)
+ {
+ frag_attacker.health += bound(0, damage_take, frag_target.health);
+ frag_attacker.health = bound(0, frag_attacker.health, autocvar_g_balance_health_limit);
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":Vampire");
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Vampire");
+ return 0;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+#include "vampirehook.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(vh, cvar("g_vampirehook"));
+
+bool autocvar_g_vampirehook_teamheal;
+float autocvar_g_vampirehook_damage;
+float autocvar_g_vampirehook_damagerate;
+float autocvar_g_vampirehook_health_steal;
+
+.float last_dmg;
+
+MUTATOR_HOOKFUNCTION(vh, GrappleHookThink)
+{SELFPARAM();
+ entity dmgent = ((SAME_TEAM(self.owner, self.aiment) && autocvar_g_vampirehook_teamheal) ? self.owner : self.aiment);
+
+ if(IS_PLAYER(self.aiment))
+ if(self.last_dmg < time)
+ if(!self.aiment.frozen)
+ if(time >= game_starttime)
+ if(DIFF_TEAM(self.owner, self.aiment) || autocvar_g_vampirehook_teamheal)
+ if(self.aiment.health > 0)
+ if(autocvar_g_vampirehook_damage)
+ {
+ self.last_dmg = time + autocvar_g_vampirehook_damagerate;
+ self.owner.damage_dealt += autocvar_g_vampirehook_damage;
+ Damage(dmgent, self, self.owner, autocvar_g_vampirehook_damage, WEP_HOOK.m_id, self.origin, '0 0 0');
+ if(SAME_TEAM(self.owner, self.aiment))
+ self.aiment.health = min(self.aiment.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
+ else
+ self.owner.health = min(self.owner.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
+
+ if(dmgent == self.owner)
+ dmgent.health -= autocvar_g_vampirehook_damage; // FIXME: friendly fire?!
+ }
+
+ return false;
+}
+
+#endif
REGISTER_WAYPOINT(OnsGen, _("Generator"), '1 0.5 0', 1);
REGISTER_WAYPOINT(OnsGenShielded, _("Generator"), '1 0.5 0', 1);
-REGISTER_WAYPOINT(Buff, _("Buff"), '1 0.5 0', 1);
-
REGISTER_WAYPOINT(Weapon, _("Weapon"), '0 0 0', 1);
REGISTER_WAYPOINT(Monster, _("Monster"), '1 0 0', 1);
#include "waypointsprites.qh"
-REGISTRY(Waypoints, BIT(6))
-REGISTER_REGISTRY(RegisterWaypoints)
+REGISTRY(Waypoints, BITS(6))
+#define Waypoints_from(i) _Waypoints_from(i, WP_Null)
+REGISTER_REGISTRY(Waypoints)
+REGISTRY_CHECK(Waypoints)
+
/** If you register a new waypoint, make sure to add it to all.inc */
-#define REGISTER_WAYPOINT_(id, init) REGISTER(RegisterWaypoints, WP, Waypoints, id, m_id, init)
+#define REGISTER_WAYPOINT_(id, init) REGISTER(Waypoints, WP, id, m_id, init)
CLASS(Waypoint, Object)
ATTRIB(Waypoint, m_id, int, 0)
#define REGISTER_WAYPOINT(id, text, color, blink) REGISTER_WAYPOINT_(id, NEW(Waypoint, #id, text, color, blink))
REGISTRY(RadarIcons, BITS(7))
-REGISTER_REGISTRY(RegisterRadarIcons)
+#define RadarIcons_from(i) _RadarIcons_from(i, RADARICON_NONE)
+REGISTER_REGISTRY(RadarIcons)
+REGISTRY_CHECK(RadarIcons)
+
.int m_radaricon;
-#define REGISTER_RADARICON(id, num) REGISTER(RegisterRadarIcons, RADARICON, RadarIcons, id, m_id, new(RadarIcon)) { this.m_radaricon = num; this.netname = #id; }
+#define REGISTER_RADARICON(id, num) REGISTER(RadarIcons, RADARICON, id, m_id, new(RadarIcon)) { make_pure(this); this.m_radaricon = num; this.netname = #id; }
REGISTER_WAYPOINT(Null, "", '0 0 0', 1);
REGISTER_RADARICON(DOMPOINT, 1);
REGISTER_RADARICON(TAGGED, 1);
-REGISTER_RADARICON(Buff, 1);
REGISTER_RADARICON(Item, 1);
REGISTER_RADARICON(Vehicle, 1);
REGISTER_RADARICON(Weapon, 1);
--- /dev/null
+#include "waypointsprites.qc"
REGISTER_MUTATOR(waypointsprites, true);
+REGISTER_NET_LINKED(waypointsprites)
+
#ifdef SVQC
/** flags origin [team displayrule] [spritename] [spritename2] [spritename3] [lifetime maxdistance hideable] */
bool WaypointSprite_SendEntity(entity this, entity to, float sendflags)
{
- WriteMutator(MSG_ENTITY, waypointsprites);
+ WriteHeader(MSG_ENTITY, waypointsprites);
sendflags = sendflags & 0x7F;
#ifdef CSQC
void Ent_WaypointSprite();
-MUTATOR_HOOKFUNCTION(waypointsprites, CSQC_Ent_Update) {
- if (MUTATOR_RETURNVALUE) return false;
- if (!ReadMutatorEquals(mutator_argv_int_0, waypointsprites)) return false;
+NET_HANDLE(waypointsprites, bool isnew) {
Ent_WaypointSprite();
return true;
}
if (get_weaponinfo(self.wp_extra).spawnflags & WEP_FLAG_SUPERWEAPON)
return 2;
}
- if (s == WP_Item.netname) return Items[self.wp_extra].m_waypointblink;
+ if (s == WP_Item.netname) return Items_from(self.wp_extra).m_waypointblink;
return 1;
}
vector spritelookupcolor(entity this, string s, vector def)
{
if (s == WP_Weapon.netname || s == RADARICON_Weapon.netname) return get_weaponinfo(this.wp_extra).wpcolor;
- if (s == WP_Item.netname || s == RADARICON_Item.netname) return Items[this.wp_extra].m_color;
- if (s == WP_Buff.netname || s == RADARICON_Buff.netname) return Buffs[this.wp_extra].m_color;
+ if (s == WP_Item.netname || s == RADARICON_Item.netname) return Items_from(this.wp_extra).m_color;
+ if (MUTATOR_CALLHOOK(WP_Format, this, s))
+ {
+ return MUTATOR_ARGV(0, vector);
+ }
return def;
}
string spritelookuptext(string s)
{SELFPARAM();
if (s == WP_RaceStartFinish.netname) return (race_checkpointtime || race_mycheckpointtime) ? _("Finish") : _("Start");
- if (s == WP_Weapon.netname) return get_weaponinfo(self.wp_extra).message;
- if (s == WP_Item.netname) return Items[self.wp_extra].m_waypoint;
- if (s == WP_Buff.netname) return Buffs[self.wp_extra].m_prettyName;
+ if (s == WP_Weapon.netname) return get_weaponinfo(self.wp_extra).m_name;
+ if (s == WP_Item.netname) return Items_from(self.wp_extra).m_waypoint;
if (s == WP_Monster.netname) return get_monsterinfo(self.wp_extra).monster_name;
+ if (MUTATOR_CALLHOOK(WP_Format, this, s))
+ {
+ return MUTATOR_ARGV(0, string);
+ }
// need to loop, as our netname could be one of three
FOREACH(Waypoints, it.netname == s, LAMBDA(
if (fabs(sa) > fabs(ca))
{
algnx = (sa < 0);
- algny = 0.5 - 0.5 * ca / fabs(sa);
+ float f = fabs(sa);
+ algny = 0.5 - 0.5 * (f ? (ca / f) : 0);
}
else
{
- algnx = 0.5 - 0.5 * sa / fabs(ca);
+ float f = fabs(ca);
+ algnx = 0.5 - 0.5 * (f ? (sa / f) : 0);
algny = (ca < 0);
}
)
{
entity wp = new(sprite_waypoint);
+ make_pure(wp);
wp.teleport_time = time + _lifetime;
wp.fade_time = _lifetime;
wp.exteriormodeltoclient = ref;
--- /dev/null
+#ifdef SVQC
+#include "weaponarena_random.qc"
+#endif
--- /dev/null
+#ifdef IMPLEMENTATION
+// WEAPONTODO: rename the cvars
+REGISTER_MUTATOR(weaponarena_random, true);
+
+MUTATOR_HOOKFUNCTION(weaponarena_random, PlayerSpawn) {
+ SELFPARAM();
+ if (!g_weaponarena_random) return;
+ if (g_weaponarena_random_with_blaster) this.weapons &= ~WEPSET(BLASTER);
+ W_RandomWeapons(this, g_weaponarena_random);
+ if (g_weaponarena_random_with_blaster) this.weapons |= WEPSET(BLASTER);
+}
+
+#endif
+++ /dev/null
-#define NADE_PROJECTILE(i, projectile, trail) do { \
- this.m_projectile[i] = projectile; \
- this.m_trail[i] = trail; \
-} while (0)
-
-REGISTER_NADE(NORMAL) {
- this.m_color = '1 1 1';
- NADE_PROJECTILE(0, PROJECTILE_NADE, EFFECT_Null);
- NADE_PROJECTILE(1, PROJECTILE_NADE_BURN, EFFECT_Null);
-}
-
-REGISTER_NADE(NAPALM) {
- this.m_color = '2 0.5 0';
- this.m_name = _("Napalm grenade");
- this.m_icon = "nade_napalm";
- NADE_PROJECTILE(0, PROJECTILE_NADE_NAPALM, EFFECT_TR_ROCKET);
- NADE_PROJECTILE(1, PROJECTILE_NADE_NAPALM_BURN, EFFECT_SPIDERBOT_ROCKET_TRAIL);
-}
-
-REGISTER_NADE(ICE) {
- this.m_color = '0 0.5 2';
- this.m_name = _("Ice grenade");
- this.m_icon = "nade_ice";
- NADE_PROJECTILE(0, PROJECTILE_NADE_ICE, EFFECT_TR_NEXUIZPLASMA);
- NADE_PROJECTILE(1, PROJECTILE_NADE_ICE_BURN, EFFECT_RACER_ROCKET_TRAIL);
-}
-
-REGISTER_NADE(TRANSLOCATE) {
- this.m_color = '1 0 1';
- this.m_name = _("Translocate grenade");
- this.m_icon = "nade_translocate";
- NADE_PROJECTILE(0, PROJECTILE_NADE_TRANSLOCATE, EFFECT_TR_CRYLINKPLASMA);
- NADE_PROJECTILE(1, PROJECTILE_NADE_TRANSLOCATE, EFFECT_TR_CRYLINKPLASMA);
-}
-
-REGISTER_NADE(SPAWN) {
- this.m_color = '1 0.9 0';
- this.m_name = _("Spawn grenade");
- this.m_icon = "nade_spawn";
- NADE_PROJECTILE(0, PROJECTILE_NADE_SPAWN, EFFECT_NADE_TRAIL_YELLOW);
- NADE_PROJECTILE(1, PROJECTILE_NADE_SPAWN, EFFECT_NADE_TRAIL_YELLOW);
-}
-
-REGISTER_NADE(HEAL) {
- this.m_color = '1 0 0';
- this.m_name = _("Heal grenade");
- this.m_icon = "nade_heal";
- NADE_PROJECTILE(0, PROJECTILE_NADE_HEAL, EFFECT_NADE_TRAIL_RED);
- NADE_PROJECTILE(1, PROJECTILE_NADE_HEAL_BURN, EFFECT_NADE_TRAIL_BURN_RED);
-}
-
-REGISTER_NADE(MONSTER) {
- this.m_color = '0.25 0.75 0';
- this.m_name = _("Monster grenade");
- this.m_icon = "nade_monster";
- NADE_PROJECTILE(0, PROJECTILE_NADE_MONSTER, EFFECT_NADE_TRAIL_RED);
- NADE_PROJECTILE(1, PROJECTILE_NADE_MONSTER_BURN, EFFECT_NADE_TRAIL_BURN_RED);
-}
+++ /dev/null
-#if defined(CSQC)
- #include "../../client/defs.qh"
- #include "all.qh"
- #include "../buffs/all.qh"
- #include "../movetypes/movetypes.qh"
- #include "../../client/main.qh"
- #include "../../lib/csqcmodel/cl_model.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../constants.qh"
- #include "../../server/constants.qh"
- #include "../turrets/sv_turrets.qh"
-#endif
-
-
-#ifdef CSQC
-.float ltime;
-void healer_draw(entity this)
-{
- float dt = time - self.move_time;
- self.move_time = time;
- if(dt <= 0)
- return;
-
- self.alpha = (self.ltime - time) / self.healer_lifetime;
- self.scale = min((1 - self.alpha)*self.healer_lifetime*4,1)*self.healer_radius;
-}
-
-void healer_setup(entity e)
-{
- setmodel(e, MDL_NADE_HEAL);
-
- setorigin(e, e.origin);
-
- float model_radius = e.maxs.x;
- vector size = '1 1 1' * e.healer_radius / 2;
- setsize(e,-size,size);
- e.healer_radius = e.healer_radius/model_radius*0.6;
-
- e.draw = healer_draw;
- e.health = 255;
- e.movetype = MOVETYPE_NONE;
- e.solid = SOLID_NOT;
- e.drawmask = MASK_NORMAL;
- e.scale = 0.01;
- e.avelocity = e.move_avelocity = '7 0 11';
- e.colormod = '1 0 0';
- e.renderflags |= RF_ADDITIVE;
-}
-#endif // CSQC
-
-REGISTER_NET_LINKED(Nade_Heal, bool isNew)
-#ifdef CSQC
-{
- Net_Accept();
- int sf = ReadByte();
- if (sf & 1) {
- this.origin_x = ReadCoord();
- this.origin_y = ReadCoord();
- this.origin_z = ReadCoord();
- setorigin(this, this.origin);
- this.healer_lifetime = ReadByte();
- this.healer_radius = ReadShort();
- this.ltime = time + ReadByte()/10.0;
- // this.ltime = time + this.healer_lifetime;
- healer_setup(this);
- }
-}
-#endif
-
-#ifdef SVQC
-bool healer_send(entity this, entity to, int sf)
-{
- int channel = MSG_ENTITY;
- WriteHeader(channel, Nade_Heal);
- WriteByte(channel, sf);
- if (sf & 1) {
- WriteCoord(channel, this.origin.x);
- WriteCoord(channel, this.origin.y);
- WriteCoord(channel, this.origin.z);
-
- WriteByte(channel, this.healer_lifetime);
- //WriteByte(MSG_ENTITY, this.ltime - time + 1);
- WriteShort(channel, this.healer_radius);
- // round time delta to a 1/10th of a second
- WriteByte(channel, (this.ltime - time)*10.0+0.5);
- }
- return true;
-}
-#endif // SVQC
+++ /dev/null
-#ifndef NADES_ALL_H
-#define NADES_ALL_H
-
-#include "../teams.qh"
-
-.float healer_lifetime;
-.float healer_radius;
-
-// use slots 70-100
-const int PROJECTILE_NADE = 71;
-const int PROJECTILE_NADE_BURN = 72;
-const int PROJECTILE_NADE_NAPALM = 73;
-const int PROJECTILE_NADE_NAPALM_BURN = 74;
-const int PROJECTILE_NAPALM_FOUNTAIN = 75;
-const int PROJECTILE_NADE_ICE = 76;
-const int PROJECTILE_NADE_ICE_BURN = 77;
-const int PROJECTILE_NADE_TRANSLOCATE = 78;
-const int PROJECTILE_NADE_SPAWN = 79;
-const int PROJECTILE_NADE_HEAL = 80;
-const int PROJECTILE_NADE_HEAL_BURN = 81;
-const int PROJECTILE_NADE_MONSTER = 82;
-const int PROJECTILE_NADE_MONSTER_BURN = 83;
-
-REGISTRY(Nades, BIT(3))
-REGISTER_REGISTRY(RegisterNades)
-#define REGISTER_NADE(id) REGISTER(RegisterNades, NADE_TYPE, Nades, id, m_id, NEW(Nade))
-
-CLASS(Nade, Object)
- ATTRIB(Nade, m_id, int, 0)
- ATTRIB(Nade, m_color, vector, '0 0 0')
- ATTRIB(Nade, m_name, string, _("Grenade"))
- ATTRIB(Nade, m_icon, string, "nade_normal")
- ATTRIBARRAY(Nade, m_projectile, int, 2)
- ATTRIBARRAY(Nade, m_trail, entity, 2)
- METHOD(Nade, display, void(entity this, void(string name, string icon) returns)) {
- returns(this.m_name, sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.m_icon));
- }
-ENDCLASS(Nade)
-
-REGISTER_NADE(Null);
-
-#ifdef SVQC
-bool healer_send(entity this, entity to, int sf);
-#endif
-
-entity Nade_FromProjectile(float proj)
-{
- FOREACH(Nades, true, LAMBDA(
- for (int j = 0; j < 2; j++)
- {
- if (it.m_projectile[j] == proj) return it;
- }
- ));
- return NADE_TYPE_Null;
-}
-
-entity Nade_TrailEffect(int proj, int nade_team)
-{
- switch (proj)
- {
- case PROJECTILE_NADE: return EFFECT_NADE_TRAIL(nade_team);
- case PROJECTILE_NADE_BURN: return EFFECT_NADE_TRAIL_BURN(nade_team);
- }
-
- FOREACH(Nades, true, LAMBDA(
- for (int j = 0; j < 2; j++)
- {
- if (it.m_projectile[j] == proj)
- {
- string trail = it.m_trail[j].eent_eff_name;
- if (trail) return it.m_trail[j];
- break;
- }
- }
- ));
-
- return EFFECT_Null;
-}
-
-#include "all.inc"
-
-#endif
#include "net_notice.qh"
+REGISTER_NET_TEMP(TE_CSQC_SVNOTICE)
+
#ifdef SVQC
void sv_notice_join_think()
{SELFPARAM();
void sv_notice_to(entity _to, string _notice, float _howlong, float _modal)
{
msg_entity = _to;
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_SVNOTICE);
+ WriteHeader(MSG_ONE, TE_CSQC_SVNOTICE);
WriteString(MSG_ONE, _notice);
WriteLong(MSG_ONE, _howlong);
WriteByte(MSG_ONE, _modal);
#endif // SVQC
#ifdef CSQC
+NET_HANDLE(TE_CSQC_SVNOTICE, bool isNew)
+{
+ cl_notice_read();
+ return true;
+}
void cl_notice_read()
{
- entity _notice;
//float _done;
//float _modal;
- _notice = spawn();
- _notice.classname = "sv_notice";
+ entity _notice = new(sv_notice);
_notice.netname = strzone(ReadString());
_notice.alpha = ReadLong() + time;
_notice.skin = ReadByte();
_notes = findchain(classname, "sv_notice");
if(!_notes)
return false;
- #define M1 30
- #define M2 10
+ const int M1 = 30;
+ const int M2 = 10;
vector v1, v2 = '0 0 0', v3;
v1 = '1 1 0' * M1;
}
#undef OUT
- #undef M1
- #undef M2
return m;
}
#if defined(CSQC)
+ #include "../client/announcer.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
#include "constants.qh"
remove(notif);
}
-void Destroy_All_Notifications(void)
+void Destroy_All_Notifications()
{
entity notif;
int i;
// Global Entity Setup
// =====================
entity notif = spawn();
+ make_pure(notif);
switch(typeId)
{
case MSG_ANNCE:
{
if(notif.nent_enabled)
{
- precache_sound(sprintf("announcer/%s/%s.wav", autocvar_cl_announcer, snd));
+ precache_sound(sprintf("announcer/%s/%s.wav", AnnouncerOption(), snd));
notif.nent_channel = channel;
notif.nent_snd = strzone(snd);
notif.nent_vol = vol;
// used by MSG_CHOICE to build list of choices
#ifdef SVQC
-void Notification_GetCvars(void)
+void Notification_GetCvars()
{
for(int i = 0; i <= NOTIF_CHOICE_COUNT; ++i)
{
soundchannel,
sprintf(
"announcer/%s/%s.wav",
- autocvar_cl_announcer,
+ AnnouncerOption(),
soundfile
),
soundvolume,
soundchannel,
sprintf(
"announcer/%s/%s.wav",
- autocvar_cl_announcer,
+ AnnouncerOption(),
soundfile
),
soundvolume,
soundchannel,
sprintf(
"announcer/%s/%s.wav",
- autocvar_cl_announcer,
+ AnnouncerOption(),
soundfile
),
soundvolume,
// Notification Networking
// =========================
+REGISTER_NET_LINKED(ENT_CLIENT_NOTIFICATION)
+
#ifdef CSQC
-void Read_Notification(float is_new)
+NET_HANDLE(ENT_CLIENT_NOTIFICATION, bool is_new)
{
int net_type = ReadByte();
int net_name = ReadShort();
+ return = true;
entity notif;
{
if(Notification_ShouldSend(self.nent_broadcast, client, self.nent_client))
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_NOTIFICATION);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_NOTIFICATION);
WriteByte(MSG_ENTITY, self.nent_net_type);
WriteShort(MSG_ENTITY, self.nent_net_name);
for(int i = 0; i < self.nent_stringcount; ++i) { WriteString(MSG_ENTITY, self.nent_strings[i]); }
if(killed_cpid != NO_CPID)
{
- net_notif = spawn();
- net_notif.classname = "net_kill_notification";
+ net_notif = new(net_kill_notification);
+ make_pure(net_notif);
net_notif.nent_broadcast = broadcast;
net_notif.nent_client = client;
net_notif.nent_net_type = MSG_CENTER_CPID;
}
else
{
- entity net_notif = spawn();
+ entity net_notif = new(net_notification);
+ make_pure(net_notif);
net_notif.owner = notif;
- net_notif.classname = "net_notification";
net_notif.nent_broadcast = broadcast;
net_notif.nent_client = client;
net_notif.nent_net_type = net_type;
VARITEM(3, 4, XPD(s1, s2, s3, f1, f2, f3, f4)) \
VARITEM(4, 4, XPD(s1, s2, s3, s4, f1, f2, f3, f4))
-void Destroy_All_Notifications(void);
+void Destroy_All_Notifications();
void Create_Notification_Entity(
float var_default,
float var_cvar,
float f1, float f2, float f3, float f4);
#ifdef CSQC // CLIENT ONLY
-void Read_Notification(float is_new);
string prev_soundfile;
float prev_soundtime;
#endif
#ifdef SVQC
.float FRAG_VERBOSE;
-void Notification_GetCvars(void);
+void Notification_GetCvars();
float autocvar_notification_server_allows_location = 1; // 0 = no, 1 = yes
#else
float autocvar_notification_item_centerprinttime = 1.5;
// todo possible idea.... declare how many floats/strings each arg needs, and then dynamically increment the input
// this way, we don't need to have duplicates like i.e. s2loc and s3loc?
+string BUFF_NAME(int i);
+
#define NOTIF_ARGUMENT_LIST \
ARG_CASE(ARG_CS_SV_HA, "s1", s1) \
ARG_CASE(ARG_CS_SV_HA, "s2", s2) \
ARG_CASE(ARG_CS_SV, "spree_end", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \
ARG_CASE(ARG_CS_SV, "spree_lost", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-2, "", "", f1) : "")) \
ARG_CASE(ARG_CS_SV, "item_wepname", WEP_NAME(f1)) \
- ARG_CASE(ARG_CS_SV, "item_buffname", sprintf("%s%s", rgb_to_hexcolor(Buffs[f1].m_color), Buffs[f1].m_prettyName)) \
- ARG_CASE(ARG_CS_SV, "f3buffname", sprintf("%s%s", rgb_to_hexcolor(Buffs[f3].m_color), Buffs[f3].m_prettyName)) \
+ ARG_CASE(ARG_CS_SV, "item_buffname", BUFF_NAME(f1)) \
+ ARG_CASE(ARG_CS_SV, "f3buffname", BUFF_NAME(f3)) \
ARG_CASE(ARG_CS_SV, "item_wepammo", (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \
ARG_CASE(ARG_DC, "item_centime", ftos(autocvar_notification_item_centerprinttime)) \
ARG_CASE(ARG_SV, "death_team", Team_ColoredFullName(f1)) \
float NOTIF_CHOICE_COUNT;
// notification limits -- INCREASE AS NECESSARY
-const float NOTIF_ANNCE_MAX = 100;
-const float NOTIF_INFO_MAX = 350;
-const float NOTIF_CENTER_MAX = 250;
-const float NOTIF_MULTI_MAX = 200;
-const float NOTIF_CHOICE_MAX = 30;
+const float NOTIF_ANNCE_MAX = 400;
+const float NOTIF_INFO_MAX = 450;
+const float NOTIF_CENTER_MAX = 350;
+const float NOTIF_MULTI_MAX = 300;
+const float NOTIF_CHOICE_MAX = 50;
// notification entities
entity msg_annce_notifs[NOTIF_ANNCE_MAX];
returns true if handled
=============
*/
-bool PlayerJump (void)
+bool PlayerJump ()
{SELFPARAM();
if (PHYS_FROZEN(self))
return true; // no jumping in freezetag when frozen
return false;
}
-void PM_check_nickspam(void)
+void PM_check_nickspam()
{SELFPARAM();
#ifdef SVQC
if (time >= self.nickspamtime)
#endif
}
-void PM_check_spider(void)
+void PM_check_spider()
{SELFPARAM();
#ifdef SVQC
if (time >= self.spider_slowness)
}
// predict frozen movement, as frozen players CAN move in some cases
-void PM_check_frozen(void)
+void PM_check_frozen()
{SELFPARAM();
if (!PHYS_FROZEN(self))
return;
if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS))
{
if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
- GlobalSound(globalsound_metalfall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ GlobalSound(GS_FALL_METAL, CH_PLAYER, VOICETYPE_PLAYERSOUND);
else
- GlobalSound(globalsound_fall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ GlobalSound(GS_FALL, CH_PLAYER, VOICETYPE_PLAYERSOUND);
}
}
}
#endif
}
-void PM_check_blocked(void)
+void PM_check_blocked()
{SELFPARAM();
#ifdef SVQC
if (!self.player_blocked)
#endif
}
-void PM_check_vortex(void)
+void PM_check_vortex()
{SELFPARAM();
#ifdef SVQC
// WEAPONTODO
RaceCarPhysics();
#endif
- else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY || (BUFFS_STAT(self) & BUFF_FLIGHT.m_itemid))
+ else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY || MUTATOR_CALLHOOK(IsFlying, self))
PM_fly(maxspeed_mod);
else if (self.waterlevel >= WATERLEVEL_SWIMMING)
}
#ifdef SVQC
-void SV_PlayerPhysics(void)
+void SV_PlayerPhysics()
#elif defined(CSQC)
-void CSQC_ClientMovement_PlayerMove_Frame(void)
+void CSQC_ClientMovement_PlayerMove_Frame()
#endif
{SELFPARAM();
PM_Main();
void PM_multijump();
.float watertype;
+ .float waterlevel;
.int items;
.vector movement;
#endif
#ifdef SVQC
-void PlayerStats_Prematch(void)
+void PlayerStats_Prematch()
{
//foobar
}
LOG_TRACE("Added item ", sprintf("#%s", event), "=", data, " to PS_D_IN_DB\n");
}
-void PlayerStats_PlayerDetail(void)
+void PlayerStats_PlayerDetail()
{
// http://stats.xonotic.org/player/me
if((autocvar_g_playerstats_playerdetail_uri != "") && (crypto_getmyidstatus(0) > 0))
}
}
-void PlayerStats_PlayerDetail_CheckUpdate(void)
+void PlayerStats_PlayerDetail_CheckUpdate()
{
// determine whether we should retrieve playerdetail information again
float gamecount = cvar("cl_matchcount");
float PlayerStats_PlayerDetail_Status = PS_D_STATUS_IDLE;
string autocvar_g_playerstats_playerdetail_uri = "http://stats.xonotic.org/player/me";
float autocvar_g_playerstats_playerdetail_autoupdatetime = 1800; // automatically update every 30 minutes anyway
-void PlayerStats_PlayerDetail(void);
-void PlayerStats_PlayerDetail_CheckUpdate(void);
+void PlayerStats_PlayerDetail();
+void PlayerStats_PlayerDetail_CheckUpdate();
void PlayerStats_PlayerDetail_Handler(entity fh, entity p, float status);
#endif
#endif
SOUND(GRENADE_BOUNCE5, W_Sound("grenade_bounce5"));
SOUND(GRENADE_BOUNCE6, W_Sound("grenade_bounce6"));
Sound SND_GRENADE_BOUNCE_RANDOM() {
- return Sounds[SND_GRENADE_BOUNCE1.m_id + rint(random() * 5)];
+ return Sounds_from(SND_GRENADE_BOUNCE1.m_id + rint(random() * 5));
}
SOUND(GRENADE_FIRE, W_Sound("grenade_fire"));
SOUND(GRENADE_IMPACT, W_Sound("grenade_impact"));
SOUND(HAGEXP2, W_Sound("hagexp2"));
SOUND(HAGEXP3, W_Sound("hagexp3"));
Sound SND_HAGEXP_RANDOM() {
- return Sounds[SND_HAGEXP1.m_id + rint(random() * 2)];
+ return Sounds_from(SND_HAGEXP1.m_id + rint(random() * 2));
}
SOUND(HOOKBOMB_FIRE, W_Sound("hookbomb_fire"));
SOUND(NEXWHOOSH2, W_Sound("nexwhoosh2"));
SOUND(NEXWHOOSH3, W_Sound("nexwhoosh3"));
Sound SND_NEXWHOOSH_RANDOM() {
- return Sounds[SND_NEXWHOOSH1.m_id + rint(random() * 2)];
+ return Sounds_from(SND_NEXWHOOSH1.m_id + rint(random() * 2));
}
SOUND(RELOAD, W_Sound("reload")); // until weapons have individual reload sounds, precache the reload sound here
SOUND(RIC2, W_Sound("ric2"));
SOUND(RIC3, W_Sound("ric3"));
Sound SND_RIC_RANDOM() {
- return Sounds[SND_RIC1.m_id + rint(random() * 2)];
+ return Sounds_from(SND_RIC1.m_id + rint(random() * 2));
}
SOUND(ROCKET_DET, W_Sound("rocket_det"));
SOUND(WEAPONPICKUP_NEW_TOYS, W_Sound("weaponpickup_new_toys"));
SOUND(WEAPON_SWITCH, W_Sound("weapon_switch"));
-SOUND(CTF_CAPTURE_NEUTRAL, "ctf/capture.ogg");
-SOUND(CTF_CAPTURE_RED, "ctf/red_capture.wav");
-SOUND(CTF_CAPTURE_BLUE, "ctf/blue_capture.wav");
-SOUND(CTF_CAPTURE_YELLOW, "ctf/yellow_capture.ogg");
-SOUND(CTF_CAPTURE_PINK, "ctf/pink_capture.ogg");
+SOUND(CTF_CAPTURE_NEUTRAL, "ctf/capture");
+SOUND(CTF_CAPTURE_RED, "ctf/red_capture");
+SOUND(CTF_CAPTURE_BLUE, "ctf/blue_capture");
+SOUND(CTF_CAPTURE_YELLOW, "ctf/yellow_capture");
+SOUND(CTF_CAPTURE_PINK, "ctf/pink_capture");
Sound SND_CTF_CAPTURE(int teamid) {
switch (teamid) {
case NUM_TEAM_1: return SND_CTF_CAPTURE_RED;
}
}
-SOUND(CTF_DROPPED_NEUTRAL, "ctf/neutral_dropped.wav");
-SOUND(CTF_DROPPED_RED, "ctf/red_dropped.wav");
-SOUND(CTF_DROPPED_BLUE, "ctf/blue_dropped.wav");
-SOUND(CTF_DROPPED_YELLOW, "ctf/yellow_dropped.wav");
-SOUND(CTF_DROPPED_PINK, "ctf/pink_dropped.wav");
+SOUND(CTF_DROPPED_NEUTRAL, "ctf/neutral_dropped");
+SOUND(CTF_DROPPED_RED, "ctf/red_dropped");
+SOUND(CTF_DROPPED_BLUE, "ctf/blue_dropped");
+SOUND(CTF_DROPPED_YELLOW, "ctf/yellow_dropped");
+SOUND(CTF_DROPPED_PINK, "ctf/pink_dropped");
Sound SND_CTF_DROPPED(int teamid) {
switch (teamid) {
case NUM_TEAM_1: return SND_CTF_DROPPED_RED;
}
}
-SOUND(CTF_PASS, "ctf/pass.wav");
-SOUND(CTF_RESPAWN, "ctf/flag_respawn.wav");
+SOUND(CTF_PASS, "ctf/pass");
+SOUND(CTF_RESPAWN, "ctf/flag_respawn");
-SOUND(CTF_RETURNED_NEUTRAL, "ctf/return.wav");
-SOUND(CTF_RETURNED_RED, "ctf/red_returned.wav");
-SOUND(CTF_RETURNED_BLUE, "ctf/blue_returned.wav");
-SOUND(CTF_RETURNED_YELLOW, "ctf/yellow_returned.wav");
-SOUND(CTF_RETURNED_PINK, "ctf/pink_returned.wav");
+SOUND(CTF_RETURNED_NEUTRAL, "ctf/return");
+SOUND(CTF_RETURNED_RED, "ctf/red_returned");
+SOUND(CTF_RETURNED_BLUE, "ctf/blue_returned");
+SOUND(CTF_RETURNED_YELLOW, "ctf/yellow_returned");
+SOUND(CTF_RETURNED_PINK, "ctf/pink_returned");
Sound SND_CTF_RETURNED(int teamid) {
switch (teamid) {
case NUM_TEAM_1: return SND_CTF_RETURNED_RED;
}
}
-SOUND(CTF_TAKEN_NEUTRAL, "ctf/neutral_taken.wav");
-SOUND(CTF_TAKEN_RED, "ctf/red_taken.wav");
-SOUND(CTF_TAKEN_BLUE, "ctf/blue_taken.wav");
-SOUND(CTF_TAKEN_YELLOW, "ctf/yellow_taken.wav");
-SOUND(CTF_TAKEN_PINK, "ctf/pink_taken.wav");
+SOUND(CTF_TAKEN_NEUTRAL, "ctf/neutral_taken");
+SOUND(CTF_TAKEN_RED, "ctf/red_taken");
+SOUND(CTF_TAKEN_BLUE, "ctf/blue_taken");
+SOUND(CTF_TAKEN_YELLOW, "ctf/yellow_taken");
+SOUND(CTF_TAKEN_PINK, "ctf/pink_taken");
Sound SND_CTF_TAKEN(int teamid) {
switch (teamid) {
case NUM_TEAM_1: return SND_CTF_TAKEN_RED;
}
}
-SOUND(CTF_TOUCH, "ctf/touch.wav");
-
-SOUND(DOM_CLAIM, "domination/claim.wav");
-
-SOUND(KA_DROPPED, "keepaway/dropped.wav");
-SOUND(KA_PICKEDUP, "keepaway/pickedup.wav");
-SOUND(KA_RESPAWN, "keepaway/respawn.wav");
-SOUND(KA_TOUCH, "keepaway/touch.wav");
-
-SOUND(KH_ALARM, "kh/alarm.wav");
-SOUND(KH_CAPTURE, "kh/capture.wav");
-SOUND(KH_COLLECT, "kh/collect.wav");
-SOUND(KH_DESTROY, "kh/destroy.wav");
-SOUND(KH_DROP, "kh/drop.wav");
-
-SOUND(NB_BOUNCE, "nexball/bounce.ogg");
-SOUND(NB_DROP, "nexball/drop.ogg");
-SOUND(NB_SHOOT1, "nexball/shoot1.ogg");
-SOUND(NB_SHOOT2, "nexball/shoot2.ogg");
-SOUND(NB_STEAL, "nexball/steal.ogg");
-
-SOUND(ONS_CONTROLPOINT_BUILD, "onslaught/controlpoint_build.ogg");
-SOUND(ONS_CONTROLPOINT_BUILT, "onslaught/controlpoint_built.ogg");
-SOUND(ONS_CONTROLPOINT_UNDERATTACK, "onslaught/controlpoint_underattack.ogg");
-SOUND(ONS_DAMAGEBLOCKEDBYSHIELD, "onslaught/damageblockedbyshield.wav");
-SOUND(ONS_ELECTRICITY_EXPLODE, "onslaught/electricity_explode.ogg");
-SOUND(ONS_GENERATOR_DECAY, "onslaught/generator_decay.ogg");
-SOUND(ONS_GENERATOR_UNDERATTACK, "onslaught/generator_underattack.ogg");
-SOUND(ONS_HIT1, "onslaught/ons_hit1.ogg");
-SOUND(ONS_HIT2, "onslaught/ons_hit2.ogg");
-SOUND(ONS_SPARK1, "onslaught/ons_spark1.ogg");
-SOUND(ONS_SPARK2, "onslaught/ons_spark2.ogg");
-SOUND(ONS_SHOCKWAVE, "onslaught/shockwave.ogg");
-
-SOUND(PORTO_BOUNCE, "porto/bounce.ogg");
-SOUND(PORTO_CREATE, "porto/create.ogg");
-SOUND(PORTO_EXPIRE, "porto/expire.ogg");
-SOUND(PORTO_EXPLODE, "porto/explode.ogg");
-SOUND(PORTO_FIRE, "porto/fire.ogg");
-SOUND(PORTO_UNSUPPORTED, "porto/unsupported.ogg");
-
-SOUND(TUR_PHASER, "turrets/phaser.ogg");
-
-SOUND(VEH_ALARM, "vehicles/alarm.wav");
-SOUND(VEH_ALARM_SHIELD, "vehicles/alarm_shield.wav");
-SOUND(VEH_MISSILE_ALARM, "vehicles/missile_alarm.wav");
+SOUND(CTF_TOUCH, "ctf/touch");
+
+SOUND(DOM_CLAIM, "domination/claim");
+
+SOUND(KA_DROPPED, "keepaway/dropped");
+SOUND(KA_PICKEDUP, "keepaway/pickedup");
+SOUND(KA_RESPAWN, "keepaway/respawn");
+SOUND(KA_TOUCH, "keepaway/touch");
+
+SOUND(KH_ALARM, "kh/alarm");
+SOUND(KH_CAPTURE, "kh/capture");
+SOUND(KH_COLLECT, "kh/collect");
+SOUND(KH_DESTROY, "kh/destroy");
+SOUND(KH_DROP, "kh/drop");
+
+SOUND(NB_BOUNCE, "nexball/bounce");
+SOUND(NB_DROP, "nexball/drop");
+SOUND(NB_SHOOT1, "nexball/shoot1");
+SOUND(NB_SHOOT2, "nexball/shoot2");
+SOUND(NB_STEAL, "nexball/steal");
+
+SOUND(ONS_CONTROLPOINT_BUILD, "onslaught/controlpoint_build");
+SOUND(ONS_CONTROLPOINT_BUILT, "onslaught/controlpoint_built");
+SOUND(ONS_CONTROLPOINT_UNDERATTACK, "onslaught/controlpoint_underattack");
+SOUND(ONS_DAMAGEBLOCKEDBYSHIELD, "onslaught/damageblockedbyshield");
+SOUND(ONS_ELECTRICITY_EXPLODE, "onslaught/electricity_explode");
+SOUND(ONS_GENERATOR_DECAY, "onslaught/generator_decay");
+SOUND(ONS_GENERATOR_UNDERATTACK, "onslaught/generator_underattack");
+SOUND(ONS_HIT1, "onslaught/ons_hit1");
+SOUND(ONS_HIT2, "onslaught/ons_hit2");
+SOUND(ONS_SPARK1, "onslaught/ons_spark1");
+SOUND(ONS_SPARK2, "onslaught/ons_spark2");
+SOUND(ONS_SHOCKWAVE, "onslaught/shockwave");
+
+SOUND(PORTO_BOUNCE, "porto/bounce");
+SOUND(PORTO_CREATE, "porto/create");
+SOUND(PORTO_EXPIRE, "porto/expire");
+SOUND(PORTO_EXPLODE, "porto/explode");
+SOUND(PORTO_FIRE, "porto/fire");
+SOUND(PORTO_UNSUPPORTED, "porto/unsupported");
+
+SOUND(TUR_PHASER, "turrets/phaser");
+
+SOUND(VEH_ALARM, "vehicles/alarm");
+SOUND(VEH_ALARM_SHIELD, "vehicles/alarm_shield");
+SOUND(VEH_MISSILE_ALARM, "vehicles/missile_alarm");
SOUND(VEH_BUMBLEBEE_FIRE, W_Sound("flacexp3"));
-SOUND(VEH_RACER_BOOST, "vehicles/racer_boost.wav");
-SOUND(VEH_RACER_IDLE, "vehicles/racer_idle.wav");
-SOUND(VEH_RACER_MOVE, "vehicles/racer_move.wav");
+SOUND(VEH_RACER_BOOST, "vehicles/racer_boost");
+SOUND(VEH_RACER_IDLE, "vehicles/racer_idle");
+SOUND(VEH_RACER_MOVE, "vehicles/racer_move");
-SOUND(VEH_RAPTOR_FLY, "vehicles/raptor_fly.wav");
-SOUND(VEH_RAPTOR_SPEED, "vehicles/raptor_speed.wav");
+SOUND(VEH_RAPTOR_FLY, "vehicles/raptor_fly");
+SOUND(VEH_RAPTOR_SPEED, "vehicles/raptor_speed");
-SOUND(VEH_SPIDERBOT_DIE, "vehicles/spiderbot_die.wav");
-SOUND(VEH_SPIDERBOT_IDLE, "vehicles/spiderbot_idle.wav");
-SOUND(VEH_SPIDERBOT_JUMP, "vehicles/spiderbot_jump.wav");
-SOUND(VEH_SPIDERBOT_LAND, "vehicles/spiderbot_land.wav");
-SOUND(VEH_SPIDERBOT_STRAFE, "vehicles/spiderbot_strafe.wav");
-SOUND(VEH_SPIDERBOT_WALK, "vehicles/spiderbot_walk.wav");
+SOUND(VEH_SPIDERBOT_DIE, "vehicles/spiderbot_die");
+SOUND(VEH_SPIDERBOT_IDLE, "vehicles/spiderbot_idle");
+SOUND(VEH_SPIDERBOT_JUMP, "vehicles/spiderbot_jump");
+SOUND(VEH_SPIDERBOT_LAND, "vehicles/spiderbot_land");
+SOUND(VEH_SPIDERBOT_STRAFE, "vehicles/spiderbot_strafe");
+SOUND(VEH_SPIDERBOT_WALK, "vehicles/spiderbot_walk");
-SOUND(NADE_BEEP, "overkill/grenadebip.ogg");
+SOUND(NADE_BEEP, "overkill/grenadebip");
-SOUND(BUFF_LOST, "relics/relic_effect.wav");
+SOUND(BUFF_LOST, "relics/relic_effect");
-SOUND(POWEROFF, "misc/poweroff.wav");
-SOUND(POWERUP, "misc/powerup.ogg");
-SOUND(SHIELD_RESPAWN, "misc/shield_respawn.wav");
-SOUND(STRENGTH_RESPAWN, "misc/strength_respawn.wav");
+SOUND(POWEROFF, "misc/poweroff");
+SOUND(POWERUP, "misc/powerup");
+SOUND(SHIELD_RESPAWN, "misc/shield_respawn");
+SOUND(STRENGTH_RESPAWN, "misc/strength_respawn");
-SOUND(ARMOR25, "misc/armor25.wav");
-SOUND(ARMORIMPACT, "misc/armorimpact.wav");
-SOUND(BODYIMPACT1, "misc/bodyimpact1.wav");
-SOUND(BODYIMPACT2, "misc/bodyimpact2.wav");
+SOUND(ARMOR25, "misc/armor25");
+SOUND(ARMORIMPACT, "misc/armorimpact");
+SOUND(BODYIMPACT1, "misc/bodyimpact1");
+SOUND(BODYIMPACT2, "misc/bodyimpact2");
-SOUND(ITEMPICKUP, "misc/itempickup.ogg");
-SOUND(ITEMRESPAWNCOUNTDOWN, "misc/itemrespawncountdown.ogg");
-SOUND(ITEMRESPAWN, "misc/itemrespawn.ogg");
-SOUND(MEGAHEALTH, "misc/megahealth.ogg");
+SOUND(ITEMPICKUP, "misc/itempickup");
+SOUND(ITEMRESPAWNCOUNTDOWN, "misc/itemrespawncountdown");
+SOUND(ITEMRESPAWN, "misc/itemrespawn");
+SOUND(MEGAHEALTH, "misc/megahealth");
-SOUND(LAVA, "player/lava.wav");
-SOUND(SLIME, "player/slime.wav");
+SOUND(LAVA, "player/lava");
+SOUND(SLIME, "player/slime");
-SOUND(GIB, "misc/gib.wav");
-SOUND(GIB_SPLAT01, "misc/gib_splat01.wav");
-SOUND(GIB_SPLAT02, "misc/gib_splat02.wav");
-SOUND(GIB_SPLAT03, "misc/gib_splat03.wav");
-SOUND(GIB_SPLAT04, "misc/gib_splat04.wav");
+SOUND(GIB, "misc/gib");
+SOUND(GIB_SPLAT01, "misc/gib_splat01");
+SOUND(GIB_SPLAT02, "misc/gib_splat02");
+SOUND(GIB_SPLAT03, "misc/gib_splat03");
+SOUND(GIB_SPLAT04, "misc/gib_splat04");
Sound SND_GIB_SPLAT_RANDOM() {
- return Sounds[SND_GIB_SPLAT01.m_id + floor(prandom() * 4)];
+ return Sounds_from(SND_GIB_SPLAT01.m_id + floor(prandom() * 4));
}
-SOUND(HIT, "misc/hit.wav");
-SOUND(TYPEHIT, "misc/typehit.wav");
+SOUND(HIT, "misc/hit");
+SOUND(TYPEHIT, "misc/typehit");
-SOUND(SPAWN, "misc/spawn.ogg");
+SOUND(SPAWN, "misc/spawn");
-SOUND(TALK, "misc/talk.wav");
+SOUND(TALK, "misc/talk");
-SOUND(TELEPORT, "misc/teleport.ogg");
+SOUND(TELEPORT, "misc/teleport");
-SOUND(INVSHOT, "misc/invshot.wav");
+SOUND(INVSHOT, "misc/invshot");
-SOUND(JETPACK_FLY, "misc/jetpack_fly.ogg");
+SOUND(JETPACK_FLY, "misc/jetpack_fly");
--- /dev/null
+#ifdef SVQC
+
+bool autocvar_bot_sound_monopoly;
+
+.entity realowner;
+bool sound_allowed(int to, entity e)
+{
+ for ( ; ; )
+ {
+ if (e.classname == "body") e = e.enemy;
+ else if (e.realowner && e.realowner != e) e = e.realowner;
+ else if (e.owner && e.owner != e) e = e.owner;
+ else break;
+ }
+ // sounds to self may always pass
+ if (to == MSG_ONE && e == msg_entity) return true;
+ // sounds by players can be removed
+ if (autocvar_bot_sound_monopoly && IS_REAL_CLIENT(e)) return false;
+ // anything else may pass
+ return true;
+}
+
+/** hack: string precache_sound(string s) = #19; */
+int precache_sound_index(string s) = #19;
+
+const int SVC_SOUND = 6;
+const int SVC_STOPSOUND = 16;
+
+const int SND_VOLUME = BIT(0);
+const int SND_ATTENUATION = BIT(1);
+const int SND_LARGEENTITY = BIT(3);
+const int SND_LARGESOUND = BIT(4);
+
+void soundtoat(int to, entity e, vector o, int chan, string samp, float vol, float attenu)
+{
+ if (!sound_allowed(to, e)) return;
+ int entno = etof(e);
+ int idx = precache_sound_index(samp);
+ attenu = floor(attenu * 64);
+ vol = floor(vol * 255);
+ int sflags = 0;
+ if (vol != 255) sflags |= SND_VOLUME;
+ if (attenu != 64) sflags |= SND_ATTENUATION;
+ if (entno >= 8192 || chan < 0 || chan > 7) sflags |= SND_LARGEENTITY;
+ if (idx >= 256) sflags |= SND_LARGESOUND;
+ WriteByte(to, SVC_SOUND);
+ WriteByte(to, sflags);
+ if (sflags & SND_VOLUME) WriteByte(to, vol);
+ if (sflags & SND_ATTENUATION) WriteByte(to, attenu);
+ if (sflags & SND_LARGEENTITY)
+ {
+ WriteShort(to, entno);
+ WriteByte(to, chan);
+ }
+ else
+ {
+ WriteShort(to, (entno << 3) | chan);
+ }
+ if (sflags & SND_LARGESOUND) WriteShort(to, idx);
+ else WriteByte(to, idx);
+ WriteCoord(to, o.x);
+ WriteCoord(to, o.y);
+ WriteCoord(to, o.z);
+}
+
+void soundto(int _dest, entity e, int chan, string samp, float vol, float _atten)
+{
+ if (!sound_allowed(_dest, e)) return;
+ vector o = e.origin + 0.5 * (e.mins + e.maxs);
+ soundtoat(_dest, e, o, chan, samp, vol, _atten);
+}
+void soundat(entity e, vector o, int chan, string samp, float vol, float _atten)
+{
+ soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, _atten);
+}
+void stopsoundto(int _dest, entity e, int chan)
+{
+ if (!sound_allowed(_dest, e)) return;
+ int entno = num_for_edict(e);
+ if (entno >= 8192 || chan < 0 || chan > 7)
+ {
+ int idx = precache_sound_index(SND(Null));
+ int sflags = SND_LARGEENTITY;
+ if (idx >= 256) sflags |= SND_LARGESOUND;
+ WriteByte(_dest, SVC_SOUND);
+ WriteByte(_dest, sflags);
+ WriteShort(_dest, entno);
+ WriteByte(_dest, chan);
+ if (sflags & SND_LARGESOUND) WriteShort(_dest, idx);
+ else WriteByte(_dest, idx);
+ WriteCoord(_dest, e.origin.x);
+ WriteCoord(_dest, e.origin.y);
+ WriteCoord(_dest, e.origin.z);
+ }
+ else
+ {
+ WriteByte(_dest, SVC_STOPSOUND);
+ WriteShort(_dest, entno * 8 + chan);
+ }
+}
+void stopsound(entity e, int chan)
+{
+ if (!sound_allowed(MSG_BROADCAST, e)) return;
+ stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
+ stopsoundto(MSG_ALL, e, chan); // in case of packet loss
+}
+
+void play2(entity e, string filename)
+{
+ msg_entity = e;
+ soundtoat(MSG_ONE, world, '0 0 0', CH_INFO, filename, VOL_BASE, ATTEN_NONE);
+}
+
+.float spamtime;
+/** use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame) */
+float spamsound(entity e, int chan, string samp, float vol, float _atten)
+{
+ if (!sound_allowed(MSG_BROADCAST, e)) return false;
+ if (time > e.spamtime)
+ {
+ e.spamtime = time;
+ _sound(e, chan, samp, vol, _atten);
+ return true;
+ }
+ return false;
+}
+
+void play2team(float t, string filename)
+{
+ if (autocvar_bot_sound_monopoly) return;
+ entity head;
+ FOR_EACH_REALPLAYER(head)
+ {
+ if (head.team == t) play2(head, filename);
+ }
+}
+
+void play2all(string samp)
+{
+ if (autocvar_bot_sound_monopoly) return;
+ _sound(world, CH_INFO, samp, VOL_BASE, ATTEN_NONE);
+}
+
+#endif
#include "sound.qh"
REGISTRY(Sounds, BITS(8))
-REGISTER_REGISTRY(RegisterSounds)
+#define Sounds_from(i) _Sounds_from(i, SND_Null)
+REGISTER_REGISTRY(Sounds)
#define SOUND(name, path) \
string SND_##name##_get() { return path; } \
- REGISTER(RegisterSounds, SND, Sounds, name, m_id, NEW(Sound, SND_##name##_get))
+ REGISTER(Sounds, SND, name, m_id, NEW(Sound, SND_##name##_get))
// Used in places where a string is required
-#define SND(id) (SND_##id.sound_str())
+#define SND(id) Sound_fixpath(SND_##id)
-STATIC_INIT(RegisterSounds_precache) {
+PRECACHE(Sounds) {
FOREACH(Sounds, true, LAMBDA({
it.sound_precache(it);
}));
}
-SOUND(Null, "misc/null.wav");
+SOUND(Null, "misc/null");
#include "all.inc"
-
+#include "all.qc"
#endif
#ifndef SOUND_H
#define SOUND_H
+const int CH_INFO = 0;
+const int CH_TRIGGER = -3;
+const int CH_WEAPON_A = -1;
+const int CH_WEAPON_SINGLE = 1;
+const int CH_VOICE = -2;
+const int CH_BGM_SINGLE = 8;
+const int CH_AMBIENT = -9;
+const int CH_TRIGGER_SINGLE = 3;
+const int CH_SHOTS = -4;
+const int CH_SHOTS_SINGLE = 4;
+const int CH_WEAPON_B = -1;
+const int CH_PAIN = -6;
+const int CH_PAIN_SINGLE = 6;
+const int CH_PLAYER = -7;
+const int CH_PLAYER_SINGLE = 7;
+const int CH_TUBA_SINGLE = 5;
+
+const float ATTEN_NONE = 0;
+const float ATTEN_MIN = 0.015625;
+const float ATTEN_NORM = 0.5;
+const float ATTEN_LARGE = 1;
+const float ATTEN_IDLE = 2;
+const float ATTEN_STATIC = 3;
+const float ATTEN_MAX = 3.984375;
+
+const float VOL_BASE = 0.7;
+const float VOL_BASEVOICE = 1.0;
+
// Play all sounds via sound7, for access to the extra channels.
// Otherwise, channels 8 to 15 would be blocked for a weird QW feature.
#ifdef SVQC
- #define _sound(e, c, s, v, a) do { \
- entity __e = e; \
- if (!sound_allowed(MSG_BROADCAST, __e)) break; \
- sound7(__e, c, s, v, a, 0, 0); \
- } while (0)
+ #define _sound(e, c, s, v, a) \
+ do \
+ { \
+ entity __e = e; \
+ if (!sound_allowed(MSG_BROADCAST, __e)) break; \
+ sound7(__e, c, s, v, a, 0, 0); \
+ } \
+ while (0)
#else
- #define _sound(e, c, s, v, a) sound7(e, c, s, v, a, 0, 0)
+ #define _sound(e, c, s, v, a) sound7(e, c, s, v, a, 0, 0)
#endif
-#define sound(e, c, s, v, a) _sound(e, c, s.sound_str(), v, a)
+#define sound(e, c, s, v, a) _sound(e, c, Sound_fixpath(s), v, a)
+
+/**
+ * because sound7 didn't have origin
+ *
+ * @param e sound owner
+ * @param o sound origin
+ * @param chan sound channel
+ * @param samp sound filename
+ * @param vol sound volume
+ * @param atten sound attenuation
+ * @param speed
+ * @param sf
+ */
+#define sound8(e, o, chan, samp, vol, atten, speed, sf) \
+ do \
+ { \
+ entity __e = e; \
+ vector old_origin = __e.origin; \
+ vector old_mins = __e.mins; \
+ vector old_maxs = __e.maxs; \
+ setorigin(__e, o); \
+ setsize(__e, '0 0 0', '0 0 0'); \
+ sound7(__e, chan, samp, vol, atten, speed, sf); \
+ setorigin(__e, old_origin); \
+ setsize(__e, old_mins, old_maxs); \
+ } \
+ while (0)
CLASS(Sound, Object)
- ATTRIB(Sound, m_id, int, 0)
- ATTRIB(Sound, sound_str, string(), func_null)
- CONSTRUCTOR(Sound, string() path)
- {
- CONSTRUCT(Sound);
- this.sound_str = path;
- }
- METHOD(Sound, sound_precache, void(entity this)) {
- string s = this.sound_str();
- if (s && s != "" && !fexists(strcat("sound/", s))) {
- LOG_WARNINGF("Missing sound: \"%s\"\n", s);
- return;
- }
- LOG_TRACEF("precache_sound(\"%s\")\n", s);
- precache_sound(s);
- }
+ ATTRIB(Sound, m_id, int, 0)
+ ATTRIB(Sound, sound_str, string(), func_null)
+ CONSTRUCTOR(Sound, string() path)
+ {
+ CONSTRUCT(Sound);
+ this.sound_str = path;
+ }
+ #define Sound_fixpath(this) _Sound_fixpath((this).sound_str())
+ string _Sound_fixpath(string base)
+ {
+ if (base == "") return string_null;
+ #define extensions(x) \
+ x(wav) \
+ x(ogg) \
+ x(flac) \
+ /**/
+ string full, relative;
+ #define tryext(ext) { if (fexists(full = strcat("sound/", relative = strcat(base, "." #ext)))) break; }
+ do
+ {
+ extensions(tryext);
+#undef tryext
+#undef extensions
+ LOG_WARNINGF("Missing sound: \"%s\"\n", full);
+ return string_null;
+ }
+ while (0);
+ return relative;
+ }
+ METHOD(Sound, sound_precache, void(entity this))
+ {
+ string s = Sound_fixpath(this);
+ if (!s) return;
+ LOG_TRACEF("precache_sound(\"%s\")\n", s);
+ precache_sound(s);
+ }
ENDCLASS(Sound)
#endif
// 29 empty?
// 30 empty?
// 31 empty?
-const int STAT_KH_KEYS = 32;
-const int STAT_CTF_STATE = 33;
-// 34 empty?
-const int STAT_WEAPONS = 35;
-const int STAT_SWITCHWEAPON = 36;
-const int STAT_GAMESTARTTIME = 37;
-const int STAT_STRENGTH_FINISHED = 38;
-const int STAT_INVINCIBLE_FINISHED = 39;
-// 40 empty?
-const int STAT_ARC_HEAT = 41;
-const int STAT_PRESSED_KEYS = 42;
-const int STAT_ALLOW_OLDVORTEXBEAM = 43; // this stat could later contain some other bits of info, like, more server-side particle config
-const int STAT_FUEL = 44;
-const int STAT_NB_METERSTART = 45;
-const int STAT_SHOTORG = 46; // compressShotOrigin
-const int STAT_LEADLIMIT = 47;
-const int STAT_WEAPON_CLIPLOAD = 48;
-const int STAT_WEAPON_CLIPSIZE = 49;
-const int STAT_VORTEX_CHARGE = 50;
-const int STAT_LAST_PICKUP = 51;
-const int STAT_HUD = 52;
-const int STAT_VORTEX_CHARGEPOOL = 53;
-const int STAT_HIT_TIME = 54;
-const int STAT_DAMAGE_DEALT_TOTAL = 55;
-const int STAT_TYPEHIT_TIME = 56;
-const int STAT_LAYED_MINES = 57;
-const int STAT_HAGAR_LOAD = 58;
-const int STAT_SWITCHINGWEAPON = 59;
-const int STAT_SUPERWEAPONS_FINISHED = 60;
-const int STAT_VEHICLESTAT_HEALTH = 61;
-const int STAT_VEHICLESTAT_SHIELD = 62;
-const int STAT_VEHICLESTAT_ENERGY = 63;
-const int STAT_VEHICLESTAT_AMMO1 = 64;
-const int STAT_VEHICLESTAT_RELOAD1 = 65;
-const int STAT_VEHICLESTAT_AMMO2 = 66;
-const int STAT_VEHICLESTAT_RELOAD2 = 67;
-const int STAT_VEHICLESTAT_W2MODE = 68;
-const int STAT_NADE_TIMER = 69;
-const int STAT_SECRETS_TOTAL = 70;
-const int STAT_SECRETS_FOUND = 71;
-const int STAT_RESPAWN_TIME = 72;
-const int STAT_ROUNDSTARTTIME = 73;
-const int STAT_WEAPONS2 = 74;
-const int STAT_WEAPONS3 = 75;
-const int STAT_MONSTERS_TOTAL = 76;
-const int STAT_MONSTERS_KILLED = 77;
-const int STAT_BUFFS = 78;
-const int STAT_NADE_BONUS = 79;
-const int STAT_NADE_BONUS_TYPE = 80;
-const int STAT_NADE_BONUS_SCORE = 81;
-const int STAT_HEALING_ORB = 82;
-const int STAT_HEALING_ORB_ALPHA = 83;
-const int STAT_PLASMA = 84;
-const int STAT_OK_AMMO_CHARGE = 85;
-const int STAT_OK_AMMO_CHARGEPOOL = 86;
-const int STAT_FROZEN = 87;
-const int STAT_REVIVE_PROGRESS = 88;
-// 89 empty?
-// 90 empty?
-// 91 empty?
-// 92 empty?
-// 93 empty?
-// 94 empty?
-// 95 empty?
-// 96 empty?
-// 97 empty?
-// 98 empty?
-const int STAT_ROUNDLOST = 99;
+
+enum {
+ STAT_WEAPONS = 32,
+ STAT_WEAPONS2,
+ STAT_WEAPONS3,
+
+ STAT_WEAPONSINMAP,
+ STAT_WEAPONSINMAP2,
+ STAT_WEAPONSINMAP3,
+
+ STAT_PL_VIEW_OFS1,
+ STAT_PL_VIEW_OFS2,
+ STAT_PL_VIEW_OFS3,
+
+ STAT_PL_CROUCH_VIEW_OFS1,
+ STAT_PL_CROUCH_VIEW_OFS2,
+ STAT_PL_CROUCH_VIEW_OFS3,
+
+ STAT_PL_MIN1,
+ STAT_PL_MIN2,
+ STAT_PL_MIN3,
+
+ STAT_PL_MAX1,
+ STAT_PL_MAX2,
+ STAT_PL_MAX3,
+
+ STAT_PL_CROUCH_MIN1,
+ STAT_PL_CROUCH_MIN2,
+ STAT_PL_CROUCH_MIN3,
+
+ STAT_PL_CROUCH_MAX1,
+ STAT_PL_CROUCH_MAX2,
+ STAT_PL_CROUCH_MAX3,
+
+ STAT_LAST_VECTOR
+};
+
+const int REGISTERED_STATS = 6;
+
+REGISTER_STAT(KH_KEYS, int)
+/** weapon requested to switch to; next WANTED weapon (for HUD) */
+REGISTER_STAT(SWITCHWEAPON, int)
+REGISTER_STAT(GAMESTARTTIME, float)
+REGISTER_STAT(STRENGTH_FINISHED, float)
+REGISTER_STAT(INVINCIBLE_FINISHED, float)
+/** arc heat in [0,1] */
+REGISTER_STAT(ARC_HEAT, float)
+
+enum {
+ STAT_FIRST_MAIN = (STAT_LAST_VECTOR - 1) + REGISTERED_STATS,
+
+ STAT_PRESSED_KEYS,
+ /** this stat could later contain some other bits of info, like, more server-side particle config */ STAT_ALLOW_OLDVORTEXBEAM,
+ STAT_FUEL,
+ STAT_NB_METERSTART,
+ /** compressShotOrigin */ STAT_SHOTORG,
+ STAT_LEADLIMIT,
+ STAT_WEAPON_CLIPLOAD,
+ STAT_WEAPON_CLIPSIZE,
+ STAT_VORTEX_CHARGE,
+ STAT_LAST_PICKUP,
+ STAT_HUD,
+ STAT_VORTEX_CHARGEPOOL,
+ STAT_HIT_TIME,
+ STAT_DAMAGE_DEALT_TOTAL,
+ STAT_TYPEHIT_TIME,
+ STAT_LAYED_MINES,
+ STAT_HAGAR_LOAD,
+ STAT_SWITCHINGWEAPON,
+ STAT_SUPERWEAPONS_FINISHED,
+ STAT_VEHICLESTAT_HEALTH,
+ STAT_VEHICLESTAT_SHIELD,
+ STAT_VEHICLESTAT_ENERGY,
+ STAT_VEHICLESTAT_AMMO1,
+ STAT_VEHICLESTAT_RELOAD1,
+ STAT_VEHICLESTAT_AMMO2,
+ STAT_VEHICLESTAT_RELOAD2,
+ STAT_VEHICLESTAT_W2MODE,
+ STAT_NADE_TIMER,
+ STAT_SECRETS_TOTAL,
+ STAT_SECRETS_FOUND,
+ STAT_RESPAWN_TIME,
+ STAT_ROUNDSTARTTIME,
+ STAT_MONSTERS_TOTAL,
+ STAT_MONSTERS_KILLED,
+ STAT_BUFFS,
+ STAT_NADE_BONUS,
+ STAT_NADE_BONUS_TYPE,
+ STAT_NADE_BONUS_SCORE,
+ STAT_HEALING_ORB,
+ STAT_HEALING_ORB_ALPHA,
+ STAT_PLASMA,
+ STAT_OK_AMMO_CHARGE,
+ STAT_OK_AMMO_CHARGEPOOL,
+ STAT_FROZEN,
+ STAT_REVIVE_PROGRESS,
+ STAT_ROUNDLOST,
+ STAT_BUFF_TIME,
+ STAT_CTF_FLAGSTATUS,
+ STAT_MULTIJUMP_DODGING,
+ STAT_MULTIJUMP_MAXSPEED,
+ STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND,
+ STAT_BUGRIGS_REVERSE_STOPPING,
+ STAT_BUGRIGS_REVERSE_SPINNING,
+ STAT_BUGRIGS_CAR_JUMPING,
+ STAT_BUGRIGS_FRICTION_AIR,
+ STAT_BUGRIGS_STEER,
+ STAT_BUGRIGS_SPEED_POW,
+ STAT_BUGRIGS_SPEED_REF,
+ STAT_BUGRIGS_ACCEL,
+ STAT_BUGRIGS_FRICTION_BRAKE,
+ STAT_BUGRIGS_AIR_STEERING,
+ STAT_BUGRIGS_FRICTION_FLOOR,
+ STAT_BUGRIGS_REVERSE_SPEEDING,
+ STAT_BUGRIGS_PLANAR_MOVEMENT,
+ STAT_BUGRIGS_ANGLE_SMOOTHING,
+ STAT_BUGRIGS,
+ STAT_GAMEPLAYFIX_STEPDOWN,
+ STAT_MOVEVARS_JUMPSTEP,
+ STAT_NOSTEP,
+ STAT_GAMEPLAYFIX_UNSTICKPLAYERS,
+ STAT_GAMEPLAYFIX_STEPMULTIPLETIMES,
+ STAT_GAMEPLAYFIX_DOWNTRACEONGROUND,
+ STAT_GAMEPLAYFIX_EASIERWATERJUMP,
+ STAT_MOVEVARS_FRICTION_SLICK,
+ STAT_MOVEVARS_FRICTION_ONLAND,
+ STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS,
+ STAT_MOVEVARS_TRACK_CANJUMP,
+ STAT_DOUBLEJUMP,
+ STAT_MOVEVARS_CL_TRACK_CANJUMP,
+ STAT_MULTIJUMP_ADD,
+ STAT_MULTIJUMP_SPEED,
+ STAT_MULTIJUMP,
+ STAT_DODGING_TIMEOUT,
+ STAT_DODGING_WALL,
+ STAT_DODGING_UP_SPEED,
+ STAT_DODGING_RAMP_TIME,
+ STAT_DODGING_HEIGHT_THRESHOLD,
+ STAT_DODGING_DISTANCE_THRESHOLD,
+ STAT_DODGING_HORIZ_SPEED,
+ STAT_DODGING_DELAY,
+ STAT_DODGING_FROZEN_NO_DOUBLETAP,
+ STAT_DODGING_HORIZ_SPEED_FROZEN,
+ STAT_DODGING,
+ STAT_DODGING_FROZEN,
+ STAT_JETPACK_MAXSPEED_UP,
+ STAT_JETPACK_MAXSPEED_SIDE,
+ STAT_JETPACK_FUEL,
+ STAT_JETPACK_ANTIGRAVITY,
+ STAT_JETPACK_ACCEL_SIDE,
+ STAT_JETPACK_ACCEL_UP,
+ STAT_MOVEVARS_HIGHSPEED,
+
+ STAT_LAST_MAIN
+};
+
+const int STAT_LAST = STAT_LAST_MAIN + 5;
/* The following stats change depending on the gamemode, so can share the same ID */
-// IDs 100 to 104 reserved for gamemodes
// freeze tag, clan arena, jailbreak
-const int STAT_REDALIVE = 100;
-const int STAT_BLUEALIVE = 101;
-const int STAT_YELLOWALIVE = 102;
-const int STAT_PINKALIVE = 103;
+enum {
+ STAT_REDALIVE = STAT_LAST_MAIN,
+ STAT_BLUEALIVE,
+ STAT_YELLOWALIVE,
+ STAT_PINKALIVE,
+};
// domination
-const int STAT_DOM_TOTAL_PPS = 100;
-const int STAT_DOM_PPS_RED = 101;
-const int STAT_DOM_PPS_BLUE = 102;
-const int STAT_DOM_PPS_YELLOW = 103;
-const int STAT_DOM_PPS_PINK = 104;
+enum {
+ STAT_DOM_TOTAL_PPS = STAT_LAST_MAIN,
+ STAT_DOM_PPS_RED,
+ STAT_DOM_PPS_BLUE,
+ STAT_DOM_PPS_YELLOW,
+ STAT_DOM_PPS_PINK,
+};
// vip
-const int STAT_VIP = 100;
-const int STAT_VIP_RED = 101;
-const int STAT_VIP_BLUE = 102;
-const int STAT_VIP_YELLOW = 103;
-const int STAT_VIP_PINK = 104;
+enum {
+ STAT_VIP = STAT_LAST_MAIN,
+ STAT_VIP_RED,
+ STAT_VIP_BLUE,
+ STAT_VIP_YELLOW,
+ STAT_VIP_PINK,
+};
// key hunt
-const int STAT_KH_REDKEY_TEAM = 100;
-const int STAT_KH_BLUEKEY_TEAM = 101;
-const int STAT_KH_YELLOWKEY_TEAM = 102;
-const int STAT_KH_PINKKEY_TEAM = 103;
+enum {
+ STAT_KH_REDKEY_TEAM = STAT_LAST_MAIN,
+ STAT_KH_BLUEKEY_TEAM,
+ STAT_KH_YELLOWKEY_TEAM,
+ STAT_KH_PINKKEY_TEAM,
+};
-/* Gamemode-specific stats end here */
+#define ASSERT_LESS(name, var, const) noref int name[(const - var + 1)];
+ASSERT_LESS(stat_limit, STAT_LAST, 220)
-const int STAT_PL_VIEW_OFS1 = 105;
-const int STAT_PL_VIEW_OFS2 = 106;
-const int STAT_PL_VIEW_OFS3 = 107;
-const int STAT_PL_MIN1 = 108;
-const int STAT_PL_MIN2 = 109;
-const int STAT_PL_MIN3 = 110;
-const int STAT_PL_MAX1 = 111;
-const int STAT_PL_MAX2 = 112;
-const int STAT_PL_MAX3 = 113;
-const int STAT_PL_CROUCH_MIN1 = 114;
-const int STAT_PL_CROUCH_MIN2 = 115;
-const int STAT_PL_CROUCH_MIN3 = 116;
-const int STAT_PL_CROUCH_MAX1 = 117;
-const int STAT_PL_CROUCH_MAX2 = 118;
-const int STAT_PL_CROUCH_MAX3 = 119;
-const int STAT_PL_CROUCH_VIEW_OFS1 = 117;
-const int STAT_PL_CROUCH_VIEW_OFS2 = 118;
-const int STAT_PL_CROUCH_VIEW_OFS3 = 119;
-const int STAT_WEAPONSINMAP = 120;
-const int STAT_WEAPONSINMAP2 = 121;
-const int STAT_WEAPONSINMAP3 = 122;
-const int STAT_BUFF_TIME = 123;
-const int STAT_CTF_FLAGSTATUS = 124;
-// 125 empty?
-// 126 empty?
-// 127 empty?
-// 128 empty?
-// 129 empty?
-// 130 empty?
-// 131 empty?
-// 132 empty?
-// 133 empty?
-// 134 empty?
-// 135 empty?
-// 136 empty?
-// 137 empty?
-// 138 empty?
-// 139 empty?
-// 140 reserved
-// 141 reserved
-// 142 reserved
-// 143 reserved
-// 144 reserved
-// 145 reserved
-// 146 reserved
-// 147 reserved
-// 148 reserved
-// 149 reserved
-// 150 reserved
-// 151 reserved
-// 152 reserved
-// 153 reserved
-// 154 reserved
-// 155 reserved
-// 156 empty?
-// 157 empty?
-// 158 empty?
-// 159 empty?
-// 160 empty?
-// 161 empty?
-// 162 empty?
-// 162 empty?
-// 163 empty?
-// 164 empty?
-// 165 empty?
-const int STAT_MULTIJUMP_DODGING = 166;
-const int STAT_MULTIJUMP_MAXSPEED = 167;
-const int STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND = 168;
-const int STAT_BUGRIGS_REVERSE_STOPPING = 169;
-const int STAT_BUGRIGS_REVERSE_SPINNING = 170;
-const int STAT_BUGRIGS_CAR_JUMPING = 171;
-const int STAT_BUGRIGS_FRICTION_AIR = 172;
-const int STAT_BUGRIGS_STEER = 173;
-const int STAT_BUGRIGS_SPEED_POW = 174;
-const int STAT_BUGRIGS_SPEED_REF = 175;
-const int STAT_BUGRIGS_ACCEL = 176;
-const int STAT_BUGRIGS_FRICTION_BRAKE = 177;
-const int STAT_BUGRIGS_AIR_STEERING = 178;
-const int STAT_BUGRIGS_FRICTION_FLOOR = 179;
-const int STAT_BUGRIGS_REVERSE_SPEEDING = 180;
-const int STAT_BUGRIGS_PLANAR_MOVEMENT = 181;
-const int STAT_BUGRIGS_ANGLE_SMOOTHING = 182;
-const int STAT_BUGRIGS = 183;
-const int STAT_GAMEPLAYFIX_STEPDOWN = 184;
-const int STAT_MOVEVARS_JUMPSTEP = 185;
-const int STAT_NOSTEP = 186;
-const int STAT_GAMEPLAYFIX_UNSTICKPLAYERS = 187;
-const int STAT_GAMEPLAYFIX_STEPMULTIPLETIMES = 188;
-const int STAT_GAMEPLAYFIX_DOWNTRACEONGROUND = 189;
-const int STAT_GAMEPLAYFIX_EASIERWATERJUMP = 190;
-const int STAT_MOVEVARS_FRICTION_SLICK = 191;
-const int STAT_MOVEVARS_FRICTION_ONLAND = 192;
-const int STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS = 193;
-const int STAT_MOVEVARS_TRACK_CANJUMP = 194;
-// 195 empty?
-const int STAT_DOUBLEJUMP = 196;
-const int STAT_MOVEVARS_CL_TRACK_CANJUMP = 197;
-const int STAT_MULTIJUMP_ADD = 198;
-const int STAT_MULTIJUMP_SPEED = 199;
-const int STAT_MULTIJUMP = 200;
-const int STAT_DODGING_TIMEOUT = 201;
-const int STAT_DODGING_WALL = 202;
-const int STAT_DODGING_UP_SPEED = 203;
-const int STAT_DODGING_RAMP_TIME = 204;
-const int STAT_DODGING_HEIGHT_THRESHOLD = 205;
-const int STAT_DODGING_DISTANCE_THRESHOLD = 206;
-const int STAT_DODGING_HORIZ_SPEED = 207;
-const int STAT_DODGING_DELAY = 208;
-const int STAT_DODGING_FROZEN_NO_DOUBLETAP = 209;
-const int STAT_DODGING_HORIZ_SPEED_FROZEN = 210;
-const int STAT_DODGING = 211;
-const int STAT_DODGING_FROZEN = 212;
-const int STAT_JETPACK_MAXSPEED_UP = 213;
-const int STAT_JETPACK_MAXSPEED_SIDE = 214;
-const int STAT_JETPACK_FUEL = 215;
-const int STAT_JETPACK_ANTIGRAVITY = 216;
-const int STAT_JETPACK_ACCEL_SIDE = 217;
-const int STAT_JETPACK_ACCEL_UP = 218;
-const int STAT_MOVEVARS_HIGHSPEED = 219;
const int STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR = 220;
const int STAT_MOVEVARS_AIRCONTROL_PENALTY = 221;
const int STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222;
return;
// wait for targets to spawn
- controller = spawn();
- controller.classname = "func_bobbing_controller";
+ controller = new(func_bobbing_controller);
controller.owner = self;
controller.nextthink = time + 1;
controller.think = func_bobbing_controller_think;
RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, world, self.dmg_force, DEATH_HURTTRIGGER.m_id, world);
if(self.cnt) // TODO
- pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
+ __pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
if(self.respawntime)
{
+REGISTER_NET_LINKED(ENT_CLIENT_CONVEYOR)
+
void conveyor_think()
{SELFPARAM();
#ifdef CSQC
bool conveyor_send(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_CONVEYOR);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_CONVEYOR);
WriteByte(MSG_ENTITY, sf);
if(sf & 1)
self.move_time = time;
}
-void ent_conveyor()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_CONVEYOR, bool isnew)
+{
float sf = ReadByte();
if(sf & 1)
if(sf & 2)
self.state = ReadByte();
+
+ return true;
}
#endif
+++ /dev/null
-#ifdef CSQC
-void ent_conveyor();
-#endif
}
}
+.float door_finished;
/*
================
{SELFPARAM();
if (!IS_PLAYER(other))
return;
- if (self.owner.attack_finished_single > time)
+ if (self.owner.door_finished > time)
return;
- self.owner.attack_finished_single = time + 2;
+ self.owner.door_finished = time + 2;
#ifdef SVQC
if (!(self.owner.dmg) && (self.owner.message != ""))
#endif
return;
- if (time < self.attack_finished_single)
+ if (time < self.door_finished)
return;
// check if door is locked
if (!door_check_keys(self, other))
return;
- self.attack_finished_single = time + 1;
+ self.door_finished = time + 1;
activator = other;
entity trigger;
vector t1 = fmins, t2 = fmaxs;
- trigger = spawn();
- trigger.classname = "doortriggerfield";
+ trigger = new(doortriggerfield);
trigger.movetype = MOVETYPE_NONE;
trigger.solid = SOLID_TRIGGER;
trigger.owner = self;
door_spawnfield(cmins, cmaxs);
}
+REGISTER_NET_LINKED(ENT_CLIENT_DOOR)
+
#ifdef SVQC
/*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
if two doors touch, they are assumed to be connected and operate as a unit.
float door_send(entity to, float sf)
{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_DOOR);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_DOOR);
WriteByte(MSG_ENTITY, sf);
if(sf & SF_TRIGGER_INIT)
trigger_draw_generic(this);
}
-void ent_door()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_DOOR, bool isnew)
+{
float sf = ReadByte();
if(sf & SF_TRIGGER_INIT)
self.pos2_y = ReadCoord();
self.pos2_z = ReadCoord();
}
+ return true;
}
#endif
#ifdef CSQC
// stuff for preload
-void ent_door();
-// abused
-.float attack_finished_single;
+.float door_finished;
#endif
_sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
}
+.float door_finished;
+
void secret_blocked()
{SELFPARAM();
- if (time < self.attack_finished_single)
+ if (time < self.door_finished)
return;
- self.attack_finished_single = time + 0.5;
+ self.door_finished = time + 0.5;
//T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
}
{SELFPARAM();
if (!other.iscreature)
return;
- if (self.attack_finished_single > time)
+ if (self.door_finished > time)
return;
- self.attack_finished_single = time + 2;
+ self.door_finished = time + 2;
if (self.message)
{
self.active = ACTIVE_ACTIVE;
// wait for targets to spawn
- controller = spawn();
- controller.classname = "func_fourier_controller";
+ controller = new(func_fourier_controller);
controller.owner = self;
controller.nextthink = time + 1;
controller.think = func_fourier_controller_think;
#ifndef TRIGGERS_FUNC_INCLUDE_H
#define TRIGGERS_FUNC_INCLUDE_H
-#include "conveyor.qh"
#include "door.qh"
#include "ladder.qh"
-#include "plat.qh"
-#include "rainsnow.qh"
-#include "pointparticles.qh"
#include "train.qh"
#endif
+REGISTER_NET_LINKED(ENT_CLIENT_LADDER)
+
void func_ladder_touch()
{SELFPARAM();
#ifdef SVQC
#ifdef SVQC
bool func_ladder_send(entity this, entity to, float sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_LADDER);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_LADDER);
WriteString(MSG_ENTITY, self.classname);
WriteByte(MSG_ENTITY, self.skin);
#elif defined(CSQC)
.float speed;
-void ent_func_ladder()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_LADDER, bool isnew)
+{
self.classname = strzone(ReadString());
self.skin = ReadByte();
self.speed = ReadByte();
self.model = strzone(ReadString());
trigger_common_read(false);
+
+ return = true;
+
self.mins = self.maxs = '0 0 0';
self.solid = SOLID_TRIGGER;
.float ladder_time;
.entity ladder_entity;
-
-#ifdef CSQC
-void ent_func_ladder();
-#endif
self.cnt = self.angles_z;
// wait for targets to spawn
- controller = spawn();
- controller.classname = "func_pendulum_controller";
+ controller = new(func_pendulum_controller);
controller.owner = self;
controller.nextthink = time + 1;
controller.think = func_pendulum_controller_think;
+REGISTER_NET_LINKED(ENT_CLIENT_PLAT)
+
#ifdef SVQC
void plat_link();
float plat_send(entity to, float sf)
{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_PLAT);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_PLAT);
WriteByte(MSG_ENTITY, sf);
if(sf & SF_TRIGGER_INIT)
//Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
}
-void ent_plat()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_PLAT, bool isnew)
+{
float sf = ReadByte();
if(sf & SF_TRIGGER_INIT)
self.move_angles = self.angles;
self.move_time = time;
}
+ return true;
}
#endif
+++ /dev/null
-#ifdef CSQC
-void ent_plat();
-#endif
-#ifdef CSQC
- #include "../../../client/particles.qh"
-#endif
+REGISTER_NET_LINKED(ENT_CLIENT_POINTPARTICLES)
#ifdef SVQC
// NOTE: also contains func_sparks
bool pointparticles_SendEntity(entity this, entity to, float fl)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
// optional features to save space
fl = fl & 0x0F;
}
#elif defined(CSQC)
+.int dphitcontentsmask;
+
+entityclass(PointParticles);
+class(PointParticles) .int cnt; // effect number
+class(PointParticles) .vector velocity; // particle velocity
+class(PointParticles) .float waterlevel; // direction jitter
+class(PointParticles) .int count; // count multiplier
+class(PointParticles) .int impulse; // density
+class(PointParticles) .string noise; // sound
+class(PointParticles) .float atten;
+class(PointParticles) .float volume;
+class(PointParticles) .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
+class(PointParticles) .vector movedir; // trace direction
+class(PointParticles) .float glow_color; // palette index
+
void Draw_PointParticles(entity this)
{
float n, i, fail;
{
traceline(p, p + normalize(self.movedir) * 4096, 0, world);
p = trace_endpos;
- pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
+ __pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
}
else
{
- pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
+ __pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
}
if(self.noise != "")
{
self.bgmscript = string_null;
}
-void Ent_PointParticles()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_POINTPARTICLES, bool isnew)
+{
float i;
vector v;
int f = ReadByte();
BGMScript_InitEntity(self);
}
+ return = true;
+
if(f & 2)
{
self.absolute = (self.impulse >= 0);
+++ /dev/null
-#ifdef CSQC
-
-void Ent_PointParticles();
-
-#endif
+REGISTER_NET_LINKED(ENT_CLIENT_RAINSNOW)
+
#ifdef SVQC
bool rainsnow_SendEntity(entity this, entity to, float sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
WriteByte(MSG_ENTITY, self.state);
WriteCoord(MSG_ENTITY, self.origin_x + self.mins_x);
WriteCoord(MSG_ENTITY, self.origin_y + self.mins_y);
te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
}
-void Ent_RainOrSnow()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_RAINSNOW, bool isnew)
+{
self.impulse = ReadByte(); // Rain, Snow, or Whatever
self.origin_x = ReadCoord();
self.origin_y = ReadCoord();
self.count = ReadShort() * 10;
self.glow_color = ReadByte(); // color
+ return = true;
+
self.mins = -0.5 * self.maxs;
self.maxs = 0.5 * self.maxs;
self.origin = self.origin - self.mins;
+++ /dev/null
-#ifdef CSQC
-void Ent_RainOrSnow();
-#endif
_sound(self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
}
+REGISTER_NET_LINKED(ENT_CLIENT_TRAIN)
+
#ifdef SVQC
float train_send(entity to, float sf)
{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_TRAIN);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_TRAIN);
WriteByte(MSG_ENTITY, sf);
if(sf & SF_TRIGGER_INIT)
Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
}
-void ent_train()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TRAIN, bool isnew)
+{
float sf = ReadByte();
if(sf & SF_TRIGGER_INIT)
{
// TODO: make a reset function for trains
}
+
+ return true;
}
#endif
#ifdef CSQC
.float dmgtime;
-void ent_train();
#endif
self.destvec = self.origin - func_vectormamamam_origin(self, 0);
entity controller;
- controller = spawn();
- controller.classname = "func_vectormamamam_controller";
+ controller = new(func_vectormamamam_controller);
controller.owner = self;
controller.nextthink = time + 1;
controller.think = func_vectormamamam_controller_think;
// func
#include "func/include.qh"
-// misc
-#include "misc/include.qh"
-
// target
#include "target/include.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_CORNER)
+
#ifdef SVQC
bool corner_send(entity to, int sf)
{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_CORNER);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_CORNER);
WriteString(MSG_ENTITY, self.platmovetype);
self.platmovetype = string_null;
}
-void ent_corner()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_CORNER, bool isnew)
+{
self.platmovetype = strzone(ReadString());
self.origin_x = ReadCoord();
self.wait = ReadByte();
+ return = true;
+
self.classname = "path_corner";
self.drawmask = MASK_NORMAL;
self.entremove = corner_remove;
+++ /dev/null
-#ifdef CSQC
-void ent_corner();
-#endif
-#include "include.qh"
-
#include "corner.qc"
#include "follow.qc"
#include "laser.qc"
+++ /dev/null
-#ifndef TRIGGERS_MISC_INCLUDE_H
-#define TRIGGERS_MISC_INCLUDE_H
-
-#include "corner.qh"
-#include "laser.qh"
-
-#endif
#if defined(CSQC)
- #include "../../buffs/all.qh"
#include "../../../lib/csqcmodel/interpolate.qh"
#include "../../../client/main.qh"
#include "../../../lib/csqcmodel/cl_model.qh"
#elif defined(SVQC)
#endif
+REGISTER_NET_LINKED(ENT_CLIENT_LASER)
+
#ifdef SVQC
.float modelscale;
void misc_laser_aim()
bool laser_SendEntity(entity this, entity to, float fl)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_LASER);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_LASER);
fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser
if(self.spawnflags & 2)
fl |= 0x80;
if (!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
{
if(self.cnt >= 0)
- pointparticles(self.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
+ __pointparticles(self.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
if(self.colormod != '0 0 0' && self.modelscale != 0)
adddynamiclight(trace_endpos + trace_plane_normal * 1, self.modelscale, self.colormod * 5);
}
}
-void Ent_Laser()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_LASER, bool isnew)
+{
InterpolateOrigin_Undo();
// 30 bytes, or 13 bytes for just moving
}
if(f & 4)
self.state = ReadByte();
+
+ return = true;
+
InterpolateOrigin_Note();
self.draw = Draw_Laser;
}
+++ /dev/null
-#ifdef CSQC
-void Ent_Laser();
-#endif
-void SUB_NullThink(void) { }
+void SUB_NullThink() { }
void() SUB_CalcMoveDone;
void() SUB_CalcAngleMoveDone;
==================
*/
.float friction;
-void SUB_Friction (void)
+void SUB_Friction ()
{SELFPARAM();
self.SUB_NEXTTHINK = time;
if(self.SUB_FLAGS & FL_ONGROUND)
}
}
-void SUB_SetFade_Think (void)
+void SUB_SetFade_Think ()
{SELFPARAM();
if(self.alpha == 0)
self.alpha = 1;
self.SUB_ORIGIN traveling at speed
===============
*/
-void SUB_CalcMoveDone (void)
+void SUB_CalcMoveDone ()
{SELFPARAM();
// After moving, set origin to exact final destination
}
.float platmovetype_turn;
-void SUB_CalcMove_controller_think (void)
+void SUB_CalcMove_controller_think ()
{SELFPARAM();
entity oldself;
float traveltime;
return;
}
- controller = spawn();
- controller.classname = "SUB_CalcMove_controller";
+ controller = new(SUB_CalcMove_controller);
controller.owner = self;
controller.platmovetype = self.platmovetype;
controller.platmovetype_start = self.platmovetype_start;
The calling function should make sure self.SUB_THINK is valid
===============
*/
-void SUB_CalcAngleMoveDone (void)
+void SUB_CalcAngleMoveDone ()
{SELFPARAM();
// After rotating, set angle to exact final angle
self.angles = self.finalangle;
#include "../../../server/defs.qh"
#endif
+REGISTER_NET_TEMP(TE_CSQC_TARGET_MUSIC)
+REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_MUSIC)
+
#ifdef SVQC
// values:
// when targetname is not set, THIS ONE is default
void target_music_sendto(float to, float is)
{SELFPARAM();
- WriteByte(to, SVC_TEMPENTITY);
- WriteByte(to, TE_CSQC_TARGET_MUSIC);
+ WriteHeader(to, TE_CSQC_TARGET_MUSIC);
WriteShort(to, num_for_edict(self));
WriteByte(to, self.volume * 255.0 * is);
WriteByte(to, self.fade_time * 16.0);
// when triggered, it is disabled/enabled for everyone
bool trigger_music_SendEntity(entity this, entity to, float sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
sf &= ~0x80;
if(self.cnt)
sf |= 0x80;
best = music_target;
if(music_trigger)
best = music_trigger;
- for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); ) if(e.noise)
+ for(e = world; (e = findfloat(e, enttype, NET_ENT_CLIENT_TRIGGER_MUSIC.m_id)); ) if(e.noise)
{
vol0 = e.lastvol;
if(getsoundtime(e, CH_BGM_SINGLE) < 0)
bgmtime = gettime(GETTIME_CDTRACK);
}
+NET_HANDLE(TE_CSQC_TARGET_MUSIC, bool isNew)
+{
+ Net_TargetMusic();
+ return true;
+}
+
void Net_TargetMusic()
{
int id = ReadShort();
string noi = ReadString();
entity e;
- for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); )
+ for(e = world; (e = findfloat(e, enttype, NET_ENT_CLIENT_TRIGGER_MUSIC.m_id)); )
{
if(e.count == id)
break;
if(!e)
{
e = spawn();
- e.enttype = ENT_CLIENT_TRIGGER_MUSIC;
+ e.enttype = NET_ENT_CLIENT_TRIGGER_MUSIC.m_id;
e.count = id;
}
if(e.noise != noi)
self.noise = string_null;
}
-void Ent_ReadTriggerMusic()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TRIGGER_MUSIC, bool isnew)
+{
int f = ReadByte();
if(f & 4)
{
self.cnt = 1;
self.think = Ent_TriggerMusic_Think;
self.nextthink = time;
+ return true;
}
#endif
void Ent_TriggerMusic_Remove();
-void Ent_ReadTriggerMusic();
-
#elif defined(SVQC)
void target_music_kill();
#endif
return e;
}
-void teleport_findtarget (void)
+void teleport_findtarget ()
{SELFPARAM();
entity e;
float n;
entity Simple_TeleportPlayer(entity teleporter, entity player);
-void Teleport_Touch (void);
+void Teleport_Touch ();
-void teleport_findtarget (void);
+void teleport_findtarget ();
entity Teleport_Find(vector mi, vector ma);
#endif
}
+REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_IMPULSE)
+
/*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
-------- KEYS --------
target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
#ifdef SVQC
bool trigger_impulse_send(entity to, int sf)
{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_IMPULSE);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_IMPULSE);
WriteCoord(MSG_ENTITY, self.radius);
WriteCoord(MSG_ENTITY, self.strength);
trigger_impulse_link();
}
#elif defined(CSQC)
-void ent_trigger_impulse()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TRIGGER_IMPULSE, bool isnew)
+{
self.radius = ReadCoord();
self.strength = ReadCoord();
self.falloff = ReadByte();
self.active = ReadByte();
trigger_common_read(true);
-
+ return = true;
self.classname = "trigger_impulse";
self.solid = SOLID_TRIGGER;
.float strength;
.float lastpushtime;
-#ifdef CSQC
-void ent_trigger_impulse();
-#endif
-
#endif
}
#endif
+REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_PUSH)
+REGISTER_NET_LINKED(ENT_CLIENT_TARGET_PUSH)
+
/*
trigger_push_calculatevelocity
#ifdef SVQC
float trigger_push_send(entity to, float sf)
{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH);
WriteByte(MSG_ENTITY, sf);
if(sf & 1)
bool target_push_send(entity this, entity to, float sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
WriteByte(MSG_ENTITY, self.cnt);
WriteString(MSG_ENTITY, self.targetname);
void target_push_link()
{SELFPARAM();
- Net_LinkEntity(self, false, 0, target_push_send);
- self.SendFlags |= 1; // update
+ //Net_LinkEntity(self, false, 0, target_push_send);
+ //self.SendFlags |= 1; // update
}
spawnfunc(target_push) { target_push_link(); }
spawnfunc(info_notnull) { target_push_link(); }
-spawnfunc(target_position) { target_push_link(); }
+spawnfunc(target_position) { make_pure(this); target_push_link(); }
#endif
#ifdef CSQC
-void ent_trigger_push()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TRIGGER_PUSH, bool isnew)
+{
float sf = ReadByte();
if(sf & 1)
self.team = ReadByte();
self.active = ReadByte();
}
+ return true;
}
void target_push_remove()
self.targetname = string_null;
}
-void ent_target_push()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TARGET_PUSH, bool isnew)
+{
self.classname = "push_target";
self.cnt = ReadByte();
self.targetname = strzone(ReadString());
self.origin_x = ReadCoord();
self.origin_y = ReadCoord();
self.origin_z = ReadCoord();
+
+ return = true;
+
setorigin(self, self.origin);
self.drawmask = MASK_NORMAL;
void trigger_push_use();
#endif
-#ifdef CSQC
-void ent_trigger_push();
-
-void ent_target_push();
-#endif
-
/*
trigger_push_calculatevelocity
}
+REGISTER_NET_LINKED(ENT_CLIENT_KEYLOCK)
+
#ifdef SVQC
bool trigger_keylock_send(entity to, int sf)
{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_KEYLOCK);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_KEYLOCK);
WriteInt24_t(MSG_ENTITY, self.itemkeys);
WriteByte(MSG_ENTITY, self.height);
if(self.sounds == 1)
self.noise = "misc/secret.wav";
else if(self.sounds == 2)
- self.noise = SND(TALK);
+ self.noise = strzone(SND(TALK));
else //if (self.sounds == 3) {
self.noise = "misc/trigger1.wav";
}
self.targetname = string_null;
}
-void ent_keylock()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_KEYLOCK, bool isnew)
+{
self.itemkeys = ReadInt24_t();
self.height = ReadByte();
trigger_common_read(true);
+ return = true;
+
self.classname = "trigger_keylock";
self.drawmask = MASK_NORMAL;
self.draw = trigger_draw_generic;
#ifdef CSQC
-void ent_keylock();
bool item_keys_usekey(entity l, entity p)
{
int valid = (l.itemkeys & p.itemkeys);
}
else if (self.sounds == 2)
{
- self.noise = SND(TALK);
+ self.noise = strzone(SND(TALK));
}
else if (self.sounds == 3)
{
#ifdef SVQC
spawnfunc(trigger_swamp);
#endif
-void swamp_touch(void);
+void swamp_touch();
void swampslug_think();
*
* I do it this way becuz there is no "untouch" event.
*/
-void swampslug_think(void)
+void swampslug_think()
{SELFPARAM();
//Slowly kill the slug
self.health = self.health - 1;
self.nextthink = time + self.swamp_interval;
}
-void swamp_touch(void)
+void swamp_touch()
{SELFPARAM();
// If whatever thats touching the swamp is not a player
// or if its a dead player, just dont care abt it.
other.swampslug.health = 2;
}
+REGISTER_NET_LINKED(ENT_CLIENT_SWAMP)
+
#ifdef SVQC
float swamp_send(entity to, float sf)
{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_LADDER);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_SWAMP);
WriteByte(MSG_ENTITY, self.dmg); // can probably get away with using a single byte here
WriteByte(MSG_ENTITY, self.swamp_slowdown);
#elif defined(CSQC)
-void ent_swamp()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_SWAMP, bool isnew)
+{
self.dmg = ReadByte();
self.swamp_slowdown = ReadByte();
self.swamp_interval = ReadByte();
trigger_common_read(false);
+ return = true;
+
self.classname = "trigger_swamp";
self.solid = SOLID_TRIGGER;
self.draw = trigger_draw_generic;
.float in_swamp; // bool
.entity swampslug; // Uses this to release from swamp ("untouch" fix)
-#ifdef CSQC
-void ent_swamp();
-#endif
-
#endif
#endif
}
-void Teleport_Touch (void)
+void Teleport_Touch ()
{SELFPARAM();
string s;
#include "../../../server/defs.qh"
#endif
+REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC)
+REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC_TRIGGER)
+
#ifdef SVQC
void viewloc_think()
bool trigger_viewloc_send(entity this, entity to, int sf)
{
// CSQC doesn't need to know our origin (yet), as we're only available for referencing
- WriteByte(MSG_ENTITY, ENT_CLIENT_VIEWLOC_TRIGGER);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC_TRIGGER);
WriteEntity(MSG_ENTITY, self.enemy);
WriteEntity(MSG_ENTITY, self.goalentity);
bool viewloc_send(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_VIEWLOC);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC);
WriteByte(MSG_ENTITY, self.cnt);
self.goalentity = findfloat(world, entnum, self.count);
}
-void ent_viewloc_trigger()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_VIEWLOC_TRIGGER, bool isnew)
+{
float point1 = ReadShort();
float point2 = ReadShort();
self.origin_x = ReadCoord();
self.origin_y = ReadCoord();
self.origin_z = ReadCoord();
+
+ return = true;
+
setorigin(self, self.origin);
self.cnt = point1;
self.drawmask = MASK_NORMAL; // not so concerned, but better keep it alive
}
-void ent_viewloc()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_VIEWLOC, bool isnew)
+{
self.cnt = ReadByte();
self.origin_x = ReadCoord();
self.movedir_y = ReadCoord();
self.movedir_z = ReadCoord();
+ return = true;
+
self.classname = ((self.cnt == 2) ? "target_viewlocation_end" : "target_viewlocation_start");
self.drawmask = MASK_NORMAL; // don't cull it
}
.entity goalentity;
.entity enemy;
.vector movedir;
-
-void ent_viewloc();
-void ent_viewloc_trigger();
#endif
#endif
if (self.delay)
{
// create a temp object to fire at a later time
- t = spawn();
- t.classname = "DelayedUse";
+ t = new(DelayedUse);
t.nextthink = time + self.delay;
t.think = DelayThink;
t.enemy = activator;
#include "all.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_TURRET)
+
#ifdef SVQC
#include "sv_turrets.qh"
#endif
-#ifdef CSQC
-#include "cl_turrets.qh"
-#endif
-
#define IMPLEMENTATION
#include "all.inc"
#undef IMPLEMENTATION
#include "turret.qh"
-REGISTRY(Turrets, BIT(5))
-REGISTER_REGISTRY(RegisterTurrets)
+REGISTRY(Turrets, BITS(5))
+#define Turrets_from(i) _Turrets_from(i, TUR_Null)
+#define get_turretinfo(i) Turrets_from(i)
+REGISTER_REGISTRY(Turrets)
+REGISTRY_CHECK(Turrets)
GENERIC_COMMAND(dumpturrets, "Dump all turrets into turrets_dump.txt")
const int TUR_FIRST = 1;
#define TUR_LAST (Turrets_COUNT - 1)
-#define REGISTER_TURRET(id, inst) REGISTER(RegisterTurrets, TUR, Turrets, id, m_id, inst)
+#define REGISTER_TURRET(id, inst) REGISTER(Turrets, TUR, id, m_id, inst)
REGISTER_TURRET(Null, NEW(Turret));
-Turret get_turretinfo(int id)
-{
- if (id >= TUR_FIRST && id <= TUR_LAST) {
- Turret t = Turrets[id];
- if (t) return t;
- }
- return TUR_Null;
-}
-
#include "all.inc"
#endif
if(self.health < 85)
if(dt < 0.01)
- pointparticles(particleeffectnum(EFFECT_SMOKE_LARGE), (self.origin + (randomvec() * 80)), '0 0 0', 1);
+ pointparticles(EFFECT_SMOKE_LARGE, (self.origin + (randomvec() * 80)), '0 0 0', 1);
if(self.health < 32)
if(dt < 0.015)
- pointparticles(particleeffectnum(EFFECT_SMOKE_SMALL), (self.origin + (randomvec() * 80)), '0 0 0', 1);
+ pointparticles(EFFECT_SMOKE_SMALL, (self.origin + (randomvec() * 80)), '0 0 0', 1);
}
float i;
sound (self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), self.origin, '0 0 0', 1);
+ pointparticles(EFFECT_ROCKET_EXPLODE, self.origin, '0 0 0', 1);
for (i = 1; i < 5; i = i + 1)
turret_gibtoss(strcat("models/turrets/head-gib", ftos(i), ".md3"), self.origin + '0 0 2', self.velocity + randomvec() * 700, '0 0 0', false);
if(trace_startsolid)
return world;
- gib = spawn();
+ gib = new(turret_gib);
setorigin(gib, _from);
_setmodel(gib, _model);
gib.colormod = _cmod;
gib.move_avelocity = prandomvec() * 32;
gib.move_time = time;
gib.damageforcescale = 1;
- gib.classname = "turret_gib";
return gib;
}
void turret_die()
{SELFPARAM();
sound (self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), self.origin, '0 0 0', 1);
+ pointparticles(EFFECT_ROCKET_EXPLODE, self.origin, '0 0 0', 1);
if (!autocvar_cl_nogibs)
{
// Base
setmodel(self.tur_head, MDL_Null);
}
-void ent_turret()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TURRET, bool isnew)
+{
float sf;
sf = ReadByte();
self.health = _tmp;
}
//self.enemy.health = self.health / 255;
+ return true;
}
+++ /dev/null
-#ifndef CL_TURRETS_H
-#define CL_TURRETS_H
-
-void ent_turret();
-
-#endif
return 0;
}
-void Dump_Turret_Settings(void)
+void Dump_Turret_Settings()
{
float x, totalsettings = 0;
FOREACH(Turrets, it != TUR_Null, LAMBDA({
#ifdef SVQC
-void Dump_Turret_Settings(void);
+void Dump_Turret_Settings();
float tur_config_file;
float tur_config_alsoprint;
if(self.aim_flags & TFL_AIM_SIMPLE)
return real_origin(self.enemy);
- mintime = max(self.attack_finished_single - time,0) + sys_frametime;
+ mintime = max(self.attack_finished_single[0] - time,0) + sys_frametime;
// Baseline
pre_pos = real_origin(self.enemy);
bool turret_send(entity this, entity to, float sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_TURRET);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_TURRET);
WriteByte(MSG_ENTITY, sf);
if(sf & TNSF_SETUP)
{
// Ready?
if (self.firecheck_flags & TFL_FIRECHECK_REFIRE)
- if (self.attack_finished_single > time) return 0;
+ if (self.attack_finished_single[0] > time) return 0;
// Special case: volly fire turret that has to fire a full volly if a shot was fired.
if (self.shoot_flags & TFL_SHOOT_VOLLYALWAYS)
Turret info = get_turretinfo(self.m_id);
info.tr_attack(info);
- self.attack_finished_single = time + self.shot_refire;
+ self.attack_finished_single[0] = time + self.shot_refire;
self.ammo -= self.shot_dmg;
self.volly_counter = self.volly_counter - 1;
self.enemy = world;
if (self.shot_volly > 1)
- self.attack_finished_single = time + self.shot_volly_refire;
+ self.attack_finished_single[0] = time + self.shot_volly_refire;
}
#ifdef TURRET_DEBUG
entity e = find(world, classname, "turret_manager");
if(!e)
{
- e = spawn();
- e.classname = "turret_manager";
+ e = new(turret_manager);
e.think = turrets_manager_think;
e.nextthink = time + 2;
}
self.nextthink = time + 1;
self.nextthink += turret_count * sys_frametime;
- self.tur_head = spawn();
+ self.tur_head = new(turret_head);
_setmodel(self.tur_head, tur.head_model);
setsize(self.tur_head, '0 0 0', '0 0 0');
setorigin(self.tur_head, '0 0 0');
setattachment(self.tur_head, self, "tag_head");
- self.tur_head.netname = self.tur_head.classname = "turret_head";
+ self.tur_head.netname = self.tur_head.classname;
self.tur_head.team = self.team;
self.tur_head.owner = self;
self.tur_head.takedamage = DAMAGE_NO;
}
ATTRIB(Turret, m_weapon, Weapon, WEP_Null)
+#ifdef SVQC
/** (SERVER) called when turret attacks */
METHOD(Turret, tr_attack, void(Turret this)) {
Weapon w = this.m_weapon;
- w.wr_think(w, self, true, false);
+ .entity weaponentity = weaponentities[0];
+ w.wr_think(w, self, weaponentity, 1);
}
+#endif
/** (ALL) */
METHOD(Turret, tr_config, void(Turret this)) {
// TODO
/* flags */ ATTRIB(EWheelAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(EWheelAttack, impulse, int, 5);
/* refname */ ATTRIB(EWheelAttack, netname, string, "turret_ewheel");
-/* wepname */ ATTRIB(EWheelAttack, message, string, _("eWheel"));
+/* wepname */ ATTRIB(EWheelAttack, m_name, string, _("eWheel"));
ENDCLASS(EWheelAttack)
REGISTER_WEAPON(EWHEEL, NEW(EWheelAttack));
#ifdef SVQC
void turret_initparams(entity);
-METHOD(EWheelAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(EWheelAttack_FIRE, W_Sound("electro_fire"));
+METHOD(EWheelAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+ if (fire & 1)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(EWheelAttack_FIRE), CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
}
turret_do_updates(actor);
/* flags */ ATTRIB(FlacAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(FlacAttack, impulse, int, 5);
/* refname */ ATTRIB(FlacAttack, netname, string, "turret_flac");
-/* wepname */ ATTRIB(FlacAttack, message, string, _("FLAC"));
+/* wepname */ ATTRIB(FlacAttack, m_name, string, _("FLAC"));
ENDCLASS(FlacAttack)
REGISTER_WEAPON(FLAC, NEW(FlacAttack));
#ifdef SVQC
void turret_flac_projectile_think_explode();
-METHOD(FlacAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(FlacAttack_FIRE, W_Sound("electro_fire"));
+METHOD(FlacAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+ if (fire & 1)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(FlacAttack_FIRE), CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
actor.tur_impacttime = 10;
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
}
turret_tag_fire_update();
#ifdef SVQC
bool turret_fusionreactor_firecheck()
{SELFPARAM();
- if (self.attack_finished_single > time)
+ if (self.attack_finished_single[0] > time)
return false;
if (self.enemy.deadflag != DEAD_NO)
/* flags */ ATTRIB(HellionAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(HellionAttack, impulse, int, 9);
/* refname */ ATTRIB(HellionAttack, netname, string, "turret_hellion");
-/* wepname */ ATTRIB(HellionAttack, message, string, _("Hellion"));
+/* wepname */ ATTRIB(HellionAttack, m_name, string, _("Hellion"));
ENDCLASS(HellionAttack)
REGISTER_WEAPON(HELLION, NEW(HellionAttack));
float autocvar_g_turrets_unit_hellion_shot_speed_max;
void turret_hellion_missile_think();
-METHOD(HellionAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(HellionAttack_FIRE, W_Sound("electro_fire"));
+METHOD(HellionAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+ if (fire & 1)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(HellionAttack_FIRE), CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
actor.shot_radius = 500;
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
}
if (!isPlayer) {
if (actor.tur_head.frame != 0)
/* flags */ ATTRIB(HunterKillerAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(HunterKillerAttack, impulse, int, 9);
/* refname */ ATTRIB(HunterKillerAttack, netname, string, "turret_hk");
-/* wepname */ ATTRIB(HunterKillerAttack, message, string, _("Hunter-Killer"));
+/* wepname */ ATTRIB(HunterKillerAttack, m_name, string, _("Hunter-Killer"));
ENDCLASS(HunterKillerAttack)
REGISTER_WEAPON(HK, NEW(HunterKillerAttack));
float autocvar_g_turrets_unit_hk_shot_speed_turnrate;
void turret_hk_missile_think();
-METHOD(HunterKillerAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+SOUND(HunterKillerAttack_FIRE, W_Sound("electro_fire"));
+METHOD(HunterKillerAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+ if (fire & 1)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(HunterKillerAttack_FIRE), CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
}
entity missile = turret_projectile(SND(ROCKET_FIRE), 6, 10, DEATH_TURRET_HK.m_id, PROJECTILE_ROCKET, FALSE, FALSE);
te_explosion (missile.origin);
/* flags */ ATTRIB(MachineGunTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(MachineGunTurretAttack, impulse, int, 9);
/* refname */ ATTRIB(MachineGunTurretAttack, netname, string, "turret_machinegun");
-/* wepname */ ATTRIB(MachineGunTurretAttack, message, string, _("Machinegun"));
+/* wepname */ ATTRIB(MachineGunTurretAttack, m_name, string, _("Machinegun"));
ENDCLASS(MachineGunTurretAttack)
REGISTER_WEAPON(TUR_MACHINEGUN, NEW(MachineGunTurretAttack));
#ifdef SVQC
void W_MachineGun_MuzzleFlash();
-
-METHOD(MachineGunTurretAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+SOUND(MachineGunTurretAttack_FIRE, W_Sound("electro_fire"));
+METHOD(MachineGunTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR(machinegun, sustained_refire))) {
+ if (fire & 1)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(machinegun, sustained_refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(MachineGunTurretAttack_FIRE), CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
- weapon_thinkf(actor, WFRAME_FIRE1, 0, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
}
fireBullet (actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_MACHINEGUN.m_id, 0);
W_MachineGun_MuzzleFlash();
/* flags */ ATTRIB(MLRSTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(MLRSTurretAttack, impulse, int, 9);
/* refname */ ATTRIB(MLRSTurretAttack, netname, string, "turret_mlrs");
-/* wepname */ ATTRIB(MLRSTurretAttack, message, string, _("MLRS"));
+/* wepname */ ATTRIB(MLRSTurretAttack, m_name, string, _("MLRS"));
ENDCLASS(MLRSTurretAttack)
REGISTER_WEAPON(TUR_MLRS, NEW(MLRSTurretAttack));
#ifdef IMPLEMENTATION
#ifdef SVQC
-
-METHOD(MLRSTurretAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+SOUND(MLRSTurretAttack_FIRE, W_Sound("electro_fire"));
+METHOD(MLRSTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR(machinegun, sustained_refire))) {
+ if (fire & 1)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(machinegun, sustained_refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(MLRSTurretAttack_FIRE), CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
actor.shot_radius = 500;
- weapon_thinkf(actor, WFRAME_FIRE1, 0, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
}
turret_tag_fire_update();
entity missile = turret_projectile(SND(ROCKET_FIRE), 6, 10, DEATH_TURRET_MLRS.m_id, PROJECTILE_ROCKET, TRUE, TRUE);
/* flags */ ATTRIB(PhaserTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(PhaserTurretAttack, impulse, int, 9);
/* refname */ ATTRIB(PhaserTurretAttack, netname, string, "turret_phaser");
-/* wepname */ ATTRIB(PhaserTurretAttack, message, string, _("Phaser"));
+/* wepname */ ATTRIB(PhaserTurretAttack, m_name, string, _("Phaser"));
ENDCLASS(PhaserTurretAttack)
REGISTER_WEAPON(PHASER, NEW(PhaserTurretAttack));
void beam_think();
.int fireflag;
-
-METHOD(PhaserTurretAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+SOUND(PhaserTurretAttack_FIRE, W_Sound("electro_fire"));
+METHOD(PhaserTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+ if (fire & 1)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(PhaserTurretAttack_FIRE), CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
actor.shot_speed = 1;
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
}
entity beam = spawn();
beam.ticrate = 0.1; //autocvar_sys_ticrate;
sound (beam, CH_SHOTS_SINGLE, SND_TUR_PHASER, VOL_BASE, ATTEN_NORM);
actor.fireflag = 1;
- beam.attack_finished_single = actor.attack_finished_single;
- actor.attack_finished_single = time; // + autocvar_sys_ticrate;
+ beam.attack_finished_single[0] = actor.attack_finished_single[0];
+ actor.attack_finished_single[0] = time; // + autocvar_sys_ticrate;
setattachment(beam,actor.tur_head, "tag_fire");
{SELFPARAM();
if ((time > self.cnt) || (self.owner.deadflag != DEAD_NO))
{
- self.owner.attack_finished_single = time + self.owner.shot_refire;
+ self.owner.attack_finished_single[0] = time + self.owner.shot_refire;
self.owner.fireflag = 2;
self.owner.tur_head.frame = 10;
sound (self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
self.nextthink = time + self.ticrate;
- self.owner.attack_finished_single = time + frametime;
+ self.owner.attack_finished_single[0] = time + frametime;
setself(self.owner);
FireImoBeam ( self.tur_shotorg,
self.tur_shotorg + self.tur_shotdir_updated * self.target_range,
}
else
{
- super.tr_attack(this);
+ SUPER(PlasmaTurret).tr_attack(this);
}
if (self.tur_head.frame == 0)
self.tur_head.frame = 1;
CLASS(PlasmaDualAttack, PlasmaAttack)
/* refname */ ATTRIB(PlasmaDualAttack, netname, string, "turret_plasma_dual");
-/* wepname */ ATTRIB(PlasmaDualAttack, message, string, _("Dual plasma"));
+/* wepname */ ATTRIB(PlasmaDualAttack, m_name, string, _("Dual plasma"));
ENDCLASS(PlasmaDualAttack)
REGISTER_WEAPON(PLASMA_DUAL, NEW(PlasmaDualAttack));
vector v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
WarpZone_TrailParticles(world, particleeffectnum(EFFECT_VAPORIZER(self.team)), self.tur_shotorg, v);
} else {
- super.vtblbase.tr_attack(this);
+ SUPER(PlasmaTurret).tr_attack(this);
}
self.tur_head.frame += 1;
}
/* flags */ ATTRIB(PlasmaAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(PlasmaAttack, impulse, int, 5);
/* refname */ ATTRIB(PlasmaAttack, netname, string, "turret_plasma");
-/* wepname */ ATTRIB(PlasmaAttack, message, string, _("Plasma"));
+/* wepname */ ATTRIB(PlasmaAttack, m_name, string, _("Plasma"));
ENDCLASS(PlasmaAttack)
REGISTER_WEAPON(PLASMA, NEW(PlasmaAttack));
#ifdef IMPLEMENTATION
#ifdef SVQC
-
-METHOD(PlasmaAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(PlasmaAttack_FIRE, W_Sound("electro_fire"));
+METHOD(PlasmaAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+ if (fire & 1)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(PlasmaAttack_FIRE), CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
}
entity missile = turret_projectile(SND(HAGAR_FIRE), 1, 0, DEATH_TURRET_PLASMA.m_id, PROJECTILE_ELECTRO_BEAM, true, true);
missile.missile_flags = MIF_SPLASH;
{
self.tur_head.avelocity = '0 180 0' * (self.ammo / self.shot_dmg);
- if(self.attack_finished_single > time)
+ if(self.attack_finished_single[0] > time)
return;
float f;
/* flags */ ATTRIB(TeslaCoilTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(TeslaCoilTurretAttack, impulse, int, 9);
/* refname */ ATTRIB(TeslaCoilTurretAttack, netname, string, "turret_tesla");
-/* wepname */ ATTRIB(TeslaCoilTurretAttack, message, string, _("Tesla Coil"));
+/* wepname */ ATTRIB(TeslaCoilTurretAttack, m_name, string, _("Tesla Coil"));
ENDCLASS(TeslaCoilTurretAttack)
REGISTER_WEAPON(TESLA, NEW(TeslaCoilTurretAttack));
#ifdef SVQC
entity toast(entity from, float range, float damage);
-METHOD(TeslaCoilTurretAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(TeslaCoilTurretAttack_FIRE, W_Sound("electro_fire"));
+METHOD(TeslaCoilTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+ if (fire & 1)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(TeslaCoilTurretAttack_FIRE), CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
}
float d = actor.shot_dmg;
actor.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_TEAMCHECK;
- actor.attack_finished_single = time + actor.shot_refire;
+ actor.attack_finished_single[0] = time + actor.shot_refire;
for (int i = 0; i < 10; ++i) {
d *= 0.75;
r *= 0.85;
te_explosion (org);
- rocket = spawn ();
+ rocket = new(walker_rocket);
setorigin(rocket, org);
sound (self, CH_WEAPON_A, SND_HAGAR_FIRE, VOL_BASE, ATTEN_NORM);
setsize (rocket, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
- rocket.classname = "walker_rocket";
rocket.owner = self;
rocket.bot_dodge = true;
rocket.bot_dodgerating = 50;
self.animflag = ANIM_MELEE;
}
}
- else if (self.tur_head.attack_finished_single < time)
+ else if (self.tur_head.attack_finished_single[0] < time)
{
if(self.tur_head.shot_volly)
{
self.tur_head.shot_volly = self.tur_head.shot_volly -1;
if(self.tur_head.shot_volly == 0)
- self.tur_head.attack_finished_single = time + (autocvar_g_turrets_unit_walker_rocket_refire);
+ self.tur_head.attack_finished_single[0] = time + (autocvar_g_turrets_unit_walker_rocket_refire);
else
- self.tur_head.attack_finished_single = time + 0.2;
+ self.tur_head.attack_finished_single[0] = time + 0.2;
if(self.tur_head.shot_volly > 1)
walker_fire_rocket(gettaginfo(self, gettagindex(self, "tag_rocket01")));
/* flags */ ATTRIB(WalkerTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(WalkerTurretAttack, impulse, int, 5);
/* refname */ ATTRIB(WalkerTurretAttack, netname, string, "turret_walker");
-/* wepname */ ATTRIB(WalkerTurretAttack, message, string, _("Walker"));
+/* wepname */ ATTRIB(WalkerTurretAttack, m_name, string, _("Walker"));
ENDCLASS(WalkerTurretAttack)
REGISTER_WEAPON(WALKER, NEW(WalkerTurretAttack));
#ifdef SVQC
-METHOD(WalkerTurretAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(WalkerTurretAttack_FIRE, W_Sound("electro_fire"));
+METHOD(WalkerTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
- if (fire1)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+ if (fire & 1)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, v_forward, false, 0, SND(WalkerTurretAttack_FIRE), CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
}
sound (actor, CH_WEAPON_A, SND_UZI_FIRE, VOL_BASE, ATTEN_NORM);
fireBullet (actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_WALK_GUN.m_id, 0);
void mark_error(vector where,float lifetime)
{
- entity err;
-
- err = spawn();
- err.classname = "error_marker";
+ entity err = new(error_marker);
setmodel(err, MDL_MARKER);
setorigin(err,where);
err.movetype = MOVETYPE_NONE;
void mark_info(vector where,float lifetime)
{
- entity err;
-
- err = spawn();
- err.classname = "info_marker";
+ entity err = spawn(info_marker);
setmodel(err, MDL_MARKER);
setorigin(err,where);
err.movetype = MOVETYPE_NONE;
entity mark_misc(vector where,float lifetime)
{
- entity err;
-
- err = spawn();
- err.classname = "mark_misc";
+ entity err = spawn(mark_misc);
setmodel(err, MDL_MARKER);
setorigin(err,where);
err.movetype = MOVETYPE_NONE;
}
}
-// converts a number to a string with the indicated number of decimals
-// works for up to 10 decimals!
-string ftos_decimals(float number, float decimals)
-{
- // inhibit stupid negative zero
- if(number == 0)
- number = 0;
- // we have sprintf...
- return sprintf("%.*f", decimals, number);
-}
-
-// Databases (hash tables)
-const float DB_BUCKETS = 8192;
-void db_save(float db, string pFilename)
-{
- float fh, i, n;
- fh = fopen(pFilename, FILE_WRITE);
- if(fh < 0)
- {
- LOG_INFO(strcat("^1Can't write DB to ", pFilename));
- return;
- }
- n = buf_getsize(db);
- fputs(fh, strcat(ftos(DB_BUCKETS), "\n"));
- for(i = 0; i < n; ++i)
- fputs(fh, strcat(bufstr_get(db, i), "\n"));
- fclose(fh);
-}
-
-int db_create()
-{
- return buf_create();
-}
-
-int db_load(string pFilename)
-{
- float db, fh, i, j, n;
- string l;
- db = buf_create();
- if(db < 0)
- return -1;
- fh = fopen(pFilename, FILE_READ);
- if(fh < 0)
- return db;
- l = fgets(fh);
- if(stof(l) == DB_BUCKETS)
- {
- i = 0;
- while((l = fgets(fh)))
- {
- if(l != "")
- bufstr_set(db, i, l);
- ++i;
- }
- }
- else
- {
- // different count of buckets, or a dump?
- // need to reorganize the database then (SLOW)
- //
- // note: we also parse the first line (l) in case the DB file is
- // missing the bucket count
- do
- {
- n = tokenizebyseparator(l, "\\");
- for(j = 2; j < n; j += 2)
- db_put(db, argv(j-1), uri_unescape(argv(j)));
- }
- while((l = fgets(fh)));
- }
- fclose(fh);
- return db;
-}
-
-void db_dump(float db, string pFilename)
-{
- float fh, i, j, n, m;
- fh = fopen(pFilename, FILE_WRITE);
- if(fh < 0)
- error(strcat("Can't dump DB to ", pFilename));
- n = buf_getsize(db);
- fputs(fh, "0\n");
- for(i = 0; i < n; ++i)
- {
- m = tokenizebyseparator(bufstr_get(db, i), "\\");
- for(j = 2; j < m; j += 2)
- fputs(fh, strcat("\\", argv(j-1), "\\", argv(j), "\n"));
- }
- fclose(fh);
-}
-
-void db_close(float db)
-{
- buf_del(db);
-}
-
-string db_get(float db, string pKey)
-{
- float h;
- h = crc16(false, pKey) % DB_BUCKETS;
- return uri_unescape(infoget(bufstr_get(db, h), pKey));
-}
-
-void db_put(float db, string pKey, string pValue)
-{
- float h;
- h = crc16(false, pKey) % DB_BUCKETS;
- bufstr_set(db, h, infoadd(bufstr_get(db, h), pKey, uri_escape(pValue)));
-}
-
-void db_test()
-{
- float db, i;
- LOG_INFO("LOAD...\n");
- db = db_load("foo.db");
- LOG_INFO("LOADED. FILL...\n");
- for(i = 0; i < DB_BUCKETS; ++i)
- db_put(db, ftos(random()), "X");
- LOG_INFO("FILLED. SAVE...\n");
- db_save(db, "foo.db");
- LOG_INFO("SAVED. CLOSE...\n");
- db_close(db);
- LOG_INFO("CLOSED.\n");
-}
-
-// Multiline text file buffers
-int buf_load(string pFilename)
-{
- float buf, fh, i;
- string l;
- buf = buf_create();
- if(buf < 0)
- return -1;
- fh = fopen(pFilename, FILE_READ);
- if(fh < 0)
- {
- buf_del(buf);
- return -1;
- }
- i = 0;
- while((l = fgets(fh)))
- {
- bufstr_set(buf, i, l);
- ++i;
- }
- fclose(fh);
- return buf;
-}
-
-void buf_save(float buf, string pFilename)
-{
- float fh, i, n;
- fh = fopen(pFilename, FILE_WRITE);
- if(fh < 0)
- error(strcat("Can't write buf to ", pFilename));
- n = buf_getsize(buf);
- for(i = 0; i < n; ++i)
- fputs(fh, strcat(bufstr_get(buf, i), "\n"));
- fclose(fh);
-}
-
-string format_time(float seconds)
-{
- float days, hours, minutes;
- seconds = floor(seconds + 0.5);
- days = floor(seconds / 864000);
- seconds -= days * 864000;
- hours = floor(seconds / 36000);
- seconds -= hours * 36000;
- minutes = floor(seconds / 600);
- seconds -= minutes * 600;
- if (days > 0)
- return sprintf(_("%d days, %02d:%02d:%02d"), days, hours, minutes, seconds);
- else
- return sprintf(_("%02d:%02d:%02d"), hours, minutes, seconds);
-}
-
-string mmsss(float tenths)
-{
- float minutes;
- string s;
- tenths = floor(tenths + 0.5);
- minutes = floor(tenths / 600);
- tenths -= minutes * 600;
- s = ftos(1000 + tenths);
- return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 1));
-}
-
-string mmssss(float hundredths)
-{
- float minutes;
- string s;
- hundredths = floor(hundredths + 0.5);
- minutes = floor(hundredths / 6000);
- hundredths -= minutes * 6000;
- s = ftos(10000 + hundredths);
- return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 2));
-}
-
string ScoreString(int pFlags, float pValue)
{
string valstr;
return order;
}
-float cvar_value_issafe(string s)
-{
- if(strstrofs(s, "\"", 0) >= 0)
- return 0;
- if(strstrofs(s, "\\", 0) >= 0)
- return 0;
- if(strstrofs(s, ";", 0) >= 0)
- return 0;
- if(strstrofs(s, "$", 0) >= 0)
- return 0;
- if(strstrofs(s, "\r", 0) >= 0)
- return 0;
- if(strstrofs(s, "\n", 0) >= 0)
- return 0;
- return 1;
-}
-
#ifndef MENUQC
void get_mi_min_max(float mode)
{
if(created_saved_value != -1)
{
// creating a new entity to keep track of this cvar
- e = spawn();
- e.classname = "saved_cvar_value";
+ e = new(saved_cvar_value);
+ make_pure(e);
e.netname = strzone(tmp_cvar);
e.message = strzone(cvar_string(tmp_cvar));
created_saved_value = 1;
return i;
}
-float rgb_mi_ma_to_hue(vector rgb, float mi, float ma)
-{
- if(mi == ma)
- return 0;
- else if(ma == rgb.x)
- {
- if(rgb.y >= rgb.z)
- return (rgb.y - rgb.z) / (ma - mi);
- else
- return (rgb.y - rgb.z) / (ma - mi) + 6;
- }
- else if(ma == rgb.y)
- return (rgb.z - rgb.x) / (ma - mi) + 2;
- else // if(ma == rgb_z)
- return (rgb.x - rgb.y) / (ma - mi) + 4;
-}
-
-vector hue_mi_ma_to_rgb(float hue, float mi, float ma)
-{
- vector rgb;
-
- hue -= 6 * floor(hue / 6);
-
- //else if(ma == rgb_x)
- // hue = 60 * (rgb_y - rgb_z) / (ma - mi);
- if(hue <= 1)
- {
- rgb.x = ma;
- rgb.y = hue * (ma - mi) + mi;
- rgb.z = mi;
- }
- //else if(ma == rgb_y)
- // hue = 60 * (rgb_z - rgb_x) / (ma - mi) + 120;
- else if(hue <= 2)
- {
- rgb.x = (2 - hue) * (ma - mi) + mi;
- rgb.y = ma;
- rgb.z = mi;
- }
- else if(hue <= 3)
- {
- rgb.x = mi;
- rgb.y = ma;
- rgb.z = (hue - 2) * (ma - mi) + mi;
- }
- //else // if(ma == rgb_z)
- // hue = 60 * (rgb_x - rgb_y) / (ma - mi) + 240;
- else if(hue <= 4)
- {
- rgb.x = mi;
- rgb.y = (4 - hue) * (ma - mi) + mi;
- rgb.z = ma;
- }
- else if(hue <= 5)
- {
- rgb.x = (hue - 4) * (ma - mi) + mi;
- rgb.y = mi;
- rgb.z = ma;
- }
- //else if(ma == rgb_x)
- // hue = 60 * (rgb_y - rgb_z) / (ma - mi);
- else // if(hue <= 6)
- {
- rgb.x = ma;
- rgb.y = mi;
- rgb.z = (6 - hue) * (ma - mi) + mi;
- }
-
- return rgb;
-}
-
-vector rgb_to_hsv(vector rgb)
-{
- float mi, ma;
- vector hsv;
-
- mi = min(rgb.x, rgb.y, rgb.z);
- ma = max(rgb.x, rgb.y, rgb.z);
-
- hsv.x = rgb_mi_ma_to_hue(rgb, mi, ma);
- hsv.z = ma;
-
- if(ma == 0)
- hsv.y = 0;
- else
- hsv.y = 1 - mi/ma;
-
- return hsv;
-}
-
-vector hsv_to_rgb(vector hsv)
-{
- return hue_mi_ma_to_rgb(hsv.x, hsv.z * (1 - hsv.y), hsv.z);
-}
-
-vector rgb_to_hsl(vector rgb)
-{
- float mi, ma;
- vector hsl;
-
- mi = min(rgb.x, rgb.y, rgb.z);
- ma = max(rgb.x, rgb.y, rgb.z);
-
- hsl.x = rgb_mi_ma_to_hue(rgb, mi, ma);
-
- hsl.z = 0.5 * (mi + ma);
- if(mi == ma)
- hsl.y = 0;
- else if(hsl.z <= 0.5)
- hsl.y = (ma - mi) / (2*hsl.z);
- else // if(hsl_z > 0.5)
- hsl.y = (ma - mi) / (2 - 2*hsl.z);
-
- return hsl;
-}
-
-vector hsl_to_rgb(vector hsl)
-{
- float mi, ma, maminusmi;
-
- if(hsl.z <= 0.5)
- maminusmi = hsl.y * 2 * hsl.z;
- else
- maminusmi = hsl.y * (2 - 2 * hsl.z);
-
- // hsl_z = 0.5 * mi + 0.5 * ma
- // maminusmi = - mi + ma
- mi = hsl.z - 0.5 * maminusmi;
- ma = hsl.z + 0.5 * maminusmi;
-
- return hue_mi_ma_to_rgb(hsl.x, mi, ma);
-}
-
-string rgb_to_hexcolor(vector rgb)
-{
- return
- strcat(
- "^x",
- DEC_TO_HEXDIGIT(floor(rgb.x * 15 + 0.5)),
- DEC_TO_HEXDIGIT(floor(rgb.y * 15 + 0.5)),
- DEC_TO_HEXDIGIT(floor(rgb.z * 15 + 0.5))
- );
-}
-
float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLengthUpToWidth_widthFunction_t w)
{
// STOP.
return 1;
}
-vector solve_quadratic(float a, float b, float c) // ax^2 + bx + c = 0
-{
- vector v;
- float D;
- v = '0 0 0';
- if(a == 0)
- {
- if(b != 0)
- {
- v.x = v.y = -c / b;
- v.z = 1;
- }
- else
- {
- if(c == 0)
- {
- // actually, every number solves the equation!
- v.z = 1;
- }
- }
- }
- else
- {
- D = b*b - 4*a*c;
- if(D >= 0)
- {
- D = sqrt(D);
- if(a > 0) // put the smaller solution first
- {
- v.x = ((-b)-D) / (2*a);
- v.y = ((-b)+D) / (2*a);
- }
- else
- {
- v.x = (-b+D) / (2*a);
- v.y = (-b-D) / (2*a);
- }
- v.z = 1;
- }
- else
- {
- // complex solutions!
- D = sqrt(-D);
- v.x = -b / (2*a);
- if(a > 0)
- v.y = D / (2*a);
- else
- v.y = -D / (2*a);
- v.z = 0;
- }
- }
- return v;
-}
-
vector solve_shotdirection(vector myorg, vector myvel, vector eorg, vector evel, float spd, float newton_style)
{
vector ret;
return argv(n - 1);
}
-// from the GNU Scientific Library
-float gsl_ran_gaussian_lastvalue;
-float gsl_ran_gaussian_lastvalue_set;
-float gsl_ran_gaussian(float sigma)
-{
- float a, b;
- if(gsl_ran_gaussian_lastvalue_set)
- {
- gsl_ran_gaussian_lastvalue_set = 0;
- return sigma * gsl_ran_gaussian_lastvalue;
- }
- else
- {
- a = random() * 2 * M_PI;
- b = sqrt(-2 * log(random()));
- gsl_ran_gaussian_lastvalue = cos(a) * b;
- gsl_ran_gaussian_lastvalue_set = 1;
- return sigma * sin(a) * b;
- }
-}
-
float matchacl(string acl, string str)
{
string t, s;
return 1;
}
-float vercmp_recursive(string v1, string v2)
-{
- float dot1, dot2;
- string s1, s2;
- float r;
-
- dot1 = strstrofs(v1, ".", 0);
- dot2 = strstrofs(v2, ".", 0);
- if(dot1 == -1)
- s1 = v1;
- else
- s1 = substring(v1, 0, dot1);
- if(dot2 == -1)
- s2 = v2;
- else
- s2 = substring(v2, 0, dot2);
-
- r = stof(s1) - stof(s2);
- if(r != 0)
- return r;
-
- r = strcasecmp(s1, s2);
- if(r != 0)
- return r;
-
- if(dot1 == -1)
- if(dot2 == -1)
- return 0;
- else
- return -1;
- else
- if(dot2 == -1)
- return 1;
- else
- return vercmp_recursive(substring(v1, dot1 + 1, 999), substring(v2, dot2 + 1, 999));
-}
-
-float vercmp(string v1, string v2)
-{
- if(strcasecmp(v1, v2) == 0) // early out check
- return 0;
-
- // "git" beats all
- if(v1 == "git")
- return 1;
- if(v2 == "git")
- return -1;
-
- return vercmp_recursive(v1, v2);
-}
-
// x-encoding (encoding as zero length invisible string)
const string XENCODE_2 = "xX";
const string XENCODE_22 = "0123456789abcdefABCDEF";
return strcat(substring(input, 0, (strlen(input) - strlen(truncation))), truncation);
}*/
-#ifdef CSQC
-entity ReadCSQCEntity()
-{
- int f = ReadShort();
- if(f == 0)
- return world;
- return findfloat(world, entnum, f);
-}
-#endif
-
float shutdown_running;
#ifdef SVQC
void SV_Shutdown()
cvar_settemp_restore(); // this must be done LAST, but in any case
}
-const float APPROXPASTTIME_ACCURACY_REQUIREMENT = 0.05;
-#define APPROXPASTTIME_MAX (16384 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
-#define APPROXPASTTIME_RANGE (64 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
-// this will use the value:
-// 128
-// accuracy near zero is APPROXPASTTIME_MAX/(256*255)
-// accuracy at x is 1/derivative, i.e.
-// APPROXPASTTIME_MAX * (1 + 256 * (dt / APPROXPASTTIME_MAX))^2 / 65536
-#ifdef SVQC
-void WriteApproxPastTime(float dst, float t)
-{
- float dt = time - t;
-
- // warning: this is approximate; do not resend when you don't have to!
- // be careful with sendflags here!
- // we want: 0 -> 0.05, 1 -> 0.1, ..., 255 -> 12.75
-
- // map to range...
- dt = 256 * (dt / ((APPROXPASTTIME_MAX / 256) + dt));
-
- // round...
- dt = rint(bound(0, dt, 255));
-
- WriteByte(dst, dt);
-}
-#endif
-#ifdef CSQC
-float ReadApproxPastTime()
-{
- float dt = ReadByte();
-
- // map from range...PPROXPASTTIME_MAX / 256
- dt = (APPROXPASTTIME_MAX / 256) * (dt / (256 - dt));
-
- return servertime - dt;
-}
-#endif
-
#ifndef MENUQC
.float skeleton_bones_index;
void Skeleton_SetBones(entity e)
float power2of(float e);
float log2of(float x);
-const string HEXDIGITS = "0123456789ABCDEF0123456789abcdef";
-#define HEXDIGIT_TO_DEC_RAW(d) (strstrofs(HEXDIGITS, (d), 0))
-#define HEXDIGIT_TO_DEC(d) ((HEXDIGIT_TO_DEC_RAW(d) | 0x10) - 0x10)
-#define DEC_TO_HEXDIGIT(d) (substring(HEXDIGITS, (d), 1))
-
vector rgb_to_hsl(vector rgb);
vector hsl_to_rgb(vector hsl);
vector rgb_to_hsv(vector rgb);
float gsl_ran_gaussian(float sigma);
-string car(string s); // returns first word
-string cdr(string s); // returns all but first word
float matchacl(string acl, string str); // matches str against ACL acl (with entries +foo*, +foo, +*foo, +*foo*, and same with - for forbidding)
-float startsWith(string haystack, string needle);
-float startsWithNocase(string haystack, string needle);
string get_model_datafilename(string mod, float skn, string fil); // skin -1 will return wildcard, mod string_null will also put wildcard there
string get_model_parameters_modelname;
string xencode(float f);
float xdecode(string s);
-#ifdef CSQC
-entity ReadCSQCEntity();
-#endif
-
#ifndef MENUQC
string strtolower(string s);
#endif
#define normal_or_gentle(normal, gentle) (GENTLE ? ((gentle != "") ? gentle : normal) : normal)
#endif
-// allow writing to also pass through to spectators (like so spectators see the same centerprints as players for example)
-#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
-#define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
-#define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
-
vector vec3(float x, float y, float z);
#ifndef MENUQC
}
#endif
+REGISTER_NET_LINKED(ENT_CLIENT_AUXILIARYXHAIR)
+
#if defined(SVQC)
#include "sv_vehicles.qc"
#elif defined(CSQC)
#include "vehicle.qh"
-REGISTRY(Vehicles, BIT(3))
-REGISTER_REGISTRY(RegisterVehicles)
+REGISTRY(Vehicles, BITS(3))
+#define Vehicles_from(i) _Vehicles_from(i, VEH_Null)
+#define get_vehicleinfo(i) Vehicles_from(i)
+REGISTER_REGISTRY(Vehicles)
+REGISTRY_CHECK(Vehicles)
+
const int VEH_FIRST = 1;
#define VEH_LAST (Vehicles_COUNT - 1)
/** If you register a new vehicle, make sure to add it to all.inc */
-#define REGISTER_VEHICLE(id, inst) REGISTER(RegisterVehicles, VEH, Vehicles, id, vehicleid, inst)
+#define REGISTER_VEHICLE(id, inst) REGISTER(Vehicles, VEH, id, vehicleid, inst)
#if defined(SVQC)
#include "sv_vehicles.qh"
REGISTER_VEHICLE(Null, NEW(Vehicle));
-Vehicle get_vehicleinfo(int id)
-{
- if (id >= VEH_FIRST && id <= VEH_LAST) {
- Vehicle v = Vehicles[id];
- if (v) return v;
- }
- return VEH_Null;
-}
-
#include "all.inc"
#endif
self.draw2d = func_null;
}
-void Net_AuXair2(bool bIsNew)
+NET_HANDLE(ENT_CLIENT_AUXILIARYXHAIR, bool isnew)
{
int axh_id = bound(0, ReadByte(), MAX_AXH);
entity axh = AuxiliaryXhair[axh_id];
axh.colormod_z = ReadByte() / 255;
axh.cnt = time;
axh.draw2d = AuxiliaryXhair_Draw2D;
+ return true;
}
-void Net_VehicleSetup()
-{SELFPARAM();
+NET_HANDLE(TE_CSQC_VEHICLESETUP, bool isnew)
+{
int hud_id = ReadByte();
+ return = true;
// hud_id == 0 means we exited a vehicle, so stop alarm sound/s
if(hud_id == 0)
vector vehicleHud_Size;
vector vehicleHud_Pos;
-void Net_AuXair2(float bIsNew);
-
-void Net_VehicleSetup();
-
void RaptorCBShellfragDraw(entity this);
void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang);
bool SendAuxiliaryXhair(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
WriteByte(MSG_ENTITY, self.cnt);
msg_entity = own;
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_VEHICLESETUP);
+ WriteHeader(MSG_ONE, TE_CSQC_VEHICLESETUP);
WriteByte(MSG_ONE, vehicle_id);
}
void vehicles_clearreturn(entity veh)
{
- entity ret;
// Remove "return helper", if any.
- ret = findchain(classname, "vehicle_return");
- while(ret)
+ for (entity ret = findchain(classname, "vehicle_return"); ret; ret = ret.chain)
{
if(ret.wp00 == veh)
{
return;
}
- ret = ret.chain;
}
}
vehicles_clearreturn(veh);
- ret = spawn();
- ret.classname = "vehicle_return";
+ ret = new(vehicle_return);
ret.wp00 = veh;
ret.team = veh.team;
ret.think = vehicles_showwp;
float _ftmp;
_ftmp = self.owner.vehicle_health / 50;
self.pain_frame = time + 0.1 + (random() * 0.5 * _ftmp);
- pointparticles(particleeffectnum(EFFECT_SMOKE_SMALL), (self.origin + (randomvec() * 80)), '0 0 0', 1);
+ pointparticles(EFFECT_SMOKE_SMALL, (self.origin + (randomvec() * 80)), '0 0 0', 1);
if(self.vehicle_flags & VHF_DMGSHAKE)
self.velocity += randomvec() * 30;
self.vehicle_flags |= VHF_ISVEHICLE;
- self.vehicle_viewport = spawn();
- self.vehicle_hudmodel = spawn();
- self.tur_head = spawn();
+ self.vehicle_viewport = new(vehicle_viewport);
+ self.vehicle_hudmodel = new(vehicle_hudmodel);
+ self.tur_head = new(tur_head);
self.tur_head.owner = self;
self.takedamage = DAMAGE_NO;
self.bot_attack = true;
if(!forbidWeaponUse(gunner))
if(gunner.BUTTON_ATCK)
- if(time > gun.attack_finished_single)
+ if(time > gun.attack_finished_single[0])
if(gun.vehicle_energy >= autocvar_g_vehicle_bumblebee_cannon_cost)
{
gun.vehicle_energy -= autocvar_g_vehicle_bumblebee_cannon_cost;
bumblebee_fire_cannon(gun, "fire", gunner);
gun.delay = time;
- gun.attack_finished_single = time + autocvar_g_vehicle_bumblebee_cannon_refire;
+ gun.attack_finished_single[0] = time + autocvar_g_vehicle_bumblebee_cannon_refire;
}
VEHICLE_UPDATE_PLAYER(gunner, health, bumblebee);
self.vehicle_shieldent.alpha = -1;
self.vehicle_shieldent.effects = EF_LOWPRECISION | EF_NODRAW;
- self.gun1 = spawn();
- self.gun2 = spawn();
- self.gun3 = spawn();
+ self.gun1 = new(vehicle_playerslot);
+ self.gun2 = new(vehicle_playerslot);
+ self.gun3 = new(bumblebee_raygun);
self.vehicle_flags |= VHF_MULTISLOT;
self.gun2.owner = self;
self.gun3.owner = self;
- self.gun1.classname = self.gun2.classname = "vehicle_playerslot";
-
setmodel(self.gun1, MDL_VEH_BUMBLEBEE_CANNON_RIGHT);
setmodel(self.gun2, MDL_VEH_BUMBLEBEE_CANNON_LEFT);
setmodel(self.gun3, MDL_VEH_BUMBLEBEE_CANNON_CENTER);
#define BUMBLEBEE_H
#ifdef CSQC
-void bumble_raygun_read(bool bIsNew);
void CSQC_BUMBLE_GUN_HUD();
#endif
#ifdef IMPLEMENTATION
+REGISTER_NET_LINKED(ENT_CLIENT_BUMBLE_RAYGUN)
+
#ifdef SVQC
float autocvar_g_vehicle_bumblebee_cannon_cost;
bool bumble_raygun_send(entity this, entity to, float sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_BUMBLE_RAYGUN);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_BUMBLE_RAYGUN);
WriteByte(MSG_ENTITY, sf);
if(sf & BRG_SETUP)
void bumble_raygun_draw(entity this);
-void bumble_raygun_read(bool bIsNew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_BUMBLE_RAYGUN, bool isnew)
+{
int sf = ReadByte();
if(sf & BRG_SETUP)
self.move_origin_y = ReadCoord();
self.move_origin_z = ReadCoord();
}
+ return true;
}
+.float bumble_raygun_nextdraw;
void bumble_raygun_draw(entity this)
{
float _len;
_len = vlen(self.origin - self.move_origin);
_dir = normalize(self.move_origin - self.origin);
- if(self.total_damages < time)
+ if(self.bumble_raygun_nextdraw < time)
{
- boxparticles(particleeffectnum(Effects[self.traileffect]), self, self.origin, self.origin + _dir * -64, _dir * -_len , _dir * -_len, 1, PARTICLES_USEALPHA);
+ boxparticles(particleeffectnum(Effects_from(self.traileffect)), self, self.origin, self.origin + _dir * -64, _dir * -_len , _dir * -_len, 1, PARTICLES_USEALPHA);
boxparticles(self.lip, self, self.move_origin, self.move_origin + _dir * -64, _dir * -200 , _dir * -200, 1, PARTICLES_USEALPHA);
- self.total_damages = time + 0.1;
+ self.bumble_raygun_nextdraw = time + 0.1;
}
float i, df, sz, al;
self.angles_z *= 1 - (autocvar_g_vehicle_racer_anglestabilizer * _delta);
}
-void racer_fire_rocket_aim(string tagname, entity trg)
+void racer_fire_rocket_aim(entity player, string tagname, entity trg)
{
- SELFPARAM();
- vector v = gettaginfo(self, gettagindex(self, tagname));
- racer_fire_rocket(v, v_forward, trg);
+ entity racer = player.vehicle;
+ vector v = gettaginfo(racer, gettagindex(racer, tagname));
+ racer_fire_rocket(player, v, v_forward, trg);
}
float racer_frame()
{
#ifdef SVQC
if(time - racer.wait > 0.2)
- pointparticles(particleeffectnum(EFFECT_RACER_BOOSTER), self.origin - v_forward * 32, v_forward * vlen(self.velocity), 1);
+ pointparticles(EFFECT_RACER_BOOSTER, self.origin - v_forward * 32, v_forward * vlen(self.velocity), 1);
#endif
racer.wait = time;
{
traceline(racer.origin, racer.origin - '0 0 256', MOVE_NORMAL, self);
if(trace_fraction != 1.0)
- pointparticles(particleeffectnum(EFFECT_SMOKE_SMALL), trace_endpos, '0 0 0', 1);
+ pointparticles(EFFECT_SMOKE_SMALL, trace_endpos, '0 0 0', 1);
racer.invincible_finished = time + 0.1 + (random() * 0.1);
}
// Fix z-aim (for chase mode)
crosshair_trace(player);
w_shotdir.z = normalize(trace_endpos - org).z * 0.5;
- wep1.wr_think(wep1, self, true, false);
+ .entity weaponentity = weaponentities[0];
+ wep1.wr_think(wep1, self, weaponentity, 1);
}
if(autocvar_g_vehicle_racer_rocket_locktarget)
if(racer.misc_bulletcounter == 1)
{
- racer_fire_rocket_aim("tag_rocket_r", (racer.lock_strength == 1 && racer.lock_target) ? racer.lock_target : world);
+ racer_fire_rocket_aim(player, "tag_rocket_r", (racer.lock_strength == 1 && racer.lock_target) ? racer.lock_target : world);
player.vehicle_ammo2 = 50;
}
else if(racer.misc_bulletcounter == 2)
{
- racer_fire_rocket_aim("tag_rocket_l", (racer.lock_strength == 1 && racer.lock_target) ? racer.lock_target : world);
+ racer_fire_rocket_aim(player, "tag_rocket_l", (racer.lock_strength == 1 && racer.lock_target) ? racer.lock_target : world);
racer.lock_strength = 0;
racer.lock_target = world;
racer.misc_bulletcounter = 0;
/* flags */ ATTRIB(RacerAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(RacerAttack, impulse, int, 3);
/* refname */ ATTRIB(RacerAttack, netname, string, "racercannon");
-/* wepname */ ATTRIB(RacerAttack, message, string, _("Racer cannon"));
+/* wepname */ ATTRIB(RacerAttack, m_name, string, _("Racer cannon"));
ENDCLASS(RacerAttack)
REGISTER_WEAPON(RACER, NEW(RacerAttack));
// TODO: move into implementation
#ifdef SVQC
float autocvar_g_vehicle_racer_rocket_refire;
-void racer_fire_rocket(vector org, vector dir, entity trg);
+void racer_fire_rocket(entity player, vector org, vector dir, entity trg);
#endif
#endif
float autocvar_g_vehicle_racer_rocket_climbspeed;
float autocvar_g_vehicle_racer_rocket_locked_maxangle;
-void racer_fire_rocket(vector org, vector dir, entity trg);
-METHOD(RacerAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+void racer_fire_rocket(entity player, vector org, vector dir, entity trg);
+METHOD(RacerAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
bool isPlayer = IS_PLAYER(actor);
entity player = isPlayer ? actor : actor.owner;
entity veh = player.vehicle;
- if (fire1)
- if (weapon_prepareattack(thiswep, player, false, autocvar_g_vehicle_racer_cannon_refire)) {
+ if (fire & 1)
+ if (weapon_prepareattack(thiswep, player, weaponentity, false, autocvar_g_vehicle_racer_cannon_refire)) {
if (veh) {
veh.vehicle_energy -= autocvar_g_vehicle_racer_cannon_cost;
veh.wait = time;
autocvar_g_vehicle_racer_cannon_damage, autocvar_g_vehicle_racer_cannon_radius, autocvar_g_vehicle_racer_cannon_force, 0,
DEATH_VH_WAKI_GUN.m_id, PROJECTILE_WAKICANNON, 0, true, true, player);
bolt.velocity = normalize(dir) * autocvar_g_vehicle_racer_cannon_speed;
- weapon_thinkf(player, WFRAME_FIRE1, 0, w_ready);
+ weapon_thinkf(player, weaponentity, WFRAME_FIRE1, 0, w_ready);
}
- if (fire2)
- if (!isPlayer || weapon_prepareattack(thiswep, actor, false, 0.2)) {
+ if (fire & 2)
+ if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) {
if (isPlayer) W_SetupShot_Dir(actor, v_forward, false, 0, SND(Null), CH_WEAPON_B, 0);
- racer_fire_rocket(w_shotorg, w_shotdir, NULL);
- weapon_thinkf(actor, WFRAME_FIRE2, 0, w_ready);
+ racer_fire_rocket(player, w_shotorg, w_shotdir, NULL);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
}
}
void racer_rocket_tracker();
void racer_rocket_groundhugger();
-void racer_fire_rocket(vector org, vector dir, entity trg)
+void racer_fire_rocket(entity player, vector org, vector dir, entity trg)
{SELFPARAM();
entity rocket = vehicles_projectile(EFFECT_RACER_ROCKETLAUNCH.eent_eff_name, SND(ROCKET_FIRE),
org, dir * autocvar_g_vehicle_racer_rocket_speed,
autocvar_g_vehicle_racer_rocket_damage, autocvar_g_vehicle_racer_rocket_radius, autocvar_g_vehicle_racer_rocket_force, 3,
- DEATH_VH_WAKI_ROCKET.m_id, PROJECTILE_WAKIROCKET, 20, false, false, self.owner);
+ DEATH_VH_WAKI_ROCKET.m_id, PROJECTILE_WAKIROCKET, 20, false, false, player);
rocket.lip = autocvar_g_vehicle_racer_rocket_accel * sys_frametime;
rocket.wait = autocvar_g_vehicle_racer_rocket_turnrate;
if(player.BUTTON_ATCK)
if (wep1.wr_checkammo1(wep1))
{
- wep1.wr_think(wep1, self, true, false);
+ .entity weaponentity = weaponentities[0];
+ wep1.wr_think(wep1, self, weaponentity, 1);
}
if(self.vehicle_flags & VHF_SHIELDREGEN)
if(time > raptor.lip + autocvar_g_vehicle_raptor_bombs_refire)
if(player.BUTTON_ATCK2)
{
- wep2a.wr_think(wep2a, self, false, true);
+ .entity weaponentity = weaponentities[1];
+ wep2a.wr_think(wep2a, self, weaponentity, 2);
raptor.delay = time + autocvar_g_vehicle_raptor_bombs_refire;
raptor.lip = time;
}
if(time > raptor.lip + autocvar_g_vehicle_raptor_flare_refire)
if(player.BUTTON_ATCK2)
{
- wep2b.wr_think(wep2b, self, false, true);
+ .entity weaponentity = weaponentities[1];
+ wep2b.wr_think(wep2b, self, weaponentity, 2);
raptor.delay = time + autocvar_g_vehicle_raptor_flare_refire;
raptor.lip = time;
}
self.frame = 0;
- self.bomb1 = spawn();
- self.bomb2 = spawn();
- self.gun1 = spawn();
- self.gun2 = spawn();
+ self.bomb1 = new(raptor_bomb);
+ self.bomb2 = new(raptor_bomb);
+ self.gun1 = new(raptor_gun);
+ self.gun2 = new(raptor_gun);
setmodel(self.bomb1, MDL_VEH_RAPTOR_CB_FOLDED);
setmodel(self.bomb2, MDL_VEH_RAPTOR_CB_FOLDED);
self.angles = self.bomb1.angles;
self.bomb1.angles = '0 0 0';
- spinner = spawn();
+ spinner = new(raptor_spinner);
spinner.owner = self;
setmodel(spinner, MDL_VEH_RAPTOR_PROP);
setattachment(spinner, self, "engine_left");
spinner.avelocity = '0 90 0';
self.bomb1.gun1 = spinner;
- spinner = spawn();
+ spinner = new(raptor_spinner);
spinner.owner = self;
setmodel(spinner, MDL_VEH_RAPTOR_PROP);
setattachment(spinner, self, "engine_right");
/* flags */ ATTRIB(RaptorCannon, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(RaptorCannon, impulse, int, 3);
/* refname */ ATTRIB(RaptorCannon, netname, string, "raptorcannon");
-/* wepname */ ATTRIB(RaptorCannon, message, string, _("Raptor cannon"));
+/* wepname */ ATTRIB(RaptorCannon, m_name, string, _("Raptor cannon"));
ENDCLASS(RaptorCannon)
REGISTER_WEAPON(RAPTOR, NEW(RaptorCannon));
/* flags */ ATTRIB(RaptorBomb, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(RaptorBomb, impulse, int, 3);
/* refname */ ATTRIB(RaptorBomb, netname, string, "raptorbomb");
-/* wepname */ ATTRIB(RaptorBomb, message, string, _("Raptor bomb"));
+/* wepname */ ATTRIB(RaptorBomb, m_name, string, _("Raptor bomb"));
ENDCLASS(RaptorBomb)
REGISTER_WEAPON(RAPTOR_BOMB, NEW(RaptorBomb));
/* flags */ ATTRIB(RaptorFlare, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
/* impulse */ ATTRIB(RaptorFlare, impulse, int, 3);
/* refname */ ATTRIB(RaptorFlare, netname, string, "raptorflare");
-/* wepname */ ATTRIB(RaptorFlare, message, string, _("Raptor flare"));
+/* wepname */ ATTRIB(RaptorFlare, m_name, string, _("Raptor flare"));
ENDCLASS(RaptorFlare)
REGISTER_WEAPON(RAPTOR_FLARE, NEW(RaptorFlare));
float autocvar_g_vehicle_raptor_bomblet_force;
float autocvar_g_vehicle_raptor_bomblet_explode_delay;
-METHOD(RaptorCannon, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+METHOD(RaptorCannon, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
entity player = isPlayer ? actor : actor.owner;
entity veh = player.vehicle;
// 1 [wait] 1 [wait] 2 [wait] 2 [wait] [wait]
float t = autocvar_g_vehicle_raptor_cannon_refire * (1 + veh.misc_bulletcounter == 4);
- if (fire1)
- if (weapon_prepareattack(thiswep, player, false, t)) {
+ if (fire & 1)
+ if (weapon_prepareattack(thiswep, player, weaponentity, false, t)) {
if (isPlayer) W_SetupShot_Dir(player, v_forward, false, 0, SND(Null), CH_WEAPON_B, 0);
vector org = w_shotorg;
vector dir = w_shotdir;
org, normalize(dir + randomvec() * autocvar_g_vehicle_raptor_cannon_spread) * autocvar_g_vehicle_raptor_cannon_speed,
autocvar_g_vehicle_raptor_cannon_damage, autocvar_g_vehicle_raptor_cannon_radius, autocvar_g_vehicle_raptor_cannon_force, 0,
DEATH_VH_RAPT_CANNON.m_id, PROJECTILE_RAPTORCANNON, 0, true, true, player);
- weapon_thinkf(player, WFRAME_FIRE1, 0, w_ready);
+ weapon_thinkf(player, weaponentity, WFRAME_FIRE1, 0, w_ready);
}
}
METHOD(RaptorCannon, wr_checkammo1, bool(RacerAttack thiswep)) {
float autocvar_g_vehicle_raptor_bombs_refire;
void raptor_bombdrop();
-METHOD(RaptorBomb, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+METHOD(RaptorBomb, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
entity player = isPlayer ? actor : actor.owner;
entity veh = player.vehicle;
- if (fire2)
- if (!isPlayer || weapon_prepareattack(thiswep, player, true, autocvar_g_vehicle_raptor_bombs_refire)) {
+ if (fire & 2)
+ if (!isPlayer || weapon_prepareattack(thiswep, player, weaponentity, true, autocvar_g_vehicle_raptor_bombs_refire)) {
if (veh) setself(veh);
raptor_bombdrop();
- weapon_thinkf(player, WFRAME_FIRE2, 0, w_ready);
+ weapon_thinkf(player, weaponentity, WFRAME_FIRE2, 0, w_ready);
}
}
void raptor_flare_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
void raptor_flare_touch();
-METHOD(RaptorFlare, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+METHOD(RaptorFlare, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
bool isPlayer = IS_PLAYER(actor);
entity player = isPlayer ? actor : actor.owner;
entity veh = player.vehicle;
- if (fire2)
- if (!isPlayer || weapon_prepareattack(thiswep, player, true, autocvar_g_vehicle_raptor_flare_refire)) {
+ if (fire & 2)
+ if (!isPlayer || weapon_prepareattack(thiswep, player, weaponentity, true, autocvar_g_vehicle_raptor_flare_refire)) {
for(int i = 0; i < 3; ++i) {
entity _flare = spawn();
setmodel(_flare, MDL_VEH_RAPTOR_FLARE);
_flare.tur_impacttime = time + autocvar_g_vehicle_raptor_flare_lifetime;
_flare.touch = raptor_flare_touch;
}
- weapon_thinkf(player, WFRAME_FIRE2, 0, w_ready);
+ weapon_thinkf(player, weaponentity, WFRAME_FIRE2, 0, w_ready);
}
}
if(player.BUTTON_ATCK)
{
spider.cnt = time;
- if(spider.vehicle_ammo1 >= autocvar_g_vehicle_spiderbot_minigun_ammo_cost && spider.tur_head.attack_finished_single <= time)
+ if(spider.vehicle_ammo1 >= autocvar_g_vehicle_spiderbot_minigun_ammo_cost && spider.tur_head.attack_finished_single[0] <= time)
{
entity gun;
vector v;
sound (gun, CH_WEAPON_A, SND_UZI_FIRE, VOL_BASE, ATTEN_NORM);
//trailparticles(self, _particleeffectnum("spiderbot_minigun_trail"), v, trace_endpos);
- pointparticles(particleeffectnum(EFFECT_SPIDERBOT_MINIGUN_MUZZLEFLASH), v, v_forward * 2500, 1);
+ pointparticles(EFFECT_SPIDERBOT_MINIGUN_MUZZLEFLASH, v, v_forward * 2500, 1);
setself(spider);
spider.vehicle_ammo1 -= autocvar_g_vehicle_spiderbot_minigun_ammo_cost;
- spider.tur_head.attack_finished_single = time + autocvar_g_vehicle_spiderbot_minigun_refire;
+ spider.tur_head.attack_finished_single[0] = time + autocvar_g_vehicle_spiderbot_minigun_refire;
player.vehicle_ammo1 = (spider.vehicle_ammo1 / autocvar_g_vehicle_spiderbot_minigun_ammo_max) * 100;
spider.gun1.angles_z += 45;
spider.gun2.angles_z -= 45;
if(spider.gun2.cnt <= time)
player.vehicle_reload2 = 100;
else
- player.vehicle_reload2 = 100 - ((spider.gun2.cnt - time) / spider.attack_finished_single) * 100;
+ player.vehicle_reload2 = 100 - ((spider.gun2.cnt - time) / spider.attack_finished_single[0]) * 100;
setorigin(player, spider.origin + '0 0 1' * spider.maxs_z);
player.velocity = spider.velocity;
self.tur_head.frame += 1;
if (self.tur_head.frame == 9)
- self.attack_finished_single = autocvar_g_vehicle_spiderbot_rocket_reload;
+ self.attack_finished_single[0] = autocvar_g_vehicle_spiderbot_rocket_reload;
else
- self.attack_finished_single = ((self.vehicle_weapon2mode == SBRM_VOLLY) ? autocvar_g_vehicle_spiderbot_rocket_refire2 : autocvar_g_vehicle_spiderbot_rocket_refire);
+ self.attack_finished_single[0] = ((self.vehicle_weapon2mode == SBRM_VOLLY) ? autocvar_g_vehicle_spiderbot_rocket_refire2 : autocvar_g_vehicle_spiderbot_rocket_refire);
- self.gun2.cnt = time + self.attack_finished_single;
+ self.gun2.cnt = time + self.attack_finished_single[0];
}
#endif
#include "weapon/seeker.qc"
#include "weapon/shockwave.qc"
#include "weapon/arc.qc"
-#include "weapon/hmg.qc"
-#include "weapon/rpc.qc"
#include "../../lib/warpzone/common.qh"
#include "../../lib/warpzone/client.qh"
#include "../util.qh"
- #include "../buffs/all.qh"
#include "../../client/autocvars.qh"
#include "../deathtypes/all.qh"
#include "../../lib/csqcmodel/interpolate.qh"
#include "../stats.qh"
#include "../teams.qh"
#include "../util.qh"
- #include "../buffs/all.qh"
#include "../monsters/all.qh"
#include "config.qh"
#include "../../server/weapons/csqcprojectile.qh"
string W_Sound(string w_snd)
{
- #define extensions(X) X(wav) X(ogg)
- #define tryext(ext) { if (fexists(strcat("sound/", output = strcat("weapons/", w_snd, "."#ext)))) break; }
- string output;
- do {
- extensions(tryext);
- #undef tryext
- #undef extensions
- output = strcat("weapons/", w_snd);
- } while (0);
-
+ string output = strcat("weapons/", w_snd);
#ifdef SVQC
MUTATOR_CALLHOOK(WeaponSound, w_snd, output);
return weapon_sound_output;
#define WEAPONS_ALL_H
#include "../command/all.qh"
+#include "../stats.qh"
#include "config.qh"
// weapon sets
#endif
REGISTRY(Weapons, 72) // Increase as needed. Can be up to 72.
-REGISTER_REGISTRY(RegisterWeapons)
-entity get_weaponinfo(int id);
+#define Weapons_from(i) _Weapons_from(i, WEP_Null)
+#define get_weaponinfo(i) Weapons_from(i)
+REGISTER_REGISTRY(Weapons)
+STATIC_INIT(WeaponPickup) { FOREACH(Weapons, true, LAMBDA(it.m_pickup = NEW(WeaponPickup, it))); }
GENERIC_COMMAND(dumpweapons, "Dump all weapons into weapons_dump.txt") // WEAPONTODO: make this work with other progs than just server
#define REGISTER_WEAPON(id, inst) \
/* WepSet WEPSET_##id; */ \
- REGISTER(RegisterWeapons, WEP, Weapons, id, m_id, inst)
+ REGISTER(Weapons, WEP, id, m_id, inst)
// create cvars for weapon settings
#define WEP_ADD_CVAR_NONE(wepname,name) [[last]] float autocvar_g_balance_##wepname##_##name;
#include "all.inc"
-entity get_weaponinfo(int id)
-{
- if (id >= WEP_FIRST && id <= WEP_LAST) {
- Weapon w = Weapons[id];
- if (w) return w;
- }
- return WEP_Null;
-}
-
// TODO: remove after 0.8.2. Retains impulse number compatibility because 0.8.1 clients don't reload the weapons.cfg
-#define WEP_HARDCODED_IMPULSES 22
+#define WEP_HARDCODED_IMPULSES 20
// TODO: invert after 0.8.2. Will require moving 'best weapon' impulses
#define WEP_IMPULSE_BEGIN 230
#define WEP_IMPULSE_END bound(WEP_IMPULSE_BEGIN, WEP_IMPULSE_BEGIN + (Weapons_COUNT - 1) - 1, 253)
-REGISTRY_SORT(Weapons, netname, WEP_HARDCODED_IMPULSES + 1)
+REGISTRY_SORT(Weapons, WEP_HARDCODED_IMPULSES + 1)
+REGISTRY_CHECK(Weapons)
STATIC_INIT(register_weapons_done)
{
#endif
weaponorder_byid = "";
for (int i = Weapons_MAX - 1; i >= 1; --i)
- if (Weapons[i])
+ if (Weapons_from(i))
weaponorder_byid = strcat(weaponorder_byid, " ", ftos(i));
weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
}
return strcmp(wep_config_queue[root], wep_config_queue[child]);
}
-void Dump_Weapon_Settings(void)
+void Dump_Weapon_Settings()
{
int i, x, totalsettings = 0;
for(i = WEP_FIRST; i <= WEP_LAST; ++i)
// Balance Config Generator
// ==========================
-void Dump_Weapon_Settings(void);
+void Dump_Weapon_Settings();
int wep_config_file;
bool wep_config_alsoprint;
#ifndef WEAPON_H
#define WEAPON_H
+#include "../items/item/pickup.qh"
+
+const int MAX_WEAPONSLOTS = 2;
+.entity weaponentities[MAX_WEAPONSLOTS];
+
+int weaponslot(.entity weaponentity)
+{
+ for (int i = 0; i < MAX_WEAPONSLOTS; ++i)
+ {
+ if (weaponentities[i] == weaponentity)
+ {
+ return i;
+ }
+ }
+ return 0;
+}
.int ammo_shells;
.int ammo_nails;
/** M: refname : reference name name */
ATTRIB(Weapon, netname, string, "");
/** M: wepname : human readable name */
- ATTRIB(Weapon, message, string, "AOL CD Thrower");
+ ATTRIB(Weapon, m_name, string, "AOL CD Thrower");
+
+ ATTRIB(Weapon, m_pickup, entity, NULL);
/** (SERVER) setup weapon data */
METHOD(Weapon, wr_setup, void(Weapon this)) {}
/** (SERVER) logic to run every frame */
- METHOD(Weapon, wr_think, void(Weapon this, entity actor, bool fire1, bool fire2)) {}
+ METHOD(Weapon, wr_think, void(Weapon this, entity actor, .entity weaponentity, int fire)) {}
/** (SERVER) checks ammo for weapon primary */
METHOD(Weapon, wr_checkammo1, bool(Weapon this)) {return false;}
/** (SERVER) checks ammo for weapon second */
METHOD(Weapon, wr_pickup, void(Weapon this)) {}
METHOD(Weapon, display, void(entity this, void(string name, string icon) returns)) {
- returns(this.message, this.model2 ? sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.model2) : string_null);
+ returns(this.m_name, this.model2 ? sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.model2) : string_null);
}
ENDCLASS(Weapon)
+#include "../items/all.qh"
+CLASS(WeaponPickup, Pickup)
+ ATTRIB(WeaponPickup, m_weapon, Weapon, NULL)
+ ATTRIB(WeaponPickup, m_name, string, string_null)
+#ifndef MENUQC
+ ATTRIB(WeaponPickup, m_sound, Sound, SND_WEAPONPICKUP)
+#endif
+#ifdef SVQC
+ ATTRIB(WeaponPickup, m_itemflags, int, FL_WEAPON)
+ float weapon_pickupevalfunc(entity player, entity item);
+ ATTRIB(WeaponPickup, m_pickupevalfunc, float(entity player, entity item), weapon_pickupevalfunc)
+#endif
+ CONSTRUCTOR(WeaponPickup, Weapon w) {
+ CONSTRUCT(WeaponPickup);
+ this.m_weapon = w;
+ this.m_name = w.m_name;
+#ifndef MENUQC
+ this.m_model = w.m_model;
+#endif
+#ifdef SVQC
+ this.m_botvalue = w.bot_pickupbasevalue;
+#endif
+ }
+#ifdef SVQC
+ METHOD(WeaponPickup, giveTo, bool(entity this, entity item, entity player))
+ {
+ bool b = Item_GiveTo(item, player);
+ if (b) {
+ LOG_TRACEF("entity %i picked up %s\n", player, this.m_name);
+ }
+ return b;
+ }
+#endif
+ENDCLASS(WeaponPickup)
+
CLASS(OffhandWeapon, Object)
METHOD(OffhandWeapon, offhand_think, void(OffhandWeapon this, entity player, bool key_pressed)) {}
ENDCLASS(OffhandWeapon)
// other useful macros
#define WEP_AMMO(wpn) (WEP_##wpn.ammo_field) // only used inside weapon files/with direct name, don't duplicate prefix
-#define WEP_NAME(wpn) ((get_weaponinfo(wpn)).message)
+#define WEP_NAME(wpn) ((get_weaponinfo(wpn)).m_name)
#endif
/* crosshair */ ATTRIB(Arc, w_crosshair_size, float, 0.7);
/* wepimg */ ATTRIB(Arc, model2, string, "weaponarc");
/* refname */ ATTRIB(Arc, netname, string, "arc");
-/* wepname */ ATTRIB(Arc, message, string, _("Arc"));
+/* wepname */ ATTRIB(Arc, m_name, string, _("Arc"));
ENDCLASS(Arc)
REGISTER_WEAPON(ARC, NEW(Arc));
.float beam_heat; // (beam) amount of heat produced
.float arc_overheat; // (dropped arc/player) time during which it's too hot
.float arc_cooldown; // (dropped arc/player) cooling speed
-.float arc_heat_percent; // (player) arc heat in [0,1] (stat)
+.float arc_heat_percent = _STAT(ARC_HEAT);
.float arc_smoke_sound;
#endif
#ifdef CSQC
-void Ent_ReadArcBeam(float isnew);
.vector beam_color;
.float beam_alpha;
.float beam_thickness;
-.float beam_traileffect;
-.float beam_hiteffect;
+.entity beam_traileffect;
+.entity beam_hiteffect;
.float beam_hitlight[4]; // 0: radius, 123: rgb
-.float beam_muzzleeffect;
+.entity beam_muzzleeffect;
.float beam_muzzlelight[4]; // 0: radius, 123: rgb
.string beam_image;
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_arc) { weapon_defaultspawnfunc(WEP_ARC.m_id); }
+spawnfunc(weapon_arc) { weapon_defaultspawnfunc(this, WEP_ARC); }
bool W_Arc_Beam_Send(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_ARC_BEAM);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_ARC_BEAM);
// Truncate information when this beam is displayed to the owner client
// - The owner client has no use for beam start position or directions,
//dprint("Heat: ",ftos(player.arc_heat_percent*100),"%\n");
}
-void W_Arc_Beam_Think(void)
+void W_Arc_Beam_Think()
{SELFPARAM();
if(self != self.owner.arc_beam)
{
if ( WEP_CVAR(arc, overheat_max) > 0 && self.beam_heat >= WEP_CVAR(arc, overheat_max) )
{
- Send_Effect_("arc_overheat",
+ Send_Effect(EFFECT_ARC_OVERHEAT,
self.beam_start, self.beam_wantdir, 1 );
sound(self, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM);
}
if(time - self.beam_prev > 1)
sound(self, CH_WEAPON_A, SND_ARC_FIRE, VOL_BASE, ATTN_NORM);
- entity beam = self.arc_beam = spawn();
- beam.classname = "W_Arc_Beam";
+ entity beam = self.arc_beam = new(W_Arc_Beam);
beam.solid = SOLID_NOT;
beam.think = W_Arc_Beam_Think;
beam.owner = self;
if ( self.arc_overheat > time )
{
if ( random() < self.arc_heat_percent )
- Send_Effect_("arc_smoke", smoke_origin, '0 0 0', 1 );
+ Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 );
if ( self.BUTTON_ATCK || self.BUTTON_ATCK2 )
{
- Send_Effect_("arc_overheat_fire", smoke_origin, w_shotdir, 1 );
+ Send_Effect(EFFECT_ARC_OVERHEAT_FIRE, smoke_origin, w_shotdir, 1 );
if ( !self.arc_smoke_sound )
{
self.arc_smoke_sound = 1;
{
if ( random() < (self.arc_beam.beam_heat-WEP_CVAR(arc, overheat_min)) /
( WEP_CVAR(arc, overheat_max)-WEP_CVAR(arc, overheat_min) ) )
- Send_Effect_("arc_smoke", smoke_origin, '0 0 0', 1 );
+ Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 );
}
if ( self.arc_smoke_sound && ( self.arc_overheat <= time ||
);
}
}
- METHOD(Arc, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
Arc_Player_SetHeat(actor);
Arc_Smoke();
if (time >= actor.arc_overheat)
- if (fire1 || fire2 || actor.arc_beam.beam_bursting)
+ if ((fire & 1) || (fire & 2) || actor.arc_beam.beam_bursting)
{
if(actor.arc_BUTTON_ATCK_prev)
{
#if 0
if(actor.animstate_startframe == actor.anim_shoot.x && actor.animstate_numframes == actor.anim_shoot.y)
- weapon_thinkf(actor, WFRAME_DONTCHANGE, autocvar_g_balance_arc_primary_animtime, w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, autocvar_g_balance_arc_primary_animtime, w_ready);
else
#endif
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
}
if((!actor.arc_beam) || wasfreed(actor.arc_beam))
{
- if(weapon_prepareattack(thiswep, actor, fire2, 0))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, boolean(fire & 2), 0))
{
- W_Arc_Beam(fire2);
+ W_Arc_Beam(boolean(fire & 2));
if(!actor.arc_BUTTON_ATCK_prev)
{
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
actor.arc_BUTTON_ATCK_prev = true;
}
}
if(actor.arc_BUTTON_ATCK_prev)
{
sound(actor, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
- ATTACK_FINISHED(actor) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor();
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
+ int slot = weaponslot(weaponentity);
+ ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor();
}
actor.arc_BUTTON_ATCK_prev = false;
#if 0
- if(fire2)
- if(weapon_prepareattack(thiswep, actor, true, autocvar_g_balance_arc_secondary_refire))
+ if(fire & 2)
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_arc_secondary_refire))
{
W_Arc_Attack2();
actor.arc_count = autocvar_g_balance_arc_secondary_count;
- weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_balance_arc_secondary_animtime, w_arc_checkattack);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_arc_secondary_animtime, w_arc_checkattack);
actor.arc_secondarytime = time + autocvar_g_balance_arc_secondary_refire2 * W_WeaponRateFactor();
}
#endif
Draw_ArcBeam_callback_last_bottom = WarpZone_UnTransformOrigin(WarpZone_trace_transform, bottom);
}
-void Reset_ArcBeam(void)
+void Reset_ArcBeam()
{
entity e;
for (e = world; (e = findfloat(e, beam_usevieworigin, 1)); ) {
Draw_ArcBeam_callback_last_bottom = '0 0 0';
}
-void Remove_ArcBeam(void)
+void Remove_ArcBeam()
{SELFPARAM();
remove(self.beam_muzzleentity);
sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
}
-void Ent_ReadArcBeam(float isnew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
+{
int sf = ReadByte();
entity flash;
self.beam_color = '1 1 1';
self.beam_alpha = 0.5;
self.beam_thickness = 8;
- self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
- self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+ self.beam_traileffect = (EFFECT_ARC_BEAM);
+ self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
self.beam_hitlight[0] = 0;
self.beam_hitlight[1] = 1;
self.beam_hitlight[2] = 1;
self.beam_hitlight[3] = 1;
- self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+ self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
self.beam_muzzlelight[0] = 0;
self.beam_muzzlelight[1] = 1;
self.beam_muzzlelight[2] = 1;
self.beam_muzzlelight[3] = 1;
- if(self.beam_muzzleeffect >= 0)
+ if(self.beam_muzzleeffect)
{
setmodel(flash, MDL_ARC_MUZZLEFLASH);
flash.alpha = self.beam_alpha;
self.beam_color = '1 1 1';
self.beam_alpha = 0.5;
self.beam_thickness = 8;
- self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
- self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+ self.beam_traileffect = (EFFECT_ARC_BEAM);
+ self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
self.beam_hitlight[0] = 0;
self.beam_hitlight[1] = 1;
self.beam_hitlight[2] = 1;
self.beam_hitlight[3] = 1;
- self.beam_muzzleeffect = -1; // particleeffectnum(EFFECT_GRENADE_MUZZLEFLASH);
+ self.beam_muzzleeffect = NULL; // (EFFECT_GRENADE_MUZZLEFLASH);
self.beam_muzzlelight[0] = 0;
self.beam_muzzlelight[1] = 1;
self.beam_muzzlelight[2] = 1;
self.beam_muzzlelight[3] = 1;
self.beam_image = "particles/lgbeam";
- if(self.beam_muzzleeffect >= 0)
+ if(self.beam_muzzleeffect)
{
setmodel(flash, MDL_ARC_MUZZLEFLASH);
flash.alpha = self.beam_alpha;
self.beam_color = '1 1 1';
self.beam_alpha = 0.5;
self.beam_thickness = 8;
- self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM_HEAL);
- self.beam_hiteffect = particleeffectnum(EFFECT_ARC_BEAM_HEAL_IMPACT);
+ self.beam_traileffect = (EFFECT_ARC_BEAM_HEAL);
+ self.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT);
self.beam_hitlight[0] = 0;
self.beam_hitlight[1] = 1;
self.beam_hitlight[2] = 1;
self.beam_hitlight[3] = 1;
- self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+ self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
self.beam_muzzlelight[0] = 0;
self.beam_muzzlelight[1] = 1;
self.beam_muzzlelight[2] = 1;
self.beam_muzzlelight[3] = 1;
self.beam_image = "particles/lgbeam";
- if(self.beam_muzzleeffect >= 0)
+ if(self.beam_muzzleeffect)
{
setmodel(flash, MDL_ARC_MUZZLEFLASH);
flash.alpha = self.beam_alpha;
self.beam_color = '1 1 1';
self.beam_alpha = 0.5;
self.beam_thickness = 8;
- self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
- self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+ self.beam_traileffect = (EFFECT_ARC_BEAM);
+ self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
self.beam_hitlight[0] = 20;
self.beam_hitlight[1] = 1;
self.beam_hitlight[2] = 0;
self.beam_hitlight[3] = 0;
- self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+ self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
self.beam_muzzlelight[0] = 50;
self.beam_muzzlelight[1] = 1;
self.beam_muzzlelight[2] = 0;
self.beam_muzzlelight[3] = 0;
self.beam_image = "particles/lgbeam";
- if(self.beam_muzzleeffect >= 0)
+ if(self.beam_muzzleeffect)
{
setmodel(flash, MDL_ARC_MUZZLEFLASH);
flash.alpha = self.beam_alpha;
self.beam_color = '1 1 1';
self.beam_alpha = 0.5;
self.beam_thickness = 14;
- self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
- self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+ self.beam_traileffect = (EFFECT_ARC_BEAM);
+ self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
self.beam_hitlight[0] = 0;
self.beam_hitlight[1] = 1;
self.beam_hitlight[2] = 1;
self.beam_hitlight[3] = 1;
- self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+ self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
self.beam_muzzlelight[0] = 0;
self.beam_muzzlelight[1] = 1;
self.beam_muzzlelight[2] = 1;
self.beam_muzzlelight[3] = 1;
self.beam_image = "particles/lgbeam";
- if(self.beam_muzzleeffect >= 0)
+ if(self.beam_muzzleeffect)
{
setmodel(flash, MDL_ARC_MUZZLEFLASH);
flash.alpha = self.beam_alpha;
self.beam_color = '1 1 1';
self.beam_alpha = 0.5;
self.beam_thickness = 14;
- self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
- self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+ self.beam_traileffect = (EFFECT_ARC_BEAM);
+ self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
self.beam_hitlight[0] = 0;
self.beam_hitlight[1] = 1;
self.beam_hitlight[2] = 1;
self.beam_hitlight[3] = 1;
- self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+ self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
self.beam_muzzlelight[0] = 0;
self.beam_muzzlelight[1] = 1;
self.beam_muzzlelight[2] = 1;
self.beam_muzzlelight[3] = 1;
self.beam_image = "particles/lgbeam";
- if(self.beam_muzzleeffect >= 0)
+ if(self.beam_muzzleeffect)
{
setmodel(flash, MDL_ARC_MUZZLEFLASH);
flash.alpha = self.beam_alpha;
self.beam_color = '1 1 1';
self.beam_alpha = 0.5;
self.beam_thickness = 14;
- self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM_HEAL);
- self.beam_hiteffect = particleeffectnum(EFFECT_ARC_BEAM_HEAL_IMPACT2);
+ self.beam_traileffect = (EFFECT_ARC_BEAM_HEAL);
+ self.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT2);
self.beam_hitlight[0] = 0;
self.beam_hitlight[1] = 1;
self.beam_hitlight[2] = 1;
self.beam_hitlight[3] = 1;
- self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+ self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
self.beam_muzzlelight[0] = 0;
self.beam_muzzlelight[1] = 1;
self.beam_muzzlelight[2] = 1;
self.beam_muzzlelight[3] = 1;
self.beam_image = "particles/lgbeam";
- if(self.beam_muzzleeffect >= 0)
+ if(self.beam_muzzleeffect)
{
setmodel(flash, MDL_ARC_MUZZLEFLASH);
flash.alpha = self.beam_alpha;
self.beam_color = '1 1 1';
self.beam_alpha = 0.5;
self.beam_thickness = 14;
- self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
- self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+ self.beam_traileffect = (EFFECT_ARC_BEAM);
+ self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
self.beam_hitlight[0] = 0;
self.beam_hitlight[1] = 1;
self.beam_hitlight[2] = 1;
self.beam_hitlight[3] = 1;
- self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+ self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
self.beam_muzzlelight[0] = 0;
self.beam_muzzlelight[1] = 1;
self.beam_muzzlelight[2] = 1;
self.beam_muzzlelight[3] = 1;
self.beam_image = "particles/lgbeam";
- if(self.beam_muzzleeffect >= 0)
+ if(self.beam_muzzleeffect)
{
setmodel(flash, MDL_ARC_MUZZLEFLASH);
flash.alpha = self.beam_alpha;
self.beam_color = randomvec();
self.beam_alpha = 1;
self.beam_thickness = 8;
- self.beam_traileffect = false;
- self.beam_hiteffect = false;
+ self.beam_traileffect = NULL;
+ self.beam_hiteffect = NULL;
self.beam_hitlight[0] = 0;
self.beam_hitlight[1] = 1;
self.beam_hitlight[2] = 1;
self.beam_hitlight[3] = 1;
- self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+ self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
self.beam_muzzlelight[0] = 0;
self.beam_muzzlelight[1] = 1;
self.beam_muzzlelight[2] = 1;
self.beam_muzzlelight[3] = 1;
self.beam_image = "particles/lgbeam";
- if(self.beam_muzzleeffect >= 0)
+ if(self.beam_muzzleeffect)
{
setmodel(flash, MDL_ARC_MUZZLEFLASH);
flash.alpha = self.beam_alpha;
{
InterpolateOrigin_Note();
}
+ return true;
}
#endif
/* crosshair */ ATTRIB(Blaster, w_crosshair_size, float, 0.5);
/* wepimg */ ATTRIB(Blaster, model2, string, "weaponlaser");
/* refname */ ATTRIB(Blaster, netname, string, "blaster");
-/* wepname */ ATTRIB(Blaster, message, string, _("Blaster"));
+/* wepname */ ATTRIB(Blaster, m_name, string, _("Blaster"));
ENDCLASS(Blaster)
REGISTER_WEAPON(BLASTER, NEW(Blaster));
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_blaster) { weapon_defaultspawnfunc(WEP_BLASTER.m_id); }
+spawnfunc(weapon_blaster) { weapon_defaultspawnfunc(this, WEP_BLASTER); }
spawnfunc(weapon_laser) { spawnfunc_weapon_blaster(this); }
-void W_Blaster_Touch(void)
+void W_Blaster_Touch()
{SELFPARAM();
PROJECTILE_TOUCH;
remove(self);
}
-void W_Blaster_Think(void)
+void W_Blaster_Think()
{SELFPARAM();
self.movetype = MOVETYPE_FLY;
self.think = SUB_Remove;
W_SetupShot_Dir(actor, s_forward, false, 3, SND(LASERGUN_FIRE), CH_WEAPON_B, atk_damage);
Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- entity missile = spawn();
+ entity missile = new(blasterbolt);
missile.owner = missile.realowner = actor;
- missile.classname = "blasterbolt";
missile.bot_dodge = true;
missile.bot_dodgerating = atk_damage;
PROJECTILE_MAKETRIGGER(missile);
{ self.BUTTON_ATCK = bot_aim(WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false); }
}
- METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, .entity weaponentity, int fire))
{
- if(fire1)
+ if(fire & 1)
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(blaster, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(blaster, refire)))
{
W_Blaster_Attack(
actor,
WEP_CVAR_PRI(blaster, delay),
WEP_CVAR_PRI(blaster, lifetime)
);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(blaster, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(blaster, animtime), w_ready);
}
}
- else if(fire2)
+ else if(fire & 2)
{
switch(WEP_CVAR(blaster, secondary))
{
case 1: // normal projectile secondary
{
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(blaster, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(blaster, refire)))
{
W_Blaster_Attack(
actor,
WEP_CVAR_SEC(blaster, delay),
WEP_CVAR_SEC(blaster, lifetime)
);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(blaster, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(blaster, animtime), w_ready);
}
break;
{
vector org2;
org2 = w_org + w_backoff * 6;
- pointparticles(particleeffectnum(EFFECT_BLASTER_IMPACT), org2, w_backoff * 1000, 1);
+ pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
if(!w_issilent) { sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM); }
}
/* crosshair */ ATTRIB(Crylink, w_crosshair_size, float, 0.5);
/* wepimg */ ATTRIB(Crylink, model2, string, "weaponcrylink");
/* refname */ ATTRIB(Crylink, netname, string, "crylink");
-/* wepname */ ATTRIB(Crylink, message, string, _("Crylink"));
+/* wepname */ ATTRIB(Crylink, m_name, string, _("Crylink"));
ENDCLASS(Crylink)
REGISTER_WEAPON(CRYLINK, NEW(Crylink));
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_crylink) { weapon_defaultspawnfunc(WEP_CRYLINK.m_id); }
+spawnfunc(weapon_crylink) { weapon_defaultspawnfunc(this, WEP_CRYLINK); }
void W_Crylink_CheckLinks(entity e)
{
W_Crylink_Dequeue_Raw(e.realowner, e.queueprev, e, e.queuenext);
}
-void W_Crylink_Reset(void)
+void W_Crylink_Reset()
{SELFPARAM();
W_Crylink_Dequeue(self);
remove(self);
return targ_origin;
}
-void W_Crylink_LinkJoinEffect_Think(void)
+void W_Crylink_LinkJoinEffect_Think()
{SELFPARAM();
// is there at least 2 projectiles very close?
entity e, p;
}
// NO bounce protection, as bounces are limited!
-void W_Crylink_Touch(void)
+void W_Crylink_Touch()
{SELFPARAM();
float finalhit;
float f;
// CSQCProjectile(proj, true, PROJECTILE_CRYLINK, true);
}
-void W_Crylink_Fadethink(void)
+void W_Crylink_Fadethink()
{SELFPARAM();
W_Crylink_Dequeue(self);
remove(self);
proj = prevproj = firstproj = world;
for(counter = 0; counter < shots; ++counter)
{
- proj = spawn();
+ proj = new(spike);
proj.reset = W_Crylink_Reset;
proj.realowner = proj.owner = self;
- proj.classname = "spike";
proj.bot_dodge = true;
proj.bot_dodgerating = WEP_CVAR_PRI(crylink, damage);
if(shots == 1) {
proj = prevproj = firstproj = world;
for(counter = 0; counter < shots; ++counter)
{
- proj = spawn();
+ proj = new(spike);
proj.reset = W_Crylink_Reset;
proj.realowner = proj.owner = self;
- proj.classname = "spike";
proj.bot_dodge = true;
proj.bot_dodgerating = WEP_CVAR_SEC(crylink, damage);
if(shots == 1) {
else
self.BUTTON_ATCK2 = bot_aim(WEP_CVAR_SEC(crylink, speed), 0, WEP_CVAR_SEC(crylink, middle_lifetime), false);
}
- METHOD(Crylink, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Crylink, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(autocvar_g_balance_crylink_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(crylink, ammo), WEP_CVAR_SEC(crylink, ammo))) { // forced reload
Weapon w = get_weaponinfo(actor.weapon);
w.wr_reload(w);
}
- if(fire1)
+ if(fire & 1)
{
if(actor.crylink_waitrelease != 1)
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(crylink, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(crylink, refire)))
{
W_Crylink_Attack(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(crylink, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(crylink, animtime), w_ready);
}
}
- if(fire2 && autocvar_g_balance_crylink_secondary)
+ if((fire & 2) && autocvar_g_balance_crylink_secondary)
{
if(actor.crylink_waitrelease != 2)
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(crylink, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(crylink, refire)))
{
W_Crylink_Attack2(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(crylink, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(crylink, animtime), w_ready);
}
}
- if((actor.crylink_waitrelease == 1 && !fire1) || (actor.crylink_waitrelease == 2 && !fire2))
+ if((actor.crylink_waitrelease == 1 && !(fire & 1)) || (actor.crylink_waitrelease == 2 && !(fire & 2)))
{
if(!actor.crylink_lastgroup || time > actor.crylink_lastgroup.teleport_time)
{
pos = W_Crylink_LinkJoin(actor.crylink_lastgroup, WEP_CVAR_BOTH(crylink, isprimary, joinspread) * WEP_CVAR_BOTH(crylink, isprimary, speed));
- linkjoineffect = spawn();
+ linkjoineffect = new(linkjoineffect);
linkjoineffect.think = W_Crylink_LinkJoinEffect_Think;
- linkjoineffect.classname = "linkjoineffect";
linkjoineffect.nextthink = time + w_crylink_linkjoin_time;
linkjoineffect.owner = actor;
setorigin(linkjoineffect, pos);
org2 = w_org + w_backoff * 2;
if(w_deathtype & HITTYPE_SECONDARY)
{
- pointparticles(particleeffectnum(EFFECT_CRYLINK_IMPACT2), org2, '0 0 0', 1);
+ pointparticles(EFFECT_CRYLINK_IMPACT2, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_CRYLINK_IMPACT2, VOL_BASE, ATTN_NORM);
}
else
{
- pointparticles(particleeffectnum(EFFECT_CRYLINK_IMPACT), org2, '0 0 0', 1);
+ pointparticles(EFFECT_CRYLINK_IMPACT, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_CRYLINK_IMPACT, VOL_BASE, ATTN_NORM);
}
/* crosshair */ ATTRIB(Devastator, w_crosshair_size, float, 0.7);
/* wepimg */ ATTRIB(Devastator, model2, string, "weaponrocketlauncher");
/* refname */ ATTRIB(Devastator, netname, string, "devastator");
-/* wepname */ ATTRIB(Devastator, message, string, _("Devastator"));
+/* wepname */ ATTRIB(Devastator, m_name, string, _("Devastator"));
ENDCLASS(Devastator)
REGISTER_WEAPON(DEVASTATOR, NEW(Devastator));
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_devastator) { weapon_defaultspawnfunc(WEP_DEVASTATOR.m_id); }
+spawnfunc(weapon_devastator) { weapon_defaultspawnfunc(this, WEP_DEVASTATOR); }
spawnfunc(weapon_rocketlauncher) { spawnfunc_weapon_devastator(this); }
.entity lastrocket;
-void W_Devastator_Unregister(void)
+void W_Devastator_Unregister()
{SELFPARAM();
if(self.realowner && self.realowner.lastrocket == self)
{
}
}
-void W_Devastator_Explode(void)
+void W_Devastator_Explode()
{SELFPARAM();
W_Devastator_Unregister();
if(!(self.realowner.items & IT_UNLIMITED_WEAPON_AMMO))
{
self.realowner.cnt = WEP_DEVASTATOR.m_id;
- ATTACK_FINISHED(self.realowner) = time;
+ int slot = 0; // TODO: unhardcode
+ ATTACK_FINISHED(self.realowner, slot) = time;
self.realowner.switchweapon = w_getbestweapon(self.realowner);
}
}
remove(self);
}
-void W_Devastator_DoRemoteExplode(void)
+void W_Devastator_DoRemoteExplode(.entity weaponentity)
{SELFPARAM();
W_Devastator_Unregister();
if(!(self.realowner.items & IT_UNLIMITED_WEAPON_AMMO))
{
self.realowner.cnt = WEP_DEVASTATOR.m_id;
- ATTACK_FINISHED(self.realowner) = time;
+ int slot = weaponslot(weaponentity);
+ ATTACK_FINISHED(self.realowner, slot) = time;
self.realowner.switchweapon = w_getbestweapon(self.realowner);
}
}
remove(self);
}
-void W_Devastator_RemoteExplode(void)
+void W_Devastator_RemoteExplode(.entity weaponentity)
{SELFPARAM();
if(self.realowner.deadflag == DEAD_NO)
if(self.realowner.lastrocket)
: (vlen(NearestPointOnBox(self.realowner, self.origin) - self.origin) > WEP_CVAR(devastator, remote_radius)) // safety device
)
{
- W_Devastator_DoRemoteExplode();
+ W_Devastator_DoRemoteExplode(weaponentity);
}
}
}
// normalize(thisdir + goaldir)
// normalize(0)
-void W_Devastator_Think(void)
+void W_Devastator_Think()
{SELFPARAM();
vector desireddir, olddir, newdir, desiredorigin, goal;
float velspeed, f;
}
}
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
if(self.rl_detonate_later)
- W_Devastator_RemoteExplode();
+ W_Devastator_RemoteExplode(weaponentity);
}
if(self.csqcprojectile_clientanimate == 0)
UpdateCSQCProjectile(self);
}
-void W_Devastator_Touch(void)
+void W_Devastator_Touch()
{SELFPARAM();
if(WarpZone_Projectile_Touch())
{
}
}
#endif
- METHOD(Devastator, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(WEP_CVAR(devastator, reload_ammo) && actor.clip_load < WEP_CVAR(devastator, ammo)) { // forced reload
Weapon w = get_weaponinfo(actor.weapon);
w.wr_reload(w);
} else {
- if(fire1)
+ if(fire & 1)
{
if(actor.rl_release || WEP_CVAR(devastator, guidestop))
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(devastator, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(devastator, refire)))
{
W_Devastator_Attack(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(devastator, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(devastator, animtime), w_ready);
actor.rl_release = 0;
}
}
else
actor.rl_release = 1;
- if(fire2)
+ if(fire & 2)
if(actor.switchweapon == WEP_DEVASTATOR.m_id)
{
entity rock;
{
#if 0
// don't switch while guiding a missile
- if(ATTACK_FINISHED(self) <= time || self.weapon != WEP_DEVASTATOR.m_id)
+ if(ATTACK_FINISHED(self, slot) <= time || self.weapon != WEP_DEVASTATOR.m_id)
{
ammo_amount = false;
if(WEP_CVAR(devastator, reload_ammo))
{
vector org2;
org2 = w_org + w_backoff * 12;
- pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), org2, '0 0 0', 1);
+ pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTN_NORM);
}
/* crosshair */ ATTRIB(Electro, w_crosshair_size, float, 0.6);
/* wepimg */ ATTRIB(Electro, model2, string, "weaponelectro");
/* refname */ ATTRIB(Electro, netname, string, "electro");
-/* wepname */ ATTRIB(Electro, message, string, _("Electro"));
+/* wepname */ ATTRIB(Electro, m_name, string, _("Electro"));
ENDCLASS(Electro)
REGISTER_WEAPON(ELECTRO, NEW(Electro));
ELECTRO_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
.float electro_count;
.float electro_secondarytime;
-void W_Electro_ExplodeCombo(void);
+void W_Electro_ExplodeCombo();
#endif
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_electro) { weapon_defaultspawnfunc(WEP_ELECTRO.m_id); }
+spawnfunc(weapon_electro) { weapon_defaultspawnfunc(this, WEP_ELECTRO); }
void W_Electro_TriggerCombo(vector org, float rad, entity own)
{
}
}
-void W_Electro_ExplodeCombo(void)
+void W_Electro_ExplodeCombo()
{SELFPARAM();
W_Electro_TriggerCombo(self.origin, WEP_CVAR(electro, combo_comboradius), self.realowner);
remove(self);
}
-void W_Electro_Explode(void)
+void W_Electro_Explode()
{SELFPARAM();
if(other.takedamage == DAMAGE_AIM)
if(IS_PLAYER(other))
remove(self);
}
-void W_Electro_TouchExplode(void)
+void W_Electro_TouchExplode()
{
PROJECTILE_TOUCH;
W_Electro_Explode();
}
-void W_Electro_Bolt_Think(void)
+void W_Electro_Bolt_Think()
{SELFPARAM();
if(time >= self.ltime)
{
Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- proj = spawn();
- proj.classname = "electro_bolt";
+ proj = new(electro_bolt);
proj.owner = proj.realowner = self;
proj.bot_dodge = true;
proj.bot_dodgerating = WEP_CVAR_PRI(electro, damage);
MUTATOR_CALLHOOK(EditProjectile, self, proj);
}
-void W_Electro_Orb_Touch(void)
+void W_Electro_Orb_Touch()
{SELFPARAM();
PROJECTILE_TOUCH;
if(other.takedamage == DAMAGE_AIM)
Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- entity proj = spawn();
- proj.classname = "electro_orb";
+ entity proj = new(electro_orb);
proj.owner = proj.realowner = self;
proj.use = W_Electro_Explode;
proj.think = adaptor_think2use_hittype_splash;
MUTATOR_CALLHOOK(EditProjectile, self, proj);
}
-void W_Electro_CheckAttack(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Electro_CheckAttack(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{SELFPARAM();
if(self.electro_count > 1)
if(self.BUTTON_ATCK2)
- if(weapon_prepareattack(thiswep, actor, true, -1))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, -1))
{
W_Electro_Attack_Orb(WEP_ELECTRO);
self.electro_count -= 1;
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
return;
}
// WEAPONTODO: when the player releases the button, cut down the length of refire2?
- w_ready(thiswep, actor, fire1, fire2);
+ w_ready(thiswep, actor, weaponentity, fire);
}
.float bot_secondary_electromooth;
}
}
}
- METHOD(Electro, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Electro, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(autocvar_g_balance_electro_reload_ammo) // forced reload // WEAPONTODO
{
}
}
- if(fire1)
+ if(fire & 1)
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire)))
{
W_Electro_Attack_Bolt(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
}
}
- else if(fire2)
+ else if(fire & 2)
{
if(time >= actor.electro_secondarytime)
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(electro, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(electro, refire)))
{
W_Electro_Attack_Orb(thiswep);
actor.electro_count = WEP_CVAR_SEC(electro, count);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
actor.electro_secondarytime = time + WEP_CVAR_SEC(electro, refire2) * W_WeaponRateFactor();
}
}
org2 = w_org + w_backoff * 6;
if(w_deathtype & HITTYPE_SECONDARY)
{
- pointparticles(particleeffectnum(EFFECT_ELECTRO_BALLEXPLODE), org2, '0 0 0', 1);
+ pointparticles(EFFECT_ELECTRO_BALLEXPLODE, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_NORM);
}
if(w_deathtype & HITTYPE_BOUNCE)
{
// this is sent as "primary (w_deathtype & HITTYPE_BOUNCE)" to distinguish it from (w_deathtype & HITTYPE_SECONDARY) bounced balls
- pointparticles(particleeffectnum(EFFECT_ELECTRO_COMBO), org2, '0 0 0', 1);
+ pointparticles(EFFECT_ELECTRO_COMBO, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_ELECTRO_IMPACT_COMBO, VOL_BASE, ATTEN_NORM);
}
else
{
- pointparticles(particleeffectnum(EFFECT_ELECTRO_IMPACT), org2, '0 0 0', 1);
+ pointparticles(EFFECT_ELECTRO_IMPACT, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_NORM);
}
/* crosshair */ //ATTRIB(Fireball, w_crosshair_size, float, 0.65);
/* wepimg */ ATTRIB(Fireball, model2, string, "weaponfireball");
/* refname */ ATTRIB(Fireball, netname, string, "fireball");
-/* wepname */ ATTRIB(Fireball, message, string, _("Fireball"));
+/* wepname */ ATTRIB(Fireball, m_name, string, _("Fireball"));
ENDCLASS(Fireball)
REGISTER_WEAPON(FIREBALL, NEW(Fireball));
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_fireball) { weapon_defaultspawnfunc(WEP_FIREBALL.m_id); }
+spawnfunc(weapon_fireball) { weapon_defaultspawnfunc(this, WEP_FIREBALL); }
-void W_Fireball_Explode(void)
+void W_Fireball_Explode()
{SELFPARAM();
entity e;
float dist;
remove(self);
}
-void W_Fireball_TouchExplode(void)
+void W_Fireball_TouchExplode()
{
PROJECTILE_TOUCH;
W_Fireball_Explode();
}
}
-void W_Fireball_Think(void)
+void W_Fireball_Think()
{SELFPARAM();
if(time > self.pushltime)
{
}
}
-void W_Fireball_Attack1(void)
+void W_Fireball_Attack1()
{SELFPARAM();
entity proj;
Send_Effect(EFFECT_FIREBALL_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- proj = spawn();
- proj.classname = "plasma_prim";
+ proj = new(plasma_prim);
proj.owner = proj.realowner = self;
proj.bot_dodge = true;
proj.bot_dodgerating = WEP_CVAR_PRI(fireball, damage);
Send_Effect(EFFECT_FIREBALL_PRE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
}
-void W_Fireball_Attack1_Frame4(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Fireball_Attack1_Frame4(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
W_Fireball_Attack1();
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), w_ready);
}
-void W_Fireball_Attack1_Frame3(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Fireball_Attack1_Frame3(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
W_Fireball_AttackEffect(0, '+1.25 +3.75 0');
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame4);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame4);
}
-void W_Fireball_Attack1_Frame2(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Fireball_Attack1_Frame2(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
W_Fireball_AttackEffect(0, '-1.25 +3.75 0');
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame3);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame3);
}
-void W_Fireball_Attack1_Frame1(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Fireball_Attack1_Frame1(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
W_Fireball_AttackEffect(1, '+1.25 -3.75 0');
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame2);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame2);
}
-void W_Fireball_Attack1_Frame0(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Fireball_Attack1_Frame0(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{SELFPARAM();
W_Fireball_AttackEffect(0, '-1.25 -3.75 0');
sound(self, CH_WEAPON_SINGLE, SND_FIREBALL_PREFIRE2, VOL_BASE, ATTEN_NORM);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame1);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame1);
}
-void W_Fireball_Firemine_Think(void)
+void W_Fireball_Firemine_Think()
{SELFPARAM();
if(time > self.pushltime)
{
self.nextthink = time + 0.1;
}
-void W_Fireball_Firemine_Touch(void)
+void W_Fireball_Firemine_Touch()
{SELFPARAM();
PROJECTILE_TOUCH;
if(other.takedamage == DAMAGE_AIM)
self.projectiledeathtype |= HITTYPE_BOUNCE;
}
-void W_Fireball_Attack2(void)
+void W_Fireball_Attack2()
{SELFPARAM();
entity proj;
vector f_diff;
Send_Effect(EFFECT_FIREBALL_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- proj = spawn();
+ proj = new(grenade);
proj.owner = proj.realowner = self;
- proj.classname = "grenade";
proj.bot_dodge = true;
proj.bot_dodgerating = WEP_CVAR_SEC(fireball, damage);
proj.movetype = MOVETYPE_BOUNCE;
}
}
}
- METHOD(Fireball, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Fireball, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
- if(fire1)
+ if(fire & 1)
{
if(time >= actor.fireball_primarytime)
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(fireball, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(fireball, refire)))
{
- W_Fireball_Attack1_Frame0(thiswep, actor, fire1, fire2);
+ W_Fireball_Attack1_Frame0(thiswep, actor, weaponentity, fire);
actor.fireball_primarytime = time + WEP_CVAR_PRI(fireball, refire2) * W_WeaponRateFactor();
}
}
- else if(fire2)
+ else if(fire & 2)
{
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(fireball, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(fireball, refire)))
{
W_Fireball_Attack2();
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(fireball, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(fireball, animtime), w_ready);
}
}
}
else
{
org2 = w_org + w_backoff * 16;
- pointparticles(particleeffectnum(EFFECT_FIREBALL_EXPLODE), org2, '0 0 0', 1);
+ pointparticles(EFFECT_FIREBALL_EXPLODE, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_FIREBALL_IMPACT2, VOL_BASE, ATTEN_NORM * 0.25); // long range boom
}
/* crosshair */ ATTRIB(Hagar, w_crosshair_size, float, 0.8);
/* wepimg */ ATTRIB(Hagar, model2, string, "weaponhagar");
/* refname */ ATTRIB(Hagar, netname, string, "hagar");
-/* wepname */ ATTRIB(Hagar, message, string, _("Hagar"));
+/* wepname */ ATTRIB(Hagar, m_name, string, _("Hagar"));
ENDCLASS(Hagar)
REGISTER_WEAPON(HAGAR, NEW(Hagar));
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_hagar) { weapon_defaultspawnfunc(WEP_HAGAR.m_id); }
+spawnfunc(weapon_hagar) { weapon_defaultspawnfunc(this, WEP_HAGAR); }
// NO bounce protection, as bounces are limited!
-void W_Hagar_Explode(void)
+void W_Hagar_Explode()
{SELFPARAM();
self.event_damage = func_null;
RadiusDamage(self, self.realowner, WEP_CVAR_PRI(hagar, damage), WEP_CVAR_PRI(hagar, edgedamage), WEP_CVAR_PRI(hagar, radius), world, world, WEP_CVAR_PRI(hagar, force), self.projectiledeathtype, other);
remove(self);
}
-void W_Hagar_Explode2(void)
+void W_Hagar_Explode2()
{SELFPARAM();
self.event_damage = func_null;
RadiusDamage(self, self.realowner, WEP_CVAR_SEC(hagar, damage), WEP_CVAR_SEC(hagar, edgedamage), WEP_CVAR_SEC(hagar, radius), world, world, WEP_CVAR_SEC(hagar, force), self.projectiledeathtype, other);
W_PrepareExplosionByDamage(attacker, self.think);
}
-void W_Hagar_Touch(void)
+void W_Hagar_Touch()
{SELFPARAM();
PROJECTILE_TOUCH;
self.use();
}
-void W_Hagar_Touch2(void)
+void W_Hagar_Touch2()
{SELFPARAM();
PROJECTILE_TOUCH;
Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- missile = spawn();
+ missile = new(missile);
missile.owner = missile.realowner = self;
- missile.classname = "missile";
missile.bot_dodge = true;
missile.bot_dodgerating = WEP_CVAR_PRI(hagar, damage);
Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- missile = spawn();
+ missile = new(missile);
missile.owner = missile.realowner = self;
- missile.classname = "missile";
missile.bot_dodge = true;
missile.bot_dodgerating = WEP_CVAR_SEC(hagar, damage);
}
.float hagar_loadstep, hagar_loadblock, hagar_loadbeep, hagar_warning;
-void W_Hagar_Attack2_Load_Release(void)
+void W_Hagar_Attack2_Load_Release(.entity weaponentity)
{SELFPARAM();
// time to release the rockets we've loaded
if(!self.hagar_load)
return;
- weapon_prepareattack_do(self, true, WEP_CVAR_SEC(hagar, refire));
+ weapon_prepareattack_do(self, weaponentity, true, WEP_CVAR_SEC(hagar, refire));
W_SetupShot(self, false, 2, SND(HAGAR_FIRE), CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage));
Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
missile = world;
for(counter = 0; counter < shots; ++counter)
{
- missile = spawn();
+ missile = new(missile);
missile.owner = missile.realowner = self;
- missile.classname = "missile";
missile.bot_dodge = true;
missile.bot_dodgerating = WEP_CVAR_SEC(hagar, damage);
MUTATOR_CALLHOOK(EditProjectile, self, missile);
}
- weapon_thinkf(self, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, load_animtime), w_ready);
+ weapon_thinkf(self, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, load_animtime), w_ready);
self.hagar_loadstep = time + WEP_CVAR_SEC(hagar, refire) * W_WeaponRateFactor();
self.hagar_load = 0;
}
-void W_Hagar_Attack2_Load(Weapon thiswep)
+void W_Hagar_Attack2_Load(Weapon thiswep, .entity weaponentity)
{SELFPARAM();
// loadable hagar secondary attack, must always run each frame
if(self.hagar_load)
{
// if we pressed primary fire while loading, unload all rockets and abort
- self.weaponentity.state = WS_READY;
+ self.(weaponentity).state = WS_READY;
W_DecreaseAmmo(thiswep, self, WEP_CVAR_SEC(hagar, ammo) * self.hagar_load * -1); // give back ammo
self.hagar_load = 0;
sound(self, CH_WEAPON_A, SND_HAGAR_BEEP, VOL_BASE, ATTN_NORM);
if(!self.hagar_loadblock && self.hagar_loadstep < time)
{
W_DecreaseAmmo(thiswep, self, WEP_CVAR_SEC(hagar, ammo));
- self.weaponentity.state = WS_INUSE;
+ self.(weaponentity).state = WS_INUSE;
self.hagar_load += 1;
sound(self, CH_WEAPON_B, SND_HAGAR_LOAD, VOL_BASE * 0.8, ATTN_NORM); // sound is too loud according to most
// release if player let go of button or if they've held it in too long
if(!self.BUTTON_ATCK2 || (stopped && self.hagar_loadstep < time && WEP_CVAR_SEC(hagar, load_hold) >= 0))
{
- self.weaponentity.state = WS_READY;
- W_Hagar_Attack2_Load_Release();
+ self.(weaponentity).state = WS_READY;
+ W_Hagar_Attack2_Load_Release(weaponentity);
}
}
else
else // not using secondary_speed since these are only 15% and should cause some ricochets without re-aiming
self.BUTTON_ATCK2 = bot_aim(WEP_CVAR_PRI(hagar, speed), 0, WEP_CVAR_PRI(hagar, lifetime), false);
}
- METHOD(Hagar, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Hagar, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
float loadable_secondary;
loadable_secondary = (WEP_CVAR_SEC(hagar, load) && WEP_CVAR(hagar, secondary));
if(loadable_secondary)
- W_Hagar_Attack2_Load(thiswep); // must always run each frame
+ W_Hagar_Attack2_Load(thiswep, weaponentity); // must always run each frame
if(autocvar_g_balance_hagar_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(hagar, ammo), WEP_CVAR_SEC(hagar, ammo))) { // forced reload
Weapon w = get_weaponinfo(actor.weapon);
w.wr_reload(w);
- } else if(fire1 && !actor.hagar_load && !actor.hagar_loadblock) // not while secondary is loaded or awaiting reset
+ } else if((fire & 1) && !actor.hagar_load && !actor.hagar_loadblock) // not while secondary is loaded or awaiting reset
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(hagar, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(hagar, refire)))
{
W_Hagar_Attack(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(hagar, refire), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hagar, refire), w_ready);
}
}
- else if(fire2 && !loadable_secondary && WEP_CVAR(hagar, secondary))
+ else if((fire & 2) && !loadable_secondary && WEP_CVAR(hagar, secondary))
{
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(hagar, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(hagar, refire)))
{
W_Hagar_Attack2(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, refire), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, refire), w_ready);
}
}
}
// we lost the weapon and want to prepare switching away
if(self.hagar_load)
{
- self.weaponentity.state = WS_READY;
- W_Hagar_Attack2_Load_Release();
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+ self.(weaponentity).state = WS_READY;
+ W_Hagar_Attack2_Load_Release(weaponentity);
}
}
METHOD(Hagar, wr_init, void(entity thiswep))
}
METHOD(Hagar, wr_playerdeath, void(entity thiswep))
{
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
// if we have any rockets loaded when we die, release them
if(self.hagar_load && WEP_CVAR_SEC(hagar, load_releasedeath))
- W_Hagar_Attack2_Load_Release();
+ W_Hagar_Attack2_Load_Release(weaponentity);
}
METHOD(Hagar, wr_reload, void(entity thiswep))
{
{
vector org2;
org2 = w_org + w_backoff * 6;
- pointparticles(particleeffectnum(EFFECT_HAGAR_EXPLODE), org2, '0 0 0', 1);
+ pointparticles(EFFECT_HAGAR_EXPLODE, org2, '0 0 0', 1);
if(!w_issilent)
{
if(w_random<0.15)
/* crosshair */ ATTRIB(HLAC, w_crosshair_size, float, 0.6);
/* wepimg */ ATTRIB(HLAC, model2, string, "weaponhlac");
/* refname */ ATTRIB(HLAC, netname, string, "hlac");
-/* wepname */ ATTRIB(HLAC, message, string, _("Heavy Laser Assault Cannon"));
+/* wepname */ ATTRIB(HLAC, m_name, string, _("Heavy Laser Assault Cannon"));
ENDCLASS(HLAC)
REGISTER_WEAPON(HLAC, NEW(HLAC));
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_hlac) { weapon_defaultspawnfunc(WEP_HLAC.m_id); }
+spawnfunc(weapon_hlac) { weapon_defaultspawnfunc(this, WEP_HLAC); }
-void W_HLAC_Touch(void)
+void W_HLAC_Touch()
{SELFPARAM();
float isprimary;
self.punchangle_y = random() - 0.5;
}
- missile = spawn();
+ missile = new(hlacbolt);
missile.owner = missile.realowner = self;
- missile.classname = "hlacbolt";
missile.bot_dodge = true;
missile.bot_dodgerating = WEP_CVAR_PRI(hlac, damage);
MUTATOR_CALLHOOK(EditProjectile, self, missile);
}
-void W_HLAC_Attack2(void)
+void W_HLAC_Attack2()
{SELFPARAM();
entity missile;
float spread;
W_SetupShot(self, false, 3, SND(LASERGUN_FIRE), CH_WEAPON_A, WEP_CVAR_SEC(hlac, damage));
Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- missile = spawn();
+ missile = new(hlacbolt);
missile.owner = missile.realowner = self;
- missile.classname = "hlacbolt";
missile.bot_dodge = true;
missile.bot_dodgerating = WEP_CVAR_SEC(hlac, damage);
}
// weapon frames
-void W_HLAC_Attack_Frame(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_HLAC_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
if(actor.weapon != actor.switchweapon) // abort immediately if switching
{
- w_ready(thiswep, actor, fire1, fire2);
+ w_ready(thiswep, actor, weaponentity, fire);
return;
}
if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
{
W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
- w_ready(thiswep, actor, fire1, fire2);
+ w_ready(thiswep, actor, weaponentity, fire);
return;
}
- ATTACK_FINISHED(actor) = time + WEP_CVAR_PRI(hlac, refire) * W_WeaponRateFactor();
+ int slot = weaponslot(weaponentity);
+ ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(hlac, refire) * W_WeaponRateFactor();
W_HLAC_Attack(WEP_HLAC);
actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
}
else
{
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, animtime), w_ready);
}
}
{
self.BUTTON_ATCK = bot_aim(WEP_CVAR_PRI(hlac, speed), 0, WEP_CVAR_PRI(hlac, lifetime), false);
}
- METHOD(HLAC, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(HLAC, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(autocvar_g_balance_hlac_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(hlac, ammo), WEP_CVAR_SEC(hlac, ammo))) { // forced reload
Weapon w = get_weaponinfo(actor.weapon);
w.wr_reload(w);
- } else if(fire1)
+ } else if(fire & 1)
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(hlac, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(hlac, refire)))
{
actor.misc_bulletcounter = 0;
W_HLAC_Attack(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
}
}
- else if(fire2 && WEP_CVAR(hlac, secondary))
+ else if((fire & 2) && WEP_CVAR(hlac, secondary))
{
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(hlac, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(hlac, refire)))
{
W_HLAC_Attack2_Frame(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(hlac, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hlac, animtime), w_ready);
}
}
}
{
vector org2;
org2 = w_org + w_backoff * 6;
- pointparticles(particleeffectnum(EFFECT_BLASTER_IMPACT), org2, w_backoff * 1000, 1);
+ pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM);
}
+++ /dev/null
-#ifndef IMPLEMENTATION
-CLASS(HeavyMachineGun, Weapon)
-/* ammotype */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails)
-/* impulse */ ATTRIB(HeavyMachineGun, impulse, int, 3)
-/* flags */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
-/* rating */ ATTRIB(HeavyMachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
-/* color */ ATTRIB(HeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
-/* modelname */ ATTRIB(HeavyMachineGun, mdl, string, "ok_hmg");
-#ifndef MENUQC
-/* model */ ATTRIB(HeavyMachineGun, m_model, Model, MDL_HMG_ITEM);
-#endif
-/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair, string, "gfx/crosshairuzi");
-/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair_size, float, 0.6);
-/* wepimg */ ATTRIB(HeavyMachineGun, model2, string, "weaponhmg");
-/* refname */ ATTRIB(HeavyMachineGun, netname, string, "hmg");
-/* wepname */ ATTRIB(HeavyMachineGun, message, string, _("Heavy Machine Gun"));
-ENDCLASS(HeavyMachineGun)
-REGISTER_WEAPON(HMG, NEW(HeavyMachineGun));
-
-#define HMG_SETTINGS(w_cvar,w_prop) HMG_SETTINGS_LIST(w_cvar, w_prop, HMG, hmg)
-#define HMG_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
- w_cvar(id, sn, NONE, spread_min) \
- w_cvar(id, sn, NONE, spread_max) \
- w_cvar(id, sn, NONE, spread_add) \
- w_cvar(id, sn, NONE, solidpenetration) \
- w_cvar(id, sn, NONE, damage) \
- w_cvar(id, sn, NONE, force) \
- w_cvar(id, sn, NONE, refire) \
- w_cvar(id, sn, NONE, ammo) \
- w_prop(id, sn, float, reloading_ammo, reload_ammo) \
- w_prop(id, sn, float, reloading_time, reload_time) \
- w_prop(id, sn, float, switchdelay_raise, switchdelay_raise) \
- w_prop(id, sn, float, switchdelay_drop, switchdelay_drop) \
- w_prop(id, sn, string, weaponreplace, weaponreplace) \
- w_prop(id, sn, float, weaponstart, weaponstart) \
- w_prop(id, sn, float, weaponstartoverride, weaponstartoverride) \
- w_prop(id, sn, float, weaponthrowable, weaponthrowable)
-
-#ifdef SVQC
-HMG_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
-#endif
-#endif
-#ifdef IMPLEMENTATION
-#ifdef SVQC
-
-spawnfunc(weapon_hmg) { weapon_defaultspawnfunc(WEP_HMG.m_id); }
-
-void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, bool fire1, bool fire2)
-{
- if (!actor.BUTTON_ATCK)
- {
- w_ready(thiswep, actor, fire1, fire2);
- return;
- }
-
- Weapon w = get_weaponinfo(actor.weapon);
- if(!w.wr_checkammo1(w))
- if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
- {
- W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
- w_ready(thiswep, actor, fire1, fire2);
- return;
- }
-
- W_DecreaseAmmo(WEP_HMG, self, WEP_CVAR(hmg, ammo));
-
- W_SetupShot (actor, true, 0, SND(UZI_FIRE), CH_WEAPON_A, WEP_CVAR(hmg, damage));
-
- if(!autocvar_g_norecoil)
- {
- actor.punchangle_x = random () - 0.5;
- actor.punchangle_y = random () - 0.5;
- }
-
- float hmg_spread = bound(WEP_CVAR(hmg, spread_min), WEP_CVAR(hmg, spread_min) + (WEP_CVAR(hmg, spread_add) * actor.misc_bulletcounter), WEP_CVAR(hmg, spread_max));
- fireBullet(w_shotorg, w_shotdir, hmg_spread, WEP_CVAR(hmg, solidpenetration), WEP_CVAR(hmg, damage), WEP_CVAR(hmg, force), WEP_HMG.m_id, 0);
-
- actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
-
- Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
-
- W_MachineGun_MuzzleFlash();
- W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
-
- if (autocvar_g_casings >= 2) // casing code
- SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
-
- ATTACK_FINISHED(actor) = time + WEP_CVAR(hmg, refire) * W_WeaponRateFactor();
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(hmg, refire), W_HeavyMachineGun_Attack_Auto);
-}
-
- METHOD(HeavyMachineGun, wr_aim, void(entity thiswep))
- {
- if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200)
- self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, false);
- else
- self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, false);
- }
- METHOD(HeavyMachineGun, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
- {
- if(WEP_CVAR(hmg, reload_ammo) && actor.clip_load < WEP_CVAR(hmg, ammo)) { // forced reload
- Weapon w = get_weaponinfo(actor.weapon);
- w.wr_reload(w);
- } else
- {
- if (fire1)
- if (weapon_prepareattack(thiswep, actor, false, 0))
- {
- actor.misc_bulletcounter = 0;
- W_HeavyMachineGun_Attack_Auto(thiswep, actor, fire1, fire2);
- }
- }
- }
- METHOD(HeavyMachineGun, wr_init, void(entity thiswep))
- {
- HMG_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
- }
- METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep))
- {
- float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
-
- if(autocvar_g_balance_hmg_reload_ammo)
- ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
-
- return ammo_amount;
- }
- METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep))
- {
- float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
-
- if(autocvar_g_balance_hmg_reload_ammo)
- ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
-
- return ammo_amount;
- }
- METHOD(HeavyMachineGun, wr_config, void(entity thiswep))
- {
- HMG_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
- }
- METHOD(HeavyMachineGun, wr_reload, void(entity thiswep))
- {
- W_Reload(self, WEP_CVAR(hmg, ammo), SND(RELOAD));
- }
- METHOD(HeavyMachineGun, wr_suicidemessage, int(entity thiswep))
- {
- return WEAPON_THINKING_WITH_PORTALS;
- }
- METHOD(HeavyMachineGun, wr_killmessage, int(entity thiswep))
- {
- if(w_deathtype & HITTYPE_SECONDARY)
- return WEAPON_HMG_MURDER_SNIPE;
- else
- return WEAPON_HMG_MURDER_SPRAY;
- }
-
-#endif
-#ifdef CSQC
-
- METHOD(HeavyMachineGun, wr_impacteffect, void(entity thiswep))
- {
- vector org2;
- org2 = w_org + w_backoff * 2;
- pointparticles(particleeffectnum(EFFECT_MACHINEGUN_IMPACT), org2, w_backoff * 1000, 1);
- if(!w_issilent)
- if(w_random < 0.05)
- sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTEN_NORM);
- else if(w_random < 0.1)
- sound(self, CH_SHOTS, SND_RIC2, VOL_BASE, ATTEN_NORM);
- else if(w_random < 0.2)
- sound(self, CH_SHOTS, SND_RIC3, VOL_BASE, ATTEN_NORM);
- }
-
-#endif
-#endif
/* crosshair */ ATTRIB(Hook, w_crosshair_size, float, 0.5);
/* wepimg */ ATTRIB(Hook, model2, string, "weaponhook");
/* refname */ ATTRIB(Hook, netname, string, "hook");
-/* wepname */ ATTRIB(Hook, message, string, _("Grappling Hook"));
+/* wepname */ ATTRIB(Hook, m_name, string, _("Grappling Hook"));
ATTRIB(Hook, ammo_factor, float, 1)
ENDCLASS(Hook)
REGISTER_WEAPON(HOOK, NEW(Hook));
CLASS(OffhandHook, OffhandWeapon)
+#ifdef SVQC
METHOD(OffhandHook, offhand_think, void(OffhandHook this, entity actor, bool key_pressed))
{
Weapon wep = WEP_HOOK;
- wep.wr_think(wep, actor, key_pressed, false);
+ .entity weaponentity = weaponentities[1];
+ wep.wr_think(wep, actor, weaponentity, key_pressed ? 1 : 0);
}
+#endif
ENDCLASS(OffhandHook)
OffhandHook OFFHAND_HOOK; STATIC_INIT(OFFHAND_HOOK) { OFFHAND_HOOK = NEW(OffhandHook); }
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_hook) { weapon_defaultspawnfunc(WEP_HOOK.m_id); }
+spawnfunc(weapon_hook) { weapon_defaultspawnfunc(this, WEP_HOOK); }
-void W_Hook_ExplodeThink(void)
+void W_Hook_ExplodeThink()
{SELFPARAM();
float dt, dmg_remaining_next, f;
remove(self);
}
-void W_Hook_Explode2(void)
+void W_Hook_Explode2()
{SELFPARAM();
self.event_damage = func_null;
self.touch = func_null;
W_PrepareExplosionByDamage(self.realowner, W_Hook_Explode2);
}
-void W_Hook_Touch2(void)
+void W_Hook_Touch2()
{SELFPARAM();
PROJECTILE_TOUCH;
self.use();
MUTATOR_CALLHOOK(EditProjectile, actor, gren);
}
- METHOD(Hook, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Hook, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
- if (fire1) {
+ if (fire & 1) {
if(!actor.hook)
if(!(actor.hook_state & HOOK_WAITING_FOR_RELEASE))
if(time > actor.hook_refire)
- if(weapon_prepareattack(thiswep, actor, false, -1))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, -1))
{
W_DecreaseAmmo(thiswep, actor, thiswep.ammo_factor * WEP_CVAR_PRI(hook, ammo));
actor.hook_state |= HOOK_FIRING;
actor.hook_state |= HOOK_WAITING_FOR_RELEASE;
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(hook, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hook, animtime), w_ready);
}
} else {
actor.hook_state |= HOOK_REMOVING;
actor.hook_state &= ~HOOK_WAITING_FOR_RELEASE;
}
- if(fire2)
+ if(fire & 2)
{
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(hook, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(hook, refire)))
{
W_Hook_Attack2(thiswep, actor);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(hook, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hook, animtime), w_ready);
}
}
{
vector org2;
org2 = w_org + w_backoff * 2;
- pointparticles(particleeffectnum(EFFECT_HOOK_EXPLODE), org2, '0 0 0', 1);
+ pointparticles(EFFECT_HOOK_EXPLODE, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_HOOKBOMB_IMPACT, VOL_BASE, ATTN_NORM);
}
/* crosshair */ ATTRIB(MachineGun, w_crosshair_size, float, 0.6);
/* wepimg */ ATTRIB(MachineGun, model2, string, "weaponuzi");
/* refname */ ATTRIB(MachineGun, netname, string, "machinegun");
-/* wepname */ ATTRIB(MachineGun, message, string, _("MachineGun"));
+/* wepname */ ATTRIB(MachineGun, m_name, string, _("MachineGun"));
ENDCLASS(MachineGun)
REGISTER_WEAPON(MACHINEGUN, NEW(MachineGun));
if(autocvar_sv_q3acompat_machineshotgunswap)
if(self.classname != "droppedweapon")
{
- weapon_defaultspawnfunc(WEP_SHOCKWAVE.m_id);
+ weapon_defaultspawnfunc(this, WEP_SHOCKWAVE);
return;
}
- weapon_defaultspawnfunc(WEP_MACHINEGUN.m_id);
+ weapon_defaultspawnfunc(this, WEP_MACHINEGUN);
}
spawnfunc(weapon_uzi) { spawnfunc_weapon_machinegun(this); }
-void W_MachineGun_MuzzleFlash_Think(void)
+void W_MachineGun_MuzzleFlash_Think()
{SELFPARAM();
self.frame = self.frame + 2;
self.scale = self.scale * 0.5;
}
-void W_MachineGun_MuzzleFlash(void)
+void W_MachineGun_MuzzleFlash()
{SELFPARAM();
if(self.muzzle_flash == world)
self.muzzle_flash = spawn();
self.muzzle_flash.owner = self.muzzle_flash.realowner = self;
}
-void W_MachineGun_Attack(Weapon thiswep, int deathtype)
+void W_MachineGun_Attack(Weapon thiswep, int deathtype, .entity weaponentity)
{SELFPARAM();
W_SetupShot(self, true, 0, SND(UZI_FIRE), CH_WEAPON_A, ((self.misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage)));
if(!autocvar_g_norecoil)
self.punchangle_x = random() - 0.5;
self.punchangle_y = random() - 0.5;
}
-
+ int slot = weaponslot(weaponentity);
// this attack_finished just enforces a cooldown at the end of a burst
- ATTACK_FINISHED(self) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor();
+ ATTACK_FINISHED(self, slot) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor();
if(self.misc_bulletcounter == 1)
fireBullet(w_shotorg, w_shotdir, WEP_CVAR(machinegun, first_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, first_damage), WEP_CVAR(machinegun, first_force), deathtype, 0);
}
// weapon frames
-void W_MachineGun_Attack_Frame(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_MachineGun_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
if(actor.weapon != actor.switchweapon) // abort immediately if switching
{
- w_ready(thiswep, actor, fire1, fire2);
+ w_ready(thiswep, actor, weaponentity, fire);
return;
}
if(actor.BUTTON_ATCK)
if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
{
W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
- w_ready(thiswep, actor, fire1, fire2);
+ w_ready(thiswep, actor, weaponentity, fire);
return;
}
actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
- W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame);
+ W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id, weaponentity);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame);
}
else
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), w_ready);
}
-void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
float machinegun_spread;
- if(!fire1)
+ if(!(fire & 1))
{
- w_ready(thiswep, actor, fire1, fire2);
+ w_ready(thiswep, actor, weaponentity, fire);
return;
}
if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
{
W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
- w_ready(thiswep, actor, fire1, fire2);
+ w_ready(thiswep, actor, weaponentity, fire);
return;
}
if(autocvar_g_casings >= 2) // casing code
SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
- ATTACK_FINISHED(actor) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor();
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Auto);
+ int slot = weaponslot(weaponentity);
+ ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor();
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Auto);
}
-void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
W_SetupShot(actor, true, 0, SND(UZI_FIRE), CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage));
if(!autocvar_g_norecoil)
actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
if(actor.misc_bulletcounter == 0)
{
- ATTACK_FINISHED(actor) = time + WEP_CVAR(machinegun, burst_refire2) * W_WeaponRateFactor();
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(machinegun, burst_animtime), w_ready);
+ int slot = weaponslot(weaponentity);
+ ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, burst_refire2) * W_WeaponRateFactor();
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(machinegun, burst_animtime), w_ready);
}
else
{
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(machinegun, burst_refire), W_MachineGun_Attack_Burst);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(machinegun, burst_refire), W_MachineGun_Attack_Burst);
}
}
else
self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, false);
}
- METHOD(MachineGun, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(MachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(WEP_CVAR(machinegun, reload_ammo) && actor.clip_load < min(max(WEP_CVAR(machinegun, sustained_ammo), WEP_CVAR(machinegun, first_ammo)), WEP_CVAR(machinegun, burst_ammo))) { // forced reload
Weapon w = get_weaponinfo(actor.weapon);
} else
if(WEP_CVAR(machinegun, mode) == 1)
{
- if(fire1)
- if(weapon_prepareattack(thiswep, actor, false, 0))
+ if(fire & 1)
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
{
actor.misc_bulletcounter = 0;
- W_MachineGun_Attack_Auto(thiswep, actor, fire1, fire2);
+ W_MachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
}
- if(fire2)
- if(weapon_prepareattack(thiswep, actor, true, 0))
+ if(fire & 2)
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, 0))
{
Weapon w = get_weaponinfo(actor.weapon);
if(!w.wr_checkammo2(w))
if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
{
W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
- w_ready(thiswep, actor, fire1, fire2);
+ w_ready(thiswep, actor, weaponentity, fire);
return;
}
W_DecreaseAmmo(thiswep, actor, WEP_CVAR(machinegun, burst_ammo));
actor.misc_bulletcounter = WEP_CVAR(machinegun, burst) * -1;
- W_MachineGun_Attack_Burst(thiswep, actor, fire1, fire2);
+ W_MachineGun_Attack_Burst(thiswep, actor, weaponentity, fire);
}
}
else
{
- if(fire1)
- if(weapon_prepareattack(thiswep, actor, false, 0))
+ if(fire & 1)
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
{
actor.misc_bulletcounter = 1;
- W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id); // sets attack_finished
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame);
+ W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id, weaponentity); // sets attack_finished
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame);
}
- if(fire2 && WEP_CVAR(machinegun, first))
- if(weapon_prepareattack(thiswep, actor, true, 0))
+ if((fire & 2) && WEP_CVAR(machinegun, first))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, 0))
{
actor.misc_bulletcounter = 1;
- W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id | HITTYPE_SECONDARY); // sets attack_finished
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(machinegun, first_refire), w_ready);
+ W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id | HITTYPE_SECONDARY, weaponentity); // sets attack_finished
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(machinegun, first_refire), w_ready);
}
}
}
{
vector org2;
org2 = w_org + w_backoff * 2;
- pointparticles(particleeffectnum(EFFECT_MACHINEGUN_IMPACT), org2, w_backoff * 1000, 1);
+ pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
if(!w_issilent)
- if(w_random < 0.05)
- sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTN_NORM);
- else if(w_random < 0.1)
- sound(self, CH_SHOTS, SND_RIC2, VOL_BASE, ATTN_NORM);
- else if(w_random < 0.2)
- sound(self, CH_SHOTS, SND_RIC3, VOL_BASE, ATTN_NORM);
+ sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTN_NORM);
}
#endif
/* crosshair */ ATTRIB(MineLayer, w_crosshair_size, float, 0.9);
/* wepimg */ ATTRIB(MineLayer, model2, string, "weaponminelayer");
/* refname */ ATTRIB(MineLayer, netname, string, "minelayer");
-/* wepname */ ATTRIB(MineLayer, message, string, _("Mine Layer"));
+/* wepname */ ATTRIB(MineLayer, m_name, string, _("Mine Layer"));
ENDCLASS(MineLayer)
REGISTER_WEAPON(MINE_LAYER, NEW(MineLayer));
#ifdef SVQC
MINELAYER_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
-void W_MineLayer_Think(void);
+void W_MineLayer_Think();
.float minelayer_detonate, mine_explodeanyway;
.float mine_time;
.vector mine_orientation;
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_minelayer) { weapon_defaultspawnfunc(WEP_MINE_LAYER.m_id); }
+spawnfunc(weapon_minelayer) { weapon_defaultspawnfunc(this, WEP_MINE_LAYER); }
void W_MineLayer_Stick(entity to)
{SELFPARAM();
// in order for mines to face properly when sticking to the ground, they must be a server side entity rather than a csqc projectile
- entity newmine;
- newmine = spawn();
+ entity newmine = spawn();
newmine.classname = self.classname;
newmine.bot_dodge = self.bot_dodge;
SetMovetypeFollow(self, to);
}
-void W_MineLayer_Explode(void)
+void W_MineLayer_Explode()
{SELFPARAM();
if(other.takedamage == DAMAGE_AIM)
if(IS_PLAYER(other))
if(!w.wr_checkammo1(w))
{
self.cnt = WEP_MINE_LAYER.m_id;
- ATTACK_FINISHED(self) = time;
+ int slot = 0; // TODO: unhardcode
+ ATTACK_FINISHED(self, slot) = time;
self.switchweapon = w_getbestweapon(self);
}
setself(this);
remove(self);
}
-void W_MineLayer_DoRemoteExplode(void)
+void W_MineLayer_DoRemoteExplode()
{SELFPARAM();
self.event_damage = func_null;
self.takedamage = DAMAGE_NO;
if(!w.wr_checkammo1(w))
{
self.cnt = WEP_MINE_LAYER.m_id;
- ATTACK_FINISHED(self) = time;
+ int slot = 0; // TODO: unhardcode
+ ATTACK_FINISHED(self, slot) = time;
self.switchweapon = w_getbestweapon(self);
}
setself(this);
remove(self);
}
-void W_MineLayer_RemoteExplode(void)
+void W_MineLayer_RemoteExplode()
{SELFPARAM();
if(self.realowner.deadflag == DEAD_NO)
if((self.spawnshieldtime >= 0)
}
}
-void W_MineLayer_ProximityExplode(void)
+void W_MineLayer_ProximityExplode()
{SELFPARAM();
// make sure no friend is in the mine's radius. If there is any, explosion is delayed until he's at a safe distance
if(WEP_CVAR(minelayer, protection) && self.mine_explodeanyway == 0)
return minecount;
}
-void W_MineLayer_Think(void)
+void W_MineLayer_Think()
{SELFPARAM();
entity head;
W_MineLayer_RemoteExplode();
}
-void W_MineLayer_Touch(void)
+void W_MineLayer_Touch()
{SELFPARAM();
if(self.movetype == MOVETYPE_NONE || self.movetype == MOVETYPE_FOLLOW)
return; // we're already a stuck mine, why do we get called? TODO does this even happen?
if(self.BUTTON_ATCK2 == true) self.BUTTON_ATCK = false;
}
}
- METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(autocvar_g_balance_minelayer_reload_ammo && actor.clip_load < WEP_CVAR(minelayer, ammo)) // forced reload
{
w.wr_reload(w);
}
}
- else if(fire1)
+ else if(fire & 1)
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(minelayer, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(minelayer, refire)))
{
W_MineLayer_Attack(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(minelayer, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(minelayer, animtime), w_ready);
}
}
- if(fire2)
+ if(fire & 2)
{
if(W_MineLayer_PlacedMines(true))
sound(actor, CH_WEAPON_B, SND_MINE_DET, VOL_BASE, ATTN_NORM);
}
METHOD(MineLayer, wr_checkammo1, bool(entity thiswep))
{
+ int slot = 0; // TODO: unhardcode
// don't switch while placing a mine
- if(ATTACK_FINISHED(self) <= time || self.weapon != WEP_MINE_LAYER.m_id)
+ if(ATTACK_FINISHED(self, slot) <= time || self.weapon != WEP_MINE_LAYER.m_id)
{
float ammo_amount = self.WEP_AMMO(MINE_LAYER) >= WEP_CVAR(minelayer, ammo);
ammo_amount += self.(weapon_load[WEP_MINE_LAYER.m_id]) >= WEP_CVAR(minelayer, ammo);
{
vector org2;
org2 = w_org + w_backoff * 12;
- pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), org2, '0 0 0', 1);
+ pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_MINE_EXP, VOL_BASE, ATTN_NORM);
}
/* crosshair */ ATTRIB(Mortar, w_crosshair_size, float, 0.7);
/* wepimg */ ATTRIB(Mortar, model2, string, "weapongrenadelauncher");
/* refname */ ATTRIB(Mortar, netname, string, "mortar");
-/* wepname */ ATTRIB(Mortar, message, string, _("Mortar"));
+/* wepname */ ATTRIB(Mortar, m_name, string, _("Mortar"));
ENDCLASS(Mortar)
REGISTER_WEAPON(MORTAR, NEW(Mortar));
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_mortar) { weapon_defaultspawnfunc(WEP_MORTAR.m_id); }
+spawnfunc(weapon_mortar) { weapon_defaultspawnfunc(this, WEP_MORTAR); }
spawnfunc(weapon_grenadelauncher) { spawnfunc_weapon_mortar(this); }
-void W_Mortar_Grenade_Explode(void)
+void W_Mortar_Grenade_Explode()
{SELFPARAM();
if(other.takedamage == DAMAGE_AIM)
if(IS_PLAYER(other))
remove(self);
}
-void W_Mortar_Grenade_Explode2(void)
+void W_Mortar_Grenade_Explode2()
{SELFPARAM();
if(other.takedamage == DAMAGE_AIM)
if(IS_PLAYER(other))
W_PrepareExplosionByDamage(attacker, self.use);
}
-void W_Mortar_Grenade_Think1(void)
+void W_Mortar_Grenade_Think1()
{SELFPARAM();
self.nextthink = time;
if(time > self.cnt)
W_Mortar_Grenade_Explode();
}
-void W_Mortar_Grenade_Touch1(void)
+void W_Mortar_Grenade_Touch1()
{SELFPARAM();
PROJECTILE_TOUCH;
if(other.takedamage == DAMAGE_AIM || WEP_CVAR_PRI(mortar, type) == 0) // always explode when hitting a player, or if normal mortar projectile
}
}
-void W_Mortar_Grenade_Touch2(void)
+void W_Mortar_Grenade_Touch2()
{SELFPARAM();
PROJECTILE_TOUCH;
if(other.takedamage == DAMAGE_AIM || WEP_CVAR_SEC(mortar, type) == 0) // always explode when hitting a player, or if normal mortar projectile
Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- gren = spawn();
+ gren = new(grenade);
gren.owner = gren.realowner = self;
- gren.classname = "grenade";
gren.bot_dodge = true;
gren.bot_dodgerating = WEP_CVAR_PRI(mortar, damage);
gren.movetype = MOVETYPE_BOUNCE;
Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- gren = spawn();
+ gren = new(grenade);
gren.owner = gren.realowner = self;
- gren.classname = "grenade";
gren.bot_dodge = true;
gren.bot_dodgerating = WEP_CVAR_SEC(mortar, damage);
gren.movetype = MOVETYPE_BOUNCE;
wepinfo_sec_dps = (WEP_CVAR_SEC(mortar, damage) * (1 / max3(sys_frametime, WEP_CVAR_SEC(mortar, refire), WEP_CVAR_SEC(mortar, animtime))));
wepinfo_ter_dps = 0;
*/
- METHOD(Mortar, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Mortar, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(autocvar_g_balance_mortar_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(mortar, ammo), WEP_CVAR_SEC(mortar, ammo))) { // forced reload
Weapon w = get_weaponinfo(actor.weapon);
w.wr_reload(w);
- } else if(fire1)
+ } else if(fire & 1)
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(mortar, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(mortar, refire)))
{
W_Mortar_Attack(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(mortar, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(mortar, animtime), w_ready);
}
}
- else if(fire2)
+ else if(fire & 2)
{
if(WEP_CVAR_SEC(mortar, remote_detonateprimary))
{
if(nadefound)
sound(actor, CH_WEAPON_B, SND_ROCKET_DET, VOL_BASE, ATTN_NORM);
}
- else if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(mortar, refire)))
+ else if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(mortar, refire)))
{
W_Mortar_Attack2(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(mortar, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(mortar, animtime), w_ready);
}
}
}
{
vector org2;
org2 = w_org + w_backoff * 12;
- pointparticles(particleeffectnum(EFFECT_GRENADE_EXPLODE), org2, '0 0 0', 1);
+ pointparticles(EFFECT_GRENADE_EXPLODE, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_GRENADE_IMPACT, VOL_BASE, ATTN_NORM);
}
/* crosshair */ ATTRIB(PortoLaunch, w_crosshair_size, float, 0.6);
/* wepimg */ ATTRIB(PortoLaunch, model2, string, "weaponporto");
/* refname */ ATTRIB(PortoLaunch, netname, string, "porto");
-/* wepname */ ATTRIB(PortoLaunch, message, string, _("Port-O-Launch"));
+/* wepname */ ATTRIB(PortoLaunch, m_name, string, _("Port-O-Launch"));
ENDCLASS(PortoLaunch)
REGISTER_WEAPON(PORTO, NEW(PortoLaunch));
#ifdef SVQC
#include "../../triggers/trigger/jumppads.qh"
-spawnfunc(weapon_porto) { weapon_defaultspawnfunc(WEP_PORTO.m_id); }
+spawnfunc(weapon_porto) { weapon_defaultspawnfunc(this, WEP_PORTO); }
REGISTER_MUTATOR(porto_ticker, true);
MUTATOR_HOOKFUNCTION(porto_ticker, SV_StartFrame) {
e.porto_forbidden = max(0, e.porto_forbidden - 1);
}
-void W_Porto_Success(void)
+void W_Porto_Success()
{SELFPARAM();
if(self.realowner == world)
{
}
}
-void W_Porto_Think(void)
+void W_Porto_Think()
{SELFPARAM();
trace_plane_normal = '0 0 0';
if(self.realowner.playerid != self.playerid)
W_Porto_Fail(0);
}
-void W_Porto_Touch(void)
+void W_Porto_Touch()
{SELFPARAM();
vector norm;
//Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- gren = spawn();
+ gren = new(porto);
gren.cnt = type;
gren.owner = gren.realowner = self;
gren.playerid = self.playerid;
- gren.classname = "porto";
gren.bot_dodge = true;
gren.bot_dodgerating = 200;
gren.movetype = MOVETYPE_BOUNCEMISSILE;
{
PORTO_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
}
- METHOD(PortoLaunch, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(PortoLaunch, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(WEP_CVAR(porto, secondary))
{
- if(fire1)
+ if(fire & 1)
if(!actor.porto_current)
if(!actor.porto_forbidden)
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(porto, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(porto, refire)))
{
W_Porto_Attack(0);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
}
- if(fire2)
+ if(fire & 2)
if(!actor.porto_current)
if(!actor.porto_forbidden)
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(porto, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(porto, refire)))
{
W_Porto_Attack(1);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(porto, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(porto, animtime), w_ready);
}
}
else
{
if(actor.porto_v_angle_held)
{
- if(!fire2)
+ if(!(fire & 2))
{
actor.porto_v_angle_held = 0;
}
else
{
- if(fire2)
+ if(fire & 2)
{
actor.porto_v_angle = actor.v_angle;
actor.porto_v_angle_held = 1;
if(actor.porto_v_angle_held)
makevectors(actor.porto_v_angle); // override the previously set angles
- if(fire1)
+ if(fire & 1)
if(!actor.porto_current)
if(!actor.porto_forbidden)
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(porto, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(porto, refire)))
{
W_Porto_Attack(-1);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
}
}
}
/* crosshair */ ATTRIB(Rifle, w_crosshair_size, float, 0.6);
/* wepimg */ ATTRIB(Rifle, model2, string, "weaponrifle");
/* refname */ ATTRIB(Rifle, netname, string, "rifle");
-/* wepname */ ATTRIB(Rifle, message, string, _("Rifle"));
+/* wepname */ ATTRIB(Rifle, m_name, string, _("Rifle"));
ENDCLASS(Rifle)
REGISTER_WEAPON(RIFLE, NEW(Rifle));
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_rifle) { weapon_defaultspawnfunc(WEP_RIFLE.m_id); }
+spawnfunc(weapon_rifle) { weapon_defaultspawnfunc(this, WEP_RIFLE); }
spawnfunc(weapon_campingrifle) { spawnfunc_weapon_rifle(this); }
spawnfunc(weapon_sniperrifle) { spawnfunc_weapon_rifle(this); }
SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self);
}
-void W_Rifle_Attack(void)
+void W_Rifle_Attack()
{
W_Rifle_FireBullet(WEP_RIFLE, WEP_CVAR_PRI(rifle, spread), WEP_CVAR_PRI(rifle, damage), WEP_CVAR_PRI(rifle, force), WEP_CVAR_PRI(rifle, solidpenetration), WEP_CVAR_PRI(rifle, ammo), WEP_RIFLE.m_id, WEP_CVAR_PRI(rifle, tracer), WEP_CVAR_PRI(rifle, shots), SND(CAMPINGRIFLE_FIRE));
}
-void W_Rifle_Attack2(void)
+void W_Rifle_Attack2()
{
W_Rifle_FireBullet(WEP_RIFLE, WEP_CVAR_SEC(rifle, spread), WEP_CVAR_SEC(rifle, damage), WEP_CVAR_SEC(rifle, force), WEP_CVAR_SEC(rifle, solidpenetration), WEP_CVAR_SEC(rifle, ammo), WEP_RIFLE.m_id | HITTYPE_SECONDARY, WEP_CVAR_SEC(rifle, tracer), WEP_CVAR_SEC(rifle, shots), SND(CAMPINGRIFLE_FIRE2));
}
-.void(void) rifle_bullethail_attackfunc;
+.void() rifle_bullethail_attackfunc;
.float rifle_bullethail_frame;
.float rifle_bullethail_animtime;
.float rifle_bullethail_refire;
-void W_Rifle_BulletHail_Continue(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Rifle_BulletHail_Continue(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
float r, sw, af;
sw = actor.switchweapon; // make it not detect weapon changes as reason to abort firing
- af = ATTACK_FINISHED(actor);
+ int slot = weaponslot(weaponentity);
+ af = ATTACK_FINISHED(actor, slot);
actor.switchweapon = actor.weapon;
- ATTACK_FINISHED(actor) = time;
- LOG_INFO(ftos(actor.WEP_AMMO(RIFLE)), "\n");
- r = weapon_prepareattack(thiswep, actor, actor.rifle_bullethail_frame == WFRAME_FIRE2, actor.rifle_bullethail_refire);
+ ATTACK_FINISHED(actor, slot) = time;
+ r = weapon_prepareattack(thiswep, actor, weaponentity, actor.rifle_bullethail_frame == WFRAME_FIRE2, actor.rifle_bullethail_refire);
if(actor.switchweapon == actor.weapon)
actor.switchweapon = sw;
if(r)
{
actor.rifle_bullethail_attackfunc();
- weapon_thinkf(actor, actor.rifle_bullethail_frame, actor.rifle_bullethail_animtime, W_Rifle_BulletHail_Continue);
- LOG_INFO("thinkf set\n");
+ weapon_thinkf(actor, weaponentity, actor.rifle_bullethail_frame, actor.rifle_bullethail_animtime, W_Rifle_BulletHail_Continue);
}
else
{
- ATTACK_FINISHED(actor) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
- LOG_INFO("out of ammo... ", ftos(actor.weaponentity.state), "\n");
+ ATTACK_FINISHED(actor, slot) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
}
}
-void W_Rifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
+void W_Rifle_BulletHail(.entity weaponentity, float mode, void() AttackFunc, float fr, float animtime, float refire)
{SELFPARAM();
// if we get here, we have at least one bullet to fire
AttackFunc();
self.rifle_bullethail_frame = fr;
self.rifle_bullethail_animtime = animtime;
self.rifle_bullethail_refire = refire;
- weapon_thinkf(self, fr, animtime, W_Rifle_BulletHail_Continue);
+ weapon_thinkf(self, weaponentity, fr, animtime, W_Rifle_BulletHail_Continue);
}
else
{
// just one shot
- weapon_thinkf(self, fr, animtime, w_ready);
+ weapon_thinkf(self, weaponentity, fr, animtime, w_ready);
}
}
}
}
}
- METHOD(Rifle, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Rifle, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(autocvar_g_balance_rifle_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(rifle, ammo), WEP_CVAR_SEC(rifle, ammo))) { // forced reload
Weapon w = get_weaponinfo(actor.weapon);
} else
{
actor.rifle_accumulator = bound(time - WEP_CVAR(rifle, bursttime), actor.rifle_accumulator, time);
- if(fire1)
- if(weapon_prepareattack_check(thiswep, actor, false, WEP_CVAR_PRI(rifle, refire)))
+ if(fire & 1)
+ if(weapon_prepareattack_check(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(rifle, refire)))
if(time >= actor.rifle_accumulator + WEP_CVAR_PRI(rifle, burstcost))
{
- weapon_prepareattack_do(actor, false, WEP_CVAR_PRI(rifle, refire));
- W_Rifle_BulletHail(WEP_CVAR_PRI(rifle, bullethail), W_Rifle_Attack, WFRAME_FIRE1, WEP_CVAR_PRI(rifle, animtime), WEP_CVAR_PRI(rifle, refire));
+ weapon_prepareattack_do(actor, weaponentity, false, WEP_CVAR_PRI(rifle, refire));
+ W_Rifle_BulletHail(weaponentity, WEP_CVAR_PRI(rifle, bullethail), W_Rifle_Attack, WFRAME_FIRE1, WEP_CVAR_PRI(rifle, animtime), WEP_CVAR_PRI(rifle, refire));
actor.rifle_accumulator += WEP_CVAR_PRI(rifle, burstcost);
}
- if(fire2)
+ if(fire & 2)
{
if(WEP_CVAR(rifle, secondary))
{
w.wr_reload(w);
} else
{
- if(weapon_prepareattack_check(thiswep, actor, true, WEP_CVAR_SEC(rifle, refire)))
+ if(weapon_prepareattack_check(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(rifle, refire)))
if(time >= actor.rifle_accumulator + WEP_CVAR_SEC(rifle, burstcost))
{
- weapon_prepareattack_do(actor, true, WEP_CVAR_SEC(rifle, refire));
- W_Rifle_BulletHail(WEP_CVAR_SEC(rifle, bullethail), W_Rifle_Attack2, WFRAME_FIRE2, WEP_CVAR_SEC(rifle, animtime), WEP_CVAR_PRI(rifle, refire));
+ weapon_prepareattack_do(actor, weaponentity, true, WEP_CVAR_SEC(rifle, refire));
+ W_Rifle_BulletHail(weaponentity, WEP_CVAR_SEC(rifle, bullethail), W_Rifle_Attack2, WFRAME_FIRE2, WEP_CVAR_SEC(rifle, animtime), WEP_CVAR_PRI(rifle, refire));
actor.rifle_accumulator += WEP_CVAR_SEC(rifle, burstcost);
}
}
{
vector org2;
org2 = w_org + w_backoff * 2;
- pointparticles(particleeffectnum(EFFECT_RIFLE_IMPACT), org2, w_backoff * 1000, 1);
+ pointparticles(EFFECT_RIFLE_IMPACT, org2, w_backoff * 1000, 1);
if(!w_issilent)
{
- if(w_random < 0.2)
- sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTN_NORM);
- else if(w_random < 0.4)
- sound(self, CH_SHOTS, SND_RIC2, VOL_BASE, ATTN_NORM);
- else if(w_random < 0.5)
- sound(self, CH_SHOTS, SND_RIC3, VOL_BASE, ATTN_NORM);
+ sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTN_NORM);
}
}
METHOD(Rifle, wr_init, void(entity thiswep))
+++ /dev/null
-#ifndef IMPLEMENTATION
-CLASS(RocketPropelledChainsaw, Weapon)
-/* ammotype */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets)
-/* impulse */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7)
-/* flags */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
-/* rating */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
-/* color */ ATTRIB(RocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
-/* modelname */ ATTRIB(RocketPropelledChainsaw, mdl, string, "ok_rl");
-#ifndef MENUQC
-/* model */ ATTRIB(RocketPropelledChainsaw, m_model, Model, MDL_RPC_ITEM);
-#endif
-/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair, string, "gfx/crosshairrocketlauncher");
-/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair_size, float, 0.6);
-/* wepimg */ ATTRIB(RocketPropelledChainsaw, model2, string, "weaponrpc");
-/* refname */ ATTRIB(RocketPropelledChainsaw, netname, string, "rpc");
-/* wepname */ ATTRIB(RocketPropelledChainsaw, message, string, _("Rocket Propelled Chainsaw"));
-ENDCLASS(RocketPropelledChainsaw)
-REGISTER_WEAPON(RPC, NEW(RocketPropelledChainsaw));
-
-#define RPC_SETTINGS(w_cvar,w_prop) RPC_SETTINGS_LIST(w_cvar, w_prop, RPC, rpc)
-#define RPC_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
- w_cvar(id, sn, NONE, ammo) \
- w_cvar(id, sn, NONE, animtime) \
- w_cvar(id, sn, NONE, damage) \
- w_cvar(id, sn, NONE, damage2) \
- w_cvar(id, sn, NONE, damageforcescale) \
- w_cvar(id, sn, NONE, edgedamage) \
- w_cvar(id, sn, NONE, force) \
- w_cvar(id, sn, NONE, health) \
- w_cvar(id, sn, NONE, lifetime) \
- w_cvar(id, sn, NONE, radius) \
- w_cvar(id, sn, NONE, refire) \
- w_cvar(id, sn, NONE, speed) \
- w_cvar(id, sn, NONE, speedaccel) \
- w_prop(id, sn, float, reloading_ammo, reload_ammo) \
- w_prop(id, sn, float, reloading_time, reload_time) \
- w_prop(id, sn, float, switchdelay_raise, switchdelay_raise) \
- w_prop(id, sn, float, switchdelay_drop, switchdelay_drop) \
- w_prop(id, sn, string, weaponreplace, weaponreplace) \
- w_prop(id, sn, float, weaponstart, weaponstart) \
- w_prop(id, sn, float, weaponstartoverride, weaponstartoverride) \
- w_prop(id, sn, float, weaponthrowable, weaponthrowable)
-
-#ifdef SVQC
-RPC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
-#endif
-#endif
-#ifdef IMPLEMENTATION
-#ifdef SVQC
-spawnfunc(weapon_rpc) { weapon_defaultspawnfunc(WEP_RPC.m_id); }
-
-void W_RocketPropelledChainsaw_Explode()
-{SELFPARAM();
- self.event_damage = func_null;
- self.takedamage = DAMAGE_NO;
-
- RadiusDamage (self, self.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), world, world, WEP_CVAR(rpc, force), self.projectiledeathtype, other);
-
- remove (self);
-}
-
-void W_RocketPropelledChainsaw_Touch (void)
-{SELFPARAM();
- if(WarpZone_Projectile_Touch())
- if(wasfreed(self))
- return;
-
- W_RocketPropelledChainsaw_Explode();
-}
-
-void W_RocketPropelledChainsaw_Damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
- if (self.health <= 0)
- return;
-
- if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
- return; // g_projectiles_damage says to halt
-
- self.health = self.health - damage;
-
- if (self.health <= 0)
- W_PrepareExplosionByDamage(attacker, W_RocketPropelledChainsaw_Explode);
-}
-
-void W_RocketPropelledChainsaw_Think()
-{SELFPARAM();
- if(self.cnt <= time)
- {
- remove(self);
- return;
- }
-
- self.cnt = vlen(self.velocity);
- self.wait = self.cnt * sys_frametime;
- self.pos1 = normalize(self.velocity);
-
- tracebox(self.origin, self.mins, self.maxs, self.origin + self.pos1 * (2 * self.wait), MOVE_NORMAL, self);
- if(IS_PLAYER(trace_ent))
- Damage (trace_ent, self, self.realowner, WEP_CVAR(rpc, damage2), self.projectiledeathtype, self.origin, normalize(self.origin - other.origin) * WEP_CVAR(rpc, force));
-
- self.velocity = self.pos1 * (self.cnt + (WEP_CVAR(rpc, speedaccel) * sys_frametime));
-
- UpdateCSQCProjectile(self);
- self.nextthink = time;
-}
-
-void W_RocketPropelledChainsaw_Attack (Weapon thiswep)
-{SELFPARAM();
- entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(self);
- entity flash = spawn ();
-
- W_DecreaseAmmo(thiswep, self, WEP_CVAR(rpc, ammo));
- W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', false, 5, SND(ROCKET_FIRE), CH_WEAPON_A, WEP_CVAR(rpc, damage));
- Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- PROJECTILE_MAKETRIGGER(missile);
-
- missile.owner = missile.realowner = self;
- missile.bot_dodge = true;
- missile.bot_dodgerating = WEP_CVAR(rpc, damage) * 2;
-
- missile.takedamage = DAMAGE_YES;
- missile.damageforcescale = WEP_CVAR(rpc, damageforcescale);
- missile.health = WEP_CVAR(rpc, health);
- missile.event_damage = W_RocketPropelledChainsaw_Damage;
- missile.damagedbycontents = true;
- missile.movetype = MOVETYPE_FLY;
-
- missile.projectiledeathtype = WEP_RPC.m_id;
- setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
-
- setorigin (missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
- W_SetupProjVelocity_Basic(missile, WEP_CVAR(rpc, speed), 0);
-
- missile.touch = W_RocketPropelledChainsaw_Touch;
-
- missile.think = W_RocketPropelledChainsaw_Think;
- missile.cnt = time + WEP_CVAR(rpc, lifetime);
- missile.nextthink = time;
- missile.flags = FL_PROJECTILE;
-
- CSQCProjectile(missile, true, PROJECTILE_RPC, false);
-
- setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
- SUB_SetFade (flash, time, 0.1);
- flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
- W_AttachToShotorg(self, flash, '5 0 0');
- missile.pos1 = missile.velocity;
-
- MUTATOR_CALLHOOK(EditProjectile, self, missile);
-}
-
- METHOD(RocketPropelledChainsaw, wr_aim, void(entity thiswep))
- {
- self.BUTTON_ATCK = bot_aim(WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false);
- }
- METHOD(RocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
- {
- if(WEP_CVAR(rpc, reload_ammo) && actor.clip_load < WEP_CVAR(rpc, ammo)) {
- Weapon w = get_weaponinfo(actor.weapon);
- w.wr_reload(w);
- } else
- {
- if (fire1)
- {
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(rpc, refire)))
- {
- W_RocketPropelledChainsaw_Attack(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(rpc, animtime), w_ready);
- }
- }
-
- if (fire2)
- {
- // to-do
- }
- }
- }
- METHOD(RocketPropelledChainsaw, wr_init, void(entity thiswep))
- {
- RPC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
- }
- METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep))
- {
- float ammo_amount = self.WEP_AMMO(RPC) >= WEP_CVAR(rpc, ammo);
- ammo_amount += self.(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo);
- return ammo_amount;
- }
- METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep))
- {
- return false;
- }
- METHOD(RocketPropelledChainsaw, wr_config, void(entity thiswep))
- {
- RPC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
- }
- METHOD(RocketPropelledChainsaw, wr_reload, void(entity thiswep))
- {
- W_Reload(self, WEP_CVAR(rpc, ammo), SND(RELOAD));
- }
- METHOD(RocketPropelledChainsaw, wr_suicidemessage, int(entity thiswep))
- {
- if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
- return WEAPON_RPC_SUICIDE_SPLASH;
- else
- return WEAPON_RPC_SUICIDE_DIRECT;
- }
- METHOD(RocketPropelledChainsaw, wr_killmessage, int(entity thiswep))
- {
- if(w_deathtype & HITTYPE_SECONDARY)
- return WEAPON_BLASTER_MURDER;
- else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
- return WEAPON_RPC_MURDER_SPLASH;
- else
- return WEAPON_RPC_MURDER_DIRECT;
- }
-
-#endif
-
-#ifdef CSQC
-
- METHOD(RocketPropelledChainsaw, wr_impacteffect, void(entity thiswep))
- {
- vector org2;
- org2 = w_org + w_backoff * 12;
- pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), org2, '0 0 0', 1);
- if(!w_issilent)
- sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
- }
-
-#endif
-#endif
/* crosshair */ ATTRIB(Seeker, w_crosshair_size, float, 0.8);
/* wepimg */ ATTRIB(Seeker, model2, string, "weaponseeker");
/* refname */ ATTRIB(Seeker, netname, string, "seeker");
-/* wepname */ ATTRIB(Seeker, message, string, _("T.A.G. Seeker"));
+/* wepname */ ATTRIB(Seeker, m_name, string, _("T.A.G. Seeker"));
ENDCLASS(Seeker)
REGISTER_WEAPON(SEEKER, NEW(Seeker));
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_seeker) { weapon_defaultspawnfunc(WEP_SEEKER.m_id); }
+spawnfunc(weapon_seeker) { weapon_defaultspawnfunc(this, WEP_SEEKER); }
// ============================
// Begin: Missile functions, these are general functions to be manipulated by other code
// ============================
-void W_Seeker_Missile_Explode(void)
+void W_Seeker_Missile_Explode()
{SELFPARAM();
self.event_damage = func_null;
RadiusDamage(self, self.realowner, WEP_CVAR(seeker, missile_damage), WEP_CVAR(seeker, missile_edgedamage), WEP_CVAR(seeker, missile_radius), world, world, WEP_CVAR(seeker, missile_force), self.projectiledeathtype, other);
remove(self);
}
-void W_Seeker_Missile_Touch(void)
+void W_Seeker_Missile_Touch()
{
PROJECTILE_TOUCH;
W_Seeker_Missile_Explode();
}
-void W_Seeker_Missile_Think(void)
+void W_Seeker_Missile_Think()
{SELFPARAM();
entity e;
vector desireddir, olddir, newdir, eorg;
}
/*
-void W_Seeker_Missile_Animate(void)
+void W_Seeker_Missile_Animate()
{
self.frame = self.frame +1;
self.nextthink = time + 0.05;
//self.detornator = false;
- missile = spawn();
+ missile = new(seeker_missile);
missile.owner = missile.realowner = self;
- missile.classname = "seeker_missile";
missile.bot_dodge = true;
missile.bot_dodgerating = WEP_CVAR(seeker, missile_damage);
// ============================
// Begin: FLAC, close range attack meant for defeating rockets which are coming at you.
// ============================
-void W_Seeker_Flac_Explode(void)
+void W_Seeker_Flac_Explode()
{SELFPARAM();
self.event_damage = func_null;
remove(self);
}
-void W_Seeker_Flac_Touch(void)
+void W_Seeker_Flac_Touch()
{
PROJECTILE_TOUCH;
Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- missile = spawn();
+ missile = new(missile);
missile.owner = missile.realowner = self;
- missile.classname = "missile";
missile.bot_dodge = true;
missile.bot_dodgerating = WEP_CVAR(seeker, flac_damage);
missile.touch = W_Seeker_Flac_Explode;
return world;
}
-void W_Seeker_Attack(void)
+void W_Seeker_Attack()
{SELFPARAM();
entity tracker, closest_target;
W_Seeker_Fire_Missile(WEP_SEEKER, '0 0 0', closest_target);
}
-void W_Seeker_Vollycontroller_Think(void) // TODO: Merge this with W_Seeker_Attack
+void W_Seeker_Vollycontroller_Think() // TODO: Merge this with W_Seeker_Attack
{SELFPARAM();
float c;
entity oldenemy;
setself(this);
}
-void W_Seeker_Tracker_Think(void)
+void W_Seeker_Tracker_Think()
{SELFPARAM();
// commit suicide if: You die OR target dies OR you switch away from the seeker OR commit suicide if lifetime is up
if((self.realowner.deadflag != DEAD_NO) || (self.tag_target.deadflag != DEAD_NO) || (self.realowner.switchweapon != WEP_SEEKER.m_id)
// ============================
// Begin: Tag projectile
// ============================
-void W_Seeker_Tag_Explode(void)
+void W_Seeker_Tag_Explode()
{SELFPARAM();
//if(other==self.realowner)
// return;
W_Seeker_Tag_Explode();
}
-void W_Seeker_Tag_Touch(void)
+void W_Seeker_Tag_Touch()
{SELFPARAM();
vector dir;
vector org2;
else
{
//sprint(self.realowner, strcat("You just tagged ^2", other.netname, "^7 with a tracking device!\n"));
- e = spawn();
+ e = new(tag_tracker);
e.cnt = WEP_CVAR(seeker, missile_count);
- e.classname = "tag_tracker";
e.owner = self.owner;
e.realowner = self.realowner;
W_SetupShot_ProjectileSize(self, '-2 -2 -2', '2 2 2', false, 2, SND(TAG_FIRE), CH_WEAPON_A, WEP_CVAR(seeker, missile_damage) * WEP_CVAR(seeker, missile_count));
- missile = spawn();
+ missile = new(seeker_tag);
missile.owner = missile.realowner = self;
- missile.classname = "seeker_tag";
missile.bot_dodge = true;
missile.bot_dodgerating = 50;
missile.touch = W_Seeker_Tag_Touch;
else
self.BUTTON_ATCK = bot_aim(WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false);
}
- METHOD(Seeker, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Seeker, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(autocvar_g_balance_seeker_reload_ammo && actor.clip_load < min(WEP_CVAR(seeker, missile_ammo), WEP_CVAR(seeker, tag_ammo))) { // forced reload
Weapon w = get_weaponinfo(actor.weapon);
w.wr_reload(w);
- } else if(fire1)
+ } else if(fire & 1)
{
if(WEP_CVAR(seeker, type) == 1)
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(seeker, missile_refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, missile_refire)))
{
W_Seeker_Attack();
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(seeker, missile_animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, missile_animtime), w_ready);
}
}
else
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(seeker, tag_refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, tag_refire)))
{
W_Seeker_Fire_Tag(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(seeker, tag_animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, tag_animtime), w_ready);
}
}
}
- else if(fire2)
+ else if(fire & 2)
{
if(WEP_CVAR(seeker, type) == 1)
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(seeker, tag_refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, tag_refire)))
{
W_Seeker_Fire_Tag(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(seeker, tag_animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, tag_animtime), w_ready);
}
}
else
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(seeker, flac_refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, flac_refire)))
{
W_Seeker_Fire_Flac(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(seeker, flac_animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, flac_animtime), w_ready);
}
}
}
}
else
{
- pointparticles(particleeffectnum(EFFECT_HAGAR_EXPLODE), org2, '0 0 0', 1);
+ pointparticles(EFFECT_HAGAR_EXPLODE, org2, '0 0 0', 1);
if(!w_issilent)
{
if(w_random<0.15)
}
else
{
- pointparticles(particleeffectnum(EFFECT_HAGAR_EXPLODE), org2, '0 0 0', 1);
+ pointparticles(EFFECT_HAGAR_EXPLODE, org2, '0 0 0', 1);
if(!w_issilent)
{
if(w_random<0.15)
/* crosshair */ ATTRIB(Shockwave, w_crosshair_size, float, 0.7);
/* wepimg */ ATTRIB(Shockwave, model2, string, "weaponshotgun");
/* refname */ ATTRIB(Shockwave, netname, string, "shockwave");
-/* wepname */ ATTRIB(Shockwave, message, string, _("Shockwave"));
+/* wepname */ ATTRIB(Shockwave, m_name, string, _("Shockwave"));
ENDCLASS(Shockwave)
REGISTER_WEAPON(SHOCKWAVE, NEW(Shockwave));
SHOCKWAVE_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
#endif
#ifdef CSQC
-void Net_ReadShockwaveParticle(void);
+void Net_ReadShockwaveParticle();
.vector sw_shotorg;
.vector sw_shotdir;
.float sw_distance;
#endif
#endif
#ifdef IMPLEMENTATION
+
+REGISTER_NET_TEMP(TE_CSQC_SHOCKWAVEPARTICLE)
+
#ifdef SVQC
spawnfunc(weapon_shockwave)
{
if(autocvar_sv_q3acompat_machineshotgunswap)
if(self.classname != "droppedweapon")
{
- weapon_defaultspawnfunc(WEP_MACHINEGUN.m_id);
+ weapon_defaultspawnfunc(this, WEP_MACHINEGUN);
return;
}
- weapon_defaultspawnfunc(WEP_SHOCKWAVE.m_id);
+ weapon_defaultspawnfunc(this, WEP_SHOCKWAVE);
}
const float MAX_SHOCKWAVE_HITS = 10;
vector shockwave_hit_force[MAX_SHOCKWAVE_HITS];
// MELEE ATTACK MODE
-void W_Shockwave_Melee_Think(void)
+void W_Shockwave_Melee_Think()
{SELFPARAM();
// declarations
float i, f, swing, swing_factor, swing_damage, meleetime, is_player;
}
}
-void W_Shockwave_Melee(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Shockwave_Melee(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
sound(actor, CH_WEAPON_A, SND_SHOTGUN_MELEE, VOL_BASE, ATTN_NORM);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(shockwave, melee_animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(shockwave, melee_animtime), w_ready);
- entity meleetemp;
- meleetemp = spawn();
+ entity meleetemp = new(meleetemp);
+ make_pure(meleetemp);
meleetemp.owner = meleetemp.realowner = actor;
meleetemp.think = W_Shockwave_Melee_Think;
meleetemp.nextthink = time + WEP_CVAR(shockwave, melee_delay) * W_WeaponRateFactor();
return true;
}
-void W_Shockwave_Send(void)
+void W_Shockwave_Send()
{SELFPARAM();
- WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte(MSG_BROADCAST, TE_CSQC_SHOCKWAVEPARTICLE);
+ WriteHeader(MSG_BROADCAST, TE_CSQC_SHOCKWAVEPARTICLE);
WriteCoord(MSG_BROADCAST, w_shotorg.x);
WriteCoord(MSG_BROADCAST, w_shotorg.y);
WriteCoord(MSG_BROADCAST, w_shotorg.z);
WriteByte(MSG_BROADCAST, num_for_edict(self));
}
-void W_Shockwave_Attack(void)
+void W_Shockwave_Attack()
{SELFPARAM();
// declarations
float multiplier, multiplier_from_accuracy, multiplier_from_distance;
else
{ self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, false); }
}
- METHOD(Shockwave, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Shockwave, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
- if(fire1)
+ if(fire & 1)
{
if(time >= actor.shockwave_blasttime) // handle refire separately so the secondary can be fired straight after a primary
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(shockwave, blast_animtime)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(shockwave, blast_animtime)))
{
W_Shockwave_Attack();
actor.shockwave_blasttime = time + WEP_CVAR(shockwave, blast_refire) * W_WeaponRateFactor();
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(shockwave, blast_animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(shockwave, blast_animtime), w_ready);
}
}
}
- else if(fire2)
+ else if(fire & 2)
{
//if(actor.clip_load >= 0) // we are not currently reloading
if(!actor.crouch) // no crouchmelee please
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR(shockwave, melee_refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR(shockwave, melee_refire)))
{
// attempt forcing playback of the anim by switching to another anim (that we never play) here...
- weapon_thinkf(actor, WFRAME_FIRE1, 0, W_Shockwave_Melee);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, W_Shockwave_Melee);
}
}
}
}
}
-void Net_ReadShockwaveParticle(void)
+NET_HANDLE(TE_CSQC_SHOCKWAVEPARTICLE, bool isNew)
+{
+ Net_ReadShockwaveParticle();
+ return true;
+}
+
+void Net_ReadShockwaveParticle()
{
entity shockwave;
shockwave = spawn();
// handled by Net_ReadShockwaveParticle
//vector org2;
//org2 = w_org + w_backoff * 2;
- //pointparticles(particleeffectnum(EFFECT_BLASTER_IMPACT), org2, w_backoff * 1000, 1);
+ //pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
}
#endif
/* crosshair */ ATTRIB(Shotgun, w_crosshair_size, float, 0.65);
/* wepimg */ ATTRIB(Shotgun, model2, string, "weaponshotgun");
/* refname */ ATTRIB(Shotgun, netname, string, "shotgun");
-/* wepname */ ATTRIB(Shotgun, message, string, _("Shotgun"));
+/* wepname */ ATTRIB(Shotgun, m_name, string, _("Shotgun"));
ENDCLASS(Shotgun)
REGISTER_WEAPON(SHOTGUN, NEW(Shotgun));
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_shotgun) { weapon_defaultspawnfunc(WEP_SHOTGUN.m_id); }
+spawnfunc(weapon_shotgun) { weapon_defaultspawnfunc(this, WEP_SHOTGUN); }
void W_Shotgun_Attack(Weapon thiswep, float isprimary)
{SELFPARAM();
.float swing_prev;
.entity swing_alreadyhit;
-void W_Shotgun_Melee_Think(void)
+void W_Shotgun_Melee_Think()
{SELFPARAM();
// declarations
float i, f, swing, swing_factor, swing_damage, meleetime, is_player;
}
}
-void W_Shotgun_Attack2(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Shotgun_Attack2(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
sound(actor, CH_WEAPON_A, SND_SHOTGUN_MELEE, VOL_BASE, ATTEN_NORM);
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(shotgun, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(shotgun, animtime), w_ready);
- entity meleetemp;
- meleetemp = spawn();
+ entity meleetemp = new(meleetemp);
+ make_pure(meleetemp);
meleetemp.realowner = actor;
meleetemp.think = W_Shotgun_Melee_Think;
meleetemp.nextthink = time + WEP_CVAR_SEC(shotgun, melee_delay) * W_WeaponRateFactor();
}
// alternate secondary weapon frames
-void W_Shotgun_Attack3_Frame2(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Shotgun_Attack3_Frame2(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
Weapon w = get_weaponinfo(actor.weapon);
if (!w.wr_checkammo2(w))
if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
{
W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
- w_ready(thiswep, actor, fire1, fire2);
+ w_ready(thiswep, actor, weaponentity, fire);
return;
}
sound(actor, CH_WEAPON_SINGLE, SND_Null, VOL_BASE, ATTN_NORM); // kill previous sound
W_Shotgun_Attack(WEP_SHOTGUN, true); // actually is secondary, but we trick the last shot into playing full reload sound
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), w_ready);
}
-void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
Weapon w = get_weaponinfo(actor.weapon);
if (!w.wr_checkammo2(w))
if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
{
W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
- w_ready(thiswep, actor, fire1, fire2);
+ w_ready(thiswep, actor, weaponentity, fire);
return;
}
W_Shotgun_Attack(WEP_SHOTGUN, false);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame2);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame2);
}
.float shotgun_primarytime;
else
self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, false);
}
- METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(WEP_CVAR(shotgun, reload_ammo) && actor.clip_load < WEP_CVAR_PRI(shotgun, ammo)) // forced reload
{
}
else
{
- if(fire1)
+ if(fire & 1)
{
if(time >= actor.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(shotgun, animtime)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(shotgun, animtime)))
{
W_Shotgun_Attack(thiswep, true);
actor.shotgun_primarytime = time + WEP_CVAR_PRI(shotgun, refire) * W_WeaponRateFactor();
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(shotgun, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(shotgun, animtime), w_ready);
}
}
}
- else if(fire2 && WEP_CVAR(shotgun, secondary) == 2)
+ else if((fire & 2) && WEP_CVAR(shotgun, secondary) == 2)
{
if(time >= actor.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_SEC(shotgun, alt_animtime)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(shotgun, alt_animtime)))
{
W_Shotgun_Attack(thiswep, false);
actor.shotgun_primarytime = time + WEP_CVAR_SEC(shotgun, alt_refire) * W_WeaponRateFactor();
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame1);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame1);
}
}
}
if(actor.clip_load >= 0) // we are not currently reloading
if(!actor.crouch) // no crouchmelee please
if(WEP_CVAR(shotgun, secondary) == 1)
- if((fire1 && actor.WEP_AMMO(SHOTGUN) <= 0 && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || fire2)
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(shotgun, refire)))
+ if(((fire & 1) && actor.WEP_AMMO(SHOTGUN) <= 0 && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (fire & 2))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(shotgun, refire)))
{
// attempt forcing playback of the anim by switching to another anim (that we never play) here...
- weapon_thinkf(actor, WFRAME_FIRE1, 0, W_Shotgun_Attack2);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, W_Shotgun_Attack2);
}
}
METHOD(Shotgun, wr_init, void(entity thiswep))
METHOD(Shotgun, wr_impacteffect, void(entity thiswep))
{
vector org2 = w_org + w_backoff * 2;
- pointparticles(particleeffectnum(EFFECT_SHOTGUN_IMPACT), org2, w_backoff * 1000, 1);
+ pointparticles(EFFECT_SHOTGUN_IMPACT, org2, w_backoff * 1000, 1);
if(!w_issilent && time - self.prevric > 0.25)
{
- if(w_random < 0.0165)
- sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTEN_NORM);
- else if(w_random < 0.033)
- sound(self, CH_SHOTS, SND_RIC2, VOL_BASE, ATTEN_NORM);
- else if(w_random < 0.05)
- sound(self, CH_SHOTS, SND_RIC3, VOL_BASE, ATTEN_NORM);
+ if(w_random < 0.05)
+ sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
self.prevric = time;
}
}
/* wepimg */ ATTRIB(Tuba, model2, string, "weapontuba");
/* refname */ ATTRIB(Tuba, netname, string, "tuba");
/* xgettext:no-c-format */
-/* wepname */ ATTRIB(Tuba, message, string, _("@!#%'n Tuba"));
+/* wepname */ ATTRIB(Tuba, m_name, string, _("@!#%'n Tuba"));
ENDCLASS(Tuba)
REGISTER_WEAPON(TUBA, NEW(Tuba));
#endif
#ifdef IMPLEMENTATION
#ifdef SVQC
-spawnfunc(weapon_tuba) { weapon_defaultspawnfunc(WEP_TUBA.m_id); }
+spawnfunc(weapon_tuba) { weapon_defaultspawnfunc(this, WEP_TUBA); }
bool W_Tuba_HasPlayed(entity pl, string melody, int instrument, bool ignorepitch, float mintempo, float maxtempo)
{
return true;
}
-void W_Tuba_NoteOff(void)
+void W_Tuba_NoteOff()
{SELFPARAM();
// we have a note:
// on: self.spawnshieldtime
if(!sound_allowed(MSG_ONE, self.realowner))
return false;
- WriteByte(MSG_ENTITY, ENT_CLIENT_TUBANOTE);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_TUBANOTE);
WriteByte(MSG_ENTITY, sf);
if(sf & 1)
{
return true;
}
-void W_Tuba_NoteThink(void)
+void W_Tuba_NoteThink()
{SELFPARAM();
float dist_mult;
float vol0, vol1;
self.BUTTON_ATCK2 = 1;
}
}
- METHOD(Tuba, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Tuba, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
- if(fire1)
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(tuba, refire)))
+ if(fire & 1)
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(tuba, refire)))
{
W_Tuba_NoteOn(0);
//weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_tuba_animtime, w_ready);
- weapon_thinkf(actor, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
}
- if(fire2)
- if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR(tuba, refire)))
+ if(fire & 2)
+ if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR(tuba, refire)))
{
W_Tuba_NoteOn(HITTYPE_SECONDARY);
//weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_balance_tuba_animtime, w_ready);
- weapon_thinkf(actor, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
}
if(actor.tuba_note)
{
- if(!fire1 && !fire2)
+ if(!(fire & 1) && !(fire & 2))
{
WITH(entity, self, actor.tuba_note, W_Tuba_NoteOff());
}
}
METHOD(Tuba, wr_reload, void(entity thiswep))
{
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
// switch to alternate instruments :)
- if(self.weaponentity.state == WS_READY)
+ if(self.(weaponentity).state == WS_READY)
{
switch(self.tuba_instrument)
{
}
W_SetupShot(self, false, 0, "", 0, 0);
Send_Effect(EFFECT_TELEPORT, w_shotorg, '0 0 0', 1);
- self.weaponentity.state = WS_INUSE;
- weapon_thinkf(self, WFRAME_RELOAD, 0.5, w_ready);
+ self.(weaponentity).state = WS_INUSE;
+ weapon_thinkf(self, weaponentity, WFRAME_RELOAD, 0.5, w_ready);
}
}
METHOD(Tuba, wr_checkammo1, bool(entity thiswep))
/* crosshair */ ATTRIB(Vaporizer, w_crosshair_size, float, 0.6);
/* wepimg */ ATTRIB(Vaporizer, model2, string, "weaponminstanex");
/* refname */ ATTRIB(Vaporizer, netname, string, "vaporizer");
-/* wepname */ ATTRIB(Vaporizer, message, string, _("Vaporizer"));
+/* wepname */ ATTRIB(Vaporizer, m_name, string, _("Vaporizer"));
ENDCLASS(Vaporizer)
REGISTER_WEAPON(VAPORIZER, NEW(Vaporizer));
#endif
#endif
#ifdef IMPLEMENTATION
+
+REGISTER_NET_TEMP(TE_CSQC_VAPORBEAMPARTICLE)
+
+#if defined(SVQC)
+void SendCSQCVaporizerBeamParticle(entity player, int hit) {
+ vector v;
+ v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
+ WriteHeader(MSG_BROADCAST, TE_CSQC_VAPORBEAMPARTICLE);
+ WriteCoord(MSG_BROADCAST, w_shotorg.x);
+ WriteCoord(MSG_BROADCAST, w_shotorg.y);
+ WriteCoord(MSG_BROADCAST, w_shotorg.z);
+ WriteCoord(MSG_BROADCAST, v.x);
+ WriteCoord(MSG_BROADCAST, v.y);
+ WriteCoord(MSG_BROADCAST, v.z);
+ WriteByte(MSG_BROADCAST, hit);
+ WriteShort(MSG_BROADCAST, num_for_edict(player));
+ WriteByte(MSG_BROADCAST, player.team);
+}
+#elif defined(CSQC)
+bool autocvar_cl_vaporizerbeam_particle = false;
+float autocvar_cl_vaporizerbeam_lifetime = 0.8;
+float autocvar_cl_vaporizerbeam_colorboost = 0.7;
+
+string Draw_VaporizerBeam_trace_callback_tex;
+float Draw_VaporizerBeam_trace_callback_rnd;
+vector Draw_VaporizerBeam_trace_callback_rgb;
+float Draw_VaporizerBeam_trace_callback_a;
+void Draw_VaporizerBeam_trace_callback(vector start, vector hit, vector end)
+{
+ float i;
+ vector vorg;
+ vorg = WarpZone_TransformOrigin(WarpZone_trace_transform, view_origin);
+ for(i = 0; i < Draw_VaporizerBeam_trace_callback_a; ++i)
+ Draw_CylindricLine(hit, start, 8, Draw_VaporizerBeam_trace_callback_tex, 0.25, Draw_VaporizerBeam_trace_callback_rnd, Draw_VaporizerBeam_trace_callback_rgb, min(1, Draw_VaporizerBeam_trace_callback_a - i), DRAWFLAG_NORMAL, vorg);
+ Draw_VaporizerBeam_trace_callback_rnd += 0.25 * vlen(hit - start) / 8;
+}
+
+.vector vorg1, vorg2;
+.float spawn_time;
+void VaporizerBeam_Draw(entity this)
+{
+ //draw either the old v2.3 beam or the new beam
+ particles_alphamin = particles_alphamax = particles_fade = 1;
+
+ string tex = "particles/lgbeam";
+ if(this.cnt)
+ tex = "particles/gauntletbeam";
+ vector rgb = getcsqcplayercolor(this.sv_entnum);
+ rgb *= (1 + autocvar_cl_vaporizerbeam_colorboost);
+
+ float fail = (self.nextthink - time);
+
+ Draw_VaporizerBeam_trace_callback_tex = tex;
+ Draw_VaporizerBeam_trace_callback_rnd = 0;
+ Draw_VaporizerBeam_trace_callback_rgb = rgb;
+ Draw_VaporizerBeam_trace_callback_a = bound(0, fail, 1);
+ WarpZone_TraceBox_ThroughZone(this.vorg1, '0 0 0', '0 0 0', this.vorg2, MOVE_NOTHING, world, world, Draw_VaporizerBeam_trace_callback);
+ Draw_VaporizerBeam_trace_callback_tex = string_null;
+
+ /*if(!MUTATOR_CALLHOOK(Particles_VaporizerBeam, this.vorg1, this.vorg2))
+ if(autocvar_cl_particles_oldvortexbeam && (getstati(STAT_ALLOW_OLDVORTEXBEAM) || isdemo()))
+ WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM_OLD), this.vorg1, this.vorg2, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
+ else
+ WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM), this.vorg1, this.vorg2, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);*/
+}
+
+NET_HANDLE(TE_CSQC_VAPORBEAMPARTICLE, bool isNew)
+{
+ Net_Accept(vortex_beam);
+ this.think = SUB_Remove;
+ this.nextthink = time + bound(0, autocvar_cl_vaporizerbeam_lifetime, 10);
+ this.draw = VaporizerBeam_Draw;
+ this.drawmask = MASK_NORMAL;
+
+ this.vorg1_x = ReadCoord(); this.vorg1_y = ReadCoord(); this.vorg1_z = ReadCoord();
+ this.vorg2_x = ReadCoord(); this.vorg2_y = ReadCoord(); this.vorg2_z = ReadCoord();
+ this.cnt = ReadByte();
+ this.sv_entnum = ReadShort();
+ this.team = ReadByte() - 1;
+
+ if(autocvar_cl_vaporizerbeam_particle)
+ {
+ WarpZone_TrailParticles(world, particleeffectnum(((this.cnt) ? EFFECT_VAPORIZER_HIT(this.team) : EFFECT_VAPORIZER(this.team))), this.vorg1, this.vorg2);
+ this.draw = func_null;
+ this.drawmask = MASK_NORMAL;
+ remove(this);
+ }
+
+ pointparticles(EFFECT_VORTEX_MUZZLEFLASH, this.vorg1, normalize(this.vorg2 - this.vorg1) * 1000, 1);
+ return true;
+}
+#endif
+
#ifdef SVQC
-spawnfunc(weapon_vaporizer) { weapon_defaultspawnfunc(WEP_VAPORIZER.m_id); }
+spawnfunc(weapon_vaporizer) { weapon_defaultspawnfunc(this, WEP_VAPORIZER); }
spawnfunc(weapon_minstanex) { spawnfunc_weapon_vaporizer(this); }
void W_RocketMinsta_Explosion(vector loc)
damage_goodhits = 0;
FireRailgunBullet(w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, vaporizer_damage, 800, 0, 0, 0, 0, WEP_VAPORIZER.m_id);
+ // do this now, as goodhits is disabled below
+ SendCSQCVaporizerBeamParticle(self, damage_goodhits);
+
if(yoda && flying)
Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
if(damage_goodhits && self.vaporizer_lasthit)
self.vaporizer_lasthit = damage_goodhits;
- Send_Effect(EFFECT_VORTEX_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
-
- // teamcolor / hit beam effect
- vector v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
- Send_Effect((damage_goodhits ? EFFECT_VAPORIZER_HIT(self.team) : EFFECT_VAPORIZER(self.team)), w_shotorg, v, 1);
-
if(autocvar_g_rm)
if(!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
W_RocketMinsta_Explosion(trace_endpos);
W_DecreaseAmmo(thiswep, self, ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo)));
}
-void W_RocketMinsta_Laser_Explode (void)
+void W_RocketMinsta_Laser_Explode ()
{SELFPARAM();
if(other.takedamage == DAMAGE_AIM)
if(IS_PLAYER(other))
remove(self);
}
-void W_RocketMinsta_Laser_Touch (void)
+void W_RocketMinsta_Laser_Touch ()
{SELFPARAM();
PROJECTILE_TOUCH;
//W_RocketMinsta_Laser_Explode ();
remove(self);
}
-void W_RocketMinsta_Attack2(void)
+void W_RocketMinsta_Attack2()
{SELFPARAM();
makevectors(self.v_angle);
while(counter < total)
{
- proj = spawn ();
- proj.classname = "plasma_prim";
+ proj = new(plasma_prim);
proj.owner = proj.realowner = self;
proj.bot_dodge = true;
proj.bot_dodgerating = autocvar_g_rm_laser_damage;
}
}
-void W_RocketMinsta_Attack3 (void)
+void W_RocketMinsta_Attack3 ()
{SELFPARAM();
makevectors(self.v_angle);
while(counter < total)
{
- proj = spawn ();
- proj.classname = "plasma_prim";
+ proj = new(plasma_prim);
proj.owner = proj.realowner = self;
proj.bot_dodge = true;
proj.bot_dodgerating = autocvar_g_rm_laser_damage;
else
self.BUTTON_ATCK2 = bot_aim(WEP_CVAR_SEC(vaporizer, speed), 0, WEP_CVAR_SEC(vaporizer, lifetime), false); // WEAPONTODO: replace with proper vaporizer cvars
}
- METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
float vaporizer_ammo = ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo));
// if the laser uses load, we also consider its ammo for reloading
Weapon w = get_weaponinfo(actor.weapon);
w.wr_reload(w);
}
- if(fire1 && (actor.ammo_cells || !autocvar_g_rm) && !forbidWeaponUse(actor))
+ if((fire & 1) && (actor.ammo_cells || !autocvar_g_rm) && !forbidWeaponUse(actor))
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(vaporizer, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(vaporizer, refire)))
{
W_Vaporizer_Attack(thiswep);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(vaporizer, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(vaporizer, animtime), w_ready);
}
}
- if(fire2 || (fire1 && !actor.ammo_cells && autocvar_g_rm))
+ if((fire & 2) || ((fire & 1) && !actor.ammo_cells && autocvar_g_rm))
{
if((autocvar_g_rm && autocvar_g_rm_laser) || autocvar_g_rm_laser == 2)
{
actor.weapon = oldwep;
// now do normal refire
- weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(vaporizer, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(vaporizer, animtime), w_ready);
}
}
else
vector org2 = w_org + w_backoff * 6;
if(w_deathtype & HITTYPE_SECONDARY)
{
- pointparticles(particleeffectnum(EFFECT_BLASTER_IMPACT), org2, w_backoff * 1000, 1);
+ pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
if(!w_issilent) { sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM); }
}
else
{
- pointparticles(particleeffectnum(EFFECT_VORTEX_IMPACT), org2, '0 0 0', 1);
+ pointparticles(EFFECT_VORTEX_IMPACT, org2, '0 0 0', 1);
if(!w_issilent) { sound(self, CH_SHOTS, SND_NEXIMPACT, VOL_BASE, ATTN_NORM); }
}
}
/* crosshair */ ATTRIB(Vortex, w_crosshair_size, float, 0.65);
/* wepimg */ ATTRIB(Vortex, model2, string, "weaponnex");
/* refname */ ATTRIB(Vortex, netname, string, "vortex");
-/* wepname */ ATTRIB(Vortex, message, string, _("Vortex"));
+/* wepname */ ATTRIB(Vortex, m_name, string, _("Vortex"));
ENDCLASS(Vortex)
REGISTER_WEAPON(VORTEX, NEW(Vortex));
#endif
#endif
#ifdef IMPLEMENTATION
-#ifdef SVQC
-spawnfunc(weapon_vortex) { weapon_defaultspawnfunc(WEP_VORTEX.m_id); }
-spawnfunc(weapon_nex) { spawnfunc_weapon_vortex(this); }
+REGISTER_NET_TEMP(TE_CSQC_VORTEXBEAMPARTICLE)
+
+#if defined(SVQC)
void SendCSQCVortexBeamParticle(float charge) {
vector v;
v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
- WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte(MSG_BROADCAST, TE_CSQC_VORTEXBEAMPARTICLE);
+ WriteHeader(MSG_BROADCAST, TE_CSQC_VORTEXBEAMPARTICLE);
WriteCoord(MSG_BROADCAST, w_shotorg.x);
WriteCoord(MSG_BROADCAST, w_shotorg.y);
WriteCoord(MSG_BROADCAST, w_shotorg.z);
WriteCoord(MSG_BROADCAST, v.z);
WriteByte(MSG_BROADCAST, bound(0, 255 * charge, 255));
}
+#elif defined(CSQC)
+NET_HANDLE(TE_CSQC_VORTEXBEAMPARTICLE, bool isNew)
+{
+ vector shotorg, endpos;
+ float charge;
+ shotorg.x = ReadCoord(); shotorg.y = ReadCoord(); shotorg.z = ReadCoord();
+ endpos.x = ReadCoord(); endpos.y = ReadCoord(); endpos.z = ReadCoord();
+ charge = ReadByte() / 255.0;
+
+ pointparticles(EFFECT_VORTEX_MUZZLEFLASH, shotorg, normalize(endpos - shotorg) * 1000, 1);
+
+ //draw either the old v2.3 beam or the new beam
+ charge = sqrt(charge); // divide evenly among trail spacing and alpha
+ particles_alphamin = particles_alphamax = particles_fade = charge;
+
+ if(!MUTATOR_CALLHOOK(Particles_VortexBeam, shotorg, endpos))
+ if(autocvar_cl_particles_oldvortexbeam && (getstati(STAT_ALLOW_OLDVORTEXBEAM) || isdemo()))
+ WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM_OLD), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
+ else
+ WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
+ return true;
+}
+#endif
+
+#ifdef SVQC
+spawnfunc(weapon_vortex) { weapon_defaultspawnfunc(this, WEP_VORTEX); }
+spawnfunc(weapon_nex) { spawnfunc_weapon_vortex(this); }
void W_Vortex_Attack(Weapon thiswep, float issecondary)
{SELFPARAM();
self.BUTTON_ATCK2 = true;
}
}
- METHOD(Vortex, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+ METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(WEP_CVAR(vortex, charge) && actor.vortex_charge < WEP_CVAR(vortex, charge_limit))
actor.vortex_charge = min(1, actor.vortex_charge + WEP_CVAR(vortex, charge_rate) * frametime / W_TICSPERFRAME);
w.wr_reload(w);
} else
{
- if(fire1)
+ if(fire & 1)
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(vortex, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(vortex, refire)))
{
W_Vortex_Attack(thiswep, 0);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(vortex, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(vortex, animtime), w_ready);
}
}
- if((WEP_CVAR(vortex, charge) && !WEP_CVAR(vortex, secondary)) ? (actor.BUTTON_ZOOM | actor.BUTTON_ZOOMSCRIPT) : fire2)
+ if((WEP_CVAR(vortex, charge) && !WEP_CVAR(vortex, secondary)) ? (actor.BUTTON_ZOOM | actor.BUTTON_ZOOMSCRIPT) : (fire & 2))
{
if(WEP_CVAR(vortex, charge))
{
else if(WEP_CVAR_SEC(vortex, ammo))
{
- if(fire2) // only eat ammo when the button is pressed
+ if(fire & 2) // only eat ammo when the button is pressed
{
dt = min(dt, (1 - actor.vortex_charge) / WEP_CVAR(vortex, charge_rate));
if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
}
else if(WEP_CVAR(vortex, secondary))
{
- if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_SEC(vortex, refire)))
+ if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(vortex, refire)))
{
W_Vortex_Attack(thiswep, 1);
- weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_SEC(vortex, animtime), w_ready);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(vortex, animtime), w_ready);
}
}
}
METHOD(Vortex, wr_impacteffect, void(entity thiswep))
{
vector org2 = w_org + w_backoff * 6;
- pointparticles(particleeffectnum(EFFECT_VORTEX_IMPACT), org2, '0 0 0', 1);
+ pointparticles(EFFECT_VORTEX_IMPACT, org2, '0 0 0', 1);
if(!w_issilent)
sound(self, CH_SHOTS, SND_NEXIMPACT, VOL_BASE, ATTN_NORM);
}
#define spawn _spawn
#define particleeffectnum _particleeffectnum
+#define trailparticles __trailparticles
+#define pointparticles __pointparticles
#define setmodel _setmodel
#include "upstream/csprogsdefs.qc"
#undef spawn
#undef particleeffectnum
+#undef trailparticles
+#undef pointparticles
#undef setmodel
#pragma noref 0
-#define ReadFloat() ReadCoord()
-
#endif
#pragma noref 1
#define particleeffectnum __particleeffectnum
+#define trailparticles __trailparticles
+#define pointparticles __pointparticles
#include "upstream/dpextensions.qc"
#undef particleeffectnum
+#undef trailparticles
+#undef pointparticles
int(entity ent, string tagname) _gettagindex = #451;
#define gettagindex _gettagindex
#pragma noref 0
-#define WriteFloat(to, f) WriteCoord(to, f)
-
#endif
#ifndef NOCOMPAT
- #define COMPAT_NO_MOD_IS_XONOTIC
+ #define COMPAT_NO_MOD_IS_XONOTIC
#endif
#include "compiler.qh"
#ifndef QCC_SUPPORT_INT
- #define int float
+ #define int float
#endif
#ifndef QCC_SUPPORT_BOOL
- #define bool float
+ #define bool float
#endif
#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "../dpdefs/keycodes.qh"
+ #include "../dpdefs/csprogsdefs.qh"
+ #include "../dpdefs/keycodes.qh"
#elif defined(SVQC)
- #include "../server/sys-pre.qh"
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../server/sys-post.qh"
+ #include "../server/sys-pre.qh"
+ #include "../dpdefs/progsdefs.qh"
+ #include "../dpdefs/dpextensions.qh"
+ #include "../server/sys-post.qh"
#elif defined(MENUQC)
- #include "../dpdefs/menudefs.qh"
- #include "../dpdefs/keycodes.qh"
+ #include "../dpdefs/menudefs.qh"
+ #include "../dpdefs/keycodes.qh"
#endif
#include "warpzone/mathlib.qc"
#include "lazy.qh"
#include "linkedlist.qh"
#include "log.qh"
+#include "map.qc"
#include "math.qh"
#include "misc.qh"
#include "net.qh"
#include "progname.qh"
#include "random.qc"
#include "registry.qh"
+#include "registry_net.qh"
#include "replicate.qh"
#include "self.qh"
#include "sortlist.qc"
#include "sort.qh"
#include "spawnfunc.qh"
#include "static.qh"
+#include "stats.qh"
#include "string.qh"
#include "struct.qh"
#include "test.qc"
#define ACCUMULATE_H
#ifdef QCC_SUPPORT_ACCUMULATE
-# define ACCUMULATE_FUNCTION(func, otherfunc) \
- [[accumulate]] void func() { otherfunc(); }
-# define CALL_ACCUMULATED_FUNCTION(func) \
- func()
+ #define ACCUMULATE_FUNCTION(func, otherfunc) \
+ [[accumulate]] void func() \
+ { \
+ otherfunc(); \
+ }
+ #define CALL_ACCUMULATED_FUNCTION(func) \
+ func()
#else
-#ifdef HAVE_YO_DAWG_CPP
+ #ifdef HAVE_YO_DAWG_CPP
// TODO make ascii art pic of xzibit
// YO DAWG!
// I HERD YO LIEK MACROS
// SO I PUT A MACRO DEFINITION IN YO MACRO DEFINITION
// SO YO CAN EXPAND MACROS WHILE YO EXPAND MACROS
-# define ACCUMULATE_FUNCTION(func,otherfunc) \
- #ifdef func \
- void __merge__##otherfunc() { func(); otherfunc(); } \
- #undef func \
- #define func __merge__##otherfunc \
- #else \
- #define func otherfunc \
- #endif
-# define CALL_ACCUMULATED_FUNCTION(func) \
- func()
-#else
-# define ACCUMULATE_FUNCTION(func,otherfunc) \
- .float _ACCUMULATE_##func##__##otherfunc;
-void ACCUMULATE_call(string func)
-{
- float i;
- float n = numentityfields();
- string funcprefix = strcat("_ACCUMULATE_", func, "__");
- float funcprefixlen = strlen(funcprefix);
- for(i = 0; i < n; ++i)
- {
- string name = entityfieldname(i);
- if(substring(name, 0, funcprefixlen) == funcprefix)
- callfunction(substring(name, funcprefixlen, -1));
- }
-}
-# define CALL_ACCUMULATED_FUNCTION(func) \
- ACCUMULATE_call(#func)
-#endif
+ #define ACCUMULATE_FUNCTION(func, otherfunc) \
+ #ifdef func \
+ void __merge__##otherfunc() \
+ { \
+ func(); otherfunc(); \
+ } \
+ #undef func \
+ #define func __merge__##otherfunc \
+ #else \
+ #define func otherfunc \
+ #endif
+ #define CALL_ACCUMULATED_FUNCTION(func) \
+ func()
+ #else
+ #define ACCUMULATE_FUNCTION(func, otherfunc) \
+ .float _ACCUMULATE_##func##__##otherfunc;
+ void ACCUMULATE_call(string func)
+ {
+ float i;
+ float n = numentityfields();
+ string funcprefix = strcat("_ACCUMULATE_", func, "__");
+ float funcprefixlen = strlen(funcprefix);
+ for (i = 0; i < n; ++i)
+ {
+ string name = entityfieldname(i);
+ if (substring(name, 0, funcprefixlen) == funcprefix) callfunction(substring(name, funcprefixlen, -1));
+ }
+ }
+ #define CALL_ACCUMULATED_FUNCTION(func) \
+ ACCUMULATE_call( #func)
+ #endif
#endif
// used for simplifying ACCUMULATE_FUNCTIONs
-#define SET_FIRST_OR_LAST(input,first,count) if(!input) { input = (first + count); }
-#define SET_FIELD_COUNT(field,first,count) if(!field) { field = (first + count); ++count; }
-#define CHECK_MAX_COUNT(name,max,count,type) if(count > max) { error(strcat("Maximum ", type, " hit: ", #name, ": ", ftos(count), ".\n")); }
+#define SET_FIRST_OR_LAST(input, first, count) \
+ if (!input) { input = (first + count); }
+#define SET_FIELD_COUNT(field, first, count) \
+ if (!field) { field = (first + count); ++count; }
+#define CHECK_MAX_COUNT(name, max, count, type) \
+ if (count > max) { error(strcat("Maximum ", type, " hit: ", #name, ": ", ftos(count), ".\n")); }
#endif
#ifndef BITS_H
#define BITS_H
+#include "log.qh"
#define BIT(n) (1 << (n))
#define BITS(n) (BIT(n) - 1)
#ifndef BRANCHLESS_BITSET
- #define BITSET(var, mask, flag) (flag ? (var) | (mask) : (var) &~ (mask))
+ #define BITSET(var, mask, flag) (flag ? (var) | (mask) : (var) & ~(mask))
#else
- #define BITSET(var, mask, flag) ((var) ^ (-(flag) ^ (var)) & (mask))
+ #define BITSET(var, mask, flag) ((var) ^ (-(flag) ^ (var)) & (mask))
#endif
int lowestbit(int f)
{
- f &= ~(f << 1);
- f &= ~(f << 2);
- f &= ~(f << 4);
- f &= ~(f << 8);
- f &= ~(f << 16);
- return f;
+ f &= ~(f << 1);
+ f &= ~(f << 2);
+ f &= ~(f << 4);
+ f &= ~(f << 8);
+ f &= ~(f << 16);
+ return f;
+}
+
+int randombit(int bits)
+{
+ if (!(bits & (bits - 1))) // this ONLY holds for powers of two!
+ return bits;
+
+ int r = random();
+ int b = 0;
+ int n = 0;
+
+ for (int f = 1; f <= bits; f *= 2)
+ {
+ if (bits & f)
+ {
+ ++n;
+ r *= n;
+ if (r <= 1) b = f;
+ else r = (r - 1) / (n - 1);
+ }
+ }
+ return b;
+}
+
+int randombits(int bits, int k, bool error_return)
+{
+ int r = 0;
+ while (k > 0 && bits != r)
+ {
+ r += randombit(bits - r);
+ --k;
+ }
+ if (error_return)
+ if (k > 0) return -1;
+ // all
+ return r;
+}
+
+void randombit_test(int bits, int iter)
+{
+ while (iter > 0)
+ {
+ LOG_INFO(ftos(randombit(bits)), "\n");
+ --iter;
+ }
+}
+
+enum {
+ OP_SET,
+ OP_MIN,
+ OP_MAX,
+ OP_PLUS,
+ OP_MINUS
+};
+
+bool GiveBit(entity e, .int fld, int bit, int op, int val)
+{
+ int v0 = (e.(fld) & bit);
+ switch (op)
+ {
+ case OP_SET:
+ if (val > 0) e.(fld) |= bit;
+ else e.(fld) &= ~bit;
+ break;
+ case OP_MIN:
+ case OP_PLUS:
+ if (val > 0) e.(fld) |= bit;
+ break;
+ case OP_MAX:
+ if (val <= 0) e.(fld) &= ~bit;
+ break;
+ case OP_MINUS:
+ if (val > 0) e.(fld) &= ~bit;
+ break;
+ }
+ int v1 = (e.(fld) & bit);
+ return v0 != v1;
+}
+
+bool GiveValue(entity e, .int fld, int op, int val)
+{
+ int v0 = e.(fld);
+ switch (op)
+ {
+ case OP_SET:
+ e.(fld) = val;
+ break;
+ case OP_MIN:
+ e.(fld) = max(e.(fld), val); // min 100 cells = at least 100 cells
+ break;
+ case OP_MAX:
+ e.(fld) = min(e.(fld), val);
+ break;
+ case OP_PLUS:
+ e.(fld) += val;
+ break;
+ case OP_MINUS:
+ e.(fld) -= val;
+ break;
+ }
+ int v1 = e.(fld);
+ return v0 != v1;
}
#endif
#define BOOL_H
#ifndef QCC_SUPPORT_BOOL
- // Boolean Constants
- const int true = 1;
- const int false = 0;
+ // Boolean Constants
+ const int true = 1;
+ const int false = 0;
#endif
// Transitional aliases
-[[deprecated("use true")]] [[alias("true")]] const bool TRUE;
-[[deprecated("use false")]] [[alias("false")]] const bool FALSE;
+[[deprecated("use true")]][[alias("true")]] const bool TRUE;
+[[deprecated("use false")]][[alias("false")]] const bool FALSE;
+
+#define boolean(value) ((value) != 0)
// get true/false value of a string with multiple different inputs
float InterpretBoolean(string input)
{
- switch (strtolower(input))
- {
- case "yes":
- case "true":
- case "on":
- return true;
-
- case "no":
- case "false":
- case "off":
- return false;
+ switch (strtolower(input))
+ {
+ case "yes":
+ case "true":
+ case "on":
+ return true;
- default: return stof(input);
- }
-}
+ case "no":
+ case "false":
+ case "off":
+ return false;
-float boolean(float value) { // if value is 0 return false (0), otherwise return true (1)
- return (value == 0) ? false : true;
+ default: return boolean(stof(input));
+ }
}
#endif
#ifndef COLOR_H
#define COLOR_H
+#include "string.qh"
+
#define colormapPaletteColor(c, isPants) colormapPaletteColor_(c, isPants, time)
vector colormapPaletteColor_(int c, bool isPants, float t)
{
- switch (c) {
- case 0: return '1.000000 1.000000 1.000000';
- case 1: return '1.000000 0.333333 0.000000';
- case 2: return '0.000000 1.000000 0.501961';
- case 3: return '0.000000 1.000000 0.000000';
- case 4: return '1.000000 0.000000 0.000000';
- case 5: return '0.000000 0.666667 1.000000';
- case 6: return '0.000000 1.000000 1.000000';
- case 7: return '0.501961 1.000000 0.000000';
- case 8: return '0.501961 0.000000 1.000000';
- case 9: return '1.000000 0.000000 1.000000';
- case 10: return '1.000000 0.000000 0.501961';
- case 11: return '0.000000 0.000000 1.000000';
- case 12: return '1.000000 1.000000 0.000000';
- case 13: return '0.000000 0.333333 1.000000';
- case 14: return '1.000000 0.666667 0.000000';
- case 15:
- if (isPants)
- return
- '1 0 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 0.0000000000))
- + '0 1 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 2.0943951024))
- + '0 0 1' * (0.502 + 0.498 * sin(t / 2.7182818285 + 4.1887902048));
- else
- return
- '1 0 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 5.2359877560))
- + '0 1 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 3.1415926536))
- + '0 0 1' * (0.502 + 0.498 * sin(t / 3.1415926536 + 1.0471975512));
- default: return '0.000 0.000 0.000';
- }
+ switch (c)
+ {
+ case 0: return '1.000000 1.000000 1.000000';
+ case 1: return '1.000000 0.333333 0.000000';
+ case 2: return '0.000000 1.000000 0.501961';
+ case 3: return '0.000000 1.000000 0.000000';
+ case 4: return '1.000000 0.000000 0.000000';
+ case 5: return '0.000000 0.666667 1.000000';
+ case 6: return '0.000000 1.000000 1.000000';
+ case 7: return '0.501961 1.000000 0.000000';
+ case 8: return '0.501961 0.000000 1.000000';
+ case 9: return '1.000000 0.000000 1.000000';
+ case 10: return '1.000000 0.000000 0.501961';
+ case 11: return '0.000000 0.000000 1.000000';
+ case 12: return '1.000000 1.000000 0.000000';
+ case 13: return '0.000000 0.333333 1.000000';
+ case 14: return '1.000000 0.666667 0.000000';
+ case 15:
+ if (isPants)
+ return '1 0 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 0.0000000000))
+ + '0 1 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 2.0943951024))
+ + '0 0 1' * (0.502 + 0.498 * sin(t / 2.7182818285 + 4.1887902048));
+ else
+ return '1 0 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 5.2359877560))
+ + '0 1 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 3.1415926536))
+ + '0 0 1' * (0.502 + 0.498 * sin(t / 3.1415926536 + 1.0471975512));
+ default: return '0.000 0.000 0.000';
+ }
+}
+
+float rgb_mi_ma_to_hue(vector rgb, float mi, float ma)
+{
+ if (mi == ma)
+ {
+ return 0;
+ }
+ else if (ma == rgb.x)
+ {
+ if (rgb.y >= rgb.z) return (rgb.y - rgb.z) / (ma - mi);
+ else return (rgb.y - rgb.z) / (ma - mi) + 6;
+ }
+ else if (ma == rgb.y)
+ {
+ return (rgb.z - rgb.x) / (ma - mi) + 2;
+ }
+ else // if(ma == rgb_z)
+ {
+ return (rgb.x - rgb.y) / (ma - mi) + 4;
+ }
+}
+
+vector hue_mi_ma_to_rgb(float hue, float mi, float ma)
+{
+ vector rgb;
+
+ hue -= 6 * floor(hue / 6);
+
+ // else if(ma == rgb_x)
+ // hue = 60 * (rgb_y - rgb_z) / (ma - mi);
+ if (hue <= 1)
+ {
+ rgb.x = ma;
+ rgb.y = hue * (ma - mi) + mi;
+ rgb.z = mi;
+ }
+ // else if(ma == rgb_y)
+ // hue = 60 * (rgb_z - rgb_x) / (ma - mi) + 120;
+ else if (hue <= 2)
+ {
+ rgb.x = (2 - hue) * (ma - mi) + mi;
+ rgb.y = ma;
+ rgb.z = mi;
+ }
+ else if (hue <= 3)
+ {
+ rgb.x = mi;
+ rgb.y = ma;
+ rgb.z = (hue - 2) * (ma - mi) + mi;
+ }
+ // else // if(ma == rgb_z)
+ // hue = 60 * (rgb_x - rgb_y) / (ma - mi) + 240;
+ else if (hue <= 4)
+ {
+ rgb.x = mi;
+ rgb.y = (4 - hue) * (ma - mi) + mi;
+ rgb.z = ma;
+ }
+ else if (hue <= 5)
+ {
+ rgb.x = (hue - 4) * (ma - mi) + mi;
+ rgb.y = mi;
+ rgb.z = ma;
+ }
+ // else if(ma == rgb_x)
+ // hue = 60 * (rgb_y - rgb_z) / (ma - mi);
+ else // if(hue <= 6)
+ {
+ rgb.x = ma;
+ rgb.y = mi;
+ rgb.z = (6 - hue) * (ma - mi) + mi;
+ }
+
+ return rgb;
+}
+
+vector rgb_to_hsv(vector rgb)
+{
+ float mi, ma;
+ vector hsv;
+
+ mi = min(rgb.x, rgb.y, rgb.z);
+ ma = max(rgb.x, rgb.y, rgb.z);
+
+ hsv.x = rgb_mi_ma_to_hue(rgb, mi, ma);
+ hsv.z = ma;
+
+ if (ma == 0) hsv.y = 0;
+ else hsv.y = 1 - mi / ma;
+
+ return hsv;
+}
+
+vector hsv_to_rgb(vector hsv)
+{
+ return hue_mi_ma_to_rgb(hsv.x, hsv.z * (1 - hsv.y), hsv.z);
+}
+
+vector rgb_to_hsl(vector rgb)
+{
+ float mi, ma;
+ vector hsl;
+
+ mi = min(rgb.x, rgb.y, rgb.z);
+ ma = max(rgb.x, rgb.y, rgb.z);
+
+ hsl.x = rgb_mi_ma_to_hue(rgb, mi, ma);
+
+ hsl.z = 0.5 * (mi + ma);
+ if (mi == ma) hsl.y = 0;
+ else if (hsl.z <= 0.5) hsl.y = (ma - mi) / (2 * hsl.z);
+ else // if(hsl_z > 0.5)
+ hsl.y = (ma - mi) / (2 - 2 * hsl.z);
+
+ return hsl;
+}
+
+vector hsl_to_rgb(vector hsl)
+{
+ float mi, ma, maminusmi;
+
+ if (hsl.z <= 0.5) maminusmi = hsl.y * 2 * hsl.z;
+ else maminusmi = hsl.y * (2 - 2 * hsl.z);
+
+ // hsl_z = 0.5 * mi + 0.5 * ma
+ // maminusmi = - mi + ma
+ mi = hsl.z - 0.5 * maminusmi;
+ ma = hsl.z + 0.5 * maminusmi;
+
+ return hue_mi_ma_to_rgb(hsl.x, mi, ma);
+}
+
+string rgb_to_hexcolor(vector rgb)
+{
+ return strcat(
+ "^x",
+ DEC_TO_HEXDIGIT(floor(rgb.x * 15 + 0.5)),
+ DEC_TO_HEXDIGIT(floor(rgb.y * 15 + 0.5)),
+ DEC_TO_HEXDIGIT(floor(rgb.z * 15 + 0.5))
+ );
}
#endif
#define COMPILER_H
#ifndef QCC_SUPPORT_ACCUMULATE
- #ifdef GMQCC
- #define QCC_SUPPORT_ACCUMULATE
- #endif
+ #ifdef GMQCC
+ #define QCC_SUPPORT_ACCUMULATE
+ #endif
#endif
#ifndef QCC_SUPPORT_NIL
- #ifdef GMQCC
- #define QCC_SUPPORT_NIL
- #endif
+ #ifdef GMQCC
+ #define QCC_SUPPORT_NIL
+ #endif
#endif
#endif
// Time processing and counting functions/macros
// ===============================================
-#define count_years_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s years")), ftos_decimals(time, decs))
-#define count_years(time) count_fill(time, \
- ZCTX(_("CI_ZER^%d years")), /* zeroth */ \
- ZCTX(_("CI_FIR^%d year")), /* first */ \
- ZCTX(_("CI_SEC^%d years")), /* year */ \
- ZCTX(_("CI_THI^%d years")), /* third */ \
- ZCTX(_("CI_MUL^%d years"))) /* multi */
-
-#define count_weeks_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s weeks")), ftos_decimals(time, decs))
-#define count_weeks(time) count_fill(time, \
- ZCTX(_("CI_ZER^%d weeks")), /* zeroth */ \
- ZCTX(_("CI_FIR^%d week")), /* first */ \
- ZCTX(_("CI_SEC^%d weeks")), /* week */ \
- ZCTX(_("CI_THI^%d weeks")), /* third */ \
- ZCTX(_("CI_MUL^%d weeks"))) /* multi */
-
-#define count_days_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s days")), ftos_decimals(time, decs))
-#define count_days(time) count_fill(time, \
- ZCTX(_("CI_ZER^%d days")), /* zeroth */ \
- ZCTX(_("CI_FIR^%d day")), /* first */ \
- ZCTX(_("CI_SEC^%d days")), /* day */ \
- ZCTX(_("CI_THI^%d days")), /* third */ \
- ZCTX(_("CI_MUL^%d days"))) /* multi */
-
-#define count_hours_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s hours")), ftos_decimals(time, decs))
-#define count_hours(time) count_fill(time, \
- ZCTX(_("CI_ZER^%d hours")), /* zeroth */ \
- ZCTX(_("CI_FIR^%d hour")), /* first */ \
- ZCTX(_("CI_SEC^%d hours")), /* hour */ \
- ZCTX(_("CI_THI^%d hours")), /* third */ \
- ZCTX(_("CI_MUL^%d hours"))) /* multi */
-
-
-#define count_minutes_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s minutes")), ftos_decimals(time, decs))
-#define count_minutes(time) count_fill(time, \
- ZCTX(_("CI_ZER^%d minutes")), /* zeroth */ \
- ZCTX(_("CI_FIR^%d minute")), /* first */ \
- ZCTX(_("CI_SEC^%d minutes")), /* minute */ \
- ZCTX(_("CI_THI^%d minutes")), /* third */ \
- ZCTX(_("CI_MUL^%d minutes"))) /* multi */
-
-#define count_seconds_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s seconds")), ftos_decimals(time, decs))
-#define count_seconds(time) count_fill(time, \
- ZCTX(_("CI_ZER^%d seconds")), /* zeroth */ \
- ZCTX(_("CI_FIR^%d second")), /* first */ \
- ZCTX(_("CI_SEC^%d seconds")), /* second */ \
- ZCTX(_("CI_THI^%d seconds")), /* third */ \
- ZCTX(_("CI_MUL^%d seconds"))) /* multi */
+#define count_years_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s years")), ftos_decimals(time, decs))
+#define count_years(time) \
+ count_fill(time, \
+ ZCTX(_("CI_ZER^%d years")), /* zeroth */ \
+ ZCTX(_("CI_FIR^%d year")), /* first */ \
+ ZCTX(_("CI_SEC^%d years")), /* year */ \
+ ZCTX(_("CI_THI^%d years")), /* third */ \
+ ZCTX(_("CI_MUL^%d years"))) /* multi */
+
+#define count_weeks_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s weeks")), ftos_decimals(time, decs))
+#define count_weeks(time) \
+ count_fill(time, \
+ ZCTX(_("CI_ZER^%d weeks")), /* zeroth */ \
+ ZCTX(_("CI_FIR^%d week")), /* first */ \
+ ZCTX(_("CI_SEC^%d weeks")), /* week */ \
+ ZCTX(_("CI_THI^%d weeks")), /* third */ \
+ ZCTX(_("CI_MUL^%d weeks"))) /* multi */
+
+#define count_days_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s days")), ftos_decimals(time, decs))
+#define count_days(time) \
+ count_fill(time, \
+ ZCTX(_("CI_ZER^%d days")), /* zeroth */ \
+ ZCTX(_("CI_FIR^%d day")), /* first */ \
+ ZCTX(_("CI_SEC^%d days")), /* day */ \
+ ZCTX(_("CI_THI^%d days")), /* third */ \
+ ZCTX(_("CI_MUL^%d days"))) /* multi */
+
+#define count_hours_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s hours")), ftos_decimals(time, decs))
+#define count_hours(time) \
+ count_fill(time, \
+ ZCTX(_("CI_ZER^%d hours")), /* zeroth */ \
+ ZCTX(_("CI_FIR^%d hour")), /* first */ \
+ ZCTX(_("CI_SEC^%d hours")), /* hour */ \
+ ZCTX(_("CI_THI^%d hours")), /* third */ \
+ ZCTX(_("CI_MUL^%d hours"))) /* multi */
+
+
+#define count_minutes_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s minutes")), ftos_decimals(time, decs))
+#define count_minutes(time) \
+ count_fill(time, \
+ ZCTX(_("CI_ZER^%d minutes")), /* zeroth */ \
+ ZCTX(_("CI_FIR^%d minute")), /* first */ \
+ ZCTX(_("CI_SEC^%d minutes")), /* minute */ \
+ ZCTX(_("CI_THI^%d minutes")), /* third */ \
+ ZCTX(_("CI_MUL^%d minutes"))) /* multi */
+
+#define count_seconds_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s seconds")), ftos_decimals(time, decs))
+#define count_seconds(time) \
+ count_fill(time, \
+ ZCTX(_("CI_ZER^%d seconds")), /* zeroth */ \
+ ZCTX(_("CI_FIR^%d second")), /* first */ \
+ ZCTX(_("CI_SEC^%d seconds")), /* second */ \
+ ZCTX(_("CI_THI^%d seconds")), /* third */ \
+ ZCTX(_("CI_MUL^%d seconds"))) /* multi */
string count_ordinal(int interval)
{
// Basically, it just allows you to represent a number or count in different ways
// depending on the number... like, with count_ordinal you can provide integers
// and retrieve 1st, 2nd, 3rd, nth ordinal numbers in a clean and simple way.
- if(floor((interval % 100)/10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block
+ if (floor((interval % 100) / 10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block
{
// otherwise, check normally for 1st,2nd,3rd insertions
- switch(interval % 10)
+ switch (interval % 10)
{
case 1: return sprintf(_("%dst"), interval);
case 2: return sprintf(_("%dnd"), interval);
// 3 seconds
// etc... minutes, hours, days, etc.
- switch(floor(interval))
+ switch (floor(interval))
{
case 0: return sprintf(zeroth, interval);
case 1:
{
- if(interval == 1) // EXACTLY value of 1
+ if (interval == 1) // EXACTLY value of 1
return sprintf(first, interval);
- else
- return sprintf(multi, interval);
+ else return sprintf(multi, interval);
}
case 2: return sprintf(second, interval);
case 3: return sprintf(third, interval);
tmp_seconds = floor(seconds);
- if(tmp_seconds)
+ if (tmp_seconds)
{
tmp_minutes = floor(tmp_seconds / 60);
- if(tmp_minutes)
+ if (tmp_minutes)
{
tmp_seconds -= (tmp_minutes * 60);
tmp_hours = floor(tmp_minutes / 60);
- if(tmp_hours)
+ if (tmp_hours)
{
tmp_minutes -= (tmp_hours * 60);
tmp_days = floor(tmp_hours / 24);
- if(tmp_days)
+ if (tmp_days)
{
tmp_hours -= (tmp_days * 24);
tmp_weeks = floor(tmp_days / 7);
- if(tmp_weeks)
+ if (tmp_weeks)
{
tmp_days -= (tmp_weeks * 7);
tmp_years = floor(tmp_weeks / 52);
}
}
- switch(outputtype)
+ switch (outputtype)
{
case 1: return sprintf("%02d:%02d:%02d", tmp_hours, tmp_minutes, tmp_seconds);
case 2:
output = count_seconds(tmp_seconds);
- if(tmp_minutes)
+ if (tmp_minutes)
{
output = sprintf(
"%s%s",
((output != "") ? sprintf(", %s", output) : ""));
}
- if(tmp_hours)
+ if (tmp_hours)
{
output = sprintf(
"%s%s",
((output != "") ? sprintf(", %s", output) : ""));
}
- if(tmp_days)
+ if (tmp_days)
{
output = sprintf(
"%s%s",
((output != "") ? sprintf(", %s", output) : ""));
}
- if(tmp_weeks)
+ if (tmp_weeks)
{
output = sprintf(
"%s%s",
((output != "") ? sprintf(", %s", output) : ""));
}
- if(tmp_years)
+ if (tmp_years)
{
output = sprintf(
"%s%s",
output = count_hours(tmp_hours);
- if(tmp_weeks) { tmp_days += (tmp_weeks * 7); }
- if(tmp_years) { tmp_days += (tmp_years * 365); }
- if(tmp_days)
+ if (tmp_weeks) tmp_days += (tmp_weeks * 7);
+ if (tmp_years) tmp_days += (tmp_years * 365);
+ if (tmp_days)
{
output = sprintf(
"%s%s",
self.csqcmodel_teleported = 0;
}
-void CSQCModel_Read(bool isnew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_MODEL, bool isnew)
+{
int sf = ReadInt24_t();
// some nice flags for CSQCMODEL_IF and the hooks
// draw it
self.drawmask = MASK_NORMAL;
self.predraw = CSQCModel_Draw;
+ return true;
}
entity CSQCModel_server2csqc(float pl)
#include "common.qh"
-void CSQCModel_Read(bool isnew);
-
#define CSQCMODEL_IF(cond)
#define CSQCMODEL_ENDIF
#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
#endif
}
-void CSQCPlayer_Physics(void)
+void CSQCPlayer_Physics()
{
switch(autocvar_cl_movement)
{
const int CSQCMODEL_PROPERTY_YAW = BIT(19);
const int CSQCMODEL_PROPERTY_PITCHROLL = BIT(18);
const int CSQCMODEL_PROPERTY_FRAME2 = BIT(17);
-const int CSQCMODEL_PROPERTY_LERPFRAC = BIT(BIT(4));
+const int CSQCMODEL_PROPERTY_LERPFRAC = BIT(16);
const int CSQCMODEL_PROPERTY_SIZE = BIT(15);
#define ALLPROPERTIES_COMMON \
unused_float = islocalplayer;
unused_float = isnolocalplayer;
- WriteByte(MSG_ENTITY, ENT_CLIENT_MODEL);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_MODEL);
WriteInt24_t(MSG_ENTITY, sf);
#define CSQCMODEL_IF(cond) if(cond) {
return true;
}
-#ifdef CSQCPLAYER_FORCE_UPDATES
+#if CSQCPLAYER_FORCE_UPDATES
.float csqcmodel_nextforcedupdate;
#endif
void CSQCModel_CheckUpdate(entity e)
unused_float = islocalplayer;
unused_float = isnolocalplayer;
-#ifdef CSQCPLAYER_FORCE_UPDATES
+#if CSQCPLAYER_FORCE_UPDATES
if(isplayer && time > e.csqcmodel_nextforcedupdate)
{
e.SendFlags |= CSQCMODEL_PROPERTY_ORIGIN;
#include "progname.qh"
#include "static.qh"
-void RegisterCvars(void(string name, string def, string desc, bool archive, string file) f) { }
+void RegisterCvars(void(string name, string def, string desc, bool archive, string file) f) {}
+
+bool cvar_value_issafe(string s)
+{
+ if (strstrofs(s, "\"", 0) >= 0) return false;
+ if (strstrofs(s, "\\", 0) >= 0) return false;
+ if (strstrofs(s, ";", 0) >= 0) return false;
+ if (strstrofs(s, "$", 0) >= 0) return false;
+ if (strstrofs(s, "\r", 0) >= 0) return false;
+ if (strstrofs(s, "\n", 0) >= 0) return false;
+ return true;
+}
/** escape the string to make it safe for consoles */
string MakeConsoleSafe(string input)
return input;
}
-void cvar_describe(string name, string desc) {
- localcmd(sprintf("\nset %1$s \"$%1$s\" \"%2$s\"\n", name, MakeConsoleSafe(desc)));
+void cvar_describe(string name, string desc)
+{
+ localcmd(sprintf("\nset %1$s \"$%1$s\" \"%2$s\"\n", name, MakeConsoleSafe(desc)));
}
-void cvar_archive(string name) {
- localcmd(sprintf("\nseta %1$s \"$%1$s\"\n", name));
+void cvar_archive(string name)
+{
+ localcmd(sprintf("\nseta %1$s \"$%1$s\"\n", name));
}
void RegisterCvars_Set(string name, string def, string desc, bool archive, string file)
{
- cvar_describe(name, desc);
- if (archive) cvar_archive(name);
+ cvar_describe(name, desc);
+ if (archive) cvar_archive(name);
}
int RegisterCvars_Save_fd;
void RegisterCvars_Save(string name, string def, string desc, bool archive, string file)
{
- if (!archive) return;
- fputs(RegisterCvars_Save_fd, sprintf("seta %s \"%s\"\n", name, def));
+ if (!archive) return;
+ fputs(RegisterCvars_Save_fd, sprintf("seta %s \"%s\"\n", name, def));
}
-STATIC_INIT_LATE(Cvars) {
- RegisterCvars(RegisterCvars_Set);
- RegisterCvars_Save_fd = fopen(sprintf("default%s.cfg", PROGNAME), FILE_WRITE);
- if (RegisterCvars_Save_fd >= 0) {
- RegisterCvars(RegisterCvars_Save);
- fclose(RegisterCvars_Save_fd);
- }
+STATIC_INIT_LATE(Cvars)
+{
+ RegisterCvars(RegisterCvars_Set);
+ RegisterCvars_Save_fd = fopen(sprintf("default%s.cfg", PROGNAME), FILE_WRITE);
+ if (RegisterCvars_Save_fd >= 0)
+ {
+ RegisterCvars(RegisterCvars_Save);
+ fclose(RegisterCvars_Save_fd);
+ }
}
const noref bool default_bool = false;
const noref string default_string = "";
const noref vector default_vector = '0 0 0';
-#define repr_cvar_bool(x) ((x) ? "1" : "0")
-#define repr_cvar_int(x) (ftos(x))
-#define repr_cvar_float(x) (ftos(x))
+#define repr_cvar_bool(x) ((x) ? "1" : "0")
+#define repr_cvar_int(x) (ftos(x))
+#define repr_cvar_float(x) (ftos(x))
#define repr_cvar_string(x) (x)
#define repr_cvar_vector(x) (sprintf("%v", x))
#define __AUTOCVAR(file, archive, var, type, desc, default) \
- [[accumulate]] void RegisterCvars(void(string, string, string, bool, string) f) { f(#var, repr_cvar_##type(default), desc, archive, file); } \
- type autocvar_##var = default
+ [[accumulate]] void RegisterCvars(void(string, string, string, bool, string) f) \
+ { \
+ f( #var, repr_cvar_##type(default), desc, archive, file); \
+ } \
+ type autocvar_##var = default
#define AUTOCVAR_5(file, archive, var, type, desc) \
- __AUTOCVAR(file, archive, var, type, desc, default_##type)
+ __AUTOCVAR(file, archive, var, type, desc, default_##type)
#define AUTOCVAR_6(file, archive, var, type, default, desc) \
- __AUTOCVAR(file, archive, var, type, desc, default)
+ __AUTOCVAR(file, archive, var, type, desc, default)
#define _AUTOCVAR(...) EVAL(OVERLOAD(AUTOCVAR, __FILE__, __VA_ARGS__))
#define AUTOCVAR_SAVE(...) _AUTOCVAR(true, __VA_ARGS__)
#define AUTOCVAR(...) _AUTOCVAR(false, __VA_ARGS__)
-#ifndef MENUQC
#ifndef DEFER_H
#define DEFER_H
+#ifndef MENUQC
-#include "oo.qh"
-#include "self.qh"
+ #include "oo.qh"
+ #include "self.qh"
-entityclass(Defer);
-class(Defer) .entity owner;
-class(Defer) .void() think;
-class(Defer) .float nextthink;
+ entityclass(Defer);
+ class(Defer).entity owner;
+ class(Defer).void() think;
+ class(Defer).float nextthink;
/*
==================
Remove self
==================
*/
-void SUB_Remove()
-{SELFPARAM();
- remove (self);
-}
-
-void defer_think()
-{SELFPARAM();
- self.think = SUB_Remove;
- self.nextthink = time;
- WITH(entity, self, self.owner, self.use());
-}
+ void SUB_Remove()
+ {
+ SELFPARAM();
+ remove(self);
+ }
+
+ void defer_think()
+ {
+ SELFPARAM();
+ self.think = SUB_Remove;
+ self.nextthink = time;
+ WITH(entity, self, self.owner, self.use());
+ }
/*
Execute func() after time + fdelay.
self when func is executed = self when defer is called
*/
-void defer(float fdelay, void() func)
-{SELFPARAM();
- entity e;
-
- e = spawn();
- e.owner = self;
- e.use = func;
- e.think = defer_think;
- e.nextthink = time + fdelay;
-}
+ void defer(float fdelay, void() func)
+ {
+ SELFPARAM();
+
+ entity e = new(deferred);
+ make_pure(e);
+ e.owner = this;
+ e.use = func;
+ e.think = defer_think;
+ e.nextthink = time + fdelay;
+ }
#endif
#endif
#ifdef CSQC
#ifndef DRAW_H
-#define DRAW_H
+ #define DRAW_H
-#include "i18n.qh"
-#include "vector.qh"
+ #include "i18n.qh"
+ #include "vector.qh"
-#include "../client/defs.qh"
+ #include "../client/defs.qh"
-void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg)
-{
- // I want to draw a quad...
- // from and to are MIDPOINTS.
+ void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg)
+ {
+ // I want to draw a quad...
+ // from and to are MIDPOINTS.
- vector axis, thickdir, A, B, C, D;
- float length_tex;
+ vector axis, thickdir, A, B, C, D;
+ float length_tex;
- axis = normalize(to - from);
- length_tex = aspect * vlen(to - from) / thickness;
+ axis = normalize(to - from);
+ length_tex = aspect * vlen(to - from) / thickness;
- // direction is perpendicular to the view normal, and perpendicular to the axis
- thickdir = normalize(cross(axis, vieworg - from));
+ // direction is perpendicular to the view normal, and perpendicular to the axis
+ thickdir = normalize(cross(axis, vieworg - from));
- A = from - thickdir * (thickness / 2);
- B = from + thickdir * (thickness / 2);
- C = to + thickdir * (thickness / 2);
- D = to - thickdir * (thickness / 2);
+ A = from - thickdir * (thickness / 2);
+ B = from + thickdir * (thickness / 2);
+ C = to + thickdir * (thickness / 2);
+ D = to - thickdir * (thickness / 2);
- R_BeginPolygon(texture, drawflag);
- R_PolygonVertex(A, '0 0 0' + shift * '1 0 0', rgb, theAlpha);
- R_PolygonVertex(B, '0 1 0' + shift * '1 0 0', rgb, theAlpha);
- R_PolygonVertex(C, '0 1 0' + (shift + length_tex) * '1 0 0', rgb, theAlpha);
- R_PolygonVertex(D, '0 0 0' + (shift + length_tex) * '1 0 0', rgb, theAlpha);
- R_EndPolygon();
-}
+ R_BeginPolygon(texture, drawflag);
+ R_PolygonVertex(A, '0 0 0' + shift * '1 0 0', rgb, theAlpha);
+ R_PolygonVertex(B, '0 1 0' + shift * '1 0 0', rgb, theAlpha);
+ R_PolygonVertex(C, '0 1 0' + (shift + length_tex) * '1 0 0', rgb, theAlpha);
+ R_PolygonVertex(D, '0 0 0' + (shift + length_tex) * '1 0 0', rgb, theAlpha);
+ R_EndPolygon();
+ }
// a border picture is a texture containing nine parts:
// 1/4 width: left part
// 1/4 height: top part
// 1/2 height: middle part (stretched)
// 1/4 height: bottom part
-void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha, vector theBorderSize)
-{
- if (theBorderSize.x < 0 && theBorderSize.y < 0) // draw whole image as it is
- {
- drawpic(theOrigin, pic, theSize, theColor, theAlpha, 0);
- return;
- }
- if (theBorderSize.x == 0 && theBorderSize.y == 0) // no border
+ void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha, vector theBorderSize)
{
- // draw only the central part
- drawsubpic(theOrigin, theSize, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
- return;
- }
-
- vector dX, dY;
- vector width, height;
- vector bW, bH;
- //pic = draw_UseSkinFor(pic);
- width = eX * theSize.x;
- height = eY * theSize.y;
- if(theSize.x <= theBorderSize.x * 2)
- {
- // not wide enough... draw just left and right then
- bW = eX * (0.25 * theSize.x / (theBorderSize.x * 2));
- if(theSize.y <= theBorderSize.y * 2)
+ if (theBorderSize.x < 0 && theBorderSize.y < 0) // draw whole image as it is
{
- // not high enough... draw just corners
- bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
- drawsubpic(theOrigin, width * 0.5 + height * 0.5, pic, '0 0 0', bW + bH, theColor, theAlpha, 0);
- drawsubpic(theOrigin + width * 0.5, width * 0.5 + height * 0.5, pic, eX - bW, bW + bH, theColor, theAlpha, 0);
- drawsubpic(theOrigin + height * 0.5, width * 0.5 + height * 0.5, pic, eY - bH, bW + bH, theColor, theAlpha, 0);
- drawsubpic(theOrigin + theSize * 0.5, width * 0.5 + height * 0.5, pic, eX + eY - bW - bH, bW + bH, theColor, theAlpha, 0);
+ drawpic(theOrigin, pic, theSize, theColor, theAlpha, 0);
+ return;
}
- else
+ if (theBorderSize.x == 0 && theBorderSize.y == 0) // no border
{
- dY = theBorderSize.x * eY;
- drawsubpic(theOrigin, width * 0.5 + dY, pic, '0 0 0', '0 0.25 0' + bW, theColor, theAlpha, 0);
- drawsubpic(theOrigin + width * 0.5, width * 0.5 + dY, pic, '0 0 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
- drawsubpic(theOrigin + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0', '0 0.5 0' + bW, theColor, theAlpha, 0);
- drawsubpic(theOrigin + width * 0.5 + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0' + eX - bW, '0 0.5 0' + bW, theColor, theAlpha, 0);
- drawsubpic(theOrigin + height - dY, width * 0.5 + dY, pic, '0 0.75 0', '0 0.25 0' + bW, theColor, theAlpha, 0);
- drawsubpic(theOrigin + width * 0.5 + height - dY, width * 0.5 + dY, pic, '0 0.75 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
+ // draw only the central part
+ drawsubpic(theOrigin, theSize, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
+ return;
}
- }
- else
- {
- if(theSize.y <= theBorderSize.y * 2)
+
+ vector dX, dY;
+ vector width, height;
+ vector bW, bH;
+ // pic = draw_UseSkinFor(pic);
+ width = eX * theSize.x;
+ height = eY * theSize.y;
+ if (theSize.x <= theBorderSize.x * 2)
{
- // not high enough... draw just top and bottom then
- bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
- dX = theBorderSize.x * eX;
- drawsubpic(theOrigin, dX + height * 0.5, pic, '0 0 0', '0.25 0 0' + bH, theColor, theAlpha, 0);
- drawsubpic(theOrigin + dX, width - 2 * dX + height * 0.5, pic, '0.25 0 0', '0.5 0 0' + bH, theColor, theAlpha, 0);
- drawsubpic(theOrigin + width - dX, dX + height * 0.5, pic, '0.75 0 0', '0.25 0 0' + bH, theColor, theAlpha, 0);
- drawsubpic(theOrigin + height * 0.5, dX + height * 0.5, pic, '0 0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
- drawsubpic(theOrigin + dX + height * 0.5, width - 2 * dX + height * 0.5, pic, '0.25 0 0' + eY - bH, '0.5 0 0' + bH, theColor, theAlpha, 0);
- drawsubpic(theOrigin + width - dX + height * 0.5, dX + height * 0.5, pic, '0.75 0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
+ // not wide enough... draw just left and right then
+ bW = eX * (0.25 * theSize.x / (theBorderSize.x * 2));
+ if (theSize.y <= theBorderSize.y * 2)
+ {
+ // not high enough... draw just corners
+ bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
+ drawsubpic(theOrigin, width * 0.5 + height * 0.5, pic, '0 0 0', bW + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width * 0.5, width * 0.5 + height * 0.5, pic, eX - bW, bW + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height * 0.5, width * 0.5 + height * 0.5, pic, eY - bH, bW + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + theSize * 0.5, width * 0.5 + height * 0.5, pic, eX + eY - bW - bH, bW + bH, theColor, theAlpha, 0);
+ }
+ else
+ {
+ dY = theBorderSize.x * eY;
+ drawsubpic(theOrigin, width * 0.5 + dY, pic, '0 0 0', '0 0.25 0' + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width * 0.5, width * 0.5 + dY, pic, '0 0 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0', '0 0.5 0' + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width * 0.5 + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0' + eX - bW, '0 0.5 0' + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height - dY, width * 0.5 + dY, pic, '0 0.75 0', '0 0.25 0' + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width * 0.5 + height - dY, width * 0.5 + dY, pic, '0 0.75 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
+ }
}
else
{
- dX = theBorderSize.x * eX;
- dY = theBorderSize.x * eY;
- drawsubpic(theOrigin, dX + dY, pic, '0 0 0', '0.25 0.25 0', theColor, theAlpha, 0);
- drawsubpic(theOrigin + dX, width - 2 * dX + dY, pic, '0.25 0 0', '0.5 0.25 0', theColor, theAlpha, 0);
- drawsubpic(theOrigin + width - dX, dX + dY, pic, '0.75 0 0', '0.25 0.25 0', theColor, theAlpha, 0);
- drawsubpic(theOrigin + dY, dX + height - 2 * dY, pic, '0 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0);
- drawsubpic(theOrigin + dY + dX, width - 2 * dX + height - 2 * dY, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
- drawsubpic(theOrigin + dY + width - dX, dX + height - 2 * dY, pic, '0.75 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0);
- drawsubpic(theOrigin + height - dY, dX + dY, pic, '0 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
- drawsubpic(theOrigin + height - dY + dX, width - 2 * dX + dY, pic, '0.25 0.75 0', '0.5 0.25 0', theColor, theAlpha, 0);
- drawsubpic(theOrigin + height - dY + width - dX, dX + dY, pic, '0.75 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
+ if (theSize.y <= theBorderSize.y * 2)
+ {
+ // not high enough... draw just top and bottom then
+ bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
+ dX = theBorderSize.x * eX;
+ drawsubpic(theOrigin, dX + height * 0.5, pic, '0 0 0', '0.25 0 0' + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dX, width - 2 * dX + height * 0.5, pic, '0.25 0 0', '0.5 0 0' + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width - dX, dX + height * 0.5, pic, '0.75 0 0', '0.25 0 0' + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height * 0.5, dX + height * 0.5, pic, '0 0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dX + height * 0.5, width - 2 * dX + height * 0.5, pic, '0.25 0 0' + eY - bH, '0.5 0 0' + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width - dX + height * 0.5, dX + height * 0.5, pic, '0.75 0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
+ }
+ else
+ {
+ dX = theBorderSize.x * eX;
+ dY = theBorderSize.x * eY;
+ drawsubpic(theOrigin, dX + dY, pic, '0 0 0', '0.25 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dX, width - 2 * dX + dY, pic, '0.25 0 0', '0.5 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width - dX, dX + dY, pic, '0.75 0 0', '0.25 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dY, dX + height - 2 * dY, pic, '0 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dY + dX, width - 2 * dX + height - 2 * dY, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dY + width - dX, dX + height - 2 * dY, pic, '0.75 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height - dY, dX + dY, pic, '0 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height - dY + dX, width - 2 * dX + dY, pic, '0.25 0.75 0', '0.5 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height - dY + width - dX, dX + dY, pic, '0.75 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
+ }
}
}
-}
-void drawstringright(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
-{
- position.x -= 2 / 3 * strlen(text) * theScale.x;
- drawstring(position, text, theScale, rgb, theAlpha, flag);
-}
+ void drawstringright(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
+ {
+ position.x -= 2 / 3 * strlen(text) * theScale.x;
+ drawstring(position, text, theScale, rgb, theAlpha, flag);
+ }
-void drawstringcenter(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
-{
- position.x = 0.5 * (vid_conwidth - 0.6025 * strlen(text) * theScale.x);
- drawstring(position, text, theScale, rgb, theAlpha, flag);
-}
+ void drawstringcenter(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
+ {
+ position.x = 0.5 * (vid_conwidth - 0.6025 * strlen(text) * theScale.x);
+ drawstring(position, text, theScale, rgb, theAlpha, flag);
+ }
#endif
#endif
bool fexists(string f)
{
- int fh = fopen(f, FILE_READ);
- if (fh < 0)
- return false;
- fclose(fh);
- return true;
+ int fh = fopen(f, FILE_READ);
+ if (fh < 0) return false;
+ fclose(fh);
+ return true;
}
#endif
#define MAP(f, ...) EVAL(OVERLOAD(MAP, f, __VA_ARGS__))
#define MAP_2(f, it) f(it)
-#define MAP_3(f, it, ...) f(it)MAP_2(f, __VA_ARGS__)
-#define MAP_4(f, it, ...) f(it)MAP_3(f, __VA_ARGS__)
-#define MAP_5(f, it, ...) f(it)MAP_4(f, __VA_ARGS__)
-#define MAP_6(f, it, ...) f(it)MAP_5(f, __VA_ARGS__)
-#define MAP_7(f, it, ...) f(it)MAP_6(f, __VA_ARGS__)
-#define MAP_8(f, it, ...) f(it)MAP_7(f, __VA_ARGS__)
-#define MAP_9(f, it, ...) f(it)MAP_8(f, __VA_ARGS__)
-#define MAP_10(f, it, ...) f(it)MAP_9(f, __VA_ARGS__)
-#define MAP_11(f, it, ...) f(it)MAP_10(f, __VA_ARGS__)
-#define MAP_12(f, it, ...) f(it)MAP_11(f, __VA_ARGS__)
-#define MAP_13(f, it, ...) f(it)MAP_12(f, __VA_ARGS__)
-#define MAP_14(f, it, ...) f(it)MAP_13(f, __VA_ARGS__)
-#define MAP_15(f, it, ...) f(it)MAP_14(f, __VA_ARGS__)
-#define MAP_16(f, it, ...) f(it)MAP_15(f, __VA_ARGS__)
-#define MAP_17(f, it, ...) f(it)MAP_16(f, __VA_ARGS__)
-#define MAP_18(f, it, ...) f(it)MAP_17(f, __VA_ARGS__)
-#define MAP_19(f, it, ...) f(it)MAP_18(f, __VA_ARGS__)
-#define MAP_20(f, it, ...) f(it)MAP_19(f, __VA_ARGS__)
+#define MAP_3(f, it, ...) f(it) MAP_2(f, __VA_ARGS__)
+#define MAP_4(f, it, ...) f(it) MAP_3(f, __VA_ARGS__)
+#define MAP_5(f, it, ...) f(it) MAP_4(f, __VA_ARGS__)
+#define MAP_6(f, it, ...) f(it) MAP_5(f, __VA_ARGS__)
+#define MAP_7(f, it, ...) f(it) MAP_6(f, __VA_ARGS__)
+#define MAP_8(f, it, ...) f(it) MAP_7(f, __VA_ARGS__)
+#define MAP_9(f, it, ...) f(it) MAP_8(f, __VA_ARGS__)
+#define MAP_10(f, it, ...) f(it) MAP_9(f, __VA_ARGS__)
+#define MAP_11(f, it, ...) f(it) MAP_10(f, __VA_ARGS__)
+#define MAP_12(f, it, ...) f(it) MAP_11(f, __VA_ARGS__)
+#define MAP_13(f, it, ...) f(it) MAP_12(f, __VA_ARGS__)
+#define MAP_14(f, it, ...) f(it) MAP_13(f, __VA_ARGS__)
+#define MAP_15(f, it, ...) f(it) MAP_14(f, __VA_ARGS__)
+#define MAP_16(f, it, ...) f(it) MAP_15(f, __VA_ARGS__)
+#define MAP_17(f, it, ...) f(it) MAP_16(f, __VA_ARGS__)
+#define MAP_18(f, it, ...) f(it) MAP_17(f, __VA_ARGS__)
+#define MAP_19(f, it, ...) f(it) MAP_18(f, __VA_ARGS__)
+#define MAP_20(f, it, ...) f(it) MAP_19(f, __VA_ARGS__)
#define IDENTITY(it) it
#define APPLY(f, ...) f(__VA_ARGS__)
#ifdef SVQC
- #define SV(f, ...) f(__VA_ARGS__)
+ #define SV(f, ...) f(__VA_ARGS__)
#else
- #define SV(f, ...)
+ #define SV(f, ...)
#endif
#ifdef CSQC
- #define CL(f, ...) f(__VA_ARGS__)
+ #define CL(f, ...) f(__VA_ARGS__)
#else
- #define CL(f, ...)
+ #define CL(f, ...)
#endif
#define IF(cond, f, ...) cond(f, __VA_ARGS__)
string language_filename(string s)
{
- string fn = prvm_language;
- if (fn == "" || fn == "dump")
- return s;
- fn = strcat(s, ".", fn);
- int fh = fopen(fn, FILE_READ);
- if (fh >= 0)
- {
- fclose(fh);
- return fn;
- }
- return s;
+ string fn = prvm_language;
+ if (fn == "" || fn == "dump") return s;
+ fn = strcat(s, ".", fn);
+ int fh = fopen(fn, FILE_READ);
+ if (fh >= 0)
+ {
+ fclose(fh);
+ return fn;
+ }
+ return s;
}
string CTX(string s)
{
- int p = strstrofs(s, "^", 0);
- if (p < 0)
- return s;
- return substring(s, p + 1, -1);
+ int p = strstrofs(s, "^", 0);
+ if (p < 0) return s;
+ return substring(s, p + 1, -1);
}
#define ZCTX(s) strzone(CTX(s))
#define INT_H
#ifndef QCC_SUPPORT_INT
- #define stoi(s) stof(s)
- #define stob(s) stof(s)
- #define itos(i) ftos(i)
+ #define stoi(s) stof(s)
+ #define stob(s) stof(s)
+ #define itos(i) ftos(i)
#else
- #define stoi(s) ((int) stof(s))
- #define stob(s) ((bool) stof(s))
- #define itos(i) ftos(i)
+ #define stoi(s) ((int) stof(s))
+ #define stob(s) ((bool) stof(s))
+ #define itos(i) ftos(i)
#endif
#endif
#ifndef ITER_H
#define ITER_H
-#define FOREACH_ARRAY(arr, start, end, cond, body) do { \
- for (int i = start; i < end; ++i) { \
- const noref entity it = arr[i]; \
- if (cond) { body } \
- } \
-} while(0)
+#define FOREACH_ARRAY(arr, start, end, cond, body) \
+ do \
+ { \
+ for (int i = start; i < end; ++i) \
+ { \
+ const noref entity it = arr[i]; \
+ if (cond) { body } \
+ } \
+ } \
+ while (0)
-#define FOREACH_LIST(list, next, cond, body) do { \
- noref int i = 0; \
- for (entity it = list##_first; it; (it = it.next, ++i)) { \
- if (cond) { body } \
- } \
-} while(0)
+#define FOREACH_LIST(list, next, cond, body) \
+ do \
+ { \
+ int i = 0; \
+ for (entity it = list##_first; it; (it = it.next, ++i)) \
+ { \
+ if (cond) { body } \
+ } \
+ } \
+ while (0)
+
+#define FOREACH_WORD(words, cond, body) \
+ do \
+ { \
+ string _words = words; \
+ int i = 0; \
+ for (string _it; (_it = car(_words)); (_words = cdr(_words), ++i)) \
+ { \
+ const noref string it = _it; \
+ if (cond) { body } \
+ } \
+ } \
+ while (0)
#define FOREACH(list, cond, body) FOREACH_LIST(list, enemy, cond, body)
#include "oo.qh"
CLASS(Lazy, Object)
- ATTRIB(Lazy, m_get, entity(), func_null);
- CONSTRUCTOR(Lazy, entity() _compute) { this.m_get = _compute; }
+ ATTRIB(Lazy, m_get, entity(), func_null);
+ CONSTRUCTOR(Lazy, entity() _compute)
+ {
+ this.m_get = _compute;
+ }
ENDCLASS(Lazy)
#define LAZY(id) __lazy_##id
-#define LAZY_NEW(id, compute) entity LAZY(id)() { \
- static bool done; \
- static entity it; \
- if (!done) { it = compute; done = true; } \
- return it; \
-}
+#define LAZY_NEW(id, compute) \
+ entity LAZY(id)() { \
+ static bool done; \
+ static entity it; \
+ if (!done) { it = compute; done = true; } \
+ return it; \
+ }
#endif
#define LINKEDLIST_H
CLASS(LinkedListNode, Object)
- ATTRIB(LinkedListNode, ll_data, entity, NULL)
- ATTRIB(LinkedListNode, ll_prev, LinkedListNode, NULL)
- ATTRIB(LinkedListNode, ll_next, LinkedListNode, NULL)
+ ATTRIB(LinkedListNode, ll_data, entity, NULL)
+ ATTRIB(LinkedListNode, ll_prev, LinkedListNode, NULL)
+ ATTRIB(LinkedListNode, ll_next, LinkedListNode, NULL)
ENDCLASS(LinkedListNode)
CLASS(LinkedList, Object)
- ATTRIB(LinkedList, ll_head, LinkedListNode, NULL);
- ATTRIB(LinkedList, ll_tail, LinkedListNode, NULL);
+ ATTRIB(LinkedList, ll_head, LinkedListNode, NULL);
+ ATTRIB(LinkedList, ll_tail, LinkedListNode, NULL);
ENDCLASS(LinkedList)
#define LL_NEW() NEW(LinkedList)
/**
* Push to tail
*/
-entity LL_PUSH(LinkedList this, entity e) {
- LinkedListNode n = NEW(LinkedListNode);
- n.ll_data = e;
- n.ll_prev = this.ll_tail;
- LinkedListNode tail = this.ll_tail;
- if (tail) {
- tail.ll_next = n;
- } else {
- this.ll_head = this.ll_tail = n;
- }
- return e;
+entity LL_PUSH(LinkedList this, entity e)
+{
+ LinkedListNode n = NEW(LinkedListNode);
+ n.ll_data = e;
+ LinkedListNode tail = n.ll_prev = this.ll_tail;
+ this.ll_tail = (tail) ? tail.ll_next = n : this.ll_head = n;
+ return e;
}
/**
* Pop from tail
*/
-entity LL_POP(LinkedList this) {
- if (!this.ll_tail) return NULL;
- LinkedListNode n = this.ll_tail;
- entity e = n.ll_data;
- LinkedListNode prev = n.ll_prev;
- if (prev) {
- prev.ll_next = NULL;
- } else {
- this.ll_head = this.ll_tail = NULL;
- }
- return e;
+entity LL_POP(LinkedList this)
+{
+ if (!this.ll_tail) return NULL;
+ LinkedListNode n = this.ll_tail;
+ entity e = n.ll_data;
+ LinkedListNode prev = n.ll_prev;
+ if (prev) prev.ll_next = NULL;
+ else this.ll_head = this.ll_tail = NULL;
+ return e;
}
-#define LL_EACH(list, cond, body) do { \
- noref int i = 0; \
- for (entity _it = list.ll_head; _it; (_it = _it.ll_next, ++i)) { \
- noref entity it = _it.ll_data; \
- if (cond) { body } \
- } \
-} while(0)
+#define LL_EACH(list, cond, body) \
+ do \
+ { \
+ noref int i = 0; \
+ for (entity _it = list.ll_head; _it; (_it = _it.ll_next, ++i)) \
+ { \
+ noref entity it = _it.ll_data; \
+ if (cond) { body } \
+ } \
+ } \
+ while (0)
#endif
#ifndef LOG_H
#define LOG_H
-#define _printferr(...) error(sprintf(__VA_ARGS__))
-#define _printfbt(...) backtrace(sprintf(__VA_ARGS__))
-#define printf(...) print(sprintf(__VA_ARGS__))
-#define dprintf(...) dprint(sprintf(__VA_ARGS__))
-#define _dprintf2(...) do { if (autocvar_developer > 1) dprintf(__VA_ARGS__); } while (0)
+#define _printferr(...) error(sprintf(__VA_ARGS__))
+#define _printfbt(...) backtrace(sprintf(__VA_ARGS__))
+#define printf(...) print(sprintf(__VA_ARGS__))
+#define dprintf(...) dprint(sprintf(__VA_ARGS__))
+#define _dprintf2(...) \
+ do \
+ { \
+ if (autocvar_developer > 1) dprintf(__VA_ARGS__); \
+ } \
+ while (0)
-#define assert(expr, ...) do { if (!(expr)) LOG_WARNINGF(__VA_ARGS__); } while (0)
+#define assert(expr, ...) \
+ do \
+ { \
+ if (!(expr)) LOG_WARNINGF(__VA_ARGS__); \
+ } \
+ while (0)
-#define _LOG(f, level, s) f("[::"level"] ["__FILE__":%s:%.0f] %s", __FUNC__, __LINE__, s)
+#define _LOG(f, level, s) f("[::"level "] ["__FILE__ ":%s:%.0f] %s", __FUNC__, __LINE__, s)
-#define LOG_FATAL(...) _LOG_FATAL(strcat("", __VA_ARGS__))
-#define LOG_FATALF(...) _LOG_FATAL(sprintf(__VA_ARGS__))
-#define _LOG_FATAL(s) _LOG(_printferr, "FATAL", s)
+#define LOG_FATAL(...) _LOG_FATAL(strcat("", __VA_ARGS__))
+#define LOG_FATALF(...) _LOG_FATAL(sprintf(__VA_ARGS__))
+#define _LOG_FATAL(s) _LOG(_printferr, "FATAL", s)
-#define LOG_SEVERE(...) _LOG_SEVERE(strcat("", __VA_ARGS__))
-#define LOG_SEVEREF(...) _LOG_SEVERE(sprintf(__VA_ARGS__))
-#define _LOG_SEVERE(s) _LOG(_printfbt, "SEVERE", s)
+#define LOG_SEVERE(...) _LOG_SEVERE(strcat("", __VA_ARGS__))
+#define LOG_SEVEREF(...) _LOG_SEVERE(sprintf(__VA_ARGS__))
+#define _LOG_SEVERE(s) _LOG(_printfbt, "SEVERE", s)
-#define LOG_WARNING(...) _LOG_WARNING(strcat("", __VA_ARGS__))
-#define LOG_WARNINGF(...) _LOG_WARNING(sprintf(__VA_ARGS__))
-#define _LOG_WARNING(s) _LOG(printf, "WARNING", s)
+#define LOG_WARNING(...) _LOG_WARNING(strcat("", __VA_ARGS__))
+#define LOG_WARNINGF(...) _LOG_WARNING(sprintf(__VA_ARGS__))
+#define _LOG_WARNING(s) _LOG(printf, "WARNING", s)
-#define LOG_INFO(...) do { if (autocvar_developer) _LOG_INFO(strcat("", __VA_ARGS__)); else print (__VA_ARGS__); } while (0)
-#define LOG_INFOF(...) do { if (autocvar_developer) _LOG_INFO(sprintf(__VA_ARGS__)); else printf(__VA_ARGS__); } while (0)
-#define _LOG_INFO(s) _LOG(printf, "INFO", s)
+#define LOG_INFO(...) \
+ do \
+ { \
+ if (autocvar_developer) _LOG_INFO(strcat("", __VA_ARGS__)); \
+ else print(__VA_ARGS__); \
+ } \
+ while (0)
+#define LOG_INFOF(...) \
+ do \
+ { \
+ if (autocvar_developer) _LOG_INFO(sprintf(__VA_ARGS__)); \
+ else printf(__VA_ARGS__); \
+ } \
+ while (0)
+#define _LOG_INFO(s) _LOG(printf, "INFO", s)
-#define LOG_TRACE(...) _LOG_TRACE(strcat("", __VA_ARGS__))
-#define LOG_TRACEF(...) _LOG_TRACE(sprintf(__VA_ARGS__))
-#define _LOG_TRACE(s) _LOG(dprintf, "TRACE", s)
+#define LOG_TRACE(...) _LOG_TRACE(strcat("", __VA_ARGS__))
+#define LOG_TRACEF(...) _LOG_TRACE(sprintf(__VA_ARGS__))
+#define _LOG_TRACE(s) _LOG(dprintf, "TRACE", s)
-#define LOG_DEBUG(...) _LOG_DEBUG(strcat("", __VA_ARGS__))
-#define LOG_DEBUGF(...) _LOG_DEBUG(sprintf(__VA_ARGS__))
-#define _LOG_DEBUG(s) _LOG(_dprintf2, "DEBUG", s)
+#define LOG_DEBUG(...) _LOG_DEBUG(strcat("", __VA_ARGS__))
+#define LOG_DEBUGF(...) _LOG_DEBUG(sprintf(__VA_ARGS__))
+#define _LOG_DEBUG(s) _LOG(_dprintf2, "DEBUG", s)
// TODO: this sucks, lets find a better way to do backtraces?
#ifdef SVQC
-void builtin_remove(entity);
-#define _backtrace() builtin_remove(NULL)
+ void builtin_remove(entity);
+ #define _backtrace() builtin_remove(NULL)
#else
-void remove(entity);
-#define _backtrace() remove(NULL)
+ void remove(entity);
+ #define _backtrace() remove(NULL)
#endif
noref int autocvar_developer;
noref bool autocvar_prvm_backtraceforwarnings;
-#define backtrace(msg) do { \
- int dev = autocvar_developer; \
- bool war = autocvar_prvm_backtraceforwarnings; \
- cvar_set("developer", "1"); \
- cvar_set("prvm_backtraceforwarnings", "1"); \
- print("\n--- CUT HERE ---\n", msg, "\n"); \
- _backtrace(); \
- print("\n--- CUT UNTIL HERE ---\n"); \
- cvar_set("developer", ftos(dev)); \
- cvar_set("prvm_backtraceforwarnings", ftos(war)); \
-} while (0)
+#define backtrace(msg) \
+ do \
+ { \
+ int dev = autocvar_developer; \
+ bool war = autocvar_prvm_backtraceforwarnings; \
+ cvar_set("developer", "1"); \
+ cvar_set("prvm_backtraceforwarnings", "1"); \
+ print("\n--- CUT HERE ---\n", msg, "\n"); \
+ _backtrace(); \
+ print("\n--- CUT UNTIL HERE ---\n"); \
+ cvar_set("developer", ftos(dev)); \
+ cvar_set("prvm_backtraceforwarnings", ftos(war)); \
+ } \
+ while (0)
-#define ASSERT(expr) do { if (!(expr)) LOG_FATAL("assertion failed: " #expr "\n"); } while (0)
+#define ASSERT(expr) \
+ do \
+ { \
+ if (!(expr)) LOG_FATAL("assertion failed: " #expr "\n"); \
+ } \
+ while (0)
#endif
--- /dev/null
+#ifndef MAP_H
+#define MAP_H
+
+// Databases (hash tables)
+const float DB_BUCKETS = 8192;
+void db_save(float db, string pFilename)
+{
+ int fh = fopen(pFilename, FILE_WRITE);
+ if (fh < 0)
+ {
+ LOG_INFO(strcat("^1Can't write DB to ", pFilename));
+ return;
+ }
+ int n = buf_getsize(db);
+ fputs(fh, strcat(ftos(DB_BUCKETS), "\n"));
+ for (int i = 0; i < n; ++i)
+ fputs(fh, strcat(bufstr_get(db, i), "\n"));
+ fclose(fh);
+}
+
+int db_create()
+{
+ return buf_create();
+}
+
+void db_put(float db, string pKey, string pValue);
+
+int db_load(string pFilename)
+{
+ int db = buf_create();
+ if (db < 0) return -1;
+ int fh = fopen(pFilename, FILE_READ);
+ if (fh < 0) return db;
+ string l = fgets(fh);
+ if (stof(l) == DB_BUCKETS)
+ {
+ for (int i = 0; (l = fgets(fh)); ++i)
+ {
+ if (l != "") bufstr_set(db, i, l);
+ }
+ }
+ else
+ {
+ // different count of buckets, or a dump?
+ // need to reorganize the database then (SLOW)
+ //
+ // note: we also parse the first line (l) in case the DB file is
+ // missing the bucket count
+ do
+ {
+ int n = tokenizebyseparator(l, "\\");
+ for (int j = 2; j < n; j += 2)
+ db_put(db, argv(j - 1), uri_unescape(argv(j)));
+ }
+ while ((l = fgets(fh)));
+ }
+ fclose(fh);
+ return db;
+}
+
+void db_dump(float db, string pFilename)
+{
+ int fh = fopen(pFilename, FILE_WRITE);
+ if (fh < 0) error(strcat("Can't dump DB to ", pFilename));
+ int n = buf_getsize(db);
+ fputs(fh, "0\n");
+ for (int i = 0; i < n; ++i)
+ {
+ int m = tokenizebyseparator(bufstr_get(db, i), "\\");
+ for (int j = 2; j < m; j += 2)
+ fputs(fh, strcat("\\", argv(j - 1), "\\", argv(j), "\n"));
+ }
+ fclose(fh);
+}
+
+void db_close(float db)
+{
+ buf_del(db);
+}
+
+string db_get(float db, string pKey)
+{
+ int h = crc16(false, pKey) % DB_BUCKETS;
+ return uri_unescape(infoget(bufstr_get(db, h), pKey));
+}
+
+void db_put(float db, string pKey, string pValue)
+{
+ int h = crc16(false, pKey) % DB_BUCKETS;
+ bufstr_set(db, h, infoadd(bufstr_get(db, h), pKey, uri_escape(pValue)));
+}
+
+void db_test()
+{
+ LOG_INFO("LOAD...\n");
+ int db = db_load("foo.db");
+ LOG_INFO("LOADED. FILL...\n");
+ for (int i = 0; i < DB_BUCKETS; ++i)
+ db_put(db, ftos(random()), "X");
+ LOG_INFO("FILLED. SAVE...\n");
+ db_save(db, "foo.db");
+ LOG_INFO("SAVED. CLOSE...\n");
+ db_close(db);
+ LOG_INFO("CLOSED.\n");
+}
+
+#endif
void mean_accumulate(entity e, .float a, .float c, float mean, float value, float weight)
{
- if (weight == 0)
- return;
- if (mean == 0)
- e.(a) *= pow(value, weight);
- else
- e.(a) += pow(value, mean) * weight;
- e.(c) += weight;
+ if (weight == 0) return;
+ if (mean == 0) e.(a) *= pow(value, weight);
+ else e.(a) += pow(value, mean) * weight;
+ e.(c) += weight;
}
float mean_evaluate(entity e, .float a, .float c, float mean)
{
- if (e.(c) == 0)
- return 0;
- if (mean == 0)
- return pow(e.(a), 1.0 / e.(c));
- else
- return pow(e.(a) / e.(c), 1.0 / mean);
+ if (e.(c) == 0) return 0;
+ if (mean == 0) return pow(e.(a), 1.0 / e.(c));
+ else return pow(e.(a) / e.(c), 1.0 / mean);
}
-#define MEAN_ACCUMULATE(prefix,v,w) mean_accumulate(self,prefix##_accumulator,prefix##_count,prefix##_mean,v,w)
-#define MEAN_EVALUATE(prefix) mean_evaluate(self,prefix##_accumulator,prefix##_count,prefix##_mean)
-#define MEAN_DECLARE(prefix,m) float prefix##_mean = m; .float prefix##_count, prefix##_accumulator
+#define MEAN_ACCUMULATE(prefix, v, w) mean_accumulate(self, prefix##_accumulator, prefix##_count, prefix##_mean, v, w)
+#define MEAN_EVALUATE(prefix) mean_evaluate(self, prefix##_accumulator, prefix##_count, prefix##_mean)
+#define MEAN_DECLARE(prefix, m) float prefix##_mean = m; .float prefix##_count, prefix##_accumulator
-/*
-==================
-crandom
-
-Returns a random number between -1.0 and 1.0
-==================
-*/
-float crandom()
-{
- return 2 * (random() - 0.5);
-}
+/** Returns a random number between -1.0 and 1.0 */
+#define crandom() (2 * (random() - 0.5))
/*
float angc(float a1, float a2)
{
- while (a1 > 180) a1 -= 360;
- while (a1 < -179) a1 += 360;
- while (a2 > 180) a2 -= 360;
- while (a2 < -179) a2 += 360;
- float a = a1 - a2;
- while (a > 180) a -= 360;
- while (a < -179) a += 360;
- return a;
+ while (a1 > 180)
+ a1 -= 360;
+ while (a1 < -179)
+ a1 += 360;
+ while (a2 > 180)
+ a2 -= 360;
+ while (a2 < -179)
+ a2 += 360;
+ float a = a1 - a2;
+ while (a > 180)
+ a -= 360;
+ while (a < -179)
+ a += 360;
+ return a;
}
-float fsnap(float val,float fsize)
+float fsnap(float val, float fsize)
{
- return rint(val / fsize) * fsize;
+ return rint(val / fsize) * fsize;
}
-vector vsnap(vector point,float fsize)
+vector vsnap(vector point, float fsize)
{
- vector vret;
+ vector vret;
- vret.x = rint(point.x / fsize) * fsize;
- vret.y = rint(point.y / fsize) * fsize;
- vret.z = ceil(point.z / fsize) * fsize;
+ vret.x = rint(point.x / fsize) * fsize;
+ vret.y = rint(point.y / fsize) * fsize;
+ vret.z = ceil(point.z / fsize) * fsize;
- return vret;
+ return vret;
}
vector lerpv(float t0, vector v0, float t1, vector v1, float t)
{
- return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));
+ return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));
}
vector bezier_quadratic_getpoint(vector a, vector b, vector c, float t)
{
- return
- (c - 2 * b + a) * (t * t) +
- (b - a) * (2 * t) +
- a;
+ return (c - 2 * b + a) * (t * t)
+ + (b - a) * (2 * t)
+ + a;
}
vector bezier_quadratic_getderivative(vector a, vector b, vector c, float t)
{
- return
- (c - 2 * b + a) * (2 * t) +
- (b - a) * 2;
+ return (c - 2 * b + a) * (2 * t)
+ + (b - a) * 2;
}
float cubic_speedfunc(float startspeedfactor, float endspeedfactor, float x)
{
- return
- ((( startspeedfactor + endspeedfactor - 2
- ) * x - 2 * startspeedfactor - endspeedfactor + 3
- ) * x + startspeedfactor
- ) * x;
+ return (((startspeedfactor + endspeedfactor - 2
+ ) * x - 2 * startspeedfactor - endspeedfactor + 3
+ ) * x + startspeedfactor
+ ) * x;
}
bool cubic_speedfunc_is_sane(float startspeedfactor, float endspeedfactor)
{
- if (startspeedfactor < 0 || endspeedfactor < 0)
- return false;
-
- /*
- // if this is the case, the possible zeros of the first derivative are outside
- // 0..1
- We can calculate this condition as condition
- if(se <= 3)
- return true;
- */
-
- // better, see below:
- if (startspeedfactor <= 3 && endspeedfactor <= 3)
- return true;
-
- // if this is the case, the first derivative has no zeros at all
- float se = startspeedfactor + endspeedfactor;
- float s_e = startspeedfactor - endspeedfactor;
- if (3 * (se - 4) * (se - 4) + s_e * s_e <= 12) // an ellipse
- return true;
-
- // Now let s <= 3, s <= 3, s+e >= 3 (triangle) then we get se <= 6 (top right corner).
- // we also get s_e <= 6 - se
- // 3 * (se - 4)^2 + (6 - se)^2
- // is quadratic, has value 12 at 3 and 6, and value < 12 in between.
- // Therefore, above "better" check works!
-
- return false;
-
- // known good cases:
- // (0, [0..3])
- // (0.5, [0..3.8])
- // (1, [0..4])
- // (1.5, [0..3.9])
- // (2, [0..3.7])
- // (2.5, [0..3.4])
- // (3, [0..3])
- // (3.5, [0.2..2.3])
- // (4, 1)
-
- /*
- On another note:
- inflection point is always at (2s + e - 3) / (3s + 3e - 6).
-
- s + e - 2 == 0: no inflection
-
- s + e > 2:
- 0 < inflection < 1 if:
- 0 < 2s + e - 3 < 3s + 3e - 6
- 2s + e > 3 and 2e + s > 3
-
- s + e < 2:
- 0 < inflection < 1 if:
- 0 > 2s + e - 3 > 3s + 3e - 6
- 2s + e < 3 and 2e + s < 3
-
- Therefore: there is an inflection point iff:
- e outside (3 - s)/2 .. 3 - s*2
-
- in other words, if (s,e) in triangle (1,1)(0,3)(0,1.5) or in triangle (1,1)(3,0)(1.5,0)
- */
+ if (startspeedfactor < 0 || endspeedfactor < 0) return false;
+
+ /*
+ // if this is the case, the possible zeros of the first derivative are outside
+ // 0..1
+ We can calculate this condition as condition
+ if(se <= 3)
+ return true;
+ */
+
+ // better, see below:
+ if (startspeedfactor <= 3 && endspeedfactor <= 3) return true;
+
+ // if this is the case, the first derivative has no zeros at all
+ float se = startspeedfactor + endspeedfactor;
+ float s_e = startspeedfactor - endspeedfactor;
+ if (3 * (se - 4) * (se - 4) + s_e * s_e <= 12) // an ellipse
+ return true;
+
+ // Now let s <= 3, s <= 3, s+e >= 3 (triangle) then we get se <= 6 (top right corner).
+ // we also get s_e <= 6 - se
+ // 3 * (se - 4)^2 + (6 - se)^2
+ // is quadratic, has value 12 at 3 and 6, and value < 12 in between.
+ // Therefore, above "better" check works!
+
+ return false;
+
+ // known good cases:
+ // (0, [0..3])
+ // (0.5, [0..3.8])
+ // (1, [0..4])
+ // (1.5, [0..3.9])
+ // (2, [0..3.7])
+ // (2.5, [0..3.4])
+ // (3, [0..3])
+ // (3.5, [0.2..2.3])
+ // (4, 1)
+
+ /*
+ On another note:
+ inflection point is always at (2s + e - 3) / (3s + 3e - 6).
+
+ s + e - 2 == 0: no inflection
+
+ s + e > 2:
+ 0 < inflection < 1 if:
+ 0 < 2s + e - 3 < 3s + 3e - 6
+ 2s + e > 3 and 2e + s > 3
+
+ s + e < 2:
+ 0 < inflection < 1 if:
+ 0 > 2s + e - 3 > 3s + 3e - 6
+ 2s + e < 3 and 2e + s < 3
+
+ Therefore: there is an inflection point iff:
+ e outside (3 - s)/2 .. 3 - s*2
+
+ in other words, if (s,e) in triangle (1,1)(0,3)(0,1.5) or in triangle (1,1)(3,0)(1.5,0)
+ */
}
/** continuous function mapping all reals into -1..1 */
float float2range11(float f)
{
- return f / (fabs(f) + 1);
+ return f / (fabs(f) + 1);
}
/** continuous function mapping all reals into 0..1 */
float float2range01(float f)
{
- return 0.5 + 0.5 * float2range11(f);
+ return 0.5 + 0.5 * float2range11(f);
}
float median(float a, float b, float c)
{
- return (a < c) ? bound(a, b, c) : bound(c, b, a);
+ return (a < c) ? bound(a, b, c) : bound(c, b, a);
}
float almost_equals(float a, float b)
{
- float eps = (max(a, -a) + max(b, -b)) * 0.001;
- return a - b < eps && b - a < eps;
+ float eps = (max(a, -a) + max(b, -b)) * 0.001;
+ return a - b < eps && b - a < eps;
}
float almost_in_bounds(float a, float b, float c)
{
- float eps = (max(a, -a) + max(c, -c)) * 0.001;
- if (a > c)
- eps = -eps;
- return b == median(a - eps, b, c + eps);
+ float eps = (max(a, -a) + max(c, -c)) * 0.001;
+ if (a > c) eps = -eps;
+ return b == median(a - eps, b, c + eps);
+}
+
+float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
+{
+ if (halflifedist > 0) return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
+ else if (halflifedist < 0) return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
+ else return 1;
}
float power2of(float e)
{
- return pow(2, e);
+ return pow(2, e);
}
float log2of(float x)
{
- // NOTE: generated code
- if (x > 2048)
- if (x > 131072)
- if (x > 1048576)
- if (x > 4194304)
- return 23;
- else
- if (x > 2097152)
- return 22;
- else
- return 21;
- else
- if (x > 524288)
- return 20;
- else
- if (x > 262144)
- return 19;
- else
- return 18;
- else
- if (x > 16384)
- if (x > 65536)
- return 17;
- else
- if (x > 32768)
- return 16;
- else
- return 15;
- else
- if (x > 8192)
- return 14;
- else
- if (x > 4096)
- return 13;
- else
- return 12;
- else
- if (x > 32)
- if (x > 256)
- if (x > 1024)
- return 11;
- else
- if (x > 512)
- return 10;
- else
- return 9;
- else
- if (x > 128)
- return 8;
- else
- if (x > 64)
- return 7;
- else
- return 6;
- else
- if (x > 4)
- if (x > 16)
- return 5;
- else
- if (x > 8)
- return 4;
- else
- return 3;
- else
- if (x > 2)
- return 2;
- else
- if (x > 1)
- return 1;
- else
- return 0;
+ // NOTE: generated code
+ if (x > 2048)
+ if (x > 131072)
+ if (x > 1048576)
+ if (x > 4194304) return 23;
+ else
+ if (x > 2097152) return 22;
+ else return 21;
+ else
+ if (x > 524288) return 20;
+ else
+ if (x > 262144) return 19;
+ else return 18;
+ else
+ if (x > 16384)
+ if (x > 65536) return 17;
+ else
+ if (x > 32768) return 16;
+ else return 15;
+ else
+ if (x > 8192) return 14;
+ else
+ if (x > 4096) return 13;
+ else return 12;
+ else
+ if (x > 32)
+ if (x > 256)
+ if (x > 1024) return 11;
+ else
+ if (x > 512) return 10;
+ else return 9;
+ else
+ if (x > 128) return 8;
+ else
+ if (x > 64) return 7;
+ else return 6;
+ else
+ if (x > 4)
+ if (x > 16) return 5;
+ else
+ if (x > 8) return 4;
+ else return 3;
+ else
+ if (x > 2) return 2;
+ else
+ if (x > 1) return 1;
+ else return 0;
}
+/** ax^2 + bx + c = 0 */
+vector solve_quadratic(float a, float b, float c)
+{
+ vector v;
+ float D;
+ v = '0 0 0';
+ if (a == 0)
+ {
+ if (b != 0)
+ {
+ v.x = v.y = -c / b;
+ v.z = 1;
+ }
+ else
+ {
+ if (c == 0)
+ {
+ // actually, every number solves the equation!
+ v.z = 1;
+ }
+ }
+ }
+ else
+ {
+ D = b * b - 4 * a * c;
+ if (D >= 0)
+ {
+ D = sqrt(D);
+ if (a > 0) // put the smaller solution first
+ {
+ v.x = ((-b) - D) / (2 * a);
+ v.y = ((-b) + D) / (2 * a);
+ }
+ else
+ {
+ v.x = (-b + D) / (2 * a);
+ v.y = (-b - D) / (2 * a);
+ }
+ v.z = 1;
+ }
+ else
+ {
+ // complex solutions!
+ D = sqrt(-D);
+ v.x = -b / (2 * a);
+ if (a > 0) v.y = D / (2 * a);
+ else v.y = -D / (2 * a);
+ v.z = 0;
+ }
+ }
+ return v;
+}
#endif
#define MISC_H
#ifdef GMQCC
- #define EVAL(...) __VA_ARGS__
+ #define EVAL(...) __VA_ARGS__
- #define OVERLOAD_(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
- #define OVERLOAD(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
+ #define OVERLOAD_(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
+ #define OVERLOAD(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
#else
- #define EMPTY()
- #define DEFER(id) id EMPTY()
-
- #define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
- #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
- #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
- #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
- #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
- #define EVAL5(...) __VA_ARGS__
-
- #define OVERLOAD___(F,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,n,...) F##_##n
- #define OVERLOAD__(F, ...) OVERLOAD___(F,##__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
- #define OVERLOAD_(...) DEFER(OVERLOAD__(__VA_ARGS__))
- #define OVERLOAD(F, ...) OVERLOAD_(F,##__VA_ARGS__)(__VA_ARGS__)
+ #define EMPTY()
+ #define DEFER(id) id EMPTY()
+
+ #define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
+ #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
+ #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
+ #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
+ #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
+ #define EVAL5(...) __VA_ARGS__
+
+ #define OVERLOAD___(F, _16, _15, _14, _13, _12, _11, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, n, ...) F##_##n
+ #define OVERLOAD__(F, ...) OVERLOAD___(F,##__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+ #define OVERLOAD_(...) DEFER(OVERLOAD__(__VA_ARGS__))
+ #define OVERLOAD(F, ...) OVERLOAD_(F,##__VA_ARGS__)(__VA_ARGS__)
#endif
-#define GET(name) name##get
-#define GETTER(type, name) type GET(name)() { return name; }
+#if defined(CSQC)
+ #define etof(e) num_for_edict(e)
+ #define ftoe(i) entitybyindex(i)
+#elif defined(SVQC)
+ #define etof(e) num_for_edict(e)
+ #define ftoe(i) edict_num(i)
+#elif defined(MENUQC)
+ // already defined
+#endif
-#define LAMBDA(...) { __VA_ARGS__ ; }
+#undef etof
+// avoid bounds checks
+#define etof(e) stof(sprintf("%i", e))
-// Can't wrap with do-while as block may contain continue or break
-#define WITH(type, name, value, block) { \
- type __with_save = (name); \
- name = (value); \
- LAMBDA(block) \
- name = __with_save; \
-} do { } while (0)
+#define GET(name) name##get
+#define GETTER(type, name) type GET(name)() { return name; }
+#define PROPERTY(type, name) type name; GETTER(type, name)
+#define LAMBDA(...) { __VA_ARGS__; }
+
+// With block may not contain continue or break
+#define WITH(type, name, value, block) \
+ do \
+ { \
+ type __with_save = (name); \
+ name = (value); \
+ LAMBDA(block) \
+ name = __with_save; \
+ } \
+ while (0)
#endif
#define NET_H
#ifdef SVQC
-.int Version; // deprecated, use SendFlags
-.int SendFlags;
-.bool(entity to, int sendflags) SendEntity;
-.bool(entity this, entity to, int sendflags) SendEntity3;
+ .int Version; // deprecated, use SendFlags
+ .int SendFlags;
+ .bool(entity to, int sendflags) SendEntity;
+ .bool(entity this, entity to, int sendflags) SendEntity3;
-bool SendEntity_self(entity to, int sendflags) { return self.SendEntity3(self, to, sendflags); }
+ bool SendEntity_self(entity to, int sendflags) { return self.SendEntity3(self, to, sendflags); }
-void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
-{
- if (e.classname == "") e.classname = "net_linked";
+ void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
+ {
+ if (e.classname == "") e.classname = "net_linked";
- if (e.model == "" || self.modelindex == 0) {
- vector mi = e.mins;
- vector ma = e.maxs;
- _setmodel(e, "null");
- setsize(e, mi, ma);
- }
+ if (e.model == "" || self.modelindex == 0)
+ {
+ vector mi = e.mins;
+ vector ma = e.maxs;
+ _setmodel(e, "null");
+ setsize(e, mi, ma);
+ }
- e.SendEntity = SendEntity_self;
- e.SendEntity3 = sendfunc;
- e.SendFlags = 0xFFFFFF;
+ e.SendEntity = SendEntity_self;
+ e.SendEntity3 = sendfunc;
+ e.SendFlags = 0xFFFFFF;
- if (!docull) e.effects |= EF_NODEPTHTEST;
+ if (!docull) e.effects |= EF_NODEPTHTEST;
- if (dt) {
- e.nextthink = time + dt;
- e.think = SUB_Remove;
- }
-}
+ if (dt)
+ {
+ e.nextthink = time + dt;
+ e.think = SUB_Remove;
+ }
+ }
-.void() uncustomizeentityforclient;
-.float uncustomizeentityforclient_set;
+ .void() uncustomizeentityforclient;
+ .float uncustomizeentityforclient_set;
-void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
-{
- e.customizeentityforclient = customizer;
- e.uncustomizeentityforclient = uncustomizer;
- e.uncustomizeentityforclient_set = !!uncustomizer;
-}
+ void SetCustomizer(entity e, float() customizer, void() uncustomizer)
+ {
+ e.customizeentityforclient = customizer;
+ e.uncustomizeentityforclient = uncustomizer;
+ e.uncustomizeentityforclient_set = !!uncustomizer;
+ }
-void UncustomizeEntitiesRun()
-{
- for (entity e = NULL; (e = findfloat(e, uncustomizeentityforclient_set, 1)); ) {
- WITH(entity, self, e, e.uncustomizeentityforclient());
- }
-}
+ void UncustomizeEntitiesRun()
+ {
+ for (entity e = NULL; (e = findfloat(e, uncustomizeentityforclient_set, 1)); )
+ WITH(entity, self, e, e.uncustomizeentityforclient());
+ }
#endif
.string netname;
.int m_id;
-.void(entity this, bool isNew) m_read;
+.bool(entity this, bool isNew) m_read;
#ifdef CSQC
- #define Net_Accept() do { if (!this) this = spawn(); } while (0)
- #define Net_Reject() do { if (this) remove(this); } while (0)
+ #define Net_Accept(classname) \
+ do \
+ { \
+ if (!this) this = new(classname); \
+ } \
+ while (0)
+ #define Net_Reject() \
+ do \
+ { \
+ if (this) remove(this); \
+ } \
+ while (0)
+ #define NET_HANDLE(id, param) \
+ bool Net_Handle_##id(entity this, param)
#else
- #define WriteHeader(to, id) do { \
- if (NET_##id##_istemp) WriteByte(to, SVC_TEMPENTITY); \
- WriteByte(to, NET_##id.m_id); \
- } while (0)
+ #define WriteHeader(to, id) \
+ do \
+ { \
+ if (NET_##id##_istemp) WriteByte(to, SVC_TEMPENTITY); \
+ WriteByte(to, NET_##id.m_id); \
+ } \
+ while (0)
#endif
#ifdef CSQC
- #define REGISTER_NET_LINKED(id, param) \
- void Ent_Read##id(entity this, param) { this = self; } \
- REGISTER(RegisterLinkedEntities, NET, LinkedEntities, id, m_id, spawn()) { \
- this.netname = #id; \
- this.m_read = Ent_Read##id; \
- } \
- [[accumulate]] void Ent_Read##id(entity this, param)
+ #define REGISTER_NET_LINKED(id) \
+ [[accumulate]] NET_HANDLE(id, bool) \
+ { \
+ this = self; \
+ this.sourceLocFile = __FILE__; \
+ this.sourceLocLine = __LINE__; \
+ } \
+ REGISTER(LinkedEntities, NET, id, m_id, new(net_linked_packet)) \
+ { \
+ make_pure(this); \
+ this.netname = #id; \
+ this.m_read = Net_Handle_##id; \
+ }
#else
- #define REGISTER_NET_LINKED(id, param) \
- const bool NET_##id##_istemp = false; \
- REGISTER(RegisterLinkedEntities, NET, LinkedEntities, id, m_id, spawn()) { \
- this.netname = #id; \
- }
+ #define REGISTER_NET_LINKED(id) \
+ const bool NET_##id##_istemp = false; \
+ REGISTER(LinkedEntities, NET, id, m_id, new(net_linked_packet)) \
+ { \
+ make_pure(this); \
+ this.netname = #id; \
+ }
#endif
-REGISTRY(LinkedEntities, BIT(0))
-REGISTER_REGISTRY(RegisterLinkedEntities)
-REGISTRY_SORT(LinkedEntities, netname, 0)
-STATIC_INIT(RegisterLinkedEntities_renumber) {
- for (int i = 0; i < LinkedEntities_COUNT; ++i) {
- LinkedEntities[i].m_id = 100 + i;
- }
+REGISTRY(LinkedEntities, BITS(8) - 1)
+#define LinkedEntities_from(i) _LinkedEntities_from(i, NULL)
+REGISTER_REGISTRY(LinkedEntities)
+REGISTRY_SORT(LinkedEntities, 0)
+REGISTRY_CHECK(LinkedEntities)
+STATIC_INIT(RegisterLinkedEntities_renumber)
+{
+ for (int i = 0; i < LinkedEntities_COUNT; ++i)
+ LinkedEntities_from(i).m_id = 1 + i;
}
#ifdef CSQC
- #define REGISTER_NET_TEMP(id, param) \
- void Net_Read##id(entity this, param); \
- REGISTER(RegisterTempEntities, NET, TempEntities, id, m_id, spawn()) { \
- this.netname = #id; \
- this.m_read = Net_Read##id; \
- } \
- void Net_Read##id(entity this, param)
+ #define REGISTER_NET_TEMP(id) \
+ NET_HANDLE(id, bool); \
+ REGISTER(TempEntities, NET, id, m_id, new(net_temp_packet)) \
+ { \
+ make_pure(this); \
+ this.netname = #id; \
+ this.m_read = Net_Handle_##id; \
+ }
#else
- #define REGISTER_NET_TEMP(id, param) \
- const bool NET_##id##_istemp = true; \
- REGISTER(RegisterTempEntities, NET, TempEntities, id, m_id, spawn()) { \
- this.netname = #id; \
- }
+ #define REGISTER_NET_TEMP(id) \
+ const bool NET_##id##_istemp = true; \
+ REGISTER(TempEntities, NET, id, m_id, new(net_temp_packet)) \
+ { \
+ make_pure(this); \
+ this.netname = #id; \
+ }
#endif
-REGISTRY(TempEntities, BIT(0))
-REGISTER_REGISTRY(RegisterTempEntities)
-REGISTRY_SORT(TempEntities, netname, 0)
-STATIC_INIT(RegisterTempEntities_renumber) {
- for (int i = 0; i < TempEntities_COUNT; ++i) {
- TempEntities[i].m_id = 115 + i;
- }
+REGISTRY(TempEntities, BITS(8) - 80)
+#define TempEntities_from(i) _TempEntities_from(i, NULL)
+REGISTER_REGISTRY(TempEntities)
+REGISTRY_SORT(TempEntities, 0)
+REGISTRY_CHECK(TempEntities)
+STATIC_INIT(RegisterTempEntities_renumber)
+{
+ for (int i = 0; i < TempEntities_COUNT; ++i)
+ TempEntities_from(i).m_id = 80 + i;
}
#ifndef MENUQC
-#ifdef CSQC
-int ReadInt24_t()
-{
- int v = ReadShort() << 8; // note: this is signed
- v += ReadByte(); // note: this is unsigned
- return v;
-}
-vector ReadInt48_t()
-{
- vector v;
- v.x = ReadInt24_t();
- v.y = ReadInt24_t();
- v.z = 0;
- return v;
-}
-vector ReadInt72_t()
-{
- vector v;
- v.x = ReadInt24_t();
- v.y = ReadInt24_t();
- v.z = ReadInt24_t();
- return v;
-}
-#else
-void WriteInt24_t(float dst, float val)
-{
- float v;
- WriteShort(dst, (v = floor(val >> 8)));
- WriteByte(dst, val - (v << 8)); // 0..255
-}
-void WriteInt48_t(float dst, vector val)
-{
- WriteInt24_t(dst, val.x);
- WriteInt24_t(dst, val.y);
-}
-void WriteInt72_t(float dst, vector val)
-{
- WriteInt24_t(dst, val.x);
- WriteInt24_t(dst, val.y);
- WriteInt24_t(dst, val.z);
-}
-#endif
+ const float APPROXPASTTIME_ACCURACY_REQUIREMENT = 0.05;
+ #define APPROXPASTTIME_MAX (16384 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
+ #define APPROXPASTTIME_RANGE (64 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
+
+ #ifdef CSQC
+ entity ReadCSQCEntity()
+ {
+ int f = ReadShort();
+ if (f == 0) return world;
+ return findfloat(world, entnum, f);
+ }
+ int ReadInt24_t()
+ {
+ int v = ReadShort() << 8; // note: this is signed
+ v += ReadByte(); // note: this is unsigned
+ return v;
+ }
+ vector ReadInt48_t()
+ {
+ vector v;
+ v.x = ReadInt24_t();
+ v.y = ReadInt24_t();
+ v.z = 0;
+ return v;
+ }
+ vector ReadInt72_t()
+ {
+ vector v;
+ v.x = ReadInt24_t();
+ v.y = ReadInt24_t();
+ v.z = ReadInt24_t();
+ return v;
+ }
+
+ #define ReadFloat() ReadCoord()
+ vector ReadVector() { vector v; v.x = ReadFloat(); v_y = ReadFloat(); v.z = ReadFloat(); return v; }
+ vector ReadVector2D() { vector v; v.x = ReadFloat(); v.y = ReadFloat(); v.z = 0; return v; }
+
+ float ReadApproxPastTime()
+ {
+ float dt = ReadByte();
+
+ // map from range...PPROXPASTTIME_MAX / 256
+ dt = (APPROXPASTTIME_MAX / 256) * (dt / (256 - dt));
+
+ return servertime - dt;
+ }
+
+ #else
+ const int MSG_ENTITY = 5;
+
+ void WriteInt24_t(float dst, float val)
+ {
+ float v;
+ WriteShort(dst, (v = floor(val >> 8)));
+ WriteByte(dst, val - (v << 8)); // 0..255
+ }
+ void WriteInt48_t(float dst, vector val)
+ {
+ WriteInt24_t(dst, val.x);
+ WriteInt24_t(dst, val.y);
+ }
+ void WriteInt72_t(float dst, vector val)
+ {
+ WriteInt24_t(dst, val.x);
+ WriteInt24_t(dst, val.y);
+ WriteInt24_t(dst, val.z);
+ }
+
+ #define WriteFloat(to, f) WriteCoord(to, f)
+ #define WriteVector(to, v) do { WriteFloat(to, v.x); WriteFloat(to, v.y); WriteFloat(to, v.z); } while (0)
+ #define WriteVector2D(to, v) do { WriteFloat(to, v.x); WriteFloat(to, v.y); } while (0)
+
+ // this will use the value:
+ // 128
+ // accuracy near zero is APPROXPASTTIME_MAX/(256*255)
+ // accuracy at x is 1/derivative, i.e.
+ // APPROXPASTTIME_MAX * (1 + 256 * (dt / APPROXPASTTIME_MAX))^2 / 65536
+ void WriteApproxPastTime(float dst, float t)
+ {
+ float dt = time - t;
+
+ // warning: this is approximate; do not resend when you don't have to!
+ // be careful with sendflags here!
+ // we want: 0 -> 0.05, 1 -> 0.1, ..., 255 -> 12.75
+
+ // map to range...
+ dt = 256 * (dt / ((APPROXPASTTIME_MAX / 256) + dt));
+
+ // round...
+ dt = rint(bound(0, dt, 255));
+
+ WriteByte(dst, dt);
+ }
+
+ // allow writing to also pass through to spectators (like so spectators see the same centerprints as players for example)
+ #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
+ #define WRITESPECTATABLE_MSG_ONE(statement) \
+ do \
+ { \
+ WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement); \
+ } \
+ while (0)
+ #define WRITESPECTATABLE(msg, statement) \
+ if (msg == MSG_ONE) WRITESPECTATABLE_MSG_ONE(statement); \
+ else \
+ statement float WRITESPECTATABLE_workaround = 0
+ #endif
#endif
#endif
#define NIL_H
#ifdef QCC_SUPPORT_NIL
-#define func_null nil
-#define string_null nil
+ #define func_null nil
+ #define string_null nil
#else
// the NULL function
-var void func_null(void);
-string string_null;
+ var void func_null();
+ string string_null;
#endif
#endif
// noises "usually" start in the range -1..1
entityclass(Noise);
-class(Noise) .float noise_baccum;
-class(Noise) .float noise_paccum;
-class(Noise) .float noise_paccum2;
-class(Noise) .float noise_paccum3;
-class(Noise) .float noise_bstate;
+class(Noise).float noise_baccum;
+class(Noise).float noise_paccum;
+class(Noise).float noise_paccum2;
+class(Noise).float noise_paccum3;
+class(Noise).float noise_bstate;
float Noise_Brown(entity e, float dt)
{
- e.noise_baccum += random() * sqrt(dt); // same stddev for all dt
+ e.noise_baccum += random() * sqrt(dt); // same stddev for all dt
return e.noise_baccum;
}
float Noise_Pink(entity e, float dt)
float f;
f = dt * 60;
// http://home.earthlink.net/~ltrammell/tech/pinkalg.htm
- if(random() > pow(0.3190, f))
- e.noise_paccum = 0.34848 * (2 * random() - 1);
- if(random() > pow(0.7756, f))
- e.noise_paccum2 = 0.28768 * (2 * random() - 1);
- if(random() > pow(0.9613, f))
- e.noise_paccum3 = 0.43488 * (2 * random() - 1);
+ if (random() > pow(0.3190, f)) e.noise_paccum = 0.34848 * (2 * random() - 1);
+ if (random() > pow(0.7756, f)) e.noise_paccum2 = 0.28768 * (2 * random() - 1);
+ if (random() > pow(0.9613, f)) e.noise_paccum3 = 0.43488 * (2 * random() - 1);
return e.noise_paccum + e.noise_paccum2 + e.noise_paccum3;
}
float Noise_White(entity e, float dt)
/** +1 or -1 */
float Noise_Burst(entity e, float dt, float p)
{
- if(random() > pow(p, dt))
- e.noise_bstate = !e.noise_bstate;
+ if (random() > pow(p, dt)) e.noise_bstate = !e.noise_bstate;
return 2 * e.noise_bstate - 1;
}
#include "misc.qh"
#include "nil.qh"
+#include "static.qh"
#ifdef MENUQC
- #define NULL (null_entity)
+ #define NULL (null_entity)
#else
- #define NULL (world)
+ #define NULL (world)
#endif
+.vector origin;
+.bool pure_data;
+#define make_pure(e) \
+ do \
+ { \
+ (e).pure_data = true; \
+ } \
+ while (0)
+#define is_pure(e) ((e).pure_data)
+
.string classname;
/** Location entity was spawned from in source */
.string sourceLocFile;
.int sourceLocLine;
entity _spawn();
-entity __spawn(string _classname, string _sourceFile, int _sourceLine) {
- entity this = _spawn();
- this.classname = _classname;
- this.sourceLocFile = _sourceFile;
- this.sourceLocLine = _sourceLine;
- return this;
+entity __spawn(string _classname, string _sourceFile, int _sourceLine, bool pure)
+{
+ entity this = _spawn();
+ this.classname = _classname;
+ this.sourceLocFile = _sourceFile;
+ this.sourceLocLine = _sourceLine;
+ if (pure) make_pure(this);
+ return this;
}
-
#define entityclass(...) EVAL(OVERLOAD(entityclass, __VA_ARGS__))
#define entityclass_1(name) entityclass_2(name, Object)
#ifndef QCC_SUPPORT_ENTITYCLASS
- #define entityclass_2(name, base) typedef entity name
- #define class(name)
- #define new(class) __spawn(#class, __FILE__, __LINE__)
+ #define entityclass_2(name, base) typedef entity name
+ #define class(name)
+ #define new(class) __spawn( #class, __FILE__, __LINE__, false)
#else
- #define entityclass_2(name, base) entityclass name : base {}
- #define class(name) [[class(name)]]
- #define new(class) ((class) __spawn(#class, __FILE__, __LINE__))
+ #define entityclass_2(name, base) entityclass name : base {}
+ #define class(name) [[class(name)]]
+ #define new(class) ((class) __spawn( #class, __FILE__, __LINE__, false))
+#endif
+#define spawn() __spawn("entity", __FILE__, __LINE__, false)
+
+entity _clearentity_ent;
+STATIC_INIT(clearentity)
+{
+ _clearentity_ent = new(clearentity);
+}
+void clearentity(entity e)
+{
+#ifdef CSQC
+ int n = e.entnum;
+#endif
+ copyentity(_clearentity_ent, e);
+#ifdef CSQC
+ e.entnum = n;
#endif
-#define spawn() new(entity)
+}
// Classes have a `spawn##cname(entity)` constructor
// The parameter is used across [[accumulate]] functions
// Macros to hide this implementation detail:
#ifdef GMQCC
-#define NEW(cname, ...) \
- OVERLOAD(spawn##cname, new(cname), ##__VA_ARGS__)
+ #define NEW(cname, ...) \
+ OVERLOAD(spawn##cname, new(cname),##__VA_ARGS__)
-#define CONSTRUCT(cname, ...) \
- OVERLOAD(spawn##cname, this, ##__VA_ARGS__)
+ #define CONSTRUCT(cname, ...) \
+ OVERLOAD(spawn##cname, this,##__VA_ARGS__)
#else
-#define NEW_(cname, ...) \
- OVERLOAD_(spawn##cname, __VA_ARGS__)
-#define NEW(cname, ...) \
- NEW_(cname, new(cname), ##__VA_ARGS__)(new(cname), ##__VA_ARGS__)
-
-#define CONSTRUCT_(cname, ...) \
- OVERLOAD_(spawn##cname, __VA_ARGS__)
-#define CONSTRUCT(cname, ...) \
- CONSTRUCT_(cname, this, ##__VA_ARGS__)(this, ##__VA_ARGS__)
+ #define NEW_(cname, ...) \
+ OVERLOAD_(spawn##cname, __VA_ARGS__)
+ #define NEW(cname, ...) \
+ NEW_(cname, new(cname),##__VA_ARGS__)(new(cname),##__VA_ARGS__)
+
+ #define CONSTRUCT_(cname, ...) \
+ OVERLOAD_(spawn##cname, __VA_ARGS__)
+ #define CONSTRUCT(cname, ...) \
+ CONSTRUCT_(cname, this,##__VA_ARGS__)(this,##__VA_ARGS__)
#endif
#define CONSTRUCTOR(cname, ...) \
- cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) { return = this; } \
- [[accumulate]] cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__)
+ cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) \
+ { \
+ return = this; \
+ } \
+ [[accumulate]] cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__)
.string vtblname;
.entity vtblbase;
-void RegisterClasses() { }
-STATIC_INIT(RegisterClasses) { RegisterClasses(); }
+void RegisterClasses() {}
+STATIC_INIT(RegisterClasses)
+{
+ RegisterClasses();
+}
#define VTBL(cname, base) \
- INIT_STATIC(cname); \
- entity cname##_vtbl; \
- void cname##_vtbl_init() { \
- cname e = new(vtbl); \
- spawn##cname##_static(e); \
- e.vtblname = #cname; \
- /* Top level objects refer to themselves */ \
- e.vtblbase = base##_vtbl ? base##_vtbl : e; \
- cname##_vtbl = e; \
- } \
- ACCUMULATE_FUNCTION(RegisterClasses, cname##_vtbl_init)
+ INIT_STATIC(cname); \
+ entity cname##_vtbl; \
+ void cname##_vtbl_init() \
+ { \
+ cname e = new(vtbl); \
+ make_pure(e); \
+ spawn##cname##_static(e); \
+ e.vtblname = #cname; \
+ /* Top level objects refer to themselves */ \
+ e.vtblbase = base##_vtbl ? base##_vtbl : e; \
+ cname##_vtbl = e; \
+ } \
+ ACCUMULATE_FUNCTION(RegisterClasses, cname##_vtbl_init)
#define INIT_STATIC(cname) [[accumulate]] void spawn##cname##_static(cname this)
#define INIT(cname) [[accumulate]] cname spawn##cname##_1(cname this)
#define CLASS(cname, base) \
- entityclass(cname, base); \
- class(cname) .bool instanceOf##cname; \
- VTBL(cname, base) \
- INIT_STATIC(cname) { \
- if (cname##_vtbl) { \
- copyentity(cname##_vtbl, this); \
- return; \
- } \
- spawn##base##_static(this); \
- this.instanceOf##cname = true; \
- } \
- INIT(cname) { \
- /* Only statically initialize the current class, it contains everything it inherits */ \
- if (cname##_vtbl.vtblname == this.classname) { \
- spawn##cname##_static(this); \
- this.classname = #cname; \
- this.vtblname = string_null; \
- this.vtblbase = cname##_vtbl; \
- } \
- spawn##base##_1(this); \
- }
+ entityclass(cname, base); \
+ class(cname).bool instanceOf##cname; \
+ VTBL(cname, base) \
+ INIT_STATIC(cname) \
+ { \
+ if (cname##_vtbl) \
+ { \
+ copyentity(cname##_vtbl, this); \
+ return; \
+ } \
+ spawn##base##_static(this); \
+ this.instanceOf##cname = true; \
+ } \
+ INIT(cname) \
+ { \
+ /* Only statically initialize the current class, it contains everything it inherits */ \
+ if (cname##_vtbl.vtblname == this.classname) \
+ { \
+ spawn##cname##_static(this); \
+ this.classname = #cname; \
+ this.vtblname = string_null; \
+ this.vtblbase = cname##_vtbl; \
+ } \
+ spawn##base##_1(this); \
+ }
#define METHOD(cname, name, prototype) \
- class(cname) .prototype name; \
- prototype cname##_##name; \
- INIT_STATIC(cname) { this.name = cname##_##name; } \
- prototype cname##_##name
+ class(cname).prototype name; \
+ prototype cname##_##name; \
+ INIT_STATIC(cname) \
+ { \
+ this.name = cname##_##name; \
+ } \
+ prototype cname##_##name
#define ATTRIB(cname, name, type, val) \
- class(cname) .type name; \
- INIT(cname) { this.name = val; }
+ class(cname).type name; \
+ INIT(cname) \
+ { \
+ this.name = val; \
+ }
#define ATTRIBARRAY(cname, name, type, cnt) \
- class(cname) .type name[cnt];
+ class(cname).type name[cnt];
#define ENDCLASS(cname) \
- [[last]] INIT(cname) { return this; }
+ INIT(cname) \
+ { \
+ return this; \
+ }
#define SUPER(cname) (cname##_vtbl.vtblbase)
-#define super (this.vtblbase.vtblbase)
#define spawn_static(this)
#define spawn_1(this)
#define _vtbl NULL
CLASS(Object, );
- METHOD(Object, describe, string(entity this)) {
- string s = _("No description");
- if (cvar("developer")) {
- for (int i = 0, n = numentityfields(); i < n; ++i) {
- string value = getentityfieldstring(i, this);
- if (value != "") s = sprintf("%s\n%s = %s", s, entityfieldname(i), value);
- }
- }
- return s;
- }
- METHOD(Object, display, void(entity this, void(string name, string icon) returns)) {
- returns(sprintf("entity %i", this), "nopreview_map");
- }
+ METHOD(Object, describe, string(entity this))
+ {
+ string s = _("No description");
+ if (cvar("developer"))
+ {
+ for (int i = 0, n = numentityfields(); i < n; ++i)
+ {
+ string value = getentityfieldstring(i, this);
+ if (value != "") s = sprintf("%s\n%s = %s", s, entityfieldname(i), value);
+ }
+ }
+ return s;
+ }
+ METHOD(Object, display, void(entity this, void(string name, string icon) returns))
+ {
+ returns(sprintf("entity %i", this), "nopreview_map");
+ }
ENDCLASS(Object)
#undef spawn_static
#undef spawn_1
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-vector vec_bias(vector v, float f){
+vector vec_bias(vector v, float f)
+{
vector c;
c_x = v_x + f;
c_y = v_y + f;
c_z = v_z + f;
return c;
}
-vector vec_to_min (vector a, vector b) {
+vector vec_to_min(vector a, vector b)
+{
vector c;
- c_x = min (a_x, b_x);
- c_y = min (a_y, b_y);
- c_z = min (a_z, b_z);
+ c_x = min(a_x, b_x);
+ c_y = min(a_y, b_y);
+ c_z = min(a_z, b_z);
return c;
}
-vector vec_to_max (vector a, vector b) {
+vector vec_to_max(vector a, vector b)
+{
vector c;
- c_x = max (a_x, b_x);
- c_y = max (a_y, b_y);
- c_z = max (a_z, b_z);
+ c_x = max(a_x, b_x);
+ c_y = max(a_y, b_y);
+ c_z = max(a_z, b_z);
return c;
}
// there may already be a function for bounding a vector in this manner, however my very quick search did not reveal one -- Player_2
-vector vec_bounds_in (vector point, vector a, vector b) {
+vector vec_bounds_in(vector point, vector a, vector b)
+{
vector c, d, e;
- d = vec_to_min(a,b);
- e = vec_to_max(a,b);
+ d = vec_to_min(a, b);
+ e = vec_to_max(a, b);
c = vec_to_max(point, d);
c = vec_to_min(c, e);
return c;
-
}
-vector vec_bounds_out (vector point, vector a, vector b) {
+vector vec_bounds_out(vector point, vector a, vector b)
+{
vector c, d, e;
- d = vec_to_max(a,b);
- e = vec_to_min(a,b);
+ d = vec_to_max(a, b);
+ e = vec_to_min(a, b);
c = vec_to_max(point, d);
c = vec_to_min(c, e);
return c;
-
}
-float angle_snap_f (float f, float increment){
-
+float angle_snap_f(float f, float increment)
+{
float i;
- for (i = 0; i <= 360; ){
- if (f <= i - increment)
- return i - increment;
+ for (i = 0; i <= 360; )
+ {
+ if (f <= i - increment) return i - increment;
i = i + increment;
}
return 0;
}
-vector angle_snap_vec (vector v, float increment) {
+vector angle_snap_vec(vector v, float increment)
+{
vector c;
- c_x = angle_snap_f (v_x, increment);
- c_y = angle_snap_f (v_y, increment);
- c_z = angle_snap_f (v_z, increment);
+ c_x = angle_snap_f(v_x, increment);
+ c_y = angle_snap_f(v_y, increment);
+ c_z = angle_snap_f(v_z, increment);
return c;
}
-vector aim_vec (vector origin, vector target) {
+vector aim_vec(vector origin, vector target)
+{
vector v;
- //we float around x and y, but rotate around z
+ // we float around x and y, but rotate around z
v_x = target_x - origin_x;
v_y = target_y - origin_y;
v_z = origin_z - target_z;
- //get the angles actual
+ // get the angles actual
return vectoangles(normalize(v));
}
vector vec_bias(vector v, float f);
-vector vec_to_min (vector a, vector b);
-vector vec_to_max (vector a, vector b);
+vector vec_to_min(vector a, vector b);
+vector vec_to_max(vector a, vector b);
// there may already be a function for bounding a vector in this manner, however my very quick search did not reveal one -- Player_2
-vector vec_bounds_in (vector point, vector a, vector b);
-vector vec_bounds_out (vector point, vector a, vector b);
+vector vec_bounds_in(vector point, vector a, vector b);
+vector vec_bounds_out(vector point, vector a, vector b);
-float angle_snap_f (float f, float increment);
-vector angle_snap_vec (vector v, float increment);
+float angle_snap_f(float f, float increment);
+vector angle_snap_vec(vector v, float increment);
-vector aim_vec (vector origin, vector target);
+vector aim_vec(vector origin, vector target);
#ifdef CSQC
#ifndef PLAYER_H
-#define PLAYER_H
+ #define PLAYER_H
-#include "string.qh"
+ #include "string.qh"
-#include "../client/main.qh"
-#include "../common/teams.qh"
+ #include "../client/main.qh"
+ #include "../common/teams.qh"
-int GetPlayerColorForce(int i)
-{
- if(!teamplay)
- return 0;
- else
- return stof(getplayerkeyvalue(i, "colors")) & 15;
-}
+ int GetPlayerColorForce(int i)
+ {
+ if (!teamplay) return 0;
+ else return stof(getplayerkeyvalue(i, "colors")) & 15;
+ }
-int GetPlayerColor(int i)
-{
- if(!playerslots[i].gotscores) // unconnected
- return NUM_SPECTATOR;
- else if(stof(getplayerkeyvalue(i, "frags")) == FRAGS_SPECTATOR)
- return NUM_SPECTATOR;
- else
- return GetPlayerColorForce(i);
-}
+ int GetPlayerColor(int i)
+ {
+ if (!playerslots[i].gotscores) // unconnected
+ return NUM_SPECTATOR;
+ else if (stof(getplayerkeyvalue(i, "frags")) == FRAGS_SPECTATOR) return NUM_SPECTATOR;
+ else return GetPlayerColorForce(i);
+ }
-string GetPlayerName(int i)
-{
- return ColorTranslateRGB(getplayerkeyvalue(i, "name"));
-}
+ string GetPlayerName(int i)
+ {
+ return ColorTranslateRGB(getplayerkeyvalue(i, "name"));
+ }
#endif
#endif
#define PROGNAME_H
#if defined(MENUQC)
- #define PROGNAME "MENUQC"
+ #define PROGNAME "MENUQC"
#elif defined(SVQC)
- #define PROGNAME "SVQC"
+ #define PROGNAME "SVQC"
#elif defined(CSQC)
- #define PROGNAME "CSQC"
+ #define PROGNAME "CSQC"
#else
- #error "Unable to detect PROGNAME"
+ #error "Unable to detect PROGNAME"
#endif
#endif
void RandomSelection_Init()
{
- RandomSelection_totalweight = 0;
- RandomSelection_chosen_ent = NULL;
- RandomSelection_chosen_float = 0;
- RandomSelection_chosen_string = string_null;
- RandomSelection_best_priority = -1;
+ RandomSelection_totalweight = 0;
+ RandomSelection_chosen_ent = NULL;
+ RandomSelection_chosen_float = 0;
+ RandomSelection_chosen_string = string_null;
+ RandomSelection_best_priority = -1;
}
void RandomSelection_Add(entity e, float f, string s, float weight, float priority)
{
- if (priority > RandomSelection_best_priority)
- {
- RandomSelection_best_priority = priority;
- RandomSelection_chosen_ent = e;
- RandomSelection_chosen_float = f;
- RandomSelection_chosen_string = s;
- RandomSelection_totalweight = weight;
- }
- else if (priority == RandomSelection_best_priority)
- {
- RandomSelection_totalweight += weight;
- if (random() * RandomSelection_totalweight <= weight)
- {
- RandomSelection_chosen_ent = e;
- RandomSelection_chosen_float = f;
- RandomSelection_chosen_string = s;
- }
- }
+ if (priority > RandomSelection_best_priority)
+ {
+ RandomSelection_best_priority = priority;
+ RandomSelection_chosen_ent = e;
+ RandomSelection_chosen_float = f;
+ RandomSelection_chosen_string = s;
+ RandomSelection_totalweight = weight;
+ }
+ else if (priority == RandomSelection_best_priority)
+ {
+ RandomSelection_totalweight += weight;
+ if (random() * RandomSelection_totalweight <= weight)
+ {
+ RandomSelection_chosen_ent = e;
+ RandomSelection_chosen_float = f;
+ RandomSelection_chosen_string = s;
+ }
+ }
}
+float DistributeEvenly_amount;
+float DistributeEvenly_totalweight;
-// prandom - PREDICTABLE random number generator (not seeded yet)
-
-#ifdef USE_PRANDOM
-float prandom_seed;
-float prandom()
+void DistributeEvenly_Init(float amount, float totalweight)
{
- float c;
- c = crc16(false, strcat(ftos(prandom_seed), ftos(prandom_seed + M_PI)));
- prandom_seed = c;
-
-#ifdef USE_PRANDOM_DEBUG
- LOG_TRACE("RANDOM -> ", ftos(c), "\n");
-#endif
-
- return c / 65536; // in [0..1[
+ if (DistributeEvenly_amount)
+ {
+ LOG_TRACE("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
+ LOG_TRACE(ftos(DistributeEvenly_totalweight), " left!)\n");
+ }
+ if (totalweight == 0) DistributeEvenly_amount = 0;
+ else DistributeEvenly_amount = amount;
+ DistributeEvenly_totalweight = totalweight;
}
-vector prandomvec()
+float DistributeEvenly_Get(float weight)
{
- vector v;
-
- do
- {
- v.x = prandom();
- v.y = prandom();
- v.z = prandom();
- }
- while(v * v > 1);
-
- return v;
+ float f;
+ if (weight <= 0) return 0;
+ f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
+ DistributeEvenly_totalweight -= weight;
+ DistributeEvenly_amount -= f;
+ return f;
}
-void psrandom(float seed)
+float DistributeEvenly_GetRandomized(float weight)
{
- prandom_seed = seed;
-#ifdef USE_PRANDOM_DEBUG
- LOG_TRACE("SRANDOM ", ftos(seed), "\n");
-#endif
+ float f;
+ if (weight <= 0) return 0;
+ f = floor(random() + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
+ DistributeEvenly_totalweight -= weight;
+ DistributeEvenly_amount -= f;
+ return f;
}
-#ifdef USE_PRANDOM_DEBUG
-void prandom_debug()
+// from the GNU Scientific Library
+float gsl_ran_gaussian_lastvalue;
+float gsl_ran_gaussian_lastvalue_set;
+float gsl_ran_gaussian(float sigma)
{
- LOG_TRACE("Current random seed = ", ftos(prandom_seed), "\n");
+ if (gsl_ran_gaussian_lastvalue_set)
+ {
+ gsl_ran_gaussian_lastvalue_set = 0;
+ return sigma * gsl_ran_gaussian_lastvalue;
+ }
+ else
+ {
+ float a = random() * 2 * M_PI;
+ float b = sqrt(-2 * log(random()));
+ gsl_ran_gaussian_lastvalue = cos(a) * b;
+ gsl_ran_gaussian_lastvalue_set = 1;
+ return sigma * sin(a) * b;
+ }
}
-#endif
+
+// prandom - PREDICTABLE random number generator (not seeded yet)
+
+#ifdef USE_PRANDOM
+ float prandom_seed;
+ float prandom()
+ {
+ float c;
+ c = crc16(false, strcat(ftos(prandom_seed), ftos(prandom_seed + M_PI)));
+ prandom_seed = c;
+
+ #ifdef USE_PRANDOM_DEBUG
+ LOG_TRACE("RANDOM -> ", ftos(c), "\n");
+ #endif
+
+ return c / 65536; // in [0..1[
+ }
+
+ vector prandomvec()
+ {
+ vector v;
+
+ do
+ {
+ v.x = prandom();
+ v.y = prandom();
+ v.z = prandom();
+ }
+ while (v * v > 1);
+
+ return v;
+ }
+
+ void psrandom(float seed)
+ {
+ prandom_seed = seed;
+ #ifdef USE_PRANDOM_DEBUG
+ LOG_TRACE("SRANDOM ", ftos(seed), "\n");
+ #endif
+ }
+
+ #ifdef USE_PRANDOM_DEBUG
+ void prandom_debug()
+ {
+ LOG_TRACE("Current random seed = ", ftos(prandom_seed), "\n");
+ }
+ #endif
#endif
#define USE_PRANDOM
#ifdef USE_PRANDOM
-float prandom();
-vector prandomvec();
+ float prandom();
+ vector prandomvec();
-void psrandom(float seed);
-#ifdef USE_PRANDOM_DEBUG
-void prandom_debug();
+ void psrandom(float seed);
+ #ifdef USE_PRANDOM_DEBUG
+ void prandom_debug();
+ #else
+ #define prandom_debug()
+ #endif
#else
-#define prandom_debug()
-#endif
-#else
-#define prandom random
-#define prandomvec randomvec
-#define psrandom(x)
-#define prandom_debug()
+ #define prandom random
+ #define prandomvec randomvec
+ #define psrandom(x)
+ #define prandom_debug()
#endif
#endif
#include "oo.qh"
-#define REGISTER_INIT(ns, id) [[accumulate]] void Register_##ns##_##id##_init(entity this)
-#define REGISTER_INIT_POST(ns, id) [[accumulate]] void Register_##ns##_##id##_init_post(entity this)
-
+/**
+ * Declare a new registry.
+ *
+ * Don't forget to call `REGISTER_REGISTRY`:
+ * REGISTER_REGISTRY(Foos)
+ */
#define REGISTRY(id, max) \
- void Register##id() {} \
- const int id##_MAX = max; \
- noref entity id[id##_MAX], id##_first, id##_last; \
- int id##_COUNT;
+ void Register##id() {} \
+ const int id##_MAX = max; \
+ noref entity _##id[id##_MAX], id##_first, id##_last; \
+ int id##_COUNT; \
+ entity _##id##_from(int i, entity null) { if (i >= 0 && i < id##_COUNT) { entity e = _##id[i]; if (e) return e; } return null; }
+
+REGISTRY(Registries, BITS(8))
+
+/** registered item identifier */
+.string registered_id;
/**
- * Register a new entity with a global constructor.
+ * Register a new entity with a registry.
* Must be followed by a semicolon or a function body with a `this` parameter.
* Wrapper macros may perform actions after user initialization like so:
* #define REGISTER_FOO(id) \
- * REGISTER(RegisterFoos, FOO, FOOS, id, m_id, NEW(Foo)); \
+ * REGISTER(Foos, FOO, id, m_id, NEW(Foo)); \
* REGISTER_INIT_POST(FOO, id) { \
* print("Registering foo #", this.m_id + 1, "\n"); \
* } \
* REGISTER_INIT(FOO, id)
*
- * Don't forget to forward declare `initfunc` and call `REGISTER_REGISTRY`:
- * void RegisterFoos();
- * REGISTER_REGISTRY(RegisterFoos)
*
- * @param initfunc The global constructor to accumulate into
+ * @param registry The registry to add each entity to.
* @param ns Short for namespace, prefix for each global (ns##_##id)
- * @param array The array to add each entity to. Also requires `array##_first` and `array##_last` to be defined
* @param id The identifier of the current entity being registered
- * @param fld The field to store the current count into
+ * @param fld The field to store the locally unique unique entity id
* @param inst An expression to create a new instance, invoked for every registration
*/
-#define REGISTER(initfunc, ns, array, id, fld, inst) \
- entity ns##_##id; \
- REGISTER_INIT(ns, id) { } \
- REGISTER_INIT_POST(ns, id) { } \
- void Register_##ns##_##id() { \
- if (array##_COUNT >= array##_MAX) LOG_FATALF("Registry capacity exceeded (%s)", ftos(array##_MAX)); \
- entity this = inst; \
- ns##_##id = this; \
- this.fld = array##_COUNT; \
- array[array##_COUNT++] = this; \
- if (!array##_first) array##_first = this; \
- if ( array##_last) array##_last.REGISTRY_NEXT = this; \
- array##_last = this; \
- Register_##ns##_##id##_init(this); \
- Register_##ns##_##id##_init_post(this); \
- } \
- ACCUMULATE_FUNCTION(initfunc, Register_##ns##_##id) \
- REGISTER_INIT(ns, id)
+#define REGISTER(registry, ns, id, fld, inst) \
+ entity ns##_##id; \
+ REGISTER_INIT(ns, id) {} \
+ REGISTER_INIT_POST(ns, id) {} \
+ void Register_##ns##_##id() \
+ { \
+ if (registry##_COUNT >= registry##_MAX) LOG_FATALF("Registry capacity exceeded (%s)", ftos(registry##_MAX)); \
+ entity this = ns##_##id = inst; \
+ this.registered_id = #id; \
+ this.fld = registry##_COUNT; \
+ _##registry[registry##_COUNT] = this; \
+ ++registry##_COUNT; \
+ if (!registry##_first) registry##_first = this; \
+ if (registry##_last) registry##_last.REGISTRY_NEXT = this; \
+ registry##_last = this; \
+ Register_##ns##_##id##_init(this); \
+ Register_##ns##_##id##_init_post(this); \
+ } \
+ ACCUMULATE_FUNCTION(Register##registry, Register_##ns##_##id) \
+ REGISTER_INIT(ns, id)
+
+#define REGISTER_INIT(ns, id) [[accumulate]] void Register_##ns##_##id##_init(entity this)
+#define REGISTER_INIT_POST(ns, id) [[accumulate]] void Register_##ns##_##id##_init_post(entity this)
/** internal next pointer */
#define REGISTRY_NEXT enemy
.entity REGISTRY_NEXT;
-#define REGISTRY_SORT(id, field, skip) \
- void _REGISTRY_SWAP_##id(int i, int j, entity pass) { \
- i += skip; j += skip; \
- \
- entity a = id[i], b = id[j]; \
- id[i] = b; \
- id[j] = a; \
- \
- entity a_next = a.REGISTRY_NEXT, b_next = b.REGISTRY_NEXT; \
- a.REGISTRY_NEXT = b_next; \
- b.REGISTRY_NEXT = a_next; \
- \
- if (i == 0) id##_first = b; \
- else id[i - 1].REGISTRY_NEXT = b; \
- \
- if (j == 0) id##_first = a; \
- else id[j - 1].REGISTRY_NEXT = a; \
- } \
- float _REGISTRY_CMP_##id(int i, int j, entity pass) { \
- i += skip; j += skip; \
- string a = id[i].field; \
- string b = id[j].field; \
- return strcasecmp(a, b); \
- } \
- STATIC_INIT(Registry_sort_##id) { \
- heapsort(id##_COUNT - (skip), _REGISTRY_SWAP_##id, _REGISTRY_CMP_##id, NULL); \
- }
+#define REGISTRY_SORT(id, skip) \
+ void _REGISTRY_SWAP_##id(int i, int j, entity pass) \
+ { \
+ i += skip; j += skip; \
+ \
+ entity a = _##id[i], b = _##id[j]; \
+ _##id[i] = b; \
+ _##id[j] = a; \
+ \
+ entity a_next = a.REGISTRY_NEXT, b_next = b.REGISTRY_NEXT; \
+ a.REGISTRY_NEXT = b_next; \
+ b.REGISTRY_NEXT = a_next; \
+ \
+ if (i == 0) id##_first = b; \
+ else _##id[i - 1].REGISTRY_NEXT = b; \
+ \
+ if (j == 0) id##_first = a; \
+ else _##id[j - 1].REGISTRY_NEXT = a; \
+ } \
+ int _REGISTRY_CMP_##id(int i, int j, entity pass) \
+ { \
+ i += skip; j += skip; \
+ string a = _##id[i].registered_id; \
+ string b = _##id[j].registered_id; \
+ return strcmp(a, b); \
+ } \
+ STATIC_INIT(Registry_sort_##id) \
+ { \
+ heapsort(id##_COUNT - (skip), _REGISTRY_SWAP_##id, _REGISTRY_CMP_##id, NULL); \
+ }
+
+#define REGISTRY_HASH(id) Registry_hash_##id
+
+[[accumulate]] void Registry_check(string r, string server) { }
+[[accumulate]] void Registry_send_all() { }
+
+#ifdef SVQC
+void Registry_send(string id, string hash);
+#else
+#define Registry_send(id, hash)
+#endif
+
+#define REGISTRY_CHECK(id) \
+ string REGISTRY_HASH(id); \
+ STATIC_INIT(Registry_check_##id) \
+ { \
+ string algo = "SHA256"; \
+ string join = ":"; \
+ string s = ""; \
+ FOREACH(id, true, LAMBDA(s = strcat(s, join, it.registered_id))); \
+ s = substring(s, strlen(join), -1); \
+ string h = REGISTRY_HASH(id) = strzone(digest_hex(algo, s)); \
+ LOG_TRACEF(#id ": %s\n[%s]\n", h, s); \
+ } \
+ void Registry_check(string r, string sv) \
+ { \
+ if (r == #id) \
+ { \
+ string cl = REGISTRY_HASH(id); \
+ if (cl != sv) \
+ { \
+ LOG_FATALF("client/server mismatch (%s).\nCL: %s\nSV: %s\n", r, cl, sv); \
+ } \
+ } \
+ } \
+ void Registry_send_all() { Registry_send(#id, REGISTRY_HASH(id)); } \
+
+#define REGISTER_REGISTRY(...) EVAL(OVERLOAD(REGISTER_REGISTRY, __VA_ARGS__))
+#define REGISTER_REGISTRY_1(id) REGISTER_REGISTRY_2(id, #id)
+#define REGISTER_REGISTRY_2(id, str) \
+ ACCUMULATE_FUNCTION(__static_init, Register##id) \
+ CLASS(id##Registry, Object) \
+ ATTRIB(id##Registry, m_name, string, str) \
+ ATTRIB(id##Registry, REGISTRY_NEXT, entity, id##_first) \
+ ENDCLASS(id##Registry) \
+ REGISTER(Registries, REGISTRY, id, m_id, NEW(id##Registry));
+
#endif
--- /dev/null
+#ifndef REGISTRY_NET_H
+#define REGISTRY_NET_H
+
+#include "net.qh"
+
+REGISTER_NET_TEMP(registry)
+
+#ifdef CSQC
+NET_HANDLE(registry, bool isnew)
+{
+ string k = ReadString();
+ string v = ReadString();
+ Registry_check(k, v);
+ return true;
+}
+#endif
+
+#ifdef SVQC
+void Registry_send(string id, string hash)
+{
+ int channel = MSG_ONE;
+ WriteHeader(channel, registry);
+ WriteString(channel, id);
+ WriteString(channel, hash);
+}
+#endif
+
+#endif
#define REPLICATE_H
#ifndef MENUQC
-#define REPLICATE(...) EVAL(OVERLOAD(REPLICATE, __VA_ARGS__))
+ #define REPLICATE(...) EVAL(OVERLOAD(REPLICATE, __VA_ARGS__))
-[[accumulate]] void ReplicateVars(entity this, string thisname, int i) { }
+ [[accumulate]] void ReplicateVars(entity this, string thisname, int i) {}
-#define REPLICATE_3(fld, type, var) REPLICATE_4(fld, type, var, )
-#define REPLICATE_4(fld, type, var, func) REPLICATE_##type(fld, var, func)
-#define REPLICATE_string(fld, var, func) REPLICATE_7(fld, string, var, , \
- { if (field) strunzone(field); field = strzone(it); }, \
- { if (field) strunzone(field); field = string_null; }, \
- { \
- /* also initialize to the default value of func when requesting cvars */ \
- string s = func(field); \
- if (s != field) { \
- strunzone(field); \
- field = strzone(s); \
- } \
- })
-#define REPLICATE_float(fld, var, func) REPLICATE_7(fld, float, var, func, { field = stof(it); }, , )
-#define REPLICATE_bool(fld, var, func) REPLICATE_7(fld, bool, var, func, { field = boolean(stoi(it)); }, , )
-#define REPLICATE_int(fld, var, func) REPLICATE_7(fld, int, var, func, { field = stoi(it); }, , )
+ #define REPLICATE_3(fld, type, var) REPLICATE_4(fld, type, var, )
+ #define REPLICATE_4(fld, type, var, func) REPLICATE_##type(fld, var, func)
+ #define REPLICATE_string(fld, var, func) \
+ REPLICATE_7(fld, string, var, , \
+ { if (field) strunzone(field); field = strzone(it); }, \
+ { if (field) strunzone(field); field = string_null; }, \
+ { \
+ /* also initialize to the default value of func when requesting cvars */ \
+ string s = func(field); \
+ if (s != field) \
+ { \
+ strunzone(field); \
+ field = strzone(s); \
+ } \
+ })
+ #define REPLICATE_float(fld, var, func) REPLICATE_7(fld, float, var, func, { field = stof(it); }, , )
+ #define REPLICATE_bool(fld, var, func) REPLICATE_7(fld, bool, var, func, { field = boolean(stoi(it)); }, , )
+ #define REPLICATE_int(fld, var, func) REPLICATE_7(fld, int, var, func, { field = stoi(it); }, , )
-#if defined(SVQC)
- #define REPLICATE_7(fld, type, var, func, create, destroy, after) \
- void ReplicateVars(entity this, string thisname, int i) { \
- type field = this.fld; \
- if (i < 0) { destroy } \
- else { \
- string it = func(argv(i + 1)); \
- bool current = thisname == var; \
- if (i > 0) { \
- if (current) { create } \
- } else { \
- stuffcmd(this, "cl_cmd sendcvar " var "\n"); \
- } \
- if (current) { after } \
- } \
- this.fld = field; \
- }
-#elif defined(CSQC)
- // TODO
- #define REPLICATE_7(fld, type, var, func, create, destroy, after)
-#endif
+ #if defined(SVQC)
+ #define REPLICATE_7(fld, type, var, func, create, destroy, after) \
+ void ReplicateVars(entity this, string thisname, int i) \
+ { \
+ type field = this.fld; \
+ if (i < 0) { destroy } \
+ else \
+ { \
+ string it = func(argv(i + 1)); \
+ bool current = thisname == var; \
+ if (i > 0) \
+ { \
+ if (current) { create } \
+ } \
+ else \
+ { \
+ stuffcmd(this, "cl_cmd sendcvar " var "\n"); \
+ } \
+ if (current) { after } \
+ } \
+ this.fld = field; \
+ }
+ #elif defined(CSQC)
+ // TODO
+ #define REPLICATE_7(fld, type, var, func, create, destroy, after)
+ #endif
#endif
#endif
// Step 1: auto oldself
#if 1
-#define SELFPARAM() noref entity this = __self
-#define setself(s) (__self = s)
-#define self __self
+ #define SELFPARAM() noref entity this = __self
+ #define setself(s) (__self = s)
+ #define self __self
#endif
// Step 2: check SELFPARAM() is present for functions that use self
#if 0
-#define SELFPARAM() [[alias("__self")]] noref entity this = __self
-#define setself(s) (__self = s)
-#define self this
+ #define SELFPARAM() [[alias("__self")]] noref entity this = __self
+ #define setself(s) (__self = s)
+ #define self this
#endif
// Step 3: const self
#if 0
-#define SELFPARAM() noref const entity this = __self
-entity setself(entity e) { return self = e; }
-entity getself() { return self; }
-#define self getself()
+ #define SELFPARAM() noref const entity this = __self
+ entity setself(entity e) { return self = e; }
+ entity getself() { return self; }
+ #define self getself()
#endif
// Step 4: enable when possible
// TODO: Remove SELFPARAM in favor of a parameter
#if 0
-#define SELFPARAM() noref const entity this = __self
-#define self this
+ #define SELFPARAM() noref const entity this = __self
+ #define self this
#endif
#endif
#define SORT_H
/** is only ever called for i1 < i2 */
-typedef void(float i1, float i2, entity pass) swapfunc_t;
+typedef void (int i1, int i2, entity pass) swapfunc_t;
/** <0 for <, ==0 for ==, >0 for > (like strcmp) */
-typedef float(float i1, float i2, entity pass) comparefunc_t;
+typedef int (int i1, int i2, entity pass) comparefunc_t;
-void heapsort(float n, swapfunc_t swap, comparefunc_t cmp, entity pass)
+void heapsort(int n, swapfunc_t swap, comparefunc_t cmp, entity pass)
{
- int root, child;
+ #define heapify(_count) \
+ do \
+ { \
+ for (int start = floor(((_count) - 2) / 2); start >= 0; --start) \
+ { \
+ siftdown(start, (_count) - 1); \
+ } \
+ } \
+ while (0)
- // heapify
- int start = floor((n - 2) / 2);
- while (start >= 0) {
- // siftdown(start, n - 1);
- root = start;
- while (root * 2 + 1 <= n - 1) {
- child = root * 2 + 1;
- if (child < n - 1 && cmp(child, child + 1, pass) < 0) {
- child += 1;
- }
- if (cmp(root, child, pass) < 0) {
- swap(root, child, pass);
- root = child;
- } else {
- break;
- }
- }
- // end of siftdown
- --start;
- }
+ #define siftdown(_start, _end) \
+ do \
+ { \
+ for (int root = (_start); root * 2 + 1 <= (_end); ) \
+ { \
+ int child = root * 2 + 1; \
+ if (child < (_end) && cmp(child, child + 1, pass) < 0) child += 1; \
+ if (cmp(root, child, pass) >= 0) break; \
+ swap(root, child, pass); \
+ root = child; \
+ } \
+ } \
+ while (0)
- // extract
- int end = n - 1;
- while (end > 0) {
- swap(0, end, pass);
- end -= 1;
- // siftdown(0, end);
- root = 0;
- while (root * 2 + 1 <= end) {
- child = root * 2 + 1;
- if (child < end && cmp(child, child+1, pass) < 0) {
- child += 1;
- }
- if (cmp(root, child, pass) < 0) {
- swap(root, child, pass);
- root = child;
- } else {
- break;
- }
- }
- // end of siftdown
- }
+ heapify(n);
+ int end = n - 1;
+ while (end > 0)
+ {
+ swap(0, end, pass);
+ end -= 1;
+ siftdown(0, end);
+ }
}
void shuffle(float n, swapfunc_t swap, entity pass)
{
- for (int i = 1; i < n; ++i) {
- // swap i-th item at a random position from 0 to i
- // proof for even distribution:
- // n = 1: obvious
- // n -> n+1:
- // item n+1 gets at any position with chance 1/(n+1)
- // all others will get their 1/n chance reduced by factor n/(n+1)
- // to be on place n+1, their chance will be 1/(n+1)
- // 1/n * n/(n+1) = 1/(n+1)
- // q.e.d.
- int j = floor(random() * (i + 1));
- if (j != i)
- swap(j, i, pass);
- }
+ for (int i = 1; i < n; ++i)
+ {
+ // swap i-th item at a random position from 0 to i
+ // proof for even distribution:
+ // n = 1: obvious
+ // n -> n+1:
+ // item n+1 gets at any position with chance 1/(n+1)
+ // all others will get their 1/n chance reduced by factor n/(n+1)
+ // to be on place n+1, their chance will be 1/(n+1)
+ // 1/n * n/(n+1) = 1/(n+1)
+ // q.e.d.
+ int j = floor(random() * (i + 1));
+ if (j != i) swap(j, i, pass);
+ }
}
#endif
entity Sort_Spawn()
{
- entity sort;
- sort = spawn();
+ entity sort = new(sortlist);
+ make_pure(sort);
sort.sort_next = NULL;
sort.chain = sort;
return sort;
/*
entity Sort_New(float(entity,entity) cmp)
{
- entity sort;
- sort = spawn();
- sort.sort_cmp = cmp;
- sort.sort_next = world;
- sort.chain = sort;
- return sort;
+ entity sort;
+ sort = spawn();
+ sort.sort_cmp = cmp;
+ sort.sort_next = world;
+ sort.chain = sort;
+ return sort;
}
void Sort_Remove(entity sort)
{
- entity next;
- while(sort.sort_next)
- {
- next = sort.sort_next;
- remove(sort);
- sort = next;
- }
- remove(sort);
+ entity next;
+ while(sort.sort_next)
+ {
+ next = sort.sort_next;
+ remove(sort);
+ sort = next;
+ }
+ remove(sort);
}
void Sort_Add(entity sort, entity ent)
{
- entity next, parent;
- parent = sort;
- next = sort.sort_next;
- while(next)
- {
- if(!sort.sort_cmp(next, ent))
- break;
- parent = next;
- next = next.sort_next;
- }
- ent.sort_next = next;
- ent.sort_prev = parent;
- parent.sort_next = ent;
- if(next)
- next.sort_prev = ent;
+ entity next, parent;
+ parent = sort;
+ next = sort.sort_next;
+ while(next)
+ {
+ if(!sort.sort_cmp(next, ent))
+ break;
+ parent = next;
+ next = next.sort_next;
+ }
+ ent.sort_next = next;
+ ent.sort_prev = parent;
+ parent.sort_next = ent;
+ if(next)
+ next.sort_prev = ent;
}
void Sort_Reset(entity sort)
{
- sort.chain = sort;
+ sort.chain = sort;
}
float Sort_HasNext(entity sort)
{
- return (sort.chain.sort_next != world);
+ return (sort.chain.sort_next != world);
}
entity Sort_Next(entity sort)
{
- entity next;
- next = sort.chain.sort_next;
- if(!next) {
- next = spawn();
- sort.chain.sort_next = next;
- next.sort_prev = sort.chain;
- next.sort_next = world;
- }
- sort.chain = next;
- return next;
+ entity next;
+ next = sort.chain.sort_next;
+ if(!next) {
+ next = spawn();
+ sort.chain.sort_next = next;
+ next.sort_prev = sort.chain;
+ next.sort_next = world;
+ }
+ sort.chain = next;
+ return next;
}
void Sort_Finish(entity sort)
{
- entity next;
- next = sort.chain;
- if(!next)
- return;
+ entity next;
+ next = sort.chain;
+ if(!next)
+ return;
- while(next.sort_next)
- {
- sort = next.sort_next;
- next.sort_next = sort.sort_next;
- remove(sort);
- }
+ while(next.sort_next)
+ {
+ sort = next.sort_next;
+ next.sort_next = sort.sort_next;
+ remove(sort);
+ }
}
entity Sort_Get(entity sort, float i)
{
- for (; sort.sort_next && i > 0; --i)
- sort = sort.sort_next;
- return sort;
+ for (; sort.sort_next && i > 0; --i)
+ sort = sort.sort_next;
+ return sort;
}
*/
/*
void Sort_Erase(entity ent)
{
- ent.sort_prev.sort_next = ent.sort_next;
- if(ent.sort_next)
- ent.sort_next.sort_prev = ent.sort_prev;
- remove(ent);
+ ent.sort_prev.sort_next = ent.sort_next;
+ if(ent.sort_next)
+ ent.sort_next.sort_prev = ent.sort_prev;
+ remove(ent);
}
void Sort_RemoveOld(entity sort)
{
- entity tmp;
- for(tmp = sort.sort_next; tmp; tmp = tmp.sort_next)
- {
- if(tmp.frame < time)
- {
- tmp = tmp.sort_prev;
- Sort_Erase(tmp.sort_next);
- }
- }
+ entity tmp;
+ for(tmp = sort.sort_next; tmp; tmp = tmp.sort_next)
+ {
+ if(tmp.frame < time)
+ {
+ tmp = tmp.sort_prev;
+ Sort_Erase(tmp.sort_next);
+ }
+ }
}
*/
#define SORTLIST_H
entityclass(Sort);
-//.float(entity,entity) sort_cmp;
-class(Sort) .entity chain, sort_next, sort_prev;
+// .float(entity,entity) sort_cmp;
+class(Sort).entity chain, sort_next, sort_prev;
entity Sort_Spawn();
* @param a FIRST entity
* @param b entity after a
*/
-#define SORT_SWAP(a,b) \
- b.sort_prev = a.sort_prev; \
- a.sort_next = b.sort_next; \
- if(b.sort_next) b.sort_next.sort_prev = a; \
- if(a.sort_prev) a.sort_prev.sort_next = b; \
- a.sort_prev = b; \
+#define SORT_SWAP(a, b) \
+ b.sort_prev = a.sort_prev; \
+ a.sort_next = b.sort_next; \
+ if (b.sort_next) b.sort_next.sort_prev = a; \
+ if (a.sort_prev) a.sort_prev.sort_next = b; \
+ a.sort_prev = b; \
b.sort_next = a
#endif
// Optional type checking; increases compile time too much to be enabled by default
#if 0
-bool entityfieldassignablefromeditor(int i) {
- switch (entityfieldtype(i)) {
- case FIELD_STRING:
- case FIELD_FLOAT:
- case FIELD_VECTOR:
- return true;
- }
- return false;
-}
+ bool entityfieldassignablefromeditor(int i)
+ {
+ switch (entityfieldtype(i))
+ {
+ case FIELD_STRING:
+ case FIELD_FLOAT:
+ case FIELD_VECTOR:
+ return true;
+ }
+ return false;
+ }
-#define _spawnfunc_checktypes(fld) if (fieldname == #fld) \
- if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted\n", fieldname);
+ #define _spawnfunc_checktypes(fld) \
+ if (fieldname == #fld) \
+ if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted\n", fieldname);
#else
-#define _spawnfunc_checktypes(fld)
+ #define _spawnfunc_checktypes(fld)
#endif
-#define _spawnfunc_check(fld) if (fieldname == #fld) \
- continue;
+ #define _spawnfunc_check(fld) \
+ if (fieldname == #fld) continue;
-#define spawnfunc_1(id, whitelist) spawnfunc_2(id, whitelist)
-#define spawnfunc_2(id, whitelist) void spawnfunc_##id(entity this) { \
- this = self; \
- if (!this.spawnfunc_checked) { \
- for (int i = 0, n = numentityfields(); i < n; ++i) { \
- string value = getentityfieldstring(i, this); \
- string fieldname = entityfieldname(i); \
- whitelist(_spawnfunc_checktypes) \
- if (value == "") continue; \
- if (fieldname == "") continue; \
- FIELDS_COMMON(_spawnfunc_check) \
- whitelist(_spawnfunc_check) \
- LOG_WARNINGF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue.\n"), #id, fieldname, value); \
- } \
- this.spawnfunc_checked = true; \
- } \
-} \
-[[accumulate]] void spawnfunc_##id(entity this)
+ #define spawnfunc_1(id, whitelist) spawnfunc_2(id, whitelist)
+ #define spawnfunc_2(id, whitelist) \
+ void spawnfunc_##id(entity this) \
+ { \
+ this = self; \
+ if (!this.sourceLocFile) \
+ { \
+ this.sourceLocFile = __FILE__; \
+ this.sourceLocLine = __LINE__; \
+ } \
+ if (!this.spawnfunc_checked) \
+ { \
+ for (int i = 0, n = numentityfields(); i < n; ++i) \
+ { \
+ string value = getentityfieldstring(i, this); \
+ string fieldname = entityfieldname(i); \
+ whitelist(_spawnfunc_checktypes) \
+ if (value == "") continue; \
+ if (fieldname == "") continue; \
+ FIELDS_COMMON(_spawnfunc_check) \
+ whitelist(_spawnfunc_check) \
+ LOG_WARNINGF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue.\n"), #id, fieldname, value); \
+ } \
+ this.spawnfunc_checked = true; \
+ } \
+ } \
+ [[accumulate]] void spawnfunc_##id(entity this)
-#define FIELD_SCALAR(fld, n) \
- fld(n)
-#define FIELD_VEC(fld, n) \
- fld(n) \
- fld(n##_x) \
- fld(n##_y) \
- fld(n##_z)
+ #define FIELD_SCALAR(fld, n) \
+ fld(n)
+ #define FIELD_VEC(fld, n) \
+ fld(n) \
+ fld(n##_x) \
+ fld(n##_y) \
+ fld(n##_z)
-#define FIELDS_NONE(fld)
-#define FIELDS_ALL(fld) if (false)
+ #define FIELDS_NONE(fld)
+ #define FIELDS_ALL(fld) if (false)
-#define FIELDS_COMMON(fld) \
- FIELD_SCALAR(fld, classname) \
- FIELD_SCALAR(fld, spawnfunc_checked) \
- /**/
+ #define FIELDS_COMMON(fld) \
+ FIELD_SCALAR(fld, classname) \
+ FIELD_SCALAR(fld, spawnfunc_checked) \
+ /**/
-#define FIELDS_UNION(fld) \
- FIELD_SCALAR(fld, Version) \
- FIELD_SCALAR(fld, ammo_cells) \
- FIELD_SCALAR(fld, ammo_nails) \
- FIELD_SCALAR(fld, ammo_rockets) \
- FIELD_SCALAR(fld, armorvalue) \
- FIELD_SCALAR(fld, atten) \
- FIELD_SCALAR(fld, bgmscriptdecay) \
- FIELD_SCALAR(fld, bgmscriptsustain) \
- FIELD_SCALAR(fld, bgmscript) \
- FIELD_SCALAR(fld, button0) \
- FIELD_SCALAR(fld, cnt) \
- FIELD_SCALAR(fld, colormap) \
- FIELD_SCALAR(fld, count) \
- FIELD_SCALAR(fld, curvetarget) \
- FIELD_SCALAR(fld, cvarfilter) \
- FIELD_SCALAR(fld, debrisdamageforcescale) \
- FIELD_SCALAR(fld, debrisfadetime) \
- FIELD_SCALAR(fld, debristimejitter) \
- FIELD_SCALAR(fld, debristime) \
- FIELD_SCALAR(fld, debris) \
- FIELD_SCALAR(fld, delay) \
- FIELD_SCALAR(fld, dmgtime) \
- FIELD_SCALAR(fld, dmg) \
- FIELD_SCALAR(fld, dmg_edge) \
- FIELD_SCALAR(fld, dmg_force) \
- FIELD_SCALAR(fld, dmg_radius) \
- FIELD_SCALAR(fld, effects) \
- FIELD_SCALAR(fld, flags) \
- FIELD_SCALAR(fld, fog) \
- FIELD_SCALAR(fld, frags) \
- FIELD_SCALAR(fld, frame) \
- FIELD_SCALAR(fld, gametypefilter) \
- FIELD_SCALAR(fld, geomtype) \
- FIELD_SCALAR(fld, gravity) \
- FIELD_SCALAR(fld, health) \
- FIELD_SCALAR(fld, height) \
- FIELD_SCALAR(fld, impulse) \
- FIELD_SCALAR(fld, killtarget) \
- FIELD_SCALAR(fld, lerpfrac) \
- FIELD_SCALAR(fld, light_lev) \
- FIELD_SCALAR(fld, lip) \
- FIELD_SCALAR(fld, loddistance1) \
- FIELD_SCALAR(fld, lodmodel1) \
- FIELD_SCALAR(fld, ltime) \
- FIELD_SCALAR(fld, mdl) \
- FIELD_SCALAR(fld, message2) \
- FIELD_SCALAR(fld, message) \
- FIELD_SCALAR(fld, modelindex) \
- FIELD_SCALAR(fld, modelscale) \
- FIELD_SCALAR(fld, model) \
- FIELD_SCALAR(fld, monster_moveflags) \
- FIELD_SCALAR(fld, movetype) \
- FIELD_SCALAR(fld, netname) \
- FIELD_SCALAR(fld, nextthink) \
- FIELD_SCALAR(fld, noalign) \
- FIELD_SCALAR(fld, noise1) \
- FIELD_SCALAR(fld, noise2) \
- FIELD_SCALAR(fld, noise) \
- FIELD_SCALAR(fld, phase) \
- FIELD_SCALAR(fld, platmovetype) \
- FIELD_SCALAR(fld, race_place) \
- FIELD_SCALAR(fld, radius) \
- FIELD_SCALAR(fld, respawntimejitter) \
- FIELD_SCALAR(fld, respawntime) \
- FIELD_SCALAR(fld, restriction) \
- FIELD_SCALAR(fld, scale) \
- FIELD_SCALAR(fld, skin) \
- FIELD_SCALAR(fld, solid) \
- FIELD_SCALAR(fld, sound1) \
- FIELD_SCALAR(fld, sounds) \
- FIELD_SCALAR(fld, spawnflags) \
- FIELD_SCALAR(fld, speed) \
- FIELD_SCALAR(fld, strength) \
- FIELD_SCALAR(fld, target2) \
- FIELD_SCALAR(fld, target3) \
- FIELD_SCALAR(fld, target4) \
- FIELD_SCALAR(fld, targetname) \
- FIELD_SCALAR(fld, target) \
- FIELD_SCALAR(fld, target_random) \
- FIELD_SCALAR(fld, target_range) \
- FIELD_SCALAR(fld, team) \
- FIELD_SCALAR(fld, turret_scale_health) \
- FIELD_SCALAR(fld, turret_scale_range) \
- FIELD_SCALAR(fld, turret_scale_respawn) \
- FIELD_SCALAR(fld, volume) \
- FIELD_SCALAR(fld, wait) \
- FIELD_SCALAR(fld, warpzone_fadeend) \
- FIELD_SCALAR(fld, warpzone_fadestart) \
- FIELD_SCALAR(fld, weapon) \
- FIELD_VEC(fld, absmax) \
- FIELD_VEC(fld, absmin) \
- FIELD_VEC(fld, angles) \
- FIELD_VEC(fld, avelocity) \
- FIELD_VEC(fld, maxs) \
- FIELD_VEC(fld, maxs) \
- FIELD_VEC(fld, mins) \
- FIELD_VEC(fld, modelscale_vec) \
- FIELD_VEC(fld, origin) \
- FIELD_VEC(fld, velocity) \
- /**/
+ #define FIELDS_UNION(fld) \
+ FIELD_SCALAR(fld, sourceLocFile) \
+ FIELD_SCALAR(fld, sourceLocLine) \
+ FIELD_SCALAR(fld, Version) \
+ FIELD_SCALAR(fld, ammo_cells) \
+ FIELD_SCALAR(fld, ammo_nails) \
+ FIELD_SCALAR(fld, ammo_rockets) \
+ FIELD_SCALAR(fld, armorvalue) \
+ FIELD_SCALAR(fld, atten) \
+ FIELD_SCALAR(fld, bgmscriptdecay) \
+ FIELD_SCALAR(fld, bgmscriptsustain) \
+ FIELD_SCALAR(fld, bgmscript) \
+ FIELD_SCALAR(fld, button0) \
+ FIELD_SCALAR(fld, cnt) \
+ FIELD_SCALAR(fld, colormap) \
+ FIELD_SCALAR(fld, count) \
+ FIELD_SCALAR(fld, curvetarget) \
+ FIELD_SCALAR(fld, cvarfilter) \
+ FIELD_SCALAR(fld, debrisdamageforcescale) \
+ FIELD_SCALAR(fld, debrisfadetime) \
+ FIELD_SCALAR(fld, debristimejitter) \
+ FIELD_SCALAR(fld, debristime) \
+ FIELD_SCALAR(fld, debris) \
+ FIELD_SCALAR(fld, delay) \
+ FIELD_SCALAR(fld, dmgtime) \
+ FIELD_SCALAR(fld, dmg) \
+ FIELD_SCALAR(fld, dmg_edge) \
+ FIELD_SCALAR(fld, dmg_force) \
+ FIELD_SCALAR(fld, dmg_radius) \
+ FIELD_SCALAR(fld, effects) \
+ FIELD_SCALAR(fld, flags) \
+ FIELD_SCALAR(fld, fog) \
+ FIELD_SCALAR(fld, frags) \
+ FIELD_SCALAR(fld, frame) \
+ FIELD_SCALAR(fld, gametypefilter) \
+ FIELD_SCALAR(fld, geomtype) \
+ FIELD_SCALAR(fld, gravity) \
+ FIELD_SCALAR(fld, health) \
+ FIELD_SCALAR(fld, height) \
+ FIELD_SCALAR(fld, impulse) \
+ FIELD_SCALAR(fld, killtarget) \
+ FIELD_SCALAR(fld, lerpfrac) \
+ FIELD_SCALAR(fld, light_lev) \
+ FIELD_SCALAR(fld, lip) \
+ FIELD_SCALAR(fld, loddistance1) \
+ FIELD_SCALAR(fld, lodmodel1) \
+ FIELD_SCALAR(fld, ltime) \
+ FIELD_SCALAR(fld, mdl) \
+ FIELD_SCALAR(fld, message2) \
+ FIELD_SCALAR(fld, message) \
+ FIELD_SCALAR(fld, modelindex) \
+ FIELD_SCALAR(fld, modelscale) \
+ FIELD_SCALAR(fld, model) \
+ FIELD_SCALAR(fld, monster_moveflags) \
+ FIELD_SCALAR(fld, movetype) \
+ FIELD_SCALAR(fld, netname) \
+ FIELD_SCALAR(fld, nextthink) \
+ FIELD_SCALAR(fld, noalign) \
+ FIELD_SCALAR(fld, noise1) \
+ FIELD_SCALAR(fld, noise2) \
+ FIELD_SCALAR(fld, noise) \
+ FIELD_SCALAR(fld, phase) \
+ FIELD_SCALAR(fld, platmovetype) \
+ FIELD_SCALAR(fld, race_place) \
+ FIELD_SCALAR(fld, radius) \
+ FIELD_SCALAR(fld, respawntimejitter) \
+ FIELD_SCALAR(fld, respawntime) \
+ FIELD_SCALAR(fld, restriction) \
+ FIELD_SCALAR(fld, scale) \
+ FIELD_SCALAR(fld, skin) \
+ FIELD_SCALAR(fld, solid) \
+ FIELD_SCALAR(fld, sound1) \
+ FIELD_SCALAR(fld, sounds) \
+ FIELD_SCALAR(fld, spawnflags) \
+ FIELD_SCALAR(fld, speed) \
+ FIELD_SCALAR(fld, strength) \
+ FIELD_SCALAR(fld, target2) \
+ FIELD_SCALAR(fld, target3) \
+ FIELD_SCALAR(fld, target4) \
+ FIELD_SCALAR(fld, targetname) \
+ FIELD_SCALAR(fld, target) \
+ FIELD_SCALAR(fld, target_random) \
+ FIELD_SCALAR(fld, target_range) \
+ FIELD_SCALAR(fld, team) \
+ FIELD_SCALAR(fld, turret_scale_health) \
+ FIELD_SCALAR(fld, turret_scale_range) \
+ FIELD_SCALAR(fld, turret_scale_respawn) \
+ FIELD_SCALAR(fld, volume) \
+ FIELD_SCALAR(fld, wait) \
+ FIELD_SCALAR(fld, warpzone_fadeend) \
+ FIELD_SCALAR(fld, warpzone_fadestart) \
+ FIELD_SCALAR(fld, weapon) \
+ FIELD_VEC(fld, absmax) \
+ FIELD_VEC(fld, absmin) \
+ FIELD_VEC(fld, angles) \
+ FIELD_VEC(fld, avelocity) \
+ FIELD_VEC(fld, maxs) \
+ FIELD_VEC(fld, maxs) \
+ FIELD_VEC(fld, mins) \
+ FIELD_VEC(fld, modelscale_vec) \
+ FIELD_VEC(fld, origin) \
+ FIELD_VEC(fld, velocity) \
+ /**/
-#define spawnfunc(...) EVAL(OVERLOAD(spawnfunc, __VA_ARGS__, FIELDS_UNION))
+ #define spawnfunc(...) EVAL(OVERLOAD(spawnfunc, __VA_ARGS__, FIELDS_UNION))
#endif
#ifndef STATIC_H
#define STATIC_H
-void __static_init() { }
+void __static_init() {}
#define static_init() CALL_ACCUMULATED_FUNCTION(__static_init)
-void __static_init_late() { }
+void __static_init_late() {}
#define static_init_late() CALL_ACCUMULATED_FUNCTION(__static_init_late)
-
-#define REGISTER_REGISTRY(func) ACCUMULATE_FUNCTION(__static_init, func)
+void __static_init_precache() {}
+#define static_init_precache() CALL_ACCUMULATED_FUNCTION(__static_init_precache)
#define _STATIC_INIT(where, func) \
- void _static_##func(); \
- ACCUMULATE_FUNCTION(where, _static_##func) \
- void _static_##func()
+ void _static_##func(); \
+ ACCUMULATE_FUNCTION(where, _static_##func) \
+ void _static_##func()
-#define STATIC_INIT(func) _STATIC_INIT(__static_init, func)
-#define STATIC_INIT_LATE(func) _STATIC_INIT(__static_init_late, func##_late)
+#define STATIC_INIT(func) _STATIC_INIT(__static_init, func)
+#define STATIC_INIT_LATE(func) _STATIC_INIT(__static_init_late, func##_late)
+#define PRECACHE(func) _STATIC_INIT(__static_init_precache, func##_precache)
#endif
--- /dev/null
+#ifndef LIB_STATS_H
+#define LIB_STATS_H
+
+#include "registry.qh"
+#include "sort.qh"
+
+.int m_id;
+
+#if defined(CSQC)
+ /** Get all stats and store them as globals, access with `STAT(ID)` */
+ void stats_get() {}
+ #define STAT(...) EVAL(OVERLOAD(STAT, __VA_ARGS__))
+ #define STAT_1(id) STAT_2(id, NULL)
+ #define STAT_2(id, cl) (0, _STAT(id))
+
+ #define getstat_int(id) getstati(id, 0, 24)
+ #define getstat_bool(id) boolean(getstati(id))
+ #define getstat_float(id) getstatf(id)
+
+ #define _STAT(id) g_stat_##id
+ #define REGISTER_STAT(id, type) \
+ type _STAT(id); \
+ REGISTER(Stats, STAT, id, m_id, new(stat)) \
+ { \
+ make_pure(this); \
+ } \
+ [[accumulate]] void stats_get() \
+ { \
+ _STAT(id) = getstat_##type(STAT_##id.m_id); \
+ }
+#elif defined(SVQC)
+ /** Add all registered stats, access with `STAT(ID, player)` or `.type stat = _STAT(ID); player.stat` */
+ void stats_add() {}
+ #define STAT(id, cl) (cl._STAT(id))
+
+ #define addstat_int(id, fld) addstat(id, AS_INT, fld)
+ #define addstat_bool(id, fld) addstat(id, AS_INT, fld)
+ #define addstat_float(id, fld) addstat(id, AS_FLOAT, fld)
+ const int AS_STRING = 1;
+ const int AS_INT = 2;
+ const int AS_FLOAT = 8;
+
+ #define _STAT(id) stat_##id
+ #define REGISTER_STAT(id, type) \
+ .type _STAT(id); \
+ REGISTER(Stats, STAT, id, m_id, new(stat)) \
+ { \
+ make_pure(this); \
+ } \
+ [[accumulate]] void stats_add() \
+ { \
+ addstat_##type(STAT_##id.m_id, _STAT(id)); \
+ }
+#else
+ #define REGISTER_STAT(id, type)
+#endif
+
+const int STATS_ENGINE_RESERVE = 32 + (8 * 3); // Not sure how to handle vector stats yet, reserve them too
+
+REGISTRY(Stats, 220 - STATS_ENGINE_RESERVE)
+REGISTER_REGISTRY(Stats)
+REGISTRY_SORT(Stats, 0)
+REGISTRY_CHECK(Stats)
+STATIC_INIT(RegisterStats_renumber)
+{
+ FOREACH(Stats, true, LAMBDA(it.m_id = STATS_ENGINE_RESERVE + i));
+}
+#ifdef SVQC
+STATIC_INIT(stats_add) { stats_add(); }
+#endif
+
+#endif
#ifndef STRING_H
#define STRING_H
+#include "nil.qh"
+#include "sort.qh"
+#include "oo.qh"
+
#ifndef SVQC
-float stringwidth_colors(string s, vector theSize)
+ float stringwidth_colors(string s, vector theSize)
+ {
+ return stringwidth(s, true, theSize);
+ }
+
+ float stringwidth_nocolors(string s, vector theSize)
+ {
+ return stringwidth(s, false, theSize);
+ }
+#endif
+
+// TODO: macro
+string seconds_tostring(float sec)
{
- return stringwidth(s, true, theSize);
+ float minutes = floor(sec / 60);
+ sec -= minutes * 60;
+ return sprintf("%d:%02d", minutes, sec);
}
-float stringwidth_nocolors(string s, vector theSize)
+string format_time(float seconds)
{
- return stringwidth(s, false, theSize);
+ seconds = floor(seconds + 0.5);
+ float days = floor(seconds / 864000);
+ seconds -= days * 864000;
+ float hours = floor(seconds / 36000);
+ seconds -= hours * 36000;
+ float minutes = floor(seconds / 600);
+ seconds -= minutes * 600;
+ if (days > 0) return sprintf(_("%d days, %02d:%02d:%02d"), days, hours, minutes, seconds);
+ else return sprintf(_("%02d:%02d:%02d"), hours, minutes, seconds);
}
-#endif
-// Timer (#5)
-//
-// TODO: macro
-string seconds_tostring(float sec)
+string mmsss(float tenths)
+{
+ tenths = floor(tenths + 0.5);
+ float minutes = floor(tenths / 600);
+ tenths -= minutes * 600;
+ string s = ftos(1000 + tenths);
+ return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 1));
+}
+
+string mmssss(float hundredths)
{
- float minutes = floor(sec / 60);
- sec -= minutes * 60;
- return sprintf("%d:%02d", minutes, sec);
+ hundredths = floor(hundredths + 0.5);
+ float minutes = floor(hundredths / 6000);
+ hundredths -= minutes * 6000;
+ string s = ftos(10000 + hundredths);
+ return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 2));
}
int ColorTranslateMode;
string ColorTranslateRGB(string s)
{
- return (ColorTranslateMode & 1) ? strdecolorize(s) : s;
+ return (ColorTranslateMode & 1) ? strdecolorize(s) : s;
}
// color code replace, place inside of sprintf and parse the string... defaults described as constants
string autocvar_hud_colorset_foreground_3 = "4"; // F3 - Blue // tertiary priority or relatively inconsequential text
string autocvar_hud_colorset_foreground_4 = "1"; // F4 - Red // notice/attention grabbing texting
// "kill" colors
-string autocvar_hud_colorset_kill_1 = "1"; // K1 - Red // "bad" or "dangerous" text (death messages against you, kill notifications, etc)
-string autocvar_hud_colorset_kill_2 = "3"; // K2 - Yellow // similar to above, but less important... OR, a highlight out of above message type
-string autocvar_hud_colorset_kill_3 = "4"; // K3 - Blue // "good" or "beneficial" text (you fragging someone, etc)
+string autocvar_hud_colorset_kill_1 = "1"; // K1 - Red // "bad" or "dangerous" text (death messages against you, kill notifications, etc)
+string autocvar_hud_colorset_kill_2 = "3"; // K2 - Yellow // similar to above, but less important... OR, a highlight out of above message type
+string autocvar_hud_colorset_kill_3 = "4"; // K3 - Blue // "good" or "beneficial" text (you fragging someone, etc)
// background color
-string autocvar_hud_colorset_background = "7"; // BG - White // neutral/unimportant text
+string autocvar_hud_colorset_background = "7"; // BG - White // neutral/unimportant text
/** color code replace, place inside of sprintf and parse the string */
string CCR(string input)
{
- // See the autocvar declarations in util.qh for default values
+ // See the autocvar declarations in util.qh for default values
- // foreground/normal colors
- input = strreplace("^F1", strcat("^", autocvar_hud_colorset_foreground_1), input);
- input = strreplace("^F2", strcat("^", autocvar_hud_colorset_foreground_2), input);
- input = strreplace("^F3", strcat("^", autocvar_hud_colorset_foreground_3), input);
- input = strreplace("^F4", strcat("^", autocvar_hud_colorset_foreground_4), input);
+ // foreground/normal colors
+ input = strreplace("^F1", strcat("^", autocvar_hud_colorset_foreground_1), input);
+ input = strreplace("^F2", strcat("^", autocvar_hud_colorset_foreground_2), input);
+ input = strreplace("^F3", strcat("^", autocvar_hud_colorset_foreground_3), input);
+ input = strreplace("^F4", strcat("^", autocvar_hud_colorset_foreground_4), input);
- // "kill" colors
- input = strreplace("^K1", strcat("^", autocvar_hud_colorset_kill_1), input);
- input = strreplace("^K2", strcat("^", autocvar_hud_colorset_kill_2), input);
- input = strreplace("^K3", strcat("^", autocvar_hud_colorset_kill_3), input);
+ // "kill" colors
+ input = strreplace("^K1", strcat("^", autocvar_hud_colorset_kill_1), input);
+ input = strreplace("^K2", strcat("^", autocvar_hud_colorset_kill_2), input);
+ input = strreplace("^K3", strcat("^", autocvar_hud_colorset_kill_3), input);
- // background colors
- input = strreplace("^BG", strcat("^", autocvar_hud_colorset_background), input);
- input = strreplace("^N", "^7", input); // "none"-- reset to white...
- return input;
+ // background colors
+ input = strreplace("^BG", strcat("^", autocvar_hud_colorset_background), input);
+ input = strreplace("^N", "^7", input); // "none"-- reset to white...
+ return input;
}
-bool startsWith(string haystack, string needle)
-{
- return substring(haystack, 0, strlen(needle)) == needle;
-}
+#define startsWith(haystack, needle) (strstrofs(haystack, needle, 0) == 0)
bool startsWithNocase(string haystack, string needle)
{
- return strcasecmp(substring(haystack, 0, strlen(needle)), needle) == 0;
+ return strcasecmp(substring(haystack, 0, strlen(needle)), needle) == 0;
}
/** unzone the string, and return it as tempstring. Safe to be called on string_null */
string fstrunzone(string s)
{
- if (!s) return s;
- string sc = strcat(s, "");
- strunzone(s);
- return sc;
+ if (!s) return s;
+ string sc = strcat(s, "");
+ strunzone(s);
+ return sc;
}
+/** returns first word */
string car(string s)
{
- int o = strstrofs(s, " ", 0);
- if (o < 0) return s;
- return substring(s, 0, o);
+ int o = strstrofs(s, " ", 0);
+ if (o < 0) return s;
+ return substring(s, 0, o);
}
+/** returns all but first word */
string cdr(string s)
{
- int o = strstrofs(s, " ", 0);
- if (o < 0) return string_null;
- return substring(s, o + 1, strlen(s) - (o + 1));
+ int o = strstrofs(s, " ", 0);
+ if (o < 0) return string_null;
+ return substring(s, o + 1, strlen(s) - (o + 1));
}
string substring_range(string s, float b, float e)
{
- return substring(s, b, e - b);
+ return substring(s, b, e - b);
}
string swapwords(string str, float i, float j)
{
- float n;
- string s1, s2, s3, s4, s5;
- float si, ei, sj, ej, s0, en;
- n = tokenizebyseparator(str, " "); // must match g_maplist processing in ShuffleMaplist and "shuffle"
- si = argv_start_index(i);
- sj = argv_start_index(j);
- ei = argv_end_index(i);
- ej = argv_end_index(j);
- s0 = argv_start_index(0);
- en = argv_end_index(n-1);
- s1 = substring_range(str, s0, si);
- s2 = substring_range(str, si, ei);
- s3 = substring_range(str, ei, sj);
- s4 = substring_range(str, sj, ej);
- s5 = substring_range(str, ej, en);
- return strcat(s1, s4, s3, s2, s5);
+ float n;
+ string s1, s2, s3, s4, s5;
+ float si, ei, sj, ej, s0, en;
+ n = tokenizebyseparator(str, " "); // must match g_maplist processing in ShuffleMaplist and "shuffle"
+ si = argv_start_index(i);
+ sj = argv_start_index(j);
+ ei = argv_end_index(i);
+ ej = argv_end_index(j);
+ s0 = argv_start_index(0);
+ en = argv_end_index(n - 1);
+ s1 = substring_range(str, s0, si);
+ s2 = substring_range(str, si, ei);
+ s3 = substring_range(str, ei, sj);
+ s4 = substring_range(str, sj, ej);
+ s5 = substring_range(str, ej, en);
+ return strcat(s1, s4, s3, s2, s5);
}
string _shufflewords_str;
void _shufflewords_swapfunc(float i, float j, entity pass)
{
- _shufflewords_str = swapwords(_shufflewords_str, i, j);
+ _shufflewords_str = swapwords(_shufflewords_str, i, j);
}
string shufflewords(string str)
{
- _shufflewords_str = str;
- int n = tokenizebyseparator(str, " ");
- shuffle(n, _shufflewords_swapfunc, NULL);
- str = _shufflewords_str;
- _shufflewords_str = string_null;
- return str;
+ _shufflewords_str = str;
+ int n = tokenizebyseparator(str, " ");
+ shuffle(n, _shufflewords_swapfunc, NULL);
+ str = _shufflewords_str;
+ _shufflewords_str = string_null;
+ return str;
}
string unescape(string in)
{
- in = strzone(in); // but it doesn't seem to be necessary in my tests at least
-
- int len = strlen(in);
- string str = "";
- for (int i = 0; i < len; ++i) {
- string s = substring(in, i, 1);
- if (s == "\\") {
- s = substring(in, i + 1, 1);
- if (s == "n")
- str = strcat(str, "\n");
- else if (s == "\\")
- str = strcat(str, "\\");
- else
- str = strcat(str, substring(in, i, 2));
- ++i;
- continue;
- }
- str = strcat(str, s);
- }
- strunzone(in);
- return str;
+ in = strzone(in); // but it doesn't seem to be necessary in my tests at least
+
+ int len = strlen(in);
+ string str = "";
+ for (int i = 0; i < len; ++i)
+ {
+ string s = substring(in, i, 1);
+ if (s == "\\")
+ {
+ s = substring(in, i + 1, 1);
+ if (s == "n") str = strcat(str, "\n");
+ else if (s == "\\") str = strcat(str, "\\");
+ else str = strcat(str, substring(in, i, 2));
+ ++i;
+ continue;
+ }
+ str = strcat(str, s);
+ }
+ strunzone(in);
+ return str;
}
string strwords(string s, int w)
{
- int endpos = 0;
- for (; w && endpos >= 0; --w) endpos = strstrofs(s, " ", endpos + 1);
- if (endpos < 0) return s;
- return substring(s, 0, endpos);
+ int endpos = 0;
+ for ( ; w && endpos >= 0; --w)
+ endpos = strstrofs(s, " ", endpos + 1);
+ if (endpos < 0) return s;
+ return substring(s, 0, endpos);
}
-bool strhasword(string s, string w)
+#define strhasword(s, w) (strstrofs(strcat(" ", s, " "), strcat(" ", w, " "), 0) >= 0)
+
+int u8_strsize(string s)
{
- return strstrofs(strcat(" ", s, " "), strcat(" ", w, " "), 0) >= 0;
+ int l = 0;
+ for (int i = 0, c; (c = str2chr(s, i)) > 0; ++i, ++l)
+ {
+ l += (c >= 0x80);
+ l += (c >= 0x800);
+ l += (c >= 0x10000);
+ }
+ return l;
}
-int u8_strsize(string s)
+bool isInvisibleString(string s)
+{
+ s = strdecolorize(s);
+ bool utf8 = cvar("utf8_enable");
+ for (int i = 0, n = strlen(s); i < n; ++i)
+ {
+ int c = str2chr(s, i);
+ switch (c)
+ {
+ case 0:
+ case 32: // space
+ break;
+ case 192: // charmap space
+ if (!utf8) break;
+ return false;
+ case 160: // space in unicode fonts
+ case 0xE000 + 192: // utf8 charmap space
+ if (utf8) break;
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+// Multiline text file buffers
+
+int buf_load(string pFilename)
+{
+ int buf = buf_create();
+ if (buf < 0) return -1;
+ int fh = fopen(pFilename, FILE_READ);
+ if (fh < 0)
+ {
+ buf_del(buf);
+ return -1;
+ }
+ string l;
+ for (int i = 0; (l = fgets(fh)); ++i)
+ bufstr_set(buf, i, l);
+ fclose(fh);
+ return buf;
+}
+
+void buf_save(float buf, string pFilename)
+{
+ int fh = fopen(pFilename, FILE_WRITE);
+ if (fh < 0) error(strcat("Can't write buf to ", pFilename));
+ int n = buf_getsize(buf);
+ for (int i = 0; i < n; ++i)
+ fputs(fh, strcat(bufstr_get(buf, i), "\n"));
+ fclose(fh);
+}
+
+/**
+ * converts a number to a string with the indicated number of decimals
+ * works for up to 10 decimals!
+ */
+string ftos_decimals(float number, int decimals)
+{
+ // inhibit stupid negative zero
+ if (number == 0) number = 0;
+ // we have sprintf...
+ return sprintf("%.*f", decimals, number);
+}
+
+int vercmp_recursive(string v1, string v2)
+{
+ int dot1 = strstrofs(v1, ".", 0);
+ int dot2 = strstrofs(v2, ".", 0);
+ string s1 = (dot1 == -1) ? v1 : substring(v1, 0, dot1);
+ string s2 = (dot2 == -1) ? v2 : substring(v2, 0, dot2);
+
+ float r;
+ r = stof(s1) - stof(s2);
+ if (r != 0) return r;
+
+ r = strcasecmp(s1, s2);
+ if (r != 0) return r;
+
+ if (dot1 == -1) return (dot2 == -1) ? 0 : -1;
+ else return (dot2 == -1) ? 1 : vercmp_recursive(substring(v1, dot1 + 1, 999), substring(v2, dot2 + 1, 999));
+}
+
+int vercmp(string v1, string v2)
{
- int l = 0;
- for (int i = 0, c; (c = str2chr(s, i)) > 0; ++i, ++l)
- {
- l += (c >= 0x80);
- l += (c >= 0x800);
- l += (c >= 0x10000);
- }
- return l;
+ if (strcasecmp(v1, v2) == 0) return 0; // early out check
+
+ // "git" beats all
+ if (v1 == "git") return 1;
+ if (v2 == "git") return -1;
+
+ return vercmp_recursive(v1, v2);
}
+const string HEXDIGITS = "0123456789ABCDEF0123456789abcdef";
+#define HEXDIGIT_TO_DEC_RAW(d) (strstrofs(HEXDIGITS, (d), 0))
+#define HEXDIGIT_TO_DEC(d) ((HEXDIGIT_TO_DEC_RAW(d) | 0x10) - 0x10)
+#define DEC_TO_HEXDIGIT(d) (substring(HEXDIGITS, (d), 1))
+
#endif
#define STRUCT_H
#ifndef QCC_SUPPORT_STRUCT
- #define _STRUCT_DECLARE(x, id, type, END) noref type x ##_## id ;
- #define STRUCT_DECLARE(id, s) s(_STRUCT_DECLARE, id)
+ #define _STRUCT_DECLARE(x, id, type, END) noref type x##_##id;
+ #define STRUCT_DECLARE(id, s) s(_STRUCT_DECLARE, id)
- #define _STRUCT_PARAM_(x, id, type) type x ##_## id ,
- #define _STRUCT_PARAM_END(x, id, type) type x ##_## id
- #define _STRUCT_PARAM(x, id, type, isend) _STRUCT_PARAM_##isend(x, id, type)
- #define STRUCT_PARAM(id, s) s(_STRUCT_PARAM, id)
+ #define _STRUCT_PARAM_(x, id, type) type x##_##id,
+ #define _STRUCT_PARAM_END(x, id, type) type x##_##id
+ #define _STRUCT_PARAM(x, id, type, isend) _STRUCT_PARAM_##isend(x, id, type)
+ #define STRUCT_PARAM(id, s) s(_STRUCT_PARAM, id)
- #define _STRUCT_PASS_(x, id, type) x ##_## id ,
- #define _STRUCT_PASS_END(x, id, type) x ##_## id
- #define _STRUCT_PASS(x, id, type, END) _STRUCT_PASS_##END(x, id, type)
- #define STRUCT_PASS(id, s) s(_STRUCT_PASS, id)
+ #define _STRUCT_PASS_(x, id, type) x##_##id,
+ #define _STRUCT_PASS_END(x, id, type) x##_##id
+ #define _STRUCT_PASS(x, id, type, END) _STRUCT_PASS_##END(x, id, type)
+ #define STRUCT_PASS(id, s) s(_STRUCT_PASS, id)
- #define _STRUCT_STORE_DST(_, it) it
- #define _STRUCT_STORE_SRC(it, _) it
- #define _CONCAT3_(a, b, c) a ## b ## c
- #define _CONCAT3(a, b, c) _CONCAT3_(a, b, c)
- #define _STRUCT_STORE(x, id, type, END) _CONCAT3(_STRUCT_STORE_DST x, _, id) = _CONCAT3(_STRUCT_STORE_SRC x, _, id);
- #define STRUCT_STORE(from, to, s) s(_STRUCT_STORE, (from, to))
+ #define _STRUCT_STORE_DST(_, it) it
+ #define _STRUCT_STORE_SRC(it, _) it
+ #define _CONCAT3_(a, b, c) a##b##c
+ #define _CONCAT3(a, b, c) _CONCAT3_(a, b, c)
+ #define _STRUCT_STORE(x, id, type, END) _CONCAT3(_STRUCT_STORE_DST x, _, id) = _CONCAT3(_STRUCT_STORE_SRC x, _, id);
+ #define STRUCT_STORE(from, to, s) s(_STRUCT_STORE, (from, to))
- #define STRUCT(id, ...)
+ #define STRUCT(id, ...)
#else
- #define STRUCT_DECLARE(id, type) type id;
- #define STRUCT_PARAM(id, type) type id
- #define STRUCT_PASS(id, type) id
- #define STRUCT_STORE(from, to, s) to = from
- #define _STRUCT_MEMBER(my, id, type, END) type id;
- #define STRUCT(id, s) struct STRUCT_##id { s(_STRUCT_MEMBER, ) };
+ #define STRUCT_DECLARE(id, type) type id;
+ #define STRUCT_PARAM(id, type) type id
+ #define STRUCT_PASS(id, type) id
+ #define STRUCT_STORE(from, to, s) to = from
+ #define _STRUCT_MEMBER(my, id, type, END) type id;
+ #define STRUCT(id, s) struct STRUCT_##id { s(_STRUCT_MEMBER, ) };
#endif
#endif
void TEST_Fail(string cond)
{
LOG_INFOF("Assertion failed: ", cond);
- //backtrace();
+ // backtrace();
++TEST_failed;
}
{
int f = 0;
float n = numentityfields();
- for(int i = 0; i < n; ++i)
+ for (int i = 0; i < n; ++i)
{
string name = entityfieldname(i);
- if(substring(name, 0, 6) == "_TEST_")
- if(!TEST_Run(substring(name, 6, -1)))
- ++f;
+ if (substring(name, 0, 6) == "_TEST_")
+ if (!TEST_Run(substring(name, 6, -1))) ++f;
}
- if(f)
+ if (f)
{
LOG_INFOF("%d tests failed\n", f);
return 1;
LOG_INFOF("%s: testing...\n", s);
TEST_failed = TEST_ok = 0;
callfunction(strcat("_TEST_", s));
- if(TEST_failed > 0)
+ if (TEST_failed > 0)
{
LOG_INFOF("%s: %d items failed.\n", s, TEST_failed);
return 0;
}
- else if(!TEST_ok)
+ else if (!TEST_ok)
{
LOG_INFOF("%s: did not complete.\n", s);
return 0;
#ifndef TEST_H
#define TEST_H
-#define TEST_Check(cond) do { if(!(cond)) TEST_Fail(#cond); } while(0)
+#define TEST_Check(cond) \
+ do \
+ { \
+ if (!(cond)) TEST_Fail( #cond); \
+ } \
+ while (0)
void TEST_OK();
void TEST_Fail(string cond);
float url_URI_Get_Callback(int id, float status, string data)
{
- if(id < MIN_URL_ID)
- return 0;
+ if (id < MIN_URL_ID) return 0;
id -= MIN_URL_ID;
- if(id >= NUM_URL_ID)
- return 0;
+ if (id >= NUM_URL_ID) return 0;
entity e;
e = url_fromid[id];
- if(!e)
- return 0;
- if(e.url_rbuf >= 0 || e.url_wbuf >= 0)
+ if (!e) return 0;
+ if (e.url_rbuf >= 0 || e.url_wbuf >= 0)
{
LOG_INFOF("WARNING: handle %d (%s) has already received data?!?\n", id + NUM_URL_ID, e.url_url);
return 0;
url_fromid[id] = NULL;
// if we get here, we MUST have both buffers cleared
- if(e.url_rbuf != -1 || e.url_wbuf != -1 || e.url_fh != URL_FH_CURL)
- error("url_URI_Get_Callback: not a request waiting for data");
+ if (e.url_rbuf != -1 || e.url_wbuf != -1 || e.url_fh != URL_FH_CURL) error("url_URI_Get_Callback: not a request waiting for data");
- if(status == 0)
+ if (status == 0)
{
// WE GOT DATA!
float n, i;
n = tokenizebyseparator(data, "\n");
e.url_rbuf = buf_create();
- if(e.url_rbuf < 0)
+ if (e.url_rbuf < 0)
{
LOG_INFO("url_URI_Get_Callback: out of memory in buf_create\n");
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
return 1;
}
e.url_rbufpos = 0;
- if(e.url_rbuf < 0)
+ if (e.url_rbuf < 0)
{
LOG_INFO("url_URI_Get_Callback: out of memory in buf_create\n");
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
remove(e);
return 1;
}
- for(i = 0; i < n; ++i)
+ for (i = 0; i < n; ++i)
bufstr_set(e.url_rbuf, i, argv(i));
e.url_ready(e, e.url_ready_pass, URL_READY_CANREAD);
return 1;
{
entity e;
int i;
- if(strstrofs(url, "://", 0) >= 0)
+ if (strstrofs(url, "://", 0) >= 0)
{
- switch(mode)
+ switch (mode)
{
case FILE_WRITE:
case FILE_APPEND:
// attempts to close will result in a reading handle
// create a writing end that does nothing yet
- e = spawn();
- e.classname = "url_single_fopen_file";
+ e = new(url_single_fopen_file);
+ make_pure(e);
e.url_url = strzone(url);
e.url_fh = URL_FH_CURL;
e.url_wbuf = buf_create();
- if(e.url_wbuf < 0)
+ if (e.url_wbuf < 0)
{
LOG_INFO("url_single_fopen: out of memory in buf_create\n");
rdy(e, pass, URL_READY_ERROR);
// read data only
// get slot for HTTP request
- for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
- if(url_fromid[i] == NULL)
- break;
- if(i >= NUM_URL_ID)
+ for (i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
+ if (url_fromid[i] == NULL) break;
+ if (i >= NUM_URL_ID)
{
- for(i = 0; i < autocvar__urllib_nextslot; ++i)
- if(url_fromid[i] == NULL)
- break;
- if(i >= autocvar__urllib_nextslot)
+ for (i = 0; i < autocvar__urllib_nextslot; ++i)
+ if (url_fromid[i] == NULL) break;
+ if (i >= autocvar__urllib_nextslot)
{
LOG_INFO("url_single_fopen: too many concurrent requests\n");
rdy(NULL, pass, URL_READY_ERROR);
}
// GET the data
- if(!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
+ if (!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
{
LOG_INFO("url_single_fopen: failure in crypto_uri_postbuf\n");
rdy(NULL, pass, URL_READY_ERROR);
// Make a dummy handle object (no buffers at
// all). Wait for data to come from the
// server, then call the callback
- e = spawn();
- e.classname = "url_single_fopen_file";
+ e = new(url_single_fopen_file);
+ make_pure(e);
e.url_url = strzone(url);
e.url_fh = URL_FH_CURL;
e.url_rbuf = -1;
break;
}
}
- else if(url == "-")
+ else if (url == "-")
{
- switch(mode)
+ switch (mode)
{
case FILE_WRITE:
case FILE_APPEND:
- e = spawn();
- e.classname = "url_single_fopen_stdout";
+ e = new(url_single_fopen_stdout);
+ make_pure(e);
e.url_fh = URL_FH_STDOUT;
e.url_ready = rdy;
e.url_ready_pass = pass;
{
float fh;
fh = fopen(url, mode);
- if(fh < 0)
+ if (fh < 0)
{
rdy(NULL, pass, URL_READY_ERROR);
return;
}
else
{
- e = spawn();
- e.classname = "url_single_fopen_file";
+ e = new(url_single_fopen_file);
+ make_pure(e);
e.url_fh = fh;
e.url_ready = rdy;
e.url_ready_pass = pass;
- if(mode == FILE_READ)
- rdy(e, pass, URL_READY_CANREAD);
- else
- rdy(e, pass, URL_READY_CANWRITE);
+ if (mode == FILE_READ) rdy(e, pass, URL_READY_CANREAD);
+ else rdy(e, pass, URL_READY_CANWRITE);
}
}
}
{
int i;
- if(e.url_fh == URL_FH_CURL)
+ if (e.url_fh == URL_FH_CURL)
{
- if(e.url_rbuf == -1 || e.url_wbuf != -1) // not(post GET/POST request)
- if(e.url_rbuf != -1 || e.url_wbuf == -1) // not(pre POST request)
- error("url_fclose: not closable in current state");
+ if (e.url_rbuf == -1 || e.url_wbuf != -1) // not(post GET/POST request)
+ if (e.url_rbuf != -1 || e.url_wbuf == -1) // not(pre POST request)
+ error("url_fclose: not closable in current state");
// closing an URL!
- if(e.url_wbuf >= 0)
+ if (e.url_wbuf >= 0)
{
// we are closing the write end (HTTP POST request)
// get slot for HTTP request
- for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
- if(url_fromid[i] == NULL)
- break;
- if(i >= NUM_URL_ID)
+ for (i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
+ if (url_fromid[i] == NULL) break;
+ if (i >= NUM_URL_ID)
{
- for(i = 0; i < autocvar__urllib_nextslot; ++i)
- if(url_fromid[i] == NULL)
- break;
- if(i >= autocvar__urllib_nextslot)
+ for (i = 0; i < autocvar__urllib_nextslot; ++i)
+ if (url_fromid[i] == NULL) break;
+ if (i >= autocvar__urllib_nextslot)
{
LOG_INFO("url_fclose: too many concurrent requests\n");
- e.url_ready(e,e.url_ready_pass, URL_READY_ERROR);
+ e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
buf_del(e.url_wbuf);
strunzone(e.url_url);
remove(e);
}
// POST the data
- if(!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
+ if (!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
{
LOG_INFO("url_fclose: failure in crypto_uri_postbuf\n");
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
remove(e);
}
}
- else if(e.url_fh == URL_FH_STDOUT)
+ else if (e.url_fh == URL_FH_STDOUT)
{
- e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
+ e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
remove(e);
}
else
{
// file
fclose(e.url_fh);
- e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
+ e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
remove(e);
}
}
// with \n (blame FRIK_FILE)
string url_fgets(entity e)
{
- if(e.url_fh == URL_FH_CURL)
+ if (e.url_fh == URL_FH_CURL)
{
- if(e.url_rbuf == -1)
- error("url_fgets: not readable in current state");
+ if (e.url_rbuf == -1) error("url_fgets: not readable in current state");
// curl
string s;
s = bufstr_get(e.url_rbuf, e.url_rbufpos);
e.url_rbufpos += 1;
return s;
}
- else if(e.url_fh == URL_FH_STDOUT)
+ else if (e.url_fh == URL_FH_STDOUT)
{
// stdout
return string_null;
// without \n (blame FRIK_FILE)
void url_fputs(entity e, string s)
{
- if(e.url_fh == URL_FH_CURL)
+ if (e.url_fh == URL_FH_CURL)
{
- if(e.url_wbuf == -1)
- error("url_fputs: not writable in current state");
+ if (e.url_wbuf == -1) error("url_fputs: not writable in current state");
// curl
bufstr_set(e.url_wbuf, e.url_wbufpos, s);
e.url_wbufpos += 1;
}
- else if(e.url_fh == URL_FH_STDOUT)
+ else if (e.url_fh == URL_FH_STDOUT)
{
// stdout
LOG_INFO(s);
void url_multi_ready(entity fh, entity me, float status)
{
float n;
- if(status == URL_READY_ERROR || status < 0)
+ if (status == URL_READY_ERROR || status < 0)
{
- if(status == -422) // Unprocessable Entity
+ if (status == -422) // Unprocessable Entity
{
LOG_INFO("uri_multi_ready: got HTTP error 422, data is in unusable format - not continuing\n");
me.url_ready(fh, me.url_ready_pass, status);
}
me.url_attempt += 1;
n = tokenize_console(me.url_url);
- if(n <= me.url_attempt)
+ if (n <= me.url_attempt)
{
me.url_ready(fh, me.url_ready_pass, status);
strunzone(me.url_url);
{
float n;
n = tokenize_console(url);
- if(n <= 0)
+ if (n <= 0)
{
LOG_INFO("url_multi_fopen: need at least one URL\n");
rdy(NULL, pass, URL_READY_ERROR);
return;
}
- entity me;
- me = spawn();
- me.classname = "url_multi";
+ entity me = new(url_multi);
+ make_pure(me);
me.url_url = strzone(url);
me.url_attempt = 0;
me.url_mode = mode;
const float URL_READY_CANWRITE = 1;
const float URL_READY_CANREAD = 2;
// errors: -1, or negative HTTP status code
-typedef void(entity handle, entity pass, float status) url_ready_func;
+typedef void (entity handle, entity pass, float status) url_ready_func;
void url_single_fopen(string url, float mode, url_ready_func rdy, entity pass);
void url_fclose(entity e);
#ifndef VECTOR_H
#define VECTOR_H
+#define cross(a, b) ((a) >< (b))
+/*
+vector cross(vector a, vector b)
+{
+ return
+ '1 0 0' * (a.y * b.z - a.z * b.y)
+ + '0 1 0' * (a.z * b.x - a.x * b.z)
+ + '0 0 1' * (a.x * b.y - a.y * b.x);
+}
+*/
+
const vector eX = '1 0 0';
const vector eY = '0 1 0';
const vector eZ = '0 0 1';
vector randompos(vector m1, vector m2)
{
- vector v;
- m2 = m2 - m1;
- v_x = m2_x * random() + m1_x;
- v_y = m2_y * random() + m1_y;
- v_z = m2_z * random() + m1_z;
- return v;
+ vector v;
+ m2 = m2 - m1;
+ v_x = m2_x * random() + m1_x;
+ v_y = m2_y * random() + m1_y;
+ v_z = m2_z * random() + m1_z;
+ return v;
}
float vlen2d(vector v)
{
- return sqrt(v.x * v.x + v.y * v.y);
+ return sqrt(v.x * v.x + v.y * v.y);
}
float vlen_maxnorm2d(vector v)
{
- return max(v.x, v.y, -v.x, -v.y);
+ return max(v.x, v.y, -v.x, -v.y);
}
float vlen_minnorm2d(vector v)
{
- return min(max(v.x, -v.x), max(v.y, -v.y));
+ return min(max(v.x, -v.x), max(v.y, -v.y));
}
float dist_point_line(vector p, vector l0, vector ldir)
{
- ldir = normalize(ldir);
+ ldir = normalize(ldir);
- // remove the component in line direction
- p = p - (p * ldir) * ldir;
+ // remove the component in line direction
+ p = p - (p * ldir) * ldir;
- // vlen of the remaining vector
- return vlen(p);
+ // vlen of the remaining vector
+ return vlen(p);
}
/** requires that m2>m1 in all coordinates, and that m4>m3 */
-float boxesoverlap(vector m1, vector m2, vector m3, vector m4) {return m2_x >= m3_x && m1_x <= m4_x && m2_y >= m3_y && m1_y <= m4_y && m2_z >= m3_z && m1_z <= m4_z;}
+float boxesoverlap(vector m1, vector m2, vector m3, vector m4) { return m2_x >= m3_x && m1_x <= m4_x && m2_y >= m3_y && m1_y <= m4_y && m2_z >= m3_z && m1_z <= m4_z; }
/** requires the same as boxesoverlap, but is a stronger condition */
-float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) {return smins.x >= bmins.x && smaxs.x <= bmaxs.x && smins.y >= bmins.y && smaxs.y <= bmaxs.y && smins.z >= bmins.z && smaxs.z <= bmaxs.z;}
+float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) { return smins.x >= bmins.x && smaxs.x <= bmaxs.x && smins.y >= bmins.y && smaxs.y <= bmaxs.y && smins.z >= bmins.z && smaxs.z <= bmaxs.z; }
vector vec2(vector v)
{
- v.z = 0;
- return v;
+ v.z = 0;
+ return v;
}
vector vec3(float x, float y, float z)
{
- vector v; v.x = x; v.y = y; v.z = z;
- return v;
+ vector v;
+ v.x = x;
+ v.y = y;
+ v.z = z;
+ return v;
}
-#ifndef MENUQC
-vector get_corner_position(entity box, int corner)
+vector rotate(vector v, float a)
{
- switch (corner) {
- case 1: return vec3(box.absmin.x, box.absmin.y, box.absmin.z);
- case 2: return vec3(box.absmax.x, box.absmin.y, box.absmin.z);
- case 3: return vec3(box.absmin.x, box.absmax.y, box.absmin.z);
- case 4: return vec3(box.absmin.x, box.absmin.y, box.absmax.z);
- case 5: return vec3(box.absmax.x, box.absmax.y, box.absmin.z);
- case 6: return vec3(box.absmin.x, box.absmax.y, box.absmax.z);
- case 7: return vec3(box.absmax.x, box.absmin.y, box.absmax.z);
- case 8: return vec3(box.absmax.x, box.absmax.y, box.absmax.z);
- default: return '0 0 0';
- }
+ float a_sin = sin(a), a_cos = cos(a);
+ vector r = '0 0 0';
+ r.x = v.x * a_cos + v.y * a_sin;
+ r.y = -1 * v.x * a_sin + v.y * a_cos;
+ return r;
}
-vector NearestPointOnBox(entity box, vector org)
+vector yinvert(vector v)
{
- vector m1 = box.mins + box.origin;
- vector m2 = box.maxs + box.origin;
-
- vector ret;
- ret.x = bound(m1.x, org.x, m2.x);
- ret.y = bound(m1.y, org.y, m2.y);
- ret.z = bound(m1.z, org.z, m2.z);
- return ret;
+ v.y = 1 - v.y;
+ return v;
}
+
+#ifndef MENUQC
+ vector get_corner_position(entity box, int corner)
+ {
+ switch (corner)
+ {
+ case 1: return vec3(box.absmin.x, box.absmin.y, box.absmin.z);
+ case 2: return vec3(box.absmax.x, box.absmin.y, box.absmin.z);
+ case 3: return vec3(box.absmin.x, box.absmax.y, box.absmin.z);
+ case 4: return vec3(box.absmin.x, box.absmin.y, box.absmax.z);
+ case 5: return vec3(box.absmax.x, box.absmax.y, box.absmin.z);
+ case 6: return vec3(box.absmin.x, box.absmax.y, box.absmax.z);
+ case 7: return vec3(box.absmax.x, box.absmin.y, box.absmax.z);
+ case 8: return vec3(box.absmax.x, box.absmax.y, box.absmax.z);
+ default: return '0 0 0';
+ }
+ }
+
+ vector NearestPointOnBox(entity box, vector org)
+ {
+ vector m1 = box.mins + box.origin;
+ vector m2 = box.maxs + box.origin;
+
+ vector ret;
+ ret.x = bound(m1.x, org.x, m2.x);
+ ret.y = bound(m1.y, org.y, m2.y);
+ ret.z = bound(m1.z, org.z, m2.z);
+ return ret;
+ }
#endif
#endif
self.drawmask = MASK_NORMAL;
}
-void WarpZone_Read(float isnew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_WARPZONE, bool isnew)
+{
warpzone_warpzones_exist = 1;
if (!self.enemy)
{
- self.enemy = spawn();
- self.enemy.classname = "warpzone_from";
+ self.enemy = new(warpzone_from);
}
self.classname = "trigger_warpzone";
// how to draw
// engine currently wants this
self.predraw = WarpZone_Fade_PreDraw;
+ return true;
}
-void WarpZone_Camera_Read(float isnew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_WARPZONE_CAMERA, bool isnew)
+{
warpzone_cameras_exist = 1;
self.classname = "func_warpzone_camera";
// how to draw
// engine currently wants this
self.predraw = WarpZone_Fade_PreDraw;
+ return true;
}
void CL_RotateMoves(vector ang) = #638;
-void WarpZone_Teleported_Read(float isnew)
-{SELFPARAM();
- vector v;
+NET_HANDLE(ENT_CLIENT_WARPZONE_TELEPORTED, bool isnew)
+{
self.classname = "warpzone_teleported";
+ vector v;
v.x = ReadCoord();
v.y = ReadCoord();
v.z = ReadCoord();
- if(!isnew)
- return;
+ return = true;
+ if (!isnew) return;
self.warpzone_transform = v;
setproperty(VF_CL_VIEWANGLES, WarpZone_TransformVAngles(self, getpropertyvec(VF_CL_VIEWANGLES)));
if(checkextension("DP_CSQC_ROTATEMOVES"))
setproperty(VF_ORIGIN, org + o);
}
-void WarpZone_Init()
-{
-}
-
void WarpZone_Shutdown()
{
WarpZone_View_Outside();
#ifndef LIB_WARPZONE_CLIENT_H
#define LIB_WARPZONE_CLIENT_H
-void WarpZone_Read(float bIsNewEntity);
-void WarpZone_Camera_Read(float bIsNewEntity);
-void WarpZone_Teleported_Read(float bIsNewEntity);
-
void WarpZone_FixPMove();
void WarpZone_FixView();
-void WarpZone_Init();
void WarpZone_Shutdown();
vector warpzone_save_view_origin;
{
if(!WarpZone_trace_transform)
{
- WarpZone_trace_transform = spawn();
- WarpZone_trace_transform.classname = "warpzone_trace_transform";
+ WarpZone_trace_transform = new(warpzone_trace_transform);
+ make_pure(WarpZone_trace_transform);
}
WarpZone_Accumulator_Clear(WarpZone_trace_transform);
}
float WarpZone_TrailParticles_trace_callback_eff;
void WarpZone_TrailParticles_trace_callback(vector from, vector endpos, vector to)
{
- trailparticles(WarpZone_TrailParticles_trace_callback_own, WarpZone_TrailParticles_trace_callback_eff, from, endpos);
+ __trailparticles(WarpZone_TrailParticles_trace_callback_own, WarpZone_TrailParticles_trace_callback_eff, from, endpos);
}
void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
bool WarpZoneLib_BadEntity(entity e)
{
- string myclassname = e.classname;
- if (e.instanceOfObject) return true;
- switch(myclassname)
+ string s = e.classname;
+ if (is_pure(e)) return true;
+ switch (s)
{
- case "deathtype":
- case "weaponentity":
- case "exteriorweaponentity":
- case "csqc_score_team":
- case "pingplreport":
- case "ent_client_scoreinfo":
- case "saved_cvar_value":
- case "accuracy":
case "entcs_sender":
case "entcs_receiver":
- case "clientinit":
- case "sprite_waypoint":
- case "waypoint":
- case "gibsplash":
- //case "net_linked": // actually some real entities are linked without classname, fail
+ // case "net_linked": // actually some real entities are linked without classname, fail
case "":
return true;
}
- if(startsWith(myclassname, "msg_"))
- return true;
-
- if(startsWith(myclassname, "target_"))
- return true;
+ if (startsWith(s, "target_")) return true;
- if(startsWith(myclassname, "info_"))
- return true;
+ if (startsWith(s, "info_")) return true;
return false;
}
{
if(me.WarpZone_refsys.owner != me)
{
- me.WarpZone_refsys = spawn();
- me.WarpZone_refsys.classname = "warpzone_refsys";
+ me.WarpZone_refsys = new(warpzone_refsys);
me.WarpZone_refsys.owner = me;
me.WarpZone_refsys.think = WarpZone_RefSys_GC;
me.WarpZone_refsys.nextthink = time + 1;
{
return !(x < y || x == y || x > y);
}
-
-vector cross(vector a, vector b)
-{
- return
- '1 0 0' * (a.y * b.z - a.z * b.y)
- + '0 1 0' * (a.z * b.x - a.x * b.z)
- + '0 0 1' * (a.x * b.y - a.y * b.x);
-}
const float M_SQRT2 = 1.41421356237309504880; /* sqrt(2) */
const float M_SQRT1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
-// Non-<math.h> stuff follows here.
-vector cross(vector a, vector b);
-
#endif
bool WarpZone_Teleported_Send(entity to, int sf)
{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
WriteCoord(MSG_ENTITY, self.angles.x);
WriteCoord(MSG_ENTITY, self.angles.y);
WriteCoord(MSG_ENTITY, self.angles.z);
// instead of fixangle, send the transform to the client for smoother operation
player.fixangle = false;
- entity ts = spawn();
+ entity ts = new(warpzone_teleported);
setmodel(ts, MDL_Null);
ts.SendEntity = WarpZone_Teleported_Send;
ts.SendFlags = 0xFFFFFF;
ts.owner = player;
ts.enemy = wz;
ts.effects = EF_NODEPTHTEST;
- ts.classname = "warpzone_teleported";
ts.angles = wz.warpzone_transform;
}
#endif
return 1;
}
-void WarpZone_Touch (void)
+void WarpZone_Touch ()
{SELFPARAM();
if(other.classname == "trigger_warpzone")
return;
bool WarpZone_Send(entity to, int sendflags)
{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_WARPZONE);
// we must send this flag for clientside to match properly too
int f = 0;
bool WarpZone_Camera_Send(entity to, int sendflags)
{SELFPARAM();
int f = 0;
- WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA);
if(self.warpzone_fadestart)
BITSET_ASSIGN(f, 2);
self.enemy.aiment = self;
}
-void WarpZoneCamera_Think(void)
+void WarpZoneCamera_Think()
{SELFPARAM();
if(self.warpzone_save_origin != self.origin
|| self.warpzone_save_angles != self.angles
spawnfunc_trigger_warpzone_reconnect(this); // both names make sense here :(
}
-void WarpZone_PlayerPhysics_FixVAngle(void)
+void WarpZone_PlayerPhysics_FixVAngle()
{SELFPARAM();
#ifndef WARPZONE_DONT_FIX_VANGLE
if(IS_REAL_CLIENT(self))
//const float ENT_CLIENT_WARPZONE;
//const float ENT_CLIENT_WARPZONE_CAMERA;
-void WarpZone_PlayerPhysics_FixVAngle(void);
+void WarpZone_PlayerPhysics_FixVAngle();
-void WarpZone_PostInitialize_Callback(void);
+void WarpZone_PostInitialize_Callback();
#endif
#ifndef ANIM_ANIMATION_H
-#define ANIM_ANIMATION_H
-void setterDummy(entity, float);
-CLASS(Animation, Object)
- METHOD(Animation, configureAnimation, void(entity, entity, void(entity, float), float, float, float, float));
- METHOD(Animation, update, void(entity, float, float, float));
- METHOD(Animation, setTimeStartEnd, void(entity, float, float));
- METHOD(Animation, setTimeStartDuration, void(entity, float, float));
- METHOD(Animation, setValueStartEnd, void(entity, float, float));
- METHOD(Animation, setValueStartDelta, void(entity, float, float));
- METHOD(Animation, setObjectSetter, void(entity, entity, void(entity, float)));
- METHOD(Animation, tick, void(entity, float));
- METHOD(Animation, calcValue, float(entity, float, float, float, float));
- METHOD(Animation, isStopped, float(entity));
- METHOD(Animation, stopAnim, void(entity));
- METHOD(Animation, resumeAnim, void(entity));
- METHOD(Animation, isFinished, float(entity));
- METHOD(Animation, finishAnim, void(entity));
- ATTRIB(Animation, object, entity, NULL)
- ATTRIB(Animation, setter, void(entity, float), setterDummy)
- ATTRIB(Animation, value, float, 0)
- ATTRIB(Animation, startTime, float, 0)
- ATTRIB(Animation, duration, float, 0)
- ATTRIB(Animation, startValue, float, 0)
- ATTRIB(Animation, delta, float, 0)
- ATTRIB(Animation, stopped, float, false)
- ATTRIB(Animation, finished, float, false)
-ENDCLASS(Animation)
+ #define ANIM_ANIMATION_H
+ CLASS(Animation, Object)
+ METHOD(Animation, configureAnimation, void(entity, entity, void(entity, float), float, float, float, float));
+ METHOD(Animation, update, void(entity, float, float, float));
+ METHOD(Animation, setTimeStartEnd, void(entity, float, float));
+ METHOD(Animation, setTimeStartDuration, void(entity, float, float));
+ METHOD(Animation, setValueStartEnd, void(entity, float, float));
+ METHOD(Animation, setValueStartDelta, void(entity, float, float));
+ METHOD(Animation, setObjectSetter, void(entity, entity, void(entity, float)));
+ METHOD(Animation, tick, void(entity, float));
+ METHOD(Animation, calcValue, float(entity, float, float, float, float));
+ METHOD(Animation, isStopped, float(entity));
+ METHOD(Animation, stopAnim, void(entity));
+ METHOD(Animation, resumeAnim, void(entity));
+ METHOD(Animation, isFinished, float(entity));
+ METHOD(Animation, finishAnim, void(entity));
+ ATTRIB(Animation, object, entity, NULL)
+ void setterDummy(entity, float) {}
+ ATTRIB(Animation, setter, void(entity, float), setterDummy)
+ ATTRIB(Animation, value, float, 0)
+ ATTRIB(Animation, startTime, float, 0)
+ ATTRIB(Animation, duration, float, 0)
+ ATTRIB(Animation, startValue, float, 0)
+ ATTRIB(Animation, delta, float, 0)
+ ATTRIB(Animation, stopped, float, false)
+ ATTRIB(Animation, finished, float, false)
+ ENDCLASS(Animation)
#endif
#ifdef IMPLEMENTATION
-void Animation_configureAnimation(entity me, entity obj, void(entity, float) objSetter, float animStartTime, float animDuration, float animStartValue, float animEndValue)
-{
- me.setObjectSetter(me, obj, objSetter);
- me.setTimeStartDuration(me, animStartTime, animDuration);
- me.setValueStartEnd(me, animStartValue, animEndValue);
-}
-
-void Animation_update(entity me, float animDuration, float animStartValue, float animEndValue)
-{
- me.setTimeStartDuration(me, time, animDuration);
- me.setValueStartEnd(me, animStartValue, animEndValue);
-}
-
-void Animation_setTimeStartEnd(entity me, float s, float e)
-{
- me.startTime = s;
- me.duration = e - s;
-}
-
-void Animation_setTimeStartDuration(entity me, float s, float d)
-{
- me.startTime = s;
- me.duration = d;
-}
-
-void Animation_setValueStartEnd(entity me, float s, float e)
-{
- me.startValue = s;
- me.delta = e - s;
-}
-
-void Animation_setValueStartDelta(entity me, float s, float d)
-{
- me.startValue = s;
- me.delta = d;
-}
-
-void Animation_setObjectSetter(entity me, entity o, void(entity, float) s)
-{
- me.object = o;
- me.setter = s;
-}
-
-void Animation_tick(entity me, float tickTime)
-{
- if (me.isStopped(me) || me.isFinished(me) || (tickTime < me.startTime))
- return;
-
- if (tickTime >= (me.startTime + me.duration))
- me.finishAnim(me);
- else
- me.value = me.calcValue(me, (tickTime - me.startTime), me.duration, me.startValue, me.delta);
-
- me.setter(me.object, me.value);
-}
-
-float Animation_calcValue(entity me, float tickTime, float animDuration, float animStartValue, float animDelta)
-{
- return animStartValue;
-}
-
-float Animation_isStopped(entity me)
-{
- return me.stopped;
-}
-
-void Animation_stopAnim(entity me)
-{
- me.stopped = true;
-}
-
-void Animation_resumeAnim(entity me)
-{
- me.stopped = false;
-}
-
-float Animation_isFinished(entity me)
-{
- return me.finished;
-}
-
-void Animation_finishAnim(entity me)
-{
- me.value = me.delta + me.startValue;
- me.finished = true;
- me.setter(me.object, me.value);
-}
-
-void setterDummy(entity obj, float objValue)
-{
-}
+ METHOD(Animation, configureAnimation, void(entity this, entity obj, void(entity, float) objSetter, float animStartTime, float animDuration, float animStartValue, float animEndValue))
+ {
+ this.setObjectSetter(this, obj, objSetter);
+ this.setTimeStartDuration(this, animStartTime, animDuration);
+ this.setValueStartEnd(this, animStartValue, animEndValue);
+ }
+
+ METHOD(Animation, update, void(entity this, float animDuration, float animStartValue, float animEndValue))
+ {
+ this.setTimeStartDuration(this, time, animDuration);
+ this.setValueStartEnd(this, animStartValue, animEndValue);
+ }
+
+ METHOD(Animation, setTimeStartEnd, void(entity this, float s, float e))
+ {
+ this.startTime = s;
+ this.duration = e - s;
+ }
+
+ METHOD(Animation, setTimeStartDuration, void(entity this, float s, float d))
+ {
+ this.startTime = s;
+ this.duration = d;
+ }
+
+ METHOD(Animation, setValueStartEnd, void(entity this, float s, float e))
+ {
+ this.startValue = s;
+ this.delta = e - s;
+ }
+
+ METHOD(Animation, setValueStartDelta, void(entity this, float s, float d))
+ {
+ this.startValue = s;
+ this.delta = d;
+ }
+
+ METHOD(Animation, setObjectSetter, void(entity this, entity o, void(entity, float) s))
+ {
+ this.object = o;
+ this.setter = s;
+ }
+
+ METHOD(Animation, tick, void(entity this, float tickTime))
+ {
+ if (this.isStopped(this) || this.isFinished(this) || (tickTime < this.startTime)) return;
+
+ if (tickTime >= (this.startTime + this.duration)) this.finishAnim(this);
+ else this.value = this.calcValue(this, (tickTime - this.startTime), this.duration, this.startValue, this.delta);
+
+ this.setter(this.object, this.value);
+ }
+
+ METHOD(Animation, calcValue, float(entity this, float tickTime, float animDuration, float animStartValue, float animDelta))
+ {
+ return animStartValue;
+ }
+
+ METHOD(Animation, isStopped, bool(entity this))
+ {
+ return this.stopped;
+ }
+
+ METHOD(Animation, stopAnim, void(entity this))
+ {
+ this.stopped = true;
+ }
+
+ METHOD(Animation, resumeAnim, void(entity this))
+ {
+ this.stopped = false;
+ }
+
+ METHOD(Animation, isFinished, bool(entity this))
+ {
+ return this.finished;
+ }
+
+ METHOD(Animation, finishAnim, void(entity this))
+ {
+ this.value = this.delta + this.startValue;
+ this.finished = true;
+ this.setter(this.object, this.value);
+ }
#endif
#include "../menu.qh"
#ifndef ANIM_ANIMHOST_H
-#define ANIM_ANIMHOST_H
-CLASS(AnimHost, Object)
- METHOD(AnimHost, addAnim, void(entity, entity));
- METHOD(AnimHost, removeAnim, void(entity, entity));
- METHOD(AnimHost, removeAllAnim, void(entity));
- METHOD(AnimHost, removeObjAnim, void(entity, entity));
- METHOD(AnimHost, stopAllAnim, void(entity));
- METHOD(AnimHost, stopObjAnim, void(entity, entity));
- METHOD(AnimHost, resumeAllAnim, void(entity));
- METHOD(AnimHost, resumeObjAnim, void(entity, entity));
- METHOD(AnimHost, finishAllAnim, void(entity));
- METHOD(AnimHost, finishObjAnim, void(entity, entity));
- METHOD(AnimHost, tickAll, void(entity));
- ATTRIB(AnimHost, firstChild, entity, NULL)
- ATTRIB(AnimHost, lastChild, entity, NULL)
-ENDCLASS(AnimHost)
-.entity nextSibling;
-.entity prevSibling;
+ #define ANIM_ANIMHOST_H
+ CLASS(AnimHost, Object)
+ METHOD(AnimHost, addAnim, void(entity, entity));
+ METHOD(AnimHost, removeAnim, void(entity, entity));
+ METHOD(AnimHost, removeAllAnim, void(entity));
+ METHOD(AnimHost, removeObjAnim, void(entity, entity));
+ METHOD(AnimHost, stopAllAnim, void(entity));
+ METHOD(AnimHost, stopObjAnim, void(entity, entity));
+ METHOD(AnimHost, resumeAllAnim, void(entity));
+ METHOD(AnimHost, resumeObjAnim, void(entity, entity));
+ METHOD(AnimHost, finishAllAnim, void(entity));
+ METHOD(AnimHost, finishObjAnim, void(entity, entity));
+ METHOD(AnimHost, tickAll, void(entity));
+ ATTRIB(AnimHost, firstChild, entity, NULL)
+ ATTRIB(AnimHost, lastChild, entity, NULL)
+ ENDCLASS(AnimHost)
+ .entity nextSibling;
+ .entity prevSibling;
#endif
#ifdef IMPLEMENTATION
-void AnimHost_addAnim(entity me, entity other)
-{
- if(other.parent)
- error("Can't add already added anim!");
-
- if(other.isFinished(other))
- error("Can't add finished anim!");
-
- other.parent = me;
-
- entity l;
- l = me.lastChild;
-
- if(l)
- l.nextSibling = other;
- else
- me.firstChild = other;
-
- other.prevSibling = l;
- other.nextSibling = NULL;
- me.lastChild = other;
-}
-
-void AnimHost_removeAnim(entity me, entity other)
-{
- if(other.parent != me)
- error("Can't remove from wrong AnimHost!");
-
- other.parent = NULL;
-
- entity n, p;
- n = other.nextSibling;
- p = other.prevSibling;
-
- if(p)
- p.nextSibling = n;
- else
- me.firstChild = n;
-
- if(n)
- n.prevSibling = p;
- else
- me.lastChild = p;
- remove(other);
-}
-
-void AnimHost_removeAllAnim(entity me)
-{
- entity e, tmp;
- for(e = me.firstChild; e; e = e.nextSibling)
+ METHOD(AnimHost, addAnim, void(entity this, entity other))
{
- tmp = e;
- e = tmp.prevSibling;
- me.removeAnim(me, tmp);
+ if (other.parent) error("Can't add already added anim!");
+
+ if (other.isFinished(other)) error("Can't add finished anim!");
+
+ other.parent = this;
+
+ entity l = this.lastChild;
+
+ if (l) l.nextSibling = other;
+ else this.firstChild = other;
+
+ other.prevSibling = l;
+ other.nextSibling = NULL;
+ this.lastChild = other;
+ }
+
+ METHOD(AnimHost, removeAnim, void(entity this, entity other))
+ {
+ if (other.parent != this) error("Can't remove from wrong AnimHost!");
+
+ other.parent = NULL;
+
+ entity n = other.nextSibling;
+ entity p = other.prevSibling;
+
+ if (p) p.nextSibling = n;
+ else this.firstChild = n;
+
+ if (n) n.prevSibling = p;
+ else this.lastChild = p;
+ remove(other);
}
-}
-void AnimHost_removeObjAnim(entity me, entity obj)
-{
- entity e, tmp;
- for(e = me.firstChild; e; e = e.nextSibling)
+ METHOD(AnimHost, removeAllAnim, void(entity this))
{
- if (e.object == obj)
+ for (entity e = this.firstChild; e; e = e.nextSibling)
{
- tmp = e;
+ entity tmp = e;
e = tmp.prevSibling;
- me.removeAnim(me, tmp);
+ this.removeAnim(this, tmp);
}
}
-}
-void AnimHost_stopAllAnim(entity me)
-{
- entity e;
- for(e = me.firstChild; e; e = e.nextSibling)
+ METHOD(AnimHost, removeObjAnim, void(entity this, entity obj))
{
- e.stopAnim(e);
+ for (entity e = this.firstChild; e; e = e.nextSibling)
+ {
+ if (e.object == obj)
+ {
+ entity tmp = e;
+ e = tmp.prevSibling;
+ this.removeAnim(this, tmp);
+ }
+ }
}
-}
-void AnimHost_stopObjAnim(entity me, entity obj)
-{
- entity e;
- for(e = me.firstChild; e; e = e.nextSibling)
+ METHOD(AnimHost, stopAllAnim, void(entity this))
{
- if (e.object == obj)
- {
+ for (entity e = this.firstChild; e; e = e.nextSibling)
e.stopAnim(e);
- }
}
-}
-void AnimHost_resumeAllAnim(entity me)
-{
- entity e;
- for(e = me.firstChild; e; e = e.nextSibling)
+ METHOD(AnimHost, stopObjAnim, void(entity this, entity obj))
{
- e.resumeAnim(e);
+ for (entity e = this.firstChild; e; e = e.nextSibling)
+ if (e.object == obj) e.stopAnim(e);
}
-}
-void AnimHost_resumeObjAnim(entity me, entity obj)
-{
- entity e;
- for(e = me.firstChild; e; e = e.nextSibling)
+ METHOD(AnimHost, resumeAllAnim, void(entity this))
{
- if (e.object == obj)
- {
+ for (entity e = this.firstChild; e; e = e.nextSibling)
e.resumeAnim(e);
- }
}
-}
-void AnimHost_finishAllAnim(entity me)
-{
- entity e, tmp;
- for(e = me.firstChild; e; e = e.nextSibling)
+ METHOD(AnimHost, resumeObjAnim, void(entity this, entity obj))
{
- tmp = e;
- e = tmp.prevSibling;
- tmp.finishAnim(tmp);
+ for (entity e = this.firstChild; e; e = e.nextSibling)
+ if (e.object == obj) e.resumeAnim(e);
}
-}
-void AnimHost_finishObjAnim(entity me, entity obj)
-{
- entity e, tmp;
- for(e = me.firstChild; e; e = e.nextSibling)
+ METHOD(AnimHost, finishAllAnim, void(entity this))
{
- if (e.object == obj)
+ for (entity e = this.firstChild; e; e = e.nextSibling)
{
- tmp = e;
+ entity tmp = e;
e = tmp.prevSibling;
tmp.finishAnim(tmp);
}
}
-}
-void AnimHost_tickAll(entity me)
-{
- entity e, tmp;
- for(e = me.firstChild; e; e = e.nextSibling)
+ METHOD(AnimHost, finishObjAnim, void(entity this, entity obj))
{
- e.tick(e, time);
- if (e.isFinished(e))
+ for (entity e = this.firstChild; e; e = e.nextSibling)
{
- tmp = e;
- e = tmp.prevSibling;
- me.removeAnim(me, tmp);
+ if (e.object == obj)
+ {
+ entity tmp = e;
+ e = tmp.prevSibling;
+ tmp.finishAnim(tmp);
+ }
+ }
+ }
+
+ METHOD(AnimHost, tickAll, void(entity this))
+ {
+ for (entity e = this.firstChild; e; e = e.nextSibling)
+ {
+ e.tick(e, time);
+ if (e.isFinished(e))
+ {
+ entity tmp = e;
+ e = tmp.prevSibling;
+ this.removeAnim(this, tmp);
+ }
}
}
-}
#endif
#ifndef ANIM_EASING_H
-#define ANIM_EASING_H
-#include "animation.qc"
-entity makeHostedEasing(entity, void(entity, float), float(float, float, float, float), float, float, float);
-entity makeEasing(entity, void(entity, float), float(float, float, float, float), float, float, float, float);
-float easingLinear(float, float, float, float);
-float easingQuadIn(float, float, float, float);
-float easingQuadOut(float, float, float, float);
-float easingQuadInOut(float, float, float, float);
-CLASS(Easing, Animation)
- METHOD(Easing, calcValue, float(entity, float, float, float, float));
- METHOD(Easing, setMath, void(entity, float(float, float, float, float)));
- ATTRIB(Easing, math, float(float, float, float, float), easingLinear)
-ENDCLASS(Easing)
+ #define ANIM_EASING_H
+ #include "animation.qc"
+ entity makeHostedEasing(entity, void(entity, float), float(float, float, float, float), float, float, float);
+ entity makeEasing(entity, void(entity, float), float(float, float, float, float), float, float, float, float);
+ float easingLinear(float, float, float, float);
+ float easingQuadIn(float, float, float, float);
+ float easingQuadOut(float, float, float, float);
+ float easingQuadInOut(float, float, float, float);
+ CLASS(Easing, Animation)
+ METHOD(Easing, calcValue, float(entity, float, float, float, float));
+ METHOD(Easing, setMath, void(entity, float(float, float, float, float)));
+ ATTRIB(Easing, math, float(float, float, float, float), easingLinear)
+ ENDCLASS(Easing)
#endif
#ifdef IMPLEMENTATION
-entity makeHostedEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animDuration, float animStartValue, float animEnd)
-{
- entity me;
- me = makeEasing(obj, objSetter, func, time, animDuration, animStartValue, animEnd);
- anim.addAnim(anim, me);
- return me;
-}
-
-entity makeEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animStartTime, float animDuration, float animStartValue, float animEnd)
-{
- entity me;
- me = NEW(Easing);
- me.configureAnimation(me, obj, objSetter, animStartTime, animDuration, animStartValue, animEnd);
- me.setMath(me, func);
- return me;
-}
+ entity makeHostedEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animDuration, float animStartValue, float animEnd)
+ {
+ entity this = makeEasing(obj, objSetter, func, time, animDuration, animStartValue, animEnd);
+ anim.addAnim(anim, this);
+ return this;
+ }
-float Easing_calcValue(entity me, float tickTime, float animDuration, float animStart, float animDelta)
-{
- return me.math(tickTime, animDuration, animStart, animDelta);
-}
+ entity makeEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animStartTime, float animDuration, float animStartValue, float animEnd)
+ {
+ entity this = NEW(Easing);
+ this.configureAnimation(this, obj, objSetter, animStartTime, animDuration, animStartValue, animEnd);
+ this.setMath(this, func);
+ return this;
+ }
-void Easing_setMath(entity me, float(float, float, float, float) func)
-{
- me.math = func;
-}
+ METHOD(Easing, calcValue, float(entity this, float tickTime, float animDuration, float animStart, float animDelta))
+ {
+ return this.math(tickTime, animDuration, animStart, animDelta);
+ }
-float easingLinear(float tickTime, float animDuration, float animStart, float animDelta)
-{
- return (animDelta * (tickTime / animDuration)) + animStart;
-}
+ METHOD(Easing, setMath, void(entity this, float(float, float, float, float) func))
+ {
+ this.math = func;
+ }
-float easingQuadIn(float tickTime, float animDuration, float animStart, float animDelta)
-{
- float frac = tickTime / animDuration;
- return (animDelta * frac * frac) + animStart;
-}
+ float easingLinear(float tickTime, float animDuration, float animStart, float animDelta)
+ {
+ return (animDelta * (tickTime / animDuration)) + animStart;
+ }
-float easingQuadOut(float tickTime, float animDuration, float animStart, float animDelta)
-{
- float frac = tickTime / animDuration;
- return (-animDelta * frac * (frac - 2)) + animStart;
-}
+ float easingQuadIn(float tickTime, float animDuration, float animStart, float animDelta)
+ {
+ float frac = tickTime / animDuration;
+ return (animDelta * frac * frac) + animStart;
+ }
-float easingQuadInOut(float tickTime, float animDuration, float animStart, float animDelta)
-{
- if (tickTime < (animDuration / 2))
+ float easingQuadOut(float tickTime, float animDuration, float animStart, float animDelta)
{
- return easingQuadIn(tickTime, (animDuration / 2), animStart, (animDelta / 2));
+ float frac = tickTime / animDuration;
+ return (-animDelta * frac * (frac - 2)) + animStart;
}
- else
+
+ float easingQuadInOut(float tickTime, float animDuration, float animStart, float animDelta)
{
- return easingQuadOut((tickTime - (animDuration / 2)), (animDuration / 2), (animStart + (animDelta / 2)), (animDelta / 2));
+ if (tickTime < (animDuration / 2)) return easingQuadIn(tickTime, (animDuration / 2), animStart, (animDelta / 2));
+ else return easingQuadOut((tickTime - (animDuration / 2)), (animDuration / 2), (animStart + (animDelta / 2)), (animDelta / 2));
}
-}
#endif
#ifndef ANIM_KEYFRAME_H
-#define ANIM_KEYFRAME_H
-#include "animation.qc"
-CLASS(Keyframe, Animation)
- METHOD(Keyframe, addEasing, entity(entity, float, float, float(float, float, float, float)));
- METHOD(Keyframe, addAnim, void(entity, entity));
- METHOD(Keyframe, calcValue, float(entity, float, float, float, float));
- ATTRIB(Keyframe, currentChild, entity, NULL)
- ATTRIB(Keyframe, firstChild, entity, NULL)
- ATTRIB(Keyframe, lastChild, entity, NULL)
-ENDCLASS(Keyframe)
-entity makeHostedKeyframe(entity, void(entity, float), float, float, float);
-entity makeKeyframe(entity, void(entity, float), float, float, float);
-float getNewChildStart(entity);
-float getNewChildDuration(entity, float);
-float getNewChildValue(entity);
+ #define ANIM_KEYFRAME_H
+ #include "animation.qc"
+ CLASS(Keyframe, Animation)
+ METHOD(Keyframe, addEasing, entity(entity, float, float, float(float, float, float, float)));
+ METHOD(Keyframe, addAnim, void(entity, entity));
+ METHOD(Keyframe, calcValue, float(entity, float, float, float, float));
+ ATTRIB(Keyframe, currentChild, entity, NULL)
+ ATTRIB(Keyframe, firstChild, entity, NULL)
+ ATTRIB(Keyframe, lastChild, entity, NULL)
+ ENDCLASS(Keyframe)
+ entity makeHostedKeyframe(entity, void(entity, float), float, float, float);
+ entity makeKeyframe(entity, void(entity, float), float, float, float);
+ float getNewChildStart(entity);
+ float getNewChildDuration(entity, float);
+ float getNewChildValue(entity);
#endif
#ifdef IMPLEMENTATION
-entity makeHostedKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
-{
- entity me;
- me = makeKeyframe(obj, objSetter, animDuration, animStart, animEnd);
- anim.addAnim(anim, me);
- return me;
-}
+ entity makeHostedKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
+ {
+ entity this = makeKeyframe(obj, objSetter, animDuration, animStart, animEnd);
+ anim.addAnim(anim, this);
+ return this;
+ }
-entity makeKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
-{
- entity me;
- me = NEW(Keyframe);
- me.configureAnimation(me, obj, objSetter, time, animDuration, animStart, animEnd);
- return me;
-}
+ entity makeKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
+ {
+ entity this = NEW(Keyframe);
+ this.configureAnimation(this, obj, objSetter, time, animDuration, animStart, animEnd);
+ return this;
+ }
-entity Keyframe_addEasing(entity me, float animDurationTime, float animEnd, float(float, float, float, float) func)
-{
- entity other;
- other = makeEasing(me.object, me.setter, func, getNewChildStart(me), getNewChildDuration(me, animDurationTime), getNewChildValue(me), animEnd);
- me.addAnim(me, other);
- return other;
-}
+ METHOD(Keyframe, addEasing, entity(entity this, float animDurationTime, float animEnd, float(float, float, float, float) func))
+ {
+ entity other = makeEasing(this.object, this.setter, func, getNewChildStart(this), getNewChildDuration(this, animDurationTime), getNewChildValue(this), animEnd);
+ this.addAnim(this, other);
+ return other;
+ }
+
+ float getNewChildStart(entity this)
+ {
+ if (this.lastChild) return this.lastChild.startTime + this.lastChild.duration;
+ else return 0;
+ }
-float getNewChildStart(entity me)
-{
- if (me.lastChild)
- return (me.lastChild.startTime + me.lastChild.duration);
- else
- return 0;
-}
+ float getNewChildDuration(entity this, float durationTime)
+ {
+ float maxDura = this.duration;
+ if (this.lastChild) maxDura = maxDura - (this.lastChild.startTime + this.lastChild.duration);
+ float dura = durationTime;
+ if (0 >= dura || dura > maxDura) dura = maxDura;
+ return dura;
+ }
-float getNewChildDuration(entity me, float durationTime)
-{
- float dura, maxDura;
- maxDura = me.duration;
- if (me.lastChild) maxDura = maxDura - (me.lastChild.startTime + me.lastChild.duration);
- dura = durationTime;
- if (0 >= dura || dura > maxDura) dura = maxDura;
- return dura;
-}
+ float getNewChildValue(entity this)
+ {
+ if (this.lastChild) return this.lastChild.startValue + this.lastChild.delta;
+ else return this.startValue;
+ }
-float getNewChildValue(entity me)
-{
- if (me.lastChild)
- return (me.lastChild.startValue + me.lastChild.delta);
- else
- return me.startValue;
-}
+ METHOD(Keyframe, addAnim, void(entity this, entity other))
+ {
+ if (other.parent) error("Can't add already added anim!");
-void Keyframe_addAnim(entity me, entity other)
-{
- if(other.parent)
- error("Can't add already added anim!");
+ if (other.isFinished(other)) error("Can't add finished anim!");
- if(other.isFinished(other))
- error("Can't add finished anim!");
+ other.parent = this;
- other.parent = me;
+ entity l = this.lastChild;
- entity l;
- l = me.lastChild;
+ if (l)
+ {
+ l.nextSibling = other;
+ }
+ else
+ {
+ this.currentChild = other;
+ this.firstChild = other;
+ }
- if(l)
- l.nextSibling = other;
- else
- {
- me.currentChild = other;
- me.firstChild = other;
+ other.prevSibling = l;
+ other.nextSibling = NULL;
+ this.lastChild = other;
}
- other.prevSibling = l;
- other.nextSibling = NULL;
- me.lastChild = other;
-}
+ METHOD(Keyframe, calcValue, float(entity this, float tickTime, float animDuration, float animStartValue, float animDelta))
+ {
+ if (this.currentChild)
+ if (this.currentChild.isFinished(this.currentChild)) this.currentChild = this.currentChild.nextSibling;
-float Keyframe_calcValue(entity me, float tickTime, float animDuration, float animStartValue, float animDelta)
-{
- if (me.currentChild)
- if (me.currentChild.isFinished(me.currentChild))
- me.currentChild = me.currentChild.nextSibling;
+ if (this.currentChild)
+ {
+ this.currentChild.tick(this.currentChild, tickTime);
+ return this.currentChild.value;
+ }
- if (me.currentChild)
- {
- me.currentChild.tick(me.currentChild, tickTime);
- return me.currentChild.value;
+ return animStartValue + animDelta;
}
-
- return animStartValue + animDelta;
-}
#endif
--- /dev/null
+#ifndef CLASSES_H
+#define CLASSES_H
+
+#include "classes.inc"
+#define IMPLEMENTATION
+#include "classes.inc"
+#undef IMPLEMENTATION
+
+#endif
#include "menu_cmd.qh"
#include "../menu.qh"
-#include "../oo/classes.qc"
+#include "../classes.qc"
+
+#include "../mutators/events.qh"
#include "../../common/command/generic.qh"
{
string s;
s = me.toString(me);
- if(s == "")
- s = me.classname;
- else
- s = strcat(me.classname, ": ", s);
+ if (s == "") s = me.classname;
+ else s = strcat(me.classname, ": ", s);
LOG_INFO(_dumptree_space, etos(me), " (", s, ")");
- if(me.firstChild)
+ if (me.firstChild)
{
LOG_INFO(" {\n");
_dumptree_space = strcat(_dumptree_space, " ");
}
else
+ {
LOG_INFO("\n");
+ }
}
void _dumptree_close(entity pass, entity me)
{
- if(me.firstChild)
+ if (me.firstChild)
{
_dumptree_space = substring(_dumptree_space, 0, strlen(_dumptree_space) - 2);
LOG_INFO(_dumptree_space, "}\n");
void GameCommand(string theCommand)
{
- float argc;
- argc = tokenize_console(theCommand);
+ int argc = tokenize_console(theCommand);
+ string ss = strtolower(argv(0));
- if(argv(0) == "help" || argc == 0)
+ if (argv(0) == "help" || argc == 0)
{
LOG_INFO(_("Usage: menu_cmd command..., where possible commands are:\n"));
LOG_INFO(_(" sync - reloads all cvars on the current menu page\n"));
return;
}
- if(GenericCommand(theCommand))
- return;
+ if (GenericCommand(theCommand)) return;
- if(argv(0) == "sync")
+ if (argv(0) == "sync")
{
m_sync();
return;
}
- if(argv(0) == "update_conwidths_before_vid_restart")
+ if (argv(0) == "update_conwidths_before_vid_restart")
{
updateConwidths(cvar("vid_width"), cvar("vid_height"), cvar("vid_pixelheight"));
return;
}
- if(argv(0) == "directmenu" || argv(0) == "directpanelhudmenu")
+ if (argv(0) == "directmenu" || argv(0) == "directpanelhudmenu")
{
string filter = string_null;
- if(argv(0) == "directpanelhudmenu")
- filter = strzone("HUD");
+ if (argv(0) == "directpanelhudmenu") filter = strzone("HUD");
- if(argc == 1)
+ if (argc == 1)
{
LOG_INFO(_("Available options:\n"));
float i;
entity e;
string s;
- for(i = 0, e = NULL; (e = nextent(e)); )
- if(e.classname != "vtbl" && e.name != "")
+ for (i = 0, e = NULL; (e = nextent(e)); )
+ if (e.classname != "vtbl" && e.name != "")
{
s = e.name;
- if(filter)
+ if (filter)
{
- if(substring(s, 0, strlen(filter)) != filter)
- continue;
+ if (substring(s, 0, strlen(filter)) != filter) continue;
s = substring(s, strlen(filter), strlen(s) - strlen(filter));
}
- LOG_INFO(strcat(" ", s ,"\n"));
+ LOG_INFO(strcat(" ", s, "\n"));
++i;
}
}
- else if(argc == 2 && !isdemo()) // don't allow this command in demos
+ else if (argc == 2 && !isdemo()) // don't allow this command in demos
{
m_play_click_sound(MENU_SOUND_OPEN);
m_goto(strcat(filter, argv(1))); // switch to a menu item
}
- if(filter)
- strunzone(filter);
+ if (filter) strunzone(filter);
return;
}
- if(argv(0) == "skinselect")
+ if (argv(0) == "skinselect")
{
m_goto("skinselector");
return;
}
- if(argv(0) == "languageselect")
+ if (argv(0) == "languageselect")
{
m_goto("languageselector");
return;
}
- if(argv(0) == "videosettings")
+ if (argv(0) == "videosettings")
{
m_goto("videosettings");
return;
}
- if(argv(0) == "dumptree")
+ if (argv(0) == "dumptree")
{
_dumptree_space = "";
depthfirst(main, parent, firstChild, nextSibling, _dumptree_open, _dumptree_close, NULL);
return;
}
+ if(MUTATOR_CALLHOOK(Menu_ConsoleCommand, ss, argc, theCommand)) // handled by a mutator
+ return;
+
LOG_INFO(_("Invalid command. For a list of supported commands, try menu_cmd help.\n"));
}
draw_endBoldFont();
}
-void draw_beginBoldFont()
-{
- drawfont = FONT_USER+3;
-}
-
-void draw_endBoldFont()
-{
- drawfont = FONT_USER+0;
-}
-
vector globalToBox(vector v, vector theOrigin, vector theScale)
{
v -= theOrigin;
float draw_alpha;
void draw_reset(float cw, float ch, float ox, float oy);
-void draw_beginBoldFont();
-void draw_endBoldFont();
+#define draw_beginBoldFont() do { drawfont = FONT_USER + 3; } while (0)
+#define draw_endBoldFont() do { drawfont = FONT_USER + 0; } while (0)
void draw_setMousePointer(string pic, vector theSize, vector theOffset);
void draw_drawMousePointer(vector where);
#include "xonotic/tab.qc"
-REGISTRY(Settings, BIT(3))
-REGISTER_REGISTRY(RegisterSettings)
+REGISTRY(Settings, BITS(3))
+#define Settings_from(i) _Settings_from(i, NULL)
+REGISTER_REGISTRY(Settings)
#define REGISTER_SETTINGS(id, impl) \
LAZY_NEW(id, impl) \
- REGISTER(RegisterSettings, MENU, Settings, id, m_id, NEW(Lazy, LAZY(id)))
+ REGISTER(Settings, MENU, id, m_id, NEW(Lazy, LAZY(id)))
#endif
#endif
#define ITEM_H
#include "skin.qh"
CLASS(Item, Object)
- METHOD(Item, draw, void(entity));
- METHOD(Item, keyDown, float(entity, float, float, float));
- METHOD(Item, keyUp, float(entity, float, float, float));
- METHOD(Item, mouseMove, float(entity, vector));
- METHOD(Item, mousePress, float(entity, vector));
- METHOD(Item, mouseDrag, float(entity, vector));
- METHOD(Item, mouseRelease, float(entity, vector));
- METHOD(Item, focusEnter, void(entity));
- METHOD(Item, focusLeave, void(entity));
- METHOD(Item, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(Item, relinquishFocus, void(entity));
- METHOD(Item, showNotify, void(entity));
- METHOD(Item, hideNotify, void(entity));
- METHOD(Item, toString, string(entity));
- METHOD(Item, destroy, void(entity));
+ METHOD(Item, draw, void(Item));
+ METHOD(Item, keyDown, float(Item, float, float, float));
+ METHOD(Item, keyUp, float(Item, float, float, float));
+ METHOD(Item, mouseMove, float(Item, vector));
+ METHOD(Item, mousePress, float(Item, vector));
+ METHOD(Item, mouseDrag, float(Item, vector));
+ METHOD(Item, mouseRelease, float(Item, vector));
+ METHOD(Item, focusEnter, void(Item));
+ METHOD(Item, focusLeave, void(Item));
+ METHOD(Item, resizeNotify, void(Item, vector, vector, vector, vector));
+ METHOD(Item, relinquishFocus, void(Item));
+ METHOD(Item, showNotify, void(Item));
+ METHOD(Item, hideNotify, void(Item));
+ METHOD(Item, toString, string(Item));
+ METHOD(Item, destroy, void(Item));
ATTRIB(Item, focused, float, 0)
ATTRIB(Item, focusable, float, 0)
ATTRIB(Item, allowFocusSound, float, 0)
#endif
#ifdef IMPLEMENTATION
-void Item_destroy(entity me)
-{
- // free memory associated with me
-}
-
-void Item_relinquishFocus(entity me)
-{
- if(me.parent)
- if(me.parent.instanceOfContainer)
- me.parent.setFocus(me.parent, NULL);
-}
-
-void Item_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- me.origin = absOrigin;
- me.size = absSize;
-}
-
-float autocvar_menu_showboxes;
-void Item_draw(entity me)
-{
- if(autocvar_menu_showboxes)
+ METHOD(Item, destroy, void(Item this))
{
+ // free memory associated with this
+ }
+
+ METHOD(Item, relinquishFocus, void(Item this))
+ {
+ entity par = this.parent;
+ if (!par) return;
+ if (par.instanceOfContainer) par.setFocus(par, NULL);
+ }
+
+ METHOD(Item, resizeNotify, void(Item this, vector relOrigin, vector relSize, vector absOrigin, vector absSize))
+ {
+ this.origin = absOrigin;
+ this.size = absSize;
+ }
+
+ int autocvar_menu_showboxes;
+ METHOD(Item, draw, void(Item this))
+ {
+ if (!autocvar_menu_showboxes) return;
vector rgb = '1 0 1';
float a = fabs(autocvar_menu_showboxes);
// don't draw containers and border images
- if(me.instanceOfContainer || me.instanceOfBorderImage)
+ if (this.instanceOfContainer || this.instanceOfBorderImage)
{
rgb = '0 0 0';
a = 0;
}
-#if 0
- // hack to detect multi drawing
- float r = random() * 3;
- if(r >= 2)
- rgb = '1 0 0';
- else if(r >= 1)
- rgb = '0 1 0';
- else
- rgb = '0 0 1';
-#endif
- if(autocvar_menu_showboxes < 0)
+ #if 0
+ // hack to detect multi drawing
+ float r = random() * 3;
+ if (r >= 2) rgb = '1 0 0';
+ else if (r >= 1) rgb = '0 1 0';
+ else rgb = '0 0 1';
+ #endif
+ if (autocvar_menu_showboxes < 0)
{
draw_Fill('0 0 0', '0.5 0.5 0', rgb, a);
draw_Fill('0.5 0.5 0', '0.5 0.5 0', rgb, a);
}
- if(autocvar_menu_showboxes > 0)
+ else if (autocvar_menu_showboxes > 0)
{
draw_Fill('0 0 0', '1 1 0', rgb, a);
}
}
-}
-
-void Item_showNotify(entity me)
-{
-}
-
-void Item_hideNotify(entity me)
-{
-}
-
-float Item_keyDown(entity me, float scan, float ascii, float shift)
-{
- return 0; // unhandled
-}
-
-float Item_keyUp(entity me, float scan, float ascii, float shift)
-{
- return 0; // unhandled
-}
-
-float Item_mouseMove(entity me, vector pos)
-{
- return 0; // unhandled
-}
-
-float Item_mousePress(entity me, vector pos)
-{
- return 0; // unhandled
-}
-
-float Item_mouseDrag(entity me, vector pos)
-{
- return 0; // unhandled
-}
-
-float Item_mouseRelease(entity me, vector pos)
-{
- return 0; // unhandled
-}
-
-void Item_focusEnter(entity me)
-{
- if(me.allowFocusSound)
- m_play_focus_sound();
-}
-
-void Item_focusLeave(entity me)
-{
-}
-
-string Item_toString(entity me)
-{
- return string_null;
-}
+
+ METHOD(Item, showNotify, void(Item this))
+ {}
+
+ METHOD(Item, hideNotify, void(Item this))
+ {}
+
+ METHOD(Item, keyDown, float(Item this, float scan, float ascii, float shift))
+ {
+ return 0; // unhandled
+ }
+
+ METHOD(Item, keyUp, float(Item this, float scan, float ascii, float shift))
+ {
+ return 0; // unhandled
+ }
+
+ METHOD(Item, mouseMove, float(Item this, vector pos))
+ {
+ return 0; // unhandled
+ }
+
+ METHOD(Item, mousePress, float(Item this, vector pos))
+ {
+ return 0; // unhandled
+ }
+
+ METHOD(Item, mouseDrag, float(Item this, vector pos))
+ {
+ return 0; // unhandled
+ }
+
+ METHOD(Item, mouseRelease, float(Item this, vector pos))
+ {
+ return 0; // unhandled
+ }
+
+ METHOD(Item, focusEnter, void(Item this))
+ {
+ if (this.allowFocusSound) m_play_focus_sound();
+ }
+
+ METHOD(Item, focusLeave, void(Item this))
+ {}
+
+ METHOD(Item, toString, string(Item this))
+ {
+ return string_null;
+ }
#endif
#ifndef ITEM_BORDERIMAGE_H
-#define ITEM_BORDERIMAGE_H
-#include "label.qc"
-CLASS(BorderImage, Label)
- METHOD(BorderImage, configureBorderImage, void(entity, string, float, vector, string, float));
- METHOD(BorderImage, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(BorderImage, recalcPositionWithText, void(entity, string));
- ATTRIB(BorderImage, isBold, float, 1)
- METHOD(BorderImage, draw, void(entity));
- ATTRIB(BorderImage, src, string, string_null)
- ATTRIB(BorderImage, borderHeight, float, 0)
- ATTRIB(BorderImage, borderVec, vector, '0 0 0')
- ATTRIB(BorderImage, color, vector, '1 1 1')
- ATTRIB(BorderImage, closeButton, entity, NULL)
- ATTRIB(BorderImage, realFontSize_Nexposeed, vector, '0 0 0')
- ATTRIB(BorderImage, realOrigin_Nexposeed, vector, '0 0 0')
- ATTRIB(BorderImage, isNexposeeTitleBar, float, 0)
- ATTRIB(BorderImage, zoomedOutTitleBarPosition, float, 0)
- ATTRIB(BorderImage, zoomedOutTitleBar, float, 0)
- ATTRIB(BorderImage, overrideRealOrigin, vector, '0 1 0')
- ATTRIB(BorderImage, saveRelOrigin, vector, '0 0 0')
- ATTRIB(BorderImage, saveRelSize, vector, '0 0 0')
-ENDCLASS(BorderImage)
+ #define ITEM_BORDERIMAGE_H
+ #include "label.qc"
+ CLASS(BorderImage, Label)
+ METHOD(BorderImage, configureBorderImage, void(entity, string, float, vector, string, float));
+ METHOD(BorderImage, resizeNotify, void(entity, vector, vector, vector, vector));
+ METHOD(BorderImage, recalcPositionWithText, void(entity, string));
+ ATTRIB(BorderImage, isBold, float, 1)
+ METHOD(BorderImage, draw, void(entity));
+ ATTRIB(BorderImage, src, string, string_null)
+ ATTRIB(BorderImage, borderHeight, float, 0)
+ ATTRIB(BorderImage, borderVec, vector, '0 0 0')
+ ATTRIB(BorderImage, color, vector, '1 1 1')
+ ATTRIB(BorderImage, closeButton, entity, NULL)
+ ATTRIB(BorderImage, realFontSize_Nexposeed, vector, '0 0 0')
+ ATTRIB(BorderImage, realOrigin_Nexposeed, vector, '0 0 0')
+ ATTRIB(BorderImage, isNexposeeTitleBar, float, 0)
+ ATTRIB(BorderImage, zoomedOutTitleBarPosition, float, 0)
+ ATTRIB(BorderImage, zoomedOutTitleBar, float, 0)
+ ATTRIB(BorderImage, overrideRealOrigin, vector, '0 1 0')
+ ATTRIB(BorderImage, saveRelOrigin, vector, '0 0 0')
+ ATTRIB(BorderImage, saveRelSize, vector, '0 0 0')
+ ENDCLASS(BorderImage)
#endif
#ifdef IMPLEMENTATION
-void BorderImage_recalcPositionWithText(entity me, string t)
-{
- if(me.isNexposeeTitleBar)
+ void BorderImage_recalcPositionWithText(entity me, string t)
{
- vector scrs;
- scrs = eX * conwidth + eY * conheight;
- me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_smallOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_smallSize, scrs));
+ if (me.isNexposeeTitleBar)
+ {
+ vector scrs;
+ scrs = eX * conwidth + eY * conheight;
+ me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_smallOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_smallSize, scrs));
+ SUPER(BorderImage).recalcPositionWithText(me, t);
+ me.realOrigin_y = me.realFontSize.y * me.zoomedOutTitleBarPosition;
+ me.realOrigin_Nexposeed = me.realOrigin;
+ me.realFontSize_Nexposeed = me.realFontSize;
+ me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_initialOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_initialSize, scrs));
+ }
SUPER(BorderImage).recalcPositionWithText(me, t);
- me.realOrigin_y = me.realFontSize.y * me.zoomedOutTitleBarPosition;
- me.realOrigin_Nexposeed = me.realOrigin;
- me.realFontSize_Nexposeed = me.realFontSize;
- me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_initialOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_initialSize, scrs));
}
- SUPER(BorderImage).recalcPositionWithText(me, t);
-}
-void BorderImage_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- me.isNexposeeTitleBar = 0;
- if(me.zoomedOutTitleBar)
- if(me.parent.parent.instanceOfNexposee)
- if(me.parent.instanceOfDialog)
- if(me == me.parent.frame)
- me.isNexposeeTitleBar = 1;
- me.saveRelOrigin = relOrigin;
- me.saveRelSize = relSize;
- SUPER(BorderImage).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
- me.borderVec_x = me.borderHeight / absSize.x;
- me.borderVec_y = me.borderHeight / absSize.y;
- me.realOrigin_y = 0.5 * (me.borderVec.y - me.realFontSize.y);
- if(me.closeButton)
+ void BorderImage_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
{
- // move the close button to the right place
- me.closeButton.Container_origin = '1 0 0' * (1 - me.borderVec.x);
- me.closeButton.Container_size = me.borderVec;
- me.closeButton.color = me.color;
- me.closeButton.colorC = me.color;
- me.closeButton.colorF = me.color;
+ me.isNexposeeTitleBar = 0;
+ if (me.zoomedOutTitleBar)
+ if (me.parent.parent.instanceOfNexposee)
+ if (me.parent.instanceOfDialog)
+ if (me == me.parent.frame) me.isNexposeeTitleBar = 1;
+ me.saveRelOrigin = relOrigin;
+ me.saveRelSize = relSize;
+ SUPER(BorderImage).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+ me.borderVec_x = me.borderHeight / absSize.x;
+ me.borderVec_y = me.borderHeight / absSize.y;
+ me.realOrigin_y = 0.5 * (me.borderVec.y - me.realFontSize.y);
+ if (me.closeButton)
+ {
+ // move the close button to the right place
+ me.closeButton.Container_origin = '1 0 0' * (1 - me.borderVec.x);
+ me.closeButton.Container_size = me.borderVec;
+ me.closeButton.color = me.color;
+ me.closeButton.colorC = me.color;
+ me.closeButton.colorF = me.color;
+ }
}
-}
-void BorderImage_configureBorderImage(entity me, string theTitle, float sz, vector theColor, string path, float theBorderHeight)
-{
- me.configureLabel(me, theTitle, sz, 0.5);
- me.src = path;
- me.color = theColor;
- me.borderHeight = theBorderHeight;
-}
-void BorderImage_draw(entity me)
-{
- if(me.src)
- draw_BorderPicture('0 0 0', me.src, '1 1 0', me.color, 1, me.borderVec);
-
- if(me.fontSize > 0)
+ void BorderImage_configureBorderImage(entity me, string theTitle, float sz, vector theColor, string path, float theBorderHeight)
+ {
+ me.configureLabel(me, theTitle, sz, 0.5);
+ me.src = path;
+ me.color = theColor;
+ me.borderHeight = theBorderHeight;
+ }
+ void BorderImage_draw(entity me)
{
- if(me.recalcPos)
- me.recalcPositionWithText(me, me.text);
+ if (me.src) draw_BorderPicture('0 0 0', me.src, '1 1 0', me.color, 1, me.borderVec);
- if(me.isNexposeeTitleBar)
+ if (me.fontSize > 0)
{
- vector ro, rf, df;
+ if (me.recalcPos) me.recalcPositionWithText(me, me.text);
- // me.parent.Nexposee_animationFactor 0 (small) or 1 (full)
- // default values are for 1
- ro = me.realOrigin;
- rf = me.realFontSize;
- df = draw_fontscale;
- me.realOrigin = ro * me.parent.Nexposee_animationFactor + me.realOrigin_Nexposeed * (1 - me.parent.Nexposee_animationFactor);
- me.realFontSize = rf * me.parent.Nexposee_animationFactor + me.realFontSize_Nexposeed * (1 - me.parent.Nexposee_animationFactor);
- draw_fontscale = globalToBoxSize(boxToGlobalSize(df, me.realFontSize), rf);
+ if (me.isNexposeeTitleBar)
+ {
+ vector ro, rf, df;
- SUPER(BorderImage).draw(me);
+ // me.parent.Nexposee_animationFactor 0 (small) or 1 (full)
+ // default values are for 1
+ ro = me.realOrigin;
+ rf = me.realFontSize;
+ df = draw_fontscale;
+ me.realOrigin = ro * me.parent.Nexposee_animationFactor + me.realOrigin_Nexposeed * (1 - me.parent.Nexposee_animationFactor);
+ me.realFontSize = rf * me.parent.Nexposee_animationFactor + me.realFontSize_Nexposeed * (1 - me.parent.Nexposee_animationFactor);
+ draw_fontscale = globalToBoxSize(boxToGlobalSize(df, me.realFontSize), rf);
+
+ SUPER(BorderImage).draw(me);
- // me.Nexposee_animationState 0 (small) or 1 (full)
- // default values are for 1
- me.realOrigin = ro;
- me.realFontSize = rf;
- draw_fontscale = df;
+ // me.Nexposee_animationState 0 (small) or 1 (full)
+ // default values are for 1
+ me.realOrigin = ro;
+ me.realFontSize = rf;
+ draw_fontscale = df;
+ }
+ else
+ {
+ SUPER(BorderImage).draw(me);
+ }
}
else
+ {
SUPER(BorderImage).draw(me);
+ }
}
- else
- {
- SUPER(BorderImage).draw(me);
- }
-}
#endif
#ifndef ITEM_BUTTON_H
-#define ITEM_BUTTON_H
-#include "label.qc"
-CLASS(Button, Label)
- METHOD(Button, configureButton, void(entity, string, float, string));
- METHOD(Button, draw, void(entity));
- METHOD(Button, showNotify, void(entity));
- METHOD(Button, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(Button, keyDown, float(entity, float, float, float));
- METHOD(Button, mousePress, float(entity, vector));
- METHOD(Button, mouseDrag, float(entity, vector));
- METHOD(Button, mouseRelease, float(entity, vector));
- METHOD(Button, playClickSound, void(entity));
- ATTRIB(Button, onClick, void(entity, entity), func_null)
- ATTRIB(Button, onClickEntity, entity, NULL)
- ATTRIB(Button, src, string, string_null)
- ATTRIB(Button, srcSuffix, string, string_null)
- ATTRIB(Button, src2, string, string_null) // is centered, same aspect, and stretched to label size
- ATTRIB(Button, src2scale, float, 1)
- ATTRIB(Button, srcMulti, float, 1) // 0: button square left, text right; 1: button stretched, text over it
- ATTRIB(Button, buttonLeftOfText, float, 0)
- ATTRIB(Button, focusable, float, 1)
- ATTRIB(Button, allowFocusSound, float, 1)
- ATTRIB(Button, pressed, float, 0)
- ATTRIB(Button, clickTime, float, 0)
- ATTRIB(Button, disabled, float, 0)
- ATTRIB(Button, disabledAlpha, float, 0.3)
- ATTRIB(Button, forcePressed, float, 0)
- ATTRIB(Button, color, vector, '1 1 1')
- ATTRIB(Button, colorC, vector, '1 1 1')
- ATTRIB(Button, colorF, vector, '1 1 1')
- ATTRIB(Button, colorD, vector, '1 1 1')
- ATTRIB(Button, color2, vector, '1 1 1')
- ATTRIB(Button, alpha2, float, 1)
+ #define ITEM_BUTTON_H
+ #include "label.qc"
+ CLASS(Button, Label)
+ METHOD(Button, configureButton, void(entity, string, float, string));
+ METHOD(Button, draw, void(entity));
+ METHOD(Button, showNotify, void(entity));
+ METHOD(Button, resizeNotify, void(entity, vector, vector, vector, vector));
+ METHOD(Button, keyDown, float(entity, float, float, float));
+ METHOD(Button, mousePress, float(entity, vector));
+ METHOD(Button, mouseDrag, float(entity, vector));
+ METHOD(Button, mouseRelease, float(entity, vector));
+ METHOD(Button, playClickSound, void(entity));
+ ATTRIB(Button, onClick, void(entity, entity), func_null)
+ ATTRIB(Button, onClickEntity, entity, NULL)
+ ATTRIB(Button, src, string, string_null)
+ ATTRIB(Button, srcSuffix, string, string_null)
+ ATTRIB(Button, src2, string, string_null) // is centered, same aspect, and stretched to label size
+ ATTRIB(Button, src2scale, float, 1)
+ ATTRIB(Button, srcMulti, float, 1) // 0: button square left, text right; 1: button stretched, text over it
+ ATTRIB(Button, buttonLeftOfText, float, 0)
+ ATTRIB(Button, focusable, float, 1)
+ ATTRIB(Button, allowFocusSound, float, 1)
+ ATTRIB(Button, pressed, float, 0)
+ ATTRIB(Button, clickTime, float, 0)
+ ATTRIB(Button, disabled, float, 0)
+ ATTRIB(Button, disabledAlpha, float, 0.3)
+ ATTRIB(Button, forcePressed, float, 0)
+ ATTRIB(Button, color, vector, '1 1 1')
+ ATTRIB(Button, colorC, vector, '1 1 1')
+ ATTRIB(Button, colorF, vector, '1 1 1')
+ ATTRIB(Button, colorD, vector, '1 1 1')
+ ATTRIB(Button, color2, vector, '1 1 1')
+ ATTRIB(Button, alpha2, float, 1)
- ATTRIB(Button, origin, vector, '0 0 0')
- ATTRIB(Button, size, vector, '0 0 0')
-ENDCLASS(Button)
+ ATTRIB(Button, origin, vector, '0 0 0')
+ ATTRIB(Button, size, vector, '0 0 0')
+ ENDCLASS(Button)
#endif
#ifdef IMPLEMENTATION
-void Button_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- if(me.srcMulti)
- me.keepspaceLeft = 0;
- else
- me.keepspaceLeft = min(0.8, absSize.x == 0 ? 0 : (absSize.y / absSize.x));
- SUPER(Button).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-}
-void Button_configureButton(entity me, string txt, float sz, string gfx)
-{
- SUPER(Button).configureLabel(me, txt, sz, me.srcMulti ? 0.5 : 0);
- me.src = gfx;
-}
-float Button_keyDown(entity me, float key, float ascii, float shift)
-{
- if(key == K_ENTER || key == K_SPACE || key == K_KP_ENTER)
+ void Button_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
{
- me.playClickSound(me);
- me.clickTime = 0.1; // delayed for effect
- return 1;
+ if (me.srcMulti) me.keepspaceLeft = 0;
+ else me.keepspaceLeft = min(0.8, absSize.x == 0 ? 0 : (absSize.y / absSize.x));
+ SUPER(Button).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+ }
+ void Button_configureButton(entity me, string txt, float sz, string gfx)
+ {
+ SUPER(Button).configureLabel(me, txt, sz, me.srcMulti ? 0.5 : 0);
+ me.src = gfx;
}
- return 0;
-}
-float Button_mouseDrag(entity me, vector pos)
-{
- me.pressed = 1;
- if(pos.x < 0) me.pressed = 0;
- if(pos.y < 0) me.pressed = 0;
- if(pos.x >= 1) me.pressed = 0;
- if(pos.y >= 1) me.pressed = 0;
- return 1;
-}
-float Button_mousePress(entity me, vector pos)
-{
- me.mouseDrag(me, pos); // verify coordinates
- return 1;
-}
-float Button_mouseRelease(entity me, vector pos)
-{
- me.mouseDrag(me, pos); // verify coordinates
- if(me.pressed)
+ float Button_keyDown(entity me, float key, float ascii, float shift)
{
- if (!me.disabled)
+ if (key == K_ENTER || key == K_SPACE || key == K_KP_ENTER)
{
me.playClickSound(me);
- if(me.onClick)
- me.onClick(me, me.onClickEntity);
+ me.clickTime = 0.1; // delayed for effect
+ return 1;
}
- me.pressed = 0;
+ return 0;
}
- return 1;
-}
-void Button_showNotify(entity me)
-{
- me.focusable = !me.disabled;
-}
-void Button_draw(entity me)
-{
- vector bOrigin, bSize;
- float save;
-
- me.focusable = !me.disabled;
-
- save = draw_alpha;
- if(me.disabled)
- draw_alpha *= me.disabledAlpha;
-
- if(me.src)
+ float Button_mouseDrag(entity me, vector pos)
+ {
+ me.pressed = 1;
+ if (pos.x < 0) me.pressed = 0;
+ if (pos.y < 0) me.pressed = 0;
+ if (pos.x >= 1) me.pressed = 0;
+ if (pos.y >= 1) me.pressed = 0;
+ return 1;
+ }
+ float Button_mousePress(entity me, vector pos)
{
- if(me.srcMulti)
+ me.mouseDrag(me, pos); // verify coordinates
+ return 1;
+ }
+ float Button_mouseRelease(entity me, vector pos)
+ {
+ me.mouseDrag(me, pos); // verify coordinates
+ if (me.pressed)
{
- bOrigin = '0 0 0';
- bSize = '1 1 0';
- if(me.disabled)
- draw_ButtonPicture(bOrigin, strcat(me.src, "_d", me.srcSuffix), bSize, me.colorD, 1);
- else if(me.forcePressed || me.pressed || me.clickTime > 0)
- draw_ButtonPicture(bOrigin, strcat(me.src, "_c", me.srcSuffix), bSize, me.colorC, 1);
- else if(me.focused)
- draw_ButtonPicture(bOrigin, strcat(me.src, "_f", me.srcSuffix), bSize, me.colorF, 1);
- else
- draw_ButtonPicture(bOrigin, strcat(me.src, "_n", me.srcSuffix), bSize, me.color, 1);
+ if (!me.disabled)
+ {
+ me.playClickSound(me);
+ if (me.onClick) me.onClick(me, me.onClickEntity);
+ }
+ me.pressed = 0;
}
- else
+ return 1;
+ }
+ void Button_showNotify(entity me)
+ {
+ me.focusable = !me.disabled;
+ }
+ void Button_draw(entity me)
+ {
+ vector bOrigin, bSize;
+ float save;
+
+ me.focusable = !me.disabled;
+
+ save = draw_alpha;
+ if (me.disabled) draw_alpha *= me.disabledAlpha;
+
+ if (me.src)
{
- if(me.realFontSize_y == 0)
+ if (me.srcMulti)
{
bOrigin = '0 0 0';
bSize = '1 1 0';
+ if (me.disabled) draw_ButtonPicture(bOrigin, strcat(me.src, "_d", me.srcSuffix), bSize, me.colorD, 1);
+ else if (me.forcePressed || me.pressed || me.clickTime > 0) draw_ButtonPicture(bOrigin, strcat(me.src, "_c", me.srcSuffix), bSize, me.colorC, 1);
+ else if (me.focused) draw_ButtonPicture(bOrigin, strcat(me.src, "_f", me.srcSuffix), bSize, me.colorF, 1);
+ else draw_ButtonPicture(bOrigin, strcat(me.src, "_n", me.srcSuffix), bSize, me.color, 1);
}
else
{
- bOrigin = eY * (0.5 * (1 - me.realFontSize.y)) + eX * (0.5 * (me.keepspaceLeft - me.realFontSize.x));
- bSize = me.realFontSize;
+ if (me.realFontSize_y == 0)
+ {
+ bOrigin = '0 0 0';
+ bSize = '1 1 0';
+ }
+ else
+ {
+ bOrigin = eY * (0.5 * (1 - me.realFontSize.y)) + eX * (0.5 * (me.keepspaceLeft - me.realFontSize.x));
+ bSize = me.realFontSize;
+ }
+ if (me.disabled) draw_Picture(bOrigin, strcat(me.src, "_d", me.srcSuffix), bSize, me.colorD, 1);
+ else if (me.forcePressed || me.pressed || me.clickTime > 0) draw_Picture(bOrigin, strcat(me.src, "_c", me.srcSuffix), bSize, me.colorC, 1);
+ else if (me.focused) draw_Picture(bOrigin, strcat(me.src, "_f", me.srcSuffix), bSize, me.colorF, 1);
+ else draw_Picture(bOrigin, strcat(me.src, "_n", me.srcSuffix), bSize, me.color, 1);
}
- if(me.disabled)
- draw_Picture(bOrigin, strcat(me.src, "_d", me.srcSuffix), bSize, me.colorD, 1);
- else if(me.forcePressed || me.pressed || me.clickTime > 0)
- draw_Picture(bOrigin, strcat(me.src, "_c", me.srcSuffix), bSize, me.colorC, 1);
- else if(me.focused)
- draw_Picture(bOrigin, strcat(me.src, "_f", me.srcSuffix), bSize, me.colorF, 1);
- else
- draw_Picture(bOrigin, strcat(me.src, "_n", me.srcSuffix), bSize, me.color, 1);
}
- }
- if(me.src2)
- {
- bOrigin = me.keepspaceLeft * eX;
- bSize = eY + eX * (1 - me.keepspaceLeft);
+ if (me.src2)
+ {
+ bOrigin = me.keepspaceLeft * eX;
+ bSize = eY + eX * (1 - me.keepspaceLeft);
- bOrigin += bSize * (0.5 - 0.5 * me.src2scale);
- bSize = bSize * me.src2scale;
+ bOrigin += bSize * (0.5 - 0.5 * me.src2scale);
+ bSize = bSize * me.src2scale;
- draw_Picture(bOrigin, me.src2, bSize, me.color2, me.alpha2);
- }
+ draw_Picture(bOrigin, me.src2, bSize, me.color2, me.alpha2);
+ }
+
+ draw_alpha = save;
- draw_alpha = save;
+ if (me.clickTime > 0 && me.clickTime <= frametime)
+ {
+ // keyboard click timer expired? Fire the event then.
+ if (!me.disabled)
+ if (me.onClick) me.onClick(me, me.onClickEntity);
+ }
+ me.clickTime -= frametime;
- if(me.clickTime > 0 && me.clickTime <= frametime)
+ SUPER(Button).draw(me);
+ }
+ void Dialog_Close(entity button, entity me);
+ void Button_playClickSound(entity me)
{
- // keyboard click timer expired? Fire the event then.
- if (!me.disabled)
- if(me.onClick)
- me.onClick(me, me.onClickEntity);
+ if (me.onClick == DialogOpenButton_Click) m_play_click_sound(MENU_SOUND_OPEN);
+ else if (me.onClick == Dialog_Close) m_play_click_sound(MENU_SOUND_CLOSE);
+ else m_play_click_sound(MENU_SOUND_EXECUTE);
}
- me.clickTime -= frametime;
-
- SUPER(Button).draw(me);
-}
-void Dialog_Close(entity button, entity me);
-void Button_playClickSound(entity me)
-{
- if(me.onClick == DialogOpenButton_Click)
- m_play_click_sound(MENU_SOUND_OPEN);
- else if(me.onClick == Dialog_Close)
- m_play_click_sound(MENU_SOUND_CLOSE);
- else
- m_play_click_sound(MENU_SOUND_EXECUTE);
-}
#endif
#ifndef ITEM_CHECKBOX_H
-#define ITEM_CHECKBOX_H
-#include "button.qc"
-void CheckBox_Click(entity me, entity other);
-CLASS(CheckBox, Button)
- METHOD(CheckBox, configureCheckBox, void(entity, string, float, string));
- METHOD(CheckBox, draw, void(entity));
- METHOD(CheckBox, playClickSound, void(entity));
- METHOD(CheckBox, toString, string(entity));
- METHOD(CheckBox, setChecked, void(entity, float));
- ATTRIB(CheckBox, useDownAsChecked, float, 0)
- ATTRIB(CheckBox, checked, float, 0)
- ATTRIB(CheckBox, onClick, void(entity, entity), CheckBox_Click)
- ATTRIB(CheckBox, srcMulti, float, 0)
- ATTRIB(CheckBox, disabled, float, 0)
-ENDCLASS(CheckBox)
+ #define ITEM_CHECKBOX_H
+ #include "button.qc"
+ void CheckBox_Click(entity me, entity other);
+ CLASS(CheckBox, Button)
+ METHOD(CheckBox, configureCheckBox, void(entity, string, float, string));
+ METHOD(CheckBox, draw, void(entity));
+ METHOD(CheckBox, playClickSound, void(entity));
+ METHOD(CheckBox, toString, string(entity));
+ METHOD(CheckBox, setChecked, void(entity, float));
+ ATTRIB(CheckBox, useDownAsChecked, float, 0)
+ ATTRIB(CheckBox, checked, float, 0)
+ ATTRIB(CheckBox, onClick, void(entity, entity), CheckBox_Click)
+ ATTRIB(CheckBox, srcMulti, float, 0)
+ ATTRIB(CheckBox, disabled, float, 0)
+ ENDCLASS(CheckBox)
#endif
#ifdef IMPLEMENTATION
-void CheckBox_setChecked(entity me, float val)
-{
- me.checked = val;
-}
-void CheckBox_Click(entity me, entity other)
-{
- me.setChecked(me, !me.checked);
-}
-string CheckBox_toString(entity me)
-{
- return strcat(SUPER(CheckBox).toString(me), ", ", me.checked ? "checked" : "unchecked");
-}
-void CheckBox_configureCheckBox(entity me, string txt, float sz, string gfx)
-{
- me.configureButton(me, txt, sz, gfx);
- me.align = 0;
-}
-void CheckBox_draw(entity me)
-{
- float s;
- s = me.pressed;
- if(me.useDownAsChecked)
+ void CheckBox_setChecked(entity me, float val)
{
- me.srcSuffix = string_null;
- me.forcePressed = me.checked;
+ me.checked = val;
+ }
+ void CheckBox_Click(entity me, entity other)
+ {
+ me.setChecked(me, !me.checked);
+ }
+ string CheckBox_toString(entity me)
+ {
+ return strcat(SUPER(CheckBox).toString(me), ", ", me.checked ? "checked" : "unchecked");
+ }
+ void CheckBox_configureCheckBox(entity me, string txt, float sz, string gfx)
+ {
+ me.configureButton(me, txt, sz, gfx);
+ me.align = 0;
+ }
+ void CheckBox_draw(entity me)
+ {
+ float s;
+ s = me.pressed;
+ if (me.useDownAsChecked)
+ {
+ me.srcSuffix = string_null;
+ me.forcePressed = me.checked;
+ }
+ else
+ {
+ me.srcSuffix = (me.checked ? "1" : "0");
+ }
+ me.pressed = s;
+ SUPER(CheckBox).draw(me);
+ }
+ void CheckBox_playClickSound(entity me)
+ {
+ m_play_click_sound(MENU_SOUND_SELECT);
}
- else
- me.srcSuffix = (me.checked ? "1" : "0");
- me.pressed = s;
- SUPER(CheckBox).draw(me);
-}
-void CheckBox_playClickSound(entity me)
-{
- m_play_click_sound(MENU_SOUND_SELECT);
-}
#endif
#ifndef ITEM_CONTAINER_H
-#define ITEM_CONTAINER_H
-#include "../item.qc"
-CLASS(Container, Item)
- METHOD(Container, draw, void(entity));
- METHOD(Container, keyUp, float(entity, float, float, float));
- METHOD(Container, keyDown, float(entity, float, float, float));
- METHOD(Container, mouseMove, float(entity, vector));
- METHOD(Container, mousePress, float(entity, vector));
- METHOD(Container, mouseDrag, float(entity, vector));
- METHOD(Container, mouseRelease, float(entity, vector));
- METHOD(Container, focusLeave, void(entity));
- METHOD(Container, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(Container, resizeNotifyLie, void(entity, vector, vector, vector, vector, .vector, .vector, .vector));
- METHOD(Container, addItem, void(entity, entity, vector, vector, float));
- METHOD(Container, addItemCentered, void(entity, entity, vector, float));
- METHOD(Container, addItemRightCentered, void(entity, entity, vector, float));
- METHOD(Container, moveItemAfter, void(entity, entity, entity));
- METHOD(Container, removeItem, void(entity, entity));
- METHOD(Container, setFocus, void(entity, entity));
- METHOD(Container, saveFocus, void(entity));
- METHOD(Container, setAlphaOf, void(entity, entity, float));
- METHOD(Container, itemFromPoint, entity(entity, vector));
- METHOD(Container, showNotify, void(entity));
- METHOD(Container, hideNotify, void(entity));
- METHOD(Container, preferredFocusedGrandChild, entity(entity));
- ATTRIB(Container, focusable, float, 0)
- ATTRIB(Container, firstChild, entity, NULL)
- ATTRIB(Container, lastChild, entity, NULL)
- ATTRIB(Container, focusedChild, entity, NULL)
- ATTRIB(Container, savedFocus, entity, NULL)
- ATTRIB(Container, shown, float, 0)
-
- METHOD(Container, enterSubitem, void(entity, entity));
- METHOD(Container, enterLieSubitem, void(entity, vector, vector, vector, float));
- METHOD(Container, leaveSubitem, void(entity));
-ENDCLASS(Container)
-.entity nextSibling;
-.entity prevSibling;
-.float resized;
-.vector Container_origin;
-.vector Container_size;
-.vector Container_fontscale;
-.float Container_alpha;
-.vector Container_save_shift;
-.vector Container_save_scale;
-.vector Container_save_fontscale;
-.float Container_save_alpha;
+ #define ITEM_CONTAINER_H
+ #include "../item.qc"
+ CLASS(Container, Item)
+ METHOD(Container, draw, void(entity));
+ METHOD(Container, keyUp, float(entity, float, float, float));
+ METHOD(Container, keyDown, float(entity, float, float, float));
+ METHOD(Container, mouseMove, float(entity, vector));
+ METHOD(Container, mousePress, float(entity, vector));
+ METHOD(Container, mouseDrag, float(entity, vector));
+ METHOD(Container, mouseRelease, float(entity, vector));
+ METHOD(Container, focusLeave, void(entity));
+ METHOD(Container, resizeNotify, void(entity, vector, vector, vector, vector));
+ METHOD(Container, resizeNotifyLie, void(entity, vector, vector, vector, vector, .vector, .vector, .vector));
+ METHOD(Container, addItem, void(entity, entity, vector, vector, float));
+ METHOD(Container, addItemCentered, void(entity, entity, vector, float));
+ METHOD(Container, addItemRightCentered, void(entity, entity, vector, float));
+ METHOD(Container, moveItemAfter, void(entity, entity, entity));
+ METHOD(Container, removeItem, void(entity, entity));
+ METHOD(Container, setFocus, void(entity, entity));
+ METHOD(Container, saveFocus, void(entity));
+ METHOD(Container, setAlphaOf, void(entity, entity, float));
+ METHOD(Container, itemFromPoint, entity(entity, vector));
+ METHOD(Container, showNotify, void(entity));
+ METHOD(Container, hideNotify, void(entity));
+ METHOD(Container, preferredFocusedGrandChild, entity(entity));
+ ATTRIB(Container, focusable, float, 0)
+ ATTRIB(Container, firstChild, entity, NULL)
+ ATTRIB(Container, lastChild, entity, NULL)
+ ATTRIB(Container, focusedChild, entity, NULL)
+ ATTRIB(Container, savedFocus, entity, NULL)
+ ATTRIB(Container, shown, float, 0)
+
+ METHOD(Container, enterSubitem, void(entity, entity));
+ METHOD(Container, enterLieSubitem, void(entity, vector, vector, vector, float));
+ METHOD(Container, leaveSubitem, void(entity));
+ ENDCLASS(Container)
+ .entity nextSibling;
+ .entity prevSibling;
+ .float resized;
+ .vector Container_origin;
+ .vector Container_size;
+ .vector Container_fontscale;
+ .float Container_alpha;
+ .vector Container_save_shift;
+ .vector Container_save_scale;
+ .vector Container_save_fontscale;
+ .float Container_save_alpha;
#endif
#ifdef IMPLEMENTATION
-void Container_enterSubitem(entity me, entity sub)
-{
- me.enterLieSubitem(me, sub.Container_origin, sub.Container_size, sub.Container_fontscale, sub.Container_alpha);
-}
-
-void Container_enterLieSubitem(entity me, vector o, vector s, vector f, float a)
-{
- me.Container_save_shift = draw_shift;
- me.Container_save_scale = draw_scale;
- me.Container_save_alpha = draw_alpha;
- me.Container_save_fontscale = draw_fontscale;
-
- draw_shift = boxToGlobal(o, draw_shift, draw_scale);
- draw_scale = boxToGlobalSize(s, draw_scale);
- if(f != '0 0 0')
- draw_fontscale = boxToGlobalSize(f, draw_fontscale);
- draw_alpha *= a;
-}
-
-void Container_leaveSubitem(entity me)
-{
- draw_shift = me.Container_save_shift;
- draw_scale = me.Container_save_scale;
- draw_alpha = me.Container_save_alpha;
- draw_fontscale = me.Container_save_fontscale;
-}
-
-void Container_showNotify(entity me)
-{
- entity e;
- if(me.shown)
- return;
- me.shown = 1;
- for(e = me.firstChild; e; e = e.nextSibling)
- if(e.Container_alpha > 0)
- e.showNotify(e);
-}
-
-void Container_hideNotify(entity me)
-{
- entity e;
- if (!me.shown)
- return;
- me.shown = 0;
- for(e = me.firstChild; e; e = e.nextSibling)
- if(e.Container_alpha > 0)
- e.hideNotify(e);
-}
-
-void Container_setAlphaOf(entity me, entity other, float theAlpha)
-{
- if(theAlpha <= 0)
+ void Container_enterSubitem(entity me, entity sub)
{
- if(other.Container_alpha > 0)
- other.hideNotify(other);
+ me.enterLieSubitem(me, sub.Container_origin, sub.Container_size, sub.Container_fontscale, sub.Container_alpha);
}
- else // value > 0
+
+ void Container_enterLieSubitem(entity me, vector o, vector s, vector f, float a)
{
- if(other.Container_alpha <= 0)
- other.showNotify(other);
+ me.Container_save_shift = draw_shift;
+ me.Container_save_scale = draw_scale;
+ me.Container_save_alpha = draw_alpha;
+ me.Container_save_fontscale = draw_fontscale;
+
+ draw_shift = boxToGlobal(o, draw_shift, draw_scale);
+ draw_scale = boxToGlobalSize(s, draw_scale);
+ if (f != '0 0 0') draw_fontscale = boxToGlobalSize(f, draw_fontscale);
+ draw_alpha *= a;
}
- other.Container_alpha = theAlpha;
-}
-
-void Container_resizeNotifyLie(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize, .vector originField, .vector sizeField, .vector fontScaleField)
-{
- entity e;
- vector o, s;
- float d;
- for(e = me.firstChild; e; e = e.nextSibling)
+
+ void Container_leaveSubitem(entity me)
{
- o = e.(originField);
- s = e.(sizeField);
- me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
- e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
- me.leaveSubitem(me);
+ draw_shift = me.Container_save_shift;
+ draw_scale = me.Container_save_scale;
+ draw_alpha = me.Container_save_alpha;
+ draw_fontscale = me.Container_save_fontscale;
}
- do
+
+ void Container_showNotify(entity me)
{
- d = 0;
- for(e = me.firstChild; e; e = e.nextSibling)
- if(e.resized)
- {
- e.resized = 0;
- d = 1;
- o = e.(originField);
- s = e.(sizeField);
- me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
- e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
- me.leaveSubitem(me);
- }
+ entity e;
+ if (me.shown) return;
+ me.shown = 1;
+ for (e = me.firstChild; e; e = e.nextSibling)
+ if (e.Container_alpha > 0) e.showNotify(e);
+ }
+
+ void Container_hideNotify(entity me)
+ {
+ entity e;
+ if (!me.shown) return;
+ me.shown = 0;
+ for (e = me.firstChild; e; e = e.nextSibling)
+ if (e.Container_alpha > 0) e.hideNotify(e);
+ }
+
+ void Container_setAlphaOf(entity me, entity other, float theAlpha)
+ {
+ if (theAlpha <= 0)
+ {
+ if (other.Container_alpha > 0) other.hideNotify(other);
+ }
+ else // value > 0
+ {
+ if (other.Container_alpha <= 0) other.showNotify(other);
+ }
+ other.Container_alpha = theAlpha;
}
- while(d);
- SUPER(Container).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-}
-
-void Container_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Container_origin, Container_size, Container_fontscale);
-}
-
-entity Container_itemFromPoint(entity me, vector pos)
-{
- entity e;
- vector o, s;
- for(e = me.lastChild; e; e = e.prevSibling)
+
+ void Container_resizeNotifyLie(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize, .vector originField, .vector sizeField, .vector fontScaleField)
{
- o = e.Container_origin;
- s = e.Container_size;
- if(pos.x < o.x) continue;
- if(pos.y < o.y) continue;
- if(pos.x >= o.x + s.x) continue;
- if(pos.y >= o.y + s.y) continue;
- return e;
+ entity e;
+ vector o, s;
+ float d;
+ for (e = me.firstChild; e; e = e.nextSibling)
+ {
+ o = e.(originField);
+ s = e.(sizeField);
+ me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
+ e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
+ me.leaveSubitem(me);
+ }
+ do
+ {
+ d = 0;
+ for (e = me.firstChild; e; e = e.nextSibling)
+ if (e.resized)
+ {
+ e.resized = 0;
+ d = 1;
+ o = e.(originField);
+ s = e.(sizeField);
+ me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
+ e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
+ me.leaveSubitem(me);
+ }
+ }
+ while (d);
+ SUPER(Container).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
}
- return NULL;
-}
-void Container_draw(entity me)
-{
- entity e;
+ void Container_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+ {
+ me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Container_origin, Container_size, Container_fontscale);
+ }
- me.focusable = 0;
- for(e = me.firstChild; e; e = e.nextSibling)
+ entity Container_itemFromPoint(entity me, vector pos)
{
- if(e.focusable)
- me.focusable += 1;
- if(e.Container_alpha < 0.003) // can't change color values anyway
- continue;
- me.enterSubitem(me, e);
- e.draw(e);
- me.leaveSubitem(me);
+ entity e;
+ vector o, s;
+ for (e = me.lastChild; e; e = e.prevSibling)
+ {
+ o = e.Container_origin;
+ s = e.Container_size;
+ if (pos.x < o.x) continue;
+ if (pos.y < o.y) continue;
+ if (pos.x >= o.x + s.x) continue;
+ if (pos.y >= o.y + s.y) continue;
+ return e;
+ }
+ return NULL;
}
- SUPER(Container).draw(me);
-}
+ void Container_draw(entity me)
+ {
+ entity e;
+
+ me.focusable = 0;
+ for (e = me.firstChild; e; e = e.nextSibling)
+ {
+ if (e.focusable) me.focusable += 1;
+ if (e.Container_alpha < 0.003) // can't change color values anyway
+ continue;
+ me.enterSubitem(me, e);
+ e.draw(e);
+ me.leaveSubitem(me);
+ }
-void Container_focusLeave(entity me)
-{
- me.setFocus(me, NULL);
-}
+ SUPER(Container).draw(me);
+ }
-float Container_keyUp(entity me, float scan, float ascii, float shift)
-{
- entity f;
- float r;
- f = me.focusedChild;
- if(f)
+ void Container_focusLeave(entity me)
{
- me.enterSubitem(me, f);
- r = f.keyUp(f, scan, ascii, shift);
- me.leaveSubitem(me);
- return r;
+ me.setFocus(me, NULL);
}
- return 0;
-}
-
-float Container_keyDown(entity me, float scan, float ascii, float shift)
-{
- entity f;
- float r;
- f = me.focusedChild;
- if(f)
+
+ float Container_keyUp(entity me, float scan, float ascii, float shift)
{
- me.enterSubitem(me, f);
- r = f.keyDown(f, scan, ascii, shift);
- me.leaveSubitem(me);
- return r;
+ entity f;
+ float r;
+ f = me.focusedChild;
+ if (f)
+ {
+ me.enterSubitem(me, f);
+ r = f.keyUp(f, scan, ascii, shift);
+ me.leaveSubitem(me);
+ return r;
+ }
+ return 0;
}
- return 0;
-}
-
-float Container_mouseMove(entity me, vector pos)
-{
- entity f;
- float r;
- f = me.focusedChild;
- if(f)
+
+ float Container_keyDown(entity me, float scan, float ascii, float shift)
{
- me.enterSubitem(me, f);
- r = f.mouseMove(f, globalToBox(pos, f.Container_origin, f.Container_size));
- me.leaveSubitem(me);
- return r;
+ entity f;
+ float r;
+ f = me.focusedChild;
+ if (f)
+ {
+ me.enterSubitem(me, f);
+ r = f.keyDown(f, scan, ascii, shift);
+ me.leaveSubitem(me);
+ return r;
+ }
+ return 0;
}
- return 0;
-}
-float Container_mousePress(entity me, vector pos)
-{
- entity f;
- float r;
- f = me.focusedChild;
- if(f)
+
+ float Container_mouseMove(entity me, vector pos)
{
- me.enterSubitem(me, f);
- r = f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
- me.leaveSubitem(me);
- return r;
+ entity f;
+ float r;
+ f = me.focusedChild;
+ if (f)
+ {
+ me.enterSubitem(me, f);
+ r = f.mouseMove(f, globalToBox(pos, f.Container_origin, f.Container_size));
+ me.leaveSubitem(me);
+ return r;
+ }
+ return 0;
}
- return 0;
-}
-float Container_mouseDrag(entity me, vector pos)
-{
- entity f;
- float r;
- f = me.focusedChild;
- if(f)
+ float Container_mousePress(entity me, vector pos)
{
- me.enterSubitem(me, f);
- r = f.mouseDrag(f, globalToBox(pos, f.Container_origin, f.Container_size));
- me.leaveSubitem(me);
- return r;
+ entity f;
+ float r;
+ f = me.focusedChild;
+ if (f)
+ {
+ me.enterSubitem(me, f);
+ r = f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
+ me.leaveSubitem(me);
+ return r;
+ }
+ return 0;
}
- return 0;
-}
-float Container_mouseRelease(entity me, vector pos)
-{
- entity f;
- float r;
- f = me.focusedChild;
- if(f)
+ float Container_mouseDrag(entity me, vector pos)
{
- me.enterSubitem(me, f);
- r = f.mouseRelease(f, globalToBox(pos, f.Container_origin, f.Container_size));
- me.leaveSubitem(me);
- return r;
+ entity f;
+ float r;
+ f = me.focusedChild;
+ if (f)
+ {
+ me.enterSubitem(me, f);
+ r = f.mouseDrag(f, globalToBox(pos, f.Container_origin, f.Container_size));
+ me.leaveSubitem(me);
+ return r;
+ }
+ return 0;
+ }
+ float Container_mouseRelease(entity me, vector pos)
+ {
+ entity f;
+ float r;
+ f = me.focusedChild;
+ if (f)
+ {
+ me.enterSubitem(me, f);
+ r = f.mouseRelease(f, globalToBox(pos, f.Container_origin, f.Container_size));
+ me.leaveSubitem(me);
+ return r;
+ }
+ return 0;
}
- return 0;
-}
-
-void Container_addItemCentered(entity me, entity other, vector theSize, float theAlpha)
-{
- me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha);
-}
-
-void Container_addItemRightCentered(entity me, entity other, vector theSize, float theAlpha)
-{
- me.addItem(me, other, '1 0.5 0' - 0.5 * theSize, theSize, theAlpha);
-}
-
-void Container_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
-{
- if(other.parent)
- error("Can't add already added item!");
- if(other.focusable)
- me.focusable += 1;
+ void Container_addItemCentered(entity me, entity other, vector theSize, float theAlpha)
+ {
+ me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha);
+ }
- if(theSize.x > 1)
+ void Container_addItemRightCentered(entity me, entity other, vector theSize, float theAlpha)
{
- theOrigin.x -= 0.5 * (theSize.x - 1);
- theSize.x = 1;
+ me.addItem(me, other, '1 0.5 0' - 0.5 * theSize, theSize, theAlpha);
}
- if(theSize.y > 1)
+
+ void Container_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
{
- theOrigin.y -= 0.5 * (theSize.y - 1);
- theSize.y = 1;
+ if (other.parent) error("Can't add already added item!");
+
+ if (other.focusable) me.focusable += 1;
+
+ if (theSize.x > 1)
+ {
+ theOrigin.x -= 0.5 * (theSize.x - 1);
+ theSize.x = 1;
+ }
+ if (theSize.y > 1)
+ {
+ theOrigin.y -= 0.5 * (theSize.y - 1);
+ theSize.y = 1;
+ }
+ theOrigin.x = bound(0, theOrigin.x, 1 - theSize.x);
+ theOrigin.y = bound(0, theOrigin.y, 1 - theSize.y);
+
+ other.parent = me;
+ other.Container_origin = theOrigin;
+ other.Container_size = theSize;
+ me.setAlphaOf(me, other, theAlpha);
+
+ entity l;
+ l = me.lastChild;
+
+ if (l) l.nextSibling = other;
+ else me.firstChild = other;
+
+ other.prevSibling = l;
+ other.nextSibling = NULL;
+ me.lastChild = other;
}
- theOrigin.x = bound(0, theOrigin.x, 1 - theSize.x);
- theOrigin.y = bound(0, theOrigin.y, 1 - theSize.y);
-
- other.parent = me;
- other.Container_origin = theOrigin;
- other.Container_size = theSize;
- me.setAlphaOf(me, other, theAlpha);
-
- entity l;
- l = me.lastChild;
-
- if(l)
- l.nextSibling = other;
- else
- me.firstChild = other;
-
- other.prevSibling = l;
- other.nextSibling = NULL;
- me.lastChild = other;
-}
-
-void Container_removeItem(entity me, entity other)
-{
- if(other.parent != me)
- error("Can't remove from wrong container!");
-
- if(other.focusable)
- me.focusable -= 1;
-
- other.parent = NULL;
-
- entity n, p;
- n = other.nextSibling;
- p = other.prevSibling;
-
- if(p)
- p.nextSibling = n;
- else
- me.firstChild = n;
-
- if(n)
- n.prevSibling = p;
- else
- me.lastChild = p;
-}
-
-void Container_setFocus(entity me, entity other)
-{
- if(me.focusedChild == other)
- return;
-
- if(me.focusedChild)
+
+ void Container_removeItem(entity me, entity other)
{
- me.focusedChild.focused = 0;
- me.focusedChild.focusLeave(me.focusedChild);
- me.focusedChild = NULL;
+ if (other.parent != me) error("Can't remove from wrong container!");
+
+ if (other.focusable) me.focusable -= 1;
+
+ other.parent = NULL;
+
+ entity n, p;
+ n = other.nextSibling;
+ p = other.prevSibling;
+
+ if (p) p.nextSibling = n;
+ else me.firstChild = n;
+
+ if (n) n.prevSibling = p;
+ else me.lastChild = p;
}
- if(other)
+ void Container_setFocus(entity me, entity other)
{
- if(!me.focused)
- error("Trying to set focus in a non-focused control!");
+ if (me.focusedChild == other) return;
- if(me.savedFocus)
+ if (me.focusedChild)
{
- me.focusedChild = me.savedFocus;
- me.savedFocus = NULL;
- me.focusedChild.focused = 1;
- me.focusedChild.focusEnter(me.focusedChild);
-
- if(me.focusedChild.instanceOfContainer)
- me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
+ me.focusedChild.focused = 0;
+ me.focusedChild.focusLeave(me.focusedChild);
+ me.focusedChild = NULL;
}
- else
+
+ if (other)
{
- me.focusedChild = other;
- me.focusedChild.focused = 1;
- me.focusedChild.focusEnter(me.focusedChild);
+ if (!me.focused) error("Trying to set focus in a non-focused control!");
+
+ if (me.savedFocus)
+ {
+ me.focusedChild = me.savedFocus;
+ me.savedFocus = NULL;
+ me.focusedChild.focused = 1;
+ me.focusedChild.focusEnter(me.focusedChild);
+
+ if (me.focusedChild.instanceOfContainer) me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
+ }
+ else
+ {
+ me.focusedChild = other;
+ me.focusedChild.focused = 1;
+ me.focusedChild.focusEnter(me.focusedChild);
+ }
}
}
-}
-
-void Container_saveFocus(entity me)
-{
- me.savedFocus = me.focusedChild;
-
- if(me.focusedChild.instanceOfContainer)
- me.focusedChild.saveFocus(me.focusedChild);
-}
-
-void Container_moveItemAfter(entity me, entity other, entity dest)
-{
- // first: remove other from the chain
- entity n, p;
-
- if(other.parent != me)
- error("Can't move in wrong container!");
-
- n = other.nextSibling;
- p = other.prevSibling;
-
- if(p)
- p.nextSibling = n;
- else
- me.firstChild = n;
-
- if(n)
- n.prevSibling = p;
- else
- me.lastChild = p;
-
- // now other got removed. Insert it behind dest now.
- other.prevSibling = dest;
- if(dest)
- other.nextSibling = dest.nextSibling;
- else
- other.nextSibling = me.firstChild;
-
- if(dest)
- dest.nextSibling = other;
- else
- me.firstChild = other;
-
- if(other.nextSibling)
- other.nextSibling.prevSibling = other;
- else
- me.lastChild = other;
-}
-entity Container_preferredFocusedGrandChild(entity me)
-{
- entity e, e2;
- entity best;
+ void Container_saveFocus(entity me)
+ {
+ me.savedFocus = me.focusedChild;
+
+ if (me.focusedChild.instanceOfContainer) me.focusedChild.saveFocus(me.focusedChild);
+ }
+
+ void Container_moveItemAfter(entity me, entity other, entity dest)
+ {
+ // first: remove other from the chain
+ entity n, p;
+
+ if (other.parent != me) error("Can't move in wrong container!");
- best = NULL;
+ n = other.nextSibling;
+ p = other.prevSibling;
- for(e = me.firstChild; e; e = e.nextSibling)
+ if (p) p.nextSibling = n;
+ else me.firstChild = n;
+
+ if (n) n.prevSibling = p;
+ else me.lastChild = p;
+
+ // now other got removed. Insert it behind dest now.
+ other.prevSibling = dest;
+ if (dest) other.nextSibling = dest.nextSibling;
+ else other.nextSibling = me.firstChild;
+
+ if (dest) dest.nextSibling = other;
+ else me.firstChild = other;
+
+ if (other.nextSibling) other.nextSibling.prevSibling = other;
+ else me.lastChild = other;
+ }
+
+ entity Container_preferredFocusedGrandChild(entity me)
{
- if(e.instanceOfContainer)
+ entity e, e2;
+ entity best;
+
+ best = NULL;
+
+ for (e = me.firstChild; e; e = e.nextSibling)
{
- e2 = e.preferredFocusedGrandChild(e);
- if(e2)
- if(!best || best.preferredFocusPriority < e2.preferredFocusPriority)
- best = e2;
+ if (e.instanceOfContainer)
+ {
+ e2 = e.preferredFocusedGrandChild(e);
+ if (e2)
+ if (!best || best.preferredFocusPriority < e2.preferredFocusPriority) best = e2;
+ }
+ if (e)
+ if (!best || best.preferredFocusPriority < e.preferredFocusPriority) best = e;
}
- if(e)
- if(!best || best.preferredFocusPriority < e.preferredFocusPriority)
- best = e;
- }
- return best;
-}
+ return best;
+ }
#endif
// a subclass may help with using this as a tab
#ifndef ITEM_DIALOG_H
-#define ITEM_DIALOG_H
-#include "inputcontainer.qc"
-CLASS(Dialog, InputContainer)
- METHOD(Dialog, configureDialog, void(entity)); // no runtime configuration, all parameters are given in the code!
- METHOD(Dialog, fill, void(entity)); // to be overridden by user to fill the dialog with controls
- METHOD(Dialog, keyDown, float(entity, float, float, float));
- METHOD(Dialog, close, void(entity));
- METHOD(Dialog, addItemSimple, void(entity, float, float, float, float, entity, vector));
-
- METHOD(Dialog, TD, void(entity, float, float, entity));
- METHOD(Dialog, TDNoMargin, void(entity, float, float, entity, vector));
- METHOD(Dialog, TDempty, void(entity, float));
- METHOD(Dialog, setFirstColumn, void(entity, float));
- METHOD(Dialog, TR, void(entity));
- METHOD(Dialog, gotoRC, void(entity, float, float));
-
- ATTRIB(Dialog, isTabRoot, float, 1)
- ATTRIB(Dialog, closeButton, entity, NULL)
- ATTRIB(Dialog, intendedHeight, float, 0)
- ATTRIB(Dialog, itemOrigin, vector, '0 0 0')
- ATTRIB(Dialog, itemSize, vector, '0 0 0')
- ATTRIB(Dialog, itemSpacing, vector, '0 0 0')
- ATTRIB(Dialog, currentRow, float, 0)
- ATTRIB(Dialog, currentColumn, float, 0)
- ATTRIB(Dialog, firstColumn, float, 0)
-
- // to be customized
- ATTRIB(Dialog, closable, float, 1)
- ATTRIB(Dialog, title, string, "Form1") // ;)
- ATTRIB(Dialog, color, vector, '1 0.5 1')
- ATTRIB(Dialog, intendedWidth, float, 0)
- ATTRIB(Dialog, rows, float, 3)
- ATTRIB(Dialog, columns, float, 2)
-
- ATTRIB(Dialog, marginTop, float, 0) // pixels
- ATTRIB(Dialog, marginBottom, float, 0) // pixels
- ATTRIB(Dialog, marginLeft, float, 0) // pixels
- ATTRIB(Dialog, marginRight, float, 0) // pixels
- ATTRIB(Dialog, columnSpacing, float, 0) // pixels
- ATTRIB(Dialog, rowSpacing, float, 0) // pixels
- ATTRIB(Dialog, rowHeight, float, 0) // pixels
- ATTRIB(Dialog, titleHeight, float, 0) // pixels
- ATTRIB(Dialog, titleFontSize, float, 0) // pixels; if 0, title causes no margin
- ATTRIB(Dialog, zoomedOutTitleBarPosition, float, 0)
- ATTRIB(Dialog, zoomedOutTitleBar, float, 0)
-
- ATTRIB(Dialog, requiresConnection, float, 0) // set to true if the dialog requires a connection to be opened
-
- ATTRIB(Dialog, backgroundImage, string, string_null)
- ATTRIB(Dialog, borderLines, float, 1)
- ATTRIB(Dialog, closeButtonImage, string, string_null)
-
- ATTRIB(Dialog, frame, entity, NULL)
-ENDCLASS(Dialog)
+ #define ITEM_DIALOG_H
+ #include "inputcontainer.qc"
+ CLASS(Dialog, InputContainer)
+ METHOD(Dialog, configureDialog, void(entity)); // no runtime configuration, all parameters are given in the code!
+ METHOD(Dialog, fill, void(entity)); // to be overridden by user to fill the dialog with controls
+ METHOD(Dialog, keyDown, float(entity, float, float, float));
+ METHOD(Dialog, close, void(entity));
+ METHOD(Dialog, addItemSimple, void(entity, float, float, float, float, entity, vector));
+
+ METHOD(Dialog, TD, void(entity, float, float, entity));
+ METHOD(Dialog, TDNoMargin, void(entity, float, float, entity, vector));
+ METHOD(Dialog, TDempty, void(entity, float));
+ METHOD(Dialog, setFirstColumn, void(entity, float));
+ METHOD(Dialog, TR, void(entity));
+ METHOD(Dialog, gotoRC, void(entity, float, float));
+
+ ATTRIB(Dialog, isTabRoot, float, 1)
+ ATTRIB(Dialog, closeButton, entity, NULL)
+ ATTRIB(Dialog, intendedHeight, float, 0)
+ ATTRIB(Dialog, itemOrigin, vector, '0 0 0')
+ ATTRIB(Dialog, itemSize, vector, '0 0 0')
+ ATTRIB(Dialog, itemSpacing, vector, '0 0 0')
+ ATTRIB(Dialog, currentRow, float, 0)
+ ATTRIB(Dialog, currentColumn, float, 0)
+ ATTRIB(Dialog, firstColumn, float, 0)
+
+ // to be customized
+ ATTRIB(Dialog, closable, float, 1)
+ ATTRIB(Dialog, title, string, "Form1") // ;)
+ ATTRIB(Dialog, color, vector, '1 0.5 1')
+ ATTRIB(Dialog, intendedWidth, float, 0)
+ ATTRIB(Dialog, rows, float, 3)
+ ATTRIB(Dialog, columns, float, 2)
+
+ ATTRIB(Dialog, marginTop, float, 0) // pixels
+ ATTRIB(Dialog, marginBottom, float, 0) // pixels
+ ATTRIB(Dialog, marginLeft, float, 0) // pixels
+ ATTRIB(Dialog, marginRight, float, 0) // pixels
+ ATTRIB(Dialog, columnSpacing, float, 0) // pixels
+ ATTRIB(Dialog, rowSpacing, float, 0) // pixels
+ ATTRIB(Dialog, rowHeight, float, 0) // pixels
+ ATTRIB(Dialog, titleHeight, float, 0) // pixels
+ ATTRIB(Dialog, titleFontSize, float, 0) // pixels; if 0, title causes no margin
+ ATTRIB(Dialog, zoomedOutTitleBarPosition, float, 0)
+ ATTRIB(Dialog, zoomedOutTitleBar, float, 0)
+
+ ATTRIB(Dialog, requiresConnection, float, 0) // set to true if the dialog requires a connection to be opened
+
+ ATTRIB(Dialog, backgroundImage, string, string_null)
+ ATTRIB(Dialog, borderLines, float, 1)
+ ATTRIB(Dialog, closeButtonImage, string, string_null)
+
+ ATTRIB(Dialog, frame, entity, NULL)
+ ENDCLASS(Dialog)
#endif
#ifdef IMPLEMENTATION
-void Dialog_Close(entity button, entity me)
-{
- me.close(me);
-}
-
-void Dialog_fill(entity me)
-{
-}
-
-void Dialog_addItemSimple(entity me, float row, float col, float rowspan, float colspan, entity e, vector v)
-{
- vector o, s;
- o = me.itemOrigin + eX * ( col * me.itemSpacing.x) + eY * ( row * me.itemSpacing.y);
- s = me.itemSize + eX * ((colspan - 1) * me.itemSpacing.x) + eY * ((rowspan - 1) * me.itemSpacing.y);
- o.x -= 0.5 * (me.itemSpacing.x - me.itemSize.x) * v.x;
- s.x += (me.itemSpacing.x - me.itemSize.x) * v.x;
- o.y -= 0.5 * (me.itemSpacing.y - me.itemSize.y) * v.y;
- s.y += (me.itemSpacing.y - me.itemSize.y) * v.y;
- me.addItem(me, e, o, s, 1);
-}
-
-void Dialog_gotoRC(entity me, float row, float col)
-{
- me.currentRow = row;
- me.currentColumn = col;
-}
-
-void Dialog_TR(entity me)
-{
- me.currentRow += 1;
- me.currentColumn = me.firstColumn;
-}
-
-void Dialog_TD(entity me, float rowspan, float colspan, entity e)
-{
- me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, '0 0 0');
- me.currentColumn += colspan;
-}
-
-void Dialog_TDNoMargin(entity me, float rowspan, float colspan, entity e, vector v)
-{
- me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, v);
- me.currentColumn += colspan;
-}
-
-void Dialog_setFirstColumn(entity me, float col)
-{
- me.firstColumn = col;
-}
-
-void Dialog_TDempty(entity me, float colspan)
-{
- me.currentColumn += colspan;
-}
-
-void Dialog_configureDialog(entity me)
-{
- float absWidth, absHeight;
-
- if(me.isTabRoot)
+ void Dialog_Close(entity button, entity me)
{
- me.frame = NEW(BorderImage);
- me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.borderLines * me.titleHeight);
- me.frame.zoomedOutTitleBarPosition = me.zoomedOutTitleBarPosition;
- me.frame.zoomedOutTitleBar = me.zoomedOutTitleBar;
- me.frame.alpha = me.alpha;
- me.addItem(me, me.frame, '0 0 0', '1 1 0', 1);
+ me.close(me);
}
- if (!me.titleFontSize)
- me.titleHeight = 0; // no title bar
-
- absWidth = me.intendedWidth * conwidth;
- absHeight = me.borderLines * me.titleHeight + me.marginTop + me.rows * me.rowHeight + (me.rows - 1) * me.rowSpacing + me.marginBottom;
- me.itemOrigin = eX * (me.marginLeft / absWidth)
- + eY * ((me.borderLines * me.titleHeight + me.marginTop) / absHeight);
- me.itemSize = eX * ((1 - (me.marginLeft + me.marginRight + me.columnSpacing * (me.columns - 1)) / absWidth) / me.columns)
- + eY * (me.rowHeight / absHeight);
- me.itemSpacing = me.itemSize
- + eX * (me.columnSpacing / absWidth)
- + eY * (me.rowSpacing / absHeight);
- me.intendedHeight = absHeight / conheight;
- me.currentRow = -1;
- me.currentColumn = -1;
-
- me.fill(me);
-
- if(me.isTabRoot && me.closable && me.borderLines > 0)
+ void Dialog_fill(entity me)
+ {}
+
+ void Dialog_addItemSimple(entity me, float row, float col, float rowspan, float colspan, entity e, vector v)
+ {
+ vector o, s;
+ o = me.itemOrigin + eX * (col * me.itemSpacing.x) + eY * (row * me.itemSpacing.y);
+ s = me.itemSize + eX * ((colspan - 1) * me.itemSpacing.x) + eY * ((rowspan - 1) * me.itemSpacing.y);
+ o.x -= 0.5 * (me.itemSpacing.x - me.itemSize.x) * v.x;
+ s.x += (me.itemSpacing.x - me.itemSize.x) * v.x;
+ o.y -= 0.5 * (me.itemSpacing.y - me.itemSize.y) * v.y;
+ s.y += (me.itemSpacing.y - me.itemSize.y) * v.y;
+ me.addItem(me, e, o, s, 1);
+ }
+
+ void Dialog_gotoRC(entity me, float row, float col)
{
- entity closebutton;
- closebutton = me.closeButton = me.frame.closeButton = NEW(Button);
- closebutton.configureButton(closebutton, "", 0, me.closeButtonImage);
- closebutton.onClick = Dialog_Close; closebutton.onClickEntity = me;
- closebutton.srcMulti = 0;
- me.addItem(me, closebutton, '0 0 0', '1 1 0', 1); // put it as LAST
+ me.currentRow = row;
+ me.currentColumn = col;
}
-}
-void Dialog_close(entity me)
-{
- if(me.parent.instanceOfNexposee)
+ void Dialog_TR(entity me)
{
- ExposeeCloseButton_Click(me, me.parent);
+ me.currentRow += 1;
+ me.currentColumn = me.firstColumn;
}
- else if(me.parent.instanceOfModalController)
+
+ void Dialog_TD(entity me, float rowspan, float colspan, entity e)
+ {
+ me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, '0 0 0');
+ me.currentColumn += colspan;
+ }
+
+ void Dialog_TDNoMargin(entity me, float rowspan, float colspan, entity e, vector v)
+ {
+ me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, v);
+ me.currentColumn += colspan;
+ }
+
+ void Dialog_setFirstColumn(entity me, float col)
+ {
+ me.firstColumn = col;
+ }
+
+ void Dialog_TDempty(entity me, float colspan)
+ {
+ me.currentColumn += colspan;
+ }
+
+ void Dialog_configureDialog(entity me)
+ {
+ float absWidth, absHeight;
+
+ if (me.isTabRoot)
+ {
+ me.frame = NEW(BorderImage);
+ me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.borderLines * me.titleHeight);
+ me.frame.zoomedOutTitleBarPosition = me.zoomedOutTitleBarPosition;
+ me.frame.zoomedOutTitleBar = me.zoomedOutTitleBar;
+ me.frame.alpha = me.alpha;
+ me.addItem(me, me.frame, '0 0 0', '1 1 0', 1);
+ }
+
+ if (!me.titleFontSize) me.titleHeight = 0; // no title bar
+
+ absWidth = me.intendedWidth * conwidth;
+ absHeight = me.borderLines * me.titleHeight + me.marginTop + me.rows * me.rowHeight + (me.rows - 1) * me.rowSpacing + me.marginBottom;
+ me.itemOrigin = eX * (me.marginLeft / absWidth)
+ + eY * ((me.borderLines * me.titleHeight + me.marginTop) / absHeight);
+ me.itemSize = eX * ((1 - (me.marginLeft + me.marginRight + me.columnSpacing * (me.columns - 1)) / absWidth) / me.columns)
+ + eY * (me.rowHeight / absHeight);
+ me.itemSpacing = me.itemSize
+ + eX * (me.columnSpacing / absWidth)
+ + eY * (me.rowSpacing / absHeight);
+ me.intendedHeight = absHeight / conheight;
+ me.currentRow = -1;
+ me.currentColumn = -1;
+
+ me.fill(me);
+
+ if (me.isTabRoot && me.closable && me.borderLines > 0)
+ {
+ entity closebutton;
+ closebutton = me.closeButton = me.frame.closeButton = NEW(Button);
+ closebutton.configureButton(closebutton, "", 0, me.closeButtonImage);
+ closebutton.onClick = Dialog_Close;
+ closebutton.onClickEntity = me;
+ closebutton.srcMulti = 0;
+ me.addItem(me, closebutton, '0 0 0', '1 1 0', 1); // put it as LAST
+ }
+ }
+
+ void Dialog_close(entity me)
{
- DialogCloseButton_Click(me, me);
+ if (me.parent.instanceOfNexposee) ExposeeCloseButton_Click(me, me.parent);
+ else if (me.parent.instanceOfModalController) DialogCloseButton_Click(me, me);
}
-}
-float Dialog_keyDown(entity me, float key, float ascii, float shift)
-{
- if(me.closable)
+ float Dialog_keyDown(entity me, float key, float ascii, float shift)
{
- if(key == K_ESCAPE)
+ if (me.closable)
{
- m_play_click_sound(MENU_SOUND_CLOSE);
- me.close(me);
- return 1;
+ if (key == K_ESCAPE)
+ {
+ m_play_click_sound(MENU_SOUND_CLOSE);
+ me.close(me);
+ return 1;
+ }
}
+ return SUPER(Dialog).keyDown(me, key, ascii, shift);
}
- return SUPER(Dialog).keyDown(me, key, ascii, shift);
-}
#endif
#ifndef ITEM_IMAGE_H
-#define ITEM_IMAGE_H
-#include "../item.qc"
-CLASS(Image, Item)
- METHOD(Image, configureImage, void(entity, string));
- METHOD(Image, draw, void(entity));
- METHOD(Image, toString, string(entity));
- METHOD(Image, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(Image, updateAspect, void(entity));
- METHOD(Image, initZoom, void(entity));
- METHOD(Image, setZoom, void(entity, float, float));
- METHOD(Image, drag_setStartPos, float(entity, vector));
- METHOD(Image, drag, float(entity, vector));
- ATTRIB(Image, src, string, string_null)
- ATTRIB(Image, color, vector, '1 1 1')
- ATTRIB(Image, forcedAspect, float, 0) // special values: -1 keep image aspect ratio, -2 keep image size but bound to the containing box, -3 always keep image size
- ATTRIB(Image, zoomBox, float, 0) // used by forcedAspect -2 when the image is larger than the containing box
- ATTRIB(Image, zoomFactor, float, 1)
- ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
- ATTRIB(Image, zoomSnapToTheBox, float, 1) // snap the zoomed in image to the box borders when zooming/dragging it
- ATTRIB(Image, zoomTime, float, 0)
- ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
- ATTRIB(Image, zoomMax, float, 0)
- ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
- ATTRIB(Image, start_coords, vector, '0 0 0')
- ATTRIB(Image, imgOrigin, vector, '0 0 0')
- ATTRIB(Image, imgSize, vector, '0 0 0')
-ENDCLASS(Image)
+ #define ITEM_IMAGE_H
+ #include "../item.qc"
+ CLASS(Image, Item)
+ METHOD(Image, configureImage, void(entity, string));
+ METHOD(Image, draw, void(entity));
+ METHOD(Image, toString, string(entity));
+ METHOD(Image, resizeNotify, void(entity, vector, vector, vector, vector));
+ METHOD(Image, updateAspect, void(entity));
+ METHOD(Image, initZoom, void(entity));
+ METHOD(Image, setZoom, void(entity, float, float));
+ METHOD(Image, drag_setStartPos, float(entity, vector));
+ METHOD(Image, drag, float(entity, vector));
+ ATTRIB(Image, src, string, string_null)
+ ATTRIB(Image, color, vector, '1 1 1')
+ ATTRIB(Image, forcedAspect, float, 0) // special values: -1 keep image aspect ratio, -2 keep image size but bound to the containing box, -3 always keep image size
+ ATTRIB(Image, zoomBox, float, 0) // used by forcedAspect -2 when the image is larger than the containing box
+ ATTRIB(Image, zoomFactor, float, 1)
+ ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
+ ATTRIB(Image, zoomSnapToTheBox, float, 1) // snap the zoomed in image to the box borders when zooming/dragging it
+ ATTRIB(Image, zoomTime, float, 0)
+ ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
+ ATTRIB(Image, zoomMax, float, 0)
+ ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
+ ATTRIB(Image, start_coords, vector, '0 0 0')
+ ATTRIB(Image, imgOrigin, vector, '0 0 0')
+ ATTRIB(Image, imgSize, vector, '0 0 0')
+ ENDCLASS(Image)
#endif
#ifdef IMPLEMENTATION
-string Image_toString(entity me)
-{
- return me.src;
-}
-void Image_configureImage(entity me, string path)
-{
- me.src = path;
-}
-void Image_initZoom(entity me)
-{
- me.zoomOffset = '0.5 0.5 0';
- me.zoomFactor = 1;
- if (me.forcedAspect == -2)
- me.zoomBox = -1; // calculate zoomBox at the first updateAspect call
- if (me.zoomLimitedByTheBox)
- me.zoomMax = -1; // calculate zoomMax at the first updateAspect call
-}
+ string Image_toString(entity me)
+ {
+ return me.src;
+ }
+ void Image_configureImage(entity me, string path)
+ {
+ me.src = path;
+ }
+ void Image_initZoom(entity me)
+ {
+ me.zoomOffset = '0.5 0.5 0';
+ me.zoomFactor = 1;
+ if (me.forcedAspect == -2) me.zoomBox = -1; // calculate zoomBox at the first updateAspect call
+ if (me.zoomLimitedByTheBox) me.zoomMax = -1; // calculate zoomMax at the first updateAspect call
+ }
-void Image_draw(entity me)
-{
- if(me.imgSize.x > 1 || me.imgSize.y > 1)
- draw_SetClip();
- draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
- if(me.imgSize.x > 1 || me.imgSize.y > 1)
- draw_ClearClip();
- SUPER(Image).draw(me);
-}
-void Image_updateAspect(entity me)
-{
- float asp = 0;
- if(me.size.x <= 0 || me.size.y <= 0)
- return;
- if(me.forcedAspect == 0)
+ void Image_draw(entity me)
{
- me.imgOrigin = '0 0 0';
- me.imgSize = '1 1 0';
+ if (me.imgSize.x > 1 || me.imgSize.y > 1) draw_SetClip();
+ draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
+ if (me.imgSize.x > 1 || me.imgSize.y > 1) draw_ClearClip();
+ SUPER(Image).draw(me);
}
- else
+ void Image_updateAspect(entity me)
{
- vector sz = '0 0 0';
- if(me.forcedAspect < 0)
+ float asp = 0;
+ if (me.size.x <= 0 || me.size.y <= 0) return;
+ if (me.forcedAspect == 0)
{
- if (me.src != "")
- sz = draw_PictureSize(me.src);
- if(sz.x <= 0 || sz.y <= 0)
- {
- // image is broken or doesn't exist, set the size for the placeholder image
- sz.x = me.size.x;
- sz.y = me.size.y;
- }
- asp = sz.x / sz.y;
+ me.imgOrigin = '0 0 0';
+ me.imgSize = '1 1 0';
}
else
- asp = me.forcedAspect;
-
- if(me.forcedAspect <= -2)
{
- me.imgSize_x = sz.x / me.size.x;
- me.imgSize_y = sz.y / me.size.y;
- if(me.zoomBox < 0 && (me.imgSize.x > 1 || me.imgSize.y > 1))
+ vector sz = '0 0 0';
+ if (me.forcedAspect < 0)
{
- // image larger than the containing box, zoom it out to fit into the box
- if(me.size.x > asp * me.size.y)
- me.zoomBox = (me.size.y * asp / me.size.x) / me.imgSize.x;
- else
- me.zoomBox = (me.size.x / (asp * me.size.y)) / me.imgSize.y;
- me.zoomFactor = me.zoomBox;
+ if (me.src != "") sz = draw_PictureSize(me.src);
+ if (sz.x <= 0 || sz.y <= 0)
+ {
+ // image is broken or doesn't exist, set the size for the placeholder image
+ sz.x = me.size.x;
+ sz.y = me.size.y;
+ }
+ asp = sz.x / sz.y;
}
- }
- else
- {
- if(me.size.x > asp * me.size.y)
+ else
{
- // x too large, so center x-wise
- me.imgSize = eY + eX * (me.size.y * asp / me.size.x);
+ asp = me.forcedAspect;
+ }
+
+ if (me.forcedAspect <= -2)
+ {
+ me.imgSize_x = sz.x / me.size.x;
+ me.imgSize_y = sz.y / me.size.y;
+ if (me.zoomBox < 0 && (me.imgSize.x > 1 || me.imgSize.y > 1))
+ {
+ // image larger than the containing box, zoom it out to fit into the box
+ if (me.size.x > asp * me.size.y) me.zoomBox = (me.size.y * asp / me.size.x) / me.imgSize.x;
+ else me.zoomBox = (me.size.x / (asp * me.size.y)) / me.imgSize.y;
+ me.zoomFactor = me.zoomBox;
+ }
}
else
{
- // y too large, so center y-wise
- me.imgSize = eX + eY * (me.size.x / (asp * me.size.y));
+ if (me.size.x > asp * me.size.y)
+ {
+ // x too large, so center x-wise
+ me.imgSize = eY + eX * (me.size.y * asp / me.size.x);
+ }
+ else
+ {
+ // y too large, so center y-wise
+ me.imgSize = eX + eY * (me.size.x / (asp * me.size.y));
+ }
}
}
- }
- if (me.zoomMax < 0)
- {
- if(me.zoomBox > 0)
- me.zoomMax = me.zoomBox;
- else
+ if (me.zoomMax < 0)
{
- if(me.size.x > asp * me.size.y)
- me.zoomMax = (me.size.y * asp / me.size.x) / me.imgSize.x;
+ if (me.zoomBox > 0)
+ {
+ me.zoomMax = me.zoomBox;
+ }
else
- me.zoomMax = (me.size.x / (asp * me.size.y)) / me.imgSize.y;
+ {
+ if (me.size.x > asp * me.size.y) me.zoomMax = (me.size.y * asp / me.size.x) / me.imgSize.x;
+ else me.zoomMax = (me.size.x / (asp * me.size.y)) / me.imgSize.y;
+ }
}
- }
- if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
- me.zoomFactor = me.zoomMax;
- if (me.zoomFactor)
- me.imgSize = me.imgSize * me.zoomFactor;
+ if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax) me.zoomFactor = me.zoomMax;
+ if (me.zoomFactor) me.imgSize = me.imgSize * me.zoomFactor;
- if(me.imgSize.x > 1 || me.imgSize.y > 1)
- {
- if(me.zoomSnapToTheBox)
+ if (me.imgSize.x > 1 || me.imgSize.y > 1)
{
- if(me.imgSize.x > 1)
- me.zoomOffset_x = bound(0.5/me.imgSize.x, me.zoomOffset.x, 1 - 0.5/me.imgSize.x);
- else
- me.zoomOffset_x = bound(1 - 0.5/me.imgSize.x, me.zoomOffset.x, 0.5/me.imgSize.x);
+ if (me.zoomSnapToTheBox)
+ {
+ if (me.imgSize.x > 1) me.zoomOffset_x = bound(0.5 / me.imgSize.x, me.zoomOffset.x, 1 - 0.5 / me.imgSize.x);
+ else me.zoomOffset_x = bound(1 - 0.5 / me.imgSize.x, me.zoomOffset.x, 0.5 / me.imgSize.x);
- if(me.imgSize.y > 1)
- me.zoomOffset_y = bound(0.5/me.imgSize.y, me.zoomOffset.y, 1 - 0.5/me.imgSize.y);
+ if (me.imgSize.y > 1) me.zoomOffset_y = bound(0.5 / me.imgSize.y, me.zoomOffset.y, 1 - 0.5 / me.imgSize.y);
+ else me.zoomOffset_y = bound(1 - 0.5 / me.imgSize.y, me.zoomOffset.y, 0.5 / me.imgSize.y);
+ }
else
- me.zoomOffset_y = bound(1 - 0.5/me.imgSize.y, me.zoomOffset.y, 0.5/me.imgSize.y);
+ {
+ me.zoomOffset_x = bound(0, me.zoomOffset.x, 1);
+ me.zoomOffset_y = bound(0, me.zoomOffset.y, 1);
+ }
}
else
{
- me.zoomOffset_x = bound(0, me.zoomOffset.x, 1);
- me.zoomOffset_y = bound(0, me.zoomOffset.y, 1);
+ me.zoomOffset = '0.5 0.5 0';
}
- }
- else
- me.zoomOffset = '0.5 0.5 0';
- me.imgOrigin_x = 0.5 - me.zoomOffset.x * me.imgSize.x;
- me.imgOrigin_y = 0.5 - me.zoomOffset.y * me.imgSize.y;
-}
-float Image_drag_setStartPos(entity me, vector coords)
-{
- //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
- {
- me.start_zoomOffset = me.zoomOffset;
- me.start_coords = coords;
- }
- return 1;
-}
-float Image_drag(entity me, vector coords)
-{
- if(me.imgSize.x > 1 || me.imgSize.y > 1)
- {
- me.zoomOffset_x = me.start_zoomOffset.x + (me.start_coords.x - coords.x) / me.imgSize.x;
- me.zoomOffset_y = me.start_zoomOffset.y + (me.start_coords.y - coords.y) / me.imgSize.y;
- me.updateAspect(me);
+ me.imgOrigin_x = 0.5 - me.zoomOffset.x * me.imgSize.x;
+ me.imgOrigin_y = 0.5 - me.zoomOffset.y * me.imgSize.y;
}
- return 1;
-}
-void Image_setZoom(entity me, float z, float atMousePosition)
-{
- float prev_zoomFactor;
- prev_zoomFactor = me.zoomFactor;
- if (z < 0) // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
+ float Image_drag_setStartPos(entity me, vector coords)
{
- me.zoomFactor *= -z;
- float realSize_in_the_middle, boxSize_in_the_middle;
- realSize_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
- boxSize_in_the_middle = (me.zoomBox > 0 && (prev_zoomFactor - me.zoomBox) * (me.zoomFactor - me.zoomBox) < 0);
- if (realSize_in_the_middle && boxSize_in_the_middle)
+ // if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
{
- // snap to real dimensions or to box
- if (prev_zoomFactor < me.zoomFactor)
- me.zoomFactor = min(1, me.zoomBox);
- else
- me.zoomFactor = max(1, me.zoomBox);
+ me.start_zoomOffset = me.zoomOffset;
+ me.start_coords = coords;
}
- else if (realSize_in_the_middle)
- me.zoomFactor = 1; // snap to real dimensions
- else if (boxSize_in_the_middle)
- me.zoomFactor = me.zoomBox; // snap to box
+ return 1;
}
- else if (z == 0) // reset (no zoom)
+ float Image_drag(entity me, vector coords)
{
- if (me.zoomBox > 0)
- me.zoomFactor = me.zoomBox;
- else
- me.zoomFactor = 1;
+ if (me.imgSize.x > 1 || me.imgSize.y > 1)
+ {
+ me.zoomOffset_x = me.start_zoomOffset.x + (me.start_coords.x - coords.x) / me.imgSize.x;
+ me.zoomOffset_y = me.start_zoomOffset.y + (me.start_coords.y - coords.y) / me.imgSize.y;
+ me.updateAspect(me);
+ }
+ return 1;
}
- else // directly set
- me.zoomFactor = z;
- me.zoomFactor = bound(1/16, me.zoomFactor, 16);
- if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
- me.zoomFactor = me.zoomMax;
- if (prev_zoomFactor != me.zoomFactor)
+ void Image_setZoom(entity me, float z, float atMousePosition)
{
- me.zoomTime = time;
- if (atMousePosition)
+ float prev_zoomFactor;
+ prev_zoomFactor = me.zoomFactor;
+ if (z < 0) // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
+ {
+ me.zoomFactor *= -z;
+ float realSize_in_the_middle, boxSize_in_the_middle;
+ realSize_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
+ boxSize_in_the_middle = (me.zoomBox > 0 && (prev_zoomFactor - me.zoomBox) * (me.zoomFactor - me.zoomBox) < 0);
+ if (realSize_in_the_middle && boxSize_in_the_middle)
+ {
+ // snap to real dimensions or to box
+ if (prev_zoomFactor < me.zoomFactor) me.zoomFactor = min(1, me.zoomBox);
+ else me.zoomFactor = max(1, me.zoomBox);
+ }
+ else if (realSize_in_the_middle)
+ {
+ me.zoomFactor = 1; // snap to real dimensions
+ }
+ else if (boxSize_in_the_middle)
+ {
+ me.zoomFactor = me.zoomBox; // snap to box
+ }
+ }
+ else if (z == 0) // reset (no zoom)
+ {
+ if (me.zoomBox > 0) me.zoomFactor = me.zoomBox;
+ else me.zoomFactor = 1;
+ }
+ else // directly set
{
- me.zoomOffset_x = me.start_zoomOffset.x + (me.start_coords.x - 0.5) / me.imgSize.x;
- me.zoomOffset_y = me.start_zoomOffset.y + (me.start_coords.y - 0.5) / me.imgSize.y;
- // updateAspect will reset zoomOffset to '0.5 0.5 0' if
- // with this zoomFactor the image will not be zoomed in
- // (updateAspect will check the new values of imgSize).
+ me.zoomFactor = z;
}
+ me.zoomFactor = bound(1 / 16, me.zoomFactor, 16);
+ if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax) me.zoomFactor = me.zoomMax;
+ if (prev_zoomFactor != me.zoomFactor)
+ {
+ me.zoomTime = time;
+ if (atMousePosition)
+ {
+ me.zoomOffset_x = me.start_zoomOffset.x + (me.start_coords.x - 0.5) / me.imgSize.x;
+ me.zoomOffset_y = me.start_zoomOffset.y + (me.start_coords.y - 0.5) / me.imgSize.y;
+ // updateAspect will reset zoomOffset to '0.5 0.5 0' if
+ // with this zoomFactor the image will not be zoomed in
+ // (updateAspect will check the new values of imgSize).
+ }
+ }
+ me.updateAspect(me);
+ }
+ void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+ {
+ SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+ me.updateAspect(me);
}
- me.updateAspect(me);
-}
-void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
- me.updateAspect(me);
-}
#endif
#ifndef ITEM_INPUTBOX_H
-#define ITEM_INPUTBOX_H
-#include "label.qc"
-CLASS(InputBox, Label)
- METHOD(InputBox, configureInputBox, void(entity, string, float, float, string));
- METHOD(InputBox, draw, void(entity));
- METHOD(InputBox, setText, void(entity, string));
- METHOD(InputBox, enterText, void(entity, string));
- METHOD(InputBox, keyDown, float(entity, float, float, float));
- METHOD(InputBox, mouseMove, float(entity, vector));
- METHOD(InputBox, mouseRelease, float(entity, vector));
- METHOD(InputBox, mousePress, float(entity, vector));
- METHOD(InputBox, mouseDrag, float(entity, vector));
- METHOD(InputBox, showNotify, void(entity));
- METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector));
-
- ATTRIB(InputBox, src, string, string_null)
-
- ATTRIB(InputBox, cursorPos, float, 0) // characters
- ATTRIB(InputBox, scrollPos, float, 0) // widths
-
- ATTRIB(InputBox, focusable, float, 1)
- ATTRIB(InputBox, allowFocusSound, float, 1)
- ATTRIB(InputBox, disabled, float, 0)
- ATTRIB(InputBox, lastChangeTime, float, 0)
- ATTRIB(InputBox, dragScrollTimer, float, 0)
- ATTRIB(InputBox, dragScrollPos, vector, '0 0 0')
- ATTRIB(InputBox, pressed, float, 0)
- ATTRIB(InputBox, editColorCodes, float, 1)
- ATTRIB(InputBox, forbiddenCharacters, string, "")
- ATTRIB(InputBox, color, vector, '1 1 1')
- ATTRIB(InputBox, colorF, vector, '1 1 1')
- ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
-
- ATTRIB(InputBox, enableClearButton, float, 1)
- ATTRIB(InputBox, clearButton, entity, NULL)
- ATTRIB(InputBox, cb_width, float, 0)
- ATTRIB(InputBox, cb_pressed, float, 0)
- ATTRIB(InputBox, cb_focused, float, 0)
- ATTRIB(InputBox, cb_color, vector, '1 1 1')
- ATTRIB(InputBox, cb_colorF, vector, '1 1 1')
- ATTRIB(InputBox, cb_colorC, vector, '1 1 1')
-ENDCLASS(InputBox)
+ #define ITEM_INPUTBOX_H
+ #include "label.qc"
+ CLASS(InputBox, Label)
+ METHOD(InputBox, configureInputBox, void(entity, string, float, float, string));
+ METHOD(InputBox, draw, void(entity));
+ METHOD(InputBox, setText, void(entity, string));
+ METHOD(InputBox, enterText, void(entity, string));
+ METHOD(InputBox, keyDown, float(entity, float, float, float));
+ METHOD(InputBox, mouseMove, float(entity, vector));
+ METHOD(InputBox, mouseRelease, float(entity, vector));
+ METHOD(InputBox, mousePress, float(entity, vector));
+ METHOD(InputBox, mouseDrag, float(entity, vector));
+ METHOD(InputBox, showNotify, void(entity));
+ METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector));
+
+ ATTRIB(InputBox, src, string, string_null)
+
+ ATTRIB(InputBox, cursorPos, float, 0) // characters
+ ATTRIB(InputBox, scrollPos, float, 0) // widths
+
+ ATTRIB(InputBox, focusable, float, 1)
+ ATTRIB(InputBox, allowFocusSound, float, 1)
+ ATTRIB(InputBox, disabled, float, 0)
+ ATTRIB(InputBox, lastChangeTime, float, 0)
+ ATTRIB(InputBox, dragScrollTimer, float, 0)
+ ATTRIB(InputBox, dragScrollPos, vector, '0 0 0')
+ ATTRIB(InputBox, pressed, float, 0)
+ ATTRIB(InputBox, editColorCodes, float, 1)
+ ATTRIB(InputBox, forbiddenCharacters, string, "")
+ ATTRIB(InputBox, color, vector, '1 1 1')
+ ATTRIB(InputBox, colorF, vector, '1 1 1')
+ ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
+
+ ATTRIB(InputBox, enableClearButton, float, 1)
+ ATTRIB(InputBox, clearButton, entity, NULL)
+ ATTRIB(InputBox, cb_width, float, 0)
+ ATTRIB(InputBox, cb_pressed, float, 0)
+ ATTRIB(InputBox, cb_focused, float, 0)
+ ATTRIB(InputBox, cb_color, vector, '1 1 1')
+ ATTRIB(InputBox, cb_colorF, vector, '1 1 1')
+ ATTRIB(InputBox, cb_colorC, vector, '1 1 1')
+ ENDCLASS(InputBox)
#endif
#ifdef IMPLEMENTATION
-void InputBox_configureInputBox(entity me, string theText, float theCursorPos, float theFontSize, string gfx)
-{
- SUPER(InputBox).configureLabel(me, theText, theFontSize, 0.0);
- me.src = gfx;
- me.cursorPos = theCursorPos;
-}
-void InputBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- SUPER(InputBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
- if (me.enableClearButton)
+ void InputBox_configureInputBox(entity me, string theText, float theCursorPos, float theFontSize, string gfx)
{
- me.cb_width = absSize.y / absSize.x;
- me.cb_offset = bound(-1, me.cb_offset, 0) * me.cb_width; // bound to range -1, 0
- me.keepspaceRight = me.keepspaceRight - me.cb_offset + me.cb_width;
+ SUPER(InputBox).configureLabel(me, theText, theFontSize, 0.0);
+ me.src = gfx;
+ me.cursorPos = theCursorPos;
}
-}
-
-void InputBox_setText(entity me, string txt)
-{
- if(me.text)
- strunzone(me.text);
- SUPER(InputBox).setText(me, strzone(txt));
-}
-
-float over_ClearButton(entity me, vector pos)
-{
- if (pos.x >= 1 + me.cb_offset - me.cb_width)
- if (pos.x < 1 + me.cb_offset)
- if (pos.y >= 0)
- if (pos.y < 1)
- return 1;
- return 0;
-}
-
-float InputBox_mouseMove(entity me, vector pos)
-{
- if (me.enableClearButton)
+ void InputBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
{
- if (over_ClearButton(me, pos))
+ SUPER(InputBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+ if (me.enableClearButton)
{
- me.cb_focused = 1;
- return 1;
+ me.cb_width = absSize.y / absSize.x;
+ me.cb_offset = bound(-1, me.cb_offset, 0) * me.cb_width; // bound to range -1, 0
+ me.keepspaceRight = me.keepspaceRight - me.cb_offset + me.cb_width;
}
- me.cb_focused = 0;
}
- return 1;
-}
-float InputBox_mouseDrag(entity me, vector pos)
-{
- float p;
- if(me.pressed)
+ void InputBox_setText(entity me, string txt)
{
- me.dragScrollPos = pos;
- p = me.scrollPos + pos.x - me.keepspaceLeft;
- me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
- me.lastChangeTime = time;
+ if (me.text) strunzone(me.text);
+ SUPER(InputBox).setText(me, strzone(txt));
}
- else if (me.enableClearButton)
+
+ float over_ClearButton(entity me, vector pos)
{
- if (over_ClearButton(me, pos))
- {
- me.cb_pressed = 1;
- return 1;
- }
+ if (pos.x >= 1 + me.cb_offset - me.cb_width)
+ if (pos.x < 1 + me.cb_offset)
+ if (pos.y >= 0)
+ if (pos.y < 1) return 1;
+ return 0;
}
- me.cb_pressed = 0;
- return 1;
-}
-
-float InputBox_mousePress(entity me, vector pos)
-{
- if (me.enableClearButton)
- if (over_ClearButton(me, pos))
+
+ float InputBox_mouseMove(entity me, vector pos)
{
- me.cb_pressed = 1;
+ if (me.enableClearButton)
+ {
+ if (over_ClearButton(me, pos))
+ {
+ me.cb_focused = 1;
+ return 1;
+ }
+ me.cb_focused = 0;
+ }
return 1;
}
- me.dragScrollTimer = time;
- me.pressed = 1;
- return InputBox_mouseDrag(me, pos);
-}
-
-float InputBox_mouseRelease(entity me, vector pos)
-{
- if(me.cb_pressed)
- if (over_ClearButton(me, pos))
+
+ float InputBox_mouseDrag(entity me, vector pos)
{
- m_play_click_sound(MENU_SOUND_CLEAR);
- me.setText(me, "");
+ float p;
+ if (me.pressed)
+ {
+ me.dragScrollPos = pos;
+ p = me.scrollPos + pos.x - me.keepspaceLeft;
+ me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
+ me.lastChangeTime = time;
+ }
+ else if (me.enableClearButton)
+ {
+ if (over_ClearButton(me, pos))
+ {
+ me.cb_pressed = 1;
+ return 1;
+ }
+ }
me.cb_pressed = 0;
return 1;
}
- float r = InputBox_mouseDrag(me, pos);
- //reset cb_pressed after mouseDrag, mouseDrag could set cb_pressed in this case:
- //mouse press out of the clear button, drag and then mouse release over the clear button
- me.cb_pressed = 0;
- me.pressed = 0;
- return r;
-}
-
-void InputBox_enterText(entity me, string ch)
-{
- float i;
- for(i = 0; i < strlen(ch); ++i)
- if(strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1)
- return;
- if(me.maxLength > 0)
+
+ float InputBox_mousePress(entity me, vector pos)
{
- if(strlen(ch) + strlen(me.text) > me.maxLength)
- return;
+ if (me.enableClearButton)
+ if (over_ClearButton(me, pos))
+ {
+ me.cb_pressed = 1;
+ return 1;
+ }
+ me.dragScrollTimer = time;
+ me.pressed = 1;
+ return InputBox_mouseDrag(me, pos);
}
- else if(me.maxLength < 0)
+
+ float InputBox_mouseRelease(entity me, vector pos)
{
- if(u8_strsize(ch) + u8_strsize(me.text) > -me.maxLength)
- return;
+ if (me.cb_pressed)
+ if (over_ClearButton(me, pos))
+ {
+ m_play_click_sound(MENU_SOUND_CLEAR);
+ me.setText(me, "");
+ me.cb_pressed = 0;
+ return 1;
+ }
+ float r = InputBox_mouseDrag(me, pos);
+ // reset cb_pressed after mouseDrag, mouseDrag could set cb_pressed in this case:
+ // mouse press out of the clear button, drag and then mouse release over the clear button
+ me.cb_pressed = 0;
+ me.pressed = 0;
+ return r;
}
- me.setText(me, strcat(substring(me.text, 0, me.cursorPos), ch, substring(me.text, me.cursorPos, strlen(me.text) - me.cursorPos)));
- me.cursorPos += strlen(ch);
-}
-
-float InputBox_keyDown(entity me, float key, float ascii, float shift)
-{
- me.lastChangeTime = time;
- me.dragScrollTimer = time;
- if(ascii >= 32 && ascii != 127)
+
+ void InputBox_enterText(entity me, string ch)
{
- me.enterText(me, chr(ascii));
- return 1;
+ float i;
+ for (i = 0; i < strlen(ch); ++i)
+ if (strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1) return;
+ if (me.maxLength > 0)
+ {
+ if (strlen(ch) + strlen(me.text) > me.maxLength) return;
+ }
+ else if (me.maxLength < 0)
+ {
+ if (u8_strsize(ch) + u8_strsize(me.text) > -me.maxLength) return;
+ }
+ me.setText(me, strcat(substring(me.text, 0, me.cursorPos), ch, substring(me.text, me.cursorPos, strlen(me.text) - me.cursorPos)));
+ me.cursorPos += strlen(ch);
}
- switch(key)
+
+ float InputBox_keyDown(entity me, float key, float ascii, float shift)
{
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- me.cursorPos -= 1;
- return 1;
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- me.cursorPos += 1;
- return 1;
- case K_KP_HOME:
- case K_HOME:
- me.cursorPos = 0;
- return 1;
- case K_KP_END:
- case K_END:
- me.cursorPos = strlen(me.text);
+ me.lastChangeTime = time;
+ me.dragScrollTimer = time;
+ if (ascii >= 32 && ascii != 127)
+ {
+ me.enterText(me, chr(ascii));
return 1;
- case K_BACKSPACE:
- if(me.cursorPos > 0)
- {
+ }
+ switch (key)
+ {
+ case K_KP_LEFTARROW:
+ case K_LEFTARROW:
me.cursorPos -= 1;
- me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
- }
- return 1;
- case K_KP_DEL:
- case K_DEL:
- if(shift & S_CTRL)
- {
- m_play_click_sound(MENU_SOUND_CLEAR);
- me.setText(me, "");
- }
- else
- me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
- return 1;
+ return 1;
+ case K_KP_RIGHTARROW:
+ case K_RIGHTARROW:
+ me.cursorPos += 1;
+ return 1;
+ case K_KP_HOME:
+ case K_HOME:
+ me.cursorPos = 0;
+ return 1;
+ case K_KP_END:
+ case K_END:
+ me.cursorPos = strlen(me.text);
+ return 1;
+ case K_BACKSPACE:
+ if (me.cursorPos > 0)
+ {
+ me.cursorPos -= 1;
+ me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
+ }
+ return 1;
+ case K_KP_DEL:
+ case K_DEL:
+ if (shift & S_CTRL)
+ {
+ m_play_click_sound(MENU_SOUND_CLEAR);
+ me.setText(me, "");
+ }
+ else
+ {
+ me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
+ }
+ return 1;
+ }
+ return 0;
}
- return 0;
-}
-void InputBox_draw(entity me)
-{
- string CURSOR = "_";
- float cursorPosInWidths, totalSizeInWidths;
+ void InputBox_draw(entity me)
+ {
+ string CURSOR = "_";
+ float cursorPosInWidths, totalSizeInWidths;
- if(me.pressed)
- me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
+ if (me.pressed) me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
- if(me.recalcPos)
- me.recalcPositionWithText(me, me.text);
+ if (me.recalcPos) me.recalcPositionWithText(me, me.text);
- me.focusable = !me.disabled;
- if(me.disabled)
- draw_alpha *= me.disabledAlpha;
+ me.focusable = !me.disabled;
+ if (me.disabled) draw_alpha *= me.disabledAlpha;
- if(me.src)
- {
- if(me.focused && !me.disabled)
- draw_ButtonPicture('0 0 0', strcat(me.src, "_f"), '1 1 0', me.colorF, 1);
- else
- draw_ButtonPicture('0 0 0', strcat(me.src, "_n"), '1 1 0', me.color, 1);
- }
+ if (me.src)
+ {
+ if (me.focused && !me.disabled) draw_ButtonPicture('0 0 0', strcat(me.src, "_f"), '1 1 0', me.colorF, 1);
+ else draw_ButtonPicture('0 0 0', strcat(me.src, "_n"), '1 1 0', me.color, 1);
+ }
- me.cursorPos = bound(0, me.cursorPos, strlen(me.text));
- cursorPosInWidths = draw_TextWidth(substring(me.text, 0, me.cursorPos), 0, me.realFontSize);
- totalSizeInWidths = draw_TextWidth(strcat(me.text, CURSOR), 0, me.realFontSize);
+ me.cursorPos = bound(0, me.cursorPos, strlen(me.text));
+ cursorPosInWidths = draw_TextWidth(substring(me.text, 0, me.cursorPos), 0, me.realFontSize);
+ totalSizeInWidths = draw_TextWidth(strcat(me.text, CURSOR), 0, me.realFontSize);
- if(me.dragScrollTimer < time)
- {
- float save;
- save = me.scrollPos;
- me.scrollPos = bound(cursorPosInWidths - (0.875 - me.keepspaceLeft - me.keepspaceRight), me.scrollPos, cursorPosInWidths - 0.125);
- if(me.scrollPos != save)
- me.dragScrollTimer = time + 0.2;
- }
- me.scrollPos = min(me.scrollPos, totalSizeInWidths - (1 - me.keepspaceRight - me.keepspaceLeft));
- me.scrollPos = max(0, me.scrollPos);
+ if (me.dragScrollTimer < time)
+ {
+ float save;
+ save = me.scrollPos;
+ me.scrollPos = bound(cursorPosInWidths - (0.875 - me.keepspaceLeft - me.keepspaceRight), me.scrollPos, cursorPosInWidths - 0.125);
+ if (me.scrollPos != save) me.dragScrollTimer = time + 0.2;
+ }
+ me.scrollPos = min(me.scrollPos, totalSizeInWidths - (1 - me.keepspaceRight - me.keepspaceLeft));
+ me.scrollPos = max(0, me.scrollPos);
- draw_SetClipRect(eX * me.keepspaceLeft, eX * (1 - me.keepspaceLeft - me.keepspaceRight) + eY);
- if(me.editColorCodes)
- {
- string ch, ch2;
- float i, n;
- vector theColor;
- float theAlpha; //float theVariableAlpha;
- vector p;
- vector theTempColor;
- float component;
-
- p = me.realOrigin - eX * me.scrollPos;
- theColor = '1 1 1';
- theAlpha = 1; //theVariableAlpha = 1; // changes when ^ax found
-
- n = strlen(me.text);
- for(i = 0; i < n; ++i)
+ draw_SetClipRect(eX * me.keepspaceLeft, eX * (1 - me.keepspaceLeft - me.keepspaceRight) + eY);
+ if (me.editColorCodes)
{
- ch = substring(me.text, i, 1);
- if(ch == "^")
+ string ch, ch2;
+ float i, n;
+ vector theColor;
+ float theAlpha; // float theVariableAlpha;
+ vector p;
+ vector theTempColor;
+ float component;
+
+ p = me.realOrigin - eX * me.scrollPos;
+ theColor = '1 1 1';
+ theAlpha = 1; // theVariableAlpha = 1; // changes when ^ax found
+
+ n = strlen(me.text);
+ for (i = 0; i < n; ++i)
{
- float w;
- ch2 = substring(me.text, i+1, 1);
- w = draw_TextWidth(strcat(ch, ch2), 0, me.realFontSize);
- if(ch2 == "^")
- {
- draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
- draw_Text(p + eX * 0.25 * w, "^", me.realFontSize, theColor, theAlpha, 0);
- }
- else if(ch2 == "0" || stof(ch2)) // digit?
+ ch = substring(me.text, i, 1);
+ if (ch == "^")
{
- switch(stof(ch2))
+ float w;
+ ch2 = substring(me.text, i + 1, 1);
+ w = draw_TextWidth(strcat(ch, ch2), 0, me.realFontSize);
+ if (ch2 == "^")
{
- case 0: theColor = '0 0 0'; theAlpha = 1; break;
- case 1: theColor = '1 0 0'; theAlpha = 1; break;
- case 2: theColor = '0 1 0'; theAlpha = 1; break;
- case 3: theColor = '1 1 0'; theAlpha = 1; break;
- case 4: theColor = '0 0 1'; theAlpha = 1; break;
- case 5: theColor = '0 1 1'; theAlpha = 1; break;
- case 6: theColor = '1 0 1'; theAlpha = 1; break;
- case 7: theColor = '1 1 1'; theAlpha = 1; break;
- case 8: theColor = '1 1 1'; theAlpha = 0.5; break;
- case 9: theColor = '0.5 0.5 0.5'; theAlpha = 1; break;
+ draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
+ draw_Text(p + eX * 0.25 * w, "^", me.realFontSize, theColor, theAlpha, 0);
}
- draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
- draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
- }
- else if(ch2 == "x") // ^x found
- {
- theColor = '1 1 1';
-
- component = HEXDIGIT_TO_DEC(substring(me.text, i+2, 1));
- if (component >= 0) // ^xr found
+ else if (ch2 == "0" || stof(ch2)) // digit?
+ {
+ switch (stof(ch2))
+ {
+ case 0: theColor = '0 0 0';
+ theAlpha = 1;
+ break;
+ case 1: theColor = '1 0 0';
+ theAlpha = 1;
+ break;
+ case 2: theColor = '0 1 0';
+ theAlpha = 1;
+ break;
+ case 3: theColor = '1 1 0';
+ theAlpha = 1;
+ break;
+ case 4: theColor = '0 0 1';
+ theAlpha = 1;
+ break;
+ case 5: theColor = '0 1 1';
+ theAlpha = 1;
+ break;
+ case 6: theColor = '1 0 1';
+ theAlpha = 1;
+ break;
+ case 7: theColor = '1 1 1';
+ theAlpha = 1;
+ break;
+ case 8: theColor = '1 1 1';
+ theAlpha = 0.5;
+ break;
+ case 9: theColor = '0.5 0.5 0.5';
+ theAlpha = 1;
+ break;
+ }
+ draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
+ draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
+ }
+ else if (ch2 == "x") // ^x found
{
- theTempColor.x = component/15;
+ theColor = '1 1 1';
- component = HEXDIGIT_TO_DEC(substring(me.text, i+3, 1));
- if (component >= 0) // ^xrg found
+ component = HEXDIGIT_TO_DEC(substring(me.text, i + 2, 1));
+ if (component >= 0) // ^xr found
{
- theTempColor.y = component/15;
+ theTempColor.x = component / 15;
- component = HEXDIGIT_TO_DEC(substring(me.text, i+4, 1));
- if (component >= 0) // ^xrgb found
+ component = HEXDIGIT_TO_DEC(substring(me.text, i + 3, 1));
+ if (component >= 0) // ^xrg found
{
- theTempColor.z = component/15;
- theColor = theTempColor;
- w = draw_TextWidth(substring(me.text, i, 5), 0, me.realFontSize);
-
- draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
- draw_Text(p, substring(me.text, i, 5), me.realFontSize, theColor, 1, 0); // theVariableAlpha instead of 1 using alpha tags ^ax
- i += 3;
+ theTempColor.y = component / 15;
+
+ component = HEXDIGIT_TO_DEC(substring(me.text, i + 4, 1));
+ if (component >= 0) // ^xrgb found
+ {
+ theTempColor.z = component / 15;
+ theColor = theTempColor;
+ w = draw_TextWidth(substring(me.text, i, 5), 0, me.realFontSize);
+
+ draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
+ draw_Text(p, substring(me.text, i, 5), me.realFontSize, theColor, 1, 0); // theVariableAlpha instead of 1 using alpha tags ^ax
+ i += 3;
+ }
+ else
+ {
+ // blue missing
+ w = draw_TextWidth(substring(me.text, i, 4), 0, me.realFontSize);
+ draw_Fill(p, eX * w + eY * me.realFontSize.y, eZ, 0.5);
+ draw_Text(p, substring(me.text, i, 4), me.realFontSize, '1 1 1', theAlpha, 0);
+ i += 2;
+ }
}
else
{
- // blue missing
- w = draw_TextWidth(substring(me.text, i, 4), 0, me.realFontSize);
- draw_Fill(p, eX * w + eY * me.realFontSize.y, eZ, 0.5);
- draw_Text(p, substring(me.text, i, 4), me.realFontSize, '1 1 1', theAlpha, 0);
- i += 2;
+ // green missing
+ w = draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize);
+ draw_Fill(p, eX * w + eY * me.realFontSize.y, eY, 0.5);
+ draw_Text(p, substring(me.text, i, 3), me.realFontSize, '1 1 1', theAlpha, 0);
+ i += 1;
}
}
else
{
- // green missing
- w = draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize);
- draw_Fill(p, eX * w + eY * me.realFontSize.y, eY, 0.5);
- draw_Text(p, substring(me.text, i, 3), me.realFontSize, '1 1 1', theAlpha, 0);
- i += 1;
+ // red missing
+ // w = draw_TextWidth(substring(me.text, i, 2), 0) * me.realFontSize_x;
+ draw_Fill(p, eX * w + eY * me.realFontSize.y, eX, 0.5);
+ draw_Text(p, substring(me.text, i, 2), me.realFontSize, '1 1 1', theAlpha, 0);
}
}
else
{
- // red missing
- //w = draw_TextWidth(substring(me.text, i, 2), 0) * me.realFontSize_x;
- draw_Fill(p, eX * w + eY * me.realFontSize.y, eX, 0.5);
- draw_Text(p, substring(me.text, i, 2), me.realFontSize, '1 1 1', theAlpha, 0);
+ draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
+ draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
}
+ p += w * eX;
+ ++i;
+ continue;
}
- else
- {
- draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
- draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
- }
- p += w * eX;
- ++i;
- continue;
+ draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0); // TODO theVariableAlpha
+ p += eX * draw_TextWidth(ch, 0, me.realFontSize);
}
- draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0); // TODO theVariableAlpha
- p += eX * draw_TextWidth(ch, 0, me.realFontSize);
}
- }
- else
- draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
+ else
+ {
+ draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
+ }
- if(!me.focused || (time - me.lastChangeTime) < floor(time - me.lastChangeTime) + 0.5)
- draw_Text(me.realOrigin + eX * (cursorPosInWidths - me.scrollPos), CURSOR, me.realFontSize, '1 1 1', 1, 0);
+ if (!me.focused || (time - me.lastChangeTime) < floor(time - me.lastChangeTime) + 0.5) draw_Text(me.realOrigin + eX * (cursorPosInWidths - me.scrollPos), CURSOR, me.realFontSize, '1 1 1', 1, 0);
- draw_ClearClip();
+ draw_ClearClip();
- if (me.enableClearButton)
- if (me.text != "")
- {
- if(me.focused && me.cb_pressed)
- draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_c"), eX * me.cb_width + eY, me.cb_colorC, 1);
- else if(me.focused && me.cb_focused)
- draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_f"), eX * me.cb_width + eY, me.cb_colorF, 1);
- else
- draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_n"), eX * me.cb_width + eY, me.cb_color, 1);
- }
+ if (me.enableClearButton)
+ if (me.text != "")
+ {
+ if (me.focused && me.cb_pressed) draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_c"), eX * me.cb_width + eY, me.cb_colorC, 1);
+ else if (me.focused && me.cb_focused) draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_f"), eX * me.cb_width + eY, me.cb_colorF, 1);
+ else draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_n"), eX * me.cb_width + eY, me.cb_color, 1);
+ }
- // skipping SUPER(InputBox).draw(me);
- Item_draw(me);
-}
+ // skipping SUPER(InputBox).draw(me);
+ Item_draw(me);
+ }
-void InputBox_showNotify(entity me)
-{
- me.focusable = !me.disabled;
-}
+ void InputBox_showNotify(entity me)
+ {
+ me.focusable = !me.disabled;
+ }
#endif
#ifndef ITEM_INPUTCONTAINER_H
-#define ITEM_INPUTCONTAINER_H
-#include "container.qc"
-CLASS(InputContainer, Container)
- METHOD(InputContainer, keyDown, float(entity, float, float, float));
- METHOD(InputContainer, mouseMove, float(entity, vector));
- METHOD(InputContainer, mousePress, float(entity, vector));
- METHOD(InputContainer, mouseRelease, float(entity, vector));
- METHOD(InputContainer, mouseDrag, float(entity, vector));
- METHOD(InputContainer, focusLeave, void(entity));
- METHOD(InputContainer, resizeNotify, void(entity, vector, vector, vector, vector));
+ #define ITEM_INPUTCONTAINER_H
+ #include "container.qc"
+ CLASS(InputContainer, Container)
+ METHOD(InputContainer, keyDown, float(entity, float, float, float));
+ METHOD(InputContainer, mouseMove, float(entity, vector));
+ METHOD(InputContainer, mousePress, float(entity, vector));
+ METHOD(InputContainer, mouseRelease, float(entity, vector));
+ METHOD(InputContainer, mouseDrag, float(entity, vector));
+ METHOD(InputContainer, focusLeave, void(entity));
+ METHOD(InputContainer, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(InputContainer, _changeFocusXY, bool(entity this, vector pos));
- ATTRIB(InputContainer, mouseFocusedChild, entity, NULL)
- ATTRIB(InputContainer, isTabRoot, float, 0)
-ENDCLASS(InputContainer)
+ METHOD(InputContainer, _changeFocusXY, bool(entity this, vector pos));
+ ATTRIB(InputContainer, mouseFocusedChild, entity, NULL)
+ ATTRIB(InputContainer, isTabRoot, float, 0)
+ ENDCLASS(InputContainer)
#endif
#ifdef IMPLEMENTATION
-void InputContainer_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- SUPER(InputContainer).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
- /*
- if(me.parent.instanceOfInputContainer)
- me.isTabRoot = 0;
- else
- me.isTabRoot = 1;
- */
-}
+ void InputContainer_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+ {
+ SUPER(InputContainer).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+ /*
+ if(me.parent.instanceOfInputContainer)
+ me.isTabRoot = 0;
+ else
+ me.isTabRoot = 1;
+ */
+ }
-void InputContainer_focusLeave(entity me)
-{
- SUPER(InputContainer).focusLeave(me);
- me.mouseFocusedChild = NULL;
-}
+ void InputContainer_focusLeave(entity me)
+ {
+ SUPER(InputContainer).focusLeave(me);
+ me.mouseFocusedChild = NULL;
+ }
-float InputContainer_keyDown(entity me, float scan, float ascii, float shift)
-{
- entity f, ff;
- if(SUPER(InputContainer).keyDown(me, scan, ascii, shift))
- return 1;
- if(scan == K_ESCAPE)
+ float InputContainer_keyDown(entity me, float scan, float ascii, float shift)
{
- f = me.focusedChild;
- if(f)
+ entity f, ff;
+ if (SUPER(InputContainer).keyDown(me, scan, ascii, shift)) return 1;
+ if (scan == K_ESCAPE)
{
- me.setFocus(me, NULL);
- return 1;
+ f = me.focusedChild;
+ if (f)
+ {
+ me.setFocus(me, NULL);
+ return 1;
+ }
+ return 0;
}
- return 0;
- }
- if(scan == K_TAB)
- {
- f = me.focusedChild;
- if(shift & S_SHIFT)
+ if (scan == K_TAB)
{
- if(f)
+ f = me.focusedChild;
+ if (shift & S_SHIFT)
{
- for(ff = f.prevSibling; ff; ff = ff.prevSibling)
+ if (f)
{
- if (!ff.focusable)
- continue;
- me.setFocus(me, ff);
- return 1;
+ for (ff = f.prevSibling; ff; ff = ff.prevSibling)
+ {
+ if (!ff.focusable) continue;
+ me.setFocus(me, ff);
+ return 1;
+ }
}
- }
- if(!f || me.isTabRoot)
- {
- for(ff = me.lastChild; ff; ff = ff.prevSibling)
+ if (!f || me.isTabRoot)
{
- if (!ff.focusable)
- continue;
- me.setFocus(me, ff);
- return 1;
+ for (ff = me.lastChild; ff; ff = ff.prevSibling)
+ {
+ if (!ff.focusable) continue;
+ me.setFocus(me, ff);
+ return 1;
+ }
+ return 0; // AIIIIEEEEE!
}
- return 0; // AIIIIEEEEE!
}
- }
- else
- {
- if(f)
+ else
{
- for(ff = f.nextSibling; ff; ff = ff.nextSibling)
+ if (f)
{
- if (!ff.focusable)
- continue;
- me.setFocus(me, ff);
- return 1;
+ for (ff = f.nextSibling; ff; ff = ff.nextSibling)
+ {
+ if (!ff.focusable) continue;
+ me.setFocus(me, ff);
+ return 1;
+ }
}
- }
- if(!f || me.isTabRoot)
- {
- for(ff = me.firstChild; ff; ff = ff.nextSibling)
+ if (!f || me.isTabRoot)
{
- if (!ff.focusable)
- continue;
- me.setFocus(me, ff);
- return 1;
+ for (ff = me.firstChild; ff; ff = ff.nextSibling)
+ {
+ if (!ff.focusable) continue;
+ me.setFocus(me, ff);
+ return 1;
+ }
+ return 0; // AIIIIEEEEE!
}
- return 0; // AIIIIEEEEE!
}
}
+ return 0;
}
- return 0;
-}
-bool InputContainer__changeFocusXY(entity this, vector pos)
-{
- entity e = this.itemFromPoint(this, pos);
- if (e && !e.focusable) e = NULL;
- entity prev = this.mouseFocusedChild;
- this.mouseFocusedChild = e;
- if (!e) return false; // keep focus when hovering over non-focusable elements
- if (e != prev) {
- this.setFocus(this, e);
- if (e.instanceOfInputContainer) {
- e.focusedChild = NULL;
- e._changeFocusXY(e, globalToBox(pos, e.Container_origin, e.Container_size));
+ bool InputContainer__changeFocusXY(entity this, vector pos)
+ {
+ entity e = this.itemFromPoint(this, pos);
+ if (e && !e.focusable) e = NULL;
+ entity prev = this.mouseFocusedChild;
+ this.mouseFocusedChild = e;
+ if (!e) return false; // keep focus when hovering over non-focusable elements
+ if (e != prev)
+ {
+ this.setFocus(this, e);
+ if (e.instanceOfInputContainer)
+ {
+ e.focusedChild = NULL;
+ e._changeFocusXY(e, globalToBox(pos, e.Container_origin, e.Container_size));
+ }
}
+ return true; // have focus
}
- return true; // have focus
-}
-float InputContainer_mouseDrag(entity me, vector pos)
-{
- if(SUPER(InputContainer).mouseDrag(me, pos))
- return 1;
- if(pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1)
- return 1;
- return 0;
-}
-float InputContainer_mouseMove(entity me, vector pos)
-{
- if(me.mouseFocusedChild != me.focusedChild) // if the keyboard moved the focus away
- me.mouseFocusedChild = NULL; // force focusing
- if(me._changeFocusXY(me, pos))
- if(SUPER(InputContainer).mouseMove(me, pos))
- return 1;
- if(pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1)
- return 1;
- return 0;
-}
-float InputContainer_mousePress(entity me, vector pos)
-{
- me.mouseFocusedChild = NULL; // force focusing
- if(me._changeFocusXY(me, pos))
- if(SUPER(InputContainer).mousePress(me, pos))
- return 1;
- if(pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1)
- return 1;
- return 0;
-}
-float InputContainer_mouseRelease(entity me, vector pos)
-{
- SUPER(InputContainer).mouseRelease(me, pos); // return value?
- if(me.focused) // am I still eligible for this? (UGLY HACK, but a mouse event could have changed focus away)
- if(me._changeFocusXY(me, pos))
- return 1;
- if(pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1)
- return 1;
- return 0;
-}
+ float InputContainer_mouseDrag(entity me, vector pos)
+ {
+ if (SUPER(InputContainer).mouseDrag(me, pos)) return 1;
+ if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return 1;
+ return 0;
+ }
+ float InputContainer_mouseMove(entity me, vector pos)
+ {
+ if (me.mouseFocusedChild != me.focusedChild) // if the keyboard moved the focus away
+ me.mouseFocusedChild = NULL; // force focusing
+ if (me._changeFocusXY(me, pos))
+ if (SUPER(InputContainer).mouseMove(me, pos)) return 1;
+ if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return 1;
+ return 0;
+ }
+ float InputContainer_mousePress(entity me, vector pos)
+ {
+ me.mouseFocusedChild = NULL; // force focusing
+ if (me._changeFocusXY(me, pos))
+ if (SUPER(InputContainer).mousePress(me, pos)) return 1;
+ if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return 1;
+ return 0;
+ }
+ float InputContainer_mouseRelease(entity me, vector pos)
+ {
+ SUPER(InputContainer).mouseRelease(me, pos); // return value?
+ if (me.focused) // am I still eligible for this? (UGLY HACK, but a mouse event could have changed focus away)
+ if (me._changeFocusXY(me, pos)) return 1;
+ if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return 1;
+ return 0;
+ }
#endif
#ifndef ITEM_LABEL_H
-#define ITEM_LABEL_H
-#include "../item.qc"
-CLASS(Label, Item)
- METHOD(Label, configureLabel, void(entity, string, float, float));
- METHOD(Label, draw, void(entity));
- METHOD(Label, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(Label, setText, void(entity, string));
- METHOD(Label, toString, string(entity));
- METHOD(Label, recalcPositionWithText, void(entity, string));
- ATTRIB(Label, isBold, float, 0)
- ATTRIB(Label, text, string, string_null)
- ATTRIB(Label, currentText, string, string_null)
- ATTRIB(Label, fontSize, float, 8)
- ATTRIB(Label, align, float, 0.5)
- ATTRIB(Label, allowCut, float, 0)
- ATTRIB(Label, allowColors, float, 0)
- ATTRIB(Label, keepspaceLeft, float, 0) // for use by subclasses (radiobuttons for example)
- ATTRIB(Label, keepspaceRight, float, 0)
- ATTRIB(Label, marginLeft, float, 0) // alternate way to specify keepspace* (in characters from the font)
- ATTRIB(Label, marginRight, float, 0)
- ATTRIB(Label, realFontSize, vector, '0 0 0')
- ATTRIB(Label, realOrigin, vector, '0 0 0')
- ATTRIB(Label, alpha, float, 0.7)
- ATTRIB(Label, colorL, vector, SKINCOLOR_TEXT)
- ATTRIB(Label, disabled, float, 0)
- ATTRIB(Label, disabledAlpha, float, 0.3)
- ATTRIB(Label, textEntity, entity, NULL)
- ATTRIB(Label, allowWrap, float, 0)
- ATTRIB(Label, recalcPos, float, 0)
- ATTRIB(Label, condenseFactor, float, 1)
- ATTRIB(Label, overrideRealOrigin, vector, '0 0 0')
- ATTRIB(Label, overrideCondenseFactor, float, 0)
-ENDCLASS(Label)
+ #define ITEM_LABEL_H
+ #include "../item.qc"
+ CLASS(Label, Item)
+ METHOD(Label, configureLabel, void(entity, string, float, float));
+ METHOD(Label, draw, void(entity));
+ METHOD(Label, resizeNotify, void(entity, vector, vector, vector, vector));
+ METHOD(Label, setText, void(entity, string));
+ METHOD(Label, toString, string(entity));
+ METHOD(Label, recalcPositionWithText, void(entity, string));
+ ATTRIB(Label, isBold, float, 0)
+ ATTRIB(Label, text, string, string_null)
+ ATTRIB(Label, currentText, string, string_null)
+ ATTRIB(Label, fontSize, float, 8)
+ ATTRIB(Label, align, float, 0.5)
+ ATTRIB(Label, allowCut, float, 0)
+ ATTRIB(Label, allowColors, float, 0)
+ ATTRIB(Label, keepspaceLeft, float, 0) // for use by subclasses (radiobuttons for example)
+ ATTRIB(Label, keepspaceRight, float, 0)
+ ATTRIB(Label, marginLeft, float, 0) // alternate way to specify keepspace* (in characters from the font)
+ ATTRIB(Label, marginRight, float, 0)
+ ATTRIB(Label, realFontSize, vector, '0 0 0')
+ ATTRIB(Label, realOrigin, vector, '0 0 0')
+ ATTRIB(Label, alpha, float, 0.7)
+ ATTRIB(Label, colorL, vector, SKINCOLOR_TEXT)
+ ATTRIB(Label, disabled, float, 0)
+ ATTRIB(Label, disabledAlpha, float, 0.3)
+ ATTRIB(Label, textEntity, entity, NULL)
+ ATTRIB(Label, allowWrap, float, 0)
+ ATTRIB(Label, recalcPos, float, 0)
+ ATTRIB(Label, condenseFactor, float, 1)
+ ATTRIB(Label, overrideRealOrigin, vector, '0 0 0')
+ ATTRIB(Label, overrideCondenseFactor, float, 0)
+ ENDCLASS(Label)
#endif
#ifdef IMPLEMENTATION
-string Label_toString(entity me)
-{
- return me.text;
-}
-void Label_setText(entity me, string txt)
-{
- me.text = txt;
- if(txt != me.currentText)
+ string Label_toString(entity me)
{
- if(me.currentText)
- strunzone(me.currentText);
- me.currentText = strzone(txt);
- me.recalcPos = 1;
+ return me.text;
}
-}
-void Label_recalcPositionWithText(entity me, string t)
-{
- float spaceAvail;
- spaceAvail = 1 - me.keepspaceLeft - me.keepspaceRight;
-
- if(me.isBold)
- draw_beginBoldFont();
-
- float spaceUsed;
- spaceUsed = draw_TextWidth(t, me.allowColors, me.realFontSize);
-
- if(spaceUsed <= spaceAvail)
+ void Label_setText(entity me, string txt)
{
- if(!me.overrideRealOrigin_x)
- me.realOrigin_x = me.align * (spaceAvail - spaceUsed) + me.keepspaceLeft;
- if(!me.overrideCondenseFactor)
- me.condenseFactor = 1;
- }
- else if(me.allowCut || me.allowWrap)
- {
- if(!me.overrideRealOrigin_x)
- me.realOrigin_x = me.keepspaceLeft;
- if(!me.overrideCondenseFactor)
- me.condenseFactor = 1;
- }
- else
- {
- if(!me.overrideRealOrigin_x)
- me.realOrigin_x = me.keepspaceLeft;
- if(!me.overrideCondenseFactor)
- me.condenseFactor = spaceAvail / spaceUsed;
- LOG_TRACEF("NOTE: label text %s too wide for label, condensed by factor %f\n", t, me.condenseFactor);
+ me.text = txt;
+ if (txt != me.currentText)
+ {
+ if (me.currentText) strunzone(me.currentText);
+ me.currentText = strzone(txt);
+ me.recalcPos = 1;
+ }
}
-
- if(!me.overrideRealOrigin_y)
+ void Label_recalcPositionWithText(entity me, string t)
{
- float lines;
- vector dfs;
- vector fs;
+ float spaceAvail;
+ spaceAvail = 1 - me.keepspaceLeft - me.keepspaceRight;
- // set up variables to draw in condensed size, but use hinting for original size
- fs = me.realFontSize;
- fs.x *= me.condenseFactor;
+ if (me.isBold) draw_beginBoldFont();
- dfs = draw_fontscale;
- draw_fontscale.x *= me.condenseFactor;
+ float spaceUsed;
+ spaceUsed = draw_TextWidth(t, me.allowColors, me.realFontSize);
- if(me.allowCut) // FIXME allowCut incompatible with align != 0
- lines = 1;
- else if(me.allowWrap) // FIXME allowWrap incompatible with align != 0
+ if (spaceUsed <= spaceAvail)
{
- getWrappedLine_remaining = me.text;
- lines = 0;
- while(getWrappedLine_remaining)
- {
- if (me.allowColors)
- getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
- else
- getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
- ++lines;
- }
+ if (!me.overrideRealOrigin_x) me.realOrigin_x = me.align * (spaceAvail - spaceUsed) + me.keepspaceLeft;
+ if (!me.overrideCondenseFactor) me.condenseFactor = 1;
+ }
+ else if (me.allowCut || me.allowWrap)
+ {
+ if (!me.overrideRealOrigin_x) me.realOrigin_x = me.keepspaceLeft;
+ if (!me.overrideCondenseFactor) me.condenseFactor = 1;
}
else
- lines = 1;
-
- draw_fontscale = dfs;
-
- me.realOrigin_y = 0.5 * (1 - lines * me.realFontSize.y);
- }
-
- if(me.isBold)
- draw_endBoldFont();
-
- me.recalcPos = 0;
-}
-void Label_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- SUPER(Label).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-
- // absSize_y is height of label
- me.realFontSize_y = absSize.y == 0 ? 0 : (me.fontSize / absSize.y);
- me.realFontSize_x = absSize.x == 0 ? 0 : (me.fontSize / absSize.x);
- if(me.marginLeft)
- me.keepspaceLeft = me.marginLeft * me.realFontSize.x;
- if(me.marginRight)
- me.keepspaceRight = me.marginRight * me.realFontSize.x;
-
- me.recalcPos = 1;
-}
-void Label_configureLabel(entity me, string txt, float sz, float algn)
-{
- me.fontSize = sz;
- me.align = algn;
- me.setText(me, txt);
-}
-void Label_draw(entity me)
-{
- string t;
- vector o;
- if(me.disabled)
- draw_alpha *= me.disabledAlpha;
-
- if(me.textEntity)
- {
- t = me.textEntity.toString(me.textEntity);
- if(t != me.currentText)
{
- if(me.currentText)
- strunzone(me.currentText);
- me.currentText = strzone(t);
- me.recalcPos = 1;
+ if (!me.overrideRealOrigin_x) me.realOrigin_x = me.keepspaceLeft;
+ if (!me.overrideCondenseFactor) me.condenseFactor = spaceAvail / spaceUsed;
+ LOG_TRACEF("NOTE: label text %s too wide for label, condensed by factor %f\n", t, me.condenseFactor);
}
- }
- else
- t = me.text;
- if(me.recalcPos)
- me.recalcPositionWithText(me, t);
-
- if(me.fontSize)
- if(t)
+ if (!me.overrideRealOrigin_y)
{
+ float lines;
vector dfs;
vector fs;
- if(me.isBold)
- draw_beginBoldFont();
-
// set up variables to draw in condensed size, but use hinting for original size
fs = me.realFontSize;
fs.x *= me.condenseFactor;
dfs = draw_fontscale;
draw_fontscale.x *= me.condenseFactor;
- if(me.allowCut) // FIXME allowCut incompatible with align != 0
- draw_Text(me.realOrigin, draw_TextShortenToWidth(t, (1 - me.keepspaceLeft - me.keepspaceRight), me.allowColors, fs), fs, me.colorL, me.alpha, me.allowColors);
- else if(me.allowWrap) // FIXME allowWrap incompatible with align != 0
+ if (me.allowCut) // FIXME allowCut incompatible with align != 0
{
- getWrappedLine_remaining = t;
- o = me.realOrigin;
- while(getWrappedLine_remaining)
+ lines = 1;
+ }
+ else if (me.allowWrap) // FIXME allowWrap incompatible with align != 0
+ {
+ getWrappedLine_remaining = me.text;
+ lines = 0;
+ while (getWrappedLine_remaining)
{
- if (me.allowColors)
- t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
- else
- t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
- draw_Text(o, t, fs, me.colorL, me.alpha, me.allowColors);
- o.y += me.realFontSize.y;
+ if (me.allowColors) getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
+ else getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
+ ++lines;
}
}
else
- draw_Text(me.realOrigin, t, fs, me.colorL, me.alpha, me.allowColors);
+ {
+ lines = 1;
+ }
draw_fontscale = dfs;
- if(me.isBold)
- draw_endBoldFont();
+ me.realOrigin_y = 0.5 * (1 - lines * me.realFontSize.y);
}
- SUPER(Label).draw(me);
-}
+ if (me.isBold) draw_endBoldFont();
+
+ me.recalcPos = 0;
+ }
+ void Label_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+ {
+ SUPER(Label).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+
+ // absSize_y is height of label
+ me.realFontSize_y = absSize.y == 0 ? 0 : (me.fontSize / absSize.y);
+ me.realFontSize_x = absSize.x == 0 ? 0 : (me.fontSize / absSize.x);
+ if (me.marginLeft) me.keepspaceLeft = me.marginLeft * me.realFontSize.x;
+ if (me.marginRight) me.keepspaceRight = me.marginRight * me.realFontSize.x;
+
+ me.recalcPos = 1;
+ }
+ void Label_configureLabel(entity me, string txt, float sz, float algn)
+ {
+ me.fontSize = sz;
+ me.align = algn;
+ me.setText(me, txt);
+ }
+ void Label_draw(entity me)
+ {
+ string t;
+ vector o;
+ if (me.disabled) draw_alpha *= me.disabledAlpha;
+
+ if (me.textEntity)
+ {
+ t = me.textEntity.toString(me.textEntity);
+ if (t != me.currentText)
+ {
+ if (me.currentText) strunzone(me.currentText);
+ me.currentText = strzone(t);
+ me.recalcPos = 1;
+ }
+ }
+ else
+ {
+ t = me.text;
+ }
+
+ if (me.recalcPos) me.recalcPositionWithText(me, t);
+
+ if (me.fontSize)
+ if (t)
+ {
+ vector dfs;
+ vector fs;
+
+ if (me.isBold) draw_beginBoldFont();
+
+ // set up variables to draw in condensed size, but use hinting for original size
+ fs = me.realFontSize;
+ fs.x *= me.condenseFactor;
+
+ dfs = draw_fontscale;
+ draw_fontscale.x *= me.condenseFactor;
+
+ if (me.allowCut) // FIXME allowCut incompatible with align != 0
+ {
+ draw_Text(me.realOrigin, draw_TextShortenToWidth(t, (1 - me.keepspaceLeft - me.keepspaceRight), me.allowColors, fs), fs, me.colorL, me.alpha, me.allowColors);
+ }
+ else if (me.allowWrap) // FIXME allowWrap incompatible with align != 0
+ {
+ getWrappedLine_remaining = t;
+ o = me.realOrigin;
+ while (getWrappedLine_remaining)
+ {
+ if (me.allowColors) t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
+ else t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
+ draw_Text(o, t, fs, me.colorL, me.alpha, me.allowColors);
+ o.y += me.realFontSize.y;
+ }
+ }
+ else
+ {
+ draw_Text(me.realOrigin, t, fs, me.colorL, me.alpha, me.allowColors);
+ }
+
+ draw_fontscale = dfs;
+
+ if (me.isBold) draw_endBoldFont();
+ }
+
+ SUPER(Label).draw(me);
+ }
#endif
#ifndef ITEM_LISTBOX_H
-#define ITEM_LISTBOX_H
-#include "../item.qc"
-CLASS(ListBox, Item)
- METHOD(ListBox, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(ListBox, configureListBox, void(entity, float, float));
- METHOD(ListBox, draw, void(entity));
- METHOD(ListBox, keyDown, float(entity, float, float, float));
- METHOD(ListBox, mouseMove, float(entity, vector));
- METHOD(ListBox, mousePress, float(entity, vector));
- METHOD(ListBox, mouseDrag, float(entity, vector));
- METHOD(ListBox, mouseRelease, float(entity, vector));
- METHOD(ListBox, focusLeave, void(entity));
- ATTRIB(ListBox, focusable, float, 1)
- ATTRIB(ListBox, focusedItem, int, -1)
- ATTRIB(ListBox, focusedItemAlpha, float, 0.3)
- METHOD(ListBox, setFocusedItem, void(entity, int));
- ATTRIB(ListBox, mouseMoveOffset, float, -1) // let know where the cursor is when the list scrolls without moving the cursor
- ATTRIB(ListBox, allowFocusSound, float, 1)
- ATTRIB(ListBox, selectedItem, int, 0)
- ATTRIB(ListBox, size, vector, '0 0 0')
- ATTRIB(ListBox, origin, vector, '0 0 0')
- ATTRIB(ListBox, scrollPos, float, 0) // measured in window heights, fixed when needed
- ATTRIB(ListBox, scrollPosTarget, float, 0)
- METHOD(ListBox, isScrolling, bool(entity));
- ATTRIB(ListBox, needScrollToItem, float, -1)
- METHOD(ListBox, scrollToItem, void(entity, int));
- ATTRIB(ListBox, previousValue, float, 0)
- ATTRIB(ListBox, pressed, float, 0) // 0 = normal, 1 = scrollbar dragging, 2 = item dragging, 3 = released
- ATTRIB(ListBox, pressOffset, float, 0)
+ #define ITEM_LISTBOX_H
+ #include "../item.qc"
+ CLASS(ListBox, Item)
+ METHOD(ListBox, resizeNotify, void(entity, vector, vector, vector, vector));
+ METHOD(ListBox, configureListBox, void(entity, float, float));
+ METHOD(ListBox, draw, void(entity));
+ METHOD(ListBox, keyDown, float(entity, float, float, float));
+ METHOD(ListBox, mouseMove, float(entity, vector));
+ METHOD(ListBox, mousePress, float(entity, vector));
+ METHOD(ListBox, mouseDrag, float(entity, vector));
+ METHOD(ListBox, mouseRelease, float(entity, vector));
+ METHOD(ListBox, focusLeave, void(entity));
+ ATTRIB(ListBox, focusable, float, 1)
+ ATTRIB(ListBox, focusedItem, int, -1)
+ ATTRIB(ListBox, focusedItemAlpha, float, 0.3)
+ METHOD(ListBox, setFocusedItem, void(entity, int));
+ ATTRIB(ListBox, mouseMoveOffset, float, -1) // let know where the cursor is when the list scrolls without moving the cursor
+ ATTRIB(ListBox, allowFocusSound, float, 1)
+ ATTRIB(ListBox, selectedItem, int, 0)
+ ATTRIB(ListBox, size, vector, '0 0 0')
+ ATTRIB(ListBox, origin, vector, '0 0 0')
+ ATTRIB(ListBox, scrollPos, float, 0) // measured in window heights, fixed when needed
+ ATTRIB(ListBox, scrollPosTarget, float, 0)
+ METHOD(ListBox, isScrolling, bool(entity));
+ ATTRIB(ListBox, needScrollToItem, float, -1)
+ METHOD(ListBox, scrollToItem, void(entity, int));
+ ATTRIB(ListBox, previousValue, float, 0)
+ ATTRIB(ListBox, pressed, float, 0) // 0 = normal, 1 = scrollbar dragging, 2 = item dragging, 3 = released
+ ATTRIB(ListBox, pressOffset, float, 0)
- METHOD(ListBox, updateControlTopBottom, void(entity));
- ATTRIB(ListBox, controlTop, float, 0)
- ATTRIB(ListBox, controlBottom, float, 0)
- ATTRIB(ListBox, controlWidth, float, 0)
- ATTRIB(ListBox, dragScrollPos, vector, '0 0 0')
- ATTRIB(ListBox, selectionDoesntMatter, bool, false) // improves scrolling by keys for lists that don't need to show an active selection
+ METHOD(ListBox, updateControlTopBottom, void(entity));
+ ATTRIB(ListBox, controlTop, float, 0)
+ ATTRIB(ListBox, controlBottom, float, 0)
+ ATTRIB(ListBox, controlWidth, float, 0)
+ ATTRIB(ListBox, dragScrollPos, vector, '0 0 0')
+ ATTRIB(ListBox, selectionDoesntMatter, bool, false) // improves scrolling by keys for lists that don't need to show an active selection
- ATTRIB(ListBox, src, string, string_null) // scrollbar
- ATTRIB(ListBox, color, vector, '1 1 1')
- ATTRIB(ListBox, color2, vector, '1 1 1')
- ATTRIB(ListBox, colorC, vector, '1 1 1')
- ATTRIB(ListBox, colorF, vector, '1 1 1')
- ATTRIB(ListBox, tolerance, vector, '0 0 0') // drag tolerance
- ATTRIB(ListBox, scrollbarWidth, float, 0) // pixels
- ATTRIB(ListBox, nItems, float, 42)
- ATTRIB(ListBox, itemHeight, float, 0)
- ATTRIB(ListBox, colorBG, vector, '0 0 0')
- ATTRIB(ListBox, alphaBG, float, 0)
+ ATTRIB(ListBox, src, string, string_null) // scrollbar
+ ATTRIB(ListBox, color, vector, '1 1 1')
+ ATTRIB(ListBox, color2, vector, '1 1 1')
+ ATTRIB(ListBox, colorC, vector, '1 1 1')
+ ATTRIB(ListBox, colorF, vector, '1 1 1')
+ ATTRIB(ListBox, tolerance, vector, '0 0 0') // drag tolerance
+ ATTRIB(ListBox, scrollbarWidth, float, 0) // pixels
+ ATTRIB(ListBox, nItems, float, 42)
+ ATTRIB(ListBox, itemHeight, float, 0)
+ ATTRIB(ListBox, colorBG, vector, '0 0 0')
+ ATTRIB(ListBox, alphaBG, float, 0)
- ATTRIB(ListBox, lastClickedItem, float, -1)
- ATTRIB(ListBox, lastClickedTime, float, 0)
+ ATTRIB(ListBox, lastClickedItem, float, -1)
+ ATTRIB(ListBox, lastClickedTime, float, 0)
- METHOD(ListBox, drawListBoxItem, void(entity, int, vector, bool, bool)); // item number, width/height, isSelected, isFocused
- METHOD(ListBox, clickListBoxItem, void(entity, float, vector)); // item number, relative clickpos
- METHOD(ListBox, doubleClickListBoxItem, void(entity, float, vector)); // item number, relative clickpos
- METHOD(ListBox, setSelected, void(entity, float));
- METHOD(ListBox, focusedItemChangeNotify, void(entity));
+ METHOD(ListBox, drawListBoxItem, void(entity, int, vector, bool, bool)); // item number, width/height, isSelected, isFocused
+ METHOD(ListBox, clickListBoxItem, void(entity, float, vector)); // item number, relative clickpos
+ METHOD(ListBox, doubleClickListBoxItem, void(entity, float, vector)); // item number, relative clickpos
+ METHOD(ListBox, setSelected, void(entity, float));
+ METHOD(ListBox, focusedItemChangeNotify, void(entity));
- METHOD(ListBox, getLastFullyVisibleItemAtScrollPos, float(entity, float));
- METHOD(ListBox, getFirstFullyVisibleItemAtScrollPos, float(entity, float));
+ METHOD(ListBox, getLastFullyVisibleItemAtScrollPos, float(entity, float));
+ METHOD(ListBox, getFirstFullyVisibleItemAtScrollPos, float(entity, float));
- // NOTE: override these four methods if you want variable sized list items
- METHOD(ListBox, getTotalHeight, float(entity));
- METHOD(ListBox, getItemAtPos, float(entity, float));
- METHOD(ListBox, getItemStart, float(entity, float));
- METHOD(ListBox, getItemHeight, float(entity, float));
- // NOTE: if getItemAt* are overridden, it may make sense to cache the
- // start and height of the last item returned by getItemAtPos and fast
- // track returning their properties for getItemStart and getItemHeight.
- // The "hot" code path calls getItemAtPos first, then will query
- // getItemStart and getItemHeight on it soon.
- // When overriding, the following consistency rules must hold:
- // getTotalHeight() == SUM(getItemHeight(i), i, 0, me.nItems-1)
- // getItemStart(i+1) == getItemStart(i) + getItemHeight(i)
- // for 0 <= i < me.nItems-1
- // getItemStart(0) == 0
- // getItemStart(getItemAtPos(p)) <= p
- // if p >= 0
- // getItemAtPos(p) == 0
- // if p < 0
- // getItemStart(getItemAtPos(p)) + getItemHeight(getItemAtPos(p)) > p
- // if p < getTotalHeigt()
- // getItemAtPos(p) == me.nItems - 1
- // if p >= getTotalHeight()
-ENDCLASS(ListBox)
+ // NOTE: override these four methods if you want variable sized list items
+ METHOD(ListBox, getTotalHeight, float(entity));
+ METHOD(ListBox, getItemAtPos, float(entity, float));
+ METHOD(ListBox, getItemStart, float(entity, float));
+ METHOD(ListBox, getItemHeight, float(entity, float));
+ // NOTE: if getItemAt* are overridden, it may make sense to cache the
+ // start and height of the last item returned by getItemAtPos and fast
+ // track returning their properties for getItemStart and getItemHeight.
+ // The "hot" code path calls getItemAtPos first, then will query
+ // getItemStart and getItemHeight on it soon.
+ // When overriding, the following consistency rules must hold:
+ // getTotalHeight() == SUM(getItemHeight(i), i, 0, me.nItems-1)
+ // getItemStart(i+1) == getItemStart(i) + getItemHeight(i)
+ // for 0 <= i < me.nItems-1
+ // getItemStart(0) == 0
+ // getItemStart(getItemAtPos(p)) <= p
+ // if p >= 0
+ // getItemAtPos(p) == 0
+ // if p < 0
+ // getItemStart(getItemAtPos(p)) + getItemHeight(getItemAtPos(p)) > p
+ // if p < getTotalHeigt()
+ // getItemAtPos(p) == me.nItems - 1
+ // if p >= getTotalHeight()
+ ENDCLASS(ListBox)
#endif
#ifdef IMPLEMENTATION
-bool ListBox_isScrolling(entity me)
-{
- return (me.scrollPos != me.scrollPosTarget);
-}
-
-void ListBox_scrollToItem(entity me, int i)
-{
- // scroll doesn't work properly until itemHeight is set to the correct value
- // at the first resizeNotify call
- if(me.itemHeight == 1) // initial temporary value of itemHeight is 1
+ bool ListBox_isScrolling(entity me)
{
- me.needScrollToItem = i;
- return;
+ return me.scrollPos != me.scrollPosTarget;
}
- i = bound(0, i, me.nItems - 1);
+ void ListBox_scrollToItem(entity me, int i)
+ {
+ // scroll doesn't work properly until itemHeight is set to the correct value
+ // at the first resizeNotify call
+ if (me.itemHeight == 1) // initial temporary value of itemHeight is 1
+ {
+ me.needScrollToItem = i;
+ return;
+ }
+
+ i = bound(0, i, me.nItems - 1);
+
+ // scroll the list to make sure the selected item is visible
+ // (even if the selected item doesn't change).
+ if (i < me.getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos))
+ {
+ // above visible area
+ me.scrollPosTarget = me.getItemStart(me, i);
+ }
+ else if (i > me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos))
+ {
+ // below visible area
+ if (i == me.nItems - 1) me.scrollPosTarget = me.getTotalHeight(me) - 1;
+ else me.scrollPosTarget = me.getItemStart(me, i + 1) - 1;
+ }
+ }
- // scroll the list to make sure the selected item is visible
- // (even if the selected item doesn't change).
- if(i < me.getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos))
+ void ListBox_setSelected(entity me, float i)
{
- // above visible area
- me.scrollPosTarget = me.getItemStart(me, i);
+ i = bound(0, i, me.nItems - 1);
+ me.scrollToItem(me, i);
+ me.selectedItem = i;
}
- else if(i > me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos))
+ void ListBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
{
- // below visible area
- if(i == me.nItems - 1)
- me.scrollPosTarget = me.getTotalHeight(me) - 1;
- else
- me.scrollPosTarget = me.getItemStart(me, i + 1) - 1;
+ SUPER(ListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+ me.controlWidth = me.scrollbarWidth / absSize.x;
+ }
+ void ListBox_configureListBox(entity me, float theScrollbarWidth, float theItemHeight)
+ {
+ me.scrollbarWidth = theScrollbarWidth;
+ me.itemHeight = theItemHeight;
}
-}
-
-void ListBox_setSelected(entity me, float i)
-{
- i = bound(0, i, me.nItems - 1);
- me.scrollToItem(me, i);
- me.selectedItem = i;
-}
-void ListBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- SUPER(ListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
- me.controlWidth = me.scrollbarWidth / absSize.x;
-}
-void ListBox_configureListBox(entity me, float theScrollbarWidth, float theItemHeight)
-{
- me.scrollbarWidth = theScrollbarWidth;
- me.itemHeight = theItemHeight;
-}
-float ListBox_getTotalHeight(entity me)
-{
- return me.nItems * me.itemHeight;
-}
-float ListBox_getItemAtPos(entity me, float pos)
-{
- return floor(pos / me.itemHeight);
-}
-float ListBox_getItemStart(entity me, float i)
-{
- return me.itemHeight * i;
-}
-float ListBox_getItemHeight(entity me, float i)
-{
- return me.itemHeight;
-}
+ float ListBox_getTotalHeight(entity me)
+ {
+ return me.nItems * me.itemHeight;
+ }
+ float ListBox_getItemAtPos(entity me, float pos)
+ {
+ return floor(pos / me.itemHeight);
+ }
+ float ListBox_getItemStart(entity me, float i)
+ {
+ return me.itemHeight * i;
+ }
+ float ListBox_getItemHeight(entity me, float i)
+ {
+ return me.itemHeight;
+ }
-float ListBox_getLastFullyVisibleItemAtScrollPos(entity me, float pos)
-{
- return me.getItemAtPos(me, pos + 0.999) - 1;
-}
-float ListBox_getFirstFullyVisibleItemAtScrollPos(entity me, float pos)
-{
- return me.getItemAtPos(me, pos + 0.001) + 1;
-}
-float ListBox_keyDown(entity me, float key, float ascii, float shift)
-{
- if(key == K_MWHEELUP)
+ float ListBox_getLastFullyVisibleItemAtScrollPos(entity me, float pos)
{
- me.scrollPosTarget = max(me.scrollPosTarget - 0.5, 0);
+ return me.getItemAtPos(me, pos + 0.999) - 1;
}
- else if(key == K_MWHEELDOWN)
+ float ListBox_getFirstFullyVisibleItemAtScrollPos(entity me, float pos)
{
- me.scrollPosTarget = min(me.scrollPosTarget + 0.5, max(0, me.getTotalHeight(me) - 1));
+ return me.getItemAtPos(me, pos + 0.001) + 1;
}
- else if(key == K_PGUP || key == K_KP_PGUP)
+ float ListBox_keyDown(entity me, float key, float ascii, float shift)
{
- if(me.selectionDoesntMatter)
+ if (key == K_MWHEELUP)
{
me.scrollPosTarget = max(me.scrollPosTarget - 0.5, 0);
- return 1;
}
+ else if (key == K_MWHEELDOWN)
+ {
+ me.scrollPosTarget = min(me.scrollPosTarget + 0.5, max(0, me.getTotalHeight(me) - 1));
+ }
+ else if (key == K_PGUP || key == K_KP_PGUP)
+ {
+ if (me.selectionDoesntMatter)
+ {
+ me.scrollPosTarget = max(me.scrollPosTarget - 0.5, 0);
+ return 1;
+ }
- float i = me.selectedItem;
- float a = me.getItemHeight(me, i);
- for (;;)
+ float i = me.selectedItem;
+ float a = me.getItemHeight(me, i);
+ for ( ; ; )
+ {
+ --i;
+ if (i < 0) break;
+ a += me.getItemHeight(me, i);
+ if (a >= 1) break;
+ }
+ me.setSelected(me, i + 1);
+ }
+ else if (key == K_PGDN || key == K_KP_PGDN)
{
- --i;
- if (i < 0)
- break;
- a += me.getItemHeight(me, i);
- if (a >= 1)
- break;
+ if (me.selectionDoesntMatter)
+ {
+ me.scrollPosTarget = min(me.scrollPosTarget + 0.5, me.nItems * me.itemHeight - 1);
+ return 1;
+ }
+
+ float i = me.selectedItem;
+ float a = me.getItemHeight(me, i);
+ for ( ; ; )
+ {
+ ++i;
+ if (i >= me.nItems) break;
+ a += me.getItemHeight(me, i);
+ if (a >= 1) break;
+ }
+ me.setSelected(me, i - 1);
}
- me.setSelected(me, i + 1);
- }
- else if(key == K_PGDN || key == K_KP_PGDN)
- {
- if(me.selectionDoesntMatter)
+ else if (key == K_UPARROW || key == K_KP_UPARROW)
{
- me.scrollPosTarget = min(me.scrollPosTarget + 0.5, me.nItems * me.itemHeight - 1);
- return 1;
+ if (me.selectionDoesntMatter)
+ {
+ me.scrollPosTarget = max(me.scrollPosTarget - me.itemHeight, 0);
+ return 1;
+ }
+
+ me.setSelected(me, me.selectedItem - 1);
}
+ else if (key == K_DOWNARROW || key == K_KP_DOWNARROW)
+ {
+ if (me.selectionDoesntMatter)
+ {
+ me.scrollPosTarget = min(me.scrollPosTarget + me.itemHeight, me.nItems * me.itemHeight - 1);
+ return 1;
+ }
- float i = me.selectedItem;
- float a = me.getItemHeight(me, i);
- for (;;)
+ me.setSelected(me, me.selectedItem + 1);
+ }
+ else if (key == K_HOME || key == K_KP_HOME)
{
- ++i;
- if (i >= me.nItems)
- break;
- a += me.getItemHeight(me, i);
- if (a >= 1)
- break;
+ me.setSelected(me, 0);
}
- me.setSelected(me, i - 1);
- }
- else if(key == K_UPARROW || key == K_KP_UPARROW)
- {
- if(me.selectionDoesntMatter)
+ else if (key == K_END || key == K_KP_END)
{
- me.scrollPosTarget = max(me.scrollPosTarget - me.itemHeight, 0);
- return 1;
+ me.setSelected(me, me.nItems - 1);
}
-
- me.setSelected(me, me.selectedItem - 1);
- }
- else if(key == K_DOWNARROW || key == K_KP_DOWNARROW)
- {
- if(me.selectionDoesntMatter)
+ else
{
- me.scrollPosTarget = min(me.scrollPosTarget + me.itemHeight, me.nItems * me.itemHeight - 1);
- return 1;
+ return 0;
}
-
- me.setSelected(me, me.selectedItem + 1);
+ return 1;
}
- else if(key == K_HOME || key == K_KP_HOME)
- me.setSelected(me, 0);
- else if(key == K_END || key == K_KP_END)
- me.setSelected(me, me.nItems - 1);
- else
- return 0;
- return 1;
-}
-float ListBox_mouseMove(entity me, vector pos)
-{
- me.mouseMoveOffset = -1;
- if(pos_x < 0) return 0;
- if(pos_y < 0) return 0;
- if(pos_x >= 1) return 0;
- if(pos_y >= 1) return 0;
- if(pos_x < 1 - me.controlWidth)
- me.mouseMoveOffset = pos.y;
- else
+ float ListBox_mouseMove(entity me, vector pos)
{
- me.setFocusedItem(me, -1);
me.mouseMoveOffset = -1;
- }
- return 1;
-}
-float ListBox_mouseDrag(entity me, vector pos)
-{
- float hit;
- me.updateControlTopBottom(me);
- me.dragScrollPos = pos;
- if(me.pressed == 1)
- {
- hit = 1;
- if(pos.x < 1 - me.controlWidth - me.tolerance.y * me.controlWidth) hit = 0;
- if(pos.y < 0 - me.tolerance.x) hit = 0;
- if(pos.x >= 1 + me.tolerance.y * me.controlWidth) hit = 0;
- if(pos.y >= 1 + me.tolerance.x) hit = 0;
- if(hit)
+ if (pos_x < 0) return 0;
+ if (pos_y < 0) return 0;
+ if (pos_x >= 1) return 0;
+ if (pos_y >= 1) return 0;
+ if (pos_x < 1 - me.controlWidth)
{
- // calculate new pos to v
- float d;
- d = (pos.y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.getTotalHeight(me) - 1);
- me.scrollPosTarget = me.previousValue + d;
+ me.mouseMoveOffset = pos.y;
}
else
- me.scrollPosTarget = me.previousValue;
- me.scrollPosTarget = min(me.scrollPosTarget, me.getTotalHeight(me) - 1);
- me.scrollPosTarget = max(me.scrollPosTarget, 0);
- }
- else if(me.pressed == 2)
- {
- me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
- me.setFocusedItem(me, me.selectedItem);
- me.mouseMoveOffset = -1;
+ {
+ me.setFocusedItem(me, -1);
+ me.mouseMoveOffset = -1;
+ }
+ return 1;
}
- return 1;
-}
-float ListBox_mousePress(entity me, vector pos)
-{
- if(pos.x < 0) return 0;
- if(pos.y < 0) return 0;
- if(pos.x >= 1) return 0;
- if(pos.y >= 1) return 0;
- me.dragScrollPos = pos;
- me.updateControlTopBottom(me);
- if(pos.x >= 1 - me.controlWidth)
+ float ListBox_mouseDrag(entity me, vector pos)
{
- // if hit, set me.pressed, otherwise scroll by one page
- if(pos.y < me.controlTop)
+ float hit;
+ me.updateControlTopBottom(me);
+ me.dragScrollPos = pos;
+ if (me.pressed == 1)
+ {
+ hit = 1;
+ if (pos.x < 1 - me.controlWidth - me.tolerance.y * me.controlWidth) hit = 0;
+ if (pos.y < 0 - me.tolerance.x) hit = 0;
+ if (pos.x >= 1 + me.tolerance.y * me.controlWidth) hit = 0;
+ if (pos.y >= 1 + me.tolerance.x) hit = 0;
+ if (hit)
+ {
+ // calculate new pos to v
+ float d;
+ d = (pos.y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.getTotalHeight(me) - 1);
+ me.scrollPosTarget = me.previousValue + d;
+ }
+ else
+ {
+ me.scrollPosTarget = me.previousValue;
+ }
+ me.scrollPosTarget = min(me.scrollPosTarget, me.getTotalHeight(me) - 1);
+ me.scrollPosTarget = max(me.scrollPosTarget, 0);
+ }
+ else if (me.pressed == 2)
{
- // page up
- me.scrollPosTarget = max(me.scrollPosTarget - 1, 0);
+ me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
+ me.setFocusedItem(me, me.selectedItem);
+ me.mouseMoveOffset = -1;
}
- else if(pos.y > me.controlBottom)
+ return 1;
+ }
+ float ListBox_mousePress(entity me, vector pos)
+ {
+ if (pos.x < 0) return 0;
+ if (pos.y < 0) return 0;
+ if (pos.x >= 1) return 0;
+ if (pos.y >= 1) return 0;
+ me.dragScrollPos = pos;
+ me.updateControlTopBottom(me);
+ if (pos.x >= 1 - me.controlWidth)
{
- // page down
- me.scrollPosTarget = min(me.scrollPosTarget + 1, me.getTotalHeight(me) - 1);
+ // if hit, set me.pressed, otherwise scroll by one page
+ if (pos.y < me.controlTop)
+ {
+ // page up
+ me.scrollPosTarget = max(me.scrollPosTarget - 1, 0);
+ }
+ else if (pos.y > me.controlBottom)
+ {
+ // page down
+ me.scrollPosTarget = min(me.scrollPosTarget + 1, me.getTotalHeight(me) - 1);
+ }
+ else
+ {
+ me.pressed = 1;
+ me.pressOffset = pos.y;
+ me.previousValue = me.scrollPos;
+ }
}
else
{
- me.pressed = 1;
- me.pressOffset = pos.y;
- me.previousValue = me.scrollPos;
+ // continue doing that while dragging (even when dragging outside). When releasing, forward the click to the then selected item.
+ me.pressed = 2;
+ // an item has been clicked. Select it, ...
+ me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
+ me.setFocusedItem(me, me.selectedItem);
}
+ return 1;
}
- else
- {
- // continue doing that while dragging (even when dragging outside). When releasing, forward the click to the then selected item.
- me.pressed = 2;
- // an item has been clicked. Select it, ...
- me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
- me.setFocusedItem(me, me.selectedItem);
- }
- return 1;
-}
-void ListBox_setFocusedItem(entity me, int item)
-{
- float focusedItem_save = me.focusedItem;
- me.focusedItem = (item < me.nItems) ? item : -1;
- if(focusedItem_save != me.focusedItem)
+ void ListBox_setFocusedItem(entity me, int item)
{
- me.focusedItemChangeNotify(me);
- if(me.focusedItem >= 0)
- me.focusedItemAlpha = SKINALPHA_LISTBOX_FOCUSED;
- }
-}
-float ListBox_mouseRelease(entity me, vector pos)
-{
- if(me.pressed == 1)
- {
- // slider dragging mode
- // in that case, nothing happens on releasing
+ float focusedItem_save = me.focusedItem;
+ me.focusedItem = (item < me.nItems) ? item : -1;
+ if (focusedItem_save != me.focusedItem)
+ {
+ me.focusedItemChangeNotify(me);
+ if (me.focusedItem >= 0) me.focusedItemAlpha = SKINALPHA_LISTBOX_FOCUSED;
+ }
}
- else if(me.pressed == 2)
+ float ListBox_mouseRelease(entity me, vector pos)
{
- me.pressed = 3; // do that here, so setSelected can know the mouse has been released
- // item dragging mode
- // select current one one last time...
- me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
- me.setFocusedItem(me, me.selectedItem);
- // and give it a nice click event
- if(me.nItems > 0)
+ if (me.pressed == 1)
+ {
+ // slider dragging mode
+ // in that case, nothing happens on releasing
+ }
+ else if (me.pressed == 2)
{
- vector where = globalToBox(pos, eY * (me.getItemStart(me, me.selectedItem) - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, me.selectedItem));
+ me.pressed = 3; // do that here, so setSelected can know the mouse has been released
+ // item dragging mode
+ // select current one one last time...
+ me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
+ me.setFocusedItem(me, me.selectedItem);
+ // and give it a nice click event
+ if (me.nItems > 0)
+ {
+ vector where = globalToBox(pos, eY * (me.getItemStart(me, me.selectedItem) - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, me.selectedItem));
- if((me.selectedItem == me.lastClickedItem) && (time < me.lastClickedTime + 0.3))
- me.doubleClickListBoxItem(me, me.selectedItem, where);
- else
- me.clickListBoxItem(me, me.selectedItem, where);
+ if ((me.selectedItem == me.lastClickedItem) && (time < me.lastClickedTime + 0.3)) me.doubleClickListBoxItem(me, me.selectedItem, where);
+ else me.clickListBoxItem(me, me.selectedItem, where);
- me.lastClickedItem = me.selectedItem;
- me.lastClickedTime = time;
+ me.lastClickedItem = me.selectedItem;
+ me.lastClickedTime = time;
+ }
}
+ me.pressed = 0;
+ return 1;
}
- me.pressed = 0;
- return 1;
-}
-void ListBox_focusLeave(entity me)
-{
- // Reset the var pressed in case listbox loses focus
- // by a mouse click on an item of the list
- // for example showing a dialog on right click
- me.pressed = 0;
- me.setFocusedItem(me, -1);
- me.mouseMoveOffset = -1;
-}
-void ListBox_updateControlTopBottom(entity me)
-{
- float f;
- // scrollPos is in 0..1 and indicates where the "page" currently shown starts.
- if(me.getTotalHeight(me) <= 1)
+ void ListBox_focusLeave(entity me)
{
- // we don't need no stinkin' scrollbar, we don't need no view control...
- me.controlTop = 0;
- me.controlBottom = 1;
- me.scrollPos = 0;
+ // Reset the var pressed in case listbox loses focus
+ // by a mouse click on an item of the list
+ // for example showing a dialog on right click
+ me.pressed = 0;
+ me.setFocusedItem(me, -1);
+ me.mouseMoveOffset = -1;
}
- else
+ void ListBox_updateControlTopBottom(entity me)
{
- // if scroll pos is below end of list, fix it
- me.scrollPos = min(me.scrollPos, me.getTotalHeight(me) - 1);
- // if scroll pos is above beginning of list, fix it
- me.scrollPos = max(me.scrollPos, 0);
- // now that we know where the list is scrolled to, find out where to draw the control
- me.controlTop = max(0, me.scrollPos / me.getTotalHeight(me));
- me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
-
- float minfactor;
- minfactor = 2 * me.controlWidth / me.size.y * me.size.x;
- f = me.controlBottom - me.controlTop;
- if(f < minfactor) // FIXME good default?
+ float f;
+ // scrollPos is in 0..1 and indicates where the "page" currently shown starts.
+ if (me.getTotalHeight(me) <= 1)
{
- // f * X + 1 * (1-X) = minfactor
- // (f - 1) * X + 1 = minfactor
- // (f - 1) * X = minfactor - 1
- // X = (minfactor - 1) / (f - 1)
- f = (minfactor - 1) / (f - 1);
- me.controlTop = me.controlTop * f + 0 * (1 - f);
- me.controlBottom = me.controlBottom * f + 1 * (1 - f);
+ // we don't need no stinkin' scrollbar, we don't need no view control...
+ me.controlTop = 0;
+ me.controlBottom = 1;
+ me.scrollPos = 0;
+ }
+ else
+ {
+ // if scroll pos is below end of list, fix it
+ me.scrollPos = min(me.scrollPos, me.getTotalHeight(me) - 1);
+ // if scroll pos is above beginning of list, fix it
+ me.scrollPos = max(me.scrollPos, 0);
+ // now that we know where the list is scrolled to, find out where to draw the control
+ me.controlTop = max(0, me.scrollPos / me.getTotalHeight(me));
+ me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
+
+ float minfactor;
+ minfactor = 2 * me.controlWidth / me.size.y * me.size.x;
+ f = me.controlBottom - me.controlTop;
+ if (f < minfactor) // FIXME good default?
+ {
+ // f * X + 1 * (1-X) = minfactor
+ // (f - 1) * X + 1 = minfactor
+ // (f - 1) * X = minfactor - 1
+ // X = (minfactor - 1) / (f - 1)
+ f = (minfactor - 1) / (f - 1);
+ me.controlTop = me.controlTop * f + 0 * (1 - f);
+ me.controlBottom = me.controlBottom * f + 1 * (1 - f);
+ }
}
}
-}
-AUTOCVAR(menu_scroll_averaging_time, float, 0.16, "smooth scroll averaging time");
+ AUTOCVAR(menu_scroll_averaging_time, float, 0.16, "smooth scroll averaging time");
// scroll faster while dragging the scrollbar
-AUTOCVAR(menu_scroll_averaging_time_pressed, float, 0.06, "smooth scroll averaging time when dragging the scrollbar");
-void ListBox_draw(entity me)
-{
- float i;
- vector absSize, fillSize = '0 0 0';
- vector oldshift, oldscale;
+ AUTOCVAR(menu_scroll_averaging_time_pressed, float, 0.06, "smooth scroll averaging time when dragging the scrollbar");
+ void ListBox_draw(entity me)
+ {
+ float i;
+ vector absSize, fillSize = '0 0 0';
+ vector oldshift, oldscale;
- // we can't do this in mouseMove as the list can scroll without moving the cursor
- if(me.mouseMoveOffset != -1)
- me.setFocusedItem(me, me.getItemAtPos(me, me.scrollPos + me.mouseMoveOffset));
+ // we can't do this in mouseMove as the list can scroll without moving the cursor
+ if (me.mouseMoveOffset != -1) me.setFocusedItem(me, me.getItemAtPos(me, me.scrollPos + me.mouseMoveOffset));
- if(me.needScrollToItem >= 0)
- {
- me.scrollToItem(me, me.needScrollToItem);
- me.needScrollToItem = -1;
- }
- if(me.scrollPos != me.scrollPosTarget)
- {
- float averaging_time = (me.pressed == 1)
- ? autocvar_menu_scroll_averaging_time_pressed
- : autocvar_menu_scroll_averaging_time;
- // this formula works with whatever framerate
- float f = averaging_time ? exp(-frametime / averaging_time) : 0;
- me.scrollPos = me.scrollPos * f + me.scrollPosTarget * (1 - f);
- if(fabs(me.scrollPos - me.scrollPosTarget) < 0.001)
- me.scrollPos = me.scrollPosTarget;
- }
+ if (me.needScrollToItem >= 0)
+ {
+ me.scrollToItem(me, me.needScrollToItem);
+ me.needScrollToItem = -1;
+ }
+ if (me.scrollPos != me.scrollPosTarget)
+ {
+ float averaging_time = (me.pressed == 1)
+ ? autocvar_menu_scroll_averaging_time_pressed
+ : autocvar_menu_scroll_averaging_time;
+ // this formula works with whatever framerate
+ float f = averaging_time ? exp(-frametime / averaging_time) : 0;
+ me.scrollPos = me.scrollPos * f + me.scrollPosTarget * (1 - f);
+ if (fabs(me.scrollPos - me.scrollPosTarget) < 0.001) me.scrollPos = me.scrollPosTarget;
+ }
- if(me.pressed == 2)
- me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
- me.updateControlTopBottom(me);
- fillSize.x = (1 - me.controlWidth);
- if(me.alphaBG)
- draw_Fill('0 0 0', '0 1 0' + fillSize, me.colorBG, me.alphaBG);
- if(me.controlWidth)
- {
- draw_VertButtonPicture(eX * (1 - me.controlWidth), strcat(me.src, "_s"), eX * me.controlWidth + eY, me.color2, 1);
- if(me.getTotalHeight(me) > 1)
+ if (me.pressed == 2) me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
+ me.updateControlTopBottom(me);
+ fillSize.x = (1 - me.controlWidth);
+ if (me.alphaBG) draw_Fill('0 0 0', '0 1 0' + fillSize, me.colorBG, me.alphaBG);
+ if (me.controlWidth)
{
- vector o, s;
- o = eX * (1 - me.controlWidth) + eY * me.controlTop;
- s = eX * me.controlWidth + eY * (me.controlBottom - me.controlTop);
- if(me.pressed == 1)
- draw_VertButtonPicture(o, strcat(me.src, "_c"), s, me.colorC, 1);
- else if(me.focused)
- draw_VertButtonPicture(o, strcat(me.src, "_f"), s, me.colorF, 1);
- else
- draw_VertButtonPicture(o, strcat(me.src, "_n"), s, me.color, 1);
+ draw_VertButtonPicture(eX * (1 - me.controlWidth), strcat(me.src, "_s"), eX * me.controlWidth + eY, me.color2, 1);
+ if (me.getTotalHeight(me) > 1)
+ {
+ vector o, s;
+ o = eX * (1 - me.controlWidth) + eY * me.controlTop;
+ s = eX * me.controlWidth + eY * (me.controlBottom - me.controlTop);
+ if (me.pressed == 1) draw_VertButtonPicture(o, strcat(me.src, "_c"), s, me.colorC, 1);
+ else if (me.focused) draw_VertButtonPicture(o, strcat(me.src, "_f"), s, me.colorF, 1);
+ else draw_VertButtonPicture(o, strcat(me.src, "_n"), s, me.color, 1);
+ }
}
- }
- draw_SetClip();
- oldshift = draw_shift;
- oldscale = draw_scale;
+ draw_SetClip();
+ oldshift = draw_shift;
+ oldscale = draw_scale;
- float y;
- i = me.getItemAtPos(me, me.scrollPos);
- y = me.getItemStart(me, i) - me.scrollPos;
- for (; i < me.nItems && y < 1; ++i)
- {
- draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
- vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
- absSize = boxToGlobalSize(relSize, me.size);
- draw_scale = boxToGlobalSize(relSize, oldscale);
- me.drawListBoxItem(me, i, absSize, (me.selectedItem == i), (me.focusedItem == i));
- y += relSize.y;
- }
- draw_ClearClip();
+ float y;
+ i = me.getItemAtPos(me, me.scrollPos);
+ y = me.getItemStart(me, i) - me.scrollPos;
+ for ( ; i < me.nItems && y < 1; ++i)
+ {
+ draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
+ vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
+ absSize = boxToGlobalSize(relSize, me.size);
+ draw_scale = boxToGlobalSize(relSize, oldscale);
+ me.drawListBoxItem(me, i, absSize, (me.selectedItem == i), (me.focusedItem == i));
+ y += relSize.y;
+ }
+ draw_ClearClip();
- draw_shift = oldshift;
- draw_scale = oldscale;
- SUPER(ListBox).draw(me);
-}
+ draw_shift = oldshift;
+ draw_scale = oldscale;
+ SUPER(ListBox).draw(me);
+ }
-void ListBox_focusedItemChangeNotify(entity me)
-{
-}
+ void ListBox_focusedItemChangeNotify(entity me)
+ {}
-void ListBox_clickListBoxItem(entity me, float i, vector where)
-{
- // template method
-}
+ void ListBox_clickListBoxItem(entity me, float i, vector where)
+ {
+ // template method
+ }
-void ListBox_doubleClickListBoxItem(entity me, float i, vector where)
-{
- // template method
-}
+ void ListBox_doubleClickListBoxItem(entity me, float i, vector where)
+ {
+ // template method
+ }
-void ListBox_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
-{
- draw_Text('0 0 0', sprintf(_("Item %d"), i), eX * (8 / absSize.x) + eY * (8 / absSize.y), (isSelected ? '0 1 0' : '1 1 1'), 1, 0);
-}
+ void ListBox_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
+ {
+ draw_Text('0 0 0', sprintf(_("Item %d"), i), eX * (8 / absSize.x) + eY * (8 / absSize.y), (isSelected ? '0 1 0' : '1 1 1'), 1, 0);
+ }
#endif
#ifndef ITEM_MODALCONTROLLER_H
-#define ITEM_MODALCONTROLLER_H
-#include "container.qc"
-CLASS(ModalController, Container)
- METHOD(ModalController, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(ModalController, draw, void(entity));
- METHOD(ModalController, showChild, void(entity, entity, vector, vector, float));
- METHOD(ModalController, hideChild, void(entity, entity, float));
- METHOD(ModalController, hideAll, void(entity, float));
- METHOD(ModalController, addItem, void(entity, entity, vector, vector, float));
- METHOD(ModalController, addTab, void(entity, entity, entity));
+ #define ITEM_MODALCONTROLLER_H
+ #include "container.qc"
+ CLASS(ModalController, Container)
+ METHOD(ModalController, resizeNotify, void(entity, vector, vector, vector, vector));
+ METHOD(ModalController, draw, void(entity));
+ METHOD(ModalController, showChild, void(entity, entity, vector, vector, float));
+ METHOD(ModalController, hideChild, void(entity, entity, float));
+ METHOD(ModalController, hideAll, void(entity, float));
+ METHOD(ModalController, addItem, void(entity, entity, vector, vector, float));
+ METHOD(ModalController, addTab, void(entity, entity, entity));
- METHOD(ModalController, initializeDialog, void(entity, entity));
+ METHOD(ModalController, initializeDialog, void(entity, entity));
- METHOD(ModalController, switchState, void(entity, entity, float, float));
- ATTRIB(ModalController, origin, vector, '0 0 0')
- ATTRIB(ModalController, size, vector, '0 0 0')
- ATTRIB(ModalController, previousButton, entity, NULL)
- ATTRIB(ModalController, fadedAlpha, float, 0.3)
-ENDCLASS(ModalController)
+ METHOD(ModalController, switchState, void(entity, entity, float, float));
+ ATTRIB(ModalController, origin, vector, '0 0 0')
+ ATTRIB(ModalController, size, vector, '0 0 0')
+ ATTRIB(ModalController, previousButton, entity, NULL)
+ ATTRIB(ModalController, fadedAlpha, float, 0.3)
+ ENDCLASS(ModalController)
-.entity tabSelectingButton;
-.vector origin;
-.vector size;
-void TabButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
-void DialogOpenButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
-void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize);
-void DialogCloseButton_Click(entity button, entity tab); // assumes a button has set the above fields to the tab to close
+ .entity tabSelectingButton;
+ .vector origin;
+ .vector size;
+ void TabButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
+ void DialogOpenButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
+ void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize);
+ void DialogCloseButton_Click(entity button, entity tab); // assumes a button has set the above fields to the tab to close
#endif
#ifdef IMPLEMENTATION
// - to initialize: me.hideAll(me, 1); me.showChild(me, me.firstChild, '0 0 0', '0 0 0', 1);
// - to show a tab: me.hideChild(me, currentTab, 0); me.showChild(me, newTab, buttonAbsOrigin, buttonAbsSize, 0);
-.vector ModalController_initialSize;
-.vector ModalController_initialOrigin;
-.vector ModalController_initialFontScale;
-.float ModalController_initialAlpha;
-.vector ModalController_buttonSize;
-.vector ModalController_buttonOrigin;
-.float ModalController_state;
-.float ModalController_factor;
-.entity ModalController_controllingButton;
+ .vector ModalController_initialSize;
+ .vector ModalController_initialOrigin;
+ .vector ModalController_initialFontScale;
+ .float ModalController_initialAlpha;
+ .vector ModalController_buttonSize;
+ .vector ModalController_buttonOrigin;
+ .float ModalController_state;
+ .float ModalController_factor;
+ .entity ModalController_controllingButton;
-void ModalController_initializeDialog(entity me, entity root)
-{
- me.hideAll(me, 1);
- me.showChild(me, root, '0 0 0', '0 0 0', 1); // someone else animates for us
-}
-
-void TabButton_Click(entity button, entity tab)
-{
- if(tab.ModalController_state == 1)
- return;
- tab.parent.hideAll(tab.parent, 0);
- button.forcePressed = 1;
- tab.ModalController_controllingButton = button;
- tab.parent.showChild(tab.parent, tab, button.origin, button.size, 0);
-}
-
-void DialogOpenButton_Click(entity button, entity tab)
-{
- DialogOpenButton_Click_withCoords(button, tab, button.origin, button.size);
-}
+ void ModalController_initializeDialog(entity me, entity root)
+ {
+ me.hideAll(me, 1);
+ me.showChild(me, root, '0 0 0', '0 0 0', 1); // someone else animates for us
+ }
-void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize)
-{
- if(tab.ModalController_state)
- return;
- if(button)
+ void TabButton_Click(entity button, entity tab)
+ {
+ if (tab.ModalController_state == 1) return;
+ tab.parent.hideAll(tab.parent, 0);
button.forcePressed = 1;
- if(tab.parent.focusedChild)
- tab.parent.focusedChild.saveFocus(tab.parent.focusedChild);
- tab.ModalController_controllingButton = button;
- tab.parent.showChild(tab.parent, tab, theOrigin, theSize, 0);
-}
+ tab.ModalController_controllingButton = button;
+ tab.parent.showChild(tab.parent, tab, button.origin, button.size, 0);
+ }
-void DialogCloseButton_Click(entity button, entity tab)
-{
- tab.parent.hideChild(tab.parent, tab, 0);
-}
+ void DialogOpenButton_Click(entity button, entity tab)
+ {
+ DialogOpenButton_Click_withCoords(button, tab, button.origin, button.size);
+ }
-void ModalController_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, ModalController_initialOrigin, ModalController_initialSize, ModalController_initialFontScale);
-}
+ void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize)
+ {
+ if (tab.ModalController_state) return;
+ if (button) button.forcePressed = 1;
+ if (tab.parent.focusedChild) tab.parent.focusedChild.saveFocus(tab.parent.focusedChild);
+ tab.ModalController_controllingButton = button;
+ tab.parent.showChild(tab.parent, tab, theOrigin, theSize, 0);
+ }
-void ModalController_switchState(entity me, entity other, float state, float skipAnimation)
-{
- float previousState;
- previousState = other.ModalController_state;
- if(state == previousState && !skipAnimation)
- return;
- other.ModalController_state = state;
- switch(state)
+ void DialogCloseButton_Click(entity button, entity tab)
{
- case 0:
- other.ModalController_factor = 1 - other.Container_alpha / other.ModalController_initialAlpha;
- // fading out
- break;
- case 1:
- other.ModalController_factor = other.Container_alpha / other.ModalController_initialAlpha;
- if(previousState == 0 && !skipAnimation)
- {
- other.Container_origin = other.ModalController_buttonOrigin;
- other.Container_size = other.ModalController_buttonSize;
- }
- // zooming in
- break;
- case 2:
- other.ModalController_factor = bound(0, (1 - other.Container_alpha / other.ModalController_initialAlpha) / me.fadedAlpha, 1);
- // fading out halfway
- break;
+ tab.parent.hideChild(tab.parent, tab, 0);
}
- if(skipAnimation)
- other.ModalController_factor = 1;
-}
-void ModalController_draw(entity me)
-{
- entity e;
- entity front;
- float animating;
- float f; // animation factor
- float df; // animation step size
- float prevFactor, targetFactor;
- vector targetOrigin, targetSize; float targetAlpha;
- vector fs;
- animating = 0;
+ void ModalController_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+ {
+ me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, ModalController_initialOrigin, ModalController_initialSize, ModalController_initialFontScale);
+ }
- front = NULL;
- for(e = me.firstChild; e; e = e.nextSibling)
- if(e.ModalController_state)
+ void ModalController_switchState(entity me, entity other, float state, float skipAnimation)
+ {
+ float previousState;
+ previousState = other.ModalController_state;
+ if (state == previousState && !skipAnimation) return;
+ other.ModalController_state = state;
+ switch (state)
{
- if(front)
- me.switchState(me, front, 2, 0);
- front = e;
+ case 0:
+ other.ModalController_factor = 1 - other.Container_alpha / other.ModalController_initialAlpha;
+ // fading out
+ break;
+ case 1:
+ other.ModalController_factor = other.Container_alpha / other.ModalController_initialAlpha;
+ if (previousState == 0 && !skipAnimation)
+ {
+ other.Container_origin = other.ModalController_buttonOrigin;
+ other.Container_size = other.ModalController_buttonSize;
+ }
+ // zooming in
+ break;
+ case 2:
+ other.ModalController_factor = bound(0, (1 - other.Container_alpha / other.ModalController_initialAlpha) / me.fadedAlpha, 1);
+ // fading out halfway
+ break;
}
- if(front)
- me.switchState(me, front, 1, 0);
-
- df = frametime * 3; // animation speed
+ if (skipAnimation) other.ModalController_factor = 1;
+ }
- for(e = me.firstChild; e; e = e.nextSibling)
+ void ModalController_draw(entity me)
{
- if(e.ModalController_state == 2)
- {
- // fading out partially
- targetOrigin = e.Container_origin; // stay as is
- targetSize = e.Container_size; // stay as is
- targetAlpha = me.fadedAlpha * e.ModalController_initialAlpha;
- }
- else if(e.ModalController_state == 1)
- {
- // zooming in
- targetOrigin = e.ModalController_initialOrigin;
- targetSize = e.ModalController_initialSize;
- targetAlpha = e.ModalController_initialAlpha;
- }
- else
- {
- // fading out
- targetOrigin = e.Container_origin; // stay as is
- targetSize = e.Container_size; // stay as is
- targetAlpha = 0;
- }
+ entity e;
+ entity front;
+ float animating;
+ float f; // animation factor
+ float df; // animation step size
+ float prevFactor, targetFactor;
+ vector targetOrigin, targetSize;
+ float targetAlpha;
+ vector fs;
+ animating = 0;
- f = (e.ModalController_factor = min(1, e.ModalController_factor + df));
- if(f == 1)
- {
- prevFactor = 0;
- targetFactor = 1;
- e.Container_origin = targetOrigin;
- e.Container_size = targetSize;
- me.setAlphaOf(me, e, targetAlpha);
- }
- else
+ front = NULL;
+ for (e = me.firstChild; e; e = e.nextSibling)
+ if (e.ModalController_state)
+ {
+ if (front) me.switchState(me, front, 2, 0);
+ front = e;
+ }
+ if (front) me.switchState(me, front, 1, 0);
+
+ df = frametime * 3; // animation speed
+
+ for (e = me.firstChild; e; e = e.nextSibling)
{
- prevFactor = (1 - f) / (1 - f + df);
- if(!e.ModalController_state) // optimize code and avoid precision errors
- me.setAlphaOf(me, e, e.Container_alpha * prevFactor);
+ if (e.ModalController_state == 2)
+ {
+ // fading out partially
+ targetOrigin = e.Container_origin; // stay as is
+ targetSize = e.Container_size; // stay as is
+ targetAlpha = me.fadedAlpha * e.ModalController_initialAlpha;
+ }
+ else if (e.ModalController_state == 1)
+ {
+ // zooming in
+ targetOrigin = e.ModalController_initialOrigin;
+ targetSize = e.ModalController_initialSize;
+ targetAlpha = e.ModalController_initialAlpha;
+ }
else
{
- animating = 1;
- targetFactor = df / (1 - f + df);
+ // fading out
+ targetOrigin = e.Container_origin; // stay as is
+ targetSize = e.Container_size; // stay as is
+ targetAlpha = 0;
+ }
- if(e.ModalController_state == 1)
+ f = (e.ModalController_factor = min(1, e.ModalController_factor + df));
+ if (f == 1)
+ {
+ prevFactor = 0;
+ targetFactor = 1;
+ e.Container_origin = targetOrigin;
+ e.Container_size = targetSize;
+ me.setAlphaOf(me, e, targetAlpha);
+ }
+ else
+ {
+ prevFactor = (1 - f) / (1 - f + df);
+ if (!e.ModalController_state) // optimize code and avoid precision errors
+ {
+ me.setAlphaOf(me, e, e.Container_alpha * prevFactor);
+ }
+ else
{
- e.Container_origin = e.Container_origin * prevFactor + targetOrigin * targetFactor;
- e.Container_size = e.Container_size * prevFactor + targetSize * targetFactor;
+ animating = 1;
+ targetFactor = df / (1 - f + df);
+
+ if (e.ModalController_state == 1)
+ {
+ e.Container_origin = e.Container_origin * prevFactor + targetOrigin * targetFactor;
+ e.Container_size = e.Container_size * prevFactor + targetSize * targetFactor;
+ }
+ me.setAlphaOf(me, e, e.Container_alpha * prevFactor + targetAlpha * targetFactor);
}
- me.setAlphaOf(me, e, e.Container_alpha * prevFactor + targetAlpha * targetFactor);
+ }
+ // assume: o == to * f_prev + X * (1 - f_prev)
+ // make: o' = to * f + X * (1 - f)
+ // -->
+ // X == (o - to * f_prev) / (1 - f_prev)
+ // o' = to * f + (o - to * f_prev) / (1 - f_prev) * (1 - f)
+ // --> (maxima)
+ // o' = (to * (f - f_prev) + o * (1 - f)) / (1 - f_prev)
+
+ if (e.ModalController_state == 1)
+ {
+ fs = globalToBoxSize(e.Container_size, e.ModalController_initialSize);
+ e.Container_fontscale_x = fs.x * e.ModalController_initialFontScale.x;
+ e.Container_fontscale_y = fs.y * e.ModalController_initialFontScale.y;
}
}
- // assume: o == to * f_prev + X * (1 - f_prev)
- // make: o' = to * f + X * (1 - f)
- // -->
- // X == (o - to * f_prev) / (1 - f_prev)
- // o' = to * f + (o - to * f_prev) / (1 - f_prev) * (1 - f)
- // --> (maxima)
- // o' = (to * (f - f_prev) + o * (1 - f)) / (1 - f_prev)
- if(e.ModalController_state == 1)
+ if (animating || !me.focused) me.setFocus(me, NULL);
+ else me.setFocus(me, front);
+ SUPER(ModalController).draw(me);
+ }
+
+ void ModalController_addTab(entity me, entity other, entity tabButton)
+ {
+ me.addItem(me, other, '0 0 0', '1 1 1', 1);
+ tabButton.onClick = TabButton_Click;
+ tabButton.onClickEntity = other;
+ other.tabSelectingButton = tabButton;
+ if (other == me.firstChild)
{
- fs = globalToBoxSize(e.Container_size, e.ModalController_initialSize);
- e.Container_fontscale_x = fs.x * e.ModalController_initialFontScale.x;
- e.Container_fontscale_y = fs.y * e.ModalController_initialFontScale.y;
+ tabButton.forcePressed = 1;
+ other.ModalController_controllingButton = tabButton;
+ me.showChild(me, other, '0 0 0', '0 0 0', 1);
}
}
- if(animating || !me.focused)
- me.setFocus(me, NULL);
- else
- me.setFocus(me, front);
- SUPER(ModalController).draw(me);
-}
-
-void ModalController_addTab(entity me, entity other, entity tabButton)
-{
- me.addItem(me, other, '0 0 0', '1 1 1', 1);
- tabButton.onClick = TabButton_Click;
- tabButton.onClickEntity = other;
- other.tabSelectingButton = tabButton;
- if(other == me.firstChild)
+ void ModalController_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
{
- tabButton.forcePressed = 1;
- other.ModalController_controllingButton = tabButton;
- me.showChild(me, other, '0 0 0', '0 0 0', 1);
+ SUPER(ModalController).addItem(me, other, theOrigin, theSize, (other == me.firstChild) ? theAlpha : 0);
+ other.ModalController_initialFontScale = other.Container_fontscale;
+ other.ModalController_initialSize = other.Container_size;
+ other.ModalController_initialOrigin = other.Container_origin;
+ other.ModalController_initialAlpha = theAlpha; // hope Container never modifies this
+ if (other.ModalController_initialFontScale == '0 0 0') other.ModalController_initialFontScale = '1 1 0';
}
-}
-void ModalController_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
-{
- SUPER(ModalController).addItem(me, other, theOrigin, theSize, (other == me.firstChild) ? theAlpha : 0);
- other.ModalController_initialFontScale = other.Container_fontscale;
- other.ModalController_initialSize = other.Container_size;
- other.ModalController_initialOrigin = other.Container_origin;
- other.ModalController_initialAlpha = theAlpha; // hope Container never modifies this
- if(other.ModalController_initialFontScale == '0 0 0')
- other.ModalController_initialFontScale = '1 1 0';
-}
-
-void ModalController_showChild(entity me, entity other, vector theOrigin, vector theSize, float skipAnimation)
-{
- if(other.ModalController_state == 0 || skipAnimation)
+ void ModalController_showChild(entity me, entity other, vector theOrigin, vector theSize, float skipAnimation)
{
- me.setFocus(me, NULL);
- if(!skipAnimation)
+ if (other.ModalController_state == 0 || skipAnimation)
{
- other.ModalController_buttonOrigin = globalToBox(theOrigin, me.origin, me.size);
- other.ModalController_buttonSize = globalToBoxSize(theSize, me.size);
- }
- me.switchState(me, other, 1, skipAnimation);
- } // zoom in from button (factor increases)
-}
+ me.setFocus(me, NULL);
+ if (!skipAnimation)
+ {
+ other.ModalController_buttonOrigin = globalToBox(theOrigin, me.origin, me.size);
+ other.ModalController_buttonSize = globalToBoxSize(theSize, me.size);
+ }
+ me.switchState(me, other, 1, skipAnimation);
+ } // zoom in from button (factor increases)
+ }
-void ModalController_hideAll(entity me, float skipAnimation)
-{
- entity e;
- for(e = me.firstChild; e; e = e.nextSibling)
- me.hideChild(me, e, skipAnimation);
-}
+ void ModalController_hideAll(entity me, float skipAnimation)
+ {
+ entity e;
+ for (e = me.firstChild; e; e = e.nextSibling)
+ me.hideChild(me, e, skipAnimation);
+ }
-void ModalController_hideChild(entity me, entity other, float skipAnimation)
-{
- if(other.ModalController_state || skipAnimation)
+ void ModalController_hideChild(entity me, entity other, float skipAnimation)
{
- me.setFocus(me, NULL);
- me.switchState(me, other, 0, skipAnimation);
- if(other.ModalController_controllingButton)
+ if (other.ModalController_state || skipAnimation)
{
- other.ModalController_controllingButton.forcePressed = 0;
- other.ModalController_controllingButton = NULL;
- }
- } // just alpha fade out (factor increases and decreases alpha)
-}
+ me.setFocus(me, NULL);
+ me.switchState(me, other, 0, skipAnimation);
+ if (other.ModalController_controllingButton)
+ {
+ other.ModalController_controllingButton.forcePressed = 0;
+ other.ModalController_controllingButton = NULL;
+ }
+ } // just alpha fade out (factor increases and decreases alpha)
+ }
#endif
#ifndef ITEM_NEXPOSEE_H
-#define ITEM_NEXPOSEE_H
-#include "container.qc"
-CLASS(Nexposee, Container)
- METHOD(Nexposee, draw, void(entity));
- METHOD(Nexposee, keyDown, float(entity, float, float, float));
- METHOD(Nexposee, keyUp, float(entity, float, float, float));
- METHOD(Nexposee, mousePress, float(entity, vector));
- METHOD(Nexposee, mouseMove, float(entity, vector));
- METHOD(Nexposee, mouseRelease, float(entity, vector));
- METHOD(Nexposee, mouseDrag, float(entity, vector));
- METHOD(Nexposee, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(Nexposee, focusEnter, void(entity));
- METHOD(Nexposee, close, void(entity));
-
- ATTRIB(Nexposee, animationState, float, -1)
- ATTRIB(Nexposee, animationFactor, float, 0)
- ATTRIB(Nexposee, selectedChild, entity, NULL)
- ATTRIB(Nexposee, mouseFocusedChild, entity, NULL)
- METHOD(Nexposee, addItem, void(entity, entity, vector, vector, float));
- METHOD(Nexposee, calc, void(entity));
- METHOD(Nexposee, setNexposee, void(entity, entity, vector, float, float));
- ATTRIB(Nexposee, mousePosition, vector, '0 0 0')
- METHOD(Nexposee, pullNexposee, void(entity, entity, vector));
-ENDCLASS(Nexposee)
-
-void ExposeeCloseButton_Click(entity button, entity other); // un-exposees the current state
+ #define ITEM_NEXPOSEE_H
+ #include "container.qc"
+ CLASS(Nexposee, Container)
+ METHOD(Nexposee, draw, void(entity));
+ METHOD(Nexposee, keyDown, float(entity, float, float, float));
+ METHOD(Nexposee, keyUp, float(entity, float, float, float));
+ METHOD(Nexposee, mousePress, float(entity, vector));
+ METHOD(Nexposee, mouseMove, float(entity, vector));
+ METHOD(Nexposee, mouseRelease, float(entity, vector));
+ METHOD(Nexposee, mouseDrag, float(entity, vector));
+ METHOD(Nexposee, resizeNotify, void(entity, vector, vector, vector, vector));
+ METHOD(Nexposee, focusEnter, void(entity));
+ METHOD(Nexposee, close, void(entity));
+
+ ATTRIB(Nexposee, animationState, float, -1)
+ ATTRIB(Nexposee, animationFactor, float, 0)
+ ATTRIB(Nexposee, selectedChild, entity, NULL)
+ ATTRIB(Nexposee, mouseFocusedChild, entity, NULL)
+ METHOD(Nexposee, addItem, void(entity, entity, vector, vector, float));
+ METHOD(Nexposee, calc, void(entity));
+ METHOD(Nexposee, setNexposee, void(entity, entity, vector, float, float));
+ ATTRIB(Nexposee, mousePosition, vector, '0 0 0')
+ METHOD(Nexposee, pullNexposee, void(entity, entity, vector));
+ ENDCLASS(Nexposee)
+
+ void ExposeeCloseButton_Click(entity button, entity other); // un-exposees the current state
// animation states:
// 0 = thumbnails seen
// 2 = zoomed in
// 3 = zooming out
// animation factor: 0 = minimum theSize, 1 = maximum theSize
-.vector Nexposee_initialSize;
-.vector Nexposee_initialFontScale;
-.vector Nexposee_initialOrigin;
-.float Nexposee_initialAlpha;
-
-.vector Nexposee_smallSize;
-.vector Nexposee_smallOrigin;
-.float Nexposee_smallAlpha;
-.float Nexposee_mediumAlpha;
-.vector Nexposee_scaleCenter;
-.vector Nexposee_align;
-.float Nexposee_animationFactor;
+ .vector Nexposee_initialSize;
+ .vector Nexposee_initialFontScale;
+ .vector Nexposee_initialOrigin;
+ .float Nexposee_initialAlpha;
+
+ .vector Nexposee_smallSize;
+ .vector Nexposee_smallOrigin;
+ .float Nexposee_smallAlpha;
+ .float Nexposee_mediumAlpha;
+ .vector Nexposee_scaleCenter;
+ .vector Nexposee_align;
+ .float Nexposee_animationFactor;
#endif
#ifdef IMPLEMENTATION
-void Nexposee_close(entity me)
-{
- // user must override this
-}
-
-void ExposeeCloseButton_Click(entity button, entity other)
-{
- other.selectedChild = other.focusedChild;
- other.setFocus(other, NULL);
- other.animationState = 3;
-}
-
-void Nexposee_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- me.calc(me);
- me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Nexposee_initialOrigin, Nexposee_initialSize, Nexposee_initialFontScale);
-}
-
-void Nexposee_Calc_Scale(entity me, float scale)
-{
- entity e;
- for(e = me.firstChild; e; e = e.nextSibling)
+ void Nexposee_close(entity me)
{
- e.Nexposee_smallOrigin = (e.Nexposee_initialOrigin - e.Nexposee_scaleCenter) * scale + e.Nexposee_scaleCenter;
- e.Nexposee_smallSize = e.Nexposee_initialSize * scale;
- if(e.Nexposee_align.x > 0)
- e.Nexposee_smallOrigin_x = 1 - e.Nexposee_align.x * scale;
- if(e.Nexposee_align.x < 0)
- e.Nexposee_smallOrigin_x = -e.Nexposee_smallSize.x + e.Nexposee_align.x * scale;
- if(e.Nexposee_align.y > 0)
- e.Nexposee_smallOrigin_y = 1 - e.Nexposee_align.y * scale;
- if(e.Nexposee_align.y < 0)
- e.Nexposee_smallOrigin_y = -e.Nexposee_smallSize.y + e.Nexposee_align.y * scale;
+ // user must override this
}
-}
-
-void Nexposee_calc(entity me)
-{
- /*
- * patented by Apple
- * can't put that here ;)
- */
- float scale;
- entity e, e2;
- vector emins, emaxs, e2mins, e2maxs;
-
- for(scale = 0.7;; scale *= 0.99)
+
+ void ExposeeCloseButton_Click(entity button, entity other)
{
- Nexposee_Calc_Scale(me, scale);
+ other.selectedChild = other.focusedChild;
+ other.setFocus(other, NULL);
+ other.animationState = 3;
+ }
- for(e = me.firstChild; e; e = e.nextSibling)
+ void Nexposee_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+ {
+ me.calc(me);
+ me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Nexposee_initialOrigin, Nexposee_initialSize, Nexposee_initialFontScale);
+ }
+
+ void Nexposee_Calc_Scale(entity me, float scale)
+ {
+ entity e;
+ for (e = me.firstChild; e; e = e.nextSibling)
{
- emins = e.Nexposee_smallOrigin;
- emaxs = emins + e.Nexposee_smallSize;
- for(e2 = e.nextSibling; e2; e2 = e2.nextSibling)
- {
- e2mins = e2.Nexposee_smallOrigin;
- e2maxs = e2mins + e2.Nexposee_smallSize;
-
- // two intervals [amins, amaxs] and [bmins, bmaxs] overlap if:
- // amins < bmins < amaxs < bmaxs
- // for which suffices
- // bmins < amaxs
- // amins < bmaxs
- if((e2mins.x - emaxs.x) * (emins.x - e2maxs.x) > 0) // x overlap
- if((e2mins.y - emaxs.y) * (emins.y - e2maxs.y) > 0) // y overlap
- {
- goto have_overlap;
- }
- }
+ e.Nexposee_smallOrigin = (e.Nexposee_initialOrigin - e.Nexposee_scaleCenter) * scale + e.Nexposee_scaleCenter;
+ e.Nexposee_smallSize = e.Nexposee_initialSize * scale;
+ if (e.Nexposee_align.x > 0) e.Nexposee_smallOrigin_x = 1 - e.Nexposee_align.x * scale;
+ if (e.Nexposee_align.x < 0) e.Nexposee_smallOrigin_x = -e.Nexposee_smallSize.x + e.Nexposee_align.x * scale;
+ if (e.Nexposee_align.y > 0) e.Nexposee_smallOrigin_y = 1 - e.Nexposee_align.y * scale;
+ if (e.Nexposee_align.y < 0) e.Nexposee_smallOrigin_y = -e.Nexposee_smallSize.y + e.Nexposee_align.y * scale;
}
-
- break;
-:have_overlap
}
- scale *= 0.95;
+ void Nexposee_calc(entity me)
+ {
+ /*
+ * patented by Apple
+ * can't put that here ;)
+ */
+ float scale;
+ entity e, e2;
+ vector emins, emaxs, e2mins, e2maxs;
+
+ for (scale = 0.7; ; scale *= 0.99)
+ {
+ Nexposee_Calc_Scale(me, scale);
- Nexposee_Calc_Scale(me, scale);
-}
+ for (e = me.firstChild; e; e = e.nextSibling)
+ {
+ emins = e.Nexposee_smallOrigin;
+ emaxs = emins + e.Nexposee_smallSize;
+ for (e2 = e.nextSibling; e2; e2 = e2.nextSibling)
+ {
+ e2mins = e2.Nexposee_smallOrigin;
+ e2maxs = e2mins + e2.Nexposee_smallSize;
+
+ // two intervals [amins, amaxs] and [bmins, bmaxs] overlap if:
+ // amins < bmins < amaxs < bmaxs
+ // for which suffices
+ // bmins < amaxs
+ // amins < bmaxs
+ if ((e2mins.x - emaxs.x) * (emins.x - e2maxs.x) > 0) // x overlap
+ if ((e2mins.y - emaxs.y) * (emins.y - e2maxs.y) > 0) // y overlap
+ goto have_overlap;
+ }
+ }
+
+ break;
+ : have_overlap
+ }
-void Nexposee_setNexposee(entity me, entity other, vector scalecenter, float a0, float a1)
-{
- other.Nexposee_scaleCenter = scalecenter;
- other.Nexposee_smallAlpha = a0;
- me.setAlphaOf(me, other, a0);
- other.Nexposee_mediumAlpha = a1;
-}
+ scale *= 0.95;
-void Nexposee_draw(entity me)
-{
- float a;
- float a0;
- entity e;
- float f;
- vector fs;
+ Nexposee_Calc_Scale(me, scale);
+ }
- if(me.animationState == -1)
+ void Nexposee_setNexposee(entity me, entity other, vector scalecenter, float a0, float a1)
{
- me.animationState = 0;
+ other.Nexposee_scaleCenter = scalecenter;
+ other.Nexposee_smallAlpha = a0;
+ me.setAlphaOf(me, other, a0);
+ other.Nexposee_mediumAlpha = a1;
}
- f = min(1, frametime * 5);
- switch(me.animationState)
+ void Nexposee_draw(entity me)
{
- case 0:
- me.animationFactor = 0;
- break;
- case 1:
- me.animationFactor += f;
- if(me.animationFactor >= 1)
- {
+ float a;
+ float a0;
+ entity e;
+ float f;
+ vector fs;
+
+ if (me.animationState == -1) me.animationState = 0;
+
+ f = min(1, frametime * 5);
+ switch (me.animationState)
+ {
+ case 0:
+ me.animationFactor = 0;
+ break;
+ case 1:
+ me.animationFactor += f;
+ if (me.animationFactor >= 1)
+ {
+ me.animationFactor = 1;
+ me.animationState = 2;
+ SUPER(Nexposee).setFocus(me, me.selectedChild);
+ }
+ break;
+ case 2:
me.animationFactor = 1;
- me.animationState = 2;
- SUPER(Nexposee).setFocus(me, me.selectedChild);
+ break;
+ case 3:
+ me.animationFactor -= f;
+ me.mouseFocusedChild = me.itemFromPoint(me, me.mousePosition);
+ if (me.animationFactor <= 0)
+ {
+ me.animationFactor = 0;
+ me.animationState = 0;
+ me.selectedChild = me.mouseFocusedChild;
+ }
+ break;
+ }
+
+ f = min(1, frametime * 10);
+ for (e = me.firstChild; e; e = e.nextSibling)
+ {
+ if (e == me.selectedChild)
+ {
+ e.Container_origin = e.Nexposee_smallOrigin * (1 - me.animationFactor) + e.Nexposee_initialOrigin * me.animationFactor;
+ e.Container_size = e.Nexposee_smallSize * (1 - me.animationFactor) + e.Nexposee_initialSize * me.animationFactor;
+ e.Nexposee_animationFactor = me.animationFactor;
+ a0 = e.Nexposee_mediumAlpha;
+ if (me.animationState == 3)
+ if (e != me.mouseFocusedChild) a0 = e.Nexposee_smallAlpha;
+ a = a0 * (1 - me.animationFactor) + me.animationFactor;
}
- break;
- case 2:
- me.animationFactor = 1;
- break;
- case 3:
- me.animationFactor -= f;
- me.mouseFocusedChild = me.itemFromPoint(me, me.mousePosition);
- if(me.animationFactor <= 0)
+ else
{
- me.animationFactor = 0;
- me.animationState = 0;
- me.selectedChild = me.mouseFocusedChild;
+ // minimum theSize counts
+ e.Container_origin = e.Nexposee_smallOrigin;
+ e.Container_size = e.Nexposee_smallSize;
+ e.Nexposee_animationFactor = 0;
+ a = e.Nexposee_smallAlpha * (1 - me.animationFactor);
}
- break;
+ me.setAlphaOf(me, e, e.Container_alpha * (1 - f) + a * f);
+
+ fs = globalToBoxSize(e.Container_size, e.Nexposee_initialSize);
+ e.Container_fontscale_x = fs.x * e.Nexposee_initialFontScale.x;
+ e.Container_fontscale_y = fs.y * e.Nexposee_initialFontScale.y;
+ }
+
+ SUPER(Nexposee).draw(me);
}
- f = min(1, frametime * 10);
- for(e = me.firstChild; e; e = e.nextSibling)
+ float Nexposee_mousePress(entity me, vector pos)
{
- if(e == me.selectedChild)
+ if (me.animationState == 0)
{
- e.Container_origin = e.Nexposee_smallOrigin * (1 - me.animationFactor) + e.Nexposee_initialOrigin * me.animationFactor;
- e.Container_size = e.Nexposee_smallSize * (1 - me.animationFactor) + e.Nexposee_initialSize * me.animationFactor;
- e.Nexposee_animationFactor = me.animationFactor;
- a0 = e.Nexposee_mediumAlpha;
- if(me.animationState == 3)
- if(e != me.mouseFocusedChild)
- a0 = e.Nexposee_smallAlpha;
- a = a0 * (1 - me.animationFactor) + me.animationFactor;
+ me.mouseFocusedChild = NULL;
+ Nexposee_mouseMove(me, pos);
+ if (me.mouseFocusedChild)
+ {
+ m_play_click_sound(MENU_SOUND_OPEN);
+ me.animationState = 1;
+ SUPER(Nexposee).setFocus(me, NULL);
+ }
+ else
+ {
+ me.close(me);
+ }
+ return 1;
}
- else
+ else if (me.animationState == 2)
{
- // minimum theSize counts
- e.Container_origin = e.Nexposee_smallOrigin;
- e.Container_size = e.Nexposee_smallSize;
- e.Nexposee_animationFactor = 0;
- a = e.Nexposee_smallAlpha * (1 - me.animationFactor);
+ if (!(SUPER(Nexposee).mousePress(me, pos)))
+ {
+ m_play_click_sound(MENU_SOUND_CLOSE);
+ me.animationState = 3;
+ SUPER(Nexposee).setFocus(me, NULL);
+ }
+ return 1;
}
- me.setAlphaOf(me, e, e.Container_alpha * (1 - f) + a * f);
-
- fs = globalToBoxSize(e.Container_size, e.Nexposee_initialSize);
- e.Container_fontscale_x = fs.x * e.Nexposee_initialFontScale.x;
- e.Container_fontscale_y = fs.y * e.Nexposee_initialFontScale.y;
+ return 0;
}
- SUPER(Nexposee).draw(me);
-}
+ float Nexposee_mouseRelease(entity me, vector pos)
+ {
+ if (me.animationState == 2) return SUPER(Nexposee).mouseRelease(me, pos);
+ return 0;
+ }
-float Nexposee_mousePress(entity me, vector pos)
-{
- if(me.animationState == 0)
+ float Nexposee_mouseDrag(entity me, vector pos)
{
- me.mouseFocusedChild = NULL;
- Nexposee_mouseMove(me, pos);
- if(me.mouseFocusedChild)
- {
- m_play_click_sound(MENU_SOUND_OPEN);
- me.animationState = 1;
- SUPER(Nexposee).setFocus(me, NULL);
- }
- else
- me.close(me);
- return 1;
+ if (me.animationState == 2) return SUPER(Nexposee).mouseDrag(me, pos);
+ return 0;
}
- else if(me.animationState == 2)
+
+ float Nexposee_mouseMove(entity me, vector pos)
{
- if (!(SUPER(Nexposee).mousePress(me, pos)))
+ entity e;
+ me.mousePosition = pos;
+ e = me.mouseFocusedChild;
+ me.mouseFocusedChild = me.itemFromPoint(me, pos);
+ if (me.animationState == 2) return SUPER(Nexposee).mouseMove(me, pos);
+ if (me.animationState == 0)
{
- m_play_click_sound(MENU_SOUND_CLOSE);
- me.animationState = 3;
- SUPER(Nexposee).setFocus(me, NULL);
+ if (me.mouseFocusedChild)
+ if (me.mouseFocusedChild != e || me.mouseFocusedChild != me.selectedChild) me.selectedChild = me.mouseFocusedChild;
+ return 1;
}
- return 1;
+ return 0;
}
- return 0;
-}
-
-float Nexposee_mouseRelease(entity me, vector pos)
-{
- if(me.animationState == 2)
- return SUPER(Nexposee).mouseRelease(me, pos);
- return 0;
-}
-
-float Nexposee_mouseDrag(entity me, vector pos)
-{
- if(me.animationState == 2)
- return SUPER(Nexposee).mouseDrag(me, pos);
- return 0;
-}
-
-float Nexposee_mouseMove(entity me, vector pos)
-{
- entity e;
- me.mousePosition = pos;
- e = me.mouseFocusedChild;
- me.mouseFocusedChild = me.itemFromPoint(me, pos);
- if(me.animationState == 2)
- return SUPER(Nexposee).mouseMove(me, pos);
- if(me.animationState == 0)
+
+ float Nexposee_keyUp(entity me, float scan, float ascii, float shift)
{
- if(me.mouseFocusedChild)
- if(me.mouseFocusedChild != e || me.mouseFocusedChild != me.selectedChild)
- me.selectedChild = me.mouseFocusedChild;
- return 1;
+ if (me.animationState == 2) return SUPER(Nexposee).keyUp(me, scan, ascii, shift);
+ return 0;
}
- return 0;
-}
-
-float Nexposee_keyUp(entity me, float scan, float ascii, float shift)
-{
- if(me.animationState == 2)
- return SUPER(Nexposee).keyUp(me, scan, ascii, shift);
- return 0;
-}
-
-float Nexposee_keyDown(entity me, float scan, float ascii, float shift)
-{
- float nexposeeKey = 0;
- if(me.animationState == 2)
- if(SUPER(Nexposee).keyDown(me, scan, ascii, shift))
- return 1;
- if(scan == K_TAB)
+
+ float Nexposee_keyDown(entity me, float scan, float ascii, float shift)
{
- if(me.animationState == 0)
+ float nexposeeKey = 0;
+ if (me.animationState == 2)
+ if (SUPER(Nexposee).keyDown(me, scan, ascii, shift)) return 1;
+ if (scan == K_TAB)
{
- if(shift & S_SHIFT)
- {
- if(me.selectedChild)
- me.selectedChild = me.selectedChild.prevSibling;
- if (!me.selectedChild)
- me.selectedChild = me.lastChild;
- }
- else
+ if (me.animationState == 0)
{
- if(me.selectedChild)
- me.selectedChild = me.selectedChild.nextSibling;
- if (!me.selectedChild)
- me.selectedChild = me.firstChild;
+ if (shift & S_SHIFT)
+ {
+ if (me.selectedChild) me.selectedChild = me.selectedChild.prevSibling;
+ if (!me.selectedChild) me.selectedChild = me.lastChild;
+ }
+ else
+ {
+ if (me.selectedChild) me.selectedChild = me.selectedChild.nextSibling;
+ if (!me.selectedChild) me.selectedChild = me.firstChild;
+ }
}
}
- }
- switch(me.animationState)
- {
- default:
- case 0:
- case 3:
- nexposeeKey = ((scan == K_SPACE) || (scan == K_ENTER) || (scan == K_KP_ENTER));
- break;
- case 1:
- case 2:
- nexposeeKey = (scan == K_ESCAPE);
- break;
- }
- if(nexposeeKey)
- {
- switch(me.animationState)
+ switch (me.animationState)
{
default:
case 0:
case 3:
- m_play_click_sound(MENU_SOUND_OPEN);
- me.animationState = 1;
+ nexposeeKey = ((scan == K_SPACE) || (scan == K_ENTER) || (scan == K_KP_ENTER));
break;
case 1:
case 2:
- m_play_click_sound(MENU_SOUND_CLOSE);
- me.animationState = 3;
+ nexposeeKey = (scan == K_ESCAPE);
break;
}
- if(me.focusedChild)
- me.selectedChild = me.focusedChild;
- if (!me.selectedChild)
- me.animationState = 0;
- SUPER(Nexposee).setFocus(me, NULL);
- return 1;
+ if (nexposeeKey)
+ {
+ switch (me.animationState)
+ {
+ default:
+ case 0:
+ case 3:
+ m_play_click_sound(MENU_SOUND_OPEN);
+ me.animationState = 1;
+ break;
+ case 1:
+ case 2:
+ m_play_click_sound(MENU_SOUND_CLOSE);
+ me.animationState = 3;
+ break;
+ }
+ if (me.focusedChild) me.selectedChild = me.focusedChild;
+ if (!me.selectedChild) me.animationState = 0;
+ SUPER(Nexposee).setFocus(me, NULL);
+ return 1;
+ }
+ return 0;
+ }
+
+ void Nexposee_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
+ {
+ SUPER(Nexposee).addItem(me, other, theOrigin, theSize, theAlpha);
+ other.Nexposee_initialFontScale = other.Container_fontscale;
+ other.Nexposee_initialSize = other.Container_size;
+ other.Nexposee_initialOrigin = other.Container_origin;
+ other.Nexposee_initialAlpha = other.Container_alpha;
+ if (other.Nexposee_initialFontScale == '0 0 0') other.Nexposee_initialFontScale = '1 1 0';
+ }
+
+ void Nexposee_focusEnter(entity me)
+ {
+ if (me.animationState == 2) SUPER(Nexposee).setFocus(me, me.selectedChild);
+ }
+
+ void Nexposee_pullNexposee(entity me, entity other, vector theAlign)
+ {
+ other.Nexposee_align = theAlign;
}
- return 0;
-}
-
-void Nexposee_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
-{
- SUPER(Nexposee).addItem(me, other, theOrigin, theSize, theAlpha);
- other.Nexposee_initialFontScale = other.Container_fontscale;
- other.Nexposee_initialSize = other.Container_size;
- other.Nexposee_initialOrigin = other.Container_origin;
- other.Nexposee_initialAlpha = other.Container_alpha;
- if(other.Nexposee_initialFontScale == '0 0 0')
- other.Nexposee_initialFontScale = '1 1 0';
-}
-
-void Nexposee_focusEnter(entity me)
-{
- if(me.animationState == 2)
- SUPER(Nexposee).setFocus(me, me.selectedChild);
-}
-
-void Nexposee_pullNexposee(entity me, entity other, vector theAlign)
-{
- other.Nexposee_align = theAlign;
-}
#endif
#ifndef ITEM_RADIOBUTTON_H
-#define ITEM_RADIOBUTTON_H
-#include "checkbox.qc"
-void RadioButton_Click(entity me, entity other);
-CLASS(RadioButton, CheckBox)
- METHOD(RadioButton, configureRadioButton, void(entity, string, float, string, float, float));
- ATTRIB(RadioButton, checked, float, 0)
- ATTRIB(RadioButton, group, float, 0)
- ATTRIB(RadioButton, allowDeselect, float, 0)
- ATTRIB(RadioButton, onClick, void(entity, entity), RadioButton_Click)
-ENDCLASS(RadioButton)
+ #define ITEM_RADIOBUTTON_H
+ #include "checkbox.qc"
+ void RadioButton_Click(entity me, entity other);
+ CLASS(RadioButton, CheckBox)
+ METHOD(RadioButton, configureRadioButton, void(entity, string, float, string, float, float));
+ ATTRIB(RadioButton, checked, float, 0)
+ ATTRIB(RadioButton, group, float, 0)
+ ATTRIB(RadioButton, allowDeselect, float, 0)
+ ATTRIB(RadioButton, onClick, void(entity, entity), RadioButton_Click)
+ ENDCLASS(RadioButton)
#endif
#ifdef IMPLEMENTATION
-void RadioButton_configureRadioButton(entity me, string txt, float sz, string gfx, float theGroup, float doAllowDeselect)
-{
- me.configureCheckBox(me, txt, sz, gfx);
- me.align = 0;
- me.group = theGroup;
- me.allowDeselect = doAllowDeselect;
-}
-void RadioButton_Click(entity me, entity other)
-{
- if(me.checked)
+ void RadioButton_configureRadioButton(entity me, string txt, float sz, string gfx, float theGroup, float doAllowDeselect)
{
- if(me.allowDeselect)
- me.setChecked(me, 0);
+ me.configureCheckBox(me, txt, sz, gfx);
+ me.align = 0;
+ me.group = theGroup;
+ me.allowDeselect = doAllowDeselect;
}
- else
+ void RadioButton_Click(entity me, entity other)
{
- entity e;
- for(e = me.parent.firstChild; e; e = e.nextSibling)
- if(e != me)
- if(e.group == me.group)
- e.setChecked(e, 0);
- me.setChecked(me, 1);
+ if (me.checked)
+ {
+ if (me.allowDeselect) me.setChecked(me, 0);
+ }
+ else
+ {
+ entity e;
+ for (e = me.parent.firstChild; e; e = e.nextSibling)
+ if (e != me)
+ if (e.group == me.group) e.setChecked(e, 0);
+ me.setChecked(me, 1);
+ }
}
-}
#endif
// Note:
// to use this, you FIRST call configureSliderVisuals, then configureSliderValues
#ifndef ITEM_SLIDER_H
-#define ITEM_SLIDER_H
-#include "label.qc"
-CLASS(Slider, Label)
- METHOD(Slider, resizeNotify, void(entity, vector, vector, vector, vector));
- METHOD(Slider, configureSliderVisuals, void(entity, float, float, float, string));
- METHOD(Slider, configureSliderValues, void(entity, float, float, float, float, float, float));
- METHOD(Slider, draw, void(entity));
- METHOD(Slider, keyDown, float(entity, float, float, float));
- METHOD(Slider, keyUp, float(entity, float, float, float));
- METHOD(Slider, mousePress, float(entity, vector));
- METHOD(Slider, mouseDrag, float(entity, vector));
- METHOD(Slider, mouseRelease, float(entity, vector));
- METHOD(Slider, valueToText, string(entity, float));
- METHOD(Slider, toString, string(entity));
- METHOD(Slider, setValue_allowAnim, void(entity, float, bool));
- METHOD(Slider, setValue_noAnim, void(entity, float));
- METHOD(Slider, setValue, void(entity, float));
- METHOD(Slider, setSliderValue, void(entity, float));
- METHOD(Slider, showNotify, void(entity));
- ATTRIB(Slider, src, string, string_null)
- ATTRIB(Slider, focusable, float, 1)
- ATTRIB(Slider, allowFocusSound, float, 1)
- ATTRIB(Slider, value, float, 0)
- ATTRIB(Slider, animated, float, 1)
- ATTRIB(Slider, sliderValue, float, 0)
- ATTRIB(Slider, sliderAnim, entity, NULL)
- ATTRIB(Slider, valueMin, float, 0)
- ATTRIB(Slider, valueMax, float, 0)
- ATTRIB(Slider, valueStep, float, 0)
- ATTRIB(Slider, valueDigits, float, 0)
- ATTRIB(Slider, valueKeyStep, float, 0)
- ATTRIB(Slider, valuePageStep, float, 0)
- ATTRIB(Slider, valueDisplayMultiplier, float, 1.0)
- ATTRIB(Slider, textSpace, float, 0)
- ATTRIB(Slider, controlWidth, float, 0)
- ATTRIB(Slider, pressed, float, 0)
- ATTRIB(Slider, pressOffset, float, 0)
- ATTRIB(Slider, previousValue, float, 0)
- ATTRIB(Slider, tolerance, vector, '0 0 0')
- ATTRIB(Slider, disabled, float, 0)
- ATTRIB(Slider, color, vector, '1 1 1')
- ATTRIB(Slider, color2, vector, '1 1 1')
- ATTRIB(Slider, colorD, vector, '1 1 1')
- ATTRIB(Slider, colorC, vector, '1 1 1')
- ATTRIB(Slider, colorF, vector, '1 1 1')
- ATTRIB(Slider, disabledAlpha, float, 0.3)
-ENDCLASS(Slider)
+ #define ITEM_SLIDER_H
+ #include "label.qc"
+ CLASS(Slider, Label)
+ METHOD(Slider, resizeNotify, void(entity, vector, vector, vector, vector));
+ METHOD(Slider, configureSliderVisuals, void(entity, float, float, float, string));
+ METHOD(Slider, configureSliderValues, void(entity, float, float, float, float, float, float));
+ METHOD(Slider, draw, void(entity));
+ METHOD(Slider, keyDown, float(entity, float, float, float));
+ METHOD(Slider, keyUp, float(entity, float, float, float));
+ METHOD(Slider, mousePress, float(entity, vector));
+ METHOD(Slider, mouseDrag, float(entity, vector));
+ METHOD(Slider, mouseRelease, float(entity, vector));
+ METHOD(Slider, valueToText, string(entity, float));
+ METHOD(Slider, toString, string(entity));
+ METHOD(Slider, setValue_allowAnim, void(entity, float, bool));
+ METHOD(Slider, setValue_noAnim, void(entity, float));
+ METHOD(Slider, setValue, void(entity, float));
+ METHOD(Slider, setSliderValue, void(entity, float));
+ METHOD(Slider, showNotify, void(entity));
+ ATTRIB(Slider, src, string, string_null)
+ ATTRIB(Slider, focusable, float, 1)
+ ATTRIB(Slider, allowFocusSound, float, 1)
+ ATTRIB(Slider, value, float, 0)
+ ATTRIB(Slider, animated, float, 1)
+ ATTRIB(Slider, sliderValue, float, 0)
+ ATTRIB(Slider, sliderAnim, entity, NULL)
+ ATTRIB(Slider, valueMin, float, 0)
+ ATTRIB(Slider, valueMax, float, 0)
+ ATTRIB(Slider, valueStep, float, 0)
+ ATTRIB(Slider, valueDigits, float, 0)
+ ATTRIB(Slider, valueKeyStep, float, 0)
+ ATTRIB(Slider, valuePageStep, float, 0)
+ ATTRIB(Slider, valueDisplayMultiplier, float, 1.0)
+ ATTRIB(Slider, textSpace, float, 0)
+ ATTRIB(Slider, controlWidth, float, 0)
+ ATTRIB(Slider, pressed, float, 0)
+ ATTRIB(Slider, pressOffset, float, 0)
+ ATTRIB(Slider, previousValue, float, 0)
+ ATTRIB(Slider, tolerance, vector, '0 0 0')
+ ATTRIB(Slider, disabled, float, 0)
+ ATTRIB(Slider, color, vector, '1 1 1')
+ ATTRIB(Slider, color2, vector, '1 1 1')
+ ATTRIB(Slider, colorD, vector, '1 1 1')
+ ATTRIB(Slider, colorC, vector, '1 1 1')
+ ATTRIB(Slider, colorF, vector, '1 1 1')
+ ATTRIB(Slider, disabledAlpha, float, 0.3)
+ ENDCLASS(Slider)
#endif
#ifdef IMPLEMENTATION
-void Slider_setValue_allowAnim(entity me, float val, bool allowAnim)
-{
- if(allowAnim && me.animated) {
- float t = 0.5;
- if(!me.sliderAnim)
- me.sliderAnim = makeHostedEasing(me, Slider_setSliderValue, easingQuadOut, t, me.sliderValue, val);
+ void Slider_setValue_allowAnim(entity me, float val, bool allowAnim)
+ {
+ if (allowAnim && me.animated)
+ {
+ float t = 0.5;
+ if (!me.sliderAnim) me.sliderAnim = makeHostedEasing(me, Slider_setSliderValue, easingQuadOut, t, me.sliderValue, val);
+ else me.sliderAnim.update(me.sliderAnim, t, me.sliderValue, val);
+ }
else
- me.sliderAnim.update(me.sliderAnim, t, me.sliderValue, val);
- } else {
- me.setSliderValue(me, val);
+ {
+ me.setSliderValue(me, val);
+ }
+ me.value = val;
}
- me.value = val;
-}
-void Slider_setValue_noAnim(entity me, float val)
-{
- Slider_setValue_allowAnim(me, val, false);
-}
-void Slider_setValue(entity me, float val)
-{
- Slider_setValue_allowAnim(me, val, true);
-}
-void Slider_setSliderValue(entity me, float val)
-{
- me.sliderValue = val;
-}
-string Slider_toString(entity me)
-{
- return sprintf("%d (%s)", me.value, me.valueToText(me, me.value));
-}
-void Slider_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
- SUPER(Slider).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
- me.controlWidth = absSize.x == 0 ? 0 : (absSize.y / absSize.x);
-}
-string Slider_valueToText(entity me, float val)
-{
- if(almost_in_bounds(me.valueMin, val, me.valueMax))
- return ftos_decimals(val * me.valueDisplayMultiplier, me.valueDigits);
- return "";
-}
-void Slider_configureSliderVisuals(entity me, float sz, float theAlign, float theTextSpace, string gfx)
-{
- SUPER(Slider).configureLabel(me, string_null, sz, theAlign);
- me.textSpace = theTextSpace;
- me.keepspaceLeft = (theTextSpace == 0) ? 0 : (1 - theTextSpace);
- me.src = gfx;
-}
-void Slider_configureSliderValues(entity me, float theValueMin, float theValue, float theValueMax, float theValueStep, float theValueKeyStep, float theValuePageStep)
-{
- me.value = theValue;
- me.sliderValue = theValue;
- me.valueStep = theValueStep;
- me.valueMin = theValueMin;
- me.valueMax = theValueMax;
- me.valueKeyStep = theValueKeyStep;
- me.valuePageStep = theValuePageStep;
- me.valueDigits = 3;
- if(fabs(floor(me.valueStep * 100 + 0.5) - (me.valueStep * 100)) < 0.01) // about a whole number of 100ths
- me.valueDigits = 2;
- if(fabs(floor(me.valueStep * 10 + 0.5) - (me.valueStep * 10)) < 0.01) // about a whole number of 10ths
- me.valueDigits = 1;
- if(fabs(floor(me.valueStep * 1 + 0.5) - (me.valueStep * 1)) < 0.01) // about a whole number
- me.valueDigits = 0;
-}
-float Slider_keyDown(entity me, float key, float ascii, float shift)
-{
- float inRange;
- if(me.disabled)
- return 0;
- inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
- if(key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELDOWN)
+ void Slider_setValue_noAnim(entity me, float val)
{
- if(inRange)
- me.setValue(me, median(me.valueMin, me.value - me.valueKeyStep, me.valueMax));
- else
- me.setValue(me, me.valueMax);
- return 1;
+ Slider_setValue_allowAnim(me, val, false);
}
- if(key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MWHEELUP)
+ void Slider_setValue(entity me, float val)
{
- if(inRange)
- me.setValue(me, median(me.valueMin, me.value + me.valueKeyStep, me.valueMax));
- else
- me.setValue(me, me.valueMin);
- return 1;
+ Slider_setValue_allowAnim(me, val, true);
}
- if(key == K_PGDN || key == K_KP_PGDN)
+ void Slider_setSliderValue(entity me, float val)
{
- if(inRange)
- me.setValue(me, median(me.valueMin, me.value - me.valuePageStep, me.valueMax));
- else
- me.setValue(me, me.valueMax);
- return 1;
+ me.sliderValue = val;
}
- if(key == K_PGUP || key == K_KP_PGUP)
+ string Slider_toString(entity me)
{
- if(inRange)
- me.setValue(me, median(me.valueMin, me.value + me.valuePageStep, me.valueMax));
- else
- me.setValue(me, me.valueMin);
- return 1;
+ return sprintf("%d (%s)", me.value, me.valueToText(me, me.value));
}
- if(key == K_HOME || key == K_KP_HOME)
+ void Slider_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
{
- me.setValue(me, me.valueMin);
- return 1;
+ SUPER(Slider).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+ me.controlWidth = absSize.x == 0 ? 0 : (absSize.y / absSize.x);
}
- if(key == K_END || key == K_KP_END)
+ string Slider_valueToText(entity me, float val)
{
- me.setValue(me, me.valueMax);
- return 1;
+ if (almost_in_bounds(me.valueMin, val, me.valueMax)) return ftos_decimals(val * me.valueDisplayMultiplier, me.valueDigits);
+ return "";
}
- // TODO more keys (NOTE also add them to Slider_keyUp)
- return 0;
-}
-float Slider_keyUp(entity me, float key, float ascii, float shift)
-{
- if(me.disabled)
- return 0;
- switch(key)
+ void Slider_configureSliderVisuals(entity me, float sz, float theAlign, float theTextSpace, string gfx)
{
- case K_LEFTARROW:
- case K_KP_LEFTARROW:
- case K_RIGHTARROW:
- case K_KP_RIGHTARROW:
- case K_PGUP:
- case K_KP_PGUP:
- case K_PGDN:
- case K_KP_PGDN:
- case K_HOME:
- case K_KP_HOME:
- case K_END:
- case K_KP_END:
- m_play_click_sound(MENU_SOUND_SLIDE);
+ SUPER(Slider).configureLabel(me, string_null, sz, theAlign);
+ me.textSpace = theTextSpace;
+ me.keepspaceLeft = (theTextSpace == 0) ? 0 : (1 - theTextSpace);
+ me.src = gfx;
}
- return 0;
-}
-float Slider_mouseDrag(entity me, vector pos)
-{
- float hit;
- float v;
- if(me.disabled)
- return 0;
-
- if(me.pressed)
+ void Slider_configureSliderValues(entity me, float theValueMin, float theValue, float theValueMax, float theValueStep, float theValueKeyStep, float theValuePageStep)
{
- hit = 1;
- if(pos.x < 0 - me.tolerance.x) hit = 0;
- if(pos.y < 0 - me.tolerance.y) hit = 0;
- if(pos.x >= 1 - me.textSpace + me.tolerance.x) hit = 0;
- if(pos.y >= 1 + me.tolerance.y) hit = 0;
- if(hit)
+ me.value = theValue;
+ me.sliderValue = theValue;
+ me.valueStep = theValueStep;
+ me.valueMin = theValueMin;
+ me.valueMax = theValueMax;
+ me.valueKeyStep = theValueKeyStep;
+ me.valuePageStep = theValuePageStep;
+ me.valueDigits = 3;
+ if (fabs(floor(me.valueStep * 100 + 0.5) - (me.valueStep * 100)) < 0.01) // about a whole number of 100ths
+ me.valueDigits = 2;
+ if (fabs(floor(me.valueStep * 10 + 0.5) - (me.valueStep * 10)) < 0.01) // about a whole number of 10ths
+ me.valueDigits = 1;
+ if (fabs(floor(me.valueStep * 1 + 0.5) - (me.valueStep * 1)) < 0.01) // about a whole number
+ me.valueDigits = 0;
+ }
+ float Slider_keyDown(entity me, float key, float ascii, float shift)
+ {
+ float inRange;
+ if (me.disabled) return 0;
+ inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
+ if (key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELDOWN)
{
- // handle dragging
- me.pressed = 2;
-
- v = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
- if(me.valueStep)
- v = floor(0.5 + v / me.valueStep) * me.valueStep;
- me.setValue_noAnim(me, v);
+ if (inRange) me.setValue(me, median(me.valueMin, me.value - me.valueKeyStep, me.valueMax));
+ else me.setValue(me, me.valueMax);
+ return 1;
}
- else
- me.setValue(me, me.previousValue);
- }
-
- return 1;
-}
-float Slider_mousePress(entity me, vector pos)
-{
- float controlCenter;
- if(me.disabled)
+ if (key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MWHEELUP)
+ {
+ if (inRange) me.setValue(me, median(me.valueMin, me.value + me.valueKeyStep, me.valueMax));
+ else me.setValue(me, me.valueMin);
+ return 1;
+ }
+ if (key == K_PGDN || key == K_KP_PGDN)
+ {
+ if (inRange) me.setValue(me, median(me.valueMin, me.value - me.valuePageStep, me.valueMax));
+ else me.setValue(me, me.valueMax);
+ return 1;
+ }
+ if (key == K_PGUP || key == K_KP_PGUP)
+ {
+ if (inRange) me.setValue(me, median(me.valueMin, me.value + me.valuePageStep, me.valueMax));
+ else me.setValue(me, me.valueMin);
+ return 1;
+ }
+ if (key == K_HOME || key == K_KP_HOME)
+ {
+ me.setValue(me, me.valueMin);
+ return 1;
+ }
+ if (key == K_END || key == K_KP_END)
+ {
+ me.setValue(me, me.valueMax);
+ return 1;
+ }
+ // TODO more keys (NOTE also add them to Slider_keyUp)
return 0;
- if(pos.x < 0) return 0;
- if(pos.y < 0) return 0;
- if(pos.x >= 1 - me.textSpace) return 0;
- if(pos.y >= 1) return 0;
- controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
- if(fabs(pos.x - controlCenter) <= 0.5 * me.controlWidth)
- {
- me.pressed = 1;
- me.pressOffset = pos.x - controlCenter;
- me.previousValue = me.value;
- //me.mouseDrag(me, pos);
}
- else
+ float Slider_keyUp(entity me, float key, float ascii, float shift)
{
- float clickValue, pageValue, inRange;
- clickValue = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
- inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
- if(pos.x < controlCenter)
+ if (me.disabled) return 0;
+ switch (key)
{
- pageValue = me.value - me.valuePageStep;
- if(me.valueStep)
- clickValue = floor(clickValue / me.valueStep) * me.valueStep;
- pageValue = max(pageValue, clickValue);
- if(inRange)
- me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
- else
- me.setValue(me, me.valueMax);
+ case K_LEFTARROW:
+ case K_KP_LEFTARROW:
+ case K_RIGHTARROW:
+ case K_KP_RIGHTARROW:
+ case K_PGUP:
+ case K_KP_PGUP:
+ case K_PGDN:
+ case K_KP_PGDN:
+ case K_HOME:
+ case K_KP_HOME:
+ case K_END:
+ case K_KP_END:
+ m_play_click_sound(MENU_SOUND_SLIDE);
}
- else
+ return 0;
+ }
+ float Slider_mouseDrag(entity me, vector pos)
+ {
+ float hit;
+ float v;
+ if (me.disabled) return 0;
+
+ if (me.pressed)
{
- pageValue = me.value + me.valuePageStep;
- if(me.valueStep)
- clickValue = ceil(clickValue / me.valueStep) * me.valueStep;
- pageValue = min(pageValue, clickValue);
- if(inRange)
- me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
+ hit = 1;
+ if (pos.x < 0 - me.tolerance.x) hit = 0;
+ if (pos.y < 0 - me.tolerance.y) hit = 0;
+ if (pos.x >= 1 - me.textSpace + me.tolerance.x) hit = 0;
+ if (pos.y >= 1 + me.tolerance.y) hit = 0;
+ if (hit)
+ {
+ // handle dragging
+ me.pressed = 2;
+
+ v = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
+ if (me.valueStep) v = floor(0.5 + v / me.valueStep) * me.valueStep;
+ me.setValue_noAnim(me, v);
+ }
else
- me.setValue(me, me.valueMax);
+ {
+ me.setValue(me, me.previousValue);
+ }
}
- if(pageValue == clickValue)
+
+ return 1;
+ }
+ float Slider_mousePress(entity me, vector pos)
+ {
+ float controlCenter;
+ if (me.disabled) return 0;
+ if (pos.x < 0) return 0;
+ if (pos.y < 0) return 0;
+ if (pos.x >= 1 - me.textSpace) return 0;
+ if (pos.y >= 1) return 0;
+ controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
+ if (fabs(pos.x - controlCenter) <= 0.5 * me.controlWidth)
{
- controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
me.pressed = 1;
me.pressOffset = pos.x - controlCenter;
me.previousValue = me.value;
- //me.mouseDrag(me, pos);
+ // me.mouseDrag(me, pos);
}
+ else
+ {
+ float clickValue, pageValue, inRange;
+ clickValue = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
+ inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
+ if (pos.x < controlCenter)
+ {
+ pageValue = me.value - me.valuePageStep;
+ if (me.valueStep) clickValue = floor(clickValue / me.valueStep) * me.valueStep;
+ pageValue = max(pageValue, clickValue);
+ if (inRange) me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
+ else me.setValue(me, me.valueMax);
+ }
+ else
+ {
+ pageValue = me.value + me.valuePageStep;
+ if (me.valueStep) clickValue = ceil(clickValue / me.valueStep) * me.valueStep;
+ pageValue = min(pageValue, clickValue);
+ if (inRange) me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
+ else me.setValue(me, me.valueMax);
+ }
+ if (pageValue == clickValue)
+ {
+ controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
+ me.pressed = 1;
+ me.pressOffset = pos.x - controlCenter;
+ me.previousValue = me.value;
+ // me.mouseDrag(me, pos);
+ }
+ }
+ return 1;
}
- return 1;
-}
-float Slider_mouseRelease(entity me, vector pos)
-{
- me.pressed = 0;
- if(me.disabled)
- return 0;
- m_play_click_sound(MENU_SOUND_SLIDE);
- return 1;
-}
-void Slider_showNotify(entity me)
-{
- me.focusable = !me.disabled;
-}
-void Slider_draw(entity me)
-{
- float controlLeft;
- float save;
- me.focusable = !me.disabled;
- save = draw_alpha;
- if(me.disabled)
- draw_alpha *= me.disabledAlpha;
- draw_ButtonPicture('0 0 0', strcat(me.src, "_s"), eX * (1 - me.textSpace) + eY, me.color2, 1);
- if(almost_in_bounds(me.valueMin, me.sliderValue, me.valueMax))
+ float Slider_mouseRelease(entity me, vector pos)
{
- controlLeft = (me.sliderValue - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth);
- if(me.disabled)
- draw_Picture(eX * controlLeft, strcat(me.src, "_d"), eX * me.controlWidth + eY, me.colorD, 1);
- else if(me.pressed)
- draw_Picture(eX * controlLeft, strcat(me.src, "_c"), eX * me.controlWidth + eY, me.colorC, 1);
- else if(me.focused)
- draw_Picture(eX * controlLeft, strcat(me.src, "_f"), eX * me.controlWidth + eY, me.colorF, 1);
- else
- draw_Picture(eX * controlLeft, strcat(me.src, "_n"), eX * me.controlWidth + eY, me.color, 1);
+ me.pressed = 0;
+ if (me.disabled) return 0;
+ m_play_click_sound(MENU_SOUND_SLIDE);
+ return 1;
}
-
- if(me.sliderAnim)
- if(me.sliderAnim.isFinished(me.sliderAnim))
+ void Slider_showNotify(entity me)
{
- anim.removeObjAnim(anim, me);
- me.sliderAnim = NULL;
+ me.focusable = !me.disabled;
}
+ void Slider_draw(entity me)
+ {
+ float controlLeft;
+ float save;
+ me.focusable = !me.disabled;
+ save = draw_alpha;
+ if (me.disabled) draw_alpha *= me.disabledAlpha;
+ draw_ButtonPicture('0 0 0', strcat(me.src, "_s"), eX * (1 - me.textSpace) + eY, me.color2, 1);
+ if (almost_in_bounds(me.valueMin, me.sliderValue, me.valueMax))
+ {
+ controlLeft = (me.sliderValue - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth);
+ if (me.disabled) draw_Picture(eX * controlLeft, strcat(me.src, "_d"), eX * me.controlWidth + eY, me.colorD, 1);
+ else if (me.pressed) draw_Picture(eX * controlLeft, strcat(me.src, "_c"), eX * me.controlWidth + eY, me.colorC, 1);
+ else if (me.focused) draw_Picture(eX * controlLeft, strcat(me.src, "_f"), eX * me.controlWidth + eY, me.colorF, 1);
+ else draw_Picture(eX * controlLeft, strcat(me.src, "_n"), eX * me.controlWidth + eY, me.color, 1);
+ }
- me.setText(me, me.valueToText(me, me.value));
- draw_alpha = save;
- SUPER(Slider).draw(me);
- me.text = string_null; // TEMPSTRING!
-}
+ if (me.sliderAnim)
+ if (me.sliderAnim.isFinished(me.sliderAnim))
+ {
+ anim.removeObjAnim(anim, me);
+ me.sliderAnim = NULL;
+ }
+
+ me.setText(me, me.valueToText(me, me.value));
+ draw_alpha = save;
+ SUPER(Slider).draw(me);
+ me.text = string_null; // TEMPSTRING!
+ }
#endif
#ifndef ITEM_TAB_H
-#define ITEM_TAB_H
-#include "dialog.qc"
-CLASS(Tab, Dialog)
- ATTRIB(Tab, isTabRoot, float, 0)
- ATTRIB(Tab, closable, float, 0)
- ATTRIB(Tab, rootDialog, float, 0)
- ATTRIB(Tab, title, string, string_null)
- ATTRIB(Tab, titleFontSize, float, 0) // pixels
+ #define ITEM_TAB_H
+ #include "dialog.qc"
+ CLASS(Tab, Dialog)
+ ATTRIB(Tab, isTabRoot, float, 0)
+ ATTRIB(Tab, closable, float, 0)
+ ATTRIB(Tab, rootDialog, float, 0)
+ ATTRIB(Tab, title, string, string_null)
+ ATTRIB(Tab, titleFontSize, float, 0) // pixels
- // still to be customized
- ATTRIB(Tab, intendedWidth, float, 0)
- ATTRIB(Tab, rows, float, 3)
- ATTRIB(Tab, columns, float, 2)
+ // still to be customized
+ ATTRIB(Tab, intendedWidth, float, 0)
+ ATTRIB(Tab, rows, float, 3)
+ ATTRIB(Tab, columns, float, 2)
- ATTRIB(Tab, marginTop, float, 0) // pixels
- ATTRIB(Tab, marginBottom, float, 0) // pixels
- ATTRIB(Tab, marginLeft, float, 0) // pixels
- ATTRIB(Tab, marginRight, float, 0) // pixels
- ATTRIB(Tab, columnSpacing, float, 0) // pixels
- ATTRIB(Tab, rowSpacing, float, 0) // pixels
- ATTRIB(Tab, rowHeight, float, 0) // pixels
- ATTRIB(Tab, titleHeight, float, 0) // pixels
+ ATTRIB(Tab, marginTop, float, 0) // pixels
+ ATTRIB(Tab, marginBottom, float, 0) // pixels
+ ATTRIB(Tab, marginLeft, float, 0) // pixels
+ ATTRIB(Tab, marginRight, float, 0) // pixels
+ ATTRIB(Tab, columnSpacing, float, 0) // pixels
+ ATTRIB(Tab, rowSpacing, float, 0) // pixels
+ ATTRIB(Tab, rowHeight, float, 0) // pixels
+ ATTRIB(Tab, titleHeight, float, 0) // pixels
- ATTRIB(Tab, backgroundImage, string, string_null)
-ENDCLASS(Tab)
+ ATTRIB(Tab, backgroundImage, string, string_null)
+ ENDCLASS(Tab)
#endif
#ifdef IMPLEMENTATION
// Note:
// to use this, you FIRST call configureSliderVisuals, then multiple times addValue, then configureTextSlider
#ifndef ITEM_TEXTSLIDER_H
-#define ITEM_TEXTSLIDER_H
-#include "slider.qc"
-CLASS(TextSlider, Slider)
- METHOD(TextSlider, valueToText, string(entity, float));
- METHOD(TextSlider, valueToIdentifier, string(entity, float));
- METHOD(TextSlider, setValueFromIdentifier_allowAnim, void(entity, string, bool));
- METHOD(TextSlider, setValueFromIdentifier_noAnim, void(entity, string));
- METHOD(TextSlider, setValueFromIdentifier, void(entity, string));
- METHOD(TextSlider, getIdentifier, string(entity));
- METHOD(TextSlider, clearValues, void(entity));
- METHOD(TextSlider, addValue, void(entity, string, string));
- METHOD(TextSlider, insertValue, void(entity, float, string, string));
- METHOD(TextSlider, configureTextSliderValues, void(entity, string));
- ATTRIBARRAY(TextSlider, valueStrings, string, 256)
- ATTRIBARRAY(TextSlider, valueIdentifiers, string, 256)
- ATTRIB(TextSlider, nValues, int, 0)
-ENDCLASS(TextSlider)
+ #define ITEM_TEXTSLIDER_H
+ #include "slider.qc"
+ CLASS(TextSlider, Slider)
+ METHOD(TextSlider, valueToText, string(entity, float));
+ METHOD(TextSlider, valueToIdentifier, string(entity, float));
+ METHOD(TextSlider, setValueFromIdentifier_allowAnim, void(entity, string, bool));
+ METHOD(TextSlider, setValueFromIdentifier_noAnim, void(entity, string));
+ METHOD(TextSlider, setValueFromIdentifier, void(entity, string));
+ METHOD(TextSlider, getIdentifier, string(entity));
+ METHOD(TextSlider, clearValues, void(entity));
+ METHOD(TextSlider, addValue, void(entity, string, string));
+ METHOD(TextSlider, insertValue, void(entity, float, string, string));
+ METHOD(TextSlider, configureTextSliderValues, void(entity, string));
+ ATTRIBARRAY(TextSlider, valueStrings, string, 256)
+ ATTRIBARRAY(TextSlider, valueIdentifiers, string, 256)
+ ATTRIB(TextSlider, nValues, int, 0)
+ ENDCLASS(TextSlider)
#endif
#ifdef IMPLEMENTATION
-string TextSlider_valueToIdentifier(entity me, int val)
-{
- if(val >= me.nValues)
- return "custom";
- if(val < 0)
- return "custom";
- return me.(valueIdentifiers[val]);
-}
-string TextSlider_valueToText(entity me, int val)
-{
- if(val >= me.nValues)
- return _("Custom");
- if(val < 0)
- return _("Custom");
- return me.(valueStrings[val]);
-}
-void TextSlider_setValueFromIdentifier_allowAnim(entity me, string id, bool allowAnim)
-{
- int i;
- for(i = 0; i < me.nValues; ++i)
- if(me.valueToIdentifier(me, i) == id)
+ string TextSlider_valueToIdentifier(entity me, int val)
+ {
+ if (val >= me.nValues) return "custom";
+ if (val < 0) return "custom";
+ return me.(valueIdentifiers[val]);
+ }
+ string TextSlider_valueToText(entity me, int val)
+ {
+ if (val >= me.nValues) return _("Custom");
+ if (val < 0) return _("Custom");
+ return me.(valueStrings[val]);
+ }
+ void TextSlider_setValueFromIdentifier_allowAnim(entity me, string id, bool allowAnim)
+ {
+ int i;
+ for (i = 0; i < me.nValues; ++i)
+ if (me.valueToIdentifier(me, i) == id)
+ {
+ SUPER(TextSlider).setValue_allowAnim(me, i, allowAnim);
+ return;
+ }
+ SUPER(TextSlider).setValue_allowAnim(me, -1, allowAnim);
+ }
+ void TextSlider_setValueFromIdentifier_noAnim(entity me, string id)
+ {
+ TextSlider_setValueFromIdentifier_allowAnim(me, id, false);
+ }
+ void TextSlider_setValueFromIdentifier(entity me, string id)
+ {
+ TextSlider_setValueFromIdentifier_allowAnim(me, id, true);
+ }
+ string TextSlider_getIdentifier(entity me)
+ {
+ return me.valueToIdentifier(me, me.value);
+ }
+ void TextSlider_clearValues(entity me)
+ {
+ me.nValues = 0;
+ }
+ void TextSlider_addValue(entity me, string theString, string theIdentifier)
+ {
+ me.(valueStrings[me.nValues]) = theString;
+ me.(valueIdentifiers[me.nValues]) = theIdentifier;
+ me.nValues += 1;
+ }
+ void TextSlider_insertValue(entity me, int pos, string theString, string theIdentifier)
+ {
+ int i;
+ for (i = me.nValues; i > pos; --i)
{
- SUPER(TextSlider).setValue_allowAnim(me, i, allowAnim);
- return;
+ me.(valueStrings[i]) = me.(valueStrings[i - 1]);
+ me.(valueIdentifiers[i]) = me.(valueIdentifiers[i - 1]);
}
- SUPER(TextSlider).setValue_allowAnim(me, -1, allowAnim);
-}
-void TextSlider_setValueFromIdentifier_noAnim(entity me, string id)
-{
- TextSlider_setValueFromIdentifier_allowAnim(me, id, false);
-}
-void TextSlider_setValueFromIdentifier(entity me, string id)
-{
- TextSlider_setValueFromIdentifier_allowAnim(me, id, true);
-}
-string TextSlider_getIdentifier(entity me)
-{
- return me.valueToIdentifier(me, me.value);
-}
-void TextSlider_clearValues(entity me)
-{
- me.nValues = 0;
-}
-void TextSlider_addValue(entity me, string theString, string theIdentifier)
-{
- me.(valueStrings[me.nValues]) = theString;
- me.(valueIdentifiers[me.nValues]) = theIdentifier;
- me.nValues += 1;
-}
-void TextSlider_insertValue(entity me, int pos, string theString, string theIdentifier)
-{
- int i;
- for (i = me.nValues; i > pos; --i)
+ me.(valueStrings[pos]) = theString;
+ me.(valueIdentifiers[pos]) = theIdentifier;
+ me.nValues += 1;
+ }
+ void TextSlider_configureTextSliderValues(entity me, string theDefault)
{
- me.(valueStrings[i]) = me.(valueStrings[i-1]);
- me.(valueIdentifiers[i]) = me.(valueIdentifiers[i-1]);
+ me.configureSliderValues(me, 0, 0, me.nValues - 1, 1, 1, 1);
+ me.setValueFromIdentifier_noAnim(me, theDefault);
}
- me.(valueStrings[pos]) = theString;
- me.(valueIdentifiers[pos]) = theIdentifier;
- me.nValues += 1;
-}
-void TextSlider_configureTextSliderValues(entity me, string theDefault)
-{
- me.configureSliderValues(me, 0, 0, me.nValues - 1, 1, 1, 1);
- me.setValueFromIdentifier_noAnim(me, theDefault);
-}
#endif
#include "menu.qh"
-#include "oo/classes.qc"
+#include "classes.qc"
#include "xonotic/util.qh"
#include "../common/items/all.qh"
#include "../common/mapinfo.qh"
#include "../common/mutators/base.qh"
-///////////////////////////////////////////////
-// Menu Source File
-///////////////////////
-// This file belongs to dpmod/darkplaces
-// AK contains all menu functions (especially the required ones)
-///////////////////////////////////////////////
-
-float mouseButtonsPressed;
+int mouseButtonsPressed;
vector menuMousePos;
int menuShiftState;
float menuPrevTime;
float menuAlpha;
float menuLogoAlpha;
float prevMenuAlpha;
-float menuInitialized;
-float menuNotTheFirstFrame;
-float menuMouseMode;
+bool menuInitialized;
+bool menuNotTheFirstFrame;
+int menuMouseMode;
-float conwidth_s, conheight_s, vidwidth_s, vidheight_s, vidpixelheight_s,
- realconwidth, realconheight;
+float conwidth_s, conheight_s;
+float vidwidth_s, vidheight_s, vidpixelheight_s;
+float realconwidth, realconheight;
void m_sync()
{
updateCompression();
- vidwidth_s = vidheight_s = vidpixelheight_s = 0; // Force updateConwidths on next draw.
+ vidwidth_s = vidheight_s = vidpixelheight_s = 0; // Force updateConwidths on next draw
loadAllCvars(main);
}
void m_gamestatus()
{
gamestatus = 0;
- if(isserver())
- gamestatus = gamestatus | GAME_ISSERVER;
- if(clientstate() == CS_CONNECTED || isdemo())
- gamestatus = gamestatus | GAME_CONNECTED;
- if(cvar("developer"))
- gamestatus = gamestatus | GAME_DEVELOPER;
+ if (isserver()) gamestatus |= GAME_ISSERVER;
+ if (clientstate() == CS_CONNECTED || isdemo()) gamestatus |= GAME_CONNECTED;
+ if (cvar("developer")) gamestatus |= GAME_DEVELOPER;
}
void m_init()
{
- float restarting = 0;
+ bool restarting = false;
cvar_set("_menu_alpha", "0");
prvm_language = cvar_string("prvm_language");
- if(prvm_language == "")
+ if (prvm_language == "")
{
prvm_language = "en";
cvar_set("prvm_language", prvm_language);
localcmd("\nmenu_restart\n");
- restarting = 1;
+ restarting = true;
}
prvm_language = strzone(prvm_language);
cvar_set("_menu_prvm_language", prvm_language);
#ifdef WATERMARK
- LOG_TRACEF("^4MQC Build information: ^1%s\n", WATERMARK);
+ LOG_INFOF("^4MQC Build information: ^1%s\n", WATERMARK);
#endif
// list all game dirs (TEST)
- if(cvar("developer"))
+ if (cvar("developer"))
{
- float i;
- string s;
- for(i = 0; ; ++i)
+ for (int i = 0; ; ++i)
{
- s = getgamedirinfo(i, GETGAMEDIRINFO_NAME);
- if (!s)
- break;
+ string s = getgamedirinfo(i, GETGAMEDIRINFO_NAME);
+ if (!s) break;
LOG_TRACE(s, ": ", getgamedirinfo(i, GETGAMEDIRINFO_DESCRIPTION));
}
}
// needs to be done so early because of the constants they create
static_init();
static_init_late();
+ static_init_precache();
RegisterSLCategories();
float ddsload = cvar("r_texture_dds_load");
float texcomp = cvar("gl_texturecompression");
updateCompression();
- if(ddsload != cvar("r_texture_dds_load") || texcomp != cvar("gl_texturecompression"))
- localcmd("\nr_restart\n");
+ if (ddsload != cvar("r_texture_dds_load") || texcomp != cvar("gl_texturecompression")) localcmd("\nr_restart\n");
- if(!restarting)
+ if (!restarting)
{
- if(cvar("_menu_initialized")) // always show menu after menu_restart
+ if (cvar("_menu_initialized")) // always show menu after menu_restart
m_display();
- else
- m_hide();
+ else m_hide();
cvar_set("_menu_initialized", "1");
}
-
}
-const float MENU_ASPECT = 1.25; // 1280x1024
+const float MENU_ASPECT = 1280 / 1024;
void draw_reset_cropped()
{
{
if (w != vidwidth_s || h != vidheight_s || p != vidpixelheight_s)
{
- if (updateConwidths(w, h, p))
- localcmd(sprintf("\nexec %s\n", cvar_string("menu_font_cfg")));
+ if (updateConwidths(w, h, p)) localcmd(sprintf("\nexec %s\n", cvar_string("menu_font_cfg")));
vidwidth_s = w;
vidheight_s = h;
vidpixelheight_s = p;
conheight_s = conheight;
realconwidth = cvar("vid_conwidth");
realconheight = cvar("vid_conheight");
- if(realconwidth / realconheight > MENU_ASPECT)
+ if (realconwidth / realconheight > MENU_ASPECT)
{
// widescreen
conwidth = realconheight * MENU_ASPECT;
conwidth = realconwidth;
conheight = realconwidth / MENU_ASPECT;
}
- if(main)
+ if (main)
{
- if(conwidth_s != conwidth || conheight_s != conheight)
+ if (conwidth_s != conwidth || conheight_s != conheight)
{
draw_reset_cropped();
main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
}
else
{
- vidwidth_s = vidheight_s = vidpixelheight_s = 0; // retry next frame
+ vidwidth_s = vidheight_s = vidpixelheight_s = 0; // retry next frame
}
}
string m_goto_buffer;
void m_init_delayed()
{
- float fh, glob, n, i;
- string s;
-
draw_reset_cropped();
- menuInitialized = 0;
- if(!preMenuInit())
- return;
- menuInitialized = 1;
+ menuInitialized = false;
+ if (!preMenuInit()) return;
+ menuInitialized = true;
- fh = -1;
- if(cvar_string("menu_skin") != "")
+ int fh = -1;
+ if (cvar_string("menu_skin") != "")
{
draw_currentSkin = strcat("gfx/menu/", cvar_string("menu_skin"));
fh = fopen(language_filename(strcat(draw_currentSkin, "/skinvalues.txt")), FILE_READ);
}
- if(fh < 0)
- if(cvar_defstring("menu_skin") != "")
+ if (fh < 0 && cvar_defstring("menu_skin") != "")
{
cvar_set("menu_skin", cvar_defstring("menu_skin"));
draw_currentSkin = strcat("gfx/menu/", cvar_string("menu_skin"));
fh = fopen(language_filename(strcat(draw_currentSkin, "/skinvalues.txt")), FILE_READ);
}
- if(fh < 0)
+ if (fh < 0)
{
draw_currentSkin = "gfx/menu/default";
fh = fopen(language_filename(strcat(draw_currentSkin, "/skinvalues.txt")), FILE_READ);
}
- if(fh < 0)
- {
- error("cannot load any menu skin\n");
- }
+ if (fh < 0) error("cannot load any menu skin\n");
draw_currentSkin = strzone(draw_currentSkin);
- while((s = fgets(fh)))
+ for (string s; (s = fgets(fh)); )
{
// these two are handled by skinlist.qc
- if(substring(s, 0, 6) == "title ")
- continue;
- if(substring(s, 0, 7) == "author ")
- continue;
- n = tokenize_console(s);
- if(n >= 2)
- Skin_ApplySetting(argv(0), substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
+ if (substring(s, 0, 6) == "title ") continue;
+ if (substring(s, 0, 7) == "author ") continue;
+ int n = tokenize_console(s);
+ if (n < 2) continue;
+ Skin_ApplySetting(argv(0), substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
}
fclose(fh);
- glob = search_begin(strcat(draw_currentSkin, "/*.tga"), true, true);
- if(glob >= 0)
+ int glob = search_begin(strcat(draw_currentSkin, "/*.tga"), true, true);
+ if (glob >= 0)
{
- n = search_getsize(glob);
- for(i = 0; i < n; ++i)
+ for (int i = 0, n = search_getsize(glob); i < n; ++i)
precache_pic(search_getfilename(glob, i));
search_end(glob);
}
draw_setMousePointer(SKINGFX_CURSOR, SKINSIZE_CURSOR, SKINOFFSET_CURSOR);
anim = NEW(AnimHost);
- main = NEW(MainWindow); main.configureMainWindow(main);
+ main = NEW(MainWindow);
+ main.configureMainWindow(main);
main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
- main.focused = 1;
+ main.focused = true;
menuShiftState = 0;
menuMousePos = '0.5 0.5 0';
m_sync();
- if(m_goto_buffer)
+ if (m_goto_buffer)
{
m_goto(m_goto_buffer);
strunzone(m_goto_buffer);
m_goto_buffer = string_null;
}
- if(Menu_Active)
- m_display(); // delayed menu display
+ if (Menu_Active) m_display(); // delayed menu display
}
-void m_keyup (float key, float ascii)
+void m_keyup(float key, float ascii)
{
- if(!menuInitialized)
- return;
- if(!Menu_Active)
- return;
+ if (!menuInitialized) return;
+ if (!Menu_Active) return;
draw_reset_cropped();
main.keyUp(main, key, ascii, menuShiftState);
- if(key >= K_MOUSE1 && key <= K_MOUSE3)
+ if (key >= K_MOUSE1 && key <= K_MOUSE3)
{
--mouseButtonsPressed;
- if(!mouseButtonsPressed)
- main.mouseRelease(main, menuMousePos);
- if(mouseButtonsPressed < 0)
+ if (!mouseButtonsPressed) main.mouseRelease(main, menuMousePos);
+ if (mouseButtonsPressed < 0)
{
mouseButtonsPressed = 0;
LOG_TRACE("Warning: released an already released button\n");
}
}
- if(key == K_ALT) menuShiftState -= (menuShiftState & S_ALT);
- if(key == K_CTRL) menuShiftState -= (menuShiftState & S_CTRL);
- if(key == K_SHIFT) menuShiftState -= (menuShiftState & S_SHIFT);
+ if (key == K_ALT) menuShiftState &= ~S_ALT;
+ if (key == K_CTRL) menuShiftState &= ~S_CTRL;
+ if (key == K_SHIFT) menuShiftState &= ~S_SHIFT;
}
void m_keydown(float key, float ascii)
{
- if(!menuInitialized)
- return;
- if(!Menu_Active)
- return;
+ if (!menuInitialized) return;
+ if (!Menu_Active) return;
- if(menuMouseMode)
- if(key >= K_MOUSE1 && key <= K_MOUSE3)
+ if (menuMouseMode && key >= K_MOUSE1 && key <= K_MOUSE3)
{
// detect a click outside of the game window
vector p = getmousepos();
- if(p.x < 0 || p.x > realconwidth || p.y < 0 || p.y > realconheight)
+ if (p.x < 0 || p.x > realconwidth || p.y < 0 || p.y > realconheight)
{
++mouseButtonsPressed;
return;
}
}
- if(keyGrabber)
+ if (keyGrabber)
{
- entity e;
- e = keyGrabber;
+ entity e = keyGrabber;
keyGrabber = NULL;
e.keyGrabbed(e, key, ascii);
}
else
{
draw_reset_cropped();
- if(key >= K_MOUSE1 && key <= K_MOUSE3)
- if(!mouseButtonsPressed)
- main.mousePress(main, menuMousePos);
- if(!main.keyDown(main, key, ascii, menuShiftState))
- if(key == K_ESCAPE)
- if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED)) // don't back out to console only
- m_hide(); // disable menu on unhandled ESC
+ if (!mouseButtonsPressed && key >= K_MOUSE1 && key <= K_MOUSE3) main.mousePress(main, menuMousePos);
+ if (!main.keyDown(main, key, ascii, menuShiftState))
+ {
+ // disable menu on unhandled ESC
+ if (key == K_ESCAPE)
+ if (gamestatus & (GAME_ISSERVER | GAME_CONNECTED)) // don't back out to console only
+ m_hide();
+ }
}
- if(key >= K_MOUSE1 && key <= K_MOUSE3)
+ if (key >= K_MOUSE1 && key <= K_MOUSE3)
{
++mouseButtonsPressed;
- if(mouseButtonsPressed > 10)
+ if (mouseButtonsPressed > 10)
{
mouseButtonsPressed = 10;
LOG_TRACE("Warning: pressed an already pressed button\n");
}
}
- if(key == K_ALT) menuShiftState |= S_ALT;
- if(key == K_CTRL) menuShiftState |= S_CTRL;
- if(key == K_SHIFT) menuShiftState |= S_SHIFT;
+ if (key == K_ALT) menuShiftState |= S_ALT;
+ if (key == K_CTRL) menuShiftState |= S_CTRL;
+ if (key == K_SHIFT) menuShiftState |= S_SHIFT;
}
-const float SCALEMODE_CROP = 0;
-const float SCALEMODE_LETTERBOX = 1;
-const float SCALEMODE_WIDTH = 2;
-const float SCALEMODE_HEIGHT = 3;
-const float SCALEMODE_STRETCH = 4;
+enum {
+ SCALEMODE_CROP,
+ SCALEMODE_LETTERBOX,
+ SCALEMODE_WIDTH,
+ SCALEMODE_HEIGHT,
+ SCALEMODE_STRETCH,
+};
void draw_Picture_Aligned(vector algn, float scalemode, string img, float a)
{
- vector sz, org, isz, isz_w, isz_h;
- float width_is_larger;
-
- sz = draw_PictureSize(img);
- width_is_larger = (sz.x * draw_scale.y >= sz.y * draw_scale.x);
- isz_w = '1 0 0' + '0 1 0' * ((sz.y / sz.x) * (draw_scale.x / draw_scale.y));
- isz_h = '0 1 0' + '1 0 0' * ((sz.x / sz.y) * (draw_scale.y / draw_scale.x));
-
- switch(scalemode)
+ vector sz = draw_PictureSize(img);
+ bool width_is_larger = (sz.x * draw_scale.y >= sz.y * draw_scale.x);
+ vector isz_w = '1 0 0' + '0 1 0' * ((sz.y / sz.x) * (draw_scale.x / draw_scale.y));
+ vector isz_h = '0 1 0' + '1 0 0' * ((sz.x / sz.y) * (draw_scale.y / draw_scale.x));
+ vector isz;
+ switch (scalemode)
{
default:
case SCALEMODE_CROP:
isz = '1 1 0';
break;
}
-
- org = eX * (algn.x * (1 - isz.x)) + eY * (algn.y * (1 - isz.y));
+ vector org = eX * (algn.x * (1 - isz.x)) + eY * (algn.y * (1 - isz.y));
draw_Picture(org, img, isz, '1 1 1', a);
}
void drawBackground(string img, float a, string algn, float force1)
{
- if(main.mainNexposee.ModalController_state == 0)
- return;
-
- vector v;
- float i, l;
- string c;
- float scalemode;
-
- v.z = 0;
-
- scalemode = SCALEMODE_CROP;
-
- l = 0;
- for(i = 0; i < strlen(algn); ++i)
+ if (main.mainNexposee.ModalController_state == 0) return;
+ vector v = '0 0 0';
+ int scalemode = SCALEMODE_CROP;
+ for (int i = 0, l = 0; i < strlen(algn); ++i)
{
- c = substring(algn, i, 1);
- switch(c)
+ string c = substring(algn, i, 1);
+ switch (c)
{
- case "c": scalemode = SCALEMODE_CROP; goto nopic;
- case "l": scalemode = SCALEMODE_LETTERBOX; goto nopic;
- case "h": scalemode = SCALEMODE_HEIGHT; goto nopic;
- case "w": scalemode = SCALEMODE_WIDTH; goto nopic;
- case "s": scalemode = SCALEMODE_STRETCH; goto nopic;
- case "1": case "4": case "7": v.x = 0.0; break;
- case "2": case "5": case "8": v.x = 0.5; break;
- case "3": case "6": case "9": v.x = 1.0; break;
- default: v.x = random(); break;
+ case "c":
+ scalemode = SCALEMODE_CROP;
+ goto nopic;
+ case "l":
+ scalemode = SCALEMODE_LETTERBOX;
+ goto nopic;
+ case "h":
+ scalemode = SCALEMODE_HEIGHT;
+ goto nopic;
+ case "w":
+ scalemode = SCALEMODE_WIDTH;
+ goto nopic;
+ case "s":
+ scalemode = SCALEMODE_STRETCH;
+ goto nopic;
+ case "1": case "4": case "7":
+ v.x = 0.0;
+ break;
+ case "2": case "5": case "8":
+ v.x = 0.5;
+ break;
+ case "3": case "6": case "9":
+ v.x = 1.0;
+ break;
+ default:
+ v.x = random();
+ break;
}
- switch(c)
+ switch (c)
{
- case "7": case "8": case "9": v.y = 0.0; break;
- case "4": case "5": case "6": v.y = 0.5; break;
- case "1": case "2": case "3": v.y = 1.0; break;
- default: v.y = random(); break;
+ case "7": case "8": case "9":
+ v.y = 0.0;
+ break;
+ case "4": case "5": case "6":
+ v.y = 0.5;
+ break;
+ case "1": case "2": case "3":
+ v.y = 1.0;
+ break;
+ default:
+ v.y = random();
+ break;
}
- if(l == 0)
+ if (l == 0)
+ {
draw_Picture_Aligned(v, scalemode, img, a);
- else if(force1)
+ }
+ else if (force1)
+ {
// force all secondary layers to use alpha 1. Prevents ugly issues
// with overlap. It's a flag because it cannot be used for the
// ingame background
- draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l+1)), 1);
+ draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l + 1)), 1);
+ }
else
- draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l+1)), a);
+ {
+ draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l + 1)), a);
+ }
++l;
-:nopic
+ : nopic
}
}
-float menu_tooltips;
-float menu_tooltips_old;
+int menu_tooltips;
+int menu_tooltips_old;
vector menuTooltipAveragedMousePos;
entity menuTooltipItem;
vector menuTooltipOrigin;
vector menuTooltipSize;
float menuTooltipAlpha;
string menuTooltipText;
-float menuTooltipState; // 0: static, 1: fading in, 2: fading out, 3: forced fading out
-float m_testmousetooltipbox(vector pos)
+int menuTooltipState; // 0: static, 1: fading in, 2: fading out, 3: forced fading out
+bool m_testmousetooltipbox(vector pos)
{
- if(pos.x >= menuTooltipOrigin.x && pos.x < menuTooltipOrigin.x + menuTooltipSize.x)
- if(pos.y >= menuTooltipOrigin.y && pos.y < menuTooltipOrigin.y + menuTooltipSize.y)
- return false;
- return true;
+ return !(
+ (pos.x >= menuTooltipOrigin.x && pos.x < menuTooltipOrigin.x + menuTooltipSize.x)
+ && (pos.y >= menuTooltipOrigin.y && pos.y < menuTooltipOrigin.y + menuTooltipSize.y)
+ );
}
-float m_testtooltipbox(vector tooltippos)
+bool m_testtooltipbox(vector tooltippos)
{
- if(tooltippos.x < 0)
- return false;
- if(tooltippos.y < 0)
- return false;
- if(tooltippos.x + menuTooltipSize.x > 1)
- return false;
- if(tooltippos.y + menuTooltipSize.y > 1)
- return false;
+ if (tooltippos.x < 0) return false;
+ if (tooltippos.y < 0) return false;
+ if (tooltippos.x + menuTooltipSize.x > 1) return false;
+ if (tooltippos.y + menuTooltipSize.y > 1) return false;
menuTooltipOrigin = tooltippos;
return true;
}
-float m_allocatetooltipbox(vector pos)
+bool m_allocatetooltipbox(vector pos)
{
- vector avoidplus, avoidminus;
- vector v;
-
+ vector avoidplus;
avoidplus.x = (SKINAVOID_TOOLTIP_x + SKINSIZE_CURSOR_x - SKINOFFSET_CURSOR_x * SKINSIZE_CURSOR_x) / conwidth;
avoidplus.y = (SKINAVOID_TOOLTIP_y + SKINSIZE_CURSOR_y - SKINOFFSET_CURSOR_y * SKINSIZE_CURSOR_y) / conheight;
avoidplus.z = 0;
+ vector avoidminus;
avoidminus.x = (SKINAVOID_TOOLTIP_x + SKINOFFSET_CURSOR_x * SKINSIZE_CURSOR_x) / conwidth + menuTooltipSize.x;
avoidminus.y = (SKINAVOID_TOOLTIP_y + SKINOFFSET_CURSOR_y * SKINSIZE_CURSOR_y) / conheight + menuTooltipSize.y;
avoidminus.z = 0;
// bottom right
- v = pos + avoidplus;
- if(m_testtooltipbox(v))
- return true;
+ vector v = pos + avoidplus;
+ if (m_testtooltipbox(v)) return true;
// bottom center
v.x = pos.x - menuTooltipSize.x * 0.5;
- if(m_testtooltipbox(v))
- return true;
+ if (m_testtooltipbox(v)) return true;
// bottom left
v.x = pos.x - avoidminus.x;
- if(m_testtooltipbox(v))
- return true;
+ if (m_testtooltipbox(v)) return true;
// top left
v.y = pos.y - avoidminus.y;
- if(m_testtooltipbox(v))
- return true;
+ if (m_testtooltipbox(v)) return true;
// top center
v.x = pos.x - menuTooltipSize.x * 0.5;
- if(m_testtooltipbox(v))
- return true;
+ if (m_testtooltipbox(v)) return true;
// top right
v.x = pos.x + avoidplus.x;
- if(m_testtooltipbox(v))
- return true;
+ if (m_testtooltipbox(v)) return true;
return false;
}
entity m_findtooltipitem(entity root, vector pos)
{
- entity it;
- entity best;
-
- best = NULL;
- it = root;
-
- while(it.instanceOfContainer)
+ entity best = NULL;
+ for (entity it = root; it.instanceOfContainer; )
{
- while(it.instanceOfNexposee && it.focusedChild)
+ while (it.instanceOfNexposee && it.focusedChild)
{
it = it.focusedChild;
pos = globalToBox(pos, it.Container_origin, it.Container_size);
}
- if(it.instanceOfNexposee)
+ if (it.instanceOfNexposee)
{
it = it.itemFromPoint(it, pos);
- if(it.tooltip)
- best = it;
- else if(menu_tooltips == 2 && (it.cvarName || it.onClickCommand))
- best = it;
+ if (it.tooltip) best = it;
+ else if (menu_tooltips == 2 && (it.cvarName || it.onClickCommand)) best = it;
it = NULL;
}
- else if(it.instanceOfModalController)
+ else if (it.instanceOfModalController)
+ {
it = it.focusedChild;
+ }
else
+ {
it = it.itemFromPoint(it, pos);
- if(!it)
- break;
- if(it.tooltip)
- best = it;
- else if(menu_tooltips == 2 && (it.cvarName || it.onClickCommand))
- best = it;
+ }
+ if (!it) break;
+ if (it.tooltip) best = it;
+ else if (menu_tooltips == 2 && (it.cvarName || it.onClickCommand)) best = it;
pos = globalToBox(pos, it.Container_origin, it.Container_size);
}
string s;
if (menuTooltipItem.cvarName)
{
- if (getCvarsMulti(menuTooltipItem))
- s = strcat("[", menuTooltipItem.cvarName, " ", getCvarsMulti(menuTooltipItem), "]");
- else
- s = strcat("[", menuTooltipItem.cvarName, "]");
+ if (getCvarsMulti(menuTooltipItem)) s =
+ strcat("[", menuTooltipItem.cvarName, " ", getCvarsMulti(menuTooltipItem), "]");
+ else s = strcat("[", menuTooltipItem.cvarName, "]");
}
else if (menuTooltipItem.onClickCommand)
+ {
s = strcat("<", menuTooltipItem.onClickCommand, ">");
+ }
else
+ {
return menuTooltipItem.tooltip;
- if (menuTooltipItem.tooltip)
- return strcat(menuTooltipItem.tooltip, " ", s);
+ }
+ if (menuTooltipItem.tooltip) return strcat(menuTooltipItem.tooltip, " ", s);
return s;
}
return menuTooltipItem.tooltip;
}
-string prev_tooltip;
void m_tooltip(vector pos)
{
- float f, i, w;
+ static string prev_tooltip;
entity it;
- vector fontsize, p;
- string s;
-
menu_tooltips = cvar("menu_tooltips");
if (!menu_tooltips)
{
// don't return immediately, fade out the active tooltip first
- if (menuTooltipItem == NULL)
- return;
+ if (menuTooltipItem == NULL) return;
it = NULL;
menu_tooltips_old = menu_tooltips;
}
else
{
- f = bound(0, frametime * 2, 1);
+ float f = bound(0, frametime * 2, 1);
menuTooltipAveragedMousePos = menuTooltipAveragedMousePos * (1 - f) + pos * f;
f = vlen(pos - menuTooltipAveragedMousePos);
- if(f < 0.01)
+ if (f < 0.01)
{
it = m_findtooltipitem(main, pos);
- if(it.instanceOfListBox && it.isScrolling(it))
- it = world;
+ if (it.instanceOfListBox && it.isScrolling(it)) it = world;
- if(it && prev_tooltip != it.tooltip)
+ if (it && prev_tooltip != it.tooltip)
{
// fade out if tooltip of a certain item has changed
menuTooltipState = 3;
- if(prev_tooltip)
- strunzone(prev_tooltip);
+ if (prev_tooltip) strunzone(prev_tooltip);
prev_tooltip = strzone(it.tooltip);
}
- else if(menuTooltipItem && !m_testmousetooltipbox(pos))
- menuTooltipState = 3; // fade out if mouse touches it
-
+ else if (menuTooltipItem && !m_testmousetooltipbox(pos))
+ {
+ menuTooltipState = 3; // fade out if mouse touches it
+ }
}
else
+ {
it = NULL;
+ }
}
- fontsize = '1 0 0' * (SKINFONTSIZE_TOOLTIP / conwidth) + '0 1 0' * (SKINFONTSIZE_TOOLTIP / conheight);
+ vector fontsize = '1 0 0' * (SKINFONTSIZE_TOOLTIP / conwidth) + '0 1 0' * (SKINFONTSIZE_TOOLTIP / conheight);
// float menuTooltipState; // 0: static, 1: fading in, 2: fading out, 3: forced fading out
- if(it != menuTooltipItem)
+ if (it != menuTooltipItem)
{
- switch(menuTooltipState)
+ switch (menuTooltipState)
{
case 0:
- if(menuTooltipItem)
+ if (menuTooltipItem)
{
// another item: fade out first
menuTooltipState = 2;
menuTooltipState = 1;
menuTooltipItem = it;
- menuTooltipOrigin.x = -1; // unallocated
+ menuTooltipOrigin.x = -1; // unallocated
- if (menuTooltipText)
- strunzone(menuTooltipText);
+ if (menuTooltipText) strunzone(menuTooltipText);
menuTooltipText = strzone(gettooltip());
- i = 0;
- w = 0;
- getWrappedLine_remaining = menuTooltipText;
- while(getWrappedLine_remaining)
+ int i = 0;
+ float w = 0;
+ for (getWrappedLine_remaining = menuTooltipText; getWrappedLine_remaining; ++i)
{
- s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);
- ++i;
- f = draw_TextWidth(s, false, fontsize);
- if(f > w)
- w = f;
+ string s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);
+ float f = draw_TextWidth(s, false, fontsize);
+ if (f > w) w = f;
}
menuTooltipSize.x = w + 2 * (SKINMARGIN_TOOLTIP_x / conwidth);
menuTooltipSize.y = i * fontsize.y + 2 * (SKINMARGIN_TOOLTIP_y / conheight);
break;
}
}
- else if(menuTooltipState == 2) // re-fade in?
+ else if (menuTooltipState == 2) // re-fade in?
+ {
menuTooltipState = 1;
+ }
- switch(menuTooltipState)
+ switch (menuTooltipState)
{
- case 1: // fade in
+ case 1: // fade in
menuTooltipAlpha = bound(0, menuTooltipAlpha + 5 * frametime, 1);
- if(menuTooltipAlpha == 1)
- menuTooltipState = 0;
+ if (menuTooltipAlpha == 1) menuTooltipState = 0;
break;
- case 2: // fade out
- case 3: // forced fade out
+ case 2: // fade out
+ case 3: // forced fade out
menuTooltipAlpha = bound(0, menuTooltipAlpha - 2 * frametime, 1);
- if(menuTooltipAlpha == 0)
+ if (menuTooltipAlpha == 0)
{
menuTooltipState = 0;
menuTooltipItem = NULL;
break;
}
- if(menuTooltipItem == NULL)
+ if (menuTooltipItem == NULL)
{
if (menuTooltipText)
{
}
else
{
- if(menu_tooltips != menu_tooltips_old)
+ if (menu_tooltips != menu_tooltips_old)
{
- if (menu_tooltips != 0 && menu_tooltips_old != 0)
- menuTooltipItem = NULL; // reload tooltip next frame
+ if (menu_tooltips != 0 && menu_tooltips_old != 0) menuTooltipItem = NULL; // reload tooltip next frame
menu_tooltips_old = menu_tooltips;
}
- else if(menuTooltipOrigin.x < 0) // unallocated?
+ else if (menuTooltipOrigin.x < 0) // unallocated?
+ {
m_allocatetooltipbox(pos);
-
- if(menuTooltipOrigin.x >= 0)
+ }
+ if (menuTooltipOrigin.x >= 0)
{
// draw the tooltip!
- p = SKINBORDER_TOOLTIP;
+ vector p = SKINBORDER_TOOLTIP;
p.x *= 1 / conwidth;
p.y *= 1 / conheight;
draw_BorderPicture(menuTooltipOrigin, SKINGFX_TOOLTIP, menuTooltipSize, '1 1 1', menuTooltipAlpha, p);
p = menuTooltipOrigin;
p.x += SKINMARGIN_TOOLTIP_x / conwidth;
p.y += SKINMARGIN_TOOLTIP_y / conheight;
- getWrappedLine_remaining = menuTooltipText;
- while(getWrappedLine_remaining)
+ for (getWrappedLine_remaining = menuTooltipText; getWrappedLine_remaining; p.y += fontsize.y)
{
- s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);
+ string s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);
draw_Text(p, s, fontsize, SKINCOLOR_TOOLTIP, SKINALPHA_TOOLTIP * menuTooltipAlpha, false);
- p.y += fontsize.y;
}
}
}
void m_draw(float width, float height)
{
- float t;
- float realFrametime;
-
m_gamestatus();
execute_next_frame();
menuMouseMode = cvar("menu_mouse_absolute");
- if (anim)
- anim.tickAll(anim);
+ if (anim) anim.tickAll(anim);
UpdateConWidthHeight(width, height, cvar("vid_pixelheight"));
- if(!menuInitialized)
+ if (!menuInitialized)
{
// TODO draw an info image about this situation
m_init_delayed();
return;
}
- if(!menuNotTheFirstFrame)
+ if (!menuNotTheFirstFrame)
{
- menuNotTheFirstFrame = 1;
- if(Menu_Active)
- if(!cvar("menu_video_played"))
- {
- localcmd("cd loop $menu_cdtrack; play sound/announcer/default/welcome.wav\n");
- menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading FIXME
- }
+ menuNotTheFirstFrame = true;
+ if (Menu_Active && !cvar("menu_video_played"))
+ {
+ localcmd("cd loop $menu_cdtrack; play sound/announcer/default/welcome.wav\n");
+ menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading FIXME
+ }
// ALWAYS set this cvar; if we start but menu is not active, this means we want no background music!
localcmd("set menu_video_played 1\n");
}
- t = gettime();
- realFrametime = frametime = min(0.2, t - menuPrevTime);
+ float t = gettime();
+ float realFrametime = frametime = min(0.2, t - menuPrevTime);
menuPrevTime = t;
time += frametime;
t = cvar("menu_slowmo");
- if(t)
+ if (t)
{
frametime *= t;
realFrametime *= t;
}
else
+ {
t = 1;
+ }
- if(Menu_Active)
+ if (Menu_Active)
{
- if(getmousetarget() == (menuMouseMode ? MT_CLIENT : MT_MENU) && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))
- setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);
- else
- m_hide();
+ if (getmousetarget() == (menuMouseMode ? MT_CLIENT : MT_MENU)
+ && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))
+ setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);
+ else m_hide();
}
- if(cvar("cl_capturevideo"))
- frametime = t / cvar("cl_capturevideo_fps"); // make capturevideo work smoothly
+ if (cvar("cl_capturevideo")) frametime = t / cvar("cl_capturevideo_fps"); // make capturevideo work smoothly
prevMenuAlpha = menuAlpha;
- if(Menu_Active)
+ if (Menu_Active)
{
- if(menuAlpha == 0 && menuLogoAlpha < 2)
+ if (menuAlpha == 0 && menuLogoAlpha < 2)
{
- menuLogoAlpha = menuLogoAlpha + frametime * 2;
+ menuLogoAlpha += 2 * frametime;
}
else
{
- menuAlpha = min(1, menuAlpha + frametime * 5);
+ menuAlpha = min(1, menuAlpha + 5 * frametime);
menuLogoAlpha = 2;
}
}
else
{
- menuAlpha = max(0, menuAlpha - frametime * 5);
+ menuAlpha = max(0, menuAlpha - 5 * frametime);
menuLogoAlpha = 2;
}
draw_reset_cropped();
- if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
+ if (!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
{
- if(menuLogoAlpha > 0)
+ if (menuLogoAlpha > 0)
{
draw_reset_full();
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_BACKGROUND, 1);
drawBackground(SKINGFX_BACKGROUND, bound(0, menuLogoAlpha, 1), SKINALIGN_BACKGROUND, true);
draw_reset_cropped();
- if(menuAlpha <= 0 && SKINALPHA_CURSOR_INTRO > 0)
+ if (menuAlpha <= 0 && SKINALPHA_CURSOR_INTRO > 0)
{
draw_alpha = SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1);
draw_drawMousePointer(menuMousePos);
}
}
}
- else if(SKINALPHA_BACKGROUND_INGAME)
+ else if (SKINALPHA_BACKGROUND_INGAME)
{
- if(menuAlpha > 0)
+ if (menuAlpha > 0)
{
draw_reset_full();
- drawBackground(SKINGFX_BACKGROUND_INGAME, menuAlpha * SKINALPHA_BACKGROUND_INGAME, SKINALIGN_BACKGROUND_INGAME, false);
+ drawBackground(SKINGFX_BACKGROUND_INGAME, menuAlpha * SKINALPHA_BACKGROUND_INGAME,
+ SKINALIGN_BACKGROUND_INGAME, false);
draw_reset_cropped();
}
}
- if(menuAlpha != prevMenuAlpha)
- cvar_set("_menu_alpha", ftos(menuAlpha));
+ if (menuAlpha != prevMenuAlpha) cvar_set("_menu_alpha", ftos(menuAlpha));
draw_reset_cropped();
preMenuDraw();
draw_reset_cropped();
- if(menuAlpha <= 0)
+ if (menuAlpha <= 0)
{
- if(prevMenuAlpha > 0)
- main.initializeDialog(main, main.firstChild);
+ if (prevMenuAlpha > 0) main.initializeDialog(main, main.firstChild);
draw_reset_cropped();
postMenuDraw();
return;
draw_alpha *= menuAlpha;
- if(!Menu_Active)
+ if (!Menu_Active)
{
// do not update mouse position
// it prevents mouse jumping to '0 0 0' when menu is fading out
}
- else if(menuMouseMode)
+ else if (menuMouseMode)
{
- vector newMouse;
- newMouse = globalToBox(getmousepos(), draw_shift, draw_scale);
- if(newMouse != '0 0 0')
- if(newMouse != menuMousePos)
- {
- menuMousePos = newMouse;
- if(mouseButtonsPressed)
- main.mouseDrag(main, menuMousePos);
- else
- main.mouseMove(main, menuMousePos);
- }
+ vector newMouse = globalToBox(getmousepos(), draw_shift, draw_scale);
+ if (newMouse != '0 0 0' && newMouse != menuMousePos)
+ {
+ menuMousePos = newMouse;
+ if (mouseButtonsPressed) main.mouseDrag(main, menuMousePos);
+ else main.mouseMove(main, menuMousePos);
+ }
}
- else
+ else if (frametime > 0)
{
- if(frametime > 0)
+ vector dMouse = getmousepos() * (frametime / realFrametime); // for capturevideo
+ if (dMouse != '0 0 0')
{
- vector dMouse, minpos, maxpos;
- dMouse = getmousepos() * (frametime / realFrametime); // for capturevideo
- if(dMouse != '0 0 0')
- {
- minpos = globalToBox('0 0 0', draw_shift, draw_scale);
- maxpos = globalToBox(eX * (realconwidth - 1) + eY * (realconheight - 1), draw_shift, draw_scale);
- dMouse = globalToBoxSize(dMouse, draw_scale);
- menuMousePos += dMouse * cvar("menu_mouse_speed");
- menuMousePos.x = bound(minpos.x, menuMousePos.x, maxpos.x);
- menuMousePos.y = bound(minpos.y, menuMousePos.y, maxpos.y);
- if(mouseButtonsPressed)
- main.mouseDrag(main, menuMousePos);
- else
- main.mouseMove(main, menuMousePos);
- }
+ vector minpos = globalToBox('0 0 0', draw_shift, draw_scale);
+ vector maxpos = globalToBox(eX * (realconwidth - 1) + eY * (realconheight - 1), draw_shift, draw_scale);
+ dMouse = globalToBoxSize(dMouse, draw_scale);
+ menuMousePos += dMouse * cvar("menu_mouse_speed");
+ menuMousePos.x = bound(minpos.x, menuMousePos.x, maxpos.x);
+ menuMousePos.y = bound(minpos.y, menuMousePos.y, maxpos.y);
+ if (mouseButtonsPressed) main.mouseDrag(main, menuMousePos);
+ else main.mouseMove(main, menuMousePos);
}
}
main.draw(main);
setkeydest(KEY_MENU);
setmousetarget((menuMouseMode ? MT_CLIENT : MT_MENU));
- if(!menuInitialized)
- return;
+ if (!menuInitialized) return;
- if(mouseButtonsPressed)
- main.mouseRelease(main, menuMousePos);
+ if (mouseButtonsPressed) main.mouseRelease(main, menuMousePos);
mouseButtonsPressed = 0;
main.focusEnter(main);
setkeydest(KEY_GAME);
setmousetarget(MT_CLIENT);
- if(!menuInitialized)
- return;
+ if (!menuInitialized) return;
main.focusLeave(main);
main.hideNotify(main);
}
-void m_toggle(float mode)
+void m_toggle(int mode)
{
- if(Menu_Active)
+ if (Menu_Active)
{
- if (mode == 1)
- return;
+ if (mode == 1) return;
m_hide();
}
else
{
- if (mode == 0)
- return;
+ if (mode == 0) return;
m_display();
}
}
void Shutdown()
{
- entity e;
-
m_hide();
- for(e = NULL; (e = nextent(e)) != NULL; )
+ for (entity e = NULL; (e = nextent(e)); )
{
- if(e.classname != "vtbl")
- if(e.destroy)
- e.destroy(e);
+ if (e.classname == "vtbl") continue;
+ if (e.destroy) e.destroy(e);
}
}
void m_focus_item_chain(entity outermost, entity innermost)
{
- if(innermost.parent != outermost)
- m_focus_item_chain(outermost, innermost.parent);
+ if (innermost.parent != outermost) m_focus_item_chain(outermost, innermost.parent);
innermost.parent.setFocus(innermost.parent, innermost);
}
void m_activate_window(entity wnd)
{
- entity par;
- par = wnd.parent;
- if(par)
- m_activate_window(par);
+ entity par = wnd.parent;
+ if (par) m_activate_window(par);
- if(par.instanceOfModalController)
+ if (par.instanceOfModalController)
{
- if(wnd.tabSelectingButton)
+ if (wnd.tabSelectingButton)
// tabs
TabButton_Click(wnd.tabSelectingButton, wnd);
else
// root
par.initializeDialog(par, wnd);
}
- else if(par.instanceOfNexposee)
+ else if (par.instanceOfNexposee)
{
// nexposee (sorry for violating abstraction here)
par.selectedChild = wnd;
par.animationState = 1;
Container_setFocus(par, NULL);
}
- else if(par.instanceOfContainer)
+ else if (par.instanceOfContainer)
{
// other containers
- if(par.focused)
- par.setFocus(par, wnd);
+ if (par.focused) par.setFocus(par, wnd);
}
}
void m_setpointerfocus(entity wnd)
{
- if(wnd.instanceOfContainer)
- {
- entity focus = wnd.preferredFocusedGrandChild(wnd);
- if(focus)
- {
- menuMousePos = focus.origin + 0.5 * focus.size;
- menuMousePos.x *= 1 / conwidth;
- menuMousePos.y *= 1 / conheight;
- entity par = wnd.parent;
- if(par.focused)
- par.setFocus(par, wnd);
- if(wnd.focused)
- m_focus_item_chain(wnd, focus);
- }
- }
+ if (!wnd.instanceOfContainer) return;
+ entity focus = wnd.preferredFocusedGrandChild(wnd);
+ if (!focus) return;
+ menuMousePos = focus.origin + 0.5 * focus.size;
+ menuMousePos.x *= 1 / conwidth;
+ menuMousePos.y *= 1 / conheight;
+ entity par = wnd.parent;
+ if (par.focused) par.setFocus(par, wnd);
+ if (wnd.focused) m_focus_item_chain(wnd, focus);
}
void m_goto(string itemname)
{
- entity e;
- if(!menuInitialized)
+ if (!menuInitialized)
{
- if(m_goto_buffer)
- strunzone(m_goto_buffer);
+ if (m_goto_buffer) strunzone(m_goto_buffer);
m_goto_buffer = strzone(itemname);
return;
}
- if(itemname == "") // this can be called by GameCommand
+ if (itemname == "") // this can be called by GameCommand
{
- if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED))
+ if (gamestatus & (GAME_ISSERVER | GAME_CONNECTED))
{
m_hide();
}
}
else
{
- for(e = NULL; (e = find(e, name, itemname)); )
- if(e.classname != "vtbl")
- break;
+ entity e;
+ for (e = NULL; (e = find(e, name, itemname)); )
+ if (e.classname != "vtbl") break;
- if((e) && (!e.requiresConnection || (gamestatus & (GAME_ISSERVER | GAME_CONNECTED))))
+ if ((e) && (!e.requiresConnection || (gamestatus & (GAME_ISSERVER | GAME_CONNECTED))))
{
m_hide();
m_activate_window(e);
}
}
-float menuLastFocusSoundTime;
void m_play_focus_sound()
{
- if(cvar("menu_sounds") > 1)
- if(time - menuLastFocusSoundTime > 0.25)
- {
- localsound(MENU_SOUND_FOCUS);
- menuLastFocusSoundTime = time;
- }
+ static float menuLastFocusSoundTime;
+ if (cvar("menu_sounds") < 2) return;
+ if (time - menuLastFocusSoundTime <= 0.25) return;
+ localsound(MENU_SOUND_FOCUS);
+ menuLastFocusSoundTime = time;
}
void m_play_click_sound(string soundfile)
{
- if(cvar("menu_sounds"))
- localsound(soundfile);
+ if (!cvar("menu_sounds")) return;
+ localsound(soundfile);
}
#include "../common/constants.qh"
#include "../common/util.qh"
-// constants
+const int GAME_ISSERVER = BIT(0);
+const int GAME_CONNECTED = BIT(1);
+const int GAME_DEVELOPER = BIT(2);
-const int GAME_ISSERVER = 1;
-const int GAME_CONNECTED = 2;
-const int GAME_DEVELOPER = 4;
-
-// prototypes
-
-float Menu_Active;
+bool Menu_Active;
int gamestatus;
const int S_SHIFT = 1;
.string name;
entity keyGrabber;
-.void(entity me, float key, float ascii) keyGrabbed;
+.void(entity this, float key, float ascii) keyGrabbed;
-float conwidth, conheight; // "virtual" conwidth/height values for other stuff to assume for scaling
+// "virtual" conwidth/height values for other stuff to assume for scaling
+float conwidth, conheight;
-float preMenuInit(); // you have to define this for pre-menu initialization. Return 0 if initialization needs to be retried a frame later, 1 if it succeeded.
-void preMenuDraw(); // this is run before the menu is drawn. You may put some stuff there that has to be done every frame.
-void postMenuDraw(); // this is run just after the menu is drawn (or not). Useful to draw something over everything else.
+/** you have to define this for pre-menu initialization. Return 0 if initialization needs to be retried a frame later, 1 if it succeeded. */
+float preMenuInit();
+/** this is run before the menu is drawn. You may put some stuff there that has to be done every frame. */
+void preMenuDraw();
+/** this is run just after the menu is drawn (or not). Useful to draw something over everything else. */
+void postMenuDraw();
void m_sync();
void draw_reset_cropped();
-// sounds
-
const string MENU_SOUND_CLEAR = "sound/menu/clear.wav";
const string MENU_SOUND_CLOSE = "sound/menu/close.wav";
const string MENU_SOUND_EXECUTE = "sound/menu/execute.wav";
--- /dev/null
+#ifndef MENU_MUTATORS_EVENTS_H
+#define MENU_MUTATORS_EVENTS_H
+
+#include "../../common/mutators/base.qh"
+
+// globals
+
+string cmd_name;
+int cmd_argc;
+string cmd_string;
+
+/**
+ * Called when a menu command is parsed
+ * NOTE: hooks MUST start with if (MUTATOR_RETURNVALUE) return false;
+ * NOTE: return true if you handled the command, return false to continue handling
+ * NOTE: THESE HOOKS MUST NEVER EVER CALL tokenize()
+ * // example:
+ * MUTATOR_HOOKFUNCTION(foo, Menu_ConsoleCommand) {
+ * if (MUTATOR_RETURNVALUE) return false; // command was already handled
+ * if (cmd_name == "echocvar" && cmd_argc >= 2) {
+ * print(cvar_string(argv(1)), "\n");
+ * return true;
+ * }
+ * if (cmd_name == "echostring" && cmd_argc >= 2) {
+ * print(substring(cmd_string, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), "\n");
+ * return true;
+ * }
+ * return false;
+ * }
+ */
+#define EV_Menu_ConsoleCommand(i, o) \
+ /** command name */ i(string, cmd_name) \
+ /** also, argv() can be used */ i(int, cmd_argc) \
+ /** whole command, use only if you really have to */ i(string, cmd_string) \
+ /**/
+MUTATOR_HOOKABLE(Menu_ConsoleCommand, EV_Menu_ConsoleCommand);
+#endif
+++ /dev/null
-#ifndef CLASSES_H
-#define CLASSES_H
-
-#include "../classes.inc"
-#define IMPLEMENTATION
-#include "../classes.inc"
-#undef IMPLEMENTATION
-
-#endif
#define world NULL
-#include "oo/classes.qc"
+#include "classes.qc"
#include "draw.qc"
#include "menu.qc"
+++ /dev/null
-#ifndef SYS_POST_H
-#define SYS_POST_H
-
-#pragma noref 0
-#endif
+++ /dev/null
-#ifndef SYS_PRE_H
-#define SYS_PRE_H
-
-#pragma noref 1
-#endif
void XonoticCrosshairPicker_cellDraw(entity me, vector cell, vector cellPos)
{
- vector sz;
- string cross = strcat("/gfx/crosshair", crosshairpicker_cellToCrosshair(me, cell));
- sz = draw_PictureSize(cross);
+ string s = strcat("/gfx/crosshair", crosshairpicker_cellToCrosshair(me, cell));
+ vector sz = draw_PictureSize(s);
sz = globalToBoxSize(sz, me.size);
float ar = sz.x / sz.y;
sz.x = me.realCellSize.x;
sz.y = sz.x / ar;
- sz = sz * 0.95;
+ sz *= 0.95;
vector crosshairPos = cellPos + 0.5 * me.realCellSize;
- draw_Picture(crosshairPos - 0.5 * sz, cross, sz, SKINCOLOR_CROSSHAIRPICKER_CROSSHAIR, SKINALPHA_CROSSHAIRPICKER_CROSSHAIR);
+ draw_Picture(crosshairPos - 0.5 * sz, s, sz, SKINCOLOR_CROSSHAIRPICKER_CROSSHAIR, SKINALPHA_CROSSHAIRPICKER_CROSSHAIR);
if(cvar("crosshair_dot"))
draw_Picture(crosshairPos - 0.5 * sz * cvar("crosshair_dot_size"), "/gfx/crosshairdot", sz * cvar("crosshair_dot_size"), SKINCOLOR_CROSSHAIRPICKER_CROSSHAIR, SKINALPHA_CROSSHAIRPICKER_CROSSHAIR);
{
string s = this.CvarStringSource_cvar;
this.StringSource_str = s ? cvar_string(s) : string_null;
- return super.getEntry(this, i, returns);
+ return SUPER(CvarStringSource).getEntry(this, i, returns);
}
METHOD(CvarStringSource, reload, int(entity this, string filter))
{
string s = this.CvarStringSource_cvar;
this.StringSource_str = s ? cvar_string(s) : string_null;
- return super.reload(this, filter);
+ return SUPER(CvarStringSource).reload(this, filter);
}
ENDCLASS(CvarStringSource)
#endif
{
e = get_weaponinfo(j);
if(argv(i) == e.netname)
- s = strcat(s, " & ", e.message);
+ s = strcat(s, " & ", e.m_name);
}
}
s = sprintf(_("%s Arena"), substring(s, 3, strlen(s) - 3));
if((j & 1) == 0)
me.TR(me);
me.TDempty(me, 0.2);
- me.TD(me, 1, 1.8, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.message)));
+ me.TD(me, 1, 1.8, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.m_name)));
setDependentWeird(e, checkCompatibility_weaponarena_weapon);
++j;
}
CLASS(SettingSource, DataSource)
METHOD(SettingSource, getEntry, entity(entity this, int i, void(string name, string icon) returns))
{
- Lazy l = Settings[i];
+ Lazy l = Settings_from(i);
entity it = l.m_get();
if (returns) returns(it.title, string_null);
return it;
}
METHOD(SettingSource, getEntryTooltip, entity(entity this, int i, void(string theTooltip) returns))
{
- Lazy l = Settings[i];
+ Lazy l = Settings_from(i);
entity it = l.m_get();
if (returns) returns(it.tooltip);
return it;
}
METHOD(XonoticRegisteredSettingsList, resizeNotify, void(entity this, vector relOrigin, vector relSize, vector absOrigin, vector absSize))
{
- super.resizeNotify(this, relOrigin, relSize, absOrigin, absSize);
+ SUPER(XonoticRegisteredSettingsList).resizeNotify(this, relOrigin, relSize, absOrigin, absSize);
this.itemAbsSize = '0 0 0';
this.realFontSize_y = this.fontSize / (this.itemAbsSize_y = (absSize.y * this.itemHeight));
}
METHOD(XonoticRegisteredSettingsList, setSelected, void(entity this, int i))
{
- super.setSelected(this, i);
+ SUPER(XonoticRegisteredSettingsList).setSelected(this, i);
this.onChange(this, this.onChangeEntity);
}
CONSTRUCTOR(XonoticRegisteredSettingsList, DataSource _source) {
topics.onChangeEntity = this;
int
- col = 0, width = 1.5;
+ col = 0, width = 1;
this.gotoRC(this, 0, col);
this.TD(this, this.rows, width, topics);
#ifdef IMPLEMENTATION
-entity makeXonoticGametypeList(void)
+entity makeXonoticGametypeList()
{
entity me;
me = NEW(XonoticGametypeList);
continue;
bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_ID, argv(0));
bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_NAME, argv(1));
- float k = strstrofs(argv(2), "(", 0);
- if(k > 0)
- if(substring(argv(2), strlen(argv(2)) - 1, 1) == ")")
- {
- string percent = substring(argv(2), k + 1, -2);
- if(percent != "100%")
- bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_PERCENTAGE, percent);
- }
- bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_NAME_LOCALIZED, (k < 0) ? argv(2) : substring(argv(2), 0, k - 1));
+ bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_NAME_LOCALIZED, argv(2));
+ string percent = argv(3);
+ if(percent && percent != "100%")
+ bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_PERCENTAGE, percent);
++i;
}
fclose(fh);
#define SLIST_CATEGORY(name,enoverride,dioverride,str) \
SET_FIELD_COUNT(name, CATEGORY_FIRST, category_ent_count) \
CHECK_MAX_COUNT(name, MAX_CATEGORIES, category_ent_count, "SLIST_CATEGORY") \
- cat = spawn(); \
- categories[name - 1] = cat; \
- cat.classname = "slist_category"; \
+ cat = categories[name - 1] = new(slist_category); \
cat.cat_name = strzone(#name); \
cat.cat_enoverride_string = strzone(SLIST_CATEGORY_AUTOCVAR(name)); \
cat.cat_dioverride_string = strzone(dioverride); \
string _Nex_ExtResponseSystem_Packs;
float _Nex_ExtResponseSystem_PacksStep;
+/** engine callback */
void URI_Get_Callback(float id, float status, string data)
{
if(url_URI_Get_Callback(id, status, data))
void UpdateNotification_URI_Get_Callback(float id, float status, string data);
-void URI_Get_Callback(float id, float status, string data);
-
// game type list box stuff (does not NEED to contain all game types, other
// types stay available via console)
int GameType_GetID(int cnt);
for(i = 0; i < n; ++i)
{
e = get_weaponinfo(stof(argv(i)));
- s = strcat(s, e.message, ", ");
+ s = strcat(s, e.m_name, ", ");
}
return substring(s, 0, strlen(s) - 2);
}
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
}
e = get_weaponinfo(stof(argv(i)));
- string msg = e.message;
+ string msg = e.m_name;
if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
msg = strcat(msg, "*");
#ifndef SERVER_ALL_H
#define SERVER_ALL_H
-#include "autocvars.qh"
-#include "constants.qh"
-#include "defs.qh"
-#include "miscfunctions.qh"
+int maxclients;
+
+const string STR_PLAYER = "player";
+const string STR_SPECTATOR = "spectator";
+const string STR_OBSERVER = "observer";
+
+#define IS_PLAYER(v) ((v).classname == STR_PLAYER)
+#define IS_SPEC(v) ((v).classname == STR_SPECTATOR)
+#define IS_OBSERVER(v) ((v).classname == STR_OBSERVER)
+
+#define IS_CLIENT(v) (v.flags & FL_CLIENT)
+#define IS_BOT_CLIENT(v) (clienttype(v) == CLIENTTYPE_BOT)
+#define IS_REAL_CLIENT(v) (clienttype(v) == CLIENTTYPE_REAL)
+#define IS_NOT_A_CLIENT(v) (clienttype(v) == CLIENTTYPE_NOTACLIENT)
+
+#define IS_MONSTER(v) (v.flags & FL_MONSTER)
+#define IS_VEHICLE(v) (v.vehicle_flags & VHF_ISVEHICLE)
+#define IS_TURRET(v) (v.turret_flags & TUR_FLAG_ISTURRET)
+#define FOR_EACH_CLIENTSLOT(v) for (v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
+#define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if (IS_CLIENT(v))
+#define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if (IS_REAL_CLIENT(v))
+
+#define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if (IS_PLAYER(v))
+#define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if (IS_SPEC(v))
+#define FOR_EACH_OBSERVER(v) FOR_EACH_CLIENT(v) if (IS_OBSERVER(v))
+#define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if (IS_PLAYER(v))
+
+#define FOR_EACH_MONSTER(v) for (v = world; (v = findflags(v, flags, FL_MONSTER)) != world; )
#include "../common/effects/all.qh"
#include "../common/models/all.qh"
#include "../common/sounds/all.qh"
+#include "autocvars.qh"
+#include "constants.qh"
+#include "defs.qh"
+#include "miscfunctions.qh"
+
#endif
bool autocvar_bot_nofire;
#define autocvar_bot_number cvar("bot_number")
#define autocvar_bot_prefix cvar_string("bot_prefix")
-bool autocvar_bot_sound_monopoly;
#define autocvar_bot_suffix cvar_string("bot_suffix")
bool autocvar_bot_usemodelnames;
int autocvar_bot_vs_human;
float autocvar_g_balance_armor_rotlinear;
int autocvar_g_balance_armor_rotstable;
int autocvar_g_balance_armor_start;
-float autocvar_g_balance_cloaked_alpha;
float autocvar_g_balance_contents_damagerate;
float autocvar_g_balance_contents_drowndelay;
int autocvar_g_balance_contents_playerdamage_drowning;
float autocvar_g_balance_health_rotstable;
float autocvar_g_balance_kill_delay;
float autocvar_g_balance_kill_antispam;
-int autocvar_g_balance_nix_ammo_cells;
-int autocvar_g_balance_nix_ammo_plasma;
-int autocvar_g_balance_nix_ammo_fuel;
-int autocvar_g_balance_nix_ammo_nails;
-int autocvar_g_balance_nix_ammo_rockets;
-int autocvar_g_balance_nix_ammo_shells;
-int autocvar_g_balance_nix_ammoincr_cells;
-int autocvar_g_balance_nix_ammoincr_plasma;
-int autocvar_g_balance_nix_ammoincr_fuel;
-int autocvar_g_balance_nix_ammoincr_nails;
-int autocvar_g_balance_nix_ammoincr_rockets;
-int autocvar_g_balance_nix_ammoincr_shells;
-float autocvar_g_balance_nix_incrtime;
-float autocvar_g_balance_nix_roundtime;
float autocvar_g_balance_pause_armor_rot;
float autocvar_g_balance_pause_armor_rot_spawn;
float autocvar_g_balance_pause_fuel_regen;
float autocvar_g_maxplayers_spectator_blocktime;
float autocvar_g_maxpushtime;
float autocvar_g_maxspeed;
-float autocvar_g_midair_shieldtime;
#define autocvar_g_instagib cvar("g_instagib")
-int autocvar_g_instagib_ammo_drop;
-int autocvar_g_instagib_extralives;
-float autocvar_g_instagib_speed_highspeed;
-float autocvar_g_instagib_invis_alpha;
bool autocvar_g_instagib_damagedbycontents = true;
bool autocvar_g_instagib_blaster_keepdamage = false;
bool autocvar_g_instagib_blaster_keepforce = false;
#define autocvar_g_mirrordamage_virtual cvar("g_mirrordamage_virtual")
float autocvar_g_movement_highspeed = 1;
-int autocvar_g_multijump;
-float autocvar_g_multijump_add;
-float autocvar_g_multijump_speed;
-float autocvar_g_multijump_maxspeed;
-float autocvar_g_multijump_dodging = 1;
string autocvar_g_mutatormsg;
//float autocvar_g_nick_flood_penalty;
int autocvar_g_nick_flood_penalty_red;
int autocvar_g_nick_flood_penalty_yellow;
//float autocvar_g_nick_flood_timeout;
-bool autocvar_g_nix_with_healtharmor;
-bool autocvar_g_nix_with_blaster;
-bool autocvar_g_nix_with_powerups;
bool autocvar_g_nodepthtestitems;
bool autocvar_g_nodepthtestplayers;
bool autocvar_g_norecoil;
float autocvar_g_items_mindist;
float autocvar_g_items_maxdist;
-int autocvar_g_pickup_cells_max;
-int autocvar_g_pickup_plasma_max;
-int autocvar_g_pickup_fuel_max;
int autocvar_g_pickup_items;
-int autocvar_g_pickup_nails_max;
-int autocvar_g_pickup_rockets_max;
-int autocvar_g_pickup_shells_max;
float autocvar_g_player_alpha;
float autocvar_g_player_brightness;
bool autocvar_g_playerclip_collisions;
float autocvar_g_respawn_ghosts_maxtime;
float autocvar_g_respawn_ghosts_speed;
int autocvar_g_respawn_waves;
-bool autocvar_g_running_guns;
bool autocvar_g_shootfromcenter;
bool autocvar_g_shootfromeye;
string autocvar_g_shootfromfixedorigin;
string autocvar_sv_defaultplayermodel_red;
string autocvar_sv_defaultplayermodel_yellow;
int autocvar_sv_defaultplayerskin;
-float autocvar_sv_dodging_delay;
-float autocvar_sv_dodging_height_threshold;
-float autocvar_sv_dodging_horiz_speed;
-float autocvar_sv_dodging_horiz_speed_frozen;
-float autocvar_sv_dodging_ramp_time;
-bool autocvar_sv_dodging_sound;
-float autocvar_sv_dodging_up_speed;
-float autocvar_sv_dodging_wall_distance_threshold;
-bool autocvar_sv_dodging_wall_dodging;
bool autocvar_sv_dodging_frozen;
-bool autocvar_sv_dodging_frozen_doubletap;
bool autocvar_sv_doublejump;
bool autocvar_sv_eventlog;
bool autocvar_sv_eventlog_console;
float autocvar_g_trueaim_minrange;
bool autocvar_g_debug_defaultsounds;
float autocvar_g_grab_range;
-int autocvar_g_sandbox_info;
-bool autocvar_g_sandbox_readonly;
-string autocvar_g_sandbox_storage_name;
-float autocvar_g_sandbox_storage_autosave;
-bool autocvar_g_sandbox_storage_autoload;
-float autocvar_g_sandbox_editor_flood;
-int autocvar_g_sandbox_editor_maxobjects;
-int autocvar_g_sandbox_editor_free;
-float autocvar_g_sandbox_editor_distance_spawn;
-float autocvar_g_sandbox_editor_distance_edit;
-float autocvar_g_sandbox_object_scale_min;
-float autocvar_g_sandbox_object_scale_max;
-float autocvar_g_sandbox_object_material_velocity_min;
-float autocvar_g_sandbox_object_material_velocity_factor;
int autocvar_g_max_info_autoscreenshot;
bool autocvar_physics_ode;
-int autocvar_g_physical_items;
-float autocvar_g_physical_items_damageforcescale;
-float autocvar_g_physical_items_reset;
float autocvar_g_monsters;
bool autocvar_g_monsters_edit;
bool autocvar_g_monsters_sounds;
float autocvar_g_monsters_miniboss_healthboost;
float autocvar_g_monsters_drop_time;
float autocvar_g_monsters_spawnshieldtime;
+bool autocvar_g_monsters_quake_resize = true;
bool autocvar_g_monsters_teams;
float autocvar_g_monsters_respawn_delay;
bool autocvar_g_monsters_respawn;
float autocvar_g_monsters_armor_blockpercent;
float autocvar_g_monsters_healthbars;
float autocvar_g_monsters_lineofsight;
-float autocvar_g_touchexplode_radius;
-float autocvar_g_touchexplode_damage;
-float autocvar_g_touchexplode_edgedamage;
-float autocvar_g_touchexplode_force;
#define autocvar_g_bloodloss cvar("g_bloodloss")
-float autocvar_g_random_gravity_negative_chance;
-float autocvar_g_random_gravity_min;
-float autocvar_g_random_gravity_max;
-float autocvar_g_random_gravity_positive;
-float autocvar_g_random_gravity_negative;
-float autocvar_g_random_gravity_delay;
bool autocvar_g_nades;
bool autocvar_g_nades_override_dropweapon = true;
vector autocvar_g_nades_throw_offset;
float autocvar_g_nades_heal_foe;
string autocvar_g_nades_pokenade_monster_type;
float autocvar_g_nades_pokenade_monster_lifetime;
-float autocvar_g_campcheck_damage;
-float autocvar_g_campcheck_distance;
-float autocvar_g_campcheck_interval;
bool autocvar_g_jump_grunt;
-bool autocvar_g_overkill_powerups_replace;
-float autocvar_g_overkill_superguns_respawn_time;
-bool autocvar_g_overkill_100h_anyway;
-bool autocvar_g_overkill_100a_anyway;
-bool autocvar_g_overkill_ammo_charge;
-float autocvar_g_overkill_ammo_charge_notice;
-float autocvar_g_overkill_ammo_charge_limit;
-float autocvar_g_spawn_near_teammate_distance;
-int autocvar_g_spawn_near_teammate_ignore_spawnpoint;
-float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
-float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
-int autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
-bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
bool autocvar_g_physics_clientselect;
string autocvar_g_physics_clientselect_options;
string autocvar_g_physics_clientselect_default;
-bool autocvar_g_buffs_effects;
-float autocvar_g_buffs_waypoint_distance;
-bool autocvar_g_buffs_randomize;
-float autocvar_g_buffs_random_lifetime;
-bool autocvar_g_buffs_random_location;
-int autocvar_g_buffs_random_location_attempts;
-int autocvar_g_buffs_spawn_count;
-bool autocvar_g_buffs_replace_powerups;
-float autocvar_g_buffs_cooldown_activate;
-float autocvar_g_buffs_cooldown_respawn;
-float autocvar_g_buffs_resistance_blockpercent;
-float autocvar_g_buffs_medic_survive_chance;
-float autocvar_g_buffs_medic_survive_health;
-float autocvar_g_buffs_medic_rot;
-float autocvar_g_buffs_medic_max;
-float autocvar_g_buffs_medic_regen;
-float autocvar_g_buffs_vengeance_damage_multiplier;
-float autocvar_g_buffs_bash_force;
-float autocvar_g_buffs_bash_force_self;
-float autocvar_g_buffs_disability_slowtime;
-float autocvar_g_buffs_disability_speed;
-float autocvar_g_buffs_disability_rate;
-float autocvar_g_buffs_disability_weaponspeed;
-float autocvar_g_buffs_speed_speed;
-float autocvar_g_buffs_speed_rate;
-float autocvar_g_buffs_speed_weaponspeed;
-float autocvar_g_buffs_speed_damage_take;
-float autocvar_g_buffs_speed_regen;
-float autocvar_g_buffs_vampire_damage_steal;
-float autocvar_g_buffs_invisible_alpha;
-float autocvar_g_buffs_flight_gravity;
-float autocvar_g_buffs_jump_height;
bool autocvar_sv_minigames;
bool autocvar_sv_minigames_observer;
-float autocvar_g_buffs_inferno_burntime_factor;
-float autocvar_g_buffs_inferno_burntime_min_time;
-float autocvar_g_buffs_inferno_burntime_target_damage;
-float autocvar_g_buffs_inferno_burntime_target_time;
-float autocvar_g_buffs_inferno_damagemultiplier;
-float autocvar_g_buffs_swapper_range;
-float autocvar_g_buffs_magnet_range_item;
float autocvar_sv_player_scale;
float autocvar_g_rm;
float autocvar_g_rm_damage;
if (targ.solid < SOLID_BBOX) // SOLID_NOT and SOLID_TRIGGER
return false; // could never hit it
if (!tracetossent)
- tracetossent = spawn();
+ tracetossent = new(tracetossent);
tracetossent.owner = ignore;
setsize(tracetossent, m1, m2);
savesolid = targ.solid;
}
if (!tracetossfaketarget)
- tracetossfaketarget = spawn();
+ tracetossfaketarget = new(tracetossfaketarget);
tracetossfaketarget.solid = savesolid;
tracetossfaketarget.movetype = targ.movetype;
_setmodel(tracetossfaketarget, targ.model); // no low precision
head.totalfrags_lastcheck = head.totalfrags;
}
-void bot_calculate_stepheightvec(void)
+void bot_calculate_stepheightvec()
{
stepheightvec = autocvar_sv_stepheight * '0 0 1';
jumpstepheightvec = stepheightvec +
void() havocbot_setupbot;
-void bot_calculate_stepheightvec(void);
+void bot_calculate_stepheightvec();
#endif
// Should it do a weapon combo?
float af, ct, combo_time, combo;
- af = ATTACK_FINISHED(self);
+ af = ATTACK_FINISHED(self, 0);
ct = autocvar_bot_ai_weapon_combo_threshold;
// Bots with no skill will be 4 times more slower than "godlike" bots when doing weapon combos
.entity tuba_note;
float bot_cmd_debug_assert_canfire()
{SELFPARAM();
- float f;
- f = bot_cmd.bot_cmd_parm_float;
+ float f = bot_cmd.bot_cmd_parm_float;
- if(self.weaponentity.state != WS_READY)
+ int slot = 0;
+ .entity weaponentity = weaponentities[slot];
+ if(self.(weaponentity).state != WS_READY)
{
if(f)
{
LOG_INFO("Bot ", self.netname, " using ", self.weaponname, " wants to fire, inhibited by weaponentity state\n");
}
}
- else if(ATTACK_FINISHED(self) > time)
+ else if(ATTACK_FINISHED(self, slot) > time)
{
if(f)
{
self.colormod = '8 0 8';
- LOG_INFO("Bot ", self.netname, " using ", self.weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(self) - time), " seconds left)\n");
+ LOG_INFO("Bot ", self.netname, " using ", self.weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(self, slot) - time), " seconds left)\n");
}
}
else if(self.tuba_note)
if(!f)
{
self.colormod = '8 8 0';
- LOG_INFO("Bot ", self.netname, " using ", self.weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(self) - time), " seconds left\n");
+ LOG_INFO("Bot ", self.netname, " using ", self.weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(self, slot) - time), " seconds left\n");
}
}
if(!self.bot_cmd_current)
{
- self.bot_cmd_current = spawn();
- self.bot_cmd_current.classname = "bot_cmd";
- self.bot_cmd_current.is_bot_cmd = 1;
+ self.bot_cmd_current = new(bot_cmd);
+ self.bot_cmd_current.is_bot_cmd = true;
}
bot_cmd = self.bot_cmd_current;
w = find(w, classname, "waypoint");
}
- w = spawn();
+ w = new(waypoint);
+ make_pure(w);
w.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
- w.classname = "waypoint";
w.wpflags = f;
setorigin(w, (m1 + m2) * 0.5);
setsize(w, m1 - w.origin, m2 - w.origin);
// shared with regular waypoint init, so this is not a cheat by itself
if(!self.personal)
{
- self.personal = spawn();
- self.personal.classname = "personal_wp";
+ self.personal = new(personal_wp);
}
self.personal.origin = self.origin;
self.personal.v_angle = self.v_angle;
effectnum = _particleeffectnum(argv(1));
W_SetupShot(self, false, false, "", CH_WEAPON_A, 0);
traceline(w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, MOVE_NORMAL, self);
- trailparticles(self, effectnum, w_shotorg, trace_endpos);
+ __trailparticles(self, effectnum, w_shotorg, trace_endpos);
DID_CHEAT();
break;
}
break;
case "dragbox_spawn": {
IS_CHEAT(0, argc, 0);
- entity e = spawn();
- e.classname = "dragbox_box";
+ entity e = new(dragbox_box);
e.think = DragBox_Think;
e.nextthink = time;
e.solid = -1; // black
else
e.cnt = max(0, drag_lastcnt);
- e.aiment = spawn();
- e.aiment.classname = "dragbox_corner_1";
+ e.aiment = new(dragbox_corner_1);
e.aiment.owner = e;
setmodel(e.aiment, MDL_MARKER);
e.aiment.skin = 0;
setorigin(e.aiment, trace_endpos);
}
- e.enemy = spawn();
- e.enemy.classname = "dragbox_corner_2";
+ e.enemy = new(dragbox_corner_2);
e.enemy.owner = e;
setmodel(e.enemy, MDL_MARKER);
e.enemy.skin = 1;
else
setorigin(e.enemy, e.aiment.origin + 32 * end);
- e.killindicator = spawn();
- e.killindicator.classname = "drag_digit";
+ e.killindicator = new(drag_digit);
e.killindicator.owner = e;
setattachment(e.killindicator, e, "");
setorigin(e.killindicator, '0 0 -8');
- e.killindicator.killindicator = spawn();
- e.killindicator.killindicator.classname = "drag_digit";
+ e.killindicator.killindicator = new(drag_digit);
e.killindicator.killindicator.owner = e;
setattachment(e.killindicator.killindicator, e, "");
setorigin(e.killindicator.killindicator, '0 0 8');
}
case "dragpoint_spawn": {
IS_CHEAT(0, argc, 0);
- entity e = spawn();
- e.classname = "dragpoint";
+ entity e = new(dragpoint);
e.think = DragBox_Think;
e.nextthink = time;
e.solid = 0; // nothing special
move_out_of_solid(e);
}
- e.killindicator = spawn();
- e.killindicator.classname = "drag_digit";
+ e.killindicator = new(drag_digit);
e.killindicator.owner = e;
setattachment(e.killindicator, e, "");
setorigin(e.killindicator, '0 0 40');
- e.killindicator.killindicator = spawn();
- e.killindicator.killindicator.classname = "drag_digit";
+ e.killindicator.killindicator = new(drag_digit);
e.killindicator.killindicator.owner = e;
setattachment(e.killindicator.killindicator, e, "");
setorigin(e.killindicator.killindicator, '0 0 56');
break;
case "teleporttotarget":
IS_CHEAT(0, argc, 0);
- setself(spawn());
+ setself(new(cheattriggerteleport));
setorigin(self, self.origin);
- self.classname = "cheattriggerteleport";
self.target = argv(1);
teleport_findtarget();
if(!wasfreed(self))
draggee.ltime = max(servertime + serverframetime, draggee.ltime); // fixes func_train breakage
vector vecs = '0 0 0';
- if(dragger.weaponentity.movedir_x > 0)
- vecs = dragger.weaponentity.movedir;
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+ if(dragger.(weaponentity).movedir.x > 0)
+ vecs = dragger.(weaponentity).movedir;
vector dv = v_right * -vecs_y + v_up * vecs_z;
void send_CSQC_teamnagger() {
- WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
+ WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
}
bool ClientData_Send(entity this, entity to, int sf)
if(e.porto_v_angle_held)
sf |= 8; // angles held
- WriteByte(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
WriteByte(MSG_ENTITY, sf);
if(sf & 2)
void ClientData_Attach()
{SELFPARAM();
- Net_LinkEntity(self.clientdata = spawn(), false, 0, ClientData_Send);
- self.clientdata.drawonlytoclient = self;
- self.clientdata.owner = self;
+ Net_LinkEntity(this.clientdata = new(clientdata), false, 0, ClientData_Send);
+ make_pure(this.clientdata);
+ self.clientdata.drawonlytoclient = this;
+ self.clientdata.owner = this;
}
void ClientData_Detach()
precache_model(modelname);
_setmodel(e, modelname);
player_setupanimsformodel();
- UpdatePlayerSounds();
+ UpdatePlayerSounds(e);
}
/*
self.weaponname = "";
self.switchingweapon = 0;
self.weaponmodel = "";
- self.weaponentity = world;
+ for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ self.weaponentities[slot] = NULL;
+ }
self.exteriorweaponentity = world;
self.killcount = FRAGS_SPECTATOR;
self.velocity = '0 0 0';
self.event_damage = func_null;
}
+int player_getspecies(entity this)
+{
+ get_model_parameters(this.model, this.skin);
+ int s = get_model_parameters_species;
+ get_model_parameters(string_null, 0);
+ if (s < 0) return SPECIES_HUMAN;
+ return s;
+}
+
.float model_randomizer;
void FixPlayermodel(entity player)
{
if(chmdl || oldskin != player.skin) // model or skin has changed
{
- player.species = player_getspecies(); // update species
- UpdatePlayerSounds(); // update skin sounds
+ player.species = player_getspecies(player); // update species
+ UpdatePlayerSounds(player); // update skin sounds
}
if(!teamplay)
this.revival_time = 0;
this.air_finished = time + 12;
- entity spawnevent = spawn();
+ entity spawnevent = new(spawnevent);
+ make_pure(spawnevent);
spawnevent.owner = this;
Net_LinkEntity(spawnevent, false, 0.5, SpawnEvent_Send);
this.killcount = 0;
}
- CL_SpawnWeaponentity(this);
+ for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ CL_SpawnWeaponentity(this, weaponentities[slot]);
+ }
this.alpha = default_player_alpha;
this.colormod = '1 1 1' * autocvar_g_player_brightness;
this.exteriorweaponentity.alpha = default_weapon_alpha;
// changes and just have a console command to update this?
bool ClientInit_SendEntity(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_INIT);
- WriteByte(MSG_ENTITY, g_nexball_meter_period * 32);
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[0]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[1]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[2]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[3]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[0]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[1]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[2]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[3]));
+ WriteHeader(MSG_ENTITY, _ENT_CLIENT_INIT);
+ return = true;
+ msg_entity = to;
+ Registry_send_all();
+ int channel = MSG_ONE;
+ WriteHeader(channel, ENT_CLIENT_INIT);
+ WriteByte(channel, g_nexball_meter_period * 32);
+ WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[0]));
+ WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[1]));
+ WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[2]));
+ WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[3]));
+ WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[0]));
+ WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[1]));
+ WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[2]));
+ WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[3]));
if(sv_foginterval && world.fog != "")
- WriteString(MSG_ENTITY, world.fog);
+ WriteString(channel, world.fog);
else
- WriteString(MSG_ENTITY, "");
- WriteByte(MSG_ENTITY, self.count * 255.0); // g_balance_armor_blockpercent
- WriteCoord(MSG_ENTITY, self.bouncefactor); // g_balance_mortar_bouncefactor // WEAPONTODO
- WriteCoord(MSG_ENTITY, self.bouncestop); // g_balance_mortar_bouncestop
- WriteCoord(MSG_ENTITY, self.ebouncefactor); // g_balance_mortar_bouncefactor
- WriteCoord(MSG_ENTITY, self.ebouncestop); // g_balance_mortar_bouncestop
- WriteByte(MSG_ENTITY, WEP_CVAR(vortex, secondary)); // client has to know if it should zoom or not // WEAPONTODO
- WriteByte(MSG_ENTITY, WEP_CVAR(rifle, secondary)); // client has to know if it should zoom or not // WEAPONTODO
- WriteByte(MSG_ENTITY, serverflags); // client has to know if it should zoom or not
- WriteByte(MSG_ENTITY, WEP_CVAR(minelayer, limit)); // minelayer max mines // WEAPONTODO
- WriteByte(MSG_ENTITY, WEP_CVAR_SEC(hagar, load_max)); // hagar max loadable rockets // WEAPONTODO
- WriteCoord(MSG_ENTITY, autocvar_g_trueaim_minrange);
- WriteByte(MSG_ENTITY, WEP_CVAR(porto, secondary)); // WEAPONTODO
- return true;
+ WriteString(channel, "");
+ WriteByte(channel, self.count * 255.0); // g_balance_armor_blockpercent
+ WriteCoord(channel, self.bouncefactor); // g_balance_mortar_bouncefactor // WEAPONTODO
+ WriteCoord(channel, self.bouncestop); // g_balance_mortar_bouncestop
+ WriteCoord(channel, self.ebouncefactor); // g_balance_mortar_bouncefactor
+ WriteCoord(channel, self.ebouncestop); // g_balance_mortar_bouncestop
+ WriteByte(channel, WEP_CVAR(vortex, secondary)); // client has to know if it should zoom or not // WEAPONTODO
+ WriteByte(channel, WEP_CVAR(rifle, secondary)); // client has to know if it should zoom or not // WEAPONTODO
+ WriteByte(channel, serverflags); // client has to know if it should zoom or not
+ WriteByte(channel, WEP_CVAR(minelayer, limit)); // minelayer max mines // WEAPONTODO
+ WriteByte(channel, WEP_CVAR_SEC(hagar, load_max)); // hagar max loadable rockets // WEAPONTODO
+ WriteCoord(channel, autocvar_g_trueaim_minrange);
+ WriteByte(channel, WEP_CVAR(porto, secondary)); // WEAPONTODO
+
+ MUTATOR_CALLHOOK(Ent_Init);
}
void ClientInit_CheckUpdate()
void ClientInit_Spawn()
{SELFPARAM();
- entity e = spawn();
- e.classname = "clientinit";
+
+ entity e = new(clientinit);
+ make_pure(e);
e.think = ClientInit_CheckUpdate;
Net_LinkEntity(e, false, 0, ClientInit_SendEntity);
SetNewParms
=============
*/
-void SetNewParms (void)
+void SetNewParms ()
{
// initialize parms for a new player
parm1 = -(86400 * 366);
SetChangeParms
=============
*/
-void SetChangeParms (void)
+void SetChangeParms ()
{SELFPARAM();
// save parms for level change
parm1 = self.parm_idlesince - time;
DecodeLevelParms
=============
*/
-void DecodeLevelParms (void)
+void DecodeLevelParms ()
{SELFPARAM();
// load parms
self.parm_idlesince = parm1;
}
-void ClientKill (void)
+void ClientKill ()
{SELFPARAM();
if(gameover) return;
if(self.player_blocked) return;
Called once (not at each match start) when a client begins a connection to the server
=============
*/
-void ClientPreConnect (void)
+void ClientPreConnect ()
{SELFPARAM();
if(autocvar_sv_eventlog)
{
Called when a client connects to the server
=============
*/
-void DecodeLevelParms (void);
-void ClientConnect (void)
+void DecodeLevelParms ();
+void ClientConnect ()
{SELFPARAM();
float t;
*/
.entity chatbubbleentity;
void ReadyCount();
-void ClientDisconnect (void)
+void ClientDisconnect ()
{SELFPARAM();
if(self.vehicle)
vehicles_exit(VHEF_RELEASE);
if(self.weaponorder_byimpulse)
strunzone(self.weaponorder_byimpulse);
- ClearPlayerSounds();
+ ClearPlayerSounds(self);
if(self.personal)
remove(self.personal);
// spawn a chatbubble entity if needed
if (!self.chatbubbleentity)
{
- self.chatbubbleentity = spawn();
+ self.chatbubbleentity = new(chatbubbleentity);
self.chatbubbleentity.owner = self;
self.chatbubbleentity.exteriormodeltoclient = self;
self.chatbubbleentity.think = ChatBubbleThink;
else self.colormod = '1 1 1';
}*/
-void respawn(void)
+void respawn()
{SELFPARAM();
if(self.alpha >= 0 && autocvar_g_respawn_ghosts)
{
_sound (self, CH_INFO, samp, VOL_BASE, ATTEN_NORM);
}
-void player_powerups (void)
+void player_powerups ()
{SELFPARAM();
// add a way to see what the items were BEFORE all of these checks for the mutator hook
int items_prev = self.items;
return current;
}
-void player_regen (void)
+void player_regen ()
{SELFPARAM();
float max_mod, regen_mod, rot_mod, limit_mod;
max_mod = regen_mod = rot_mod = limit_mod = 1;
}
void GetPressedKeys()
-{SELFPARAM();
+{
+ SELFPARAM();
MUTATOR_CALLHOOK(GetPressedKeys);
- #define X(var,bit,flag) (flag ? var |= bit : var &= ~bit)
- X(self.pressedkeys, KEY_FORWARD, self.movement_x > 0);
- X(self.pressedkeys, KEY_BACKWARD, self.movement_x < 0);
- X(self.pressedkeys, KEY_RIGHT, self.movement_y > 0);
- X(self.pressedkeys, KEY_LEFT, self.movement_y < 0);
-
- X(self.pressedkeys, KEY_JUMP, PHYS_INPUT_BUTTON_JUMP(self));
- X(self.pressedkeys, KEY_CROUCH, PHYS_INPUT_BUTTON_CROUCH(self));
- X(self.pressedkeys, KEY_ATCK, PHYS_INPUT_BUTTON_ATCK(self));
- X(self.pressedkeys, KEY_ATCK2, PHYS_INPUT_BUTTON_ATCK2(self));
- #undef X
+ int keys = this.pressedkeys;
+ keys = BITSET(keys, KEY_FORWARD, this.movement.x > 0);
+ keys = BITSET(keys, KEY_BACKWARD, this.movement.x < 0);
+ keys = BITSET(keys, KEY_RIGHT, this.movement.y > 0);
+ keys = BITSET(keys, KEY_LEFT, this.movement.y < 0);
+
+ keys = BITSET(keys, KEY_JUMP, PHYS_INPUT_BUTTON_JUMP(this));
+ keys = BITSET(keys, KEY_CROUCH, PHYS_INPUT_BUTTON_CROUCH(this));
+ keys = BITSET(keys, KEY_ATCK, PHYS_INPUT_BUTTON_ATCK(this));
+ keys = BITSET(keys, KEY_ATCK2, PHYS_INPUT_BUTTON_ATCK2(this));
+ this.pressedkeys = keys;
}
/*
{SELFPARAM();
other = find(self.enemy, classname, "player");
- bool mutator_returnvalue = MUTATOR_CALLHOOK(SpectateNext, self, other);
- other = spec_player;
-
- if(!mutator_returnvalue && !other)
+ if (MUTATOR_CALLHOOK(SpectateNext, self, other))
+ other = spec_player;
+ else if (!other)
other = find(other, classname, "player");
if(other) { SetSpectatee(self, other); }
while(other && other != self.enemy)
other = other.chain;
- int mutator_returnvalue = MUTATOR_CALLHOOK(SpectatePrev, self, other, first);
- other = spec_player;
-
- switch(mutator_returnvalue)
+ switch (MUTATOR_CALLHOOK(SpectatePrev, self, other, first))
{
- case MUT_SPECPREV_FOUND: break;
- case MUT_SPECPREV_RETURN: return true;
+ case MUT_SPECPREV_FOUND:
+ other = spec_player;
+ break;
+ case MUT_SPECPREV_RETURN:
+ other = spec_player;
+ return true;
case MUT_SPECPREV_CONTINUE:
default:
{
if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
{
self.classname = STR_PLAYER;
- nades_RemoveBonus(self);
if(autocvar_g_campaign || autocvar_g_balance_teams)
{ JoinBestTeam(self, false, true); }
{
if(self.BUTTON_INFO) // BUTTON_INFO hides initial MOTD
self.motd_actived_time = -2; // wait until BUTTON_INFO gets released
- else if(self.motd_actived_time == -2 || IS_PLAYER(self))
+ else if(self.motd_actived_time == -2 || IS_PLAYER(self) || IS_SPEC(self))
{
// instanctly hide MOTD
self.motd_actived_time = 0;
MUTATOR_CALLHOOK(PlayerUseKey);
}
-float isInvisibleString(string s)
-{
- float i, n, c;
- s = strdecolorize(s);
- for((i = 0), (n = strlen(s)); i < n; ++i)
- {
- c = str2chr(s, i);
- switch(c)
- {
- case 0:
- case 32: // space
- break;
- case 192: // charmap space
- if (!autocvar_utf8_enable)
- break;
- return false;
- case 160: // space in unicode fonts
- case 0xE000 + 192: // utf8 charmap space
- if (autocvar_utf8_enable)
- break;
- default:
- return false;
- }
- }
- return true;
-}
/*
=============
void() nexball_setstatus;
.float last_vehiclecheck;
.int items_added;
-void PlayerPreThink (void)
+void PlayerPreThink ()
{SELFPARAM();
WarpZone_PlayerPhysics_FixVAngle();
// WEAPONTODO: THIS SHIT NEEDS TO GO EVENTUALLY
// It cannot be predicted by the engine!
- if((self.weapon == WEP_SHOCKWAVE.m_id || self.weapon == WEP_SHOTGUN.m_id) && self.weaponentity.wframe == WFRAME_FIRE2 && time < self.weapon_nextthink)
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+ if((self.weapon == WEP_SHOCKWAVE.m_id || self.weapon == WEP_SHOTGUN.m_id) && self.(weaponentity).wframe == WFRAME_FIRE2 && time < self.(weaponentity).weapon_nextthink)
do_crouch = 0;
if (do_crouch)
=============
*/
.float idlekick_lasttimeleft;
-void PlayerPostThink (void)
+void PlayerPostThink ()
{SELFPARAM();
if(sv_maxidle > 0 && frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
if(IS_REAL_CLIENT(self))
* 230 to 253: individual weapons (up to 24)
*/
-void ImpulseCommands (void)
+void ImpulseCommands ()
{SELFPARAM();
int imp;
vector org;
break;
}
}
- else
- self.impulse = imp; // retry in next frame
+ //else
+ //self.impulse = imp; // retry in next frame
}
else if(imp == 21)
{
m = (imp - (210 + i)); // <0 for prev, =0 for best, >0 for next
W_CycleWeapon(self.(cvar_cl_weaponpriorities[i]), m);
}
- else
- self.impulse = imp; // retry in next frame
+ //else
+ //self.impulse = imp; // retry in next frame
}
else if(imp >= WEP_IMPULSE_BEGIN && imp <= WEP_IMPULSE_END)
{
if(!self.vehicle)
if(self.deadflag == DEAD_NO)
W_SwitchWeapon (imp - WEP_IMPULSE_BEGIN + WEP_FIRST);
- else
- self.impulse = imp; // retry in next frame
+ //else
+ //self.impulse = imp; // retry in next frame
}
// deploy waypoints
else if (imp >= 30 && imp <= 49)
* 230 to 253: individual weapons (up to 24)
*/
-void ImpulseCommands (void);
+void ImpulseCommands ();
#endif
#include "cheats.qh"
#include "g_damage.qh"
#include "g_subs.qh"
-#include "g_violence.qh"
#include "miscfunctions.qh"
#include "portals.qh"
#include "teamplay.qh"
MUTATOR_CALLHOOK(DropSpecialItems, player);
}
-void CopyBody_Think(void)
+void CopyBody_Think()
{SELFPARAM();
if(self.CopyBody_nextthink && time > self.CopyBody_nextthink)
{
{SELFPARAM();
if (self.effects & EF_NODRAW)
return;
- setself(spawn());
+ setself(new(body));
self.enemy = this;
self.lip = this.lip;
self.colormap = this.colormap;
self.angles = this.angles;
self.v_angle = this.v_angle;
self.avelocity = this.avelocity;
- self.classname = "body";
self.damageforcescale = this.damageforcescale;
self.effects = this.effects;
self.glowmod = this.glowmod;
setself(this);
}
-float player_getspecies()
-{SELFPARAM();
- float s;
- get_model_parameters(self.model, self.skin);
- s = get_model_parameters_species;
- get_model_parameters(string_null, 0);
- if(s < 0)
- return SPECIES_HUMAN;
- return s;
-}
-
void player_setupanimsformodel()
{SELFPARAM();
// load animation info
animdecide_setstate(self, 0, false);
}
-void player_anim (void)
+void player_anim ()
{SELFPARAM();
int deadbits = (self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
if(self.deadflag) {
animdecide_setstate(self, animbits, false);
animdecide_setimplicitstate(self, (self.flags & FL_ONGROUND));
- if (self.weaponentity)
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
{
- updateanim(self.weaponentity);
- if (!self.weaponentity.animstate_override)
- setanim(self.weaponentity, self.weaponentity.anim_idle, true, false, false);
+ if (self.(weaponentity))
+ {
+ updateanim(self.(weaponentity));
+ if (!self.(weaponentity).animstate_override)
+ setanim(self.(weaponentity), self.(weaponentity).anim_idle, true, false, false);
+ }
}
}
self.dmg_take = self.dmg_take + take;//max(take - 10, 0);
self.dmg_inflictor = inflictor;
- float abot, vbot;
- abot = (IS_BOT_CLIENT(attacker));
- vbot = (IS_BOT_CLIENT(self));
+ if (self != attacker) {
+ float realdmg = damage - excess;
+ if (IS_PLAYER(attacker)) {
+ PlayerScore_Add(attacker, SP_DMG, realdmg);
+ }
+ if (IS_PLAYER(self)) {
+ PlayerScore_Add(self, SP_DMGTAKEN, realdmg);
+ }
+ }
+
+ bool abot = (IS_BOT_CLIENT(attacker));
+ bool vbot = (IS_BOT_CLIENT(self));
valid_damage_for_weaponstats = 0;
Weapon awep = WEP_Null;
{
Weapon w = get_weaponinfo(j);
w.wr_resetplayer(w);
- ATTACK_FINISHED_FOR(self, j) = 0;
+ for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ ATTACK_FINISHED_FOR(self, j, slot) = 0;
+ }
}
}
}
-float Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol)
-// message "": do not say, just test flood control
-// return value:
-// 1 = accept
-// 0 = reject
-// -1 = fake accept
+void MoveToTeam(entity client, int team_colour, int type)
+{
+ int lockteams_backup = lockteams; // backup any team lock
+ lockteams = 0; // disable locked teams
+ TeamchangeFrags(client); // move the players frags
+ SetPlayerColors(client, team_colour - 1); // set the players colour
+ Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, client.origin, '0 0 0'); // kill the player
+ lockteams = lockteams_backup; // restore the team lock
+ LogTeamchange(client.playerid, client.team, type);
+}
+
+/**
+ * message "": do not say, just test flood control
+ * return value:
+ * 1 = accept
+ * 0 = reject
+ * -1 = fake accept
+ */
+int Say(entity source, float teamsay, entity privatesay, string msgin, bool floodcontrol)
{
string msgstr, colorstr, cmsgstr, namestr, fullmsgstr, sourcemsgstr, fullcmsgstr, sourcecmsgstr, colorprefix;
float flood;
return ret;
}
-float GetVoiceMessageVoiceType(string type)
+int GetVoiceMessageVoiceType(string type)
{
- if(type == "taunt")
- return VOICETYPE_TAUNT;
- if(type == "teamshoot")
- return VOICETYPE_LASTATTACKER;
+ if (type == "taunt") return VOICETYPE_TAUNT;
+ if (type == "teamshoot") return VOICETYPE_LASTATTACKER;
return VOICETYPE_TEAMRADIO;
}
.string GetVoiceMessageSampleField(string type)
{
- GetPlayerSoundSampleField_notFound = 0;
- switch(type)
+ GetPlayerSoundSampleField_notFound = false;
+ switch (type)
{
-#define _VOICEMSG(m) case #m: return playersound_##m;
- ALLVOICEMSGS
-#undef _VOICEMSG
+#define X(m) case #m: return playersound_##m;
+ ALLVOICEMSGS(X)
+#undef X
}
- GetPlayerSoundSampleField_notFound = 1;
+ GetPlayerSoundSampleField_notFound = true;
return playersound_taunt;
}
.string GetPlayerSoundSampleField(string type)
{
- GetPlayerSoundSampleField_notFound = 0;
- switch(type)
+ GetPlayerSoundSampleField_notFound = false;
+ switch (type)
{
-#define _VOICEMSG(m) case #m: return playersound_##m;
- ALLPLAYERSOUNDS
-#undef _VOICEMSG
+#define X(m) case #m: return playersound_##m;
+ ALLPLAYERSOUNDS(X)
+#undef X
}
- GetPlayerSoundSampleField_notFound = 1;
+ GetPlayerSoundSampleField_notFound = true;
return playersound_taunt;
}
-void PrecacheGlobalSound(string samplestring)
+void PrecacheGlobalSound(string sample)
{
- float n, i;
- tokenize_console(samplestring);
- n = stof(argv(1));
- if(n > 0)
+ int n;
{
- for(i = 1; i <= n; ++i)
- precache_sound(strcat(argv(0), ftos(i), ".wav"));
+ string s = cdr(sample);
+ if (s) n = stof(s);
+ else n = 0;
+ }
+ sample = car(sample);
+ if (n > 0)
+ {
+ for (int i = 1; i <= n; ++i)
+ precache_sound(sprintf("%s%d.wav", sample, i));
}
else
{
- precache_sound(strcat(argv(0), ".wav"));
+ precache_sound(sprintf("%s.wav", sample));
}
}
+string allvoicesamples;
+
void PrecachePlayerSounds(string f)
{
int fh = fopen(f, FILE_READ);
if (fh < 0)
+ {
+ LOG_WARNINGF("Player sound file not found: %s\n", f);
return;
+ }
for (string s; (s = fgets(fh)); )
{
int n = tokenize_console(s);
if (n != 3)
{
- if (n != 0) LOG_TRACEF("Invalid sound info line: %s\n", s);
+ if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s);
continue;
}
- PrecacheGlobalSound(strcat(argv(1), " ", argv(2)));
+ string file = argv(1);
+ string variants = argv(2);
+ PrecacheGlobalSound(strcat(file, " ", variants));
}
fclose(fh);
if (!allvoicesamples)
{
-#define _VOICEMSG(m) allvoicesamples = strcat(allvoicesamples, " ", #m);
- ALLVOICEMSGS
-#undef _VOICEMSG
- allvoicesamples = strzone(substring(allvoicesamples, 1, strlen(allvoicesamples) - 1));
+#define X(m) allvoicesamples = strcat(allvoicesamples, " ", #m);
+ ALLVOICEMSGS(X)
+#undef X
+ allvoicesamples = strzone(substring(allvoicesamples, 1, -1));
}
}
-void ClearPlayerSounds()
-{SELFPARAM();
-#define _VOICEMSG(m) if(self.playersound_##m) { strunzone(self.playersound_##m); self.playersound_##m = string_null; }
- ALLPLAYERSOUNDS
- ALLVOICEMSGS
-#undef _VOICEMSG
+void ClearPlayerSounds(entity this)
+{
+#define X(m) if (this.playersound_##m) { strunzone(this.playersound_##m); this.playersound_##m = string_null; }
+ ALLPLAYERSOUNDS(X)
+ ALLVOICEMSGS(X)
+#undef X
}
-float LoadPlayerSounds(string f, float first)
-{SELFPARAM();
- float fh;
- string s;
- var .string field;
- fh = fopen(f, FILE_READ);
- if(fh < 0)
+bool LoadPlayerSounds(string f, bool strict)
+{
+ SELFPARAM();
+ int fh = fopen(f, FILE_READ);
+ if (fh < 0)
{
- LOG_TRACE("Player sound file not found: ", f, "\n");
- return 0;
+ if (strict) LOG_WARNINGF("Player sound file not found: %s\n", f);
+ return false;
}
- while((s = fgets(fh)))
+ for (string s; (s = fgets(fh)); )
{
- if(tokenize_console(s) != 3)
+ int n = tokenize_console(s);
+ if (n != 3)
+ {
+ if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s);
continue;
- field = GetPlayerSoundSampleField(argv(0));
- if(GetPlayerSoundSampleField_notFound)
- field = GetVoiceMessageSampleField(argv(0));
- if(GetPlayerSoundSampleField_notFound)
+ }
+ string key = argv(0);
+ var .string field = GetPlayerSoundSampleField(key);
+ if (GetPlayerSoundSampleField_notFound) field = GetVoiceMessageSampleField(key);
+ if (GetPlayerSoundSampleField_notFound)
+ {
+ LOG_TRACEF("Invalid sound info field: %s\n", key);
continue;
- if (self.(field))
- strunzone(self.(field));
- self.(field) = strzone(strcat(argv(1), " ", argv(2)));
+ }
+ string file = argv(1);
+ string variants = argv(2);
+ if (self.(field)) strunzone(self.(field));
+ self.(field) = strzone(strcat(file, " ", variants));
}
fclose(fh);
- return 1;
-}
-
-void UpdatePlayerSounds()
-{SELFPARAM();
- if(self.modelindex == self.modelindex_for_playersound)
- if(self.skin == self.skin_for_playersound)
- return;
- self.modelindex_for_playersound = self.modelindex;
- self.skin_for_playersound = self.skin;
- ClearPlayerSounds();
- LoadPlayerSounds("sound/player/default.sounds", 1);
- if(!autocvar_g_debug_defaultsounds)
- if(!LoadPlayerSounds(get_model_datafilename(self.model, self.skin, "sounds"), 0))
- LoadPlayerSounds(get_model_datafilename(self.model, 0, "sounds"), 0);
+ return true;
}
-void FakeGlobalSound(string sample, float chan, float voicetype)
-{SELFPARAM();
- float n;
- float tauntrand;
-
- if(sample == "")
- return;
+.int modelindex_for_playersound;
+.int skin_for_playersound;
- tokenize_console(sample);
- n = stof(argv(1));
- if(n > 0)
- sample = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
- else
- sample = strcat(argv(0), ".wav"); // randomization
+void UpdatePlayerSounds(entity this)
+{
+ if (this.modelindex == this.modelindex_for_playersound && this.skin == this.skin_for_playersound) return;
+ this.modelindex_for_playersound = this.modelindex;
+ this.skin_for_playersound = this.skin;
+ ClearPlayerSounds(this);
+ LoadPlayerSounds("sound/player/default.sounds", true);
+ if (autocvar_g_debug_defaultsounds) return;
+ if (!LoadPlayerSounds(get_model_datafilename(this.model, this.skin, "sounds"), false))
+ LoadPlayerSounds(get_model_datafilename(this.model, 0, "sounds"), true);
+}
- switch(voicetype)
+void _GlobalSound(string sample, int chan, int voicetype, bool fake)
+{
+ SELFPARAM();
+ if (sample == "") return;
+ int n;
+ {
+ string s = cdr(sample);
+ if (s) n = stof(s);
+ else n = 0;
+ }
+ sample = car(sample);
+ if (n > 0) sample = sprintf("%s%d.wav", sample, floor(random() * n + 1)); // randomization
+ else sample = sprintf("%s.wav", sample);
+ switch (voicetype)
{
case VOICETYPE_LASTATTACKER_ONLY:
- break;
case VOICETYPE_LASTATTACKER:
- if(self.pusher)
+ {
+ if (!fake)
{
- msg_entity = self;
- if(IS_REAL_CLIENT(msg_entity))
- soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTEN_NONE);
+ if (!this.pusher) break;
+ msg_entity = this.pusher;
+ if (IS_REAL_CLIENT(msg_entity))
+ {
+ float atten = (msg_entity.cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE;
+ soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten);
+ }
}
+ if (voicetype == VOICETYPE_LASTATTACKER_ONLY) break;
+ msg_entity = this;
+ if (IS_REAL_CLIENT(msg_entity)) soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NONE);
break;
+ }
case VOICETYPE_TEAMRADIO:
- msg_entity = self;
- if(msg_entity.cvar_cl_voice_directional == 1)
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_MIN);
+ {
+ #define X() \
+ do \
+ { \
+ float atten = (msg_entity.cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE; \
+ soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \
+ } \
+ while (0)
+
+ if (fake) { msg_entity = this; X(); }
else
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
- break;
- case VOICETYPE_AUTOTAUNT:
- if(!sv_autotaunt)
- break;
- if(!sv_taunt)
- break;
- if(autocvar_sv_gentle)
- break;
- tauntrand = random();
- msg_entity = self;
- if (tauntrand < msg_entity.cvar_cl_autotaunt)
{
- if (msg_entity.cvar_cl_voice_directional >= 1)
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX));
- else
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
+ FOR_EACH_REALCLIENT(msg_entity)
+ {
+ if (!teamplay || msg_entity.team == this.team) X();
+ }
}
+ #undef X
break;
+ }
+ case VOICETYPE_AUTOTAUNT:
case VOICETYPE_TAUNT:
- if(IS_PLAYER(self))
- if(self.deadflag == DEAD_NO)
- animdecide_setaction(self, ANIMACTION_TAUNT, true);
- if(!sv_taunt)
- break;
- if(autocvar_sv_gentle)
- break;
- msg_entity = self;
- if (msg_entity.cvar_cl_voice_directional >= 1)
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX));
+ {
+ if (voicetype == VOICETYPE_AUTOTAUNT) if (!sv_autotaunt) { break; }else {}
+ else if (IS_PLAYER(this) && this.deadflag == DEAD_NO) animdecide_setaction(this, ANIMACTION_TAUNT, true);
+ if (!sv_taunt) break;
+ if (autocvar_sv_gentle) break;
+ float tauntrand = 0;
+ if (voicetype == VOICETYPE_AUTOTAUNT) tauntrand = random();
+ #define X() \
+ do \
+ { \
+ if (voicetype != VOICETYPE_AUTOTAUNT || tauntrand < msg_entity.cvar_cl_autotaunt) \
+ { \
+ float atten = (msg_entity.cvar_cl_voice_directional >= 1) \
+ ? bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX) \
+ : ATTEN_NONE; \
+ soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \
+ } \
+ } \
+ while (0)
+ if (fake)
+ {
+ msg_entity = this;
+ X();
+ }
else
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
- break;
- case VOICETYPE_PLAYERSOUND:
- msg_entity = self;
- soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTEN_NORM);
- break;
- default:
- backtrace("Invalid voice type!");
- break;
- }
-}
-
-void GlobalSound(string sample, float chan, float voicetype)
-{SELFPARAM();
- float n;
- float tauntrand;
-
- if(sample == "")
- return;
-
- tokenize_console(sample);
- n = stof(argv(1));
- if(n > 0)
- sample = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
- else
- sample = strcat(argv(0), ".wav"); // randomization
-
- switch(voicetype)
- {
- case VOICETYPE_LASTATTACKER_ONLY:
- if(self.pusher)
{
- msg_entity = self.pusher;
- if(IS_REAL_CLIENT(msg_entity))
+ FOR_EACH_REALCLIENT(msg_entity)
{
- if(msg_entity.cvar_cl_voice_directional == 1)
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_MIN);
- else
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
+ X();
}
}
+ #undef X
break;
- case VOICETYPE_LASTATTACKER:
- if(self.pusher)
+ }
+ case VOICETYPE_PLAYERSOUND:
+ {
+ if (fake)
{
- msg_entity = self.pusher;
- if(IS_REAL_CLIENT(msg_entity))
- {
- if(msg_entity.cvar_cl_voice_directional == 1)
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_MIN);
- else
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
- }
- msg_entity = self;
- if(IS_REAL_CLIENT(msg_entity))
- soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTEN_NONE);
+ msg_entity = this;
+ soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NORM);
}
- break;
- case VOICETYPE_TEAMRADIO:
- FOR_EACH_REALCLIENT(msg_entity)
- if(!teamplay || msg_entity.team == self.team)
- {
- if(msg_entity.cvar_cl_voice_directional == 1)
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_MIN);
- else
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
- }
- break;
- case VOICETYPE_AUTOTAUNT:
- if(!sv_autotaunt)
- break;
- if(!sv_taunt)
- break;
- if(autocvar_sv_gentle)
- break;
- tauntrand = random();
- FOR_EACH_REALCLIENT(msg_entity)
- if (tauntrand < msg_entity.cvar_cl_autotaunt)
- {
- if (msg_entity.cvar_cl_voice_directional >= 1)
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX));
- else
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
- }
- break;
- case VOICETYPE_TAUNT:
- if(IS_PLAYER(self))
- if(self.deadflag == DEAD_NO)
- animdecide_setaction(self, ANIMACTION_TAUNT, true);
- if(!sv_taunt)
- break;
- if(autocvar_sv_gentle)
- break;
- FOR_EACH_REALCLIENT(msg_entity)
+ else
{
- if (msg_entity.cvar_cl_voice_directional >= 1)
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX));
- else
- soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
+ _sound(this, chan, sample, VOL_BASE, ATTEN_NORM);
}
break;
- case VOICETYPE_PLAYERSOUND:
- _sound(self, chan, sample, VOL_BASE, ATTEN_NORM);
- break;
+ }
default:
+ {
backtrace("Invalid voice type!");
break;
+ }
}
}
-void PlayerSound(.string samplefield, float chan, float voicetype)
-{SELFPARAM();
- GlobalSound(self.(samplefield), chan, voicetype);
+void PlayerSound(.string samplefield, int chan, float voicetype)
+{
+ SELFPARAM();
+ _GlobalSound(this.(samplefield), chan, voicetype, false);
}
void VoiceMessage(string type, string msg)
-{SELFPARAM();
- float voicetype, ownteam;
- float flood;
+{
+ SELFPARAM();
var .string sample = GetVoiceMessageSampleField(type);
-
- if(GetPlayerSoundSampleField_notFound)
+ if (GetPlayerSoundSampleField_notFound)
{
- sprint(self, strcat("Invalid voice. Use one of: ", allvoicesamples, "\n"));
+ sprint(this, sprintf("Invalid voice. Use one of: %s\n", allvoicesamples));
return;
}
-
- voicetype = GetVoiceMessageVoiceType(type);
- ownteam = (voicetype == VOICETYPE_TEAMRADIO);
-
- flood = Say(self, ownteam, world, msg, 1);
-
- if (IS_SPEC(self) || IS_OBSERVER(self) || flood < 0)
- FakeGlobalSound(self.(sample), CH_VOICE, voicetype);
- else if (flood > 0)
- GlobalSound(self.(sample), CH_VOICE, voicetype);
-}
-
-void MoveToTeam(entity client, float team_colour, float type)
-{
- float lockteams_backup;
-
- lockteams_backup = lockteams; // backup any team lock
-
- lockteams = 0; // disable locked teams
-
- TeamchangeFrags(client); // move the players frags
- SetPlayerColors(client, team_colour - 1); // set the players colour
- Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, client.origin, '0 0 0'); // kill the player
-
- lockteams = lockteams_backup; // restore the team lock
-
- LogTeamchange(client.playerid, client.team, type);
+ int voicetype = GetVoiceMessageVoiceType(type);
+ bool ownteam = (voicetype == VOICETYPE_TEAMRADIO);
+ int flood = Say(this, ownteam, world, msg, true);
+ bool fake;
+ if (IS_SPEC(this) || IS_OBSERVER(this) || flood < 0) fake = true;
+ else if (flood > 0) fake = false;
+ else return;
+ _GlobalSound(this.(sample), CH_VOICE, voicetype, fake);
}
.float istypefrag;
.float CopyBody_nextthink;
-.void(void) CopyBody_think;
-void CopyBody_Think(void);
+.void() CopyBody_think;
+void CopyBody_Think();
void CopyBody(float keepvelocity);
-float player_getspecies();
-
void player_setupanimsformodel();
-void player_anim (void);
+void player_anim();
-void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+void PlayerCorpseDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
// g_<gametype>_str:
// If 0, default is used.
// For consistency, negative values there are mapped to zero too.
#define GAMETYPE_DEFAULTED_SETTING(str) \
((gametype_setting_tmp = cvar(strcat("g_", GetGametype(), "_" #str))), \
- (gametype_setting_tmp < 0) ? 0 : \
- (gametype_setting_tmp == 0 || autocvar_g_respawn_delay_forced) ? max(0, autocvar_g_##str) : \
- gametype_setting_tmp)
-
+ (gametype_setting_tmp < 0) ? 0 \
+ : (gametype_setting_tmp == 0 || autocvar_g_respawn_delay_forced) ? max(0, autocvar_g_##str) \
+ : gametype_setting_tmp)
void calculate_player_respawn_time();
void ClientKill_Now_TeamChange();
-void PlayerDamage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
-
-.float muted; // to be used by prvm_edictset server playernumber muted 1
-float Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol);
-// message "": do not say, just test flood control
-// return value:
-// 1 = accept
-// 0 = reject
-// -1 = fake accept
+void MoveToTeam(entity client, float team_colour, float type);
+void PlayerDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+
+/** to be used by `prvm_edictset server playernumber muted 1` */
+.float muted;
+int Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol);
+
+// player sounds, voice messages
+// TODO implemented fall and falling
+#define ALLPLAYERSOUNDS(X) \
+ X(death) \
+ X(drown) \
+ X(fall) \
+ X(falling) \
+ X(gasp) \
+ X(jump) \
+ X(pain100) \
+ X(pain25) \
+ X(pain50) \
+ X(pain75)
+
+#define ALLVOICEMSGS(X) \
+ X(attack) \
+ X(attackinfive) \
+ X(coverme) \
+ X(defend) \
+ X(freelance) \
+ X(incoming) \
+ X(meet) \
+ X(needhelp) \
+ X(seenflag) \
+ X(taunt) \
+ X(teamshoot)
+
+// reserved sound names for the future (some models lack sounds for them):
+// _VOICEMSG(flagcarriertakingdamage)
+// _VOICEMSG(getflag)
+// reserved sound names for the future (ALL models lack sounds for them):
+// _VOICEMSG(affirmative)
+// _VOICEMSG(attacking)
+// _VOICEMSG(defending)
+// _VOICEMSG(roaming)
+// _VOICEMSG(onmyway)
+// _VOICEMSG(droppedflag)
+// _VOICEMSG(negative)
+// _VOICEMSG(seenenemy)
+
+#define X(m) .string playersound_##m;
+ALLPLAYERSOUNDS(X)
+ALLVOICEMSGS(X)
+#undef X
+
+bool GetPlayerSoundSampleField_notFound;
float GetVoiceMessageVoiceType(string type);
-
-string allvoicesamples;
.string GetVoiceMessageSampleField(string type);
-
.string GetPlayerSoundSampleField(string type);
-
void PrecacheGlobalSound(string samplestring);
-
void PrecachePlayerSounds(string f);
-
-void ClearPlayerSounds();
-
-float LoadPlayerSounds(string f, float first);
-
-.int modelindex_for_playersound;
-.int skin_for_playersound;
-void UpdatePlayerSounds();
-
-void FakeGlobalSound(string sample, float chan, float voicetype);
-
-void GlobalSound(string sample, float chan, float voicetype);
-
+void ClearPlayerSounds(entity this);
+float LoadPlayerSounds(string f, bool strict);
+void UpdatePlayerSounds(entity this);
+#define FakeGlobalSound(sample, chan, voicetype) _GlobalSound(sample, chan, voicetype, true)
+void _GlobalSound(string sample, float chan, float voicetype, bool fake);
+#define GlobalSound(def, chan, voicetype) _GlobalSound((def).m_globalsoundstr, chan, voicetype, false)
void PlayerSound(.string samplefield, float chan, float voicetype);
-
void VoiceMessage(string type, string msg);
-void MoveToTeam(entity client, float team_colour, float type);
+.string m_globalsoundstr;
+REGISTRY(GlobalSounds, BITS(8) - 1)
+#define GlobalSounds_from(i) _GlobalSounds_from(i, NULL)
+#define REGISTER_GLOBALSOUND(id, str) \
+ REGISTER(GlobalSounds, GS, id, m_id, new(GlobalSound)) \
+ { \
+ make_pure(this); \
+ this.m_globalsoundstr = str; \
+ }
+REGISTER_REGISTRY(GlobalSounds)
+REGISTRY_SORT(GlobalSounds, 0)
+REGISTRY_CHECK(GlobalSounds)
+PRECACHE(GlobalSounds)
+{
+ FOREACH(GlobalSounds, true, LAMBDA(PrecacheGlobalSound(it.m_globalsoundstr)));
+}
+
+REGISTER_GLOBALSOUND(STEP, "misc/footstep0 6")
+REGISTER_GLOBALSOUND(STEP_METAL, "misc/metalfootstep0 6")
+REGISTER_GLOBALSOUND(FALL, "misc/hitground 4")
+REGISTER_GLOBALSOUND(FALL_METAL, "misc/metalhitground 4")
+
#endif
void BanCommand_ban(float request, float argc, string command)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argc >= 2)
+ if (argc >= 2)
{
string ip = argv(1);
float reason_arg, bantime;
void BanCommand_banlist(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
void BanCommand_kickban(float request, float argc, string command)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argc >= 2)
+ if (argc >= 2)
{
entity client = GetIndexedEntity(argc, 1);
float accepted = VerifyKickableEntity(client);
float reason_arg, bantime, masksize;
string reason;
- if(accepted > 0)
+ if (accepted > 0)
{
reason_arg = next_token;
}
}
-void BanCommand_mute(float request, float argc, string command) // TODO: Add a sort of mute-"ban" which allows players to be muted based on IP/cryptokey
+void BanCommand_mute(float request, float argc, string command) // TODO: Add a sort of mute-"ban" which allows players to be muted based on IP/cryptokey
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argc >= 2)
+ if (argc >= 2)
{
entity client = GetFilteredEntity(argv(1));
float accepted = VerifyClientEntity(client, true, false);
- if(accepted > 0)
+ if (accepted > 0)
{
client.muted = true;
return;
void BanCommand_unban(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1))
+ if (argv(1))
{
float tmp_number = -1;
string tmp_string;
- if(substring(argv(1), 0, 1) == "#")
+ if (substring(argv(1), 0, 1) == "#")
{
tmp_string = substring(argv(1), 1, -1);
- if(tmp_string != "") // is it all one token? like #1
- {
+ if (tmp_string != "") // is it all one token? like #1
tmp_number = stof(tmp_string);
- }
- else if(argc > 2) // no, it's two tokens? # 1
- {
+ else if (argc > 2) // no, it's two tokens? # 1
tmp_number = stof(argv(2));
- }
- else
- tmp_number = -1;
+ else tmp_number = -1;
}
- else // maybe it's ONLY a number?
+ else // maybe it's ONLY a number?
{
tmp_number = stof(argv(1));
- if((tmp_number == 0) && (argv(1) != "0"))
- { tmp_number = -1; }
- }
+ if ((tmp_number == 0) && (argv(1) != "0")) tmp_number = -1; }
- if(tmp_number >= 0)
+ if (tmp_number >= 0)
{
Ban_Delete(tmp_number);
return;
void BanCommand_unmute(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argc >= 2)
+ if (argc >= 2)
{
entity client = GetFilteredEntity(argv(1));
float accepted = VerifyClientEntity(client, true, false);
- if(accepted > 0)
+ if (accepted > 0)
{
client.muted = false;
return;
** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
void BanCommand_(float request)
{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
-
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- print("\nUsage:^3 sv_cmd \n");
- print(" No arguments required.\n");
- return;
- }
- }
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ print("\nUsage:^3 sv_cmd \n");
+ print(" No arguments required.\n");
+ return;
+ }
+ }
}
*/
// ==================================
// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define BAN_COMMANDS(request,arguments,command) \
+#define BAN_COMMANDS(request, arguments, command) \
BAN_COMMAND("ban", BanCommand_ban(request, arguments, command), "Ban an IP address or a range of addresses (like 1.2.3)") \
BAN_COMMAND("banlist", BanCommand_banlist(request), "List all existing bans") \
BAN_COMMAND("kickban", BanCommand_kickban(request, arguments, command), "Disconnect a client and ban it at the same time") \
void BanCommand_macro_help()
{
- #define BAN_COMMAND(name,function,description) \
- { if(strtolower(description) != "") { LOG_INFO(" ^2", name, "^7: ", description, "\n"); } }
+ #define BAN_COMMAND(name, function, description) \
+ { if (strtolower(description) != "") { LOG_INFO(" ^2", name, "^7: ", description, "\n"); } }
BAN_COMMANDS(0, 0, "");
- #undef BAN_COMMAND
-
- return;
+#undef BAN_COMMAND
}
float BanCommand_macro_command(float argc, string command)
{
- #define BAN_COMMAND(name,function,description) \
- { if(name == strtolower(argv(0))) { function; return true; } }
+ #define BAN_COMMAND(name, function, description) \
+ { if (name == strtolower(argv(0))) { function; return true; } }
BAN_COMMANDS(CMD_REQUEST_COMMAND, argc, command);
- #undef BAN_COMMAND
+#undef BAN_COMMAND
return false;
}
float BanCommand_macro_usage(float argc)
{
- #define BAN_COMMAND(name,function,description) \
- { if(name == strtolower(argv(1))) { function; return true; } }
+ #define BAN_COMMAND(name, function, description) \
+ { if (name == strtolower(argv(1))) { function; return true; } }
BAN_COMMANDS(CMD_REQUEST_USAGE, argc, "");
- #undef BAN_COMMAND
+#undef BAN_COMMAND
return false;
}
void BanCommand_macro_write_aliases(float fh)
{
- #define BAN_COMMAND(name,function,description) \
- { if(strtolower(description) != "") { CMD_Write_Alias("qc_cmd_sv", name, description); } }
+ #define BAN_COMMAND(name, function, description) \
+ { if (strtolower(description) != "") { CMD_Write_Alias("qc_cmd_sv", name, description); } }
BAN_COMMANDS(0, 0, "");
- #undef BAN_COMMAND
-
- return;
+#undef BAN_COMMAND
}
float BanCommand(string command)
// argv: 0 - 1 - 2 - 3
// cmd vote - master - login - password
- if(BanCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
- {
- return true; // handled by one of the above GenericCommand_* functions
- }
+ if (BanCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+ return true; // handled by one of the above GenericCommand_* functions
return false;
}
// Last updated: December 29th, 2011
// =====================================
-#define GET_BAN_ARG(v,d) if(argc > reason_arg) { if((v = stof(argv(reason_arg))) != 0) ++reason_arg; else v = d; } else { v = d; }
-#define GET_BAN_REASON(v,d) if(argc > reason_arg) v = substring(command, argv_start_index(reason_arg), strlen(command) - argv_start_index(reason_arg)); else v = d;
+#define GET_BAN_ARG(v, d) if (argc > reason_arg) { if ((v = stof(argv(reason_arg))) != 0) ++reason_arg; else v = d; } else { v = d; }
+#define GET_BAN_REASON(v, d) if (argc > reason_arg) v = substring(command, argv_start_index(reason_arg), strlen(command) - argv_start_index(reason_arg)); else v = d;
void Ban_KickBanClient(entity client, float bantime, float masksize, string reason);
void Ban_View();
#include "../../lib/warpzone/common.qh"
-void ClientKill_TeamChange (float targetteam); // 0 = don't change, -1 = auto, -2 = spec
+void ClientKill_TeamChange(float targetteam); // 0 = don't change, -1 = auto, -2 = spec
// =========================================================
// Server side networked commands code, reworked by Samual
// =========================================================
float SV_ParseClientCommand_floodcheck()
-{SELFPARAM();
- if (!timeout_status) // not while paused
+{
+ SELFPARAM();
+ if (!timeout_status) // not while paused
{
- if(time <= (self.cmd_floodtime + autocvar_sv_clientcommand_antispam_time))
+ if (time <= (self.cmd_floodtime + autocvar_sv_clientcommand_antispam_time))
{
self.cmd_floodcount += 1;
- if(self.cmd_floodcount > autocvar_sv_clientcommand_antispam_count) { return false; } // too much spam, halt
+ if (self.cmd_floodcount > autocvar_sv_clientcommand_antispam_count) return false; // too much spam, halt
}
else
{
self.cmd_floodcount = 1;
}
}
- return true; // continue, as we're not flooding yet
+ return true; // continue, as we're not flooding yet
}
// =======================
void ClientCommand_autoswitch(float request, float argc)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1) != "")
+ if (argv(1) != "")
{
self.autoswitch = InterpretBoolean(argv(1));
sprint(self, strcat("^1autoswitch is currently turned ", (self.autoswitch ? "on" : "off"), ".\n"));
}
}
-void ClientCommand_clientversion(float request, float argc) // internal command, used only by code
-{SELFPARAM();
- switch(request)
+void ClientCommand_clientversion(float request, float argc) // internal command, used only by code
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1) != "")
+ if (argv(1) != "")
{
- if(IS_CLIENT(self))
+ if (IS_CLIENT(self))
{
self.version = ((argv(1) == "$gameversion") ? 1 : stof(argv(1)));
- if(self.version < autocvar_gameversion_min || self.version > autocvar_gameversion_max)
+ if (self.version < autocvar_gameversion_min || self.version > autocvar_gameversion_max)
{
self.version_mismatch = 1;
- ClientKill_TeamChange(-2); // observe
+ ClientKill_TeamChange(-2); // observe
}
- else if(autocvar_g_campaign || autocvar_g_balance_teams)
+ else if (autocvar_g_campaign || autocvar_g_balance_teams)
{
- //JoinBestTeam(self, false, true);
+ // JoinBestTeam(self, false, true);
}
- else if(teamplay && !autocvar_sv_spectate && !(self.team_forced > 0))
+ else if (teamplay && !autocvar_sv_spectate && !(self.team_forced > 0))
{
- self.classname = STR_OBSERVER; // really?
+ self.classname = STR_OBSERVER; // really?
stuffcmd(self, "menu_showteamselect\n");
}
}
}
}
-void ClientCommand_mv_getpicture(float request, float argc) // internal command, used only by code
-{SELFPARAM();
- switch(request)
+void ClientCommand_mv_getpicture(float request, float argc) // internal command, used only by code
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1) != "")
+ if (argv(1) != "")
{
- if(intermission_running)
- MapVote_SendPicture(stof(argv(1)));
+ if (intermission_running) MapVote_SendPicture(stof(argv(1)));
return;
}
}
void ClientCommand_join(float request)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(IS_CLIENT(self))
+ if (IS_CLIENT(self))
{
- if(!IS_PLAYER(self) && !lockteams && !gameover)
+ if (!IS_PLAYER(self) && !lockteams && !gameover)
{
- if(self.caplayer)
- return;
- if(nJoinAllowed(self))
+ if (self.caplayer) return;
+ if (nJoinAllowed(self))
{
- if(autocvar_g_campaign) { campaign_bots_may_start = 1; }
-
+ if (autocvar_g_campaign) campaign_bots_may_start = 1;
self.classname = STR_PLAYER;
PlayerScore_Clear(self);
Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
}
else
{
- //player may not join because of g_maxplayers is set
+ // player may not join because of g_maxplayers is set
Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT);
}
}
}
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
}
void ClientCommand_physics(float request, float argc)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
string command = strtolower(argv(1));
- if(!autocvar_g_physics_clientselect)
+ if (!autocvar_g_physics_clientselect)
{
sprint(self, "Client physics selection is currently disabled.\n");
return;
}
- if(command == "list" || command == "help")
+ if (command == "list" || command == "help")
{
sprint(self, strcat("Available physics sets: \n\n", autocvar_g_physics_clientselect_options, " default\n"));
return;
}
- if(Physics_Valid(command) || command == "default")
+ if (Physics_Valid(command) || command == "default")
{
stuffcmd(self, strcat("\nseta cl_physics ", command, "\nsendcvar cl_physics\n"));
sprint(self, strcat("^2Physics set successfully changed to ^3", command, "\n"));
}
}
-void ClientCommand_ready(float request) // todo: anti-spam for toggling readyness
-{SELFPARAM();
- switch(request)
+void ClientCommand_ready(float request) // todo: anti-spam for toggling readyness
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(IS_CLIENT(self))
+ if (IS_CLIENT(self))
{
- if(warmup_stage || autocvar_sv_ready_restart || g_race_qualifying == 2)
+ if (warmup_stage || autocvar_sv_ready_restart || g_race_qualifying == 2)
{
- if(!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
+ if (!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
{
- if(time < game_starttime) // game is already restarting
+ if (time < game_starttime) // game is already restarting
return;
- if (self.ready) // toggle
+ if (self.ready) // toggle
{
self.ready = false;
bprint(self.netname, "^2 is ^1NOT^2 ready\n");
}
// cannot reset the game while a timeout is active!
- if (!timeout_status)
- ReadyCount();
- } else {
+ if (!timeout_status) ReadyCount();
+ }
+ else
+ {
sprint(self, "^1Game has already been restarted\n");
}
}
}
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
}
void ClientCommand_say(float request, float argc, string command)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argc >= 2) { Say(self, false, world, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1); }
- return; // never fall through to usage
+ if (argc >= 2) Say(self, false, world, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
+ return; // never fall through to usage
}
default:
}
void ClientCommand_say_team(float request, float argc, string command)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argc >= 2) { Say(self, true, world, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1); }
- return; // never fall through to usage
+ if (argc >= 2) Say(self, true, world, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
+ return; // never fall through to usage
}
default:
}
void ClientCommand_selectteam(float request, float argc)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1) != "")
+ if (argv(1) != "")
{
- if(IS_CLIENT(self))
+ if (IS_CLIENT(self))
{
- if(teamplay)
- if(self.team_forced <= 0)
+ if (teamplay)
+ {
+ if (self.team_forced <= 0)
+ {
if (!lockteams)
{
float selection;
- switch(argv(1))
+ switch (argv(1))
{
- case "red": selection = NUM_TEAM_1; break;
- case "blue": selection = NUM_TEAM_2; break;
- case "yellow": selection = NUM_TEAM_3; break;
- case "pink": selection = NUM_TEAM_4; break;
- case "auto": selection = (-1); break;
-
- default: selection = 0; break;
+ case "red": selection = NUM_TEAM_1;
+ break;
+ case "blue": selection = NUM_TEAM_2;
+ break;
+ case "yellow": selection = NUM_TEAM_3;
+ break;
+ case "pink": selection = NUM_TEAM_4;
+ break;
+ case "auto": selection = (-1);
+ break;
+
+ default: selection = 0;
+ break;
}
- if(selection)
+ if (selection)
{
- if(self.team == selection && self.deadflag == DEAD_NO)
+ if (self.team == selection && self.deadflag == DEAD_NO)
+ {
sprint(self, "^7You already are on that team.\n");
- else if(self.wasplayer && autocvar_g_changeteam_banned)
+ }
+ else if (self.wasplayer && autocvar_g_changeteam_banned)
+ {
sprint(self, "^1You cannot change team, forbidden by the server.\n");
+ }
else
{
- if(autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)
+ if (autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)
{
CheckAllowedTeams(self);
GetTeamCounts(self);
- if(!TeamSmallerEqThanTeam(Team_TeamToNumber(selection), Team_TeamToNumber(self.team), self))
+ if (!TeamSmallerEqThanTeam(Team_TeamToNumber(selection), Team_TeamToNumber(self.team), self))
{
Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
return;
}
}
else
+ {
sprint(self, "^7The game has already begun, you must wait until the next map to be able to join a team.\n");
+ }
+ }
else
+ {
sprint(self, "^7selectteam can not be used as your team is forced\n");
+ }
+ }
else
+ {
sprint(self, "^7selectteam can only be used in teamgames\n");
+ }
}
return;
}
}
void ClientCommand_selfstuff(float request, string command)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1) != "")
+ if (argv(1) != "")
{
stuffcmd(self, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
return;
}
void ClientCommand_sentcvar(float request, float argc, string command)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1) != "")
+ if (argv(1) != "")
{
- //float tokens;
+ // float tokens;
string s;
- if(argc == 2) // undefined cvar: use the default value on the server then
+ if (argc == 2) // undefined cvar: use the default value on the server then
{
s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
tokenize_console(s);
}
void ClientCommand_spectate(float request)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(IS_CLIENT(self))
+ if (IS_CLIENT(self))
{
int mutator_returnvalue = MUTATOR_CALLHOOK(ClientCommand_Spectate, self);
- if(mutator_returnvalue == MUT_SPECCMD_RETURN)
- return;
+ if (mutator_returnvalue == MUT_SPECCMD_RETURN) return;
- if((IS_PLAYER(self) || mutator_returnvalue == MUT_SPECCMD_FORCE) && autocvar_sv_spectate == 1)
- ClientKill_TeamChange(-2); // observe
+ if ((IS_PLAYER(self) || mutator_returnvalue == MUT_SPECCMD_FORCE) && autocvar_sv_spectate == 1) ClientKill_TeamChange(-2); // observe
}
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
}
void ClientCommand_suggestmap(float request, float argc)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1) != "")
+ if (argv(1) != "")
{
sprint(self, strcat(MapVote_Suggest(argv(1)), "\n"));
return;
}
void ClientCommand_tell(float request, float argc, string command)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argc >= 3)
+ if (argc >= 3)
{
entity tell_to = GetIndexedEntity(argc, 1);
float tell_accepted = VerifyClientEntity(tell_to, true, false);
- if(tell_accepted > 0) // the target is a real client
+ if (tell_accepted > 0) // the target is a real client
{
- if(tell_to != self) // and we're allowed to send to them :D
+ if (tell_to != self) // and we're allowed to send to them :D
{
// workaround for argv indexes indexing ascii chars instead of utf8 chars
// In this case when the player name contains utf8 chars
}
else { print_to(self, "You can't ^2tell^7 a message to yourself."); return; }
}
- else if(argv(1) == "#0")
+ else if (argv(1) == "#0")
{
trigger_magicear_processmessage_forallears(self, -1, world, substring(command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)));
return;
}
void ClientCommand_voice(float request, float argc, string command)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1) != "")
+ if (argv(1) != "")
{
- if(argc >= 3)
- VoiceMessage(argv(1), substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
- else
- VoiceMessage(argv(1), "");
+ if (argc >= 3) VoiceMessage(argv(1), substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
+ else VoiceMessage(argv(1), "");
return;
}
** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
void ClientCommand_(float request)
{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
-
- return; // never fall through to usage
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- sprint(self, "\nUsage:^3 cmd \n");
- sprint(self, " No arguments required.\n");
- return;
- }
- }
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+
+ return; // never fall through to usage
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ sprint(self, "\nUsage:^3 cmd \n");
+ sprint(self, " No arguments required.\n");
+ return;
+ }
+ }
}
*/
// =====================================
// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define CLIENT_COMMANDS(request,arguments,command) \
+#define CLIENT_COMMANDS(request, arguments, command) \
CLIENT_COMMAND("autoswitch", ClientCommand_autoswitch(request, arguments), "Whether or not to switch automatically when getting a better weapon") \
CLIENT_COMMAND("clientversion", ClientCommand_clientversion(request, arguments), "Release version of the game") \
CLIENT_COMMAND("mv_getpicture", ClientCommand_mv_getpicture(request, arguments), "Retrieve mapshot picture from the server") \
/* nothing */
void ClientCommand_macro_help()
-{SELFPARAM();
- #define CLIENT_COMMAND(name,function,description) \
+{
+ SELFPARAM();
+ #define CLIENT_COMMAND(name, function, description) \
{ sprint(self, " ^2", name, "^7: ", description, "\n"); }
CLIENT_COMMANDS(0, 0, "");
- #undef CLIENT_COMMAND
-
- return;
+#undef CLIENT_COMMAND
}
float ClientCommand_macro_command(float argc, string command)
{
- #define CLIENT_COMMAND(name,function,description) \
- { if(name == strtolower(argv(0))) { function; return true; } }
+ #define CLIENT_COMMAND(name, function, description) \
+ { if (name == strtolower(argv(0))) { function; return true; } }
CLIENT_COMMANDS(CMD_REQUEST_COMMAND, argc, command);
- #undef CLIENT_COMMAND
+#undef CLIENT_COMMAND
return false;
}
float ClientCommand_macro_usage(float argc)
{
- #define CLIENT_COMMAND(name,function,description) \
- { if(name == strtolower(argv(1))) { function; return true; } }
+ #define CLIENT_COMMAND(name, function, description) \
+ { if (name == strtolower(argv(1))) { function; return true; } }
CLIENT_COMMANDS(CMD_REQUEST_USAGE, argc, "");
- #undef CLIENT_COMMAND
+#undef CLIENT_COMMAND
return false;
}
void ClientCommand_macro_write_aliases(float fh)
{
- #define CLIENT_COMMAND(name,function,description) \
+ #define CLIENT_COMMAND(name, function, description) \
{ CMD_Write_Alias("qc_cmd_cmd", name, description); }
CLIENT_COMMANDS(0, 0, "");
- #undef CLIENT_COMMAND
-
- return;
+#undef CLIENT_COMMAND
}
// ======================================
// If this function exists, server game code parses clientcommand before the engine code gets it.
void SV_ParseClientCommand(string command)
-{SELFPARAM();
+{
+ SELFPARAM();
// If invalid UTF-8, don't even parse it
string command2 = "";
float len = strlen(command);
float i;
for (i = 0; i < len; ++i)
command2 = strcat(command2, chr2str(str2chr(command, i)));
- if (command != command2)
- return;
+ if (command != command2) return;
// if we're banned, don't even parse the command
- if(Ban_MaybeEnforceBanOnce(self))
- return;
+ if (Ban_MaybeEnforceBanOnce(self)) return;
float argc = tokenize_console(command);
// cmd vote - master - login - password
// for floodcheck
- switch(strtolower(argv(0)))
+ switch (strtolower(argv(0)))
{
// exempt commands which are not subject to floodcheck
- case "begin": break; // handled by engine in host_cmd.c
- case "download": break; // handled by engine in cl_parse.c
- case "mv_getpicture": break; // handled by server in this file
- case "pause": break; // handled by engine in host_cmd.c
- case "prespawn": break; // handled by engine in host_cmd.c
- case "sentcvar": break; // handled by server in this file
- case "spawn": break; // handled by engine in host_cmd.c
+ case "begin": break; // handled by engine in host_cmd.c
+ case "download": break; // handled by engine in cl_parse.c
+ case "mv_getpicture": break; // handled by server in this file
+ case "pause": break; // handled by engine in host_cmd.c
+ case "prespawn": break; // handled by engine in host_cmd.c
+ case "sentcvar": break; // handled by server in this file
+ case "spawn": break; // handled by engine in host_cmd.c
default:
- if(SV_ParseClientCommand_floodcheck())
- break; // "true": continue, as we're not flooding yet
- else
- return; // "false": not allowed to continue, halt // print("^1ERROR: ^7ANTISPAM CAUGHT: ", command, ".\n");
+ if (SV_ParseClientCommand_floodcheck()) break; // "true": continue, as we're not flooding yet
+ else return; // "false": not allowed to continue, halt // print("^1ERROR: ^7ANTISPAM CAUGHT: ", command, ".\n");
}
/* NOTE: should this be disabled? It can be spammy perhaps, but hopefully it's okay for now */
- if(argv(0) == "help")
+ if (argv(0) == "help")
{
- if(argc == 1)
+ if (argc == 1)
{
sprint(self, "\nClient networked commands:\n");
ClientCommand_macro_help();
sprint(self, "For help about a specific command, type cmd help COMMAND\n");
return;
}
- else if(CommonCommand_macro_usage(argc, self)) // Instead of trying to call a command, we're going to see detailed information about it
+ else if (CommonCommand_macro_usage(argc, self)) // Instead of trying to call a command, we're going to see detailed information about it
{
return;
}
- else if(ClientCommand_macro_usage(argc)) // same, but for normal commands now
+ else if (ClientCommand_macro_usage(argc)) // same, but for normal commands now
{
return;
}
}
- else if(MUTATOR_CALLHOOK(SV_ParseClientCommand, strtolower(argv(0)), argc, command))
+ else if (MUTATOR_CALLHOOK(SV_ParseClientCommand, strtolower(argv(0)), argc, command))
{
- return; // handled by a mutator
+ return; // handled by a mutator
}
- else if(CheatCommand(argc))
+ else if (CheatCommand(argc))
{
- return; // handled by server/cheats.qc
+ return; // handled by server/cheats.qc
}
- else if(CommonCommand_macro_command(argc, self, command))
+ else if (CommonCommand_macro_command(argc, self, command))
{
- return; // handled by server/command/common.qc
+ return; // handled by server/command/common.qc
}
- else if(ClientCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+ else if (ClientCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
{
- return; // handled by one of the above ClientCommand_* functions
+ return; // handled by one of the above ClientCommand_* functions
}
else
+ {
clientcommand(self, command);
+ }
}
// select the proper prefix for usage and other messages
string GetCommandPrefix(entity caller)
{
- if(caller)
- return "cmd";
- else
- return "sv_cmd";
+ if (caller) return "cmd";
+ else return "sv_cmd";
}
// if client return player nickname, or if server return admin nickname
string GetCallerName(entity caller)
{
- if(caller)
- return caller.netname;
- else
- return admin_name(); //((autocvar_sv_adminnick != "") ? autocvar_sv_adminnick : autocvar_hostname);
+ if (caller) return caller.netname;
+ else return admin_name(); // ((autocvar_sv_adminnick != "") ? autocvar_sv_adminnick : autocvar_hostname);
}
// verify that the client provided is acceptable for kicking
float VerifyKickableEntity(entity client)
{
- if (!IS_REAL_CLIENT(client))
- return CLIENT_NOT_REAL;
+ if (!IS_REAL_CLIENT(client)) return CLIENT_NOT_REAL;
return CLIENT_ACCEPTABLE;
}
// verify that the client provided is acceptable for use
float VerifyClientEntity(entity client, float must_be_real, float must_be_bots)
{
- if (!IS_CLIENT(client))
- return CLIENT_DOESNT_EXIST;
- else if(must_be_real && !IS_REAL_CLIENT(client))
- return CLIENT_NOT_REAL;
- else if(must_be_bots && !IS_BOT_CLIENT(client))
- return CLIENT_NOT_BOT;
+ if (!IS_CLIENT(client)) return CLIENT_DOESNT_EXIST;
+ else if (must_be_real && !IS_REAL_CLIENT(client)) return CLIENT_NOT_REAL;
+ else if (must_be_bots && !IS_BOT_CLIENT(client)) return CLIENT_NOT_BOT;
return CLIENT_ACCEPTABLE;
}
// if the client is not acceptable, return a string to be used for error messages
string GetClientErrorString_color(float clienterror, string original_input, string col)
{
- switch(clienterror)
+ switch (clienterror)
{
- case CLIENT_DOESNT_EXIST: { return strcat(col, "Client '", original_input, col, "' doesn't exist"); }
- case CLIENT_NOT_REAL: { return strcat(col, "Client '", original_input, col, "' is not real"); }
- case CLIENT_NOT_BOT: { return strcat(col, "Client '", original_input, col, "' is not a bot"); }
- default: { return "Incorrect usage of GetClientErrorString"; }
+ case CLIENT_DOESNT_EXIST:
+ { return strcat(col, "Client '", original_input, col, "' doesn't exist");
+ }
+ case CLIENT_NOT_REAL:
+ { return strcat(col, "Client '", original_input, col, "' is not real");
+ }
+ case CLIENT_NOT_BOT:
+ { return strcat(col, "Client '", original_input, col, "' is not a bot");
+ }
+ default:
+ { return "Incorrect usage of GetClientErrorString";
+ }
}
}
// is this entity number even in the possible range of entities?
float VerifyClientNumber(float tmp_number)
{
- if((tmp_number < 1) || (tmp_number > maxclients))
- return false;
- else
- return true;
+ if ((tmp_number < 1) || (tmp_number > maxclients)) return false;
+ else return true;
}
entity GetIndexedEntity(float argc, float start_index)
index = start_index;
selection = world;
- if(argc > start_index)
+ if (argc > start_index)
{
- if(substring(argv(index), 0, 1) == "#")
+ if (substring(argv(index), 0, 1) == "#")
{
tmp_string = substring(argv(index), 1, -1);
++index;
- if(tmp_string != "") // is it all one token? like #1
+ if (tmp_string != "") // is it all one token? like #1
{
tmp_number = stof(tmp_string);
}
- else if(argc > index) // no, it's two tokens? # 1
+ else if (argc > index) // no, it's two tokens? # 1
{
tmp_number = stof(argv(index));
++index;
}
else
+ {
tmp_number = 0;
+ }
}
- else // maybe it's ONLY a number?
+ else // maybe it's ONLY a number?
{
tmp_number = stof(argv(index));
++index;
}
- if(VerifyClientNumber(tmp_number))
+ if (VerifyClientNumber(tmp_number))
{
- selection = edict_num(tmp_number); // yes, it was a number
+ selection = edict_num(tmp_number); // yes, it was a number
}
- else // no, maybe it's a name?
+ else // no, maybe it's a name?
{
FOR_EACH_CLIENT(tmp_player)
- if (strdecolorize(tmp_player.netname) == strdecolorize(argv(start_index)))
- selection = tmp_player;
+ if (strdecolorize(tmp_player.netname) == strdecolorize(argv(start_index))) selection = tmp_player;
index = (start_index + 1);
}
}
next_token = index;
- //print(strcat("start_index: ", ftos(start_index), ", next_token: ", ftos(next_token), ", edict: ", ftos(num_for_edict(selection)), ".\n"));
+ // print(strcat("start_index: ", ftos(start_index), ", next_token: ", ftos(next_token), ", edict: ", ftos(num_for_edict(selection)), ".\n"));
return selection;
}
entity tmp_player, selection;
float tmp_number;
- if(substring(input, 0, 1) == "#")
- tmp_number = stof(substring(input, 1, -1));
- else
- tmp_number = stof(input);
+ if (substring(input, 0, 1) == "#") tmp_number = stof(substring(input, 1, -1));
+ else tmp_number = stof(input);
- if(VerifyClientNumber(tmp_number))
+ if (VerifyClientNumber(tmp_number))
{
selection = edict_num(tmp_number);
}
{
selection = world;
FOR_EACH_CLIENT(tmp_player)
- if (strdecolorize(tmp_player.netname) == strdecolorize(input))
- selection = tmp_player;
+ if (strdecolorize(tmp_player.netname) == strdecolorize(input)) selection = tmp_player;
}
return selection;
// switch between sprint and print depending on whether the receiver is the server or a player
void print_to(entity to, string input)
{
- if(to)
- sprint(to, strcat(input, "\n"));
- else
- LOG_INFO(input, "\n");
+ if (to) sprint(to, strcat(input, "\n"));
+ else LOG_INFO(input, "\n");
}
// ==========================================
// used by CommonCommand_timeout() and CommonCommand_timein() to handle game pausing and messaging and such.
void timeout_handler_reset()
-{SELFPARAM();
+{
+ SELFPARAM();
timeout_caller = world;
timeout_time = 0;
timeout_leadtime = 0;
}
void timeout_handler_think()
-{SELFPARAM();
+{
+ SELFPARAM();
entity tmp_player;
- switch(timeout_status)
+ switch (timeout_status)
{
case TIMEOUT_ACTIVE:
{
- if(timeout_time > 0) // countdown is still going
+ if (timeout_time > 0) // countdown is still going
{
Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_TIMEOUT_ENDING, timeout_time);
- if(timeout_time == autocvar_sv_timeout_resumetime) // play a warning sound when only <sv_timeout_resumetime> seconds are left
+ if (timeout_time == autocvar_sv_timeout_resumetime) // play a warning sound when only <sv_timeout_resumetime> seconds are left
Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_PREPARE);
- self.nextthink = time + TIMEOUT_SLOWMO_VALUE; // think again in one second
- timeout_time -= 1; // decrease the time counter
+ self.nextthink = time + TIMEOUT_SLOWMO_VALUE; // think again in one second
+ timeout_time -= 1; // decrease the time counter
}
- else // time to end the timeout
+ else // time to end the timeout
{
timeout_status = TIMEOUT_INACTIVE;
// unlock the view for players so they can move around again
FOR_EACH_REALPLAYER(tmp_player)
- tmp_player.fixangle = false;
+ tmp_player.fixangle = false;
timeout_handler_reset();
}
case TIMEOUT_LEADTIME:
{
- if(timeout_leadtime > 0) // countdown is still going
+ if (timeout_leadtime > 0) // countdown is still going
{
Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_TIMEOUT_BEGINNING, timeout_leadtime);
self.nextthink = time + 1; // think again in one second
- timeout_leadtime -= 1; // decrease the time counter
+ timeout_leadtime -= 1; // decrease the time counter
}
- else // time to begin the timeout
+ else // time to begin the timeout
{
timeout_status = TIMEOUT_ACTIVE;
// reset all the flood variables
FOR_EACH_CLIENT(tmp_player)
- tmp_player.nickspamcount = tmp_player.nickspamtime = tmp_player.floodcontrol_chat =
- tmp_player.floodcontrol_chatteam = tmp_player.floodcontrol_chattell =
- tmp_player.floodcontrol_voice = tmp_player.floodcontrol_voiceteam = 0;
+ tmp_player.nickspamcount = tmp_player.nickspamtime = tmp_player.floodcontrol_chat =
+ tmp_player.floodcontrol_chatteam = tmp_player.floodcontrol_chattell =
+ tmp_player.floodcontrol_voice = tmp_player.floodcontrol_voiceteam = 0;
// copy .v_angle to .lastV_angle for every player in order to fix their view during pause (see PlayerPreThink)
FOR_EACH_REALPLAYER(tmp_player)
- tmp_player.lastV_angle = tmp_player.v_angle;
+ tmp_player.lastV_angle = tmp_player.v_angle;
- self.nextthink = time; // think again next frame to handle it under TIMEOUT_ACTIVE code
+ self.nextthink = time; // think again next frame to handle it under TIMEOUT_ACTIVE code
}
return;
}
-
// ===================================================
// Common commands used in both sv_cmd.qc and cmd.qc
// ===================================================
void CommonCommand_cvar_changes(float request, entity caller)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
print_to(caller, cvar_changes);
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
void CommonCommand_cvar_purechanges(float request, entity caller)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
print_to(caller, cvar_purechanges);
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
}
void CommonCommand_editmob(int request, entity caller, int argc)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(autocvar_g_campaign) { print_to(caller, "Monster editing is disabled in singleplayer"); return; }
+ if (autocvar_g_campaign) { print_to(caller, "Monster editing is disabled in singleplayer"); return; }
// no checks for g_monsters here, as it may be toggled mid match which existing monsters
- if(caller)
+ if (caller)
{
makevectors(self.v_angle);
WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * 100, MOVE_NORMAL, self);
bool is_visible = IS_MONSTER(mon);
string argument = argv(2);
- switch(argv(1))
+ switch (argv(1))
{
case "name":
{
- if(!caller) { print_to(caller, "Only players can edit monsters"); return; }
- if(!argument) { break; } // escape to usage
- if(!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
- if(mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
- if(!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
+ if (!caller) { print_to(caller, "Only players can edit monsters"); return; }
+ if (!argument) break; // escape to usage
+ if (!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
+ if (mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
+ if (!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
string mon_oldname = mon.monster_name;
mon.monster_name = argument;
- if(mon.sprite) { WaypointSprite_UpdateSprites(mon.sprite, WP_Monster, WP_Null, WP_Null); }
+ if (mon.sprite) WaypointSprite_UpdateSprites(mon.sprite, WP_Monster, WP_Null, WP_Null);
print_to(caller, sprintf("Your pet '%s' is now known as '%s'", mon_oldname, mon.monster_name));
return;
}
case "spawn":
{
- if(!caller) { print_to(caller, "Only players can spawn monsters"); return; }
- if(!argv(2)) { break; } // escape to usage
+ if (!caller) { print_to(caller, "Only players can spawn monsters"); return; }
+ if (!argv(2)) break; // escape to usage
int moveflag, tmp_moncount = 0;
string arg_lower = strtolower(argument);
- moveflag = (argv(3)) ? stof(argv(3)) : 1; // follow owner if not defined
+ moveflag = (argv(3)) ? stof(argv(3)) : 1; // follow owner if not defined
ret_string = "Monster spawning is currently disabled by a mutator";
- if(arg_lower == "list") { print_to(caller, monsterlist_reply); return; }
+ if (arg_lower == "list") { print_to(caller, monsterlist_reply); return; }
- FOR_EACH_MONSTER(mon) { if(mon.realowner == caller) ++tmp_moncount; }
+ FOR_EACH_MONSTER(mon)
+ {
+ if (mon.realowner == caller) ++tmp_moncount;
+ }
- if(!autocvar_g_monsters) { print_to(caller, "Monsters are disabled"); return; }
- if(autocvar_g_monsters_max <= 0 || autocvar_g_monsters_max_perplayer <= 0) { print_to(caller, "Monster spawning is disabled"); return; }
- if(!IS_PLAYER(caller)) { print_to(caller, "You must be playing to spawn a monster"); return; }
- if(MUTATOR_CALLHOOK(AllowMobSpawning)) { print_to(caller, ret_string); return; }
- if(caller.vehicle) { print_to(caller, "You can't spawn monsters while driving a vehicle"); return; }
- if(caller.frozen) { print_to(caller, "You can't spawn monsters while frozen"); return; }
- if(caller.deadflag != DEAD_NO) { print_to(caller, "You can't spawn monsters while dead"); return; }
- if(tmp_moncount >= autocvar_g_monsters_max) { print_to(caller, "The maximum monster count has been reached"); return; }
- if(tmp_moncount >= autocvar_g_monsters_max_perplayer) { print_to(caller, "You can't spawn any more monsters"); return; }
+ if (!autocvar_g_monsters) { print_to(caller, "Monsters are disabled"); return; }
+ if (autocvar_g_monsters_max <= 0 || autocvar_g_monsters_max_perplayer <= 0) { print_to(caller, "Monster spawning is disabled"); return; }
+ if (!IS_PLAYER(caller)) { print_to(caller, "You must be playing to spawn a monster"); return; }
+ if (MUTATOR_CALLHOOK(AllowMobSpawning)) { print_to(caller, ret_string); return; }
+ if (caller.vehicle) { print_to(caller, "You can't spawn monsters while driving a vehicle"); return; }
+ if (caller.frozen) { print_to(caller, "You can't spawn monsters while frozen"); return; }
+ if (caller.deadflag != DEAD_NO) { print_to(caller, "You can't spawn monsters while dead"); return; }
+ if (tmp_moncount >= autocvar_g_monsters_max) { print_to(caller, "The maximum monster count has been reached"); return; }
+ if (tmp_moncount >= autocvar_g_monsters_max_perplayer) { print_to(caller, "You can't spawn any more monsters"); return; }
bool found = false;
- for(int i = MON_FIRST; i <= MON_LAST; ++i)
+ for (int i = MON_FIRST; i <= MON_LAST; ++i)
{
mon = get_monsterinfo(i);
- if(mon.netname == arg_lower) { found = true; break; }
+ if (mon.netname == arg_lower) { found = true; break; }
}
- if(!found && arg_lower != "random") { print_to(caller, "Invalid monster"); return; }
+ if (!found && arg_lower != "random") { print_to(caller, "Invalid monster"); return; }
totalspawned += 1;
- WarpZone_TraceBox (CENTER_OR_VIEWOFS(caller), caller.mins, caller.maxs, CENTER_OR_VIEWOFS(caller) + v_forward * 150, true, caller);
+ WarpZone_TraceBox(CENTER_OR_VIEWOFS(caller), caller.mins, caller.maxs, CENTER_OR_VIEWOFS(caller) + v_forward * 150, true, caller);
mon = spawnmonster(arg_lower, 0, caller, caller, trace_endpos, false, false, moveflag);
print_to(caller, strcat("Spawned ", mon.monster_name));
return;
}
case "kill":
{
- if(!caller) { print_to(caller, "Only players can kill monsters"); return; }
- if(mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
- if(!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
+ if (!caller) { print_to(caller, "Only players can kill monsters"); return; }
+ if (mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
+ if (!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
- Damage (mon, world, world, mon.health + mon.max_health + 200, DEATH_KILL.m_id, mon.origin, '0 0 0');
+ Damage(mon, world, world, mon.health + mon.max_health + 200, DEATH_KILL.m_id, mon.origin, '0 0 0');
print_to(caller, strcat("Your pet '", mon.monster_name, "' has been brutally mutilated"));
return;
}
case "skin":
{
- if(!caller) { print_to(caller, "Only players can edit monsters"); return; }
- if(!argument) { break; } // escape to usage
- if(!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
- if(!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
- if(mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
- if(mon.monsterid == MON_MAGE.monsterid) { print_to(caller, "Mage skins can't be changed"); return; } // TODO
+ if (!caller) { print_to(caller, "Only players can edit monsters"); return; }
+ if (!argument) break; // escape to usage
+ if (!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
+ if (!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
+ if (mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
+ if (mon.monsterid == MON_MAGE.monsterid) { print_to(caller, "Mage skins can't be changed"); return; } // TODO
mon.skin = stof(argument);
print_to(caller, strcat("Monster skin successfully changed to ", ftos(mon.skin)));
}
case "movetarget":
{
- if(!caller) { print_to(caller, "Only players can edit monsters"); return; }
- if(!argument) { break; } // escape to usage
- if(!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
- if(!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
- if(mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
+ if (!caller) { print_to(caller, "Only players can edit monsters"); return; }
+ if (!argument) break; // escape to usage
+ if (!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
+ if (!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
+ if (mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
mon.monster_moveflags = stof(argument);
print_to(caller, strcat("Monster move target successfully changed to ", ftos(mon.monster_moveflags)));
}
case "butcher":
{
- if(caller) { print_to(caller, "This command is not available to players"); return; }
- if(MUTATOR_CALLHOOK(AllowMobButcher)) { LOG_INFO(ret_string, "\n"); return; }
+ if (caller) { print_to(caller, "This command is not available to players"); return; }
+ if (MUTATOR_CALLHOOK(AllowMobButcher)) { LOG_INFO(ret_string, "\n"); return; }
int tmp_remcount = 0;
entity tmp_entity;
- FOR_EACH_MONSTER(tmp_entity) { Monster_Remove(tmp_entity); ++tmp_remcount; }
+ FOR_EACH_MONSTER(tmp_entity)
+ {
+ Monster_Remove(tmp_entity);
+ ++tmp_remcount;
+ }
monsters_total = monsters_killed = totalspawned = 0;
void CommonCommand_info(float request, entity caller, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
string command = builtin_cvar_string(strcat("sv_info_", argv(1)));
- if(command)
- wordwrap_sprint(command, 1000);
- else
- print_to(caller, "ERROR: unsupported info command");
+ if (command) wordwrap_sprint(command, 1000);
+ else print_to(caller, "ERROR: unsupported info command");
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
void CommonCommand_ladder(float request, entity caller)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
print_to(caller, ladder_reply);
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
void CommonCommand_lsmaps(float request, entity caller)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
print_to(caller, lsmaps_reply);
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
void CommonCommand_printmaplist(float request, entity caller)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
print_to(caller, maplist_reply);
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
void CommonCommand_rankings(float request, entity caller)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
print_to(caller, rankings_reply);
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
void CommonCommand_records(float request, entity caller)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- for(int i = 0; i < 10; ++i)
- if(records_reply[i] != "")
- print_to(caller, records_reply[i]);
+ for (int i = 0; i < 10; ++i)
+ if (records_reply[i] != "") print_to(caller, records_reply[i]);
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
void CommonCommand_teamstatus(float request, entity caller)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
Score_NicePrint(caller);
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
void CommonCommand_time(float request, entity caller)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
void CommonCommand_timein(float request, entity caller)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(!caller || autocvar_sv_timeout)
+ if (!caller || autocvar_sv_timeout)
{
if (!timeout_status) { print_to(caller, "^7Error: There is no active timeout called."); }
- else if(caller && (caller != timeout_caller)) { print_to(caller, "^7Error: You are not allowed to stop the active timeout."); }
+ else if (caller && (caller != timeout_caller))
+ {
+ print_to(caller, "^7Error: You are not allowed to stop the active timeout.");
+ }
- else // everything should be okay, continue aborting timeout
+ else // everything should be okay, continue aborting timeout
{
- switch(timeout_status)
+ switch (timeout_status)
{
case TIMEOUT_LEADTIME:
{
timeout_status = TIMEOUT_INACTIVE;
timeout_time = 0;
- timeout_handler.nextthink = time; // timeout_handler has to take care of it immediately
+ timeout_handler.nextthink = time; // timeout_handler has to take care of it immediately
bprint(strcat("^7The timeout was aborted by ", GetCallerName(caller), " !\n"));
return;
}
case TIMEOUT_ACTIVE:
{
timeout_time = autocvar_sv_timeout_resumetime;
- timeout_handler.nextthink = time; // timeout_handler has to take care of it immediately
+ timeout_handler.nextthink = time; // timeout_handler has to take care of it immediately
bprint(strcat("^1Attention: ^7", GetCallerName(caller), " resumed the game! Prepare for battle!\n"));
return;
}
- default: LOG_TRACE("timeout status was inactive, but this code was executed anyway?"); return;
+ default: LOG_TRACE("timeout status was inactive, but this code was executed anyway?");
+ return;
}
}
}
else { print_to(caller, "^1Timeins are not allowed to be called, enable them with sv_timeout 1.\n"); }
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
}
}
-void CommonCommand_timeout(float request, entity caller) // DEAR GOD THIS COMMAND IS TERRIBLE.
+void CommonCommand_timeout(float request, entity caller) // DEAR GOD THIS COMMAND IS TERRIBLE.
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(!caller || autocvar_sv_timeout)
+ if (!caller || autocvar_sv_timeout)
{
float last_possible_timeout = ((autocvar_timelimit * 60) - autocvar_sv_timeout_leadtime - 1);
- if(timeout_status) { print_to(caller, "^7Error: A timeout is already active."); }
- else if(vote_called) { print_to(caller, "^7Error: You can not call a timeout while a vote is active."); }
- else if(warmup_stage && !g_warmup_allow_timeout) { print_to(caller, "^7Error: You can not call a timeout in warmup-stage."); }
- else if(time < game_starttime) { print_to(caller, "^7Error: You can not call a timeout while the map is being restarted."); }
- else if(caller && (caller.allowed_timeouts < 1)) { print_to(caller, "^7Error: You already used all your timeout calls for this map."); }
- else if(caller && !IS_PLAYER(caller)) { print_to(caller, "^7Error: You must be a player to call a timeout."); }
- else if((autocvar_timelimit) && (last_possible_timeout < time - game_starttime)) { print_to(caller, "^7Error: It is too late to call a timeout now!"); }
-
- else // everything should be okay, proceed with starting the timeout
+ if (timeout_status) { print_to(caller, "^7Error: A timeout is already active."); }
+ else if (vote_called)
{
- if(caller) { caller.allowed_timeouts -= 1; }
+ print_to(caller, "^7Error: You can not call a timeout while a vote is active.");
+ }
+ else if (warmup_stage && !g_warmup_allow_timeout)
+ {
+ print_to(caller, "^7Error: You can not call a timeout in warmup-stage.");
+ }
+ else if (time < game_starttime)
+ {
+ print_to(caller, "^7Error: You can not call a timeout while the map is being restarted.");
+ }
+ else if (caller && (caller.allowed_timeouts < 1))
+ {
+ print_to(caller, "^7Error: You already used all your timeout calls for this map.");
+ }
+ else if (caller && !IS_PLAYER(caller))
+ {
+ print_to(caller, "^7Error: You must be a player to call a timeout.");
+ }
+ else if ((autocvar_timelimit) && (last_possible_timeout < time - game_starttime))
+ {
+ print_to(caller, "^7Error: It is too late to call a timeout now!");
+ }
+ else // everything should be okay, proceed with starting the timeout
+ {
+ if (caller) caller.allowed_timeouts -= 1;
// write a bprint who started the timeout (and how many they have left)
bprint(GetCallerName(caller), " ^7called a timeout", (caller ? strcat(" (", ftos(caller.allowed_timeouts), " timeout(s) left)") : ""), "!\n");
timeout_handler = spawn();
timeout_handler.think = timeout_handler_think;
- timeout_handler.nextthink = time; // always let the entity think asap
+ timeout_handler.nextthink = time; // always let the entity think asap
Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_TIMEOUT);
}
}
else { print_to(caller, "^1Timeouts are not allowed to be called, enable them with sv_timeout 1.\n"); }
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
void CommonCommand_who(float request, entity caller, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
{
is_bot = (IS_BOT_CLIENT(tmp_player));
- if(is_bot)
+ if (is_bot)
{
tmp_netaddress = "null/botclient";
tmp_crypto_idfp = "null/botclient";
}
- else if(privacy)
+ else if (privacy)
{
tmp_netaddress = "hidden";
tmp_crypto_idfp = "hidden";
print_to(caller, strcat("Finished listing ", ftos(total_listed_players), " client(s) out of ", ftos(maxclients), " slots."));
- return; // never fall through to usage
+ return; // never fall through to usage
}
default:
** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
void CommonCommand_(float request, entity caller)
{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
-
- return; // never fall through to usage
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " "));
- print_to(caller, " No arguments required.");
- return;
- }
- }
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+
+ return; // never fall through to usage
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " "));
+ print_to(caller, " No arguments required.");
+ return;
+ }
+ }
}
*/
const float TIMEOUT_SLOWMO_VALUE = 0.0001;
// global timeout information declarations
-entity timeout_caller; // contains the entity of the player who started the last timeout
-entity timeout_handler; // responsible for centerprinting the timeout countdowns and playing sounds
-float sys_frametime; // gets initialised in worldspawn, saves the value from autocvar_sys_ticrate
-float orig_slowmo; // contains the value of autocvar_slowmo so that, after timeout finished, it isn't set to slowmo 1 necessarily
-float timeout_time; // contains the time in seconds that the active timeout has left
-float timeout_leadtime; // contains the number of seconds left of the leadtime (before the timeout starts)
-float timeout_status; // (values: 0, 1, 2) contains whether a timeout is not active (0), was called but still at leadtime (1) or is active (2)
+entity timeout_caller; // contains the entity of the player who started the last timeout
+entity timeout_handler; // responsible for centerprinting the timeout countdowns and playing sounds
+float sys_frametime; // gets initialised in worldspawn, saves the value from autocvar_sys_ticrate
+float orig_slowmo; // contains the value of autocvar_slowmo so that, after timeout finished, it isn't set to slowmo 1 necessarily
+float timeout_time; // contains the time in seconds that the active timeout has left
+float timeout_leadtime; // contains the number of seconds left of the leadtime (before the timeout starts)
+float timeout_status; // (values: 0, 1, 2) contains whether a timeout is not active (0), was called but still at leadtime (1) or is active (2)
.float allowed_timeouts; // contains the number of allowed timeouts for each player
-.vector lastV_angle; //used when pausing the game in order to force the player to keep his old view angle fixed
+.vector lastV_angle; // used when pausing the game in order to force the player to keep his old view angle fixed
// allow functions to be used in other code like g_world.qc and teamplay.qc
void timeout_handler_think();
// if the client is not acceptable, return a string to be used for error messages
string GetClientErrorString_color(float clienterror, string original_input, string col);
-#define GetClientErrorString(clienterror,original_input) GetClientErrorString_color(clienterror,original_input,"^7")
+#define GetClientErrorString(clienterror, original_input) GetClientErrorString_color(clienterror, original_input, "^7")
// is this entity number even in the possible range of entities?
float VerifyClientNumber(float tmp_number);
// ==================================
// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define COMMON_COMMANDS(request,caller,arguments,command) \
+#define COMMON_COMMANDS(request, caller, arguments, command) \
COMMON_COMMAND("cvar_changes", CommonCommand_cvar_changes(request, caller), "Prints a list of all changed server cvars") \
COMMON_COMMAND("cvar_purechanges", CommonCommand_cvar_purechanges(request, caller), "Prints a list of all changed gameplay cvars") \
COMMON_COMMAND("editmob", CommonCommand_editmob(request, caller, arguments), "Modifies a monster or all monsters") \
void CommonCommand_macro_help(entity caller)
{
- #define COMMON_COMMAND(name,function,description) \
+ #define COMMON_COMMAND(name, function, description) \
{ print_to(caller, strcat(" ^2", name, "^7: ", description)); }
COMMON_COMMANDS(0, caller, 0, "");
- #undef COMMON_COMMAND
-
- return;
+#undef COMMON_COMMAND
}
float CommonCommand_macro_command(float argc, entity caller, string command)
{
- #define COMMON_COMMAND(name,function,description) \
- { if(name == strtolower(argv(0))) { function; return true; } }
+ #define COMMON_COMMAND(name, function, description) \
+ { if (name == strtolower(argv(0))) { function; return true; } }
COMMON_COMMANDS(CMD_REQUEST_COMMAND, caller, argc, command);
- #undef COMMON_COMMAND
+#undef COMMON_COMMAND
return false;
}
float CommonCommand_macro_usage(float argc, entity caller)
{
- #define COMMON_COMMAND(name,function,description) \
- { if(name == strtolower(argv(1))) { function; return true; } }
+ #define COMMON_COMMAND(name, function, description) \
+ { if (name == strtolower(argv(1))) { function; return true; } }
COMMON_COMMANDS(CMD_REQUEST_USAGE, caller, argc, "");
- #undef COMMON_COMMAND
+#undef COMMON_COMMAND
return false;
}
void CommonCommand_macro_write_aliases(float fh)
{
- #define COMMON_COMMAND(name,function,description) \
+ #define COMMON_COMMAND(name, function, description) \
{ CMD_Write_Alias("qc_cmd_svcmd", name, description); }
COMMON_COMMANDS(0, world, 0, "");
- #undef COMMON_COMMAND
-
- return;
+#undef COMMON_COMMAND
}
// See common.qc for their proper commands
-string getrecords(int page) // 50 records per page
+string getrecords(int page) // 50 records per page
{
string s = "";
MapInfo_ClearTemps();
- if(s == "" && page == 0)
- return "No records are available on this server.\n";
- else
- return s;
+ if (s == "" && page == 0) return "No records are available on this server.\n";
+ else return s;
}
string getrankings()
{
t = race_readTime(map, i);
- if (t == 0)
- continue;
+ if (t == 0) continue;
n = race_readName(map, i);
p = count_ordinal(i);
MapInfo_ClearTemps();
- if (s == "")
- return strcat("No records are available for the map: ", map, "\n");
- else
- return strcat("Records for ", map, ":\n", s);
+ if (s == "") return strcat("No records are available for the map: ", map, "\n");
+ else return strcat("Records for ", map, ":\n", s);
}
string getladder()
rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
- for(k = 0; k < MapInfo_count; ++k)
+ for (k = 0; k < MapInfo_count; ++k)
{
- if(MapInfo_Get_ByID(k))
+ if (MapInfo_Get_ByID(k))
{
- for(i = 0; i <= LADDER_CNT; ++i) // i = 0 because it is the speed award
+ for (i = 0; i <= LADDER_CNT; ++i) // i = 0 because it is the speed award
{
- if(i == 0) // speed award
+ if (i == 0) // speed award
{
- if(stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/speed"))) == 0)
- continue;
+ if (stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/speed"))) == 0) continue;
myuid = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/crypto_idfp"));
}
- else // normal record, if it exists (else break)
+ else // normal record, if it exists (else break)
{
- if(race_readTime(MapInfo_Map_bspname, i) == 0)
- continue;
+ if (race_readTime(MapInfo_Map_bspname, i) == 0) continue;
myuid = race_readUID(MapInfo_Map_bspname, i);
}
temp_s = db_get(TemporaryDB, strcat("ladder", myuid));
- if(temp_s == "")
+ if (temp_s == "")
{
db_put(TemporaryDB, strcat("uid", ftos(uidcnt)), myuid);
++uidcnt;
- for(j = 0; j <= LADDER_CNT + 1; ++j)
+ for (j = 0; j <= LADDER_CNT + 1; ++j)
{
- if(j != LADDER_CNT + 1)
- temp_s = strcat(temp_s, "0 ");
- else
- temp_s = strcat(temp_s, "0");
+ if (j != LADDER_CNT + 1) temp_s = strcat(temp_s, "0 ");
+ else temp_s = strcat(temp_s, "0");
}
}
tokenize_console(temp_s);
s = "";
- if(i == 0) // speed award
+ if (i == 0) // speed award
{
- for(j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
+ for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
{
- if(j == 0) // speed award
- s = strcat(s, ftos(stof(argv(j)) +1)); // add 1 to speed rec count and write
- else
- s = strcat(s, " ", argv(j)); // just copy over everything else
+ if (j == 0) // speed award
+ s = strcat(s, ftos(stof(argv(j)) + 1)); // add 1 to speed rec count and write
+ else s = strcat(s, " ", argv(j)); // just copy over everything else
}
}
- else // record
+ else // record
{
- for(j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
+ for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
{
- if(j == 0)
- s = strcat(s, argv(j)); // speed award, dont prefix with " "
- else if(j == i) // wanted rec!
- s = strcat(s, " ", ftos(stof(argv(j)) +1)); // update argv(j)
- else
- s = strcat(s, " ", argv(j)); // just copy over everything else
+ if (j == 0) s = strcat(s, argv(j)); // speed award, dont prefix with " "
+ else if (j == i) // wanted rec!
+ s = strcat(s, " ", ftos(stof(argv(j)) + 1)); // update argv(j)
+ else s = strcat(s, " ", argv(j)); // just copy over everything else
}
}
// 5th place = floor(100 / 5) = 20 points
// ... etc
- if(i == 0)
- s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + LADDER_FIRSTPOINT / 10)); // speed award, add LADDER_FIRSTPOINT / 10 points
- else
- s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + floor(LADDER_FIRSTPOINT / i))); // record, add LADDER_FIRSTPOINT / i points
+ if (i == 0) s = strcat(s, " ", ftos(stof(argv(LADDER_CNT + 1)) + LADDER_FIRSTPOINT / 10)); // speed award, add LADDER_FIRSTPOINT / 10 points
+ else s = strcat(s, " ", ftos(stof(argv(LADDER_CNT + 1)) + floor(LADDER_FIRSTPOINT / i))); // record, add LADDER_FIRSTPOINT / i points
db_put(TemporaryDB, strcat("ladder", myuid), s);
}
}
}
- for(i = 0; i <= uidcnt; ++i) // for each known uid
+ for (i = 0; i <= uidcnt; ++i) // for each known uid
{
thisuid = db_get(TemporaryDB, strcat("uid", ftos(i)));
temp_s = db_get(TemporaryDB, strcat("ladder", thisuid));
tokenize_console(temp_s);
- thiscnt = stof(argv(LADDER_CNT+1));
+ thiscnt = stof(argv(LADDER_CNT + 1));
- if(thiscnt > top_scores[LADDER_SIZE-1])
+ if (thiscnt > top_scores[LADDER_SIZE - 1])
{
- for(j = 0; j < LADDER_SIZE; ++j) // for each place in ladder
+ for (j = 0; j < LADDER_SIZE; ++j) // for each place in ladder
{
- if(thiscnt > top_scores[j])
+ if (thiscnt > top_scores[j])
{
- for(k = LADDER_SIZE-1; k >= j; --k)
+ for (k = LADDER_SIZE - 1; k >= j; --k)
{
- top_uids[k] = top_uids[k-1];
- top_scores[k] = top_scores[k-1];
+ top_uids[k] = top_uids[k - 1];
+ top_scores[k] = top_scores[k - 1];
}
top_uids[j] = thisuid;
s = strcat(s, "Pos ^3|");
s = strcat(s, " ^7Total ^3|");
- for(i = 1; i <= LADDER_CNT; ++i)
- { s = strcat(s, " ^7", count_ordinal(i), " ^3|"); }
-
+ for (i = 1; i <= LADDER_CNT; ++i)
+ s = strcat(s, " ^7", count_ordinal(i), " ^3|");
s = strcat(s, " ^7Speed awards ^3| ^7Name");
s = strcat(s, "\n^3----+--------");
- for(i = 1; i <= min(9, LADDER_CNT); ++i)
- { s = strcat(s, "+-----"); }
-
- #if LADDER_CNT > 9
- for(i = 1; i <= LADDER_CNT - 9; ++i)
- { s = strcat(s, "+------"); }
- #endif
+ for (i = 1; i <= min(9, LADDER_CNT); ++i)
+ s = strcat(s, "+-----");
+#if LADDER_CNT > 9
+ for (i = 1; i <= LADDER_CNT - 9; ++i)
+ s = strcat(s, "+------");
+#endif
s = strcat(s, "+--------------+--------------------\n");
- for(i = 0; i < LADDER_SIZE; ++i)
+ for (i = 0; i < LADDER_SIZE; ++i)
{
temp_s = db_get(TemporaryDB, strcat("ladder", top_uids[i]));
tokenize_console(temp_s);
- if(argv(LADDER_CNT+1) == "") // total is 0, skip
+ if (argv(LADDER_CNT + 1) == "") // total is 0, skip
continue;
- s = strcat(s, strpad(4, count_ordinal(i+1)), "^3| ^7"); // pos
- s = strcat(s, strpad(7, argv(LADDER_CNT+1)), "^3| ^7"); // total
+ s = strcat(s, strpad(4, count_ordinal(i + 1)), "^3| ^7"); // pos
+ s = strcat(s, strpad(7, argv(LADDER_CNT + 1)), "^3| ^7"); // total
- for(j = 1; j <= min(9, LADDER_CNT); ++j)
- { s = strcat(s, strpad(4, argv(j)), "^3| ^7"); } // 1st, 2nd, 3rd etc cnt
+ for (j = 1; j <= min(9, LADDER_CNT); ++j)
+ s = strcat(s, strpad(4, argv(j)), "^3| ^7"); // 1st, 2nd, 3rd etc cnt
- #if LADDER_CNT > 9
- for(j = 10; j <= LADDER_CNT; ++j)
- { s = strcat(s, strpad(4, argv(j)), " ^3| ^7"); } // 1st, 2nd, 3rd etc cnt
- #endif
+#if LADDER_CNT > 9
+ for (j = 10; j <= LADDER_CNT; ++j)
+ s = strcat(s, strpad(4, argv(j)), " ^3| ^7"); // 1st, 2nd, 3rd etc cnt
+#endif
- s = strcat(s, strpad(13, argv(0)), "^3| ^7"); // speed award cnt
- s = strcat(s, uid2name(top_uids[i]), "\n"); // name
+ s = strcat(s, strpad(13, argv(0)), "^3| ^7"); // speed award cnt
+ s = strcat(s, uid2name(top_uids[i]), "\n"); // name
}
MapInfo_ClearTemps();
- if(s == "")
- return "No ladder on this server!\n";
- else
- return strcat("Top ", ftos(LADDER_SIZE), " ladder rankings:\n", s);
+ if (s == "") return "No ladder on this server!\n";
+ else return strcat("Top ", ftos(LADDER_SIZE), " ladder rankings:\n", s);
}
string getmaplist()
int i, argc;
argc = tokenize_console(autocvar_g_maplist);
- for(i = 0; i < argc; ++i)
+ for (i = 0; i < argc; ++i)
{
- if(MapInfo_CheckMap(argv(i)))
+ if (MapInfo_CheckMap(argv(i)))
{
- if(i % 2) { col = "^2"; }
- else { col = "^3"; }
+ if (i % 2) col = "^2"; else col = "^3";
maplist = sprintf("%s%s%s ", maplist, col, argv(i));
}
}
string lsmaps = "", col;
float i, newmaps = 0;
- for(i = 0; i < MapInfo_count; ++i)
+ for (i = 0; i < MapInfo_count; ++i)
{
- if((MapInfo_Get_ByID(i)) && !(MapInfo_Map_flags & MapInfo_ForbiddenFlags()))
+ if ((MapInfo_Get_ByID(i)) && !(MapInfo_Map_flags & MapInfo_ForbiddenFlags()))
{
// todo: Check by play count of maps for other game types?
- if(
- (g_race && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time"))))
- ||
- (g_cts && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time"))))
- )
+ if (
+ (g_race && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time"))))
+ ||
+ (g_cts && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time"))))
+ )
{
newmaps = true;
- if(i % 2) { col = "^4*"; }
- else { col = "^5*"; }
+ if (i % 2) col = "^4*"; else col = "^5*";
}
else
{
- if(i % 2) { col = "^2"; }
- else { col = "^3"; }
+ if (i % 2) col = "^2"; else col = "^3";
}
lsmaps = sprintf("%s%s%s ", lsmaps, col, MapInfo_Map_bspname);
{
string monsterlist = "", col;
- for(int i = MON_FIRST; i <= MON_LAST; ++i)
+ for (int i = MON_FIRST; i <= MON_LAST; ++i)
{
- if(i % 2) { col = "^2"; }
- else { col = "^3"; }
+ if (i % 2) col = "^2"; else col = "^3";
monsterlist = sprintf("%s%s%s ", monsterlist, col, (get_monsterinfo(i)).netname);
}
// ladder bullshit todo
const int LADDER_FIRSTPOINT = 100;
-#define LADDER_CNT 10 // position X still gives LADDER_FIRSTPOINT/X points
-const int LADDER_SIZE = 30; // ladder shows the top X players
+#define LADDER_CNT 10 // position X still gives LADDER_FIRSTPOINT/X points
+const int LADDER_SIZE = 30; // ladder shows the top X players
string top_uids[LADDER_SIZE];
float top_scores[LADDER_SIZE];
// allow functions to be used in other code like g_world.qc and race.qc
string getrecords(float page);
-string getrankings(void);
-string getladder(void);
-string getmaplist(void);
-string getlsmaps(void);
-string getmonsterlist(void);
+string getrankings();
+string getladder();
+string getmaplist();
+string getlsmaps();
+string getmonsterlist();
#endif
float n, m;
n = m = 0;
- while(vlen(c - b) > 1)
+ while (vlen(c - b) > 1)
{
++m;
tracebox(c, mi, ma, b, MOVE_WORLDONLY, world);
++n;
- if(!trace_startsolid)
+ if (!trace_startsolid)
{
black += vlen(trace_endpos - c);
c = trace_endpos;
c = trace_endpos;
}
- if(n > 200)
- LOG_TRACE("HOLY SHIT! FullTraceFraction: ", ftos(n), " total traces, ", ftos(m), " iterations\n");
+ if (n > 200) LOG_TRACE("HOLY SHIT! FullTraceFraction: ", ftos(n), " total traces, ", ftos(m), " iterations\n");
return white / (black + white);
}
ma = '1 0 0' * w + '0 1 0' * h + dz;
o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
- if(x < world.absmin.x - w)
- return 0;
- if(y < world.absmin.y - h)
- return 0;
- if(x > world.absmax.x)
- return 0;
- if(y > world.absmax.y)
- return 0;
+ if (x < world.absmin.x - w) return 0;
+ if (y < world.absmin.y - h) return 0;
+ if (x > world.absmax.x) return 0;
+ if (y > world.absmax.y) return 0;
r = 0;
- for(i = 0; i < q; ++i)
+ for (i = 0; i < q; ++i)
{
vector v1, v2;
v1 = v2 = o + dz * i + mi;
v2_y += random() * (ma.y - mi.y);
v2_z += random() * (ma.z - mi.z);
traceline(v1, v2, MOVE_WORLDONLY, world);
- if(trace_startsolid || trace_fraction < 1)
- ++r;
+ if (trace_startsolid || trace_fraction < 1) ++r;
}
return r / q;
}
ma = '1 0 0' * w + '0 1 0' * h + dz;
o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
- if(x < world.absmin.x - w)
- return 0;
- if(y < world.absmin.y - h)
- return 0;
- if(x > world.absmax.x)
- return 0;
- if(y > world.absmax.y)
- return 0;
+ if (x < world.absmin.x - w) return 0;
+ if (y < world.absmin.y - h) return 0;
+ if (x > world.absmax.x) return 0;
+ if (y > world.absmax.y) return 0;
r = 0;
- for(i = 0; i < q; ++i)
+ for (i = 0; i < q; ++i)
{
tracebox(o + dz * i, mi, ma, o + dz * i, MOVE_WORLDONLY, world);
- if(trace_startsolid)
- ++r;
+ if (trace_startsolid) ++r;
}
return r / q;
}
{
vector a, b, mi, ma;
- q *= 4; // choose q so it matches the regular algorithm in speed
+ q *= 4; // choose q so it matches the regular algorithm in speed
q = 256 * q - 1;
// 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value
float c, i;
c = 0;
- for(i = 0; i < q; ++i)
+ for (i = 0; i < q; ++i)
{
vector v;
v.x = a.x + random() * b.x;
v.y = a.y + random() * b.y;
v.z = a.z + random() * b.z;
traceline(v, v, MOVE_WORLDONLY, world);
- if(trace_startsolid)
- ++c;
+ if (trace_startsolid) ++c;
}
return c / q;
}
float sharpen_getpixel(int x, int y)
{
- if(x < 0)
- return 0;
- if(x >= RADAR_WIDTH_MAX)
- return 0;
- if(y < 0)
- return 0;
- if(y > 2)
- return 0;
+ if (x < 0) return 0;
+ if (x >= RADAR_WIDTH_MAX) return 0;
+ if (y < 0) return 0;
+ if (y > 2) return 0;
return sharpen_buffer[x + y * RADAR_WIDTH_MAX];
}
float sharpen_get(float x, float a)
{
float sum = sharpen_getpixel(x, 1);
- if(a == 0)
- return sum;
- sum *= (8 + 1/a);
+ if (a == 0) return sum;
+ sum *= (8 + 1 / a);
sum -= sharpen_getpixel(x - 1, 0);
sum -= sharpen_getpixel(x - 1, 1);
sum -= sharpen_getpixel(x - 1, 2);
}
void sharpen_shift(int w)
{
- for(int i = 0; i < w; ++i)
+ for (int i = 0; i < w; ++i)
{
sharpen_buffer[i] = sharpen_buffer[i + RADAR_WIDTH_MAX];
sharpen_buffer[i + RADAR_WIDTH_MAX] = sharpen_buffer[i + 2 * RADAR_WIDTH_MAX];
}
void sharpen_init(int w)
{
- for(int i = 0; i < w; ++i)
+ for (int i = 0; i < w; ++i)
{
sharpen_buffer[i] = 0;
sharpen_buffer[i + RADAR_WIDTH_MAX] = 0;
}
void RadarMap_Next()
{
- if(radarmapper.count & 4)
+ if (radarmapper.count & 4)
{
localcmd("quit\n");
}
- else if(radarmapper.count & 2)
+ else if (radarmapper.count & 2)
{
localcmd(strcat("defer 1 \"sv_cmd radarmap --flags ", ftos(radarmapper.count), strcat(" --res ", ftos(radarmapper.size.x), " ", ftos(radarmapper.size.y), " --sharpen ", ftos(radarmapper.ltime), " --qual ", ftos(radarmapper.size.z)), "\"\n"));
GotoNextMap(0);
radarmapper = world;
}
void RadarMap_Think()
-{SELFPARAM();
+{
+ SELFPARAM();
// rough map entity
// cnt: current line
// size: pixel width/height
float i, x, l;
string si;
- if(self.frame == 0)
+ if (self.frame == 0)
{
// initialize
get_mi_min_max_texcoords(1);
self.maxs_z = mi_max.z - mi_min.z;
LOG_INFO("Picture mins/maxs: ", ftos(self.maxs.x), " and ", ftos(self.maxs.y), " should match\n");
self.netname = strzone(strcat("gfx/", mi_shortname, "_radar.xpm"));
- if(!(self.count & 1))
+ if (!(self.count & 1))
{
self.cnt = fopen(self.netname, FILE_READ);
- if(self.cnt < 0)
- self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.tga"), FILE_READ);
- if(self.cnt < 0)
- self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.png"), FILE_READ);
- if(self.cnt < 0)
- self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.jpg"), FILE_READ);
- if(self.cnt < 0)
- self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.tga"), FILE_READ);
- if(self.cnt < 0)
- self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.png"), FILE_READ);
- if(self.cnt < 0)
- self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.jpg"), FILE_READ);
- if(self.cnt >= 0)
+ if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.tga"), FILE_READ);
+ if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.png"), FILE_READ);
+ if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.jpg"), FILE_READ);
+ if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.tga"), FILE_READ);
+ if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.png"), FILE_READ);
+ if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.jpg"), FILE_READ);
+ if (self.cnt >= 0)
{
fclose(self.cnt);
}
}
self.cnt = fopen(self.netname, FILE_WRITE);
- if(self.cnt < 0)
+ if (self.cnt < 0)
{
LOG_INFO("Error writing ", self.netname, "\n");
remove(self);
fputs(self.cnt, "static char *RadarMap[] = {\n");
fputs(self.cnt, "/* columns rows colors chars-per-pixel */\n");
fputs(self.cnt, strcat("\"", ftos(self.size.x), " ", ftos(self.size.y), " 256 2\",\n"));
- for(i = 0; i < 256; ++i)
+ for (i = 0; i < 256; ++i)
{
- si = substring(doublehex, i*2, 2);
+ si = substring(doublehex, i * 2, 2);
fputs(self.cnt, strcat("\"", si, " c #", si, si, si, "\",\n"));
}
self.frame += 1;
self.nextthink = time;
sharpen_init(self.size.x);
}
- else if(self.frame <= self.size.y)
+ else if (self.frame <= self.size.y)
{
// fill the sharpen buffer with this line
sharpen_shift(self.size.x);
i = self.count & 24;
- switch(i)
+ switch (i)
{
case 0:
default:
- for(x = 0; x < self.size.x; ++x)
+ for (x = 0; x < self.size.x; ++x)
{
l = RadarMapAtPoint_Block(self.mins.x + x * self.maxs.x, self.mins.y + (self.size.y - self.frame) * self.maxs.y, self.maxs.x, self.maxs.y, self.mins.z, self.maxs.z, self.size.z);
sharpen_set(x, l);
}
break;
case 8:
- for(x = 0; x < self.size.x; ++x)
+ for (x = 0; x < self.size.x; ++x)
{
l = RadarMapAtPoint_Trace(self.mins.x + x * self.maxs.x, self.mins.y + (self.size.y - self.frame) * self.maxs.y, self.maxs.x, self.maxs.y, self.mins.z, self.maxs.z, self.size.z);
sharpen_set(x, l);
}
break;
case 16:
- for(x = 0; x < self.size.x; ++x)
+ for (x = 0; x < self.size.x; ++x)
{
l = RadarMapAtPoint_Sample(self.mins.x + x * self.maxs.x, self.mins.y + (self.size.y - self.frame) * self.maxs.y, self.maxs.x, self.maxs.y, self.mins.z, self.maxs.z, self.size.z);
sharpen_set(x, l);
}
break;
case 24:
- for(x = 0; x < self.size.x; ++x)
+ for (x = 0; x < self.size.x; ++x)
{
l = RadarMapAtPoint_LineBlock(self.mins.x + x * self.maxs.x, self.mins.y + (self.size.y - self.frame) * self.maxs.y, self.maxs.x, self.maxs.y, self.mins.z, self.maxs.z, self.size.z);
sharpen_set(x, l);
}
// do we have enough lines?
- if(self.frame >= 2)
+ if (self.frame >= 2)
{
// write a pixel line
fputs(self.cnt, "\"");
- for(x = 0; x < self.size.x; ++x)
+ for (x = 0; x < self.size.x; ++x)
{
l = sharpen_get(x, self.ltime);
fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));
}
- if(self.frame == self.size.y)
+ if (self.frame == self.size.y)
+ {
fputs(self.cnt, "\"\n");
+ }
else
{
fputs(self.cnt, "\",\n");
}
// is this the last line? then write back the missing line
- if(self.frame == self.size.y)
+ if (self.frame == self.size.y)
{
sharpen_shift(self.size.x);
// write a pixel line
fputs(self.cnt, "\"");
- for(x = 0; x < self.size.x; ++x)
+ for (x = 0; x < self.size.x; ++x)
{
l = sharpen_get(x, self.ltime);
fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));
}
- if(self.frame == self.size.y)
+ if (self.frame == self.size.y)
+ {
fputs(self.cnt, "\"\n");
+ }
else
{
fputs(self.cnt, "\",\n");
{
float i;
- if(!radarmapper)
+ if (!radarmapper)
{
- radarmapper = spawn();
- radarmapper.classname = "radarmapper";
+ radarmapper = new(radarmapper);
radarmapper.think = RadarMap_Think;
radarmapper.nextthink = time;
- radarmapper.count = 8; // default to the --trace method, as it is faster now
+ radarmapper.count = 8; // default to the --trace method, as it is faster now
radarmapper.ltime = 1;
radarmapper.size = '512 512 1';
- for(i = 1; i < argc; ++i)
+ for (i = 1; i < argc; ++i)
{
- switch(argv(i))
+ switch (argv(i))
{
- case "--force": { radarmapper.count |= 1; break; }
- case "--loop": { radarmapper.count |= 2; break; }
- case "--quit": { radarmapper.count |= 4; break; }
- case "--block": { radarmapper.count &= ~24; break; }
- case "--trace": { radarmapper.count &= ~24; radarmapper.count |= 8; break; }
- case "--sample": { radarmapper.count &= ~24; radarmapper.count |= 16; break; }
- case "--lineblock": { radarmapper.count |= 24; break; }
- case "--flags": { ++i; radarmapper.count = stof(argv(i)); break; } // for the recursive call
- case "--sharpen": { ++i; radarmapper.ltime = stof(argv(i)); break; } // for the recursive call
- case "--res": // minor alias
- case "--resolution": { ++i; radarmapper.size_x = stof(argv(i)); ++i; radarmapper.size_y = stof(argv(i)); break; }
- case "--qual": // minor alias
- case "--quality": { ++i; radarmapper.size_z = stof(argv(i)); break; }
+ case "--force":
+ { radarmapper.count |= 1;
+ break;
+ }
+ case "--loop":
+ { radarmapper.count |= 2;
+ break;
+ }
+ case "--quit":
+ { radarmapper.count |= 4;
+ break;
+ }
+ case "--block":
+ { radarmapper.count &= ~24;
+ break;
+ }
+ case "--trace":
+ { radarmapper.count &= ~24;
+ radarmapper.count |= 8;
+ break;
+ }
+ case "--sample":
+ { radarmapper.count &= ~24;
+ radarmapper.count |= 16;
+ break;
+ }
+ case "--lineblock":
+ { radarmapper.count |= 24;
+ break;
+ }
+ case "--flags":
+ { ++i;
+ radarmapper.count = stof(argv(i));
+ break;
+ } // for the recursive call
+ case "--sharpen":
+ { ++i;
+ radarmapper.ltime = stof(argv(i));
+ break;
+ } // for the recursive call
+ case "--res": // minor alias
+ case "--resolution":
+ { ++i;
+ radarmapper.size_x = stof(argv(i));
+ ++i;
+ radarmapper.size_y = stof(argv(i));
+ break;
+ }
+ case "--qual": // minor alias
+ case "--quality":
+ { ++i;
+ radarmapper.size_z = stof(argv(i));
+ break;
+ }
default:
i = argc;
}
}
- if(radarmapper) // after doing the arguments, see if we successfully went forward.
+ if (radarmapper) // after doing the arguments, see if we successfully went forward.
{
LOG_INFO("Radarmap entity spawned.\n");
- return true; // if so, don't print usage.
+ return true; // if so, don't print usage.
}
}
#include "../../common/monsters/sv_monsters.qh"
-void PutObserverInServer (void);
+void PutObserverInServer();
// =====================================================
// Server side game commands code, reworked by Samual
// used by GameCommand_make_mapinfo()
void make_mapinfo_Think()
-{SELFPARAM();
- if(MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
+{
+ SELFPARAM();
+ if (MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
{
LOG_INFO("Done rebuiling mapinfos.\n");
MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
float update;
float lim;
- if(delta == 0)
- return;
- if(autocvar_timelimit < 0)
- return;
+ if (delta == 0) return;
+ if (autocvar_timelimit < 0) return;
- if(mi <= 10)
- mi = 10; // at least ten sec in the future
+ if (mi <= 10) mi = 10; // at least ten sec in the future
cur = time - game_starttime;
- if(cur > 0)
- mi += cur; // from current time!
+ if (cur > 0) mi += cur; // from current time!
lim = autocvar_timelimit * 60;
- if(delta > 0)
+ if (delta > 0)
{
- if(lim == 0)
- return; // cannot increase any further
- else if(lim < ma)
- update = min(ma, lim + delta);
- else // already above maximum: FAIL
+ if (lim == 0) return; // cannot increase any further
+ else if (lim < ma) update = min(ma, lim + delta);
+ else // already above maximum: FAIL
return;
}
else
{
- if(lim == 0) // infinite: try reducing to max, if we are allowed to
+ if (lim == 0) // infinite: try reducing to max, if we are allowed to
update = max(mi, ma);
- else if(lim > mi) // above minimum: decrease
+ else if (lim > mi) // above minimum: decrease
update = max(mi, lim + delta);
- else // already below minimum: FAIL
+ else // already below minimum: FAIL
return;
}
void GameCommand_adminmsg(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
string successful, t;
successful = string_null;
- if((targets) && (admin_message))
+ if ((targets) && (admin_message))
{
- for (;targets;)
+ for ( ; targets; )
{
- t = car(targets); targets = cdr(targets);
+ t = car(targets);
+ targets = cdr(targets);
// Check to see if the player is a valid target
client = GetFilteredEntity(t);
accepted = VerifyClientEntity(client, true, false);
- if(accepted <= 0)
+ if (accepted <= 0)
{
LOG_INFO("adminmsg: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".\n"));
continue;
}
// send the centerprint/console print or infomessage
- if(infobartime)
+ if (infobartime)
{
stuffcmd(client, sprintf("\ninfobar %f \"%s\"\n", infobartime, MakeConsoleSafe(admin_message)));
}
continue;
}
- if(successful)
- bprint("Successfully sent message '", admin_message, "' to ", successful, ".\n");
- else
- LOG_INFO("No players given (", original_targets, ") could receive the message.\n");
+ if (successful) bprint("Successfully sent message '", admin_message, "' to ", successful, ".\n");
+ else LOG_INFO("No players given (", original_targets, ") could receive the message.\n");
return;
}
void GameCommand_allready(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
}
void GameCommand_allspec(float request, float argc)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
FOR_EACH_REALPLAYER(client)
{
- if (client.caplayer)
- client.caplayer = 0;
+ if (client.caplayer) client.caplayer = 0;
WITH(entity, self, client, PutObserverInServer());
++i;
}
- if(i) { bprint(strcat("Successfully forced all (", ftos(i), ") players to spectate", (reason ? strcat(" for reason: '", reason, "'") : ""), ".\n")); }
- else { LOG_INFO("No players found to spectate.\n"); }
+ if (i) bprint(strcat("Successfully forced all (", ftos(i), ") players to spectate", (reason ? strcat(" for reason: '", reason, "'") : ""), ".\n"));
+ else LOG_INFO("No players found to spectate.\n");
return;
}
}
void GameCommand_anticheat(float request, float argc)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
entity client = GetIndexedEntity(argc, 1);
float accepted = VerifyClientEntity(client, false, false);
- if(accepted > 0)
+ if (accepted > 0)
{
WITH(entity, self, client, anticheat_report());
return;
void GameCommand_bbox(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
LOG_INFO("Solid bounding box size:");
tracebox('1 0 0' * world.absmin.x,
- '0 1 0' * world.absmin.y + '0 0 1' * world.absmin.z,
- '0 1 0' * world.absmax.y + '0 0 1' * world.absmax.z,
- '1 0 0' * world.absmax.x,
- MOVE_WORLDONLY,
- world);
- if(trace_startsolid)
- LOG_INFO(" ", ftos(world.absmin.x));
- else
- LOG_INFO(" ", ftos(trace_endpos.x));
+ '0 1 0' * world.absmin.y + '0 0 1' * world.absmin.z,
+ '0 1 0' * world.absmax.y + '0 0 1' * world.absmax.z,
+ '1 0 0' * world.absmax.x,
+ MOVE_WORLDONLY,
+ world);
+ if (trace_startsolid) LOG_INFO(" ", ftos(world.absmin.x));
+ else LOG_INFO(" ", ftos(trace_endpos.x));
tracebox('0 1 0' * world.absmin.y,
- '1 0 0' * world.absmin.x + '0 0 1' * world.absmin.z,
- '1 0 0' * world.absmax.x + '0 0 1' * world.absmax.z,
- '0 1 0' * world.absmax.y,
- MOVE_WORLDONLY,
- world);
- if(trace_startsolid)
- LOG_INFO(" ", ftos(world.absmin.y));
- else
- LOG_INFO(" ", ftos(trace_endpos.y));
+ '1 0 0' * world.absmin.x + '0 0 1' * world.absmin.z,
+ '1 0 0' * world.absmax.x + '0 0 1' * world.absmax.z,
+ '0 1 0' * world.absmax.y,
+ MOVE_WORLDONLY,
+ world);
+ if (trace_startsolid) LOG_INFO(" ", ftos(world.absmin.y));
+ else LOG_INFO(" ", ftos(trace_endpos.y));
tracebox('0 0 1' * world.absmin.z,
- '1 0 0' * world.absmin.x + '0 1 0' * world.absmin.y,
- '1 0 0' * world.absmax.x + '0 1 0' * world.absmax.y,
- '0 0 1' * world.absmax.z,
- MOVE_WORLDONLY,
- world);
- if(trace_startsolid)
- LOG_INFO(" ", ftos(world.absmin.z));
- else
- LOG_INFO(" ", ftos(trace_endpos.z));
+ '1 0 0' * world.absmin.x + '0 1 0' * world.absmin.y,
+ '1 0 0' * world.absmax.x + '0 1 0' * world.absmax.y,
+ '0 0 1' * world.absmax.z,
+ MOVE_WORLDONLY,
+ world);
+ if (trace_startsolid) LOG_INFO(" ", ftos(world.absmin.z));
+ else LOG_INFO(" ", ftos(trace_endpos.z));
tracebox('1 0 0' * world.absmax.x,
- '0 1 0' * world.absmin.y + '0 0 1' * world.absmin.z,
- '0 1 0' * world.absmax.y + '0 0 1' * world.absmax.z,
- '1 0 0' * world.absmin.x,
- MOVE_WORLDONLY,
- world);
- if(trace_startsolid)
- LOG_INFO(" ", ftos(world.absmax.x));
- else
- LOG_INFO(" ", ftos(trace_endpos.x));
+ '0 1 0' * world.absmin.y + '0 0 1' * world.absmin.z,
+ '0 1 0' * world.absmax.y + '0 0 1' * world.absmax.z,
+ '1 0 0' * world.absmin.x,
+ MOVE_WORLDONLY,
+ world);
+ if (trace_startsolid) LOG_INFO(" ", ftos(world.absmax.x));
+ else LOG_INFO(" ", ftos(trace_endpos.x));
tracebox('0 1 0' * world.absmax.y,
- '1 0 0' * world.absmin.x + '0 0 1' * world.absmin.z,
- '1 0 0' * world.absmax.x + '0 0 1' * world.absmax.z,
- '0 1 0' * world.absmin.y,
- MOVE_WORLDONLY,
- world);
- if(trace_startsolid)
- LOG_INFO(" ", ftos(world.absmax.y));
- else
- LOG_INFO(" ", ftos(trace_endpos.y));
+ '1 0 0' * world.absmin.x + '0 0 1' * world.absmin.z,
+ '1 0 0' * world.absmax.x + '0 0 1' * world.absmax.z,
+ '0 1 0' * world.absmin.y,
+ MOVE_WORLDONLY,
+ world);
+ if (trace_startsolid) LOG_INFO(" ", ftos(world.absmax.y));
+ else LOG_INFO(" ", ftos(trace_endpos.y));
tracebox('0 0 1' * world.absmax.z,
- '1 0 0' * world.absmin.x + '0 1 0' * world.absmin.y,
- '1 0 0' * world.absmax.x + '0 1 0' * world.absmax.y,
- '0 0 1' * world.absmin.z,
- MOVE_WORLDONLY,
- world);
- if(trace_startsolid)
- LOG_INFO(" ", ftos(world.absmax.z));
- else
- LOG_INFO(" ", ftos(trace_endpos.z));
+ '1 0 0' * world.absmin.x + '0 1 0' * world.absmin.y,
+ '1 0 0' * world.absmax.x + '0 1 0' * world.absmax.y,
+ '0 0 1' * world.absmin.z,
+ MOVE_WORLDONLY,
+ world);
+ if (trace_startsolid) LOG_INFO(" ", ftos(world.absmax.z));
+ else LOG_INFO(" ", ftos(trace_endpos.z));
LOG_INFO("\n");
return;
void GameCommand_bot_cmd(float request, float argc, string command)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
entity bot;
- if(argv(1) == "reset")
+ if (argv(1) == "reset")
{
bot_resetqueues();
return;
}
- else if(argv(1) == "setbots")
+ else if (argv(1) == "setbots")
{
cvar_settemp("bot_vs_human", "0");
cvar_settemp("minplayers", "0");
cvar_settemp("bot_number", "0");
bot_fixcount();
cvar_settemp("bot_number", argv(2));
- if(!bot_fixcount())
- LOG_INFO("Sorry, could not set requested bot count\n");
+ if (!bot_fixcount()) LOG_INFO("Sorry, could not set requested bot count\n");
return;
}
- else if(argv(1) == "load" && argc == 3)
+ else if (argv(1) == "load" && argc == 3)
{
float fh, i;
string s;
fh = fopen(argv(2), FILE_READ);
- if(fh < 0)
+ if (fh < 0)
{
LOG_INFO("cannot open the file\n");
return;
}
i = 0;
- while((s = fgets(fh)))
+ while ((s = fgets(fh)))
{
argc = tokenize_console(s);
- if(argc >= 3 && argv(0) == "sv_cmd" && argv(1) == "bot_cmd")
+ if (argc >= 3 && argv(0) == "sv_cmd" && argv(1) == "bot_cmd")
{
- if(argv(2) == "reset")
+ if (argv(2) == "reset")
{
bot_resetqueues();
}
- else if(argv(2) == "setbots")
+ else if (argv(2) == "setbots")
{
cvar_settemp("bot_vs_human", "0");
cvar_settemp("minplayers", "0");
cvar_settemp("bot_number", "0");
bot_fixcount();
cvar_settemp("bot_number", argv(3));
- if(!bot_fixcount())
- LOG_INFO("Sorry, could not set requested bot count\n");
+ if (!bot_fixcount()) LOG_INFO("Sorry, could not set requested bot count\n");
}
else
{
// let's start at token 2 so we can skip sv_cmd bot_cmd
bot = find_bot_by_number(stof(argv(2)));
- if(bot == world)
- bot = find_bot_by_name(argv(2));
- if(bot)
- bot_queuecommand(bot, substring(s, argv_start_index(3), -1));
+ if (bot == world) bot = find_bot_by_name(argv(2));
+ if (bot) bot_queuecommand(bot, substring(s, argv_start_index(3), -1));
}
}
else
+ {
localcmd(strcat(s, "\n"));
+ }
++i;
}
fclose(fh);
return;
}
- else if(argv(1) == "help")
+ else if (argv(1) == "help")
{
- if(argv(2))
- bot_cmdhelp(argv(2));
- else
- bot_list_commands();
+ if (argv(2)) bot_cmdhelp(argv(2));
+ else bot_list_commands();
return;
}
- else if(argc >= 3) // this comes last
+ else if (argc >= 3) // this comes last
{
bot = find_bot_by_number(stof(argv(1)));
- if(bot == world)
- bot = find_bot_by_name(argv(1));
- if(bot)
+ if (bot == world) bot = find_bot_by_name(argv(1));
+ if (bot)
{
LOG_INFO(strcat("Command '", substring(command, argv_start_index(2), -1), "' sent to bot ", bot.netname, "\n"));
bot_queuecommand(bot, substring(command, argv_start_index(2), -1));
return;
}
else
- LOG_INFO(strcat("Error: Can't find bot with the name or id '", argv(1),"' - Did you mistype the command?\n")); // don't return so that usage is shown
+ {
+ LOG_INFO(strcat("Error: Can't find bot with the name or id '", argv(1), "' - Did you mistype the command?\n")); // don't return so that usage is shown
+ }
}
}
void GameCommand_cointoss(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
void GameCommand_database(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argc == 3)
+ if (argc == 3)
{
- if(argv(1) == "save")
+ if (argv(1) == "save")
{
db_save(ServerProgsDB, argv(2));
LOG_INFO(strcat("Copied serverprogs database to '", argv(2), "' in the data directory.\n"));
return;
}
- else if(argv(1) == "dump")
+ else if (argv(1) == "dump")
{
db_dump(ServerProgsDB, argv(2));
- LOG_INFO("DB dumped.\n"); // wtf does this do?
+ LOG_INFO("DB dumped.\n"); // wtf does this do?
return;
}
- else if(argv(1) == "load")
+ else if (argv(1) == "load")
{
db_close(ServerProgsDB);
ServerProgsDB = db_load(argv(2));
void GameCommand_defer_clear(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
entity client;
float accepted;
- if(argc >= 2)
+ if (argc >= 2)
{
client = GetIndexedEntity(argc, 1);
accepted = VerifyClientEntity(client, true, false);
- if(accepted > 0)
+ if (accepted > 0)
{
stuffcmd(client, "defer clear\n");
LOG_INFO("defer clear stuffed to ", client.netname, "\n");
void GameCommand_defer_clear_all(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
GameCommand_defer_clear(CMD_REQUEST_COMMAND, argc);
++i;
}
- if(i) { LOG_INFO(strcat("Successfully stuffed defer clear to all clients (", ftos(i), ")\n")); } // should a message be added if no players were found?
+ if (i) LOG_INFO(strcat("Successfully stuffed defer clear to all clients (", ftos(i), ")\n")); // should a message be added if no players were found?
return;
}
void GameCommand_delrec(float request, float argc) // perhaps merge later with records and printstats and such?
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1))
+ if (argv(1))
{
- if(argv(2))
- race_deleteTime(argv(2), stof(argv(1)));
- else
- race_deleteTime(GetMapname(), stof(argv(1)));
+ if (argv(2)) race_deleteTime(argv(2), stof(argv(1)));
+ else race_deleteTime(GetMapname(), stof(argv(1)));
return;
}
}
void GameCommand_effectindexdump(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
d = db_create();
LOG_INFO("begin of effects list\n");
- db_put(d, "TE_GUNSHOT", "1"); LOG_INFO("effect TE_GUNSHOT is ", ftos(_particleeffectnum("TE_GUNSHOT")), "\n");
- db_put(d, "TE_GUNSHOTQUAD", "1"); LOG_INFO("effect TE_GUNSHOTQUAD is ", ftos(_particleeffectnum("TE_GUNSHOTQUAD")), "\n");
- db_put(d, "TE_SPIKE", "1"); LOG_INFO("effect TE_SPIKE is ", ftos(_particleeffectnum("TE_SPIKE")), "\n");
- db_put(d, "TE_SPIKEQUAD", "1"); LOG_INFO("effect TE_SPIKEQUAD is ", ftos(_particleeffectnum("TE_SPIKEQUAD")), "\n");
- db_put(d, "TE_SUPERSPIKE", "1"); LOG_INFO("effect TE_SUPERSPIKE is ", ftos(_particleeffectnum("TE_SUPERSPIKE")), "\n");
- db_put(d, "TE_SUPERSPIKEQUAD", "1"); LOG_INFO("effect TE_SUPERSPIKEQUAD is ", ftos(_particleeffectnum("TE_SUPERSPIKEQUAD")), "\n");
- db_put(d, "TE_WIZSPIKE", "1"); LOG_INFO("effect TE_WIZSPIKE is ", ftos(_particleeffectnum("TE_WIZSPIKE")), "\n");
- db_put(d, "TE_KNIGHTSPIKE", "1"); LOG_INFO("effect TE_KNIGHTSPIKE is ", ftos(_particleeffectnum("TE_KNIGHTSPIKE")), "\n");
- db_put(d, "TE_EXPLOSION", "1"); LOG_INFO("effect TE_EXPLOSION is ", ftos(_particleeffectnum("TE_EXPLOSION")), "\n");
- db_put(d, "TE_EXPLOSIONQUAD", "1"); LOG_INFO("effect TE_EXPLOSIONQUAD is ", ftos(_particleeffectnum("TE_EXPLOSIONQUAD")), "\n");
- db_put(d, "TE_TAREXPLOSION", "1"); LOG_INFO("effect TE_TAREXPLOSION is ", ftos(_particleeffectnum("TE_TAREXPLOSION")), "\n");
- db_put(d, "TE_TELEPORT", "1"); LOG_INFO("effect TE_TELEPORT is ", ftos(_particleeffectnum("TE_TELEPORT")), "\n");
- db_put(d, "TE_LAVASPLASH", "1"); LOG_INFO("effect TE_LAVASPLASH is ", ftos(_particleeffectnum("TE_LAVASPLASH")), "\n");
- db_put(d, "TE_SMALLFLASH", "1"); LOG_INFO("effect TE_SMALLFLASH is ", ftos(_particleeffectnum("TE_SMALLFLASH")), "\n");
- db_put(d, "TE_FLAMEJET", "1"); LOG_INFO("effect TE_FLAMEJET is ", ftos(_particleeffectnum("TE_FLAMEJET")), "\n");
- db_put(d, "EF_FLAME", "1"); LOG_INFO("effect EF_FLAME is ", ftos(_particleeffectnum("EF_FLAME")), "\n");
- db_put(d, "TE_BLOOD", "1"); LOG_INFO("effect TE_BLOOD is ", ftos(_particleeffectnum("TE_BLOOD")), "\n");
- db_put(d, "TE_SPARK", "1"); LOG_INFO("effect TE_SPARK is ", ftos(_particleeffectnum("TE_SPARK")), "\n");
- db_put(d, "TE_PLASMABURN", "1"); LOG_INFO("effect TE_PLASMABURN is ", ftos(_particleeffectnum("TE_PLASMABURN")), "\n");
- db_put(d, "TE_TEI_G3", "1"); LOG_INFO("effect TE_TEI_G3 is ", ftos(_particleeffectnum("TE_TEI_G3")), "\n");
- db_put(d, "TE_TEI_SMOKE", "1"); LOG_INFO("effect TE_TEI_SMOKE is ", ftos(_particleeffectnum("TE_TEI_SMOKE")), "\n");
- db_put(d, "TE_TEI_BIGEXPLOSION", "1"); LOG_INFO("effect TE_TEI_BIGEXPLOSION is ", ftos(_particleeffectnum("TE_TEI_BIGEXPLOSION")), "\n");
- db_put(d, "TE_TEI_PLASMAHIT", "1"); LOG_INFO("effect TE_TEI_PLASMAHIT is ", ftos(_particleeffectnum("TE_TEI_PLASMAHIT")), "\n");
- db_put(d, "EF_STARDUST", "1"); LOG_INFO("effect EF_STARDUST is ", ftos(_particleeffectnum("EF_STARDUST")), "\n");
- db_put(d, "TR_ROCKET", "1"); LOG_INFO("effect TR_ROCKET is ", ftos(_particleeffectnum("TR_ROCKET")), "\n");
- db_put(d, "TR_GRENADE", "1"); LOG_INFO("effect TR_GRENADE is ", ftos(_particleeffectnum("TR_GRENADE")), "\n");
- db_put(d, "TR_BLOOD", "1"); LOG_INFO("effect TR_BLOOD is ", ftos(_particleeffectnum("TR_BLOOD")), "\n");
- db_put(d, "TR_WIZSPIKE", "1"); LOG_INFO("effect TR_WIZSPIKE is ", ftos(_particleeffectnum("TR_WIZSPIKE")), "\n");
- db_put(d, "TR_SLIGHTBLOOD", "1"); LOG_INFO("effect TR_SLIGHTBLOOD is ", ftos(_particleeffectnum("TR_SLIGHTBLOOD")), "\n");
- db_put(d, "TR_KNIGHTSPIKE", "1"); LOG_INFO("effect TR_KNIGHTSPIKE is ", ftos(_particleeffectnum("TR_KNIGHTSPIKE")), "\n");
- db_put(d, "TR_VORESPIKE", "1"); LOG_INFO("effect TR_VORESPIKE is ", ftos(_particleeffectnum("TR_VORESPIKE")), "\n");
- db_put(d, "TR_NEHAHRASMOKE", "1"); LOG_INFO("effect TR_NEHAHRASMOKE is ", ftos(_particleeffectnum("TR_NEHAHRASMOKE")), "\n");
- db_put(d, "TR_NEXUIZPLASMA", "1"); LOG_INFO("effect TR_NEXUIZPLASMA is ", ftos(_particleeffectnum("TR_NEXUIZPLASMA")), "\n");
- db_put(d, "TR_GLOWTRAIL", "1"); LOG_INFO("effect TR_GLOWTRAIL is ", ftos(_particleeffectnum("TR_GLOWTRAIL")), "\n");
- db_put(d, "TR_SEEKER", "1"); LOG_INFO("effect TR_SEEKER is ", ftos(_particleeffectnum("TR_SEEKER")), "\n");
- db_put(d, "SVC_PARTICLE", "1"); LOG_INFO("effect SVC_PARTICLE is ", ftos(_particleeffectnum("SVC_PARTICLE")), "\n");
+ db_put(d, "TE_GUNSHOT", "1");
+ LOG_INFO("effect TE_GUNSHOT is ", ftos(_particleeffectnum("TE_GUNSHOT")), "\n");
+ db_put(d, "TE_GUNSHOTQUAD", "1");
+ LOG_INFO("effect TE_GUNSHOTQUAD is ", ftos(_particleeffectnum("TE_GUNSHOTQUAD")), "\n");
+ db_put(d, "TE_SPIKE", "1");
+ LOG_INFO("effect TE_SPIKE is ", ftos(_particleeffectnum("TE_SPIKE")), "\n");
+ db_put(d, "TE_SPIKEQUAD", "1");
+ LOG_INFO("effect TE_SPIKEQUAD is ", ftos(_particleeffectnum("TE_SPIKEQUAD")), "\n");
+ db_put(d, "TE_SUPERSPIKE", "1");
+ LOG_INFO("effect TE_SUPERSPIKE is ", ftos(_particleeffectnum("TE_SUPERSPIKE")), "\n");
+ db_put(d, "TE_SUPERSPIKEQUAD", "1");
+ LOG_INFO("effect TE_SUPERSPIKEQUAD is ", ftos(_particleeffectnum("TE_SUPERSPIKEQUAD")), "\n");
+ db_put(d, "TE_WIZSPIKE", "1");
+ LOG_INFO("effect TE_WIZSPIKE is ", ftos(_particleeffectnum("TE_WIZSPIKE")), "\n");
+ db_put(d, "TE_KNIGHTSPIKE", "1");
+ LOG_INFO("effect TE_KNIGHTSPIKE is ", ftos(_particleeffectnum("TE_KNIGHTSPIKE")), "\n");
+ db_put(d, "TE_EXPLOSION", "1");
+ LOG_INFO("effect TE_EXPLOSION is ", ftos(_particleeffectnum("TE_EXPLOSION")), "\n");
+ db_put(d, "TE_EXPLOSIONQUAD", "1");
+ LOG_INFO("effect TE_EXPLOSIONQUAD is ", ftos(_particleeffectnum("TE_EXPLOSIONQUAD")), "\n");
+ db_put(d, "TE_TAREXPLOSION", "1");
+ LOG_INFO("effect TE_TAREXPLOSION is ", ftos(_particleeffectnum("TE_TAREXPLOSION")), "\n");
+ db_put(d, "TE_TELEPORT", "1");
+ LOG_INFO("effect TE_TELEPORT is ", ftos(_particleeffectnum("TE_TELEPORT")), "\n");
+ db_put(d, "TE_LAVASPLASH", "1");
+ LOG_INFO("effect TE_LAVASPLASH is ", ftos(_particleeffectnum("TE_LAVASPLASH")), "\n");
+ db_put(d, "TE_SMALLFLASH", "1");
+ LOG_INFO("effect TE_SMALLFLASH is ", ftos(_particleeffectnum("TE_SMALLFLASH")), "\n");
+ db_put(d, "TE_FLAMEJET", "1");
+ LOG_INFO("effect TE_FLAMEJET is ", ftos(_particleeffectnum("TE_FLAMEJET")), "\n");
+ db_put(d, "EF_FLAME", "1");
+ LOG_INFO("effect EF_FLAME is ", ftos(_particleeffectnum("EF_FLAME")), "\n");
+ db_put(d, "TE_BLOOD", "1");
+ LOG_INFO("effect TE_BLOOD is ", ftos(_particleeffectnum("TE_BLOOD")), "\n");
+ db_put(d, "TE_SPARK", "1");
+ LOG_INFO("effect TE_SPARK is ", ftos(_particleeffectnum("TE_SPARK")), "\n");
+ db_put(d, "TE_PLASMABURN", "1");
+ LOG_INFO("effect TE_PLASMABURN is ", ftos(_particleeffectnum("TE_PLASMABURN")), "\n");
+ db_put(d, "TE_TEI_G3", "1");
+ LOG_INFO("effect TE_TEI_G3 is ", ftos(_particleeffectnum("TE_TEI_G3")), "\n");
+ db_put(d, "TE_TEI_SMOKE", "1");
+ LOG_INFO("effect TE_TEI_SMOKE is ", ftos(_particleeffectnum("TE_TEI_SMOKE")), "\n");
+ db_put(d, "TE_TEI_BIGEXPLOSION", "1");
+ LOG_INFO("effect TE_TEI_BIGEXPLOSION is ", ftos(_particleeffectnum("TE_TEI_BIGEXPLOSION")), "\n");
+ db_put(d, "TE_TEI_PLASMAHIT", "1");
+ LOG_INFO("effect TE_TEI_PLASMAHIT is ", ftos(_particleeffectnum("TE_TEI_PLASMAHIT")), "\n");
+ db_put(d, "EF_STARDUST", "1");
+ LOG_INFO("effect EF_STARDUST is ", ftos(_particleeffectnum("EF_STARDUST")), "\n");
+ db_put(d, "TR_ROCKET", "1");
+ LOG_INFO("effect TR_ROCKET is ", ftos(_particleeffectnum("TR_ROCKET")), "\n");
+ db_put(d, "TR_GRENADE", "1");
+ LOG_INFO("effect TR_GRENADE is ", ftos(_particleeffectnum("TR_GRENADE")), "\n");
+ db_put(d, "TR_BLOOD", "1");
+ LOG_INFO("effect TR_BLOOD is ", ftos(_particleeffectnum("TR_BLOOD")), "\n");
+ db_put(d, "TR_WIZSPIKE", "1");
+ LOG_INFO("effect TR_WIZSPIKE is ", ftos(_particleeffectnum("TR_WIZSPIKE")), "\n");
+ db_put(d, "TR_SLIGHTBLOOD", "1");
+ LOG_INFO("effect TR_SLIGHTBLOOD is ", ftos(_particleeffectnum("TR_SLIGHTBLOOD")), "\n");
+ db_put(d, "TR_KNIGHTSPIKE", "1");
+ LOG_INFO("effect TR_KNIGHTSPIKE is ", ftos(_particleeffectnum("TR_KNIGHTSPIKE")), "\n");
+ db_put(d, "TR_VORESPIKE", "1");
+ LOG_INFO("effect TR_VORESPIKE is ", ftos(_particleeffectnum("TR_VORESPIKE")), "\n");
+ db_put(d, "TR_NEHAHRASMOKE", "1");
+ LOG_INFO("effect TR_NEHAHRASMOKE is ", ftos(_particleeffectnum("TR_NEHAHRASMOKE")), "\n");
+ db_put(d, "TR_NEXUIZPLASMA", "1");
+ LOG_INFO("effect TR_NEXUIZPLASMA is ", ftos(_particleeffectnum("TR_NEXUIZPLASMA")), "\n");
+ db_put(d, "TR_GLOWTRAIL", "1");
+ LOG_INFO("effect TR_GLOWTRAIL is ", ftos(_particleeffectnum("TR_GLOWTRAIL")), "\n");
+ db_put(d, "TR_SEEKER", "1");
+ LOG_INFO("effect TR_SEEKER is ", ftos(_particleeffectnum("TR_SEEKER")), "\n");
+ db_put(d, "SVC_PARTICLE", "1");
+ LOG_INFO("effect SVC_PARTICLE is ", ftos(_particleeffectnum("SVC_PARTICLE")), "\n");
fh = fopen("effectinfo.txt", FILE_READ);
- while((s = fgets(fh)))
+ while ((s = fgets(fh)))
{
tokenize_console(s);
- if(argv(0) == "effect")
+ if (argv(0) == "effect")
{
- if(db_get(d, argv(1)) != "1")
+ if (db_get(d, argv(1)) != "1")
{
int i = _particleeffectnum(argv(1));
- if(i >= 0)
- LOG_INFO("effect ", argv(1), " is ", ftos(i), "\n");
+ if (i >= 0) LOG_INFO("effect ", argv(1), " is ", ftos(i), "\n");
db_put(d, argv(1), "1");
}
}
void GameCommand_extendmatchtime(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
void GameCommand_find(float request, float argc) // is this even needed? We have prvm_edicts command and such ANYWAY
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
entity client;
- for(client = world; (client = find(client, classname, argv(1))); )
+ for (client = world; (client = find(client, classname, argv(1))); )
LOG_INFO(etos(client), "\n");
return;
void GameCommand_gametype(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1) != "")
+ if (argv(1) != "")
{
string s = argv(1);
float t = MapInfo_Type_FromString(s), tsave = MapInfo_CurrentGametype();
- if(t)
+ if (t)
{
MapInfo_SwitchGameType(t);
MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
- if(MapInfo_count > 0)
+ if (MapInfo_count > 0)
{
// update lsmaps in case the gametype changed, this way people can easily list maps for it
- if(lsmaps_reply != "") { strunzone(lsmaps_reply); }
+ if (lsmaps_reply != "") strunzone(lsmaps_reply);
lsmaps_reply = strzone(getlsmaps());
bprint("Game type successfully switched to ", s, "\n");
}
}
}
else
+ {
bprint("Game type switch to ", s, " failed: this type does not exist!\n");
+ }
return;
}
void GameCommand_gettaginfo(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
float i;
vector v;
- if(argc >= 4)
+ if (argc >= 4)
{
tmp_entity = spawn();
- if(argv(1) == "w")
- _setmodel(tmp_entity, (nextent(world)).weaponentity.model);
+ if (argv(1) == "w")
+ {
+ .entity weaponentity = weaponentities[0];
+ _setmodel(tmp_entity, (nextent(world)).(weaponentity).model);
+ }
else
{
precache_model(argv(1));
_setmodel(tmp_entity, argv(1));
}
tmp_entity.frame = stof(argv(2));
- if(substring(argv(3), 0, 1) == "#")
- i = stof(substring(argv(3), 1, -1));
- else
- i = gettagindex(tmp_entity, argv(3));
- if(i)
+ if (substring(argv(3), 0, 1) == "#") i = stof(substring(argv(3), 1, -1));
+ else i = gettagindex(tmp_entity, argv(3));
+ if (i)
{
v = gettaginfo(tmp_entity, i);
LOG_INFO("model ", tmp_entity.model, " frame ", ftos(tmp_entity.frame), " tag ", gettaginfo_name);
LOG_INFO(" forward = ", ftos(gettaginfo_forward.x), " ", ftos(gettaginfo_forward.y), " ", ftos(gettaginfo_forward.z), "\n");
LOG_INFO(" right = ", ftos(gettaginfo_right.x), " ", ftos(gettaginfo_right.y), " ", ftos(gettaginfo_right.z), "\n");
LOG_INFO(" up = ", ftos(gettaginfo_up.x), " ", ftos(gettaginfo_up.y), " ", ftos(gettaginfo_up.z), "\n");
- if(argc >= 6)
+ if (argc >= 6)
{
v.y = -v.y;
localcmd(strcat(argv(4), vtos(v), argv(5), "\n"));
}
}
else
+ {
LOG_INFO("bone not found\n");
+ }
remove(tmp_entity);
return;
void GameCommand_animbench(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
entity tmp_entity;
- if(argc >= 4)
+ if (argc >= 4)
{
tmp_entity = spawn();
- if(argv(1) == "w")
- _setmodel(tmp_entity, (nextent(world)).weaponentity.model);
+ if (argv(1) == "w")
+ {
+ .entity weaponentity = weaponentities[0];
+ _setmodel(tmp_entity, (nextent(world)).(weaponentity).model);
+ }
else
{
precache_model(argv(1));
float t2 = 0;
float n = 0;
- while(t1 + t2 < 1)
+ while (t1 + t2 < 1)
{
tmp_entity.frame = f1;
t0 = gettime(GETTIME_HIRES);
void GameCommand_gotomap(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(1))
+ if (argv(1))
{
LOG_INFO(GotoMap(argv(1)), "\n");
return;
void GameCommand_lockteams(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(teamplay)
+ if (teamplay)
{
lockteams = 1;
bprint("^1The teams are now locked.\n");
void GameCommand_make_mapinfo(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
entity tmp_entity;
- tmp_entity = spawn();
- tmp_entity.classname = "make_mapinfo";
+ tmp_entity = new(make_mapinfo);
tmp_entity.think = make_mapinfo_Think;
tmp_entity.nextthink = time;
MapInfo_Enumerate();
}
void GameCommand_moveplayer(float request, float argc)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
successful = string_null;
// lets see if the target(s) even actually exist.
- if((targets) && (destination))
+ if ((targets) && (destination))
{
- for (;targets;)
+ for ( ; targets; )
{
- t = car(targets); targets = cdr(targets);
+ t = car(targets);
+ targets = cdr(targets);
// Check to see if the player is a valid target
client = GetFilteredEntity(t);
accepted = VerifyClientEntity(client, false, false);
- if(accepted <= 0)
+ if (accepted <= 0)
{
LOG_INFO("moveplayer: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".\n"));
continue;
}
// Where are we putting this player?
- if(destination == "spec" || destination == "spectator")
+ if (destination == "spec" || destination == "spectator")
{
- if(!IS_SPEC(client) && !IS_OBSERVER(client))
+ if (!IS_SPEC(client) && !IS_OBSERVER(client))
{
- if (client.caplayer)
- client.caplayer = 0;
+ if (client.caplayer) client.caplayer = 0;
WITH(entity, self, client, PutObserverInServer());
successful = strcat(successful, (successful ? ", " : ""), client.netname);
}
else
{
- if(!IS_SPEC(client) && !IS_OBSERVER(client))
+ if (!IS_SPEC(client) && !IS_OBSERVER(client))
{
- if(teamplay)
+ if (teamplay)
{
// set up
float team_id;
// find the team to move the player to
team_id = Team_ColorToTeam(destination);
- if(team_id == client.team) // already on the destination team
+ if (team_id == client.team) // already on the destination team
{
// keep the forcing undone
LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") is already on the ", Team_ColoredFullName(client.team), (targets ? "^7, skipping to next player.\n" : "^7.\n"));
continue;
}
- else if(team_id == 0) // auto team
+ else if (team_id == 0) // auto team
{
CheckAllowedTeams(client);
team_id = Team_NumberToTeam(FindSmallestTeam(client, false));
client.team_forced = save;
// Check to see if the destination team is even available
- switch(team_id)
+ switch (team_id)
{
- case NUM_TEAM_1: if(c1 == -1) { LOG_INFO("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break;
- case NUM_TEAM_2: if(c2 == -1) { LOG_INFO("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break;
- case NUM_TEAM_3: if(c3 == -1) { LOG_INFO("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break;
- case NUM_TEAM_4: if(c4 == -1) { LOG_INFO("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break;
+ case NUM_TEAM_1: if (c1 == -1) { LOG_INFO("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break;
+ case NUM_TEAM_2: if (c2 == -1) { LOG_INFO("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break;
+ case NUM_TEAM_3: if (c3 == -1) { LOG_INFO("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break;
+ case NUM_TEAM_4: if (c4 == -1) { LOG_INFO("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break;
- default: LOG_INFO("Sorry, can't move player here if team ", destination, " doesn't exist.\n"); return;
+ default: LOG_INFO("Sorry, can't move player here if team ", destination, " doesn't exist.\n");
+ return;
}
// If so, lets continue and finally move the player
}
else
{
- LOG_INFO("Can't change teams if the player isn't in the game.\n"); // well technically we could, but should we allow that? :P
+ LOG_INFO("Can't change teams if the player isn't in the game.\n"); // well technically we could, but should we allow that? :P
return;
}
}
}
- if(successful)
- bprint("Successfully moved players ", successful, " to destination ", destination, ".\n");
- else
- LOG_INFO("No players given (", original_targets, ") are able to move.\n");
+ if (successful) bprint("Successfully moved players ", successful, " to destination ", destination, ".\n");
+ else LOG_INFO("No players given (", original_targets, ") are able to move.\n");
- return; // still correct parameters so return to avoid usage print
+ return; // still correct parameters so return to avoid usage print
}
}
void GameCommand_nospectators(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
blockSpectators = 1;
entity plr;
- FOR_EACH_REALCLIENT(plr) //give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
+ FOR_EACH_REALCLIENT(plr) // give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
{
- if(IS_SPEC(plr) || IS_OBSERVER(plr))
- if(!plr.caplayer)
+ if (IS_SPEC(plr) || IS_OBSERVER(plr))
{
- plr.spectatortime = time;
- Send_Notification(NOTIF_ONE_ONLY, plr, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
+ if (!plr.caplayer)
+ {
+ plr.spectatortime = time;
+ Send_Notification(NOTIF_ONE_ONLY, plr, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
+ }
}
}
bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds!\n"));
}
void GameCommand_playerdemo(float request, float argc)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argv(2) && argv(3))
+ if (argv(2) && argv(3))
{
entity client;
float i, n, accepted;
- switch(argv(1))
+ switch (argv(1))
{
case "read":
{
client = GetIndexedEntity(argc, 2);
accepted = VerifyClientEntity(client, false, true);
- if(accepted <= 0)
+ if (accepted <= 0)
{
LOG_INFO("playerdemo: read: ", GetClientErrorString(accepted, argv(2)), ".\n");
return;
client = GetIndexedEntity(argc, 2);
accepted = VerifyClientEntity(client, false, false);
- if(accepted <= 0)
+ if (accepted <= 0)
{
LOG_INFO("playerdemo: write: ", GetClientErrorString(accepted, argv(2)), ".\n");
return;
cvar_set("bot_number", ftos(n));
localcmd("wait; wait; wait\n");
- for(i = 0; i < n; ++i) { localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", argv(2), ftos(i+1), "\n"); }
-
- localcmd("sv_cmd playerdemo write 1 ", ftos(n+1), "\n");
+ for (i = 0; i < n; ++i)
+ localcmd("sv_cmd playerdemo read ", ftos(i + 2), " ", argv(2), ftos(i + 1), "\n");
+ localcmd("sv_cmd playerdemo write 1 ", ftos(n + 1), "\n");
return;
}
cvar_set("bot_number", ftos(n));
localcmd("wait; wait; wait\n");
- for(i = 0; i < n; ++i) { localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", argv(2), ftos(i+1), "\n"); }
+ for (i = 0; i < n; ++i)
+ localcmd("sv_cmd playerdemo read ", ftos(i + 2), " ", argv(2), ftos(i + 1), "\n");
return;
}
}
void GameCommand_printstats(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
void GameCommand_radarmap(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(RadarMap_Make(argc))
- return;
+ if (RadarMap_Make(argc)) return;
}
default:
void GameCommand_reducematchtime(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- changematchtime(autocvar_timelimit_decrement *-60, autocvar_timelimit_min * 60, autocvar_timelimit_max * 60);
+ changematchtime(autocvar_timelimit_decrement * -60, autocvar_timelimit_min * 60, autocvar_timelimit_max * 60);
return;
}
void GameCommand_setbots(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(argc >= 2)
+ if (argc >= 2)
{
cvar_settemp("minplayers", "0");
cvar_settemp("bot_number", argv(1));
}
void GameCommand_shuffleteams(float request)
-{SELFPARAM();
- switch(request)
+{
+ SELFPARAM();
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(teamplay)
+ if (teamplay)
{
entity tmp_player;
int i;
t_players = 0;
t_teams = 0;
FOR_EACH_CLIENT(tmp_player)
- if(IS_PLAYER(tmp_player) || tmp_player.caplayer)
+ if (IS_PLAYER(tmp_player) || tmp_player.caplayer)
{
CheckAllowedTeams(tmp_player);
- if(c1 >= 0) t_teams = max(1, t_teams);
- if(c2 >= 0) t_teams = max(2, t_teams);
- if(c3 >= 0) t_teams = max(3, t_teams);
- if(c4 >= 0) t_teams = max(4, t_teams);
+ if (c1 >= 0) t_teams = max(1, t_teams);
+ if (c2 >= 0) t_teams = max(2, t_teams);
+ if (c3 >= 0) t_teams = max(3, t_teams);
+ if (c4 >= 0) t_teams = max(4, t_teams);
++t_players;
}
// build a list of the players in a random order
FOR_EACH_CLIENT(tmp_player)
- if(IS_PLAYER(tmp_player) || tmp_player.caplayer)
+ if (IS_PLAYER(tmp_player) || tmp_player.caplayer)
{
- for (;;)
+ for ( ; ; )
{
i = bound(1, floor(random() * maxclients) + 1, maxclients);
- if(shuffleteams_players[i])
+ if (shuffleteams_players[i])
{
- continue; // a player is already assigned to this slot
+ continue; // a player is already assigned to this slot
}
else
{
{
if (!(shuffleteams_teams[i] >= x))
{
- if (!(shuffleteams_players[z]))
- continue; // not a player, move on to next random slot
+ if (!(shuffleteams_players[z])) continue; // not a player, move on to next random slot
- if(VerifyClientNumber(shuffleteams_players[z]))
- setself(edict_num(shuffleteams_players[z]));
+ if (VerifyClientNumber(shuffleteams_players[z])) setself(edict_num(shuffleteams_players[z]));
- if(self.team != team_color)
- MoveToTeam(self, team_color, 6);
+ if (self.team != team_color) MoveToTeam(self, team_color, 6);
shuffleteams_players[z] = 0;
shuffleteams_teams[i] = shuffleteams_teams[i] + 1;
}
else
{
- break; // move on to next team
+ break; // move on to next team
}
}
}
bprint("Successfully shuffled the players around randomly.\n");
// clear the buffers now
- for (i=0; i<SHUFFLETEAMS_MAX_PLAYERS; ++i)
+ for (i = 0; i < SHUFFLETEAMS_MAX_PLAYERS; ++i)
shuffleteams_players[i] = 0;
- for (i=0; i<SHUFFLETEAMS_MAX_TEAMS; ++i)
+ for (i = 0; i < SHUFFLETEAMS_MAX_TEAMS; ++i)
shuffleteams_teams[i] = 0;
}
else
// Because of this, it is disabled by default and must be enabled by the server owner when doing compilation. That way,
// we can be certain they understand the risks of it... So to enable, compile server with -DSTUFFTO_ENABLED argument.
- #ifdef STUFFTO_ENABLED
+#ifdef STUFFTO_ENABLED
#message "stuffto command enabled"
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
+ switch (request)
{
- if(argv(2))
+ case CMD_REQUEST_COMMAND:
{
- entity client = GetIndexedEntity(argc, 1);
- float accepted = VerifyClientEntity(client, true, false);
-
- if(accepted > 0)
+ if (argv(2))
{
- stuffcmd(client, strcat("\n", argv(next_token), "\n"));
- LOG_INFO(strcat("Command: \"", argv(next_token), "\" sent to ", GetCallerName(client), " (", argv(1) ,").\n"));
+ entity client = GetIndexedEntity(argc, 1);
+ float accepted = VerifyClientEntity(client, true, false);
+
+ if (accepted > 0)
+ {
+ stuffcmd(client, strcat("\n", argv(next_token), "\n"));
+ LOG_INFO(strcat("Command: \"", argv(next_token), "\" sent to ", GetCallerName(client), " (", argv(1), ").\n"));
+ }
+ else
+ {
+ LOG_INFO("stuffto: ", GetClientErrorString(accepted, argv(1)), ".\n");
+ }
+
+ return;
}
- else
- LOG_INFO("stuffto: ", GetClientErrorString(accepted, argv(1)), ".\n");
+ }
+ default:
+ LOG_INFO("Incorrect parameters for ^2stuffto^7\n");
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 sv_cmd stuffto client \"command\"\n");
+ LOG_INFO(" 'client' is the entity number or name of the player,\n");
+ LOG_INFO(" and 'command' is the command to be sent to that player.\n");
return;
}
}
-
- default:
- LOG_INFO("Incorrect parameters for ^2stuffto^7\n");
- case CMD_REQUEST_USAGE:
+#else
+ if (request)
{
- LOG_INFO("\nUsage:^3 sv_cmd stuffto client \"command\"\n");
- LOG_INFO(" 'client' is the entity number or name of the player,\n");
- LOG_INFO(" and 'command' is the command to be sent to that player.\n");
+ LOG_INFO("stuffto command is not enabled on this server.\n");
return;
}
- }
- #else
- if(request)
- {
- LOG_INFO("stuffto command is not enabled on this server.\n");
- return;
- }
- #endif
+#endif
}
void GameCommand_trace(float request, float argc)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
vector org, delta, start, end, p, q, q0, pos, vv, dv;
float i, f, safe, unsafe, dq, dqf;
- switch(argv(1))
+ switch (argv(1))
{
case "debug":
{
float hitcount = 0;
LOG_INFO("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky.\n");
float worst_endpos_bug = 0;
- for (;;)
+ for ( ; ; )
{
org = world.mins;
delta = world.maxs - world.mins;
end = stov(vtos(end));
tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);
- if(!trace_startsolid && trace_fraction < 1)
+ if (!trace_startsolid && trace_fraction < 1)
{
p = trace_endpos;
tracebox(p, PL_MIN, PL_MAX, p, MOVE_NOMONSTERS, world);
- if(trace_startsolid)
+ if (trace_startsolid)
{
- rint(42); // do an engine breakpoint on VM_rint so you can get the trace that errnoeously returns startsolid
+ rint(42); // do an engine breakpoint on VM_rint so you can get the trace that errnoeously returns startsolid
tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);
// how much do we need to back off?
safe = 1;
unsafe = 0;
- for (;;)
+ for ( ; ; )
{
pos = p * (1 - (safe + unsafe) * 0.5) + start * ((safe + unsafe) * 0.5);
tracebox(pos, PL_MIN, PL_MAX, pos, MOVE_NOMONSTERS, world);
- if(trace_startsolid)
+ if (trace_startsolid)
{
- if((safe + unsafe) * 0.5 == unsafe)
- break;
+ if ((safe + unsafe) * 0.5 == unsafe) break;
unsafe = (safe + unsafe) * 0.5;
}
else
{
- if((safe + unsafe) * 0.5 == safe)
- break;
+ if ((safe + unsafe) * 0.5 == safe) break;
safe = (safe + unsafe) * 0.5;
}
}
LOG_INFO("unsafe distance to back off: ", ftos(unsafe * vlen(p - start)), "qu\n");
tracebox(p, PL_MIN + '0.1 0.1 0.1', PL_MAX - '0.1 0.1 0.1', p, MOVE_NOMONSTERS, world);
- if(trace_startsolid)
- LOG_INFO("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
- else
- LOG_INFO("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
- if (++hitcount >= 10)
- break;
+ if (trace_startsolid) LOG_INFO("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
+ else LOG_INFO("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
+ if (++hitcount >= 10) break;
}
else
{
q0 = p;
dq = 0;
dqf = 1;
- for (;;)
+ for ( ; ; )
{
q = p + normalize(end - p) * (dq + dqf);
- if(q == q0)
- break;
+ if (q == q0) break;
tracebox(p, PL_MIN, PL_MAX, q, MOVE_NOMONSTERS, world);
- if(trace_startsolid)
- error("THIS ONE cannot happen");
- if(trace_fraction > 0)
- dq += dqf * trace_fraction;
+ if (trace_startsolid) error("THIS ONE cannot happen");
+ if (trace_fraction > 0) dq += dqf * trace_fraction;
dqf *= 0.5;
q0 = q;
}
- if(dq > worst_endpos_bug)
+ if (dq > worst_endpos_bug)
{
worst_endpos_bug = dq;
LOG_INFO("trace_endpos still before solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
LOG_INFO("could go ", ftos(dq), " units further to ", vtos(q), "\n");
- if (++hitcount >= 10)
- break;
+ if (++hitcount >= 10) break;
}
}
}
e = nextent(world);
tracebox(e.origin + '0 0 32', e.mins, e.maxs, e.origin + '0 0 -1024', MOVE_NORMAL, e);
vv = trace_endpos;
- if(trace_fraction == 1)
+ if (trace_fraction == 1)
{
LOG_INFO("not above ground, aborting\n");
return;
}
f = 0;
- for(i = 0; i < 100000; ++i)
+ for (i = 0; i < 100000; ++i)
{
dv = randomvec();
- if(dv.z > 0)
- dv = -1 * dv;
+ if (dv.z > 0) dv = -1 * dv;
tracebox(vv, e.mins, e.maxs, vv + dv, MOVE_NORMAL, e);
- if(trace_startsolid)
- LOG_INFO("bug 1\n");
- if(trace_fraction == 1)
- if(dv.z < f)
+ if (trace_startsolid) LOG_INFO("bug 1\n");
+ if (trace_fraction == 1)
{
- LOG_INFO("bug 2: ", ftos(dv.x), " ", ftos(dv.y), " ", ftos(dv.z));
- LOG_INFO(" (", ftos(asin(dv.z / vlen(dv)) * 180 / M_PI), " degrees)\n");
- f = dv.z;
+ if (dv.z < f)
+ {
+ LOG_INFO("bug 2: ", ftos(dv.x), " ", ftos(dv.y), " ", ftos(dv.z));
+ LOG_INFO(" (", ftos(asin(dv.z / vlen(dv)) * 180 / M_PI), " degrees)\n");
+ f = dv.z;
+ }
}
}
LOG_INFO("highest possible dist: ", ftos(f), "\n");
case "walk":
{
- if(argc == 4)
+ if (argc == 4)
{
e = nextent(world);
- if(tracewalk(e, stov(argv(2)), e.mins, e.maxs, stov(argv(3)), MOVE_NORMAL))
- LOG_INFO("can walk\n");
- else
- LOG_INFO("cannot walk\n");
+ if (tracewalk(e, stov(argv(2)), e.mins, e.maxs, stov(argv(3)), MOVE_NORMAL)) LOG_INFO("can walk\n");
+ else LOG_INFO("cannot walk\n");
return;
}
}
case "showline":
{
- if(argc == 4)
+ if (argc == 4)
{
vv = stov(argv(2));
dv = stov(argv(3));
traceline(vv, dv, MOVE_NORMAL, world);
- trailparticles(world, particleeffectnum(EFFECT_TR_NEXUIZPLASMA), vv, trace_endpos);
- trailparticles(world, particleeffectnum(EFFECT_TR_CRYLINKPLASMA), trace_endpos, dv);
+ __trailparticles(world, particleeffectnum(EFFECT_TR_NEXUIZPLASMA), vv, trace_endpos);
+ __trailparticles(world, particleeffectnum(EFFECT_TR_CRYLINKPLASMA), trace_endpos, dv);
return;
}
}
- // no default case, just go straight to invalid
+ // no default case, just go straight to invalid
}
}
void GameCommand_unlockteams(float request)
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(teamplay)
+ if (teamplay)
{
lockteams = 0;
bprint("^1The teams are now unlocked.\n");
{
case CMD_REQUEST_COMMAND:
{
- if(autocvar_g_campaign)
+ if (autocvar_g_campaign)
{
- if(argc >= 2)
+ if (argc >= 2)
{
CampaignLevelWarp(stof(argv(1)));
LOG_INFO("Successfully warped to campaign level ", stof(argv(1)), ".\n");
}
}
else
+ {
LOG_INFO("Not in campaign, can't level warp\n");
+ }
return;
}
** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
void GameCommand_(float request)
{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
-
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- print("\nUsage:^3 sv_cmd \n");
- print(" No arguments required.\n");
- return;
- }
- }
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ print("\nUsage:^3 sv_cmd \n");
+ print(" No arguments required.\n");
+ return;
+ }
+ }
}
*/
// ==================================
// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define SERVER_COMMANDS(request,arguments,command) \
+#define SERVER_COMMANDS(request, arguments, command) \
SERVER_COMMAND("adminmsg", GameCommand_adminmsg(request, arguments), "Send an admin message to a client directly") \
SERVER_COMMAND("allready", GameCommand_allready(request), "Restart the server and reset the players") \
SERVER_COMMAND("allspec", GameCommand_allspec(request, arguments), "Force all players to spectate") \
void GameCommand_macro_help()
{
- #define SERVER_COMMAND(name,function,description) \
+ #define SERVER_COMMAND(name, function, description) \
{ LOG_INFO(" ^2", name, "^7: ", description, "\n"); }
SERVER_COMMANDS(0, 0, "");
- #undef SERVER_COMMAND
-
- return;
+#undef SERVER_COMMAND
}
float GameCommand_macro_command(float argc, string command)
{
- #define SERVER_COMMAND(name,function,description) \
- { if(name == strtolower(argv(0))) { function; return true; } }
+ #define SERVER_COMMAND(name, function, description) \
+ { if (name == strtolower(argv(0))) { function; return true; } }
SERVER_COMMANDS(CMD_REQUEST_COMMAND, argc, command);
- #undef SERVER_COMMAND
+#undef SERVER_COMMAND
return false;
}
float GameCommand_macro_usage(float argc)
{
- #define SERVER_COMMAND(name,function,description) \
- { if(name == strtolower(argv(1))) { function; return true; } }
+ #define SERVER_COMMAND(name, function, description) \
+ { if (name == strtolower(argv(1))) { function; return true; } }
SERVER_COMMANDS(CMD_REQUEST_USAGE, argc, "");
- #undef SERVER_COMMAND
+#undef SERVER_COMMAND
return false;
}
void GameCommand_macro_write_aliases(float fh)
{
- #define SERVER_COMMAND(name,function,description) \
+ #define SERVER_COMMAND(name, function, description) \
{ CMD_Write_Alias("qc_cmd_sv", name, description); }
SERVER_COMMANDS(0, 0, "");
- #undef SERVER_COMMAND
-
- return;
+#undef SERVER_COMMAND
}
// argv: 0 - 1 - 2 - 3
// cmd vote - master - login - password
- if(strtolower(argv(0)) == "help")
+ if (strtolower(argv(0)) == "help")
{
- if(argc == 1)
+ if (argc == 1)
{
LOG_INFO("\nServer console commands:\n");
GameCommand_macro_help();
return;
}
- else if(BanCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
+ else if (BanCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
{
return;
}
- else if(CommonCommand_macro_usage(argc, world)) // same here, but for common commands instead
+ else if (CommonCommand_macro_usage(argc, world)) // same here, but for common commands instead
{
return;
}
- else if(GenericCommand_macro_usage(argc)) // same here, but for generic commands instead
+ else if (GenericCommand_macro_usage(argc)) // same here, but for generic commands instead
{
return;
}
- else if(GameCommand_macro_usage(argc)) // finally try for normal commands too
+ else if (GameCommand_macro_usage(argc)) // finally try for normal commands too
{
return;
}
}
- else if(MUTATOR_CALLHOOK(SV_ParseServerCommand, strtolower(argv(0)), argc, command))
+ else if (MUTATOR_CALLHOOK(SV_ParseServerCommand, strtolower(argv(0)), argc, command))
{
- return; // handled by a mutator
+ return; // handled by a mutator
}
- else if(BanCommand(command))
+ else if (BanCommand(command))
{
- return; // handled by server/command/ipban.qc
+ return; // handled by server/command/ipban.qc
}
- else if(CommonCommand_macro_command(argc, world, command))
+ else if (CommonCommand_macro_command(argc, world, command))
{
- return; // handled by server/command/common.qc
+ return; // handled by server/command/common.qc
}
- else if(GenericCommand(command))
+ else if (GenericCommand(command))
{
- return; // handled by common/command/generic.qc
+ return; // handled by common/command/generic.qc
}
- else if(GameCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+ else if (GameCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
{
- return; // handled by one of the above GameCommand_* functions
+ return; // handled by one of the above GameCommand_* functions
}
// nothing above caught the command, must be invalid
LOG_INFO(((command != "") ? strcat("Unknown server command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try sv_cmd help.\n");
-
- return;
}
const float SHUFFLETEAMS_MAX_PLAYERS = 255;
const float SHUFFLETEAMS_MAX_TEAMS = 4;
float shuffleteams_players[SHUFFLETEAMS_MAX_PLAYERS]; // maximum of 255 player slots
-float shuffleteams_teams[SHUFFLETEAMS_MAX_TEAMS]; // maximum of 4 teams
+float shuffleteams_teams[SHUFFLETEAMS_MAX_TEAMS]; // maximum of 4 teams
// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
void GameCommand_macro_write_aliases(float fh);
{
int nags, i, f, b;
entity e;
- WriteByte(MSG_ENTITY, ENT_CLIENT_NAGGER);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_NAGGER);
// bits:
// 1 = ready
// 128 = vote string
nags = 0;
- if(readycount)
+ if (readycount)
{
nags |= BIT(0);
- if(to.ready == 0)
- nags |= BIT(1);
+ if (to.ready == 0) nags |= BIT(1);
}
- if(vote_called)
+ if (vote_called)
{
nags |= BIT(2);
- if(to.vote_selection == 0)
- nags |= BIT(3);
+ if (to.vote_selection == 0) nags |= BIT(3);
}
- if(warmup_stage)
- nags |= BIT(4);
+ if (warmup_stage) nags |= BIT(4);
- if(sendflags & BIT(6))
- nags |= BIT(6);
+ if (sendflags & BIT(6)) nags |= BIT(6);
- if(sendflags & BIT(7))
- nags |= BIT(7);
+ if (sendflags & BIT(7)) nags |= BIT(7);
- if(!(nags & 4)) // no vote called? send no string
+ if (!(nags & 4)) // no vote called? send no string
nags &= ~(BIT(6) | BIT(7));
WriteByte(MSG_ENTITY, nags);
- if(nags & BIT(6))
+ if (nags & BIT(6))
{
WriteByte(MSG_ENTITY, vote_accept_count);
WriteByte(MSG_ENTITY, vote_reject_count);
WriteChar(MSG_ENTITY, to.vote_selection);
}
- if(nags & BIT(7))
- WriteString(MSG_ENTITY, vote_called_display);
+ if (nags & BIT(7)) WriteString(MSG_ENTITY, vote_called_display);
- if(nags & 1)
+ if (nags & 1)
{
- for(i = 1; i <= maxclients; i += 8)
+ for (i = 1; i <= maxclients; i += 8)
{
- for(f = 0, e = edict_num(i), b = 1; b < 256; b *= 2, e = nextent(e))
- if(!IS_REAL_CLIENT(e) || e.ready)
- f |= b;
+ for (f = 0, e = edict_num(i), b = 1; b < 256; b *= 2, e = nextent(e))
+ if (!IS_REAL_CLIENT(e) || e.ready) f |= b;
WriteByte(MSG_ENTITY, f);
}
}
void Nagger_Init()
{
- Net_LinkEntity(nagger = spawn(), false, 0, Nagger_SendEntity);
+ Net_LinkEntity(nagger = new(nagger), false, 0, Nagger_SendEntity);
+ make_pure(nagger);
}
void Nagger_VoteChanged()
{
- if(nagger)
- nagger.SendFlags |= BIT(7);
+ if (nagger) nagger.SendFlags |= BIT(7);
}
void Nagger_VoteCountChanged()
{
- if(nagger)
- nagger.SendFlags |= BIT(6);
+ if (nagger) nagger.SendFlags |= BIT(6);
}
void Nagger_ReadyCounted()
{
- if(nagger)
- nagger.SendFlags |= BIT(0);
+ if (nagger) nagger.SendFlags |= BIT(0);
}
// If the vote_caller is still here, return their name, otherwise vote_caller_name
string OriginalCallerName()
{
- if (IS_REAL_CLIENT(vote_caller))
- return vote_caller.netname;
+ if (IS_REAL_CLIENT(vote_caller)) return vote_caller.netname;
return vote_caller_name;
}
{
entity tmp_player;
- FOR_EACH_CLIENT(tmp_player) { tmp_player.vote_selection = 0; }
+ FOR_EACH_CLIENT(tmp_player)
+ {
+ tmp_player.vote_selection = 0;
+ }
- if(vote_called)
+ if (vote_called)
{
strunzone(vote_called_command);
strunzone(vote_called_display);
void VoteStop(entity stopper)
{
bprint("\{1}^2* ^3", GetCallerName(stopper), "^2 stopped ^3", OriginalCallerName(), "^2's vote\n");
- if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid))); }
-
+ if (autocvar_sv_eventlog) GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid)));
// Don't force them to wait for next vote, this way they can e.g. correct their vote.
- if((vote_caller) && (stopper == vote_caller)) { vote_caller.vote_waittime = time + autocvar_sv_vote_stop; }
-
+ if ((vote_caller) && (stopper == vote_caller)) vote_caller.vote_waittime = time + autocvar_sv_vote_stop;
VoteReset();
}
{
bprint("\{1}^2* ^3", OriginalCallerName(), "^2's vote for ^1", vote_called_display, "^2 was accepted\n");
- if((vote_called == VOTE_MASTER) && vote_caller)
- vote_caller.vote_master = 1;
- else
- localcmd(strcat(vote_called_command, "\n"));
+ if ((vote_called == VOTE_MASTER) && vote_caller) vote_caller.vote_master = 1;
+ else localcmd(strcat(vote_called_command, "\n"));
- if(vote_caller) { vote_caller.vote_waittime = 0; } // people like your votes, you don't need to wait to vote again
+ if (vote_caller) vote_caller.vote_waittime = 0; // people like your votes, you don't need to wait to vote again
VoteReset();
Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_ACCEPT);
strcat(", ^1", ftos(vote_abstain_count), "^2 didn't care"),
strcat(", ^1", ftos(notvoters), strcat("^2 didn't ", ((mincount >= 0) ? "" : "have to "), "vote\n"))));
- if(autocvar_sv_eventlog)
+ if (autocvar_sv_eventlog)
{
GameLogEcho(strcat(
strcat(":vote:v", result, ":", ftos(vote_accept_count)),
vote_accept_count = vote_reject_count = vote_abstain_count = 0;
float spectators_allowed = ((autocvar_sv_vote_nospectators != 2)
- || ((autocvar_sv_vote_nospectators == 1) && (warmup_stage || gameover))
- || (autocvar_sv_vote_nospectators == 0));
+ || ((autocvar_sv_vote_nospectators == 1) && (warmup_stage || gameover))
+ || (autocvar_sv_vote_nospectators == 0));
float vote_player_count = 0, notvoters = 0;
float vote_real_player_count = 0, vote_real_accept_count = 0;
FOR_EACH_REALCLIENT(tmp_player)
{
++vote_player_count;
- if(IS_PLAYER(tmp_player)) { ++vote_real_player_count; }
-
- switch(tmp_player.vote_selection)
+ if (IS_PLAYER(tmp_player)) ++vote_real_player_count;
+ switch (tmp_player.vote_selection)
{
- case VOTE_SELECT_REJECT: { ++vote_reject_count; { if(IS_PLAYER(tmp_player)) ++vote_real_reject_count; } break; }
- case VOTE_SELECT_ACCEPT: { ++vote_accept_count; { if(IS_PLAYER(tmp_player)) ++vote_real_accept_count; } break; }
- case VOTE_SELECT_ABSTAIN: { ++vote_abstain_count; { if(IS_PLAYER(tmp_player)) ++vote_real_abstain_count; } break; }
+ case VOTE_SELECT_REJECT:
+ { ++vote_reject_count;
+ { if (IS_PLAYER(tmp_player)) ++vote_real_reject_count; } break;
+ }
+ case VOTE_SELECT_ACCEPT:
+ { ++vote_accept_count;
+ { if (IS_PLAYER(tmp_player)) ++vote_real_accept_count; } break;
+ }
+ case VOTE_SELECT_ABSTAIN:
+ { ++vote_abstain_count;
+ { if (IS_PLAYER(tmp_player)) ++vote_real_abstain_count; } break;
+ }
default: break;
}
}
// Check to see if there are enough players on the server to allow master voting... otherwise, vote master could be used for evil.
- if((vote_called == VOTE_MASTER) && autocvar_sv_vote_master_playerlimit > vote_player_count)
+ if ((vote_called == VOTE_MASTER) && autocvar_sv_vote_master_playerlimit > vote_player_count)
{
- if(vote_caller) { vote_caller.vote_waittime = 0; }
+ if (vote_caller) vote_caller.vote_waittime = 0;
print_to(vote_caller, "^1There are not enough players on this server to allow you to become vote master.");
VoteReset();
return;
}
// if spectators aren't allowed to vote and there are players in a match, then only count the players in the vote and ignore spectators.
- if(!spectators_allowed && (vote_real_player_count > 0))
+ if (!spectators_allowed && (vote_real_player_count > 0))
{
vote_accept_count = vote_real_accept_count;
vote_reject_count = vote_real_reject_count;
vote_needed_of_voted = floor((vote_accept_count + vote_reject_count) * vote_factor_of_voted) + 1;
// are there any players at all on the server? it could be an admin vote
- if(vote_player_count == 0 && first_count)
+ if (vote_player_count == 0 && first_count)
{
- VoteSpam(0, -1, "yes"); // no players at all, just accept it
+ VoteSpam(0, -1, "yes"); // no players at all, just accept it
VoteAccept();
return;
}
// since there ARE players, finally calculate the result of the vote
- if(vote_accept_count >= vote_needed_overall)
+ if (vote_accept_count >= vote_needed_overall)
{
- VoteSpam(notvoters, -1, "yes"); // there is enough acceptions to pass the vote
+ VoteSpam(notvoters, -1, "yes"); // there is enough acceptions to pass the vote
VoteAccept();
return;
}
- if(vote_reject_count > vote_player_count - vote_abstain_count - vote_needed_overall)
+ if (vote_reject_count > vote_player_count - vote_abstain_count - vote_needed_overall)
{
- VoteSpam(notvoters, -1, "no"); // there is enough rejections to deny the vote
+ VoteSpam(notvoters, -1, "no"); // there is enough rejections to deny the vote
VoteReject();
return;
}
// there is not enough votes in either direction, now lets just calculate what the voters have said
- if(time > vote_endtime)
+ if (time > vote_endtime)
{
final_needed_votes = vote_needed_overall;
- if(autocvar_sv_vote_majority_factor_of_voted)
+ if (autocvar_sv_vote_majority_factor_of_voted)
{
- if(vote_accept_count >= vote_needed_of_voted)
+ if (vote_accept_count >= vote_needed_of_voted)
{
VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "yes");
VoteAccept();
return;
}
- if(vote_accept_count + vote_reject_count > 0)
+ if (vote_accept_count + vote_reject_count > 0)
{
VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "no");
VoteReject();
void VoteThink()
{
- if(vote_endtime > 0) // a vote was called
- if(time > vote_endtime) // time is up
+ if (vote_endtime > 0) // a vote was called
{
- VoteCount(false);
+ if (time > vote_endtime) // time is up
+ VoteCount(false);
}
-
- return;
}
// Resets the state of all clients, items, weapons, waypoints, ... of the map.
void reset_map(float dorespawn)
-{SELFPARAM();
+{
+ SELFPARAM();
- if(time <= game_starttime && round_handler_IsActive())
+ if (time <= game_starttime && round_handler_IsActive())
round_handler_Reset(game_starttime);
MUTATOR_CALLHOOK(reset_map_global);
- for(entity e = world; (e = nextent(e)); )
+ for (entity e = world; (e = nextent(e)); )
{
setself(e);
- if(IS_NOT_A_CLIENT(self))
+ if (IS_NOT_A_CLIENT(self))
{
- if(self.reset)
+ if (self.reset)
{
self.reset();
continue;
}
- if(self.team_saved)
- self.team = self.team_saved;
+ if (self.team_saved) self.team = self.team_saved;
- if(self.flags & FL_PROJECTILE) // remove any projectiles left
+ if (self.flags & FL_PROJECTILE) // remove any projectiles left
remove(self);
}
}
// Waypoints and assault start come LAST
- for(entity e = world; (e = nextent(e)); )
+ for (entity e = world; (e = nextent(e)); )
{
setself(e);
- if(IS_NOT_A_CLIENT(self))
+ if (IS_NOT_A_CLIENT(self))
{
- if(self.reset2)
+ if (self.reset2)
{
self.reset2();
continue;
entity e;
FOR_EACH_PLAYER(e)
- if(e.frozen)
- {
- WITH(entity, self, e, Unfreeze(self));
- }
+ if (e.frozen) WITH(entity, self, e, Unfreeze(self));
// Moving the player reset code here since the player-reset depends
// on spawnpoint entities which have to be reset first --blub
- if(dorespawn)
- if(!MUTATOR_CALLHOOK(reset_map_players))
- FOR_EACH_CLIENT(e) // reset all players
+ if (dorespawn)
{
- setself(e);
- /*
- only reset players if a restart countdown is active
- this can either be due to cvar sv_ready_restart_after_countdown having set
- restart_mapalreadyrestarted to 1 after the countdown ended or when
- sv_ready_restart_after_countdown is not used and countdown is still running
- */
- if (restart_mapalreadyrestarted || (time < game_starttime))
+ if (!MUTATOR_CALLHOOK(reset_map_players))
{
- //NEW: changed behaviour so that it prevents that previous spectators/observers suddenly spawn as players
- if (IS_PLAYER(self)) {
- //PlayerScore_Clear(self);
- self.killcount = 0;
- //stop the player from moving so that he stands still once he gets respawned
- self.velocity = '0 0 0';
- self.avelocity = '0 0 0';
- self.movement = '0 0 0';
- PutClientInServer();
+ FOR_EACH_CLIENT(e) // reset all players
+ {
+ setself(e);
+ /*
+ only reset players if a restart countdown is active
+ this can either be due to cvar sv_ready_restart_after_countdown having set
+ restart_mapalreadyrestarted to 1 after the countdown ended or when
+ sv_ready_restart_after_countdown is not used and countdown is still running
+ */
+ if (restart_mapalreadyrestarted || (time < game_starttime))
+ {
+ // NEW: changed behaviour so that it prevents that previous spectators/observers suddenly spawn as players
+ if (IS_PLAYER(self))
+ {
+ // PlayerScore_Clear(self);
+ self.killcount = 0;
+ // stop the player from moving so that he stands still once he gets respawned
+ self.velocity = '0 0 0';
+ self.avelocity = '0 0 0';
+ self.movement = '0 0 0';
+ PutClientInServer();
+ }
+ }
}
+
+ setself(this);
}
}
-
- setself(this);
}
// Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set)
void ReadyRestart_think()
-{SELFPARAM();
+{
+ SELFPARAM();
restart_mapalreadyrestarted = 1;
reset_map(true);
Score_ClearAll();
remove(self);
-
- return;
}
// Forces a restart of the game without actually reloading the map // this is a mess...
VoteReset();
// clear overtime, we have to decrease timelimit to its original value again.
- if (checkrules_overtimesadded > 0 && g_race_qualifying != 2) { cvar_set("timelimit", ftos(autocvar_timelimit - (checkrules_overtimesadded * autocvar_timelimit_overtime))); }
-
+ if (checkrules_overtimesadded > 0 && g_race_qualifying != 2) cvar_set("timelimit", ftos(autocvar_timelimit - (checkrules_overtimesadded * autocvar_timelimit_overtime)));
checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;
readyrestart_happened = 1;
restart_mapalreadyrestarted = 0; // reset this var, needed when cvar sv_ready_restart_repeatable is in use
// disable the warmup global for the server
- warmup_stage = 0; // once the game is restarted the game is in match stage
+ warmup_stage = 0; // once the game is restarted the game is in match stage
// reset the .ready status of all players (also spectators)
- FOR_EACH_REALCLIENT(tmp_player) { tmp_player.ready = 0; }
+ FOR_EACH_REALCLIENT(tmp_player)
+ {
+ tmp_player.ready = 0;
+ }
readycount = 0;
- Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
+ Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
// lock teams with lockonrestart
- if(autocvar_teamplay_lockonrestart && teamplay)
+ if (autocvar_teamplay_lockonrestart && teamplay)
{
lockteams = 1;
bprint("^1The teams are now locked.\n");
}
- //initiate the restart-countdown-announcer entity
- if(autocvar_sv_ready_restart_after_countdown)
+ // initiate the restart-countdown-announcer entity
+ if (autocvar_sv_ready_restart_after_countdown)
{
restart_timer = spawn();
restart_timer.think = ReadyRestart_think;
}
// after a restart every players number of allowed timeouts gets reset, too
- if(autocvar_sv_timeout) { FOR_EACH_REALPLAYER(tmp_player) { tmp_player.allowed_timeouts = autocvar_sv_timeout_number; } }
-
- //reset map immediately if this cvar is not set
- if (!autocvar_sv_ready_restart_after_countdown) { reset_map(true); }
-
- if(autocvar_sv_eventlog) { GameLogEcho(":restart"); }
-}
+ if (autocvar_sv_timeout)
+ {
+ FOR_EACH_REALPLAYER(tmp_player)
+ {
+ tmp_player.allowed_timeouts = autocvar_sv_timeout_number;
+ }
+ // reset map immediately if this cvar is not set
+ if (!autocvar_sv_ready_restart_after_countdown) reset_map(true); }
+ if (autocvar_sv_eventlog) GameLogEcho(":restart"); }
void ReadyRestart()
{
// no assault support yet...
- if(g_assault | gameover | intermission_running | race_completing)
- localcmd("restart\n");
- else
- localcmd("\nsv_hook_gamerestart\n");
+ if (g_assault | gameover | intermission_running | race_completing) localcmd("restart\n");
+ else localcmd("\nsv_hook_gamerestart\n");
// Reset ALL scores, but only do that at the beginning of the countdown if sv_ready_restart_after_countdown is off!
// Otherwise scores could be manipulated during the countdown.
- if (!autocvar_sv_ready_restart_after_countdown) { Score_ClearAll(); }
-
+ if (!autocvar_sv_ready_restart_after_countdown) Score_ClearAll();
ReadyRestart_force();
-
- return;
}
// Count the players who are ready and determine whether or not to restart the match
FOR_EACH_REALCLIENT(tmp_player)
{
- if(IS_PLAYER(tmp_player) || tmp_player.caplayer == 1)
+ if (IS_PLAYER(tmp_player) || tmp_player.caplayer == 1)
{
++t_players;
- if(tmp_player.ready) { ++t_ready; }
- }
+ if (tmp_player.ready) ++t_ready; }
}
readycount = t_ready;
ready_needed_factor = bound(0.5, cvar("g_warmup_majority_factor"), 0.999);
ready_needed_count = floor(t_players * ready_needed_factor) + 1;
- if(readycount >= ready_needed_count)
- {
- ReadyRestart();
- }
-
- return;
+ if (readycount >= ready_needed_count) ReadyRestart();
}
{
float from_server = (!caller);
- if((assignment == VC_ASGNMNT_BOTH)
- || ((!from_server && assignment == VC_ASGNMNT_CLIENTONLY)
- || (from_server && assignment == VC_ASGNMNT_SERVERONLY)))
- {
- return true;
- }
+ if ((assignment == VC_ASGNMNT_BOTH)
+ || ((!from_server && assignment == VC_ASGNMNT_CLIENTONLY)
+ || (from_server && assignment == VC_ASGNMNT_SERVERONLY))) return true;
return false;
}
{
string output;
- if((argc - 1) < startpos)
- output = "";
- else
- output = substring(input, argv_start_index(startpos), argv_end_index(-1) - argv_start_index(startpos));
+ if ((argc - 1) < startpos) output = "";
+ else output = substring(input, argv_start_index(startpos), argv_end_index(-1) - argv_start_index(startpos));
return output;
}
float VoteCommand_checknasty(string vote_command)
{
- if((strstrofs(vote_command, ";", 0) >= 0)
- || (strstrofs(vote_command, "\n", 0) >= 0)
- || (strstrofs(vote_command, "\r", 0) >= 0)
- || (strstrofs(vote_command, "$", 0) >= 0))
- return false;
+ if ((strstrofs(vote_command, ";", 0) >= 0)
+ || (strstrofs(vote_command, "\n", 0) >= 0)
+ || (strstrofs(vote_command, "\r", 0) >= 0)
+ || (strstrofs(vote_command, "$", 0) >= 0)) return false;
return true;
}
{
string l = strcat(" ", list, " ");
- if(strstrofs(l, strcat(" ", vote_command, " "), 0) >= 0)
- return true;
+ if (strstrofs(l, strcat(" ", vote_command, " "), 0) >= 0) return true;
return false;
}
return string_null;
}
- if(!autocvar_sv_vote_override_mostrecent && caller)
+ if (!autocvar_sv_vote_override_mostrecent && caller)
{
- if(Map_IsRecent(validated_map))
+ if (Map_IsRecent(validated_map))
{
print_to(caller, "This server does not allow for recent maps to be played again. Please be patient for some rounds.");
return string_null;
}
}
- if(!MapInfo_CheckMap(validated_map))
+ if (!MapInfo_CheckMap(validated_map))
{
print_to(caller, strcat("^1Invalid mapname, \"^3", validated_map, "^1\" does not support the current game mode."));
return string_null;
{
float p, q, check, minargs;
string cvarname = strcat("sv_vote_command_restriction_", argv(startpos));
- string cmdrestriction = cvar_string(cvarname); // note: this warns on undefined cvar. We want that.
+ string cmdrestriction = cvar_string(cvarname); // note: this warns on undefined cvar. We want that.
string charlist, arg;
float checkmate;
- if(cmdrestriction == "")
- return true;
+ if (cmdrestriction == "") return true;
- ++startpos; // skip command name
+ ++startpos; // skip command name
// check minimum arg count
// ...
minargs = stof(cmdrestriction);
- if(argc - startpos < minargs)
- return false;
+ if (argc - startpos < minargs) return false;
- p = strstrofs(cmdrestriction, ";", 0); // find first semicolon
+ p = strstrofs(cmdrestriction, ";", 0); // find first semicolon
- for (;;)
+ for ( ; ; )
{
// we know that at any time, startpos <= argc - minargs
// so this means: argc-minargs >= startpos >= argc, thus
// argc-minargs >= argc, thus minargs <= 0, thus all minargs
// have been seen already
- if(startpos >= argc) // all args checked? GOOD
+ if (startpos >= argc) // all args checked? GOOD
break;
- if(p < 0) // no more args? FAIL
+ if (p < 0) // no more args? FAIL
{
// exception: exactly minargs left, this one included
- if(argc - startpos == minargs)
- break;
+ if (argc - startpos == minargs) break;
// otherwise fail
return false;
}
// cut to next semicolon
- q = strstrofs(cmdrestriction, ";", p+1); // find next semicolon
- if(q < 0)
- charlist = substring(cmdrestriction, p+1, -1);
- else
- charlist = substring(cmdrestriction, p+1, q - (p+1));
+ q = strstrofs(cmdrestriction, ";", p + 1); // find next semicolon
+ if (q < 0) charlist = substring(cmdrestriction, p + 1, -1);
+ else charlist = substring(cmdrestriction, p + 1, q - (p + 1));
// in case we ever want to allow semicolons in VoteCommand_checknasty
// charlist = strreplace("^^", ";", charlist);
- if(charlist != "")
+ if (charlist != "")
{
// verify the arg only contains allowed chars
arg = argv(startpos);
checkmate = strlen(arg);
- for(check = 0; check < checkmate; ++check)
- if(strstrofs(charlist, substring(arg, check, 1), 0) < 0)
- return false; // not allowed character
+ for (check = 0; check < checkmate; ++check)
+ if (strstrofs(charlist, substring(arg, check, 1), 0) < 0) return false;
+ // not allowed character
// all characters are allowed. FINE.
}
first_command = argv(startpos);
/*printf("VoteCommand_parse(): Command: '%s', Length: %f.\n",
- substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)),
- strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)))
+ substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)),
+ strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)))
);*/
- if(
- (autocvar_sv_vote_limit > 0)
- &&
- (strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos))) > autocvar_sv_vote_limit)
- )
- return false;
+ if (
+ (autocvar_sv_vote_limit > 0)
+ &&
+ (strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos))) > autocvar_sv_vote_limit)
+ ) return false;
- if (!VoteCommand_checkinlist(first_command, vote_list))
- return false;
+ if (!VoteCommand_checkinlist(first_command, vote_list)) return false;
- if (!VoteCommand_checkargs(startpos, argc))
- return false;
+ if (!VoteCommand_checkargs(startpos, argc)) return false;
- switch(first_command) // now go through and parse the proper commands to adjust as needed.
+ switch (first_command) // now go through and parse the proper commands to adjust as needed.
{
case "kick":
- case "kickban": // catch all kick/kickban commands
+ case "kickban": // catch all kick/kickban commands
{
entity victim = GetIndexedEntity(argc, (startpos + 1));
float accepted = VerifyClientEntity(victim, true, false);
- if(accepted > 0)
+ if (accepted > 0)
{
string reason = ((argc > next_token) ? substring(vote_command, argv_start_index(next_token), strlen(vote_command) - argv_start_index(next_token)) : "No reason provided");
string command_arguments;
- if(first_command == "kickban")
- command_arguments = strcat(ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ~");
- else
- command_arguments = reason;
+ if (first_command == "kickban") command_arguments = strcat(ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ~");
+ else command_arguments = reason;
vote_parsed_command = strcat(first_command, " # ", ftos(num_for_edict(victim)), " ", command_arguments);
vote_parsed_display = strcat("^1", vote_command, " (^7", victim.netname, "^1): ", reason);
case "map":
case "chmap":
- case "gotomap": // re-direct all map selection commands to gotomap
+ case "gotomap": // re-direct all map selection commands to gotomap
{
vote_command = ValidateMap(argv(startpos + 1), caller);
- if (!vote_command) { return false; }
+ if (!vote_command) return false;
vote_parsed_command = strcat("gotomap ", vote_command);
vote_parsed_display = strzone(strcat("^1", vote_parsed_command));
// Command Sub-Functions
// =======================
-void VoteCommand_abstain(float request, entity caller) // CLIENT ONLY
+void VoteCommand_abstain(float request, entity caller) // CLIENT ONLY
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
if (!vote_called) { print_to(caller, "^1No vote called."); }
- else if(caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+ else if (caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change)
+ {
+ print_to(caller, "^1You have already voted.");
+ }
- else // everything went okay, continue changing vote
+ else // everything went okay, continue changing vote
{
print_to(caller, "^1You abstained from your vote.");
caller.vote_selection = VOTE_SELECT_ABSTAIN;
msg_entity = caller;
- if(!autocvar_sv_vote_singlecount) { VoteCount(false); }
- }
+ if (!autocvar_sv_vote_singlecount) VoteCount(false); }
return;
}
}
}
-void VoteCommand_call(float request, entity caller, float argc, string vote_command) // BOTH
+void VoteCommand_call(float request, entity caller, float argc, string vote_command) // BOTH
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
float spectators_allowed = ((autocvar_sv_vote_nospectators != 2)
- || ((autocvar_sv_vote_nospectators == 1) && warmup_stage)
- || (autocvar_sv_vote_nospectators == 0));
+ || ((autocvar_sv_vote_nospectators == 1) && warmup_stage)
+ || (autocvar_sv_vote_nospectators == 0));
float tmp_playercount = 0;
entity tmp_player;
vote_command = VoteCommand_extractcommand(vote_command, 2, argc);
- if(!autocvar_sv_vote_call && caller) { print_to(caller, "^1Vote calling is not allowed."); }
- else if(!autocvar_sv_vote_gamestart && time < game_starttime) { print_to(caller, "^1Vote calling is not allowed before the match has started."); }
- else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
- else if(!spectators_allowed && (caller && !IS_PLAYER(caller))) { print_to(caller, "^1Only players can call a vote."); }
- else if(caller && !IS_CLIENT(caller)) { print_to(caller, "^1Only connected clients can vote."); }
- else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
- else if(caller && (time < caller.vote_waittime)) { print_to(caller, strcat("^1You have to wait ^2", ftos(ceil(caller.vote_waittime - time)), "^1 seconds before you can again call a vote.")); }
- else if (!VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
- else if (!VoteCommand_parse(caller, vote_command, autocvar_sv_vote_commands, 2, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
-
- else // everything went okay, continue with calling the vote
+ if (!autocvar_sv_vote_call && caller) { print_to(caller, "^1Vote calling is not allowed."); }
+ else if (!autocvar_sv_vote_gamestart && time < game_starttime)
{
- vote_caller = caller; // remember who called the vote
+ print_to(caller, "^1Vote calling is not allowed before the match has started.");
+ }
+ else if (vote_called)
+ {
+ print_to(caller, "^1There is already a vote called.");
+ }
+ else if (!spectators_allowed && (caller && !IS_PLAYER(caller)))
+ {
+ print_to(caller, "^1Only players can call a vote.");
+ }
+ else if (caller && !IS_CLIENT(caller))
+ {
+ print_to(caller, "^1Only connected clients can vote.");
+ }
+ else if (timeout_status)
+ {
+ print_to(caller, "^1You can not call a vote while a timeout is active.");
+ }
+ else if (caller && (time < caller.vote_waittime))
+ {
+ print_to(caller, strcat("^1You have to wait ^2", ftos(ceil(caller.vote_waittime - time)), "^1 seconds before you can again call a vote."));
+ }
+ else if (!VoteCommand_checknasty(vote_command))
+ {
+ print_to(caller, "^1Syntax error in command, see 'vhelp' for more info.");
+ }
+ else if (!VoteCommand_parse(caller, vote_command, autocvar_sv_vote_commands, 2, argc))
+ {
+ print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info.");
+ }
+
+ else // everything went okay, continue with calling the vote
+ {
+ vote_caller = caller; // remember who called the vote
vote_caller_name = strzone(GetCallerName(vote_caller));
vote_called = VOTE_NORMAL;
vote_called_command = strzone(vote_parsed_command);
vote_called_display = strzone(vote_parsed_display);
vote_endtime = time + autocvar_sv_vote_timeout;
- if(caller)
+ if (caller)
{
caller.vote_selection = VOTE_SELECT_ACCEPT;
caller.vote_waittime = time + autocvar_sv_vote_wait;
msg_entity = caller;
}
- FOR_EACH_REALCLIENT(tmp_player) { ++tmp_playercount; }
- if(tmp_playercount > 1) { Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_CALL); } // don't announce a "vote now" sound if player is alone
+ FOR_EACH_REALCLIENT(tmp_player)
+ {
+ ++tmp_playercount;
+ }
+ if (tmp_playercount > 1) Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_CALL); // don't announce a "vote now" sound if player is alone
bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote for ", vote_called_display, "\n");
- if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
+ if (autocvar_sv_eventlog) GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
Nagger_VoteChanged();
- VoteCount(true); // needed if you are the only one
+ VoteCount(true); // needed if you are the only one
}
return;
}
}
-void VoteCommand_master(float request, entity caller, float argc, string vote_command) // CLIENT ONLY
+void VoteCommand_master(float request, entity caller, float argc, string vote_command) // CLIENT ONLY
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(autocvar_sv_vote_master)
+ if (autocvar_sv_vote_master)
{
- switch(strtolower(argv(2)))
+ switch (strtolower(argv(2)))
{
case "do":
{
vote_command = VoteCommand_extractcommand(vote_command, 3, argc);
if (!caller.vote_master) { print_to(caller, "^1You do not have vote master privelages."); }
- else if (!VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
- else if (!VoteCommand_parse(caller, vote_command, strcat(autocvar_sv_vote_commands, " ", autocvar_sv_vote_master_commands), 3, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
+ else if (!VoteCommand_checknasty(vote_command))
+ {
+ print_to(caller, "^1Syntax error in command, see 'vhelp' for more info.");
+ }
+ else if (!VoteCommand_parse(caller, vote_command, strcat(autocvar_sv_vote_commands, " ", autocvar_sv_vote_master_commands), 3, argc))
+ {
+ print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info.");
+ }
- else // everything went okay, proceed with command
+ else // everything went okay, proceed with command
{
localcmd(strcat(vote_parsed_command, "\n"));
print_to(caller, strcat("Executing command '", vote_parsed_display, "' on server."));
bprint("\{1}^2* ^3", GetCallerName(caller), "^2 used their ^3master^2 status to do \"^2", vote_parsed_display, "^2\".\n");
- if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vdo:", ftos(caller.playerid), ":", vote_parsed_display)); }
- }
+ if (autocvar_sv_eventlog) GameLogEcho(strcat(":vote:vdo:", ftos(caller.playerid), ":", vote_parsed_display)); }
return;
}
case "login":
{
- if(autocvar_sv_vote_master_password == "") { print_to(caller, "^1Login to vote master is not allowed."); }
- else if(caller.vote_master) { print_to(caller, "^1You are already logged in as vote master."); }
- else if(autocvar_sv_vote_master_password != argv(3)) { print_to(caller, strcat("Rejected vote master login from ", GetCallerName(caller))); }
+ if (autocvar_sv_vote_master_password == "") { print_to(caller, "^1Login to vote master is not allowed."); }
+ else if (caller.vote_master)
+ {
+ print_to(caller, "^1You are already logged in as vote master.");
+ }
+ else if (autocvar_sv_vote_master_password != argv(3))
+ {
+ print_to(caller, strcat("Rejected vote master login from ", GetCallerName(caller)));
+ }
- else // everything went okay, proceed with giving this player master privilages
+ else // everything went okay, proceed with giving this player master privilages
{
caller.vote_master = true;
print_to(caller, strcat("Accepted vote master login from ", GetCallerName(caller)));
bprint("\{1}^2* ^3", GetCallerName(caller), "^2 logged in as ^3master^2\n");
- if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vlogin:", ftos(caller.playerid))); }
- }
+ if (autocvar_sv_eventlog) GameLogEcho(strcat(":vote:vlogin:", ftos(caller.playerid))); }
return;
}
- default: // calling a vote for master
+ default: // calling a vote for master
{
float spectators_allowed = ((autocvar_sv_vote_nospectators != 2)
- || ((autocvar_sv_vote_nospectators == 1) && warmup_stage)
- || (autocvar_sv_vote_nospectators == 0));
+ || ((autocvar_sv_vote_nospectators == 1) && warmup_stage)
+ || (autocvar_sv_vote_nospectators == 0));
if (!autocvar_sv_vote_master_callable) { print_to(caller, "^1Vote to become vote master is not allowed."); }
- else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
- else if(!spectators_allowed && (caller && !IS_PLAYER(caller))) { print_to(caller, "^1Only players can call a vote."); }
- else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
+ else if (vote_called)
+ {
+ print_to(caller, "^1There is already a vote called.");
+ }
+ else if (!spectators_allowed && (caller && !IS_PLAYER(caller)))
+ {
+ print_to(caller, "^1Only players can call a vote.");
+ }
+ else if (timeout_status)
+ {
+ print_to(caller, "^1You can not call a vote while a timeout is active.");
+ }
- else // everything went okay, continue with creating vote
+ else // everything went okay, continue with creating vote
{
vote_caller = caller;
vote_caller_name = strzone(GetCallerName(vote_caller));
caller.vote_waittime = time + autocvar_sv_vote_wait;
bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote to become ^3master^2.\n");
- if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
+ if (autocvar_sv_eventlog) GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
Nagger_VoteChanged();
- VoteCount(true); // needed if you are the only one
+ VoteCount(true); // needed if you are the only one
}
return;
}
}
-void VoteCommand_no(float request, entity caller) // CLIENT ONLY
+void VoteCommand_no(float request, entity caller) // CLIENT ONLY
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
if (!vote_called) { print_to(caller, "^1No vote called."); }
- else if(caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
- else if(((caller == vote_caller) || caller.vote_master) && autocvar_sv_vote_no_stops_vote) { VoteStop(caller); }
+ else if (caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change)
+ {
+ print_to(caller, "^1You have already voted.");
+ }
+ else if (((caller == vote_caller) || caller.vote_master) && autocvar_sv_vote_no_stops_vote)
+ {
+ VoteStop(caller);
+ }
- else // everything went okay, continue changing vote
+ else // everything went okay, continue changing vote
{
print_to(caller, "^1You rejected the vote.");
caller.vote_selection = VOTE_SELECT_REJECT;
msg_entity = caller;
- if(!autocvar_sv_vote_singlecount) { VoteCount(false); }
- }
+ if (!autocvar_sv_vote_singlecount) VoteCount(false); }
return;
}
}
}
-void VoteCommand_status(float request, entity caller) // BOTH
+void VoteCommand_status(float request, entity caller) // BOTH
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(vote_called)
- print_to(caller, strcat("^7Vote for ", vote_called_display, "^7 called by ^7", OriginalCallerName(), "^7."));
- else
- print_to(caller, "^1No vote called.");
+ if (vote_called) print_to(caller, strcat("^7Vote for ", vote_called_display, "^7 called by ^7", OriginalCallerName(), "^7."));
+ else print_to(caller, "^1No vote called.");
return;
}
}
}
-void VoteCommand_stop(float request, entity caller) // BOTH
+void VoteCommand_stop(float request, entity caller) // BOTH
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if (!vote_called) { print_to(caller, "^1No vote called."); }
- else if((caller == vote_caller) || !caller || caller.vote_master) { VoteStop(caller); }
- else { print_to(caller, "^1You are not allowed to stop that vote."); }
-
+ if (!vote_called) print_to(caller, "^1No vote called.");
+ else if ((caller == vote_caller) || !caller || caller.vote_master) VoteStop(caller);
+ else print_to(caller, "^1You are not allowed to stop that vote.");
return;
}
}
}
-void VoteCommand_yes(float request, entity caller) // CLIENT ONLY
+void VoteCommand_yes(float request, entity caller) // CLIENT ONLY
{
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
if (!vote_called) { print_to(caller, "^1No vote called."); }
- else if(caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+ else if (caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change)
+ {
+ print_to(caller, "^1You have already voted.");
+ }
- else // everything went okay, continue changing vote
+ else // everything went okay, continue changing vote
{
print_to(caller, "^1You accepted the vote.");
caller.vote_selection = VOTE_SELECT_ACCEPT;
msg_entity = caller;
- if(!autocvar_sv_vote_singlecount) { VoteCount(false); }
- }
+ if (!autocvar_sv_vote_singlecount) VoteCount(false); }
return;
}
** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
void VoteCommand_(float request)
{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
-
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote ");
- print_to(caller, " No arguments required.");
- return;
- }
- }
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote ");
+ print_to(caller, " No arguments required.");
+ return;
+ }
+ }
}
*/
// ================================
// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define VOTE_COMMANDS(request,caller,arguments,command) \
+#define VOTE_COMMANDS(request, caller, arguments, command) \
VOTE_COMMAND("abstain", VoteCommand_abstain(request, caller), "Abstain your vote in current vote", VC_ASGNMNT_CLIENTONLY) \
VOTE_COMMAND("call", VoteCommand_call(request, caller, arguments, command), "Create a new vote for players to decide on", VC_ASGNMNT_BOTH) \
VOTE_COMMAND("help", VoteCommand_macro_help(caller, arguments), "Shows this information", VC_ASGNMNT_BOTH) \
{
string command_origin = GetCommandPrefix(caller);
- if(argc == 2 || argv(2) == "help") // help display listing all commands
+ if (argc == 2 || argv(2) == "help") // help display listing all commands
{
print_to(caller, "\nVoting commands:\n");
- #define VOTE_COMMAND(name,function,description,assignment) \
- { if(Votecommand_check_assignment(caller, assignment)) { print_to(caller, strcat(" ^2", name, "^7: ", description)); } }
+ #define VOTE_COMMAND(name, function, description, assignment) \
+ { if (Votecommand_check_assignment(caller, assignment)) { print_to(caller, strcat(" ^2", name, "^7: ", description)); } }
VOTE_COMMANDS(0, caller, 0, "");
- #undef VOTE_COMMAND
+#undef VOTE_COMMAND
print_to(caller, strcat("\nUsage:^3 ", command_origin, " vote COMMAND...^7, where possible commands are listed above.\n"));
print_to(caller, strcat("For help about a specific command, type ", command_origin, " vote help COMMAND"));
print_to(caller, strcat("\n^7You can call a vote for or execute these commands: ^3", autocvar_sv_vote_commands, "^7 and maybe further ^3arguments^7"));
}
- else // usage for individual command
+ else // usage for individual command
{
- #define VOTE_COMMAND(name,function,description,assignment) \
- { if(Votecommand_check_assignment(caller, assignment)) { if(name == strtolower(argv(2))) { function; return; } } }
+ #define VOTE_COMMAND(name, function, description, assignment) \
+ { if (Votecommand_check_assignment(caller, assignment)) { if (name == strtolower(argv(2))) { function; return; } } }
VOTE_COMMANDS(CMD_REQUEST_USAGE, caller, argc, "");
- #undef VOTE_COMMAND
+#undef VOTE_COMMAND
}
-
- return;
}
float VoteCommand_macro_command(entity caller, float argc, string vote_command)
{
- #define VOTE_COMMAND(name,function,description,assignment) \
- { if(Votecommand_check_assignment(caller, assignment)) { if(name == strtolower(argv(1))) { function; return true; } } }
+ #define VOTE_COMMAND(name, function, description, assignment) \
+ { if (Votecommand_check_assignment(caller, assignment)) { if (name == strtolower(argv(1))) { function; return true; } } }
VOTE_COMMANDS(CMD_REQUEST_COMMAND, caller, argc, vote_command);
- #undef VOTE_COMMAND
+#undef VOTE_COMMAND
return false;
}
// argv: 0 - 1 - 2 - 3
// cmd vote - master - login - password
- switch(request)
+ switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if(VoteCommand_macro_command(caller, argc, vote_command))
- return;
+ if (VoteCommand_macro_command(caller, argc, vote_command)) return;
}
default:
const float VOTE_MASTER = 2;
// global vote information declarations
-entity vote_caller; // original caller of the current vote
-string vote_caller_name; // name of the vote caller
-float vote_called; // stores status of current vote (See VOTE_*)
-float vote_endtime; // time when the vote is finished
-float vote_accept_count; // total amount of players who accept the vote (counted by VoteCount() function)
-float vote_reject_count; // same as above, but rejected
-float vote_abstain_count; // same as above, but abstained
-float vote_needed_overall; // total amount of players NEEDED for a vote to pass (based on sv_vote_majority_factor)
-.float vote_master; // flag for if the player has vote master privelages
-.float vote_waittime; // flag for how long the player must wait before they can vote again
-.float vote_selection; // flag for which vote selection the player has made (See VOTE_SELECT_*)
+entity vote_caller; // original caller of the current vote
+string vote_caller_name; // name of the vote caller
+float vote_called; // stores status of current vote (See VOTE_*)
+float vote_endtime; // time when the vote is finished
+float vote_accept_count; // total amount of players who accept the vote (counted by VoteCount() function)
+float vote_reject_count; // same as above, but rejected
+float vote_abstain_count; // same as above, but abstained
+float vote_needed_overall; // total amount of players NEEDED for a vote to pass (based on sv_vote_majority_factor)
+.float vote_master; // flag for if the player has vote master privelages
+.float vote_waittime; // flag for how long the player must wait before they can vote again
+.float vote_selection; // flag for which vote selection the player has made (See VOTE_SELECT_*)
string vote_called_command; // command sent by client
string vote_called_display; // visual string of command sent by client
string vote_parsed_command; // command which is fixed after being parsed
// warmup and nagger stuff
const float RESTART_COUNTDOWN = 10;
entity nagger;
-float readycount; // amount of players who are ready
-float readyrestart_happened; // keeps track of whether a restart has already happened
+float readycount; // amount of players who are ready
+float readyrestart_happened; // keeps track of whether a restart has already happened
float restart_mapalreadyrestarted; // bool, indicates whether reset_map() was already executed
-.float ready; // flag for if a player is ready
+.float ready; // flag for if a player is ready
void reset_map(float dorespawn);
void ReadyCount();
void ReadyRestart_force();
const int FL_WEAPON = BIT(13);
const int FL_POWERUP = BIT(14);
const int FL_PROJECTILE = BIT(15);
-const int FL_TOSSED = BIT(BIT(4));
+const int FL_TOSSED = BIT(16);
const int FL_NO_WEAPON_STAY = BIT(17);
const int FL_SPAWNING = BIT(18);
const int FL_PICKUPITEMS = BIT(19);
-const int SVC_SOUND = 6;
-const int SVC_STOPSOUND = 16;
const int SVC_SETVIEW = 5;
const int RESPAWN_FORCE = 1;
#define EFMASK_CHEAP (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NODRAW | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT)
-const int MSG_ENTITY = 5; // csqc
-
const int NUM_PLAYERSKINS_TEAMPLAY = 3;
const int ASSAULT_VALUE_INACTIVE = 1000;
+++ /dev/null
-#include "controlpoint.qh"
-
-#include "command/common.qh"
-
-.bool iscaptured;
-
-bool cpicon_send(entity this, entity to, int sf)
-{
- WriteByte(MSG_ENTITY, ENT_CLIENT_CONTROLPOINT_ICON);
- WriteByte(MSG_ENTITY, sf);
- if(sf & CPSF_SETUP)
- {
- WriteCoord(MSG_ENTITY, self.origin_x);
- WriteCoord(MSG_ENTITY, self.origin_y);
- WriteCoord(MSG_ENTITY, self.origin_z);
-
- WriteByte(MSG_ENTITY, self.health);
- WriteByte(MSG_ENTITY, self.max_health);
- WriteByte(MSG_ENTITY, self.count);
- WriteByte(MSG_ENTITY, self.team);
- WriteByte(MSG_ENTITY, self.owner.iscaptured);
- }
-
- if(sf & CPSF_STATUS)
- {
- WriteByte(MSG_ENTITY, self.team);
-
- if(self.health <= 0)
- WriteByte(MSG_ENTITY, 0);
- else
- WriteByte(MSG_ENTITY, ceil((self.health / self.max_health) * 255));
- }
-
- return true;
-}
-
-void onslaught_controlpoint_icon_link(entity e, void() spawnproc)
-{
- Net_LinkEntity(e, true, 0, cpicon_send);
- e.think = spawnproc;
- e.nextthink = time * sys_frametime;
-}
+++ /dev/null
-#ifndef CONTROLPOINT_H
-#define CONTROLPOINT_H
-
-const vector CPICON_MIN = '-32 -32 -9';
-const vector CPICON_MAX = '32 32 25';
-
-const int CPSF_STATUS = 4;
-const int CPSF_SETUP = 8;
-
-#endif
+++ /dev/null
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../common/constants.qh"
-#endif
-
-void te_csqc_lightningarc(vector from,vector to)
-{
- WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte(MSG_BROADCAST, TE_CSQC_ARC);
-
- WriteCoord(MSG_BROADCAST, from.x);
- WriteCoord(MSG_BROADCAST, from.y);
- WriteCoord(MSG_BROADCAST, from.z);
- WriteCoord(MSG_BROADCAST, to.x);
- WriteCoord(MSG_BROADCAST, to.y);
- WriteCoord(MSG_BROADCAST, to.z);
-}
-
+++ /dev/null
-#ifndef CSQCEFFECTS_H
-#define CSQCEFFECTS_H
-void te_csqc_lightningarc(vector from,vector to);
-#endif
#define SERVER_DEFS_H
#include "../common/weapons/all.qh"
+#include "../common/stats.qh"
-#define INDEPENDENT_ATTACK_FINISHED
+#define INDEPENDENT_ATTACK_FINISHED 1
#define BUTTON_ATCK button0
#define BUTTON_JUMP button2
// Globals
-float g_cloaked, g_footsteps, g_grappling_hook, g_instagib;
+float g_footsteps, g_grappling_hook, g_instagib;
float g_warmup_limit;
float g_warmup_allguns;
float g_warmup_allow_timeout;
float warmup_stage;
-float g_pickup_respawntime_weapon;
-float g_pickup_respawntime_superweapon;
-float g_pickup_respawntime_ammo;
-float g_pickup_respawntime_short;
-float g_pickup_respawntime_medium;
-float g_pickup_respawntime_long;
-float g_pickup_respawntime_powerup;
-float g_pickup_respawntimejitter_weapon;
-float g_pickup_respawntimejitter_superweapon;
-float g_pickup_respawntimejitter_ammo;
-float g_pickup_respawntimejitter_short;
-float g_pickup_respawntimejitter_medium;
-float g_pickup_respawntimejitter_long;
-float g_pickup_respawntimejitter_powerup;
+PROPERTY(float, g_pickup_respawntime_weapon)
+PROPERTY(float, g_pickup_respawntime_superweapon)
+PROPERTY(float, g_pickup_respawntime_ammo)
+PROPERTY(float, g_pickup_respawntime_short)
+PROPERTY(float, g_pickup_respawntime_medium)
+PROPERTY(float, g_pickup_respawntime_long)
+PROPERTY(float, g_pickup_respawntime_powerup)
+PROPERTY(float, g_pickup_respawntimejitter_weapon)
+PROPERTY(float, g_pickup_respawntimejitter_superweapon)
+PROPERTY(float, g_pickup_respawntimejitter_ammo)
+PROPERTY(float, g_pickup_respawntimejitter_short)
+PROPERTY(float, g_pickup_respawntimejitter_medium)
+PROPERTY(float, g_pickup_respawntimejitter_long)
+PROPERTY(float, g_pickup_respawntimejitter_powerup)
float g_jetpack;
float sv_clones;
float team1_score, team2_score, team3_score, team4_score;
-float maxclients;
-
// flag set on worldspawn so that the code knows if it is dedicated or not
float server_is_dedicated;
.float pain_frame; //"
.float crouch; // Crouching or not?
-.float strength_finished;
-.float invincible_finished;
+.float strength_finished = _STAT(STRENGTH_FINISHED);
+.float invincible_finished = _STAT(INVINCIBLE_FINISHED);
.float superweapons_finished;
.float cnt; // used in too many places
// string overrides entity
.string item_pickupsound;
.entity item_pickupsound_ent;
+.entity item_model_ent;
// definitions for weaponsystem
// more WEAPONTODO: move these to their proper files
-.entity weaponentity;
.entity exteriorweaponentity;
.vector weaponentity_glowmod;
//.int weapon; // current weapon
-.int switchweapon; // weapon requested to switch to
+.int switchweapon = _STAT(SWITCHWEAPON);
.int switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible)
.string weaponname; // name of .weapon
// WEAPONTODO
.float autoswitch;
float client_hasweapon(entity cl, float wpn, float andammo, float complain);
-void w_clear(Weapon thiswep, entity actor, bool fire1, bool fire2);
-void w_ready(Weapon thiswep, entity actor, bool fire1, bool fire2);
+void w_clear(Weapon thiswep, entity actor, .entity weaponentity, int fire);
+void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire);
// VorteX: standalone think for weapons, so normal think on weaponentity can be reserved by weaponflashes (which needs update even player dies)
.float weapon_nextthink;
-.void(Weapon thiswep, entity actor, bool fire1, bool fire2) weapon_think;
+.void(Weapon thiswep, entity actor, .entity weaponentity, int fire) weapon_think;
// weapon states (self.weaponentity.state)
// there is 2 weapon tics that can run in one server frame
const int W_TICSPERFRAME = 2;
-void weapon_defaultspawnfunc(float wpn);
+void weapon_defaultspawnfunc(entity this, Weapon e);
float gameover;
float intermission_running;
float bot_waypoints_for_items;
-.float attack_finished_for[Weapons_MAX];
-.float attack_finished_single;
-#ifdef INDEPENDENT_ATTACK_FINISHED
-#define ATTACK_FINISHED_FOR(ent,w) ((ent).(attack_finished_for[(w) - WEP_FIRST]))
+.float attack_finished_for[Weapons_MAX * MAX_WEAPONSLOTS];
+.float attack_finished_single[MAX_WEAPONSLOTS];
+#if INDEPENDENT_ATTACK_FINISHED
+#define ATTACK_FINISHED_FOR(ent, w, slot) ((ent).(attack_finished_for[((w) - WEP_FIRST) * MAX_WEAPONSLOTS + (slot)]))
#else
-#define ATTACK_FINISHED_FOR(ent,w) ((ent).attack_finished_single)
+#define ATTACK_FINISHED_FOR(ent, w, slot) ((ent).attack_finished_single[slot])
#endif
-#define ATTACK_FINISHED(ent) ATTACK_FINISHED_FOR(ent,(ent).weapon)
+#define ATTACK_FINISHED(ent, slot) ATTACK_FINISHED_FOR(ent, (ent).weapon, slot)
// assault game mode: Which team is attacking in this round?
float assault_attacker_team;
float next_pingtime;
-// player sounds, voice messages
-// TODO implemented fall and falling
-#define ALLPLAYERSOUNDS \
- _VOICEMSG(death) \
- _VOICEMSG(drown) \
- _VOICEMSG(fall) \
- _VOICEMSG(falling) \
- _VOICEMSG(gasp) \
- _VOICEMSG(jump) \
- _VOICEMSG(pain100) \
- _VOICEMSG(pain25) \
- _VOICEMSG(pain50) \
- _VOICEMSG(pain75)
-
-#define ALLVOICEMSGS \
- _VOICEMSG(attack) \
- _VOICEMSG(attackinfive) \
- _VOICEMSG(coverme) \
- _VOICEMSG(defend) \
- _VOICEMSG(freelance) \
- _VOICEMSG(incoming) \
- _VOICEMSG(meet) \
- _VOICEMSG(needhelp) \
- _VOICEMSG(seenflag) \
- _VOICEMSG(taunt) \
- _VOICEMSG(teamshoot)
-
-#define _VOICEMSG(m) .string playersound_##m;
-ALLPLAYERSOUNDS
-ALLVOICEMSGS
-#undef _VOICEMSG
-
-// reserved sound names for the future (some models lack sounds for them):
-// _VOICEMSG(flagcarriertakingdamage) \
-// _VOICEMSG(getflag) \
-// reserved sound names for the future (ALL models lack sounds for them):
-// _VOICEMSG(affirmative) \
-// _VOICEMSG(attacking) \
-// _VOICEMSG(defending) \
-// _VOICEMSG(roaming) \
-// _VOICEMSG(onmyway) \
-// _VOICEMSG(droppedflag) \
-// _VOICEMSG(negative) \
-// _VOICEMSG(seenenemy) \
-// /**/
-
-string globalsound_fall;
-string globalsound_metalfall;
-string globalsound_step;
-string globalsound_metalstep;
-
const float VOICETYPE_PLAYERSOUND = 10;
const float VOICETYPE_TEAMRADIO = 11;
const float VOICETYPE_LASTATTACKER = 12;
const float VOICETYPE_AUTOTAUNT = 14;
const float VOICETYPE_TAUNT = 15;
-void PrecachePlayerSounds(string f);
-void PrecacheGlobalSound(string samplestring);
-void UpdatePlayerSounds();
-void ClearPlayerSounds();
-void PlayerSound(.string samplefield, float channel, float voicetype);
-void GlobalSound(string samplestring, float channel, float voicetype);
-void FakeGlobalSound(string samplestring, float channel, float voicetype);
-void VoiceMessage(string type, string message);
-float GetPlayerSoundSampleField_notFound;
-.string GetVoiceMessageSampleField(string type);
-
// autotaunt system
.float cvar_cl_autotaunt;
.float cvar_cl_voice_directional;
float game_starttime; //point in time when the countdown to game start is over
float round_starttime; //point in time when the countdown to round start is over
-.float stat_game_starttime;
+.float stat_game_starttime = _STAT(GAMESTARTTIME);
.float stat_round_starttime;
void W_Porto_Remove (entity p);
bool entcs_send(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_ENTCS);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_ENTCS);
WriteByte(MSG_ENTITY, sf);
if(sf & BIT(0))
WriteByte(MSG_ENTITY, num_for_edict(self.owner) - 1);
entity attach_entcs(entity e)
{
entity ent = e.entcs = new(entcs_sender);
+ make_pure(ent);
ent.owner = e;
ent.think = entcs_think;
ent.nextthink = time;
#include "weapons/accuracy.qh"
#include "weapons/csqcprojectile.qh"
#include "weapons/selection.qh"
-#include "../common/buffs/all.qh"
#include "../common/constants.qh"
#include "../common/deathtypes/all.qh"
#include "../common/notifications.qh"
#include "../lib/csqcmodel/sv_model.qh"
#include "../lib/warpzone/common.qh"
-bool Damage_DamageInfo_SendEntity(entity this, entity to, int sf)
-{
- WriteByte(MSG_ENTITY, ENT_CLIENT_DAMAGEINFO);
- WriteShort(MSG_ENTITY, self.projectiledeathtype);
- WriteCoord(MSG_ENTITY, floor(self.origin.x));
- WriteCoord(MSG_ENTITY, floor(self.origin.y));
- WriteCoord(MSG_ENTITY, floor(self.origin.z));
- WriteByte(MSG_ENTITY, bound(1, self.dmg, 255));
- WriteByte(MSG_ENTITY, bound(0, self.dmg_radius, 255));
- WriteByte(MSG_ENTITY, bound(1, self.dmg_edge, 255));
- WriteShort(MSG_ENTITY, self.oldorigin.x);
- WriteByte(MSG_ENTITY, self.species);
- return true;
-}
-
-void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, int deathtype, float bloodtype, entity dmgowner)
-{
- // TODO maybe call this from non-edgedamage too?
- // TODO maybe make the client do the particle effects for the weapons and the impact sounds using this info?
-
- entity e;
-
- if(!sound_allowed(MSG_BROADCAST, dmgowner))
- deathtype |= 0x8000;
-
- e = spawn();
- setorigin(e, org);
- e.projectiledeathtype = deathtype;
- e.dmg = coredamage;
- e.dmg_edge = edgedamage;
- e.dmg_radius = rad;
- e.dmg_force = vlen(force);
- e.velocity = force;
- e.oldorigin_x = compressShortVector(e.velocity);
- e.species = bloodtype;
-
- Net_LinkEntity(e, false, 0.2, Damage_DamageInfo_SendEntity);
-}
-
void UpdateFrags(entity player, float f)
{
PlayerTeamScore_AddScore(player, f);
{
if(!GiveFrags_randomweapons)
{
- GiveFrags_randomweapons = spawn();
- GiveFrags_randomweapons.classname = "GiveFrags_randomweapons";
+ GiveFrags_randomweapons = new(GiveFrags_randomweapons);
}
if(warmup_stage)
{
if(DEATH_ISSPECIAL(deathtype))
{
- entity deathent = Deathtypes[deathtype - DT_FIRST];
+ entity deathent = Deathtypes_from(deathtype - DT_FIRST);
if (!deathent) { backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n"); return; }
if(murder)
return false;
}
+.int buffs; // TODO: remove
+
void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
{
// Sanity check
targ.revive_speed = freeze_time;
self.bot_attack = false;
- entity ice, head;
- ice = spawn();
+ entity ice = new(ice);
ice.owner = targ;
- ice.classname = "ice";
ice.scale = targ.scale;
ice.think = Ice_Think;
ice.nextthink = time;
RemoveGrapplingHook(targ);
+ entity head;
FOR_EACH_PLAYER(head)
if(head.hook.aiment == targ)
RemoveGrapplingHook(head);
vector farce = damage_explosion_calcpush(self.damageforcescale * force, self.velocity, autocvar_g_balance_damagepush_speedfactor);
if(self.movetype == MOVETYPE_PHYSICS)
{
- entity farcent;
- farcent = spawn();
- farcent.classname = "farce";
+ entity farcent = new(farce);
farcent.enemy = self;
farcent.movedir = farce * 10;
if(self.mass)
if(!e.fire_burner)
{
// print("adding a fire burner to ", e.classname, "\n");
- e.fire_burner = spawn();
- e.fire_burner.classname = "fireburner";
+ e.fire_burner = new(fireburner);
e.fire_burner.think = fireburner_think;
e.fire_burner.nextthink = time;
e.fire_burner.owner = e;
//pl.disableclientprediction = false;
}
-void GrapplingHookReset(void)
+void GrapplingHookReset()
{SELFPARAM();
if(self.realowner.hook == self)
RemoveGrapplingHook(self.owner);
.vector hook_start, hook_end;
bool GrapplingHookSend(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_HOOK);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_HOOK);
sf = sf & 0x7F;
if(sound_allowed(MSG_BROADCAST, self.realowner))
sf |= 0x80;
}
}
-void GrapplingHookTouch (void)
+void GrapplingHookTouch ()
{SELFPARAM();
if(other.movetype == MOVETYPE_FOLLOW)
return;
}
}
-void FireGrapplingHook (void)
+void FireGrapplingHook ()
{SELFPARAM();
entity missile;
vector org;
.float modelscale;
-void g_model_setcolormaptoactivator (void)
+void g_model_setcolormaptoactivator ()
{SELFPARAM();
if(teamplay)
{
self.colormap |= BIT(10); // RENDER_COLORMAPPED
}
-void g_clientmodel_setcolormaptoactivator (void)
+void g_clientmodel_setcolormaptoactivator ()
{SELFPARAM();
g_model_setcolormaptoactivator();
self.SendFlags |= (BIT(3) | BIT(0));
}
-void g_clientmodel_use(void)
+void g_clientmodel_use()
{SELFPARAM();
if (self.antiwall_flag == 1)
{
if(self.lodmodelindex1)
sf |= 0x80;
- WriteByte(MSG_ENTITY, ENT_CLIENT_WALL);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_WALL);
WriteByte(MSG_ENTITY, sf);
- if(sf & 1)
+ if(sf & BIT(0))
{
if(sf & 0x40)
WriteShort(MSG_ENTITY, self.colormap);
}
- if(sf & 2)
+ if(sf & BIT(1))
{
WriteCoord(MSG_ENTITY, self.origin.x);
WriteCoord(MSG_ENTITY, self.origin.y);
WriteCoord(MSG_ENTITY, self.origin.z);
}
- if(sf & 4)
+ if(sf & BIT(2))
{
if(sf & 0x10)
{
}
}
- if(sf & 8)
+ if(sf & BIT(3))
{
if(sf & 0x80)
{
unused but required by the engine
==================
*/
-void main (void)
+void main ()
{
}
#ifndef G_SUBS_H
#define G_SUBS_H
-void SUB_NullThink(void);
+void SUB_NullThink();
void() SUB_CalcMoveDone;
void() SUB_CalcAngleMoveDone;
Remove self
==================
*/
-void SUB_Remove (void);
+void SUB_Remove ();
/*
==================
==================
*/
.float friction;
-void SUB_Friction (void);
+void SUB_Friction ();
/*
==================
*/
void SUB_VanishOrRemove (entity ent);
-void SUB_SetFade_Think (void);
+void SUB_SetFade_Think ();
/*
==================
self.origin traveling at speed
===============
*/
-void SUB_CalcMoveDone (void);
+void SUB_CalcMoveDone ();
.float platmovetype_turn;
-void SUB_CalcMove_controller_think (void);
+void SUB_CalcMove_controller_think ();
void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector dest);
The calling function should make sure self.think is valid
===============
*/
-void SUB_CalcAngleMoveDone (void);
+void SUB_CalcAngleMoveDone ();
// FIXME: I fixed this function only for rotation around the main axes
void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func);
unused but required by the engine
==================
*/
-void main (void);
+void main ();
// Misc
*/
vector findbetterlocation (vector org, float mindist);
-/*
-==================
-crandom
-
-Returns a random number between -1.0 and 1.0
-==================
-*/
-float crandom (void);
-
/*
==================
Angc used for animations
+++ /dev/null
-#include "g_violence.qh"
-
-.int state;
-
-bool Violence_GibSplash_SendEntity(entity this, entity to, int sf)
-{
- WriteByte(MSG_ENTITY, ENT_CLIENT_GIBSPLASH);
- WriteByte(MSG_ENTITY, self.state); // actually type
- WriteByte(MSG_ENTITY, bound(1, self.cnt * 16, 255)); // gibbage amount multiplier
- WriteShort(MSG_ENTITY, floor(self.origin.x / 4)); // not using a coord here, as gibs don't need this accuracy
- WriteShort(MSG_ENTITY, floor(self.origin.y / 4)); // not using a coord here, as gibs don't need this accuracy
- WriteShort(MSG_ENTITY, floor(self.origin.z / 4)); // not using a coord here, as gibs don't need this accuracy
- WriteShort(MSG_ENTITY, self.oldorigin.x); // acrually compressed velocity
- return true;
-}
-
-// TODO maybe convert this to a TE?
-void Violence_GibSplash_At(vector org, vector dir, float type, float amount, entity gibowner, entity attacker)
-{SELFPARAM();
- if(g_cts) // no gibs in CTS
- return;
-
- entity e;
-
- e = spawn();
- e.classname = "gibsplash";
- e.cnt = amount;
- e.state = type; // should stay smaller than 15
- if(!sound_allowed(MSG_BROADCAST, gibowner) || !sound_allowed(MSG_BROADCAST, attacker))
- e.state |= 0x40; // "silence" bit
- e.state |= 8 * self.species; // gib type, ranges from 0 to 15
-
- // if this is a copied dead body, send the num of its player instead
- // TODO: remove this field, read from model txt files
- if(self.classname == "body")
- e.team = num_for_edict(self.enemy);
- else
- e.team = num_for_edict(self);
-
- setorigin(e, org);
- e.velocity = dir;
-
- e.oldorigin_x = compressShortVector(e.velocity);
-
- Net_LinkEntity(e, false, 0.2, Violence_GibSplash_SendEntity);
-}
-
-void Violence_GibSplash(entity source, float type, float amount, entity attacker)
-{
- Violence_GibSplash_At(source.origin + source.view_ofs, source.velocity, type, amount, source, attacker);
-}
+++ /dev/null
-#ifndef G_VIOLENCE_H
-#define G_VIOLENCE_H
-
-bool Violence_GibSplash_SendEntity(entity this, entity to, int sf);
-
-// TODO maybe convert this to a TE?
-void Violence_GibSplash_At(vector org, vector dir, float type, float amount, entity gibowner, entity attacker);
-
-void Violence_GibSplash(entity source, float type, float amount, entity attacker);
-#endif
#include "scores.qh"
#include "teamplay.qh"
#include "weapons/weaponstats.qh"
-#include "../common/buffs/all.qh"
#include "../common/constants.qh"
#include "../common/deathtypes/all.qh"
#include "../common/mapinfo.qh"
e = edict_num(self.cnt + 1);
if(IS_REAL_CLIENT(e))
{
- WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
+ WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
WriteByte(MSG_BROADCAST, self.cnt);
WriteShort(MSG_BROADCAST, max(1, e.ping));
WriteByte(MSG_BROADCAST, ceil(e.ping_packetloss * 255));
}
else
{
- WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
+ WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
WriteByte(MSG_BROADCAST, self.cnt);
WriteShort(MSG_BROADCAST, 0);
WriteByte(MSG_BROADCAST, 0);
}
void PingPLReport_Spawn()
{
- pingplreport = spawn();
- pingplreport.classname = "pingplreport";
+ pingplreport = new(pingplreport);
+ make_pure(pingplreport);
pingplreport.think = PingPLReport_Think;
pingplreport.nextthink = time;
}
void SetDefaultAlpha()
{
- if(autocvar_g_running_guns)
- {
- default_player_alpha = -1;
- default_weapon_alpha = +1;
- }
- else if(g_cloaked)
- {
- default_player_alpha = autocvar_g_balance_cloaked_alpha;
- default_weapon_alpha = default_player_alpha;
- }
- else
+ if (!MUTATOR_CALLHOOK(SetDefaultAlpha))
{
default_player_alpha = autocvar_g_player_alpha;
if(default_player_alpha == 0)
entity randomseed;
bool RandomSeed_Send(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
WriteShort(MSG_ENTITY, self.cnt);
return true;
}
}
void RandomSeed_Spawn()
{SELFPARAM();
- randomseed = spawn();
+ randomseed = new(randomseed);
+ make_pure(randomseed);
randomseed.think = RandomSeed_Think;
Net_LinkEntity(randomseed, false, 0, RandomSeed_Send);
remove = remove_unsafely;
- entity e;
- e = spawn();
+ entity e = spawn();
e.think = GotoFirstMap;
e.nextthink = time; // this is usually 1 at this point
- e = spawn();
- e.classname = "info_player_deathmatch"; // safeguard against player joining
+ e = new(info_player_deathmatch); // safeguard against player joining
self.classname = "worldspawn"; // safeguard against various stuff ;)
// needs to be done so early because of the constants they create
static_init();
static_init_late();
+ static_init_precache();
MapInfo_Enumerate();
MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
InitGameplayMode();
static_init_late();
+ static_init_precache();
readlevelcvars();
GrappleHookInit();
WepSet_AddStat();
WepSet_AddStat_InMap();
- addstat(STAT_SWITCHWEAPON, AS_INT, switchweapon);
addstat(STAT_SWITCHINGWEAPON, AS_INT, switchingweapon);
- addstat(STAT_GAMESTARTTIME, AS_FLOAT, stat_game_starttime);
addstat(STAT_ROUNDSTARTTIME, AS_FLOAT, stat_round_starttime);
addstat(STAT_ALLOW_OLDVORTEXBEAM, AS_INT, stat_allow_oldvortexbeam);
Nagger_Init();
- addstat(STAT_STRENGTH_FINISHED, AS_FLOAT, strength_finished);
- addstat(STAT_INVINCIBLE_FINISHED, AS_FLOAT, invincible_finished);
addstat(STAT_SUPERWEAPONS_FINISHED, AS_FLOAT, superweapons_finished);
addstat(STAT_PRESSED_KEYS, AS_FLOAT, pressedkeys);
addstat(STAT_FUEL, AS_INT, ammo_fuel);
addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
- addstat(STAT_ARC_HEAT, AS_FLOAT, arc_heat_percent);
-
// freeze attacks
addstat(STAT_FROZEN, AS_INT, frozen);
addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, revive_progress);
void FixIntermissionClient(entity e)
{
- string s;
if(!e.autoscreenshot) // initial call
{
e.autoscreenshot = time + 0.8; // used for autoscreenshot
e.solid = SOLID_NOT;
e.movetype = MOVETYPE_NONE;
e.takedamage = DAMAGE_NO;
- if(e.weaponentity)
+ for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
- e.weaponentity.effects = EF_NODRAW;
- if (e.weaponentity.weaponentity)
- e.weaponentity.weaponentity.effects = EF_NODRAW;
+ .entity weaponentity = weaponentities[slot];
+ if(e.(weaponentity))
+ {
+ e.(weaponentity).effects = EF_NODRAW;
+ if (e.(weaponentity).(weaponentity))
+ e.(weaponentity).(weaponentity).effects = EF_NODRAW;
+ }
}
if(IS_REAL_CLIENT(e))
{
stuffcmd(e, "\nscr_printspeed 1000000\n");
- s = autocvar_sv_intermission_cdtrack;
- if(s != "")
- stuffcmd(e, strcat("\ncd loop ", s, "\n"));
+ string list = autocvar_sv_intermission_cdtrack;
+ for(string it; (it = car(list)); list = cdr(list))
+ RandomSelection_Add(world, 0, it, 1, 1);
+ if(RandomSelection_chosen_string && RandomSelection_chosen_string != "")
+ stuffcmd(e, strcat("\ncd loop ", RandomSelection_chosen_string, "\n"));
msg_entity = e;
WriteByte(MSG_ONE, SVC_INTERMISSION);
}
}
// clear the .winning flags
-void ClearWinners(void)
+void ClearWinners()
{
entity head;
FOR_EACH_PLAYER(head)
+++ /dev/null
-#include "generator.qh"
-
-bool generator_send(entity this, entity to, int sf)
-{
- WriteByte(MSG_ENTITY, ENT_CLIENT_GENERATOR);
- WriteByte(MSG_ENTITY, sf);
- if(sf & GSF_SETUP)
- {
- WriteCoord(MSG_ENTITY, self.origin_x);
- WriteCoord(MSG_ENTITY, self.origin_y);
- WriteCoord(MSG_ENTITY, self.origin_z);
-
- WriteByte(MSG_ENTITY, self.health);
- WriteByte(MSG_ENTITY, self.max_health);
- WriteByte(MSG_ENTITY, self.count);
- WriteByte(MSG_ENTITY, self.team);
- }
-
- if(sf & GSF_STATUS)
- {
- WriteByte(MSG_ENTITY, self.team);
-
- if(self.health <= 0)
- WriteByte(MSG_ENTITY, 0);
- else
- WriteByte(MSG_ENTITY, ceil((self.health / self.max_health) * 255));
- }
-
- return true;
-}
-
-void generator_link(void() spawnproc)
-{SELFPARAM();
- Net_LinkEntity(self, true, 0, generator_send);
- self.think = spawnproc;
- self.nextthink = time;
-}
+++ /dev/null
-#ifndef GENERATOR_H
-#define GENERATOR_H
-const vector GENERATOR_MIN = '-52 -52 -14';
-const vector GENERATOR_MAX = '52 52 75';
-
-const int GSF_STATUS = 4;
-const int GSF_SETUP = 8;
-
-bool generator_send(entity this, entity to, int sf);
-#endif
}
}
- entity e;
- e = spawn();
- e.classname = "bansyncer";
+ entity e = new(bansyncer);
e.think = OnlineBanList_Think;
e.nextthink = time + 1;
}
self.message = strzone(strcat("You've picked up the ", self.netname, "!"));
if (self.noise == "")
- self.noise = SND(ITEMPICKUP);
+ self.noise = strzone(SND(ITEMPICKUP));
// save the name for later
item_keys_names[lowestbit(self.itemkeys)] = self.netname;
void MapVote_SendPicture(float id)
{SELFPARAM();
msg_entity = self;
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_PICTURE);
+ WriteHeader(MSG_ONE, TE_CSQC_PICTURE);
WriteByte(MSG_ONE, id);
WritePicture(MSG_ONE, strcat(mapvote_screenshot_dirs[mapvote_maps_screenshot_dir[id]], "/", mapvote_maps[id]), 3072);
}
if(sf & 1)
sf &= ~2; // if we send 1, we don't need to also send 2
- WriteByte(MSG_ENTITY, ENT_CLIENT_MAPVOTE);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_MAPVOTE);
WriteByte(MSG_ENTITY, sf);
if(sf & 1)
}
-string admin_name(void)
+string admin_name()
{
if(autocvar_sv_adminnick != "")
return autocvar_sv_adminnick;
return "SERVER ADMIN";
}
-void DistributeEvenly_Init(float amount, float totalweight)
-{
- if (DistributeEvenly_amount)
- {
- LOG_TRACE("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
- LOG_TRACE(ftos(DistributeEvenly_totalweight), " left!)\n");
- }
- if (totalweight == 0)
- DistributeEvenly_amount = 0;
- else
- DistributeEvenly_amount = amount;
- DistributeEvenly_totalweight = totalweight;
-}
-float DistributeEvenly_Get(float weight)
-{
- float f;
- if (weight <= 0)
- return 0;
- f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
- DistributeEvenly_totalweight -= weight;
- DistributeEvenly_amount -= f;
- return f;
-}
-float DistributeEvenly_GetRandomized(float weight)
-{
- float f;
- if (weight <= 0)
- return 0;
- f = floor(random() + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
- DistributeEvenly_totalweight -= weight;
- DistributeEvenly_amount -= f;
- return f;
-}
-
void GameLogEcho(string s)
{
case "l": replacement = NearestLocation(self.origin); break;
case "y": replacement = NearestLocation(cursor); break;
case "d": replacement = NearestLocation(self.death_origin); break;
- case "w": replacement = WEP_NAME((!self.weapon) ? (!self.switchweapon ? self.cnt : self.switchweapon) : self.weapon); break;
+ case "w": replacement = WEP_NAME(((!self.weapon) ? (!self.switchweapon ? self.cnt : self.switchweapon) : self.weapon)); break;
case "W": replacement = ammoitems; break;
case "x": replacement = ((cursor_ent.netname == "" || !cursor_ent) ? "nothing" : cursor_ent.netname); break;
case "s": replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1')); break;
GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
- GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
- GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
-
- self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
- self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
GetCvars_handleFloat(s, f, cvar_cl_allow_uid2name, "cl_allow_uid2name");
if (e.netname == s)
{
g_weaponarena_weapons |= WepSet_FromWeapon(j);
- g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
+ g_weaponarena_list = strcat(g_weaponarena_list, e.m_name, " & ");
break;
}
}
warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
}
-float sound_allowed(float destin, entity e)
-{
- // sounds from world may always pass
- for (;;)
- {
- if (e.classname == "body")
- e = e.enemy;
- else if (e.realowner && e.realowner != e)
- e = e.realowner;
- else if (e.owner && e.owner != e)
- e = e.owner;
- else
- break;
- }
- // sounds to self may always pass
- if (destin == MSG_ONE)
- if (e == msg_entity)
- return true;
- // sounds by players can be removed
- if (autocvar_bot_sound_monopoly)
- if (IS_REAL_CLIENT(e))
- return false;
- // anything else may pass
- return true;
-}
-
-void soundtoat(float _dest, entity e, vector o, float chan, string samp, float vol, float attenu)
-{
- float entno, idx;
-
- if (!sound_allowed(_dest, e))
- return;
-
- entno = num_for_edict(e);
- idx = precache_sound_index(samp);
-
- int sflags;
- sflags = 0;
-
- attenu = floor(attenu * 64);
- vol = floor(vol * 255);
-
- if (vol != 255)
- sflags |= SND_VOLUME;
- if (attenu != 64)
- sflags |= SND_ATTENUATION;
- if (entno >= 8192 || chan < 0 || chan > 7)
- sflags |= SND_LARGEENTITY;
- if (idx >= 256)
- sflags |= SND_LARGESOUND;
-
- WriteByte(_dest, SVC_SOUND);
- WriteByte(_dest, sflags);
- if (sflags & SND_VOLUME)
- WriteByte(_dest, vol);
- if (sflags & SND_ATTENUATION)
- WriteByte(_dest, attenu);
- if (sflags & SND_LARGEENTITY)
- {
- WriteShort(_dest, entno);
- WriteByte(_dest, chan);
- }
- else
- {
- WriteShort(_dest, entno * 8 + chan);
- }
- if (sflags & SND_LARGESOUND)
- WriteShort(_dest, idx);
- else
- WriteByte(_dest, idx);
-
- WriteCoord(_dest, o.x);
- WriteCoord(_dest, o.y);
- WriteCoord(_dest, o.z);
-}
-void soundto(float _dest, entity e, float chan, string samp, float vol, float _atten)
-{
- vector o;
-
- if (!sound_allowed(_dest, e))
- return;
-
- o = e.origin + 0.5 * (e.mins + e.maxs);
- soundtoat(_dest, e, o, chan, samp, vol, _atten);
-}
-void soundat(entity e, vector o, float chan, string samp, float vol, float _atten)
-{
- soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, _atten);
-}
-void stopsoundto(float _dest, entity e, float chan)
-{
- float entno;
-
- if (!sound_allowed(_dest, e))
- return;
-
- entno = num_for_edict(e);
-
- if (entno >= 8192 || chan < 0 || chan > 7)
- {
- float idx, sflags;
- idx = precache_sound_index(SND(Null));
- sflags = SND_LARGEENTITY;
- if (idx >= 256)
- sflags |= SND_LARGESOUND;
- WriteByte(_dest, SVC_SOUND);
- WriteByte(_dest, sflags);
- WriteShort(_dest, entno);
- WriteByte(_dest, chan);
- if (sflags & SND_LARGESOUND)
- WriteShort(_dest, idx);
- else
- WriteByte(_dest, idx);
- WriteCoord(_dest, e.origin.x);
- WriteCoord(_dest, e.origin.y);
- WriteCoord(_dest, e.origin.z);
- }
- else
- {
- WriteByte(_dest, SVC_STOPSOUND);
- WriteShort(_dest, entno * 8 + chan);
- }
-}
-void stopsound(entity e, float chan)
-{
- if (!sound_allowed(MSG_BROADCAST, e))
- return;
-
- stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
- stopsoundto(MSG_ALL, e, chan); // in case of packet loss
-}
-
-void play2(entity e, string filename)
-{
- //stuffcmd(e, strcat("play2 ", filename, "\n"));
- msg_entity = e;
- soundtoat(MSG_ONE, world, '0 0 0', CH_INFO, filename, VOL_BASE, ATTEN_NONE);
-}
-
-// use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
-.float spamtime;
-float spamsound(entity e, float chan, string samp, float vol, float _atten)
-{
- if (!sound_allowed(MSG_BROADCAST, e))
- return false;
-
- if (time > e.spamtime)
- {
- e.spamtime = time;
- _sound(e, chan, samp, vol, _atten);
- return true;
- }
- return false;
-}
-
-void play2team(float t, string filename)
-{
- entity head;
-
- if (autocvar_bot_sound_monopoly)
- return;
-
- FOR_EACH_REALPLAYER(head)
- {
- if (head.team == t)
- play2(head, filename);
- }
-}
-
-void play2all(string samp)
-{
- if (autocvar_bot_sound_monopoly)
- return;
-
- _sound(world, CH_INFO, samp, VOL_BASE, ATTEN_NONE);
-}
-
void PrecachePlayerSounds(string f);
void precache_playermodel(string m)
{
precache_playermodels(autocvar_sv_defaultplayermodel);
}
- if (g_footsteps)
- {
- PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
- PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
- }
-
- // gore and miscellaneous sounds
- PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
- PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
-
#if 0
// Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
builtin_remove(e);
}
-void InitializeEntity(entity e, void(void) func, float order)
+void InitializeEntity(entity e, void() func, float order)
{
entity prev, cur;
{
float i, f, b;
entity e;
- WriteByte(MSG_ENTITY, ENT_CLIENT_ELIMINATEDPLAYERS);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_ELIMINATEDPLAYERS);
WriteByte(MSG_ENTITY, sendflags);
if(sendflags & 1)
return false;
}
-
+/** engine callback */
void URI_Get_Callback(float id, float status, string data)
{
if(url_URI_Get_Callback(id, status, data))
return gettaginfo(gettaginfo_relative_ent, tag);
}
-.float scale2;
-
-bool modeleffect_SendEntity(entity this, entity to, int sf)
-{
- float f;
- WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
-
- f = 0;
- if(self.velocity != '0 0 0')
- f |= 1;
- if(self.angles != '0 0 0')
- f |= 2;
- if(self.avelocity != '0 0 0')
- f |= 4;
-
- WriteByte(MSG_ENTITY, f);
- WriteShort(MSG_ENTITY, self.modelindex);
- WriteByte(MSG_ENTITY, self.skin);
- WriteByte(MSG_ENTITY, self.frame);
- WriteCoord(MSG_ENTITY, self.origin.x);
- WriteCoord(MSG_ENTITY, self.origin.y);
- WriteCoord(MSG_ENTITY, self.origin.z);
- if(f & 1)
- {
- WriteCoord(MSG_ENTITY, self.velocity.x);
- WriteCoord(MSG_ENTITY, self.velocity.y);
- WriteCoord(MSG_ENTITY, self.velocity.z);
- }
- if(f & 2)
- {
- WriteCoord(MSG_ENTITY, self.angles.x);
- WriteCoord(MSG_ENTITY, self.angles.y);
- WriteCoord(MSG_ENTITY, self.angles.z);
- }
- if(f & 4)
- {
- WriteCoord(MSG_ENTITY, self.avelocity.x);
- WriteCoord(MSG_ENTITY, self.avelocity.y);
- WriteCoord(MSG_ENTITY, self.avelocity.z);
- }
- WriteShort(MSG_ENTITY, self.scale * 256.0);
- WriteShort(MSG_ENTITY, self.scale2 * 256.0);
- WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
- WriteByte(MSG_ENTITY, self.fade_time * 100.0);
- WriteByte(MSG_ENTITY, self.alpha * 255.0);
-
- return true;
-}
-
-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)
-{
- entity e;
- float sz;
- e = spawn();
- e.classname = "modeleffect";
- _setmodel(e, m);
- e.frame = f;
- setorigin(e, o);
- e.velocity = v;
- e.angles = ang;
- e.avelocity = angv;
- e.alpha = a;
- e.teleport_time = t1;
- e.fade_time = t2;
- e.skin = s;
- if(s0 >= 0)
- e.scale = s0 / max6(-e.mins.x, -e.mins.y, -e.mins.z, e.maxs.x, e.maxs.y, e.maxs.z);
- else
- e.scale = -s0;
- if(s2 >= 0)
- e.scale2 = s2 / max6(-e.mins.x, -e.mins.y, -e.mins.z, e.maxs.x, e.maxs.y, e.maxs.z);
- else
- e.scale2 = -s2;
- sz = max(e.scale, e.scale2);
- setsize(e, e.mins * sz, e.maxs * sz);
- Net_LinkEntity(e, false, 0.1, modeleffect_SendEntity);
-}
-
-void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
-{
- return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
-}
-
-float randombit(float bits)
-{
- if(!(bits & (bits-1))) // this ONLY holds for powers of two!
- return bits;
-
- float n, f, b, r;
-
- r = random();
- b = 0;
- n = 0;
-
- for(f = 1; f <= bits; f *= 2)
- {
- if(bits & f)
- {
- ++n;
- r *= n;
- if(r <= 1)
- b = f;
- else
- r = (r - 1) / (n - 1);
- }
- }
-
- return b;
-}
-
-float randombits(float bits, float k, float error_return)
-{
- float r;
- r = 0;
- while(k > 0 && bits != r)
- {
- r += randombit(bits - r);
- --k;
- }
- if(error_return)
- if(k > 0)
- return -1; // all
- return r;
-}
-
-void randombit_test(float bits, float iter)
-{
- while(iter > 0)
- {
- LOG_INFO(ftos(randombit(bits)), "\n");
- --iter;
- }
-}
-
-float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
-{
- if(halflifedist > 0)
- return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
- else if(halflifedist < 0)
- return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
- else
- return 1;
-}
-
-
.string aiment_classname;
.float aiment_deadflag;
void SetMovetypeFollow(entity ent, entity e)
entity eliminatedPlayers;
void EliminatedPlayers_Init(float(entity) isEliminated_func);
-string admin_name(void);
+string admin_name();
void write_recordmarker(entity pl, float tstart, float dt);
void play2all(string samp);
-void DistributeEvenly_Init(float amount, float totalweight);
-float DistributeEvenly_Get(float weight);
-
-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);
-
-void shockwave_spawn(string m, vector org, float sz, float t1, float t2);
-
void play2team(float t, string filename);
void GetCvars_handleFloat(string thisname, float f, .float field, string name);
void stopsoundto(float _dest, entity e, float chan);
void soundtoat(float _dest, entity e, vector o, float chan, string samp, float vol, float _atten);
-float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d);
-float DistributeEvenly_amount;
-float DistributeEvenly_totalweight;
void objerror(string s);
void droptofloor();
void() SUB_Remove;
#define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
-const string STR_PLAYER = "player";
-const string STR_SPECTATOR = "spectator";
-const string STR_OBSERVER = "observer";
-
-#define IS_PLAYER(v) ((v).classname == STR_PLAYER)
-#define IS_SPEC(v) ((v).classname == STR_SPECTATOR)
-#define IS_OBSERVER(v) ((v).classname == STR_OBSERVER)
-#define IS_CLIENT(v) (v.flags & FL_CLIENT)
-#define IS_BOT_CLIENT(v) (clienttype(v) == CLIENTTYPE_BOT)
-#define IS_REAL_CLIENT(v) (clienttype(v) == CLIENTTYPE_REAL)
-#define IS_NOT_A_CLIENT(v) (clienttype(v) == CLIENTTYPE_NOTACLIENT)
-
-#define IS_MONSTER(v) (v.flags & FL_MONSTER)
-#define IS_VEHICLE(v) (v.vehicle_flags & VHF_ISVEHICLE)
-#define IS_TURRET(v) (v.turret_flags & TUR_FLAG_ISTURRET)
-
-#define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
-#define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(IS_CLIENT(v))
-#define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(IS_REAL_CLIENT(v))
-
-#define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(IS_PLAYER(v))
-#define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if (!IS_PLAYER(v)) // Samual: shouldn't this be IS_SPEC(v)? and rather create a separate macro to include observers too
-#define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(IS_PLAYER(v))
-
-#define FOR_EACH_MONSTER(v) for(v = world; (v = findflags(v, flags, FL_MONSTER)) != world; )
-
#define CENTER_OR_VIEWOFS(ent) (ent.origin + (IS_PLAYER(ent) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
// copies a string to a tempstring (so one can strunzone it)
float sv_taunt;
string GetGametype(); // g_world.qc
-void readlevelcvars(void)
+void readlevelcvars()
{
if(cvar("sv_allow_fullbright"))
serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
sv_clones = cvar("sv_clones");
sv_foginterval = cvar("sv_foginterval");
- g_cloaked = cvar("g_cloaked");
g_footsteps = cvar("g_footsteps");
g_jetpack = cvar("g_jetpack");
sv_maxidle = cvar("sv_maxidle");
//#NO AUTOCVARS END
-
-// Sound functions
-//string precache_sound (string s) = #19;
-// hack
-float precache_sound_index (string s) = #19;
-
-const float SND_VOLUME = BIT(0);
-const float SND_ATTENUATION = BIT(1);
-const float SND_LARGEENTITY = BIT(3);
-const float SND_LARGESOUND = BIT(4);
-
const float INITPRIO_FIRST = 0;
const float INITPRIO_GAMETYPE = 0;
const float INITPRIO_GAMETYPE_FALLBACK = 1;
const float INITPRIO_LINKDOORS = 91;
const float INITPRIO_LAST = 99;
-.void(void) initialize_entity;
+.void() initialize_entity;
.float initialize_entity_order;
.entity initialize_entity_next;
entity initialize_entity_first;
float sound_allowed(float dest, entity e);
-void InitializeEntity(entity e, void(void) func, float order);
-void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer);
+void InitializeEntity(entity e, void() func, float order);
+void SetCustomizer(entity e, float() customizer, void() uncustomizer);
#endif
#include "mutator/gamemode_keepaway.qc"
#include "mutator/gamemode_keyhunt.qc"
#include "mutator/gamemode_lms.qc"
-#include "mutator/gamemode_onslaught.qc"
#include "mutator/gamemode_race.qc"
#include "mutator/gamemode_tdm.qc"
-
-#include "mutator/mutator_bloodloss.qc"
-#include "mutator/mutator_breakablehook.qc"
-#include "mutator/mutator_buffs.qc"
-#include "mutator/mutator_campcheck.qc"
-#include "mutator/mutator_dodging.qc"
-#include "mutator/mutator_hook.qc"
-#include "mutator/mutator_invincibleproj.qc"
-#include "mutator/mutator_melee_only.qc"
-#include "mutator/mutator_midair.qc"
-#include "mutator/mutator_multijump.qc"
-#include "mutator/mutator_nades.qc"
-#include "mutator/mutator_new_toys.qc"
-#include "mutator/mutator_nix.qc"
-#include "mutator/mutator_overkill.qc"
-#include "mutator/mutator_physical_items.qc"
-#include "mutator/mutator_pinata.qc"
-#include "mutator/mutator_random_gravity.qc"
-#include "mutator/mutator_rocketflying.qc"
-#include "mutator/mutator_rocketminsta.qc"
-#include "mutator/mutator_spawn_near_teammate.qc"
-#include "mutator/mutator_superspec.qc"
-#include "mutator/mutator_touchexplode.qc"
-#include "mutator/mutator_vampirehook.qc"
-#include "mutator/mutator_vampire.qc"
-#include "mutator/mutator_weaponarena_random.qc"
-
-#include "mutator/sandbox.qc"
#include "../../common/stats.qh"
#include "../../common/teams.qh"
#include "../../common/util.qh"
- #include "../../common/nades/all.qh"
- #include "../../common/buffs/all.qh"
#include "../../common/command/markup.qh"
#include "../../common/command/rpn.qh"
#include "../../common/command/generic.qh"
/** returns true if dropping the current weapon shall not be allowed at any time including death */
MUTATOR_HOOKABLE(ForbidDropCurrentWeapon, EV_NO_ARGS);
+/** */
+MUTATOR_HOOKABLE(SetDefaultAlpha, EV_NO_ARGS);
+
/** allows changing attack rate */
#define EV_WeaponRateFactor(i, o) \
/**/ i(float, weapon_rate) \
* checks if the current item may be spawned (self.items and self.weapons may be read and written to, as well as the ammo_ fields)
* return error to request removal
*/
-MUTATOR_HOOKABLE(FilterItem, EV_NO_ARGS);
+#define EV_FilterItem(i, o) \
+ /** the current item */ i(entity, __self) \
+ /**/
+MUTATOR_HOOKABLE(FilterItem, EV_FilterItem);
/** return error to request removal */
#define EV_TurretSpawn(i, o) \
* Called when a player is damaged
*/
#define EV_PlayerDamaged(i, o) \
- /** attacker */ i(entity, mutator_argv_entity_0) \
- /** target */ i(entity, mutator_argv_entity_1) \
- /** health */ i(int, mutator_argv_int_0) \
- /** armor */ i(int, mutator_argv_int_1) \
- /** location */ i(vector, mutator_argv_vector_0) \
- /** deathtype */ i(int, mutator_argv_int_2) \
+ /** attacker */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** target */ i(entity, MUTATOR_ARGV_1_entity) \
+ /** health */ i(int, MUTATOR_ARGV_0_int) \
+ /** armor */ i(int, MUTATOR_ARGV_1_int) \
+ /** location */ i(vector, MUTATOR_ARGV_0_vector) \
+ /** deathtype */ i(int, MUTATOR_ARGV_2_int) \
/**/
MUTATOR_HOOKABLE(PlayerDamaged, EV_PlayerDamaged);
+/**
+ * Called by W_DecreaseAmmo
+ */
+#define EV_W_DecreaseAmmo(i, o) \
+ /** actor */ i(entity, MUTATOR_ARGV_0_entity) \
+ /**/
+MUTATOR_HOOKABLE(W_DecreaseAmmo, EV_W_DecreaseAmmo);
+
+/**
+ * Called by W_Reload
+ */
+#define EV_W_Reload(i, o) \
+ /** actor */ i(entity, MUTATOR_ARGV_0_entity) \
+ /**/
+MUTATOR_HOOKABLE(W_Reload, EV_W_Reload);
+
/** called at the end of player_powerups() in cl_client.qc, used for manipulating the values which are set by powerup items. */
#define EV_PlayerPowerups(i, o) \
/**/ i(entity, __self) \
/**/ i(entity, __self) \
/**/
MUTATOR_HOOKABLE(TurretThink, EV_TurretThink);
+
+MUTATOR_HOOKABLE(Ent_Init, EV_NO_ARGS);
+
+/** */
+#define EV_PrepareExplosionByDamage(i, o) \
+ /**/ i(entity, __self) \
+ /**/ i(entity, frag_attacker) \
+ /**/
+MUTATOR_HOOKABLE(PrepareExplosionByDamage, EV_PrepareExplosionByDamage);
+
+/** called when a monster model is about to be set, allows custom paths etc. */
+#define EV_MonsterModel(i, o) \
+ /**/ i(string, monster_model) \
+ /**/ i(string, monster_model_output) \
+ /**/ o(string, monster_model_output) \
+ /**/
+string monster_model;
+string monster_model_output;
+MUTATOR_HOOKABLE(MonsterModel, EV_MonsterModel);
#endif
REGISTER_MUTATOR(ca, false)
{
- ActivateTeamplay();
- SetLimits(autocvar_g_ca_point_limit, autocvar_g_ca_point_leadlimit, -1, -1);
-
- if (autocvar_g_ca_team_spawns)
- have_team_spawns = -1; // request team spawns
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
ca_Initialize();
+
+ ActivateTeamplay();
+ SetLimits(autocvar_g_ca_point_limit, autocvar_g_ca_point_leadlimit, -1, -1);
+
+ if (autocvar_g_ca_team_spawns)
+ have_team_spawns = -1; // request team spawns
}
MUTATOR_ONREMOVE
REGISTER_MUTATOR(ctf, false)
{
- ActivateTeamplay();
- SetLimits(autocvar_capturelimit_override, -1, autocvar_captureleadlimit_override, -1);
- have_team_spawns = -1; // request team spawns
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
ctf_Initialize();
+
+ ActivateTeamplay();
+ SetLimits(autocvar_capturelimit_override, autocvar_captureleadlimit_override, -1, -1);
+ have_team_spawns = -1; // request team spawns
}
MUTATOR_ONROLLBACK_OR_REMOVE
const int SP_CTF_FCKILLS = 8;
const int SP_CTF_RETURNS = 9;
+CLASS(Flag, Pickup)
+ ATTRIB(Flag, m_mins, vector, PL_MIN_CONST + '0 0 -13')
+ ATTRIB(Flag, m_maxs, vector, PL_MAX_CONST + '0 0 -13')
+ENDCLASS(Flag)
+Flag CTF_FLAG; STATIC_INIT(Flag) { CTF_FLAG = NEW(Flag); }
+void ctf_FlagTouch() { SELFPARAM(); ITEM_HANDLE(Pickup, CTF_FLAG, this, other); }
+
// flag constants // for most of these, there is just one question to be asked: WHYYYYY?
-#define FLAG_MIN (PL_MIN_CONST + '0 0 -13')
-#define FLAG_MAX (PL_MAX_CONST + '0 0 -13')
const float FLAG_SCALE = 0.6;
const int RETURN_SPEEDRUN = 4;
const int RETURN_NEEDKILL = 5;
+void ctf_Handle_Throw(entity player, entity receiver, float droptype);
+
// flag properties
#define ctf_spawnorigin dropped_origin
bool ctf_stalemate; // indicates that a stalemate is active
void ctf_CaptureShield_Spawn(entity flag)
{SELFPARAM();
- entity shield = spawn();
+ entity shield = new(ctf_captureshield);
shield.enemy = self;
shield.team = self.team;
shield.touch = ctf_CaptureShield_Touch;
shield.customizeentityforclient = ctf_CaptureShield_Customize;
- shield.classname = "ctf_captureshield";
shield.effects = EF_ADDITIVE;
shield.movetype = MOVETYPE_NOCLIP;
shield.solid = SOLID_TRIGGER;
ctf_CaptureShield_Update(player, 0); // shield player from picking up flag
}
+void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
+{
+ return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
+}
// ==============
// Event Handlers
return true;
}
-void ctf_CheckStalemate(void)
+void ctf_CheckStalemate()
{
// declarations
int stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0, stale_neutral_flags = 0;
ctf_CaptureShield_Update(tmp_entity, 1); // release shield only
// sanity checks
- if(self.mins != FLAG_MIN || self.maxs != FLAG_MAX) { // reset the flag boundaries in case it got squished
+ if(self.mins != CTF_FLAG.m_mins || self.maxs != CTF_FLAG.m_maxs) { // reset the flag boundaries in case it got squished
LOG_TRACE("wtf the flag got squashed?\n");
- tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self);
+ tracebox(self.origin, CTF_FLAG.m_mins, CTF_FLAG.m_maxs, self.origin, MOVE_NOMONSTERS, self);
if(!trace_startsolid || self.noalign) // can we resize it without getting stuck?
- setsize(self, FLAG_MIN, FLAG_MAX); }
+ setsize(self, CTF_FLAG.m_mins, CTF_FLAG.m_maxs); }
switch(self.ctf_status) // reset flag angles in case warpzones adjust it
{
}
}
-void ctf_FlagTouch()
-{SELFPARAM();
+METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
+{
+ return = false;
if(gameover) { return; }
if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
- entity toucher = other, tmp_entity;
- bool is_not_monster = (!IS_MONSTER(toucher)), num_perteam = 0;
+ bool is_not_monster = (!IS_MONSTER(toucher));
// automatically kill the flag and return it if it touched lava/slime/nodrop surfaces
if(ITEM_TOUCH_NEEDKILL())
{
if(!autocvar_g_ctf_flag_return_damage_delay)
{
- self.health = 0;
- ctf_CheckFlagReturn(self, RETURN_NEEDKILL);
+ flag.health = 0;
+ ctf_CheckFlagReturn(flag, RETURN_NEEDKILL);
}
- if(!self.ctf_flagdamaged) { return; }
+ if(!flag.ctf_flagdamaged) { return; }
}
- FOR_EACH_PLAYER(tmp_entity) if(SAME_TEAM(toucher, tmp_entity)) { ++num_perteam; }
+ int num_perteam = 0;
+ entity tmp_entity; FOR_EACH_PLAYER(tmp_entity) if(SAME_TEAM(toucher, tmp_entity)) { ++num_perteam; }
// special touch behaviors
if(toucher.frozen) { return; }
}
else if (!IS_PLAYER(toucher)) // The flag just touched an object, most likely the world
{
- if(time > self.wait) // if we haven't in a while, play a sound/effect
+ if(time > flag.wait) // if we haven't in a while, play a sound/effect
{
- Send_Effect_(self.toucheffect, self.origin, '0 0 0', 1);
- _sound(self, CH_TRIGGER, self.snd_flag_touch, VOL_BASE, ATTEN_NORM);
- self.wait = time + FLAG_TOUCHRATE;
+ Send_Effect_(flag.toucheffect, flag.origin, '0 0 0', 1);
+ _sound(flag, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
+ flag.wait = time + FLAG_TOUCHRATE;
}
return;
}
else if(toucher.deadflag != DEAD_NO) { return; }
- switch(self.ctf_status)
+ switch(flag.ctf_status)
{
case FLAG_BASE:
{
if(ctf_oneflag)
{
- if(CTF_SAMETEAM(toucher, self) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
- ctf_Handle_Capture(self, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
- else if(!self.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
- ctf_Handle_Pickup(self, toucher, PICKUP_BASE); // toucher just stole the neutral flag
+ if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
+ ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
+ else if(!flag.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
+ ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the neutral flag
}
- else if(CTF_SAMETEAM(toucher, self) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, self) && is_not_monster)
- ctf_Handle_Capture(self, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
- else if(CTF_DIFFTEAM(toucher, self) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
- ctf_Handle_Pickup(self, toucher, PICKUP_BASE); // toucher just stole the enemies flag
+ else if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, flag) && is_not_monster)
+ ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
+ else if(CTF_DIFFTEAM(toucher, flag) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
+ ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the enemies flag
break;
}
case FLAG_DROPPED:
{
- if(CTF_SAMETEAM(toucher, self) && (autocvar_g_ctf_flag_return || num_perteam <= 1) && self.team) // automatically return if there's only 1 player on the team
- ctf_Handle_Return(self, toucher); // toucher just returned his own flag
- else if(is_not_monster && (!toucher.flagcarried) && ((toucher != self.ctf_dropper) || (time > self.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
- ctf_Handle_Pickup(self, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
+ if(CTF_SAMETEAM(toucher, flag) && (autocvar_g_ctf_flag_return || num_perteam <= 1) && flag.team) // automatically return if there's only 1 player on the team
+ ctf_Handle_Return(flag, toucher); // toucher just returned his own flag
+ else if(is_not_monster && (!toucher.flagcarried) && ((toucher != flag.ctf_dropper) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
+ ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
break;
}
case FLAG_PASSING:
{
- if((IS_PLAYER(toucher)) && (toucher.deadflag == DEAD_NO) && (toucher != self.pass_sender))
+ if((IS_PLAYER(toucher)) && (toucher.deadflag == DEAD_NO) && (toucher != flag.pass_sender))
{
- if(DIFF_TEAM(toucher, self.pass_sender))
- ctf_Handle_Return(self, toucher);
+ if(DIFF_TEAM(toucher, flag.pass_sender))
+ ctf_Handle_Return(flag, toucher);
else
- ctf_Handle_Retrieve(self, toucher);
+ ctf_Handle_Retrieve(flag, toucher);
}
break;
}
ctf_RespawnFlag(self);
}
-void ctf_DelayedFlagSetup(void) // called after a flag is placed on a map by ctf_FlagSetup()
+void ctf_DelayedFlagSetup() // called after a flag is placed on a map by ctf_FlagSetup()
{SELFPARAM();
// bot waypoints
waypoint_spawnforitem_force(self, self.origin);
ctf_CaptureShield_Spawn(self);
}
-void set_flag_string(entity flag, .string field, string value, string teamname)
-{
- if(flag.(field) == "")
- flag.(field) = strzone(sprintf(value,teamname));
-}
-
void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
{SELFPARAM();
// declarations
if(!flag.scale) { flag.scale = FLAG_SCALE; }
if(flag.skin == 0) { flag.skin = cvar(sprintf("g_ctf_flag_%s_skin", teamname)); }
if(flag.model == "") { flag.model = cvar_string(sprintf("g_ctf_flag_%s_model", teamname)); }
- set_flag_string(flag, toucheffect, "%sflag_touch", teamname);
- set_flag_string(flag, passeffect, "%s_pass", teamname);
- set_flag_string(flag, capeffect, "%s_cap", teamname);
+ if (flag.toucheffect == "") { flag.toucheffect = EFFECT_FLAG_TOUCH(teamnumber).eent_eff_name; }
+ if (flag.passeffect == "") { flag.passeffect = EFFECT_PASS(teamnumber).eent_eff_name; }
+ if (flag.capeffect == "") { flag.capeffect = EFFECT_CAP(teamnumber).eent_eff_name; }
// sounds
- flag.snd_flag_taken = SND(CTF_TAKEN(teamnumber));
- flag.snd_flag_returned = SND(CTF_RETURNED(teamnumber));
- flag.snd_flag_capture = SND(CTF_CAPTURE(teamnumber));
- flag.snd_flag_dropped = SND(CTF_DROPPED(teamnumber));
- if (flag.snd_flag_respawn == "") flag.snd_flag_respawn = SND(CTF_RESPAWN); // if there is ever a team-based sound for this, update the code to match.
+ flag.snd_flag_taken = strzone(SND(CTF_TAKEN(teamnumber)));
+ flag.snd_flag_returned = strzone(SND(CTF_RETURNED(teamnumber)));
+ flag.snd_flag_capture = strzone(SND(CTF_CAPTURE(teamnumber)));
+ flag.snd_flag_dropped = strzone(SND(CTF_DROPPED(teamnumber)));
+ if (flag.snd_flag_respawn == "") flag.snd_flag_respawn = strzone(SND(CTF_RESPAWN)); // if there is ever a team-based sound for this, update the code to match.
precache_sound(flag.snd_flag_respawn);
- if (flag.snd_flag_touch == "") flag.snd_flag_touch = SND(CTF_TOUCH); // again has no team-based sound
+ if (flag.snd_flag_touch == "") flag.snd_flag_touch = strzone(SND(CTF_TOUCH)); // again has no team-based sound
precache_sound(flag.snd_flag_touch);
- if (flag.snd_flag_pass == "") flag.snd_flag_pass = SND(CTF_PASS); // same story here
+ if (flag.snd_flag_pass == "") flag.snd_flag_pass = strzone(SND(CTF_PASS)); // same story here
precache_sound(flag.snd_flag_pass);
// precache
// appearence
_setmodel(flag, flag.model); // precision set below
- setsize(flag, FLAG_MIN, FLAG_MAX);
+ setsize(flag, CTF_FLAG.m_mins, CTF_FLAG.m_maxs);
setorigin(flag, (flag.origin + FLAG_SPAWN_OFFSET));
if(autocvar_g_ctf_flag_glowtrails)
REGISTER_MUTATOR(cts, false)
{
- g_race_qualifying = true;
- independent_players = 1;
- SetLimits(0, 0, 0, -1);
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
cts_Initialize();
+
+ g_race_qualifying = true;
+ independent_players = 1;
+ SetLimits(0, 0, 0, -1);
}
MUTATOR_ONROLLBACK_OR_REMOVE
return true; // in CTS, you don't lose score by observing
}
-MUTATOR_HOOKFUNCTION(cts, SetModname)
-{
- g_cloaked = 1; // always enable cloak in CTS
-
- return false;
-}
-
MUTATOR_HOOKFUNCTION(cts, GetRecords)
{
for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
MUTATOR_ONREMOVE
{
- print("This is a game type and it cannot be removed at runtime.");
+ error("This is a game type and it cannot be removed at runtime.");
return -1;
}
REGISTER_MUTATOR(dom, false)
{
- int fraglimit_override = autocvar_g_domination_point_limit;
- if (autocvar_g_domination_roundbased && autocvar_g_domination_roundbased_point_limit)
- fraglimit_override = autocvar_g_domination_roundbased_point_limit;
-
- ActivateTeamplay();
- SetLimits(fraglimit_override, autocvar_g_domination_point_leadlimit, -1, -1);
- have_team_spawns = -1; // request team spawns
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
dom_Initialize();
+
+ int fraglimit_override = autocvar_g_domination_point_limit;
+ if (autocvar_g_domination_roundbased && autocvar_g_domination_roundbased_point_limit)
+ fraglimit_override = autocvar_g_domination_roundbased_point_limit;
+
+ ActivateTeamplay();
+ SetLimits(fraglimit_override, autocvar_g_domination_point_leadlimit, -1, -1);
+ have_team_spawns = -1; // request team spawns
}
MUTATOR_ONREMOVE
REGISTER_MUTATOR(ft, false)
{
- ActivateTeamplay();
- SetLimits(autocvar_g_freezetag_point_limit, autocvar_g_freezetag_point_leadlimit, -1, -1);
-
- if (autocvar_g_freezetag_team_spawns)
- have_team_spawns = -1; // request team spawns
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
freezetag_Initialize();
+
+ ActivateTeamplay();
+ SetLimits(autocvar_g_freezetag_point_limit, autocvar_g_freezetag_point_leadlimit, -1, -1);
+
+ if (autocvar_g_freezetag_team_spawns)
+ have_team_spawns = -1; // request team spawns
}
MUTATOR_ONROLLBACK_OR_REMOVE
float freezetag_teams;
.float reviving; // temp var
-#endif
+float autocvar_g_freezetag_revive_extra_size;
+float autocvar_g_freezetag_revive_speed;
+bool autocvar_g_freezetag_revive_nade;
+float autocvar_g_freezetag_revive_nade_health;
+
+#endif
#ifdef IMPLEMENTATION
float autocvar_g_freezetag_frozen_maxtime;
-bool autocvar_g_freezetag_revive_nade;
-float autocvar_g_freezetag_revive_nade_health;
-float autocvar_g_freezetag_revive_extra_size;
-float autocvar_g_freezetag_revive_speed;
float autocvar_g_freezetag_revive_clearspeed;
float autocvar_g_freezetag_round_timelimit;
int autocvar_g_freezetag_teams;
REGISTER_MUTATOR(inv, false)
{
- SetLimits(autocvar_g_invasion_point_limit, -1, -1, -1);
- if (autocvar_g_invasion_teams >= 2)
- {
- ActivateTeamplay();
- if (autocvar_g_invasion_team_spawns)
- have_team_spawns = -1; // request team spawns
- }
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
invasion_Initialize();
cvar_settemp("g_monsters", "1");
+
+ SetLimits(autocvar_g_invasion_point_limit, -1, -1, -1);
+ if (autocvar_g_invasion_teams >= 2)
+ {
+ ActivateTeamplay();
+ if (autocvar_g_invasion_team_spawns)
+ have_team_spawns = -1; // request team spawns
+ }
}
MUTATOR_ONROLLBACK_OR_REMOVE
void ka_SpawnBall() // loads various values for the ball, runs only once at start of match
{
- entity e;
- e = spawn();
+ entity e = new(keepawayball);
e.model = "models/orbs/orbblue.md3";
precache_model(e.model);
_setmodel(e, e.model);
setsize(e, '-16 -16 -20', '16 16 20'); // 20 20 20 was too big, player is only 16 16 24... gotta cheat with the Z (20) axis so that the particle isn't cut off
- e.classname = "keepawayball";
e.damageforcescale = autocvar_g_keepawayball_damageforcescale;
e.takedamage = DAMAGE_YES;
e.solid = SOLID_TRIGGER;
REGISTER_MUTATOR(kh, false)
{
- ActivateTeamplay();
- SetLimits(autocvar_g_keyhunt_point_limit, autocvar_g_keyhunt_point_leadlimit, -1, -1);
- if (autocvar_g_keyhunt_team_spawns)
- have_team_spawns = -1; // request team spawns
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
kh_Initialize();
+
+ ActivateTeamplay();
+ SetLimits(autocvar_g_keyhunt_point_limit, autocvar_g_keyhunt_point_leadlimit, -1, -1);
+ if (autocvar_g_keyhunt_team_spawns)
+ have_team_spawns = -1; // request team spawns
}
MUTATOR_ONROLLBACK_OR_REMOVE
.entity kh_next;
float kh_Key_AllOwnedByWhichTeam();
-typedef void(void) kh_Think_t;
+typedef void() kh_Think_t;
void kh_StartRound();
void kh_Controller_SetThink(float t, kh_Think_t func);
// bits 5- 9: team of key 2, or 0 for no such key, or 30 for dropped, or 31 for self
// bits 10-14: team of key 3, or 0 for no such key, or 30 for dropped, or 31 for self
// bits 15-19: team of key 4, or 0 for no such key, or 30 for dropped, or 31 for self
-.float kh_state;
+.float kh_state = _STAT(KH_KEYS);
.float siren_time; // time delay the siren
//.float stuff_time; // time delay to stuffcmd a cvar
}
const string STR_ITEM_KH_KEY = "item_kh_key";
-void kh_Key_Spawn(entity initial_owner, float angle, float i) // runs every time a new flag is created, ie after all the keys have been collected
+void kh_Key_Spawn(entity initial_owner, float _angle, float i) // runs every time a new flag is created, ie after all the keys have been collected
{
- entity key;
- key = spawn();
+ entity key = spawn();
key.count = i;
key.classname = STR_ITEM_KH_KEY;
key.touch = kh_Key_Touch;
key.think = kh_Key_Think;
key.nextthink = time;
key.items = IT_KEY1 | IT_KEY2;
- key.cnt = angle;
+ key.cnt = _angle;
key.angles = '0 360 0' * random();
key.event_damage = kh_Key_Damage;
key.takedamage = DAMAGE_YES;
kh_controller.model = "";
kh_controller.modelindex = 0;
- addstat(STAT_KH_KEYS, AS_INT, kh_state);
-
kh_ScoreRules(kh_teams);
}
REGISTER_MUTATOR(lms, false)
{
- SetLimits(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override), 0, -1, -1);
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
lms_Initialize();
+
+ SetLimits(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override), 0, -1, -1);
}
MUTATOR_ONROLLBACK_OR_REMOVE
+++ /dev/null
-#ifndef GAMEMODE_ONSLAUGHT_H
-#define GAMEMODE_ONSLAUGHT_H
-
-float autocvar_g_onslaught_point_limit;
-void ons_Initialize();
-
-REGISTER_MUTATOR(ons, false)
-{
- ActivateTeamplay();
- SetLimits(autocvar_g_onslaught_point_limit, -1, -1, -1);
- have_team_spawns = -1; // request team spawns
-
- MUTATOR_ONADD
- {
- if (time > 1) // game loads at time 1
- error("This is a game type and it cannot be added at runtime.");
- ons_Initialize();
- }
-
- MUTATOR_ONROLLBACK_OR_REMOVE
- {
- // we actually cannot roll back ons_Initialize here
- // BUT: we don't need to! If this gets called, adding always
- // succeeds.
- }
-
- MUTATOR_ONREMOVE
- {
- LOG_INFO("This is a game type and it cannot be removed at runtime.");
- return -1;
- }
-
- return false;
-}
-
-#ifdef SVQC
-
-.entity ons_toucher; // player who touched the control point
-
-// control point / generator constants
-const float ONS_CP_THINKRATE = 0.2;
-const float GEN_THINKRATE = 1;
-#define CPGEN_SPAWN_OFFSET ('0 0 1' * (PL_MAX_CONST.z - 13))
-const vector CPGEN_WAYPOINT_OFFSET = ('0 0 128');
-const vector CPICON_OFFSET = ('0 0 96');
-
-// list of generators on the map
-entity ons_worldgeneratorlist;
-.entity ons_worldgeneratornext;
-.entity ons_stalegeneratornext;
-
-// list of control points on the map
-entity ons_worldcplist;
-.entity ons_worldcpnext;
-.entity ons_stalecpnext;
-
-// list of links on the map
-entity ons_worldlinklist;
-.entity ons_worldlinknext;
-.entity ons_stalelinknext;
-
-// definitions
-.entity sprite;
-.string target2;
-.int iscaptured;
-.int islinked;
-.int isshielded;
-.float lasthealth;
-.int lastteam;
-.int lastshielded;
-.int lastcaptured;
-
-.bool waslinked;
-
-bool ons_stalemate;
-
-.float teleport_antispam;
-
-.bool ons_roundlost;
-
-// waypoint sprites
-.entity bot_basewaypoint; // generator waypointsprite
-
-.bool isgenneighbor[17];
-.bool iscpneighbor[17];
-float ons_notification_time[17];
-
-.float ons_overtime_damagedelay;
-
-.vector ons_deathloc;
-
-.entity ons_spawn_by;
-
-// declarations for functions used outside gamemode_onslaught.qc
-void ons_Generator_UpdateSprite(entity e);
-void ons_ControlPoint_UpdateSprite(entity e);
-bool ons_ControlPoint_Attackable(entity cp, int teamnumber);
-
-// CaptureShield: Prevent capturing or destroying control point/generator if it is not available yet
-float ons_captureshield_force; // push force of the shield
-
-// bot player logic
-const int HAVOCBOT_ONS_ROLE_NONE = 0;
-const int HAVOCBOT_ONS_ROLE_DEFENSE = 2;
-const int HAVOCBOT_ONS_ROLE_ASSISTANT = 4;
-const int HAVOCBOT_ONS_ROLE_OFFENSE = 8;
-
-.entity havocbot_ons_target;
-
-.int havocbot_role_flags;
-.float havocbot_attack_time;
-
-void havocbot_role_ons_defense();
-void havocbot_role_ons_offense();
-void havocbot_role_ons_assistant();
-
-void havocbot_ons_reset_role(entity bot);
-void havocbot_goalrating_items(float ratingscale, vector org, float sradius);
-void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius);
-
-// score rule declarations
-const int ST_ONS_CAPS = 1;
-const int SP_ONS_CAPS = 4;
-const int SP_ONS_TAKES = 6;
-
-#endif
-#endif
-
-#ifdef IMPLEMENTATION
-
-#include "../../controlpoint.qh"
-#include "../../generator.qh"
-
-bool g_onslaught;
-
-float autocvar_g_onslaught_debug;
-float autocvar_g_onslaught_teleport_wait;
-bool autocvar_g_onslaught_spawn_at_controlpoints;
-bool autocvar_g_onslaught_spawn_at_generator;
-float autocvar_g_onslaught_cp_proxydecap;
-float autocvar_g_onslaught_cp_proxydecap_distance = 512;
-float autocvar_g_onslaught_cp_proxydecap_dps = 100;
-float autocvar_g_onslaught_spawn_at_controlpoints_chance = 0.5;
-float autocvar_g_onslaught_spawn_at_controlpoints_random;
-float autocvar_g_onslaught_spawn_at_generator_chance;
-float autocvar_g_onslaught_spawn_at_generator_random;
-float autocvar_g_onslaught_cp_buildhealth;
-float autocvar_g_onslaught_cp_buildtime;
-float autocvar_g_onslaught_cp_health;
-float autocvar_g_onslaught_cp_regen;
-float autocvar_g_onslaught_gen_health;
-float autocvar_g_onslaught_shield_force = 100;
-float autocvar_g_onslaught_allow_vehicle_touch;
-float autocvar_g_onslaught_round_timelimit;
-float autocvar_g_onslaught_warmup;
-float autocvar_g_onslaught_teleport_radius;
-float autocvar_g_onslaught_spawn_choose;
-float autocvar_g_onslaught_click_radius;
-
-void FixSize(entity e);
-
-// =======================
-// CaptureShield Functions
-// =======================
-
-bool ons_CaptureShield_Customize()
-{SELFPARAM();
- entity e = WaypointSprite_getviewentity(other);
-
- if(!self.enemy.isshielded && (ons_ControlPoint_Attackable(self.enemy, e.team) > 0 || self.enemy.classname != "onslaught_controlpoint")) { return false; }
- if(SAME_TEAM(self, e)) { return false; }
-
- return true;
-}
-
-void ons_CaptureShield_Touch()
-{SELFPARAM();
- if(!self.enemy.isshielded && (ons_ControlPoint_Attackable(self.enemy, other.team) > 0 || self.enemy.classname != "onslaught_controlpoint")) { return; }
- if(!IS_PLAYER(other)) { return; }
- if(SAME_TEAM(other, self)) { return; }
-
- vector mymid = (self.absmin + self.absmax) * 0.5;
- vector othermid = (other.absmin + other.absmax) * 0.5;
-
- Damage(other, self, self, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(othermid - mymid) * ons_captureshield_force);
-
- if(IS_REAL_CLIENT(other))
- {
- play2(other, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
-
- if(self.enemy.classname == "onslaught_generator")
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_GENERATOR_SHIELDED);
- else
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_CONTROLPOINT_SHIELDED);
- }
-}
-
-void ons_CaptureShield_Reset()
-{SELFPARAM();
- self.colormap = self.enemy.colormap;
- self.team = self.enemy.team;
-}
-
-void ons_CaptureShield_Spawn(entity generator, bool is_generator)
-{
- entity shield = spawn();
-
- shield.enemy = generator;
- shield.team = generator.team;
- shield.colormap = generator.colormap;
- shield.reset = ons_CaptureShield_Reset;
- shield.touch = ons_CaptureShield_Touch;
- shield.customizeentityforclient = ons_CaptureShield_Customize;
- shield.classname = "ons_captureshield";
- shield.effects = EF_ADDITIVE;
- shield.movetype = MOVETYPE_NOCLIP;
- shield.solid = SOLID_TRIGGER;
- shield.avelocity = '7 0 11';
- shield.scale = 1;
- shield.model = ((is_generator) ? "models/onslaught/generator_shield.md3" : "models/onslaught/controlpoint_shield.md3");
-
- precache_model(shield.model);
- setorigin(shield, generator.origin);
- _setmodel(shield, shield.model);
- setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
-}
-
-
-// ==========
-// Junk Pile
-// ==========
-
-void ons_debug(string input)
-{
- switch(autocvar_g_onslaught_debug)
- {
- case 1: LOG_TRACE(input); break;
- case 2: LOG_INFO(input); break;
- }
-}
-
-void setmodel_fixsize(entity e, Model m)
-{
- setmodel(e, m);
- FixSize(e);
-}
-
-void onslaught_updatelinks()
-{
- entity l;
- // first check if the game has ended
- ons_debug("--- updatelinks ---\n");
- // mark generators as being shielded and networked
- for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
- {
- if (l.iscaptured)
- ons_debug(strcat(etos(l), " (generator) belongs to team ", ftos(l.team), "\n"));
- else
- ons_debug(strcat(etos(l), " (generator) is destroyed\n"));
- l.islinked = l.iscaptured;
- l.isshielded = l.iscaptured;
- l.sprite.SendFlags |= 16;
- }
- // mark points as shielded and not networked
- for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
- {
- l.islinked = false;
- l.isshielded = true;
- int i;
- for(i = 0; i < 17; ++i) { l.isgenneighbor[i] = false; l.iscpneighbor[i] = false; }
- ons_debug(strcat(etos(l), " (point) belongs to team ", ftos(l.team), "\n"));
- l.sprite.SendFlags |= 16;
- }
- // flow power outward from the generators through the network
- bool stop = false;
- while (!stop)
- {
- stop = true;
- for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
- {
- // if both points are captured by the same team, and only one of
- // them is powered, mark the other one as powered as well
- if (l.enemy.iscaptured && l.goalentity.iscaptured)
- if (l.enemy.islinked != l.goalentity.islinked)
- if(SAME_TEAM(l.enemy, l.goalentity))
- {
- if (!l.goalentity.islinked)
- {
- stop = false;
- l.goalentity.islinked = true;
- ons_debug(strcat(etos(l), " (link) is marking ", etos(l.goalentity), " (point) because its team matches ", etos(l.enemy), " (point)\n"));
- }
- else if (!l.enemy.islinked)
- {
- stop = false;
- l.enemy.islinked = true;
- ons_debug(strcat(etos(l), " (link) is marking ", etos(l.enemy), " (point) because its team matches ", etos(l.goalentity), " (point)\n"));
- }
- }
- }
- }
- // now that we know which points are powered we can mark their neighbors
- // as unshielded if team differs
- for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
- {
- if (l.goalentity.islinked)
- {
- if(DIFF_TEAM(l.goalentity, l.enemy))
- {
- ons_debug(strcat(etos(l), " (link) is unshielding ", etos(l.enemy), " (point) because its team does not match ", etos(l.goalentity), " (point)\n"));
- l.enemy.isshielded = false;
- }
- if(l.goalentity.classname == "onslaught_generator")
- l.enemy.isgenneighbor[l.goalentity.team] = true;
- else
- l.enemy.iscpneighbor[l.goalentity.team] = true;
- }
- if (l.enemy.islinked)
- {
- if(DIFF_TEAM(l.goalentity, l.enemy))
- {
- ons_debug(strcat(etos(l), " (link) is unshielding ", etos(l.goalentity), " (point) because its team does not match ", etos(l.enemy), " (point)\n"));
- l.goalentity.isshielded = false;
- }
- if(l.enemy.classname == "onslaught_generator")
- l.goalentity.isgenneighbor[l.enemy.team] = true;
- else
- l.goalentity.iscpneighbor[l.enemy.team] = true;
- }
- }
- // now update the generators
- for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
- {
- if (l.isshielded)
- {
- ons_debug(strcat(etos(l), " (generator) is shielded\n"));
- l.takedamage = DAMAGE_NO;
- l.bot_attack = false;
- }
- else
- {
- ons_debug(strcat(etos(l), " (generator) is not shielded\n"));
- l.takedamage = DAMAGE_AIM;
- l.bot_attack = true;
- }
-
- ons_Generator_UpdateSprite(l);
- }
- // now update the takedamage and alpha variables on control point icons
- for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
- {
- if (l.isshielded)
- {
- ons_debug(strcat(etos(l), " (point) is shielded\n"));
- if (l.goalentity)
- {
- l.goalentity.takedamage = DAMAGE_NO;
- l.goalentity.bot_attack = false;
- }
- }
- else
- {
- ons_debug(strcat(etos(l), " (point) is not shielded\n"));
- if (l.goalentity)
- {
- l.goalentity.takedamage = DAMAGE_AIM;
- l.goalentity.bot_attack = true;
- }
- }
- ons_ControlPoint_UpdateSprite(l);
- }
- l = findchain(classname, "ons_captureshield");
- while(l)
- {
- l.team = l.enemy.team;
- l.colormap = l.enemy.colormap;
- l = l.chain;
- }
-}
-
-
-// ===================
-// Main Link Functions
-// ===================
-
-bool ons_Link_Send(entity this, entity to, int sendflags)
-{
- WriteByte(MSG_ENTITY, ENT_CLIENT_RADARLINK);
- WriteByte(MSG_ENTITY, sendflags);
- if(sendflags & 1)
- {
- WriteCoord(MSG_ENTITY, self.goalentity.origin_x);
- WriteCoord(MSG_ENTITY, self.goalentity.origin_y);
- WriteCoord(MSG_ENTITY, self.goalentity.origin_z);
- }
- if(sendflags & 2)
- {
- WriteCoord(MSG_ENTITY, self.enemy.origin_x);
- WriteCoord(MSG_ENTITY, self.enemy.origin_y);
- WriteCoord(MSG_ENTITY, self.enemy.origin_z);
- }
- if(sendflags & 4)
- {
- WriteByte(MSG_ENTITY, self.clientcolors); // which is goalentity's color + enemy's color * 16
- }
- return true;
-}
-
-void ons_Link_CheckUpdate()
-{SELFPARAM();
- // TODO check if the two sides have moved (currently they won't move anyway)
- float cc = 0, cc1 = 0, cc2 = 0;
-
- if(self.goalentity.islinked || self.goalentity.iscaptured) { cc1 = (self.goalentity.team - 1) * 0x01; }
- if(self.enemy.islinked || self.enemy.iscaptured) { cc2 = (self.enemy.team - 1) * 0x10; }
-
- cc = cc1 + cc2;
-
- if(cc != self.clientcolors)
- {
- self.clientcolors = cc;
- self.SendFlags |= 4;
- }
-
- self.nextthink = time;
-}
-
-void ons_DelayedLinkSetup()
-{SELFPARAM();
- self.goalentity = find(world, targetname, self.target);
- self.enemy = find(world, targetname, self.target2);
- if(!self.goalentity) { objerror("can not find target\n"); }
- if(!self.enemy) { objerror("can not find target2\n"); }
-
- ons_debug(strcat(etos(self.goalentity), " linked with ", etos(self.enemy), "\n"));
- self.SendFlags |= 3;
- self.think = ons_Link_CheckUpdate;
- self.nextthink = time;
-}
-
-
-// =============================
-// Main Control Point Functions
-// =============================
-
-int ons_ControlPoint_CanBeLinked(entity cp, int teamnumber)
-{
- if(cp.isgenneighbor[teamnumber]) { return 2; }
- if(cp.iscpneighbor[teamnumber]) { return 1; }
-
- return 0;
-}
-
-int ons_ControlPoint_Attackable(entity cp, int teamnumber)
- // -2: SAME TEAM, attackable by enemy!
- // -1: SAME TEAM!
- // 0: off limits
- // 1: attack it
- // 2: touch it
- // 3: attack it (HIGH PRIO)
- // 4: touch it (HIGH PRIO)
-{
- int a;
-
- if(cp.isshielded)
- {
- return 0;
- }
- else if(cp.goalentity)
- {
- // if there's already an icon built, nothing happens
- if(cp.team == teamnumber)
- {
- a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
- if(a) // attackable by enemy?
- return -2; // EMERGENCY!
- return -1;
- }
- // we know it can be linked, so no need to check
- // but...
- a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
- if(a == 2) // near our generator?
- return 3; // EMERGENCY!
- return 1;
- }
- else
- {
- // free point
- if(ons_ControlPoint_CanBeLinked(cp, teamnumber))
- {
- a = ons_ControlPoint_CanBeLinked(cp, teamnumber); // why was this here NUM_TEAM_1 + NUM_TEAM_2 - t
- if(a == 2)
- return 4; // GET THIS ONE NOW!
- else
- return 2; // TOUCH ME
- }
- }
- return 0;
-}
-
-void ons_ControlPoint_Icon_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
- if(damage <= 0) { return; }
-
- if (self.owner.isshielded)
- {
- // this is protected by a shield, so ignore the damage
- if (time > self.pain_finished)
- if (IS_PLAYER(attacker))
- {
- play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
- self.pain_finished = time + 1;
- attacker.typehitsound += 1; // play both sounds (shield is way too quiet)
- }
-
- return;
- }
-
- if(IS_PLAYER(attacker))
- if(time - ons_notification_time[self.team] > 10)
- {
- play2team(self.team, SND(ONS_CONTROLPOINT_UNDERATTACK));
- ons_notification_time[self.team] = time;
- }
-
- self.health = self.health - damage;
- if(self.owner.iscaptured)
- WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
- else
- WaypointSprite_UpdateBuildFinished(self.owner.sprite, time + (self.max_health - self.health) / (self.count / ONS_CP_THINKRATE));
- self.pain_finished = time + 1;
- // particles on every hit
- pointparticles(particleeffectnum(EFFECT_SPARKS), hitloc, force*-1, 1);
- //sound on every hit
- if (random() < 0.5)
- sound(self, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE+0.3, ATTEN_NORM);
- else
- sound(self, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE+0.3, ATTEN_NORM);
-
- if (self.health < 0)
- {
- sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), self.origin, '0 0 0', 1);
- Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_CPDESTROYED_), self.owner.message, attacker.netname);
-
- PlayerScore_Add(attacker, SP_ONS_TAKES, 1);
- PlayerScore_Add(attacker, SP_SCORE, 10);
-
- self.owner.goalentity = world;
- self.owner.islinked = false;
- self.owner.iscaptured = false;
- self.owner.team = 0;
- self.owner.colormap = 1024;
-
- WaypointSprite_UpdateMaxHealth(self.owner.sprite, 0);
-
- onslaught_updatelinks();
-
- // Use targets now (somebody make sure this is in the right place..)
- setself(self.owner);
- activator = self;
- SUB_UseTargets ();
- setself(this);
-
- self.owner.waslinked = self.owner.islinked;
- if(self.owner.model != "models/onslaught/controlpoint_pad.md3")
- setmodel_fixsize(self.owner, MDL_ONS_CP_PAD1);
- //setsize(self, '-32 -32 0', '32 32 8');
-
- remove(self);
- }
-
- self.SendFlags |= CPSF_STATUS;
-}
-
-void ons_ControlPoint_Icon_Think()
-{SELFPARAM();
- self.nextthink = time + ONS_CP_THINKRATE;
-
- if(autocvar_g_onslaught_cp_proxydecap)
- {
- int _enemy_count = 0;
- int _friendly_count = 0;
- float _dist;
- entity _player;
-
- FOR_EACH_PLAYER(_player)
- {
- if(!_player.deadflag)
- {
- _dist = vlen(_player.origin - self.origin);
- if(_dist < autocvar_g_onslaught_cp_proxydecap_distance)
- {
- if(SAME_TEAM(_player, self))
- ++_friendly_count;
- else
- ++_enemy_count;
- }
- }
- }
-
- _friendly_count = _friendly_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
- _enemy_count = _enemy_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
-
- self.health = bound(0, self.health + (_friendly_count - _enemy_count), self.max_health);
- self.SendFlags |= CPSF_STATUS;
- if(self.health <= 0)
- {
- ons_ControlPoint_Icon_Damage(self, self, 1, 0, self.origin, '0 0 0');
- return;
- }
- }
-
- if (time > self.pain_finished + 5)
- {
- if(self.health < self.max_health)
- {
- self.health = self.health + self.count;
- if (self.health >= self.max_health)
- self.health = self.max_health;
- WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
- }
- }
-
- if(self.owner.islinked != self.owner.waslinked)
- {
- // unteam the spawnpoint if needed
- int t = self.owner.team;
- if(!self.owner.islinked)
- self.owner.team = 0;
-
- setself(self.owner);
- activator = self;
- SUB_UseTargets ();
- setself(this);
-
- self.owner.team = t;
-
- self.owner.waslinked = self.owner.islinked;
- }
-
- // damaged fx
- if(random() < 0.6 - self.health / self.max_health)
- {
- Send_Effect(EFFECT_ELECTRIC_SPARKS, self.origin + randompos('-10 -10 -20', '10 10 20'), '0 0 0', 1);
-
- if(random() > 0.8)
- sound(self, CH_PAIN, SND_ONS_SPARK1, VOL_BASE, ATTEN_NORM);
- else if (random() > 0.5)
- sound(self, CH_PAIN, SND_ONS_SPARK2, VOL_BASE, ATTEN_NORM);
- }
-}
-
-void ons_ControlPoint_Icon_BuildThink()
-{SELFPARAM();
- int a;
-
- self.nextthink = time + ONS_CP_THINKRATE;
-
- // only do this if there is power
- a = ons_ControlPoint_CanBeLinked(self.owner, self.owner.team);
- if(!a)
- return;
-
- self.health = self.health + self.count;
-
- self.SendFlags |= CPSF_STATUS;
-
- if (self.health >= self.max_health)
- {
- self.health = self.max_health;
- self.count = autocvar_g_onslaught_cp_regen * ONS_CP_THINKRATE; // slow repair rate from now on
- self.think = ons_ControlPoint_Icon_Think;
- sound(self, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILT, VOL_BASE, ATTEN_NORM);
- self.owner.iscaptured = true;
- self.solid = SOLID_BBOX;
-
- Send_Effect(EFFECT_CAP(self.owner.team), self.owner.origin, '0 0 0', 1);
-
- WaypointSprite_UpdateMaxHealth(self.owner.sprite, self.max_health);
- WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
-
- if(IS_PLAYER(self.owner.ons_toucher))
- {
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ONSLAUGHT_CAPTURE, self.owner.ons_toucher.netname, self.owner.message);
- Send_Notification(NOTIF_ALL_EXCEPT, self.owner.ons_toucher, MSG_CENTER, APP_TEAM_ENT_4(self.owner.ons_toucher, CENTER_ONS_CAPTURE_), self.owner.message);
- Send_Notification(NOTIF_ONE, self.owner.ons_toucher, MSG_CENTER, CENTER_ONS_CAPTURE, self.owner.message);
- PlayerScore_Add(self.owner.ons_toucher, SP_ONS_CAPS, 1);
- PlayerTeamScore_AddScore(self.owner.ons_toucher, 10);
- }
-
- self.owner.ons_toucher = world;
-
- onslaught_updatelinks();
-
- // Use targets now (somebody make sure this is in the right place..)
- setself(self.owner);
- activator = self;
- SUB_UseTargets ();
- setself(this);
-
- self.SendFlags |= CPSF_SETUP;
- }
- if(self.owner.model != MDL_ONS_CP_PAD2.model_str())
- setmodel_fixsize(self.owner, MDL_ONS_CP_PAD2);
-
- if(random() < 0.9 - self.health / self.max_health)
- Send_Effect(EFFECT_RAGE, self.origin + 10 * randomvec(), '0 0 -1', 1);
-}
-
-void onslaught_controlpoint_icon_link(entity e, void() spawnproc);
-
-void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
-{
- entity e = spawn();
-
- setsize(e, CPICON_MIN, CPICON_MAX);
- setorigin(e, cp.origin + CPICON_OFFSET);
-
- e.classname = "onslaught_controlpoint_icon";
- e.owner = cp;
- e.max_health = autocvar_g_onslaught_cp_health;
- e.health = autocvar_g_onslaught_cp_buildhealth;
- e.solid = SOLID_NOT;
- e.takedamage = DAMAGE_AIM;
- e.bot_attack = true;
- e.event_damage = ons_ControlPoint_Icon_Damage;
- e.team = player.team;
- e.colormap = 1024 + (e.team - 1) * 17;
- e.count = (e.max_health - e.health) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
-
- sound(e, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILD, VOL_BASE, ATTEN_NORM);
-
- cp.goalentity = e;
- cp.team = e.team;
- cp.colormap = e.colormap;
-
- Send_Effect(EFFECT_FLAG_TOUCH(player.team), e.origin, '0 0 0', 1);
-
- WaypointSprite_UpdateBuildFinished(cp.sprite, time + (e.max_health - e.health) / (e.count / ONS_CP_THINKRATE));
- WaypointSprite_UpdateRule(cp.sprite,cp.team,SPRITERULE_TEAMPLAY);
- cp.sprite.SendFlags |= 16;
-
- onslaught_controlpoint_icon_link(e, ons_ControlPoint_Icon_BuildThink);
-}
-
-entity ons_ControlPoint_Waypoint(entity e)
-{
- if(e.team)
- {
- int a = ons_ControlPoint_Attackable(e, e.team);
-
- if(a == -2) { return WP_OnsCPDefend; } // defend now
- if(a == -1 || a == 1 || a == 2) { return WP_OnsCP; } // touch
- if(a == 3 || a == 4) { return WP_OnsCPAttack; } // attack
- }
- else
- return WP_OnsCP;
-
- return WP_Null;
-}
-
-void ons_ControlPoint_UpdateSprite(entity e)
-{
- entity s1 = ons_ControlPoint_Waypoint(e);
- WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
-
- bool sh;
- sh = !(ons_ControlPoint_CanBeLinked(e, NUM_TEAM_1) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_2) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_3) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_4));
-
- if(e.lastteam != e.team + 2 || e.lastshielded != sh || e.iscaptured != e.lastcaptured)
- {
- if(e.iscaptured) // don't mess up build bars!
- {
- if(sh)
- {
- WaypointSprite_UpdateMaxHealth(e.sprite, 0);
- }
- else
- {
- WaypointSprite_UpdateMaxHealth(e.sprite, e.goalentity.max_health);
- WaypointSprite_UpdateHealth(e.sprite, e.goalentity.health);
- }
- }
- if(e.lastshielded)
- {
- if(e.team)
- WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, 0.5 * colormapPaletteColor(e.team - 1, false));
- else
- WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.5 0.5 0.5');
- }
- else
- {
- if(e.team)
- WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, colormapPaletteColor(e.team - 1, false));
- else
- WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.75 0.75 0.75');
- }
- WaypointSprite_Ping(e.sprite);
-
- e.lastteam = e.team + 2;
- e.lastshielded = sh;
- e.lastcaptured = e.iscaptured;
- }
-}
-
-void ons_ControlPoint_Touch()
-{SELFPARAM();
- entity toucher = other;
- int attackable;
-
- if(IS_VEHICLE(toucher) && toucher.owner)
- if(autocvar_g_onslaught_allow_vehicle_touch)
- toucher = toucher.owner;
- else
- return;
-
- if(!IS_PLAYER(toucher)) { return; }
- if(toucher.frozen) { return; }
- if(toucher.deadflag != DEAD_NO) { return; }
-
- if ( SAME_TEAM(self,toucher) )
- if ( self.iscaptured )
- {
- if(time <= toucher.teleport_antispam)
- Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT_ANTISPAM, rint(toucher.teleport_antispam - time));
- else
- Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT);
- }
-
- attackable = ons_ControlPoint_Attackable(self, toucher.team);
- if(attackable != 2 && attackable != 4)
- return;
- // we've verified that this player has a legitimate claim to this point,
- // so start building the captured point icon (which only captures this
- // point if it successfully builds without being destroyed first)
- ons_ControlPoint_Icon_Spawn(self, toucher);
-
- self.ons_toucher = toucher;
-
- onslaught_updatelinks();
-}
-
-void ons_ControlPoint_Think()
-{SELFPARAM();
- self.nextthink = time + ONS_CP_THINKRATE;
- CSQCMODEL_AUTOUPDATE(self);
-}
-
-void ons_ControlPoint_Reset()
-{SELFPARAM();
- if(self.goalentity)
- remove(self.goalentity);
-
- self.goalentity = world;
- self.team = 0;
- self.colormap = 1024;
- self.iscaptured = false;
- self.islinked = false;
- self.isshielded = true;
- self.think = ons_ControlPoint_Think;
- self.ons_toucher = world;
- self.nextthink = time + ONS_CP_THINKRATE;
- setmodel_fixsize(self, MDL_ONS_CP_PAD1);
-
- WaypointSprite_UpdateMaxHealth(self.sprite, 0);
- WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
-
- onslaught_updatelinks();
-
- activator = self;
- SUB_UseTargets(); // to reset the structures, playerspawns etc.
-
- CSQCMODEL_AUTOUPDATE(self);
-}
-
-void ons_DelayedControlPoint_Setup(void)
-{SELFPARAM();
- onslaught_updatelinks();
-
- // captureshield setup
- ons_CaptureShield_Spawn(self, false);
-
- CSQCMODEL_AUTOINIT(self);
-}
-
-void ons_ControlPoint_Setup(entity cp)
-{SELFPARAM();
- // declarations
- setself(cp); // for later usage with droptofloor()
-
- // main setup
- cp.ons_worldcpnext = ons_worldcplist; // link control point into ons_worldcplist
- ons_worldcplist = cp;
-
- cp.netname = "Control point";
- cp.team = 0;
- cp.solid = SOLID_BBOX;
- cp.movetype = MOVETYPE_NONE;
- cp.touch = ons_ControlPoint_Touch;
- cp.think = ons_ControlPoint_Think;
- cp.nextthink = time + ONS_CP_THINKRATE;
- cp.reset = ons_ControlPoint_Reset;
- cp.colormap = 1024;
- cp.iscaptured = false;
- cp.islinked = false;
- cp.isshielded = true;
-
- if(cp.message == "") { cp.message = "a"; }
-
- // appearence
- setmodel_fixsize(cp, MDL_ONS_CP_PAD1);
-
- // control point placement
- if((cp.spawnflags & 1) || cp.noalign) // don't drop to floor, just stay at fixed location
- {
- cp.noalign = true;
- cp.movetype = MOVETYPE_NONE;
- }
- else // drop to floor, automatically find a platform and set that as spawn origin
- {
- setorigin(cp, cp.origin + '0 0 20');
- cp.noalign = false;
- setself(cp);
- droptofloor();
- cp.movetype = MOVETYPE_TOSS;
- }
-
- // waypointsprites
- WaypointSprite_SpawnFixed(WP_Null, self.origin + CPGEN_WAYPOINT_OFFSET, self, sprite, RADARICON_NONE);
- WaypointSprite_UpdateRule(self.sprite, self.team, SPRITERULE_TEAMPLAY);
-
- InitializeEntity(cp, ons_DelayedControlPoint_Setup, INITPRIO_SETLOCATION);
-}
-
-
-// =========================
-// Main Generator Functions
-// =========================
-
-entity ons_Generator_Waypoint(entity e)
-{
- if (e.isshielded)
- return WP_OnsGenShielded;
- return WP_OnsGen;
-}
-
-void ons_Generator_UpdateSprite(entity e)
-{
- entity s1 = ons_Generator_Waypoint(e);
- WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
-
- if(e.lastteam != e.team + 2 || e.lastshielded != e.isshielded)
- {
- e.lastteam = e.team + 2;
- e.lastshielded = e.isshielded;
- if(e.lastshielded)
- {
- if(e.team)
- WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, 0.5 * colormapPaletteColor(e.team - 1, false));
- else
- WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.5 0.5 0.5');
- }
- else
- {
- if(e.team)
- WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, colormapPaletteColor(e.team - 1, false));
- else
- WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.75 0.75 0.75');
- }
- WaypointSprite_Ping(e.sprite);
- }
-}
-
-void ons_GeneratorDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
- if(damage <= 0) { return; }
- if(warmup_stage || gameover) { return; }
- if(!round_handler_IsRoundStarted()) { return; }
-
- if (attacker != self)
- {
- if (self.isshielded)
- {
- // this is protected by a shield, so ignore the damage
- if (time > self.pain_finished)
- if (IS_PLAYER(attacker))
- {
- play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
- attacker.typehitsound += 1;
- self.pain_finished = time + 1;
- }
- return;
- }
- if (time > self.pain_finished)
- {
- self.pain_finished = time + 10;
- entity head;
- FOR_EACH_REALPLAYER(head) if(SAME_TEAM(head, self)) { Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_GENERATOR_UNDERATTACK); }
- play2team(self.team, SND(ONS_GENERATOR_UNDERATTACK));
- }
- }
- self.health = self.health - damage;
- WaypointSprite_UpdateHealth(self.sprite, self.health);
- // choose an animation frame based on health
- self.frame = 10 * bound(0, (1 - self.health / self.max_health), 1);
- // see if the generator is still functional, or dying
- if (self.health > 0)
- {
- self.lasthealth = self.health;
- }
- else
- {
- if (attacker == self)
- Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_GENDESTROYED_OVERTIME_));
- else
- {
- Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_GENDESTROYED_));
- PlayerScore_Add(attacker, SP_SCORE, 100);
- }
- self.iscaptured = false;
- self.islinked = false;
- self.isshielded = false;
- self.takedamage = DAMAGE_NO; // can't be hurt anymore
- self.event_damage = func_null; // won't do anything if hurt
- self.count = 0; // reset counter
- self.think = func_null;
- self.nextthink = 0;
- //self.think(); // do the first explosion now
-
- WaypointSprite_UpdateMaxHealth(self.sprite, 0);
- WaypointSprite_Ping(self.sprite);
- //WaypointSprite_Kill(self.sprite); // can't do this yet, code too poor
-
- onslaught_updatelinks();
- }
-
- // Throw some flaming gibs on damage, more damage = more chance for gib
- if(random() < damage/220)
- {
- sound(self, CH_TRIGGER, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
- }
- else
- {
- // particles on every hit
- Send_Effect(EFFECT_SPARKS, hitloc, force * -1, 1);
-
- //sound on every hit
- if (random() < 0.5)
- sound(self, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE, ATTEN_NORM);
- else
- sound(self, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE, ATTEN_NORM);
- }
-
- self.SendFlags |= GSF_STATUS;
-}
-
-void ons_GeneratorThink()
-{SELFPARAM();
- entity e;
- self.nextthink = time + GEN_THINKRATE;
- if (!gameover)
- {
- if(!self.isshielded && self.wait < time)
- {
- self.wait = time + 5;
- FOR_EACH_REALPLAYER(e)
- {
- if(SAME_TEAM(e, self))
- {
- Send_Notification(NOTIF_ONE, e, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
- soundto(MSG_ONE, e, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE); // FIXME: unique sound?
- }
- else
- Send_Notification(NOTIF_ONE, e, MSG_CENTER, APP_TEAM_NUM_4(self.team, CENTER_ONS_NOTSHIELDED_));
- }
- }
- }
-}
-
-void ons_GeneratorReset()
-{SELFPARAM();
- self.team = self.team_saved;
- self.lasthealth = self.max_health = self.health = autocvar_g_onslaught_gen_health;
- self.takedamage = DAMAGE_AIM;
- self.bot_attack = true;
- self.iscaptured = true;
- self.islinked = true;
- self.isshielded = true;
- self.event_damage = ons_GeneratorDamage;
- self.think = ons_GeneratorThink;
- self.nextthink = time + GEN_THINKRATE;
-
- Net_LinkEntity(self, false, 0, generator_send);
-
- self.SendFlags = GSF_SETUP; // just incase
- self.SendFlags |= GSF_STATUS;
-
- WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
- WaypointSprite_UpdateHealth(self.sprite, self.health);
- WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
-
- onslaught_updatelinks();
-}
-
-void ons_DelayedGeneratorSetup()
-{SELFPARAM();
- // bot waypoints
- waypoint_spawnforitem_force(self, self.origin);
- self.nearestwaypointtimeout = 0; // activate waypointing again
- self.bot_basewaypoint = self.nearestwaypoint;
-
- // captureshield setup
- ons_CaptureShield_Spawn(self, true);
-
- onslaught_updatelinks();
-
- Net_LinkEntity(self, false, 0, generator_send);
-}
-
-
-void onslaught_generator_touch()
-{SELFPARAM();
- if ( IS_PLAYER(other) )
- if ( SAME_TEAM(self,other) )
- if ( self.iscaptured )
- {
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_TELEPORT);
- }
-}
-
-void ons_GeneratorSetup(entity gen) // called when spawning a generator entity on the map as a spawnfunc
-{SELFPARAM();
- // declarations
- int teamnumber = gen.team;
- setself(gen); // for later usage with droptofloor()
-
- // main setup
- gen.ons_worldgeneratornext = ons_worldgeneratorlist; // link generator into ons_worldgeneratorlist
- ons_worldgeneratorlist = gen;
-
- gen.netname = sprintf("%s generator", Team_ColoredFullName(teamnumber));
- gen.classname = "onslaught_generator";
- gen.solid = SOLID_BBOX;
- gen.team_saved = teamnumber;
- gen.movetype = MOVETYPE_NONE;
- gen.lasthealth = gen.max_health = gen.health = autocvar_g_onslaught_gen_health;
- gen.takedamage = DAMAGE_AIM;
- gen.bot_attack = true;
- gen.event_damage = ons_GeneratorDamage;
- gen.reset = ons_GeneratorReset;
- gen.think = ons_GeneratorThink;
- gen.nextthink = time + GEN_THINKRATE;
- gen.iscaptured = true;
- gen.islinked = true;
- gen.isshielded = true;
- gen.touch = onslaught_generator_touch;
-
- // appearence
- // model handled by CSQC
- setsize(gen, GENERATOR_MIN, GENERATOR_MAX);
- setorigin(gen, (gen.origin + CPGEN_SPAWN_OFFSET));
- gen.colormap = 1024 + (teamnumber - 1) * 17;
-
- // generator placement
- setself(gen);
- droptofloor();
-
- // waypointsprites
- WaypointSprite_SpawnFixed(WP_Null, self.origin + CPGEN_WAYPOINT_OFFSET, self, sprite, RADARICON_NONE);
- WaypointSprite_UpdateRule(self.sprite, self.team, SPRITERULE_TEAMPLAY);
- WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
- WaypointSprite_UpdateHealth(self.sprite, self.health);
-
- InitializeEntity(gen, ons_DelayedGeneratorSetup, INITPRIO_SETLOCATION);
-}
-
-
-// ===============
-// Round Handler
-// ===============
-
-int total_generators;
-void Onslaught_count_generators()
-{
- entity e;
- total_generators = redowned = blueowned = yellowowned = pinkowned = 0;
- for(e = ons_worldgeneratorlist; e; e = e.ons_worldgeneratornext)
- {
- ++total_generators;
- redowned += (e.team == NUM_TEAM_1 && e.health > 0);
- blueowned += (e.team == NUM_TEAM_2 && e.health > 0);
- yellowowned += (e.team == NUM_TEAM_3 && e.health > 0);
- pinkowned += (e.team == NUM_TEAM_4 && e.health > 0);
- }
-}
-
-int Onslaught_GetWinnerTeam()
-{
- int winner_team = 0;
- if(redowned > 0)
- winner_team = NUM_TEAM_1;
- if(blueowned > 0)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_2;
- }
- if(yellowowned > 0)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_3;
- }
- if(pinkowned > 0)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_4;
- }
- if(winner_team)
- return winner_team;
- return -1; // no generators left?
-}
-
-#define ONS_OWNED_GENERATORS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
-#define ONS_OWNED_GENERATORS_OK() (ONS_OWNED_GENERATORS() > 1)
-bool Onslaught_CheckWinner()
-{
- entity e;
-
- if ((autocvar_timelimit && time > game_starttime + autocvar_timelimit * 60) || (round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0))
- {
- ons_stalemate = true;
-
- if (!wpforenemy_announced)
- {
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT);
- sound(world, CH_INFO, SND_ONS_GENERATOR_DECAY, VOL_BASE, ATTEN_NONE);
-
- wpforenemy_announced = true;
- }
-
- entity tmp_entity; // temporary entity
- float d;
- for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext) if(time >= tmp_entity.ons_overtime_damagedelay)
- {
- // tmp_entity.max_health / 300 gives 5 minutes of overtime.
- // control points reduce the overtime duration.
- d = 1;
- for(e = ons_worldcplist; e; e = e.ons_worldcpnext)
- {
- if(DIFF_TEAM(e, tmp_entity))
- if(e.islinked)
- d = d + 1;
- }
-
- if(autocvar_g_campaign && autocvar__campaign_testrun)
- d = d * tmp_entity.max_health;
- else
- d = d * tmp_entity.max_health / max(30, 60 * autocvar_timelimit_suddendeath);
-
- Damage(tmp_entity, tmp_entity, tmp_entity, d, DEATH_HURTTRIGGER.m_id, tmp_entity.origin, '0 0 0');
-
- tmp_entity.sprite.SendFlags |= 16;
-
- tmp_entity.ons_overtime_damagedelay = time + 1;
- }
- }
- else { wpforenemy_announced = false; ons_stalemate = false; }
-
- Onslaught_count_generators();
-
- if(ONS_OWNED_GENERATORS_OK())
- return 0;
-
- int winner_team = Onslaught_GetWinnerTeam();
-
- if(winner_team > 0)
- {
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner_team, CENTER_ROUND_TEAM_WIN_));
- Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner_team, INFO_ROUND_TEAM_WIN_));
- TeamScore_AddToTeam(winner_team, ST_ONS_CAPS, +1);
- }
- else if(winner_team == -1)
- {
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
- }
-
- ons_stalemate = false;
-
- play2all(SND(CTF_CAPTURE(winner_team)));
-
- round_handler_Init(7, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
-
- FOR_EACH_PLAYER(e)
- {
- e.ons_roundlost = true;
- e.player_blocked = true;
-
- nades_Clear(e);
- }
-
- return 1;
-}
-
-bool Onslaught_CheckPlayers()
-{
- return 1;
-}
-
-void Onslaught_RoundStart()
-{
- entity tmp_entity;
- FOR_EACH_PLAYER(tmp_entity) { tmp_entity.player_blocked = false; }
-
- for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
- tmp_entity.sprite.SendFlags |= 16;
-
- for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
- tmp_entity.sprite.SendFlags |= 16;
-}
-
-
-// ================
-// Bot player logic
-// ================
-
-// NOTE: LEGACY CODE, needs to be re-written!
-
-void havocbot_goalrating_ons_offenseitems(float ratingscale, vector org, float sradius)
-{SELFPARAM();
- entity head;
- float t, c;
- int i;
- bool needarmor = false, needweapons = false;
-
- // Needs armor/health?
- if(self.health<100)
- needarmor = true;
-
- // Needs weapons?
- c = 0;
- for(i = WEP_FIRST; i <= WEP_LAST ; ++i)
- {
- // Find weapon
- if(self.weapons & WepSet_FromWeapon(i))
- if(++c>=4)
- break;
- }
-
- if(c<4)
- needweapons = true;
-
- if(!needweapons && !needarmor)
- return;
-
- ons_debug(strcat(self.netname, " needs weapons ", ftos(needweapons) , "\n"));
- ons_debug(strcat(self.netname, " needs armor ", ftos(needarmor) , "\n"));
-
- // See what is around
- head = findchainfloat(bot_pickup, true);
- while (head)
- {
- // gather health and armor only
- if (head.solid)
- if ( ((head.health || head.armorvalue) && needarmor) || (head.weapons && needweapons ) )
- if (vlen(head.origin - org) < sradius)
- {
- t = head.bot_pickupevalfunc(self, head);
- if (t > 0)
- navigation_routerating(head, t * ratingscale, 500);
- }
- head = head.chain;
- }
-}
-
-void havocbot_role_ons_setrole(entity bot, int role)
-{
- ons_debug(strcat(bot.netname," switched to "));
- switch(role)
- {
- case HAVOCBOT_ONS_ROLE_DEFENSE:
- ons_debug("defense");
- bot.havocbot_role = havocbot_role_ons_defense;
- bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
- bot.havocbot_role_timeout = 0;
- break;
- case HAVOCBOT_ONS_ROLE_ASSISTANT:
- ons_debug("assistant");
- bot.havocbot_role = havocbot_role_ons_assistant;
- bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
- bot.havocbot_role_timeout = 0;
- break;
- case HAVOCBOT_ONS_ROLE_OFFENSE:
- ons_debug("offense");
- bot.havocbot_role = havocbot_role_ons_offense;
- bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
- bot.havocbot_role_timeout = 0;
- break;
- }
- ons_debug("\n");
-}
-
-int havocbot_ons_teamcount(entity bot, int role)
-{SELFPARAM();
- int c = 0;
- entity head;
-
- FOR_EACH_PLAYER(head)
- if(SAME_TEAM(head, self))
- if(head.havocbot_role_flags & role)
- ++c;
-
- return c;
-}
-
-void havocbot_goalrating_ons_controlpoints_attack(float ratingscale)
-{SELFPARAM();
- entity cp, cp1, cp2, best, pl, wp;
- float radius, bestvalue;
- int c;
- bool found;
-
- // Filter control points
- for(cp2 = ons_worldcplist; cp2; cp2 = cp2.ons_worldcpnext)
- {
- cp2.wpcost = c = 0;
- cp2.wpconsidered = false;
-
- if(cp2.isshielded)
- continue;
-
- // Ignore owned controlpoints
- if(!(cp2.isgenneighbor[self.team] || cp2.iscpneighbor[self.team]))
- continue;
-
- // Count team mates interested in this control point
- // (easier and cleaner than keeping counters per cp and teams)
- FOR_EACH_PLAYER(pl)
- if(SAME_TEAM(pl, self))
- if(pl.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
- if(pl.havocbot_ons_target==cp2)
- ++c;
-
- // NOTE: probably decrease the cost of attackable control points
- cp2.wpcost = c;
- cp2.wpconsidered = true;
- }
-
- // We'll consider only the best case
- bestvalue = 99999999999;
- cp = world;
- for(cp1 = ons_worldcplist; cp1; cp1 = cp1.ons_worldcpnext)
- {
- if (!cp1.wpconsidered)
- continue;
-
- if(cp1.wpcost<bestvalue)
- {
- bestvalue = cp1.wpcost;
- cp = cp1;
- self.havocbot_ons_target = cp1;
- }
- }
-
- if (!cp)
- return;
-
- ons_debug(strcat(self.netname, " chose cp ranked ", ftos(bestvalue), "\n"));
-
- if(cp.goalentity)
- {
- // Should be attacked
- // Rate waypoints near it
- found = false;
- best = world;
- bestvalue = 99999999999;
- for(radius=0; radius<1000 && !found; radius+=500)
- {
- for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
- {
- if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
- if(wp.classname=="waypoint")
- if(checkpvs(wp.origin,cp))
- {
- found = true;
- if(wp.cnt<bestvalue)
- {
- best = wp;
- bestvalue = wp.cnt;
- }
- }
- }
- }
-
- if(best)
- {
- navigation_routerating(best, ratingscale, 10000);
- best.cnt += 1;
-
- self.havocbot_attack_time = 0;
- if(checkpvs(self.view_ofs,cp))
- if(checkpvs(self.view_ofs,best))
- self.havocbot_attack_time = time + 2;
- }
- else
- {
- navigation_routerating(cp, ratingscale, 10000);
- }
- ons_debug(strcat(self.netname, " found an attackable controlpoint at ", vtos(cp.origin) ,"\n"));
- }
- else
- {
- // Should be touched
- ons_debug(strcat(self.netname, " found a touchable controlpoint at ", vtos(cp.origin) ,"\n"));
- found = false;
-
- // Look for auto generated waypoint
- if (!bot_waypoints_for_items)
- for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
- {
- if(wp.classname=="waypoint")
- {
- navigation_routerating(wp, ratingscale, 10000);
- found = true;
- }
- }
-
- // Nothing found, rate the controlpoint itself
- if (!found)
- navigation_routerating(cp, ratingscale, 10000);
- }
-}
-
-bool havocbot_goalrating_ons_generator_attack(float ratingscale)
-{SELFPARAM();
- entity g, wp, bestwp;
- bool found;
- int best;
-
- for(g = ons_worldgeneratorlist; g; g = g.ons_worldgeneratornext)
- {
- if(SAME_TEAM(g, self) || g.isshielded)
- continue;
-
- // Should be attacked
- // Rate waypoints near it
- found = false;
- bestwp = world;
- best = 99999999999;
-
- for(wp=findradius(g.origin,400); wp; wp=wp.chain)
- {
- if(wp.classname=="waypoint")
- if(checkpvs(wp.origin,g))
- {
- found = true;
- if(wp.cnt<best)
- {
- bestwp = wp;
- best = wp.cnt;
- }
- }
- }
-
- if(bestwp)
- {
- ons_debug("waypoints found around generator\n");
- navigation_routerating(bestwp, ratingscale, 10000);
- bestwp.cnt += 1;
-
- self.havocbot_attack_time = 0;
- if(checkpvs(self.view_ofs,g))
- if(checkpvs(self.view_ofs,bestwp))
- self.havocbot_attack_time = time + 5;
-
- return true;
- }
- else
- {
- ons_debug("generator found without waypoints around\n");
- // if there aren't waypoints near the generator go straight to it
- navigation_routerating(g, ratingscale, 10000);
- self.havocbot_attack_time = 0;
- return true;
- }
- }
- return false;
-}
-
-void havocbot_role_ons_offense()
-{SELFPARAM();
- if(self.deadflag != DEAD_NO)
- {
- self.havocbot_attack_time = 0;
- havocbot_ons_reset_role(self);
- return;
- }
-
- // Set the role timeout if necessary
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + 120;
-
- if (time > self.havocbot_role_timeout)
- {
- havocbot_ons_reset_role(self);
- return;
- }
-
- if(self.havocbot_attack_time>time)
- return;
-
- if (self.bot_strategytime < time)
- {
- navigation_goalrating_start();
- havocbot_goalrating_enemyplayers(20000, self.origin, 650);
- if(!havocbot_goalrating_ons_generator_attack(20000))
- havocbot_goalrating_ons_controlpoints_attack(20000);
- havocbot_goalrating_ons_offenseitems(10000, self.origin, 10000);
- navigation_goalrating_end();
-
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- }
-}
-
-void havocbot_role_ons_assistant()
-{SELFPARAM();
- havocbot_ons_reset_role(self);
-}
-
-void havocbot_role_ons_defense()
-{SELFPARAM();
- havocbot_ons_reset_role(self);
-}
-
-void havocbot_ons_reset_role(entity bot)
-{SELFPARAM();
- entity head;
- int c = 0;
-
- if(self.deadflag != DEAD_NO)
- return;
-
- bot.havocbot_ons_target = world;
-
- // TODO: Defend control points or generator if necessary
-
- // if there is only me on the team switch to offense
- c = 0;
- FOR_EACH_PLAYER(head)
- if(SAME_TEAM(head, self))
- ++c;
-
- if(c==1)
- {
- havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
- return;
- }
-
- havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
-}
-
-
-/*
- * Find control point or generator owned by the same team self which is nearest to pos
- * if max_dist is positive, only control points within this range will be considered
- */
-entity ons_Nearest_ControlPoint(vector pos, float max_dist)
-{SELFPARAM();
- entity tmp_entity, closest_target = world;
- tmp_entity = findchain(classname, "onslaught_controlpoint");
- while(tmp_entity)
- {
- if(SAME_TEAM(tmp_entity, self))
- if(tmp_entity.iscaptured)
- if(max_dist <= 0 || vlen(tmp_entity.origin - pos) <= max_dist)
- if(vlen(tmp_entity.origin - pos) <= vlen(closest_target.origin - pos) || closest_target == world)
- closest_target = tmp_entity;
- tmp_entity = tmp_entity.chain;
- }
- tmp_entity = findchain(classname, "onslaught_generator");
- while(tmp_entity)
- {
- if(SAME_TEAM(tmp_entity, self))
- if(max_dist <= 0 || vlen(tmp_entity.origin - pos) < max_dist)
- if(vlen(tmp_entity.origin - pos) <= vlen(closest_target.origin - pos) || closest_target == world)
- closest_target = tmp_entity;
- tmp_entity = tmp_entity.chain;
- }
-
- return closest_target;
-}
-
-/*
- * Find control point or generator owned by the same team self which is nearest to pos
- * if max_dist is positive, only control points within this range will be considered
- * This function only check distances on the XY plane, disregarding Z
- */
-entity ons_Nearest_ControlPoint_2D(vector pos, float max_dist)
-{SELFPARAM();
- entity tmp_entity, closest_target = world;
- vector delta;
- float smallest_distance = 0, distance;
-
- tmp_entity = findchain(classname, "onslaught_controlpoint");
- while(tmp_entity)
- {
- delta = tmp_entity.origin - pos;
- delta_z = 0;
- distance = vlen(delta);
-
- if(SAME_TEAM(tmp_entity, self))
- if(tmp_entity.iscaptured)
- if(max_dist <= 0 || distance <= max_dist)
- if(closest_target == world || distance <= smallest_distance )
- {
- closest_target = tmp_entity;
- smallest_distance = distance;
- }
-
- tmp_entity = tmp_entity.chain;
- }
- tmp_entity = findchain(classname, "onslaught_generator");
- while(tmp_entity)
- {
- delta = tmp_entity.origin - pos;
- delta_z = 0;
- distance = vlen(delta);
-
- if(SAME_TEAM(tmp_entity, self))
- if(max_dist <= 0 || distance <= max_dist)
- if(closest_target == world || distance <= smallest_distance )
- {
- closest_target = tmp_entity;
- smallest_distance = distance;
- }
-
- tmp_entity = tmp_entity.chain;
- }
-
- return closest_target;
-}
-/**
- * find the number of control points and generators in the same team as self
- */
-int ons_Count_SelfControlPoints()
-{SELFPARAM();
- entity tmp_entity;
- tmp_entity = findchain(classname, "onslaught_controlpoint");
- int n = 0;
- while(tmp_entity)
- {
- if(SAME_TEAM(tmp_entity, self))
- if(tmp_entity.iscaptured)
- n++;
- tmp_entity = tmp_entity.chain;
- }
- tmp_entity = findchain(classname, "onslaught_generator");
- while(tmp_entity)
- {
- if(SAME_TEAM(tmp_entity, self))
- n++;
- tmp_entity = tmp_entity.chain;
- }
- return n;
-}
-
-/**
- * Teleport player to a random position near tele_target
- * if tele_effects is true, teleport sound+particles are created
- * return false on failure
- */
-bool ons_Teleport(entity player, entity tele_target, float range, bool tele_effects)
-{
- if ( !tele_target )
- return false;
-
- int i;
- vector loc;
- float theta;
- // narrow the range for each iteration to increase chances that a spawnpoint
- // can be found even if there's little room around the control point
- float iteration_scale = 1;
- for(i = 0; i < 16; ++i)
- {
- iteration_scale -= i / 16;
- theta = random() * 2 * M_PI;
- loc_y = sin(theta);
- loc_x = cos(theta);
- loc_z = 0;
- loc *= random() * range * iteration_scale;
-
- loc += tele_target.origin + '0 0 128' * iteration_scale;
-
- tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, player);
- if(trace_fraction == 1.0 && !trace_startsolid)
- {
- traceline(tele_target.origin, loc, MOVE_NOMONSTERS, tele_target); // double check to make sure we're not spawning outside the world
- if(trace_fraction == 1.0 && !trace_startsolid)
- {
- if ( tele_effects )
- {
- Send_Effect(EFFECT_TELEPORT, player.origin, '0 0 0', 1);
- sound (player, CH_TRIGGER, SND_TELEPORT, VOL_BASE, ATTEN_NORM);
- }
- setorigin(player, loc);
- player.angles = '0 1 0' * ( theta * RAD2DEG + 180 );
- makevectors(player.angles);
- player.fixangle = true;
- player.teleport_antispam = time + autocvar_g_onslaught_teleport_wait;
-
- if ( tele_effects )
- Send_Effect(EFFECT_TELEPORT, player.origin + v_forward * 32, '0 0 0', 1);
- return true;
- }
- }
- }
-
- return false;
-}
-
-// ==============
-// Hook Functions
-// ==============
-
-MUTATOR_HOOKFUNCTION(ons, reset_map_global)
-{SELFPARAM();
- entity e;
- FOR_EACH_PLAYER(e)
- {
- e.ons_roundlost = false;
- e.ons_deathloc = '0 0 0';
- WITH(entity, self, e, PutClientInServer());
- }
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, ClientDisconnect)
-{SELFPARAM();
- self.ons_deathloc = '0 0 0';
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, MakePlayerObserver)
-{SELFPARAM();
- self.ons_deathloc = '0 0 0';
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayerSpawn)
-{SELFPARAM();
- if(!round_handler_IsRoundStarted())
- {
- self.player_blocked = true;
- return false;
- }
-
- entity l;
- for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
- {
- l.sprite.SendFlags |= 16;
- }
- for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
- {
- l.sprite.SendFlags |= 16;
- }
-
- if(ons_stalemate) { Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT); }
-
- if ( autocvar_g_onslaught_spawn_choose )
- if ( self.ons_spawn_by )
- if ( ons_Teleport(self,self.ons_spawn_by,autocvar_g_onslaught_teleport_radius,false) )
- {
- self.ons_spawn_by = world;
- return false;
- }
-
- if(autocvar_g_onslaught_spawn_at_controlpoints)
- if(random() <= autocvar_g_onslaught_spawn_at_controlpoints_chance)
- {
- float random_target = autocvar_g_onslaught_spawn_at_controlpoints_random;
- entity tmp_entity, closest_target = world;
- vector spawn_loc = self.ons_deathloc;
-
- // new joining player or round reset, don't bother checking
- if(spawn_loc == '0 0 0') { return false; }
-
- if(random_target) { RandomSelection_Init(); }
-
- for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
- {
- if(SAME_TEAM(tmp_entity, self))
- if(random_target)
- RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
- else if(vlen(tmp_entity.origin - spawn_loc) <= vlen(closest_target.origin - spawn_loc) || closest_target == world)
- closest_target = tmp_entity;
- }
-
- if(random_target) { closest_target = RandomSelection_chosen_ent; }
-
- if(closest_target)
- {
- float i;
- vector loc;
- float iteration_scale = 1;
- for(i = 0; i < 10; ++i)
- {
- iteration_scale -= i / 10;
- loc = closest_target.origin + '0 0 96' * iteration_scale;
- loc += ('0 1 0' * random()) * 128 * iteration_scale;
- tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, self);
- if(trace_fraction == 1.0 && !trace_startsolid)
- {
- traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the world
- if(trace_fraction == 1.0 && !trace_startsolid)
- {
- setorigin(self, loc);
- self.angles = normalize(loc - closest_target.origin) * RAD2DEG;
- return false;
- }
- }
- }
- }
- }
-
- if(autocvar_g_onslaught_spawn_at_generator)
- if(random() <= autocvar_g_onslaught_spawn_at_generator_chance)
- {
- float random_target = autocvar_g_onslaught_spawn_at_generator_random;
- entity tmp_entity, closest_target = world;
- vector spawn_loc = self.ons_deathloc;
-
- // new joining player or round reset, don't bother checking
- if(spawn_loc == '0 0 0') { return false; }
-
- if(random_target) { RandomSelection_Init(); }
-
- for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
- {
- if(random_target)
- RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
- else
- {
- if(SAME_TEAM(tmp_entity, self))
- if(vlen(tmp_entity.origin - spawn_loc) <= vlen(closest_target.origin - spawn_loc) || closest_target == world)
- closest_target = tmp_entity;
- }
- }
-
- if(random_target) { closest_target = RandomSelection_chosen_ent; }
-
- if(closest_target)
- {
- float i;
- vector loc;
- float iteration_scale = 1;
- for(i = 0; i < 10; ++i)
- {
- iteration_scale -= i / 10;
- loc = closest_target.origin + '0 0 128' * iteration_scale;
- loc += ('0 1 0' * random()) * 256 * iteration_scale;
- tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, self);
- if(trace_fraction == 1.0 && !trace_startsolid)
- {
- traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the world
- if(trace_fraction == 1.0 && !trace_startsolid)
- {
- setorigin(self, loc);
- self.angles = normalize(loc - closest_target.origin) * RAD2DEG;
- return false;
- }
- }
- }
- }
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayerDies)
-{SELFPARAM();
- frag_target.ons_deathloc = frag_target.origin;
- entity l;
- for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
- {
- l.sprite.SendFlags |= 16;
- }
- for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
- {
- l.sprite.SendFlags |= 16;
- }
-
- if ( autocvar_g_onslaught_spawn_choose )
- if ( ons_Count_SelfControlPoints() > 1 )
- stuffcmd(self, "qc_cmd_cl hud clickradar\n");
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, MonsterMove)
-{SELFPARAM();
- entity e = find(world, targetname, self.target);
- if (e != world)
- self.team = e.team;
-
- return false;
-}
-
-void ons_MonsterSpawn_Delayed()
-{SELFPARAM();
- entity e, own = self.owner;
-
- if(!own) { remove(self); return; }
-
- if(own.targetname)
- {
- e = find(world, target, own.targetname);
- if(e != world)
- {
- own.team = e.team;
-
- activator = e;
- own.use();
- }
- }
-
- remove(self);
-}
-
-MUTATOR_HOOKFUNCTION(ons, MonsterSpawn)
-{SELFPARAM();
- entity e = spawn();
- e.owner = self;
- InitializeEntity(e, ons_MonsterSpawn_Delayed, INITPRIO_FINDTARGET);
-
- return false;
-}
-
-void ons_TurretSpawn_Delayed()
-{SELFPARAM();
- entity e, own = self.owner;
-
- if(!own) { remove(self); return; }
-
- if(own.targetname)
- {
- e = find(world, target, own.targetname);
- if(e != world)
- {
- own.team = e.team;
- own.active = ACTIVE_NOT;
-
- activator = e;
- own.use();
- }
- }
-
- remove(self);
-}
-
-MUTATOR_HOOKFUNCTION(ons, TurretSpawn)
-{SELFPARAM();
- entity e = spawn();
- e.owner = self;
- InitializeEntity(e, ons_TurretSpawn_Delayed, INITPRIO_FINDTARGET);
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, HavocBot_ChooseRole)
-{SELFPARAM();
- havocbot_ons_reset_role(self);
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ons, GetTeamCount)
-{
- // onslaught is special
- for(entity tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
- {
- switch(tmp_entity.team)
- {
- case NUM_TEAM_1: c1 = 0; break;
- case NUM_TEAM_2: c2 = 0; break;
- case NUM_TEAM_3: c3 = 0; break;
- case NUM_TEAM_4: c4 = 0; break;
- }
- }
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ons, SpectateCopy)
-{SELFPARAM();
- self.ons_roundlost = other.ons_roundlost; // make spectators see it too
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, SV_ParseClientCommand)
-{SELFPARAM();
- if(MUTATOR_RETURNVALUE) // command was already handled?
- return false;
-
- if ( cmd_name == "ons_spawn" )
- {
- vector pos = self.origin;
- if(cmd_argc > 1)
- pos_x = stof(argv(1));
- if(cmd_argc > 2)
- pos_y = stof(argv(2));
- if(cmd_argc > 3)
- pos_z = stof(argv(3));
-
- if ( IS_PLAYER(self) )
- {
- if ( !self.frozen )
- {
- entity source_point = ons_Nearest_ControlPoint(self.origin, autocvar_g_onslaught_teleport_radius);
-
- if ( !source_point && self.health > 0 )
- {
- sprint(self, "\nYou need to be next to a control point\n");
- return 1;
- }
-
-
- entity closest_target = ons_Nearest_ControlPoint_2D(pos, autocvar_g_onslaught_click_radius);
-
- if ( closest_target == world )
- {
- sprint(self, "\nNo control point found\n");
- return 1;
- }
-
- if ( self.health <= 0 )
- {
- self.ons_spawn_by = closest_target;
- self.respawn_flags = self.respawn_flags | RESPAWN_FORCE;
- }
- else
- {
- if ( source_point == closest_target )
- {
- sprint(self, "\nTeleporting to the same point\n");
- return 1;
- }
-
- if ( !ons_Teleport(self,closest_target,autocvar_g_onslaught_teleport_radius,true) )
- sprint(self, "\nUnable to teleport there\n");
- }
-
- return 1;
- }
-
- sprint(self, "\nNo teleportation for you\n");
- }
-
- return 1;
- }
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayerUseKey)
-{SELFPARAM();
- if(MUTATOR_RETURNVALUE || gameover) { return false; }
-
- if((time > self.teleport_antispam) && (self.deadflag == DEAD_NO) && !self.vehicle)
- {
- entity source_point = ons_Nearest_ControlPoint(self.origin, autocvar_g_onslaught_teleport_radius);
- if ( source_point )
- {
- stuffcmd(self, "qc_cmd_cl hud clickradar\n");
- return true;
- }
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayHitsound)
-{
- return (frag_victim.classname == "onslaught_generator" && !frag_victim.isshielded)
- || (frag_victim.classname == "onslaught_controlpoint_icon" && !frag_victim.owner.isshielded);
-}
-
-MUTATOR_HOOKFUNCTION(ons, SendWaypoint)
-{
- if(wp_sendflags & 16)
- {
- if(self.owner.classname == "onslaught_controlpoint")
- {
- entity wp_owner = self.owner;
- entity e = WaypointSprite_getviewentity(wp_sendto);
- if(SAME_TEAM(e, wp_owner) && wp_owner.goalentity.health >= wp_owner.goalentity.max_health) { wp_flag |= 2; }
- if(!ons_ControlPoint_Attackable(wp_owner, e.team)) { wp_flag |= 2; }
- }
- if(self.owner.classname == "onslaught_generator")
- {
- entity wp_owner = self.owner;
- if(wp_owner.isshielded && wp_owner.health >= wp_owner.max_health) { wp_flag |= 2; }
- if(wp_owner.health <= 0) { wp_flag |= 2; }
- }
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, TurretValidateTarget)
-{
- if(substring(turret_target.classname, 0, 10) == "onslaught_") // don't attack onslaught targets, that's the player's job!
- {
- ret_float = -3;
- return true;
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, TurretThink)
-{
- // ONS uses somewhat backwards linking.
- if(self.target)
- {
- entity e = find(world, targetname, self.target);
- if (e != world)
- self.team = e.team;
- }
-
- if(self.team != self.tur_head.team)
- turret_respawn();
-
- return false;
-}
-
-
-// ==========
-// Spawnfuncs
-// ==========
-
-/*QUAKED spawnfunc_onslaught_link (0 .5 .8) (-16 -16 -16) (16 16 16)
- Link between control points.
-
- This entity targets two different spawnfunc_onslaught_controlpoint or spawnfunc_onslaught_generator entities, and suppresses shielding on both if they are owned by different teams.
-
-keys:
-"target" - first control point.
-"target2" - second control point.
- */
-spawnfunc(onslaught_link)
-{
- if(!g_onslaught) { remove(self); return; }
-
- if (self.target == "" || self.target2 == "")
- objerror("target and target2 must be set\n");
-
- self.ons_worldlinknext = ons_worldlinklist; // link into ons_worldlinklist
- ons_worldlinklist = self;
-
- InitializeEntity(self, ons_DelayedLinkSetup, INITPRIO_FINDTARGET);
- Net_LinkEntity(self, false, 0, ons_Link_Send);
-}
-
-/*QUAKED spawnfunc_onslaught_controlpoint (0 .5 .8) (-32 -32 0) (32 32 128)
- Control point. Be sure to give this enough clearance so that the shootable part has room to exist
-
- This should link to an spawnfunc_onslaught_controlpoint entity or spawnfunc_onslaught_generator entity.
-
-keys:
-"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
-"target" - target any entities that are tied to this control point, such as vehicles and buildable structure entities.
-"message" - name of this control point (should reflect the location in the map, such as "center bridge", "north tower", etc)
- */
-
-spawnfunc(onslaught_controlpoint)
-{
- if(!g_onslaught) { remove(self); return; }
-
- ons_ControlPoint_Setup(self);
-}
-
-/*QUAKED spawnfunc_onslaught_generator (0 .5 .8) (-32 -32 -24) (32 32 64)
- Base generator.
-
- spawnfunc_onslaught_link entities can target this.
-
-keys:
-"team" - team that owns this generator (5 = red, 14 = blue, etc), MUST BE SET.
-"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
- */
-spawnfunc(onslaught_generator)
-{
- if(!g_onslaught) { remove(self); return; }
- if(!self.team) { objerror("team must be set"); }
-
- ons_GeneratorSetup(self);
-}
-
-// scoreboard setup
-void ons_ScoreRules()
-{
- CheckAllowedTeams(world);
- ScoreRules_basics(((c4>=0) ? 4 : (c3>=0) ? 3 : 2), SFL_SORT_PRIO_PRIMARY, 0, true);
- ScoreInfo_SetLabel_TeamScore (ST_ONS_CAPS, "destroyed", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_ONS_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
- ScoreInfo_SetLabel_PlayerScore(SP_ONS_TAKES, "takes", 0);
- ScoreRules_basics_end();
-}
-
-void ons_DelayedInit() // Do this check with a delay so we can wait for teams to be set up
-{
- ons_ScoreRules();
-
- round_handler_Spawn(Onslaught_CheckPlayers, Onslaught_CheckWinner, Onslaught_RoundStart);
- round_handler_Init(5, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
-}
-
-void ons_Initialize()
-{
- g_onslaught = true;
- ons_captureshield_force = autocvar_g_onslaught_shield_force;
-
- addstat(STAT_ROUNDLOST, AS_INT, ons_roundlost);
-
- InitializeEntity(world, ons_DelayedInit, INITPRIO_GAMETYPE);
-}
-
-#endif
REGISTER_MUTATOR(rc, false)
{
- rc_SetLimits();
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
race_Initialize();
+
+ rc_SetLimits();
}
MUTATOR_ONROLLBACK_OR_REMOVE
REGISTER_MUTATOR(tdm, false)
{
- ActivateTeamplay();
- SetLimits(autocvar_g_tdm_point_limit, autocvar_g_tdm_point_leadlimit, -1, -1);
- if (autocvar_g_tdm_team_spawns)
- have_team_spawns = -1; // request team spawns
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
InitializeEntity(world, tdm_DelayedInit, INITPRIO_GAMETYPE);
+
+ ActivateTeamplay();
+ SetLimits(autocvar_g_tdm_point_limit, autocvar_g_tdm_point_leadlimit, -1, -1);
+ if (autocvar_g_tdm_team_spawns)
+ have_team_spawns = -1; // request team spawns
}
MUTATOR_ONROLLBACK_OR_REMOVE
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(bloodloss, cvar("g_bloodloss"));
-
-.float bloodloss_timer;
-
-MUTATOR_HOOKFUNCTION(bloodloss, PlayerPreThink)
-{SELFPARAM();
- if(IS_PLAYER(self))
- if(self.health <= autocvar_g_bloodloss && self.deadflag == DEAD_NO)
- {
- self.BUTTON_CROUCH = true;
-
- if(time >= self.bloodloss_timer)
- {
- if(self.vehicle)
- vehicles_exit(VHEF_RELEASE);
- if(self.event_damage)
- self.event_damage(self, self, 1, DEATH_ROT.m_id, self.origin, '0 0 0');
- self.bloodloss_timer = time + 0.5 + random() * 0.5;
- }
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(bloodloss, PlayerJump)
-{SELFPARAM();
- if(self.health <= autocvar_g_bloodloss)
- return true;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":bloodloss");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Blood loss");
- return false;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-#include "../../../common/deathtypes/all.qh"
-#include "../../g_hook.qh"
-
-REGISTER_MUTATOR(breakablehook, cvar("g_breakablehook"));
-
-bool autocvar_g_breakablehook; // allow toggling mid match?
-bool autocvar_g_breakablehook_owner;
-
-MUTATOR_HOOKFUNCTION(breakablehook, PlayerDamage_Calculate)
-{
- if(frag_target.classname == "grapplinghook")
- {
- if((!autocvar_g_breakablehook)
- || (!autocvar_g_breakablehook_owner && frag_attacker == frag_target.realowner)
- ) { frag_damage = 0; }
-
- // hurt the owner of the hook
- if(DIFF_TEAM(frag_attacker, frag_target.realowner))
- {
- Damage (frag_target.realowner, frag_attacker, frag_attacker, 5, WEP_HOOK.m_id | HITTYPE_SPLASH, frag_target.realowner.origin, '0 0 0');
- RemoveGrapplingHook(frag_target.realowner);
- return false; // dead
- }
- }
-
- return false;
-}
-#endif
+++ /dev/null
-#ifndef MUTATOR_BUFFS_H
-#define MUTATOR_BUFFS_H
-
-// ammo
-.float buff_ammo_prev_infitems;
-.int buff_ammo_prev_clipload;
-// invisible
-.float buff_invisible_prev_alpha;
-// flight
-.float buff_flight_prev_gravity;
-// disability
-.float buff_disability_time;
-.float buff_disability_effect_time;
-// common buff variables
-.float buff_effect_delay;
-
-// buff definitions
-.float buff_active;
-.float buff_activetime;
-.float buff_activetime_updated;
-.entity buff_waypoint;
-.int oldbuffs; // for updating effects
-.entity buff_model; // controls effects (TODO: make csqc)
-
-const vector BUFF_MIN = ('-16 -16 -20');
-const vector BUFF_MAX = ('16 16 20');
-
-// client side options
-.float cvar_cl_buffs_autoreplace;
-#endif
-
-#ifdef IMPLEMENTATION
-
-#include "../../../common/triggers/target/music.qh"
-#include "../../../common/gamemodes/all.qh"
-#include "../../../common/buffs/all.qh"
-
-.float buff_time;
-void buffs_DelayedInit();
-
-REGISTER_MUTATOR(buffs, cvar("g_buffs"))
-{
- MUTATOR_ONADD
- {
- addstat(STAT_BUFFS, AS_INT, buffs);
- addstat(STAT_BUFF_TIME, AS_FLOAT, buff_time);
-
- InitializeEntity(world, buffs_DelayedInit, INITPRIO_FINDTARGET);
- }
-}
-
-entity buff_FirstFromFlags(int _buffs)
-{
- if (flags)
- {
- FOREACH(Buffs, it.m_itemid & _buffs, LAMBDA(return it));
- }
- return BUFF_Null;
-}
-
-bool buffs_BuffModel_Customize()
-{SELFPARAM();
- entity player, myowner;
- bool same_team;
-
- player = WaypointSprite_getviewentity(other);
- myowner = self.owner;
- same_team = (SAME_TEAM(player, myowner) || SAME_TEAM(player, myowner));
-
- if(myowner.alpha <= 0.5 && !same_team && myowner.alpha != 0)
- return false;
-
- if(MUTATOR_CALLHOOK(BuffModel_Customize, self, player))
- return false;
-
- if(player == myowner || (IS_SPEC(other) && other.enemy == myowner))
- {
- // somewhat hide the model, but keep the glow
- self.effects = 0;
- self.alpha = -1;
- }
- else
- {
- self.effects = EF_FULLBRIGHT | EF_LOWPRECISION;
- self.alpha = 1;
- }
- return true;
-}
-
-void buffs_BuffModel_Spawn(entity player)
-{
- player.buff_model = spawn();
- setmodel(player.buff_model, MDL_BUFF);
- setsize(player.buff_model, '0 0 -40', '0 0 40');
- setattachment(player.buff_model, player, "");
- setorigin(player.buff_model, '0 0 1' * (player.buff_model.maxs.z * 1));
- player.buff_model.owner = player;
- player.buff_model.scale = 0.7;
- player.buff_model.pflags = PFLAGS_FULLDYNAMIC;
- player.buff_model.light_lev = 200;
- player.buff_model.customizeentityforclient = buffs_BuffModel_Customize;
-}
-
-vector buff_GlowColor(entity buff)
-{
- //if(buff.team) { return Team_ColorRGB(buff.team); }
- return buff.m_color;
-}
-
-void buff_Effect(entity player, string eff)
-{SELFPARAM();
- if(!autocvar_g_buffs_effects) { return; }
-
- if(time >= self.buff_effect_delay)
- {
- Send_Effect_(eff, player.origin + ((player.mins + player.maxs) * 0.5), '0 0 0', 1);
- self.buff_effect_delay = time + 0.05; // prevent spam
- }
-}
-
-// buff item
-float buff_Waypoint_visible_for_player(entity plr)
-{SELFPARAM();
- if(!self.owner.buff_active && !self.owner.buff_activetime)
- return false;
-
- if (plr.buffs)
- {
- return plr.cvar_cl_buffs_autoreplace == false || plr.buffs != self.owner.buffs;
- }
-
- return WaypointSprite_visible_for_player(plr);
-}
-
-void buff_Waypoint_Spawn(entity e)
-{
- entity buff = buff_FirstFromFlags(e.buffs);
- entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, world, e.team, e, buff_waypoint, true, RADARICON_Buff);
- wp.wp_extra = buff.m_id;
- WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_Buff, e.glowmod);
- e.buff_waypoint.waypointsprite_visible_for_player = buff_Waypoint_visible_for_player;
-}
-
-void buff_SetCooldown(float cd)
-{SELFPARAM();
- cd = max(0, cd);
-
- if(!self.buff_waypoint)
- buff_Waypoint_Spawn(self);
-
- WaypointSprite_UpdateBuildFinished(self.buff_waypoint, time + cd);
- self.buff_activetime = cd;
- self.buff_active = !cd;
-}
-
-void buff_Respawn(entity ent)
-{SELFPARAM();
- if(gameover) { return; }
-
- vector oldbufforigin = ent.origin;
-
- if(!MoveToRandomMapLocation(ent, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, ((autocvar_g_buffs_random_location_attempts > 0) ? autocvar_g_buffs_random_location_attempts : 10), 1024, 256))
- {
- entity spot = SelectSpawnPoint(true);
- setorigin(ent, ((spot.origin + '0 0 200') + (randomvec() * 300)));
- ent.angles = spot.angles;
- }
-
- tracebox(ent.origin, ent.mins * 1.5, self.maxs * 1.5, ent.origin, MOVE_NOMONSTERS, ent);
-
- setorigin(ent, trace_endpos); // attempt to unstick
-
- ent.movetype = MOVETYPE_TOSS;
-
- makevectors(ent.angles);
- ent.velocity = '0 0 200';
- ent.angles = '0 0 0';
- if(autocvar_g_buffs_random_lifetime > 0)
- ent.lifetime = time + autocvar_g_buffs_random_lifetime;
-
- Send_Effect(EFFECT_ELECTRO_COMBO, oldbufforigin + ((ent.mins + ent.maxs) * 0.5), '0 0 0', 1);
- Send_Effect(EFFECT_ELECTRO_COMBO, CENTER_OR_VIEWOFS(ent), '0 0 0', 1);
-
- WaypointSprite_Ping(ent.buff_waypoint);
-
- sound(ent, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
-}
-
-void buff_Touch()
-{SELFPARAM();
- if(gameover) { return; }
-
- if(ITEM_TOUCH_NEEDKILL())
- {
- buff_Respawn(self);
- return;
- }
-
- if((self.team && DIFF_TEAM(other, self))
- || (other.frozen)
- || (other.vehicle)
- || (!self.buff_active)
- )
- {
- // can't touch this
- return;
- }
-
- if(MUTATOR_CALLHOOK(BuffTouch, self, other))
- return;
-
- if(!IS_PLAYER(other))
- return; // incase mutator changed other
-
- if (other.buffs)
- {
- if (other.cvar_cl_buffs_autoreplace && other.buffs != self.buffs)
- {
- int buffid = buff_FirstFromFlags(other.buffs).m_id;
- //Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_DROP, other.buffs);
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ITEM_BUFF_LOST, other.netname, buffid);
-
- other.buffs = 0;
- //sound(other, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
- }
- else { return; } // do nothing
- }
-
- self.owner = other;
- self.buff_active = false;
- self.lifetime = 0;
- int buffid = buff_FirstFromFlags(self.buffs).m_id;
- Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_GOT, buffid);
- Send_Notification(NOTIF_ALL_EXCEPT, other, MSG_INFO, INFO_ITEM_BUFF, other.netname, buffid);
-
- Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
- sound(other, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
- other.buffs |= (self.buffs);
-}
-
-float buff_Available(entity buff)
-{
- if (buff == BUFF_Null)
- return false;
- if (buff == BUFF_AMMO && ((start_items & IT_UNLIMITED_WEAPON_AMMO) || (start_items & IT_UNLIMITED_AMMO) || (cvar("g_melee_only"))))
- return false;
- if (buff == BUFF_VAMPIRE && cvar("g_vampire"))
- return false;
- return cvar(strcat("g_buffs_", buff.m_name));
-}
-
-.int buff_seencount;
-
-void buff_NewType(entity ent, float cb)
-{
- RandomSelection_Init();
- FOREACH(Buffs, buff_Available(it), LAMBDA(
- it.buff_seencount += 1;
- // if it's already been chosen, give it a lower priority
- RandomSelection_Add(world, it.m_itemid, string_null, 1, max(0.2, 1 / it.buff_seencount));
- ));
- ent.buffs = RandomSelection_chosen_float;
-}
-
-void buff_Think()
-{SELFPARAM();
- if(self.buffs != self.oldbuffs)
- {
- entity buff = buff_FirstFromFlags(self.buffs);
- self.color = buff.m_color;
- self.glowmod = buff_GlowColor(buff);
- self.skin = buff.m_skin;
-
- setmodel(self, MDL_BUFF);
-
- if(self.buff_waypoint)
- {
- //WaypointSprite_Disown(self.buff_waypoint, 1);
- WaypointSprite_Kill(self.buff_waypoint);
- buff_Waypoint_Spawn(self);
- if(self.buff_activetime)
- WaypointSprite_UpdateBuildFinished(self.buff_waypoint, time + self.buff_activetime - frametime);
- }
-
- self.oldbuffs = self.buffs;
- }
-
- if(!gameover)
- if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
- if(!self.buff_activetime_updated)
- {
- buff_SetCooldown(self.buff_activetime);
- self.buff_activetime_updated = true;
- }
-
- if(!self.buff_active && !self.buff_activetime)
- if(!self.owner || self.owner.frozen || self.owner.deadflag != DEAD_NO || !self.owner.iscreature || !(self.owner.buffs & self.buffs))
- {
- buff_SetCooldown(autocvar_g_buffs_cooldown_respawn + frametime);
- self.owner = world;
- if(autocvar_g_buffs_randomize)
- buff_NewType(self, self.buffs);
-
- if(autocvar_g_buffs_random_location || (self.spawnflags & 64))
- buff_Respawn(self);
- }
-
- if(self.buff_activetime)
- if(!gameover)
- if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
- {
- self.buff_activetime = max(0, self.buff_activetime - frametime);
-
- if(!self.buff_activetime)
- {
- self.buff_active = true;
- sound(self, CH_TRIGGER, SND_STRENGTH_RESPAWN, VOL_BASE, ATTN_NORM);
- Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
- }
- }
-
- if(self.buff_active)
- {
- if(self.team && !self.buff_waypoint)
- buff_Waypoint_Spawn(self);
-
- if(self.lifetime)
- if(time >= self.lifetime)
- buff_Respawn(self);
- }
-
- self.nextthink = time;
- //self.angles_y = time * 110.1;
-}
-
-void buff_Waypoint_Reset()
-{SELFPARAM();
- WaypointSprite_Kill(self.buff_waypoint);
-
- if(self.buff_activetime) { buff_Waypoint_Spawn(self); }
-}
-
-void buff_Reset()
-{SELFPARAM();
- if(autocvar_g_buffs_randomize)
- buff_NewType(self, self.buffs);
- self.owner = world;
- buff_SetCooldown(autocvar_g_buffs_cooldown_activate);
- buff_Waypoint_Reset();
- self.buff_activetime_updated = false;
-
- if(autocvar_g_buffs_random_location || (self.spawnflags & 64))
- buff_Respawn(self);
-}
-
-float buff_Customize()
-{SELFPARAM();
- entity player = WaypointSprite_getviewentity(other);
- if(!self.buff_active || (self.team && DIFF_TEAM(player, self)))
- {
- self.alpha = 0.3;
- if(self.effects & EF_FULLBRIGHT) { self.effects &= ~(EF_FULLBRIGHT); }
- self.pflags = 0;
- }
- else
- {
- self.alpha = 1;
- if(!(self.effects & EF_FULLBRIGHT)) { self.effects |= EF_FULLBRIGHT; }
- self.light_lev = 220 + 36 * sin(time);
- self.pflags = PFLAGS_FULLDYNAMIC;
- }
- return true;
-}
-
-void buff_Init(entity ent)
-{SELFPARAM();
- if(!cvar("g_buffs")) { remove(ent); return; }
-
- if(!teamplay && ent.team) { ent.team = 0; }
-
- entity buff = buff_FirstFromFlags(self.buffs);
-
- setself(ent);
- if(!self.buffs || buff_Available(buff))
- buff_NewType(self, 0);
-
- self.classname = "item_buff";
- self.solid = SOLID_TRIGGER;
- self.flags = FL_ITEM;
- self.think = buff_Think;
- self.touch = buff_Touch;
- self.reset = buff_Reset;
- self.nextthink = time + 0.1;
- self.gravity = 1;
- self.movetype = MOVETYPE_TOSS;
- self.scale = 1;
- self.skin = buff.m_skin;
- self.effects = EF_FULLBRIGHT | EF_STARDUST | EF_NOSHADOW;
- self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
- self.customizeentityforclient = buff_Customize;
- //self.gravity = 100;
- self.color = buff.m_color;
- self.glowmod = buff_GlowColor(self);
- buff_SetCooldown(autocvar_g_buffs_cooldown_activate + game_starttime);
- self.buff_active = !self.buff_activetime;
- self.pflags = PFLAGS_FULLDYNAMIC;
-
- if(self.spawnflags & 1)
- self.noalign = true;
-
- if(self.noalign)
- self.movetype = MOVETYPE_NONE; // reset by random location
-
- setmodel(self, MDL_BUFF);
- setsize(self, BUFF_MIN, BUFF_MAX);
-
- if(cvar("g_buffs_random_location") || (self.spawnflags & 64))
- buff_Respawn(self);
-
- setself(this);
-}
-
-void buff_Init_Compat(entity ent, entity replacement)
-{
- if (ent.spawnflags & 2)
- ent.team = NUM_TEAM_1;
- else if (ent.spawnflags & 4)
- ent.team = NUM_TEAM_2;
-
- ent.buffs = replacement.m_itemid;
-
- buff_Init(ent);
-}
-
-void buff_SpawnReplacement(entity ent, entity old)
-{
- setorigin(ent, old.origin);
- ent.angles = old.angles;
- ent.noalign = (old.noalign || (old.spawnflags & 1));
-
- buff_Init(ent);
-}
-
-void buff_Vengeance_DelayedDamage()
-{SELFPARAM();
- if(self.enemy)
- Damage(self.enemy, self.owner, self.owner, self.dmg, DEATH_BUFF.m_id, self.enemy.origin, '0 0 0');
-
- remove(self);
- return;
-}
-
-float buff_Inferno_CalculateTime(float x, float offset_x, float offset_y, float intersect_x, float intersect_y, float base)
-{
- return offset_y + (intersect_y - offset_y) * logn(((x - offset_x) * ((base - 1) / intersect_x)) + 1, base);
-}
-
-// mutator hooks
-MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_SplitHealthArmor)
-{
- if(frag_deathtype == DEATH_BUFF.m_id) { return false; }
-
- if(frag_target.buffs & BUFF_RESISTANCE.m_itemid)
- {
- vector v = healtharmor_applydamage(50, autocvar_g_buffs_resistance_blockpercent, frag_deathtype, frag_damage);
- damage_take = v.x;
- damage_save = v.y;
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_Calculate)
-{
- if(frag_deathtype == DEATH_BUFF.m_id) { return false; }
-
- if(frag_target.buffs & BUFF_SPEED.m_itemid)
- if(frag_target != frag_attacker)
- frag_damage *= autocvar_g_buffs_speed_damage_take;
-
- if(frag_target.buffs & BUFF_MEDIC.m_itemid)
- if((frag_target.health - frag_damage) <= 0)
- if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
- if(frag_attacker)
- if(random() <= autocvar_g_buffs_medic_survive_chance)
- frag_damage = max(5, frag_target.health - autocvar_g_buffs_medic_survive_health);
-
- if(frag_target.buffs & BUFF_JUMP.m_itemid)
- if(frag_deathtype == DEATH_FALL.m_id)
- frag_damage = 0;
-
- if(frag_target.buffs & BUFF_VENGEANCE.m_itemid)
- if(frag_attacker)
- if(frag_attacker != frag_target)
- if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
- {
- entity dmgent = spawn();
-
- dmgent.dmg = frag_damage * autocvar_g_buffs_vengeance_damage_multiplier;
- dmgent.enemy = frag_attacker;
- dmgent.owner = frag_target;
- dmgent.think = buff_Vengeance_DelayedDamage;
- dmgent.nextthink = time + 0.1;
- }
-
- if(frag_target.buffs & BUFF_BASH.m_itemid)
- if(frag_attacker != frag_target)
- if(vlen(frag_force))
- frag_force = '0 0 0';
-
- if(frag_attacker.buffs & BUFF_BASH.m_itemid)
- if(vlen(frag_force))
- if(frag_attacker == frag_target)
- frag_force *= autocvar_g_buffs_bash_force_self;
- else
- frag_force *= autocvar_g_buffs_bash_force;
-
- if(frag_attacker.buffs & BUFF_DISABILITY.m_itemid)
- if(frag_target != frag_attacker)
- frag_target.buff_disability_time = time + autocvar_g_buffs_disability_slowtime;
-
- if(frag_attacker.buffs & BUFF_MEDIC.m_itemid)
- if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC)
- if(SAME_TEAM(frag_attacker, frag_target))
- if(frag_attacker != frag_target)
- {
- frag_target.health = min(g_pickup_healthmega_max, frag_target.health + frag_damage);
- frag_damage = 0;
- }
-
- if(frag_attacker.buffs & BUFF_INFERNO.m_itemid)
- if(frag_target != frag_attacker) {
- float time = buff_Inferno_CalculateTime(
- frag_damage,
- 0,
- autocvar_g_buffs_inferno_burntime_min_time,
- autocvar_g_buffs_inferno_burntime_target_damage,
- autocvar_g_buffs_inferno_burntime_target_time,
- autocvar_g_buffs_inferno_burntime_factor
- );
- Fire_AddDamage(frag_target, frag_attacker, (frag_damage * autocvar_g_buffs_inferno_damagemultiplier) * time, time, DEATH_BUFF.m_id);
- }
-
- // this... is ridiculous (TODO: fix!)
- if(frag_attacker.buffs & BUFF_VAMPIRE.m_itemid)
- if(!frag_target.vehicle)
- if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC)
- if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
- if(frag_target.deadflag == DEAD_NO)
- if(IS_PLAYER(frag_target) || IS_MONSTER(frag_target))
- if(frag_attacker != frag_target)
- if(!frag_target.frozen)
- if(frag_target.takedamage)
- if(DIFF_TEAM(frag_attacker, frag_target))
- {
- frag_attacker.health = bound(0, frag_attacker.health + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.health), g_pickup_healthsmall_max);
- if(frag_target.armorvalue)
- frag_attacker.armorvalue = bound(0, frag_attacker.armorvalue + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.armorvalue), g_pickup_armorsmall_max);
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs,PlayerSpawn)
-{SELFPARAM();
- self.buffs = 0;
- // reset timers here to prevent them continuing after re-spawn
- self.buff_disability_time = 0;
- self.buff_disability_effect_time = 0;
- return false;
-}
-
-.float stat_sv_maxspeed;
-.float stat_sv_airspeedlimit_nonqw;
-.float stat_sv_jumpvelocity;
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
-{SELFPARAM();
- if(self.buffs & BUFF_SPEED.m_itemid)
- {
- self.stat_sv_maxspeed *= autocvar_g_buffs_speed_speed;
- self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_speed_speed;
- }
-
- if(time < self.buff_disability_time)
- {
- self.stat_sv_maxspeed *= autocvar_g_buffs_disability_speed;
- self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_disability_speed;
- }
-
- if(self.buffs & BUFF_JUMP.m_itemid)
- {
- // automatically reset, no need to worry
- self.stat_sv_jumpvelocity = autocvar_g_buffs_jump_height;
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerJump)
-{SELFPARAM();
- if(self.buffs & BUFF_JUMP.m_itemid)
- player_jumpheight = autocvar_g_buffs_jump_height;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, MonsterMove)
-{SELFPARAM();
- if(time < self.buff_disability_time)
- {
- monster_speed_walk *= autocvar_g_buffs_disability_speed;
- monster_speed_run *= autocvar_g_buffs_disability_speed;
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerDies)
-{SELFPARAM();
- if(self.buffs)
- {
- int buffid = buff_FirstFromFlags(self.buffs).m_id;
- Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
- self.buffs = 0;
-
- if(self.buff_model)
- {
- remove(self.buff_model);
- self.buff_model = world;
- }
- }
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerUseKey, CBC_ORDER_FIRST)
-{SELFPARAM();
- if(MUTATOR_RETURNVALUE || gameover) { return false; }
- if(self.buffs)
- {
- int buffid = buff_FirstFromFlags(self.buffs).m_id;
- Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, buffid);
- Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
-
- self.buffs = 0;
- sound(self, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
- return true;
- }
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
-{SELFPARAM();
- if(MUTATOR_RETURNVALUE || gameover) { return false; }
-
- if(self.buffs & BUFF_SWAPPER.m_itemid)
- {
- float best_distance = autocvar_g_buffs_swapper_range;
- entity closest = world;
- entity player;
- FOR_EACH_PLAYER(player)
- if(DIFF_TEAM(self, player))
- if(player.deadflag == DEAD_NO && !player.frozen && !player.vehicle)
- if(vlen(self.origin - player.origin) <= best_distance)
- {
- best_distance = vlen(self.origin - player.origin);
- closest = player;
- }
-
- if(closest)
- {
- vector my_org, my_vel, my_ang, their_org, their_vel, their_ang;
-
- my_org = self.origin;
- my_vel = self.velocity;
- my_ang = self.angles;
- their_org = closest.origin;
- their_vel = closest.velocity;
- their_ang = closest.angles;
-
- Drop_Special_Items(closest);
-
- MUTATOR_CALLHOOK(PortalTeleport, self); // initiate flag dropper
-
- setorigin(self, their_org);
- setorigin(closest, my_org);
-
- closest.velocity = my_vel;
- closest.angles = my_ang;
- closest.fixangle = true;
- closest.oldorigin = my_org;
- closest.oldvelocity = my_vel;
- self.velocity = their_vel;
- self.angles = their_ang;
- self.fixangle = true;
- self.oldorigin = their_org;
- self.oldvelocity = their_vel;
-
- // set pusher so self gets the kill if they fall into void
- closest.pusher = self;
- closest.pushltime = time + autocvar_g_maxpushtime;
- closest.istypefrag = closest.BUTTON_CHAT;
-
- Send_Effect(EFFECT_ELECTRO_COMBO, their_org, '0 0 0', 1);
- Send_Effect(EFFECT_ELECTRO_COMBO, my_org, '0 0 0', 1);
-
- sound(self, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
- sound(closest, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
-
- // TODO: add a counter to handle how many times one can teleport, and a delay to prevent spam
- self.buffs = 0;
- return true;
- }
- }
- return false;
-}
-
-bool buffs_RemovePlayer(entity player)
-{
- if(player.buff_model)
- {
- remove(player.buff_model);
- player.buff_model = world;
- }
-
- // also reset timers here to prevent them continuing after spectating
- player.buff_disability_time = 0;
- player.buff_disability_effect_time = 0;
-
- return false;
-}
-MUTATOR_HOOKFUNCTION(buffs, MakePlayerObserver) { return buffs_RemovePlayer(self); }
-MUTATOR_HOOKFUNCTION(buffs, ClientDisconnect) { return buffs_RemovePlayer(self); }
-
-MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint)
-{SELFPARAM();
- entity e = WaypointSprite_getviewentity(other);
-
- // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
- // but only apply this to real players, not to spectators
- if((self.owner.flags & FL_CLIENT) && (self.owner.buffs & BUFF_INVISIBLE.m_itemid) && (e == other))
- if(DIFF_TEAM(self.owner, e))
- return true;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, OnEntityPreSpawn, CBC_ORDER_LAST)
-{SELFPARAM();
- if(autocvar_g_buffs_replace_powerups)
- switch(self.classname)
- {
- case "item_strength":
- case "item_invincible":
- {
- entity e = spawn();
- buff_SpawnReplacement(e, self);
- return true;
- }
- }
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, WeaponRateFactor)
-{SELFPARAM();
- if(self.buffs & BUFF_SPEED.m_itemid)
- weapon_rate *= autocvar_g_buffs_speed_rate;
-
- if(time < self.buff_disability_time)
- weapon_rate *= autocvar_g_buffs_disability_rate;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, WeaponSpeedFactor)
-{SELFPARAM();
- if(self.buffs & BUFF_SPEED.m_itemid)
- ret_float *= autocvar_g_buffs_speed_weaponspeed;
-
- if(time < self.buff_disability_time)
- ret_float *= autocvar_g_buffs_disability_weaponspeed;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
-{SELFPARAM();
- if(gameover || self.deadflag != DEAD_NO) { return false; }
-
- if(time < self.buff_disability_time)
- if(time >= self.buff_disability_effect_time)
- {
- Send_Effect(EFFECT_SMOKING, self.origin + ((self.mins + self.maxs) * 0.5), '0 0 0', 1);
- self.buff_disability_effect_time = time + 0.5;
- }
-
- // handle buff lost status
- // 1: notify everyone else
- // 2: notify carrier as well
- int buff_lost = 0;
-
- if(self.buff_time)
- if(time >= self.buff_time)
- buff_lost = 2;
-
- if(self.frozen) { buff_lost = 1; }
-
- if(buff_lost)
- {
- if(self.buffs)
- {
- int buffid = buff_FirstFromFlags(self.buffs).m_id;
- Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
- if(buff_lost >= 2)
- {
- Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
- sound(self, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
- }
- self.buffs = 0;
- }
- }
-
- if(self.buffs & BUFF_MAGNET.m_itemid)
- {
- vector pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item;
- for(other = world; (other = findflags(other, flags, FL_ITEM)); )
- if(boxesoverlap(self.absmin - pickup_size, self.absmax + pickup_size, other.absmin, other.absmax))
- {
- setself(other);
- other = this;
- if(self.touch)
- self.touch();
- other = self;
- setself(this);
- }
- }
-
- if(self.buffs & BUFF_AMMO.m_itemid)
- if(self.clip_size)
- self.clip_load = self.(weapon_load[self.switchweapon]) = self.clip_size;
-
- if((self.buffs & BUFF_INVISIBLE.m_itemid) && (self.oldbuffs & BUFF_INVISIBLE.m_itemid))
- if(self.alpha != autocvar_g_buffs_invisible_alpha)
- self.alpha = autocvar_g_buffs_invisible_alpha; // powerups reset alpha, so we must enforce this (TODO)
-
-#define BUFF_ONADD(b) if ( (self.buffs & (b).m_itemid) && !(self.oldbuffs & (b).m_itemid))
-#define BUFF_ONREM(b) if (!(self.buffs & (b).m_itemid) && (self.oldbuffs & (b).m_itemid))
-
- if(self.buffs != self.oldbuffs)
- {
- entity buff = buff_FirstFromFlags(self.buffs);
- float bufftime = buff != BUFF_Null ? buff.m_time(buff) : 0;
- self.buff_time = (bufftime) ? time + bufftime : 0;
-
- BUFF_ONADD(BUFF_AMMO)
- {
- self.buff_ammo_prev_infitems = (self.items & IT_UNLIMITED_WEAPON_AMMO);
- self.items |= IT_UNLIMITED_WEAPON_AMMO;
-
- if(self.clip_load)
- self.buff_ammo_prev_clipload = self.clip_load;
- self.clip_load = self.(weapon_load[self.switchweapon]) = self.clip_size;
- }
-
- BUFF_ONREM(BUFF_AMMO)
- {
- if(self.buff_ammo_prev_infitems)
- self.items |= IT_UNLIMITED_WEAPON_AMMO;
- else
- self.items &= ~IT_UNLIMITED_WEAPON_AMMO;
-
- if(self.buff_ammo_prev_clipload)
- self.clip_load = self.buff_ammo_prev_clipload;
- }
-
- BUFF_ONADD(BUFF_INVISIBLE)
- {
- if(time < self.strength_finished && g_instagib)
- self.alpha = autocvar_g_instagib_invis_alpha;
- else
- self.alpha = self.buff_invisible_prev_alpha;
- self.alpha = autocvar_g_buffs_invisible_alpha;
- }
-
- BUFF_ONREM(BUFF_INVISIBLE)
- self.alpha = self.buff_invisible_prev_alpha;
-
- BUFF_ONADD(BUFF_FLIGHT)
- {
- self.buff_flight_prev_gravity = self.gravity;
- self.gravity = autocvar_g_buffs_flight_gravity;
- }
-
- BUFF_ONREM(BUFF_FLIGHT)
- self.gravity = self.buff_flight_prev_gravity;
-
- self.oldbuffs = self.buffs;
- if(self.buffs)
- {
- if(!self.buff_model)
- buffs_BuffModel_Spawn(self);
-
- self.buff_model.color = buff.m_color;
- self.buff_model.glowmod = buff_GlowColor(self.buff_model);
- self.buff_model.skin = buff.m_skin;
-
- self.effects |= EF_NOSHADOW;
- }
- else
- {
- remove(self.buff_model);
- self.buff_model = world;
-
- self.effects &= ~(EF_NOSHADOW);
- }
- }
-
- if(self.buff_model)
- {
- self.buff_model.effects = self.effects;
- self.buff_model.effects |= EF_LOWPRECISION;
- self.buff_model.effects = self.buff_model.effects & EFMASK_CHEAP; // eat performance
-
- self.buff_model.alpha = self.alpha;
- }
-
-#undef BUFF_ONADD
-#undef BUFF_ONREM
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, SpectateCopy)
-{SELFPARAM();
- self.buffs = other.buffs;
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, VehicleEnter)
-{
- vh_vehicle.buffs = vh_player.buffs;
- vh_player.buffs = 0;
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, VehicleExit)
-{
- vh_player.buffs = vh_vehicle.buffs;
- vh_vehicle.buffs = 0;
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerRegen)
-{SELFPARAM();
- if(self.buffs & BUFF_MEDIC.m_itemid)
- {
- regen_mod_rot = autocvar_g_buffs_medic_rot;
- regen_mod_limit = regen_mod_max = autocvar_g_buffs_medic_max;
- regen_mod_regen = autocvar_g_buffs_medic_regen;
- }
-
- if(self.buffs & BUFF_SPEED.m_itemid)
- regen_mod_regen = autocvar_g_buffs_speed_regen;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, GetCvars)
-{
- GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_buffs_autoreplace, "cl_buffs_autoreplace");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":Buffs");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Buffs");
- return false;
-}
-
-void buffs_DelayedInit()
-{
- if(autocvar_g_buffs_spawn_count > 0)
- if(find(world, classname, "item_buff") == world)
- {
- float i;
- for(i = 0; i < autocvar_g_buffs_spawn_count; ++i)
- {
- entity e = spawn();
- e.spawnflags |= 64; // always randomize
- e.velocity = randomvec() * 250; // this gets reset anyway if random location works
- buff_Init(e);
- }
- }
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(campcheck, cvar("g_campcheck"));
-
-.float campcheck_nextcheck;
-.float campcheck_traveled_distance;
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerDies)
-{SELFPARAM();
- Kill_Notification(NOTIF_ONE, self, MSG_CENTER_CPID, CPID_CAMPCHECK);
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerDamage_Calculate)
-{
- if(IS_PLAYER(frag_target))
- if(IS_PLAYER(frag_attacker))
- if(frag_attacker != frag_target)
- {
- frag_target.campcheck_traveled_distance = autocvar_g_campcheck_distance;
- frag_attacker.campcheck_traveled_distance = autocvar_g_campcheck_distance;
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerPreThink)
-{SELFPARAM();
- if(!gameover)
- if(!warmup_stage) // don't consider it camping during warmup?
- if(time >= game_starttime)
- if(IS_PLAYER(self))
- if(IS_REAL_CLIENT(self)) // bots may camp, but that's no reason to constantly kill them
- if(self.deadflag == DEAD_NO)
- if(!self.frozen)
- if(!self.BUTTON_CHAT)
- if(autocvar_g_campcheck_interval)
- {
- vector dist;
-
- // calculate player movement (in 2 dimensions only, so jumping on one spot doesn't count as movement)
- dist = self.prevorigin - self.origin;
- dist.z = 0;
- self.campcheck_traveled_distance += fabs(vlen(dist));
-
- if((autocvar_g_campaign && !campaign_bots_may_start) || (time < game_starttime) || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
- {
- self.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
- self.campcheck_traveled_distance = 0;
- }
-
- if(time > self.campcheck_nextcheck)
- {
- if(self.campcheck_traveled_distance < autocvar_g_campcheck_distance)
- {
- Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_CAMPCHECK);
- if(self.vehicle)
- Damage(self.vehicle, self, self, autocvar_g_campcheck_damage * 2, DEATH_CAMP.m_id, self.vehicle.origin, '0 0 0');
- else
- Damage(self, self, self, bound(0, autocvar_g_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP.m_id, self.origin, '0 0 0');
- }
- self.campcheck_nextcheck = time + autocvar_g_campcheck_interval;
- self.campcheck_traveled_distance = 0;
- }
-
- return false;
- }
-
- self.campcheck_nextcheck = time + autocvar_g_campcheck_interval; // one of the above checks failed, so keep the timer up to date
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerSpawn)
-{SELFPARAM();
- self.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
- self.campcheck_traveled_distance = 0;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":CampCheck");
- return false;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-
-#ifdef CSQC
- #define PHYS_DODGING_FRAMETIME (1 / (frametime <= 0 ? 60 : frametime))
- #define PHYS_DODGING getstati(STAT_DODGING)
- #define PHYS_DODGING_DELAY getstatf(STAT_DODGING_DELAY)
- #define PHYS_DODGING_TIMEOUT(s) getstatf(STAT_DODGING_TIMEOUT)
- #define PHYS_DODGING_HORIZ_SPEED_FROZEN getstatf(STAT_DODGING_HORIZ_SPEED_FROZEN)
- #define PHYS_DODGING_FROZEN_NODOUBLETAP getstati(STAT_DODGING_FROZEN_NO_DOUBLETAP)
- #define PHYS_DODGING_HORIZ_SPEED getstatf(STAT_DODGING_HORIZ_SPEED)
- #define PHYS_DODGING_PRESSED_KEYS(s) s.pressedkeys
- #define PHYS_DODGING_HEIGHT_THRESHOLD getstatf(STAT_DODGING_HEIGHT_THRESHOLD)
- #define PHYS_DODGING_DISTANCE_THRESHOLD getstatf(STAT_DODGING_DISTANCE_THRESHOLD)
- #define PHYS_DODGING_RAMP_TIME getstatf(STAT_DODGING_RAMP_TIME)
- #define PHYS_DODGING_UP_SPEED getstatf(STAT_DODGING_UP_SPEED)
- #define PHYS_DODGING_WALL getstatf(STAT_DODGING_WALL)
-#elif defined(SVQC)
- #define PHYS_DODGING_FRAMETIME sys_frametime
- #define PHYS_DODGING g_dodging
- #define PHYS_DODGING_DELAY autocvar_sv_dodging_delay
- #define PHYS_DODGING_TIMEOUT(s) s.cvar_cl_dodging_timeout
- #define PHYS_DODGING_HORIZ_SPEED_FROZEN autocvar_sv_dodging_horiz_speed_frozen
- #define PHYS_DODGING_FROZEN_NODOUBLETAP autocvar_sv_dodging_frozen_doubletap
- #define PHYS_DODGING_HORIZ_SPEED autocvar_sv_dodging_horiz_speed
- #define PHYS_DODGING_PRESSED_KEYS(s) s.pressedkeys
- #define PHYS_DODGING_HEIGHT_THRESHOLD autocvar_sv_dodging_height_threshold
- #define PHYS_DODGING_DISTANCE_THRESHOLD autocvar_sv_dodging_wall_distance_threshold
- #define PHYS_DODGING_RAMP_TIME autocvar_sv_dodging_ramp_time
- #define PHYS_DODGING_UP_SPEED autocvar_sv_dodging_up_speed
- #define PHYS_DODGING_WALL autocvar_sv_dodging_wall_dodging
-#endif
-
-#ifdef SVQC
-
-float g_dodging;
-
-// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
-.float dodging_action;
-
-// the jump part of the dodge cannot be ramped
-.float dodging_single_action;
-
-#include "../../../common/animdecide.qh"
-#include "../../../common/physics.qh"
-
-.float cvar_cl_dodging_timeout;
-
-.float stat_dodging;
-.float stat_dodging_delay;
-.float stat_dodging_horiz_speed_frozen;
-.float stat_dodging_frozen_nodoubletap;
-.float stat_dodging_frozen;
-.float stat_dodging_horiz_speed;
-.float stat_dodging_height_threshold;
-.float stat_dodging_distance_threshold;
-.float stat_dodging_ramp_time;
-.float stat_dodging_up_speed;
-.float stat_dodging_wall;
-
-REGISTER_MUTATOR(dodging, cvar("g_dodging"))
-{
- // this just turns on the cvar.
- MUTATOR_ONADD
- {
- g_dodging = cvar("g_dodging");
- addstat(STAT_DODGING, AS_INT, stat_dodging);
- addstat(STAT_DODGING_DELAY, AS_FLOAT, stat_dodging_delay);
- addstat(STAT_DODGING_TIMEOUT, AS_FLOAT, cvar_cl_dodging_timeout); // we stat this, so it is updated on the client when updated on server (otherwise, chaos)
- addstat(STAT_DODGING_FROZEN_NO_DOUBLETAP, AS_INT, stat_dodging_frozen_nodoubletap);
- addstat(STAT_DODGING_HORIZ_SPEED_FROZEN, AS_FLOAT, stat_dodging_horiz_speed_frozen);
- addstat(STAT_DODGING_FROZEN, AS_INT, stat_dodging_frozen);
- addstat(STAT_DODGING_HORIZ_SPEED, AS_FLOAT, stat_dodging_horiz_speed);
- addstat(STAT_DODGING_HEIGHT_THRESHOLD, AS_FLOAT, stat_dodging_height_threshold);
- addstat(STAT_DODGING_DISTANCE_THRESHOLD, AS_FLOAT, stat_dodging_distance_threshold);
- addstat(STAT_DODGING_RAMP_TIME, AS_FLOAT, stat_dodging_ramp_time);
- addstat(STAT_DODGING_UP_SPEED, AS_FLOAT, stat_dodging_up_speed);
- addstat(STAT_DODGING_WALL, AS_FLOAT, stat_dodging_wall);
- }
-
- // this just turns off the cvar.
- MUTATOR_ONROLLBACK_OR_REMOVE
- {
- g_dodging = 0;
- }
-
- return false;
-}
-
-#endif
-
-// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
-.float dodging_action;
-
-// the jump part of the dodge cannot be ramped
-.float dodging_single_action;
-
-
-// these are used to store the last key press time for each of the keys..
-.float last_FORWARD_KEY_time;
-.float last_BACKWARD_KEY_time;
-.float last_LEFT_KEY_time;
-.float last_RIGHT_KEY_time;
-
-// these store the movement direction at the time of the dodge action happening.
-.vector dodging_direction;
-
-// this indicates the last time a dodge was executed. used to check if another one is allowed
-// and to ramp up the dodge acceleration in the physics hook.
-.float last_dodging_time;
-
-// This is the velocity gain to be added over the ramp time.
-// It will decrease from frame to frame during dodging_action = 1
-// until it's 0.
-.float dodging_velocity_gain;
-
-#ifdef CSQC
-.int pressedkeys;
-
-#elif defined(SVQC)
-
-void dodging_UpdateStats()
-{SELFPARAM();
- self.stat_dodging = PHYS_DODGING;
- self.stat_dodging_delay = PHYS_DODGING_DELAY;
- self.stat_dodging_horiz_speed_frozen = PHYS_DODGING_HORIZ_SPEED_FROZEN;
- self.stat_dodging_frozen = PHYS_DODGING_FROZEN;
- self.stat_dodging_frozen_nodoubletap = PHYS_DODGING_FROZEN_NODOUBLETAP;
- self.stat_dodging_height_threshold = PHYS_DODGING_HEIGHT_THRESHOLD;
- self.stat_dodging_distance_threshold = PHYS_DODGING_DISTANCE_THRESHOLD;
- self.stat_dodging_ramp_time = PHYS_DODGING_RAMP_TIME;
- self.stat_dodging_up_speed = PHYS_DODGING_UP_SPEED;
- self.stat_dodging_wall = PHYS_DODGING_WALL;
-}
-
-#endif
-
-// returns 1 if the player is close to a wall
-bool check_close_to_wall(float threshold)
-{SELFPARAM();
- if (PHYS_DODGING_WALL == 0) { return false; }
-
- #define X(OFFSET) \
- tracebox(self.origin, self.mins, self.maxs, self.origin + OFFSET, true, self); \
- if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold) \
- return true;
- X(1000*v_right);
- X(-1000*v_right);
- X(1000*v_forward);
- X(-1000*v_forward);
- #undef X
-
- return false;
-}
-
-bool check_close_to_ground(float threshold)
-{SELFPARAM();
- return IS_ONGROUND(self) ? true : false;
-}
-
-float PM_dodging_checkpressedkeys()
-{SELFPARAM();
- if(!PHYS_DODGING)
- return false;
-
- float frozen_dodging = (PHYS_FROZEN(self) && PHYS_DODGING_FROZEN);
- float frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
-
- // first check if the last dodge is far enough back in time so we can dodge again
- if ((time - self.last_dodging_time) < PHYS_DODGING_DELAY)
- return false;
-
- makevectors(self.angles);
-
- if (check_close_to_ground(PHYS_DODGING_HEIGHT_THRESHOLD) != 1
- && check_close_to_wall(PHYS_DODGING_DISTANCE_THRESHOLD) != 1)
- return true;
-
- float tap_direction_x = 0;
- float tap_direction_y = 0;
- float dodge_detected = 0;
-
- #define X(COND,BTN,RESULT) \
- if (self.movement_##COND) \
- /* is this a state change? */ \
- if(!(PHYS_DODGING_PRESSED_KEYS(self) & KEY_##BTN) || frozen_no_doubletap) { \
- tap_direction_##RESULT; \
- if ((time - self.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(self)) \
- dodge_detected = 1; \
- self.last_##BTN##_KEY_time = time; \
- }
- X(x < 0, BACKWARD, x--);
- X(x > 0, FORWARD, x++);
- X(y < 0, LEFT, y--);
- X(y > 0, RIGHT, y++);
- #undef X
-
- if (dodge_detected == 1)
- {
- self.last_dodging_time = time;
-
- self.dodging_action = 1;
- self.dodging_single_action = 1;
-
- self.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
-
- self.dodging_direction_x = tap_direction_x;
- self.dodging_direction_y = tap_direction_y;
-
- // normalize the dodging_direction vector.. (unlike UT99) XD
- float length = self.dodging_direction_x * self.dodging_direction_x
- + self.dodging_direction_y * self.dodging_direction_y;
- length = sqrt(length);
-
- self.dodging_direction_x = self.dodging_direction_x * 1.0 / length;
- self.dodging_direction_y = self.dodging_direction_y * 1.0 / length;
- return true;
- }
- return false;
-}
-
-void PM_dodging()
-{SELFPARAM();
- if (!PHYS_DODGING)
- return;
-
-#ifdef SVQC
- dodging_UpdateStats();
-#endif
-
- if (PHYS_DEAD(self))
- return;
-
- // when swimming, no dodging allowed..
- if (self.waterlevel >= WATERLEVEL_SWIMMING)
- {
- self.dodging_action = 0;
- self.dodging_direction_x = 0;
- self.dodging_direction_y = 0;
- return;
- }
-
- // make sure v_up, v_right and v_forward are sane
- makevectors(self.angles);
-
- // if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
- // will be called ramp_time/frametime times = 2 times. so, we need to
- // add 0.5 * the total speed each frame until the dodge action is done..
- float common_factor = PHYS_DODGING_FRAMETIME / PHYS_DODGING_RAMP_TIME;
-
- // if ramp time is smaller than frametime we get problems ;D
- common_factor = min(common_factor, 1);
-
- float horiz_speed = PHYS_FROZEN(self) ? PHYS_DODGING_HORIZ_SPEED_FROZEN : PHYS_DODGING_HORIZ_SPEED;
- float new_velocity_gain = self.dodging_velocity_gain - (common_factor * horiz_speed);
- new_velocity_gain = max(0, new_velocity_gain);
-
- float velocity_difference = self.dodging_velocity_gain - new_velocity_gain;
-
- // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
- if (self.dodging_action == 1)
- {
- //disable jump key during dodge accel phase
- if(self.movement_z > 0) { self.movement_z = 0; }
-
- self.velocity += ((self.dodging_direction_y * velocity_difference) * v_right)
- + ((self.dodging_direction_x * velocity_difference) * v_forward);
-
- self.dodging_velocity_gain = self.dodging_velocity_gain - velocity_difference;
- }
-
- // the up part of the dodge is a single shot action
- if (self.dodging_single_action == 1)
- {
- UNSET_ONGROUND(self);
-
- self.velocity += PHYS_DODGING_UP_SPEED * v_up;
-
-#ifdef SVQC
- if (autocvar_sv_dodging_sound)
- PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
-
- animdecide_setaction(self, ANIMACTION_JUMP, true);
-#endif
-
- self.dodging_single_action = 0;
- }
-
- // are we done with the dodging ramp yet?
- if((self.dodging_action == 1) && ((time - self.last_dodging_time) > PHYS_DODGING_RAMP_TIME))
- {
- // reset state so next dodge can be done correctly
- self.dodging_action = 0;
- self.dodging_direction_x = 0;
- self.dodging_direction_y = 0;
- }
-}
-
-#ifdef SVQC
-
-MUTATOR_HOOKFUNCTION(dodging, GetCvars)
-{
- GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(dodging, PlayerPhysics)
-{
- // print("dodging_PlayerPhysics\n");
- PM_dodging();
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(dodging, GetPressedKeys)
-{
- PM_dodging_checkpressedkeys();
-
- return false;
-}
-
-#endif
-
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-AUTOCVAR(g_grappling_hook, bool, false, _("let players spawn with the grappling hook which allows them to pull themselves up"));
-#ifdef SVQC
-REGISTER_MUTATOR(hook, autocvar_g_grappling_hook) {
- MUTATOR_ONADD {
- g_grappling_hook = true;
- WEP_HOOK.ammo_factor = 0;
- }
- MUTATOR_ONROLLBACK_OR_REMOVE {
- g_grappling_hook = false;
- WEP_HOOK.ammo_factor = 1;
- }
-}
-
-MUTATOR_HOOKFUNCTION(hook, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":grappling_hook");
-}
-
-MUTATOR_HOOKFUNCTION(hook, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Hook");
-}
-
-MUTATOR_HOOKFUNCTION(hook, BuildGameplayTipsString)
-{
- ret_string = strcat(ret_string, "\n\n^3grappling hook^8 is enabled, press 'e' to use it\n");
-}
-
-MUTATOR_HOOKFUNCTION(hook, PlayerSpawn)
-{
- SELFPARAM();
- self.offhand = OFFHAND_HOOK;
-}
-
-MUTATOR_HOOKFUNCTION(hook, FilterItem)
-{
- return self.weapon == WEP_HOOK.m_id;
-}
-
-#endif
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(invincibleprojectiles, cvar("g_invincible_projectiles"));
-
-MUTATOR_HOOKFUNCTION(invincibleprojectiles, EditProjectile)
-{
- if(other.health)
- {
- // disable health which in effect disables damage calculations
- other.health = 0;
- }
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":InvincibleProjectiles");
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Invincible Projectiles");
- return 0;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(melee_only, cvar("g_melee_only") && !cvar("g_instagib") && !g_nexball);
-
-MUTATOR_HOOKFUNCTION(melee_only, SetStartItems)
-{
- start_ammo_shells = warmup_start_ammo_shells = 0;
- start_weapons = warmup_start_weapons = WEPSET(SHOTGUN);
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, ForbidThrowCurrentWeapon)
-{
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, FilterItem)
-{SELFPARAM();
- switch (self.items)
- {
- case ITEM_HealthSmall.m_itemid:
- case ITEM_ArmorSmall.m_itemid:
- return false;
- }
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":MeleeOnly");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Melee Only Arena");
- return false;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(midair, cvar("g_midair"));
-
-.float midair_shieldtime;
-
-MUTATOR_HOOKFUNCTION(midair, PlayerDamage_Calculate)
-{SELFPARAM();
- if(IS_PLAYER(frag_attacker))
- if(IS_PLAYER(frag_target))
- if(time < self.midair_shieldtime)
- frag_damage = false;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(midair, PlayerPowerups)
-{SELFPARAM();
- if(time >= game_starttime)
- if(self.flags & FL_ONGROUND)
- {
- self.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
- self.midair_shieldtime = max(self.midair_shieldtime, time + autocvar_g_midair_shieldtime);
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(midair, PlayerSpawn)
-{SELFPARAM();
- if(IS_BOT_CLIENT(self))
- self.bot_moveskill = 0; // disable bunnyhopping
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(midair, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":midair");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(midair, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Midair");
- return false;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-#ifdef SVQC
- #include "../../antilag.qh"
-#endif
-#include "../../../common/physics.qh"
-
-.int multijump_count;
-.bool multijump_ready;
-.bool cvar_cl_multijump;
-
-#ifdef CSQC
-
-#define PHYS_MULTIJUMP getstati(STAT_MULTIJUMP)
-#define PHYS_MULTIJUMP_SPEED getstatf(STAT_MULTIJUMP_SPEED)
-#define PHYS_MULTIJUMP_ADD getstati(STAT_MULTIJUMP_ADD)
-#define PHYS_MULTIJUMP_MAXSPEED getstatf(STAT_MULTIJUMP_MAXSPEED)
-#define PHYS_MULTIJUMP_DODGING getstati(STAT_MULTIJUMP_DODGING)
-
-#elif defined(SVQC)
-
-#define PHYS_MULTIJUMP autocvar_g_multijump
-#define PHYS_MULTIJUMP_SPEED autocvar_g_multijump_speed
-#define PHYS_MULTIJUMP_ADD autocvar_g_multijump_add
-#define PHYS_MULTIJUMP_MAXSPEED autocvar_g_multijump_maxspeed
-#define PHYS_MULTIJUMP_DODGING autocvar_g_multijump_dodging
-
-
-.float stat_multijump;
-.float stat_multijump_speed;
-.float stat_multijump_add;
-.float stat_multijump_maxspeed;
-.float stat_multijump_dodging;
-
-void multijump_UpdateStats()
-{SELFPARAM();
- self.stat_multijump = PHYS_MULTIJUMP;
- self.stat_multijump_speed = PHYS_MULTIJUMP_SPEED;
- self.stat_multijump_add = PHYS_MULTIJUMP_ADD;
- self.stat_multijump_maxspeed = PHYS_MULTIJUMP_MAXSPEED;
- self.stat_multijump_dodging = PHYS_MULTIJUMP_DODGING;
-}
-
-void multijump_AddStats()
-{
- addstat(STAT_MULTIJUMP, AS_INT, stat_multijump);
- addstat(STAT_MULTIJUMP_SPEED, AS_FLOAT, stat_multijump_speed);
- addstat(STAT_MULTIJUMP_ADD, AS_INT, stat_multijump_add);
- addstat(STAT_MULTIJUMP_MAXSPEED, AS_FLOAT, stat_multijump_maxspeed);
- addstat(STAT_MULTIJUMP_DODGING, AS_INT, stat_multijump_dodging);
-}
-
-#endif
-
-void PM_multijump()
-{SELFPARAM();
- if(!PHYS_MULTIJUMP) { return; }
-
- if(IS_ONGROUND(self))
- {
- self.multijump_count = 0;
- }
-}
-
-bool PM_multijump_checkjump()
-{SELFPARAM();
- if(!PHYS_MULTIJUMP) { return false; }
-
-#ifdef SVQC
- bool client_multijump = self.cvar_cl_multijump;
-#elif defined(CSQC)
- bool client_multijump = cvar("cl_multijump");
-
- if(cvar("cl_multijump") > 1)
- return false; // nope
-#endif
-
- if (!IS_JUMP_HELD(self) && !IS_ONGROUND(self) && client_multijump) // jump button pressed this frame and we are in midair
- self.multijump_ready = true; // this is necessary to check that we released the jump button and pressed it again
- else
- self.multijump_ready = false;
-
- int phys_multijump = PHYS_MULTIJUMP;
-
-#ifdef CSQC
- phys_multijump = (PHYS_MULTIJUMP) ? -1 : 0;
-#endif
-
- if(!player_multijump && self.multijump_ready && (self.multijump_count < phys_multijump || phys_multijump == -1) && self.velocity_z > PHYS_MULTIJUMP_SPEED && (!PHYS_MULTIJUMP_MAXSPEED || vlen(self.velocity) <= PHYS_MULTIJUMP_MAXSPEED))
- {
- if (PHYS_MULTIJUMP)
- {
- if (!PHYS_MULTIJUMP_ADD) // in this case we make the z velocity == jumpvelocity
- {
- if (self.velocity_z < PHYS_JUMPVELOCITY)
- {
- player_multijump = true;
- self.velocity_z = 0;
- }
- }
- else
- player_multijump = true;
-
- if(player_multijump)
- {
- if(PHYS_MULTIJUMP_DODGING)
- if(self.movement_x != 0 || self.movement_y != 0) // don't remove all speed if player isnt pressing any movement keys
- {
- float curspeed;
- vector wishvel, wishdir;
-
-/*#ifdef SVQC
- curspeed = max(
- vlen(vec2(self.velocity)), // current xy speed
- vlen(vec2(antilag_takebackavgvelocity(self, max(self.lastteleporttime + sys_frametime, time - 0.25), time))) // average xy topspeed over the last 0.25 secs
- );
-#elif defined(CSQC)*/
- curspeed = vlen(vec2(self.velocity));
-//#endif
-
- makevectors(self.v_angle_y * '0 1 0');
- wishvel = v_forward * self.movement_x + v_right * self.movement_y;
- wishdir = normalize(wishvel);
-
- self.velocity_x = wishdir_x * curspeed; // allow "dodging" at a multijump
- self.velocity_y = wishdir_y * curspeed;
- // keep velocity_z unchanged!
- }
- if (PHYS_MULTIJUMP > 0)
- {
- self.multijump_count += 1;
- }
- }
- }
- self.multijump_ready = false; // require releasing and pressing the jump button again for the next jump
- }
-
- return false;
-}
-
-#ifdef SVQC
-REGISTER_MUTATOR(multijump, cvar("g_multijump"))
-{
- MUTATOR_ONADD
- {
- multijump_AddStats();
- }
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(multijump, PlayerPhysics)
-{
- multijump_UpdateStats();
- PM_multijump();
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(multijump, PlayerJump)
-{
- return PM_multijump_checkjump();
-}
-
-MUTATOR_HOOKFUNCTION(multijump, GetCvars)
-{
- GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_multijump, "cl_multijump");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":multijump");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Multi jump");
- return false;
-}
-
-#endif
-#endif
+++ /dev/null
-#ifndef MUTATOR_NADES_H
-#define MUTATOR_NADES_H
-
-.entity nade;
-.entity fake_nade;
-.float nade_timer;
-.float nade_refire;
-.float bonus_nades;
-.float nade_special_time;
-.float bonus_nade_score;
-.float nade_type;
-.string pokenade_type;
-.entity nade_damage_target;
-.float cvar_cl_nade_type;
-.string cvar_cl_pokenade_type;
-.float toss_time;
-.float stat_healing_orb;
-.float stat_healing_orb_alpha;
-.float nade_show_particles;
-
-// Remove nades that are being thrown
-void(entity player) nades_Clear;
-
-// Give a bonus grenade to a player
-void(entity player, float score) nades_GiveBonus;
-// Remove all bonus nades from a player
-void(entity player) nades_RemoveBonus;
-
-#endif
-#ifdef IMPLEMENTATION
-
-#include "../../../common/nades/all.qh"
-#include "../../../common/gamemodes/all.qh"
-#include "../../../common/monsters/spawn.qh"
-#include "../../../common/monsters/sv_monsters.qh"
-#include "../../g_subs.qh"
-
-REGISTER_MUTATOR(nades, cvar("g_nades"))
-{
- MUTATOR_ONADD
- {
- addstat(STAT_NADE_TIMER, AS_FLOAT, nade_timer);
- addstat(STAT_NADE_BONUS, AS_FLOAT, bonus_nades);
- addstat(STAT_NADE_BONUS_TYPE, AS_INT, nade_type);
- addstat(STAT_NADE_BONUS_SCORE, AS_FLOAT, bonus_nade_score);
- addstat(STAT_HEALING_ORB, AS_FLOAT, stat_healing_orb);
- addstat(STAT_HEALING_ORB_ALPHA, AS_FLOAT, stat_healing_orb_alpha);
- }
-
- return false;
-}
-
-.float nade_time_primed;
-
-.entity nade_spawnloc;
-
-void nade_timer_think()
-{SELFPARAM();
- self.skin = 8 - (self.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10);
- self.nextthink = time;
- if(!self.owner || wasfreed(self.owner))
- remove(self);
-}
-
-void nade_burn_spawn(entity _nade)
-{
- CSQCProjectile(_nade, true, Nades[_nade.nade_type].m_projectile[true], true);
-}
-
-void nade_spawn(entity _nade)
-{
- entity timer = spawn();
- setmodel(timer, MDL_NADE_TIMER);
- setattachment(timer, _nade, "");
- timer.classname = "nade_timer";
- timer.colormap = _nade.colormap;
- timer.glowmod = _nade.glowmod;
- timer.think = nade_timer_think;
- timer.nextthink = time;
- timer.wait = _nade.wait;
- timer.owner = _nade;
- timer.skin = 10;
-
- _nade.effects |= EF_LOWPRECISION;
-
- CSQCProjectile(_nade, true, Nades[_nade.nade_type].m_projectile[false], true);
-}
-
-void napalm_damage(float dist, float damage, float edgedamage, float burntime)
-{SELFPARAM();
- entity e;
- float d;
- vector p;
-
- if ( damage < 0 )
- return;
-
- RandomSelection_Init();
- for(e = WarpZone_FindRadius(self.origin, dist, true); e; e = e.chain)
- if(e.takedamage == DAMAGE_AIM)
- if(self.realowner != e || autocvar_g_nades_napalm_selfdamage)
- if(!IS_PLAYER(e) || !self.realowner || DIFF_TEAM(e, self))
- if(!e.frozen)
- {
- p = e.origin;
- p.x += e.mins.x + random() * (e.maxs.x - e.mins.x);
- p.y += e.mins.y + random() * (e.maxs.y - e.mins.y);
- p.z += e.mins.z + random() * (e.maxs.z - e.mins.z);
- d = vlen(WarpZone_UnTransformOrigin(e, self.origin) - p);
- if(d < dist)
- {
- e.fireball_impactvec = p;
- RandomSelection_Add(e, 0, string_null, 1 / (1 + d), !Fire_IsBurning(e));
- }
- }
- if(RandomSelection_chosen_ent)
- {
- d = vlen(WarpZone_UnTransformOrigin(RandomSelection_chosen_ent, self.origin) - RandomSelection_chosen_ent.fireball_impactvec);
- d = damage + (edgedamage - damage) * (d / dist);
- Fire_AddDamage(RandomSelection_chosen_ent, self.realowner, d * burntime, burntime, self.projectiledeathtype | HITTYPE_BOUNCE);
- //trailparticles(self, particleeffectnum(EFFECT_FIREBALL_LASER), self.origin, RandomSelection_chosen_ent.fireball_impactvec);
- Send_Effect(EFFECT_FIREBALL_LASER, self.origin, RandomSelection_chosen_ent.fireball_impactvec - self.origin, 1);
- }
-}
-
-
-void napalm_ball_think()
-{SELFPARAM();
- if(round_handler_IsActive())
- if(!round_handler_IsRoundStarted())
- {
- remove(self);
- return;
- }
-
- if(time > self.pushltime)
- {
- remove(self);
- return;
- }
-
- vector midpoint = ((self.absmin + self.absmax) * 0.5);
- if(pointcontents(midpoint) == CONTENT_WATER)
- {
- self.velocity = self.velocity * 0.5;
-
- if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
- { self.velocity_z = 200; }
- }
-
- self.angles = vectoangles(self.velocity);
-
- napalm_damage(autocvar_g_nades_napalm_ball_radius,autocvar_g_nades_napalm_ball_damage,
- autocvar_g_nades_napalm_ball_damage,autocvar_g_nades_napalm_burntime);
-
- self.nextthink = time + 0.1;
-}
-
-
-void nade_napalm_ball()
-{SELFPARAM();
- entity proj;
- vector kick;
-
- spamsound(self, CH_SHOTS, SND(FIREBALL_FIRE), VOL_BASE, ATTEN_NORM);
-
- proj = spawn ();
- proj.owner = self.owner;
- proj.realowner = self.realowner;
- proj.team = self.owner.team;
- proj.classname = "grenade";
- proj.bot_dodge = true;
- proj.bot_dodgerating = autocvar_g_nades_napalm_ball_damage;
- proj.movetype = MOVETYPE_BOUNCE;
- proj.projectiledeathtype = DEATH_NADE_NAPALM.m_id;
- PROJECTILE_MAKETRIGGER(proj);
- setmodel(proj, MDL_Null);
- proj.scale = 1;//0.5;
- setsize(proj, '-4 -4 -4', '4 4 4');
- setorigin(proj, self.origin);
- proj.think = napalm_ball_think;
- proj.nextthink = time;
- proj.damageforcescale = autocvar_g_nades_napalm_ball_damageforcescale;
- proj.effects = EF_LOWPRECISION | EF_FLAME;
-
- kick.x =(random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread;
- kick.y = (random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread;
- kick.z = (random()/2+0.5) * autocvar_g_nades_napalm_ball_spread;
- proj.velocity = kick;
-
- proj.pushltime = time + autocvar_g_nades_napalm_ball_lifetime;
-
- proj.angles = vectoangles(proj.velocity);
- proj.flags = FL_PROJECTILE;
- proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
-
- //CSQCProjectile(proj, true, PROJECTILE_NAPALM_FIRE, true);
-}
-
-
-void napalm_fountain_think()
-{SELFPARAM();
-
- if(round_handler_IsActive())
- if(!round_handler_IsRoundStarted())
- {
- remove(self);
- return;
- }
-
- if(time >= self.ltime)
- {
- remove(self);
- return;
- }
-
- vector midpoint = ((self.absmin + self.absmax) * 0.5);
- if(pointcontents(midpoint) == CONTENT_WATER)
- {
- self.velocity = self.velocity * 0.5;
-
- if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
- { self.velocity_z = 200; }
-
- UpdateCSQCProjectile(self);
- }
-
- napalm_damage(autocvar_g_nades_napalm_fountain_radius, autocvar_g_nades_napalm_fountain_damage,
- autocvar_g_nades_napalm_fountain_edgedamage, autocvar_g_nades_napalm_burntime);
-
- self.nextthink = time + 0.1;
- if(time >= self.nade_special_time)
- {
- self.nade_special_time = time + autocvar_g_nades_napalm_fountain_delay;
- nade_napalm_ball();
- }
-}
-
-void nade_napalm_boom()
-{SELFPARAM();
- entity fountain;
- int c;
- for (c = 0; c < autocvar_g_nades_napalm_ball_count; c++)
- nade_napalm_ball();
-
-
- fountain = spawn();
- fountain.owner = self.owner;
- fountain.realowner = self.realowner;
- fountain.origin = self.origin;
- setorigin(fountain, fountain.origin);
- fountain.think = napalm_fountain_think;
- fountain.nextthink = time;
- fountain.ltime = time + autocvar_g_nades_napalm_fountain_lifetime;
- fountain.pushltime = fountain.ltime;
- fountain.team = self.team;
- fountain.movetype = MOVETYPE_TOSS;
- fountain.projectiledeathtype = DEATH_NADE_NAPALM.m_id;
- fountain.bot_dodge = true;
- fountain.bot_dodgerating = autocvar_g_nades_napalm_fountain_damage;
- fountain.nade_special_time = time;
- setsize(fountain, '-16 -16 -16', '16 16 16');
- CSQCProjectile(fountain, true, PROJECTILE_NAPALM_FOUNTAIN, true);
-}
-
-void nade_ice_freeze(entity freezefield, entity frost_target, float freeze_time)
-{
- frost_target.frozen_by = freezefield.realowner;
- Send_Effect(EFFECT_ELECTRO_IMPACT, frost_target.origin, '0 0 0', 1);
- Freeze(frost_target, 1/freeze_time, 3, false);
-
- Drop_Special_Items(frost_target);
-}
-
-void nade_ice_think()
-{SELFPARAM();
-
- if(round_handler_IsActive())
- if(!round_handler_IsRoundStarted())
- {
- remove(self);
- return;
- }
-
- if(time >= self.ltime)
- {
- if ( autocvar_g_nades_ice_explode )
- {
- entity expef = EFFECT_NADE_EXPLODE(self.realowner.team);
- Send_Effect(expef, self.origin + '0 0 1', '0 0 0', 1);
- sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-
- RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
- autocvar_g_nades_nade_radius, self, world, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
- Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
- autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
- }
- remove(self);
- return;
- }
-
-
- self.nextthink = time+0.1;
-
- // gaussian
- float randomr;
- randomr = random();
- randomr = exp(-5*randomr*randomr)*autocvar_g_nades_nade_radius;
- float randomw;
- randomw = random()*M_PI*2;
- vector randomp;
- randomp.x = randomr*cos(randomw);
- randomp.y = randomr*sin(randomw);
- randomp.z = 1;
- Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, self.origin + randomp, '0 0 0', 1);
-
- if(time >= self.nade_special_time)
- {
- self.nade_special_time = time+0.7;
-
- Send_Effect(EFFECT_ELECTRO_IMPACT, self.origin, '0 0 0', 1);
- Send_Effect(EFFECT_ICEFIELD, self.origin, '0 0 0', 1);
- }
-
-
- float current_freeze_time = self.ltime - time - 0.1;
-
- entity e;
- for(e = findradius(self.origin, autocvar_g_nades_nade_radius); e; e = e.chain)
- if(e != self)
- if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(e, self.realowner) || e == self.realowner))
- if(e.takedamage && e.deadflag == DEAD_NO)
- if(e.health > 0)
- if(!e.revival_time || ((time - e.revival_time) >= 1.5))
- if(!e.frozen)
- if(current_freeze_time > 0)
- nade_ice_freeze(self, e, current_freeze_time);
-}
-
-void nade_ice_boom()
-{SELFPARAM();
- entity fountain;
- fountain = spawn();
- fountain.owner = self.owner;
- fountain.realowner = self.realowner;
- fountain.origin = self.origin;
- setorigin(fountain, fountain.origin);
- fountain.think = nade_ice_think;
- fountain.nextthink = time;
- fountain.ltime = time + autocvar_g_nades_ice_freeze_time;
- fountain.pushltime = fountain.wait = fountain.ltime;
- fountain.team = self.team;
- fountain.movetype = MOVETYPE_TOSS;
- fountain.projectiledeathtype = DEATH_NADE_ICE.m_id;
- fountain.bot_dodge = false;
- setsize(fountain, '-16 -16 -16', '16 16 16');
- fountain.nade_special_time = time+0.3;
- fountain.angles = self.angles;
-
- if ( autocvar_g_nades_ice_explode )
- {
- setmodel(fountain, MDL_PROJECTILE_GRENADE);
- entity timer = spawn();
- setmodel(timer, MDL_NADE_TIMER);
- setattachment(timer, fountain, "");
- timer.classname = "nade_timer";
- timer.colormap = self.colormap;
- timer.glowmod = self.glowmod;
- timer.think = nade_timer_think;
- timer.nextthink = time;
- timer.wait = fountain.ltime;
- timer.owner = fountain;
- timer.skin = 10;
- }
- else
- setmodel(fountain, MDL_Null);
-}
-
-void nade_translocate_boom()
-{SELFPARAM();
- if(self.realowner.vehicle)
- return;
-
- vector locout = self.origin + '0 0 1' * (1 - self.realowner.mins.z - 24);
- tracebox(locout, self.realowner.mins, self.realowner.maxs, locout, MOVE_NOMONSTERS, self.realowner);
- locout = trace_endpos;
-
- makevectors(self.realowner.angles);
-
- MUTATOR_CALLHOOK(PortalTeleport, self.realowner);
-
- TeleportPlayer(self, self.realowner, locout, self.realowner.angles, v_forward * vlen(self.realowner.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
-}
-
-void nade_spawn_boom()
-{SELFPARAM();
- entity spawnloc = spawn();
- setorigin(spawnloc, self.origin);
- setsize(spawnloc, self.realowner.mins, self.realowner.maxs);
- spawnloc.movetype = MOVETYPE_NONE;
- spawnloc.solid = SOLID_NOT;
- spawnloc.drawonlytoclient = self.realowner;
- spawnloc.effects = EF_STARDUST;
- spawnloc.cnt = autocvar_g_nades_spawn_count;
-
- if(self.realowner.nade_spawnloc)
- {
- remove(self.realowner.nade_spawnloc);
- self.realowner.nade_spawnloc = world;
- }
-
- self.realowner.nade_spawnloc = spawnloc;
-}
-
-void nade_heal_think()
-{SELFPARAM();
- if(time >= self.ltime)
- {
- remove(self);
- return;
- }
-
- self.nextthink = time;
-
- if(time >= self.nade_special_time)
- {
- self.nade_special_time = time+0.25;
- self.nade_show_particles = 1;
- }
- else
- self.nade_show_particles = 0;
-}
-
-void nade_heal_touch()
-{SELFPARAM();
- float maxhealth;
- float health_factor;
- if(IS_PLAYER(other) || IS_MONSTER(other))
- if(other.deadflag == DEAD_NO)
- if(!other.frozen)
- {
- health_factor = autocvar_g_nades_heal_rate*frametime/2;
- if ( other != self.realowner )
- {
- if ( SAME_TEAM(other,self) )
- health_factor *= autocvar_g_nades_heal_friend;
- else
- health_factor *= autocvar_g_nades_heal_foe;
- }
- if ( health_factor > 0 )
- {
- maxhealth = (IS_MONSTER(other)) ? other.max_health : g_pickup_healthmega_max;
- if ( other.health < maxhealth )
- {
- if ( self.nade_show_particles )
- Send_Effect(EFFECT_HEALING, other.origin, '0 0 0', 1);
- other.health = min(other.health+health_factor, maxhealth);
- }
- other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
- }
- else if ( health_factor < 0 )
- {
- Damage(other,self,self.realowner,-health_factor,DEATH_NADE_HEAL.m_id,other.origin,'0 0 0');
- }
-
- }
-
- if ( IS_REAL_CLIENT(other) || IS_VEHICLE(other) )
- {
- entity show_red = (IS_VEHICLE(other)) ? other.owner : other;
- show_red.stat_healing_orb = time+0.1;
- show_red.stat_healing_orb_alpha = 0.75 * (self.ltime - time) / self.healer_lifetime;
- }
-}
-
-void nade_heal_boom()
-{SELFPARAM();
- entity healer;
- healer = spawn();
- healer.owner = self.owner;
- healer.realowner = self.realowner;
- setorigin(healer, self.origin);
- healer.healer_lifetime = autocvar_g_nades_heal_time; // save the cvar
- healer.ltime = time + healer.healer_lifetime;
- healer.team = self.realowner.team;
- healer.bot_dodge = false;
- healer.solid = SOLID_TRIGGER;
- healer.touch = nade_heal_touch;
-
- setmodel(healer, MDL_NADE_HEAL);
- healer.healer_radius = autocvar_g_nades_nade_radius;
- vector size = '1 1 1' * healer.healer_radius / 2;
- setsize(healer,-size,size);
-
- Net_LinkEntity(healer, true, 0, healer_send);
-
- healer.think = nade_heal_think;
- healer.nextthink = time;
- healer.SendFlags |= 1;
-}
-
-void nade_monster_boom()
-{SELFPARAM();
- entity e = spawnmonster(self.pokenade_type, 0, self.realowner, self.realowner, self.origin, false, false, 1);
-
- if(autocvar_g_nades_pokenade_monster_lifetime > 0)
- e.monster_lifetime = time + autocvar_g_nades_pokenade_monster_lifetime;
- e.monster_skill = MONSTER_SKILL_INSANE;
-}
-
-void nade_boom()
-{SELFPARAM();
- entity expef = NULL;
- bool nade_blast = true;
-
- switch ( Nades[self.nade_type] )
- {
- case NADE_TYPE_NAPALM:
- nade_blast = autocvar_g_nades_napalm_blast;
- expef = EFFECT_EXPLOSION_MEDIUM;
- break;
- case NADE_TYPE_ICE:
- nade_blast = false;
- expef = EFFECT_ELECTRO_COMBO; // hookbomb_explode electro_combo bigplasma_impact
- break;
- case NADE_TYPE_TRANSLOCATE:
- nade_blast = false;
- break;
- case NADE_TYPE_MONSTER:
- case NADE_TYPE_SPAWN:
- nade_blast = false;
- switch(self.realowner.team)
- {
- case NUM_TEAM_1: expef = EFFECT_SPAWN_RED; break;
- case NUM_TEAM_2: expef = EFFECT_SPAWN_BLUE; break;
- case NUM_TEAM_3: expef = EFFECT_SPAWN_YELLOW; break;
- case NUM_TEAM_4: expef = EFFECT_SPAWN_PINK; break;
- default: expef = EFFECT_SPAWN_NEUTRAL; break;
- }
- break;
- case NADE_TYPE_HEAL:
- nade_blast = false;
- expef = EFFECT_SPAWN_RED;
- break;
-
- default:
- case NADE_TYPE_NORMAL:
- expef = EFFECT_NADE_EXPLODE(self.realowner.team);
- break;
- }
-
- if(expef)
- Send_Effect(expef, findbetterlocation(self.origin, 8), '0 0 0', 1);
-
- sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
- sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-
- self.event_damage = func_null; // prevent somehow calling damage in the next call
-
- if(nade_blast)
- {
- RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
- autocvar_g_nades_nade_radius, self, world, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
- Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
- }
-
- if(self.takedamage)
- switch ( Nades[self.nade_type] )
- {
- case NADE_TYPE_NAPALM: nade_napalm_boom(); break;
- case NADE_TYPE_ICE: nade_ice_boom(); break;
- case NADE_TYPE_TRANSLOCATE: nade_translocate_boom(); break;
- case NADE_TYPE_SPAWN: nade_spawn_boom(); break;
- case NADE_TYPE_HEAL: nade_heal_boom(); break;
- case NADE_TYPE_MONSTER: nade_monster_boom(); break;
- }
-
- entity head;
- for(head = world; (head = find(head, classname, "grapplinghook")); )
- if(head.aiment == self)
- RemoveGrapplingHook(head.realowner);
-
- remove(self);
-}
-
-void nade_touch()
-{SELFPARAM();
- /*float is_weapclip = 0;
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW)
- if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID))
- if (!(trace_dphitcontents & DPCONTENTS_OPAQUE))
- is_weapclip = 1;*/
- if(ITEM_TOUCH_NEEDKILL()) // || is_weapclip)
- {
- entity head;
- for(head = world; (head = find(head, classname, "grapplinghook")); )
- if(head.aiment == self)
- RemoveGrapplingHook(head.realowner);
- remove(self);
- return;
- }
-
- PROJECTILE_TOUCH;
-
- //setsize(self, '-2 -2 -2', '2 2 2');
- //UpdateCSQCProjectile(self);
- if(self.health == self.max_health)
- {
- spamsound(self, CH_SHOTS, SND(GRENADE_BOUNCE_RANDOM()), VOL_BASE, ATTEN_NORM);
- return;
- }
-
- self.enemy = other;
- nade_boom();
-}
-
-void nade_beep()
-{SELFPARAM();
- sound(self, CH_SHOTS_SINGLE, SND_NADE_BEEP, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
- self.think = nade_boom;
- self.nextthink = max(self.wait, time);
-}
-
-void nade_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
- if(ITEM_DAMAGE_NEEDKILL(deathtype))
- {
- self.takedamage = DAMAGE_NO;
- nade_boom();
- return;
- }
-
- if(self.nade_type == NADE_TYPE_TRANSLOCATE.m_id || self.nade_type == NADE_TYPE_SPAWN.m_id)
- return;
-
- if(DEATH_ISWEAPON(deathtype, WEP_BLASTER))
- {
- force *= 1.5;
- damage = 0;
- }
-
- if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER) && (deathtype & HITTYPE_SECONDARY))
- {
- force *= 0.5; // too much
- frag_damage = 0;
- }
-
- if(DEATH_ISWEAPON(deathtype, WEP_VORTEX) || DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
- {
- force *= 6;
- damage = self.max_health * 0.55;
- }
-
- if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN) || DEATH_ISWEAPON(deathtype, WEP_HMG))
- damage = self.max_health * 0.1;
-
- if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE) || DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) // WEAPONTODO
- if(deathtype & HITTYPE_SECONDARY)
- {
- damage = self.max_health * 0.1;
- force *= 10;
- }
- else
- damage = self.max_health * 1.15;
-
- self.velocity += force;
- UpdateCSQCProjectile(self);
-
- if(damage <= 0 || ((self.flags & FL_ONGROUND) && IS_PLAYER(attacker)))
- return;
-
- if(self.health == self.max_health)
- {
- sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
- self.nextthink = max(time + autocvar_g_nades_nade_lifetime, time);
- self.think = nade_beep;
- }
-
- self.health -= damage;
-
- if ( self.nade_type != NADE_TYPE_HEAL.m_id || IS_PLAYER(attacker) )
- self.realowner = attacker;
-
- if(self.health <= 0)
- W_PrepareExplosionByDamage(attacker, nade_boom);
- else
- nade_burn_spawn(self);
-}
-
-void toss_nade(entity e, vector _velocity, float _time)
-{SELFPARAM();
- if(e.nade == world)
- return;
-
- entity _nade = e.nade;
- e.nade = world;
-
- remove(e.fake_nade);
- e.fake_nade = world;
-
- makevectors(e.v_angle);
-
- W_SetupShot(e, false, false, "", CH_WEAPON_A, 0);
-
- Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_NADES);
-
- vector offset = (v_forward * autocvar_g_nades_throw_offset.x)
- + (v_right * autocvar_g_nades_throw_offset.y)
- + (v_up * autocvar_g_nades_throw_offset.z);
- if(autocvar_g_nades_throw_offset == '0 0 0')
- offset = '0 0 0';
-
- setorigin(_nade, w_shotorg + offset + (v_right * 25) * -1);
- //setmodel(_nade, MDL_PROJECTILE_NADE);
- //setattachment(_nade, world, "");
- PROJECTILE_MAKETRIGGER(_nade);
- setsize(_nade, '-16 -16 -16', '16 16 16');
- _nade.movetype = MOVETYPE_BOUNCE;
-
- tracebox(_nade.origin, _nade.mins, _nade.maxs, _nade.origin, false, _nade);
- if (trace_startsolid)
- setorigin(_nade, e.origin);
-
- if(self.v_angle.x >= 70 && self.v_angle.x <= 110 && self.BUTTON_CROUCH)
- _nade.velocity = '0 0 100';
- else if(autocvar_g_nades_nade_newton_style == 1)
- _nade.velocity = e.velocity + _velocity;
- else if(autocvar_g_nades_nade_newton_style == 2)
- _nade.velocity = _velocity;
- else
- _nade.velocity = W_CalculateProjectileVelocity(e.velocity, _velocity, true);
-
- _nade.touch = nade_touch;
- _nade.health = autocvar_g_nades_nade_health;
- _nade.max_health = _nade.health;
- _nade.takedamage = DAMAGE_AIM;
- _nade.event_damage = nade_damage;
- _nade.customizeentityforclient = func_null;
- _nade.exteriormodeltoclient = world;
- _nade.traileffectnum = 0;
- _nade.teleportable = true;
- _nade.pushable = true;
- _nade.gravity = 1;
- _nade.missile_flags = MIF_SPLASH | MIF_ARC;
- _nade.damagedbycontents = true;
- _nade.angles = vectoangles(_nade.velocity);
- _nade.flags = FL_PROJECTILE;
- _nade.projectiledeathtype = DEATH_NADE.m_id;
- _nade.toss_time = time;
- _nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
-
- if(_nade.nade_type == NADE_TYPE_TRANSLOCATE.m_id || _nade.nade_type == NADE_TYPE_SPAWN.m_id)
- _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
- else
- _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
-
- nade_spawn(_nade);
-
- if(_time)
- {
- _nade.think = nade_boom;
- _nade.nextthink = _time;
- }
-
- e.nade_refire = time + autocvar_g_nades_nade_refire;
- e.nade_timer = 0;
-}
-
-void nades_GiveBonus(entity player, float score)
-{
- if (autocvar_g_nades)
- if (autocvar_g_nades_bonus)
- if (IS_REAL_CLIENT(player))
- if (IS_PLAYER(player) && player.bonus_nades < autocvar_g_nades_bonus_max)
- if (player.frozen == 0)
- if (player.deadflag == DEAD_NO)
- {
- if ( player.bonus_nade_score < 1 )
- player.bonus_nade_score += score/autocvar_g_nades_bonus_score_max;
-
- if ( player.bonus_nade_score >= 1 )
- {
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_BONUS);
- play2(player, SND(KH_ALARM));
- player.bonus_nades++;
- player.bonus_nade_score -= 1;
- }
- }
-}
-
-void nades_RemoveBonus(entity player)
-{
- player.bonus_nades = player.bonus_nade_score = 0;
-}
-
-float nade_customize()
-{SELFPARAM();
- //if(IS_SPEC(other)) { return false; }
- if(other == self.realowner || (IS_SPEC(other) && other.enemy == self.realowner))
- {
- // somewhat hide the model, but keep the glow
- //self.effects = 0;
- if(self.traileffectnum)
- self.traileffectnum = 0;
- self.alpha = -1;
- }
- else
- {
- //self.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
- if(!self.traileffectnum)
- self.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades[self.nade_type].m_projectile[false], self.team).eent_eff_name);
- self.alpha = 1;
- }
-
- return true;
-}
-
-void nade_prime()
-{SELFPARAM();
- if(autocvar_g_nades_bonus_only)
- if(!self.bonus_nades)
- return; // only allow bonus nades
-
- if(self.nade)
- remove(self.nade);
-
- if(self.fake_nade)
- remove(self.fake_nade);
-
- entity n = spawn(), fn = spawn();
-
- n.classname = "nade";
- fn.classname = "fake_nade";
-
- if(self.items & ITEM_Strength.m_itemid && autocvar_g_nades_bonus_onstrength)
- n.nade_type = self.nade_type;
- else if (self.bonus_nades >= 1)
- {
- n.nade_type = self.nade_type;
- n.pokenade_type = self.pokenade_type;
- self.bonus_nades -= 1;
- }
- else
- {
- n.nade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_nade_type : autocvar_g_nades_nade_type);
- n.pokenade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_pokenade_type : autocvar_g_nades_pokenade_monster_type);
- }
-
- n.nade_type = bound(1, n.nade_type, Nades_COUNT);
-
- setmodel(n, MDL_PROJECTILE_NADE);
- //setattachment(n, self, "bip01 l hand");
- n.exteriormodeltoclient = self;
- n.customizeentityforclient = nade_customize;
- n.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades[n.nade_type].m_projectile[false], self.team).eent_eff_name);
- n.colormod = Nades[n.nade_type].m_color;
- n.realowner = self;
- n.colormap = self.colormap;
- n.glowmod = self.glowmod;
- n.wait = time + autocvar_g_nades_nade_lifetime;
- n.nade_time_primed = time;
- n.think = nade_beep;
- n.nextthink = max(n.wait - 3, time);
- n.projectiledeathtype = DEATH_NADE.m_id;
-
- setmodel(fn, MDL_NADE_VIEW);
- setattachment(fn, self.weaponentity, "");
- fn.realowner = fn.owner = self;
- fn.colormod = Nades[n.nade_type].m_color;
- fn.colormap = self.colormap;
- fn.glowmod = self.glowmod;
- fn.think = SUB_Remove;
- fn.nextthink = n.wait;
-
- self.nade = n;
- self.fake_nade = fn;
-}
-
-float CanThrowNade()
-{SELFPARAM();
- if(self.vehicle)
- return false;
-
- if(gameover)
- return false;
-
- if(self.deadflag != DEAD_NO)
- return false;
-
- if (!autocvar_g_nades)
- return false; // allow turning them off mid match
-
- if(forbidWeaponUse(self))
- return false;
-
- if (!IS_PLAYER(self))
- return false;
-
- return true;
-}
-
-.bool nade_altbutton;
-
-void nades_CheckThrow()
-{SELFPARAM();
- if(!CanThrowNade())
- return;
-
- entity held_nade = self.nade;
- if (!held_nade)
- {
- self.nade_altbutton = true;
- if(time > self.nade_refire)
- {
- Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_NADE_THROW);
- nade_prime();
- self.nade_refire = time + autocvar_g_nades_nade_refire;
- }
- }
- else
- {
- self.nade_altbutton = false;
- if (time >= held_nade.nade_time_primed + 1) {
- makevectors(self.v_angle);
- float _force = time - held_nade.nade_time_primed;
- _force /= autocvar_g_nades_nade_lifetime;
- _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
- toss_nade(self, (v_forward * 0.75 + v_up * 0.2 + v_right * 0.05) * _force, 0);
- }
- }
-}
-
-void nades_Clear(entity player)
-{
- if(player.nade)
- remove(player.nade);
- if(player.fake_nade)
- remove(player.fake_nade);
-
- player.nade = player.fake_nade = world;
- player.nade_timer = 0;
-}
-
-MUTATOR_HOOKFUNCTION(nades, VehicleEnter)
-{
- if(vh_player.nade)
- toss_nade(vh_player, '0 0 100', max(vh_player.nade.wait, time + 0.05));
-
- return false;
-}
-
-CLASS(NadeOffhand, OffhandWeapon)
- METHOD(NadeOffhand, offhand_think, void(NadeOffhand this, entity player, bool key_pressed))
- {
- entity held_nade = player.nade;
- if (held_nade)
- {
- player.nade_timer = bound(0, (time - held_nade.nade_time_primed) / autocvar_g_nades_nade_lifetime, 1);
- // LOG_TRACEF("%d %d\n", player.nade_timer, time - held_nade.nade_time_primed);
- makevectors(player.angles);
- held_nade.velocity = player.velocity;
- setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
- held_nade.angles_y = player.angles.y;
-
- if (time + 0.1 >= held_nade.wait)
- toss_nade(player, '0 0 0', time + 0.05);
- }
-
- if (!CanThrowNade()) return;
- if (!(time > player.nade_refire)) return;
- if (key_pressed) {
- if (!held_nade) {
- nade_prime();
- held_nade = player.nade;
- }
- } else if (time >= held_nade.nade_time_primed + 1) {
- if (held_nade) {
- makevectors(player.v_angle);
- float _force = time - held_nade.nade_time_primed;
- _force /= autocvar_g_nades_nade_lifetime;
- _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
- toss_nade(player, (v_forward * 0.7 + v_up * 0.2 + v_right * 0.1) * _force, 0);
- }
- }
- }
-ENDCLASS(NadeOffhand)
-NadeOffhand OFFHAND_NADE; STATIC_INIT(OFFHAND_NADE) { OFFHAND_NADE = NEW(NadeOffhand); }
-
-MUTATOR_HOOKFUNCTION(nades, ForbidThrowCurrentWeapon, CBC_ORDER_LAST)
-{
- if (self.offhand != OFFHAND_NADE || (self.weapons & WEPSET(HOOK)) || autocvar_g_nades_override_dropweapon) {
- nades_CheckThrow();
- return true;
- }
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
-{SELFPARAM();
- if (!IS_PLAYER(self)) { return false; }
-
- if (self.nade && (self.offhand != OFFHAND_NADE || (self.weapons & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, self, self.nade_altbutton);
-
- if(IS_PLAYER(self))
- {
- if ( autocvar_g_nades_bonus && autocvar_g_nades )
- {
- entity key;
- float key_count = 0;
- FOR_EACH_KH_KEY(key) if(key.owner == self) { ++key_count; }
-
- float time_score;
- if(self.flagcarried || self.ballcarried) // this player is important
- time_score = autocvar_g_nades_bonus_score_time_flagcarrier;
- else
- time_score = autocvar_g_nades_bonus_score_time;
-
- if(key_count)
- time_score = autocvar_g_nades_bonus_score_time_flagcarrier * key_count; // multiply by the number of keys the player is holding
-
- if(autocvar_g_nades_bonus_client_select)
- {
- self.nade_type = self.cvar_cl_nade_type;
- self.pokenade_type = self.cvar_cl_pokenade_type;
- }
- else
- {
- self.nade_type = autocvar_g_nades_bonus_type;
- self.pokenade_type = autocvar_g_nades_pokenade_monster_type;
- }
-
- self.nade_type = bound(1, self.nade_type, Nades_COUNT);
-
- if(self.bonus_nade_score >= 0 && autocvar_g_nades_bonus_score_max)
- nades_GiveBonus(self, time_score / autocvar_g_nades_bonus_score_max);
- }
- else
- {
- self.bonus_nades = self.bonus_nade_score = 0;
- }
- }
-
- float n = 0;
- entity o = world;
- if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
- n = -1;
- else
- {
- vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
- n = 0;
- FOR_EACH_PLAYER(other) if(self != other)
- {
- if(other.deadflag == DEAD_NO)
- if(other.frozen == 0)
- if(SAME_TEAM(other, self))
- if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
- {
- if(!o)
- o = other;
- if(self.frozen == 1)
- other.reviving = true;
- ++n;
- }
- }
- }
-
- if(n && self.frozen == 3) // OK, there is at least one teammate reviving us
- {
- self.revive_progress = bound(0, self.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
- self.health = max(1, self.revive_progress * start_health);
-
- if(self.revive_progress >= 1)
- {
- Unfreeze(self);
-
- Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
- Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname);
- }
-
- FOR_EACH_PLAYER(other) if(other.reviving)
- {
- other.revive_progress = self.revive_progress;
- other.reviving = false;
- }
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, PlayerSpawn)
-{SELFPARAM();
- if(autocvar_g_nades_spawn)
- self.nade_refire = time + autocvar_g_spawnshieldtime;
- else
- self.nade_refire = time + autocvar_g_nades_nade_refire;
-
- if(autocvar_g_nades_bonus_client_select)
- self.nade_type = self.cvar_cl_nade_type;
-
- self.nade_timer = 0;
-
- if (!self.offhand) self.offhand = OFFHAND_NADE;
-
- if(self.nade_spawnloc)
- {
- setorigin(self, self.nade_spawnloc.origin);
- self.nade_spawnloc.cnt -= 1;
-
- if(self.nade_spawnloc.cnt <= 0)
- {
- remove(self.nade_spawnloc);
- self.nade_spawnloc = world;
- }
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, PlayerDies, CBC_ORDER_LAST)
-{
- if(frag_target.nade)
- if(!frag_target.frozen || !autocvar_g_freezetag_revive_nade)
- toss_nade(frag_target, '0 0 100', max(frag_target.nade.wait, time + 0.05));
-
- float killcount_bonus = ((frag_attacker.killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * frag_attacker.killcount, autocvar_g_nades_bonus_score_medium) : autocvar_g_nades_bonus_score_minor);
-
- if(IS_PLAYER(frag_attacker))
- {
- if (SAME_TEAM(frag_attacker, frag_target) || frag_attacker == frag_target)
- nades_RemoveBonus(frag_attacker);
- else if(frag_target.flagcarried)
- nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_medium);
- else if(autocvar_g_nades_bonus_score_spree && frag_attacker.killcount > 1)
- {
- #define SPREE_ITEM(counta,countb,center,normal,gentle) \
- case counta: { nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_spree); break; }
- switch(frag_attacker.killcount)
- {
- KILL_SPREE_LIST
- default: nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor); break;
- }
- #undef SPREE_ITEM
- }
- else
- nades_GiveBonus(frag_attacker, killcount_bonus);
- }
-
- nades_RemoveBonus(frag_target);
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, PlayerDamage_Calculate)
-{
- if(frag_target.frozen)
- if(autocvar_g_freezetag_revive_nade)
- if(frag_attacker == frag_target)
- if(frag_deathtype == DEATH_NADE.m_id)
- if(time - frag_inflictor.toss_time <= 0.1)
- {
- Unfreeze(frag_target);
- frag_target.health = autocvar_g_freezetag_revive_nade_health;
- Send_Effect(EFFECT_ICEORGLASS, frag_target.origin, '0 0 0', 3);
- frag_damage = 0;
- frag_force = '0 0 0';
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_NADE, frag_target.netname);
- Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF);
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, MonsterDies)
-{SELFPARAM();
- if(IS_PLAYER(frag_attacker))
- if(DIFF_TEAM(frag_attacker, self))
- if(!(self.spawnflags & MONSTERFLAG_SPAWNED))
- nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor);
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, DropSpecialItems)
-{
- if(frag_target.nade)
- toss_nade(frag_target, '0 0 0', time + 0.05);
-
- return false;
-}
-
-bool nades_RemovePlayer()
-{SELFPARAM();
- nades_Clear(self);
- nades_RemoveBonus(self);
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, MakePlayerObserver) { nades_RemovePlayer(); }
-MUTATOR_HOOKFUNCTION(nades, ClientDisconnect) { nades_RemovePlayer(); }
-MUTATOR_HOOKFUNCTION(nades, reset_map_global) { nades_RemovePlayer(); }
-
-MUTATOR_HOOKFUNCTION(nades, SpectateCopy)
-{SELFPARAM();
- self.nade_timer = other.nade_timer;
- self.nade_type = other.nade_type;
- self.pokenade_type = other.pokenade_type;
- self.bonus_nades = other.bonus_nades;
- self.bonus_nade_score = other.bonus_nade_score;
- self.stat_healing_orb = other.stat_healing_orb;
- self.stat_healing_orb_alpha = other.stat_healing_orb_alpha;
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, GetCvars)
-{
- GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_nade_type, "cl_nade_type");
- GetCvars_handleString(get_cvars_s, get_cvars_f, cvar_cl_pokenade_type, "cl_pokenade_type");
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":Nades");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Nades");
- return false;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-/*
-
-CORE laser vortex lg rl cry gl elec hagar fireb hook
- vaporizer porto
- tuba
-
-NEW rifle hlac minel seeker
-IDEAS OPEN flak OPEN FUN FUN FUN FUN
-
-
-
-How this mutator works:
- =======================
-
-When a gun tries to spawn, this mutator is called. It will provide alternate
-weaponreplace lists.
-
-Entity:
-
-{
-"classname" "weapon_vortex"
-"new_toys" "rifle"
-}
--> This will spawn as Rifle in this mutator ONLY, and as Vortex otherwise.
-
-{
-"classname" "weapon_vortext"
-"new_toys" "vortex rifle"
-}
--> This will spawn as either Vortex or Rifle in this mutator ONLY, and as Vortex otherwise.
-
-{
-"classname" "weapon_vortex"
-"new_toys" "vortex"
-}
--> This is always a Vortex.
-
-If the map specifies no "new_toys" argument
-
-There will be two default replacements selectable: "replace all" and "replace random".
-In "replace all" mode, e.g. Vortex will have the default replacement "rifle".
-In "replace random" mode, Vortex will have the default replacement "vortex rifle".
-
-This mutator's replacements run BEFORE regular weaponreplace!
-
-The New Toys guns do NOT get a spawn function, so they can only ever be spawned
-when this mutator is active.
-
-Likewise, warmup, give all, give ALL and impulse 99 will not give them unless
-this mutator is active.
-
-Outside this mutator, they still can be spawned by:
-- setting their start weapon cvar to 1
-- give weaponname
-- weaponreplace
-- weaponarena (but all and most weapons arena again won't include them)
-
-This mutator performs the default replacements on the DEFAULTS of the
-start weapon selection.
-
-These weapons appear in the menu's priority list, BUT get a suffix
-"(Mutator weapon)".
-
-Picking up a "new toys" weapon will not play standard weapon pickup sound, but
-roflsound "New toys, new toys!" sound.
-
-*/
-
-bool nt_IsNewToy(int w);
-
-REGISTER_MUTATOR(nt, cvar("g_new_toys") && !cvar("g_instagib") && !cvar("g_overkill"))
-{
- MUTATOR_ONADD
- {
- if(time > 1) // game loads at time 1
- error("This cannot be added at runtime\n");
-
- // mark the guns as ok to use by e.g. impulse 99
- for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
- if(nt_IsNewToy(i))
- get_weaponinfo(i).spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
- }
-
- MUTATOR_ONROLLBACK_OR_REMOVE
- {
- for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
- if(nt_IsNewToy(i))
- get_weaponinfo(i).spawnflags |= WEP_FLAG_MUTATORBLOCKED;
- }
-
- MUTATOR_ONREMOVE
- {
- LOG_INFO("This cannot be removed at runtime\n");
- return -1;
- }
-
- return 0;
-}
-
-.string new_toys;
-
-float autocvar_g_new_toys_autoreplace;
-bool autocvar_g_new_toys_use_pickupsound = true;
-const float NT_AUTOREPLACE_NEVER = 0;
-const float NT_AUTOREPLACE_ALWAYS = 1;
-const float NT_AUTOREPLACE_RANDOM = 2;
-
-MUTATOR_HOOKFUNCTION(nt, SetModname)
-{
- modname = "NewToys";
- return 0;
-}
-
-bool nt_IsNewToy(int w)
-{
- switch(w)
- {
- case WEP_SEEKER.m_id:
- case WEP_MINE_LAYER.m_id:
- case WEP_HLAC.m_id:
- case WEP_RIFLE.m_id:
- case WEP_SHOCKWAVE.m_id:
- return true;
- default:
- return false;
- }
-}
-
-string nt_GetFullReplacement(string w)
-{
- switch(w)
- {
- case "hagar": return "seeker";
- case "devastator": return "minelayer";
- case "machinegun": return "hlac";
- case "vortex": return "rifle";
- //case "shotgun": return "shockwave";
- default: return string_null;
- }
-}
-
-string nt_GetReplacement(string w, float m)
-{
- if(m == NT_AUTOREPLACE_NEVER)
- return w;
- string s = nt_GetFullReplacement(w);
- if (!s)
- return w;
- if(m == NT_AUTOREPLACE_RANDOM)
- s = strcat(w, " ", s);
- return s;
-}
-
-MUTATOR_HOOKFUNCTION(nt, SetStartItems)
-{
- // rearrange start_weapon_default
- // apply those bits that are set by start_weapon_defaultmask
- // same for warmup
-
- float i, j, k, n;
-
- WepSet newdefault;
- WepSet warmup_newdefault;
-
- newdefault = '0 0 0';
- warmup_newdefault = '0 0 0';
-
- for(i = WEP_FIRST; i <= WEP_LAST; ++i)
- {
- entity e = get_weaponinfo(i);
- if(!e.weapon)
- continue;
-
- n = tokenize_console(nt_GetReplacement(e.netname, autocvar_g_new_toys_autoreplace));
-
- for(j = 0; j < n; ++j)
- for(k = WEP_FIRST; k <= WEP_LAST; ++k)
- if(get_weaponinfo(k).netname == argv(j))
- {
- if(start_weapons & WepSet_FromWeapon(i))
- newdefault |= WepSet_FromWeapon(k);
- if(warmup_start_weapons & WepSet_FromWeapon(i))
- warmup_newdefault |= WepSet_FromWeapon(k);
- }
- }
-
- newdefault &= start_weapons_defaultmask;
- start_weapons &= ~start_weapons_defaultmask;
- start_weapons |= newdefault;
-
- warmup_newdefault &= warmup_start_weapons_defaultmask;
- warmup_start_weapons &= ~warmup_start_weapons_defaultmask;
- warmup_start_weapons |= warmup_newdefault;
-
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nt, SetWeaponreplace)
-{SELFPARAM();
- // otherwise, we do replace
- if(self.new_toys)
- {
- // map defined replacement:
- ret_string = self.new_toys;
- }
- else
- {
- // auto replacement:
- ret_string = nt_GetReplacement(other.netname, autocvar_g_new_toys_autoreplace);
- }
-
- // apply regular weaponreplace
- ret_string = W_Apply_Weaponreplace(ret_string);
-
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nt, FilterItem)
-{SELFPARAM();
- if(nt_IsNewToy(self.weapon) && autocvar_g_new_toys_use_pickupsound) {
- self.item_pickupsound = string_null;
- self.item_pickupsound_ent = SND_WEAPONPICKUP_NEW_TOYS;
- }
- return 0;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-float g_nix_with_blaster;
-// WEAPONTODO
-int nix_weapon;
-float nix_nextchange;
-float nix_nextweapon;
-.float nix_lastchange_id;
-.float nix_lastinfotime;
-.float nix_nextincr;
-
-bool NIX_CanChooseWeapon(int wpn);
-
-REGISTER_MUTATOR(nix, cvar("g_nix") && !cvar("g_instagib") && !cvar("g_overkill"))
-{
- MUTATOR_ONADD
- {
- g_nix_with_blaster = autocvar_g_nix_with_blaster;
-
- nix_nextchange = 0;
- nix_nextweapon = 0;
-
- for (int i = WEP_FIRST; i <= WEP_LAST; ++i)
- if (NIX_CanChooseWeapon(i)) {
- Weapon w = get_weaponinfo(i);
- w.wr_init(w);
- }
- }
-
- MUTATOR_ONROLLBACK_OR_REMOVE
- {
- // nothing to roll back
- }
-
- MUTATOR_ONREMOVE
- {
- // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
- entity e;
- FOR_EACH_PLAYER(e) if(e.deadflag == DEAD_NO)
- {
- e.ammo_cells = start_ammo_cells;
- e.ammo_plasma = start_ammo_plasma;
- e.ammo_shells = start_ammo_shells;
- e.ammo_nails = start_ammo_nails;
- e.ammo_rockets = start_ammo_rockets;
- e.ammo_fuel = start_ammo_fuel;
- e.weapons = start_weapons;
- if(!client_hasweapon(e, e.weapon, true, false))
- e.switchweapon = w_getbestweapon(self);
- }
- }
-
- return 0;
-}
-
-bool NIX_CanChooseWeapon(int wpn)
-{
- entity e = get_weaponinfo(wpn);
- if(!e.weapon) // skip dummies
- return false;
- if(g_weaponarena)
- {
- if(!(g_weaponarena_weapons & WepSet_FromWeapon(wpn)))
- return false;
- }
- else
- {
- if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
- return false;
- if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
- return false;
- if (!(e.spawnflags & WEP_FLAG_NORMAL))
- return false;
- }
- return true;
-}
-void NIX_ChooseNextWeapon()
-{
- float j;
- RandomSelection_Init();
- for(j = WEP_FIRST; j <= WEP_LAST; ++j)
- if(NIX_CanChooseWeapon(j))
- RandomSelection_Add(world, j, string_null, 1, (j != nix_weapon));
- nix_nextweapon = RandomSelection_chosen_float;
-}
-
-void NIX_GiveCurrentWeapon()
-{SELFPARAM();
- float dt;
-
- if(!nix_nextweapon)
- NIX_ChooseNextWeapon();
-
- dt = ceil(nix_nextchange - time);
-
- if(dt <= 0)
- {
- nix_weapon = nix_nextweapon;
- nix_nextweapon = 0;
- if (!nix_nextchange) // no round played yet?
- nix_nextchange = time; // start the first round now!
- else
- nix_nextchange = time + autocvar_g_balance_nix_roundtime;
- // Weapon w = get_weaponinfo(nix_weapon);
- // w.wr_init(w); // forget it, too slow
- }
-
- // get weapon info
- entity e = get_weaponinfo(nix_weapon);
-
- if(nix_nextchange != self.nix_lastchange_id) // this shall only be called once per round!
- {
- self.ammo_shells = self.ammo_nails = self.ammo_rockets = self.ammo_cells = self.ammo_plasma = self.ammo_fuel = 0;
-
- if(self.items & IT_UNLIMITED_WEAPON_AMMO)
- {
- switch(e.ammo_field)
- {
- case ammo_shells: self.ammo_shells = autocvar_g_pickup_shells_max; break;
- case ammo_nails: self.ammo_nails = autocvar_g_pickup_nails_max; break;
- case ammo_rockets: self.ammo_rockets = autocvar_g_pickup_rockets_max; break;
- case ammo_cells: self.ammo_cells = autocvar_g_pickup_cells_max; break;
- case ammo_plasma: self.ammo_plasma = autocvar_g_pickup_plasma_max; break;
- case ammo_fuel: self.ammo_fuel = autocvar_g_pickup_fuel_max; break;
- }
- }
- else
- {
- switch(e.ammo_field)
- {
- case ammo_shells: self.ammo_shells = autocvar_g_balance_nix_ammo_shells; break;
- case ammo_nails: self.ammo_nails = autocvar_g_balance_nix_ammo_nails; break;
- case ammo_rockets: self.ammo_rockets = autocvar_g_balance_nix_ammo_rockets; break;
- case ammo_cells: self.ammo_cells = autocvar_g_balance_nix_ammo_cells; break;
- case ammo_plasma: self.ammo_plasma = autocvar_g_balance_nix_ammo_plasma; break;
- case ammo_fuel: self.ammo_fuel = autocvar_g_balance_nix_ammo_fuel; break;
- }
- }
-
- self.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
- if(dt >= 1 && dt <= 5)
- self.nix_lastinfotime = -42;
- else
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
-
- Weapon w = get_weaponinfo(nix_weapon);
- w.wr_resetplayer(w);
-
- // all weapons must be fully loaded when we spawn
- if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
- self.(weapon_load[nix_weapon]) = e.reloading_ammo;
-
- // vortex too
- if(WEP_CVAR(vortex, charge))
- {
- if(WEP_CVAR_SEC(vortex, chargepool))
- self.vortex_chargepool_ammo = 1;
- self.vortex_charge = WEP_CVAR(vortex, charge_start);
- }
-
- // set last change info
- self.nix_lastchange_id = nix_nextchange;
- }
- if(self.nix_lastinfotime != dt)
- {
- self.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
- if(dt >= 1 && dt <= 5)
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
- }
-
- if(!(self.items & IT_UNLIMITED_WEAPON_AMMO) && time > self.nix_nextincr)
- {
- switch(e.ammo_field)
- {
- case ammo_shells: self.ammo_shells += autocvar_g_balance_nix_ammoincr_shells; break;
- case ammo_nails: self.ammo_nails += autocvar_g_balance_nix_ammoincr_nails; break;
- case ammo_rockets: self.ammo_rockets += autocvar_g_balance_nix_ammoincr_rockets; break;
- case ammo_cells: self.ammo_cells += autocvar_g_balance_nix_ammoincr_cells; break;
- case ammo_plasma: self.ammo_plasma += autocvar_g_balance_nix_ammoincr_plasma; break;
- case ammo_fuel: self.ammo_fuel += autocvar_g_balance_nix_ammoincr_fuel; break;
- }
-
- self.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
- }
-
- self.weapons = '0 0 0';
- if(g_nix_with_blaster)
- self.weapons |= WEPSET(BLASTER);
- self.weapons |= WepSet_FromWeapon(nix_weapon);
-
- if(self.switchweapon != nix_weapon)
- if(!client_hasweapon(self, self.switchweapon, true, false))
- if(client_hasweapon(self, nix_weapon, true, false))
- W_SwitchWeapon(nix_weapon);
-}
-
-MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
-{
- return 1; // no throwing in NIX
-}
-
-MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":NIX");
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", NIX");
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nix, FilterItem)
-{SELFPARAM();
- switch (self.items)
- {
- case ITEM_HealthSmall.m_itemid:
- case ITEM_HealthMedium.m_itemid:
- case ITEM_HealthLarge.m_itemid:
- case ITEM_HealthMega.m_itemid:
- case ITEM_ArmorSmall.m_itemid:
- case ITEM_ArmorMedium.m_itemid:
- case ITEM_ArmorLarge.m_itemid:
- case ITEM_ArmorMega.m_itemid:
- if (autocvar_g_nix_with_healtharmor)
- return 0;
- break;
- case ITEM_Strength.m_itemid:
- case ITEM_Shield.m_itemid:
- if (autocvar_g_nix_with_powerups)
- return 0;
- break;
- }
-
- return 1; // delete all other items
-}
-
-MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
-{SELFPARAM();
- if(self.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
- return 1;
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
-{SELFPARAM();
- if(!intermission_running)
- if(self.deadflag == DEAD_NO)
- if(IS_PLAYER(self))
- NIX_GiveCurrentWeapon();
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
-{SELFPARAM();
- self.nix_lastchange_id = -1;
- NIX_GiveCurrentWeapon(); // overrides the weapons you got when spawning
- self.items |= IT_UNLIMITED_SUPERWEAPONS;
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
-{
- modname = "NIX";
- return 0;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-.vector ok_deathloc;
-.float ok_spawnsys_timer;
-.float ok_lastwep;
-.float ok_item;
-
-.float ok_notice_time;
-.float ammo_charge[Weapons_MAX];
-.float ok_use_ammocharge;
-.float ok_ammo_charge;
-
-.float ok_pauseregen_finished;
-
-void(entity ent, float wep) ok_DecreaseCharge;
-
-void ok_Initialize();
-
-REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
-{
- MUTATOR_ONADD
- {
- ok_Initialize();
- }
-
- MUTATOR_ONREMOVE
- {
- WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
- WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
- }
-
- return false;
-}
-
-void W_Blaster_Attack(entity, float, float, float, float, float, float, float, float, float, float);
-spawnfunc(weapon_hmg);
-spawnfunc(weapon_rpc);
-
-void ok_DecreaseCharge(entity ent, int wep)
-{
- if(!ent.ok_use_ammocharge) return;
-
- entity wepent = get_weaponinfo(wep);
-
- if(wepent.weapon == 0)
- return; // dummy
-
- ent.ammo_charge[wep] -= max(0, cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
-}
-
-void ok_IncreaseCharge(entity ent, int wep)
-{
- entity wepent = get_weaponinfo(wep);
-
- if(wepent.weapon == 0)
- return; // dummy
-
- if(ent.ok_use_ammocharge)
- if(!ent.BUTTON_ATCK) // not while attacking?
- ent.ammo_charge[wep] = min(autocvar_g_overkill_ammo_charge_limit, ent.ammo_charge[wep] + cvar(sprintf("g_overkill_ammo_charge_rate_%s", wepent.netname)) * frametime / W_TICSPERFRAME);
-}
-
-float ok_CheckWeaponCharge(entity ent, int wep)
-{
- if(!ent.ok_use_ammocharge) return true;
-
- entity wepent = get_weaponinfo(wep);
-
- if(wepent.weapon == 0)
- return 0; // dummy
-
- return (ent.ammo_charge[wep] >= cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDamage_Calculate, CBC_ORDER_LAST)
-{
- if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target))
- if(DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
- {
- frag_damage = 0;
-
- if(frag_attacker != frag_target)
- if(frag_target.health > 0)
- if(frag_target.frozen == 0)
- if(frag_target.deadflag == DEAD_NO)
- {
- Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE);
- frag_force = '0 0 0';
- }
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDamage_SplitHealthArmor)
-{SELFPARAM();
- if(damage_take)
- self.ok_pauseregen_finished = max(self.ok_pauseregen_finished, time + 2);
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDies)
-{SELFPARAM();
- entity targ = ((frag_attacker) ? frag_attacker : frag_target);
-
- if(IS_MONSTER(self))
- {
- remove(other); // remove default item
- other = world;
- }
-
- setself(spawn());
- self.ok_item = true;
- self.noalign = true;
- self.pickup_anyway = true;
- spawnfunc_item_armor_small(this);
- self.movetype = MOVETYPE_TOSS;
- self.gravity = 1;
- self.reset = SUB_Remove;
- setorigin(self, frag_target.origin + '0 0 32');
- self.velocity = '0 0 200' + normalize(targ.origin - self.origin) * 500;
- self.classname = "droppedweapon"; // hax
- SUB_SetFade(self, time + 5, 1);
- setself(this);
-
- self.ok_lastwep = self.switchweapon;
-
- return false;
-}
-MUTATOR_HOOKFUNCTION(ok, MonsterDropItem) { ok_PlayerDies(); }
-
-MUTATOR_HOOKFUNCTION(ok, PlayerRegen)
-{SELFPARAM();
- // overkill's values are different, so use custom regen
- if(!self.frozen)
- {
- self.armorvalue = CalcRotRegen(self.armorvalue, autocvar_g_balance_armor_regenstable, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, 1 * frametime * (time > self.ok_pauseregen_finished), 0, 0, 1, 1 * frametime * (time > self.pauserotarmor_finished), autocvar_g_balance_armor_limit);
- self.health = CalcRotRegen(self.health, autocvar_g_balance_health_regenstable, 0, 100, 1 * frametime * (time > self.ok_pauseregen_finished), 200, 0, autocvar_g_balance_health_rotlinear, 1 * frametime * (time > self.pauserothealth_finished), autocvar_g_balance_health_limit);
-
- float minf, maxf, limitf;
-
- maxf = autocvar_g_balance_fuel_rotstable;
- minf = autocvar_g_balance_fuel_regenstable;
- limitf = autocvar_g_balance_fuel_limit;
-
- self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > self.pauseregen_finished) * ((self.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > self.pauserotfuel_finished), limitf);
- }
- return true; // return true anyway, as frozen uses no regen
-}
-
-MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
-{
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
-{SELFPARAM();
- if(intermission_running || gameover)
- return false;
-
- if(self.deadflag != DEAD_NO || !IS_PLAYER(self) || self.frozen)
- return false;
-
- if(self.ok_lastwep)
- {
- self.switchweapon = self.ok_lastwep;
- self.ok_lastwep = 0;
- }
-
- ok_IncreaseCharge(self, self.weapon);
-
- if(self.BUTTON_ATCK2)
- if(!forbidWeaponUse(self) || self.weapon_blocked) // allow if weapon is blocked
- if(time >= self.jump_interval)
- {
- self.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor();
- makevectors(self.v_angle);
-
- int oldwep = self.weapon;
- self.weapon = WEP_BLASTER.m_id;
- W_Blaster_Attack(
- self,
- WEP_BLASTER.m_id | HITTYPE_SECONDARY,
- WEP_CVAR_SEC(vaporizer, shotangle),
- WEP_CVAR_SEC(vaporizer, damage),
- WEP_CVAR_SEC(vaporizer, edgedamage),
- WEP_CVAR_SEC(vaporizer, radius),
- WEP_CVAR_SEC(vaporizer, force),
- WEP_CVAR_SEC(vaporizer, speed),
- WEP_CVAR_SEC(vaporizer, spread),
- WEP_CVAR_SEC(vaporizer, delay),
- WEP_CVAR_SEC(vaporizer, lifetime)
- );
- self.weapon = oldwep;
- }
-
- self.weapon_blocked = false;
-
- self.ok_ammo_charge = self.ammo_charge[self.weapon];
-
- if(self.ok_use_ammocharge)
- if(!ok_CheckWeaponCharge(self, self.weapon))
- {
- if(autocvar_g_overkill_ammo_charge_notice && time > self.ok_notice_time && self.BUTTON_ATCK && IS_REAL_CLIENT(self) && self.weapon == self.switchweapon)
- {
- //Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_OVERKILL_CHARGE);
- self.ok_notice_time = time + 2;
- play2(self, SND(DRYFIRE));
- }
- Weapon wpn = get_weaponinfo(self.weapon);
- if(self.weaponentity.state != WS_CLEAR)
- w_ready(wpn, self, self.BUTTON_ATCK, self.BUTTON_ATCK2);
-
- self.weapon_blocked = true;
- }
-
- self.BUTTON_ATCK2 = 0;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerSpawn)
-{SELFPARAM();
- if(autocvar_g_overkill_ammo_charge)
- {
- for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
- self.ammo_charge[i] = autocvar_g_overkill_ammo_charge_limit;
-
- self.ok_use_ammocharge = 1;
- self.ok_notice_time = time;
- }
- else
- self.ok_use_ammocharge = 0;
-
- self.ok_pauseregen_finished = time + 2;
-
- return false;
-}
-
-void _spawnfunc_weapon_hmg() { SELFPARAM(); spawnfunc_weapon_hmg(this); }
-void _spawnfunc_weapon_rpc() { SELFPARAM(); spawnfunc_weapon_rpc(this); }
-
-MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
-{SELFPARAM();
- if(autocvar_g_powerups)
- if(autocvar_g_overkill_powerups_replace)
- {
- if(self.classname == "item_strength")
- {
- entity wep = spawn();
- setorigin(wep, self.origin);
- setmodel(wep, MDL_OK_HMG);
- wep.classname = "weapon_hmg";
- wep.ok_item = true;
- wep.noalign = self.noalign;
- wep.cnt = self.cnt;
- wep.team = self.team;
- wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
- wep.pickup_anyway = true;
- wep.think = _spawnfunc_weapon_hmg;
- wep.nextthink = time + 0.1;
- return true;
- }
-
- if(self.classname == "item_invincible")
- {
- entity wep = spawn();
- setorigin(wep, self.origin);
- setmodel(wep, MDL_OK_RPC);
- wep.classname = "weapon_rpc";
- wep.ok_item = true;
- wep.noalign = self.noalign;
- wep.cnt = self.cnt;
- wep.team = self.team;
- wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
- wep.pickup_anyway = true;
- wep.think = _spawnfunc_weapon_rpc;
- wep.nextthink = time + 0.1;
- return true;
- }
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, FilterItem)
-{SELFPARAM();
- if(self.ok_item)
- return false;
-
- switch(self.items)
- {
- case ITEM_HealthMega.m_itemid: return !(autocvar_g_overkill_100h_anyway);
- case ITEM_ArmorMega.m_itemid: return !(autocvar_g_overkill_100a_anyway);
- }
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SpectateCopy)
-{SELFPARAM();
- self.ammo_charge[self.weapon] = other.ammo_charge[other.weapon];
- self.ok_use_ammocharge = other.ok_use_ammocharge;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SetStartItems)
-{
- WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
-
- if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
- if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
-
- start_items |= IT_UNLIMITED_WEAPON_AMMO;
- start_weapons = warmup_start_weapons = ok_start_items;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":OK");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Overkill");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SetModname)
-{
- modname = "Overkill";
- return true;
-}
-
-void ok_SetCvars()
-{
- // hack to force overkill playermodels
- cvar_settemp("sv_defaultcharacter", "1");
- cvar_settemp("sv_defaultplayermodel", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
- cvar_settemp("sv_defaultplayermodel_red", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm");
- cvar_settemp("sv_defaultplayermodel_blue", "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
-}
-
-void ok_Initialize()
-{
- ok_SetCvars();
-
- precache_all_playermodels("models/ok_player/*.dpm");
-
- addstat(STAT_OK_AMMO_CHARGE, AS_FLOAT, ok_use_ammocharge);
- addstat(STAT_OK_AMMO_CHARGEPOOL, AS_FLOAT, ok_ammo_charge);
-
- WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
- WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-
- WEP_SHOTGUN.mdl = "ok_shotgun";
- WEP_MACHINEGUN.mdl = "ok_mg";
- WEP_VORTEX.mdl = "ok_sniper";
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(physical_items, cvar("g_physical_items"))
-{
- // check if we have a physics engine
- MUTATOR_ONADD
- {
- if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
- {
- LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.\n");
- return -1;
- }
- }
-
- MUTATOR_ONROLLBACK_OR_REMOVE
- {
- // nothing to roll back
- }
-
- MUTATOR_ONREMOVE
- {
- LOG_INFO("This cannot be removed at runtime\n");
- return -1;
- }
-
- return 0;
-}
-
-.vector spawn_origin, spawn_angles;
-
-void physical_item_think()
-{SELFPARAM();
- self.nextthink = time;
-
- self.alpha = self.owner.alpha; // apply fading and ghosting
-
- if(!self.cnt) // map item, not dropped
- {
- // copy ghost item properties
- self.colormap = self.owner.colormap;
- self.colormod = self.owner.colormod;
- self.glowmod = self.owner.glowmod;
-
- // if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
- if(autocvar_g_physical_items_reset)
- {
- if(self.owner.wait > time) // awaiting respawn
- {
- setorigin(self, self.spawn_origin);
- self.angles = self.spawn_angles;
- self.solid = SOLID_NOT;
- self.alpha = -1;
- self.movetype = MOVETYPE_NONE;
- }
- else
- {
- self.alpha = 1;
- self.solid = SOLID_CORPSE;
- self.movetype = MOVETYPE_PHYSICS;
- }
- }
- }
-
- if(!self.owner.modelindex)
- remove(self); // the real item is gone, remove this
-}
-
-void physical_item_touch()
-{SELFPARAM();
- if(!self.cnt) // not for dropped items
- if (ITEM_TOUCH_NEEDKILL())
- {
- setorigin(self, self.spawn_origin);
- self.angles = self.spawn_angles;
- }
-}
-
-void physical_item_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
- if(!self.cnt) // not for dropped items
- if(ITEM_DAMAGE_NEEDKILL(deathtype))
- {
- setorigin(self, self.spawn_origin);
- self.angles = self.spawn_angles;
- }
-}
-
-MUTATOR_HOOKFUNCTION(physical_items, Item_Spawn)
-{SELFPARAM();
- if(self.owner == world && autocvar_g_physical_items <= 1)
- return false;
- if (self.spawnflags & 1) // floating item
- return false;
-
- // The actual item can't be physical and trigger at the same time, so make it invisible and use a second entity for physics.
- // Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
- entity wep;
- wep = spawn();
- _setmodel(wep, self.model);
- setsize(wep, self.mins, self.maxs);
- setorigin(wep, self.origin);
- wep.angles = self.angles;
- wep.velocity = self.velocity;
-
- wep.owner = self;
- wep.solid = SOLID_CORPSE;
- wep.movetype = MOVETYPE_PHYSICS;
- wep.takedamage = DAMAGE_AIM;
- wep.effects |= EF_NOMODELFLAGS; // disable the spinning
- wep.colormap = self.owner.colormap;
- wep.glowmod = self.owner.glowmod;
- wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
- wep.dphitcontentsmask = self.dphitcontentsmask;
- wep.cnt = (self.owner != world);
-
- wep.think = physical_item_think;
- wep.nextthink = time;
- wep.touch = physical_item_touch;
- wep.event_damage = physical_item_damage;
-
- if(!wep.cnt)
- {
- // fix the spawn origin
- setorigin(wep, wep.origin + '0 0 1');
- entity oldself;
- oldself = self;
- WITH(entity, self, wep, builtin_droptofloor());
- }
-
- wep.spawn_origin = wep.origin;
- wep.spawn_angles = self.angles;
-
- self.effects |= EF_NODRAW; // hide the original weapon
- self.movetype = MOVETYPE_FOLLOW;
- self.aiment = wep; // attach the original weapon
- self.SendEntity = func_null;
-
- return false;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(pinata, cvar("g_pinata") && !cvar("g_instagib") && !cvar("g_overkill"));
-
-MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
-{SELFPARAM();
- for(int j = WEP_FIRST; j <= WEP_LAST; ++j)
- if(self.weapons & WepSet_FromWeapon(j))
- if(self.switchweapon != j)
- if(W_IsWeaponThrowable(j))
- W_ThrowNewWeapon(self, j, false, self.origin + (self.mins + self.maxs) * 0.5, randomvec() * 175 + '0 0 325');
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":Pinata");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Piñata");
- return false;
-}
-
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-// Random Gravity
-//
-// Mutator by Mario
-// Inspired by Player 2
-
-REGISTER_MUTATOR(random_gravity, cvar("g_random_gravity"))
-{
- MUTATOR_ONADD
- {
- cvar_settemp("sv_gravity", cvar_string("sv_gravity")); // settemp current gravity so it's restored on match end
- }
-
- return false;
-}
-
-float gravity_delay;
-
-MUTATOR_HOOKFUNCTION(random_gravity, SV_StartFrame)
-{
- if(gameover || !cvar("g_random_gravity")) return false;
- if(time < gravity_delay) return false;
- if(time < game_starttime) return false;
- if(round_handler_IsActive() && !round_handler_IsRoundStarted()) return false;
-
- if(random() >= autocvar_g_random_gravity_negative_chance)
- cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() - random() * -autocvar_g_random_gravity_negative, autocvar_g_random_gravity_max)));
- else
- cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() * autocvar_g_random_gravity_positive, autocvar_g_random_gravity_max)));
-
- gravity_delay = time + autocvar_g_random_gravity_delay;
-
- LOG_TRACE("Gravity is now: ", ftos(autocvar_sv_gravity), "\n");
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":RandomGravity");
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Random gravity");
- return 0;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(rocketflying, cvar("g_rocket_flying"));
-
-MUTATOR_HOOKFUNCTION(rocketflying, EditProjectile)
-{
- if(other.classname == "rocket" || other.classname == "mine")
- {
- // kill detonate delay of rockets
- other.spawnshieldtime = time;
- }
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":RocketFlying");
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Rocket Flying");
- return 0;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-#include "../../../common/deathtypes/all.qh"
-#include "../../round_handler.qh"
-
-REGISTER_MUTATOR(rm, cvar("g_instagib"));
-
-MUTATOR_HOOKFUNCTION(rm, PlayerDamage_Calculate)
-{
- // we do it this way, so rm can be toggled during the match
- if(!autocvar_g_rm) { return false; }
-
- if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR))
- if(frag_attacker == frag_target || frag_target.classname == "nade")
- frag_damage = 0;
-
- if(autocvar_g_rm_laser)
- if(DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
- if(frag_attacker == frag_target || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
- frag_damage = 0;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(rm, PlayerDies)
-{
- // we do it this way, so rm can be toggled during the match
- if(!autocvar_g_rm) { return false; }
-
- if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR) || DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
- frag_damage = 1000; // always gib if it was a vaporizer death
-
- return false;
-}
-
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(spawn_near_teammate, cvar("g_spawn_near_teammate") && teamplay);
-
-.entity msnt_lookat;
-
-.float msnt_timer;
-.vector msnt_deathloc;
-
-.float cvar_cl_spawn_near_teammate;
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, Spawn_Score)
-{SELFPARAM();
- if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && self.cvar_cl_spawn_near_teammate))
- return 0;
-
- entity p;
-
- spawn_spot.msnt_lookat = world;
-
- if(!teamplay)
- return 0;
-
- RandomSelection_Init();
- FOR_EACH_PLAYER(p) if(p != self) if(p.team == self.team) if(!p.deadflag)
- {
- float l = vlen(spawn_spot.origin - p.origin);
- if(l > autocvar_g_spawn_near_teammate_distance)
- continue;
- if(l < 48)
- continue;
- if(!checkpvs(spawn_spot.origin, p))
- continue;
- RandomSelection_Add(p, 0, string_null, 1, 1);
- }
-
- if(RandomSelection_chosen_ent)
- {
- spawn_spot.msnt_lookat = RandomSelection_chosen_ent;
- spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_FOUND;
- }
- else if(self.team == spawn_spot.team)
- spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM; // prefer same team, if we can't find a spawn near teammate
-
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
-{SELFPARAM();
- // Note: when entering this, fixangle is already set.
- if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && self.cvar_cl_spawn_near_teammate))
- {
- if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death)
- self.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
-
- entity team_mate, best_mate = world;
- vector best_spot = '0 0 0';
- float pc = 0, best_dist = 0, dist = 0;
- FOR_EACH_PLAYER(team_mate)
- {
- if((autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health >= 0 && team_mate.health >= autocvar_g_balance_health_regenstable) || autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health == 0)
- if(team_mate.deadflag == DEAD_NO)
- if(team_mate.msnt_timer < time)
- if(SAME_TEAM(self, team_mate))
- if(time > team_mate.spawnshieldtime) // spawn shielding
- if(team_mate.frozen == 0)
- if(team_mate != self)
- {
- tracebox(team_mate.origin, PL_MIN, PL_MAX, team_mate.origin - '0 0 100', MOVE_WORLDONLY, team_mate);
- if(trace_fraction != 1.0)
- if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
- {
- pc = pointcontents(trace_endpos + '0 0 1');
- if(pc == CONTENT_EMPTY)
- {
- if(vlen(team_mate.velocity) > 5)
- fixedmakevectors(vectoangles(team_mate.velocity));
- else
- fixedmakevectors(team_mate.angles);
-
- for(pc = 0; pc != 5; ++pc) // test 5 diffrent spots close to mate
- {
- switch(pc)
- {
- case 0:
- tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin + v_right * 128, MOVE_NORMAL, team_mate);
- break;
- case 1:
- tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_right * 128 , MOVE_NORMAL, team_mate);
- break;
- case 2:
- tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin + v_right * 64 - v_forward * 64, MOVE_NORMAL, team_mate);
- break;
- case 3:
- tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_right * 64 - v_forward * 64, MOVE_NORMAL, team_mate);
- break;
- case 4:
- tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_forward * 128, MOVE_NORMAL, team_mate);
- break;
- }
-
- if(trace_fraction == 1.0)
- {
- traceline(trace_endpos + '0 0 4', trace_endpos - '0 0 100', MOVE_NORMAL, team_mate);
- if(trace_fraction != 1.0)
- {
- if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
- {
- dist = vlen(trace_endpos - self.msnt_deathloc);
- if(dist < best_dist || best_dist == 0)
- {
- best_dist = dist;
- best_spot = trace_endpos;
- best_mate = team_mate;
- }
- }
- else
- {
- setorigin(self, trace_endpos);
- self.angles = team_mate.angles;
- self.angles_z = 0; // never spawn tilted even if the spot says to
- team_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
- return 0;
- }
- }
- }
- }
- }
- }
- }
- }
-
- if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
- if(best_dist)
- {
- setorigin(self, best_spot);
- self.angles = best_mate.angles;
- self.angles_z = 0; // never spawn tilted even if the spot says to
- best_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
- }
- }
- else if(spawn_spot.msnt_lookat)
- {
- self.angles = vectoangles(spawn_spot.msnt_lookat.origin - self.origin);
- self.angles_x = -self.angles.x;
- self.angles_z = 0; // never spawn tilted even if the spot says to
- /*
- sprint(self, "You should be looking at ", spawn_spot.msnt_lookat.netname, "^7.\n");
- sprint(self, "distance: ", vtos(spawn_spot.msnt_lookat.origin - self.origin), "\n");
- sprint(self, "angles: ", vtos(self.angles), "\n");
- */
- }
-
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerDies)
-{SELFPARAM();
- self.msnt_deathloc = self.origin;
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, GetCvars)
-{
- GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_spawn_near_teammate, "cl_spawn_near_teammate");
- return false;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(superspec, cvar("g_superspectate"));
-
-#define _SSMAGIX "SUPERSPEC_OPTIONSFILE_V1"
-#define _ISLOCAL ((edict_num(1) == self) ? true : false)
-
-const float ASF_STRENGTH = BIT(0);
-const float ASF_SHIELD = BIT(1);
-const float ASF_MEGA_AR = BIT(2);
-const float ASF_MEGA_HP = BIT(3);
-const float ASF_FLAG_GRAB = BIT(4);
-const float ASF_OBSERVER_ONLY = BIT(5);
-const float ASF_SHOWWHAT = BIT(6);
-const float ASF_SSIM = BIT(7);
-const float ASF_FOLLOWKILLER = BIT(8);
-const float ASF_ALL = 0xFFFFFF;
-.float autospec_flags;
-
-const float SSF_SILENT = 1;
-const float SSF_VERBOSE = 2;
-const float SSF_ITEMMSG = 4;
-.float superspec_flags;
-
-.string superspec_itemfilter; //"classname1 classname2 ..."
-
-bool superspec_Spectate(entity _player)
-{SELFPARAM();
- if(Spectate(_player) == 1)
- self.classname = STR_SPECTATOR;
-
- return true;
-}
-
-void superspec_save_client_conf()
-{SELFPARAM();
- string fn = "superspec-local.options";
- float fh;
-
- if (!_ISLOCAL)
- {
- if(self.crypto_idfp == "")
- return;
-
- fn = sprintf("superspec-%s.options", uri_escape(self.crypto_idfp));
- }
-
- fh = fopen(fn, FILE_WRITE);
- if(fh < 0)
- {
- LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for writing.\n");
- }
- else
- {
- fputs(fh, _SSMAGIX);
- fputs(fh, "\n");
- fputs(fh, ftos(self.autospec_flags));
- fputs(fh, "\n");
- fputs(fh, ftos(self.superspec_flags));
- fputs(fh, "\n");
- fputs(fh, self.superspec_itemfilter);
- fputs(fh, "\n");
- fclose(fh);
- }
-}
-
-void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel)
-{
- sprint(_to, strcat(_con_title, _msg));
-
- if(_to.superspec_flags & SSF_SILENT)
- return;
-
- if(_spamlevel > 1)
- if (!(_to.superspec_flags & SSF_VERBOSE))
- return;
-
- centerprint(_to, strcat(_center_title, _msg));
-}
-
-float superspec_filteritem(entity _for, entity _item)
-{
- float i;
-
- if(_for.superspec_itemfilter == "")
- return true;
-
- if(_for.superspec_itemfilter == "")
- return true;
-
- float l = tokenize_console(_for.superspec_itemfilter);
- for(i = 0; i < l; ++i)
- {
- if(argv(i) == _item.classname)
- return true;
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, ItemTouch)
-{SELFPARAM();
- entity _item = self;
-
- entity e;
- FOR_EACH_SPEC(e)
- {
- setself(e);
- if(self.superspec_flags & SSF_ITEMMSG)
- if(superspec_filteritem(self, _item))
- {
- if(self.superspec_flags & SSF_VERBOSE)
- superspec_msg("", "", self, sprintf("Player %s^7 just picked up ^3%s\n", other.netname, _item.netname), 1);
- else
- superspec_msg("", "", self, sprintf("Player %s^7 just picked up ^3%s\n^8(%s^8)\n", other.netname, _item.netname, _item.classname), 1);
- if((self.autospec_flags & ASF_SSIM) && self.enemy != other)
- {
- superspec_Spectate(other);
-
- setself(this);
- return MUT_ITEMTOUCH_CONTINUE;
- }
- }
-
- if((self.autospec_flags & ASF_SHIELD && _item.invincible_finished) ||
- (self.autospec_flags & ASF_STRENGTH && _item.strength_finished) ||
- (self.autospec_flags & ASF_MEGA_AR && _item.itemdef == ITEM_ArmorMega) ||
- (self.autospec_flags & ASF_MEGA_HP && _item.itemdef == ITEM_HealthMega) ||
- (self.autospec_flags & ASF_FLAG_GRAB && _item.classname == "item_flag_team"))
- {
-
- if((self.enemy != other) || IS_OBSERVER(self))
- {
- if(self.autospec_flags & ASF_OBSERVER_ONLY && !IS_OBSERVER(self))
- {
- if(self.superspec_flags & SSF_VERBOSE)
- superspec_msg("", "", self, sprintf("^8Ignored that ^7%s^8 grabbed %s^8 since the observer_only option is ON\n", other.netname, _item.netname), 2);
- }
- else
- {
- if(self.autospec_flags & ASF_SHOWWHAT)
- superspec_msg("", "", self, sprintf("^7Following %s^7 due to picking up %s\n", other.netname, _item.netname), 2);
-
- superspec_Spectate(other);
- }
- }
- }
- }
-
- setself(this);
-
- return MUT_ITEMTOUCH_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, SV_ParseClientCommand)
-{SELFPARAM();
-#define OPTIONINFO(flag,var,test,text,long,short) \
- var = strcat(var, ((flag & test) ? "^2[ON] ^7" : "^1[OFF] ^7")); \
- var = strcat(var, text," ^7(^3 ", long, "^7 | ^3", short, " ^7)\n")
-
- if(MUTATOR_RETURNVALUE) // command was already handled?
- return false;
-
- if(IS_PLAYER(self))
- return false;
-
- if(cmd_name == "superspec_itemfilter")
- {
- if(argv(1) == "help")
- {
- string _aspeco;
- _aspeco = "^7 superspec_itemfilter ^3\"item_classname1 item_classname2\"^7 only show thise items when ^2superspec ^3item_message^7 is on\n";
- _aspeco = strcat(_aspeco, "^3 clear^7 Remove the filter (show all pickups)\n");
- _aspeco = strcat(_aspeco, "^3 show ^7 Display current filter\n");
- superspec_msg("^3superspec_itemfilter help:\n\n\n", "\n^3superspec_itemfilter help:\n", self, _aspeco, 1);
- }
- else if(argv(1) == "clear")
- {
- if(self.superspec_itemfilter != "")
- strunzone(self.superspec_itemfilter);
-
- self.superspec_itemfilter = "";
- }
- else if(argv(1) == "show" || argv(1) == "")
- {
- if(self.superspec_itemfilter == "")
- {
- superspec_msg("^3superspec_itemfilter^7 is ^1not^7 set", "\n^3superspec_itemfilter^7 is ^1not^7 set\n", self, "", 1);
- return true;
- }
- float i;
- float l = tokenize_console(self.superspec_itemfilter);
- string _msg = "";
- for(i = 0; i < l; ++i)
- _msg = strcat(_msg, "^3#", ftos(i), " ^7", argv(i), "\n");
- //_msg = sprintf("^3#%d^7 %s\n%s", i, _msg, argv(i));
-
- _msg = strcat(_msg,"\n");
-
- superspec_msg("^3superspec_itemfilter is:\n\n\n", "\n^3superspec_itemfilter is:\n", self, _msg, 1);
- }
- else
- {
- if(self.superspec_itemfilter != "")
- strunzone(self.superspec_itemfilter);
-
- self.superspec_itemfilter = strzone(argv(1));
- }
-
- return true;
- }
-
- if(cmd_name == "superspec")
- {
- string _aspeco;
-
- if(cmd_argc > 1)
- {
- float i, _bits = 0, _start = 1;
- if(argv(1) == "help")
- {
- _aspeco = "use cmd superspec [option] [on|off] to set options\n\n";
- _aspeco = strcat(_aspeco, "^3 silent ^7(short^5 si^7) supresses ALL messages from superspectate.\n");
- _aspeco = strcat(_aspeco, "^3 verbose ^7(short^5 ve^7) makes superspectate print some additional information.\n");
- _aspeco = strcat(_aspeco, "^3 item_message ^7(short^5 im^7) makes superspectate print items that were picked up.\n");
- _aspeco = strcat(_aspeco, "^7 Use cmd superspec_itemfilter \"item_class1 item_class2\" to set up a filter of what to show with ^3item_message.\n");
- superspec_msg("^2Available Super Spectate ^3options:\n\n\n", "\n^2Available Super Spectate ^3options:\n", self, _aspeco, 1);
- return true;
- }
-
- if(argv(1) == "clear")
- {
- self.superspec_flags = 0;
- _start = 2;
- }
-
- for(i = _start; i < cmd_argc; ++i)
- {
- if(argv(i) == "on" || argv(i) == "1")
- {
- self.superspec_flags |= _bits;
- _bits = 0;
- }
- else if(argv(i) == "off" || argv(i) == "0")
- {
- if(_start == 1)
- self.superspec_flags &= ~_bits;
-
- _bits = 0;
- }
- else
- {
- if((argv(i) == "silent") || (argv(i) == "si")) _bits |= SSF_SILENT ;
- if((argv(i) == "verbose") || (argv(i) == "ve")) _bits |= SSF_VERBOSE;
- if((argv(i) == "item_message") || (argv(i) == "im")) _bits |= SSF_ITEMMSG;
- }
- }
- }
-
- _aspeco = "";
- OPTIONINFO(self.superspec_flags, _aspeco, SSF_SILENT, "Silent", "silent", "si");
- OPTIONINFO(self.superspec_flags, _aspeco, SSF_VERBOSE, "Verbose", "verbose", "ve");
- OPTIONINFO(self.superspec_flags, _aspeco, SSF_ITEMMSG, "Item pickup messages", "item_message", "im");
-
- superspec_msg("^3Current Super Spectate options are:\n\n\n\n\n", "\n^3Current Super Spectate options are:\n", self, _aspeco, 1);
-
- return true;
- }
-
-/////////////////////
-
- if(cmd_name == "autospec")
- {
- string _aspeco;
- if(cmd_argc > 1)
- {
- if(argv(1) == "help")
- {
- _aspeco = "use cmd autospec [option] [on|off] to set options\n\n";
- _aspeco = strcat(_aspeco, "^3 strength ^7(short^5 st^7) for automatic spectate on strength powerup\n");
- _aspeco = strcat(_aspeco, "^3 shield ^7(short^5 sh^7) for automatic spectate on shield powerup\n");
- _aspeco = strcat(_aspeco, "^3 mega_health ^7(short^5 mh^7) for automatic spectate on mega health\n");
- _aspeco = strcat(_aspeco, "^3 mega_armor ^7(short^5 ma^7) for automatic spectate on mega armor\n");
- _aspeco = strcat(_aspeco, "^3 flag_grab ^7(short^5 fg^7) for automatic spectate on CTF flag grab\n");
- _aspeco = strcat(_aspeco, "^3 observer_only ^7(short^5 oo^7) for automatic spectate only if in observer mode\n");
- _aspeco = strcat(_aspeco, "^3 show_what ^7(short^5 sw^7) to display what event triggered autospectate\n");
- _aspeco = strcat(_aspeco, "^3 item_msg ^7(short^5 im^7) to autospec when item_message in superspectate is triggered\n");
- _aspeco = strcat(_aspeco, "^3 followkiller ^7(short ^5fk^7) to autospec the killer/off\n");
- _aspeco = strcat(_aspeco, "^3 all ^7(short ^5aa^7) to turn everything on/off\n");
- superspec_msg("^2Available Auto Spectate ^3options:\n\n\n", "\n^2Available Auto Spectate ^3options:\n", self, _aspeco, 1);
- return true;
- }
-
- float i, _bits = 0, _start = 1;
- if(argv(1) == "clear")
- {
- self.autospec_flags = 0;
- _start = 2;
- }
-
- for(i = _start; i < cmd_argc; ++i)
- {
- if(argv(i) == "on" || argv(i) == "1")
- {
- self.autospec_flags |= _bits;
- _bits = 0;
- }
- else if(argv(i) == "off" || argv(i) == "0")
- {
- if(_start == 1)
- self.autospec_flags &= ~_bits;
-
- _bits = 0;
- }
- else
- {
- if((argv(i) == "strength") || (argv(i) == "st")) _bits |= ASF_STRENGTH;
- if((argv(i) == "shield") || (argv(i) == "sh")) _bits |= ASF_SHIELD;
- if((argv(i) == "mega_health") || (argv(i) == "mh")) _bits |= ASF_MEGA_HP;
- if((argv(i) == "mega_armor") || (argv(i) == "ma")) _bits |= ASF_MEGA_AR;
- if((argv(i) == "flag_grab") || (argv(i) == "fg")) _bits |= ASF_FLAG_GRAB;
- if((argv(i) == "observer_only") || (argv(i) == "oo")) _bits |= ASF_OBSERVER_ONLY;
- if((argv(i) == "show_what") || (argv(i) == "sw")) _bits |= ASF_SHOWWHAT;
- if((argv(i) == "item_msg") || (argv(i) == "im")) _bits |= ASF_SSIM;
- if((argv(i) == "followkiller") || (argv(i) == "fk")) _bits |= ASF_FOLLOWKILLER;
- if((argv(i) == "all") || (argv(i) == "aa")) _bits |= ASF_ALL;
- }
- }
- }
-
- _aspeco = "";
- OPTIONINFO(self.autospec_flags, _aspeco, ASF_STRENGTH, "Strength", "strength", "st");
- OPTIONINFO(self.autospec_flags, _aspeco, ASF_SHIELD, "Shield", "shield", "sh");
- OPTIONINFO(self.autospec_flags, _aspeco, ASF_MEGA_HP, "Mega Health", "mega_health", "mh");
- OPTIONINFO(self.autospec_flags, _aspeco, ASF_MEGA_AR, "Mega Armor", "mega_armor", "ma");
- OPTIONINFO(self.autospec_flags, _aspeco, ASF_FLAG_GRAB, "Flag grab", "flag_grab","fg");
- OPTIONINFO(self.autospec_flags, _aspeco, ASF_OBSERVER_ONLY, "Only switch if observer", "observer_only", "oo");
- OPTIONINFO(self.autospec_flags, _aspeco, ASF_SHOWWHAT, "Show what item triggered spectate", "show_what", "sw");
- OPTIONINFO(self.autospec_flags, _aspeco, ASF_SSIM, "Switch on superspec item message", "item_msg", "im");
- OPTIONINFO(self.autospec_flags, _aspeco, ASF_FOLLOWKILLER, "Followkiller", "followkiller", "fk");
-
- superspec_msg("^3Current auto spectate options are:\n\n\n\n\n", "\n^3Current auto spectate options are:\n", self, _aspeco, 1);
- return true;
- }
-
- if(cmd_name == "followpowerup")
- {
- entity _player;
- FOR_EACH_PLAYER(_player)
- {
- if(_player.strength_finished > time || _player.invincible_finished > time)
- return superspec_Spectate(_player);
- }
-
- superspec_msg("", "", self, "No active powerup\n", 1);
- return true;
- }
-
- if(cmd_name == "followstrength")
- {
- entity _player;
- FOR_EACH_PLAYER(_player)
- {
- if(_player.strength_finished > time)
- return superspec_Spectate(_player);
- }
-
- superspec_msg("", "", self, "No active Strength\n", 1);
- return true;
- }
-
- if(cmd_name == "followshield")
- {
- entity _player;
- FOR_EACH_PLAYER(_player)
- {
- if(_player.invincible_finished > time)
- return superspec_Spectate(_player);
- }
-
- superspec_msg("", "", self, "No active Shield\n", 1);
- return true;
- }
-
- return false;
-#undef OPTIONINFO
-}
-
-MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":SS");
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Super Spectators");
- return 0;
-}
-
-void superspec_hello()
-{SELFPARAM();
- if(self.enemy.crypto_idfp == "")
- Send_Notification(NOTIF_ONE_ONLY, self.enemy, MSG_INFO, INFO_SUPERSPEC_MISSING_UID);
-
- remove(self);
-}
-
-MUTATOR_HOOKFUNCTION(superspec, ClientConnect)
-{SELFPARAM();
- if(!IS_REAL_CLIENT(self))
- return false;
-
- string fn = "superspec-local.options";
- float fh;
-
- self.superspec_flags = SSF_VERBOSE;
- self.superspec_itemfilter = "";
-
- entity _hello = spawn();
- _hello.enemy = self;
- _hello.think = superspec_hello;
- _hello.nextthink = time + 5;
-
- if (!_ISLOCAL)
- {
- if(self.crypto_idfp == "")
- return false;
-
- fn = sprintf("superspec-%s.options", uri_escape(self.crypto_idfp));
- }
-
- fh = fopen(fn, FILE_READ);
- if(fh < 0)
- {
- LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for reading.\n");
- }
- else
- {
- string _magic = fgets(fh);
- if(_magic != _SSMAGIX)
- {
- LOG_TRACE("^1ERROR^7 While reading superspec options file: unknown magic\n");
- }
- else
- {
- self.autospec_flags = stof(fgets(fh));
- self.superspec_flags = stof(fgets(fh));
- self.superspec_itemfilter = strzone(fgets(fh));
- }
- fclose(fh);
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, PlayerDies)
-{SELFPARAM();
- entity e;
- FOR_EACH_SPEC(e)
- {
- setself(e);
- if(self.autospec_flags & ASF_FOLLOWKILLER && IS_PLAYER(frag_attacker) && self.enemy == this)
- {
- if(self.autospec_flags & ASF_SHOWWHAT)
- superspec_msg("", "", self, sprintf("^7Following %s^7 due to followkiller\n", frag_attacker.netname), 2);
-
- superspec_Spectate(frag_attacker);
- }
- }
-
- setself(this);
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, ClientDisconnect)
-{
- superspec_save_client_conf();
- return false;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(touchexplode, cvar("g_touchexplode"));
-
-.float touchexplode_time;
-
-void PlayerTouchExplode(entity p1, entity p2)
-{SELFPARAM();
- vector org = (p1.origin + p2.origin) * 0.5;
- org.z += (p1.mins.z + p2.mins.z) * 0.5;
-
- sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
- Send_Effect(EFFECT_EXPLOSION_SMALL, org, '0 0 0', 1);
-
- entity e = spawn();
- setorigin(e, org);
- RadiusDamage(e, world, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, world, world, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE.m_id, world);
- remove(e);
-}
-
-MUTATOR_HOOKFUNCTION(touchexplode, PlayerPreThink)
-{SELFPARAM();
- if(time > self.touchexplode_time)
- if(!gameover)
- if(!self.frozen)
- if(IS_PLAYER(self))
- if(self.deadflag == DEAD_NO)
- if (!IS_INDEPENDENT_PLAYER(self))
- FOR_EACH_PLAYER(other) if(self != other)
- {
- if(time > other.touchexplode_time)
- if(!other.frozen)
- if(other.deadflag == DEAD_NO)
- if (!IS_INDEPENDENT_PLAYER(other))
- if(boxesoverlap(self.absmin, self.absmax, other.absmin, other.absmax))
- {
- PlayerTouchExplode(self, other);
- self.touchexplode_time = other.touchexplode_time = time + 0.2;
- }
- }
-
- return false;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(vampire, cvar("g_vampire") && !cvar("g_instagib"));
-
-MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
-{
- if(time >= frag_target.spawnshieldtime)
- if(frag_target != frag_attacker)
- if(frag_target.deadflag == DEAD_NO)
- {
- frag_attacker.health += bound(0, damage_take, frag_target.health);
- frag_attacker.health = bound(0, frag_attacker.health, autocvar_g_balance_health_limit);
- }
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":Vampire");
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Vampire");
- return 0;
-}
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(vh, cvar("g_vampirehook"));
-
-bool autocvar_g_vampirehook_teamheal;
-float autocvar_g_vampirehook_damage;
-float autocvar_g_vampirehook_damagerate;
-float autocvar_g_vampirehook_health_steal;
-
-.float last_dmg;
-
-MUTATOR_HOOKFUNCTION(vh, GrappleHookThink)
-{SELFPARAM();
- entity dmgent = ((SAME_TEAM(self.owner, self.aiment) && autocvar_g_vampirehook_teamheal) ? self.owner : self.aiment);
-
- if(IS_PLAYER(self.aiment))
- if(self.last_dmg < time)
- if(!self.aiment.frozen)
- if(time >= game_starttime)
- if(DIFF_TEAM(self.owner, self.aiment) || autocvar_g_vampirehook_teamheal)
- if(self.aiment.health > 0)
- if(autocvar_g_vampirehook_damage)
- {
- self.last_dmg = time + autocvar_g_vampirehook_damagerate;
- self.owner.damage_dealt += autocvar_g_vampirehook_damage;
- Damage(dmgent, self, self.owner, autocvar_g_vampirehook_damage, WEP_HOOK.m_id, self.origin, '0 0 0');
- if(SAME_TEAM(self.owner, self.aiment))
- self.aiment.health = min(self.aiment.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
- else
- self.owner.health = min(self.owner.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
-
- if(dmgent == self.owner)
- dmgent.health -= autocvar_g_vampirehook_damage; // FIXME: friendly fire?!
- }
-
- return false;
-}
-
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-// WEAPONTODO: rename the cvars
-REGISTER_MUTATOR(weaponarena_random, true);
-
-MUTATOR_HOOKFUNCTION(weaponarena_random, PlayerSpawn) {
- SELFPARAM();
- if (!g_weaponarena_random) return;
- if (g_weaponarena_random_with_blaster) this.weapons &= ~WEPSET(BLASTER);
- W_RandomWeapons(this, g_weaponarena_random);
- if (g_weaponarena_random_with_blaster) this.weapons |= WEPSET(BLASTER);
-}
-
-#endif
+++ /dev/null
-#ifdef IMPLEMENTATION
-float autosave_time;
-void sandbox_Database_Load();
-
-REGISTER_MUTATOR(sandbox, cvar("g_sandbox"))
-{
- MUTATOR_ONADD
- {
- autosave_time = time + autocvar_g_sandbox_storage_autosave; // don't save the first server frame
- if(autocvar_g_sandbox_storage_autoload)
- sandbox_Database_Load();
- }
-
- MUTATOR_ONROLLBACK_OR_REMOVE
- {
- // nothing to roll back
- }
-
- MUTATOR_ONREMOVE
- {
- // nothing to remove
- }
-
- return false;
-}
-
-const float MAX_STORAGE_ATTACHMENTS = 16;
-float object_count;
-.float object_flood;
-.entity object_attach;
-.string material;
-
-.float touch_timer;
-void sandbox_ObjectFunction_Touch()
-{SELFPARAM();
- // apply material impact effects
-
- if(!self.material)
- return;
- if(self.touch_timer > time)
- return; // don't execute each frame
- self.touch_timer = time + 0.1;
-
- // make particle count and sound volume depend on impact speed
- float intensity;
- intensity = vlen(self.velocity) + vlen(other.velocity);
- if(intensity) // avoid divisions by 0
- intensity /= 2; // average the two velocities
- if (!(intensity >= autocvar_g_sandbox_object_material_velocity_min))
- return; // impact not strong enough to do anything
- // now offset intensity and apply it to the effects
- intensity -= autocvar_g_sandbox_object_material_velocity_min; // start from minimum velocity, not actual velocity
- intensity = bound(0, intensity * autocvar_g_sandbox_object_material_velocity_factor, 1);
-
- _sound(self, CH_TRIGGER, strcat("object/impact_", self.material, "_", ftos(ceil(random() * 5)) , ".wav"), VOL_BASE * intensity, ATTEN_NORM);
- Send_Effect_(strcat("impact_", self.material), self.origin, '0 0 0', ceil(intensity * 10)); // allow a count from 1 to 10
-}
-
-void sandbox_ObjectFunction_Think()
-{SELFPARAM();
- entity e;
-
- // decide if and how this object can be grabbed
- if(autocvar_g_sandbox_readonly)
- self.grab = 0; // no grabbing
- else if(autocvar_g_sandbox_editor_free < 2 && self.crypto_idfp)
- self.grab = 1; // owner only
- else
- self.grab = 3; // anyone
-
- // Object owner is stored via player UID, but we also need the owner as an entity (if the player is available on the server).
- // Therefore, scan for all players, and update the owner as long as the player is present. We must always do this,
- // since if the owning player disconnects, the object's owner should also be reset.
- FOR_EACH_REALPLAYER(e) // bots can't have objects
- {
- if(self.crypto_idfp == e.crypto_idfp)
- {
- self.realowner = e;
- break;
- }
- self.realowner = world;
- }
-
- self.nextthink = time;
-
- CSQCMODEL_AUTOUPDATE(self);
-}
-
-.float old_solid, old_movetype;
-entity sandbox_ObjectEdit_Get(float permissions)
-{SELFPARAM();
- // Returns the traced entity if the player can edit it, and world if not.
- // If permissions if false, the object is returned regardless of editing rights.
- // Attached objects are SOLID_NOT and do not get traced.
-
- crosshair_trace_plusvisibletriggers(self);
- if(vlen(self.origin - trace_ent.origin) > autocvar_g_sandbox_editor_distance_edit)
- return world; // out of trace range
- if(trace_ent.classname != "object")
- return world; // entity is not an object
- if(!permissions)
- return trace_ent; // don't check permissions, anyone can edit this object
- if(trace_ent.crypto_idfp == "")
- return trace_ent; // the player who spawned this object did not have an UID, so anyone can edit it
- if (!(trace_ent.realowner != self && autocvar_g_sandbox_editor_free < 2))
- return trace_ent; // object does not belong to the player, and players can only edit their own objects on this server
- return world;
-}
-
-void sandbox_ObjectEdit_Scale(entity e, float f)
-{
- e.scale = f;
- if(e.scale)
- {
- e.scale = bound(autocvar_g_sandbox_object_scale_min, e.scale, autocvar_g_sandbox_object_scale_max);
- _setmodel(e, e.model); // reset mins and maxs based on mesh
- setsize(e, e.mins * e.scale, e.maxs * e.scale); // adapt bounding box size to model size
- }
-}
-
-void sandbox_ObjectAttach_Remove(entity e);
-void sandbox_ObjectAttach_Set(entity e, entity parent, string s)
-{
- // attaches e to parent on string s
-
- // we can't attach to an attachment, for obvious reasons
- sandbox_ObjectAttach_Remove(e);
-
- e.old_solid = e.solid; // persist solidity
- e.old_movetype = e.movetype; // persist physics
- e.movetype = MOVETYPE_FOLLOW;
- e.solid = SOLID_NOT;
- e.takedamage = DAMAGE_NO;
-
- setattachment(e, parent, s);
- e.owner = parent;
-}
-
-void sandbox_ObjectAttach_Remove(entity e)
-{
- // detaches any object attached to e
-
- entity head;
- for(head = world; (head = find(head, classname, "object")); )
- {
- if(head.owner == e)
- {
- vector org;
- org = gettaginfo(head, 0);
- setattachment(head, world, "");
- head.owner = world;
-
- // objects change origin and angles when detached, so apply previous position
- setorigin(head, org);
- head.angles = e.angles; // don't allow detached objects to spin or roll
-
- head.solid = head.old_solid; // restore persisted solidity
- head.movetype = head.old_movetype; // restore persisted physics
- head.takedamage = DAMAGE_AIM;
- }
- }
-}
-
-entity sandbox_ObjectSpawn(float database)
-{SELFPARAM();
- // spawn a new object with default properties
-
- entity e = spawn();
- e.classname = "object";
- e.takedamage = DAMAGE_AIM;
- e.damageforcescale = 1;
- e.solid = SOLID_BBOX; // SOLID_BSP would be best, but can lag the server badly
- e.movetype = MOVETYPE_TOSS;
- e.frame = 0;
- e.skin = 0;
- e.material = string_null;
- e.touch = sandbox_ObjectFunction_Touch;
- e.think = sandbox_ObjectFunction_Think;
- e.nextthink = time;
- //e.effects |= EF_SELECTABLE; // don't do this all the time, maybe just when editing objects?
-
- if(!database)
- {
- // set the object's owner via player UID
- // if the player does not have an UID, the owner cannot be stored and his objects may be edited by anyone
- if(self.crypto_idfp != "")
- e.crypto_idfp = strzone(self.crypto_idfp);
- else
- print_to(self, "^1SANDBOX - WARNING: ^7You spawned an object, but lack a player UID. ^1Your objects are not secured and can be edited by any player!");
-
- // set public object information
- e.netname = strzone(self.netname); // name of the owner
- e.message = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // creation time
- e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // last editing time
-
- // set origin and direction based on player position and view angle
- makevectors(self.v_angle);
- WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * autocvar_g_sandbox_editor_distance_spawn, MOVE_NORMAL, self);
- setorigin(e, trace_endpos);
- e.angles_y = self.v_angle.y;
- }
-
- WITH(entity, self, e, CSQCMODEL_AUTOINIT(e));
-
- object_count += 1;
- return e;
-}
-
-void sandbox_ObjectRemove(entity e)
-{
- sandbox_ObjectAttach_Remove(e); // detach child objects
-
- // if the object being removed has been selected for attachment by a player, unset it
- entity head;
- FOR_EACH_REALPLAYER(head) // bots can't have objects
- {
- if(head.object_attach == e)
- head.object_attach = world;
- }
-
- if(e.material) { strunzone(e.material); e.material = string_null; }
- if(e.crypto_idfp) { strunzone(e.crypto_idfp); e.crypto_idfp = string_null; }
- if(e.netname) { strunzone(e.netname); e.netname = string_null; }
- if(e.message) { strunzone(e.message); e.message = string_null; }
- if(e.message2) { strunzone(e.message2); e.message2 = string_null; }
- remove(e);
- e = world;
-
- object_count -= 1;
-}
-
-string port_string[MAX_STORAGE_ATTACHMENTS]; // fteqcc crashes if this isn't defined as a global
-
-string sandbox_ObjectPort_Save(entity e, float database)
-{
- // save object properties, and return them as a string
- float i = 0;
- string s;
- entity head;
-
- for(head = world; (head = find(head, classname, "object")); )
- {
- // the main object needs to be first in the array [0] with attached objects following
- float slot, physics, solidity;
- if(head == e) // this is the main object, place it first
- {
- slot = 0;
- solidity = head.solid; // applied solidity is normal solidity for children
- physics = head.movetype; // applied physics are normal physics for parents
- }
- else if(head.owner == e) // child object, list them in order
- {
- i += 1; // children start from 1
- slot = i;
- solidity = head.old_solid; // persisted solidity is normal solidity for children
- physics = head.old_movetype; // persisted physics are normal physics for children
- gettaginfo(head.owner, head.tag_index); // get the name of the tag our object is attached to, used further below
- }
- else
- continue;
-
- // ---------------- OBJECT PROPERTY STORAGE: SAVE ----------------
- if(slot)
- {
- // properties stored only for child objects
- if(gettaginfo_name) port_string[slot] = strcat(port_string[slot], "\"", gettaginfo_name, "\" "); else port_string[slot] = strcat(port_string[slot], "\"\" "); // none
- }
- else
- {
- // properties stored only for parent objects
- if(database)
- {
- port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.origin), " ");
- port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.angles), " ");
- }
- }
- // properties stored for all objects
- port_string[slot] = strcat(port_string[slot], "\"", head.model, "\" ");
- port_string[slot] = strcat(port_string[slot], ftos(head.skin), " ");
- port_string[slot] = strcat(port_string[slot], ftos(head.alpha), " ");
- port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.colormod), " ");
- port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.glowmod), " ");
- port_string[slot] = strcat(port_string[slot], ftos(head.frame), " ");
- port_string[slot] = strcat(port_string[slot], ftos(head.scale), " ");
- port_string[slot] = strcat(port_string[slot], ftos(solidity), " ");
- port_string[slot] = strcat(port_string[slot], ftos(physics), " ");
- port_string[slot] = strcat(port_string[slot], ftos(head.damageforcescale), " ");
- if(head.material) port_string[slot] = strcat(port_string[slot], "\"", head.material, "\" "); else port_string[slot] = strcat(port_string[slot], "\"\" "); // none
- if(database)
- {
- // properties stored only for the database
- if(head.crypto_idfp) port_string[slot] = strcat(port_string[slot], "\"", head.crypto_idfp, "\" "); else port_string[slot] = strcat(port_string[slot], "\"\" "); // none
- port_string[slot] = strcat(port_string[slot], "\"", e.netname, "\" ");
- port_string[slot] = strcat(port_string[slot], "\"", e.message, "\" ");
- port_string[slot] = strcat(port_string[slot], "\"", e.message2, "\" ");
- }
- }
-
- // now apply the array to a simple string, with the ; symbol separating objects
- s = "";
- for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
- {
- if(port_string[i])
- s = strcat(s, port_string[i], "; ");
- port_string[i] = string_null; // fully clear the string
- }
-
- return s;
-}
-
-entity sandbox_ObjectPort_Load(string s, float database)
-{
- // load object properties, and spawn a new object with them
- float n, i;
- entity e = world, parent = world;
-
- // separate objects between the ; symbols
- n = tokenizebyseparator(s, "; ");
- for(i = 0; i < n; ++i)
- port_string[i] = argv(i);
-
- // now separate and apply the properties of each object
- for(i = 0; i < n; ++i)
- {
- float argv_num;
- string tagname = string_null;
- argv_num = 0;
- tokenize_console(port_string[i]);
- e = sandbox_ObjectSpawn(database);
-
- // ---------------- OBJECT PROPERTY STORAGE: LOAD ----------------
- if(i)
- {
- // properties stored only for child objects
- if(argv(argv_num) != "") tagname = argv(argv_num); else tagname = string_null; ++argv_num;
- }
- else
- {
- // properties stored only for parent objects
- if(database)
- {
- setorigin(e, stov(argv(argv_num))); ++argv_num;
- e.angles = stov(argv(argv_num)); ++argv_num;
- }
- parent = e; // mark parent objects as such
- }
- // properties stored for all objects
- _setmodel(e, argv(argv_num)); ++argv_num;
- e.skin = stof(argv(argv_num)); ++argv_num;
- e.alpha = stof(argv(argv_num)); ++argv_num;
- e.colormod = stov(argv(argv_num)); ++argv_num;
- e.glowmod = stov(argv(argv_num)); ++argv_num;
- e.frame = stof(argv(argv_num)); ++argv_num;
- sandbox_ObjectEdit_Scale(e, stof(argv(argv_num))); ++argv_num;
- e.solid = e.old_solid = stof(argv(argv_num)); ++argv_num;
- e.movetype = e.old_movetype = stof(argv(argv_num)); ++argv_num;
- e.damageforcescale = stof(argv(argv_num)); ++argv_num;
- if(e.material) strunzone(e.material); if(argv(argv_num) != "") e.material = strzone(argv(argv_num)); else e.material = string_null; ++argv_num;
- if(database)
- {
- // properties stored only for the database
- if(e.crypto_idfp) strunzone(e.crypto_idfp); if(argv(argv_num) != "") e.crypto_idfp = strzone(argv(argv_num)); else e.crypto_idfp = string_null; ++argv_num;
- if(e.netname) strunzone(e.netname); e.netname = strzone(argv(argv_num)); ++argv_num;
- if(e.message) strunzone(e.message); e.message = strzone(argv(argv_num)); ++argv_num;
- if(e.message2) strunzone(e.message2); e.message2 = strzone(argv(argv_num)); ++argv_num;
- }
-
- // attach last
- if(i)
- sandbox_ObjectAttach_Set(e, parent, tagname);
- }
-
- for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
- port_string[i] = string_null; // fully clear the string
-
- return e;
-}
-
-void sandbox_Database_Save()
-{
- // saves all objects to the database file
- entity head;
- string file_name;
- float file_get;
-
- file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
- file_get = fopen(file_name, FILE_WRITE);
- fputs(file_get, strcat("// sandbox storage \"", autocvar_g_sandbox_storage_name, "\" for map \"", GetMapname(), "\" last updated ", strftime(true, "%d-%m-%Y %H:%M:%S")));
- fputs(file_get, strcat(" containing ", ftos(object_count), " objects\n"));
-
- for(head = world; (head = find(head, classname, "object")); )
- {
- // attached objects are persisted separately, ignore them here
- if(head.owner != world)
- continue;
-
- // use a line of text for each object, listing all properties
- fputs(file_get, strcat(sandbox_ObjectPort_Save(head, true), "\n"));
- }
- fclose(file_get);
-}
-
-void sandbox_Database_Load()
-{
- // loads all objects from the database file
- string file_read, file_name;
- float file_get, i;
-
- file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
- file_get = fopen(file_name, FILE_READ);
- if(file_get < 0)
- {
- if(autocvar_g_sandbox_info > 0)
- LOG_INFO(strcat("^3SANDBOX - SERVER: ^7could not find storage file ^3", file_name, "^7, no objects were loaded\n"));
- }
- else
- {
- for (;;)
- {
- file_read = fgets(file_get);
- if(file_read == "")
- break;
- if(substring(file_read, 0, 2) == "//")
- continue;
- if(substring(file_read, 0, 1) == "#")
- continue;
-
- entity e;
- e = sandbox_ObjectPort_Load(file_read, true);
-
- if(e.material)
- {
- // since objects are being loaded for the first time, precache material sounds for each
- for (i = 1; i <= 5; i++) // 5 sounds in total
- precache_sound(strcat("object/impact_", e.material, "_", ftos(i), ".wav"));
- }
- }
- if(autocvar_g_sandbox_info > 0)
- LOG_INFO(strcat("^3SANDBOX - SERVER: ^7successfully loaded storage file ^3", file_name, "\n"));
- }
- fclose(file_get);
-}
-
-MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
-{SELFPARAM();
- if(MUTATOR_RETURNVALUE) // command was already handled?
- return false;
- if(cmd_name == "g_sandbox")
- {
- if(autocvar_g_sandbox_readonly)
- {
- print_to(self, "^2SANDBOX - INFO: ^7Sandbox mode is active, but in read-only mode. Sandbox commands cannot be used");
- return true;
- }
- if(cmd_argc < 2)
- {
- print_to(self, "^2SANDBOX - INFO: ^7Sandbox mode is active. For usage information, type 'sandbox help'");
- return true;
- }
-
- switch(argv(1))
- {
- entity e;
- float i;
- string s;
-
- // ---------------- COMMAND: HELP ----------------
- case "help":
- print_to(self, "You can use the following sandbox commands:");
- print_to(self, "^7\"^2object_spawn ^3models/foo/bar.md3^7\" spawns a new object in front of the player, and gives it the specified model");
- print_to(self, "^7\"^2object_remove^7\" removes the object the player is looking at. Players can only remove their own objects");
- print_to(self, "^7\"^2object_duplicate ^3value^7\" duplicates the object, if the player has copying rights over the original");
- print_to(self, "^3copy value ^7- copies the properties of the object to the specified client cvar");
- print_to(self, "^3paste value ^7- spawns an object with the given properties. Properties or cvars must be specified as follows; eg1: \"0 1 2 ...\", eg2: \"$cl_cvar\"");
- print_to(self, "^7\"^2object_attach ^3property value^7\" attaches one object to another. Players can only attach their own objects");
- print_to(self, "^3get ^7- selects the object you are facing as the object to be attached");
- print_to(self, "^3set value ^7- attaches the previously selected object to the object you are facing, on the specified bone");
- print_to(self, "^3remove ^7- detaches all objects from the object you are facing");
- print_to(self, "^7\"^2object_edit ^3property value^7\" edits the given property of the object. Players can only edit their own objects");
- print_to(self, "^3skin value ^7- changes the skin of the object");
- print_to(self, "^3alpha value ^7- sets object transparency");
- print_to(self, "^3colormod \"value_x value_y value_z\" ^7- main object color");
- print_to(self, "^3glowmod \"value_x value_y value_z\" ^7- glow object color");
- print_to(self, "^3frame value ^7- object animation frame, for self-animated models");
- print_to(self, "^3scale value ^7- changes object scale. 0.5 is half size and 2 is double size");
- print_to(self, "^3solidity value ^7- object collisions, 0 = non-solid, 1 = solid");
- print_to(self, "^3physics value ^7- object physics, 0 = static, 1 = movable, 2 = physical");
- print_to(self, "^3force value ^7- amount of force applied to objects that are shot");
- print_to(self, "^3material value ^7- sets the material of the object. Default materials are: metal, stone, wood, flesh");
- print_to(self, "^7\"^2object_claim^7\" sets the player as the owner of the object, if he has the right to edit it");
- print_to(self, "^7\"^2object_info ^3value^7\" shows public information about the object");
- print_to(self, "^3object ^7- prints general information about the object, such as owner and creation / editing date");
- print_to(self, "^3mesh ^7- prints information about the object's mesh, including skeletal bones");
- print_to(self, "^3attachments ^7- prints information about the object's attachments");
- print_to(self, "^7The ^1drag object ^7key can be used to grab and carry objects. Players can only grab their own objects");
- return true;
-
- // ---------------- COMMAND: OBJECT, SPAWN ----------------
- case "object_spawn":
- if(time < self.object_flood)
- {
- print_to(self, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(self.object_flood - time), " ^7seconds beofore spawning another object"));
- return true;
- }
- self.object_flood = time + autocvar_g_sandbox_editor_flood;
- if(object_count >= autocvar_g_sandbox_editor_maxobjects)
- {
- print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
- return true;
- }
- if(cmd_argc < 3)
- {
- print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object without specifying a model. Please specify the path to your model file after the 'object_spawn' command");
- return true;
- }
- if (!(fexists(argv(2))))
- {
- print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object with a non-existent model. Make sure the path to your model file is correct");
- return true;
- }
-
- e = sandbox_ObjectSpawn(false);
- _setmodel(e, argv(2));
-
- if(autocvar_g_sandbox_info > 0)
- LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " spawned an object at origin ^3", vtos(e.origin), "\n"));
- return true;
-
- // ---------------- COMMAND: OBJECT, REMOVE ----------------
- case "object_remove":
- e = sandbox_ObjectEdit_Get(true);
- if(e != world)
- {
- if(autocvar_g_sandbox_info > 0)
- LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " removed an object at origin ^3", vtos(e.origin), "\n"));
- sandbox_ObjectRemove(e);
- return true;
- }
-
- print_to(self, "^1SANDBOX - WARNING: ^7Object could not be removed. Make sure you are facing an object that you have edit rights over");
- return true;
-
- // ---------------- COMMAND: OBJECT, DUPLICATE ----------------
- case "object_duplicate":
- switch(argv(2))
- {
- case "copy":
- // copies customizable properties of the selected object to the clipboard cvar
- e = sandbox_ObjectEdit_Get(autocvar_g_sandbox_editor_free); // can we copy objects we can't edit?
- if(e != world)
- {
- s = sandbox_ObjectPort_Save(e, false);
- s = strreplace("\"", "\\\"", s);
- stuffcmd(self, strcat("set ", argv(3), " \"", s, "\""));
-
- print_to(self, "^2SANDBOX - INFO: ^7Object copied to clipboard");
- return true;
- }
- print_to(self, "^1SANDBOX - WARNING: ^7Object could not be copied. Make sure you are facing an object that you have copy rights over");
- return true;
-
- case "paste":
- // spawns a new object using the properties in the player's clipboard cvar
- if(time < self.object_flood)
- {
- print_to(self, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(self.object_flood - time), " ^7seconds beofore spawning another object"));
- return true;
- }
- self.object_flood = time + autocvar_g_sandbox_editor_flood;
- if(argv(3) == "") // no object in clipboard
- {
- print_to(self, "^1SANDBOX - WARNING: ^7No object in clipboard. You must copy an object before you can paste it");
- return true;
- }
- if(object_count >= autocvar_g_sandbox_editor_maxobjects)
- {
- print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
- return true;
- }
- e = sandbox_ObjectPort_Load(argv(3), false);
-
- print_to(self, "^2SANDBOX - INFO: ^7Object pasted successfully");
- if(autocvar_g_sandbox_info > 0)
- LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " pasted an object at origin ^3", vtos(e.origin), "\n"));
- return true;
- }
- return true;
-
- // ---------------- COMMAND: OBJECT, ATTACH ----------------
- case "object_attach":
- switch(argv(2))
- {
- case "get":
- // select e as the object as meant to be attached
- e = sandbox_ObjectEdit_Get(true);
- if(e != world)
- {
- self.object_attach = e;
- print_to(self, "^2SANDBOX - INFO: ^7Object selected for attachment");
- return true;
- }
- print_to(self, "^1SANDBOX - WARNING: ^7Object could not be selected for attachment. Make sure you are facing an object that you have edit rights over");
- return true;
- case "set":
- if(self.object_attach == world)
- {
- print_to(self, "^1SANDBOX - WARNING: ^7No object selected for attachment. Please select an object to be attached first.");
- return true;
- }
-
- // attaches the previously selected object to e
- e = sandbox_ObjectEdit_Get(true);
- if(e != world)
- {
- sandbox_ObjectAttach_Set(self.object_attach, e, argv(3));
- self.object_attach = world; // object was attached, no longer keep it scheduled for attachment
- print_to(self, "^2SANDBOX - INFO: ^7Object attached successfully");
- if(autocvar_g_sandbox_info > 1)
- LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " attached objects at origin ^3", vtos(e.origin), "\n"));
- return true;
- }
- print_to(self, "^1SANDBOX - WARNING: ^7Object could not be attached to the parent. Make sure you are facing an object that you have edit rights over");
- return true;
- case "remove":
- // removes e if it was attached
- e = sandbox_ObjectEdit_Get(true);
- if(e != world)
- {
- sandbox_ObjectAttach_Remove(e);
- print_to(self, "^2SANDBOX - INFO: ^7Child objects detached successfully");
- if(autocvar_g_sandbox_info > 1)
- LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " detached objects at origin ^3", vtos(e.origin), "\n"));
- return true;
- }
- print_to(self, "^1SANDBOX - WARNING: ^7Child objects could not be detached. Make sure you are facing an object that you have edit rights over");
- return true;
- }
- return true;
-
- // ---------------- COMMAND: OBJECT, EDIT ----------------
- case "object_edit":
- if(argv(2) == "")
- {
- print_to(self, "^1SANDBOX - WARNING: ^7Too few parameters. You must specify a property to edit");
- return true;
- }
-
- e = sandbox_ObjectEdit_Get(true);
- if(e != world)
- {
- switch(argv(2))
- {
- case "skin":
- e.skin = stof(argv(3));
- break;
- case "alpha":
- e.alpha = stof(argv(3));
- break;
- case "color_main":
- e.colormod = stov(argv(3));
- break;
- case "color_glow":
- e.glowmod = stov(argv(3));
- break;
- case "frame":
- e.frame = stof(argv(3));
- break;
- case "scale":
- sandbox_ObjectEdit_Scale(e, stof(argv(3)));
- break;
- case "solidity":
- switch(argv(3))
- {
- case "0": // non-solid
- e.solid = SOLID_TRIGGER;
- break;
- case "1": // solid
- e.solid = SOLID_BBOX;
- break;
- default:
- break;
- }
- case "physics":
- switch(argv(3))
- {
- case "0": // static
- e.movetype = MOVETYPE_NONE;
- break;
- case "1": // movable
- e.movetype = MOVETYPE_TOSS;
- break;
- case "2": // physical
- e.movetype = MOVETYPE_PHYSICS;
- break;
- default:
- break;
- }
- break;
- case "force":
- e.damageforcescale = stof(argv(3));
- break;
- case "material":
- if(e.material) strunzone(e.material);
- if(argv(3))
- {
- for (i = 1; i <= 5; i++) // precache material sounds, 5 in total
- precache_sound(strcat("object/impact_", argv(3), "_", ftos(i), ".wav"));
- e.material = strzone(argv(3));
- }
- else
- e.material = string_null; // no material
- break;
- default:
- print_to(self, "^1SANDBOX - WARNING: ^7Invalid object property. For usage information, type 'sandbox help'");
- return true;
- }
-
- // update last editing time
- if(e.message2) strunzone(e.message2);
- e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S"));
-
- if(autocvar_g_sandbox_info > 1)
- LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " edited property ^3", argv(2), " ^7of an object at origin ^3", vtos(e.origin), "\n"));
- return true;
- }
-
- print_to(self, "^1SANDBOX - WARNING: ^7Object could not be edited. Make sure you are facing an object that you have edit rights over");
- return true;
-
- // ---------------- COMMAND: OBJECT, CLAIM ----------------
- case "object_claim":
- // if the player can edit an object but is not its owner, this can be used to claim that object
- if(self.crypto_idfp == "")
- {
- print_to(self, "^1SANDBOX - WARNING: ^7You do not have a player UID, and cannot claim objects");
- return true;
- }
- e = sandbox_ObjectEdit_Get(true);
- if(e != world)
- {
- // update the owner's name
- // Do this before checking if you're already the owner and skipping if such, so we
- // also update the player's nickname if he changed it (but has the same player UID)
- if(e.netname != self.netname)
- {
- if(e.netname) strunzone(e.netname);
- e.netname = strzone(self.netname);
- print_to(self, "^2SANDBOX - INFO: ^7Object owner name updated");
- }
-
- if(e.crypto_idfp == self.crypto_idfp)
- {
- print_to(self, "^2SANDBOX - INFO: ^7Object is already yours, nothing to claim");
- return true;
- }
-
- if(e.crypto_idfp) strunzone(e.crypto_idfp);
- e.crypto_idfp = strzone(self.crypto_idfp);
-
- print_to(self, "^2SANDBOX - INFO: ^7Object claimed successfully");
- }
- print_to(self, "^1SANDBOX - WARNING: ^7Object could not be claimed. Make sure you are facing an object that you have edit rights over");
- return true;
-
- // ---------------- COMMAND: OBJECT, INFO ----------------
- case "object_info":
- // prints public information about the object to the player
- e = sandbox_ObjectEdit_Get(false);
- if(e != world)
- {
- switch(argv(2))
- {
- case "object":
- print_to(self, strcat("^2SANDBOX - INFO: ^7Object is owned by \"^7", e.netname, "^7\", created \"^3", e.message, "^7\", last edited \"^3", e.message2, "^7\""));
- return true;
- case "mesh":
- s = "";
- FOR_EACH_TAG(e)
- s = strcat(s, "^7\"^5", gettaginfo_name, "^7\", ");
- print_to(self, strcat("^2SANDBOX - INFO: ^7Object mesh is \"^3", e.model, "^7\" at animation frame ^3", ftos(e.frame), " ^7containing the following tags: ", s));
- return true;
- case "attachments":
- // this should show the same info as 'mesh' but for attachments
- s = "";
- entity head;
- i = 0;
- for(head = world; (head = find(head, classname, "object")); )
- {
- if(head.owner == e)
- {
- ++i; // start from 1
- gettaginfo(e, head.tag_index);
- s = strcat(s, "^1attachment ", ftos(i), "^7 has mesh \"^3", head.model, "^7\" at animation frame ^3", ftos(head.frame));
- s = strcat(s, "^7 and is attached to bone \"^5", gettaginfo_name, "^7\", ");
- }
- }
- if(i) // object contains attachments
- print_to(self, strcat("^2SANDBOX - INFO: ^7Object contains the following ^1", ftos(i), "^7 attachment(s): ", s));
- else
- print_to(self, "^2SANDBOX - INFO: ^7Object contains no attachments");
- return true;
- }
- }
- print_to(self, "^1SANDBOX - WARNING: ^7No information could be found. Make sure you are facing an object");
- return true;
-
- // ---------------- COMMAND: DEFAULT ----------------
- default:
- print_to(self, "Invalid command. For usage information, type 'sandbox help'");
- return true;
- }
- }
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(sandbox, SV_StartFrame)
-{
- if(!autocvar_g_sandbox_storage_autosave)
- return false;
- if(time < autosave_time)
- return false;
- autosave_time = time + autocvar_g_sandbox_storage_autosave;
-
- sandbox_Database_Save();
-
- return true;
-}
-#endif
{
LOG_TRACE("AStar: Goal found on first node!\n");
- open = spawn();
+ open = new(path_end);
open.owner = open;
- open.classname = "path_end";
setorigin(open,path.origin);
pathlib_cleanup();
if(!CheckWireframeBox(own, org - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward))
return world;
- portal = spawn();
- portal.classname = "portal";
+ portal = new(portal);
portal.aiment = own;
setorigin(portal, org);
portal.mangle = ang;
#include "../lib/_all.inc"
#include "_all.qh"
+#include "../common/effects/qc/all.qc"
+
#include "anticheat.qc"
#include "antilag.qc"
#include "campaign.qc"
#include "cl_client.qc"
#include "cl_impulse.qc"
#include "cl_player.qc"
-#include "controlpoint.qc"
-#include "csqceffects.qc"
#include "ent_cs.qc"
#include "g_damage.qc"
#include "g_hook.qc"
// #include "g_lights.qc" // TODO: was never used
#include "g_models.qc"
#include "g_subs.qc"
-#include "g_violence.qc"
#include "g_world.qc"
-#include "generator.qc"
#include "ipban.qc"
#include "item_key.qc"
#include "mapvoting.qc"
#include "command/all.qc"
-#include "mutators/all.qc"
-
#include "pathlib/_all.inc"
#include "weapons/accuracy.qc"
#include "../common/campaign_setup.qc"
#include "../common/effects/effectinfo.qc"
#include "../common/mapinfo.qc"
-#include "../common/monsters/spawn.qc"
-#include "../common/monsters/sv_monsters.qc"
#include "../common/minigames/minigames.qc"
#include "../common/minigames/sv_minigames.qc"
+#include "../common/monsters/spawn.qc"
+#include "../common/monsters/sv_monsters.qc"
#include "../common/movetypes/include.qc"
#include "../common/net_notice.qc"
#include "../common/notifications.qc"
#include "../common/physics.qc"
#include "../common/playerstats.qc"
-#include "../common/viewloc.qc"
#include "../common/triggers/include.qc"
#include "../common/util.qc"
+#include "../common/viewloc.qc"
#include "../common/deathtypes/all.qc"
-#include "../common/buffs/all.qc"
#include "../common/effects/all.qc"
#include "../common/gamemodes/all.qc"
#include "../common/items/all.qc"
#include "../common/monsters/all.qc"
-#include "../common/mutators/all.qc"
-#include "../common/nades/all.qc"
#include "../common/turrets/all.qc"
#include "../common/vehicles/all.qc"
#include "../common/weapons/all.qc"
+#include "../common/mutators/all.qc"
+#include "mutators/all.qc"
#include "../common/turrets/sv_turrets.qc"
#include "../common/turrets/config.qc"
if(!spec)
msg_entity = e;
WRITESPECTATABLE_MSG_ONE({
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteHeader(MSG_ONE, TE_CSQC_RACE);
if(spec)
{
WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING);
void race_send_recordtime(float msg)
{
// send the server best time
- WriteByte(msg, SVC_TEMPENTITY);
- WriteByte(msg, TE_CSQC_RACE);
+ WriteHeader(msg, TE_CSQC_RACE);
WriteByte(msg, RACE_NET_SERVER_RECORD);
WriteInt24_t(msg, race_readTime(GetMapname(), 1));
}
void race_send_speedaward(float msg)
{
// send the best speed of the round
- WriteByte(msg, SVC_TEMPENTITY);
- WriteByte(msg, TE_CSQC_RACE);
+ WriteHeader(msg, TE_CSQC_RACE);
WriteByte(msg, RACE_NET_SPEED_AWARD);
WriteInt24_t(msg, floor(speedaward_speed+0.5));
WriteString(msg, speedaward_holder);
void race_send_speedaward_alltimebest(float msg)
{
// send the best speed
- WriteByte(msg, SVC_TEMPENTITY);
- WriteByte(msg, TE_CSQC_RACE);
+ WriteHeader(msg, TE_CSQC_RACE);
WriteByte(msg, RACE_NET_SPEED_AWARD_BEST);
WriteInt24_t(msg, floor(speedaward_alltimebest+0.5));
WriteString(msg, speedaward_alltimebest_holder);
void race_SendRankings(float pos, float prevpos, float del, float msg)
{
- WriteByte(msg, SVC_TEMPENTITY);
- WriteByte(msg, TE_CSQC_RACE);
+ WriteHeader(msg, TE_CSQC_RACE);
WriteByte(msg, RACE_NET_SERVER_RANKINGS);
WriteShort(msg, pos);
WriteShort(msg, prevpos);
msg = MSG_ALL;
msg_entity = e;
WRITESPECTATABLE_MSG_ONE_VARNAME(dummy3, {
- WriteByte(msg, SVC_TEMPENTITY);
- WriteByte(msg, TE_CSQC_RACE);
+ WriteHeader(msg, TE_CSQC_RACE);
WriteByte(msg, RACE_NET_SERVER_STATUS);
WriteShort(msg, id);
WriteString(msg, e.netname);
if(g_race_qualifying)
{
WRITESPECTATABLE_MSG_ONE_VARNAME(dummy1, {
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteHeader(MSG_ONE, TE_CSQC_RACE);
WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_QUALIFYING);
WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
WriteInt24_t(MSG_ONE, t); // time to that intermediate
{
msg_entity = e;
WRITESPECTATABLE_MSG_ONE_VARNAME(dummy2, {
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteHeader(MSG_ONE, TE_CSQC_RACE);
WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE);
WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
if(e == oth)
{
msg_entity = oth;
WRITESPECTATABLE_MSG_ONE_VARNAME(dummy3, {
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteHeader(MSG_ONE, TE_CSQC_RACE);
WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT);
WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
if(e == oth)
msg_entity = e;
WRITESPECTATABLE_MSG_ONE({
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteHeader(MSG_ONE, TE_CSQC_RACE);
WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_CLEAR); // next
});
}
{
msg_entity = pl;
WRITESPECTATABLE_MSG_ONE({
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteHeader(MSG_ONE, TE_CSQC_RACE);
WriteByte(MSG_ONE, RACE_NET_PENALTY_QUALIFYING);
WriteShort(MSG_ONE, TIME_ENCODE(penalty));
WriteString(MSG_ONE, reason);
{
msg_entity = pl;
WRITESPECTATABLE_MSG_ONE_VARNAME(dummy, {
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteHeader(MSG_ONE, TE_CSQC_RACE);
WriteByte(MSG_ONE, RACE_NET_PENALTY_RACE);
WriteShort(MSG_ONE, TIME_ENCODE(penalty));
WriteString(MSG_ONE, reason);
#include "../common/util.qh"
void round_handler_Think()
-{SELFPARAM();
- float f;
+{
+ SELFPARAM();
- if(time < game_starttime)
+ if (time < game_starttime)
{
round_handler_Reset(game_starttime);
return;
}
- if(gameover)
+ if (gameover)
{
round_handler_Reset(0);
round_handler_Remove();
return;
}
- if(self.wait)
+ if (this.wait)
{
- self.wait = false;
- self.cnt = self.count + 1; // init countdown
- round_starttime = time + self.count;
+ this.wait = false;
+ this.cnt = this.count + 1; // init countdown
+ round_starttime = time + this.count;
reset_map(true);
}
- if(self.cnt > 0) // countdown running
+ if (this.cnt > 0) // countdown running
{
- if(self.canRoundStart())
+ if (this.canRoundStart())
{
- if(self.cnt == self.count + 1)
- round_starttime = time + self.count;
- f = self.cnt - 1;
- if(f == 0)
+ if (this.cnt == this.count + 1) round_starttime = time + this.count;
+ int f = this.cnt - 1;
+ if (f == 0)
{
- self.cnt = 0;
- self.round_endtime = (self.round_timelimit) ? time + self.round_timelimit : 0;
- self.nextthink = time;
- if(self.roundStart)
- self.roundStart();
+ this.cnt = 0;
+ this.round_endtime = (this.round_timelimit) ? time + this.round_timelimit : 0;
+ this.nextthink = time;
+ if (this.roundStart) this.roundStart();
return;
}
- self.cnt = self.cnt - 1;
+ this.cnt = this.cnt - 1;
}
else
{
round_handler_Reset(0);
}
- self.nextthink = time + 1; // canRoundStart every second
+ this.nextthink = time + 1; // canRoundStart every second
}
else
{
- if(self.canRoundEnd())
+ if (this.canRoundEnd())
{
// schedule a new round
- self.wait = true;
- self.nextthink = time + self.delay;
+ this.wait = true;
+ this.nextthink = time + this.delay;
}
else
{
- self.nextthink = time; // canRoundEnd every frame
+ this.nextthink = time; // canRoundEnd every frame
}
}
}
void round_handler_Init(float the_delay, float the_count, float the_round_timelimit)
{
- round_handler.delay = (the_delay > 0) ? the_delay : 0;
- round_handler.count = fabs(floor(the_count));
- round_handler.cnt = round_handler.count + 1;
- round_handler.round_timelimit = (the_round_timelimit > 0) ? the_round_timelimit : 0;
+ entity this = round_handler;
+ this.delay = (the_delay > 0) ? the_delay : 0;
+ this.count = fabs(floor(the_count));
+ this.cnt = this.count + 1;
+ this.round_timelimit = (the_round_timelimit > 0) ? the_round_timelimit : 0;
}
// NOTE: this is only needed because if round_handler spawns at time 1
// gamestarttime isn't initialized yet
void round_handler_FirstThink()
{
- round_starttime = max(time, game_starttime) + round_handler.count;
- round_handler.think = round_handler_Think;
- round_handler.nextthink = max(time, game_starttime);
+ SELFPARAM();
+ round_starttime = max(time, game_starttime) + this.count;
+ this.think = round_handler_Think;
+ this.nextthink = max(time, game_starttime);
}
void round_handler_Spawn(float() canRoundStart_func, float() canRoundEnd_func, void() roundStart_func)
{
- if(round_handler)
+ if (round_handler)
{
backtrace("Can't spawn round_handler again!");
return;
}
- round_handler = spawn();
- round_handler.classname = "round_handler";
+ entity this = round_handler = new(round_handler);
- round_handler.think = round_handler_FirstThink;
- round_handler.canRoundStart = canRoundStart_func;
- round_handler.canRoundEnd = canRoundEnd_func;
- round_handler.roundStart = roundStart_func;
- round_handler.wait = false;
+ this.think = round_handler_FirstThink;
+ this.canRoundStart = canRoundStart_func;
+ this.canRoundEnd = canRoundEnd_func;
+ this.roundStart = roundStart_func;
+ this.wait = false;
round_handler_Init(5, 5, 180);
- round_handler.nextthink = time;
+ this.nextthink = time;
}
void round_handler_Reset(float next_think)
{
- round_handler.wait = false;
- if(round_handler.count)
- if(round_handler.cnt < round_handler.count + 1)
- round_handler.cnt = round_handler.count + 1;
- round_handler.nextthink = next_think;
- round_starttime = (next_think) ? (next_think + round_handler.count) : -1;
+ entity this = round_handler;
+ this.wait = false;
+ if (this.count)
+ if (this.cnt < this.count + 1) this.cnt = this.count + 1;
+ this.nextthink = next_think;
+ round_starttime = (next_think) ? (next_think + this.count) : -1;
}
void round_handler_Remove()
remove(round_handler);
round_handler = world;
}
-
{
float i, p, longflags;
- WriteByte(MSG_ENTITY, ENT_CLIENT_TEAMSCORES);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_TEAMSCORES);
WriteByte(MSG_ENTITY, self.team - 1);
longflags = 0;
void TeamScore_Spawn(float t, string name)
{
- entity ts;
- ts = spawn();
- ts.classname = "csqc_score_team";
+ entity ts = new(csqc_score_team);
+ make_pure(ts);
ts.netname = name; // not used yet, FIXME
ts.team = t;
Net_LinkEntity(ts, false, 0, TeamScore_SendEntity);
bool ScoreInfo_SendEntity(entity this, entity to, int sf)
{
float i;
- WriteByte(MSG_ENTITY, ENT_CLIENT_SCORES_INFO);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_SCORES_INFO);
WriteInt24_t(MSG_ENTITY, MapInfo_LoadedGametype);
for(i = 0; i < MAX_SCORE; ++i)
{
}
else
{
- scores_initialized = spawn();
- scores_initialized.classname = "ent_client_scoreinfo";
+ scores_initialized = new(ent_client_scoreinfo);
+ make_pure(scores_initialized);
Net_LinkEntity(scores_initialized, false, 0, ScoreInfo_SendEntity);
}
if(teams >= 1)
{
float i, p, longflags;
- WriteByte(MSG_ENTITY, ENT_CLIENT_SCORES);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_SCORES);
WriteByte(MSG_ENTITY, num_for_edict(self.owner));
longflags = 0;
void PlayerScore_Attach(entity player)
{
- entity sk;
if(player.scorekeeper)
error("player already has a scorekeeper");
- sk = spawn();
+ entity sk = new(scorekeeper);
+ make_pure(sk);
sk.owner = player;
Net_LinkEntity(sk, false, 0, PlayerScore_SendEntity);
player.scorekeeper = sk;
FOR_EACH_CLIENT(p)
{
+ string s = "";
if(fullstatus)
{
s = GetPlayerScoreString(p, 1);
PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_SCOREBOARD, scores_label[i]), s.(scores[i]));
}
-void PlayerScore_TeamStats(void)
+void PlayerScore_TeamStats()
{
entity sk;
float t, i;
if(score_enabled)
ScoreInfo_SetLabel_PlayerScore(SP_SCORE, "score", sprio);
+
+ ScoreInfo_SetLabel_PlayerScore(SP_DMG, "damage", 0);
+ ScoreInfo_SetLabel_PlayerScore(SP_DMGTAKEN, "damagetaken", SFL_LOWER_IS_BETTER);
}
void ScoreRules_basics_end()
{
bool SpawnPoint_Send(entity this, entity to, int sf)
{
- WriteByte(MSG_ENTITY, ENT_CLIENT_SPAWNPOINT);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_SPAWNPOINT);
WriteByte(MSG_ENTITY, self.team);
WriteShort(MSG_ENTITY, self.origin.x);
{
float send;
- WriteByte(MSG_ENTITY, ENT_CLIENT_SPAWNEVENT);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_SPAWNEVENT);
if(autocvar_g_spawn_alloweffects)
{
{
// show where spawnpoints point at too
makevectors(self.angles);
- entity e;
- e = spawn();
- e.classname = "info_player_foo";
+ entity e = new(info_player_foo);
setorigin(e, self.origin + v_forward * 24);
setsize(e, '-8 -8 -8', '8 8 8');
e.solid = SOLID_TRIGGER;
void spawn_flocker()
{SELFPARAM();
- entity flocker;
-
- flocker = spawn ();
+ entity flocker = new(flocker);
setorigin(flocker, self.origin + '0 0 32');
setmodel (flocker, MDL_FLOCKER);
setsize (flocker, '-3 -3 -3', '3 3 3');
flocker.flock_id = self.flock_id;
- flocker.classname = "flocker";
flocker.owner = self;
flocker.think = flocker_think;
flocker.nextthink = time + random() * 5;
self.think = flockerspawn_think;
self.nextthink = time + 0.25;
- self.enemy = spawn();
+ self.enemy = new(FLock Hunter);
setmodel(self.enemy, MDL_FLOCKER);
setorigin(self.enemy,self.origin + '0 0 768' + (randomvec() * 128));
- self.enemy.classname = "FLock Hunter";
self.enemy.scale = 3;
self.enemy.effects = EF_LOWPRECISION;
self.enemy.movetype = MOVETYPE_BOUNCEMISSILE;
#include "../common/constants.qh"
#include "../common/deathtypes/all.qh"
+#include "../common/debug.qh"
#include "../common/mapinfo.qh"
#include "../common/util.qh"
.float lastground;
.int state;
-void CreatureFrame (void)
+void CreatureFrame ()
{SELFPARAM();
float dm;
if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS))
{
if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
- GlobalSound(globalsound_metalstep, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ GlobalSound(GS_STEP_METAL, CH_PLAYER, VOICETYPE_PLAYERSOUND);
else
- GlobalSound(globalsound_step, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ GlobalSound(GS_STEP, CH_PLAYER, VOICETYPE_PLAYERSOUND);
}
}
}
}
}
-void WarpZone_PostInitialize_Callback(void)
+void WarpZone_PostInitialize_Callback()
{
// create waypoint links for warpzones
entity e;
#include "../lib/warpzone/util_server.qh"
#endif
+REGISTER_NET_LINKED(ENT_CLIENT_ITEM)
+
#ifdef CSQC
void ItemDraw(entity self)
{
self.drawmask = MASK_NORMAL;
}
-void ItemRead(float _IsNew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
+{
int sf = ReadByte();
if(sf & ISF_LOCATION)
if(self.ItemStatus & ITS_ANIMATE2)
self.move_avelocity = '0 -90 0';
}
+ return true;
}
#endif
else
sf &= ~ISF_DROP;
- WriteByte(MSG_ENTITY, ENT_CLIENT_ITEM);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_ITEM);
WriteByte(MSG_ENTITY, sf);
//WriteByte(MSG_ENTITY, self.cnt);
if(sf & ISF_SIZE)
{
- WriteByte(MSG_ENTITY, ((self.flags & FL_POWERUP) || self.health || self.armorvalue));
+ Pickup p = this.itemdef;
+ WriteByte(MSG_ENTITY, p.instanceOfPowerup || p.instanceOfHealth || p.instanceOfArmor);
}
if(sf & ISF_STATUS)
item.SendFlags |= ISF_LOCATION;
}
-float have_pickup_item(void)
-{SELFPARAM();
- if(self.flags & FL_POWERUP)
+bool have_pickup_item(entity this)
+{
+ if(this.itemdef.instanceOfPowerup)
{
if(autocvar_g_powerups > 0)
return true;
if(autocvar_g_pickup_items == 0)
return false;
if(g_weaponarena)
- if(self.weapons || (self.items & IT_AMMO)) // no item or ammo pickups in weaponarena
+ if(this.weapons || (this.items & IT_AMMO)) // no item or ammo pickups in weaponarena
return false;
}
return true;
e.spawnshieldtime = 1;
e.ItemStatus &= ~ITS_AVAILABLE;
}
- else if((e.flags & FL_WEAPON) && !(e.flags & FL_NO_WEAPON_STAY) && g_weapon_stay)
+ else {
+ entity def = e.itemdef;
+ bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.weapons & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
+ || e.team // weapon stay isn't supported for teamed weapons
+ ;
+ if(def.instanceOfWeaponPickup && !nostay && g_weapon_stay)
{
// make the item translucent and not touchable
e.model = e.mdl;
e.glowmod = e.colormod;
e.spawnshieldtime = 1;
e.ItemStatus &= ~ITS_AVAILABLE;
- }
+ }}
if (e.items & ITEM_Strength.m_itemid || e.items & ITEM_Shield.m_itemid)
e.ItemStatus |= ITS_POWERUP;
void Item_ItemsTime_SetTime(entity e, float t);
void Item_ItemsTime_SetTimesForAllPlayers();
-void Item_Respawn (void)
+void Item_Respawn ()
{SELFPARAM();
Item_Show(self, 1);
// this is ugly...
Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
}
-void Item_RespawnCountdown (void)
+void Item_RespawnCountdown ()
{SELFPARAM();
if(self.count >= ITEM_RESPAWN_TICKS)
{
pickedup |= Item_GiveAmmoTo(item, player, health, item.max_health, ITEM_MODE_HEALTH);
pickedup |= Item_GiveAmmoTo(item, player, armorvalue, item.max_armorvalue, ITEM_MODE_ARMOR);
- if (item.flags & FL_WEAPON)
+ if (item.itemdef.instanceOfWeaponPickup)
{
WepSet it;
it = item.weapons;
return 0;
// crude hack to enforce switching weapons
- if(g_cts && (item.flags & FL_WEAPON))
+ if(g_cts && item.itemdef.instanceOfWeaponPickup)
{
W_SwitchWeapon_Force(player, item.weapon);
return 1;
return 1;
}
-void Item_Touch (void)
-{SELFPARAM();
- entity e, head;
+void Item_Touch()
+{
+ SELFPARAM();
// remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
- if(self.classname == "droppedweapon")
+ if (this.classname == "droppedweapon")
{
if (ITEM_TOUCH_NEEDKILL())
{
- remove(self);
+ remove(this);
return;
}
}
if(!(other.flags & FL_PICKUPITEMS)
|| other.frozen
|| other.deadflag
- || (self.solid != SOLID_TRIGGER)
- || (self.owner == other)
- || (time < self.item_spawnshieldtime)
- ) { return;}
+ || (this.solid != SOLID_TRIGGER)
+ || (this.owner == other)
+ || (time < this.item_spawnshieldtime)
+ ) { return; }
- switch(MUTATOR_CALLHOOK(ItemTouch, self, other))
+ switch (MUTATOR_CALLHOOK(ItemTouch, this, other))
{
case MUT_ITEMTOUCH_RETURN: { return; }
case MUT_ITEMTOUCH_PICKUP: { goto pickup; }
}
- if (self.classname == "droppedweapon")
+ if (this.classname == "droppedweapon")
{
- self.strength_finished = max(0, self.strength_finished - time);
- self.invincible_finished = max(0, self.invincible_finished - time);
- self.superweapons_finished = max(0, self.superweapons_finished - time);
+ this.strength_finished = max(0, this.strength_finished - time);
+ this.invincible_finished = max(0, this.invincible_finished - time);
+ this.superweapons_finished = max(0, this.superweapons_finished - time);
}
- entity it = self.itemdef;
- bool gave = (it && it.instanceOfPickup) ? ITEM_HANDLE(Pickup, it, self, other) : Item_GiveTo(self, other);
+ entity it = this.itemdef;
+ bool gave = ITEM_HANDLE(Pickup, it, this, other);
if (!gave)
{
- if (self.classname == "droppedweapon")
+ if (this.classname == "droppedweapon")
{
// undo what we did above
- self.strength_finished += time;
- self.invincible_finished += time;
- self.superweapons_finished += time;
+ this.strength_finished += time;
+ this.invincible_finished += time;
+ this.superweapons_finished += time;
}
return;
}
other.last_pickup = time;
- Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
- _sound (other, CH_TRIGGER, (self.item_pickupsound ? self.item_pickupsound : self.item_pickupsound_ent.sound_str()), VOL_BASE, ATTEN_NORM);
+ Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
+ _sound (other, CH_TRIGGER, (this.item_pickupsound ? this.item_pickupsound : Sound_fixpath(this.item_pickupsound_ent)), VOL_BASE, ATTEN_NORM);
- if (self.classname == "droppedweapon")
- remove (self);
- else if (self.spawnshieldtime)
+ if (this.classname == "droppedweapon")
+ remove (this);
+ else if (this.spawnshieldtime)
{
- if(self.team)
+ entity e;
+ if(this.team)
{
RandomSelection_Init();
- for(head = world; (head = findfloat(head, team, self.team)); )
+ for(entity head = world; (head = findfloat(head, team, this.team)); )
{
if(head.flags & FL_ITEM)
if(head.classname != "item_flag_team" && head.classname != "item_key_team")
}
else
- e = self;
+ e = this;
Item_ScheduleRespawn(e);
}
}
-void Item_Reset()
-{SELFPARAM();
- Item_Show(self, !self.state);
- setorigin (self, self.origin);
+void Item_Reset(entity this)
+{
+ Item_Show(this, !this.state);
+ setorigin(this, this.origin);
- if(self.classname != "droppedweapon")
+ if (this.classname != "droppedweapon")
{
- self.think = Item_Think;
- self.nextthink = time;
+ this.think = Item_Think;
+ this.nextthink = time;
- if(self.waypointsprite_attached)
- WaypointSprite_Kill(self.waypointsprite_attached);
+ if (this.waypointsprite_attached)
+ WaypointSprite_Kill(this.waypointsprite_attached);
- if((self.flags & FL_POWERUP) || (self.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
- Item_ScheduleInitialRespawn(self);
+ if (this.itemdef.instanceOfPowerup || (this.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
+ Item_ScheduleInitialRespawn(this);
}
}
+void Item_Reset_self() { SELFPARAM(); Item_Reset(this); }
void Item_FindTeam()
{SELFPARAM();
head.effects &= ~EF_NODRAW;
}
- Item_Reset();
+ Item_Reset(self);
}
}
// Savage: used for item garbage-collection
// TODO: perhaps nice special effect?
-void RemoveItem(void)
+void RemoveItem()
{SELFPARAM();
if(wasfreed(self) || !self) { return; }
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
RemoveItem();
}
-void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, float defaultrespawntimejitter, string itemname, float itemid, float weaponid, float itemflags, float(entity player, entity item) pickupevalfunc, float pickupbasevalue)
-{SELFPARAM();
- startitem_failed = false;
-
- if(self.model == "")
- self.model = itemmodel;
+void _StartItem(entity this, entity def, float defaultrespawntime, float defaultrespawntimejitter)
+{
+ string itemname = def.m_name;
+ Model itemmodel = def.m_model;
+ Sound pickupsound = def.m_sound;
+ float(entity player, entity item) pickupevalfunc = def.m_pickupevalfunc;
+ float pickupbasevalue = def.m_botvalue;
+ int itemflags = def.m_itemflags;
- if(self.model == "")
- {
- error(strcat("^1Tried to spawn ", itemname, " with no model!\n"));
- return;
- }
+ startitem_failed = false;
- if(self.item_pickupsound == "")
- self.item_pickupsound = pickupsound;
+ this.item_model_ent = itemmodel;
+ this.item_pickupsound_ent = pickupsound;
- if(!self.respawntime) // both need to be set
+ if(!this.respawntime) // both need to be set
{
- self.respawntime = defaultrespawntime;
- self.respawntimejitter = defaultrespawntimejitter;
+ this.respawntime = defaultrespawntime;
+ this.respawntimejitter = defaultrespawntimejitter;
}
- self.items = itemid;
- self.weapon = weaponid;
+ int itemid = def.m_itemid;
+ this.items = itemid;
+ int weaponid = def.instanceOfWeaponPickup ? def.m_weapon.m_id : 0;
+ this.weapon = weaponid;
- if(!self.fade_end)
+ if(!this.fade_end)
{
- self.fade_start = autocvar_g_items_mindist;
- self.fade_end = autocvar_g_items_maxdist;
+ this.fade_start = autocvar_g_items_mindist;
+ this.fade_end = autocvar_g_items_maxdist;
}
if(weaponid)
- self.weapons = WepSet_FromWeapon(weaponid);
+ this.weapons = WepSet_FromWeapon(weaponid);
- self.flags = FL_ITEM | itemflags;
+ this.flags = FL_ITEM | itemflags;
- if(MUTATOR_CALLHOOK(FilterItem)) // error means we do not want the item
+ if(MUTATOR_CALLHOOK(FilterItem, this)) // error means we do not want the item
{
startitem_failed = true;
- remove(self);
+ remove(this);
return;
}
// is it a dropped weapon?
- if (self.classname == "droppedweapon")
+ if (this.classname == "droppedweapon")
{
- self.reset = SUB_Remove;
+ this.reset = SUB_Remove;
// it's a dropped weapon
- self.movetype = MOVETYPE_TOSS;
+ this.movetype = MOVETYPE_TOSS;
// Savage: remove thrown items after a certain period of time ("garbage collection")
- self.think = RemoveItem;
- self.nextthink = time + 20;
+ this.think = RemoveItem;
+ this.nextthink = time + 20;
- self.takedamage = DAMAGE_YES;
- self.event_damage = Item_Damage;
+ this.takedamage = DAMAGE_YES;
+ this.event_damage = Item_Damage;
- if(self.strength_finished || self.invincible_finished || self.superweapons_finished)
- /*
- if(self.items == 0)
- if(!(self.weapons & ~WEPSET_SUPERWEAPONS)) // only superweapons
- if(self.ammo_nails == 0)
- if(self.ammo_cells == 0)
- if(self.ammo_rockets == 0)
- if(self.ammo_shells == 0)
- if(self.ammo_fuel == 0)
- if(self.health == 0)
- if(self.armorvalue == 0)
- */
+ if(this.strength_finished || this.invincible_finished || this.superweapons_finished)
{
// if item is worthless after a timer, have it expire then
- self.nextthink = max(self.strength_finished, self.invincible_finished, self.superweapons_finished);
+ this.nextthink = max(this.strength_finished, this.invincible_finished, this.superweapons_finished);
}
// don't drop if in a NODROP zone (such as lava)
- traceline(self.origin, self.origin, MOVE_NORMAL, self);
+ traceline(this.origin, this.origin, MOVE_NORMAL, this);
if (trace_dpstartcontents & DPCONTENTS_NODROP)
{
startitem_failed = true;
- remove(self);
+ remove(this);
return;
}
}
else
{
- if(!have_pickup_item())
+ if(!have_pickup_item(this))
{
startitem_failed = true;
- remove (self);
+ remove (this);
return;
}
- if(self.angles != '0 0 0')
- self.SendFlags |= ISF_ANGLES;
+ if(this.angles != '0 0 0')
+ this.SendFlags |= ISF_ANGLES;
- self.reset = Item_Reset;
+ this.reset = Item_Reset_self;
// it's a level item
- if(self.spawnflags & 1)
- self.noalign = 1;
- if (self.noalign > 0)
- self.movetype = MOVETYPE_NONE;
+ if(this.spawnflags & 1)
+ this.noalign = 1;
+ if (this.noalign > 0)
+ this.movetype = MOVETYPE_NONE;
else
- self.movetype = MOVETYPE_TOSS;
+ this.movetype = MOVETYPE_TOSS;
// do item filtering according to game mode and other things
- if (self.noalign <= 0)
+ if (this.noalign <= 0)
{
// first nudge it off the floor a little bit to avoid math errors
- setorigin(self, self.origin + '0 0 1');
+ setorigin(this, this.origin + '0 0 1');
// set item size before we spawn a spawnfunc_waypoint
- if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
- setsize (self, '-16 -16 0', '16 16 48');
- else
- setsize (self, '-16 -16 0', '16 16 32');
- self.SendFlags |= ISF_SIZE;
+ setsize(this, def.m_mins, def.m_maxs);
+ this.SendFlags |= ISF_SIZE;
// note droptofloor returns false if stuck/or would fall too far
- if(!self.noalign)
- droptofloor();
- waypoint_spawnforitem(self);
+ if (!this.noalign)
+ WITH(entity, self, this, droptofloor());
+ waypoint_spawnforitem(this);
}
/*
* can't do it that way, as it would break maps
* TODO make a target_give like entity another way, that perhaps has
* the weapon name in a key
- if(self.targetname)
+ if(this.targetname)
{
// target_give not yet supported; maybe later
- print("removed targeted ", self.classname, "\n");
+ print("removed targeted ", this.classname, "\n");
startitem_failed = true;
- remove (self);
+ remove (this);
return;
}
*/
if(autocvar_spawn_debug >= 2)
{
- entity otheritem;
- for(otheritem = findradius(self.origin, 3); otheritem; otheritem = otheritem.chain)
+ for(entity otheritem = findradius(this.origin, 3); otheritem; otheritem = otheritem.chain)
{
// why not flags & fl_item?
if(otheritem.is_item)
{
- LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(self.origin));
+ LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
LOG_TRACE(" vs ", otheritem.netname, vtos(otheritem.origin), "\n");
error("Mapper sucks.");
}
}
- self.is_item = true;
+ this.is_item = true;
}
weaponsInMap |= WepSet_FromWeapon(weaponid);
- precache_model (self.model);
- precache_sound (self.item_pickupsound);
+ precache_model(this.model);
+ precache_sound(this.item_pickupsound);
- if((itemflags & (FL_POWERUP | FL_WEAPON)) || (itemid & (IT_HEALTH | IT_ARMOR | IT_KEY1 | IT_KEY2)))
- self.target = "###item###"; // for finding the nearest item using find()
+ if ( def.instanceOfPowerup
+ || def.instanceOfWeaponPickup
+ || (def.instanceOfHealth && def != ITEM_HealthSmall)
+ || (def.instanceOfArmor && def != ITEM_ArmorSmall)
+ || (itemid & (IT_KEY1 | IT_KEY2))
+ ) this.target = "###item###"; // for finding the nearest item using find()
- Item_ItemsTime_SetTime(self, 0);
+ Item_ItemsTime_SetTime(this, 0);
}
- self.bot_pickup = true;
- self.bot_pickupevalfunc = pickupevalfunc;
- self.bot_pickupbasevalue = pickupbasevalue;
- self.mdl = self.model;
- self.netname = itemname;
- self.touch = Item_Touch;
- setmodel(self, MDL_Null); // precision set below
- //self.effects |= EF_LOWPRECISION;
-
- if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
- {
- self.pos1 = '-16 -16 0';
- self.pos2 = '16 16 48';
- }
- else
- {
- self.pos1 = '-16 -16 0';
- self.pos2 = '16 16 32';
- }
- setsize (self, self.pos1, self.pos2);
+ this.bot_pickup = true;
+ this.bot_pickupevalfunc = pickupevalfunc;
+ this.bot_pickupbasevalue = pickupbasevalue;
+ this.mdl = this.model ? this.model : strzone(this.item_model_ent.model_str());
+ this.netname = itemname;
+ this.touch = Item_Touch;
+ setmodel(this, MDL_Null); // precision set below
+ //this.effects |= EF_LOWPRECISION;
- self.SendFlags |= ISF_SIZE;
+ setsize (this, this.pos1 = def.m_mins, this.pos2 = def.m_maxs);
- if(!(self.spawnflags & 1024))
- {
- if(itemflags & FL_POWERUP)
- self.ItemStatus |= ITS_ANIMATE1;
+ this.SendFlags |= ISF_SIZE;
- if(self.armorvalue || self.health)
- self.ItemStatus |= ITS_ANIMATE2;
+ if (!(this.spawnflags & 1024)) {
+ if(def.instanceOfPowerup)
+ this.ItemStatus |= ITS_ANIMATE1;
+
+ if(this.armorvalue || this.health)
+ this.ItemStatus |= ITS_ANIMATE2;
}
- if(itemflags & FL_WEAPON)
+ if(def.instanceOfWeaponPickup)
{
- if (self.classname != "droppedweapon") // if dropped, colormap is already set up nicely
- self.colormap = 1024; // color shirt=0 pants=0 grey
+ if (this.classname != "droppedweapon") // if dropped, colormap is already set up nicely
+ this.colormap = 1024; // color shirt=0 pants=0 grey
else
- self.gravity = 1;
-
- if(!(self.spawnflags & 1024))
- self.ItemStatus |= ITS_ANIMATE1;
- self.ItemStatus |= ISF_COLORMAP;
+ this.gravity = 1;
+ if (!(this.spawnflags & 1024))
+ this.ItemStatus |= ITS_ANIMATE1;
+ this.ItemStatus |= ISF_COLORMAP;
}
- self.state = 0;
- if(self.team) // broken, no idea why.
+ this.state = 0;
+ if(this.team) // broken, no idea why.
{
- if(!self.cnt)
- self.cnt = 1; // item probability weight
+ if(!this.cnt)
+ this.cnt = 1; // item probability weight
- self.effects |= EF_NODRAW; // marker for item team search
- InitializeEntity(self, Item_FindTeam, INITPRIO_FINDTARGET);
+ this.effects |= EF_NODRAW; // marker for item team search
+ InitializeEntity(this, Item_FindTeam, INITPRIO_FINDTARGET);
}
else
- Item_Reset();
+ Item_Reset(this);
- Net_LinkEntity(self, !((itemflags & FL_POWERUP) || self.health || self.armorvalue), 0, ItemSend);
+ Net_LinkEntity(this, !(def.instanceOfPowerup || def.instanceOfHealth || def.instanceOfArmor), 0, ItemSend);
// call this hook after everything else has been done
- if(MUTATOR_CALLHOOK(Item_Spawn, self))
+ if (MUTATOR_CALLHOOK(Item_Spawn, this))
{
startitem_failed = true;
- remove(self);
+ remove(this);
return;
}
}
-void StartItemA (entity a)
-{SELFPARAM();
- self.itemdef = a;
- StartItem(strzone(a.m_model.model_str()), a.m_sound, a.m_respawntime(), a.m_respawntimejitter(), a.m_name, a.m_itemid, 0, a.m_itemflags, a.m_pickupevalfunc, a.m_botvalue);
+void StartItem(entity this, GameItem def)
+{
+ _StartItem(
+ this,
+ this.itemdef = def,
+ def.m_respawntime(), // defaultrespawntime
+ def.m_respawntimejitter() // defaultrespawntimejitter
+ );
}
spawnfunc(item_rockets)
self.ammo_rockets = g_pickup_rockets;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItemA (ITEM_Rockets);
+ StartItem(this, ITEM_Rockets);
}
spawnfunc(item_bullets)
self.ammo_nails = g_pickup_nails;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItemA (ITEM_Bullets);
+ StartItem(this, ITEM_Bullets);
}
spawnfunc(item_cells)
self.ammo_cells = g_pickup_cells;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItemA (ITEM_Cells);
+ StartItem(this, ITEM_Cells);
}
spawnfunc(item_plasma)
self.ammo_plasma = g_pickup_plasma;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItemA (ITEM_Plasma);
+ StartItem(this, ITEM_Plasma);
}
spawnfunc(item_shells)
self.ammo_shells = g_pickup_shells;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItemA (ITEM_Shells);
+ StartItem(this, ITEM_Shells);
}
spawnfunc(item_armor_small)
self.max_armorvalue = g_pickup_armorsmall_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armorsmall_anyway;
- StartItemA (ITEM_ArmorSmall);
+ StartItem(this, ITEM_ArmorSmall);
}
spawnfunc(item_armor_medium)
self.max_armorvalue = g_pickup_armormedium_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armormedium_anyway;
- StartItemA (ITEM_ArmorMedium);
+ StartItem(this, ITEM_ArmorMedium);
}
spawnfunc(item_armor_big)
self.max_armorvalue = g_pickup_armorbig_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armorbig_anyway;
- StartItemA (ITEM_ArmorLarge);
+ StartItem(this, ITEM_ArmorLarge);
}
spawnfunc(item_armor_large)
self.max_armorvalue = g_pickup_armorlarge_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armorlarge_anyway;
- StartItemA (ITEM_ArmorMega);
+ StartItem(this, ITEM_ArmorMega);
}
spawnfunc(item_health_small)
self.health = g_pickup_healthsmall;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_healthsmall_anyway;
- StartItemA (ITEM_HealthSmall);
+ StartItem(this, ITEM_HealthSmall);
}
spawnfunc(item_health_medium)
self.health = g_pickup_healthmedium;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_healthmedium_anyway;
- StartItemA (ITEM_HealthMedium);
+ StartItem(this, ITEM_HealthMedium);
}
spawnfunc(item_health_large)
self.health = g_pickup_healthlarge;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_healthlarge_anyway;
- StartItemA (ITEM_HealthLarge);
+ StartItem(this, ITEM_HealthLarge);
}
spawnfunc(item_health_mega)
self.health = g_pickup_healthmega;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_healthmega_anyway;
- StartItemA (ITEM_HealthMega);
+ StartItem(this, ITEM_HealthMega);
}
// support old misnamed entities
{
if(!self.strength_finished)
self.strength_finished = autocvar_g_balance_powerup_strength_time;
- StartItemA (ITEM_Strength);
+ StartItem(this, ITEM_Strength);
}
spawnfunc(item_invincible)
{
if(!self.invincible_finished)
self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
- StartItemA (ITEM_Shield);
+ StartItem(this, ITEM_Shield);
}
// compatibility:
self.ammo_fuel = g_pickup_fuel;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItemA (ITEM_JetpackFuel);
+ StartItem(this, ITEM_JetpackFuel);
}
spawnfunc(item_fuel_regen)
spawnfunc_item_fuel(this);
return;
}
- StartItemA (ITEM_JetpackRegen);
+ StartItem(this, ITEM_JetpackRegen);
}
spawnfunc(item_jetpack)
spawnfunc_item_fuel(this);
return;
}
- StartItemA (ITEM_Jetpack);
+ StartItem(this, ITEM_Jetpack);
}
float GiveWeapon(entity e, float wpn, float op, float val)
return (v0 != v1);
}
-float GiveBit(entity e, .float fld, float bit, float op, float val)
-{
- float v0, v1;
- v0 = (e.(fld) & bit);
- switch(op)
- {
- case OP_SET:
- if(val > 0)
- e.(fld) |= bit;
- else
- e.(fld) &= ~bit;
- break;
- case OP_MIN:
- case OP_PLUS:
- if(val > 0)
- e.(fld) |= bit;
- break;
- case OP_MAX:
- if(val <= 0)
- e.(fld) &= ~bit;
- break;
- case OP_MINUS:
- if(val > 0)
- e.(fld) &= ~bit;
- break;
- }
- v1 = (e.(fld) & bit);
- return (v0 != v1);
-}
-
-float GiveValue(entity e, .float fld, float op, float val)
-{
- float v0, v1;
- v0 = e.(fld);
- switch(op)
- {
- case OP_SET:
- e.(fld) = val;
- break;
- case OP_MIN:
- e.(fld) = max(e.(fld), val); // min 100 cells = at least 100 cells
- break;
- case OP_MAX:
- e.(fld) = min(e.(fld), val);
- break;
- case OP_PLUS:
- e.(fld) += val;
- break;
- case OP_MINUS:
- e.(fld) -= val;
- break;
- }
- v1 = e.(fld);
- return (v0 != v1);
-}
-
void GiveSound(entity e, float v0, float v1, float t, string snd_incr, string snd_decr)
{
if(v1 == v0)
.float fade_end;
#ifdef SVQC
-void StartItemA (entity a);
+void StartItem(entity this, entity a);
#endif
#ifdef CSQC
void ItemDraw(entity this);
void ItemDrawSimple(entity this);
-void ItemRead(float _IsNew);
-
#endif
#ifdef SVQC
spawnfunc(item_strength);
bool ItemSend(entity this, entity to, int sf);
-float have_pickup_item(void);
+bool have_pickup_item(entity this);
const float ITEM_RESPAWN_TICKS = 10;
void Item_Show (entity e, float mode);
-void Item_Respawn (void);
+void Item_Respawn ();
-void Item_RespawnCountdown (void);
+void Item_RespawnCountdown ();
void Item_ScheduleRespawnIn(entity e, float t);
void Item_ScheduleRespawn(entity e);
float Item_GiveTo(entity item, entity player);
-void Item_Touch (void);
+void Item_Touch();
-void Item_Reset();
+void Item_Reset(entity this);
void Item_FindTeam();
// Savage: used for item garbage-collection
.float is_item;
.entity itemdef;
-void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, float defaultrespawntimejitter, string itemname, float itemid, float weaponid, float itemflags, float(entity player, entity item) pickupevalfunc, float pickupbasevalue);
-
+void _StartItem(entity this, entity def, float defaultrespawntime, float defaultrespawntimejitter);
-void target_items_use (void);
-const float OP_SET = 0;
-const float OP_MIN = 1;
-const float OP_MAX = 2;
-const float OP_PLUS = 3;
-const float OP_MINUS = 4;
+void target_items_use ();
float GiveWeapon(entity e, float wpn, float op, float val);
#include "../common/weapons/all.qh"
-#include "../common/buffs/all.qh"
spawnfunc(weapon_crylink);
spawnfunc(weapon_electro);
spawnfunc(item_flight)
{
- if(!cvar("g_buffs") || !cvar("g_buffs_flight"))
- spawnfunc_item_jetpack(this);
- else
- buff_Init_Compat(self, BUFF_FLIGHT);
+ spawnfunc_item_jetpack(this);
}
.float notteam;
return versionmsg;
}
-string getwelcomemessage(void)
+string getwelcomemessage()
{
string s, modifications, motd;
modifications = strcat(modifications, ", No start weapons");
if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
modifications = strcat(modifications, ", Low gravity");
- if(g_cloaked && !g_cts)
- modifications = strcat(modifications, ", Cloaked");
if(g_weapon_stay && !g_cts)
modifications = strcat(modifications, ", Weapons stay");
if(g_jetpack)
// since this is an engine function, and gamecode doesn't have any calls earlier than this, do the connecting message here
if(!IS_CLIENT(self))
- Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_CONNECTING, self.netname);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_CONNECTING, self.netname);
SetPlayerTeam(self, dteam, steam, !IS_CLIENT(self));
string GetClientVersionMessage();
-string getwelcomemessage(void);
+string getwelcomemessage();
void SetPlayerColors(entity pl, float _color);
#include "../../common/util.qh"
#include "../../common/weapons/all.qh"
-float accuracy_byte(float n, float d)
+int accuracy_byte(float n, float d)
{
- //printf("accuracy: %d / %d\n", n, d);
- if(n <= 0)
- return 0;
- if(n > d)
- return 255;
+ if (n <= 0) return 0;
+ if (n > d) return 255;
return 1 + rint(n * 100.0 / d);
}
bool accuracy_send(entity this, entity to, int sf)
{
- int w, f;
- entity a;
- WriteByte(MSG_ENTITY, ENT_CLIENT_ACCURACY);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_ACCURACY);
- a = self.owner;
- if(IS_SPEC(a))
- a = a.enemy;
+ entity a = this.owner;
+ if (IS_SPEC(a)) a = a.enemy;
a = a.accuracy;
- if(to != a.owner)
- if (!(self.owner.cvar_cl_accuracy_data_share && autocvar_sv_accuracy_data_share))
+ if (to != a.owner)
+ if (!autocvar_sv_accuracy_data_share && !a.owner.cvar_cl_accuracy_data_share)
sf = 0;
// note: zero sendflags can never be sent... so we can use that to say that we send no accuracy!
WriteInt24_t(MSG_ENTITY, sf);
- if(sf == 0)
- return true;
+ if (sf == 0) return true;
// note: we know that client and server agree about SendFlags...
- for(w = 0, f = 1; w <= WEP_LAST - WEP_FIRST; ++w)
- {
- if(sf & f)
- WriteByte(MSG_ENTITY, accuracy_byte(self.(accuracy_hit[w]), self.(accuracy_fired[w])));
- if(f == 0x800000)
- f = 1;
- else
- f *= 2;
+ int f = 1;
+ for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w) {
+ if (sf & f) WriteByte(MSG_ENTITY, accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]));
+ f = (f == 0x800000) ? 1 : f * 2;
}
return true;
}
// init/free
void accuracy_init(entity e)
{
- e.accuracy = spawn();
- e.accuracy.owner = e;
- e.accuracy.classname = "accuracy";
- e.accuracy.drawonlytoclient = e;
- Net_LinkEntity(e.accuracy, false, 0, accuracy_send);
+ entity a = e.accuracy = new(accuracy);
+ make_pure(a);
+ a.owner = e;
+ a.drawonlytoclient = e;
+ Net_LinkEntity(a, false, 0, accuracy_send);
}
void accuracy_free(entity e)
.float hit_time;
.float fired_time;
-void accuracy_add(entity e, int w, float fired, float hit)
+void accuracy_add(entity this, int w, int fired, int hit)
{
- entity a;
- float b;
- if(IS_INDEPENDENT_PLAYER(e))
- return;
- a = e.accuracy;
- if(!a || !(hit || fired))
- return;
+ if (IS_INDEPENDENT_PLAYER(this)) return;
+ entity a = this.accuracy;
+ if (!a) return;
+ if (!hit && !fired) return;
w -= WEP_FIRST;
- b = accuracy_byte(a.(accuracy_hit[w]), a.(accuracy_fired[w]));
- if(hit)
- a.(accuracy_hit[w]) += hit;
- if(fired)
- a.(accuracy_fired[w]) += fired;
-
- if(hit && a.hit_time != time) // only run this once per frame
- {
- a.(accuracy_cnt_hit[w]) += 1;
+ int b = accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]);
+ if (hit) a.accuracy_hit [w] += hit;
+ if (fired) a.accuracy_fired[w] += fired;
+
+ if (hit && a.hit_time != time) { // only run this once per frame
+ a.accuracy_cnt_hit[w] += 1;
a.hit_time = time;
}
- if(fired && a.fired_time != time) // only run this once per frame
- {
- a.(accuracy_cnt_fired[w]) += 1;
+ if (fired && a.fired_time != time) { // only run this once per frame
+ a.accuracy_cnt_fired[w] += 1;
a.fired_time = time;
}
- if(b == accuracy_byte(a.(accuracy_hit[w]), a.(accuracy_fired[w])))
- return;
- w = pow(2, w % 24);
- a.SendFlags |= w;
- FOR_EACH_CLIENT(a)
- if(IS_SPEC(a))
- if(a.enemy == e)
- a.SendFlags |= w;
+ if (b == accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w])) return; // no change
+ int sf = 1 << (w % 24);
+ a.SendFlags |= sf;
+ entity e; FOR_EACH_CLIENT(e) if (IS_SPEC(e)) if (e.enemy == this) {
+ e.accuracy.SendFlags |= sf;
+ }
}
-float accuracy_isgooddamage(entity attacker, entity targ)
+bool accuracy_isgooddamage(entity attacker, entity targ)
{
- float mutator_check = MUTATOR_CALLHOOK(AccuracyTargetValid, attacker, targ);
-
- if(!warmup_stage)
- if(targ.deadflag == DEAD_NO)
- if(!targ.frozen)
- if(mutator_check == MUT_ACCADD_INVALID || (mutator_check == MUT_ACCADD_VALID && IS_CLIENT(targ)))
- if(DIFF_TEAM(attacker, targ))
- return true;
- return false;
+ int mutator_check = MUTATOR_CALLHOOK(AccuracyTargetValid, attacker, targ);
+
+ if (warmup_stage) return false;
+ if (targ.deadflag != DEAD_NO) return false;
+ if (targ.frozen) return false;
+ if (SAME_TEAM(attacker, targ)) return false;
+
+ if (mutator_check == MUT_ACCADD_INVALID) return true;
+
+ if (mutator_check != MUT_ACCADD_VALID) return false;
+ if (!IS_CLIENT(targ)) return false;
+
+ return true;
}
-float accuracy_canbegooddamage(entity attacker)
+bool accuracy_canbegooddamage(entity attacker)
{
- if(!warmup_stage)
- return true;
- return false;
+ return !warmup_stage;
}
#ifndef ACCURACY_H
#define ACCURACY_H
-.float cvar_cl_accuracy_data_share;
-.float cvar_cl_accuracy_data_receive;
+.bool cvar_cl_accuracy_data_share;
+REPLICATE(cvar_cl_accuracy_data_share, bool, "cl_accuracy_data_share");
+.bool cvar_cl_accuracy_data_receive;
+REPLICATE(cvar_cl_accuracy_data_receive, bool, "cl_accuracy_data_receive");
.entity accuracy;
.float accuracy_frags[Weapons_MAX];
void accuracy_add(entity e, float w, float fired, float hit);
// helper
-float accuracy_isgooddamage(entity attacker, entity targ);
-float accuracy_canbegooddamage(entity attacker);
+bool accuracy_isgooddamage(entity attacker, entity targ);
+bool accuracy_canbegooddamage(entity attacker);
#endif
self.realowner = attacker;
}
+ MUTATOR_CALLHOOK(PrepareExplosionByDamage, self, attacker);
+
// do not explode NOW but in the NEXT FRAME!
// because recursive calls to RadiusDamage are not allowed
self.nextthink = time;
if(self.gravity != 0)
sf |= 0x10;
- WriteByte(MSG_ENTITY, ENT_CLIENT_PROJECTILE);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_PROJECTILE);
WriteByte(MSG_ENTITY, sf);
if(sf & 1)
void Send_WeaponComplain(entity e, float wpn, float type)
{
msg_entity = e;
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_WEAPONCOMPLAIN);
+ WriteHeader(MSG_ONE, TE_CSQC_WEAPONCOMPLAIN);
WriteByte(MSG_ONE, wpn);
WriteByte(MSG_ONE, type);
}
}
// previously used if exists and has ammo, (second) best otherwise
-void W_LastWeapon(void)
+void W_LastWeapon()
{SELFPARAM();
if(client_hasweapon(self, self.cnt, true, false))
W_SwitchWeapon(self.cnt);
void W_PreviousWeapon(float list);
// previously used if exists and has ammo, (second) best otherwise
-void W_LastWeapon(void);
+void W_LastWeapon();
#endif
return substring(out, 1, -1);
}
-void weapon_defaultspawnfunc(float wpn)
-{SELFPARAM();
- entity e;
- float t;
- string s;
- float i, j;
- int f;
-
- if(self.classname != "droppedweapon" && self.classname != "replacedweapon")
+void weapon_defaultspawnfunc(entity this, Weapon e)
+{
+ int wpn = e.m_id;
+ if (this.classname != "droppedweapon" && this.classname != "replacedweapon")
{
- e = get_weaponinfo(wpn);
-
- if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
+ if (e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
{
objerror("Attempted to spawn a mutator-blocked weapon rejected");
startitem_failed = true;
return;
}
- s = W_Apply_Weaponreplace(e.netname);
- MUTATOR_CALLHOOK(SetWeaponreplace, self, e, s);
+ string s = W_Apply_Weaponreplace(e.netname);
+ MUTATOR_CALLHOOK(SetWeaponreplace, this, e, s);
s = ret_string;
- if(s == "")
+ if (s == "")
{
- remove(self);
+ remove(this);
startitem_failed = true;
return;
}
- t = tokenize_console(s);
- if(t >= 2)
+ int t = tokenize_console(s);
+ if (t >= 2)
{
- self.team = --internalteam;
- for(i = 1; i < t; ++i)
+ this.team = --internalteam;
+ for (int i = 1; i < t; ++i)
{
s = argv(i);
- for(j = WEP_FIRST; j <= WEP_LAST; ++j)
+ int j;
+ for (j = WEP_FIRST; j <= WEP_LAST; ++j)
{
e = get_weaponinfo(j);
- if(e.netname == s)
+ if (e.netname == s)
{
- setself(spawn());
- copyentity(this, self);
- self.classname = "replacedweapon";
- weapon_defaultspawnfunc(j);
+ entity replacement = spawn();
+ copyentity(this, replacement);
+ replacement.classname = "replacedweapon";
+ weapon_defaultspawnfunc(replacement, e);
break;
}
}
- if(j > WEP_LAST)
+ if (j > WEP_LAST)
{
LOG_INFO("The weapon replace list for ", this.classname, " contains an unknown weapon ", s, ". Skipped.\n");
}
}
- setself(this);
}
- if(t >= 1) // always the case!
+ if (t >= 1) // always the case!
{
s = argv(0);
wpn = 0;
- for(j = WEP_FIRST; j <= WEP_LAST; ++j)
+ int j;
+ for (j = WEP_FIRST; j <= WEP_LAST; ++j)
{
e = get_weaponinfo(j);
- if(e.netname == s)
+ if (e.netname == s)
{
wpn = j;
break;
}
}
- if(j > WEP_LAST)
+ if (j > WEP_LAST)
{
- LOG_INFO("The weapon replace list for ", self.classname, " contains an unknown weapon ", s, ". Skipped.\n");
+ LOG_INFO("The weapon replace list for ", this.classname, " contains an unknown weapon ", s, ". Skipped.\n");
}
}
- if(wpn == 0)
+ if (wpn == 0)
{
- remove(self);
+ remove(this);
startitem_failed = true;
return;
}
e = get_weaponinfo(wpn);
- if(!self.respawntime)
+ if (!this.respawntime)
{
- if(e.weapons & WEPSET_SUPERWEAPONS)
+ if (e.weapons & WEPSET_SUPERWEAPONS)
{
- self.respawntime = g_pickup_respawntime_superweapon;
- self.respawntimejitter = g_pickup_respawntimejitter_superweapon;
+ this.respawntime = g_pickup_respawntime_superweapon;
+ this.respawntimejitter = g_pickup_respawntimejitter_superweapon;
}
else
{
- self.respawntime = g_pickup_respawntime_weapon;
- self.respawntimejitter = g_pickup_respawntimejitter_weapon;
+ this.respawntime = g_pickup_respawntime_weapon;
+ this.respawntimejitter = g_pickup_respawntimejitter_weapon;
}
}
- if(e.weapons & WEPSET_SUPERWEAPONS)
- if(!self.superweapons_finished)
- self.superweapons_finished = autocvar_g_balance_superweapons_time;
+ if (e.weapons & WEPSET_SUPERWEAPONS)
+ if (!this.superweapons_finished)
+ this.superweapons_finished = autocvar_g_balance_superweapons_time;
// if we don't already have ammo, give us some ammo
- if(!self.(e.ammo_field))
+ if (!this.(e.ammo_field))
{
- switch(e.ammo_field)
+ switch (e.ammo_field)
{
- case ammo_shells: self.ammo_shells = cvar("g_pickup_shells_weapon"); break;
- case ammo_nails: self.ammo_nails = cvar("g_pickup_nails_weapon"); break;
- case ammo_rockets: self.ammo_rockets = cvar("g_pickup_rockets_weapon"); break;
- case ammo_cells: self.ammo_cells = cvar("g_pickup_cells_weapon"); break;
- case ammo_plasma: self.ammo_plasma = cvar("g_pickup_plasma_weapon"); break;
- case ammo_fuel: self.ammo_fuel = cvar("g_pickup_fuel_weapon"); break;
+ case ammo_shells: this.ammo_shells = cvar("g_pickup_shells_weapon"); break;
+ case ammo_nails: this.ammo_nails = cvar("g_pickup_nails_weapon"); break;
+ case ammo_rockets: this.ammo_rockets = cvar("g_pickup_rockets_weapon"); break;
+ case ammo_cells: this.ammo_cells = cvar("g_pickup_cells_weapon"); break;
+ case ammo_plasma: this.ammo_plasma = cvar("g_pickup_plasma_weapon"); break;
+ case ammo_fuel: this.ammo_fuel = cvar("g_pickup_fuel_weapon"); break;
}
}
#if 0 // WEAPONTODO
- if(e.items)
+ if (e.items)
{
- for(i = 0, j = 1; i < 24; ++i, j *= 2)
+ for (int i = 0, j = 1; i < 24; ++i, j <<= 1)
{
- if(e.items & j)
+ if (e.items & j)
{
ammotype = Item_CounterField(j);
- if(!self.ammotype)
- self.ammotype = cvar(strcat("g_pickup_", Item_CounterFieldName(j), "_weapon"));
+ if (!this.ammotype)
+ this.ammotype = cvar(strcat("g_pickup_", Item_CounterFieldName(j), "_weapon"));
}
}
}
#endif
// pickup anyway
- if(g_pickup_weapons_anyway)
- self.pickup_anyway = true;
-
- f = FL_WEAPON;
-
- // no weapon-stay on superweapons
- if(e.weapons & WEPSET_SUPERWEAPONS)
- f |= FL_NO_WEAPON_STAY;
-
- // weapon stay isn't supported for teamed weapons
- if(self.team)
- f |= FL_NO_WEAPON_STAY;
-
- StartItem(strzone(e.m_model.model_str()), string_null, self.respawntime, self.respawntimejitter, e.message, 0, e.weapon, f, weapon_pickupevalfunc, e.bot_pickupbasevalue);
- self.item_pickupsound_ent = SND_WEAPONPICKUP;
+ if (g_pickup_weapons_anyway)
+ this.pickup_anyway = true;
+
+ GameItem def = e.m_pickup;
+ _StartItem(
+ this,
+ this.itemdef = def,
+ this.respawntime, // defaultrespawntime
+ this.respawntimejitter // defaultrespawntimejitter
+ );
#if 0 // WEAPONTODO
- if (self.modelindex) { // don't precache if self was removed
- Weapon w = get_weaponinfo(e.weapon);
- w.wr_init(w);
+ if (this.modelindex) { // don't precache if this was removed
+ e.wr_init(e);
}
#endif
}
string W_Apply_Weaponreplace(string in);
-void weapon_defaultspawnfunc(float wpn);
+void weapon_defaultspawnfunc(entity this, Weapon e);
#endif
{SELFPARAM();
float thisammo, i;
string s;
- var .int ammotype = (get_weaponinfo(wpn)).ammo_field;
+ Weapon info = get_weaponinfo(wpn);
+ var .int ammotype = info.ammo_field;
- entity wep = spawn();
+ entity wep = new(droppedweapon);
setorigin(wep, org);
- wep.classname = "droppedweapon";
wep.velocity = velo;
wep.owner = wep.enemy = own;
wep.flags |= FL_TOSSED;
}
}
- WITH(entity, self, wep, weapon_defaultspawnfunc(wpn));
+ weapon_defaultspawnfunc(wep, info);
if(startitem_failed)
return string_null;
wep.glowmod = own.weaponentity_glowmod;
return;
if(!autocvar_g_weapon_throwable)
return;
- if(self.weaponentity.state != WS_READY)
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+ if(self.(weaponentity).state != WS_READY)
return;
if(!W_IsWeaponThrowable(w))
return;
W_HitPlotAnalysis(ent, v_forward, v_right, v_up);
- if(ent.weaponentity.movedir.x > 0)
- vecs = ent.weaponentity.movedir;
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+ vector md = ent.(weaponentity).movedir;
+ if(md.x > 0)
+ vecs = md;
else
vecs = '0 0 0';
float total_damage = 0;
if(tracereffects & EF_RED)
- fireBullet_trace_callback_eff = particleeffectnum(EFFECT_RIFLE);
+ fireBullet_trace_callback_eff = EFFECT_RIFLE;
else if(tracereffects & EF_BLUE)
- fireBullet_trace_callback_eff = particleeffectnum(EFFECT_RIFLE_WEAK);
+ fireBullet_trace_callback_eff = EFFECT_RIFLE_WEAK;
else
- fireBullet_trace_callback_eff = particleeffectnum(EFFECT_BULLET);
+ fireBullet_trace_callback_eff = EFFECT_BULLET;
float lag = ANTILAG_LATENCY(self);
if(lag < 0.001)
.vector railgunforce;
void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype);
-float fireBullet_trace_callback_eff;
+entity fireBullet_trace_callback_eff;
entity fireBullet_last_hit;
void fireBullet_trace_callback(vector start, vector hit, vector end);
void fireBullet(vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, int tracereffects);
vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn)
{
- switch(algn)
+ switch (algn)
{
default: case 3: break; // right alignment
- case 4: vecs.y = -vecs.y; break; // left
- case 1: case 2: vecs.y = 0; vecs.z -= 2; break; // center
+ case 4: vecs.y = -vecs.y;
+ break; // left
+ case 1: case 2: vecs.y = 0;
+ vecs.z -= 2;
+ break; // center
}
return vecs;
{
string s;
- if(visual)
+ if (visual)
+ {
vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
- else if(autocvar_g_shootfromeye)
+ }
+ else if (autocvar_g_shootfromeye)
+ {
vecs.y = vecs.z = 0;
- else if(autocvar_g_shootfromcenter)
+ }
+ else if (autocvar_g_shootfromcenter)
{
vecs.y = 0;
vecs.z -= 2;
}
- else if((s = autocvar_g_shootfromfixedorigin) != "")
+ else if ((s = autocvar_g_shootfromfixedorigin) != "")
{
vector v = stov(s);
- if(y_is_right) { v.y = -v.y; }
- if(v.x != 0) { vecs.x = v.x; }
+ if (y_is_right) v.y = -v.y;
+ if (v.x != 0) vecs.x = v.x;
vecs.y = v.y;
vecs.z = v.z;
}
- else // just do the same as top
+ else // just do the same as top
+ {
vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
+ }
return vecs;
}
}
-void weapon_thinkf(entity actor, float fr, float t, void(Weapon thiswep, entity actor, bool fire1, bool fire2) func);
+void weapon_thinkf(entity actor, .entity weaponentity, float fr, float t, void(Weapon thiswep, entity actor,
+ .entity weaponentity, int fire) func);
-float CL_Weaponentity_CustomizeEntityForClient()
-{SELFPARAM();
- self.viewmodelforclient = self.owner;
- if(IS_SPEC(other))
- if(other.enemy == self.owner)
- self.viewmodelforclient = other;
+bool CL_Weaponentity_CustomizeEntityForClient()
+{
+ SELFPARAM();
+ this.viewmodelforclient = this.owner;
+ if (IS_SPEC(other) && other.enemy == this.owner) this.viewmodelforclient = other;
return true;
}
*/
// writes:
-// self.origin, self.angles
-// self.weaponentity
-// self.movedir, self.view_ofs
+// this.origin, this.angles
+// this.weaponentity
+// this.movedir, this.view_ofs
// attachment stuff
// anim stuff
// to free:
// call again with ""
// remove the ent
-void CL_WeaponEntity_SetModel(string name)
-{SELFPARAM();
- float v_shot_idx;
+void CL_WeaponEntity_SetModel(entity this, .entity weaponentity, string name)
+{
if (name != "")
{
// if there is a child entity, hide it until we're sure we use it
- if (self.weaponentity)
- self.weaponentity.model = "";
- _setmodel(self, W_Model(strcat("v_", name, ".md3")));
- v_shot_idx = gettagindex(self, "shot"); // used later
- if(!v_shot_idx)
- v_shot_idx = gettagindex(self, "tag_shot");
-
- _setmodel(self, W_Model(strcat("h_", name, ".iqm")));
+ if (this.(weaponentity)) this.(weaponentity).model = "";
+ _setmodel(this, W_Model(strcat("v_", name, ".md3")));
+ int v_shot_idx = gettagindex(this, "shot"); // used later
+ if (!v_shot_idx) v_shot_idx = gettagindex(this, "tag_shot");
+
+ _setmodel(this, W_Model(strcat("h_", name, ".iqm")));
// preset some defaults that work great for renamed zym files (which don't need an animinfo)
- self.anim_fire1 = animfixfps(self, '0 1 0.01', '0 0 0');
- self.anim_fire2 = animfixfps(self, '1 1 0.01', '0 0 0');
- self.anim_idle = animfixfps(self, '2 1 0.01', '0 0 0');
- self.anim_reload = animfixfps(self, '3 1 0.01', '0 0 0');
+ this.anim_fire1 = animfixfps(this, '0 1 0.01', '0 0 0');
+ this.anim_fire2 = animfixfps(this, '1 1 0.01', '0 0 0');
+ this.anim_idle = animfixfps(this, '2 1 0.01', '0 0 0');
+ this.anim_reload = animfixfps(this, '3 1 0.01', '0 0 0');
// if we have a "weapon" tag, let's attach the v_ model to it ("invisible hand" style model)
// if we don't, this is a "real" animated model
- if(gettagindex(self, "weapon"))
+ if (gettagindex(this, "weapon"))
{
- if (!self.weaponentity)
- self.weaponentity = spawn();
- _setmodel(self.weaponentity, W_Model(strcat("v_", name, ".md3")));
- setattachment(self.weaponentity, self, "weapon");
+ if (!this.(weaponentity)) this.(weaponentity) = new(weaponentity);
+ _setmodel(this.(weaponentity), W_Model(strcat("v_", name, ".md3")));
+ setattachment(this.(weaponentity), this, "weapon");
}
- else if(gettagindex(self, "tag_weapon"))
+ else if (gettagindex(this, "tag_weapon"))
{
- if (!self.weaponentity)
- self.weaponentity = spawn();
- _setmodel(self.weaponentity, W_Model(strcat("v_", name, ".md3")));
- setattachment(self.weaponentity, self, "tag_weapon");
+ if (!this.(weaponentity)) this.(weaponentity) = new(weaponentity);
+ _setmodel(this.(weaponentity), W_Model(strcat("v_", name, ".md3")));
+ setattachment(this.(weaponentity), this, "tag_weapon");
}
else
{
- if(self.weaponentity)
- remove(self.weaponentity);
- self.weaponentity = world;
+ if (this.(weaponentity)) remove(this.(weaponentity));
+ this.(weaponentity) = NULL;
}
- setorigin(self,'0 0 0');
- self.angles = '0 0 0';
- self.frame = 0;
- self.viewmodelforclient = world;
+ setorigin(this, '0 0 0');
+ this.angles = '0 0 0';
+ this.frame = 0;
+ this.viewmodelforclient = NULL;
float idx;
- if(v_shot_idx) // v_ model attached to invisible h_ model
+ if (v_shot_idx) // v_ model attached to invisible h_ model
{
- self.movedir = gettaginfo(self.weaponentity, v_shot_idx);
+ this.movedir = gettaginfo(this.(weaponentity), v_shot_idx);
}
else
{
- idx = gettagindex(self, "shot");
- if(!idx)
- idx = gettagindex(self, "tag_shot");
- if(idx)
- self.movedir = gettaginfo(self, idx);
+ idx = gettagindex(this, "shot");
+ if (!idx) idx = gettagindex(this, "tag_shot");
+ if (idx)
+ {
+ this.movedir = gettaginfo(this, idx);
+ }
else
{
- LOG_INFO("WARNING: weapon model ", self.model, " does not support the 'shot' tag, will display shots TOTALLY wrong\n");
- self.movedir = '0 0 0';
+ LOG_INFO("WARNING: weapon model ", this.model,
+ " does not support the 'shot' tag, will display shots TOTALLY wrong\n");
+ this.movedir = '0 0 0';
}
}
- if(self.weaponentity) // v_ model attached to invisible h_ model
+ if (this.(weaponentity)) // v_ model attached to invisible h_ model
{
- idx = gettagindex(self.weaponentity, "shell");
- if(!idx)
- idx = gettagindex(self.weaponentity, "tag_shell");
- if(idx)
- self.spawnorigin = gettaginfo(self.weaponentity, idx);
+ idx = gettagindex(this.(weaponentity), "shell");
+ if (!idx) idx = gettagindex(this.(weaponentity), "tag_shell");
+ if (idx) this.spawnorigin = gettaginfo(this.(weaponentity), idx);
}
else
+ {
idx = 0;
- if(!idx)
+ }
+ if (!idx)
{
- idx = gettagindex(self, "shell");
- if(!idx)
- idx = gettagindex(self, "tag_shell");
- if(idx)
- self.spawnorigin = gettaginfo(self, idx);
+ idx = gettagindex(this, "shell");
+ if (!idx) idx = gettagindex(this, "tag_shell");
+ if (idx)
+ {
+ this.spawnorigin = gettaginfo(this, idx);
+ }
else
{
- LOG_INFO("WARNING: weapon model ", self.model, " does not support the 'shell' tag, will display casings wrong\n");
- self.spawnorigin = self.movedir;
+ LOG_INFO("WARNING: weapon model ", this.model,
+ " does not support the 'shell' tag, will display casings wrong\n");
+ this.spawnorigin = this.movedir;
}
}
- if(v_shot_idx)
+ if (v_shot_idx)
{
- self.oldorigin = '0 0 0'; // use regular attachment
+ this.oldorigin = '0 0 0'; // use regular attachment
}
else
{
- if(self.weaponentity)
+ if (this.(weaponentity))
{
- idx = gettagindex(self, "weapon");
- if(!idx)
- idx = gettagindex(self, "tag_weapon");
+ idx = gettagindex(this, "weapon");
+ if (!idx) idx = gettagindex(this, "tag_weapon");
}
else
{
- idx = gettagindex(self, "handle");
- if(!idx)
- idx = gettagindex(self, "tag_handle");
+ idx = gettagindex(this, "handle");
+ if (!idx) idx = gettagindex(this, "tag_handle");
}
- if(idx)
+ if (idx)
{
- self.oldorigin = self.movedir - gettaginfo(self, idx);
+ this.oldorigin = this.movedir - gettaginfo(this, idx);
}
else
{
- LOG_INFO("WARNING: weapon model ", self.model, " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n");
- self.oldorigin = '0 0 0'; // there is no way to recover from this
+ LOG_INFO("WARNING: weapon model ", this.model,
+ " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n");
+ this.oldorigin = '0 0 0'; // there is no way to recover from this
}
}
- self.viewmodelforclient = self.owner;
+ this.viewmodelforclient = this.owner;
}
else
{
- self.model = "";
- if(self.weaponentity)
- remove(self.weaponentity);
- self.weaponentity = world;
- self.movedir = '0 0 0';
- self.spawnorigin = '0 0 0';
- self.oldorigin = '0 0 0';
- self.anim_fire1 = '0 1 0.01';
- self.anim_fire2 = '0 1 0.01';
- self.anim_idle = '0 1 0.01';
- self.anim_reload = '0 1 0.01';
+ this.model = "";
+ if (this.(weaponentity)) remove(this.(weaponentity));
+ this.(weaponentity) = NULL;
+ this.movedir = '0 0 0';
+ this.spawnorigin = '0 0 0';
+ this.oldorigin = '0 0 0';
+ this.anim_fire1 = '0 1 0.01';
+ this.anim_fire2 = '0 1 0.01';
+ this.anim_idle = '0 1 0.01';
+ this.anim_reload = '0 1 0.01';
}
- self.view_ofs = '0 0 0';
+ this.view_ofs = '0 0 0';
- if(self.movedir.x >= 0)
+ if (this.movedir.x >= 0)
{
- vector v0;
- v0 = self.movedir;
- self.movedir = shotorg_adjust(v0, false, false, self.owner.cvar_cl_gunalign);
- self.view_ofs = shotorg_adjust(v0, false, true, self.owner.cvar_cl_gunalign) - v0;
+ vector v0 = this.movedir;
+ this.movedir = shotorg_adjust(v0, false, false, this.owner.cvar_cl_gunalign);
+ this.view_ofs = shotorg_adjust(v0, false, true, this.owner.cvar_cl_gunalign) - v0;
}
- self.owner.stat_shotorg = compressShotOrigin(self.movedir);
- self.movedir = decompressShotOrigin(self.owner.stat_shotorg); // make them match perfectly
+ this.owner.stat_shotorg = compressShotOrigin(this.movedir);
+ this.movedir = decompressShotOrigin(this.owner.stat_shotorg); // make them match perfectly
- self.spawnorigin += self.view_ofs; // offset the casings origin by the same amount
+ this.spawnorigin += this.view_ofs; // offset the casings origin by the same amount
// check if an instant weapon switch occurred
- setorigin(self, self.view_ofs);
+ setorigin(this, this.view_ofs);
// reset animstate now
- self.wframe = WFRAME_IDLE;
- setanim(self, self.anim_idle, true, false, true);
+ this.wframe = WFRAME_IDLE;
+ setanim(this, this.anim_idle, true, false, true);
}
vector CL_Weapon_GetShotOrg(float wpn)
-{SELFPARAM();
- entity wi = get_weaponinfo(wpn);
- setself(spawn());
- CL_WeaponEntity_SetModel(wi.mdl);
- vector ret = self.movedir;
- CL_WeaponEntity_SetModel("");
- remove(self);
- setself(this);
+{
+ entity wi = Weapons_from(wpn);
+ entity e = spawn();
+ .entity weaponentity = weaponentities[0];
+ CL_WeaponEntity_SetModel(e, weaponentity, wi.mdl);
+ vector ret = e.movedir;
+ CL_WeaponEntity_SetModel(e, weaponentity, "");
+ remove(e);
return ret;
}
+..entity weaponentity_fld;
+
void CL_Weaponentity_Think()
-{SELFPARAM();
- int tb;
- self.nextthink = time;
- if (intermission_running)
- self.frame = self.anim_idle.x;
- if (self.owner.weaponentity != self)
+{
+ SELFPARAM();
+ this.nextthink = time;
+ if (intermission_running) this.frame = this.anim_idle.x;
+ .entity weaponentity = this.weaponentity_fld;
+ if (this.owner.(weaponentity) != this)
{
- if (self.weaponentity)
- remove(self.weaponentity);
- remove(self);
+ if (this.(weaponentity)) remove(this.(weaponentity));
+ remove(this);
return;
}
- if (self.owner.deadflag != DEAD_NO)
+ if (this.owner.deadflag != DEAD_NO)
{
- self.model = "";
- if (self.weaponentity)
- self.weaponentity.model = "";
+ this.model = "";
+ if (this.(weaponentity)) this.(weaponentity).model = "";
return;
}
- if (self.weaponname != self.owner.weaponname || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag)
+ if (this.weaponname != this.owner.weaponname || this.dmg != this.owner.modelindex
+ || this.deadflag != this.owner.deadflag)
{
- self.weaponname = self.owner.weaponname;
- self.dmg = self.owner.modelindex;
- self.deadflag = self.owner.deadflag;
+ this.weaponname = this.owner.weaponname;
+ this.dmg = this.owner.modelindex;
+ this.deadflag = this.owner.deadflag;
- CL_WeaponEntity_SetModel(self.owner.weaponname);
+ CL_WeaponEntity_SetModel(this, weaponentity, this.owner.weaponname);
}
- tb = (self.effects & (EF_TELEPORT_BIT | EF_RESTARTANIM_BIT));
- self.effects = self.owner.effects & EFMASK_CHEAP;
- self.effects &= ~EF_LOWPRECISION;
- self.effects &= ~EF_FULLBRIGHT; // can mask team color, so get rid of it
- self.effects &= ~EF_TELEPORT_BIT;
- self.effects &= ~EF_RESTARTANIM_BIT;
- self.effects |= tb;
-
- if(self.owner.alpha == default_player_alpha)
- self.alpha = default_weapon_alpha;
- else if(self.owner.alpha != 0)
- self.alpha = self.owner.alpha;
- else
- self.alpha = 1;
-
- self.glowmod = self.owner.weaponentity_glowmod;
- self.colormap = self.owner.colormap;
- if (self.weaponentity)
+ int tb = (this.effects & (EF_TELEPORT_BIT | EF_RESTARTANIM_BIT));
+ this.effects = this.owner.effects & EFMASK_CHEAP;
+ this.effects &= ~EF_LOWPRECISION;
+ this.effects &= ~EF_FULLBRIGHT; // can mask team color, so get rid of it
+ this.effects &= ~EF_TELEPORT_BIT;
+ this.effects &= ~EF_RESTARTANIM_BIT;
+ this.effects |= tb;
+ if (weaponentity != weaponentities[0]) this.effects |= EF_NODRAW;
+
+ if (this.owner.alpha == default_player_alpha) this.alpha = default_weapon_alpha;
+ else if (this.owner.alpha != 0) this.alpha = this.owner.alpha;
+ else this.alpha = 1;
+
+ this.glowmod = this.owner.weaponentity_glowmod;
+ this.colormap = this.owner.colormap;
+ if (this.(weaponentity))
{
- self.weaponentity.effects = self.effects;
- self.weaponentity.alpha = self.alpha;
- self.weaponentity.colormap = self.colormap;
- self.weaponentity.glowmod = self.glowmod;
+ this.(weaponentity).effects = this.effects;
+ this.(weaponentity).alpha = this.alpha;
+ this.(weaponentity).colormap = this.colormap;
+ this.(weaponentity).glowmod = this.glowmod;
}
- self.angles = '0 0 0';
+ this.angles = '0 0 0';
- float f = (self.owner.weapon_nextthink - time);
- if (self.state == WS_RAISE && !intermission_running)
+ float f = this.weapon_nextthink - time;
+ if (this.state == WS_RAISE && !intermission_running)
{
- entity newwep = get_weaponinfo(self.owner.switchweapon);
+ entity newwep = Weapons_from(this.owner.switchweapon);
f = f * g_weaponratefactor / max(f, newwep.switchdelay_raise);
- self.angles_x = -90 * f * f;
+ this.angles_x = -90 * f * f;
}
- else if (self.state == WS_DROP && !intermission_running)
+ else if (this.state == WS_DROP && !intermission_running)
{
- entity oldwep = get_weaponinfo(self.owner.weapon);
+ entity oldwep = Weapons_from(this.owner.weapon);
f = 1 - f * g_weaponratefactor / max(f, oldwep.switchdelay_drop);
- self.angles_x = -90 * f * f;
+ this.angles_x = -90 * f * f;
}
- else if (self.state == WS_CLEAR)
+ else if (this.state == WS_CLEAR)
{
f = 1;
- self.angles_x = -90 * f * f;
+ this.angles_x = -90 * f * f;
}
}
void CL_ExteriorWeaponentity_Think()
-{SELFPARAM();
- float tag_found;
- self.nextthink = time;
- if (self.owner.exteriorweaponentity != self)
+{
+ SELFPARAM();
+ this.nextthink = time;
+ if (this.owner.exteriorweaponentity != this)
{
- remove(self);
+ remove(this);
return;
}
- if (self.owner.deadflag != DEAD_NO)
+ if (this.owner.deadflag != DEAD_NO)
{
- self.model = "";
+ this.model = "";
return;
}
- if (self.weaponname != self.owner.weaponname || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag)
+ if (this.weaponname != this.owner.weaponname || this.dmg != this.owner.modelindex
+ || this.deadflag != this.owner.deadflag)
{
- self.weaponname = self.owner.weaponname;
- self.dmg = self.owner.modelindex;
- self.deadflag = self.owner.deadflag;
- if (self.owner.weaponname != "")
- _setmodel(self, W_Model(strcat("v_", self.owner.weaponname, ".md3")));
- else
- self.model = "";
-
- if((tag_found = gettagindex(self.owner, "tag_weapon")))
+ this.weaponname = this.owner.weaponname;
+ this.dmg = this.owner.modelindex;
+ this.deadflag = this.owner.deadflag;
+ if (this.owner.weaponname != "") _setmodel(this, W_Model(strcat("v_", this.owner.weaponname, ".md3")));
+ else this.model = "";
+
+ int tag_found;
+ if ((tag_found = gettagindex(this.owner, "tag_weapon")))
{
- self.tag_index = tag_found;
- self.tag_entity = self.owner;
+ this.tag_index = tag_found;
+ this.tag_entity = this.owner;
}
else
- setattachment(self, self.owner, "bip01 r hand");
+ {
+ setattachment(this, this.owner, "bip01 r hand");
+ }
}
- self.effects = self.owner.effects;
- self.effects |= EF_LOWPRECISION;
- self.effects = self.effects & EFMASK_CHEAP; // eat performance
- if(self.owner.alpha == default_player_alpha)
- self.alpha = default_weapon_alpha;
- else if(self.owner.alpha != 0)
- self.alpha = self.owner.alpha;
- else
- self.alpha = 1;
+ this.effects = this.owner.effects;
+ this.effects |= EF_LOWPRECISION;
+ this.effects = this.effects & EFMASK_CHEAP; // eat performance
+ if (this.owner.alpha == default_player_alpha) this.alpha = default_weapon_alpha;
+ else if (this.owner.alpha != 0) this.alpha = this.owner.alpha;
+ else this.alpha = 1;
- self.glowmod = self.owner.weaponentity_glowmod;
- self.colormap = self.owner.colormap;
+ this.glowmod = this.owner.weaponentity_glowmod;
+ this.colormap = this.owner.colormap;
- CSQCMODEL_AUTOUPDATE(self);
+ CSQCMODEL_AUTOUPDATE(this);
}
// spawning weaponentity for client
-void CL_SpawnWeaponentity(entity e)
+void CL_SpawnWeaponentity(entity e, .entity weaponentity)
{
- entity view = e.weaponentity = spawn();
- view.classname = "weaponentity";
+ entity view = e.(weaponentity) = new(weaponentity);
+ make_pure(view);
view.solid = SOLID_NOT;
view.owner = e;
- setmodel(view, MDL_Null); // precision set when changed
+ setmodel(view, MDL_Null); // precision set when changed
setorigin(view, '0 0 0');
view.angles = '0 0 0';
view.viewmodelforclient = e;
view.flags = 0;
+ view.weaponentity_fld = weaponentity;
view.think = CL_Weaponentity_Think;
view.customizeentityforclient = CL_Weaponentity_CustomizeEntityForClient;
view.nextthink = time;
- entity exterior = e.exteriorweaponentity = spawn();
- exterior.classname = "exteriorweaponentity";
- exterior.solid = SOLID_NOT;
- exterior.exteriorweaponentity = exterior;
- exterior.owner = e;
- setorigin(exterior, '0 0 0');
- exterior.angles = '0 0 0';
- exterior.think = CL_ExteriorWeaponentity_Think;
- exterior.nextthink = time;
-
- CSQCMODEL_AUTOINIT(exterior);
+ if (weaponentity == weaponentities[0])
+ {
+ entity exterior = e.exteriorweaponentity = new(exteriorweaponentity);
+ make_pure(exterior);
+ exterior.solid = SOLID_NOT;
+ exterior.exteriorweaponentity = exterior;
+ exterior.owner = e;
+ setorigin(exterior, '0 0 0');
+ exterior.angles = '0 0 0';
+ exterior.think = CL_ExteriorWeaponentity_Think;
+ exterior.nextthink = time;
+
+ CSQCMODEL_AUTOINIT(exterior);
+ }
}
// Weapon subs
-void w_clear(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void w_clear(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
if (actor.weapon != -1)
{
actor.weapon = 0;
actor.switchingweapon = 0;
}
- if (actor.weaponentity)
+ entity this = actor.(weaponentity);
+ if (this)
{
- actor.weaponentity.state = WS_CLEAR;
- actor.weaponentity.effects = 0;
+ this.state = WS_CLEAR;
+ this.effects = 0;
}
}
-void w_ready(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
- if (actor.weaponentity)
- actor.weaponentity.state = WS_READY;
- weapon_thinkf(actor, WFRAME_IDLE, 1000000, w_ready);
+ entity this = actor.(weaponentity);
+ if (this) this.state = WS_READY;
+ weapon_thinkf(actor, weaponentity, WFRAME_IDLE, 1000000, w_ready);
}
.float prevdryfire;
.float prevwarntime;
-bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, float secondary)
+bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary)
{
if ((actor.items & IT_UNLIMITED_WEAPON_AMMO)) return true;
bool ammo = false;
- if (secondary) {
- WITH(entity, self, actor, ammo = thiswep.wr_checkammo2(thiswep));
- } else {
- WITH(entity, self, actor, ammo = thiswep.wr_checkammo1(thiswep));
- }
+ if (secondary) WITH(entity, self, actor, ammo = thiswep.wr_checkammo2(thiswep));
+ else WITH(entity, self, actor, ammo = thiswep.wr_checkammo1(thiswep));
if (ammo) return true;
// always keep the Mine Layer if we placed mines, so that we can detonate them
- entity mine;
- if(actor.weapon == WEP_MINE_LAYER.m_id)
- for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == actor)
- return false;
+ if (thiswep == WEP_MINE_LAYER)
+ for (entity mine; (mine = find(mine, classname, "mine")); )
+ if (mine.owner == actor) return false;
- if(actor.weapon == WEP_SHOTGUN.m_id)
- if(!secondary && WEP_CVAR(shotgun, secondary) == 1)
- return false; // no clicking, just allow
+ if (thiswep == WEP_SHOTGUN)
+ if (!secondary && WEP_CVAR(shotgun, secondary) == 1) return false; // no clicking, just allow
- if(actor.weapon == actor.switchweapon && time - actor.prevdryfire > 1) // only play once BEFORE starting to switch weapons
+ if (thiswep == Weapons_from(actor.switchweapon) && time - actor.prevdryfire > 1) // only play once BEFORE starting to switch weapons
{
- sound (actor, CH_WEAPON_A, SND_DRYFIRE, VOL_BASE, ATTEN_NORM);
+ sound(actor, CH_WEAPON_A, SND_DRYFIRE, VOL_BASE, ATTEN_NORM);
actor.prevdryfire = time;
}
// check if the other firing mode has enough ammo
bool ammo_other = false;
- if (secondary) {
- WITH(entity, self, actor, ammo = thiswep.wr_checkammo1(thiswep));
- } else {
- WITH(entity, self, actor, ammo = thiswep.wr_checkammo2(thiswep));
- }
+ if (secondary) WITH(entity, self, actor, ammo_other = thiswep.wr_checkammo1(thiswep));
+ else WITH(entity, self, actor, ammo_other = thiswep.wr_checkammo2(thiswep));
if (ammo_other)
{
if (time - actor.prevwarntime > 1)
actor,
MSG_MULTI,
ITEM_WEAPON_PRIMORSEC,
- actor.weapon,
+ thiswep.m_id,
secondary,
(1 - secondary)
- );
+ );
}
actor.prevwarntime = time;
}
- else // this weapon is totally unable to fire, switch to another one
+ else // this weapon is totally unable to fire, switch to another one
{
W_SwitchToOtherWeapon(actor);
}
return false;
}
+
.float race_penalty;
-bool weapon_prepareattack_check(Weapon thiswep, entity actor, bool secondary, float attacktime)
+bool weapon_prepareattack_check(Weapon thiswep, entity actor, .entity weaponentity, bool secondary, float attacktime)
{
- if(!weapon_prepareattack_checkammo(thiswep, actor, secondary))
- return false;
+ if (!weapon_prepareattack_checkammo(thiswep, actor, secondary)) return false;
- //if sv_ready_restart_after_countdown is set, don't allow the player to shoot
- //if all players readied up and the countdown is running
- if(time < game_starttime || time < actor.race_penalty) {
- return false;
- }
+ // if sv_ready_restart_after_countdown is set, don't allow the player to shoot
+ // if all players readied up and the countdown is running
+ if (time < game_starttime || time < actor.race_penalty) return false;
- if (timeout_status == TIMEOUT_ACTIVE) //don't allow the player to shoot while game is paused
+ if (timeout_status == TIMEOUT_ACTIVE) // don't allow the player to shoot while game is paused
return false;
// do not even think about shooting if switching
- if(actor.switchweapon != actor.weapon)
- return false;
+ if (actor.switchweapon != actor.weapon) return false;
- if(attacktime >= 0)
+ if (attacktime >= 0)
{
+ int slot = weaponslot(weaponentity);
// don't fire if previous attack is not finished
- if (ATTACK_FINISHED(actor) > time + actor.weapon_frametime * 0.5)
- return false;
+ if (ATTACK_FINISHED(actor, slot) > time + actor.weapon_frametime * 0.5) return false;
+ entity this = actor.(weaponentity);
// don't fire while changing weapon
- if (actor.weaponentity.state != WS_READY)
- return false;
+ if (this.state != WS_READY) return false;
}
return true;
}
-void weapon_prepareattack_do(entity actor, bool secondary, float attacktime)
+
+void weapon_prepareattack_do(entity actor, .entity weaponentity, bool secondary, float attacktime)
{
- actor.weaponentity.state = WS_INUSE;
+ entity this = actor.(weaponentity);
+ this.state = WS_INUSE;
- actor.spawnshieldtime = min(actor.spawnshieldtime, time); // kill spawn shield when you fire
+ actor.spawnshieldtime = min(actor.spawnshieldtime, time); // kill spawn shield when you fire
// if the weapon hasn't been firing continuously, reset the timer
- if(attacktime >= 0)
+ if (attacktime >= 0)
{
- if (ATTACK_FINISHED(actor) < time - actor.weapon_frametime * 1.5)
+ int slot = weaponslot(weaponentity);
+ if (ATTACK_FINISHED(actor, slot) < time - actor.weapon_frametime * 1.5)
{
- ATTACK_FINISHED(actor) = time;
- //dprint("resetting attack finished to ", ftos(time), "\n");
+ ATTACK_FINISHED(actor, slot) = time;
+ // dprint("resetting attack finished to ", ftos(time), "\n");
}
- ATTACK_FINISHED(actor) = ATTACK_FINISHED(actor) + attacktime * W_WeaponRateFactor();
+ ATTACK_FINISHED(actor, slot) = ATTACK_FINISHED(actor, slot) + attacktime * W_WeaponRateFactor();
}
actor.bulletcounter += 1;
- //dprint("attack finished ", ftos(ATTACK_FINISHED(actor)), "\n");
+ // dprint("attack finished ", ftos(ATTACK_FINISHED(actor, slot)), "\n");
}
-bool weapon_prepareattack(Weapon thiswep, entity actor, bool secondary, float attacktime)
+
+bool weapon_prepareattack(Weapon thiswep, entity actor, .entity weaponentity, bool secondary, float attacktime)
{
- if (weapon_prepareattack_check(thiswep, actor, secondary, attacktime)) {
- weapon_prepareattack_do(actor, secondary, attacktime);
+ if (weapon_prepareattack_check(thiswep, actor, weaponentity, secondary, attacktime))
+ {
+ weapon_prepareattack_do(actor, weaponentity, secondary, attacktime);
return true;
}
return false;
}
-void weapon_thinkf(entity actor, float fr, float t, void(Weapon thiswep, entity actor, bool fire1, bool fire2) func)
+void weapon_thinkf(entity actor, .entity weaponentity, float fr, float t, void(Weapon thiswep, entity actor,
+ .entity weaponentity, int fire) func)
{
- vector a;
- vector of, or, ou;
- float restartanim;
-
- if(fr == WFRAME_DONTCHANGE)
+ entity this = actor.(weaponentity);
+ bool restartanim;
+ if (fr == WFRAME_DONTCHANGE)
{
- fr = actor.weaponentity.wframe;
+ fr = this.wframe;
restartanim = false;
}
else if (fr == WFRAME_IDLE)
+ {
restartanim = false;
+ }
else
+ {
restartanim = true;
+ }
- of = v_forward;
- or = v_right;
- ou = v_up;
+ vector of = v_forward;
+ vector or = v_right;
+ vector ou = v_up;
- if (actor.weaponentity)
+ if (this)
{
- actor.weaponentity.wframe = fr;
- a = '0 0 0';
- if (fr == WFRAME_IDLE)
- a = actor.weaponentity.anim_idle;
- else if (fr == WFRAME_FIRE1)
- a = actor.weaponentity.anim_fire1;
- else if (fr == WFRAME_FIRE2)
- a = actor.weaponentity.anim_fire2;
- else // if (fr == WFRAME_RELOAD)
- a = actor.weaponentity.anim_reload;
+ this.wframe = fr;
+ vector a = '0 0 0';
+ if (fr == WFRAME_IDLE) a = this.anim_idle;
+ else if (fr == WFRAME_FIRE1) a = this.anim_fire1;
+ else if (fr == WFRAME_FIRE2) a = this.anim_fire2;
+ else // if (fr == WFRAME_RELOAD)
+ a = this.anim_reload;
a.z *= g_weaponratefactor;
- setanim(actor.weaponentity, a, restartanim == false, restartanim, restartanim);
+ setanim(this, a, restartanim == false, restartanim, restartanim);
}
v_forward = of;
v_right = or;
v_up = ou;
- if(actor.weapon_think == w_ready && func != w_ready && actor.weaponentity.state == WS_RAISE)
- {
- backtrace("Tried to override initial weapon think function - should this really happen?");
- }
+ if (this.weapon_think == w_ready && func != w_ready && this.state == WS_RAISE) backtrace(
+ "Tried to override initial weapon think function - should this really happen?");
t *= W_WeaponRateFactor();
// VorteX: haste can be added here
- if (actor.weapon_think == w_ready)
+ if (this.weapon_think == w_ready)
{
- actor.weapon_nextthink = time;
- //dprint("started firing at ", ftos(time), "\n");
+ this.weapon_nextthink = time;
+ // dprint("started firing at ", ftos(time), "\n");
}
- if (actor.weapon_nextthink < time - actor.weapon_frametime * 1.5 || actor.weapon_nextthink > time + actor.weapon_frametime * 1.5)
+ if (this.weapon_nextthink < time - actor.weapon_frametime * 1.5
+ || this.weapon_nextthink > time + actor.weapon_frametime * 1.5)
{
- actor.weapon_nextthink = time;
- //dprint("reset weapon animation timer at ", ftos(time), "\n");
+ this.weapon_nextthink = time;
+ // dprint("reset weapon animation timer at ", ftos(time), "\n");
}
- actor.weapon_nextthink = actor.weapon_nextthink + t;
- actor.weapon_think = func;
- //dprint("next ", ftos(actor.weapon_nextthink), "\n");
+ this.weapon_nextthink = this.weapon_nextthink + t;
+ this.weapon_think = func;
+ // dprint("next ", ftos(this.weapon_nextthink), "\n");
- if((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t)
+ if ((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t)
{
- if((actor.weapon == WEP_SHOCKWAVE.m_id || actor.weapon == WEP_SHOTGUN.m_id) && fr == WFRAME_FIRE2)
- animdecide_setaction(actor, ANIMACTION_MELEE, restartanim);
- else
- animdecide_setaction(actor, ANIMACTION_SHOOT, restartanim);
+ if ((actor.weapon == WEP_SHOCKWAVE.m_id || actor.weapon == WEP_SHOTGUN.m_id)
+ && fr == WFRAME_FIRE2) animdecide_setaction(actor, ANIMACTION_MELEE, restartanim);
+ else animdecide_setaction(actor, ANIMACTION_SHOOT, restartanim);
}
else
{
- if(actor.anim_upper_action == ANIMACTION_SHOOT || actor.anim_upper_action == ANIMACTION_MELEE)
- actor.anim_upper_action = 0;
+ if (actor.anim_upper_action == ANIMACTION_SHOOT
+ || actor.anim_upper_action == ANIMACTION_MELEE) actor.anim_upper_action = 0;
}
}
-float forbidWeaponUse(entity player)
+bool forbidWeaponUse(entity player)
{
- if(time < game_starttime && !autocvar_sv_ready_restart_after_countdown)
- return 1;
- if(round_handler_IsActive() && !round_handler_IsRoundStarted())
- return 1;
- if(player.player_blocked)
- return 1;
- if(player.frozen)
- return 1;
- if(player.weapon_blocked)
- return 1;
- return 0;
+ if (time < game_starttime && !autocvar_sv_ready_restart_after_countdown) return true;
+ if (round_handler_IsActive() && !round_handler_IsRoundStarted()) return true;
+ if (player.player_blocked) return true;
+ if (player.frozen) return true;
+ if (player.weapon_blocked) return true;
+ return false;
}
.bool hook_switchweapon;
void W_WeaponFrame(entity actor)
{
- vector fo, ri, up;
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+ entity this = actor.(weaponentity);
+ if (frametime) actor.weapon_frametime = frametime;
- if (frametime)
- actor.weapon_frametime = frametime;
+ if (!this || actor.health < 1) return; // Dead player can't use weapons and injure impulse commands
- if (!actor.weaponentity || actor.health < 1)
- return; // Dead player can't use weapons and injure impulse commands
- if(forbidWeaponUse(actor))
- if(actor.weaponentity.state != WS_CLEAR)
+ if (forbidWeaponUse(actor))
{
- Weapon wpn = get_weaponinfo(actor.weapon);
- w_ready(wpn, actor, actor.BUTTON_ATCK, actor.BUTTON_ATCK2);
- return;
+ if (actor.(weaponentity).state != WS_CLEAR)
+ {
+ Weapon wpn = Weapons_from(actor.weapon);
+ w_ready(wpn, actor, weaponentity, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0));
+ return;
+ }
}
- if(!actor.switchweapon)
+ if (actor.switchweapon == 0)
{
actor.weapon = 0;
actor.switchingweapon = 0;
- actor.weaponentity.state = WS_CLEAR;
+ this.state = WS_CLEAR;
actor.weaponname = "";
- //actor.items &= ~IT_AMMO;
+ // actor.items &= ~IT_AMMO;
return;
}
makevectors(actor.v_angle);
- fo = v_forward; // save them in case the weapon think functions change it
- ri = v_right;
- up = v_up;
+ vector fo = v_forward; // save them in case the weapon think functions change it
+ vector ri = v_right;
+ vector up = v_up;
// Change weapon
if (actor.weapon != actor.switchweapon)
{
- if (actor.weaponentity.state == WS_CLEAR)
+ switch (this.state)
{
- // end switching!
- actor.switchingweapon = actor.switchweapon;
- entity newwep = get_weaponinfo(actor.switchweapon);
-
- // the two weapon entities will notice this has changed and update their models
- actor.weapon = actor.switchweapon;
- actor.weaponname = newwep.mdl;
- actor.bulletcounter = 0;
- actor.ammo_field = newwep.ammo_field;
- Weapon w = get_weaponinfo(actor.switchweapon);
- w.wr_setup(w);
- actor.weaponentity.state = WS_RAISE;
-
- // set our clip load to the load of the weapon we switched to, if it's reloadable
- if(newwep.spawnflags & WEP_FLAG_RELOADABLE && newwep.reloading_ammo) // prevent accessing undefined cvars
+ default:
+ LOG_WARNINGF("unhandled weaponentity (%i) state for player (%i): %d\n", this, actor, this.state);
+ break;
+ case WS_INUSE:
+ case WS_RAISE:
+ break;
+ case WS_CLEAR:
{
- actor.clip_load = actor.(weapon_load[actor.switchweapon]);
- actor.clip_size = newwep.reloading_ammo;
- }
- else
- actor.clip_load = actor.clip_size = 0;
-
- weapon_thinkf(actor, WFRAME_IDLE, newwep.switchdelay_raise, w_ready);
- }
- else if (actor.weaponentity.state == WS_DROP)
- {
- // in dropping phase we can switch at any time
- actor.switchingweapon = actor.switchweapon;
- }
- else if (actor.weaponentity.state == WS_READY)
- {
- // start switching!
- actor.switchingweapon = actor.switchweapon;
- entity oldwep = get_weaponinfo(actor.weapon);
+ // end switching!
+ actor.switchingweapon = actor.switchweapon;
+ entity newwep = Weapons_from(actor.switchweapon);
+
+ // the two weapon entities will notice this has changed and update their models
+ actor.weapon = actor.switchweapon;
+ actor.weaponname = newwep.mdl;
+ actor.bulletcounter = 0;
+ actor.ammo_field = newwep.ammo_field;
+ newwep.wr_setup(newwep);
+ this.state = WS_RAISE;
+
+ // set our clip load to the load of the weapon we switched to, if it's reloadable
+ if ((newwep.spawnflags & WEP_FLAG_RELOADABLE) && newwep.reloading_ammo) // prevent accessing undefined cvars
+ {
+ actor.clip_load = actor.(weapon_load[actor.switchweapon]);
+ actor.clip_size = newwep.reloading_ammo;
+ }
+ else
+ {
+ actor.clip_load = actor.clip_size = 0;
+ }
- // set up weapon switch think in the future, and start drop anim
- #ifndef INDEPENDENT_ATTACK_FINISHED
- if(ATTACK_FINISHED(actor) <= time + actor.weapon_frametime * 0.5)
+ weapon_thinkf(actor, weaponentity, WFRAME_IDLE, newwep.switchdelay_raise, w_ready);
+ break;
+ }
+ case WS_DROP:
{
- #endif
- sound(actor, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM);
- actor.weaponentity.state = WS_DROP;
- weapon_thinkf(actor, WFRAME_DONTCHANGE, oldwep.switchdelay_drop, w_clear);
- #ifndef INDEPENDENT_ATTACK_FINISHED
+ // in dropping phase we can switch at any time
+ actor.switchingweapon = actor.switchweapon;
+ break;
+ }
+ case WS_READY:
+ {
+ // start switching!
+ actor.switchingweapon = actor.switchweapon;
+ entity oldwep = Weapons_from(actor.weapon);
+
+ // set up weapon switch think in the future, and start drop anim
+ if (
+#if INDEPENDENT_ATTACK_FINISHED
+ true
+#else
+ ATTACK_FINISHED(actor, slot) <= time + actor.weapon_frametime * 0.5
+#endif
+ )
+ {
+ sound(actor, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM);
+ this.state = WS_DROP;
+ weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, oldwep.switchdelay_drop, w_clear);
+ }
+ break;
}
- #endif
}
}
// LordHavoc: network timing test code
- //if (actor.button0)
- // print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor)), " >= ", ftos(actor.weapon_nextthink), "\n");
+ // if (actor.button0)
+ // print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor, slot)), " >= ", ftos(this.weapon_nextthink), "\n");
- float w;
- w = actor.weapon;
+ int w = actor.weapon;
// call the think code which may fire the weapon
// and do so multiple times to resolve framerate dependency issues if the
// server framerate is very low and the weapon fire rate very high
- float c;
- c = 0;
- while (c < W_TICSPERFRAME)
+ for (int c = 0; c < W_TICSPERFRAME; ++c)
{
- c = c + 1;
- if(w && !(actor.weapons & WepSet_FromWeapon(w)))
+ if (w && !(actor.weapons & WepSet_FromWeapon(w)))
{
- if(actor.weapon == actor.switchweapon)
- W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
+ if (actor.weapon == actor.switchweapon) W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
w = 0;
}
bool block_weapon = false;
{
bool key_pressed = actor.BUTTON_HOOK && !actor.vehicle;
- Weapon off = actor.offhand;
- if (off && !(actor.weapons & WEPSET(HOOK))) {
- if (off.offhand_think) off.offhand_think(off, actor, key_pressed);
- } else {
- if (key_pressed && actor.switchweapon != WEP_HOOK.m_id && !actor.hook_switchweapon) {
- W_SwitchWeapon(WEP_HOOK.m_id);
- }
+ Weapon off = actor.offhand;
+ if (off && !(actor.weapons & WEPSET(HOOK)))
+ {
+ if (off.offhand_think) off.offhand_think(off, actor, key_pressed);
+ }
+ else
+ {
+ if (key_pressed && actor.switchweapon != WEP_HOOK.m_id && !actor.hook_switchweapon) W_SwitchWeapon(
+ WEP_HOOK.m_id);
actor.hook_switchweapon = key_pressed;
Weapon h = WEP_HOOK;
block_weapon = (actor.weapon == h.m_id && (actor.BUTTON_ATCK || key_pressed));
- h.wr_think(h, actor, block_weapon, false);
- }
- }
+ h.wr_think(h, actor, weaponentity, block_weapon ? 1 : 0);
+ }
+ }
+
+ v_forward = fo;
+ v_right = ri;
+ v_up = up;
if (!block_weapon)
- if (w) {
- Weapon e = get_weaponinfo(actor.weapon);
- e.wr_think(e, actor, actor.BUTTON_ATCK, actor.BUTTON_ATCK2);
- } else {
- Weapon w = get_weaponinfo(actor.weapon);
- w.wr_gonethink(w);
+ {
+ if (w)
+ {
+ Weapon e = Weapons_from(actor.weapon);
+ e.wr_think(e, actor, weaponentity, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0));
+ }
+ else
+ {
+ Weapon w = Weapons_from(actor.weapon);
+ w.wr_gonethink(w);
+ }
}
- if (time + actor.weapon_frametime * 0.5 >= actor.weapon_nextthink)
+ if (time + actor.weapon_frametime * 0.5 >= this.weapon_nextthink)
{
- if(actor.weapon_think)
+ if (this.weapon_think)
{
v_forward = fo;
v_right = ri;
v_up = up;
- Weapon wpn = get_weaponinfo(actor.weapon);
- actor.weapon_think(wpn, actor, actor.BUTTON_ATCK, actor.BUTTON_ATCK2);
+ Weapon wpn = Weapons_from(actor.weapon);
+ this.weapon_think(wpn, actor, weaponentity,
+ (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0));
}
else
+ {
bprint("\{1}^1ERROR: undefined weapon think function for ", actor.netname, "\n");
+ }
}
}
}
void W_AttachToShotorg(entity actor, entity flash, vector offset)
{
- entity xflash;
+ .entity weaponentity = weaponentities[0];
flash.owner = actor;
flash.angles_z = random() * 360;
- if(gettagindex(actor.weaponentity, "shot"))
- setattachment(flash, actor.weaponentity, "shot");
- else
- setattachment(flash, actor.weaponentity, "tag_shot");
+ entity this = actor.(weaponentity);
+ if (gettagindex(this, "shot")) setattachment(flash, this, "shot");
+ else setattachment(flash, this, "tag_shot");
setorigin(flash, offset);
- xflash = spawn();
+ entity xflash = spawn();
copyentity(flash, xflash);
flash.viewmodelforclient = actor;
- if(actor.weaponentity.oldorigin.x > 0)
+ if (this.oldorigin.x > 0)
{
setattachment(xflash, actor.exteriorweaponentity, "");
- setorigin(xflash, actor.weaponentity.oldorigin + offset);
+ setorigin(xflash, this.oldorigin + offset);
}
else
{
- if(gettagindex(actor.exteriorweaponentity, "shot"))
- setattachment(xflash, actor.exteriorweaponentity, "shot");
- else
- setattachment(xflash, actor.exteriorweaponentity, "tag_shot");
+ if (gettagindex(actor.exteriorweaponentity, "shot")) setattachment(xflash, actor.exteriorweaponentity, "shot");
+ else setattachment(xflash, actor.exteriorweaponentity, "tag_shot");
setorigin(xflash, offset);
}
}
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use)
{
+ if (MUTATOR_CALLHOOK(W_DecreaseAmmo, actor)) return;
- if(cvar("g_overkill"))
- if(actor.ok_use_ammocharge)
- {
- ok_DecreaseCharge(actor, actor.weapon);
- return; // TODO
- }
-
- if((actor.items & IT_UNLIMITED_WEAPON_AMMO) && !wep.reloading_ammo)
- return;
+ if ((actor.items & IT_UNLIMITED_WEAPON_AMMO) && !wep.reloading_ammo) return;
// if this weapon is reloadable, decrease its load. Else decrease the player's ammo
- if(wep.reloading_ammo)
+ if (wep.reloading_ammo)
{
actor.clip_load -= ammo_use;
actor.(weapon_load[actor.weapon]) = actor.clip_load;
}
- else if(wep.ammo_field != ammo_none)
+ else if (wep.ammo_field != ammo_none)
{
actor.(wep.ammo_field) -= ammo_use;
- if(actor.(wep.ammo_field) < 0)
+ if (actor.(wep.ammo_field) < 0)
{
backtrace(sprintf(
"W_DecreaseAmmo(%.2f): '%s' subtracted too much %s from '%s', resulting with '%.2f' left... "
GetAmmoPicture(wep.ammo_field),
actor.netname,
actor.(wep.ammo_field)
- ));
+ ));
}
}
}
.float reload_complain;
.string reload_sound;
-void W_ReloadedAndReady(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_ReloadedAndReady(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
// finish the reloading process, and do the ammo transfer
- actor.clip_load = actor.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
+ actor.clip_load = actor.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
// if the gun uses no ammo, max out weapon load, else decrease ammo as we increase weapon load
- if(!actor.reload_ammo_min || actor.items & IT_UNLIMITED_WEAPON_AMMO || actor.ammo_field == ammo_none)
+ if (!actor.reload_ammo_min || actor.items & IT_UNLIMITED_WEAPON_AMMO || actor.ammo_field == ammo_none)
+ {
actor.clip_load = actor.reload_ammo_amount;
+ }
else
{
// make sure we don't add more ammo than we have
float load = min(actor.reload_ammo_amount - actor.clip_load, actor.(actor.ammo_field));
- actor.clip_load += load;
- actor.(actor.ammo_field) -= load;
+ actor.clip_load += load;
+ actor.(actor.ammo_field) -= load;
}
actor.(weapon_load[actor.weapon]) = actor.clip_load;
// then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there,
// so your weapon is disabled for a few seconds without reason
- //ATTACK_FINISHED(actor) -= actor.reload_time - 1;
+ // ATTACK_FINISHED(actor, slot) -= actor.reload_time - 1;
- Weapon wpn = get_weaponinfo(actor.weapon);
- w_ready(wpn, actor, actor.BUTTON_ATCK, actor.BUTTON_ATCK2);
+ Weapon wpn = Weapons_from(actor.weapon);
+ w_ready(wpn, actor, weaponentity, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0));
}
void W_Reload(entity actor, float sent_ammo_min, string sent_sound)
{
+ .entity weaponentity = weaponentities[0];
// set global values to work with
- entity e;
- e = get_weaponinfo(actor.weapon);
+ entity e = Weapons_from(actor.weapon);
- if(cvar("g_overkill"))
- if(actor.ok_use_ammocharge)
- return; // TODO
+ if (MUTATOR_CALLHOOK(W_Reload, actor)) return;
actor.reload_ammo_min = sent_ammo_min;
actor.reload_ammo_amount = e.reloading_ammo;
// don't reload weapons that don't have the RELOADABLE flag
if (!(e.spawnflags & WEP_FLAG_RELOADABLE))
{
- LOG_TRACE("Warning: Attempted to reload a weapon that does not have the WEP_FLAG_RELOADABLE flag. Fix your code!\n");
+ LOG_TRACE(
+ "Warning: Attempted to reload a weapon that does not have the WEP_FLAG_RELOADABLE flag. Fix your code!\n");
return;
}
// return if reloading is disabled for this weapon
- if(!actor.reload_ammo_amount)
- return;
+ if (!actor.reload_ammo_amount) return;
// our weapon is fully loaded, no need to reload
- if (actor.clip_load >= actor.reload_ammo_amount)
- return;
+ if (actor.clip_load >= actor.reload_ammo_amount) return;
// no ammo, so nothing to load
- if(actor.ammo_field != ammo_none)
- if(!actor.(actor.ammo_field) && actor.reload_ammo_min)
- if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+ if (actor.ammo_field != ammo_none)
{
- if(IS_REAL_CLIENT(actor) && actor.reload_complain < time)
+ if (!actor.(actor.ammo_field) && actor.reload_ammo_min)
{
- play2(actor, SND(UNAVAILABLE));
- sprint(actor, strcat("You don't have enough ammo to reload the ^2", WEP_NAME(actor.weapon), "\n"));
- actor.reload_complain = time + 1;
- }
- // switch away if the amount of ammo is not enough to keep using this weapon
- Weapon w = get_weaponinfo(actor.weapon);
- if (!(w.wr_checkammo1(w) + w.wr_checkammo2(w)))
- {
- actor.clip_load = -1; // reload later
- W_SwitchToOtherWeapon(actor);
+ if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+ {
+ if (IS_REAL_CLIENT(actor) && actor.reload_complain < time)
+ {
+ play2(actor, SND(UNAVAILABLE));
+ sprint(actor, strcat("You don't have enough ammo to reload the ^2", WEP_NAME(actor.weapon), "\n"));
+ actor.reload_complain = time + 1;
+ }
+ // switch away if the amount of ammo is not enough to keep using this weapon
+ Weapon w = Weapons_from(actor.weapon);
+ if (!(w.wr_checkammo1(w) + w.wr_checkammo2(w)))
+ {
+ actor.clip_load = -1; // reload later
+ W_SwitchToOtherWeapon(actor);
+ }
+ return;
+ }
}
- return;
}
- if (actor.weaponentity)
+ entity this = actor.(weaponentity);
+ if (this)
{
- if (actor.weaponentity.wframe == WFRAME_RELOAD)
- return;
+ if (this.wframe == WFRAME_RELOAD) return;
// allow switching away while reloading, but this will cause a new reload!
- actor.weaponentity.state = WS_READY;
+ this.state = WS_READY;
}
// now begin the reloading process
// then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there,
// so your weapon is disabled for a few seconds without reason
- //ATTACK_FINISHED(actor) = max(time, ATTACK_FINISHED(actor)) + actor.reload_time + 1;
+ // ATTACK_FINISHED(actor, slot) = max(time, ATTACK_FINISHED(actor, slot)) + actor.reload_time + 1;
- weapon_thinkf(actor, WFRAME_RELOAD, actor.reload_time, W_ReloadedAndReady);
+ weapon_thinkf(actor, weaponentity, WFRAME_RELOAD, actor.reload_time, W_ReloadedAndReady);
- if(actor.clip_load < 0)
- actor.clip_load = 0;
+ if (actor.clip_load < 0) actor.clip_load = 0;
actor.old_clip_load = actor.clip_load;
actor.clip_load = actor.(weapon_load[actor.weapon]) = -1;
}
void W_DropEvent(.void(Weapon) event, entity player, float weapon_type, entity weapon_item)
-{SELFPARAM();
- setself(player);
+{
+ Weapon w = Weapons_from(weapon_type);
weapon_dropevent_item = weapon_item;
- Weapon w = get_weaponinfo(weapon_type);
- w.event(w);
- setself(this);
+ WITH(entity, self, player, w.event(w));
}
vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn);
-void CL_SpawnWeaponentity(entity e);
+void CL_SpawnWeaponentity(entity e, .entity weaponentity);
vector CL_Weapon_GetShotOrg(float wpn);
float W_WeaponSpeedFactor();
-bool weapon_prepareattack(Weapon thiswep, entity actor, bool secondary, float attacktime);
+bool weapon_prepareattack(Weapon thiswep, entity actor, .entity weaponentity, bool secondary, float attacktime);
-bool weapon_prepareattack_check(Weapon thiswep, entity actor, float secondary, float attacktime);
+bool weapon_prepareattack_check(Weapon thiswep, entity actor, .entity weaponentity, float secondary, float attacktime);
-void weapon_prepareattack_do(entity actor, float secondary, float attacktime);
+void weapon_prepareattack_do(entity actor, .entity weaponentity, float secondary, float attacktime);
-void weapon_thinkf(entity actor, float fr, float t, void(Weapon thiswep, entity actor, bool fire1, bool fire2) func);
+void weapon_thinkf(entity actor, .entity weaponentity, float fr, float t, void(Weapon thiswep, entity actor, .entity weaponentity, int fire) func);
#endif
#
# Whether to collapse empty blocks between '{' and '}'
-nl_collapse_empty_body = false # false/true
+nl_collapse_empty_body = true # false/true
# Don't split one-line braced assignments - 'foo_t f = { 1, 2 };'
# WARNING: Code doesn't seem to use this feature - delete from the config?
-nl_assign_leave_one_liners = false # false/true
+nl_assign_leave_one_liners = true # false/true
# Don't split one-line braced statements inside a class xx { } body
# WARNING: Code doesn't seem to use this feature - delete from the config?
-nl_class_leave_one_liners = false # false/true
+nl_class_leave_one_liners = true # false/true
# Don't split one-line enums: 'enum foo { BAR = 15 };'
# WARNING: Code doesn't seem to use this feature - delete from the config?
-nl_enum_leave_one_liners = false # false/true
+nl_enum_leave_one_liners = true # false/true
# Don't split one-line get or set functions
# WARNING: Code doesn't seem to use this feature - delete from the config?
-nl_getset_leave_one_liners = false # false/true
+nl_getset_leave_one_liners = true # false/true
# Don't split one-line function definitions - 'int foo() { return 0; }'
nl_func_leave_one_liners = true # false/true
nl_multi_line_cond = false # false/true
# Force a newline in a define after the macro name for multi-line defines.
-nl_multi_line_define = false # false/true
+nl_multi_line_define = true # false/true
# Whether to put a newline before 'case' statement
nl_before_case = false # false/true
nl_return_expr = remove # ignore/add/remove/force
# Whether to put a newline after semicolons, except in 'for' statements
-nl_after_semicolon = false # false/true
+nl_after_semicolon = true # false/true
# Whether to put a newline after brace open.
# This also adds a newline before the matching brace close.
nl_brace_struct_var = remove # ignore/add/remove/force
# Whether to alter newlines in '#define' macros
-nl_define_macro = false # false/true
+nl_define_macro = true # false/true
# Whether to not put blanks after '#ifxx', '#elxx', or before '#endif'
nl_squeeze_ifdef = false # false/true
# Change simple unbraced if statements into a one-liner
# 'if(b)\n i++;' => 'if(b) i++;'
-nl_create_if_one_liner = false # false/true
+nl_create_if_one_liner = true # false/true
# Change simple unbraced for statements into a one-liner
# 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);'
#
# Try to limit code width to N number of columns
-code_width = 0 # number
+code_width = 120 # number
# Whether to fully split long 'for' statements at semi-colons
# WARNING: Code doesn't seem to use this feature - delete from the config?
# If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C]
# This is generally a bad idea, as it may break your code.
-mod_sort_include = false # false/true
+mod_sort_include = false # false/true
# If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace.
# WARNING: Code doesn't seem to use this feature - delete from the config?
# Will add or remove the braces around a fully braced case statement.
# Will only remove the braces if there are no variable declarations in the block.
# NOTE: is 78 worse than ignore
-mod_case_brace = remove # ignore/add/remove/force
+mod_case_brace = add # ignore/add/remove/force
# If TRUE, it will remove a void 'return;' that appears as the last statement in a function.
mod_remove_empty_return = true # false/true #force
# Whether to put a star on subsequent comment lines
# WARNING: Code doesn't seem to use this feature - delete from the config?
-cmt_star_cont = false # false/true
+cmt_star_cont = true # false/true
# The number of spaces to insert at the start of subsequent comment lines
# WARNING: Code doesn't seem to use this feature - delete from the config?
# Control indent of preprocessors inside #if blocks at brace level 0
# WARNING: Indifferent... please decide manually.
-pp_indent = ignore # ignore/add/remove/force
+pp_indent = force # ignore/add/remove/force
# Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false)
pp_indent_at_level = false # false/true
# If pp_indent_at_level=false, specifies the number of columns to indent per level. Default=1.
# WARNING: Code doesn't seem to use this feature - delete from the config?
-pp_indent_count = 0 # number
+pp_indent_count = 4 # number
# Add or remove space after # based on pp_level of #if blocks
# NOTE: is 28 worse than ignore
# Whether to indent the code between #region and #endregion
# WARNING: Code doesn't seem to use this feature - delete from the config?
-pp_region_indent_code = false # false/true
+pp_region_indent_code = true # false/true
# If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level
# WARNING: Code doesn't seem to use this feature - delete from the config?
-pp_indent_if = 0 # number
+pp_indent_if = 4 # number
# Control whether to indent the code between #if, #else and #endif when not at file-level
-pp_if_indent_code = false # false/true
+pp_if_indent_code = true # false/true
# Whether to indent '#define' at the brace level (true) or from column 1 (false)
pp_define_at_level = true # false/true
# type myfoo1 myfoo2
type void
+type bool
+type int
type float
type vector
type entity
type string
type .void
+type .bool
+type .int
type .float
type .vector
type .entity
# You can assign any keyword to any type with the set option.
# set func_call_user _ N_
-# menu QC OO
+# QC OO
macro-open CLASS
macro-else EXTENDS
macro-close ENDCLASS
# void(void) func;
# ) wrong and removes the space between type and variable. Fix this by
# a simple sed on ")letter" which should normally not occur.
- sed -e 's/)\([A-Za-z0-9]\)/) \1/g' "$@"
+ sed -e 's/)\([A-Za-z_]\)/) \1/g' "$@"
}
if [ -z "$UNCRUSTIFY_CONFIG" ]; then
fix_function_types
;;
*)
- uncrustify --replace --no-backup -c "$UNCRUSTIFY_CONFIG" "$@" &&\
+ uncrustify --replace --no-backup -c "$UNCRUSTIFY_CONFIG" "$@" ;\
fix_function_types -i "$@"
;;
esac
--- /dev/null
+// This quickmenu example file can be loaded by setting
+// hud_panel_quickmenu_file quickmenu_example.txt
+// and executing "quickmenu file"
+// For more options see "quickmenu help"
+
+"Chat"
+ "nice one" "say :-) / nice one"
+ "good game" "say good game"
+ "hi / good luck" "say hi / good luck and have fun"
+"Chat"
+
+"Settings"
+ // nested submenu
+ "Sound settings"
+ "Hit sound" "toggle cl_hitsound"
+ "Chat sound" "toggle cl_chatsound"
+ "Sound settings"
+
+ // A toggle command displays a checkbox showing the current cvar's state
+ "enable 3rd person view" "toggle chase_active"
+ // it's possible to invert the meaning of the checkbox by inverting the
+ // parameters of toggle from the implicit 1 0 to 0 1
+ "disable 3rd person view" "toggle chase_active 0 1"
+"Settings"
+
+"screenshot" "wait; screenshot"
+
+// Commands that accept a player's name as parameter (%s), followed by one of
+// these special keywords:
+// ALLPLAYERS_BUT_ME
+// ALLPLAYERS
+// OWNTEAMPLAYERS_BUT_ME
+// OWNTEAMPLAYERS
+// ENEMYTEAMPLAYERS
+// lets you pick a player's name from a list:
+"private chat with:" "commandmode tell \"%s\"" ALLPLAYERS_BUT_ME