mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-06-25 05:58:30 +02:00
Tools were a mess, spread all over the code with hundreds of `else-if` statements. Instead of magic numbers denoting tools, an enum has been created, and logic has been extracted into simple switch/cases, shared logic being deduplicated. The base of a state system for the editor has been created as well, laying a good path for further organization improvements. Because of this, the entire editor no longer gets drawn underneath the menus, except for a few pieces which I haven't extracted yet. Either way, this should be good for performance, if that was a concern.
4289 lines
127 KiB
C++
4289 lines
127 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 "Maths.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();
|
|
|
|
register_tool(EditorTool_WALLS, "Walls", "1", SDLK_1, false);
|
|
register_tool(EditorTool_BACKING, "Backing", "2", SDLK_2, false);
|
|
register_tool(EditorTool_SPIKES, "Spikes", "3", SDLK_3, false);
|
|
register_tool(EditorTool_TRINKETS, "Trinkets", "4", SDLK_4, false);
|
|
register_tool(EditorTool_CHECKPOINTS, "Checkpoints", "5", SDLK_5, false);
|
|
register_tool(EditorTool_DISAPPEARING_PLATFORMS, "Disappear", "6", SDLK_6, false);
|
|
register_tool(EditorTool_CONVEYORS, "Conveyors", "7", SDLK_7, false);
|
|
register_tool(EditorTool_MOVING_PLATFORMS, "Moving", "8", SDLK_8, false);
|
|
register_tool(EditorTool_ENEMIES, "Enemies", "9", SDLK_9, false);
|
|
register_tool(EditorTool_GRAVITY_LINES, "Grav Lines", "0", SDLK_0, false);
|
|
register_tool(EditorTool_ROOMTEXT, "Roomtext", "R", SDLK_r, false);
|
|
register_tool(EditorTool_TERMINALS, "Terminals", "T", SDLK_t, false);
|
|
register_tool(EditorTool_SCRIPTS, "Script Boxes", "Y", SDLK_y, false);
|
|
register_tool(EditorTool_WARP_TOKENS, "Warp Tokens", "U", SDLK_u, false);
|
|
register_tool(EditorTool_WARP_LINES, "Warp Lines", "I", SDLK_i, false);
|
|
register_tool(EditorTool_CREWMATES, "Crewmates", "O", SDLK_o, false);
|
|
register_tool(EditorTool_START_POINT, "Start Point", "P", SDLK_p, false);
|
|
}
|
|
|
|
void editorclass::reset(void)
|
|
{
|
|
current_tool = EditorTool_WALLS;
|
|
|
|
roomnamehide = 0;
|
|
zmod = false;
|
|
xmod = false;
|
|
cmod = false;
|
|
vmod = false;
|
|
hmod = false;
|
|
bmod = false;
|
|
spacemod = false;
|
|
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 = "";
|
|
|
|
state = EditorState_DRAW;
|
|
substate = EditorSubState_MAIN;
|
|
}
|
|
|
|
void editorclass::handle_tile_placement(const int tile)
|
|
{
|
|
int range = 1;
|
|
|
|
if (bmod)
|
|
{
|
|
// Vertical line
|
|
for (int i = 0; i < 30; i++)
|
|
{
|
|
settile(tilex, i, tile);
|
|
}
|
|
return;
|
|
}
|
|
else if (hmod)
|
|
{
|
|
// Horizontal line
|
|
for (int i = 0; i < 40; i++)
|
|
{
|
|
settile(i, tiley, tile);
|
|
}
|
|
return;
|
|
}
|
|
else if (vmod)
|
|
{
|
|
range = 4;
|
|
}
|
|
else if (cmod)
|
|
{
|
|
range = 3;
|
|
}
|
|
else if (xmod)
|
|
{
|
|
range = 2;
|
|
}
|
|
else if (zmod)
|
|
{
|
|
range = 1;
|
|
}
|
|
else
|
|
{
|
|
settile(tilex, tiley, tile);
|
|
return;
|
|
}
|
|
|
|
for (int i = -range; i <= range; i++)
|
|
{
|
|
for (int j = -range; j <= range; j++)
|
|
{
|
|
settile(tilex + i, tiley + j, tile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void editorclass::tool_remove()
|
|
{
|
|
switch (current_tool)
|
|
{
|
|
case EditorTool_WALLS:
|
|
case EditorTool_BACKING:
|
|
handle_tile_placement(0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
for (size_t i = 0; i < customentities.size(); i++)
|
|
{
|
|
if (customentities[i].x == tilex + (levx * 40) && customentities[i].y == tiley + (levy * 30))
|
|
{
|
|
removeedentity(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void editorclass::entity_clicked(const int index)
|
|
{
|
|
CustomEntity* entity = &customentities[index];
|
|
|
|
lclickdelay = 1;
|
|
|
|
switch (entity->t)
|
|
{
|
|
case 1:
|
|
// Enemies
|
|
entity->p1 = (entity->p1 + 1) % 4;
|
|
break;
|
|
case 2:
|
|
{
|
|
// Moving Platforms and Conveyors
|
|
const bool conveyor = entity->p1 >= 5;
|
|
entity->p1++;
|
|
if (conveyor)
|
|
{
|
|
entity->p1 = (entity->p1 - 5) % 4 + 5;
|
|
}
|
|
else
|
|
{
|
|
entity->p1 %= 4;
|
|
}
|
|
break;
|
|
}
|
|
case 10:
|
|
// Checkpoints
|
|
// If it's not textured as a checkpoint, then just leave it be
|
|
if (entity->p1 == 0 || entity->p1 == 1)
|
|
{
|
|
entity->p1 = (entity->p1 + 1) % 2;
|
|
}
|
|
break;
|
|
case 11:
|
|
case 16:
|
|
// Gravity Lines, Start Point
|
|
entity->p1 = (entity->p1 + 1) % 2;
|
|
break;
|
|
case 15:
|
|
// Crewmates
|
|
entity->p1 = (entity->p1 + 1) % 6;
|
|
break;
|
|
case 17:
|
|
// Roomtext
|
|
getlin(TEXT_ROOMTEXT, loc::gettext("Enter roomtext:"), &entity->scriptname);
|
|
textent = index;
|
|
break;
|
|
case 18:
|
|
// Terminals
|
|
if (entity->p1 == 0 || entity->p1 == 1)
|
|
{
|
|
// Flip the terminal, but if it's not textured as a terminal leave it alone
|
|
entity->p1 = (entity->p1 + 1) % 2;
|
|
}
|
|
SDL_FALLTHROUGH;
|
|
case 19:
|
|
// Script Boxes (and terminals)
|
|
getlin(TEXT_SCRIPT, loc::gettext("Enter script name:"), &entity->scriptname);
|
|
textent = index;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void editorclass::tool_place()
|
|
{
|
|
|
|
const int entity = edentat(tilex + (levx * 40), tiley + (levy * 30));
|
|
if (entity != -1)
|
|
{
|
|
entity_clicked(entity);
|
|
return;
|
|
}
|
|
|
|
switch (current_tool)
|
|
{
|
|
case EditorTool_WALLS:
|
|
case EditorTool_BACKING:
|
|
{
|
|
int tile = 0;
|
|
|
|
if (cl.getroomprop(levx, levy)->directmode >= 1)
|
|
{
|
|
tile = dmtile;
|
|
}
|
|
else if (current_tool == EditorTool_WALLS)
|
|
{
|
|
tile = 1;
|
|
}
|
|
else if (current_tool == EditorTool_BACKING)
|
|
{
|
|
tile = 2;
|
|
}
|
|
|
|
handle_tile_placement(tile);
|
|
break;
|
|
}
|
|
case EditorTool_SPIKES:
|
|
settile(tilex, tiley, 8);
|
|
break;
|
|
case EditorTool_TRINKETS:
|
|
if (cl.numtrinkets() < 100)
|
|
{
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 9);
|
|
lclickdelay = 1;
|
|
}
|
|
else
|
|
{
|
|
note = loc::gettext("ERROR: Max number of trinkets is 100");
|
|
notedelay = 45;
|
|
}
|
|
break;
|
|
case EditorTool_CHECKPOINTS:
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 10, 1);
|
|
lclickdelay = 1;
|
|
break;
|
|
case EditorTool_DISAPPEARING_PLATFORMS:
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 3);
|
|
lclickdelay = 1;
|
|
break;
|
|
case EditorTool_CONVEYORS:
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 2, 5);
|
|
lclickdelay = 1;
|
|
break;
|
|
case EditorTool_MOVING_PLATFORMS:
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 2, 0);
|
|
lclickdelay = 1;
|
|
break;
|
|
case EditorTool_ENEMIES:
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 1, 0);
|
|
lclickdelay = 1;
|
|
break;
|
|
case EditorTool_GRAVITY_LINES:
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 11, 0);
|
|
lclickdelay = 1;
|
|
break;
|
|
case EditorTool_ROOMTEXT:
|
|
lclickdelay = 1;
|
|
textent = customentities.size();
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 17);
|
|
getlin(TEXT_ROOMTEXT, loc::gettext("Enter roomtext:"), &(customentities[textent].scriptname));
|
|
break;
|
|
case EditorTool_TERMINALS:
|
|
lclickdelay = 1;
|
|
textent = customentities.size();
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 18, 0);
|
|
getlin(TEXT_SCRIPT, loc::gettext("Enter script name:"), &(customentities[textent].scriptname));
|
|
break;
|
|
case EditorTool_SCRIPTS:
|
|
boundarytype = 0;
|
|
boundx1 = tilex * 8;
|
|
boundy1 = tiley * 8;
|
|
boundarymod = 2;
|
|
lclickdelay = 1;
|
|
break;
|
|
case EditorTool_WARP_TOKENS:
|
|
warpmod = true;
|
|
warpent = customentities.size();
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 13);
|
|
lclickdelay = 1;
|
|
break;
|
|
case EditorTool_WARP_LINES:
|
|
//Warp lines
|
|
if (tilex == 0)
|
|
{
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 50, 0);
|
|
}
|
|
else if (tilex == 39)
|
|
{
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 50, 1);
|
|
}
|
|
else if (tiley == 0)
|
|
{
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 50, 2);
|
|
}
|
|
else if (tiley == 29)
|
|
{
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 50, 3);
|
|
}
|
|
else
|
|
{
|
|
note = loc::gettext("ERROR: Warp lines must be on edges");
|
|
notedelay = 45;
|
|
}
|
|
lclickdelay = 1;
|
|
break;
|
|
case EditorTool_CREWMATES:
|
|
if (cl.numcrewmates() < 100)
|
|
{
|
|
addedentity(tilex + (levx * 40), tiley + (levy * 30), 15, int(fRandom() * 6));
|
|
lclickdelay = 1;
|
|
}
|
|
else
|
|
{
|
|
note = loc::gettext("ERROR: Max number of crewmates is 100");
|
|
notedelay = 45;
|
|
}
|
|
break;
|
|
case EditorTool_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(tilex + (levx * 40), tiley + (levy * 30), 16, 0);
|
|
lclickdelay = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void editorclass::draw_tool(EditorTools tool, int x, int y)
|
|
{
|
|
extern editorclass ed;
|
|
|
|
switch (tool)
|
|
{
|
|
case EditorTool_WALLS:
|
|
graphics.drawtile(x, y, 83);
|
|
graphics.drawtile(x + 8, y, 83);
|
|
graphics.drawtile(x, y + 8, 83);
|
|
graphics.drawtile(x + 8, y + 8, 83);
|
|
break;
|
|
case EditorTool_BACKING:
|
|
graphics.drawtile(x, y, 680);
|
|
graphics.drawtile(x + 8, y, 680);
|
|
graphics.drawtile(x, y + 8, 680);
|
|
graphics.drawtile(x + 8, y + 8, 680);
|
|
break;
|
|
case EditorTool_SPIKES:
|
|
graphics.drawtile(x + 4, y + 4, 8);
|
|
break;
|
|
case EditorTool_TRINKETS:
|
|
graphics.draw_sprite(x, y, 22, 196, 196, 196);
|
|
break;
|
|
case EditorTool_CHECKPOINTS:
|
|
graphics.draw_sprite(x, y, 21, 196, 196, 196);
|
|
break;
|
|
case EditorTool_DISAPPEARING_PLATFORMS:
|
|
graphics.drawtile(x, y + 4, 3);
|
|
graphics.drawtile(x + 8, y + 4, 4);
|
|
break;
|
|
case EditorTool_CONVEYORS:
|
|
graphics.drawtile(x, y + 4, 24);
|
|
graphics.drawtile(x + 8, y + 4, 24);
|
|
break;
|
|
case EditorTool_MOVING_PLATFORMS:
|
|
graphics.drawtile(x, y + 4, 1);
|
|
graphics.drawtile(x + 8, y + 4, 1);
|
|
break;
|
|
case EditorTool_ENEMIES:
|
|
graphics.draw_sprite(x, y, 78 + ed.entframe, 196, 196, 196);
|
|
break;
|
|
case EditorTool_GRAVITY_LINES:
|
|
graphics.fill_rect(x + 2, y + 8, 12, 1, graphics.getRGB(255, 255, 255));
|
|
break;
|
|
case EditorTool_ROOMTEXT:
|
|
font::print(PR_FONT_8X8, x + 1, y, "AB", 196, 196, 255 - help.glow);
|
|
font::print(PR_FONT_8X8, x + 1, y + 9, "CD", 196, 196, 255 - help.glow);
|
|
break;
|
|
case EditorTool_TERMINALS:
|
|
graphics.draw_sprite(x, y, 17, 196, 196, 196);
|
|
break;
|
|
case EditorTool_SCRIPTS:
|
|
graphics.draw_rect(x + 4, y + 4, 8, 8, graphics.getRGB(96, 96, 96));
|
|
break;
|
|
case EditorTool_WARP_TOKENS:
|
|
graphics.draw_sprite(x, y, 18 + (ed.entframe % 2), 196, 196, 196);
|
|
break;
|
|
case EditorTool_WARP_LINES:
|
|
graphics.fill_rect(x + 6, y + 2, 4, 12, graphics.getRGB(255, 255, 255));
|
|
break;
|
|
case EditorTool_CREWMATES:
|
|
graphics.draw_sprite(x, y, 186, graphics.col_crewblue);
|
|
break;
|
|
case EditorTool_START_POINT:
|
|
graphics.draw_sprite(x, y, 184, graphics.col_crewcyan);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void editorclass::register_tool(EditorTools tool, const char* name, const char* keychar, const SDL_KeyCode key, const bool shift)
|
|
{
|
|
toolnames[tool] = name;
|
|
toolkeychar[tool] = keychar;
|
|
toolkey[tool] = key;
|
|
toolshift[tool] = shift;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void editorclass::addedentity(int xp, int yp, int tp, int p1, int p2, int p3, int p4, int p5, int p6)
|
|
{
|
|
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);
|
|
}
|
|
|
|
void editorclass::removeedentity(int t)
|
|
{
|
|
customentities.erase(customentities.begin() + t);
|
|
}
|
|
|
|
int editorclass::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 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 draw_background_grid(void)
|
|
{
|
|
for (int j = 0; j < 30; j++)
|
|
{
|
|
for (int i = 0; i < 40; i++)
|
|
{
|
|
if (i == 19 || i == 20 || j == 14 || j == 29)
|
|
{
|
|
// Major guidelines
|
|
graphics.draw_rect(i * 8, j * 8, 7, 7, graphics.getRGB(32, 32, 32));
|
|
}
|
|
else if (i == 9 || i == 30 || j == 6 || j == 7 || j == 21 || j == 22)
|
|
{
|
|
// Minor guidelines
|
|
graphics.draw_rect(i * 8, j * 8, 7, 7, graphics.getRGB(24, 24, 24));
|
|
}
|
|
else if (i % 4 == 0 || j % 4 == 0)
|
|
{
|
|
graphics.draw_rect(i * 8, j * 8, 7, 7, graphics.getRGB(16, 16, 16));
|
|
}
|
|
else
|
|
{
|
|
graphics.draw_rect(i * 8, j * 8, 7, 7, graphics.getRGB(8, 8, 8));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_background(int warpdir)
|
|
{
|
|
extern editorclass ed;
|
|
|
|
switch (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;
|
|
}
|
|
}
|
|
|
|
void draw_edgeguide(int type, int x, int y, bool vertical)
|
|
{
|
|
static const SDL_Color white = graphics.getRGB(255 - help.glow, 255, 255);
|
|
static const SDL_Color red = graphics.getRGB(255 - help.glow, 127, 127);
|
|
|
|
if (type != TileType_SOLID && type != TileType_SPIKE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (vertical)
|
|
{
|
|
graphics.fill_rect(x, y, 8, 2, (type == TileType_SOLID) ? white : red);
|
|
}
|
|
else
|
|
{
|
|
graphics.fill_rect(x, y, 2, 8, (type == TileType_SOLID) ? white : red);
|
|
}
|
|
}
|
|
|
|
void draw_edgeguides(void)
|
|
{
|
|
extern editorclass ed;
|
|
|
|
const int global_x = ed.levx * 40;
|
|
const int global_y = ed.levy * 30;
|
|
|
|
// Draw edge-guides, so there's no room misalignments!
|
|
|
|
for (int i = 0; i < 40; i++)
|
|
{
|
|
if (i < 30)
|
|
{
|
|
// Left edge
|
|
draw_edgeguide(ed.tile_type_wrap(global_x - 1, global_y + i), 0, i * 8, false);
|
|
// Right edge
|
|
draw_edgeguide(ed.tile_type_wrap(global_x + 40, global_y + i), 318, i * 8, false);
|
|
}
|
|
|
|
// Top edge
|
|
draw_edgeguide(ed.tile_type_wrap(global_x + i, global_y - 1), i * 8, 0, true);
|
|
// Bottom edge
|
|
draw_edgeguide(ed.tile_type_wrap(global_x + i, global_y + 30), i * 8, 238, true);
|
|
}
|
|
}
|
|
|
|
void draw_entities(void)
|
|
{
|
|
extern editorclass ed;
|
|
|
|
const RoomProperty* const room = cl.getroomprop(ed.levx, ed.levy);
|
|
|
|
//Draw entities
|
|
obj.customplatformtile = game.customcol * 12;
|
|
|
|
const int edent_under_cursor = ed.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--)
|
|
{
|
|
CustomEntity* entity = &customentities[i];
|
|
|
|
// If the entity is in the current room, draw it
|
|
if (entity->x / 40 == ed.levx && entity->y / 30 == ed.levy)
|
|
{
|
|
const int x = entity->x % 40 * 8;
|
|
const int y = entity->y % 30 * 8;
|
|
static const char arrows[] = "V^<>";
|
|
|
|
switch (entity->t)
|
|
{
|
|
case 1: // Enemies
|
|
{
|
|
const int movement = entity->p1;
|
|
|
|
if (custom_gray)
|
|
{
|
|
ed.entcolreal = graphics.getcol(18);
|
|
}
|
|
|
|
graphics.draw_sprite(x, y, ed.getenemyframe(room->enemytype), ed.entcolreal);
|
|
|
|
if (movement >= 0 && movement < 4)
|
|
{
|
|
// If they have a basic movement type, draw an arrow to indicate direction
|
|
font::print(PR_FONT_8X8, x + 4, y + 4, std::string(1, arrows[movement]), 255, 255, 255 - help.glow);
|
|
}
|
|
|
|
graphics.draw_rect(x, y, 16, 16, graphics.getRGB(255, 164, 255));
|
|
break;
|
|
}
|
|
case 2: // Conveyors & Platforms
|
|
{
|
|
const int movement = entity->p1;
|
|
const short length = (movement == 7 || movement == 8) ? 8 : 4;
|
|
const short glow = 255 - help.glow;
|
|
|
|
for (int j = 0; j < length; j++) {
|
|
graphics.draw_grid_tile(custom_gray ? graphics.grphx.im_entcolours_tint : graphics.grphx.im_entcolours, obj.customplatformtile, x + (j * 8), y, 8, 8);
|
|
}
|
|
|
|
switch (movement)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
// If they have a basic movement type, draw an arrow to indicate direction
|
|
font::print(PR_FONT_8X8, x + 12, y, std::string(1, arrows[movement]), glow, glow, glow);
|
|
break;
|
|
case 4:
|
|
// Always move right, stopping when hitting collision
|
|
font::print(PR_FONT_8X8, x + 8, y, ">I", glow, glow, glow);
|
|
break;
|
|
case 5:
|
|
font::print(PR_FONT_8X8, x, y, ">>>>", glow, glow, glow);
|
|
break;
|
|
case 6:
|
|
font::print(PR_FONT_8X8, x, y, "<<<<", glow, glow, glow);
|
|
break;
|
|
case 7:
|
|
font::print(PR_FONT_8X8, x + 4, y, "> > > > ", glow, glow, glow);
|
|
break;
|
|
case 8:
|
|
font::print(PR_FONT_8X8, x + 4, y, "< < < < ", glow, glow, glow);
|
|
break;
|
|
}
|
|
|
|
if (movement < 0)
|
|
{
|
|
// Well, it's a negative type, so it'll just be still.
|
|
font::print(PR_FONT_8X8, x + 8, y, "[]", glow, glow, glow);
|
|
}
|
|
else if (movement > 8)
|
|
{
|
|
// Invalid... draw a scary red X
|
|
font::print(PR_FONT_8X8, x + 12, y, "X", glow, 0, 0);
|
|
}
|
|
|
|
graphics.draw_rect(x, y, 8 * length, 8, graphics.getRGB(255, 255, 255));
|
|
break;
|
|
}
|
|
case 3: // Disappearing Platforms
|
|
for (int j = 0; j < 4; j++) {
|
|
graphics.draw_grid_tile(custom_gray ? graphics.grphx.im_entcolours_tint : graphics.grphx.im_entcolours, obj.customplatformtile, x + (j * 8), y, 8, 8);
|
|
}
|
|
|
|
font::print(PR_FONT_8X8, x, y, "////", 255 - help.glow, 255 - help.glow, 255 - help.glow);
|
|
graphics.draw_rect(x, y, 32, 8, graphics.getRGB(255, 255, 255));
|
|
break;
|
|
case 9: // Shiny Trinkets
|
|
graphics.draw_sprite(x, y, 22, 196, 196, 196);
|
|
graphics.draw_rect(x, y, 16, 16, graphics.getRGB(255, 164, 164));
|
|
break;
|
|
case 10: // Checkpoints
|
|
graphics.draw_sprite(x, y, 20 + entity->p1, 196, 196, 196);
|
|
graphics.draw_rect(x, y, 16, 16, graphics.getRGB(255, 164, 164));
|
|
break;
|
|
case 11: // Gravity Lines
|
|
// p2 is in tiles, and p3 is in pixels
|
|
if (entity->p1 == 0)
|
|
{
|
|
// Horizontal gravity line
|
|
const int left = entity->p2 * 8;
|
|
const int width = entity->p3;
|
|
graphics.fill_rect(left, y + 4, width, 1, graphics.getRGB(194, 194, 194));
|
|
}
|
|
else
|
|
{
|
|
// Vertical gravity line
|
|
const int top = entity->p2 * 8;
|
|
const int height = entity->p3;
|
|
graphics.fill_rect(x + 3, top, 1, height, graphics.getRGB(194, 194, 194));
|
|
}
|
|
graphics.draw_rect(x, y, 8, 8, graphics.getRGB(164, 255, 164));
|
|
break;
|
|
case 13: // Warp Tokens
|
|
{
|
|
std::string text;
|
|
|
|
graphics.draw_sprite(x, y, 18 + (ed.entframe % 2), 196, 196, 196);
|
|
graphics.draw_rect(x, y, 16, 16, graphics.getRGB(255, 164, 164));
|
|
|
|
if (i == edent_under_cursor)
|
|
{
|
|
text = "(" + help.String(entity->p1 / 40 + 1) + "," + help.String(entity->p2 / 30 + 1) + ")";
|
|
}
|
|
else
|
|
{
|
|
text = help.String(cl.findwarptoken(i));
|
|
}
|
|
|
|
font::print(PR_BOR | PR_CJK_HIGH, x, y - 8, text, 210, 210, 255);
|
|
break;
|
|
}
|
|
case 15: // Crewmates
|
|
graphics.draw_sprite(x - 4, y, 144, graphics.crewcolourreal(entity->p1));
|
|
graphics.draw_rect(x, y, 16, 24, graphics.getRGB(164, 164, 164));
|
|
break;
|
|
case 16: // Start Point
|
|
{
|
|
const short labelcol = ed.entframe < 2 ? 255 : 196;
|
|
|
|
if (entity->p1 == 0) // Facing right
|
|
{
|
|
graphics.draw_sprite(x - 4, y, 0, graphics.col_crewcyan);
|
|
}
|
|
else // Non-zero is facing left
|
|
{
|
|
graphics.draw_sprite(x - 4, y, 3, graphics.col_crewcyan);
|
|
}
|
|
|
|
graphics.draw_rect(x, y, 16, 24, graphics.getRGB(255, 255, 164));
|
|
font::print(PR_BOR | PR_CEN | PR_CJK_HIGH, x + 8, y - 8, loc::gettext("START"), labelcol, labelcol, labelcol);
|
|
break;
|
|
}
|
|
case 17: // Roomtext
|
|
{
|
|
int width = 8;
|
|
int height = 8;
|
|
|
|
if (entity->scriptname.length() > 0)
|
|
{
|
|
width = font::len(PR_FONT_LEVEL, entity->scriptname.c_str());
|
|
height = font::height(PR_FONT_LEVEL);
|
|
}
|
|
|
|
graphics.draw_rect(x, y, width, height, graphics.getRGB(96, 96, 96));
|
|
font::print(PR_FONT_LEVEL | PR_CJK_LOW, x, y, entity->scriptname, 196, 196, 255 - help.glow);
|
|
break;
|
|
}
|
|
case 18: // Terminals
|
|
{
|
|
int sprite = entity->p1;
|
|
int corrected_y = y;
|
|
|
|
// Not a boolean: just swapping 0 and 1, leaving the rest alone
|
|
if (sprite == 0)
|
|
{
|
|
sprite = 1; // Unflipped
|
|
}
|
|
else if (sprite == 1)
|
|
{
|
|
sprite = 0; // Flipped;
|
|
corrected_y -= 8;
|
|
}
|
|
|
|
graphics.draw_sprite(x, corrected_y + 8, sprite + 16, 96, 96, 96);
|
|
graphics.draw_rect(x, y, 16, 24, graphics.getRGB(164, 164, 164));
|
|
if (i == edent_under_cursor)
|
|
{
|
|
font::print(PR_FONT_LEVEL | PR_BOR | PR_CJK_HIGH, x, y - 8, entity->scriptname, 210, 210, 255);
|
|
}
|
|
break;
|
|
}
|
|
case 19: // Script Triggers
|
|
graphics.draw_rect(x, y, entity->p1 * 8, entity->p2 * 8, graphics.getRGB(255, 164, 255));
|
|
graphics.draw_rect(x, y, 8, 8, graphics.getRGB(255, 255, 255));
|
|
if (i == edent_under_cursor)
|
|
{
|
|
font::print(PR_FONT_LEVEL | PR_BOR | PR_CJK_HIGH, x, y - 8, entity->scriptname, 210, 210, 255);
|
|
}
|
|
break;
|
|
case 50: // Warp Lines
|
|
if (entity->p1 >= 2) // Horizontal
|
|
{
|
|
int left = x / 8;
|
|
int right = left;
|
|
int tile_y = y / 8;
|
|
|
|
if (entity->p4 != 1)
|
|
{
|
|
// Unlocked
|
|
while (ed.free(left, tile_y) == 0) left--;
|
|
while (ed.free(right, tile_y) == 0) right++;
|
|
left++;
|
|
entity->p2 = left;
|
|
entity->p3 = (right - left) * 8;
|
|
}
|
|
else
|
|
{
|
|
// Locked
|
|
left = entity->p2;
|
|
right = left + entity->p3 / 8;
|
|
}
|
|
|
|
graphics.draw_rect((left * 8), y + 1, (right - left) * 8, 6, graphics.getRGB(194, 255, 255));
|
|
graphics.draw_rect(x, y, 8, 8, graphics.getRGB(164, 255, 255));
|
|
}
|
|
else // Vertical
|
|
{
|
|
int tile_x = x / 8;
|
|
int top = y / 8;
|
|
int bottom = top;
|
|
|
|
if (entity->p4 != 1)
|
|
{
|
|
// Unlocked
|
|
while (ed.free(tile_x, top) == 0) top--;
|
|
while (ed.free(tile_x, bottom) == 0) bottom++;
|
|
top++;
|
|
entity->p2 = top;
|
|
entity->p3 = (bottom - top) * 8;
|
|
}
|
|
else
|
|
{
|
|
// Locked
|
|
top = entity->p2;
|
|
bottom = top + entity->p3 / 8;
|
|
}
|
|
|
|
graphics.draw_rect(x + 1, (top * 8), 6, (bottom - top) * 8, graphics.getRGB(194, 255, 255));
|
|
graphics.draw_rect(x, y, 8, 8, graphics.getRGB(164, 255, 255));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Need to also check warp point destinations
|
|
if (entity->t == 13 && ed.warpent != i)
|
|
{
|
|
// Is the destination in this room?
|
|
if (entity->p1 / 40 == ed.levx && entity->p2 / 30 == ed.levy)
|
|
{
|
|
const int x = entity->p1 % 40 * 8;
|
|
const int y = entity->p2 % 30 * 8;
|
|
std::string text;
|
|
|
|
graphics.draw_sprite(x, y, 18 + (ed.entframe % 2), 64, 64, 64);
|
|
graphics.draw_rect((entity->p1 * 8) - (ed.levx * 40 * 8), (entity->p2 * 8) - (ed.levy * 30 * 8), 16, 16, graphics.getRGB(96, 64, 64));
|
|
|
|
if (ed.tilex == x / 8 && ed.tiley == y / 8)
|
|
{
|
|
text = "(" + help.String(entity->x / 40 + 1) + "," + help.String(entity->y / 30 + 1) + ")";
|
|
}
|
|
else
|
|
{
|
|
text = help.String(cl.findwarptoken(i));
|
|
}
|
|
|
|
font::print(PR_BOR | PR_CJK_HIGH, x, y - 8, text, 190, 190, 225);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_ghosts(void)
|
|
{
|
|
extern editorclass ed;
|
|
|
|
//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_Color ct = ed.ghosts[i].realcol;
|
|
const int alpha = 3 * ct.a / 4;
|
|
ct.a = (Uint8)alpha;
|
|
graphics.draw_sprite(ed.ghosts[i].x, ed.ghosts[i].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);
|
|
}
|
|
}
|
|
|
|
void draw_bounds(void)
|
|
{
|
|
extern editorclass ed;
|
|
|
|
const RoomProperty* const room = cl.getroomprop(ed.levx, ed.levy);
|
|
|
|
if (ed.boundarymod>0)
|
|
{
|
|
if(ed.boundarymod==1)
|
|
{
|
|
graphics.draw_rect(ed.tilex*8, ed.tiley*8, 8,8,graphics.getRGB(210 + help.glow/2, 191 + help.glow, 255 - help.glow/2));
|
|
graphics.draw_rect((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)
|
|
{
|
|
graphics.draw_rect(ed.boundx1, ed.boundy1, 8, 8,graphics.getRGB(210 + help.glow/2, 191 + help.glow, 255 - help.glow/2));
|
|
graphics.draw_rect(ed.boundx1+2, ed.boundy1+2, 4, 4,graphics.getRGB(105 + help.glow/4, 100 + help.glow/2, 128 - help.glow/4));
|
|
}
|
|
else
|
|
{
|
|
graphics.draw_rect(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));
|
|
graphics.draw_rect(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)
|
|
{
|
|
graphics.draw_rect( 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)
|
|
{
|
|
graphics.draw_rect( room->platx1, room->platy1,
|
|
room->platx2-room->platx1,
|
|
room->platy2-room->platy1,
|
|
graphics.getRGB(64,64,255-(help.glow/2)));
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_cursor(void)
|
|
{
|
|
extern editorclass ed;
|
|
|
|
static const SDL_Color blue = graphics.getRGB(32, 32, 200);
|
|
|
|
const int x = ed.tilex * 8;
|
|
const int y = ed.tiley * 8;
|
|
|
|
switch (ed.current_tool)
|
|
{
|
|
case EditorTool_WALLS:
|
|
case EditorTool_BACKING:
|
|
// Modifiers!
|
|
if (ed.bmod) graphics.draw_rect(x, 0, 8, 240, blue); // Vertical
|
|
else if (ed.hmod) graphics.draw_rect(0, y, 320, 8, blue); // Horizontal
|
|
else if (ed.vmod) graphics.draw_rect(x - 32, y - 32, 24 + 48, 24 + 48, blue); // 9x9
|
|
else if (ed.cmod) graphics.draw_rect(x - 24, y - 24, 24 + 32, 24 + 32, blue); // 7x7
|
|
else if (ed.xmod) graphics.draw_rect(x - 16, y - 16, 24 + 16, 24 + 16, blue); // 5x5
|
|
else if (ed.zmod) graphics.draw_rect(x - 8, y - 8, 24, 24, blue); // 3x3
|
|
SDL_FALLTHROUGH;
|
|
case EditorTool_SPIKES:
|
|
case EditorTool_GRAVITY_LINES:
|
|
case EditorTool_ROOMTEXT:
|
|
case EditorTool_SCRIPTS:
|
|
// 1x1
|
|
graphics.draw_rect(x, y, 8, 8, blue);
|
|
break;
|
|
case EditorTool_TRINKETS:
|
|
case EditorTool_CHECKPOINTS:
|
|
case EditorTool_ENEMIES:
|
|
case EditorTool_WARP_TOKENS:
|
|
// 2x2
|
|
graphics.draw_rect(x, y, 16, 16, blue);
|
|
break;
|
|
case EditorTool_DISAPPEARING_PLATFORMS:
|
|
case EditorTool_CONVEYORS:
|
|
case EditorTool_MOVING_PLATFORMS:
|
|
// 1x4 (platforms)
|
|
graphics.draw_rect(x, y, 32, 8, blue);
|
|
break;
|
|
case EditorTool_WARP_LINES:
|
|
// 1x1, but X if not on an edge (warp lines)
|
|
if (ed.tilex == 0 || ed.tilex == 39 || ed.tiley == 0 || ed.tiley == 29)
|
|
{
|
|
graphics.draw_rect(x, y, 8, 8, blue);
|
|
}
|
|
else
|
|
{
|
|
font::print(PR_FONT_8X8, x, y, "X", 255, 0, 0);
|
|
}
|
|
break;
|
|
case EditorTool_TERMINALS:
|
|
case EditorTool_CREWMATES:
|
|
case EditorTool_START_POINT:
|
|
// 2x3
|
|
graphics.draw_rect(x, y, 16, 24, blue);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void editorrender(void)
|
|
{
|
|
extern editorclass ed;
|
|
|
|
const RoomProperty* const room = cl.getroomprop(ed.levx, ed.levy);
|
|
|
|
graphics.clear();
|
|
|
|
switch (ed.state)
|
|
{
|
|
case EditorState_DRAW:
|
|
// Draw the editor guidelines
|
|
draw_background_grid();
|
|
|
|
// Draw the background, if any, over the guidelines
|
|
if (!ed.settingsmod)
|
|
{
|
|
draw_background(room->warpdir);
|
|
}
|
|
|
|
graphics.drawmap();
|
|
draw_edgeguides();
|
|
|
|
draw_entities();
|
|
draw_ghosts();
|
|
|
|
draw_bounds();
|
|
|
|
draw_cursor();
|
|
|
|
break;
|
|
}
|
|
|
|
//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
|
|
graphics.draw_rect(((ed.dmtile % 40) * 8) - 2, 16 - t2 - 2, 12, 12, graphics.getRGB(255 - help.glow, 196, 196));
|
|
graphics.draw_rect(((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 tool icons!
|
|
|
|
int tx = 6;
|
|
const int ty = 210;
|
|
const int tg = 32;
|
|
|
|
const int page = ed.current_tool / 10;
|
|
const int max_pages = SDL_ceil(NUM_EditorTools / 10);
|
|
const int page_tool_count = SDL_min(10, NUM_EditorTools - (page * 10));
|
|
|
|
for (int i = 0; i < page_tool_count; i++)
|
|
{
|
|
const int current_tool_id = i + (page * 10);
|
|
|
|
// First, draw the background
|
|
graphics.fill_rect(4 + (i * tg), 208, 20, 20, graphics.getRGB(32, 32, 32));
|
|
|
|
// Draw the actual tool icon
|
|
ed.draw_tool((EditorTools) current_tool_id, 4 + (i * tg) + 2, 208 + 2);
|
|
|
|
// Draw the tool outline...
|
|
graphics.draw_rect(4 + (i * tg), 208, 20, 20, (current_tool_id == ed.current_tool) ? graphics.getRGB(200, 200, 200) : graphics.getRGB(96, 96, 96));
|
|
|
|
// ...and the hotkey
|
|
const int col = current_tool_id == ed.current_tool ? 255 : 164;
|
|
font::print(PR_FONT_8X8 | PR_BOR, 22 + i * tg - 4, 224 - 4, ed.toolkeychar[current_tool_id], col, col, col);
|
|
}
|
|
|
|
// Draw the page number, limit is 1 digit, so the max is 9 pages
|
|
char buffer[4];
|
|
SDL_snprintf(buffer, sizeof(buffer), "%d/%d", page + 1, max_pages + 1);
|
|
font::print(PR_CJK_HIGH, 4, 232, buffer, 196, 196, 255 - help.glow);
|
|
|
|
// Draw the button hint text
|
|
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);
|
|
|
|
// Draw the current tool name
|
|
char toolname[SCREEN_WIDTH_CHARS + 1];
|
|
SDL_snprintf(toolname, sizeof(toolname), "%s: %s", ed.toolkeychar[ed.current_tool], loc::gettext(ed.toolnames[ed.current_tool]));
|
|
|
|
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;
|
|
|
|
graphics.draw_rect(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);
|
|
|
|
graphics.draw_rect(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)
|
|
{
|
|
// Draw the current tool name
|
|
char toolname[SCREEN_WIDTH_CHARS + 1];
|
|
SDL_snprintf(toolname, sizeof(toolname), "%s: %s", ed.toolkeychar[ed.current_tool], loc::gettext(ed.toolnames[ed.current_tool]));
|
|
font::print(PR_BOR, 2, 2, toolname, 196, 196, 255 - help.glow);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
ed.tilex = (key.mx - (key.mx % 8)) / 8;
|
|
ed.tiley = (key.my - (key.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 == "")
|
|
{
|
|
ed.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;
|
|
}
|
|
|
|
for (int i = 0; i < NUM_EditorTools; i++)
|
|
{
|
|
if (key.keymap[ed.toolkey[i]])
|
|
{
|
|
ed.current_tool = (EditorTools) i;
|
|
}
|
|
}
|
|
|
|
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;
|
|
bool startpoint = false;
|
|
//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 = true;
|
|
}
|
|
}
|
|
}
|
|
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)
|
|
{
|
|
//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.current_tool = (EditorTools) POS_MOD(ed.current_tool - 1, NUM_EditorTools);
|
|
ed.keydelay=6;
|
|
}
|
|
else if(key.keymap[SDLK_PERIOD])
|
|
{
|
|
ed.current_tool = (EditorTools) POS_MOD(ed.current_tool + 1, NUM_EditorTools);
|
|
ed.keydelay=6;
|
|
}
|
|
|
|
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();
|
|
ed.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)
|
|
{
|
|
ed.removeedentity(ed.warpent);
|
|
ed.warpmod=false;
|
|
ed.warpent=-1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Mouse input
|
|
if(key.leftbutton)
|
|
{
|
|
if (ed.lclickdelay == 0)
|
|
{
|
|
ed.tool_place();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ed.lclickdelay = 0;
|
|
}
|
|
|
|
|
|
if (key.rightbutton)
|
|
{
|
|
// place tiles
|
|
ed.tool_remove();
|
|
}
|
|
|
|
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;
|
|
}
|
|
graphics.foregrounddrawn = false;
|
|
}
|
|
}
|
|
|
|
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::settile( int x, int y, int t )
|
|
{
|
|
if (x >= 0 && y >= 0 && x < 40 && y < 30)
|
|
{
|
|
cl.settile(levx, levy, x, y, t);
|
|
}
|
|
graphics.foregrounddrawn = false;
|
|
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 )
|
|
{
|
|
x = SDL_max(0, SDL_min(x, 39));
|
|
y = SDL_max(0, SDL_min(y, 29));
|
|
|
|
return cl.gettile(levx, levy, x, y);
|
|
}
|
|
|
|
int editorclass::tile_type_wrap(int x, int y)
|
|
{
|
|
x = POS_MOD(x, cl.mapwidth * 40);
|
|
y = POS_MOD(y, cl.mapheight * 30);
|
|
|
|
const RoomProperty* const room = cl.getroomprop(x / 40, y / 30);
|
|
int tile = cl.getabstile(x, y);
|
|
|
|
if (tile == 1 || (tile >= 80 && tile <= 679))
|
|
{
|
|
// It's solid.
|
|
return TileType_SOLID;
|
|
}
|
|
|
|
if ((tile >= 6 && tile <= 9) || tile == 49 || tile == 50)
|
|
{
|
|
// It's a spike!
|
|
return TileType_SPIKE;
|
|
}
|
|
|
|
if (room->tileset != 0)
|
|
{
|
|
// tiles2.png is slightly different.
|
|
|
|
if (tile >= 51 && tile <= 74)
|
|
{
|
|
// It has more spikes!
|
|
return TileType_SPIKE;
|
|
}
|
|
|
|
if (tile == 740)
|
|
{
|
|
// And a stray solid.
|
|
return TileType_SOLID;
|
|
}
|
|
}
|
|
|
|
return TileType_NONSOLID;
|
|
}
|
|
|
|
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 */
|