1 /*
2  * Holotz's Castle
3  * Copyright (C) 2004 Juan Carlos Seijo P�rez
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc., 59
17  * Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Juan Carlos Seijo P�rez
20  * jacob@mainreactor.net
21  */
22 
23 /** Level editor for Holotz's Castle.
24  * @file    HCed.cpp
25  * @author  Juan Carlos Seijo P�rez
26  * @date    30/05/2004
27  * @version 0.0.1 - 30/05/2004 - First version
28  * @version 0.0.2 - 30/05/2004 - Install support, Miriam Ruiz (Debian package). Load/Create story support.
29  */
30 
31 #include <HCed.h>
32 
33 #ifndef _WIN32
34 #include <unistd.h>
35 #endif
36 
37 #ifndef HC_DATA_DIR
38 #define HC_DATA_DIR "res/"
39 #endif
40 
41 #ifndef HCED_DATA_DIR
42 #define HCED_DATA_DIR "HCedHome/res/"
43 #endif
44 
45 /** This application.
46  */
47 HCed *theApp;
48 HCPreferences prefs;
49 
PrintUsage(char * program)50 void HCed::PrintUsage(char *program)
51 {
52 	fprintf(stderr, "HCed v1.3. (C) Juan Carlos Seijo P�rez - 2004.\n\n");
53 	fprintf(stderr, "Usage: %s [-t themeName] [story name] [levelToLoad]", program);
54 	fprintf(stderr, " [-h] [-r numRows] [-c numColumns]");
55 	fprintf(stderr, " [-f]ullscreen [-w]indowed [--fps nnn] [-mWxHxBPP]\n");
56 	fprintf(stderr, "\n");
57 	exit(0);
58 }
59 
OnKeyUp(SDL_keysym key)60 void HCed::OnKeyUp(SDL_keysym key)
61 {
62 	if (theApp->state == HCEDSTATE_OPENSTORY)
63 	{
64 		if (key.sym == SDLK_ESCAPE)
65 		{
66 			// Ends opening/creating the a story
67 			theApp->OnFloor(0);
68 			theApp->inputNewStory = 0;
69 		}
70 
71 		if (HCED_INPUT_STORY == theApp->inputNewStory)
72 		{
73 			bool upd = false;
74 
75 			if ((key.sym >= SDLK_0 && key.sym <= SDLK_9) ||
76 					(key.sym >= SDLK_a && key.sym <= SDLK_z) ||
77 					key.sym == SDLK_MINUS)
78 			{
79 				if (key.sym == SDLK_MINUS && (theApp->KeyMods() & KMOD_SHIFT))
80 				{
81 					theApp->strNewStoryName += '_';
82 				}
83 				else
84 				{
85 					if ((theApp->KeyMods() & KMOD_SHIFT))
86 					{
87 						theApp->strNewStoryName += toupper(key.sym);
88 					}
89 					else
90 					{
91 						theApp->strNewStoryName += key.sym;
92 					}
93 				}
94 
95 				upd = true;
96 			}
97 			else
98 			if (key.sym == SDLK_DELETE || key.sym == SDLK_BACKSPACE)
99 			{
100 				// Deletes last character
101 				if (theApp->strNewStoryName.Length() > 0)
102 				{
103 					JString str(theApp->strNewStoryName, 0, theApp->strNewStoryName.Length() - 1);
104 					theApp->strNewStoryName = str;
105 					upd = true;
106 				}
107 			}
108 			else
109 			if (key.sym == SDLK_RETURN || key.sym == SDLK_KP_ENTER)
110 			{
111 				theApp->inputNewStory = HCED_INPUT_THEME;
112 
113 				// Updates the input string
114 				JDELETE(theApp->imgNewStory);
115 				SDL_Color fg = {0xff, 0xcc, 0x00, 0x00};
116 				SDL_Color bg = {0x00, 0x00, 0x00, 0x00};
117 				theApp->imgNewStory = theApp->fontLarge.RenderTextShaded("Select a theme", fg, bg);
118 			}
119 
120 			if (upd)
121 			{
122 				// Updates the input string
123 				JDELETE(theApp->imgNewStory);
124 				SDL_Color fg = {0xff, 0xcc, 0x00, 0x00};
125 				SDL_Color bg = {0x00, 0x00, 0x00, 0x00};
126 				theApp->imgNewStory = theApp->fontLarge.RenderTextShaded((const char *)(JString("Name: ") + theApp->strNewStoryName), fg, bg);
127 			}
128 		}
129 		else
130 		if (HCED_INPUT_THEME == theApp->inputNewStory)
131 		{
132 			theApp->menuTheme->TrackKeyboard(key);
133 		}
134 		else
135 		{
136 			theApp->menuOpenStory->TrackKeyboard(key);
137 		}
138 
139 		return;
140 	}
141 
142 	switch (key.sym)
143 	{
144 		case SDLK_1:
145 			OnFloor(0);
146 			break;
147 
148 		case SDLK_2:
149 			OnContFloor(0);
150 			break;
151 
152 		case SDLK_3:
153 			OnLadder(0);
154 			break;
155 
156 		case SDLK_4:
157 			OnBar(0);
158 			break;
159 
160 		case SDLK_5:
161 			OnBreak(0);
162 			break;
163 
164 		case SDLK_6:
165 			OnObject(0);
166 			break;
167 
168 		case SDLK_7:
169 			OnRope(0);
170 			break;
171 
172 		case SDLK_8:
173 			OnStart(0);
174 			break;
175 
176 		case SDLK_9:
177 			OnExit(0);
178 			break;
179 
180 		case SDLK_0:
181 			OnEnemy(0);
182 			break;
183 
184 		case SDLK_s:
185 			OnSave(0);
186 			break;
187 
188 		case SDLK_PAGEUP:
189 			switch (theApp->PrevLevel())
190 			{
191 			case -1:
192 				fprintf(stderr, "HCed: Error going to previous level.\n");
193 				break;
194 
195 			case 1:
196 				fprintf(stderr, "HCed: This is the first level.\n");
197 				break;
198 
199 			case 0:
200 			default:
201 				break;
202 			}
203 			break;
204 
205 		case SDLK_PAGEDOWN:
206 			if (theApp->NextLevel() < 0)
207 			{
208 				fprintf(stderr, "HCed: Error going to next level.\n");
209 			}
210 			break;
211 
212 		case SDLK_q:
213 			if (theApp->KeyMods() & KMOD_CTRL)
214 			{
215 				theApp->Exit();
216 			}
217 			break;
218 
219 		default:
220 			break;
221 	}
222 }
223 
OnKeyDown(SDL_keysym key)224 void HCed::OnKeyDown(SDL_keysym key)
225 {
226 	switch (key.sym)
227 	{
228 		// Scrolls down the map
229 	case SDLK_UP:
230 		{
231 			HCMap *map = &theApp->level.Map();
232 
233 			if (map->Y() < HCED_MARGIN)
234 			{
235 				theApp->level.Pos((s32)map->X(),
236 													(s32)map->Y() + map->CellHeight());
237 			}
238 			else
239 			if (map->Y() > HCED_MARGIN && map->Height() > float(theApp->Height() - HCED_MARGIN))
240 			{
241 				theApp->level.Pos((s32)map->X(), HCED_MARGIN);
242 			}
243 		}
244 		break;
245 
246 		// Scrolls up the map
247 	case SDLK_DOWN:
248 		{
249 			HCMap *map = &theApp->level.Map();
250 
251 			if (map->Y() + map->Height() > theApp->Height())
252 			{
253 				theApp->level.Pos((s32)map->X(),
254 													(s32)map->Y() - map->CellHeight());
255 			}
256 			else
257 			if (map->Y() + map->Height() > theApp->Height() &&
258 					map->Height() > theApp->Height() - HCED_MARGIN)
259 			{
260 				theApp->level.Pos((s32)map->X(), HCED_MARGIN);
261 			}
262 		}
263 		break;
264 
265 		// Scrolls right the map
266 	case SDLK_LEFT:
267 		{
268 			HCMap *map = &theApp->level.Map();
269 
270 			if (map->X() < HCED_MARGIN)
271 			{
272 				theApp->level.Pos((s32)map->X() + map->CellWidth(),
273 													(s32)map->Y());
274 			}
275 			else
276 			if (map->X() > HCED_MARGIN && map->Width() > float(theApp->Width() - HCED_MARGIN))
277 			{
278 				theApp->level.Pos(HCED_MARGIN, (s32)map->Y());
279 			}
280 		}
281 		break;
282 
283 		// Scrolls left the map
284 	case SDLK_RIGHT:
285 		{
286 			HCMap *map = &theApp->level.Map();
287 
288 			if (map->X() + map->Width() > theApp->Width())
289 			{
290 				theApp->level.Pos((s32)map->X() - map->CellWidth(),
291 													(s32)map->Y());
292 			}
293 			else
294 			if (map->X() + map->Width() > theApp->Width() &&
295 					map->Width() > theApp->Width() - HCED_MARGIN)
296 			{
297 				theApp->level.Pos(HCED_MARGIN, (s32)map->Y());
298 			}
299 		}
300 		break;
301 
302 	case SDLK_KP_PLUS:
303 		{
304 			// Time to complete level up
305 			theApp->level.maxTime += 1;
306 			if (theApp->level.maxTime > 0xffff)
307 			{
308 				theApp->level.maxTime = 0xffff;
309 			}
310 			theApp->level.levelTimer.Init(theApp->level.maxTime, &theApp->fontNormal);
311 		}
312 		break;
313 
314 	case SDLK_KP_MINUS:
315 		{
316 			// Time to complete level down
317 			theApp->level.maxTime -= 1;
318 			if (theApp->level.maxTime == 0)
319 			{
320 				theApp->level.maxTime = 1;
321 			}
322 
323 			theApp->level.levelTimer.Init(theApp->level.maxTime, &theApp->fontNormal);
324 		}
325 		break;
326 
327 	case SDLK_g:
328 		{
329 			if ((SDL_GetModState() & KMOD_SHIFT))
330 			{
331 				// Map gravity down
332 				theApp->level.map.Gravity(theApp->level.map.Gravity() - 0.1f);
333 			}
334 			else
335 			{
336 				// Map gravity up
337 				theApp->level.map.Gravity(theApp->level.map.Gravity() + 0.1f);
338 			}
339 
340 			OnGravityChange();
341 		}
342 		break;
343 
344 	case SDLK_x:
345 		{
346 			if ((SDL_GetModState() & KMOD_SHIFT))
347 			{
348 				// Main character's Vx down
349 				theApp->level.character.MaxVeloccity().x -= 0.1f;
350 			}
351 			else
352 			{
353 				// Main character's Vx up
354 				theApp->level.character.MaxVeloccity().x += 0.1f;
355 			}
356 
357 			OnCharVxChange();
358 		}
359 		break;
360 
361 	case SDLK_y:
362 		{
363 			if ((SDL_GetModState() & KMOD_SHIFT))
364 			{
365 				// Main character's Vy down
366 				theApp->level.character.MaxVeloccity().y -= 0.1f;
367 			}
368 			else
369 			{
370 				// Main character's Vy up
371 				theApp->level.character.MaxVeloccity().y += 0.1f;
372 			}
373 
374 			OnCharVyChange();
375 		}
376 		break;
377 
378 	case SDLK_j:
379 		{
380 			if ((SDL_GetModState() & KMOD_SHIFT))
381 			{
382 				// Main character's max jump rows down
383 				theApp->level.character.MaxJumpRows(theApp->level.character.MaxJumpRows() - 1);
384 			}
385 			else
386 			{
387 				// Main character's max jump rows up
388 				theApp->level.character.MaxJumpRows(theApp->level.character.MaxJumpRows() + 1);
389 			}
390 
391 			OnCharJumpRowsChange();
392 		}
393 		break;
394 
395 	case SDLK_r:
396 		{
397 			if ((SDL_GetModState() & KMOD_SHIFT))
398 			{
399 				if ((SDL_GetModState() & KMOD_CTRL))
400 				{
401 					// Decrease number of rows from the top
402 					theApp->level.map.Resize(theApp->level.map.Rows() - 1, theApp->level.map.Cols(), true, false);
403 				}
404 				else
405 				{
406 					// Decrease number of rows from the bottom
407 					theApp->level.map.Resize(theApp->level.map.Rows() - 1, theApp->level.map.Cols());
408 				}
409 			}
410 			else
411 			{
412 				if ((SDL_GetModState() & KMOD_CTRL))
413 				{
414 					// Increase number of rows from the top
415 					theApp->level.map.Resize(theApp->level.map.Rows() + 1, theApp->level.map.Cols(), true, false);
416 				}
417 				else
418 				{
419 					// Increase number of rows from the bottom
420 					theApp->level.map.Resize(theApp->level.map.Rows() + 1, theApp->level.map.Cols());
421 				}
422 			}
423 
424 			OnMapSizeChange();
425 		}
426 		break;
427 
428 	case SDLK_c:
429 		{
430 			if ((SDL_GetModState() & KMOD_SHIFT))
431 			{
432 				if ((SDL_GetModState() & KMOD_CTRL))
433 				{
434 					// Decrease number of columns from the left
435 					theApp->level.map.Resize(theApp->level.map.Rows(), theApp->level.map.Cols() - 1, false);
436 				}
437 				else
438 				{
439 					// Decrease number of columns from the right
440 					theApp->level.map.Resize(theApp->level.map.Rows(), theApp->level.map.Cols() - 1);
441 				}
442 			}
443 			else
444 			{
445 				if ((SDL_GetModState() & KMOD_CTRL))
446 				{
447 					// Increase number of columns from the left
448 					theApp->level.map.Resize(theApp->level.map.Rows(), theApp->level.map.Cols() + 1, false);
449 				}
450 				else
451 				{
452 					// Increase number of columns from the right
453 					theApp->level.map.Resize(theApp->level.map.Rows(), theApp->level.map.Cols() + 1);
454 				}
455 			}
456 
457 			OnMapSizeChange();
458 		}
459 		break;
460 
461   default:
462     break;
463 	}
464 }
465 
OnMouseUp(s32 bt,s32 x,s32 y)466 void HCed::OnMouseUp(s32 bt, s32 x, s32 y)
467 {
468 	switch (theApp->state)
469 	{
470 	case HCEDSTATE_FLOOR:
471 		theApp->menuFloorSubtype->TrackMouse(bt, x, y);
472 		break;
473 	case HCEDSTATE_CONTFLOOR:
474 		theApp->menuContFloorSubtype->TrackMouse(bt, x, y);
475 		break;
476 	case HCEDSTATE_LADDER:
477 		theApp->menuLadderSubtype->TrackMouse(bt, x, y);
478 		break;
479 	case HCEDSTATE_BAR:
480 		theApp->menuBarSubtype->TrackMouse(bt, x, y);
481 		break;
482 	case HCEDSTATE_BREAK:
483 		theApp->menuBreakSubtype->TrackMouse(bt, x, y);
484 		break;
485 	case HCEDSTATE_OBJECT:
486 		theApp->curObject = 0;
487 		theApp->menuObjectSubtype->TrackMouse(bt, x, y);
488 		break;
489 	case HCEDSTATE_ROPE:
490 		theApp->curRope = 0;
491 		theApp->menuRopePeriod->TrackMouse(bt, x, y);
492 		theApp->menuRopeSubtype->TrackMouse(bt, x, y);
493 		break;
494 	case HCEDSTATE_START:
495 		theApp->menuMainSubtype->TrackMouse(bt, x, y);
496 		break;
497 	case HCEDSTATE_EXIT:
498 		break;
499 	case HCEDSTATE_ENEMY:
500 		theApp->curEnemy = 0;
501 		theApp->menuEnemyType->TrackMouse(bt, x, y);
502 		theApp->menuEnemySubtype[theApp->enemyType]->TrackMouse(bt, x, y);
503 		theApp->menuEnemyParam1->TrackMouse(bt, x, y);
504 		theApp->menuEnemyParam2->TrackMouse(bt, x, y);
505 		break;
506 	case HCEDSTATE_SAVE:
507 		break;
508 
509 	case HCEDSTATE_OPENSTORY:
510 		switch (theApp->inputNewStory)
511 		{
512 		case 0:
513 			theApp->menuOpenStory->TrackMouse(bt, x, y);
514 			break;
515 
516 		case HCED_INPUT_THEME:
517 			theApp->menuTheme->TrackMouse(bt, x, y);
518 			break;
519 
520 		default:
521 			break;
522 		}
523 		break;
524 
525 	case HCEDSTATE_APPEXIT:
526 		break;
527 	default:
528 		break;
529 	}
530 
531 	theApp->menuMain->TrackMouse(bt, x, y);
532 }
533 
OnMouseDown(s32 bt,s32 x,s32 y)534 void HCed::OnMouseDown(s32 bt, s32 x, s32 y)
535 {
536 	switch (theApp->state)
537 	{
538 	case HCEDSTATE_OBJECT:
539 		theApp->curObject = 0;
540 		HCObject *obj;
541 
542 		// Checks for objects bellow the mouse cursor
543 		for (s32 i = 0;	i < theApp->level.numObjects; ++i)
544 		{
545 			obj = theApp->level.objects[i];
546 
547 			if (theApp->MouseX() > obj->X() - obj->Normal().MaxW()/2 &&
548 					theApp->MouseX() < obj->X() + obj->Normal().MaxW()/2 &&
549 					theApp->MouseY() > obj->Y() - obj->Normal().MaxH() &&
550 					theApp->MouseY() < obj->Y())
551 			{
552 				theApp->curObject = theApp->level.objects[i];
553 			}
554 		}
555 		break;
556 
557 	case HCEDSTATE_ROPE:
558 		theApp->curRope = 0;
559 
560 		// Checks for ropes bellow the mouse cursor
561 		for (s32 i = 0;	i < theApp->level.numRopes; ++i)
562 		{
563 			if (theApp->MouseX() > (theApp->level.ropes[i])->X() - theApp->level.Map().CellWidth()/2 &&
564 					theApp->MouseX() < (theApp->level.ropes[i])->X() + theApp->level.Map().CellWidth()/2 &&
565 					theApp->MouseY() > (theApp->level.ropes[i])->Y() &&
566 					theApp->MouseY() < (theApp->level.ropes[i])->Y() + theApp->level.Map().CellHeight())
567 			{
568 				theApp->curRope = theApp->level.ropes[i];
569 			}
570 		}
571 
572 		if (theApp->curRope)
573 		{
574 			// Sets the period
575 			if (theApp->ropePeriod != theApp->curRope->Period())
576 			{
577 				theApp->curRope->Init(theApp->ropePeriod,
578 															theApp->curRope->Amplitude(),
579 															theApp->curRope->Length(),
580 															theApp->level.Theme());
581 			}
582 		}
583 		break;
584 
585 	case HCEDSTATE_ENEMY:
586 		theApp->curEnemy = 0;
587 
588 		// Checks for enemies bellow the mouse cursor
589 		for (s32 i = 0; i < theApp->level.numEnemies; ++i)
590 		{
591 			if (theApp->MouseX() > (theApp->level.enemies[i])->X() - (theApp->level.enemies[i]->states[HCCS_STOP].MaxW()/2) &&
592 					theApp->MouseX() < (theApp->level.enemies[i])->X() + (theApp->level.enemies[i]->states[HCCS_STOP].MaxW()/2) &&
593 					theApp->MouseY() > (theApp->level.enemies[i])->Y() - (theApp->level.enemies[i]->states[HCCS_STOP].MaxH()/2) &&
594 					theApp->MouseY() < (theApp->level.enemies[i])->Y())
595 			{
596 				theApp->curEnemy = theApp->level.enemies[i];
597 			}
598 		}
599 		break;
600 
601 	default:
602 		break;
603 	}
604 }
605 
ParseArg(char * args[],int argc)606 int HCed::ParseArg(char *args[], int argc)
607 {
608 	printf("Parsing %d args %s\n", argc, args[0]);
609 	if (args[0][0] != '-')
610 	{
611 		// Argument without score, treat it as the story name
612 		storyName = args[0];
613 
614 		if (argc < 2)
615 		{
616 			levelNumber = 1;
617 
618 			return 0; // no aditional arguments needed
619 		}
620 
621 		levelNumber = atoi(args[1]);
622 
623 		if (levelNumber <= 0)
624 		{
625 			levelNumber = 1;
626 			fprintf(stderr, "HCed: The level number must be greater than 0, defaulting to 1.\n");
627 		}
628 		return 1; // 1 aditional argument used
629 	}
630 
631 	switch (args[0][1])
632 	{
633 		// '-t themeName' option
634 		case 't':
635 			if (argc<2)
636 				return -2;
637 			themeName = args[1];
638 			return 1;
639 
640 		// '-r numRows' option
641 		case 'r':
642 			if (argc<2)
643 				return -2;
644 			defRows = atoi(args[1]);
645 
646 			if (defRows <= 0)
647 			{
648 				defRows = 10;
649 			}
650 			return 1;
651 
652 		// '-c numCols' option
653 		case 'c':
654 			if (argc<2)
655 				return -2;
656 			defCols = atoi(args[1]);
657 
658 			if (defCols <= 0)
659 			{
660 				defCols = 10;
661 			}
662 			return 1;
663 	}
664 
665 	return JApp::ParseArg(args, argc);
666 }
667 
ParseArgs(s32 argc,char ** argv)668 void HCed::ParseArgs(s32 argc, char **argv)
669 {
670 	JApp::ParseArgs(argc, argv);
671 
672 	char str[4096];
673 
674 #ifndef _WIN32
675 	char *home;
676 	home = getenv("HOME");
677 	if (home != NULL)
678 	{
679 		snprintf(str, sizeof(str), "%s/.holotz-castle", home);
680 		mkdir(str, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
681 		snprintf(str, sizeof(str), "%s/.holotz-castle/stories", home);
682 		mkdir(str, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
683 		snprintf(str, sizeof(str), "%s/.holotz-castle/stories/%s", home, storyName.Str());
684 		mkdir(str, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
685 	}
686 #endif
687 
688 	if (!HCUtil::FindFile("stories"))
689 	{
690 		fprintf(stderr, "Directory 'stories' not found. Check manual.\n");
691 		exit(-1);
692 	}
693 	else
694 	{
695 		// Assigns this directory as the default working directory
696 		storyDir = HCUtil::File();
697 		storyDir += "/";
698 	}
699 
700 	if (levelNumber == -1)
701 	{
702 		// Selects the next file name from the requested story
703 		levelNumber = 1;
704 
705 		snprintf(str, sizeof(str), "%s%s/level%03d.hlv", storyDir.Str(), storyName.Str(), levelNumber);
706 		while (JFile::Exists(str))
707 		{
708 			snprintf(str, sizeof(str), "%s%s/level%03d.hlv", storyDir.Str(), storyName.Str(), ++levelNumber);
709 		}
710 
711 		filename = str;
712 	}
713 	else
714 	{
715 		// Sets the name of the requested story and level number.
716 		snprintf(str, sizeof(str), "%s%s/level%03d.hlv", storyDir.Str(), storyName.Str(), levelNumber);
717 		filename = str;
718 	}
719 
720 	OnFilenameChange();
721 }
722 
HCed()723 HCed::HCed() : JApp("HCed v1.1", HCED_REFAPPWIDTH, HCED_REFAPPHEIGHT, false)
724 {
725 	state = HCEDSTATE_FLOOR;
726 	SetOnMouseUp(&OnMouseUp);
727 	SetOnMouseDown(&OnMouseDown);
728 	SetOnKeyUp(&OnKeyUp);
729 	SetOnKeyDown(&OnKeyDown);
730 	doInput = true;
731 	curObject = 0;
732 	curRope = 0;
733 	curEnemy = 0;
734 	defRows = defCols = 10;
735 	enemyParam1 = 1;
736 	enemyParam2 = 1;
737 	imgNewStory = 0;
738 	imgGravity = 0;
739 	imgCharVx = 0;
740 	imgCharVy = 0;
741 	imgCharJumpRows = 0;
742 	imgMapSize = 0;
743 	levelNumber = -1;
744 	menuMain = 0;
745 	menuEnemyType = 0;
746 	menuEnemyParam1 = 0;
747 	menuEnemyParam2 = 0;
748 	menuOpenStory = 0;
749 	menuTheme = 0;
750 	menuRopePeriod = 0;
751 	menuMainSubtype = 0;
752 	menuBreakSubtype = 0;
753 	menuObjectSubtype = 0;
754 	menuFloorSubtype = 0;
755 	menuContFloorSubtype = 0;
756 	menuBarSubtype = 0;
757 	menuLadderSubtype = 0;
758 	menuRopeSubtype = 0;
759 	appBackColor = 0;
760 
761 	for (s32 i = 0; i < HCENEMYTYPE_COUNT; ++i)
762 	{
763 		menuEnemySubtype[i] = 0;
764 	}
765 
766 	storyName = "unknown";
767 	themeName = "default";
768 	inputNewStory = 0;
769 }
770 
LoadLevel()771 s32 HCed::LoadLevel()
772 {
773 	// If the level exists, loads it
774 	bool ok = false;
775 
776 	// Sets the timer font
777 	level.SetTimerFont(&fontNormal);
778 
779 	if (JFile::Exists(filename))
780 	{
781 		JRW f;
782 		if (f.Create(filename, "rb"))
783 		{
784 			if (0 == level.Load(f, filename))
785 			{
786 				if (InitLoadedLevel())
787 				{
788 					ok = true;
789 				}
790 				else
791 				{
792 					fprintf(stderr, "Could not init the loaded level.\n");
793 				}
794 			}
795 			else
796 			{
797 				fprintf(stderr, "Could not load level from %s.\n", filename.Str());
798 			}
799 		}
800 		else
801 		{
802 			fprintf(stderr, "Could not open file %s for reading.\n", filename.Str());
803 		}
804 	}
805 	else
806 	{
807 		fprintf(stderr, "HCed: File %s doesn't exist, creating a new level.\n", filename.Str());
808 	}
809 
810 	// If an error occurred or the file didn't exist, tries to load the default level/theme
811 	if (!ok)
812 	{
813 		if (!InitDefaultLevel())
814 		{
815 			fprintf(stderr, "Could not init default level.\n");
816 			return -1;
817 		}
818 	}
819 
820 	// Places the level
821 	level.Pos(HCED_MARGIN, HCED_MARGIN);
822 
823 	// Prepares the current gravity and main character's parameters to be shown
824 	OnGravityChange();
825 	OnCharVxChange();
826 	OnCharVyChange();
827 	OnCharJumpRowsChange();
828 	OnMapSizeChange();
829 
830 	// Types and theme subtypes
831 	enemyType = HCENEMYTYPE_BALL;
832 	enemySubtype = 0;
833 	floorSubtype = 0;
834 	contFloorSubtype = 0;
835 	breakSubtype = 0;
836 	barSubtype = 0;
837 	ladderSubtype = 0;
838 	objectSubtype = 0;
839 	ropeSubtype = 0;
840 	ropePeriod = 0;
841 
842 	// Re-initializes level/theme dependant menus
843 	return InitLevelMenus();
844 }
845 
InitLevelMenus()846 s32 HCed::InitLevelMenus()
847 {
848 	imgMouse = 0;
849 
850 	// Inits the main character subtype menu
851 	if (!InitMainSubtypeMenu())
852 	{
853 		fprintf(stderr, "Failed to init main character's subtype menu.\n");
854 
855 		return -1;
856 	}
857 
858 	// Inits the break subtypes menu
859 	if (!InitBreakSubtypeMenu())
860 	{
861 		fprintf(stderr, "Failed to init break subtypes menu.\n");
862 
863 		return -1;
864 	}
865 
866 	// Inits the object subtypes menu
867 	if (!InitObjectSubtypeMenu())
868 	{
869 		fprintf(stderr, "Failed to init object subtypes menu.\n");
870 
871 		return -1;
872 	}
873 
874 	// Inits the enemy representations menu
875 	if (!InitEnemySubtypeMenu())
876 	{
877 		fprintf(stderr, "Failed to init enemy subtypes menu.\n");
878 
879 		return -1;
880 	}
881 
882 	// Inits the floor subtypes menu
883 	if (!InitFloorSubtypeMenu())
884 	{
885 		fprintf(stderr, "Failed to init floor subtypes menu.\n");
886 
887 		return false;
888 	}
889 
890 
891 	// Inits the continuous floor subtypes menu
892 	if (!InitContFloorSubtypeMenu())
893 	{
894 		fprintf(stderr, "Failed to init floor subtypes menu.\n");
895 
896 		return false;
897 	}
898 
899 	// Inits the bar subtypes menu
900 	if (!InitBarSubtypeMenu())
901 	{
902 		fprintf(stderr, "Failed to init bar subtypes menu.\n");
903 
904 		return false;
905 	}
906 
907 	// Inits the ladder subtypes menu
908 	if (!InitLadderSubtypeMenu())
909 	{
910 		fprintf(stderr, "Failed to init ladder subtypes menu.\n");
911 
912 		return false;
913 	}
914 
915 	// Inits the rope subtypes menu
916 	if (!InitRopeSubtypeMenu())
917 	{
918 		fprintf(stderr, "Failed to init rope subtypes menu.\n");
919 
920 		return false;
921 	}
922 
923 	// Inits the open story menu
924 	if (!InitOpenStoryMenu())
925 	{
926 		fprintf(stderr, "Failed to init stories menu.\n");
927 
928 		return false;
929 	}
930 
931 	// Inits the theme subtypes menu
932 	if (!InitThemeMenu())
933 	{
934 		fprintf(stderr, "Failed to init stories menu.\n");
935 
936 		return false;
937 	}
938 
939 	return 0;
940 }
941 
NextLevel()942 s32 HCed::NextLevel()
943 {
944 	char str[256];
945 
946 	// Sets the name of the story with the next level number.
947 	snprintf(str, sizeof(str), "%s%s/level%03d.hlv", storyDir.Str(), storyName.Str(), ++levelNumber);
948 	filename = str;
949 
950 	if (0 == LoadLevel())
951 	{
952 		themeName = level.Theme().Name();
953 		OnFilenameChange();
954 
955 		if (0 == InitLevelMenus())
956 		{
957 			OnFloor(this);
958 
959 			return 0;
960 		}
961 	}
962 
963 	return -1;
964 }
965 
PrevLevel()966 s32 HCed::PrevLevel()
967 {
968 	if (levelNumber > 1)
969 	{
970 		char str[256];
971 
972 		// Sets the name of the story with the next level number.
973 		snprintf(str, sizeof(str), "%s%s/level%03d.hlv", storyDir.Str(), storyName.Str(), --levelNumber);
974 		filename = str;
975 
976 		if (0 == LoadLevel())
977 		{
978 			OnFilenameChange();
979 
980 			if (0 == InitLevelMenus())
981 			{
982 				OnFloor(this);
983 
984 				return 0;
985 			}
986 		}
987 
988 		return -1;
989 	}
990 
991 	// No more levels before
992 	return 1;
993 }
994 
NewLevel()995 s32 HCed::NewLevel()
996 {
997 	if (0 == LoadLevel())
998 	{
999 		OnFilenameChange();
1000 
1001 		if (0 == InitLevelMenus())
1002 		{
1003 			OnFloor(this);
1004 
1005 			return 0;
1006 		}
1007 	}
1008 
1009 	return -1;
1010 }
1011 
Init(int argc,char ** argv)1012 bool HCed::Init(int argc, char **argv)
1013 {
1014 	// Parse standard JApp args and HCed args
1015 	ParseArgs(argc, argv);
1016 
1017 	// Inits base system
1018 	if (!JApp::Init())
1019 	{
1020 		fprintf(stderr, "Failed to init base system. Check manual.\n");
1021 
1022 		return false;
1023 	}
1024 
1025 	// Loads preferences
1026   // 	if (0 != prefs.Load())
1027   // 	{
1028   // 		fprintf(stderr, "Error loading preferences. Check manual.\n");
1029   // 	}
1030 
1031 	// In edition mode the time must be that of the highest level of difficulty
1032 	prefs.Difficulty(HCPREFERENCES_HARD);
1033 
1034 	// Initializes fonts
1035 	if (!JFile::Exists(HC_DATA_DIR "font/font.ttf"))
1036 	{
1037 		fprintf(stderr,
1038 						"Could not find data directory.\n\n"
1039 						"Posible solutions are:\n"
1040 						" - Open folder JLib-1.3.1/Games/HolotzCastle and double.\n"
1041 						"   click 'holotz-castle' application icon.\n"
1042 						" - Maybe you did 'make' but didn't do 'make install'.\n"
1043 						" - Else, try to reinstall the game.\n");
1044 		return false;
1045 	}
1046 
1047 	if (!fontSmall.Open(HC_DATA_DIR "font/font.ttf", 12) ||
1048 			!fontNormal.Open(HC_DATA_DIR "font/font.ttf", 18) ||
1049 			!fontLarge.Open(HC_DATA_DIR "font/font.ttf", 24))
1050 	{
1051 		fprintf(stderr, "Couldn't open fonts. Check manual.\n");
1052 		return false;
1053 	}
1054 
1055 	// Loads the level
1056 	if (0 != LoadLevel())
1057 	{
1058 		fprintf(stderr, "Couldn't load level. Check manual.\n");
1059 		return false;
1060 	}
1061 
1062 	// Inits the main menu
1063 	if (!InitMainMenu())
1064 	{
1065 		fprintf(stderr, "Failed to init main menu.\n");
1066 
1067 		return false;
1068 	}
1069 
1070 	// Inits the level dependant menus
1071 	if (0 != InitLevelMenus())
1072 	{
1073 		fprintf(stderr, "Failed to init level menus.\n");
1074 
1075 		return false;
1076 	}
1077 
1078 	// Inits the rope periods menu
1079 	if (!InitRopePeriodMenu())
1080 	{
1081 		fprintf(stderr, "Failed to init rope periods menu.\n");
1082 
1083 		return false;
1084 	}
1085 
1086 	// Inits the enemy types menu
1087 	if (!InitEnemyTypeMenu())
1088 	{
1089 		fprintf(stderr, "Failed to init enemy types menu.\n");
1090 
1091 		return false;
1092 	}
1093 
1094 	// Inits the enemy param 1 menu
1095 	if (!InitEnemyParam1Menu())
1096 	{
1097 		fprintf(stderr, "Failed to init enemy param 1 menu.\n");
1098 
1099 		return false;
1100 	}
1101 
1102 	// Inits the enemy param 2 menu
1103 	if (!InitEnemyParam2Menu())
1104 	{
1105 		fprintf(stderr, "Failed to init enemy param 2 menu.\n");
1106 
1107 		return false;
1108 	}
1109 
1110 	appBackColor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x07);
1111 
1112 	OnFloor(this);
1113 
1114 	return true;
1115 }
1116 
InitLoadedLevel()1117 bool HCed::InitLoadedLevel()
1118 {
1119 	// Nothing for the moment
1120 	return true;
1121 }
1122 
InitDefaultLevel()1123 bool HCed::InitDefaultLevel()
1124 {
1125 	// Destroy a previous level
1126 	level.Destroy();
1127 
1128 	// Sets the timer font
1129 	level.SetTimerFont(&fontNormal);
1130 
1131 	// Loads the theme
1132 	printf("Using theme %s\n", themeName.Str());
1133 	if (!level.Theme().Load(themeName.Str()))
1134 	{
1135 		fprintf(stderr, "Error loading theme.\n");
1136 		return false;
1137 	}
1138 
1139 	// Initializes the map
1140 	level.Map().Init(level.Theme());
1141 	level.Map().Resize(defRows, defCols);
1142 	level.Map().CellWidth(level.Theme().Floor(0).Width());
1143 	level.Map().CellHeight(level.Theme().Floor(0).Height());
1144 
1145 	// Initializes the character
1146 	level.character.Pos(20, 20);
1147 
1148 	if (!level.Init())
1149 	{
1150 		fprintf(stderr, "Error initializing level.\n");
1151 		return false;
1152 	}
1153 
1154 	return true;
1155 }
1156 
InitMainMenu()1157 bool HCed::InitMainMenu()
1158 {
1159 	JDELETE(menuMain);
1160 	menuMain = new JImageMenu;
1161 
1162 	char str[256];
1163 
1164 	for (s32 i = 0; i < HCEDSTATE_COUNT; ++i)
1165 	{
1166 		snprintf(str, sizeof(str), HCED_DATA_DIR "MainMenu/%d.tga", i);
1167 		//fprintf(stderr, "Loading UI Item " HCED_DATA_DIR "MainMenu/%d.tga\n", i);
1168 
1169 		if (!imgMenu[i].Load(str))
1170 		{
1171 			return false;
1172 		}
1173 
1174 		snprintf(str, sizeof(str), HCED_DATA_DIR "MainMenu/%d_hi.tga", i);
1175 		//fprintf(stderr, "Loading UI Item " HCED_DATA_DIR "MainMenu/%d_hi.tga\n", i);
1176 
1177 		if (!imgMenuOver[i].Load(str))
1178 		{
1179 			return false;
1180 		}
1181 	}
1182 
1183 	// Adds the options
1184 	JTree<JImageMenuEntry *>::Iterator *it = menuMain->Menu();
1185 
1186 	it->Data(new JImageMenuEntry(&imgMenu[HCEDSTATE_FLOOR],
1187 															 &imgMenuOver[HCEDSTATE_FLOOR], &OnFloor, this));
1188 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_CONTFLOOR],
1189 																		&imgMenuOver[HCEDSTATE_CONTFLOOR], &OnContFloor, this));
1190 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_LADDER],
1191 																		&imgMenuOver[HCEDSTATE_LADDER], &OnLadder, this));
1192 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_BAR],
1193 																		&imgMenuOver[HCEDSTATE_BAR], &OnBar, this));
1194 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_BREAK],
1195 																		&imgMenuOver[HCEDSTATE_BREAK], &OnBreak, this));
1196 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_OBJECT],
1197 																		&imgMenuOver[HCEDSTATE_OBJECT], &OnObject, this));
1198 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_ROPE],
1199 																		&imgMenuOver[HCEDSTATE_ROPE], &OnRope, this));
1200 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_START],
1201 																		&imgMenuOver[HCEDSTATE_START], &OnStart, this));
1202 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_EXIT],
1203 																		&imgMenuOver[HCEDSTATE_EXIT], &OnExit, this));
1204 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_ENEMY],
1205 																		&imgMenuOver[HCEDSTATE_ENEMY], &OnEnemy, this));
1206 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_SAVE],
1207 																		&imgMenuOver[HCEDSTATE_SAVE], &OnSave, this));
1208 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_OPENSTORY],
1209 																		&imgMenuOver[HCEDSTATE_OPENSTORY], &OnOpenStory, this));
1210 	it->AddNodeGo(new JImageMenuEntry(&imgMenu[HCEDSTATE_APPEXIT],
1211 																		&imgMenuOver[HCEDSTATE_APPEXIT], &OnAppExit, this));
1212 	it->Root();
1213 
1214 	JImageMenuConfig cfg;
1215 	cfg.layout = JIMAGEMENU_LEFT;
1216 	cfg.trackMouse = true;
1217 	cfg.trackKeyboard = false;
1218 	cfg.autoEnter = false;
1219 
1220 	if (!menuMain->Init(cfg))
1221 	{
1222 		return false;
1223 	}
1224 
1225 	menuMain->Pos(0, 0);
1226 	menuMain->Menu()->Root();
1227 
1228 	return true;
1229 }
1230 
InitMainSubtypeMenu()1231 bool HCed::InitMainSubtypeMenu()
1232 {
1233 	DestroyMainSubtypeMenu();
1234 	menuMainSubtype = new JImageMenu;
1235 
1236 	// Adds the options
1237 	JTree<JImageMenuEntry *>::Iterator *it = menuMainSubtype->Menu();
1238 	it->Root();
1239 
1240 	it->Data(new JImageMenuEntry(new JImage(*((JImage*)level.theme.MainChar(0)[HCCDT_STOP].Frame(0))),
1241 															 new JImage(*((JImage*)level.theme.MainChar(0)[HCCDT_LEFT].Frame(0))),
1242 															 &OnMainSubtype, (void *)0));
1243 
1244 	// Adds the subtypes
1245 	for (s32 i = 1; i < level.theme.NumMainChars(); ++i)
1246 	{
1247 		it->AddNodeGo(new JImageMenuEntry(new JImage(*((JImage*)level.theme.MainChar(i)[HCCDT_STOP].Frame(0))),
1248 																			new JImage(*((JImage*)level.theme.MainChar(i)[HCCDT_LEFT].Frame(0))),
1249 																			&OnMainSubtype, JCAST_S32_TO_VOIDPTR(i)));
1250 	}
1251 
1252 	it->Root();
1253 
1254 	JImageMenuConfig cfg;
1255 	cfg.layout = JIMAGEMENU_SAMELINE;
1256 	cfg.trackMouse = true;
1257 	cfg.trackKeyboard = false;
1258 	cfg.autoEnter = false;
1259 	menuMainSubtype->Pos(HCED_MARGIN, 0);
1260 
1261 	if (!menuMainSubtype->Init(cfg))
1262 	{
1263 		return false;
1264 	}
1265 
1266 	menuMainSubtype->Menu()->Root();
1267 
1268 	return true;
1269 }
1270 
InitFloorSubtypeMenu()1271 bool HCed::InitFloorSubtypeMenu()
1272 {
1273 	JDELETE(menuFloorSubtype);
1274 	menuFloorSubtype = new JImageMenu;
1275 
1276 	// Adds the options
1277 	JTree<JImageMenuEntry *>::Iterator *it = menuFloorSubtype->Menu();
1278 
1279 	// At least we must have this
1280 	it->Data(new JImageMenuEntry(&level.Theme().Floor(0), &level.Theme().Floor(0), &OnFloorSubtype, (void *)0));
1281 
1282 	// Adds the rest of subtypes
1283 	for (s32 i = 1; i < level.Theme().NumFloors(); ++i)
1284 	{
1285 		it->AddNodeGo(new JImageMenuEntry(&level.Theme().Floor(i), &level.Theme().Floor(i), &OnFloorSubtype, JCAST_S32_TO_VOIDPTR(i)));
1286 	}
1287 
1288 	it->Root();
1289 
1290 	JImageMenuConfig cfg;
1291 	cfg.layout = JIMAGEMENU_SAMELINE;
1292 	cfg.trackMouse = true;
1293 	cfg.trackKeyboard = false;
1294 	cfg.autoEnter = false;
1295 
1296 	if (!menuFloorSubtype->Init(cfg))
1297 	{
1298 		fprintf(stderr, "Error\n");
1299 		return false;
1300 	}
1301 
1302 	menuFloorSubtype->Pos(HCED_MARGIN, 0);
1303 	menuFloorSubtype->Menu()->Root();
1304 
1305 	return true;
1306 }
1307 
InitContFloorSubtypeMenu()1308 bool HCed::InitContFloorSubtypeMenu()
1309 {
1310 	JDELETE(menuContFloorSubtype);
1311 	menuContFloorSubtype = new JImageMenu;
1312 
1313 	// Adds the options
1314 	JTree<JImageMenuEntry *>::Iterator *it = menuContFloorSubtype->Menu();
1315 
1316 	// At least we must have this
1317 	it->Data(new JImageMenuEntry(&level.Theme().ContFloor(0)[HCFDT_I], &level.Theme().ContFloor(0)[HCFDT_I], &OnContFloorSubtype, (void *)0));
1318 
1319 	// Adds the rest of subtypes
1320 	for (s32 i = 1; i < level.Theme().NumContFloors(); ++i)
1321 	{
1322 		it->AddNodeGo(new JImageMenuEntry(&level.Theme().ContFloor(i)[HCFDT_I], &level.Theme().ContFloor(i)[HCFDT_I], &OnContFloorSubtype, JCAST_S32_TO_VOIDPTR(i)));
1323 	}
1324 
1325 	it->Root();
1326 
1327 	JImageMenuConfig cfg;
1328 	cfg.layout = JIMAGEMENU_SAMELINE;
1329 	cfg.trackMouse = true;
1330 	cfg.trackKeyboard = false;
1331 	cfg.autoEnter = false;
1332 
1333 	if (!menuContFloorSubtype->Init(cfg))
1334 	{
1335 		fprintf(stderr, "Error\n");
1336 		return false;
1337 	}
1338 
1339 	menuContFloorSubtype->Pos(HCED_MARGIN, 0);
1340 	menuContFloorSubtype->Menu()->Root();
1341 
1342 	return true;
1343 }
1344 
InitBreakSubtypeMenu()1345 bool HCed::InitBreakSubtypeMenu()
1346 {
1347 	DestroyBreakSubtypeMenu();
1348 	menuBreakSubtype = new JImageMenu;
1349 
1350 	// Adds the options
1351 	JTree<JImageMenuEntry *>::Iterator *it = menuBreakSubtype->Menu();
1352 	it->Root();
1353 
1354 	// At least we must have this
1355 	it->Data(new JImageMenuEntry(new JImage(*((JImage*)level.Theme().Break(0)[HCBDT_NORMAL].Frame(0))),
1356 															 new JImage(*((JImage*)level.Theme().Break(0)[HCBDT_NORMAL].Frame(0))),
1357 															 &OnBreakSubtype, (void *)0));
1358 
1359 	// Adds the rest of subtypes
1360 	for (s32 i = 1; i < level.Theme().NumBreaks(); ++i)
1361 	{
1362 		it->AddNodeGo(new JImageMenuEntry(new JImage(*((JImage*)level.Theme().Break(i)[HCBDT_NORMAL].Frame(0))),
1363 																			new JImage(*((JImage*)level.Theme().Break(i)[HCBDT_NORMAL].Frame(0))),
1364 																			&OnBreakSubtype, JCAST_S32_TO_VOIDPTR(i)));
1365 	}
1366 
1367 	it->Root();
1368 
1369 	JImageMenuConfig cfg;
1370 	cfg.layout = JIMAGEMENU_SAMELINE;
1371 	cfg.trackMouse = true;
1372 	cfg.trackKeyboard = false;
1373 	cfg.autoEnter = false;
1374 	menuBreakSubtype->Pos(HCED_MARGIN, 0);
1375 
1376 	if (!menuBreakSubtype->Init(cfg))
1377 	{
1378 		return false;
1379 	}
1380 
1381 	menuBreakSubtype->Menu()->Root();
1382 
1383 	return true;
1384 }
1385 
InitBarSubtypeMenu()1386 bool HCed::InitBarSubtypeMenu()
1387 {
1388 	JDELETE(menuBarSubtype);
1389 	menuBarSubtype = new JImageMenu;
1390 
1391 	// Adds the options
1392 	JTree<JImageMenuEntry *>::Iterator *it = menuBarSubtype->Menu();
1393 
1394 	// At least we must have this
1395 	it->Data(new JImageMenuEntry(&level.Theme().Bar(0), &level.Theme().Bar(0), &OnBarSubtype, (void *)0));
1396 
1397 	// Adds the rest of subtypes
1398 	for (s32 i = 1; i < level.Theme().NumBars(); ++i)
1399 	{
1400 		it->AddNodeGo(new JImageMenuEntry(&level.Theme().Bar(i), &level.Theme().Bar(i), &OnBarSubtype, JCAST_S32_TO_VOIDPTR(i)));
1401 	}
1402 
1403 	it->Root();
1404 
1405 	JImageMenuConfig cfg;
1406 	cfg.layout = JIMAGEMENU_SAMELINE;
1407 	cfg.trackMouse = true;
1408 	cfg.trackKeyboard = false;
1409 	cfg.autoEnter = false;
1410 	menuBarSubtype->Pos(HCED_MARGIN, 0);
1411 
1412 	if (!menuBarSubtype->Init(cfg))
1413 	{
1414 		return false;
1415 	}
1416 
1417 	menuBarSubtype->Menu()->Root();
1418 
1419 	return true;
1420 }
1421 
InitLadderSubtypeMenu()1422 bool HCed::InitLadderSubtypeMenu()
1423 {
1424 	JDELETE(menuLadderSubtype);
1425 	menuLadderSubtype = new JImageMenu;
1426 
1427 	// Adds the options
1428 	JTree<JImageMenuEntry *>::Iterator *it = menuLadderSubtype->Menu();
1429 
1430 	// At least we must have this
1431 	it->Data(new JImageMenuEntry(&level.Theme().Ladder(0), &level.Theme().Ladder(0), &OnLadderSubtype, (void *)0));
1432 
1433 	// Adds the rest of subtypes
1434 	for (s32 i = 1; i < level.Theme().NumLadders(); ++i)
1435 	{
1436 		it->AddNodeGo(new JImageMenuEntry(&level.Theme().Ladder(i), &level.Theme().Ladder(i), &OnLadderSubtype, JCAST_S32_TO_VOIDPTR(i)));
1437 	}
1438 
1439 	it->Root();
1440 
1441 	JImageMenuConfig cfg;
1442 	cfg.layout = JIMAGEMENU_SAMELINE;
1443 	cfg.trackMouse = true;
1444 	cfg.trackKeyboard = false;
1445 	cfg.autoEnter = false;
1446 	menuLadderSubtype->Pos(HCED_MARGIN, 0);
1447 
1448 	if (!menuLadderSubtype->Init(cfg))
1449 	{
1450 		return false;
1451 	}
1452 
1453 	menuLadderSubtype->Menu()->Root();
1454 
1455 	return true;
1456 }
1457 
InitObjectSubtypeMenu()1458 bool HCed::InitObjectSubtypeMenu()
1459 {
1460 	DestroyObjectSubtypeMenu();
1461 	menuObjectSubtype = new JImageMenu;
1462 
1463 	// Adds the options
1464 	JTree<JImageMenuEntry *>::Iterator *it = menuObjectSubtype->Menu();
1465 	it->Root();
1466 
1467 	// At least we must have this
1468 	it->Data(new JImageMenuEntry(new JImage(*((JImage*)level.Theme().Object(0)[HCODT_NORMAL].Frame(0))),
1469 															 new JImage(*((JImage*)level.Theme().Object(0)[HCODT_ACQUIRED].Frame(0))),
1470 															 &OnObjectSubtype,
1471 															 (void *)0));
1472 
1473 	// Adds the rest of subtypes
1474 	for (s32 i = 1; i < level.Theme().NumObjects(); ++i)
1475 	{
1476 		it->AddNodeGo(new JImageMenuEntry(new JImage(*((JImage*)level.Theme().Object(i)[HCODT_NORMAL].Frame(0))),
1477 																			new JImage(*((JImage*)level.Theme().Object(i)[HCODT_ACQUIRED].Frame(0))),
1478 																			&OnObjectSubtype,
1479 																			JCAST_S32_TO_VOIDPTR(i)));
1480 	}
1481 
1482 	it->Root();
1483 
1484 	JImageMenuConfig cfg;
1485 	cfg.layout = JIMAGEMENU_SAMELINE;
1486 	cfg.trackMouse = true;
1487 	cfg.trackKeyboard = false;
1488 	cfg.autoEnter = false;
1489 	menuObjectSubtype->Pos(HCED_MARGIN, 0);
1490 
1491 	if (!menuObjectSubtype->Init(cfg))
1492 	{
1493 		return false;
1494 	}
1495 
1496 	menuObjectSubtype->Menu()->Root();
1497 
1498 	return true;
1499 }
1500 
InitRopeSubtypeMenu()1501 bool HCed::InitRopeSubtypeMenu()
1502 {
1503 	JDELETE(menuRopeSubtype);
1504 	menuRopeSubtype = new JImageMenu;
1505 
1506 	// Adds the options
1507 	JTree<JImageMenuEntry *>::Iterator *it = menuRopeSubtype->Menu();
1508 
1509 	// At least we must have this
1510 	it->Data(new JImageMenuEntry(&level.Theme().Rope(0)[HCRDT_TOP], &level.Theme().Rope(0)[HCRDT_TOP], &OnRopeSubtype, (void *)0));
1511 
1512 	// Adds the rest of subtypes
1513 	for (s32 i = 1; i < level.Theme().NumRopes(); ++i)
1514 	{
1515 		it->AddNodeGo(new JImageMenuEntry(&level.Theme().Rope(i)[HCRDT_TOP], &level.Theme().Rope(i)[HCRDT_TOP], &OnRopeSubtype, JCAST_S32_TO_VOIDPTR(i)));
1516 	}
1517 
1518 	it->Root();
1519 
1520 	JImageMenuConfig cfg;
1521 	cfg.layout = JIMAGEMENU_SAMELINE;
1522 	cfg.trackMouse = true;
1523 	cfg.trackKeyboard = false;
1524 	cfg.autoEnter = false;
1525 		menuRopeSubtype->Pos(HCED_MARGIN, 0);
1526 
1527 	if (!menuRopeSubtype->Init(cfg))
1528 	{
1529 		return false;
1530 	}
1531 
1532 	menuRopeSubtype->Menu()->Root();
1533 
1534 	return true;
1535 }
1536 
InitRopePeriodMenu()1537 bool HCed::InitRopePeriodMenu()
1538 {
1539 	JDELETE(menuRopePeriod);
1540 	menuRopePeriod = new JTextMenu;
1541 
1542 	// Crea el men�
1543 	JTree<JTextMenuEntry *>::Iterator *it = menuRopePeriod->Menu();
1544 
1545 	it->Data(new JTextMenuEntry("1", &OnRopePeriod, (void *)1));
1546 	it->AddNodeGo(new JTextMenuEntry("2", &OnRopePeriod, (void *)2));
1547 	it->AddNodeGo(new JTextMenuEntry("3", &OnRopePeriod, (void *)3));
1548 	it->AddNodeGo(new JTextMenuEntry("4", &OnRopePeriod, (void *)4));
1549 	it->AddNodeGo(new JTextMenuEntry("5", &OnRopePeriod, (void *)5));
1550 	it->AddNodeGo(new JTextMenuEntry("6", &OnRopePeriod, (void *)6));
1551 	it->AddNodeGo(new JTextMenuEntry("7", &OnRopePeriod, (void *)7));
1552 	it->AddNodeGo(new JTextMenuEntry("8", &OnRopePeriod, (void *)8));
1553 	it->AddNodeGo(new JTextMenuEntry("9", &OnRopePeriod, (void *)9));
1554 	it->AddNodeGo(new JTextMenuEntry("10", &OnRopePeriod, (void *)10));
1555 	it->Root();
1556 
1557 	JTextMenuConfig cfg;
1558 	cfg.font = &fontSmall;
1559 	cfg.color.r = 0x00;
1560 	cfg.color.g = 0x00;
1561 	cfg.color.b = 0x00;
1562 	cfg.backColor.r = 0xff;
1563 	cfg.backColor.g = 0xcc;
1564 	cfg.backColor.b = 0x00;
1565 	cfg.hiColor.r = 0xff;
1566 	cfg.hiColor.g = 0xff;
1567 	cfg.hiColor.b = 0xff;
1568 	cfg.hiBackColor.r = 0xff;
1569 	cfg.hiBackColor.g = 0xdd;
1570 	cfg.hiBackColor.b = 0x00;
1571 	cfg.renderMode = JTEXTMENU_SHADED;
1572 	cfg.layout = JTEXTMENU_SAMELINE;
1573 	cfg.trackKeyboard = true;
1574 	cfg.trackMouse = true;
1575 	cfg.autoEnter = true;
1576 
1577 	if (!menuRopePeriod->Init(cfg))
1578 	{
1579 		return false;
1580 	}
1581 
1582 	menuRopePeriod->Pos(Width() - (12 * HCED_MARGIN), 0);
1583 	menuRopePeriod->Menu()->Root();
1584 
1585 	return true;
1586 }
1587 
InitEnemySubtypeMenu()1588 bool HCed::InitEnemySubtypeMenu()
1589 {
1590 	DestroyEnemySubtypeMenu();
1591 
1592 	for (s32 n = 0; n < HCENEMYTYPE_COUNT; ++n)
1593 	{
1594 		menuEnemySubtype[n] = new JImageMenu;
1595 
1596 		// Adds the options
1597 		JTree<JImageMenuEntry *>::Iterator *it = menuEnemySubtype[n]->Menu();
1598 		it->Root();
1599 
1600 		it->Data(new JImageMenuEntry(new JImage(*((JImage*)GetEnemySprites((HCEnemyType)n, 0)[HCCDT_STOP].Frame(0))),
1601 																 new JImage(*((JImage*)GetEnemySprites((HCEnemyType)n, 0)[HCCDT_STOP].Frame(0))),
1602 																 &OnEnemySubtype, (void *)0));
1603 
1604 		// Adds the subtypes
1605 		for (s32 i = 1; i < GetNumEnemySprites((HCEnemyType)n); ++i)
1606 		{
1607 			// Scales the normal and highlighted images to fit 20 and 32 pixels, respectively
1608 			it->AddNodeGo(new JImageMenuEntry(new JImage(*((JImage*)GetEnemySprites((HCEnemyType)n, i)[HCCDT_STOP].Frame(0))),
1609 																				new JImage(*((JImage*)GetEnemySprites((HCEnemyType)n, i)[HCCDT_STOP].Frame(0))),
1610 																				&OnEnemySubtype, JCAST_S32_TO_VOIDPTR(i)));
1611 		}
1612 
1613 		it->Root();
1614 
1615 		JImageMenuConfig cfg;
1616 		cfg.layout = JIMAGEMENU_SAMELINE;
1617 		cfg.trackMouse = true;
1618 		cfg.trackKeyboard = false;
1619 		cfg.autoEnter = false;
1620 		menuEnemySubtype[n]->Pos(HCED_MARGIN, 0);
1621 
1622 		if (!menuEnemySubtype[n]->Init(cfg))
1623 		{
1624 			return false;
1625 		}
1626 
1627 		menuEnemySubtype[n]->Menu()->Root();
1628 	}
1629 
1630 	return true;
1631 }
1632 
InitEnemyTypeMenu()1633 bool HCed::InitEnemyTypeMenu()
1634 {
1635 	char str[256];
1636 
1637 	if (!menuEnemyType)
1638 	{
1639 		for (s32 i = 0; i < HCENEMYTYPE_COUNT; ++i)
1640 		{
1641 			snprintf(str, sizeof(str), HCED_DATA_DIR "EnemyMenu/%d.tga", i);
1642 			//fprintf(stderr, "Loading UI Item " HCED_DATA_DIR "EnemyMenu/%d.tga\n", i);
1643 
1644 			if (!imgEnemy[i].Load(str))
1645 			{
1646 				return false;
1647 			}
1648 
1649 			snprintf(str, sizeof(str), HCED_DATA_DIR "EnemyMenu/%d_hi.tga", i);
1650 			//fprintf(stderr, "Loading UI Item " HCED_DATA_DIR "EnemyMenu/%d_hi.tga\n", i);
1651 
1652 			if (!imgEnemyOver[i].Load(str))
1653 			{
1654 				return false;
1655 			}
1656 		}
1657 	}
1658 
1659 	JDELETE(menuEnemyType);
1660 	menuEnemyType = new JImageMenu;
1661 
1662 	// Adds the options
1663 	JTree<JImageMenuEntry *>::Iterator *it = menuEnemyType->Menu();
1664 
1665 	it->Data(new JImageMenuEntry(&imgEnemy[HCENEMYTYPE_BALL],
1666 															 &imgEnemyOver[HCENEMYTYPE_BALL],
1667 															 &OnEnemyType, (void *)HCENEMYTYPE_BALL));
1668 	it->AddNodeGo(new JImageMenuEntry(&imgEnemy[HCENEMYTYPE_RANDOM],
1669 																		&imgEnemyOver[HCENEMYTYPE_RANDOM],
1670 																		&OnEnemyType, (void *)HCENEMYTYPE_RANDOM));
1671 	it->AddNodeGo(new JImageMenuEntry(&imgEnemy[HCENEMYTYPE_STATIC],
1672 																		&imgEnemyOver[HCENEMYTYPE_STATIC],
1673 																		&OnEnemyType, (void *)HCENEMYTYPE_STATIC));
1674 	it->AddNodeGo(new JImageMenuEntry(&imgEnemy[HCENEMYTYPE_MAKER],
1675 																		&imgEnemyOver[HCENEMYTYPE_MAKER],
1676 																		&OnEnemyType, (void *)HCENEMYTYPE_MAKER));
1677 	it->AddNodeGo(new JImageMenuEntry(&imgEnemy[HCENEMYTYPE_CHASER],
1678 																		&imgEnemyOver[HCENEMYTYPE_CHASER],
1679 																		&OnEnemyType, (void *)HCENEMYTYPE_CHASER));
1680 	it->Root();
1681 
1682 	JImageMenuConfig cfg;
1683 	cfg.layout = JIMAGEMENU_SAMELINE;
1684 	cfg.trackMouse = true;
1685 	cfg.trackKeyboard = false;
1686 	cfg.autoEnter = false;
1687 	menuEnemyType->Pos(Width() - (5 * HCED_MARGIN), 0);
1688 
1689 	if (!menuEnemyType->Init(cfg))
1690 	{
1691 		return false;
1692 	}
1693 
1694 	menuEnemyType->Menu()->Root();
1695 
1696 	return true;
1697 }
1698 
InitEnemyParam1Menu()1699 bool HCed::InitEnemyParam1Menu()
1700 {
1701 	JDELETE(menuEnemyParam1);
1702 	menuEnemyParam1 = new JTextMenu;
1703 
1704 	// Crea el men�
1705 	JTree<JTextMenuEntry *>::Iterator *it = menuEnemyParam1->Menu();
1706 
1707 	it->Data(new JTextMenuEntry(" 1 ", &OnEnemyParam1, (void *)1));
1708 	it->AddNodeGo(new JTextMenuEntry(" 2 ", &OnEnemyParam1, (void *)2));
1709 	it->AddNodeGo(new JTextMenuEntry(" 3 ", &OnEnemyParam1, (void *)3));
1710 	it->AddNodeGo(new JTextMenuEntry(" 4 ", &OnEnemyParam1, (void *)4));
1711 	it->AddNodeGo(new JTextMenuEntry(" 5 ", &OnEnemyParam1, (void *)5));
1712 	it->AddNodeGo(new JTextMenuEntry(" 6 ", &OnEnemyParam1, (void *)6));
1713 	it->AddNodeGo(new JTextMenuEntry(" 7 ", &OnEnemyParam1, (void *)7));
1714 	it->AddNodeGo(new JTextMenuEntry(" 8 ", &OnEnemyParam1, (void *)8));
1715 	it->AddNodeGo(new JTextMenuEntry(" 9 ", &OnEnemyParam1, (void *)9));
1716 	it->AddNodeGo(new JTextMenuEntry(" 10 ", &OnEnemyParam1, (void *)10));
1717 	it->Root();
1718 
1719 	JTextMenuConfig cfg;
1720 	cfg.font = &fontSmall;
1721 	cfg.color.r = 0x00;
1722 	cfg.color.g = 0x00;
1723 	cfg.color.b = 0x00;
1724 	cfg.backColor.r = 0x00;
1725 	cfg.backColor.g = 0x00;
1726 	cfg.backColor.b = 0xcc;
1727 	cfg.hiColor.r = 0xff;
1728 	cfg.hiColor.g = 0xff;
1729 	cfg.hiColor.b = 0xff;
1730 	cfg.hiBackColor.r = 0x00;
1731 	cfg.hiBackColor.g = 0x00;
1732 	cfg.hiBackColor.b = 0xcc;
1733 	cfg.renderMode = JTEXTMENU_SHADED;
1734 	cfg.layout = JTEXTMENU_SAMELINE;
1735 	cfg.trackKeyboard = true;
1736 	cfg.trackMouse = true;
1737 	cfg.autoEnter = true;
1738 
1739 	if (!menuEnemyParam1->Init(cfg))
1740 	{
1741 		return false;
1742 	}
1743 
1744 	menuEnemyParam1->Pos(Width() - (20 * 20), 32);
1745 	menuEnemyParam1->Menu()->Root();
1746 
1747 	return true;
1748 }
1749 
InitEnemyParam2Menu()1750 bool HCed::InitEnemyParam2Menu()
1751 {
1752 	JDELETE(menuEnemyParam2);
1753 	menuEnemyParam2 = new JTextMenu;
1754 
1755 	// Crea el men�
1756 	JTree<JTextMenuEntry *>::Iterator *it = menuEnemyParam2->Menu();
1757 
1758 	it->Data(new JTextMenuEntry(" 1 ", &OnEnemyParam2, (void *)1));
1759 	it->AddNodeGo(new JTextMenuEntry(" 2 ", &OnEnemyParam2, (void *)2));
1760 	it->AddNodeGo(new JTextMenuEntry(" 3 ", &OnEnemyParam2, (void *)3));
1761 	it->AddNodeGo(new JTextMenuEntry(" 4 ", &OnEnemyParam2, (void *)4));
1762 	it->AddNodeGo(new JTextMenuEntry(" 5 ", &OnEnemyParam2, (void *)5));
1763 	it->AddNodeGo(new JTextMenuEntry(" 6 ", &OnEnemyParam2, (void *)6));
1764 	it->AddNodeGo(new JTextMenuEntry(" 7 ", &OnEnemyParam2, (void *)7));
1765 	it->AddNodeGo(new JTextMenuEntry(" 8 ", &OnEnemyParam2, (void *)8));
1766 	it->AddNodeGo(new JTextMenuEntry(" 9 ", &OnEnemyParam2, (void *)9));
1767 	it->AddNodeGo(new JTextMenuEntry(" 10 ", &OnEnemyParam2, (void *)10));
1768 	it->Root();
1769 
1770 	JTextMenuConfig cfg;
1771 	cfg.font = &fontSmall;
1772 	cfg.color.r = 0x00;
1773 	cfg.color.g = 0x00;
1774 	cfg.color.b = 0x00;
1775 	cfg.backColor.r = 0x00;
1776 	cfg.backColor.g = 0xcc;
1777 	cfg.backColor.b = 0x00;
1778 	cfg.hiColor.r = 0xff;
1779 	cfg.hiColor.g = 0xff;
1780 	cfg.hiColor.b = 0xff;
1781 	cfg.hiBackColor.r = 0x00;
1782 	cfg.hiBackColor.g = 0xcc;
1783 	cfg.hiBackColor.b = 0x00;
1784 	cfg.renderMode = JTEXTMENU_SHADED;
1785 	cfg.layout = JTEXTMENU_SAMELINE;
1786 	cfg.trackKeyboard = true;
1787 	cfg.trackMouse = true;
1788 	cfg.autoEnter = true;
1789 
1790 	if (!menuEnemyParam2->Init(cfg))
1791 	{
1792 		return false;
1793 	}
1794 
1795 	menuEnemyParam2->Pos(Width() - (10 * 20), 32);
1796 	menuEnemyParam2->Menu()->Root();
1797 
1798 	return true;
1799 }
1800 
InitOpenStoryMenu()1801 bool HCed::InitOpenStoryMenu()
1802 {
1803 	HCUtil::FindStories(true);
1804 
1805 	JDELETE(menuOpenStory);
1806 	menuOpenStory = new JTextMenu;
1807 
1808 	// Crea el men�
1809 	JTree<JTextMenuEntry *>::Iterator *it = menuOpenStory->Menu();
1810 
1811 	if (HCUtil::Stories().size() > 0)
1812 	{
1813 		it->Data(new JTextMenuEntry(HCUtil::Stories()[0], &OnSelectStory, (void *)0));
1814 
1815 		for (u32 i = 1; i < HCUtil::Stories().size(); ++i)
1816 		{
1817 			it->AddNodeGo(new JTextMenuEntry(HCUtil::Stories()[i], &OnSelectStory, JCAST_S32_TO_VOIDPTR(i)));
1818 		}
1819 
1820 		it->AddNodeGo(new JTextMenuEntry("<------>", &OnSelectStory, (void *)-1));
1821 	}
1822 	else
1823 	{
1824 		it->Data(new JTextMenuEntry("<------>", &OnSelectStory, (void *)-1));
1825 	}
1826 
1827 	it->Root();
1828 
1829 	JTextMenuConfig cfg;
1830 	cfg.font = &fontSmall;
1831 	cfg.lineDistance = 3;
1832 	cfg.color.r = 0xff;
1833 	cfg.color.g = 0xcc;
1834 	cfg.color.b = 0x00;
1835 	cfg.backColor.r = 0x00;
1836 	cfg.backColor.g = 0x00;
1837 	cfg.backColor.b = 0x00;
1838 	cfg.hiColor.r = 0xff;
1839 	cfg.hiColor.g = 0xff;
1840 	cfg.hiColor.b = 0xff;
1841 	cfg.hiBackColor.r = 0x00;
1842 	cfg.hiBackColor.g = 0x00;
1843 	cfg.hiBackColor.b = 0x00;
1844 	cfg.renderMode = JTEXTMENU_BLENDED;
1845 	cfg.layout = JTEXTMENU_CENTER;
1846 	cfg.layoutV = JTEXTMENU_CENTER;
1847 	cfg.trackKeyboard = true;
1848 	cfg.trackMouse = true;
1849 	cfg.autoEnter = false;
1850 
1851 	if (!menuOpenStory->Init(cfg))
1852 	{
1853 		return false;
1854 	}
1855 
1856 	menuOpenStory->Pos(Width()/2, Height()/2);
1857 	menuOpenStory->Menu()->Root();
1858 
1859 	return true;
1860 }
1861 
InitThemeMenu()1862 bool HCed::InitThemeMenu()
1863 {
1864 	if (HCUtil::FindThemes())
1865 	{
1866 		JDELETE(menuTheme);
1867 		menuTheme = new JTextMenu;
1868 
1869 		// Crea el men�
1870 		JTree<JTextMenuEntry *>::Iterator *it = menuTheme->Menu();
1871 
1872 		it->Data(new JTextMenuEntry(HCUtil::Themes()[0], &OnSelectTheme, 0));
1873 		for (u32 i = 1; i < HCUtil::Themes().size(); ++i)
1874 		{
1875 			it->AddNodeGo(new JTextMenuEntry(HCUtil::Themes()[i], &OnSelectTheme, JCAST_S32_TO_VOIDPTR(i)));
1876 		}
1877 
1878 		it->Root();
1879 
1880 		JTextMenuConfig cfg;
1881 		cfg.font = &fontSmall;
1882 		cfg.lineDistance = 3;
1883 		cfg.color.r = 0xff;
1884 		cfg.color.g = 0xcc;
1885 		cfg.color.b = 0x00;
1886 		cfg.backColor.r = 0x00;
1887 		cfg.backColor.g = 0x00;
1888 		cfg.backColor.b = 0x00;
1889 		cfg.hiColor.r = 0xff;
1890 		cfg.hiColor.g = 0xff;
1891 		cfg.hiColor.b = 0xff;
1892 		cfg.hiBackColor.r = 0x00;
1893 		cfg.hiBackColor.g = 0x00;
1894 		cfg.hiBackColor.b = 0x00;
1895 		cfg.renderMode = JTEXTMENU_BLENDED;
1896 		cfg.layout = JTEXTMENU_CENTER;
1897 		cfg.layoutV = JTEXTMENU_CENTER;
1898 		cfg.trackKeyboard = true;
1899 		cfg.trackMouse = true;
1900 		cfg.autoEnter = false;
1901 
1902 		if (!menuTheme->Init(cfg))
1903 		{
1904 			return false;
1905 		}
1906 
1907 		menuTheme->Pos(Width()/2, Height()/2);
1908 		menuTheme->Menu()->Root();
1909 
1910 		return true;
1911 	}
1912 
1913 	return false;
1914 }
1915 
Draw()1916 bool HCed::Draw()
1917 {
1918 	bool ret = true;
1919 
1920 	SDL_FillRect(screen, 0, appBackColor);
1921 	level.Draw();
1922 	menuMain->Draw();
1923 
1924 	// Draws the mouse cursor
1925 	imgMouse->Draw(MouseX() + imgMouse->Width(), MouseY() + imgMouse->Height());
1926 
1927 	switch (state)
1928 	{
1929 	case HCEDSTATE_FLOOR:
1930     ret = DrawFloor();
1931 		break;
1932 	case HCEDSTATE_CONTFLOOR:
1933 		ret = DrawContFloor();
1934 		break;
1935 	case HCEDSTATE_LADDER:
1936     ret = DrawLadder();
1937 		break;
1938 	case HCEDSTATE_BAR:
1939     ret = DrawBar();
1940 		break;
1941 	case HCEDSTATE_BREAK:
1942     ret = DrawBreak();
1943 		break;
1944 	case HCEDSTATE_OBJECT:
1945     ret = DrawObject();
1946 		break;
1947 	case HCEDSTATE_ROPE:
1948     ret = DrawRope();
1949 		break;
1950 	case HCEDSTATE_START:
1951     ret = DrawStart();
1952 		break;
1953 	case HCEDSTATE_EXIT:
1954     ret = DrawExit();
1955 		break;
1956 	case HCEDSTATE_ENEMY:
1957     ret = DrawEnemy();
1958 		break;
1959 	case HCEDSTATE_SAVE:
1960     ret = DrawSave();
1961 		break;
1962 	case HCEDSTATE_OPENSTORY:
1963     ret = DrawOpenStory();
1964 		break;
1965 	case HCEDSTATE_APPEXIT:
1966     ret = DrawAppExit();
1967 		break;
1968 	default:
1969 		break;
1970 	}
1971 
1972 	level.levelTimer.Y(13 * 32);
1973 	level.levelTimer.Draw();
1974 
1975 	imgGravity->Y(14 * 32);
1976 	imgGravity->Draw();
1977 
1978 	imgCharVx->Y(15 * 32);
1979 	imgCharVx->Draw();
1980 
1981 	imgCharVy->Y(16 * 32);
1982 	imgCharVy->Draw();
1983 
1984 	imgCharJumpRows->Y(17 * 32);
1985 	imgCharJumpRows->Draw();
1986 
1987 	imgMapSize->Y(18 * 32);
1988 	imgMapSize->Draw();
1989 
1990 	// Swaps buffers!
1991 	Flip();
1992 
1993 	return ret;
1994 }
1995 
DrawFloor()1996 bool HCed::DrawFloor()
1997 {
1998 	menuFloorSubtype->Draw();
1999 
2000 	return true;
2001 }
2002 
DrawContFloor()2003 bool HCed::DrawContFloor()
2004 {
2005 	menuContFloorSubtype->Draw();
2006 
2007 	return true;
2008 }
2009 
DrawLadder()2010 bool HCed::DrawLadder()
2011 {
2012 	menuLadderSubtype->Draw();
2013 
2014 	return true;
2015 }
2016 
DrawBar()2017 bool HCed::DrawBar()
2018 {
2019 	menuBarSubtype->Draw();
2020 
2021 	return true;
2022 }
2023 
DrawBreak()2024 bool HCed::DrawBreak()
2025 {
2026 	menuBreakSubtype->Draw();
2027 
2028 	return true;
2029 }
2030 
DrawObject()2031 bool HCed::DrawObject()
2032 {
2033 	menuObjectSubtype->Draw();
2034 
2035 	return true;
2036 }
2037 
DrawRope()2038 bool HCed::DrawRope()
2039 {
2040 	menuRopeSubtype->Draw();
2041 	menuRopePeriod->Draw();
2042 
2043 	return true;
2044 }
2045 
DrawStart()2046 bool HCed::DrawStart()
2047 {
2048 	menuMainSubtype->Draw();
2049 
2050 	return true;
2051 }
2052 
DrawExit()2053 bool HCed::DrawExit()
2054 {
2055 	return true;
2056 }
2057 
DrawEnemy()2058 bool HCed::DrawEnemy()
2059 {
2060 	menuEnemyType->Draw();
2061 	menuEnemySubtype[enemyType]->Draw();
2062 	menuEnemyParam1->Draw();
2063 	menuEnemyParam2->Draw();
2064 
2065 	return true;
2066 }
2067 
DrawSave()2068 bool HCed::DrawSave()
2069 {
2070 
2071 
2072 	return true;
2073 }
2074 
DrawOpenStory()2075 bool HCed::DrawOpenStory()
2076 {
2077 	switch (inputNewStory)
2078 	{
2079 	case 0:
2080 		// Selecting story
2081 		menuOpenStory->Draw();
2082 		break;
2083 
2084 	case HCED_INPUT_STORY:
2085 		// Input of new story name
2086 		if (imgNewStory)
2087 		{
2088 			imgNewStory->Draw();
2089 		}
2090 		break;
2091 
2092 	case HCED_INPUT_THEME:
2093 		// Selection of theme
2094 		if (imgNewStory)
2095 		{
2096 			imgNewStory->Draw();
2097 		}
2098 
2099 		menuTheme->Draw();
2100 		break;
2101 	}
2102 
2103 	return true;
2104 }
2105 
DrawAppExit()2106 bool HCed::DrawAppExit()
2107 {
2108 
2109 
2110 	return true;
2111 }
2112 
Update()2113 bool HCed::Update()
2114 {
2115 	menuMain->Update();
2116 
2117 	// Updates the objects
2118 	for (s32 i = 0; i < level.numObjects; ++i)
2119 	{
2120 		level.objects[i]->Update();
2121 	}
2122 
2123 	// Updates the ropes
2124 	for (s32 i = 0; i < level.numRopes; ++i)
2125 	{
2126 		level.ropes[i]->Update();
2127 	}
2128 
2129 	// Updates the enemies
2130 	//for (s32 i = 0; i < level.numEnemies; ++i)
2131 	//{
2132 	//	level.enemies[i]->Update();
2133 	//}
2134 
2135 	// Updates the exit
2136 	level.levelExit.Update();
2137 
2138 	switch (state)
2139 	{
2140 	case HCEDSTATE_FLOOR:
2141     return UpdateFloor();
2142 	case HCEDSTATE_CONTFLOOR:
2143 		return UpdateContFloor();
2144 	case HCEDSTATE_LADDER:
2145     return UpdateLadder();
2146 	case HCEDSTATE_BAR:
2147     return UpdateBar();
2148 	case HCEDSTATE_BREAK:
2149     return UpdateBreak();
2150 	case HCEDSTATE_OBJECT:
2151     return UpdateObject();
2152 	case HCEDSTATE_ROPE:
2153     return UpdateRope();
2154 	case HCEDSTATE_START:
2155     return UpdateStart();
2156 	case HCEDSTATE_EXIT:
2157     return UpdateExit();
2158 	case HCEDSTATE_ENEMY:
2159     return UpdateEnemy();
2160 	case HCEDSTATE_SAVE:
2161     return UpdateSave();
2162 	case HCEDSTATE_OPENSTORY:
2163     return UpdateOpenStory();
2164 	case HCEDSTATE_APPEXIT:
2165     return UpdateAppExit();
2166 
2167   default:
2168     break;
2169 	}
2170 
2171 	return true;
2172 }
2173 
UpdateEraseFloor()2174 void HCed::UpdateEraseFloor()
2175 {
2176 	if (MouseBt() & SDL_BUTTON_RIGHT)
2177 	{
2178 		s32 row = level.Map().ToRow(MouseY()), col = level.Map().ToCol(MouseX());
2179 
2180 		// Put a blank cell border around the map, do no let edit those cells
2181 		if (row > 0 && col > 0 && row < level.Map().Rows() - 1 && col < level.Map().Cols() - 1)
2182 		{
2183 			HCCell ***cells = level.Map().Cells();
2184 			float x = cells[row][col]->X(), y = cells[row][col]->Y();
2185 
2186 			// Erases the floor
2187 			JDELETE(cells[row][col]);
2188 			cells[row][col] = new HCCell;
2189 			level.Map().BuildContFloor(row, col);
2190 			cells[row][col]->Subtype(0);
2191 			cells[row][col]->Pos((s32)x, (s32)y);
2192 			level.Map().BuildCellLinkList();
2193 		}
2194 	}
2195 }
2196 
UpdateFloor()2197 bool HCed::UpdateFloor()
2198 {
2199 	// Button down
2200   if (MouseOverMap())
2201 	{
2202 		if (MouseBt() & SDL_BUTTON_LEFT)
2203 		{
2204 			s32 row = level.Map().ToRow(MouseY()), col = level.Map().ToCol(MouseX());
2205 
2206 			// Put a blank cell border around the map, do no let edit those cells
2207 			if (row > 0 && col > 0 && row < level.Map().Rows() - 1 && col < level.Map().Cols() - 1)
2208 			{
2209 				HCCell ***cells = level.Map().Cells();
2210 				float x = cells[row][col]->X(), y = cells[row][col]->Y();
2211 
2212 				if (cells[row][col]->Type() != HCCELLTYPE_FLOOR ||
2213 						cells[row][col]->Subtype() != floorSubtype)
2214 				{
2215 					// Substitutes the floor
2216 					JDELETE(cells[row][col]);
2217 					cells[row][col] = new HCFloorCell(&level.Theme().Floor(floorSubtype));
2218 					cells[row][col]->Subtype(floorSubtype);
2219 					cells[row][col]->Pos((s32)x, (s32)y);
2220 				}
2221 
2222 				level.Map().BuildContFloor(row, col);
2223 				level.Map().BuildCellLinkList();
2224 			}
2225 		}
2226 		else
2227 		{
2228 			UpdateEraseFloor();
2229 		}
2230 	}
2231 
2232 	return true;
2233 }
2234 
UpdateContFloor()2235 bool HCed::UpdateContFloor()
2236 {
2237 	// Button down
2238   if (MouseOverMap())
2239 	{
2240 		if (MouseBt() & SDL_BUTTON_LEFT)
2241 		{
2242 			s32 row = level.Map().ToRow(MouseY()), col = level.Map().ToCol(MouseX());
2243 
2244 			// Put a blank cell border around the map, do no let edit those cells
2245 			if (row > 0 && col > 0 && row < level.Map().Rows() - 1 && col < level.Map().Cols() - 1)
2246 			{
2247 				HCCell ***cells = level.Map().Cells();
2248 				float x = cells[row][col]->X(), y = cells[row][col]->Y();
2249 
2250 				if (cells[row][col]->Type() != HCCELLTYPE_CONTFLOOR ||
2251 						cells[row][col]->Subtype() != contFloorSubtype)
2252 				{
2253 					// Substitutes the floor
2254 					JDELETE(cells[row][col]);
2255 					cells[row][col] = new HCContFloor;
2256 					cells[row][col]->Subtype(contFloorSubtype);
2257 					level.Map().BuildContFloor(row, col);
2258 					cells[row][col]->Pos((s32)x, (s32)y);
2259 					level.Map().BuildCellLinkList();
2260 				}
2261 			}
2262 		}
2263 		else
2264 		{
2265 			UpdateEraseFloor();
2266 		}
2267 	}
2268 
2269 	return true;
2270 }
2271 
UpdateLadder()2272 bool HCed::UpdateLadder()
2273 {
2274 	// Button down
2275   if (MouseOverMap())
2276 	{
2277 		if (MouseBt() & SDL_BUTTON_LEFT)
2278 		{
2279 			s32 row = level.Map().ToRow(MouseY()), col = level.Map().ToCol(MouseX());
2280 
2281 			// Put a blank cell border around the map, do no let edit those cells
2282 			if (row > 0 && col > 0 && row < level.Map().Rows() - 1 && col < level.Map().Cols() - 1)
2283 			{
2284 				HCCell ***cells = level.Map().Cells();
2285 				float x = cells[row][col]->X(), y = cells[row][col]->Y();
2286 
2287 				if (cells[row][col]->Type() != HCCELLTYPE_LADDER ||
2288 						cells[row][col]->Subtype() != ladderSubtype)
2289 				{
2290 					// Substitutes the ladder
2291 					JDELETE(cells[row][col]);
2292 					cells[row][col] = new HCLadderCell(&level.Theme().Ladder(ladderSubtype));
2293 					cells[row][col]->Subtype(ladderSubtype);
2294 					cells[row][col]->Pos((s32)x, (s32)y);
2295 					level.Map().BuildCellLinkList();
2296 				}
2297 
2298 				level.Map().BuildContFloor(row, col);
2299 			}
2300 		}
2301 		else
2302 		{
2303 			UpdateEraseFloor();
2304 		}
2305 	}
2306 
2307 	return true;
2308 }
2309 
UpdateBar()2310 bool HCed::UpdateBar()
2311 {
2312 	// Button down
2313   if (MouseOverMap())
2314 	{
2315 		if (MouseBt() & SDL_BUTTON_LEFT)
2316 		{
2317 			s32 row = level.Map().ToRow(MouseY()), col = level.Map().ToCol(MouseX());
2318 
2319 			// Put a blank cell border around the map, do no let edit those cells
2320 			if (row > 0 && col > 0 && row < level.Map().Rows() - 1 && col < level.Map().Cols() - 1)
2321 			{
2322 				HCCell ***cells = level.Map().Cells();
2323 				float x = cells[row][col]->X(), y = cells[row][col]->Y();
2324 
2325 				if (cells[row][col]->Type() != HCCELLTYPE_BAR ||
2326 						cells[row][col]->Subtype() != barSubtype)
2327 				{
2328 					// Substitutes the bar
2329 					JDELETE(cells[row][col]);
2330 					cells[row][col] = new HCBarCell(&level.Theme().Bar(barSubtype));
2331 					cells[row][col]->Subtype(barSubtype);
2332 					cells[row][col]->Pos((s32)x, (s32)y);
2333 				}
2334 
2335 				level.Map().BuildContFloor(row, col);
2336 				level.Map().BuildCellLinkList();
2337 			}
2338 		}
2339 		else
2340 		{
2341 			UpdateEraseFloor();
2342 		}
2343 	}
2344 
2345 	return true;
2346 }
2347 
UpdateBreak()2348 bool HCed::UpdateBreak()
2349 {
2350 	// Button down
2351   if (MouseOverMap())
2352 	{
2353 		if (MouseBt() & SDL_BUTTON_LEFT)
2354 		{
2355 			s32 row = level.Map().ToRow(MouseY()), col = level.Map().ToCol(MouseX());
2356 
2357 			// Put a blank cell border around the map, do no let edit those cells
2358 			if (row > 0 && col > 0 && row < level.Map().Rows() - 1 && col < level.Map().Cols() - 1)
2359 			{
2360 				HCCell ***cells = level.Map().Cells();
2361 				float x = cells[row][col]->X(), y = cells[row][col]->Y();
2362 
2363 				if (cells[row][col]->Type() != HCCELLTYPE_BREAK ||
2364 						cells[row][col]->Subtype() != breakSubtype)
2365 				{
2366 					// Substitutes the cell
2367 					JDELETE(cells[row][col]);
2368 					cells[row][col] = new HCBreak(level.Theme().Break(breakSubtype));
2369 					cells[row][col]->Subtype(breakSubtype);
2370 					cells[row][col]->Pos((s32)x, (s32)y);
2371 				}
2372 
2373 				level.Map().BuildContFloor(row, col);
2374 				level.Map().BuildCellLinkList();
2375 			}
2376 		}
2377 		else
2378 		{
2379 			UpdateEraseFloor();
2380 		}
2381 	}
2382 
2383 	return true;
2384 }
2385 
UpdateObject()2386 bool HCed::UpdateObject()
2387 {
2388 	// Button down
2389   if (MouseOverMap())
2390 	{
2391 		if (MouseBt() & SDL_BUTTON_LEFT)
2392 		{
2393 			if (curObject != 0)
2394 			{
2395 				// An object is selected
2396 				if (KeyMods() & KMOD_CTRL)
2397 				{
2398 					// Adjust to map cell
2399 					s32 row = level.Map().ToRow(MouseY()), col = level.Map().ToCol(MouseX());
2400 					curObject->Pos(level.Map().ToX(col), level.Map().ToY(row));
2401 				}
2402 				else
2403 				{
2404 					// Place the object right bellow the mouse cursor
2405 					curObject->Pos(MouseX(), MouseY());
2406 				}
2407 			}
2408 			else
2409 			{
2410 				// No selected object, create it
2411 				AddObject(MouseX(), MouseY());
2412 			}
2413 		}
2414 		else
2415 		// Erase object
2416 		if (MouseBt() & SDL_BUTTON_RIGHT)
2417 		{
2418 			// Delete the current object
2419 			DeleteObject();
2420 		}
2421 	}
2422 
2423 	return true;
2424 }
2425 
UpdateRope()2426 bool HCed::UpdateRope()
2427 {
2428 	// Button down
2429   if (MouseOverMap())
2430 	{
2431 		if (MouseBt() & SDL_BUTTON_LEFT)
2432 		{
2433 			if (curRope != 0)
2434 			{
2435 				// A rope is selected
2436 				if (KeyMods() & KMOD_CTRL)
2437 				{
2438 					// Adjust to map cell ('ceiling')
2439 					s32 row = level.Map().ToRow(MouseY()), col = level.Map().ToCol(MouseX());
2440 					curRope->Pos(level.Map().ToX(col) - level.Map().CellWidth()/2,
2441 											 level.Map().ToY(row) - level.Map().CellHeight() + 1);
2442 				}
2443 				else
2444 				if (KeyMods() & KMOD_SHIFT)
2445 				{
2446 					// Adjust the amplitude
2447 					s32 amplitude = abs(MouseX() - (s32)curRope->X());
2448 					curRope->Init(ropePeriod, amplitude, curRope->Length(), level.Theme());
2449 				}
2450 				else
2451 				if (KeyMods() & KMOD_ALT)
2452 				{
2453 					// Adjust the length
2454 					s32 length = abs(MouseY() - (s32)curRope->Y());
2455 					curRope->Init(ropePeriod, curRope->Amplitude(), length, level.Theme());
2456 				}
2457 				else
2458 				{
2459 					// Place the rope right bellow the mouse cursor
2460 					curRope->Pos(MouseX(), MouseY());
2461 				}
2462 			}
2463 			else
2464 			{
2465 				// No selected rope, create it
2466 				AddRope(MouseX(), MouseY());
2467 			}
2468 		}
2469 		else
2470 		// Erase rope
2471 		if (MouseBt() & SDL_BUTTON_RIGHT)
2472 		{
2473 			// Delete the current rope
2474 			DeleteRope();
2475 		}
2476 	}
2477 
2478 	return true;
2479 }
2480 
UpdateStart()2481 bool HCed::UpdateStart()
2482 {
2483 	if (MouseOverMap())
2484 	{
2485 		if (MouseBt() & SDL_BUTTON_LEFT)
2486 		{
2487 			HCMap *m = &level.Map();
2488 
2489 			if ((KeyMods() & KMOD_CTRL))
2490 			{
2491 				s32 row = m->ToRow(MouseY()), col = m->ToCol(MouseX());
2492 				level.character.Pos(m->ToX(col), m->ToY(row));
2493 			}
2494 			else
2495 			{
2496 				level.character.Pos(MouseX(), MouseY());
2497 			}
2498 		}
2499 	}
2500 
2501 	return true;
2502 }
2503 
UpdateExit()2504 bool HCed::UpdateExit()
2505 {
2506 	if (MouseOverMap())
2507 	{
2508 		if (MouseBt() & SDL_BUTTON_LEFT)
2509 		{
2510 			HCMap *m = &level.Map();
2511 			s32 row = m->ToRow(MouseY()), col = m->ToCol(MouseX());
2512 			if (m->ExitRow() != row || m->ExitCol() != col)
2513 			{
2514 				m->ExitRow(row);
2515 				m->ExitCol(col);
2516 				level.levelExit.Init(m, 100);
2517 			}
2518 		}
2519 	}
2520 
2521 	return true;
2522 }
2523 
UpdateEnemy()2524 bool HCed::UpdateEnemy()
2525 {
2526 	// Button down
2527   if (MouseOverMap())
2528 	{
2529 		if (MouseBt() & SDL_BUTTON_LEFT)
2530 		{
2531 			if (curEnemy != 0)
2532 			{
2533 				// An enemy is selected
2534 				if (KeyMods() & KMOD_CTRL)
2535 				{
2536 					// Adjust to map cell
2537 					s32 row = level.Map().ToRow(MouseY()), col = level.Map().ToCol(MouseX());
2538 					curEnemy->Pos(level.Map().ToX(col), level.Map().ToY(row));
2539 				}
2540 				else
2541 				{
2542 					// Place the enemy right bellow the mouse cursor
2543 					curEnemy->Pos(MouseX(), MouseY());
2544 				}
2545 
2546 				curEnemy->Param1(enemyParam1);
2547 				curEnemy->Param2(enemyParam2);
2548 			}
2549 			else
2550 			{
2551 				// No selected enemy, create it
2552 				AddEnemy(MouseX(), MouseY());
2553 			}
2554 		}
2555 		else
2556 		// Erase enemy
2557 		if (MouseBt() & SDL_BUTTON_RIGHT)
2558 		{
2559 			// Delete the current enemy
2560 			DeleteEnemy();
2561 		}
2562 	}
2563 
2564 	return true;
2565 }
2566 
UpdateSave()2567 bool HCed::UpdateSave()
2568 {
2569 
2570 
2571 	return true;
2572 }
2573 
UpdateOpenStory()2574 bool HCed::UpdateOpenStory()
2575 {
2576 	switch (inputNewStory)
2577 	{
2578 	case 0:
2579 		// Only updates if not waiting for user input on new story
2580 		menuOpenStory->Update();
2581 		break;
2582 
2583 	case 2:
2584 		menuTheme->Update();
2585 		break;
2586 
2587 	default:
2588 		break;
2589 	}
2590 
2591 	return true;
2592 }
2593 
UpdateAppExit()2594 bool HCed::UpdateAppExit()
2595 {
2596 
2597 
2598 	return true;
2599 }
2600 
OnFilenameChange()2601 void HCed::OnFilenameChange()
2602 {
2603 	JString strTitle;
2604 	strTitle.Format("%s - HCed v1.0", filename.Str());
2605 	Title(strTitle);
2606 }
2607 
OnGravityChange()2608 void HCed::OnGravityChange()
2609 {
2610 	SDL_Color c;
2611 
2612 	float maxG = theApp->level.Map().CellHeight()/5.0f;
2613 
2614 	// Forces the gravity value to be between maxG and -maxG
2615 	float g = theApp->level.Map().Gravity();
2616 	JClamp(g, -maxG, maxG);
2617 	theApp->level.Map().Gravity(g);
2618 
2619 	// Positive values tend to green, negative ones tend to red.
2620 	c.unused = 255;
2621 	c.b = 0;
2622 	c.g = (u8)(255 * ((g + maxG)/(2.0f * maxG)));
2623 	c.r = 255 - c.g;
2624 
2625 	JDELETE(theApp->imgGravity);
2626 	theApp->imgGravity = theApp->fontSmall.PrintfBlended(JFONTALIGN_LEFT, c, "g: %1.1f", theApp->level.Map().Gravity());
2627 }
2628 
OnCharVxChange()2629 void HCed::OnCharVxChange()
2630 {
2631 	SDL_Color c;
2632 
2633 	float maxVx = theApp->level.Map().CellWidth() - 1;
2634 
2635 	// Forces the Vx value to be between maxVx and 0
2636 	float v = theApp->level.character.MaxVeloccity().x;
2637 	JClamp(v, 0.0f, maxVx);
2638 	theApp->level.character.MaxVeloccity().x = v;
2639 
2640 	// Greater values tend to yellow, small ones tend to grey.
2641 	c.unused = 255;
2642 	c.b = 127 + (u8)(255 * (v/(2.0f * maxVx)));
2643 	c.r = c.g;
2644 	c.g = 127;
2645 
2646 	JDELETE(theApp->imgCharVx);
2647 	theApp->imgCharVx = theApp->fontSmall.PrintfBlended(JFONTALIGN_LEFT, c, "vX:%1.1f", theApp->level.character.MaxVeloccity().x);
2648 }
2649 
OnCharVyChange()2650 void HCed::OnCharVyChange()
2651 {
2652 	SDL_Color c;
2653 
2654 	float maxVy = theApp->level.Map().CellWidth() - 1;
2655 
2656 	// Forces the Vy value to be between maxVy and 0
2657 	float v = theApp->level.character.MaxVeloccity().y;
2658 	JClamp(v, 0.0f, maxVy);
2659 	theApp->level.character.MaxVeloccity().y = v;
2660 
2661 	// Greater values tend to yellow, small ones tend to grey.
2662 	c.unused = 255;
2663 	c.g = 127 + (u8)(255 * (v/(2.0f * maxVy)));
2664 	c.r = c.g;
2665 	c.b = 127;
2666 
2667 	JDELETE(theApp->imgCharVy);
2668 	theApp->imgCharVy = theApp->fontSmall.PrintfBlended(JFONTALIGN_LEFT, c, "vY:%1.1f", theApp->level.character.MaxVeloccity().y);
2669 }
2670 
OnCharJumpRowsChange()2671 void HCed::OnCharJumpRowsChange()
2672 {
2673 	SDL_Color c;
2674 
2675 	s32 maxJ = theApp->level.Map().Rows();
2676 
2677 	// Forces the jump value to be between maxJ and 0
2678 	s32 j = theApp->level.character.MaxJumpRows();
2679 	JClamp(j, 0, maxJ);
2680 	theApp->level.character.MaxJumpRows(j);
2681 
2682 	// Greater values tend to light blue, small ones tend to dark blue.
2683 	c.unused = 255;
2684 	c.b = 127 + (u8)(255 * (j/(2.0f * maxJ)));
2685 	c.r = c.b/2;
2686 	c.g = 127;
2687 
2688 	JDELETE(theApp->imgCharJumpRows);
2689 	theApp->imgCharJumpRows = theApp->fontSmall.PrintfBlended(JFONTALIGN_LEFT, c, "Jump:%d", theApp->level.character.MaxJumpRows());
2690 }
2691 
OnMapSizeChange()2692 void HCed::OnMapSizeChange()
2693 {
2694 	SDL_Color c;
2695 
2696 	c.unused = 255;
2697 	c.r = 0xff;
2698 	c.b = 0xcc;
2699 	c.g = 0x00;
2700 
2701 	JDELETE(theApp->imgMapSize);
2702 	theApp->imgMapSize = theApp->fontSmall.PrintfBlended(JFONTALIGN_LEFT,
2703 																											 c,
2704 																											 "Map: %dx%d",
2705 																											 theApp->level.map.Rows(),
2706 																											 theApp->level.map.Cols());
2707 }
2708 
OnFloor(void * data)2709 void HCed::OnFloor(void *data)
2710 {
2711 	theApp->state = HCEDSTATE_FLOOR;
2712 	theApp->imgMouse = &theApp->level.Theme().Floor(theApp->floorSubtype);
2713 }
2714 
OnContFloor(void * data)2715 void HCed::OnContFloor(void *data)
2716 {
2717 	theApp->state = HCEDSTATE_CONTFLOOR;
2718 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2719 }
2720 
OnLadder(void * data)2721 void HCed::OnLadder(void *data)
2722 {
2723 	theApp->state = HCEDSTATE_LADDER;
2724 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2725 }
2726 
OnBar(void * data)2727 void HCed::OnBar(void *data)
2728 {
2729 	theApp->state = HCEDSTATE_BAR;
2730 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2731 }
2732 
OnBreak(void * data)2733 void HCed::OnBreak(void *data)
2734 {
2735 	theApp->state = HCEDSTATE_BREAK;
2736 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2737 }
2738 
OnObject(void * data)2739 void HCed::OnObject(void *data)
2740 {
2741 	theApp->state = HCEDSTATE_OBJECT;
2742 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2743 }
2744 
OnRope(void * data)2745 void HCed::OnRope(void *data)
2746 {
2747 	theApp->state = HCEDSTATE_ROPE;
2748 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2749 }
2750 
OnStart(void * data)2751 void HCed::OnStart(void *data)
2752 {
2753 	theApp->state = HCEDSTATE_START;
2754 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2755 }
2756 
OnExit(void * data)2757 void HCed::OnExit(void *data)
2758 {
2759 	theApp->state = HCEDSTATE_EXIT;
2760 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2761 }
2762 
OnEnemy(void * data)2763 void HCed::OnEnemy(void *data)
2764 {
2765 	theApp->state = HCEDSTATE_ENEMY;
2766 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2767 }
2768 
OnSave(void * data)2769 void HCed::OnSave(void *data)
2770 {
2771 	HCedState old = theApp->state;
2772 	theApp->state = HCEDSTATE_SAVE;
2773 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2774 	theApp->Draw();
2775 
2776 	// Save in the command line-given file.
2777 	JRW file;
2778 
2779 	if (file.Create(theApp->filename, "wb"))
2780 	{
2781 		fprintf(stderr, "Saving the level to %s.\n", theApp->filename.Str());
2782 
2783 		if (0 != theApp->level.Save(file))
2784 		{
2785 			fprintf(stderr, "Could not save the level to %s.\n", theApp->filename.Str());
2786 		}
2787 
2788 		file.Close();
2789 	}
2790 	else
2791 	{
2792 		fprintf(stderr, "Could not open file %s.\n", theApp->filename.Str());
2793 	}
2794 
2795 	// Return to the old state
2796 	theApp->state = old;
2797 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2798 }
2799 
OnOpenStory(void * data)2800 void HCed::OnOpenStory(void *data)
2801 {
2802 	theApp->state = HCEDSTATE_OPENSTORY;
2803 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2804 	theApp->strNewStoryName = "";
2805 }
2806 
OnSelectStory(void * data)2807 void HCed::OnSelectStory(void *data)
2808 {
2809 	if ((long)data < 0)
2810 	{
2811 		theApp->inputNewStory = HCED_INPUT_STORY;
2812 
2813 		// Updates the input string
2814 		JDELETE(theApp->imgNewStory);
2815 		SDL_Color fg = {0xff, 0xcc, 0x00, 0x00};
2816 		SDL_Color bg = {0x00, 0x00, 0x00, 0x00};
2817 		theApp->imgNewStory = theApp->fontLarge.RenderTextShaded("Name: ", fg, bg);
2818 	}
2819 	else
2820 	{
2821 		theApp->OnFloor(0);
2822 		theApp->filename = JString(theApp->storyDir) + JString(HCUtil::Stories()[(long)data]) + "/level001.hlv";
2823 
2824 		if (0 != theApp->NewLevel())
2825 		{
2826 			fprintf(stderr, "Error loading %s\n", theApp->filename.Str());
2827 			return;
2828 		}
2829 
2830 		theApp->storyName = HCUtil::Stories()[(long)data];
2831 		theApp->levelNumber = 1;
2832 	}
2833 }
2834 
OnSelectTheme(void * data)2835 void HCed::OnSelectTheme(void *data)
2836 {
2837 	s32 rt = HCUtil::CreateStory(theApp->strNewStoryName);
2838 
2839 	switch (rt)
2840 	{
2841 	case 0:
2842 		{
2843 			// Creates new story
2844 			JString oldName = theApp->filename;
2845 			JString oldTheme = theApp->themeName;
2846 			s32 oldLevel = theApp->levelNumber;
2847 			theApp->filename = JString(theApp->storyDir) + JString(theApp->strNewStoryName) + JString("/level001.hlv");
2848 			theApp->themeName = HCUtil::Themes()[(long)data];
2849 			theApp->levelNumber = 1;
2850 
2851 			if (0 != theApp->NewLevel())
2852 			{
2853 				fprintf(stderr, "Error initializing new level %s\n", (const char *)theApp->filename);
2854 				theApp->filename = oldName;
2855 				theApp->themeName = oldTheme;
2856 				theApp->levelNumber = oldLevel;
2857 			}
2858 			else
2859 			{
2860 				// All went right
2861 				JDELETE(theApp->imgNewStory);
2862 				theApp->storyName = theApp->strNewStoryName;
2863 				theApp->inputNewStory = 0;
2864 			}
2865 		}
2866 		break;
2867 
2868 	case 1:	fprintf(stderr, "Story %s already exists, give it a different name, please.\n", (const char *)theApp->strNewStoryName);	break;
2869 	case 2:	fprintf(stderr, "Directory 'stories' could not be found, check installation.\n");	break;
2870 	case 3:	fprintf(stderr, "Couldn't create story. Check permissions for %s.\n", (const char *)theApp->strNewStoryName);	break;
2871 	default:
2872 		break;
2873 	}
2874 }
2875 
OnAppExit(void * data)2876 void HCed::OnAppExit(void *data)
2877 {
2878 	theApp->state = HCEDSTATE_APPEXIT;
2879 	theApp->imgMouse = &theApp->imgMenu[theApp->state];
2880 	theApp->Exit();
2881 }
2882 
OnMainSubtype(void * data)2883 void HCed::OnMainSubtype(void *data)
2884 {
2885 	theApp->level.character.subtype = (long)data;
2886 	theApp->level.character.Init(theApp->level.theme.MainChar((long)data), &theApp->level.map);
2887 }
2888 
OnFloorSubtype(void * data)2889 void HCed::OnFloorSubtype(void *data)
2890 {
2891 	theApp->floorSubtype = (long)data;
2892 	theApp->imgMouse = &(theApp->level.Theme().Floor(theApp->floorSubtype));
2893 }
2894 
OnContFloorSubtype(void * data)2895 void HCed::OnContFloorSubtype(void *data)
2896 {
2897 	theApp->contFloorSubtype = (long)data;
2898 	theApp->imgMouse = &(theApp->level.Theme().ContFloor(theApp->contFloorSubtype)[HCFDT_I]);
2899 }
2900 
OnBarSubtype(void * data)2901 void HCed::OnBarSubtype(void *data)
2902 {
2903 	theApp->barSubtype = (long)data;
2904 	theApp->imgMouse = &(theApp->level.Theme().Bar(theApp->barSubtype));
2905 }
2906 
OnLadderSubtype(void * data)2907 void HCed::OnLadderSubtype(void *data)
2908 {
2909 	theApp->ladderSubtype = (long)data;
2910 	theApp->imgMouse = &(theApp->level.Theme().Ladder(theApp->ladderSubtype));
2911 }
2912 
OnBreakSubtype(void * data)2913 void HCed::OnBreakSubtype(void *data)
2914 {
2915 	theApp->breakSubtype = (long)data;
2916 	theApp->imgMouse = (JImage *)(theApp->level.Theme().Break(theApp->breakSubtype)[HCBDT_NORMAL].Frame(0));
2917 }
2918 
OnObjectSubtype(void * data)2919 void HCed::OnObjectSubtype(void *data)
2920 {
2921 	theApp->objectSubtype = (long)data;
2922 	theApp->imgMouse = (JImage *)(theApp->level.Theme().Object(theApp->objectSubtype)[HCODT_NORMAL].Frame(0));
2923 }
2924 
OnRopeSubtype(void * data)2925 void HCed::OnRopeSubtype(void *data)
2926 {
2927 	theApp->ropeSubtype = (long)data;
2928 	theApp->imgMouse = &(theApp->level.Theme().Rope(theApp->ropeSubtype)[HCRDT_TOP]);
2929 }
2930 
OnRopePeriod(void * data)2931 void HCed::OnRopePeriod(void *data)
2932 {
2933 	theApp->ropePeriod = 0.5f + (0.25f * float((long)data));
2934 }
2935 
OnEnemySubtype(void * data)2936 void HCed::OnEnemySubtype(void *data)
2937 {
2938 	theApp->enemySubtype = (long)data;
2939 	theApp->imgMouse = (JImage *)(theApp->GetEnemySprites(theApp->enemyType, theApp->enemySubtype)[HCCDT_STOP].Frame(0));
2940 }
2941 
OnEnemyType(void * data)2942 void HCed::OnEnemyType(void *data)
2943 {
2944 	// 0 always is a valid subtype so init to that
2945 	theApp->enemySubtype = 0;
2946 
2947 	theApp->enemyType = (HCEnemyType)(long)data;
2948 	theApp->imgMouse = (JImage *)(theApp->GetEnemySprites(theApp->enemyType, theApp->enemySubtype)[HCCDT_STOP].Frame(0));
2949 }
2950 
OnEnemyParam1(void * data)2951 void HCed::OnEnemyParam1(void *data)
2952 {
2953 	theApp->enemyParam1 = (long)data;
2954 }
2955 
OnEnemyParam2(void * data)2956 void HCed::OnEnemyParam2(void *data)
2957 {
2958 	theApp->enemyParam2 = (long)data;
2959 }
2960 
MouseOverMap()2961 bool HCed::MouseOverMap()
2962 {
2963 	return 	(MouseX() > HCED_MARGIN &&
2964 					 MouseX() < (level.Map().X() + (level.Map().Cols() * level.Map().CellWidth())) &&
2965 					 MouseY() > HCED_MARGIN &&
2966 					 MouseY() < (level.Map().Y() + (level.Map().Rows() * level.Map().CellHeight())));
2967 }
2968 
AddObject(s32 x,s32 y)2969 void HCed::AddObject(s32 x, s32 y)
2970 {
2971 	curObject = new HCObject;
2972 
2973 	// Update the level objects
2974 	HCObject **tmp = level.objects;
2975 
2976 	level.objects = new HCObject *[level.numObjects + 1];
2977 
2978 	// Copies the old elements
2979 	s32 i = 0;
2980 	for (i = 0; i < level.numObjects; ++i)
2981 	{
2982 		level.objects[i] = tmp[i];
2983 	}
2984 
2985 	// New and last element
2986 	level.objects[i] = curObject;
2987 
2988 	++level.numObjects;
2989 
2990 	curObject->Subtype(objectSubtype);
2991 	curObject->Init(&level.Theme());
2992 	curObject->Pos(x, y);
2993 
2994 	// If it exists, deletes the old array of pointers (not the pointers inside)
2995 	JDELETE_ARRAY(tmp);
2996 }
2997 
AddRope(s32 x,s32 y)2998 void HCed::AddRope(s32 x, s32 y)
2999 {
3000 	curRope = new HCRope();
3001 	curRope->Init(ropePeriod, 0, 0, level.Theme());
3002 	curRope->Subtype(ropeSubtype);
3003 
3004 	// Update the level ropes
3005 	HCRope **tmp = level.ropes;
3006 
3007 	level.ropes = new HCRope *[level.numRopes + 1];
3008 
3009 	// Copies the old elements
3010 	s32 i = 0;
3011 	for (i = 0; i < level.numRopes; ++i)
3012 	{
3013 		level.ropes[i] = tmp[i];
3014 	}
3015 
3016 	// New and last element
3017 	level.ropes[i] = curRope;
3018 
3019 	++level.numRopes;
3020 
3021 	curRope->Pos(x, y);
3022 
3023 	// If it exists, deletes the old array of pointers (not the pointers inside)
3024 	JDELETE_ARRAY(tmp);
3025 }
3026 
AddEnemy(s32 x,s32 y)3027 void HCed::AddEnemy(s32 x, s32 y)
3028 {
3029 	switch (enemyType)
3030 	{
3031 	default:
3032 	case HCENEMYTYPE_BALL:
3033 		curEnemy = new HCEnemyBall();
3034 		curEnemy->Init(level.Theme().Ball(enemySubtype), &level.Map());
3035 		break;
3036 
3037 	case HCENEMYTYPE_RANDOM:
3038 		curEnemy = new HCEnemyRandom();
3039 		curEnemy->Init(level.Theme().Random(enemySubtype), &level.Map());
3040 		break;
3041 
3042 	case HCENEMYTYPE_STATIC:
3043 		curEnemy = new HCEnemyStatic();
3044 		curEnemy->Init(level.Theme().Static(enemySubtype), &level.Map());
3045 		break;
3046 
3047 	case HCENEMYTYPE_MAKER:
3048 		curEnemy = new HCEnemyMaker();
3049 		curEnemy->Init(level.Theme().Maker(enemySubtype), &level.Map());
3050 		break;
3051 
3052 	case HCENEMYTYPE_CHASER:
3053 		curEnemy = new HCEnemyChaser();
3054 		curEnemy->Init(level.Theme().Chaser(enemySubtype), &level.Map());
3055 		break;
3056 	}
3057 
3058 	curEnemy->Subtype(enemySubtype);
3059 	curEnemy->Param1(enemyParam1);
3060 	curEnemy->Param2(enemyParam2);
3061 
3062 	// Update the level enemies
3063 	HCEnemy **tmp = level.enemies;
3064 
3065 	level.enemies = new HCEnemy *[level.numEnemies + 1];
3066 
3067 	// Copies the old elements
3068 	s32 i = 0;
3069 	for (i = 0; i < level.numEnemies; ++i)
3070 	{
3071 		level.enemies[i] = tmp[i];
3072 	}
3073 
3074 	// New and last element
3075 	level.enemies[i] = curEnemy;
3076 
3077 	++level.numEnemies;
3078 
3079 	curEnemy->Pos(x, y);
3080 
3081 	// If it exists, deletes the old array of pointers (not the pointers inside)
3082 	JDELETE_ARRAY(tmp);
3083 }
3084 
DeleteObject()3085 void HCed::DeleteObject()
3086 {
3087 	if (curObject)
3088 	{
3089 		// Update the level objects
3090 		HCObject **tmp = level.objects;
3091 
3092 		level.objects = new HCObject *[level.numObjects - 1];
3093 
3094 		// Copies all but the selected object
3095 		for (s32 i = 0, newI = 0; i < level.numObjects; ++i, ++newI)
3096 		{
3097 			if (tmp[i] != curObject)
3098 			{
3099 				level.objects[newI] = tmp[i];
3100 			}
3101 			else
3102 			{
3103 				// Note that tmp is 1 element larger than level.objects
3104 				// we have to delay 1 its index after curObject has been found inside of it
3105 				--newI;
3106 			}
3107 		}
3108 
3109 		--level.numObjects;
3110 
3111 		// If it exists, deletes the old array of pointers (not the pointers inside)
3112 		JDELETE_ARRAY(tmp);
3113 
3114 		delete curObject;
3115 		curObject = 0;
3116 	}
3117 }
3118 
DeleteRope()3119 void HCed::DeleteRope()
3120 {
3121 	if (curRope)
3122 	{
3123 		// Update the level ropes
3124 		HCRope **tmp = level.ropes;
3125 
3126 		level.ropes = new HCRope *[level.numRopes - 1];
3127 
3128 		// Copies all but the selected rope
3129 		for (s32 i = 0, newI = 0; i < level.numRopes; ++i, ++newI)
3130 		{
3131 			if (tmp[i] != curRope)
3132 			{
3133 				level.ropes[newI] = tmp[i];
3134 			}
3135 			else
3136 			{
3137 				// Note that tmp is 1 element larger than level.ropes
3138 				// we have to delay 1 its index after curRope has been found inside of it
3139 				--newI;
3140 			}
3141 		}
3142 
3143 		--level.numRopes;
3144 
3145 		// If it exists, deletes the old array of pointers (not the pointers inside)
3146 		JDELETE_ARRAY(tmp);
3147 
3148 		delete curRope;
3149 		curRope = 0;
3150 	}
3151 }
3152 
DeleteEnemy()3153 void HCed::DeleteEnemy()
3154 {
3155 	if (curEnemy)
3156 	{
3157 		// Update the level enemies
3158 		HCEnemy **tmp = level.enemies;
3159 
3160 		level.enemies = new HCEnemy *[level.numEnemies - 1];
3161 
3162 		// Copies all but the selected enemy
3163 		for (s32 i = 0, newI = 0; i < level.numEnemies; ++i, ++newI)
3164 		{
3165 			if (tmp[i] != curEnemy)
3166 			{
3167 				level.enemies[newI] = tmp[i];
3168 			}
3169 			else
3170 			{
3171 				// Note that tmp is 1 element larger than level.enemies
3172 				// we have to delay 1 its index after curEnemy has been found inside of it
3173 				--newI;
3174 			}
3175 		}
3176 
3177 		--level.numEnemies;
3178 
3179 		// If it exists, deletes the old array of pointers (not the pointers inside)
3180 		JDELETE_ARRAY(tmp);
3181 
3182 		delete curEnemy;
3183 		curEnemy = 0;
3184 	}
3185 }
3186 
GetEnemySprites(HCEnemyType t,s32 s)3187 JImageSprite * HCed::GetEnemySprites(HCEnemyType t, s32 s)
3188 {
3189 	switch (t)
3190 	{
3191 	case HCENEMYTYPE_BALL:
3192 		return level.theme.Ball(s);
3193 
3194 	case HCENEMYTYPE_STATIC:
3195 		return level.theme.Static(s);
3196 
3197 	case HCENEMYTYPE_MAKER:
3198 		return level.theme.Maker(s);
3199 
3200 	case HCENEMYTYPE_RANDOM:
3201 		return level.theme.Random(s);
3202 
3203 	case HCENEMYTYPE_CHASER:
3204 		return level.theme.Chaser(s);
3205 
3206   default:
3207     break;
3208 	}
3209 
3210 	return 0;
3211 }
3212 
GetNumEnemySprites(HCEnemyType t)3213 s32 HCed::GetNumEnemySprites(HCEnemyType t)
3214 {
3215 	switch (t)
3216 	{
3217 	case HCENEMYTYPE_BALL:
3218 		return level.theme.NumBalls();
3219 
3220 	case HCENEMYTYPE_STATIC:
3221 		return level.theme.NumStatics();
3222 
3223 	case HCENEMYTYPE_MAKER:
3224 		return level.theme.NumMakers();
3225 
3226 	case HCENEMYTYPE_RANDOM:
3227 		return level.theme.NumRandoms();
3228 
3229 	case HCENEMYTYPE_CHASER:
3230 		return level.theme.NumChasers();
3231 
3232   default:
3233     break;
3234 	}
3235 
3236 	return 0;
3237 }
3238 
DestroyMainSubtypeMenu()3239 void HCed::DestroyMainSubtypeMenu()
3240 {
3241 	if (menuMainSubtype)
3242 	{
3243 		JImage *img;
3244 		JTree<JImageMenuEntry *>::Iterator *it;
3245 		it = menuMainSubtype->Menu();
3246 		it->Root();
3247 
3248 		do
3249 		{
3250 			if (it->Data())
3251 			{
3252 				img = it->Data()->Image();
3253 				JDELETE(img);
3254 				img = it->Data()->HiImage();
3255 				JDELETE(img);
3256 			}
3257 		} while (it->Next());
3258 
3259 		delete menuMainSubtype;
3260 	}
3261 }
3262 
DestroyBreakSubtypeMenu()3263 void HCed::DestroyBreakSubtypeMenu()
3264 {
3265 	if (menuBreakSubtype)
3266 	{
3267 		JImage *img;
3268 		JTree<JImageMenuEntry *>::Iterator *it;
3269 		it = menuBreakSubtype->Menu();
3270 		it->Root();
3271 
3272 		do
3273 		{
3274 			if (it->Data())
3275 			{
3276 				img = it->Data()->Image();
3277 				JDELETE(img);
3278 				img = it->Data()->HiImage();
3279 				JDELETE(img);
3280 			}
3281 		} while (it->Next());
3282 
3283 		delete menuBreakSubtype;
3284 	}
3285 }
3286 
DestroyObjectSubtypeMenu()3287 void HCed::DestroyObjectSubtypeMenu()
3288 {
3289 	if (menuObjectSubtype)
3290 	{
3291 		JImage *img;
3292 		JTree<JImageMenuEntry *>::Iterator *it;
3293 		it = menuObjectSubtype->Menu();
3294 		it->Root();
3295 
3296 		do
3297 		{
3298 			if (it->Data())
3299 			{
3300 				img = it->Data()->Image();
3301 				JDELETE(img);
3302 				img = it->Data()->HiImage();
3303 				JDELETE(img);
3304 			}
3305 		} while (it->Next());
3306 
3307 		delete menuObjectSubtype;
3308 	}
3309 }
3310 
DestroyEnemySubtypeMenu()3311 void HCed::DestroyEnemySubtypeMenu()
3312 {
3313 	JImage *img;
3314 	JTree<JImageMenuEntry *>::Iterator *it;
3315 
3316 	for (s32 n = 0; n < HCENEMYTYPE_COUNT; ++n)
3317 	{
3318 		if (menuEnemySubtype[n])
3319 		{
3320 			it = menuEnemySubtype[n]->Menu();
3321 			it->Root();
3322 
3323 			do
3324 			{
3325 				if (it->Data())
3326 				{
3327 					img = it->Data()->Image();
3328 					JDELETE(img);
3329 					img = it->Data()->HiImage();
3330 					JDELETE(img);
3331 				}
3332 			} while (it->Next());
3333 
3334 			delete menuEnemySubtype[n];
3335 		}
3336 	}
3337 }
3338 
DestroyLevelMenus()3339 void HCed::DestroyLevelMenus()
3340 {
3341   DestroyMainSubtypeMenu();
3342   DestroyBreakSubtypeMenu();
3343   DestroyObjectSubtypeMenu();
3344   DestroyEnemySubtypeMenu();
3345 }
3346 
~HCed()3347 HCed::~HCed()
3348 {
3349 	JDELETE(menuMain);
3350 	JDELETE(menuEnemyType);
3351 	JDELETE(menuEnemyParam1);
3352 	JDELETE(menuEnemyParam2);
3353 	JDELETE(menuRopePeriod);
3354 	JDELETE(menuFloorSubtype);
3355 	JDELETE(menuContFloorSubtype);
3356 	JDELETE(menuBarSubtype);
3357 	JDELETE(menuLadderSubtype);
3358 	JDELETE(menuRopeSubtype);
3359 	JDELETE(menuOpenStory);
3360 	JDELETE(menuTheme);
3361 
3362 	DestroyLevelMenus();
3363 
3364 	JDELETE(imgGravity);
3365 	JDELETE(imgCharVx);
3366 	JDELETE(imgCharVy);
3367 	JDELETE(imgCharJumpRows);
3368 	JDELETE(imgMapSize);
3369 }
3370 
main(s32 argc,char ** argv)3371 int main(s32 argc, char **argv)
3372 {
3373 	HCed editor;
3374 
3375 	theApp = &editor;
3376 
3377 	if (!editor.Init(argc, argv))
3378 	{
3379 		fprintf(stderr, "Error launching the editor.\n");
3380 
3381 		return -1;
3382 	}
3383 
3384 	return editor.MainLoop();
3385 }
3386