1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-18 02:28:30 +02:00

Compare commits

...

15 Commits

Author SHA1 Message Date
Misa
64c554261e Fix regression: Entities not moving
Commit 53d725f78a, intended to fix an
overzealous commit, was itself overzealous. This is because it applied
to all entities when it should only apply to entity-emitting entities.
To fix this, `entityclonefix` needs to no-op if the entity is not an
entity emitter.

Fixes #1176.
2024-06-09 19:41:48 -07:00
Misa
53d725f78a Fix regression: Overzealous emitter dupe fix
Commit 4f881b9e26 fixed a duplication bug
where enemy movement types 10 and 12 would keep duplicating itself on
every frame if it was spawned outside of the rooms they were supposed to
be used in the main game. The downside was that this was an overzealous
fix and unintentionally broke some cases that were working before.

As brought to my attention by Ally, you can no longer place an edentity
with a `p1` of 10 or 12 (translating to movement type 10 or 12) in the
proper rooms and have it spawn perfectly working entities (that don't
clone on themselves every frame), whereas you could in 2.2. This is
considered a regression from 2.3.

So the problem here is that the reason the two emitter entities were so
dangerous outside their respective rooms is because the entity they
spawned (`createentity` entry 1) checked if it was in the correct rooms,
and if so, it would call `setenemy`, and `setenemy` would set the
`behave` attribute (movement type) correctly, and so the new entity
would have a different `behave` that wouldn't be the exact same `behave`
as the previous one, so it wouldn't be a duplicate emitter entity.

The previous `entityclonefix` worked okay for entry 1, because it would
only be run if the room checks failed and `setenemy` wasn't called, but
it broke a previously-working case for entry 56, because it was always
run for entry 56.

So the best way to check if we have a dangerous entity is not by seeing
if it is still `behave` 10 or 12 at the end of entity creation - because
10 or 12 could be harmless under the right conditions - but by checking
if the right conditions were satisfied, and if not, then neutralize the
entity.

I considered making the emitter entities work everywhere - which would
be simpler - but I didn't want to go too far and add a new feature,
especially in a minor release.
2024-06-07 14:20:28 -07:00
Misa
c20db02f15 Unload zips before loading zips
This fixes a minor issue where if you had a zip in the levels list, but
then removed it, it would still show up in the levels list after
reloading it (if you also had a .vvvvvv file named the same as in the
zip) even though it shouldn't.

Thankfully, this didn't lead to a memory leak or duplicate zip mounts or
anything like that, because PhysFS ignores mounting a zip if it's
already mounted.

This also didn't result in a level entry from a zip persisting after
removal after reloading the levels list, because the entry would be gone
due to the .vvvvvv file not being found.
2024-06-04 15:42:39 -07:00
Misa
dd15d67e62 Fix info args not working with -console
The intention of the `-console` argument was to enable seeing console
output on Windows without having to use workarounds. However, this
didn't actually work for arguments like `-addresses` and `-version`,
because the program would exit first before it could get the chance to
create the console.

The other issue is that the console closes too quickly before output can
be read by the user. So to fix that, we must hold it open and let the
user close it when they want to by waiting for an enter press from
STDIN.
2024-06-03 21:42:57 -07:00
Misa
a9d43b543f Fix regression: Foreground redraw after G keybind
This fixes a regression from 2.4 where the foreground wouldn't update
after using the G keybind to go to a room, requiring the user to touch a
tile to update the rendering.
2024-06-03 20:58:52 -07:00
Misa
16d75d2da8 Disable state locking if inc'ing state w/ ACTION
This fixes a bug report from Elomavi that you could still softlock from
warping to ship and incrementing the gamestate by pressing ACTION, which
is diverging behavior from how it was in 2.3. Warping to ship and
incrementing by pressing ACTION is useful behavior for a couple niche
speedrun categories.

