merge new_graphics back into default, it should work OK, and there's a lot of additional functionality already
--- a/src/Application.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Application.cc Thu Jan 22 03:02:43 2009 +0200
@@ -1,5 +1,14 @@
#include "Application.hh"
+#include "Config.hh"
+
+#if GRAPHICS_ENABLED
+ // for dump_display_modes
+ #include "Graphics/Display.hh"
+
+ // for CL_SetupGL
+ #include <ClanLib/gl.h>
+#endif
#include <stdexcept>
#include <sstream>
@@ -19,6 +28,7 @@
ARG_VERSION = 0xff02,
ARG_TERRAIN_SEED = 0xff03,
ARG_TERRAIN_SIZE = 0xff04,
+ ARG_LOG_LEVEL = 0xff05,
};
@@ -36,42 +46,65 @@
* Set the arg_* members
*/
bool Main::parse_args (int argc, char **argv) {
- // set up the options
- args.add_option(ARG_HELP, "help", "",
- "display argument help and exit");
-
- args.add_option(ARG_PORT, "port", "PORT",
- "set network port used");
-
- args.add_option(ARG_SERVER, "server", "",
- "act as a network server");
- args.add_option(ARG_CLIENT, "client", "SERVERHOST",
- "act as a network client");
-
- args.add_option(ARG_GRAPHICS, "graphics", "",
- "run graphics/local input. Implied with --connect");
+ // set up the options
+ args.add_usage("[OPTIONS]");
+ args.set_help_indent(30);
+
+ if (NETWORK_ENABLED) {
+ args.add_group("Network");
- args.add_option(ARG_FULLSCREEN, "fullscreen", "",
- "run graphics in fullscreen mode");
+ args.add_option(ARG_PORT, "port", "PORT",
+ "set network port used");
- args.add_option(ARG_RESOLUTION, "resolution", "WIDTHxHEIGHT",
- "set graphics resolution");
-
- args.add_option(ARG_LIST_MODES, "list-modes", "",
- "output a list of available display modes and exit");
+ args.add_option(ARG_SERVER, "server", "",
+ "act as a network server");
+
+ // require graphics for network-client
+ if (GRAPHICS_ENABLED)
+ args.add_option(ARG_CLIENT, "client", "SERVERHOST",
+ "act as a network client");
+ }
+ if (GRAPHICS_ENABLED) {
+ args.add_group("Graphics");
+
+ args.add_option(ARG_GRAPHICS, "graphics", "",
+ "run graphics/local input. Implied with --client");
+
+ args.add_option(ARG_FULLSCREEN, "fullscreen", "",
+ "run graphics in fullscreen mode");
+
+ args.add_option(ARG_RESOLUTION, "resolution", "WIDTHxHEIGHT",
+ "set graphics resolution");
+
+ args.add_option(ARG_LIST_MODES, "list-modes", "",
+ "output a list of available display modes and exit");
+ }
+
+ args.add_group("Game");
args.add_option(ARG_TERRAIN_SEED, "terrain-seed", "SEED",
"set seed for terrain random generator");
args.add_option(ARG_TERRAIN_SIZE, "terrain-size", "WIDTHxHEIGHT",
"set terrain size for random generator");
+
+ args.add_group("General");
+ args.add_option(ARG_LOG_LEVEL, "log-level", "LEVEL",
+ "set maximum log level to one of FATAL/ERROR/WARN/INFO/DEBUG");
+
+ args.add_option(ARG_HELP, "help", "",
+ "display argument help and exit");
+
args.add_option(ARG_VERSION, "version", "",
- "output application version and exit");
+ "output application version plus configuration and exit");
+#if GRAPHICS_ENABLED
// extra state
bool resolution_default = true;
+
+#endif
try {
// parse args
@@ -87,6 +120,11 @@
args.print_help();
return false;
+ case ARG_LOG_LEVEL:
+ engine.log_level = parse_arg_loglevel(args.get_argument(), "--log-level");
+ break;
+
+#if NETWORK_ENABLED
case ARG_PORT:
net_port = args.get_argument();
break;
@@ -99,31 +137,35 @@
net_connect = args.get_argument();
break;
+#endif
+
+#if GRAPHICS_ENABLED
case ARG_GRAPHICS:
graphics_enabled = true;
break;
case ARG_FULLSCREEN:
- graphics.fullscreen = true;
+ display.fullscreen = true;
// choose best resolution unless explicitly set
if (resolution_default) {
- const CL_DisplayMode best_mode = Graphics::getBestMode();
+ const CL_DisplayMode best_mode = graphics::Display::getBestMode();
const CL_Size best_resolution = best_mode.get_resolution();
- graphics.resolution = PixelCoordinate(best_resolution.width, best_resolution.height);
+ display.resolution = PixelDimensions(best_resolution.width, best_resolution.height);
}
break;
case ARG_RESOLUTION:
- graphics.resolution = parse_arg_dimensions(args.get_argument(), "--resolution");
+ display.resolution = parse_arg_dimensions(args.get_argument(), "--resolution");
resolution_default = false;
break;
case ARG_LIST_MODES:
dump_display_modes();
return false;
+#endif
case ARG_VERSION:
dump_version();
@@ -146,14 +188,18 @@
}
}
+#if NETWORK_ENABLED
// check for invalid combinations of arugments
if (net_server and !net_connect.empty())
throw ArgumentError("cannot be both server and client");
+#endif
+#if GRAPHICS_ENABLED
// enable graphics by default unless server
if (!net_server)
graphics_enabled = true;
-
+#endif
+
// continue
return true;
}
@@ -170,27 +216,69 @@
return int_val;
}
-PixelCoordinate Main::parse_arg_dimensions (const std::string &arg_val, const char *arg_name) {
+PixelDimensions Main::parse_arg_dimensions (const std::string &arg_val, const char *arg_name) {
unsigned int w, h;
// sccanf as unsigned
if (sscanf(arg_val.c_str(), "%ux%u", &w, &h) != 2)
throw ArgumentError(std::string() + "invalid format for " + arg_name + ": " + arg_val);
- return PixelCoordinate(w, h);
+ return PixelDimensions(w, h);
}
-
+
+LogLevel Main::parse_arg_loglevel (const std::string &arg_val, const char *arg_name) {
+ // brute-force if-elseif
+ if (arg_val == "FATAL")
+ return FATAL;
+
+ else if (arg_val == "ERROR")
+ return ERROR;
+
+ else if (arg_val == "WARN")
+ return WARN;
+
+ else if (arg_val == "INFO")
+ return INFO;
+
+ else if (arg_val == "DEBUG")
+ return DEBUG;
+
+ else
+ throw ArgumentError(std::string() + "invalid log level for " + arg_name + ": " + arg_val);
+}
+
+#if GRAPHICS_ENABLED
void Main::dump_display_modes (void) {
- const std::vector<CL_DisplayMode> &modes = Graphics::getDisplayModes();
+ // get the list of display modes from graphics
+ const std::vector<CL_DisplayMode> &modes = graphics::Display::getDisplayModes();
+ PixelCoordinate last_resolution;
std::cout << "Available display modes:" << std::endl;
-
- for (std::vector<CL_DisplayMode>::const_iterator it = modes.begin(); it != modes.end(); it++)
- std::cout << "\t" << it->get_resolution().width << "x" << it->get_resolution().height << std::endl;
+
+ // iterate over the list of available display modes
+ for (std::vector<CL_DisplayMode>::const_iterator it = modes.begin(); it != modes.end(); it++) {
+ PixelCoordinate resolution(it->get_resolution().width, it->get_resolution().height);
+
+ // filter out those that haven't changed
+ if (resolution != last_resolution)
+ std::cout << "\t" << it->get_resolution().width << "x" << it->get_resolution().height << std::endl;
+
+ // update for next item
+ last_resolution = resolution;
+ }
}
+#endif
void Main::dump_version (void) {
- std::cout << PROJECT_LONG_NAME << " version " << PROJECT_VERSION << " built " << PROJECT_BUILD_TIMESTAMP << std::endl;
+ std::cout
+ << PROJECT_LONG_NAME << " version " << PROJECT_VERSION << " built [" << PROJECT_BUILD_TIMESTAMP << "]" << std::endl;
+
+ // then some additional stuff about what's enabled
+ std::cout
+ << std::endl
+ << "Enabled components:" << std::endl
+ << "\tGraphics:\t" << (GRAPHICS_ENABLED ? "Yes" : "No") << std::endl
+ << "\tNetwork:\t" << (NETWORK_ENABLED ? "Yes" : "No") << std::endl;
}
/**
@@ -199,9 +287,12 @@
int Main::main (int argc, char **argv) {
// initialize the ClanLib components that we use
CL_SetupCore setup_core;
- CL_SetupNetwork setup_network;
+
+#if GRAPHICS_ENABLED
+ // XXX: move to Graphics/Graphics.hh?
CL_SetupDisplay setup_disp;
CL_SetupGL setup_gl;
+#endif
try {
// parse arugments, exit if false
@@ -209,7 +300,7 @@
return 0;
// our engine
- Engine engine;
+ Engine engine(this->engine);
// setup game unless client
if (net_connect.empty())
@@ -217,7 +308,7 @@
// setup graphics
if (graphics_enabled)
- engine.setupGraphics(graphics);
+ engine.setupGraphics(display);
// setup either network server, client or singleplayer
if (net_server) {
@@ -226,8 +317,12 @@
} else if (!net_connect.empty()) {
engine.setupNetworkClient(net_connect, net_port);
+ } else if (graphics_enabled) {
+ engine.setupSinglePlayer();
+
} else {
- engine.setupSinglePlayer();
+ throw ArgumentError("Nothing to do");
+
}
// run the main loop
@@ -237,11 +332,14 @@
return 0;
} catch (ArgumentError &e) {
- std::cerr << e.what() << std::endl;
+ std::cerr
+ << "Error: " << e.what() << std::endl
+ << std::endl;
+
args.print_help();
- // XXX: handle --help
return 1;
+
} catch (CL_Error &e) {
std::cerr << "main: CL_Error:" << e.message << std::endl;
--- a/src/Application.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Application.hh Thu Jan 22 03:02:43 2009 +0200
@@ -28,7 +28,7 @@
/**
* --fullscreen and --resolution
*/
- GraphicsConfig graphics;
+ DisplayConfig display;
/**
* --terrain-seed and --terrain-size
@@ -36,6 +36,11 @@
TerrainConfig terrain;
/**
+ * --log-level
+ */
+ EngineConfig engine;
+
+ /**
* --port
*/
std::string net_port;
@@ -66,7 +71,12 @@
/**
* Parse unsigned WIDTHxHEIGHT argument
*/
- PixelCoordinate parse_arg_dimensions (const std::string &arg_val, const char *arg_name);
+ PixelDimensions parse_arg_dimensions (const std::string &arg_val, const char *arg_name);
+
+ /**
+ * Parse a LogLevel
+ */
+ LogLevel parse_arg_loglevel (const std::string &arg_val, const char *arg_name);
/**
* Print out a list of display modes
@@ -74,7 +84,7 @@
void dump_display_modes (void);
/**
- * Print out our project version
+ * Print out our project version and some configuration info
*/
void dump_version (void);
--- a/src/CMakeLists.txt Wed Jan 21 00:21:42 2009 +0200
+++ b/src/CMakeLists.txt Thu Jan 22 03:02:43 2009 +0200
@@ -1,19 +1,47 @@
-FILE(GLOB SOURCE_FILES "*.cc" "Network/*.cc")
-FILE(GLOB HEADER_FILES "*.hh" "Network/*.hh")
+FILE(GLOB SOURCE_FILES "*.cc")
+FILE(GLOB HEADER_FILES "*.hh")
set_source_files_properties("version.c" PROPERTIES GENERATED true)
-set(SOURCES ${SOURCE_FILES} ${HEADER_FILES} "version.c")
+
+# Component selection
+set (GRAPHICS_ENABLED true)
+set (NETWORK_ENABLED true)
+
+mark_as_advanced (CLEAR GRAPHICS_ENABLED NETWORK_ENABLED)
# Generate config.h
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+# main module
+set (CORE_CLANLIB_COMPONENTS Core App Signals)
+set (CORE_SOURCES ${SOURCE_FILES} ${HEADER_FILES} "version.c")
+
+# Graphics module
+if (GRAPHICS_ENABLED)
+ add_subdirectory (Graphics)
+
+endif (GRAPHICS_ENABLED)
+
+# Network module
+if (NETWORK_ENABLED)
+ add_subdirectory (Network)
+
+endif (NETWORK_ENABLED)
+
# Libraries
+set (CLANLIB_VERSION 0.8)
+set (CLANLIB_COMPONENTS ${CORE_CLANLIB_COMPONENTS} ${GRAPHICS_CLANLIB_COMPONENTS} ${NETWORK_CLANLIB_COMPONENTS})
# ClanLib 0.8
-find_package(ClanLib 0.8 REQUIRED COMPONENTS Core App Signals Display GL Sound Network)
+message (STATUS "Finding ClanLib version=${CLANLIB_VERSION}, components=${CLANLIB_COMPONENTS}" )
+find_package(ClanLib ${CLANLIB_VERSION} REQUIRED COMPONENTS ${CLANLIB_COMPONENTS})
+
include_directories(${ClanLib_INCLUDE_DIRS})
+
+# build list of libs/source files
set(LIBS ${LIBS} ${ClanLib_LIBRARIES})
+set(SOURCES ${CORE_SOURCES} ${GRAPHICS_SOURCES} ${NETWORK_SOURCES})
# Assumes the project generates only one executable. If you need more, you'll need to alter
# the script and replace ${PROJECT_SHORT_NAME} by executable name.
--- a/src/Config.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Config.hh Thu Jan 22 03:02:43 2009 +0200
@@ -1,50 +1,85 @@
#ifndef CONFIG_HH
#define CONFIG_HH
-// XXX: merge this as Config.hh.in?
+/**
+ * @file
+ *
+ * Various constants used to define application/game behaviour
+ */
+
+// build settings
#include "config.h"
+// custom types
#include "Types.hh"
+// for CL_Color
#include <ClanLib/display.h>
-// This is a temporary way to declare different constants. Maybe we
-// should do somekind of resource manager? Do we have time?
-
/**
- * The value of pi used in physics/graphics calculations
+ * @name General
+ * @{
*/
-const float KG_PI = 3.14159265;
+
+// @}
/**
- * Random generator seed to use for terrain generator
+ * @name Terrain
+ * @{
*/
+
+/** Default random generator seed to use for terrain generator */
const int TERRAIN_RANDOM_SEED = 1337;
+/** Default terrain size, equal to physics simulation size */
+const PixelDimensions TERRAIN_DIMENSIONS (1000, 800);
+
+/** Base color of empty space (i.e. background color) */
+const CL_Color COLOR_EMPTY(86, 41, 0);
+
+/** Base color of dirt */
+const CL_Color COLOR_DIRT(144, 82, 23);
+
+/** Base color of rock */
+const CL_Color COLOR_ROCK(132, 136, 135);
+
+
+// @}
+
/**
- * Terrain size, equal to physics simulation size
+ * @name Engine
+ * @{
*/
-const PixelDimension TERRAIN_WIDTH = 1000;
-const PixelDimension TERRAIN_HEIGHT = 800;
/** Engine timeout, this determines our minimum tick rate */
const TimeMS ENGINE_TIMEOUT_MS = 10;
+/** Default log output level */
+const LogLevel DEFAULT_LOG_LEVEL = DEBUG;
+
+// @}
+
+/**
+ * @name Physics
+ * @{
+ */
+
+/** The value of pi used in physics/graphics calculations */
+const float KG_PI = 3.14159265;
+
/** Physics tick interval */
const TimeMS PHYSICS_TICK_MS = 10;
-/** Input handling keyboard poll interval */
-const TimeMS INPUT_POLL_INTERVAL = 10;
+/** The force of gravity on objects, exerted on the Y axis */
+const float MAP_GRAVITY = 1500.0;
-/** How long to block INPUT_FLAG_NOREPEAT for */
-const TimeMS INPUT_REPEAT_DELAY = 250;
+// @}
/**
- * The force of gravity on objects, exerted on the Y axis
+ * @name Player
+ * @{
*/
-const float MAP_GRAVITY = 1500.0;
-// Player properties
const float PLAYER_MASS = 10.0;
const float PLAYER_MOVE_FORCE = 1100.0;
const float PLAYER_MIN_SPEED = 10.0;
@@ -56,16 +91,12 @@
const float PLAYER_CROSSHAIR_DISTANCE = 20.0;
const float PLAYER_CROSSHAIR_WIDTH = 4;
const float CROSSHAIR_ANGLE_SPEED = PI/2000;
-
const float PLAYER_MAX_SPEED = 43;
const float PLAYER_WALK_SPEED = 33;
-
-const float PLAYER_COLLISION_ELASTICITY = 0.25; // TODO: This could be
- // different for different
- // objects
+const float PLAYER_COLLISION_ELASTICITY = 0.25;
const float PLAYER_RADIUS = 10;
-/** What size of hole to dig */
+/** Radius if ground removed on digging */
const float PLAYER_DIG_RADIUS = 15;
/** Player's initial health */
@@ -74,17 +105,22 @@
/** How long to wait after dying to respawn */
const TimeMS PLAYER_RESPAWN_DELAY = 2500;
-/*
- * Projectiles
+// @}
+
+/**
+ * @name Projectile
+ * @{
*/
-// object mass...
+/** Projectiles mass is irrelevant */
const float PROJECTILE_MASS = 10.0;
-// how far away from the player the projectile spawns
+/** How far away from the player the projectile spawns */
const float PROJECTILE_START_DISTANCE = 10.0;
-/*
+// @}
+
+/**
* @name Rope
* @{
*/
@@ -112,25 +148,61 @@
// @}
-// Graphical properties
-const CL_Color COLOR_EMPTY(86, 41, 0);
-const CL_Color COLOR_DIRT(144, 82, 23);
-const CL_Color COLOR_ROCK(132, 136, 135);
+/**
+ * @name Graphics/Input
+ * @{
+ */
-// graphics params
+/** Window title, XXX: PROJECT_VERSION is unreliable */
const std::string GRAPHICS_WINDOW_TITLE = (std::string() + PROJECT_LONG_NAME + " : Version " + PROJECT_VERSION);
-const uint32_t GRAPHICS_RESOLUTION_WIDTH = 800;
-const uint32_t GRAPHICS_RESOLUTION_HEIGHT = 600;
-const uint16_t GRAPHICS_UPDATE_INTERVAL_MS = 20;
+
+/** Default resolution */
+const PixelDimensions GRAPHICS_RESOLUTION (800, 600);
+
+/** Interval between frames */
+const TimeMS GRAPHICS_UPDATE_INTERVAL_MS = 20;
+
+/** Default fullscreen mode? */
const bool GRAPHICS_FULLSCREEN = false;
-/**
- * Number of pixels between lines
- */
+/** Number of pixels between lines */
const PixelDimension GRAPHICS_INFO_TEXT_LINE_OFFSET = 5;
-// Filesystem paths
+/** Input handling keyboard poll interval */
+const TimeMS INPUT_POLL_INTERVAL = 10;
+
+/** How long to block INPUT_FLAG_NOREPEAT for */
+const TimeMS INPUT_REPEAT_DELAY = 250;
+
+// @}
+
+/**
+ * @name Network
+ * @{
+ */
+
+/** Default port used for network games */
+const std::string NETWORK_PORT_STR = "9338";
+
+/** Maximum packet size used for normal NetworkPackets... aligned to a sensible UDP mtu */
+const size_t NETWORK_PACKET_SIZE = 1280;
+
+/** Backlog used for TCP server... doesn't really matter all that much */
+const int NETWORK_LISTEN_BACKLOG = 5;
+
+/** Magic string used to identify game between client/server */
+const char NETWORK_MAGIC_STR[8+1] = "KISNGLIS";
+const uint64_t NETWORK_MAGIC_ID = * ((const uint64_t *) NETWORK_MAGIC_STR);
+
+// @}
+
+/**
+ * @name Filesystem paths
+ * @{
+ */
const std::string PLAYER_SKIN_PATH = (PROJECT_DATA_DIR "/skin.png");
const std::string RESOURCE_XML_PATH = (PROJECT_DATA_DIR "/resources.xml");
+// @}
+
#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Configuration.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,58 @@
+#ifndef CONFIGURATION_HH
+#define CONFIGURATION_HH
+
+/**
+ * @file
+ *
+ * Various classes/modules have their own configuration structures, which are defined here
+ *
+ * XXX: rename to "Settings" to distinguish from Config/config?
+ */
+
+#include "Types.hh"
+#include "Config.hh"
+
+/**
+ * Engine configuration
+ */
+struct EngineConfig {
+ /** Path to the XML ClanLib resource file */
+ std::string resource_path;
+
+ /** Log output level */
+ enum LogLevel log_level;
+
+ /** Defaults */
+ EngineConfig (void) : resource_path(RESOURCE_XML_PATH), log_level(DEFAULT_LOG_LEVEL) { }
+};
+
+/**
+ * Terrain configuration
+ */
+struct TerrainConfig {
+ /** Size of the terrain field*/
+ PixelDimensions dimensions;
+
+ /** Set to nonzero to generate random map */
+ int random_seed;
+
+ /** Defaults */
+ TerrainConfig (void) : dimensions(TERRAIN_DIMENSIONS), random_seed(TERRAIN_RANDOM_SEED) { }
+};
+
+/**
+ * Graphics display configuration
+ */
+struct DisplayConfig {
+ /** Display resolution */
+ PixelDimensions resolution;
+
+ /** Fullscreen mode? */
+ bool fullscreen;
+
+ /** Defaults */
+ DisplayConfig (void) : resolution(GRAPHICS_RESOLUTION), fullscreen(GRAPHICS_FULLSCREEN) { }
+};
+
+
+#endif
--- a/src/Engine.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Engine.cc Thu Jan 22 03:02:43 2009 +0200
@@ -1,19 +1,39 @@
#include "Engine.hh"
#include "SinglePlayer.hh"
+#include "Config.hh"
+
+// XXX: how does this work if we don't have NETWORK_ENABLED?
#include "Network/Reactor.hh"
-#include "Config.hh"
+
+// include the real component definitions
+#if NETWORK_ENABLED
+ #include "Network/Client.hh"
+ #include "Network/Server.hh"
+#endif
+
+#if GRAPHICS_ENABLED
+ #include "Graphics/Graphics.hh"
+#endif
#include <iostream>
+#include <cassert>
-Engine::Engine (const std::string resource_xml_path) :
- terrain(NULL), game_state(NULL), graphics_config(NULL), graphics(NULL), net_server(NULL), net_client_connect(NULL),
- is_running(true), resources(resource_xml_path)
+/*
+ * Initialize static Engine global state
+ */
+LogLevel Engine::log_level = DEBUG;
+
+Engine::Engine (const EngineConfig &config) :
+ terrain(NULL), game_state(NULL), graphics(NULL), net_server(NULL), net_client_connect(NULL),
+ game_view(NULL),
+ is_running(true), resources(config.resource_path)
{
-
+ // update global log_level
+ Engine::log_level = config.log_level;
}
-GameState& Engine::setupGame (Terrain *terrain) {
+void Engine::setupGame (Terrain *terrain) {
// ensure this isn't called in inappropriate ways
assert(!net_server);
@@ -22,12 +42,6 @@
// create the GameState
game_state = new GameState(*terrain);
-
- // start graphics?
- if (graphics_config)
- startGraphics();
-
- return *game_state;
}
void Engine::setupGame (const TerrainConfig &config) {
@@ -35,38 +49,78 @@
setupGame(new Terrain(config));
}
-void Engine::setupGraphics (const GraphicsConfig &config) {
- // store config
- graphics_config = &config;
-
- // start already?
- if (game_state)
- startGraphics();
-}
+void Engine::setupGraphics (const DisplayConfig &config) {
-void Engine::startGraphics (void) {
- // check state
- assert(game_state && graphics_config);
+#if GRAPHICS_ENABLED
+ assert(!graphics);
// create the graphics
- graphics = new Graphics(*this, *game_state, *graphics_config);
+ graphics = new graphics::Graphics(*this, resources, config);
+
+#else
+ (void) config;
+
+ throw Error("No Graphics support available");
+
+#endif
+
+}
+
+void Engine::startGameView (LocalPlayer *player) {
+
+#if GRAPHICS_ENABLED
+ assert(graphics && !game_view);
+
+ game_view = graphics->displayGameView(*game_state, player);
+
+#else
+ (void) player;
+
+ throw Error("No Graphics support available");
+
+#endif
+
}
void Engine::setupNetworkServer (const std::string &listen_port) {
+
+#if NETWORK_ENABLED
NetworkEndpoint listen_addr(listen_port);
assert(terrain && game_state);
// create the server
net_server = new NetworkServer(*game_state, listen_addr);
+
+ // put graphics into GameView mode
+ if (graphics)
+ startGameView(NULL);
+
+#else
+ (void) listen_port;
+
+ throw Error("No Network support available");
+
+#endif
}
void Engine::setupNetworkClient (const std::string &connect_host, const std::string &connect_port) {
+
+#if NETWORK_ENABLED
// connect_to
NetworkEndpoint connect_addr(connect_host, connect_port);
// begin connecting, the client will callback us with setupGame once it's connected
net_client_connect = new NetworkClientConnect(*this, connect_addr);
+
+#else
+ (void) connect_host;
+ (void) connect_port;
+
+ throw Error("No Network support available");
+
+#endif
+
}
void Engine::setupSinglePlayer (void) {
@@ -77,6 +131,29 @@
// add to gamestate
game_state->setLocalPlayer(lp);
+
+ // put graphics into GameView mode
+ if (graphics)
+ startGameView(lp);
+}
+
+
+GameState& Engine::onNetworkClientConnected (Terrain *terrain) {
+ // setup the game
+ setupGame(terrain);
+
+ // start the GameView, but no LocalPlayer yet
+ startGameView(NULL);
+
+ // return GameState
+ return *game_state;
+}
+
+void Engine::onNetworkClientPlayer (LocalPlayer *player) {
+ assert(game_view);
+
+ // set the GameView's player
+ game_view->setPlayer(player);
}
void Engine::stop (void) {
@@ -84,34 +161,28 @@
}
void Engine::run (void) {
- // our NetworkReactor
- NetworkReactor *reactor = NetworkReactor::current;
-
- // timeout info
+ // timeout for NetworkReactor
timeval timeout;
while (is_running) {
- // this does.... magical things
- CL_System::keep_alive();
+ /*
+ * Run internal ClanLib stuff (also includes our timers) until our timeout has elapsed
+ */
+ CL_System::keep_alive(ENGINE_TIMEOUT_MS);
- // setup our timeout to ENGINE_TIMEOUT_MS
+#if NETWORK_ENABLED
+ // setup timeout to zero
timeout.tv_sec = 0;
- timeout.tv_usec = ENGINE_TIMEOUT_MS * 1000;
-
+ timeout.tv_usec = 0;
+
/*
* Thursday came and went, I re-wrote clan-event.
*
- * We use the NetworkReactor for sleeping, as it handles it effeciently even if we're not using network.
+ * (actually, we only use it for zero-timeout polling now... not sure if this is better than using the above
+ * CL_System::keep_alive)
*/
- reactor->poll(&timeout);
+ NetworkReactor::current->poll(&timeout);
+#endif
}
}
-CL_ResourceManager* Engine::getResourceManager (void) {
- return &resources;
-}
-
-Logger Engine::log (enum LogLevel level, const char *type) {
- return Logger(level <= WARN ? std::cerr : std::cout, level, type);
-}
-
--- a/src/Engine.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Engine.hh Thu Jan 22 03:02:43 2009 +0200
@@ -5,48 +5,60 @@
class Engine;
#include "GameState.hh"
-#include "Graphics.hh"
-#include "Network/Server.hh"
-#include "Network/Client.hh"
+#include "Configuration.hh"
+#include "Logger.hh"
-#include "Logger.hh"
+// forward-declare component pointer types
+// XXX: move to some kind of Components.hh file?
+namespace graphics { class Graphics; class GameView; }
+class NetworkServer;
+class NetworkClientConnect;
+class NetworkClient;
+class NetworkClientController;
/**
* This is the core class that glues all the other components together and runs the main loop
*/
class Engine {
private:
- // game state
+ /** The game's terrain */
Terrain *terrain;
- GameState *game_state;
-
- /** Set if setupGraphics has been called */
- const GraphicsConfig *graphics_config;
-
- // Graphics/Input
- Graphics *graphics;
- // network server/client
+ /** The game's state */
+ GameState *game_state;
+
+ /** The graphics+input component */
+ graphics::Graphics *graphics;
+
+ /** Network server */
NetworkServer *net_server;
- NetworkClientConnect *net_client_connect;
- // XXX: currently unused: NetworkClient *net_client;
- // to exit the mainloop
+ /** Network client connector */
+ NetworkClientConnect *net_client_connect;
+
+ /** Network client, currently unused */
+ NetworkClient *net_client;
+
+ /** The GameView, if open */
+ graphics::GameView *game_view;
+
+ /** Is the mainloop still running? */
bool is_running;
+
+ /** Used to load ClanLib resources */
+ CL_ResourceManager resources;
- // ClanLib resources
- CL_ResourceManager resources;
+ /** *Global* log level */
+ static LogLevel log_level;
public:
// default constructor
- Engine (const std::string resource_xml_path = RESOURCE_XML_PATH);
+ Engine (const EngineConfig &config);
/**
* Setup game world using the given terrain, returning the new GameState
- *
- * XXX: fix to return void
*/
- GameState& setupGame (Terrain *terrain);
+ void setupGame (Terrain *terrain);
/**
* Setup game world using given terrain configuration
@@ -54,17 +66,23 @@
void setupGame (const TerrainConfig &config);
/**
- * Enable graphics
+ * Enable graphics.
+ *
+ * Requires: GRAPHICS_ENABLED
*/
- void setupGraphics (const GraphicsConfig &config);
+ void setupGraphics (const DisplayConfig &config);
/**
* Setup server, must call setupGame first
+ *
+ * Requires: NETWORK_ENABLED
*/
void setupNetworkServer (const std::string &listen_port);
/**
* Setup client, do *not* call setupGame, configuration comes from the server
+ *
+ * Requires: NETWORK_ENABLED
*/
void setupNetworkClient (const std::string &connect_host, const std::string &connect_port);
@@ -85,16 +103,40 @@
private:
/**
- * Actually start graphics, requires that game_state is now set
+ * Puts graphics into GameView mode, using our GameState and the given player
*/
- void startGraphics (void);
+ void startGameView (LocalPlayer *player);
+
+ protected:
+ friend class NetworkClientConnect;
+ friend class NetworkClientController;
+
+ /**
+ * Interface for NetworkClient to use once it has connected
+ */
+ GameState& onNetworkClientConnected (Terrain *terrain);
+
+ /**
+ * Interface for NetworkClient to use once it has set up the player
+ */
+ void onNetworkClientPlayer (LocalPlayer *player);
public:
- // get a pointer to our resource manager
- CL_ResourceManager* getResourceManager (void);
-
- // logging utility
- static Logger log (enum LogLevel level, const char *type);
+ /**
+ * Get a pointer to our resource manager, please don't break it.
+ *
+ * Guaranteed to never be NULL
+ */
+ CL_ResourceManager* getResourceManager (void) { return &resources; }
+
+ /**
+ * Log output, see Logger for more info
+ *
+ * @see Logger
+ */
+ static inline Logger log (LogLevel level, const char *type) {
+ return Logger(level <= WARN ? std::cerr : std::cout, level, type, log_level);
+ }
};
--- a/src/GameMessageView.cc Wed Jan 21 00:21:42 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-
-#include "GameMessageView.hh"
-#include "Graphics.hh"
-#include "Engine.hh"
-
-GameMessageView::GameMessageView (PixelArea area) :
- area(area), messages()
-{
-
-}
-
-void GameMessageView::add_message (CL_Color color, std::string message) {
- GameMessage msg (color, message);
-
- messages.push_back(msg);
-}
-
-void GameMessageView::draw (Graphics *g) {
- // get font
- CL_Font &font = g->getSimpleFont();
-
- // remember color
- CL_Color font_color = font.get_color();
-
- // maximum width
- CL_Size max_size = CL_Size(area.right - area.left, 0);
-
- // starting point for drawing
- PixelDimension offset_prev = area.bottom;
-
- // render messages, bottom up
- for (std::vector<GameMessage>::reverse_iterator it = messages.rbegin(); it != messages.rend(); it++) {
- // set message color
- font.set_color(it->color);
-
- // calculate height
- PixelDimension height = font.get_height(it->message, max_size) + GRAPHICS_INFO_TEXT_LINE_OFFSET;
-
- // new draw_point
- PixelDimension offset_this = offset_prev - height;
-
- // break if it doesn't fit anymore
- if (offset_this < area.top)
- break;
-
- // draw text
- font.draw(CL_Rect(area.left, offset_this, area.right, offset_prev), it->message, g->get_gc());
-
- // advance offset
- offset_prev = offset_this;
- }
-
- // restore font color
- font.set_color(font_color);
-}
-
--- a/src/GameMessageView.hh Wed Jan 21 00:21:42 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-#ifndef GRAPHICS_INFO_TEXT_HH
-#define GRAPHICS_INFO_TEXT_HH
-
-#include "GraphicsPointer.hh"
-#include "Types.hh"
-
-#include <string>
-#include <vector>
-#include <ClanLib/display.h>
-
-struct GameMessage {
- CL_Color color;
- std::string message;
-
- GameMessage (CL_Color color, std::string message) : color(color), message(message) { }
- GameMessage (const GameMessage ©) : color(copy.color), message(copy.message) { }
- GameMessage &operator= (const GameMessage ©) { color = copy.color; message = copy.message; return *this; }
-};
-
-class GameMessageView {
- protected:
- PixelArea area;
- std::vector<GameMessage> messages;
-
- public:
- /**
- * Define the area where messages are drawn
- */
- GameMessageView (PixelArea area);
-
- /**
- * Update draw area
- */
- void on_resize (PixelArea new_area) { this->area = new_area; }
-
- /**
- * Add a message to the list of messages displayed
- */
- void add_message (CL_Color color, std::string message);
-
- /**
- * Draw as many messages as fits
- */
- void draw (Graphics *g);
-};
-
-#endif
--- a/src/GameState.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/GameState.cc Thu Jan 22 03:02:43 2009 +0200
@@ -2,6 +2,7 @@
#include "GameState.hh"
#include "Engine.hh"
#include "Config.hh"
+#include "Error.hh"
GameState::GameState (Terrain &terrain) :
world(Vector(0, MAP_GRAVITY), Vector(terrain.getWidth(), terrain.getHeight()), terrain),
@@ -49,10 +50,11 @@
if (event_handler)
event_handler->on_player_left(player);
}
-
-void GameState::draw(Graphics *g, PixelCoordinate camera, bool displayWeapon) {
+
+#if GRAPHICS_ENABLED
+void GameState::draw (graphics::Display &display, PixelCoordinate camera, bool displayWeapon) {
// Draw terrain
- terrain.draw(g, camera);
+ terrain.draw(display, camera);
// Draw players
for (std::list<Player*>::iterator it = player_list.begin(); it != player_list.end(); it++) {
@@ -60,14 +62,15 @@
// our LocalPlayer has it's own draw method
if (p == local_player)
- local_player->draw(g, displayWeapon, camera);
+ local_player->draw(display, displayWeapon, camera);
else
- p->draw(g, camera);
+ p->draw(display, camera);
}
// Draw projectiles
for (std::list<Projectile*>::iterator it = projectiles.begin(); it != projectiles.end(); it++) {
- (*it)->draw(g, camera);
+ (*it)->draw(display, camera);
}
}
-
+#endif
+
--- a/src/GameState.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/GameState.hh Thu Jan 22 03:02:43 2009 +0200
@@ -4,13 +4,13 @@
class GameState;
#include "PhysicsWorld.hh"
+#include "Terrain.hh"
#include "Player.hh"
#include "Projectile.hh"
-#include "Rope.hh"
-#include "Input.hh"
-#include "GraphicsPointer.hh"
#include "Config.hh"
+#include "Graphics/Drawable.hh"
+
#include <list>
#include <stdexcept>
#include <cmath>
@@ -93,11 +93,13 @@
* Removes the given player from player_list. If the given player was the local_player, set that to NULL
*/
void removePlayer (Player *player);
-
+
+#if GRAPHICS_ENABLED
/**
* Draws the terrain, players and projectiles
*/
- virtual void draw (Graphics *g, PixelCoordinate camera, bool displayWeapon);
+ virtual void draw (graphics::Display &display, PixelCoordinate camera, bool displayWeapon);
+#endif
};
#endif
--- a/src/Graphics.cc Wed Jan 21 00:21:42 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,352 +0,0 @@
-
-#include "Graphics.hh"
-#include "GameState.hh"
-#include <cmath>
-#include <sstream>
-
-/*
- * XXX: until we figure out a better way to layout stuff
- */
-static PixelArea getMessageViewArea (PixelCoordinate resolution) {
- return PixelArea(
- 400,
- resolution.y - 100,
- resolution.x,
- resolution.y
- );
-}
-
-Graphics::Graphics (Engine &engine, GameState &state, const GraphicsConfig &config) :
- CL_DisplayWindow(GRAPHICS_WINDOW_TITLE, config.resolution.x, config.resolution.y, config.fullscreen, true),
- engine(engine),
- state(state),
- resolution(config.resolution),
- fullscreen_resolution(0, 0), window_resolution(0, 0),
- update_timer(GRAPHICS_UPDATE_INTERVAL_MS),
- input(get_ic()->get_keyboard()),
- simple_font("Font2", engine.getResourceManager()),
- message_view(getMessageViewArea(resolution))
-{
-
- // connect timer signal
- slots.connect(update_timer.sig_tick(), this, &Graphics::on_update);
- slots.connect(this->sig_resize(), this, &Graphics::on_window_resize);
-
- // enable
- update_timer.start();
-
- // push something to message_view
- message_view.add_message(CL_Color::white, "Hello World");
-
- // GameState events....
- state.setEventHandler(this);
-
- // set correct resolution
- if (config.fullscreen) {
- fullscreen_resolution = resolution;
-
- } else {
- CL_DisplayMode best_mode = getBestMode();
-
- fullscreen_resolution = PixelCoordinate(best_mode.get_resolution().width, best_mode.get_resolution().height);
- window_resolution = resolution;
- }
-
-}
-
-const std::vector<CL_DisplayMode> & Graphics::getDisplayModes (void) {
- return CL_DisplayMode::get_display_modes();
-}
-
-const CL_DisplayMode Graphics::getBestMode (void) {
- const std::vector<CL_DisplayMode> &modes = Graphics::getDisplayModes();
-
- const CL_DisplayMode *best_mode = NULL;
-
- for (std::vector<CL_DisplayMode>::const_iterator it = modes.begin(); it != modes.end(); it++)
- if (best_mode == NULL || (
- it->get_resolution().width * it->get_resolution().height >
- best_mode->get_resolution().width * best_mode->get_resolution().height
- ))
- best_mode = &*it;
-
- if (best_mode == NULL)
- throw Error("No available video modes!");
-
- return *best_mode;
-}
-
-void Graphics::check_input (void) {
- LocalPlayer *player;
- PlayerInput input_mask;
- TimeMS input_dt;
-
- // update gui flags
- handle_input(input.readGuiInput());
-
- // stop here if we don't have a local player
- if ((player = state.getLocalPlayer()) == NULL)
- return;
-
- // build input_mask
- input.readPlayerInput(input_mask, input_dt);
-
- // apply input if there was any
- if (input_mask)
- player->handleInput(input_mask, input_dt);
-}
-
-void Graphics::toggle_fullscreen (void) {
- if (is_fullscreen()) {
- // remember current fullscreen resolution
- fullscreen_resolution = resolution;
-
- // enter windowed mode
- set_windowed();
-
-/*
- // do we have a window-mode resolution stored?
- if (window_resolution.x && window_resolution.y)
- set_size(window_resolution.x, window_resolution.y);
-*/
- } else {
- // remember current window resolution
- window_resolution = resolution;
-
- // enter fullscreen mode
- set_fullscreen(fullscreen_resolution.x, fullscreen_resolution.y);
-
- // update resolution
- resolution = fullscreen_resolution;
-
- // log
- message_view.add_message(CL_Color::yellow, CL_String::format("[ Enter fullscreen mode with %1 x %2 resolution ]",
- (int) resolution.x, (int) resolution.y));
- }
-}
-
-void Graphics::handle_input (GuiInput flags) {
- // update flags
- this->flags = flags;
-
- // quit?
- if (flags & GUI_INPUT_QUIT) {
- engine.stop();
-
- return;
- }
-
- // dump player debug info on stderr
- if ((flags & GUI_INPUT_DEBUG_PLAYER) && state.getLocalPlayer()) {
- state.getLocalPlayer()->printDebugInfo();
-
- message_view.add_message(CL_Color::green, "...");
- }
-
- // toggle fullscreen?
- if (flags & GUI_INPUT_TOGGLE_FULLSCREEN)
- toggle_fullscreen();
-}
-
-static PixelDimension value_between (PixelDimension low, PixelDimension value, PixelDimension high) {
- if (high < low)
- return (high + low) / 2;
-
- else if (value < low)
- return low;
-
- else if (value > high)
- return high;
-
- else
- return value;
-}
-
-void Graphics::do_redraw (void) {
- CL_GraphicContext *gc = get_gc();
- LocalPlayer *player;
-
- // calculate camera
- PixelCoordinate camera(0, 0);
-
- // ...to track our local player
- if ((player = state.getLocalPlayer()) != NULL) {
- // try and center the screen on the player
- PixelCoordinate target = player->getCoordinate() - PixelCoordinate(resolution.x / 2, (resolution.y - 100) / 2);
-
- // ...but keep the world in view
- PixelCoordinate max = state.terrain.getDimensions() - resolution + PixelCoordinate(0, 100);
-
- // ...by limiting the value to 0...max
- camera = PixelCoordinate(
- value_between(0, target.x, max.x),
- value_between(0, target.y, max.y)
- );
- }
-
- // Black background
- gc->clear(CL_Color::black);
-
- // Draw the game
- state.draw(this, camera, flags & GUI_INPUT_DISPLAY_WEAPON);
-
- // draw player info box
- if (player != NULL) {
- draw_player_info(gc, player);
- }
-
- // draw messages
- message_view.draw(this);
-
- // Flip window buffer, sync
- flip(1);
-}
-
-void Graphics::on_update (TimeMS tick_length) {
- (void) tick_length;
-
- // check keyboard input
- check_input();
-
- // redraw display
- do_redraw();
-}
-
-void Graphics::draw_player_info(CL_GraphicContext *gc, Player *p) {
- int box_top = resolution.y - 100;
- int box_left = 0;
- int box_right = resolution.x;
- int box_bottom = resolution.y;
- int bar_length = 3; // *100
-
- // draw status info at bottom of display
- gc->fill_rect(
- CL_Rect(
- box_left,
- box_top,
- box_right,
- box_bottom
- ),
- CL_Gradient(
- CL_Color(0, 0, 0),
- CL_Color(50, 50, 50),
- CL_Color(50, 50, 50, 150),
- CL_Color(100, 100, 100, 200)
- )
- );
-
- // Health
- gc->draw_rect(
- CL_Rect(
- box_left + 9,
- box_top + 9,
- box_left + 11 + 100 * bar_length,
- box_top + 31
- ),
- CL_Color(150, 150, 150)
- );
-
- gc->fill_rect(
- CL_Rect(
- box_left + 10,
- box_top + 10,
- box_left + 10 + (int) (p->getHealthPercent() * bar_length),
- box_top + 30
- ),
- CL_Gradient(
- CL_Color(200, 0, 0),
- CL_Color(200 - (int)(p->getHealthPercent() * 2), (int)(p->getHealthPercent() * 2), 0),
- CL_Color(200, 0, 0),
- CL_Color(200 - (int)(p->getHealthPercent() * 2), (int)(p->getHealthPercent() * 2), 0)
- )
- );
-
- // stats - kills
- std::stringstream sskills;
- sskills << "Kills: " << p->getKills();
- getSimpleFont().draw(
- box_left + 20 + 100 * bar_length,
- box_top + 10,
- sskills.str(),
- get_gc()
- );
-
- // stats - deaths
- std::stringstream ssdeaths;
- ssdeaths << "Deaths: " << p->getDeaths();
- getSimpleFont().draw(
- box_left + 20 + 100 * bar_length,
- box_top + 30,
- ssdeaths.str(),
- get_gc()
- );
-
- // stats - ratio
- std::stringstream ssratio;
- ssratio << "Ratio: " << (p->getKills()+1) / (p->getDeaths()+1);
- getSimpleFont().draw(
- box_left + 20 + 100 * bar_length,
- box_top + 50,
- ssratio.str(),
- get_gc()
- );
-
-
- // Weapon clip / reloading
- gc->draw_rect(
- CL_Rect(
- box_left + 9,
- box_top + 69,
- box_left + 11 + 100 * bar_length,
- box_top + 91
- ),
- CL_Color(150, 150, 150)
- );
-
- gc->fill_rect(
- CL_Rect(
- box_left + 10,
- box_top + 70,
- box_left + 10 + (100 - (int) (p->getCurrentWeapon()->getReloadTimer() * 100 / p->getCurrentWeapon()->getReloadTime())) * bar_length,
- box_top + 90
- ),
- CL_Gradient(
- CL_Color(100, 100, 0),
- CL_Color(100, 100, 0),
- CL_Color(100, 100, 0),
- CL_Color(100, 100, 100)
- )
- );
-
- // current weapon name
- getSimpleFont().draw(
- box_left + 20 + 100 * bar_length,
- box_top + 70,
- p->getCurrentWeapon()->getName(),
- get_gc()
- );
-
-}
-
-void Graphics::on_window_resize (int new_x, int new_y) {
- // ignore resize in fullscreen mode
- if (is_fullscreen())
- return;
-
- // update resolution
- resolution = PixelCoordinate(new_x, new_y);
-
- // resize components
- message_view.on_resize(getMessageViewArea(resolution));
-
- // log message
- message_view.add_message(CL_Color::yellow, CL_String::format("[ Resized window to %1 x %2 ]", new_x, new_y));
-}
-
-void Graphics::on_player_joined (Player *p) {
- message_view.add_message(CL_Color::white, " *** Player joined");
-}
-
-void Graphics::on_player_left (Player *p) {
- message_view.add_message(CL_Color::white, " *** Player left");
-}
--- a/src/Graphics.hh Wed Jan 21 00:21:42 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-#ifndef GRAPHICS_HH
-#define GRAPHICS_HH
-
-#include "GraphicsPointer.hh"
-#include "Types.hh"
-#include "Config.hh"
-
-/**
- * Parameters used by Graphics
- */
-struct GraphicsConfig {
- /** Initial resolution to use */
- PixelCoordinate resolution;
-
- /* Use fullscreen mode at startup */
- bool fullscreen;
-
- /** Defaults */
- GraphicsConfig (void) : resolution(GRAPHICS_RESOLUTION_WIDTH, GRAPHICS_RESOLUTION_HEIGHT), fullscreen(GRAPHICS_FULLSCREEN) { }
-};
-
-#include "GameState.hh"
-#include "Input.hh"
-#include "Timer.hh"
-#include "Engine.hh"
-
-#include "GameMessageView.hh"
-
-#include <ClanLib/core.h>
-#include <ClanLib/gl.h>
-#include <ClanLib/display.h>
-
-/**
- * This handles drawing the GameState with an appropriate camera view each frame, loading fonts, and currently,
- * handling the input from Input to GameState.
- */
-class Graphics : public GameStateEventHandler, public CL_DisplayWindow {
-private:
- /**
- * Our engine reference
- */
- Engine &engine;
-
- /**
- * GameState we are associated with
- */
- GameState &state;
-
- /**
- * Current window resolution
- */
- PixelCoordinate resolution;
-
- /**
- * Target resolution in fullscreen/windowed mode
- */
- PixelCoordinate fullscreen_resolution, window_resolution;
-
- /**
- * ClanLib signal slots
- */
- CL_SlotContainer slots;
-
- /**
- * Our timer that drives redraws
- */
- Timer update_timer;
-
- /**
- * Our input handler for GUI and Player input
- */
- Input input;
-
- /**
- * Current GUI input state
- */
- GuiInput flags;
-
- /**
- * A basic font
- */
- CL_Font simple_font;
-
- /**
- * View components
- */
- GameMessageView message_view;
-
-public:
- /**
- *
- */
- Graphics (Engine &engine, GameState &state, const GraphicsConfig &config);
-
- /**
- * Returns a CL_Font that can be used for drawing text
- */
- CL_Font& getSimpleFont (void) { return simple_font; }
-
- /**
- * Returns a vector of CL_DisplayModes that lists possible display modes to use for fullscreen mode.
- */
- static const std::vector<CL_DisplayMode> & getDisplayModes (void);
-
- /**
- * Returns the "best" CL_DisplayMode to use for fullscreen mode.
- *
- * Currently, this just means the largest resolution.
- */
- static const CL_DisplayMode getBestMode (void);
-
-private:
- /**
- * Shift back and forth between fullscreen and windowed mode, retaining resolutions
- */
- void toggle_fullscreen (void);
-
- /**
- * Reads current input events from Input and applies them, using LocalPlayer::handleInput and
- * Graphics::handle_input.
- */
- void check_input (void);
-
- /**
- * Handles GuiInput flags read from Input.
- */
- void handle_input (GuiInput flags);
-
- /**
- * Redraws entire screen
- */
- void do_redraw (void);
-
- /**
- * Handles input and redraws screen
- */
- void on_update (TimeMS tick_length);
-
- /**
- * Draws status view
- */
- void draw_player_info (CL_GraphicContext *gc, Player *p);
-
- /**
- * Handles window resize. This just updates resolution
- */
- void on_window_resize (int new_x, int new_y);
-
-protected:
- /* GameStateEventHandler */
- virtual void on_player_joined (Player *p);
- virtual void on_player_left (Player *p);
-};
-
-#endif /* GRAPHICS_HH */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/CMakeLists.txt Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,9 @@
+FILE(GLOB GRAPHICS_SOURCE_FILES "*.cc")
+FILE(GLOB GRAPHICS_HEADER_FILES "*.hh")
+
+# what ClanLib components we need
+set (GRAPHICS_CLANLIB_COMPONENTS Display GL GUI PARENT_SCOPE)
+
+# list of source files
+set (GRAPHICS_SOURCES ${GRAPHICS_SOURCE_FILES} ${GRAPHICS_HEADER_FILES} PARENT_SCOPE)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Console.cc Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,23 @@
+
+#include "Console.hh"
+
+namespace graphics
+{
+
+Console::Console (const CL_Rect& pos, CL_Component* parent) :
+ CL_Component(pos, parent),
+ messages(), input(getInputPosition(), this)
+{
+ // hide by default
+ show(false);
+
+}
+
+CL_Rect Console::getInputPosition (void) {
+ CL_Rect pos = get_position();
+
+ return CL_Rect(pos.left, pos.bottom - 30, pos.right, pos.bottom);
+}
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Console.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,34 @@
+#ifndef GRAPHICS_CONSOLE_HH
+#define GRAPHICS_CONSOLE_HH
+
+#include "GUI.hh"
+
+#include <list>
+
+namespace graphics
+{
+
+class Console : public CL_Component {
+protected:
+ /** our list of messages */
+ std::list<std::string> messages;
+
+ /** our input dialog */
+ CL_InputBox input;
+
+public:
+ /**
+ * Construct a new console, positioned in the given area, with the given parent
+ */
+ Console (const CL_Rect& pos, CL_Component* parent);
+
+private:
+ /**
+ * Calculate the position for the input box
+ */
+ CL_Rect getInputPosition (void);
+};
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Display.cc Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,102 @@
+
+#include "Display.hh"
+#include "../Error.hh"
+
+namespace graphics
+{
+
+Display::Display (const DisplayConfig &config) :
+ CL_DisplayWindow(GRAPHICS_WINDOW_TITLE, config.resolution.width, config.resolution.height, config.fullscreen, true),
+ config(config),
+ fullscreen_resolution(0, 0),
+ update_timer(GRAPHICS_UPDATE_INTERVAL_MS),
+ current_view(NULL)
+{
+ // connect timer signal
+ slots.connect(update_timer.sig_tick(), this, &Display::on_update);
+ slots.connect(this->sig_resize(), this, &Display::on_window_resize);
+
+ // enable timer
+ update_timer.start();
+
+ // set correct fullscreen resolution
+ if (config.fullscreen) {
+ fullscreen_resolution = config.resolution;
+
+ } else {
+ CL_DisplayMode best_mode = getBestMode();
+
+ fullscreen_resolution = PixelDimensions(best_mode.get_resolution().width, best_mode.get_resolution().height);
+ }
+}
+
+const std::vector<CL_DisplayMode> & Display::getDisplayModes (void) {
+ return CL_DisplayMode::get_display_modes();
+}
+
+const CL_DisplayMode Display::getBestMode (void) {
+ const std::vector<CL_DisplayMode> &modes = getDisplayModes();
+
+ const CL_DisplayMode *best_mode = NULL;
+
+ for (std::vector<CL_DisplayMode>::const_iterator it = modes.begin(); it != modes.end(); it++)
+ if (best_mode == NULL || (
+ it->get_resolution().width * it->get_resolution().height >
+ best_mode->get_resolution().width * best_mode->get_resolution().height
+ ))
+ best_mode = &*it;
+
+ if (best_mode == NULL)
+ throw Error("No available video modes!");
+
+ return *best_mode;
+}
+
+void Display::setView (View *view) {
+ this->current_view = view;
+
+ // resize to fill display
+ if (view)
+ view->resize(PixelArea(0, 0, get_width(), get_height()));
+}
+
+void Display::toggleFullscreen (void) {
+ if (is_fullscreen()) {
+ // enter windowed mode
+ set_windowed();
+
+ } else {
+ // enter fullscreen mode
+ set_fullscreen(fullscreen_resolution.width, fullscreen_resolution.height);
+ }
+}
+
+void Display::on_update (TimeMS dt) {
+ (void) dt;
+
+ // do we have something to draw?
+ if (current_view) {
+ // draw it
+ current_view->draw(*this);
+
+ // flip buffers, sync
+ flip(1);
+ }
+}
+
+void Display::on_window_resize (int new_x, int new_y) {
+ (void) new_x;
+ (void) new_y;
+
+ // ignore resize in fullscreen mode
+ if (is_fullscreen())
+ return;
+
+ // resize view
+ if (current_view)
+ current_view->resize(PixelArea(0, 0, new_x, new_y));
+}
+
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Display.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,102 @@
+#ifndef GRAPHICS_DISPLAY_HH
+#define GRAPHICS_DISPLAY_HH
+
+#include "../Types.hh"
+#include "../Config.hh"
+
+namespace graphics
+{
+
+class Display;
+
+}
+
+#include "View.hh"
+#include "../Timer.hh"
+#include "../Configuration.hh"
+
+#include <ClanLib/display.h>
+
+namespace graphics
+{
+
+/**
+ * We wrap ClanLib's DisplayWindow for our own functionality. This is the core of the graphics code
+ */
+class Display : public CL_DisplayWindow {
+private:
+ /**
+ * Our configuration
+ */
+ DisplayConfig config;
+
+ /**
+ * Target fullscreen resolution
+ */
+ PixelDimensions fullscreen_resolution;
+
+ /**
+ * Our timer that drives redraws
+ */
+ Timer update_timer;
+
+ /**
+ * What we draw
+ */
+ View *current_view;
+
+ CL_SlotContainer slots;
+
+public:
+ /**
+ * Construct default display, empty window unless otherwise build
+ */
+ Display (const DisplayConfig &config);
+
+ /**
+ * Returns a vector of CL_DisplayModes that lists possible display modes to use for fullscreen mode.
+ */
+ static const std::vector<CL_DisplayMode> & getDisplayModes (void);
+
+ /**
+ * Returns the "best" CL_DisplayMode to use for fullscreen mode.
+ *
+ * Currently, this just means the largest resolution.
+ */
+ static const CL_DisplayMode getBestMode (void);
+
+ /**
+ * Get current resolution
+ *
+ * XXX: should be PixelDimensions...
+ */
+ PixelCoordinate getResolution (void) {
+ return PixelCoordinate(get_width(), get_height());
+ }
+
+ /**
+ * Display the given view, this will initialize resize it to the right size
+ */
+ void setView (View *view);
+
+ /**
+ * Shift back and forth between fullscreen and windowed mode, retaining resolutions
+ */
+ void toggleFullscreen (void);
+
+private:
+ /**
+ * Draw next frame
+ */
+ void on_update (TimeMS dt);
+
+ /**
+ * Handles window resize. This just updates resolution
+ */
+ void on_window_resize (int new_x, int new_y);
+
+};
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Drawable.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,30 @@
+#ifndef GRAPHICS_DRAWABLE_HH
+#define GRAPHICS_DRAWABLE_HH
+
+namespace graphics
+{
+
+class Drawable;
+
+}
+
+#include "Display.hh"
+
+namespace graphics
+{
+
+/**
+ * Abstract interface class to define something that's drawable
+ */
+class Drawable {
+public:
+ /**
+ * Draw graphics onto the given display
+ */
+ virtual void draw (Display &display) = 0;
+};
+
+}
+
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/FontManager.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,43 @@
+#ifndef GRAPHICS_FONT_MANAGER_HH
+#define GRAPHICS_FONT_MANAGER_HH
+
+#include <ClanLib/display.h>
+
+namespace graphics
+{
+
+/**
+ * Loads fonts and lets other components use them
+ */
+class FontManager {
+private:
+ /**
+ * Our resource manager for loading these
+ */
+ CL_ResourceManager &resources;
+
+ /**
+ * A basic monospace font
+ */
+ CL_Font simple_font;
+
+public:
+ /**
+ * Load fonts
+ */
+ FontManager (CL_ResourceManager &resources) :
+ resources(resources), simple_font("Font2", &resources)
+ {
+
+ }
+
+ /**
+ * Returns a CL_Font that can be used for drawing text
+ */
+ CL_Font& getSimpleFont (void) { return simple_font; }
+};
+
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/GUI.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,31 @@
+#ifndef GRAPHICS_GUI_HH
+#define GRAPHICS_GUI_HH
+
+#include "GUIStyle.hh"
+
+#include <ClanLib/gui.h>
+
+
+namespace graphics
+{
+
+/**
+ * Our CL_GUIManager, for when we use ClanLib's GUI stuff
+ */
+class GUI : public CL_GUIManager {
+public:
+ /**
+ * Construct default manager
+ */
+ GUI (CL_ResourceManager *resources) :
+ CL_GUIManager(new GUIStyle(resources))
+ {
+
+ }
+
+
+};
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/GUIStyle.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,37 @@
+#ifndef GRAPHICS_GUI_STYLE_HH
+#define GRAPHICS_GUI_STYLE_HH
+
+#include "GUI.hh"
+
+#include <ClanLib/guistylesilver.h>
+
+namespace graphics
+{
+
+/**
+ * Our CL_StyleManager used for drawing ClanLib's GUI components
+ */
+class GUIStyle : public CL_StyleManager_Silver {
+public:
+ /**
+ * Construct GUI style
+ */
+ GUIStyle (CL_ResourceManager *resources) :
+ CL_StyleManager_Silver(resources)
+ {
+
+ }
+
+ /**
+ * Handle attaching style objects to components
+ */
+ virtual void connect_styles (const std::string &type, CL_Component *component) {
+
+ // default to parent impl
+ CL_StyleManager_Silver::connect_styles(type, component);
+ }
+};
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/GameView.cc Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,136 @@
+
+#include "GameView.hh"
+#include "Graphics.hh"
+
+#include <cassert>
+
+namespace graphics
+{
+
+GameView::GameView (GameState &state, LocalPlayer *player) :
+ View(PixelArea(0, 0, graphics->display.get_width(), graphics->display.get_height())),
+ state(state), player(NULL), info_view(NULL), message_view(getMessageViewArea()),
+ flags(0)
+{
+ // have player?
+ if (player)
+ setPlayer(player);
+
+ // insert message
+ message_view.add_message(CL_Color::white, "Hello World!");
+
+ // enable GUI input
+ slots.connect(graphics->input.gui.sig_input(), this, &GameView::handleInput);
+ graphics->input.gui.enable();
+}
+
+void GameView::setPlayer (LocalPlayer *player) {
+ assert(!this->player && player);
+
+ // remember it
+ this->player = player;
+
+ // build the info_view as well
+ info_view = new PlayerInfoView(getInfoViewArea(), player);
+
+ // enable player input
+ slots.connect(graphics->input.player.sig_input(), player, &LocalPlayer::handleInput);
+ graphics->input.player.enable();
+}
+
+void GameView::handleInput (GuiInput flags, TimeMS dt) {
+ // ignore timing info
+ (void) dt;
+
+ // update our flags
+ this->flags = flags;
+
+ // quit?
+ if (flags & GUI_INPUT_QUIT) {
+ graphics->engine.stop();
+ return;
+ }
+
+ // dump player debug info on stderr
+ if ((flags & GUI_INPUT_DEBUG_PLAYER) && player) {
+ player->printDebugInfo();
+
+ message_view.add_message(CL_Color::green, "...");
+ }
+
+ // toggle fullscreen?
+ if (flags & GUI_INPUT_TOGGLE_FULLSCREEN)
+ graphics->display.toggleFullscreen();
+}
+
+
+/*
+ * Helper function for Camera
+ */
+static PixelDimension value_between (PixelDimension low, PixelDimension value, PixelDimension high) {
+ if (high < low)
+ return (high + low) / 2;
+
+ else if (value < low)
+ return low;
+
+ else if (value > high)
+ return high;
+
+ else
+ return value;
+}
+
+void GameView::draw (Display &display) {
+ CL_GraphicContext *gc = display.get_gc();
+
+ // calculate camera
+ PixelCoordinate camera(0, 0);
+
+ // ...to track our local player
+ if (player != NULL) {
+ // display resolution
+ PixelCoordinate resolution = display.getResolution();
+
+ // try and center the screen on the player
+ PixelCoordinate target = player->getCoordinate() - PixelCoordinate(resolution.x / 2, (resolution.y - 100) / 2);
+
+ // ...but keep the world in view
+ PixelCoordinate max = state.terrain.getDimensions() - resolution + PixelCoordinate(0, 100);
+
+ // ...by limiting the value to 0...max
+ camera = PixelCoordinate(
+ value_between(0, target.x, max.x),
+ value_between(0, target.y, max.y)
+ );
+ }
+
+ // Black background
+ gc->clear(CL_Color::black);
+
+ // Draw the game
+ state.draw(display, camera, flags & GUI_INPUT_DISPLAY_WEAPON);
+
+ // draw info view?
+ if (info_view)
+ info_view->draw(display);
+
+ // draw messages
+ message_view.draw(display);
+}
+
+void GameView::resize (const PixelArea &new_area) {
+ View::resize(new_area);
+
+ // resize subcomponents
+ if (info_view)
+ info_view->resize(getInfoViewArea());
+
+ message_view.resize(getMessageViewArea());
+
+ // log message
+ message_view.add_message(CL_Color::yellow, CL_String::format("[ Resized window to %1 x %2 ]", (int) getWidth(), (int) getHeight()));
+}
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/GameView.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,89 @@
+#ifndef GRAPHICS_GAME_VIEW_HH
+#define GRAPHICS_GAME_VIEW_HH
+
+#include "Drawable.hh"
+#include "PlayerInfoView.hh"
+#include "MessageView.hh"
+#include "Input.hh"
+#include "../GameState.hh"
+
+
+namespace graphics
+{
+
+/**
+ * This is the main in-game view, which is what the player sees when they are playing.
+ *
+ * This enables graphics->input.gui/player
+ */
+class GameView : public View {
+protected:
+ /** The GameState that we're drawing */
+ GameState &state;
+
+ /** The player that we are controlling, if any */
+ LocalPlayer *player;
+
+ /**
+ * The PlayerInfo view is built once we have a player
+ */
+ PlayerInfoView *info_view;
+
+ /**
+ * The message list view
+ */
+ MessageView message_view;
+
+ /**
+ * Input flags
+ */
+ GuiInput flags;
+
+ CL_SlotContainer slots;
+
+public:
+ /**
+ * Constructed once the game is running
+ */
+ GameView (GameState &state, LocalPlayer *player);
+
+ /**
+ * Set a player where none was set before
+ */
+ void setPlayer (LocalPlayer *player);
+
+private:
+ /**
+ * Calculate new area for the info_view based on our own area
+ */
+ PixelArea getInfoViewArea (void) {
+ return PixelArea(0, area.bottom - 100, area.right, area.bottom);
+ }
+
+ /**
+ * Calculate new area for the message view
+ */
+ PixelArea getMessageViewArea (void) {
+ return PixelArea(400, area.bottom - 100, area.right, area.bottom);
+ }
+
+ /**
+ * Handle GUI input
+ */
+ void handleInput (GuiInput flags, TimeMS dt);
+
+public:
+
+ /**
+ * Draw this view onto the given display
+ */
+ virtual void draw (Display &display);
+
+ /**
+ * Resize sub-views
+ */
+ virtual void resize (const PixelArea &new_area);
+};
+
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Graphics.cc Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,26 @@
+
+#include "Graphics.hh"
+
+#include <cassert>
+
+namespace graphics
+{
+
+// initialize the global graphics object
+Graphics *graphics = NULL;
+
+Graphics::Graphics (Engine &engine, CL_ResourceManager &resources, const DisplayConfig &display_config) :
+ engine(engine), display(display_config),
+ // display must be set up before fonts, due to implicit CL_DisplayWindow
+ fonts(resources),
+ // get the InputContext from display
+ input(display.get_ic()->get_keyboard())
+{
+ assert(!graphics);
+
+ // set the global graphics object
+ graphics = this;
+
+}
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Graphics.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,75 @@
+#ifndef GRAPHICS_GRAPHICS_HH
+#define GRAPHICS_GRAPHICS_HH
+
+namespace graphics
+{
+
+class Graphics;
+
+}
+
+#include "../Engine.hh"
+#include "Display.hh"
+#include "FontManager.hh"
+#include "Input.hh"
+#include "GameView.hh"
+
+namespace graphics
+{
+
+/**
+ * Core class that ties everything else together
+ */
+class Graphics {
+public:
+ /**
+ * Our reference to the engine
+ */
+ Engine &engine;
+
+ /**
+ * Our primary display
+ */
+ Display display;
+
+ /**
+ * For loading fonts
+ */
+ FontManager fonts;
+
+ /**
+ * Input handling
+ *
+ * XXX: move Input class into this?
+ */
+ Input input;
+
+ /**
+ * Initialize the graphics subsystem
+ */
+ Graphics (Engine &engine, CL_ResourceManager &resources, const DisplayConfig &display_config);
+
+ /**
+ * Display a new GameView
+ */
+ GameView* displayGameView (GameState &state, LocalPlayer *player) {
+ // allocate a new GameView
+ GameView *view = new GameView(state, player);
+
+ // assign it to the display
+ display.setView(view);
+
+ // return it
+ return view;
+ }
+
+};
+
+/**
+ * The global Graphics instance
+ */
+extern Graphics *graphics;
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Input.cc Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,254 @@
+
+#include "Input.hh"
+#include "../Error.hh"
+#include "../Config.hh"
+
+#include <cassert>
+
+namespace graphics
+{
+
+InputKeymapEntry<PlayerInputBit> INPUT_PLAYER_KEYMAP[] = {
+ { INPUT_AIM_UP, INPUT_FLAG_UNLIMITED, { -CL_KEY_ENTER, CL_KEY_UP } },
+ { INPUT_AIM_DOWN, INPUT_FLAG_UNLIMITED, { -CL_KEY_ENTER, CL_KEY_DOWN } },
+ { INPUT_MOVE_LEFT, INPUT_FLAG_UNLIMITED, { -CL_KEY_ENTER, CL_KEY_LEFT } },
+ { INPUT_MOVE_RIGHT, INPUT_FLAG_UNLIMITED, { -CL_KEY_ENTER, CL_KEY_RIGHT } },
+ { INPUT_JUMP, INPUT_FLAG_SLOWREPEAT, { -CL_KEY_ENTER, CL_KEY_RSHIFT } },
+ { INPUT_DIG, INPUT_FLAG_NOREPEAT, { CL_KEY_LEFT, CL_KEY_RIGHT } },
+ { INPUT_SHOOT, INPUT_FLAG_UNLIMITED, { CL_KEY_RCONTROL, 0 } },
+ { INPUT_CHANGE_PREV, INPUT_FLAG_SLOWREPEAT, { CL_KEY_ENTER, CL_KEY_LEFT } },
+ { INPUT_CHANGE_NEXT, INPUT_FLAG_SLOWREPEAT, { CL_KEY_ENTER, CL_KEY_RIGHT } },
+ { INPUT_ROPE, INPUT_FLAG_NOREPEAT, { CL_KEY_ENTER, CL_KEY_RSHIFT } },
+ { INPUT_UNROPE, INPUT_FLAG_SLOWREPEAT, { -CL_KEY_ENTER, CL_KEY_RSHIFT } },
+ { INPUT_ROPE_UP, INPUT_FLAG_UNLIMITED, { CL_KEY_ENTER, CL_KEY_UP } },
+ { INPUT_ROPE_DOWN, INPUT_FLAG_UNLIMITED, { CL_KEY_ENTER, CL_KEY_DOWN } },
+ { INPUT_SUICIDE, INPUT_FLAG_NOREPEAT, { CL_KEY_LCONTROL, CL_KEY_K } },
+ { INPUT_NONE, 0, { 0, 0 } }
+};
+
+InputKeymapEntry<GuiInputBit> INPUT_GUI_KEYMAP[] = {
+ { GUI_INPUT_QUIT, 0, { CL_KEY_ESCAPE, 0 } },
+ { GUI_INPUT_DISPLAY_WEAPON, 0, { CL_KEY_ENTER, 0 } },
+ { GUI_INPUT_DEBUG_PLAYER, 0, { CL_KEY_I, 0 } },
+ { GUI_INPUT_TOGGLE_FULLSCREEN, INPUT_FLAG_NOREPEAT,{ CL_KEY_LCONTROL, CL_KEY_F } },
+ { GUI_INPUT_NONE, 0, { 0, 0, } }
+};
+
+/*
+ * InputKeyRepeatEntry
+ */
+template <typename BitEnumType>
+InputKeyRepeatEntry<BitEnumType>::InputKeyRepeatEntry (BitEnumType value, TimeMS expire) :
+ value(value), expire(expire)
+{
+
+}
+
+template <typename BitEnumType>
+bool InputKeyRepeatEntry<BitEnumType>::operator< (const struct InputKeyRepeatEntry &other) {
+ return other.expire > expire;
+}
+
+template <typename BitEnumType>
+bool InputKeyRepeatEntry<BitEnumType>::updateExpired (TimeMS dt) {
+ if (expire == 0)
+ return false;
+
+ expire -= dt;
+
+ return (expire <= 0);
+}
+
+/*
+ * InputKeyRepeatQueue
+ */
+template <typename BitEnumType>
+InputKeyRepeatQueue<BitEnumType>::InputKeyRepeatQueue (TimeMS expire) :
+ expire(expire)
+{
+
+}
+
+template <typename BitEnumType>
+void InputKeyRepeatQueue<BitEnumType>::push (BitEnumType bit, bool expire) {
+ list.push_back(InputKeyRepeatEntry<BitEnumType>(bit, expire ? this->expire : 0));
+}
+
+template <typename BitEnumType>
+void InputKeyRepeatQueue<BitEnumType>::forget (BitEnumType bit) {
+ // go through the list, looking for it
+ for (list_iterator it = list.begin(); it != list.end(); it++) {
+ if (it->value == bit) {
+ // found, erase it and return
+ list.erase(it);
+
+ return;
+ }
+ }
+}
+
+template <typename BitEnumType>
+bool InputKeyRepeatQueue<BitEnumType>::find (BitEnumType bit) {
+ for (list_iterator it = list.begin(); it != list.end(); it++) {
+ if (it->value == bit)
+ return true;
+ }
+
+ return false;
+}
+
+template <typename BitEnumType>
+void InputKeyRepeatQueue<BitEnumType>::update (TimeMS dt) {
+ list_iterator it = list.begin();
+
+ // go through each entry, updateExpired and remove if expired
+ while (it != list.end()) {
+ if (it->updateExpired(dt))
+ it = list.erase(it);
+ else
+ it++;
+ }
+}
+
+template <typename BitEnumType>
+void InputKeyRepeatQueue<BitEnumType>::clear (void) {
+ // just clear our list of events
+ list.clear();
+}
+
+/*
+ * InputHandler
+ */
+template <typename BitEnumType, typename BitMaskType>
+InputHandler<BitEnumType, BitMaskType>::InputHandler (CL_InputDevice &keyboard, InputKeymapEntry<BitEnumType> *keymap, TimeMS keyrepeat_expire) :
+ keyboard(keyboard),
+ keymap(keymap),
+ value(0),
+ prev_value(0),
+ dt(0),
+ queue(keyrepeat_expire),
+ _enabled(false)
+{
+
+}
+
+template <typename BitEnumType, typename BitMaskType>
+bool InputHandler<BitEnumType, BitMaskType>::checkKeycode (int keycode) {
+ if (keycode > 0)
+ return keyboard.get_keycode(keycode);
+
+ else if (keycode < 0)
+ return !keyboard.get_keycode(-keycode);
+
+ else // == 0
+ return true;
+}
+
+template <typename BitEnumType, typename BitMaskType>
+void InputHandler<BitEnumType, BitMaskType>::update (TimeMS dt) {
+ // ignore if not enabled
+ if (!_enabled)
+ return;
+
+ // all bits that are held down, even those ignored
+ BitMaskType raw_value = 0, this_value = 0;
+
+ // update the key-repeat queue
+ queue.update(dt);
+
+ // then go through the keymap
+ for (InputKeymapEntry<BitEnumType> *e = keymap; e->input != 0; e++) {
+ // check if we've got the correct keycodes
+ if (checkKeycode(e->keycodes[0]) && checkKeycode(e->keycodes[1])) {
+ // set raw_value
+ raw_value |= e->input;
+
+ if (e->flags & INPUT_FLAG_SLOWREPEAT) {
+ // repeat, but slowly
+ if (!(prev_value & e->input)) {
+ // we've released the key earlier, move it to the back of the queue
+ queue.forget(e->input);
+ queue.push(e->input);
+
+ } else if (queue.find(e->input)) {
+ // it's still in the queue, so ignore, but set it in ignore_value
+ continue;
+
+ } else {
+ // ok, but add it to the queue
+ queue.push(e->input);
+ }
+
+ } else if (e->flags & INPUT_FLAG_NOREPEAT) {
+ // do not repeat at all
+ if (prev_value & e->input) {
+ // ignore repeats
+ continue;
+ }
+ }
+
+ // set bit in value mask
+ this_value |= e->input;
+ }
+ }
+
+ // signal unless value was and remains zero
+ if (this_value || prev_value) {
+ // trigger signal
+ _sig_input(this_value, dt);
+ }
+
+ // update prev_value, also adding ignored values
+ prev_value = raw_value;
+
+ // update our collective value + dt for use with readValue
+ // XXX: remove this functionality?
+ value |= this_value;
+ this->dt += dt;
+}
+
+template <typename BitEnumType, typename BitMaskType>
+void InputHandler<BitEnumType, BitMaskType>::readValue (BitMaskType &mask, TimeMS &dt) {
+ // throw exception if disabled
+ if (!_enabled)
+ throw Error("InputHandler is disabled");
+
+ // copy to args
+ mask = this->value;
+ dt = this->dt;
+
+ this->value = 0;
+ this->dt = 0;
+}
+
+/**
+ * Input
+ */
+Input::Input (CL_InputDevice &keyboard) :
+ keyboard(keyboard),
+ update_timer(INPUT_POLL_INTERVAL),
+ player(keyboard, INPUT_PLAYER_KEYMAP, INPUT_REPEAT_DELAY),
+ gui(keyboard, INPUT_GUI_KEYMAP, INPUT_REPEAT_DELAY)
+{
+ // connect timer
+ slots.connect(update_timer.sig_tick(), &player, &InputHandler<PlayerInputBit, PlayerInput>::update);
+ slots.connect(update_timer.sig_tick(), &gui, &InputHandler<GuiInputBit, GuiInput>::update);
+
+ // enable timer
+ update_timer.start();
+}
+
+void Input::readPlayerInput (PlayerInput &mask, TimeMS &dt) {
+ player.readValue(mask, dt);
+}
+
+GuiInput Input::readGuiInput (void) {
+ GuiInput mask;
+ TimeMS dt;
+
+ gui.readValue(mask, dt);
+
+ return mask;
+}
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Input.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,348 @@
+#ifndef GRAPHICS_INPUT_HH
+#define GRAPHICS_INPUT_HH
+
+#include "../Input.hh"
+#include "../Timer.hh"
+#include "../Types.hh"
+
+#include <ClanLib/signals.h>
+#include <ClanLib/Display/input_device.h>
+#include <ClanLib/Display/keys.h>
+
+#include <list>
+
+namespace graphics
+{
+
+/**
+ * Flags to control input behaviour
+ */
+enum InputFlagBits {
+ /** Default */
+
+ /**
+ * The bit is not limited, i.e. it is set every time if it's present
+ */
+ INPUT_FLAG_UNLIMITED = 0x0000,
+
+ /**
+ * The bit is repeat-limited using INPUT_REPEAT_DELAY
+ */
+ INPUT_FLAG_SLOWREPEAT = 0x0001,
+
+ /**
+ * The bit is repeat-limited using an infinite delay, i.e. you must release the key to trigger it again
+ */
+ INPUT_FLAG_NOREPEAT = 0x0002,
+};
+
+
+/**
+ * The bits used in the GuiInput bitmask, each represents something handled locally by Graphics.
+ */
+enum GuiInputBit {
+ GUI_INPUT_NONE = 0x0000,
+
+ GUI_INPUT_QUIT = 0x0001,
+ GUI_INPUT_DISPLAY_WEAPON = 0x0002,
+ GUI_INPUT_DEBUG_PLAYER = 0x0004,
+
+ GUI_INPUT_TOGGLE_FULLSCREEN = 0x0008,
+};
+
+/**
+ * Bitmask of InputFlagBits
+ */
+typedef uint8_t InputFlags;
+
+/**
+ * Bitmask for GuiInputBits
+ *
+ * @see GuiInputBit
+ */
+typedef uint16_t GuiInput;
+
+/**
+ * Keymap definition struct
+ */
+template <typename BitEnumType> struct InputKeymapEntry {
+ /**
+ * The input bit to set if present
+ */
+ BitEnumType input;
+
+ /**
+ * Flags to use
+ *
+ * @see InputFlagBits
+ */
+ InputFlags flags;
+
+ /**
+ * Up to two keycodes to check
+ */
+ int keycodes[2];
+};
+
+
+/**
+ * A InputKeyRepeatQueue entry, this contains the input bit value itself, and then the remaining expire time
+ */
+template <typename BitEnumType> struct InputKeyRepeatEntry {
+ BitEnumType value;
+
+ /**
+ * The remaining expire time. If this is zero, it never expires
+ */
+ TimeMS expire;
+
+ public:
+ InputKeyRepeatEntry (BitEnumType value, TimeMS expire);
+
+ /**
+ * Since priority_queue always gives the greatest item, the one with the longest expire is the least item
+ */
+ bool operator< (const struct InputKeyRepeatEntry &other);
+
+ /**
+ * Decrements expire, returning true if it has now expired, false otherwise. Always returns false if expire is
+ * zero.
+ */
+ bool updateExpired (TimeMS dt);
+};
+
+/**
+ * A InputKeyRepeatQueue maintains a list of InputKeyRepeatEntry's, lets you add new input values, find old ones,
+ * and update the list
+ */
+template <typename BitEnumType> class InputKeyRepeatQueue {
+ private:
+ TimeMS expire;
+
+ typedef InputKeyRepeatEntry<BitEnumType> entry_type;
+
+ std::list<entry_type> list;
+
+ typedef typename std::list<entry_type>::iterator list_iterator;
+
+ public:
+ /**
+ * Constructs this queue to contain entries with the given expiry time
+ */
+ InputKeyRepeatQueue (TimeMS expire);
+
+ /**
+ * Push a new input bit onto the queue.
+ *
+ * If expire is true, the bit will automatically expire after our expire time, otherwise, it iwll never expire
+ * until forget()'d
+ */
+ void push (BitEnumType bit, bool expire = true);
+
+ /**
+ * Remove any entry for the given bit
+ */
+ void forget (BitEnumType bit);
+
+ /**
+ * Checks if the given input is in the queue
+ */
+ bool find (BitEnumType bit);
+
+ /**
+ * Updates the list, removing expired items
+ */
+ void update (TimeMS dt);
+
+ /**
+ * Clear the queue completely
+ */
+ void clear (void);
+};
+
+/**
+ * An InputHandler uses an InputKeymapEntry to maintain a BitMaskType of current inputs
+ */
+template <typename BitEnumType, typename BitMaskType> class InputHandler {
+ private:
+ /**
+ * The keyboard that we read input from
+ */
+ CL_InputDevice &keyboard;
+
+ /**
+ * The keymap that we use
+ */
+ InputKeymapEntry<BitEnumType> *keymap;
+
+ /**
+ * The current bitmask value
+ */
+ BitMaskType value;
+
+ /**
+ * The previous value, used to detect key-up. This also includes keys that were filtered out
+ */
+ BitMaskType prev_value;
+
+ /**
+ * How long the bitmask was held...
+ */
+ TimeMS dt;
+
+ /**
+ * The KeyRepeatQueue
+ */
+ InputKeyRepeatQueue<BitEnumType> queue;
+
+ /**
+ * Are we enabled or not?
+ */
+ bool _enabled;
+
+ /**
+ * The keyevent signal
+ */
+ CL_Signal_v2<BitMaskType, TimeMS> _sig_input;
+
+ public:
+ /**
+ * Constructs the InputHandler using the given keyboard, keymap and key-repeat expire time.
+ *
+ * The InputHandler is initially disabled, and must be enabled using enable() for use.
+ */
+ InputHandler (CL_InputDevice &keyboard, InputKeymapEntry<BitEnumType> *keymap, TimeMS keyrepeat_expire);
+
+ private:
+ /**
+ * Returns true if the keycode is valid, false if not.
+ *
+ * A positive keycode requires that the keycode be active, a negative keycode that the keycode be inactive,
+ * and a zero keycode always returns true.
+ *
+ * @param keycode A positive keycode to check that it's set, negative keycode to check that it's not set, or zero
+ * @returns bool true if positive+set/negavtive+notset/zero, false otherwise
+ */
+ bool checkKeycode (int keycode);
+
+ public:
+ /**
+ * Updates the keyrepeat queue
+ */
+ void update (TimeMS dt);
+
+ /**
+ * Reads the current input mask value and length into mask and dt, and reset ours to zero.
+ *
+ * It is an error to attempt to read input while disabled.
+ *
+ * @param mask our BitMaskType value is returned using this
+ * @param dt how long the input was held for
+ */
+ void readValue (BitMaskType &mask, TimeMS &dt);
+
+ /**
+ * Enables this input handler, collecting bits in value
+ */
+ void enable (void);
+
+ /**
+ * Disables this input handler, zeroing any state, so that enable() works cleanly
+ */
+ void disable (void);
+
+ /**
+ * Current enable/disable state
+ */
+ bool enabled (void) const { return _enabled; }
+
+ /**
+ * This signal is triggered whenever there is nonzero input, or when the input goes to zero
+ */
+ CL_Signal_v2<BitMaskType, TimeMS>& sig_input (void) { return _sig_input; }
+};
+
+/**
+ * Handles reading input from a keyboard and mapping it to PlayerInput/GuiInput bitmasks
+ */
+class Input {
+ protected:
+ /**
+ * The keyboard device that we use
+ */
+ CL_InputDevice &keyboard;
+
+ /**
+ * Our update timer
+ */
+ Timer update_timer;
+
+ CL_SlotContainer slots;
+
+ public:
+ /**
+ * Our PlayerInput
+ */
+ InputHandler<PlayerInputBit, PlayerInput> player;
+
+ /**
+ * Our GuiInput
+ */
+ InputHandler<GuiInputBit, GuiInput> gui;
+
+ public:
+ /**
+ * Build the input handler using the given keyboard and the default keymaps
+ */
+ Input (CL_InputDevice &keyboard);
+
+ public:
+ /**
+ * Reads the current PlayerInput value via mask, and the length of the input via dt
+ */
+ void readPlayerInput (PlayerInput &mask, TimeMS &dt);
+
+ /**
+ * Reads the current GuiInput mask and returns it
+ */
+ GuiInput readGuiInput (void);
+};
+
+}
+
+
+
+/*
+ * Public template class method definitions
+ */
+#include <cassert>
+
+namespace graphics
+{
+
+template <typename BitEnumType, typename BitMaskType>
+void InputHandler<BitEnumType, BitMaskType>::enable (void) {
+ // sanity-check
+ assert(!_enabled);
+
+ // update state
+ _enabled = true;
+}
+
+template <typename BitEnumType, typename BitMaskType>
+void InputHandler<BitEnumType, BitMaskType>::disable (void) {
+ // sanity-check
+ assert(_enabled);
+
+ // update state
+ value = prev_value = 0;
+ _enabled = false;
+
+ // and clear keyrepeat list
+ queue.clear();
+}
+
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/MessageView.cc Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,59 @@
+
+#include "MessageView.hh"
+#include "Graphics.hh"
+
+namespace graphics
+{
+
+MessageView::MessageView (const PixelArea &area) :
+ View(area), messages()
+{
+
+}
+
+void MessageView::add_message (CL_Color color, std::string message) {
+ Message msg (color, message);
+
+ messages.push_back(msg);
+}
+
+void MessageView::draw (Display &display) {
+ // get font
+ CL_Font &font = graphics->fonts.getSimpleFont();
+
+ // remember color
+ CL_Color font_color = font.get_color();
+
+ // maximum width
+ CL_Size max_size = CL_Size(area.right - area.left, 0);
+
+ // starting point for drawing
+ PixelDimension offset_prev = area.bottom;
+
+ // render messages, bottom up
+ for (std::vector<Message>::reverse_iterator it = messages.rbegin(); it != messages.rend(); it++) {
+ // set message color
+ font.set_color(it->color);
+
+ // calculate height
+ PixelDimension height = font.get_height(it->message, max_size) + MESSAGE_VIEW_LINE_OFFSET;
+
+ // new draw_point
+ PixelDimension offset_this = offset_prev - height;
+
+ // break if it doesn't fit anymore
+ if (offset_this < area.top)
+ break;
+
+ // draw text
+ font.draw(CL_Rect(area.left, offset_this, area.right, offset_prev), it->message, display.get_gc());
+
+ // advance offset
+ offset_prev = offset_this;
+ }
+
+ // restore font color
+ font.set_color(font_color);
+}
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/MessageView.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,48 @@
+#ifndef GRAPHICS_MESSAGE_VIEW_HH
+#define GRAPHICS_MESSAGE_VIEW_HH
+
+#include "View.hh"
+
+#include <ClanLib/display.h>
+#include <string>
+#include <vector>
+
+namespace graphics
+{
+
+/**
+ * Offset between consecutive lines
+ */
+const PixelDimension MESSAGE_VIEW_LINE_OFFSET = 5;
+
+struct Message {
+ CL_Color color;
+ std::string message;
+
+ Message (CL_Color color, std::string message) : color(color), message(message) { }
+};
+
+class MessageView : public View {
+protected:
+ std::vector<Message> messages;
+
+public:
+ /**
+ * Define the area where messages are drawn
+ */
+ MessageView (const PixelArea &area);
+
+ /**
+ * Add a message to the list of messages displayed
+ */
+ void add_message (CL_Color color, std::string message);
+
+ /**
+ * Draw as many messages as fits
+ */
+ virtual void draw (Display &display);
+};
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/PlayerInfoView.cc Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,125 @@
+
+#include "PlayerInfoView.hh"
+#include "Graphics.hh"
+
+#include <sstream>
+
+namespace graphics
+{
+
+void PlayerInfoView::draw (Display &display) {
+ CL_GraphicContext *gc = display.get_gc();
+ CL_Font font = graphics->fonts.getSimpleFont();
+
+ int bar_length = 3;
+
+ // draw status info at bottom of display
+ gc->fill_rect(
+ CL_Rect(area.left, area.top, area.right, area.bottom),
+ CL_Gradient(
+ CL_Color(0, 0, 0),
+ CL_Color(50, 50, 50),
+ CL_Color(50, 50, 50, 150),
+ CL_Color(100, 100, 100, 200)
+ )
+ );
+
+ // Health
+ double health_percent = player->getHealthPercent();
+
+ gc->draw_rect(
+ CL_Rect(
+ area.left + 9,
+ area.top + 9,
+ area.left + 11 + 100 * bar_length,
+ area.top + 31
+ ),
+ CL_Color(150, 150, 150)
+ );
+
+ gc->fill_rect(
+ CL_Rect(
+ area.left + 10,
+ area.top + 10,
+ area.left + 10 + (int) (health_percent * bar_length),
+ area.top + 30
+ ),
+ CL_Gradient(
+ CL_Color(200, 0, 0),
+ CL_Color(200 - (int)(health_percent * 2), (int)(health_percent * 2), 0),
+ CL_Color(200, 0, 0),
+ CL_Color(200 - (int)(health_percent * 2), (int)(health_percent * 2), 0)
+ )
+ );
+
+ // stats - kills
+ std::stringstream sskills;
+ sskills << "Kills: " << player->getKills();
+ font.draw(
+ area.left + 20 + 100 * bar_length,
+ area.top + 10,
+ sskills.str(),
+ gc
+ );
+
+ // stats - deaths
+ std::stringstream ssdeaths;
+ ssdeaths << "Deaths: " << player->getDeaths();
+ font.draw(
+ area.left + 20 + 100 * bar_length,
+ area.top + 30,
+ ssdeaths.str(),
+ gc
+ );
+
+ // stats - ratio
+ std::stringstream ssratio;
+ ssratio << "Ratio: " << (player->getKills() + 1) / (player->getDeaths() + 1);
+ font.draw(
+ area.left + 20 + 100 * bar_length,
+ area.top + 50,
+ ssratio.str(),
+ gc
+ );
+
+
+ // Weapon clip / reloading
+ gc->draw_rect(
+ CL_Rect(
+ area.left + 9,
+ area.top + 69,
+ area.left + 11 + 100 * bar_length,
+ area.top + 91
+ ),
+ CL_Color(150, 150, 150)
+ );
+
+ gc->fill_rect(
+ CL_Rect(
+ area.left + 10,
+ area.top + 70,
+ area.left + 10 + (100 - (int) (
+ player->getCurrentWeapon()->getReloadTimer() * 100 / player->getCurrentWeapon()->getReloadTime()
+ )) * bar_length,
+ area.top + 90
+ ),
+ CL_Gradient(
+ CL_Color(100, 100, 0),
+ CL_Color(100, 100, 0),
+ CL_Color(100, 100, 0),
+ CL_Color(100, 100, 100)
+ )
+ );
+
+ // current weapon name
+ font.draw(
+ area.left + 20 + 100 * bar_length,
+ area.top + 70,
+ player->getCurrentWeapon()->getName(),
+ gc
+ );
+}
+
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/PlayerInfoView.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,37 @@
+#ifndef GRAPHICS_PLAYER_INFO_VIEW_HH
+#define GRAPHICS_PLAYER_INFO_VIEW_HH
+
+#include "View.hh"
+#include "../Player.hh"
+
+namespace graphics
+{
+
+class PlayerInfoView : public View {
+private:
+ /**
+ * The player whose info we are drawing
+ *
+ * XXX: should this be LocalPlayer or is Player good?
+ */
+ Player *player;
+
+public:
+ /**
+ * Set initial view area and player
+ */
+ PlayerInfoView (const PixelArea &area, Player *player) :
+ View(area), player(player)
+ {
+
+ }
+
+ /**
+ * Draw the player info onto the given display
+ */
+ virtual void draw (Display &display);
+};
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/View.hh Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,67 @@
+#ifndef GRAPHICS_VIEW_HH
+#define GRAPHICS_VIEW_HH
+
+namespace graphics
+{
+
+class View;
+
+}
+
+#include "Drawable.hh"
+#include "Display.hh"
+#include "../Types.hh"
+
+namespace graphics
+{
+
+/**
+ * A view is some area of the display that displays something
+ */
+class View /* : public Drawable */ {
+protected:
+ /**
+ * The area of the screen that is ours to draw on
+ */
+ PixelArea area;
+
+public:
+ /**
+ * Set the initial area that is drawn into
+ */
+ View (const PixelArea &area) :
+ area(area)
+ {
+
+ }
+
+ /**
+ * Draw into the view area
+ */
+ virtual void draw (Display &display) = 0;
+
+ /**
+ * Update the view area
+ */
+ virtual void resize (const PixelArea &new_area) {
+ this->area = new_area;
+ }
+
+ /**
+ * Get current width
+ */
+ PixelDimension getWidth (void) const {
+ return area.right - area.left;
+ }
+
+ /**
+ * Get current height
+ */
+ PixelDimension getHeight (void) const {
+ return area.bottom - area.top;
+ }
+};
+
+}
+
+#endif
--- a/src/GraphicsPointer.hh Wed Jan 21 00:21:42 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-#ifndef GRAPHICS_POINTER_HH
-#define GRAPHICS_POINTER_HH
-
-/*
- * Break our #include-loop dependancy
- */
-class Graphics;
-
-#endif
--- a/src/Input.cc Wed Jan 21 00:21:42 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-
-#include "Input.hh"
-#include "Engine.hh"
-#include "Config.hh"
-
-InputKeymapEntry<PlayerInputBit> INPUT_PLAYER_KEYMAP[] = {
- { INPUT_AIM_UP, INPUT_FLAG_UNLIMITED, { -CL_KEY_ENTER, CL_KEY_UP } },
- { INPUT_AIM_DOWN, INPUT_FLAG_UNLIMITED, { -CL_KEY_ENTER, CL_KEY_DOWN } },
- { INPUT_MOVE_LEFT, INPUT_FLAG_UNLIMITED, { -CL_KEY_ENTER, CL_KEY_LEFT } },
- { INPUT_MOVE_RIGHT, INPUT_FLAG_UNLIMITED, { -CL_KEY_ENTER, CL_KEY_RIGHT } },
- { INPUT_JUMP, INPUT_FLAG_SLOWREPEAT, { -CL_KEY_ENTER, CL_KEY_RSHIFT } },
- { INPUT_DIG, INPUT_FLAG_NOREPEAT, { CL_KEY_LEFT, CL_KEY_RIGHT } },
- { INPUT_SHOOT, INPUT_FLAG_UNLIMITED, { CL_KEY_RCONTROL, 0 } },
- { INPUT_CHANGE_PREV, INPUT_FLAG_SLOWREPEAT, { CL_KEY_ENTER, CL_KEY_LEFT } },
- { INPUT_CHANGE_NEXT, INPUT_FLAG_SLOWREPEAT, { CL_KEY_ENTER, CL_KEY_RIGHT } },
- { INPUT_ROPE, INPUT_FLAG_NOREPEAT, { CL_KEY_ENTER, CL_KEY_RSHIFT } },
- { INPUT_UNROPE, INPUT_FLAG_SLOWREPEAT, { -CL_KEY_ENTER, CL_KEY_RSHIFT } },
- { INPUT_ROPE_UP, INPUT_FLAG_UNLIMITED, { CL_KEY_ENTER, CL_KEY_UP } },
- { INPUT_ROPE_DOWN, INPUT_FLAG_UNLIMITED, { CL_KEY_ENTER, CL_KEY_DOWN } },
- { INPUT_SUICIDE, INPUT_FLAG_NOREPEAT, { CL_KEY_LCONTROL, CL_KEY_K } },
- { INPUT_NONE, 0, { 0, 0 } }
-};
-
-InputKeymapEntry<GuiInputBit> INPUT_GUI_KEYMAP[] = {
- { GUI_INPUT_QUIT, 0, { CL_KEY_ESCAPE, 0 } },
- { GUI_INPUT_DISPLAY_WEAPON, 0, { CL_KEY_ENTER, 0 } },
- { GUI_INPUT_DEBUG_PLAYER, 0, { CL_KEY_I, 0 } },
- { GUI_INPUT_TOGGLE_FULLSCREEN, INPUT_FLAG_NOREPEAT,{ CL_KEY_LCONTROL, CL_KEY_F } },
- { GUI_INPUT_NONE, 0, { 0, 0, } }
-};
-
-/*
- * InputKeyRepeatEntry
- */
-template <typename BitEnumType>
-InputKeyRepeatEntry<BitEnumType>::InputKeyRepeatEntry (BitEnumType value, TimeMS expire) :
- value(value), expire(expire)
-{
-
-}
-
-template <typename BitEnumType>
-bool InputKeyRepeatEntry<BitEnumType>::operator< (const struct InputKeyRepeatEntry &other) {
- return other.expire > expire;
-}
-
-template <typename BitEnumType>
-bool InputKeyRepeatEntry<BitEnumType>::updateExpired (TimeMS dt) {
- if (expire == 0)
- return false;
-
- expire -= dt;
-
- return (expire <= 0);
-}
-
-/*
- * InputKeyRepeatQueue
- */
-template <typename BitEnumType>
-InputKeyRepeatQueue<BitEnumType>::InputKeyRepeatQueue (TimeMS expire) :
- expire(expire)
-{
-
-}
-
-template <typename BitEnumType>
-void InputKeyRepeatQueue<BitEnumType>::push (BitEnumType bit, bool expire) {
- list.push_back(InputKeyRepeatEntry<BitEnumType>(bit, expire ? this->expire : 0));
-}
-
-template <typename BitEnumType>
-void InputKeyRepeatQueue<BitEnumType>::forget (BitEnumType bit) {
- // go through the list, looking for it
- for (list_iterator it = list.begin(); it != list.end(); it++) {
- if (it->value == bit) {
- // found, erase it and return
- list.erase(it);
-
- return;
- }
- }
-}
-
-template <typename BitEnumType>
-bool InputKeyRepeatQueue<BitEnumType>::find (BitEnumType bit) {
- for (list_iterator it = list.begin(); it != list.end(); it++) {
- if (it->value == bit)
- return true;
- }
-
- return false;
-}
-
-template <typename BitEnumType>
-void InputKeyRepeatQueue<BitEnumType>::update (TimeMS dt) {
- list_iterator it = list.begin();
-
- // go through each entry, updateExpired and remove if expired
- while (it != list.end()) {
- if (it->updateExpired(dt))
- it = list.erase(it);
- else
- it++;
- }
-}
-
-/*
- * InputHandler
- */
-template <typename BitEnumType, typename BitMaskType>
-InputHandler<BitEnumType, BitMaskType>::InputHandler (CL_InputDevice &keyboard, InputKeymapEntry<BitEnumType> *keymap, TimeMS keyrepeat_expire) :
- keyboard(keyboard),
- keymap(keymap),
- value(0),
- prev_value(0),
- dt(0),
- queue(keyrepeat_expire)
-{
-
-}
-
-template <typename BitEnumType, typename BitMaskType>
-bool InputHandler<BitEnumType, BitMaskType>::checkKeycode (int keycode) {
- if (keycode > 0)
- return keyboard.get_keycode(keycode);
-
- else if (keycode < 0)
- return !keyboard.get_keycode(-keycode);
-
- else // == 0
- return true;
-}
-
-template <typename BitEnumType, typename BitMaskType>
-void InputHandler<BitEnumType, BitMaskType>::readValue (BitMaskType &mask, TimeMS &dt) {
- // copy to args
- mask = this->value;
- dt = this->dt;
-
- this->value = 0;
- this->dt = 0;
-}
-
-template <typename BitEnumType, typename BitMaskType>
-void InputHandler<BitEnumType, BitMaskType>::update (TimeMS dt) {
- // all bits that are held down, even those ignored
- BitMaskType raw_value = 0;
-
- // update the key-repeat queue
- queue.update(dt);
-
- // then go through the keymap
- for (InputKeymapEntry<BitEnumType> *e = keymap; e->input != 0; e++) {
- // check if we've got the correct keycodes
- if (checkKeycode(e->keycodes[0]) && checkKeycode(e->keycodes[1])) {
- // set raw_value
- raw_value |= e->input;
-
- if (e->flags & INPUT_FLAG_SLOWREPEAT) {
- // repeat, but slowly
- if (!(prev_value & e->input)) {
- // we've released the key earlier, move it to the back of the queue
- queue.forget(e->input);
- queue.push(e->input);
-
- } else if (queue.find(e->input)) {
- // it's still in the queue, so ignore, but set it in ignore_value
- continue;
-
- } else {
- // ok, but add it to the queue
- queue.push(e->input);
- }
-
- } else if (e->flags & INPUT_FLAG_NOREPEAT) {
- // do not repeat at all
- if (prev_value & e->input) {
- // ignore repeats
- continue;
- }
- }
-
- // set bit in masks
- this->value |= e->input;
- }
- }
-
- // update prev_value, also adding ignored values
- prev_value = raw_value;
-
- // then increment our dt
- this->dt += dt;
-}
-
-/**
- * Input
- */
-Input::Input (CL_InputDevice &keyboard) :
- keyboard(keyboard),
- update_timer(INPUT_POLL_INTERVAL),
- player(keyboard, INPUT_PLAYER_KEYMAP, INPUT_REPEAT_DELAY),
- gui(keyboard, INPUT_GUI_KEYMAP, INPUT_REPEAT_DELAY)
-{
- // connect timer
- slots.connect(update_timer.sig_tick(), &player, &InputHandler<PlayerInputBit, PlayerInput>::update);
- slots.connect(update_timer.sig_tick(), &gui, &InputHandler<GuiInputBit, GuiInput>::update);
-
- // enable timer
- update_timer.start();
-}
-
-void Input::readPlayerInput (PlayerInput &mask, TimeMS &dt) {
- player.readValue(mask, dt);
-}
-
-GuiInput Input::readGuiInput (void) {
- GuiInput mask;
- TimeMS dt;
-
- gui.readValue(mask, dt);
-
- return mask;
-}
-
--- a/src/Input.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Input.hh Thu Jan 22 03:02:43 2009 +0200
@@ -1,36 +1,11 @@
#ifndef INPUT_HH
#define INPUT_HH
-#include "Timer.hh"
-#include "Types.hh"
-
-#include <ClanLib/Display/input_device.h>
-#include <ClanLib/Display/keys.h>
-#include <queue>
-
-// const TimeMS INPUT_INTERVAL_MS = 20;
-
/**
- * Flags to control input behaviour
+ * Core game input events, used to control LocalPlayer
*/
-enum InputFlagBits {
- /** Default */
- /**
- * The bit is not limited, i.e. it is set every time if it's present
- */
- INPUT_FLAG_UNLIMITED = 0x0000,
-
- /**
- * The bit is repeat-limited using INPUT_REPEAT_DELAY
- */
- INPUT_FLAG_SLOWREPEAT = 0x0001,
-
- /**
- * The bit is repeat-limited using an infinite delay, i.e. you must release the key to trigger it again
- */
- INPUT_FLAG_NOREPEAT = 0x0002,
-};
+#include "Types.hh"
/**
* The bits used in the PlayerInput bitmask, each represents a separate action handled by LocalPlayer::handleInput.
@@ -60,242 +35,10 @@
};
/**
- * The bits used in the GuiInput bitmask, each represents something handled locally by Graphics.
- */
-enum GuiInputBit {
- GUI_INPUT_NONE = 0x0000,
-
- GUI_INPUT_QUIT = 0x0001,
- GUI_INPUT_DISPLAY_WEAPON = 0x0002,
- GUI_INPUT_DEBUG_PLAYER = 0x0004,
-
- GUI_INPUT_TOGGLE_FULLSCREEN = 0x0008,
-};
-
-/**
- * Bitmask of InputFlagBits
- */
-typedef uint8_t InputFlags;
-
-/**
* Bitmask of PlayerInputBits
*
* @see PlayerInputBit
*/
typedef uint16_t PlayerInput;
-/**
- * Bitmask for GuiInputBits
- *
- * @see GuiInputBit
- */
-typedef uint16_t GuiInput;
-
-/**
- * Keymap definition struct
- */
-template <typename BitEnumType> struct InputKeymapEntry {
- /**
- * The input bit to set if present
- */
- BitEnumType input;
-
- /**
- * Flags to use
- *
- * @see InputFlagBits
- */
- InputFlags flags;
-
- /**
- * Up to two keycodes to check
- */
- int keycodes[2];
-};
-
-
-/**
- * A InputKeyRepeatQueue entry, this contains the input bit value itself, and then the remaining expire time
- */
-template <typename BitEnumType> struct InputKeyRepeatEntry {
- BitEnumType value;
-
- /**
- * The remaining expire time. If this is zero, it never expires
- */
- TimeMS expire;
-
- public:
- InputKeyRepeatEntry (BitEnumType value, TimeMS expire);
-
- /**
- * Since priority_queue always gives the greatest item, the one with the longest expire is the least item
- */
- bool operator< (const struct InputKeyRepeatEntry &other);
-
- /**
- * Decrements expire, returning true if it has now expired, false otherwise. Always returns false if expire is
- * zero.
- */
- bool updateExpired (TimeMS dt);
-};
-
-/**
- * A InputKeyRepeatQueue maintains a list of InputKeyRepeatEntry's, lets you add new input values, find old ones,
- * and update the list
- */
-template <typename BitEnumType> class InputKeyRepeatQueue {
- private:
- TimeMS expire;
-
- typedef InputKeyRepeatEntry<BitEnumType> entry_type;
-
- std::list<entry_type> list;
-
- typedef typename std::list<entry_type>::iterator list_iterator;
-
- public:
- /**
- * Constructs this queue to contain entries with the given expiry time
- */
- InputKeyRepeatQueue (TimeMS expire);
-
- /**
- * Push a new input bit onto the queue.
- *
- * If expire is true, the bit will automatically expire after our expire time, otherwise, it iwll never expire
- * until forget()'d
- */
- void push (BitEnumType bit, bool expire = true);
-
- /**
- * Remove any entry for the given bit
- */
- void forget (BitEnumType bit);
-
- /**
- * Checks if the given input is in the queue
- */
- bool find (BitEnumType bit);
-
- /**
- * Updates the list, removing expired items
- */
- void update (TimeMS dt);
-};
-
-/**
- * An InputHandler uses an InputKeymapEntry to maintain a BitMaskType of current inputs
- */
-template <typename BitEnumType, typename BitMaskType> class InputHandler {
- private:
- /**
- * The keyboard that we read input from
- */
- CL_InputDevice &keyboard;
-
- /**
- * The keymap that we use
- */
- InputKeymapEntry<BitEnumType> *keymap;
-
- /**
- * The current bitmask value
- */
- BitMaskType value;
-
- /**
- * The previous value, used to detect key-up. This also includes keys that were filtered out
- */
- BitMaskType prev_value;
-
- /**
- * How long the bitmask was held...
- */
- TimeMS dt;
-
- /**
- * The KeyRepeatQueue
- */
- InputKeyRepeatQueue<BitEnumType> queue;
-
- public:
- /**
- * Constructs the InputHandler using the given keyboard, keymap and key-repeat expire time
- */
- InputHandler (CL_InputDevice &keyboard, InputKeymapEntry<BitEnumType> *keymap, TimeMS keyrepeat_expire);
-
- private:
- /**
- * Returns true if the keycode is valid, false if not.
- *
- * A positive keycode requires that the keycode be active, a negative keycode that the keycode be inactive,
- * and a zero keycode always returns true.
- *
- * @param keycode A positive keycode to check that it's set, negative keycode to check that it's not set, or zero
- * @returns bool true if positive+set/negavtive+notset/zero, false otherwise
- */
- bool checkKeycode (int keycode);
-
- public:
- /**
- * Updates the keyrepeat queue
- */
- void update (TimeMS dt);
-
- /**
- * Reads the current input mask value and length into mask and dt, and reset ours to zero
- *
- * @param mask our BitMaskType value is returned using this
- * @param dt how long the input was held for
- */
- void readValue (BitMaskType &mask, TimeMS &dt);
-
-};
-
-/**
- * Handles reading input from a keyboard and mapping it to PlayerInput/GuiInput bitmasks
- */
-class Input {
- protected:
- /**
- * The keyboard device that we use
- */
- CL_InputDevice &keyboard;
-
- /**
- * Our update timer
- */
- Timer update_timer;
-
- CL_SlotContainer slots;
-
- /**
- * Our PlayerInput
- */
- InputHandler<PlayerInputBit, PlayerInput> player;
-
- /**
- * Our GuiInput
- */
- InputHandler<GuiInputBit, GuiInput> gui;
-
- public:
- /**
- * Build the input handler using the given keyboard and the default keymaps
- */
- Input (CL_InputDevice &keyboard);
-
- public:
- /**
- * Reads the current PlayerInput value via mask, and the length of the input via dt
- */
- void readPlayerInput (PlayerInput &mask, TimeMS &dt);
-
- /**
- * Reads the current GuiInput mask and returns it
- */
- GuiInput readGuiInput (void);
-};
-
#endif
--- a/src/Logger.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Logger.cc Thu Jan 22 03:02:43 2009 +0200
@@ -1,8 +1,8 @@
#include "Logger.hh"
-Logger::Logger (std::ostream &stream, enum LogLevel level, const char *module) :
- stream(stream), level(level), module(module)
+Logger::Logger (std::ostream &stream, LogLevel level, const char *module, LogLevel max_level) :
+ stream(stream), show(level <= max_level)
{
const char *l;
@@ -14,33 +14,13 @@
case DEBUG: l = "DEBUG"; break;
default: l = "???"; break;
};
-
-#ifndef NDEBUG
- stream << l << " [" << module << "] ";
-#endif
+
+ if (show)
+ stream << l << " [" << module << "] ";
}
Logger::~Logger (void) {
-#ifndef NDEBUG
- stream << std::endl;
-#endif
-}
-
-std::ostream& operator<< (std::ostream &s, CL_NetComputer &c) {
- s << "[" << c.get_address().get_address() << ":" << c.get_address().get_port() << "]";
-
- return s;
+ if (show)
+ stream << std::endl;
}
-std::ostream& operator<< (std::ostream &s, CL_NetObject_Server &obj) {
- s << "%" << obj.get_obj_id();
-
- return s;
-}
-
-std::ostream& operator<< (std::ostream &s, CL_NetObject_Client &obj) {
- s << "%" << obj.get_obj_id();
-
- return s;
-}
-
--- a/src/Logger.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Logger.hh Thu Jan 22 03:02:43 2009 +0200
@@ -1,52 +1,69 @@
#ifndef LOGGER_HH
#define LOGGER_HH
-#include <ClanLib/network.h>
+#include "Types.hh"
#include <iostream>
/**
- * Message severity, WARN and above should go to stderr, INFO and DEBUG to stdout
+ * Utility class used for logging, use Engine::log() to construct these. Implements the same streaming behaviour as
+ * std::ostream, but the construtor prints out a header, and the destructor a newline.
*
- * @see Engine::log
- */
-enum LogLevel {
- FATAL,
- ERROR,
- WARN,
- INFO,
- DEBUG,
-};
-
-/**
- * Utility class used for logging, use Engine::log to construct these
+ * Useage example:
+ *
+ * \code
+ * Engine::log(INFO, "foo.bar") << "value of quux=" << quux;
+ *
+ * \endcode
+ *
+ * This will result in output like the following to stdout:
+ *
+ * \verbatim
+ * INFO [foo.bar] value of quux=5
+ * \endverbatim
*
* @see Engine::log
*/
class Logger {
private:
+ /**
+ * The stream we output to
+ */
std::ostream &stream;
- enum LogLevel level;
- const char *module;
+
+ /**
+ * Do we even care?
+ */
+ bool show;
public:
- Logger (std::ostream &stream, enum LogLevel level, const char *module);
-
- template <typename T> Logger& operator<< (const T val) {
-#ifndef NDEBUG
- stream << val;
-#else
- (void) val;
-#endif
-
- return *this;
- }
-
+ /**
+ * If the given level is smaller than the given maximum level, output the header. Otherwise, act as a
+ * no-op.
+ */
+ Logger (std::ostream &stream, LogLevel level, const char *module, LogLevel max_level);
+
+ /**
+ * Stream the given value to our output stream, just like with std::ostream, unless we're acting as a no-op.
+ */
+ template <typename T> Logger& operator<< (const T val);
+
+ /**
+ * Output the final newline
+ */
~Logger (void);
};
-std::ostream& operator<< (std::ostream &s, CL_NetComputer &c);
-std::ostream& operator<< (std::ostream &s, CL_NetObject_Server &obj);
-std::ostream& operator<< (std::ostream &s, CL_NetObject_Client &obj);
+/*
+ * Logger template method definition
+ */
+template <typename T>
+inline Logger& Logger::operator<< (const T val) {
+ if (show)
+ stream << val;
+
+ // chaining
+ return *this;
+}
#endif /* LOGGER_HH */
--- a/src/Network/Buffer.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Network/Buffer.cc Thu Jan 22 03:02:43 2009 +0200
@@ -1,6 +1,6 @@
#include "Buffer.hh"
-#include "Config.hh"
+#include "../Config.hh"
#include <ClanLib/core.h>
#include <cstdlib>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Network/CMakeLists.txt Thu Jan 22 03:02:43 2009 +0200
@@ -0,0 +1,9 @@
+FILE(GLOB NETWORK_SOURCE_FILES "*.cc")
+FILE(GLOB NETWORK_HEADER_FILES "*.hh")
+
+# what ClanLib components we need
+set (NETWORK_CLANLIB_COMPONENTS "" PARENT_SCOPE)
+
+# list of source files
+set (NETWORK_SOURCES ${NETWORK_SOURCE_FILES} ${NETWORK_HEADER_FILES} PARENT_SCOPE)
+
--- a/src/Network/Client.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Network/Client.cc Thu Jan 22 03:02:43 2009 +0200
@@ -1,7 +1,7 @@
#include "Client.hh"
#include "Protocol.hh"
-#include "Config.hh"
+#include "../Config.hh"
#include "../Engine.hh"
#include "../Logger.hh"
@@ -13,8 +13,12 @@
NetworkClientConnect::NetworkClientConnect (Engine &engine, const NetworkEndpoint &connect_to) :
engine(engine), netsession(NETWORK_MAGIC_ID)
{
+ Engine::log(INFO, "net.client") << "Connecting to server: " << connect_to;
+
// connect NetworkSession to get server node (this is still blocking)
server = netsession.connect(connect_to);
+
+ Engine::log(INFO, "net.client") << "Connected, receiving game data";
// connect slots
slots.connect(netsession.sig_chan_message(NETCHAN_TERRAIN_ARRAY), this, &NetworkClientConnect::on_terrain_array);
@@ -57,7 +61,9 @@
void NetworkClientConnect::connectDone (Terrain *terrain) {
// pass Terrain to engine to create game
- GameState &gs = engine.setupGame(terrain);
+ GameState &gs = engine.onNetworkClientConnected(terrain);
+
+ Engine::log(INFO, "net.client") << "Got game data, creating player";
// create our new NetworkClient object
client = new NetworkClient(engine, gs, netsession, server);
@@ -116,17 +122,22 @@
// read the packet
Vector position = pkt.read_vector();
- Engine::log(INFO, "client.on_server_hello") << this << ": pos=" << position;
+ Engine::log(DEBUG, "client.on_server_hello") << this << ": pos=" << position;
// create the LocalPlayer object
- new NetworkClientLocalPlayer(client, obj_id, position);
+ NetworkClientLocalPlayer *player = new NetworkClientLocalPlayer(client, obj_id, position);
+
+ // pass it on to engine
+ client.engine.onNetworkClientPlayer(player);
+
+ Engine::log(INFO, "net.client") << "Joined server: " << player;
}
void NetworkClientController::on_player_info (NetworkObjectID obj_id, NetworkPacketInput &pkt) {
// read the packet
Vector position = pkt.read_vector();
- Engine::log(INFO, "client.on_player_info") << this << ": pos=" << position;
+ Engine::log(DEBUG, "client.on_player_info") << this << ": pos=" << position;
// create the LocalPlayer object
new NetworkClientRemotePlayer(client, obj_id, position);
@@ -136,10 +147,12 @@
// read the packet
Vector position = pkt.read_vector();
- Engine::log(INFO, "client.on_player_join") << this << ": pos=" << position;
+ Engine::log(DEBUG, "client.on_player_join") << this << ": pos=" << position;
// create the RemotePlayer object
- new NetworkClientRemotePlayer(client, obj_id, position);
+ NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(client, obj_id, position);
+
+ Engine::log(INFO, "net.client") << "Player joined: " << player;
}
void NetworkClientController::on_projectile_player_fired (NetworkObjectID obj_id, NetworkPacketInput &pkt) {
@@ -164,7 +177,7 @@
Engine::log(ERROR, "client.on_projectile_player_fired") << this << ": Unknown weapon id: player=" << player << ", weapon_id=" << weapon_id;
}
- Engine::log(INFO, "client.on_projectile_create") << this << ": player=" << player << ", pos=" << position << ", velocity=" << velocity << ", weapon=" << weapon;
+ Engine::log(DEBUG, "client.on_projectile_create") << this << ": player=" << player << ", pos=" << position << ", velocity=" << velocity << ", weapon=" << weapon;
// create the NetworkClientPorjectile object
new NetworkClientProjectile(client, obj_id, player, position, velocity, weapon);
@@ -221,7 +234,7 @@
int flags = pkt.read_uint8();
float aim = pkt.read_float32();
-// Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity << ", aim=" << aim << ", [" << flags << "]";
+// Engine::log(DEBUG, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity << ", aim=" << aim << ", [" << flags << "]";
// just update...
updatePhysics(position, velocity,
@@ -235,7 +248,7 @@
Vector position = pkt.read_vector();
float radius = pkt.read_float32();
- Engine::log(INFO, "client_player.on_dig") << this << ": position=" << position << ", radius=" << radius;
+ Engine::log(DEBUG, "client_player.on_dig") << this << ": position=" << position << ", radius=" << radius;
// just update...
handleDig(position, radius);
@@ -244,7 +257,7 @@
void NetworkClientPlayerBase::on_weapon_change (NetworkPacketInput &pkt) {
uint8_t weapon_index = pkt.read_uint8();
- Engine::log(INFO, "client_player.on_weapon_change") << this << ": weapon_index=" << weapon_index;
+ Engine::log(DEBUG, "client_player.on_weapon_change") << this << ": weapon_index=" << weapon_index;
handleChangeWeapon(weapon_index);
}
@@ -254,7 +267,7 @@
Vector velocity = pkt.read_vector();
float length = pkt.read_float32();
- Engine::log(INFO, "client_player.on_rope_throw") << this << ": position=" << position << ", velocity=" << velocity << ", length=" << length;
+ Engine::log(DEBUG, "client_player.on_rope_throw") << this << ": position=" << position << ", velocity=" << velocity << ", length=" << length;
rope.updateState(ROPE_FLYING, position, velocity, length, NULL);
}
@@ -271,7 +284,7 @@
return;
}
- Engine::log(INFO, "client_player.on_rope_fixed") << this << ": position=" << position << ", length=" << length
+ Engine::log(DEBUG, "client_player.on_rope_fixed") << this << ": position=" << position << ", length=" << length
<< ", player=" << player;
rope.updateState(ROPE_FIXED, position, Vector(0, 0), length, player);
@@ -280,7 +293,7 @@
void NetworkClientPlayerBase::on_rope_released (NetworkPacketInput &pkt) {
(void) pkt;
- Engine::log(INFO, "client_player.on_rope_released") << this;
+ Engine::log(DEBUG, "client_player.on_rope_released") << this;
// use rope.getPosition() instead of e.g. Vector(0, 0) because it will collide there...
rope.updateState(ROPE_FOLDED, rope.getPosition(), Vector(0, 0), 0, NULL);
@@ -289,7 +302,7 @@
void NetworkClientPlayerBase::on_rope_length (NetworkPacketInput &pkt) {
float length = pkt.read_float32();
- Engine::log(INFO, "client_player.on_rope_length") << this << ": length=" << length;
+ Engine::log(DEBUG, "client_player.on_rope_length") << this << ": length=" << length;
rope.updateLength(length);
}
@@ -298,7 +311,7 @@
// read packet
Vector position = pkt.read_vector();
- Engine::log(INFO, "client_player.on_spawn") << this << ": position=" << position;
+ Engine::log(DEBUG, "client_player.on_spawn") << this << ": position=" << position;
// super
Player::spawn(position);
@@ -307,7 +320,7 @@
void NetworkClientPlayerBase::on_die (NetworkPacketInput &pkt) {
(void) pkt;
- Engine::log(INFO, "client_player.on_die") << this;
+ Engine::log(DEBUG, "client_player.on_die") << this;
// super, but don't start the respawn_timer
Player::die(false);
@@ -350,7 +363,7 @@
// pkt is empty
(void) pkt;
- Engine::log(INFO, "client_player.on_quit") << this;
+ Engine::log(INFO, "net.client") << "Player quit: " << this;
client.player_quit(this);
@@ -391,7 +404,7 @@
Vector position = pkt.read_vector();
uint8_t flags = pkt.read_uint8();
- Engine::log(INFO, "client_projectile.on_destroy") << this << ": position=" << position << ", flags=" << flags;
+ Engine::log(DEBUG, "client_projectile.on_destroy") << this << ": position=" << position << ", flags=" << flags;
// pass on to super
Projectile::onDestroy(position, flags & NETWORK_PROJECTILE_REMOVE_GROUND);
@@ -409,7 +422,7 @@
return;
}
- Engine::log(INFO, "client_projectile.hit_player") << this << ": player=" << player;
+ Engine::log(DEBUG, "client_projectile.hit_player") << this << ": player=" << player;
// pass on to super
Projectile::onHitPlayer(player);
--- a/src/Network/Config.hh Wed Jan 21 00:21:42 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#ifndef NETWORK_CONFIG_HH
-#define NETWORK_CONFIG_HH
-
-/**
- * @file
- *
- * Network-related configuration
- */
-
-#include <string>
-
-/** Default port used for network games */
-const std::string NETWORK_PORT_STR = "9338";
-
-/** Maximum packet size used for normal NetworkPackets... aligned to a sensible UDP mtu */
-const size_t NETWORK_PACKET_SIZE = 1280;
-
-/** Backlog used for TCP server... doesn't really matter all that much */
-const int NETWORK_LISTEN_BACKLOG = 5;
-
-/** Magic string used to identify game between client/server */
-const char NETWORK_MAGIC_STR[8+1] = "KISNGLIS";
-const uint64_t NETWORK_MAGIC_ID = * ((const uint64_t *) NETWORK_MAGIC_STR);
-
-#endif /* NETWORK_CONFIG_HH */
--- a/src/Network/Packet.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Network/Packet.hh Thu Jan 22 03:02:43 2009 +0200
@@ -7,7 +7,7 @@
* Provides the NetworkPackets that are used to communicate over a NetworkTCP/NetworkUDP sockets.
*/
-#include "Config.hh"
+#include "../Config.hh"
#include "../Types.hh"
#include "../Error.hh"
--- a/src/Network/Server.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Network/Server.cc Thu Jan 22 03:02:43 2009 +0200
@@ -1,7 +1,7 @@
#include "Server.hh"
#include "Protocol.hh"
-#include "Config.hh"
+#include "../Config.hh"
#include "../Engine.hh"
#include "../Logger.hh"
@@ -16,10 +16,12 @@
// and then we listen
netsession.listen(listen_addr);
- Engine::log(INFO, "server") << "running, listen_addr=" << listen_addr;
+ Engine::log(INFO, "net.server") << "Listening on interface: " << listen_addr;
}
void NetworkServer::on_node_connected (NetworkNode *node) {
+ Engine::log(INFO, "net.server") << "Client connected, sending terrain data: " << node->getRemoteAddress();
+
// send the terrain data
send_terrain_data(node);
@@ -28,7 +30,6 @@
// add to players
players.push_back(player);
-
}
void NetworkServer::send_terrain_data (NetworkNode *node) {
@@ -90,9 +91,6 @@
NetworkServerPlayer::NetworkServerPlayer (NetworkServer &server, NetworkNode *node) :
Player(server.state, Vector(PLAYER_INITIAL_X, PLAYER_INITIAL_Y), true), NetworkServerObject(server), node(node)
{
- // log
- Engine::log(INFO, "server_player.connected") << this << ": node=" << node;
-
// messages
slots.connect(node->sig_disconnected(), this, &NetworkServerPlayer::on_disconnected);
slots.connect(this->sig_message(NETMSG_CLIENT_INPUT), this, &NetworkServerPlayer::on_input);
@@ -123,6 +121,8 @@
// broadcast NETMSG_PLAYER_JOIN to all clients except current
this->send_all_except(NETMSG_PLAYER_JOIN, hello_pkt, node, true);
+
+ Engine::log(INFO, "net.server") << "Player joined: " << this << " from " << node->getRemoteAddress();
}
void NetworkServerPlayer::handleDig (Vector position, float radius) {
@@ -131,7 +131,7 @@
pkt.write_vector(position);
pkt.write_float32(radius);
- Engine::log(INFO, "server_player.handle_dig") << "position=" << position << ", radius=" << radius;
+ Engine::log(DEBUG, "server_player.handle_dig") << "position=" << position << ", radius=" << radius;
// tell everyone... make this reliable...
this->send_all(NETMSG_PLAYER_DIG, pkt, true);
@@ -141,7 +141,7 @@
}
void NetworkServerPlayer::handleFireWeapon (Weapon *weapon, Vector position, Vector velocity) {
- Engine::log(INFO, "server_player.fire_weapon") << "weapon='" << weapon->getName() << "', position=" << position << ", velocity=" << velocity;
+ Engine::log(DEBUG, "server_player.fire_weapon") << "weapon='" << weapon->getName() << "', position=" << position << ", velocity=" << velocity;
// create new NetworkServerProjectile object
new NetworkServerProjectile(server, this, position, velocity, weapon);
@@ -153,7 +153,7 @@
void NetworkServerPlayer::handleChangeWeapon (unsigned int weaponIndex) {
NetworkPacket pkt;
- Engine::log(INFO, "server_player.change_weapon") << "weaponIndex=" << weaponIndex;
+ Engine::log(DEBUG, "server_player.change_weapon") << "weaponIndex=" << weaponIndex;
// write packet
pkt.write_uint8(weaponIndex);
@@ -168,7 +168,7 @@
void NetworkServerPlayer::handleRopeState (RopeState state) {
NetworkPacket pkt;
- Engine::log(INFO, "server_player.rope_state") << "state=" << rope.getState() << ", position=" << rope.getPosition() << ", velocity=" << rope.getVelocity() << ", length=" << rope.getLength() << ", pivotPlayer=" << rope.getPivotPlayer();
+ Engine::log(DEBUG, "server_player.rope_state") << "state=" << rope.getState() << ", position=" << rope.getPosition() << ", velocity=" << rope.getVelocity() << ", length=" << rope.getLength() << ", pivotPlayer=" << rope.getPivotPlayer();
switch (state) {
case ROPE_FLYING:
@@ -216,7 +216,7 @@
// write packet
pkt.write_vector(position);
- Engine::log(INFO, "server_player.spawn") << this << ": position=" << position;
+ Engine::log(DEBUG, "server_player.spawn") << this << ": position=" << position;
// send
send_all(NETMSG_PLAYER_SPAWN, pkt, true);
@@ -228,7 +228,7 @@
void NetworkServerPlayer::die (bool start_timer) {
NetworkPacket pkt;
- Engine::log(INFO, "server_player.die") << this;
+ Engine::log(DEBUG, "server_player.die") << this;
// send
send_all(NETMSG_PLAYER_DIE, pkt, true);
@@ -240,7 +240,7 @@
void NetworkServerPlayer::on_disconnected (void) {
NetworkPacket pkt;
- Engine::log(INFO, "server_player.disconnected") << this << ": node=" << node;
+ Engine::log(INFO, "net.server") << "Player disconnected: " << this;
// remove from server
server.handle_disconnect(this);
@@ -309,7 +309,7 @@
void NetworkServerProjectile::onDestroy (Vector position, bool removeGround) {
NetworkPacket pkt;
- Engine::log(INFO, "server_projectile.destroy") << this << "position=" << position << ", removeGround=" << removeGround;
+ Engine::log(DEBUG, "server_projectile.destroy") << this << "position=" << position << ", removeGround=" << removeGround;
pkt.write_vector(position);
pkt.write_uint8(removeGround ? NETWORK_PROJECTILE_REMOVE_GROUND : 0);
@@ -329,7 +329,7 @@
if (player == NULL)
throw Error("NetworkServerProjectile::onHitPlayer called with non-NetworkServerPlayer player");
- Engine::log(INFO, "server_projectile.hit_player") << this << ": player=" << player;
+ Engine::log(DEBUG, "server_projectile.hit_player") << this << ": player=" << player;
// write packet
controller.write_object(pkt, player);
--- a/src/Network/Socket.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Network/Socket.hh Thu Jan 22 03:02:43 2009 +0200
@@ -15,6 +15,8 @@
#include "Address.hh"
#include "Reactor.hh"
+#include <ClanLib/signals.h>
+
/**
* This is a socket class that wraps an OS socket filedescriptor and provides the more important socket operations
* as methods. The implementation aims to be address-family agnostic, and should thence work with both IPv6 and IPv4.
--- a/src/Player.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Player.cc Thu Jan 22 03:02:43 2009 +0200
@@ -2,7 +2,8 @@
#include "Player.hh"
#include "Weapons.hh"
#include "Engine.hh"
-#include "Graphics.hh"
+
+#include "Graphics/Graphics.hh"
#include <cstdlib>
#include <ClanLib/display.h>
@@ -10,11 +11,15 @@
#include <string>
#include <cassert>
-
-// player static state
+#if GRAPHICS_ENABLED
+/*
+ * Static draw-related state
+ */
bool Player::skin_loaded = false;
CL_Surface Player::skin_surface;
+#endif
+
// XXX: give these better names and move elsewhere
const int img_num_aim = 5;
const int img_num_step = 4;
@@ -324,14 +329,15 @@
kills++;
}
-void Player::draw (Graphics *g, PixelCoordinate camera) {
- CL_GraphicContext *gc = g->get_gc();
+#if GRAPHICS_ENABLED
+void Player::draw (graphics::Display &display, PixelCoordinate camera) {
+ CL_GraphicContext *gc = display.get_gc();
if (!isAlive())
return;
// draw rope behind player
- rope.draw(g, camera);
+ rope.draw(display, camera);
// animation indexes
int aim_img_idx = (int)((1 - (getAim() + KG_PI / 2) / KG_PI) * img_num_aim);
@@ -375,23 +381,28 @@
);
}
-void LocalPlayer::draw (Graphics *g, bool displayWeapon, PixelCoordinate camera) {
+void LocalPlayer::draw (graphics::Display &display, bool displayWeapon, PixelCoordinate camera) {
// superclass draw
- Player::draw(g, camera);
+ Player::draw(display, camera);
// display weapon name?
if (isAlive() && displayWeapon && getCurrentWeapon()) {
const std::string weaponName = getCurrentWeapon()->getName();
+
+ // position
+ PixelCoordinate pc = getCoordinate() - camera;
- PixelCoordinate pc = getCoordinate() - camera;
+ // get font
+ CL_Font &font = graphics::graphics->fonts.getSimpleFont();
// XXX: fix magic constants once we know how big the worm is
- g->getSimpleFont().draw(
- pc.x - g->getSimpleFont().get_width(weaponName) / 2,
- pc.y - 20,
- weaponName,
- g->get_gc()
+ font.draw(
+ pc.x - font.get_width(weaponName) / 2,
+ pc.y - 20,
+ weaponName,
+ display.get_gc()
);
}
}
+#endif
--- a/src/Player.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Player.hh Thu Jan 22 03:02:43 2009 +0200
@@ -9,10 +9,12 @@
#include "Projectile.hh"
#include "GameState.hh"
#include "PhysicsObject.hh"
-#include "Input.hh"
#include "Rope.hh"
-#include "GraphicsPointer.hh"
#include "Types.hh"
+#include "Input.hh"
+
+#include "Graphics/Drawable.hh"
+
#include <vector>
/**
@@ -150,14 +152,27 @@
*/
void addKill ();
+#if GRAPHICS_ENABLED
/*
* Drawing requires the skin texture, which is loaded on-demand when draw is called
*/
static bool skin_loaded;
static CL_Surface skin_surface;
- virtual void draw (Graphics *g, PixelCoordinate camera);
+ /**
+ * Draw this player
+ */
+ virtual void draw (graphics::Display &display, PixelCoordinate camera);
+#endif
+
+ /**
+ * Returns statistics on the number of kills for this player
+ */
uint16_t getKills() { return kills; }
+
+ /**
+ * Returns statistics on the number of deaths for this player
+ */
uint16_t getDeaths() { return deaths; }
};
@@ -187,10 +202,12 @@
*/
virtual void handleInput (PlayerInput input, TimeMS dt);
+#if GRAPHICS_ENABLED
/**
* As Player, but also draws the current weapon name if displayWeapon
*/
- virtual void draw (Graphics *g, bool displayWeapon, PixelCoordinate camera);
+ virtual void draw (graphics::Display &display, bool displayWeapon, PixelCoordinate camera);
+#endif
};
/**
--- a/src/Projectile.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Projectile.cc Thu Jan 22 03:02:43 2009 +0200
@@ -1,5 +1,4 @@
#include "Projectile.hh"
-#include "Graphics.hh"
#include "Timer.hh"
@@ -75,8 +74,9 @@
PhysicsObject::tick(dt);
}
-void Projectile::draw(Graphics *g, PixelCoordinate camera) const {
- CL_GraphicContext *gc = g->get_gc();
+#if GRAPHICS_ENABLED
+void Projectile::draw(graphics::Display &display, PixelCoordinate camera) const {
+ CL_GraphicContext *gc = display.get_gc();
if (visible) {
PixelCoordinate pos = getCoordinate() - camera;
@@ -93,4 +93,5 @@
gc->fill_quad(projectile, CL_Color::green);
}
}
-
+#endif
+
--- a/src/Projectile.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Projectile.hh Thu Jan 22 03:02:43 2009 +0200
@@ -8,7 +8,8 @@
#include "PhysicsObject.hh"
#include "Timer.hh"
#include "Types.hh"
-#include "GraphicsPointer.hh"
+
+#include "Graphics/Drawable.hh"
/**
* A projectile is a flying PhysicsObject, created by firing a player's weapon. It has an initial velocity, is
@@ -47,11 +48,6 @@
virtual ~Projectile (void);
/**
- * Draw
- */
- virtual void draw (Graphics *g, PixelCoordinate camera) const;
-
- /**
* Get damage inflicted by this projectile.
*
* @return Damage inflicted by projectile.
@@ -93,6 +89,18 @@
* If we have expired, call onDestory and removeGround
*/
virtual void tick (TimeMS dt);
+
+public:
+
+#if GRAPHICS_ENABLED
+ /**
+ * Draw
+ */
+ virtual void draw (graphics::Display &display, PixelCoordinate camera) const;
+
+#endif
+
+
};
#endif
--- a/src/Rope.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Rope.cc Thu Jan 22 03:02:43 2009 +0200
@@ -1,7 +1,10 @@
+
+// XXX: must include Player first, as it contains an instance of Rope
#include "Player.hh"
#include "Rope.hh"
#include "Engine.hh"
-#include "Graphics.hh"
+#include "Error.hh"
+
#include <math.h>
#include <stdexcept>
@@ -150,7 +153,8 @@
this->length = length;
}
-void Rope::draw (Graphics *g, PixelCoordinate camera) {
+#if GRAPHICS_ENABLED
+void Rope::draw (graphics::Display &display, PixelCoordinate camera) {
PixelCoordinate player_pos = player.getCoordinate() - camera;
PixelCoordinate target_pos;
@@ -175,12 +179,13 @@
target_pos -= camera;
// draw a line from the player to the target chosen above
- g->get_gc()->draw_line(
+ display.get_gc()->draw_line(
player_pos.x, player_pos.y,
target_pos.x, target_pos.y,
ROPE_COLOR_DARK
);
}
+#endif
void Rope::tick (TimeMS dt) {
if (state == ROPE_FLYING) {
--- a/src/Rope.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Rope.hh Thu Jan 22 03:02:43 2009 +0200
@@ -5,10 +5,6 @@
// and the Player wants to know the rope.
class Rope;
-#include "Player.hh"
-#include "PhysicsObject.hh"
-#include "GraphicsPointer.hh"
-
/**
* The rope can be in one of three states...
*
@@ -20,6 +16,11 @@
ROPE_FIXED //<<< The rope is attached to something
};
+#include "Player.hh"
+#include "PhysicsObject.hh"
+
+#include "Graphics/Drawable.hh"
+
/**
* A rope is a PhysicsObject that can be thrown, whereupon it then flies until it hits something, whereupon
* it attaches to that, and sets itself as the player's pivot.
@@ -83,10 +84,12 @@
virtual void tick (TimeMS dt);
+#if GRAPHICS_ENABLED
/*
- * Just draws it
+ * Draw the rope, in the FLYING/FIXED state
*/
- virtual void draw (Graphics *c, PixelCoordinate camera);
+ virtual void draw (graphics::Display &display, PixelCoordinate camera);
+#endif
};
#endif
--- a/src/Terrain.cc Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Terrain.cc Thu Jan 22 03:02:43 2009 +0200
@@ -1,5 +1,5 @@
+
#include "Terrain.hh"
-#include "Graphics.hh"
#include "Engine.hh"
#include <cmath>
@@ -20,7 +20,7 @@
Terrain::Terrain (const TerrainConfig &config) :
terrain_buf(NULL),
- width(config.dimensions.x), height(config.dimensions.y)
+ width(config.dimensions.width), height(config.dimensions.height)
{
// allocate terrain_buf
terrain_buf = new TerrainPixel[width * height];
@@ -101,6 +101,8 @@
}
void Terrain::generatePixelBuffer (void) {
+
+#if GRAPHICS_ENABLED
// initialize textures
generateTexture();
@@ -114,6 +116,12 @@
pixbuf.draw_pixel(x, y, getTexturePixel(x, y));
}
}
+
+#else
+ // no-op
+
+#endif
+
}
/*
@@ -410,13 +418,15 @@
return normal;
}
-void Terrain::draw (Graphics *g, PixelCoordinate camera) {
+#if GRAPHICS_ENABLED
+void Terrain::draw (graphics::Display &display, PixelCoordinate camera) {
// XXX: can we optimize this somehow?
// load the terrain pixbuf as a surface
CL_Surface surf (pixbuf);
// draw it onto the graphics, offset by camera position
- surf.draw(-camera.x, -camera.y, g->get_gc());
+ surf.draw(-camera.x, -camera.y, display.get_gc());
}
+#endif
--- a/src/Terrain.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Terrain.hh Thu Jan 22 03:02:43 2009 +0200
@@ -2,9 +2,13 @@
#define TERRAIN_HH
#include "Vector.hh"
-#include "GraphicsPointer.hh"
#include "Types.hh"
#include "Config.hh"
+#include "Configuration.hh"
+
+#include "Graphics/Drawable.hh"
+
+#include <vector>
/**
* Different types of terrain available
@@ -21,27 +25,6 @@
};
/**
- * Terrain "pixel" type
- */
-typedef uint8_t TerrainPixel;
-
-/**
- * Terrain configuration
- */
-struct TerrainConfig {
- /** Size of the terrain field*/
- PixelCoordinate dimensions;
-
- /** Set to nonzero to generate random map */
- int random_seed;
-
- /** Defaults */
- TerrainConfig (void) : dimensions(TERRAIN_WIDTH, TERRAIN_HEIGHT), random_seed(TERRAIN_RANDOM_SEED) { }
-};
-
-#include <vector>
-
-/**
* Terrain class. Represents game terrain and contains member
* functions to manipulate terrain and get info about it.
*
@@ -58,10 +41,13 @@
/** Terrain dimensions */
PixelDimension width, height;
-
+
+#if GRAPHICS_ENABLED
/** We pre-render the textured terrain data for display */
CL_PixelBuffer pixbuf;
+#endif
+
// XXX: terrain texture
std::vector<std::vector<int> > texture;
@@ -102,8 +88,10 @@
inline void setType (PixelDimension x, PixelDimension y, TerrainType t) {
terrain_buf[y * width + x] = (TerrainPixel) t;
+#if GRAPHICS_ENABLED
// XXX: locking?
pixbuf.draw_pixel(x, y, getTexturePixel(x, y));
+#endif
}
/**
@@ -240,13 +228,15 @@
*/
Vector getNormal (Vector point, Vector prevPoint) const;
+#if GRAPHICS_ENABLED
/**
* Draw the terrain onto the given graphics context
*
* @param gc Graphics to draw on
* @param camera view position
*/
- virtual void draw (Graphics *g, PixelCoordinate camera = PixelCoordinate(0, 0));
+ virtual void draw (graphics::Display &display, PixelCoordinate camera = PixelCoordinate(0, 0));
+#endif
};
#endif
--- a/src/Types.hh Wed Jan 21 00:21:42 2009 +0200
+++ b/src/Types.hh Thu Jan 22 03:02:43 2009 +0200
@@ -15,6 +15,21 @@
typedef VectorType<float> Vector;
/**
+ * Message severity, WARN and above should go to stderr, INFO and DEBUG to stdout
+ *
+ * @see Engine::log
+ * @see EngineConfig::log_level
+ * @see Logger
+ */
+enum LogLevel {
+ FATAL,
+ ERROR,
+ WARN,
+ INFO,
+ DEBUG,
+};
+
+/**
* A player's health is measured in...
*/
typedef int16_t Health;
@@ -30,6 +45,19 @@
typedef VectorType<PixelDimension> PixelCoordinate;
/**
+ * Dimensions of something in pixels
+ */
+struct PixelDimensions {
+ /** Item width/height */
+ PixelDimension width, height;
+
+ /** Simple constructor */
+ PixelDimensions (PixelDimension width, PixelDimension height) :
+ width(width), height(height)
+ { }
+};
+
+/**
* A rectangular area of pixels
*/
struct PixelArea {
@@ -50,4 +78,11 @@
*/
typedef int32_t TickCount;
+/**
+ * Terrain "pixel" type
+ *
+ * @see TerrainType
+ */
+typedef uint8_t TerrainPixel;
+
#endif
--- a/src/config.h.in Wed Jan 21 00:21:42 2009 +0200
+++ b/src/config.h.in Thu Jan 22 03:02:43 2009 +0200
@@ -13,5 +13,17 @@
*/
extern const char *PROJECT_VERSION, *PROJECT_BUILD_TIMESTAMP;
+/**
+ * Provide possibility to compile without graphics code.
+ *
+ * Defined as a boolean value (so use #if GRAPHICS_ENABLED / if (GRAPHICS_ENABLED) )
+ */
+#define GRAPHICS_ENABLED @GRAPHICS_ENABLED@
+
+/**
+ * Provide possibility to compile without network code.
+ */
+#define NETWORK_ENABLED @NETWORK_ENABLED@
+
#endif