about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--datasrc/network.py21
-rw-r--r--src/game/client/components/menus.cpp22
-rw-r--r--src/game/client/components/voting.cpp61
-rw-r--r--src/game/client/components/voting.hpp39
-rw-r--r--src/game/client/gameclient.cpp4
-rw-r--r--src/game/client/gameclient.hpp1
-rw-r--r--src/game/server/gamecontext.cpp91
-rw-r--r--src/game/server/gamecontext.hpp9
-rw-r--r--src/game/server/player.hpp3
9 files changed, 246 insertions, 5 deletions
diff --git a/datasrc/network.py b/datasrc/network.py
index 0f1d3496..8d0bf246 100644
--- a/datasrc/network.py
+++ b/datasrc/network.py
@@ -224,7 +224,19 @@ Messages = [
 		NetIntRange("cid", 0, 'MAX_CLIENTS-1'),
 		NetIntRange("emoticon", 0, 'NUM_EMOTICONS-1'),
 	]),
-	
+
+	NetMessage("sv_vote_set", [
+		NetIntRange("timeout", 0, 60),
+		NetString("description"),
+		NetString("command"),
+	]),
+
+	NetMessage("sv_vote_status", [
+		NetIntRange("yes", 0, 'MAX_CLIENTS'),
+		NetIntRange("no", 0, 'MAX_CLIENTS'),
+		NetIntRange("pass", 0, 'MAX_CLIENTS'),
+		NetIntRange("total", 0, 'MAX_CLIENTS'),
+	]),
 	
 	### Client messages
 	NetMessage("cl_say", [
@@ -251,11 +263,14 @@ Messages = [
 		NetIntAny("color_body"),
 		NetIntAny("color_feet"),
 	]),
-	
+
 	NetMessage("cl_kill", []),
 
 	NetMessage("cl_emoticon", [
 		NetIntRange("emoticon", 0, 'NUM_EMOTICONS-1'),
 	]),
-	
+
+	NetMessage("cl_vote", [
+		NetIntRange("vote", -1, 1),
+	]),
 ]
diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp
index 36bf6378..6c28138d 100644
--- a/src/game/client/components/menus.cpp
+++ b/src/game/client/components/menus.cpp
@@ -23,6 +23,7 @@ extern "C" {
 #include <game/generated/gc_data.hpp>
 #include <game/client/components/binds.hpp>
 #include <game/client/components/motd.hpp>
+#include <game/client/components/voting.hpp>
 #include <game/client/gameclient.hpp>
 #include <game/client/animstate.hpp>
 #include <game/client/gc_render.hpp>
@@ -620,8 +621,8 @@ void MENUS::render_news(RECT main_view)
 
 void MENUS::render_game(RECT main_view)
 {
-	RECT button;
-	ui_hsplit_t(&main_view, 45.0f, &main_view, 0);
+	RECT button, votearea;
+	ui_hsplit_t(&main_view, 45.0f, &main_view, &votearea);
 	ui_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f);
 
 	ui_hsplit_t(&main_view, 10.0f, 0, &main_view);
@@ -688,6 +689,23 @@ void MENUS::render_game(RECT main_view)
 			}
 		}
 	}
+	
+	ui_hsplit_t(&votearea, 10.0f, 0, &votearea);
+	ui_hsplit_t(&votearea, 25.0f+10.0f*2, &votearea, 0);
+
+	ui_draw_rect(&votearea, color_tabbar_active, CORNER_ALL, 10.0f);
+
+	ui_vmargin(&votearea, 10.0f, &votearea);
+	ui_hmargin(&votearea, 10.0f, &votearea);
+	if(gameclient.voting->is_voting())
+	{
+		
+	}
+	else
+	{
+		ui_do_label(&votearea, "No vote in progress", 18.0f, -1);
+	}
+	
 }
 
 void MENUS::render_serverinfo(RECT main_view)
