1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3 
4 This file is part of Aquaria.
5 
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15 See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 */
21 #include "../BBGE/MathFunctions.h"
22 #include "../ExternalLibs/glpng.h"
23 #include "../BBGE/Gradient.h"
24 #include "../BBGE/DebugFont.h"
25 
26 #include "Game.h"
27 #include "DSQ.h"
28 #include "Avatar.h"
29 #include "GridRender.h"
30 
31 
32 #ifdef AQUARIA_BUILD_SCENEEDITOR  // Through end of file
33 
34 
35 #ifdef BBGE_BUILD_WINDOWS
36 	#include <shellapi.h>
37 #endif
38 
39 const int minSelectionSize = 64;
40 PathRender *pathRender;
41 
42 
SelectedEntity()43 SelectedEntity::SelectedEntity()
44 {
45 	clear();
46 }
47 
setSelectEntity(const SelectedEntity & ent)48 void SelectedEntity::setSelectEntity(const SelectedEntity &ent)
49 {
50 	(*this) = ent;
51 }
52 
clear()53 void SelectedEntity::clear()
54 {
55 	typeListIndex = -1;
56 	prevScale = 1;
57 	nameBased = false;
58 	index = -1;
59 	name = "";
60 	prevGfx="";
61 }
62 
setIndex(int idx)63 void SelectedEntity::setIndex(int idx)
64 {
65 	clear();
66 	if (idx > -1)
67 	{
68 		nameBased = false;
69 		typeListIndex = idx;
70 		index = dsq->game->entityTypeList[idx].idx;
71 		prevGfx = dsq->game->entityTypeList[idx].prevGfx;
72 		prevScale = dsq->game->entityTypeList[idx].prevScale;
73 		name = dsq->game->entityTypeList[idx].name;
74 	}
75 }
76 
setName(const std::string & name,const std::string & prevGfx)77 void SelectedEntity::setName(const std::string &name, const std::string &prevGfx)
78 {
79 	clear();
80 	nameBased = true;
81 	this->name = name;
82 	this->prevGfx = prevGfx;
83 }
84 
getMapTemplateFilename()85 std::string getMapTemplateFilename()
86 {
87 	if (dsq->mod.isActive())
88 		return std::string(dsq->mod.getPath() + "maptemplates/" + dsq->game->sceneName + ".png");
89 	else
90 		return std::string("maptemplates/" + dsq->game->sceneName + ".png");
91 	return "";
92 }
93 
onRender()94 void WarpAreaRender::onRender()
95 {
96 #ifdef BBGE_BUILD_OPENGL
97 	for (int i = 0; i < dsq->game->warpAreas.size(); i++)
98 	{
99 		WarpArea *a = &dsq->game->warpAreas[i];
100 		glTranslatef(a->position.x, a->position.y,0);
101 
102 		if (a->warpAreaType == "Brown")
103 			glColor4f(0.5, 0.25, 0, alpha.getValue());
104 		else
105 		{
106 			switch (a->warpAreaType[0])
107 			{
108 			case 'B':
109 				glColor4f(0,0,1,alpha.getValue());
110 			break;
111 			case 'R':
112 				glColor4f(1,0,0,alpha.getValue());
113 			break;
114 			case 'G':
115 				glColor4f(0, 1, 0,alpha.getValue());
116 			break;
117 			case 'Y':
118 				glColor4f(1,1,0,alpha.getValue());
119 			break;
120 			case 'P':
121 				glColor4f(1,0,1,alpha.getValue());
122 			break;
123 			case 'O':
124 				glColor4f(1,0.5,0,alpha.getValue());
125 			break;
126 			}
127 		}
128 
129 		if (a->radius)
130 			drawCircle(a->radius);
131 		else
132 		{
133 			glBegin(GL_QUADS);
134 			{
135 				glVertex2f(-a->w,-a->h);
136 				glVertex2f(-a->w,a->h);
137 				glVertex2f(a->w,a->h);
138 				glVertex2f(a->w,-a->h);
139 			}
140 			glEnd();
141 		}
142 		glTranslatef(-a->position.x, -a->position.y,0);
143 	}
144 #endif
145 #ifdef BBGE_BUILD_DIRECTX
146 	for (int i = 0; i < dsq->game->warpAreas.size(); i++)
147 	{
148 		WarpArea *a = &dsq->game->warpAreas[i];
149 		core->translateMatrixStack(a->position.x, a->position.y);
150 		switch (a->warpAreaType[0])
151 		{
152 		case 'B':
153 			core->setColor(0, 0, 1, alpha.x);
154 		break;
155 		case 'R':
156 			core->setColor(1,0,0,alpha.x);
157 		break;
158 		case 'G':
159 			core->setColor(0,1,0,alpha.x);
160 		break;
161 		case 'Y':
162 			core->setColor(1,1,0,alpha.x);
163 		break;
164 		case 'P':
165 			core->setColor(1,0,1,alpha.x);
166 		break;
167 		}
168 		if (a->radius)
169 		{
170 		//	drawCircle(a->radius);
171 		}
172 		else
173 		{
174 			core->applyMatrixStackToWorld();
175 			core->blitD3D(0, a->w*2, a->h*2);
176 			/*
177 			glBegin(GL_QUADS);
178 			{
179 				glVertex2f(-a->w,-a->h);
180 				glVertex2f(-a->w,a->h);
181 				glVertex2f(a->w,a->h);
182 				glVertex2f(a->w,-a->h);
183 			}
184 			glEnd();
185 			*/
186 		}
187 		core->translateMatrixStack(-a->position.x, -a->position.y);
188 		//glTranslatef(-a->position.x, -a->position.y,0);
189 	}
190 #endif
191 }
192 
SceneEditor()193 SceneEditor::SceneEditor() : ActionMapper(), on(false)
194 {
195 	autoSaveFile = 0;
196 	selectedIdx = -1;
197 }
198 
setBackgroundGradient()199 void SceneEditor::setBackgroundGradient()
200 {
201 	float g1r, g1g, g1b;
202 	float g2r, g2g, g2b;
203 	std::string gtop = dsq->getUserInputString("Set Gradient Top (3 rgb, spaced)", "");
204 	std::string gbtm = dsq->getUserInputString("Set Gradient Bottom (3 rgb, spaced)", "");
205 	std::istringstream is1(gtop);
206 	is1 >> g1r >> g1g >> g1b;
207 	std::istringstream is2(gbtm);
208 	is2 >> g2r >> g2g >> g2b;
209 
210 	if (dsq->game->grad)
211 	{
212 		dsq->game->grad->makeVertical(Vector(g1r, g1g, g1b), Vector(g2r, g2g, g2b));
213 	}
214 }
215 
changeDepth()216 void SceneEditor::changeDepth()
217 {
218 	if (editingElement)
219 	{
220 		//editingElement->parallax = 0.9;
221 		//editingElement->followCamera = 0.001;
222 		editingElement->followCamera = 0.9;
223 		editingElement->cull = false;
224 	}
225 }
226 
updateSelectedElementPosition(Vector dist)227 void SceneEditor::updateSelectedElementPosition(Vector dist)
228 {
229 	if (state == ES_MOVING)
230 	{
231 		if (!selectedElements.empty())
232 		{
233 			dummy.position = oldPosition + dist;
234 		}
235 		else if (editingElement)
236 		{
237 			editingElement->position = oldPosition + dist;
238 		}
239 	}
240 }
241 
242 bool se_changedEntityType = false;
243 class SEQuad : public Quad
244 {
245 public:
246 	int entType;
247 	Quad *glow;
248 	DebugFont *label;
249 	float doubleClickTimer;
250 	std::string entName;
251 	bool mbld;
252 	SelectedEntity selectedEntity;
253 
SEQuad(std::string tex,Vector pos,int entType,std::string name)254 	SEQuad(std::string tex, Vector pos, int entType, std::string name) : Quad(tex, pos), entType(entType)
255 	{
256 		glow = new Quad;
257 		addChild(glow, PM_POINTER, RBP_ON);
258 		glow->setWidthHeight(48, 64);
259 		glow->alpha = 0;
260 		glow->setBlendType(RenderObject::BLEND_ADD);
261 		scale = Vector(0.5, 0.5);
262 		scale.interpolateTo(Vector(1,1), 0.5, 0, 0, 1);
263 
264 		label = new DebugFont();
265 		label->setFontSize(5);
266 		label->position = Vector(-32,12);
267 		label->setText(name);
268 		label->alpha = 0;
269 		addChild(label, PM_POINTER);
270 
271 		doubleClickTimer = 0;
272 		entName = name;
273 		mbld = false;
274 		selectedEntity.prevGfx = tex;
275 		selectedEntity.name = name;
276 	}
277 
onUpdate(float dt)278 	void onUpdate(float dt)
279 	{
280 		if (doubleClickTimer > 0)
281 			doubleClickTimer -= dt;
282 		Quad::onUpdate(dt);
283 		//if ()
284 
285 		if (dsq->game->sceneEditor.selectedEntity.name == selectedEntity.name
286 			|| (entType != -1 && dsq->game->sceneEditor.selectedEntity.typeListIndex == entType))
287 		{
288 			glow->alpha.interpolateTo(0.2, 0.2);
289 		}
290 		else
291 		{
292 			glow->alpha.interpolateTo(0, 0.1);
293 		}
294 		if ((core->mouse.position - position).isLength2DIn(32))
295 		{
296 			label->alpha.interpolateTo(1, 0.1);
297 			alpha.interpolateTo(1, 0.2);
298 			scale.interpolateTo(Vector(1.5, 1.5), 0.3);
299 
300 			if (!core->mouse.buttons.left && mbld)
301 			{
302 				mbld = false;
303 			}
304 			else if (core->mouse.buttons.left && !mbld)
305 			{
306 				mbld = true;
307 
308 				if (entType > -1)
309 					dsq->game->sceneEditor.selectedEntity.setIndex(entType);
310 				else
311 				{
312 					dsq->game->sceneEditor.selectedEntity.setName(selectedEntity.name, selectedEntity.prevGfx);
313 				}
314 				//se_changedEntityType = true;
315 				if (doubleClickTimer > 0)
316 				{
317 					doubleClickTimer = 0;
318 					if (!dsq->isFullscreen())
319 					{
320 						std::string fn = "scripts/entities/" + entName + ".lua";
321 						#ifdef BBGE_BUILD_WINDOWS
322 						debugLog("SHELL EXECUTE!");
323 						ShellExecute(dsq->hWnd, "open", fn.c_str(), NULL, NULL, SW_SHOWNORMAL);
324 						#endif
325 					}
326 				}
327 				else
328 				{
329 					doubleClickTimer = 0.4;
330 				}
331 			}
332 		}
333 		else
334 		{
335 			label->alpha.interpolateTo(0, 0.1);
336 			alpha.interpolateTo(0.7, 0.2);
337 			scale.interpolateTo(Vector(1.0, 1.0), 0.3);
338 			doubleClickTimer = 0;
339 		}
340 	}
341 };
342 
343 
344 std::vector<DebugButton*> mainMenu;
345 int execID = 0;
346 bool inMainMenu = false;
347 
348 std::vector<SEQuad*> qs;
349 DebugFont *se_label=0;
350 
351 
352 
buttonPress(DebugButton * db)353 void SceneEditorMenuReceiver::buttonPress(DebugButton *db)
354 {
355 	execID = db->buttonID;
356 
357 	switch(execID)
358 	{
359 	case 200:
360 	{
361 		if (inMainMenu)
362 		{
363 			dsq->game->sceneEditor.closeMainMenu();
364 		}
365 		else
366 		{
367 			dsq->game->sceneEditor.openMainMenu();
368 		}
369 		execID = 0;
370 	}
371 	break;
372 	}
373 }
374 
executeButtonID(int bid)375 void SceneEditor::executeButtonID(int bid)
376 {
377 	switch(bid)
378 	{
379 	case 100:
380 		loadSceneByName();
381 	break;
382 	case 101:
383 		reloadScene();
384 	break;
385 	case 102:
386 		saveScene();
387 	break;
388 	case 103:
389 		// regen collision
390 		dsq->game->reconstructGrid(true);
391 	break;
392 	case 104:
393 		generateLevel();
394 	break;
395 	case 105:
396 		skinLevel();
397 	break;
398 	case 106:
399 		editModeElements();
400 	break;
401 	case 107:
402 		editModeEntities();
403 	break;
404 	case 108:
405 		editModePaths();
406 	break;
407 	case 110:
408 	{
409 		std::ostringstream os;
410 		os << dsq->game->gradTop.x << " " << dsq->game->gradTop.y << " " << dsq->game->gradTop.z;
411 		std::string read;
412 		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());
413 
414 		if (!read.empty())
415 		{
416 			std::istringstream is(read);
417 			is >> dsq->game->gradTop.x >> dsq->game->gradTop.y >> dsq->game->gradTop.z;
418 		}
419 
420 		std::ostringstream os2;
421 		os2 << dsq->game->gradBtm.x << " " << dsq->game->gradBtm.y << " " << dsq->game->gradBtm.z;
422 		read = dsq->getUserInputString("Enter Spaced R G B 0-1 Values for the Bottom Color (e.g. 0 0 0 for black)", os2.str());
423 
424 		if (!read.empty())
425 		{
426 			std::istringstream is2(read);
427 			is2 >> dsq->game->gradBtm.x >> dsq->game->gradBtm.y >> dsq->game->gradBtm.z;
428 		}
429 
430 		dsq->game->createGradient();
431 	}
432 	break;
433 	case 111:
434 	{
435 		std::string track = dsq->getUserInputString("Set Background Music Track", dsq->game->saveMusic);
436 		if (!track.empty())
437 		{
438 			dsq->game->setMusicToPlay(track);
439 			dsq->game->saveMusic = track;
440 			dsq->game->updateMusic();
441 		}
442 	}
443 	break;
444 	case 112:
445 	{
446 		selectEntityFromGroups();
447 	}
448 	break;
449 	case 113:
450 		dsq->game->toggleGridRender();
451 	break;
452 	case 114:
453 		dsq->screenshot();
454 	break;
455 	case 115:
456 	{
457 		dsq->returnToScene = dsq->game->sceneName;
458 		core->enqueueJumpState("AnimationEditor");
459 	}
460 	break;
461 	case 120:
462 	{
463 		dsq->returnToScene = dsq->game->sceneName;
464 		core->enqueueJumpState("ParticleEditor");
465 	}
466 	break;
467 	case 116:
468 		regenLevel();
469 	break;
470 	case 130:
471 		dsq->mod.recache();
472 	break;
473 	}
474 }
475 
addMainMenuItem(const std::string & label,int bid)476 void SceneEditor::addMainMenuItem(const std::string &label, int bid)
477 {
478 	DebugButton *b = new DebugButton(bid, &menuReceiver, 350);
479 	b->label->setText(label);
480 	b->followCamera = 1;
481 	b->position.x = btnMenu->position.x + 20;
482 	b->position.y = btnMenu->position.y + (mainMenu.size()+1)*22;
483 	dsq->game->addRenderObject(b, LR_HUD);
484 	mainMenu.push_back(b);
485 }
486 
openMainMenu()487 void SceneEditor::openMainMenu()
488 {
489 	/*
490 	core->clearDebugMenu();
491 	core->addDebugMenuItem("", bid);
492 	core->doModalDebugMenu();
493 	*/
494 
495 	if (core->getNestedMains()>1)
496 	{
497 		return;
498 	}
499 
500 	inMainMenu = true;
501 
502 	if (placer)
503 		placer->renderQuad = 0;
504 
505 	execID = -1;
506 	debugLog("Open Main Menu");
507 
508 	mainMenu.clear();
509 
510 	while (core->mouse.buttons.left)
511 	{
512 		core->main(FRAME_TIME);
513 	}
514 
515 	addMainMenuItem("LOAD LEVEL...                    (SHIFT-F1)",			100);
516 	addMainMenuItem("RELOAD LEVEL                           (F1)",			101);
517 	addMainMenuItem("SAVE LEVEL                             (F2)",			102);
518 	addMainMenuItem("EDIT TILES                             (F5)",			106);
519 	addMainMenuItem("EDIT ENTITIES                          (F6)",			107);
520 	addMainMenuItem("EDIT NODES                             (F7)",			108);
521 	addMainMenuItem("REGEN COLLISIONS                    (ALT-R)",			103);
522 	addMainMenuItem("RECACHE TEXTURES					(CTRL-R)",			130);
523 //	addMainMenuItem("REFRESH DATAFILES					   (F11)",			117);
524 	addMainMenuItem("REGEN ROCK FROM MAPTEMPLATE       (F11+F12)",			116);
525 	/*
526 	addMainMenuItem("RE-TEMPLATE                           (F11)",			104);
527 	addMainMenuItem("RE-SKIN                               (F12)",			105);
528 	*/
529 	addMainMenuItem("SET BG GRADIENT",										110);
530 	addMainMenuItem("SET MUSIC",											111);
531 	addMainMenuItem("ENTITY GROUPS                      (CTRL-E)",			112);
532 	if (dsq->game->gridRender)
533 		addMainMenuItem(std::string("TOGGLE TILE COLLISION RENDER ") + ((dsq->game->gridRender->alpha!=0) ? "OFF" : "ON ") + std::string("       (F9)"),			113);
534 	addMainMenuItem("SCREENSHOT                                 ",	        114);
535 
536 
537 
538 	addMainMenuItem("PARTICLE VIEWER                            ",	        120);
539 	addMainMenuItem("ANIMATION EDITOR                           ",	        115);
540 
541 	while (1 && !core->getKeyState(KEY_TAB))
542 	{
543 		core->main(FRAME_TIME);
544 		if (execID != -1)
545 			break;
546 	}
547 
548 	closeMainMenu();
549 
550 	executeButtonID(execID);
551 }
552 
closeMainMenu()553 void SceneEditor::closeMainMenu()
554 {
555 	inMainMenu = false;
556 	for (int i = 0; i < mainMenu.size(); i++)
557 	{
558 		mainMenu[i]->alpha = 0;
559 		mainMenu[i]->safeKill();
560 	}
561 	mainMenu.clear();
562 
563 
564 	if (placer)
565 		placer->renderQuad = 1;
566 
567 	core->quitNestedMain();
568 }
569 
init()570 void SceneEditor::init()
571 {
572 	entityPageNum = 0;
573 	multiSelecting = false;
574 	selectedElements.clear();
575 	autoSaveTimer = 0;
576 	skinMinX = skinMinY = skinMaxX = skinMaxY = -1;
577 	editingElement = 0;
578 	editingEntity = 0;
579 	pathRender = new PathRender();
580 	core->getTopStateData()->addRenderObject(pathRender, LR_DEBUG_TEXT);
581 	pathRender->alpha = 0;
582 
583 	editType = ET_ELEMENTS;
584 	state = ES_SELECTING;
585 	drawingWarpArea = 'N';
586 
587 	btnMenu = new DebugButton(200, &menuReceiver, 700);
588 	btnMenu->position = Vector(20, 20);
589 	btnMenu->label->setText("Menu");
590 	btnMenu->followCamera = 1;
591 	btnMenu->alpha = 0;
592 	//btnMenu->event.set(MakeFunctionEvent(SceneEditor, openMainMenu));
593 	dsq->game->addRenderObject(btnMenu, LR_HUD);
594 
595 	selectedEntityType = 0;
596 	zoom = Vector(0.2,0.2);
597 	drawingBox = false;
598 	bgLayer = 5;
599 	text = new DebugFont();
600 	text->setFontSize(6);
601 
602 	text->followCamera = 1;
603 	text->position = Vector(125,20,4.5);
604 	//text->setAlign(ALIGN_CENTER);
605 	dsq->game->addRenderObject(text, LR_HUD);
606 	text->alpha = 0;
607 	selectedVariation = -1;
608 
609 	boxPromo = new Quad;
610 	boxPromo->color = 0;
611 	boxPromo->alpha =0;
612 	boxPromo->cull = false;
613 	dsq->game->addRenderObject(boxPromo, LR_HUD);
614 	on = false;
615 
616 	//addAction(MakeFunctionEvent(SceneEditor, addSpringPlant), KEY_K, 0);
617 
618 	addAction(MakeFunctionEvent(SceneEditor, loadScene), KEY_F1, 0);
619 	addAction(MakeFunctionEvent(SceneEditor, saveScene), KEY_F2, 0);
620 
621 	// removed in fc3
622 	//addAction(MakeFunctionEvent(SceneEditor, setGroup), KEY_G, 0);
623 
624 	addAction(MakeFunctionEvent(SceneEditor, moveToBack), KEY_Z, 0);
625 	addAction(MakeFunctionEvent(SceneEditor, moveToFront), KEY_X, 0);
626 
627 	addAction(MakeFunctionEvent(SceneEditor, toggleWarpAreaRender), KEY_F4, 0);
628 
629 	addAction(MakeFunctionEvent(SceneEditor, editModeElements), KEY_F5, 0);
630 	addAction(MakeFunctionEvent(SceneEditor, editModeEntities), KEY_F6, 0);
631 	addAction(MakeFunctionEvent(SceneEditor, editModePaths), KEY_F7, 0);
632 
633 	addAction(MakeFunctionEvent(SceneEditor, mouseButtonLeft), MOUSE_BUTTON_LEFT, 1);
634 	addAction(MakeFunctionEvent(SceneEditor, mouseButtonRight), MOUSE_BUTTON_RIGHT, 1);
635 	addAction(MakeFunctionEvent(SceneEditor, mouseButtonLeftUp), MOUSE_BUTTON_LEFT, 0);
636 	addAction(MakeFunctionEvent(SceneEditor, mouseButtonRightUp), MOUSE_BUTTON_RIGHT, 0);
637 
638 	addAction(MakeFunctionEvent(SceneEditor, alignHorz), KEY_C, 1);
639 	addAction(MakeFunctionEvent(SceneEditor, alignVert), KEY_V, 1);
640 
641 
642 
643 /*
644 	addAction(MakeFunctionEvent(SceneEditor, placeEntity), KEY_U, 0);
645 	addAction(MakeFunctionEvent(SceneEditor, removeEntity), KEY_I, 0);
646 	*/
647 	//addAction(MakeFunctionEvent(SceneEditor, changeDepth), KEY_N, 0);
648 
649 	addAction(MakeFunctionEvent(SceneEditor, placeElement), KEY_SPACE, 1);
650 
651 	addAction(MakeFunctionEvent(SceneEditor, enterName), KEY_N, 0);
652 	addAction(MakeFunctionEvent(SceneEditor, changeShape), KEY_Y, 0);
653 	addAction(MakeFunctionEvent(SceneEditor, reversePath), KEY_T, 0);
654 
655 
656 	addAction(MakeFunctionEvent(SceneEditor, moveLayer), KEY_F10, 0);
657 
658 	addAction(MakeFunctionEvent(SceneEditor, nextElement), KEY_R, 1);
659 	addAction(MakeFunctionEvent(SceneEditor, prevElement), KEY_E, 1);
660 	addAction(MakeFunctionEvent(SceneEditor, selectZero), KEY_HOME, 1);
661 	addAction(MakeFunctionEvent(SceneEditor, selectEnd), KEY_END, 1);
662 
663 	addAction(MakeFunctionEvent(SceneEditor, placeAvatar), KEY_P, 0);
664 	addAction(MakeFunctionEvent(SceneEditor, deleteSelected), KEY_DELETE, 0);
665 	addAction(MakeFunctionEvent(SceneEditor, deleteSelected), KEY_BACKSPACE, 0);
666 
667 	addAction(MakeFunctionEvent(SceneEditor, generateLevel), KEY_F11, 0);
668 	addAction(MakeFunctionEvent(SceneEditor, skinLevel), KEY_F12, 0);
669 
670 	//addAction(MakeFunctionEvent(SceneEditor, regenLevel), KEY_F12, 0);
671 
672 	addAction(MakeFunctionEvent(SceneEditor, nextEntityType), KEY_RIGHT, 0);
673 	addAction(MakeFunctionEvent(SceneEditor, prevEntityType), KEY_LEFT, 0);
674 	addAction(MakeFunctionEvent(SceneEditor, down), KEY_DOWN, 0);
675 	addAction(MakeFunctionEvent(SceneEditor, up), KEY_UP, 0);
676 
677 
678 	addAction(MakeFunctionEvent(SceneEditor, flipElementHorz), KEY_T, 0);
679 	addAction(MakeFunctionEvent(SceneEditor, flipElementVert), KEY_Y, 0);
680 
681 	addAction(MakeFunctionEvent(SceneEditor, toggleElementSolid), KEY_O, 0);
682 	addAction(MakeFunctionEvent(SceneEditor, toggleElementHurt), KEY_I, 0);
683 	addAction(MakeFunctionEvent(SceneEditor, toggleElementRepeat), KEY_L, 0);
684 
685 	addAction(MakeFunctionEvent(SceneEditor, setGridPattern0), KEY_NUMPAD0, 0);
686 	addAction(MakeFunctionEvent(SceneEditor, setGridPattern1), KEY_NUMPAD1, 0);
687 	addAction(MakeFunctionEvent(SceneEditor, setGridPattern2), KEY_NUMPAD2, 0);
688 	addAction(MakeFunctionEvent(SceneEditor, setGridPattern3), KEY_NUMPAD3, 0);
689 	addAction(MakeFunctionEvent(SceneEditor, setGridPattern4), KEY_NUMPAD4, 0);
690 	addAction(MakeFunctionEvent(SceneEditor, setGridPattern5), KEY_NUMPAD5, 0);
691 	addAction(MakeFunctionEvent(SceneEditor, setGridPattern6), KEY_NUMPAD6, 0);
692 	addAction(MakeFunctionEvent(SceneEditor, setGridPattern7), KEY_NUMPAD7, 0);
693 	addAction(MakeFunctionEvent(SceneEditor, setGridPattern8), KEY_NUMPAD8, 0);
694 	addAction(MakeFunctionEvent(SceneEditor, setGridPattern9), KEY_NUMPAD9, 0);
695 
696 
697 	addAction(MakeFunctionEvent(SceneEditor, createAquarian), KEY_F, 0);
698 
699 	addAction(MakeFunctionEvent(SceneEditor, dumpObs), KEY_F8, 0);
700 
701 
702 	/*
703 	// OLD CRAP
704 	addAction(MakeFunctionEvent(SceneEditor, rotateElement), KEY_MULTIPLY, 0);
705 	addAction(MakeFunctionEvent(SceneEditor, rotateElement2), KEY_DIVIDE, 0);
706 	addAction(MakeFunctionEvent(SceneEditor, scaleElementUp), KEY_NUMPAD7, 0);
707 	addAction(MakeFunctionEvent(SceneEditor, scaleElementDown), KEY_NUMPAD1, 0);
708 	addAction(MakeFunctionEvent(SceneEditor, scaleElement1), KEY_NUMPAD0, 0);
709 	addAction(MakeFunctionEvent(SceneEditor, nextVariation), KEY_UP, 0);
710 	addAction(MakeFunctionEvent(SceneEditor, prevVariation), KEY_DOWN, 0);
711 	*/
712 
713 
714 	addAction(ACTION_ZOOMIN,		KEY_PGUP);
715 	addAction(ACTION_ZOOMOUT,		KEY_PGDN);
716 
717 	addAction(ACTION_CAMLEFT,		KEY_A);
718 	addAction(ACTION_CAMRIGHT,		KEY_D);
719 	addAction(ACTION_CAMUP,			KEY_W);
720 	addAction(ACTION_CAMDOWN,		KEY_S);
721 
722 	addAction(ACTION_BGLAYEREND,	KEY_0);
723 
724 	addAction(ACTION_BGLAYER1,		KEY_1);
725 	addAction(ACTION_BGLAYER2,		KEY_2);
726 	addAction(ACTION_BGLAYER3,		KEY_3);
727 	addAction(ACTION_BGLAYER4,		KEY_4);
728 	addAction(ACTION_BGLAYER5,		KEY_5);
729 	addAction(ACTION_BGLAYER6,		KEY_6);
730 	addAction(ACTION_BGLAYER7,		KEY_7);
731 	addAction(ACTION_BGLAYER8,		KEY_8);
732 	addAction(ACTION_BGLAYER9,		KEY_9);
733 
734 	addAction(ACTION_BGLAYER10,		KEY_B);
735 	addAction(ACTION_BGLAYER11,		KEY_N);
736 	addAction(ACTION_BGLAYER12,		KEY_M);
737 
738 	addAction(ACTION_BGLAYER13,		KEY_J);
739 
740 	addAction(ACTION_BGLAYER14,		KEY_COMMA);
741 	addAction(ACTION_BGLAYER15,		KEY_PERIOD);
742 	addAction(ACTION_BGLAYER16,		KEY_SLASH);
743 	addAction(ACTION_BGLAYER16,		KEY_MINUS); // HACK: for german keyboard layout -- FG
744 
745 	addAction(ACTION_MULTISELECT,	KEY_LALT);
746 
747 	placer = new Quad;
748 	dsq->game->addRenderObject(placer, LR_HUD);
749 	placer->alpha = 0;
750 	curElement = 0;
751 	selectedEntity.clear();
752 	nextElement();
753 
754 
755 	if (curElement < dsq->game->elementTemplates.size())
756 	{
757 		placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
758 		placer->scale = Vector(1,1);
759 	}
760 	else
761 	{
762 		placer->setTexture("missingimage");
763 	}
764 
765 	warpAreaRender = new WarpAreaRender;
766 	warpAreaRender->alpha = 0;
767 	warpAreaRender->toggleCull(false);
768 	dsq->game->addRenderObject(warpAreaRender, LR_HUD);
769 
770 	updateText();
771 
772 	doPrevElement();
773 }
774 
alignHorz()775 void SceneEditor::alignHorz()
776 {
777 	if (core->getShiftState()) return;
778 	if (editType == ET_ELEMENTS && state == ES_SELECTING && editingElement)
779 	{
780 		TileVector t(editingElement->position);
781 		int startOn = dsq->game->getGrid(t);
782 		TileVector c=t;
783 		bool found = false;
784 		int dir = -1;
785 		for (int i = 1; i < 5; i++)
786 		{
787 			// search down
788 			c.y = t.y + i;
789 			if (dsq->game->getGrid(c) != startOn)
790 			{
791 				found = true;
792 				dir = 1;
793 				break;
794 			}
795 			c.y = t.y - i;
796 			if (dsq->game->getGrid(c) != startOn)
797 			{
798 				found = true;
799 				dir = -1;
800 				break;
801 			}
802 		}
803 		if (found)
804 		{
805 			editingElement->position.y = c.worldVector().y + (editingElement->texture->getPixelHeight()/2)*(-dir);
806 		}
807 	}
808 }
809 
alignVert()810 void SceneEditor::alignVert()
811 {
812 	if (core->getShiftState()) return;
813 	if (editType == ET_ELEMENTS && state == ES_SELECTING && editingElement)
814 	{
815 		TileVector t(editingElement->position);
816 		int startOn = dsq->game->getGrid(t);
817 		TileVector c=t;
818 		bool found = false;
819 		int dir = -1;
820 		for (int i = 1; i < 5; i++)
821 		{
822 			// search down
823 			c.x = t.x + i;
824 			if (dsq->game->getGrid(c) != startOn)
825 			{
826 				found = true;
827 				dir = 1;
828 				break;
829 			}
830 			c.x = t.x - i;
831 			if (dsq->game->getGrid(c) != startOn)
832 			{
833 				found = true;
834 				dir = -1;
835 				break;
836 			}
837 		}
838 		if (found)
839 		{
840 			editingElement->position.x = c.worldVector().x + (editingElement->texture->getPixelWidth()/2)*(-dir);
841 		}
842 	}
843 }
844 
createAquarian()845 void SceneEditor::createAquarian()
846 {
847 	//if (dsq->mod.isActive())	return;
848 	static bool inCreateAqurian = false;
849 	if (inCreateAqurian) return;
850 	//if (dsq->game->isPaused()) return;
851 	inCreateAqurian = true;
852 	std::string t = dsq->getUserInputString("Enter Aquarian:", "");
853 	stringToUpper(t);
854 	Vector startPos = dsq->getGameCursorPosition();
855 	for (int i = 0; i < t.size(); i++)
856 	{
857 		int v = 0;
858 		if (t[i] >= 'A' && t[i] <= 'Z')
859 		{
860 			v = 1024+int(t[i] - 'A');
861 		}
862 		if (t[i] == '.' || t[i] == ' ')
863 		{
864 			v = 1024+26;
865 		}
866 		//ElementTemplate et = dsq->game->getElementTemplateForLetter(v);
867 		dsq->game->createElement(v, startPos + Vector(64*i,0), this->bgLayer);
868 	}
869 	inCreateAqurian = false;
870 }
871 
getSelectedPath()872 Path *SceneEditor::getSelectedPath()
873 {
874 	if (selectedIdx >= 0 && selectedIdx < dsq->game->getNumPaths())
875 	{
876 		return dsq->game->getPath(selectedIdx);
877 	}
878 	return 0;
879 }
880 
enterName()881 void SceneEditor::enterName()
882 {
883 	if (editType == ET_PATHS)
884 	{
885 		Path *p = getSelectedPath();
886 		if (p)
887 		{
888 			std::string newname = dsq->getUserInputString("PathName", p->name);
889 			bool changed = newname != p->name;
890 			p->name = newname;
891 			if (changed)
892 			{
893 				p->refreshScript();
894 				p->init();
895 			}
896 		}
897 	}
898 }
899 
changeShape()900 void SceneEditor::changeShape()
901 {
902 	if (editType == ET_PATHS)
903 	{
904 		Path *p = getSelectedPath();
905 		if (p)
906 		{
907 			switch (p->pathShape)
908 			{
909 			case PATHSHAPE_RECT:
910 				p->pathShape = PATHSHAPE_CIRCLE;
911 			break;
912 			case PATHSHAPE_CIRCLE:
913 				p->pathShape = PATHSHAPE_RECT;
914 			break;
915 			}
916 		}
917 	}
918 }
919 
reversePath()920 void SceneEditor::reversePath()
921 {
922 	if (editType == ET_PATHS)
923 	{
924 		Path *p = getSelectedPath();
925 		if (p)
926 		{
927 			p->reverseNodes();
928 		}
929 	}
930 }
931 
toggleWarpAreaRender()932 void SceneEditor::toggleWarpAreaRender()
933 {
934 	if (warpAreaRender->alpha.x == 0)
935 		warpAreaRender->alpha.x = 0.5;
936 	else if (warpAreaRender->alpha.x >= 0.5f)
937 		warpAreaRender->alpha.x = 0;
938 		//warpAreaRender->alpha.interpolateTo(1, 0.2);
939 }
940 
941 
setGridPattern(int gi)942 void SceneEditor::setGridPattern(int gi)
943 {
944     if (selectedElements.size())
945         for (int i = 0; i < selectedElements.size(); ++i)
946             selectedElements[i]->setElementEffectByIndex(gi);
947     else if (editingElement)
948         editingElement->setElementEffectByIndex(gi);
949 }
950 
setGridPattern0()951 void SceneEditor::setGridPattern0()
952 {	setGridPattern(-1); }
953 
setGridPattern1()954 void SceneEditor::setGridPattern1()
955 {	setGridPattern(0);	}
956 
setGridPattern2()957 void SceneEditor::setGridPattern2()
958 {	setGridPattern(1);	}
959 
setGridPattern3()960 void SceneEditor::setGridPattern3()
961 {	setGridPattern(2);	}
962 
setGridPattern4()963 void SceneEditor::setGridPattern4()
964 {	setGridPattern(3);	}
965 
setGridPattern5()966 void SceneEditor::setGridPattern5()
967 {	setGridPattern(4);	}
968 
setGridPattern6()969 void SceneEditor::setGridPattern6()
970 {	setGridPattern(5);	}
971 
setGridPattern7()972 void SceneEditor::setGridPattern7()
973 {	setGridPattern(6);	}
974 
setGridPattern8()975 void SceneEditor::setGridPattern8()
976 {	setGridPattern(7);	}
977 
setGridPattern9()978 void SceneEditor::setGridPattern9()
979 {	setGridPattern(8);	}
980 
moveToFront()981 void SceneEditor::moveToFront()
982 {
983 	if (editingElement && !core->getShiftState())
984 	{
985 		std::vector<Element*> copy = dsq->getElementsCopy();
986 		dsq->clearElements();
987 
988 		//  move to the foreground ... this means that the editing element should be last in the list (Added last)
989 		for (int i = 0; i < copy.size(); i++)
990 		{
991 			if (copy[i] != editingElement)
992 				dsq->addElement(copy[i]);
993 		}
994 		dsq->addElement(editingElement);
995 
996 		editingElement->moveToFront();
997 	}
998 }
999 
moveToBack()1000 void SceneEditor::moveToBack()
1001 {
1002 	if (editingElement && !core->getShiftState())
1003 	{
1004 		std::vector<Element*> copy = dsq->getElementsCopy();
1005 		dsq->clearElements();
1006 
1007 		//  move to the background ... this means that the editing element should be first in the list (Added first)
1008 		dsq->addElement(editingElement);
1009 		for (int i = 0; i < copy.size(); i++)
1010 		{
1011 			if (copy[i] != editingElement)
1012 				dsq->addElement(copy[i]);
1013 		}
1014 
1015 		editingElement->moveToBack();
1016 	}
1017 }
1018 
editModeElements()1019 void SceneEditor::editModeElements()
1020 {
1021 	selectedIdx = -1;
1022 	editType = ET_ELEMENTS;
1023 	if (curElement < dsq->game->elementTemplates.size())
1024 	{
1025 		placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
1026 		placer->scale = Vector(1,1);
1027 	}
1028 	placer->alpha = 0.5;
1029 	pathRender->alpha = 0;
1030 	editingEntity = NULL;
1031 	editingPath = NULL;
1032 }
1033 
editModeEntities()1034 void SceneEditor::editModeEntities()
1035 {
1036 	selectedIdx = -1;
1037 	//HACK: methinks target is useless now
1038 	//target->alpha.interpolateTo(0, 0.5);
1039 	editType = ET_ENTITIES;
1040 
1041 	//dsq->game->entityTypeList[curEntity].prevGfx
1042 	placer->setTexture(selectedEntity.prevGfx);
1043 	placer->alpha = 0.5;
1044 	pathRender->alpha = 0;
1045 	selectedElements.clear();
1046 	editingElement = NULL;
1047 	editingPath = NULL;
1048 }
1049 
editModePaths()1050 void SceneEditor::editModePaths()
1051 {
1052 	selectedIdx = -1;
1053 	editType = ET_PATHS;
1054 	placer->alpha = 0;
1055 	pathRender->alpha = 0.5;
1056 	selectedElements.clear();
1057 	editingElement = NULL;
1058 	editingEntity = NULL;
1059 }
1060 
getElementAtCursor()1061 Element *SceneEditor::getElementAtCursor()
1062 {
1063 	int minDist = -1;
1064 	Element *selected = 0;
1065 	for (Element *e = dsq->getFirstElementOnLayer(this->bgLayer); e; e = e->bgLayerNext)
1066 	{
1067 		if (e->life == 1)
1068 		{
1069 			if (e->isCoordinateInside(dsq->getGameCursorPosition()))//, minSelectionSize
1070 			{
1071 				Vector v = dsq->getGameCursorPosition() - e->position;
1072 				int dist = v.getSquaredLength2D();
1073 				if (dist < minDist || minDist == -1)
1074 				{
1075 					minDist = dist;
1076 					selected = e;
1077 				}
1078 			}
1079 		}
1080 	}
1081 	return selected;
1082 }
1083 
getEntityAtCursor()1084 Entity *SceneEditor::getEntityAtCursor()
1085 {
1086 	int minDist = -1;
1087 	Entity *selected = 0;
1088 	FOR_ENTITIES(i)
1089 	{
1090 		Entity *e = *i;
1091 		if (e->life == 1)
1092 		{
1093 			if (e->isCoordinateInside(dsq->getGameCursorPosition(), minSelectionSize))
1094 			{
1095 				Vector v = dsq->getGameCursorPosition() - e->position;
1096 				int dist = v.getSquaredLength2D();
1097 				if (dist < minDist || minDist == -1)
1098 				{
1099 					minDist = dist;
1100 					selected = e;
1101 				}
1102 			}
1103 		}
1104 	}
1105 	return selected;
1106 }
1107 
deleteSelected()1108 void SceneEditor::deleteSelected()
1109 {
1110 	if (state != ES_SELECTING) return;
1111 	if (editType == ET_ELEMENTS)
1112 	{
1113 		if (selectedElements.size()>0)
1114 		{
1115 			for (int i = 0; i < selectedElements.size(); i++)
1116 			{
1117 				selectedElements[i]->safeKill();
1118 				dsq->removeElement(selectedElements[i]);
1119 			}
1120 			selectedElements.clear();
1121 			dsq->game->reconstructGrid();
1122 		}
1123 		else if (editingElement)
1124 		{
1125 			editingElement->safeKill();
1126 			dsq->removeElement(editingElement);
1127 			editingElement = 0;
1128 			dsq->game->reconstructGrid();
1129 		}
1130 	}
1131 	else if (editType == ET_ENTITIES)
1132 	{
1133 		if (editingEntity)
1134 		{
1135 			if (editingEntity->getEntityType() != ET_AVATAR)
1136 			{
1137 				dsq->game->removeEntity(editingEntity);
1138 				editingEntity = 0;
1139 			}
1140 		}
1141 	}
1142 	else if (editType == ET_PATHS)
1143 	{
1144 		if (core->getShiftState())
1145 		{
1146 			dsq->game->removePath(selectedIdx);
1147 		}
1148 		else
1149 		{
1150 			if (selectedIdx != -1)
1151 			{
1152 				Path *p = dsq->game->getPath(selectedIdx);
1153 				if (p->nodes.size() == 1)
1154 				{
1155 					dsq->game->removePath(selectedIdx);
1156 					selectedIdx = -1;
1157 				}
1158 				else
1159 					p->removeNode(selectedNode);
1160 				/*
1161 				if (p->nodes.size() > 1)
1162 					p->nodes.resize(p->nodes.size()-1);
1163 				*/
1164 				//selectedIdx = -1;
1165 			}
1166 		}
1167 	}
1168 }
1169 
updateSaveFileEnemyPosition(Entity * ent)1170 void SceneEditor::updateSaveFileEnemyPosition(Entity *ent)
1171 {
1172 	XMLElement *exml = dsq->game->saveFile->FirstChildElement("Enemy");
1173 	while (exml)
1174 	{
1175 		int x = atoi(exml->Attribute("x"));
1176 		int y = atoi(exml->Attribute("y"));
1177 		if (ent->startPos.x == x && ent->startPos.y == y)
1178 		{
1179 			ent->startPos = Vector(int(ent->position.x), int(ent->position.y));
1180 			exml->SetAttribute("x", int(ent->startPos.x));
1181 			exml->SetAttribute("y", int(ent->startPos.y));
1182 			return;
1183 		}
1184 		exml = exml->NextSiblingElement("Enemy");
1185 	}
1186 	exml = dsq->game->saveFile->FirstChildElement("Entity");
1187 	while (exml)
1188 	{
1189 		int x = atoi(exml->Attribute("x"));
1190 		int y = atoi(exml->Attribute("y"));
1191 		if (ent->startPos.x == x && ent->startPos.y == y)
1192 		{
1193 			ent->startPos = Vector(int(ent->position.x), int(ent->position.y));
1194 			exml->SetAttribute("x", int(ent->startPos.x));
1195 			exml->SetAttribute("y", int(ent->startPos.y));
1196 			return;
1197 		}
1198 		exml = exml->NextSiblingElement("Entity");
1199 	}
1200 
1201 }
1202 
checkForRebuild()1203 void SceneEditor::checkForRebuild()
1204 {
1205 	if (editType == ET_ELEMENTS && state != ES_SELECTING && !selectedElements.empty())
1206 	{
1207 		bool rebuild = false;
1208 		for (int i = 0; i < selectedElements.size(); i++)
1209 		{
1210 			if (selectedElements[i]->elementFlag == EF_SOLID || selectedElements[i]->elementFlag == EF_HURT)
1211 			{
1212 				rebuild = true;
1213 				break;
1214 			}
1215 		}
1216 		if (rebuild)
1217 		{
1218 			dsq->game->reconstructGrid();
1219 		}
1220 	}
1221 	else if (editType == ET_ELEMENTS && state != ES_SELECTING && editingElement != 0 && (editingElement->elementFlag == EF_SOLID || editingElement->elementFlag == EF_HURT))
1222 	{
1223 		dsq->game->reconstructGrid();
1224 	}
1225 }
1226 
exitMoveState()1227 void SceneEditor::exitMoveState()
1228 {
1229 	if (!selectedElements.empty())
1230 	{
1231 		for (int i = 0; i < selectedElements.size(); i++)
1232 		{
1233 			selectedElements[i]->position = selectedElements[i]->getWorldPosition();
1234 			dummy.removeChild(selectedElements[i]);
1235 		}
1236 		core->removeRenderObject(&dummy, Core::DO_NOT_DESTROY_RENDER_OBJECT);
1237 	}
1238 	checkForRebuild();
1239 	state = ES_SELECTING;
1240 }
1241 
enterMoveState()1242 void SceneEditor::enterMoveState()
1243 {
1244 	if (state != ES_SELECTING) return;
1245 	state = ES_MOVING;
1246 	if (editType == ET_ELEMENTS)
1247 	{
1248 		if (!selectedElements.empty())
1249 		{
1250 			dummy.rotation = Vector(0,0,0);
1251 			cursorOffset = dsq->getGameCursorPosition();
1252 			groupCenter = getSelectedElementsCenter();
1253 			for (int i = 0; i < selectedElements.size(); i++)
1254 			{
1255 				selectedElements[i]->position -= groupCenter;
1256 				dummy.addChild(selectedElements[i], PM_NONE);
1257 			}
1258 			core->addRenderObject(&dummy, selectedElements[0]->layer);
1259 			dummy.cull = false;
1260 			dummy.position = groupCenter;
1261 			oldPosition = dummy.position;
1262 			dummy.scale = Vector(1,1,1);
1263 		}
1264 		else if (editingElement)
1265 		{
1266 			oldPosition = editingElement->position;
1267 			cursorOffset = dsq->getGameCursorPosition();
1268 		}
1269 	}
1270 	else if (editType == ET_ENTITIES)
1271 	{
1272 		oldPosition = editingEntity->position;
1273 		cursorOffset = editingEntity->position - dsq->getGameCursorPosition();
1274 	}
1275 	else if (editType == ET_PATHS)
1276 	{
1277 		oldPosition = dsq->game->getPath(selectedIdx)->nodes[selectedNode].position;
1278 		cursorOffset = oldPosition - dsq->getGameCursorPosition();
1279 	}
1280 }
1281 
enterRotateState()1282 void SceneEditor::enterRotateState()
1283 {
1284 	if (state != ES_SELECTING) return;
1285 	if (editType == ET_ENTITIES)
1286 	{
1287 		state = ES_ROTATING;
1288 		oldRotation = editingEntity->rotation;
1289 		oldPosition = editingEntity->position;
1290 		cursorOffset = dsq->getGameCursorPosition();
1291 	}
1292 	if (editType == ET_ELEMENTS)
1293 	{
1294 		if (!selectedElements.empty())
1295 		{
1296 			state = ES_ROTATING;
1297 			dummy.rotation = Vector(0,0,0);
1298 			oldRotation = dummy.rotation;
1299 			cursorOffset = dsq->getGameCursorPosition();
1300 			groupCenter = getSelectedElementsCenter();
1301 			for (int i = 0; i < selectedElements.size(); i++)
1302 			{
1303 				selectedElements[i]->position -= groupCenter;
1304 				dummy.addChild(selectedElements[i], PM_NONE);
1305 			}
1306 			core->addRenderObject(&dummy, selectedElements[0]->layer);
1307 			dummy.cull = false;
1308 			dummy.position = groupCenter;
1309 			dummy.scale = Vector(1,1,1);
1310 		}
1311 		else if (editingElement)
1312 		{
1313 			state = ES_ROTATING;
1314 			oldRotation = editingElement->rotation;
1315 			cursorOffset = dsq->getGameCursorPosition();
1316 		}
1317 	}
1318 }
1319 
enterScaleState()1320 void SceneEditor::enterScaleState()
1321 {
1322 	if (state != ES_SELECTING) return;
1323 	if (editType == ET_ELEMENTS)
1324 	{
1325 		if (!selectedElements.empty())
1326 		{
1327 			state = ES_SCALING;
1328 			dummy.rotation = Vector(0,0,0);
1329 			dummy.scale = Vector(1,1,1);
1330 			oldScale = dummy.scale;
1331 			oldRepeatScale = Vector(1, 1); // not handled for multi-selection
1332 			cursorOffset = dsq->getGameCursorPosition();
1333 			groupCenter = getSelectedElementsCenter();
1334 			for (int i = 0; i < selectedElements.size(); i++)
1335 			{
1336 				selectedElements[i]->position -= groupCenter;
1337 				dummy.addChild(selectedElements[i], PM_NONE);
1338 			}
1339 			core->addRenderObject(&dummy, selectedElements[0]->layer);
1340 			dummy.cull = false;
1341 			dummy.position = groupCenter;
1342 		}
1343 		else if (editingElement)
1344 		{
1345 			oldPosition = editingElement->position;
1346 			state = ES_SCALING;
1347 			oldScale = editingElement->scale;
1348 			oldRepeatScale = editingElement->repeatToFillScale;
1349 			cursorOffset = dsq->getGameCursorPosition();
1350 		}
1351 	}
1352 	else if (editType == ET_PATHS)
1353 	{
1354 		state = ES_SCALING;
1355 		oldScale = Vector(editingPath->rect.x2-editingPath->rect.x1,
1356 			editingPath->rect.y2-editingPath->rect.y1);
1357 		cursorOffset = dsq->getGameCursorPosition();
1358 	}
1359 }
1360 
updateEntitySaveData(Entity * editingEntity)1361 void SceneEditor::updateEntitySaveData(Entity *editingEntity)
1362 {
1363 	if (editingEntity)
1364 	{
1365 		/*
1366 		std::ostringstream os;
1367 		os << "oldPos (" << oldPosition.x << ", " << oldPosition.y << ")";
1368 		debugLog(os.str());
1369 		*/
1370 		EntitySaveData *d = dsq->game->getEntitySaveDataForEntity(editingEntity, oldPosition);
1371 		if (d)
1372 		{
1373 			std::ostringstream os;
1374 			os << "idx1: " << d->idx << " ";
1375 			os << "idx2: " << editingEntity->entityTypeIdx << " ";
1376 			os << "name: " << editingEntity->name;
1377 			//os << "state: " << editingEntity->getState();
1378 			debugLog(os.str());
1379 			//debugLog("changing entity save data");
1380 			d->x = editingEntity->position.x;
1381 			d->y = editingEntity->position.y;
1382 			editingEntity->startPos = Vector(d->x, d->y);
1383 			/*
1384 			std::ostringstream os2;
1385 			os2 << "setting savedata rot to: " << d->rot;
1386 			debugLog(os2.str());
1387 			*/
1388 			d->rot = editingEntity->rotation.z;
1389 		}
1390 		else
1391 		{
1392 			//debugLog("didn't get entity save data");
1393 		}
1394 	}
1395 }
1396 
mouseButtonLeftUp()1397 void SceneEditor::mouseButtonLeftUp()
1398 {
1399 	if (multiSelecting || core->mouse.buttons.right) return;
1400 
1401 	if (editType == ET_ENTITIES)
1402 	{
1403 		updateEntitySaveData(editingEntity);
1404 	}
1405 	if (state == ES_MOVING)
1406 	{
1407 		exitMoveState();
1408 	}
1409 	state = ES_SELECTING;
1410 }
1411 
mouseButtonRightUp()1412 void SceneEditor::mouseButtonRightUp()
1413 {
1414 	if (multiSelecting || core->mouse.buttons.left) return;
1415 
1416 	if (editType == ET_ENTITIES)
1417 		updateEntitySaveData(editingEntity);
1418 	if (editType == ET_ELEMENTS)
1419 	{
1420 
1421 		if (state == ES_ROTATING)
1422 		{
1423 			if (!selectedElements.empty())
1424 			{
1425 				for (int i = 0; i < selectedElements.size(); i++)
1426 				{
1427 					selectedElements[i]->position = selectedElements[i]->getWorldPosition();
1428 					selectedElements[i]->rotation = selectedElements[i]->getAbsoluteRotation();
1429 					dummy.removeChild(selectedElements[i]);
1430 				}
1431 				core->removeRenderObject(&dummy, Core::DO_NOT_DESTROY_RENDER_OBJECT);
1432 			}
1433 		}
1434 		else if (state == ES_SCALING)
1435 		{
1436 
1437 			if (!selectedElements.empty())
1438 			{
1439 				for (int i = 0; i < selectedElements.size(); i++)
1440 				{
1441 					selectedElements[i]->position = selectedElements[i]->getWorldPosition();
1442 					selectedElements[i]->scale = selectedElements[i]->scale * dummy.scale;
1443 					selectedElements[i]->rotation = selectedElements[i]->getAbsoluteRotation();
1444 					dummy.removeChild(selectedElements[i]);
1445 				}
1446 				core->removeRenderObject(&dummy, Core::DO_NOT_DESTROY_RENDER_OBJECT);
1447 			}
1448 			else if (editingElement)
1449 			{
1450 				Vector add = editingElement->beforeScaleOffset;
1451 				Vector newScale = editingElement->scale;
1452 				editingElement->beforeScaleOffset = Vector(0,0,0);
1453 				editingElement->scale = Vector(1,1,1);
1454 				editingElement->position = editingElement->getWorldCollidePosition(add);
1455 				editingElement->scale = newScale;
1456 			}
1457 		}
1458 		checkForRebuild();
1459 	}
1460 	state = ES_SELECTING;
1461 	//dsq->game->reconstructGrid();
1462 }
1463 
1464 
toggleElementSolid()1465 void SceneEditor::toggleElementSolid()
1466 {
1467 	if (editingElement)
1468 	{
1469 		switch(editingElement->elementFlag)
1470 		{
1471 		default:
1472 		case EF_NONE:
1473 		{
1474 			std::ostringstream os;
1475 			os << "elementFlag: " << editingElement->elementFlag;
1476 			debugLog(os.str());
1477 			debugLog("Solid");
1478 			editingElement->elementFlag = EF_SOLID;
1479 		}
1480 		break;
1481 		case EF_SOLID:
1482 			debugLog("Solid2");
1483 			editingElement->elementFlag = EF_SOLID2;
1484 		break;
1485 		case EF_SOLID2:
1486 			debugLog("Solid3");
1487 			editingElement->elementFlag = EF_SOLID3;
1488 		break;
1489 		case EF_SOLID3:
1490 			debugLog("None");
1491 			editingElement->elementFlag = EF_NONE;
1492 		break;
1493 		}
1494 		dsq->game->reconstructGrid(true);
1495 	}
1496 }
1497 
toggleElementHurt()1498 void SceneEditor::toggleElementHurt()
1499 {
1500 	if (editingElement)
1501 	{
1502 		if (editingElement->elementFlag == EF_HURT)
1503 			editingElement->elementFlag = EF_NONE;
1504 		else
1505 			editingElement->elementFlag = EF_HURT;
1506 		dsq->game->reconstructGrid(true);
1507 	}
1508 }
1509 
toggleElementRepeat()1510 void SceneEditor::toggleElementRepeat()
1511 {
1512 	if (editingElement)
1513 	{
1514 		editingElement->repeatTextureToFill(!editingElement->isRepeatingTextureToFill());
1515 	}
1516 }
1517 
mouseButtonLeft()1518 void SceneEditor::mouseButtonLeft()
1519 {
1520 	if (multiSelecting || state != ES_SELECTING || !dummy.children.empty() || core->mouse.buttons.right) return;
1521 	if (editType == ET_ELEMENTS)
1522 	{
1523 		if (selectedElements.empty() || editingElement)
1524 		{
1525 			if (core->getShiftState())
1526 			{
1527 				cloneSelectedElement();
1528 			}
1529 			else
1530 			{
1531 				enterMoveState();
1532 			}
1533 		}
1534 	}
1535 	else if (editType == ET_ENTITIES)
1536 	{
1537 		if (editingEntity)
1538 		{
1539 			if (core->getShiftState())
1540 			{
1541 				cloneSelectedElement();
1542 			}
1543 			else
1544 			{
1545 				enterMoveState();
1546 			}
1547 		}
1548 	}
1549 	else if (editType == ET_PATHS)
1550 	{
1551 		if (selectedIdx != -1)
1552 		{
1553 			Path *p = getSelectedPath();
1554 			editingPath = p;
1555 			if (p && selectedNode >= 0 && selectedNode < p->nodes.size())
1556 			{
1557 				if (core->getShiftState())
1558 				{
1559 					cloneSelectedElement();
1560 				}
1561 				else
1562 				{
1563 					enterMoveState();
1564 				}
1565 			}
1566 		}
1567 	}
1568 }
1569 
mouseButtonRight()1570 void SceneEditor::mouseButtonRight()
1571 {
1572 	if (multiSelecting || state != ES_SELECTING || !dummy.children.empty() || core->mouse.buttons.left) return;
1573 	if (editType == ET_ENTITIES)
1574 	{
1575 		if (editingEntity)
1576 		{
1577 			if (core->getShiftState())
1578 				enterScaleState();
1579 			else
1580 				enterRotateState();
1581 		}
1582 	}
1583 	if (editType == ET_PATHS)
1584 	{
1585 		if (selectedIdx != -1)
1586 		{
1587 			debugLog("path scaling HERE!");
1588 			Path *p = dsq->game->getPath(selectedIdx);
1589 			editingPath = p;
1590 			if (core->getShiftState())
1591 			{
1592 				enterScaleState();
1593 			}
1594 		}
1595 	}
1596 	if (editType == ET_ELEMENTS)
1597 	{
1598 		if (selectedElements.empty() || editingElement)
1599 		{
1600 			if (core->getShiftState())
1601 				enterScaleState();
1602 			else
1603 				enterRotateState();
1604 		}
1605 	}
1606 	if (editType == ET_ELEMENTS && state == ES_MOVING)
1607 	{
1608 	}
1609 }
1610 
startMoveEntity()1611 void SceneEditor::startMoveEntity()
1612 {
1613 	movingEntity = dsq->game->getEntityAtCursor();
1614 }
1615 
endMoveEntity()1616 void SceneEditor::endMoveEntity()
1617 {
1618 	if (movingEntity)
1619 	{
1620 		updateSaveFileEnemyPosition(movingEntity);
1621 		movingEntity = 0;
1622 	}
1623 }
1624 
up()1625 void SceneEditor::up()
1626 {
1627 	if (editType == ET_ELEMENTS && state == ES_SELECTING)
1628 	{
1629 		if (editingElement || !selectedElements.empty())
1630 		{
1631 			enterMoveState();
1632 			updateSelectedElementPosition(Vector(0,-1));
1633 			exitMoveState();
1634 		}
1635 	}
1636 }
1637 
down()1638 void SceneEditor::down()
1639 {
1640 	if (editType == ET_ELEMENTS && state == ES_SELECTING)
1641 	{
1642 		if (editingElement || !selectedElements.empty())
1643 		{
1644 			enterMoveState();
1645 			updateSelectedElementPosition(Vector(0,1));
1646 			exitMoveState();
1647 		}
1648 	}
1649 }
1650 
1651 class Row
1652 {
1653 public:
Row()1654 	Row()
1655 	{
1656 		x1=x2=y=0;
1657 		rows=1;
1658 	}
1659 	int x1, x2, y;
1660 	int rows;
1661 };
1662 
getGrassPixel(pngRawInfo * png,int x,int y)1663 bool getGrassPixel(pngRawInfo *png, int x, int y)
1664 {
1665 	if (x >= png->Width || y >= png->Height || x < 0 || y < 0) return false;
1666 
1667 	//int c = ((x*png->Width)*3)+y*3;
1668 	int c = (y*png->Width)*png->Components + x*png->Components;
1669 	if (png->Data[c] == 128 &&
1670 		png->Data[c+1] == 255 &&
1671 		png->Data[c+2] == 128)
1672 	{
1673 		return true;
1674 	}
1675 	return false;
1676 }
1677 
regenLevel()1678 void SceneEditor::regenLevel()
1679 {
1680 	generateLevel();
1681 	skinLevel();
1682 }
1683 
skinLevel()1684 void SceneEditor::skinLevel()
1685 {
1686 	if (skinMinX == -1)
1687 	{
1688 		dsq->screenMessage("Cannot skin without generated level.");
1689 		return;
1690 	}
1691 	pngRawInfo rawinfo;
1692 	std::string file = getMapTemplateFilename();
1693 	bool success = pngLoadRaw(file.c_str(), &rawinfo);
1694 	if (success)
1695 	{
1696 		skinLevel(&rawinfo, skinMinX, skinMinY, skinMaxX, skinMaxY);
1697 		if (rawinfo.Data != NULL)
1698 			free(rawinfo.Data);
1699 	}
1700 }
1701 
skinLevel(pngRawInfo * png,int minX,int minY,int maxX,int maxY)1702 void SceneEditor::skinLevel(pngRawInfo *png, int minX, int minY, int maxX, int maxY)
1703 {
1704 	std::vector<Element*> deleteElements;
1705 	int i = 0;
1706 	for (i = 0; i < dsq->getNumElements(); i++)
1707 	{
1708 		Element *e = dsq->getElement(i);
1709 		if (e->bgLayer==4 && e->templateIdx >= 1 && e->templateIdx <= 4)
1710 		{
1711 			e->safeKill();
1712 			deleteElements.push_back(e);
1713 		}
1714 	}
1715 	for (i = 0; i < deleteElements.size(); i++)
1716 	{
1717 		dsq->removeElement(deleteElements[i]);
1718 	}
1719 	deleteElements.clear();
1720 
1721 	int idx=1;
1722 	int idxCount = 0;
1723 	for (int x = minX; x < maxX-2; x++)
1724 	{
1725 		for (int y = minY; y < maxY; y++)
1726 		{
1727 			Vector offset, pOffset;
1728 			Vector wallNormal;
1729 			float rot=0;
1730 			bool addTile = false;
1731 			TileVector t(x,y);
1732 			if (dsq->game->isObstructed(t, OT_MASK_BLACK)
1733 				&& (
1734 				!dsq->game->isObstructed(TileVector(x+1,y), OT_MASK_BLACK) ||
1735 				!dsq->game->isObstructed(TileVector(x-1,y), OT_MASK_BLACK) ||
1736 				!dsq->game->isObstructed(TileVector(x,y-1), OT_MASK_BLACK) ||
1737 				!dsq->game->isObstructed(TileVector(x,y+1), OT_MASK_BLACK)
1738 				)
1739 				)
1740 			{
1741 				// do color check
1742 				/*
1743 				int ci = x+(y*png->Height);
1744 				if (png->data[ci] < pixelColor.x &&
1745 					png->data[ci+1] < pixelColor.y &&
1746 					png->data[ci+2] < pixelColor.z)
1747 				{
1748 				*/
1749 				float dist=0;
1750 				wallNormal = dsq->game->getWallNormal(t.worldVector(), 5, &dist, OT_MASK_BLACK);
1751 				offset = wallNormal*(-TILE_SIZE*0.6f);
1752 				MathFunctions::calculateAngleBetweenVectorsInDegrees(Vector(0,0,0), wallNormal, rot);
1753 				rot = 180-(360-rot);
1754 				addTile = true;
1755 				//}
1756 			}
1757 
1758 			if (addTile)
1759 			{
1760 				TileVector t(x,y);
1761 				Vector p = t.worldVector();
1762 				Quad q;
1763 				q.rotation.z = rot;
1764 				p += Vector(TILE_SIZE/2, TILE_SIZE/2,0);
1765 				offset.z = 0;
1766 
1767 				bool skip = false;
1768 				for (int i = 0; i < dsq->getNumElements(); i++)
1769 				{
1770 					Element *e = dsq->getElement(i);
1771 					if (e->templateIdx <= 4 && e->templateIdx >= 1)
1772 					{
1773 						if ((p - e->position).getSquaredLength2D() < sqr(50))
1774 						{
1775 							skip = true;
1776 							break;
1777 						}
1778 					}
1779 				}
1780 
1781 				if (!skip)
1782 				{
1783 					std::vector<int> cantUse;
1784 					cantUse.resize(4);
1785 					int i = 0;
1786 					for (i = 0; i < dsq->getNumElements(); i++)
1787 					{
1788 						Element *e = dsq->getElement(i);
1789 						if (e->templateIdx <= 4 && e->templateIdx >= 1)
1790 						{
1791 							if ((p - e->position).getSquaredLength2D() < sqr(120))//sqr(60*3+10)) // 120
1792 							{
1793 								cantUse[e->templateIdx-1]++;
1794 							}
1795 						}
1796 					}
1797 					int useIdx = rand()%cantUse.size()+1;
1798 					for (i = 0; i < cantUse.size(); i++)
1799 					{
1800 						int check = i + idxCount;
1801 						if (check >= cantUse.size())
1802 							check -= cantUse.size();
1803 						if (cantUse[check]<=0)
1804 						{
1805 							useIdx = check+1;
1806 						}
1807 					}
1808 					idxCount = rand()%cantUse.size();
1809 
1810 					Element *e = dsq->game->createElement(useIdx, p, 4, &q);
1811 					e->offset = offset;
1812 
1813 
1814 					/*
1815 					bool addGrass = false;
1816 					int search = 2;
1817 					for (int dx = -search; dx < search; dx++)
1818 					{
1819 						for (int dy = -search; dy < search; dy++)
1820 						{
1821 							if (getGrassPixel(png, x+dx, y+dy))
1822 							{
1823 								//std::ostringstream os;
1824 								//os << "found grass pixel at (" << x+dx << ", " << y+dy << ")";
1825 								//debugLog(os.str());
1826 								//errorLog ("add grass");
1827 								addGrass = true;
1828 								break;
1829 							}
1830 						}
1831 					}
1832 
1833 					if (addGrass)
1834 					{
1835 						//Vector detailPos = p + wallNormal*48;
1836 						Element *grassE = dsq->game->createElement(5, p, 0, &q);
1837 							//dsq->game->createElement(5, detailPos, 6, &q);
1838 						//grassE->offset = offset;
1839 					}
1840 					*/
1841 
1842 
1843 					/*
1844 					float sz = ((rand()%1000)/4000.0f);
1845 					e->scale = Vector(1+sz, 1+sz, 1);
1846 					*/
1847 
1848 
1849 					idx++;
1850 					if(idx > 4)
1851 						idx = 1;
1852 				}
1853 			}
1854 		}
1855 		for (int i = 0; i < dsq->getNumElements(); i++)
1856 		{
1857 			Element *e = dsq->getElement(i);
1858 			if (e->bgLayer == 4 && e->templateIdx >= 1 && e->templateIdx <= 4)
1859 			{
1860 				e->position += e->offset;
1861 				e->offset = Vector(0,0,0);
1862 			}
1863 		}
1864 	}
1865 }
1866 
fixEntityIDs()1867 void SceneEditor::fixEntityIDs()
1868 {
1869 	FOR_ENTITIES(i)
1870 	{
1871 		Entity *e = *i;
1872 		e->assignUniqueID();
1873 	}
1874 }
1875 
generateLevel()1876 void SceneEditor::generateLevel()
1877 {
1878 	//pngSetStandardOrientation(0);
1879 	std::string file=getMapTemplateFilename();
1880 	//pngInfo info;
1881 	//PNG_ALPHA
1882 
1883 	//errorLog("generate level");
1884 	// Y R G B P
1885 		int maxX=0, maxY=0;
1886 	const int YELLOW=0, RED=1, GREEN=2, BLUE=3, PURPLE=4, ORANGE=5, BROWN=6, MAX=7;
1887 	int firstColorX[MAX], firstColorY[MAX];
1888 	int lastColorX[MAX], lastColorY[MAX];
1889 	Vector colorVects[MAX];
1890 	colorVects[YELLOW] = Vector(1,1,0);
1891 	colorVects[RED]	= Vector(1,0,0);
1892 	colorVects[GREEN] = Vector(0,1,0);
1893 	colorVects[BLUE] = Vector(0,0,1);
1894 	colorVects[PURPLE] = Vector(1,0,1);
1895 	colorVects[ORANGE] = Vector(1,0.5,0);
1896 	colorVects[BROWN] = Vector(0.5,0.25,0);
1897 	for (int i = 0; i < MAX; i++)
1898 	{
1899 		firstColorX[i] = firstColorY[i] = -1;
1900 		lastColorX[i] = lastColorY[i] = -1;
1901 	}
1902 	pngRawInfo rawinfo;
1903 	bool success = pngLoadRaw(file.c_str(), &rawinfo);
1904 	if (success)
1905 	{
1906 		//dsq->elements.clear();
1907 		std::vector<Row> rows;
1908 		std::vector<Vector> positions;
1909 		const int maxRowCount = 9999;//9999;//9999;
1910 		int rowCount = 0;
1911 		if (rawinfo.Components < 3)
1912 		{
1913 			errorLog("png color depth ( < 3 bit) not supported by generate level");
1914 		}
1915 		int scale = TILE_SIZE;
1916 		int c = 0;
1917 		//for (int y = rawinfo.Height-1; y >= 0; y--)
1918 		for (int y = 0; y < rawinfo.Height; y++)
1919 		{
1920 			Vector lastElement;
1921 			lastElement = Vector(0,0,0);
1922 			bool hasLastElement = false;
1923 			Vector *firstRowElement = 0;
1924 			Row row;
1925 			rowCount = 0;
1926 			positions.clear();
1927 			for (int x = 0; x < rawinfo.Width; x++)
1928 			{
1929 				Vector *e = 0;
1930 				if
1931 				(
1932 					(
1933 						rawinfo.Data[c] < 48 &&
1934 						rawinfo.Data[c+1] < 48 &&
1935 						rawinfo.Data[c+2] < 48
1936 					)
1937 					||
1938 					(
1939 						rawinfo.Data[c] == 128
1940 						&&
1941 						rawinfo.Data[c+1] == 255
1942 						&&
1943 						rawinfo.Data[c+2] == 128
1944 					)
1945 				)
1946 				{
1947 					if (x > maxX)
1948 						maxX = x;
1949 					if (y > maxY)
1950 						maxY = y;
1951 					positions.push_back(Vector(x*scale+(scale/2.0f),y*scale+(scale/2.0f)));
1952 					e = &positions[positions.size()-1];
1953 				}
1954 				if (rawinfo.Data[c] < 32 &&
1955 					rawinfo.Data[c+1] > 200 &&
1956 					rawinfo.Data[c+2] > 200)
1957 				{
1958 					dsq->game->saveWaterLevel = dsq->game->waterLevel.x = y*TILE_SIZE;
1959 				}
1960 				for (int i = 0; i < MAX; i++)
1961 				{
1962 					//if (checkWarpPixel(rawinfo.Data, c, colorVects[i]))
1963 					bool p1, p2, p3;
1964 					p1=p2=p3=false;
1965 					int diff;
1966 					diff = fabsf((colorVects[i].x*255) - rawinfo.Data[c]);
1967 					p1 = (diff < 5);
1968 					diff = fabsf((colorVects[i].y*255) - rawinfo.Data[c+1]);
1969 					p2 = (diff < 5);
1970 					diff = fabsf((colorVects[i].z*255) - rawinfo.Data[c+2]);
1971 					p3 = (diff < 5);
1972 					/*
1973 					p1 = (colorVects[i].x == 1 && rawinfo.Data[c] > 200);
1974 					if (!p1)
1975 					{
1976 						p1 = (colorVects[i].x == 0 && rawinfo.Data[c] < 32);
1977 					}
1978 					p2 = (colorVects[i].y == 1 && rawinfo.Data[c+1] > 200);
1979 					if (!p2)
1980 					{
1981 						p2 = (colorVects[i].y == 0 && rawinfo.Data[c+1] < 32);
1982 						if (!p2)
1983 						{
1984 							p2 = (colorVects[i].y == 0.5f && rawinfo.Data[c+1] > 96 && rawinfo.Data[c+1] < 164);
1985 						}
1986 					}
1987 					p3 = (colorVects[i].z == 1 && rawinfo.Data[c+2] > 200);
1988 					if (!p3)
1989 						p3 = (colorVects[i].z == 0 && rawinfo.Data[c+2] < 32);
1990 					*/
1991 					if (p1 && p2 && p3)
1992 					{
1993 						lastColorX[i] = x;
1994 						lastColorY[i] = y;
1995 						if (firstColorX[i] == -1)
1996 						{
1997 							firstColorX[i] = x;
1998 							firstColorY[i] = y;
1999 						}
2000 					}
2001 				}
2002 				/*
2003 				else if (checkPixel(1, 0, 0))
2004 				{
2005 					lastColorX[RED] = x;
2006 					lastColorY[RED] = y;
2007 					if (firstColorX[RED] == -1)
2008 					{
2009 						firstColorX[RED] = x;
2010 						firstColorY[RED] = y;
2011 					}
2012 				}
2013 				*/
2014 				/*
2015 				else if (	rawinfo.Data[c]		> 200	&&
2016 							rawinfo.Data[c+1]	< 32	&&
2017 							rawinfo.Data[c+2]	< 32)
2018 				{
2019 
2020 				}
2021 				else if (rawinfo.
2022 				*/
2023 
2024 				c += rawinfo.Components;
2025 				if ((e==0 && firstRowElement) || (firstRowElement && rowCount >= maxRowCount && hasLastElement)
2026 					|| (firstRowElement && x == rawinfo.Width-1))
2027 				{
2028 					/*
2029 					if (x == rawinfo.Width-1)
2030 						row.x2 = rawinfo.Width-1;
2031 					else
2032 					{
2033 					*/
2034 					// HACK: it crashes here:
2035 					// because lastElement is garbage data
2036 					// fixed!
2037 					if (hasLastElement)
2038 						row.x2 = lastElement.x;
2039 					//}
2040 
2041 					hasLastElement = false;
2042 					firstRowElement = 0;
2043 
2044 					bool add = true;
2045 					/*
2046 					for (int i = 0; i < rows.size(); i++)
2047 					{
2048 						if (rows[i].x1 == row.x1 && rows[i].x2 == row.x2)
2049 						{
2050 							if (abs(rows[i].y - row.y) <= TILE_SIZE+1)
2051 							{
2052 								rows[i].rows++;
2053 								add = false;
2054 								break;
2055 							}
2056 						}
2057 					}
2058 					*/
2059 					if (add)
2060 						rows.push_back(row);
2061 				}
2062 				if (!firstRowElement && e)
2063 				{
2064 					row.x1 = e->x;
2065 					row.y = e->y;
2066 					firstRowElement = e;
2067 					rowCount = 1;
2068 				}
2069 				if (e)
2070 				{
2071 					lastElement = *e;
2072 					hasLastElement = true;
2073 				}
2074 				else
2075 					hasLastElement = false;
2076 				rowCount ++ ;
2077 			}
2078 		}
2079 
2080 		dsq->game->clearObsRows();
2081 		int i = 0;
2082 		for (i = 0; i < rows.size(); i++)
2083 		{
2084 			int w = rows[i].x2 - rows[i].x1;
2085 			//int h = scale * rows[i].rows;
2086 			int useY = rows[i].y;
2087 			if (rows[i].rows > 1)
2088 			{
2089 				useY += (rows[i].rows-1)*TILE_SIZE/2;
2090 			}
2091 
2092 			dsq->game->addObsRow(rows[i].x1/TILE_SIZE, rows[i].y/TILE_SIZE, w/TILE_SIZE);
2093 		}
2094 
2095 		dsq->game->reconstructGrid(true);
2096 
2097 		// create warp areas
2098 		dsq->game->warpAreas.clear();
2099 		for (i = 0; i < MAX; i++)
2100 		{
2101 			if (firstColorX[i] != -1)
2102 			{
2103 				WarpArea warpArea;
2104 				int w = lastColorX[i] - firstColorX[i];
2105 				int h = lastColorY[i] - firstColorY[i];
2106 
2107 				warpArea.w = w*TILE_SIZE;
2108 				warpArea.h = h*TILE_SIZE;
2109 				warpArea.position = Vector(firstColorX[i]*TILE_SIZE + warpArea.w/2, firstColorY[i]*TILE_SIZE + warpArea.h/2);
2110 				warpArea.w += TILE_SIZE*4;
2111 				warpArea.h += TILE_SIZE*4;
2112 
2113 				switch (i)
2114 				{
2115 				case RED:		warpArea.warpAreaType = "Red";			break;
2116 				case BLUE:		warpArea.warpAreaType = "Blue";			break;
2117 				case GREEN:		warpArea.warpAreaType = "Green";		break;
2118 				case YELLOW:	warpArea.warpAreaType = "Yellow";		break;
2119 				case PURPLE:	warpArea.warpAreaType = "Purple";		break;
2120 				case ORANGE:	warpArea.warpAreaType = "Orange";		break;
2121 				case BROWN:		warpArea.warpAreaType = "Brown";		break;
2122 				}
2123 
2124 				dsq->game->setWarpAreaSceneName(warpArea);
2125 
2126 				warpArea.generated = true;
2127 
2128 				std::ostringstream os;
2129 				os << "WarpArea (" << warpArea.w << ", " << warpArea.h << ") - pos(" << warpArea.position.x << ", " <<
2130 					warpArea.position.y << ")";
2131 				debugLog(os.str());
2132 
2133 				dsq->game->warpAreas.push_back(warpArea);
2134 			}
2135 		}
2136 
2137 		maxX--;
2138 		maxY--;
2139 		this->skinMinX = 4;
2140 		this->skinMinY = 4;
2141 		this->skinMaxX = maxX;
2142 		this->skinMaxY = maxY;
2143 		//skinLevel(&rawinfo, 4, 4, maxX, maxY);
2144 		if (rawinfo.Data != NULL)
2145 			free(rawinfo.Data);
2146 	}
2147 	else
2148 	{
2149 		debugLog("generateLevel: Failed to load mapTemplate");
2150 	}
2151 //	pngSetStandardOrientation(1);
2152 }
2153 
removeEntity()2154 void SceneEditor::removeEntity()
2155 {
2156 	debugLog("remove entity at cursor");
2157 	dsq->game->removeEntityAtCursor();
2158 }
2159 
placeAvatar()2160 void SceneEditor::placeAvatar()
2161 {
2162 	dsq->game->avatar->position = dsq->getGameCursorPosition();
2163 	dsq->game->action(ACTION_PLACE_AVATAR, 0);
2164 }
2165 
scaleElementUp()2166 void SceneEditor::scaleElementUp()
2167 {
2168 	placer->scale += Vector(0.25, 0.25,0);
2169 }
2170 
scaleElementDown()2171 void SceneEditor::scaleElementDown()
2172 {
2173 	placer->scale -= Vector(0.25, 0.25,0);
2174 }
2175 
scaleElement1()2176 void SceneEditor::scaleElement1()
2177 {
2178 	placer->scale = Vector(1,1,1);
2179 }
2180 
flipElementHorz()2181 void SceneEditor::flipElementHorz()
2182 {
2183 	if (editType != ET_ELEMENTS)
2184 		return;
2185 
2186 	if (editingElement)
2187 		editingElement->flipHorizontal();
2188 	else
2189 		this->placer->flipHorizontal();
2190 }
2191 
flipElementVert()2192 void SceneEditor::flipElementVert()
2193 {
2194 	if (editType != ET_ELEMENTS)
2195 		return;
2196 
2197 	if (editingElement)
2198 		editingElement->flipVertical();
2199 	else
2200 		this->placer->flipVertical();
2201 }
2202 
moveElementToLayer(Element * e,int bgLayer)2203 void SceneEditor::moveElementToLayer(Element *e, int bgLayer)
2204 {
2205 	if (!selectedElements.empty())
2206 	{
2207 		for (int i = 0; i < selectedElements.size(); i++)
2208 		{
2209 			Element *e = selectedElements[i];
2210 			core->removeRenderObject(e, Core::DO_NOT_DESTROY_RENDER_OBJECT);
2211 			dsq->removeElement(e);
2212 			e->bgLayer = bgLayer;
2213 			dsq->addElement(e);
2214 			core->addRenderObject(e, LR_ELEMENTS1+bgLayer);
2215 		}
2216 	}
2217 	else if (e)
2218 	{
2219 		core->removeRenderObject(e, Core::DO_NOT_DESTROY_RENDER_OBJECT);
2220 		dsq->removeElement(e);
2221 		e->bgLayer = bgLayer;
2222 		dsq->addElement(e);
2223 		core->addRenderObject(e, LR_ELEMENTS1+bgLayer);
2224 	}
2225 }
2226 
updateMultiSelect()2227 void SceneEditor::updateMultiSelect()
2228 {
2229 	if (!multiSelecting) return;
2230 	Vector secondPoint = dsq->getGameCursorPosition();
2231 	if (!(multiSelectPoint-secondPoint).isLength2DIn(64))
2232 	{
2233 		Vector p1, p2;
2234 
2235 		if (secondPoint.x < multiSelectPoint.x)
2236 		{
2237 			p1.x = secondPoint.x;
2238 			p2.x = multiSelectPoint.x;
2239 		}
2240 		else
2241 		{
2242 			p1.x = multiSelectPoint.x;
2243 			p2.x = secondPoint.x;
2244 		}
2245 
2246 		if (secondPoint.y < multiSelectPoint.y)
2247 		{
2248 			p1.y = secondPoint.y;
2249 			p2.y = multiSelectPoint.y;
2250 		}
2251 		else
2252 		{
2253 			p1.y = multiSelectPoint.y;
2254 			p2.y = secondPoint.y;
2255 		}
2256 
2257 		selectedElements.clear();
2258 
2259 		for (int i = 0; i < dsq->getNumElements(); i++)
2260 		{
2261 			Element *e = dsq->getElement(i);
2262 			if (e->bgLayer == bgLayer && e->position.x >= p1.x && e->position.y >= p1.y && e->position.x <= p2.x && e->position.y <= p2.y)
2263 			{
2264 				selectedElements.push_back(e);
2265 			}
2266 		}
2267 	}
2268 }
2269 
action(int id,int state)2270 void SceneEditor::action(int id, int state)
2271 {
2272 	if (core->getCtrlState() && editingElement)
2273 	{
2274 		if (id == ACTION_BGLAYEREND)
2275 		{
2276 			editingElement->setElementEffectByIndex(-1);
2277 		}
2278 		else if (id >= ACTION_BGLAYER1 && id < ACTION_BGLAYER10)
2279 		{
2280 			editingElement->setElementEffectByIndex(id - ACTION_BGLAYER1);
2281 		}
2282 	}
2283 	else if (editType == ET_ELEMENTS && state && id >= ACTION_BGLAYER1 && id < ACTION_BGLAYEREND)
2284 	{
2285 		int newLayer = id - ACTION_BGLAYER1;
2286 
2287 		updateText();
2288 
2289 		if (core->getAltState())
2290 		{
2291 			dsq->game->setElementLayerVisible(newLayer, !dsq->game->isElementLayerVisible(newLayer));
2292 			return; // do not switch to the layer that was just hidden
2293 		}
2294 		else if (core->getShiftState() && (editingElement || !selectedElements.empty()))
2295 		{
2296 			moveElementToLayer(editingElement, newLayer);
2297 		}
2298 		else
2299 		{
2300 			selectedElements.clear();
2301 		}
2302 
2303 		this->bgLayer = newLayer;
2304 
2305 	}
2306 	/*
2307 	Vector multiSelectPoint, secondMultiSelectPoint;
2308 	*/
2309 	if (id == ACTION_MULTISELECT && this->state == ES_SELECTING)
2310 	{
2311 		if (state)
2312 		{
2313 			if (!multiSelecting)
2314 				selectedElements.clear();
2315 			multiSelecting = true;
2316 			multiSelectPoint = dsq->getGameCursorPosition();
2317 		}
2318 		else
2319 		{
2320 			multiSelecting = false;
2321 		}
2322 	}
2323 }
2324 
rotateElement()2325 void SceneEditor::rotateElement()
2326 {
2327 	placer->rotation += Vector(0, 0, 45);
2328 	if (placer->rotation.z > 360)
2329 		placer->rotation.z -= 360;
2330 }
2331 
rotateElement2()2332 void SceneEditor::rotateElement2()
2333 {
2334 	placer->rotation -= Vector(0, 0, 45);
2335 	if (placer->rotation.z < 0)
2336 		placer->rotation.z += 360;
2337 }
2338 
loadSceneByName()2339 void SceneEditor::loadSceneByName()
2340 {
2341 	std::string s = dsq->getUserInputString("Enter Name of Map to Load");
2342 	if (!s.empty())
2343 		dsq->game->transitionToScene(s);
2344 }
2345 
reloadScene()2346 void SceneEditor::reloadScene()
2347 {
2348 	debugLog("reloadScene");
2349 	dsq->game->positionToAvatar = dsq->game->avatar->position;
2350 	dsq->game->transitionToScene(dsq->game->sceneName);
2351 }
2352 
2353 
loadScene()2354 void SceneEditor::loadScene()
2355 {
2356 	if (core->getShiftState())
2357 	{
2358 		loadSceneByName();
2359 	}
2360 	else
2361 	{
2362 		reloadScene();
2363 	}
2364 
2365 	// HACK: reload stuff when (re-) loading a map this way
2366 	particleManager->loadParticleBank(dsq->particleBank1, dsq->particleBank2);
2367 	Shot::loadShotBank(dsq->shotBank1, dsq->shotBank2);
2368 	dsq->game->loadEntityTypeList();
2369 	dsq->loadElementEffects();
2370 	dsq->continuity.loadSongBank();
2371 	dsq->continuity.stringBank.load();
2372 }
2373 
saveScene()2374 void SceneEditor::saveScene()
2375 {
2376 	if(dsq->game->saveScene(dsq->game->sceneName))
2377 		dsq->screenMessage(dsq->game->sceneName + " Saved!");
2378 	else
2379 		dsq->screenMessage(dsq->game->sceneName + " FAILED to save!");
2380 }
2381 
deleteSelectedElement()2382 void SceneEditor::deleteSelectedElement()
2383 {
2384 	deleteElement(selectedIdx);
2385 	selectedIdx = -1;
2386 }
2387 
deleteElement(int selectedIdx)2388 void SceneEditor::deleteElement(int selectedIdx)
2389 {
2390 	if (selectedIdx == -1) return;
2391 	Element *e = dsq->getElement(selectedIdx);
2392 	e->setLife(0.5);
2393 	e->setDecayRate(1);
2394 	e->fadeAlphaWithLife = true;
2395 	dsq->removeElement(selectedIdx);
2396 	dsq->game->reconstructGrid();
2397 }
2398 
2399 Quad *se_grad = 0;
2400 
destroyEntityPage()2401 void destroyEntityPage()
2402 {
2403 	if (se_label)
2404 	{
2405 		se_label->safeKill();
2406 		se_label = 0;
2407 	}
2408 	if (se_grad)
2409 	{
2410 		//se_grad->safeKill();
2411 		se_grad->setLife(1);
2412 		se_grad->setDecayRate(10);
2413 		se_grad->fadeAlphaWithLife = 1;
2414 		se_grad = 0;
2415 	}
2416 	for (int i = 0; i < qs.size(); i++)
2417 	{
2418 		qs[i]->safeKill();
2419 	}
2420 	qs.clear();
2421 }
2422 
createEntityPage()2423 void createEntityPage()
2424 {
2425 	int c = 0;
2426 	int rowSize = 12;
2427 	int sizing = 64;
2428 	Vector basePos = Vector(48, 164);
2429 
2430 	destroyEntityPage();
2431 
2432 	se_grad = new Quad();
2433 	//Gradient()
2434 	//se_grad->makeHorizontal(Vector(0,0,0.3), Vector(0,0,0.1));
2435 	se_grad->scale = Vector(800, 500);
2436 	se_grad->position = Vector(400,350);
2437 	se_grad->followCamera = 1;
2438 	se_grad->alpha = 0;
2439 	se_grad->color = Vector(0,0,0);
2440 	se_grad->alpha.interpolateTo(0.8, 0.2);
2441 	dsq->game->addRenderObject(se_grad, LR_HUD);
2442 
2443 	EntityGroup &group = game->entityGroups[game->sceneEditor.entityPageNum];
2444 
2445 	for (int i = 0; i < group.entities.size(); i++)
2446 	{
2447 		EntityGroupEntity ent = group.entities[i];
2448 		EntityClass *ec = dsq->game->getEntityClassForEntityType(ent.name);
2449 		if (!ec && !dsq->mod.isActive())
2450 		{
2451 			errorLog("Entity Page List Error: Typo in Entities.txt?");
2452 		}
2453 		int type = -1;
2454 		if (ec)
2455 		{
2456 			int j=0;
2457 			for (j = 0; j < dsq->game->entityTypeList.size(); j++)
2458 			{
2459 				if (ec->idx == dsq->game->entityTypeList[j].idx)
2460 					break;
2461 			}
2462 			type = j;
2463 		}
2464 
2465 		int bit = int(floorf(float(c/rowSize)));  // FIXME: Not float(c)/rowSize?  --achurch
2466 		std::string prevGfx = ent.gfx;
2467 		if (prevGfx.empty() && ec)
2468 			prevGfx = ec->prevGfx;
2469 		std::string ecName = ent.name;
2470 		if (ec)
2471 			ecName = ec->name;
2472 		if (!ecName.empty())
2473 		{
2474 			SEQuad *q = new SEQuad(prevGfx, Vector((c-(bit*rowSize)), bit)*sizing, type, ecName);
2475 			q->position += basePos;
2476 			if (q->getWidth() > q->getHeight())
2477 			{
2478 				q->setWidthHeight(sizing, (q->getHeight()*sizing) / q->getWidth());
2479 			}
2480 			else
2481 			{
2482 				q->setWidthHeight((q->getWidth()*sizing) / q->getHeight(), sizing);
2483 			}
2484 			//q->setWidthHeight(sizing, sizing);
2485 			q->followCamera = 1;
2486 			dsq->game->addRenderObject(q, LR_HUD);
2487 			qs.push_back(q);
2488 			c++;
2489 		}
2490 	}
2491 
2492 	se_label = new DebugFont();
2493 	se_label->setFontSize(10);
2494 	se_label->setText(group.name);
2495 	se_label->position = Vector(20,90);
2496 	se_label->followCamera = 1;
2497 	dsq->game->addRenderObject(se_label, LR_HUD);
2498 }
2499 
nextEntityPage()2500 void nextEntityPage()
2501 {
2502 	game->sceneEditor.entityPageNum++;
2503 	if (game->sceneEditor.entityPageNum >= game->entityGroups.size())
2504 		game->sceneEditor.entityPageNum = 0;
2505 
2506 	createEntityPage();
2507 }
2508 
2509 
prevEntityPage()2510 void prevEntityPage()
2511 {
2512 	game->sceneEditor.entityPageNum--;
2513 	if (game->sceneEditor.entityPageNum < 0)
2514 		game->sceneEditor.entityPageNum = game->entityGroups.size()-1;
2515 
2516 	createEntityPage();
2517 }
2518 
selectEntityFromGroups()2519 void SceneEditor::selectEntityFromGroups()
2520 {
2521 	createEntityPage();
2522 
2523 	placer->alpha = 0;
2524 	se_changedEntityType = false;
2525 	editType = ET_SELECTENTITY;
2526 
2527 	bool mbld = false;
2528 	bool ld = false, rd = false;
2529 	ld = core->getKeyState(KEY_E);
2530 	while (!se_changedEntityType)
2531 	{
2532 		if (core->mouse.buttons.left && !mbld)
2533 			mbld = true;
2534 		else if (!core->mouse.buttons.left && mbld)
2535 		{
2536 			mbld = false;
2537 			if (core->mouse.position.y < 100)
2538 				break;
2539 		}
2540 
2541 		if (core->getKeyState(KEY_ESCAPE))
2542 			break;
2543 		if (core->getKeyState(KEY_SPACE))
2544 			break;
2545 
2546 		if (!core->getKeyState(KEY_E))
2547 			ld = false;
2548 		else if (!ld)
2549 		{
2550 			ld=true;
2551 			nextEntityPage();
2552 		}
2553 
2554 		if (!core->getKeyState(KEY_R))
2555 			rd = !true;
2556 		else if (!rd)
2557 		{
2558 			rd=!false;
2559 			prevEntityPage();
2560 		}
2561 
2562 		core->main(FRAME_TIME);
2563 	}
2564 
2565 	destroyEntityPage();
2566 
2567 	editType = ET_ENTITIES;
2568 	updateEntityPlacer();
2569 	placer->alpha = 1;
2570 }
2571 
2572 
updateEntityPlacer()2573 void SceneEditor::updateEntityPlacer()
2574 {
2575 	placer->setTexture(selectedEntity.prevGfx);
2576 	placer->scale = Vector(selectedEntity.prevScale,selectedEntity.prevScale);
2577 }
2578 
cycleElementNext(Element * e1)2579 Element* SceneEditor::cycleElementNext(Element *e1)
2580 {
2581 	int ce = e1->templateIdx;
2582 	int idx=0;
2583 	for (int i = 0; i < dsq->game->elementTemplates.size(); i++)
2584 	{
2585 		if (dsq->game->elementTemplates[i].idx == ce)
2586 			idx = i;
2587 	}
2588 	ce = idx;
2589 	ce++;
2590 	if (ce >= dsq->game->elementTemplates.size())
2591 		ce = 0;
2592 	idx = dsq->game->elementTemplates[ce].idx;
2593 	if (idx < 1024)
2594 	{
2595 		Element *e = dsq->game->createElement(idx, e1->position, e1->bgLayer, e1);
2596 		e1->safeKill();
2597 		dsq->removeElement(e1);
2598 		return e;
2599 	}
2600 	return e1;
2601 }
2602 
cycleElementPrev(Element * e1)2603 Element* SceneEditor::cycleElementPrev(Element *e1)
2604 {
2605 	int ce = e1->templateIdx;
2606 	int idx=0;
2607 	for (int i = 0; i < dsq->game->elementTemplates.size(); i++)
2608 	{
2609 		if (dsq->game->elementTemplates[i].idx == ce)
2610 		{
2611 			idx = i;
2612 			break;
2613 		}
2614 	}
2615 	ce = idx;
2616 	ce--;
2617 	if (ce < 0)
2618 		ce = dsq->game->elementTemplates.size()-1;
2619 	idx = dsq->game->elementTemplates[ce].idx;
2620 	if (idx < 1024)
2621 	{
2622 		Element *e = dsq->game->createElement(idx, e1->position, e1->bgLayer, e1);
2623 		e1->safeKill();
2624 		dsq->removeElement(e1);
2625 		return e;
2626 	}
2627 	return e1;
2628 }
2629 
nextElement()2630 void SceneEditor::nextElement()
2631 {
2632 	if (state != ES_SELECTING) return;
2633 
2634 
2635 	if (core->getCtrlState())
2636 	{
2637 		dsq->mod.recache();
2638 		return;
2639 	}
2640 
2641 	if (core->getAltState())
2642 	{
2643 		debugLog("rebuilding level!");
2644 		dsq->game->reconstructGrid(true);
2645 		return;
2646 	}
2647 
2648 	if (editType == ET_ELEMENTS)
2649 	{
2650 		if (dsq->game->elementTemplates.empty()) return;
2651 		if (core->getCtrlState())
2652 		{
2653 			if (!selectedElements.empty())
2654 			{
2655 				for (int i = 0; i < selectedElements.size(); i++)
2656 				{
2657 					selectedElements[i]->rotation.z = 0;
2658 				}
2659 			}
2660 			else if (editingElement)
2661 			{
2662 				editingElement->rotation.z = 0;
2663 			}
2664 		}
2665 		else if (!selectedElements.empty())
2666 		{
2667 			for (int i = 0; i < selectedElements.size(); i++)
2668 			{
2669 				selectedElements[i] = cycleElementNext(selectedElements[i]);
2670 			}
2671 		}
2672 		else if (editingElement)
2673 		{
2674 			cycleElementNext(editingElement);
2675 			editingElement = 0;
2676 		}
2677 		else
2678 		{
2679 			int oldCur = curElement;
2680 			curElement++;
2681 			if (curElement >= dsq->game->elementTemplates.size())
2682 				curElement = 0;
2683 
2684 			if (dsq->game->elementTemplates[curElement].idx < 1024)
2685 			{
2686 				placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
2687 			}
2688 			else
2689 			{
2690 				curElement = oldCur;
2691 			}
2692 		}
2693 	}
2694 }
2695 
prevElement()2696 void SceneEditor::prevElement()
2697 {
2698 	if (state != ES_SELECTING) return;
2699 
2700 	if (editType != ET_SELECTENTITY)
2701 	{
2702 		if (core->getCtrlState())
2703 		{
2704 			debugLog("SELECT ENTITY FROM GROUPS!");
2705 			selectEntityFromGroups();
2706 			return;
2707 		}
2708 	}
2709 
2710 	if (editType == ET_ELEMENTS)
2711 	{
2712 		if (dsq->game->elementTemplates.empty()) return;
2713 		if (!selectedElements.empty())
2714 		{
2715 			for (int i = 0; i < selectedElements.size(); i++)
2716 			{
2717 				selectedElements[i] = cycleElementPrev(selectedElements[i]);
2718 			}
2719 		}
2720 		else if (editingElement)
2721 		{
2722 			cycleElementPrev(editingElement);
2723 			editingElement = 0;
2724 		}
2725 		else
2726 		{
2727 			doPrevElement();
2728 		}
2729 	}
2730 }
2731 
doPrevElement()2732 void SceneEditor::doPrevElement()
2733 {
2734 	int oldCur = curElement;
2735 	curElement--;
2736 	if (curElement < 0)
2737 		curElement = dsq->game->elementTemplates.size()-1;
2738 
2739 	if (curElement < 0)
2740 		return;
2741 
2742 	if (dsq->game->elementTemplates[curElement].idx < 1024)
2743 	{
2744 		placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
2745 	}
2746 	else
2747 	{
2748 		curElement = oldCur;
2749 	}
2750 }
2751 
moveLayer()2752 void SceneEditor::moveLayer()
2753 {
2754 	std::string s = dsq->getUserInputString("Enter 'fromLayer toLayer' (space inbetween, ESC/m-ty to cancel)");
2755 	if (!s.empty())
2756 	{
2757 		std::istringstream is(s);
2758 		int fromLayer, toLayer;
2759 		is >> fromLayer >> toLayer;
2760 		toLayer--;
2761 		fromLayer--;
2762 		for (int i = 0; i < dsq->getNumElements(); i++)
2763 		{
2764 			Element *e = dsq->getElement(i);
2765 			if (e)
2766 			{
2767 				if (e->bgLayer == fromLayer)
2768 				{
2769 					moveElementToLayer(e, toLayer);
2770 				}
2771 			}
2772 		}
2773 	}
2774 }
2775 
selectZero()2776 void SceneEditor::selectZero()
2777 {
2778 	if (state != ES_SELECTING) return;
2779 
2780 	if (editType == ET_ELEMENTS)
2781 	{
2782 		if (dsq->game->elementTemplates.empty()) return;
2783 		if (editingElement)
2784 		{
2785 		}
2786 		else
2787 		{
2788 			curElement = 0;
2789 			placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
2790 		}
2791 	}
2792 }
2793 
selectEnd()2794 void SceneEditor::selectEnd()
2795 {
2796 	if (state != ES_SELECTING) return;
2797 	if (editType == ET_ELEMENTS)
2798 	{
2799 		if (dsq->game->elementTemplates.empty()) return;
2800 		if (!editingElement)
2801 		{
2802 			int largest = 0;
2803 			for (int i = 0; i < dsq->game->elementTemplates.size(); i++)
2804 			{
2805 				ElementTemplate et = dsq->game->elementTemplates[i];
2806 				if (et.idx < 1024 && i > largest)
2807 				{
2808 					largest = i;
2809 				}
2810 			}
2811 			curElement = largest;
2812 			placer->setTexture(dsq->game->elementTemplates[curElement].gfx);
2813 		}
2814 	}
2815 }
2816 
placeElement()2817 void SceneEditor::placeElement()
2818 {
2819 	if (editType == ET_ELEMENTS)
2820 	{
2821 		if (!core->getShiftState() && !core->getKeyState(KEY_LALT) && !drawingBox)
2822 		{
2823 			dsq->game->createElement(dsq->game->elementTemplates[curElement].idx, placer->position, bgLayer, placer);
2824 			updateText();
2825 			dsq->game->reconstructGrid();
2826 		}
2827 	}
2828 	else if (editType == ET_ENTITIES)
2829 	{
2830 		if (!selectedEntity.nameBased)
2831 			dsq->game->createEntity(selectedEntity.index, 0, dsq->getGameCursorPosition(), 0, true, "", ET_ENEMY, true);
2832 		else
2833 			dsq->game->createEntity(selectedEntity.name, 0, dsq->getGameCursorPosition(), 0, true, "", ET_ENEMY, true);
2834 	}
2835 	else if (editType == ET_PATHS)
2836 	{
2837 		if (core->getCtrlState())
2838 		{
2839 			// new path
2840 			Path *p = new Path;
2841 			p->name = "";
2842 			PathNode n;
2843 			n.position = dsq->getGameCursorPosition();
2844 			p->nodes.push_back(n);
2845 			dsq->game->addPath(p);
2846 			selectedIdx = dsq->game->getNumPaths()-1;
2847 		}
2848 		else
2849 		{
2850 			Path *p = getSelectedPath();
2851 			if (p)
2852 			{
2853 				p->addNode(selectedNode);
2854 			}
2855 		}
2856 	}
2857 }
2858 
cloneSelectedElement()2859 void SceneEditor::cloneSelectedElement()
2860 {
2861 	if (editType == ET_ELEMENTS)
2862 	{
2863 		if (!selectedElements.empty())
2864 		{
2865 			std::vector<Element*>copy;
2866 			Vector groupCenter = this->getSelectedElementsCenter();
2867 			for (int i = 0; i < selectedElements.size(); i++)
2868 			{
2869 				Element *e1 = selectedElements[i];
2870 				Vector dist = e1->position - groupCenter;
2871 				Element *e = dsq->game->createElement(e1->templateIdx, placer->position + Vector(40,40) + dist, e1->bgLayer, e1);
2872 				e->elementFlag = e1->elementFlag;
2873 				e->setElementEffectByIndex(e1->getElementEffectIndex());
2874 				copy.push_back(e);
2875 			}
2876 			selectedElements.clear();
2877 			selectedElements = copy;
2878 			copy.clear();
2879 		}
2880 		else if (editingElement)
2881 		{
2882 			Element *e1 = editingElement;
2883 			Element *e = dsq->game->createElement(e1->templateIdx, placer->position + Vector(40,40), e1->bgLayer, e1);
2884 			e->elementFlag = e1->elementFlag;
2885 			e->setElementEffectByIndex(e1->getElementEffectIndex());
2886 			//e->repeatTextureToFill(e1->isRepeatingTextureToFill());
2887 		}
2888 		dsq->game->reconstructGrid();
2889 	}
2890 	else if (editType == ET_ENTITIES)
2891 	{
2892 
2893 	}
2894 	else if (editType == ET_PATHS)
2895 	{
2896 		if (editingPath)
2897 		{
2898 			Path *p = editingPath;
2899 			Path *newp = new Path;
2900 			newp->name = p->name;
2901 			newp->nodes = p->nodes;
2902 			newp->rect = p->rect;
2903 			newp->refreshScript();
2904 			newp->pathShape = p->pathShape;
2905 			newp->nodes[0].position += Vector(64,64);
2906 
2907 			dsq->game->addPath(newp);
2908 			selectedIdx = dsq->game->getNumPaths()-1;
2909 			newp->init();
2910 		}
2911 	}
2912 }
2913 
shutdown()2914 void SceneEditor::shutdown()
2915 {
2916 	clearActions();
2917 	text = 0;
2918 	placer = 0;
2919 }
2920 
toggle()2921 void SceneEditor::toggle()
2922 {
2923 	toggle(!on);
2924 }
2925 
toggle(bool on)2926 void SceneEditor::toggle(bool on)
2927 {
2928 	if (core->getNestedMains() > 1) return;
2929 	if (dsq->game->isInGameMenu()) return;
2930 	if (!on && editType == ET_SELECTENTITY) return;
2931 	if (dsq->game->worldMapRender && dsq->game->worldMapRender->isOn()) return;
2932 	this->on = on;
2933 	autoSaveTimer = 0;
2934 
2935 	execID = -1;
2936 	if (on)
2937 	{
2938 		btnMenu->alpha = 1;
2939 		dsq->getRenderObjectLayer(LR_BLACKGROUND)->update = true;
2940 
2941 		warpAreaRender->alpha = 0.5;
2942 		dsq->game->togglePause(on);
2943 		if (dsq->game->avatar)
2944 			dsq->game->avatar->disableInput();
2945 		text->alpha.interpolateTo(1, 0.5);
2946 		placer->alpha.interpolateTo(0.5, 0.5);
2947 		movingEntity = 0;
2948 		dsq->toggleCursor(true);
2949 		dsq->setCursor(CURSOR_NORMAL);
2950 		//core->flags.set(CF_CLEARBUFFERS);
2951 
2952 		dsq->darkLayer.toggle(false);
2953 
2954 		dsq->game->rebuildElementUpdateList();
2955 
2956 		for (int i = LR_ELEMENTS1; i <= LR_ELEMENTS8; i++)
2957 		{
2958 			dsq->getRenderObjectLayer(i)->update = true;
2959 		}
2960 
2961 		oldGlobalScale = core->globalScale;
2962 		const float cameraOffset = 1/oldGlobalScale.x - 1/zoom.x;
2963 		core->cameraPos.x += cameraOffset * core->getVirtualWidth()/2;
2964 		core->cameraPos.y += cameraOffset * core->getVirtualHeight()/2;
2965 		core->globalScale = zoom;
2966 		core->globalScaleChanged();
2967 	}
2968 	else
2969 	{
2970 		btnMenu->alpha = 0;
2971 		//dsq->game->reconstructGrid();
2972 		selectedElements.clear();
2973 		for (int i = 0; i < 9; i++)
2974 			dsq->getRenderObjectLayer(LR_ELEMENTS1+i)->visible = true;
2975 
2976 		if (movingEntity)
2977 			endMoveEntity();
2978 		movingEntity = 0;
2979 
2980 		dsq->getRenderObjectLayer(LR_BLACKGROUND)->update = false;
2981 
2982 		warpAreaRender->alpha = 0;
2983 		dsq->game->togglePause(on);
2984 		if (dsq->game->avatar)
2985 			dsq->game->avatar->enableInput();
2986 		text->alpha.interpolateTo(0, 0.2);
2987 		placer->alpha.interpolateTo(0, 0.2);
2988 		//core->flags.unset(CF_CLEARBUFFERS);
2989 		dsq->darkLayer.toggle(true);
2990 
2991 		dsq->game->rebuildElementUpdateList();
2992 
2993 		const float cameraOffset = 1/oldGlobalScale.x - 1/zoom.x;
2994 		core->cameraPos.x -= cameraOffset * core->getVirtualWidth()/2;
2995 		core->cameraPos.y -= cameraOffset * core->getVirtualHeight()/2;
2996 		core->globalScale = oldGlobalScale;
2997 	}
2998 }
2999 
isOn()3000 bool SceneEditor::isOn()
3001 {
3002 	return on;
3003 }
3004 
updateText()3005 void SceneEditor::updateText()
3006 {
3007 	std::ostringstream os;
3008 	os << dsq->game->sceneName << " bgL[" << bgLayer << "] (" <<
3009 		(int)dsq->cameraPos.x << "," << (int)dsq->cameraPos.y << ") ("
3010 		//<< (int)dsq->game->avatar->position.x
3011 		//<< "," << (int)dsq->game->avatar->position.y << "," << (int)dsq->game->avatar->position.z << ")" << " ("
3012 		<< (int)dsq->getGameCursorPosition().x << "," << (int)dsq->getGameCursorPosition().y << ")" << " ";
3013 	switch(editType)
3014 	{
3015 	case ET_ELEMENTS:
3016 		os << "elements (" << dsq->getNumElements() << ")";
3017 		if (selectedElements.size() > 1)
3018 		{
3019 			os << " - " << selectedElements.size() << " selected";
3020 		}
3021 		else
3022 		{
3023 			Element *e;
3024 			if (!selectedElements.empty())
3025 				e = selectedElements[0];
3026 			else
3027 				e = editingElement;
3028 			if (e)
3029 			{
3030 				os << " id: " << e->templateIdx;
3031 				ElementTemplate *et = game->getElementTemplateByIdx(e->templateIdx);
3032 				if (et)
3033 					os << " gfx: " << et->gfx;
3034 				os << " efx: " << (e->getElementEffectIndex() + 1); // +1 so that it resembles the layout on numpad
3035 			}
3036 		}
3037 	break;
3038 	case ET_ENTITIES:
3039 		os << "entities (" << dsq->entities.size() << ")";
3040 		if (editingEntity)
3041 		{
3042 			os.precision(1);
3043 			os << std::fixed;
3044 			os << " id: " << editingEntity->getID()
3045 				<< " name: " << editingEntity->name
3046 				<< " flag:" << dsq->continuity.getEntityFlag(dsq->game->sceneName, editingEntity->getID())
3047 				<< " fh:" << editingEntity->isfh()
3048 				<< " fv:" << editingEntity->isfv()
3049 				<< " state:" << editingEntity->getState()
3050 				<< " et:" << editingEntity->getEntityType()
3051 				<< " hp:" << editingEntity->health << "/" << editingEntity->maxHealth;
3052 		}
3053 	break;
3054 	case ET_PATHS:
3055 		os << "paths (" << dsq->game->getNumPaths()<<  ") si[" << selectedIdx << "]";
3056 		if (getSelectedPath())
3057 			os << " name: " << getSelectedPath()->name;
3058 	break;
3059 	}
3060 	text->setText(os.str());
3061 }
3062 
startDrawingWarpArea(char c)3063 void SceneEditor::startDrawingWarpArea(char c)
3064 {
3065 	if (drawingWarpArea == 'N')
3066 	{
3067 		boxPos = dsq->getGameCursorPosition();
3068 		boxPromo->alpha = 1;
3069 		switch(c)
3070 		{
3071 		case 'Y': boxPromo->color = Vector(1,1,0); break;
3072 		case 'U': boxPromo->color = Vector(1,0,0); break;
3073 		case 'I': boxPromo->color = Vector(0,1,0); break;
3074 		case 'O': boxPromo->color = Vector(0,0,1); break;
3075 		case 'P': boxPromo->color = Vector(1,0,1); break;
3076 		}
3077 		drawingWarpArea = c;
3078 	}
3079 	if (drawingWarpArea == c)
3080 	{
3081 		Vector diff = dsq->getGameCursorPosition() - boxPos;
3082 		boxPromo->setWidthHeight(diff.x, diff.y);
3083 		boxPromo->position = boxPos + diff/2;
3084 	}
3085 }
3086 
updateDrawingWarpArea(char c,int k)3087 void SceneEditor::updateDrawingWarpArea(char c, int k)
3088 {
3089 	if (core->getKeyState(k))
3090 	{
3091 		startDrawingWarpArea(c);
3092 	}
3093 	else
3094 	{
3095 		endDrawingWarpArea(c);
3096 	}
3097 }
3098 
endDrawingWarpArea(char c)3099 void SceneEditor::endDrawingWarpArea(char c)
3100 {
3101 	if (drawingWarpArea == c)
3102 	{
3103 		drawingWarpArea = 'N';
3104 		boxPromo->alpha = 0;
3105 		if (boxPromo->getWidth() > TILE_SIZE && boxPromo->getHeight() > TILE_SIZE)
3106 		{
3107 			WarpArea a;
3108 			a.position = boxPromo->position;
3109 			a.w = boxPromo->getWidth()/2;
3110 			a.h = boxPromo->getHeight()/2;
3111 			switch (c)
3112 			{
3113 			case 'Y': a.warpAreaType = "Yellow"; break;
3114 			case 'U': a.warpAreaType = "Red"; break;
3115 			case 'I': a.warpAreaType = "Green"; break;
3116 			case 'O': a.warpAreaType = "Blue"; break;
3117 			case 'P': a.warpAreaType = "Purple"; break;
3118 			}
3119 
3120 			a.sceneName = dsq->getUserInputString("Enter map to warp to");
3121 			a.spawnOffset = dsq->getUserInputDirection("Enter warp direction");
3122 			dsq->game->warpAreas.push_back(a);
3123 		}
3124 	}
3125 }
3126 
getSelectedElementsCenter()3127 Vector SceneEditor::getSelectedElementsCenter()
3128 {
3129 	Vector c;
3130 	for (int i = 0; i < selectedElements.size(); i++)
3131 	{
3132 		c += selectedElements[i]->position;
3133 	}
3134 	c /= float(selectedElements.size());
3135 	return c;
3136 }
3137 
update(float dt)3138 void SceneEditor::update(float dt)
3139 {
3140 	if (on)
3141 	{
3142 		if (core->getNestedMains() > 1) return;
3143 
3144 		autoSaveTimer += dt;
3145 		if (autoSaveTimer > vars->autoSaveTime && state == ES_SELECTING)
3146 		{
3147 			autoSaveTimer = 0;
3148 			std::ostringstream os;
3149 			os << "auto/AUTO_" << autoSaveFile << "_" << dsq->game->sceneName;
3150 			if(dsq->game->saveScene(os.str()))
3151 			{
3152 				std::string m = "Map AutoSaved to " + os.str();
3153 				dsq->debugLog(m);
3154 				dsq->screenMessage(m);
3155 			}
3156 
3157 			autoSaveFile++;
3158 			if (autoSaveFile > vars->autoSaveFiles)
3159 				autoSaveFile = 0;
3160 		}
3161 
3162 		updateMultiSelect();
3163 		switch (editType)
3164 		{
3165 		case ET_ELEMENTS:
3166 			editingEntity = 0;
3167 			if (isActing(ACTION_MULTISELECT) || !selectedElements.empty())
3168 			{
3169 				editingElement = 0;
3170 			}
3171 			if (state == ES_SELECTING && !isActing(ACTION_MULTISELECT))
3172 				editingElement = this->getElementAtCursor();
3173 
3174 			if (editingElement)
3175 				placer->alpha = 0;
3176 			else
3177 				placer->alpha = 0.5;
3178 		break;
3179 		case ET_ENTITIES:
3180 			editingElement = 0;
3181 			if (state == ES_SELECTING)
3182 				editingEntity = this->getEntityAtCursor();
3183 			if (editingEntity)
3184 				placer->alpha = 0;
3185 			else
3186 				placer->alpha = 0.5;
3187 		break;
3188 		}
3189 
3190 		updateText();
3191 		ActionMapper::onUpdate(dt);
3192 
3193 		TileVector cursorTile(dsq->getGameCursorPosition());
3194 		Vector p = Vector(cursorTile.x*TILE_SIZE+TILE_SIZE/2, cursorTile.y*TILE_SIZE+TILE_SIZE/2);
3195 		placer->position = p;
3196 
3197 		int camSpeed = 500/zoom.x;
3198 		if (core->getShiftState())
3199 			camSpeed = 5000/zoom.x;
3200 		if (isActing(ACTION_CAMLEFT))
3201 			dsq->cameraPos.x -= dt*camSpeed;
3202 		if (isActing(ACTION_CAMRIGHT))
3203 			dsq->cameraPos.x += dt*camSpeed;
3204 		if (isActing(ACTION_CAMUP))
3205 			dsq->cameraPos.y -= dt*camSpeed;
3206 		if (isActing(ACTION_CAMDOWN))
3207 			dsq->cameraPos.y += dt*camSpeed;
3208 		if (core->mouse.buttons.middle && !core->mouse.change.isZero())
3209 		{
3210 			dsq->cameraPos += core->mouse.change*(4/zoom.x);
3211 			core->setMousePosition(core->mouse.lastPosition);
3212 		}
3213 
3214 		float spd = 0.5;
3215 		const Vector oldZoom = zoom;
3216 		if (isActing(ACTION_ZOOMOUT))
3217 			zoom /= (1 + spd*dt);
3218 		else if (isActing(ACTION_ZOOMIN))
3219 			zoom *= (1 + spd*dt);
3220 		else if (core->mouse.scrollWheelChange < 0)
3221 		{
3222 			if (core->getShiftState() && !core->getCtrlState()) // hackish: to prevent accidental recache()
3223 				nextElement();
3224 			else
3225 				zoom /= 1.12f;
3226 		}
3227 		else if (core->mouse.scrollWheelChange > 0)
3228 		{
3229 			if (core->getShiftState() && !core->getCtrlState()) // hackish: to prevent accidental entity selection
3230 				prevElement();
3231 			else
3232 				zoom *= 1.12f;
3233 		}
3234 		if (zoom.x < 0.04f)
3235 			zoom.x = zoom.y = 0.04f;
3236 		core->globalScale = zoom;
3237 		core->globalScaleChanged();
3238 		if (zoom.x != oldZoom.x)
3239 		{
3240 			const float mouseX = core->mouse.position.x;
3241 			const float mouseY = core->mouse.position.y;
3242 			dsq->cameraPos.x += mouseX/oldZoom.x - mouseX/zoom.x;
3243 			dsq->cameraPos.y += mouseY/oldZoom.y - mouseY/zoom.y;
3244 		}
3245 
3246 		if (this->editType == ET_PATHS)
3247 		{
3248 			switch(state)
3249 			{
3250 			case ES_SELECTING:
3251 			{
3252 				selectedIdx = -1;
3253 				selectedNode = -1;
3254 				float smallestDist = sqr(64);
3255 				for (int i = 0; i < dsq->game->getNumPaths(); i++)
3256 				{
3257 					for (int n = dsq->game->getPath(i)->nodes.size()-1; n >=0; n--)
3258 					{
3259 						Vector v = dsq->game->getPath(i)->nodes[n].position - dsq->getGameCursorPosition();
3260 						float dist = v.getSquaredLength2D();
3261 						if (dist < smallestDist)
3262 						{
3263 							smallestDist = dist;
3264 							selectedIdx = i;
3265 							selectedNode = n;
3266 							//return;
3267 						}
3268 					}
3269 				}
3270 			}
3271 			break;
3272 			case ES_SCALING:
3273 			{
3274 				if (editingPath)
3275 				{
3276 					float factor = 1;
3277 					Vector add = Vector((dsq->getGameCursorPosition().x - cursorOffset.x)*factor,
3278 						(dsq->getGameCursorPosition().y - cursorOffset.y)*factor);
3279 					Vector sz = oldScale + add;
3280 					if (sz.x < 32)
3281 						sz.x = 32;
3282 					if (sz.y < 32)
3283 						sz.y = 32;
3284 					editingPath->rect.x1 = -sz.x/2;
3285 					editingPath->rect.x2 = sz.x/2;
3286 					editingPath->rect.y1 = -sz.y/2;
3287 					editingPath->rect.y2 = sz.y/2;
3288 				}
3289 			}
3290 			break;
3291 			case ES_MOVING:
3292 				if (selectedIdx >= 0)
3293 					dsq->game->getPath(selectedIdx)->nodes[selectedNode].position = dsq->getGameCursorPosition() + cursorOffset;
3294 			break;
3295 			}
3296 		}
3297 		else if (editType == ET_ENTITIES)
3298 		{
3299 			switch(state)
3300 			{
3301 			case ES_MOVING:
3302 				if (editingEntity)
3303 					editingEntity->position = dsq->getGameCursorPosition() + cursorOffset;
3304 			break;
3305 			case ES_ROTATING:
3306 			{
3307 				if (editingEntity)
3308 				{
3309 					float add = (dsq->getGameCursorPosition().x - cursorOffset.x)/2.4f;
3310 					if (core->getCtrlState())
3311 					{
3312 						int a = (oldRotation.z + add)/45;
3313 						add = a * 45;
3314 						editingEntity->rotation.z = add;
3315 					}
3316 					else
3317 					{
3318 						editingEntity->rotation.z = oldRotation.z + add;
3319 					}
3320 				}
3321 			}
3322 			}
3323 		}
3324 		else if (editType == ET_ELEMENTS)
3325 		{
3326 			switch(state)
3327 			{
3328 			case ES_SELECTING:
3329 			{
3330 				float closest = sqr(800);
3331 				int idx = -1, i = 0;
3332 				for (i = 0; i < dsq->getNumElements(); i++)
3333 				{
3334 					Vector dist = dsq->getElement(i)->getFollowCameraPosition() - dsq->getGameCursorPosition();
3335 					float len = dist.getSquaredLength2D();
3336 					if (len < closest)
3337 					{
3338 						closest = len;
3339 						idx = i;
3340 					}
3341 				}
3342 			}
3343 			break;
3344 			case ES_MOVING:
3345 				updateSelectedElementPosition(dsq->getGameCursorPosition() - cursorOffset);
3346 			break;
3347 			case ES_ROTATING:
3348 			{
3349 				if (!selectedElements.empty())
3350 				{
3351 
3352 					float add = (dsq->getGameCursorPosition().x - cursorOffset.x)/2.4f;
3353 					if (core->getCtrlState())
3354 					{
3355 						int a = (oldRotation.z + add)/45;
3356 						add = a * 45;
3357 						dummy.rotation.z = add;
3358 					}
3359 					else
3360 					{
3361 						dummy.rotation.z = oldRotation.z + add;
3362 					}
3363 				}
3364 				else if (editingElement)
3365 				{
3366 					float add = (dsq->getGameCursorPosition().x - cursorOffset.x)/2.4f;
3367 					if (core->getCtrlState())
3368 					{
3369 						int a = (oldRotation.z + add)/45;
3370 						add = a * 45;
3371 						editingElement->rotation.z = add;
3372 					}
3373 					else
3374 					{
3375 						editingElement->rotation.z = oldRotation.z + add;
3376 					}
3377 				}
3378 			}
3379 			break;
3380 			case ES_SCALING:
3381 			{
3382 				bool right=false, middle=false, down=false, uni=false, repeatScale=false;
3383 				bool noSide = 0;
3384 				if (cursorOffset.x > oldPosition.x+10)
3385 					right = true;
3386 				else if (cursorOffset.x < oldPosition.x-10)
3387 					right = false;
3388 				else
3389 					noSide++;
3390 				if (cursorOffset.y > oldPosition.y+10)
3391 					down = true;
3392 				else if (cursorOffset.y < oldPosition.y-10)
3393 					down = false;
3394 				else if (noSide)
3395 					middle = true;
3396 
3397 				Vector add = Vector((dsq->getGameCursorPosition().x - cursorOffset.x)/100.0f,
3398 					(dsq->getGameCursorPosition().y - cursorOffset.y)/100.0f);
3399 				{
3400 					if (!selectedElements.empty())
3401 						add.y = add.x;
3402 					else
3403 					{
3404 						if (core->getKeyState(KEY_C))
3405 						{
3406 							add.y = 0;
3407 							if (!right && !middle)
3408 								add.x *= -1;
3409 						}
3410 						else if (core->getKeyState(KEY_V))
3411 						{
3412 							add.x = 0;
3413 							if (!down && !middle)
3414 								add.y *= -1;
3415 						}
3416 						else
3417 						{
3418 							add.y = add.x;
3419 							uni = true;
3420 						}
3421 
3422 						repeatScale = core->getKeyState(KEY_X);
3423 						if(repeatScale)
3424 							add *= 0.1f;
3425 					}
3426 				}
3427 				if (!selectedElements.empty())
3428 				{
3429 					if (core->getCtrlState())
3430 					{
3431 						dummy.scale = Vector(1,1);
3432 					}
3433 					else
3434 					{
3435 						dummy.scale=oldScale + add;
3436 						if (dummy.scale.x < MIN_SIZE)
3437 							dummy.scale.x  = MIN_SIZE;
3438 						if (dummy.scale.y < MIN_SIZE)
3439 							dummy.scale.y  = MIN_SIZE;
3440 					}
3441 
3442 					for (int i = 0; i < selectedElements.size(); i++)
3443 						selectedElements[i]->refreshRepeatTextureToFill();
3444 				}
3445 				else if (editingElement)
3446 				{
3447 					Vector& editVec = repeatScale ? editingElement->repeatToFillScale : editingElement->scale;
3448 					if (core->getCtrlState())
3449 					{
3450 						editVec = Vector(1,1);
3451 					}
3452 					else
3453 					{
3454 						//editingElement->scale=oldScale + add;
3455 						editVec = (repeatScale ? oldRepeatScale : oldScale) + add;
3456 						if (!uni && !repeatScale)
3457 						{
3458 							if (!middle)
3459 							{
3460 								Vector offsetChange = (add*Vector(editingElement->getWidth(), editingElement->getHeight()))*0.5f;
3461 								if (add.y == 0)
3462 								{
3463 									if (right)
3464 										editingElement->beforeScaleOffset = offsetChange;
3465 									else
3466 										editingElement->beforeScaleOffset = -offsetChange;
3467 								}
3468 								else
3469 								{
3470 									if (down)
3471 										editingElement->beforeScaleOffset = offsetChange;
3472 									else
3473 										editingElement->beforeScaleOffset = -offsetChange;
3474 								}
3475 							}
3476 						}
3477 						if (editVec.x < MIN_SIZE)
3478 							editVec.x  = MIN_SIZE;
3479 						if (editVec.y < MIN_SIZE)
3480 							editVec.y  = MIN_SIZE;
3481 					}
3482 
3483 					editingElement->refreshRepeatTextureToFill();
3484 				}
3485 			}
3486 			break;
3487 			}
3488 		}
3489 	}
3490 }
3491 
nextEntityType()3492 void SceneEditor::nextEntityType()
3493 {
3494 	if (editType == ET_ELEMENTS && state == ES_SELECTING)
3495 	{
3496 		if (editingElement || !selectedElements.empty())
3497 		{
3498 			enterMoveState();
3499 			updateSelectedElementPosition(Vector(1,0));
3500 			exitMoveState();
3501 		}
3502 	}
3503 	else if (editType == ET_SELECTENTITY)
3504 	{
3505 		nextEntityPage();
3506 	}
3507 }
3508 
prevEntityType()3509 void SceneEditor::prevEntityType()
3510 {
3511 	if (editType == ET_ELEMENTS && state == ES_SELECTING)
3512 	{
3513 		if (editingElement || !selectedElements.empty())
3514 		{
3515 			enterMoveState();
3516 			updateSelectedElementPosition(Vector(-1,0));
3517 			exitMoveState();
3518 		}
3519 	}
3520 	else if (editType == ET_SELECTENTITY)
3521 	{
3522 		prevEntityPage();
3523 	}
3524 }
3525 
dumpObs()3526 void SceneEditor::dumpObs()
3527 {
3528 	TileVector tv;
3529 	unsigned char *data = new unsigned char[MAX_GRID * MAX_GRID * sizeof(uint32)];
3530 	uint32 *ptr = (uint32*)data;
3531 	for(tv.y = MAX_GRID - 1; ; --tv.y)
3532 	{
3533 		for(tv.x = 0; tv.x < MAX_GRID; ++tv.x)
3534 			*ptr++ = game->isObstructed(tv, OT_MASK_BLACK) ? 0xFF000000 : 0xFFFFFFFF;
3535 		if(tv.y == 0)
3536 			break;
3537 	}
3538 	std::string outfn = dsq->getUserDataFolder() + "/griddump-" + game->sceneName + ".tga";
3539 	core->tgaSave(outfn.c_str(), MAX_GRID, MAX_GRID, 32, data);
3540 	dsq->screenMessage("Saved grid image to " + outfn);
3541 }
3542 
3543 
3544 #endif  // AQUARIA_BUILD_SCENEEDITOR
3545