1
0
forked from 0ad/0ad

Add basic help page into the main menu.

Add buttons to open the web site and IRC.
Tentatively allow Atlas to be launched from the menu.
Add some shutdown functions to support relaunching into Atlas without
having to restart the whole process.

This was SVN commit r7714.
This commit is contained in:
Ykkrosh 2010-07-07 21:47:31 +00:00
parent db8dda7bda
commit 4b06ebd52d
20 changed files with 291 additions and 17 deletions

View File

@ -0,0 +1,39 @@
[font="serif-bold-18"]0 A.D. in-game manual
[font="serif-14"]
Thank you for installing 0 A.D.! This page will give a brief overview of the features available in this incomplete, under-development, pre-alpha version of the game.
[font="serif-bold-16"]Graphics settings
[font="serif-14"]You can switch between fullscreen and windowed mode by pressing Alt+Enter. In windowed mode, you can resize the window. If the game runs too slowly, you can change some settings in the configuration file: look for binaries/data/config/default.cfg in the location where the game is installed, which gives instructions for editing, and try disabling the "fancywater" and "shadows" options.
[font="serif-bold-16"]Modes
[font="serif-14"]The main menu gives access to two game modes:
• [font="serif-bold-14"]Single-player[font="serif-14"] — the game does not have any AI opponents yet, but you can use this to test the game's mechanics.
• [font="serif-bold-14"]Multiplayer[font="serif-14"] — play against human opponents over the internet.
To set up a multiplayer game, one player must select the "Host game" option. The game uses UDP port 20595, so the host must configure their NAT/firewall/etc to allow this. Other players can then select "Join game" and enter the host's IP address.
[font="serif-bold-16"]Game setup
[font="serif-14"]In a multiplayer game, only the host can alter the game setup options.
First, select a map to play on. The "techdemo" maps are designed for testing particular gameplay features and are probably not generally useful.
Next, you can use the drop-down lists in the player list to select who controls which player in the map. This always shows 8 players – anyone who is assigned to a player that doesn't exist in the map, or is not assigned to any player at all, will probably not have a fun time.
When you are ready to start, click the "Start game" button.
[font="serif-bold-16"]Playing the game
[font="serif-14"]The controls and gameplay should be familiar to players of traditional RTS games. There are currently a lot of missing features and poorly-balanced stats – you will probably have to wait until a beta release for it to work well.
Basic controls:
• Left-click to select units.
• Left-click-and-drag to select groups of units.
• Right-click to order units to the target.
• Arrow keys or WASD keys to move the camera.
• Ctrl + arrow keys to rotate the camera.
• F2 to save a screenshot (into %appdata%\0ad\screenshots\ on Windows, and ~/.local/share/0ad/screenshots/ on Unix).
• Ctrl+Alt+F2 to save a very high-resolution screenshot.
• F11 to view the built-in performance profiler.
Use the "X" button in the top-right corner of this window to close it.

View File

@ -0,0 +1,4 @@
function init()
{
getGUIObjectByName("mainText").caption = readFile("gui/manual/intro.txt");
}

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<objects>
<script file="gui/manual/manual.js"/>
<!-- Add a translucent black background to fade out the menu page -->
<object type="image" z="0" sprite="bkTranslucent"/>
<object type="image" style="wheatWindow" size="100 100 100%-100 100%-100">
<object type="button" style="wheatExit" tooltip_style="snToolTip">
<action on="Press"><![CDATA[
Engine.PopGuiPage();
]]></action>
</object>
<object type="image" sprite="wheatIndentFillVeryLight">
<object name="mainText" type="text" style="textPanel"/>
</object>
</object>
</objects>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<styles>
<style name="textPanel"
buffer_zone="8"
font="serif-13"
scrollbar="true"
scrollbar_style="wheatScrollBar"
textcolor="black"
textcolor_selected="white"
text_align="left"
text_valign="center"
/>
</styles>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<page>
<include>common/setup.xml</include>
<include>common/styles.xml</include>
<include>common/sprite1.xml</include>
<include>manual/styles.xml</include>
<include>manual/manual.xml</include>
</page>

View File

