From: Mario Date: Mon, 17 Nov 2014 23:58:19 +0000 (+1100) Subject: Merge branch 'master' into samual/combined_updates X-Git-Tag: xonotic-v0.8.0~139^2~1^2~1 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=5e3a7beca384caa6f3da36fe07b29aff942e7b3e;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'master' into samual/combined_updates Conflicts: defaultXonotic.cfg effects-high.cfg effects-low.cfg effects-med.cfg effects-normal.cfg effects-omg.cfg effects-ultimate.cfg effects-ultra.cfg qcsrc/common/mapinfo.qh qcsrc/menu/xonotic/demolist.c qcsrc/menu/xonotic/dialog_settings_effects.c qcsrc/menu/xonotic/gametypelist.c qcsrc/menu/xonotic/mainwindow.c qcsrc/menu/xonotic/maplist.c qcsrc/server/cl_client.qc qcsrc/server/g_world.qc qcsrc/server/playerstats.qc qcsrc/server/progs.src --- 5e3a7beca384caa6f3da36fe07b29aff942e7b3e diff --cc effects-high.cfg index d28b69b43,456061536..48c8253a3 --- a/effects-high.cfg +++ b/effects-high.cfg @@@ -1,11 -1,10 +1,11 @@@ cl_decals 1 cl_decals_models 0 - cl_decals_time 4 + cl_decals_fadetime 4 -cl_particles_quality 1 +cl_particles 1 +cl_particles_quality 1.0 cl_damageeffect 1 cl_spawn_point_particles 1 - cl_playerdetailreduction 1 + cl_playerdetailreduction 4 gl_flashblend 0 gl_picmip -1 mod_q3bsp_nolightmaps 0 diff --cc effects-low.cfg index 3af46190f,d98ba526d..91459c7b0 --- a/effects-low.cfg +++ b/effects-low.cfg @@@ -1,7 -1,6 +1,7 @@@ cl_decals 1 cl_decals_models 0 - cl_decals_time 2 +cl_particles 1 + cl_decals_fadetime 2 cl_particles_quality 0.4 cl_damageeffect 0 cl_spawn_point_particles 0 diff --cc effects-med.cfg index 53034c19b,58191f266..66eed5aa5 --- a/effects-med.cfg +++ b/effects-med.cfg @@@ -1,11 -1,10 +1,11 @@@ cl_decals 1 cl_decals_models 0 - cl_decals_time 2 + cl_decals_fadetime 2 -cl_particles_quality 1 +cl_particles 1 +cl_particles_quality 0.8 cl_damageeffect 0 cl_spawn_point_particles 0 - cl_playerdetailreduction 3 + cl_playerdetailreduction 4 gl_flashblend 0 gl_picmip 0 mod_q3bsp_nolightmaps 0 diff --cc effects-normal.cfg index d7af2166c,dd8cce9a7..63dcd134a --- a/effects-normal.cfg +++ b/effects-normal.cfg @@@ -1,11 -1,10 +1,11 @@@ cl_decals 1 cl_decals_models 0 - cl_decals_time 2 + cl_decals_fadetime 2 -cl_particles_quality 1 +cl_particles 1 +cl_particles_quality 1.0 cl_damageeffect 1 cl_spawn_point_particles 1 - cl_playerdetailreduction 2 + cl_playerdetailreduction 4 gl_flashblend 0 gl_picmip 0 mod_q3bsp_nolightmaps 0 diff --cc effects-omg.cfg index eb1ae56f9,7c39fbbef..9e30a5fbd --- a/effects-omg.cfg +++ b/effects-omg.cfg @@@ -1,7 -1,6 +1,7 @@@ cl_decals 0 cl_decals_models 0 - cl_decals_time 2 +cl_particles 1 + cl_decals_fadetime 2 cl_particles_quality 0.4 cl_damageeffect 0 cl_spawn_point_particles 0 diff --cc effects-ultimate.cfg index d92cefe32,6897ccc16..0cf3a899c --- a/effects-ultimate.cfg +++ b/effects-ultimate.cfg @@@ -1,8 -1,7 +1,8 @@@ cl_decals 1 cl_decals_models 1 - cl_decals_time 10 + cl_decals_fadetime 10 -cl_particles_quality 1 +cl_particles 1 +cl_particles_quality 1.0 cl_damageeffect 2 cl_spawn_point_particles 1 cl_playerdetailreduction 0 diff --cc effects-ultra.cfg index 8da513bd0,d530f03b8..6095e189f --- a/effects-ultra.cfg +++ b/effects-ultra.cfg @@@ -1,11 -1,10 +1,11 @@@ cl_decals 1 cl_decals_models 0 - cl_decals_time 10 + cl_decals_fadetime 10 +cl_particles 1 - cl_particles_quality 1.0 - cl_damageeffect 2 + cl_particles_quality 1 + cl_damageeffect 1 cl_spawn_point_particles 1 - cl_playerdetailreduction 0 + cl_playerdetailreduction 2 gl_flashblend 0 gl_picmip -1 mod_q3bsp_nolightmaps 0 diff --cc gfx/menu/wickedx/skinvalues.txt index 00a026300,c5062d91a..9ef8d2bcb mode 100644,100755..100644 --- a/gfx/menu/wickedx/skinvalues.txt +++ b/gfx/menu/wickedx/skinvalues.txt diff --cc qcsrc/client/progs.src index dd51ffcf7,86a8b4339..d58bf3f11 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@@ -14,9 -15,10 +15,11 @@@ Defs.q ../warpzonelib/common.qh ../warpzonelib/client.qh +../common/playerstats.qh ../common/teams.qh ../common/util.qh + ../common/nades.qh + ../common/buffs.qh ../common/test.qh ../common/counting.qh ../common/items.qh diff --cc qcsrc/common/mapinfo.qh index 4efc85ca7,aa1d8fd5e..351fb679c --- a/qcsrc/common/mapinfo.qh +++ b/qcsrc/common/mapinfo.qh @@@ -7,10 -7,10 +7,11 @@@ entity MapInfo_Type_last .string netname; // game type name as in cvar (with g_ prefix) .string mdl; // game type short name .string message; // human readable name +.float team; // does this gametype support teamplay? .string model2; // game type defaults + .string gametype_description; // game type description - #define REGISTER_GAMETYPE(hname,sname,g_name,NAME,gteamplay,defaults) \ -#define REGISTER_GAMETYPE(hname,sname,g_name,NAME,defaults,gdescription) \ ++#define REGISTER_GAMETYPE(hname,sname,g_name,NAME,gteamplay,defaults,gdescription) \ var float MAPINFO_TYPE_##NAME; \ var entity MapInfo_Type##g_name; \ void RegisterGametypes_##g_name() \ @@@ -22,8 -22,8 +23,9 @@@ MapInfo_Type##g_name.netname = #g_name; \ MapInfo_Type##g_name.mdl = #sname; \ MapInfo_Type##g_name.message = hname; \ + MapInfo_Type##g_name.team = gteamplay; \ MapInfo_Type##g_name.model2 = defaults; \ + MapInfo_Type##g_name.gametype_description = gdescription; \ if(!MapInfo_Type_first) \ MapInfo_Type_first = MapInfo_Type##g_name; \ if(MapInfo_Type_last) \ @@@ -35,49 -35,49 +37,49 @@@ #define IS_GAMETYPE(NAME) \ (MapInfo_LoadedGametype == MAPINFO_TYPE_##NAME) - REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,FALSE,"timelimit=20 pointlimit=30 leadlimit=0"); -REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,"timelimit=20 pointlimit=30 leadlimit=0",_("Kill all enemies")); ++REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,FALSE,"timelimit=20 pointlimit=30 leadlimit=0",_("Kill all enemies")); #define g_dm IS_GAMETYPE(DEATHMATCH) - REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,FALSE,"timelimit=20 lives=9 leadlimit=0"); -REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,"timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left")); ++REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,FALSE,"timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left")); #define g_lms IS_GAMETYPE(LMS) - REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,FALSE,"timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0"); -REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,"timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line")); ++REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,FALSE,"timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line")); #define g_race IS_GAMETYPE(RACE) - REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,FALSE,"timelimit=20 skill=-1"); -REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,"timelimit=20 skill=-1",_("Race for fastest time")); ++REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,FALSE,"timelimit=20 skill=-1",_("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"); -REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,"timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Kill all enemy teammates")); ++REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,TRUE,"timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Kill all enemy teammates")); #define g_tdm IS_GAMETYPE(TEAM_DEATHMATCH) - REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,TRUE,"timelimit=20 caplimit=10 leadlimit=0"); -REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,"timelimit=20 caplimit=10 leadlimit=0",_("Find and bring the enemy flag to your base to capture it")); ++REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,TRUE,"timelimit=20 caplimit=10 leadlimit=0",_("Find and bring the enemy flag to your base to capture it")); #define g_ctf IS_GAMETYPE(CTF) - REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,TRUE,"timelimit=20 pointlimit=10 leadlimit=0"); -REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,"timelimit=20 pointlimit=10 leadlimit=0",_("Kill all enemy teammates to win the round")); ++REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,TRUE,"timelimit=20 pointlimit=10 leadlimit=0",_("Kill all enemy teammates to win the round")); #define g_ca IS_GAMETYPE(CA) - REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,TRUE,"timelimit=20 pointlimit=200 teams=2 leadlimit=0"); -REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,"timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture all the control points to win")); ++REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,TRUE,"timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture all the control points to win")); #define g_domination IS_GAMETYPE(DOMINATION) - REGISTER_GAMETYPE(_("Key Hunt"),kh,g_keyhunt,KEYHUNT,TRUE,"timelimit=20 pointlimit=1000 teams=3 leadlimit=0"); -REGISTER_GAMETYPE(_("Key Hunt"),kh,g_keyhunt,KEYHUNT,"timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round")); ++REGISTER_GAMETYPE(_("Key Hunt"),kh,g_keyhunt,KEYHUNT,TRUE,"timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round")); #define g_keyhunt IS_GAMETYPE(KEYHUNT) - REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,TRUE,"timelimit=20"); -REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,"timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out")); ++REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,TRUE,"timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out")); #define g_assault IS_GAMETYPE(ASSAULT) - REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,TRUE,"timelimit=20"); -REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,"timelimit=20",_("Capture control points to reach and destroy the enemy generator")); ++REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,TRUE,"timelimit=20",_("Capture control points to reach and destroy the enemy generator")); #define g_onslaught IS_GAMETYPE(ONSLAUGHT) - REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,TRUE,"timelimit=20 pointlimit=5 leadlimit=0"); -REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,"timelimit=20 pointlimit=5 leadlimit=0",_("XonSports")); ++REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,TRUE,"timelimit=20 pointlimit=5 leadlimit=0",_("XonSports")); #define g_nexball IS_GAMETYPE(NEXBALL) - REGISTER_GAMETYPE(_("Freeze Tag"),ft,g_freezetag,FREEZETAG,TRUE,"timelimit=20 pointlimit=10 teams=2 leadlimit=0"); -REGISTER_GAMETYPE(_("Freeze Tag"),ft,g_freezetag,FREEZETAG,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to teammates to revive them")); ++REGISTER_GAMETYPE(_("Freeze Tag"),ft,g_freezetag,FREEZETAG,TRUE,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to teammates to revive them")); #define g_freezetag IS_GAMETYPE(FREEZETAG) - REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,FALSE,"timelimit=20 pointlimit=30"); -REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,"timelimit=20 pointlimit=30",_("Hold the ball to get points for kills")); ++REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,TRUE,"timelimit=20 pointlimit=30",_("Hold the ball to get points for kills")); #define g_keepaway IS_GAMETYPE(KEEPAWAY) - REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,FALSE,"pointlimit=5"); -REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,"pointlimit=50 teams=0",_("Survive against waves of monsters")); ++REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,FALSE,"pointlimit=50 teams=0",_("Survive against waves of monsters")); #define g_invasion IS_GAMETYPE(INVASION) const float MAPINFO_FEATURE_WEAPONS = 1; // not defined for minstagib-only maps @@@ -141,8 -142,8 +144,9 @@@ string MapInfo_ListAllAllowedMaps(floa // gets a gametype from a string string _MapInfo_GetDefaultEx(float t); +float _MapInfo_GetTeamPlayBool(float t); float MapInfo_Type_FromString(string t); + string MapInfo_Type_Description(float t); string MapInfo_Type_ToString(float t); string MapInfo_Type_ToText(float t); void MapInfo_SwitchGameType(float t); diff --cc qcsrc/menu/classes.c index a22a60eac,ee1ce5d31..2cc5f7d81 --- a/qcsrc/menu/classes.c +++ b/qcsrc/menu/classes.c @@@ -34,11 -34,11 +34,12 @@@ #include "xonotic/dialog_settings_video.c" #include "xonotic/dialog_settings_effects.c" #include "xonotic/dialog_settings_audio.c" +#include "xonotic/dialog_settings_game.c" #include "xonotic/dialog_settings_user.c" + #include "xonotic/dialog_settings_user_languagewarning.c" #include "xonotic/dialog_settings_misc.c" #include "xonotic/dialog_multiplayer.c" -#include "xonotic/dialog_multiplayer_playersetup.c" +#include "xonotic/dialog_multiplayer_profile.c" #include "xonotic/tabcontroller.c" #include "xonotic/textlabel.c" #include "xonotic/slider.c" @@@ -119,6 -111,5 +120,7 @@@ #include "xonotic/dialog_hudpanel_weapons.c" #include "xonotic/dialog_hudpanel_physics.c" #include "xonotic/dialog_hudpanel_centerprint.c" + #include "xonotic/dialog_hudpanel_buffs.c" #include "xonotic/slider_picmip.c" +#include "xonotic/slider_particles.c" +#include "xonotic/slider_sbfadetime.c" diff --cc qcsrc/menu/xonotic/demolist.c index 55e1ccc31,cf0e987c0..f04fde83d --- a/qcsrc/menu/xonotic/demolist.c +++ b/qcsrc/menu/xonotic/demolist.c @@@ -140,7 -104,7 +140,7 @@@ void XonoticDemoList_drawListBoxItem(en s = me.demoName(me,i); s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize); - draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1); - draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0); ++ draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 1); } void XonoticDemoList_showNotify(entity me) diff --cc qcsrc/menu/xonotic/dialog_multiplayer_create.c index 2c4ca4e5a,e4aa1d6d9..9da8419a3 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_create.c @@@ -2,9 -2,10 +2,10 @@@ CLASS(XonoticServerCreateTab) EXTENDS(XonoticTab) METHOD(XonoticServerCreateTab, fill, void(entity)) METHOD(XonoticServerCreateTab, gameTypeChangeNotify, void(entity)) + METHOD(XonoticServerCreateTab, gameTypeSelectNotify, void(entity)) ATTRIB(XonoticServerCreateTab, title, string, _("Create")) ATTRIB(XonoticServerCreateTab, intendedWidth, float, 0.9) - ATTRIB(XonoticServerCreateTab, rows, float, 22) + ATTRIB(XonoticServerCreateTab, rows, float, 23) ATTRIB(XonoticServerCreateTab, columns, float, 6.2) // added extra .2 for center space ATTRIB(XonoticServerCreateTab, mapListBox, entity, NULL) diff --cc qcsrc/menu/xonotic/dialog_settings_effects.c index 16d364425,e3b562ee3..11cad9fa8 --- a/qcsrc/menu/xonotic/dialog_settings_effects.c +++ b/qcsrc/menu/xonotic/dialog_settings_effects.c @@@ -171,7 -166,7 +171,6 @@@ void XonoticEffectsSettingsTab_fill(ent me.TDempty(me, 0.2); me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "r_coronas_occlusionquery", _("Fade corona according to visibility"))); setDependent(e, "r_coronas", 1, 1); -- me.TR(me); me.TR(me); me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_bloom", _("Bloom"))); me.TD(me, 1, 2, e = makeXonoticCheckBoxEx(0.5, 0, "hud_postprocessing_maxbluralpha", _("Extra postprocessing effects"))); @@@ -183,18 -178,23 +182,29 @@@ if(s.value != e.savedValue) e.savedValue = 0.4; // default me.TD(me, 1, 2, s); - me.TR(me); me.TR(me); + me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_particles", _("Particles"))); + me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_spawn_point_particles", _("Spawnpoint effects"))); + makeMulti(e, "cl_spawn_event_particles"); + setDependent(e, "cl_particles", 1, 1); me.TR(me); - me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_decals", _("Decals"))); - me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_decals_models", _("Decals on models"))); - setDependent(e, "cl_decals", 1, 1); - me.TR(me); + me.TDempty(me, 0.2); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Quality:"))); + setDependent(e, "cl_particles", 1, 1); + me.TD(me, 1, 2, e = makeXonoticParticlesSlider()); + setDependent(e, "cl_particles", 1, 1); ++ me.TR(me); + me.TDempty(me, 0.2); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:"))); + setDependent(e, "cl_decals", 1, 1); + me.TD(me, 1, 2, e = makeXonoticSlider(200, 500, 20, "r_drawdecals_drawdistance")); + setDependent(e, "cl_decals", 1, 1); - me.TR(me); ++ me.TR(me); + me.TDempty(me, 0.2); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Time:"))); + setDependent(e, "cl_decals", 1, 1); + me.TD(me, 1, 2, e = makeXonoticSlider(1, 20, 1, "cl_decals_fadetime")); + setDependent(e, "cl_decals", 1, 1); me.gotoRC(me, me.rows - 1, 0); me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "vid_restart", COMMANDBUTTON_APPLY)); diff --cc qcsrc/menu/xonotic/gametypelist.c index 59d41f5ab,8883e8bbe..ffb5ef027 --- a/qcsrc/menu/xonotic/gametypelist.c +++ b/qcsrc/menu/xonotic/gametypelist.c @@@ -7,9 -7,11 +7,10 @@@ CLASS(XonoticGametypeList) EXTENDS(Xono METHOD(XonoticGametypeList, setSelected, void(entity, float)) METHOD(XonoticGametypeList, loadCvars, void(entity)) METHOD(XonoticGametypeList, saveCvars, void(entity)) + METHOD(XonoticGametypeList, keyDown, float(entity, float, float, float)) ATTRIB(XonoticGametypeList, realFontSize, vector, '0 0 0') - ATTRIB(XonoticGametypeList, realUpperMargin1, float, 0) - ATTRIB(XonoticGametypeList, realUpperMargin2, float, 0) + ATTRIB(XonoticGametypeList, realUpperMargin, float, 0) ATTRIB(XonoticGametypeList, columnIconOrigin, float, 0) ATTRIB(XonoticGametypeList, columnIconSize, float, 0) ATTRIB(XonoticGametypeList, columnNameOrigin, float, 0) @@@ -82,14 -84,9 +83,16 @@@ void XonoticGametypeList_drawListBoxIte draw_Picture(me.columnIconOrigin * eX, GameType_GetIcon(i), me.columnIconSize * eX + eY, '1 1 1', SKINALPHA_LISTBOX_SELECTED); s = GameType_GetName(i); + draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0); + + if(_MapInfo_GetTeamPlayBool(GameType_GetID(i))) + s = _("teamplay"); + else + s = _("free for all"); + - draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT * 0.5, 0); + draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.5 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0); + //s = GameType_GetTeams(i); + //draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 1.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0); } void XonoticGametypeList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize) { @@@ -98,10 -95,22 +101,21 @@@ me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize_y * me.itemHeight)); me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize_x * (1 - me.controlWidth))); - me.realUpperMargin1 = 0.5 * (1 - me.realFontSize_y); - me.realUpperMargin2 = me.realUpperMargin1 + me.realFontSize_y; + me.realUpperMargin = 0.5 * (1 - me.realFontSize_y); me.columnIconOrigin = 0; me.columnIconSize = me.itemAbsSize_y / me.itemAbsSize_x; - me.columnNameOrigin = me.columnIconOrigin + me.columnIconSize; - me.columnNameSize = 1 - me.columnIconSize - 2 * me.realFontSize_x; + me.columnNameOrigin = me.columnIconOrigin + me.columnIconSize + (0.5 * me.realFontSize_x); + me.columnNameSize = 1 - me.columnIconSize - (1.5 * me.realFontSize_x); } + + float XonoticGametypeList_keyDown(entity me, float scan, float ascii, float shift) + { + if(scan == K_ENTER || scan == K_KP_ENTER) + { + me.parent.gameTypeSelectNotify(me.parent); + return 1; + } + + return SUPER(XonoticGametypeList).keyDown(me, scan, ascii, shift); + } #endif diff --cc qcsrc/menu/xonotic/mainwindow.c index ef98fbd19,5c58025fc..178b3fc73 --- a/qcsrc/menu/xonotic/mainwindow.c +++ b/qcsrc/menu/xonotic/mainwindow.c @@@ -10,9 -11,12 +10,10 @@@ CLASS(MainWindow) EXTENDS(ModalControll ATTRIB(MainWindow, winnerDialog, entity, NULL) ATTRIB(MainWindow, serverInfoDialog, entity, NULL) ATTRIB(MainWindow, cvarsDialog, entity, NULL) + ATTRIB(MainWindow, screenshotViewerDialog, entity, NULL) ATTRIB(MainWindow, viewDialog, entity, NULL) - ATTRIB(MainWindow, modelDialog, entity, NULL) - ATTRIB(MainWindow, crosshairDialog, entity, NULL) - ATTRIB(MainWindow, hudDialog, entity, NULL) ATTRIB(MainWindow, hudconfirmDialog, entity, NULL) + ATTRIB(MainWindow, languageWarningDialog, entity, NULL) ATTRIB(MainWindow, mainNexposee, entity, NULL) ATTRIB(MainWindow, fadedAlpha, float, SKINALPHA_BEHIND) ATTRIB(MainWindow, dialogToShow, entity, NULL) @@@ -138,10 -140,10 +143,15 @@@ void MainWindow_configureMainWindow(ent i.configureDialog(i); me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + me.languageWarningDialog = i = spawnXonoticLanguageWarningDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + me.hudconfirmDialog = i = spawnXonoticHUDConfirmDialog(); ++ me.languageWarningDialog = i = spawnXonoticLanguageWarningDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + // dialog used by singleplayer me.winnerDialog = i = spawnXonoticWinnerDialog(); diff --cc qcsrc/server/cl_client.qc index 4fb794aa7,84657d6f6..c747a44f5 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@@ -1265,8 -1236,10 +1238,10 @@@ void ClientDisconnect (void return; } - if(IS_PLAYER(self)) { pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); } + PlayerStats_GameReport_FinalizePlayer(self); - PlayerStats_AddGlobalInfo(self); ++ if(IS_PLAYER(self)) { pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); } + CheatShutdownClient(); if(self.hitplotfh >= 0) diff --cc qcsrc/server/mapvoting.qc index 000000000,3e1a86620..9a2cb1871 mode 000000,100644..100644 --- a/qcsrc/server/mapvoting.qc +++ b/qcsrc/server/mapvoting.qc @@@ -1,0 -1,742 +1,741 @@@ + float GameTypeVote_AvailabilityStatus(string gtname) + { + float type = MapInfo_Type_FromString(gtname); + if( type == 0 ) + return GTV_FORBIDDEN; + + if ( autocvar_nextmap != "" ) + { + if ( !MapInfo_Get_ByName(autocvar_nextmap, FALSE, 0) ) + return GTV_FORBIDDEN; + if (!(MapInfo_Map_supportedGametypes & type)) + return GTV_FORBIDDEN; + } + + return GTV_AVAILABLE; + } + + float GameTypeVote_GetMask() + { + float n, j, gametype_mask; + n = tokenizebyseparator(autocvar_sv_vote_gametype_options, " "); + n = min(MAPVOTE_COUNT, n); + gametype_mask = 0; + for(j = 0; j < n; ++j) + gametype_mask |= MapInfo_Type_FromString(argv(j)); + return gametype_mask; + } + + string GameTypeVote_MapInfo_FixName(string m) + { + if ( autocvar_sv_vote_gametype ) + { + MapInfo_Enumerate(); + MapInfo_FilterGametype(GameTypeVote_GetMask(), 0, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0); + } + return MapInfo_FixName(m); + } + + void MapVote_ClearAllVotes() + { + FOR_EACH_CLIENT(other) + other.mapvote = 0; + } + + void MapVote_UnzoneStrings() + { + float j; + for(j = 0; j < mapvote_count; ++j) + { + if ( mapvote_maps[j] ) + { + strunzone(mapvote_maps[j]); + mapvote_maps[j] = string_null; + } + if ( mapvote_maps_pakfile[j] ) + { + strunzone(mapvote_maps_pakfile[j]); + mapvote_maps_pakfile[j] = string_null; + } + } + } + + string MapVote_Suggest(string m) + { + float i; + if(m == "") + return "That's not how to use this command."; + if(!autocvar_g_maplist_votable_suggestions) + return "Suggestions are not accepted on this server."; + if(mapvote_initialized) + if(!gametypevote) + return "Can't suggest - voting is already in progress!"; + m = GameTypeVote_MapInfo_FixName(m); + if (!m) + return "The map you suggested is not available on this server."; + if(!autocvar_g_maplist_votable_suggestions_override_mostrecent) + if(Map_IsRecent(m)) + return "This server does not allow for recent maps to be played again. Please be patient for some rounds."; + + if (!autocvar_sv_vote_gametype) + if(!MapInfo_CheckMap(m)) + return "The map you suggested does not support the current game mode."; + for(i = 0; i < mapvote_suggestion_ptr; ++i) + if(mapvote_suggestions[i] == m) + return "This map was already suggested."; + if(mapvote_suggestion_ptr >= MAPVOTE_COUNT) + { + i = floor(random() * mapvote_suggestion_ptr); + } + else + { + i = mapvote_suggestion_ptr; + mapvote_suggestion_ptr += 1; + } + if(mapvote_suggestions[i] != "") + strunzone(mapvote_suggestions[i]); + mapvote_suggestions[i] = strzone(m); + if(autocvar_sv_eventlog) + GameLogEcho(strcat(":vote:suggested:", m, ":", ftos(self.playerid))); + return strcat("Suggestion of ", m, " accepted."); + } + + void MapVote_AddVotable(string nextMap, float isSuggestion) + { + float j, i, o; + string pakfile, mapfile; + + if(nextMap == "") + return; + for(j = 0; j < mapvote_count; ++j) + if(mapvote_maps[j] == nextMap) + return; + // suggestions might be no longer valid/allowed after gametype switch! + if(isSuggestion) + if(!MapInfo_CheckMap(nextMap)) + return; + mapvote_maps[mapvote_count] = strzone(nextMap); + mapvote_maps_suggested[mapvote_count] = isSuggestion; + + pakfile = string_null; + for(i = 0; i < mapvote_screenshot_dirs_count; ++i) + { + mapfile = strcat(mapvote_screenshot_dirs[i], "/", mapvote_maps[i]); + pakfile = whichpack(strcat(mapfile, ".tga")); + if(pakfile == "") + pakfile = whichpack(strcat(mapfile, ".jpg")); + if(pakfile == "") + pakfile = whichpack(strcat(mapfile, ".png")); + if(pakfile != "") + break; + } + if(i >= mapvote_screenshot_dirs_count) + i = 0; // FIXME maybe network this error case, as that means there is no mapshot on the server? + for(o = strstr(pakfile, "/", 0)+1; o > 0; o = strstr(pakfile, "/", 0)+1) + pakfile = substring(pakfile, o, -1); + + mapvote_maps_screenshot_dir[mapvote_count] = i; + mapvote_maps_pakfile[mapvote_count] = strzone(pakfile); + mapvote_maps_availability[mapvote_count] = GTV_AVAILABLE; + + mapvote_count += 1; + } + + void MapVote_Init() + { + float i; + float nmax, smax; + + MapVote_ClearAllVotes(); + MapVote_UnzoneStrings(); + + mapvote_count = 0; + mapvote_detail = !autocvar_g_maplist_votable_nodetail; + mapvote_abstain = autocvar_g_maplist_votable_abstain; + + if(mapvote_abstain) + nmax = min(MAPVOTE_COUNT - 1, autocvar_g_maplist_votable); + else + nmax = min(MAPVOTE_COUNT, autocvar_g_maplist_votable); + smax = min3(nmax, autocvar_g_maplist_votable_suggestions, mapvote_suggestion_ptr); + + // we need this for AddVotable, as that cycles through the screenshot dirs + mapvote_screenshot_dirs_count = tokenize_console(autocvar_g_maplist_votable_screenshot_dir); + if(mapvote_screenshot_dirs_count == 0) + mapvote_screenshot_dirs_count = tokenize_console("maps levelshots"); + mapvote_screenshot_dirs_count = min(mapvote_screenshot_dirs_count, MAPVOTE_SCREENSHOT_DIRS_COUNT); + for(i = 0; i < mapvote_screenshot_dirs_count; ++i) + mapvote_screenshot_dirs[i] = strzone(argv(i)); + + if(mapvote_suggestion_ptr) + for(i = 0; i < 100 && mapvote_count < smax; ++i) + MapVote_AddVotable(mapvote_suggestions[floor(random() * mapvote_suggestion_ptr)], TRUE); + + for(i = 0; i < 100 && mapvote_count < nmax; ++i) + MapVote_AddVotable(GetNextMap(), FALSE); + + if(mapvote_count == 0) + { + bprint( "Maplist contains no single playable map! Resetting it to default map list.\n" ); + cvar_set("g_maplist", MapInfo_ListAllowedMaps(MapInfo_CurrentGametype(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags())); + if(autocvar_g_maplist_shuffle) + ShuffleMaplist(); + localcmd("\nmenu_cmd sync\n"); + for(i = 0; i < 100 && mapvote_count < nmax; ++i) + MapVote_AddVotable(GetNextMap(), FALSE); + } + + mapvote_count_real = mapvote_count; + if(mapvote_abstain) + MapVote_AddVotable("don't care", 0); + + //dprint("mapvote count is ", ftos(mapvote_count), "\n"); + + mapvote_keeptwotime = time + autocvar_g_maplist_votable_keeptwotime; + mapvote_timeout = time + autocvar_g_maplist_votable_timeout; + if(mapvote_count_real < 3 || mapvote_keeptwotime <= time) + mapvote_keeptwotime = 0; + mapvote_message = "Choose a map and press its key!"; + + MapVote_Spawn(); + } + + void MapVote_SendPicture(float id) + { + msg_entity = self; + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(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); + } + + + void MapVote_WriteMask() + { + float i; + if ( mapvote_count < 24 ) + { + float mask,power; + mask = 0; + for(i = 0, power = 1; i < mapvote_count; ++i, power *= 2) + if(mapvote_maps_availability[i] == GTV_AVAILABLE ) + mask |= power; + + if(mapvote_count < 8) + WriteByte(MSG_ENTITY, mask); + else if (mapvote_count < 16) + WriteShort(MSG_ENTITY,mask); + else + WriteLong(MSG_ENTITY, mask); + } + else + { + for ( i = 0; i < mapvote_count; ++i ) + WriteByte(MSG_ENTITY, mapvote_maps_availability[i]); + } + } + + float MapVote_SendEntity(entity to, float sf) + { + float i; + + if(sf & 1) + sf &= ~2; // if we send 1, we don't need to also send 2 + + WriteByte(MSG_ENTITY, ENT_CLIENT_MAPVOTE); + WriteByte(MSG_ENTITY, sf); + + if(sf & 1) + { + // flag 1 == initialization + for(i = 0; i < mapvote_screenshot_dirs_count; ++i) + WriteString(MSG_ENTITY, mapvote_screenshot_dirs[i]); + WriteString(MSG_ENTITY, ""); + WriteByte(MSG_ENTITY, mapvote_count); + WriteByte(MSG_ENTITY, mapvote_abstain); + WriteByte(MSG_ENTITY, mapvote_detail); + WriteCoord(MSG_ENTITY, mapvote_timeout); + + if ( gametypevote ) + { + // gametype vote + WriteByte(MSG_ENTITY, 1); + WriteString(MSG_ENTITY, autocvar_nextmap); + } + else if ( autocvar_sv_vote_gametype ) + { + // map vote but gametype has been chosen via voting screen + WriteByte(MSG_ENTITY, 2); + WriteString(MSG_ENTITY, MapInfo_Type_ToText(MapInfo_CurrentGametype())); + } + else + WriteByte(MSG_ENTITY, 0); // map vote + + MapVote_WriteMask(); + + for(i = 0; i < mapvote_count; ++i) + { + if(mapvote_abstain && i == mapvote_count - 1) + { + WriteString(MSG_ENTITY, ""); // abstain needs no text + WriteString(MSG_ENTITY, ""); // abstain needs no pack + WriteByte(MSG_ENTITY, 0); // abstain needs no screenshot dir + WriteByte(MSG_ENTITY, GTV_AVAILABLE); + } + else + { + WriteString(MSG_ENTITY, mapvote_maps[i]); + WriteString(MSG_ENTITY, mapvote_maps_pakfile[i]); + WriteByte(MSG_ENTITY, mapvote_maps_screenshot_dir[i]); + WriteByte(MSG_ENTITY, mapvote_maps_availability[i]); + } + } + } + + if(sf & 2) + { + // flag 2 == update of mask + MapVote_WriteMask(); + } + + if(sf & 4) + { + if(mapvote_detail) + for(i = 0; i < mapvote_count; ++i) + if ( mapvote_maps_availability[i] == GTV_AVAILABLE ) + WriteByte(MSG_ENTITY, mapvote_selections[i]); + + WriteByte(MSG_ENTITY, to.mapvote); + } + + return TRUE; + } + + void MapVote_Spawn() + { + Net_LinkEntity(mapvote_ent = spawn(), FALSE, 0, MapVote_SendEntity); + } + + void MapVote_TouchMask() + { + mapvote_ent.SendFlags |= 2; + } + + void MapVote_TouchVotes(entity voter) + { + mapvote_ent.SendFlags |= 4; + } + + float MapVote_Finished(float mappos) + { + if(alreadychangedlevel) + return FALSE; + + string result; + float i; + float didntvote; + + if(autocvar_sv_eventlog) + { + result = strcat(":vote:finished:", mapvote_maps[mappos]); + result = strcat(result, ":", ftos(mapvote_selections[mappos]), "::"); + didntvote = mapvote_voters; + for(i = 0; i < mapvote_count; ++i) + if(mapvote_maps_availability[i] == GTV_AVAILABLE ) + { + didntvote -= mapvote_selections[i]; + if(i != mappos) + { + result = strcat(result, ":", mapvote_maps[i]); + result = strcat(result, ":", ftos(mapvote_selections[i])); + } + } + result = strcat(result, ":didn't vote:", ftos(didntvote)); + + GameLogEcho(result); + if(mapvote_maps_suggested[mappos]) + GameLogEcho(strcat(":vote:suggestion_accepted:", mapvote_maps[mappos])); + } + + FOR_EACH_REALCLIENT(other) + FixClientCvars(other); + + if(gametypevote) + { + if ( GameTypeVote_Finished(mappos) ) + { + gametypevote = FALSE; + if(autocvar_nextmap != "") + { + Map_Goto_SetStr(autocvar_nextmap); + Map_Goto(0); + alreadychangedlevel = TRUE; + return TRUE; + } + else + MapVote_Init(); + } + return FALSE; + } + + Map_Goto_SetStr(mapvote_maps[mappos]); + Map_Goto(0); + alreadychangedlevel = TRUE; + + return TRUE; + } + + void MapVote_CheckRules_1() + { + float i; + + for(i = 0; i < mapvote_count; ++i) + if( mapvote_maps_availability[i] == GTV_AVAILABLE ) + { + //dprint("Map ", ftos(i), ": "); dprint(mapvote_maps[i], "\n"); + mapvote_selections[i] = 0; + } + + mapvote_voters = 0; + FOR_EACH_REALCLIENT(other) + { + ++mapvote_voters; + if(other.mapvote) + { + i = other.mapvote - 1; + //dprint("Player ", other.netname, " vote = ", ftos(other.mapvote - 1), "\n"); + mapvote_selections[i] = mapvote_selections[i] + 1; + } + } + } + + float MapVote_CheckRules_2() + { + float i; + float firstPlace, secondPlace, currentPlace; + float firstPlaceVotes, secondPlaceVotes, currentVotes; + float mapvote_voters_real; + string result; + + if(mapvote_count_real == 1) + return MapVote_Finished(0); + + mapvote_voters_real = mapvote_voters; + if(mapvote_abstain) + mapvote_voters_real -= mapvote_selections[mapvote_count - 1]; + + RandomSelection_Init(); + currentPlace = 0; + currentVotes = -1; + for(i = 0; i < mapvote_count_real; ++i) + if ( mapvote_maps_availability[i] == GTV_AVAILABLE ) + { + RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]); + if ( gametypevote && mapvote_maps[i] == MapInfo_Type_ToString(MapInfo_CurrentGametype()) ) + { + currentVotes = mapvote_selections[i]; + currentPlace = i; + } + } + firstPlaceVotes = RandomSelection_best_priority; + if ( autocvar_sv_vote_gametype_default_current && currentVotes == firstPlaceVotes ) + firstPlace = currentPlace; + else + firstPlace = RandomSelection_chosen_float; + + //dprint("First place: ", ftos(firstPlace), "\n"); + //dprint("First place votes: ", ftos(firstPlaceVotes), "\n"); + + RandomSelection_Init(); + for(i = 0; i < mapvote_count_real; ++i) + if(i != firstPlace) + if ( mapvote_maps_availability[i] == GTV_AVAILABLE ) + RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]); + secondPlace = RandomSelection_chosen_float; + secondPlaceVotes = RandomSelection_best_priority; + //dprint("Second place: ", ftos(secondPlace), "\n"); + //dprint("Second place votes: ", ftos(secondPlaceVotes), "\n"); + + if(firstPlace == -1) + error("No first place in map vote... WTF?"); + + if(secondPlace == -1 || time > mapvote_timeout || (mapvote_voters_real - firstPlaceVotes) < firstPlaceVotes) + return MapVote_Finished(firstPlace); + + if(mapvote_keeptwotime) + if(time > mapvote_keeptwotime || (mapvote_voters_real - firstPlaceVotes - secondPlaceVotes) < secondPlaceVotes) + { + float didntvote; + MapVote_TouchMask(); + mapvote_message = "Now decide between the TOP TWO!"; + mapvote_keeptwotime = 0; + result = strcat(":vote:keeptwo:", mapvote_maps[firstPlace]); + result = strcat(result, ":", ftos(firstPlaceVotes)); + result = strcat(result, ":", mapvote_maps[secondPlace]); + result = strcat(result, ":", ftos(secondPlaceVotes), "::"); + didntvote = mapvote_voters; + for(i = 0; i < mapvote_count; ++i) + { + didntvote -= mapvote_selections[i]; + if(i != firstPlace) + if(i != secondPlace) + { + result = strcat(result, ":", mapvote_maps[i]); + result = strcat(result, ":", ftos(mapvote_selections[i])); + if(i < mapvote_count_real) + { + mapvote_maps_availability[i] = GTV_FORBIDDEN; + } + } + } + result = strcat(result, ":didn't vote:", ftos(didntvote)); + if(autocvar_sv_eventlog) + GameLogEcho(result); + } + + return FALSE; + } + + void MapVote_Tick() + { + float keeptwo; + float totalvotes; + + keeptwo = mapvote_keeptwotime; + MapVote_CheckRules_1(); // count + if(MapVote_CheckRules_2()) // decide + return; + + totalvotes = 0; + FOR_EACH_REALCLIENT(other) + { + // hide scoreboard again + if(other.health != 2342) + { + other.health = 2342; + other.impulse = 0; + if(IS_REAL_CLIENT(other)) + { + msg_entity = other; + WriteByte(MSG_ONE, SVC_FINALE); + WriteString(MSG_ONE, ""); + } + } + + // clear possibly invalid votes + if ( mapvote_maps_availability[other.mapvote-1] != GTV_AVAILABLE ) + other.mapvote = 0; + // use impulses as new vote + if(other.impulse >= 1 && other.impulse <= mapvote_count) + if( mapvote_maps_availability[other.impulse - 1] == GTV_AVAILABLE ) + { + other.mapvote = other.impulse; + MapVote_TouchVotes(other); + } + other.impulse = 0; + + if(other.mapvote) + ++totalvotes; + } + + MapVote_CheckRules_1(); // just count + } + + void MapVote_Start() + { - if(mapvote_run) - return; ++ // if mapvote is already running, don't do this initialization again ++ if(mapvote_run) { return; } + - // wait for stats to be sent first - if(!playerstats_waitforme) - return; ++ // don't start mapvote until after playerstats gamereport is sent ++ if(PlayerStats_GameReport_DelayMapVote) { return; } + + MapInfo_Enumerate(); + if(MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1)) + mapvote_run = TRUE; + } + + void MapVote_Think() + { + if(!mapvote_run) + return; + + if(alreadychangedlevel) + return; + + if(time < mapvote_nextthink) + return; + //dprint("tick\n"); + + mapvote_nextthink = time + 0.5; + + if(!mapvote_initialized) + { + if(autocvar_rescan_pending == 1) + { + cvar_set("rescan_pending", "2"); + localcmd("fs_rescan\nrescan_pending 3\n"); + return; + } + else if(autocvar_rescan_pending == 2) + { + return; + } + else if(autocvar_rescan_pending == 3) + { + // now build missing mapinfo files + if(!MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1)) + return; + + // we're done, start the timer + cvar_set("rescan_pending", "0"); + } + + mapvote_initialized = TRUE; + if(DoNextMapOverride(0)) + return; + if(!autocvar_g_maplist_votable || player_count <= 0) + { + GotoNextMap(0); + return; + } + + if(autocvar_sv_vote_gametype) { GameTypeVote_Start(); } + else if(autocvar_nextmap == "") { MapVote_Init(); } + } + + MapVote_Tick(); + } + + float GameTypeVote_SetGametype(float type) + { + if (MapInfo_CurrentGametype() == type) + return TRUE; + + float tsave = MapInfo_CurrentGametype(); + + MapInfo_SwitchGameType(type); + + MapInfo_Enumerate(); + MapInfo_FilterGametype(type, MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 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); } + lsmaps_reply = strzone(getlsmaps()); + bprint("Game type successfully switched to ", MapInfo_Type_ToString(type), "\n"); + } + else + { + bprint("Cannot use this game type: no map for it found\n"); + MapInfo_SwitchGameType(tsave); + MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0); + return FALSE; + } + + //localcmd("gametype ", MapInfo_Type_ToString(type), "\n"); + + cvar_set("g_maplist", MapInfo_ListAllowedMaps(type, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()) ); + if(autocvar_g_maplist_shuffle) + ShuffleMaplist(); + + return TRUE; + } + + float gametypevote_finished; + float GameTypeVote_Finished(float pos) + { + if(!gametypevote || gametypevote_finished) + return FALSE; + + if ( !GameTypeVote_SetGametype(MapInfo_Type_FromString(mapvote_maps[pos])) ) + { + dprint("Selected gametype is not supported by any map"); + } + + localcmd("sv_vote_gametype_hook_all\n"); + localcmd("sv_vote_gametype_hook_", mapvote_maps[pos], "\n"); + + gametypevote_finished = TRUE; + + return TRUE; + } + + float GameTypeVote_AddVotable(string nextMode) + { + float j; + if ( nextMode == "" || MapInfo_Type_FromString(nextMode) == 0 ) + return FALSE; + for(j = 0; j < mapvote_count; ++j) + if(mapvote_maps[j] == nextMode) + return FALSE; + + mapvote_maps[mapvote_count] = strzone(nextMode); + mapvote_maps_suggested[mapvote_count] = FALSE; + + mapvote_maps_screenshot_dir[mapvote_count] = 0; + mapvote_maps_pakfile[mapvote_count] = strzone(""); + mapvote_maps_availability[mapvote_count] = GameTypeVote_AvailabilityStatus(nextMode); + + mapvote_count += 1; + + return TRUE; + + } + + float GameTypeVote_Start() + { + float j; + MapVote_ClearAllVotes(); + MapVote_UnzoneStrings(); + + mapvote_count = 0; + mapvote_timeout = time + autocvar_sv_vote_gametype_timeout; + mapvote_abstain = 0; + mapvote_detail = !autocvar_g_maplist_votable_nodetail; + + float n = tokenizebyseparator(autocvar_sv_vote_gametype_options, " "); + n = min(MAPVOTE_COUNT, n); + + float really_available, which_available; + really_available = 0; + which_available = -1; + for(j = 0; j < n; ++j) + { + if ( GameTypeVote_AddVotable(argv(j)) ) + if ( mapvote_maps_availability[j] == GTV_AVAILABLE ) + { + really_available++; + which_available = j; + } + } + + mapvote_count_real = mapvote_count; + + gametypevote = 1; + + if ( really_available == 0 ) + { + if ( mapvote_count > 0 ) + strunzone(mapvote_maps[0]); + mapvote_maps[0] = strzone(MapInfo_Type_ToString(MapInfo_CurrentGametype())); + //GameTypeVote_Finished(0); + MapVote_Finished(0); + return FALSE; + } + if ( really_available == 1 ) + { + //GameTypeVote_Finished(which_available); + MapVote_Finished(which_available); + return FALSE; + } + + mapvote_count_real = mapvote_count; + + mapvote_keeptwotime = time + autocvar_sv_vote_gametype_keeptwotime; + if(mapvote_count_real < 3 || mapvote_keeptwotime <= time) + mapvote_keeptwotime = 0; + + MapVote_Spawn(); + + return TRUE; + }