2020-09-28 04:15:06 +02:00
|
|
|
#define GRAPHICS_DEFINITION
|
2020-01-01 21:29:24 +01:00
|
|
|
#include "Graphics.h"
|
2020-07-19 21:43:29 +02:00
|
|
|
|
2021-11-12 08:52:47 +01:00
|
|
|
#include <SDL.h>
|
2020-07-19 21:43:29 +02:00
|
|
|
#include <utf8/unchecked.h>
|
|
|
|
|
2022-12-01 07:30:16 +01:00
|
|
|
#include "Alloc.h"
|
2021-09-25 01:37:27 +02:00
|
|
|
#include "Constants.h"
|
2021-02-20 08:19:09 +01:00
|
|
|
#include "CustomLevels.h"
|
2020-01-01 21:29:24 +01:00
|
|
|
#include "Entity.h"
|
2021-02-16 03:53:17 +01:00
|
|
|
#include "Exit.h"
|
2020-07-19 21:43:29 +02:00
|
|
|
#include "FileSystemUtils.h"
|
Fix filter/screenshake/flash update order
In 2.2, at render time, the game rendered screenshakes and flashes if
their timers were above 0, and then decremented them afterwards. The
game would also update the analogue filter right before rendering it,
too.
In 2.3, this was changed so the flash and screenshake timers were
unified, and also done at the end of the frame - right before rendering
happened. This resulted in 1-frame flashes and screenshakes not
rendering at all. The other changes in this patchset don't fix this
either. The analogue filter was also in the wrong order, but that is
less of an issue than flashes and screenshakes.
So, what I've done is made the flash and screenshake timers update right
before the loop switches over to rendering, and only decrements them
when we switch back to fixed functions (after rendering). The analogue
filter is also updated right before rendering as well. This restores
1-frame flashes and screenshakes, as well as restores the correct order
of analogue filter updates.
2021-03-18 01:53:17 +01:00
|
|
|
#include "GraphicsUtil.h"
|
2022-12-30 22:57:24 +01:00
|
|
|
#include "Localization.h"
|
2020-01-01 21:29:24 +01:00
|
|
|
#include "Map.h"
|
2020-07-19 21:05:41 +02:00
|
|
|
#include "Music.h"
|
2022-12-30 22:57:24 +01:00
|
|
|
#include "RoomnameTranslator.h"
|
2020-01-01 21:29:24 +01:00
|
|
|
#include "Screen.h"
|
2020-07-19 21:05:41 +02:00
|
|
|
#include "UtilityClass.h"
|
2022-12-30 22:57:24 +01:00
|
|
|
#include "VFormat.h"
|
2021-02-24 00:21:29 +01:00
|
|
|
#include "Vlogging.h"
|
2020-01-01 21:29:24 +01:00
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::init(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
flipmode = false;
|
|
|
|
setRect(tiles_rect, 0,0,8,8);
|
|
|
|
setRect(sprites_rect, 0,0,32,32);
|
|
|
|
setRect(footerrect, 0, 230, 320, 10);
|
|
|
|
setRect(prect, 0, 0, 4, 4);
|
|
|
|
setRect(line_rect, 0,0,0,0);
|
|
|
|
setRect(tele_rect,0,0,96,96);
|
2020-11-02 19:44:53 +01:00
|
|
|
setRect(towerbuffer_rect, 8, 8, 320, 240);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
//We initialise a few things
|
|
|
|
|
2020-04-02 22:05:48 +02:00
|
|
|
linestate = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
trinketcolset = false;
|
|
|
|
|
|
|
|
showcutscenebars = false;
|
2021-03-20 07:08:35 +01:00
|
|
|
setbars(0);
|
2020-01-17 18:37:53 +01:00
|
|
|
notextoutline = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
flipmode = false;
|
|
|
|
setflipmode = false;
|
|
|
|
|
|
|
|
//Background inits
|
2020-07-03 11:31:13 +02:00
|
|
|
for (int i = 0; i < numstars; i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).
Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)
We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 20:13:12 +02:00
|
|
|
SDL_Rect s = {(int) (fRandom() * 320), (int) (fRandom() * 240), 2, 2};
|
2020-01-01 21:29:24 +01:00
|
|
|
int s2 = 4+(fRandom()*4);
|
2020-07-03 11:31:13 +02:00
|
|
|
stars[i] = s;
|
|
|
|
starsspeed[i] = s2;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-07-03 11:31:13 +02:00
|
|
|
for (int i = 0; i < numbackboxes; i++)
|
|
|
|
{
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect bb;
|
|
|
|
int bvx = 0;
|
|
|
|
int bvy = 0;
|
|
|
|
if(fRandom()*100 > 50)
|
|
|
|
{
|
|
|
|
bvx = 9 - (fRandom() * 19);
|
|
|
|
if (bvx > -6 && bvx < 6) bvx = 6;
|
|
|
|
bvx = bvx * 1.5;
|
|
|
|
setRect(bb, fRandom() * 320, fRandom() * 240, 32, 12);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bvy = 9 - (fRandom() * 19);
|
|
|
|
if (bvy > -6 && bvy < 6) bvy = 6;
|
|
|
|
bvy = bvy * 1.5;
|
|
|
|
setRect(bb, fRandom() * 320, fRandom() * 240, 12, 32) ;
|
|
|
|
}
|
|
|
|
float bint = 0.5 + ((fRandom() * 100) / 200);
|
2020-07-03 11:31:13 +02:00
|
|
|
backboxes[i] = bb;
|
|
|
|
backboxvx[i] = bvx;
|
|
|
|
backboxvy[i] = bvy;
|
|
|
|
backboxint[i] = bint;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
backoffset = 0;
|
|
|
|
backgrounddrawn = false;
|
|
|
|
|
|
|
|
warpskip = 0;
|
|
|
|
|
|
|
|
spcol = 0;
|
|
|
|
spcoldel = 0;
|
2020-04-02 22:05:48 +02:00
|
|
|
rcol = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
crewframe = 0;
|
|
|
|
crewframedelay = 4;
|
|
|
|
menuoffset = 0;
|
2020-04-29 05:46:33 +02:00
|
|
|
oldmenuoffset = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
resumegamemode = false;
|
|
|
|
|
|
|
|
//Fading stuff
|
2020-07-03 11:40:57 +02:00
|
|
|
SDL_memset(fadebars, 0, sizeof(fadebars));
|
2020-01-12 18:26:00 +01:00
|
|
|
|
2021-03-20 07:09:11 +01:00
|
|
|
setfade(0);
|
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 09:57:47 +02:00
|
|
|
fademode = FADE_NONE;
|
|
|
|
ingame_fademode = FADE_NONE;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-01-11 01:37:23 +01:00
|
|
|
// initialize everything else to zero
|
2020-01-11 17:33:36 +01:00
|
|
|
backBuffer = NULL;
|
2020-01-11 01:37:23 +01:00
|
|
|
foregrounddrawn = false;
|
2020-01-11 17:33:36 +01:00
|
|
|
foregroundBuffer = NULL;
|
2020-01-11 01:37:23 +01:00
|
|
|
backgrounddrawn = false;
|
|
|
|
m = 0;
|
|
|
|
linedelay = 0;
|
2020-01-11 17:33:36 +01:00
|
|
|
menubuffer = NULL;
|
|
|
|
tempBuffer = NULL;
|
2020-11-03 01:54:17 +01:00
|
|
|
warpbuffer = NULL;
|
|
|
|
warpbuffer_lerp = NULL;
|
2020-07-06 22:04:34 +02:00
|
|
|
footerbuffer = NULL;
|
|
|
|
ghostbuffer = NULL;
|
2020-11-03 00:05:24 +01:00
|
|
|
towerbg = TowerBG();
|
2020-11-03 00:23:53 +01:00
|
|
|
titlebg = TowerBG();
|
2020-01-11 01:37:23 +01:00
|
|
|
trinketr = 0;
|
|
|
|
trinketg = 0;
|
|
|
|
trinketb = 0;
|
2020-01-25 05:43:04 +01:00
|
|
|
|
|
|
|
translucentroomname = false;
|
2020-04-29 01:02:55 +02:00
|
|
|
|
|
|
|
alpha = 1.0f;
|
2020-04-29 02:29:59 +02:00
|
|
|
|
|
|
|
screenshake_x = 0;
|
|
|
|
screenshake_y = 0;
|
2020-05-02 01:40:35 +02:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_zero(col_crewred);
|
|
|
|
SDL_zero(col_crewyellow);
|
|
|
|
SDL_zero(col_crewgreen);
|
|
|
|
SDL_zero(col_crewcyan);
|
|
|
|
SDL_zero(col_crewblue);
|
|
|
|
SDL_zero(col_crewpurple);
|
|
|
|
SDL_zero(col_crewinactive);
|
|
|
|
SDL_zero(col_clock);
|
|
|
|
SDL_zero(col_trinket);
|
2020-05-02 01:40:35 +02:00
|
|
|
col_tr = 0;
|
|
|
|
col_tg = 0;
|
|
|
|
col_tb = 0;
|
2020-05-02 21:06:40 +02:00
|
|
|
|
|
|
|
kludgeswnlinewidth = false;
|
Make one-way recolors check for specific files
So, 2.3 added recoloring one-way tiles to no longer make them be always
yellow. However, custom levels that retexture the one-way tiles might
not want them to be recolored. So, if there are ANY custom assets
mounted, then the one-ways will not be recolored. However, if the XML
has a <onewaycol_override>1</onewaycol_override> tag, then the one-way
will be recolored again anyways.
When I added one-way recoloring, I didn't intend for any custom asset to
disable the recoloring; I only did it because I couldn't find a way to
check if a specific file was customized by the custom level or not.
However, I have figured out how to do so, and so now tiles.png one-way
recolors will only be disabled if there's a custom tiles.png, and
tiles2.png one-way recolors will only be disabled if there's a custom
tiles2.png.
In order to make sure we're not calling PhysFS functions on every single
deltaframe, I've added caching variables, tiles1_mounted and
tiles2_mounted, to Graphics; these get assigned every time
reloadresources() is called.
2021-03-06 19:52:11 +01:00
|
|
|
|
|
|
|
#ifndef NO_CUSTOM_LEVELS
|
|
|
|
tiles1_mounted = false;
|
|
|
|
tiles2_mounted = false;
|
2021-04-19 08:39:10 +02:00
|
|
|
minimap_mounted = false;
|
Make one-way recolors check for specific files
So, 2.3 added recoloring one-way tiles to no longer make them be always
yellow. However, custom levels that retexture the one-way tiles might
not want them to be recolored. So, if there are ANY custom assets
mounted, then the one-ways will not be recolored. However, if the XML
has a <onewaycol_override>1</onewaycol_override> tag, then the one-way
will be recolored again anyways.
When I added one-way recoloring, I didn't intend for any custom asset to
disable the recoloring; I only did it because I couldn't find a way to
check if a specific file was customized by the custom level or not.
However, I have figured out how to do so, and so now tiles.png one-way
recolors will only be disabled if there's a custom tiles.png, and
tiles2.png one-way recolors will only be disabled if there's a custom
tiles2.png.
In order to make sure we're not calling PhysFS functions on every single
deltaframe, I've added caching variables, tiles1_mounted and
tiles2_mounted, to Graphics; these get assigned every time
reloadresources() is called.
2021-03-06 19:52:11 +01:00
|
|
|
#endif
|
2021-08-07 05:57:34 +02:00
|
|
|
|
2022-12-30 22:57:24 +01:00
|
|
|
gamecomplete_mounted = false;
|
|
|
|
levelcomplete_mounted = false;
|
|
|
|
flipgamecomplete_mounted = false;
|
|
|
|
fliplevelcomplete_mounted = false;
|
|
|
|
|
2021-08-07 05:57:34 +02:00
|
|
|
SDL_zeroa(error);
|
|
|
|
SDL_zeroa(error_title);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::destroy(void)
|
2021-02-16 01:13:18 +01:00
|
|
|
{
|
|
|
|
#define CLEAR_ARRAY(name) \
|
|
|
|
for (size_t i = 0; i < name.size(); i += 1) \
|
|
|
|
{ \
|
2022-12-01 07:30:16 +01:00
|
|
|
VVV_freefunc(SDL_FreeSurface, name[i]); \
|
2021-02-16 01:13:18 +01:00
|
|
|
} \
|
|
|
|
name.clear();
|
|
|
|
|
|
|
|
CLEAR_ARRAY(tiles)
|
|
|
|
CLEAR_ARRAY(tiles2)
|
|
|
|
CLEAR_ARRAY(tiles3)
|
|
|
|
CLEAR_ARRAY(entcolours)
|
|
|
|
CLEAR_ARRAY(sprites)
|
|
|
|
CLEAR_ARRAY(flipsprites)
|
|
|
|
CLEAR_ARRAY(tele)
|
|
|
|
CLEAR_ARRAY(bfont)
|
|
|
|
CLEAR_ARRAY(flipbfont)
|
|
|
|
|
|
|
|
#undef CLEAR_ARRAY
|
|
|
|
}
|
|
|
|
|
2021-02-16 01:18:45 +01:00
|
|
|
void Graphics::create_buffers(const SDL_PixelFormat* fmt)
|
|
|
|
{
|
|
|
|
#define CREATE_SURFACE(w, h) \
|
|
|
|
SDL_CreateRGBSurface( \
|
|
|
|
SDL_SWSURFACE, \
|
|
|
|
w, h, \
|
|
|
|
fmt->BitsPerPixel, \
|
|
|
|
fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask \
|
|
|
|
)
|
|
|
|
backBuffer = CREATE_SURFACE(320, 240);
|
|
|
|
SDL_SetSurfaceBlendMode(backBuffer, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
footerbuffer = CREATE_SURFACE(320, 10);
|
|
|
|
SDL_SetSurfaceBlendMode(footerbuffer, SDL_BLENDMODE_BLEND);
|
|
|
|
SDL_SetSurfaceAlphaMod(footerbuffer, 127);
|
2023-01-02 01:36:43 +01:00
|
|
|
FillRect(footerbuffer, 0, 0, 0);
|
2021-02-16 01:18:45 +01:00
|
|
|
|
2022-12-30 22:57:24 +01:00
|
|
|
roomname_translator::dimbuffer = CREATE_SURFACE(320, 240);
|
|
|
|
SDL_SetSurfaceBlendMode(roomname_translator::dimbuffer, SDL_BLENDMODE_BLEND);
|
|
|
|
SDL_SetSurfaceAlphaMod(roomname_translator::dimbuffer, 96);
|
2023-01-02 01:36:43 +01:00
|
|
|
FillRect(roomname_translator::dimbuffer, 0, 0, 0);
|
2022-12-30 22:57:24 +01:00
|
|
|
|
2021-02-16 01:18:45 +01:00
|
|
|
ghostbuffer = CREATE_SURFACE(320, 240);
|
|
|
|
SDL_SetSurfaceBlendMode(ghostbuffer, SDL_BLENDMODE_BLEND);
|
|
|
|
SDL_SetSurfaceAlphaMod(ghostbuffer, 127);
|
|
|
|
|
|
|
|
foregroundBuffer = CREATE_SURFACE(320, 240);
|
|
|
|
SDL_SetSurfaceBlendMode(foregroundBuffer, SDL_BLENDMODE_BLEND);
|
|
|
|
|
|
|
|
menubuffer = CREATE_SURFACE(320, 240);
|
|
|
|
SDL_SetSurfaceBlendMode(menubuffer, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
warpbuffer = CREATE_SURFACE(320 + 16, 240 + 16);
|
|
|
|
SDL_SetSurfaceBlendMode(warpbuffer, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
warpbuffer_lerp = CREATE_SURFACE(320 + 16, 240 + 16);
|
|
|
|
SDL_SetSurfaceBlendMode(warpbuffer_lerp, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
towerbg.buffer = CREATE_SURFACE(320 + 16, 240 + 16);
|
|
|
|
SDL_SetSurfaceBlendMode(towerbg.buffer, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
towerbg.buffer_lerp = CREATE_SURFACE(320 + 16, 240 + 16);
|
|
|
|
SDL_SetSurfaceBlendMode(towerbg.buffer_lerp, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
titlebg.buffer = CREATE_SURFACE(320 + 16, 240 + 16);
|
|
|
|
SDL_SetSurfaceBlendMode(titlebg.buffer, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
titlebg.buffer_lerp = CREATE_SURFACE(320 + 16, 240 + 16);
|
|
|
|
SDL_SetSurfaceBlendMode(titlebg.buffer_lerp, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
tempBuffer = CREATE_SURFACE(320, 240);
|
|
|
|
SDL_SetSurfaceBlendMode(tempBuffer, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
#undef CREATE_SURFACE
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::destroy_buffers(void)
|
2021-02-16 01:16:52 +01:00
|
|
|
{
|
2022-12-01 07:30:16 +01:00
|
|
|
#define FREE_SURFACE(SURFACE) VVV_freefunc(SDL_FreeSurface, SURFACE)
|
|
|
|
|
|
|
|
FREE_SURFACE(backBuffer);
|
|
|
|
FREE_SURFACE(footerbuffer);
|
2022-12-30 22:57:24 +01:00
|
|
|
FREE_SURFACE(roomname_translator::dimbuffer);
|
2022-12-01 07:30:16 +01:00
|
|
|
FREE_SURFACE(ghostbuffer);
|
|
|
|
FREE_SURFACE(foregroundBuffer);
|
|
|
|
FREE_SURFACE(menubuffer);
|
|
|
|
FREE_SURFACE(warpbuffer);
|
|
|
|
FREE_SURFACE(warpbuffer_lerp);
|
|
|
|
FREE_SURFACE(towerbg.buffer);
|
|
|
|
FREE_SURFACE(towerbg.buffer_lerp);
|
|
|
|
FREE_SURFACE(titlebg.buffer);
|
|
|
|
FREE_SURFACE(titlebg.buffer_lerp);
|
|
|
|
FREE_SURFACE(tempBuffer);
|
2021-02-16 01:16:52 +01:00
|
|
|
|
|
|
|
#undef FREE_SURFACE
|
|
|
|
}
|
|
|
|
|
2021-02-16 01:21:27 +01:00
|
|
|
int Graphics::font_idx(uint32_t ch)
|
|
|
|
{
|
|
|
|
if (font_positions.size() > 0)
|
|
|
|
{
|
2020-01-31 19:25:37 +01:00
|
|
|
std::map<int, int>::iterator iter = font_positions.find(ch);
|
2021-02-16 01:21:27 +01:00
|
|
|
if (iter == font_positions.end())
|
|
|
|
{
|
2020-01-31 19:25:37 +01:00
|
|
|
iter = font_positions.find('?');
|
2021-02-16 01:21:27 +01:00
|
|
|
if (iter == font_positions.end())
|
|
|
|
{
|
2021-08-07 06:06:04 +02:00
|
|
|
WHINE_ONCE("font.txt missing fallback character!");
|
|
|
|
return -1;
|
2020-01-31 19:25:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return iter->second;
|
2021-02-16 01:21:27 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-01-31 19:25:37 +01:00
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawspritesetcol(int x, int y, int t, int c)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-09-08 09:31:44 +02:00
|
|
|
if (!INBOUNDS_VEC(t, sprites))
|
2020-06-14 03:35:12 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect,x,y,sprites_rect.w,sprites_rect.h);
|
2023-01-02 05:16:08 +01:00
|
|
|
const SDL_Color ct = getcol(c);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
BlitSurfaceColoured(sprites[t],NULL,backBuffer, &rect, ct);
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::updatetitlecolours(void)
|
2020-05-02 01:40:35 +02:00
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
col_crewred = getcol(15);
|
|
|
|
col_crewyellow = getcol(14);
|
|
|
|
col_crewgreen = getcol(13);
|
|
|
|
col_crewcyan = getcol(0);
|
|
|
|
col_crewblue = getcol(16);
|
|
|
|
col_crewpurple = getcol(20);
|
|
|
|
col_crewinactive = getcol(19);
|
|
|
|
|
|
|
|
col_clock = getcol(18);
|
|
|
|
col_trinket = getcol(18);
|
2020-05-02 01:40:35 +02:00
|
|
|
}
|
|
|
|
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
#define PROCESS_TILESHEET_CHECK_ERROR(tilesheet, tile_square) \
|
2021-04-18 19:57:48 +02:00
|
|
|
if (grphx.im_##tilesheet == NULL) \
|
|
|
|
{ \
|
|
|
|
/* We have already asserted; just no-op. */ \
|
|
|
|
} \
|
|
|
|
else if (grphx.im_##tilesheet->w % tile_square != 0 \
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
|| grphx.im_##tilesheet->h % tile_square != 0) \
|
|
|
|
{ \
|
2021-08-07 05:57:34 +02:00
|
|
|
static const char error_fmt[] = "%s.png dimensions not exact multiples of %i!"; \
|
|
|
|
static const char error_title_fmt[] = "Error with %s.png"; \
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
\
|
2021-08-07 05:57:34 +02:00
|
|
|
SDL_snprintf(error, sizeof(error), error_fmt, #tilesheet, tile_square); \
|
|
|
|
SDL_snprintf(error_title, sizeof(error_title), error_title_fmt, #tilesheet); \
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
\
|
2021-12-05 15:50:20 +01:00
|
|
|
vlog_error("%s", error); \
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
\
|
2021-08-07 05:57:34 +02:00
|
|
|
return false; \
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#define PROCESS_TILESHEET_RENAME(tilesheet, vector, tile_square, extra_code) \
|
|
|
|
PROCESS_TILESHEET_CHECK_ERROR(tilesheet, tile_square) \
|
|
|
|
\
|
2021-04-18 19:57:48 +02:00
|
|
|
else \
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
{ \
|
2021-04-18 19:57:48 +02:00
|
|
|
int j; \
|
|
|
|
for (j = 0; j < grphx.im_##tilesheet->h / tile_square; ++j) \
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
{ \
|
2021-04-18 19:57:48 +02:00
|
|
|
int i; \
|
|
|
|
for (i = 0; i < grphx.im_##tilesheet->w / tile_square; ++i) \
|
|
|
|
{ \
|
|
|
|
SDL_Surface* temp = GetSubSurface( \
|
|
|
|
grphx.im_##tilesheet, \
|
|
|
|
i * tile_square, j * tile_square, \
|
|
|
|
tile_square, tile_square \
|
|
|
|
); \
|
|
|
|
vector.push_back(temp); \
|
|
|
|
\
|
|
|
|
extra_code \
|
|
|
|
} \
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
} \
|
2021-04-18 19:57:48 +02:00
|
|
|
\
|
2022-12-01 07:30:16 +01:00
|
|
|
VVV_freefunc(SDL_FreeSurface, grphx.im_##tilesheet); \
|
2021-04-18 19:57:48 +02:00
|
|
|
}
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
|
|
|
|
#define PROCESS_TILESHEET(tilesheet, tile_square, extra_code) \
|
|
|
|
PROCESS_TILESHEET_RENAME(tilesheet, tilesheet, tile_square, extra_code)
|
|
|
|
|
2021-08-07 05:57:34 +02:00
|
|
|
bool Graphics::Makebfont(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
PROCESS_TILESHEET(bfont, 8,
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
SDL_Surface* TempFlipped = FlipSurfaceVerticle(temp);
|
|
|
|
flipbfont.push_back(TempFlipped);
|
|
|
|
})
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2022-12-30 22:57:24 +01:00
|
|
|
unsigned char* charmap = NULL;
|
2020-01-31 19:25:37 +01:00
|
|
|
size_t length;
|
2022-12-30 22:57:24 +01:00
|
|
|
if (FILESYSTEM_areAssetsInSameRealDir("graphics/font.png", "graphics/font.txt"))
|
|
|
|
{
|
|
|
|
FILESYSTEM_loadAssetToMemory("graphics/font.txt", &charmap, &length, false);
|
|
|
|
}
|
2020-09-25 21:55:12 +02:00
|
|
|
if (charmap != NULL)
|
|
|
|
{
|
2020-01-31 19:25:37 +01:00
|
|
|
unsigned char* current = charmap;
|
|
|
|
unsigned char* end = charmap + length;
|
|
|
|
int pos = 0;
|
2020-09-25 21:55:12 +02:00
|
|
|
while (current != end)
|
|
|
|
{
|
2020-01-31 19:25:37 +01:00
|
|
|
int codepoint = utf8::unchecked::next(current);
|
|
|
|
font_positions[codepoint] = pos;
|
|
|
|
++pos;
|
|
|
|
}
|
2022-12-01 07:30:16 +01:00
|
|
|
VVV_free(charmap);
|
2020-09-25 21:55:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-25 21:52:34 +02:00
|
|
|
font_positions.clear();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2021-08-07 05:57:34 +02:00
|
|
|
|
|
|
|
return true;
|
2020-01-31 19:25:37 +01:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-09-25 21:55:12 +02:00
|
|
|
int Graphics::bfontlen(uint32_t ch)
|
|
|
|
{
|
|
|
|
if (ch < 32)
|
|
|
|
{
|
2020-01-31 19:25:37 +01:00
|
|
|
return 6;
|
2020-09-25 21:55:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-01-31 19:25:37 +01:00
|
|
|
return 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-07 05:57:34 +02:00
|
|
|
bool Graphics::MakeTileArray(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-04-11 01:59:05 +02:00
|
|
|
PROCESS_TILESHEET(tiles, 8, {})
|
|
|
|
PROCESS_TILESHEET(tiles2, 8, {})
|
|
|
|
PROCESS_TILESHEET(tiles3, 8, {})
|
|
|
|
PROCESS_TILESHEET(entcolours, 8, {})
|
2021-08-07 05:57:34 +02:00
|
|
|
|
|
|
|
return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-08-07 05:57:34 +02:00
|
|
|
bool Graphics::maketelearray(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-04-11 01:59:05 +02:00
|
|
|
PROCESS_TILESHEET_RENAME(teleporter, tele, 96, {})
|
2021-08-07 05:57:34 +02:00
|
|
|
|
|
|
|
return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-08-07 05:57:34 +02:00
|
|
|
bool Graphics::MakeSpriteArray(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-04-11 01:59:05 +02:00
|
|
|
PROCESS_TILESHEET(sprites, 32, {})
|
|
|
|
PROCESS_TILESHEET(flipsprites, 32, {})
|
2021-08-07 05:57:34 +02:00
|
|
|
|
|
|
|
return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.
This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)
Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:59:47 +02:00
|
|
|
#undef PROCESS_TILESHEET
|
|
|
|
#undef PROCESS_TILESHEET_RENAME
|
|
|
|
#undef PROCESS_TILESHEET_CHECK_ERROR
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2022-12-31 01:48:27 +01:00
|
|
|
void Graphics::map_tab(int opt, const char* text, bool selected /*= false*/)
|
2020-06-21 03:33:55 +02:00
|
|
|
{
|
2022-12-31 01:48:27 +01:00
|
|
|
int x = opt*80 + 40;
|
2020-06-21 03:33:55 +02:00
|
|
|
if (selected)
|
|
|
|
{
|
2022-12-31 01:48:27 +01:00
|
|
|
char buffer[SCREEN_WIDTH_CHARS + 1];
|
|
|
|
vformat_buf(buffer, sizeof(buffer), loc::get_langmeta()->menu_select_tight.c_str(), "label:str", text);
|
|
|
|
Print(x - len(buffer)/2, 220, buffer, 196, 196, 255 - help.glow);
|
2020-06-21 03:33:55 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-12-31 01:48:27 +01:00
|
|
|
Print(x - len(text)/2, 220, text, 64, 64, 64);
|
2020-06-21 03:33:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-23 00:23:15 +02:00
|
|
|
void Graphics::map_option(int opt, int num_opts, const std::string& text, bool selected /*= false*/)
|
|
|
|
{
|
|
|
|
int x = 80 + opt*32;
|
|
|
|
int y = 136; // start from middle of menu
|
|
|
|
|
|
|
|
int yoff = -(num_opts * 12) / 2; // could be simplified to -num_opts * 6, this conveys my intent better though
|
|
|
|
yoff += opt * 12;
|
|
|
|
|
|
|
|
if (flipmode)
|
|
|
|
{
|
|
|
|
y -= yoff; // going down, which in Flip Mode means going up
|
|
|
|
y -= 40;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
y += yoff; // going up
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selected)
|
|
|
|
{
|
2022-12-30 23:39:12 +01:00
|
|
|
std::string text_upper(loc::toupper(text));
|
|
|
|
|
|
|
|
char buffer[SCREEN_WIDTH_CHARS + 1];
|
|
|
|
vformat_buf(buffer, sizeof(buffer), loc::get_langmeta()->menu_select.c_str(), "label:str", text_upper.c_str());
|
|
|
|
Print(x - 16, y, buffer, 196, 196, 255 - help.glow);
|
2020-06-23 00:23:15 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::remove_toupper_escape_chars(text), 96, 96, 96);
|
2020-06-23 00:23:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-07 00:18:22 +02:00
|
|
|
static void print_char(
|
|
|
|
SDL_Surface* const buffer,
|
|
|
|
SDL_Surface* const font,
|
|
|
|
const int x,
|
|
|
|
const int y,
|
|
|
|
const int scale,
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color color
|
2021-09-07 00:18:22 +02:00
|
|
|
) {
|
|
|
|
SDL_Rect font_rect = {x, y, 8*scale, 8*scale};
|
|
|
|
SDL_Surface* surface;
|
|
|
|
|
|
|
|
if (scale > 1)
|
|
|
|
{
|
|
|
|
surface = ScaleSurface(font, 8 * scale, 8 * scale);
|
|
|
|
if (surface == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
surface = font;
|
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
BlitSurfaceColoured(surface, NULL, buffer, &font_rect, color);
|
2021-09-07 00:18:22 +02:00
|
|
|
|
|
|
|
if (scale > 1)
|
|
|
|
{
|
2022-12-01 07:30:16 +01:00
|
|
|
VVV_freefunc(SDL_FreeSurface, surface);
|
2021-09-07 00:18:22 +02:00
|
|
|
}
|
2020-02-10 03:23:12 +01:00
|
|
|
}
|
|
|
|
|
2021-09-07 00:18:22 +02:00
|
|
|
void Graphics::do_print(
|
|
|
|
const int x,
|
|
|
|
const int y,
|
|
|
|
const std::string& text,
|
|
|
|
int r,
|
|
|
|
int g,
|
|
|
|
int b,
|
|
|
|
int a,
|
|
|
|
const int scale
|
|
|
|
) {
|
2020-06-14 03:46:32 +02:00
|
|
|
std::vector<SDL_Surface*>& font = flipmode ? flipbfont : bfont;
|
|
|
|
|
2021-09-07 00:18:22 +02:00
|
|
|
int position = 0;
|
|
|
|
std::string::const_iterator iter = text.begin();
|
|
|
|
|
2021-12-23 01:55:07 +01:00
|
|
|
r = SDL_clamp(r, 0, 255);
|
|
|
|
g = SDL_clamp(g, 0, 255);
|
|
|
|
b = SDL_clamp(b, 0, 255);
|
|
|
|
a = SDL_clamp(a, 0, 255);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2023-01-02 05:16:08 +01:00
|
|
|
const SDL_Color ct = getRGBA(r, g, b, a);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 00:18:22 +02:00
|
|
|
while (iter != text.end())
|
|
|
|
{
|
|
|
|
const uint32_t character = utf8::unchecked::next(iter);
|
|
|
|
const int idx = font_idx(character);
|
|
|
|
|
2020-09-08 09:31:44 +02:00
|
|
|
if (INBOUNDS_VEC(idx, font))
|
2020-06-14 03:56:59 +02:00
|
|
|
{
|
2021-09-07 00:18:22 +02:00
|
|
|
print_char(backBuffer, font[idx], x + position, y, scale, ct);
|
2020-06-14 03:56:59 +02:00
|
|
|
}
|
2021-09-07 00:18:22 +02:00
|
|
|
|
|
|
|
position += bfontlen(character) * scale;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-07 00:41:49 +02:00
|
|
|
void Graphics::Print( int _x, int _y, const std::string& _s, int r, int g, int b, bool cen /*= false*/ ) {
|
2021-09-07 00:18:22 +02:00
|
|
|
return PrintAlpha(_x,_y,_s,r,g,b,255,cen);
|
|
|
|
}
|
|
|
|
|
2021-09-07 00:41:49 +02:00
|
|
|
void Graphics::PrintAlpha( int _x, int _y, const std::string& _s, int r, int g, int b, int a, bool cen /*= false*/ )
|
2021-09-07 00:18:22 +02:00
|
|
|
{
|
|
|
|
if (cen)
|
|
|
|
_x = ((160 ) - ((len(_s)) / 2));
|
|
|
|
|
|
|
|
return do_print(_x, _y, _s, r, g, b, a, 1);
|
|
|
|
}
|
|
|
|
|
2021-08-07 05:55:09 +02:00
|
|
|
bool Graphics::next_wrap(
|
|
|
|
size_t* start,
|
|
|
|
size_t* len,
|
|
|
|
const char* str,
|
|
|
|
const int maxwidth
|
|
|
|
) {
|
|
|
|
/* This function is UTF-8 aware. But start/len still are bytes. */
|
|
|
|
size_t idx = 0;
|
|
|
|
size_t lenfromlastspace = 0;
|
|
|
|
size_t lastspace = 0;
|
|
|
|
int linewidth = 0;
|
|
|
|
*len = 0;
|
|
|
|
|
|
|
|
if (str[idx] == '\0')
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
/* FIXME: This only checks one byte, not multiple! */
|
|
|
|
if ((str[idx] & 0xC0) == 0x80)
|
|
|
|
{
|
|
|
|
/* Skip continuation byte. */
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
|
|
|
|
linewidth += bfontlen(str[idx]);
|
|
|
|
|
|
|
|
switch (str[idx])
|
|
|
|
{
|
|
|
|
case ' ':
|
2022-12-30 22:57:24 +01:00
|
|
|
if (loc::get_langmeta()->autowordwrap)
|
|
|
|
{
|
|
|
|
lenfromlastspace = idx;
|
|
|
|
lastspace = *start;
|
|
|
|
}
|
2021-08-07 05:55:09 +02:00
|
|
|
break;
|
|
|
|
case '\n':
|
2022-12-30 22:57:24 +01:00
|
|
|
case '|':
|
2021-08-07 05:55:09 +02:00
|
|
|
*start += 1;
|
2021-11-12 08:48:41 +01:00
|
|
|
SDL_FALLTHROUGH;
|
2021-08-07 05:55:09 +02:00
|
|
|
case '\0':
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (linewidth > maxwidth)
|
|
|
|
{
|
|
|
|
if (lenfromlastspace != 0)
|
|
|
|
{
|
|
|
|
*len = lenfromlastspace;
|
|
|
|
*start = lastspace + 1;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
next:
|
|
|
|
idx += 1;
|
|
|
|
*start += 1;
|
|
|
|
*len += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Graphics::next_wrap_s(
|
|
|
|
char buffer[],
|
|
|
|
const size_t buffer_size,
|
|
|
|
size_t* start,
|
|
|
|
const char* str,
|
|
|
|
const int maxwidth
|
|
|
|
) {
|
|
|
|
size_t len = 0;
|
|
|
|
const size_t prev_start = *start;
|
|
|
|
|
|
|
|
const bool retval = next_wrap(start, &len, &str[*start], maxwidth);
|
|
|
|
|
|
|
|
if (retval)
|
|
|
|
{
|
|
|
|
/* Like next_split_s(), don't use SDL_strlcpy() here. */
|
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-23 01:43:31 +01:00
|
|
|
const size_t length = SDL_min(buffer_size - 1, len);
|
2021-08-07 05:55:09 +02:00
|
|
|
SDL_memcpy(buffer, &str[prev_start], length);
|
|
|
|
buffer[length] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2022-12-30 22:57:24 +01:00
|
|
|
int Graphics::PrintWrap(
|
2021-08-07 05:55:09 +02:00
|
|
|
const int x,
|
|
|
|
int y,
|
2022-12-30 22:57:24 +01:00
|
|
|
std::string s,
|
2021-08-07 05:55:09 +02:00
|
|
|
const int r,
|
|
|
|
const int g,
|
|
|
|
const int b,
|
2022-12-30 22:57:24 +01:00
|
|
|
const bool cen /*= false*/,
|
|
|
|
int linespacing /*= -1*/,
|
|
|
|
int maxwidth /*= -1*/
|
2021-08-07 05:55:09 +02:00
|
|
|
) {
|
2022-12-30 22:57:24 +01:00
|
|
|
if (linespacing == -1)
|
|
|
|
{
|
|
|
|
linespacing = 10;
|
|
|
|
}
|
|
|
|
linespacing = SDL_max(linespacing, loc::get_langmeta()->font_h);
|
|
|
|
|
|
|
|
if (maxwidth == -1)
|
|
|
|
{
|
|
|
|
maxwidth = 304;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* str = s.c_str();
|
2021-08-07 05:55:09 +02:00
|
|
|
/* Screen width is 320 pixels. The shortest a char can be is 6 pixels wide.
|
|
|
|
* 320 / 6 is 54, rounded up. 4 bytes per char. */
|
|
|
|
char buffer[54*4 + 1];
|
|
|
|
size_t start = 0;
|
|
|
|
|
`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-02 05:47:31 +02:00
|
|
|
if (flipmode)
|
|
|
|
{
|
|
|
|
/* Correct for the height of the resulting print. */
|
|
|
|
size_t len = 0;
|
|
|
|
while (next_wrap(&start, &len, &str[start], maxwidth))
|
|
|
|
{
|
|
|
|
y += linespacing;
|
|
|
|
}
|
|
|
|
y -= linespacing;
|
|
|
|
start = 0;
|
|
|
|
}
|
|
|
|
|
2021-08-07 05:55:09 +02:00
|
|
|
while (next_wrap_s(buffer, sizeof(buffer), &start, str, maxwidth))
|
|
|
|
{
|
|
|
|
Print(x, y, buffer, r, g, b, cen);
|
|
|
|
|
|
|
|
if (flipmode)
|
|
|
|
{
|
|
|
|
y -= linespacing;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
y += linespacing;
|
|
|
|
}
|
|
|
|
}
|
2022-12-30 22:57:24 +01:00
|
|
|
|
|
|
|
return y + linespacing;
|
2021-08-07 05:55:09 +02:00
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 00:41:49 +02:00
|
|
|
void Graphics::bigprint( int _x, int _y, const std::string& _s, int r, int g, int b, bool cen, int sc )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-02 22:05:48 +02:00
|
|
|
if (cen)
|
|
|
|
{
|
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-23 01:43:31 +01:00
|
|
|
const int len_ = len(_s);
|
|
|
|
_x = SDL_max(160 - (int((len_/ 2.0)*sc)), 0 );
|
2020-04-02 22:05:48 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 00:18:22 +02:00
|
|
|
return do_print(_x, _y, _s, r, g, b, 255, sc);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-09-07 00:41:49 +02:00
|
|
|
void Graphics::bigbprint(int x, int y, const std::string& s, int r, int g, int b, bool cen, int sc)
|
2021-03-19 22:26:59 +01:00
|
|
|
{
|
|
|
|
if (!notextoutline)
|
|
|
|
{
|
|
|
|
bigprint(x, y - sc, s, 0, 0, 0, cen, sc);
|
|
|
|
if (cen)
|
|
|
|
{
|
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-23 01:43:31 +01:00
|
|
|
const int len_ = len(s);
|
|
|
|
int x_cen = SDL_max(160 - (len_ / 2) * sc, 0);
|
2021-03-19 22:26:59 +01:00
|
|
|
bigprint(x_cen - sc, y, s, 0, 0, 0, false, sc);
|
|
|
|
bigprint(x_cen + sc, y, s, 0, 0, 0, false, sc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bigprint(x - sc, y, s, 0, 0, 0, cen, sc);
|
|
|
|
bigprint(x + sc, y, s, 0, 0, 0, cen, sc);
|
|
|
|
}
|
|
|
|
bigprint(x, y + sc, s, 0, 0, 0, cen, sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
bigprint(x, y, s, r, g, b, cen, sc);
|
|
|
|
}
|
|
|
|
|
2021-09-07 00:41:49 +02:00
|
|
|
int Graphics::len(const std::string& t)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
int bfontpos = 0;
|
2021-09-07 00:41:49 +02:00
|
|
|
std::string::const_iterator iter = t.begin();
|
2020-01-31 19:25:37 +01:00
|
|
|
while (iter != t.end()) {
|
|
|
|
int cur = utf8::unchecked::next(iter);
|
|
|
|
bfontpos += bfontlen(cur);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
return bfontpos;
|
|
|
|
}
|
|
|
|
|
2022-12-30 22:57:24 +01:00
|
|
|
std::string Graphics::string_wordwrap(const std::string& s, int maxwidth, short *lines /*= NULL*/)
|
|
|
|
{
|
|
|
|
// Return a string wordwrapped to a maximum limit by adding newlines.
|
|
|
|
// CJK will need to have autowordwrap disabled and have manually inserted newlines.
|
|
|
|
|
|
|
|
if (lines != NULL)
|
|
|
|
{
|
|
|
|
*lines = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* orig = s.c_str();
|
|
|
|
|
|
|
|
std::string result;
|
|
|
|
size_t start = 0;
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
size_t len = 0;
|
|
|
|
const char* part = &orig[start];
|
|
|
|
|
|
|
|
const bool retval = next_wrap(&start, &len, part, maxwidth);
|
|
|
|
|
|
|
|
if (!retval)
|
|
|
|
{
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (first)
|
|
|
|
{
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result.push_back('\n');
|
|
|
|
|
|
|
|
if (lines != NULL)
|
|
|
|
{
|
|
|
|
(*lines)++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result.append(part, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Graphics::string_wordwrap_balanced(const std::string& s, int maxwidth)
|
|
|
|
{
|
|
|
|
// Return a string wordwrapped to a limit of maxwidth by adding newlines.
|
|
|
|
// Try to fill the lines as far as possible, and return result where lines are most filled.
|
|
|
|
// Goal is to have all lines in textboxes be about as long and to avoid wrapping just one word to a new line.
|
|
|
|
// CJK will need to have autowordwrap disabled and have manually inserted newlines.
|
|
|
|
|
|
|
|
if (!loc::get_langmeta()->autowordwrap)
|
|
|
|
{
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
short lines;
|
|
|
|
string_wordwrap(s, maxwidth, &lines);
|
|
|
|
|
|
|
|
int bestwidth = maxwidth;
|
|
|
|
if (lines > 1)
|
|
|
|
{
|
|
|
|
for (int curlimit = maxwidth; curlimit > 1; curlimit -= 8)
|
|
|
|
{
|
|
|
|
short try_lines;
|
|
|
|
string_wordwrap(s, curlimit, &try_lines);
|
|
|
|
|
|
|
|
if (try_lines > lines)
|
|
|
|
{
|
|
|
|
bestwidth = curlimit + 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return string_wordwrap(s, bestwidth);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Graphics::string_unwordwrap(const std::string& s)
|
|
|
|
{
|
|
|
|
/* Takes a string wordwrapped by newlines, and turns it into a single line, undoing the wrapping.
|
|
|
|
* Also trims any leading/trailing whitespace and collapses multiple spaces into one (to undo manual centering)
|
|
|
|
* Only applied to English, so langmeta.autowordwrap isn't used here (it'd break looking up strings) */
|
|
|
|
|
|
|
|
std::string result;
|
|
|
|
std::back_insert_iterator<std::string> inserter = std::back_inserter(result);
|
|
|
|
std::string::const_iterator iter = s.begin();
|
|
|
|
bool latest_was_space = true; // last character was a space (or the beginning, don't want leading whitespace)
|
|
|
|
int consecutive_newlines = 0; // number of newlines currently encountered in a row (multiple newlines should stay!)
|
|
|
|
while (iter != s.end())
|
|
|
|
{
|
|
|
|
uint32_t ch = utf8::unchecked::next(iter);
|
|
|
|
|
|
|
|
if (ch == '\n')
|
|
|
|
{
|
|
|
|
if (consecutive_newlines == 0)
|
|
|
|
{
|
|
|
|
ch = ' ';
|
|
|
|
}
|
|
|
|
else if (consecutive_newlines == 1)
|
|
|
|
{
|
|
|
|
// The last character was already a newline, so change it back from the space we thought it should have become.
|
|
|
|
result[result.size()-1] = '\n';
|
|
|
|
}
|
|
|
|
consecutive_newlines++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
consecutive_newlines = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ch != ' ' || !latest_was_space)
|
|
|
|
{
|
|
|
|
utf8::unchecked::append(ch, inserter);
|
|
|
|
}
|
|
|
|
|
|
|
|
latest_was_space = (ch == ' ' || ch == '\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
// We could have one trailing space
|
|
|
|
if (!result.empty() && result[result.size()-1] == ' ')
|
|
|
|
{
|
|
|
|
result.erase(result.end()-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-09-07 00:41:49 +02:00
|
|
|
void Graphics::bprint( int x, int y, const std::string& t, int r, int g, int b, bool cen /*= false*/ ) {
|
2020-02-10 03:23:12 +01:00
|
|
|
bprintalpha(x,y,t,r,g,b,255,cen);
|
|
|
|
}
|
|
|
|
|
2021-09-07 00:41:49 +02:00
|
|
|
void Graphics::bprintalpha( int x, int y, const std::string& t, int r, int g, int b, int a, bool cen /*= false*/ )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-01-17 18:37:53 +01:00
|
|
|
if (!notextoutline)
|
2020-01-14 01:22:26 +01:00
|
|
|
{
|
2020-02-10 03:23:12 +01:00
|
|
|
PrintAlpha(x, y - 1, t, 0, 0, 0, a, cen);
|
2020-01-17 18:37:53 +01:00
|
|
|
if (cen)
|
|
|
|
{
|
2021-09-07 00:18:22 +02:00
|
|
|
const int x_cen = 160 - len(t)/2;
|
2021-09-07 04:50:24 +02:00
|
|
|
PrintAlpha(x_cen - 1, y, t, 0, 0, 0, a, false);
|
|
|
|
PrintAlpha(x_cen + 1, y, t, 0, 0, 0, a, false);
|
2020-01-17 18:37:53 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-02-10 03:23:12 +01:00
|
|
|
PrintAlpha(x -1, y, t, 0, 0, 0, a, cen);
|
|
|
|
PrintAlpha(x +1, y, t, 0, 0, 0, a, cen);
|
2020-01-17 18:37:53 +01:00
|
|
|
}
|
2020-02-10 03:23:12 +01:00
|
|
|
PrintAlpha(x, y+1, t, 0, 0, 0, a, cen);
|
2020-01-14 01:22:26 +01:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-02-10 03:23:12 +01:00
|
|
|
PrintAlpha(x, y, t, r, g, b, a, cen);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::printcrewname( int x, int y, int t )
|
|
|
|
{
|
|
|
|
//Print the name of crew member t in the right colour
|
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case 0:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Viridian"), 16, 240, 240,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 1:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Violet"), 240, 16, 240,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Vitellary"), 240, 240, 16,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 3:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Vermilion"), 240, 16, 16,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 4:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Verdigris"), 16, 240, 16,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 5:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Victoria"), 16, 16, 240,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::printcrewnamedark( int x, int y, int t )
|
|
|
|
{
|
|
|
|
//Print the name of crew member t as above, but in black and white
|
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case 0:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Viridian"), 128,128,128,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 1:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Violet"), 128,128,128,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Vitellary"), 128,128,128,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 3:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Vermilion"), 128,128,128,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 4:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Verdigris"), 128,128,128,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 5:
|
2022-12-30 23:39:12 +01:00
|
|
|
Print(x, y, loc::gettext("Victoria"), 128,128,128,false);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-01 01:27:30 +01:00
|
|
|
void Graphics::printcrewnamestatus( int x, int y, int t, bool rescued )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Print the status of crew member t in the right colour
|
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-01 01:27:30 +01:00
|
|
|
int r, g, b;
|
|
|
|
char gender;
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case 0:
|
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-01 01:27:30 +01:00
|
|
|
r=12; g=140, b=140;
|
|
|
|
gender = 3;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 1:
|
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-01 01:27:30 +01:00
|
|
|
r=140; g=12; b=140;
|
|
|
|
gender = 2;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
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-01 01:27:30 +01:00
|
|
|
r=140; g=140; b=12;
|
|
|
|
gender = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 3:
|
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-01 01:27:30 +01:00
|
|
|
r=140; g=12; b=12;
|
|
|
|
gender = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 4:
|
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-01 01:27:30 +01:00
|
|
|
r=12; g=140; b=12;
|
|
|
|
gender = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 5:
|
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-01 01:27:30 +01:00
|
|
|
r=12; g=12; b=140;
|
|
|
|
gender = 2;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
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-01 01:27:30 +01:00
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* status_text;
|
|
|
|
if (gender == 3 && rescued)
|
|
|
|
{
|
|
|
|
status_text = loc::gettext("(that's you!)");
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
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-01 01:27:30 +01:00
|
|
|
else if (rescued)
|
|
|
|
{
|
|
|
|
status_text = loc::gettext_case("Rescued!", gender);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
r=64; g=64; b=64;
|
|
|
|
status_text = loc::gettext_case("Missing...", gender);
|
|
|
|
}
|
|
|
|
|
|
|
|
Print(x, y, status_text, r, g, b, false);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawsprite( int x, int y, int t, int r, int g, int b )
|
|
|
|
{
|
2020-09-10 07:35:35 +02:00
|
|
|
if (!INBOUNDS_VEC(t, sprites))
|
|
|
|
{
|
|
|
|
WHINE_ONCE("drawsprite() out-of-bounds!");
|
2021-04-18 19:43:36 +02:00
|
|
|
return;
|
2020-09-10 07:35:35 +02:00
|
|
|
}
|
|
|
|
|
Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).
Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)
We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 20:13:12 +02:00
|
|
|
SDL_Rect rect = {x, y, sprites_rect.w, sprites_rect.h};
|
2023-01-02 05:16:08 +01:00
|
|
|
BlitSurfaceColoured(sprites[t], NULL, backBuffer, &rect, getRGB(r, g, b));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
void Graphics::drawsprite(int x, int y, int t, const SDL_Color color)
|
2020-05-02 01:40:35 +02:00
|
|
|
{
|
2020-09-10 07:35:35 +02:00
|
|
|
if (!INBOUNDS_VEC(t, sprites))
|
|
|
|
{
|
|
|
|
WHINE_ONCE("drawsprite() out-of-bounds!");
|
2021-04-18 19:43:36 +02:00
|
|
|
return;
|
2020-09-10 07:35:35 +02:00
|
|
|
}
|
|
|
|
|
Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).
Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)
We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 20:13:12 +02:00
|
|
|
SDL_Rect rect = {x, y, sprites_rect.w, sprites_rect.h};
|
2023-01-02 05:16:08 +01:00
|
|
|
BlitSurfaceColoured(sprites[t], NULL, backBuffer, &rect, color);
|
2020-05-02 01:40:35 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 08:55:35 +01:00
|
|
|
#ifndef NO_CUSTOM_LEVELS
|
Make one-way recolors check for specific files
So, 2.3 added recoloring one-way tiles to no longer make them be always
yellow. However, custom levels that retexture the one-way tiles might
not want them to be recolored. So, if there are ANY custom assets
mounted, then the one-ways will not be recolored. However, if the XML
has a <onewaycol_override>1</onewaycol_override> tag, then the one-way
will be recolored again anyways.
When I added one-way recoloring, I didn't intend for any custom asset to
disable the recoloring; I only did it because I couldn't find a way to
check if a specific file was customized by the custom level or not.
However, I have figured out how to do so, and so now tiles.png one-way
recolors will only be disabled if there's a custom tiles.png, and
tiles2.png one-way recolors will only be disabled if there's a custom
tiles2.png.
In order to make sure we're not calling PhysFS functions on every single
deltaframe, I've added caching variables, tiles1_mounted and
tiles2_mounted, to Graphics; these get assigned every time
reloadresources() is called.
2021-03-06 19:52:11 +01:00
|
|
|
bool Graphics::shouldrecoloroneway(const int tilenum, const bool mounted)
|
2021-03-06 08:55:35 +01:00
|
|
|
{
|
|
|
|
return (tilenum >= 14 && tilenum <= 17
|
Make one-way recolors check for specific files
So, 2.3 added recoloring one-way tiles to no longer make them be always
yellow. However, custom levels that retexture the one-way tiles might
not want them to be recolored. So, if there are ANY custom assets
mounted, then the one-ways will not be recolored. However, if the XML
has a <onewaycol_override>1</onewaycol_override> tag, then the one-way
will be recolored again anyways.
When I added one-way recoloring, I didn't intend for any custom asset to
disable the recoloring; I only did it because I couldn't find a way to
check if a specific file was customized by the custom level or not.
However, I have figured out how to do so, and so now tiles.png one-way
recolors will only be disabled if there's a custom tiles.png, and
tiles2.png one-way recolors will only be disabled if there's a custom
tiles2.png.
In order to make sure we're not calling PhysFS functions on every single
deltaframe, I've added caching variables, tiles1_mounted and
tiles2_mounted, to Graphics; these get assigned every time
reloadresources() is called.
2021-03-06 19:52:11 +01:00
|
|
|
&& (!mounted
|
2021-02-21 00:40:11 +01:00
|
|
|
|| cl.onewaycol_override));
|
2021-03-06 08:55:35 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-04-02 00:42:22 +02:00
|
|
|
void Graphics::drawtile( int x, int y, int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-09-08 09:31:44 +02:00
|
|
|
if (!INBOUNDS_VEC(t, tiles))
|
2020-06-14 03:37:18 +02:00
|
|
|
{
|
2021-08-07 06:05:03 +02:00
|
|
|
WHINE_ONCE("drawtile() out-of-bounds!");
|
2020-06-14 03:37:18 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-06-30 20:47:22 +02:00
|
|
|
|
Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).
Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)
We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 20:13:12 +02:00
|
|
|
SDL_Rect rect = {x, y, tiles_rect.w, tiles_rect.h};
|
2020-06-30 20:47:22 +02:00
|
|
|
|
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
Make one-way recolors check for specific files
So, 2.3 added recoloring one-way tiles to no longer make them be always
yellow. However, custom levels that retexture the one-way tiles might
not want them to be recolored. So, if there are ANY custom assets
mounted, then the one-ways will not be recolored. However, if the XML
has a <onewaycol_override>1</onewaycol_override> tag, then the one-way
will be recolored again anyways.
When I added one-way recoloring, I didn't intend for any custom asset to
disable the recoloring; I only did it because I couldn't find a way to
check if a specific file was customized by the custom level or not.
However, I have figured out how to do so, and so now tiles.png one-way
recolors will only be disabled if there's a custom tiles.png, and
tiles2.png one-way recolors will only be disabled if there's a custom
tiles2.png.
In order to make sure we're not calling PhysFS functions on every single
deltaframe, I've added caching variables, tiles1_mounted and
tiles2_mounted, to Graphics; these get assigned every time
reloadresources() is called.
2021-03-06 19:52:11 +01:00
|
|
|
if (shouldrecoloroneway(t, tiles1_mounted))
|
2020-06-30 20:47:22 +02:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color thect = cl.getonewaycol();
|
2020-06-30 20:47:22 +02:00
|
|
|
BlitSurfaceTinted(tiles[t], NULL, backBuffer, &rect, thect);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
BlitSurfaceStandard(tiles[t], NULL, backBuffer, &rect);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-02 00:47:35 +02:00
|
|
|
void Graphics::drawtile2( int x, int y, int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-09-08 09:31:44 +02:00
|
|
|
if (!INBOUNDS_VEC(t, tiles2))
|
2020-06-14 03:37:18 +02:00
|
|
|
{
|
2021-08-07 06:05:03 +02:00
|
|
|
WHINE_ONCE("drawtile2() out-of-bounds!");
|
2020-06-14 03:37:18 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-06-30 20:47:22 +02:00
|
|
|
|
Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).
Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)
We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 20:13:12 +02:00
|
|
|
SDL_Rect rect = {x, y, tiles_rect.w, tiles_rect.h};
|
2020-06-30 20:47:22 +02:00
|
|
|
|
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
Make one-way recolors check for specific files
So, 2.3 added recoloring one-way tiles to no longer make them be always
yellow. However, custom levels that retexture the one-way tiles might
not want them to be recolored. So, if there are ANY custom assets
mounted, then the one-ways will not be recolored. However, if the XML
has a <onewaycol_override>1</onewaycol_override> tag, then the one-way
will be recolored again anyways.
When I added one-way recoloring, I didn't intend for any custom asset to
disable the recoloring; I only did it because I couldn't find a way to
check if a specific file was customized by the custom level or not.
However, I have figured out how to do so, and so now tiles.png one-way
recolors will only be disabled if there's a custom tiles.png, and
tiles2.png one-way recolors will only be disabled if there's a custom
tiles2.png.
In order to make sure we're not calling PhysFS functions on every single
deltaframe, I've added caching variables, tiles1_mounted and
tiles2_mounted, to Graphics; these get assigned every time
reloadresources() is called.
2021-03-06 19:52:11 +01:00
|
|
|
if (shouldrecoloroneway(t, tiles2_mounted))
|
2020-06-30 20:47:22 +02:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color thect = cl.getonewaycol();
|
2020-06-30 20:47:22 +02:00
|
|
|
BlitSurfaceTinted(tiles2[t], NULL, backBuffer, &rect, thect);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
BlitSurfaceStandard(tiles2[t], NULL, backBuffer, &rect);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-08-04 04:13:08 +02:00
|
|
|
void Graphics::drawtile3( int x, int y, int t, int off, int height_subtract /*= 0*/ )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-08-04 03:58:53 +02:00
|
|
|
t += off * 30;
|
2020-09-08 09:31:44 +02:00
|
|
|
if (!INBOUNDS_VEC(t, tiles3))
|
2020-06-14 03:37:18 +02:00
|
|
|
{
|
2021-08-07 06:05:03 +02:00
|
|
|
WHINE_ONCE("drawtile3() out-of-bounds!");
|
2020-06-14 03:37:18 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-08-04 04:13:08 +02:00
|
|
|
SDL_Rect src_rect = { 0, 0, tiles_rect.w, tiles_rect.h - height_subtract };
|
Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).
Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)
We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 20:13:12 +02:00
|
|
|
SDL_Rect rect = {x, y, tiles_rect.w, tiles_rect.h};
|
2020-08-04 04:13:08 +02:00
|
|
|
BlitSurfaceStandard(tiles3[t], &src_rect, backBuffer, &rect);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawtowertile( int x, int y, int t )
|
|
|
|
{
|
2020-09-08 09:31:44 +02:00
|
|
|
if (!INBOUNDS_VEC(t, tiles2))
|
2020-06-14 03:37:18 +02:00
|
|
|
{
|
2021-08-07 06:05:03 +02:00
|
|
|
WHINE_ONCE("drawtowertile() out-of-bounds!");
|
2020-06-14 03:37:18 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-11-02 19:44:53 +01:00
|
|
|
x += 8;
|
|
|
|
y += 8;
|
Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).
Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)
We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 20:13:12 +02:00
|
|
|
SDL_Rect rect = {x, y, tiles_rect.w, tiles_rect.h};
|
2020-11-03 01:54:17 +01:00
|
|
|
BlitSurfaceStandard(tiles2[t], NULL, warpbuffer, &rect);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-03 00:05:24 +01:00
|
|
|
void Graphics::drawtowertile3( int x, int y, int t, TowerBG& bg_obj )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-11-03 00:05:24 +01:00
|
|
|
t += bg_obj.colstate*30;
|
2020-09-08 09:31:44 +02:00
|
|
|
if (!INBOUNDS_VEC(t, tiles3))
|
2020-06-14 03:37:18 +02:00
|
|
|
{
|
2021-08-07 06:05:03 +02:00
|
|
|
WHINE_ONCE("drawtowertile3() out-of-bounds!");
|
2020-06-14 03:37:18 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-11-02 19:44:53 +01:00
|
|
|
x += 8;
|
|
|
|
y += 8;
|
Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).
Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)
We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 20:13:12 +02:00
|
|
|
SDL_Rect rect = {x, y, tiles_rect.w, tiles_rect.h};
|
2020-11-03 00:05:24 +01:00
|
|
|
BlitSurfaceStandard(tiles3[t], NULL, bg_obj.buffer, &rect);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::drawgui(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-03-19 21:31:53 +01:00
|
|
|
int text_sign;
|
2021-03-19 21:34:13 +01:00
|
|
|
int crew_yp;
|
|
|
|
int crew_sprite;
|
2021-09-06 09:36:35 +02:00
|
|
|
size_t i;
|
|
|
|
|
2021-03-19 21:31:53 +01:00
|
|
|
if (flipmode)
|
|
|
|
{
|
|
|
|
text_sign = -1;
|
2021-03-19 21:34:13 +01:00
|
|
|
crew_yp = 64 + 48 + 4;
|
|
|
|
crew_sprite = 6;
|
2021-03-19 21:31:53 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text_sign = 1;
|
2021-03-19 21:34:13 +01:00
|
|
|
crew_yp = 64 + 32 + 4;
|
|
|
|
crew_sprite = 0;
|
2021-03-19 21:31:53 +01:00
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//Draw all the textboxes to the screen
|
2021-09-13 06:02:15 +02:00
|
|
|
for (i = 0; i<textboxes.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-03-19 21:31:53 +01:00
|
|
|
int text_yoff;
|
2021-03-20 03:51:36 +01:00
|
|
|
int yp;
|
Fix text box deltaframe flashing on deltaframes after fully opaque
So #434 didn't end up solving the deltaframe flashing fully, only
reduced the chances that it could happen.
I've had the Level Complete image flash a few times when the Game Saved
text box pops up. This seems to be because the Level Complete image is
based off of the text box being at y-position 12, and the Game Saved
text box is also at y-position 12. Level Complete only gets drawn if the
text box additionally has a red channel value of 165, and the Game Saved
text box has a red channel value of 174. However, there is a check that
the text box be fully opaque first before drawing special images. So
what went wrong?
Well, after thinking about it for a while, I realized that even though
there is indeed an opaqueness check, the alpha of the text box updates
BEFORE it gets drawn. And during the deltaframes immediately after it
gets updated, the text box is considered fully opaque. It's completely
possible for the linear interpolation to end up with a red channel value
of 165 during these deltaframes, while the text box is opaque as well.
As always, it helps if you have a high refresh rate, and run the game
under 40% slowdown.
Anyways, so what's the final fix for this issue? Well, use the text box
'target' RGB values instead - its tr/tg/tb attributes instead of its
r/g/b attributes. They are not subject to interpolation and so are
completely reliable. The opaqueness check should still be kept, though,
because the target values don't account for opaqueness. And this way, we
get no more deltaframe flashes during text box fades.
An even better fix would be to not use magic RGB values to draw special
images... but that'd be something to do later.
2021-03-21 20:49:14 +01:00
|
|
|
bool opaque;
|
2021-03-19 21:31:53 +01:00
|
|
|
if (flipmode)
|
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
text_yoff = textboxes[i].lines.size() * 8;
|
2021-03-19 21:31:53 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text_yoff = 8;
|
|
|
|
}
|
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
yp = textboxes[i].yp;
|
|
|
|
if (flipmode && textboxes[i].flipme)
|
2021-03-20 03:51:36 +01:00
|
|
|
{
|
2021-10-02 05:59:55 +02:00
|
|
|
yp = SCREEN_HEIGHT_PIXELS - yp - 8 * (textboxes[i].lines.size() + 2);
|
2021-03-20 03:51:36 +01:00
|
|
|
}
|
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
if (textboxes[i].r == 0 && textboxes[i].g == 0 && textboxes[i].b == 0)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
2021-09-06 09:36:35 +02:00
|
|
|
size_t j;
|
2021-09-13 06:02:15 +02:00
|
|
|
for (j = 0; j < textboxes[i].lines.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
bprint(textboxes[i].xp + 8, yp + text_yoff + text_sign * (j * 8), textboxes[i].lines[j], 196, 196, 255 - help.glow);
|
2020-04-04 02:26:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
const float tl_lerp = lerp(textboxes[i].prev_tl, textboxes[i].tl);
|
|
|
|
const int r = textboxes[i].r * tl_lerp;
|
|
|
|
const int g = textboxes[i].g * tl_lerp;
|
|
|
|
const int b = textboxes[i].b * tl_lerp;
|
2021-09-06 09:36:35 +02:00
|
|
|
size_t j;
|
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
drawtextbox(textboxes[i].xp, yp, textboxes[i].w/8, textboxes[i].h/8, r, g, b);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
for (j = 0; j < textboxes[i].lines.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
Print(textboxes[i].xp + 8, yp + text_yoff + text_sign * (j * 8), textboxes[i].lines[j], r, g, b);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-04 02:26:29 +02:00
|
|
|
}
|
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
opaque = textboxes[i].tl >= 1.0;
|
Remove allowspecial, replace with opaqueness check
When I added the over-30-FPS mode, I kept running into this problem
where the special images of text boxes would render during the
deltaframes of fade-in/fade-out animations, even though they shouldn't
be. So I simply added a flag to the text box that enables drawing these
special images.
However, this doesn't solve the problem fully, and there's still a small
chance that a special-image text box could draw another special image
during its deltaframes. It's really rare and you have to have your
deltaframe luck juuuuuust right (or you could use libTAS, probably), but
it helps to be in 40% slowmode and have a high refresh rate (which, if
it isn't a multiple of 30, you should disable VSync, too, in order to
not have a low framerate).
So instead, special images will only be drawn if the text box has fully
faded in completely. That solves the issue completely.
2020-08-05 05:42:43 +02:00
|
|
|
|
Fix text box deltaframe flashing on deltaframes after fully opaque
So #434 didn't end up solving the deltaframe flashing fully, only
reduced the chances that it could happen.
I've had the Level Complete image flash a few times when the Game Saved
text box pops up. This seems to be because the Level Complete image is
based off of the text box being at y-position 12, and the Game Saved
text box is also at y-position 12. Level Complete only gets drawn if the
text box additionally has a red channel value of 165, and the Game Saved
text box has a red channel value of 174. However, there is a check that
the text box be fully opaque first before drawing special images. So
what went wrong?
Well, after thinking about it for a while, I realized that even though
there is indeed an opaqueness check, the alpha of the text box updates
BEFORE it gets drawn. And during the deltaframes immediately after it
gets updated, the text box is considered fully opaque. It's completely
possible for the linear interpolation to end up with a red channel value
of 165 during these deltaframes, while the text box is opaque as well.
As always, it helps if you have a high refresh rate, and run the game
under 40% slowdown.
Anyways, so what's the final fix for this issue? Well, use the text box
'target' RGB values instead - its tr/tg/tb attributes instead of its
r/g/b attributes. They are not subject to interpolation and so are
completely reliable. The opaqueness check should still be kept, though,
because the target values don't account for opaqueness. And this way, we
get no more deltaframe flashes during text box fades.
An even better fix would be to not use magic RGB values to draw special
images... but that'd be something to do later.
2021-03-21 20:49:14 +01:00
|
|
|
if (!opaque)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
if (textboxes[i].yp == 12 && textboxes[i].r == 165)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
2022-12-30 23:39:12 +01:00
|
|
|
// Level complete
|
|
|
|
const char* english = "Level Complete!";
|
|
|
|
const char* translation = loc::gettext(english);
|
|
|
|
if (SDL_strcmp(english, translation) != 0
|
|
|
|
&& !(flipmode && fliplevelcomplete_mounted)
|
|
|
|
&& !(!flipmode && levelcomplete_mounted)
|
|
|
|
)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2022-12-30 23:39:12 +01:00
|
|
|
int sc = 2;
|
|
|
|
int y = 28;
|
|
|
|
if (len(translation) > 144)
|
|
|
|
{
|
|
|
|
// We told translators how long it could be... Ah well, mitigate the damage.
|
|
|
|
sc = 1;
|
|
|
|
y += 4;
|
|
|
|
}
|
|
|
|
if (flipmode)
|
|
|
|
{
|
|
|
|
y = 240 - y - 8*sc;
|
|
|
|
}
|
|
|
|
bigprint(-1, y, translation, 164, 164, 255, true, sc);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-12-30 23:39:12 +01:00
|
|
|
if (flipmode)
|
|
|
|
{
|
|
|
|
drawimage(5, 0, 180, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
drawimage(0, 0, 12, true);
|
|
|
|
}
|
2020-04-04 02:26:29 +02:00
|
|
|
}
|
|
|
|
}
|
2021-09-13 06:02:15 +02:00
|
|
|
else if (textboxes[i].yp == 12 && textboxes[i].g == 165)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
2022-12-30 23:39:12 +01:00
|
|
|
// Game complete
|
|
|
|
const char* english = "Game Complete!";
|
|
|
|
const char* translation = loc::gettext(english);
|
|
|
|
if (SDL_strcmp(english, translation) != 0
|
|
|
|
&& !(flipmode && flipgamecomplete_mounted)
|
|
|
|
&& !(!flipmode && gamecomplete_mounted)
|
|
|
|
)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
2022-12-30 23:39:12 +01:00
|
|
|
int sc = 2;
|
|
|
|
int y = 28;
|
|
|
|
if (len(translation) > 144)
|
|
|
|
{
|
|
|
|
// We told translators how long it could be... Ah well, mitigate the damage.
|
|
|
|
sc = 1;
|
|
|
|
y += 4;
|
|
|
|
}
|
|
|
|
if (flipmode)
|
|
|
|
{
|
|
|
|
y = 240 - y - 8*sc;
|
|
|
|
}
|
|
|
|
bigprint(-1, y, translation, 164, 164, 255, true, sc);
|
2020-04-04 02:26:29 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-12-30 23:39:12 +01:00
|
|
|
if (flipmode)
|
|
|
|
{
|
|
|
|
drawimage(6, 0, 180, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
drawimage(4, 0, 12, true);
|
|
|
|
}
|
2020-04-04 02:26:29 +02:00
|
|
|
}
|
|
|
|
}
|
2022-12-30 23:39:12 +01:00
|
|
|
int crew_xp = textboxes[i].xp+20 - 6;
|
2021-09-13 06:02:15 +02:00
|
|
|
if (textboxes[i].r == 175 && textboxes[i].g == 175)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
2021-03-19 21:34:13 +01:00
|
|
|
//purple guy
|
2022-12-30 23:39:12 +01:00
|
|
|
drawsprite(crew_xp, crew_yp, crew_sprite, 220- help.glow/4 - textboxes[i].rand, 120- help.glow/4, 210 - help.glow/4);
|
2020-04-04 02:26:29 +02:00
|
|
|
}
|
2021-09-13 06:02:15 +02:00
|
|
|
else if (textboxes[i].r == 175 && textboxes[i].b == 175)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
2021-03-19 21:34:13 +01:00
|
|
|
//red guy
|
2022-12-30 23:39:12 +01:00
|
|
|
drawsprite(crew_xp, crew_yp, crew_sprite, 255 - help.glow/8, 70 - help.glow/4, 70 - help.glow / 4);
|
2021-03-19 21:34:13 +01:00
|
|
|
}
|
2021-09-13 06:02:15 +02:00
|
|
|
else if (textboxes[i].r == 175)
|
2021-03-19 21:34:13 +01:00
|
|
|
{
|
|
|
|
//green guy
|
2022-12-30 23:39:12 +01:00
|
|
|
drawsprite(crew_xp, crew_yp, crew_sprite, 120 - help.glow / 4 - textboxes[i].rand, 220 - help.glow / 4, 120 - help.glow / 4);
|
2021-03-19 21:34:13 +01:00
|
|
|
}
|
2021-09-13 06:02:15 +02:00
|
|
|
else if (textboxes[i].g == 175)
|
2021-03-19 21:34:13 +01:00
|
|
|
{
|
|
|
|
//yellow guy
|
2022-12-30 23:39:12 +01:00
|
|
|
drawsprite(crew_xp, crew_yp, crew_sprite, 220- help.glow/4 - textboxes[i].rand, 210 - help.glow/4, 120- help.glow/4);
|
2021-03-19 21:34:13 +01:00
|
|
|
}
|
2021-09-13 06:02:15 +02:00
|
|
|
else if (textboxes[i].b == 175)
|
2021-03-19 21:34:13 +01:00
|
|
|
{
|
|
|
|
//blue guy
|
2022-12-30 23:39:12 +01:00
|
|
|
drawsprite(crew_xp, crew_yp, crew_sprite, 75, 75, 255- help.glow/4 - textboxes[i].rand);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::updatetextboxes(void)
|
2020-04-29 03:38:43 +02:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
for (size_t i = 0; i < textboxes.size(); i++)
|
2020-04-29 03:38:43 +02:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes[i].update();
|
2020-04-29 03:38:43 +02:00
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
if (textboxes[i].tm == 2 && textboxes[i].tl <= 0.5)
|
2020-04-29 03:38:43 +02:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes.erase(textboxes.begin() + i);
|
2020-04-29 03:38:43 +02:00
|
|
|
i--;
|
|
|
|
continue;
|
|
|
|
}
|
2021-03-23 22:29:32 +01:00
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
if (textboxes[i].tl >= 1.0f
|
|
|
|
&& ((textboxes[i].r == 175 && textboxes[i].g == 175)
|
|
|
|
|| textboxes[i].r == 175
|
|
|
|
|| textboxes[i].g == 175
|
|
|
|
|| textboxes[i].b == 175)
|
|
|
|
&& (textboxes[i].r != 175 || textboxes[i].b != 175))
|
2021-03-23 22:29:32 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes[i].rand = fRandom() * 20;
|
2021-03-23 22:29:32 +01:00
|
|
|
}
|
2020-04-29 03:38:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-02 05:16:08 +01:00
|
|
|
void Graphics::drawimagecol( int t, int xp, int yp, const SDL_Color ct, bool cent/*= false*/ )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2022-05-17 21:07:51 +02:00
|
|
|
if (!INBOUNDS_VEC(t, images) || images[t] == NULL)
|
2020-06-14 03:37:53 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect trect;
|
|
|
|
|
|
|
|
point tpoint;
|
|
|
|
if (cent)
|
|
|
|
{
|
|
|
|
tpoint.x = 160 - int(images[t]->w / 2);
|
|
|
|
tpoint.y = yp;
|
|
|
|
trect.x = tpoint.x ;
|
|
|
|
trect.y = tpoint.y;
|
|
|
|
trect.w = images[t]->w;
|
|
|
|
trect.h= images[t]->h;
|
|
|
|
BlitSurfaceColoured(images[t], NULL, backBuffer, &trect, ct);
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
trect.x = xp;
|
|
|
|
trect.y = yp;
|
|
|
|
trect.w = images[t]->w;
|
|
|
|
trect.h = images[t]->h;
|
|
|
|
BlitSurfaceColoured(images[t], NULL, backBuffer, &trect, ct);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawimage( int t, int xp, int yp, bool cent/*=false*/ )
|
|
|
|
{
|
2022-05-17 21:07:51 +02:00
|
|
|
if (!INBOUNDS_VEC(t, images) || images[t] == NULL)
|
2020-06-14 03:37:53 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
SDL_Rect trect;
|
|
|
|
if (cent)
|
|
|
|
{
|
|
|
|
trect.x = 160 - int(images[t]->w / 2);
|
|
|
|
trect.y = yp;
|
|
|
|
trect.w = images[t]->w;
|
|
|
|
trect.h = images[t]->h;
|
|
|
|
BlitSurfaceStandard(images[t], NULL, backBuffer, &trect);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
trect.x = xp;
|
|
|
|
trect.y = yp;
|
|
|
|
trect.w = images[t]->w;
|
|
|
|
trect.h= images[t]->h;
|
|
|
|
|
|
|
|
BlitSurfaceStandard(images[t], NULL, backBuffer, &trect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawpartimage( int t, int xp, int yp, int wp, int hp)
|
|
|
|
{
|
2022-05-17 21:07:51 +02:00
|
|
|
if (!INBOUNDS_VEC(t, images) || images[t] == NULL)
|
2020-06-14 03:37:53 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect trect;
|
|
|
|
|
|
|
|
trect.x = xp;
|
|
|
|
trect.y = yp;
|
|
|
|
trect.w = wp;
|
|
|
|
trect.h= hp;
|
|
|
|
|
|
|
|
SDL_Rect trect2;
|
|
|
|
|
|
|
|
trect2.x = 0;
|
|
|
|
trect2.y = 0;
|
|
|
|
trect2.w = wp;
|
|
|
|
trect2.h= hp;
|
|
|
|
|
|
|
|
BlitSurfaceStandard(images[t], &trect2, backBuffer, &trect);
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::cutscenebars(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
const int usethispos = lerp(oldcutscenebarspos, cutscenebarspos);
|
2020-01-01 21:29:24 +01:00
|
|
|
if (showcutscenebars)
|
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
FillRect(backBuffer, 0, 0, usethispos, 16, 0, 0, 0);
|
|
|
|
FillRect(backBuffer, 360-usethispos, 224, usethispos, 16, 0, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-29 02:17:13 +02:00
|
|
|
else if (cutscenebarspos > 0) //disappearing
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-29 02:17:13 +02:00
|
|
|
//draw
|
2023-01-02 01:36:43 +01:00
|
|
|
FillRect(backBuffer, 0, 0, usethispos, 16, 0, 0, 0);
|
|
|
|
FillRect(backBuffer, 360-usethispos, 224, usethispos, 16, 0, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::cutscenebarstimer(void)
|
2020-04-29 02:11:02 +02:00
|
|
|
{
|
2020-04-29 02:16:24 +02:00
|
|
|
oldcutscenebarspos = cutscenebarspos;
|
2020-04-29 02:11:02 +02:00
|
|
|
if (showcutscenebars)
|
|
|
|
{
|
|
|
|
cutscenebarspos += 25;
|
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-23 01:43:31 +01:00
|
|
|
cutscenebarspos = SDL_min(cutscenebarspos, 361);
|
2020-04-29 02:11:02 +02:00
|
|
|
}
|
|
|
|
else if (cutscenebarspos > 0)
|
|
|
|
{
|
|
|
|
//disappearing
|
|
|
|
cutscenebarspos -= 25;
|
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-23 01:43:31 +01:00
|
|
|
cutscenebarspos = SDL_max(cutscenebarspos, 0);
|
2020-04-29 02:11:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-20 07:08:35 +01:00
|
|
|
void Graphics::setbars(const int position)
|
|
|
|
{
|
|
|
|
cutscenebarspos = position;
|
|
|
|
oldcutscenebarspos = position;
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawcrewman( int x, int y, int t, bool act, bool noshift /*=false*/ )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (!act)
|
|
|
|
{
|
|
|
|
if (noshift)
|
|
|
|
{
|
|
|
|
if (flipmode)
|
|
|
|
{
|
2020-05-02 01:40:35 +02:00
|
|
|
drawsprite(x, y, 14, col_crewinactive);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-02 01:40:35 +02:00
|
|
|
drawsprite(x, y, 12, col_crewinactive);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (flipmode)
|
|
|
|
{
|
2020-05-02 01:40:35 +02:00
|
|
|
drawsprite(x - 8, y, 14, col_crewinactive);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-02 01:40:35 +02:00
|
|
|
drawsprite(x - 8, y, 12, col_crewinactive);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (flipmode) crewframe += 6;
|
|
|
|
|
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case 0:
|
2020-05-02 01:40:35 +02:00
|
|
|
drawsprite(x, y, crewframe, col_crewcyan);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-05-02 01:40:35 +02:00
|
|
|
drawsprite(x, y, crewframe, col_crewpurple);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-05-02 01:40:35 +02:00
|
|
|
drawsprite(x, y, crewframe, col_crewyellow);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 3:
|
2020-05-02 01:40:35 +02:00
|
|
|
drawsprite(x, y, crewframe, col_crewred);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 4:
|
2020-05-02 01:40:35 +02:00
|
|
|
drawsprite(x, y, crewframe, col_crewgreen);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 5:
|
2020-05-02 01:40:35 +02:00
|
|
|
drawsprite(x, y, crewframe, col_crewblue);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flipmode) crewframe -= 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-04 00:31:59 +02:00
|
|
|
void Graphics::drawpixeltextbox(
|
|
|
|
const int x,
|
|
|
|
const int y,
|
|
|
|
const int w,
|
|
|
|
const int h,
|
|
|
|
const int r,
|
|
|
|
const int g,
|
|
|
|
const int b
|
|
|
|
) {
|
|
|
|
int k;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-04 00:31:59 +02:00
|
|
|
FillRect(backBuffer, x, y, w, h, r/6, g/6, b/6);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-04 00:31:59 +02:00
|
|
|
/* Horizontal tiles */
|
|
|
|
for (k = 0; k < w/8 - 2; ++k)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-04 00:31:59 +02:00
|
|
|
drawcoloredtile(x + 8 + k*8, y, 41, r, g, b);
|
|
|
|
drawcoloredtile(x + 8 + k*8, y + h - 8, 46, r, g, b);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-09-04 00:04:25 +02:00
|
|
|
if (w % 8 != 0)
|
|
|
|
{
|
2021-09-04 00:31:59 +02:00
|
|
|
/* Fill in horizontal gap */
|
2021-09-04 00:04:25 +02:00
|
|
|
drawcoloredtile(x + w - 16, y, 41, r, g, b);
|
|
|
|
drawcoloredtile(x + w - 16, y + h - 8, 46, r, g, b);
|
|
|
|
}
|
|
|
|
|
2021-09-04 00:31:59 +02:00
|
|
|
/* Vertical tiles */
|
|
|
|
for (k = 0; k < h/8 - 2; ++k)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-04 00:31:59 +02:00
|
|
|
drawcoloredtile(x, y + 8 + k*8, 43, r, g, b);
|
|
|
|
drawcoloredtile(x + w - 8, y + 8 + k*8, 44, r, g, b);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-09-04 00:04:25 +02:00
|
|
|
if (h % 8 != 0)
|
|
|
|
{
|
2021-09-04 00:31:59 +02:00
|
|
|
/* Fill in vertical gap */
|
2021-09-04 00:04:25 +02:00
|
|
|
drawcoloredtile(x, y + h - 16, 43, r, g, b);
|
|
|
|
drawcoloredtile(x + w - 8, y + h - 16, 44, r, g, b);
|
|
|
|
}
|
|
|
|
|
2021-09-04 00:31:59 +02:00
|
|
|
/* Corners */
|
2020-01-01 21:29:24 +01:00
|
|
|
drawcoloredtile(x, y, 40, r, g, b);
|
2021-09-04 00:31:59 +02:00
|
|
|
drawcoloredtile(x + w - 8, y, 42, r, g, b);
|
|
|
|
drawcoloredtile(x, y + h - 8, 45, r, g, b);
|
|
|
|
drawcoloredtile(x + w - 8, y + h - 8, 47, r, g, b);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-09-04 00:31:59 +02:00
|
|
|
void Graphics::drawtextbox(
|
|
|
|
const int x,
|
|
|
|
const int y,
|
|
|
|
const int w,
|
|
|
|
const int h,
|
|
|
|
const int r,
|
|
|
|
const int g,
|
|
|
|
const int b
|
|
|
|
) {
|
2021-09-04 00:28:45 +02:00
|
|
|
return drawpixeltextbox(x, y, w*8, h*8, r, g, b);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::textboxactive(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Remove all but the most recent textbox
|
2021-09-13 06:02:15 +02:00
|
|
|
for (int i = 0; i < (int) textboxes.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
if (m != i) textboxes[i].remove();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::textboxremovefast(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Remove all textboxes
|
2021-09-13 06:02:15 +02:00
|
|
|
for (size_t i = 0; i < textboxes.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes[i].removefast();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::textboxremove(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Remove all textboxes
|
2021-09-13 06:02:15 +02:00
|
|
|
for (size_t i = 0; i < textboxes.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes[i].remove();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxtimer( int t )
|
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
2020-06-28 19:40:58 +02:00
|
|
|
{
|
2021-02-24 00:21:29 +01:00
|
|
|
vlog_error("textboxtimer() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes[m].timer=t;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-09-07 00:41:49 +02:00
|
|
|
void Graphics::addline( const std::string& t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
2020-06-28 19:40:58 +02:00
|
|
|
{
|
2021-02-24 00:21:29 +01:00
|
|
|
vlog_error("addline() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes[m].addline(t);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::textboxadjust(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
2020-06-28 19:40:58 +02:00
|
|
|
{
|
2021-02-24 00:21:29 +01:00
|
|
|
vlog_error("textboxadjust() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes[m].adjust();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-20 04:03:08 +01:00
|
|
|
void Graphics::createtextboxreal(
|
2021-09-07 00:41:49 +02:00
|
|
|
const std::string& t,
|
2021-03-20 04:03:08 +01:00
|
|
|
int xp,
|
|
|
|
int yp,
|
|
|
|
int r,
|
|
|
|
int g,
|
|
|
|
int b,
|
|
|
|
bool flipme
|
|
|
|
) {
|
2021-09-13 06:02:15 +02:00
|
|
|
m = textboxes.size();
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if(m<20)
|
|
|
|
{
|
2020-04-04 02:25:17 +02:00
|
|
|
textboxclass text;
|
2021-09-13 06:02:15 +02:00
|
|
|
text.lines.push_back(t);
|
2020-04-04 02:25:17 +02:00
|
|
|
text.xp = xp;
|
2020-01-31 19:25:37 +01:00
|
|
|
int length = utf8::unchecked::distance(t.begin(), t.end());
|
2020-04-04 02:25:17 +02:00
|
|
|
if (xp == -1) text.xp = 160 - (((length / 2) + 1) * 8);
|
|
|
|
text.yp = yp;
|
|
|
|
text.initcol(r, g, b);
|
2021-03-20 04:03:08 +01:00
|
|
|
text.flipme = flipme;
|
2020-04-04 02:25:17 +02:00
|
|
|
text.resize();
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes.push_back(text);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-20 04:03:08 +01:00
|
|
|
void Graphics::createtextbox(
|
2021-09-07 00:41:49 +02:00
|
|
|
const std::string& t,
|
2021-03-20 04:03:08 +01:00
|
|
|
int xp,
|
|
|
|
int yp,
|
|
|
|
int r,
|
|
|
|
int g,
|
|
|
|
int b
|
|
|
|
) {
|
|
|
|
createtextboxreal(t, xp, yp, r, g, b, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::createtextboxflipme(
|
2021-09-07 00:41:49 +02:00
|
|
|
const std::string& t,
|
2021-03-20 04:03:08 +01:00
|
|
|
int xp,
|
|
|
|
int yp,
|
|
|
|
int r,
|
|
|
|
int g,
|
|
|
|
int b
|
|
|
|
) {
|
|
|
|
createtextboxreal(t, xp, yp, r, g, b, true);
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::drawfade(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
const int usethisamount = lerp(oldfadeamount, fadeamount);
|
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 09:57:47 +02:00
|
|
|
switch (fademode)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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 09:57:47 +02:00
|
|
|
case FADE_FULLY_BLACK:
|
|
|
|
case FADE_START_FADEIN:
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(backBuffer);
|
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 09:57:47 +02:00
|
|
|
break;
|
|
|
|
case FADE_FADING_OUT:
|
2020-07-03 11:40:57 +02:00
|
|
|
for (size_t i = 0; i < SDL_arraysize(fadebars); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
FillRect(backBuffer, fadebars[i], i * 16, usethisamount, 16, 0, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
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 09:57:47 +02:00
|
|
|
break;
|
|
|
|
case FADE_FADING_IN:
|
2020-07-03 11:40:57 +02:00
|
|
|
for (size_t i = 0; i < SDL_arraysize(fadebars); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
FillRect(backBuffer, fadebars[i]-usethisamount, i * 16, 500, 16, 0, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
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 09:57:47 +02:00
|
|
|
break;
|
|
|
|
case FADE_NONE:
|
|
|
|
case FADE_START_FADEOUT:
|
|
|
|
break;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::processfade(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-29 03:10:40 +02:00
|
|
|
oldfadeamount = fadeamount;
|
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 09:57:47 +02:00
|
|
|
switch (fademode)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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 09:57:47 +02:00
|
|
|
case FADE_START_FADEOUT:
|
|
|
|
for (size_t i = 0; i < SDL_arraysize(fadebars); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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 09:57:47 +02:00
|
|
|
fadebars[i] = -int(fRandom() * 12) * 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
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 09:57:47 +02:00
|
|
|
setfade(0);
|
|
|
|
fademode = FADE_FADING_OUT;
|
|
|
|
break;
|
|
|
|
case FADE_FADING_OUT:
|
|
|
|
fadeamount += 24;
|
|
|
|
if (fadeamount > 416)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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 09:57:47 +02:00
|
|
|
fademode = FADE_FULLY_BLACK;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
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 09:57:47 +02:00
|
|
|
break;
|
|
|
|
case FADE_START_FADEIN:
|
|
|
|
for (size_t i = 0; i < SDL_arraysize(fadebars); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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 09:57:47 +02:00
|
|
|
fadebars[i] = 320 + int(fRandom() * 12) * 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
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 09:57:47 +02:00
|
|
|
setfade(416);
|
|
|
|
fademode = FADE_FADING_IN;
|
|
|
|
break;
|
|
|
|
case FADE_FADING_IN:
|
|
|
|
fadeamount -= 24;
|
|
|
|
if (fadeamount <= 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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 09:57:47 +02:00
|
|
|
fademode = FADE_NONE;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2022-04-25 10:21:43 +02:00
|
|
|
break;
|
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 09:57:47 +02:00
|
|
|
case FADE_NONE:
|
|
|
|
case FADE_FULLY_BLACK:
|
|
|
|
break;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-20 07:09:11 +01:00
|
|
|
void Graphics::setfade(const int amount)
|
|
|
|
{
|
|
|
|
fadeamount = amount;
|
|
|
|
oldfadeamount = amount;
|
|
|
|
}
|
|
|
|
|
2022-12-30 22:57:24 +01:00
|
|
|
void Graphics::drawmenu(int cr, int cg, int cb, enum Menu::MenuName menu)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2022-12-30 22:57:24 +01:00
|
|
|
/* The MenuName is only used for some special cases,
|
|
|
|
* like the levels list and the language screen. */
|
|
|
|
|
|
|
|
bool language_screen = menu == Menu::language && !loc::languagelist.empty();
|
|
|
|
unsigned int twocol_voptions;
|
|
|
|
if (language_screen)
|
|
|
|
{
|
|
|
|
size_t n_options = game.menuoptions.size();
|
|
|
|
twocol_voptions = n_options - (n_options/2);
|
|
|
|
}
|
|
|
|
|
Refactor menu creation code
Firstly, menu options are no longer ad-hoc objects, and are added by
using Game::option() (this is the biggest change). This removes the
vector Game::menuoptionsactive, and Game::menuoptions is now a vector of
MenuOption instead of std::string.
Secondly, the manual tracker variable of the amount of menu options,
Game::nummenuoptions, has been removed, in favor of using vectors
properly and using Game::menuoptions::size().
As a result, a lot of copy-pasted code has been removed from
Game::createmenu(), mostly due to having to have different versions of
menus depending on whether or not we have certain defines, or having an
mmmmmm.vvv file inside the VVVVVV directory. In the old days, you
couldn't just add or remove a menu option conveniently, you had to
shuffle around the position of every other menu option too, which
resulted in lots of copy-pasted code. But now this copy-pasted code has
been de-duplicated, at least in Game::createmenu().
2020-04-15 06:50:17 +02:00
|
|
|
for (size_t i = 0; i < game.menuoptions.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-07-04 23:53:05 +02:00
|
|
|
MenuOption& opt = game.menuoptions[i];
|
|
|
|
|
|
|
|
int fr, fg, fb;
|
|
|
|
if (opt.active)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-07-04 23:53:05 +02:00
|
|
|
// Color it normally
|
|
|
|
fr = cr;
|
|
|
|
fg = cg;
|
|
|
|
fb = cb;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-04 23:53:05 +02:00
|
|
|
// Color it gray
|
|
|
|
fr = 128;
|
|
|
|
fg = 128;
|
|
|
|
fb = 128;
|
|
|
|
}
|
|
|
|
|
2022-12-30 22:57:24 +01:00
|
|
|
int x, y;
|
|
|
|
if (language_screen)
|
|
|
|
{
|
|
|
|
int name_len = len(opt.text);
|
|
|
|
x = (i < twocol_voptions ? 80 : 240) - name_len/2;
|
|
|
|
y = 36 + (i % twocol_voptions)*12;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x = i*game.menuspacing + game.menuxoff;
|
|
|
|
y = 140 + i*12 + game.menuyoff;
|
|
|
|
}
|
2020-07-04 23:53:05 +02:00
|
|
|
|
2021-08-18 18:26:14 +02:00
|
|
|
#ifndef NO_CUSTOM_LEVELS
|
2022-12-30 22:57:24 +01:00
|
|
|
if (menu == Menu::levellist)
|
2020-07-04 23:53:05 +02:00
|
|
|
{
|
2021-08-18 18:17:41 +02:00
|
|
|
size_t separator;
|
2021-02-21 00:40:11 +01:00
|
|
|
if (cl.ListOfMetaData.size() > 8)
|
2021-08-18 18:17:41 +02:00
|
|
|
{
|
|
|
|
separator = 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
separator = 1;
|
|
|
|
}
|
|
|
|
if (game.menuoptions.size() - i <= separator)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-07-04 23:53:05 +02:00
|
|
|
// We're on "next page", "previous page", or "return to menu". Draw them separated by a bit
|
|
|
|
y += 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-04 23:53:05 +02:00
|
|
|
// Get out of the way of the level descriptions
|
|
|
|
y += 4;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2021-08-18 18:26:14 +02:00
|
|
|
#endif
|
2022-12-24 04:16:56 +01:00
|
|
|
if (menu == Menu::translator_options_cutscenetest)
|
|
|
|
{
|
|
|
|
size_t separator = 4;
|
|
|
|
if (game.menuoptions.size() - i <= separator)
|
|
|
|
{
|
|
|
|
y += 4;
|
|
|
|
}
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-03-07 03:14:44 +01:00
|
|
|
char buffer[MENU_TEXT_BYTES];
|
2021-04-12 02:43:17 +02:00
|
|
|
if ((int) i == game.currentmenuoption && game.slidermode == SLIDER_NONE)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2022-12-30 22:57:24 +01:00
|
|
|
std::string opt_text;
|
2020-07-04 23:53:05 +02:00
|
|
|
if (opt.active)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-07-04 23:53:05 +02:00
|
|
|
// Uppercase the text
|
2022-12-30 22:57:24 +01:00
|
|
|
opt_text = loc::toupper(opt.text);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2022-12-30 22:57:24 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
opt_text = loc::remove_toupper_escape_chars(opt.text);
|
|
|
|
}
|
|
|
|
|
|
|
|
vformat_buf(buffer, sizeof(buffer), loc::get_langmeta()->menu_select.c_str(), "label:str", opt_text.c_str());
|
2020-07-04 23:53:05 +02:00
|
|
|
|
|
|
|
// Account for brackets
|
2022-12-30 22:57:24 +01:00
|
|
|
x -= (len(buffer)-len(opt_text))/2;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-12-30 22:57:24 +01:00
|
|
|
SDL_strlcpy(buffer, loc::remove_toupper_escape_chars(opt.text).c_str(), sizeof(buffer));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-07-04 23:53:05 +02:00
|
|
|
|
|
|
|
Print(x, y, buffer, fr, fg, fb);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-09-04 00:34:45 +02:00
|
|
|
void Graphics::drawcoloredtile(
|
|
|
|
const int x,
|
|
|
|
const int y,
|
|
|
|
const int t,
|
|
|
|
const int r,
|
|
|
|
const int g,
|
|
|
|
const int b
|
|
|
|
) {
|
|
|
|
SDL_Rect rect;
|
|
|
|
|
2020-09-08 09:31:44 +02:00
|
|
|
if (!INBOUNDS_VEC(t, tiles))
|
2020-06-14 03:37:18 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-04 00:34:45 +02:00
|
|
|
setRect(rect, x, y, tiles_rect.w, tiles_rect.h);
|
2023-01-02 05:16:08 +01:00
|
|
|
BlitSurfaceColoured(tiles[t], NULL, backBuffer, &rect, getRGB(r, g, b));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-02 00:35:27 +02:00
|
|
|
bool Graphics::Hitest(SDL_Surface* surface1, point p1, SDL_Surface* surface2, point p2)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
//find rectangle where they intersect:
|
|
|
|
|
|
|
|
int r1_left = p1.x;
|
|
|
|
int r1_right = r1_left + surface1->w;
|
|
|
|
int r2_left = p2.x;
|
|
|
|
int r2_right = r2_left + surface2->w;
|
|
|
|
|
|
|
|
int r1_bottom = p1.y;
|
|
|
|
int r1_top = p1.y + surface1->h;
|
|
|
|
int r2_bottom = p2.y;
|
|
|
|
int r2_top = p2.y + surface2->h;
|
|
|
|
|
2020-08-04 09:55:18 +02:00
|
|
|
SDL_Rect rect1 = {p1.x, p1.y, surface1->w, surface1->h};
|
|
|
|
SDL_Rect rect2 = {p2.x, p2.y, surface2->w, surface2->h};
|
|
|
|
bool intersection = help.intersects(rect1, rect2);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if(intersection)
|
|
|
|
{
|
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-23 01:43:31 +01:00
|
|
|
int r3_left = SDL_max(r1_left, r2_left);
|
|
|
|
int r3_top = SDL_min(r1_top, r2_top);
|
|
|
|
int r3_right = SDL_min(r1_right, r2_right);
|
|
|
|
int r3_bottom= SDL_max(r1_bottom, r2_bottom);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//for every pixel inside rectangle
|
|
|
|
for(int x = r3_left; x < r3_right; x++)
|
|
|
|
{
|
|
|
|
for(int y = r3_bottom; y < r3_top; y++)
|
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color pixel1 = ReadPixel(surface1, x - p1.x, y - p1.y);
|
|
|
|
const SDL_Color pixel2 = ReadPixel(surface2, x - p2.x, y - p2.y);
|
2021-10-07 08:18:58 +02:00
|
|
|
/* INTENTIONAL BUG! In previous versions, the game mistakenly
|
|
|
|
* checked the red channel, not the alpha channel.
|
|
|
|
* We preserve it here because some people abuse this. */
|
2023-01-02 01:36:43 +01:00
|
|
|
if (pixel1.r != 0 && pixel2.r != 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 09:56:45 +02:00
|
|
|
return false;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawgravityline( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-11-01 05:23:59 +01:00
|
|
|
if (!INBOUNDS_VEC(t, obj.entities))
|
|
|
|
{
|
|
|
|
WHINE_ONCE("drawgravityline() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-08 02:29:06 +01:00
|
|
|
if (obj.entities[t].life == 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
switch(linestate)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(200-20, 200-20, 200-20));
|
|
|
|
break;
|
|
|
|
case 1:
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer,line_rect, getRGB(245-30, 245-30, 225-30));
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer,line_rect, getRGB(225-30, 245-30, 245-30));
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 3:
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer,line_rect, getRGB(200-20, 200-20, 164-10));
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 4:
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer,line_rect, getRGB(196-20, 255-30, 224-20));
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 5:
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer,line_rect, getRGB(196-20, 235-30, 205-20));
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(164-10, 164-10, 164-10));
|
|
|
|
break;
|
|
|
|
case 7:
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer,line_rect, getRGB(205-20, 245-30, 225-30));
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 8:
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer,line_rect, getRGB(225-30, 255-30, 205-20));
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(245-30, 245-30, 245-30));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(96, 96, 96));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::drawtrophytext(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
int temp, temp2, temp3;
|
|
|
|
|
|
|
|
if (obj.trophytext < 15)
|
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
const int usethismult = lerp(obj.oldtrophytext, obj.trophytext);
|
2020-04-30 01:54:36 +02:00
|
|
|
temp = (196 * usethismult) / 15;
|
|
|
|
temp2 = (196 * usethismult) / 15;
|
|
|
|
temp3 = ((255 - help.glow) * usethismult) / 15;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
temp = 196;
|
|
|
|
temp2 = 196;
|
|
|
|
temp3 = 255 - help.glow;
|
|
|
|
}
|
2022-12-30 23:39:12 +01:00
|
|
|
|
|
|
|
/* These were originally all at the top of the screen, but might be too tight for localization.
|
|
|
|
* It probably makes sense to make them all have a top text now, but for now this is probably fine.
|
|
|
|
* Look at the Steam achievements, they have pretty logical titles that should probably be used. */
|
|
|
|
const char* top_text = NULL;
|
|
|
|
const char* bottom_text = NULL;
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
switch(obj.trophytype)
|
|
|
|
{
|
|
|
|
case 1:
|
2022-12-30 23:39:12 +01:00
|
|
|
top_text = loc::gettext("SPACE STATION 1 MASTERED");
|
|
|
|
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2022-12-30 23:39:12 +01:00
|
|
|
top_text = loc::gettext("LABORATORY MASTERED");
|
|
|
|
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 3:
|
2022-12-30 23:39:12 +01:00
|
|
|
top_text = loc::gettext("THE TOWER MASTERED");
|
|
|
|
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 4:
|
2022-12-30 23:39:12 +01:00
|
|
|
top_text = loc::gettext("SPACE STATION 2 MASTERED");
|
|
|
|
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 5:
|
2022-12-30 23:39:12 +01:00
|
|
|
top_text = loc::gettext("WARP ZONE MASTERED");
|
|
|
|
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 6:
|
2022-12-30 23:39:12 +01:00
|
|
|
top_text = loc::gettext("FINAL LEVEL MASTERED");
|
|
|
|
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 7:
|
2022-12-30 23:39:12 +01:00
|
|
|
top_text = loc::gettext("GAME COMPLETE");
|
|
|
|
bottom_text = loc::gettext("Complete the game");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 8:
|
2022-12-30 23:39:12 +01:00
|
|
|
top_text = loc::gettext("FLIP MODE COMPLETE");
|
|
|
|
bottom_text = loc::gettext("Complete the game in flip mode");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 9:
|
2022-12-30 23:39:12 +01:00
|
|
|
bottom_text = loc::gettext("Win with less than 50 deaths");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 10:
|
2022-12-30 23:39:12 +01:00
|
|
|
bottom_text = loc::gettext("Win with less than 100 deaths");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 11:
|
2022-12-30 23:39:12 +01:00
|
|
|
bottom_text = loc::gettext("Win with less than 250 deaths");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 12:
|
2022-12-30 23:39:12 +01:00
|
|
|
bottom_text = loc::gettext("Win with less than 500 deaths");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 13:
|
2022-12-30 23:39:12 +01:00
|
|
|
bottom_text = loc::gettext("Last 5 seconds on the Super Gravitron");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 14:
|
2022-12-30 23:39:12 +01:00
|
|
|
bottom_text = loc::gettext("Last 10 seconds on the Super Gravitron");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 15:
|
2022-12-30 23:39:12 +01:00
|
|
|
bottom_text = loc::gettext("Last 15 seconds on the Super Gravitron");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 16:
|
2022-12-30 23:39:12 +01:00
|
|
|
bottom_text = loc::gettext("Last 20 seconds on the Super Gravitron");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 17:
|
2022-12-30 23:39:12 +01:00
|
|
|
bottom_text = loc::gettext("Last 30 seconds on the Super Gravitron");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 18:
|
2022-12-30 23:39:12 +01:00
|
|
|
bottom_text = loc::gettext("Last 1 minute on the Super Gravitron");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 20:
|
2022-12-30 23:39:12 +01:00
|
|
|
top_text = loc::gettext("MASTER OF THE UNIVERSE");
|
|
|
|
bottom_text = loc::gettext("Complete the game in no death mode");
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
}
|
2022-12-30 23:39:12 +01:00
|
|
|
|
|
|
|
/* These were `bprint` before */
|
|
|
|
short lines;
|
|
|
|
if (top_text != NULL)
|
|
|
|
{
|
|
|
|
string_wordwrap(top_text, 304, &lines);
|
|
|
|
PrintWrap(-1, 11-(lines-1)*5, top_text, temp, temp2, temp3, true);
|
|
|
|
}
|
|
|
|
if (bottom_text != NULL)
|
|
|
|
{
|
|
|
|
string_wordwrap(bottom_text, 304, &lines);
|
|
|
|
PrintWrap(-1, 221-(lines-1)*5, bottom_text, temp, temp2, temp3, true);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::drawentities(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-11-01 05:38:15 +01:00
|
|
|
const int yoff = map.towermode ? lerp(map.oldypos, map.ypos) : 0;
|
|
|
|
|
Fix crewmates being drawn behind other entities
This fixes the draw order by drawing all other entities first, before
then drawing all humanoids[1] after, including the player afterwards.
This is actually a regression fix from #191. When I was testing this, I
was thinking about where get a crewmate in front of another entity in
the main game, other than the checkpoints in Intermission 1. And then I
thought about the teleporters, because I remember the pre-Deep Space
cutscene in Dimension Open looking funny because Vita ended up being
behind the teleporter. (Actually, a lot of the cutscenes of Dimension
Open look funny because of crewmates standing behind terminals.)
So then I tried to get crewmates in front of teleporters. It actually
turns out that you can't do it for most of them... except for Verdigris.
And then that's what I realized why there was an oddity in WarpClass.cpp
when I was removing the `active` system from the game - for some reason,
the game put a hole in `obj.entities` between the teleporter and the
player when loading the room Murdering Twinmaker. In a violation of
Chesterton's Fence (the principle that you should understand something
before removing it), I shrugged it off and decided "there's no way to
support having holes with my new system, and having holes is probably
bad anyway, so I'm going to remove this and move on". The fact that
there wasn't any comments clarifying the mysterious code didn't help
(but, this *was* 2.2 code after all; have you *seen* 2.2 code?!).
And it turns out that this maneuver was done so Verdigris would fill
that hole when he got created, and Verdigris being first before the
teleporter would mean he would be drawn in front of the teleporter,
instead of being behind it. So ever since
b1b1474b7bbc3ceddea24f689a7ddb050cfe4490 got merged, there has actually
been a regression from 2.2 where Verdigris got drawn behind the
teleporter in Murdering Twinmaker, instead of properly being in front of
it like in 2.2 and previous.
This patch fixes that regression, but it actually properly fixes it
instead of hacking around with the `active` system.
Closes #426.
[1]: I'm going to go on a rant here, so hear me out. It's not explicitly
stated that the characters in VVVVVV are human. So, given this
information, what do we call them? Well, the VVVVVV community (at least
the custom levels one, I don't think the speedrunning community does
this or is preoccupied with lore in the first place) decided to call
them "villis", because of the roomname "The Villi People" - which is
only one blunder in a series of awful headcanons based off of the
assumption that the intent of Bennett Foddy (who named the roomnames)
was to decree some sort of lore to the game. Another one being
"Verdigris can't flip" because of "Green Dudes Can't Flip". Then an OC
(original character) got named based off of "The Voon Show" too. And so
on and so forth.
2020-11-01 07:23:40 +01:00
|
|
|
if (!map.custommode)
|
2020-11-01 05:38:15 +01:00
|
|
|
{
|
Fix crewmates being drawn behind other entities
This fixes the draw order by drawing all other entities first, before
then drawing all humanoids[1] after, including the player afterwards.
This is actually a regression fix from #191. When I was testing this, I
was thinking about where get a crewmate in front of another entity in
the main game, other than the checkpoints in Intermission 1. And then I
thought about the teleporters, because I remember the pre-Deep Space
cutscene in Dimension Open looking funny because Vita ended up being
behind the teleporter. (Actually, a lot of the cutscenes of Dimension
Open look funny because of crewmates standing behind terminals.)
So then I tried to get crewmates in front of teleporters. It actually
turns out that you can't do it for most of them... except for Verdigris.
And then that's what I realized why there was an oddity in WarpClass.cpp
when I was removing the `active` system from the game - for some reason,
the game put a hole in `obj.entities` between the teleporter and the
player when loading the room Murdering Twinmaker. In a violation of
Chesterton's Fence (the principle that you should understand something
before removing it), I shrugged it off and decided "there's no way to
support having holes with my new system, and having holes is probably
bad anyway, so I'm going to remove this and move on". The fact that
there wasn't any comments clarifying the mysterious code didn't help
(but, this *was* 2.2 code after all; have you *seen* 2.2 code?!).
And it turns out that this maneuver was done so Verdigris would fill
that hole when he got created, and Verdigris being first before the
teleporter would mean he would be drawn in front of the teleporter,
instead of being behind it. So ever since
b1b1474b7bbc3ceddea24f689a7ddb050cfe4490 got merged, there has actually
been a regression from 2.2 where Verdigris got drawn behind the
teleporter in Murdering Twinmaker, instead of properly being in front of
it like in 2.2 and previous.
This patch fixes that regression, but it actually properly fixes it
instead of hacking around with the `active` system.
Closes #426.
[1]: I'm going to go on a rant here, so hear me out. It's not explicitly
stated that the characters in VVVVVV are human. So, given this
information, what do we call them? Well, the VVVVVV community (at least
the custom levels one, I don't think the speedrunning community does
this or is preoccupied with lore in the first place) decided to call
them "villis", because of the roomname "The Villi People" - which is
only one blunder in a series of awful headcanons based off of the
assumption that the intent of Bennett Foddy (who named the roomnames)
was to decree some sort of lore to the game. Another one being
"Verdigris can't flip" because of "Green Dudes Can't Flip". Then an OC
(original character) got named based off of "The Voon Show" too. And so
on and so forth.
2020-11-01 07:23:40 +01:00
|
|
|
for (int i = obj.entities.size() - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (!obj.entities[i].ishumanoid())
|
|
|
|
{
|
|
|
|
drawentity(i, yoff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = obj.entities.size() - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (obj.entities[i].ishumanoid())
|
|
|
|
{
|
|
|
|
drawentity(i, yoff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (int i = obj.entities.size() - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
drawentity(i, yoff);
|
|
|
|
}
|
2020-11-01 05:38:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawentity(const int i, const int yoff)
|
|
|
|
{
|
|
|
|
if (!INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
WHINE_ONCE("drawentity() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-01 05:39:19 +01:00
|
|
|
if (obj.entities[i].invis)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-11-01 05:38:15 +01:00
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
point tpoint;
|
|
|
|
|
|
|
|
SDL_Rect drawRect;
|
|
|
|
|
2020-06-30 00:27:23 +02:00
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
|
|
|
// Special case for gray Warp Zone tileset!
|
2021-02-21 00:45:48 +01:00
|
|
|
const RoomProperty* const room = cl.getroomprop(game.roomx - 100, game.roomy - 100);
|
2021-03-24 19:59:36 +01:00
|
|
|
const bool custom_gray = room->tileset == 3 && room->tilecol == 6;
|
2020-06-30 00:27:23 +02:00
|
|
|
#else
|
2020-10-20 08:57:23 +02:00
|
|
|
const bool custom_gray = false;
|
2020-06-30 00:27:23 +02:00
|
|
|
#endif
|
|
|
|
|
2020-10-20 08:55:49 +02:00
|
|
|
std::vector<SDL_Surface*>& tilesvec = (map.custommode && !map.finalmode) ? entcolours : tiles;
|
2020-04-25 23:29:26 +02:00
|
|
|
|
2020-10-20 08:55:49 +02:00
|
|
|
std::vector<SDL_Surface*>& spritesvec = flipmode ? flipsprites : sprites;
|
2020-04-26 04:47:09 +02:00
|
|
|
|
2020-11-01 05:39:19 +01:00
|
|
|
const int xp = lerp(obj.entities[i].lerpoldxp, obj.entities[i].xp);
|
|
|
|
const int yp = lerp(obj.entities[i].lerpoldyp, obj.entities[i].yp);
|
2020-04-29 01:02:55 +02:00
|
|
|
|
2020-11-01 05:39:19 +01:00
|
|
|
switch (obj.entities[i].size)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
// Sprites
|
|
|
|
if (!INBOUNDS_VEC(obj.entities[i].drawframe, spritesvec))
|
2020-04-26 20:13:47 +02:00
|
|
|
{
|
2020-11-01 05:39:19 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
2023-01-02 05:16:08 +01:00
|
|
|
const SDL_Color ct = obj.entities[i].realcol;
|
2020-11-01 05:39:19 +01:00
|
|
|
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe], NULL, backBuffer, &drawRect, ct);
|
|
|
|
|
|
|
|
//screenwrapping!
|
|
|
|
point wrappedPoint;
|
|
|
|
bool wrapX = false;
|
|
|
|
bool wrapY = false;
|
|
|
|
|
|
|
|
wrappedPoint.x = tpoint.x;
|
|
|
|
if (tpoint.x < 0)
|
2020-07-29 18:17:28 +02:00
|
|
|
{
|
2020-11-01 05:39:19 +01:00
|
|
|
wrapX = true;
|
|
|
|
wrappedPoint.x += 320;
|
|
|
|
}
|
2021-12-21 05:13:36 +01:00
|
|
|
else if (tpoint.x > 288)
|
2020-11-01 05:39:19 +01:00
|
|
|
{
|
|
|
|
wrapX = true;
|
|
|
|
wrappedPoint.x -= 320;
|
|
|
|
}
|
|
|
|
|
|
|
|
wrappedPoint.y = tpoint.y;
|
2021-04-14 03:26:06 +02:00
|
|
|
if (tpoint.y < 8)
|
2020-11-01 05:39:19 +01:00
|
|
|
{
|
|
|
|
wrapY = true;
|
2021-04-14 03:21:21 +02:00
|
|
|
wrappedPoint.y += 232;
|
2020-11-01 05:39:19 +01:00
|
|
|
}
|
2021-12-21 05:13:36 +01:00
|
|
|
else if (tpoint.y > 200)
|
2020-11-01 05:39:19 +01:00
|
|
|
{
|
|
|
|
wrapY = true;
|
2021-04-14 03:21:21 +02:00
|
|
|
wrappedPoint.y -= 232;
|
2020-11-01 05:39:19 +01:00
|
|
|
}
|
2020-04-26 20:13:47 +02:00
|
|
|
|
2020-11-01 05:39:19 +01:00
|
|
|
const bool isInWrappingAreaOfTower = map.towermode && !map.minitowermode && map.ypos >= 500 && map.ypos <= 5000;
|
|
|
|
if (wrapX && (map.warpx || isInWrappingAreaOfTower))
|
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
drawRect = sprites_rect;
|
2020-11-01 05:39:19 +01:00
|
|
|
drawRect.x += wrappedPoint.x;
|
2020-04-26 20:13:47 +02:00
|
|
|
drawRect.y += tpoint.y;
|
2020-10-20 08:55:49 +02:00
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe], NULL, backBuffer, &drawRect, ct);
|
2020-07-29 18:17:28 +02:00
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
if (wrapY && map.warpy)
|
|
|
|
{
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += wrappedPoint.y;
|
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe], NULL, backBuffer, &drawRect, ct);
|
|
|
|
}
|
|
|
|
if (wrapX && wrapY && map.warpx && map.warpy)
|
|
|
|
{
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += wrappedPoint.x;
|
|
|
|
drawRect.y += wrappedPoint.y;
|
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe], NULL, backBuffer, &drawRect, ct);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
// Tiles
|
|
|
|
if (!INBOUNDS_VEC(obj.entities[i].drawframe, tiles))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
|
|
|
drawRect = tiles_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceStandard(tiles[obj.entities[i].drawframe],NULL, backBuffer, &drawRect);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 8:
|
|
|
|
{
|
|
|
|
// Special: Moving platform, 4 tiles or 8 tiles
|
|
|
|
if (!INBOUNDS_VEC(obj.entities[i].drawframe, tilesvec))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
|
|
|
int thiswidth = 4;
|
|
|
|
if (obj.entities[i].size == 8)
|
|
|
|
{
|
|
|
|
thiswidth = 8;
|
|
|
|
}
|
|
|
|
for (int ii = 0; ii < thiswidth; ii++)
|
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
drawRect = tiles_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2020-11-01 05:39:19 +01:00
|
|
|
drawRect.x += 8 * ii;
|
|
|
|
if (custom_gray)
|
2020-06-14 03:35:12 +02:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color temp_ct = {255, 255, 255, 255};
|
|
|
|
BlitSurfaceTinted(tilesvec[obj.entities[i].drawframe], NULL, backBuffer, &drawRect, temp_ct);
|
2020-06-14 03:35:12 +02:00
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
else
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-11-01 05:39:19 +01:00
|
|
|
BlitSurfaceStandard(tilesvec[obj.entities[i].drawframe],NULL, backBuffer, &drawRect);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-26 20:13:47 +02:00
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3: // Big chunky pixels!
|
|
|
|
prect.x = xp;
|
|
|
|
prect.y = yp - yoff;
|
|
|
|
FillRect(backBuffer, prect, obj.entities[i].realcol);
|
|
|
|
break;
|
|
|
|
case 4: // Small pickups
|
2023-01-02 05:16:08 +01:00
|
|
|
drawhuetile(xp, yp - yoff, obj.entities[i].tile, obj.entities[i].realcol);
|
2020-11-01 05:39:19 +01:00
|
|
|
break;
|
|
|
|
case 5: //Horizontal Line
|
|
|
|
{
|
|
|
|
int oldw = obj.entities[i].w;
|
|
|
|
if ((game.swngame == 3 || kludgeswnlinewidth) && obj.getlineat(84 - 32) == i)
|
2020-05-02 02:57:07 +02:00
|
|
|
{
|
2020-11-01 05:39:19 +01:00
|
|
|
oldw -= 24;
|
|
|
|
}
|
|
|
|
line_rect.x = xp;
|
|
|
|
line_rect.y = yp - yoff;
|
|
|
|
line_rect.w = lerp(oldw, obj.entities[i].w);
|
|
|
|
line_rect.h = 1;
|
|
|
|
drawgravityline(i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 6: //Vertical Line
|
|
|
|
line_rect.x = xp;
|
|
|
|
line_rect.y = yp - yoff;
|
|
|
|
line_rect.w = 1;
|
|
|
|
line_rect.h = obj.entities[i].h;
|
|
|
|
drawgravityline(i);
|
|
|
|
break;
|
|
|
|
case 7: //Teleporter
|
|
|
|
drawtele(xp, yp - yoff, obj.entities[i].drawframe, obj.entities[i].realcol);
|
|
|
|
break;
|
|
|
|
//case 8: // Special: Moving platform, 8 tiles
|
|
|
|
// Note: This code is in the 4-tile code
|
|
|
|
break;
|
|
|
|
case 9: // Really Big Sprite! (2x2)
|
2023-01-02 05:16:08 +01:00
|
|
|
{
|
|
|
|
const SDL_Color ct = obj.entities[i].realcol;
|
2020-11-01 05:39:19 +01:00
|
|
|
|
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
|
|
|
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2021-03-24 20:32:43 +01:00
|
|
|
if (INBOUNDS_VEC(obj.entities[i].drawframe, spritesvec))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
|
|
|
|
tpoint.x = xp+32;
|
|
|
|
tpoint.y = yp - yoff;
|
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2021-03-24 20:32:43 +01:00
|
|
|
if (INBOUNDS_VEC(obj.entities[i].drawframe+1, spritesvec))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe+1],NULL, backBuffer, &drawRect, ct);
|
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
|
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp+32 - yoff;
|
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2021-03-24 20:32:43 +01:00
|
|
|
if (INBOUNDS_VEC(obj.entities[i].drawframe+12, spritesvec))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe+12],NULL, backBuffer, &drawRect, ct);
|
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
|
|
|
|
tpoint.x = xp+32;
|
|
|
|
tpoint.y = yp+32 - yoff;
|
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2021-03-24 20:32:43 +01:00
|
|
|
if (INBOUNDS_VEC(obj.entities[i].drawframe+13, spritesvec))
|
2020-11-01 05:39:19 +01:00
|
|
|
{
|
2021-03-24 20:32:43 +01:00
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe + 13],NULL, backBuffer, &drawRect, ct);
|
2020-11-01 05:39:19 +01:00
|
|
|
}
|
2021-03-24 20:32:43 +01:00
|
|
|
break;
|
2023-01-02 05:16:08 +01:00
|
|
|
}
|
2021-03-24 20:32:43 +01:00
|
|
|
case 10: // 2x1 Sprite
|
2023-01-02 05:16:08 +01:00
|
|
|
{
|
|
|
|
const SDL_Color ct = obj.entities[i].realcol;
|
2020-11-01 05:39:19 +01:00
|
|
|
|
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2021-03-24 20:32:43 +01:00
|
|
|
if (INBOUNDS_VEC(obj.entities[i].drawframe, spritesvec))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
|
|
|
|
tpoint.x = xp+32;
|
|
|
|
tpoint.y = yp - yoff;
|
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2021-03-24 20:32:43 +01:00
|
|
|
if (INBOUNDS_VEC(obj.entities[i].drawframe+1, spritesvec))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe+1],NULL, backBuffer, &drawRect, ct);
|
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
break;
|
2023-01-02 05:16:08 +01:00
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
case 11: //The fucking elephant
|
2023-01-02 05:16:08 +01:00
|
|
|
drawimagecol(3, xp, yp - yoff, obj.entities[i].realcol);
|
2020-11-01 05:39:19 +01:00
|
|
|
break;
|
|
|
|
case 12: // Regular sprites that don't wrap
|
2023-01-02 05:16:08 +01:00
|
|
|
{
|
2020-11-01 05:39:19 +01:00
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
2023-01-02 05:16:08 +01:00
|
|
|
const SDL_Color ct = obj.entities[i].realcol;
|
2020-11-01 05:39:19 +01:00
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2021-03-24 20:32:43 +01:00
|
|
|
if (INBOUNDS_VEC(obj.entities[i].drawframe, spritesvec))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
|
|
|
|
|
|
|
|
//if we're outside the screen, we need to draw indicators
|
|
|
|
|
|
|
|
if (obj.entities[i].xp < -20 && obj.entities[i].vx > 0)
|
|
|
|
{
|
|
|
|
if (obj.entities[i].xp < -100)
|
2020-05-02 02:57:07 +02:00
|
|
|
{
|
2021-06-12 07:20:06 +02:00
|
|
|
tpoint.x = -5 + (int(( -xp) / 10));
|
2020-05-02 02:57:07 +02:00
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
else
|
2020-06-14 03:35:12 +02:00
|
|
|
{
|
2020-11-01 05:39:19 +01:00
|
|
|
tpoint.x = 5;
|
2020-06-14 03:35:12 +02:00
|
|
|
}
|
2020-04-26 20:13:47 +02:00
|
|
|
|
2020-11-01 05:39:19 +01:00
|
|
|
tpoint.y = tpoint.y+4;
|
2020-04-26 20:13:47 +02:00
|
|
|
|
|
|
|
|
2020-11-01 05:39:19 +01:00
|
|
|
drawRect = tiles_rect;
|
2020-04-26 20:13:47 +02:00
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2021-03-24 20:32:43 +01:00
|
|
|
if (INBOUNDS_VEC(1167, tiles))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured(tiles[1167],NULL, backBuffer, &drawRect, ct);
|
|
|
|
}
|
2020-04-26 20:13:47 +02:00
|
|
|
|
2020-11-01 05:39:19 +01:00
|
|
|
}
|
|
|
|
else if (obj.entities[i].xp > 340 && obj.entities[i].vx < 0)
|
|
|
|
{
|
|
|
|
if (obj.entities[i].xp > 420)
|
2020-06-14 03:35:12 +02:00
|
|
|
{
|
2021-06-12 07:20:06 +02:00
|
|
|
tpoint.x = 320 - (int(( xp-320) / 10));
|
2020-06-14 03:35:12 +02:00
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
else
|
2020-06-14 03:35:12 +02:00
|
|
|
{
|
2020-11-01 05:39:19 +01:00
|
|
|
tpoint.x = 310;
|
2020-06-14 03:35:12 +02:00
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
|
|
|
|
tpoint.y = tpoint.y+4;
|
2020-04-26 20:13:47 +02:00
|
|
|
//
|
2020-11-01 05:39:19 +01:00
|
|
|
|
|
|
|
drawRect = tiles_rect;
|
2020-04-26 20:13:47 +02:00
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2021-03-24 20:32:43 +01:00
|
|
|
if (INBOUNDS_VEC(1166, tiles))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured(tiles[1166],NULL, backBuffer, &drawRect, ct);
|
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
}
|
|
|
|
break;
|
2023-01-02 05:16:08 +01:00
|
|
|
}
|
2020-11-01 05:39:19 +01:00
|
|
|
case 13:
|
|
|
|
{
|
|
|
|
//Special for epilogue: huge hero!
|
|
|
|
if (!INBOUNDS_VEC(obj.entities[i].drawframe, spritesvec))
|
2020-04-26 20:13:47 +02:00
|
|
|
{
|
2020-11-01 05:39:19 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-04-26 04:50:09 +02:00
|
|
|
|
2020-11-01 05:39:19 +01:00
|
|
|
tpoint.x = xp; tpoint.y = yp - yoff;
|
Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).
Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)
We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 20:13:12 +02:00
|
|
|
setRect(drawRect, xp, yp - yoff, sprites_rect.x * 6, sprites_rect.y * 6);
|
2020-11-01 05:39:19 +01:00
|
|
|
SDL_Surface* TempSurface = ScaleSurface( spritesvec[obj.entities[i].drawframe], 6 * sprites_rect.w,6* sprites_rect.h );
|
2023-01-02 05:16:08 +01:00
|
|
|
BlitSurfaceColoured(TempSurface, NULL, backBuffer, &drawRect, obj.entities[i].realcol);
|
2022-12-01 07:30:16 +01:00
|
|
|
VVV_freefunc(SDL_FreeSurface, TempSurface);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2020-11-01 05:39:19 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawbackground( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
//Starfield
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(backBuffer);
|
2020-07-03 11:31:13 +02:00
|
|
|
for (int i = 0; i < numstars; i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
stars[i].w = 2;
|
|
|
|
stars[i].h = 2;
|
2020-04-29 04:30:37 +02:00
|
|
|
SDL_Rect star_rect = stars[i];
|
|
|
|
star_rect.x = lerp(star_rect.x + starsspeed[i], star_rect.x);
|
2020-01-01 21:29:24 +01:00
|
|
|
if (starsspeed[i] <= 6)
|
|
|
|
{
|
2020-04-29 04:30:37 +02:00
|
|
|
FillRect(backBuffer,star_rect, getRGB(0x22,0x22,0x22));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-29 04:30:37 +02:00
|
|
|
FillRect(backBuffer,star_rect, getRGB(0x55,0x55,0x55));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
2020-11-02 22:02:51 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Color bcol;
|
|
|
|
SDL_Color bcol2;
|
|
|
|
SDL_zero(bcol);
|
|
|
|
SDL_zero(bcol2);
|
2020-11-02 22:02:51 +01:00
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//Lab
|
|
|
|
switch(rcol)
|
|
|
|
{
|
|
|
|
//Akward ordering to match tileset
|
|
|
|
case 0:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(0, 16*backboxint[0], 16*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Cyan
|
|
|
|
case 1:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(16*backboxint[0], 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Red
|
|
|
|
case 2:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(16*backboxint[0], 0, 16*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Purple
|
|
|
|
case 3:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(0, 0, 16*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Blue
|
|
|
|
case 4:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(16*backboxint[0], 16*backboxint[0], 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Yellow
|
|
|
|
case 5:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(0, 16 * backboxint[0], 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Green
|
|
|
|
case 6:
|
|
|
|
//crazy case
|
|
|
|
switch(spcol)
|
|
|
|
{
|
|
|
|
case 0:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(0, 16*backboxint[0], 16*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Cyan
|
|
|
|
case 1:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(0, (spcoldel+1)*backboxint[0], 16*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Cyan
|
|
|
|
case 2:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(0, 0, 16*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Blue
|
|
|
|
case 3:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB((16-spcoldel)*backboxint[0], 0, 16*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Blue
|
|
|
|
case 4:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(16*backboxint[0], 0, 16*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Purple
|
|
|
|
case 5:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(16*backboxint[0], 0, (spcoldel+1)*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Purple
|
|
|
|
case 6:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(16*backboxint[0], 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Red
|
|
|
|
case 7:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(16*backboxint[0], (16-spcoldel)*backboxint[0], 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Red
|
|
|
|
case 8:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(16*backboxint[0], 16*backboxint[0], 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Yellow
|
|
|
|
case 9:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB((spcoldel+1)*backboxint[0], 16*backboxint[0], 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Yellow
|
|
|
|
case 10:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(0, 16 * backboxint[0], 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Green
|
|
|
|
case 11:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol2 = getRGB(0, 16 * backboxint[0], (16-spcoldel)*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Green
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
FillRect(backBuffer,bcol2);
|
|
|
|
|
2020-07-03 11:31:13 +02:00
|
|
|
for (int i = 0; i < numbackboxes; i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
switch(rcol)
|
|
|
|
{
|
|
|
|
//Akward ordering to match tileset
|
|
|
|
case 0:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(16, 128*backboxint[0], 128*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Cyan
|
|
|
|
case 1:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(128*backboxint[0], 16, 16);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Red
|
|
|
|
case 2:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(128*backboxint[0], 16, 128*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Purple
|
|
|
|
case 3:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(16, 16, 128*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Blue
|
|
|
|
case 4:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(128*backboxint[0], 128*backboxint[0], 16);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Yellow
|
|
|
|
case 5:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(16, 128 * backboxint[0], 16);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Green
|
|
|
|
case 6:
|
|
|
|
//crazy case
|
|
|
|
switch(spcol)
|
|
|
|
{
|
|
|
|
case 0:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(16, 128*backboxint[0], 128*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Cyan
|
|
|
|
case 1:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(16, ((spcoldel+1)*8)*backboxint[0], 128*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Cyan
|
|
|
|
case 2:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(16, 16, 128*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Blue
|
|
|
|
case 3:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB((128-(spcoldel*8))*backboxint[0], 16, 128*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Blue
|
|
|
|
case 4:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(128*backboxint[0], 16, 128*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Purple
|
|
|
|
case 5:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(128*backboxint[0], 16, ((spcoldel+1)*8)*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Purple
|
|
|
|
case 6:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(128*backboxint[0], 16, 16);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Red
|
|
|
|
case 7:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(128*backboxint[0], (128-(spcoldel*8))*backboxint[0], 16);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Red
|
|
|
|
case 8:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(128*backboxint[0], 128*backboxint[0], 16);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Yellow
|
|
|
|
case 9:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(((spcoldel+1)*8)*backboxint[0], 128*backboxint[0], 16);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Yellow
|
|
|
|
case 10:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(16, 128 * backboxint[0], 16);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Green
|
|
|
|
case 11:
|
2021-09-11 11:15:20 +02:00
|
|
|
bcol = getRGB(16, 128 * backboxint[0], (128-(spcoldel*8))*backboxint[0]);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Green
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-04-29 04:45:18 +02:00
|
|
|
|
2020-04-29 04:54:53 +02:00
|
|
|
SDL_Rect backboxrect = backboxes[i];
|
2020-04-29 04:45:18 +02:00
|
|
|
backboxrect.x = lerp(backboxes[i].x - backboxvx[i], backboxes[i].x);
|
|
|
|
backboxrect.y = lerp(backboxes[i].y - backboxvy[i], backboxes[i].y);
|
|
|
|
|
|
|
|
FillRect(backBuffer, backboxrect, bcol);
|
|
|
|
backboxrect.x += 1;
|
|
|
|
backboxrect.y += 1;
|
|
|
|
backboxrect.w -= 2;
|
|
|
|
backboxrect.h -= 2;
|
2020-01-01 21:29:24 +01:00
|
|
|
FillRect(backBuffer,backboxrect, bcol2);
|
|
|
|
}
|
|
|
|
break;
|
2020-11-02 22:02:51 +01:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
case 3: //Warp zone (horizontal)
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(backBuffer);
|
2020-11-03 01:54:17 +01:00
|
|
|
BlitSurfaceStandard(warpbuffer, NULL, warpbuffer_lerp, NULL);
|
|
|
|
ScrollSurface(warpbuffer_lerp, lerp(0, -3), 0);
|
|
|
|
BlitSurfaceStandard(warpbuffer_lerp, &towerbuffer_rect, backBuffer, NULL);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 4: //Warp zone (vertical)
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(backBuffer);
|
2020-11-03 01:54:17 +01:00
|
|
|
SDL_BlitSurface(warpbuffer, NULL, warpbuffer_lerp, NULL);
|
|
|
|
ScrollSurface(warpbuffer_lerp, 0, lerp(0, -3));
|
|
|
|
SDL_BlitSurface(warpbuffer_lerp, &towerbuffer_rect, backBuffer, NULL);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 5:
|
2023-01-02 20:15:54 +01:00
|
|
|
{
|
2020-01-01 21:29:24 +01:00
|
|
|
//Warp zone, central
|
2023-01-02 20:15:54 +01:00
|
|
|
SDL_Color warpbcol;
|
|
|
|
SDL_Color warpfcol;
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
switch(rcol)
|
|
|
|
{
|
|
|
|
//Akward ordering to match tileset
|
|
|
|
case 0:
|
2021-09-11 11:15:20 +02:00
|
|
|
warpbcol = getRGB(0x0A, 0x10, 0x0E);
|
|
|
|
warpfcol = getRGB(0x10, 0x22, 0x21);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Cyan
|
|
|
|
case 1:
|
2021-09-11 11:15:20 +02:00
|
|
|
warpbcol = getRGB(0x11, 0x09, 0x0B);
|
|
|
|
warpfcol = getRGB(0x22, 0x10, 0x11);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Red
|
|
|
|
case 2:
|
2021-09-11 11:15:20 +02:00
|
|
|
warpbcol = getRGB(0x0F, 0x0A, 0x10);
|
|
|
|
warpfcol = getRGB(0x22,0x10,0x22);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Purple
|
|
|
|
case 3:
|
2021-09-11 11:15:20 +02:00
|
|
|
warpbcol = getRGB(0x0A, 0x0B, 0x10);
|
|
|
|
warpfcol = getRGB(0x10, 0x10, 0x22);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Blue
|
|
|
|
case 4:
|
2021-09-11 11:15:20 +02:00
|
|
|
warpbcol = getRGB(0x10, 0x0D, 0x0A);
|
|
|
|
warpfcol = getRGB(0x22, 0x1E, 0x10);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Yellow
|
|
|
|
case 5:
|
2021-09-11 11:15:20 +02:00
|
|
|
warpbcol = getRGB(0x0D, 0x10, 0x0A);
|
|
|
|
warpfcol = getRGB(0x14, 0x22, 0x10);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Green
|
|
|
|
case 6:
|
2021-09-11 11:15:20 +02:00
|
|
|
warpbcol = getRGB(0x0A, 0x0A, 0x0A);
|
|
|
|
warpfcol = getRGB(0x12, 0x12, 0x12);
|
2020-01-01 21:29:24 +01:00
|
|
|
break; //Gray
|
2020-04-02 22:05:48 +02:00
|
|
|
default:
|
2021-09-11 11:15:20 +02:00
|
|
|
warpbcol = getRGB(0xFF, 0xFF, 0xFF);
|
|
|
|
warpfcol = getRGB(0xFF, 0xFF, 0xFF);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 10 ; i >= 0; i--)
|
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
const int temp = (i * 16) + backoffset;
|
2023-01-02 20:15:54 +01:00
|
|
|
const SDL_Rect warprect = {160 - temp, 120 - temp, temp * 2, temp * 2};
|
2020-01-01 21:29:24 +01:00
|
|
|
if (i % 2 == warpskip)
|
|
|
|
{
|
|
|
|
FillRect(backBuffer, warprect, warpbcol);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-01-02 20:15:54 +01:00
|
|
|
FillRect(backBuffer, warprect, warpfcol);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2023-01-02 20:15:54 +01:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
case 6:
|
|
|
|
//Final Starfield
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(backBuffer);
|
2020-07-03 11:31:13 +02:00
|
|
|
for (int i = 0; i < numstars; i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-29 04:52:59 +02:00
|
|
|
stars[i].w = 2;
|
|
|
|
stars[i].h = 2;
|
|
|
|
SDL_Rect star_rect = stars[i];
|
|
|
|
star_rect.y = lerp(star_rect.y + starsspeed[i], star_rect.y);
|
2020-01-01 21:29:24 +01:00
|
|
|
if (starsspeed[i] <= 8)
|
|
|
|
{
|
2020-04-29 04:52:59 +02:00
|
|
|
FillRect(backBuffer, star_rect, getRGB(0x22, 0x22, 0x22));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-29 04:52:59 +02:00
|
|
|
FillRect(backBuffer, star_rect, getRGB(0x55, 0x55, 0x55));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
//Static, unscrolling section of the tower
|
|
|
|
for (int j = 0; j < 30; j++)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 40; i++)
|
|
|
|
{
|
|
|
|
drawtile3(i * 8, j * 8, map.tower.backat(i, j, 200), 15);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
//Static, unscrolling section of the tower
|
|
|
|
for (int j = 0; j < 30; j++)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 40; i++)
|
|
|
|
{
|
|
|
|
drawtile3(i * 8, j * 8, map.tower.backat(i, j, 200), 10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
//Static, unscrolling section of the tower
|
|
|
|
for (int j = 0; j < 30; j++)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 40; i++)
|
|
|
|
{
|
|
|
|
drawtile3(i * 8, j * 8, map.tower.backat(i, j, 600), 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(backBuffer);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-29 04:28:16 +02:00
|
|
|
void Graphics::updatebackground(int t)
|
|
|
|
{
|
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
//Starfield
|
2020-07-03 11:31:13 +02:00
|
|
|
for (int i = 0; i < numstars; i++)
|
2020-04-29 04:28:16 +02:00
|
|
|
{
|
|
|
|
stars[i].w = 2;
|
|
|
|
stars[i].h = 2;
|
Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).
Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)
We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 20:13:12 +02:00
|
|
|
stars[i].x -= starsspeed[i];
|
2020-04-29 04:28:16 +02:00
|
|
|
if (stars[i].x < -10)
|
|
|
|
{
|
|
|
|
stars[i].x += 340;
|
|
|
|
stars[i].y = int(fRandom() * 240);
|
|
|
|
stars[i].w = 2;
|
|
|
|
starsspeed[i] = 4+int(fRandom()*4);
|
|
|
|
}
|
|
|
|
}
|
2020-04-29 04:33:33 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
//Lab
|
2020-04-29 04:47:37 +02:00
|
|
|
if (rcol == 6)
|
|
|
|
{
|
|
|
|
//crazy caze
|
|
|
|
spcoldel--;
|
|
|
|
if (spcoldel <= 0)
|
|
|
|
{
|
|
|
|
spcoldel = 15;
|
|
|
|
spcol++;
|
|
|
|
if (spcol >= 12) spcol = 0;
|
|
|
|
}
|
|
|
|
}
|
2020-07-03 11:31:13 +02:00
|
|
|
for (int i = 0; i < numbackboxes; i++)
|
2020-04-29 04:33:33 +02:00
|
|
|
{
|
|
|
|
backboxes[i].x += backboxvx[i];
|
|
|
|
backboxes[i].y += backboxvy[i];
|
|
|
|
if (backboxes[i].x < -40)
|
|
|
|
{
|
|
|
|
backboxes[i].x = 320;
|
|
|
|
backboxes[i].y = fRandom() * 240;
|
|
|
|
}
|
|
|
|
if (backboxes[i].x > 320)
|
|
|
|
{
|
|
|
|
backboxes[i].x = -32;
|
|
|
|
backboxes[i].y = fRandom() * 240;
|
|
|
|
}
|
|
|
|
if (backboxes[i].y < -40)
|
|
|
|
{
|
|
|
|
backboxes[i].y = 240;
|
|
|
|
backboxes[i].x = fRandom() * 320;
|
|
|
|
}
|
|
|
|
if (backboxes[i].y > 260)
|
|
|
|
{
|
|
|
|
backboxes[i].y = -32;
|
|
|
|
backboxes[i].x = fRandom() * 320;
|
|
|
|
}
|
|
|
|
}
|
2020-04-29 04:50:03 +02:00
|
|
|
break;
|
2020-04-29 19:37:56 +02:00
|
|
|
case 3: //Warp zone (horizontal)
|
2020-05-02 22:11:36 +02:00
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
const int temp = 680 + (rcol * 3);
|
2020-04-29 19:37:56 +02:00
|
|
|
backoffset+=3;
|
|
|
|
if (backoffset >= 16) backoffset -= 16;
|
|
|
|
|
|
|
|
if (backgrounddrawn)
|
|
|
|
{
|
2020-11-03 01:54:17 +01:00
|
|
|
ScrollSurface(warpbuffer, -3, 0 );
|
2020-04-29 19:37:56 +02:00
|
|
|
for (int j = 0; j < 15; j++)
|
|
|
|
{
|
2020-05-02 22:11:36 +02:00
|
|
|
for (int i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
drawtowertile(317 - backoffset + (i * 16), (j * 16), temp+40); //20*16 = 320
|
|
|
|
drawtowertile(317 - backoffset + (i * 16) + 8, (j * 16), temp + 41);
|
|
|
|
drawtowertile(317 - backoffset + (i * 16), (j * 16) + 8, temp + 80);
|
|
|
|
drawtowertile(317 - backoffset + (i * 16) + 8, (j * 16) + 8, temp + 81);
|
|
|
|
}
|
2020-04-29 19:37:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//draw the whole thing for the first time!
|
|
|
|
backoffset = 0;
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(warpbuffer);
|
2020-04-29 19:37:56 +02:00
|
|
|
for (int j = 0; j < 15; j++)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 21; i++)
|
|
|
|
{
|
|
|
|
drawtowertile((i * 16) - backoffset - 3, (j * 16), temp+40);
|
|
|
|
drawtowertile((i * 16) - backoffset + 8 - 3, (j * 16), temp + 41);
|
|
|
|
drawtowertile((i * 16) - backoffset - 3, (j * 16) + 8, temp + 80);
|
|
|
|
drawtowertile((i * 16) - backoffset + 8 - 3, (j * 16) + 8, temp + 81);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
backgrounddrawn = true;
|
|
|
|
}
|
|
|
|
break;
|
2020-05-02 22:11:36 +02:00
|
|
|
}
|
2020-04-29 20:06:03 +02:00
|
|
|
case 4: //Warp zone (vertical)
|
2020-05-02 22:11:36 +02:00
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
const int temp = 760 + (rcol * 3);
|
2020-04-29 20:06:03 +02:00
|
|
|
backoffset+=3;
|
|
|
|
if (backoffset >= 16) backoffset -= 16;
|
|
|
|
|
|
|
|
if (backgrounddrawn)
|
|
|
|
{
|
2020-11-03 01:54:17 +01:00
|
|
|
ScrollSurface(warpbuffer,0,-3);
|
2020-05-02 22:11:36 +02:00
|
|
|
for (int j = 0; j < 2; j++)
|
2020-04-29 20:06:03 +02:00
|
|
|
{
|
2020-05-02 22:11:36 +02:00
|
|
|
for (int i = 0; i < 21; i++)
|
|
|
|
{
|
|
|
|
drawtowertile((i * 16), 237 - backoffset + (j * 16), temp + 40); //14*17=240 - 3
|
|
|
|
drawtowertile((i * 16) + 8, 237 - backoffset + (j * 16), temp + 41);
|
|
|
|
drawtowertile((i * 16), 237 - backoffset + (j * 16) + 8, temp + 80);
|
|
|
|
drawtowertile((i * 16) + 8, 237 - backoffset + (j * 16) + 8, temp + 81);
|
|
|
|
}
|
2020-04-29 20:06:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//draw the whole thing for the first time!
|
|
|
|
backoffset = 0;
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(warpbuffer);
|
2020-05-02 22:11:36 +02:00
|
|
|
for (int j = 0; j < 16; j++)
|
2020-04-29 20:06:03 +02:00
|
|
|
{
|
|
|
|
for (int i = 0; i < 21; i++)
|
|
|
|
{
|
|
|
|
drawtowertile((i * 16), (j * 16)- backoffset - 3, temp+40);
|
|
|
|
drawtowertile((i * 16)+ 8, (j * 16)- backoffset - 3, temp + 41);
|
|
|
|
drawtowertile((i * 16), (j * 16)- backoffset + 8 - 3, temp + 80);
|
|
|
|
drawtowertile((i * 16)+ 8, (j * 16)- backoffset + 8 - 3, temp + 81);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
backgrounddrawn = true;
|
|
|
|
}
|
|
|
|
break;
|
2020-05-02 22:11:36 +02:00
|
|
|
}
|
2020-04-30 00:37:39 +02:00
|
|
|
case 5:
|
|
|
|
//Warp zone, central
|
|
|
|
|
|
|
|
backoffset += 1;
|
|
|
|
if (backoffset >= 16)
|
|
|
|
{
|
|
|
|
backoffset -= 16;
|
|
|
|
warpskip = (warpskip + 1) % 2;
|
|
|
|
}
|
|
|
|
break;
|
2020-04-29 04:50:03 +02:00
|
|
|
case 6:
|
|
|
|
//Final Starfield
|
2020-07-03 11:31:13 +02:00
|
|
|
for (int i = 0; i < numstars; i++)
|
2020-04-29 04:50:03 +02:00
|
|
|
{
|
|
|
|
stars[i].w = 2;
|
|
|
|
stars[i].h = 2;
|
|
|
|
stars[i].y -= starsspeed[i];
|
|
|
|
if (stars[i].y < -10)
|
|
|
|
{
|
|
|
|
stars[i].y += 260;
|
|
|
|
stars[i].x = fRandom() * 320;
|
|
|
|
starsspeed[i] = 5+(fRandom()*5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2020-04-29 04:28:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::drawmap(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (!foregrounddrawn)
|
|
|
|
{
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(foregroundBuffer);
|
2020-01-01 21:29:24 +01:00
|
|
|
if(map.tileset==0)
|
|
|
|
{
|
2020-06-14 20:21:32 +02:00
|
|
|
for (int j = 0; j < 30; j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < 40; i++)
|
|
|
|
{
|
2021-09-25 01:37:27 +02:00
|
|
|
const int tile = map.contents[TILE_IDX(i, j)];
|
|
|
|
if(tile>0) drawforetile(i * 8, j * 8, tile);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (map.tileset == 1)
|
|
|
|
{
|
Add and draw one more row to all rooms with roomnames
Since translucent roomname backgrounds were introduced in
TerryCavanagh/VVVVVV#122, it exposes one glaring flaw with the game that
until now has been kept hidden: in rooms with room names, the game
cheapens out with the tile data and doesn't have a 30th row, because the
room name would hide the missing row. As a result, rooms with room names
have 29 rows instead of 30 to fill up the entire screen. And it looks
really weird when there's nothing but empty space behind the translucent
room name background.
To remedy this, I added one row to each room with a room name in the level.
First, I had to filter out all the rooms with no room names. However, that's
actually all contained in Otherlevel.cpp, the Overworld, which contains 221
rooms (8 of which are the Secret Lab, 6 more of which are the Ship, so 207 are
the actual Overworld, right? Wrong, 2 of those Overworld no-roomname rooms are
in the Lab, so there are actually 205 Overworld rooms). The remaining level
data files all contain rooms with room names.
But the process wasn't that easy. I noticed a while ago that each room
contains 29 `tmap.push_back()`s, one for each row of the room, and each row is
simply a string containing the 40 tiles for that row, concatenated with
commas.
However, I decided to actually check my intuition by doing a grep on each
level file and counting the number of results, for example `grep 'push_back'
Labclass.cpp | wc -l`. Whatever number comes out should be divisible by 29.
That particular grep on Labclass.cpp returns 1306, which divided by 29 is 45
with a remainder of 1.
So what does that mean? Does that mean there's 45 rooms each, and 1 leftover
row? Well, not exactly. The extra row comes from the fact that Outer Space has
30 rows instead of 29. Outer Space is the room that comes up when the game
finds a room is non-existent, which shouldn't happen with a properly-working
game, except in Outside Dimension VVVVVV. In fact, each level file has their
own Outer Space, and every single Outer Space also has 30 rooms. So really,
this means there are 44 rooms in the Lab and one Outer Space room. (Well, in
reality, there are 46 rooms in the Lab, because 2 of them use the Outside
tileset but have no room names, so they're stored in Otherlevel.cpp instead.)
We find the same result for the Warp Zone. `grep 'push_back' WarpClass.cpp |
wc -l` returns 697, which is 24 remainder 1, meaning 23 rooms of 29 rows and 1
room of 30 rows, which corresponds with 23 rooms in the Warp Zone and one
Outer Space room.
However, Outside Dimension VVVVVV + Tower Hallways and Space Station 1 and 2
are both odd curiosities. Finalclass.cpp contains Outside Dimension VVVVVV,
(which is Intermission 1 and 2 and the Final Level), but also the Tower
Hallway rooms, i.e. the auxiliary Tower rooms that are not a part of the main
tower. Spacestation2.cpp contains both Space Station 1 and 2, so don't be
deceived by the name.
`grep 'push_back' Finalclass.cpp | wc -l` returns 1597, which is actually 55
remainder 2. So... are there two rooms with 30 rows? Yes, in fact, The
Gravitron and Outer Space both contain 30 rows. So there are actually 55 rooms
stored in Finalclass.cpp (not including the minitowers Panic Room and The
Final Challenge), 54 rooms of actual level data and one Outer Space room, and
breaking down the 54 rooms even further, 51 of them are actually in Outside
Dimension VVVVVV and 3 of them are Tower Hallways. Of the 51 Outside Dimension
VVVVVV rooms, 14 of those are Intermission 1, 4 of them are Intermission 2,
and the rest of the 33 rooms are the Final Level (again, not including the
minitowers).
`grep 'push_back' Spacestation2.cpp | wc -l` returns 2148, which is 74
remainder 2. Are there two rooms with 30 rows again? No; one of those counted
2148 rows is a false-positive, because there's an if-else in Prize for the
Reckless that replaces the row with spikes with a row without spikes if you
are in a time trial or in No Death Mode. So there's 73 rooms in Space Station
1 and 2, and one Outer Space room.
With all this in mind, I decided to duplicate the current last row of each
room, the 29th row, to add a 30th row. However, I wasn't going to do this
automatically! But neither was I going to write some kludge-y code to parse
each nightmare of a level file and duplicate the rows that way.
Enter: Vim macros! (Er, well, actually, I use Neovim.) I first did
`/push_back`, so that pressing `n` would keep going to the next `push_back` in
the file. Then I went to the 29th row of the first room in the file, did a
`Yp`, and then started my macro with `qq`. The macro went like this: `30nYp`,
which is simply going to the 29th row of the next room over and duplicating
it. And that's all there was to it. However, I had to make sure that (1) my
cursor was before the `push_back` on the line of the 29th row of the room, and
(2) that I didn't skip rooms, both of which were problems I encountered when
pressing Ctrl+Z a given invocation of the macro (the Ctrl+Z is just a
metaphor, you actually undo by typing `u` in Vim). And also I had to make sure
to be careful around the extra lines of `push_back`s in Prize for the Reckless
and The Gravitron, and make sure I didn't run past the end of the file and
loop back around. Thankfully, all Outer Space rooms are at the end of each
file.
But first, I had to increase the number of rows drawn in Graphics.cpp by 1 in
order to compensate for this, and do the same when reading the tile data in
Map.cpp. I had to change fillcontent(), drawmap(), drawfinalmap(),
drawtowermap(), and drawtowermap_nobackground(). Funnily enough, the tower
functions already used 30 rows, but I guess it's an off-by-one due to the
camera scrolling, so they now draw 31 rows each.
Then, I went in-game to make sure that the row behind each room name looked
fine. I checked EVERY single room with a room name. I turned on invincibility
mode and added a temporary line to hardreset() that always turned on
game.nocutscenes for a smoother playtesting experience. And to make sure that
rooms which have entirely empty bottom rows actually still have 30 rows,
instead of having 29 and the game assuming that the 30th row was empty
(because that sounds like it could lead to Undefined Behavior), I added this
temporary debugging line to the start of mapclass::fillcontent():
printf("(%i,%i) has %i rows\n", game.roomx, game.roomy, (int) tmap.size());
Everywhere I checked - and I made sure to check all rooms - every room had 30
rows and not 29 rows.
Unfortunately, some rooms simply couldn't be left alone with their 29th row
duplicated and had to be manually edited. This was because the 29th row would
contain some edge tiles because the player would be able to walk somewhere on
the 28th, 27th, and 26th rows, and if you duplicated said edge tiles behind
the room name, it would look bad.
Here's a list of rooms whose 30th rows I had to manually edit:
- Comms Relay
- The Yes Men
- Stop and Reflect
- They Call Him Flipper
- Double-slit Experiment
- Square Root
- Brought to you by the letter G
- The Bernoulli Principle
- Purest Unobtainium
- I Smell Ozone
- Conveying a New Idea
- Upstream Downstream
- Give Me A V
- $eeing Dollar $ign$
- Doing Things The Hard Way
- Very Good
- Must I Do Everything For You?
- Now Stay Close To Me...
- ...But Not Too Close
- ...Not as I Do
- Do Try To Keep Up
- Whee Sports
- As you like it
This is actually a strange case where it looked bad because of the 29th
row, instead of the 30th row, and I had to change the 29th row instead of
the 30th row to fix it.
- Maze With No Entrance
- Ascending and Descending
- Mind The Gap
Same strange case as "As you like it" (it's the 29th row I had to change
that was the problem, not the 30th).
- 1950 Silverstone Grand V
- The Villi People
I found that Panic Room and The Final Challenge also looked strange behind the
roomname background, but I can't do much about either because towers' tile
data wrap around at the top and bottom, and if I added another row to either
it would be visible above the room name.
I've considered updating the development editors with these new level tiles,
but I decided against it as the development editors are already pretty
outdated anyway.
2020-02-03 22:24:30 +01:00
|
|
|
for (int jt = 0; jt < 30; jt++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
for (int it = 0; it < 40; it++)
|
|
|
|
{
|
2021-09-25 01:37:27 +02:00
|
|
|
const int tile = map.contents[TILE_IDX(it, jt)];
|
|
|
|
if(tile>0) drawforetile2(it * 8, jt * 8, tile);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (map.tileset == 2)
|
|
|
|
{
|
2020-06-14 20:21:32 +02:00
|
|
|
for (int j = 0; j < 30; j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < 40; i++)
|
|
|
|
{
|
2021-09-25 01:37:27 +02:00
|
|
|
const int tile = map.contents[TILE_IDX(i, j)];
|
|
|
|
if(tile>0) drawforetile3(i * 8, j * 8, tile,map.rcol);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foregrounddrawn = true;
|
|
|
|
}
|
Ax OverlaySurfaceKeyed(), set proper foregroundBuffer blend mode
So, earlier in the development of 2.0, Simon Roth (I presume)
encountered a problem: Oh no, all my backgrounds aren't appearing! And
this is because my foregroundBuffer, which contains all the drawn tiles,
is drawing complete black over it!
So he had a solution that seems ingenius, but is actually really really
hacky and super 100% NOT the proper solution. Just, take the
foregroundBuffer, iterate over each pixel, and DON'T draw any pixel
that's 0xDEADBEEF. 0xDEADBEEF is a special signal meaning "don't draw
this pixel". It is called a 'key'.
Unfortunately, this causes a bug where translucent pixels on tiles
(pixels between 0% and 100% opacity) didn't get drawn correctly. They
would be drawn against this weird blue color.
Now, in #103, I came across this weird constant and decided "hey, this
looks awfully like that weird blue color I came across, maybe if I set
it to 0x00000000, i.e. complete and transparent black, the issue will be
fixed". And it DID appear to be fixed. However, I didn't look too
closely, nor did I test it that much, and all that ended up doing was
drawing the pixels against black, which more subtly disguised the
problem with translucent pixels.
So, after some investigation, I noticed that BlitSurfaceColoured() was
drawing translucent pixels just fine. And I thought at the time that
there was something wrong with BlitSurfaceStandard(), or something.
Further along later I realized that all drawn tiles were passing through
this weird OverlaySurfaceKeyed() function. And removing it in favor of a
straight SDL_BlitSurface() produced the bug I mentioned above: Oh no,
all the backgrounds don't show up, because my foregroundBuffer is
drawing pure black over them!
Well... just... set the proper blend mode for foregroundBuffer. It
should be SDL_BLENDMODE_BLEND instead of SDL_BLENDMODE_NONE.
Then you don't have to worry about your transparency at all. If you did
it right, you won't have to resort this hacky color-keying business.
*sigh*
2020-08-04 09:24:04 +02:00
|
|
|
SDL_BlitSurface(foregroundBuffer, NULL, backBuffer, NULL);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::drawfinalmap(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-02 22:05:48 +02:00
|
|
|
if (!foregrounddrawn) {
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(foregroundBuffer);
|
2020-04-02 22:05:48 +02:00
|
|
|
if(map.tileset==0){
|
Add and draw one more row to all rooms with roomnames
Since translucent roomname backgrounds were introduced in
TerryCavanagh/VVVVVV#122, it exposes one glaring flaw with the game that
until now has been kept hidden: in rooms with room names, the game
cheapens out with the tile data and doesn't have a 30th row, because the
room name would hide the missing row. As a result, rooms with room names
have 29 rows instead of 30 to fill up the entire screen. And it looks
really weird when there's nothing but empty space behind the translucent
room name background.
To remedy this, I added one row to each room with a room name in the level.
First, I had to filter out all the rooms with no room names. However, that's
actually all contained in Otherlevel.cpp, the Overworld, which contains 221
rooms (8 of which are the Secret Lab, 6 more of which are the Ship, so 207 are
the actual Overworld, right? Wrong, 2 of those Overworld no-roomname rooms are
in the Lab, so there are actually 205 Overworld rooms). The remaining level
data files all contain rooms with room names.
But the process wasn't that easy. I noticed a while ago that each room
contains 29 `tmap.push_back()`s, one for each row of the room, and each row is
simply a string containing the 40 tiles for that row, concatenated with
commas.
However, I decided to actually check my intuition by doing a grep on each
level file and counting the number of results, for example `grep 'push_back'
Labclass.cpp | wc -l`. Whatever number comes out should be divisible by 29.
That particular grep on Labclass.cpp returns 1306, which divided by 29 is 45
with a remainder of 1.
So what does that mean? Does that mean there's 45 rooms each, and 1 leftover
row? Well, not exactly. The extra row comes from the fact that Outer Space has
30 rows instead of 29. Outer Space is the room that comes up when the game
finds a room is non-existent, which shouldn't happen with a properly-working
game, except in Outside Dimension VVVVVV. In fact, each level file has their
own Outer Space, and every single Outer Space also has 30 rooms. So really,
this means there are 44 rooms in the Lab and one Outer Space room. (Well, in
reality, there are 46 rooms in the Lab, because 2 of them use the Outside
tileset but have no room names, so they're stored in Otherlevel.cpp instead.)
We find the same result for the Warp Zone. `grep 'push_back' WarpClass.cpp |
wc -l` returns 697, which is 24 remainder 1, meaning 23 rooms of 29 rows and 1
room of 30 rows, which corresponds with 23 rooms in the Warp Zone and one
Outer Space room.
However, Outside Dimension VVVVVV + Tower Hallways and Space Station 1 and 2
are both odd curiosities. Finalclass.cpp contains Outside Dimension VVVVVV,
(which is Intermission 1 and 2 and the Final Level), but also the Tower
Hallway rooms, i.e. the auxiliary Tower rooms that are not a part of the main
tower. Spacestation2.cpp contains both Space Station 1 and 2, so don't be
deceived by the name.
`grep 'push_back' Finalclass.cpp | wc -l` returns 1597, which is actually 55
remainder 2. So... are there two rooms with 30 rows? Yes, in fact, The
Gravitron and Outer Space both contain 30 rows. So there are actually 55 rooms
stored in Finalclass.cpp (not including the minitowers Panic Room and The
Final Challenge), 54 rooms of actual level data and one Outer Space room, and
breaking down the 54 rooms even further, 51 of them are actually in Outside
Dimension VVVVVV and 3 of them are Tower Hallways. Of the 51 Outside Dimension
VVVVVV rooms, 14 of those are Intermission 1, 4 of them are Intermission 2,
and the rest of the 33 rooms are the Final Level (again, not including the
minitowers).
`grep 'push_back' Spacestation2.cpp | wc -l` returns 2148, which is 74
remainder 2. Are there two rooms with 30 rows again? No; one of those counted
2148 rows is a false-positive, because there's an if-else in Prize for the
Reckless that replaces the row with spikes with a row without spikes if you
are in a time trial or in No Death Mode. So there's 73 rooms in Space Station
1 and 2, and one Outer Space room.
With all this in mind, I decided to duplicate the current last row of each
room, the 29th row, to add a 30th row. However, I wasn't going to do this
automatically! But neither was I going to write some kludge-y code to parse
each nightmare of a level file and duplicate the rows that way.
Enter: Vim macros! (Er, well, actually, I use Neovim.) I first did
`/push_back`, so that pressing `n` would keep going to the next `push_back` in
the file. Then I went to the 29th row of the first room in the file, did a
`Yp`, and then started my macro with `qq`. The macro went like this: `30nYp`,
which is simply going to the 29th row of the next room over and duplicating
it. And that's all there was to it. However, I had to make sure that (1) my
cursor was before the `push_back` on the line of the 29th row of the room, and
(2) that I didn't skip rooms, both of which were problems I encountered when
pressing Ctrl+Z a given invocation of the macro (the Ctrl+Z is just a
metaphor, you actually undo by typing `u` in Vim). And also I had to make sure
to be careful around the extra lines of `push_back`s in Prize for the Reckless
and The Gravitron, and make sure I didn't run past the end of the file and
loop back around. Thankfully, all Outer Space rooms are at the end of each
file.
But first, I had to increase the number of rows drawn in Graphics.cpp by 1 in
order to compensate for this, and do the same when reading the tile data in
Map.cpp. I had to change fillcontent(), drawmap(), drawfinalmap(),
drawtowermap(), and drawtowermap_nobackground(). Funnily enough, the tower
functions already used 30 rows, but I guess it's an off-by-one due to the
camera scrolling, so they now draw 31 rows each.
Then, I went in-game to make sure that the row behind each room name looked
fine. I checked EVERY single room with a room name. I turned on invincibility
mode and added a temporary line to hardreset() that always turned on
game.nocutscenes for a smoother playtesting experience. And to make sure that
rooms which have entirely empty bottom rows actually still have 30 rows,
instead of having 29 and the game assuming that the 30th row was empty
(because that sounds like it could lead to Undefined Behavior), I added this
temporary debugging line to the start of mapclass::fillcontent():
printf("(%i,%i) has %i rows\n", game.roomx, game.roomy, (int) tmap.size());
Everywhere I checked - and I made sure to check all rooms - every room had 30
rows and not 29 rows.
Unfortunately, some rooms simply couldn't be left alone with their 29th row
duplicated and had to be manually edited. This was because the 29th row would
contain some edge tiles because the player would be able to walk somewhere on
the 28th, 27th, and 26th rows, and if you duplicated said edge tiles behind
the room name, it would look bad.
Here's a list of rooms whose 30th rows I had to manually edit:
- Comms Relay
- The Yes Men
- Stop and Reflect
- They Call Him Flipper
- Double-slit Experiment
- Square Root
- Brought to you by the letter G
- The Bernoulli Principle
- Purest Unobtainium
- I Smell Ozone
- Conveying a New Idea
- Upstream Downstream
- Give Me A V
- $eeing Dollar $ign$
- Doing Things The Hard Way
- Very Good
- Must I Do Everything For You?
- Now Stay Close To Me...
- ...But Not Too Close
- ...Not as I Do
- Do Try To Keep Up
- Whee Sports
- As you like it
This is actually a strange case where it looked bad because of the 29th
row, instead of the 30th row, and I had to change the 29th row instead of
the 30th row to fix it.
- Maze With No Entrance
- Ascending and Descending
- Mind The Gap
Same strange case as "As you like it" (it's the 29th row I had to change
that was the problem, not the 30th).
- 1950 Silverstone Grand V
- The Villi People
I found that Panic Room and The Final Challenge also looked strange behind the
roomname background, but I can't do much about either because towers' tile
data wrap around at the top and bottom, and if I added another row to either
it would be visible above the room name.
I've considered updating the development editors with these new level tiles,
but I decided against it as the development editors are already pretty
outdated anyway.
2020-02-03 22:24:30 +01:00
|
|
|
for (int j = 0; j < 30; j++) {
|
2020-04-02 22:05:48 +02:00
|
|
|
for (int i = 0; i < 40; i++) {
|
2021-09-25 01:37:27 +02:00
|
|
|
if((map.contents[TILE_IDX(i, j)])>0)
|
2020-04-02 22:05:48 +02:00
|
|
|
drawforetile(i * 8, j * 8, map.finalat(i,j));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}else if (map.tileset == 1) {
|
Add and draw one more row to all rooms with roomnames
Since translucent roomname backgrounds were introduced in
TerryCavanagh/VVVVVV#122, it exposes one glaring flaw with the game that
until now has been kept hidden: in rooms with room names, the game
cheapens out with the tile data and doesn't have a 30th row, because the
room name would hide the missing row. As a result, rooms with room names
have 29 rows instead of 30 to fill up the entire screen. And it looks
really weird when there's nothing but empty space behind the translucent
room name background.
To remedy this, I added one row to each room with a room name in the level.
First, I had to filter out all the rooms with no room names. However, that's
actually all contained in Otherlevel.cpp, the Overworld, which contains 221
rooms (8 of which are the Secret Lab, 6 more of which are the Ship, so 207 are
the actual Overworld, right? Wrong, 2 of those Overworld no-roomname rooms are
in the Lab, so there are actually 205 Overworld rooms). The remaining level
data files all contain rooms with room names.
But the process wasn't that easy. I noticed a while ago that each room
contains 29 `tmap.push_back()`s, one for each row of the room, and each row is
simply a string containing the 40 tiles for that row, concatenated with
commas.
However, I decided to actually check my intuition by doing a grep on each
level file and counting the number of results, for example `grep 'push_back'
Labclass.cpp | wc -l`. Whatever number comes out should be divisible by 29.
That particular grep on Labclass.cpp returns 1306, which divided by 29 is 45
with a remainder of 1.
So what does that mean? Does that mean there's 45 rooms each, and 1 leftover
row? Well, not exactly. The extra row comes from the fact that Outer Space has
30 rows instead of 29. Outer Space is the room that comes up when the game
finds a room is non-existent, which shouldn't happen with a properly-working
game, except in Outside Dimension VVVVVV. In fact, each level file has their
own Outer Space, and every single Outer Space also has 30 rooms. So really,
this means there are 44 rooms in the Lab and one Outer Space room. (Well, in
reality, there are 46 rooms in the Lab, because 2 of them use the Outside
tileset but have no room names, so they're stored in Otherlevel.cpp instead.)
We find the same result for the Warp Zone. `grep 'push_back' WarpClass.cpp |
wc -l` returns 697, which is 24 remainder 1, meaning 23 rooms of 29 rows and 1
room of 30 rows, which corresponds with 23 rooms in the Warp Zone and one
Outer Space room.
However, Outside Dimension VVVVVV + Tower Hallways and Space Station 1 and 2
are both odd curiosities. Finalclass.cpp contains Outside Dimension VVVVVV,
(which is Intermission 1 and 2 and the Final Level), but also the Tower
Hallway rooms, i.e. the auxiliary Tower rooms that are not a part of the main
tower. Spacestation2.cpp contains both Space Station 1 and 2, so don't be
deceived by the name.
`grep 'push_back' Finalclass.cpp | wc -l` returns 1597, which is actually 55
remainder 2. So... are there two rooms with 30 rows? Yes, in fact, The
Gravitron and Outer Space both contain 30 rows. So there are actually 55 rooms
stored in Finalclass.cpp (not including the minitowers Panic Room and The
Final Challenge), 54 rooms of actual level data and one Outer Space room, and
breaking down the 54 rooms even further, 51 of them are actually in Outside
Dimension VVVVVV and 3 of them are Tower Hallways. Of the 51 Outside Dimension
VVVVVV rooms, 14 of those are Intermission 1, 4 of them are Intermission 2,
and the rest of the 33 rooms are the Final Level (again, not including the
minitowers).
`grep 'push_back' Spacestation2.cpp | wc -l` returns 2148, which is 74
remainder 2. Are there two rooms with 30 rows again? No; one of those counted
2148 rows is a false-positive, because there's an if-else in Prize for the
Reckless that replaces the row with spikes with a row without spikes if you
are in a time trial or in No Death Mode. So there's 73 rooms in Space Station
1 and 2, and one Outer Space room.
With all this in mind, I decided to duplicate the current last row of each
room, the 29th row, to add a 30th row. However, I wasn't going to do this
automatically! But neither was I going to write some kludge-y code to parse
each nightmare of a level file and duplicate the rows that way.
Enter: Vim macros! (Er, well, actually, I use Neovim.) I first did
`/push_back`, so that pressing `n` would keep going to the next `push_back` in
the file. Then I went to the 29th row of the first room in the file, did a
`Yp`, and then started my macro with `qq`. The macro went like this: `30nYp`,
which is simply going to the 29th row of the next room over and duplicating
it. And that's all there was to it. However, I had to make sure that (1) my
cursor was before the `push_back` on the line of the 29th row of the room, and
(2) that I didn't skip rooms, both of which were problems I encountered when
pressing Ctrl+Z a given invocation of the macro (the Ctrl+Z is just a
metaphor, you actually undo by typing `u` in Vim). And also I had to make sure
to be careful around the extra lines of `push_back`s in Prize for the Reckless
and The Gravitron, and make sure I didn't run past the end of the file and
loop back around. Thankfully, all Outer Space rooms are at the end of each
file.
But first, I had to increase the number of rows drawn in Graphics.cpp by 1 in
order to compensate for this, and do the same when reading the tile data in
Map.cpp. I had to change fillcontent(), drawmap(), drawfinalmap(),
drawtowermap(), and drawtowermap_nobackground(). Funnily enough, the tower
functions already used 30 rows, but I guess it's an off-by-one due to the
camera scrolling, so they now draw 31 rows each.
Then, I went in-game to make sure that the row behind each room name looked
fine. I checked EVERY single room with a room name. I turned on invincibility
mode and added a temporary line to hardreset() that always turned on
game.nocutscenes for a smoother playtesting experience. And to make sure that
rooms which have entirely empty bottom rows actually still have 30 rows,
instead of having 29 and the game assuming that the 30th row was empty
(because that sounds like it could lead to Undefined Behavior), I added this
temporary debugging line to the start of mapclass::fillcontent():
printf("(%i,%i) has %i rows\n", game.roomx, game.roomy, (int) tmap.size());
Everywhere I checked - and I made sure to check all rooms - every room had 30
rows and not 29 rows.
Unfortunately, some rooms simply couldn't be left alone with their 29th row
duplicated and had to be manually edited. This was because the 29th row would
contain some edge tiles because the player would be able to walk somewhere on
the 28th, 27th, and 26th rows, and if you duplicated said edge tiles behind
the room name, it would look bad.
Here's a list of rooms whose 30th rows I had to manually edit:
- Comms Relay
- The Yes Men
- Stop and Reflect
- They Call Him Flipper
- Double-slit Experiment
- Square Root
- Brought to you by the letter G
- The Bernoulli Principle
- Purest Unobtainium
- I Smell Ozone
- Conveying a New Idea
- Upstream Downstream
- Give Me A V
- $eeing Dollar $ign$
- Doing Things The Hard Way
- Very Good
- Must I Do Everything For You?
- Now Stay Close To Me...
- ...But Not Too Close
- ...Not as I Do
- Do Try To Keep Up
- Whee Sports
- As you like it
This is actually a strange case where it looked bad because of the 29th
row, instead of the 30th row, and I had to change the 29th row instead of
the 30th row to fix it.
- Maze With No Entrance
- Ascending and Descending
- Mind The Gap
Same strange case as "As you like it" (it's the 29th row I had to change
that was the problem, not the 30th).
- 1950 Silverstone Grand V
- The Villi People
I found that Panic Room and The Final Challenge also looked strange behind the
roomname background, but I can't do much about either because towers' tile
data wrap around at the top and bottom, and if I added another row to either
it would be visible above the room name.
I've considered updating the development editors with these new level tiles,
but I decided against it as the development editors are already pretty
outdated anyway.
2020-02-03 22:24:30 +01:00
|
|
|
for (int j = 0; j < 30; j++) {
|
2020-04-02 22:05:48 +02:00
|
|
|
for (int i = 0; i < 40; i++) {
|
2021-09-25 01:37:27 +02:00
|
|
|
if((map.contents[TILE_IDX(i, j)])>0)
|
2020-04-02 22:05:48 +02:00
|
|
|
drawforetile2(i * 8, j * 8, map.finalat(i,j));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foregrounddrawn=true;
|
|
|
|
}
|
|
|
|
|
Ax OverlaySurfaceKeyed(), set proper foregroundBuffer blend mode
So, earlier in the development of 2.0, Simon Roth (I presume)
encountered a problem: Oh no, all my backgrounds aren't appearing! And
this is because my foregroundBuffer, which contains all the drawn tiles,
is drawing complete black over it!
So he had a solution that seems ingenius, but is actually really really
hacky and super 100% NOT the proper solution. Just, take the
foregroundBuffer, iterate over each pixel, and DON'T draw any pixel
that's 0xDEADBEEF. 0xDEADBEEF is a special signal meaning "don't draw
this pixel". It is called a 'key'.
Unfortunately, this causes a bug where translucent pixels on tiles
(pixels between 0% and 100% opacity) didn't get drawn correctly. They
would be drawn against this weird blue color.
Now, in #103, I came across this weird constant and decided "hey, this
looks awfully like that weird blue color I came across, maybe if I set
it to 0x00000000, i.e. complete and transparent black, the issue will be
fixed". And it DID appear to be fixed. However, I didn't look too
closely, nor did I test it that much, and all that ended up doing was
drawing the pixels against black, which more subtly disguised the
problem with translucent pixels.
So, after some investigation, I noticed that BlitSurfaceColoured() was
drawing translucent pixels just fine. And I thought at the time that
there was something wrong with BlitSurfaceStandard(), or something.
Further along later I realized that all drawn tiles were passing through
this weird OverlaySurfaceKeyed() function. And removing it in favor of a
straight SDL_BlitSurface() produced the bug I mentioned above: Oh no,
all the backgrounds don't show up, because my foregroundBuffer is
drawing pure black over them!
Well... just... set the proper blend mode for foregroundBuffer. It
should be SDL_BLENDMODE_BLEND instead of SDL_BLENDMODE_NONE.
Then you don't have to worry about your transparency at all. If you did
it right, you won't have to resort this hacky color-keying business.
*sigh*
2020-08-04 09:24:04 +02:00
|
|
|
SDL_BlitSurface(foregroundBuffer, NULL, backBuffer, NULL);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::drawtowermap(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
const int yoff = lerp(map.oldypos, map.ypos);
|
Add and draw one more row to all rooms with roomnames
Since translucent roomname backgrounds were introduced in
TerryCavanagh/VVVVVV#122, it exposes one glaring flaw with the game that
until now has been kept hidden: in rooms with room names, the game
cheapens out with the tile data and doesn't have a 30th row, because the
room name would hide the missing row. As a result, rooms with room names
have 29 rows instead of 30 to fill up the entire screen. And it looks
really weird when there's nothing but empty space behind the translucent
room name background.
To remedy this, I added one row to each room with a room name in the level.
First, I had to filter out all the rooms with no room names. However, that's
actually all contained in Otherlevel.cpp, the Overworld, which contains 221
rooms (8 of which are the Secret Lab, 6 more of which are the Ship, so 207 are
the actual Overworld, right? Wrong, 2 of those Overworld no-roomname rooms are
in the Lab, so there are actually 205 Overworld rooms). The remaining level
data files all contain rooms with room names.
But the process wasn't that easy. I noticed a while ago that each room
contains 29 `tmap.push_back()`s, one for each row of the room, and each row is
simply a string containing the 40 tiles for that row, concatenated with
commas.
However, I decided to actually check my intuition by doing a grep on each
level file and counting the number of results, for example `grep 'push_back'
Labclass.cpp | wc -l`. Whatever number comes out should be divisible by 29.
That particular grep on Labclass.cpp returns 1306, which divided by 29 is 45
with a remainder of 1.
So what does that mean? Does that mean there's 45 rooms each, and 1 leftover
row? Well, not exactly. The extra row comes from the fact that Outer Space has
30 rows instead of 29. Outer Space is the room that comes up when the game
finds a room is non-existent, which shouldn't happen with a properly-working
game, except in Outside Dimension VVVVVV. In fact, each level file has their
own Outer Space, and every single Outer Space also has 30 rooms. So really,
this means there are 44 rooms in the Lab and one Outer Space room. (Well, in
reality, there are 46 rooms in the Lab, because 2 of them use the Outside
tileset but have no room names, so they're stored in Otherlevel.cpp instead.)
We find the same result for the Warp Zone. `grep 'push_back' WarpClass.cpp |
wc -l` returns 697, which is 24 remainder 1, meaning 23 rooms of 29 rows and 1
room of 30 rows, which corresponds with 23 rooms in the Warp Zone and one
Outer Space room.
However, Outside Dimension VVVVVV + Tower Hallways and Space Station 1 and 2
are both odd curiosities. Finalclass.cpp contains Outside Dimension VVVVVV,
(which is Intermission 1 and 2 and the Final Level), but also the Tower
Hallway rooms, i.e. the auxiliary Tower rooms that are not a part of the main
tower. Spacestation2.cpp contains both Space Station 1 and 2, so don't be
deceived by the name.
`grep 'push_back' Finalclass.cpp | wc -l` returns 1597, which is actually 55
remainder 2. So... are there two rooms with 30 rows? Yes, in fact, The
Gravitron and Outer Space both contain 30 rows. So there are actually 55 rooms
stored in Finalclass.cpp (not including the minitowers Panic Room and The
Final Challenge), 54 rooms of actual level data and one Outer Space room, and
breaking down the 54 rooms even further, 51 of them are actually in Outside
Dimension VVVVVV and 3 of them are Tower Hallways. Of the 51 Outside Dimension
VVVVVV rooms, 14 of those are Intermission 1, 4 of them are Intermission 2,
and the rest of the 33 rooms are the Final Level (again, not including the
minitowers).
`grep 'push_back' Spacestation2.cpp | wc -l` returns 2148, which is 74
remainder 2. Are there two rooms with 30 rows again? No; one of those counted
2148 rows is a false-positive, because there's an if-else in Prize for the
Reckless that replaces the row with spikes with a row without spikes if you
are in a time trial or in No Death Mode. So there's 73 rooms in Space Station
1 and 2, and one Outer Space room.
With all this in mind, I decided to duplicate the current last row of each
room, the 29th row, to add a 30th row. However, I wasn't going to do this
automatically! But neither was I going to write some kludge-y code to parse
each nightmare of a level file and duplicate the rows that way.
Enter: Vim macros! (Er, well, actually, I use Neovim.) I first did
`/push_back`, so that pressing `n` would keep going to the next `push_back` in
the file. Then I went to the 29th row of the first room in the file, did a
`Yp`, and then started my macro with `qq`. The macro went like this: `30nYp`,
which is simply going to the 29th row of the next room over and duplicating
it. And that's all there was to it. However, I had to make sure that (1) my
cursor was before the `push_back` on the line of the 29th row of the room, and
(2) that I didn't skip rooms, both of which were problems I encountered when
pressing Ctrl+Z a given invocation of the macro (the Ctrl+Z is just a
metaphor, you actually undo by typing `u` in Vim). And also I had to make sure
to be careful around the extra lines of `push_back`s in Prize for the Reckless
and The Gravitron, and make sure I didn't run past the end of the file and
loop back around. Thankfully, all Outer Space rooms are at the end of each
file.
But first, I had to increase the number of rows drawn in Graphics.cpp by 1 in
order to compensate for this, and do the same when reading the tile data in
Map.cpp. I had to change fillcontent(), drawmap(), drawfinalmap(),
drawtowermap(), and drawtowermap_nobackground(). Funnily enough, the tower
functions already used 30 rows, but I guess it's an off-by-one due to the
camera scrolling, so they now draw 31 rows each.
Then, I went in-game to make sure that the row behind each room name looked
fine. I checked EVERY single room with a room name. I turned on invincibility
mode and added a temporary line to hardreset() that always turned on
game.nocutscenes for a smoother playtesting experience. And to make sure that
rooms which have entirely empty bottom rows actually still have 30 rows,
instead of having 29 and the game assuming that the 30th row was empty
(because that sounds like it could lead to Undefined Behavior), I added this
temporary debugging line to the start of mapclass::fillcontent():
printf("(%i,%i) has %i rows\n", game.roomx, game.roomy, (int) tmap.size());
Everywhere I checked - and I made sure to check all rooms - every room had 30
rows and not 29 rows.
Unfortunately, some rooms simply couldn't be left alone with their 29th row
duplicated and had to be manually edited. This was because the 29th row would
contain some edge tiles because the player would be able to walk somewhere on
the 28th, 27th, and 26th rows, and if you duplicated said edge tiles behind
the room name, it would look bad.
Here's a list of rooms whose 30th rows I had to manually edit:
- Comms Relay
- The Yes Men
- Stop and Reflect
- They Call Him Flipper
- Double-slit Experiment
- Square Root
- Brought to you by the letter G
- The Bernoulli Principle
- Purest Unobtainium
- I Smell Ozone
- Conveying a New Idea
- Upstream Downstream
- Give Me A V
- $eeing Dollar $ign$
- Doing Things The Hard Way
- Very Good
- Must I Do Everything For You?
- Now Stay Close To Me...
- ...But Not Too Close
- ...Not as I Do
- Do Try To Keep Up
- Whee Sports
- As you like it
This is actually a strange case where it looked bad because of the 29th
row, instead of the 30th row, and I had to change the 29th row instead of
the 30th row to fix it.
- Maze With No Entrance
- Ascending and Descending
- Mind The Gap
Same strange case as "As you like it" (it's the 29th row I had to change
that was the problem, not the 30th).
- 1950 Silverstone Grand V
- The Villi People
I found that Panic Room and The Final Challenge also looked strange behind the
roomname background, but I can't do much about either because towers' tile
data wrap around at the top and bottom, and if I added another row to either
it would be visible above the room name.
I've considered updating the development editors with these new level tiles,
but I decided against it as the development editors are already pretty
outdated anyway.
2020-02-03 22:24:30 +01:00
|
|
|
for (int j = 0; j < 31; j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < 40; i++)
|
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
const int temp = map.tower.at(i, j, yoff);
|
|
|
|
if (temp > 0)
|
|
|
|
{
|
|
|
|
drawtile3(i * 8, (j * 8) - (yoff % 8), temp, towerbg.colstate);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::drawtowerspikes(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-30 21:58:08 +02:00
|
|
|
int spikeleveltop = lerp(map.oldspikeleveltop, map.spikeleveltop);
|
|
|
|
int spikelevelbottom = lerp(map.oldspikelevelbottom, map.spikelevelbottom);
|
2020-01-01 21:29:24 +01:00
|
|
|
for (int i = 0; i < 40; i++)
|
|
|
|
{
|
2020-11-03 00:05:24 +01:00
|
|
|
drawtile3(i * 8, -8+spikeleveltop, 9, towerbg.colstate);
|
|
|
|
drawtile3(i * 8, 230-spikelevelbottom, 8, towerbg.colstate, 8 - spikelevelbottom);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-03 00:05:24 +01:00
|
|
|
void Graphics::drawtowerbackground(const TowerBG& bg_obj)
|
2020-04-30 00:25:01 +02:00
|
|
|
{
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(backBuffer);
|
2020-11-03 00:05:24 +01:00
|
|
|
SDL_BlitSurface(bg_obj.buffer, NULL, bg_obj.buffer_lerp, NULL);
|
|
|
|
ScrollSurface(bg_obj.buffer_lerp, 0, lerp(0, -bg_obj.bscroll));
|
|
|
|
SDL_BlitSurface(bg_obj.buffer_lerp, &towerbuffer_rect, backBuffer, NULL);
|
2020-04-30 00:25:01 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 00:05:24 +01:00
|
|
|
void Graphics::updatetowerbackground(TowerBG& bg_obj)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-11-03 00:05:24 +01:00
|
|
|
if (bg_obj.bypos < 0) bg_obj.bypos += 120 * 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-11-03 00:05:24 +01:00
|
|
|
if (bg_obj.tdrawback)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-11-03 00:05:24 +01:00
|
|
|
int off = bg_obj.scrolldir == 0 ? 0 : bg_obj.bscroll;
|
2020-01-01 21:29:24 +01:00
|
|
|
//Draw the whole thing; needed for every colour cycle!
|
2020-11-02 19:49:54 +01:00
|
|
|
for (int j = -1; j < 32; j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < 40; i++)
|
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
const int temp = map.tower.backat(i, j, bg_obj.bypos);
|
2020-11-03 00:05:24 +01:00
|
|
|
drawtowertile3(i * 8, (j * 8) - (bg_obj.bypos % 8) - off, temp, bg_obj);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-03 00:05:24 +01:00
|
|
|
bg_obj.tdrawback = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//just update the bottom
|
2020-11-03 00:05:24 +01:00
|
|
|
ScrollSurface(bg_obj.buffer, 0, -bg_obj.bscroll);
|
|
|
|
if (bg_obj.scrolldir == 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-29 23:28:11 +02:00
|
|
|
for (int i = 0; i < 40; i++)
|
2020-04-29 22:44:28 +02:00
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
int temp = map.tower.backat(i, -1, bg_obj.bypos);
|
2020-11-03 00:05:24 +01:00
|
|
|
drawtowertile3(i * 8, -1*8 - (bg_obj.bypos % 8), temp, bg_obj);
|
|
|
|
temp = map.tower.backat(i, 0, bg_obj.bypos);
|
|
|
|
drawtowertile3(i * 8, -(bg_obj.bypos % 8), temp, bg_obj);
|
2020-04-29 22:44:28 +02:00
|
|
|
}
|
2020-04-29 23:28:11 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 40; i++)
|
2020-04-29 22:44:28 +02:00
|
|
|
{
|
2022-12-30 07:23:48 +01:00
|
|
|
int temp = map.tower.backat(i, 29, bg_obj.bypos);
|
2020-11-03 00:05:24 +01:00
|
|
|
drawtowertile3(i * 8, 29*8 - (bg_obj.bypos % 8) - bg_obj.bscroll, temp, bg_obj);
|
|
|
|
temp = map.tower.backat(i, 30, bg_obj.bypos);
|
|
|
|
drawtowertile3(i * 8, 30*8 - (bg_obj.bypos % 8) - bg_obj.bscroll, temp, bg_obj);
|
|
|
|
temp = map.tower.backat(i, 31, bg_obj.bypos);
|
|
|
|
drawtowertile3(i * 8, 31*8 - (bg_obj.bypos % 8) - bg_obj.bscroll, temp, bg_obj);
|
|
|
|
temp = map.tower.backat(i, 32, bg_obj.bypos);
|
|
|
|
drawtowertile3(i * 8, 32*8 - (bg_obj.bypos % 8) - bg_obj.bscroll, temp, bg_obj);
|
2020-04-29 22:44:28 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-02 05:16:08 +01:00
|
|
|
SDL_Color Graphics::getcol( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
//Setup predefinied colours as per our zany palette
|
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
//Player Normal
|
|
|
|
case 0:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(160 - help.glow/2 - (fRandom() * 20), 200 - help.glow/2, 220 - help.glow);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Player Hurt
|
|
|
|
case 1:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(196 - (fRandom() * 64), 10, 10);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Enemies and stuff
|
|
|
|
case 2:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(225 - (help.glow / 2), 75, 30);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 3: //Trinket
|
|
|
|
if (!trinketcolset)
|
|
|
|
{
|
|
|
|
trinketr = 200 - (fRandom() * 64);
|
|
|
|
trinketg = 200 - (fRandom() * 128);
|
|
|
|
trinketb = 164 + (fRandom() * 60);
|
|
|
|
trinketcolset = true;
|
|
|
|
}
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(trinketr, trinketg, trinketb);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 4: //Inactive savepoint
|
2022-12-30 07:23:48 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const int temp = (help.glow / 2) + (fRandom() * 8);
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(80 + temp, 80 + temp, 80 + temp);
|
2022-12-30 07:23:48 +01:00
|
|
|
}
|
2021-09-07 03:56:39 +02:00
|
|
|
case 5: //Active savepoint
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(164 + (fRandom() * 64), 164 + (fRandom() * 64), 255 - (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
case 6: //Enemy : Red
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(250 - help.glow/2, 60- help.glow/2, 60 - help.glow/2);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 7: //Enemy : Green
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(100 - help.glow/2 - (fRandom() * 30), 250 - help.glow/2, 100 - help.glow/2 - (fRandom() * 30));
|
2021-09-07 03:56:39 +02:00
|
|
|
case 8: //Enemy : Purple
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(250 - help.glow/2, 20, 128 - help.glow/2 + (fRandom() * 30));
|
2021-09-07 03:56:39 +02:00
|
|
|
case 9: //Enemy : Yellow
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(250 - help.glow/2, 250 - help.glow/2, 20);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 10: //Warp point (white)
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(255 - (fRandom() * 64), 255 - (fRandom() * 64), 255 - (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
case 11: //Enemy : Cyan
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(20, 250 - help.glow/2, 250 - help.glow/2);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 12: //Enemy : Blue
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(90 - help.glow/2, 90 - help.glow/2, 250 - help.glow/2);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Crew Members
|
|
|
|
//green
|
|
|
|
case 13:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(120 - help.glow/4 - (fRandom() * 20), 220 - help.glow/4, 120 - help.glow/4);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Yellow
|
|
|
|
case 14:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(220 - help.glow/4 - (fRandom() * 20), 210 - help.glow/4, 120 - help.glow/4);
|
2021-09-07 03:56:39 +02:00
|
|
|
//pink
|
|
|
|
case 15:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(255 - help.glow/8, 70 - help.glow/4, 70 - help.glow / 4);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Blue
|
|
|
|
case 16:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(75, 75, 255 - help.glow/4 - (fRandom() * 20));
|
2021-09-07 03:56:39 +02:00
|
|
|
|
|
|
|
|
|
|
|
case 17: //Enemy : Orange
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(250 - help.glow/2, 130 - help.glow/2, 20);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 18: //Enemy : Gray
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(130 - help.glow/2, 130 - help.glow/2, 130 - help.glow/2);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 19: //Enemy : Dark gray
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(60 - help.glow/8, 60 - help.glow/8, 60 - help.glow/8);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Purple
|
|
|
|
case 20:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(220 - help.glow/4 - (fRandom() * 20), 120 - help.glow/4, 210 - help.glow/4);
|
2021-09-07 03:56:39 +02:00
|
|
|
|
|
|
|
case 21: //Enemy : Light Gray
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(180 - help.glow/2, 180 - help.glow/2, 180 - help.glow/2);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 22: //Enemy : Indicator Gray
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(230 - help.glow/2, 230- help.glow/2, 230 - help.glow/2);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 23: //Enemy : Indicator Gray
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(255 - help.glow/2 - (fRandom() * 40) , 255 - help.glow/2 - (fRandom() * 40), 255 - help.glow/2 - (fRandom() * 40));
|
2021-09-07 03:56:39 +02:00
|
|
|
|
|
|
|
//Trophies
|
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
37b7615b71c3a2f44e03c47894383107850812ff, 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, 37b7615b71c3a2f44e03c47894383107850812ff
("Fix surface color masks") was the real fix, and
d271907f8c5d84308a3cf9323ac692199b8685a6 ("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 d271907f8c5d84308a3cf9323ac692199b8685a6.
Fixes #862.
2022-02-12 09:39:30 +01:00
|
|
|
//cyan
|
2021-09-07 03:56:39 +02:00
|
|
|
case 30:
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(160, 200, 220);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Purple
|
|
|
|
case 31:
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(220, 120, 210);
|
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
37b7615b71c3a2f44e03c47894383107850812ff, 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, 37b7615b71c3a2f44e03c47894383107850812ff
("Fix surface color masks") was the real fix, and
d271907f8c5d84308a3cf9323ac692199b8685a6 ("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 d271907f8c5d84308a3cf9323ac692199b8685a6.
Fixes #862.
2022-02-12 09:39:30 +01:00
|
|
|
//Yellow
|
2021-09-07 03:56:39 +02:00
|
|
|
case 32:
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(220, 210, 120);
|
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
37b7615b71c3a2f44e03c47894383107850812ff, 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, 37b7615b71c3a2f44e03c47894383107850812ff
("Fix surface color masks") was the real fix, and
d271907f8c5d84308a3cf9323ac692199b8685a6 ("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 d271907f8c5d84308a3cf9323ac692199b8685a6.
Fixes #862.
2022-02-12 09:39:30 +01:00
|
|
|
//red
|
2021-09-07 03:56:39 +02:00
|
|
|
case 33:
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(255, 70, 70);
|
2021-09-07 03:56:39 +02:00
|
|
|
//green
|
|
|
|
case 34:
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(120, 220, 120);
|
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
37b7615b71c3a2f44e03c47894383107850812ff, 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, 37b7615b71c3a2f44e03c47894383107850812ff
("Fix surface color masks") was the real fix, and
d271907f8c5d84308a3cf9323ac692199b8685a6 ("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 d271907f8c5d84308a3cf9323ac692199b8685a6.
Fixes #862.
2022-02-12 09:39:30 +01:00
|
|
|
//Blue
|
2021-09-07 03:56:39 +02:00
|
|
|
case 35:
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(75, 75, 255);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Gold
|
|
|
|
case 36:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(180, 120, 20);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 37: //Trinket
|
|
|
|
if (!trinketcolset)
|
|
|
|
{
|
|
|
|
trinketr = 200 - (fRandom() * 64);
|
|
|
|
trinketg = 200 - (fRandom() * 128);
|
|
|
|
trinketb = 164 + (fRandom() * 60);
|
|
|
|
trinketcolset = true;
|
|
|
|
}
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(trinketr, trinketg, trinketb);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Silver
|
|
|
|
case 38:
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(196, 196, 196);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Bronze
|
|
|
|
case 39:
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(128, 64, 10);
|
2021-09-07 03:56:39 +02:00
|
|
|
//Awesome
|
|
|
|
case 40: //Teleporter in action!
|
2022-12-30 07:23:48 +01:00
|
|
|
{
|
|
|
|
const int temp = fRandom() * 150;
|
2021-09-07 03:56:39 +02:00
|
|
|
if(temp<33)
|
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(255 - (fRandom() * 64), 64 + (fRandom() * 64), 64 + (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if (temp < 66)
|
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(64 + (fRandom() * 64), 255 - (fRandom() * 64), 64 + (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if (temp < 100)
|
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(64 + (fRandom() * 64), 64 + (fRandom() * 64), 255 - (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
return RGBf(164 + (fRandom() * 64), 164 + (fRandom() * 64), 255 - (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
2022-12-30 07:23:48 +01:00
|
|
|
}
|
2021-09-07 03:56:39 +02:00
|
|
|
|
|
|
|
case 100: //Inactive Teleporter
|
2022-12-30 07:23:48 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const int temp = (help.glow / 2) + (fRandom() * 8);
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(42 + temp, 42 + temp, 42 + temp);
|
2022-12-30 07:23:48 +01:00
|
|
|
}
|
2021-09-07 03:56:39 +02:00
|
|
|
case 101: //Active Teleporter
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(164 + (fRandom() * 64), 164 + (fRandom() * 64), 255 - (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
case 102: //Teleporter in action!
|
2022-12-30 07:23:48 +01:00
|
|
|
{
|
|
|
|
const int temp = fRandom() * 150;
|
2023-01-02 01:36:43 +01:00
|
|
|
if (temp < 33)
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(255 - (fRandom() * 64), 64 + (fRandom() * 64), 64 + (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if (temp < 66)
|
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(64 + (fRandom() * 64), 255 - (fRandom() * 64), 64 + (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if (temp < 100)
|
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(64 + (fRandom() * 64), 64 + (fRandom() * 64), 255 - (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(164 + (fRandom() * 64), 164 + (fRandom() * 64), 255 - (fRandom() * 64));
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
2022-12-30 07:23:48 +01:00
|
|
|
}
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
2023-01-02 05:16:08 +01:00
|
|
|
|
|
|
|
return getRGB(255, 255, 255);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::menuoffrender(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
const int usethisoffset = lerp(oldmenuoffset, menuoffset);
|
|
|
|
SDL_Rect offsetRect = {0, usethisoffset, backBuffer->w, backBuffer->h};
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
BlitSurfaceStandard(backBuffer, NULL, menubuffer, NULL);
|
|
|
|
BlitSurfaceStandard(tempBuffer, NULL, backBuffer, NULL);
|
|
|
|
BlitSurfaceStandard(menubuffer, NULL, backBuffer, &offsetRect);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
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 08:56:47 +01:00
|
|
|
gameScreen.UpdateScreen(backBuffer, NULL);
|
2021-09-07 03:56:39 +02:00
|
|
|
ClearSurface(backBuffer);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 05:16:08 +01:00
|
|
|
void Graphics::drawhuetile(const int x, const int y, const int tile, const SDL_Color ct)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
if (!INBOUNDS_VEC(tile, tiles))
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
point tpoint;
|
|
|
|
tpoint.x = x;
|
|
|
|
tpoint.y = y;
|
2020-04-30 23:42:08 +02:00
|
|
|
|
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect,tpoint.x,tpoint.y,tiles_rect.w, tiles_rect.h);
|
2023-01-02 05:16:08 +01:00
|
|
|
BlitSurfaceColoured(tiles[tile], NULL, backBuffer, &rect, ct);
|
2020-04-30 23:42:08 +02:00
|
|
|
}
|
|
|
|
|
2023-01-02 05:16:08 +01:00
|
|
|
SDL_Color Graphics::huetilegetcol(const int t)
|
2020-04-30 23:42:08 +02:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case 0:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(250-int(fRandom()*32), 250-int(fRandom()*32), 10);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 1:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(250-int(fRandom()*32), 250-int(fRandom()*32), 10);
|
2021-09-07 03:56:39 +02:00
|
|
|
default:
|
2023-01-02 05:16:08 +01:00
|
|
|
return getRGB(250-int(fRandom()*32), 250-int(fRandom()*32), 10);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Color Graphics::bigchunkygetcol(int t)
|
2020-04-30 23:57:21 +02:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
//A seperate index of colours, for simplicity
|
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case 1:
|
2021-08-28 21:59:46 +02:00
|
|
|
return getRGB((fRandom() * 64), 10, 10);
|
2021-09-07 03:56:39 +02:00
|
|
|
case 2:
|
2021-08-28 21:59:46 +02:00
|
|
|
return getRGB(int(160- help.glow/2 - (fRandom()*20)), 200- help.glow/2, 220 - help.glow);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color color = {0, 0, 0, 0};
|
|
|
|
return color;
|
2020-04-30 23:57:21 +02:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::textboxcenterx(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
vlog_error("textboxcenterx() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
2020-06-28 19:40:58 +02:00
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes[m].centerx();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
int Graphics::textboxwidth(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
vlog_error("textboxwidth() out-of-bounds!");
|
|
|
|
return 0;
|
|
|
|
}
|
2020-06-28 19:40:58 +02:00
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
return textboxes[m].w;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxmoveto(int xo)
|
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
vlog_error("textboxmoveto() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
2020-06-28 19:40:58 +02:00
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes[m].xp = xo;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::textboxcentery(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-13 06:02:15 +02:00
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
vlog_error("textboxcentery() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
2020-06-28 19:40:58 +02:00
|
|
|
|
2021-09-13 06:02:15 +02:00
|
|
|
textboxes[m].centery();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2022-12-30 22:57:24 +01:00
|
|
|
int Graphics::textboxwrap(int pad)
|
|
|
|
{
|
|
|
|
/* This function just takes a single-line textbox and wraps it...
|
|
|
|
* pad = the total number of characters we are going to pad this textbox.
|
|
|
|
* (or how many characters we should stay clear of 288 pixels width in general)
|
|
|
|
* Only to be used after a manual graphics.createtextbox[flipme] call.
|
|
|
|
* Returns the new, total height of the textbox. */
|
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
|
|
|
{
|
|
|
|
vlog_error("textboxwrap() out-of-bounds!");
|
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
if (textboxes[m].lines.empty())
|
|
|
|
{
|
|
|
|
vlog_error("textboxwrap() has no first line!");
|
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
std::string wrapped = string_wordwrap_balanced(textboxes[m].lines[0], 36*8 - pad*8);
|
|
|
|
textboxes[m].lines.clear();
|
|
|
|
|
|
|
|
size_t startline = 0;
|
|
|
|
size_t newline;
|
|
|
|
do {
|
|
|
|
size_t pos_n = wrapped.find('\n', startline);
|
|
|
|
size_t pos_p = wrapped.find('|', startline);
|
|
|
|
newline = SDL_min(pos_n, pos_p);
|
|
|
|
addline(wrapped.substr(startline, newline-startline));
|
|
|
|
startline = newline+1;
|
|
|
|
} while (newline != std::string::npos);
|
|
|
|
|
|
|
|
return textboxes[m].h;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxpad(size_t left_pad, size_t right_pad)
|
|
|
|
{
|
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
|
|
|
{
|
|
|
|
vlog_error("textboxpad() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
textboxes[m].pad(left_pad, right_pad);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxpadtowidth(size_t new_w)
|
|
|
|
{
|
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
|
|
|
{
|
|
|
|
vlog_error("textboxpadtowidth() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
textboxes[m].padtowidth(new_w);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxcentertext()
|
|
|
|
{
|
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
|
|
|
{
|
|
|
|
vlog_error("textboxcentertext() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
textboxes[m].centertext();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxcommsrelay()
|
|
|
|
{
|
|
|
|
/* Special treatment for the gamestate textboxes in Comms Relay */
|
|
|
|
if (!INBOUNDS_VEC(m, textboxes))
|
|
|
|
{
|
|
|
|
vlog_error("textboxcommsrelay() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
textboxwrap(11);
|
|
|
|
textboxes[m].xp = 224 - textboxes[m].w;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
int Graphics::crewcolour(const int t)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
//given crewmate t, return colour in setcol
|
|
|
|
if (t == 0) return CYAN;
|
|
|
|
if (t == 1) return PURPLE;
|
|
|
|
if (t == 2) return YELLOW;
|
|
|
|
if (t == 3) return RED;
|
|
|
|
if (t == 4) return GREEN;
|
|
|
|
if (t == 5) return BLUE;
|
|
|
|
return 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::flashlight(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
FillRect(backBuffer, 0xBB, 0xBB, 0xBB, 0xBB);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::screenshake(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
SDL_Rect shakeRect = {screenshake_x, screenshake_y, backBuffer->w, backBuffer->h};
|
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 08:56:47 +01:00
|
|
|
gameScreen.UpdateScreen(backBuffer, &shakeRect);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
ClearSurface(backBuffer);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::updatescreenshake(void)
|
2020-04-29 02:29:59 +02:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
screenshake_x = static_cast<Sint32>((fRandom() * 7) - 4);
|
|
|
|
screenshake_y = static_cast<Sint32>((fRandom() * 7) - 4);
|
2020-04-29 02:29:59 +02:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::render(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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 08:56:47 +01:00
|
|
|
gameScreen.UpdateScreen(backBuffer, NULL);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void Graphics::renderwithscreeneffects(void)
|
2020-04-27 04:24:50 +02:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (game.flashlight > 0 && !game.noflashingmode)
|
|
|
|
{
|
|
|
|
flashlight();
|
|
|
|
}
|
2020-04-27 04:24:50 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
if (game.screenshake > 0 && !game.noflashingmode)
|
|
|
|
{
|
|
|
|
screenshake();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
render();
|
|
|
|
}
|
2020-04-27 04:24:50 +02:00
|
|
|
}
|
|
|
|
|
Fix filter/screenshake/flash update order
In 2.2, at render time, the game rendered screenshakes and flashes if
their timers were above 0, and then decremented them afterwards. The
game would also update the analogue filter right before rendering it,
too.
In 2.3, this was changed so the flash and screenshake timers were
unified, and also done at the end of the frame - right before rendering
happened. This resulted in 1-frame flashes and screenshakes not
rendering at all. The other changes in this patchset don't fix this
either. The analogue filter was also in the wrong order, but that is
less of an issue than flashes and screenshakes.
So, what I've done is made the flash and screenshake timers update right
before the loop switches over to rendering, and only decrements them
when we switch back to fixed functions (after rendering). The analogue
filter is also updated right before rendering as well. This restores
1-frame flashes and screenshakes, as well as restores the correct order
of analogue filter updates.
2021-03-18 01:53:17 +01:00
|
|
|
void Graphics::renderfixedpre(void)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (game.screenshake > 0)
|
|
|
|
{
|
|
|
|
updatescreenshake();
|
|
|
|
}
|
Fix filter/screenshake/flash update order
In 2.2, at render time, the game rendered screenshakes and flashes if
their timers were above 0, and then decremented them afterwards. The
game would also update the analogue filter right before rendering it,
too.
In 2.3, this was changed so the flash and screenshake timers were
unified, and also done at the end of the frame - right before rendering
happened. This resulted in 1-frame flashes and screenshakes not
rendering at all. The other changes in this patchset don't fix this
either. The analogue filter was also in the wrong order, but that is
less of an issue than flashes and screenshakes.
So, what I've done is made the flash and screenshake timers update right
before the loop switches over to rendering, and only decrements them
when we switch back to fixed functions (after rendering). The analogue
filter is also updated right before rendering as well. This restores
1-frame flashes and screenshakes, as well as restores the correct order
of analogue filter updates.
2021-03-18 01:53:17 +01:00
|
|
|
|
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 08:56:47 +01:00
|
|
|
if (gameScreen.badSignalEffect)
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
UpdateFilter();
|
|
|
|
}
|
Fix filter/screenshake/flash update order
In 2.2, at render time, the game rendered screenshakes and flashes if
their timers were above 0, and then decremented them afterwards. The
game would also update the analogue filter right before rendering it,
too.
In 2.3, this was changed so the flash and screenshake timers were
unified, and also done at the end of the frame - right before rendering
happened. This resulted in 1-frame flashes and screenshakes not
rendering at all. The other changes in this patchset don't fix this
either. The analogue filter was also in the wrong order, but that is
less of an issue than flashes and screenshakes.
So, what I've done is made the flash and screenshake timers update right
before the loop switches over to rendering, and only decrements them
when we switch back to fixed functions (after rendering). The analogue
filter is also updated right before rendering as well. This restores
1-frame flashes and screenshakes, as well as restores the correct order
of analogue filter updates.
2021-03-18 01:53:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::renderfixedpost(void)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
/* Screen effects timers */
|
|
|
|
if (game.flashlight > 0)
|
|
|
|
{
|
|
|
|
--game.flashlight;
|
|
|
|
}
|
|
|
|
if (game.screenshake > 0)
|
|
|
|
{
|
|
|
|
--game.screenshake;
|
|
|
|
}
|
Fix filter/screenshake/flash update order
In 2.2, at render time, the game rendered screenshakes and flashes if
their timers were above 0, and then decremented them afterwards. The
game would also update the analogue filter right before rendering it,
too.
In 2.3, this was changed so the flash and screenshake timers were
unified, and also done at the end of the frame - right before rendering
happened. This resulted in 1-frame flashes and screenshakes not
rendering at all. The other changes in this patchset don't fix this
either. The analogue filter was also in the wrong order, but that is
less of an issue than flashes and screenshakes.
So, what I've done is made the flash and screenshake timers update right
before the loop switches over to rendering, and only decrements them
when we switch back to fixed functions (after rendering). The analogue
filter is also updated right before rendering as well. This restores
1-frame flashes and screenshakes, as well as restores the correct order
of analogue filter updates.
2021-03-18 01:53:17 +01:00
|
|
|
}
|
|
|
|
|
2021-09-07 00:41:49 +02:00
|
|
|
void Graphics::bigrprint(int x, int y, const std::string& t, int r, int g, int b, bool cen, float sc)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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-23 01:43:31 +01:00
|
|
|
const int len_ = len(t);
|
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
x = x / (sc);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
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-23 01:43:31 +01:00
|
|
|
x -= len_;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
if (cen)
|
|
|
|
{
|
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-23 01:43:31 +01:00
|
|
|
x = SDL_max(160 - (int((len_/ 2.0)*sc)), 0 );
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x *= (sc);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
return do_print(x, y, t, r, g, b, 255, sc);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-09-07 00:41:49 +02:00
|
|
|
void Graphics::bigbrprint(int x, int y, const std::string& s, int r, int g, int b, bool cen, float sc)
|
2021-03-19 22:28:04 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (!notextoutline)
|
|
|
|
{
|
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-23 01:43:31 +01:00
|
|
|
const int len_ = len(s);
|
|
|
|
int x_o = x / sc - len_;
|
2021-09-07 03:56:39 +02:00
|
|
|
bigrprint(x, y - sc, s, 0, 0, 0, cen, sc);
|
|
|
|
if (cen)
|
|
|
|
{
|
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-23 01:43:31 +01:00
|
|
|
x_o = SDL_max(160 - (len_ / 2) * sc, 0);
|
2021-09-07 03:56:39 +02:00
|
|
|
bigprint(x_o - sc, y, s, 0, 0, 0, false, sc);
|
|
|
|
bigprint(x_o + sc, y, s, 0, 0, 0, false, sc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x_o *= sc;
|
|
|
|
bigprint(x_o - sc, y, s, 0, 0, 0, false, sc);
|
|
|
|
bigprint(x_o + sc, y, s, 0, 0, 0, false, sc);
|
|
|
|
}
|
|
|
|
bigrprint(x, y + sc, s, 0, 0, 0, cen, sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
bigrprint(x, y, s, r, g, b, cen, sc);
|
2021-03-19 22:28:04 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
void Graphics::drawtele(int x, int y, int t, const SDL_Color color)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
SDL_Rect telerect;
|
|
|
|
setRect(telerect, x , y, tele_rect.w, tele_rect.h );
|
|
|
|
if (INBOUNDS_VEC(0, tele))
|
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
BlitSurfaceColoured(tele[0], NULL, backBuffer, &telerect, getRGB(16, 16, 16));
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
if (t > 9) t = 8;
|
|
|
|
if (t < 1) t = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
setRect(telerect, x , y, tele_rect.w, tele_rect.h );
|
|
|
|
if (INBOUNDS_VEC(t, tele))
|
|
|
|
{
|
2023-01-02 05:16:08 +01:00
|
|
|
BlitSurfaceColoured(tele[t], NULL, backBuffer, &telerect, color);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Color Graphics::getRGBA(const Uint8 r, const Uint8 g, const Uint8 b, const Uint8 a)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color color = {r, g, b, a};
|
|
|
|
return color;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Color Graphics::getRGB(const Uint8 r, const Uint8 g, const Uint8 b)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color color = {r, g, b, 255};
|
|
|
|
return color;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Color Graphics::RGBf(int r, int g, int b)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
r = (r + 128) / 3;
|
|
|
|
g = (g + 128) / 3;
|
|
|
|
b = (b + 128) / 3;
|
|
|
|
const SDL_Color color = {(Uint8) r, (Uint8) g, (Uint8) b, 255};
|
|
|
|
return color;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawforetile(int x, int y, int t)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (!INBOUNDS_VEC(t, tiles))
|
|
|
|
{
|
|
|
|
WHINE_ONCE("drawforetile() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
2020-06-30 20:51:01 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect, x,y,tiles_rect.w, tiles_rect.h);
|
2020-06-30 20:47:22 +02:00
|
|
|
|
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
2021-09-07 03:56:39 +02:00
|
|
|
if (shouldrecoloroneway(t, tiles1_mounted))
|
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color thect = cl.getonewaycol();
|
2021-09-07 03:56:39 +02:00
|
|
|
BlitSurfaceTinted(tiles[t], NULL, foregroundBuffer, &rect, thect);
|
|
|
|
}
|
|
|
|
else
|
2020-06-30 20:47:22 +02:00
|
|
|
#endif
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
BlitSurfaceStandard(tiles[t],NULL, foregroundBuffer, &rect );
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawforetile2(int x, int y, int t)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (!INBOUNDS_VEC(t, tiles2))
|
|
|
|
{
|
|
|
|
WHINE_ONCE("drawforetile2() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
2020-06-30 20:51:01 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect, x,y,tiles_rect.w, tiles_rect.h);
|
2020-06-30 20:47:22 +02:00
|
|
|
|
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
2021-09-07 03:56:39 +02:00
|
|
|
if (shouldrecoloroneway(t, tiles2_mounted))
|
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color thect = cl.getonewaycol();
|
2021-09-07 03:56:39 +02:00
|
|
|
BlitSurfaceTinted(tiles2[t], NULL, foregroundBuffer, &rect, thect);
|
|
|
|
}
|
|
|
|
else
|
2020-06-30 20:47:22 +02:00
|
|
|
#endif
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
BlitSurfaceStandard(tiles2[t],NULL, foregroundBuffer, &rect );
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawforetile3(int x, int y, int t, int off)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
t += off * 30;
|
|
|
|
if (!INBOUNDS_VEC(t, tiles3))
|
|
|
|
{
|
|
|
|
WHINE_ONCE("drawforetile3() out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect, x,y,tiles_rect.w, tiles_rect.h);
|
|
|
|
BlitSurfaceStandard(tiles3[t],NULL, foregroundBuffer, &rect );
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawrect(int x, int y, int w, int h, int r, int g, int b)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
SDL_Rect madrect;
|
|
|
|
//Draw the retangle indicated by that object
|
|
|
|
madrect.x = x;
|
|
|
|
madrect.y = y;
|
|
|
|
madrect.w = w;
|
|
|
|
madrect.h = 1;
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer, madrect, getRGB(r, g, b));
|
2021-09-07 03:56:39 +02:00
|
|
|
|
|
|
|
madrect.w = 1;
|
|
|
|
madrect.h = h;
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer, madrect, getRGB(r, g, b));
|
2021-09-07 03:56:39 +02:00
|
|
|
|
|
|
|
madrect.x = x + w - 1;
|
|
|
|
madrect.w = 1;
|
|
|
|
madrect.h = h;
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer, madrect, getRGB(r, g, b));
|
2021-09-07 03:56:39 +02:00
|
|
|
madrect.x = x;
|
|
|
|
madrect.y = y + h - 1;
|
|
|
|
madrect.w = w;
|
|
|
|
madrect.h = 1;
|
2021-09-07 05:08:00 +02:00
|
|
|
FillRect(backBuffer, madrect, getRGB(r, g, b));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Graphics::onscreen(int t)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
return (t >= -40 && t <= 280);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-06-01 01:31:02 +02:00
|
|
|
|
2021-08-07 05:57:34 +02:00
|
|
|
bool Graphics::reloadresources(void)
|
2021-02-16 00:38:41 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
grphx.destroy();
|
|
|
|
grphx.init();
|
2020-06-12 02:55:27 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
destroy();
|
2020-06-12 02:55:27 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
MAYBE_FAIL(MakeTileArray());
|
|
|
|
MAYBE_FAIL(MakeSpriteArray());
|
|
|
|
MAYBE_FAIL(maketelearray());
|
|
|
|
MAYBE_FAIL(Makebfont());
|
2020-06-12 02:55:27 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
images.clear();
|
2020-06-12 02:55:27 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
images.push_back(grphx.im_image0);
|
|
|
|
images.push_back(grphx.im_image1);
|
|
|
|
images.push_back(grphx.im_image2);
|
|
|
|
images.push_back(grphx.im_image3);
|
|
|
|
images.push_back(grphx.im_image4);
|
|
|
|
images.push_back(grphx.im_image5);
|
|
|
|
images.push_back(grphx.im_image6);
|
2020-06-12 02:55:27 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
images.push_back(grphx.im_image7);
|
|
|
|
images.push_back(grphx.im_image8);
|
|
|
|
images.push_back(grphx.im_image9);
|
|
|
|
images.push_back(grphx.im_image10);
|
|
|
|
images.push_back(grphx.im_image11);
|
|
|
|
images.push_back(grphx.im_image12);
|
2020-06-12 02:55:27 +02:00
|
|
|
|
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 08:56:47 +01:00
|
|
|
gameScreen.LoadIcon();
|
2020-11-01 04:30:24 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
music.destroy();
|
|
|
|
music.init();
|
Make one-way recolors check for specific files
So, 2.3 added recoloring one-way tiles to no longer make them be always
yellow. However, custom levels that retexture the one-way tiles might
not want them to be recolored. So, if there are ANY custom assets
mounted, then the one-ways will not be recolored. However, if the XML
has a <onewaycol_override>1</onewaycol_override> tag, then the one-way
will be recolored again anyways.
When I added one-way recoloring, I didn't intend for any custom asset to
disable the recoloring; I only did it because I couldn't find a way to
check if a specific file was customized by the custom level or not.
However, I have figured out how to do so, and so now tiles.png one-way
recolors will only be disabled if there's a custom tiles.png, and
tiles2.png one-way recolors will only be disabled if there's a custom
tiles2.png.
In order to make sure we're not calling PhysFS functions on every single
deltaframe, I've added caching variables, tiles1_mounted and
tiles2_mounted, to Graphics; these get assigned every time
reloadresources() is called.
2021-03-06 19:52:11 +01:00
|
|
|
|
|
|
|
#ifndef NO_CUSTOM_LEVELS
|
2021-09-07 03:56:39 +02:00
|
|
|
tiles1_mounted = FILESYSTEM_isAssetMounted("graphics/tiles.png");
|
|
|
|
tiles2_mounted = FILESYSTEM_isAssetMounted("graphics/tiles2.png");
|
|
|
|
minimap_mounted = FILESYSTEM_isAssetMounted("graphics/minimap.png");
|
Make one-way recolors check for specific files
So, 2.3 added recoloring one-way tiles to no longer make them be always
yellow. However, custom levels that retexture the one-way tiles might
not want them to be recolored. So, if there are ANY custom assets
mounted, then the one-ways will not be recolored. However, if the XML
has a <onewaycol_override>1</onewaycol_override> tag, then the one-way
will be recolored again anyways.
When I added one-way recoloring, I didn't intend for any custom asset to
disable the recoloring; I only did it because I couldn't find a way to
check if a specific file was customized by the custom level or not.
However, I have figured out how to do so, and so now tiles.png one-way
recolors will only be disabled if there's a custom tiles.png, and
tiles2.png one-way recolors will only be disabled if there's a custom
tiles2.png.
In order to make sure we're not calling PhysFS functions on every single
deltaframe, I've added caching variables, tiles1_mounted and
tiles2_mounted, to Graphics; these get assigned every time
reloadresources() is called.
2021-03-06 19:52:11 +01:00
|
|
|
#endif
|
2021-08-07 05:57:34 +02:00
|
|
|
|
2022-12-30 22:57:24 +01:00
|
|
|
gamecomplete_mounted = FILESYSTEM_isAssetMounted("graphics/gamecomplete.png");
|
|
|
|
levelcomplete_mounted = FILESYSTEM_isAssetMounted("graphics/levelcomplete.png");
|
|
|
|
flipgamecomplete_mounted = FILESYSTEM_isAssetMounted("graphics/flipgamecomplete.png");
|
|
|
|
fliplevelcomplete_mounted = FILESYSTEM_isAssetMounted("graphics/fliplevelcomplete.png");
|
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
return true;
|
2021-08-07 05:57:34 +02:00
|
|
|
|
|
|
|
fail:
|
2021-09-07 03:56:39 +02:00
|
|
|
return false;
|
2020-06-01 01:31:02 +02:00
|
|
|
}
|
2020-05-02 22:53:19 +02:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Color Graphics::crewcolourreal(int t)
|
2020-05-02 22:53:19 +02:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
return col_crewcyan;
|
|
|
|
case 1:
|
|
|
|
return col_crewpurple;
|
|
|
|
case 2:
|
|
|
|
return col_crewyellow;
|
|
|
|
case 3:
|
|
|
|
return col_crewred;
|
|
|
|
case 4:
|
|
|
|
return col_crewgreen;
|
|
|
|
case 5:
|
|
|
|
return col_crewblue;
|
|
|
|
}
|
|
|
|
return col_crewcyan;
|
2020-05-02 22:53:19 +02:00
|
|
|
}
|
2022-12-30 22:57:24 +01:00
|
|
|
|
|
|
|
void Graphics::render_roomname(const char* roomname, int r, int g, int b)
|
|
|
|
{
|
|
|
|
footerrect.y = 230;
|
|
|
|
if (translucentroomname)
|
|
|
|
{
|
|
|
|
SDL_BlitSurface(footerbuffer, NULL, backBuffer, &footerrect);
|
|
|
|
bprint(5, 231, roomname, r, g, b, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
FillRect(backBuffer, footerrect, 0, 0, 0);
|
2022-12-30 22:57:24 +01:00
|
|
|
Print(5, 231, roomname, r, g, b, true);
|
|
|
|
}
|
|
|
|
}
|