@ -77,7 +77,7 @@
type="text" type="text"
sprite="bkTranslucent" sprite="bkTranslucent"
textcolor="255 255 0" textcolor="255 255 0"
size="4 4 230 300" size="4 4 230 200"
>[font="serif-bold-16"]WARNING[/font] >[font="serif-bold-16"]WARNING[/font]
This is an under-development unpolished snapshot. Some major components have been rewritten recently, and many gameplay features are still missing. This is an under-development unpolished snapshot. Some major components have been rewritten recently, and many gameplay features are still missing.
@ -100,6 +100,33 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
>tooltipText >tooltipText
</object> </object>
<!--
==========================================
- MAIN MENU - RANDOM BUTTONS
==========================================
-->
<object type="button" style="wheatButton" size="8 230 158 270">
How to play
<action on="Press"><![CDATA[
Engine.PushGuiPage("page_manual.xml");
]]></action>
</object>
<object type="button" style="wheatButton" size="8 275 158 315">
Visit our web site
<action on="Press"><![CDATA[
Engine.OpenURL("http://wildfiregames.com/0ad/");
]]></action>
</object>
<object type="button" style="wheatButton" size="8 320 158 360">
Chat on IRC
<action on="Press"><![CDATA[
Engine.OpenURL("http://webchat.quakenet.org/?channels=0ad");
]]></action>
</object>
<!-- <!--
========================================== ==========================================
- MAIN MENU - PARCHMENT BUTTONS - MAIN MENU - PARCHMENT BUTTONS
@ -157,20 +184,19 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
> >
<action on="Load"><![CDATA[ <action on="Load"><![CDATA[
// Disable the Editor button if the Atlas DLL is not active. // Disable the Editor button if the Atlas DLL is not active.
// if (ATLAS_IsAvailable() == true) if (Engine.AtlasIsAvailable())
// { {
// this.enabled = true; this.enabled = true;
// this.tooltip = "Open 'Atlas', 0 A.D.'s Scenario Editor."; this.tooltip = "Open the Atlas Scenario Editor in a new window. You can run this more reliably by starting the game with the command-line argument \"-editor\".";
// } }
// else else
// { {
this.enabled = false; this.enabled = false;
this.tooltip = "The Scenario Editor is not currently available."; this.tooltip = "The Scenario Editor is not available.";
// } }
]]></action> ]]></action>
<action on="Press"><![CDATA[ <action on="Press"><![CDATA[
// Open Atlas Editor. Engine.RestartInAtlas();
// ATLAS_Run();
]]></action> ]]></action>
</object> </object>

View File

@ -30,6 +30,7 @@
#include "ps/CLogger.h" #include "ps/CLogger.h"
#include "ps/Game.h" #include "ps/Game.h"
#include "ps/Overlay.h" #include "ps/Overlay.h"
#include "ps/GameSetup/Atlas.h"
#include "ps/GameSetup/Config.h" #include "ps/GameSetup/Config.h"
#include "simulation2/Simulation2.h" #include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpCommandQueue.h" #include "simulation2/components/ICmpCommandQueue.h"
@ -46,6 +47,8 @@
* scripts should call "Engine.FunctionName(...)" etc. * scripts should call "Engine.FunctionName(...)" etc.
*/ */
extern void restart_mainloop_in_atlas(); // from main.cpp
namespace { namespace {
CScriptVal GetActiveGui(void* UNUSED(cbdata)) CScriptVal GetActiveGui(void* UNUSED(cbdata))
@ -273,6 +276,20 @@ void SendNetworkChat(void* UNUSED(cbdata), std::wstring message)
g_NetClient->SendChatMessage(message); g_NetClient->SendChatMessage(message);
} }
void OpenURL(void* UNUSED(cbdata), std::string url)
{
sys_open_url(url);
}
void RestartInAtlas(void* UNUSED(cbdata))
{
restart_mainloop_in_atlas();
}
bool AtlasIsAvailable(void* UNUSED(cbdata))
{
return ATLAS_IsAvailable();
}
} // namespace } // namespace
@ -309,4 +326,7 @@ void GuiScriptingInit(ScriptInterface& scriptInterface)
scriptInterface.RegisterFunction<std::wstring, std::wstring, &SetCursor>("SetCursor"); scriptInterface.RegisterFunction<std::wstring, std::wstring, &SetCursor>("SetCursor");
scriptInterface.RegisterFunction<int, &GetPlayerID>("GetPlayerID"); scriptInterface.RegisterFunction<int, &GetPlayerID>("GetPlayerID");
scriptInterface.RegisterFunction<std::wstring, &GetDefaultPlayerName>("GetDefaultPlayerName"); scriptInterface.RegisterFunction<std::wstring, &GetDefaultPlayerName>("GetDefaultPlayerName");
scriptInterface.RegisterFunction<void, std::string, &OpenURL>("OpenURL");
scriptInterface.RegisterFunction<void, &RestartInAtlas>("RestartInAtlas");
scriptInterface.RegisterFunction<bool, &AtlasIsAvailable>("AtlasIsAvailable");
} }

