Skip to content

Commit

Permalink
FTE/SERVER: Map Voting functionality; Map rotation modes for dedicate…
Browse files Browse the repository at this point in the history
…d servers
  • Loading branch information
MotoLegacy committed Dec 27, 2024
1 parent be22fef commit c780582
Show file tree
Hide file tree
Showing 9 changed files with 423 additions and 17 deletions.
3 changes: 3 additions & 0 deletions progs/ssqc.src
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ defs/standard.qc
#endif
shared_defs.qc
defs/custom.qc
map_rotation.qc
utilities/sound_helper.qc
weapon_stats.qc
utilities/math.qc
Expand All @@ -28,6 +29,8 @@ hash_table.qc
dummies.qc
rounds.qc
main.qc
plugins/plugin_mapvote.qc
plugins/plugin_core.qc
utilities/weapon_utilities.qc
utilities/game_restart.qc
utilities/command_parser.qc
Expand Down
10 changes: 9 additions & 1 deletion source/client/chat.qc
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ string Chat_GetHexCodeForPlayer(float player_id)
case 2: return "^x07E";
case 3: return "^xCA0";
case 4: return "^x5D0";
case 255: return "^xF76";
}
return "^xFFF";
}
Expand All @@ -112,7 +113,14 @@ void Chat_Register(int sender, int player_id, string message)
// Append name+color to the message
string player_hex = Chat_GetHexCodeForPlayer(player_id);
string player_name = getplayerkeyvalue(sender, "name");
message = strcat(player_hex, player_name, "^xCCC: ", message);

// Not a server message.
if (player_id != 255) {
message = strcat(player_hex, player_name, "^xCCC: ", message);
} else {
message = strcat(player_hex, message);
}


if (g_chatlines < (CHAT_LINES - 1)) {
g_chatbuffer[g_chatlines + 1] = message;
Expand Down
16 changes: 14 additions & 2 deletions source/server/clientfuncs.qc
Original file line number Diff line number Diff line change
Expand Up @@ -513,14 +513,26 @@ void (float achievement_id, optional entity who) GiveAchievement =

#ifdef FTE

void CSQC_SendChatMessage(float player_id, string message) {
void CSQC_SendChatMessage(float player_id, string message) =
{
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_CHATMESSAGE);
WriteByte(MSG_MULTICAST, num_for_edict(self) - 1);
WriteByte(MSG_MULTICAST, player_id);
WriteString(MSG_MULTICAST, message);
multicast('0 0 0', MULTICAST_ALL);
}
};

void CSQC_SendChatMessageToPlayer(float player_id, string message, entity who) =
{
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_CHATMESSAGE);
WriteByte(MSG_MULTICAST, num_for_edict(self) - 1);
WriteByte(MSG_MULTICAST, player_id);
WriteString(MSG_MULTICAST, message);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
};

/*
=================
Expand Down
7 changes: 1 addition & 6 deletions source/server/damage.qc
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ void(entity client) LastStand_Begin;
void() Barrel_Hit;
void() teddy_react;

void() EndGame_Restart =
{
localcmd("restart\n");
}

// Fade to black function, creates another think for restart
void() EndGame_FadePrompt =
{
Expand All @@ -56,7 +51,7 @@ void() EndGame_FadePrompt =

#ifdef FTE

self.think = EndGame_Restart;
self.think = MapRotation_Decide;

#else

Expand Down
12 changes: 5 additions & 7 deletions source/server/main.qc
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,6 @@ void() precaches =
precache_model ("models/weapons/grenade/g_grenade.mdl");
precache_extra (W_BIATCH);

// perk machine defaults
//precache_model (PERK_QUICKREVIVE_DEFAULT_MODEL);
//precache_model (PERK_JUGGERNOG_DEFAULT_MODEL);
//precache_model (PERK_SPEEDCOLA_DEFAULT_MODEL);
//precache_model (PERK_)

#ifdef FTE

// FTE only has co-op, so don't precache morphine elsewhere.
Expand Down Expand Up @@ -371,13 +365,17 @@ void() worldspawn =
clientstat(STAT_INSTA, EV_FLOAT, insta_icon);
clientstat(STAT_X2, EV_FLOAT, x2_icon);
clientstat(STAT_SPECTATING, EV_FLOAT, is_spectator);
clientstat(STAT_PLAYERNUM, EV_FLOAT, playernum); // literally useless but will be kept in case
clientstat(STAT_PLAYERNUM, EV_FLOAT, playernum);
clientstat(STAT_PLAYERSTANCE, EV_FLOAT, stance);
clientstat(STAT_FACINGENEMY, EV_FLOAT, facingenemy);
clientstat(STAT_VIEWZOOM, EV_FLOAT, viewzoom);
clientstat(STAT_MAXHEALTH, EV_FLOAT, max_health);
clientstat(STAT_PERKS, EV_FLOAT, perks);

autocvar(sv_enablechatplugins, 0);
autocvar(sv_maprotationbasename, "map_rotation");
autocvar(sv_maprotationmode, 0);

#endif // FTE

mappath = strcat("maps/", mapname);
Expand Down
140 changes: 140 additions & 0 deletions source/server/map_rotation.qc
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
server/map_rotation.qc

Map Rotation Logic for Dedicated Servers.

Copyright (C) 2021-2024 NZ:P Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to:

Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA

*/
#ifdef FTE

