Page MenuHomePhabricator (Chris)

No OneTemporary

Size
105 KB
Referenced Files
None
Subscribers
None
diff --git a/src/Makefile.am b/src/Makefile.am
index eaea251..0b3aba2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,27 +1,28 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = openmortal
openmortal_SOURCES = Audio.cpp Backend.cpp common.cpp \
Demo.cpp FighterStats.cpp FlyingChars.cpp Game.cpp gfx.cpp main.cpp \
menu.cpp PlayerSelect.cpp RlePack.cpp sge_bm_text.cpp \
sge_primitives.cpp sge_surface.cpp sge_tt_text.cpp State.cpp \
- GameOver.cpp Background.cpp
+ GameOver.cpp Background.cpp MortalNetworkImpl.cpp
EXTRA_DIST = Audio.h Backend.h common.h Demo.h FlyingChars.h gfx.h \
menu.h RlePack.h sge_bm_text.h sge_config.h sge_internal.h \
sge_primitives.h sge_surface.h sge_tt_text.h State.h \
Game.h FighterEnum.h PlayerSelect.h MszPerl.h \
Audio.cpp Backend.cpp common.cpp \
Demo.cpp FighterStats.cpp FlyingChars.cpp Game.cpp gfx.cpp main.cpp \
menu.cpp PlayerSelect.cpp RlePack.cpp sge_bm_text.cpp \
sge_primitives.cpp sge_surface.cpp sge_tt_text.cpp State.cpp \
- GameOver.cpp Background.h
+ GameOver.cpp Background.h MortalNetwork.h MortalNetworkImpl.h \
+ FighterStats.h
CXXFLAGS= @CXXFLAGS@ -DDATADIR=\"${pkgdatadir}\" -Wall
# set the include path found by configure
#INCLUDES= $(all_includes)
# the library search path.
#msz_LDFLAGS = $(all_libraries)
diff --git a/src/Makefile.in b/src/Makefile.in
index 909babb..d6ad6bb 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,364 +1,364 @@
# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
DESTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_alias = @build_alias@
build_triplet = @build@
host_alias = @host_alias@
host_triplet = @host@
target_alias = @target_alias@
target_triplet = @target@
AUTODIRS = @AUTODIRS@
CXX = @CXX@
FT2_CFLAGS = @FT2_CFLAGS@
FT2_CONFIG = @FT2_CONFIG@
FT2_LIBS = @FT2_LIBS@
MAKEINFO = @MAKEINFO@
PACKAGE = @PACKAGE@
PERL = @PERL@
SDL_CFLAGS = @SDL_CFLAGS@
SDL_CONFIG = @SDL_CONFIG@
SDL_LIBS = @SDL_LIBS@
VERSION = @VERSION@
perl_embed_ccflags = @perl_embed_ccflags@
perl_embed_ldflags = @perl_embed_ldflags@
bin_PROGRAMS = openmortal
-openmortal_SOURCES = Audio.cpp Backend.cpp common.cpp Demo.cpp FighterStats.cpp FlyingChars.cpp Game.cpp gfx.cpp main.cpp menu.cpp PlayerSelect.cpp RlePack.cpp sge_bm_text.cpp sge_primitives.cpp sge_surface.cpp sge_tt_text.cpp State.cpp GameOver.cpp Background.cpp
+openmortal_SOURCES = Audio.cpp Backend.cpp common.cpp Demo.cpp FighterStats.cpp FlyingChars.cpp Game.cpp gfx.cpp main.cpp menu.cpp PlayerSelect.cpp RlePack.cpp sge_bm_text.cpp sge_primitives.cpp sge_surface.cpp sge_tt_text.cpp State.cpp GameOver.cpp Background.cpp MortalNetworkImpl.cpp
-EXTRA_DIST = Audio.h Backend.h common.h Demo.h FlyingChars.h gfx.h menu.h RlePack.h sge_bm_text.h sge_config.h sge_internal.h sge_primitives.h sge_surface.h sge_tt_text.h State.h Game.h FighterEnum.h PlayerSelect.h MszPerl.h Audio.cpp Backend.cpp common.cpp Demo.cpp FighterStats.cpp FlyingChars.cpp Game.cpp gfx.cpp main.cpp menu.cpp PlayerSelect.cpp RlePack.cpp sge_bm_text.cpp sge_primitives.cpp sge_surface.cpp sge_tt_text.cpp State.cpp GameOver.cpp Background.h
+EXTRA_DIST = Audio.h Backend.h common.h Demo.h FlyingChars.h gfx.h menu.h RlePack.h sge_bm_text.h sge_config.h sge_internal.h sge_primitives.h sge_surface.h sge_tt_text.h State.h Game.h FighterEnum.h PlayerSelect.h MszPerl.h Audio.cpp Backend.cpp common.cpp Demo.cpp FighterStats.cpp FlyingChars.cpp Game.cpp gfx.cpp main.cpp menu.cpp PlayerSelect.cpp RlePack.cpp sge_bm_text.cpp sge_primitives.cpp sge_surface.cpp sge_tt_text.cpp State.cpp GameOver.cpp Background.h MortalNetwork.h MortalNetworkImpl.h FighterStats.h
CXXFLAGS = @CXXFLAGS@ -DDATADIR=\"${pkgdatadir}\" -Wall
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
PROGRAMS = $(bin_PROGRAMS)
DEFS = @DEFS@ -I. -I$(srcdir) -I..
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
openmortal_OBJECTS = Audio.o Backend.o common.o Demo.o FighterStats.o \
FlyingChars.o Game.o gfx.o main.o menu.o PlayerSelect.o RlePack.o \
sge_bm_text.o sge_primitives.o sge_surface.o sge_tt_text.o State.o \
-GameOver.o Background.o
+GameOver.o Background.o MortalNetworkImpl.o
openmortal_LDADD = $(LDADD)
openmortal_DEPENDENCIES =
openmortal_LDFLAGS =
CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
CXXLD = $(CXX)
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
DIST_COMMON = Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = gtar
GZIP_ENV = --best
DEP_FILES = .deps/Audio.P .deps/Backend.P .deps/Background.P \
.deps/Demo.P .deps/FighterStats.P .deps/FlyingChars.P .deps/Game.P \
-.deps/GameOver.P .deps/PlayerSelect.P .deps/RlePack.P .deps/State.P \
-.deps/common.P .deps/gfx.P .deps/main.P .deps/menu.P \
-.deps/sge_bm_text.P .deps/sge_primitives.P .deps/sge_surface.P \
-.deps/sge_tt_text.P
+.deps/GameOver.P .deps/MortalNetworkImpl.P .deps/PlayerSelect.P \
+.deps/RlePack.P .deps/State.P .deps/common.P .deps/gfx.P .deps/main.P \
+.deps/menu.P .deps/sge_bm_text.P .deps/sge_primitives.P \
+.deps/sge_surface.P .deps/sge_tt_text.P
SOURCES = $(openmortal_SOURCES)
OBJECTS = $(openmortal_OBJECTS)
all: all-redirect
.SUFFIXES:
.SUFFIXES: .S .c .cpp .o .s
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
mostlyclean-binPROGRAMS:
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
distclean-binPROGRAMS:
maintainer-clean-binPROGRAMS:
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(bindir)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
if test -f $$p; then \
echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
else :; fi; \
done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
list='$(bin_PROGRAMS)'; for p in $$list; do \
rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
done
.s.o:
$(COMPILE) -c $<
.S.o:
$(COMPILE) -c $<
mostlyclean-compile:
-rm -f *.o core *.core
clean-compile:
distclean-compile:
-rm -f *.tab.c
maintainer-clean-compile:
openmortal: $(openmortal_OBJECTS) $(openmortal_DEPENDENCIES)
@rm -f openmortal
$(CXXLINK) $(openmortal_LDFLAGS) $(openmortal_OBJECTS) $(openmortal_LDADD) $(LIBS)
.cpp.o:
$(CXXCOMPILE) -c $<
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
here=`pwd` && cd $(srcdir) \
&& mkid -f$$here/ID $$unique $(LISP)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
-rm -f TAGS ID
maintainer-clean-tags:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = src
distdir: $(DISTFILES)
here=`cd $(top_builddir) && pwd`; \
top_distdir=`cd $(top_distdir) && pwd`; \
distdir=`cd $(distdir) && pwd`; \
cd $(top_srcdir) \
&& $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/Makefile
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
cp -pr $$d/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
-include $(DEP_FILES)
mostlyclean-depend:
clean-depend:
distclean-depend:
-rm -rf .deps
maintainer-clean-depend:
%.o: %.c
@echo '$(COMPILE) -c $<'; \
$(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
@-cp .deps/$(*F).pp .deps/$(*F).P; \
tr ' ' '\012' < .deps/$(*F).pp \
| sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
>> .deps/$(*F).P; \
rm .deps/$(*F).pp
%.lo: %.c
@echo '$(LTCOMPILE) -c $<'; \
$(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
@-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
< .deps/$(*F).pp > .deps/$(*F).P; \
tr ' ' '\012' < .deps/$(*F).pp \
| sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
>> .deps/$(*F).P; \
rm -f .deps/$(*F).pp
%.o: %.cpp
@echo '$(CXXCOMPILE) -c $<'; \
$(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
@-cp .deps/$(*F).pp .deps/$(*F).P; \
tr ' ' '\012' < .deps/$(*F).pp \
| sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
>> .deps/$(*F).P; \
rm .deps/$(*F).pp
%.lo: %.cpp
@echo '$(LTCXXCOMPILE) -c $<'; \
$(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
@-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
< .deps/$(*F).pp > .deps/$(*F).P; \
tr ' ' '\012' < .deps/$(*F).pp \
| sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
>> .deps/$(*F).P; \
rm -f .deps/$(*F).pp
info-am:
info: info-am
dvi-am:
dvi: dvi-am
check-am: all-am
check: check-am
installcheck-am:
installcheck: installcheck-am
install-exec-am: install-binPROGRAMS
install-exec: install-exec-am
install-data-am:
install-data: install-data-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-am
uninstall-am: uninstall-binPROGRAMS
uninstall: uninstall-am
all-am: Makefile $(PROGRAMS)
all-redirect: all-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
installdirs:
$(mkinstalldirs) $(DESTDIR)$(bindir)
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
maintainer-clean-generic:
mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \
mostlyclean-tags mostlyclean-depend mostlyclean-generic
mostlyclean: mostlyclean-am
clean-am: clean-binPROGRAMS clean-compile clean-tags clean-depend \
clean-generic mostlyclean-am
clean: clean-am
distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \
distclean-depend distclean-generic clean-am
distclean: distclean-am
maintainer-clean-am: maintainer-clean-binPROGRAMS \
maintainer-clean-compile maintainer-clean-tags \
maintainer-clean-depend maintainer-clean-generic \
distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
maintainer-clean: maintainer-clean-am
.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile tags mostlyclean-tags distclean-tags \
clean-tags maintainer-clean-tags distdir mostlyclean-depend \
distclean-depend clean-depend maintainer-clean-depend info-am info \
dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
install-exec install-data-am install-data install-am install \
uninstall-am uninstall all-redirect all-am all installdirs \
mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
# set the include path found by configure
#INCLUDES= $(all_includes)
# the library search path.
#msz_LDFLAGS = $(all_libraries)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/src/MortalNetwork.h b/src/MortalNetwork.h
new file mode 100644
index 0000000..0fbeaa3
--- /dev/null
+++ b/src/MortalNetwork.h
@@ -0,0 +1,121 @@
+/***************************************************************************
+ MortalNetwork.h - description
+ -------------------
+ begin : Sun Jan 25 2004
+ copyright : (C) 2004 by upi
+ email : upi@feel
+ ***************************************************************************/
+
+
+#ifndef MORTALNETWORK_H
+#define MORTALNETWORK_H
+
+#include "FighterEnum.h"
+
+
+/** Mortal Network messages:
+
+
+TYPICAL MESSAGE FLOW:
+
+<connection is established>
+Introduction messages are sent (version checking, usernames)
+
+<players go to the character selection screen>
+1. F <number> messages go both ways as players choose their characters.
+2. R message goes in both direction when players have finished choosing.
+
+<both sides go to the game screen>
+In odd rounds, the "server" if the "master" and the "client" is the "slave"
+In even rounds, the "client" if the "master" and the "server" is the "slave"
+
+Both the master and the slave send an S message to synchronize the game start.
+
+The master sends G <text> messages to update the backend on the slave side.
+The slave sends K <number> <bool> messages to communicate keystrokes to the master side.
+The master sends O <number> <bool> message when the round is over.
+
+Back to game start synchronization.
+
+<both sides go to final judgement - may disconnect the game>
+
+<both sides go back to the character selection screen>
+
+
+OTHERS:
+
+Msgs can be send on the character selection screen with M <text>.
+The connection can be broken at any time. IsConnectionAlive() must be called
+periodically.
+
+The "server" is always appears as player 1, the "client" is always player 2.
+However, they both use the "Player 1" keys.
+
+
+SUMMARY OF MESSAGES:
+
+I <version> <username> - Introduction sent both ways on connection.
+G <text> - Update on the game backend data.
+K <number> <bool> - Key # up/down
+M <text> - Incoming Msg text.
+F <number> - I have switched to fighter X.
+R - I have chosen a fighter.
+S - Ready for the next round (synch).
+O <number> <bool> - The round is over (who won, are there more rounds).
+
+*/
+
+
+
+
+
+
+class CMortalNetwork
+{
+public:
+
+ static void Create();
+
+ // Connection's lifecycle
+
+ virtual bool Start( const char* a_pcServerName ) = 0; // Accept connection, or connect to given server
+ virtual void Stop() = 0; // Disconnect
+ virtual bool IsConnectionAlive() = 0; // Is the connection still good?
+ virtual void Update() = 0; // Read network traffic. Might get disconnected...
+ virtual const char* GetLastError() = 0;
+ virtual bool IsMaster() = 0; // Am I Master or Slave?
+
+ // Msg related methods
+
+ virtual const char* GetRemoteUsername() = 0; // This is the name that is passed upon connection.
+ virtual void SendMsg( const char* a_rsMsg ) = 0; // Prompt the user for a line of chat text
+ virtual bool IsMsgAvailable() = 0; // Returns true is a chatline has arrived
+ virtual const char* GetMsg() = 0; // The next chatline, or NULL if there are no more.
+
+ // Charater Selection methods
+
+ virtual bool IsRemoteFighterAvailable( FighterEnum a_enFighter ) = 0; // Does the other computer have fighter X installed?
+ virtual FighterEnum GetRemoteFighter() = 0; // Returns the latest fighter chosen by the remote side.
+ virtual bool IsRemoteSideReady() = 0; // The other player is finished choosing.
+
+ virtual void SendFighter( FighterEnum a_enFighter ) = 0; // Let the other side know that I switched to fighter X.
+ virtual void SendReady() = 0; // Let the other side know that I am ready.
+
+ // Game methods
+
+ virtual void SynchStartRound() = 0;
+ virtual void SendGameData( const char* a_pcGameData ) = 0;
+ virtual const char* GetLatestGameData() = 0;
+ virtual void SendKeystroke( int a_iKey, bool a_bPressed ) = 0;
+ virtual bool GetKeystroke( int& a_riOutKey, bool a_rbPressed ) = 0;
+
+ virtual void SendRoundOver( int a_iWhoWon, bool a_bGameOver ) = 0;
+ virtual bool IsRoundOver( int& a_riOutWhoWon ) = 0;
+ virtual bool IsGameOver() = 0;
+};
+
+
+extern CMortalNetwork* g_poNetwork;
+
+
+#endif // MORTALNETWORK_H
diff --git a/src/MortalNetworkImpl.cpp b/src/MortalNetworkImpl.cpp
new file mode 100644
index 0000000..277aa83
--- /dev/null
+++ b/src/MortalNetworkImpl.cpp
@@ -0,0 +1,668 @@
+/***************************************************************************
+ MortalNetworkImpl.cpp - description
+ -------------------
+ begin : Sun Jan 25 2004
+ copyright : (C) 2004 by upi
+ email : upi@feel
+ ***************************************************************************/
+
+#include "MortalNetworkImpl.h"
+#include "State.h"
+#include "common.h"
+#include "config.h"
+
+
+#define MORTALNETWORKPORT 0x3A22
+
+
+void MortalNetworkMessage( const char* format, ... );
+bool MortalNetworkCheckKey();
+
+
+
+
+CMortalNetwork* g_poNetwork = NULL;
+
+
+
+
+void CMortalNetwork::Create() // static
+{
+ if ( NULL == g_poNetwork )
+ {
+ g_poNetwork = new CMortalNetworkImpl;
+ }
+}
+
+
+
+CMortalNetworkImpl::CMortalNetworkImpl()
+{
+ m_enState = NS_DISCONNECTED;
+ m_bServer = false;
+ m_bMaster = false;
+ m_poSocket = NULL;
+
+ m_enRemoteFighter = UNKNOWN;
+ m_bRemoteReady = false;
+ m_bRoundOver = false;
+ m_iWhoWon = -1;
+ m_bGameOver = false;
+
+ if(SDLNet_Init()==-1)
+ {
+ m_bNetworkAvailable = false;
+ m_sLastError = SDLNet_GetError();
+ debug ( "Error opening SDLNet: %s\n", m_sLastError.c_str() );
+ }
+
+ m_bNetworkAvailable = true;
+}
+
+
+CMortalNetworkImpl::~CMortalNetworkImpl()
+{
+ Stop();
+}
+
+
+bool CMortalNetworkImpl::Start( const char* a_pcServerName )
+{
+#define RETURNNOERROR { \
+ debug( "%s\n", m_sLastError.c_str() ); \
+ return false; }
+#define RETURNWITHERROR { \
+ m_sLastError = SDLNet_GetError(); \
+ debug( "%s\n", m_sLastError.c_str() ); \
+ return false; }
+#define RETURNWITHADDITIONALERROR { \
+ m_sLastError += SDLNet_GetError(); \
+ debug( "%s\n", m_sLastError.c_str() ); \
+ return false; }
+
+ if ( !m_bNetworkAvailable )
+ {
+ return false;
+ }
+
+ debug( "CMortalNetworkImpl::Start( %s )\n", a_pcServerName ? a_pcServerName : "NULL" );
+ IPaddress oAddress;
+
+ if ( a_pcServerName )
+ {
+ MortalNetworkMessage( Translate("Resolving hostname...") );
+ }
+
+ int iResult = SDLNet_ResolveHost( &oAddress, a_pcServerName, MORTALNETWORKPORT );
+ if ( iResult )
+ {
+ m_sLastError = Translate( "Couldn't resolve host." );
+ RETURNNOERROR;
+ }
+ debug( "IP Address of server is 0x%x\n", oAddress.host );
+
+ if ( a_pcServerName )
+ {
+ Uint32 ipaddr=SDL_SwapBE32(oAddress.host);
+ MortalNetworkMessage("Connecting to %d.%d.%d.%d port %d",
+ ipaddr>>24, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff, oAddress.port);
+ }
+
+ if ( !a_pcServerName )
+ {
+ // SERVER-MODE CONNECTION
+
+ m_poSocket = SDLNet_TCP_Open( &oAddress );
+
+ // Wait for connection ...
+ MortalNetworkMessage ( Translate("Waiting for connection... (press any key to abort)") );
+ TCPsocket poClient;
+ while ( 1 )
+ {
+ poClient = SDLNet_TCP_Accept( m_poSocket );
+ if ( poClient ) break;
+
+ if (MortalNetworkCheckKey()) break;;
+ SDL_Delay( 100 );
+ }
+
+ SDLNet_TCP_Close( m_poSocket );
+
+ if ( NULL == poClient )
+ {
+ m_sLastError = "No connection.";
+ return false;
+ }
+
+ IPaddress* poRemoteAddress = SDLNet_TCP_GetPeerAddress(poClient);
+
+ if ( !poRemoteAddress )
+ {
+ RETURNWITHERROR;
+ }
+ Uint32 ipaddr=SDL_SwapBE32(poRemoteAddress->host);
+ MortalNetworkMessage("Accepted connection from %d.%d.%d.%d port %d",
+ ipaddr>>24, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff, oAddress.port);
+
+ // Set the client socket as our socket, and drop the server socket.
+
+ m_poSocket = poClient;
+ }
+ else
+ {
+ // CLIENT-MODE CONNECTION
+
+ MortalNetworkMessage ( Translate("Waiting for connection... (press any key to abort)") );
+
+ while (1)
+ {
+ m_poSocket = SDLNet_TCP_Open( &oAddress );
+ if ( m_poSocket ) break;
+ if ( MortalNetworkCheckKey() ) break;
+ SDL_Delay( 100 );
+ }
+ if ( NULL == m_poSocket )
+ {
+ RETURNWITHERROR;
+ }
+ }
+
+ // CONNECTION ESTABLISHED. SEND INTRO PACKETS
+
+ MortalNetworkMessage( Translate("Connection established.") );
+
+ struct SIntroPackage
+ {
+ char cID;
+ char acVersion[10];
+ } oIntroPackage, oRemotePackage;
+
+ oIntroPackage.cID = 'I';
+ strncpy( oIntroPackage.acVersion, VERSION, 10 );
+ oIntroPackage.acVersion[9] = 0;
+
+ debug( "Sending intro package... " );
+
+ int iRetval = SDLNet_TCP_Send( m_poSocket, &oIntroPackage, sizeof( oIntroPackage ) );
+
+ if ( iRetval < (int) sizeof( oIntroPackage ) )
+ {
+ RETURNWITHERROR;
+ }
+
+ iRetval = SDLNet_TCP_Recv( m_poSocket, &oRemotePackage, sizeof( oRemotePackage ) );
+ if ( iRetval <= 0 )
+ {
+ RETURNWITHERROR;
+ }
+ if ( iRetval < (int) sizeof( oRemotePackage )
+ || oRemotePackage.cID != 'I'
+ || strncmp( oRemotePackage.acVersion, VERSION, 9 ) )
+ {
+ m_sLastError = Translate( "The remote side has a different version of OpenMortal running." );
+ RETURNNOERROR;
+ }
+
+ MortalNetworkMessage( Translate("Life is good.") );
+
+ m_enState = NS_CHARACTER_SELECTION;
+ m_bServer = NULL == a_pcServerName;
+ m_bMaster = m_bServer;
+ m_sLastError = "";
+ m_asMsgs.clear();
+ m_enRemoteFighter = UNKNOWN;
+ m_bRemoteReady = false;
+ m_sLatestGameData = "";
+ m_aiKeystrokes.clear();
+ m_abKeystrokes.clear();
+
+ m_poSocketSet = SDLNet_AllocSocketSet( 1 );
+ SDLNet_TCP_AddSocket( m_poSocketSet, m_poSocket ); // Check for errors?
+
+ while (!MortalNetworkCheckKey()) SDL_Delay( 100 );
+
+ return true;
+}
+
+
+void CMortalNetworkImpl::Stop()
+{
+ if ( NS_DISCONNECTED == m_enState )
+ {
+ return;
+ }
+
+ g_oState.m_enGameMode = SState::IN_DEMO;
+ m_enState = NS_DISCONNECTED;
+ SDLNet_FreeSocketSet( m_poSocketSet );
+ SDLNet_TCP_Close( m_poSocket );
+}
+
+
+bool CMortalNetworkImpl::IsConnectionAlive()
+{
+ return ( NS_DISCONNECTED != m_enState );
+}
+
+
+
+#define DISCONNECTONCOMMUNICATIONERROR { \
+ m_sLastError = Translate("Communication error. Disconnecting."); \
+ Stop(); \
+ return; }
+#define DISCONNECTWITH(A) { \
+ m_sLastError = Translate("Communication error. Disconnecting."); \
+ Stop(); \
+ return(A); }
+
+#define CHECKCONNECTION if ( NS_DISCONNECTED == m_enState ) return;
+
+
+void CMortalNetworkImpl::Update()
+{
+ CHECKCONNECTION;
+
+ int iRetval = SDLNet_CheckSockets( m_poSocketSet, 0 );
+ if ( iRetval <= 0 )
+ {
+ return;
+ }
+
+ char acBuffer[1024];
+ iRetval = SDLNet_TCP_Recv( m_poSocket, acBuffer, 1024 );
+ if ( iRetval <= 0 )
+ {
+ m_sLastError = SDLNet_GetError();
+ Stop();
+ return;
+ }
+
+ // OK, we've read it. Now let's see what it is.
+
+ int iOffset = 0;
+
+ while ( iOffset < iRetval )
+ {
+ debug( "Received stuff.. %c type, %d length, %d offset\n", acBuffer[iOffset], iRetval, iOffset );
+
+ if ( NS_CHARACTER_SELECTION == m_enState )
+ {
+ switch ( acBuffer[iOffset] )
+ {
+ case 'M': iOffset += ReceiveMsg( acBuffer+iOffset, iRetval ); break;
+ case 'F': iOffset += ReceiveFighter( acBuffer+iOffset, iRetval ); break;
+ case 'R': iOffset += ReceiveReady( acBuffer+iOffset, iRetval ); break;
+ case 'S': ++iOffset; break;
+ default: DISCONNECTONCOMMUNICATIONERROR;
+ }
+ }
+ else
+ {
+ switch ( acBuffer[iOffset] )
+ {
+ case 'M': iOffset += ReceiveMsg( acBuffer+iOffset, iRetval ); break;
+ case 'G': iOffset += ReceiveGameData( acBuffer+iOffset, iRetval ); break;
+ case 'K': iOffset += ReceiveKeystroke( acBuffer+iOffset, iRetval ); break;
+ case 'O': iOffset += ReceiveRoundOver( acBuffer+iOffset, iRetval ); break;
+ case 'S': ++iOffset; break;
+ default: DISCONNECTONCOMMUNICATIONERROR;
+ }
+ }
+
+ if ( !IsConnectionAlive() )
+ {
+ return;
+ }
+ }
+}
+
+
+const char* CMortalNetworkImpl::GetLastError()
+{
+ return m_sLastError.c_str();
+}
+
+
+bool CMortalNetworkImpl::IsMaster()
+{
+ return m_bMaster;
+}
+
+
+/*
+ enum TNetworkState
+ {
+ NS_DISCONNECTED,
+ NS_CHARACTER_SELECTION,
+ NS_IN_GAME,
+ };
+
+ TNetworkState m_enState;
+ bool m_bServer;
+ bool m_bMaster;
+ TCPsocket m_poSocket;
+
+ std::list<std::string> m_asMsgs;
+
+ // GAME DATA
+
+ FighterEnum m_enRemoteFighter;
+ bool m_bRemoteReady;
+
+ std::string m_sLatestGameData;
+ std::list<int> m_iKeystrokes;
+ std::list<int> m_bKeystrokes;
+
+ bool m_bRoundOver;
+ int m_iWhoWon;
+ bool m_bGameOver;
+*/
+
+
+const char* CMortalNetworkImpl::GetRemoteUsername()
+{
+ return "upi";
+}
+
+
+
+/*************************************************************************
+ MSG RELATED METHODS
+*************************************************************************/
+
+
+#define MAXSTRINGLENGTH 900
+struct SMsgPackage
+{
+ char cID;
+ Uint16 iLength;
+ char acData[1024];
+};
+
+void CMortalNetworkImpl::InternalSendString( const char* a_pcText, char a_cID )
+{
+ CHECKCONNECTION;
+
+ if ( NULL == a_pcText
+ || 0 == *a_pcText )
+ {
+ return;
+ }
+
+ int iLength = strlen( a_pcText );
+ if ( iLength > MAXSTRINGLENGTH ) iLength = MAXSTRINGLENGTH;
+
+ SMsgPackage oPackage;
+ oPackage.cID = a_cID;
+ oPackage.iLength = iLength;
+ strncpy( oPackage.acData, a_pcText, iLength );
+ oPackage.acData[iLength] = 0;
+
+ int iPackageLength = iLength + sizeof(char) + sizeof(Uint16);
+
+ int iRetval = SDLNet_TCP_Send( m_poSocket, &oPackage, iPackageLength );
+ if ( iRetval < iPackageLength ) DISCONNECTONCOMMUNICATIONERROR;
+}
+
+char* CMortalNetworkImpl::InternalReceiveString( void* a_pData, int a_iLength, int& a_riOutLength )
+{
+ a_riOutLength = -1;
+
+ // Verify data length vs package length
+
+ SMsgPackage* pcPackage = (SMsgPackage*) a_pData;
+ if ( a_iLength < (int) sizeof(char) + (int) sizeof(Uint16) + 1 )
+ {
+ DISCONNECTWITH(NULL);
+ }
+
+ a_riOutLength = sizeof(char) + sizeof(Uint16) + pcPackage->iLength;
+ if ( pcPackage->iLength > MAXSTRINGLENGTH
+ || a_iLength < a_riOutLength )
+ {
+ DISCONNECTWITH(NULL);
+ }
+
+ pcPackage->acData[ pcPackage->iLength ] = 0;
+ return pcPackage->acData;
+}
+
+
+
+
+
+void CMortalNetworkImpl::SendMsg( const char* a_pcMsg )
+{
+ InternalSendString( a_pcMsg, 'M' );
+}
+
+int CMortalNetworkImpl::ReceiveMsg( void* a_pData, int a_iLength )
+{
+ int iRetval;
+ char* pcMsg = InternalReceiveString( a_pData, a_iLength, iRetval );
+
+ if ( iRetval > 0 )
+ {
+ m_asMsgs.push_back( pcMsg );
+ }
+
+ return iRetval;
+}
+
+
+bool CMortalNetworkImpl::IsMsgAvailable()
+{
+ return m_asMsgs.size() > 0;
+}
+
+const char* CMortalNetworkImpl::GetMsg()
+{
+ static std::string sLastMsg;
+ if ( IsMsgAvailable() )
+ {
+ sLastMsg = m_asMsgs.front();
+ m_asMsgs.pop_front();
+ return sLastMsg.c_str();
+ }
+ return NULL;
+}
+
+
+
+
+/*************************************************************************
+ CHARACTER SELECTION RELATED METHODS
+*************************************************************************/
+
+
+
+
+bool CMortalNetworkImpl::IsRemoteFighterAvailable( FighterEnum a_enFighter )
+{
+ return true;
+}
+
+
+
+
+struct SFighterPackage
+{
+ char cID;
+ Uint32 iFighter;
+};
+
+void CMortalNetworkImpl::SendFighter( FighterEnum a_enFighter )
+{
+ CHECKCONNECTION;
+
+ SFighterPackage oPackage;
+ oPackage.cID = 'F';
+ oPackage.iFighter = SDL_SwapBE32( a_enFighter );
+ int iRetval = SDLNet_TCP_Send( m_poSocket, &oPackage, sizeof(oPackage) );
+ if ( iRetval < (int) sizeof(oPackage) ) DISCONNECTONCOMMUNICATIONERROR;
+}
+
+int CMortalNetworkImpl::ReceiveFighter( void* a_pcData, int a_iLength )
+{
+ SFighterPackage *poPackage = (SFighterPackage*) a_pcData;
+ if ( a_iLength < (int) sizeof(SFighterPackage) ) DISCONNECTWITH(-1);
+
+ m_enRemoteFighter = (FighterEnum) SDL_SwapBE32( poPackage->iFighter );
+ debug( "ReceiveFighter: %d\n", m_enRemoteFighter );
+ return sizeof( SFighterPackage );
+}
+
+FighterEnum CMortalNetworkImpl::GetRemoteFighter()
+{
+ return m_enRemoteFighter;
+}
+
+
+
+
+void CMortalNetworkImpl::SendReady()
+{
+ CHECKCONNECTION;
+
+ char cReady = 'R';
+ int iRetval = SDLNet_TCP_Send( m_poSocket, &cReady, sizeof(cReady) );
+ if ( iRetval != sizeof(cReady) ) DISCONNECTONCOMMUNICATIONERROR;
+}
+
+int CMortalNetworkImpl::ReceiveReady( void* a_pData, int a_iLength )
+{
+ if ( a_iLength < (int) sizeof(char) ) DISCONNECTWITH(-1);
+ m_bRemoteReady = true;
+ return sizeof(char);
+}
+
+bool CMortalNetworkImpl::IsRemoteSideReady()
+{
+ return m_bRemoteReady;
+}
+
+
+
+
+/*************************************************************************
+ GAME RELATED METHODS
+*************************************************************************/
+
+
+
+
+
+void CMortalNetworkImpl::SynchStartRound()
+{
+ m_bSynchQueryResponse = false;
+
+ // run until both sides manage to get a SYNCH
+
+ char cID = 'S';
+
+ while ( !m_bSynchQueryResponse )
+ {
+ CHECKCONNECTION;
+ int iRetval = SDLNet_TCP_Send( m_poSocket, &cID, 1 );
+ if ( iRetval < 1 ) DISCONNECTONCOMMUNICATIONERROR;
+ Update();
+ SDL_Delay(200);
+ if ( !IsConnectionAlive() ) break;
+ }
+}
+
+
+
+
+
+void CMortalNetworkImpl::SendGameData( const char* a_pcGameData )
+{
+ InternalSendString( a_pcGameData, 'G' );
+}
+
+int CMortalNetworkImpl::ReceiveGameData( void* a_pData, int a_iLength )
+{
+ int iRetval;
+ char* pcData = InternalReceiveString( a_pData, a_iLength, iRetval );
+
+ if ( iRetval > 0 )
+ {
+ m_sLatestGameData = pcData;
+ }
+
+ return iRetval;
+}
+
+const char* CMortalNetworkImpl::GetLatestGameData()
+{
+ return m_sLatestGameData.c_str();
+}
+
+
+
+
+struct SKeystrokePackage
+{
+ char cID;
+ char cKey;
+ bool bPressed;
+};
+
+void CMortalNetworkImpl::SendKeystroke( int a_iKey, bool a_bPressed )
+{
+ SKeystrokePackage oPackage;
+ oPackage.cID = 'K';
+ oPackage.cKey = a_iKey;
+ oPackage.bPressed = a_bPressed;
+
+ int iRetval = SDLNet_TCP_Send( m_poSocket, &oPackage, sizeof(oPackage) );
+ if ( iRetval < (int)sizeof(oPackage) ) DISCONNECTONCOMMUNICATIONERROR;
+}
+
+int CMortalNetworkImpl::ReceiveKeystroke( void* a_pData, int a_iLength )
+{
+ if ( a_iLength < (int)sizeof(SKeystrokePackage) ) DISCONNECTWITH(-1);
+ SKeystrokePackage* poPackage = (SKeystrokePackage*) a_pData;
+
+ m_aiKeystrokes.push_back( poPackage->cKey );
+ m_abKeystrokes.push_back( poPackage->bPressed );
+ return sizeof(SKeystrokePackage);
+}
+
+bool CMortalNetworkImpl::GetKeystroke( int& a_riOutKey, bool a_rbOutPressed )
+{
+ if ( m_aiKeystrokes.size() == 0 )
+ {
+ return false;
+ }
+ a_riOutKey = m_aiKeystrokes.front();
+ a_rbOutPressed = m_abKeystrokes.front();
+ m_aiKeystrokes.pop_front();
+ m_abKeystrokes.pop_front();
+ return true;
+}
+
+
+
+void CMortalNetworkImpl::SendRoundOver( int a_iWhoWon, bool a_bGameOver )
+{
+}
+
+
+int CMortalNetworkImpl::ReceiveRoundOver( void* a_pData, int a_iLength )
+{
+ return a_iLength;
+}
+
+bool CMortalNetworkImpl::IsRoundOver( int& a_riOutWhoWon )
+{
+ return false;
+}
+
+bool CMortalNetworkImpl::IsGameOver()
+{
+ return false;
+}
+
+
+
diff --git a/src/MortalNetworkImpl.h b/src/MortalNetworkImpl.h
new file mode 100644
index 0000000..6cad767
--- /dev/null
+++ b/src/MortalNetworkImpl.h
@@ -0,0 +1,113 @@
+/***************************************************************************
+ MortalNetworkImpl.h - description
+ -------------------
+ begin : Sun Jan 25 2004
+ copyright : (C) 2004 by upi
+ email : upi@feel
+ ***************************************************************************/
+
+#ifndef MORTALNETWORKIMPL_H
+#define MORTALNETWORKIMPL_H
+
+
+#include "MortalNetwork.h"
+#include "SDL_net.h"
+#include <string>
+#include <list>
+
+
+class CMortalNetworkImpl: public CMortalNetwork
+{
+public:
+ CMortalNetworkImpl();
+ virtual ~CMortalNetworkImpl();
+
+ // Connection's lifecycle
+
+ bool Start( const char* a_pcServerName );
+ void Stop(); // Disconnect
+ bool IsConnectionAlive(); // Is the connection still good?
+ void Update(); // Read network traffic. Might get disconnected...
+ const char* GetLastError();
+ bool IsMaster(); // Am I Master or Slave?
+
+ // Msg related methods
+
+ const char* GetRemoteUsername(); // This is the name that is passed upon connection.
+ void SendMsg( const char* a_pcMsg ); // Prompt the user for a line of chat text
+ bool IsMsgAvailable(); // Returns true is a chatline has arrived
+ const char* GetMsg(); // The next chatline, or NULL if there are no more.
+
+ // Charater Selection methods
+
+ bool IsRemoteFighterAvailable( FighterEnum a_enFighter ); // Does the other computer have fighter X installed?
+ FighterEnum GetRemoteFighter(); // Returns the latest fighter chosen by the remote side.
+ bool IsRemoteSideReady(); // The other player is finished choosing.
+
+ void SendFighter( FighterEnum a_enFighter ); // Let the other side know that I switched to fighter X.
+ void SendReady(); // Let the other side know that I am ready.
+
+ // Game methods
+
+ void SynchStartRound();
+ void SendGameData( const char* a_pcGameData );
+ const char* GetLatestGameData();
+ void SendKeystroke( int a_iKey, bool a_bPressed );
+ bool GetKeystroke( int& a_riOutKey, bool a_rbPressed );
+
+ void SendRoundOver( int a_iWhoWon, bool a_bGameOver );
+ bool IsRoundOver( int& a_riOutWhoWon );
+ bool IsGameOver();
+
+protected:
+ void InternalSendString( const char* a_pcText, char a_cID );
+ char* InternalReceiveString( void* a_pData, int a_iLength, int& a_riOutLength );
+
+ int ReceiveMsg( void* a_pData, int a_iLength );
+ int ReceiveGameData( void* a_pData, int a_iLength );
+ int ReceiveKeystroke( void* a_pData, int a_iLength );
+ int ReceiveFighter( void* a_pData, int a_iLength );
+ int ReceiveReady( void* a_pData, int a_iLength );
+ int ReceiveRoundOver( void* a_pData, int a_iLength );
+
+protected:
+ bool m_bNetworkAvailable;
+
+ enum TNetworkState
+ {
+ NS_DISCONNECTED,
+ NS_CHARACTER_SELECTION,
+ NS_IN_GAME,
+ };
+
+ TNetworkState m_enState;
+ bool m_bServer;
+ bool m_bMaster;
+ TCPsocket m_poSocket;
+ SDLNet_SocketSet m_poSocketSet;
+
+ std::string m_sLastError;
+
+ std::list<std::string> m_asMsgs;
+
+ // GAME DATA
+
+ FighterEnum m_enRemoteFighter;
+ bool m_bRemoteReady;
+
+ std::string m_sLatestGameData;
+ std::list<int> m_aiKeystrokes;
+ std::list<int> m_abKeystrokes;
+
+ bool m_bRoundOver;
+ int m_iWhoWon;
+ bool m_bGameOver;
+
+ // REMOTE QUERY RESPONSES
+
+ bool m_bSynchQueryResponse;
+};
+
+
+#endif // MORTALNETWORKIMPL_H
+
diff --git a/src/PlayerSelect.cpp b/src/PlayerSelect.cpp
index dbf876c..c462440 100644
--- a/src/PlayerSelect.cpp
+++ b/src/PlayerSelect.cpp
@@ -1,498 +1,558 @@
/***************************************************************************
PlayerSelect.cpp - description
-------------------
begin : Sun Dec 8 2002
copyright : (C) 2002 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include <stdio.h>
#include "PlayerSelect.h"
#include "SDL.h"
#include "SDL_video.h"
#include "SDL_image.h"
#include "sge_primitives.h"
#include "common.h"
#include "Audio.h"
#include "sge_bm_text.h"
#include "gfx.h"
#include "RlePack.h"
#include "Backend.h"
#include "State.h"
+#include "MortalNetwork.h"
#define CHOOSERLEFT 158
#define CHOOSERTOP 74
#define CHOOSERHEIGHT 80
#define CHOOSERWIDTH 80
#define CHOOSERROWS 5
#define CHOOSERCOLS 4
#ifndef NULL
#define NULL 0
#endif
/***************************************************************************
PUBLIC EXPORTED VARIABLES
***************************************************************************/
PlayerSelect g_oPlayerSelect;
/***************************************************************************
PRIVATE VARIABLES (perl variable space)
***************************************************************************/
/*
int p1 = 0;
int p2 = 3;
bool done1 = false;
bool done2 = false;
*/
/*
FighterEnum ChooserCells[CHOOSERROWS][CHOOSERCOLS] = {
{ ZOLI, UPI, CUMI, SIRPI },
{ ULMAR, MACI, BENCE, GRIZLI },
{ AMBRUS, DESCANT, SURBA, DANI },
{ UNKNOWN, KINGA, MISI, UNKNOWN },
};
*/
FighterEnum ChooserCells[CHOOSERROWS][CHOOSERCOLS] = {
{ ZOLI, UPI, CUMI, SIRPI },
{ ULMAR, MACI, GRIZLI, DESCANT },
{ DANI, AMBRUS, BENCE, SURBA },
{ (FighterEnum)100, (FighterEnum)101, (FighterEnum)102, (FighterEnum)103 },
{ (FighterEnum)104, (FighterEnum)105, KINGA, MISI }
};
PlayerSelect::PlayerSelect()
{
for ( int i=0; i<2; ++i )
{
m_aoPlayers[i].m_enFighter = UNKNOWN;
m_aoPlayers[i].m_enTint = NO_TINT;
m_aoPlayers[i].m_poPack = NULL;
}
m_iP1 = 0;
m_iP2 = CHOOSERCOLS-1;
}
const PlayerInfo& PlayerSelect::GetPlayerInfo( int a_iPlayer )
{
return m_aoPlayers[ a_iPlayer ? 1 : 0 ];
}
const char* PlayerSelect::GetFighterName( int a_iPlayer )
{
return m_aoPlayers[ a_iPlayer ? 1 : 0 ].m_sFighterName.c_str();
}
int PlayerSelect::GetFighterNameWidth( int a_iPlayer )
{
return m_aiFighterNameWidth[ a_iPlayer ? 1 : 0 ];
}
bool PlayerSelect::IsFighterAvailable( FighterEnum a_enFighter )
{
- /*
- static bool g_abFighterAvailable[ LASTFIGHTER ] =
- {
- false,
- true, true, true, true,
- true, true, true, true,
- true, false, false, false,
- false, false
- };
- */
-
if ( a_enFighter <= UNKNOWN )
{
return false;
}
g_oBackend.PerlEvalF("GetFighterStats(%d);", a_enFighter);
const char* pcDatafile = g_oBackend.GetPerlString("Datafile");
return ( pcDatafile && *pcDatafile );
}
/** LoadFighter simply looks up the filename associated with the given
fighter, loads it, and returns the RlePack.
\return The freshly loaded RlePack, or NULL if it could not be loaded.
*/
RlePack* PlayerSelect::LoadFighter( FighterEnum m_enFighter ) // static
{
char a_pcFilename[FILENAME_MAX+1];
const char* s;
g_oBackend.PerlEvalF( "GetFighterStats(%d);", m_enFighter );
s = g_oBackend.GetPerlString( "Datafile" );
strcpy( a_pcFilename, DATADIR );
strcat( a_pcFilename, "/characters/" );
strcat( a_pcFilename, s );
RlePack* pack = new RlePack( a_pcFilename, COLORSPERPLAYER );
if ( pack->Count() <= 0 )
{
debug( "Couldn't load RlePack: '%s'\n", a_pcFilename );
delete pack;
return NULL;
}
return pack;
}
/** SetPlayer loads the given fighter for the given player.
The RlePack is loaded first. If that succeeds, then the perl backend is
set too. The tint and palette of both players are set. */
void PlayerSelect::SetPlayer( int a_iPlayer, FighterEnum a_enFighter )
{
if ( a_iPlayer ) a_iPlayer = 1; // It's 0 or 1.
if ( m_aoPlayers[a_iPlayer].m_enFighter == a_enFighter )
{
return;
}
if ( !IsFighterAvailable( a_enFighter ) )
{
return;
}
int iOffset = a_iPlayer ? COLOROFFSETPLAYER2 : COLOROFFSETPLAYER1;
RlePack* poPack = LoadFighter( a_enFighter );
poPack->OffsetSprites( iOffset );
if ( NULL == poPack )
{
debug( "SetPlayer(%d,%d): Couldn't load RlePack\n", a_iPlayer, a_enFighter );
return;
}
delete m_aoPlayers[a_iPlayer].m_poPack;
m_aoPlayers[a_iPlayer].m_poPack = poPack;
m_aoPlayers[a_iPlayer].m_enFighter = a_enFighter;
g_oBackend.PerlEvalF( "SetPlayerNumber(%d,%d);", a_iPlayer, a_enFighter );
m_aoPlayers[a_iPlayer].m_sFighterName = g_oBackend.GetPerlString( "PlayerName" );
m_aiFighterNameWidth[a_iPlayer] = sge_BF_TextSize( fastFont, GetFighterName(a_iPlayer) ).w;
TintEnum enTint = NO_TINT;
if ( m_aoPlayers[0].m_enFighter == m_aoPlayers[1].m_enFighter )
{
enTint = TintEnum( (rand() % 4) + 1 );
}
SetTint( 1, enTint );
m_aoPlayers[a_iPlayer].m_poPack->ApplyPalette();
}
void PlayerSelect::SetTint( int a_iPlayer, TintEnum a_enTint )
{
m_aoPlayers[a_iPlayer].m_enTint = a_enTint;
if ( m_aoPlayers[a_iPlayer].m_poPack )
{
m_aoPlayers[a_iPlayer].m_poPack->SetTint( a_enTint );
m_aoPlayers[a_iPlayer].m_poPack->ApplyPalette();
}
}
+bool PlayerSelect::IsNetworkGame()
+{
+ return SState::IN_NETWORK == g_oState.m_enGameMode;
+}
+
void PlayerSelect::HandleKey( int a_iPlayer, int a_iKey )
{
+ // If we are in network mode, all keys count as the local player's...
+ if ( IsNetworkGame() )
+ {
+ a_iPlayer = g_poNetwork->IsMaster() ? 0 : 1;
+ }
+
int& riP = a_iPlayer ? m_iP2 : m_iP1;
int iOldP = riP;
bool& rbDone = a_iPlayer ? m_bDone2 : m_bDone1;
if ( rbDone )
{
return;
}
-
switch ( a_iKey )
{
case 0: // up
if ( riP >= CHOOSERCOLS ) riP -= CHOOSERCOLS;
break;
case 1: // down
if ( (riP/CHOOSERCOLS) < (CHOOSERROWS-1) ) riP += CHOOSERCOLS;
break;
case 2: // left
if ( (riP % CHOOSERCOLS) > 0 ) riP--;
break;
case 3: // right
if ( (riP % CHOOSERCOLS) < (CHOOSERCOLS-1) ) riP++;
break;
default:
if ( IsFighterAvailable( ChooserCells[riP/CHOOSERCOLS][riP%CHOOSERCOLS] ) )
{
- rbDone = true;
+ Audio->PlaySample("magic.voc");
+ rbDone = true;
g_oBackend.PerlEvalF( "PlayerSelected(%d);", a_iPlayer );
- Audio->PlaySample("magic.voc");
+ if ( IsNetworkGame() )
+ {
+ g_poNetwork->SendFighter( ChooserCells[riP/CHOOSERCOLS][riP%CHOOSERCOLS] );
+ g_poNetwork->SendReady();
+ }
return;
}
}
if ( iOldP != riP )
{
Audio->PlaySample("strange_quack.voc");
if ( IsFighterAvailable( ChooserCells[riP/CHOOSERCOLS][riP%CHOOSERCOLS] ) )
{
+ if ( IsNetworkGame() )
+ {
+ g_poNetwork->SendFighter( ChooserCells[riP/CHOOSERCOLS][riP%CHOOSERCOLS] );
+ }
SetPlayer( a_iPlayer, ChooserCells[riP/CHOOSERCOLS][riP%CHOOSERCOLS] );
}
}
}
+void PlayerSelect::HandleNetwork()
+{
+ g_poNetwork->Update();
+
+ bool bMaster = g_poNetwork->IsMaster();
+ int iPlayer = bMaster ? 1 : 0;
+ int& riP = bMaster ? m_iP2 : m_iP1;
+ bool& rbDone = bMaster ? m_bDone2 : m_bDone1;
+
+ if ( rbDone )
+ {
+ return;
+ }
+
+ int iOldP = riP;
+ FighterEnum enOldFighter = ChooserCells[iOldP/CHOOSERCOLS][iOldP%CHOOSERCOLS];
+ FighterEnum enRemoteFighter = g_poNetwork->GetRemoteFighter();
+
+ if ( enOldFighter != enRemoteFighter
+ && enRemoteFighter != UNKNOWN )
+ {
+ SetPlayer( iPlayer, enRemoteFighter );
+ int i, j;
+ for ( i=0; i<CHOOSERROWS; ++i )
+ {
+ for ( int j=0; j<CHOOSERCOLS; ++j )
+ {
+ if ( ChooserCells[i][j] == enRemoteFighter )
+ {
+ riP = i * CHOOSERCOLS + j;
+ break;
+ }
+ }
+ }
+ }
+
+ bool bDone = g_poNetwork->IsRemoteSideReady();
+ if ( bDone )
+ {
+ rbDone = true;
+ Audio->PlaySample("magic.voc");
+ g_oBackend.PerlEvalF( "PlayerSelected(%d);", iPlayer );
+ }
+}
+
+
void PlayerSelect::DrawRect( int a_iPos, int a_iColor )
{
int iRow = a_iPos / CHOOSERCOLS;
int iCol = a_iPos % CHOOSERCOLS;
SDL_Rect r, r1;
r.x = CHOOSERLEFT + iCol * CHOOSERWIDTH;
r.y = CHOOSERTOP + iRow * CHOOSERHEIGHT;
r.w = CHOOSERWIDTH + 5;
r.h = 5;
r1 = r;
SDL_FillRect( gamescreen, &r1, a_iColor );
r.y += CHOOSERHEIGHT;
r1 = r;
SDL_FillRect( gamescreen, &r1, a_iColor );
r.y -= CHOOSERHEIGHT;
r.w = 5;
r.h = CHOOSERHEIGHT + 5;
r1 = r;
SDL_FillRect( gamescreen, &r1, a_iColor );
r.x += CHOOSERWIDTH;
r1 = r;
SDL_FillRect( gamescreen, &r1, a_iColor );
}
void PlayerSelect::CheckPlayer( SDL_Surface* a_poBackground, int a_iRow, int a_iCol )
{
int x1, y1;
x1 = CHOOSERLEFT + a_iCol * CHOOSERWIDTH +5;
y1 = CHOOSERTOP + a_iRow * CHOOSERHEIGHT +5;
sge_Line(a_poBackground, x1+5, y1+5, x1 + CHOOSERWIDTH-10, y1 + CHOOSERHEIGHT-10, 252);
sge_Line(a_poBackground, x1 + CHOOSERWIDTH-10, y1+5, x1+5, y1 + CHOOSERHEIGHT-10, 252);
x1++;
sge_Line(a_poBackground, x1+5, y1+5, x1 + CHOOSERWIDTH-10, y1 + CHOOSERHEIGHT-10, 252);
sge_Line(a_poBackground, x1 + CHOOSERWIDTH-10, y1+5, x1+5, y1 + CHOOSERHEIGHT-10, 252);
y1++;
sge_Line(a_poBackground, x1+5, y1+5, x1 + CHOOSERWIDTH-10, y1 + CHOOSERHEIGHT-10, 252);
sge_Line(a_poBackground, x1 + CHOOSERWIDTH-10, y1+5, x1+5, y1 + CHOOSERHEIGHT-10, 252);
x1--;
sge_Line(a_poBackground, x1+5, y1+5, x1 + CHOOSERWIDTH-10, y1 + CHOOSERHEIGHT-10, 252);
sge_Line(a_poBackground, x1 + CHOOSERWIDTH-10, y1+5, x1+5, y1 + CHOOSERHEIGHT-10, 252);
}
void PlayerSelect::DoPlayerSelect()
{
// 1. Set up: Load background, mark unavailable fighters
SDL_FillRect( gamescreen, NULL, C_BLACK );
SDL_Flip( gamescreen );
SDL_Surface* poBackground = LoadBackground( "PlayerSelect.png", 111 );
DrawGradientText( "Choose A Fighter Dammit", titleFont, 10, poBackground );
int i, j;
for ( i=0; i<CHOOSERROWS; ++i )
{
for ( int j=0; j<CHOOSERCOLS; ++j )
{
if ( !IsFighterAvailable(ChooserCells[i][j]) &&
UNKNOWN != ChooserCells[i][j] )
{
CheckPlayer( poBackground, i, j );
}
}
}
for ( i=0; i<2; ++i )
{
if ( m_aoPlayers[i].m_poPack ) m_aoPlayers[i].m_poPack->ApplyPalette();
}
SetPlayer( 0, ChooserCells[m_iP1/CHOOSERCOLS][m_iP1%CHOOSERCOLS] );
SetPlayer( 1, ChooserCells[m_iP2/CHOOSERCOLS][m_iP2%CHOOSERCOLS] );
// 2. Run selection screen
g_oBackend.PerlEvalF( "SelectStart();" );
m_bDone1 = m_bDone2 = false;
int thisTick, lastTick, gameSpeed;
gameSpeed = 12 ;
thisTick = SDL_GetTicks() / gameSpeed;
lastTick = thisTick - 1;
i = 0;
int over = 0;
int iCourtain = 0;
int iCourtainSpeed = 0;
int iCourtainTime = 80;
SDL_Event event;
while (1)
{
// 1. Wait for the next tick (on extremely fast machines..)
while (1)
{
thisTick = SDL_GetTicks() / gameSpeed;
if ( thisTick==lastTick )
{
SDL_Delay(1);
}
else
{
break;
}
}
// 2. Advance as many ticks as necessary..
if ( iCourtainTime > 0 )
{
int iAdvance = thisTick - lastTick;
if ( iAdvance > 5 ) iAdvance = 5;
if ( iCourtain + iCourtainSpeed * iCourtainTime /2 < 320 * 4 )
iCourtainSpeed += iAdvance;
else
iCourtainSpeed -= iAdvance;
iCourtain += iCourtainSpeed * iAdvance;
iCourtainTime -= iAdvance;
if ( iCourtainTime > 0 )
{
SDL_Rect oRect;
oRect.x = 320 - iCourtain/4; oRect.y = 0;
oRect.w = iCourtain / 2; oRect.h = gamescreen->h;
if ( oRect.x < 0 ) oRect.x = 0;
if ( oRect.w > gamescreen->w ) oRect.w = gamescreen->w;
SDL_SetClipRect( gamescreen, &oRect );
}
else
{
SDL_SetClipRect( gamescreen, NULL );
}
}
int iNumFrames = thisTick - lastTick;
if ( iNumFrames>5 ) iNumFrames = 5;
for ( i=0; i<iNumFrames; ++i )
{
g_oBackend.AdvancePerl();
}
lastTick = thisTick;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
g_oState.m_bQuitFlag = true;
break;
case SDL_KEYDOWN:
{
if ( event.key.keysym.sym == SDLK_ESCAPE )
{
DoMenu( false );
break;
}
for ( i=0; i<2; i++ )
{
for ( j=0; j<9; j++ )
{
if (g_oState.m_aiPlayerKeys[i][j] == event.key.keysym.sym)
{
DrawRect( m_iP1, 240 );
DrawRect( m_iP2, 240 );
HandleKey( i, j );
}
}
}
}
break;
} // switch statement
} // Polling events
+ if ( IsNetworkGame() )
+ {
+ HandleNetwork();
+ }
+
g_oBackend.ReadFromPerl();
over = g_oBackend.m_iGameOver;
SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
if ( !m_bDone1) DrawRect( m_iP1, 250 );
if ( !m_bDone2) DrawRect( m_iP2, 253 );
for ( i=0; i<2; ++i )
{
if ( g_oBackend.m_aoPlayers[i].m_iFrame )
{
m_aoPlayers[i].m_poPack->Draw(
ABS(g_oBackend.m_aoPlayers[i].m_iFrame)-1,
g_oBackend.m_aoPlayers[i].m_iX, g_oBackend.m_aoPlayers[i].m_iY,
g_oBackend.m_aoPlayers[i].m_iFrame < 0 );
}
int x = ( CHOOSERLEFT - m_aiFighterNameWidth[i] ) / 2;
if ( x<10 ) x = 10;
if ( i ) x = gamescreen->w - x - m_aiFighterNameWidth[i];
sge_BF_textout( gamescreen, fastFont, GetFighterName(i),
x, gamescreen->h - 30 );
}
SDL_Flip( gamescreen );
if (over || g_oState.m_bQuitFlag || SState::IN_DEMO == g_oState.m_enGameMode) break;
}
SDL_FreeSurface( poBackground );
SDL_SetClipRect( gamescreen, NULL );
return;
}
diff --git a/src/PlayerSelect.h b/src/PlayerSelect.h
index 81dec57..2ed09f0 100644
--- a/src/PlayerSelect.h
+++ b/src/PlayerSelect.h
@@ -1,82 +1,84 @@
/***************************************************************************
PlayerSelect.h - description
-------------------
begin : 2003-09-05
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef PLAYERSELECT_H
#define PLAYERSELECT_H
#define COLORSPERPLAYER 64
#define COLOROFFSETPLAYER1 112
#define COLOROFFSETPLAYER2 (COLOROFFSETPLAYER1+64)
#include "FighterEnum.h"
#include <string>
class RlePack;
struct SDL_Surface;
/** PlayerInfo structure stores information about a PLAYER.
In OpenMortal, the term PLAYER refers to one of the two guys playing the
game, as opposed to FIGHTER, which refers to one of the many playable
characters.
PlayerInfo stores: the player's selected fighter, the fighters tint and
RlePack. */
struct PlayerInfo
{
FighterEnum m_enFighter;
TintEnum m_enTint;
RlePack* m_poPack;
std::string m_sFighterName;
};
/** This class implements services that allows players to select their
fighters. It also stores info about which fighter is available, and
allows other parts of the program to programmatically assign a fighter
to a player, and set fighter tints (this is used by e.g. the "frozen"
effect.) */
class PlayerSelect
{
public:
PlayerSelect();
const PlayerInfo& GetPlayerInfo( int a_iPlayer );
const char* GetFighterName( int a_iPlayer );
int GetFighterNameWidth( int a_iPlayer );
void DoPlayerSelect();
void SetPlayer( int a_iPlayer, FighterEnum a_enFighter );
void SetTint( int a_iPlayer, TintEnum a_enFighter );
bool IsFighterAvailable( FighterEnum a_enFighter );
protected:
void HandleKey( int a_iPlayer, int a_iKey );
+ void HandleNetwork();
void DrawRect( int a_iPos, int a_iColor );
void CheckPlayer( SDL_Surface* a_poBackground, int a_iRow, int a_iCol );
static RlePack* LoadFighter( FighterEnum m_enFighter );
+ bool IsNetworkGame();
protected:
PlayerInfo m_aoPlayers[2];
int m_iP1, m_iP2; // Chooser cells for player 1 and 2
bool m_bDone1, m_bDone2; // Has player n chosen a player?
int m_aiFighterNameWidth[2];
};
extern PlayerSelect g_oPlayerSelect;
#endif // PLAYERSELECT_H
diff --git a/src/main.cpp b/src/main.cpp
index afafe4b..a903f46 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,361 +1,382 @@
/***************************************************************************
main.cpp - description
-------------------
begin : Wed Aug 22 10:18:47 CEST 2001
copyright : (C) 2001 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "PlayerSelect.h"
#include "SDL_video.h"
#include "sge_tt_text.h"
#include "sge_bm_text.h"
#include "sge_surface.h"
#include "SDL.h"
#include "SDL_image.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <string>
#include "common.h"
#include "gfx.h"
#include "Audio.h"
#include "RlePack.h"
#include "Backend.h"
#include "State.h"
-#include "Demo.h"
+#include "FighterStats.h"
+#include "MortalNetwork.h"
#ifdef _WINDOWS
#undef DATADIR // GRRR.. windows keyword...
#include <windows.h>
#define DATADIR "../data"
#endif
_sge_TTFont* inkFont;
_sge_TTFont* impactFont;
_sge_TTFont* titleFont;
sge_bmpFont* fastFont;
sge_bmpFont* creditsFont;
sge_bmpFont* storyFont;
SDL_Color Colors[] =
{
{ 0, 0, 0, 0 }, { 0, 0, 42, 0 }, { 0, 42, 0, 0 }, { 0, 42, 42, 0 },
{ 42, 0, 0, 0 }, { 42, 0, 42, 0 }, { 63, 42, 0, 0 }, { 42, 42, 42, 0 },
{ 21, 21, 21, 0 }, { 21, 21, 63, 0 }, { 21, 63, 21, 0 }, { 21, 63, 63, 0 },
{ 63, 21, 21, 0 }, { 63, 21, 63, 0 }, { 63, 63, 21, 0 }, { 63, 63, 63, 0 }
};
void Complain( const char* a_pcError )
{
#ifdef _WINDOWS
::MessageBoxA( 0, a_pcError, "OpenMortal", MB_ICONEXCLAMATION );
#else
fprintf( stderr, "%s", a_pcError );
#endif
}
_sge_TTFont* LoadTTF( const char* a_pcFilename, int a_iSize )
{
std::string sPath = std::string(DATADIR) + "/fonts/" + a_pcFilename;
_sge_TTFont* poFont = sge_TTF_OpenFont( sPath.c_str(), a_iSize );
if ( NULL == poFont )
{
Complain( ("Couldn't load font: " + sPath).c_str() );
}
+
+
+
+
return poFont;
}
sge_bmpFont* LoadBMPFont( const char* a_pcFilename )
{
std::string sPath = std::string(DATADIR) + "/fonts/" + a_pcFilename;
sge_bmpFont* poFont = sge_BF_OpenFont( sPath.c_str(), SGE_BFSFONT | SGE_BFTRANSP );
if ( NULL == poFont )
{
Complain( ("Couldn't load font: " + sPath).c_str() );
}
return poFont;
}
int init( int iFlags )
{
if (SDL_Init(SDL_INIT_VIDEO /*| SDL_INIT_AUDIO*/) < 0)
{
fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError());
return -1;
}
atexit(SDL_Quit);
int d = SDL_VideoModeOK(640, 480, 8, iFlags);
if (d == 0)
{
fprintf(stderr, "requested video mode not available\n");
// return -1;
}
gamescreen = SDL_SetVideoMode(640, 480, 8, iFlags);
if (gamescreen == NULL)
{
fprintf(stderr, "failed to set video mode: %s\n", SDL_GetError());
return -1;
}
SDL_WM_SetCaption( "OpenMortal", "OpenMortal" );
std::string sPath = std::string(DATADIR) + "/gfx/icon.png";
SDL_WM_SetIcon(IMG_Load(sPath.c_str()), NULL);
SDL_ShowCursor( SDL_DISABLE );
for ( int i=0; i<16; ++i ) { Colors[i].r *=4; Colors[i].g *=4; Colors[i].b *=4; }
SDL_SetColors( gamescreen, Colors, 256-16, 16 );
if ( sge_TTF_Init() )
{
fprintf(stderr, "couldn't start ttf engine: %s\n", SDL_GetError());
return -1;
}
sge_TTF_AAOff();
- inkFont = LoadTTF( "aardvark.ttf", 24 );
+ inkFont = LoadTTF( "aardvark.ttf", 20 );
if ( !inkFont ) return -1;
- impactFont = LoadTTF( "gooddogc.ttf", 20 );
+ impactFont = LoadTTF( "bradybun.ttf", 20 ); // gooddogc.ttf, 20
if ( !impactFont ) return -1;
- titleFont = LoadTTF( "manslem.ttf", 40 );
+ titleFont = LoadTTF( "deadgrit.ttf", 48 ); // deadgrit.ttf, 48
if ( !titleFont ) return -1;
- fastFont = LoadBMPFont( "impactfont2.png" );
+ fastFont = LoadBMPFont( "brandybun3.png" );
if ( !fastFont ) return -1;
- //SDL_SetColorKey( fastFont->FontSurface, SDL_SRCCOLORKEY | SDL_RLEACCEL,
- // sge_GetPixel(fastFont->FontSurface,0,fastFont->FontSurface->h-1) );
- creditsFont = LoadBMPFont( "fangfont.png" );
- storyFont = LoadBMPFont( "glossyfont.png" );
+ creditsFont = LoadBMPFont( "CreditsFont2.png" );//"fangfont.png" );
if ( !creditsFont ) return -1;
+ storyFont = LoadBMPFont( "glossyfont.png" );
+ if ( !storyFont ) return -1;
return 0;
}
int init2()
{
if ( !g_oBackend.Construct() )
{
+
fprintf(stderr, "couldn't start backend.\n" );
return -1;
}
return 0;
}
int DrawMainScreen()
{
SDL_Surface* background = LoadBackground( "Mortal.png", 240 );
SDL_Rect r;
r.x = r.y = 0;
std::string sStaffFilename = DATADIR;
sStaffFilename += "/characters/STAFF.DAT";
RlePack pack( sStaffFilename.c_str(), 240 );
pack.ApplyPalette();
//SDL_SetColors( gamescreen, pack.getPalette(), 0, 240 );
SDL_BlitSurface( background, NULL, gamescreen, &r );
SDL_Flip( gamescreen );
char* filename[15] = {
"Jacint.pl", "Jozsi.pl", "Agent.pl", "Mrsmith.pl",
"Sleepy.pl", "Tejszin.pl",
"UPi.pl", "Zoli.pl", "Ulmar.pl", "Bence.pl",
"Descant.pl", "Grizli.pl", "Sirpi.pl", "Macy.pl", "Cumi.pl" };
int x[14] = {
0, 26, 67, 125, 159, 209,
249, 289, 358, 397, 451, 489, 532, 161 };
int y[14] = {
5, 4, 5, 5, 5, 7,
4, 0, 7, 5, 5, 6, 5, 243 };
int i;
g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Ambrus.pl';\" )", DATADIR );
g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Dani.pl';\" )", DATADIR );
for ( i=0; i<15; ++i )
{
pack.Draw( i, x[i], y[i], false );
SDL_Flip( gamescreen );
if ( filename[i] != NULL )
{
debug( "Loading fighter %s", filename[i] );
g_oBackend.PerlEvalF( "eval( \"require '%s/characters/%s';\" )", DATADIR, filename[i] );
}
}
int retval = 0;
i = 0;
- SDL_Event event;
SDL_FreeSurface( background );
return retval;
}
int main(int argc, char *argv[])
{
srand( (unsigned int)time(NULL) );
if ( 0 != init2() )
{
fprintf( stderr, "init2() failed." );
return -1;
}
g_oState.m_pcArgv0 = argv[0];
g_oState.Load();
+ CMortalNetwork::Create();
bool bDebug = false;
int iFlags = SDL_SWSURFACE | SDL_HWPALETTE;
if ( g_oState.m_bFullscreen )
{
iFlags |= SDL_FULLSCREEN;
}
int i;
for ( i=1; i<argc; ++i )
{
if ( !strcmp(argv[i], "-debug") )
{
bDebug = true;
}
else if ( !strcmp(argv[i], "-fullscreen") )
{
iFlags |= SDL_FULLSCREEN;
}
else if ( !strcmp(argv[i], "-hwsurface") )
{
iFlags |= SDL_HWSURFACE;
}
else if ( !strcmp(argv[i], "-doublebuf") )
{
iFlags |= SDL_DOUBLEBUF;
}
else if ( !strcmp(argv[i], "-anyformat") )
{
iFlags |= SDL_ANYFORMAT;
}
else
{
printf( "Usage: %s [-debug] [-fullscreen] [-hwsurface] [-doublebuf] [-anyformat]\n", argv[0] );
return 0;
}
}
if (init( iFlags )<0)
{
return -1;
}
+
+ g_oState.SetLanguage( g_oState.m_acLanguage );
new MszAudio;
Audio->LoadMusic( "Last_Ninja_-_The_Wilderness.mid", "DemoMusic" );
Audio->PlayMusic( "DemoMusic" );
Audio->LoadMusic( "2nd_pm.s3m", "GameMusic" );
DrawMainScreen();
g_oPlayerSelect.SetPlayer( 0, ZOLI );
g_oPlayerSelect.SetPlayer( 1, SIRPI );
-
+
+ /*
int nextFighter = 0;
int describeOrder[ (int)LASTFIGHTER ];
for ( i=0; i<(int)LASTFIGHTER; ++i ) describeOrder[i] = i;
for ( i=0; i<100; ++i )
{
int j = rand() % (int)LASTFIGHTER;
int k = rand() % (int)LASTFIGHTER;
int l;
l = describeOrder[j];
describeOrder[j] = describeOrder[k];
describeOrder[k] = l;
}
+ */
/*
{
int iGameNumber=0;
char acReplayFile[1024];
for ( i=0; i<15; ++i )
{
sprintf( acReplayFile, DATADIR "/msz%i.replay", i );
DrawTextMSZ( acReplayFile, impactFont, 10, 10, 0, C_WHITE, gamescreen );
SDL_Delay(5000 );
DoGame( acReplayFile, true, bDebug );
}
}
*/
+ bool bNetworkGame = false;
while ( 1 )
{
if ( g_oState.m_bQuitFlag ) break;
DoDemos();
if ( g_oState.m_bQuitFlag ) break;
Audio->PlaySample( "car_start.voc" );
Audio->PlayMusic( "GameMusic" );
+ bNetworkGame = false;
+
while ( g_oState.m_enGameMode != SState::IN_DEMO
&& !g_oState.m_bQuitFlag )
{
+ bNetworkGame = SState::IN_NETWORK == g_oState.m_enGameMode;
+
g_oPlayerSelect.DoPlayerSelect();
if ( g_oState.m_bQuitFlag || g_oState.m_enGameMode == SState::IN_DEMO ) break;
//sprintf( acReplayFile, "/tmp/msz%d.replay", ++iGameNumber );
int iGameResult = DoGame( NULL, false, bDebug );
//int iGameResult = DoGame( acReplayFile, false, bDebug );
//DoGame( acReplayFile, true, bDebug );
if ( g_oState.m_bQuitFlag || g_oState.m_enGameMode == SState::IN_DEMO ) break;
debug ( "iGameResult = %d\n", iGameResult );
if ( iGameResult >= 0 )
{
GameOver( iGameResult );
FighterStatsDemo oDemo( g_oPlayerSelect.GetPlayerInfo( iGameResult ).m_enFighter );
oDemo.Run();
}
if ( g_oState.m_bQuitFlag || g_oState.m_enGameMode == SState::IN_DEMO ) break;
}
+ if ( bNetworkGame && !g_oState.m_bQuitFlag )
+ {
+ DrawTextMSZ( "Connection closed.", inkFont, 320, 210, AlignHCenter | UseShadow, C_WHITE, gamescreen );
+ DrawTextMSZ( g_poNetwork->GetLastError(), impactFont, 320, 250, AlignHCenter | UseShadow, C_WHITE, gamescreen );
+ GetKey();
+ }
+
if ( g_oState.m_bQuitFlag ) break;
Audio->PlayMusic( "DemoMusic" );
}
g_oState.Save();
SDL_Quit();
return EXIT_SUCCESS;
}
diff --git a/src/menu.cpp b/src/menu.cpp
index 8224833..a5ad14d 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -1,759 +1,1051 @@
-/***************************************************************************
- menu.cpp - description
- -------------------
- begin : Sun Aug 3 2003
- copyright : (C) 2003 by upi
- email : upi@apocalypse.rulez.org
- ***************************************************************************/
-
-#include "SDL.h"
-#include "SDL_video.h"
-
-#include "menu.h"
-#include "gfx.h"
-#include "State.h"
-#include "common.h"
-#include "Audio.h"
-#include "Backend.h"
-
-
-enum
-{
-/* Master menu structure:
-MAIN MENU
-*/
-MENU_UNKNOWN,
- MENU_SURRENDER,
- MENU_SINGLE_PLAYER,
- MENU_EASY,
- MENU_MEDIUM,
- MENU_HARD,
- MENU_MULTI_PLAYER,
- MENU_OPTIONS,
- MENU_GAME_SPEED,
- MENU_GAME_TIME, // ( :30 - 5:00 )
+/***************************************************************************
+ menu.cpp - description
+ -------------------
+ begin : Sun Aug 3 2003
+ copyright : (C) 2003 by upi
+ email : upi@apocalypse.rulez.org
+ ***************************************************************************/
+
+#include "SDL.h"
+#include "SDL_video.h"
+
+#include "menu.h"
+#include "gfx.h"
+#include "State.h"
+#include "common.h"
+#include "Audio.h"
+#include "Backend.h"
+#include "sge_tt_text.h"
+#include "MortalNetwork.h"
+
+#include <stdarg.h>
+
+
+enum
+{
+/* Master menu structure:
+MAIN MENU
+*/
+MENU_UNKNOWN,
+ MENU_SURRENDER,
+ MENU_SINGLE_PLAYER,
+ MENU_EASY,
+ MENU_MEDIUM,
+ MENU_HARD,
+ MENU_MULTI_PLAYER,
+ MENU_NETWORK_GAME,
+ MENU_SERVER,
+ MENU_HOSTNAME,
+ MENU_CONNECT,
+ MENU_CANCEL,
+ MENU_OPTIONS,
+ MENU_GAME_SPEED,
+ MENU_GAME_TIME, // ( :30 - 5:00 )
MENU_TOTAL_HIT_POINTS, // ( 25 - 1000 )
- MENU_SOUND,
- MENU_CHANNELS, // MONO / STEREO
+ MENU_SOUND,
+ MENU_CHANNELS, // MONO / STEREO
+
MENU_MIXING_RATE, // 11kHz / 22kHz / 44.1 kHz
MENU_BITS, // 8 bit / 16 bit
MENU_MUSIC_VOLUME, // (0% - 100%)
MENU_SOUND_VOLUME, // (0% - 100%)
- MENU_SOUND_OK,
- MENU_FULLSCREEN,
- MENU_KEYS_RIGHT,
- MENU_KEYS_LEFT,
- MENU_OPTIONS_OK,
- MENU_INFO,
- MENU_QUIT, // (confirm)
-};
-
-
-const char* g_ppcGameTime[] = { "0:30", "0:45", "1:00", "1:15", "1:30", "1:45", "2:00", "3:00", "5:00", NULL };
-const int g_piGameTime[] = { 30, 45, 60, 75, 90, 105, 120, 180, 300 };
-const char* g_ppcHitPoints[] = { "BABY", "VERY LOW", "LOW", "NORMAL", "HIGH", "VERY HIGH", "NEAR IMMORTAL", NULL };
-const int g_piHitPoints[] = { 1, 10, 50, 100, 150, 200, 500 };
-const char* g_ppcGameSpeed[] = { "SNAIL RACE", "SLOW", "NORMAL", "TURBO", "KUNG-FU MOVIE", NULL };
-const int g_piGameSpeed[] = { 16, 14, 12, 10, 8 };
-const char* g_ppcChannels[] = { "MONO", "STEREO", NULL };
-const int g_piChannels[] = { 1, 2 };
-const char* g_ppcMixingRate[] = { "LOW", "MEDIUM", "HIGH", NULL };
-const int g_piMixingRate[] = { 1, 2, 3 };
-const char* g_ppcMixingBits[] = { "8 bit", "16 bit", NULL };
-const int g_piMixingBits[] = { 1, 2 };
-const char* g_ppcVolume[] = { "OFF", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%", NULL };
-const int g_piVolume[] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
-
-
-
-SDL_Surface* poBackground = NULL;
-
-
-
-void InputKeys( int a_iPlayerNumber )
-{
- SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
- DrawGradientText( "Input keys", titleFont, 20, gamescreen );
- SDL_Flip( gamescreen );
-
- static const char* apcKeyNames[9] = { "up", "down", "left", "right", "block",
- "low punch", "high punch", "low kick", "high kick" };
- char acBuffer[1024];
- int iY = 70;
-
- for ( int i=0; i<9; ++i )
- {
- sprintf( acBuffer, "%s player-'%s'?", a_iPlayerNumber ? "Left" : "Right", apcKeyNames[i] );
- DrawTextMSZ( acBuffer, inkFont, 10, iY, UseShadow, C_WHITE, gamescreen );
-
- SDLKey enKey = GetKey();
-
- if ( SDLK_ESCAPE == enKey )
- {
- SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
- SDL_Flip( gamescreen );
- return;
- }
- g_oBackend.PerlEvalF( "GetKeysym(%d);", enKey );
- DrawTextMSZ( g_oBackend.GetPerlString("keysym"), inkFont, 530, iY, UseShadow, C_WHITE, gamescreen );
- g_oState.m_aiPlayerKeys[a_iPlayerNumber][i] = enKey;
- iY += 35;
- }
-
- DrawTextMSZ( "Thanks!", inkFont, 320, iY + 20, UseShadow | AlignCenter, C_WHITE, gamescreen );
- GetKey();
- SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
- SDL_Flip( gamescreen );
-}
-
-
-
-/***************************************************************************
- MENUITEM DEFINITION
- ***************************************************************************/
-
-
-
+ MENU_SOUND_OK,
+ MENU_FULLSCREEN,
+ MENU_KEYS_RIGHT,
+ MENU_KEYS_LEFT,
+ MENU_OPTIONS_OK,
+ MENU_LANGUAGE,
+ MENU_INFO,
+ MENU_QUIT, // (confirm)
+};
+
+
+const char* g_ppcGameTime[] = { "0:30", "0:45", "1:00", "1:15", "1:30", "1:45", "2:00", "3:00", "5:00", NULL };
+const int g_piGameTime[] = { 30, 45, 60, 75, 90, 105, 120, 180, 300 };
+
+const char* g_ppcHitPoints[] = { "BABY", "VERY LOW", "LOW", "NORMAL", "HIGH", "VERY HIGH", "NEAR IMMORTAL", NULL };
+const int g_piHitPoints[] = { 1, 10, 50, 100, 150, 200, 500 };
+const char* g_ppcGameSpeed[] = { "SNAIL RACE", "SLOW", "NORMAL", "TURBO", "KUNG-FU MOVIE", NULL };
+const int g_piGameSpeed[] = { 16, 14, 12, 10, 8 };
+const char* g_ppcChannels[] = { "MONO", "STEREO", NULL };
+const int g_piChannels[] = { 1, 2 };
+const char* g_ppcMixingRate[] = { "LOW", "MEDIUM", "HIGH", NULL };
+const int g_piMixingRate[] = { 1, 2, 3 };
+const char* g_ppcMixingBits[] = { "8 bit", "16 bit", NULL };
+const int g_piMixingBits[] = { 1, 2 };
+
+
+const char* g_ppcVolume[] = { "OFF", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%", NULL };
+const int g_piVolume[] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
+
+const char* g_ppcLanguage[] = { "English", "Spanish", "Francais", "Magyar", NULL };
+const int g_piLanguage[] = { 0, 1, 2, 3 };
+const char* g_ppcLanguageCodes[] = { "en", "es", "fr", "hu" };
+
+const char* g_ppcServer[] = { "Connect to game", "Create game", NULL };
+int g_piServer[] = { 0, 1 };
+
+
+SDL_Surface* poBackground = NULL;
+
+
+
+void InputKeys( int a_iPlayerNumber )
+{
+ SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
+ DrawGradientText( "Input keys", titleFont, 20, gamescreen );
+ SDL_Flip( gamescreen );
+
+ static const char* apcKeyNames[9] = { "up", "down", "left", "right", "block",
+ "low punch", "high punch", "low kick", "high kick" };
+ char acBuffer[1024];
+ int iY = 70;
+
+ for ( int i=0; i<9; ++i )
+ {
+ sprintf( acBuffer,
+ Translate("%s player-'%s'?"),
+ Translate(a_iPlayerNumber ? "Left" : "Right"),
+ Translate(apcKeyNames[i]) );
+ DrawTextMSZ( acBuffer, inkFont, 10, iY, UseShadow, C_WHITE, gamescreen );
+
+ SDLKey enKey = GetKey();
+
+ if ( SDLK_ESCAPE == enKey )
+ {
+ SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
+ SDL_Flip( gamescreen );
+
+ return;
+ }
+ g_oBackend.PerlEvalF( "GetKeysym(%d);", enKey );
+ DrawTextMSZ( g_oBackend.GetPerlString("keysym"), inkFont, 530, iY, UseShadow, C_WHITE, gamescreen );
+ g_oState.m_aiPlayerKeys[a_iPlayerNumber][i] = enKey;
+ iY += 35;
+ }
+
+ DrawTextMSZ( "Thanks!", inkFont, 320, iY + 20, UseShadow | AlignCenter, C_WHITE, gamescreen );
+ GetKey();
+ SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
+ SDL_Flip( gamescreen );
+}
+
+
+
+
+/***************************************************************************
+ NETWORK MENU DEFINITION
+ ***************************************************************************/
+
+static int g_iMessageY;
+
+void MortalNetworkMessage( const char* format, ... )
+{
+ char acBuffer[1024];
+ va_list ap;
+ va_start( ap, format );
+ vsnprintf( acBuffer, 1023, format, ap );
+ va_end( ap );
+ DrawTextMSZ( acBuffer, impactFont, 20, g_iMessageY, 0, C_LIGHTGRAY, gamescreen );
+ g_iMessageY += 25;
+}
+
+
+bool MortalNetworkCheckKey()
+{
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ switch (event.type)
+ {
+ case SDL_QUIT:
+ g_oState.m_bQuitFlag = true;
+ return true;
+
+ case SDL_KEYDOWN:
+ {
+ return true;
+ }
+ break;
+ } // switch statement
+ } // Polling events
+
+ return false;
+}
+
+
+
+class CNetworkMenu: public Menu
+{
+public:
+ CNetworkMenu(): Menu( "Network Play Setup" )
+ {
+ m_bOK = false;
+ m_bServer = g_oState.m_bServer;
+ m_sHostname = g_oState.m_acLatestServer;
+
+ AddEnumMenuItem( "Network mode: ", m_bServer ? 1 : 0, g_ppcServer, g_piServer, MENU_SERVER );
+ m_poServerMenuItem = AddTextMenuItem( "Connect to: ", m_sHostname.c_str(), MENU_HOSTNAME );
+ m_poServerMenuItem->SetEnabled(!m_bServer);
+ AddMenuItem( "START NETWORK GAME!", SDLK_UNKNOWN, MENU_CONNECT );
+
+ MenuItem* poItem = AddMenuItem( "Cancel", SDLK_UNKNOWN, MENU_CANCEL );
+ SDL_Rect oRect;
+ oRect.x = gamescreen->w - 150; oRect.w = 150;
+ oRect.y = gamescreen->h - 50; oRect.h = 30;
+ poItem->SetPosition( oRect );
+ }
+
+ ~CNetworkMenu() {}
+
+ void ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem )
+ {
+ switch ( a_iItemCode )
+ {
+ case MENU_SERVER:
+ {
+ EnumMenuItem* poItem = (EnumMenuItem*) a_poMenuItem;
+ if ( m_bServer )
+ {
+ poItem->Decrement();
+ }
+ else
+ {
+ poItem->Increment();
+ }
+ break;
+ }
+
+ case MENU_CONNECT:
+ {
+ Clear();
+ Draw();
+
+ g_iMessageY = 260;
+ m_bOK = g_poNetwork->Start( m_bServer ? NULL : m_sHostname.c_str() );
+
+ if ( m_bOK )
+ {
+ g_oState.SetServer( m_bServer ? NULL : m_sHostname.c_str() );
+ g_oState.m_enGameMode = SState::IN_NETWORK;
+ m_bDone = true;
+ m_iReturnCode = 100;
+ }
+ else
+ {
+ const char* acError = g_poNetwork->GetLastError();
+ DrawTextMSZ( "Couldn't connect", inkFont, 320, g_iMessageY, AlignHCenter|UseShadow, C_LIGHTRED, gamescreen );
+ DrawTextMSZ( acError, impactFont, 320, g_iMessageY + 40, AlignHCenter|UseShadow, C_LIGHTRED, gamescreen, false );
+ }
+
+ if ( g_oState.m_bQuitFlag )
+ {
+ m_bDone = true;
+ m_iReturnCode = 100;
+ }
+ break;
+ }
+
+ case MENU_CANCEL:
+ m_bOK = false;
+ m_bDone = true;
+ m_iReturnCode = -1;
+ break;
+
+ case MENU_HOSTNAME:
+ Clear();
+ Draw();
+
+ char acBuffer[256];
+ strncpy( acBuffer, m_sHostname.c_str(), 255 );
+ acBuffer[255] = 0;
+
+ int x = DrawTextMSZ( "Server name: ", impactFont, 20, 270, 0, C_WHITE, gamescreen );
+
+ int iRetval = sge_tt_input( gamescreen, impactFont, acBuffer, SGE_IBG, strlen(acBuffer), 255,
+ 20+x, 270 + sge_TTF_FontAscent(impactFont), C_LIGHTCYAN, C_BLACK, 255 );
+ //DECLSPEC int sge_tt_input(SDL_Surface *screen,sge_TTFont *font,char *string,Uint8 flags, int pos,int len,Sint16 x,Sint16 y, Uint32 fcol, Uint32 bcol, int Alpha);
+ if ( iRetval == -1 )
+ {
+ m_bDone = true;
+ m_iReturnCode = 100;
+ g_oState.m_bQuitFlag = true;
+ }
+ if ( iRetval > 0 )
+ {
+ m_sHostname = acBuffer;
+ m_poServerMenuItem->SetValue( acBuffer );
+ }
+ Clear();
+ Draw();
+ break;
+ }
+ }
+
+ void ItemChanged( int a_iItemCode, int a_iValue, MenuItem* a_poMenuItem )
+ {
+ switch ( a_iItemCode )
+ {
+ case MENU_SERVER:
+ m_bServer = a_iValue;
+ m_poServerMenuItem->SetEnabled(!m_bServer);
+ break;
+ }
+ }
+
+
+protected:
+ bool m_bOK;
+ bool m_bServer;
+ std::string m_sHostname;
+
+ TextMenuItem* m_poServerMenuItem;
+};
+
+
+
+
+/***************************************************************************
+ MENUITEM DEFINITION
+ ***************************************************************************/
+
+
+
MenuItem::MenuItem( Menu* a_poMenu, const char* a_pcUtf8Text, int a_iCode )
: m_sUtf8Text( a_pcUtf8Text )
{
m_poMenu = a_poMenu;
m_iCode = a_iCode;
m_oPosition.x = m_oPosition.y = 100;
m_oPosition.w = m_oPosition.h = 100;
m_bCenter = true;
m_iHighColor = C_WHITE;
m_iLowColor = C_LIGHTGRAY;
m_iInactiveColor = C_DARKGRAY;
m_iBackgroundColor = C_BLACK;
m_bActive = false;
m_bEnabled = true;
+
}
MenuItem::~MenuItem()
{
}
void MenuItem::Draw()
{
if ( NULL != poBackground )
- {
+ {
SDL_BlitSurface( poBackground, &m_oPosition, gamescreen, &m_oPosition );
- }
- else
- {
+ }
+ else
+ {
SDL_FillRect( gamescreen, &m_oPosition, 0 );
- }
+ }
+
int iX = m_oPosition.x;
int iY = m_oPosition.y;
if ( m_bCenter )
{
iX += m_oPosition.w / 2;
}
DrawTextMSZ( m_sUtf8Text.c_str(), inkFont, iX, iY,
UseTilde | UseShadow | (m_bCenter ? AlignHCenter : 0),
m_bEnabled ? (m_bActive ? m_iHighColor : m_iLowColor) : m_iInactiveColor,
- gamescreen );
-
- SDL_UpdateRect( gamescreen, m_oPosition.x, m_oPosition.y, m_oPosition.w, m_oPosition.h );
-}
-
-
-void MenuItem::Clear()
-{
-// debug( "Clear: %d:%d %dx%d\n", m_oPosition.x, m_oPosition.y, m_oPosition.w, m_oPosition.h );
- if (poBackground )
- {
- SDL_Rect oDest = m_oPosition;
- SDL_BlitSurface( poBackground, &m_oPosition, gamescreen, &oDest );
- }
- else
- {
- SDL_FillRect( gamescreen, &m_oPosition, C_WHITE );
- }
-
- SDL_UpdateRect( gamescreen, m_oPosition.x, m_oPosition.y, m_oPosition.w, m_oPosition.h );
-}
-
-
-void MenuItem::Activate()
-{
- if ( m_poMenu )
- {
- m_poMenu->ItemActivated( m_iCode, this );
- }
-}
-
-
+ gamescreen );
+
+ SDL_UpdateRect( gamescreen, m_oPosition.x, m_oPosition.y, m_oPosition.w, m_oPosition.h );
+}
+
+
+void MenuItem::Clear()
+{
+// debug( "Clear: %d:%d %dx%d\n", m_oPosition.x, m_oPosition.y, m_oPosition.w, m_oPosition.h );
+ if (poBackground )
+ {
+ SDL_Rect oDest = m_oPosition;
+ SDL_BlitSurface( poBackground, &m_oPosition, gamescreen, &oDest );
+ }
+ else
+ {
+ SDL_FillRect( gamescreen, &m_oPosition, C_WHITE );
+
+ }
+
+
+ SDL_UpdateRect( gamescreen, m_oPosition.x, m_oPosition.y, m_oPosition.w, m_oPosition.h );
+}
+
+
+void MenuItem::Activate()
+{
+ if ( m_poMenu )
+ {
+ m_poMenu->ItemActivated( m_iCode, this );
+ }
+}
+
+
+
void MenuItem::SetText( const char* a_pcUtf8Text, bool a_bCenter )
{
m_sUtf8Text = a_pcUtf8Text;
m_bCenter = a_bCenter;
Draw();
}
void MenuItem::SetPosition( const SDL_Rect& a_roPosition )
{
m_oPosition = a_roPosition;
}
void MenuItem::SetActive( bool a_bActive )
{
if ( m_bActive == a_bActive )
{
return;
}
m_bActive = a_bActive;
Draw();
}
void MenuItem::SetEnabled( bool a_bEnabled )
{
if ( m_bEnabled == a_bEnabled )
{
return;
}
m_bEnabled = a_bEnabled;
Draw();
-}
-
-
-
-
-/***************************************************************************
- ENUMMENUITEM DEFINITION
- ***************************************************************************/
-
-
-
-EnumMenuItem::EnumMenuItem( Menu* a_poMenu, int a_iInitialValue, const char* a_pcUtf8Text, int a_iCode )
-: MenuItem( a_poMenu, a_pcUtf8Text, a_iCode )
-{
- m_sUtf8Title = a_pcUtf8Text;
- m_iMax = -1;
- m_iValue = a_iInitialValue;
-}
-
-EnumMenuItem::~EnumMenuItem()
-{
-}
-
-
-void EnumMenuItem::Draw()
-{
- m_sUtf8Text = m_sUtf8Title;
- if ( m_iValue <= m_iMax )
- {
- m_sUtf8Text += m_ppcNames[m_iValue];
- }
- if ( m_iValue > 0 )
- {
- m_sUtf8Text = "< " + m_sUtf8Text;
- }
- if ( m_iValue < m_iMax )
- {
- m_sUtf8Text += " >";
- }
-
- MenuItem::Draw();
-}
-
-
-void EnumMenuItem::Increment()
-{
- if ( m_iValue < m_iMax )
- {
- ++m_iValue;
- Draw();
- m_poMenu->ItemChanged( m_iCode, m_piValues[m_iValue], this );
- Audio->PlaySample( "ding.voc" );
- }
-}
-
-
-void EnumMenuItem::Decrement()
-{
- if ( m_iValue > 0 )
- {
- --m_iValue;
- Draw();
- m_poMenu->ItemChanged( m_iCode, m_piValues[m_iValue], this );
- Audio->PlaySample( "ding.voc" );
- }
-}
-
-
-void EnumMenuItem::SetEnumValues( const char ** a_ppcNames, const int * a_piValues )
-{
- m_ppcNames = a_ppcNames;
- m_piValues = a_piValues;
-
- int i;
- bool bFoundValue = false;
-
- for ( i=0; NULL != a_ppcNames[i]; ++i )
- {
- if ( !bFoundValue &&
- m_iValue == a_piValues[i] )
- {
- bFoundValue = true;
- m_iValue = i;
- }
- }
-
- if ( !bFoundValue )
- {
- m_iValue = 0;
- }
-
- m_iMax = i-1;
-}
-
-
-
-
-
-
-/***************************************************************************
- MENU DEFINITION
- ***************************************************************************/
-
-
+}
+
+
+
+
+/***************************************************************************
+ ENUMMENUITEM DEFINITION
+ ***************************************************************************/
+
+
+
+EnumMenuItem::EnumMenuItem( Menu* a_poMenu, int a_iInitialValue, const char* a_pcUtf8Text, int a_iCode )
+: MenuItem( a_poMenu, a_pcUtf8Text, a_iCode )
+{
+ m_sUtf8Title = a_pcUtf8Text;
+ m_iMax = -1;
+ m_iValue = a_iInitialValue;
+}
+
+EnumMenuItem::~EnumMenuItem()
+{
+}
+
+
+void EnumMenuItem::Draw()
+{
+ m_sUtf8Text = Translate( m_sUtf8Title.c_str() );
+ if ( m_iValue <= m_iMax )
+ {
+ m_sUtf8Text += Translate(m_ppcNames[m_iValue]);
+ }
+ if ( m_iValue > 0 )
+ {
+ m_sUtf8Text = "< " + m_sUtf8Text;
+ }
+ if ( m_iValue < m_iMax )
+ {
+ m_sUtf8Text += " >";
+ }
+
+ MenuItem::Draw();
+}
+
+
+
+void EnumMenuItem::Increment()
+{
+ if ( m_iValue < m_iMax )
+ {
+ ++m_iValue;
+ Draw();
+ m_poMenu->ItemChanged( m_iCode, m_piValues[m_iValue], this );
+ Audio->PlaySample( "ding.voc" );
+ }
+}
+
+
+
+void EnumMenuItem::Decrement()
+{
+ if ( m_iValue > 0 )
+ {
+ --m_iValue;
+ Draw();
+ m_poMenu->ItemChanged( m_iCode, m_piValues[m_iValue], this );
+ Audio->PlaySample( "ding.voc" );
+ }
+}
+
+
+void EnumMenuItem::SetEnumValues( const char ** a_ppcNames, const int * a_piValues )
+{
+ m_ppcNames = a_ppcNames;
+ m_piValues = a_piValues;
+
+ int i;
+ bool bFoundValue = false;
+
+ for ( i=0; NULL != a_ppcNames[i]; ++i )
+ {
+ if ( !bFoundValue &&
+ m_iValue == a_piValues[i] )
+ {
+ bFoundValue = true;
+ m_iValue = i;
+ }
+ }
+
+ if ( !bFoundValue )
+ {
+ m_iValue = 0;
+ }
+
+ m_iMax = i-1;
+}
+
+
+
+
+
+
+/***************************************************************************
+ TextMenuItem DEFINITION
+ ***************************************************************************/
+
+
+
+TextMenuItem::TextMenuItem( Menu* a_poMenu, const char* a_pcInitialValue, const char* a_pcUtf8Title, int a_iCode )
+ : MenuItem( a_poMenu, a_pcUtf8Title, a_iCode )
+
+{
+ m_sTitle = a_pcUtf8Title;
+ m_sValue = a_pcInitialValue;
+}
+
+
+TextMenuItem::~TextMenuItem()
+{
+}
+
+
+void TextMenuItem::Draw()
+{
+ m_sUtf8Text = Translate( m_sTitle.c_str() );
+ m_sUtf8Text += m_sValue;
+
+ MenuItem::Draw();
+}
+
+
+void TextMenuItem::SetValue( const char* a_pcValue )
+{
+ m_sValue = a_pcValue;
+ Draw();
+}
+
+
+
+
+
+
+
+
+
+/***************************************************************************
+ MENU DEFINITION
+ ***************************************************************************/
+
+
+
Menu::Menu( const char* a_pcTitle )
: m_sTitle( a_pcTitle )
-{
- m_iCurrentItem = 0;
- m_iReturnCode = -1;
- m_bDone = false;
-}
-
-
-Menu::~Menu()
-{
+{
+ m_iCurrentItem = 0;
+ m_iReturnCode = -1;
+ m_bDone = false;
+}
+
+
+Menu::~Menu()
+{
ItemIterator it;
for ( it = m_oItems.begin(); it != m_oItems.end(); ++it )
{
delete *it;
}
}
MenuItem* Menu::AddMenuItem( const char* a_pcUtf8Text, SDLKey a_tShortcut, int a_iCode )
{
MenuItem* poItem = new MenuItem( this, a_pcUtf8Text, a_iCode );
- return AddMenuItem( poItem );
-}
-
-
-
-EnumMenuItem* Menu::AddEnumMenuItem( const char* a_pcUtf8Text, int a_iInitialValue,
- const char** a_ppcNames, const int* a_piValues, int a_iCode )
-{
- EnumMenuItem* poItem = new EnumMenuItem( this, a_iInitialValue, a_pcUtf8Text, a_iCode );
- poItem->SetEnumValues( a_ppcNames, a_piValues );
-
- AddMenuItem( poItem );
- return poItem;
-}
-
-
-
+ return AddMenuItem( poItem );
+}
+
+
+
+EnumMenuItem* Menu::AddEnumMenuItem( const char* a_pcUtf8Text, int a_iInitialValue,
+ const char** a_ppcNames, const int* a_piValues, int a_iCode )
+{
+ EnumMenuItem* poItem = new EnumMenuItem( this, a_iInitialValue, a_pcUtf8Text, a_iCode );
+ poItem->SetEnumValues( a_ppcNames, a_piValues );
+
+ AddMenuItem( poItem );
+ return poItem;
+}
+
+
+TextMenuItem* Menu::AddTextMenuItem( const char* a_pcTitle, const char* a_pcValue, int a_iCode )
+{
+ TextMenuItem* poItem = new TextMenuItem( this, a_pcValue, a_pcTitle, a_iCode );
+ AddMenuItem( poItem );
+ return poItem;
+}
+
+
+
+
MenuItem* Menu::AddMenuItem( MenuItem* a_poItem )
{
- m_oItems.push_back( a_poItem );
-
- SDL_Rect oRect;
- oRect.x = 0; oRect.w = gamescreen->w;
- oRect.y = m_oItems.size() * 45 + 100;
- oRect.h = 45;
-
- a_poItem->SetPosition( oRect );
-
+ m_oItems.push_back( a_poItem );
+
+ SDL_Rect oRect;
+ oRect.x = 0; oRect.w = gamescreen->w;
+ oRect.y = m_oItems.size() * 40 + 100;
+ oRect.h = 43;
+
+ a_poItem->SetPosition( oRect );
+
return a_poItem;
}
-
-
-void Menu::AddOkCancel( int a_iOkCode )
-{
- SDL_Rect oRect;
- oRect.x = 0; oRect.w = 150;
- oRect.y = gamescreen->h - 50; oRect.h = 30;
-
- MenuItem* poItem = AddMenuItem( "~OK", SDLK_o, a_iOkCode );
- poItem->SetPosition( oRect );
-
-// poItem = AddMenuItem( "Cancel", SDLK_UNKNOWN, 0 );
- oRect.x = gamescreen->w - 150;
- poItem->SetPosition( oRect );
-}
-
-
-void Menu::InvokeSubmenu( Menu* a_poMenu )
-{
- Audio->PlaySample( "strange_button.voc" );
- Clear();
- m_iReturnCode = a_poMenu->Run();
- if ( m_iReturnCode < 0 )
- {
- Audio->PlaySample( "pop.voc" );
- Draw();
- }
- else
- {
- m_iReturnCode --;
- m_bDone = true;
- }
-}
-
-
-void Menu::ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem )
-{
- debug( "Menu::ItemActivated( %d )\n", a_iItemCode );
-
- switch ( a_iItemCode )
- {
- case MENU_QUIT:
- m_bDone = true;
- m_iReturnCode = 100;
- g_oState.m_bQuitFlag = true;
- break;
-
- case MENU_SURRENDER:
- m_bDone = true;
- m_iReturnCode = 100;
- g_oState.m_enGameMode = SState::IN_DEMO;
- break;
-
- case MENU_MULTI_PLAYER:
- m_bDone = true;
- m_iReturnCode = 100;
- g_oState.m_enGameMode = SState::IN_MULTI;
- break;
-
- case MENU_FULLSCREEN:
- Audio->PlaySample( "strange_button.voc" );
- g_oState.ToggleFullscreen();
- if ( NULL != poBackground )
- {
- SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
- }
- else
- {
- SDL_FillRect( gamescreen, NULL, 0 );
- }
- a_poMenuItem->SetText( g_oState.m_bFullscreen ? "~FULLSCREEN ON" : "~FULLSCREEN OFF", true );
- Draw();
- break;
-
- case MENU_OPTIONS_OK:
- m_bDone = true;
- m_iReturnCode = -1;
- break;
-
- case MENU_OPTIONS:
- {
- Menu* poMenu = new Menu( "Options" );
- poMenu->AddEnumMenuItem( "GAME SPEED: ", g_oState.m_iGameSpeed, g_ppcGameSpeed, g_piGameSpeed, MENU_GAME_SPEED );
- poMenu->AddEnumMenuItem( "GAME TIME: ", g_oState.m_iGameTime, g_ppcGameTime, g_piGameTime, MENU_GAME_TIME );
- poMenu->AddEnumMenuItem( "STAMINA: ", g_oState.m_iHitPoints, g_ppcHitPoints, g_piHitPoints, MENU_TOTAL_HIT_POINTS );
- poMenu->AddMenuItem( "~SOUND", SDLK_s, MENU_SOUND );
- poMenu->AddMenuItem( g_oState.m_bFullscreen ? "~FULLSCREEN ON" : "~FULLSCREEN OFF", SDLK_f, MENU_FULLSCREEN );
- poMenu->AddMenuItem( "~RIGHT PLAYER KEYS", SDLK_r, MENU_KEYS_RIGHT );
- poMenu->AddMenuItem( "~LEFT PLAYER KEYS", SDLK_l, MENU_KEYS_LEFT );
- poMenu->AddOkCancel( MENU_OPTIONS_OK );
-
- InvokeSubmenu( poMenu );
- delete poMenu;
- break;
- }
-
- case MENU_SOUND:
- {
- Menu* poMenu = new Menu( "Sound" );
- poMenu->AddEnumMenuItem( "CHANNELS: ", 1, g_ppcChannels, g_piChannels, MENU_CHANNELS )->SetEnabled(false);
- poMenu->AddEnumMenuItem( "SOUND QUALITY: ", 2, g_ppcMixingRate, g_piMixingRate, MENU_MIXING_RATE )->SetEnabled(false);
- poMenu->AddEnumMenuItem( "SOUND FIDELITY: ", 2, g_ppcMixingBits, g_piMixingBits, MENU_BITS )->SetEnabled(false);
- poMenu->AddEnumMenuItem( "MUSIC VOLUME: ", g_oState.m_iMusicVolume, g_ppcVolume, g_piVolume, MENU_MUSIC_VOLUME );
- poMenu->AddEnumMenuItem( "EFFECTS VOLUME: ", g_oState.m_iSoundVolume, g_ppcVolume, g_piVolume, MENU_SOUND_VOLUME );
- poMenu->AddOkCancel( MENU_SOUND_OK );
-
- InvokeSubmenu( poMenu );
- delete poMenu;
- break;
- }
-
- case MENU_SOUND_OK:
- m_bDone = true;
- m_iReturnCode = -1;
- break;
-
- case MENU_KEYS_LEFT:
- InputKeys(1);
- Draw();
- break;
-
- case MENU_KEYS_RIGHT:
- InputKeys(0);
- Draw();
- break;
-
- default:
- break;
- }
-}
-
-
-
-void Menu::ItemChanged( int a_iItemCode, int a_iValue, MenuItem* a_poMenuItem )
-{
- debug( "Menu::ItemChanged( %d, %d )\n", a_iItemCode, a_iValue );
-
- switch ( a_iItemCode )
- {
- case MENU_MUSIC_VOLUME:
- g_oState.m_iMusicVolume = a_iValue;
- Audio->SetMusicVolume( a_iValue );
- break;
-
- case MENU_SOUND_VOLUME:
- g_oState.m_iSoundVolume = a_iValue;
- break;
-
- case MENU_GAME_TIME:
- g_oState.m_iGameTime = a_iValue;
- break;
-
- case MENU_GAME_SPEED:
- g_oState.m_iGameSpeed = a_iValue;
- break;
-
- case MENU_TOTAL_HIT_POINTS:
- g_oState.m_iHitPoints = a_iValue;
- break;
- } // end of switch a_iItemCode
-}
-
-
-/** Run executes the menus, maybe invoking submenus as well. The
-menus modify the global game state.
-
-Returns 0, or the number of parent menus that should be cleared. */
-
-int Menu::Run()
-{
- if ( m_oItems[m_iCurrentItem]->GetEnabled() )
- {
- m_oItems[m_iCurrentItem]->SetActive(true);
- }
- else
- {
- FocusNext();
- }
-
- Draw();
-
- while ( !m_bDone )
- {
- SDLKey enKey = GetKey();
-
- if ( g_oState.m_bQuitFlag ||
- SDLK_ESCAPE == enKey )
- {
- m_bDone = true;
- m_iReturnCode = -1;
- break;
- }
-
- switch ( enKey )
- {
- case SDLK_UP:
- {
- FocusPrev();
- break;
- } // end of SDLK_UP
-
-
- case SDLK_DOWN:
- {
- FocusNext();
- break;
- } // end of SDLK_DOWN
-
- case SDLK_LEFT:
- {
- MenuItem* poItem = m_oItems[m_iCurrentItem];
- poItem->Decrement();
- break;
- }
-
- case SDLK_RIGHT:
- {
- MenuItem* poItem = m_oItems[m_iCurrentItem];
- poItem->Increment();
- break;
- }
-
- case SDLK_RETURN:
- {
- MenuItem* poItem = m_oItems[m_iCurrentItem];
- if ( poItem->GetEnabled() )
- {
- poItem->Activate();
- }
- }
-
- default:
- break;
- } // end of switch
- }
-
- Clear();
-
- return m_iReturnCode;
-}
-
-
-void Menu::Draw()
-{
- DrawGradientText( m_sTitle.c_str(), titleFont, 20, gamescreen );
-
- for ( ItemIterator it=m_oItems.begin(); it!=m_oItems.end(); ++it )
- {
- (*it)->Draw();
- }
-
- SDL_Flip( gamescreen );
-
-}
-
-
-
-void Menu::FocusNext()
-{
- MenuItem* poItem = NULL;
- int iNextItem;
-
- for ( iNextItem = m_iCurrentItem+1; iNextItem < (int) m_oItems.size(); ++iNextItem )
- {
- poItem = m_oItems[iNextItem];
- if ( poItem->GetEnabled() )
- {
- break;
- }
- poItem = NULL;
- }
-
- if ( NULL != poItem )
- {
- Audio->PlaySample("strange_quack.voc");
- m_oItems[m_iCurrentItem]->SetActive(false);
- m_oItems[iNextItem]->SetActive(true);
- m_iCurrentItem = iNextItem;
- }
-}
-
-
-
-void Menu::FocusPrev()
-{
- MenuItem* poItem = NULL;
- int iPrevItem;
-
- for ( iPrevItem = m_iCurrentItem-1; iPrevItem >= 0; --iPrevItem )
- {
- poItem = m_oItems[iPrevItem];
- if ( poItem->GetEnabled() )
- {
- break;
- }
- poItem = NULL;
- }
-
- if ( NULL != poItem )
- {
- Audio->PlaySample("strange_quack.voc");
- m_oItems[m_iCurrentItem]->SetActive(false);
- m_oItems[iPrevItem]->SetActive(true);
- m_iCurrentItem = iPrevItem;
- }
-}
-
-
-
+
+
+void Menu::AddOkCancel( int a_iOkCode )
+{
+ SDL_Rect oRect;
+ oRect.x = 0; oRect.w = 150;
+ oRect.y = gamescreen->h - 50; oRect.h = 30;
+
+ MenuItem* poItem = AddMenuItem( "~OK", SDLK_o, a_iOkCode );
+ poItem->SetPosition( oRect );
+
+// poItem = AddMenuItem( "Cancel", SDLK_UNKNOWN, 0 );
+ oRect.x = gamescreen->w - 150;
+ poItem->SetPosition( oRect );
+}
+
+
+void Menu::InvokeSubmenu( Menu* a_poMenu )
+{
+ Audio->PlaySample( "strange_button.voc" );
+ Clear();
+
+ m_iReturnCode = a_poMenu->Run();
+ if ( g_oState.m_bQuitFlag )
+ {
+ m_iReturnCode = 100;
+ m_bDone = true;
+ }
+
+ if ( m_iReturnCode < 0 )
+ {
+ Audio->PlaySample( "pop.voc" );
+ Draw();
+ }
+ else
+ {
+ m_iReturnCode --;
+ m_bDone = true;
+ }
+}
+
+
+void Menu::ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem )
+{
+ debug( "Menu::ItemActivated( %d )\n", a_iItemCode );
+
+ switch ( a_iItemCode )
+ {
+ case MENU_QUIT:
+ m_bDone = true;
+ m_iReturnCode = 100;
+ g_oState.m_bQuitFlag = true;
+ break;
+
+ case MENU_SURRENDER:
+ m_bDone = true;
+ m_iReturnCode = 100;
+ g_oState.m_enGameMode = SState::IN_DEMO;
+ break;
+
+ case MENU_NETWORK_GAME:
+ {
+ Menu* poMenu = new CNetworkMenu();
+ InvokeSubmenu( poMenu );
+ delete poMenu;
+ break;
+ }
+
+ case MENU_MULTI_PLAYER:
+ m_bDone = true;
+ m_iReturnCode = 100;
+ g_oState.m_enGameMode = SState::IN_MULTI;
+ break;
+
+ case MENU_FULLSCREEN:
+ Audio->PlaySample( "strange_button.voc" );
+ g_oState.ToggleFullscreen();
+ if ( NULL != poBackground )
+ {
+ SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
+ }
+ else
+ {
+ SDL_FillRect( gamescreen, NULL, 0 );
+ }
+ a_poMenuItem->SetText( g_oState.m_bFullscreen ? "~FULLSCREEN ON" : "~FULLSCREEN OFF", true );
+ Draw();
+ break;
+
+ case MENU_OPTIONS_OK:
+ m_bDone = true;
+ m_iReturnCode = -1;
+ break;
+
+ case MENU_OPTIONS:
+ {
+ Menu* poMenu = new Menu( "Options" );
+ poMenu->AddEnumMenuItem( "GAME SPEED: ", g_oState.m_iGameSpeed, g_ppcGameSpeed, g_piGameSpeed, MENU_GAME_SPEED );
+ poMenu->AddEnumMenuItem( "GAME TIME: ", g_oState.m_iGameTime, g_ppcGameTime, g_piGameTime, MENU_GAME_TIME );
+ poMenu->AddEnumMenuItem( "STAMINA: ", g_oState.m_iHitPoints, g_ppcHitPoints, g_piHitPoints, MENU_TOTAL_HIT_POINTS );
+ poMenu->AddMenuItem( "~SOUND", SDLK_s, MENU_SOUND );
+ poMenu->AddMenuItem( g_oState.m_bFullscreen ? "~FULLSCREEN ON" : "~FULLSCREEN OFF", SDLK_f, MENU_FULLSCREEN );
+ poMenu->AddMenuItem( "~RIGHT PLAYER KEYS", SDLK_r, MENU_KEYS_RIGHT );
+ poMenu->AddMenuItem( "~LEFT PLAYER KEYS", SDLK_l, MENU_KEYS_LEFT );
+ poMenu->AddOkCancel( MENU_OPTIONS_OK );
+
+ InvokeSubmenu( poMenu );
+ delete poMenu;
+ break;
+ }
+
+ case MENU_SOUND:
+ {
+ Menu* poMenu = new Menu( "Sound" );
+ poMenu->AddEnumMenuItem( "CHANNELS: ", 1, g_ppcChannels, g_piChannels, MENU_CHANNELS )->SetEnabled(false);
+ poMenu->AddEnumMenuItem( "SOUND QUALITY: ", 2, g_ppcMixingRate, g_piMixingRate, MENU_MIXING_RATE )->SetEnabled(false);
+ poMenu->AddEnumMenuItem( "SOUND FIDELITY: ", 2, g_ppcMixingBits, g_piMixingBits, MENU_BITS )->SetEnabled(false);
+ poMenu->AddEnumMenuItem( "MUSIC VOLUME: ", g_oState.m_iMusicVolume, g_ppcVolume, g_piVolume, MENU_MUSIC_VOLUME );
+ poMenu->AddEnumMenuItem( "EFFECTS VOLUME: ", g_oState.m_iSoundVolume, g_ppcVolume, g_piVolume, MENU_SOUND_VOLUME );
+ poMenu->AddOkCancel( MENU_SOUND_OK );
+
+ InvokeSubmenu( poMenu );
+ delete poMenu;
+ break;
+ }
+
+ case MENU_SOUND_OK:
+ m_bDone = true;
+ m_iReturnCode = -1;
+ break;
+
+ case MENU_KEYS_LEFT:
+ InputKeys(1);
+ Draw();
+ break;
+
+ case MENU_KEYS_RIGHT:
+ InputKeys(0);
+ Draw();
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+
+
+void Menu::ItemChanged( int a_iItemCode, int a_iValue, MenuItem* a_poMenuItem )
+{
+ debug( "Menu::ItemChanged( %d, %d )\n", a_iItemCode, a_iValue );
+
+ switch ( a_iItemCode )
+ {
+ case MENU_MUSIC_VOLUME:
+ g_oState.m_iMusicVolume = a_iValue;
+ Audio->SetMusicVolume( a_iValue );
+ break;
+
+ case MENU_SOUND_VOLUME:
+ g_oState.m_iSoundVolume = a_iValue;
+ break;
+
+ case MENU_GAME_TIME:
+ g_oState.m_iGameTime = a_iValue;
+ break;
+
+ case MENU_GAME_SPEED:
+ g_oState.m_iGameSpeed = a_iValue;
+ break;
+
+ case MENU_TOTAL_HIT_POINTS:
+ g_oState.m_iHitPoints = a_iValue;
+ break;
+
+ case MENU_LANGUAGE:
+ g_oState.SetLanguage( g_ppcLanguageCodes[ a_iValue ] );
+ Clear();
+ Draw();
+ break;
+ } // end of switch a_iItemCode
+}
+
+
+/** Run executes the menus, maybe invoking submenus as well. The
+menus modify the global game state.
+
+Returns 0, or the number of parent menus that should be cleared. */
+
+int Menu::Run()
+{
+ if ( m_oItems[m_iCurrentItem]->GetEnabled() )
+ {
+ m_oItems[m_iCurrentItem]->SetActive(true);
+ }
+ else
+ {
+ FocusNext();
+ }
+
+ Draw();
+
+ while ( !m_bDone )
+ {
+ SDLKey enKey = GetKey();
+
+ if ( g_oState.m_bQuitFlag ||
+ SDLK_ESCAPE == enKey )
+ {
+ m_bDone = true;
+ m_iReturnCode = -1;
+ break;
+ }
+
+ switch ( enKey )
+ {
+ case SDLK_UP:
+ {
+ FocusPrev();
+ break;
+ } // end of SDLK_UP
+
+
+ case SDLK_DOWN:
+ {
+ FocusNext();
+ break;
+ } // end of SDLK_DOWN
+
+ case SDLK_LEFT:
+ {
+ MenuItem* poItem = m_oItems[m_iCurrentItem];
+ poItem->Decrement();
+ break;
+ }
+
+ case SDLK_RIGHT:
+ {
+ MenuItem* poItem = m_oItems[m_iCurrentItem];
+ poItem->Increment();
+ break;
+ }
+
+ case SDLK_RETURN:
+ {
+ MenuItem* poItem = m_oItems[m_iCurrentItem];
+ if ( poItem->GetEnabled() )
+ {
+ poItem->Activate();
+ }
+ }
+
+ default:
+ break;
+ } // end of switch
+ }
+
+ Clear();
+
+ return m_iReturnCode;
+}
+
+
+void Menu::Draw()
+{
+ DrawGradientText( m_sTitle.c_str(), titleFont, 20, gamescreen );
+
+ for ( ItemIterator it=m_oItems.begin(); it!=m_oItems.end(); ++it )
+ {
+ (*it)->Draw();
+ }
+
+ SDL_Flip( gamescreen );
+
+}
+
+
+
+void Menu::FocusNext()
+{
+ MenuItem* poItem = NULL;
+ int iNextItem;
+
+ for ( iNextItem = m_iCurrentItem+1; iNextItem < (int) m_oItems.size(); ++iNextItem )
+ {
+ poItem = m_oItems[iNextItem];
+ if ( poItem->GetEnabled() )
+ {
+ break;
+ }
+ poItem = NULL;
+ }
+
+ if ( NULL != poItem )
+ {
+ Audio->PlaySample("strange_quack.voc");
+ m_oItems[m_iCurrentItem]->SetActive(false);
+ m_oItems[iNextItem]->SetActive(true);
+ m_iCurrentItem = iNextItem;
+ }
+}
+
+
+
+void Menu::FocusPrev()
+{
+ MenuItem* poItem = NULL;
+ int iPrevItem;
+
+ for ( iPrevItem = m_iCurrentItem-1; iPrevItem >= 0; --iPrevItem )
+ {
+ poItem = m_oItems[iPrevItem];
+ if ( poItem->GetEnabled() )
+ {
+ break;
+ }
+ poItem = NULL;
+ }
+
+ if ( NULL != poItem )
+ {
+ Audio->PlaySample("strange_quack.voc");
+ m_oItems[m_iCurrentItem]->SetActive(false);
+ m_oItems[iPrevItem]->SetActive(true);
+ m_iCurrentItem = iPrevItem;
+ }
+}
+
+
+
void Menu::Clear()
{
if (poBackground)
{
SDL_BlitSurface( poBackground, 0, gamescreen, 0 );
}
else
{
SDL_FillRect( gamescreen, NULL, 0 );
- }
-}
-
-
-void DoMenu( bool a_bDrawBackground )
-{
- Audio->PlaySample( "crashhh.voc" );
-
- poBackground = SDL_ConvertSurface( gamescreen, gamescreen->format, SDL_SWSURFACE );
- if ( NULL == poBackground )
- {
- debug( "DoMenu: Couldn't allocate background.\n" );
- }
- else
- {
- int i;
- SDL_Rect oRect;
- oRect.x = 0; oRect.w = poBackground->w; oRect.h = 1;
-
- for ( i=0; i<poBackground->h; i += 2 )
- {
- oRect.y = i;
- SDL_FillRect( poBackground, &oRect, C_BLACK );
- }
-
- oRect.w = 1; oRect.y = 0; oRect.h = poBackground->h;
-
- for ( i=0; i<poBackground->w; i+=2 )
- {
- oRect.x = i;
- SDL_FillRect(poBackground, &oRect, C_BLACK );
- }
-
- SDL_BlitSurface( poBackground, 0, gamescreen, 0 );
- SDL_Flip( gamescreen );
- }
-
- Menu oMenu( "Main Menu" );
-
- if ( SState::IN_DEMO == g_oState.m_enGameMode )
- {
- oMenu.AddMenuItem( "~SINGLE PLAYER GAME", SDLK_s, MENU_SINGLE_PLAYER )->SetEnabled(false);
- oMenu.AddMenuItem( "~MULTI PLAYER GAME", SDLK_m, MENU_MULTI_PLAYER );
- }
- else
- {
- oMenu.AddMenuItem( "~SURRENDER GAME", SDLK_s, MENU_SURRENDER );
- }
- oMenu.AddMenuItem( "~OPTIONS", SDLK_o, MENU_OPTIONS );
- oMenu.AddMenuItem( "~INFO", SDLK_i, MENU_INFO )->SetEnabled(false);
- oMenu.AddMenuItem( "QUIT", SDLK_UNKNOWN, MENU_QUIT );
-
- oMenu.Run();
-
- Audio->PlaySample("shades_rollup.voc");
-
- //SDL_BlitSurface( poBackground, 0, gamescreen, 0 );
- //SDL_Flip( gamescreen );
- SDL_FreeSurface( poBackground );
- poBackground = NULL;
-}
-
-
+ }
+}
+
+
+
+
+
+
+
+
+
+void DoMenu( bool a_bDrawBackground )
+{
+ Audio->PlaySample( "crashhh.voc" );
+
+ poBackground = SDL_ConvertSurface( gamescreen, gamescreen->format, SDL_SWSURFACE );
+ if ( NULL == poBackground )
+ {
+ debug( "DoMenu: Couldn't allocate background.\n" );
+ }
+ else
+ {
+ int i;
+ SDL_Rect oRect;
+ oRect.x = 0; oRect.w = poBackground->w; oRect.h = 1;
+
+ for ( i=0; i<poBackground->h; i += 2 )
+ {
+ oRect.y = i;
+ SDL_FillRect( poBackground, &oRect, C_BLACK );
+ }
+
+ oRect.w = 1; oRect.y = 0; oRect.h = poBackground->h;
+
+ for ( i=0; i<poBackground->w; i+=2 )
+ {
+ oRect.x = i;
+ SDL_FillRect(poBackground, &oRect, C_BLACK );
+ }
+
+ SDL_BlitSurface( poBackground, 0, gamescreen, 0 );
+ SDL_Flip( gamescreen );
+ }
+
+ Menu oMenu( "Main Menu" );
+
+ if ( SState::IN_DEMO == g_oState.m_enGameMode )
+ {
+ oMenu.AddMenuItem( "~SINGLE PLAYER GAME", SDLK_s, MENU_SINGLE_PLAYER )->SetEnabled(false);
+ oMenu.AddMenuItem( "~NETWORK GAME", SDLK_n, MENU_NETWORK_GAME );
+ oMenu.AddMenuItem( "~MULTI PLAYER GAME", SDLK_m, MENU_MULTI_PLAYER );
+ }
+ else
+ {
+ oMenu.AddMenuItem( "~SURRENDER GAME", SDLK_s, MENU_SURRENDER );
+ }
+ oMenu.AddEnumMenuItem( "~LANGUAGE: ", g_oState.m_iLanguageCode, g_ppcLanguage, g_piLanguage, MENU_LANGUAGE );
+
+ oMenu.AddMenuItem( "~OPTIONS", SDLK_o, MENU_OPTIONS );
+ oMenu.AddMenuItem( "~INFO", SDLK_i, MENU_INFO )->SetEnabled(false);
+ oMenu.AddMenuItem( "QUIT", SDLK_UNKNOWN, MENU_QUIT );
+
+ oMenu.Run();
+
+ if ( !g_oState.m_bQuitFlag )
+ {
+ Audio->PlaySample("shades_rollup.voc");
+ }
+
+ //SDL_BlitSurface( poBackground, 0, gamescreen, 0 );
+ //SDL_Flip( gamescreen );
+ SDL_FreeSurface( poBackground );
+ poBackground = NULL;
+}
+
+
diff --git a/src/menu.h b/src/menu.h
index 9eda289..9406558 100644
--- a/src/menu.h
+++ b/src/menu.h
@@ -1,119 +1,137 @@
/***************************************************************************
menu.h - description
-------------------
begin : Sun Aug 3 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
-#ifndef MENU_H
-#define MENU_H
-
-
+#ifndef MENU_H
+#define MENU_H
+
+
#include <string>
#include <vector>
-
-class MenuItem;
-class EnumMenuItem;
-
-class Menu
-{
-public:
- Menu( const char* a_pcTitle );
- ~Menu();
-
- MenuItem* AddMenuItem( const char* a_pcUtf8Text, SDLKey a_tShortcut = SDLK_UNKNOWN, int a_iCode = 0 );
- EnumMenuItem* AddEnumMenuItem( const char* a_pcUtf8Text, int a_iInitialValue,
- const char** a_ppcNames, const int* a_piValues, int a_iCode = 0 );
- MenuItem* AddMenuItem( MenuItem* a_poItem );
- void AddOkCancel( int a_iOkCode = 0 );
- void ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem );
- void ItemChanged( int a_iItemCode, int a_iValue, MenuItem* a_poMenuItem );
- int Run();
-
- void Draw();
- void Clear();
-
-protected:
-
- void FocusNext();
- void FocusPrev();
- void InvokeSubmenu( Menu* a_poSubmenu );
-
+
+class MenuItem;
+class EnumMenuItem;
+class TextMenuItem;
+
+class Menu
+{
+public:
+ Menu( const char* a_pcTitle );
+ virtual ~Menu();
+
+ virtual MenuItem* AddMenuItem( const char* a_pcUtf8Text, SDLKey a_tShortcut = SDLK_UNKNOWN, int a_iCode = 0 );
+ virtual EnumMenuItem* AddEnumMenuItem( const char* a_pcUtf8Text, int a_iInitialValue,
+ const char** a_ppcNames, const int* a_piValues, int a_iCode = 0 );
+ virtual TextMenuItem* AddTextMenuItem( const char* a_pcTitle, const char* a_pcValue, int a_iCode = 0 );
+ virtual MenuItem* AddMenuItem( MenuItem* a_poItem );
+ virtual void AddOkCancel( int a_iOkCode = 0 );
+ virtual void ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem );
+ virtual void ItemChanged( int a_iItemCode, int a_iValue, MenuItem* a_poMenuItem );
+ virtual int Run();
+
+ virtual void Draw();
+ virtual void Clear();
+
+protected:
+
+ virtual void FocusNext();
+ virtual void FocusPrev();
+ virtual void InvokeSubmenu( Menu* a_poSubmenu );
+
typedef std::vector<MenuItem*> ItemList;
typedef ItemList::iterator ItemIterator;
std::string m_sTitle;
ItemList m_oItems;
int m_iCurrentItem;
- int m_iReturnCode;
- bool m_bDone;
+ int m_iReturnCode;
+ bool m_bDone;
};
class MenuItem
{
public:
MenuItem( Menu* a_poMenu, const char* a_pcUtf8Text, int a_iCode = -1 );
virtual ~MenuItem();
- virtual void Draw();
- virtual void Clear();
- virtual void Activate();
- virtual void Increment() {};
- virtual void Decrement() {};
-
+ virtual void Draw();
+ virtual void Clear();
+ virtual void Activate();
+ virtual void Increment() {};
+ virtual void Decrement() {};
+
virtual void SetText( const char* a_pcUtf8Text, bool a_bCenter );
virtual void SetPosition( const SDL_Rect& a_roPosition );
virtual void SetActive( bool a_bActive );
virtual void SetEnabled( bool a_bEnabled );
-
- virtual bool GetEnabled() { return m_bEnabled; }
+
+ virtual bool GetEnabled() { return m_bEnabled; }
protected:
Menu* m_poMenu;
// appearance
std::string m_sUtf8Text;
SDL_Rect m_oPosition;
bool m_bCenter;
Uint32 m_iHighColor;
Uint32 m_iLowColor;
Uint32 m_iInactiveColor;
Uint32 m_iBackgroundColor;
// data content
int m_iCode;
bool m_bActive;
bool m_bEnabled;
-};
-
-
-
-class EnumMenuItem: public MenuItem
-{
-public:
- EnumMenuItem( Menu* a_poMenu, int a_iInitialValue, const char* a_pcUtf8Text, int a_iCode = -1 );
- virtual ~EnumMenuItem();
-
- virtual void Draw();
- virtual void Increment();
- virtual void Decrement();
-
- virtual void SetEnumValues( const char ** a_ppcNames, const int * a_piValues );
-
-protected:
- int m_iValue;
- int m_iMax;
- std::string m_sUtf8Title;
- const char** m_ppcNames;
- const int* m_piValues;
-};
-
-
-
-void DoMenu( bool a_bDrawBackground );
-
-#endif
+};
+
+
+
+class EnumMenuItem: public MenuItem
+{
+public:
+ EnumMenuItem( Menu* a_poMenu, int a_iInitialValue, const char* a_pcUtf8Text, int a_iCode = -1 );
+ virtual ~EnumMenuItem();
+
+ virtual void Draw();
+ virtual void Increment();
+ virtual void Decrement();
+
+ virtual void SetEnumValues( const char ** a_ppcNames, const int * a_piValues );
+
+protected:
+ int m_iValue;
+ int m_iMax;
+ std::string m_sUtf8Title;
+ const char** m_ppcNames;
+ const int* m_piValues;
+};
+
+
+
+class TextMenuItem: public MenuItem
+{
+public:
+ TextMenuItem( Menu* a_poMenu, const char* a_pcInitialValue, const char* a_pcUtf8Title, int a_iCode );
+ virtual ~TextMenuItem();
+
+ virtual void Draw();
+ virtual void SetValue( const char* a_pcValue );
+
+protected:
+ std::string m_sTitle;
+ std::string m_sValue;
+};
+
+
+
+void DoMenu( bool a_bDrawBackground );
+
+#endif

File Metadata

Mime Type
text/x-diff
Expires
Wed, Feb 4, 2:12 PM (2 h, 2 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55633
Default Alt Text
(105 KB)

Event Timeline