1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-01 18:43:33 +02:00
VVVVVV/desktop_version/src/Graphics.cpp
Misa 351a022ebd Use SDL_Color for colors instead of colourTransform
colourTransform is a struct with only one member, a Uint32. The issue
with `Uint32`s is that it requires a bunch of bit shifting logic to edit
the colors. The issue with bit shifting logic is that people have a
tendency to hardcode the shift amounts instead of using the shift amount
variables of the SDL_PixelFormat, which makes it annoying to change the
color masks of surfaces.

This commit fixes both issues by unhardcoding the bit shift amounts in
DrawPixel and ReadPixel, and by axing the `Uint32`s in favor of using
SDL_Color.

According to the SDL_PixelFormat documentation (
https://wiki.libsdl.org/SDL2/SDL_PixelFormat ), the logic to read and
draw to pixels from colors below 32-bit was just wrong. Specifically,
for 8-bit, there's a color palette used instead of some intrinsic color
information stored in the pixel itself. But we shouldn't need that logic
anyways because we don't use colors below 32-bit. So I axed that too.
2023-01-01 16:36:43 -08:00

3837 lines
101 KiB
C++

#define GRAPHICS_DEFINITION
#include "Graphics.h"
#include <SDL.h>
#include <utf8/unchecked.h>
#include "Alloc.h"
#include "Constants.h"
#include "CustomLevels.h"
#include "Entity.h"
#include "Exit.h"
#include "FileSystemUtils.h"
#include "GraphicsUtil.h"
#include "Localization.h"
#include "Map.h"
#include "Music.h"
#include "RoomnameTranslator.h"
#include "Screen.h"
#include "UtilityClass.h"
#include "VFormat.h"
#include "Vlogging.h"
void Graphics::init(void)
{
flipmode = false;
setRect(tiles_rect, 0,0,8,8);
setRect(sprites_rect, 0,0,32,32);
setRect(footerrect, 0, 230, 320, 10);
setRect(prect, 0, 0, 4, 4);
setRect(line_rect, 0,0,0,0);
setRect(tele_rect,0,0,96,96);
setRect(towerbuffer_rect, 8, 8, 320, 240);
//We initialise a few things
linestate = 0;
trinketcolset = false;
showcutscenebars = false;
setbars(0);
notextoutline = false;
flipmode = false;
setflipmode = false;
//Background inits
for (int i = 0; i < numstars; i++)
{
SDL_Rect s = {(int) (fRandom() * 320), (int) (fRandom() * 240), 2, 2};
int s2 = 4+(fRandom()*4);
stars[i] = s;
starsspeed[i] = s2;
}
for (int i = 0; i < numbackboxes; i++)
{
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[i] = bb;
backboxvx[i] = bvx;
backboxvy[i] = bvy;
backboxint[i] = bint;
}
backoffset = 0;
backgrounddrawn = false;
warpskip = 0;
SDL_zero(warpfcol);
SDL_zero(warpbcol);
spcol = 0;
spcoldel = 0;
rcol = 0;
crewframe = 0;
crewframedelay = 4;
menuoffset = 0;
oldmenuoffset = 0;
resumegamemode = false;
//Fading stuff
SDL_memset(fadebars, 0, sizeof(fadebars));
setfade(0);
fademode = FADE_NONE;
ingame_fademode = FADE_NONE;
// initialize everything else to zero
backBuffer = NULL;
SDL_zero(ct);
foregrounddrawn = false;
foregroundBuffer = NULL;
backgrounddrawn = false;
m = 0;
linedelay = 0;
menubuffer = NULL;
tempBuffer = NULL;
warpbuffer = NULL;
warpbuffer_lerp = NULL;
footerbuffer = NULL;
ghostbuffer = NULL;
towerbg = TowerBG();
titlebg = TowerBG();
trinketr = 0;
trinketg = 0;
trinketb = 0;
warprect = SDL_Rect();
translucentroomname = false;
alpha = 1.0f;
screenshake_x = 0;
screenshake_y = 0;
SDL_zero(col_crewred);
SDL_zero(col_crewyellow);
SDL_zero(col_crewgreen);
SDL_zero(col_crewcyan);
SDL_zero(col_crewblue);
SDL_zero(col_crewpurple);
SDL_zero(col_crewinactive);
SDL_zero(col_clock);
SDL_zero(col_trinket);
col_tr = 0;
col_tg = 0;
col_tb = 0;
kludgeswnlinewidth = false;
#ifndef NO_CUSTOM_LEVELS
tiles1_mounted = false;
tiles2_mounted = false;
minimap_mounted = false;
#endif
gamecomplete_mounted = false;
levelcomplete_mounted = false;
flipgamecomplete_mounted = false;
fliplevelcomplete_mounted = false;
SDL_zeroa(error);
SDL_zeroa(error_title);
}
void Graphics::destroy(void)
{
#define CLEAR_ARRAY(name) \
for (size_t i = 0; i < name.size(); i += 1) \
{ \
VVV_freefunc(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
}
void Graphics::create_buffers(const SDL_PixelFormat* fmt)
{
#define CREATE_SURFACE(w, h) \
SDL_CreateRGBSurface( \
SDL_SWSURFACE, \
w, h, \
fmt->BitsPerPixel, \
fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask \
)
backBuffer = CREATE_SURFACE(320, 240);
SDL_SetSurfaceBlendMode(backBuffer, SDL_BLENDMODE_NONE);
footerbuffer = CREATE_SURFACE(320, 10);
SDL_SetSurfaceBlendMode(footerbuffer, SDL_BLENDMODE_BLEND);
SDL_SetSurfaceAlphaMod(footerbuffer, 127);
FillRect(footerbuffer, 0, 0, 0);
roomname_translator::dimbuffer = CREATE_SURFACE(320, 240);
SDL_SetSurfaceBlendMode(roomname_translator::dimbuffer, SDL_BLENDMODE_BLEND);
SDL_SetSurfaceAlphaMod(roomname_translator::dimbuffer, 96);
FillRect(roomname_translator::dimbuffer, 0, 0, 0);
ghostbuffer = CREATE_SURFACE(320, 240);
SDL_SetSurfaceBlendMode(ghostbuffer, SDL_BLENDMODE_BLEND);
SDL_SetSurfaceAlphaMod(ghostbuffer, 127);
foregroundBuffer = CREATE_SURFACE(320, 240);
SDL_SetSurfaceBlendMode(foregroundBuffer, SDL_BLENDMODE_BLEND);
menubuffer = CREATE_SURFACE(320, 240);
SDL_SetSurfaceBlendMode(menubuffer, SDL_BLENDMODE_NONE);
warpbuffer = CREATE_SURFACE(320 + 16, 240 + 16);
SDL_SetSurfaceBlendMode(warpbuffer, SDL_BLENDMODE_NONE);
warpbuffer_lerp = CREATE_SURFACE(320 + 16, 240 + 16);
SDL_SetSurfaceBlendMode(warpbuffer_lerp, SDL_BLENDMODE_NONE);
towerbg.buffer = CREATE_SURFACE(320 + 16, 240 + 16);
SDL_SetSurfaceBlendMode(towerbg.buffer, SDL_BLENDMODE_NONE);
towerbg.buffer_lerp = CREATE_SURFACE(320 + 16, 240 + 16);
SDL_SetSurfaceBlendMode(towerbg.buffer_lerp, SDL_BLENDMODE_NONE);
titlebg.buffer = CREATE_SURFACE(320 + 16, 240 + 16);
SDL_SetSurfaceBlendMode(titlebg.buffer, SDL_BLENDMODE_NONE);
titlebg.buffer_lerp = CREATE_SURFACE(320 + 16, 240 + 16);
SDL_SetSurfaceBlendMode(titlebg.buffer_lerp, SDL_BLENDMODE_NONE);
tempBuffer = CREATE_SURFACE(320, 240);
SDL_SetSurfaceBlendMode(tempBuffer, SDL_BLENDMODE_NONE);
#undef CREATE_SURFACE
}
void Graphics::destroy_buffers(void)
{
#define FREE_SURFACE(SURFACE) VVV_freefunc(SDL_FreeSurface, SURFACE)
FREE_SURFACE(backBuffer);
FREE_SURFACE(footerbuffer);
FREE_SURFACE(roomname_translator::dimbuffer);
FREE_SURFACE(ghostbuffer);
FREE_SURFACE(foregroundBuffer);
FREE_SURFACE(menubuffer);
FREE_SURFACE(warpbuffer);
FREE_SURFACE(warpbuffer_lerp);
FREE_SURFACE(towerbg.buffer);
FREE_SURFACE(towerbg.buffer_lerp);
FREE_SURFACE(titlebg.buffer);
FREE_SURFACE(titlebg.buffer_lerp);
FREE_SURFACE(tempBuffer);
#undef FREE_SURFACE
}
int Graphics::font_idx(uint32_t ch)
{
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())
{
WHINE_ONCE("font.txt missing fallback character!");
return -1;
}
}
return iter->second;
}
else
{
return ch;
}
}
void Graphics::drawspritesetcol(int x, int y, int t, int c)
{
if (!INBOUNDS_VEC(t, sprites))
{
return;
}
SDL_Rect rect;
setRect(rect,x,y,sprites_rect.w,sprites_rect.h);
setcol(c);
BlitSurfaceColoured(sprites[t],NULL,backBuffer, &rect, ct);
}
void Graphics::updatetitlecolours(void)
{
setcol(15);
col_crewred = ct;
setcol(14);
col_crewyellow = ct;
setcol(13);
col_crewgreen = ct;
setcol(0);
col_crewcyan = ct;
setcol(16);
col_crewblue = ct;
setcol(20);
col_crewpurple = ct;
setcol(19);
col_crewinactive = ct;
setcol(18);
col_clock = ct;
setcol(18);
col_trinket = ct;
}
#define PROCESS_TILESHEET_CHECK_ERROR(tilesheet, tile_square) \
if (grphx.im_##tilesheet == NULL) \
{ \
/* We have already asserted; just no-op. */ \
} \
else if (grphx.im_##tilesheet->w % tile_square != 0 \
|| grphx.im_##tilesheet->h % tile_square != 0) \
{ \
static const char error_fmt[] = "%s.png dimensions not exact multiples of %i!"; \
static const char error_title_fmt[] = "Error with %s.png"; \
\
SDL_snprintf(error, sizeof(error), error_fmt, #tilesheet, tile_square); \
SDL_snprintf(error_title, sizeof(error_title), error_title_fmt, #tilesheet); \
\
vlog_error("%s", error); \
\
return false; \
}
#define PROCESS_TILESHEET_RENAME(tilesheet, vector, tile_square, extra_code) \
PROCESS_TILESHEET_CHECK_ERROR(tilesheet, tile_square) \
\
else \
{ \
int j; \
for (j = 0; j < grphx.im_##tilesheet->h / tile_square; ++j) \
{ \
int i; \
for (i = 0; i < grphx.im_##tilesheet->w / tile_square; ++i) \
{ \
SDL_Surface* temp = GetSubSurface( \
grphx.im_##tilesheet, \
i * tile_square, j * tile_square, \
tile_square, tile_square \
); \
vector.push_back(temp); \
\
extra_code \
} \
} \
\
VVV_freefunc(SDL_FreeSurface, grphx.im_##tilesheet); \
}
#define PROCESS_TILESHEET(tilesheet, tile_square, extra_code) \
PROCESS_TILESHEET_RENAME(tilesheet, tilesheet, tile_square, extra_code)
bool Graphics::Makebfont(void)
{
PROCESS_TILESHEET(bfont, 8,
{
SDL_Surface* TempFlipped = FlipSurfaceVerticle(temp);
flipbfont.push_back(TempFlipped);
})
unsigned char* charmap = NULL;
size_t length;
if (FILESYSTEM_areAssetsInSameRealDir("graphics/font.png", "graphics/font.txt"))
{
FILESYSTEM_loadAssetToMemory("graphics/font.txt", &charmap, &length, false);
}
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;
}
VVV_free(charmap);
}
else
{
font_positions.clear();
}
return true;
}
int Graphics::bfontlen(uint32_t ch)
{
if (ch < 32)
{
return 6;
}
else
{
return 8;
}
}
bool Graphics::MakeTileArray(void)
{
PROCESS_TILESHEET(tiles, 8, {})
PROCESS_TILESHEET(tiles2, 8, {})
PROCESS_TILESHEET(tiles3, 8, {})
PROCESS_TILESHEET(entcolours, 8, {})
return true;
}
bool Graphics::maketelearray(void)
{
PROCESS_TILESHEET_RENAME(teleporter, tele, 96, {})
return true;
}
bool Graphics::MakeSpriteArray(void)
{
PROCESS_TILESHEET(sprites, 32, {})
PROCESS_TILESHEET(flipsprites, 32, {})
return true;
}
#undef PROCESS_TILESHEET
#undef PROCESS_TILESHEET_RENAME
#undef PROCESS_TILESHEET_CHECK_ERROR
void Graphics::map_tab(int opt, const char* text, bool selected /*= false*/)
{
int x = opt*80 + 40;
if (selected)
{
char buffer[SCREEN_WIDTH_CHARS + 1];
vformat_buf(buffer, sizeof(buffer), loc::get_langmeta()->menu_select_tight.c_str(), "label:str", text);
Print(x - len(buffer)/2, 220, buffer, 196, 196, 255 - help.glow);
}
else
{
Print(x - len(text)/2, 220, text, 64, 64, 64);
}
}
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)
{
std::string text_upper(loc::toupper(text));
char buffer[SCREEN_WIDTH_CHARS + 1];
vformat_buf(buffer, sizeof(buffer), loc::get_langmeta()->menu_select.c_str(), "label:str", text_upper.c_str());
Print(x - 16, y, buffer, 196, 196, 255 - help.glow);
}
else
{
Print(x, y, loc::remove_toupper_escape_chars(text), 96, 96, 96);
}
}
static void print_char(
SDL_Surface* const buffer,
SDL_Surface* const font,
const int x,
const int y,
const int scale,
const SDL_Color color
) {
SDL_Rect font_rect = {x, y, 8*scale, 8*scale};
SDL_Surface* surface;
if (scale > 1)
{
surface = ScaleSurface(font, 8 * scale, 8 * scale);
if (surface == NULL)
{
return;
}
}
else
{
surface = font;
}
BlitSurfaceColoured(surface, NULL, buffer, &font_rect, color);
if (scale > 1)
{
VVV_freefunc(SDL_FreeSurface, surface);
}
}
void Graphics::do_print(
const int x,
const int y,
const std::string& text,
int r,
int g,
int b,
int a,
const int scale
) {
std::vector<SDL_Surface*>& font = flipmode ? flipbfont : bfont;
int position = 0;
std::string::const_iterator iter = text.begin();
r = SDL_clamp(r, 0, 255);
g = SDL_clamp(g, 0, 255);
b = SDL_clamp(b, 0, 255);
a = SDL_clamp(a, 0, 255);
ct = getRGBA(r, g, b, a);
while (iter != text.end())
{
const uint32_t character = utf8::unchecked::next(iter);
const int idx = font_idx(character);
if (INBOUNDS_VEC(idx, font))
{
print_char(backBuffer, font[idx], x + position, y, scale, ct);
}
position += bfontlen(character) * scale;
}
}
void Graphics::Print( int _x, int _y, const 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, const std::string& _s, int r, int g, int b, int a, bool cen /*= false*/ )
{
if (cen)
_x = ((160 ) - ((len(_s)) / 2));
return do_print(_x, _y, _s, r, g, b, a, 1);
}
bool Graphics::next_wrap(
size_t* start,
size_t* len,
const char* str,
const int maxwidth
) {
/* This function is UTF-8 aware. But start/len still are bytes. */
size_t idx = 0;
size_t lenfromlastspace = 0;
size_t lastspace = 0;
int linewidth = 0;
*len = 0;
if (str[idx] == '\0')
{
return false;
}
while (true)
{
/* FIXME: This only checks one byte, not multiple! */
if ((str[idx] & 0xC0) == 0x80)
{
/* Skip continuation byte. */
goto next;
}
linewidth += bfontlen(str[idx]);
switch (str[idx])
{
case ' ':
if (loc::get_langmeta()->autowordwrap)
{
lenfromlastspace = idx;
lastspace = *start;
}
break;
case '\n':
case '|':
*start += 1;
SDL_FALLTHROUGH;
case '\0':
return true;
}
if (linewidth > maxwidth)
{
if (lenfromlastspace != 0)
{
*len = lenfromlastspace;
*start = lastspace + 1;
}
return true;
}
next:
idx += 1;
*start += 1;
*len += 1;
}
}
bool Graphics::next_wrap_s(
char buffer[],
const size_t buffer_size,
size_t* start,
const char* str,
const int maxwidth
) {
size_t len = 0;
const size_t prev_start = *start;
const bool retval = next_wrap(start, &len, &str[*start], maxwidth);
if (retval)
{
/* Like next_split_s(), don't use SDL_strlcpy() here. */
const size_t length = SDL_min(buffer_size - 1, len);
SDL_memcpy(buffer, &str[prev_start], length);
buffer[length] = '\0';
}
return retval;
}
int Graphics::PrintWrap(
const int x,
int y,
std::string s,
const int r,
const int g,
const int b,
const bool cen /*= false*/,
int linespacing /*= -1*/,
int maxwidth /*= -1*/
) {
if (linespacing == -1)
{
linespacing = 10;
}
linespacing = SDL_max(linespacing, loc::get_langmeta()->font_h);
if (maxwidth == -1)
{
maxwidth = 304;
}
const char* str = s.c_str();
/* Screen width is 320 pixels. The shortest a char can be is 6 pixels wide.
* 320 / 6 is 54, rounded up. 4 bytes per char. */
char buffer[54*4 + 1];
size_t start = 0;
if (flipmode)
{
/* Correct for the height of the resulting print. */
size_t len = 0;
while (next_wrap(&start, &len, &str[start], maxwidth))
{
y += linespacing;
}
y -= linespacing;
start = 0;
}
while (next_wrap_s(buffer, sizeof(buffer), &start, str, maxwidth))
{
Print(x, y, buffer, r, g, b, cen);
if (flipmode)
{
y -= linespacing;
}
else
{
y += linespacing;
}
}
return y + linespacing;
}
void Graphics::bigprint( int _x, int _y, const std::string& _s, int r, int g, int b, bool cen, int sc )
{
if (cen)
{
const int len_ = len(_s);
_x = SDL_max(160 - (int((len_/ 2.0)*sc)), 0 );
}
return do_print(_x, _y, _s, r, g, b, 255, sc);
}
void Graphics::bigbprint(int x, int y, const std::string& s, int r, int g, int b, bool cen, int sc)
{
if (!notextoutline)
{
bigprint(x, y - sc, s, 0, 0, 0, cen, sc);
if (cen)
{
const int len_ = len(s);
int x_cen = SDL_max(160 - (len_ / 2) * sc, 0);
bigprint(x_cen - sc, y, s, 0, 0, 0, false, sc);
bigprint(x_cen + sc, y, s, 0, 0, 0, false, sc);
}
else
{
bigprint(x - sc, y, s, 0, 0, 0, cen, sc);
bigprint(x + sc, y, s, 0, 0, 0, cen, sc);
}
bigprint(x, y + sc, s, 0, 0, 0, cen, sc);
}
bigprint(x, y, s, r, g, b, cen, sc);
}
int Graphics::len(const std::string& t)
{
int bfontpos = 0;
std::string::const_iterator iter = t.begin();
while (iter != t.end()) {
int cur = utf8::unchecked::next(iter);
bfontpos += bfontlen(cur);
}
return bfontpos;
}
std::string Graphics::string_wordwrap(const std::string& s, int maxwidth, short *lines /*= NULL*/)
{
// Return a string wordwrapped to a maximum limit by adding newlines.
// CJK will need to have autowordwrap disabled and have manually inserted newlines.
if (lines != NULL)
{
*lines = 1;
}
const char* orig = s.c_str();
std::string result;
size_t start = 0;
bool first = true;
while (true)
{
size_t len = 0;
const char* part = &orig[start];
const bool retval = next_wrap(&start, &len, part, maxwidth);
if (!retval)
{
return result;
}
if (first)
{
first = false;
}
else
{
result.push_back('\n');
if (lines != NULL)
{
(*lines)++;
}
}
result.append(part, len);
}
}
std::string Graphics::string_wordwrap_balanced(const std::string& s, int maxwidth)
{
// Return a string wordwrapped to a limit of maxwidth by adding newlines.
// Try to fill the lines as far as possible, and return result where lines are most filled.
// Goal is to have all lines in textboxes be about as long and to avoid wrapping just one word to a new line.
// CJK will need to have autowordwrap disabled and have manually inserted newlines.
if (!loc::get_langmeta()->autowordwrap)
{
return s;
}
short lines;
string_wordwrap(s, maxwidth, &lines);
int bestwidth = maxwidth;
if (lines > 1)
{
for (int curlimit = maxwidth; curlimit > 1; curlimit -= 8)
{
short try_lines;
string_wordwrap(s, curlimit, &try_lines);
if (try_lines > lines)
{
bestwidth = curlimit + 8;
break;
}
}
}
return string_wordwrap(s, bestwidth);
}
std::string Graphics::string_unwordwrap(const std::string& s)
{
/* Takes a string wordwrapped by newlines, and turns it into a single line, undoing the wrapping.
* Also trims any leading/trailing whitespace and collapses multiple spaces into one (to undo manual centering)
* Only applied to English, so langmeta.autowordwrap isn't used here (it'd break looking up strings) */
std::string result;
std::back_insert_iterator<std::string> inserter = std::back_inserter(result);
std::string::const_iterator iter = s.begin();
bool latest_was_space = true; // last character was a space (or the beginning, don't want leading whitespace)
int consecutive_newlines = 0; // number of newlines currently encountered in a row (multiple newlines should stay!)
while (iter != s.end())
{
uint32_t ch = utf8::unchecked::next(iter);
if (ch == '\n')
{
if (consecutive_newlines == 0)
{
ch = ' ';
}
else if (consecutive_newlines == 1)
{
// The last character was already a newline, so change it back from the space we thought it should have become.
result[result.size()-1] = '\n';
}
consecutive_newlines++;
}
else
{
consecutive_newlines = 0;
}
if (ch != ' ' || !latest_was_space)
{
utf8::unchecked::append(ch, inserter);
}
latest_was_space = (ch == ' ' || ch == '\n');
}
// We could have one trailing space
if (!result.empty() && result[result.size()-1] == ' ')
{
result.erase(result.end()-1);
}
return result;
}
void Graphics::bprint( int x, int y, const 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, const std::string& t, int r, int g, int b, int a, bool cen /*= false*/ )
{
if (!notextoutline)
{
PrintAlpha(x, y - 1, t, 0, 0, 0, a, cen);
if (cen)
{
const int x_cen = 160 - len(t)/2;
PrintAlpha(x_cen - 1, y, t, 0, 0, 0, a, false);
PrintAlpha(x_cen + 1, y, t, 0, 0, 0, a, false);
}
else
{
PrintAlpha(x -1, y, t, 0, 0, 0, a, cen);
PrintAlpha(x +1, y, t, 0, 0, 0, a, cen);
}
PrintAlpha(x, y+1, t, 0, 0, 0, a, cen);
}
PrintAlpha(x, y, t, r, g, b, a, cen);
}
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, loc::gettext("Viridian"), 16, 240, 240,false);
break;
case 1:
Print(x, y, loc::gettext("Violet"), 240, 16, 240,false);
break;
case 2:
Print(x, y, loc::gettext("Vitellary"), 240, 240, 16,false);
break;
case 3:
Print(x, y, loc::gettext("Vermilion"), 240, 16, 16,false);
break;
case 4:
Print(x, y, loc::gettext("Verdigris"), 16, 240, 16,false);
break;
case 5:
Print(x, y, loc::gettext("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, loc::gettext("Viridian"), 128,128,128,false);
break;
case 1:
Print(x, y, loc::gettext("Violet"), 128,128,128,false);
break;
case 2:
Print(x, y, loc::gettext("Vitellary"), 128,128,128,false);
break;
case 3:
Print(x, y, loc::gettext("Vermilion"), 128,128,128,false);
break;
case 4:
Print(x, y, loc::gettext("Verdigris"), 128,128,128,false);
break;
case 5:
Print(x, y, loc::gettext("Victoria"), 128,128,128,false);
break;
}
}
void Graphics::printcrewnamestatus( int x, int y, int t, bool rescued )
{
//Print the status of crew member t in the right colour
int r, g, b;
char gender;
switch(t)
{
case 0:
r=12; g=140, b=140;
gender = 3;
break;
case 1:
r=140; g=12; b=140;
gender = 2;
break;
case 2:
r=140; g=140; b=12;
gender = 1;
break;
case 3:
r=140; g=12; b=12;
gender = 1;
break;
case 4:
r=12; g=140; b=12;
gender = 1;
break;
case 5:
r=12; g=12; b=140;
gender = 2;
break;
default:
return;
}
const char* status_text;
if (gender == 3 && rescued)
{
status_text = loc::gettext("(that's you!)");
}
else if (rescued)
{
status_text = loc::gettext_case("Rescued!", gender);
}
else
{
r=64; g=64; b=64;
status_text = loc::gettext_case("Missing...", gender);
}
Print(x, y, status_text, r, g, b, false);
}
void Graphics::drawsprite( int x, int y, int t, int r, int g, int b )
{
if (!INBOUNDS_VEC(t, sprites))
{
WHINE_ONCE("drawsprite() out-of-bounds!");
return;
}
SDL_Rect rect = {x, y, sprites_rect.w, sprites_rect.h};
setcolreal(getRGB(r,g,b));
BlitSurfaceColoured(sprites[t], NULL, backBuffer, &rect, ct);
}
void Graphics::drawsprite(int x, int y, int t, const SDL_Color color)
{
if (!INBOUNDS_VEC(t, sprites))
{
WHINE_ONCE("drawsprite() out-of-bounds!");
return;
}
SDL_Rect rect = {x, y, sprites_rect.w, sprites_rect.h};
setcolreal(color);
BlitSurfaceColoured(sprites[t], NULL, backBuffer, &rect, ct);
}
#ifndef NO_CUSTOM_LEVELS
bool Graphics::shouldrecoloroneway(const int tilenum, const bool mounted)
{
return (tilenum >= 14 && tilenum <= 17
&& (!mounted
|| cl.onewaycol_override));
}
#endif
void Graphics::drawtile( int x, int y, int t )
{
if (!INBOUNDS_VEC(t, tiles))
{
WHINE_ONCE("drawtile() out-of-bounds!");
return;
}
SDL_Rect rect = {x, y, tiles_rect.w, tiles_rect.h};
#if !defined(NO_CUSTOM_LEVELS)
if (shouldrecoloroneway(t, tiles1_mounted))
{
const SDL_Color thect = cl.getonewaycol();
BlitSurfaceTinted(tiles[t], NULL, backBuffer, &rect, thect);
}
else
#endif
{
BlitSurfaceStandard(tiles[t], NULL, backBuffer, &rect);
}
}
void Graphics::drawtile2( int x, int y, int t )
{
if (!INBOUNDS_VEC(t, tiles2))
{
WHINE_ONCE("drawtile2() out-of-bounds!");
return;
}
SDL_Rect rect = {x, y, tiles_rect.w, tiles_rect.h};
#if !defined(NO_CUSTOM_LEVELS)
if (shouldrecoloroneway(t, tiles2_mounted))
{
const SDL_Color thect = cl.getonewaycol();
BlitSurfaceTinted(tiles2[t], NULL, backBuffer, &rect, thect);
}
else
#endif
{
BlitSurfaceStandard(tiles2[t], NULL, backBuffer, &rect);
}
}
void Graphics::drawtile3( int x, int y, int t, int off, int height_subtract /*= 0*/ )
{
t += off * 30;
if (!INBOUNDS_VEC(t, tiles3))
{
WHINE_ONCE("drawtile3() out-of-bounds!");
return;
}
SDL_Rect src_rect = { 0, 0, tiles_rect.w, tiles_rect.h - height_subtract };
SDL_Rect rect = {x, y, tiles_rect.w, tiles_rect.h};
BlitSurfaceStandard(tiles3[t], &src_rect, backBuffer, &rect);
}
void Graphics::drawtowertile( int x, int y, int t )
{
if (!INBOUNDS_VEC(t, tiles2))
{
WHINE_ONCE("drawtowertile() out-of-bounds!");
return;
}
x += 8;
y += 8;
SDL_Rect rect = {x, y, tiles_rect.w, tiles_rect.h};
BlitSurfaceStandard(tiles2[t], NULL, warpbuffer, &rect);
}
void Graphics::drawtowertile3( int x, int y, int t, TowerBG& bg_obj )
{
t += bg_obj.colstate*30;
if (!INBOUNDS_VEC(t, tiles3))
{
WHINE_ONCE("drawtowertile3() out-of-bounds!");
return;
}
x += 8;
y += 8;
SDL_Rect rect = {x, y, tiles_rect.w, tiles_rect.h};
BlitSurfaceStandard(tiles3[t], NULL, bg_obj.buffer, &rect);
}
void Graphics::drawgui(void)
{
int text_sign;
int crew_yp;
int crew_sprite;
size_t i;
if (flipmode)
{
text_sign = -1;
crew_yp = 64 + 48 + 4;
crew_sprite = 6;
}
else
{
text_sign = 1;
crew_yp = 64 + 32 + 4;
crew_sprite = 0;
}
//Draw all the textboxes to the screen
for (i = 0; i<textboxes.size(); i++)
{
int text_yoff;
int yp;
bool opaque;
if (flipmode)
{
text_yoff = textboxes[i].lines.size() * 8;
}
else
{
text_yoff = 8;
}
yp = textboxes[i].yp;
if (flipmode && textboxes[i].flipme)
{
yp = SCREEN_HEIGHT_PIXELS - yp - 8 * (textboxes[i].lines.size() + 2);
}
if (textboxes[i].r == 0 && textboxes[i].g == 0 && textboxes[i].b == 0)
{
size_t j;
for (j = 0; j < textboxes[i].lines.size(); j++)
{
bprint(textboxes[i].xp + 8, yp + text_yoff + text_sign * (j * 8), textboxes[i].lines[j], 196, 196, 255 - help.glow);
}
}
else
{
const float tl_lerp = lerp(textboxes[i].prev_tl, textboxes[i].tl);
const int r = textboxes[i].r * tl_lerp;
const int g = textboxes[i].g * tl_lerp;
const int b = textboxes[i].b * tl_lerp;
size_t j;
drawtextbox(textboxes[i].xp, yp, textboxes[i].w/8, textboxes[i].h/8, r, g, b);
for (j = 0; j < textboxes[i].lines.size(); j++)
{
Print(textboxes[i].xp + 8, yp + text_yoff + text_sign * (j * 8), textboxes[i].lines[j], r, g, b);
}
}
opaque = textboxes[i].tl >= 1.0;
if (!opaque)
{
continue;
}
if (textboxes[i].yp == 12 && textboxes[i].r == 165)
{
// Level complete
const char* english = "Level Complete!";
const char* translation = loc::gettext(english);
if (SDL_strcmp(english, translation) != 0
&& !(flipmode && fliplevelcomplete_mounted)
&& !(!flipmode && levelcomplete_mounted)
)
{
int sc = 2;
int y = 28;
if (len(translation) > 144)
{
// We told translators how long it could be... Ah well, mitigate the damage.
sc = 1;
y += 4;
}
if (flipmode)
{
y = 240 - y - 8*sc;
}
bigprint(-1, y, translation, 164, 164, 255, true, sc);
}
else
{
if (flipmode)
{
drawimage(5, 0, 180, true);
}
else
{
drawimage(0, 0, 12, true);
}
}
}
else if (textboxes[i].yp == 12 && textboxes[i].g == 165)
{
// Game complete
const char* english = "Game Complete!";
const char* translation = loc::gettext(english);
if (SDL_strcmp(english, translation) != 0
&& !(flipmode && flipgamecomplete_mounted)
&& !(!flipmode && gamecomplete_mounted)
)
{
int sc = 2;
int y = 28;
if (len(translation) > 144)
{
// We told translators how long it could be... Ah well, mitigate the damage.
sc = 1;
y += 4;
}
if (flipmode)
{
y = 240 - y - 8*sc;
}
bigprint(-1, y, translation, 164, 164, 255, true, sc);
}
else
{
if (flipmode)
{
drawimage(6, 0, 180, true);
}
else
{
drawimage(4, 0, 12, true);
}
}
}
int crew_xp = textboxes[i].xp+20 - 6;
if (textboxes[i].r == 175 && textboxes[i].g == 175)
{
//purple guy
drawsprite(crew_xp, crew_yp, crew_sprite, 220- help.glow/4 - textboxes[i].rand, 120- help.glow/4, 210 - help.glow/4);
}
else if (textboxes[i].r == 175 && textboxes[i].b == 175)
{
//red guy
drawsprite(crew_xp, crew_yp, crew_sprite, 255 - help.glow/8, 70 - help.glow/4, 70 - help.glow / 4);
}
else if (textboxes[i].r == 175)
{
//green guy
drawsprite(crew_xp, crew_yp, crew_sprite, 120 - help.glow / 4 - textboxes[i].rand, 220 - help.glow / 4, 120 - help.glow / 4);
}
else if (textboxes[i].g == 175)
{
//yellow guy
drawsprite(crew_xp, crew_yp, crew_sprite, 220- help.glow/4 - textboxes[i].rand, 210 - help.glow/4, 120- help.glow/4);
}
else if (textboxes[i].b == 175)
{
//blue guy
drawsprite(crew_xp, crew_yp, crew_sprite, 75, 75, 255- help.glow/4 - textboxes[i].rand);
}
}
}
void Graphics::updatetextboxes(void)
{
for (size_t i = 0; i < textboxes.size(); i++)
{
textboxes[i].update();
if (textboxes[i].tm == 2 && textboxes[i].tl <= 0.5)
{
textboxes.erase(textboxes.begin() + i);
i--;
continue;
}
if (textboxes[i].tl >= 1.0f
&& ((textboxes[i].r == 175 && textboxes[i].g == 175)
|| textboxes[i].r == 175
|| textboxes[i].g == 175
|| textboxes[i].b == 175)
&& (textboxes[i].r != 175 || textboxes[i].b != 175))
{
textboxes[i].rand = fRandom() * 20;
}
}
}
void Graphics::drawimagecol( int t, int xp, int yp, bool cent/*= false*/ )
{
if (!INBOUNDS_VEC(t, images) || images[t] == NULL)
{
return;
}
SDL_Rect trect;
point tpoint;
if (cent)
{
tpoint.x = 160 - int(images[t]->w / 2);
tpoint.y = yp;
trect.x = tpoint.x ;
trect.y = tpoint.y;
trect.w = images[t]->w;
trect.h= images[t]->h;
BlitSurfaceColoured(images[t], NULL, backBuffer, &trect, ct);
}
else
{
trect.x = xp;
trect.y = yp;
trect.w = images[t]->w;
trect.h = images[t]->h;
BlitSurfaceColoured(images[t], NULL, backBuffer, &trect, ct);
}
}
void Graphics::drawimage( int t, int xp, int yp, bool cent/*=false*/ )
{
if (!INBOUNDS_VEC(t, images) || images[t] == NULL)
{
return;
}
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)
{
if (!INBOUNDS_VEC(t, images) || images[t] == NULL)
{
return;
}
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(void)
{
const int usethispos = lerp(oldcutscenebarspos, cutscenebarspos);
if (showcutscenebars)
{
FillRect(backBuffer, 0, 0, usethispos, 16, 0, 0, 0);
FillRect(backBuffer, 360-usethispos, 224, usethispos, 16, 0, 0, 0);
}
else if (cutscenebarspos > 0) //disappearing
{
//draw
FillRect(backBuffer, 0, 0, usethispos, 16, 0, 0, 0);
FillRect(backBuffer, 360-usethispos, 224, usethispos, 16, 0, 0, 0);
}
}
void Graphics::cutscenebarstimer(void)
{
oldcutscenebarspos = cutscenebarspos;
if (showcutscenebars)
{
cutscenebarspos += 25;
cutscenebarspos = SDL_min(cutscenebarspos, 361);
}
else if (cutscenebarspos > 0)
{
//disappearing
cutscenebarspos -= 25;
cutscenebarspos = SDL_max(cutscenebarspos, 0);
}
}
void Graphics::setbars(const int position)
{
cutscenebarspos = position;
oldcutscenebarspos = position;
}
void Graphics::drawcrewman( int x, int y, int t, bool act, bool noshift /*=false*/ )
{
if (!act)
{
if (noshift)
{
if (flipmode)
{
drawsprite(x, y, 14, col_crewinactive);
}
else
{
drawsprite(x, y, 12, col_crewinactive);
}
}
else
{
if (flipmode)
{
drawsprite(x - 8, y, 14, col_crewinactive);
}
else
{
drawsprite(x - 8, y, 12, col_crewinactive);
}
}
}
else
{
if (flipmode) crewframe += 6;
switch(t)
{
case 0:
drawsprite(x, y, crewframe, col_crewcyan);
break;
case 1:
drawsprite(x, y, crewframe, col_crewpurple);
break;
case 2:
drawsprite(x, y, crewframe, col_crewyellow);
break;
case 3:
drawsprite(x, y, crewframe, col_crewred);
break;
case 4:
drawsprite(x, y, crewframe, col_crewgreen);
break;
case 5:
drawsprite(x, y, crewframe, col_crewblue);
break;
}
if (flipmode) crewframe -= 6;
}
}
void Graphics::drawpixeltextbox(
const int x,
const int y,
const int w,
const int h,
const int r,
const int g,
const int b
) {
int k;
FillRect(backBuffer, x, y, w, h, r/6, g/6, b/6);
/* Horizontal tiles */
for (k = 0; k < w/8 - 2; ++k)
{
drawcoloredtile(x + 8 + k*8, y, 41, r, g, b);
drawcoloredtile(x + 8 + k*8, y + h - 8, 46, r, g, b);
}
if (w % 8 != 0)
{
/* Fill in horizontal gap */
drawcoloredtile(x + w - 16, y, 41, r, g, b);
drawcoloredtile(x + w - 16, y + h - 8, 46, r, g, b);
}
/* Vertical tiles */
for (k = 0; k < h/8 - 2; ++k)
{
drawcoloredtile(x, y + 8 + k*8, 43, r, g, b);
drawcoloredtile(x + w - 8, y + 8 + k*8, 44, r, g, b);
}
if (h % 8 != 0)
{
/* Fill in vertical gap */
drawcoloredtile(x, y + h - 16, 43, r, g, b);
drawcoloredtile(x + w - 8, y + h - 16, 44, r, g, b);
}
/* Corners */
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(
const int x,
const int y,
const int w,
const int h,
const int r,
const int g,
const int b
) {
return drawpixeltextbox(x, y, w*8, h*8, r, g, b);
}
void Graphics::textboxactive(void)
{
//Remove all but the most recent textbox
for (int i = 0; i < (int) textboxes.size(); i++)
{
if (m != i) textboxes[i].remove();
}
}
void Graphics::textboxremovefast(void)
{
//Remove all textboxes
for (size_t i = 0; i < textboxes.size(); i++)
{
textboxes[i].removefast();
}
}
void Graphics::textboxremove(void)
{
//Remove all textboxes
for (size_t i = 0; i < textboxes.size(); i++)
{
textboxes[i].remove();
}
}
void Graphics::textboxtimer( int t )
{
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxtimer() out-of-bounds!");
return;
}
textboxes[m].timer=t;
}
void Graphics::addline( const std::string& t )
{
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("addline() out-of-bounds!");
return;
}
textboxes[m].addline(t);
}
void Graphics::textboxadjust(void)
{
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxadjust() out-of-bounds!");
return;
}
textboxes[m].adjust();
}
void Graphics::createtextboxreal(
const std::string& t,
int xp,
int yp,
int r,
int g,
int b,
bool flipme
) {
m = textboxes.size();
if(m<20)
{
textboxclass text;
text.lines.push_back(t);
text.xp = xp;
int length = utf8::unchecked::distance(t.begin(), t.end());
if (xp == -1) text.xp = 160 - (((length / 2) + 1) * 8);
text.yp = yp;
text.initcol(r, g, b);
text.flipme = flipme;
text.resize();
textboxes.push_back(text);
}
}
void Graphics::createtextbox(
const std::string& t,
int xp,
int yp,
int r,
int g,
int b
) {
createtextboxreal(t, xp, yp, r, g, b, false);
}
void Graphics::createtextboxflipme(
const std::string& t,
int xp,
int yp,
int r,
int g,
int b
) {
createtextboxreal(t, xp, yp, r, g, b, true);
}
void Graphics::drawfade(void)
{
const int usethisamount = lerp(oldfadeamount, fadeamount);
switch (fademode)
{
case FADE_FULLY_BLACK:
case FADE_START_FADEIN:
ClearSurface(backBuffer);
break;
case FADE_FADING_OUT:
for (size_t i = 0; i < SDL_arraysize(fadebars); i++)
{
FillRect(backBuffer, fadebars[i], i * 16, usethisamount, 16, 0, 0, 0);
}
break;
case FADE_FADING_IN:
for (size_t i = 0; i < SDL_arraysize(fadebars); i++)
{
FillRect(backBuffer, fadebars[i]-usethisamount, i * 16, 500, 16, 0, 0, 0);
}
break;
case FADE_NONE:
case FADE_START_FADEOUT:
break;
}
}
void Graphics::processfade(void)
{
oldfadeamount = fadeamount;
switch (fademode)
{
case FADE_START_FADEOUT:
for (size_t i = 0; i < SDL_arraysize(fadebars); i++)
{
fadebars[i] = -int(fRandom() * 12) * 8;
}
setfade(0);
fademode = FADE_FADING_OUT;
break;
case FADE_FADING_OUT:
fadeamount += 24;
if (fadeamount > 416)
{
fademode = FADE_FULLY_BLACK;
}
break;
case FADE_START_FADEIN:
for (size_t i = 0; i < SDL_arraysize(fadebars); i++)
{
fadebars[i] = 320 + int(fRandom() * 12) * 8;
}
setfade(416);
fademode = FADE_FADING_IN;
break;
case FADE_FADING_IN:
fadeamount -= 24;
if (fadeamount <= 0)
{
fademode = FADE_NONE;
}
break;
case FADE_NONE:
case FADE_FULLY_BLACK:
break;
}
}
void Graphics::setfade(const int amount)
{
fadeamount = amount;
oldfadeamount = amount;
}
void Graphics::drawmenu(int cr, int cg, int cb, enum Menu::MenuName menu)
{
/* The MenuName is only used for some special cases,
* like the levels list and the language screen. */
bool language_screen = menu == Menu::language && !loc::languagelist.empty();
unsigned int twocol_voptions;
if (language_screen)
{
size_t n_options = game.menuoptions.size();
twocol_voptions = n_options - (n_options/2);
}
for (size_t i = 0; i < game.menuoptions.size(); i++)
{
MenuOption& opt = game.menuoptions[i];
int fr, fg, fb;
if (opt.active)
{
// Color it normally
fr = cr;
fg = cg;
fb = cb;
}
else
{
// Color it gray
fr = 128;
fg = 128;
fb = 128;
}
int x, y;
if (language_screen)
{
int name_len = len(opt.text);
x = (i < twocol_voptions ? 80 : 240) - name_len/2;
y = 36 + (i % twocol_voptions)*12;
}
else
{
x = i*game.menuspacing + game.menuxoff;
y = 140 + i*12 + game.menuyoff;
}
#ifndef NO_CUSTOM_LEVELS
if (menu == Menu::levellist)
{
size_t separator;
if (cl.ListOfMetaData.size() > 8)
{
separator = 3;
}
else
{
separator = 1;
}
if (game.menuoptions.size() - i <= separator)
{
// We're on "next page", "previous page", or "return to menu". Draw them separated by a bit
y += 8;
}
else
{
// Get out of the way of the level descriptions
y += 4;
}
}
#endif
if (menu == Menu::translator_options_cutscenetest)
{
size_t separator = 4;
if (game.menuoptions.size() - i <= separator)
{
y += 4;
}
}
char buffer[MENU_TEXT_BYTES];
if ((int) i == game.currentmenuoption && game.slidermode == SLIDER_NONE)
{
std::string opt_text;
if (opt.active)
{
// Uppercase the text
opt_text = loc::toupper(opt.text);
}
else
{
opt_text = loc::remove_toupper_escape_chars(opt.text);
}
vformat_buf(buffer, sizeof(buffer), loc::get_langmeta()->menu_select.c_str(), "label:str", opt_text.c_str());
// Account for brackets
x -= (len(buffer)-len(opt_text))/2;
}
else
{
SDL_strlcpy(buffer, loc::remove_toupper_escape_chars(opt.text).c_str(), sizeof(buffer));
}
Print(x, y, buffer, fr, fg, fb);
}
}
void Graphics::drawcoloredtile(
const int x,
const int y,
const int t,
const int r,
const int g,
const int b
) {
SDL_Rect rect;
if (!INBOUNDS_VEC(t, tiles))
{
return;
}
setcolreal(getRGB(r, g, b));
setRect(rect, x, y, tiles_rect.w, tiles_rect.h);
BlitSurfaceColoured(tiles[t], NULL, backBuffer, &rect, ct);
}
bool Graphics::Hitest(SDL_Surface* surface1, point p1, SDL_Surface* surface2, point p2)
{
//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;
SDL_Rect rect1 = {p1.x, p1.y, surface1->w, surface1->h};
SDL_Rect rect2 = {p2.x, p2.y, surface2->w, surface2->h};
bool intersection = help.intersects(rect1, rect2);
if(intersection)
{
int r3_left = SDL_max(r1_left, r2_left);
int r3_top = SDL_min(r1_top, r2_top);
int r3_right = SDL_min(r1_right, r2_right);
int r3_bottom= SDL_max(r1_bottom, r2_bottom);
//for every pixel inside rectangle
for(int x = r3_left; x < r3_right; x++)
{
for(int y = r3_bottom; y < r3_top; y++)
{
const SDL_Color pixel1 = ReadPixel(surface1, x - p1.x, y - p1.y);
const SDL_Color pixel2 = ReadPixel(surface2, x - p2.x, y - p2.y);
/* INTENTIONAL BUG! In previous versions, the game mistakenly
* checked the red channel, not the alpha channel.
* We preserve it here because some people abuse this. */
if (pixel1.r != 0 && pixel2.r != 0)
{
return true;
}
}
}
}
return false;
}
void Graphics::drawgravityline( int t )
{
if (!INBOUNDS_VEC(t, obj.entities))
{
WHINE_ONCE("drawgravityline() out-of-bounds!");
return;
}
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(245-30, 245-30, 225-30));
break;
case 2:
FillRect(backBuffer,line_rect, getRGB(225-30, 245-30, 245-30));
break;
case 3:
FillRect(backBuffer,line_rect, getRGB(200-20, 200-20, 164-10));
break;
case 4:
FillRect(backBuffer,line_rect, getRGB(196-20, 255-30, 224-20));
break;
case 5:
FillRect(backBuffer,line_rect, getRGB(196-20, 235-30, 205-20));
break;
case 6:
FillRect(backBuffer,line_rect, getRGB(164-10, 164-10, 164-10));
break;
case 7:
FillRect(backBuffer,line_rect, getRGB(205-20, 245-30, 225-30));
break;
case 8:
FillRect(backBuffer,line_rect, getRGB(225-30, 255-30, 205-20));
break;
case 9:
FillRect(backBuffer,line_rect, getRGB(245-30, 245-30, 245-30));
break;
}
}
else
{
FillRect(backBuffer,line_rect, getRGB(96, 96, 96));
}
}
void Graphics::drawtrophytext(void)
{
int temp, temp2, temp3;
if (obj.trophytext < 15)
{
const int usethismult = lerp(obj.oldtrophytext, obj.trophytext);
temp = (196 * usethismult) / 15;
temp2 = (196 * usethismult) / 15;
temp3 = ((255 - help.glow) * usethismult) / 15;
}
else
{
temp = 196;
temp2 = 196;
temp3 = 255 - help.glow;
}
/* These were originally all at the top of the screen, but might be too tight for localization.
* It probably makes sense to make them all have a top text now, but for now this is probably fine.
* Look at the Steam achievements, they have pretty logical titles that should probably be used. */
const char* top_text = NULL;
const char* bottom_text = NULL;
switch(obj.trophytype)
{
case 1:
top_text = loc::gettext("SPACE STATION 1 MASTERED");
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
break;
case 2:
top_text = loc::gettext("LABORATORY MASTERED");
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
break;
case 3:
top_text = loc::gettext("THE TOWER MASTERED");
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
break;
case 4:
top_text = loc::gettext("SPACE STATION 2 MASTERED");
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
break;
case 5:
top_text = loc::gettext("WARP ZONE MASTERED");
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
break;
case 6:
top_text = loc::gettext("FINAL LEVEL MASTERED");
bottom_text = loc::gettext("Obtain a V Rank in this Time Trial");
break;
case 7:
top_text = loc::gettext("GAME COMPLETE");
bottom_text = loc::gettext("Complete the game");
break;
case 8:
top_text = loc::gettext("FLIP MODE COMPLETE");
bottom_text = loc::gettext("Complete the game in flip mode");
break;
case 9:
bottom_text = loc::gettext("Win with less than 50 deaths");
break;
case 10:
bottom_text = loc::gettext("Win with less than 100 deaths");
break;
case 11:
bottom_text = loc::gettext("Win with less than 250 deaths");
break;
case 12:
bottom_text = loc::gettext("Win with less than 500 deaths");
break;
case 13:
bottom_text = loc::gettext("Last 5 seconds on the Super Gravitron");
break;
case 14:
bottom_text = loc::gettext("Last 10 seconds on the Super Gravitron");
break;
case 15:
bottom_text = loc::gettext("Last 15 seconds on the Super Gravitron");
break;
case 16:
bottom_text = loc::gettext("Last 20 seconds on the Super Gravitron");
break;
case 17:
bottom_text = loc::gettext("Last 30 seconds on the Super Gravitron");
break;
case 18:
bottom_text = loc::gettext("Last 1 minute on the Super Gravitron");
break;
case 20:
top_text = loc::gettext("MASTER OF THE UNIVERSE");
bottom_text = loc::gettext("Complete the game in no death mode");
break;
}
/* These were `bprint` before */
short lines;
if (top_text != NULL)
{
string_wordwrap(top_text, 304, &lines);
PrintWrap(-1, 11-(lines-1)*5, top_text, temp, temp2, temp3, true);
}
if (bottom_text != NULL)
{
string_wordwrap(bottom_text, 304, &lines);
PrintWrap(-1, 221-(lines-1)*5, bottom_text, temp, temp2, temp3, true);
}
}
void Graphics::drawentities(void)
{
const int yoff = map.towermode ? lerp(map.oldypos, map.ypos) : 0;
if (!map.custommode)
{
for (int i = obj.entities.size() - 1; i >= 0; i--)
{
if (!obj.entities[i].ishumanoid())
{
drawentity(i, yoff);
}
}
for (int i = obj.entities.size() - 1; i >= 0; i--)
{
if (obj.entities[i].ishumanoid())
{
drawentity(i, yoff);
}
}
}
else
{
for (int i = obj.entities.size() - 1; i >= 0; i--)
{
drawentity(i, yoff);
}
}
}
void Graphics::drawentity(const int i, const int yoff)
{
if (!INBOUNDS_VEC(i, obj.entities))
{
WHINE_ONCE("drawentity() out-of-bounds!");
return;
}
if (obj.entities[i].invis)
{
return;
}
point tpoint;
SDL_Rect drawRect;
#if !defined(NO_CUSTOM_LEVELS)
// Special case for gray Warp Zone tileset!
const RoomProperty* const room = cl.getroomprop(game.roomx - 100, game.roomy - 100);
const bool custom_gray = room->tileset == 3 && room->tilecol == 6;
#else
const bool custom_gray = false;
#endif
std::vector<SDL_Surface*>& tilesvec = (map.custommode && !map.finalmode) ? entcolours : tiles;
std::vector<SDL_Surface*>& spritesvec = flipmode ? flipsprites : sprites;
const int xp = lerp(obj.entities[i].lerpoldxp, obj.entities[i].xp);
const int yp = lerp(obj.entities[i].lerpoldyp, obj.entities[i].yp);
switch (obj.entities[i].size)
{
case 0:
{
// Sprites
if (!INBOUNDS_VEC(obj.entities[i].drawframe, spritesvec))
{
return;
}
tpoint.x = xp;
tpoint.y = yp - yoff;
setcolreal(obj.entities[i].realcol);
drawRect = sprites_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe], NULL, backBuffer, &drawRect, ct);
//screenwrapping!
point wrappedPoint;
bool wrapX = false;
bool wrapY = false;
wrappedPoint.x = tpoint.x;
if (tpoint.x < 0)
{
wrapX = true;
wrappedPoint.x += 320;
}
else if (tpoint.x > 288)
{
wrapX = true;
wrappedPoint.x -= 320;
}
wrappedPoint.y = tpoint.y;
if (tpoint.y < 8)
{
wrapY = true;
wrappedPoint.y += 232;
}
else if (tpoint.y > 200)
{
wrapY = true;
wrappedPoint.y -= 232;
}
const bool isInWrappingAreaOfTower = map.towermode && !map.minitowermode && map.ypos >= 500 && map.ypos <= 5000;
if (wrapX && (map.warpx || isInWrappingAreaOfTower))
{
drawRect = sprites_rect;
drawRect.x += wrappedPoint.x;
drawRect.y += tpoint.y;
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe], NULL, backBuffer, &drawRect, ct);
}
if (wrapY && map.warpy)
{
drawRect = sprites_rect;
drawRect.x += tpoint.x;
drawRect.y += wrappedPoint.y;
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe], NULL, backBuffer, &drawRect, ct);
}
if (wrapX && wrapY && map.warpx && map.warpy)
{
drawRect = sprites_rect;
drawRect.x += wrappedPoint.x;
drawRect.y += wrappedPoint.y;
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe], NULL, backBuffer, &drawRect, ct);
}
break;
}
case 1:
// Tiles
if (!INBOUNDS_VEC(obj.entities[i].drawframe, tiles))
{
return;
}
tpoint.x = xp;
tpoint.y = yp - yoff;
drawRect = tiles_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
BlitSurfaceStandard(tiles[obj.entities[i].drawframe],NULL, backBuffer, &drawRect);
break;
case 2:
case 8:
{
// Special: Moving platform, 4 tiles or 8 tiles
if (!INBOUNDS_VEC(obj.entities[i].drawframe, tilesvec))
{
return;
}
tpoint.x = xp;
tpoint.y = yp - yoff;
int thiswidth = 4;
if (obj.entities[i].size == 8)
{
thiswidth = 8;
}
for (int ii = 0; ii < thiswidth; ii++)
{
drawRect = tiles_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
drawRect.x += 8 * ii;
if (custom_gray)
{
const SDL_Color temp_ct = {255, 255, 255, 255};
BlitSurfaceTinted(tilesvec[obj.entities[i].drawframe], NULL, backBuffer, &drawRect, temp_ct);
}
else
{
BlitSurfaceStandard(tilesvec[obj.entities[i].drawframe],NULL, backBuffer, &drawRect);
}
}
break;
}
case 3: // Big chunky pixels!
prect.x = xp;
prect.y = yp - yoff;
FillRect(backBuffer, prect, obj.entities[i].realcol);
break;
case 4: // Small pickups
setcolreal(obj.entities[i].realcol);
drawhuetile(xp, yp - yoff, obj.entities[i].tile);
break;
case 5: //Horizontal Line
{
int oldw = obj.entities[i].w;
if ((game.swngame == 3 || kludgeswnlinewidth) && obj.getlineat(84 - 32) == i)
{
oldw -= 24;
}
line_rect.x = xp;
line_rect.y = yp - yoff;
line_rect.w = lerp(oldw, obj.entities[i].w);
line_rect.h = 1;
drawgravityline(i);
break;
}
case 6: //Vertical Line
line_rect.x = xp;
line_rect.y = yp - yoff;
line_rect.w = 1;
line_rect.h = obj.entities[i].h;
drawgravityline(i);
break;
case 7: //Teleporter
drawtele(xp, yp - yoff, obj.entities[i].drawframe, obj.entities[i].realcol);
break;
//case 8: // Special: Moving platform, 8 tiles
// Note: This code is in the 4-tile code
break;
case 9: // Really Big Sprite! (2x2)
setcolreal(obj.entities[i].realcol);
tpoint.x = xp;
tpoint.y = yp - yoff;
drawRect = sprites_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
if (INBOUNDS_VEC(obj.entities[i].drawframe, spritesvec))
{
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
}
tpoint.x = xp+32;
tpoint.y = yp - yoff;
//
drawRect = sprites_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
if (INBOUNDS_VEC(obj.entities[i].drawframe+1, spritesvec))
{
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe+1],NULL, backBuffer, &drawRect, ct);
}
tpoint.x = xp;
tpoint.y = yp+32 - yoff;
//
drawRect = sprites_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
if (INBOUNDS_VEC(obj.entities[i].drawframe+12, spritesvec))
{
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe+12],NULL, backBuffer, &drawRect, ct);
}
tpoint.x = xp+32;
tpoint.y = yp+32 - yoff;
//
drawRect = sprites_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
if (INBOUNDS_VEC(obj.entities[i].drawframe+13, spritesvec))
{
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe + 13],NULL, backBuffer, &drawRect, ct);
}
break;
case 10: // 2x1 Sprite
setcolreal(obj.entities[i].realcol);
tpoint.x = xp;
tpoint.y = yp - yoff;
//
drawRect = sprites_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
if (INBOUNDS_VEC(obj.entities[i].drawframe, spritesvec))
{
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
}
tpoint.x = xp+32;
tpoint.y = yp - yoff;
//
drawRect = sprites_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
if (INBOUNDS_VEC(obj.entities[i].drawframe+1, spritesvec))
{
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe+1],NULL, backBuffer, &drawRect, ct);
}
break;
case 11: //The fucking elephant
setcolreal(obj.entities[i].realcol);
drawimagecol(3, xp, yp - yoff);
break;
case 12: // Regular sprites that don't wrap
tpoint.x = xp;
tpoint.y = yp - yoff;
setcolreal(obj.entities[i].realcol);
//
drawRect = sprites_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
if (INBOUNDS_VEC(obj.entities[i].drawframe, spritesvec))
{
BlitSurfaceColoured(spritesvec[obj.entities[i].drawframe],NULL, backBuffer, &drawRect, ct);
}
//if we're outside the screen, we need to draw indicators
if (obj.entities[i].xp < -20 && obj.entities[i].vx > 0)
{
if (obj.entities[i].xp < -100)
{
tpoint.x = -5 + (int(( -xp) / 10));
}
else
{
tpoint.x = 5;
}
tpoint.y = tpoint.y+4;
drawRect = tiles_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
if (INBOUNDS_VEC(1167, tiles))
{
BlitSurfaceColoured(tiles[1167],NULL, backBuffer, &drawRect, ct);
}
}
else if (obj.entities[i].xp > 340 && obj.entities[i].vx < 0)
{
if (obj.entities[i].xp > 420)
{
tpoint.x = 320 - (int(( xp-320) / 10));
}
else
{
tpoint.x = 310;
}
tpoint.y = tpoint.y+4;
//
drawRect = tiles_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
if (INBOUNDS_VEC(1166, tiles))
{
BlitSurfaceColoured(tiles[1166],NULL, backBuffer, &drawRect, ct);
}
}
break;
case 13:
{
//Special for epilogue: huge hero!
if (!INBOUNDS_VEC(obj.entities[i].drawframe, spritesvec))
{
return;
}
tpoint.x = xp; tpoint.y = yp - yoff;
setcolreal(obj.entities[i].realcol);
setRect(drawRect, xp, yp - yoff, sprites_rect.x * 6, sprites_rect.y * 6);
SDL_Surface* TempSurface = ScaleSurface( spritesvec[obj.entities[i].drawframe], 6 * sprites_rect.w,6* sprites_rect.h );
BlitSurfaceColoured(TempSurface, NULL , backBuffer, &drawRect, ct );
VVV_freefunc(SDL_FreeSurface, TempSurface);
break;
}
}
}
void Graphics::drawbackground( int t )
{
switch(t)
{
case 1:
//Starfield
ClearSurface(backBuffer);
for (int i = 0; i < numstars; i++)
{
stars[i].w = 2;
stars[i].h = 2;
SDL_Rect star_rect = stars[i];
star_rect.x = lerp(star_rect.x + starsspeed[i], star_rect.x);
if (starsspeed[i] <= 6)
{
FillRect(backBuffer,star_rect, getRGB(0x22,0x22,0x22));
}
else
{
FillRect(backBuffer,star_rect, getRGB(0x55,0x55,0x55));
}
}
break;
case 2:
{
SDL_Color bcol;
SDL_Color bcol2;
SDL_zero(bcol);
SDL_zero(bcol2);
//Lab
switch(rcol)
{
//Akward ordering to match tileset
case 0:
bcol2 = getRGB(0, 16*backboxint[0], 16*backboxint[0]);
break; //Cyan
case 1:
bcol2 = getRGB(16*backboxint[0], 0, 0);
break; //Red
case 2:
bcol2 = getRGB(16*backboxint[0], 0, 16*backboxint[0]);
break; //Purple
case 3:
bcol2 = getRGB(0, 0, 16*backboxint[0]);
break; //Blue
case 4:
bcol2 = getRGB(16*backboxint[0], 16*backboxint[0], 0);
break; //Yellow
case 5:
bcol2 = getRGB(0, 16 * backboxint[0], 0);
break; //Green
case 6:
//crazy case
switch(spcol)
{
case 0:
bcol2 = getRGB(0, 16*backboxint[0], 16*backboxint[0]);
break; //Cyan
case 1:
bcol2 = getRGB(0, (spcoldel+1)*backboxint[0], 16*backboxint[0]);
break; //Cyan
case 2:
bcol2 = getRGB(0, 0, 16*backboxint[0]);
break; //Blue
case 3:
bcol2 = getRGB((16-spcoldel)*backboxint[0], 0, 16*backboxint[0]);
break; //Blue
case 4:
bcol2 = getRGB(16*backboxint[0], 0, 16*backboxint[0]);
break; //Purple
case 5:
bcol2 = getRGB(16*backboxint[0], 0, (spcoldel+1)*backboxint[0]);
break; //Purple
case 6:
bcol2 = getRGB(16*backboxint[0], 0, 0);
break; //Red
case 7:
bcol2 = getRGB(16*backboxint[0], (16-spcoldel)*backboxint[0], 0);
break; //Red
case 8:
bcol2 = getRGB(16*backboxint[0], 16*backboxint[0], 0);
break; //Yellow
case 9:
bcol2 = getRGB((spcoldel+1)*backboxint[0], 16*backboxint[0], 0);
break; //Yellow
case 10:
bcol2 = getRGB(0, 16 * backboxint[0], 0);
break; //Green
case 11:
bcol2 = getRGB(0, 16 * backboxint[0], (16-spcoldel)*backboxint[0]);
break; //Green
}
break;
}
FillRect(backBuffer,bcol2);
for (int i = 0; i < numbackboxes; i++)
{
switch(rcol)
{
//Akward ordering to match tileset
case 0:
bcol = getRGB(16, 128*backboxint[0], 128*backboxint[0]);
break; //Cyan
case 1:
bcol = getRGB(128*backboxint[0], 16, 16);
break; //Red
case 2:
bcol = getRGB(128*backboxint[0], 16, 128*backboxint[0]);
break; //Purple
case 3:
bcol = getRGB(16, 16, 128*backboxint[0]);
break; //Blue
case 4:
bcol = getRGB(128*backboxint[0], 128*backboxint[0], 16);
break; //Yellow
case 5:
bcol = getRGB(16, 128 * backboxint[0], 16);
break; //Green
case 6:
//crazy case
switch(spcol)
{
case 0:
bcol = getRGB(16, 128*backboxint[0], 128*backboxint[0]);
break; //Cyan
case 1:
bcol = getRGB(16, ((spcoldel+1)*8)*backboxint[0], 128*backboxint[0]);
break; //Cyan
case 2:
bcol = getRGB(16, 16, 128*backboxint[0]);
break; //Blue
case 3:
bcol = getRGB((128-(spcoldel*8))*backboxint[0], 16, 128*backboxint[0]);
break; //Blue
case 4:
bcol = getRGB(128*backboxint[0], 16, 128*backboxint[0]);
break; //Purple
case 5:
bcol = getRGB(128*backboxint[0], 16, ((spcoldel+1)*8)*backboxint[0]);
break; //Purple
case 6:
bcol = getRGB(128*backboxint[0], 16, 16);
break; //Red
case 7:
bcol = getRGB(128*backboxint[0], (128-(spcoldel*8))*backboxint[0], 16);
break; //Red
case 8:
bcol = getRGB(128*backboxint[0], 128*backboxint[0], 16);
break; //Yellow
case 9:
bcol = getRGB(((spcoldel+1)*8)*backboxint[0], 128*backboxint[0], 16);
break; //Yellow
case 10:
bcol = getRGB(16, 128 * backboxint[0], 16);
break; //Green
case 11:
bcol = getRGB(16, 128 * backboxint[0], (128-(spcoldel*8))*backboxint[0]);
break; //Green
}
break;
}
SDL_Rect backboxrect = backboxes[i];
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;
FillRect(backBuffer,backboxrect, bcol2);
}
break;
}
case 3: //Warp zone (horizontal)
ClearSurface(backBuffer);
BlitSurfaceStandard(warpbuffer, NULL, warpbuffer_lerp, NULL);
ScrollSurface(warpbuffer_lerp, lerp(0, -3), 0);
BlitSurfaceStandard(warpbuffer_lerp, &towerbuffer_rect, backBuffer, NULL);
break;
case 4: //Warp zone (vertical)
ClearSurface(backBuffer);
SDL_BlitSurface(warpbuffer, NULL, warpbuffer_lerp, NULL);
ScrollSurface(warpbuffer_lerp, 0, lerp(0, -3));
SDL_BlitSurface(warpbuffer_lerp, &towerbuffer_rect, backBuffer, NULL);
break;
case 5:
//Warp zone, central
switch(rcol)
{
//Akward ordering to match tileset
case 0:
warpbcol = getRGB(0x0A, 0x10, 0x0E);
warpfcol = getRGB(0x10, 0x22, 0x21);
break; //Cyan
case 1:
warpbcol = getRGB(0x11, 0x09, 0x0B);
warpfcol = getRGB(0x22, 0x10, 0x11);
break; //Red
case 2:
warpbcol = getRGB(0x0F, 0x0A, 0x10);
warpfcol = getRGB(0x22,0x10,0x22);
break; //Purple
case 3:
warpbcol = getRGB(0x0A, 0x0B, 0x10);
warpfcol = getRGB(0x10, 0x10, 0x22);
break; //Blue
case 4:
warpbcol = getRGB(0x10, 0x0D, 0x0A);
warpfcol = getRGB(0x22, 0x1E, 0x10);
break; //Yellow
case 5:
warpbcol = getRGB(0x0D, 0x10, 0x0A);
warpfcol = getRGB(0x14, 0x22, 0x10);
break; //Green
case 6:
warpbcol = getRGB(0x0A, 0x0A, 0x0A);
warpfcol = getRGB(0x12, 0x12, 0x12);
break; //Gray
default:
warpbcol = getRGB(0xFF, 0xFF, 0xFF);
warpfcol = getRGB(0xFF, 0xFF, 0xFF);
}
for (int i = 10 ; i >= 0; i--)
{
const int temp = (i * 16) + backoffset;
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
ClearSurface(backBuffer);
for (int i = 0; i < numstars; i++)
{
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);
if (starsspeed[i] <= 8)
{
FillRect(backBuffer, star_rect, getRGB(0x22, 0x22, 0x22));
}
else
{
FillRect(backBuffer, star_rect, getRGB(0x55, 0x55, 0x55));
}
}
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:
ClearSurface(backBuffer);
break;
}
}
void Graphics::updatebackground(int t)
{
switch (t)
{
case 1:
//Starfield
for (int i = 0; i < numstars; i++)
{
stars[i].w = 2;
stars[i].h = 2;
stars[i].x -= 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);
}
}
break;
case 2:
//Lab
if (rcol == 6)
{
//crazy caze
spcoldel--;
if (spcoldel <= 0)
{
spcoldel = 15;
spcol++;
if (spcol >= 12) spcol = 0;
}
}
for (int i = 0; i < numbackboxes; 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;
}
}
break;
case 3: //Warp zone (horizontal)
{
const int temp = 680 + (rcol * 3);
backoffset+=3;
if (backoffset >= 16) backoffset -= 16;
if (backgrounddrawn)
{
ScrollSurface(warpbuffer, -3, 0 );
for (int j = 0; j < 15; j++)
{
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);
}
}
}
else
{
//draw the whole thing for the first time!
backoffset = 0;
ClearSurface(warpbuffer);
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;
}
case 4: //Warp zone (vertical)
{
const int temp = 760 + (rcol * 3);
backoffset+=3;
if (backoffset >= 16) backoffset -= 16;
if (backgrounddrawn)
{
ScrollSurface(warpbuffer,0,-3);
for (int j = 0; j < 2; j++)
{
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);
}
}
}
else
{
//draw the whole thing for the first time!
backoffset = 0;
ClearSurface(warpbuffer);
for (int j = 0; j < 16; j++)
{
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;
}
case 5:
//Warp zone, central
backoffset += 1;
if (backoffset >= 16)
{
backoffset -= 16;
warpskip = (warpskip + 1) % 2;
}
break;
case 6:
//Final Starfield
for (int i = 0; i < numstars; 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;
}
}
void Graphics::drawmap(void)
{
if (!foregrounddrawn)
{
ClearSurface(foregroundBuffer);
if(map.tileset==0)
{
for (int j = 0; j < 30; j++)
{
for (int i = 0; i < 40; i++)
{
const int tile = map.contents[TILE_IDX(i, j)];
if(tile>0) drawforetile(i * 8, j * 8, tile);
}
}
}
else if (map.tileset == 1)
{
for (int jt = 0; jt < 30; jt++)
{
for (int it = 0; it < 40; it++)
{
const int tile = map.contents[TILE_IDX(it, jt)];
if(tile>0) drawforetile2(it * 8, jt * 8, tile);
}
}
}
else if (map.tileset == 2)
{
for (int j = 0; j < 30; j++)
{
for (int i = 0; i < 40; i++)
{
const int tile = map.contents[TILE_IDX(i, j)];
if(tile>0) drawforetile3(i * 8, j * 8, tile,map.rcol);
}
}
}
foregrounddrawn = true;
}
SDL_BlitSurface(foregroundBuffer, NULL, backBuffer, NULL);
}
void Graphics::drawfinalmap(void)
{
if (!foregrounddrawn) {
ClearSurface(foregroundBuffer);
if(map.tileset==0){
for (int j = 0; j < 30; j++) {
for (int i = 0; i < 40; i++) {
if((map.contents[TILE_IDX(i, j)])>0)
drawforetile(i * 8, j * 8, map.finalat(i,j));
}
}
}else if (map.tileset == 1) {
for (int j = 0; j < 30; j++) {
for (int i = 0; i < 40; i++) {
if((map.contents[TILE_IDX(i, j)])>0)
drawforetile2(i * 8, j * 8, map.finalat(i,j));
}
}
}
foregrounddrawn=true;
}
SDL_BlitSurface(foregroundBuffer, NULL, backBuffer, NULL);
}
void Graphics::drawtowermap(void)
{
const int yoff = lerp(map.oldypos, map.ypos);
for (int j = 0; j < 31; j++)
{
for (int i = 0; i < 40; i++)
{
const int temp = map.tower.at(i, j, yoff);
if (temp > 0)
{
drawtile3(i * 8, (j * 8) - (yoff % 8), temp, towerbg.colstate);
}
}
}
}
void Graphics::drawtowerspikes(void)
{
int spikeleveltop = lerp(map.oldspikeleveltop, map.spikeleveltop);
int spikelevelbottom = lerp(map.oldspikelevelbottom, map.spikelevelbottom);
for (int i = 0; i < 40; i++)
{
drawtile3(i * 8, -8+spikeleveltop, 9, towerbg.colstate);
drawtile3(i * 8, 230-spikelevelbottom, 8, towerbg.colstate, 8 - spikelevelbottom);
}
}
void Graphics::drawtowerbackground(const TowerBG& bg_obj)
{
ClearSurface(backBuffer);
SDL_BlitSurface(bg_obj.buffer, NULL, bg_obj.buffer_lerp, NULL);
ScrollSurface(bg_obj.buffer_lerp, 0, lerp(0, -bg_obj.bscroll));
SDL_BlitSurface(bg_obj.buffer_lerp, &towerbuffer_rect, backBuffer, NULL);
}
void Graphics::updatetowerbackground(TowerBG& bg_obj)
{
if (bg_obj.bypos < 0) bg_obj.bypos += 120 * 8;
if (bg_obj.tdrawback)
{
int off = bg_obj.scrolldir == 0 ? 0 : bg_obj.bscroll;
//Draw the whole thing; needed for every colour cycle!
for (int j = -1; j < 32; j++)
{
for (int i = 0; i < 40; i++)
{
const int temp = map.tower.backat(i, j, bg_obj.bypos);
drawtowertile3(i * 8, (j * 8) - (bg_obj.bypos % 8) - off, temp, bg_obj);
}
}
bg_obj.tdrawback = false;
}
else
{
//just update the bottom
ScrollSurface(bg_obj.buffer, 0, -bg_obj.bscroll);
if (bg_obj.scrolldir == 0)
{
for (int i = 0; i < 40; i++)
{
int temp = map.tower.backat(i, -1, bg_obj.bypos);
drawtowertile3(i * 8, -1*8 - (bg_obj.bypos % 8), temp, bg_obj);
temp = map.tower.backat(i, 0, bg_obj.bypos);
drawtowertile3(i * 8, -(bg_obj.bypos % 8), temp, bg_obj);
}
}
else
{
for (int i = 0; i < 40; i++)
{
int temp = map.tower.backat(i, 29, bg_obj.bypos);
drawtowertile3(i * 8, 29*8 - (bg_obj.bypos % 8) - bg_obj.bscroll, temp, bg_obj);
temp = map.tower.backat(i, 30, bg_obj.bypos);
drawtowertile3(i * 8, 30*8 - (bg_obj.bypos % 8) - bg_obj.bscroll, temp, bg_obj);
temp = map.tower.backat(i, 31, bg_obj.bypos);
drawtowertile3(i * 8, 31*8 - (bg_obj.bypos % 8) - bg_obj.bscroll, temp, bg_obj);
temp = map.tower.backat(i, 32, bg_obj.bypos);
drawtowertile3(i * 8, 32*8 - (bg_obj.bypos % 8) - bg_obj.bscroll, temp, bg_obj);
}
}
}
}
void Graphics::setcol( int t )
{
//Setup predefinied colours as per our zany palette
switch(t)
{
//Player Normal
case 0:
ct = getRGB(160 - help.glow/2 - (fRandom() * 20), 200 - help.glow/2, 220 - help.glow);
break;
//Player Hurt
case 1:
ct = getRGB(196 - (fRandom() * 64), 10, 10);
break;
//Enemies and stuff
case 2:
ct = 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 = getRGB(trinketr, trinketg, trinketb);
break;
case 4: //Inactive savepoint
{
const int temp = (help.glow / 2) + (fRandom() * 8);
ct = getRGB(80 + temp, 80 + temp, 80 + temp);
break;
}
case 5: //Active savepoint
ct = getRGB(164 + (fRandom() * 64), 164 + (fRandom() * 64), 255 - (fRandom() * 64));
break;
case 6: //Enemy : Red
ct = getRGB(250 - help.glow/2, 60- help.glow/2, 60 - help.glow/2);
break;
case 7: //Enemy : Green
ct = getRGB(100 - help.glow/2 - (fRandom() * 30), 250 - help.glow/2, 100 - help.glow/2 - (fRandom() * 30));
break;
case 8: //Enemy : Purple
ct = getRGB(250 - help.glow/2, 20, 128 - help.glow/2 + (fRandom() * 30));
break;
case 9: //Enemy : Yellow
ct = getRGB(250 - help.glow/2, 250 - help.glow/2, 20);
break;
case 10: //Warp point (white)
ct = getRGB(255 - (fRandom() * 64), 255 - (fRandom() * 64), 255 - (fRandom() * 64));
break;
case 11: //Enemy : Cyan
ct = getRGB(20, 250 - help.glow/2, 250 - help.glow/2);
break;
case 12: //Enemy : Blue
ct = getRGB(90 - help.glow/2, 90 - help.glow/2, 250 - help.glow/2);
break;
//Crew Members
//green
case 13:
ct = getRGB(120 - help.glow/4 - (fRandom() * 20), 220 - help.glow/4, 120 - help.glow/4);
break;
//Yellow
case 14:
ct = getRGB(220 - help.glow/4 - (fRandom() * 20), 210 - help.glow/4, 120 - help.glow/4);
break;
//pink
case 15:
ct = getRGB(255 - help.glow/8, 70 - help.glow/4, 70 - help.glow / 4);
break;
//Blue
case 16:
ct = getRGB(75, 75, 255 - help.glow/4 - (fRandom() * 20));
break;
case 17: //Enemy : Orange
ct = getRGB(250 - help.glow/2, 130 - help.glow/2, 20);
break;
case 18: //Enemy : Gray
ct = getRGB(130 - help.glow/2, 130 - help.glow/2, 130 - help.glow/2);
break;
case 19: //Enemy : Dark gray
ct = getRGB(60 - help.glow/8, 60 - help.glow/8, 60 - help.glow/8);
break;
//Purple
case 20:
ct = getRGB(220 - help.glow/4 - (fRandom() * 20), 120 - help.glow/4, 210 - help.glow/4);
break;
case 21: //Enemy : Light Gray
ct = getRGB(180 - help.glow/2, 180 - help.glow/2, 180 - help.glow/2);
break;
case 22: //Enemy : Indicator Gray
ct = getRGB(230 - help.glow/2, 230- help.glow/2, 230 - help.glow/2);
break;
case 23: //Enemy : Indicator Gray
ct = 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 = RGBf(160, 200, 220);
break;
//Purple
case 31:
ct = RGBf(220, 120, 210);
break;
//Yellow
case 32:
ct = RGBf(220, 210, 120);
break;
//red
case 33:
ct = RGBf(255, 70, 70);
break;
//green
case 34:
ct = RGBf(120, 220, 120);
break;
//Blue
case 35:
ct = RGBf(75, 75, 255);
break;
//Gold
case 36:
ct = 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 = RGBf(trinketr, trinketg, trinketb);
break;
//Silver
case 38:
ct = RGBf(196, 196, 196);
break;
//Bronze
case 39:
ct = RGBf(128, 64, 10);
break;
//Awesome
case 40: //Teleporter in action!
{
const int temp = fRandom() * 150;
if(temp<33)
{
ct = RGBf(255 - (fRandom() * 64), 64 + (fRandom() * 64), 64 + (fRandom() * 64));
}
else if (temp < 66)
{
ct = RGBf(64 + (fRandom() * 64), 255 - (fRandom() * 64), 64 + (fRandom() * 64));
}
else if (temp < 100)
{
ct = RGBf(64 + (fRandom() * 64), 64 + (fRandom() * 64), 255 - (fRandom() * 64));
}
else
{
ct = RGBf(164 + (fRandom() * 64), 164 + (fRandom() * 64), 255 - (fRandom() * 64));
}
break;
}
case 100: //Inactive Teleporter
{
const int temp = (help.glow / 2) + (fRandom() * 8);
ct = getRGB(42 + temp, 42 + temp, 42 + temp);
break;
}
case 101: //Active Teleporter
ct = getRGB(164 + (fRandom() * 64), 164 + (fRandom() * 64), 255 - (fRandom() * 64));
break;
case 102: //Teleporter in action!
{
const int temp = fRandom() * 150;
if (temp < 33)
{
ct = getRGB(255 - (fRandom() * 64), 64 + (fRandom() * 64), 64 + (fRandom() * 64));
}
else if (temp < 66)
{
ct = getRGB(64 + (fRandom() * 64), 255 - (fRandom() * 64), 64 + (fRandom() * 64));
}
else if (temp < 100)
{
ct = getRGB(64 + (fRandom() * 64), 64 + (fRandom() * 64), 255 - (fRandom() * 64));
}
else
{
ct = getRGB(164 + (fRandom() * 64), 164 + (fRandom() * 64), 255 - (fRandom() * 64));
}
break;
}
default:
ct = getRGB(255, 255, 255);
break;
}
}
void Graphics::menuoffrender(void)
{
const int usethisoffset = lerp(oldmenuoffset, menuoffset);
SDL_Rect offsetRect = {0, usethisoffset, backBuffer->w, backBuffer->h};
BlitSurfaceStandard(backBuffer, NULL, menubuffer, NULL);
BlitSurfaceStandard(tempBuffer, NULL, backBuffer, NULL);
BlitSurfaceStandard(menubuffer, NULL, backBuffer, &offsetRect);
gameScreen.UpdateScreen(backBuffer, NULL);
ClearSurface(backBuffer);
}
void Graphics::drawhuetile( int x, int y, int t )
{
if (!INBOUNDS_VEC(t, tiles))
{
return;
}
point tpoint;
tpoint.x = x;
tpoint.y = y;
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)
{
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;
}
}
SDL_Color 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);
}
const SDL_Color color = {0, 0, 0, 0};
return color;
}
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::textboxcenterx(void)
{
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxcenterx() out-of-bounds!");
return;
}
textboxes[m].centerx();
}
int Graphics::textboxwidth(void)
{
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxwidth() out-of-bounds!");
return 0;
}
return textboxes[m].w;
}
void Graphics::textboxmoveto(int xo)
{
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxmoveto() out-of-bounds!");
return;
}
textboxes[m].xp = xo;
}
void Graphics::textboxcentery(void)
{
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxcentery() out-of-bounds!");
return;
}
textboxes[m].centery();
}
int Graphics::textboxwrap(int pad)
{
/* This function just takes a single-line textbox and wraps it...
* pad = the total number of characters we are going to pad this textbox.
* (or how many characters we should stay clear of 288 pixels width in general)
* Only to be used after a manual graphics.createtextbox[flipme] call.
* Returns the new, total height of the textbox. */
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxwrap() out-of-bounds!");
return 16;
}
if (textboxes[m].lines.empty())
{
vlog_error("textboxwrap() has no first line!");
return 16;
}
std::string wrapped = string_wordwrap_balanced(textboxes[m].lines[0], 36*8 - pad*8);
textboxes[m].lines.clear();
size_t startline = 0;
size_t newline;
do {
size_t pos_n = wrapped.find('\n', startline);
size_t pos_p = wrapped.find('|', startline);
newline = SDL_min(pos_n, pos_p);
addline(wrapped.substr(startline, newline-startline));
startline = newline+1;
} while (newline != std::string::npos);
return textboxes[m].h;
}
void Graphics::textboxpad(size_t left_pad, size_t right_pad)
{
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxpad() out-of-bounds!");
return;
}
textboxes[m].pad(left_pad, right_pad);
}
void Graphics::textboxpadtowidth(size_t new_w)
{
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxpadtowidth() out-of-bounds!");
return;
}
textboxes[m].padtowidth(new_w);
}
void Graphics::textboxcentertext()
{
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxcentertext() out-of-bounds!");
return;
}
textboxes[m].centertext();
}
void Graphics::textboxcommsrelay()
{
/* Special treatment for the gamestate textboxes in Comms Relay */
if (!INBOUNDS_VEC(m, textboxes))
{
vlog_error("textboxcommsrelay() out-of-bounds!");
return;
}
textboxwrap(11);
textboxes[m].xp = 224 - textboxes[m].w;
}
int Graphics::crewcolour(const int t)
{
//given crewmate t, return colour in setcol
if (t == 0) return CYAN;
if (t == 1) return PURPLE;
if (t == 2) return YELLOW;
if (t == 3) return RED;
if (t == 4) return GREEN;
if (t == 5) return BLUE;
return 0;
}
void Graphics::flashlight(void)
{
FillRect(backBuffer, 0xBB, 0xBB, 0xBB, 0xBB);
}
void Graphics::screenshake(void)
{
SDL_Rect shakeRect = {screenshake_x, screenshake_y, backBuffer->w, backBuffer->h};
gameScreen.UpdateScreen(backBuffer, &shakeRect);
ClearSurface(backBuffer);
}
void Graphics::updatescreenshake(void)
{
screenshake_x = static_cast<Sint32>((fRandom() * 7) - 4);
screenshake_y = static_cast<Sint32>((fRandom() * 7) - 4);
}
void Graphics::render(void)
{
gameScreen.UpdateScreen(backBuffer, NULL);
}
void Graphics::renderwithscreeneffects(void)
{
if (game.flashlight > 0 && !game.noflashingmode)
{
flashlight();
}
if (game.screenshake > 0 && !game.noflashingmode)
{
screenshake();
}
else
{
render();
}
}
void Graphics::renderfixedpre(void)
{
if (game.screenshake > 0)
{
updatescreenshake();
}
if (gameScreen.badSignalEffect)
{
UpdateFilter();
}
}
void Graphics::renderfixedpost(void)
{
/* Screen effects timers */
if (game.flashlight > 0)
{
--game.flashlight;
}
if (game.screenshake > 0)
{
--game.screenshake;
}
}
void Graphics::bigrprint(int x, int y, const std::string& t, int r, int g, int b, bool cen, float sc)
{
const int len_ = len(t);
x = x / (sc);
x -= len_;
if (cen)
{
x = SDL_max(160 - (int((len_/ 2.0)*sc)), 0 );
}
else
{
x *= (sc);
}
return do_print(x, y, t, r, g, b, 255, sc);
}
void Graphics::bigbrprint(int x, int y, const std::string& s, int r, int g, int b, bool cen, float sc)
{
if (!notextoutline)
{
const int len_ = len(s);
int x_o = x / sc - len_;
bigrprint(x, y - sc, s, 0, 0, 0, cen, sc);
if (cen)
{
x_o = SDL_max(160 - (len_ / 2) * sc, 0);
bigprint(x_o - sc, y, s, 0, 0, 0, false, sc);
bigprint(x_o + sc, y, s, 0, 0, 0, false, sc);
}
else
{
x_o *= sc;
bigprint(x_o - sc, y, s, 0, 0, 0, false, sc);
bigprint(x_o + sc, y, s, 0, 0, 0, false, sc);
}
bigrprint(x, y + sc, s, 0, 0, 0, cen, sc);
}
bigrprint(x, y, s, r, g, b, cen, sc);
}
void Graphics::drawtele(int x, int y, int t, const SDL_Color color)
{
setcolreal(getRGB(16,16,16));
SDL_Rect telerect;
setRect(telerect, x , y, tele_rect.w, tele_rect.h );
if (INBOUNDS_VEC(0, tele))
{
BlitSurfaceColoured(tele[0], NULL, backBuffer, &telerect, ct);
}
setcolreal(color);
if (t > 9) t = 8;
if (t < 1) t = 1;
setRect(telerect, x , y, tele_rect.w, tele_rect.h );
if (INBOUNDS_VEC(t, tele))
{
BlitSurfaceColoured(tele[t], NULL, backBuffer, &telerect, ct);
}
}
SDL_Color Graphics::getRGBA(const Uint8 r, const Uint8 g, const Uint8 b, const Uint8 a)
{
const SDL_Color color = {r, g, b, a};
return color;
}
SDL_Color Graphics::getRGB(const Uint8 r, const Uint8 g, const Uint8 b)
{
const SDL_Color color = {r, g, b, 255};
return color;
}
SDL_Color Graphics::RGBf(int r, int g, int b)
{
r = (r + 128) / 3;
g = (g + 128) / 3;
b = (b + 128) / 3;
const SDL_Color color = {(Uint8) r, (Uint8) g, (Uint8) b, 255};
return color;
}
void Graphics::setcolreal(const SDL_Color color)
{
ct = color;
}
void Graphics::drawforetile(int x, int y, int t)
{
if (!INBOUNDS_VEC(t, tiles))
{
WHINE_ONCE("drawforetile() out-of-bounds!");
return;
}
SDL_Rect rect;
setRect(rect, x,y,tiles_rect.w, tiles_rect.h);
#if !defined(NO_CUSTOM_LEVELS)
if (shouldrecoloroneway(t, tiles1_mounted))
{
const SDL_Color thect = cl.getonewaycol();
BlitSurfaceTinted(tiles[t], NULL, foregroundBuffer, &rect, thect);
}
else
#endif
{
BlitSurfaceStandard(tiles[t],NULL, foregroundBuffer, &rect );
}
}
void Graphics::drawforetile2(int x, int y, int t)
{
if (!INBOUNDS_VEC(t, tiles2))
{
WHINE_ONCE("drawforetile2() out-of-bounds!");
return;
}
SDL_Rect rect;
setRect(rect, x,y,tiles_rect.w, tiles_rect.h);
#if !defined(NO_CUSTOM_LEVELS)
if (shouldrecoloroneway(t, tiles2_mounted))
{
const SDL_Color thect = cl.getonewaycol();
BlitSurfaceTinted(tiles2[t], NULL, foregroundBuffer, &rect, thect);
}
else
#endif
{
BlitSurfaceStandard(tiles2[t],NULL, foregroundBuffer, &rect );
}
}
void Graphics::drawforetile3(int x, int y, int t, int off)
{
t += off * 30;
if (!INBOUNDS_VEC(t, tiles3))
{
WHINE_ONCE("drawforetile3() out-of-bounds!");
return;
}
SDL_Rect rect;
setRect(rect, x,y,tiles_rect.w, tiles_rect.h);
BlitSurfaceStandard(tiles3[t],NULL, foregroundBuffer, &rect );
}
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(r, g, b));
madrect.w = 1;
madrect.h = h;
FillRect(backBuffer, madrect, getRGB(r, g, b));
madrect.x = x + w - 1;
madrect.w = 1;
madrect.h = h;
FillRect(backBuffer, madrect, getRGB(r, g, b));
madrect.x = x;
madrect.y = y + h - 1;
madrect.w = w;
madrect.h = 1;
FillRect(backBuffer, madrect, getRGB(r, g, b));
}
bool Graphics::onscreen(int t)
{
return (t >= -40 && t <= 280);
}
bool Graphics::reloadresources(void)
{
grphx.destroy();
grphx.init();
destroy();
MAYBE_FAIL(MakeTileArray());
MAYBE_FAIL(MakeSpriteArray());
MAYBE_FAIL(maketelearray());
MAYBE_FAIL(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);
gameScreen.LoadIcon();
music.destroy();
music.init();
#ifndef NO_CUSTOM_LEVELS
tiles1_mounted = FILESYSTEM_isAssetMounted("graphics/tiles.png");
tiles2_mounted = FILESYSTEM_isAssetMounted("graphics/tiles2.png");
minimap_mounted = FILESYSTEM_isAssetMounted("graphics/minimap.png");
#endif
gamecomplete_mounted = FILESYSTEM_isAssetMounted("graphics/gamecomplete.png");
levelcomplete_mounted = FILESYSTEM_isAssetMounted("graphics/levelcomplete.png");
flipgamecomplete_mounted = FILESYSTEM_isAssetMounted("graphics/flipgamecomplete.png");
fliplevelcomplete_mounted = FILESYSTEM_isAssetMounted("graphics/fliplevelcomplete.png");
return true;
fail:
return false;
}
SDL_Color 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;
}
void Graphics::render_roomname(const char* roomname, int r, int g, int b)
{
footerrect.y = 230;
if (translucentroomname)
{
SDL_BlitSurface(footerbuffer, NULL, backBuffer, &footerrect);
bprint(5, 231, roomname, r, g, b, true);
}
else
{
FillRect(backBuffer, footerrect, 0, 0, 0);
Print(5, 231, roomname, r, g, b, true);
}
}