I had already fixed this earlier by ignoring state locking if
glitchrunner 2.2 or 2.0 was enabled, but softlocks could still happen
because having glitchrunner mode off still enabled you to increment the
gamestate when otherwise unintended. Softlocks shouldn't happen.

But without removing state locking entirely, I've chosen a middle ground
where it will only be disabled if you press ACTION. That signifies
intent that you still want to perform state incrementing glitches even
with glitchrunner mode off (but in the future it could be considered a
2.3/2.4 glitch that could be patched and made re-enable-able). That way,
casual players can't interrupt the warp to ship by accident (unless they
accidentally press ACTION) while softlocks will be removed.
2024-05-25 23:34:03 -07:00
Misa
ff6bb68f3a Fix "Thanks for playing!" reversed in Flip Mode
For localization, the "Thanks for playing!" text was split into two
lines, when it was originally one line. Unfortunately, it was not
updated to account for Flip Mode, so in Flip Mode, it looked like
"playing! Thanks for".

This has been fixed.
2024-05-25 23:33:45 -07:00
leo60228
4b2b4fb7c9 CONTRIBUTORS.txt: leo60228 -> leo vriska 2024-05-21 20:57:19 -07:00
Terry Cavanagh
d678bd59ff
Added license exception for Recalbox project
https://shop.recalbox.com/
2024-05-02 17:12:36 +01:00
Misa
ff785aaa8a Bump version to 2.4.2
We still need to fix a couple bugs from 2.4.0.
2024-03-29 21:18:39 -07:00
NyakoFox
3361e71036 Add MSVC version check 2024-03-29 20:31:00 -07:00
NyakoFox
4bba26280f Add /utf-8 to MVSC 2024-03-29 20:31:00 -07:00
Misa
217996b134 Fix UB from out-of-range <stretch>
If there was a scaling mode value (serialized in the XML as <stretch>
for legacy reasons) that was not 0 or 1 or 2, then the rectangle with
the stretch information would not be initialized by get_stretch_info,
which would lead to a crash, either from dividing by zero (most likely)
or from reading an uninitialized value.

To fix this, when reading <stretch>, normalize it to a sane default if
the value is otherwise bogus. And for good measure, an assertion is
added in get_stretch_info() if the value is still somehow bogus.