#define MAPROTATION_MODE_DONTROTATE 0
#define MAPROTATION_MODE_FIXEDROTATION 1
#define MAPROTATION_MODE_RANDOM 2

//
// MapRotation_RestartMap()
// Loads the current map once again.
//
void() MapRotation_RestartMap =
{
localcmd(sprintf("changelevel %s\n", mapname));
};

//
// MapRotation_GetRandomMap()
// Loads a random map in the server's
// map directory.
//
void() MapRotation_GetRandomMap =
{
searchhandle maps;
string map_path;
string map_name;
float map_count;
float map_index;

// Grab a random map file
maps = search_begin("maps/*.bsp", 0, 0);
map_count = search_getsize(maps);
map_index = rint(random() * map_count);

map_path = search_getfilename(maps, map_index);
map_name = substring(map_path, 5, strlen(map_path)); // maps/
map_name = substring(map_name, 0, strlen(map_name) - 4); // .bsp

search_end(maps);

localcmd(sprintf("changelevel %s\n", map_name));
};

//
// MapRotation_SelectNextMap()
// Loads the next map in the map rotation
// text file.
//
void() MapRotation_SelectNextMap =
{
float rotation_file = fopen(sprintf("%s.txt", cvar_string("sv_maprotationbasename")), FILE_READ);

if (rotation_file == -1) {
MapRotation_GetRandomMap();
}

float load_loop = true;
string map_to_load = "";
string first_map = fgets(rotation_file);
string current_map = first_map;

while(load_loop) {
// End of file, use the first map in the file.
if not (current_map) {
load_loop = false;
break;
}

// Current line is for our map, so load the next
// and then break out.
if (mapname == current_map) {
map_to_load = fgets(rotation_file);
load_loop = false;
break;
}

current_map = fgets(rotation_file);
}

// If map_to_load is blank, use the first map in the rotation list.
if (map_to_load == "") {
map_to_load = first_map;
}

fclose(rotation_file);

localcmd(sprintf("changelevel %s\n", strtrim(map_to_load)));
};

//
// MapRotation_Decide()
// Called at game's end, picks an appropriate
// map rotation mode.
//
void() MapRotation_Decide =
{
float map_rotation_mode = cvar("sv_maprotationmode");

switch(map_rotation_mode) {
case MAPROTATION_MODE_DONTROTATE:
MapRotation_RestartMap();
break;
case MAPROTATION_MODE_FIXEDROTATION:
MapRotation_SelectNextMap();
break;
case MAPROTATION_MODE_RANDOM:
MapRotation_GetRandomMap();
break;
default:
MapRotation_RestartMap();
break;
}
};

#endif // FTE
47 changes: 47 additions & 0 deletions source/server/plugins/plugin_core.qc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
server/plugins/plugin_core.qc

In-game chat plugin core.

Copyright (C) 2021-2024 NZ:P Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to:

Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA

*/
#ifdef FTE

//
// Plugin command table
// command_name : Command string entered into developer console.
// command_function : QuakeC function called when command is executed.
// Returns 0 for success, 1 for failure.
//
var struct {
string command_name;
float(string params) command_function;
float requires_arguments;
string command_description;
} plugin_commands[] = {
{"mapvote", ChatPlugin_MapVote, true, "Usage: mapvote <bsp_name>\nAttempts to initiate a Map Vote. Fails if one is already in progress.\n"},
{"mapvote_y", ChatPlugin_MapVoteYes, false, "Usage: mapvote_y\n"},
{"mapvote_n", ChatPlugin_MapVoteNo, false, "Usage: mapvote_n\n"},

};

#endif // FTE
Loading

0 comments on commit c780582

Please sign in to comment.