Several of the fixes taken from the forks changed source/ without the
port: comment that marks a change from the original (the second copy's
datagram ports, the downloaded maps' refusals, the main menu's clock,
the one-magazine HUD states, the render lists' sizes and others), and a
comment still named a function of that fork's. Each change now says so.
A tick waits for an input update with an action for each player, and the
menus change who the local players are (signing profiles in and out, a
lobby's network game owning the queues). In a lobby, or once a client's
clock waited for a game, the main menu's scene stopped ticking; and a
screen flagged to pause game time (Mods, the map and gametype screens of
setting up a game) paused the clock that runs the scene, which then
started again from its beginning as the screen closed.
The main menu's scene now always ticks on this machine's clock
(game_time_menu_scene), its players idle where the queues have no input
for them, and at the main menu those screens no longer pause it. The
distributed netcode's per-tick work is not done for the scene: a lobby's
machines do not share it.
(cherry picked from commits 8444785804f8cfb413020da5a03fc5dd65f918e9, 6267d199117f87e56a3f41fc8932966a39a3feb2
and 3a4097bb48f34245b750028a5c0ae28e03bae037, made again on OpenCE's game_time_update,
which has no separate clock connection for the scene)
The Join Game server browser shows each ping coloured: green under 80 ms,
yellow under 160, red above. A text colour hook of the menus'
(pc_menu_text_color) gives the ping its colour; the rest keep their own.
(cherry picked from commit 335c6522e9fb7aa33762e3f2cf27c518ac0e48ce, without that fork's
Online Games screen, the thresholds and colours kept in menu_functions.c)
In Join Game's server browser a click selects a game, its row in the
yellow-outlined picture Custom Edition draws for it, and a click on the
selected game, a double click, A, Enter or JOIN joins it; one click
joined it before. The keys move the selection.
(cherry picked from commit 472d232246568ed2e3ee56bc93d97a3530feea54, without that fork's
Online Games screen; OpenCE's rows already take the focus only from a
click, not from the pointer passing over them)
"event handler function failed" said nothing of which: the gametype
editor logged it fifteen times. It names the function's number and the
widget's tag, taken before the function runs (it may delete the widget).
(cherry picked from commit 5f4494f42b1919dc1e38c6f8e168b646768e74f1)
A screen's button bar (SELECT and BACK under a list) steps sideways, so
once the wheel scrolled past a list's last row onto the bar it went back
and forth between the two buttons until a row was chosen again with the
mouse. A touch drag already left the bar with up and down, as the d-pad
does; the wheel now does the same.
(cherry picked from commit 2ddad079fa5435a70a383d757de16b960c421505)
The Xbox's postgame map select wrappers already carry
main_menu_if_no_history, with which the stock event code calls
main_goto_main_menu() when Back closes the last screen. The PC menus'
connected_map_select_wrapper, which menu_tags.c opens in their place,
was given the same flag by tools/port_settings.py in 4301ca88d, so the
hard-coded names and the network_game_abort() call in
widget_instance_go_back_to_previous were not needed, and they changed
stock split-screen behaviour (a split-screen game is a local server).
widget_instance_go_back_to_previous is as it was before 7d128e1bd.
Checked: the harness and touch menu tests (491 passed), test_web_build
(11 passed), ui_widget.c compiled for Linux and the Android guest.
Fast setup and the network test's join opened ui.map's pregame screen by name, where ui_widget.c opens the port's lobby; a ui.map of only the menus' tags hosts and joins with both.
The map's letters do not sit alike on every icon: on the message icons'
sheet, X's and Y's are about 1.7 texels lower on their ovals than the
redraws put them. tools/button_assets.py layout now moves each icon's
letter (and Y's shadow, given the id "shadow") to where it best matches
the map's, and buttons.json keeps the move; the menus' large buttons move
by under 0.03 texels, the message icons' by up to 1.7. The PNGs are drawn
again, the sheet with all 256 levels of alpha rather than 32.
hud_hires_sprites_drawable read display.high_res_hud and high_res_text
only once, and hud_hires_sprite_bitmap kept its answer for the bitmap's
address, so turning either setting off or on left the message icons as
they were: both check again when the settings change, as
hud_hires_override_find does. ui_widget.c declares hud_hires_sprite_bitmap
with the port's other functions instead of in the block that calls it.
AUTHORS.md credits saulob for the redraws.
Checked with button_assets.py check against ui.map and side by side with
the map's icons; ninja linux and ninja android build, and the harness and
test_linux_port pass.
The new helpers sat between widget_takes_events_of_controller's comment and the function, so the comment now heads it again; pc_menu_split_players is declared with the file's other port prototypes rather than as an extern among the functions, the players' count is read with players_port_local_player_count (safe before the players' globals are made), the comment names process_ui_widgets, and the test widget_takes_any_controller already makes is not made twice.
A list whose focus reached its first or last row scrolled on and moved the
focus a row in; the pointer hovering that row took the focus back the next
frame it moved, so the list ran through everything and the row under the
pointer never stayed lit (the game types, the lobby, the internet lobby).
A list now scrolls on at its end only when the d-pad (keys, controller,
the wheel) put the focus there (ui_widget_port_pointer_focused).
(cherry picked from commit e74f5bbb541a480a72871adeb719472908607d12)
With input.touch_aim_assist false, walking with the touch stick still let the view follow a target: the touch controls now count as aiming without the assist until a stick aims again (halo_linux_touch_aiming), as the mouse does. The stick's diagonal is full on both axes, as a controller's square stick gives. The gyroscope reaches the game apart from the swipe (nativeGyro), so the profile's invert look turns only the swipe.
The overlay shows once the game has been in play for 200 ms, so it does not flash at a level's first frame. The options dialogs are counted, so a dialog opened from another keeps the controls released, and the layout is saved when the last one closes (a slider moved without a finger was not). A floating stick rests where the thumb lands, even near an edge, and not in the bottom gesture zone. A finger's width is at most 34 logical units, so the D-pad's buttons stay apart on a small dense display. A held button that takes over the swipe from another finger starts from where it is, not from where it went down. The system bars coming and going no longer release every finger. Hide stops the gyroscope.
The libtiff comments are corrected: the screenshot_count and screenshot_size globals also reached tiff_export, but read back-buffer memory the port never draws into, so they never had the picture. Stale comments are fixed and the source exclusion test covers folders.
Each controller's events went only to its own player's screens, and the
main menu is the first player's: a gamepad on any port but the first
did nothing, and a phone can list a device of its own (its touch
controls) before the gamepad. With one person playing, the first
player's screens now read and take every controller's events; with two
or more, each controller keeps to its own player's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A finger's targets: a tap on a setting row's label reaches its value, and the values are wider. The mouse clicks the labels and values where CE's menus have them, as before the PR.
Operate the Android menus by touch
Conflicts resolved: the pointer's window-to-menu mapping takes main's centering (the scoreboard's) and the PR's missing-back-buffer check, and is shared; the scoreboard's pointer stays the desktop's (an Android stub); FOCUS_LOST drops both the scoreboard's pointer and the touch; main's Steam on-screen keyboard and the PR's Android pointer each keep their side of the #ifndef; CI runs test_touch_menu.py with the harness.
Opus voice chat (port/third_party/opus 1.5.2, port/linux/src/voice_audio.c, port/linux/game/network_voice.c), relayed by the host, in the lobby too. The host decides in Server Setup > Teamplay Options: lobby voice (on by default), the game's mode (off, team near, anyone near, team, team and enemies near: the default), the near distance, and the quality, 8 to 64 kbps (24). Each player picks push to talk (V), open mic or off, the voices' volume, and the output and input devices in Settings > Audio, and mutes others from the scoreboard's menu. A speaker icon marks who talks in the lobby, on the scoreboard and in a list in game. The host takes a machine's frames only with the key it gave it over its stream, within the quality's size, 50 a second and 8 talkers at once, and sends voices only to machines that asked for them, so the network version stays.
Text boxes take a string index from 0x5000 as a spinner's extra item's
description (kills_to_win_extra_descriptions). Custom Edition multiplayer
maps' display indices now run from 0x4000 to 0x6000 (8192 maps), so a
list of more than 4096 showed the next maps' names as kills-to-win
descriptions. The descriptions move to 0x7000, which custom_edition_maps.c
already keeps every map's display index below.
A client joining a game on a map it does not have (a Custom Edition map
not in custom_maps, or one of the game's own not in maps) now leaves with
an error naming the map and where to copy it, instead of the damaged disc
error. It also says when the map cannot run there or the host names a
Custom Edition map as other versions do. The port's error texts wrap to
their dialog, in the smaller font when they would not fit.
Network version 22: hosts now name Custom Edition maps custom_maps\<name>,
which older clients cannot load or explain; they are told to update.
Hosting a co-op level from the Map screen (CO-OP CAMPAIGN, a level and its
difficulty, then Server Setup) makes a network game on the campaign map
with no game engine, which is what co-op is. Only the host runs the
scripts and the AI; port/linux/game/network_coop.c sends clients what the
scripts do (cutscenes, camera, fades, HUD, sounds, devices, named objects,
animations), and network_actors.c drives the host's AI units on every
machine. Players spawn beside each other, respawn beside a safe teammate,
and spectate while dead or waiting. Skipping a cutscene is a vote.
Players can join a game in progress at any time.
The game type editor's kills to win (Slayer and Team Slayer) went up to
50, which a game of many players reaches in moments: it now also offers 75,
100, 150, 200, 250 and 500. The spinner's items are its string list's
(ui.map's 5, 10, 15, 25, 50) and then strings of the port's own, each with
its description; the options list's descriptions count only a spinner's
items of the tag's own, so those of the rows after it are where they were.
A spinner with extra items is a little wider, for three digits.