Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 31 additions & 30 deletions config/setup.cfg
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
complete exec .
complete copyprefab prefab obr

mapcomplete = [ setcomplete $arg1 1; complete $arg1 maps mpz ]; mapcomplete map
start = [ mode $arg2 $arg3; map $arg1 ]; mapcomplete start
mapcomplete = [ setcomplete $arg1 1; complete $arg1 maps mpz ]
mapcomplete map
mapcomplete start

demo = [ stopdemo; start $arg1 0 0 ]; complete demo demos dmo
edit = [ start $arg1 $modeidxediting (+ $mutsbitffa $mutsbitclassic $arg2) ]; mapcomplete edit
deathmatch = [ start $arg1 $modeidxdeathmatch (| 0 $arg2) ]; mapcomplete deathmatch; dm = [ deathmatch $arg1 $arg2 ]; mapcomplete dm
teamdm = [ start $arg1 $modeidxdeathmatch (| 0 $arg2) ]; mapcomplete teamdm; tdm = [ teamdm $arg1 $arg2 ]; mapcomplete tdm
gladiator = [ start $arg1 $modeidxdeathmatch (| $mutsbitgsp1 $arg2) ]; mapcomplete gladiator
ffa = [ start $arg1 $modeidxdeathmatch (| $mutsbitffa $arg2) ]; mapcomplete ffa; fdm = [ ffa $arg1 $arg2 ]; mapcomplete fdm
multidm = [ start $arg1 $modeidxdeathmatch (| $mutsbitmulti $arg2) ]; mapcomplete multidm; mdm = [ multidm $arg1 $arg2 ]; mapcomplete mdm
coop = [ start $arg1 $modeidxdeathmatch (| $mutsbitcoop $arg2) ]; mapcomplete coop; cdm = [ coop $arg1 $arg2 ]; mapcomplete cdm
capture = [ start $arg1 $modeidxcapture (| 0 $arg2) ]; mapcomplete capture; ctf = [ capture $arg1 $arg2 ]; mapcomplete ctf
defend = [ start $arg1 $modeidxdefend (| 0 $arg2) ]; mapcomplete defend; dnc = [ defend $arg1 $arg2 ]; mapcomplete dnc; dac = [defend $arg1 $arg2 ] ; mapcomplete dac
bomber = [ start $arg1 $modeidxbomber (| 0 $arg2) ]; mapcomplete bomber; bb = [ bomber $arg1 $arg2 ]; mapcomplete bbr
race = [ start $arg1 $modeidxrace (| 0 $arg2) ]; mapcomplete race
instagib = [ start $arg1 $modeidxdeathmatch (| $mutsbitinstagib $arg2) ]; mapcomplete instagib; insta = [ instagib $arg1 $arg2 ]; mapcomplete insta
medieval = [ start $arg1 $modeidxdeathmatch (| $mutsbitmedieval $arg2) ]; mapcomplete medieval
kaboom = [ start $arg1 $modeidxdeathmatch (| $mutsbitkaboom $arg2) ]; mapcomplete kaboom
duel = [ start $arg1 $modeidxdeathmatch (+ $mutsbitduel $mutsbitffa $mutsbitbasic $mutsbithard $arg2) ]; mapcomplete duel
survivor = [ start $arg1 $modeidxdeathmatch (| $mutsbitsurvivor $arg2) ]; mapcomplete survivor; lms = [ survivor $arg1 $arg2 ]; mapcomplete lms
classic = [ start $arg1 $modeidxdeathmatch (| $mutsbitclassic $arg2) ]; mapcomplete classic
quickcapture = [ start $arg1 $modeidxcapture (| $mutsbitgsp1 $arg2) ]; mapcomplete quickcapture
defendcapture = [ start $arg1 $modeidxcapture (| $mutsbitgsp2 $arg2) ]; mapcomplete defendcapture
protectcapture = [ start $arg1 $modeidxcapture (| $mutsbitgsp3 $arg2) ]; mapcomplete protectcapture
quickdefend = [ start $arg1 $modeidxdefend (| $mutsbitgsp1 $arg2) ]; mapcomplete quickdefend
kingdefend = [ start $arg1 $modeidxdefend (| $mutsbitgsp2 $arg2) ]; mapcomplete kingdefend; koth = [ kingdefend $arg1 $arg2 ]; mapcomplete koth
holdbomber = [ start $arg1 $modeidxbomber (| $mutsbitgsp1 $arg2) ]; mapcomplete holdbomber
basketbomber = [ start $arg1 $modeidxbomber (| $mutsbitgsp2 $arg2) ]; mapcomplete basketbomber
attackbomber = [ start $arg1 $modeidxbomber (| $mutsbitgsp3 $arg2) ]; mapcomplete attackbomber
trial = [ start $arg1 $modeidxrace (+ $mutsbitgsp1 $mutsbitffa $arg2) ]; mapcomplete trial
endurancerace = [ start $arg1 $modeidxrace (| $mutsbitgsp2 $arg2) ]; mapcomplete endurancerace
gauntletrace = [ start $arg1 $modeidxrace (| $mutsbitgsp3 $arg2) ]; mapcomplete gauntletrace
edit = [ start $arg1 $modeidxediting $mutsbitffa $mutsbitclassic $arg2 ]; mapcomplete edit
deathmatch = [ start $arg1 $modeidxdeathmatch $arg2 ]; mapcomplete deathmatch; dm = [ deathmatch $arg1 $arg2 ]; mapcomplete dm
teamdm = [ start $arg1 $modeidxdeathmatch $arg2 ]; mapcomplete teamdm; tdm = [ teamdm $arg1 $arg2 ]; mapcomplete tdm
gladiator = [ start $arg1 $modeidxdeathmatch $mutsbitgsp1 $arg2 ]; mapcomplete gladiator
ffa = [ start $arg1 $modeidxdeathmatch $mutsbitffa $arg2 ]; mapcomplete ffa; fdm = [ ffa $arg1 $arg2 ]; mapcomplete fdm
multidm = [ start $arg1 $modeidxdeathmatch $mutsbitmulti $arg2 ]; mapcomplete multidm; mdm = [ multidm $arg1 $arg2 ]; mapcomplete mdm
coop = [ start $arg1 $modeidxdeathmatch $mutsbitcoop $arg2 ]; mapcomplete coop; cdm = [ coop $arg1 $arg2 ]; mapcomplete cdm
capture = [ start $arg1 $modeidxcapture $arg2 ]; mapcomplete capture; ctf = [ capture $arg1 $arg2 ]; mapcomplete ctf
defend = [ start $arg1 $modeidxdefend $arg2 ]; mapcomplete defend; dnc = [ defend $arg1 $arg2 ]; mapcomplete dnc; dac = [defend $arg1 $arg2 ] ; mapcomplete dac
bomber = [ start $arg1 $modeidxbomber $arg2 ]; mapcomplete bomber; bb = [ bomber $arg1 $arg2 ]; mapcomplete bbr
race = [ start $arg1 $modeidxrace $arg2 ]; mapcomplete race
instagib = [ start $arg1 $modeidxdeathmatch $mutsbitinstagib $arg2 ]; mapcomplete instagib; insta = [ instagib $arg1 $arg2 ]; mapcomplete insta
medieval = [ start $arg1 $modeidxdeathmatch $mutsbitmedieval $arg2 ]; mapcomplete medieval
kaboom = [ start $arg1 $modeidxdeathmatch $mutsbitkaboom $arg2 ]; mapcomplete kaboom
duel = [ start $arg1 $modeidxdeathmatch $mutsbitduel $mutsbitffa $mutsbitbasic $mutsbithard $arg2 ]; mapcomplete duel
survivor = [ start $arg1 $modeidxdeathmatch $mutsbitsurvivor $arg2 ]; mapcomplete survivor; lms = [ survivor $arg1 $arg2 ]; mapcomplete lms
classic = [ start $arg1 $modeidxdeathmatch $mutsbitclassic $arg2 ]; mapcomplete classic
quickcapture = [ start $arg1 $modeidxcapture $mutsbitgsp1 $arg2 ]; mapcomplete quickcapture
defendcapture = [ start $arg1 $modeidxcapture $mutsbitgsp2 $arg2 ]; mapcomplete defendcapture
protectcapture = [ start $arg1 $modeidxcapture $mutsbitgsp3 $arg2 ]; mapcomplete protectcapture
quickdefend = [ start $arg1 $modeidxdefend $mutsbitgsp1 $arg2 ]; mapcomplete quickdefend
kingdefend = [ start $arg1 $modeidxdefend $mutsbitgsp2 $arg2 ]; mapcomplete kingdefend; koth = [ kingdefend $arg1 $arg2 ]; mapcomplete koth
holdbomber = [ start $arg1 $modeidxbomber $mutsbitgsp1 $arg2 ]; mapcomplete holdbomber
basketbomber = [ start $arg1 $modeidxbomber $mutsbitgsp2 $arg2 ]; mapcomplete basketbomber
attackbomber = [ start $arg1 $modeidxbomber $mutsbitgsp3 $arg2 ]; mapcomplete attackbomber
trial = [ start $arg1 $modeidxrace $mutsbitgsp1 $mutsbitffa $arg2 ]; mapcomplete trial
endurancerace = [ start $arg1 $modeidxrace $mutsbitgsp2 $arg2 ]; mapcomplete endurancerace
gauntletrace = [ start $arg1 $modeidxrace $mutsbitgsp3 $arg2 ]; mapcomplete gauntletrace