View File

@ -47,6 +47,10 @@ void in_add_handler(InHandler handler)
handler_stack[handler_stack_top++] = handler; handler_stack[handler_stack_top++] = handler;
} }
void in_reset_handlers()
{
handler_stack_top = 0;
}
// send ev to each handler until one returns IN_HANDLED // send ev to each handler until one returns IN_HANDLED
static void dispatch_ev(const SDL_Event_* ev) static void dispatch_ev(const SDL_Event_* ev)

View File

@ -50,6 +50,9 @@ typedef InReaction (*InHandler)(const SDL_Event_*);
// events are passed to other handlers if handler returns IN_PASS. // events are passed to other handlers if handler returns IN_PASS.
extern void in_add_handler(InHandler handler); extern void in_add_handler(InHandler handler);
// remove all registered input handlers
extern void in_reset_handlers();
// send event to each handler (newest first) until one returns true // send event to each handler (newest first) until one returns true
extern void in_dispatch_event(const SDL_Event_* event); extern void in_dispatch_event(const SDL_Event_* event);

View File

@ -65,4 +65,10 @@ extern LibError sys_cursor_set(sys_cursor cursor);
**/ **/
extern LibError sys_cursor_free(sys_cursor cursor); extern LibError sys_cursor_free(sys_cursor cursor);
/**
* reset any cached cursor data.
* on some systems, this is needed when resetting the SDL video subsystem.
**/
extern LibError sys_cursor_reset();
#endif // #ifndef INCLUDED_SYSDEP_CURSOR #endif // #ifndef INCLUDED_SYSDEP_CURSOR

View File

@ -148,7 +148,8 @@ LibError sys_cursor_set(sys_cursor cursor)
{ {
// Gaah, SDL doesn't have a good API for setting the default cursor // Gaah, SDL doesn't have a good API for setting the default cursor
// SetCursor(NULL) just /repaints/ the cursor (well, obviously! or...) // SetCursor(NULL) just /repaints/ the cursor (well, obviously! or...)
ONCE(defaultCursor = SDL_GetCursor()); if(!defaultCursor)
defaultCursor = SDL_GetCursor();
// restore default cursor. // restore default cursor.
if(!cursor) if(!cursor)
@ -177,6 +178,13 @@ LibError sys_cursor_free(sys_cursor cursor)
return INFO::OK; return INFO::OK;
} }
LibError sys_cursor_reset()
{
defaultCursor = NULL;
return INFO::OK;
}
// note: just use the sector size: Linux aio doesn't really care about // note: just use the sector size: Linux aio doesn't really care about
// the alignment of buffers/lengths/offsets, so we'll just pick a // the alignment of buffers/lengths/offsets, so we'll just pick a
// sane value and not bother scanning all drives. // sane value and not bother scanning all drives.
@ -224,3 +232,33 @@ LibError sys_generate_random_bytes(u8* buf, size_t count)
return INFO::OK; return INFO::OK;
} }
LibError sys_open_url(const std::string& url)
{
pid_t pid = fork();
if (pid < 0)
{
debug_warn(L"Fork failed");
return ERR::FAIL;
}
else if (pid == 0)
{
// we are the child
execlp("xdg-open", "xdg-open", url.c_str(), (const char*)NULL);
debug_printf(L"Failed to run xdg-open command\n");
// We can't call exit() because that'll try to free resources which were the parent's,
// so just abort here
abort();
}
else
{
// we are the parent
// TODO: maybe we should wait for the child and make sure it succeeded
return INFO::OK;
}
}

View File

@ -118,3 +118,8 @@ LibError sys_cursor_free(sys_cursor cursor)
BOOL ok = DestroyIcon(HICON_from_cursor(cursor)); BOOL ok = DestroyIcon(HICON_from_cursor(cursor));
return LibError_from_win32(ok); return LibError_from_win32(ok);
} }
LibError sys_cursor_reset()
{
return INFO::OK;
}

View File