diff --git a/src/game/client/components/voting.cpp b/src/game/client/components/voting.cpp
new file mode 100644
index 00000000..b81cfb97
--- /dev/null
+++ b/src/game/client/components/voting.cpp
@@ -0,0 +1,61 @@
+#include <engine/e_client_interface.h>
+#include <game/generated/g_protocol.hpp>
+#include "voting.hpp"
+
+void VOTING::con_callvote(void *result, void *user_data)
+{
+}
+
+void VOTING::con_vote(void *result, void *user_data)
+{
+}
+	
+VOTING::VOTING()
+{
+	on_reset();
+}
+
+void VOTING::on_reset()
+{
+	closetime = 0;
+	description[0] = 0;
+	command[0] = 0;
+	yes = no = pass = total = 0;
+	voted = 0;
+}
+
+void VOTING::on_console_init()
+{
+	MACRO_REGISTER_COMMAND("callvote", "r", con_callvote, this);
+	MACRO_REGISTER_COMMAND("vote", "r", con_vote, this);
+}
+
+void VOTING::on_message(int msgtype, void *rawmsg)
+{
+	if(msgtype == NETMSGTYPE_SV_VOTE_SET)
+	{
+		NETMSG_SV_VOTE_SET *msg = (NETMSG_SV_VOTE_SET *)rawmsg;
+		if(msg->timeout)
+		{
+			on_reset();
+			str_copy(description, msg->description, sizeof(description));
+			str_copy(command, msg->command, sizeof(description));
+			closetime = time_get() + time_freq() * msg->timeout;
+		}
+		else
+			on_reset();
+	}
+	else if(msgtype == NETMSGTYPE_SV_VOTE_STATUS)
+	{
+		NETMSG_SV_VOTE_STATUS *msg = (NETMSG_SV_VOTE_STATUS *)rawmsg;
+		yes = msg->yes;
+		no = msg->no;
+		pass = msg->pass;
+		total = msg->total;
+	}	
+}
+
+void VOTING::on_render()
+{
+}
+
diff --git a/src/game/client/components/voting.hpp b/src/game/client/components/voting.hpp
new file mode 100644
index 00000000..6f518d10
--- /dev/null
+++ b/src/game/client/components/voting.hpp
@@ -0,0 +1,39 @@
+#include <game/client/component.hpp>
+
+class VOTING : public COMPONENT
+{
+	/*
+	void render_goals(float x, float y, float w);
+	void render_spectators(float x, float y, float w);
+	void render_scoreboard(float x, float y, float w, int team, const char *title);
+
+	static void con_key_scoreboard(void *result, void *user_data);
+	
+	bool active;
+	*/
+
+	static void con_callvote(void *result, void *user_data);
+	static void con_vote(void *result, void *user_data);
+	
+	int64 closetime;
+	char description[512];
+	char command[512];
+	int voted;
+	
+public:
+	VOTING();
+	virtual void on_reset();
+	virtual void on_console_init();
+	virtual void on_message(int msgtype, void *rawmsg);
+	virtual void on_render();
+	
+	void vote(int v); // -1 = no, 1 = yes
+	
+	bool is_voting() { return closetime != 0; }
+	int taken_choice() const { return voted; }
+	const char *vote_description() const { return description; }
+	const char *vote_command() const { return command; }
+	
+	int yes, no, pass, total;
+};
+
diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp
index 5ae98ced..e1634706 100644
--- a/src/game/client/gameclient.cpp
+++ b/src/game/client/gameclient.cpp
@@ -32,6 +32,7 @@
 #include "components/scoreboard.hpp"
 #include "components/skins.hpp"
 #include "components/sounds.hpp"
+#include "components/voting.hpp"
 
 GAMECLIENT gameclient;
 
@@ -55,6 +56,7 @@ static SCOREBOARD scoreboard;
 static SOUNDS sounds;
 static EMOTICON emoticon;
 static DAMAGEIND damageind;
+static VOTING voting;
 
 static PLAYERS players;
 static NAMEPLATES nameplates;
@@ -105,6 +107,7 @@ void GAMECLIENT::on_console_init()
 	motd = &::motd;
 	damageind = &::damageind;
 	mapimages = &::mapimages;
+	voting = &::voting;
 	
 	// make a list of all the systems, make sure to add them in the corrent render order
 	all.add(skins);
@@ -115,6 +118,7 @@ void GAMECLIENT::on_console_init()
 	all.add(controls);
 	all.add(camera);
 	all.add(sounds);
+	all.add(voting);
 	all.add(particles); // doesn't render anything, just updates all the particles
 	
 	all.add(&maplayers_background); // first to render
diff --git a/src/game/client/gameclient.hpp b/src/game/client/gameclient.hpp
index 4b397e86..c1e60c2c 100644
--- a/src/game/client/gameclient.hpp
+++ b/src/game/client/gameclient.hpp
@@ -137,6 +137,7 @@ public:
 	class SOUNDS *sounds;
 	class MOTD *motd;
 	class MAPIMAGES *mapimages;
