1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-11-18 00:49:42 +01:00
Commit graph

2340 commits

Author SHA1 Message Date
Dav999-v
cc6b00a711 Add setfont scripting command
The <font> in the level file is basically the starting font, but it can
be changed at any time via scripting.
2023-02-13 23:27:00 -08:00
Dav999-v
7db0e73109 Allow levels to select a font via XML, show correct font in levels list
There still needs to be a menu for selecting a font, but it can now be
loaded and saved correctly in the XML!
2023-02-13 23:27:00 -08:00
Dav999-v
8d5e3b1a8a Improve level metadata display and font handling
- If the level font is higher than 10 pixels, the third description
  line (Desc3) is disabled and unavailable. CJK languages require less
  characters to convey the same message (140 characters caused people
  to cram tweets in all languages except CJK) and this gives us enough
  room in the levels list without having to cram the metadata even more
  than it already was or showing less levels per page.
- The "Untitled Level" and "by Unknown" now selectively show up in the
  interface font instead of the level font.
2023-02-13 23:27:00 -08:00
Dav999-v
653eee505b Clean up Font.h, move structs into Font.cpp
None of the structs in the new font system ended up being "publicly"
accessible, they were all treated as implementation details for
Font.cpp to use, so these structs are now fully defined in Font.cpp
only.
2023-02-13 23:27:00 -08:00
Dav999-v
d2461c90ce Completely remove Graphics::bigprint
The last two deprecated functions are:
- Graphics::Print
- Graphics::PrintWrap

These are used a lot, but they're relatively easy to replace, since the
only flag I probably have to immediately worry about is PR_CEN. I do
often need to add PR_FONT_* flags but I don't need to add any
PR_2X/PR_3X/PR_4X anymore.
2023-02-13 23:27:00 -08:00
Dav999-v
ddaabb3efe Completely remove Graphics::bprint
Only three deprecated functions remain:
- Graphics::Print
- Graphics::PrintWrap
- Graphics::bigprint

I also fixed multiline transparent textboxes having their outlines
overlap the text itself, and fixed textboxclass::padtowidth assuming
glyph widths of 8 (it made the hints at the start of intermission 1
run offscreen for example)
2023-02-13 23:27:00 -08:00
Dav999-v
d784f7f61a Completely remove Graphics::PrintAlpha and Graphics::bprintalpha
Only four deprecated functions remain:
- Graphics::Print
- Graphics::PrintWrap
- Graphics::bigprint
- Graphics::bprint

