1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-25 05:58:30 +02:00
VVVVVV/desktop_version/src/Editor.cpp
Misa 54990638fd Persist windowed mode size through fullscreen mode
Previously, the game would not store the size of the window itself, and
would always call SDL_GetRendererOutputSize() (via
Screen::GetWindowSize()) to figure out the size of the window. The only
problem is, this would return the size of the whole monitor if the game
was in fullscreen mode. And the only place where the original windowed
mode size was stored would be in SDL itself, but that wouldn't persist
after the game was closed.

So, if you exited the game while in fullscreen mode, then your window
size would get set to the size of your monitor (1920 by 1080 in my
case). Then when you opened the game and toggled fullscreen off, it
would go back to the default window size, which is 640 by 480.

This is made worse, however, if you were in forced fullscreen mode when
you previously exited the game in windowed mode. In that case, the game
saves the size of 1920 by 1080, but doesn't save that you were in
fullscreen mode, so opening the game not in forced fullscreen mode would
result in you having a 1920 by 1080 window, but in windowed mode.
Meaning that not even fullscreening and unfullscreening would put the
game window back to normal size.

The solution, of course, is to just store the window size ourselves,
like any other screen setting, and only use GetWindowSize() if needed.
And just to make things clear, I've also renamed the GetWindowSize()
function to GetScreenSize(), because if it was named "window" it could
lead one to think that it would always return the size of the screen in
windowed mode, when in fact it returns the size of the screen whatever
mode it is in - fullscreen size if in fullscreen mode and window size if
in windowed mode.

And doing this also fixes the FIXME above Screen::isForcedFullscreen().
2023-03-20 20:59:37 -07:00

4526 lines
150 KiB
C++