Fixes #1155.
2024-03-29 20:22:00 -07:00
Misa
8640ead937 Fix copy-paste error in customposition
This would otherwise result in text boxes for custom crewmates being
improperly positioned.
2024-03-29 19:55:41 -07:00
Dav999
a9d438968d Change reply scripting command to player color
This is just a small visual fix to an inconsistency with textbox
colors in simplified scripting. The `reply` command is meant to be
used for the player, and always correctly positions it above the
player, while the `say` command may be used to generate a cyan textbox
that's positioned above a cyan non-player crewmate. However, the color
for both textboxes is always `cyan`, so the `reply` command doesn't use
the (normally identical) `player` color even though all its other
behavior (squeak, position) does. Now that customized textbox colors
were added in 2.4 (#910), it's a shame that this distinction isn't
made between `cyan` and `player`, so this change addresses that (before
we're stuck with levels that change `cyan` but not `player`).
2024-03-29 19:47:46 -07:00
15 changed files with 158 additions and 41 deletions

View File

@ -22,3 +22,4 @@ Last updated on January 23rd, 2024.
| XBox One/UWP Port | [tunip3](https://github.com/tunip3) | Port for XBOX ONE (DURANGO) via UWP. | Permission is given to distribute a pre-compiled package (containing the data.zip assets) for people to run on development mode xboxes, for non commercial use only. | [github repo](https://github.com/tunip3/DURANGO-V6)|
| armhf Port | [johnnyonFlame](https://github.com/johnnyonFlame/) | Armhf port for Raspberry PI and other SBC devices| Permission is for non commercial use only. Display the following text in the readme to make it clear that this is an exception: "VVVVVV is a commercial game! The author has given special permission to make this port available for free. If you enjoy the game, please consider purchasing a copy at [thelettervsixtim.es](http://thelettervsixtim.es)."| [github release](https://github.com/JohnnyonFlame/VVVVVV/releases/tag/v2.4-r1) |
| Wii Port | [Alberto Mardegan](https://github.com/mardy/) | Port for the Nintendo Wii. | Permission is given to distribute a ready-to-use build for the Nintendo Wii containing the data.zip assets for non commercial use only. | [github repo](https://github.com/mardy/VVVVVV/tree/wii) |
| Recalbox Port | [digitalLumberjack](https://gitlab.com/recalbox/recalbox) | Port for Recalbox project. | Display the following text in the readme to make it clear that this is an exception: "VVVVVV is a commercial game! The author has given special permission to make this port available for free. If you enjoy the game, please consider purchasing a copy at [thelettervsixtim.es](http://thelettervsixtim.es)." | [website](https://recalbox.com/) |

View File

@ -294,6 +294,11 @@ if(MSVC)
# Disable RTTI
string(REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
if(MSVC_VERSION GREATER 1900)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8")
endif()
else()
string(REGEX REPLACE "-std=[a-z0-9]+" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")

View File

@ -20,7 +20,7 @@ Contributors
* Jules de Sartiges (@strikersh)
* Keith Stellyes (@keithstellyes)
* KyoZM (@lsaa)
* leo60228 (@leo60228)
* leo vriska (@leo60228)
* MAO3J1m0Op (@MAO3J1m0Op)
* Malte Grimm (@trelbutate)
* Marvin Scholz (@ePirat)

View File

@ -173,7 +173,7 @@ static const char* githubfriends[] = {
"Jules de Sartiges",
"Keith Stellyes",
"KyoZM",
"leo60228",
"leo vriska",
"MAO3J1m0Op",
"Malte Grimm",
"Marvin Scholz",

View File

@ -251,6 +251,23 @@ static void levelMetaDataCallback(const char* filename)
}
}
static void unloadZips(void)
{
char** list = PHYSFS_getSearchPath();
if (list == NULL)
{
return;
}
for (char** path = list; *path != NULL; path++)
{
if (SDL_strncmp(*path, "levels/", 7) == 0 && endsWith(*path, ".zip"))
{
PHYSFS_unmount(*path);
}
}
PHYSFS_freeList(list);
}
void customlevelclass::getDirectoryData(void)
{
@ -258,6 +275,8 @@ void customlevelclass::getDirectoryData(void)
FILESYSTEM_clearLevelDirError();
unloadZips();
loadZips();
FILESYSTEM_enumerateLevelDirFileNames(levelMetaDataCallback);

View File

@ -2105,6 +2105,7 @@ static void input_submitted(void)
ed.levx = SDL_clamp(help.Int(coord_x) - 1, 0, cl.mapwidth - 1);
ed.levy = SDL_clamp(help.Int(coord_y) - 1, 0, cl.mapheight - 1);
graphics.foregrounddrawn = false;
graphics.backgrounddrawn = false;
break;
}

View File

@ -1232,7 +1232,24 @@ static bool gridmatch( int p1, int p2, int p3, int p4, int p11, int p21, int p31
static void entityclonefix(entclass* entity)
{
if (entity->behave == 10 || entity->behave == 12)
const bool is_lies_emitter = entity->behave == 10;
const bool is_factory_emitter = entity->behave == 12;
const bool is_emitter = is_lies_emitter || is_factory_emitter;
if (!is_emitter)
{
return;
}
const bool in_lies_emitter_room =
game.roomx >= 113 && game.roomx <= 117 && game.roomy == 111;
const bool in_factory_emitter_room =
game.roomx == 113 && game.roomy >= 108 && game.roomy <= 110;
const bool valid = (is_lies_emitter && in_lies_emitter_room)
|| (is_factory_emitter && in_factory_emitter_room);
if (!valid)
{
/* Fix memory leak */
entity->behave = -1;

View File

@ -4728,7 +4728,13 @@ void Game::deserializesettings(tinyxml2::XMLElement* dataNode, struct ScreenSett
if (SDL_strcmp(pKey, "stretch") == 0)
{
screen_settings->scalingMode = help.Int(pText);
int mode = help.Int(pText);
if (mode < 0 || mode >= NUM_SCALING_MODES)
{
/* Pick a sane default. */
mode = SCALING_INTEGER;
}
screen_settings->scalingMode = mode;
}
if (SDL_strcmp(pKey, "useLinearFilter") == 0)

View File

@ -3517,6 +3517,13 @@ void Graphics::get_stretch_info(SDL_Rect* rect)
rect->w = width;
rect->h = height;
break;
default:
SDL_assert(0 && "Invalid scaling mode!");
/* Width and height should be nonzero to avoid division by zero. */
rect->x = 0;
rect->y = 0;
rect->w = width;
rect->h = height;
}
}

View File

@ -2617,6 +2617,7 @@ void gameinput(void)
|| !game.glitchrunkludge)
{
game.state++;
game.unlockstate();
}
game.jumpheld = true;
game.glitchrunkludge=true;

View File

@ -1,6 +1,6 @@
#ifndef RELEASEVERSION_H
#define RELEASEVERSION_H
#define RELEASE_VERSION "v2.4.1"
#define RELEASE_VERSION "v2.4.2"
#endif /* RELEASEVERSION_H */

View File

@ -2135,9 +2135,21 @@ void gamecompleterender(void)
creditOffset += 140;
if (graphics.onscreen(creditOffset + position))
{
font::print(PR_2X | PR_CEN | PR_CJK_HIGH, -1, creditOffset + position, loc::gettext("Thanks for"), tr, tg, tb);
const char* line1;
const char* line2;
if (graphics.flipmode)
{
line1 = loc::gettext("playing!");
line2 = loc::gettext("Thanks for");
}
else
{
line1 = loc::gettext("Thanks for");
line2 = loc::gettext("playing!");
}
font::print(PR_2X | PR_CEN | PR_CJK_HIGH, -1, creditOffset + position, line1, tr, tg, tb);
creditOffset += 20;
font::print(PR_2X | PR_CEN | PR_CJK_LOW, -1, creditOffset + position, loc::gettext("playing!"), tr, tg, tb);
font::print(PR_2X | PR_CEN | PR_CJK_LOW, -1, creditOffset + position, line2, tr, tg, tb);
}
draw_skip_message();

View File

@ -681,7 +681,7 @@ void scriptclass::run(void)
texty = 0;
textcrewmateposition.x = obj.entities[i].xp;
textcrewmateposition.override_x = true;
textcrewmateposition.y = obj.entities[i].xp;
textcrewmateposition.y = obj.entities[i].yp;
textcrewmateposition.override_y = true;
textcrewmateposition.dir = j;
@ -3547,7 +3547,7 @@ bool scriptclass::loadcustom(const std::string& t)
}else if(words[0] == "reply"){
//For this version, terminal only
if(squeakmode==0) add("squeak(player)");
add("text(cyan,0,0,"+words[1]+")");
add("text(player,0,0,"+words[1]+")");
int ti=help.Int(words[1].c_str());
int nti = ti>=0 ? ti : 1;

View File

@ -220,6 +220,12 @@ void vlog_open_console(void)
vlog_error("Could not redirect STDERR to console.");
}
handle = freopen("CON", "r", stdin);
if (handle == NULL)
{
vlog_error("Could not redirect STDIN to console.");
}
check_color_support();
if (!SetConsoleOutputCP(CP_UTF8))

View File

@ -363,6 +363,23 @@ static void emscriptenloop(void)
}
#endif
static void keep_console_open(const bool open_console)
{
if (!open_console)
{
return;
}
printf("Press ENTER to quit.");
int c;
do
{
c = getchar();
}
while (c != '\n' && c != EOF);
}
int main(int argc, char *argv[])
{
char* baseDir = NULL;
@ -370,9 +387,11 @@ int main(int argc, char *argv[])
char* langDir = NULL;
char* fontsDir = NULL;
bool seed_use_sdl_getticks = false;
#ifdef _WIN32
bool open_console = false;
#endif
bool print_version = false;
bool print_addresses = false;
int invalid_arg = 0;
int invalid_partial_arg = 0;
vlog_init();
@ -386,41 +405,16 @@ int main(int argc, char *argv[])
} \
else \
{ \
vlog_error("%s option requires one argument.", argv[i]); \
VVV_exit(1); \
invalid_partial_arg = i; \
}
if (ARG("-version"))
{
/* Just print the version and exit. No vlogging. */
puts(
"VVVVVV " RELEASE_VERSION
#ifdef MAKEANDPLAY
" [M&P]"
#endif
);
#ifdef INTERIM_VERSION_EXISTS
puts(COMMIT_DATE);
puts(INTERIM_COMMIT);
puts(BRANCH_NAME);
#endif
VVV_exit(0);
print_version = true;
}
else if (ARG("-addresses"))
{
printf("cl : %p\n", (void*) &cl);
printf("ed : %p\n", (void*) &ed);
printf("game : %p\n", (void*) &game);
printf("gameScreen : %p\n", (void*) &gameScreen);
printf("graphics : %p\n", (void*) &graphics);
printf("help : %p\n", (void*) &help);
printf("key : %p\n", (void*) &key);
printf("map : %p\n", (void*) &map);
printf("music : %p\n", (void*) &music);
printf("obj : %p\n", (void*) &obj);
printf("script : %p\n", (void*) &script);
VVV_exit(0);
print_addresses = true;
}
else if (ARG("-renderer"))
{
@ -541,8 +535,7 @@ int main(int argc, char *argv[])
#undef ARG
else
{
vlog_error("Error: invalid option: %s", argv[i]);
VVV_exit(1);
invalid_arg = i;
}
}
@ -557,6 +550,54 @@ int main(int argc, char *argv[])
}
#endif
if (invalid_arg > 0)
{
vlog_error("Error: invalid option: %s", argv[invalid_arg]);
keep_console_open(open_console);
VVV_exit(1);
}
else if (invalid_partial_arg > 0)
{
vlog_error("%s option requires one argument.", argv[invalid_partial_arg]);
keep_console_open(open_console);
VVV_exit(1);
}
if (print_version)
{
/* Just print the version and exit. No vlogging. */
puts(
"VVVVVV " RELEASE_VERSION
#ifdef MAKEANDPLAY
" [M&P]"
#endif
);
#ifdef INTERIM_VERSION_EXISTS
puts(COMMIT_DATE);
puts(INTERIM_COMMIT);
puts(BRANCH_NAME);
#endif
keep_console_open(open_console);
VVV_exit(0);
}
else if (print_addresses)
{
printf("cl : %p\n", (void*) &cl);
printf("ed : %p\n", (void*) &ed);
printf("game : %p\n", (void*) &game);
printf("gameScreen : %p\n", (void*) &gameScreen);
printf("graphics : %p\n", (void*) &graphics);
printf("help : %p\n", (void*) &help);
printf("key : %p\n", (void*) &key);
printf("map : %p\n", (void*) &map);
printf("music : %p\n", (void*) &music);
printf("obj : %p\n", (void*) &obj);
printf("script : %p\n", (void*) &script);
keep_console_open(open_console);
VVV_exit(0);
}
SDL_SetHintWithPriority(SDL_HINT_IME_SHOW_UI, "1", SDL_HINT_OVERRIDE);
/* We already do the button swapping in ButtonGlyphs, disable SDL's swapping */
@ -774,6 +815,7 @@ int main(int argc, char *argv[])
cl.ListOfMetaData.push_back(meta);
} else {
vlog_error("Level not found");
keep_console_open(open_console);
VVV_exit(1);
}
}