Commit Graph

213 Commits

Author SHA1 Message Date
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
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
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 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 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 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
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 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
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
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 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 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 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 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 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
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 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 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 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 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 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 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 c64fd89325 Untabify every single file
YOLO.

This is a repeat of #642. As before, I just did

    rg -l '\t' | xargs -n 1 sed -i -e 's/\t/    /g'

inside the desktop_version/ folder.
2021-09-06 18:56:39 -07:00
Misa 9767eb91f4 drawpixeltextbox: Remove now-unused parameters
They go bye-bye.

This is a friendly reminder that the map menu rendering code is heavily
copy-pasted, dear god...
2021-09-06 00:56:49 -07:00
Misa 31844eabc6 Axe drawcustompixeltextbox in favor of drawpixeltextbox
I'm honestly not too sure why drawcustompixeltextbox ever existed? All
it seemed to do was draw even more horizontal/vertical tiles to finish
any gaps in the tiling... which was all completely unnecessary and
wasteful, because even the previous drawpixeltextbox implementation
covered all gaps in all custom level map sizes that I tried.

Anyway, that at least gets rid of one copy-pasted function.
2021-09-06 00:56:48 -07:00
Misa a23014350f Move all editor-specific attributes to a new editorclass
This is a pretty hefty commit! But essentially, I made a new editorclass
object, and moved all functions and variables that only get used in the
in-game level editor to that class. This cleanly demarcates which things
are in the editor and which things are just general custom level stuff.

Then I fixed up all the callers. I also fixed up some NO_CUSTOM_LEVELS
and NO_EDITOR ifdefs, too, in several places.
2021-09-01 15:30:02 -07:00
Misa 3e380e23fb Rename editor.h to CustomLevels.h
This accompanies the editor.cpp -> CustomLevels.cpp change; I'll be
splitting out the editor functions in the next commit. The name of the
include guard has been changed as well, but not anything else.
2021-09-01 15:30:02 -07:00
Misa 5abe615507 Fix Pauli Kohberger's name stopping being drawn too early
This is because the y-position of the graphics.onscreen() check was a
little too high. Then their name (under Beta Testing) would suddenly
disappear too early. You'd have to look real close to spot it, but it
does happen. It's cuz the credits are all kinda hardcoded, which is
probably bad, but fixing that would have to come later...
2021-08-31 23:23:27 -07:00
Misa 4c69281738 Move Misa to C++ credits
I talked with Ethan earlier about this. For 2.3, he wanted me in GitHub
contributors (well, still separate from the rest), to really highlight
the source-code-release community-driven nature of 2.3, but he said it'd
be fine to put me in C++ credits in 2.4.
2021-08-31 23:22:22 -07:00