#if !defined(NO_CUSTOM_LEVELS) && !defined(NO_EDITOR)
#define ED_DEFINITION
#include "Editor.h"
#include <string>
#include "Constants.h"
#include "CustomLevels.h"
#include "DeferCallbacks.h"
#include "Entity.h"
#include "Enums.h"
#include "Font.h"
#include "Game.h"
#include "Graphics.h"
#include "GraphicsUtil.h"
#include "KeyPoll.h"
#include "Localization.h"
#include "Map.h"
#include "Music.h"
#include "Screen.h"
#include "Script.h"
#include "UTF8.h"
#include "UtilityClass.h"
#include "VFormat.h"
#include "Vlogging.h"
editorclass::editorclass(void)
{
reset();
}
void editorclass::reset(void)
{
roomnamehide=0;
zmod=false;
xmod=false;
cmod=false;
vmod=false;
hmod=false;
bmod=false;
spacemod=false;
spacemenu=0;
shiftmenu=false;
shiftkey=false;
saveandquit=false;
note="";
notedelay=0;
oldnotedelay=0;
deletekeyheld=false;
textmod = TEXT_NONE;
titlemod=false;
creatormod=false;
desc1mod=false;
desc2mod=false;
desc3mod=false;
websitemod=false;
settingsmod=false;
warpmod=false; //Two step process
warpent=-1;
boundarymod=0;
boundarytype=0;
boundx1=0;
boundx2=0;
boundy1=0;
boundy2=0;
textent=0;
scripttexttype=0;
drawmode=0;
dmtile=0;
dmtileeditor=0;
entcol=0;
tilex=0;
tiley=0;
levx=0;
levy=0;
keydelay=0;
lclickdelay=0;
savekey=false;
loadkey=false;
updatetiles=true;
changeroom=true;
entframe=0;
entframedelay=0;
SDL_zeroa(kludgewarpdir);
hooklist.clear();
sb.clear();
clearscriptbuffer();
sbx=0;
sby=0;
pagey=0;
lines_visible = 25;
scripteditmod=false;
sbscript="null";
scripthelppage=0;
scripthelppagedelay=0;
hookmenupage=0;
hookmenu=0;
returneditoralpha = 0;
oldreturneditoralpha = 0;
ghosts.clear();
currentghosts = 0;
loaded_filepath = "";
}
void editorclass::gethooks(void)
{
//Scan through the script and create a hooks list based on it
hooklist.clear();
for (size_t i = 0; i < script.customscripts.size(); i++)
{
Script& script_ = script.customscripts[i];
hooklist.push_back(script_.name);
}
}
void editorclass::loadhookineditor(const std::string& t)
{
//Find hook t in the scriptclass, then load it into the editor
clearscriptbuffer();
for(size_t i = 0; i < script.customscripts.size(); i++)
{
Script& script_ = script.customscripts[i];
if(script_.name == t)
{
sb = script_.contents;
break;
}
}
if(sb.empty())
{
//Always have one line or we'll have problems
sb.resize(1);
}
}
void editorclass::addhooktoscript(const std::string& t)
{
//Adds hook+the scriptbuffer to the end of the scriptclass
removehookfromscript(t);
Script script_;
script_.name = t;
script_.contents = sb;
script.customscripts.push_back(script_);
}
void editorclass::removehookfromscript(const std::string& t)
{
/* Find hook t in the scriptclass, then removes it (and any other code with it)
* When this loop reaches the end, it wraps to SIZE_MAX; SIZE_MAX + 1 is 0 */
size_t i;
for (i = script.customscripts.size() - 1; i + 1 > 0; --i)
{
if (script.customscripts[i].name == t)
{
script.customscripts.erase(script.customscripts.begin() + i);
}
}
}
void editorclass::removehook(const std::string& t)
{
//Check the hooklist for the hook t. If it's there, remove it from here and the script
size_t i;
removehookfromscript(t);
/* When this loop reaches the end, it wraps to SIZE_MAX; SIZE_MAX + 1 is 0 */
for (i = hooklist.size() - 1; i + 1 > 0; --i)
{
if (hooklist[i] == t)
{
hooklist.erase(hooklist.begin() + i);
}
}
}
void editorclass::addhook(const std::string& t)
{
//Add an empty function to the list in both editor and script
removehook(t);
hooklist.push_back(t);
addhooktoscript(t);
}
bool editorclass::checkhook(const std::string& t)
{
//returns true if hook t already is in the list
for(size_t i=0; i<hooklist.size(); i++)
{
if(hooklist[i]==t) return true;
}
return false;
}
void editorclass::clearscriptbuffer(void)
{
sb.clear();
}
void editorclass::removeline(int t)
{
//Remove line t from the script
if((int)sb.size()>1)
{
sb.erase(sb.begin() + t);
}
}
void editorclass::insertline(int t)
{
//insert a blank line into script at line t
sb.insert(sb.begin() + t, "");
}
void editorclass::getlin(const enum textmode mode, const std::string& prompt, std::string* ptr)
{
textmod = mode;
textptr = ptr;
textdesc = prompt;
key.enabletextentry();
if (ptr)
{
key.keybuffer = *ptr;
}
else
{
key.keybuffer = "";
textptr = &(key.keybuffer);
}
oldenttext = key.keybuffer;
}
static void addedentity( int xp, int yp, int tp, int p1 = 0, int p2 = 0, int p3 = 0, int p4 = 0, int p5 = 320, int p6 = 240)
{
CustomEntity entity;
entity.x=xp;
entity.y=yp;
entity.t=tp;
entity.p1=p1;
entity.p2=p2;
entity.p3=p3;
entity.p4=p4;
entity.p5=p5;
entity.p6=p6;
entity.scriptname="";
customentities.push_back(entity);
}
static void removeedentity( int t )
{
customentities.erase(customentities.begin() + t);
}
static int edentat( int xp, int yp )
{
for(size_t i=0; i<customentities.size(); i++)
{
if(customentities[i].x==xp && customentities[i].y==yp) return i;
}
return -1;
}
static void fillbox(const int x, const int y, const int x2, const int y2, const SDL_Color color)
{
graphics.set_color(color);
const SDL_Rect rect = {x, y, x2 - x, y2 - y};
const int result = SDL_RenderDrawRect(gameScreen.m_renderer, &rect);
if (result != 0)
{
WHINE_ONCE_ARGS(("Could not render rectangle outline: %s", SDL_GetError()));
}
}
static void fillboxabs(const int x, const int y, const int x2, const int y2, const SDL_Color color)
{
graphics.set_color(color);
const SDL_Rect rect = {x, y, x2, y2};
const int result = SDL_RenderDrawRect(gameScreen.m_renderer, &rect);
if (result != 0)
{
WHINE_ONCE_ARGS(("Could not render rectangle outline: %s", SDL_GetError()));
}
}
static void editormenurender(int tr, int tg, int tb)
{
extern editorclass ed;
switch (game.currentmenuname)
{
case Menu::ed_settings:
font::print(PR_2X | PR_CEN, -1, 75, loc::gettext("Map Settings"), tr, tg, tb);
if (game.currentmenuoption == 3)
{
if (!game.ghostsenabled)
font::print(0, 2, 230, loc::gettext("Editor ghost trail is OFF"), tr/2, tg/2, tb/2);
else
font::print(0, 2, 230, loc::gettext("Editor ghost trail is ON"), tr, tg, tb);
}
break;
case Menu::ed_desc:
{
if(ed.titlemod)
{
if(ed.entframe<2)
{
font::print(PR_2X | PR_CEN | PR_FONT_LEVEL, -1, 35, key.keybuffer+"_", tr, tg, tb);
}
else
{
font::print(PR_2X | PR_CEN | PR_FONT_LEVEL, -1, 35, key.keybuffer+" ", tr, tg, tb);
}
}
else
{
bool title_is_gettext;
std::string title = translate_title(cl.title, &title_is_gettext);
font::print(PR_2X | PR_CEN | (title_is_gettext ? PR_FONT_INTERFACE : PR_FONT_LEVEL), -1, 35, title, tr, tg, tb);
}
bool creator_is_gettext = false;
std::string creator;
if(ed.creatormod)
{
if(ed.entframe<2)
{
creator = key.keybuffer + "_";
}
else
{
creator = key.keybuffer + " ";
}
}
else
{
creator = translate_creator(cl.creator, &creator_is_gettext);
}
int sp = SDL_max(10, font::height(PR_FONT_LEVEL));
graphics.print_level_creator((creator_is_gettext ? PR_FONT_INTERFACE : PR_FONT_LEVEL), 60, creator, tr, tg, tb);
if(ed.websitemod)
{
if(ed.entframe<2)
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp, key.keybuffer+"_", tr, tg, tb);
}
else
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp, key.keybuffer+" ", tr, tg, tb);
}
}
else
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp, cl.website, tr, tg, tb);
}
if(ed.desc1mod)
{
if(ed.entframe<2)
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp*3, key.keybuffer+"_", tr, tg, tb);
}
else
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp*3, key.keybuffer+" ", tr, tg, tb);
}
}
else
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp*3, cl.Desc1, tr, tg, tb);
}
if(ed.desc2mod)
{
if(ed.entframe<2)
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp*4, key.keybuffer+"_", tr, tg, tb);
}
else
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp*4, key.keybuffer+" ", tr, tg, tb);
}
}
else
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp*4, cl.Desc2, tr, tg, tb);
}
if(ed.desc3mod)
{
if(ed.entframe<2)
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp*5, key.keybuffer+"_", tr, tg, tb);
}
else
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp*5, key.keybuffer+" ", tr, tg, tb);
}
}
else if (sp <= 10)
{
font::print(PR_CEN | PR_FONT_LEVEL, -1, 60+sp*5, cl.Desc3, tr, tg, tb);
}
const char* label = loc::gettext("Font: ");
int len_label = font::len(0, label);
const char* name = font::get_level_font_display_name();
font::print(0, 2, 230, label, tr/2, tg/2, tb/2);
font::print(PR_FONT_LEVEL, 2+len_label, 230, name, tr/2, tg/2, tb/2);
break;
}
case Menu::ed_music:
{
font::print(PR_2X | PR_CEN | PR_CJK_HIGH, -1, 65, loc::gettext("Map Music"), tr, tg, tb);
font::print_wrap(PR_CEN | PR_CJK_LOW, -1, 85, loc::gettext("Current map music:"), tr, tg, tb);
const char* songname;
switch(cl.levmusic)
{
case 0:
songname = loc::gettext("No background music");
break;
case 1:
songname = loc::gettext("1: Pushing Onwards");
break;
case 2:
songname = loc::gettext("2: Positive Force");
break;
case 3:
songname = loc::gettext("3: Potential for Anything");
break;
case 4:
songname = loc::gettext("4: Passion for Exploring");
break;
case 5:
songname = loc::gettext("N/A: Pause");
break;
case 6:
songname = loc::gettext("5: Presenting VVVVVV");
break;
case 7:
songname = loc::gettext("N/A: Plenary");
break;
case 8:
songname = loc::gettext("6: Predestined Fate");
break;
case 9:
songname = loc::gettext("N/A: ecroF evitisoP");
break;
case 10:
songname = loc::gettext("7: Popular Potpourri");
break;
case 11:
songname = loc::gettext("8: Pipe Dream");
break;
case 12:
songname = loc::gettext("9: Pressure Cooker");
break;
case 13:
songname = loc::gettext("10: Paced Energy");
break;
case 14:
songname = loc::gettext("11: Piercing the Sky");
break;
case 15:
songname = loc::gettext("N/A: Predestined Fate Remix");
break;
default:
songname = loc::gettext("?: something else");
break;
}
font::print_wrap(PR_CEN, -1, 120, songname, tr, tg, tb);
break;
}
case Menu::ed_quit:
font::print_wrap(PR_CEN, -1, 90, loc::gettext("Save before quitting?"), tr, tg, tb);
break;
case Menu::ed_font:
{
font::print(PR_2X | PR_CEN, -1, 30, loc::gettext("Level Font"), tr, tg, tb);
font::print_wrap(PR_CEN, -1, 65, loc::gettext("Select the language in which the text in this level is written."), tr, tg, tb);
const char* label = loc::gettext("Font: ");
int len_label = font::len(0, label);
const char* name = font::get_level_font_display_name();
font::print(0, 2, 230, label, tr/2, tg/2, tb/2);
font::print(PR_FONT_LEVEL, 2+len_label, 230, name, tr/2, tg/2, tb/2);
break;
}
default:
break;
}
}
void editorrender(void)
{
extern editorclass ed;
const RoomProperty* const room = cl.getroomprop(ed.levx, ed.levy);
//Draw grid
graphics.clear();
for(int j=0; j<30; j++)
{
for(int i=0; i<40; i++)
{
fillbox(i*8, j*8, (i*8)+7, (j*8)+7, graphics.getRGB(8,8,8)); //a simple grid
if(i%4==0) fillbox(i*8, j*8, (i*8)+7, (j*8)+7, graphics.getRGB(16,16,16));
if(j%4==0) fillbox(i*8, j*8, (i*8)+7, (j*8)+7, graphics.getRGB(16,16,16));
//Minor guides
if(i==9) fillbox(i*8, j*8, (i*8)+7, (j*8)+7, graphics.getRGB(24,24,24));
if(i==30) fillbox(i*8, j*8, (i*8)+7, (j*8)+7, graphics.getRGB(24,24,24));
if(j==6 || j==7) fillbox(i*8, j*8, (i*8)+7, (j*8)+7, graphics.getRGB(24,24,24));
if(j==21 || j==22) fillbox(i*8, j*8, (i*8)+7, (j*8)+7, graphics.getRGB(24,24,24));
//Major guides
if(i==20 || i==19) fillbox(i*8, j*8, (i*8)+7, (j*8)+7, graphics.getRGB(32,32,32));
if(j==14) fillbox(i*8, j*8, (i*8)+7, (j*8)+7, graphics.getRGB(32,32,32));
}
}
//Or draw background
if(!ed.settingsmod)
{
switch(room->warpdir)
{
case 1:
graphics.rcol=cl.getwarpbackground(ed.levx, ed.levy);
graphics.drawbackground(3);
break;
case 2:
graphics.rcol=cl.getwarpbackground(ed.levx, ed.levy);
graphics.drawbackground(4);
break;
case 3:
graphics.rcol=cl.getwarpbackground(ed.levx, ed.levy);
graphics.drawbackground(5);
break;
default:
break;
}
}
//Draw map, in function
for (int j = 0; j < 30; j++)
{
for (int i = 0; i < 40; i++)
{
const int tile = cl.gettile(ed.levx, ed.levy, i, j);
if (tile <= 0)
{
continue;
}
if (room->tileset == 0)
{
graphics.drawtile(i * 8, j * 8, tile);
}
else
{
graphics.drawtile2(i * 8, j * 8, tile);
}
}
}
//Edge tile fix
//Buffer the sides of the new room with tiles from other rooms, to ensure no gap problems.
for(int j=0; j<30; j++)
{
//left edge
if(ed.freewrap((ed.levx*40)-1,j+(ed.levy*30))==1)
{
graphics.fill_rect(0,j*8, 2,8, graphics.getRGB(255 - help.glow, 255, 255));
}
//right edge
if(ed.freewrap((ed.levx*40)+40,j+(ed.levy*30))==1)
{
graphics.fill_rect(318,j*8, 2,8, graphics.getRGB(255 - help.glow, 255, 255));
}
}
for(int i=0; i<40; i++)
{
if(ed.freewrap((ed.levx*40)+i,(ed.levy*30)-1)==1)
{
graphics.fill_rect(i*8,0, 8,2, graphics.getRGB(255 - help.glow, 255, 255));
}
if(ed.freewrap((ed.levx*40)+i,30+(ed.levy*30))==1)
{
graphics.fill_rect(i*8,238, 8,2, graphics.getRGB(255 - help.glow, 255, 255));
}
}
//Draw entities
obj.customplatformtile=game.customcol*12;
const int edent_under_cursor = edentat(ed.tilex + ed.levx*40, ed.tiley + ed.levy*30);
// Special case for drawing gray entities
bool custom_gray = room->tileset == 3 && room->tilecol == 6;
// Draw entities backward to remain accurate with ingame
for (int i = customentities.size() - 1; i >= 0; i--)
{
SDL_Point tpoint;
SDL_Rect drawRect;
//if() on screen
if(customentities[i].x / 40 == ed.levx && customentities[i].y / 30 == ed.levy)
{
switch(customentities[i].t)
{
case 1: //Entities
if (custom_gray)
{
ed.entcolreal = graphics.getcol(18);
}
graphics.draw_sprite((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),ed.getenemyframe(room->enemytype),ed.entcolreal);
if(customentities[i].p1==0) font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8)+4,(customentities[i].y*8)- (ed.levy*30*8)+4, "V", 255, 255, 255 - help.glow);
if(customentities[i].p1==1) font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8)+4,(customentities[i].y*8)- (ed.levy*30*8)+4, "^", 255, 255, 255 - help.glow);
if(customentities[i].p1==2) font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8)+4,(customentities[i].y*8)- (ed.levy*30*8)+4, "<", 255, 255, 255 - help.glow);
if(customentities[i].p1==3) font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8)+4,(customentities[i].y*8)- (ed.levy*30*8)+4, ">", 255, 255, 255 - help.glow);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),16,16,graphics.getRGB(255,164,255));
break;
case 2: //Threadmills & platforms
tpoint.x = (customentities[i].x*8)- (ed.levx*40*8);
tpoint.y = (customentities[i].y*8)- (ed.levy*30*8);
drawRect = graphics.tiles_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
for (int j = 0; j < 4; j++) {
graphics.draw_grid_tile(custom_gray ? graphics.grphx.im_entcolours_tint : graphics.grphx.im_entcolours, obj.customplatformtile, drawRect.x, drawRect.y, 8, 8);
drawRect.x += 8;
}
if(customentities[i].p1<=4)
{
if(customentities[i].p1==0) font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8)+12,(customentities[i].y*8)- (ed.levy*30*8), "V", 255 - help.glow, 255 - help.glow, 255 - help.glow);
if(customentities[i].p1==1) font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8)+12,(customentities[i].y*8)- (ed.levy*30*8), "^", 255 - help.glow, 255 - help.glow, 255 - help.glow);
if(customentities[i].p1==2) font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8)+12,(customentities[i].y*8)- (ed.levy*30*8), "<", 255 - help.glow, 255 - help.glow, 255 - help.glow);
if(customentities[i].p1==3) font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8)+12,(customentities[i].y*8)- (ed.levy*30*8), ">", 255 - help.glow, 255 - help.glow, 255 - help.glow);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),32,8,graphics.getRGB(255,255,255));
}
if(customentities[i].p1==5)
{
font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8), ">>>>", 255 - help.glow, 255 - help.glow, 255 - help.glow);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),32,8,graphics.getRGB(255,255,255));
}
else if(customentities[i].p1==6)
{
font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8), "<<<<", 255 - help.glow, 255 - help.glow, 255 - help.glow);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),32,8,graphics.getRGB(255,255,255));
}
if(customentities[i].p1>=7)
{
tpoint.x = (customentities[i].x*8)- (ed.levx*40*8)+32;
tpoint.y = (customentities[i].y*8)- (ed.levy*30*8);
drawRect = graphics.tiles_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
for (int j = 0; j < 4; j++) {
graphics.draw_grid_tile(custom_gray ? graphics.grphx.im_entcolours_tint : graphics.grphx.im_entcolours, obj.customplatformtile, drawRect.x, drawRect.y, 8, 8);
drawRect.x += 8;
}
}
if(customentities[i].p1==7)
{
font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8)+4,(customentities[i].y*8)- (ed.levy*30*8), "> > > > ", 255 - help.glow, 255 - help.glow, 255 - help.glow);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),64,8,graphics.getRGB(255,255,255));
}
else if(customentities[i].p1==8)
{
font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8)+4,(customentities[i].y*8)- (ed.levy*30*8), "< < < < ", 255 - help.glow, 255 - help.glow, 255 - help.glow);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),64,8,graphics.getRGB(255,255,255));
}
break;
case 3: //Disappearing Platform
tpoint.x = (customentities[i].x*8)- (ed.levx*40*8);
tpoint.y = (customentities[i].y*8)- (ed.levy*30*8);
drawRect = graphics.tiles_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
for (int j = 0; j < 4; j++) {
graphics.draw_grid_tile(custom_gray ? graphics.grphx.im_entcolours_tint : graphics.grphx.im_entcolours, obj.customplatformtile, drawRect.x, drawRect.y, 8, 8);
drawRect.x += 8;
}
font::print(PR_FONT_8X8, (customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8), "////", 255 - help.glow, 255 - help.glow, 255 - help.glow);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),32,8,graphics.getRGB(255,255,255));
break;
case 9: //Shiny Trinket
graphics.draw_sprite((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),22,196,196,196);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),16,16,graphics.getRGB(255, 164, 164));
break;
case 10: //Checkpoints
graphics.draw_sprite((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),20 + customentities[i].p1,196,196,196);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),16,16,graphics.getRGB(255, 164, 164));
break;
case 11: //Gravity lines
if(customentities[i].p1==0) //Horizontal
{
int tx = customentities[i].p2;
int tx2 = tx + customentities[i].p3/8;
int ty = customentities[i].y % 30;
graphics.fill_rect((tx*8),(ty*8)+4, (tx2-tx)*8,1, graphics.getRGB(194,194,194));
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),8,8,graphics.getRGB(164,255,164));
}
else //Vertical
{
int tx = customentities[i].x % 40;
int ty = customentities[i].p2;
int ty2 = ty + customentities[i].p3/8;
graphics.fill_rect((tx*8)+3,(ty*8), 1,(ty2-ty)*8, graphics.getRGB(194,194,194));
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),8,8,graphics.getRGB(164,255,164));
}
break;
case 13://Warp tokens
graphics.draw_sprite((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),18+(ed.entframe%2),196,196,196);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),16,16,graphics.getRGB(255, 164, 164));
if (i == edent_under_cursor)
{
font::print(PR_BOR | PR_CJK_HIGH, (customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8)-8,
"("+help.String(customentities[i].p1/40 + 1)+","+help.String(customentities[i].p2/30 + 1)+")",210,210,255);
}
else
{
font::print(PR_BOR | PR_CJK_HIGH, (customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8)-8,help.String(cl.findwarptoken(i)),210,210,255);
}
break;
case 15: //Crewmates
graphics.draw_sprite((customentities[i].x*8)- (ed.levx*40*8)-4,(customentities[i].y*8)- (ed.levy*30*8),144,graphics.crewcolourreal(customentities[i].p1));
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),16,24,graphics.getRGB(164,164,164));
break;
case 16: //Start
{
if(customentities[i].p1==0) //Left
{
graphics.draw_sprite((customentities[i].x*8)- (ed.levx*40*8)-4,(customentities[i].y*8)- (ed.levy*30*8),0,graphics.col_crewcyan);
}
else if(customentities[i].p1==1)
{
graphics.draw_sprite((customentities[i].x*8)- (ed.levx*40*8)-4,(customentities[i].y*8)- (ed.levy*30*8),3,graphics.col_crewcyan);
}
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),16,24,graphics.getRGB(255, 255, 164));
short labelcol = ed.entframe<2 ? 255 : 196;
font::print(
PR_BOR | PR_CEN | PR_CJK_HIGH,
(customentities[i].x*8) - (ed.levx*40*8) + 8,
(customentities[i].y*8) - (ed.levy*30*8) - 8,
loc::gettext("START"),
labelcol,labelcol,labelcol
);
break;
}
case 17: //Roomtext
if(customentities[i].scriptname.length()<1)
{
fillboxabs((customentities[i].x*8)-(ed.levx*40*8), (customentities[i].y*8)-(ed.levy*30*8), 8, 8, graphics.getRGB(96,96,96));
}
else
{
fillboxabs((customentities[i].x*8)-(ed.levx*40*8), (customentities[i].y*8)-(ed.levy*30*8), font::len(PR_FONT_LEVEL, customentities[i].scriptname.c_str()), font::height(PR_FONT_LEVEL), graphics.getRGB(96,96,96));
}
font::print(PR_FONT_LEVEL | PR_CJK_LOW, (customentities[i].x*8)-(ed.levx*40*8), (customentities[i].y*8)-(ed.levy*30*8), customentities[i].scriptname, 196, 196, 255 - help.glow);
break;
case 18: //Terminals
{
int usethistile = customentities[i].p1;
int usethisy = (customentities[i].y % 30) * 8;
// Not a boolean: just swapping 0 and 1, leaving the rest alone
if (usethistile == 0)
{
usethistile = 1; // Unflipped
}
else if (usethistile == 1)
{
usethistile = 0; // Flipped;
usethisy -= 8;
}
graphics.draw_sprite((customentities[i].x*8)- (ed.levx*40*8), usethisy + 8, usethistile + 16, 96,96,96);
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),16,24,graphics.getRGB(164,164,164));
if (i == edent_under_cursor)
{
font::print(PR_FONT_LEVEL | PR_BOR | PR_CJK_HIGH, (customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8)-8,customentities[i].scriptname,210,210,255);
}
break;
}
case 19: //Script Triggers
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),customentities[i].p1*8,customentities[i].p2*8,graphics.getRGB(255,164,255));
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),8,8,graphics.getRGB(255,255,255));
if (i == edent_under_cursor)
{
font::print(PR_FONT_LEVEL | PR_BOR | PR_CJK_HIGH, (customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8)-8,customentities[i].scriptname,210,210,255);
}
break;
case 50: //Warp lines
if(customentities[i].p1>=2) //Horizontal
{
int tx=customentities[i].x-(ed.levx*40);
int tx2=customentities[i].x-(ed.levx*40);
int ty=customentities[i].y-(ed.levy*30);
if (customentities[i].p4 != 1)
{
// Unlocked
while(ed.free(tx,ty)==0) tx--;
while(ed.free(tx2,ty)==0) tx2++;
tx++;
customentities[i].p2=tx;
customentities[i].p3=(tx2-tx)*8;
}
else
{
// Locked
tx = customentities[i].p2;
tx2 = tx + customentities[i].p3/8;
}
fillboxabs((tx*8),(ty*8)+1, (tx2-tx)*8,6, graphics.getRGB(194, 255, 255));
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),8,8,graphics.getRGB(164, 255, 255));
}
else //Vertical
{
int tx=customentities[i].x-(ed.levx*40);
int ty=customentities[i].y-(ed.levy*30);
int ty2=customentities[i].y-(ed.levy*30);
if (customentities[i].p4 != 1)
{
// Unlocked
while(ed.free(tx,ty)==0) ty--;
while(ed.free(tx,ty2)==0) ty2++;
ty++;
customentities[i].p2=ty;
customentities[i].p3=(ty2-ty)*8;
}
else
{
// Locked
ty = customentities[i].p2;
ty2 = ty + customentities[i].p3/8;
}
fillboxabs((tx*8)+1,(ty*8), 6,(ty2-ty)*8, graphics.getRGB(194, 255, 255));
fillboxabs((customentities[i].x*8)- (ed.levx*40*8),(customentities[i].y*8)- (ed.levy*30*8),8,8,graphics.getRGB(164, 255, 255));
}
break;
}
}
//Need to also check warp point destinations
if(customentities[i].t==13 && ed.warpent!=i)
{
if (customentities[i].p1 / 40 == ed.levx && customentities[i].p2 / 30 == ed.levy)
{
graphics.draw_sprite((customentities[i].p1*8)- (ed.levx*40*8),(customentities[i].p2*8)- (ed.levy*30*8),18+(ed.entframe%2),64,64,64);
fillboxabs((customentities[i].p1*8)- (ed.levx*40*8),(customentities[i].p2*8)- (ed.levy*30*8),16,16,graphics.getRGB(96, 64, 64));
if(ed.tilex+(ed.levx*40)==customentities[i].p1 && ed.tiley+(ed.levy*30)==customentities[i].p2)
{
font::print(PR_BOR | PR_CJK_HIGH, (customentities[i].p1*8)- (ed.levx*40*8),(customentities[i].p2*8)- (ed.levy*30*8)-8,
"("+help.String(customentities[i].x/40 + 1)+","+help.String(customentities[i].y/30 + 1)+")",190,190,225);
}
else
{
font::print(PR_BOR | PR_CJK_HIGH, (customentities[i].p1*8)- (ed.levx*40*8),(customentities[i].p2*8)- (ed.levy*30*8)-8,help.String(cl.findwarptoken(i)),190,190,225);
}
}
}
}
if(ed.boundarymod>0)
{
if(ed.boundarymod==1)
{
fillboxabs(ed.tilex*8, ed.tiley*8, 8,8,graphics.getRGB(210 + help.glow/2, 191 + help.glow, 255 - help.glow/2));
fillboxabs((ed.tilex*8)+2, (ed.tiley*8)+2, 4,4,graphics.getRGB(105 + help.glow/4, 100 + help.glow/2, 128 - help.glow/4));
}
else if(ed.boundarymod==2)
{
if((ed.tilex*8)+8<=ed.boundx1 || (ed.tiley*8)+8<=ed.boundy1)
{
fillboxabs(ed.boundx1, ed.boundy1, 8, 8,graphics.getRGB(210 + help.glow/2, 191 + help.glow, 255 - help.glow/2));
fillboxabs(ed.boundx1+2, ed.boundy1+2, 4, 4,graphics.getRGB(105 + help.glow/4, 100 + help.glow/2, 128 - help.glow/4));
}
else
{
fillboxabs(ed.boundx1, ed.boundy1, (ed.tilex*8)+8-ed.boundx1,(ed.tiley*8)+8-ed.boundy1,graphics.getRGB(210 + help.glow/2, 191 + help.glow, 255 - help.glow/2));
fillboxabs(ed.boundx1+2, ed.boundy1+2, (ed.tilex*8)+8-ed.boundx1-4,(ed.tiley*8)+8-ed.boundy1-4,graphics.getRGB(105 + help.glow/4, 100 + help.glow/2, 128 - help.glow/4));
}
}
}
else
{
//Draw boundaries
if(room->enemyx1!=0 || room->enemyy1!=0
|| room->enemyx2!=320 || room->enemyy2!=240)
{
fillboxabs( room->enemyx1, room->enemyy1,
room->enemyx2-room->enemyx1,
room->enemyy2-room->enemyy1,
graphics.getRGB(255-(help.glow/2),64,64));
}
if(room->platx1!=0 || room->platy1!=0
|| room->platx2!=320 || room->platy2!=240)
{
fillboxabs( room->platx1, room->platy1,
room->platx2-room->platx1,
room->platy2-room->platy1,
graphics.getRGB(64,64,255-(help.glow/2)));
}
}
//Draw ghosts (spooky!)
if (game.ghostsenabled) {
graphics.set_render_target(graphics.ghostTexture);
graphics.set_blendmode(graphics.ghostTexture, SDL_BLENDMODE_BLEND);
graphics.clear(0, 0, 0, 0);
for (int i = 0; i < (int)ed.ghosts.size(); i++) {
if (i <= ed.currentghosts) { // We don't want all of them to show up at once :)
if (ed.ghosts[i].rx != ed.levx || ed.ghosts[i].ry != ed.levy)
continue;
SDL_Point tpoint;
tpoint.x = ed.ghosts[i].x;
tpoint.y = ed.ghosts[i].y;
SDL_Color ct = ed.ghosts[i].realcol;
const int alpha = 3 * ct.a / 4;
ct.a = (Uint8) alpha;
SDL_Rect drawRect = graphics.sprites_rect;
drawRect.x += tpoint.x;
drawRect.y += tpoint.y;
graphics.draw_sprite(drawRect.x, drawRect.y, ed.ghosts[i].frame, ct);
}
}
graphics.set_render_target(graphics.gameTexture);
graphics.set_texture_alpha_mod(graphics.ghostTexture, 128);
graphics.copy_texture(graphics.ghostTexture, NULL, NULL);
}
//Draw Cursor
switch(ed.drawmode)
{
case 0:
case 1:
case 2:
case 9:
case 10:
case 12: //Single point
fillboxabs((ed.tilex*8),(ed.tiley*8),8,8, graphics.getRGB(32, 32, 200));
break;
case 3:
case 4:
case 8:
case 13://2x2
fillboxabs((ed.tilex*8),(ed.tiley*8),16,16, graphics.getRGB(32, 32, 200));
break;
case 5:
case 6:
case 7://Platform
fillboxabs((ed.tilex*8),(ed.tiley*8),32,8, graphics.getRGB(32, 32, 200));
break;
case 14: //X if not on edge
if(ed.tilex==0 || ed.tilex==39 || ed.tiley==0 || ed.tiley==29)
{
fillboxabs((ed.tilex*8),(ed.tiley*8),8,8, graphics.getRGB(32, 32, 200));
}
else
{
font::print(PR_FONT_8X8, (ed.tilex*8),(ed.tiley*8),"X",255,0,0);
}
break;
case 11:
case 15:
case 16: //2x3
fillboxabs((ed.tilex*8),(ed.tiley*8),16,24, graphics.getRGB(32, 32, 200));
break;
}
if(ed.drawmode<3)
{
if(ed.bmod && ed.drawmode<2)
{
fillboxabs((ed.tilex*8),0,8,240,graphics.getRGB(32, 32, 200));
}
else if(ed.hmod && ed.drawmode<2)
{
fillboxabs(0,(ed.tiley*8),320,8,graphics.getRGB(32, 32, 200));
}
else if(ed.vmod && ed.drawmode<2)
{
fillboxabs((ed.tilex*8)-32,(ed.tiley*8)-32,24+48,24+48, graphics.getRGB(32, 32, 200));
}
else if(ed.cmod && ed.drawmode<2)
{
fillboxabs((ed.tilex*8)-24,(ed.tiley*8)-24,24+32,24+32, graphics.getRGB(32, 32, 200));
}
else if(ed.xmod && ed.drawmode<2)
{
fillboxabs((ed.tilex*8)-16,(ed.tiley*8)-16,24+16,24+16, graphics.getRGB(32, 32, 200));
}
else if(ed.zmod && ed.drawmode<2)
{
fillboxabs((ed.tilex*8)-8,(ed.tiley*8)-8,24,24, graphics.getRGB(32, 32, 200));
}
}
//If in directmode, show current directmode tile
if(room->directmode==1)
{
//Tile box for direct mode
int t2=0;
if(ed.dmtileeditor>0)
{
if(ed.dmtileeditor<=4)
{
t2=graphics.lerp((4-ed.dmtileeditor+1)*12, (4-ed.dmtileeditor)*12);
}
//Draw five lines of the editor
const int temp = ed.dmtile - (ed.dmtile % 40) - 80;
graphics.fill_rect(0,-t2,320,40, graphics.getRGB(0,0,0));
graphics.fill_rect(0,-t2+40,320,2, graphics.getRGB(255,255,255));
int texturewidth;
int textureheight;
if (room->tileset == 0)
{
if (graphics.query_texture(graphics.grphx.im_tiles, NULL, NULL, &texturewidth, &textureheight) != 0)
{
return;
}
const int numtiles = (int) (texturewidth / 8) * (textureheight / 8);
for(int i=0; i<40; i++)
{
graphics.drawtile(i*8,0-t2,(temp+numtiles+i)%numtiles);
graphics.drawtile(i*8,8-t2,(temp+numtiles+40+i)%numtiles);
graphics.drawtile(i*8,16-t2,(temp+numtiles+80+i)%numtiles);
graphics.drawtile(i*8,24-t2,(temp+numtiles+120+i)%numtiles);
graphics.drawtile(i*8,32-t2,(temp+numtiles+160+i)%numtiles);
}
}
else
{
if (graphics.query_texture(graphics.grphx.im_tiles2, NULL, NULL, &texturewidth, &textureheight) != 0)
{
return;
}
const int numtiles = (int) (texturewidth / 8) * (textureheight / 8);
for(int i=0; i<40; i++)
{
graphics.drawtile2(i*8,0-t2,(temp+numtiles+i)%numtiles);
graphics.drawtile2(i*8,8-t2,(temp+numtiles+40+i)%numtiles);
graphics.drawtile2(i*8,16-t2,(temp+numtiles+80+i)%numtiles);
graphics.drawtile2(i*8,24-t2,(temp+numtiles+120+i)%numtiles);
graphics.drawtile2(i*8,32-t2,(temp+numtiles+160+i)%numtiles);
}
}
//Highlight our little block
fillboxabs(((ed.dmtile%40)*8)-2,16-t2-2,12,12,graphics.getRGB(255 - help.glow, 196, 196));
fillboxabs(((ed.dmtile%40)*8)-1,16-t2-1,10,10,graphics.getRGB(0,0,0));
}
if(ed.dmtileeditor>0 && t2<=30)
{
short labellen = 2 + font::len(0, loc::gettext("Tile:"));
font::print(PR_BOR, 2, 45-t2, loc::gettext("Tile:"), 196, 196, 255 - help.glow);
font::print(PR_BOR, labellen+16, 45-t2, help.String(ed.dmtile), 196, 196, 255 - help.glow);
graphics.fill_rect(labellen+2,44-t2,10,10, graphics.getRGB(255 - help.glow, 196, 196));
graphics.fill_rect(labellen+3,45-t2,8,8, graphics.getRGB(0,0,0));
if(room->tileset==0)
{
graphics.drawtile(labellen+3,45-t2,ed.dmtile);
}
else
{
graphics.drawtile2(labellen+3,45-t2,ed.dmtile);
}
}
else
{
short labellen = 2 + font::len(0, loc::gettext("Tile:"));
int y = 2 + font::height(0);
y = SDL_max(y, 12);
font::print(PR_BOR, 2, y, loc::gettext("Tile:"), 196, 196, 255 - help.glow);
font::print(PR_BOR, labellen+16, y, help.String(ed.dmtile), 196, 196, 255 - help.glow);
graphics.fill_rect(labellen+2, y-1, 10,10, graphics.getRGB(255 - help.glow, 196, 196));
graphics.fill_rect(labellen+3, y, 8,8, graphics.getRGB(0,0,0));
if(room->tileset==0)
{
graphics.drawtile(labellen+3,12,ed.dmtile);
}
else
{
graphics.drawtile2(labellen+3,12,ed.dmtile);
}
}
}
//Draw GUI
if(ed.boundarymod>0)
{
std::string message;
if(ed.boundarymod==1)
{
switch(ed.boundarytype)
{
case 0:
message = loc::gettext("SCRIPT BOX: Click on top left");
break;
case 1:
message = loc::gettext("ENEMY BOUNDS: Click on top left");
break;
case 2:
message = loc::gettext("PLATFORM BOUNDS: Click on top left");
break;
default:
message = loc::gettext("Click on top left");
break;
}
}
else if(ed.boundarymod==2)
{
switch(ed.boundarytype)
{
case 0:
message = loc::gettext("SCRIPT BOX: Click on bottom right");
break;
case 1:
message = loc::gettext("ENEMY BOUNDS: Click on bottom right");
break;
case 2:
message = loc::gettext("PLATFORM BOUNDS: Click on bottom right");
break;
default:
message = loc::gettext("Click on bottom right");
break;
}
}
short lines;
message = font::string_wordwrap(0, message, 312, &lines);
short textheight = font::height(0)*lines;
graphics.fill_rect(0,238-textheight,320,240, graphics.getRGB(32,32,32));
graphics.fill_rect(0,239-textheight,320,240, graphics.getRGB(0,0,0));
font::print_wrap(0, 4, 240-textheight, message.c_str(), 255,255,255, 8, 312);
}
else if(ed.scripteditmod)
{
//Elaborate C64 BASIC menu goes here!
graphics.fill_rect(0,0,320,240, graphics.getRGB(123, 111, 218));
graphics.fill_rect(14,16,292,208, graphics.getRGB(61, 48, 162));
switch(ed.scripthelppage)
{
case 0:
font::print(PR_CEN, -1,28,loc::gettext("**** VVVVVV SCRIPT EDITOR ****"), 123, 111, 218);
font::print(PR_CEN, -1,44,loc::gettext("PRESS ESC TO RETURN TO MENU"), 123, 111, 218);
if(!ed.hooklist.empty())
{
for(int i=0; i<9; i++)
{
if(ed.hookmenupage+i<(int)ed.hooklist.size())
{
if(ed.hookmenupage+i==ed.hookmenu)
{
std::string text_upper(loc::toupper(ed.hooklist[(ed.hooklist.size()-1)-(ed.hookmenupage+i)]));
char buffer[SCREEN_WIDTH_CHARS + 1];
vformat_buf(buffer, sizeof(buffer), loc::get_langmeta()->menu_select.c_str(), "label:str", text_upper.c_str());
font::print(PR_CEN, -1, 68+(i*16), buffer, 123, 111, 218);
}
else
{
font::print(PR_CEN, -1, 68+(i*16), ed.hooklist[(ed.hooklist.size()-1)-(ed.hookmenupage+i)], 123, 111, 218);
}
}
}
}
else
{
font::print(PR_CEN, -1,110,loc::gettext("NO SCRIPT IDS FOUND"), 123, 111, 218);
font::print_wrap(PR_CEN, -1,130,loc::gettext("CREATE A SCRIPT WITH EITHER THE TERMINAL OR SCRIPT BOX TOOLS"), 123, 111, 218, 10, 288);
}
break;
case 1:
{
//Current scriptname
graphics.fill_rect(14,226,292,12, graphics.getRGB(61, 48, 162));
char namebuffer[SCREEN_WIDTH_CHARS + 1];
vformat_buf(
namebuffer, sizeof(namebuffer),
loc::gettext("CURRENT SCRIPT: {name}"),
"name:str",
ed.sbscript.c_str()
);
font::print(PR_CEN, -1,228, namebuffer, 123, 111, 218);
//Draw text
int font_height = font::height(PR_FONT_LEVEL);
for(int i=0; i<ed.lines_visible; i++)
{
if(i+ed.pagey<(int)ed.sb.size())
{
font::print(PR_FONT_LEVEL | PR_CJK_LOW, 16, 20+(i*font_height), ed.sb[i+ed.pagey], 123, 111, 218);
}
}
//Draw cursor
if(ed.entframe<2)
{
font::print(PR_FONT_LEVEL | PR_CJK_LOW, 16+font::len(PR_FONT_LEVEL, ed.sb[ed.pagey+ed.sby].c_str()),20+(ed.sby*font_height),"_",123, 111, 218);
}
break;
}
}
}
else if(ed.settingsmod)
{
if(!game.colourblindmode)
{
graphics.drawtowerbackground(graphics.titlebg);
}
else
{
graphics.clear();
}
int tr = graphics.titlebg.r - (help.glow / 4) - int(fRandom() * 4);
int tg = graphics.titlebg.g - (help.glow / 4) - int(fRandom() * 4);
int tb = graphics.titlebg.b - (help.glow / 4) - int(fRandom() * 4);
if (tr < 0) tr = 0;
if(tr>255) tr=255;
if (tg < 0) tg = 0;
if(tg>255) tg=255;
if (tb < 0) tb = 0;
if(tb>255) tb=255;
editormenurender(tr, tg, tb);
graphics.drawmenu(tr, tg, tb, game.currentmenuname);
}
else if (ed.textmod)
{
short lines;
std::string wrapped = font::string_wordwrap(0, ed.textdesc, 312, &lines);
short textheight = font::height(0)*lines+font::height(PR_FONT_LEVEL);
graphics.fill_rect(0, 238-textheight, 320, 240, graphics.getRGB(32, 32, 32));
graphics.fill_rect(0, 239-textheight, 320, 240, graphics.getRGB(0, 0, 0));
font::print_wrap(0, 4, 240-textheight, wrapped.c_str(), 255, 255, 255, 8, 312);
std::string input = key.keybuffer;
if (ed.entframe < 2)
{
input += "_";
}
else
{
input += " ";
}
font::print(PR_CEN | PR_FONT_LEVEL | PR_CJK_HIGH, -1, 232, input, 196, 196, 255 - help.glow);
}
else if(ed.warpmod)
{
//placing warp token
int textheight = font::height(0);
graphics.fill_rect(0,237-textheight*2,320,240, graphics.getRGB(32,32,32));
graphics.fill_rect(0,238-textheight*2,320,240, graphics.getRGB(0,0,0));
font::print(PR_CJK_LOW, 4, 240-textheight*2, loc::gettext("Left click to place warp destination"), 196, 196, 255 - help.glow);
font::print(PR_CJK_LOW, 4, 240-textheight, loc::gettext("Right click to cancel"), 196, 196, 255 - help.glow);
}
else
{
char coords[8];
SDL_snprintf(coords, sizeof(coords), "(%d,%d)", ed.levx+1, ed.levy+1);
if(ed.spacemod)
{
graphics.fill_rect(0,207,320,240, graphics.getRGB(32,32,32));
graphics.fill_rect(0,208,320,240, graphics.getRGB(0,0,0));
//Draw little icons for each thingy
int tx=6, ty=210, tg=32;
if(ed.spacemenu==0)
{
for(int i=0; i<10; i++)
{
graphics.fill_rect(4+(i*tg), 208,20,20,graphics.getRGB(32,32,32));
}
graphics.fill_rect(4+(ed.drawmode*tg), 208,20,20,graphics.getRGB(64,64,64));
//0:
graphics.drawtile(tx,ty,83);
graphics.drawtile(tx+8,ty,83);
graphics.drawtile(tx,ty+8,83);
graphics.drawtile(tx+8,ty+8,83);
//1:
tx+=tg;
graphics.drawtile(tx,ty,680);
graphics.drawtile(tx+8,ty,680);
graphics.drawtile(tx,ty+8,680);
graphics.drawtile(tx+8,ty+8,680);
//2:
tx+=tg;
graphics.drawtile(tx+4,ty+4,8);
//3:
tx+=tg;
graphics.draw_sprite(tx,ty,22,196,196,196);
//4:
tx+=tg;
graphics.draw_sprite(tx,ty,21,196,196,196);
//5:
tx+=tg;
graphics.drawtile(tx,ty+4,3);
graphics.drawtile(tx+8,ty+4,4);
//6:
tx+=tg;
graphics.drawtile(tx,ty+4,24);
graphics.drawtile(tx+8,ty+4,24);
//7:
tx+=tg;
graphics.drawtile(tx,ty+4,1);
graphics.drawtile(tx+8,ty+4,1);
//8:
tx+=tg;
graphics.draw_sprite(tx,ty,78+ed.entframe,196,196,196);
//9:
tx+=tg;
graphics.fill_rect(tx+2,ty+8,12,1,graphics.getRGB(255,255,255));
for (int i = 0; i < 10; i++)
{
fillboxabs(4+(i*tg), 208,20,20,graphics.getRGB(96,96,96));
if (i == ed.drawmode)
{
fillboxabs(4+(ed.drawmode*tg), 208,20,20,graphics.getRGB(200,200,200));
}
const int col = i == ed.drawmode ? 255 : 164;
const std::string glyph = i == 9 ? "0" : help.String(i + 1);
font::print(PR_FONT_8X8 | PR_BOR, 22 + i*tg - 4, 224 - 4, glyph, col, col, col);
}
font::print(PR_CJK_HIGH, 4, 232, "1/2", 196, 196, 255 - help.glow);
}
else
{
for(int i=0; i<7; i++)
{
graphics.fill_rect(4+(i*tg), 208,20,20,graphics.getRGB(32,32,32));
}
graphics.fill_rect(4+((ed.drawmode-10)*tg), 208,20,20,graphics.getRGB(64,64,64));
//10:
font::print(PR_FONT_8X8, tx, ty, "AB", 196, 196, 255 - help.glow);
font::print(PR_FONT_8X8, tx, ty+8, "CD", 196, 196, 255 - help.glow);
//11:
tx+=tg;
graphics.draw_sprite(tx,ty,17,196,196,196);
//12:
tx+=tg;
fillboxabs(tx+4,ty+4,8,8,graphics.getRGB(96,96,96));
//13:
tx+=tg;
graphics.draw_sprite(tx,ty,18+(ed.entframe%2),196,196,196);
//14:
tx+=tg;
graphics.fill_rect(tx+6,ty+2,4,12,graphics.getRGB(255,255,255));
//15:
tx+=tg;
graphics.draw_sprite(tx,ty,186,graphics.col_crewblue);
//16:
tx+=tg;
graphics.draw_sprite(tx,ty,184,graphics.col_crewcyan);
for (int i = 0; i < 7; i++)
{
fillboxabs(4 + i*tg, 208, 20, 20, graphics.getRGB(96, 96, 96));
if (i + 10 == ed.drawmode)
{
fillboxabs(4 + (ed.drawmode - 10) * tg, 208, 20, 20, graphics.getRGB(200, 200, 200));
}
const int col = i + 10 == ed.drawmode ? 255 : 164;
static const char glyphs[] = "RTYUIOP";
font::print(PR_FONT_8X8 | PR_BOR, 22 + i*tg - 4, 224 - 4, std::string(1, glyphs[i]), col, col, col);
}
font::print(PR_CJK_HIGH, 4, 232, "2/2", 196, 196, 255 - help.glow);
}
char changetooltext[SCREEN_WIDTH_CHARS + 1];
vformat_buf(changetooltext, sizeof(changetooltext),
loc::gettext("{button1} and {button2} keys change tool"),
"button1:str, button2:str",
",", "."
);
font::print(PR_CJK_HIGH | PR_RIGHT, 320, 232, changetooltext, 196, 196, 255 - help.glow);
const char* toolname;
switch(ed.drawmode)
{
case 0:
toolname = loc::gettext("1: Walls");
break;
case 1:
toolname = loc::gettext("2: Backing");
break;
case 2:
toolname = loc::gettext("3: Spikes");
break;
case 3:
toolname = loc::gettext("4: Trinkets");
break;
case 4:
toolname = loc::gettext("5: Checkpoint");
break;
case 5:
toolname = loc::gettext("6: Disappear");
break;
case 6:
toolname = loc::gettext("7: Conveyors");
break;
case 7:
toolname = loc::gettext("8: Moving");
break;
case 8:
toolname = loc::gettext("9: Enemies");
break;
case 9:
toolname = loc::gettext("0: Grav Line");
break;
case 10:
toolname = loc::gettext("R: Roomtext");
break;
case 11:
toolname = loc::gettext("T: Terminal");
break;
case 12:
toolname = loc::gettext("Y: Script Box");
break;
case 13:
toolname = loc::gettext("U: Warp Token");
break;
case 14:
toolname = loc::gettext("I: Warp Lines");
break;
case 15:
toolname = loc::gettext("O: Crewmate");
break;
case 16:
toolname = loc::gettext("P: Start Point");
break;
default:
toolname = "???";
break;
}
int bgheight = 2 + font::height(0);
int toolnamelen = font::len(0, toolname);
graphics.fill_rect(0,206-bgheight,toolnamelen+8,bgheight+1, graphics.getRGB(32,32,32));
graphics.fill_rect(0,207-bgheight,toolnamelen+7,bgheight, graphics.getRGB(0,0,0));
font::print(PR_BOR | PR_CJK_HIGH, 2,198, toolname, 196, 196, 255 - help.glow);
int coordslen = font::len(0, coords);
graphics.fill_rect(319-coordslen-8,206-bgheight,coordslen+8,bgheight+1, graphics.getRGB(32,32,32));
graphics.fill_rect(320-coordslen-8,207-bgheight,coordslen+8,bgheight, graphics.getRGB(0,0,0));
font::print(PR_BOR | PR_CJK_HIGH | PR_RIGHT, 316, 198, coords, 196, 196, 255 - help.glow);
}
else
{
//graphics.fill_rect(0,230,72,240, graphics.RGB(32,32,32));
//graphics.fill_rect(0,231,71,240, graphics.RGB(0,0,0));
if(room->roomname!="")
{
int font_height = font::height(PR_FONT_LEVEL);
if (font_height <= 8)
{
graphics.footerrect.h = font_height + 2;
}
else
{
graphics.footerrect.h = font_height + 1;
}
graphics.footerrect.y = 240 - graphics.footerrect.h + ed.roomnamehide;
graphics.set_blendmode(SDL_BLENDMODE_BLEND);
graphics.fill_rect(&graphics.footerrect, graphics.getRGBA(0, 0, 0, graphics.translucentroomname ? 127 : 255));
graphics.set_blendmode(SDL_BLENDMODE_NONE);
font::print(PR_CEN | PR_BOR | PR_FONT_LEVEL | PR_CJK_LOW, -1, graphics.footerrect.y+1+ed.roomnamehide, room->roomname, 196, 196, 255 - help.glow);
font::print(PR_BOR | PR_CJK_HIGH, 4, 232-graphics.footerrect.h, loc::gettext("SPACE ^ SHIFT ^"), 196, 196, 255 - help.glow);
font::print(PR_BOR | PR_CJK_HIGH | PR_RIGHT, 316, 232-graphics.footerrect.h, coords, 196, 196, 255 - help.glow);
}
else
{
font::print(PR_BOR | PR_CJK_HIGH, 4, 232, loc::gettext("SPACE ^ SHIFT ^"), 196, 196, 255 - help.glow);
font::print(PR_BOR | PR_CJK_HIGH | PR_RIGHT, 316, 232, coords, 196, 196, 255 - help.glow);
}
}
if(ed.shiftmenu)
{
const char* shiftmenuoptions[] = {
loc::gettext("F1: Change Tileset"),
loc::gettext("F2: Change Colour"),
loc::gettext("F3: Change Enemies"),
loc::gettext("F4: Enemy Bounds"),
loc::gettext("F5: Platform Bounds"),
"",
loc::gettext("F9: Reload Resources"),
loc::gettext("F10: Direct Mode"),
"",
loc::gettext("W: Change Warp Dir"),
loc::gettext("E: Change Roomname"),
};
int menuwidth = 0;
for (size_t i = 0; i < SDL_arraysize(shiftmenuoptions); i++)
{
int len = font::len(0, shiftmenuoptions[i]);
if (len > menuwidth)
menuwidth = len;
}
int lineheight = font::height(0);
lineheight = SDL_max(10, lineheight);
int left_y = 230-SDL_arraysize(shiftmenuoptions)*lineheight;
fillboxabs(0, left_y-3, menuwidth+17, 240,graphics.getRGB(64,64,64));
graphics.fill_rect(0,left_y-2,menuwidth+16,240, graphics.getRGB(0,0,0));
for (size_t i = 0; i < SDL_arraysize(shiftmenuoptions); i++)
font::print(0, 4, left_y+i*lineheight, shiftmenuoptions[i], 164,164,164);
fillboxabs(220, 207,100,60,graphics.getRGB(64,64,64));
graphics.fill_rect(221,208,160,60, graphics.getRGB(0,0,0));
font::print(0, 224, 210, loc::gettext("S: Save Map"),164,164,164);
font::print(0, 224, 210+lineheight, loc::gettext("L: Load Map"),164,164,164);
}
}
if(!ed.settingsmod && !ed.scripteditmod)
{
//Same as above, without borders
switch(ed.drawmode)
{
case 0:
font::print(PR_BOR, 2,2, loc::gettext("1: Walls"),196, 196, 255 - help.glow);
break;
case 1:
font::print(PR_BOR, 2,2, loc::gettext("2: Backing"),196, 196, 255 - help.glow);
break;
case 2:
font::print(PR_BOR, 2,2, loc::gettext("3: Spikes"),196, 196, 255 - help.glow);
break;
case 3:
font::print(PR_BOR, 2,2, loc::gettext("4: Trinkets"),196, 196, 255 - help.glow);
break;
case 4:
font::print(PR_BOR, 2,2, loc::gettext("5: Checkpoint"),196, 196, 255 - help.glow);
break;
case 5:
font::print(PR_BOR, 2,2, loc::gettext("6: Disappear"),196, 196, 255 - help.glow);
break;
case 6:
font::print(PR_BOR, 2,2, loc::gettext("7: Conveyors"),196, 196, 255 - help.glow);
break;
case 7:
font::print(PR_BOR, 2,2, loc::gettext("8: Moving"),196, 196, 255 - help.glow);
break;
case 8:
font::print(PR_BOR, 2,2, loc::gettext("9: Enemies"),196, 196, 255 - help.glow);
break;
case 9:
font::print(PR_BOR, 2,2, loc::gettext("0: Grav Line"),196, 196, 255 - help.glow);
break;
case 10:
font::print(PR_BOR, 2,2, loc::gettext("R: Roomtext"),196, 196, 255 - help.glow);
break;
case 11:
font::print(PR_BOR, 2,2, loc::gettext("T: Terminal"),196, 196, 255 - help.glow);
break;
case 12:
font::print(PR_BOR, 2,2, loc::gettext("Y: Script Box"),196, 196, 255 - help.glow);
break;
case 13:
font::print(PR_BOR, 2,2, loc::gettext("U: Warp Token"),196, 196, 255 - help.glow);
break;
case 14:
font::print(PR_BOR, 2,2, loc::gettext("I: Warp Lines"),196, 196, 255 - help.glow);
break;
case 15:
font::print(PR_BOR, 2,2, loc::gettext("O: Crewmate"),196, 196, 255 - help.glow);
break;
case 16:
font::print(PR_BOR, 2,2, loc::gettext("P: Start Point"),196, 196, 255 - help.glow);
break;
}
}
if(ed.notedelay>0 || ed.oldnotedelay>0)
{
short lines;
std::string wrapped = font::string_wordwrap(0, ed.note, 304, &lines);
short textheight = 8+(lines-1)*SDL_max(10, font::height(0));
short banner_y = 120 - textheight/2 - 5;
float alpha = graphics.lerp(ed.oldnotedelay, ed.notedelay);
graphics.fill_rect(0, banner_y, 320, 10+textheight, graphics.getRGB(92,92,92));
graphics.fill_rect(0, banner_y+1, 320, 8+textheight, graphics.getRGB(0,0,0));
font::print_wrap(PR_CEN, -1,banner_y+5, wrapped.c_str(), 196-((45.0f-alpha)*4), 196-((45.0f-alpha)*4), 196-((45.0f-alpha)*4));
}
graphics.drawfade();
graphics.render();
}
void editorrenderfixed(void)
{
extern editorclass ed;
const RoomProperty* const room = cl.getroomprop(ed.levx, ed.levy);
graphics.updatetitlecolours();
game.customcol=cl.getlevelcol(room->tileset, room->tilecol)+1;
ed.entcol=cl.getenemycol(game.customcol);
ed.entcolreal = graphics.getcol(ed.entcol);
if (game.ghostsenabled)
{
for (size_t i = 0; i < ed.ghosts.size(); i++)
{
GhostInfo& ghost = ed.ghosts[i];
if ((int) i > ed.currentghosts || ghost.rx != ed.levx || ghost.ry != ed.levy)
{
continue;
}
ghost.realcol = graphics.getcol(ghost.col);
}
if (ed.currentghosts + 1 < (int)ed.ghosts.size()) {
ed.currentghosts++;
if (ed.zmod) ed.currentghosts++;
} else {
ed.currentghosts = (int)ed.ghosts.size() - 1;
}
}
if (!ed.settingsmod)
{
switch(room->warpdir)
{
case 1:
graphics.rcol=cl.getwarpbackground(ed.levx, ed.levy);
graphics.updatebackground(3);
break;
case 2:
graphics.rcol=cl.getwarpbackground(ed.levx, ed.levy);
graphics.updatebackground(4);
break;
case 3:
graphics.rcol=cl.getwarpbackground(ed.levx, ed.levy);
graphics.updatebackground(5);
break;
default:
break;
}
}
else if (!game.colourblindmode)
{
graphics.updatetowerbackground(graphics.titlebg);
}
/* Correct gravity lines */
for (size_t i = 0; i < customentities.size(); ++i)
{
if (customentities[i].x / 40 != ed.levx
|| customentities[i].y / 30 != ed.levy
|| customentities[i].t != 11
/* Is the gravity line locked? */
|| customentities[i].p4 == 1)
{
continue;
}
if (customentities[i].p1 == 0)
{
/* Horizontal */
int tx = customentities[i].x % 40;
int tx2 = tx;
int ty = customentities[i].y % 30;
while (!ed.spikefree(tx, ty))
{
--tx;
}
while (!ed.spikefree(tx2, ty))
{
++tx2;
}
++tx;
customentities[i].p2 = tx;
customentities[i].p3 = (tx2 - tx) * 8;
}
else
{
/* Vertical */
int tx = customentities[i].x % 40;
int ty = customentities[i].y % 30;
int ty2 = ty;
/* Unlocked */
while (!ed.spikefree(tx, ty))
{
--ty;
}
while (!ed.spikefree(tx, ty2))
{
++ty2;
}
++ty;
customentities[i].p2 = ty;
customentities[i].p3 = (ty2 - ty) * 8;
}
}
if (cl.getroomprop(ed.levx, ed.levy)->directmode == 1)
{
if (ed.dmtileeditor > 0)
{
ed.dmtileeditor--;
}
}
else
{
ed.dmtileeditor = 0;
}
if (cl.getroomprop(ed.levx, ed.levy)->roomname != "")
{
if (ed.tiley < 28)
{
if (ed.roomnamehide > 0)
{
ed.roomnamehide--;
}
}
else
{
if (ed.roomnamehide < 14)
{
ed.roomnamehide++;
}
}
}
else
{
if (ed.tiley < 28)
{
ed.roomnamehide = 0;
}
else
{
ed.roomnamehide = 14;
}
}
}
void editorlogic(void)
{
extern editorclass ed;
//Misc
help.updateglow();
graphics.titlebg.bypos -= 2;
graphics.titlebg.bscroll = -2;
ed.entframedelay--;
if(ed.entframedelay<=0)
{
ed.entframe=(ed.entframe+1)%4;
ed.entframedelay=8;
}
ed.oldnotedelay = ed.notedelay;
if(ed.notedelay>0)
{
ed.notedelay--;
}
if (graphics.fademode == FADE_FULLY_BLACK)
{
//Return to game
graphics.titlebg.colstate = 10;
map.nexttowercolour();
game.quittomenu();
music.play(6); //should be before game.quittomenu()
ed.settingsmod=false;
}
}
static void creategameoptions(void)
{
game.createmenu(Menu::options);
}
static void nextbgcolor(void)
{
map.nexttowercolour();
}
static void editormenuactionpress(void)
{
extern editorclass ed;
switch (game.currentmenuname)
{
case Menu::ed_desc:
switch (game.currentmenuoption)
{
case 0:
{
bool title_is_gettext;
translate_title(cl.title, &title_is_gettext);
ed.titlemod=true;
key.enabletextentry();
if (title_is_gettext)
{
key.keybuffer="";
}
else
{
key.keybuffer = cl.title;
}
break;
}
case 1:
{
bool creator_is_gettext;
translate_creator(cl.creator, &creator_is_gettext);
ed.creatormod=true;
key.enabletextentry();
if (creator_is_gettext)
{
key.keybuffer="";
}
else
{
key.keybuffer = cl.creator;
}
break;
}
case 2:
ed.desc1mod=true;
key.enabletextentry();
key.keybuffer=cl.Desc1;
break;
case 3:
ed.websitemod=true;
key.enabletextentry();
key.keybuffer=cl.website;
break;
case 4:
game.createmenu(Menu::ed_font);
map.nexttowercolour();
break;
case 5:
game.returnmenu();
map.nexttowercolour();
break;
}
music.playef(11);
break;
case Menu::ed_settings:
switch (game.currentmenuoption)
{
case 0:
//Change level description stuff
music.playef(11);
game.createmenu(Menu::ed_desc);
map.nexttowercolour();
break;
case 1:
//Enter script editormode
music.playef(11);
ed.scripteditmod=true;
ed.clearscriptbuffer();
key.keybuffer="";
ed.hookmenupage=0;
ed.hookmenu=0;
ed.scripthelppage=0;
ed.scripthelppagedelay=0;
ed.sby=0;
ed.sbx=0, ed.pagey=0;
ed.lines_visible = 200/font::height(PR_FONT_LEVEL);
break;
case 2:
music.playef(11);
game.createmenu(Menu::ed_music);
map.nexttowercolour();
if(cl.levmusic>0) music.play(cl.levmusic);
break;
case 3:
music.playef(11);
game.ghostsenabled = !game.ghostsenabled;
break;
case 4:
//Load level
ed.settingsmod = false;
map.nexttowercolour();
ed.keydelay = 6;
ed.getlin(TEXT_LOAD, loc::gettext("Enter map filename to load:"), &(ed.filename));
game.mapheld = true;
graphics.backgrounddrawn = false;
break;
case 5:
//Save level
ed.settingsmod=false;
map.nexttowercolour();
ed.keydelay = 6;
ed.getlin(TEXT_SAVE, loc::gettext("Enter map filename to save as:"), &(ed.filename));
game.mapheld = true;
graphics.backgrounddrawn = false;
break;
case 6:
/* Game options */
music.playef(11);
game.gamestate = TITLEMODE;
game.ingame_titlemode = true;
game.ingame_editormode = true;
DEFER_CALLBACK(creategameoptions);
DEFER_CALLBACK(nextbgcolor);
break;
default:
music.playef(11);
game.createmenu(Menu::ed_quit);
map.nexttowercolour();
break;
}
break;
case Menu::ed_music:
switch (game.currentmenuoption)
{
case 0:
case 1:
switch (game.currentmenuoption)
{
case 0:
cl.levmusic++;
break;
case 1:
cl.levmusic--;
break;
}
cl.levmusic = (cl.levmusic % 16 + 16) % 16;
if(cl.levmusic>0)
{
music.play(cl.levmusic);
}
else
{
music.haltdasmusik();
}
music.playef(11);
break;
case 2:
music.playef(11);
music.fadeout();
game.returnmenu();
map.nexttowercolour();
break;
}
break;
case Menu::ed_quit:
switch (game.currentmenuoption)
{
case 0:
//Saving and quit
ed.saveandquit=true;
ed.settingsmod=false;
map.nexttowercolour();
ed.keydelay = 6;
ed.getlin(TEXT_SAVE, loc::gettext("Enter map filename to save as:"), &(ed.filename));
game.mapheld = true;
graphics.backgrounddrawn = false;
break;
case 1:
//Quit without saving
music.playef(11);
music.fadeout();
graphics.fademode = FADE_START_FADEOUT;
graphics.backgrounddrawn = false;
break;
case 2:
//Go back to editor
music.playef(11);
game.returnmenu();
map.nexttowercolour();
break;
}
break;
case Menu::ed_font:
{
uint8_t idx_selected = font::font_idx_options[game.currentmenuoption];
cl.level_font_name = font::get_main_font_name(idx_selected);
if (idx_selected == loc::get_langmeta()->font_idx)
{
loc::new_level_font = "";
}
else
{
loc::new_level_font = cl.level_font_name;
}
font::set_level_font(cl.level_font_name.c_str());
music.playef(11);
game.returnmenu();
map.nexttowercolour();
game.savestatsandsettings_menu();
break;
}
default:
break;
}
}
void editorinput(void)
{
extern editorclass ed;
if (graphics.fademode == FADE_FADING_OUT)
{
return;
}
game.mx = (float) key.mx;
game.my = (float) key.my;
ed.tilex=(game.mx - (game.mx%8))/8;
ed.tiley=(game.my - (game.my%8))/8;
if (gameScreen.scalingMode == SCALING_STRETCH) {
// In this mode specifically, we have to fix the mouse coordinates
int screenwidth, screenheight;
gameScreen.GetScreenSize(&screenwidth, &screenheight);
ed.tilex = ed.tilex * 320 / screenwidth;
ed.tiley = ed.tiley * 240 / screenheight;
}
bool up_pressed = key.isDown(SDLK_UP) || key.isDown(SDL_CONTROLLER_BUTTON_DPAD_UP);
bool down_pressed = key.isDown(SDLK_DOWN) || key.isDown(SDL_CONTROLLER_BUTTON_DPAD_DOWN);
bool left_pressed = key.isDown(SDLK_LEFT) || key.isDown(SDL_CONTROLLER_BUTTON_DPAD_LEFT);
bool right_pressed = key.isDown(SDLK_RIGHT) || key.isDown(SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
game.press_left = false;
game.press_right = false;
game.press_action = false;
game.press_map = false;
game.press_interact = false;
if (key.isDown(KEYBOARD_LEFT) || key.isDown(KEYBOARD_a) || key.controllerWantsLeft(false))
{
game.press_left = true;
}
if (key.isDown(KEYBOARD_RIGHT) || key.isDown(KEYBOARD_d) || key.controllerWantsRight(false))
{
game.press_right = true;
}
if (key.isDown(KEYBOARD_z) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v) || key.isDown(game.controllerButton_flip))
{
game.press_action = true;
};
if (key.keymap[SDLK_F9] && (ed.keydelay==0)) {
ed.keydelay = 30;
ed.note=loc::gettext("Reloaded resources");
ed.notedelay=45;
graphics.reloadresources();
}
if (key.isDown(KEYBOARD_ENTER)) game.press_map = true;
if (key.isDown(27) && !ed.settingskey)
{
ed.settingskey=true;
if (ed.textmod)
{
key.disabletextentry();
if (ed.textmod >= FIRST_ENTTEXT && ed.textmod <= LAST_ENTTEXT)
{
*ed.textptr = ed.oldenttext;
if (ed.oldenttext == "")
{
removeedentity(ed.textent);
}
}
ed.textmod = TEXT_NONE;
ed.shiftmenu = false;
ed.shiftkey = false;
}
else if (key.textentry())
{
key.disabletextentry();
ed.titlemod=false;
ed.desc1mod=false;
ed.desc2mod=false;
ed.desc3mod=false;
ed.websitemod=false;
ed.creatormod=false;
music.playef(11);
ed.shiftmenu=false;
ed.shiftkey=false;
}
else if(ed.boundarymod>0)
{
ed.boundarymod=0;
}
else
{
bool esc_from_font = false;
music.playef(11);
if (ed.settingsmod)
{
if (ed.scripteditmod)
{
ed.scripteditmod = false;
}
else if (ed.settingsmod)
{
if (game.currentmenuname == Menu::ed_settings)
{
ed.settingsmod = false;
}
else if (game.currentmenuname == Menu::ed_font)
{
// Prevent double return
esc_from_font = true;
game.returnmenu();
map.nexttowercolour();
}
else
{
game.returnmenu();
map.nexttowercolour();
}
}
}
else
{
ed.settingsmod = true;
}
if (ed.settingsmod && !esc_from_font)
{
bool edsettings_in_stack = game.currentmenuname == Menu::ed_settings;
if (!edsettings_in_stack)
{
size_t i;
for (i = 0; i < game.menustack.size(); ++i)
{
if (game.menustack[i].name == Menu::ed_settings)
{
edsettings_in_stack = true;
break;
}
}
}
if (edsettings_in_stack)
{
game.returntomenu(Menu::ed_settings);
}
else
{
game.createmenu(Menu::ed_settings);
}
map.nexttowercolour();
}
}
}
if (!key.isDown(27))
{
ed.settingskey=false;
}
if(key.keymap[SDLK_LCTRL] || key.keymap[SDLK_RCTRL])
{
if(key.leftbutton) key.rightbutton=true;
}
if(ed.scripteditmod)
{
if(ed.scripthelppage==0)
{
//hook select menu
if(ed.keydelay>0) ed.keydelay--;
if(up_pressed && ed.keydelay<=0)
{
ed.keydelay=6;
ed.hookmenu--;
}
if(down_pressed && ed.keydelay<=0)
{
ed.keydelay=6;
ed.hookmenu++;
}
if(ed.hookmenu>=(int)ed.hooklist.size())
{
ed.hookmenu=ed.hooklist.size()-1;
}
if(ed.hookmenu<0) ed.hookmenu=0;
if(ed.hookmenu<ed.hookmenupage)
{
ed.hookmenupage=ed.hookmenu;
}
if(ed.hookmenu>=ed.hookmenupage+9)
{
ed.hookmenupage=ed.hookmenu+8;
}
if(!key.keymap[SDLK_BACKSPACE]) ed.deletekeyheld=0;
if(key.keymap[SDLK_BACKSPACE] && ed.deletekeyheld==0 && !ed.hooklist.empty())
{
ed.deletekeyheld=1;
music.playef(2);
ed.removehook(ed.hooklist[(ed.hooklist.size()-1)-ed.hookmenu]);
}
if (!game.press_action && !game.press_left && !game.press_right
&& !up_pressed && !down_pressed && !key.isDown(27)) game.jumpheld = false;
if (!game.jumpheld)
{
if (game.press_action || game.press_left || game.press_right || game.press_map
|| up_pressed || down_pressed || key.isDown(27))
{
game.jumpheld = true;
}
if ((game.press_action || game.press_map) && !ed.hooklist.empty())
{
game.mapheld=true;
ed.scripthelppage=1;
key.enabletextentry();
key.keybuffer="";
ed.sbscript=ed.hooklist[(ed.hooklist.size()-1)-ed.hookmenu];
ed.loadhookineditor(ed.sbscript);
ed.sby=ed.sb.size()-1;
ed.pagey=0;
while(ed.sby>=ed.lines_visible-5)
{
ed.pagey++;
ed.sby--;
}
key.keybuffer=ed.sb[ed.pagey+ed.sby];
ed.sbx = UTF8_total_codepoints(ed.sb[ed.pagey+ed.sby].c_str());
music.playef(11);
}
}
}
else if(ed.scripthelppage==1)
{
//Script editor!
if (key.isDown(27))
{
ed.scripthelppage=0;
game.jumpheld = true;
//save the script for use again!
ed.addhook(ed.sbscript);
}
if(ed.keydelay>0) ed.keydelay--;
if(up_pressed && ed.keydelay<=0)
{
ed.keydelay=6;
ed.sby--;
if(ed.sby<=5)
{
if(ed.pagey>0)
{
ed.pagey--;
ed.sby++;
}
else
{
if(ed.sby<0) ed.sby=0;
}
}
key.keybuffer=ed.sb[ed.pagey+ed.sby];
}
if(down_pressed && ed.keydelay<=0)
{
ed.keydelay=6;
if(ed.sby+ed.pagey<(int)ed.sb.size()-1)
{
ed.sby++;
if(ed.sby>=ed.lines_visible-5)
{
ed.pagey++;
ed.sby--;
}
}
key.keybuffer=ed.sb[ed.pagey+ed.sby];
}
if(key.linealreadyemptykludge)
{
ed.keydelay=6;
key.linealreadyemptykludge=false;
}
if(key.pressedbackspace && ed.sb[ed.pagey+ed.sby]=="" && ed.keydelay<=0)
{
//Remove this line completely
ed.removeline(ed.pagey+ed.sby);
ed.sby--;
if(ed.sby<=5)
{
if(ed.pagey>0)
{
ed.pagey--;
ed.sby++;
}
else
{
if(ed.sby<0) ed.sby=0;
}
}
key.keybuffer=ed.sb[ed.pagey+ed.sby];
ed.keydelay=6;
}
/* Remove all pipes, they are the line separator in the XML
* When this loop reaches the end, it wraps to SIZE_MAX; SIZE_MAX + 1 is 0 */
{size_t i; for (i = key.keybuffer.length() - 1; i + 1 > 0; --i)
{
if (key.keybuffer[i] == '|')
{
key.keybuffer.erase(key.keybuffer.begin() + i);
}
}}
ed.sb[ed.pagey+ed.sby]=key.keybuffer;
ed.sbx = UTF8_total_codepoints(ed.sb[ed.pagey+ed.sby].c_str());
if(!game.press_map && !key.isDown(27)) game.mapheld=false;
if (!game.mapheld)
{
if(game.press_map)
{
game.mapheld=true;
//Continue to next line
if(ed.sby+ed.pagey>=(int)ed.sb.size()) //we're on the last line
{
ed.sby++;
if(ed.sby>=ed.lines_visible-5)
{
ed.pagey++;
ed.sby--;
}
key.keybuffer=ed.sb[ed.pagey+ed.sby];
ed.sbx = UTF8_total_codepoints(ed.sb[ed.pagey+ed.sby].c_str());
}
else
{
//We're not, insert a line instead
ed.sby++;
if(ed.sby>=ed.lines_visible-5)
{
ed.pagey++;
ed.sby--;
}
ed.insertline(ed.sby+ed.pagey);
key.keybuffer="";
ed.sbx = 0;
}
}
}
}
}
else if (ed.textmod)
{
*ed.textptr = key.keybuffer;
if (!game.press_map && !key.isDown(27))
{
game.mapheld = false;
}
if (!game.mapheld && game.press_map)
{
game.mapheld = true;
key.disabletextentry();
switch (ed.textmod)
{
case TEXT_GOTOROOM:
{
char coord_x[16];
char coord_y[16];
const char* comma = SDL_strchr(key.keybuffer.c_str(), ',');
bool valid_input = comma != NULL;
if (valid_input)
{
SDL_strlcpy(
coord_x,
key.keybuffer.c_str(),
SDL_min((size_t) (comma - key.keybuffer.c_str() + 1), sizeof(coord_x))
);
SDL_strlcpy(coord_y, &comma[1], sizeof(coord_y));
valid_input = is_number(coord_x) && is_number(coord_y);
}
if (!valid_input)
{
ed.note = loc::gettext("ERROR: Invalid format");
ed.notedelay = 45;
break;
}
ed.levx = SDL_clamp(help.Int(coord_x) - 1, 0, cl.mapwidth - 1);
ed.levy = SDL_clamp(help.Int(coord_y) - 1, 0, cl.mapheight - 1);
graphics.backgrounddrawn = false;
break;
}
case TEXT_LOAD:
{
std::string loadstring = ed.filename + ".vvvvvv";
if (cl.load(loadstring))
{
// don't use filename, it has the full path
char buffer[3*SCREEN_WIDTH_CHARS + 1];
vformat_buf(buffer, sizeof(buffer), loc::gettext("Loaded map: {filename}.vvvvvv"), "filename:str", ed.filename.c_str());
ed.note = buffer;
}
else
{
ed.note = loc::gettext("ERROR: Could not load level");
}
ed.notedelay = 45;
break;
}
case TEXT_SAVE:
{
std::string savestring = ed.filename + ".vvvvvv";
if (cl.save(savestring))
{
char buffer[3*SCREEN_WIDTH_CHARS + 1];
vformat_buf(buffer, sizeof(buffer), loc::gettext("Saved map: {filename}.vvvvvv"), "filename:str", ed.filename.c_str());
ed.note = buffer;
}
else
{
ed.note = loc::gettext("ERROR: Could not save level!");
ed.saveandquit = false;
}
ed.notedelay = 45;
if (ed.saveandquit)
{
graphics.fademode = FADE_START_FADEOUT; /* quit editor */
}
break;
}
case TEXT_SCRIPT:
ed.clearscriptbuffer();
if (!ed.checkhook(key.keybuffer))
{
ed.addhook(key.keybuffer);
}
break;
default:
break;
}
ed.shiftmenu = false;
ed.shiftkey = false;
ed.textmod = TEXT_NONE;
}
}
else if (key.textentry())
{
if(ed.titlemod)
{
cl.title=key.keybuffer;
if (cl.title == "")
{
cl.title = "Untitled Level";
}
}
else if(ed.creatormod)
{
cl.creator=key.keybuffer;
if (cl.creator == "")
{
cl.creator = "Unknown";
}
}
else if(ed.websitemod)
{
cl.website=key.keybuffer;
}
else if(ed.desc1mod)
{
cl.Desc1=key.keybuffer;
}
else if(ed.desc2mod)
{
cl.Desc2=key.keybuffer;
}
else if(ed.desc3mod)
{
cl.Desc3=key.keybuffer;
}
if(!game.press_map && !key.isDown(27)) game.mapheld=false;
if (!game.mapheld)
{
if(game.press_map)
{
game.mapheld=true;
if(ed.titlemod)
{
cl.title=key.keybuffer;
if (cl.title == "")
{
cl.title = "Untitled Level";
}
ed.titlemod=false;
}
else if(ed.creatormod)
{
cl.creator=key.keybuffer;
if (cl.creator == "")
{
cl.creator = "Unknown";
}
ed.creatormod=false;
}
else if(ed.websitemod)
{
cl.website=key.keybuffer;
ed.websitemod=false;
}
else if(ed.desc1mod)
{
cl.Desc1=key.keybuffer;
}
else if(ed.desc2mod)
{
cl.Desc2=key.keybuffer;
}
else if(ed.desc3mod)
{
cl.Desc3=key.keybuffer;
ed.desc3mod=false;
}
key.disabletextentry();
if(ed.desc1mod)
{
ed.desc1mod=false;
ed.desc2mod=true;
key.enabletextentry();
key.keybuffer=cl.Desc2;
}
else if(ed.desc2mod)
{
ed.desc2mod=false;
if (font::height(PR_FONT_LEVEL) <= 10)
{
ed.desc3mod=true;
key.enabletextentry();
key.keybuffer=cl.Desc3;
}
else
{
cl.Desc3="";
}
}
music.playef(11);
}
}
}
else
{
if(ed.settingsmod)
{
if (!game.press_action && !game.press_left && !game.press_right
&& !up_pressed && !down_pressed) game.jumpheld = false;
if (!game.jumpheld)
{
if (game.press_action || game.press_left || game.press_right || game.press_map
|| up_pressed || down_pressed)
{
game.jumpheld = true;
}
if(game.menustart)
{
if (game.press_left || up_pressed)
{
game.currentmenuoption--;
}
else if (game.press_right || down_pressed)
{
game.currentmenuoption++;
}
}
if (game.currentmenuoption < 0) game.currentmenuoption = game.menuoptions.size()-1;
if (game.currentmenuoption >= (int) game.menuoptions.size() ) game.currentmenuoption = 0;
if (game.press_action)
{
editormenuactionpress();
}
}
}
else if (ed.keydelay > 0)
{
ed.keydelay--;
}
else if (key.keymap[SDLK_LCTRL] || key.keymap[SDLK_RCTRL])
{
// Ctrl modifiers
int texturewidth;
int textureheight;
if (cl.getroomprop(ed.levx, ed.levy)->tileset == 0)
{
if (graphics.query_texture(graphics.grphx.im_tiles, NULL, NULL, &texturewidth, &textureheight) != 0)
{
return;
}
}
else
{
if (graphics.query_texture(graphics.grphx.im_tiles2, NULL, NULL, &texturewidth, &textureheight) != 0)
{
return;
}
}
const int numtiles = (int) (texturewidth / 8) * (textureheight / 8);
ed.dmtileeditor=10;
if(left_pressed)
{
ed.dmtile--;
ed.keydelay=3;
if(ed.dmtile<0) ed.dmtile+=numtiles;
}
else if(right_pressed)
{
ed.dmtile++;
ed.keydelay=3;
if(ed.dmtile>=numtiles) ed.dmtile-=numtiles;
}
if(up_pressed)
{
ed.dmtile-=40;
ed.keydelay=3;
if(ed.dmtile<0) ed.dmtile+=numtiles;
}
else if(down_pressed)
{
ed.dmtile+=40;
ed.keydelay=3;
if(ed.dmtile>=numtiles) ed.dmtile-=numtiles;
}
}
else if (key.keymap[SDLK_LSHIFT] || key.keymap[SDLK_RSHIFT])
{
// Shift modifiers
if (key.keymap[SDLK_F1])
{
ed.switch_tileset(true);
ed.keydelay = 6;
}
if (key.keymap[SDLK_F2])
{
ed.switch_tilecol(true);
ed.keydelay = 6;
}
if (key.keymap[SDLK_F3])
{
ed.switch_enemy(true);
ed.keydelay=6;
}
if (key.keymap[SDLK_w])
{
ed.switch_warpdir(true);
ed.keydelay = 6;
}
if (up_pressed || down_pressed || left_pressed || right_pressed)
{
ed.keydelay=6;
if(up_pressed)
{
cl.mapheight--;
}
else if(down_pressed)
{
cl.mapheight++;
}
else if(left_pressed)
{
cl.mapwidth--;
}
else if(right_pressed)
{
cl.mapwidth++;
}
if(cl.mapwidth<1) cl.mapwidth=1;
if(cl.mapheight<1) cl.mapheight=1;
if(cl.mapwidth>=cl.maxwidth) cl.mapwidth=cl.maxwidth;
if(cl.mapheight>=cl.maxheight) cl.mapheight=cl.maxheight;
char buffer[3*SCREEN_WIDTH_CHARS + 1];
vformat_buf(
buffer, sizeof(buffer),
loc::gettext("Mapsize is now [{width},{height}]"),
"width:int, height:int",
cl.mapwidth, cl.mapheight
);
ed.note = buffer;
ed.notedelay=45;
}
if(!ed.shiftkey)
{
if(ed.shiftmenu)
{
ed.shiftmenu=false;
}
else
{
ed.shiftmenu=true;
}
}
ed.shiftkey=true;
}
else
{
// No modifiers
ed.shiftkey=false;
if(key.keymap[SDLK_F1])
{
ed.switch_tileset(false);
ed.keydelay = 6;
}
if(key.keymap[SDLK_F2])
{
ed.switch_tilecol(false);
ed.keydelay = 6;
}
if(key.keymap[SDLK_F3])
{
ed.switch_enemy(false);
ed.keydelay=6;
}
if(key.keymap[SDLK_F4])
{
ed.keydelay=6;
ed.boundarytype=1;
ed.boundarymod=1;
}
if(key.keymap[SDLK_F5])
{
ed.keydelay=6;
ed.boundarytype=2;
ed.boundarymod=1;
}
if(key.keymap[SDLK_F10])
{
if(cl.getroomprop(ed.levx, ed.levy)->directmode==1)
{
cl.setroomdirectmode(ed.levx, ed.levy, 0);
ed.note=loc::gettext("Direct Mode Disabled");
/* Kludge fix for rainbow BG here... */
if (cl.getroomprop(ed.levx, ed.levy)->tileset == 2
&& cl.getroomprop(ed.levx, ed.levy)->tilecol == 6)
{
cl.setroomtilecol(ed.levx, ed.levy, 0);
}
}
else
{
cl.setroomdirectmode(ed.levx, ed.levy, 1);
ed.note=loc::gettext("Direct Mode Enabled");
}
graphics.backgrounddrawn = false;
ed.notedelay = 45;
ed.updatetiles = true;
ed.keydelay = 6;
}
if(key.keymap[SDLK_1]) ed.drawmode=0;
if(key.keymap[SDLK_2]) ed.drawmode=1;
if(key.keymap[SDLK_3]) ed.drawmode=2;
if(key.keymap[SDLK_4]) ed.drawmode=3;
if(key.keymap[SDLK_5]) ed.drawmode=4;
if(key.keymap[SDLK_6]) ed.drawmode=5;
if(key.keymap[SDLK_7]) ed.drawmode=6;
if(key.keymap[SDLK_8]) ed.drawmode=7;
if(key.keymap[SDLK_9]) ed.drawmode=8;
if(key.keymap[SDLK_0]) ed.drawmode=9;
if(key.keymap[SDLK_r]) ed.drawmode=10;
if(key.keymap[SDLK_t]) ed.drawmode=11;
if(key.keymap[SDLK_y]) ed.drawmode=12;
if(key.keymap[SDLK_u]) ed.drawmode=13;
if(key.keymap[SDLK_i]) ed.drawmode=14;
if(key.keymap[SDLK_o]) ed.drawmode=15;
if(key.keymap[SDLK_p]) ed.drawmode=16;
if(key.keymap[SDLK_w])
{
ed.switch_warpdir(false);
ed.keydelay = 6;
}
if(key.keymap[SDLK_e])
{
ed.keydelay = 6;
ed.getlin(TEXT_ROOMNAME, loc::gettext("Enter new room name:"), const_cast<std::string*>(&(cl.getroomprop(ed.levx, ed.levy)->roomname)));
game.mapheld=true;
}
if (key.keymap[SDLK_g])
{
ed.keydelay = 6;
ed.getlin(TEXT_GOTOROOM, loc::gettext("Enter room coordinates x,y:"), NULL);
game.mapheld=true;
}
//Save and load
if(key.keymap[SDLK_s])
{
ed.keydelay = 6;
ed.getlin(TEXT_SAVE, loc::gettext("Enter map filename to save as:"), &(ed.filename));
game.mapheld=true;
}
if(key.keymap[SDLK_l])
{
ed.keydelay = 6;
ed.getlin(TEXT_LOAD, loc::gettext("Enter map filename to load:"), &(ed.filename));
game.mapheld=true;
}
if(!game.press_map) game.mapheld=false;
if (!game.mapheld)
{
if(game.press_map)
{
game.mapheld=true;
//Ok! Scan the room for the closest checkpoint
int testeditor=-1;
int startpoint=0;
//First up; is there a start point on this screen?
for(size_t i=0; i<customentities.size(); i++)
{
//if() on screen
if(customentities[i].t==16 && testeditor==-1)
{
int tx=customentities[i].x/40;
int ty=customentities[i].y/30;
if(tx==ed.levx && ty==ed.levy)
{
testeditor=i;
startpoint=1;
}
}
}
if(testeditor==-1)
{
//Ok, settle for a check point
for(size_t i=0; i<customentities.size(); i++)
{
//if() on screen
if(customentities[i].t==10 && testeditor==-1)
{
int tx=customentities[i].x/40;
int ty=customentities[i].y/30;
if(tx==ed.levx && ty==ed.levy)
{
testeditor=i;
}
}
}
}
if(testeditor==-1)
{
ed.note=loc::gettext("ERROR: No checkpoint to spawn at");
ed.notedelay=45;
}
else
{
ed.currentghosts = 0;
if(startpoint==0)
{
//Checkpoint spawn
int tx=customentities[testeditor].x/40;
int ty=customentities[testeditor].y/30;
game.edsavex = (customentities[testeditor].x%40)*8 - 4;
game.edsavey = (customentities[testeditor].y%30)*8;
game.edsaverx = 100+tx;
game.edsavery = 100+ty;
if (customentities[testeditor].p1 == 0) // NOT a bool check!
{
game.edsavegc = 1;
game.edsavey -= 2;
}
else
{
game.edsavegc = 0;
game.edsavey -= 7;
}
game.edsavedir = 0;
}
else
{
//Start point spawn
int tx=customentities[testeditor].x/40;
int ty=customentities[testeditor].y/30;
game.edsavex = (customentities[testeditor].x%40)*8 - 4;
game.edsavey = (customentities[testeditor].y%30)*8;
game.edsaverx = 100+tx;
game.edsavery = 100+ty;
game.edsavegc = 0;
game.edsavey++;
game.edsavedir=1-customentities[testeditor].p1;
}
music.haltdasmusik();
ed.returneditoralpha = 1000; // Let's start it higher than 255 since it gets clamped
ed.oldreturneditoralpha = 1000;
script.startgamemode(Start_EDITORPLAYTESTING);
}
}
}
ed.hmod = key.keymap[SDLK_h];
ed.vmod = key.keymap[SDLK_v];
ed.bmod = key.keymap[SDLK_b];
ed.cmod = key.keymap[SDLK_c];
ed.xmod = key.keymap[SDLK_x];
ed.zmod = key.keymap[SDLK_z];
if(key.keymap[SDLK_COMMA])
{
ed.drawmode--;
ed.keydelay=6;
}
else if(key.keymap[SDLK_PERIOD])
{
ed.drawmode++;
ed.keydelay=6;
}
if(ed.drawmode<0)
{
ed.drawmode=16;
if(ed.spacemod) ed.spacemenu=0;
}
if(ed.drawmode>16) ed.drawmode=0;
if(ed.drawmode>9)
{
if(ed.spacemod) ed.spacemenu=1;
}
else
{
if(ed.spacemod) ed.spacemenu=0;
}
if(up_pressed)
{
ed.keydelay = 6;
ed.levy--;
ed.updatetiles = true;
ed.changeroom = true;
graphics.backgrounddrawn = false;
}
else if(down_pressed)
{
ed.keydelay = 6;
ed.levy++;
ed.updatetiles = true;
ed.changeroom = true;
graphics.backgrounddrawn = false;
}
else if(left_pressed)
{
ed.keydelay = 6;
ed.levx--;
ed.updatetiles = true;
ed.changeroom = true;
graphics.backgrounddrawn = false;
}
else if(right_pressed)
{
ed.keydelay = 6;
ed.levx++;
ed.updatetiles = true;
ed.changeroom = true;
graphics.backgrounddrawn = false;
}
if (ed.levx < 0) ed.levx += cl.mapwidth;
if (ed.levx >= cl.mapwidth) ed.levx -= cl.mapwidth;
if (ed.levy < 0) ed.levy += cl.mapheight;
if (ed.levy >= cl.mapheight) ed.levy -= cl.mapheight;
if (key.keymap[SDLK_SPACE])
{
ed.spacemod = !ed.spacemod;
ed.keydelay = 6;
}
}
if(!ed.settingsmod)
{
if(ed.boundarymod>0)
{
if(key.leftbutton)
{
if(ed.lclickdelay==0)
{
if(ed.boundarymod==1)
{
ed.lclickdelay=1;
ed.boundx1=(ed.tilex*8);
ed.boundy1=(ed.tiley*8);
ed.boundarymod=2;
}
else if(ed.boundarymod==2)
{
if((ed.tilex*8)+8>=ed.boundx1 && (ed.tiley*8)+8>=ed.boundy1)
{
ed.boundx2=(ed.tilex*8)+8;
ed.boundy2=(ed.tiley*8)+8;
}
else
{
ed.boundx2=ed.boundx1+8;
ed.boundy2=ed.boundy1+8;
}
if(ed.boundarytype==0)
{
//Script trigger
ed.lclickdelay=1;
ed.textent=customentities.size();
addedentity((ed.boundx1/8)+(ed.levx*40),(ed.boundy1/8)+ (ed.levy*30),19,
(ed.boundx2-ed.boundx1)/8, (ed.boundy2-ed.boundy1)/8);
ed.getlin(TEXT_SCRIPT, loc::gettext("Enter script name:"), &(customentities[ed.textent].scriptname));
ed.lclickdelay=1;
}
else if(ed.boundarytype==1)
{
//Enemy bounds
cl.setroomenemyx1(ed.levx, ed.levy, ed.boundx1);
cl.setroomenemyy1(ed.levx, ed.levy, ed.boundy1);
cl.setroomenemyx2(ed.levx, ed.levy, ed.boundx2);
cl.setroomenemyy2(ed.levx, ed.levy, ed.boundy2);
}
else if(ed.boundarytype==2)
{
//Platform bounds
cl.setroomplatx1(ed.levx, ed.levy, ed.boundx1);
cl.setroomplaty1(ed.levx, ed.levy, ed.boundy1);
cl.setroomplatx2(ed.levx, ed.levy, ed.boundx2);
cl.setroomplaty2(ed.levx, ed.levy, ed.boundy2);
}
else if(ed.boundarytype==3)
{
//Copy
}
ed.boundarymod=0;
ed.lclickdelay=1;
}
}
}
else
{
ed.lclickdelay=0;
}
if(key.rightbutton)
{
ed.boundarymod=0;
}
}
else if(ed.warpmod)
{
//Placing warp token
if(key.leftbutton)
{
if(ed.lclickdelay==0)
{
if(ed.free(ed.tilex, ed.tiley)==0)
{
customentities[ed.warpent].p1=ed.tilex+(ed.levx*40);
customentities[ed.warpent].p2=ed.tiley+(ed.levy*30);
ed.warpmod=false;
ed.warpent=-1;
ed.lclickdelay=1;
}
}
}
else
{
ed.lclickdelay=0;
}
if(key.rightbutton)
{
removeedentity(ed.warpent);
ed.warpmod=false;
ed.warpent=-1;
}
}
else
{
//Mouse input
if(key.leftbutton)
{
if(ed.lclickdelay==0)
{
//Depending on current mode, place something
if(ed.drawmode==0)
{
//place tiles
//Are we in direct mode?
if(cl.getroomprop(ed.levx, ed.levy)->directmode>=1)
{
if(ed.bmod)
{
for(int i=0; i<30; i++)
{
ed.placetilelocal(ed.tilex, i, ed.dmtile);
}
}
else if(ed.hmod)
{
for(int i=0; i<40; i++)
{
ed.placetilelocal(i, ed.tiley, ed.dmtile);
}
}
else if(ed.vmod)
{
for(int j=-4; j<5; j++)
{
for(int i=-4; i<5; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, ed.dmtile);
}
}
}
else if(ed.cmod)
{
for(int j=-3; j<4; j++)
{
for(int i=-3; i<4; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, ed.dmtile);
}
}
}
else if(ed.xmod)
{
for(int j=-2; j<3; j++)
{
for(int i=-2; i<3; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, ed.dmtile);
}
}
}
else if(ed.zmod)
{
for(int j=-1; j<2; j++)
{
for(int i=-1; i<2; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, ed.dmtile);
}
}
}
else
{
ed.placetilelocal(ed.tilex, ed.tiley, ed.dmtile);
}
}
else
{
if(ed.bmod)
{
for(int i=0; i<30; i++)
{
ed.placetilelocal(ed.tilex, i, 80);
}
}
else if(ed.hmod)
{
for(int i=0; i<40; i++)
{
ed.placetilelocal(i, ed.tiley, 80);
}
}
else if(ed.vmod)
{
for(int j=-4; j<5; j++)
{
for(int i=-4; i<5; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 80);
}
}
}
else if(ed.cmod)
{
for(int j=-3; j<4; j++)
{
for(int i=-3; i<4; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 80);
}
}
}
else if(ed.xmod)
{
for(int j=-2; j<3; j++)
{
for(int i=-2; i<3; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 80);
}
}
}
else if(ed.zmod)
{
for(int j=-1; j<2; j++)
{
for(int i=-1; i<2; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 80);
}
}
}
else
{
ed.placetilelocal(ed.tilex, ed.tiley, 80);
}
}
}
else if(ed.drawmode==1)
{
//place background tiles
if(ed.bmod)
{
for(int i=0; i<30; i++)
{
ed.placetilelocal(ed.tilex, i, 2);
}
}
else if(ed.hmod)
{
for(int i=0; i<40; i++)
{
ed.placetilelocal(i, ed.tiley, 2);
}
}
else if(ed.vmod)
{
for(int j=-4; j<5; j++)
{
for(int i=-4; i<5; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 2);
}
}
}
else if(ed.cmod)
{
for(int j=-3; j<4; j++)
{
for(int i=-3; i<4; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 2);
}
}
}
else if(ed.xmod)
{
for(int j=-2; j<3; j++)
{
for(int i=-2; i<3; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 2);
}
}
}
else if(ed.zmod)
{
for(int j=-1; j<2; j++)
{
for(int i=-1; i<2; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 2);
}
}
}
else
{
ed.placetilelocal(ed.tilex, ed.tiley, 2);
}
}
else if(ed.drawmode==2)
{
//place spikes
ed.placetilelocal(ed.tilex, ed.tiley, 8);
}
int tmp=edentat(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30));
if(tmp==-1)
{
//Room text and script triggers can be placed in walls
if(ed.drawmode==10)
{
ed.lclickdelay=1;
ed.textent=customentities.size();
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),17);
ed.getlin(TEXT_ROOMTEXT, loc::gettext("Enter roomtext:"), &(customentities[ed.textent].scriptname));
}
else if(ed.drawmode==12) //Script Trigger
{
ed.boundarytype=0;
ed.boundx1=ed.tilex*8;
ed.boundy1=ed.tiley*8;
ed.boundarymod=2;
ed.lclickdelay=1;
}
}
if(tmp==-1 && ed.free(ed.tilex,ed.tiley)==0)
{
if(ed.drawmode==3)
{
if(cl.numtrinkets()<100)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),9);
ed.lclickdelay=1;
}
else
{
ed.note=loc::gettext("ERROR: Max number of trinkets is 100");
ed.notedelay=45;
}
}
else if(ed.drawmode==4)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),10, 1);
ed.lclickdelay=1;
}
else if(ed.drawmode==5)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),3);
ed.lclickdelay=1;
}
else if(ed.drawmode==6)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),2,5);
ed.lclickdelay=1;
}
else if(ed.drawmode==7)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),2,0);
ed.lclickdelay=1;
}
else if(ed.drawmode==8)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),1,0);
ed.lclickdelay=1;
}
else if(ed.drawmode==9)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),11,0);
ed.lclickdelay=1;
}
else if(ed.drawmode==11)
{
ed.lclickdelay=1;
ed.textent=customentities.size();
addedentity(ed.tilex+(ed.levx*40),ed.tiley+ (ed.levy*30),18,0);
ed.getlin(TEXT_SCRIPT, loc::gettext("Enter script name:"), &(customentities[ed.textent].scriptname));
}
else if(ed.drawmode==13)
{
ed.warpmod=true;
ed.warpent=customentities.size();
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),13);
ed.lclickdelay=1;
}
else if(ed.drawmode==14)
{
//Warp lines
if(ed.tilex==0)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),50,0);
}
else if(ed.tilex==39)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),50,1);
}
else if(ed.tiley==0)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),50,2);
}
else if(ed.tiley==29)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),50,3);
}
else
{
ed.note=loc::gettext("ERROR: Warp lines must be on edges");
ed.notedelay=45;
}
ed.lclickdelay=1;
}
else if(ed.drawmode==15) //Crewmate
{
if(cl.numcrewmates()<100)
{
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),15,int(fRandom() * 6));
ed.lclickdelay=1;
}
else
{
ed.note=loc::gettext("ERROR: Max number of crewmates is 100");
ed.notedelay=45;
}
}
else if(ed.drawmode==16) //Start Point
{
//If there is another start point, destroy it
for(size_t i=0; i<customentities.size(); i++)
{
if(customentities[i].t==16)
{
removeedentity(i);
i--;
}
}
addedentity(ed.tilex+ (ed.levx*40),ed.tiley+ (ed.levy*30),16,0);
ed.lclickdelay=1;
}
}
else if(tmp == -1)
{
//Important! Do nothing, or else Undefined Behavior will happen
}
else if(customentities[tmp].t==1)
{
customentities[tmp].p1=(customentities[tmp].p1+1)%4;
ed.lclickdelay=1;
}
else if(customentities[tmp].t==2)
{
if(customentities[tmp].p1>=5)
{
customentities[tmp].p1=(customentities[tmp].p1+1)%9;
if(customentities[tmp].p1<5) customentities[tmp].p1=5;
}
else
{
customentities[tmp].p1=(customentities[tmp].p1+1)%4;
}
ed.lclickdelay=1;
}
else if(customentities[tmp].t==10)
{
// If it's not textured as a checkpoint, leave it alone
if (customentities[tmp].p1 == 0 || customentities[tmp].p1 == 1)
{
customentities[tmp].p1=(customentities[tmp].p1+1)%2;
}
ed.lclickdelay=1;
}
else if(customentities[tmp].t==11)
{
customentities[tmp].p1=(customentities[tmp].p1+1)%2;
ed.lclickdelay=1;
}
else if(customentities[tmp].t==15)
{
customentities[tmp].p1=(customentities[tmp].p1+1)%6;
ed.lclickdelay=1;
}
else if(customentities[tmp].t==16)
{
customentities[tmp].p1=(customentities[tmp].p1+1)%2;
ed.lclickdelay=1;
}
else if(customentities[tmp].t==17)
{
ed.getlin(TEXT_ROOMTEXT, loc::gettext("Enter roomtext:"), &(customentities[tmp].scriptname));
ed.textent=tmp;
ed.lclickdelay=1;
}
else if(customentities[tmp].t==18 || customentities[tmp].t==19)
{
ed.lclickdelay=1;
ed.textent=tmp;
ed.getlin(TEXT_SCRIPT, loc::gettext("Enter script name:"), &(customentities[ed.textent].scriptname));
if (customentities[tmp].t == 18
&& (customentities[tmp].p1 == 0 || customentities[tmp].p1 == 1))
{
// Flip the terminal, but if it's not textured as a terminal leave it alone
customentities[tmp].p1 = (customentities[tmp].p1 + 1) % 2;
}
}
}
}
else
{
ed.lclickdelay=0;
}
if(key.rightbutton)
{
//place tiles
if(ed.drawmode < 2) {
if(ed.bmod)
{
for(int i=0; i<30; i++)
{
ed.placetilelocal(ed.tilex, i, 0);
}
}
else if(ed.hmod)
{
for(int i=0; i<40; i++)
{
ed.placetilelocal(i, ed.tiley, 0);
}
}
else if(ed.vmod)
{
for(int j=-4; j<5; j++)
{
for(int i=-4; i<5; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 0);
}
}
}
else if(ed.cmod)
{
for(int j=-3; j<4; j++)
{
for(int i=-3; i<4; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 0);
}
}
}
else if(ed.xmod)
{
for(int j=-2; j<3; j++)
{
for(int i=-2; i<3; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 0);
}
}
}
else if(ed.zmod)
{
for(int j=-1; j<2; j++)
{
for(int i=-1; i<2; i++)
{
ed.placetilelocal(ed.tilex+i, ed.tiley+j, 0);
}
}
}
else
{
ed.placetilelocal(ed.tilex, ed.tiley, 0);
}
}
else
{
ed.placetilelocal(ed.tilex, ed.tiley, 0);
}
for(size_t i=0; i<customentities.size(); i++)
{
if(customentities[i].x==ed.tilex + (ed.levx*40)&& customentities[i].y==ed.tiley+ (ed.levy*30))
{
removeedentity(i);
}
}
}
if(key.middlebutton)
{
ed.dmtile=cl.gettile(ed.levx, ed.levy, ed.tilex, ed.tiley);
}
}
}
}
if(ed.updatetiles && cl.getroomprop(ed.levx, ed.levy)->directmode==0)
{
ed.updatetiles=false;
//Correctly set the tiles in the current room
switch(cl.getroomprop(ed.levx, ed.levy)->tileset)
{
case 0: //The Space Station
for(int j=0; j<30; j++)
{
for(int i=0; i<40; i++)
{
int temp=cl.gettile(ed.levx, ed.levy, i, j);
if(temp>=3 && temp<80)
{
//Fix spikes
cl.settile(ed.levx, ed.levy, i, j, ed.spikedir(i, j));
}
else if(temp==2 || temp>=680)
{
//Fix background
cl.settile(
ed.levx,
ed.levy,
i,
j,
ed.backedgetile(i, j) + ed.backbase(ed.levx, ed.levy)
);
}
else if(temp>0)
{
//Fix tiles
cl.settile(
ed.levx,
ed.levy,
i,
j,
ed.edgetile(i, j) + ed.base(ed.levx, ed.levy)
);
}
}
}
break;
case 1: //Outside
for(int j=0; j<30; j++)
{
for(int i=0; i<40; i++)
{
int temp=cl.gettile(ed.levx, ed.levy, i, j);
if(temp>=3 && temp<80)
{
//Fix spikes
cl.settile(ed.levx, ed.levy, i, j, ed.spikedir(i, j));
}
else if(temp==2 || temp>=680)
{
//Fix background
cl.settile(
ed.levx,
ed.levy,
i,
j,
ed.outsideedgetile(i, j) + ed.backbase(ed.levx, ed.levy)
);
}
else if(temp>0)
{
//Fix tiles
cl.settile(
ed.levx,
ed.levy,
i,
j,
ed.edgetile(i, j) + ed.base(ed.levx, ed.levy)
);
}
}
}
break;
case 2: //Lab
for(int j=0; j<30; j++)
{
for(int i=0; i<40; i++)
{
int temp=cl.gettile(ed.levx, ed.levy, i, j);
if(temp>=3 && temp<80)
{
//Fix spikes
cl.settile(
ed.levx,
ed.levy,
i,
j,
ed.labspikedir(
i,
j,
cl.getroomprop(ed.levx, ed.levy)->tilecol
)
);
}
else if(temp==2 || temp>=680)
{
//Fix background
cl.settile(ed.levx, ed.levy, i, j, 713);
}
else if(temp>0)
{
//Fix tiles
cl.settile(
ed.levx,
ed.levy,
i,
j,
ed.edgetile(i, j) + ed.base(ed.levx, ed.levy)
);
}
}
}
break;
case 3: //Warp Zone/Intermission
for(int j=0; j<30; j++)
{
for(int i=0; i<40; i++)
{
int temp=cl.gettile(ed.levx, ed.levy, i, j);
if(temp>=3 && temp<80)
{
//Fix spikes
cl.settile(ed.levx, ed.levy, i, j, ed.spikedir(i, j));
}
else if(temp==2 || temp>=680)
{
//Fix background
cl.settile(ed.levx, ed.levy, i, j, 713);
}
else if(temp>0)
{
//Fix tiles
cl.settile(
ed.levx,
ed.levy,
i,
j,
ed.edgetile(i, j) + ed.base(ed.levx, ed.levy)
);
}
}
}
break;
case 4: //The ship
for(int j=0; j<30; j++)
{
for(int i=0; i<40; i++)
{
int temp=cl.gettile(ed.levx, ed.levy, i, j);
if(temp>=3 && temp<80)
{
//Fix spikes
cl.settile(ed.levx, ed.levy, i, j, ed.spikedir(i, j));
}
else if(temp==2 || temp>=680)
{
//Fix background
cl.settile(
ed.levx,
ed.levy,
i,
j,
ed.backedgetile(i, j) + ed.backbase(ed.levx, ed.levy)
);
}
else if(temp>0)
{
//Fix tiles
cl.settile(
ed.levx,
ed.levy,
i,
j,
ed.edgetile(i, j) + ed.base(ed.levx, ed.levy)
);
}
}
}
break;
case 5: //The Tower
break;
case 6: //Custom Set 1
break;
case 7: //Custom Set 2
break;
case 8: //Custom Set 3
break;
case 9: //Custom Set 4
break;
}
}
}
int editorclass::getenemyframe(int t)
{
switch(t)
{
case 0:
return 78;
break;
case 1:
return 88;
break;
case 2:
return 36;
break;
case 3:
return 164;
break;
case 4:
return 68;
break;
case 5:
return 48;
break;
case 6:
return 176;
break;
case 7:
return 168;
break;
case 8:
return 112;
break;
case 9:
return 114;
break;
default:
return 78;
break;
}
}
void editorclass::placetilelocal( int x, int y, int t )
{
if(x>=0 && y>=0 && x<40 && y<30)
{
cl.settile(levx, levy, x, y, t);
}
updatetiles=true;
}
int editorclass::base( int x, int y )
{
//Return the base tile for the given tileset and colour
const RoomProperty* const room = cl.getroomprop(x, y);
if(room->tileset==0) //Space Station
{
if(room->tilecol>=22)
{
return 483 + ((room->tilecol-22)*3);
}
else if(room->tilecol>=11)
{
return 283 + ((room->tilecol-11)*3);
}
else
{
return 83 + (room->tilecol*3);
}
}
else if(room->tileset==1) //Outside
{
return 480 + (room->tilecol*3);
}
else if(room->tileset==2) //Lab
{
return 280 + (room->tilecol*3);
}
else if(room->tileset==3) //Warp Zone/Intermission
{
return 80 + (room->tilecol*3);
}
else if(room->tileset==4) //SHIP
{
return 101 + (room->tilecol*3);
}
return 0;
}
int editorclass::backbase( int x, int y )
{
//Return the base tile for the background of the given tileset and colour
const RoomProperty* const room = cl.getroomprop(x, y);
if(room->tileset==0) //Space Station
{
//Pick depending on tilecol
switch(room->tilecol)
{
case 0:
case 5:
case 26:
return 680; //Blue
break;
case 3:
case 16:
case 23:
return 683; //Yellow
break;
case 9:
case 12:
case 21:
return 686; //Greeny Cyan
break;
case 4:
case 8:
case 24:
case 28:
case 30:
return 689; //Green
break;
case 20:
case 29:
return 692; //Orange
break;
case 2:
case 6:
case 11:
case 22:
case 27:
return 695; //Red
break;
case 1:
case 10:
case 15:
case 19:
case 31:
return 698; //Pink
break;
case 14:
case 18:
return 701; //Dark Blue
break;
case 7:
case 13:
case 17:
case 25:
return 704; //Cyan
break;
default:
return 680;
break;
}
}
else if(room->tileset==1) //outside
{
return 680 + (room->tilecol*3);
}
else if(room->tileset==2) //Lab
{
return 0;
}
else if(room->tileset==3) //Warp Zone/Intermission
{
return 120 + (room->tilecol*3);
}
else if(room->tileset==4) //SHIP
{
return 741 + (room->tilecol*3);
}
return 0;
}
int editorclass::at( int x, int y )
{
if(x<0) return at(0,y);
if(y<0) return at(x,0);
if(x>=40) return at(39,y);
if(y>=30) return at(x,29);
if(x>=0 && y>=0 && x<40 && y<30)
{
return cl.gettile(levx, levy, x, y);
}
return 0;
}
int editorclass::freewrap( int x, int y )
{
if(x<0) return freewrap(x+(cl.mapwidth*40),y);
if(y<0) return freewrap(x,y+(cl.mapheight*30));
if(x>=(cl.mapwidth*40)) return freewrap(x-(cl.mapwidth*40),y);
if(y>=(cl.mapheight*30)) return freewrap(x,y-(cl.mapheight*30));
if(x>=0 && y>=0 && x<(cl.mapwidth*40) && y<(cl.mapheight*30))
{
if(cl.getabstile(x, y)==0)
{
return 0;
}
else
{
if(cl.getabstile(x, y)>=2 && cl.getabstile(x, y)<80)
{
return 0;
}
if(cl.getabstile(x, y)>=680)
{
return 0;
}
}
}
return 1;
}
int editorclass::backonlyfree( int x, int y )
{
//Returns 1 if tile is a background tile, 0 otherwise
if(x<0) return backonlyfree(0,y);
if(y<0) return backonlyfree(x,0);
if(x>=40) return backonlyfree(39,y);
if(y>=30) return backonlyfree(x,29);
if(x>=0 && y>=0 && x<40 && y<30)
{
if(cl.gettile(levx, levy, x, y)>=680)
{
return 1;
}
}
return 0;
}
int editorclass::backfree( int x, int y )
{
//Returns 0 if tile is not a block or background tile, 1 otherwise
if(x<0) return backfree(0,y);
if(y<0) return backfree(x,0);
if(x>=40) return backfree(39,y);
if(y>=30) return backfree(x,29);
if(x>=0 && y>=0 && x<40 && y<30)
{
if(cl.gettile(levx, levy, x, y)==0)
{
return 0;
}
}
return 1;
}
int editorclass::spikefree( int x, int y )
{
//Returns 0 if tile is not a block or spike, 1 otherwise
if(x==-1) return free(0,y);
if(y==-1) return free(x,0);
if(x==40) return free(39,y);
if(y==30) return free(x,29);
if(x>=0 && y>=0 && x<40 && y<30)
{
if(cl.gettile(levx, levy, x, y)==0)
{
return 0;
}
else
{
if(cl.gettile(levx, levy, x, y)>=680)
{
return 0;
}
}
}
return 1;
}
int editorclass::free( int x, int y )
{
//Returns 0 if tile is not a block, 1 otherwise
if(x==-1) return free(0,y);
if(y==-1) return free(x,0);
if(x==40) return free(39,y);
if(y==30) return free(x,29);
if(x>=0 && y>=0 && x<40 && y<30)
{
if(cl.gettile(levx, levy, x, y)==0)
{
return 0;
}
else
{
if(cl.gettile(levx, levy, x, y)>=2 && cl.gettile(levx, levy, x, y)<80)
{
return 0;
}
if(cl.gettile(levx, levy, x, y)>=680)
{
return 0;
}
}
}
return 1;
}
int editorclass::match( int x, int y )
{
if(free(x-1,y)==0 && free(x,y-1)==0 && free(x+1,y)==0 && free(x,y+1)==0) return 0;
if(free(x-1,y)==0 && free(x,y-1)==0) return 10;
if(free(x+1,y)==0 && free(x,y-1)==0) return 11;
if(free(x-1,y)==0 && free(x,y+1)==0) return 12;
if(free(x+1,y)==0 && free(x,y+1)==0) return 13;
if(free(x,y-1)==0) return 1;
if(free(x-1,y)==0) return 2;
if(free(x,y+1)==0) return 3;
if(free(x+1,y)==0) return 4;
if(free(x-1,y-1)==0) return 5;
if(free(x+1,y-1)==0) return 6;
if(free(x-1,y+1)==0) return 7;
if(free(x+1,y+1)==0) return 8;
return 0;
}
int editorclass::outsidematch( int x, int y )
{
if(backonlyfree(x-1,y)==0 && backonlyfree(x+1,y)==0) return 2;
if(backonlyfree(x,y-1)==0 && backonlyfree(x,y+1)==0) return 1;
return 0;
}
int editorclass::backmatch( int x, int y )
{
//Returns the first position match for a border
// 5 1 6
// 2 X 4
// 7 3 8
if(backfree(x-1,y)==0 && backfree(x,y-1)==0 && backfree(x+1,y)==0 && backfree(x,y+1)==0) return 0;
if(backfree(x-1,y)==0 && backfree(x,y-1)==0) return 10;
if(backfree(x+1,y)==0 && backfree(x,y-1)==0) return 11;
if(backfree(x-1,y)==0 && backfree(x,y+1)==0) return 12;
if(backfree(x+1,y)==0 && backfree(x,y+1)==0) return 13;
if(backfree(x,y-1)==0) return 1;
if(backfree(x-1,y)==0) return 2;
if(backfree(x,y+1)==0) return 3;
if(backfree(x+1,y)==0) return 4;
if(backfree(x-1,y-1)==0) return 5;
if(backfree(x+1,y-1)==0) return 6;
if(backfree(x-1,y+1)==0) return 7;
if(backfree(x+1,y+1)==0) return 8;
return 0;
}
int editorclass::edgetile( int x, int y )
{
switch(match(x,y))
{
case 14:
return 0;
break;
case 10:
return 80;
break;
case 11:
return 82;
break;
case 12:
return 160;
break;
case 13:
return 162;
break;
case 1:
return 81;
break;
case 2:
return 120;
break;
case 3:
return 161;
break;
case 4:
return 122;
break;
case 5:
return 42;
break;
case 6:
return 41;
break;
case 7:
return 2;
break;
case 8:
return 1;
break;
case 0:
default:
return 0;
break;
}
}
int editorclass::outsideedgetile( int x, int y )
{
switch(outsidematch(x,y))
{
case 2:
return 0;
break;
case 1:
return 1;
break;
case 0:
default:
return 2;
break;
}
}
int editorclass::backedgetile( int x, int y )
{
switch(backmatch(x,y))
{
case 14:
return 0;
break;
case 10:
return 80;
break;
case 11:
return 82;
break;
case 12:
return 160;
break;
case 13:
return 162;
break;
case 1:
return 81;
break;
case 2:
return 120;
break;
case 3:
return 161;
break;
case 4:
return 122;
break;
case 5:
return 42;
break;
case 6:
return 41;
break;
case 7:
return 2;
break;
case 8:
return 1;
break;
case 0:
default:
return 0;
break;
}
}
int editorclass::labspikedir( int x, int y, int t )
{
// a slightly more tricky case
if(free(x,y+1)==1) return 63 + (t*2);
if(free(x,y-1)==1) return 64 + (t*2);
if(free(x-1,y)==1) return 51 + (t*2);
if(free(x+1,y)==1) return 52 + (t*2);
return 63 + (t*2);
}
int editorclass::spikedir( int x, int y )
{
if(free(x,y+1)==1) return 8;
if(free(x,y-1)==1) return 9;
if(free(x-1,y)==1) return 49;
if(free(x+1,y)==1) return 50;
return 8;
}
void editorclass::switch_tileset(const bool reversed)
{
const char* tilesets[] = {"Space Station", "Outside", "Lab", "Warp Zone", "Ship"};
int tiles = cl.getroomprop(levx, levy)->tileset;
if (reversed)
{
tiles--;
}
else
{
tiles++;
}
const int modulus = SDL_arraysize(tilesets);
tiles = POS_MOD(tiles, modulus);
cl.setroomtileset(levx, levy, tiles);
clamp_tilecol(levx, levy, false);
char buffer[3*SCREEN_WIDTH_CHARS + 1];
vformat_buf(
buffer, sizeof(buffer),
loc::gettext("Now using {area} Tileset"),
"area:str",
loc::gettext(tilesets[tiles])
);
note = buffer;
notedelay = 45;
updatetiles = true;
graphics.backgrounddrawn = false;
}
void editorclass::switch_tilecol(const bool reversed)
{
int tilecol = cl.getroomprop(levx, levy)->tilecol;
if (reversed)
{
tilecol--;
}
else
{
tilecol++;
}
cl.setroomtilecol(levx, levy, tilecol);
clamp_tilecol(levx, levy, true);
notedelay = 45;
note = loc::gettext("Tileset Colour Changed");
updatetiles = true;
graphics.backgrounddrawn = false;
}
void editorclass::clamp_tilecol(const int rx, const int ry, const bool wrap)
{
const RoomProperty* const room = cl.getroomprop(rx, ry);
const int tileset = room->tileset;
int tilecol = room->tilecol;
int mincol = -1;
int maxcol = 5;
// Only Space Station allows tileset -1
if (tileset != 0)
{
mincol = 0;
}
switch (tileset)
{
case 0:
maxcol = 31;
break;
case 1:
maxcol = 7;
break;
case 2:
if (room->directmode)
{
maxcol = 6;
}
break;
case 3:
maxcol = 6;
break;
case 5:
maxcol = 29;
break;
}
// If wrap is true, wrap-around, otherwise just cap
if (tilecol > maxcol)
{
tilecol = (wrap ? mincol : maxcol);
}
if (tilecol < mincol)
{
tilecol = (wrap ? maxcol : mincol);
}
cl.setroomtilecol(rx, ry, tilecol);
}
void editorclass::switch_enemy(const bool reversed)
{
const RoomProperty* const room = cl.getroomprop(levx, levy);
int enemy = room->enemytype;
if (reversed)
{
enemy--;
}
else
{
enemy++;
}
const int modulus = 10;
enemy = POS_MOD(enemy, modulus);
cl.setroomenemytype(levx, levy, enemy);
note = loc::gettext("Enemy Type Changed");
notedelay = 45;
}
void editorclass::switch_warpdir(const bool reversed)
{
static const int modulus = 4;
const RoomProperty* const room = cl.getroomprop(levx, levy);
int warpdir = room->warpdir;
if (reversed)
{
--warpdir;
}
else
{
++warpdir;
}
warpdir = POS_MOD(warpdir, modulus);
cl.setroomwarpdir(levx, levy, warpdir);
switch (warpdir)
{
default:
note = loc::gettext("Room warping disabled");
break;
case 1:
note = loc::gettext("Room warps horizontally");
break;
case 2:
note = loc::gettext("Room warps vertically");
break;
case 3:
note = loc::gettext("Room warps in all directions");
break;
}
notedelay = 45;
graphics.backgrounddrawn = false;
}
#endif /* NO_CUSTOM_LEVELS and NO_EDITOR */