This aborts and prints the error from SDL_GetError() if
SDL_CreateWindow() or SDL_CreateRenderer() fails.
We abort because there's not much point in continuing if the window or
renderer can't be created. There might be a use case for running the
game in headless mode, but let's code that in explicitly if we ever want
it.
This sets the minimum window size (to 320 x 240), so that the window
cannot be resized to lower than that.
This is because there's no utility in having a game window smaller than
that, and it provides a bonus convenience of being able to resize the
game to exactly 320x240 without needing to be exactly precise about it.
This idea was suggested by Dav999.
The `point` struct was a relic of ActionScript and was added because of
the Flash 'point' object. However, it seems like Simon Roth didn't
realize that SDL has its own point struct.
With this, `Maths.h` can be un-included from a couple headers, which
exposes the fact that `preloader.cpp` was relying on `Maths.h` being
transitively included from `Graphics.h`.
Dav999 added `#include "Localization.h"` before `#include "KeyPoll.h"`,
when it should go after instead, because the letter L comes after the
letter K in the English alphabet.
Ever since VVVVVV was initially ported to C++ in 2.0, it has used surfaces from SDL. The downside is, that's all software rendering. This commit moves most things off of surfaces, and all into GPU, by using textures and SDL_Renderer.
Pixel-perfect collision has been kept by keeping a copy of sprites as surfaces. There's plans for pixel-perfect collision to use masks instead of reading pixel data directly, but that's out of scope for this commit.
- `graphics.reloadresources()` is now called later in `main`, because textures cannot be created without a renderer.
- This commit also removes a bunch of surface functions which are no longer needed.
- This also recaches target textures in certain places for d3d9.
- graphics.images was converted to a fixed-size array.
- fillbox and fillboxabs use SDL_RenderDrawRect instead of drawing an outline using four filled rectangles
- Update my name in the credits
The pixel border around the map fits to map size normally. However, when
the map is off, it's always the dimensions of the full size map, and the
border didn't reflect that, so if the custom minimap was off, and the
map wasn't the full size, it wouldn't fit correctly.
This bug was introduced in PR #898.
The branch name will be added to the window title if it is an interim
version, e.g. "VVVVVV [master]".
This makes it easier for developers to tell at a glance which build of
the game they're running.
While the window is initialized with 640x480, the screen settings
defaulted to 320x240, which is a tiny window. The screen settings take
priority over the initialized window, so people with no previous
settings file will get 320x240. This makes it so they get 640x480
instead.
The window is still initialized to 640x480 (constants used for clarity)
just in case there's some weirdness if it's initialized to a potentially
odd resolution from the user's settings file.
This is useful for developers who may have multiple builds of the game
from various different branches and may easily forget which build of the
game is what.
This shows up in the bottom-right corner of the title screen and also
with the `-version` command-line option, and in the status message
printed when building the game.
Unfortunately there needs to be an intermediate surface for proper alpha
color blending to happen via SDL_BlitSurface. The exact SDL blending
logic seems complicated and unclear for me to implement at the moment,
and my attempts kind of failed, so this is just a stopgap measure to at
least get the game rendering how it was before I screwed it up.
This refactors them to not allocate a temporary surface by instead
simply drawing directly to the destination surface.
This means re-implementing the original semantics of SDL_BlitSurface in
them, which is the function signature they (and BlitSurfaceStandard)
were based off of. So now if src_rect or dest_rect are NULL, it
automatically uses a rect of the entirety of the corresponding surface,
and other things like that. And also some other optimizations like
no-opping if the alpha is 0 (because then nothing will be drawn), and
critical checks (not drawing if the destination pixel is out of bounds,
because then otherwise it would wrap around, or at least that's what it
did when I tested it).
This resulted in a bunch of code that would really suck to copy-paste
because then you'd have to remember to update the other copy, so I
refactored them further and put the common code into one function, while
separating the different code (the exact transformation they do) into
different functions that get passed in through function pointers.
In general, "temp" is a bad name because it could mean anything. In this
case the buffer isn't really temporary and it's only used for drawing
the menu with a certain offset, so I made it use a better name. But also
because I'm going to be adding temporary buffers so I don't want the
names to be confused.
Honestly not too sure why we ever wrote the mask handling logic
ourselves instead of using SDL functions. Hell, we even used SDL_MapRGB
for Graphics::getRGB before.
`ct` was used to be a variable that a color was temporarily stored in
before being passed to a draw function. But this is unnecessary and you
might as well just have a temporary of the color directly. I guess this
was the practice used because temporaries were apparently really bad in
Flash.
setcolreal() was added in 2.3 to do basically the same thing (set it
directly from entities' realcol attributes). But it's no longer needed.
Correspondingly, Graphics::setcol has been renamed to Graphics::getcol
and now returns an SDL_Color, and Graphics::huetilesetcol has been
renamed to Graphics::huetilegetcol for the same reason.
Some functions (notably Graphics::drawimagecol and
Graphics::drawhuetile) were relying on the `ct` to be implicitly set and
weren't ever having it passed in directly. They have been corrected
accordingly.
colourTransform is a struct with only one member, a Uint32. The issue
with `Uint32`s is that it requires a bunch of bit shifting logic to edit
the colors. The issue with bit shifting logic is that people have a
tendency to hardcode the shift amounts instead of using the shift amount
variables of the SDL_PixelFormat, which makes it annoying to change the
color masks of surfaces.
This commit fixes both issues by unhardcoding the bit shift amounts in
DrawPixel and ReadPixel, and by axing the `Uint32`s in favor of using
SDL_Color.
According to the SDL_PixelFormat documentation (
https://wiki.libsdl.org/SDL2/SDL_PixelFormat ), the logic to read and
draw to pixels from colors below 32-bit was just wrong. Specifically,
for 8-bit, there's a color palette used instead of some intrinsic color
information stored in the pixel itself. But we shouldn't need that logic
anyways because we don't use colors below 32-bit. So I axed that too.
This makes it so temporary variables have their scopes reduced (if
possible). I also didn't hesitate to fix style issues, such as their
names ("temp" is such a bad name), making them const if possible, and
any code it touched too.
It previously duplicated the for-loop twice, once for tiles.png and
tiles2.png, which just made me sad. Now it doesn't do that.
Also it previously had an alternate tileset == 10 condition for
tiles.png, which didn't seem to do anything because there's no such
thing as tileset 10, and anyways it's useless in-game because when
playing in the actual game it won't draw tiles.png, so I removed it. I
don't know why it was there in the first place.
Since I removed the temp variable from the outer scope, the other usage
of it has to be updated.
For some reason they all have their executable bits set. Presumably this
is because they were made on an NTFS system where every file is
executable (which doesn't sound secure at all but that's another story).
This allows translators to test all text boxes in the scripts. It
doesn't run the scripts themselves - it only shows the basic appearance
of each text box individually, so context may be lost but it's good to
have a way to see any text boxes that might otherwise not be easily
seen because they require specific circumstances to appear.
Did another complete proofread of all the non-roomnames (hadn't looked
through *everything* in a while), and it's just three little things
that I felt would be important enough to tweak.
The strings "Vitellary"/"Vermilion"/"Verdigris"/"Victoria" now have two
cases to support changing them for the intermission replay menu options
(like "with Vitellary").
Also, the string "< and > keys change tool" is now "{button1} and
{button2} keys change tool", so it can be changed dynamically without
having to retranslate the string.
I wanted to not complicate the system with different string cases (like
cgettext) if possible, and I have been able to keep the main strings a
simple English=Translation mapping thus far, but apparently strings
like "Rescued!" (which are one string in English), have to be
translated for the correct gender in some languages. So this was a good
time to add support for string cases anyway.
It's a number that can be given to a string to specify the specific
case it's used, to disambiguate identical English keys. In the case of
"Rescued!" and "Missing...", male versions of the string are case 1,
female versions are case 2, and Viridian being missing is case 3. Of
course, if a language doesn't need to use different variants, it can
simply fill in the same string for the different cases.
If any other string needs to switch to different cases: distinguish
them in the English strings.xml with the case="N" attribute (N=1 and
higher), sync language files from the translator menu (existing
translations for the uncased string will simply be copied to all cases)
and change loc::gettext("...") to loc::gettext_case("...", 1),
loc::gettext_case("...", 2), etc.
With a single README.txt for both translators and maintainers, both
have to read through info that's not relevant for them, because
translators don't need to worry about the specifics of adding new
English strings and recompiling the game, and programmers don't need to
worry about the specifics of how to translate things. Now it's split
into README-translators.txt and README-programmers.txt.
I would, of course, recommend translators to translate the roomnames
while playing the full game (optionally in invincibility) so they can
immediately get all the context and maybe the most inspiration. And if
you want to go back into a specific level, then there's always the time
trials and intermission replays which will give you full coverage of
all the room names.
However, the time trials weren't really made for room name translation.
They have some annoying features like the instant restart when you
press ENTER at the wrong time, they remove context clues like
teleporters and companions, but the worst problem is that the last room
in a level is often completely untranslatable inside the time trials
because you immediately get sent to the results screen...
So, I added a new menu in the translator options, "explore game", which
gives you access to all the time trials and the two intermissions, from
the same menu. All these time trials (which they're still based off of,
under the hood) are stripped of the annoying features that come with
time trials. These are the changes I made to time trial behavior in
translator exploring mode:
- No 3-2-1-Go! countdown
- No on-screen time/death/shiny/par
- ENTER doesn't restart, and the map menu works. The entire map is also
revealed.
- Prize for the Reckless is in its normal form
- The teleporters in Entanglement Generator, Wheeler's Wormhole and
Level Complete are restored as context for room names (actually, we
should probably restore them in time trials anyway? Their "press to
teleport" prompt is already blocked out in time trials and they do
nothing other than being a checkpoint. I guess the reason they were
removed was to stop people from opening the teleporter menu when that
was not specifically blocked out in time trials yet.)
- The companions are there at the end of levels, and behave like in no
death mode (become happy and follow you to the teleporter). Also for
context.
- At the end of each level, you're not suddenly sent to the menu, but
you can use the teleporter at your leisure just like in the
intermission replays. In the Final Level, you do get sent to the menu
automatically, but after a longer delay.
I made another mark on VVVVVV: don't be startled, I added gamestates.
I wanted all teleporters at the end of levels to behave like the ones
at the end of the intermission replays, and all handling for
teleporting with specific companions is already done in gamestates, so
rather than adding conditional blocks across 5 or so different
gamestates, it made more sense to make a single gamestate for
"teleporting in translator exploring mode" (3090). I also added an
alternative to having to use gamestate 3500 or 82 for the end of the
final level: 3091-3092.
One other thing I want to add to the "explore game" menu: a per-level
count of how many room names are left to translate. That shouldn't be
too difficult, and I'm planning that for the next commit.
This is a single block of code so it was easy to split from the
foundation commit.
This commit is part of rewritten history of the localization branch.
The original (unsquashed) commit history can be found here:
https://github.com/Dav999-v/VVVVVV/tree/localization-orig
This involves loc::gettext_roomname and loc::gettext_roomname_special.
This commit is part of rewritten history of the localization branch.
The original (unsquashed) commit history can be found here:
https://github.com/Dav999-v/VVVVVV/tree/localization-orig
This mainly adds loc::gettext calls and replaces SDL_snprintf by
VFormat for the percentage.
This commit is part of rewritten history of the localization branch.
The original (unsquashed) commit history can be found here:
https://github.com/Dav999-v/VVVVVV/tree/localization-orig
This replaces SDL_snprintf by VFormat for the time strings, and makes
number_words get translated numbers.
This commit is part of rewritten history of the localization branch.
The original (unsquashed) commit history can be found here:
https://github.com/Dav999-v/VVVVVV/tree/localization-orig