delta_game_0 = [ if (iszooming) [ setzoom $arg1 ] [ weapon -1 $arg1 ] ]
delta_spec_0 = [ followdelta $arg1 ]
Expand Down
2 changes: 1 addition & 1 deletion config/usage.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ setdesc "map" "requests a map change to a given map, with no change of mode or m
//modes
setdesc "gamemode" "returns the current game mode; 0 = demo, 1 = edit, 2 = dm, 3 = ctf, 4 = dac, 5 = bb, 6 = race"
setdesc "mode" "sets the mode and mutator values for the next map change request;^nmode sets the mode type,^nmuts sets the mutators according to a bitwise sum of mutator values,^nconveniently set using $modeidx* vars and sums of $mutsbit* vars,^nexample: mode $modeidxdeathmatch (+ $mutsbitinstagib $mutsbitmedieval)" "mode muts"
setdesc "start" "requests a map change to a given map with a specific mode and mutators;^ndepending on privileges, this will force or vote for the map change,^nmode sets the mode type,^nmuts sets the mutators according to a bitwise sum of mutator values,^nconveniently set using $modeidx* vars and sums of $mutsbit* vars,^nexample: start bath $modeidxdeathmatch (+ $mutsbitinstagib $mutsbitmedieval)" "map mode muts"
setdesc "start" "requests a map change to a given map with a specific mode and mutators;^ndepending on privileges, this will force or vote for the map change,^nmode sets the mode, can be as name or number,^nmuts sets the mutators, can be either their names, or a bitwise sum of mutator values,^nconveniently set using $modeidx* vars and sums of $mutsbit* vars,^nexample: start castle dm ffa duel^nexample: start bath $modeidxdeathmatch (+ $mutsbitinstagib $mutsbitmedieval)" "map mode muts"
setdesc "edit" "starts editing on a random map. specifying a file name will create a new map file on a blank map canvas" "map"
setdesc "demo" "starts playback of a given demo" "demo"
setdesc "deathmatch" "requests a map change to deathmatch on a given map;^n[muts] optionally adds extra mutators according to bitwise mutator values, conveniently set using a sum of $mutsbit* vars,^nexample: deathmatch bath (+ $mutsbitinstagib $mutsbitmedieval)" "map [muts]"
Expand Down
136 changes: 136 additions & 0 deletions src/game/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,142 @@ namespace client
}
//ICOMMAND(0, sendmap, "", (), sendmap());