Graphics::bprint is the least-used one of them, and after that, the
other functions are used a LOT, but it'll be a lot faster to go through
them, since I have less and less flags to worry about. I'll probably
start using Vim macros again like I did for loc::gettext()ing strings,
or maybe I'll automate this completely.
2023-02-13 23:27:00 -08:00
Dav999-v
9749858365 Completely remove Graphics::bigbprint, bigrprint and bigbrprint
I migrated all of them to font::print, so they can now be removed.
Six deprecated print functions left! (Of which some are used a whole
lot, it's simpler if the lesser-used ones are gone first.)
2023-02-13 23:27:00 -08:00
Dav999-v
c82e1f2902 Use PR_RIGHT for interim version info in main menu
This used some constants counting numbers of characters
(LEN_INTERIM_COMMIT and LEN_BRANCH_NAME) and even an SDL_arraysize,
all multiplied by 8, to get the length of the displayed text.
Now it just uses the new PR_RIGHT flag of font::print.

I did also force the 8x8 font for all the interim information, since
the date kinda overlapped with the menu options... And all of these
lines only show up in interim versions anyway, except for the version
number - which is left in the interface font for consistency with the
rest of the menu in non-interim versions. The inconsistency in interim
versions doesn't really matter all that much I think, it's just some
technical/debug info.
2023-02-13 23:27:00 -08:00
Dav999-v
da6be09993 Completely remove Graphics::len
I migrated all graphics.len calls over to font::len (and also migrated
prints mainly surrounding those graphics.len's) so the old len function
is now completely removed.
2023-02-13 23:27:00 -08:00
Dav999-v
a706fb249a Migrate more prints and graphics.len calls to font::
I especially focused on graphics.len and the print calls around them,
because graphics.len calls appear a bit less often, might be overlooked
when migrating print calls (thus possibly using different fonts by
accident) and are often used for some kind of right-alignment or
centering which can be changed into PR_RIGHT or PR_CEN with a different
X anyway.

Notably, I also added a new function to generate these kinds of
sliders: ....[]............

Different languages means that the slider for analogue stick
sensitivity needs to be longer to fit possibly long words for
Low/Medium/High, and then different font sizes means that the longer
slider won't fit onscreen in a language that needs a 12-wide font. So
slider_get() can take a "target width", which dynamically changes the
number of characters depending on the width of them in the interface
font.

I kinda forgot that I could force the 8x8 font instead of adapting the
characters in the slider to the font, and other ideas (like using
different characters or a more graphical progress bar) have been
brought up on Discord, so this might all change again sooner or later.
2023-02-13 23:27:00 -08:00
Dav999-v
7c55ea7832 Fix pause screen font on language screen with other language selected
If you for example have your VVVVVV set to English, have the option for
Chinese selected, and then the window loses focus, the English pause
screen would show up in the Chinese font. This is now fixed.
2023-02-13 23:27:00 -08:00
Dav999-v
df4e351b30 Use languages' fonts for options on language screen 2023-02-13 23:27:00 -08:00
Dav999-v
5dad6b38be Add language-specific font configuration
meta.xml can now have a <font> tag, which gives the name of the font
that the language needs. This will directly control the interface font
when the language is active, and will soon also control the font used
for each option on the language screen.
2023-02-13 23:27:00 -08:00
Dav999-v
dadb7f2623 Complete font::print_wrap flag handling
Also added some borders to more of the text in room name translator
mode, fixed a positioning issue if the interface font is not 8x8, and
migrated the trophy texts to font::print_wrap (including
PR_COLORGLYPH_BRI that still needed to be done)
2023-02-13 23:27:00 -08:00
Dav999-v
689d6e3e97 Print activity zone text in correct font, remove Graphics::drawtextbox
Activity zones need to be in the interface font if the message is from
the system (like Press ENTER to activate terminal, which may be in a
different language) and in the level font if it's a customized message
(setactivitytext).

Graphics::drawtextbox was counting the textbox width and height in
8x8 characters, even including the borders as characters, so it'd need
to be told what the font for the textbox is, and then probably only the
height needs to be adapted to the font and not the width because that's
adapted to the screen width... So just call Graphics::drawpixeltextbox
directly instead. It was already weird enough how actual cutscene
textboxes called Graphics::drawtextbox with x/8, y/8 before the
previous commit, (when you already have the pixel width and height!)
only to have that be a wrapper for drawpixeltextbox by doing x*8, y*8.
2023-02-13 23:27:00 -08:00
Dav999-v
48a4e19635 Migrate more prints to font::, determine font for most textboxes
Some textboxes need to be in the level font (like room names, cutscene
dialogue, etc - even in the main game), and some need to be in the
interface font (like when you collect a shiny trinket or crewmate). So
most of these textboxes now have graphics.textboxprintflags(font_flag)
as appropriate.

RoomnameTranslator.cpp is now also migrated to the new print system -
in room name translator mode, the room name is now displayed in the 8x8
font if it's untranslated and the level font if it is.
2023-02-13 23:27:00 -08:00
Dav999-v
6ca83114bc Start using level-specific font where needed, make CJK tweaks
Level text such as room names, text box content, and the contents of
the script editor need to be displayed in the level-specific font, and
tweaked to look right. This involves displaying less lines in the
script editor, making text boxes bigger, displaying some text higher
and some text lower. This is still unfinished, but it's the real start
of a migration to font::print functions!
2023-02-13 23:27:00 -08:00
Dav999-v
29a3789dec Add some more preparation for multi-font support and proper unloading
find_font_by_name() just finds the index of a given font name. This
index is supposed to be stored and reused, because the font (for a
language/level) won't be changed very often. So this function would
only run when getting the language metadata, when loading a level, etc.
2023-02-13 23:27:00 -08:00
Dav999-v
83d645c8e3 Add font containers for global and custom fonts
All global fonts and all custom fonts in a level are now loaded, and
added to their respective "vectors". The selected font is still always
as the global font.png, and the custom level font also isn't selected
yet, but it's now easier to implement that.

Also, I added FILESYSTEM_enumerateAssets, which #902 already has but I
needed it now. I also rewrote it to not use std::vector<std::string>.
That was my idea, it's also how FILESYSTEM_getLanguageCodes worked,
so for symmetry, that function is getting changed as well.
2023-02-13 23:27:00 -08:00
Dav999-v
22dcc29d45 Handle more flags in print and len functions
The font::len function now handles the printing scale, so it can
immediately return the scaled length instead of having the caller
calculate it. The print function now handles CJK low/high flags and
vertically centers CJK text by default (instead of letting it stick
out on the bottom).
2023-02-13 23:27:00 -08:00
Dav999-v
159c70dade Move wordwrapping functions and len to Font.cpp/font:: namespace
The following functions were moved directly:
- next_wrap
- next_wrap_s
- string_wordwrap
- string_wordwrap_balanced
- string_unwordwrap

These ones will probably still need get a flags argument, except for
string_unwordwrap (since they need to know what font we're talking
about.

The implementation of graphics.len has also been moved to Font.cpp,
but graphics.len still exists for now and is deprecated.
2023-02-13 23:27:00 -08:00
Dav999-v
1d8494db8d Add initial version of font::print_wrap
graphics.PrintWrap is now also deprecated. An advantage of the new
version (with flags) is that it'll be possible to do things like put
a border around wrapped text, wrap text at larger scales, etc, but
these things don't work perfectly yet.

This commit also has some other fixes, like the default advance of
6 pixels for characters 0x00-0x1F in 8x8 fonts.
2023-02-13 23:27:00 -08:00
Dav999-v
0475539075 Implement first font::print function, fix most fading of colored glyphs
There has always been a mess of different print functions that all had
slightly different specifics and called each other:

Print(x, y, text, r, g, b, cen)
    nothing special here, just does what the arguments say

PrintAlpha(x, y, text, r, g, b, a, cen)
    just Print but with an alpha argument

PrintWrap(x, y, text, r, g, b, cen, linespacing, maxwidth)
    added for wordwrapping, heavily used now

bprint(x, y, text, r, g, b, cen)
    prints an outline, then just PrintAlpha

bprintalpha(x, y, text, r, g, b, a, cen)
    just bprint but with an alpha argument

bigprint(x, y, text, r, g, b, cen, sc)
    nothing special here, just does what the arguments say

bigbprint(x, y, text, r, g, b, cen, sc)
    prints an outline, then just bigprint

bigrprint(x, y, text, r, g, b, cen, sc)
    right-aligns text, unless cen is given in which case it just
    centers text like other functions already do?

bigbrprint(x, y, text, r, g, b, cen, sc)
    prints an outline, then just bigrprint

We need even more specifics with the new font system: we need to be
able to specify whether CJK characters should be vertically centered or
stick out on the top/bottom, and we sometimes need to pass in
brightness variables for colored glyphs. And text printing functions
now fit better in Font.cpp anyway. So there's now a big overhaul of
print functions: all these functions will be replaced by font::print
and font::print_wrap (the former of which now exists). These take flags
as their first argument, which can be 0 for a basic left-aligned print,
PR_CEN for centered text (set X to -1!!!) PR_BOR for a border (instead
of functions like bprint and bigbprint), PR_2X, PR_3X etc for scaling,
and these can be combined with |.

Some text, for example [Press ESC to return to editor], fades in/out
using the alpha value, which is passed to the print function. In some
other places (like Press ENTER to teleport, textboxes, trophy text...)
text can fade in or out by direct changes to the RGB values. This means
regular color-adjusted white text can change color, but colored button
glyphs can't, since there's no way to know in the print system what the
maximum RGB values of a specific textbox are supposed to be, so the
only thing it can do is draw the button glyphs at full brightness,
which looks bad. Therefore, you can now also pass in the brightness
value via the flags, with PR_COLORGLYPH_BRI(255).
2023-02-13 23:27:00 -08:00
Dav999-v
9879fb2809 Draw outlines for colored characters correctly
If we try to draw a colored character, and the color is fully black,
it means we're drawing the outline.
2023-02-13 23:27:00 -08:00
Dav999-v
794f081530 Start rewrite of font system
This is still a work in progress, but the existing font system has been
removed and replaced by a new one, in Font.cpp.

Design goals of the new font system include supporting colored button
glyphs, different fonts for different languages, and larger fonts than
8x8 for Chinese, Japanese and Korean, while being able to support their
30000+ characters without hiccups, slowdowns or high memory usage. And
to have more flexibility with fonts in general. Plus, Graphics.cpp was
long enough as-is, so it's good to have a dedicated file for font
storage.

The old font system worked with a std::vector<SDL_Surface*> to store
8x8 surfaces for each character, and a std::map<int,int> to store
mappings between codepoints and vector indexes.

The new system has a per-font collection of pages for every block of
0x1000 (4096) codepoints, that may be allocated as needed. A glyph on
a page contains the index of the glyph in the image (giving its
coordinates), the advance (how much the cursor should advance, so the
width of that glyph) and some flags which would be at least whether the
glyph exists and whether it is colored.

Most of the *new* features aren't implemented yet; it's currently
hardcoded to the regular 8x8 font.png, but it should be functionally
equivalent to the previous behavior. The only thing that doesn't really
work yet is level-specific font.png, but that'll be supported again
soon enough.

This commit also adds fontmeta (xml) support.

Since the fonts folder is mounted at graphics/, there are two main
options for recognizing non-font.png fonts: the font files have to be
prefixed with font (or font_) or some special file extension is
involved to signal what files are fonts. I always had a font.xml in
mind (so font_cn.xml, font_ja.xml, etc) but if there's ever gonna be
a need for further xml files inside the graphics folder, we have a
problem. So I named them .fontmeta instead.

A .fontmeta file looks somewhat like this:

<?xml version="1.0" encoding="UTF-8"?>
<font_metadata>
    <width>12</width>
    <height>12</height>
    <white_teeth>1</white_teeth>
    <chars>
        <range start="0x20" end="0x7E"/>
        <range start="0x80" end="0x80"/>
        <range start="0xA0" end="0xDF"/>
        <range start="0x250" end="0x2A8"/>
        <range start="0x2AD" end="0x2AD"/>
        <range start="0x2C7" end="0x2C7"/>
        <range start="0x2C9" end="0x2CB"/>
        ...
    </chars>
    <special>
        <range start="0x00" end="0x1F" advance="6"/>
        <range start="0x61" end="0x66" color="1"/>
        <range start="0x63" end="0x63" color="0"/>
    </special>
</font_metadata>

The <chars> tag can be used to specify characters instead of in a .txt.
The original idea was to just always use the existing .txt system for
specifying the font charset, and only use the XML for the other stuff
that the .txt doesn't cover. However, it's probably better to keep it
simple if possible - having to only have a .png and a .fontmeta seems
simpler than having the data spread out over three files. And a major
advantage: Chinese fonts can have about 30000 characters! It's more
efficient to be able to have a tag saying "now there's 20902 characters
starting at U+4E00" than to include them all in a text file and having
to UTF-8 decode every single one of them.

If a font.txt exists, it takes priority over the <chars> tag, and in
that case, there's no reason to include the <chars> tag in the XML.
But font.txt has to be in the same directory as font.png, otherwise it
is rejected. Same for font.fontmeta. If neither font.txt nor <chars>
exist, then the font is seen as a 2.2-and-below-style ASCII font.

In <special>: advance is the number of pixels the cursor advances after
drawing the character (so the width of the character, without affecting
the grid in the source image), color is whether the character should
have its original colors retained when printed (for button glyphs).

As for <white_teeth>:

The renderer PR has replaced draw-time whitening of sprites/etc
(using BlitSurfaceColoured) by load-time whitening of entire images
(using LoadImage with TEX_WHITE as an argument).

This means we have a problem: fonts have always had their glyphs
whitened at printing time, and since I'm adding support for colored
button glyphs, I changed it so glyphs would sometimes not be whitened.
But if we can't whiten at print time, then we'd need to whiten at load
time, and if we whiten the entire font, any colored glyphs will get
destroyed too. If you whiten the image selectively, well, we need more
code to target specific squares in the image, and it's kind of a waste
when you need to whiten 30000 12x12 Chinese characters when you're only
going to need a handful, but you don't know which ones.

The solution: Whitening fonts is useless if all the non-colored glyphs
are already white, so we don't need to do it anyway! However, any
existing fonts that have non-white glyphs (and I know of at least one
level like that) will still need to be whitened. So there is now a
font property <white_teeth> that can be specified in the fontmeta,
which indicates that the font is already pre-whitened. If not
specified, traditional whitening behavior will be used, and the font
cannot use colored glyphs.
2023-02-13 23:27:00 -08:00
Misa
b29f3e2fae Silence various warnings in builds removing content
The MAKEANDPLAY, NO_CUSTOM_LEVELS, and NO_EDITOR defines remove content
or features. However, they then raise several warnings because of some
cases, functions, or variables that end up not being used.

This silences them by using the UNUSED macro, or by adding a default
catch-all case if the define is defined (so unhandled cases will still
raise warnings in a build that doesn't have these defines).
2023-02-04 00:14:04 -08:00
Misa
113fbb0fdb Add build type to -version
This adds the build type in brackets in `-version` output after e.g.
"VVVVVV v2.4". The build type is MAKEANDPLAY, NO_CUSTOM_LEVELS, or
NO_EDITOR (which are not necessarily mutually exclusive).

This is appended on to the end of the first line so as to not break
Ved's existing `-version` check which only checks if the beginning of
STDOUT is "VVVVVV" followed by any version number.
2023-02-02 13:10:25 -08:00
Misa
6665f4f8f6 Prioritize loading processed script names
This makes it so that whenever the game loads a script as directed by a
script command, it will first try to load the script from the processed
argument, and if that fails only then will it try to load the script
from the raw argument.

This fixes a regression reported by Dav999 in the custom level "Vungeon"
created by Dynaboom, where a script `ifflag`s to `aselectP1.1` even
though the actual script name is `aselectp1.1`. In 2.3, it would
lowercase `aselectP1.1` and load the script properly, but previous to
this commit it would try to load the script with a capital name and then
fail.
2023-01-31 20:09:44 -08:00
Misa
fbe613ce5c Abort and print error if window/renderer cannot be created
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.
2023-01-28 23:44:07 -08:00
Misa
2525017990 Set minimum window size (to 320 x 240)
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.
2023-01-28 23:37:24 -08:00
Misa
fbc9b3ddd7 Use SDL_Point instead of rolling our own point struct
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`.
2023-01-28 23:32:14 -08:00
Misa
c7098f84e5 Fix alphabetical ordering of includes in preloader.cpp
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.
2023-01-28 23:29:04 -08:00
AllyTally
d9859d4a98 Fix screenshake not clearing the gameplay cache 2023-01-28 17:48:15 -08:00
AllyTally
19b2a317f1 Move from surfaces to the SDL render system
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
2023-01-28 14:36:28 -08:00
AllyTally
556e3a110a Fix small bug with map being off in custom levels
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.
2023-01-26 12:23:23 -08:00
Misa
172e3a8985 Add branch name to window title in brackets
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.
2023-01-16 12:59:48 -08:00
Misa
19a83853b8 Default width and height settings to 640x480
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.
2023-01-16 12:45:40 -08:00
Misa
d2b6fb2d06 Add branch name to interim version information
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.
2023-01-07 19:18:28 -08:00
Misa
f35618999f Allocate to the size of source surface instead
Otherwise it will slow down since the destination surface is usually
pretty big.
2023-01-05 12:23:34 -08:00
Misa
2e03f2b03d Re-add temporary allocation in BlitSurfaceTransform
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.
2023-01-04 15:33:56 -08:00
Misa
91339c77db Refactor BlitSurfaceColoured and BlitSurfaceTinted to not allocate
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.
2023-01-02 18:01:42 -08:00
Misa
e5d32c653b Rename tempBuffer to menuoffbuffer
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.
2023-01-02 11:19:08 -08:00
Misa
0a51141720 Use named constants in Graphics::create_buffers
I'm gonna be doing work on these and I took the opportunity to clean up
the code style a bit.
2023-01-02 11:17:02 -08:00
Misa
38c3b4ab41 Move warpfcol, warpbcol, and warprect off of Graphics
These are all temporary variables only used when drawing the all-sides
warp background.

warpskip isn't though, it's a persistent variable.
2023-01-02 11:16:03 -08:00
Misa
b0ca322b3f Use SDL_GetRGBA and SDL_MapRGBA to read and draw pixels
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.
2023-01-02 10:44:35 -08:00
Misa
8dc088896f Axe Graphics::ct and Graphics::setcolreal
`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.
2023-01-01 20:16:08 -08:00
Misa
351a022ebd Use SDL_Color for colors instead of colourTransform
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.
2023-01-01 16:36:43 -08:00
Misa
f24265f0fb Fix up temporary variables being in topmost scope and bad style
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.
2022-12-31 20:46:01 -08:00
Misa
5a6bc8bb9b De-duplicate room tile drawing code in editor
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.
2022-12-31 20:45:56 -08:00
Dav999-v
2f770e9b5a Use setstate(n)/incstate()/setstatedelay(n) in localization changes
This mirrors PR #917.
2022-12-31 20:04:56 -08:00
Dav999-v
2b84384606 Replace all localization SDL_free with VVV_free
This mirrors a926ce9851 upstream, which
replaces all other SDL_free calls.
2022-12-31 20:04:56 -08:00
Dav999-v
3937a12a85 Add cutscene test menu
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.
2022-12-31 20:04:56 -08:00
Dav999-v
7aec2c2242 Remove "COPY TILES" strings
This feature was never implemented, so these strings are making
translators wonder where to find them so they can be tested.
2022-12-31 20:04:56 -08:00
Dav999-v
6a1ddad8f8 Add cases for intermission replay options, button fillers in editor
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.
2022-12-31 20:04:56 -08:00
Dav999-v
795bdf886b Add support for string cases in strings.xml (gendered Rescued/Missing)
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.
2022-12-31 20:04:56 -08:00
Dav999-v
88c8ad5a57 Add per-area untranslated roomname counters
This makes it easy from the "explore game" menu to see which levels
still have untranslated room names and how many.
2022-12-31 20:04:56 -08:00
Dav999-v
80b9bcf0dd Add level exploring menu for translators
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.
2022-12-31 20:04:56 -08:00
Dav999-v
34cb42a19f Add Ctrl+X for roomname translator mode
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
2022-12-31 20:04:56 -08:00
Dav999-v
df76145314 Make some hardcoded room names (and some special ones) translatable
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
2022-12-31 20:04:56 -08:00
Dav999-v
b548783df2 preloader.cpp: make loading screen translatable
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
2022-12-31 20:04:56 -08:00
Dav999-v
56f812a7e9 main.cpp: make pause screen translatable
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
93a3c40c39 UtilityClass.cpp: make time formats and numbers translatable
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
2022-12-31 20:04:56 -08:00
Dav999-v
70a6cf407c Script.cpp: make whole file translatable (except for a Welcome Aboard)
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
3203f99938 Render.cpp: make remaining strings translatable
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
949f0fa2e2 Render.cpp: make maprender translatable
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
52e847d5c1 Render.cpp: make titlerender and gamecompleterender translatable
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
17c11f7e6c Render.cpp: make gamerender translatable
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
0c9b54f819 Render.cpp: make menurender translatable
This mainly adds loc::gettext calls for all the menu titles and
explanations. It also redesigns the time trial screen.

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
2022-12-31 20:04:56 -08:00
Dav999-v
45b564b4fb Graphics.cpp: make whole file translatable
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
e90cc86a3c Game.cpp: make remaining strings translatable except gethardestroom
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
e96a0344e7 Game.cpp: Make Game::updatestate translatable
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
713fc00034 Game.cpp: make menu options (in Game::createmenu) translatable
This mainly adds loc::gettext calls for menu option labels.

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
2022-12-31 20:04:56 -08:00
Dav999-v
1e45e263f5 FileSystemUtils.cpp: make translatable
setLevelDirError was changed from snprintf-style to VFormat, but it's
only used in that file so...

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
2022-12-31 20:04:56 -08:00
Dav999-v
c142b3bb3b Entity.cpp: make all activity prompts translatable
This adds loc::gettext for all "Press {button} to explode" and friends,
and also changes the interact_prompt function in Render.cpp to expect
{button} instead of %s.

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
2022-12-31 20:04:56 -08:00
Dav999-v
2210863e73 Editor.cpp: make remaining strings translatable
The affected functions are:
- editormenuactionpress
- editorinput
- editorclass::switch_tileset
- editorclass::switch_tilecol
- editorclass::switch_enemy
- editorclass::switch_warpdir

This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
17f246912d Editor.cpp: make editorrender translatable
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
d09cab2a38 Editor.cpp: make editormenurender translatable
This mainly adds loc::gettext calls.

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
2022-12-31 20:04:56 -08:00
Dav999-v
1d46e17286 Add textcase(n) commands to scripts
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
2022-12-31 20:04:56 -08:00
Dav999-v
1ead8885ba Use loc::toupper_ch instead of SDL_toupper in VFormat
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
2022-12-31 20:04:56 -08:00
Dav999-v
7ffbf0b115 Use UTF-8 characters for names in credits instead of {|}~
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
2022-12-31 20:04:56 -08:00
Dav999-v
ec611ffa9d Add localization "foundation" (many code changes)
This commit adds most of the code changes necessary for making the game
translatable, but does not yet "unhardcode" nearly all of the strings
(except in a few cases where it was hard to separate added
loc::gettexts from foundational code changes, or all the localization-
related menus which were also added by this 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
2022-12-31 20:04:56 -08:00
Dav999-v
35d92e8e64 Add RoomnameTranslator.cpp/h (not compiled yet)
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
2022-12-31 20:04:56 -08:00
Dav999-v
97d905e8bf Add LocalizationMaint.cpp/h (not compiled yet)
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
2022-12-31 20:04:56 -08:00
Dav999-v
8e33815c97 Add LocalizationStorage.cpp/h (not compiled yet)
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
2022-12-31 20:04:56 -08:00
Dav999-v
98742ed852 Add Localization.cpp/h (not compiled yet)
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
2022-12-31 20:04:56 -08:00
Dav999-v
72f030fd8e Support underscore (_) in VFormat arg name
This is needed for the limits check in the translator menu.

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
2022-12-31 20:04:56 -08:00
Dav999-v
f8fd51fc95 Indicate what special roomnames are in the levels
This just adds booleans roomname_special to the level classes in
preparation for the localization system to use them.

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
2022-12-31 20:04:56 -08:00
Dav999-v
0ed2cb1bc0 Add Textbook
A relevant paragraph copied from the original commit history:

The idea is that we store all strings somewhere managed, and then the
hashmap only needs pointers to those strings. For storing strings, I
created a `Textbook` structure, which consists of one or more 50 KB
"pages" (allocated as needed) on which you can simply write strings in
both languages back-to-back with `textbook_store(textbook, text)` and
get pointers to each of them. (I was originally going to just use one
big buffer and realloc to double the size when filled up, but then the
hashmap would be full of dangling pointers...) When needed, like when
switching to a different language, an entire textbook can be freed at
once.

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
2022-12-31 20:04:56 -08:00
Misa
aa2cf3ab4b Use _SDL_HAS_BUILTIN
I think this is because if you both check that __has_builtin is defined
and use it in the same 'if' preprocessor statement, it can error because
there's no equivalent to short-circuiting in preprocessor statements.
_SDL_HAS_BUILTIN should be safer.
2022-12-29 16:13:54 -08:00
Misa
3758d61fe9 Axe scriptclass::resetgametomenu
This creates the game over screen for dying in No Death Mode. It's three
lines long and it's only called once. There's no reason it has to be a
separate function. From the name it sounds like it was meant to be a
generic function but it's anything but that. So just inline it in to
where it's called.
2022-12-29 15:51:16 -08:00
Misa
593641ce82 Always destroy and create new player in startgamemode
This fixes a bug where players could flip in mid-air at the start of
custom levels whose start points were in mid-air, because
onground/onroof were not being reset. This could also be done when
loading in to a save with a checkpoint in mid-air. All that's required
is to exit the game while standing on a surface (or otherwise having a
nonzero onground/onroof).

This reminded me that there were other variables on the player entity
persisting through that made loading in to a level not have a totally
clean slate, such as walkingframe (which could affect sequencing
individual TASes together into one TAS), so it's better to just destroy
the player entity and recreate it.

Except some attributes still have to be persisted for 2.2 and 2.0
glitchrunner mode. But it's better that this is done via a whitelist
rather than a blacklist.

The player duplicate removal code in hardreset is mostly redundant now
(except for some very unlikely corner cases), but there's nothing wrong
with having redundant code as long as it's not harmful. I had a
paragraph here justifying why it could be removed but decided it was
simpler to just keep it.
2022-12-29 15:51:16 -08:00
Misa
97deda2675 Add debug print to unlockAchievement
This print is useful to know if an achievement (one that's not already
unlocked) would actually be unlocked in an end user environment, while
running the game in a dev environment.

Also fixed up the style of the function because it was definitely
inconsistent with the surrounding code.
2022-12-29 15:51:14 -08:00
Misa
69e9a32e1b Refactor scriptclass::startgamemode
This overhauls scriptclass::gamemode massively.

The first change is that it now uses an enum, and enforces using that
enum via using its type instead of an int. This is because whenever
you're reading any calls to startgamemode, you have no idea what magic
number actually corresponds to what unless you read startgamemode
itself. And when you do read it, not every case is commented adequately,
so you'd have to do more work to figure out what each case is. With the
enum, it's obvious and self-evident, and that also removes the need for
all the comments in the function too. Some math is still done on mode
variables (to simplify time trial code), but it's okay, we can just cast
between int and the enum as needed.

The second is that common code is now de-duplicated. There was a lot of
code that every case does, such as calling hardreset, setting Flip Mode,
resetting the player, calling gotoroom and so on.

Now some code may be duplicated between cases, so I've tried to group up
similar cases where possible (most notable example is grouping up the
main game and No Death Mode cases together). But some code still might
be duplicated in the end. Which is okay - I could've tried to
de-duplicate it further but that just results in logic relevant to a
specific case that's located far from the actual case itself. It's much
better to leave things like setting fademode or loading scripts in the
case itself.

This also fixes a bug since 2.3 where playing No Death Mode (and never
opening and closing the options menu) and beating it would also give you
the Flip Mode trophy, since turning on the flag to invalidate Flip Mode
in startgamemode only happened for the main game cases and in previous
versions the game relied upon this flag being set when using a
teleporter for some reason (which I removed in 2.3). Now instead of
specifying it per case, I just do a !map.custommode check instead so it
covers every single case at once.
2022-12-29 14:01:36 -08:00
Misa
6768a33f2d Reset savex, savey, and savegc in hardreset
While refactoring scriptclass::startgamemode, I noticed that these
variables weren't being reset. Fortunately, this doesn't seem to have
affected anything because they get overwritten one way or another in
startgamemode. But it's good just to be defensive and reset them anyway.

They are not reset in 2.2 or 2.0 glitchrunner mode because dying during
exiting to the menu is needed for credits warp, and that means the
checkpoint position needs to be maintained through.
2022-12-29 12:21:18 -08:00
Misa
7a48d0a53e Add Unreachable.h
This is to indicate when a code path is absolutely, for certain, 100%
unreachable. Useful as the default case inside a case-switch that is for
sure 100% exhaustive because it's inside the case of another case-switch
(and the default case is there to suppress compiler warnings about the
case-switch not being exhaustive), which is a situation coming up in my
scriptclass::startgamemode refactor.

It does this by deliberately invoking undefined behavior, either using a
compiler builtin that does the same thing or being a noreturn function
that returns. (And undefined behavior is not undefined behavior if it is
not executed in a code path, otherwise all NULL checks would be useless
because it'd dereference something that could be NULL in another code
path.)
2022-12-29 12:10:25 -08:00
Misa
c177f456f4 Unexport getgridpoint
It's a method of entityclass even though it doesn't use anything on the
class and it's not used outside of Entity.cpp.
2022-12-11 12:40:45 -08:00
Misa
7347975cc5 Unexport yline
It's a method of entityclass, even though it doesn't use anything on the
class and it's not used outside of Entity.cpp.
2022-12-11 12:37:55 -08:00
Misa
52e29b68bc Unexport gridmatch
It's a method of entityclass, but it has no reason to be because it
doesn't use anything on entityclass and it's not used outside of
Entity.cpp.
2022-12-11 12:37:43 -08:00
Misa
ec520838df Retype testwallsy's tx and ty to be ints, not floats
I have no idea why they were floats in the first place. They are
coordinates, and coordinates are integer positions in this game. They
get converted to float only to be explicitly `static_cast`ed back to
ints in `testwallsy`.
2022-12-11 11:00:20 -08:00
Misa
12820473db Retype dr to be int instead of float
This variable passes along the rule of the entity, which is an int. No
idea why it was converted to a float. Thankfully this is only used for
an unused block type, so it doesn't really matter.
2022-12-11 10:55:25 -08:00
Misa
babcadc99f Remove unnecessary consts from Entity.h
`const`s don't mean anything in a prototype declaration unless it's a
pointer or a reference. Remove them to make the header a bit more
readable.
2022-12-11 10:52:12 -08:00
Ally
3e0954b9b8 Update desktop_version/src/Game.cpp
Co-authored-by: Misa Elizabeth Kai <infoteddy@infoteddy.info>
2022-12-07 17:40:15 -08:00
Ally
85b54dac17 Fix accidental replacement 2022-12-07 17:40:15 -08:00
AllyTally
f659eca818 remove two-argument setstate 2022-12-07 17:40:15 -08:00
AllyTally
af3e5be09b Convert more statedelay assignments to function call 2022-12-07 17:40:15 -08:00
AllyTally
d6c38f8d5c Small fixes 2022-12-07 17:40:15 -08:00
Ally
e4d02feffa Apply suggestions from code review
Co-authored-by: Misa Elizabeth Kai <infoteddy@infoteddy.info>
2022-12-07 17:40:15 -08:00
AllyTally
86604c5748 Also lock statedelay 2022-12-07 17:40:15 -08:00
AllyTally
4b66920865 state locking 2022-12-07 17:40:15 -08:00
Misa
43bebecf3b Make room names own their own memory
This makes it so room names are no longer pointers to someone else's
memory, and instead to set them you use `mapclass::setroomname`. If the
string is short enough to fit in a static, no-alloc buffer, then it gets
copied there. Otherwise, a new heap allocation is made that duplicates
the string, and the new pointer is used instead.

This makes it possible for room names to contain arbitrary data whose
origin is temporary (e.g. from a script command that could be added in
the future).
2022-11-30 22:53:36 -08:00
Misa
a926ce9851 Replace all free calls with VVV_free[func]
This replaces all calls to SDL_free with a new macro, VVV_free, that
nulls the pointer afterwards. This mitigates any use-after-frees and
also completely eliminates double-frees. The same is done for any
function to free specific objects such as SDL_FreeSurface, with the
VVV_freefunc macro.

No exceptions for any of these calls, even if the pointer is discarded
or zeroed afterwards anyway. Better safe than sorry.

This is a macro rather than a function that takes in a
pointer-to-pointer because such a function would have type issues that
require casting and that's just not safe.

Even though SDL_free and other SDL functions already check for NULL, the
macro has a NULL check for other functions that don't. For example,
FAudioVoice_DestroyVoice does not check for NULL.

FILESYSTEM_freeMemory has been axed in favor of VVV_free because it
functionally does the same thing except for `unsigned char*` only.
2022-11-30 22:50:08 -08:00
Misa
6e583d949b Don't set legends if out of bounds
Trinket and teleporter legends would be drawn even if they were out of
bounds. Trinket legends in particular were easy to do because you can
just place a trinket in a custom level and resize the map to not include
the room of the trinket.

Now, there are checks added so they won't be added if they are out of
bounds. This is in line with the fact that, since 2.3, if a trinket
exists outside of the map in custom levels, it won't count towards the
number of trinkets.
2022-11-30 13:42:10 -08:00
Misa
de38b6b55c Unify all queries to map size to map.getwidth and map.getheight
It's becoming pretty clear that the size of the map is important enough
to be queried a lot, but each time it's something like `map.custommode ?
map.customwidth : 20` and `map.custommode ? map.customheight : 20` which
is not ideal because of copy-pasting.

Furthermore, even `map.customwidth` and `map.customheight` are just
duplicates of `cl.mapwidth` and `cl.mapheight`, which are only set in
`customlevelclass::generatecustomminimap`. This is a bit annoying if you
want to, say, add checks that depend on the width and height of the
custom map in `mapclass::initcustommapdata`, but `map.customwidth` and
`map.customheight` are out of date because `generatecustomminimap`
hasn't been called yet. And doing the ternary there requires a `#ifndef
NO_CUSTOM_LEVELS` to reference `cl.mapwidth` and `cl.mapheight` which is
just awful.

So I'm axing `map.customwidth` and `map.customheight`, and I'm axing all
the ternaries that are duplicating the source of truth in
`MapRenderData`. Instead, there will just be one function to call for
the width and height, `mapclass::getwidth` and `mapclass::getheight`,
and everyone can simply call those without needing to do ternaries or
duplication.
2022-11-30 13:35:14 -08:00
Misa
d183ea6367 Clean up the code style of generatecustomminimap
The existing code was allergic to putting spaces between tokens, and had
some minor code duplication that I took the time to clean up as well.
The logic should be easier to follow now that the for-loops are no
longer duplicated for each of the map zoom levels.

I tested this by temporarily disabling map fog entirely and going
through a couple different custom levels to compare their minimap with
the existing code. These were A New Dimension and 333333 for 1x, Golden
Spiral and VVVV 4k for 2x, and VVVVVV is NP-Hard for 4x. There was no
difference in the output, not even a single pixel.
2022-11-30 13:25:28 -08:00
AllyTally
88142ea839 Fix legend positions 2022-11-30 12:33:56 -08:00
Ally
cbfef2eb53 Apply suggestions from code review
Co-authored-by: Misa Elizabeth Kai <infoteddy@infoteddy.info>
2022-11-30 12:33:56 -08:00
AllyTally
c16fe04519 Deduplicate map render data calcuations 2022-11-30 12:33:56 -08:00
AllyTally
7cdfe6e9a3 Move generatecustomminimap to case 21 2022-11-30 12:33:56 -08:00
Ally
0bf1e1494b Apply suggestions from code review
Co-authored-by: Misa Elizabeth Kai <infoteddy@infoteddy.info>
2022-11-30 12:33:56 -08:00
AllyTally
f7bbf4670c Fix copy-paste error 2022-11-30 12:33:56 -08:00
AllyTally
1837fe8abf Remove accidental comment change 2022-11-30 12:33:56 -08:00
AllyTally
1cf8f1503a Generate the minimap when entering editor playtesting 2022-11-30 12:33:56 -08:00
AllyTally
ca506a7bb5 Fix a missing mapzoom multiplication 2022-11-30 12:33:56 -08:00
AllyTally
f2e2ae591a dedupe another piece of code 2022-11-30 12:33:56 -08:00
AllyTally
a5939a888a deduplicate a lot of map code 2022-11-30 12:33:56 -08:00
Misa
145355e603 Add fraZ0R to the list of contributors
fraZ0R's PR #915 was merged.
2022-11-30 11:22:50 -08:00
fraZ0R
63b8c71264 Actually fix #913 oops 2022-11-30 11:21:37 -08:00
AllyTally
ef6a2886e9 Fix #892 2022-11-25 13:10:16 -08:00
Misa
86d90a1296 Add color support to Windows console output, properly
This adds color support to the output of the console on Windows. Now if
you're using Windows 10 build 1511 or later (I think it's build 1511
anyway; they added more VT sequence support in later versions), you will
see colors by default. This isn't due to Windows helping in any way;
this commit has to specifically enable it with SetConsoleMode() because
by default, Windows won't enable color support unless we enable it. (Or
if it's enabled in the registry, but having to go through the registry
to enable basic shit like that is completely fucking stupid.)

I tested this in my Windows 10 virtual machine and it's completely
working.
2022-11-14 21:57:01 -08:00
Misa
40dd2571c2 Add error checks to freopen calls on Windows
I don't know if they could fail but it's still good to attempt to print
_something_ if they do end up failing.
2022-11-14 21:56:02 -08:00
Misa
0a181d8c3d Separate color being supported from being enabled
Previously, we were using `color_enabled` to mean both that the color
was supported and that it was enabled by the user (which it is enabled
by default). But this logic doesn't work well if the color check
function is called again and ends up enabling color after the user
disabled it. To fix this, just separate the two so the user controls one
`color_supported` variable and the `color_enabled` variable is separate.
Check both of them in order to print color, of course.
2022-11-14 21:51:53 -08:00
Misa
3fc23f2b2c Add -console option on Windows
This adds the `-console` command-line option (for Win32 only) so the
game can spawn an attached console window which will contain all console
output.

This is to make it easier for people to debug on Windows systems.
Otherwise, the only way to get console output would be to either compile
the application as a console app (i.e. switch the subsystem to console)
- which is undesirable for regular users as this makes it so a console
is always spawned even when unwanted - or launch the game with shell
arguments that make it so output is redirected to a file.

As a result, color checking support is factored out of vlog_init() into
its own function, even though we don't support colors on Windows.
2022-11-14 19:40:23 -08:00
Misa
5bb3768782 Fix indentation style of #defines in Vlogging.c
This makes it so the hash is always in the first column while the rest
of the line follows normal indentation rules.
2022-11-14 19:40:23 -08:00
Misa
9def8fd704 Seed with frame counter instead of SDL_GetTicks
Using SDL_GetTicks() to seed the Gravitron RNG caused many
reproducibility issues while syncing https://tasvideos.org/7575S . To
fix this, add a frame counter, which is a number that is incremented
every frame and never resets, and use it instead.

If someone needs to switch back to SDL_GetTicks() for old TASes, then
provide the -seed-use-sdl-getticks command-line option for them.
2022-11-14 14:10:24 -08:00
Misa
e6a3df6ca6 Move xoshiro_seed debug print to top
In its previous location, it would only print the value of `s` after it
had been mutated by `splitmix32` four times, and it doesn't get used
after that, so the print isn't very useful.

Mixing code and declarations here is fine because starting from a few
months ago, we compile with C99 and if we ever need to compile with C90
then it's trivial to add braces surrounding the declarations.
2022-11-14 13:14:25 -08:00
Misa
876362365b Ignore comments of tracks with a negative loop comment
If a music track has a loop comment with a negative value, ignore all
comments of the track. This is just to prevent any weirdness from
happening as it's safer to just let the track loop improperly. Also log
to the console to let users know.

This is the same thing that SDL_mixer does now:
libsdl-org/SDL_mixer@e819489459

This commit happened as a result of discussion on the VVVVVV Discord
server about SDL_mixer 2.0.4 behavior with weird loop comment values
(e.g. octal input with leading zeroes). This is simply updating the code
to be in line with what newer versions of SDL_mixer do.
2022-11-13 19:51:56 -08:00
Misa
fb13e652fa Check for SDL_strdup failure in parseComments
Just in case it happens. Comments aren't really important to the game
(at worst a track will just loop in the wrong place) so it's fine to
carry on here and ignore all comments if this happens.
2022-11-13 19:41:32 -08:00
Misa
27e04e9dbf Fix up style in parseComments
This does the following:

- Wrap lines that are too long (around 80 columns)
- Place the asterisk with the type instead of the variable name
2022-11-13 19:31:01 -08:00
Misa
6dd9200503 Fix up style in _Mix_ParseTime
This does the following:

- Const-qualify variables if they are not modified
- Place each statement onto their own separate lines
- Place the asterisk with the type instead of the variable name
- Combine declarations and initializations where possible
2022-11-13 19:11:50 -08:00
Misa
ac11b91540 Remove return values from vlog_* functions
They weren't ever being used, and nobody really ever uses the return
value from the printf family of functions anyway. They return how many
bytes were actually printed, but if it's less than you expected then
there's not much you can really do about them. Also the vlog_* functions
were computing them inaccurately because I only set the return value to
the return value of vprintf when there's other print functions being
called, but regardless there's no reason to have a return value here
anyway.
2022-08-29 10:48:21 -07:00
Misa
3bb3976e7e vlog_init: Fix brace style
Whoops.
2022-08-29 10:46:05 -07:00
Misa
3f9d30855f Define WIN32_LEAN_AND_MEAN when including windows.h
The hilariously-named WIN32_LEAN_AND_MEAN slims down the number of
header files included in the already-massive `windows.h`. I know people
say Moore's law and precompiled headers and all that (well, we don't use
precompiled headers), but they kinda forgot about virtual machines, and
there's no reason not to define this and slim down the number of headers
anyway.
2022-08-29 09:42:26 -07:00
Misa
aca1e8695c Remove attempt to autoenable color output on Win32
This started when I saw the warning that GetVersionExW was deprecated,
then looked it up and found StackOverflow answers saying that you should
basically detect the feature directly instead of checking the version,
which makes sense to me. Then I found that I could probably detect color
support by using GetConsoleMode and GetStdHandle. But then I asked
myself what the point was unless you could get color output directly in
the terminal, which it seems like you really can't if your app is a GUI
app. (I have no idea why Windows makes this pointless distinction
between console and GUI apps...)

I tested Command Prompt, PowerShell, Windows Terminal (which is just
PowerShell again), and even Git Bash (MINGW64), but none of them will
ever give the console output of a GUI app such as VVVVVV. The closest I
got is that Git Bash doesn't seem to detach the process, but it will
simply produce no output.

At this point I feel like it's not worth it keeping this code around if
it didn't even work in the first place, so I'm removing it. People can
always enable color by using the -forcecolor command-line argument
anyway.
2022-08-29 09:37:30 -07:00
Misa
e7e74bb8ab Add commit hash & date to -version flag output
This prints the commit hash and date in the same order as they are
printed on the title screen.
2022-08-23 00:00:39 -07:00
Misa
52124f7010 De-duplicate release version
I'm fine with putting the release version in a header file, thus
necessitating the need to recompile every file that includes it if it's
changed, simply because it's not supposed to be changed that often.

The SDL_arraysize is necessary because sometimes we'll have subreleases
(e.g. 2.4.1, 2.4.2, 2.4.3), and who knows, maybe we'll get to 2.10
someday.
2022-08-23 00:00:39 -07:00
Misa
4bf5e5e6a0 Optimize recompilation from changing commit hash
This reworks how the commit hash and date are compiled so that if
they're changed (and they're changed often), only one source file needs
to be recompiled in order to update it everywhere in the game, no matter
how many source files use the hash or date.

The commit hash and date are now declared in InterimVersion.h (and they
need `extern "C"` guards because otherwise it results in a link fail on
MSVC because MSVC is stupid).

To do this, what now happens is that upon every rebuild,
InterimVersion.in.c is processed to create InterimVersion.out.c, then
InterimVersion.out.c is compiled into its own static library that is
then linked with VVVVVV.

(Why didn't I just simply add it to the list of VVVVVV source files?
Well, doing it _now_ does nothing because at that point the horse is
already out of the barn, and the VVVVVV executable has already been
declared, so I can't modify its sources. And I can't do it before
either, because we depend on the VVVVVV executable existing to do the
interim version logic. I could probably work around this by cleverly
moving around lines, but that'd separate related logic from each other.)

And yes, the naming convention has changed. Not only did I rename
Version to InterimVersion (to clearly differentiate it from
ReleaseVersion, which I'll be adding later), I also named the files
InterimVersion.in.c and InterimVersion.out.c instead of
InterimVersion.c.in and InterimVersion.c.out. I needed to put the file
extension on the end because otherwise CMake wouldn't recognize what
kind of language it is, and I mean like yeah duh of course it doesn't,
my text editor doesn't recognize it either.
2022-08-23 00:00:38 -07:00
Misa
67d350de05 Only process tapleft/tapright if has_control
This fixes a regression where the game ignored the amount of frames you
held down a direction if you released the direction during death.

Previously, the game only checked the amount of frames you held down a
direction if you were able to control the player. If you weren't able to
control the player (e.g. during the death animation), then the number of
frames it counted didn't change. This also meant that if you were
holding a direction before you died, but released it during death, the
game wouldn't zero out the number of frames you held it.

This behavior was useful because it meant you could keep the
deceleration momentum that you normally get by holding a direction for 5
frames just by holding a direction for less than 5 frames after dying,
if you had the rest of the hold frames before you died. This behavior is
what's used in https://tasvideos.org/7575S at around frame 7200.

Unfortunately, #609 made it so that the direction hold processing
happened even if the player didn't have control, meaning that it would
zero the hold frames during the death animation in the TAS, thus
desyncing it when it performed the maneuver it relied on the extra
momentum for after Viridian respawns.

The solution here is to just add the check back in again.

Fixes #887.
2022-08-05 07:38:35 -07:00
Misa
c3750e3b34 Fix special/stdin.vvvvvv being saved to levelstats.vvv
While fixing #885, I noticed that I had a bunch of
`special/stdin.vvvvvv` entries saved in my `levelstats.vvv`. At once I
knew that the dumb `special/stdin` hack that actually checks if the
filename passed is `special/stdin` was to blame.

STDIN playtesting was first merged, I knew in the back of my mind that
it was a bit of a dumb hack, but I didn't know it would cause
consequences like showing up in `levelstats.vvv`. For now, I'll just
have to patch it, but hopefully in the future I'll remove the dumb hack
entirely. Commenting both instances of the dumb hack with instructions
to grep for it should help maintainers out.
2022-08-03 17:30:23 -07:00
Misa
550dfe676a Clear level stats vector before loading them into the vector
Otherwise this results in what is basically a memory leak that can be
triggered repeatedly by selecting "play a level" over and over again.

Fixes #885.
2022-08-03 17:21:35 -07:00
Misa
424c8c80be Add debug statements to print xoshiro RNG values
This is useful to investigate any TAS desync/reproducibility issues
relating to RNG, because even though I specifically separated the
Gravitron RNG away from other RNG and made it not dependent on the
system libc rand() function, there's still apparently some differences
in RNG execution between systems, resulting in TASVideos submission 7575
( https://tasvideos.org/7575S ) not syncing for everyone except the
author.

It seems that SDL_GetTicks(), which is used to seed the xoshiro RNG, is
not reliably consistent between systems, so in the future I will
probably replace it with a counter that is incremented each frame
starting from game startup, which is probably better.
2022-07-28 16:55:29 -07:00
Misa
058fb9fff0 Fix warning: use of non-static data member initialization
This fixes the following warnings:

desktop_version/src/Music.cpp: At global scope:
desktop_version/src/Music.cpp:240:23: warning: non-static data member initializers only available with ‘-std=c++11’ or ‘-std=gnu++11’ [-Wc++11-extensions]
  240 |     Uint8 *wav_buffer = NULL;
      |                       ^
desktop_version/src/Music.cpp:414:32: warning: non-static data member initializers only available with ‘-std=c++11’ or ‘-std=gnu++11’ [-Wc++11-extensions]
  414 |     Uint8* decoded_buf_playing = NULL;
      |                                ^
desktop_version/src/Music.cpp:415:32: warning: non-static data member initializers only available with ‘-std=c++11’ or ‘-std=gnu++11’ [-Wc++11-extensions]
  415 |     Uint8* decoded_buf_reserve = NULL;
      |                                ^
desktop_version/src/Music.cpp:416:21: warning: non-static data member initializers only available with ‘-std=c++11’ or ‘-std=gnu++11’ [-Wc++11-extensions]
  416 |     Uint8* read_buf = NULL;
      |                     ^

These warnings are because the non-static data members (i.e. data
members that will be different for each instance of a class) are being
initialized at the same time as they're being declared, which means
that's what their value will be when the class instance is initialized.

However, this is only a C++11 feature, and we don't use C++11. Luckily,
we don't need to do this, and this is in fact redundant because we
already zero out the class instance in its constructor using
SDL_zerop(). Therefore, we should remove these initializers to fix
compliance with C++03.
2022-07-28 16:48:58 -07:00
Misa
8ca53fa5d2 Remove "Lots" and "???" from number_words
Instead, for any number that isn't in the list of number words, just
return the regular Arabic numerical representation (i.e. just convert it
to string). It's better than having "Lots" or "???", neither of which
really tell you what the number actually is.
2022-07-04 23:14:44 -07:00
Dav999-v
10acd67377 Add support for start position via level XML for CLI playtesting
As already described in cc61194bed, as
well as Ved's commits from the last almost two weeks, starting VVVVVV
from Ved for playtesting could be made a lot faster by "preloading" the
game - letting it do all its asset loading in the background without
creating a window - and then waiting until the level is passed in via
stdin. There's only one problem left with this approach: VVVVVV
currently expects the starting position to be passed via command line
arguments, which isn't known yet at the time we'd like to start VVVVVV.
Therefore, this commit allows passing the starting position via the
level XML, instead of via arguments.

The extra XML looks like this, and is added next to the <Data> tag:

    <Playtest>
        <playx>214</playx>
        <playy>112</playy>
        <playrx>100</playrx>
        <playry>100</playry>
        <playgc>0</playgc>
        <playmusic>4</playmusic>
    </Playtest>

This is handled similarly to how the equivalent arguments are handled:
when the level metadata is loaded for CLI playtesting, we also try to
find this tag, and if it exists, it sets the same variables that the
arguments would have otherwise set.
2022-06-19 15:21:36 -07:00
Misa
dca3c9600c Explicitly initialize SoundTrack::volume
While this is not needed because it's a static variable, it doesn't hurt
to be explicit, especially if it's going to be refactored in the future.
2022-06-10 11:17:38 -07:00
N00byKing
c077500d16 Fix semi random volume jumps 2022-06-10 11:16:45 -07:00
Misa
f0aa1a8cae Don't treat spikes as solid for non-humanoid entities
There's always been a bit of an inconsistency in the game where enabling
invincibility would make spikes so solid that enemies and moving
platforms would treat spikes as solid and bounces off of them.

This fixes that by adding an `invincible` parameter to collision
functions, so the functions will only treat spikes as solid if that
parameter is true, and the parameter passed will only be true if it's
called for an entity that is a humanoid and invincibility mode is
enabled.

Also, for clarity, `spikecollide` is renamed to `towerspikecollide`
because it's only used for tower spikes. And as a small optimization,
`checktowerspikes` returns early if invincibility mode is enabled.
2022-06-05 20:21:51 -07:00
Misa
cc61194bed Move SDL_ShowWindow to after assets are loaded
This is a minor optimization to streamline the experience of Ved
playtesting. Previously, the user would have to wait for all the assets
to load when launching playtesting (most of the time, I suspect, is
taken up by loading music from a vvvvvvmusic blob). With this
optimization, however, the game can be launched in the background and
its assets can be loaded, while it blocks on STDIN input. During this
time, the user in Ved will be choosing where to start playtesting. After
Ved provides STDIN input, then the window will be created and appears
instantaneously.

This also fixes a related issue in which providing an invalid
playtesting level name would result in a brief window flash that gets
instantly destroyed. With this, if the level is invalid then no window
is ever shown at all.
2022-06-01 16:42:22 -07:00
Misa
a46c49c89a Add -version command-line argument
Probably should have done this earlier in 2.3, but better late than
never.

This makes it easier for third-party programs like Ved to detect what
version of the game this is.

Slightly quick-n-dirty for now, I'll de-duplicate the version number
later, and add commit hash and date if applicable.
2022-05-23 14:34:36 -07:00
Misa
e77fad5db8 Fix potential NULL dereference of images[t]
Without this, entering in-game and opening the map with missing graphics
will result in a segfault. This is because even if the image doesn't
exist, it's still pushed into the `images` std::vector as a NULL
pointer. And it segfaults because we dereference it (to get things like
their width and height). In contrast, passing them to SDL is fine
because SDL always checks for NULL first.
2022-05-17 12:07:51 -07:00
Misa
a23a4cbbd0 Improve vlog statements when PHYSFS_openRead fails
There are three different places where we call PHYSFS_openRead. This
commit makes sure all of them print a statement upon failure along with
the PhysFS reason for failure, and assigns the log level of each print
as so:

- FILESYSTEM_loadFileToMemory: Debug print (previously no
  print existed in the first place), because some files (such as
  font.txt) may or may not be needed, but if it isn't then no need to
  print and worry the user. The game will error anyway if a critical
  file like a graphics file is missing.

- FILESYSTEM_loadBinaryBlob: Debug print (previously info print),
  because sometimes it's not needed, such as mmmmmm.vvv. I remember one
  user being worried that the game printed "Unable to open file
  mmmmmm.vvv" when it's not critical unlike vvvvvvmusic.vvv (and that
  file is assumed to exist if data.zip exists anyways). Though maybe we
  should move to loose-leaf files to save on memory usage (and so we
  don't have to use special tools to modify a binary blob)...

- FILESYSTEM_loadZip: Error print. If we're calling this function, we
  really do expect the zip to be loaded, and if it fails because we
  can't open the file in the first place, then it would be good to know
  why.
2022-05-17 11:52:45 -07:00
Dav999-v
ea4302b41e Implement new string formatting system (VFormat)
This commit adds a new string formatting system to replace uses of
`SDL_snprintf` and string concatenation.

Making our own string formatting system has been briefly discussed
during the review of the localization branch, and on the VVVVVV
Discord. It's inspired by Python's format strings, but simpler.

This is primarily to benefit localization - strings will be easier to
understand (`Now using %s Tileset` → `Now using {area} Tileset`,
`"%s remain"` → `"{n_crewmates|wordy} remain"`), translators can change
the word order for their language's grammar (`%1$s` is a POSIX
extension), and this system is also less error-prone (making the format
string not align with the actual arguments won't result in a crash or
UB).

It also integrates our needs better - particularly the "wordy" numbers
without having to have a `help.number_words(n).c_str()` at the
callsite, translators can opt in and out of wordy numbers per string,
and this should also make it easier to solve #859.

This commit adds the formatting system itself, and changes one
`SDL_snprintf` in the code to use it as a small demo (the rest should
probably be done in the localization branch to avoid more unneeded
work).

The system is described in full detail in VFormat.h and in the pull
request description.
2022-05-06 00:19:30 -07:00
Misa
8bece4f6aa Add a missing break;
Whoops. Now I wonder why the compile didn't fail for me locally, even
though I *should* have -Werror=implicit-fallthrough enabled...
2022-04-25 01:21:43 -07:00
Misa
98cb415675 Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.

0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN

There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.

I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).

As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 00:57:47 -07:00
Misa
af1cebf7a1 Unify drawing room name on map menus into one function
Previously, it was copy-pasted and slightly different, when really, they
ought to both be the exact same code.

It kind of pains me that the room name, glitch name, and hidden name
don't own their own memory, but, that's to be addressed later.

What's a bit annoying is that the `temp` variable used in
`teleporterrender` also ends up being reused later in the function. In
this case, I opted to just redeclare them when they are used anyway, to
make it clearer.

Apart from `teleporterrender` no longer calling `map.area` or caring
about `map.custommode`, it also no longer cares about
`graphics.fademode` being 0. I could never actually get this condition
to be false in practice, and I have absolutely no idea why it's there.
I'm guessing it could be some weird edge case rendering issue if the
screen is fully black? But I wouldn't know how to trigger that, and
anyway it should probably be fixed elsewhere. So I'm just going to
remove that conditional.
2022-04-25 00:53:13 -07:00
N00byKing
e16c1557fa Fix music changes between areas 2022-04-10 14:17:46 -07:00
Misa
b8553107ff Fix a rare chance that finalstretch displays glitchy cycle (color 7)
It's quite rare, though possible, that during finalstretch you could see
a glitchy tileset that looked like this:

https://i.imgur.com/V7cYKDW.png

This happened because final_mapcol, the variable that controls which
color of finalstretch is rendered, could end up being 7. Normally, it's
in the range of 1..6, which perfectly correlates with the Warp Zone
tilesets in tiles2.png, and the higher the number the farther back in
the tileset it goes from the gray Warp Zone tileset. However, if it's 7,
then it'll start grabbing tiles from the Ship plus some unused blank
tiles, which does not look pretty in the slightest.

This happened because it's possible, though exceedingly unlikely, that
fRandom(), a function which returns a float between 0..1, could return
exactly 1. fRandom() calls rand(), which returns a result between 0 and
RAND_MAX, and divides it by RAND_MAX. This value is implementation
dependent, but required to be at least 32767, and on most systems is
2147483647. Even taking the value of 32767, that means there's a 0.003%
chance that you could get this glitchy tileset when the game cycled the
color in finalstretch. But of course, playing the game for long periods
of time will eventually increase this chance - cycling the color 1,000
times (around 17 minutes of playing) will result in the chance being 3%.

Then as the calculations in the finalstretch color cycling logic calls
fRandom(), then multiplies by 6 and adds 1, it was possible for
fRandom() to return exactly 1, then have
6 added to it, resulting in final_mapcol being 7.

To fix this, just decrement the multiplication by fRandom() to multiply
by 5 instead of 6. Now the only possible numbers that calculation can
produce would be 1..6.
2022-04-09 17:31:17 -07:00
Misa
e47781f92f SoundTrack::Init: Remove unused audio_channels arg
Missed this when reviewing the FAudio PR, so I'll just remove it now.
2022-03-31 11:13:57 -07:00
Misa
828aca2c8e Load zips using real dir instead of filename
This fixes a limitation where the level filename had to be the exact
same name as the name of the zip, because the game used the name of the
level to identify the zip of which to load assets, and this also made it
impossible to use assets for more than one level in a zip.

Instead, we just look up where the level came from, so we can always
load its assets regardless of its filename.

Additionally, the zip structure checks can go away too, simplifying the
code further.
2022-03-30 13:12:56 -07:00
Misa
7b53c1289d Remove .data.zip assets
This WOULD be a huge breaking change, if it weren't for the fact that no
one uses them. Which is why I'm removing them, to simplify the code.

I asked on the VVVVVV Discord whether anyone used them or was even aware
of them and basically the answer was no. I go on Distractionware and no
one uses them. And why would they, when they'd have to distribute the
level .vvvvvv file separately? Better to just distribute everything in
one zip. And it's quite a bit obscure that you have to suffix the file
with .data.zip anyway.
2022-03-30 13:12:56 -07:00
N00byKing
f877eb3b56 Port to FAudio 2022-03-24 16:19:29 -07:00
Misa
a8feba029f Clean up and harden music loading code
During review of #869, I looked at this part of the codebase again. I
have no idea how or why, but during the course of 2.4 this whole area
just became a mess.

The issues I fixed (in no particular order):
- Copy-pasting the code that loads from the binary blobs
- Making sure SDL_RWFromConstMem is used over SDL_RWFromMem wherever
  possible
- Adding checks to make sure the index from the binary blob is valid
  (it's possible it could not exist)
- Adding checks to make sure we gracefully handle
  SDL_RWFromConstMem/PHYSFSRWOPS_openRead returning NULL
- Moving the pointer asterisk to the type instead of the name :)
2022-03-24 09:38:47 -07:00
Misa
84279354e5 cleanup: Don't savestatsandsettings if filesystem not init
This isn't necessary, but it does silence these annoying logs if you
pass an invalid argument or don't have data.zip:

    [ERROR] Could not get window size: Invalid renderer
    [WARN] Stats not loaded! Not writing unlock.vvv.
    [ERROR] Could not get window size: Invalid renderer
    [WARN] Settings not loaded! Not writing settings.vvv.

To do this, I've added FILESYSTEM_isInit().
2022-03-14 10:45:19 -07:00
Misa
7a0d3046a5 Migrate LodePNG to submodule
We are no longer copy-pasting LodePNG source files directly.

As we can't rename lodepng.cpp to lodepng.c in the submodule itself, we
need to make a wrapper file, lodepng_wrapper.c, that #includes
lodepng.cpp, but gets compiled as C.
2022-03-13 23:50:37 -07:00
Misa
5bd7dce075 Prevent writing stats/settings if they're not loaded
This prevents writing to unlock.vvv or settings.vvv if the game hasn't
made an attempt to load them yet. Otherwise, if the game aborted via
VVV_exit() because of, say, failure to parse a graphics file, it would
overwrite perfectly existing valid save data since it hasn't loaded it
yet.

Fixes #870.
2022-03-13 22:40:59 -07:00
Misa
75ee657612 Explicitly prevent writing to saves if filesystem is not init
Another cause of #870 is d0ffafe117, as a
bisect tells me. What that commit did is remove screenbuffer as a
pointer, since it's a statically-allocated object that _should_ always
exist, and it removed the `screenbuffer == NULL` guards in savestats()
and savesettings(). Unfortunately, those guards did something very
important - namely, they prevented writing to the save files when the
filesystem wasn't initialized. But that wasn't made clear, because it
seemed like the point of those guards was to prevent dereferencing NULL.

So instead, explicitly make it clear that
FILESYSTEM_saveTiXml2Document() needs to fail if the filesystem isn't
initialized. I've done this by adding an isInit bool to
FileSystemUtils.cpp.
2022-03-12 16:50:32 -08:00
Misa
997363ce56 GetWindowSize: Initialize out values if GetRendererOutput fails
Issue #870 showed one of the problems that this game has, namely that it
only sometimes checks SDL return values, and did not do so in this case.
Part of the cause of #870 is that Screen::GetWindowSize does not check
the return value of SDL_GetRendererOutputSize, so when that function
fails (as in the case where m_renderer is NULL and does not exist), it
does not initialize the out values, so it ends up writing uninitialized
values to the save files.

We need to make sure every function's return value is checked, not just
SDL functions, but that will have to be done later.
2022-03-12 16:49:55 -08:00
Misa
726b149fbb Refactor Screen.cpp to use named constants
No more hardcoded 320s and 240s here.
2022-03-12 16:46:58 -08:00
Misa
6fffa5c11d Make basePath and pathSep global variables
While reviewing #272, I noticed that the PR was passing these two
arguments through a helper function, even though they really shouldn't
ever change. To obviate the need to pass these through, I'm making them
global variables.

pathSep is just a string literal from PhysFS, while basePath is a whole
complicated calculation from SDL and needs to be freed. It will be freed
upon filesystem deinit (as is done with PhysFS and the STDIN buffer).

Additionally the logic in FILESYSTEM_init is simplified by no longer
needing to keep a retval variable or use gotos to free basePath in
there.
2022-03-09 11:55:38 -08:00
Misa
9c698c084e Add Yussur Mustafa Oraji (N00byKing) to contributors list
Their PR #865 just got merged, so add them to CONTRIBUTORS.txt and
Credits.h.
2022-02-14 12:34:07 -08:00
Misa
f3797ff866 Allow spaces and capitals in script names when loading
This lets any script name use capitals and spaces all they want, while
still being able to jump to them via iftrinkets() or similar.

The issue is that whenever tokenize() is ran, all spaces are stripped
and every argument is lowercased before being put into `words`. So, the
solution here is to create a raw_words array that doesn't perform space
stripping or lowercasing, and to refer to that whenever there's a script
command that loads a script. We keep the lowercasing and space removal
elsewhere to be more forgiving to newcomers.

This is technically a forwards compatibility break, but it's only a
minor one, and all levels that utilize it can still be easily modified
to work on older versions anyway.
2022-02-12 14:56:27 -08:00
Misa
e93d8989d3 Revert "Fix Secret Lab Time Trial trophies having wrong colors"
As reported by Dav999, Victoria and Vermilion's trophy colors are
swapped again in 2.4. He points to
37b7615b71, the commit where I fixed the
color masks of every single surface to always be RGB or RGBA.

It sounded plausible to me, because it did have to do with colors, after
all. However, it didn't make sense to me, because I was like, I didn't
touch the trophy colors at all after I originally fixed them.

After I ruled out the RGBf() function as a confounder, I decided to see
whether intentionally reversing the color order in RGBf() to be BGR
would do anything, and to my surprise it actually swapped the colors
back around and it didn't actually look bad.

And then I realized: Swapping the trophy colors between RGB and BGR
ordering results in similar colors that still look good, but are simply
wrong, but not so wrong that they take on a color that no crewmate uses,
so it'd appear as if the crewmates were swapped, when in reality the
only thing that was swapped was actually the color order of the colors.

Trying to fix this by swapping the colors again, I actively confused
colors 33 and 35 (Vermilion and Victoria) with colors 32 and 34
(Vitellary and Viridian), so I was confused when Vermilion and Victoria
weren't swapping. Then as a debugging step, I only changed 34 to 32
without swapping 32 as well, and then finally noticed that I was
swapping Vitellary and Viridian, because there were now two Vitellarys.
And then I was reminded that Vitellary and Viridian were also wrongly
swapped since 2.0 as well.

And so then I finally realized: The original comments accompanying the
colors were correct after all. The only problem was that they were fed
into a function, RGBf(), that read the colors backwards, because the
codebase habitually changed the color order on a whim and it was really
hard to reason out which color order should be used at a given time, so
it ended up reading RGB colors as BGR, while it looked like it was
passing them through as-is.

So what happened was that in the first place, RGBf() was swapping RGB to
BGR. Then I came and swapped Vermilion and Victoria, and Vitellary and
Viridian around. Then later I fixed all the color masks, so RGBf()
stopped swapping RGB and BGR around. But then this ended up swapping the
colors of Vermilion and Victoria, and Vitellary and Viridian once again!

Therefore, swapping Vermilion and Victoria, and Vitellary and Viridian
was incorrect. Or at least, not the fix to the root cause. The root
cause would be to swap the colors in RGBf(), but this would be sort of
confusing to reason about - at least if I didn't bother to just type the
RGB values into an image editor. But that doesn't fix the real issue,
which is that the game kept swapping RGB and BGR around in every corner
of the codebase.

I further confirmed that there was no more RGB or BGR swapping by
deleting the plus-one-divide-by-three transformation in RGBf() and
seeing if the colors looked okay. Now with the colors being brighter, I
could see that passing it straight through looked fine, but
intentionally reversing it to be BGR resulted in colors that at a
distance looked okay, but were either washed out or too bright. At least
finally I could use my 8 years of playing this game for something.

So in conclusion, actually, 37b7615b71
("Fix surface color masks") was the real fix, and
d271907f8c ("Fix Secret Lab Time Trial
trophies having wrong colors") was the real regression. It's just that
the regression came first, but it wasn't really a regression until I did
the other fix, so the fix isn't the regression, the regression is...
this is hurting my brain. Or the real regression was the friends we made
along the way, or something like that.

This is the most trivial bug ever caused by the technical debt of those
god-awful reversed color masks.

---

This reverts commit d271907f8c.

Fixes #862.
2022-02-12 00:41:02 -08:00
Misa
ef03c2a54a Remove clamp in favor of SDL_clamp
For the same reasons as I removed VVV_min/max in favor of SDL_min/max in
aa7b63fa5f, I'm doing the same thing here.
2022-02-11 17:31:41 -05:00
Misa
e40f54f06b Remove temporary SDL fallthrough
We don't need a temporary fallback if we just start using SDL 2.0.18 or
later.
2022-02-11 17:31:41 -05:00
Misa
aa343bc334 Remove SDL_GetTicks64() ifdefs
We can now use the function that doesn't wrap after ~49 days since
SDL 2.0.18 released.
2022-02-11 17:31:41 -05:00
Misa
470a4358ef Remove VSync toggle ifdefs
These ifdefs can go away now that our minimum SDL version is 2.0.20.
2022-02-11 17:31:41 -05:00
Ethan Lee
84f9bb6dd6 Point to SDL_LoadWAV for SoundTrack FAudio suggestion 2022-01-15 01:02:24 -05:00
Ethan Lee
3b18a475dd Move MusicTrack below SoundTrack.
It's very likely that MusicTrack will be pulling from the SoundTrack FAudio
context, so make it so forward declarations are unnecessary.
2022-01-14 17:24:22 -05:00
Ethan Lee
adcabb9483 Add notes for FAudio implementation 2022-01-14 17:11:16 -05:00
Ethan Lee
5202b80a3d Remove unused m_isValid value from MusicTrack 2022-01-14 16:56:00 -05:00
Ethan Lee
d36741fa07 Move the Mix_OpenAudio call to SoundTrack, from MusicTrack.
In hindsight, the FAudio pointer will likely be in SoundTrack since we will
want to keep the mastering voice closer to the sounds and their source voice
arrays, while the MusicTrack will likely just be one source voice that gets
PCM from different streams.
2022-01-14 16:52:52 -05:00
Ethan Lee
df618e6d22 Isolate all SDL_mixer references to SoundTrack/MusicTrack.
This looks redundant but will actually help in the transition to FAudio; we
mostly want to keep the game logic the same while reimplementing the current
mixer, weirdness and all. Once that's done and confirmed to be stable and
consistent we can start cutting out the workarounds and quirks.
2022-01-14 16:46:04 -05:00
Misa
017d54adb0 Don't use function pointer to print room name
This improves the readability of the code.
2021-12-26 10:08:21 -08:00
Ethan Lee
81aa02e29b SDL_mixer is now entirely contained in Music.cpp.
This meant making the track vectors static, but that's kind of what we do with musicclass anyway?

In any case, this will make the transition to FAudio MUCH less invasive.
2021-12-26 08:57:38 -05:00
Ethan Lee
1eda3647ff Move the mute logic to musicclass.
This moves the last of the SDL_mixer calls to Music.cpp.
2021-12-26 08:48:23 -05:00
Ethan Lee
579f0f763a Update docs for MusicTrack/SoundTrack 2021-12-26 08:41:57 -05:00
Ethan Lee
230859f8f9 Inline SoundSystem into musicclass constructor 2021-12-26 08:41:01 -05:00
Ethan Lee
c87f0e1a0c Consolidate SoundSystem into Music.
It's just some small wrappers, and SoundSystem can be inlined trivially.
2021-12-26 08:38:19 -05:00
Ethan Lee
f723e03871 Remove unused MusicTrack constructor.
This wouldn't work anyway since music would need to be loaded via physfs.
2021-12-26 08:31:40 -05:00
Misa
dfb1e31d78 Optimization: Don't outline if room name BG opaque
This is quite simple. Just use a function pointer that switches out
which function we're going to use.

...Or not. C++ syntax makes this a bit awful since the function is a
member of a class. Did I mention how much I don't like C++?
2021-12-26 00:04:20 -08:00
Misa
8f226ced84 De-duplicate finalmode glitchname printing
Instead of copy-pasting the call twice, just use a variable to switch
between the two names.
2021-12-26 00:03:18 -08:00
Misa
276aab1209 Default to integer scaling mode
Issue #849 suggested making integer be the default on Big Picture and
Steam Deck, but after thinking about it more, I think it's better and
more simple to just default to integer mode in general.

Reason being that people in Big Picture shouldn't expect the picture to
look different if they're out of Big Picture but still in fullscreen, or
have the picture look different in fullscreen depending on if they
launched the game for the first time in Big Picture or not. And besides,
the less lines of code, the better. So I'm just making integer mode the
default.
2021-12-25 23:14:43 -08:00
Misa
550e76a6dc Add and use scaling mode enum
This enum is to just make each mode be readable, instead of mysterious
0/1/2 values. It's not a strictly-typed enum because we still have to
serialize it as ints in the XML, but it's better than just leaving them
as ints.

This also adds a NUM_SCALING_MODES enum, so we don't have to hardcode
that 3 when cycling scaling modes anymore.
2021-12-25 23:14:12 -08:00
Misa
f5166c437e Add forced fullscreen mode
This is mainly to make sure the game is definitely set to fullscreen in
Big Picture and on the Steam Deck, and to also remove windowed options
that wouldn't make sense if you're not on a desktop (toggling
fullscreen, resize to nearest). Those options would also be removed on
console and mobile too.

There's a bit of an annoying bug where if you launch the game in forced
fullscreen mode, but then exit and relaunch in normal mode, your game
will have fullscreen window sizes but it won't be fullscreen. This is
because forced fullscreen mode tries to preserve your non-forced
fullscreen setting, but due to the way window sizes are stored and
queried, it can't preserve the non-forced window size. This is a bit
difficult to work around, so I'm just putting in a FIXME here because we
can fix it later and I'd rather have a slightly buggy forced fullscreen
mode than not have one at all.

Closes #849.
2021-12-25 23:01:45 -08:00
Dav999-v
3e36bfd56f Simplify time formatting functions
Here's my notes on all the existing functions and what kind of time
formats they output:

- Game::giventimestring(int hrs, int min, int sec)
	H:MM:SS
	MM:SS

- Game::timestring()
// uses game.hours/minutes/seconds
	H:MM:SS
	MM:SS

- Game::partimestring()
// uses game.timetrialpar (seconds)
	MM:SS

- Game::resulttimestring()
// uses game.timetrialresulttime (sec) + timetrialresultframes (1/30s)
	MM:SS.CC

- Game::timetstring(int t)
// t = seconds
	MM:SS

- Game::timestringcenti(char* buffer, const size_t buffer_size)
// uses game.hours/minutes/seconds/frames
	H:MM:SS.CC
	MM:SS.CC

- UtilityClass::timestring(int t)
// t = frames, 30 frames = 1 second
	S:CC
	M:SS:CC

This is kind of a mess, and there's a lot of functions that do the same
thing except using different variables. For localization, I also want
translators to be able to localize all these time formats - many
languages use the decimal comma instead of the decimal point (12:34,56)
maybe some languages really prefer something like 1時02分11秒44瞬...
Which I don't know to be correct, but it's good to be prepared for it
and not restrict translators arbitrarily to only changing ":" and "."
when we can start making the system better in the first place.

I added a new function, UtilityClass::format_time. This is the place
where all time formats come together, given the number of seconds and
optionally frames. I have simplified the above-mentioned functions
somewhat, but I haven't given them a complete refactor or renaming -
I mainly made sure that they all use the same backend so I can make the
formats consistent and properly localizable.

(And before we start shoving more temporary char buffers everywhere
just to get rid of the std::string's, maybe we need to think of a
globally used working buffer of size SCREEN_WIDTH_CHARS+1, as a
register of sorts, for when any line of text needs to be made or
processed, then printed, and then goes unused. Maybe help.textrow,
or something like that.)

As for this commit, the available time formats are now more consistent
and changed a little in some places. Leading zeroes for the first unit
are now no longer included, time trial results and the Super Gravitron
can now display hours when they went to 60 minutes before, and we now
always use .CC instead of :CC. These are the formats:
- H:MM:SS
- H:MM:SS.CC
- M:SS
- M:SS.CC
- S.CC  (only used when always_minutes=false, for the Gravitrons)

Here's what changes to the current functions:
- Game::partimestring() is removed - it was used in two places, and
  could be replaced by game.timetstring(game.timetrialpar)
- Game::giventimestring(h,m,s) and Game::timestring() are now wrappers
  for the other functions
- The four remaining functions (Game::resulttimestring(),
  Game::timetstring(t), Game::timestringcenti(buffer, buffer_size)
  and UtilityClass::timestring(t)) are now wrappers for the "central
  function", UtilityClass::format_time.
- UtilityClass::twodigits(int t) is now unused so it's also removed.
- I also added int UtilityClass::hms_to_seconds(int h, int m, int s)
2021-12-25 11:38:12 -08:00
Misa
dd24343141 Use LoadImage in LoadIcon
This de-duplicates the code, simplifying the codebase and reducing the
number of code paths that needs to be maintained. It also adds
robustness checks to LoadIcon that weren't there before (checking that
loading the file succeeded and that decoding the file also succeeded).

Now, you might think that loading the image with alpha will change
things in some way. But actually, I tested it, and I'm pretty sure it
doesn't. Since my window manager, i3, doesn't display icons, I've had to
resort to this hacky multi-liner
( https://unix.stackexchange.com/a/48866 ) to dump the icon to a PAM
file. I don't know what a PAM file is and all my various attempts to
convert it into something readable failed. But what I did instead was
just grab the icon of the game before this commit (on 2.3, just to be
extra sure), and `diff`ed it with the grabbed icon now, and they end up
being the exact same file. So there's literally no difference.

The only other consideration is that LoadImage needs to be exported,
since it's implemented in GraphicsResources.cpp. I just opted to
forward-declare it right before LoadIcon in Screen.cpp, since it's
really the only other time it's used. No need to create a new header
file for it or anything.
2021-12-25 01:29:24 -08:00
Misa
a5c3bd97a0 Remove noAlpha argument from LoadImage
This is just to simplify the function. I really don't see any point in
taking away the alpha for some images, other than to disappoint people
who mod the game assets. It just complicates loading the image with no
real gain. To reduce maintenance costs, let's remove this alternate code
path.

Also it's a default argument and I don't like default arguments.
2021-12-25 01:29:12 -08:00
Misa
3108178c53 Remove noBlend argument from LoadImage
This argument... doesn't do anything.

First off, setting it to true explicitly enables blending on the
resulting surface, which is kind of the exact opposite of the variable
name and is misleading to say the least? And secondly, SDL surfaces have
blending enabled by default anyways, so it still doesn't even do
anything.

It's also a default argument, and I'm not one to shy away from removing
such default arguments.
2021-12-25 01:26:42 -08:00
Misa
a6b076e234 Explicitly zero declared struct ScreenSettingss
Performance cost is negligible and well worth being safe in case there
are more members added in the future but we forget to initialize them.
2021-12-25 00:30:10 -08:00
Misa
1e157f3cc9 De-C++-ify struct ScreenSettings
This includes:
- Removing the constructor in favor of actually being able to see that
  there's an actual function called being made initializing the struct
- Removing the use of a reference in Screen::init() in favor of using a
  pointer
- Adding the struct qualifier everywhere (it's not much typing),
  although technically you could typedef it in C, but I'd rather much
  not typedef just to remove a tag qualifier
2021-12-25 00:30:10 -08:00
Misa
d0ffafe117 Extern gameScreen, remove screenbuffer
I know earlier I removed the gameScreen extern in favor of using
screenbuffer, but that was only to be consistent. After further
consideration, I have found that it's actually really stupid.

There's no reason to be accessing it through screenbuffer, and it's
probably an artifact of 2.0-2.2 passing stack-allocated otherwise-global
classes everywhere through function arguments. Also, it leads to stupid
bugs where screenbuffer could potentially be NULL, which has already
resulted in various annoying crashes in the past. Although those could
be fixed by simply initializing screenbuffer at the very top of main(),
but, why not just scrap the whole thing anyway?

So that's what I'm doing.

As a nice side effect, I've removed the transitive include of Screen.h
from Graphics.h. This could've been done already since it only includes
it for the pointer anyway, but it's still good to do it now.
2021-12-25 00:29:28 -08:00
Misa
b7cbdfe8f9 Fix char overflow in Analogue Mode
In aa7b63fa5f, I didn't notice that the
result was implicitly being converted to int by the min/max from before.
I instead added it to the existing char, but that resulted in a char
overflow (it's unsigned, so thankfully not undefined behavior).

But of course the entire point of that commit is to make it explicitly
clear when you are converting between types, intentionally or otherwise,
in min/max comparisons. So despite causing a regression (which I have
now fixed), at least it did its job.
2021-12-22 21:49:08 -08:00
Misa
816a0b9eb7 Move filterSubrect off of Screen
It's only used in FlipScreen.
2021-12-22 20:39:11 -08:00
Misa
f7b4ac8322 Rename stretch mode to scaling mode internally
It's been long overdue that this variable be named properly. 2.2 added
integer scaling mode (thanks Ethan), 2.3 renamed it to scaling mode. Now
2.4 will properly call it what it is so people won't be confused by it.

The ScreenSettings struct member is renamed from stretch to scalingMode
along with the Screen class member being renamed, as well as the
toggleStretchMode function being renamed to toggleScalingMode as well.
Unfortunately, due to compatibility, we can't change the <stretch> XML
tag.
2021-12-22 19:54:59 -08:00
Misa
aa7b63fa5f Remove VVV_min/max in favor of SDL_min/max
VVV_min/max are functions that only operate on ints, and SDL_min/max are
macros that operate on any type but double-evaluate everything.

I know I more-or-less said earlier that SDL_min/max were dumb but I've
changed my mind and think it's better to use them, taking care to make
sure you don't double-evaluate, rather than trying to generate your own
litany of functions with either your own hand-rolled generation macros,
C++ templates, C11 generics, or GCC extensions (that last one you'd
technically use in a macro but it doesn't really matter), all of which
have more downsides than just not double-evaluating.

And the upside of not double-evaluating is that you're disencouraged
from having really complicated single-line min/max expressions and
encouraged to precompute the values beforehand anyway so the final
min/max is more readable. And furthermore you'll notice when you
yourself end up doing double-evaluations anyway. I removed a couple
instances of Graphics::len() being double-evaluated in this commit (as
well as cleaned up some other min/max-using code). Although the only
downside to those double-evaluations was unnecessary computation,
rather than checking the wrong result or having multiple side effects,
thankfully, it's still good to minimize double-evaluations where
possible.
2021-12-22 16:43:31 -08:00
Misa
f7454baffa Hide level path by default
You will now need to go through another confirm menu in order to print
your level path. The confirm menu warns you may leak sensitive
information if you are streaming.

Screenshots:
https://i.imgur.com/0Dc9jsZ.png
https://i.imgur.com/UhDgXqj.png
https://i.imgur.com/Z0ftQnH.png

Fixes #853.
2021-12-22 00:58:27 -08:00
Misa
8ba1325d0f Fix regression with wall stuck flipping behavior exactly reversed
The reason why the wall stuck flipping behavior happened in the first
place was because the code went like this:

    if (jumppressed)
    {
        if (onground && gravitycontrol == 0)
        {
            gravitycontrol = 1;
        }
        if (onroof && gravitycontrol == 1)
        {
            gravitycontrol = 0;
        }
    }

Basically, if you were both on ground and on a roof (i.e. stuck in a
wall), you would flip, but then due to code order and the fact that the
statement is not connected to the previous one, you would immediately
unflip afterwards. But if you were already flipped then the only path
that can be taken is to unflip you, since it's the statement that
appears last.

52fceb3f69 replaces the onground/onroof
conditionals with any_onground/any_onroof, so any player entity would
allow you to flip. But otherwise the code is the same. So is that the
problem?

No; tracing it through with GDB reveals that when you flip,
gravitycontrol is being set to 1, but never being set to 0. And it turns
out that's because any_onroof is not getting set. And that happens
because of another thing that 52fceb3f69
did - which was to set any_onground/any_onroof to true if indeed any
player entity was on ground or on a roof.

Unfortunately, the way Leo did it was to make the two statements
mutually exclusive - an 'if'-'else if' instead of two separate
statements. So a single entity could not mark both any_onground and
any_onroof as true (and the majority of the time, you will be a single
entity).

Thus, the solution is to just drop that 'else'.

Fixes #855.
2021-12-22 00:25:19 -08:00
Misa
caebde9e33 Fix warp sprites of big sprites sometimes not being drawn
I noticed when going frame-by-frame in Vertigo that sometimes the
wrapping enemies at the top sometimes just "popped" in frame. This is
because the sprite warp code only draws the warping sprite of sprites at
the bottom of the screen if they're below y=210. However, the warp point
starts at y=232, and warp sprites can be at most 32x32, which is exactly
the case with the Vertigo sprites, which are exactly 32x32. So the warp
code should start warping sprites if they're below y=200 (232 - 32)
instead.

Horizontal warping also has this problem; it warps at x=320 and
starts drawing warp sprites at x=300, even though it should start
drawing at x=288 (320 - 32). I've gone ahead and fixed that as well.
2021-12-20 20:18:24 -08:00
Misa
44ebb19d77 Outline "NO SIGNAL"
This is just in case the background gets changed by a custom level or
something to be something that would otherwise result in bad contrast.
Also if it needs to go outside the box for some reason. And I just like
the look of the outline.
2021-12-20 20:07:38 -08:00
Misa
9cddae8cc3 Outline trophy text
Whew, look at all those copy-pasted print statements!

Doing this because of the in-game timer feature. The text would
otherwise clash harshly with the timer otherwise. Even with the outline
it still clashes, but at least there's an outline so it's not as harsh.
2021-12-20 20:02:07 -08:00
Misa
1d6a808cbd Add centiseconds to timer overlays
This adds centiseconds to the in-game timer, as well as the time trial
timer.

This is to aid speedrun moderators in determining when exactly a run was
completed, which they can't easily do if the timer only has a precision
up to a second.
2021-12-20 19:26:01 -08:00
Misa
51fac68d3a Fix in-game timer going away after playing Super Gravitron
The problem was that it also needed to check that game.swnmode was true,
in addition to game.swngame being 1, to actually check that the Super
Gravitron was being played.
2021-12-20 17:44:34 -08:00
Misa
b7b9caacfc Remove unused game-gamestates
These were `CLICKTOSTART` and `FOCUSMODE`.
2021-12-18 00:01:32 -08:00
Misa
119e25d0bb Change all game-gamestates to use an enum type
Currently, all game-gamestate variables are just ints. This is not
particularly type-safe, in case the number of enums changes. To verify
that all current uses of the game-gamestate variables actually use the
enums, change them to be typed with the enum instead.

(As an aside, we should probably rename this so that it can't be
confused with Terry's state machine that has several different ways to
exploit to warp you to the credits, but that's something to do later.)
2021-12-17 23:57:55 -08:00
Misa
b67386894c hardreset: Reset ingame_titlemode
You'll note that getting in to the glitchy state of the game (the state
where you could play the game after it had hardreset() called on it)
required the player to quit to menu with ingame_titlemode set to true.
Well, quitting to menu calls hardreset(). So if hardreset() is called
when quitting, then you can no longer preserve ingame_titlemode that
way. This is a bit overkill, but I'm just taking precautions.
2021-12-17 23:39:26 -08:00
Misa
7f9247b0c7 Add asserts if ingame_titlemode in unexpected places
The game will now assert if the main menu is created while
ingame_titlemode is true, or if we attempt to load into a mode while
it's true. And if assertions are disabled then it just stops doing it
anyway.

I don't think there's any way to get a glitched ingame_titlemode again,
ever since I removed save data deletion taking you back to the main
menu. But I've had enough bugs with the fact that we more-or-less use
the same state for main menu options and in-game options, and that
glitched ingame_titlemode bug DID just happen, so I'm taking
precautions.
2021-12-17 23:36:13 -08:00
Misa
5ebc65d1a2 Pull out fade mode handling into separate function
The next commit will add logic that more-or-less quits the whole block
if ingame_titlemode, and instead of adding another layer of indentation
I will just pull this into its own function so we can use a return
statement.
2021-12-17 23:35:08 -08:00
Misa
cc9c71a94a deletestats: Properly reset bestgamedeaths
While I was testing deleting data while you were in-game, I noticed that
deleting data gave you all the "Win with less than X deaths" trophies,
even if you never got any of them before deleting data. Well, it turns
out that if you have the best game death count of 0, then you win every
trophy, and if you have the best game death count of -1 then that means
you haven't completed the game yet.

This reset was added in e3bfc79d4a, so at
least it's not in 2.3, but I only have myself to blame for making this
mistake. Whoops.
2021-12-17 23:34:44 -08:00
Misa
2770353142 Don't go back to main menu when deleting main game save data
Going back to the main menu allowed for glitchiness to occur if you
deleted your save data while in in-game options. This meant you could
then load back in to the game, and then quit to the menu, then open the
options and then jump back in-game, exploring the state of the game
after hardreset() had been called on it. Which is: pretty glitchy.

For example, this meant having your room coordinates be 0,0 (which is
different from 100,100, which is the actual 0,0, thanks for the
100-indexing Terry), which caused some of the room transitions to be
disabled because room transitions were disabled if the
game.door_up/down/left/right variables were -2 or less, and they were
computed based on room coordinates, which meant some of them went
negative if you were 0,0 and not 100,100. At least this was the case
until I removed those variables for, at best, doing nothing, and at
worst, being actively harmful.

Anyways, so deleting your save data now just takes you back to the
previous menu, much like deleting custom level data does. I don't know
why deleting save data put you back on the main menu in the first place.
It's not like the options menu needed to be reloaded or anything. I
checked and this was the behavior in 2.0 as well, so it was probably
added for a dumb reason.

I considered prohibiting data deletion if you were ingame_titlemode, but
as of the moment it seems to be okay (if albeit weird, e.g. returning to
menu while in Secret Lab doesn't place your cursor on the "play"
button), and I can always add such a prohibition later if it was really
causing problems. Can't think of anything bad off of the top of my head,
though.

Btw thanks to Elomavi for discovering that you could do this glitch.
2021-12-17 23:34:25 -08:00
Misa
1924ca53ac Remove game.door_left/right/up/down variables
These don't do anything, and in fact are actively harmful by disabling
room transitions if your roomx/roomy is glitched.
2021-12-17 19:43:29 -08:00
Misa
a345cf93b8 Fix elephant placement across rooms
Okay, so, this is the elephant sprite, right?

https://i.imgur.com/dtS70zk.png

This is how it looks in the actual game, when you stitch all the rooms
together:

https://i.imgur.com/aztVnFT.png

Looks kind of messed-up, doesn't it?

Okay, so, in the bottom two rooms (11,9) and (12,9), the elephant is
placed at y-position -152. But in (11,8) and (12,8), it's placed at
y-position 96. This is despite the fact that -152 plus 240 is 88, not
96.

Similarly, in the left two rooms (11,8) and (11,9), the elephant is
placed at x-position 64, but in the right two rooms (12,8) and (12,9),
the elephant is placed at -264. This is despite the fact that 64 minus
320 is -256, not -264.

All of this stems from the calculations in Otherlevel.cpp using offsets
of -248 and -328 instead of -240 and -320.

So there's an 8-pixel offset that causes the elephant to be chopped off
when viewed with all the rooms stitched together. Simple enough to fix.
For the y-position fixes, I decremented the initial 8-pixel multiplier
as well, else the elephant would sink into the floor.

And this is what the elephant looks like now after stitching:

https://i.imgur.com/27ePLm1.png

Thanks to Tzann for pointing this out.
2021-12-08 16:25:18 -08:00
Dav999-v
f60d2a2964 Fix -Wformat-security warnings
These warnings are kinda spammy, and they make sense in principle.
vlog_error takes a format string, so passing it an arbitrary string
(even error messages from libraries) isn't a good idea.
2021-12-05 10:45:36 -08:00
Misa
6e832cae20 LoadImage: Check LodePNG return value and print errors
Dvoid from Discord just reported a crash when trying to load a
custom tiles2.png that was encoded weirdly.

The problem is that we don't check the return value from LodePNG, so
LodePNG gives us a null pointer, and then
SDL_CreateRGBSurfaceWithFormatFrom doesn't check this null pointer,
which then propagates until we crash in SDL_ConvertSurfaceFormat (or
rather, one of its sub-functions), and we would probably crash somewhere
else anyway if it continued.

After properly checking LodePNG's return value, along with printing the
error, it turns out that Dvoid's custom tiles2.png had an "invalid CRC".
I don't know what this means but it sounds worrying. `feh` can read the
file correctly but it also reports a "CRC error".
2021-11-14 14:02:51 -08:00
Misa
cd15ae0fdc Use SDL_FALLTHROUGH if available
The SDL_FALLTHROUGH macro has been added to SDL 2.0.18. Until 2.0.18 is
released, use it if it's available.
2021-11-11 23:48:41 -08:00
Misa
0c1f756af8 Switch over to using SDL_GetTicks64()
SDL_GetTicks64() is a function that got added in SDL 2.0.18, which is
just an SDL_GetTicks() without a value that wraps every ~49 days,
instead wrapping after the sun explodes and kills us all. Oh sorry,
didn't mean to get existential.

For now, put this behind an SDL_VERSION_ATLEAST guard, which will be
removed when SDL 2.0.18 officially releases and we can update to it.
2021-11-01 11:37:50 -07:00
Misa
75e031cef0 Don't toggle VSync twice
The vsync variable is already toggled in toggleVSync(). Whoops.
2021-10-29 12:24:10 -07:00
Misa
d0992e18a4 Fix regression with rainbow lab BG in editor
731fb89c90 was partially reverted by #624
because of my bad rebase.
2021-10-28 17:27:13 -07:00
Misa
1bc1149ab5 Fix regression with counting out-of-bounds custom entities
My latest rebase of #624 (refactoring/splitting editor.cpp) accidentally
overwrote #787 and essentially reverted it entirely. So, add it back in.

This is the same as #787 except it uses the new names, uses SDL_INLINE
to inline the function, and uses named constants.
2021-10-27 16:49:57 -07:00
Misa
58c518c856 Silence GCC warnings about void*-to-function-pointer casts
GCC warns on casting `void*` to function pointers. This is because the C
standard makes a clear distinction between pointers to objects (`void*`)
and pointers to functions (function pointers), and does not specify
anything related to being able to cast object pointers to function
pointers.

The warning message is factually wrong, though - it states that it is
forbidden by ISO C, when in fact it is not, and is actually just
unspecified.

We can't get rid of the cast entirely, because we need the explicit cast
(the C standard _does_ mandate you need an explicit cast when converting
between object pointers and function pointers), and at the end of the
day, this is simply how `SDL_LoadFunction()` works (and more
importantly, how `dlsym()` works), so we can't get rid of it, and we
have no reason to anyways since it means we don't have a hard runtime
dependency on Steam (unlike some other games) and casting `void*` to
function pointers always behaves well on every single platform we ship
on that supports Steam.

Unfortunately, this warning seems to be a part of -Wpedantic, and
there's no way to disable this warning specifically without disabling
-Wpedantic. Luckily, I've found a workaround - just cast to `intptr_t`
before casting to the function pointer. Hopefully the compiler doesn't
get smarter in the future and this ends up breaking or anything...
2021-10-21 01:00:06 -07:00
Ally
f3786a8e3f
Add setactivityposition(x,y), add new textbox color transparent (#847)
* Add `setactivityposition(x,y)`, add new textbox color `transparent`

This commit adds a new internal command as a part of the visual activity zone changes I've been making.
This one allows the user to reposition the activity zone to anywhere on the screen.
In addition, this commit adds the textbox color `transparent`, which just sets r, g and b to 0.
rgb(0, 0, 0) normally creates the color black, however in VVVVVV textboxes, it makes the background
of them invisible, and makes the text the off-white color which the game uses elsewhere.

* add new variables to hardreset

* Fix unwanted text centering; offset position by 16, 4

It makes sense for `setactivityposition(0, 0)` to place the activity zone in the default position,
so the x has been offset by 16, and the y has been offset by 4.

Text was being automatically centered, meaning any activity zone which wasn't centered had misplaced text.
This has been fixed by calculating the center manually, and offsetting it by the passed value.
2021-10-13 15:38:51 -07:00
Misa
700be11137 Remove space at end of Press %s to Teleport
This wasn't there in 2.2 and previous. I accidentally introduced it in.
2021-10-12 16:59:36 -07:00
Misa
449526bb4f Fix regression with per-pixel collision colors
In previous versions, the game mistakenly checked the wrong color
channel of sprites, checking the red channel instead of the alpha
channel. I abuse this in some of my levels. Then I broke it when
refactoring masks so the game now no longer checks the red channel but
seems to check the blue channel instead. So re-fix this to the previous
bug, and preserve the previous bug with a comment explaining why.
2021-10-06 23:18:58 -07:00
Misa
2f25ab77b1 Fix regression with tile 10 not having nothing behind it
This broke when I was refactoring things earlier, because we no longer
have a direct reference to the contents array, instead using a copied
int. But we have a settile() function anyway, so why not use it?
2021-10-06 17:00:50 -07:00
Misa
038f15f4a6 Remove outdated FIXMEs from Screen.cpp
The VSync renderer workaround is no longer a thing, so these comments
should go away.
2021-10-03 13:23:12 -07:00
Misa
7eea59a7e8 Make impossible time trial save screen message less verbose
Ally asked me why it was so verbose, and recommended wording it like
this instead. Not that it should matter much, since it _is_ impossible,
but...
2021-10-02 09:24:44 -07:00
Misa
0ed0892977 Add impossible message for quicksave screen in time trials
It is impossible to get on the quicksave screen in time trials, because
Enter is always bound to restarting time trials in a time trial, and
there's no way to open the map screen otherwise.

So, I've decided to add a fun little message in case someone somehow
manages to get to this screen in a time trial.
2021-10-01 21:13:51 -07:00
Misa
db8e0cd70a De-duplicate map menu quicksave screen
As is typical, the code was copy-pasted to account for Flip Mode, and
then copy-pasted again to account for custom levels, leading to four
instances of the same code.

I clean this up while also improving code style. This is where the new
FLIP macro and the fixed PrintWrap help a lot - otherwise the "Game
saved ok!" screen would look really wrong without the height
corrections.
2021-10-01 21:06:31 -07:00
Misa
b26ccd914d Simplify flipme text box position correction
It now looks more like the FLIP macro in Render.cpp: The y-position is
simply the height of the area the object is being flipped in, minus the
y-position itself, minus the height of the object. So:

    flipped_yp = constant - yp - height

This is just a mathematical simplification of the existing statement,
which is:

    flipped_yp = yp + 2 * (constant/2 - yp) - height

Using algebra, the 2 distributes into the parentheses, so

    flipped_yp = yp + constant - 2 * yp - height

And the two `yp`s add together, so

    flipped_yp = constant - yp - height

It's more readable this way.

Also I am using a named constant instead of a hardcoded one.
2021-10-01 20:59:55 -07:00
Misa
98b392197c PrintWrap: Account for height in Flip Mode
Otherwise, the text will be in the wrong position compared to normal
mode.

PrintWrap is not used in Flip Mode yet, but it will be used on the map
screen in an upcoming change of mine. The FLIP macro in Render.cpp can't
help us there, since it would need to know the height of the wrapped
text at compile time, when the height is only figured out at runtime
based off of the string (or, well, right _now_ the string _is_ known,
but we are going to merge localization for 2.4, and it's better to
future-proof...), and only PrintWrap itself can figure out the height of
the text. (Or, well, I suppose you could call it from outside the
function, but that's not very separation-of-concernsy style.)
2021-10-01 20:49:27 -07:00
Misa
517e20cecb Account for heights in the FLIP macro
Flipping objects in Flip Mode needs to account for the heights of those
objects (that's why flipme text boxes in Flip Mode in 2.2 were
positioned wrongly).

Also, turn it into a macro instead of an inline function.

This changes the positions of all existing de-duplicated map menu text
in Flip Mode, but it'll be more correct.
2021-10-01 20:39:24 -07:00
Misa
3a911a9a9b Fix SCREEN_HEIGHT_PIXELS being wrong constant
Whoops.
2021-10-01 09:35:28 -07:00
Misa
a346379413 Remove unused math.h include from Maths.h
Apparently this was in here, just completely unused.
2021-09-27 23:11:20 -07:00
Misa
3decf54dbc Mark all vlog functions with printf attributes
This ensures that compiler warnings about format strings will apply to
all calls of these functions as well.
2021-09-27 20:49:09 -07:00
Misa
5533215019 Use SDL_NORETURN
I misread SDL's code and thought that SDL's `begin_code.h` was internal
only to SDL. It turns out you get it when you include basically any
header, such as `SDL_stdinc.h`. So use it directly instead of copying it
for our own.
2021-09-27 10:32:23 -07:00
Misa
c3dfd4a4b1 De-duplicate map menu stats screen rendering code
Between accounting for Flip Mode and custom levels, this code was
copy-pasted three times, leading to _four_ instances of one code!

Anyways, I've cleaned it up. The position of the text in Flip Mode is
going to differ by 4 pixels from how it was previously, but that really
shouldn't matter.
2021-09-25 17:16:52 -07:00
Misa
e9351b4a00 Fix winning in No Death Mode saying "One trinkets"
While dying in No Death Mode was fixed to no longer say "One trinkets"
in 2.3, if you win in No Death Mode with one trinket, the game would say
"One trinkets".

So to fix this, just slot a ternary in there. The code is already kind
of bad anyways and is going to be refactored/de-STLed in the future
regardless, so I'm not feeling too badly about shoving a ternary in
there like that.
2021-09-25 17:06:59 -07:00
Misa
38b2213745 Rename number to number_words
This is to clarify that it returns the word forms of numbers, not
numbers themselves.
2021-09-25 15:08:13 -07:00
Misa
cace685020 Add POS_MOD macro and use for all positive modulos
This macro is to make it so it won't be error-prone to write the
semi-confusing `(a % b + b) % b` statement, and you can just use an easy
macro instead.

Currently, the only places a positive modulo is needed is when switching
tilesets, enemies, and warp directions in the editor, as well as when
getting a tile in the tower, since towers just repeat themselves
vertically. Towers used this weird while-loop to sort of emulate a
modulo, which isn't half-bad, but is unnecessary, and I don't think any
compiler would recognize it as a modulo. (And if it's not optimized to a
proper modulo... what happens if the number being moduloed is really,
really big?)
2021-09-24 17:48:15 -07:00
Misa
891ca527f9 Remove overcomplicated integer divisions
Believe it or not, there are still some remnants of the ActionScript
coding standards in the codebase! And one of them sometimes pops up
whenever an integer division happens.

As it so happens, it seems like division in ActionScript automatically
produces a decimal number. So to prevent that, the game sometimes
subtracts off the remainder of the number to be divided before
performing the division on it.

Thus, we get statements that look like

    (a - (a % b)) / b

And probably more parentheses surrounding it too, since it would be
copy-pasted into yet another larger expression, because of course it
would.

`(a % b)` here is subtracting the remainder of `a` divided by `b`, using
the modulo operator, before it gets divided by `b`. Thus, the number
will always be divisible by `b`, so dividing it will mathematically not
produce a decimal number.

Needless to say, this is unnecessary, and very unreadable. In fact, when
I saw these for the first time, I thought they were overcomplicated
_modulos_, _not_ integer division! In C and C++, dividing an integer by
an integer will always result in an integer, so there's no need to do
all this runaround just to divide two integers.

To find all of these, I used the command

    rg --pcre2 '(.+?).+?-.+?(?=\1).+?%.+?([\d]+?).+?\/.+?(?=\2)'

which basically matches expressions of the form 'a - a % b / b', where
'a' and 'b' are identical and there could be any characters in the
spaces.
2021-09-24 17:39:31 -07:00
Misa
6192269128 Remove vmult lookup tables
There's really no need to put the y-multiplication in a lookup table.
The compiler will optimize the multiplication better than putting it in
a lookup table will.

To improve readability and to hardcode things less, the new
SCREEN_WIDTH_TILES and SCREEN_HEIGHT_TILES constant names are used, as
well as adding a new TILE_IDX macro to calculate the index of a tile in
a concatenated-rows (row-major in formal parlance) array. Also, tile
numbers are stored in a temporary variable to improve readability as
well (no more copy-pasting `contents[i + vmult[j]]` over and over
again).
2021-09-24 16:37:27 -07:00
Misa
491f3732aa Fix trailing whitespace in CustomLevels.h
Really not sure how they got there. I think it was because of my naive
indentation fix, so.
2021-09-24 16:36:54 -07:00
Misa
f9573a036d Remove commented-out old spike block code
This seems to be code for creating spike blocks in a previous version of
the game. It's unused and commented out, so, remove it.
2021-09-24 16:26:11 -07:00
Misa
3fcab3a395 Remove splitseconds lookup table and inline it
There's really no reason for this simple multiplication plus division to
be in a lookup table. The compiler will optimize it faster than putting
it in a lookup table will, I'm sure.
2021-09-24 16:03:14 -07:00
Misa
f48e385e68 Remove Ethan's binary-or comment
This comment was referring to a now-deleted variable named mkdirResult
that was binary-"or"ed with all mkdir() results... except for the saves
directory. That variable was only used for save file migration, which is
now axed, so this comment is referring to nothing now.

I don't really know the answer to Ethan's question, but it doesn't
matter now.
2021-09-23 23:26:28 -07:00
Misa
1b7a1248a8 Declare Windows mkdir as static
It's not going to be used in any other files so... best to declare it
static.
2021-09-23 23:26:00 -07:00
Misa
eabb3941fd Mark VVV_exit implementation as VVV_NORETURN
For consistency. And in case it matters that much (which I don't really
think it does).
2021-09-23 23:02:46 -07:00
Misa
32bd6c41bc Fix regression with VVV_COMPILEMUSIC aborting
So, it turns out freeing everything in binaryBlob::clear() without
checking for NULL results in an abort() because clear() gets called on
musicWriteBlob after it attempts to write the compiled music. It's just
that no one's using VVV_COMPILEMUSIC, so no one's ran into this.

I'm keeping VVV_COMPILEMUSIC around so in the future people can compile
music directly from the game (and probably half the existing
VVV_COMPILEMUSIC code is going to be thrown out, but oh well).
2021-09-23 22:35:52 -07:00
Misa
0c5024f7e7 Use fixed-size int types for resourceheader
Since this refers to specific exported file data, let's make sure this
is portable. I'm not sure if we'll ever ship on systems where
sizeof(int) != 4 or sizeof(bool) != 1, but better to be safer and
future-proof than not.
2021-09-23 22:21:49 -07:00
Misa
51bfed2032 Ifdef numberofHeaders out if not compiling music
This variable is only used when compiling music. Since it doesn't
actually keep track of the number of headers otherwise, ifdef it behind
VVV_COMPILEMUSIC.
2021-09-23 21:55:58 -07:00
Misa
1297b09c47 Fix regression from 2.3 with destroy(platforms)
2.3 introduced a regression with destroy(platforms). The problem was
that isplatform wasn't being set to false when the entity got disabled,
so if the platform was moving, it would keep moving until it hit a wall,
instead of stopping immediately.
2021-09-23 13:16:57 -07:00
Misa
c94d04a932 Use SDL_isxdigit() in favor of VVV_isxdigit()
SDL_isxdigit() was added in SDL 2.0.16, so we no longer have to
implement isxdigit() ourselves.
2021-09-23 12:26:50 -07:00
Misa
b74dcdc7ee Remove unused Steam GetStat/SetStat
Forgot these when I was cleaning up the unused achievement percentages
functions...
2021-09-22 20:04:34 -07:00
Misa
bf2f33f1ca Add noreturn qualifier to VVV_exit
This function doesn't return, so we mark it as noreturn if the compiler
supports it.
2021-09-22 19:58:31 -07:00
Misa
b2d7a0b4b6 Rewrite STDIN loading to not use STL
Previously, loading STDIN used std::istreambuf_iterator and std::vector
and whatnot because... I guess it was less typing? But this isn't 1989;
we have the disk space to spare and we don't need to use fancy stuff
just to save on typing. It's not that hard to implement an array that
regrows to the nearest power of two every time.
2021-09-22 19:55:28 -07:00
Misa
dbe9f7c2a0 Declare emscriptenloop as static
It's not going to link with anything in a different translation unit, so
just to make sure, we declare it as static.
2021-09-20 13:48:49 -07:00
Misa
1d0401ef83 Move Emscripten includes to top of main.cpp
All system header includes should come before project-specific includes
(includes specific to this game), while coming after the include
specific to the given file (if any; main.cpp doesn't have any).
2021-09-20 13:47:53 -07:00
Misa
4eb7f973ef Axe NETWORK_[set/get]AchievementProgress()
These are unused.

Ethan originally added them in case Terry wanted achievement
percentages. But he didn't add them, and I don't think the achievements
are changing anytime soon, so it's safe to remove this dead code.
2021-09-19 21:49:54 -07:00
Misa
e13d3af2eb Use stub types instead of intptr_t
This is so there are at least compiler warnings raised if one of the
pointers mismatch their types.
2021-09-17 21:11:25 -07:00
Misa
1a0e720be8 Don't use print formatting for hardcoded strings
If the string is hardcoded, then use compile-time string literal
concatenation instead.

I don't know if compilers are smart enough to recognize when you're
passing in hardcoded strings and to concatenate them into the string
literal at compile time instead. I also don't know that if compilers are
smart enough to recognize that, that further they recognize all the
logging functions are just wrappers around printf, and so they can
perform the same optimization at those function call sites, too. So it's
better to just do the string concatenation explicitly instead.
2021-09-17 14:05:23 -07:00
Misa
32f30020fa Name the return types rettype instead of retval
Minor code style fix. They are return types, not return values.
2021-09-17 13:58:44 -07:00
Misa
9d1659c3a4 De-duplicate Steam network function list
Instead of having three separate copies of the function list, use macro
magic to make it so there is only one list that we use in three
different cases.
2021-09-17 13:55:16 -07:00
Misa
135ff36409 Remove <stdio.h> include from SteamNetwork.c
It's unused.
2021-09-17 13:55:16 -07:00
Misa
6ba7058a0e Fix VSync renderer workaround
SDL just got an API to toggle VSync without having to tear down the
renderer ( libsdl-org/SDL#4157 ). We can remove the workaround and use
that instead. For now, we are putting it behind an ifdef until SDL
2.0.18 officially releases in November.

Fixes #831.
2021-09-14 20:23:22 -07:00
Misa
8d0a90a588 Avoid function call to check empty room name
Instead, a simple comparison of the first element will do.
2021-09-12 21:54:47 -07:00
Misa
ddff461a6c Replace hardcoded temp buffer sizes with a named constant
Constants.h will house constants like the screen size and others. But
basically only the screen size for now.

Now we don't have to type that "4 bytes per 40 chars (whole screen)"
comment everywhere...
2021-09-12 21:40:20 -07:00
Misa
ffe53746bc Rename textbox to textboxes and textbox line to lines
It's really dumb that these array names aren't plural when they should
be, because they contain more than one thing.
2021-09-12 21:06:27 -07:00
Misa
a50e8ecf48 Replace roomnames/hiddennames/glitchnames with const char*
Since those are all downstream recipients of either static storage or
memory that doesn't move for the duration of the custom level, it's okay
to make these be `const char*`s without having to redo any of the RAII
memory management.

mapclass::currentarea() is included in this as well. I also cleaned up
Tower.cpp's headers to fix some transitive includes because I was
removing UtilityClass.h includes from all other level files too.

The "Untitled room" names no longer show any coordinates, because doing
so would require complicated memory management that's completely
unneeded. No one will ever see them, and if they do they already know
they have a problem anyway. The only time they might be able to see them
is if they corrupted the areamap, but this was only possible in 2.2 and
previous by dying outside the room deaths array in Outside Dimension
VVVVVV, which has since been patched out. Besides, sometimes the
"Untitled room" gets overwritten by something else anyway (especially in
Finalclass.cpp), so it really, really doesn't matter.
2021-09-12 21:06:26 -07:00
Misa
a10342f5e6 Replace setblockcolour() argument with const char*
There's no reason it needs to be an std::string here.

Although, realistically, we should be using an enum instead of
string-typing, but, eh, that can be fixed later.
2021-09-12 21:06:26 -07:00
Misa
2991b2341a Fix regression with companions not spawning
Companions would not spawn if you didn't load the current room via a
room transition. This meant that companions wouldn't spawn if you loaded
a save file with a companion, at least not until you moved to a
different room and triggered a screen transition. But most importantly,
it meant that the Intermission 1 supercrewmate would never spawn,
because going to Intermission 1 does a straight gotoroom, and does not
do a room transition.

Turns out the roomchange refactor broke things, because of course it
did. The companion logic was implicitly relying on that bool to be set,
because...? Either way, it doesn't make sense. Using roomchange implied
that the code wanted to be ran only when doing a room transition, which
is clearly not the case here. The best thing to do here is to just move
it to a separate function that gets called at the end of
mapclass::gotoroom().
2021-09-11 22:53:07 -07:00
Misa
a7ae3e0fb0 Remove scmmoveme
So, I ended up breaking supercrewmate spawning with that roomchange
refactor. However, upon investigating how to fix it, I was running into
a weird interpolation issue due to scmmoveme, as well as the companion
spawning in the ground in "Very Good". And I was wondering why I or no
one else ended up running into them.

Well, as it turns out, scmmoveme ends up doing absolutely nothing. There
are only two instances where scmmoveme is used. The first is if you
respawn in "Very Good", and somehow have your scmprogress set to that
room. But that's impossible, because whenever you respawn, your
scmprogress is always set to the one after the room you respawn in. Even
if you respawned in the room previous to "Very Good" (which is "Don't
Get Ahead of Yourself!"), it still wouldn't work, since the logic always
kicks in when a gotoroom happens, and not only when a supercrewmate is
actually spawned. Since the scmprogress doesn't match, that case never
gets triggered, and we get to the second time scmmoveme is used, which
is in the catch-all case that always executes.

This second instance... also does nothing, because since we just
respawned, and our scmprogress got set to the room ahead of us, there is
no supercrewmate on screen. Then getscm() returns 0, and the player is
always indice 0, so the only thing we end up doing is setting the
player's x-position to their own x-position. Brilliant.

Anyway, this code results in interpolation issues and the supercrewmate
spawning in the ground on "Very Good" if you die, when my fix is
applied, because my fix moves this logic around to a different frame
order, and that actually ends up making scmmoveme no longer dead code.

So to recap: we have dead code, which looks like it does something, but
doesn't. But if you move it around in a certain way, it ends up having
harmful effects. One of the joys of working on this game...

It's also hilarious that it gets saved to the save file. Why? The only
time this variable is true, it is for literally less than a frame,
because it always gets set to false, because you always respawn using a
gotoroom whenever the supercrewmate dies, because you never respawn in
the same room as a supercrewmate, because Intermission 1 was
deliberately designed that way (else you'd keep continually dying since
the supercrewmate wouldn't move out of the way).
2021-09-11 22:23:47 -07:00
Misa
029463ad47 Remove unused or useless SDL_Rects from Graphics
These were bfont_rect, bg_rect, foot_rect, and images_rect.

bg_rect was only used once to draw the ghost buffer in the editor, but
that was only because Ally didn't know you could just pass NULL in, cuz
the ghost buffer is the same size as the backbuffer.
2021-09-11 02:24:55 -07:00
Misa
d3a868b566 Axe RGBflip() in favor of getRGB()
RGBflip() does the exact same thing as getRGB(), now that all the
surface masks have been fixed. This axes RGBflip() and changes all
callers to use getRGB() instead. It is more readable that way.

By doing this, there is less copy-pasting. Additionally, it is now
easier to search for RGBf() - which is an ENTIRELY different function
than RGBflip() - now that the name of RGBf is no longer the first four
characters of some different, unrelated function. Previously I would've
had to do `rg 'RGBf[^\w]'` which was stupid and awful and I hated it.
2021-09-11 02:15:20 -07:00
Misa
f237f41d8e Remove useless arguments from drawimagecol()
Turns out, the r, g, and b arguments don't actually do anything!

There was a call to RGBf() in the function. RGBf() is just getRGB() but
first adds 128 and then divides by 3 to each of the color channels
beforehand. Unfortunately, RGBf() does not have any side effects, and
the function threw away the return value. Bravo.

This also reveals that the website images drawn in the credits in the
main menu are only recolored because of a stale `ct` set by the previous
graphics.bigprint(), and not because any color values were passed in to
drawimagecol()... What fun surprises the game has in store for me every
day.
2021-09-11 02:12:03 -07:00
Misa
58ae93c4cc Music: Do not do fades if not playing
This fixes a regression where entering playtesting while a track was
fading out (by exiting out of playtesting with a track playing and then
immediately entering back in with the level start music set) would
result in no music.

The cause is the game doing fades even though nothing is playing, which
puts it in a confusing state.
2021-09-10 19:37:33 -07:00
Misa
8e02b90b76 Move Mix_PausedMusic() call into wrapper function
This wrapper function is for (a) future-proofing (b) proactive
prevention of future copy-pasting (c) to clarify that we never actually
halt music in the SDL_mixer sense, we only pause it, so to check if the
music is halted we actually check if the music is paused instead. This
is important because Mix_PlayingMusic() does not check if the music is
paused and Mix_PausedMusic() does not check if the music is halted.
2021-09-10 19:37:31 -07:00
Misa
06a88eff39 Kludge-fix being able to play music in editor
When you're on the music changing screen in the editor, it plays the
current track. When you return, it stops playing the track. However, if
you press escape, it doesn't stop playing the track. This is because
pressing escape just returns to the previous menu without stopping
playing the track.

To fix this, I just added some kludge in the return menu function. This
is kinda super bad but it works for now and is just something to clean
up later. Maybe like each menu having exit callbacks or something, I
dunno.

This is kinda a regression, kinda sorta not. In 2.2 and previous,
pressing escape would just close the settings menu entirely, which also
bypassed the music fadeout. 2.3 made it so pressing escape doesn't
entirely close the settings menu, and just returns to the previous menu,
which fails in a different way. But the intended way is definitely to
select the return option and having the music fade out.
2021-09-10 18:56:12 -07:00
Misa
e3bfc79d4a Reset some stats that weren't being reset in deletestats
This function now properly deletes the Super Gravitron record, the Super
Gravitron rank, and the best game deaths. They were not being properly
reset previously, meaning you would have to go into your save file to
properly clean out your save data.
2021-09-10 18:02:52 -07:00
Misa
74b7ce9d80 Reset fade booleans when silencing music
This fixes a bug where the music would keep playing when a collection
prompt appeared if the music was still fading in at that time.
2021-09-10 17:02:24 -07:00
Misa
6f499abef0 Fix platv values outside map size being saved as 67372036
If the map size was less than 20x20, platv values outside the map would
end up being saved as 67372036.

This happens because SDL_memset() operates on the byte level, and not
the multi-byte level. So it takes only the lower 8 bits of 4 and repeats
it for each byte in each integer, creating 67372036.
2021-09-10 16:58:53 -07:00
Misa
07bbc5b2de Don't check !muted when fading music after completion prompt
This was done in 2.2 and previous probably to fix the fact that there
were multiple conflicting audio controls (the player wants to mute the
audio but the game wants to fade in the audio), but is now actively
harmful since 2.3, because muting the game while finishing the
completion prompt means the music will never come back in, even after
unmuting.

I also notice that when collecting a custom crewmate, the game checks
for the level's start music instead of if there's actually a current
song playing right now. I don't know why this was done, because it
would've been better to copy-paste the trinket collection logic here.
It's entirely possible for the audio to just be muted and never come
back if the level has no start music but plays a song by using a script.
Anyways, leaving it alone because it's quite possible that a level might
be intentionally designed around this, I can't really tell the
intentions of every level creator, and it's easy to work around (either
don't use custom crewmates, which every modern level basically does
nowadays, or just set the start music).
2021-09-10 15:48:18 -07:00