To recognize getaddrinfo as supported, require that the AI_* flags
passed to it be usable:
- AI_NUMERICSERV must be defined as a number or be undefined
- If ipv6=1, then AI_V4MAPPED and AI_ALL must be defined as numbers
When getaddrinfo is used, raise _WIN32_WINNT from 0x501 to 0x600.
Otherwise, lower it to 0x500.
This fixes two problems on systems where sizeof(int) < sizeof(fix64)
(which applies on most systems).
Normally, the omega cannon does not charge for ~1/3 of a
second after firing stops.
The first problem is that, if (Last_omega_fire_time + 1/3 second)
exceeds 0x80000000 (about 9.1 hours), truncation issues confuse this
rule into not applying, thus allowing the omega cannon to charge
whenever energy is available, even while firing.
The second problem is that, if GameTime64 exceeds 0x8000000000000000
(about 4459701.8 years), a sanity check that attempted to compensate for
the incorrect tracking of Last_omega_fire_time would confuse the
recharge rule into deciding that the user had always fired recently,
which would prevent the omega cannon from ever recharging. The sanity
check would reset Last_omega_fire_time when Last_omega_fire_time was in
the future relative to GameTime64. Unfortunately, Last_omega_fire_time
was only an int, so the reset truncates off the high bits of GameTime64.
This truncation is harmless when GameTime64 is less than 0x80000000,
causes the first problem when GameTime64 is not less than 0x80000000,
but is positive, and causes the second problem when GameTime64 is
negative.
These problems were mitigated in prior releases by three factors. First,
a hack resets GameTime64 when restoring from a saved game, so the
affected game needs to run for ~9.1 hours (or ~4459701.8 years) without
reloading. Second, starting a new level resets GameTime64, so the game
needs to stay on a single level for ~9.1 hours (or ~4459701.8 years).
Third, the omega cannon discharges faster than it can recharge, so even
when the first bug allowed it to charge while firing, a player could
still drain Omega_charge to zero by continuous firing. However, it
would take longer to drain due to the bug-induced concurrent recharge,
and would not be subject to the 1/3 second wait normally imposed between
depleting Omega_charge and recharge beginning.
Fix these problems by replacing Last_omega_fire_time with
Omega_recharge_delay, which is 0 when recharging is allowed or a
positive amount of frame time if recharging is disallowed due to recent
firing. Set Omega_recharge_delay to 1/3 second when the user fires.
Decrease it by up to FrameTime when omega_recharge_frame runs.
This does not fix the preexisting problem that reloading a savegame does
not update the recharge delay, which manifests two related problems.
First, firing the omega cannon and then loading a game will bring the
delay through into the save, whether or not the user had been firing
just before saving. Second, not firing the omega cannon and then
loading a game will allow the user to fire immediately on load, even if
the user had been firing when the game was saved. Future work can
address the first problem by clearing the delay, but a savegame file
modification is required to address the second problem.
------------->8-------------
#include <cstdio>
int last_fire;
long t64;
/* The test program only shows the bug on 64-bit systems */
static_assert(sizeof(last_fire) == 4, "sizeof(int) != 4");
static_assert(sizeof(t64) == 8, "sizeof(long) != 8");
void frame(bool expect_recharge, const unsigned line)
/* clang does not support __builtin_LINE, so fake it with a macro
*/
#define frame(E) frame(E, __LINE__)
{
if (last_fire > t64)
{
printf(__FILE__ ":%u:%u: last_fire=%8x t64=%16lx: last_fire > t64, resetting\n", __LINE__, line, last_fire, t64);
last_fire = t64;
}
const int time_bias = 0x5555;
if (last_fire + time_bias > t64)
{
printf(__FILE__ ":%u:%u: %5sexpect_recharge=%i last_fire=%8x t64=%16lx: last_fire recent (%16lx), refusing to recharge\n", __LINE__, line, expect_recharge ? "BUG: " : "", expect_recharge, last_fire, t64, static_cast<long>(last_fire + time_bias));
return;
}
printf(__FILE__ ":%u:%u: %5sexpect_recharge=%i last_fire=%8x t64=%16lx: last_fire old (%16lx), recharging\n", __LINE__, line, expect_recharge ? "" : "BUG: ", expect_recharge, last_fire, t64, static_cast<long>(last_fire + time_bias));
}
int main(int, char **)
{
frame(false);
t64 = 0x7fff;
frame(true);
last_fire = t64 - 4;
frame(false);
t64 = 0x7fffaaab;
frame(true);
last_fire = t64;
++t64;
frame(false);
t64 = 0x7ffffffffd;
frame(true);
last_fire = t64;
++t64;
frame(false);
t64 += 0x10000;
frame(true);
t64 = 0x7fffffffffffff00;
frame(true);
last_fire = t64;
frame(false);
t64 = 0x8000000000000000;
frame(true);
t64 += 0x800000000;
frame(true);
}
Previously, do_laser_firing_player would update Next_laser_firing_time,
then do_omega_stuff would update it again. OMEGA_BASE_TIME is smaller
than Weapon_info[OMEGA_ID].fire_wait, so the first store was overridden
by the second. As a quirk, the override was skipped if the omega cannon
was unable to fire due to object limits or due to insufficient energy,
causing those rare cases to use the longer
Weapon_info[OMEGA_ID].fire_wait delay.
Fold the omega cannon handling of Next_laser_firing_time into
do_laser_firing_player to eliminate that quirk, simplify the code, and
remove the need to recompute fire_frame_overhead from
Last_omega_fire_time.
Constructing valptridx::basic_ptr with a known-invalid magic index does
not require an array. Simplify the static_assert to reject uses of
factory functions with known-invalid magic index values. Fix the two
sites that fail with the stricter static_assert.
When File->'Play in 320x200' is chosen, use StartNewGame(Current_level_num). For now use create_new_mission and Current_level_num = 1 every time. Also remove the now redundant hacks GM_EDITOR and editor_reset_stuff_on_level.
build_segment_list and build_object_lists are now required for _search_mode as well (i.e. required for every frame), as the segment list is no longer a set of global variables.
If a game was playing, continue playing. If it was in the main menu, return to the main menu. (If all files are put in place the editor can load again.)
This prevents newdemo_stop_playback from attempting to close Game_wind, which results in it being freed twice - in particular when switching to the editor (via delete-E) when playing a demo.
When responding to EVENT_WINDOW_CLOSE, set MainWindow to nullptr - fixing multiple issues with these dialogs including the inability to re-open them and a crash on exiting the editor.
If loading an pre-v22 save game, or loading any save where the player
died on the secret level, clear Omega_charge instead of retaining
whatever value the prior game used.
Commit 30f9233b36 introduced a test for
Game_Mode, which does not exist, rather than Game_mode, which does
exist. However, the test for game mode is unnecessary. Objects of type
OBJ_NONE are always in segment_none and no object of any other type
should be in segment_none. Use that fact to test obj->type instead of
obj->segnum during multiplayer object clobber, so that multiplayer can
overwrite unallocated objects without accessing any undefined fields and
without making object::segnum a defined field.
Fixes: 30f9233b36 ("Reverted 2e6aa0f081 and partially reverted 7064fcccba to still allow segnum and signature init for multiplayer games, keeping consistency during object sync.")
Move the main part of obj_link into obj_link_unchecked. Implement
obj_link as sanity check assertions followed by a call to
obj_link_unchecked. Remove caller-side writes that were present solely
to bypass the assertions, since the assertions can now be bypassed by
calling obj_link_unchecked directly.
menu.cpp always needs SDL.h, but included it only as a side effect of
joy.h including SDL.h. joy.h only includes SDL.h when max_joysticks!=0.
Reported-by: kreatordxx <https://github.com/dxx-rebirth/dxx-rebirth/issues/258>
Split ogl_get_verinfo() into ogl_tune_for_current() and
ogl_extensions_init(), and consolidate all the OpenGL extension handling
into ogl_extensions.cpp. Unify the code paths for texture anisotropy and
GPU synchronization for OpenGL and OpenGL ES.
Currently, our renderer only uses GLES 1.0, so no real world implementation
will support sync objects for such an old context, but the logic is valid,
and this way, the GLES specific code paths are reduced.
This patch also fixes an issue where the old ogl_get_verinfo() did modify
the texture filtering mode if no anisotropic filter was available. This
was some leftover from the time when the anisotropic filter was a just
a specific CGameConfig.TexFilt mode, and not a separate, orthogonal setting
CGameCfg.TexAnisotropy that it is now.
derhass reports that OpenGL ES builds warn for unused parameter
`texanis`. This parameter controls a feature that is not available in
current Rebirth OpenGL ES builds. Cast the parameter to void to silence
the warning. Long term, the code ought to be changed to advise the user
when their platform lacks this feature. In the short term, merge this
fix so that the build will succeed.
https://github.com/dxx-rebirth/dxx-rebirth/pull/256
One caller uses fuelcen_activate when segp->special != station_type.
Every other caller passes the type that was already on the segment.
Move the assignment into the one caller that needs it, then remove the
argument.
Whenever a robot is sent to peers, it needs to be added to the local
mapping also. Move the one use so far into multi_send_boss_create_robot
to simplify maintenance.
gcc generates better code for:
if (variable == magic_constant)
return magic_constant;
than it does for:
if (variable == magic_constant)
return variable;
even though the two have the same result. Switch to the form which
generates slightly better code.
Add 'track' method to dcx::window, which takes a bool and will set it to 'false' when the window closes. Use for newmenu_do2 and simpler newmenu_do's, since there's the possibility of another window without its own polling loop opening on top - meaning window_event_result::deleted would be returned for that window, not the one we're polling on.
Hidden windows don't receive events, so the only way to close is outside its handler, which there should be no cases of here. The function window_exists could return a false positive if a new window was created with the same pointer value as a deleted one. Will later disable window_exists function.
Replace with a disabled check for window_event_result::deleted, which will be enabled when all newmenu subfunctions return a window_event_result. There are currently no instances of a subfunction closing the window itself (which is preferred).
This ensures the event system will know what's going on. Also remove the 'likely' branch prediction macro from close_wall_window because close_wall_window will only be called outside of the wall dialog's handler (to open a different dialog or close the editor).
Make the listbox handlers and all sub-handlers (when_selected callbacks) return a window_event_result. Makes code more readable and removes one use of window_close, making it easier to inform event system if a window closes in future.
Return window_event_result::deleted if Game_wind was closed somewhere in response to an event handled by game_handler, so in future the event code can use that instead of window_exists to avoid tripping up.
gcc permits strlen("") in a constexpr context, but clang prohibits it.
Kreator reports that this broke the OS X build. Use sizeof(), which
produces approximately the same result and works in both compilers.
Reported-by: kreatordxx <https://github.com/dxx-rebirth/dxx-rebirth/issues/251>
Fixes: 63ca86698e ("Added communication for tracker written by A Future Pilot")
Kreator reports that clang warns that `i` may be uninitialized in
write_key_text. This is a valid warning, but gcc does not generate it.
Refactor write_key_text to eliminate the warning and simplify the code.
Reported-by: kreatordxx <https://github.com/dxx-rebirth/dxx-rebirth/issues/252>
Fixes: 20776fcfbc ("Use range_for/vcwallptr for write_key_text")
Some custom levels attempt to use texture overrides that reference
textures that are not yet paged in. It is not legal to access the data
of a paged-out texture, but ogl_loadbmtexture_f attempted to access it
anyway, causing a crash. Page in the texture before calling
ogl_loadbmtexture_f. Old versions of the engine would have cached
garbage data when this happened.
Reported-by: kreator <https://github.com/dxx-rebirth/dxx-rebirth/issues/228>
Fixes: 3c20c24ac0 ("Disable piggy_bitmap_page_out_all")
Mako88 reports that e335cdacb3 broke
reading historical high score files.
Code analysis shows that the size of the high score file must match the
size of struct all_scores, but this was not enforced anywhere. Commit
e335cdacb3 changed the size of struct
all_scores. Restore it to its previous size, and add a static_assert to
break the build if anyone tries to change it again.
Reported-by: Mako88 <https://github.com/dxx-rebirth/dxx-rebirth/issues/241>
Fixes: e335cdacb3 ("Reverted 81d7db279b and rather removed the terminator byte from string length in nm_set_item_input(). This also fixes possible 9 character length for pilot callsigns. Had to fix up COOL_SAYING_LEN as it was not considering the termintor but considering the original D2 source, this was a mess to begin with (def = 50, text string = 60, input field len = 45). Made score saying 50 characters as this seems to be the maximum witdth without overlapping.")
Mako88 reports that 2a19da88d4 changed
robot movement. That commit reordered the operations in a way that
tends to truncate small values prematurely. Restore the original order
of operations.
Reported-by: Mako88 <https://github.com/dxx-rebirth/dxx-rebirth/issues/247>
Fixes: 2a19da88d4 ("Pass object_base &to move_towards_vector")
multi_do_reappear is overloaded to be used both on ghosts and on live
players. This causes a diagnostic because the *_id checks expect
exactly one type: either test for ghost or test for player, but not test
for and accept both. Open code the type check to support both.
kmatrix_draw_coop_item computes various values that are always the same
for every iteration of the calling loop. Expand it inline in its one
caller so that the caller can cache those values.
The only caller for get_multi_endlevel_poll1 was DoEndLevelScoreGlitz,
which only called it on an unreachable path. That path is now gone, so
remove get_multi_endlevel_poll1.
Commit 63ca866 reduced the number of elements in UDP_Socket[] from (2 +
tracker) to (2), but added a write to UDP_Socket[2], which is now out of
bounds. Fortunately, UDP_Socket[2] is never read. Remove the
initialization of it.
Fixes: 63ca86698e ("Added communication for tracker written by A Future Pilot")
Conflicts:
common/arch/sdl/window.cpp - Remove unused EVENT_WINDOW_CLOSED and w_callback local var
common/ui/dialog.cpp - Remove unused EVENT_WINDOW_CLOSED
Rename symbol WORDS_NEED_ALIGNMENT to DXX_WORDS_NEED_ALIGNMENT to show that it is a DXX
symbol, not one inherited from a library.
This is a mostly automated transform, but the changes to SConstruct were
manual.
git grep -wl WORDS_NEED_ALIGNMENT -- '*.h' '*.cpp' | xargs sed -i -e 's/^\s*#ifdef \(WORDS_NEED_ALIGNMENT\)\>/#if DXX_\1/' -e 's/\s*#\(el\)\?if \(.*\)defined(\(WORDS_NEED_ALIGNMENT\))/#\1if \2DXX_\3/' -e 's/^\s*#ifndef \(WORDS_NEED_ALIGNMENT\)\>/#if !DXX_\1/'
Fixes: 435aa5a020 ("Move USE_UDP to dxxsconf.h; rename to DXX_USE_UDP")
Fixes: 7c8c2b5aa4 ("Move USE_TRACKER to dxxsconf.h; rename to DXX_USE_TRACKER")
Saved games dump robot ai_local state for all objects, regardless of
whether the object is a robot. Loading a game restored all ai_local
values, regardless of whether the object was a robot on restore. This
caused memory corruption in objects that were not robots when the
`ctype.`_T_ for that object was large enough to overlap
`ctype.ai_info.ail`.
Fix this by loading the ai_local into a junk buffer when the object is
not a robot. It would be better to skip over the bogus ai_local
entirely, but the structure of ai_local_read_swap makes that difficult.
Use the easy fix for now.
Kreator reports that "Pyramids of Luxoran" crashes due to a valptridx
sanity check. The level incorrectly attempts to open a wall on a
segment/side which has no wall.
Add an error check and a con_printf suggesting that the level author
needs to fix the invalid trigger.
Kreator reports that a level from back when Descent was new fails the
test for bogus matcen triggers. This level cannot be played when that
test throws an exception, so downgrade the exception to a CON_URGENT
message. This will hopefully deter level authors from creating any new
levels with this problem, but will allow users to play existing levels.
Replace delete dcx::window kludge with a better solution: instead of requiring every handler to delete the window, add a window_event_result::deleted, which gets returned if the window was deleted by the handler, so window_close knows not to attempt to delete it again.