Extra enemies: per player or static multiplier

This commit is contained in:
MrBruh committed 2026-10-06 00:08:26 +13:00
1 parent 16ad4cc900
commit f0804aa587
7 files changed
+203 -65

No files matched your search

@@ -20,6 +20,8 @@
<child widget="main_menu/multiplayer_type_select/server_settings/op_listing" x="54" y="157"/>
<child widget="main_menu/multiplayer_type_select/server_settings/op_friendly_fire" x="54" y="185"/>
<child widget="main_menu/multiplayer_type_select/server_settings/op_extra_enemies" x="54" y="213"/>
<child widget="main_menu/multiplayer_type_select/server_settings/op_enemies_per_player" x="54" y="241"/>
<child widget="main_menu/multiplayer_type_select/server_settings/op_enemies_multiplier" x="54" y="241"/>
<child widget="main_menu/multiplayer_type_select/server_settings/op_game_type" x="54" y="185"/>
<child widget="main_menu/multiplayer_type_select/server_settings/op_player_options" x="54" y="213"/>
<child widget="main_menu/multiplayer_type_select/server_settings/op_item_options" x="54" y="241"/>
@@ -93,7 +95,29 @@
</widget>
<widget name="main_menu/multiplayer_type_select/server_settings/extra_enemies_label" type="text" controller="1" width="300" height="22" string_list="main_menu/multiplayer_type_select/server_settings/labels" string_index="11" font="ui\large_ui" color="#FF2896FF" text_x="13" text_y="4">
</widget>
<widget name="main_menu/multiplayer_type_select/server_settings/extra_enemies_spinner" type="spinner" top="2" width="206" height="20" flags="pass_unhandled_to_focused_child left_right_tabs_items" strings="0%|25%|50%|100%|150%|200%" setting="network.coop_enemies" values="0|25|50|100|150|200" font="ui\large_ui" color="#FF2896FF" align="center" text_y="4" header_bitmap="bitmaps/arrow_sm_left" footer_bitmap="bitmaps/arrow_sm_right" header_bounds="7 -13 19 -7" footer_bounds="7 208 19 214">
<widget name="main_menu/multiplayer_type_select/server_settings/extra_enemies_spinner" type="spinner" top="2" width="206" height="20" flags="pass_unhandled_to_focused_child left_right_tabs_items" strings="NONE|PER PLAYER|STATIC MULTIPLIER" setting="network.coop_enemies_mode" values="none|per_player|multiplier" font="ui\large_ui" color="#FF2896FF" align="center" text_y="4" header_bitmap="bitmaps/arrow_sm_left" footer_bitmap="bitmaps/arrow_sm_right" header_bounds="7 -13 19 -7" footer_bounds="7 208 19 214">
<on event="created" run="port setting load"/>
<on event="deleted" run="port setting save"/>
<on event="left_mouse" run="mouse spinner 1wide click"/>
</widget>
<widget name="main_menu/multiplayer_type_select/server_settings/op_enemies_per_player" width="512" height="28" flags="pass_unhandled_to_focused_child" bitmap="bitmaps/option_bkds" color="#FF2896FF">
<child widget="main_menu/multiplayer_type_select/server_settings/enemies_per_player_label"/>
<child widget="main_menu/multiplayer_type_select/server_settings/enemies_per_player_spinner" x="286" y="1"/>
</widget>
<widget name="main_menu/multiplayer_type_select/server_settings/enemies_per_player_label" type="text" controller="1" width="300" height="22" string_list="main_menu/multiplayer_type_select/server_settings/labels" string_index="12" font="ui\large_ui" color="#FF2896FF" text_x="13" text_y="4">
</widget>
<widget name="main_menu/multiplayer_type_select/server_settings/enemies_per_player_spinner" type="spinner" top="2" width="206" height="20" flags="pass_unhandled_to_focused_child left_right_tabs_items" strings="25%|50%|100%|150%|200%" setting="network.coop_enemies" values="25|50|100|150|200" font="ui\large_ui" color="#FF2896FF" align="center" text_y="4" header_bitmap="bitmaps/arrow_sm_left" footer_bitmap="bitmaps/arrow_sm_right" header_bounds="7 -13 19 -7" footer_bounds="7 208 19 214">
<on event="created" run="port setting load"/>
<on event="deleted" run="port setting save"/>
<on event="left_mouse" run="mouse spinner 1wide click"/>
</widget>
<widget name="main_menu/multiplayer_type_select/server_settings/op_enemies_multiplier" width="512" height="28" flags="pass_unhandled_to_focused_child" bitmap="bitmaps/option_bkds" color="#FF2896FF">
<child widget="main_menu/multiplayer_type_select/server_settings/enemies_multiplier_label"/>
<child widget="main_menu/multiplayer_type_select/server_settings/enemies_multiplier_spinner" x="286" y="1"/>
</widget>
<widget name="main_menu/multiplayer_type_select/server_settings/enemies_multiplier_label" type="text" controller="1" width="300" height="22" string_list="main_menu/multiplayer_type_select/server_settings/labels" string_index="13" font="ui\large_ui" color="#FF2896FF" text_x="13" text_y="4">
</widget>
<widget name="main_menu/multiplayer_type_select/server_settings/enemies_multiplier_spinner" type="spinner" top="2" width="206" height="20" flags="pass_unhandled_to_focused_child left_right_tabs_items" strings="2X|4X|8X|16X|32X" setting="network.coop_enemies_multiplier" values="2|4|8|16|32" font="ui\large_ui" color="#FF2896FF" align="center" text_y="4" header_bitmap="bitmaps/arrow_sm_left" footer_bitmap="bitmaps/arrow_sm_right" header_bounds="7 -13 19 -7" footer_bounds="7 208 19 214">
<on event="created" run="port setting load"/>
<on event="deleted" run="port setting save"/>
<on event="left_mouse" run="mouse spinner 1wide click"/>
@@ -185,6 +209,8 @@
<string text="LISTING:"/>
<string text="FRIENDLY FIRE:"/>
<string text="EXTRA ENEMIES:"/>
<string text="PER PLAYER:"/>
<string text="MULTIPLIER:"/>
</strings>
<strings name="main_menu/multiplayer_type_select/server_settings/help_strings">
<string text=""/>
@@ -203,6 +229,10 @@
<string text="Players can be hurt by weapons or explosives\nfired by the other players."/>
<string text="Damage from the other players will only reduce\nshields. Health will be unaffected."/>
<string text="Players can be hurt by damage from explosives\nfired by the other players."/>
<string text="Enemy squads are as the campaign has them."/>
<string text="Enemy squads grow with the players: by the amount\nbelow for each player past the first."/>
<string text="Enemy squads are the amount below times as large,\nhowever many players there are."/>
<string text="For each player past the first, enemy squads get\nthis much more of themselves (100%: as many again)."/>
<string text="Each enemy squad is this many times as large."/>
</strings>
</menus>
+9 -8
View File
@@ -54,14 +54,15 @@ with ideas from VALORANT's netcode articles, keeping the 30 Hz tick:
threads' wake times along with it. The object, device and name syncs
bring the clients up to date.
The host's EXTRA ENEMIES (`coop_enemies.c`, `network.coop_enemies`)
give each squad of enemies a level places that percentage of itself more
for each player past the first, in rings about its starting locations
where the ground is open, and never past the actors a level needs for its
own (the actor pool, `halo_port_capacity.h`, holds 1024). Riders a
dropship has no seats for are kept, and placed beside its riders once
they get out. Only the host runs the AI, so the clients see them as the
host's other actors.
The host's EXTRA ENEMIES (`coop_enemies.c`, `network.coop_enemies_mode`)
give each squad of enemies a level places more of itself: PER PLAYER, a
percentage of itself for each player past the first; STATIC MULTIPLIER,
that many times itself for any number of players. They stand in rings
about its starting locations where the ground is open, and never take the
actors a level needs for its own (the actor pool, `halo_port_capacity.h`,
holds 1024). Riders a dropship has no seats for are kept, and placed
beside its riders once they get out. Only the host runs the AI, so the
clients see them as the host's other actors.
- **Host authoritative.** The host alone decides damage, deaths, spawns,
pickups, scores and the game's objects; clients do not decide them but
apply what the host sends.
+3 -1
View File
@@ -261,7 +261,9 @@ the setting for one start of the game. It has priority over the file.
| `network.public_lobby` | `true` | `HALO_NET_PUBLIC_LOBBY` | `true`: the server browser. Public games are listed, and Join Game > Server Browser shows them. `false`: no games are listed or shown. Refer to "Server browser". |
| `network.host_public` | `true` | `HALO_NET_HOST_PUBLIC` | `true`: a new game of Create Game > Internet starts as PUBLIC. `false`: it starts as PRIVATE. LISTING in Server Setup changes it for each game. Refer to "Server browser". |
| `network.coop_friendly_fire` | `"on"` | `HALO_NET_COOP_FRIENDLY_FIRE` | Whether the players of an online co-op game hurt each other: `"off"`, `"on"`, `"shields_only"` or `"explosives_only"`. FRIENDLY FIRE in co-op's Server Setup writes its choice here. Their AI allies they always can, as in the campaign. |
| `network.coop_enemies` | `50` | `HALO_NET_COOP_ENEMIES` | Online co-op's extra enemies, a percentage from `0` to `200`: for each player past the first, each squad of enemies that a level places gets this much of itself more (`100`: as many again, so four players meet four times the squad). The extra enemies stand around the squad's places, and those that a dropship has no seats for drop out of it after its passengers. EXTRA ENEMIES in co-op's Server Setup writes its choice here. |
| `network.coop_enemies_mode` | `"per_player"` | `HALO_NET_COOP_ENEMIES_MODE` | Online co-op's extra enemies: `"none"`; `"per_player"`, each squad of enemies that a level places grows by `network.coop_enemies` for each player past the first; or `"multiplier"`, each squad is `network.coop_enemies_multiplier` times as large, for any number of players. The extra enemies stand around the squad's places, and those that a dropship has no seats for drop out of it after its passengers. EXTRA ENEMIES in co-op's Server Setup writes its choice here. |
| `network.coop_enemies` | `50` | `HALO_NET_COOP_ENEMIES` | The extra enemies per player, a percentage from `25` to `200`: for each player past the first, each squad of enemies gets this much of itself more (`100`: as many again, so four players meet four times the squad). PER PLAYER in co-op's Server Setup writes its choice here. |
| `network.coop_enemies_multiplier` | `2` | `HALO_NET_COOP_ENEMIES_MULTIPLIER` | The static multiplier of the enemies, `2` to `32`: each squad of enemies is this many times as large. MULTIPLIER in co-op's Server Setup writes its choice here. |
| `network.coop_public` | `false` | `HALO_NET_COOP_PUBLIC` | `true`: an online co-op game (Create Game > Internet, a SINGLEPLAYER map) starts as PUBLIC. `false`: it starts as PRIVATE. LISTING in co-op's Server Setup writes its choice here. Refer to "Server browser". |
| `network.brokers_file` | `"brokers.txt"` | `HALO_NET_BROKERS_FILE` | The file of the public MQTT brokers that let the machines of an invite find each other, and that carry the listings of the server browser: next to `config.toml`, unless a full path. One `host:port` on each line, up to 4; `#` starts a comment. |
| `network.stun_servers` | Google and Cloudflare | `HALO_NET_STUN` | The public STUN servers (`host:port`, with commas between them) that give the internet address of a machine. |
+57 -16
View File
@@ -2,12 +2,14 @@
COOP_ENEMIES.C
Network co-op's extra enemies: Server Setup's EXTRA ENEMIES
(network.coop_enemies, a percentage). For each player past the first, each
squad of the players' enemies that a level places (encounters.c's
encounter_create) gets that much of its count more: at 100%, two players
meet twice the squad, four players four times it. The extra enemies stand
in rings about the squad's starting locations, on open ground, so they do
not start inside each other.
(network.coop_enemies_mode). PER PLAYER (network.coop_enemies, a
percentage): for each player past the first, each squad of the players'
enemies that a level places (encounters.c's encounter_create) gets that
much of its count more; at 100%, two players meet twice the squad, four
players four times it. STATIC MULTIPLIER (network.coop_enemies_multiplier):
each squad is that many times as large, for any number of players. The
extra enemies stand in rings about the squad's starting locations, on
open ground, so they do not start inside each other.
A squad a script loads into a dropship (vehicle_load_magic) can be larger
than the dropship's seats. The riders left without a seat are erased, and
@@ -39,9 +41,11 @@ Only the host runs the AI, so all of this is the host's.
#include "network_coop.h"
#include <math.h>
#include <string.h>
/* port_config.c's */
long config_integer(char const *name);
char const *config_string(char const *name);
/* ---------- constants */
@@ -50,8 +54,12 @@ enum
/* the actors a level keeps for its own placements, which the extra
enemies never take: as many as the Xbox's whole pool */
COOP_ENEMIES_LEVEL_ACTORS = 256,
/* EXTRA ENEMIES' greatest (Server Setup's choices: 0 to 200%) */
/* EXTRA ENEMIES' amounts, as Server Setup has them: 25 to 200% per
player, or 2 to 32 times (none is its NONE) */
COOP_ENEMIES_MINIMUM_PERCENT = 25,
COOP_ENEMIES_MAXIMUM_PERCENT = 200,
COOP_ENEMIES_MINIMUM_MULTIPLIER = 2,
COOP_ENEMIES_MAXIMUM_MULTIPLIER = 32,
/* the places tried for an extra enemy, a ring further out each */
SPREAD_ATTEMPTS = 8,
SPREAD_PLACES_PER_RING = 6,
@@ -71,6 +79,14 @@ looked along, and the ground looked for below it */
/* a kept rider's place beside a rider who got out, each a little apart */
#define RIDER_SPACING 0.5f
/* EXTRA ENEMIES' choices (network.coop_enemies_mode's values) */
enum
{
_coop_enemies_none,
_coop_enemies_per_player,
_coop_enemies_multiplier,
};
/* ---------- structures */
/* a vehicle a script loaded riders into: its seated ones, and whether they
@@ -99,8 +115,11 @@ struct coop_kept_rider
static struct
{
/* EXTRA ENEMIES, as the game began with it */
/* EXTRA ENEMIES, as the game began with it: its choice, and the amount
of PER PLAYER (a percentage) and of STATIC MULTIPLIER */
short mode;
short percent;
short multiplier;
struct coop_riding_vehicle vehicles[MAXIMUM_RIDING_VEHICLES];
short vehicle_count;
struct coop_kept_rider riders[MAXIMUM_KEPT_RIDERS];
@@ -115,6 +134,14 @@ static boolean coop_enemies_host(
return game_connection() == _game_connection_network_server && network_coop_active();
}
/* whether this game has extra enemies (it is a co-op host's, with some
chosen) */
static boolean coop_enemies_on(
void)
{
return coop_enemies.mode != _coop_enemies_none && coop_enemies_host();
}
/* the players in the game, every machine's: the network game's (a level
places its first enemies before the players' units are made, as it loads:
game_initialize_for_new_map) */
@@ -283,8 +310,17 @@ static void coop_enemies_rider_place(
void coop_enemies_new_game(
void)
{
char const *mode = config_string("network.coop_enemies_mode");
csmemset(&coop_enemies, 0, sizeof(coop_enemies));
coop_enemies.percent = (short)PIN(config_integer("network.coop_enemies"), 0, COOP_ENEMIES_MAXIMUM_PERCENT);
/* (an amount past Server Setup's, as it shows it: its nearest choice's
end) */
coop_enemies.percent = (short)PIN(config_integer("network.coop_enemies"), COOP_ENEMIES_MINIMUM_PERCENT,
COOP_ENEMIES_MAXIMUM_PERCENT);
coop_enemies.multiplier = (short)PIN(config_integer("network.coop_enemies_multiplier"),
COOP_ENEMIES_MINIMUM_MULTIPLIER, COOP_ENEMIES_MAXIMUM_MULTIPLIER);
coop_enemies.mode = !strcmp(mode, "per_player") ? _coop_enemies_per_player :
!strcmp(mode, "multiplier") ? _coop_enemies_multiplier : _coop_enemies_none;
}
void coop_enemies_reset(
@@ -302,15 +338,20 @@ short coop_enemies_extra_count(
long extra, room;
short players;
if (count <= 0 || coop_enemies.percent <= 0 || !coop_enemies_host())
if (count <= 0 || !coop_enemies_on())
return 0;
encounter = encounter_get(encounter_index);
if (!game_team_is_enemy(_game_team_player, encounter->team_index))
return 0;
players = coop_enemies_player_count();
if (players <= 1)
return 0;
extra = ((long)count * coop_enemies.percent * (players - 1) + 50) / 100;
if (coop_enemies.mode == _coop_enemies_multiplier)
extra = (long)count * (coop_enemies.multiplier - 1);
else
{
players = coop_enemies_player_count();
if (players <= 1)
return 0;
extra = ((long)count * coop_enemies.percent * (players - 1) + 50) / 100;
}
room = MAXIMUM_ACTORS - COOP_ENEMIES_LEVEL_ACTORS - actor_data->actual_count;
return (short)PIN(extra, 0, MAX(room, 0));
}
@@ -349,7 +390,7 @@ void coop_enemies_rider_seated(
struct coop_riding_vehicle *vehicle;
struct unit_datum *unit;
if (coop_enemies.percent <= 0 || !coop_enemies_host())
if (!coop_enemies_on())
return;
vehicle = coop_enemies_riding_vehicle(vehicle_index, TRUE);
unit = unit_get(unit_index);
@@ -391,7 +432,7 @@ boolean coop_enemies_rider_unseated(
struct coop_kept_rider *rider;
struct coop_riding_vehicle *vehicle;
if (coop_enemies.percent <= 0 || !coop_enemies_host() || coop_enemies.rider_count >= MAXIMUM_KEPT_RIDERS)
if (!coop_enemies_on() || coop_enemies.rider_count >= MAXIMUM_KEPT_RIDERS)
return FALSE;
unit = unit_get(unit_index);
vehicle = coop_enemies_riding_vehicle(vehicle_index, FALSE);
+38 -9
View File
@@ -2576,10 +2576,23 @@ static char const *const server_settings_gametype_rows[] =
/* the most players a co-op game hosted starts with (maximum_players') */
#define COOPERATIVE_DEFAULT_PLAYERS 16
/* Server Setup's help for co-op's FRIENDLY FIRE, by its choice, and its
EXTRA ENEMIES (its help_strings, tools/port_settings.py) */
/* Server Setup's help for co-op's FRIENDLY FIRE and EXTRA ENEMIES, by
their choices, and EXTRA ENEMIES' PER PLAYER and MULTIPLIER (its
help_strings, tools/port_settings.py) */
#define COOPERATIVE_FRIENDLY_FIRE_HELP 12
#define COOPERATIVE_EXTRA_ENEMIES_HELP 16
#define COOPERATIVE_ENEMIES_PER_PLAYER_HELP 19
#define COOPERATIVE_ENEMIES_MULTIPLIER_HELP 20
/* co-op's EXTRA ENEMIES' choices (port_settings.COOP_ENEMIES_MODES, in this
order): its amount's row is the choice's */
enum
{
_cooperative_enemies_none,
_cooperative_enemies_per_player,
_cooperative_enemies_multiplier,
NUMBER_OF_COOPERATIVE_ENEMIES_MODES
};
/* co-op's FRIENDLY FIRE's choices (network.coop_friendly_fire's values,
port_settings.COOP_FRIENDLY_FIRE_VALUES, in this order) */
@@ -2708,14 +2721,30 @@ static void server_settings_update(struct widget_instance *list)
if (help && list->focused_child == named(list, "op_friendly_fire", 0))
help->parameters.text_box.string_list_index = (short)(COOPERATIVE_FRIENDLY_FIRE_HELP + choice);
}
/* ... and its EXTRA ENEMIES (network.coop_enemies, which the host
reads as the game begins: coop_enemies.c) */
visible_set(named(list, "op_extra_enemies", 0), cooperative);
if (cooperative && list->parameters.list.extended_description &&
list->focused_child == named(list, "op_extra_enemies", 0))
/* ... and its EXTRA ENEMIES, with the row of the amount of the one
chosen below it (network.coop_enemies_mode and its amounts, which the
host reads as the game begins: coop_enemies.c) */
{
list->parameters.list.extended_description->parameters.text_box.string_list_index =
COOPERATIVE_EXTRA_ENEMIES_HELP;
struct widget_instance *help = list->parameters.list.extended_description;
short mode = _cooperative_enemies_none;
if ((spinner = named(list, "extra_enemies_spinner", 0)) != NULL)
{
mode = (short)PIN(spinner->parameters.list.selected_index, 0,
NUMBER_OF_COOPERATIVE_ENEMIES_MODES - 1);
}
visible_set(named(list, "op_extra_enemies", 0), cooperative);
visible_set(named(list, "op_enemies_per_player", 0), cooperative && mode == _cooperative_enemies_per_player);
visible_set(named(list, "op_enemies_multiplier", 0), cooperative && mode == _cooperative_enemies_multiplier);
if (cooperative && help)
{
if (list->focused_child == named(list, "op_extra_enemies", 0))
help->parameters.text_box.string_list_index = (short)(COOPERATIVE_EXTRA_ENEMIES_HELP + mode);
else if (list->focused_child == named(list, "op_enemies_per_player", 0))
help->parameters.text_box.string_list_index = COOPERATIVE_ENEMIES_PER_PLAYER_HELP;
else if (list->focused_child == named(list, "op_enemies_multiplier", 0))
help->parameters.text_box.string_list_index = COOPERATIVE_ENEMIES_MULTIPLIER_HELP;
}
}
}
/* LISTING (an internet game's): PUBLIC, listed in everyone's server
+16 -4
View File
@@ -266,11 +266,23 @@ static const struct config_setting config_settings[] =
"\"on\", \"shields_only\" or \"explosives_only\" (Server Setup's FRIENDLY\n"
"FIRE in co-op, which writes its choice here). Their AI allies they\n"
"always can, as in the campaign." },
{ "network.coop_enemies_mode", _config_string, "\"per_player\"", "HALO_NET_COOP_ENEMIES_MODE", _environment_value,
_platform_all,
"Online co-op's extra enemies: \"none\", \"per_player\" (each squad of\n"
"enemies grows by coop_enemies for each player past the first) or\n"
"\"multiplier\" (each is coop_enemies_multiplier times as large, for any\n"
"number of players). Server Setup's EXTRA ENEMIES in co-op writes its\n"
"choice here." },
{ "network.coop_enemies", _config_integer, "50", "HALO_NET_COOP_ENEMIES", _environment_value, _platform_all,
"Online co-op's extra enemies, a percentage: for each player past the\n"
"first, each squad of enemies a level places gets this much of itself\n"
"more (100: as many again; 0 to 200). Server Setup's EXTRA ENEMIES in\n"
"co-op writes its choice here." },
"Online co-op's extra enemies per player, a percentage: for each player\n"
"past the first, each squad of enemies a level places gets this much of\n"
"itself more (100: as many again; 25 to 200). Server Setup's PER PLAYER\n"
"in co-op writes its choice here." },
{ "network.coop_enemies_multiplier", _config_integer, "2", "HALO_NET_COOP_ENEMIES_MULTIPLIER", _environment_value,
_platform_all,
"Online co-op's static multiplier of its enemies: each squad of enemies\n"
"a level places is this many times as large (2 to 32). Server Setup's\n"
"MULTIPLIER in co-op writes its choice here." },
{ "network.brokers_file", _config_string, "\"brokers.txt\"",
"HALO_NET_BROKERS_FILE", _environment_value, _platform_all,
"The file of the public MQTT brokers through which the machines of an\n"
+49 -26
View File
@@ -681,29 +681,42 @@ def _server_settings() -> list:
['<on event="created" run="port setting load"/>', '<on event="deleted" run="port setting save"/>',
'<on event="left_mouse" run="mouse spinner 1wide click"/>'])
rows.append((f"{base}/op_friendly_fire", None, 4))
# ... and its EXTRA ENEMIES (port/linux/game/coop_enemies.c), below it;
# its choice kept in network.coop_enemies
extra += _widget(f"{base}/op_extra_enemies", [("width", 512), ("height", 28),
("flags", "pass_unhandled_to_focused_child"),
("bitmap", "bitmaps/option_bkds"), ("color", "#FF2896FF")],
[f'<child widget="{base}/extra_enemies_label"/>',
f'<child widget="{base}/extra_enemies_spinner" x="286" y="1"/>'])
extra += _widget(f"{base}/extra_enemies_label", [("type", "text"), ("controller", 1), ("width", 300),
("height", 22), ("string_list", f"{base}/labels"),
("string_index", 11), ("font", "ui\\large_ui"),
("color", "#FF2896FF"), ("text_x", 13), ("text_y", 4)], [])
extra += _widget(f"{base}/extra_enemies_spinner",
[("type", "spinner"), ("top", 2), ("width", 206), ("height", 20),
("flags", "pass_unhandled_to_focused_child left_right_tabs_items"),
("strings", "|".join(f"{value}%" for value in COOP_ENEMIES_VALUES)),
("setting", "network.coop_enemies"),
("values", "|".join(str(value) for value in COOP_ENEMIES_VALUES)), ("font", "ui\\large_ui"),
("color", "#FF2896FF"), ("align", "center"), ("text_y", 4),
("header_bitmap", "bitmaps/arrow_sm_left"), ("footer_bitmap", "bitmaps/arrow_sm_right"),
("header_bounds", "7 -13 19 -7"), ("footer_bounds", "7 208 19 214")],
['<on event="created" run="port setting load"/>', '<on event="deleted" run="port setting save"/>',
'<on event="left_mouse" run="mouse spinner 1wide click"/>'])
# ... and its EXTRA ENEMIES (port/linux/game/coop_enemies.c), below it:
# NONE, PER PLAYER or STATIC MULTIPLIER, and below that the amount of the
# one chosen (its own row, the other hidden: menu_functions.c's
# server_settings_update); each kept in its network.coop_enemies setting
def spinner_row(key, label_index, strings, setting, values):
nonlocal extra
extra += _widget(f"{base}/op_{key}", [("width", 512), ("height", 28),
("flags", "pass_unhandled_to_focused_child"),
("bitmap", "bitmaps/option_bkds"), ("color", "#FF2896FF")],
[f'<child widget="{base}/{key}_label"/>',
f'<child widget="{base}/{key}_spinner" x="286" y="1"/>'])
extra += _widget(f"{base}/{key}_label", [("type", "text"), ("controller", 1), ("width", 300),
("height", 22), ("string_list", f"{base}/labels"),
("string_index", label_index), ("font", "ui\\large_ui"),
("color", "#FF2896FF"), ("text_x", 13), ("text_y", 4)], [])
extra += _widget(f"{base}/{key}_spinner",
[("type", "spinner"), ("top", 2), ("width", 206), ("height", 20),
("flags", "pass_unhandled_to_focused_child left_right_tabs_items"),
("strings", "|".join(strings)), ("setting", setting),
("values", "|".join(str(value) for value in values)), ("font", "ui\\large_ui"),
("color", "#FF2896FF"), ("align", "center"), ("text_y", 4),
("header_bitmap", "bitmaps/arrow_sm_left"), ("footer_bitmap", "bitmaps/arrow_sm_right"),
("header_bounds", "7 -13 19 -7"), ("footer_bounds", "7 208 19 214")],
['<on event="created" run="port setting load"/>',
'<on event="deleted" run="port setting save"/>',
'<on event="left_mouse" run="mouse spinner 1wide click"/>'])
spinner_row("extra_enemies", 11, ["NONE", "PER PLAYER", "STATIC MULTIPLIER"], "network.coop_enemies_mode",
COOP_ENEMIES_MODES)
rows.append((f"{base}/op_extra_enemies", None, 5))
spinner_row("enemies_per_player", 12, [f"{value}%" for value in COOP_ENEMIES_PERCENTAGES],
"network.coop_enemies", COOP_ENEMIES_PERCENTAGES)
rows.append((f"{base}/op_enemies_per_player", None, 6))
spinner_row("enemies_multiplier", 13, [f"{value}X" for value in COOP_ENEMIES_MULTIPLIERS],
"network.coop_enemies_multiplier", COOP_ENEMIES_MULTIPLIERS)
rows.append((f"{base}/op_enemies_multiplier", None, 6))
# the gametype's options for this game (the gametype editor's screens,
# editing a copy of the gametype chosen: "port setup edit")
for index, (key, screen) in enumerate(SETUP_OPTION_SCREENS):
@@ -733,7 +746,8 @@ def _server_settings() -> list:
'<on event="left_mouse" run="mouse emit accept event"/>'])
extra += _strings(f"{base}/labels", ["GAME NAME:", "MAXIMUM PLAYERS:", "INVITE LINK:", "GAME TYPE:",
"PLAYER OPTIONS:", "ITEM OPTIONS:", "VEHICLE OPTIONS:", "INDICATOR OPTIONS:",
"TEAMPLAY OPTIONS:", "LISTING:", "FRIENDLY FIRE:", "EXTRA ENEMIES:"])
"TEAMPLAY OPTIONS:", "LISTING:", "FRIENDLY FIRE:", "EXTRA ENEMIES:",
"PER PLAYER:", "MULTIPLIER:"])
extra += _strings(f"{base}/help_strings", [
"",
"The name the game shows in the lists of games.\\nEnter changes it.",
@@ -753,8 +767,13 @@ def _server_settings() -> list:
"Players can be hurt by weapons or explosives\\nfired by the other players.",
"Damage from the other players will only reduce\\nshields. Health will be unaffected.",
"Players can be hurt by damage from explosives\\nfired by the other players.",
# (EXTRA ENEMIES')
# (EXTRA ENEMIES', by its choice: COOP_ENEMIES_MODES' order)
"Enemy squads are as the campaign has them.",
"Enemy squads grow with the players: by the amount\\nbelow for each player past the first.",
"Enemy squads are the amount below times as large,\\nhowever many players there are.",
# (PER PLAYER's and MULTIPLIER's)
"For each player past the first, enemy squads get\\nthis much more of themselves (100%: as many again).",
"Each enemy squad is this many times as large.",
])
lines = _screen(base, spec, rows, ["server settings update"],
['<on event="created" run="server settings init"/>'], extra)
@@ -770,8 +789,12 @@ MAXIMUM_PLAYERS = [2, 4, 8, 12, 16, 24, 32, 48, 64, 96, 128]
# network.coop_friendly_fire's values, as Server Setup's FRIENDLY FIRE shows
# them (menu_functions.c's cooperative_friendly_fire_modes, in this order)
COOP_FRIENDLY_FIRE_VALUES = ["off", "on", "shields_only", "explosives_only"]
# network.coop_enemies' values, percentages (Server Setup's EXTRA ENEMIES)
COOP_ENEMIES_VALUES = [0, 25, 50, 100, 150, 200]
# Server Setup's EXTRA ENEMIES: network.coop_enemies_mode's values (in
# coop_enemies.c's order), and the amounts of PER PLAYER (network.coop_enemies,
# percentages) and STATIC MULTIPLIER (network.coop_enemies_multiplier)
COOP_ENEMIES_MODES = ["none", "per_player", "multiplier"]
COOP_ENEMIES_PERCENTAGES = [25, 50, 100, 150, 200]
COOP_ENEMIES_MULTIPLIERS = [2, 4, 8, 16, 32]
# Server Setup's rows of the gametype's options: the gametype editor's
# screens
SETUP_OPTION_SCREENS = [