1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-02-10 06:04:03 +00:00
Aquaria/Aquaria/SceneEditor.cpp
fgenesis d7ff053efd Rewrite SceneEditor level generation and skinning, use light pink to designate areas that should not be skinned
This also fixes a long-standing off-by-one with the generated ObsRows:
Before this commit, the game would (upon F11) eat every black pixel from
the map template that was directly left of a white pixel, eg.
#### ## # ## ... would become
###  #    #  ...

GENERATED MAPS ARE NOW DIFFERENT!
With this bug gone, dumping obs (F8) and loading that back in as a map
template (F11) should now be fully round-trip compatible and not lose
pixels anymore.

Extra feature:
(R>=200, G in [128..199], B>=200) in the map template now designate zones
that should not be obstructed but also not generate border rocks when
skinned (F12). Makes editing energy temple styled maps much easier since
we don't have to manually erase tiles on layer "5" anymore, all the time.
2022-07-06 08:59:55 +02:00

3071 lines
68 KiB
C++

/*
Copyright (C) 2007, 2010 - Bit-Blot
This file is part of Aquaria.
Aquaria is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "SceneEditor.h"
#include "../BBGE/MathFunctions.h"
#include "Image.h"
#include "../BBGE/Gradient.h"
#include "../BBGE/DebugFont.h"
#include "Game.h"
#include "DSQ.h"
#include "Avatar.h"
#include "GridRender.h"
#include "Shot.h"
#ifdef BBGE_BUILD_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#endif
const int minSelectionSize = 64;
PathRender *pathRender;
SelectedEntity::SelectedEntity()
{
clear();
}
void SelectedEntity::setSelectEntity(const SelectedEntity &ent)
{
(*this) = ent;
}
void SelectedEntity::clear()
{
typeListIndex = -1;
prevScale = 1;
nameBased = false;
index = -1;
name = "";
prevGfx="";
}
void SelectedEntity::setIndex(int idx)
{
clear();
if (idx > -1)
{
nameBased = false;
typeListIndex = idx;
index = dsq->game->entityTypeList[idx].idx;
prevGfx = dsq->game->entityTypeList[idx].prevGfx;
prevScale = dsq->game->entityTypeList[idx].prevScale;
name = dsq->game->entityTypeList[idx].name;
}
}
void SelectedEntity::setName(const std::string &name, const std::string &prevGfx)
{
clear();
nameBased = true;
this->name = name;
this->prevGfx = prevGfx;
}
std::string getMapTemplateFilename()
{
if (dsq->mod.isActive())
return std::string(dsq->mod.getPath() + "maptemplates/" + dsq->game->sceneName + ".png");
else
return std::string("maptemplates/" + dsq->game->sceneName + ".png");
return "";
}
SceneEditor::SceneEditor() : ActionMapper(), on(false)
{
autoSaveFile = 0;
selectedIdx = -1;
}
void SceneEditor::setBackgroundGradient()
{
float g1r, g1g, g1b;
float g2r, g2g, g2b;
std::string gtop = dsq->getUserInputString("Set Gradient Top (3 rgb, spaced)", "");
std::string gbtm = dsq->getUserInputString("Set Gradient Bottom (3 rgb, spaced)", "");
std::istringstream is1(gtop);
is1 >> g1r >> g1g >> g1b;
std::istringstream is2(gbtm);
is2 >> g2r >> g2g >> g2b;
if (dsq->game->grad)
{
dsq->game->grad->makeVertical(Vector(g1r, g1g, g1b), Vector(g2r, g2g, g2b));
}
}
void SceneEditor::changeDepth()
{
if (editingElement)
{
editingElement->followCamera = 0.9f;
editingElement->cull = false;
}
}
void SceneEditor::updateSelectedElementPosition(Vector dist)
{
if (state == ES_MOVING)
{
if (!selectedElements.empty())
{
dummy.position = oldPosition + dist;
}
else if (editingElement)
{
editingElement->position = oldPosition + dist;
}
}
}
bool se_changedEntityType = false;
class SEQuad : public Quad
{
public:
int entType;
Quad *glow;
DebugFont *label;
float doubleClickTimer;
std::string entName;
bool mbld;
SelectedEntity selectedEntity;
SEQuad(std::string tex, Vector pos, int entType, std::string name) : Quad(tex, pos), entType(entType)
{
glow = new Quad;
addChild(glow, PM_POINTER, RBP_ON);
glow->setWidthHeight(48, 64);
glow->alpha = 0;
glow->setBlendType(BLEND_ADD);
scale = Vector(0.5, 0.5);
scale.interpolateTo(Vector(1,1), 0.5, 0, 0, 1);
label = new DebugFont();
label->setFontSize(5);
label->position = Vector(-32,12);
label->setText(name);
label->alpha = 0;
addChild(label, PM_POINTER);
doubleClickTimer = 0;
entName = name;
mbld = false;
selectedEntity.prevGfx = tex;
selectedEntity.name = name;
}
void onUpdate(float dt)
{
if (doubleClickTimer > 0)
doubleClickTimer -= dt;
Quad::onUpdate(dt);
if (dsq->game->sceneEditor.selectedEntity.name == selectedEntity.name
|| (entType != -1 && dsq->game->sceneEditor.selectedEntity.typeListIndex == entType))
{
glow->alpha.interpolateTo(0.2f, 0.2f);
}
else
{
glow->alpha.interpolateTo(0, 0.1f);
}
if ((core->mouse.position - position).isLength2DIn(32))
{
label->alpha.interpolateTo(1, 0.1f);
alpha.interpolateTo(1, 0.2f);
scale.interpolateTo(Vector(1.5f, 1.5f), 0.3f);
if (!core->mouse.buttons.left && mbld)
{
mbld = false;
}
else if (core->mouse.buttons.left && !mbld)
{
mbld = true;
if (entType > -1)
dsq->game->sceneEditor.selectedEntity.setIndex(entType);
else
{
dsq->game->sceneEditor.selectedEntity.setName(selectedEntity.name, selectedEntity.prevGfx);
}
if (doubleClickTimer > 0)
{
doubleClickTimer = 0;
if (!dsq->isFullscreen())
{
std::string fn = "scripts/entities/" + entName + ".lua";
#ifdef BBGE_BUILD_WINDOWS
debugLog("SHELL EXECUTE!");
ShellExecute(0, "open", fn.c_str(), NULL, NULL, SW_SHOWNORMAL);
#endif
}
}
else
{
doubleClickTimer = 0.4f;
}
}
}
else
{
label->alpha.interpolateTo(0, 0.1f);
alpha.interpolateTo(0.7f, 0.2f);
scale.interpolateTo(Vector(1.0f, 1.0f), 0.3f);
doubleClickTimer = 0;
}
}
};
std::vector<DebugButton*> mainMenu;
int execID = 0;
bool inMainMenu = false;
std::vector<SEQuad*> qs;
DebugFont *se_label=0;
void SceneEditorMenuReceiver::buttonPress(DebugButton *db)
{
execID = db->buttonID;
switch(execID)
{
case 200:
{
if (inMainMenu)
{
dsq->game->sceneEditor.closeMainMenu();
}
else
{
dsq->game->sceneEditor.openMainMenu();
}
execID = 0;
}
break;
}
}
void SceneEditor::executeButtonID(int bid)
{
switch(bid)
{
case 100:
loadSceneByName();
break;
case 101:
reloadScene();
break;
case 102:
saveScene();
break;
case 103:
// regen collision
dsq->game->reconstructGrid(true);
break;
case 104:
generateLevel();
break;
case 105:
skinLevel();
break;
case 106:
editModeElements();
break;
case 107:
editModeEntities();
break;
case 108:
editModePaths();
break;
case 110:
{
std::ostringstream os;
os << dsq->game->gradTop.x << " " << dsq->game->gradTop.y << " " << dsq->game->gradTop.z;
std::string read;
read = dsq->getUserInputString("Enter Spaced R G B 0-1 Values for the Top Color (e.g. 1 0.5 0.5 for bright red)", os.str());
if (!read.empty())
{
std::istringstream is(read);
is >> dsq->game->gradTop.x >> dsq->game->gradTop.y >> dsq->game->gradTop.z;
}
std::ostringstream os2;
os2 << dsq->game->gradBtm.x << " " << dsq->game->gradBtm.y << " " << dsq->game->gradBtm.z;
read = dsq->getUserInputString("Enter Spaced R G B 0-1 Values for the Bottom Color (e.g. 0 0 0 for black)", os2.str());
if (!read.empty())
{
std::istringstream is2(read);
is2 >> dsq->game->gradBtm.x >> dsq->game->gradBtm.y >> dsq->game->gradBtm.z;
}
dsq->game->createGradient();
}
break;
case 111:
{
std::string track = dsq->getUserInputString("Set Background Music Track", dsq->game->saveMusic);
if (!track.empty())
{
dsq->game->setMusicToPlay(track);
dsq->game->saveMusic = track;
dsq->game->updateMusic();
}
}
break;
case 112:
{
selectEntityFromGroups();
}
break;
case 113:
dsq->game->toggleGridRender();
break;
case 114:
dsq->screenshot();
break;
case 115:
{
dsq->returnToScene = dsq->game->sceneName;
core->enqueueJumpState("AnimationEditor");
}
break;
case 120:
{
dsq->returnToScene = dsq->game->sceneName;
core->enqueueJumpState("ParticleEditor");
}
break;
case 116:
regenLevel();
break;
case 130:
dsq->mod.recache();
break;
}
}
void SceneEditor::addMainMenuItem(const std::string &label, int bid)
{
DebugButton *b = new DebugButton(bid, &menuReceiver, 350);
b->label->setText(label);
b->followCamera = 1;
b->position.x = btnMenu->position.x + 20;
b->position.y = btnMenu->position.y + (mainMenu.size()+1)*22;
dsq->game->addRenderObject(b, LR_HUD);
mainMenu.push_back(b);
}
void SceneEditor::openMainMenu()
{
if (core->getNestedMains()>1)
{
return;
}
inMainMenu = true;
if (placer)
placer->renderQuad = 0;
execID = -1;
debugLog("Open Main Menu");
mainMenu.clear();
while (core->mouse.buttons.left)
{
core->run(FRAME_TIME);
}
addMainMenuItem("LOAD LEVEL... (SHIFT-F1)", 100);
addMainMenuItem("RELOAD LEVEL (F1)", 101);
addMainMenuItem("SAVE LEVEL (F2)", 102);
addMainMenuItem("EDIT TILES (F5)", 106);
addMainMenuItem("EDIT ENTITIES (F6)", 107);
addMainMenuItem("EDIT NODES (F7)", 108);
addMainMenuItem("REGEN COLLISIONS (ALT-R)", 103);
addMainMenuItem("RECACHE TEXTURES (CTRL-R)", 130);
addMainMenuItem("REGEN ROCK FROM MAPTEMPLATE (F11+F12)", 116);
addMainMenuItem("SET BG GRADIENT", 110);
addMainMenuItem("SET MUSIC", 111);
addMainMenuItem("ENTITY GROUPS (CTRL-E)", 112);
if (dsq->game->gridRender)
addMainMenuItem(std::string("TOGGLE TILE COLLISION RENDER ") + ((dsq->game->gridRender->alpha!=0) ? "OFF" : "ON ") + std::string(" (F9)"), 113);
addMainMenuItem("SCREENSHOT ", 114);
addMainMenuItem("PARTICLE VIEWER ", 120);
addMainMenuItem("ANIMATION EDITOR ", 115);
while (1 && !core->getKeyState(KEY_TAB))
{
core->run(FRAME_TIME);
if (execID != -1)
break;
}
closeMainMenu();
executeButtonID(execID);
}
void SceneEditor::closeMainMenu()
{
inMainMenu = false;
for (size_t i = 0; i < mainMenu.size(); i++)
{
mainMenu[i]->alpha = 0;
mainMenu[i]->safeKill();
}
mainMenu.clear();
if (placer)
placer->renderQuad = 1;
core->quitNestedMain();
}
void SceneEditor::init()
{
entityPageNum = 0;
multiSelecting = false;
selectedElements.clear();
autoSaveTimer = 0;
skinMinX = skinMinY = skinMaxX = skinMaxY = -1;
editingElement = 0;
editingEntity = 0;
pathRender = new PathRender();
core->getTopStateData()->addRenderObject(pathRender, LR_DEBUG_TEXT);
pathRender->alpha = 0;
editType = ET_ELEMENTS;
state = ES_SELECTING;
btnMenu = new DebugButton(200, &menuReceiver, 700);
btnMenu->position = Vector(20, 20);
btnMenu->label->setText("Menu");
btnMenu->followCamera = 1;
btnMenu->alpha = 0;
dsq->game->addRenderObject(btnMenu, LR_HUD);
selectedEntityType = 0;
zoom = Vector(0.2f,0.2f);
bgLayer = 5;
text = new DebugFont();
text->setFontSize(6);
text->followCamera = 1;
text->position = Vector(125,20,4.5);
dsq->game->addRenderObject(text, LR_HUD);
text->alpha = 0;
selectedVariation = -1;
on = false;
addAction(MakeFunctionEvent(SceneEditor, loadScene), KEY_F1, 0);
addAction(MakeFunctionEvent(SceneEditor, saveScene), KEY_F2, 0);
addAction(MakeFunctionEvent(SceneEditor, moveToBack), KEY_Z, 0);
addAction(MakeFunctionEvent(SceneEditor, moveToFront), KEY_X, 0);
addAction(MakeFunctionEvent(SceneEditor, editModeElements), KEY_F5, 0);
addAction(MakeFunctionEvent(SceneEditor, editModeEntities), KEY_F6, 0);
addAction(MakeFunctionEvent(SceneEditor, editModePaths), KEY_F7, 0);
addAction(MakeFunctionEvent(SceneEditor, mouseButtonLeft), MOUSE_BUTTON_LEFT, 1);
addAction(MakeFunctionEvent(SceneEditor, mouseButtonRight), MOUSE_BUTTON_RIGHT, 1);
addAction(MakeFunctionEvent(SceneEditor, mouseButtonLeftUp), MOUSE_BUTTON_LEFT, 0);
addAction(MakeFunctionEvent(SceneEditor, mouseButtonRightUp), MOUSE_BUTTON_RIGHT, 0);
addAction(MakeFunctionEvent(SceneEditor, alignHorz), KEY_C, 1);
addAction(MakeFunctionEvent(SceneEditor, alignVert), KEY_V, 1);
addAction(MakeFunctionEvent(SceneEditor, placeElement), KEY_SPACE, 1);
addAction(MakeFunctionEvent(SceneEditor, enterName), KEY_N, 0);
addAction(MakeFunctionEvent(SceneEditor, changeShape), KEY_Y, 0);
addAction(MakeFunctionEvent(SceneEditor, reversePath), KEY_T, 0);
addAction(MakeFunctionEvent(SceneEditor, moveLayer), KEY_F10, 0);
addAction(MakeFunctionEvent(SceneEditor, nextElement), KEY_R, 1);
addAction(MakeFunctionEvent(SceneEditor, prevElement), KEY_E, 1);
addAction(MakeFunctionEvent(SceneEditor, selectZero), KEY_HOME, 1);
addAction(MakeFunctionEvent(SceneEditor, selectEnd), KEY_END, 1);
addAction(MakeFunctionEvent(SceneEditor, placeAvatar), KEY_P, 0);
addAction(MakeFunctionEvent(SceneEditor, deleteSelected), KEY_DELETE, 0);
addAction(MakeFunctionEvent(SceneEditor, deleteSelected), KEY_BACKSPACE, 0);
addAction(MakeFunctionEvent(SceneEditor, generateLevel), KEY_F11, 0);
addAction(MakeFunctionEvent(SceneEditor, skinLevel), KEY_F12, 0);
addAction(MakeFunctionEvent(SceneEditor, nextEntityType), KEY_RIGHT, 0);
addAction(MakeFunctionEvent(SceneEditor, prevEntityType), KEY_LEFT, 0);
addAction(MakeFunctionEvent(SceneEditor, down), KEY_DOWN, 0);
addAction(MakeFunctionEvent(SceneEditor, up), KEY_UP, 0);
addAction(MakeFunctionEvent(SceneEditor, flipElementHorz), KEY_T, 0);
addAction(MakeFunctionEvent(SceneEditor, flipElementVert), KEY_Y, 0);
addAction(MakeFunctionEvent(SceneEditor, toggleElementSolid), KEY_O, 0);
addAction(MakeFunctionEvent(SceneEditor, toggleElementHurt), KEY_I, 0);
addAction(MakeFunctionEvent(SceneEditor, toggleElementRepeat), KEY_L, 0);
addAction(MakeFunctionEvent(SceneEditor, setGridPattern0), KEY_NUMPAD0, 0);
addAction(MakeFunctionEvent(SceneEditor, setGridPattern1), KEY_NUMPAD1, 0);
addAction(MakeFunctionEvent(SceneEditor, setGridPattern2), KEY_NUMPAD2, 0);
addAction(MakeFunctionEvent(SceneEditor, setGridPattern3), KEY_NUMPAD3, 0);
addAction(MakeFunctionEvent(SceneEditor, setGridPattern4), KEY_NUMPAD4, 0);
addAction(MakeFunctionEvent(SceneEditor, setGridPattern5), KEY_NUMPAD5, 0);
addAction(MakeFunctionEvent(SceneEditor, setGridPattern6), KEY_NUMPAD6, 0);
addAction(MakeFunctionEvent(SceneEditor, setGridPattern7), KEY_NUMPAD7, 0);
addAction(MakeFunctionEvent(SceneEditor, setGridPattern8), KEY_NUMPAD8, 0);
addAction(MakeFunctionEvent(SceneEditor, setGridPattern9), KEY_NUMPAD9, 0);
addAction(MakeFunctionEvent(SceneEditor, createAquarian), KEY_F, 0);
addAction(MakeFunctionEvent(SceneEditor, dumpObs), KEY_F8, 0);
addAction(ACTION_ZOOMIN, KEY_PGUP, -1);
addAction(ACTION_ZOOMOUT, KEY_PGDN, -1);
addAction(ACTION_CAMLEFT, KEY_A, -1);
addAction(ACTION_CAMRIGHT, KEY_D, -1);
addAction(ACTION_CAMUP, KEY_W, -1);
addAction(ACTION_CAMDOWN, KEY_S, -1);
addAction(ACTION_BGLAYEREND, KEY_0, -1);
addAction(ACTION_BGLAYER1, KEY_1, -1);
addAction(ACTION_BGLAYER2, KEY_2, -1);
addAction(ACTION_BGLAYER3, KEY_3, -1);
addAction(ACTION_BGLAYER4, KEY_4, -1);
addAction(ACTION_BGLAYER5, KEY_5, -1);
addAction(ACTION_BGLAYER6, KEY_6, -1);
addAction(ACTION_BGLAYER7, KEY_7, -1);
addAction(ACTION_BGLAYER8, KEY_8, -1);
addAction(ACTION_BGLAYER9, KEY_9, -1);
addAction(ACTION_BGLAYER10, KEY_B, -1);
addAction(ACTION_BGLAYER11, KEY_N, -1);
addAction(ACTION_BGLAYER12, KEY_M, -1);
addAction(ACTION_BGLAYER13, KEY_J, -1);
addAction(ACTION_BGLAYER14, KEY_COMMA, -1);
addAction(ACTION_BGLAYER15, KEY_PERIOD, -1);
addAction(ACTION_BGLAYER16, KEY_SLASH, -1);
addAction(ACTION_MULTISELECT, KEY_LALT, -1);
placer = new Quad;
dsq->game->addRenderObject(placer, LR_HUD);
placer->alpha = 0;
curElement = 0;
selectedEntity.clear();
nextElement();
if (curElement < dsq->game->elementTemplates.size())
{
placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
placer->scale = Vector(1,1);
}
else
{
placer->setTexture("missingimage");
}
updateText();
doPrevElement();
}
void SceneEditor::alignHorz()
{
if (core->getShiftState()) return;
if (editType == ET_ELEMENTS && state == ES_SELECTING && editingElement)
{
TileVector t(editingElement->position);
int startOn = dsq->game->getGrid(t);
TileVector c=t;
bool found = false;
int dir = -1;
for (int i = 1; i < 5; i++)
{
// search down
c.y = t.y + i;
if (dsq->game->getGrid(c) != startOn)
{
found = true;
dir = 1;
break;
}
c.y = t.y - i;
if (dsq->game->getGrid(c) != startOn)
{
found = true;
dir = -1;
break;
}
}
if (found)
{
editingElement->position.y = c.worldVector().y + (editingElement->texture->getPixelHeight()/2)*(-dir);
}
}
}
void SceneEditor::alignVert()
{
if (core->getShiftState()) return;
if (editType == ET_ELEMENTS && state == ES_SELECTING && editingElement)
{
TileVector t(editingElement->position);
int startOn = dsq->game->getGrid(t);
TileVector c=t;
bool found = false;
int dir = -1;
for (int i = 1; i < 5; i++)
{
// search down
c.x = t.x + i;
if (dsq->game->getGrid(c) != startOn)
{
found = true;
dir = 1;
break;
}
c.x = t.x - i;
if (dsq->game->getGrid(c) != startOn)
{
found = true;
dir = -1;
break;
}
}
if (found)
{
editingElement->position.x = c.worldVector().x + (editingElement->texture->getPixelWidth()/2)*(-dir);
}
}
}
void SceneEditor::createAquarian()
{
static bool inCreateAqurian = false;
if (inCreateAqurian) return;
inCreateAqurian = true;
std::string t = dsq->getUserInputString("Enter Aquarian:", "");
stringToUpper(t);
Vector startPos = dsq->getGameCursorPosition();
for (size_t i = 0; i < t.size(); i++)
{
int v = 0;
if (t[i] >= 'A' && t[i] <= 'Z')
{
v = 1024+int(t[i] - 'A');
}
if (t[i] == '.' || t[i] == ' ')
{
v = 1024+26;
}
dsq->game->createElement(v, startPos + Vector(64*i,0), this->bgLayer);
}
inCreateAqurian = false;
}
Path *SceneEditor::getSelectedPath()
{
if (selectedIdx < dsq->game->getNumPaths())
{
return dsq->game->getPath(selectedIdx);
}
return 0;
}
void SceneEditor::enterName()
{
if (editType == ET_PATHS)
{
Path *p = getSelectedPath();
if (p)
{
std::string newname = dsq->getUserInputString("PathName", p->name);
bool changed = newname != p->name;
p->name = newname;
if (changed)
{
p->refreshScript();
p->init();
}
}
}
}
void SceneEditor::changeShape()
{
if (editType == ET_PATHS)
{
Path *p = getSelectedPath();
if (p)
{
switch (p->pathShape)
{
case PATHSHAPE_RECT:
p->pathShape = PATHSHAPE_CIRCLE;
break;
case PATHSHAPE_CIRCLE:
p->pathShape = PATHSHAPE_RECT;
break;
}
}
}
}
void SceneEditor::reversePath()
{
if (editType == ET_PATHS)
{
Path *p = getSelectedPath();
if (p)
{
p->reverseNodes();
}
}
}
void SceneEditor::setGridPattern(int gi)
{
if (selectedElements.size())
for (size_t i = 0; i < selectedElements.size(); ++i)
selectedElements[i]->setElementEffectByIndex(gi);
else if (editingElement)
editingElement->setElementEffectByIndex(gi);
}
void SceneEditor::setGridPattern0()
{ setGridPattern(-1); }
void SceneEditor::setGridPattern1()
{ setGridPattern(0); }
void SceneEditor::setGridPattern2()
{ setGridPattern(1); }
void SceneEditor::setGridPattern3()
{ setGridPattern(2); }
void SceneEditor::setGridPattern4()
{ setGridPattern(3); }
void SceneEditor::setGridPattern5()
{ setGridPattern(4); }
void SceneEditor::setGridPattern6()
{ setGridPattern(5); }
void SceneEditor::setGridPattern7()
{ setGridPattern(6); }
void SceneEditor::setGridPattern8()
{ setGridPattern(7); }
void SceneEditor::setGridPattern9()
{ setGridPattern(8); }
void SceneEditor::moveToFront()
{
if (editingElement && !core->getShiftState())
{
std::vector<Element*> copy = dsq->getElementsCopy();
dsq->clearElements();
// move to the foreground ... this means that the editing element should be last in the list (Added last)
for (size_t i = 0; i < copy.size(); i++)
{
if (copy[i] != editingElement)
dsq->addElement(copy[i]);
}
dsq->addElement(editingElement);
editingElement->moveToFront();
}
}
void SceneEditor::moveToBack()
{
if (editingElement && !core->getShiftState())
{
std::vector<Element*> copy = dsq->getElementsCopy();
dsq->clearElements();
// move to the background ... this means that the editing element should be first in the list (Added first)
dsq->addElement(editingElement);
for (size_t i = 0; i < copy.size(); i++)
{
if (copy[i] != editingElement)
dsq->addElement(copy[i]);
}
editingElement->moveToBack();
}
}
void SceneEditor::editModeElements()
{
selectedIdx = -1;
editType = ET_ELEMENTS;
if (curElement < dsq->game->elementTemplates.size())
{
placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
placer->scale = Vector(1,1);
}
placer->alpha = 0.5;
pathRender->alpha = 0;
editingEntity = NULL;
editingPath = NULL;
}
void SceneEditor::editModeEntities()
{
selectedIdx = -1;
//HACK: methinks target is useless now
//target->alpha.interpolateTo(0, 0.5);
editType = ET_ENTITIES;
placer->setTexture(selectedEntity.prevGfx);
placer->alpha = 0.5;
pathRender->alpha = 0;
selectedElements.clear();
editingElement = NULL;
editingPath = NULL;
}
void SceneEditor::editModePaths()
{
selectedIdx = -1;
editType = ET_PATHS;
placer->alpha = 0;
pathRender->alpha = 0.5;
selectedElements.clear();
editingElement = NULL;
editingEntity = NULL;
}
Element *SceneEditor::getElementAtCursor()
{
int minDist = -1;
Element *selected = 0;
for (Element *e = dsq->getFirstElementOnLayer(this->bgLayer); e; e = e->bgLayerNext)
{
if (e->life == 1)
{
if (e->isCoordinateInside(dsq->getGameCursorPosition()))
{
Vector v = dsq->getGameCursorPosition() - e->position;
int dist = v.getSquaredLength2D();
if (dist < minDist || minDist == -1)
{
minDist = dist;
selected = e;
}
}
}
}
return selected;
}
Entity *SceneEditor::getEntityAtCursor()
{
int minDist = -1;
Entity *selected = 0;
FOR_ENTITIES(i)
{
Entity *e = *i;
if (e->life == 1)
{
if (e->isCoordinateInside(dsq->getGameCursorPosition(), minSelectionSize))
{
Vector v = dsq->getGameCursorPosition() - e->position;
int dist = v.getSquaredLength2D();
if (dist < minDist || minDist == -1)
{
minDist = dist;
selected = e;
}
}
}
}
return selected;
}
void SceneEditor::deleteSelected()
{
if (state != ES_SELECTING) return;
if (editType == ET_ELEMENTS)
{
if (selectedElements.size()>0)
{
for (size_t i = 0; i < selectedElements.size(); i++)
{
selectedElements[i]->safeKill();
dsq->removeElement(selectedElements[i]);
}
selectedElements.clear();
dsq->game->reconstructGrid();
}
else if (editingElement)
{
editingElement->safeKill();
dsq->removeElement(editingElement);
editingElement = 0;
dsq->game->reconstructGrid();
}
}
else if (editType == ET_ENTITIES)
{
if (editingEntity)
{
if (editingEntity->getEntityType() != ET_AVATAR)
{
dsq->game->removeEntity(editingEntity);
editingEntity = 0;
}
}
}
else if (editType == ET_PATHS)
{
if (core->getShiftState())
{
dsq->game->removePath(selectedIdx);
}
else
{
if (selectedIdx != -1)
{
Path *p = dsq->game->getPath(selectedIdx);
if (p->nodes.size() == 1)
{
dsq->game->removePath(selectedIdx);
selectedIdx = -1;
}
else
p->removeNode(selectedNode);
}
}
}
}
void SceneEditor::updateSaveFileEnemyPosition(Entity *ent)
{
XMLElement *exml = dsq->game->saveFile->FirstChildElement("Enemy");
while (exml)
{
int x = atoi(exml->Attribute("x"));
int y = atoi(exml->Attribute("y"));
if (ent->startPos.x == x && ent->startPos.y == y)
{
ent->startPos = Vector(int(ent->position.x), int(ent->position.y));
exml->SetAttribute("x", int(ent->startPos.x));
exml->SetAttribute("y", int(ent->startPos.y));
return;
}
exml = exml->NextSiblingElement("Enemy");
}
exml = dsq->game->saveFile->FirstChildElement("Entity");
while (exml)
{
int x = atoi(exml->Attribute("x"));
int y = atoi(exml->Attribute("y"));
if (ent->startPos.x == x && ent->startPos.y == y)
{
ent->startPos = Vector(int(ent->position.x), int(ent->position.y));
exml->SetAttribute("x", int(ent->startPos.x));
exml->SetAttribute("y", int(ent->startPos.y));
return;
}
exml = exml->NextSiblingElement("Entity");
}
}
void SceneEditor::checkForRebuild()
{
if (editType == ET_ELEMENTS && state != ES_SELECTING && !selectedElements.empty())
{
bool rebuild = false;
for (size_t i = 0; i < selectedElements.size(); i++)
{
if (selectedElements[i]->elementFlag == EF_SOLID || selectedElements[i]->elementFlag == EF_HURT)
{
rebuild = true;
break;
}
}
if (rebuild)
{
dsq->game->reconstructGrid();
}
}
else if (editType == ET_ELEMENTS && state != ES_SELECTING && editingElement != 0 && (editingElement->elementFlag == EF_SOLID || editingElement->elementFlag == EF_HURT))
{
dsq->game->reconstructGrid();
}
}
void SceneEditor::exitMoveState()
{
if (!selectedElements.empty())
{
for (size_t i = 0; i < selectedElements.size(); i++)
{
selectedElements[i]->position = selectedElements[i]->getWorldPosition();
dummy.removeChild(selectedElements[i]);
}
core->removeRenderObject(&dummy, Core::DO_NOT_DESTROY_RENDER_OBJECT);
}
checkForRebuild();
state = ES_SELECTING;
}
void SceneEditor::enterMoveState()
{
if (state != ES_SELECTING) return;
state = ES_MOVING;
if (editType == ET_ELEMENTS)
{
if (!selectedElements.empty())
{
dummy.rotation = Vector(0,0,0);
cursorOffset = dsq->getGameCursorPosition();
groupCenter = getSelectedElementsCenter();
for (size_t i = 0; i < selectedElements.size(); i++)
{
selectedElements[i]->position -= groupCenter;
dummy.addChild(selectedElements[i], PM_NONE);
}
core->addRenderObject(&dummy, selectedElements[0]->layer);
dummy.cull = false;
dummy.position = groupCenter;
oldPosition = dummy.position;
dummy.scale = Vector(1,1,1);
}
else if (editingElement)
{
oldPosition = editingElement->position;
cursorOffset = dsq->getGameCursorPosition();
}
}
else if (editType == ET_ENTITIES)
{
oldPosition = editingEntity->position;
cursorOffset = editingEntity->position - dsq->getGameCursorPosition();
}
else if (editType == ET_PATHS)
{
oldPosition = dsq->game->getPath(selectedIdx)->nodes[selectedNode].position;
cursorOffset = oldPosition - dsq->getGameCursorPosition();
}
}
void SceneEditor::enterRotateState()
{
if (state != ES_SELECTING) return;
if (editType == ET_ENTITIES)
{
state = ES_ROTATING;
oldRotation = editingEntity->rotation;
oldPosition = editingEntity->position;
cursorOffset = dsq->getGameCursorPosition();
}
if (editType == ET_ELEMENTS)
{
if (!selectedElements.empty())
{
state = ES_ROTATING;
dummy.rotation = Vector(0,0,0);
oldRotation = dummy.rotation;
cursorOffset = dsq->getGameCursorPosition();
groupCenter = getSelectedElementsCenter();
for (size_t i = 0; i < selectedElements.size(); i++)
{
selectedElements[i]->position -= groupCenter;
dummy.addChild(selectedElements[i], PM_NONE);
}
core->addRenderObject(&dummy, selectedElements[0]->layer);
dummy.cull = false;
dummy.position = groupCenter;
dummy.scale = Vector(1,1,1);
}
else if (editingElement)
{
state = ES_ROTATING;
oldRotation = editingElement->rotation;
cursorOffset = dsq->getGameCursorPosition();
}
}
}
void SceneEditor::enterScaleState()
{
if (state != ES_SELECTING) return;
if (editType == ET_ELEMENTS)
{
if (!selectedElements.empty())
{
state = ES_SCALING;
dummy.rotation = Vector(0,0,0);
dummy.scale = Vector(1,1,1);
oldScale = dummy.scale;
oldRepeatScale = Vector(1, 1); // not handled for multi-selection
cursorOffset = dsq->getGameCursorPosition();
groupCenter = getSelectedElementsCenter();
for (size_t i = 0; i < selectedElements.size(); i++)
{
selectedElements[i]->position -= groupCenter;
dummy.addChild(selectedElements[i], PM_NONE);
}
core->addRenderObject(&dummy, selectedElements[0]->layer);
dummy.cull = false;
dummy.position = groupCenter;
}
else if (editingElement)
{
oldPosition = editingElement->position;
state = ES_SCALING;
oldScale = editingElement->scale;
oldRepeatScale = editingElement->repeatToFillScale;
cursorOffset = dsq->getGameCursorPosition();
}
}
else if (editType == ET_PATHS)
{
state = ES_SCALING;
oldScale = Vector(editingPath->rect.x2-editingPath->rect.x1,
editingPath->rect.y2-editingPath->rect.y1);
cursorOffset = dsq->getGameCursorPosition();
}
}
void SceneEditor::updateEntitySaveData(Entity *editingEntity)
{
if (editingEntity)
{
EntitySaveData *d = dsq->game->getEntitySaveDataForEntity(editingEntity, oldPosition);
if (d)
{
std::ostringstream os;
os << "idx1: " << d->idx << " ";
os << "idx2: " << editingEntity->entityTypeIdx << " ";
os << "name: " << editingEntity->name;
debugLog(os.str());
d->x = editingEntity->position.x;
d->y = editingEntity->position.y;
editingEntity->startPos = Vector(d->x, d->y);
d->rot = editingEntity->rotation.z;
}
else
{
}
}
}
void SceneEditor::mouseButtonLeftUp()
{
if (multiSelecting || core->mouse.buttons.right) return;
if (editType == ET_ENTITIES)
{
updateEntitySaveData(editingEntity);
}
if (state == ES_MOVING)
{
exitMoveState();
}
state = ES_SELECTING;
}
void SceneEditor::mouseButtonRightUp()
{
if (multiSelecting || core->mouse.buttons.left) return;
if (editType == ET_ENTITIES)
updateEntitySaveData(editingEntity);
if (editType == ET_ELEMENTS)
{
if (state == ES_ROTATING)
{
if (!selectedElements.empty())
{
for (size_t i = 0; i < selectedElements.size(); i++)
{
selectedElements[i]->position = selectedElements[i]->getWorldPosition();
selectedElements[i]->rotation = selectedElements[i]->getAbsoluteRotation();
dummy.removeChild(selectedElements[i]);
}
core->removeRenderObject(&dummy, Core::DO_NOT_DESTROY_RENDER_OBJECT);
}
}
else if (state == ES_SCALING)
{
if (!selectedElements.empty())
{
for (size_t i = 0; i < selectedElements.size(); i++)
{
selectedElements[i]->position = selectedElements[i]->getWorldPosition();
selectedElements[i]->scale = selectedElements[i]->scale * dummy.scale;
selectedElements[i]->rotation = selectedElements[i]->getAbsoluteRotation();
dummy.removeChild(selectedElements[i]);
}
core->removeRenderObject(&dummy, Core::DO_NOT_DESTROY_RENDER_OBJECT);
}
else if (editingElement)
{
Vector add = editingElement->beforeScaleOffset;
Vector newScale = editingElement->scale;
editingElement->beforeScaleOffset = Vector(0,0,0);
editingElement->scale = Vector(1,1,1);
editingElement->position = editingElement->getWorldCollidePosition(add);
editingElement->scale = newScale;
}
}
checkForRebuild();
}
state = ES_SELECTING;
}
void SceneEditor::toggleElementSolid()
{
if (editingElement)
{
switch(editingElement->elementFlag)
{
default:
case EF_NONE:
{
std::ostringstream os;
os << "elementFlag: " << editingElement->elementFlag;
debugLog(os.str());
debugLog("Solid");
editingElement->elementFlag = EF_SOLID;
}
break;
case EF_SOLID:
debugLog("Solid2");
editingElement->elementFlag = EF_SOLID2;
break;
case EF_SOLID2:
debugLog("Solid3");
editingElement->elementFlag = EF_SOLID3;
break;
case EF_SOLID3:
debugLog("None");
editingElement->elementFlag = EF_NONE;
break;
}
dsq->game->reconstructGrid(true);
}
}
void SceneEditor::toggleElementHurt()
{
if (editingElement)
{
if (editingElement->elementFlag == EF_HURT)
editingElement->elementFlag = EF_NONE;
else
editingElement->elementFlag = EF_HURT;
dsq->game->reconstructGrid(true);
}
}
void SceneEditor::toggleElementRepeat()
{
if (editingElement)
{
editingElement->repeatTextureToFill(!editingElement->isRepeatingTextureToFill());
}
}
void SceneEditor::mouseButtonLeft()
{
if (multiSelecting || state != ES_SELECTING || !dummy.children.empty() || core->mouse.buttons.right) return;
if (editType == ET_ELEMENTS)
{
if (selectedElements.empty() || editingElement)
{
if (core->getShiftState())
{
cloneSelectedElement();
}
else
{
enterMoveState();
}
}
}
else if (editType == ET_ENTITIES)
{
if (editingEntity)
{
if (core->getShiftState())
{
cloneSelectedElement();
}
else
{
enterMoveState();
}
}
}
else if (editType == ET_PATHS)
{
if (selectedIdx != -1)
{
Path *p = getSelectedPath();
editingPath = p;
if (p && selectedNode < p->nodes.size())
{
if (core->getShiftState())
{
cloneSelectedElement();
}
else
{
enterMoveState();
}
}
}
}
}
void SceneEditor::mouseButtonRight()
{
if (multiSelecting || state != ES_SELECTING || !dummy.children.empty() || core->mouse.buttons.left) return;
if (editType == ET_ENTITIES)
{
if (editingEntity)
{
if (core->getShiftState())
enterScaleState();
else
enterRotateState();
}
}
if (editType == ET_PATHS)
{
if (selectedIdx != -1)
{
debugLog("path scaling HERE!");
Path *p = dsq->game->getPath(selectedIdx);
editingPath = p;
if (core->getShiftState())
{
enterScaleState();
}
}
}
if (editType == ET_ELEMENTS)
{
if (selectedElements.empty() || editingElement)
{
if (core->getShiftState())
enterScaleState();
else
enterRotateState();
}
}
if (editType == ET_ELEMENTS && state == ES_MOVING)
{
}
}
void SceneEditor::startMoveEntity()
{
movingEntity = dsq->game->getEntityAtCursor();
}
void SceneEditor::endMoveEntity()
{
if (movingEntity)
{
updateSaveFileEnemyPosition(movingEntity);
movingEntity = 0;
}
}
void SceneEditor::up()
{
if (editType == ET_ELEMENTS && state == ES_SELECTING)
{
if (editingElement || !selectedElements.empty())
{
enterMoveState();
updateSelectedElementPosition(Vector(0,-1));
exitMoveState();
}
}
}
void SceneEditor::down()
{
if (editType == ET_ELEMENTS && state == ES_SELECTING)
{
if (editingElement || !selectedElements.empty())
{
enterMoveState();
updateSelectedElementPosition(Vector(0,1));
exitMoveState();
}
}
}
void SceneEditor::regenLevel()
{
generateLevel();
skinLevel();
}
void SceneEditor::skinLevel()
{
if (skinMinX == -1)
{
dsq->screenMessage("Cannot skin without generated level.");
return;
}
skinLevel(skinMinX, skinMinY, skinMaxX, skinMaxY);
}
void SceneEditor::skinLevel(int minX, int minY, int maxX, int maxY)
{
std::vector<Element*> deleteElements;
size_t i = 0;
for (i = 0; i < dsq->getNumElements(); i++)
{
Element *e = dsq->getElement(i);
if (e->bgLayer==4 && e->templateIdx >= 1 && e->templateIdx <= 4)
{
e->safeKill();
deleteElements.push_back(e);
}
}
for (i = 0; i < deleteElements.size(); i++)
{
dsq->removeElement(deleteElements[i]);
}
deleteElements.clear();
int idx=1;
int idxCount = 0;
for (int x = minX; x < maxX-2; x++)
{
for (int y = minY; y < maxY; y++)
{
Vector offset, pOffset;
Vector wallNormal;
float rot=0;
bool addTile = false;
TileVector t(x,y);
if (dsq->game->isObstructed(t, OT_MASK_BLACK)
&& (
!dsq->game->isObstructed(TileVector(x+1,y), OT_MASK_BLACK) ||
!dsq->game->isObstructed(TileVector(x-1,y), OT_MASK_BLACK) ||
!dsq->game->isObstructed(TileVector(x,y-1), OT_MASK_BLACK) ||
!dsq->game->isObstructed(TileVector(x,y+1), OT_MASK_BLACK)
)
)
{
float dist=0;
wallNormal = dsq->game->getWallNormal(t.worldVector(), 5, &dist, OT_MASK_BLACK);
offset = wallNormal*(-TILE_SIZE*0.6f);
MathFunctions::calculateAngleBetweenVectorsInDegrees(Vector(0,0,0), wallNormal, rot);
rot = 180-(360-rot);
addTile = true;
}
if(addTile)
{
const unsigned char u = tileProps.at(x, y-1, TPR_DEFAULT);
const unsigned char d = tileProps.at(x, y+1, TPR_DEFAULT);
const unsigned char l = tileProps.at(x-1, y, TPR_DEFAULT);
const unsigned char r = tileProps.at(x+1, y, TPR_DEFAULT);
if(u == TPR_DONT_SKIN
|| d == TPR_DONT_SKIN
|| l == TPR_DONT_SKIN
|| r == TPR_DONT_SKIN)
{
addTile = false;
}
}
if (addTile)
{
TileVector t(x,y);
Vector p = t.worldVector();
Quad q;
q.rotation.z = rot;
p += Vector(TILE_SIZE/2, TILE_SIZE/2,0);
offset.z = 0;
bool skip = false;
for (size_t i = 0; i < dsq->getNumElements(); i++)
{
Element *e = dsq->getElement(i);
if (e->templateIdx <= 4 && e->templateIdx >= 1)
{
if ((p - e->position).getSquaredLength2D() < sqr(50))
{
skip = true;
break;
}
}
}
if (!skip)
{
std::vector<int> cantUse;
cantUse.resize(4);
size_t i = 0;
for (i = 0; i < dsq->getNumElements(); i++)
{
Element *e = dsq->getElement(i);
if (e->templateIdx <= 4 && e->templateIdx >= 1)
{
if ((p - e->position).getSquaredLength2D() < sqr(120))
{
cantUse[e->templateIdx-1]++;
}
}
}
size_t useIdx = rand()%cantUse.size()+1;
for (i = 0; i < cantUse.size(); i++)
{
size_t check = i + idxCount;
if (check >= cantUse.size())
check -= cantUse.size();
if (cantUse[check]<=0)
{
useIdx = check+1;
}
}
idxCount = rand()%cantUse.size();
Element *e = dsq->game->createElement(useIdx, p, 4, &q);
e->offset = offset;
idx++;
if(idx > 4)
idx = 1;
}
}
}
for (size_t i = 0; i < dsq->getNumElements(); i++)
{
Element *e = dsq->getElement(i);
if (e->bgLayer == 4 && e->templateIdx >= 1 && e->templateIdx <= 4)
{
e->position += e->offset;
e->offset = Vector(0,0,0);
}
}
}
}
SceneEditor::TileProperty SceneEditor::GetColorProperty(unsigned char r, unsigned char g, unsigned char b)
{
if(r >= 200 && g > 127 && g < 200 && b >= 200)
return TPR_DONT_SKIN;
return TPR_DEFAULT;
}
void SceneEditor::generateLevel()
{
tileProps.clear();
std::string file=getMapTemplateFilename();
size_t maxX=0, maxY=0;
const ImageData img = imageLoadGeneric(file.c_str(), true);
if (img.pixels)
{
dsq->game->clearObsRows();
assert(img.channels == 4);
tileProps.init(img.w, img.h);
int c = 0;
for (size_t y = 0; y < img.h; y++)
{
bool isobs = false; // start assuming that there is no obstruction
size_t xobs = 0;
for(size_t x = 0; x < img.w; ++x)
{
tileProps(x, y) = GetColorProperty(img.pixels[c], img.pixels[c+1], img.pixels[c+2]);
// anything that is close to black is obstruction
bool obs = img.pixels[c] < 48 &&
img.pixels[c+1] < 48 &&
img.pixels[c+2] < 48;
if(obs != isobs)
{
isobs = obs;
if(obs)
{
xobs = x; // just changed from not-obs to obs, record start
if (x > maxX)
maxX = x;
if (y > maxY)
maxY = y;
}
else if(x != xobs) // safeguard against left side starting with obs
{
assert(x > xobs);
dsq->game->addObsRow(xobs, y, x - xobs); // just changed from obs to not-obs, emit row
}
}
c += img.channels;
}
if(isobs) // right side ends with obs, add final row
{
dsq->game->addObsRow(xobs, y, img.w - xobs);
if (img.w > maxX)
maxX = img.w;
if (y > maxY)
maxY = y;
}
}
dsq->game->reconstructGrid(true);
maxX--;
maxY--;
this->skinMinX = 4;
this->skinMinY = 4;
this->skinMaxX = maxX;
this->skinMaxY = maxY;
if (img.pixels != NULL)
free(img.pixels);
}
else
{
debugLog("generateLevel: Failed to load mapTemplate");
}
}
void SceneEditor::removeEntity()
{
debugLog("remove entity at cursor");
dsq->game->removeEntityAtCursor();
}
void SceneEditor::placeAvatar()
{
dsq->game->avatar->position = dsq->getGameCursorPosition();
dsq->game->action(ACTION_PLACE_AVATAR, 0, -1, INPUT_NODEVICE);
}
void SceneEditor::scaleElementUp()
{
placer->scale += Vector(0.25, 0.25,0);
}
void SceneEditor::scaleElementDown()
{
placer->scale -= Vector(0.25, 0.25,0);
}
void SceneEditor::scaleElement1()
{
placer->scale = Vector(1,1,1);
}
void SceneEditor::flipElementHorz()
{
if (editType != ET_ELEMENTS)
return;
if (editingElement)
editingElement->flipHorizontal();
else
this->placer->flipHorizontal();
}
void SceneEditor::flipElementVert()
{
if (editType != ET_ELEMENTS)
return;
if (editingElement)
editingElement->flipVertical();
else
this->placer->flipVertical();
}
void SceneEditor::moveElementToLayer(Element *e, int bgLayer)
{
if (!selectedElements.empty())
{
for (size_t i = 0; i < selectedElements.size(); i++)
{
Element *e = selectedElements[i];
core->removeRenderObject(e, Core::DO_NOT_DESTROY_RENDER_OBJECT);
dsq->removeElement(e);
e->bgLayer = bgLayer;
dsq->addElement(e);
core->addRenderObject(e, LR_ELEMENTS1+bgLayer);
}
}
else if (e)
{
core->removeRenderObject(e, Core::DO_NOT_DESTROY_RENDER_OBJECT);
dsq->removeElement(e);
e->bgLayer = bgLayer;
dsq->addElement(e);
core->addRenderObject(e, LR_ELEMENTS1+bgLayer);
}
}
void SceneEditor::updateMultiSelect()
{
if (!multiSelecting) return;
Vector secondPoint = dsq->getGameCursorPosition();
if (!(multiSelectPoint-secondPoint).isLength2DIn(64))
{
Vector p1, p2;
if (secondPoint.x < multiSelectPoint.x)
{
p1.x = secondPoint.x;
p2.x = multiSelectPoint.x;
}
else
{
p1.x = multiSelectPoint.x;
p2.x = secondPoint.x;
}
if (secondPoint.y < multiSelectPoint.y)
{
p1.y = secondPoint.y;
p2.y = multiSelectPoint.y;
}
else
{
p1.y = multiSelectPoint.y;
p2.y = secondPoint.y;
}
selectedElements.clear();
for (size_t i = 0; i < dsq->getNumElements(); i++)
{
Element *e = dsq->getElement(i);
if (e->bgLayer == bgLayer && e->position.x >= p1.x && e->position.y >= p1.y && e->position.x <= p2.x && e->position.y <= p2.y)
{
selectedElements.push_back(e);
}
}
}
}
void SceneEditor::action(int id, int state, int source, InputDevice device)
{
if (core->getCtrlState() && editingElement)
{
if (id == ACTION_BGLAYEREND)
{
editingElement->setElementEffectByIndex(-1);
}
else if (id >= ACTION_BGLAYER1 && id < ACTION_BGLAYER10)
{
editingElement->setElementEffectByIndex(id - ACTION_BGLAYER1);
}
}
else if (editType == ET_ELEMENTS && state && id >= ACTION_BGLAYER1 && id < ACTION_BGLAYEREND)
{
int newLayer = id - ACTION_BGLAYER1;
updateText();
if (core->getAltState())
{
dsq->game->setElementLayerVisible(newLayer, !dsq->game->isElementLayerVisible(newLayer));
return; // do not switch to the layer that was just hidden
}
else if (core->getShiftState() && (editingElement || !selectedElements.empty()))
{
moveElementToLayer(editingElement, newLayer);
}
else
{
selectedElements.clear();
}
this->bgLayer = newLayer;
}
if (id == ACTION_MULTISELECT && this->state == ES_SELECTING)
{
if (state)
{
if (!multiSelecting)
selectedElements.clear();
multiSelecting = true;
multiSelectPoint = dsq->getGameCursorPosition();
}
else
{
multiSelecting = false;
}
}
}
void SceneEditor::rotateElement()
{
placer->rotation += Vector(0, 0, 45);
if (placer->rotation.z > 360)
placer->rotation.z -= 360;
}
void SceneEditor::rotateElement2()
{
placer->rotation -= Vector(0, 0, 45);
if (placer->rotation.z < 0)
placer->rotation.z += 360;
}
void SceneEditor::loadSceneByName()
{
std::string s = dsq->getUserInputString("Enter Name of Map to Load");
if (!s.empty())
dsq->game->transitionToScene(s);
}
void SceneEditor::reloadScene()
{
debugLog("reloadScene");
dsq->game->positionToAvatar = dsq->game->avatar->position;
dsq->game->transitionToScene(dsq->game->sceneName);
}
void SceneEditor::loadScene()
{
if (core->getShiftState())
{
loadSceneByName();
}
else
{
reloadScene();
}
// HACK: reload stuff when (re-) loading a map this way
particleManager->loadParticleBank(dsq->particleBank1, dsq->particleBank2);
Shot::loadShotBank(dsq->shotBank1, dsq->shotBank2);
dsq->game->loadEntityTypeList();
dsq->loadElementEffects();
dsq->continuity.loadSongBank();
dsq->loadStringBank();
}
void SceneEditor::saveScene()
{
if(dsq->game->saveScene(dsq->game->sceneName))
dsq->screenMessage(dsq->game->sceneName + " Saved!");
else
dsq->screenMessage(dsq->game->sceneName + " FAILED to save!");
}
void SceneEditor::deleteSelectedElement()
{
deleteElement(selectedIdx);
selectedIdx = -1;
}
void SceneEditor::deleteElement(int selectedIdx)
{
if (selectedIdx == -1) return;
Element *e = dsq->getElement(selectedIdx);
e->setLife(0.5);
e->setDecayRate(1);
e->fadeAlphaWithLife = true;
dsq->removeElement(selectedIdx);
dsq->game->reconstructGrid();
}
Quad *se_grad = 0;
void destroyEntityPage()
{
if (se_label)
{
se_label->safeKill();
se_label = 0;
}
if (se_grad)
{
se_grad->setLife(1);
se_grad->setDecayRate(10);
se_grad->fadeAlphaWithLife = 1;
se_grad = 0;
}
for (size_t i = 0; i < qs.size(); i++)
{
qs[i]->safeKill();
}
qs.clear();
}
void createEntityPage()
{
int c = 0;
int rowSize = 12;
int sizing = 64;
Vector basePos = Vector(48, 164);
destroyEntityPage();
se_grad = new Quad();
se_grad->scale = Vector(800, 500);
se_grad->position = Vector(400,350);
se_grad->followCamera = 1;
se_grad->alpha = 0;
se_grad->color = Vector(0,0,0);
se_grad->alpha.interpolateTo(0.8f, 0.2f);
dsq->game->addRenderObject(se_grad, LR_HUD);
EntityGroup &group = game->entityGroups[game->sceneEditor.entityPageNum];
for (size_t i = 0; i < group.entities.size(); i++)
{
EntityGroupEntity ent = group.entities[i];
EntityClass *ec = dsq->game->getEntityClassForEntityType(ent.name);
if (!ec && !dsq->mod.isActive())
{
errorLog("Entity Page List Error: Typo in Entities.txt?");
}
int type = -1;
if (ec)
{
size_t j=0;
for (j = 0; j < dsq->game->entityTypeList.size(); j++)
{
if (ec->idx == dsq->game->entityTypeList[j].idx)
break;
}
type = j;
}
int bit = int(floorf(float(c/rowSize))); // FIXME: Not float(c)/rowSize? --achurch
std::string prevGfx = ent.gfx;
if (prevGfx.empty() && ec)
prevGfx = ec->prevGfx;
std::string ecName = ent.name;
if (ec)
ecName = ec->name;
if (!ecName.empty())
{
SEQuad *q = new SEQuad(prevGfx, Vector((c-(bit*rowSize)), bit)*sizing, type, ecName);
q->position += basePos;
if (q->getWidth() > q->getHeight())
{
q->setWidthHeight(sizing, (q->getHeight()*sizing) / q->getWidth());
}
else
{
q->setWidthHeight((q->getWidth()*sizing) / q->getHeight(), sizing);
}
q->followCamera = 1;
dsq->game->addRenderObject(q, LR_HUD);
qs.push_back(q);
c++;
}
}
se_label = new DebugFont();
se_label->setFontSize(10);
se_label->setText(group.name);
se_label->position = Vector(20,90);
se_label->followCamera = 1;
dsq->game->addRenderObject(se_label, LR_HUD);
}
void nextEntityPage()
{
game->sceneEditor.entityPageNum++;
if (game->sceneEditor.entityPageNum >= game->entityGroups.size())
game->sceneEditor.entityPageNum = 0;
createEntityPage();
}
void prevEntityPage()
{
game->sceneEditor.entityPageNum--;
if (game->sceneEditor.entityPageNum >= game->entityGroups.size())
game->sceneEditor.entityPageNum = game->entityGroups.size()-1;
createEntityPage();
}
void SceneEditor::selectEntityFromGroups()
{
createEntityPage();
placer->alpha = 0;
se_changedEntityType = false;
editType = ET_SELECTENTITY;
bool mbld = false;
bool ld = false, rd = false;
ld = core->getKeyState(KEY_E);
while (!se_changedEntityType)
{
if (core->mouse.buttons.left && !mbld)
mbld = true;
else if (!core->mouse.buttons.left && mbld)
{
mbld = false;
if (core->mouse.position.y < 100)
break;
}
if (core->getKeyState(KEY_ESCAPE))
break;
if (core->getKeyState(KEY_SPACE))
break;
if (!core->getKeyState(KEY_E))
ld = false;
else if (!ld)
{
ld=true;
nextEntityPage();
}
if (!core->getKeyState(KEY_R))
rd = !true;
else if (!rd)
{
rd=!false;
prevEntityPage();
}
core->run(FRAME_TIME);
}
destroyEntityPage();
editType = ET_ENTITIES;
updateEntityPlacer();
placer->alpha = 1;
}
void SceneEditor::updateEntityPlacer()
{
placer->setTexture(selectedEntity.prevGfx);
placer->scale = Vector(selectedEntity.prevScale,selectedEntity.prevScale);
}
Element* SceneEditor::cycleElementNext(Element *e1)
{
size_t ce = e1->templateIdx;
int idx=0;
for (size_t i = 0; i < dsq->game->elementTemplates.size(); i++)
{
if (dsq->game->elementTemplates[i].idx == ce)
idx = i;
}
ce = idx;
ce++;
if (ce >= dsq->game->elementTemplates.size())
ce = 0;
idx = dsq->game->elementTemplates[ce].idx;
if (idx < 1024)
{
Element *e = dsq->game->createElement(idx, e1->position, e1->bgLayer, e1);
e1->safeKill();
dsq->removeElement(e1);
return e;
}
return e1;
}
Element* SceneEditor::cycleElementPrev(Element *e1)
{
size_t ce = e1->templateIdx;
size_t idx=0;
for (size_t i = 0; i < dsq->game->elementTemplates.size(); i++)
{
if (dsq->game->elementTemplates[i].idx == ce)
{
idx = i;
break;
}
}
ce = idx;
ce--;
if (ce == -1)
ce = dsq->game->elementTemplates.size()-1;
idx = dsq->game->elementTemplates[ce].idx;
if (idx < 1024)
{
Element *e = dsq->game->createElement(idx, e1->position, e1->bgLayer, e1);
e1->safeKill();
dsq->removeElement(e1);
return e;
}
return e1;
}
void SceneEditor::nextElement()
{
if (state != ES_SELECTING) return;
if (core->getCtrlState())
{
dsq->mod.recache();
return;
}
if (core->getAltState())
{
debugLog("rebuilding level!");
dsq->game->reconstructGrid(true);
return;
}
if (editType == ET_ELEMENTS)
{
if (dsq->game->elementTemplates.empty()) return;
if (core->getCtrlState())
{
if (!selectedElements.empty())
{
for (size_t i = 0; i < selectedElements.size(); i++)
{
selectedElements[i]->rotation.z = 0;
}
}
else if (editingElement)
{
editingElement->rotation.z = 0;
}
}
else if (!selectedElements.empty())
{
for (size_t i = 0; i < selectedElements.size(); i++)
{
selectedElements[i] = cycleElementNext(selectedElements[i]);
}
}
else if (editingElement)
{
cycleElementNext(editingElement);
editingElement = 0;
}
else
{
int oldCur = curElement;
curElement++;
if (curElement >= dsq->game->elementTemplates.size())
curElement = 0;
if (dsq->game->elementTemplates[curElement].idx < 1024)
{
placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
}
else
{
curElement = oldCur;
}
}
}
}
void SceneEditor::prevElement()
{
if (state != ES_SELECTING) return;
if (editType != ET_SELECTENTITY)
{
if (core->getCtrlState())
{
debugLog("SELECT ENTITY FROM GROUPS!");
selectEntityFromGroups();
return;
}
}
if (editType == ET_ELEMENTS)
{
if (dsq->game->elementTemplates.empty()) return;
if (!selectedElements.empty())
{
for (size_t i = 0; i < selectedElements.size(); i++)
{
selectedElements[i] = cycleElementPrev(selectedElements[i]);
}
}
else if (editingElement)
{
cycleElementPrev(editingElement);
editingElement = 0;
}
else
{
doPrevElement();
}
}
}
void SceneEditor::doPrevElement()
{
size_t oldCur = curElement;
size_t maxn = dsq->game->elementTemplates.size();
if(curElement)
curElement--;
else if(maxn)
curElement = maxn-1;
if (maxn && curElement >= maxn)
curElement = maxn-1;
if (maxn && dsq->game->elementTemplates[curElement].idx < 1024)
{
placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
}
else
{
curElement = oldCur;
}
}
void SceneEditor::moveLayer()
{
std::string s = dsq->getUserInputString("Enter 'fromLayer toLayer' (space inbetween, ESC/m-ty to cancel)");
if (!s.empty())
{
std::istringstream is(s);
int fromLayer, toLayer;
is >> fromLayer >> toLayer;
toLayer--;
fromLayer--;
for (size_t i = 0; i < dsq->getNumElements(); i++)
{
Element *e = dsq->getElement(i);
if (e)
{
if (e->bgLayer == fromLayer)
{
moveElementToLayer(e, toLayer);
}
}
}
}
}
void SceneEditor::selectZero()
{
if (state != ES_SELECTING) return;
if (editType == ET_ELEMENTS)
{
if (dsq->game->elementTemplates.empty()) return;
if (editingElement)
{
}
else
{
curElement = 0;
placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
}
}
}
void SceneEditor::selectEnd()
{
if (state != ES_SELECTING) return;
if (editType == ET_ELEMENTS)
{
if (dsq->game->elementTemplates.empty()) return;
if (!editingElement)
{
size_t largest = 0;
for (size_t i = 0; i < dsq->game->elementTemplates.size(); i++)
{
ElementTemplate et = dsq->game->elementTemplates[i];
if (et.idx < 1024 && i > largest)
{
largest = i;
}
}
curElement = largest;
placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
}
}
}
void SceneEditor::placeElement()
{
if (editType == ET_ELEMENTS)
{
if (!core->getShiftState() && !core->getKeyState(KEY_LALT))
{
dsq->game->createElement(dsq->game->elementTemplates[curElement].idx, placer->position, bgLayer, placer);
updateText();
dsq->game->reconstructGrid();
}
}
else if (editType == ET_ENTITIES)
{
if (!selectedEntity.nameBased)
dsq->game->createEntity(selectedEntity.index, 0, dsq->getGameCursorPosition(), 0, true, "", ET_ENEMY, true);
else
dsq->game->createEntity(selectedEntity.name, 0, dsq->getGameCursorPosition(), 0, true, "", ET_ENEMY, true);
}
else if (editType == ET_PATHS)
{
if (core->getCtrlState())
{
// new path
Path *p = new Path;
p->name = "";
PathNode n;
n.position = dsq->getGameCursorPosition();
p->nodes.push_back(n);
dsq->game->addPath(p);
selectedIdx = dsq->game->getNumPaths()-1;
}
else
{
Path *p = getSelectedPath();
if (p)
{
p->addNode(selectedNode);
}
}
}
}
void SceneEditor::cloneSelectedElement()
{
if (editType == ET_ELEMENTS)
{
if (!selectedElements.empty())
{
std::vector<Element*>copy;
Vector groupCenter = this->getSelectedElementsCenter();
for (size_t i = 0; i < selectedElements.size(); i++)
{
Element *e1 = selectedElements[i];
Vector dist = e1->position - groupCenter;
Element *e = dsq->game->createElement(e1->templateIdx, placer->position + Vector(40,40) + dist, e1->bgLayer, e1);
e->elementFlag = e1->elementFlag;
e->setElementEffectByIndex(e1->getElementEffectIndex());
copy.push_back(e);
}
selectedElements.clear();
selectedElements = copy;
copy.clear();
}
else if (editingElement)
{
Element *e1 = editingElement;
Element *e = dsq->game->createElement(e1->templateIdx, placer->position + Vector(40,40), e1->bgLayer, e1);
e->elementFlag = e1->elementFlag;
e->setElementEffectByIndex(e1->getElementEffectIndex());
}
dsq->game->reconstructGrid();
}
else if (editType == ET_ENTITIES)
{
}
else if (editType == ET_PATHS)
{
if (editingPath)
{
Path *p = editingPath;
Path *newp = new Path;
newp->name = p->name;
newp->nodes = p->nodes;
newp->rect = p->rect;
newp->refreshScript();
newp->pathShape = p->pathShape;
newp->nodes[0].position += Vector(64,64);
dsq->game->addPath(newp);
selectedIdx = dsq->game->getNumPaths()-1;
newp->init();
}
}
}
void SceneEditor::shutdown()
{
clearActions();
text = 0;
placer = 0;
}
void SceneEditor::toggle()
{
toggle(!on);
}
void SceneEditor::toggle(bool on)
{
if (core->getNestedMains() > 1) return;
if (dsq->game->isInGameMenu()) return;
if (!on && editType == ET_SELECTENTITY) return;
if (dsq->game->worldMapRender && dsq->game->worldMapRender->isOn()) return;
this->on = on;
autoSaveTimer = 0;
execID = -1;
if (on)
{
btnMenu->alpha = 1;
dsq->getRenderObjectLayer(LR_BLACKGROUND)->update = true;
dsq->game->togglePause(on);
if (dsq->game->avatar)
dsq->game->avatar->disableInput();
text->alpha.interpolateTo(1, 0.5);
placer->alpha.interpolateTo(0.5, 0.5);
movingEntity = 0;
dsq->toggleCursor(true);
dsq->setCursor(CURSOR_NORMAL);
dsq->darkLayer.toggle(false);
dsq->game->rebuildElementUpdateList();
for (int i = LR_ELEMENTS1; i <= LR_ELEMENTS8; i++)
{
dsq->getRenderObjectLayer(i)->update = true;
}
oldGlobalScale = core->globalScale;
const float cameraOffset = 1/oldGlobalScale.x - 1/zoom.x;
core->cameraPos.x += cameraOffset * core->getVirtualWidth()/2;
core->cameraPos.y += cameraOffset * core->getVirtualHeight()/2;
core->globalScale = zoom;
core->globalScaleChanged();
}
else
{
btnMenu->alpha = 0;
selectedElements.clear();
for (int i = 0; i < 9; i++)
dsq->getRenderObjectLayer(LR_ELEMENTS1+i)->visible = true;
if (movingEntity)
endMoveEntity();
movingEntity = 0;
dsq->getRenderObjectLayer(LR_BLACKGROUND)->update = false;
dsq->game->togglePause(on);
if (dsq->game->avatar)
dsq->game->avatar->enableInput();
text->alpha.interpolateTo(0, 0.2f);
placer->alpha.interpolateTo(0, 0.2f);
dsq->darkLayer.toggle(true);
dsq->game->rebuildElementUpdateList();
const float cameraOffset = 1/oldGlobalScale.x - 1/zoom.x;
core->cameraPos.x -= cameraOffset * core->getVirtualWidth()/2;
core->cameraPos.y -= cameraOffset * core->getVirtualHeight()/2;
core->globalScale = oldGlobalScale;
}
}
bool SceneEditor::isOn()
{
return on;
}
void SceneEditor::updateText()
{
const Vector cursor = dsq->getGameCursorPosition();
TileVector tv(cursor);
std::ostringstream os;
os << dsq->game->sceneName << " bgL[" << bgLayer << "] (" <<
(int)dsq->cameraPos.x << "," << (int)dsq->cameraPos.y << ") ("
<< (int)cursor.x << "," << (int)cursor.y << ") T("
<< tv.x << "," << tv.y << ") ";
switch(editType)
{
case ET_ELEMENTS:
os << "elements (" << dsq->getNumElements() << ")";
if (selectedElements.size() > 1)
{
os << " - " << selectedElements.size() << " selected";
}
else
{
Element *e;
if (!selectedElements.empty())
e = selectedElements[0];
else
e = editingElement;
if (e)
{
os << " id: " << e->templateIdx;
ElementTemplate *et = game->getElementTemplateByIdx(e->templateIdx);
if (et)
os << " gfx: " << et->gfx;
os << " efx: " << (e->getElementEffectIndex() + 1); // +1 so that it resembles the layout on numpad
}
}
break;
case ET_ENTITIES:
os << "entities (" << dsq->entities.size() << ")";
if (editingEntity)
{
os.precision(1);
os << std::fixed;
os << " id: " << editingEntity->getID()
<< " name: " << editingEntity->name
<< " flag:" << dsq->continuity.getEntityFlag(dsq->game->sceneName, editingEntity->getID())
<< " fh:" << editingEntity->isfh()
<< " fv:" << editingEntity->isfv()
<< " state:" << editingEntity->getState()
<< " et:" << editingEntity->getEntityType()
<< " hp:" << editingEntity->health << "/" << editingEntity->maxHealth;
}
break;
case ET_PATHS:
os << "paths (" << dsq->game->getNumPaths() << ")";
if (selectedIdx != size_t(-1))
os << " si[" << selectedIdx << "]";
if (getSelectedPath())
os << " name: " << getSelectedPath()->name;
break;
case ET_SELECTENTITY:
case ET_MAX:
break;
}
text->setText(os.str());
}
Vector SceneEditor::getSelectedElementsCenter()
{
Vector c;
for (size_t i = 0; i < selectedElements.size(); i++)
{
c += selectedElements[i]->position;
}
c /= float(selectedElements.size());
return c;
}
void SceneEditor::update(float dt)
{
if (on)
{
if (core->getNestedMains() > 1) return;
autoSaveTimer += dt;
if (autoSaveTimer > vars->autoSaveTime && state == ES_SELECTING)
{
autoSaveTimer = 0;
std::ostringstream os;
os << "auto/AUTO_" << autoSaveFile << "_" << dsq->game->sceneName;
if(dsq->game->saveScene(os.str()))
{
std::string m = "Map AutoSaved to " + os.str();
dsq->debugLog(m);
dsq->screenMessage(m);
}
autoSaveFile++;
if (autoSaveFile > vars->autoSaveFiles)
autoSaveFile = 0;
}
updateMultiSelect();
switch (editType)
{
case ET_ELEMENTS:
editingEntity = 0;
if (isActing(ACTION_MULTISELECT, -1) || !selectedElements.empty())
{
editingElement = 0;
}
if (state == ES_SELECTING && !isActing(ACTION_MULTISELECT, -1))
editingElement = this->getElementAtCursor();
if (editingElement)
placer->alpha = 0;
else
placer->alpha = 0.5;
break;
case ET_ENTITIES:
editingElement = 0;
if (state == ES_SELECTING)
editingEntity = this->getEntityAtCursor();
if (editingEntity)
placer->alpha = 0;
else
placer->alpha = 0.5;
break;
case ET_PATHS:
case ET_SELECTENTITY:
case ET_MAX:
break;
}
updateText();
ActionMapper::onUpdate(dt);
TileVector cursorTile(dsq->getGameCursorPosition());
Vector p = Vector(cursorTile.x*TILE_SIZE+TILE_SIZE/2, cursorTile.y*TILE_SIZE+TILE_SIZE/2);
placer->position = p;
int camSpeed = 500/zoom.x;
if (core->getShiftState())
camSpeed = 5000/zoom.x;
if (isActing(ACTION_CAMLEFT, -1))
dsq->cameraPos.x -= dt*camSpeed;
if (isActing(ACTION_CAMRIGHT, -1))
dsq->cameraPos.x += dt*camSpeed;
if (isActing(ACTION_CAMUP, -1))
dsq->cameraPos.y -= dt*camSpeed;
if (isActing(ACTION_CAMDOWN, -1))
dsq->cameraPos.y += dt*camSpeed;
if (core->mouse.buttons.middle && !core->mouse.change.isZero())
{
dsq->cameraPos += core->mouse.change*(4/zoom.x);
core->setMousePosition(core->mouse.lastPosition);
}
float spd = 0.5;
const Vector oldZoom = zoom;
if (isActing(ACTION_ZOOMOUT, -1))
zoom /= (1 + spd*dt);
else if (isActing(ACTION_ZOOMIN, -1))
zoom *= (1 + spd*dt);
else if (core->mouse.scrollWheelChange < 0)
{
if (core->getShiftState() && !core->getCtrlState()) // hackish: to prevent accidental recache()
nextElement();
else
zoom /= 1.12f;
}
else if (core->mouse.scrollWheelChange > 0)
{
if (core->getShiftState() && !core->getCtrlState()) // hackish: to prevent accidental entity selection
prevElement();
else
zoom *= 1.12f;
}
if (zoom.x < 0.04f)
zoom.x = zoom.y = 0.04f;
core->globalScale = zoom;
core->globalScaleChanged();
if (zoom.x != oldZoom.x)
{
const float mouseX = core->mouse.position.x;
const float mouseY = core->mouse.position.y;
dsq->cameraPos.x += mouseX/oldZoom.x - mouseX/zoom.x;
dsq->cameraPos.y += mouseY/oldZoom.y - mouseY/zoom.y;
}
if (this->editType == ET_PATHS)
{
switch(state)
{
case ES_SELECTING:
{
selectedIdx = -1;
selectedNode = -1;
float smallestDist = sqr(64);
for (size_t i = 0; i < dsq->game->getNumPaths(); i++)
{
if(dsq->game->getPath(i)->nodes.size() == 0) {
continue;
}
for (size_t n = dsq->game->getPath(i)->nodes.size(); n-- > 0; )
{
Vector v = dsq->game->getPath(i)->nodes[n].position - dsq->getGameCursorPosition();
float dist = v.getSquaredLength2D();
if (dist < smallestDist)
{
smallestDist = dist;
selectedIdx = i;
selectedNode = n;
}
}
}
}
break;
case ES_SCALING:
{
if (editingPath)
{
float factor = 1;
Vector add = Vector((dsq->getGameCursorPosition().x - cursorOffset.x)*factor,
(dsq->getGameCursorPosition().y - cursorOffset.y)*factor);
Vector sz = oldScale + add;
if (sz.x < 32)
sz.x = 32;
if (sz.y < 32)
sz.y = 32;
editingPath->rect.x1 = -sz.x/2;
editingPath->rect.x2 = sz.x/2;
editingPath->rect.y1 = -sz.y/2;
editingPath->rect.y2 = sz.y/2;
}
}
break;
case ES_MOVING:
dsq->game->getPath(selectedIdx)->nodes[selectedNode].position = dsq->getGameCursorPosition() + cursorOffset;
break;
case ES_ROTATING:
case ES_MAX:
break;
}
}
else if (editType == ET_ENTITIES)
{
switch(state)
{
case ES_MOVING:
if (editingEntity)
editingEntity->position = dsq->getGameCursorPosition() + cursorOffset;
break;
case ES_ROTATING:
{
if (editingEntity)
{
float add = (dsq->getGameCursorPosition().x - cursorOffset.x)/2.4f;
if (core->getCtrlState())
{
int a = (oldRotation.z + add)/45;
add = a * 45;
editingEntity->rotation.z = add;
}
else
{
editingEntity->rotation.z = oldRotation.z + add;
}
}
}
break;
case ES_SELECTING:
case ES_SCALING:
case ES_MAX:
break;
}
}
else if (editType == ET_ELEMENTS)
{
switch(state)
{
case ES_SELECTING:
{
float closest = sqr(800);
size_t i = 0;
for (i = 0; i < dsq->getNumElements(); i++)
{
Vector dist = dsq->getElement(i)->getFollowCameraPosition() - dsq->getGameCursorPosition();
float len = dist.getSquaredLength2D();
if (len < closest)
{
closest = len;
}
}
}
break;
case ES_MOVING:
updateSelectedElementPosition(dsq->getGameCursorPosition() - cursorOffset);
break;
case ES_ROTATING:
{
if (!selectedElements.empty())
{
float add = (dsq->getGameCursorPosition().x - cursorOffset.x)/2.4f;
if (core->getCtrlState())
{
int a = (oldRotation.z + add)/45;
add = a * 45;
dummy.rotation.z = add;
}
else
{
dummy.rotation.z = oldRotation.z + add;
}
}
else if (editingElement)
{
float add = (dsq->getGameCursorPosition().x - cursorOffset.x)/2.4f;
if (core->getCtrlState())
{
int a = (oldRotation.z + add)/45;
add = a * 45;
editingElement->rotation.z = add;
}
else
{
editingElement->rotation.z = oldRotation.z + add;
}
}
}
break;
case ES_SCALING:
{
bool right=false, middle=false, down=false, uni=false, repeatScale=false;
bool noSide = 0;
if (cursorOffset.x > oldPosition.x+10)
right = true;
else if (cursorOffset.x < oldPosition.x-10)
right = false;
else
noSide = true;
if (cursorOffset.y > oldPosition.y+10)
down = true;
else if (cursorOffset.y < oldPosition.y-10)
down = false;
else if (noSide)
middle = true;
Vector add = Vector((dsq->getGameCursorPosition().x - cursorOffset.x)/100.0f,
(dsq->getGameCursorPosition().y - cursorOffset.y)/100.0f);
{
if (!selectedElements.empty())
add.y = add.x;
else
{
if (core->getKeyState(KEY_C))
{
add.y = 0;
if (!right && !middle)
add.x *= -1;
}
else if (core->getKeyState(KEY_V))
{
add.x = 0;
if (!down && !middle)
add.y *= -1;
}
else
{
add.y = add.x;
uni = true;
}
repeatScale = core->getKeyState(KEY_X);
if(repeatScale)
add *= 0.1f;
}
}
if (!selectedElements.empty())
{
if (core->getCtrlState())
{
dummy.scale = Vector(1,1);
}
else
{
dummy.scale=oldScale + add;
if (dummy.scale.x < MIN_SIZE)
dummy.scale.x = MIN_SIZE;
if (dummy.scale.y < MIN_SIZE)
dummy.scale.y = MIN_SIZE;
}
for (size_t i = 0; i < selectedElements.size(); i++)
selectedElements[i]->refreshRepeatTextureToFill();
}
else if (editingElement)
{
Vector& editVec = repeatScale ? editingElement->repeatToFillScale : editingElement->scale;
if (core->getCtrlState())
{
editVec = Vector(1,1);
}
else
{
editVec = (repeatScale ? oldRepeatScale : oldScale) + add;
if (!uni && !repeatScale)
{
if (!middle)
{
Vector offsetChange = (add*Vector(editingElement->getWidth(), editingElement->getHeight()))*0.5f;
if (add.y == 0)
{
if (right)
editingElement->beforeScaleOffset = offsetChange;
else
editingElement->beforeScaleOffset = -offsetChange;
}
else
{
if (down)
editingElement->beforeScaleOffset = offsetChange;
else
editingElement->beforeScaleOffset = -offsetChange;
}
}
}
if (editVec.x < MIN_SIZE)
editVec.x = MIN_SIZE;
if (editVec.y < MIN_SIZE)
editVec.y = MIN_SIZE;
}
editingElement->refreshRepeatTextureToFill();
}
}
break;
case ES_MAX:
break;
}
}
}
}
void SceneEditor::nextEntityType()
{
if (editType == ET_ELEMENTS && state == ES_SELECTING)
{
if (editingElement || !selectedElements.empty())
{
enterMoveState();
updateSelectedElementPosition(Vector(1,0));
exitMoveState();
}
}
else if (editType == ET_SELECTENTITY)
{
nextEntityPage();
}
}
void SceneEditor::prevEntityType()
{
if (editType == ET_ELEMENTS && state == ES_SELECTING)
{
if (editingElement || !selectedElements.empty())
{
enterMoveState();
updateSelectedElementPosition(Vector(-1,0));
exitMoveState();
}
}
else if (editType == ET_SELECTENTITY)
{
prevEntityPage();
}
}
void SceneEditor::dumpObs()
{
TileVector tv;
unsigned char *data = new unsigned char[MAX_GRID * MAX_GRID * sizeof(unsigned)];
unsigned *ptr = (unsigned*)data;
for(tv.y = MAX_GRID - 1; ; --tv.y)
{
for(tv.x = 0; tv.x < MAX_GRID; ++tv.x)
*ptr++ = game->isObstructed(tv, OT_MASK_BLACK) ? 0xFF000000 : 0xFFFFFFFF;
if(tv.y == 0)
break;
}
std::string outfn = dsq->getUserDataFolder() + "/griddump-" + game->sceneName + ".tga";
tgaSaveRGBA(outfn.c_str(), MAX_GRID, MAX_GRID, data);
dsq->screenMessage("Saved grid image to " + outfn);
}