static void startcmd(char *map, char *mode_str, char *muts_str)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could likely use std::string instead of these char arrays.

Copy link
Copy Markdown
Contributor Author

@robalni robalni Aug 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could but that doesn't give me any benefit. The only change it would make is that I would have to type ".c_str()" more inside the function. (ok maybe I can skip a strcmp)

{
static const struct {const char *name; int val;} mode_names[] =
{
{"demo", G_DEMO},
{"edit", G_EDITMODE},
{"deathmatch", G_DEATHMATCH},
{"dm", G_DEATHMATCH},
{"capture", G_CAPTURE},
{"ctf", G_CAPTURE},
{"defend", G_DEFEND},
{"dac", G_DEFEND},
{"bomber", G_BOMBER},
{"bb", G_BOMBER},
{"race", G_RACE},
};
static const struct {const char *name; int val; int modes;} mut_names[] =
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be a struct array. Come on, we've got the power of C++ 11/14. Why not make it an std::set<std::string, std::pair<size_t, size_t>> or so? There is really no reason to use anonymous structs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a struct array? I like it when code is simple and easy to understand. Why should I put a wrapper around my char array (called std::string) that might allocate it on the heap and do some other undefined things when I don't need that? And why should I do similar thing with the whole array? It might even be slower. I never add things to these arrays either so they don't need to grow. They are just static data.

{
{"multi", 1 << G_M_MULTI, G_ALL},
{"ffa", 1 << G_M_FFA, G_ALL},
{"coop", 1 << G_M_COOP, G_ALL},
{"insta", 1 << G_M_INSTA, G_ALL},
{"instagib", 1 << G_M_INSTA, G_ALL},
{"medieval", 1 << G_M_MEDIEVAL, G_ALL},
{"kaboom", 1 << G_M_KABOOM, G_ALL},
{"duel", 1 << G_M_DUEL, G_ALL},
{"survivor", 1 << G_M_SURVIVOR, G_ALL},
{"classic", 1 << G_M_CLASSIC, G_ALL},
{"onslaught", 1 << G_M_ONSLAUGHT, G_ALL},
{"freestyle", 1 << G_M_FREESTYLE, G_ALL},
{"vampire", 1 << G_M_VAMPIRE, G_ALL},
{"resize", 1 << G_M_RESIZE, G_ALL},
{"hard", 1 << G_M_HARD, G_ALL},
{"basic", 1 << G_M_BASIC, G_ALL},
{"gladiator", 1 << G_M_GSP1, 1 << G_DEATHMATCH},
{"oldscool", 1 << G_M_GSP2, 1 << G_DEATHMATCH},
{"quick", 1 << G_M_GSP1, 1 << G_CAPTURE},
{"defend", 1 << G_M_GSP2, 1 << G_CAPTURE},
{"protect", 1 << G_M_GSP3, 1 << G_CAPTURE},
{"quick", 1 << G_M_GSP1, 1 << G_DEFEND},
{"king", 1 << G_M_GSP2, 1 << G_DEFEND},
{"hold", 1 << G_M_GSP1, 1 << G_BOMBER},
{"basket", 1 << G_M_GSP2, 1 << G_BOMBER},
{"attack", 1 << G_M_GSP3, 1 << G_BOMBER},
{"timed", 1 << G_M_GSP1, 1 << G_RACE},
{"endurance", 1 << G_M_GSP2, 1 << G_RACE},
{"gauntlet", 1 << G_M_GSP3, 1 << G_RACE},
};

int nextmode = G_DEATHMATCH;
int nextmuts = 0;

if(mode_str && isnumeric(*mode_str))
{
nextmode = atoi(mode_str);
}
else if(mode_str && *mode_str)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We prefer proper pointer comparisons. Please replace with e.g.,

Suggested change
else if(mode_str && *mode_str)
else if(mode_str != nullptr && *mode_str != '\0')

or something like that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually try to follow the existing style when I write code. What are we trying to do here? Are we trying to change the style of the code? Then what's the new style that we should follow?

{
bool found_one = false;
for(auto possible_mode : mode_names)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be const auto or even const auto&.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a proper map will also eliminate the need to implement a custom linear search. If you wanted, you could've even used std::find_if here if you used an std::vector.

{
if(strcmp(possible_mode.name, mode_str) == 0)
{
nextmode = possible_mode.val;
found_one = true;
break;
}
}
if(!found_one)
{
conoutft(CON_MESG, "\frgame mode \"%s\" not found", mode_str);
return;
}
}

if(muts_str && *muts_str)
{
std::vector<std::string> muts_vec;
char *begin = muts_str;
char *end = NULL;
// Split the muts string on ' ' and '-' into muts_vec.
while(*begin)
{
if(end)
{
if(*end == ' ' || *end == '-' || *end == '\0')
{
muts_vec.emplace_back(begin, end - begin);
begin = end;
end = NULL;
}
else end++;
}
else
{
if(*begin != ' ' && *begin != '-')
{
end = begin;
}
else begin++;
}
}

for(const std::string &mut : muts_vec)
{
if(isnumeric(*mut.c_str()))
{
nextmuts |= atoi(mut.c_str());
}
else
{
bool found_one = false;
for(auto possible_mut : mut_names)
{
if(strcmp(possible_mut.name, mut.c_str()) == 0 && (1 << nextmode) & possible_mut.modes)
{
nextmuts |= possible_mut.val;
found_one = true;
break;
}
}
if(!found_one)
{
conoutft(CON_MESG, "\frmutator \"%s\" not found or incompatible with mode \"%s\"", mut.c_str(), mode_str);
return;
}
}
}
}

game::nextmode = nextmode;
game::nextmuts = nextmuts;
changemap(map);
}
ICOMMAND(0, start, "sss", (char *map, char *mode, char *muts), startcmd(map, mode, muts));

void gotoplayer(const char *arg)
{
if(game::player1.state!=CS_SPECTATOR && game::player1.state!=CS_EDITING) return;
Expand Down