+	class VOTING *voting;
 };
 
 extern GAMECLIENT gameclient;
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index 987ce64e..f896a140 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -8,6 +8,8 @@ GAMECONTEXT::GAMECONTEXT()
 {
 	for(int i = 0; i < MAX_CLIENTS; i++)
 		players[i] = 0;
+		
+	vote_closetime = 0;
 }
 
 GAMECONTEXT::~GAMECONTEXT()
@@ -211,6 +213,69 @@ void GAMECONTEXT::send_broadcast(const char *text, int cid)
 
 
 
+// 
+void GAMECONTEXT::start_vote(const char *desc, const char *command)
+{
+	// check if a vote is already running
+	if(vote_closetime)
+		return;
+
+	// reset votes
+	for(int i = 0; i < MAX_CLIENTS; i++)
+	{
+		if(players[i])
+			players[i]->vote = 0;
+	}
+	
+	// start vote
+	vote_closetime = time_get() + time_freq()*10;
+	str_copy(vote_description, desc, sizeof(vote_description));
+	str_copy(vote_command, command, sizeof(vote_description));
+	send_vote_set(-1);
+	send_vote_status(-1);
+}
+
+void GAMECONTEXT::send_vote_set(int cid)
+{
+	NETMSG_SV_VOTE_SET msg;
+	if(vote_closetime)
+	{
+		msg.timeout = (vote_closetime-time_get())/time_freq();
+		msg.description = vote_description;
+		msg.command = vote_command;
+	}
+	else
+	{
+		msg.timeout = 0;
+		msg.description = "";
+		msg.command = "";
+	}
+	msg.pack(MSGFLAG_VITAL);
+	server_send_msg(cid);
+}
+
+void GAMECONTEXT::send_vote_status(int cid)
+{
+	NETMSG_SV_VOTE_STATUS msg = {0};
+	for(int i = 0; i < MAX_CLIENTS; i++)
+	{
+		if(players[i])
+		{
+			msg.total++;
+			if(players[i]->vote > 0)
+				msg.yes++;
+			else if(players[i]->vote > 0)
+				msg.no++;
+			else
+				msg.pass++;
+		}
+	}	
+
+	msg.pack(MSGFLAG_VITAL);
+	server_send_msg(cid);
+	
+}
+
 void GAMECONTEXT::tick()
 {
 	world.core.tuning = tuning;
@@ -224,6 +289,32 @@ void GAMECONTEXT::tick()
 		if(players[i])
 			players[i]->tick();
 	}
+	
+	// update voting
+	if(vote_closetime)
+	{
+		// count votes
+		int total = 0, yes = 0, no = 0;
+		for(int i = 0; i < MAX_CLIENTS; i++)
+		{
+			if(players[i])
+			{
+				total++;
+				if(players[i]->vote > 0)
+					yes++;
+				else if(players[i]->vote > 0)
+					no++;
+			}
+		}
+		
+		if(yes > (total+1)/2)
+		{
+			console_execute_line(vote_command);
+			vote_closetime = 0;
+		}
+		else if(time_get() > vote_closetime || no > (total+1)/2)
+			vote_closetime = 0;
+	}
 }
 
 void GAMECONTEXT::snap(int client_id)
diff --git a/src/game/server/gamecontext.hpp b/src/game/server/gamecontext.hpp
index dd10ec4d..83ada09f 100644
--- a/src/game/server/gamecontext.hpp
+++ b/src/game/server/gamecontext.hpp
@@ -43,6 +43,14 @@ public:
 
 	void tick();
 	void snap(int client_id);
+	
+	// voting
+	void start_vote(const char *desc, const char *command);
+	void send_vote_set(int cid);
+	void send_vote_status(int cid);
+	int64 vote_closetime;
+	char vote_description[512];
+	char vote_command[512];
 
 	// helper functions
 	void create_damageind(vec2 p, float angle_mod, int amount);
@@ -68,6 +76,7 @@ public:
 	void send_weapon_pickup(int cid, int weapon);
 	void send_broadcast(const char *text, int cid);
 	void send_info(int who, int to_who);
+
 };
 
 extern GAMECONTEXT game;
diff --git a/src/game/server/player.hpp b/src/game/server/player.hpp
index c92265a8..f483ecf9 100644
--- a/src/game/server/player.hpp
+++ b/src/game/server/player.hpp
@@ -26,6 +26,9 @@ public:
 	int team;
 	int score;
 	bool force_balanced;
+	
+	//
+	int vote;
 
 	//
 	int64 last_chat;