...
 
Commits (16)
Sun Dec 16 07:25:19 CET 2018
Thu Dec 20 07:24:05 CET 2018
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -951,68 +951,13 @@ effect machinegun_impact
tex 40 40
velocityjitter 300 300 300
velocitymultiplier 0.200000
effect grenadelauncher_muzzleflash
type smoke
airfriction 12
alpha 256 256 512
color 0x202020 0x404040
count 1.500000
lightcolor 2 1.5 0.2
lightradiusfade 2000
lightradius 200
originjitter 1.5 1.5 1.5
size 5 5
tex 0 8
velocityjitter 20 20 20
velocitymultiplier 0.030000
effect grenadelauncher_muzzleflash
type spark
airfriction 5
alpha 0 128 1024
color 0xffdb96 0xff5400
count 16
originjitter 1 1 1
size 10 20
stretchfactor 2.500000
tex 48 55
velocityjitter 100 100 100
velocitymultiplier 0.500000
effect TR_GRENADE
type smoke
alpha 300 400 780
bounce 1
color 0x101010 0x000000
originjitter 1 1 1
sizeincrease 10
size 3 2
tex 0 8
trailspacing 4
velocityjitter 1 1 1
velocitymultiplier -0.020000
effect TR_GRENADE
type static
airfriction 8
alpha 100 144 988
color 0xffdf72 0x811200
notunderwater
sizeincrease -15
size 5 2
alpha 133 200 150
color 0xff0000 0xff0000
size 5 5
tex 48 55
trailspacing 4
velocityjitter 32 32 32
velocitymultiplier -1
effect TR_GRENADE
type bubble
alpha 256 256 256
bounce 1.500000
color 0x404040 0x808080
gravity -0.125000
liquidfriction 4
size 1 1
tex 62 62
trailspacing 16
underwater
velocityjitter 16 16 16
trailspacing 6
effect TR_KNIGHTSPIKE
type smoke
alpha 300 400 600
......@@ -1358,29 +1303,6 @@ effect electro_combo
size 30 30
tex 33 33
velocitymultiplier 0.300000
effect crylink_muzzleflash
type smoke
alpha 128 128 2024
color 0xdd9cff 0xff0090
count 0.500000
lightcolor 1.6 0.2 2
lightradiusfade 2000
lightradius 200
size 15 20
tex 65 65
velocitymultiplier 0.010000
effect crylink_muzzleflash
type spark
airfriction 12
alpha 0 128 1024
color 0xA080C0 0xA080C0
count 5
originjitter 1 1 1
size 5 10
stretchfactor 1.500000
tex 35 36
velocityjitter 200 200 200
velocitymultiplier 0.300000
effect crylink_impact
type decal
alpha 256 256 0
......@@ -1547,58 +1469,6 @@ effect nex_impact
tex 41 41
velocityjitter 300 300 600
velocitymultiplier 2.500000
effect hagar_muzzleflash
type smoke
alpha 256 256 512
color 0x202020 0x404040
count 2
lightcolor 2 1.5 0.2
lightradiusfade 2000
lightradius 200
originjitter 1.5 1.5 1.5
size 5 5
tex 0 8
velocityjitter 6 6 6
velocitymultiplier 0.010000
effect hagar_muzzleflash
type spark
airfriction 12
alpha 0 128 1024
color 0xff8400 0xff4200
count 15
originjitter 1 1 1
rotate -180 180 -400 400
size 5 10
stretchfactor 2
tex 48 55
velocityjitter 200 200 200
velocitymultiplier 0.500000
effect hagar_bounce
type smoke
alpha 256 256 256
color 0x202020 0x404040
count 2
lightcolor 2 1.5 0.2
lightradiusfade 300
lightradius 60
originjitter 1.5 1.5 1.5
size 5 5
tex 0 8
velocityjitter 6 6 6
velocitymultiplier 0.010000
effect hagar_bounce
type spark
airfriction 12
alpha 0 256 256
bounce 1.500000
color 0xFFFDD9 0xFFFDD9
count 15
gravity 1
originjitter 1 1 1
size 3 3
tex 40 40
velocityjitter 600 600 600
velocitymultiplier 0.500000
effect hagar_explode
type decal
alpha 256 256 0
......@@ -1677,82 +1547,54 @@ effect hagar_explode
tex 40 40
velocityjitter 224 224 224
velocityoffset 0 0 80
effect rocketlauncher_muzzleflash
type smoke
airfriction 2
alpha 256 256 256
color 0x202020 0x404040
count 10
originjitter 1.5 1.5 1.5
sizeincrease 20
size 1 1
tex 0 8
velocityjitter 40 40 40
velocitymultiplier -0.130000
effect rocketlauncher_muzzleflash
type smoke
airfriction 9
alpha 10 25 20
color 0xFFFDD9 0xFFFDD9
count 6
originjitter 3 3 3
rotate -180 180 -30 30
sizeincrease 20
size 5 10
tex 35 36
velocityjitter 100 100 100
velocitymultiplier 0.300000
effect TR_ROCKET
type smoke
alpha 200 300 200
bounce 1
color 0x000000 0x666666
color 0xaa6660 0xaa6600
lightcolor 6 3 1
lightradius 150
notunderwater
originjitter 2 2 2
rotate -180 180 -30 30
sizeincrease 11
size 3 4
sizeincrease 10
size 1 2
tex 0 8
trailspacing 10
trailspacing 8
velocityjitter 3 3 3
velocitymultiplier -0.020000
effect TR_ROCKET
type static
airfriction 8
alpha 100 144 588
alpha 100 144 1000
color 0xffdf72 0x811200
sizeincrease -20
size 20 20
tex 48 55
trailspacing 5
velocityjitter 32 32 32
velocitymultiplier -1.500000
effect TR_ROCKET
type static
airfriction 8
alpha 100 144 388
color 0xffdf72 0x811200
sizeincrease -30
size 7 7
tex 48 55
trailspacing 4
trailspacing 5
velocityjitter 32 32 32
velocitymultiplier -1.500000
effect TR_ROCKET
type bubble
alpha 256 256 256
bounce 1.500000
gravity -0.125000
liquidfriction 4
size 1 2
tex 62 62
trailspacing 16
underwater
velocityjitter 16 16 16
velocitymultiplier -0.310000
effect TR_ROCKET
type spark
airfriction 5
alpha 444 512 1866
alpha 444 512 1066
bounce 1
color 0xFFFDD9 0xFFFDD9
notunderwater
originjitter 1 1 1
size 0.500000 0.500000
size 0.300000 0.900000
stretchfactor 0.300000
tex 40 40
trailspacing 20
trailspacing 8
velocityjitter 100 100 100
velocitymultiplier -0.310000
effect rocket_explode
......@@ -2795,7 +2637,7 @@ effect smoking_smallemitter
velocityjitter 5 5 20
effect TR_CRYLINKPLASMA
type static
alpha 256 256 1024
alpha 256 256 624
color 0x5522aa 0x6622ff
sizeincrease 8
size 2 2
......@@ -2805,10 +2647,10 @@ effect TR_CRYLINKPLASMA
velocitymultiplier -0.010000
effect TR_CRYLINKPLASMA
type static
alpha 256 256 2600
alpha 256 256 1000
color 0x5522aa 0x6622ff
sizeincrease 15
size 3 3
sizeincrease 17
size 4 3
tex 3 3
trailspacing 16
velocityjitter 2 2 2
......@@ -5596,42 +5438,17 @@ effect impact_flesh
tex 24 32
velocityjitter 96 96 96
velocitymultiplier 5
effect tr_hagar
type smoke
alpha 300 400 780
bounce 1
color 0x101010 0x000000
originjitter 1 1 1
sizeincrease 10
size 3 2
tex 0 8
trailspacing 4
velocityjitter 1 1 1
velocitymultiplier -0.020000
effect tr_hagar
type static
airfriction 8
alpha 100 144 988
alpha 100 144 1400
color 0xffdf72 0x811200
notunderwater
sizeincrease -15
size 5 2
size 3 2
tex 48 55
trailspacing 4
trailspacing 2
velocityjitter 32 32 32
velocitymultiplier -1
effect tr_hagar
type bubble
alpha 256 256 256
bounce 1.500000
color 0x404040 0x808080
gravity -0.125000
liquidfriction 4
size 1 1
tex 62 62
trailspacing 16
underwater
velocityjitter 16 16 16
effect damage_laser
type smoke
airfriction -0.350000
......
......@@ -4,14 +4,14 @@ de_CH "German (Switzerland)" "Deutsch (Schweiz)" 92%
en "English" "English" 100%
en_AU "English (Australia)" "English (Australia)" 81%
es "Spanish" "Español" 92%
fr "French" "Français" 96%
fr "French" "Français" 97%
ga "Irish" "Irish" 34%
it "Italian" "Italiano" 100%
hu "Hungarian" "Magyar" 51%
nl "Dutch" "Nederlands" 66%
pl "Polish" "Polski" 76%
pt "Portuguese" "Português" 91%
pt_BR "Portuguese (Brazil)" "Português (Brasil)" 95%
pt_BR "Portuguese (Brazil)" "Português (Brasil)" 99%
ro "Romanian" "Romana" 78%
fi "Finnish" "Suomi" 32%
el "Greek" "Ελληνική" 42%
......
......@@ -74,6 +74,8 @@ bool autocvar_hud_panel_scoreboard_spectators_showping = true;
bool autocvar_hud_panel_scoreboard_spectators_aligned = false;
float autocvar_hud_panel_scoreboard_minwidth = 0.4;
AUTOCVAR(_scoreboard_instagib, bool, false, "");
// wrapper to put all possible scores titles through gettext
string TranslateScoresLabel(string l)
{
......@@ -116,6 +118,7 @@ string TranslateScoresLabel(string l)
case "suicides": return CTX(_("SCO^suicides"));
case "takes": return CTX(_("SCO^takes"));
case "ticks": return CTX(_("SCO^ticks"));
case "country": return CTX(_("SCO^country"));
default: return l;
}
}
......@@ -365,7 +368,7 @@ void Cmd_Scoreboard_Help()
// otherwise the previous exclusive rule warns anyway
// e.g. -teams,rc,cts,lms/kills ?+rc/kills
#define SCOREBOARD_DEFAULT_COLUMNS \
"ping pl fps name |" \
"ping pl fps name country |" \
" -teams,rc,cts,inv,lms/kills +ft,tdm/kills ?+rc,inv/kills" \
" -teams,lms/deaths +ft,tdm/deaths" \
" +tdm/sum" \
......@@ -382,17 +385,41 @@ void Cmd_Scoreboard_Help()
" +dom/ticks +dom/takes" \
" -lms,rc,cts,inv,nb/score"
#define SCOREBOARD_DEFAULT_COLUMNS_INSTAGIB \
"ping pl fps name country |" \
" -teams,rc,cts,inv,lms/kills +ft,tdm/kills ?+rc,inv/kills" \
" -teams,lms/deaths +ft,tdm/deaths" \
" +tdm/sum" \
" -teams,lms,rc,cts,inv,ka/suicides +ft,tdm/suicides ?+rc,inv/suicides" \
" -cts,dm,tdm,ka,ft/frags" /* tdm already has this in "score" */ \
" -cts,nb,rc/accuracy" \
" +tdm,ft,dom,ons,as/teamkills"\
" +ctf/pickups +ctf/fckills +ctf/returns +ctf/caps +ons/takes +ons/caps" \
" +lms/lives +lms/rank" \
" +kh/kckills +kh/losses +kh/caps" \
" ?+rc/laps ?+rc/time +rc,cts/fastest" \
" +as/objectives +nb/faults +nb/goals" \
" +ka/pickups +ka/bckills +ka/bctime +ft/revivals" \
" +dom/ticks +dom/takes" \
" -lms,rc,cts,inv,nb/score"
void Cmd_Scoreboard_SetFields(int argc)
{
TC(int, argc);
int i, slash;
string str, pattern;
string str, pattern, default_scoreboard;
bool have_name = false, have_primary = false, have_secondary = false, have_separator = false;
int missing;
if(!gametype)
return; // do nothing, we don't know gametype and scores yet
if (autocvar__scoreboard_instagib) {
default_scoreboard = SCOREBOARD_DEFAULT_COLUMNS_INSTAGIB;
} else {
default_scoreboard = SCOREBOARD_DEFAULT_COLUMNS;
}
// sbt_fields uses strunzone on the titles!
if(!sbt_field_title[0])
for(i = 0; i < MAX_SBT_FIELDS; ++i)
......@@ -403,16 +430,12 @@ void Cmd_Scoreboard_SetFields(int argc)
argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
if(argc < 3)
argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " ");
argc = tokenizebyseparator(strcat("0 1 ", default_scoreboard), " ");
if(argc == 3)
{
if(argv(2) == "default" || argv(2) == "expand_default")
{
if(argv(2) == "expand_default")
cvar_set("scoreboard_columns", SCOREBOARD_DEFAULT_COLUMNS);
argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " ");
}
if(argv(2) == "default")
argc = tokenizebyseparator(strcat("0 1 ", default_scoreboard), " ");
else if(argv(2) == "all")
{
string s = "ping pl name |"; // scores without a label
......@@ -463,6 +486,7 @@ void Cmd_Scoreboard_SetFields(int argc)
{
case "ping": sbt_field[sbt_num_fields] = SP_PING; break;
case "pl": sbt_field[sbt_num_fields] = SP_PL; break;
case "country": sbt_field[sbt_num_fields] = SP_COUNTRY; break;
case "kd": case "kdr": case "kdratio": sbt_field[sbt_num_fields] = SP_KDRATIO; break;
case "sum": case "diff": case "k-d": sbt_field[sbt_num_fields] = SP_SUM; break;
case "name": case "nick": sbt_field[sbt_num_fields] = SP_NAME; have_name = true; break;
......@@ -624,6 +648,10 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field)
sbt_field_rgb = '1 1 1' - '0 1 1' * tmp;
return ftos(f);
case SP_COUNTRY:
float cn = pl.(scores(SP_COUNTRY));
return chr2str((cn >> 8) & 0xff, cn & 0xff);
case SP_PL:
if (!pl.gotscores)
return _("N/A");
......@@ -869,7 +897,7 @@ void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, i
if(field == SP_SEPARATOR)
break;
if(is_spec && field != SP_NAME && field != SP_PING) {
if(is_spec && field != SP_NAME && field != SP_PING && field != SP_COUNTRY) {
pos.x += sbt_field_size[i] + hud_fontsize.x;
continue;
}
......
......@@ -322,6 +322,7 @@ float MapVote_Selection(vector topleft, vector cellsize, float rows, float colum
}
vector prev_mousepos;
// draws map vote or gametype vote
void MapVote_Draw()
{
string map;
......@@ -464,7 +465,7 @@ void MapVote_Draw()
mv_selection = MapVote_Selection(pos, dist, rows, mv_columns);
if (mv_top2_time)
mv_top2_alpha = max(0.2, 1 - (time - mv_top2_time)*(time - mv_top2_time));
mv_top2_alpha = max(0.2, 1 - (time - mv_top2_time) ** 2);
void (vector, float, float, string, string, float, float) DrawItem;
......
......@@ -37,7 +37,7 @@ int WinningCondition_LMS()
{
entity first_player = NULL;
int totalplayers = 0;
FOREACH_CLIENT(IS_PLAYER(it), {
FOREACH_CLIENT(IS_PLAYER(it) && it.frags != FRAGS_LMS_LOSER, {
if (!totalplayers)
first_player = it;
++totalplayers;
......@@ -185,8 +185,10 @@ void lms_RemovePlayer(entity player)
if (!player_rank)
{
int pl_cnt = 0;
FOREACH_CLIENT(IS_PLAYER(it), { pl_cnt++; });
if (player.lms_spectate_warning != 2)
FOREACH_CLIENT(IS_PLAYER(it) && it.frags != FRAGS_LMS_LOSER, {
pl_cnt++;
});
if (player.lms_spectate_warning < 2)
{
if(IS_BOT_CLIENT(player))
bot_clear(player);
......@@ -220,12 +222,10 @@ void lms_RemovePlayer(entity player)
player.frags = FRAGS_LMS_LOSER;
TRANSMUTE(Observer, player);
}
if (pl_cnt == 2 && !warmup_stage) // a player is forfeiting leaving only one player
lms_lowest_lives = 0; // end the game now!
}
if(CS(player).killcount != FRAGS_SPECTATOR)
if(GameRules_scoring_add(player, LMS_RANK, 0) > 0 && player.lms_spectate_warning != 2)
if (CS(player).killcount != FRAGS_SPECTATOR && player.lms_spectate_warning < 3)
if (GameRules_scoring_add(player, LMS_RANK, 0) > 0 && player.lms_spectate_warning < 2)
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_LMS_NOLIVES, player.netname);
else
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_LMS_FORFEIT, player.netname);
......@@ -235,6 +235,9 @@ MUTATOR_HOOKFUNCTION(lms, ClientDisconnect)
{
entity player = M_ARGV(0, entity);
// no further message other than the disconnect message
player.lms_spectate_warning = 3;
lms_RemovePlayer(player);
}
......@@ -302,7 +305,9 @@ MUTATOR_HOOKFUNCTION(lms, GiveFragsForKill)
if(tl <= 0)
{
int pl_cnt = 0;
FOREACH_CLIENT(IS_PLAYER(it), { pl_cnt++; });
FOREACH_CLIENT(IS_PLAYER(it) && it.frags != FRAGS_LMS_LOSER, {
pl_cnt++;
});
if(IS_BOT_CLIENT(frag_target))
bot_clear(frag_target);
frag_target.frags = FRAGS_LMS_LOSER;
......
......@@ -571,6 +571,12 @@ MUTATOR_HOOKFUNCTION(mutator_instagib, OnEntityPreSpawn)
return true;
}
MUTATOR_HOOKFUNCTION(mutator_instagib, FixClientCvars)
{
entity player = M_ARGV(0, entity);
stuffcmd(player, "cl_cmd settemp _scoreboard_instagib 1\n");
}
MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsString)
{
M_ARGV(0, string) = strcat(M_ARGV(0, string), ":instagib");
......
......@@ -31,6 +31,8 @@ REGISTER_SP(SCORE);
REGISTER_SP(DMG);
REGISTER_SP(DMGTAKEN);
REGISTER_SP(COUNTRY);
REGISTER_SP(KILLS);
REGISTER_SP(DEATHS);
REGISTER_SP(SUICIDES);
......@@ -84,6 +86,9 @@ REGISTER_SP(NEXBALL_FAULTS);
REGISTER_SP(ONS_TAKES);
REGISTER_SP(ONS_CAPS);
// accuracy
REGISTER_SP(ACC_VAPORIZER);
#endif
......
......@@ -36,3 +36,4 @@
#include <server/mutators/_mod.inc>
#include <server/pathlib/_mod.inc>
#include <server/weapons/_mod.inc>
#include <server/ip2country.qc>
......@@ -580,7 +580,7 @@ void bot_calculate_stepheightvec()
jumpstepheightvec = stepheightvec + jumpheight_vec * 0.85; // reduce it a bit to make the jumps easy
}
float bot_fixcount()
bool bot_fixcount()
{
int activerealplayers = 0;
int realplayers = 0;
......
......@@ -88,7 +88,7 @@ int _content_type;
*/
entity bot_spawn();
float bot_fixcount();
bool bot_fixcount();
void bot_think(entity this);
void bot_setnameandstuff(entity this);
......
......@@ -15,6 +15,7 @@
#include "g_damage.qh"
#include "handicap.qh"
#include "g_hook.qh"
#include "ip2country.qh"
#include "command/common.qh"
#include "command/vote.qh"
#include "clientkill.qh"
......@@ -804,6 +805,7 @@ void PutClientInServer(entity this)
} else if (IS_PLAYER(this)) {
PutPlayerInServer(this);
}
SetCountryToScoreboard(this);
}
// TODO do we need all these fields, or should we stop autodetecting runtime
......@@ -984,6 +986,7 @@ void ClientPreConnect(entity this)
((IS_REAL_CLIENT(this)) ? this.netaddress : "bot")
));
}
IP2Country_SetPlayer(self);
}
#endif
......@@ -1131,6 +1134,10 @@ void ClientConnect(entity this)
CS(this).jointime = time;
#ifndef DP_EXT_PRECONNECT
IP2Country_SetPlayer(self);
#endif
if (IS_REAL_CLIENT(this))
{
if (g_weaponarena_weapons == WEPSET(TUBA))
......
......@@ -1648,6 +1648,27 @@ void GameCommand_warp(int request, int argc)
}
}
void GameCommand_ip2country(float request, float argc)
{
switch(request)
{
case CMD_REQUEST_COMMAND:
IP2Country_command(argc);
return;
case CMD_REQUEST_USAGE:
default:
LOG_INFO("\nUsage:^3 sv_cmd ip2country command [arguments]\n");
LOG_INFO("Available commands:\n");
LOG_INFO(" ^2status^7: list requests in process\n");
LOG_INFO(" ^2reset^7: timeout all current requests\n");
LOG_INFO(" ^2lookup ip^7: query country for ip\n");
LOG_INFO(" ^2flushcache^7: remove all ips from cache\n");
LOG_INFO(" ^2players^7: list players with ip and country code\n");
LOG_INFO(" ^2change ID CN^7: change country code by player id\n");
return;
}
}
/* use this when creating a new command, making sure to place it in alphabetical order... also,
** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
void GameCommand_(int request)
......@@ -1707,6 +1728,7 @@ SERVER_COMMAND(stuffto, "Send a command to be executed on a client") { GameComma
SERVER_COMMAND(trace, "Various debugging tools with tracing") { GameCommand_trace(request, arguments); }
SERVER_COMMAND(unlockteams, "Enable the ability for players to switch or enter teams") { GameCommand_unlockteams(request); }
SERVER_COMMAND(warp, "Choose different level in campaign") { GameCommand_warp(request, arguments); }
SERVER_COMMAND(ip2country, "Get country code by ip") { GameCommand_ip2country(request, arguments); }
void GameCommand_macro_help()
{
......
......@@ -18,6 +18,7 @@
#include "scores.qh"
#include "scores_rules.qh"
#include "teamplay.qh"
#include "ip2country.qh"
#include "weapons/weaponstats.qh"
#include "../common/constants.qh"
#include <common/net_linked.qh>
......@@ -882,6 +883,8 @@ spawnfunc(worldspawn)
WeaponStats_Init();
IP2Country_Init();
Nagger_Init();
next_pingtime = time + 5;
......@@ -2211,6 +2214,7 @@ void Shutdown()
db_save(TemporaryDB, "server-temp.db");
}
CheatShutdown(); // must be after cheatcount check
IP2Country_Cleanup();
db_close(ServerProgsDB);
db_close(TemporaryDB);
LOG_TRACE("Saving persistent data... done!");
......
#include "ip2country.qh"
float IP2Country_cachedb;
.entity ip2country_cbent;
.string netaddress;
.ip2country_callback callbackfunction;
.float started_at;
void IP2Country_Init() {
registercvar("sv_ip2country", "1");
registercvar("sv_ip2country_localcn", "XX");
registercvar("sv_ip2country_timeout", "15");
registercvar("sv_ip2country_server", "http://api.vinnica.in/country?type=xonotic&ip=");
LOG_INFO("Loading cached ips\n");
IP2Country_cachedb = db_load(IP2COUNTRY_DBNAME);
}
void IP2Country_Cleanup() {
entity e;
for(e = world; (e = find(e, classname, "ip2country_cbprovider"));)
IP2Country_FreeCallbackEnt(e);
LOG_INFO("Saving cached ips\n");
db_save(IP2Country_cachedb, IP2COUNTRY_DBNAME);
db_close(IP2Country_cachedb);
}
void IP2Country_CacheIP(string ip, string cn) {
LOG_DEBUGF("Cached ip %s %s\n", ip, cn);
db_put(IP2Country_cachedb, ip, cn);
}
string IP2Country_Cache_Get(string ip) {
return db_get(IP2Country_cachedb, ip);
}
void IP2Country_AddCallback(string ip, ip2country_callback callback, float timeout, entity callbackent) {
if(timeout <= 0)
timeout = cvar("sv_ip2country_timeout");
entity cb = spawn();
cb.classname = "ip2country_cbprovider";
cb.netaddress = strzone(ip);
cb.ip2country_cbent = callbackent;
cb.callbackfunction = callback;
cb.started_at = time;
setthink(cb, IP2Country_RequestTimeout);
cb.nextthink = time + timeout;
}
void IP2Country_ExecCallback(string ip, string cn) {
entity e;
for(e = world; (e = find(e, classname, "ip2country_cbprovider")); ) {
if(e.netaddress == ip) {
e.callbackfunction(ip, cn, e.ip2country_cbent);
IP2Country_FreeCallbackEnt(e);
}
}
}
void IP2Country_FreeCallbackEnt(entity e) {
if(e.netaddress)
strunzone(e.netaddress);
remove(e);
}
void IP2Country_RequestTimeout(entity e) {
LOG_INFOF("\nIP to country request for ip : %s timed out after %f", e.netaddress, time - e.started_at);
e.callbackfunction(e.netaddress, "", e.ip2country_cbent);
IP2Country_FreeCallbackEnt(e);
}
int is_local(string IP) {
string ipl;
ipl = strtolower(IP);
if(strncmp(ipl, "local", 5) == 0)
return 1;
else if(strncmp(ipl, "127.", 4) == 0)
return 1;
else if(strncmp(ipl, "10.", 3) == 0)
return 1;
else if(strncmp(ipl, "192.168.", 8) == 0)
return 1;
else if(strncmp(ipl, "169.254.", 8) == 0)
return 1;
else if(strncmp(ipl, "172.16.", 7) == 0)
return 1;
else
return 0;
}
void IP2Country_lookup(string ip, ip2country_callback callback, float timeout, entity cbent) {
string res;
if(!cvar("sv_ip2country"))
return;
if(is_local(ip) == 1) {
callback(ip, cvar_string("sv_ip2country_localcn"), cbent);
return;
}
res = IP2Country_Cache_Get(ip);
if(res != "") {
callback(ip, res, cbent);
return;
}
IP2Country_AddCallback(ip, callback, timeout, cbent);
if (cvar_string("sv_ip2country_server") == "") {
LOG_INFOF("\nCan't lookup ip - %s, because sv_ip2country_server is not set", ip);
return;
}
uri_get(strcat(cvar_string("sv_ip2country_server"), ip), URI_GET_IP2C);
}
void IP2Country_Get_Callback(float id, float status, string data) {
string cn, ip;
if (status) {
LOG_INFOF("\nIP lookup failed, status: %f", status);
return;
}
tokenizebyseparator(data, " ");
cn = substring(argv(0), 0, 2);
ip = argv(1);
if (cn == "--") {
LOG_INFOF("\nServer can't determine country for ip -- %s", ip);
IP2Country_ExecCallback(ip, "");
return;
}
IP2Country_CacheIP(ip, cn);
IP2Country_ExecCallback(ip, cn);
}
void IP2Country_DumpToConsole(string ip, string cn, entity e) {
LOG_INFOF("Country for IP %s: %s\n", ip, (cn == "") ? "Unknown" : cn);
}
void IP2Country_check(string ip) {
IP2Country_lookup(ip, IP2Country_DumpToConsole, 0, world);
}
void IP2Country_status() {
entity e;
LOG_INFO("^3Requests in process:\n");
for(e = world; (e = find(e, classname, "ip2country_cbprovider"));)
LOG_INFOF("%-30s: ^5%4.2f\n", e.netaddress, time - e.started_at);
}
void IP2Country_reset() {
entity e;
for(e = world; (e = find(e, classname, "ip2country_cbprovider"));) {
e.think();
}
}
void IP2Country_flushcache() {
db_close(IP2Country_cachedb);
IP2Country_cachedb = db_create();
db_save(IP2Country_cachedb, IP2COUNTRY_DBNAME);
LOG_INFO("ip2country cache flushed\n");
}
void SetPlayerCountry(entity player, string cn) {
if(player.ip2country_code)
strunzone(player.ip2country_code);
player.ip2country_code = strzone(strtoupper(cn));
}
void SetCountryToScoreboard(entity player) {
string cn;
if(CS(player).scorekeeper && player.ip2country_code) {
cn = player.ip2country_code;
PlayerScore_Set(player, SP_COUNTRY, (str2chr(cn, 0) << 8) + str2chr(cn, 1));
} else {
LOG_INFOF("Player %s has no scorekeeper\n", player.netname);
}
}
void IP2Country_PlayerCallback(string ip, string cn, entity player) {
SetPlayerCountry(player, cn);
}
void IP2Country_SetPlayer(entity player) {
if(IS_REAL_CLIENT(player))
IP2Country_lookup(player.netaddress, IP2Country_PlayerCallback, 0, player);
else
SetPlayerCountry(player, "");
}
void IP2Country_players() {
FOREACH_CLIENT(IS_REAL_CLIENT(it), {
LOG_INFOF("#%-2d %12s^7 %18s [%2s]\n", num_for_edict(it), it.netname, it.netaddress, it.ip2country_code);
});
}
void IP2Country_redraw() {
FOREACH_CLIENT(IS_REAL_CLIENT(it), {
SetCountryToScoreboard(it);
});
}
void IP2Country_ChangeCountry(entity player, string country) {
if(strlen(country) == 2 && IS_REAL_CLIENT(player)) {
SetPlayerCountry(player, country);
SetCountryToScoreboard(player);
}
}
void IP2Country_command(float argc) {
if(argc < 2)
goto wrong_argument;
switch(argv(1)) {
case "status":
IP2Country_status();
if (argc != 2)
goto wrong_argument;
return;
case "reset":
if (argc != 2)
goto wrong_argument;
IP2Country_reset();
return;
case "flushcache":
if (argc != 2)
goto wrong_argument;
IP2Country_flushcache();
return;
case "players":
if (argc != 2)
goto wrong_argument;
IP2Country_players();
return;
case "redraw":
if (argc != 2)
goto wrong_argument;
IP2Country_redraw();
return;
case "lookup":
if (argc != 3)
goto wrong_argument;
IP2Country_check(argv(2));
return;
case "change":
if (argc != 4)
goto wrong_argument;
entity client = GetFilteredEntity(argv(2));
IP2Country_ChangeCountry(client, argv(3));
return;
default:
LOG_INFO("Wrong command\n"
"Available commands: status,reset,flushcache,players,lookup,change\n");
return;
}
:wrong_argument
LOG_INFO("Wrong argument count\n");
}
#ifndef IP2COUNTRY_H
#define IP2COUNTRY_H
#define IP2COUNTRY_DBNAME "ip2country.db"
typedef void(string, string, entity) ip2country_callback;
const int URI_GET_IP2C = 33;
.string ip2country_code;
void IP2Country_Init();
void IP2Country_Cleanup();
void IP2Country_lookup(string, ip2country_callback, float, entity);
void IP2Country_Get_Callback(float, float, string);
void IP2Country_FreeCallbackEnt(entity);
void IP2Country_RequestTimeout(entity);
void IP2Country_check(string);
void IP2Country_command(float);
void IP2Country_SetPlayer(entity);
void IP2Country_redraw();
void SetCountryToScoreboard(entity);
#endif
......@@ -35,6 +35,7 @@
#include "../lib/csqcmodel/sv_model.qh"
#include "../lib/warpzone/anglestransform.qh"
#include "../lib/warpzone/server.qh"
#include "ip2country.qh"
void crosshair_trace(entity pl)
{
......@@ -1138,6 +1139,10 @@ void URI_Get_Callback(float id, float status, string data)
{
// handled
}
else if (id == URI_GET_IP2C)
{
IP2Country_Get_Callback(id, status, data);
}
else if (id == URI_GET_DISCARD)
{
// discard
......
......@@ -271,11 +271,13 @@ float PlayerScore_Clear(entity player)
sk = CS(player).scorekeeper;
FOREACH(Scores, true, {
if(it != SP_COUNTRY) {
if(sk.(scores(it)) != 0)
if(scores_label(it) != "")
sk.SendFlags |= (2 ** (i % 16));
if(i != SP_ELO.m_id)
sk.(scores(it)) = 0;
}
});
return 1;
......@@ -286,6 +288,7 @@ void Score_ClearAll()
entity sk;
float t;
FOREACH_CLIENTSLOT(true, {
if(it != SP_COUNTRY) {
sk = CS(it).scorekeeper;
if (!sk) continue;
FOREACH(Scores, true, {
......@@ -294,6 +297,7 @@ void Score_ClearAll()
sk.SendFlags |= (2 ** (i % 16));
if(i != SP_ELO.m_id)
sk.(scores(it)) = 0;
}
});
});
for(t = 0; t < 16; ++t)
......@@ -309,6 +313,7 @@ void Score_ClearAll()
sk.(teamscores(j)) = 0;
}
}
IP2Country_redraw();
}
void PlayerScore_Attach(entity player)
......
......@@ -51,6 +51,8 @@ void ScoreRules_basics(int teams, float sprio, float stprio, float score_enabled
ScoreInfo_SetLabel_PlayerScore(SP_DMG, "dmg", 0);
ScoreInfo_SetLabel_PlayerScore(SP_DMGTAKEN, "dmgtaken", SFL_LOWER_IS_BETTER);
ScoreInfo_SetLabel_PlayerScore(SP_ELO, "elo", 0);
ScoreInfo_SetLabel_PlayerScore(SP_COUNTRY, "country", 0);
ScoreInfo_SetLabel_PlayerScore(SP_ACC_VAPORIZER, "accuracy", 0);
if(STAT(SHOWFPS))
ScoreInfo_SetLabel_PlayerScore(SP_FPS, "fps", 0);
......
......@@ -63,6 +63,7 @@ void accuracy_resend(entity e)
void accuracy_add(entity this, Weapon w, int fired, int hit)
{
int orig_wep = w.m_id;
if (IS_INDEPENDENT_PLAYER(this)) return;
entity a = CS(this).accuracy;
if (!a) return;
......@@ -84,7 +85,22 @@ void accuracy_add(entity this, Weapon w, int fired, int hit)
a.fired_time = time;
}
if (b == accuracy_byte(a.accuracy_hit[wepid], a.accuracy_fired[wepid])) return; // no change
int new_b = accuracy_byte(a.accuracy_hit[wepid], a.accuracy_fired[wepid]);
if (b == new_b) return; // no change
if (orig_wep == WEP_VAPORIZER.m_id) {
int acc;
if (new_b == 0) {
acc = 0;
} else if (new_b == 255) {
acc = 1.0;
} else {
acc = (new_b - 1) / 100;
}
// hack to make acc look same
PlayerScore_Set(this, SP_ACC_VAPORIZER, acc * 100);
}
int sf = 1 << (wepid % 24);
a.SendFlags |= sf;
FOREACH_CLIENT(IS_SPEC(it) && it.enemy == this, { CS(it).accuracy.SendFlags |= sf; });
......
This diff is collapsed.