@ -413,6 +413,15 @@ LibError sys_pick_directory(fs::wpath& path)
return LibError_from_GLE(); return LibError_from_GLE();
} }
LibError sys_open_url(const std::string& url)
{
LONG r = ShellExecuteA(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL);
if (r > 32)
return INFO::OK;
WARN_RETURN(ERR::FAIL);
}
LibError sys_generate_random_bytes(u8* buf, size_t count) LibError sys_generate_random_bytes(u8* buf, size_t count)
{ {
HCRYPTPROV hCryptProv; HCRYPTPROV hCryptProv;

View File

@ -122,6 +122,11 @@ extern std::wstring sys_get_user_name();
**/ **/
extern LibError sys_pick_directory(fs::wpath& path); extern LibError sys_pick_directory(fs::wpath& path);
/**
* open the user's default web browser to the given URL.
**/
extern LibError sys_open_url(const std::string& url);
/** /**
* return the largest sector size [bytes] of any storage medium * return the largest sector size [bytes] of any storage medium
* (HD, optical, etc.) in the system. * (HD, optical, etc.) in the system.

View File

@ -261,6 +261,11 @@ extern void tex_set_global_orientation(int orientation);
**/ **/
extern void tex_codec_register_all(); extern void tex_codec_register_all();
/**
* remove all codecs that have been registered.
**/
extern void tex_codec_unregister_all();
/** /**
* decode an in-memory texture file into texture object. * decode an in-memory texture file into texture object.
* *

View File

@ -53,6 +53,11 @@ int tex_codec_register(TexCodecVTbl* c)
return 0; // (assigned to dummy variable) return 0; // (assigned to dummy variable)
} }
// remove all codecs that have been registered.
void tex_codec_unregister_all()
{
codecs = NULL;
}
// find codec that recognizes the desired output file extension, // find codec that recognizes the desired output file extension,
// or return ERR::TEX_UNKNOWN_FORMAT if unknown. // or return ERR::TEX_UNKNOWN_FORMAT if unknown.

View File

@ -389,6 +389,15 @@ void kill_mainloop()
} }
static bool restart_in_atlas = false;
// called by game code to indicate main() should restart in Atlas mode
// instead of terminating
void restart_mainloop_in_atlas()
{
quit = true;
restart_in_atlas = true;
}
// moved into a helper function to ensure args is destroyed before // moved into a helper function to ensure args is destroyed before
// exit(), which may result in a memory leak. // exit(), which may result in a memory leak.
static void RunGameOrAtlas(int argc, const char* argv[]) static void RunGameOrAtlas(int argc, const char* argv[])
@ -401,7 +410,7 @@ static void RunGameOrAtlas(int argc, const char* argv[])
CXeromyces::Startup(); CXeromyces::Startup();
// run Atlas (if requested via args) // run Atlas (if requested via args)
bool ran_atlas = ATLAS_RunIfOnCmdLine(args); bool ran_atlas = ATLAS_RunIfOnCmdLine(args, false);
// Atlas handles the whole init/shutdown/etc sequence by itself; // Atlas handles the whole init/shutdown/etc sequence by itself;
// when we get here, it has exited and we're done. // when we get here, it has exited and we're done.
if(ran_atlas) if(ran_atlas)
@ -419,6 +428,12 @@ static void RunGameOrAtlas(int argc, const char* argv[])
ScriptingHost::FinalShutdown(); // this can't go in Shutdown() because that could be called multiple times per process, so stick it here instead ScriptingHost::FinalShutdown(); // this can't go in Shutdown() because that could be called multiple times per process, so stick it here instead
MainControllerShutdown(); MainControllerShutdown();
if (restart_in_atlas)
{
ATLAS_RunIfOnCmdLine(args, true);
return;
}
// Shut down libxml2 (done here to match the Startup call) // Shut down libxml2 (done here to match the Startup call)
CXeromyces::Terminate(); CXeromyces::Terminate();
} }

View File

@ -58,6 +58,10 @@ static void ATLAS_Run(const CmdLineArgs& args, int flags = 0)
} }
} }
bool ATLAS_IsAvailable()
{
return atlas_dll.LoadDLL();
}
// starts the Atlas UI if an "-editor" switch is found on the command line. // starts the Atlas UI if an "-editor" switch is found on the command line.
// this is the alternative to starting the main menu and clicking on // this is the alternative to starting the main menu and clicking on
@ -66,9 +70,9 @@ static void ATLAS_Run(const CmdLineArgs& args, int flags = 0)
// notes: // notes:
// - GUI init still runs, but some GUI setup will be skipped since // - GUI init still runs, but some GUI setup will be skipped since
// ATLAS_IsRunning() will return true. // ATLAS_IsRunning() will return true.
bool ATLAS_RunIfOnCmdLine(const CmdLineArgs& args) bool ATLAS_RunIfOnCmdLine(const CmdLineArgs& args, bool force)
{ {
if (args.Has("editor")) if (force || args.Has("editor"))
{ {
ATLAS_Run(args, ATLAS_NO_GUI); ATLAS_Run(args, ATLAS_NO_GUI);
return true; return true;

View File

@ -23,10 +23,13 @@ class CmdLineArgs;
// free reference to Atlas UI SO (avoids resource leak report) // free reference to Atlas UI SO (avoids resource leak report)
extern void ATLAS_Shutdown(); extern void ATLAS_Shutdown();
// returns whether the Atlas UI SO is available for loading
extern bool ATLAS_IsAvailable();
// starts the Atlas UI if an "-editor" switch is found on the command line. // starts the Atlas UI if an "-editor" switch is found on the command line.
// this is the alternative to starting the main menu and clicking on // this is the alternative to starting the main menu and clicking on
// the editor button; it is much faster because it's called during early // the editor button; it is much faster because it's called during early
// init and therefore skips GUI setup. // init and therefore skips GUI setup.
extern bool ATLAS_RunIfOnCmdLine(const CmdLineArgs& args); extern bool ATLAS_RunIfOnCmdLine(const CmdLineArgs& args, bool force);
#endif // INCLUDED_ATLAS #endif // INCLUDED_ATLAS

View File

@ -27,6 +27,7 @@
#include "lib/res/h_mgr.h" #include "lib/res/h_mgr.h"
#include "lib/res/graphics/cursor.h" #include "lib/res/graphics/cursor.h"
#include "lib/res/sound/snd_mgr.h" #include "lib/res/sound/snd_mgr.h"
#include "lib/sysdep/cursor.h"
#include "lib/sysdep/cpu.h" #include "lib/sysdep/cpu.h"
#include "lib/sysdep/gfx.h" #include "lib/sysdep/gfx.h"
#include "lib/tex/tex.h" #include "lib/tex/tex.h"
@ -97,6 +98,13 @@
#include "ps/GameSetup/Config.h" #include "ps/GameSetup/Config.h"
#include "ps/GameSetup/CmdLineArgs.h" #include "ps/GameSetup/CmdLineArgs.h"
#if !(OS_WIN || OS_MACOSX) // assume all other platforms use X11 for wxWidgets
#define MUST_INIT_X11 1
#include <X11/Xlib.h>
#else
#define MUST_INIT_X11 0
#endif
#include <iostream> #include <iostream>
ERROR_GROUP(System); ERROR_GROUP(System);
@ -555,6 +563,12 @@ static void InitSDL()
SDL_EnableUNICODE(1); SDL_EnableUNICODE(1);
} }
static void ShutdownSDL()
{
SDL_QuitSubSystem(SDL_INIT_VIDEO|SDL_INIT_TIMER);
sys_cursor_reset();
}
void EndGame() void EndGame()
{ {
@ -572,6 +586,8 @@ void Shutdown(int UNUSED(flags))
ShutdownPs(); // Must delete g_GUI before g_ScriptingHost ShutdownPs(); // Must delete g_GUI before g_ScriptingHost
in_reset_handlers();
// destroy actor related stuff // destroy actor related stuff
TIMER_BEGIN(L"shutdown actor stuff"); TIMER_BEGIN(L"shutdown actor stuff");
delete &g_MaterialManager; delete &g_MaterialManager;
@ -588,6 +604,12 @@ void Shutdown(int UNUSED(flags))
g_VBMan.Shutdown(); g_VBMan.Shutdown();
TIMER_END(L"shutdown Renderer"); TIMER_END(L"shutdown Renderer");
tex_codec_unregister_all();
TIMER_BEGIN(L"shutdown SDL");
ShutdownSDL();
TIMER_END(L"shutdown SDL");
TIMER_BEGIN(L"shutdown ScriptingHost"); TIMER_BEGIN(L"shutdown ScriptingHost");
delete &g_ScriptingHost; delete &g_ScriptingHost;
TIMER_END(L"shutdown ScriptingHost"); TIMER_END(L"shutdown ScriptingHost");
@ -643,6 +665,17 @@ void EarlyInit()
timer_LatchStartTime(); timer_LatchStartTime();
// Because we do GL calls from a secondary thread, Xlib needs to
// be told to support multiple threads safely.
// This is needed for Atlas, but we have to call it before any other
// Xlib functions (e.g. the ones used when drawing the main menu
// before launching Atlas)
#if MUST_INIT_X11
int status = XInitThreads();
if (status == 0)
debug_printf(L"Error enabling thread-safety via XInitThreads\n");
#endif
// Initialise the low-quality rand function // Initialise the low-quality rand function
srand(time(NULL)); // NOTE: this rand should *not* be used for simulation! srand(time(NULL)); // NOTE: this rand should *not* be used for simulation!
} }