mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-06-25 05:58:30 +02:00
7b5ef40926
While warp lines were being drawn, they also got resized to automatically fit between collision. In renderfixed, gravity lines are resized the same way. Doing logic while drawing is very poor practice, so resizing of these has been moved into logic, and merged together. Aside from some more cleanup, this commit also removes the very poorly done right click emulation, when you hold CTRL and click. It never worked well in the past, and even requires a right click to use, so there's not really any point to keeping it around.
4252 lines
125 KiB
C++
4252 lines
125 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;
|
|
}
|
|
}
|
|
|
|
static 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));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
}
|
|
|
|
static void update_entities(void)
|
|
{
|
|
extern editorclass ed;
|
|
|
|
for (size_t i = 0; i < customentities.size(); ++i)
|
|
{
|
|
CustomEntity* entity = &customentities[i];
|
|
|
|
if (entity->x / 40 != ed.levx || entity->y / 30 != ed.levy)
|
|
{
|
|
// It's not in this room, so just continue
|
|
continue;
|
|
}
|
|
|
|
bool grav_line = (entity->t == 11);
|
|
bool warp_line = (entity->t == 50);
|
|
|
|
if ((grav_line || warp_line) && entity->p4 != 1)
|
|
{
|
|
// If it's a grav line or a warp line, and it's not locked
|
|
if ((grav_line && entity->p1 == 0) || (warp_line && entity->p1 >= 2))
|
|
{
|
|
/* Horizontal */
|
|
int tx = entity->x % 40;
|
|
int tx2 = tx;
|
|
int ty = entity->y % 30;
|
|
while (!ed.spikefree(tx, ty))
|
|
{
|
|
--tx;
|
|
}
|
|
while (!ed.spikefree(tx2, ty))
|
|
{
|
|
++tx2;
|
|
}
|
|
++tx;
|
|
entity->p2 = tx;
|
|
entity->p3 = (tx2 - tx) * 8;
|
|
}
|
|
else
|
|
{
|
|
/* Vertical */
|
|
int tx = entity->x % 40;
|
|
int ty = entity->y % 30;
|
|
int ty2 = ty;
|
|
while (!ed.spikefree(tx, ty))
|
|
{
|
|
--ty;
|
|
}
|
|
while (!ed.spikefree(tx, ty2))
|
|
{
|
|
++ty2;
|
|
}
|
|
++ty;
|
|
entity->p2 = ty;
|
|
entity->p3 = (ty2 - ty) * 8;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static 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 = entity->p2;
|
|
int 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 top = entity->p2;
|
|
int 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
}
|
|
|
|
static 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)));
|
|
}
|
|
}
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
}
|
|
|
|
static void draw_tile_toolbox(int tileset)
|
|
{
|
|
extern editorclass ed;
|
|
|
|
// Tile toolbox 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 (graphics.query_texture(graphics.grphx.im_tiles, NULL, NULL, &texturewidth, &textureheight) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const int numtiles = (int)(texturewidth / 8) * (textureheight / 8);
|
|
|
|
for (int x = 0; x < 40; x++)
|
|
{
|
|
for (int y = 0; y < 5; y++)
|
|
{
|
|
if (tileset == 0)
|
|
{
|
|
graphics.drawtile(x * 8, (y * 8) - t2, (temp + numtiles + (y * 40) + x) % numtiles);
|
|
}
|
|
else
|
|
{
|
|
graphics.drawtile2(x * 8, (y * 8) - t2, (temp + numtiles + (y * 40) + x) % 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 (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 (tileset == 0)
|
|
{
|
|
graphics.drawtile(labellen + 3, 12, ed.dmtile);
|
|
}
|
|
else
|
|
{
|
|
graphics.drawtile2(labellen + 3, 12, ed.dmtile);
|
|
}
|
|
}
|
|
}
|
|
|
|
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();
|
|
|
|
if (room->directmode == 1)
|
|
{
|
|
draw_tile_toolbox(room->tileset);
|
|
}
|
|
|
|
draw_cursor();
|
|
break;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
ed.currentghosts++;
|
|
if (ed.zmod)
|
|
{
|
|
ed.currentghosts++;
|
|
}
|
|
|
|
ed.currentghosts = SDL_min(ed.currentghosts, ed.ghosts.size());
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
ed.notedelay = SDL_max(ed.notedelay - 1, 0);
|
|
|
|
update_entities();
|
|
|
|
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 = POS_MOD(cl.levmusic, 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(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++;
|
|
}
|
|
|
|
cl.mapwidth = SDL_clamp(cl.mapwidth, 1, cl.maxwidth);
|
|
cl.mapheight = SDL_clamp(cl.mapheight, 1, 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;
|
|
}
|
|
|
|
ed.levx = POS_MOD(ed.levx, cl.mapwidth);
|
|
ed.levy = POS_MOD(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 */
|