1 //       _________ __                 __
2 //      /   _____//  |_____________ _/  |______     ____  __ __  ______
3 //      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
4 //      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
5 //     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
6 //             \/                  \/          \//_____/            \/
7 //  ______________________                           ______________________
8 //                        T H E   W A R   B E G I N S
9 //         Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name stratagus.cpp - The main file. */
12 //
13 //      (c) Copyright 1998-2015 by Lutz Sammer, Francois Beerten,
14 //                                 Jimmy Salmon, Pali Rohár and cybermind
15 //
16 //      This program is free software; you can redistribute it and/or modify
17 //      it under the terms of the GNU General Public License as published by
18 //      the Free Software Foundation; only version 2 of the License.
19 //
20 //      This program is distributed in the hope that it will be useful,
21 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
22 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 //      GNU General Public License for more details.
24 //
25 //      You should have received a copy of the GNU General Public License
26 //      along with this program; if not, write to the Free Software
27 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 //      02111-1307, USA.
29 //
30 
31 //@{
32 
33 /**
34 ** @mainpage
35 **
36 ** @section Introduction Introduction
37 **
38 ** Welcome to the source code documentation of the Stratagus engine.
39 ** Extract the source documentation with doxygen (http://www.doxygen.org) tool.
40 **
41 ** Any help to improve this documention is welcome. If you didn't
42 ** understand something or you found an error or a wrong spelling
43 ** or wrong grammar please write an email (including a patch :).
44 **
45 ** @section Information Information
46 **
47 ** Visit the https://github.com/Andrettin/Wyrmgus web page for the latest news and
48 ** <A HREF="../index.html">Stratagus Info</A> for other documentation.
49 **
50 ** @section Modules Modules
51 **
52 ** This are the main modules of the Stratagus engine.
53 **
54 ** @subsection Map Map
55 **
56 ** Handles the map. A map is made from tiles.
57 **
58 ** @see map.h @see map.cpp @see tileset.h @see tileset.cpp
59 **
60 ** @subsection Unit Unit
61 **
62 ** Handles units. Units are ships, flyers, buildings, creatures,
63 ** machines.
64 **
65 ** @see unit.h @see unit.cpp @see unittype.h @see unittype.cpp
66 **
67 ** @subsection Missile Missile
68 **
69 ** Handles missiles. Missiles are all other sprites on map
70 ** which are no unit.
71 **
72 ** @see missile.h @see missile.cpp
73 **
74 ** @subsection Player Player
75 **
76 ** Handles players, all units are owned by a player. A player
77 ** could be controlled by a human or a computer.
78 **
79 ** @see player.h @see player.cpp @see ::CPlayer
80 **
81 ** @subsection Sound Sound
82 **
83 ** Handles the high and low level of the sound. There are the
84 ** background music support, voices and sound effects.
85 ** Following low level backends are supported: OSS and SDL.
86 **
87 ** @todo adpcm file format support for sound effects
88 ** @todo better separation of low and high level, assembler mixing
89 ** support.
90 ** @todo Streaming support of ogg/mp3 files.
91 **
92 ** @see sound.h @see sound.cpp
93 ** @see script_sound.cpp @see sound_id.cpp @see sound_server.cpp
94 ** @see unitsound.cpp
95 ** @see sdl_audio.cpp
96 ** @see ogg.cpp @see wav.cpp
97 **
98 ** @subsection Video Video
99 **
100 ** Handles the high and low level of the graphics.
101 ** This also contains the sprite and linedrawing routines.
102 **
103 ** See page @ref VideoModule for more information upon supported
104 ** features and video platforms.
105 **
106 ** @see video.h @see video.cpp
107 **
108 ** @subsection Network Network
109 **
110 ** Handles the high and low level of the network protocol.
111 ** The network protocol is needed for multiplayer games.
112 **
113 ** See page @ref NetworkModule for more information upon supported
114 ** features and API.
115 **
116 ** @see network.h @see network.cpp
117 **
118 ** @subsection Pathfinder Pathfinder
119 **
120 ** @see pathfinder.h @see pathfinder.cpp
121 **
122 ** @subsection AI AI
123 **
124 ** There are currently two AI's. The old one is very hardcoded,
125 ** but does things like placing buildings better than the new.
126 ** The old AI shouldn't be used.  The new is very flexible, but
127 ** very basic. It includes none optimations.
128 **
129 ** See page @ref AiModule for more information upon supported
130 ** features and API.
131 **
132 ** @see ai_local.h
133 ** @see ai.h @see ai.cpp
134 **
135 ** @subsection CCL CCL
136 **
137 ** CCL is Craft Configuration Language, which is used to
138 ** configure and customize Stratagus.
139 **
140 ** @see script.h @see script.cpp
141 **
142 ** @subsection Icon Icon
143 **
144 ** @see icons.h @see icons.cpp
145 **
146 ** @subsection Editor Editor
147 **
148 ** This is the integrated editor, it shouldn't be a perfect
149 ** editor. It is used to test new features of the engine.
150 **
151 ** See page @ref EditorModule for more information upon supported
152 ** features and API.
153 **
154 ** @see editor.h @see editor.cpp
155 */
156 
157 /*----------------------------------------------------------------------------
158 --  Includes
159 ----------------------------------------------------------------------------*/
160 
161 #include <ctype.h>
162 
163 #ifdef USE_BEOS
164 #include <fcntl.h>
165 #include <sys/types.h>
166 #include <sys/stat.h>
167 
168 extern void beos_init(int argc, char **argv);
169 
170 #endif
171 
172 #ifdef MAC_BUNDLE
173 #define Button ButtonOSX
174 #include <Carbon/Carbon.h>
175 #undef Button
176 #endif
177 
178 #include "SDL.h"
179 
180 #include "stratagus.h"
181 
182 #include "ai.h"
183 //Wyrmgus start
184 #include "character.h"
185 //Wyrmgus end
186 #include "editor.h"
187 #include "game.h"
188 #include "guichan.h"
189 #include "iocompat.h"
190 #include "iolib.h"
191 #include "map/map.h"
192 #include "netconnect.h"
193 #include "network.h"
194 #include "parameters.h"
195 #include "player.h"
196 #include "replay.h"
197 #include "results.h"
198 #include "settings.h"
199 #include "sound_server.h"
200 #include "time/calendar.h"
201 #include "time/timeline.h"
202 #include "title.h"
203 #include "translate.h"
204 #include "ui/interface.h"
205 #include "ui/ui.h"
206 #include "unit/unit_manager.h"
207 #include "version.h"
208 #include "video.h"
209 #include "widgets.h"
210 #include "util.h"
211 
212 #include "missile.h" //for FreeBurningBuildingFrames
213 
214 #ifdef USE_STACKTRACE
215 #include <stdexcept>
216 #include <stacktrace/call_stack.hpp>
217 #include <stacktrace/stack_exception.hpp>
218 #endif
219 
220 #include <stdlib.h>
221 #include <stdio.h>
222 
223 #ifdef USE_WIN32
224 #include <windows.h>
225 #include <dbghelp.h>
226 #endif
227 
228 #ifdef USE_PHYSFS
229 #include <physfs.h>
230 #endif
231 
232 #if defined(USE_WIN32) && ! defined(NO_STDIO_REDIRECT)
233 #include "windows.h"
234 #define REDIRECT_OUTPUT
235 #endif
236 
237 #if defined(USE_WIN32) && ! defined(REDIRECT_OUTPUT)
238 #include "SetupConsole_win32.h"
239 #endif
240 
241 #ifdef __MORPHOS__
242 unsigned long __stack = 1000000;
243 __attribute__ ((section(".text"))) UBYTE VString[] = "$VER: Wyrmsun " VERSION "\r\n";
244 #endif
245 
246 /*----------------------------------------------------------------------------
247 --  Variables
248 ----------------------------------------------------------------------------*/
249 
250 std::string StratagusLibPath;		/// Path for data directory
251 
252 /// Name, Version, Copyright
253 const char NameLine[] = NAME " v" VERSION ", " COPYRIGHT;
254 
255 std::string CliMapName;				/// Filename of the map given on the command line
256 std::string MenuRace;
257 
258 bool EnableDebugPrint;				/// if enabled, print the debug messages
259 bool EnableAssert;					/// if enabled, halt on assertion failures
260 bool EnableUnitDebug;				/// if enabled, a unit info dump will be created
261 
262 /*============================================================================
263 ==  MAIN
264 ============================================================================*/
265 
266 /**
267 **  Pre menu setup.
268 */
PreMenuSetup()269 void PreMenuSetup()
270 {
271 	//
272 	//  Initial menus require some gfx.
273 	//
274 	SetDefaultTextColors(FontWhite, FontYellow);
275 
276 	LoadFonts();
277 
278 	InitVideoCursors();
279 
280 	LoadCursors();
281 
282 	InitSettings();
283 
284 	InitUserInterface();
285 	UI.Load();
286 }
287 
288 /**
289 **  Run the guichan main menus loop.
290 **
291 **  @return          0 for success, else exit.
292 */
MenuLoop()293 static int MenuLoop()
294 {
295 	int status;
296 
297 	initGuichan();
298 	InterfaceState = IfaceStateMenu;
299 	//  Clear screen
300 	Video.ClearScreen();
301 	Invalidate();
302 
303 	ButtonUnderCursor = -1;
304 	OldButtonUnderCursor = -1;
305 	CursorState = CursorStatePoint;
306 	GameCursor = UI.Point.Cursor;
307 
308 	// FIXME delete this when switching to full guichan GUI
309 	const std::string filename = LibraryFileName("scripts/guichan.lua");
310 	status = LuaLoadFile(filename);
311 
312 	// We clean up later in Exit
313 	return status;
314 }
315 
316 //----------------------------------------------------------------------------
317 
318 /**
319 **  Print headerline, copyright, ...
320 */
PrintHeader()321 static void PrintHeader()
322 {
323 	std::string CompileOptions =
324 #ifdef DEBUG
325 		"DEBUG "
326 #endif
327 #ifdef USE_ZLIB
328 		"ZLIB "
329 #endif
330 #ifdef USE_BZ2LIB
331 		"BZ2LIB "
332 #endif
333 #ifdef USE_VORBIS
334 		"VORBIS "
335 #endif
336 #ifdef USE_THEORA
337 		"THEORA "
338 #endif
339 #ifdef USE_FLUIDSYNTH
340 	"FLUIDSYNTH "
341 #endif
342 #ifdef USE_MIKMOD
343 		"MIKMOD "
344 #endif
345 #ifdef USE_MNG
346 		"MNG "
347 #endif
348 #ifdef USE_OPENGL
349 		"OPENGL "
350 #endif
351 #ifdef USE_GLES
352 		"GLES "
353 #endif
354 #ifdef USE_WIN32
355 		"WIN32 "
356 #endif
357 #ifdef USE_LINUX
358 		"LINUX "
359 #endif
360 #ifdef USE_BSD
361 		"BSD "
362 #endif
363 #ifdef __MORPHOS__
364 		"MORPHOS "
365 #endif
366 #ifdef USE_BEOS
367 		"BEOS "
368 #endif
369 #ifdef USE_MAC
370 		"MAC "
371 #endif
372 #ifdef USE_X11
373 		"X11 "
374 #endif
375 #ifdef USE_TOUCHSCREEN
376 		"TOUCHSCREEN "
377 #endif
378 		"";
379 
380 	fprintf(stdout,
381 			"%s\n  written by Lutz Sammer, Fabrice Rossi, Vladi Shabanski, Patrice Fortier,\n"
382 			"  Jon Gabrielson, Andreas Arens, Nehal Mistry, Jimmy Salmon, Pali Rohar,\n"
383 			"  cybermind, Andrettin and others.\n"
384 			"\t" HOMEPAGE "\n"
385 			"Compile options %s",
386 			NameLine, CompileOptions.c_str());
387 }
388 
PrintLicense()389 void PrintLicense()
390 {
391 	printf("\n"
392 		   "\n"
393 		   "Stratagus may be copied only under the terms of the GNU General Public License\n"
394 		   "which may be found in the Stratagus source kit.\n"
395 		   "\n"
396 		   "DISCLAIMER:\n"
397 		   "This software is provided as-is.  The author(s) can not be held liable for any\n"
398 		   "damage that might arise from the use of this software.\n"
399 		   "Use it at your own risk.\n"
400 		   "\n");
401 }
402 
403 
404 /**
405 **  Exit the game.
406 **
407 **  @param err  Error code to pass to shell.
408 */
Exit(int err)409 void Exit(int err)
410 {
411 	if (GameRunning) {
412 		StopGame(GameExit);
413 		return;
414 	}
415 
416 	StopMusic();
417 	QuitSound();
418 	NetworkQuitGame();
419 
420 	ExitNetwork1();
421 	CleanModules();
422 	FreeBurningBuildingFrames();
423 	FreeSounds();
424 	FreeGraphics();
425 	FreePlayerColors();
426 	FreeButtonStyles();
427 	FreeAllContainers();
428 	freeGuichan();
429 	DebugPrint("Frames %lu, Slow frames %d = %ld%%\n" _C_
430 			   FrameCounter _C_ SlowFrameCounter _C_
431 			   (SlowFrameCounter * 100) / (FrameCounter ? FrameCounter : 1));
432 	lua_settop(Lua, 0);
433 	lua_close(Lua);
434 	DeInitVideo();
435 #ifdef USE_PHYSFS
436 	if (PHYSFS_isInit()) {
437 		PHYSFS_deinit();
438 	}
439 #endif
440 
441 	fprintf(stdout, "%s", _("Thanks for playing " NAME ".\n"));
442 	exit(err);
443 }
444 
445 /**
446 **  Do a fatal exit.
447 **  Called on out of memory or crash.
448 **
449 **  @param err  Error code to pass to shell.
450 */
ExitFatal(int err)451 void ExitFatal(int err)
452 {
453 #ifdef USE_STACKTRACE
454 	throw stacktrace::stack_runtime_error((const char*)err);
455 #endif
456 	exit(err);
457 }
458 
459 /**
460 **  Display the usage.
461 */
Usage()462 static void Usage()
463 {
464 	PrintHeader();
465 	printf(
466 		"\n\nUsage: %s [OPTIONS] [map.smp|map.smp.gz]\n"
467 		"\t-a\t\tEnables asserts check in engine code (for debugging)\n"
468 		"\t-c file.lua\tConfiguration start file (default stratagus.lua)\n"
469 		"\t-d datapath\tPath to stratagus data (default current directory)\n"
470 		"\t-D depth\tVideo mode depth = pixel per point\n"
471 		"\t-e\t\tStart editor (instead of game)\n"
472 		"\t-E file.lua\tEditor configuration start file (default editor.lua)\n"
473 		"\t-F\t\tFull screen video mode\n"
474 		"\t-G \"options\"\tGame options (passed to game scripts)\n"
475 		"\t-h\t\tHelp shows this page\n"
476 		"\t-i\t\tEnables unit info dumping into log (for debugging)\n"
477 		"\t-I addr\t\tNetwork address to use\n"
478 		"\t-l\t\tDisable command log\n"
479 		"\t-N name\t\tName of the player\n"
480 #if defined(USE_OPENGL) || defined(USE_GLES)
481 		"\t-o\t\tDo not use OpenGL or OpenGL ES 1.1\n"
482 		"\t-O\t\tUse OpenGL or OpenGL ES 1.1\n"
483 #endif
484 		"\t-p\t\tEnables debug messages printing in console\n"
485 		"\t-P port\t\tNetwork port to use\n"
486 		"\t-s sleep\tNumber of frames for the AI to sleep before it starts\n"
487 		"\t-S speed\tSync speed (100 = 30 frames/s)\n"
488 		"\t-u userpath\tPath where stratagus saves preferences, log and savegame\n"
489 		"\t-v mode\t\tVideo mode resolution in format <xres>x<yres>\n"
490 		"\t-W\t\tWindowed video mode\n"
491 #if defined(USE_OPENGL) || defined(USE_GLES)
492 		"\t-x idx\t\tControls fullscreen scaling if your graphics card supports shaders.\n"\
493 		"\t  \t\tPass 1 for nearest-neigubour, 2 for EPX/AdvMame, 3 for HQx, 4 for SAL, 5 for SuperEagle\n"\
494 		"\t  \t\tYou can also use Ctrl+Alt+/ to cycle between these scaling algorithms at runtime.\n"
495 		"\t  \t\tPass -1 to force old-school nearest neighbour scaling without shaders\n"\
496 		"\t-Z\t\tUse OpenGL to scale the screen to the viewport (retro-style). Implies -O.\n"
497 #endif
498 		"map is relative to StratagusLibPath=datapath, use ./map for relative to cwd\n",
499 		Parameters::Instance.applicationName.c_str());
500 }
501 
502 #ifdef REDIRECT_OUTPUT
503 
504 static std::string stdoutFile;
505 static std::string stderrFile;
506 
CleanupOutput()507 static void CleanupOutput()
508 {
509 	fclose(stdout);
510 	fclose(stderr);
511 
512 	struct stat st;
513 	if (stat(stdoutFile.c_str(), &st) == 0 && st.st_size == 0) {
514 		unlink(stdoutFile.c_str());
515 	}
516 	if (stat(stderrFile.c_str(), &st) == 0 && st.st_size == 0) {
517 		unlink(stderrFile.c_str());
518 	}
519 }
520 
RedirectOutput()521 static void RedirectOutput()
522 {
523 	std::string path = Parameters::Instance.GetUserDirectory();
524 
525 	makedir(path.c_str(), 0777);
526 
527 	stdoutFile = path + "\\stdout.txt";
528 	stderrFile = path + "\\stderr.txt";
529 
530 	if (!freopen(stdoutFile.c_str(), "w", stdout)) {
531 		printf("freopen stdout failed");
532 	}
533 	if (!freopen(stderrFile.c_str(), "w", stderr)) {
534 		printf("freopen stderr failed");
535 	}
536 	atexit(CleanupOutput);
537 }
538 #endif
539 
ParseCommandLine(int argc,char ** argv,Parameters & parameters)540 void ParseCommandLine(int argc, char **argv, Parameters &parameters)
541 {
542 	for (;;) {
543 		switch (getopt(argc, argv, "ac:d:D:eE:FG:hiI:lN:oOP:ps:S:u:v:Wx:Z?-")) {
544 			case 'a':
545 				EnableAssert = true;
546 				continue;
547 			case 'c':
548 				parameters.luaStartFilename = optarg;
549 				if (strlen(optarg) > 4 &&
550 					!(strstr(optarg, ".lua") == optarg + strlen(optarg) - 4)) {
551 						parameters.luaStartFilename += ".lua";
552 				}
553 				continue;
554 			case 'd': {
555 				StratagusLibPath = optarg;
556 				size_t index;
557 				while ((index = StratagusLibPath.find('\\')) != std::string::npos) {
558 					StratagusLibPath[index] = '/';
559 				}
560 				continue;
561 			}
562 			case 'D':
563 				Video.Depth = atoi(optarg);
564 				continue;
565 			case 'e':
566 				Editor.Running = EditorCommandLine;
567 				continue;
568 			case 'E':
569 				parameters.luaEditorStartFilename = optarg;
570 				continue;
571 			case 'F':
572 				VideoForceFullScreen = 1;
573 				Video.FullScreen = 1;
574 				continue;
575 			case 'G':
576 				parameters.luaScriptArguments = optarg;
577 				continue;
578 			case 'i':
579 				EnableUnitDebug = true;
580 				continue;
581 			case 'I':
582 				CNetworkParameter::Instance.localHost = optarg;
583 				continue;
584 			case 'l':
585 				CommandLogDisabled = true;
586 				continue;
587 			case 'N':
588 				parameters.LocalPlayerName = optarg;
589 				continue;
590 #if defined(USE_OPENGL) || defined(USE_GLES)
591 			case 'o':
592 				ForceUseOpenGL = 1;
593 				UseOpenGL = 0;
594 				if (ZoomNoResize) {
595 					fprintf(stderr, "Error: -Z only works with OpenGL enabled\n");
596 					Usage();
597 					ExitFatal(-1);
598 				}
599 				continue;
600 			case 'O':
601 				ForceUseOpenGL = 1;
602 				UseOpenGL = 1;
603 				continue;
604 #endif
605 			case 'P':
606 				CNetworkParameter::Instance.localPort = atoi(optarg);
607 				continue;
608 			case 'p':
609 				EnableDebugPrint = true;
610 				continue;
611 			case 's':
612 				AiSleepCycles = atoi(optarg);
613 				continue;
614 			case 'S':
615 				VideoSyncSpeed = atoi(optarg);
616 				continue;
617 			case 'u':
618 				Parameters::Instance.SetUserDirectory(optarg);
619 				continue;
620 			case 'v': {
621 				char *sep = strchr(optarg, 'x');
622 				if (!sep || !*(sep + 1)) {
623 					fprintf(stderr, "%s: incorrect format of video mode resolution -- '%s'\n", argv[0], optarg);
624 					Usage();
625 					ExitFatal(-1);
626 				}
627 				Video.Height = atoi(sep + 1);
628 				*sep = 0;
629 				Video.Width = atoi(optarg);
630 				if (!Video.Height || !Video.Width) {
631 					fprintf(stderr, "%s: incorrect format of video mode resolution -- '%sx%s'\n", argv[0], optarg, sep + 1);
632 					Usage();
633 					ExitFatal(-1);
634 				}
635 #if defined(USE_OPENGL) || defined(USE_GLES)
636 				if (ZoomNoResize) {
637 					Video.ViewportHeight = Video.Height;
638 					Video.ViewportWidth = Video.Width;
639 					Video.Height = 0;
640 					Video.Width = 0;
641 				}
642 #endif
643 				continue;
644 			}
645 			case 'W':
646 				VideoForceFullScreen = 1;
647 				Video.FullScreen = 0;
648 				continue;
649 #if defined(USE_OPENGL) || defined(USE_GLES)
650 			case 'x':
651 				ShaderIndex = atoi(optarg) % MAX_SHADERS;
652 				if (atoi(optarg) == -1) {
653 					GLShaderPipelineSupported = false;
654 				//Wyrmgus start
655 				} else {
656 					GLShaderPipelineSupported = true;
657 				//Wyrmgus end
658 				}
659 				continue;
660 			case 'Z':
661 				ForceUseOpenGL = 1;
662 				UseOpenGL = 1;
663 				ZoomNoResize = 1;
664 				Video.ViewportHeight = Video.Height;
665 				Video.ViewportWidth = Video.Width;
666 				Video.Height = 0;
667 				Video.Width = 0;
668 				continue;
669 #endif
670 			case -1:
671 				break;
672 			case '?':
673 			case 'h':
674 			default:
675 				Usage();
676 				ExitFatal(-1);
677 		}
678 		break;
679 	}
680 
681 	if (argc - optind > 1) {
682 		fprintf(stderr, "too many map files. if you meant to pass game arguments, these go after '--'\n");
683 		Usage();
684 		ExitFatal(-1);
685 	}
686 
687 	if (argc - optind) {
688 		size_t index;
689 		CliMapName = argv[optind];
690 		while ((index = CliMapName.find('\\')) != std::string::npos) {
691 			CliMapName[index] = '/';
692 		}
693 	}
694 }
695 
696 #ifdef USE_WIN32
CreateDumpFile(EXCEPTION_POINTERS * ExceptionInfo)697 static LONG WINAPI CreateDumpFile(EXCEPTION_POINTERS *ExceptionInfo)
698 {
699 	HANDLE hFile = CreateFile("crash.dmp", GENERIC_READ | GENERIC_WRITE,    FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
700 		NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
701 	MINIDUMP_EXCEPTION_INFORMATION mei;
702 	mei.ThreadId = GetCurrentThreadId();
703 	mei.ClientPointers = TRUE;
704 	mei.ExceptionPointers = ExceptionInfo;
705 	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mei, NULL, NULL);
706 	fprintf(stderr, "" NAME " crashed!\n");
707 	fprintf(stderr, "A mini dump file \"crash.dmp\" has been created in the Stratagus folder.\n");
708 	fprintf(stderr, "Please send this call stack to our bug tracker: " HOMEPAGE "/issues\n");
709 	fprintf(stderr, "and tell us what caused this bug to occur.\n");
710 	return EXCEPTION_EXECUTE_HANDLER;
711 }
712 #endif
713 
714 /**
715 **  The main program: initialise, parse options and arguments.
716 **
717 **  @param argc  Number of arguments.
718 **  @param argv  Vector of arguments.
719 */
stratagusMain(int argc,char ** argv)720 int stratagusMain(int argc, char **argv)
721 {
722 #ifdef USE_BEOS
723 	//  Parse arguments for BeOS
724 	beos_init(argc, argv);
725 #endif
726 #ifdef USE_WIN32
727 	SetUnhandledExceptionFilter(CreateDumpFile);
728 #endif
729 #if defined(USE_WIN32) && ! defined(REDIRECT_OUTPUT)
730 	SetupConsole();
731 #endif
732 	//  Setup some defaults.
733 #ifndef MAC_BUNDLE
734 	StratagusLibPath = ".";
735 #else
736 	freopen("/tmp/stdout.txt", "w", stdout);
737 	freopen("/tmp/stderr.txt", "w", stderr);
738 	// Look for the specified data set inside the application bundle
739 	// This should be a subdir of the Resources directory
740 	CFURLRef pluginRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
741 												 CFSTR(MAC_BUNDLE_DATADIR), nullptr, nullptr);
742 	CFStringRef macPath = CFURLCopyFileSystemPath(pluginRef,  kCFURLPOSIXPathStyle);
743 	const char *pathPtr = CFStringGetCStringPtr(macPath, CFStringGetSystemEncoding());
744 	Assert(pathPtr);
745 	StratagusLibPath = pathPtr;
746 #endif
747 
748 #ifdef USE_PHYSFS
749 	if (PHYSFS_init(argv[0])) {
750 		PHYSFS_mount(PHYSFS_DATAFILE, "/", 0);
751 	}
752 #endif
753 
754 #ifdef USE_STACKTRACE
755 	try {
756 #endif
757 	Parameters &parameters = Parameters::Instance;
758 	parameters.SetDefaultValues();
759 	parameters.SetLocalPlayerNameFromEnv();
760 
761 #ifdef REDIRECT_OUTPUT
762 	RedirectOutput();
763 #endif
764 
765 	if (argc > 0) {
766 		parameters.applicationName = argv[0];
767 	}
768 
769 	// FIXME: Parse options before or after scripts?
770 	ParseCommandLine(argc, argv, parameters);
771 	// Init the random number generator.
772 	InitSyncRand();
773 
774 	makedir(parameters.GetUserDirectory().c_str(), 0777);
775 
776 	// Init Lua and register lua functions!
777 	InitLua();
778 	LuaRegisterModules();
779 
780 	// Initialise AI module
781 	InitAiModule();
782 
783 	LoadCcl(parameters.luaStartFilename, parameters.luaScriptArguments);
784 
785 	PrintHeader();
786 	PrintLicense();
787 
788 	// Setup video display
789 	InitVideo();
790 
791 	// Setup sound card
792 	if (!InitSound()) {
793 		InitMusic();
794 	}
795 
796 #ifndef DEBUG			// For debug it's better not to have:
797 	srand(time(nullptr));	// Random counter = random each start
798 #endif
799 
800 	//  Show title screens.
801 	SetDefaultTextColors(FontYellow, FontWhite);
802 	LoadFonts();
803 	SetClipping(0, 0, Video.Width - 1, Video.Height - 1);
804 	Video.ClearScreen();
805 	ShowTitleScreens();
806 
807 	// Init player data
808 	ThisPlayer = nullptr;
809 	//Don't clear the Players structure as it would erase the allowed units.
810 	// memset(Players, 0, sizeof(Players));
811 	NumPlayers = 0;
812 
813 	UnitManager.Init();	// Units memory management
814 	PreMenuSetup();		// Load everything needed for menus
815 
816 	MenuLoop();
817 
818 	Exit(0);
819 #ifdef USE_STACKTRACE
820 	} catch (const std::exception &e) {
821 		fprintf(stderr, "" NAME " crashed!\n");
822 		fprintf(stderr, "Please send this call stack to our bug tracker: " HOMEPAGE "/issues\n");
823 		fprintf(stderr, "and tell us what caused this bug to occur.\n");
824 		fprintf(stderr, " === exception state traceback === \n");
825 		fprintf(stderr, "%s", e.what());
826 		exit(1);
827 	}
828 #endif
829 	return 0;
830 }
831 
832 //Wyrmgus start
GetReverseDirection(int direction)833 int GetReverseDirection(int direction)
834 {
835 	if (direction == North) {
836 		return South;
837 	} else if (direction == Northeast) {
838 		return Southwest;
839 	} else if (direction == East) {
840 		return West;
841 	} else if (direction == Southeast) {
842 		return Northwest;
843 	} else if (direction == South) {
844 		return North;
845 	} else if (direction == Southwest) {
846 		return Northeast;
847 	} else if (direction == West) {
848 		return East;
849 	} else if (direction == Northwest) {
850 		return Southeast;
851 	}
852 	return -1;
853 }
854 
GetDirectionNameById(int direction)855 std::string GetDirectionNameById(int direction)
856 {
857 	if (direction == North) {
858 		return "north";
859 	} else if (direction == Northeast) {
860 		return "northeast";
861 	} else if (direction == East) {
862 		return "east";
863 	} else if (direction == Southeast) {
864 		return "southeast";
865 	} else if (direction == South) {
866 		return "south";
867 	} else if (direction == Southwest) {
868 		return "southwest";
869 	} else if (direction == West) {
870 		return "west";
871 	} else if (direction == Northwest) {
872 		return "northwest";
873 	}
874 	return "";
875 }
876 
GetDirectionIdByName(const std::string & direction)877 int GetDirectionIdByName(const std::string &direction)
878 {
879 	if (direction == "north") {
880 		return North;
881 	} else if (direction == "northeast") {
882 		return Northeast;
883 	} else if (direction == "east") {
884 		return East;
885 	} else if (direction == "southeast") {
886 		return Southeast;
887 	} else if (direction == "south") {
888 		return South;
889 	} else if (direction == "southwest") {
890 		return Southwest;
891 	} else if (direction == "west") {
892 		return West;
893 	} else if (direction == "northwest") {
894 		return Northwest;
895 	} else {
896 		return -1;
897 	}
898 }
899 
GetDirectionFromOffset(int x,int y)900 int GetDirectionFromOffset(int x, int y)
901 {
902 	if (x < 0 && y == 0) {
903 		return West;
904 	} else if (x > 0 && y == 0) {
905 		return East;
906 	} else if (y < 0 && x == 0) {
907 		return North;
908 	} else if (y > 0 && x == 0) {
909 		return South;
910 	} else if (x < 0 && y < 0) {
911 		return Northwest;
912 	} else if (x > 0 && y < 0) {
913 		return Northeast;
914 	} else if (x < 0 && y > 0) {
915 		return Southwest;
916 	} else if (x > 0 && y > 0) {
917 		return Southeast;
918 	}
919 
920 	return -1;
921 }
922 
GetDirectionOffset(int direction)923 Vec2i GetDirectionOffset(int direction)
924 {
925 	Vec2i offset(0, 0);
926 
927 	if (direction == North || direction == Northwest || direction == Northeast) {
928 		offset.y = -1;
929 	} else if (direction == South || direction == Southwest || direction == Southeast) {
930 		offset.y = 1;
931 	}
932 	if (direction == West || direction == Northwest || direction == Southwest) {
933 		offset.x = -1;
934 	} else if (direction == East || direction == Northeast || direction == Southeast) {
935 		offset.x = 1;
936 	}
937 
938 	return offset;
939 }
940 //Wyrmgus end
941 
942 //@}
943