2020-01-01 21:29:24 +01:00
|
|
|
#include "Graphics.h"
|
|
|
|
#include "Maths.h"
|
|
|
|
#include "Entity.h"
|
|
|
|
#include "Map.h"
|
|
|
|
#include "Screen.h"
|
2020-01-31 19:25:37 +01:00
|
|
|
#include "FileSystemUtils.h"
|
|
|
|
#include <utf8/unchecked.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2020-01-01 21:29:24 +01:00
|
|
|
|
Allow using help/graphics/music/game/key/map/obj everywhere
This commit makes `help`, `graphics`, `music`, `game`, `key`, `map`, and
`obj` essentially static global objects that can be used everywhere.
This is useful in case we ever need to add a new function in the future,
so we don't have to bother with passing a new argument in which means we
have to pass a new argument in to the function that calls that function
which means having to pass a new argument into the function that calls
THAT function, etc. which is a real headache when working on fan mods of
the source code.
Note that this changes NONE of the existing function signatures, it
merely just makes those variables accessible everywhere in the same way
`script` and `ed` are.
Also note that some classes had to be initialized after the filesystem
was initialized, but C++ would keep initializing them before the
filesystem got initialized, because I *had* to put them at the top of
`main.cpp`, or else they wouldn't be global variables.
The only way to work around this was to use entityclass's initialization
style (which I'm pretty sure entityclass of all things doesn't need to
be initialized this way), where you actually initialize the class in an
`init()` function, and so then you do `graphics.init()` after the
filesystem initialization, AFTER doing `Graphics graphics` up at the
top.
I've had to do this for `graphics` (but only because its child
GraphicsResources `grphx` needs to be initialized this way), `music`,
and `game`. I don't think this will affect anything. Other than that,
`help`, `key`, and `map` are still using the C++-intended method of
having ClassName::ClassName() functions.
2020-01-29 08:35:03 +01:00
|
|
|
void Graphics::init()
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Allow using help/graphics/music/game/key/map/obj everywhere
This commit makes `help`, `graphics`, `music`, `game`, `key`, `map`, and
`obj` essentially static global objects that can be used everywhere.
This is useful in case we ever need to add a new function in the future,
so we don't have to bother with passing a new argument in which means we
have to pass a new argument in to the function that calls that function
which means having to pass a new argument into the function that calls
THAT function, etc. which is a real headache when working on fan mods of
the source code.
Note that this changes NONE of the existing function signatures, it
merely just makes those variables accessible everywhere in the same way
`script` and `ed` are.
Also note that some classes had to be initialized after the filesystem
was initialized, but C++ would keep initializing them before the
filesystem got initialized, because I *had* to put them at the top of
`main.cpp`, or else they wouldn't be global variables.
The only way to work around this was to use entityclass's initialization
style (which I'm pretty sure entityclass of all things doesn't need to
be initialized this way), where you actually initialize the class in an
`init()` function, and so then you do `graphics.init()` after the
filesystem initialization, AFTER doing `Graphics graphics` up at the
top.
I've had to do this for `graphics` (but only because its child
GraphicsResources `grphx` needs to be initialized this way), `music`,
and `game`. I don't think this will affect anything. Other than that,
`help`, `key`, and `map` are still using the C++-intended method of
having ClassName::ClassName() functions.
2020-01-29 08:35:03 +01:00
|
|
|
grphx.init();
|
|
|
|
|
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(bfont_rect, 0,0,8,8);
|
|
|
|
setRect(bfontmask_rect, 0,0,8,8);
|
|
|
|
setRect(bg_rect, 0,0,320,240);
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
//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;
|
|
|
|
cutscenebarspos = 0;
|
2020-04-29 02:16:24 +02:00
|
|
|
oldcutscenebarspos = 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
|
|
|
|
for (int i = 0; i < 50; i++)
|
|
|
|
{
|
|
|
|
SDL_Rect s = {Sint16(fRandom() * 320), Sint16(fRandom() * 240), 2, 2};
|
|
|
|
int s2 = 4+(fRandom()*4);
|
|
|
|
stars.push_back(s);
|
|
|
|
starsspeed.push_back(s2);
|
|
|
|
|
|
|
|
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);
|
|
|
|
backboxes.push_back(bb);
|
|
|
|
backboxvx.push_back(bvx);
|
|
|
|
backboxvy.push_back(bvy);
|
|
|
|
backboxint.push_back(bint);
|
|
|
|
}
|
|
|
|
backoffset = 0;
|
|
|
|
backgrounddrawn = false;
|
|
|
|
|
|
|
|
warpskip = 0;
|
|
|
|
warpfcol = 0x000000;
|
|
|
|
warpbcol = 0x000000;
|
|
|
|
|
|
|
|
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-01-12 18:26:00 +01:00
|
|
|
fadebars.resize(15);
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
fadeamount = 0;
|
2020-04-29 03:10:40 +02:00
|
|
|
oldfadeamount = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
fademode = 0;
|
|
|
|
|
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
|
|
|
bcol = 0;
|
|
|
|
bcol2 = 0;
|
2020-01-12 18:26:00 +01:00
|
|
|
ct = colourTransform();
|
|
|
|
foot_rect = SDL_Rect();
|
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;
|
2020-01-12 18:26:00 +01:00
|
|
|
images_rect = SDL_Rect();
|
2020-01-11 01:37:23 +01:00
|
|
|
m = 0;
|
|
|
|
linedelay = 0;
|
2020-01-11 17:33:36 +01:00
|
|
|
menubuffer = NULL;
|
|
|
|
screenbuffer = NULL;
|
|
|
|
tempBuffer = NULL;
|
2020-01-12 18:26:00 +01:00
|
|
|
tl = point();
|
2020-01-11 17:33:36 +01:00
|
|
|
towerbuffer = NULL;
|
2020-04-29 20:03:17 +02:00
|
|
|
towerbuffer_lerp = NULL;
|
2020-01-11 01:37:23 +01:00
|
|
|
trinketr = 0;
|
|
|
|
trinketg = 0;
|
|
|
|
trinketb = 0;
|
2020-01-12 18:26:00 +01:00
|
|
|
warprect = SDL_Rect();
|
2020-01-25 05:43:04 +01:00
|
|
|
|
|
|
|
translucentroomname = false;
|
2020-01-29 08:17:13 +01:00
|
|
|
showmousecursor = true;
|
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
|
|
|
|
|
|
|
col_crewred = 0x00000000;
|
|
|
|
col_crewyellow = 0x00000000;
|
|
|
|
col_crewgreen = 0x00000000;
|
|
|
|
col_crewcyan = 0x00000000;
|
|
|
|
col_crewblue = 0x00000000;
|
|
|
|
col_crewpurple = 0x00000000;
|
|
|
|
col_crewinactive = 0x00000000;
|
|
|
|
col_clock = 0x00000000;
|
|
|
|
col_trinket = 0x00000000;
|
|
|
|
col_tr = 0;
|
|
|
|
col_tg = 0;
|
|
|
|
col_tb = 0;
|
2020-05-02 21:06:40 +02:00
|
|
|
|
|
|
|
kludgeswnlinewidth = false;
|
2020-05-04 22:19:47 +02:00
|
|
|
|
|
|
|
vsync = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-02-11 06:48:07 +01:00
|
|
|
int Graphics::font_idx(uint32_t ch) {
|
2020-01-31 19:25:37 +01:00
|
|
|
if (font_positions.size() > 0) {
|
|
|
|
std::map<int, int>::iterator iter = font_positions.find(ch);
|
|
|
|
if (iter == font_positions.end()) {
|
|
|
|
iter = font_positions.find('?');
|
|
|
|
if (iter == font_positions.end()) {
|
|
|
|
puts("font.txt missing fallback character!");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return iter->second;
|
|
|
|
} else {
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
Graphics::~Graphics()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
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-06-14 03:35:12 +02:00
|
|
|
if (!INBOUNDS(t, sprites))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect,x,y,sprites_rect.w,sprites_rect.h);
|
2020-03-31 21:26:11 +02:00
|
|
|
setcol(c);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
BlitSurfaceColoured(sprites[t],NULL,backBuffer, &rect, ct);
|
|
|
|
}
|
|
|
|
|
2020-05-02 01:40:35 +02:00
|
|
|
void Graphics::updatetitlecolours()
|
|
|
|
{
|
|
|
|
setcol(15);
|
|
|
|
col_crewred = ct.colour;
|
|
|
|
setcol(14);
|
|
|
|
col_crewyellow = ct.colour;
|
|
|
|
setcol(13);
|
|
|
|
col_crewgreen = ct.colour;
|
|
|
|
setcol(0);
|
|
|
|
col_crewcyan = ct.colour;
|
|
|
|
setcol(16);
|
|
|
|
col_crewblue = ct.colour;
|
|
|
|
setcol(20);
|
|
|
|
col_crewpurple = ct.colour;
|
|
|
|
setcol(19);
|
|
|
|
col_crewinactive = ct.colour;
|
|
|
|
|
|
|
|
setcol(18);
|
|
|
|
col_clock = ct.colour;
|
|
|
|
setcol(18);
|
|
|
|
col_trinket = ct.colour;
|
|
|
|
}
|
|
|
|
|
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) \
|
|
|
|
if (grphx.im_##tilesheet->w % tile_square != 0 \
|
|
|
|
|| grphx.im_##tilesheet->h % tile_square != 0) \
|
|
|
|
{ \
|
|
|
|
const char* error = "Error: %s.png dimensions not exact multiples of %i!"; \
|
|
|
|
char message[128]; \
|
|
|
|
SDL_snprintf(message, sizeof(message), error, #tilesheet, tile_square); \
|
|
|
|
\
|
|
|
|
const char* error_title = "Error with %s.png"; \
|
|
|
|
char message_title[128]; \
|
|
|
|
SDL_snprintf(message_title, sizeof(message_title), error_title, #tilesheet); \
|
|
|
|
\
|
|
|
|
puts(message); \
|
|
|
|
\
|
|
|
|
SDL_ShowSimpleMessageBox( \
|
|
|
|
SDL_MESSAGEBOX_ERROR, \
|
|
|
|
message_title, \
|
|
|
|
message, \
|
|
|
|
NULL \
|
|
|
|
); \
|
|
|
|
\
|
|
|
|
exit(1); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define PROCESS_TILESHEET_RENAME(tilesheet, vector, tile_square, extra_code) \
|
|
|
|
PROCESS_TILESHEET_CHECK_ERROR(tilesheet, tile_square) \
|
|
|
|
\
|
|
|
|
for (int j = 0; j < grphx.im_##tilesheet->h / tile_square; j++) \
|
|
|
|
{ \
|
|
|
|
for (int 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 \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define PROCESS_TILESHEET(tilesheet, tile_square, extra_code) \
|
|
|
|
PROCESS_TILESHEET_RENAME(tilesheet, tilesheet, tile_square, extra_code)
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
void Graphics::Makebfont()
|
|
|
|
{
|
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
|
|
|
|
2020-01-31 19:25:37 +01:00
|
|
|
unsigned char* charmap = NULL;
|
|
|
|
size_t length;
|
|
|
|
FILESYSTEM_loadFileToMemory("graphics/font.txt", &charmap, &length);
|
|
|
|
if (charmap != NULL) {
|
|
|
|
unsigned char* current = charmap;
|
|
|
|
unsigned char* end = charmap + length;
|
|
|
|
int pos = 0;
|
|
|
|
while (current != end) {
|
|
|
|
int codepoint = utf8::unchecked::next(current);
|
|
|
|
font_positions[codepoint] = pos;
|
|
|
|
++pos;
|
|
|
|
}
|
2020-06-07 22:29:48 +02:00
|
|
|
FILESYSTEM_freeMemory(&charmap);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-01-31 19:25:37 +01:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-02-11 06:48:07 +01:00
|
|
|
int Graphics::bfontlen(uint32_t ch) {
|
2020-01-31 19:25:37 +01:00
|
|
|
if (ch < 32) {
|
|
|
|
return 6;
|
|
|
|
} else {
|
|
|
|
return 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::MakeTileArray()
|
|
|
|
{
|
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(tiles, 8, )
|
|
|
|
PROCESS_TILESHEET(tiles2, 8, )
|
|
|
|
PROCESS_TILESHEET(tiles3, 8, )
|
|
|
|
PROCESS_TILESHEET(entcolours, 8, )
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::maketelearray()
|
|
|
|
{
|
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_RENAME(teleporter, tele, 96, )
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::MakeSpriteArray()
|
|
|
|
{
|
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(sprites, 32, )
|
|
|
|
PROCESS_TILESHEET(flipsprites, 32, )
|
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
|
|
|
|
2020-06-21 03:33:55 +02:00
|
|
|
void Graphics::map_tab(int opt, const std::string& text, bool selected /*= false*/)
|
|
|
|
{
|
|
|
|
int x = opt*80 + 40 - len(text)/2;
|
|
|
|
if (selected)
|
|
|
|
{
|
|
|
|
Print(x-8, 220, "[" + text + "]", 196, 196, 255 - help.glow);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Print(x, 220, text, 64, 64, 64);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2020-06-23 03:29:52 +02:00
|
|
|
std::string text_upper(text);
|
|
|
|
std::transform(text_upper.begin(), text_upper.end(), text_upper.begin(), ::toupper);
|
|
|
|
Print(x - 16, y, "[ " + text_upper + " ]", 196, 196, 255 - help.glow);
|
2020-06-23 00:23:15 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Print(x, y, text, 96, 96, 96);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-10 03:23:12 +01:00
|
|
|
void Graphics::Print( int _x, int _y, std::string _s, int r, int g, int b, bool cen /*= false*/ ) {
|
|
|
|
return PrintAlpha(_x,_y,_s,r,g,b,255,cen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::PrintAlpha( int _x, int _y, std::string _s, int r, int g, int b, int a, bool cen /*= false*/ )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-14 03:46:32 +02:00
|
|
|
std::vector<SDL_Surface*>& font = flipmode ? flipbfont : bfont;
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
r = clamp(r,0,255);
|
|
|
|
g = clamp(g,0,255);
|
|
|
|
b = clamp(b,0,255);
|
2020-02-10 03:23:12 +01:00
|
|
|
a = clamp(a,0,255);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-02-10 03:23:12 +01:00
|
|
|
ct.colour = getRGBA(r, g, b, a);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if (cen)
|
|
|
|
_x = ((160 ) - ((len(_s)) / 2));
|
|
|
|
int bfontpos = 0;
|
|
|
|
int curr;
|
2020-06-14 03:56:59 +02:00
|
|
|
int idx;
|
2020-01-31 19:25:37 +01:00
|
|
|
std::string::iterator iter = _s.begin();
|
|
|
|
while (iter != _s.end()) {
|
|
|
|
curr = utf8::unchecked::next(iter);
|
2020-01-01 21:29:24 +01:00
|
|
|
point tpoint;
|
|
|
|
tpoint.x = _x + bfontpos;
|
|
|
|
tpoint.y = _y;
|
|
|
|
|
|
|
|
SDL_Rect fontRect = bfont_rect;
|
|
|
|
fontRect.x = tpoint.x ;
|
|
|
|
fontRect.y = tpoint.y ;
|
|
|
|
|
2020-06-14 03:56:59 +02:00
|
|
|
idx = font_idx(curr);
|
|
|
|
if (INBOUNDS(idx, font))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured( font[idx], NULL, backBuffer, &fontRect , ct);
|
|
|
|
}
|
2020-01-31 19:25:37 +01:00
|
|
|
bfontpos+=bfontlen(curr) ;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Graphics::bigprint( int _x, int _y, std::string _s, int r, int g, int b, bool cen, int sc )
|
|
|
|
{
|
2020-06-14 03:46:32 +02:00
|
|
|
std::vector<SDL_Surface*>& font = flipmode ? flipbfont : bfont;
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
r = clamp(r,0,255);
|
|
|
|
g = clamp(g,0,255);
|
|
|
|
b = clamp(b,0,255);
|
|
|
|
|
|
|
|
ct.colour = getRGB(r, g, b);
|
|
|
|
|
2020-04-02 22:05:48 +02:00
|
|
|
if (cen)
|
|
|
|
{
|
|
|
|
_x = std::max(160 - (int((len(_s)/ 2.0)*sc)), 0 );
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
int bfontpos = 0;
|
|
|
|
int curr;
|
2020-06-14 03:56:59 +02:00
|
|
|
int idx;
|
2020-01-31 19:25:37 +01:00
|
|
|
std::string::iterator iter = _s.begin();
|
|
|
|
while (iter != _s.end()) {
|
|
|
|
curr = utf8::unchecked::next(iter);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
point tpoint;
|
|
|
|
tpoint.x = _x + bfontpos;
|
|
|
|
tpoint.y = _y;
|
|
|
|
|
|
|
|
SDL_Rect fontRect = bfont_rect;
|
|
|
|
fontRect.x = tpoint.x ;
|
|
|
|
fontRect.y = tpoint.y ;
|
|
|
|
*/
|
|
|
|
|
2020-06-14 03:56:59 +02:00
|
|
|
idx = font_idx(curr);
|
|
|
|
if (INBOUNDS(idx, font))
|
|
|
|
{
|
|
|
|
SDL_Surface* tempPrint = ScaleSurfaceSlow(font[idx], font[idx]->w *sc,font[idx]->h *sc);
|
|
|
|
SDL_Rect printrect = { static_cast<Sint16>((_x) + bfontpos), static_cast<Sint16>(_y) , static_cast<Sint16>((bfont_rect.w*sc)+1), static_cast<Sint16>((bfont_rect.h * sc)+1)};
|
|
|
|
BlitSurfaceColoured(tempPrint, NULL, backBuffer, &printrect, ct);
|
|
|
|
SDL_FreeSurface(tempPrint);
|
|
|
|
}
|
2020-01-31 19:25:37 +01:00
|
|
|
bfontpos+=bfontlen(curr) *sc;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int Graphics::len(std::string t)
|
|
|
|
{
|
|
|
|
int bfontpos = 0;
|
2020-01-31 19:25:37 +01:00
|
|
|
std::string::iterator iter = t.begin();
|
|
|
|
while (iter != t.end()) {
|
|
|
|
int cur = utf8::unchecked::next(iter);
|
|
|
|
bfontpos += bfontlen(cur);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
return bfontpos;
|
|
|
|
}
|
|
|
|
|
2020-02-10 03:23:12 +01:00
|
|
|
void Graphics::PrintOff( int _x, int _y, std::string _s, int r, int g, int b, bool cen /*= false*/ ) {
|
|
|
|
PrintOffAlpha(_x,_y,_s,r,g,b,255,cen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::PrintOffAlpha( int _x, int _y, std::string _s, int r, int g, int b, int a, bool cen /*= false*/ )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-14 03:46:32 +02:00
|
|
|
std::vector<SDL_Surface*>& font = flipmode ? flipbfont : bfont;
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
r = clamp(r,0,255);
|
|
|
|
g = clamp(g,0,255);
|
|
|
|
b = clamp(b,0,255);
|
2020-02-10 03:23:12 +01:00
|
|
|
a = clamp(a,0,255);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
ct.colour = getRGB(r, g, b);
|
|
|
|
|
|
|
|
if (cen)
|
|
|
|
_x = ((160) - (len(_s) / 2))+_x;
|
|
|
|
int bfontpos = 0;
|
2020-06-14 03:56:59 +02:00
|
|
|
int idx;
|
2020-01-31 19:25:37 +01:00
|
|
|
std::string::iterator iter = _s.begin();
|
|
|
|
while (iter != _s.end()) {
|
|
|
|
int curr = utf8::unchecked::next(iter);
|
2020-01-01 21:29:24 +01:00
|
|
|
point tpoint;
|
|
|
|
tpoint.x = _x + bfontpos;
|
|
|
|
tpoint.y = _y;
|
|
|
|
|
|
|
|
SDL_Rect fontRect = bfont_rect;
|
|
|
|
fontRect.x = tpoint.x ;
|
|
|
|
fontRect.y = tpoint.y ;
|
|
|
|
|
2020-06-14 03:56:59 +02:00
|
|
|
idx = font_idx(curr);
|
|
|
|
if (INBOUNDS(idx, font))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured( font[idx], NULL, backBuffer, &fontRect , ct);
|
|
|
|
}
|
2020-01-31 19:25:37 +01:00
|
|
|
bfontpos+=bfontlen(curr) ;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-10 03:23:12 +01:00
|
|
|
void Graphics::bprint( int x, int y, std::string t, int r, int g, int b, bool cen /*= false*/ ) {
|
|
|
|
bprintalpha(x,y,t,r,g,b,255,cen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::bprintalpha( int x, int y, 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)
|
|
|
|
{
|
2020-02-10 03:23:12 +01:00
|
|
|
PrintOffAlpha(-1, y, t, 0, 0, 0, a, cen);
|
|
|
|
PrintOffAlpha(1, y, t, 0, 0, 0, a, cen);
|
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::RPrint( int _x, int _y, std::string _s, int r, int g, int b, bool cen /*= false*/ )
|
|
|
|
{
|
2020-06-14 03:46:32 +02:00
|
|
|
std::vector<SDL_Surface*>& font = flipmode ? flipbfont : bfont;
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
r = clamp(r,0,255);
|
|
|
|
g = clamp(g,0,255);
|
|
|
|
b = clamp(b,0,255);
|
|
|
|
ct.colour = getRGB(r, g, b);
|
|
|
|
|
|
|
|
if (cen)
|
|
|
|
_x = ((308) - (_s.length() / 2));
|
|
|
|
int bfontpos = 0;
|
|
|
|
int curr;
|
2020-06-14 03:56:59 +02:00
|
|
|
int idx;
|
2020-01-31 19:25:37 +01:00
|
|
|
std::string::iterator iter = _s.begin();
|
|
|
|
while (iter != _s.end()) {
|
|
|
|
curr = utf8::unchecked::next(iter);
|
2020-01-01 21:29:24 +01:00
|
|
|
point tpoint;
|
|
|
|
tpoint.x = _x + bfontpos;
|
|
|
|
tpoint.y = _y;
|
|
|
|
|
|
|
|
SDL_Rect fontRect = bfont_rect;
|
|
|
|
fontRect.x = tpoint.x ;
|
|
|
|
fontRect.y = tpoint.y ;
|
|
|
|
|
2020-06-14 03:56:59 +02:00
|
|
|
idx = font_idx(curr);
|
|
|
|
if (INBOUNDS(idx, font))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured( font[idx], NULL, backBuffer, &fontRect , ct);
|
|
|
|
}
|
2020-01-31 19:25:37 +01:00
|
|
|
bfontpos+=bfontlen(curr) ;
|
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:
|
|
|
|
Print(x, y, "Viridian", 16, 240, 240,false );
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
Print(x, y, "Violet", 240, 16, 240,false);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Print(x, y, "Vitellary", 240, 240, 16,false);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
Print(x, y, "Vermilion", 240, 16, 16,false);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
Print(x, y, "Verdigris", 16, 240, 16,false);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
Print(x, y, "Victoria", 16, 16, 240,false);
|
|
|
|
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:
|
|
|
|
Print(x, y, "Viridian", 128,128,128,false);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
Print(x, y, "Violet", 128,128,128,false);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Print(x, y, "Vitellary", 128,128,128,false);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
Print(x, y, "Vermilion", 128,128,128,false);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
Print(x, y, "Verdigris", 128,128,128,false);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
Print(x, y, "Victoria", 128,128,128,false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::printcrewnamestatus( int x, int y, int t )
|
|
|
|
{
|
|
|
|
//Print the status of crew member t in the right colour
|
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
Print(x, y, "(that's you!)", 12, 140, 140,false);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
Print(x, y, "Rescued!", 140, 12, 140,false);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Print(x, y, "Rescued!", 140, 140, 12,false);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
Print(x, y, "Rescued!", 140, 12, 12,false);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
Print(x, y, "Rescued!", 12, 140, 12,false);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
Print(x, y, "Rescued!", 12, 12, 140,false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawsprite( int x, int y, int t, int r, int g, int b )
|
|
|
|
{
|
|
|
|
SDL_Rect rect = { Sint16(x), Sint16(y), sprites_rect.w, sprites_rect.h };
|
|
|
|
setcolreal(getRGB(r,g,b));
|
|
|
|
BlitSurfaceColoured(sprites[t], NULL, backBuffer, &rect, ct);
|
|
|
|
}
|
|
|
|
|
2020-05-02 01:40:35 +02:00
|
|
|
void Graphics::drawsprite(int x, int y, int t, Uint32 c)
|
|
|
|
{
|
|
|
|
SDL_Rect rect = { Sint16(x), Sint16(y), sprites_rect.w, sprites_rect.h };
|
|
|
|
setcolreal(c);
|
|
|
|
BlitSurfaceColoured(sprites[t], NULL, backBuffer, &rect, ct);
|
|
|
|
}
|
|
|
|
|
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-06-14 03:37:18 +02:00
|
|
|
if (!INBOUNDS(t, tiles))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-06-30 20:47:22 +02:00
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect rect = { Sint16(x), Sint16(y), tiles_rect.w, tiles_rect.h };
|
2020-06-30 20:47:22 +02:00
|
|
|
|
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
2020-06-30 23:08:14 +02:00
|
|
|
if (t >= 14 && t <= 17 && (!FILESYSTEM_assetsmounted || ed.onewaycol_override))
|
2020-06-30 20:47:22 +02:00
|
|
|
{
|
|
|
|
colourTransform thect = {ed.getonewaycol()};
|
|
|
|
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-06-14 03:37:18 +02:00
|
|
|
if (!INBOUNDS(t, tiles2))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-06-30 20:47:22 +02:00
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect rect = { Sint16(x), Sint16(y), tiles_rect.w, tiles_rect.h };
|
2020-06-30 20:47:22 +02:00
|
|
|
|
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
2020-06-30 23:08:14 +02:00
|
|
|
if (t >= 14 && t <= 17 && (!FILESYSTEM_assetsmounted || ed.onewaycol_override))
|
2020-06-30 20:47:22 +02:00
|
|
|
{
|
|
|
|
colourTransform thect = {ed.getonewaycol()};
|
|
|
|
BlitSurfaceTinted(tiles2[t], NULL, backBuffer, &rect, thect);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
BlitSurfaceStandard(tiles2[t], NULL, backBuffer, &rect);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Graphics::drawtile3( int x, int y, int t, int off )
|
|
|
|
{
|
2020-06-14 03:37:18 +02:00
|
|
|
if (!INBOUNDS(t, tiles3))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect rect = { Sint16(x), Sint16(y), tiles_rect.w, tiles_rect.h };
|
|
|
|
BlitSurfaceStandard(tiles3[t+(off*30)], NULL, backBuffer, &rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawentcolours( int x, int y, int t)
|
|
|
|
{
|
2020-06-14 03:37:18 +02:00
|
|
|
if (!INBOUNDS(t, entcolours))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect rect = { Sint16(x), Sint16(y), tiles_rect.w, tiles_rect.h };
|
|
|
|
BlitSurfaceStandard(entcolours[t], NULL, backBuffer, &rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawtowertile( int x, int y, int t )
|
|
|
|
{
|
2020-06-14 03:37:18 +02:00
|
|
|
if (!INBOUNDS(t, tiles2))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect rect = { Sint16(x), Sint16(y), tiles_rect.w, tiles_rect.h };
|
|
|
|
BlitSurfaceStandard(tiles2[t], NULL, towerbuffer, &rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Graphics::drawtowertile3( int x, int y, int t, int off )
|
|
|
|
{
|
2020-06-14 03:37:18 +02:00
|
|
|
t += off*30;
|
|
|
|
if (!INBOUNDS(t, tiles3))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect rect = { Sint16(x), Sint16(y), tiles_rect.w, tiles_rect.h };
|
2020-06-14 03:37:18 +02:00
|
|
|
BlitSurfaceStandard(tiles3[t], NULL, towerbuffer, &rect);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawgui()
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Draw all the textboxes to the screen
|
2020-04-04 02:25:17 +02:00
|
|
|
for (size_t i = 0; i<textbox.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-29 06:49:15 +02:00
|
|
|
//This routine also updates textbox colors
|
|
|
|
float tl_lerp = lerp(textbox[i].prev_tl, textbox[i].tl);
|
|
|
|
textbox[i].setcol(textbox[i].tr * tl_lerp, textbox[i].tg * tl_lerp, textbox[i].tb * tl_lerp);
|
|
|
|
|
2020-04-04 02:26:29 +02:00
|
|
|
if (textbox[i].r == 0 && textbox[i].g == 0 && textbox[i].b == 0)
|
|
|
|
{
|
|
|
|
if(flipmode)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-14 20:21:32 +02:00
|
|
|
for (size_t j = 0; j < textbox[i].line.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:41:01 +02:00
|
|
|
Print(textbox[i].xp + 8, textbox[i].yp + (textbox[i].line.size()*8) - (j * 8), textbox[i].line[j], 196, 196, 255 - help.glow);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-06-14 20:21:32 +02:00
|
|
|
for (size_t j = 0; j < textbox[i].line.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:26:29 +02:00
|
|
|
Print(textbox[i].xp + 8, textbox[i].yp + 8 + (j * 8), textbox[i].line[j], 196, 196, 255 - help.glow);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-04 02:26:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-04 02:26:29 +02:00
|
|
|
FillRect(backBuffer,textbox[i].textrect, textbox[i].r/6, textbox[i].g/6, textbox[i].b / 6 );
|
|
|
|
|
|
|
|
drawcoloredtile(textbox[i].xp, textbox[i].yp, 40, textbox[i].r, textbox[i].g, textbox[i].b);
|
|
|
|
drawcoloredtile(textbox[i].xp+textbox[i].w-8, textbox[i].yp, 42, textbox[i].r, textbox[i].g, textbox[i].b);
|
|
|
|
drawcoloredtile(textbox[i].xp, textbox[i].yp+textbox[i].h-8, 45, textbox[i].r, textbox[i].g, textbox[i].b);
|
|
|
|
drawcoloredtile(textbox[i].xp+textbox[i].w-8, textbox[i].yp+textbox[i].h-8, 47, textbox[i].r, textbox[i].g, textbox[i].b);
|
|
|
|
for (int k = 0; k < textbox[i].lw; k++)
|
|
|
|
{
|
|
|
|
drawcoloredtile(textbox[i].xp + 8 + (k * 8), textbox[i].yp, 41, textbox[i].r, textbox[i].g, textbox[i].b);
|
|
|
|
drawcoloredtile(textbox[i].xp + 8 + (k * 8), textbox[i].yp+textbox[i].h-8, 46, textbox[i].r, textbox[i].g, textbox[i].b);
|
|
|
|
}
|
2020-04-04 02:41:01 +02:00
|
|
|
for (size_t k = 0; k < textbox[i].line.size(); k++)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
drawcoloredtile(textbox[i].xp, textbox[i].yp + 8 + (k * 8), 43, textbox[i].r, textbox[i].g, textbox[i].b);
|
|
|
|
drawcoloredtile(textbox[i].xp + textbox[i].w-8, textbox[i].yp + 8 + (k * 8), 44, textbox[i].r, textbox[i].g, textbox[i].b);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-04 02:26:29 +02:00
|
|
|
if(flipmode)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-14 20:21:32 +02:00
|
|
|
for (size_t j = 0; j < textbox[i].line.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:41:01 +02:00
|
|
|
Print(textbox[i].xp + 8, textbox[i].yp + (textbox[i].line.size()*8) - (j * 8), textbox[i].line[j], textbox[i].r, textbox[i].g, textbox[i].b);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-04 02:26:29 +02:00
|
|
|
else
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-14 20:21:32 +02:00
|
|
|
for (size_t j = 0; j < textbox[i].line.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:26:29 +02:00
|
|
|
Print(textbox[i].xp + 8, textbox[i].yp +8 + (j * 8), textbox[i].line[j], textbox[i].r, textbox[i].g, textbox[i].b);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-04 02:26:29 +02:00
|
|
|
}
|
|
|
|
|
2020-04-30 08:46:50 +02:00
|
|
|
if ((textbox[i].yp == 12 || textbox[i].yp == 180) && textbox[i].r == 165 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
2020-01-01 21:29:24 +01:00
|
|
|
if (flipmode)
|
|
|
|
{
|
2020-04-04 02:26:29 +02:00
|
|
|
drawimage(5, 0, 180, true);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-04 02:26:29 +02:00
|
|
|
drawimage(0, 0, 12, true);
|
|
|
|
}
|
|
|
|
}
|
2020-04-30 08:46:50 +02:00
|
|
|
else if ((textbox[i].yp == 12 || textbox[i].yp == 180) && textbox[i].g == 165 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
if (flipmode)
|
|
|
|
{
|
|
|
|
drawimage(6, 0, 180, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
drawimage(4, 0, 12, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (flipmode)
|
|
|
|
{
|
2020-04-30 08:46:50 +02:00
|
|
|
if (textbox[i].r == 175 && textbox[i].g == 175 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
//purple guy
|
|
|
|
drawsprite(80 - 6, 64 + 48 + 4, 6, 220- help.glow/4 - int(fRandom()*20), 120- help.glow/4, 210 - help.glow/4);
|
|
|
|
}
|
2020-04-30 08:46:50 +02:00
|
|
|
else if (textbox[i].r == 175 && textbox[i].b == 175 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
//red guy
|
|
|
|
drawsprite(80 - 6, 64 + 48+ 4, 6, 255 - help.glow/8, 70 - help.glow/4, 70 - help.glow / 4);
|
|
|
|
}
|
2020-04-30 08:46:50 +02:00
|
|
|
else if (textbox[i].r == 175 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
//green guy
|
|
|
|
drawsprite(80 - 6, 64 + 48 + 4, 6, 120 - help.glow / 4 - int(fRandom() * 20), 220 - help.glow / 4, 120 - help.glow / 4);
|
|
|
|
}
|
2020-04-30 08:46:50 +02:00
|
|
|
else if (textbox[i].g == 175 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
//yellow guy
|
|
|
|
drawsprite(80 - 6, 64 + 48+ 4, 6, 220- help.glow/4 - int(fRandom()*20), 210 - help.glow/4, 120- help.glow/4);
|
|
|
|
}
|
2020-04-30 08:46:50 +02:00
|
|
|
else if (textbox[i].b == 175 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
//blue guy
|
|
|
|
drawsprite(80 - 6, 64 + 48+ 4, 6, 75, 75, 255- help.glow/4 - int(fRandom()*20));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-30 08:46:50 +02:00
|
|
|
if (textbox[i].r == 175 && textbox[i].g == 175 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
//purple guy
|
|
|
|
drawsprite(80 - 6, 64 + 32 + 4, 0, 220- help.glow/4 - int(fRandom()*20), 120- help.glow/4, 210 - help.glow/4);
|
|
|
|
}
|
2020-04-30 08:46:50 +02:00
|
|
|
else if (textbox[i].r == 175 && textbox[i].b == 175 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
//red guy
|
|
|
|
drawsprite(80 - 6, 64 + 32 + 4, 0, 255 - help.glow/8, 70 - help.glow/4, 70 - help.glow / 4);
|
|
|
|
}
|
2020-04-30 08:46:50 +02:00
|
|
|
else if (textbox[i].r == 175 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
//green guy
|
|
|
|
drawsprite(80 - 6, 64 + 32 + 4, 0, 120 - help.glow / 4 - int(fRandom() * 20), 220 - help.glow / 4, 120 - help.glow / 4);
|
|
|
|
}
|
2020-04-30 08:46:50 +02:00
|
|
|
else if (textbox[i].g == 175 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
//yellow guy
|
|
|
|
drawsprite(80 - 6, 64 + 32 + 4, 0, 220- help.glow/4 - int(fRandom()*20), 210 - help.glow/4, 120- help.glow/4);
|
|
|
|
}
|
2020-04-30 08:46:50 +02:00
|
|
|
else if (textbox[i].b == 175 && textbox[i].allowspecial)
|
2020-04-04 02:26:29 +02:00
|
|
|
{
|
|
|
|
//blue guy
|
|
|
|
drawsprite(80 - 6, 64 + 32 + 4, 0, 75, 75, 255- help.glow/4 - int(fRandom()*20));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-29 03:38:43 +02:00
|
|
|
void Graphics::updatetextboxes()
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < textbox.size(); i++)
|
|
|
|
{
|
|
|
|
textbox[i].update();
|
|
|
|
|
|
|
|
if (textbox[i].tm == 2 && textbox[i].tl <= 0.5)
|
|
|
|
{
|
|
|
|
textbox.erase(textbox.begin() + i);
|
|
|
|
i--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
void Graphics::drawimagecol( int t, int xp, int yp, int r = 0, int g = 0, int b = 0, bool cent/*= false*/ )
|
|
|
|
{
|
2020-06-14 03:37:53 +02:00
|
|
|
if (!INBOUNDS(t, images))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect trect;
|
2020-04-02 22:05:48 +02:00
|
|
|
if(r+g+b != 0)
|
|
|
|
{
|
|
|
|
RGBf(r,g,b);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
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*/ )
|
|
|
|
{
|
2020-06-14 03:37:53 +02:00
|
|
|
if (!INBOUNDS(t, images))
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2020-06-14 03:37:53 +02:00
|
|
|
if (!INBOUNDS(t, images))
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::cutscenebars()
|
|
|
|
{
|
2020-04-29 02:16:24 +02:00
|
|
|
int usethispos = lerp(oldcutscenebarspos, cutscenebarspos);
|
2020-01-01 21:29:24 +01:00
|
|
|
if (showcutscenebars)
|
|
|
|
{
|
2020-04-29 02:16:24 +02:00
|
|
|
FillRect(backBuffer, 0, 0, usethispos, 16, 0x000000);
|
|
|
|
FillRect(backBuffer, 360-usethispos, 224, usethispos, 16, 0x000000);
|
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
|
|
|
|
FillRect(backBuffer, 0, 0, usethispos, 16, 0x000000);
|
|
|
|
FillRect(backBuffer, 360-usethispos, 224, usethispos, 16, 0x000000);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-29 02:11:02 +02:00
|
|
|
void Graphics::cutscenebarstimer()
|
|
|
|
{
|
2020-04-29 02:16:24 +02:00
|
|
|
oldcutscenebarspos = cutscenebarspos;
|
2020-04-29 02:11:02 +02:00
|
|
|
if (showcutscenebars)
|
|
|
|
{
|
|
|
|
cutscenebarspos += 25;
|
|
|
|
cutscenebarspos = std::min(cutscenebarspos, 361);
|
|
|
|
}
|
|
|
|
else if (cutscenebarspos > 0)
|
|
|
|
{
|
|
|
|
//disappearing
|
|
|
|
cutscenebarspos -= 25;
|
|
|
|
cutscenebarspos = std::max(cutscenebarspos, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawpixeltextbox( int x, int y, int w, int h, int w2, int h2, int r, int g, int b, int xo, int yo )
|
|
|
|
{
|
|
|
|
//given these parameters, draw a textbox with a pixel width
|
|
|
|
|
|
|
|
//madrect.x = x; madrect.y = y; madrect.w = w; madrect.h = h;
|
|
|
|
FillRect(backBuffer,x,y,w,h, r/6, g/6, b/6 );
|
|
|
|
|
2020-06-14 20:21:32 +02:00
|
|
|
for (int k = 0; k < w2-2; k++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
drawcoloredtile(x + 8-xo + (k * 8), y, 41, r, g, b);
|
|
|
|
drawcoloredtile(x + 8-xo + (k * 8), y + (h) - 8, 46, r, g, b);
|
|
|
|
}
|
|
|
|
|
2020-06-14 20:21:32 +02:00
|
|
|
for (int k = 0; k < h2-2; k++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
drawcoloredtile(x, y + 8-yo + (k * 8), 43, r, g, b);
|
|
|
|
drawcoloredtile(x + (w) - 8, y + 8-yo + (k * 8), 44, r, g, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
drawcoloredtile(x, y, 40, r, g, b);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawcustompixeltextbox( int x, int y, int w, int h, int w2, int h2, int r, int g, int b, int xo, int yo )
|
|
|
|
{
|
|
|
|
//given these parameters, draw a textbox with a pixel width
|
|
|
|
|
|
|
|
FillRect(backBuffer,x,y,w,h, r/6, g/6, b/6 );
|
|
|
|
|
2020-06-14 20:21:32 +02:00
|
|
|
for (int k = 0; k < w2-2; k++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
drawcoloredtile(x + 8-xo + (k * 8), y, 41, r, g, b);
|
|
|
|
drawcoloredtile(x + 8-xo + (k * 8), y + (h) - 8, 46, r, g, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
drawcoloredtile(x+ (w) - 16, y, 41, r, g, b);
|
|
|
|
drawcoloredtile(x+ (w) - 16, y + (h) - 8, 46, r, g, b);
|
|
|
|
drawcoloredtile(x+ (w) - 24, y, 41, r, g, b);
|
|
|
|
drawcoloredtile(x+ (w) - 24, y + (h) - 8, 46, r, g, b);
|
|
|
|
|
2020-06-14 20:21:32 +02:00
|
|
|
for (int k = 0; k < h2-2; k++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
drawcoloredtile(x, y + 8-yo + (k * 8), 43, r, g, b);
|
|
|
|
drawcoloredtile(x + (w) - 8, y + 8-yo + (k * 8), 44, r, g, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
drawcoloredtile(x, y + (h) - 16, 43, r, g, b);
|
|
|
|
drawcoloredtile(x + (w) - 8, y + (h) - 16, 44, r, g, b);
|
|
|
|
drawcoloredtile(x, y + (h) - 24, 43, r, g, b);
|
|
|
|
drawcoloredtile(x + (w) - 8, y + (h) - 24, 44, r, g, b);
|
|
|
|
|
|
|
|
drawcoloredtile(x, y, 40, r, g, b);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawtextbox( int x, int y, int w, int h, int r, int g, int b )
|
|
|
|
{
|
|
|
|
//given these parameters, draw a textbox
|
|
|
|
FillRect(backBuffer,x,y,w*8,h*8, r/6, g/6, b/6 );
|
|
|
|
|
|
|
|
drawcoloredtile(x, y, 40, r, g, b);
|
|
|
|
drawcoloredtile(x + (w*8) - 8, y, 42, r, g, b);
|
|
|
|
drawcoloredtile(x, y + (h*8) - 8, 45, r, g, b);
|
|
|
|
drawcoloredtile(x + (w*8) - 8, y + (h*8) - 8, 47, r, g, b);
|
|
|
|
|
|
|
|
for (int k = 0; k < w-2; k++)
|
|
|
|
{
|
|
|
|
drawcoloredtile(x + 8 + (k * 8), y, 41, r, g, b);
|
|
|
|
drawcoloredtile(x + 8 + (k * 8), y + (h * 8) - 8, 46, r, g, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int k = 0; k < h-2; k++)
|
|
|
|
{
|
|
|
|
drawcoloredtile(x, y + 8 + (k * 8), 43, r, g, b);
|
|
|
|
drawcoloredtile(x + (w * 8) - 8, y + 8 + (k * 8), 44, r, g, b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxactive()
|
|
|
|
{
|
|
|
|
//Remove all but the most recent textbox
|
2020-04-04 02:25:17 +02:00
|
|
|
for (int i = 0; i < (int) textbox.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (m != i) textbox[i].remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxremovefast()
|
|
|
|
{
|
|
|
|
//Remove all textboxes
|
2020-04-04 02:25:17 +02:00
|
|
|
for (size_t i = 0; i < textbox.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
textbox[i].removefast();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxremove()
|
|
|
|
{
|
|
|
|
//Remove all textboxes
|
2020-04-04 02:25:17 +02:00
|
|
|
for (size_t i = 0; i < textbox.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
textbox[i].remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxtimer( int t )
|
|
|
|
{
|
2020-06-28 19:40:58 +02:00
|
|
|
if (!INBOUNDS(m, textbox))
|
|
|
|
{
|
2020-06-28 21:43:12 +02:00
|
|
|
puts("textboxtimer() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
textbox[m].timer=t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::addline( std::string t )
|
|
|
|
{
|
2020-06-28 19:40:58 +02:00
|
|
|
if (!INBOUNDS(m, textbox))
|
|
|
|
{
|
2020-06-28 21:43:12 +02:00
|
|
|
puts("addline() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
textbox[m].addline(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxadjust()
|
|
|
|
{
|
2020-06-28 19:40:58 +02:00
|
|
|
if (!INBOUNDS(m, textbox))
|
|
|
|
{
|
2020-06-28 21:43:12 +02:00
|
|
|
puts("textboxadjust() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
textbox[m].adjust();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-30 08:46:50 +02:00
|
|
|
void Graphics::createtextbox( std::string t, int xp, int yp, int r/*= 255*/, int g/*= 255*/, int b /*= 255*/, bool allowspecial/*= false*/ )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:25:17 +02:00
|
|
|
m = textbox.size();
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if(m<20)
|
|
|
|
{
|
2020-04-04 02:25:17 +02:00
|
|
|
textboxclass text;
|
2020-04-04 02:41:01 +02:00
|
|
|
text.line.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);
|
|
|
|
text.resize();
|
2020-04-30 08:46:50 +02:00
|
|
|
text.allowspecial = allowspecial;
|
2020-04-04 02:25:17 +02:00
|
|
|
textbox.push_back(text);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawfade()
|
|
|
|
{
|
2020-04-29 03:10:40 +02:00
|
|
|
int usethisamount = lerp(oldfadeamount, fadeamount);
|
2020-01-01 21:29:24 +01:00
|
|
|
if ((fademode == 1)||(fademode == 4))
|
|
|
|
{
|
|
|
|
FillRect(backBuffer, 0, 0, backBuffer->w, backBuffer->h, 0x000000);
|
|
|
|
}
|
|
|
|
else if(fademode==3)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 15; i++)
|
|
|
|
{
|
2020-04-29 03:10:40 +02:00
|
|
|
FillRect(backBuffer, fadebars[i], i * 16, usethisamount, 16, 0x000000 );
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(fademode==5 )
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 15; i++)
|
|
|
|
{
|
2020-04-29 03:10:40 +02:00
|
|
|
FillRect(backBuffer, fadebars[i]-usethisamount, i * 16, 500, 16, 0x000000 );
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::processfade()
|
|
|
|
{
|
2020-04-29 03:10:40 +02:00
|
|
|
oldfadeamount = fadeamount;
|
2020-01-01 21:29:24 +01:00
|
|
|
if (fademode > 1)
|
|
|
|
{
|
|
|
|
if (fademode == 2)
|
|
|
|
{
|
|
|
|
//prepare fade out
|
|
|
|
for (int i = 0; i < 15; i++)
|
|
|
|
{
|
|
|
|
fadebars[i] = -int(fRandom() * 12) * 8;
|
|
|
|
}
|
|
|
|
fadeamount = 0;
|
|
|
|
fademode = 3;
|
|
|
|
}
|
|
|
|
else if (fademode == 3)
|
|
|
|
{
|
|
|
|
fadeamount += 24;
|
|
|
|
if (fadeamount > 416)
|
|
|
|
{
|
|
|
|
fademode = 1; //faded
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (fademode == 4)
|
|
|
|
{
|
|
|
|
//prepare fade in
|
|
|
|
for (int i = 0; i < 15; i++)
|
|
|
|
{
|
|
|
|
fadebars[i] = 320 + int(fRandom() * 12) * 8;
|
|
|
|
}
|
|
|
|
fadeamount = 416;
|
|
|
|
fademode = 5;
|
|
|
|
}
|
|
|
|
else if (fademode == 5)
|
|
|
|
{
|
|
|
|
fadeamount -= 24;
|
|
|
|
if (fadeamount <= 0)
|
|
|
|
{
|
|
|
|
fademode = 0; //normal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
void Graphics::drawmenu( int cr, int cg, int cb )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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
|
|
|
{
|
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
|
|
|
if ((int) i == game.currentmenuoption)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Draw it highlighted
|
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
|
|
|
if (game.menuoptions[i].active)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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
|
|
|
std::string tempstring = game.menuoptions[i].text;
|
2020-01-01 21:29:24 +01:00
|
|
|
std::transform(tempstring.begin(), tempstring.end(),tempstring.begin(), ::toupper);
|
|
|
|
tempstring = std::string("[ ") + tempstring + std::string(" ]");
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) - 16 +game.menuxoff, 140 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
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
|
|
|
std::string tempstring = game.menuoptions[i].text;
|
2020-01-01 21:29:24 +01:00
|
|
|
tempstring = "[ " + tempstring + " ]";
|
|
|
|
//Draw it in gray
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) - 16 +game.menuxoff, 140 + (i * 12)+game.menuyoff, tempstring, 128, 128, 128);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Draw it normally
|
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
|
|
|
if (game.menuoptions[i].active)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) +game.menuxoff, 140 + (i * 12)+game.menuyoff, game.menuoptions[i].text, cr, cg, cb);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Draw it in gray
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) +game.menuxoff, 140 + (i * 12)+game.menuyoff, game.menuoptions[i].text, 128, 128, 128);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
void Graphics::drawlevelmenu( int cr, int cg, int cb )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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
|
|
|
{
|
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
|
|
|
if ((int) i == game.currentmenuoption)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-17 08:05:49 +02:00
|
|
|
if(game.menuoptions.size()-i<=3){
|
2020-01-01 21:29:24 +01:00
|
|
|
//Draw it highlighted
|
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
|
|
|
if (game.menuoptions[i].active)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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
|
|
|
std::string tempstring = game.menuoptions[i].text;
|
2020-01-01 21:29:24 +01:00
|
|
|
std::transform(tempstring.begin(), tempstring.end(),tempstring.begin(), ::toupper);
|
|
|
|
tempstring = std::string("[ ") + tempstring + std::string(" ]");
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) - 16 +game.menuxoff, 140+8 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
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
|
|
|
std::string tempstring = game.menuoptions[i].text;
|
2020-01-01 21:29:24 +01:00
|
|
|
tempstring = "[ " + tempstring + " ]";
|
|
|
|
//Draw it in gray
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) - 16 +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, tempstring, 128, 128, 128);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}else{
|
|
|
|
//Draw it highlighted
|
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
|
|
|
if (game.menuoptions[i].active)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
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
|
|
|
std::string tempstring = game.menuoptions[i].text;
|
2020-01-01 21:29:24 +01:00
|
|
|
std::transform(tempstring.begin(), tempstring.end(),tempstring.begin(), ::toupper);
|
|
|
|
tempstring = std::string("[ ") + tempstring + std::string(" ]");
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) - 16 +game.menuxoff, 144 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
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
|
|
|
std::string tempstring = game.menuoptions[i].text;
|
2020-01-01 21:29:24 +01:00
|
|
|
tempstring = "[ " + tempstring + " ]";
|
|
|
|
//Draw it in gray
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) - 16 +game.menuxoff, 144 + (i * 12)+game.menuyoff, tempstring, 128, 128, 128);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-17 08:05:49 +02:00
|
|
|
if(game.menuoptions.size()-i<=3){
|
2020-01-01 21:29:24 +01:00
|
|
|
//Draw it normally
|
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
|
|
|
if (game.menuoptions[i].active)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, game.menuoptions[i].text, cr, cg, cb);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Draw it in gray
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, game.menuoptions[i].text, 128, 128, 128);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}else{
|
|
|
|
//Draw it normally
|
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
|
|
|
if (game.menuoptions[i].active)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) +game.menuxoff, 144 + (i * 12)+game.menuyoff, game.menuoptions[i].text, cr, cg, cb);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Draw it in gray
|
Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.
This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.
Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110
The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.
The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
|
|
|
Print((i * game.menuspacing) +game.menuxoff, 144 + (i * 12)+game.menuyoff, game.menuoptions[i].text, 128, 128, 128);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Graphics::drawcoloredtile( int x, int y, int t, int r, int g, int b )
|
|
|
|
{
|
2020-06-14 03:37:18 +02:00
|
|
|
if (!INBOUNDS(t, tiles))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
setcolreal(getRGB(r,g,b));
|
|
|
|
|
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect,x,y,tiles_rect.w,tiles_rect.h);
|
|
|
|
BlitSurfaceColoured(tiles[t],NULL, backBuffer, &rect, ct );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
bool intersection = intersectRect(r1_left, r1_right, r1_bottom, r1_top, r2_left, r2_right, r2_bottom, r2_top);
|
|
|
|
|
|
|
|
if(intersection)
|
|
|
|
{
|
|
|
|
int r3_left = std::max(r1_left, r2_left);
|
|
|
|
int r3_top = std::min(r1_top, r2_top);
|
|
|
|
int r3_right = std::min(r1_right, r2_right);
|
|
|
|
int r3_bottom= std::max(r1_bottom, r2_bottom);
|
|
|
|
|
|
|
|
//for every pixel inside rectangle
|
|
|
|
for(int x = r3_left; x < r3_right; x++)
|
|
|
|
{
|
|
|
|
for(int y = r3_bottom; y < r3_top; y++)
|
|
|
|
{
|
|
|
|
Uint32 pixel1 = ReadPixel(surface1 , x - p1.x, y - p1.y);
|
|
|
|
Uint32 pixel2 = ReadPixel(surface2 , x - p2.x, y - p2.y);
|
|
|
|
if ((pixel1 & 0x000000FF) && (pixel2 & 0x000000FF))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawgravityline( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (obj.entities[t].life == 0)
|
|
|
|
{
|
|
|
|
switch(linestate)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(200-20, 200-20, 200-20));
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(225-30, 245-30, 245-30));
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(245-30, 245-30, 225-30));
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(164-10, 200-20, 200-20));
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(224-20, 255-30, 196-20));
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(205-20, 235-30, 196-20));
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(164-10, 164-10, 164-10));
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(225-30, 245-30, 205-20));
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(205-20, 255-30, 225-30));
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(245-30, 245-30, 245-30));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FillRect(backBuffer,line_rect, getRGB(96, 96, 96));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawtrophytext()
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
int temp, temp2, temp3;
|
|
|
|
|
|
|
|
if (obj.trophytext < 15)
|
|
|
|
{
|
2020-04-30 01:54:36 +02:00
|
|
|
int usethismult = lerp(obj.oldtrophytext, obj.trophytext);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
switch(obj.trophytype)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
Print( -1, 6, "SPACE STATION 1 MASTERED", temp, temp2, temp3, true);
|
|
|
|
Print( -1, 16, "Obtain a V Rank in this Time Trial", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Print( -1, 6, "LABORATORY MASTERED", temp, temp2, temp3, true);
|
|
|
|
Print( -1, 16, "Obtain a V Rank in this Time Trial", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
Print( -1, 6, "THE TOWER MASTERED", temp, temp2, temp3, true);
|
|
|
|
Print( -1, 16, "Obtain a V Rank in this Time Trial", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
Print( -1, 6, "SPACE STATION 2 MASTERED", temp, temp2, temp3, true);
|
|
|
|
Print( -1, 16, "Obtain a V Rank in this Time Trial", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
Print( -1, 6, "WARP ZONE MASTERED", temp, temp2, temp3, true);
|
|
|
|
Print( -1, 16, "Obtain a V Rank in this Time Trial", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
Print( -1, 6, "FINAL LEVEL MASTERED", temp, temp2, temp3, true);
|
|
|
|
Print( -1, 16, "Obtain a V Rank in this Time Trial", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
Print( -1, 6, "GAME COMPLETE", temp, temp2, temp3, true);
|
|
|
|
Print( -1, 16, "Complete the game", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
Print( -1, 6, "FLIP MODE COMPLETE", temp, temp2, temp3, true);
|
|
|
|
Print( -1, 16, "Complete the game in flip mode", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
Print( -1, 11, "Win with less than 50 deaths", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
Print( -1, 11, "Win with less than 100 deaths", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
Print( -1, 11, "Win with less than 250 deaths", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
Print( -1, 11, "Win with less than 500 deaths", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 13:
|
|
|
|
Print( -1, 11, "Last 5 seconds on the Super Gravitron", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
Print( -1, 11, "Last 10 seconds on the Super Gravitron", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
Print( -1, 11, "Last 15 seconds on the Super Gravitron", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
Print( -1, 11, "Last 20 seconds on the Super Gravitron", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 17:
|
|
|
|
Print( -1, 11, "Last 30 seconds on the Super Gravitron", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 18:
|
|
|
|
Print( -1, 11, "Last 1 minute on the Super Gravitron", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
case 20:
|
|
|
|
Print( -1, 6, "MASTER OF THE UNIVERSE", temp, temp2, temp3, true);
|
|
|
|
Print( -1, 16, "Complete the game in no death mode", temp, temp2, temp3, true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawentities()
|
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!
|
|
|
|
int room = game.roomx-100 + (game.roomy-100) * ed.maxwidth;
|
|
|
|
bool custom_gray = room >= 0 && room < 400
|
|
|
|
&& ed.level[room].tileset == 3 && ed.level[room].tilecol == 6;
|
|
|
|
#else
|
|
|
|
bool custom_gray = false;
|
|
|
|
#endif
|
|
|
|
|
2020-04-25 23:29:26 +02:00
|
|
|
std::vector<SDL_Surface*> *tilesvec;
|
2020-06-14 04:24:59 +02:00
|
|
|
if (map.custommode && !map.finalmode)
|
2020-04-25 23:29:26 +02:00
|
|
|
{
|
|
|
|
tilesvec = &entcolours;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tilesvec = &tiles;
|
|
|
|
}
|
|
|
|
|
2020-04-26 04:47:09 +02:00
|
|
|
std::vector<SDL_Surface*> *spritesvec;
|
|
|
|
if (flipmode)
|
|
|
|
{
|
|
|
|
spritesvec = &flipsprites;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spritesvec = &sprites;
|
|
|
|
}
|
|
|
|
|
2020-04-27 00:03:02 +02:00
|
|
|
int yoff;
|
|
|
|
if (map.towermode)
|
|
|
|
{
|
2020-04-30 20:52:21 +02:00
|
|
|
yoff = lerp(map.oldypos, map.ypos);
|
2020-04-27 00:03:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
yoff = 0;
|
|
|
|
}
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
for (int i = obj.entities.size() - 1; i >= 0; i--)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
if (obj.entities[i].invis)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
continue;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-29 01:02:55 +02:00
|
|
|
int xp = lerp(obj.entities[i].oldxp, obj.entities[i].xp);
|
|
|
|
int yp = lerp(obj.entities[i].oldyp, obj.entities[i].yp);
|
|
|
|
|
2020-04-26 21:30:58 +02:00
|
|
|
switch (obj.entities[i].size)
|
2020-04-26 20:13:47 +02:00
|
|
|
{
|
2020-04-26 21:30:58 +02:00
|
|
|
case 0:
|
2020-04-26 20:13:47 +02:00
|
|
|
// Sprites
|
2020-06-14 03:35:12 +02:00
|
|
|
if (!INBOUNDS(obj.entities[i].drawframe, (*spritesvec)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
setcolreal(obj.entities[i].realcol);
|
2020-04-26 20:13:47 +02:00
|
|
|
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
2020-04-27 00:03:02 +02:00
|
|
|
//screenwrapping!
|
|
|
|
if (map.warpx ||
|
|
|
|
(map.towermode && !map.minitowermode
|
|
|
|
&& map.ypos >= 500 && map.ypos <= 5000)) //The "wrapping" area of the tower
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
if (tpoint.x < 0)
|
2020-04-25 23:49:05 +02:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
tpoint.x += 320;
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
2020-04-25 23:49:05 +02:00
|
|
|
}
|
2020-04-26 20:17:53 +02:00
|
|
|
else if (tpoint.x > 300)
|
2020-04-25 23:42:37 +02:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
tpoint.x -= 320;
|
|
|
|
drawRect = sprites_rect;
|
2020-04-25 23:57:05 +02:00
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2020-04-26 20:13:47 +02:00
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
2020-04-25 23:42:37 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-26 20:13:47 +02:00
|
|
|
else if (map.warpy)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
if (tpoint.y < 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
tpoint.y += 230;
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-26 20:17:53 +02:00
|
|
|
else if (tpoint.y > 210)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
tpoint.y -= 230;
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-04-26 20:13:47 +02:00
|
|
|
// Tiles
|
2020-06-14 03:35:12 +02:00
|
|
|
if (!INBOUNDS(obj.entities[i].drawframe, tiles))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
2020-04-26 20:13:47 +02:00
|
|
|
drawRect = tiles_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceStandard(tiles[obj.entities[i].drawframe],NULL, backBuffer, &drawRect);
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 8:
|
2020-04-26 20:13:47 +02:00
|
|
|
{
|
|
|
|
// Special: Moving platform, 4 tiles or 8 tiles
|
2020-06-14 03:35:12 +02:00
|
|
|
if (!INBOUNDS(obj.entities[i].drawframe, (*tilesvec)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
2020-04-26 20:13:47 +02:00
|
|
|
int thiswidth = 4;
|
|
|
|
if (obj.entities[i].size == 8)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
thiswidth = 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-26 20:13:47 +02:00
|
|
|
for (int ii = 0; ii < thiswidth; ii++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
drawRect = tiles_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
drawRect.x += 8 * ii;
|
2020-06-30 00:27:23 +02:00
|
|
|
if (custom_gray)
|
|
|
|
{
|
|
|
|
colourTransform temp_ct;
|
|
|
|
temp_ct.colour = 0xFFFFFFFF;
|
|
|
|
BlitSurfaceTinted((*tilesvec)[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, temp_ct);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BlitSurfaceStandard((*tilesvec)[obj.entities[i].drawframe],NULL, backBuffer, &drawRect);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
2020-04-26 20:13:47 +02:00
|
|
|
}
|
2020-04-26 21:30:58 +02:00
|
|
|
case 3: // Big chunky pixels!
|
2020-04-29 01:02:55 +02:00
|
|
|
prect.x = xp;
|
|
|
|
prect.y = yp - yoff;
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
FillRect(backBuffer, prect, obj.entities[i].realcol);
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
case 4: // Small pickups
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
setcol(obj.entities[i].realcol);
|
2020-04-30 23:42:08 +02:00
|
|
|
drawhuetile(xp, yp - yoff, obj.entities[i].tile);
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
case 5: //Horizontal Line
|
2020-05-02 02:57:07 +02:00
|
|
|
{
|
|
|
|
int oldw = obj.entities[i].w;
|
2020-05-02 21:06:40 +02:00
|
|
|
if ((game.swngame == 3 || kludgeswnlinewidth) && obj.getlineat(84 - 32) == i)
|
2020-05-02 02:57:07 +02:00
|
|
|
{
|
|
|
|
oldw -= 24;
|
|
|
|
}
|
2020-04-29 01:02:55 +02:00
|
|
|
line_rect.x = xp;
|
|
|
|
line_rect.y = yp - yoff;
|
2020-05-02 02:57:07 +02:00
|
|
|
line_rect.w = lerp(oldw, obj.entities[i].w);
|
2020-04-26 20:13:47 +02:00
|
|
|
line_rect.h = 1;
|
|
|
|
drawgravityline(i);
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
2020-05-02 02:57:07 +02:00
|
|
|
}
|
2020-04-26 21:30:58 +02:00
|
|
|
case 6: //Vertical Line
|
2020-04-29 01:02:55 +02:00
|
|
|
line_rect.x = xp;
|
|
|
|
line_rect.y = yp - yoff;
|
2020-04-26 20:13:47 +02:00
|
|
|
line_rect.w = 1;
|
|
|
|
line_rect.h = obj.entities[i].h;
|
|
|
|
drawgravityline(i);
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
case 7: //Teleporter
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
drawtele(xp, yp - yoff, obj.entities[i].drawframe, obj.entities[i].realcol);
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
//case 8: // Special: Moving platform, 8 tiles
|
2020-04-26 20:13:47 +02:00
|
|
|
// Note: This code is in the 4-tile code
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
case 9: // Really Big Sprite! (2x2)
|
2020-06-14 03:35:12 +02:00
|
|
|
if (!INBOUNDS(obj.entities[i].drawframe, (*spritesvec)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
setcolreal(obj.entities[i].realcol);
|
2020-04-26 20:13:47 +02:00
|
|
|
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
2020-04-26 20:13:47 +02:00
|
|
|
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
|
|
|
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp+32;
|
|
|
|
tpoint.y = yp - yoff;
|
2020-04-26 20:13:47 +02:00
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe+1],NULL, backBuffer, &drawRect, ct);
|
|
|
|
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp+32 - yoff;
|
2020-04-26 20:13:47 +02:00
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe+12],NULL, backBuffer, &drawRect, ct);
|
|
|
|
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp+32;
|
|
|
|
tpoint.y = yp+32 - yoff;
|
2020-04-26 20:13:47 +02:00
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe + 13],NULL, backBuffer, &drawRect, ct);
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
case 10: // 2x1 Sprite
|
2020-06-14 03:35:12 +02:00
|
|
|
if (!INBOUNDS(obj.entities[i].drawframe, (*spritesvec)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
setcolreal(obj.entities[i].realcol);
|
2020-04-26 20:13:47 +02:00
|
|
|
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
2020-04-26 20:13:47 +02:00
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
|
|
|
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp+32;
|
|
|
|
tpoint.y = yp - yoff;
|
2020-04-26 20:13:47 +02:00
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe+1],NULL, backBuffer, &drawRect, ct);
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
case 11: //The fucking elephant
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
setcolreal(obj.entities[i].realcol);
|
2020-04-29 01:02:55 +02:00
|
|
|
drawimagecol(3, xp, yp - yoff);
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
case 12: // Regular sprites that don't wrap
|
2020-06-14 03:35:12 +02:00
|
|
|
if (!INBOUNDS(obj.entities[i].drawframe, (*spritesvec)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp;
|
|
|
|
tpoint.y = yp - yoff;
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
setcolreal(obj.entities[i].realcol);
|
2020-04-26 20:13:47 +02:00
|
|
|
//
|
|
|
|
drawRect = sprites_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured((*spritesvec)[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
|
2020-04-26 20:13:47 +02:00
|
|
|
//if we're outside the screen, we need to draw indicators
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-26 20:13:47 +02:00
|
|
|
if (obj.entities[i].xp < -20 && obj.entities[i].vx > 0)
|
|
|
|
{
|
|
|
|
if (obj.entities[i].xp < -100)
|
|
|
|
{
|
|
|
|
tpoint.x = -5 + (int(( -obj.entities[i].xp) / 10));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tpoint.x = 5;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-26 20:13:47 +02:00
|
|
|
tpoint.y = tpoint.y+4;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
|
2020-04-26 20:13:47 +02:00
|
|
|
drawRect = tiles_rect;
|
2020-04-26 04:50:09 +02:00
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
2020-04-26 20:13:47 +02:00
|
|
|
BlitSurfaceColoured(tiles[1167],NULL, backBuffer, &drawRect, ct);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
}
|
2020-04-26 20:13:47 +02:00
|
|
|
else if (obj.entities[i].xp > 340 && obj.entities[i].vx < 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
if (obj.entities[i].xp > 420)
|
2020-04-26 04:50:09 +02:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
tpoint.x = 320 - (int(( obj.entities[i].xp-320) / 10));
|
2020-04-26 04:50:09 +02:00
|
|
|
}
|
2020-04-26 20:13:47 +02:00
|
|
|
else
|
2020-04-26 04:50:09 +02:00
|
|
|
{
|
2020-04-26 20:13:47 +02:00
|
|
|
tpoint.x = 310;
|
2020-04-26 04:50:09 +02:00
|
|
|
}
|
2020-04-26 20:13:47 +02:00
|
|
|
|
|
|
|
tpoint.y = tpoint.y+4;
|
|
|
|
//
|
|
|
|
|
|
|
|
drawRect = tiles_rect;
|
|
|
|
drawRect.x += tpoint.x;
|
|
|
|
drawRect.y += tpoint.y;
|
|
|
|
BlitSurfaceColoured(tiles[1166],NULL, backBuffer, &drawRect, ct);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-26 21:30:58 +02:00
|
|
|
break;
|
|
|
|
case 13:
|
2020-04-26 20:13:47 +02:00
|
|
|
{
|
|
|
|
//Special for epilogue: huge hero!
|
2020-06-14 03:35:12 +02:00
|
|
|
if (!INBOUNDS(obj.entities[i].drawframe, (*spritesvec)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-26 04:50:09 +02:00
|
|
|
|
2020-04-29 01:02:55 +02:00
|
|
|
tpoint.x = xp; tpoint.y = yp - yoff;
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
setcolreal(obj.entities[i].realcol);
|
2020-04-27 00:03:02 +02:00
|
|
|
SDL_Rect drawRect = {Sint16(obj.entities[i].xp ), Sint16(obj.entities[i].yp - yoff), Sint16(sprites_rect.x * 6), Sint16(sprites_rect.y * 6 ) };
|
2020-04-26 20:13:47 +02:00
|
|
|
SDL_Surface* TempSurface = ScaleSurface( (*spritesvec)[obj.entities[i].drawframe], 6 * sprites_rect.w,6* sprites_rect.h );
|
|
|
|
BlitSurfaceColoured(TempSurface, NULL , backBuffer, &drawRect, ct );
|
|
|
|
SDL_FreeSurface(TempSurface);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2020-04-26 21:30:58 +02: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
|
|
|
{
|
|
|
|
int temp = 0;
|
|
|
|
|
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
//Starfield
|
|
|
|
FillRect(backBuffer,0x00000);
|
|
|
|
for (int i = 0; i < 50; i++)
|
|
|
|
{
|
|
|
|
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:
|
|
|
|
//Lab
|
|
|
|
switch(rcol)
|
|
|
|
{
|
|
|
|
//Akward ordering to match tileset
|
|
|
|
case 0:
|
|
|
|
bcol2 = RGBflip(0, 16*backboxint[0], 16*backboxint[0]);
|
|
|
|
break; //Cyan
|
|
|
|
case 1:
|
|
|
|
bcol2 = RGBflip(16*backboxint[0], 0, 0);
|
|
|
|
break; //Red
|
|
|
|
case 2:
|
|
|
|
bcol2 = RGBflip(16*backboxint[0], 0, 16*backboxint[0]);
|
|
|
|
break; //Purple
|
|
|
|
case 3:
|
|
|
|
bcol2 = RGBflip(0, 0, 16*backboxint[0]);
|
|
|
|
break; //Blue
|
|
|
|
case 4:
|
|
|
|
bcol2 = RGBflip(16*backboxint[0], 16*backboxint[0], 0);
|
|
|
|
break; //Yellow
|
|
|
|
case 5:
|
|
|
|
bcol2 = RGBflip(0, 16 * backboxint[0], 0);
|
|
|
|
break; //Green
|
|
|
|
case 6:
|
|
|
|
//crazy case
|
|
|
|
switch(spcol)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
bcol2 = RGBflip(0, 16*backboxint[0], 16*backboxint[0]);
|
|
|
|
break; //Cyan
|
|
|
|
case 1:
|
|
|
|
bcol2 = RGBflip(0, (spcoldel+1)*backboxint[0], 16*backboxint[0]);
|
|
|
|
break; //Cyan
|
|
|
|
case 2:
|
|
|
|
bcol2 = RGBflip(0, 0, 16*backboxint[0]);
|
|
|
|
break; //Blue
|
|
|
|
case 3:
|
|
|
|
bcol2 = RGBflip((16-spcoldel)*backboxint[0], 0, 16*backboxint[0]);
|
|
|
|
break; //Blue
|
|
|
|
case 4:
|
|
|
|
bcol2 = RGBflip(16*backboxint[0], 0, 16*backboxint[0]);
|
|
|
|
break; //Purple
|
|
|
|
case 5:
|
|
|
|
bcol2 = RGBflip(16*backboxint[0], 0, (spcoldel+1)*backboxint[0]);
|
|
|
|
break; //Purple
|
|
|
|
case 6:
|
|
|
|
bcol2 = RGBflip(16*backboxint[0], 0, 0);
|
|
|
|
break; //Red
|
|
|
|
case 7:
|
|
|
|
bcol2 = RGBflip(16*backboxint[0], (16-spcoldel)*backboxint[0], 0);
|
|
|
|
break; //Red
|
|
|
|
case 8:
|
|
|
|
bcol2 = RGBflip(16*backboxint[0], 16*backboxint[0], 0);
|
|
|
|
break; //Yellow
|
|
|
|
case 9:
|
|
|
|
bcol2 = RGBflip((spcoldel+1)*backboxint[0], 16*backboxint[0], 0);
|
|
|
|
break; //Yellow
|
|
|
|
case 10:
|
|
|
|
bcol2 = RGBflip(0, 16 * backboxint[0], 0);
|
|
|
|
break; //Green
|
|
|
|
case 11:
|
|
|
|
bcol2 = RGBflip(0, 16 * backboxint[0], (16-spcoldel)*backboxint[0]);
|
|
|
|
break; //Green
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
FillRect(backBuffer,bcol2);
|
|
|
|
|
|
|
|
for (int i = 0; i < 18; i++)
|
|
|
|
{
|
|
|
|
switch(rcol)
|
|
|
|
{
|
|
|
|
//Akward ordering to match tileset
|
|
|
|
case 0:
|
|
|
|
bcol = RGBflip(16, 128*backboxint[0], 128*backboxint[0]);
|
|
|
|
break; //Cyan
|
|
|
|
case 1:
|
|
|
|
bcol = RGBflip(128*backboxint[0], 16, 16);
|
|
|
|
break; //Red
|
|
|
|
case 2:
|
|
|
|
bcol = RGBflip(128*backboxint[0], 16, 128*backboxint[0]);
|
|
|
|
break; //Purple
|
|
|
|
case 3:
|
|
|
|
bcol = RGBflip(16, 16, 128*backboxint[0]);
|
|
|
|
break; //Blue
|
|
|
|
case 4:
|
|
|
|
bcol = RGBflip(128*backboxint[0], 128*backboxint[0], 16);
|
|
|
|
break; //Yellow
|
|
|
|
case 5:
|
|
|
|
bcol = RGBflip(16, 128 * backboxint[0], 16);
|
|
|
|
break; //Green
|
|
|
|
case 6:
|
|
|
|
//crazy case
|
|
|
|
switch(spcol)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
bcol = RGBflip(16, 128*backboxint[0], 128*backboxint[0]);
|
|
|
|
break; //Cyan
|
|
|
|
case 1:
|
|
|
|
bcol = RGBflip(16, ((spcoldel+1)*8)*backboxint[0], 128*backboxint[0]);
|
|
|
|
break; //Cyan
|
|
|
|
case 2:
|
|
|
|
bcol = RGBflip(16, 16, 128*backboxint[0]);
|
|
|
|
break; //Blue
|
|
|
|
case 3:
|
|
|
|
bcol = RGBflip((128-(spcoldel*8))*backboxint[0], 16, 128*backboxint[0]);
|
|
|
|
break; //Blue
|
|
|
|
case 4:
|
|
|
|
bcol = RGBflip(128*backboxint[0], 16, 128*backboxint[0]);
|
|
|
|
break; //Purple
|
|
|
|
case 5:
|
|
|
|
bcol = RGBflip(128*backboxint[0], 16, ((spcoldel+1)*8)*backboxint[0]);
|
|
|
|
break; //Purple
|
|
|
|
case 6:
|
|
|
|
bcol = RGBflip(128*backboxint[0], 16, 16);
|
|
|
|
break; //Red
|
|
|
|
case 7:
|
|
|
|
bcol = RGBflip(128*backboxint[0], (128-(spcoldel*8))*backboxint[0], 16);
|
|
|
|
break; //Red
|
|
|
|
case 8:
|
|
|
|
bcol = RGBflip(128*backboxint[0], 128*backboxint[0], 16);
|
|
|
|
break; //Yellow
|
|
|
|
case 9:
|
|
|
|
bcol = RGBflip(((spcoldel+1)*8)*backboxint[0], 128*backboxint[0], 16);
|
|
|
|
break; //Yellow
|
|
|
|
case 10:
|
|
|
|
bcol = RGBflip(16, 128 * backboxint[0], 16);
|
|
|
|
break; //Green
|
|
|
|
case 11:
|
|
|
|
bcol = RGBflip(16, 128 * backboxint[0], (128-(spcoldel*8))*backboxint[0]);
|
|
|
|
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;
|
|
|
|
case 3: //Warp zone (horizontal)
|
2020-05-02 21:15:52 +02:00
|
|
|
FillRect(backBuffer, 0x000000);
|
2020-04-29 20:03:17 +02:00
|
|
|
BlitSurfaceStandard(towerbuffer, NULL, towerbuffer_lerp, NULL);
|
|
|
|
ScrollSurface(towerbuffer_lerp, lerp(0, -3), 0);
|
|
|
|
BlitSurfaceStandard(towerbuffer_lerp, NULL, backBuffer, NULL);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 4: //Warp zone (vertical)
|
2020-05-02 21:15:52 +02:00
|
|
|
FillRect(backBuffer, 0x000000);
|
2020-04-29 20:09:07 +02:00
|
|
|
SDL_BlitSurface(towerbuffer, NULL, towerbuffer_lerp, NULL);
|
|
|
|
ScrollSurface(towerbuffer_lerp, 0, lerp(0, -3));
|
|
|
|
SDL_BlitSurface(towerbuffer_lerp,NULL, backBuffer,NULL);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
//Warp zone, central
|
|
|
|
switch(rcol)
|
|
|
|
{
|
|
|
|
//Akward ordering to match tileset
|
|
|
|
case 0:
|
|
|
|
warpbcol = RGBflip(0x0A, 0x10, 0x0E);
|
|
|
|
warpfcol = RGBflip(0x10, 0x22, 0x21);
|
|
|
|
break; //Cyan
|
|
|
|
case 1:
|
|
|
|
warpbcol = RGBflip(0x11, 0x09, 0x0B);
|
|
|
|
warpfcol = RGBflip(0x22, 0x10, 0x11);
|
|
|
|
break; //Red
|
|
|
|
case 2:
|
|
|
|
warpbcol = RGBflip(0x0F, 0x0A, 0x10);
|
|
|
|
warpfcol = RGBflip(0x22,0x10,0x22);
|
|
|
|
break; //Purple
|
|
|
|
case 3:
|
|
|
|
warpbcol = RGBflip(0x0A, 0x0B, 0x10);
|
|
|
|
warpfcol = RGBflip(0x10, 0x10, 0x22);
|
|
|
|
break; //Blue
|
|
|
|
case 4:
|
|
|
|
warpbcol = RGBflip(0x10, 0x0D, 0x0A);
|
|
|
|
warpfcol = RGBflip(0x22, 0x1E, 0x10);
|
|
|
|
break; //Yellow
|
|
|
|
case 5:
|
|
|
|
warpbcol = RGBflip(0x0D, 0x10, 0x0A);
|
|
|
|
warpfcol = RGBflip(0x14, 0x22, 0x10);
|
|
|
|
break; //Green
|
|
|
|
case 6:
|
|
|
|
warpbcol = RGBflip(0x0A, 0x0A, 0x0A);
|
|
|
|
warpfcol = RGBflip(0x12, 0x12, 0x12);
|
|
|
|
break; //Gray
|
2020-04-02 22:05:48 +02:00
|
|
|
default:
|
|
|
|
warpbcol = RGBflip(0xFF, 0xFF, 0xFF);
|
|
|
|
warpfcol = RGBflip(0xFF, 0xFF, 0xFF);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 10 ; i >= 0; i--)
|
|
|
|
{
|
2020-04-30 00:44:07 +02:00
|
|
|
temp = (i << 4) + lerp(backoffset - 1, backoffset);
|
2020-01-01 21:29:24 +01:00
|
|
|
setwarprect(160 - temp, 120 - temp, temp * 2, temp * 2);
|
|
|
|
if (i % 2 == warpskip)
|
|
|
|
{
|
|
|
|
FillRect(backBuffer, warprect, warpbcol);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FillRect(backBuffer,warprect, warpfcol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
//Final Starfield
|
|
|
|
FillRect(backBuffer,0x000000);
|
|
|
|
for (int i = 0; i < 50; i++)
|
|
|
|
{
|
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:
|
|
|
|
FillRect(backBuffer, 0x000000 );
|
|
|
|
BlitSurfaceStandard(backgrounds[t], NULL, backBuffer, &bg_rect);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-29 04:28:16 +02:00
|
|
|
void Graphics::updatebackground(int t)
|
|
|
|
{
|
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
//Starfield
|
|
|
|
for (int i = 0; i < 50; i++)
|
|
|
|
{
|
|
|
|
stars[i].w = 2;
|
|
|
|
stars[i].h = 2;
|
|
|
|
stars[i].x -= Sint16(starsspeed[i]);
|
|
|
|
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-04-29 04:33:33 +02:00
|
|
|
for (int i = 0; i < 18; i++)
|
|
|
|
{
|
|
|
|
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
|
|
|
{
|
|
|
|
int temp = 680 + (rcol * 3);
|
2020-04-29 19:37:56 +02:00
|
|
|
backoffset+=3;
|
|
|
|
if (backoffset >= 16) backoffset -= 16;
|
|
|
|
|
|
|
|
if (backgrounddrawn)
|
|
|
|
{
|
|
|
|
ScrollSurface(towerbuffer, -3, 0 );
|
|
|
|
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;
|
|
|
|
FillRect(towerbuffer, 0x000000);
|
|
|
|
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
|
|
|
{
|
|
|
|
int temp = 760 + (rcol * 3);
|
2020-04-29 20:06:03 +02:00
|
|
|
backoffset+=3;
|
|
|
|
if (backoffset >= 16) backoffset -= 16;
|
|
|
|
|
|
|
|
if (backgrounddrawn)
|
|
|
|
{
|
|
|
|
ScrollSurface(towerbuffer,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;
|
|
|
|
FillRect(towerbuffer,0x000000 );
|
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
|
|
|
|
for (int i = 0; i < 50; i++)
|
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawmap()
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (!foregrounddrawn)
|
|
|
|
{
|
Fix bug with displaying translucent pixels incorrectly
For a long time, VVVVVV has had an issue where if you used custom
graphics with translucent pixels (i.e. pixels whose opacity was neither
0% nor 100%, but somewhere between 0% and 100%), those pixels would end
up looking very ugly. They seemed to be overlaid on top of some weird
blue color, instead of actually being translucent.
This bug only occurred when in-game and not in towermode. So, most of
the time, basically. The translucent pixels only displayed properly
inside the Tower, both minitowers, and the editor (when not
playtesting).
I traced this down to the use of the magic number 0xDEADBEEF in
Graphics::drawmap() and Graphics::drawfinalmap(). Looks like someone had
fun finding a color. Was it you, simoroth? Anyway, I've changed it so it
simply uses 0 instead. Note that this magic number needs to be changed
for BOTH FillRect() and OverlaySurfaceKeyed(), or else the game's
background will be some random solid color instead of actually being
drawn properly.
2020-01-22 05:02:21 +01:00
|
|
|
FillRect(foregroundBuffer, 0x00000000);
|
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++)
|
|
|
|
{
|
|
|
|
if(map.contents[i + map.vmult[j]]>0) drawforetile(i * 8, j * 8, map.contents[i + map.vmult[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 jt = 0; jt < 30; jt++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
for (int it = 0; it < 40; it++)
|
|
|
|
{
|
|
|
|
if(map.contents[it + map.vmult[jt]]>0) drawforetile2(it * 8, jt * 8, map.contents[it + map.vmult[jt]]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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++)
|
|
|
|
{
|
|
|
|
if(map.contents[i + map.vmult[j]]>0) drawforetile3(i * 8, j * 8, map.contents[i + map.vmult[j]],map.rcol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foregrounddrawn = true;
|
|
|
|
}
|
Fix bug with displaying translucent pixels incorrectly
For a long time, VVVVVV has had an issue where if you used custom
graphics with translucent pixels (i.e. pixels whose opacity was neither
0% nor 100%, but somewhere between 0% and 100%), those pixels would end
up looking very ugly. They seemed to be overlaid on top of some weird
blue color, instead of actually being translucent.
This bug only occurred when in-game and not in towermode. So, most of
the time, basically. The translucent pixels only displayed properly
inside the Tower, both minitowers, and the editor (when not
playtesting).
I traced this down to the use of the magic number 0xDEADBEEF in
Graphics::drawmap() and Graphics::drawfinalmap(). Looks like someone had
fun finding a color. Was it you, simoroth? Anyway, I've changed it so it
simply uses 0 instead. Note that this magic number needs to be changed
for BOTH FillRect() and OverlaySurfaceKeyed(), or else the game's
background will be some random solid color instead of actually being
drawn properly.
2020-01-22 05:02:21 +01:00
|
|
|
OverlaySurfaceKeyed(foregroundBuffer, backBuffer, 0x00000000);
|
2020-01-11 01:37:23 +01:00
|
|
|
//SDL_BlitSurface(foregroundBuffer, NULL, backBuffer, NULL);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawfinalmap()
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-02 22:05:48 +02:00
|
|
|
if (!foregrounddrawn) {
|
|
|
|
FillRect(foregroundBuffer, 0x00000000);
|
|
|
|
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++) {
|
|
|
|
if((map.contents[i + map.vmult[j]])>0)
|
|
|
|
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++) {
|
|
|
|
if((map.contents[i + map.vmult[j]])>0)
|
|
|
|
drawforetile2(i * 8, j * 8, map.finalat(i,j));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foregrounddrawn=true;
|
|
|
|
}
|
|
|
|
|
|
|
|
OverlaySurfaceKeyed(foregroundBuffer, backBuffer, 0x00000000);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawtowermap()
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
int temp;
|
2020-04-30 20:52:21 +02:00
|
|
|
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++)
|
|
|
|
{
|
2020-04-30 20:52:21 +02:00
|
|
|
temp = map.tower.at(i, j, yoff);
|
|
|
|
if (temp > 0) drawtile3(i * 8, (j * 8) - (yoff % 8), temp, map.colstate);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawtowerspikes()
|
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-04-30 21:58:08 +02:00
|
|
|
drawtile3(i * 8, -8+spikeleveltop, 9, map.colstate);
|
|
|
|
drawtile3(i * 8, 230-spikelevelbottom, 8, map.colstate);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::drawtowerbackground()
|
2020-04-30 00:25:01 +02:00
|
|
|
{
|
2020-05-02 21:32:20 +02:00
|
|
|
FillRect(backBuffer, 0x000000);
|
2020-04-30 00:28:06 +02:00
|
|
|
SDL_BlitSurface(towerbuffer, NULL, towerbuffer_lerp, NULL);
|
|
|
|
ScrollSurface(towerbuffer_lerp, 0, lerp(0, -map.bscroll));
|
|
|
|
SDL_BlitSurface(towerbuffer_lerp,NULL, backBuffer,NULL);
|
2020-04-30 00:25:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::updatetowerbackground()
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
int temp;
|
|
|
|
|
|
|
|
if (map.bypos < 0) map.bypos += 120 * 8;
|
|
|
|
|
|
|
|
if (map.tdrawback)
|
|
|
|
{
|
2020-04-29 23:04:41 +02:00
|
|
|
int off = map.scrolldir == 0 ? 0 : map.bscroll;
|
2020-01-01 21:29:24 +01:00
|
|
|
//Draw the whole thing; needed for every colour cycle!
|
2020-05-02 22:21:42 +02:00
|
|
|
for (int j = 0; j < 32; j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < 40; i++)
|
|
|
|
{
|
|
|
|
temp = map.tower.backat(i, j, map.bypos);
|
2020-04-29 23:04:41 +02:00
|
|
|
drawtowertile3(i * 8, (j * 8) - (map.bypos % 8) - off, temp, map.colstate);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
map.tdrawback = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//just update the bottom
|
|
|
|
ScrollSurface(towerbuffer, 0, -map.bscroll);
|
2020-04-29 23:28:11 +02:00
|
|
|
if (map.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
|
|
|
{
|
|
|
|
temp = map.tower.backat(i, 0, map.bypos);
|
|
|
|
drawtowertile3(i * 8, -(map.bypos % 8), temp, map.colstate);
|
|
|
|
}
|
2020-04-29 23:28:11 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 40; i++)
|
2020-04-29 22:44:28 +02:00
|
|
|
{
|
|
|
|
temp = map.tower.backat(i, 29, map.bypos);
|
|
|
|
drawtowertile3(i * 8, 29*8 - (map.bypos % 8) - map.bscroll, temp, map.colstate);
|
|
|
|
temp = map.tower.backat(i, 30, map.bypos);
|
|
|
|
drawtowertile3(i * 8, 30*8 - (map.bypos % 8) - map.bscroll, temp, map.colstate);
|
Don't re-draw credits scroll background every frame
While I was working on my over-30-FPS patch, I found out that the tower
background in the credits scroll was being completely re-drawn every
single frame, which was a bit wasteful and expensive. It's also harder
to interpolate for my over-30-FPS patch. I'm guessing this constant
re-draw was done because the math to get the surface scroll properly
working is a bit subtle, but I've figured the precise math out!
The first changes of this patch is just removing the unconditional
`map.tdrawback = true;`, and having to set `map.scrolldir` everywhere to
get the credits scrolling in the right direction but make sure the title
screen doesn't start scrolling like a descending tower, too.
After that, the first problem is that it looks like the ACTION press to
speed up the credits scrolling doesn't speed up the background, too. No
problem, just shove a `!game.press_action` check in
`gamecompletelogic()`.
However, this introduces a mini-problem, which is that NOW when you hold
down ACTION, the background appears to be slowly getting out of sync
with the credits text by a one-pixel-per-second difference. This is
actually due to the fact that, as a result of me adding the conditional,
`map.bscroll` is no longer always unconditionally getting set to 1,
while `game.creditposition` IS always unconditionally getting
decremented by 1. And when you hold down ACTION, `game.creditposition`
gets decremented by 6.
Thus, I need to set `map.bscroll` when holding down ACTION to be 7,
which is 6 plus 1.
Then we have another problem, which is that the incoming textures desync
when you press ACTION, and when you release ACTION. They desync by
precisely 6 pixels, which should be a familiar number. I (eventually)
tracked this down to `map.bypos` being updated at the same time
`map.bscroll` is, even though `map.bypos` should be updated a frame
later AFTER updating `map.bscroll`.
So I had to change the `map.bypos` update in `gamecompleteinput()` and
`gamecompletelogic()` to be `map.bypos += map.bscroll;` and then place
it before any `map.bscroll` update, thus ensuring that `map.bscroll`
updates exactly one frame before `map.ypos` does. I had to move the
`map.bypos += map.bscroll;` to be in `gamecompleteinput()`, because
`gamecompleteinput()` comes first before `gamecompletelogic()` in the
`main.cpp` game loop, otherwise the `map.bypos` update won't be delayed
by one frame for when you press ACTION to make it go faster, and thus
cause a desync when you press ACTION.
Oh and then after that, I had to make the descending tower background
draw a THIRD row of incoming tiles, otherwise you could see some black
flickering at the bottom of the screen when you held down ACTION.
All of this took me way too long to figure out, but now the credits
scroll works perfectly while being more optimized.
2020-04-30 05:52:33 +02:00
|
|
|
temp = map.tower.backat(i, 31, map.bypos);
|
|
|
|
drawtowertile3(i * 8, 31*8 - (map.bypos % 8) - map.bscroll, temp, map.colstate);
|
2020-05-02 22:21:42 +02:00
|
|
|
temp = map.tower.backat(i, 32, map.bypos);
|
|
|
|
drawtowertile3(i * 8, 32*8 - (map.bypos % 8) - map.bscroll, temp, map.colstate);
|
2020-04-29 22:44:28 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 21:26:11 +02:00
|
|
|
void Graphics::setcol( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
int temp;
|
|
|
|
|
|
|
|
//Setup predefinied colours as per our zany palette
|
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
//Player Normal
|
|
|
|
case 0:
|
|
|
|
ct.colour = getRGB(160- help.glow/2 - (fRandom()*20), 200- help.glow/2, 220 - help.glow);
|
|
|
|
break;
|
|
|
|
//Player Hurt
|
|
|
|
case 1:
|
|
|
|
ct.colour = getRGB(196 - (fRandom() * 64), 10, 10);
|
|
|
|
break;
|
|
|
|
//Enemies and stuff
|
|
|
|
case 2:
|
|
|
|
ct.colour = getRGB(225-(help.glow/2), 75, 30);
|
|
|
|
break;
|
|
|
|
case 3: //Trinket
|
|
|
|
if (!trinketcolset)
|
|
|
|
{
|
|
|
|
trinketr = 200 - (fRandom() * 64);
|
|
|
|
trinketg = 200 - (fRandom() * 128);
|
|
|
|
trinketb = 164 + (fRandom() * 60);
|
|
|
|
trinketcolset = true;
|
|
|
|
}
|
|
|
|
ct.colour = getRGB(trinketr, trinketg, trinketb);
|
|
|
|
break;
|
|
|
|
case 4: //Inactive savepoint
|
|
|
|
temp = (help.glow/2) + (fRandom() * 8);
|
|
|
|
ct.colour = getRGB(80 + temp, 80 + temp, 80 + temp);
|
|
|
|
break;
|
|
|
|
case 5: //Active savepoint
|
|
|
|
ct.colour = getRGB(164+(fRandom()*64),164+(fRandom()*64), 255-(fRandom()*64));
|
|
|
|
break;
|
|
|
|
case 6: //Enemy : Red
|
|
|
|
ct.colour = getRGB(250 - help.glow/2, 60- help.glow/2, 60 - help.glow/2);
|
|
|
|
break;
|
|
|
|
case 7: //Enemy : Green
|
|
|
|
ct.colour = getRGB(100 - help.glow/2 - (fRandom()*30), 250 - help.glow/2, 100 - help.glow/2 - (fRandom()*30));
|
|
|
|
break;
|
|
|
|
case 8: //Enemy : Purple
|
|
|
|
ct.colour = getRGB(250 - help.glow/2, 20, 128 - help.glow/2 + (fRandom()*30));
|
|
|
|
break;
|
|
|
|
case 9: //Enemy : Yellow
|
|
|
|
ct.colour = getRGB(250 - help.glow/2, 250 - help.glow/2, 20);
|
|
|
|
break;
|
|
|
|
case 10: //Warp point (white)
|
|
|
|
ct.colour = getRGB(255 - (fRandom() * 64), 255 - (fRandom() * 64), 255 - (fRandom() * 64));
|
|
|
|
break;
|
|
|
|
case 11: //Enemy : Cyan
|
|
|
|
ct.colour = getRGB(20, 250 - help.glow/2, 250 - help.glow/2);
|
|
|
|
break;
|
|
|
|
case 12: //Enemy : Blue
|
|
|
|
ct.colour = getRGB(90- help.glow/2, 90 - help.glow/2, 250 - help.glow/2);
|
|
|
|
break;
|
|
|
|
//Crew Members
|
|
|
|
//green
|
|
|
|
case 13:
|
|
|
|
ct.colour = getRGB(120- help.glow/4 - (fRandom()*20), 220 - help.glow/4, 120- help.glow/4);
|
|
|
|
break;
|
|
|
|
//Yellow
|
|
|
|
case 14:
|
|
|
|
ct.colour = getRGB(220- help.glow/4 - (fRandom()*20), 210 - help.glow/4, 120- help.glow/4);
|
|
|
|
break;
|
|
|
|
//pink
|
|
|
|
case 15:
|
|
|
|
ct.colour = getRGB(255 - help.glow/8, 70 - help.glow/4, 70 - help.glow / 4);
|
|
|
|
break;
|
|
|
|
//Blue
|
|
|
|
case 16:
|
|
|
|
ct.colour = getRGB(75, 75, 255- help.glow/4 - (fRandom()*20));
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 17: //Enemy : Orange
|
|
|
|
ct.colour = getRGB(250 - help.glow/2, 130 - help.glow/2, 20);
|
|
|
|
break;
|
|
|
|
case 18: //Enemy : Gray
|
|
|
|
ct.colour = getRGB(130- help.glow/2, 130 - help.glow/2, 130 - help.glow/2);
|
|
|
|
break;
|
|
|
|
case 19: //Enemy : Dark gray
|
|
|
|
ct.colour = getRGB(60- help.glow/8, 60 - help.glow/8, 60 - help.glow/8);
|
|
|
|
break;
|
|
|
|
//Purple
|
|
|
|
case 20:
|
|
|
|
ct.colour = getRGB(220 - help.glow / 4 - (fRandom() * 20), 120 - help.glow / 4, 210 - help.glow / 4);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 21: //Enemy : Light Gray
|
|
|
|
ct.colour = getRGB(180- help.glow/2, 180 - help.glow/2, 180 - help.glow/2);
|
|
|
|
break;
|
|
|
|
case 22: //Enemy : Indicator Gray
|
|
|
|
ct.colour = getRGB(230- help.glow/2, 230- help.glow/2, 230- help.glow/2);
|
|
|
|
break;
|
|
|
|
case 23: //Enemy : Indicator Gray
|
|
|
|
ct.colour = getRGB(255- help.glow/2 - (fRandom() * 40) , 255- help.glow/2 - (fRandom() * 40), 255- help.glow/2 - (fRandom() * 40));
|
|
|
|
break;
|
|
|
|
|
|
|
|
//Trophies
|
|
|
|
//cyan
|
|
|
|
case 30:
|
|
|
|
ct.colour = RGBf(160, 200, 220);
|
|
|
|
break;
|
|
|
|
//Purple
|
|
|
|
case 31:
|
|
|
|
ct.colour = RGBf(220, 120, 210);
|
|
|
|
break;
|
|
|
|
//Yellow
|
|
|
|
case 32:
|
|
|
|
ct.colour = RGBf(220, 210, 120);
|
|
|
|
break;
|
|
|
|
//red
|
|
|
|
case 33:
|
|
|
|
ct.colour = RGBf(255, 70, 70);
|
|
|
|
break;
|
|
|
|
//green
|
|
|
|
case 34:
|
|
|
|
ct.colour = RGBf(120, 220, 120);
|
|
|
|
break;
|
|
|
|
//Blue
|
|
|
|
case 35:
|
|
|
|
ct.colour = RGBf(75, 75, 255);
|
|
|
|
break;
|
|
|
|
//Gold
|
|
|
|
case 36:
|
|
|
|
ct.colour = getRGB(180, 120, 20);
|
|
|
|
break;
|
|
|
|
case 37: //Trinket
|
|
|
|
if (!trinketcolset)
|
|
|
|
{
|
|
|
|
trinketr = 200 - (fRandom() * 64);
|
|
|
|
trinketg = 200 - (fRandom() * 128);
|
|
|
|
trinketb = 164 + (fRandom() * 60);
|
|
|
|
trinketcolset = true;
|
|
|
|
}
|
|
|
|
ct.colour = RGBf(trinketr, trinketg, trinketb);
|
|
|
|
break;
|
|
|
|
//Silver
|
|
|
|
case 38:
|
|
|
|
ct.colour = RGBf(196, 196, 196);
|
|
|
|
break;
|
|
|
|
//Bronze
|
|
|
|
case 39:
|
|
|
|
ct.colour = RGBf(128, 64, 10);
|
|
|
|
break;
|
|
|
|
//Awesome
|
|
|
|
case 40: //Teleporter in action!
|
|
|
|
temp = fRandom() * 150;
|
|
|
|
if(temp<33)
|
|
|
|
{
|
|
|
|
ct.colour = RGBf(255 - (fRandom() * 64), 64 + (fRandom() * 64), 64 + (fRandom() * 64));
|
|
|
|
}
|
|
|
|
else if (temp < 66)
|
|
|
|
{
|
|
|
|
ct.colour = RGBf(64 + (fRandom() * 64), 255 - (fRandom() * 64), 64 + (fRandom() * 64));
|
|
|
|
}
|
|
|
|
else if (temp < 100)
|
|
|
|
{
|
|
|
|
ct.colour = RGBf(64 + (fRandom() * 64), 64 + (fRandom() * 64), 255 - (fRandom() * 64));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ct.colour = RGBf(164+(fRandom()*64),164+(fRandom()*64), 255-(fRandom()*64));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 100: //Inactive Teleporter
|
|
|
|
temp = (help.glow/2) + (fRandom() * 8);
|
|
|
|
ct.colour = getRGB(42 + temp, 42 + temp, 42 + temp);
|
|
|
|
break;
|
|
|
|
case 101: //Active Teleporter
|
|
|
|
ct.colour = getRGB(164+(fRandom()*64),164+(fRandom()*64), 255-(fRandom()*64));
|
|
|
|
break;
|
|
|
|
case 102: //Teleporter in action!
|
|
|
|
temp = fRandom() * 150;
|
|
|
|
if(temp<33)
|
|
|
|
{
|
|
|
|
ct.colour = getRGB(255 - (fRandom() * 64), 64 + (fRandom() * 64), 64 + (fRandom() * 64));
|
|
|
|
}
|
|
|
|
else if (temp < 66)
|
|
|
|
{
|
|
|
|
ct.colour = getRGB(64 + (fRandom() * 64), 255 - (fRandom() * 64), 64 + (fRandom() * 64));
|
|
|
|
}
|
|
|
|
else if (temp < 100)
|
|
|
|
{
|
|
|
|
ct.colour = getRGB(64 + (fRandom() * 64), 64 + (fRandom() * 64), 255 - (fRandom() * 64));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ct.colour = getRGB(164+(fRandom()*64),164+(fRandom()*64), 255-(fRandom()*64));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ct.colour = 0xFFFFFF;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::menuoffrender()
|
|
|
|
{
|
|
|
|
SDL_Rect offsetRect1;
|
|
|
|
setRect (offsetRect1, 0, 0, backBuffer->w ,backBuffer->h);
|
|
|
|
|
|
|
|
//put the back buffer in the menubuffer
|
|
|
|
BlitSurfaceStandard(backBuffer, NULL, menubuffer, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-04-29 05:46:33 +02:00
|
|
|
int usethisoffset = lerp(oldmenuoffset, menuoffset);
|
2020-01-01 21:29:24 +01:00
|
|
|
if(flipmode)
|
|
|
|
{
|
|
|
|
// flipmatrix.translate(0, menuoffset);
|
|
|
|
// screenbuffer.draw(backbuffer, flipmatrix);
|
|
|
|
// flipmatrix.translate(0, -menuoffset);
|
|
|
|
SDL_Surface* tempbufferFlipped = FlipSurfaceVerticle(tempBuffer);
|
|
|
|
//put the stored backbuffer in the backbuffer.
|
|
|
|
SDL_FillRect(backBuffer, NULL, 0x00000000);
|
|
|
|
BlitSurfaceStandard(tempbufferFlipped, NULL, backBuffer, NULL);
|
|
|
|
SDL_FreeSurface(tempbufferFlipped);
|
|
|
|
SDL_Rect offsetRect;
|
2020-04-29 05:46:33 +02:00
|
|
|
setRect (offsetRect, 0, usethisoffset, backBuffer->w ,backBuffer->h);
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Surface* temp = FlipSurfaceVerticle(menubuffer);
|
|
|
|
BlitSurfaceStandard(temp,NULL,backBuffer,&offsetRect);
|
|
|
|
SDL_FreeSurface(temp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//put the stored backbuffer in the backbuffer.
|
|
|
|
BlitSurfaceStandard(tempBuffer, NULL, backBuffer, NULL);
|
|
|
|
|
|
|
|
SDL_Rect offsetRect;
|
2020-04-29 05:46:33 +02:00
|
|
|
setRect (offsetRect, 0, usethisoffset, backBuffer->w ,backBuffer->h);
|
2020-01-01 21:29:24 +01:00
|
|
|
BlitSurfaceStandard(menubuffer,NULL,backBuffer,&offsetRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect, 0, 0, backBuffer->w, backBuffer->h);
|
|
|
|
screenbuffer->UpdateScreen(backBuffer,&rect);
|
|
|
|
FillRect(backBuffer, 0x000000);
|
|
|
|
}
|
|
|
|
|
2020-04-30 23:42:08 +02:00
|
|
|
void Graphics::drawhuetile( int x, int y, int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-14 03:37:18 +02:00
|
|
|
if (!INBOUNDS(t, tiles))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
point tpoint;
|
|
|
|
tpoint.x = x;
|
|
|
|
tpoint.y = y;
|
2020-04-30 23:42:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect,tpoint.x,tpoint.y,tiles_rect.w, tiles_rect.h);
|
|
|
|
BlitSurfaceColoured(tiles[t],NULL,backBuffer, &rect, ct);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::huetilesetcol(int t)
|
|
|
|
{
|
|
|
|
switch (t)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
setcolreal(getRGB(250-int(fRandom()*32), 250-int(fRandom()*32), 10));
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
setcolreal(getRGB(250-int(fRandom()*32), 250-int(fRandom()*32), 10));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
setcolreal(getRGB(250-int(fRandom()*32), 250-int(fRandom()*32), 10));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 23:57:21 +02:00
|
|
|
Uint32 Graphics::bigchunkygetcol(int t)
|
|
|
|
{
|
|
|
|
//A seperate index of colours, for simplicity
|
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
return getRGB((fRandom() * 64), 10, 10);
|
|
|
|
case 2:
|
|
|
|
return getRGB(int(160- help.glow/2 - (fRandom()*20)), 200- help.glow/2, 220 - help.glow);
|
|
|
|
}
|
|
|
|
return 0x00000000;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
void Graphics::setwarprect( int a, int b, int c, int d )
|
|
|
|
{
|
|
|
|
warprect.x = a;
|
|
|
|
warprect.y = b;
|
|
|
|
warprect.w = c;
|
|
|
|
warprect.h = d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxcenter()
|
|
|
|
{
|
2020-06-28 19:40:58 +02:00
|
|
|
if (!INBOUNDS(m, textbox))
|
|
|
|
{
|
2020-06-28 21:43:12 +02:00
|
|
|
puts("textboxcenter() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
textbox[m].centerx();
|
|
|
|
textbox[m].centery();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxcenterx()
|
|
|
|
{
|
2020-06-28 19:40:58 +02:00
|
|
|
if (!INBOUNDS(m, textbox))
|
|
|
|
{
|
2020-06-28 21:43:12 +02:00
|
|
|
puts("textboxcenterx() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
textbox[m].centerx();
|
|
|
|
}
|
|
|
|
|
|
|
|
int Graphics::textboxwidth()
|
|
|
|
{
|
2020-06-28 19:40:58 +02:00
|
|
|
if (!INBOUNDS(m, textbox))
|
|
|
|
{
|
2020-06-28 21:43:12 +02:00
|
|
|
puts("textboxwidth() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
return textbox[m].w;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxmove(int xo, int yo)
|
|
|
|
{
|
2020-06-28 19:40:58 +02:00
|
|
|
if (!INBOUNDS(m, textbox))
|
|
|
|
{
|
2020-06-28 21:43:12 +02:00
|
|
|
puts("textboxmove() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
textbox[m].xp += xo;
|
|
|
|
textbox[m].yp += yo;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxmoveto(int xo)
|
|
|
|
{
|
2020-06-28 19:40:58 +02:00
|
|
|
if (!INBOUNDS(m, textbox))
|
|
|
|
{
|
2020-06-28 21:43:12 +02:00
|
|
|
puts("textboxmoveto() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
textbox[m].xp = xo;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::textboxcentery()
|
|
|
|
{
|
2020-06-28 19:40:58 +02:00
|
|
|
if (!INBOUNDS(m, textbox))
|
|
|
|
{
|
2020-06-28 21:43:12 +02:00
|
|
|
puts("textboxcentery() out-of-bounds!");
|
2020-06-28 19:40:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
textbox[m].centery();
|
|
|
|
}
|
|
|
|
|
|
|
|
int Graphics::crewcolour(const int t)
|
|
|
|
{
|
|
|
|
//given crewmate t, return colour in setcol
|
|
|
|
if (t == 0) return 0;
|
|
|
|
if (t == 1) return 20;
|
|
|
|
if (t == 2) return 14;
|
|
|
|
if (t == 3) return 15;
|
|
|
|
if (t == 4) return 13;
|
|
|
|
if (t == 5) return 16;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::flashlight()
|
|
|
|
{
|
|
|
|
FillRect(backBuffer, 0xBBBBBBBB);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::screenshake()
|
|
|
|
{
|
|
|
|
if(flipmode)
|
|
|
|
{
|
|
|
|
// tpoint.x = int((Math.random() * 7) - 4); tpoint.y = int((Math.random() * 7) - 4);
|
|
|
|
// flipmatrix.translate(tpoint.x, tpoint.y);
|
|
|
|
// screenbuffer.draw(backbuffer, flipmatrix);
|
|
|
|
// flipmatrix.translate(-tpoint.x, -tpoint.y);
|
|
|
|
|
|
|
|
SDL_Rect shakeRect;
|
2020-04-29 02:29:59 +02:00
|
|
|
setRect(shakeRect,screenshake_x, screenshake_y, backBuffer->w, backBuffer->h);
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Surface* flipBackBuffer = FlipSurfaceVerticle(backBuffer);
|
|
|
|
screenbuffer->UpdateScreen( flipBackBuffer, &shakeRect);
|
|
|
|
SDL_FreeSurface(flipBackBuffer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//FillRect(screenbuffer, 0x000);
|
|
|
|
//SDL_Rect rect;
|
|
|
|
//setRect(rect, blackBars/2, 0, screenbuffer->w, screenbuffer->h);
|
|
|
|
//SDL_BlitSurface(backBuffer, NULL, screenbuffer, &rect);
|
|
|
|
SDL_Rect shakeRect;
|
2020-04-29 02:29:59 +02:00
|
|
|
setRect(shakeRect,screenshake_x, screenshake_y, backBuffer->w, backBuffer->h);
|
2020-01-01 21:29:24 +01:00
|
|
|
screenbuffer->UpdateScreen( backBuffer, &shakeRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
FillRect(backBuffer, 0x000000 );
|
|
|
|
}
|
|
|
|
|
2020-04-29 02:29:59 +02:00
|
|
|
void Graphics::updatescreenshake()
|
|
|
|
{
|
|
|
|
screenshake_x = static_cast<Sint32>((fRandom() * 7) - 4);
|
|
|
|
screenshake_y = static_cast<Sint32>((fRandom() * 7) - 4);
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
void Graphics::render()
|
|
|
|
{
|
|
|
|
if(screenbuffer == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(flipmode)
|
|
|
|
{
|
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect, 0, 0, backBuffer->w, backBuffer->h);
|
|
|
|
//setRect(rect, 0, 0, backBuffer->w, backBuffer->h);
|
|
|
|
//SDL_BlitSurface(backBuffer, NULL, screenbuffer, &rect);
|
|
|
|
SDL_Surface* tempsurface = FlipSurfaceVerticle(backBuffer);
|
|
|
|
if(tempsurface != NULL)
|
|
|
|
{
|
|
|
|
screenbuffer->UpdateScreen( tempsurface, &rect);
|
|
|
|
SDL_FreeSurface(tempsurface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect, 0, 0, backBuffer->w, backBuffer->h);
|
|
|
|
//setRect(rect, 0, 0, backBuffer->w, backBuffer->h);
|
|
|
|
//SDL_BlitSurface(backBuffer, NULL, screenbuffer, &rect);
|
|
|
|
screenbuffer->UpdateScreen( backBuffer, &rect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-27 04:24:50 +02:00
|
|
|
void Graphics::renderwithscreeneffects()
|
|
|
|
{
|
|
|
|
if (game.flashlight > 0 && !game.noflashingmode)
|
|
|
|
{
|
|
|
|
graphics.flashlight();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (game.screenshake > 0 && !game.noflashingmode)
|
|
|
|
{
|
|
|
|
graphics.screenshake();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
graphics.render();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
void Graphics::bigrprint(int x, int y, std::string& t, int r, int g, int b, bool cen, float sc)
|
|
|
|
{
|
2020-06-14 03:46:32 +02:00
|
|
|
std::vector<SDL_Surface*>& font = flipmode ? flipbfont : bfont;
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
if (r < 0) r = 0;
|
|
|
|
if (g < 0) g = 0;
|
|
|
|
if (b < 0) b = 0;
|
|
|
|
if (r > 255) r = 255;
|
|
|
|
if (g > 255) g = 255;
|
|
|
|
if (b > 255) b = 255;
|
|
|
|
ct.colour = getRGB(r, g, b);
|
|
|
|
|
|
|
|
x = x / (sc);
|
|
|
|
|
|
|
|
x -= (len(t));
|
|
|
|
|
2020-01-11 02:05:26 +01:00
|
|
|
if (r < -1) r = -1;
|
|
|
|
if (g < 0) g = 0;
|
|
|
|
if (b < 0) b = 0;
|
|
|
|
if (r > 255) r = 255;
|
|
|
|
if (g > 255) g = 255;
|
|
|
|
if (b > 255) b = 255;
|
2020-01-01 21:29:24 +01:00
|
|
|
ct.colour = getRGB(r, g, b);
|
|
|
|
|
|
|
|
if (cen)
|
|
|
|
{
|
|
|
|
x = std::max(160 - (int((len(t)/ 2.0)*sc)), 0 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x *= (sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
int bfontpos = 0;
|
|
|
|
int cur;
|
2020-06-14 03:56:59 +02:00
|
|
|
int idx;
|
2020-01-31 19:25:37 +01:00
|
|
|
std::string::iterator iter = t.begin();
|
|
|
|
while (iter != t.end()) {
|
|
|
|
cur = utf8::unchecked::next(iter);
|
2020-06-14 03:56:59 +02:00
|
|
|
idx = font_idx(cur);
|
|
|
|
if (INBOUNDS(idx, font))
|
|
|
|
{
|
|
|
|
SDL_Surface* tempPrint = ScaleSurfaceSlow(font[idx], font[idx]->w *sc,font[idx]->h *sc);
|
|
|
|
SDL_Rect printrect = { Sint16((x) + bfontpos), Sint16(y) , Sint16(bfont_rect.w*sc), Sint16(bfont_rect.h * sc)};
|
|
|
|
BlitSurfaceColoured(tempPrint, NULL, backBuffer, &printrect, ct);
|
|
|
|
SDL_FreeSurface(tempPrint);
|
|
|
|
}
|
2020-01-31 19:25:37 +01:00
|
|
|
bfontpos+=bfontlen(cur)* sc;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
void Graphics::drawtele(int x, int y, int t, Uint32 c)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
setcolreal(getRGB(16,16,16));
|
|
|
|
|
|
|
|
SDL_Rect telerect;
|
|
|
|
setRect(telerect, x , y, tele_rect.w, tele_rect.h );
|
2020-06-14 03:37:53 +02:00
|
|
|
if (INBOUNDS(0, tele))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured(tele[0], NULL, backBuffer, &telerect, ct);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
setcolreal(c);
|
2020-01-01 21:29:24 +01:00
|
|
|
if (t > 9) t = 8;
|
|
|
|
if (t < 0) t = 0;
|
|
|
|
|
2020-04-26 20:42:06 +02:00
|
|
|
setRect(telerect, x , y, tele_rect.w, tele_rect.h );
|
2020-06-14 03:37:53 +02:00
|
|
|
if (INBOUNDS(t, tele))
|
|
|
|
{
|
|
|
|
BlitSurfaceColoured(tele[t], NULL, backBuffer, &telerect, ct);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-02-10 03:23:12 +01:00
|
|
|
Uint32 Graphics::getRGBA(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
|
|
|
|
{
|
|
|
|
return SDL_MapRGBA(backBuffer->format, b, g, r, a);
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
Uint32 Graphics::getRGB(Uint8 r, Uint8 g, Uint8 b)
|
|
|
|
{
|
|
|
|
return SDL_MapRGB(backBuffer->format, b, g, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
Uint32 Graphics::getBGR(Uint8 r, Uint8 g, Uint8 b)
|
|
|
|
{
|
|
|
|
return SDL_MapRGB(backBuffer->format, r, g, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Uint32 Graphics::getRGB(Uint32 _col)
|
|
|
|
{
|
|
|
|
return ( _col);
|
|
|
|
}
|
|
|
|
|
|
|
|
Uint32 Graphics::RGBflip(Uint8 r, Uint8 g, Uint8 b)
|
|
|
|
{
|
|
|
|
return SDL_MapRGB(backBuffer->format, r, g, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Uint32 Graphics::RGBf(int r, int g, int b)
|
|
|
|
{
|
|
|
|
r = (r+128) / 3;
|
|
|
|
g = (g+128) / 3;
|
|
|
|
b = (b+128) / 3;
|
|
|
|
return SDL_MapRGB(backBuffer->format, r, g, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::setcolreal(Uint32 t)
|
|
|
|
{
|
|
|
|
ct.colour = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawforetile(int x, int y, int t)
|
|
|
|
{
|
2020-06-30 20:51:01 +02:00
|
|
|
if (!INBOUNDS(t, tiles))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01: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)
|
2020-06-30 23:08:14 +02:00
|
|
|
if (t >= 14 && t <= 17 && (!FILESYSTEM_assetsmounted || ed.onewaycol_override))
|
2020-06-30 20:47:22 +02:00
|
|
|
{
|
|
|
|
colourTransform thect = {ed.getonewaycol()};
|
|
|
|
BlitSurfaceTinted(tiles[t], NULL, foregroundBuffer, &rect, thect);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
BlitSurfaceStandard(tiles[t],NULL, foregroundBuffer, &rect );
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Graphics::drawforetile2(int x, int y, int t)
|
|
|
|
{
|
2020-06-30 20:51:01 +02:00
|
|
|
if (!INBOUNDS(t, tiles2))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01: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)
|
2020-06-30 23:08:14 +02:00
|
|
|
if (t >= 14 && t <= 17 && (!FILESYSTEM_assetsmounted || ed.onewaycol_override))
|
2020-06-30 20:47:22 +02:00
|
|
|
{
|
|
|
|
colourTransform thect = {ed.getonewaycol()};
|
|
|
|
BlitSurfaceTinted(tiles2[t], NULL, foregroundBuffer, &rect, thect);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2020-06-30 20:51:01 +02:00
|
|
|
t += off * 30;
|
|
|
|
if (!INBOUNDS(t, tiles3))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Rect rect;
|
|
|
|
setRect(rect, x,y,tiles_rect.w, tiles_rect.h);
|
2020-06-30 20:51:01 +02:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
SDL_Rect madrect;
|
|
|
|
//Draw the retangle indicated by that object
|
|
|
|
madrect.x = x;
|
|
|
|
madrect.y = y;
|
|
|
|
madrect.w = w;
|
|
|
|
madrect.h = 1;
|
|
|
|
FillRect(backBuffer, madrect, getRGB(b,g,r));
|
|
|
|
|
|
|
|
madrect.w = 1;
|
|
|
|
madrect.h = h;
|
|
|
|
FillRect(backBuffer, madrect, getRGB(b,g,r));
|
|
|
|
|
|
|
|
madrect.x = x + w - 1;
|
|
|
|
madrect.w = 1;
|
|
|
|
madrect.h = h;
|
|
|
|
FillRect(backBuffer, madrect, getRGB(b,g,r));
|
|
|
|
madrect.x = x;
|
|
|
|
madrect.y = y + h - 1;
|
|
|
|
madrect.w = w;
|
|
|
|
madrect.h = 1;
|
|
|
|
FillRect(backBuffer, madrect, getRGB(b,g,r));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Graphics::onscreen(int t)
|
|
|
|
{
|
|
|
|
return (t >= -40 && t <= 280);
|
|
|
|
}
|
2020-06-01 01:31:02 +02:00
|
|
|
|
|
|
|
void Graphics::reloadresources() {
|
2020-06-12 02:55:27 +02:00
|
|
|
grphx.destroy();
|
|
|
|
grphx = GraphicsResources();
|
|
|
|
grphx.init();
|
|
|
|
|
|
|
|
#define CLEAR_ARRAY(name) \
|
|
|
|
for (size_t i = 0; i < name.size(); i += 1) \
|
|
|
|
{ \
|
|
|
|
SDL_FreeSurface(name[i]); \
|
|
|
|
} \
|
|
|
|
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
|
|
|
|
|
|
|
|
MakeTileArray();
|
|
|
|
MakeSpriteArray();
|
|
|
|
maketelearray();
|
|
|
|
Makebfont();
|
|
|
|
|
|
|
|
images.clear();
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
music.init();
|
2020-06-01 01:31:02 +02:00
|
|
|
}
|
2020-05-02 22:53:19 +02:00
|
|
|
|
|
|
|
Uint32 Graphics::crewcolourreal(int t)
|
|
|
|
{
|
|
|
|
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-04 22:19:47 +02:00
|
|
|
|
|
|
|
void Graphics::processVsync()
|
|
|
|
{
|
|
|
|
SDL_SetHintWithPriority(SDL_HINT_RENDER_VSYNC, vsync ? "1" : "0", SDL_HINT_OVERRIDE);
|
Work around SDL2 bug where VSync hint only applies on renderer creation
Ugh, this is terrible and stupid and I hate myself for it.
Anyway, since the SDL2 VSync hint only applies when the renderer is
created, we have to re-create the renderer whenever VSync is toggled.
However, this also means we need to re-create m_screenTexture as well,
AND call ResizeScreen() after that or else the letterbox/integer modes
won't be applied.
Unfortunately, this means that in main(), gameScreen.init() will create
a renderer only to be destroyed later by graphics.processVsync().
There's not much we can do about this. Fixing this would require putting
graphics.processVsync() before gameScreen.init(). However, in order to
know whether the user has VSync set, we would have to call
game.loadstats() first, but wait, we can't, because game.loadstats()
mutates gameScreen! Gahhhhhh!!!!
@leo60228 suggested to fix that problem (
https://github.com/TerryCavanagh/VVVVVV/pull/220#issuecomment-624217939
) by adding NULL checks to game.loadstats() and then calling it twice,
but then you're trading wastefully creating a renderer only to be
destroyed, for wastefully opening and parsing unlock.vvv twice instead
of once. In either case, you're doing something twice and wasting work.
2020-06-19 23:12:56 +02:00
|
|
|
|
|
|
|
// FIXME: Sigh... work around SDL2 bug where the VSync hint is only listened to at renderer creation
|
|
|
|
SDL_DestroyRenderer(screenbuffer->m_renderer);
|
|
|
|
screenbuffer->m_renderer = SDL_CreateRenderer(screenbuffer->m_window, -1, 0);
|
|
|
|
|
|
|
|
// Ugh, have to re-create m_screenTexture as well, otherwise the screen will be black...
|
|
|
|
SDL_DestroyTexture(screenbuffer->m_screenTexture);
|
|
|
|
// FIXME: This is duplicated from Screen::init()!
|
|
|
|
screenbuffer->m_screenTexture = SDL_CreateTexture(
|
|
|
|
screenbuffer->m_renderer,
|
|
|
|
SDL_PIXELFORMAT_ARGB8888,
|
|
|
|
SDL_TEXTUREACCESS_STREAMING,
|
|
|
|
320,
|
|
|
|
240
|
|
|
|
);
|
|
|
|
|
|
|
|
// Ugh, have to make sure to re-apply graphics options after doing the above, otherwise letterbox/integer won't be applied...
|
|
|
|
screenbuffer->ResizeScreen(-1, -1);
|
2020-05-04 22:19:47 +02:00
|
|
|
}
|