blobby-1.0/src/raknet/SocketLayer.h000644 001750 001750 00000012476 12313310247 022072 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Socket Layer Abstraction * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __SOCKET_LAYER_H #define __SOCKET_LAYER_H #ifdef _WIN32 #include #else #include #include #include #include #include #include /** * typename for communication endpoint */ typedef int SOCKET; /** * Invalid socket */ static const SOCKET INVALID_SOCKET = -1; /** * Socket error */ #define SOCKET_ERROR -1 #endif class RakPeer; /** * the SocketLayer provide platform independent Socket implementation */ class SocketLayer { public: /** * Default Constructor */ SocketLayer(); /** * Destructor */ ~SocketLayer(); /** * Get Singleton Instance of the Socket Layer unique object. * @return unique instance */ static inline SocketLayer* Instance() { return & I; } /** * Create a socket connected to a remote host * @param writeSocket The local socket * @param binaryAddress The address of the remote host * @param port the remote port * @return A new socket used for communication * @todo * Check for the binary address byte order * */ SOCKET Connect( SOCKET writeSocket, unsigned int binaryAddress, unsigned short port ); /** * Creates a socket to listen for incoming connections on the specified port * @param port the port number * @param blockingSocket * @return A new socket used for accepting clients */ SOCKET CreateBoundSocket( unsigned short port, bool blockingSocket, const char *forceHostAddress ); const char* DomainNameToIP( const char *domainName ); /** * Does a writing operation on a socket. * It Send a packet to a peer throught the network. * The socket must be connected * @param writeSocket the socket to use to do the communication * @param data a byte buffer containing the data * @param length the size of the byte buffer * return written bytes */ int Write( SOCKET writeSocket, const char* data, int length ); /** * Read data from a socket * @param s the socket * @param rakPeer * @param errorCode An error code if an error occured * @return Returns true if you successfully read data * @todo check the role of RakPeer * */ int RecvFrom( SOCKET s, RakPeer *rakPeer, int *errorCode ); /** * Retrieve all local IP address in a printable format * @param ipList An array of ip address in dot format. */ void GetMyIP( char ipList[ 10 ][ 16 ] ); /** * Send data to a peer. The socket should not be connected to a remote host. * @param s the socket * @param data the byte buffer to send * @param length The length of the @em data * @param ip The address of the remote host in dot format * @param port The port number used by the remote host * @return 0 on success. * * @todo check return value */ int SendTo( SOCKET s, const char *data, int length, char ip[ 16 ], unsigned short port ); /** * Send data to a peer. The socket should not be connected to a remote host. * @param s the socket * @param data the byte buffer to send * @param length The length of the @em data * @param binaryAddress The peer address in binary format. * @param port The port number used by the remote host * @return 0 on success. * * @todo check return value */ int SendTo( SOCKET s, const char *data, int length, unsigned int binaryAddress, unsigned short port ); /// @brief Get the Ip address of an domain /// @param name Name of the domain /// @return Ip address /// @todo This is only for IPv4. IPv6 is not available jet const char* nameToIP(const char* name) const; private: /** * Tell whether or not the socket layer is already active */ static int socketLayerInstanceCount; /** * Singleton instance */ static SocketLayer I; }; #endif blobby-1.0/src/GenericIO.cpp000644 001750 001750 00000024450 12313310251 020506 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #include "GenericIO.h" #include #include #include #include "raknet/BitStream.h" #include "raknet/NetworkTypes.h" #include "FileWrite.h" #include "FileRead.h" #include "PlayerInput.h" // ------------------------------------------------------------------------------------------------- // File Output Class // ------------------------------------------------------------------------------------------------- class FileOut : public GenericOut { public: FileOut(boost::shared_ptr file) : mFile(file) { } private: virtual void byte(const unsigned char& data) { mFile->writeByte(data); } virtual void boolean(const bool& data) { mFile->writeByte(data); } virtual void uint32(const unsigned int& data) { mFile->writeUInt32(data); } virtual void number(const float& data) { mFile->writeFloat(data); } virtual void string(const std::string& string) { uint32(string.size()); mFile->write(string.data(), string.size()); } virtual unsigned int tell() const { return mFile->tell(); } virtual void seek(unsigned int pos) const { mFile->seek(pos); } virtual void array(const char* data, unsigned int length) { mFile->write(data, length); } boost::shared_ptr mFile; }; // ------------------------------------------------------------------------------------------------- // File Input Class // ------------------------------------------------------------------------------------------------- class FileIn : public GenericIn { public: FileIn(boost::shared_ptr file) : mFile(file) { } private: virtual void byte(unsigned char& data) { data = mFile->readByte(); } virtual void boolean(bool& data) { data = mFile->readByte(); } virtual void uint32(unsigned int& data) { data = mFile->readUInt32(); } virtual void number(float& data) { data = mFile->readFloat(); } virtual void string(std::string& string) { /// \todo this might be bad performance wise unsigned int ts; uint32(ts); string.resize(ts); for(unsigned int i = 0; i < ts; ++i) { unsigned char nc; byte(nc); string[i] = nc; } } virtual unsigned int tell() const { return mFile->tell(); } virtual void seek(unsigned int pos) const { mFile->seek(pos); } virtual void array(char* data, unsigned int length) { mFile->readRawBytes(data, length); } boost::shared_ptr mFile; }; // ------------------------------------------------------------------------------------------------- // Bitstream Output Class // ------------------------------------------------------------------------------------------------- class NetworkOut : public GenericOut { public: NetworkOut(RakNet::BitStream* stream) : mStream(stream) { } private: virtual void byte(const unsigned char& data) { mStream->Write(data); } virtual void boolean(const bool& data) { mStream->Write(data); } virtual void uint32(const unsigned int& data) { mStream->Write(data); } virtual void number(const float& data) { mStream->Write(data); } virtual void string(const std::string& string) { uint32(string.size()); mStream->Write(string.c_str(), string.size()); } virtual unsigned int tell() const { return mStream->GetNumberOfBitsUsed(); } virtual void seek(unsigned int pos) const { mStream->SetWriteOffset(pos); } virtual void array(const char* data, unsigned int length) { mStream->Write(data, length); } RakNet::BitStream* mStream; }; // ------------------------------------------------------------------------------------------------- // Bistream Input Class // ------------------------------------------------------------------------------------------------- class NetworkIn : public GenericIn { public: NetworkIn(RakNet::BitStream* stream) : mStream(stream) { } private: virtual void byte(unsigned char& data) { mStream->Read(data); } virtual void boolean(bool& data) { mStream->Read(data); } virtual void uint32( unsigned int& data) { mStream->Read(data); } virtual void number( float& data) { mStream->Read(data); } virtual void string( std::string& string) { /// \todo this might be bad performance wise unsigned int ts; uint32(ts); string.resize(ts); for(unsigned int i = 0; i < ts; ++i) { unsigned char nc; byte(nc); string[i] = nc; } } virtual unsigned int tell() const { return mStream->GetReadOffset(); } virtual void seek(unsigned int pos) const { mStream->ResetReadPointer(); mStream->IgnoreBits(pos); } virtual void array( char* data, unsigned int length) { mStream->Read(data, length); } RakNet::BitStream* mStream; }; // ------------------------------------------------------------------------------------------------- // File Output Class // ------------------------------------------------------------------------------------------------- class StreamOut : public GenericOut { public: StreamOut(std::ostream& stream) : mStream(stream) { } private: virtual void byte(const unsigned char& data) { mStream << data << "\n"; } virtual void boolean(const bool& data) { mStream << data << "\n"; } virtual void uint32(const unsigned int& data) { mStream << data << "\n"; } virtual void number(const float& data) { mStream << data << "\n"; } virtual void string(const std::string& string) { mStream << string << "\n"; } /// currently not supported by StreamOut virtual unsigned int tell() const { return -1; } virtual void seek(unsigned int pos) const { } virtual void array(const char* data, unsigned int length) { std::string stringed(data, length); mStream << stringed << "\n"; } std::ostream& mStream; }; // ------------------------------------------------------------------------------------------------- // Factory Functions // ------------------------------------------------------------------------------------------------- boost::shared_ptr< GenericOut > createGenericWriter(boost::shared_ptr file) { return boost::make_shared< FileOut > (file); } boost::shared_ptr< GenericOut > createGenericWriter(RakNet::BitStream* stream) { return boost::make_shared< NetworkOut > (stream); } boost::shared_ptr< GenericOut > createGenericWriter(std::ostream& stream) { return boost::shared_ptr< StreamOut > ( new StreamOut(stream) ); } boost::shared_ptr< GenericIn > createGenericReader(boost::shared_ptr file) { return boost::make_shared< FileIn > (file); } boost::shared_ptr< GenericIn > createGenericReader(RakNet::BitStream* stream) { return boost::make_shared< NetworkIn > (stream); } // ------------------------------------------------------------------------------------------------- // Default generic implementations // ------------------------------------------------------------------------------------------------- /* Several instantiations of serializer functions are made so these can be used without further user actions. These are the instantiations for the standard types * unsigned char * bool * unsigned int * float * string Furthermore, some types used in BlobbyVolley get their serialisation algorithms here * Color * PlayerInput * PlayerSide */ // these templates help to avoid boilderplate code #define GENERATE_STD_SERIALIZER_OUT(type) \ template<> \ void predifined_serializer::serialize(GenericOut& io, const type& value) #define GENERATE_STD_SERIALIZER_IN(type) \ template<> \ void predifined_serializer::serialize(GenericIn& io, type& value) #define GENERATE_STD_SERIALIZER(type, func) \ GENERATE_STD_SERIALIZER_OUT(type) { io.func(value); }; \ GENERATE_STD_SERIALIZER_IN(type) { io.func(value); }; namespace detail { // std implementations GENERATE_STD_SERIALIZER(unsigned char, byte); GENERATE_STD_SERIALIZER(unsigned int, uint32); GENERATE_STD_SERIALIZER(bool, boolean); GENERATE_STD_SERIALIZER(float, number); GENERATE_STD_SERIALIZER(std::string, string); // Blobby types GENERATE_STD_SERIALIZER_OUT(Color) { io.uint32(value.toInt()); } GENERATE_STD_SERIALIZER_IN(Color) { unsigned int target; io.uint32(target); value = Color(target); } GENERATE_STD_SERIALIZER_OUT(PlayerInput) { io.uint32(value.getAll()); } GENERATE_STD_SERIALIZER_IN(PlayerInput) { unsigned int target; io.uint32(target); value.setAll(target); } GENERATE_STD_SERIALIZER_OUT(PlayerSide) { io.uint32(value); } GENERATE_STD_SERIALIZER_IN(PlayerSide) { unsigned int target; io.uint32(target); value = (PlayerSide)target; } GENERATE_STD_SERIALIZER_OUT(PlayerID) { io.uint32(value.binaryAddress); io.uint32(value.port); } GENERATE_STD_SERIALIZER_IN(PlayerID) { io.uint32(value.binaryAddress); unsigned int port; io.uint32(port); value.port = port; } } blobby-1.0/src/RenderManagerNull.cpp000644 001750 001750 00000002054 12313310253 022245 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #include "RenderManagerNull.h" RenderManager* RenderManager::createRenderManagerNull() { return new RenderManagerNull(); } blobby-1.0/test/GenericIOTest.cpp000644 001750 001750 00000031422 12313310246 021537 0ustar00danielknobedanielknobe000000 000000 #define BOOST_TEST_MODULE FileAbstraction #include #include "FileRead.h" #include "FileWrite.h" #include "FileSystem.h" #include #include #include "GenericIO.h" #include "InputSource.h" #include "DuelMatchState.h" #include "raknet/BitStream.h" #include #include #include #include #include #include #define TEST_EXECUTION_PATH "C:\\Dokumente und Einstellungen\\Erik\\Eigene Dateien\\Blobby Volley 2\\test" //#define DISABLE_COMPILATION_TEST // helper void init_Physfs() { static bool initialised = false; if(!initialised) { std::cout << "initialising physfs to " << TEST_EXECUTION_PATH << "\n"; static FileSystem fs( TEST_EXECUTION_PATH ); fs.setWriteDir("."); initialised = true; } } void generic_io_types_test_f(boost::shared_ptr in, boost::shared_ptr out); void generic_io_types_test_generics_f(boost::shared_ptr in, boost::shared_ptr out); template void generic_io_types_test_vector_f(boost::shared_ptr in, boost::shared_ptr out); void generic_io_seek_tell_f(boost::shared_ptr in, boost::shared_ptr out); void generic_io_types_test_special_f(boost::shared_ptr in, boost::shared_ptr out); #define CHECK_EXCEPTION_SAFETY(expr, excp) try { \ BOOST_TEST_CHECKPOINT("trying " #expr); \ expr; \ BOOST_ERROR(#expr " does not cause " #excp " to be thrown");\ } \ catch(excp& e) {\ \ } catch (std::exception& exp) \ { \ BOOST_ERROR(std::string("unexpected exception ") + exp.what() + "instead of " #excp " caught from "#expr); \ }; // Tests of common FileSystem functions // test init BOOST_AUTO_TEST_SUITE( GenericIOTest ) BOOST_AUTO_TEST_CASE( generic_io_create ) { init_Physfs(); boost::shared_ptr write = boost::make_shared("test.tmp"); boost::shared_ptr read = boost::make_shared("test.tmp"); boost::shared_ptr stream = boost::make_shared(); // no checks, just let this pass without exceptions createGenericReader( read ); createGenericWriter( write ); createGenericReader( stream ); createGenericWriter( stream ); } BOOST_AUTO_TEST_CASE( generic_io_types_test_file ) { boost::shared_ptr write = boost::make_shared("test.tmp"); boost::shared_ptr read = boost::make_shared("test.tmp"); boost::shared_ptr inf = createGenericReader( read ); boost::shared_ptr outf = createGenericWriter( write ); generic_io_types_test_f( inf, outf); }; BOOST_AUTO_TEST_CASE( generic_io_types_test_stream ) { boost::shared_ptr stream = boost::make_shared(); boost::shared_ptr ins = createGenericReader( stream ); boost::shared_ptr outs = createGenericWriter( stream ); generic_io_types_test_f( ins, outs); }; BOOST_AUTO_TEST_CASE( generic_io_generic_types_file ) { boost::shared_ptr write = boost::make_shared("test.tmp"); boost::shared_ptr read = boost::make_shared("test.tmp"); boost::shared_ptr inf = createGenericReader( read ); boost::shared_ptr outf = createGenericWriter( write ); generic_io_types_test_generics_f( inf, outf); }; BOOST_AUTO_TEST_CASE( generic_io_generic_types_stream ) { boost::shared_ptr stream = boost::make_shared(); boost::shared_ptr ins = createGenericReader( stream ); boost::shared_ptr outs = createGenericWriter( stream ); generic_io_types_test_generics_f( ins, outs); }; BOOST_AUTO_TEST_CASE( generic_io_seek_tell ) { boost::shared_ptr write = boost::make_shared("test.tmp"); boost::shared_ptr read = boost::make_shared("test.tmp"); boost::shared_ptr inf = createGenericReader( read ); boost::shared_ptr outf = createGenericWriter( write ); generic_io_seek_tell_f( inf, outf); boost::shared_ptr stream = boost::make_shared(); boost::shared_ptr ins = createGenericReader( stream ); boost::shared_ptr outs = createGenericWriter( stream ); generic_io_seek_tell_f( ins, outs); }; BOOST_AUTO_TEST_CASE( generic_io_generic_types_vector ) { boost::shared_ptr write = boost::make_shared("test.tmp"); boost::shared_ptr read = boost::make_shared("test.tmp"); boost::shared_ptr inf = createGenericReader( read ); boost::shared_ptr outf = createGenericWriter( write ); generic_io_types_test_vector_f >( inf, outf ); generic_io_types_test_vector_f >( inf, outf ); generic_io_types_test_vector_f >( inf, outf ); boost::shared_ptr stream = boost::make_shared(); boost::shared_ptr ins = createGenericReader( stream ); boost::shared_ptr outs = createGenericWriter( stream ); generic_io_types_test_vector_f >( ins, outs ); generic_io_types_test_vector_f >( ins, outs ); generic_io_types_test_vector_f >( ins, outs ); }; BOOST_AUTO_TEST_CASE( generic_io_special_types ) { boost::shared_ptr write = boost::make_shared("test.tmp"); boost::shared_ptr read = boost::make_shared("test.tmp"); boost::shared_ptr inf = createGenericReader( read ); boost::shared_ptr outf = createGenericWriter( write ); generic_io_types_test_special_f( inf, outf); boost::shared_ptr stream = boost::make_shared(); boost::shared_ptr ins = createGenericReader( stream ); boost::shared_ptr outs = createGenericWriter( stream ); generic_io_types_test_special_f( ins, outs); }; BOOST_AUTO_TEST_SUITE_END() void generic_io_types_test_f(boost::shared_ptr in, boost::shared_ptr out) { // writing const unsigned char byte1 = 6; const unsigned char byte2 = 222; const unsigned char byte3 = rand(); out->byte( byte1 ); out->byte( byte2 ); out->byte( byte3 ); out->boolean(true); out->boolean(false); const unsigned int int1 = 8; const unsigned int int2 = 123456; const unsigned int int3 = rand(); out->uint32( int1 ); out->uint32( int2 ); out->uint32( int3 ); const float f1 = 1.54f; const float f2 = -0.785f; const float f3 = (float)rand() / RAND_MAX * 1000; const float f4 = 1.0e10f; out->number( f1 ); out->number( f2 ); out->number( f3 ); out->number( f4 ); std::string str1 = "hello world"; std::string str2 = std::string("s w \0 in it", 11); std::string str3 = std::string(1000, 'l'); out->string( str1 ); out->string( str2 ); out->string( str3 ); out->array( str1.c_str(), str1.size() ); out->array( str2.c_str(), str2.size() ); out->array( str3.c_str(), str3.size() ); // reading unsigned char bytec; in->byte(bytec); BOOST_CHECK_EQUAL( bytec, byte1 ); in->byte(bytec); BOOST_CHECK_EQUAL( bytec, byte2 ); in->byte(bytec); BOOST_CHECK_EQUAL( bytec, byte3 ); bool boolc; in->boolean(boolc); BOOST_CHECK_EQUAL(boolc, true); in->boolean(boolc); BOOST_CHECK_EQUAL(boolc, false); unsigned int intc; in->uint32( intc ); BOOST_CHECK_EQUAL(intc, int1); in->uint32( intc ); BOOST_CHECK_EQUAL(intc, int2); in->uint32( intc ); BOOST_CHECK_EQUAL(intc, int3); float fc; in->number(fc); BOOST_CHECK_EQUAL(fc, f1); in->number(fc); BOOST_CHECK_EQUAL(fc, f2); in->number(fc); BOOST_CHECK_EQUAL(fc, f3); in->number(fc); BOOST_CHECK_EQUAL(fc, f4); std::string stringc; in->string(stringc); BOOST_CHECK_EQUAL(stringc, str1); in->string(stringc); BOOST_CHECK_EQUAL(stringc, str2); in->string(stringc); BOOST_CHECK_EQUAL(stringc, str3); boost::scoped_array ar1(new char[str1.size()]); in->array(ar1.get(), str1.size()); BOOST_CHECK( memcmp(ar1.get(), str1.data(), str1.size()) == 0); boost::scoped_array ar2(new char[str2.size()]); in->array(ar2.get(), str2.size()); BOOST_CHECK( memcmp(ar2.get(), str2.data(), str2.size()) == 0); boost::scoped_array ar3(new char[str3.size()]); in->array(ar3.get(), str3.size()); BOOST_CHECK( memcmp(ar3.get(), str3.data(), str3.size()) == 0); } void generic_io_types_test_generics_f(boost::shared_ptr in, boost::shared_ptr out) { #ifndef DISABLE_COMPILATION_TEST // writing // these are not really run time tests... // it is tested here wether this code compiles. const unsigned char byte = 6; out->generic( byte ); out->generic(true); const unsigned int intv = 8; out->generic( intv ); const float fv = 1.54f; out->generic( fv ); std::string str1 = "hello world"; out->generic( str1 ); // reading unsigned char bytec; in->generic(bytec); BOOST_CHECK_EQUAL( bytec, byte ); bool boolc; in->generic(boolc); BOOST_CHECK_EQUAL(boolc, true); unsigned int intc; in->generic( intc ); BOOST_CHECK_EQUAL(intc, intv); float fc; in->generic(fc); BOOST_CHECK_EQUAL(fc, fv); std::string stringc; in->generic(stringc); #endif } template void generic_io_types_test_vector_f(boost::shared_ptr in, boost::shared_ptr out) { // writing T basevec; for(int i=0; i < 100; ++i) { basevec.push_back(rand()); } const T vector_of_bytes(basevec); out->generic( vector_of_bytes ); // reading // make sure at least one entry of basevec is changed. *basevec.begin() = ~*basevec.begin(); in->generic< T >(basevec); typename T::const_iterator j = vector_of_bytes.begin(); for(typename T::iterator i = basevec.begin(); i != basevec.end(); ++i, ++j) { BOOST_CHECK_EQUAL( *i, *j ); } } void generic_io_seek_tell_f(boost::shared_ptr in, boost::shared_ptr out) { out->uint32(5); int pos = out->tell(); out->uint32(76); out->uint32(13); out->seek(pos); out->uint32(42); unsigned int val; in->uint32(val); pos = in->tell(); in->uint32(val); BOOST_CHECK_EQUAL(val, 42); in->uint32(val); in->seek(pos); in->uint32(val); BOOST_CHECK_EQUAL(val, 42); } void generic_io_types_test_special_f(boost::shared_ptr in, boost::shared_ptr out) { const PlayerInput pi(true, false, false); out->generic(pi); const PlayerSide ps1 = LEFT_PLAYER; const PlayerSide ps2 = RIGHT_PLAYER; const PlayerSide ps3 = NO_PLAYER; out->generic(ps1); out->generic(ps2); out->generic(ps3); const Color col(255, 127, 127); out->generic(col); DuelMatchState dlms; dlms.logicState.leftScore = 12; dlms.logicState.rightScore = 6; dlms.logicState.leftSquish = 8; dlms.logicState.rightSquish = 3; dlms.logicState.servingPlayer = RIGHT_PLAYER; dlms.worldState.blobPosition[LEFT_PLAYER] = Vector2(65, 12); dlms.worldState.blobPosition[RIGHT_PLAYER] = Vector2(465, 120); dlms.worldState.blobVelocity[LEFT_PLAYER] = Vector2(5.2f, 1.f); dlms.worldState.blobVelocity[RIGHT_PLAYER] = Vector2(-5.2f, 1.f); dlms.worldState.ballVelocity = Vector2(8.2f, 12.f); dlms.worldState.ballPosition = Vector2(122.7f, 765.f); dlms.worldState.isBallValid = true; dlms.worldState.isGameRunning = false; dlms.worldState.ballAngularVelocity = 7.43f; dlms.worldState.playerInput[LEFT_PLAYER] = pi; dlms.worldState.playerInput[RIGHT_PLAYER] = PlayerInput(false, false, true); out->generic(dlms); PlayerInput piv; in->generic(piv); /// \todo we can not use CHECK_EQUAL here because we don't have a pretty printer for PlayerInput BOOST_CHECK( pi == piv ); PlayerSide psv; in->generic(psv); BOOST_CHECK_EQUAL(ps1, psv); in->generic(psv); BOOST_CHECK_EQUAL(ps2, psv); in->generic(psv); BOOST_CHECK_EQUAL(ps3, psv); Color colv; in->generic(colv); BOOST_CHECK(col == colv); DuelMatchState dlmsv; in->generic (dlmsv); BOOST_CHECK( dlmsv == dlms ); // sub-object test for better error localisation BOOST_CHECK( dlmsv.logicState == dlms.logicState ); BOOST_CHECK( dlmsv.worldState == dlms.worldState ); } blobby-1.0/src/lua/lualib.h000644 001750 001750 00000002113 12313310253 020372 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lualib.h,v 1.43.1.1 2013/04/12 18:48:47 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ #ifndef lualib_h #define lualib_h #include "lua.h" LUAMOD_API int (luaopen_base) (lua_State *L); #define LUA_COLIBNAME "coroutine" LUAMOD_API int (luaopen_coroutine) (lua_State *L); #define LUA_TABLIBNAME "table" LUAMOD_API int (luaopen_table) (lua_State *L); #define LUA_IOLIBNAME "io" LUAMOD_API int (luaopen_io) (lua_State *L); #define LUA_OSLIBNAME "os" LUAMOD_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" LUAMOD_API int (luaopen_string) (lua_State *L); #define LUA_BITLIBNAME "bit32" LUAMOD_API int (luaopen_bit32) (lua_State *L); #define LUA_MATHLIBNAME "math" LUAMOD_API int (luaopen_math) (lua_State *L); #define LUA_DBLIBNAME "debug" LUAMOD_API int (luaopen_debug) (lua_State *L); #define LUA_LOADLIBNAME "package" LUAMOD_API int (luaopen_package) (lua_State *L); /* open all previous libraries */ LUALIB_API void (luaL_openlibs) (lua_State *L); #if !defined(lua_assert) #define lua_assert(x) ((void)0) #endif #endif blobby-1.0/src/IReplayLoader.h000644 001750 001750 00000012230 12313310251 021034 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include // for time_t #include #include "Global.h" #include "ReplayDefs.h" #include "BlobbyDebug.h" #include "GenericIOFwd.h" struct PlayerInput; class InputSource; /// \class IReplayLoader /// \brief Base class for replay loaders. /// \details \todo add detailed description. class IReplayLoader : public ObjectCounter { public: /// \todo maybe we should use a safeptr here. /// \brief create IReplayLoader by major version /// \details creates a replay loader for replays with a /// certain major version. The minor version of the /// created loader is the highest one possible. /// \return the replay loader or 0 is no sufficient loader has been found. static IReplayLoader* createReplayLoader(int major); /// \brief Creates an IReplayLoader for a certain file. /// \details Determines the version of the file and creates a /// corresponding IReplayLoader. /// \exception \todo we have to add and document the exceptions static IReplayLoader* createReplayLoader(const std::string& file); /// \brief virtual destructor /// \details /// \exception none virtual ~IReplayLoader() {}; // General Interface /// \brief returns the major version of replay files the loader can load. /// \details /// \exception none virtual int getVersionMajor() const = 0; /// \brief returns the maximum minor version this loader can load. /// \details As minor indicates downward compatibility, this indicates /// that all replays with lower minor version can be loaded, too. /// \exception none virtual int getVersionMinor() const = 0; // Attributes Interface /// gets the name of a player virtual std::string getPlayerName(PlayerSide player) const = 0; /// gets blob color of a player virtual Color getBlobColor(PlayerSide player) const = 0; /// get final score of a player virtual int getFinalScore(PlayerSide player) const = 0; /// gets the speed this game was played virtual int getSpeed() const = 0; /// gets the duration of the game in seconds virtual int getDuration() const = 0; /// gets the length of the replay in physic steps virtual int getLength() const = 0; /// gets the date this replay was recorded virtual std::time_t getDate() const = 0; // Replay data interface /// \brief gets the player input at the moment step /// \param step Timestep from when the player input should be received. /// Has to be in range 0 ... getLength(); /// \param left[out] target where left player input is stored /// \param right[out] target where right player input is stored virtual void getInputAt(int step, InputSource* left, InputSource* right) = 0; /// \brief checks wether the specified position is a savepoint /// \param position[in] position to check for savepoint /// \param save_position[out] if \t position is a savepoint, this int /// contains the index of the savepoint /// \return true, if \t position is a savepoint virtual bool isSavePoint(int position, int& save_position) const = 0 ; /// \brief gets the save point at position targetPosition /// \details returns the index of the last safepoint before targetPosition, /// so the game status at targetPosition can be calculated /// by simulating as few steps as possible. /// \param targetPosition[in] which position should be reached /// \param save_position[out] which position the safepoint has /// \return index of the savepoint, or -1 if none found. virtual int getSavePoint(int targetPosition, int& save_position) const = 0; /// \brief reads the specified savepoint /// \param index[in] index of the savepoint, as returned by getSavePoint /// \param state[out] the read savepoint is written there virtual void readSavePoint(int index, ReplaySavePoint& state) const = 0; protected: /// \brief protected constructor. /// \details Create IReplayLoaders with createReplayLoader functions. /// \exception none IReplayLoader() {}; private: /// \todo add documentation virtual void initLoading(boost::shared_ptr file_handle, int minor_version) = 0; }; blobby-1.0/src/PlayerInput.h000644 001750 001750 00000004773 12313310252 020632 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include "BlobbyDebug.h" #include "Global.h" class DuelMatch; namespace RakNet { class BitStream; } /*! \struct PlayerInput \brief struct for easy exchange of a single player input frame */ struct PlayerInput { // constructors PlayerInput() : left(false), right(false), up(false) { } PlayerInput(bool l, bool r, bool u) : left(l), right(r), up(u) { } // set or get complete input as bits in a byte void setAll( unsigned char all ); unsigned char getAll() const; bool operator==(const PlayerInput& other) const; // data bool left; bool right; bool up; }; class PlayerInputAbs { public: PlayerInputAbs(); PlayerInputAbs(RakNet::BitStream& stream); PlayerInputAbs(bool l, bool r, bool j); // set input void setLeft( bool v ); void setRight( bool v ); void setJump( bool v); void setTarget( short target, PlayerSide player ); void swapSides(); // we need some way of getting information about the game, for which we use the match // currently. PlayerInput toPlayerInput( const DuelMatch* match ) const; // send via network void writeTo(RakNet::BitStream& stream); private: enum Flags { F_LEFT = 1, F_RIGHT = 2, F_JUMP = 4, F_RELATIVE = 8 }; unsigned char mFlags; short mTarget; }; // This operator converts a PlayerInput structure in a packed string // suitable for saving std::ostream& operator<< (std::ostream& out, const PlayerInput& input); blobby-1.0/data/gfx/ball08.bmp000644 001750 001750 00000012066 12313310254 020671 0ustar00danielknobedanielknobe000000 000000 BM66(@@  YWZfcfigigeg767QPQNMN{z{rqrjija_`zxxnllgeekjjhggbaaqnldcb~fecggeaa`xywklj  ^b^egeABA~~vwvpqphihegf bee;<<`aajklvvxnnpggieegxxyhhi[[\}}}tttmmmlllkkkgggeeeccc```^^^YYYWWWVVVTTTIII...%%% 酈&d-l- :lGz>A^--l,-+Uf -, '^-GdeeUde -'  dd<<<$qNʗWOOjdff qPOOOQ3deVf,^PpʗΗOde f >POOOO*c& -NmBmOO;R4i*% -fp2OOOPijd&--V7~OOq~N}QR;i<dV:-+bN2(͗}}}pPOTdz+h}MNOP}}}OOOΙ5cUV}OƖPPOT6*8:]lffOPO44Cc%> fV==Y–¿}p}}}O̘nXXXi*elf罾|1KLMhh}}(nn3CiU&>%JLYĖ}OPՁ֋C݃cJ{II{¾LƏP;R߂&o0{{{{–}PRS$ՋX T+{½I{}MQRSwF¾00{}ƐQSjc000}ǗPQ! jco0{L}2W_;4x00WИmΙTg{{JY–mΘgygL{=}QH{{{KL–}2;RvH/{{YҀPEgI{|}2W0|bȗE{F{1–/I{D/F{1L.{.1{/JK{I0Y/blobby-1.0/src/raknet/BitStream.cpp000644 001750 001750 00000102620 12313310247 022061 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * * @brief Implementation of BitStream class * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Uncomment this to check that read and writes match with the same * type and in the case of streams, size. Useful during debugging */ //#define TYPE_CHECKING #ifdef TYPE_CHECKING #ifndef _DEBUG #ifdef _WIN32 #pragma message("Warning: TYPE_CHECKING is defined in BitStream.cpp when not in _DEBUG mode" ) #endif #endif #endif // This should be on by default for speed. Turn it off if you actually need endian swapping #define __BITSTREAM_NATIVE_END #include "BitStream.h" #include #include #include #include #include #include /*if defined ( __APPLE__ ) || defined ( __APPLE_CC__ ) || defined ( __MACOSX__ ) #include #endif*/ #ifdef __BITSTREAM_BIG_END // Set up the read/write routines to produce Big-End network streams. #define B16_1 0 #define B16_0 1 #define B32_3 0 #define B32_2 1 #define B32_1 2 #define B32_0 3 #define B64_7 0 #define B64_6 1 #define B64_5 2 #define B64_4 3 #define B64_3 4 #define B64_2 5 #define B64_1 6 #define B64_0 7 #else // Default to producing Little-End network streams. #define B16_1 1 #define B16_0 0 #define B32_3 3 #define B32_2 2 #define B32_1 1 #define B32_0 0 #define B64_7 7 #define B64_6 6 #define B64_5 5 #define B64_4 4 #define B64_3 3 #define B64_2 2 #define B64_1 1 #define B64_0 0 #endif using namespace RakNet; BitStream::BitStream() { numberOfBitsUsed = 0; numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE * 8; readOffset = 0; data = stackData; copyData = true; } BitStream::BitStream( int initialBytesToAllocate ) { numberOfBitsUsed = 0; readOffset = 0; if (initialBytesToAllocate <= BITSTREAM_STACK_ALLOCATION_SIZE) { data = ( unsigned char* ) stackData; numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE * 8; } else { data = ( unsigned char* ) malloc( initialBytesToAllocate ); numberOfBitsAllocated = initialBytesToAllocate << 3; } #ifdef _DEBUG assert( data ); #endif // memset(data, 0, initialBytesToAllocate); copyData = true; } BitStream::BitStream( char* _data, unsigned int lengthInBytes, bool _copyData ) { numberOfBitsUsed = lengthInBytes << 3; readOffset = 0; copyData = _copyData; numberOfBitsAllocated = lengthInBytes << 3; if ( copyData ) { if ( lengthInBytes > 0 ) { if (lengthInBytes < BITSTREAM_STACK_ALLOCATION_SIZE) { data = ( unsigned char* ) stackData; numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE << 3; } else { data = ( unsigned char* ) malloc( lengthInBytes ); } #ifdef _DEBUG assert( data ); #endif memcpy( data, _data, lengthInBytes ); } else data = 0; } else data = ( unsigned char* ) _data; } // Use this if you pass a pointer copy to the constructor (_copyData==false) and want to overallocate to prevent reallocation void BitStream::SetNumberOfBitsAllocated( const unsigned int lengthInBits ) { #ifdef _DEBUG assert( lengthInBits >= ( unsigned int ) numberOfBitsAllocated ); #endif numberOfBitsAllocated = lengthInBits; } BitStream::~BitStream() { if ( copyData && numberOfBitsAllocated > BITSTREAM_STACK_ALLOCATION_SIZE << 3) free( data ); // Use realloc and free so we are more efficient than delete and new for resizing } void BitStream::Reset( void ) { // Note: Do NOT reallocate memory because BitStream is used // in places to serialize/deserialize a buffer. Reallocation // is a dangerous operation (may result in leaks). if ( numberOfBitsUsed > 0 ) { // memset(data, 0, BITS_TO_BYTES(numberOfBitsUsed)); } // Don't free memory here for speed efficiency //free(data); // Use realloc and free so we are more efficient than delete and new for resizing numberOfBitsUsed = 0; //numberOfBitsAllocated=8; readOffset = 0; //data=(unsigned char*)malloc(1); // if (numberOfBitsAllocated>0) // memset(data, 0, BITS_TO_BYTES(numberOfBitsAllocated)); } // Write the native types to the end of the buffer void BitStream::Write( const bool input ) { #ifdef TYPE_CHECKING unsigned char ID = 0; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif if ( input ) Write1(); else Write0(); } void BitStream::Write( const unsigned char input ) { #ifdef TYPE_CHECKING unsigned char ID = 1; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif WriteBits( ( unsigned char* ) & input, sizeof( input ) * 8, true ); } void BitStream::Write( const char input ) { #ifdef TYPE_CHECKING unsigned char ID = 2; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif WriteBits( ( unsigned char* ) & input, sizeof( input ) * 8, true ); } void BitStream::Write( const unsigned short input ) { #ifdef TYPE_CHECKING unsigned char ID = 3; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif #ifdef __BITSTREAM_NATIVE_END WriteBits( ( unsigned char* ) & input, sizeof( input ) * 8, true ); #else static unsigned char uint16w[2]; uint16w[B16_1] = (input >> 8)&(0xff); uint16w[B16_0] = input&(0xff); WriteBits( uint16w, sizeof( input ) * 8, true ); #endif } void BitStream::Write( const short input ) { #ifdef TYPE_CHECKING unsigned char ID = 4; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif #ifdef __BITSTREAM_NATIVE_END WriteBits( ( unsigned char* ) & input, sizeof( input ) * 8, true ); #else static unsigned char int16w[2]; int16w[B16_1] = (input >> 8)&(0xff); int16w[B16_0] = input&(0xff); WriteBits( int16w, sizeof( input ) * 8, true ); #endif } void BitStream::Write( const unsigned int input ) { #ifdef TYPE_CHECKING unsigned char ID = 5; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif #ifdef __BITSTREAM_NATIVE_END WriteBits( ( unsigned char* ) & input, sizeof( input ) * 8, true ); #else static unsigned char uint32w[4]; uint32w[B32_3] = (input >> 24)&(0x000000ff); uint32w[B32_2] = (input >> 16)&(0x000000ff); uint32w[B32_1] = (input >> 8)&(0x000000ff); uint32w[B32_0] = (input)&(0x000000ff); WriteBits( uint32w, sizeof( input ) * 8, true ); #endif } void BitStream::Write( const int input ) { #ifdef TYPE_CHECKING unsigned char ID = 6; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif #ifdef __BITSTREAM_NATIVE_END WriteBits( ( unsigned char* ) & input, sizeof( input ) * 8, true ); #else static unsigned char int32w[4]; int32w[B32_3] = (input >> 24)&(0x000000ff); int32w[B32_2] = (input >> 16)&(0x000000ff); int32w[B32_1] = (input >> 8)&(0x000000ff); int32w[B32_0] = (input)&(0x000000ff); WriteBits( int32w, sizeof( input ) * 8, true ); #endif } void BitStream::Write( const float input ) { #ifdef TYPE_CHECKING unsigned char ID = 9; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif #ifndef __BITSTREAM_NATIVE_END unsigned int intval = *((unsigned int *)(&input)); Write(intval); #else WriteBits( ( unsigned char* ) & input, sizeof( input ) * 8, true ); #endif } void BitStream::Write( const double input ) { #ifdef TYPE_CHECKING unsigned char ID = 10; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif WriteBits( ( unsigned char* ) & input, sizeof( input ) * 8, true ); } // Write an array or casted stream void BitStream::Write( const char* input, const int numberOfBytes ) { #ifdef TYPE_CHECKING unsigned char ID = 11; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); WriteBits( ( unsigned char* ) & numberOfBytes, sizeof( int ) * 8, true ); #endif WriteBits( ( unsigned char* ) input, numberOfBytes * 8, true ); } // Write the native types with simple compression. // Best used with negatives and positives close to 0 void BitStream::WriteCompressed( const unsigned char input ) { #ifdef TYPE_CHECKING unsigned char ID = 12; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif WriteCompressed( ( unsigned char* ) & input, sizeof( input ) * 8, true ); } void BitStream::WriteCompressed( const char input ) { #ifdef TYPE_CHECKING unsigned char ID = 13; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif WriteCompressed( ( unsigned char* ) & input, sizeof( input ) * 8, false ); } void BitStream::WriteCompressed( const unsigned short input ) { #ifdef TYPE_CHECKING unsigned char ID = 14; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif #ifdef __BITSTREAM_NATIVE_END WriteCompressed( ( unsigned char* ) & input, sizeof( input ) * 8, true ); #else static unsigned char uint16wc[2]; uint16wc[B16_1] = (input >> 8)&(0xff); uint16wc[B16_0] = input&(0xff); WriteCompressed( uint16wc, sizeof( input ) * 8, true ); #endif } void BitStream::WriteCompressed( const short input ) { #ifdef TYPE_CHECKING unsigned char ID = 15; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif #ifdef __BITSTREAM_NATIVE_END WriteCompressed( ( unsigned char* ) & input, sizeof( input ) * 8, true ); #else static unsigned char int16wc[2]; int16wc[B16_1] = (input >> 8)&(0xff); int16wc[B16_0] = input&(0xff); WriteCompressed( int16wc, sizeof( input ) * 8, false ); #endif } void BitStream::WriteCompressed( const unsigned int input ) { #ifdef TYPE_CHECKING unsigned char ID = 16; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif #ifdef __BITSTREAM_NATIVE_END WriteCompressed( ( unsigned char* ) & input, sizeof( input ) * 8, true ); #else static unsigned char uint32wc[4]; uint32wc[B32_3] = (input >> 24)&(0x000000ff); uint32wc[B32_2] = (input >> 16)&(0x000000ff); uint32wc[B32_1] = (input >> 8)&(0x000000ff); uint32wc[B32_0] = (input)&(0x000000ff); WriteCompressed( uint32wc, sizeof( input ) * 8, true ); #endif } void BitStream::WriteCompressed( const int input ) { #ifdef TYPE_CHECKING unsigned char ID = 17; WriteBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8, true ); #endif #ifdef __BITSTREAM_NATIVE_END WriteCompressed( ( unsigned char* ) & input, sizeof( input ) * 8, true ); #else static unsigned char int32wc[4]; int32wc[B32_3] = (input >> 24)&(0x000000ff); int32wc[B32_2] = (input >> 16)&(0x000000ff); int32wc[B32_1] = (input >> 8)&(0x000000ff); int32wc[B32_0] = (input)&(0x000000ff); WriteCompressed( int32wc, sizeof( input ) * 8, false ); #endif } // Read the native types from the front of the buffer // Write the native types to the end of the buffer bool BitStream::Read( bool& output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; #ifdef _DEBUG assert( ID == 0 ); #endif #endif //assert(readOffset+1 <=numberOfBitsUsed); // If this assert is hit the stream wasn't long enough to read from if ( readOffset + 1 > numberOfBitsUsed ) return false; //if (ReadBit()) // Check that bit if ( data[ readOffset >> 3 ] & ( 0x80 >> ( readOffset % 8 ) ) ) // Is it faster to just write it out here? output = true; else output = false; readOffset++; return true; } bool BitStream::Read( unsigned char &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 1 ); #endif return ReadBits( ( unsigned char* ) & output, sizeof( output ) * 8 ); } bool BitStream::Read( char &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 2 ); #endif return ReadBits( ( unsigned char* ) & output, sizeof( output ) * 8 ); } bool BitStream::Read( unsigned short &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 3 ); #endif #ifdef __BITSTREAM_NATIVE_END return ReadBits( ( unsigned char* ) & output, sizeof( output ) * 8 ); #else static unsigned char uint16r[2]; if (ReadBits( uint16r, sizeof( output ) * 8 ) != true) return false; output = (((unsigned short) uint16r[B16_1])<<8)|((unsigned short)uint16r[B16_0]); return true; #endif } bool BitStream::Read( short &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 4 ); #endif #ifdef __BITSTREAM_NATIVE_END return ReadBits( ( unsigned char* ) & output, sizeof( output ) * 8 ); #else static unsigned char int16r[2]; if (ReadBits( int16r, sizeof( output ) * 8 ) != true) return false; output = (((unsigned short) int16r[B16_1])<<8)|((unsigned short)int16r[B16_0]); return true; #endif } bool BitStream::Read( unsigned int &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 5 ); #endif #ifdef __BITSTREAM_NATIVE_END return ReadBits( ( unsigned char* ) & output, sizeof( output ) * 8 ); #else static unsigned char uint32r[4]; if(ReadBits( uint32r, sizeof( output ) * 8 ) != true) return false; output = (((unsigned int) uint32r[B32_3])<<24)| (((unsigned int) uint32r[B32_2])<<16)| (((unsigned int) uint32r[B32_1])<<8)| ((unsigned int) uint32r[B32_0]); return true; #endif } bool BitStream::Read( int &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 6 ); #endif #ifdef __BITSTREAM_NATIVE_END return ReadBits( ( unsigned char* ) & output, sizeof( output ) * 8 ); #else static unsigned char int32r[4]; if(ReadBits( int32r, sizeof( output ) * 8 ) != true) return false; output = (((unsigned int) int32r[B32_3])<<24)| (((unsigned int) int32r[B32_2])<<16)| (((unsigned int) int32r[B32_1])<<8)| ((unsigned int) int32r[B32_0]); return true; #endif } bool BitStream::Read( float &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 9 ); #endif #ifdef __BITSTREAM_NATIVE_END return ReadBits( ( unsigned char* ) & output, sizeof( output ) * 8 ); #else unsigned int val; if (Read(val) == false) return false; output = *((float *)(&val)); return true; #endif } bool BitStream::Read( double &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 10 ); #endif return ReadBits( ( unsigned char* ) & output, sizeof( output ) * 8 ); } // Read an array or casted stream bool BitStream::Read( char* output, const int numberOfBytes ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 11 ); int NOB; ReadBits( ( unsigned char* ) & NOB, sizeof( int ) * 8 ); assert( NOB == numberOfBytes ); #endif return ReadBits( ( unsigned char* ) output, numberOfBytes * 8 ); } // Read the types you wrote with WriteCompressed bool BitStream::ReadCompressed( unsigned char & output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 12 ); #endif return ReadCompressed( ( unsigned char* ) & output, sizeof( output ) * 8, true ); } bool BitStream::ReadCompressed( char &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 13 ); #endif return ReadCompressed( ( unsigned char* ) & output, sizeof( output ) * 8, false ); } bool BitStream::ReadCompressed( unsigned short &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 14 ); #endif #ifdef __BITSTREAM_NATIVE_END return ReadCompressed( ( unsigned char* ) & output, sizeof( output ) * 8, true ); #else static unsigned char uint16rc[2]; if (ReadCompressed( uint16rc, sizeof( output ) * 8, true ) != true) return false; output = (((unsigned short) uint16rc[B16_1])<<8)| ((unsigned short)uint16rc[B16_0]); return true; #endif } bool BitStream::ReadCompressed( short &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 15 ); #endif #ifdef __BITSTREAM_NATIVE_END return ReadCompressed( ( unsigned char* ) & output, sizeof( output ) * 8, true ); #else static unsigned char int16rc[2]; if (ReadCompressed( int16rc, sizeof( output ) * 8, false ) != true) return false; output = (((unsigned short) int16rc[B16_1])<<8)|((unsigned short)int16rc[B16_0]); return true; #endif } bool BitStream::ReadCompressed( unsigned int &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 16 ); #endif #ifdef __BITSTREAM_NATIVE_END return ReadCompressed( ( unsigned char* ) & output, sizeof( output ) * 8, true ); #else static unsigned char uint32rc[4]; if(ReadCompressed( uint32rc, sizeof( output ) * 8, true ) != true) return false; output = (((unsigned int) uint32rc[B32_3])<<24)| (((unsigned int) uint32rc[B32_2])<<16)| (((unsigned int) uint32rc[B32_1])<<8)| ((unsigned int) uint32rc[B32_0]); return true; #endif } bool BitStream::ReadCompressed( int &output ) { #ifdef TYPE_CHECKING unsigned char ID; if ( ReadBits( ( unsigned char* ) & ID, sizeof(unsigned char) * 8 ) == false ) return false; assert( ID == 17 ); #endif #ifdef __BITSTREAM_NATIVE_END return ReadCompressed( ( unsigned char* ) & output, sizeof( output ) * 8, true ); #else static unsigned char int32rc[4]; if(ReadCompressed( int32rc, sizeof( output ) * 8, false ) != true) return false; output = (((unsigned int) int32rc[B32_3])<<24)| (((unsigned int) int32rc[B32_2])<<16)| (((unsigned int) int32rc[B32_1])<<8)| ((unsigned int) int32rc[B32_0]); return true; #endif } // Sets the read pointer back to the beginning of your data. void BitStream::ResetReadPointer( void ) { readOffset = 0; } // Sets the write pointer back to the beginning of your data. void BitStream::ResetWritePointer( void ) { numberOfBitsUsed = 0; } // Write a 0 void BitStream::Write0( void ) { AddBitsAndReallocate( 1 ); // New bytes need to be zeroed if ( ( numberOfBitsUsed % 8 ) == 0 ) data[ numberOfBitsUsed >> 3 ] = 0; numberOfBitsUsed++; // This ++ was in the line above - but boundschecker didn't like that for some reason. } // Write a 1 void BitStream::Write1( void ) { AddBitsAndReallocate( 1 ); int numberOfBitsMod8 = numberOfBitsUsed % 8; if ( numberOfBitsMod8 == 0 ) data[ numberOfBitsUsed >> 3 ] = 0x80; else data[ numberOfBitsUsed >> 3 ] |= 0x80 >> ( numberOfBitsMod8 ); // Set the bit to 1 numberOfBitsUsed++; // This ++ was in the line above - but boundschecker didn't like that for some reason. } // Returns true if the next data read is a 1, false if it is a 0 bool BitStream::ReadBit( void ) { #pragma warning( disable : 4800 ) readOffset++; return ( bool ) ( data[ readOffset-1 >> 3 ] & ( 0x80 >> ( (readOffset-1) % 8 ) ) ); #pragma warning( default : 4800 ) } // Align the bitstream to the byte boundary and then write the specified number of bits. // This is faster than WriteBits but wastes the bits to do the alignment and requires you to call // SetReadToByteAlignment at the corresponding read position void BitStream::WriteAlignedBytes( const unsigned char* input, const int numberOfBytesToWrite ) { #ifdef _DEBUG assert( numberOfBytesToWrite > 0 ); #endif AlignWriteToByteBoundary(); // Allocate enough memory to hold everything AddBitsAndReallocate( numberOfBytesToWrite << 3 ); // Write the data memcpy( data + ( numberOfBitsUsed >> 3 ), input, numberOfBytesToWrite ); numberOfBitsUsed += numberOfBytesToWrite << 3; } // Read bits, starting at the next aligned bits. Note that the modulus 8 starting offset of the // sequence must be the same as was used with WriteBits. This will be a problem with packet coalescence // unless you byte align the coalesced packets. bool BitStream::ReadAlignedBytes( unsigned char* output, const int numberOfBytesToRead ) { #ifdef _DEBUG assert( numberOfBytesToRead > 0 ); #endif if ( numberOfBytesToRead <= 0 ) return false; // Byte align AlignReadToByteBoundary(); if ( readOffset + ( numberOfBytesToRead << 3 ) > numberOfBitsUsed ) return false; // Write the data memcpy( output, data + ( readOffset >> 3 ), numberOfBytesToRead ); readOffset += numberOfBytesToRead << 3; return true; } // Align the next write and/or read to a byte boundary. This can be used to 'waste' bits to byte align for efficiency reasons void BitStream::AlignWriteToByteBoundary( void ) { if ( numberOfBitsUsed ) numberOfBitsUsed += 8 - ( ( numberOfBitsUsed - 1 ) % 8 + 1 ); } // Align the next write and/or read to a byte boundary. This can be used to 'waste' bits to byte align for efficiency reasons void BitStream::AlignReadToByteBoundary( void ) { if ( readOffset ) readOffset += 8 - ( ( readOffset - 1 ) % 8 + 1 ); } // Write numberToWrite bits from the input source void BitStream::WriteBits( const unsigned char *input, int numberOfBitsToWrite, const bool rightAlignedBits ) { // if (numberOfBitsToWrite<=0) // return; AddBitsAndReallocate( numberOfBitsToWrite ); int offset = 0; int numberOfBitsUsedMod8; numberOfBitsUsedMod8 = numberOfBitsUsed % 8; // Faster to put the while at the top surprisingly enough while ( numberOfBitsToWrite > 0 ) //do { unsigned char dataByte = *( input + offset ); if ( numberOfBitsToWrite < 8 && rightAlignedBits ) // rightAlignedBits means in the case of a partial byte, the bits are aligned from the right (bit 0) rather than the left (as in the normal internal representation) dataByte <<= 8 - numberOfBitsToWrite; // shift left to get the bits on the left, as in our internal representation // Writing to a new byte each time if ( numberOfBitsUsedMod8 == 0 ) * ( data + ( numberOfBitsUsed >> 3 ) ) = dataByte; else { // Copy over the new data. *( data + ( numberOfBitsUsed >> 3 ) ) |= dataByte >> ( numberOfBitsUsedMod8 ); // First half if ( 8 - ( numberOfBitsUsedMod8 ) < 8 && 8 - ( numberOfBitsUsedMod8 ) < numberOfBitsToWrite ) // If we didn't write it all out in the first half (8 - (numberOfBitsUsed%8) is the number we wrote in the first half) { *( data + ( numberOfBitsUsed >> 3 ) + 1 ) = (unsigned char) ( dataByte << ( 8 - ( numberOfBitsUsedMod8 ) ) ); // Second half (overlaps byte boundary) } } if ( numberOfBitsToWrite >= 8 ) numberOfBitsUsed += 8; else numberOfBitsUsed += numberOfBitsToWrite; numberOfBitsToWrite -= 8; offset++; } // } while(numberOfBitsToWrite>0); } // Set the stream to some initial data. For internal use void BitStream::SetData( const unsigned char* input, const int numberOfBits ) { #ifdef _DEBUG assert( numberOfBitsUsed == 0 ); // Make sure the stream is clear #endif if ( numberOfBits <= 0 ) return ; AddBitsAndReallocate( numberOfBits ); memcpy( data, input, BITS_TO_BYTES( numberOfBits ) ); numberOfBitsUsed = numberOfBits; } // Assume the input source points to a native type, compress and write it void BitStream::WriteCompressed( const unsigned char* input, const int size, const bool unsignedData ) { int currentByte = ( size >> 3 ) - 1; // PCs unsigned char byteMatch; if ( unsignedData ) { byteMatch = 0; } else { byteMatch = 0xFF; } // Write upper bytes with a single 1 // From high byte to low byte, if high byte is a byteMatch then write a 1 bit. Otherwise write a 0 bit and then write the remaining bytes while ( currentByte > 0 ) { if ( input[ currentByte ] == byteMatch ) // If high byte is byteMatch (0 of 0xff) then it would have the same value shifted { bool b = true; Write( b ); } else { // Write the remainder of the data after writing 0 bool b = false; Write( b ); WriteBits( input, ( currentByte + 1 ) << 3, true ); // currentByte--; return ; } currentByte--; } // If the upper half of the last byte is a 0 (positive) or 16 (negative) then write a 1 and the remaining 4 bits. Otherwise write a 0 and the 8 bites. if ( ( unsignedData && ( ( *( input + currentByte ) ) & 0xF0 ) == 0x00 ) || ( unsignedData == false && ( ( *( input + currentByte ) ) & 0xF0 ) == 0xF0 ) ) { bool b = true; Write( b ); WriteBits( input + currentByte, 4, true ); } else { bool b = false; Write( b ); WriteBits( input + currentByte, 8, true ); } } // Read numberOfBitsToRead bits to the output source // alignBitsToRight should be set to true to convert internal bitstream data to userdata // It should be false if you used WriteBits with rightAlignedBits false bool BitStream::ReadBits( unsigned char* output, int numberOfBitsToRead, const bool alignBitsToRight ) { #ifdef _DEBUG assert( numberOfBitsToRead > 0 ); #endif // if (numberOfBitsToRead<=0) // return false; if ( readOffset + numberOfBitsToRead > numberOfBitsUsed ) return false; int readOffsetMod8; int offset = 0; memset( output, 0, BITS_TO_BYTES( numberOfBitsToRead ) ); readOffsetMod8 = readOffset % 8; // do // Faster to put the while at the top surprisingly enough while ( numberOfBitsToRead > 0 ) { *( output + offset ) |= *( data + ( readOffset >> 3 ) ) << ( readOffsetMod8 ); // First half if ( readOffsetMod8 > 0 && numberOfBitsToRead > 8 - ( readOffsetMod8 ) ) // If we have a second half, we didn't read enough bytes in the first half *( output + offset ) |= *( data + ( readOffset >> 3 ) + 1 ) >> ( 8 - ( readOffsetMod8 ) ); // Second half (overlaps byte boundary) numberOfBitsToRead -= 8; if ( numberOfBitsToRead < 0 ) // Reading a partial byte for the last byte, shift right so the data is aligned on the right { if ( alignBitsToRight ) * ( output + offset ) >>= -numberOfBitsToRead; readOffset += 8 + numberOfBitsToRead; } else readOffset += 8; offset++; } //} while(numberOfBitsToRead>0); return true; } // Assume the input source points to a compressed native type. Decompress and read it bool BitStream::ReadCompressed( unsigned char* output, const int size, const bool unsignedData ) { int currentByte = ( size >> 3 ) - 1; unsigned char byteMatch, halfByteMatch; if ( unsignedData ) { byteMatch = 0; halfByteMatch = 0; } else { byteMatch = 0xFF; halfByteMatch = 0xF0; } // Upper bytes are specified with a single 1 if they match byteMatch // From high byte to low byte, if high byte is a byteMatch then write a 1 bit. Otherwise write a 0 bit and then write the remaining bytes while ( currentByte > 0 ) { // If we read a 1 then the data is byteMatch. bool b; if ( Read( b ) == false ) return false; if ( b ) // Check that bit { output[ currentByte ] = byteMatch; currentByte--; } else { // Read the rest of the bytes if ( ReadBits( output, ( currentByte + 1 ) << 3 ) == false ) return false; return true; } } // All but the first bytes are byteMatch. If the upper half of the last byte is a 0 (positive) or 16 (negative) then what we read will be a 1 and the remaining 4 bits. // Otherwise we read a 0 and the 8 bytes //assert(readOffset+1 <=numberOfBitsUsed); // If this assert is hit the stream wasn't long enough to read from if ( readOffset + 1 > numberOfBitsUsed ) return false; bool b; if ( Read( b ) == false ) return false; if ( b ) // Check that bit { if ( ReadBits( output + currentByte, 4 ) == false ) return false; output[ currentByte ] |= halfByteMatch; // We have to set the high 4 bits since these are set to 0 by ReadBits } else { if ( ReadBits( output + currentByte, 8 ) == false ) return false; } return true; } // Reallocates (if necessary) in preparation of writing numberOfBitsToWrite void BitStream::AddBitsAndReallocate( const int numberOfBitsToWrite ) { if ( numberOfBitsToWrite <= 0 ) return; int newNumberOfBitsAllocated = numberOfBitsToWrite + numberOfBitsUsed; if ( numberOfBitsToWrite + numberOfBitsUsed > 0 && ( ( numberOfBitsAllocated - 1 ) >> 3 ) < ( ( newNumberOfBitsAllocated - 1 ) >> 3 ) ) // If we need to allocate 1 or more new bytes { #ifdef _DEBUG // If this assert hits then we need to specify true for the third parameter in the constructor // It needs to reallocate to hold all the data and can't do it unless we allocated to begin with assert( copyData == true ); #endif // Less memory efficient but saves on news and deletes newNumberOfBitsAllocated = ( numberOfBitsToWrite + numberOfBitsUsed ) * 2; // int newByteOffset = BITS_TO_BYTES( numberOfBitsAllocated ); // Use realloc and free so we are more efficient than delete and new for resizing int amountToAllocate = BITS_TO_BYTES( newNumberOfBitsAllocated ); if (data==(unsigned char*)stackData) { if (amountToAllocate > BITSTREAM_STACK_ALLOCATION_SIZE) { data = ( unsigned char* ) malloc( amountToAllocate ); // need to copy the stack data over to our new memory area too memcpy ((void *)data, (void *)stackData, BITS_TO_BYTES( numberOfBitsAllocated )); } } else { data = ( unsigned char* ) realloc( data, amountToAllocate ); } #ifdef _DEBUG assert( data ); // Make sure realloc succeeded #endif // memset(data+newByteOffset, 0, ((newNumberOfBitsAllocated-1)>>3) - ((numberOfBitsAllocated-1)>>3)); // Set the new data block to 0 } if ( newNumberOfBitsAllocated > numberOfBitsAllocated ) numberOfBitsAllocated = newNumberOfBitsAllocated; } // Should hit if reads didn't match writes void BitStream::AssertStreamEmpty( void ) { assert( readOffset == numberOfBitsUsed ); } void BitStream::PrintBits( void ) const { if ( numberOfBitsUsed <= 0 ) { printf( "No bits\n" ); return ; } for ( int counter = 0; counter < BITS_TO_BYTES( numberOfBitsUsed ); counter++ ) { int stop; if ( counter == ( numberOfBitsUsed - 1 ) >> 3 ) stop = 8 - ( ( ( numberOfBitsUsed - 1 ) % 8 ) + 1 ); else stop = 0; for ( int counter2 = 7; counter2 >= stop; counter2-- ) { if ( ( data[ counter ] >> counter2 ) & 1 ) putchar( '1' ); else putchar( '0' ); } putchar( ' ' ); } putchar( '\n' ); } // Exposes the data for you to look at, like PrintBits does. // Data will point to the stream. Returns the length in bits of the stream. int BitStream::CopyData( unsigned char** _data ) const { #ifdef _DEBUG assert( numberOfBitsUsed > 0 ); #endif *_data = new unsigned char [ BITS_TO_BYTES( numberOfBitsUsed ) ]; memcpy( *_data, data, sizeof(unsigned char) * ( BITS_TO_BYTES( numberOfBitsUsed ) ) ); return numberOfBitsUsed; } // Ignore data we don't intend to read void BitStream::IgnoreBits( const int numberOfBits ) { readOffset += numberOfBits; } void BitStream::IgnoreBytes( const int numberOfBytes ) { IgnoreBits( 8 * numberOfBytes ); } // Move the write pointer to a position on the array. Dangerous if you don't know what you are doing! void BitStream::SetWriteOffset( const int offset ) { numberOfBitsUsed = offset; } // Returns the length in bits of the stream int BitStream::GetNumberOfBitsUsed( void ) const { return numberOfBitsUsed; } // Returns the length in bytes of the stream int BitStream::GetNumberOfBytesUsed( void ) const { return BITS_TO_BYTES( numberOfBitsUsed ); } // Returns the number of bits into the stream that we have read int BitStream::GetReadOffset( void ) const { return readOffset; } // Returns the number of bits left in the stream that haven't been read int BitStream::GetNumberOfUnreadBits( void ) const { return numberOfBitsUsed - readOffset; } // Exposes the internal data unsigned char* BitStream::GetData( void ) const { return data; } // If we used the constructor version with copy data off, this makes sure it is set to on and the data pointed to is copied. void BitStream::AssertCopyData( void ) { if ( copyData == false ) { copyData = true; if ( numberOfBitsAllocated > 0 ) { unsigned char * newdata = ( unsigned char* ) malloc( BITS_TO_BYTES( numberOfBitsAllocated ) ); #ifdef _DEBUG assert( data ); #endif memcpy( newdata, data, BITS_TO_BYTES( numberOfBitsAllocated ) ); data = newdata; } else data = 0; } } blobby-1.0/data/config.xml000644 001750 001750 00000002634 12313310255 020313 0ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/ReplayLoader.cpp000644 001750 001750 00000023747 12313310252 021276 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "IReplayLoader.h" /* includes */ #include #include #include #include #include // debugging #include #include #include "InputSource.h" #include "FileRead.h" #include "GenericIO.h" /* implementation */ IReplayLoader* IReplayLoader::createReplayLoader(const std::string& filename) { // do some generic loading stuff: // first, try to open the file boost::shared_ptr file = boost::make_shared(filename); // then, check the file length. We need at least 12 bytes. int fileLength = file->length(); if (fileLength < 12) { /// \todo add some error handling here! return 0; } // check if file contains a valid BV2 header char header[4]; file->readRawBytes(header, sizeof(header)); if (memcmp(&header, &validHeader, 4) != 0) { /// \todo add some error handling here! return 0; } // now, find out which version we need! char version[4]; file->readRawBytes(version, sizeof(version)); // now we got our version number. int major = version[1]; int minor = version[2]; // read checksum uint32_t checksum; file->readRawBytes((char*)&checksum, 4); // calculate reference checksum uint32_t refchecksum = file->calcChecksum(file->tell()); if(refchecksum != checksum && major > 0 && minor > 0) { BOOST_THROW_EXCEPTION (ChecksumException(file->getFileName(), checksum, refchecksum)); } IReplayLoader* loader = createReplayLoader(major); boost::shared_ptr in = createGenericReader(file); loader->initLoading(in, minor); return loader; } /*************************************************************************************************** R E P L A Y L O A D E R V 0.1 ***************************************************************************************************/ // That version used different physics than we use now, and it does not include any save-points that would // allow to extrapolate the match, so we could not play these matches, even if we had a loader for them // // ------------------------------------------------------------------------------------------------- // /*************************************************************************************************** R E P L A Y L O A D E R V 1.x ***************************************************************************************************/ /*! \class ReplayLoader_V1X \brief Replay Loader V 1.x \details Replay Loader for 1.0 and 1.1 replays */ class ReplayLoader_V1X: public IReplayLoader { public: ReplayLoader_V1X() {}; virtual ~ReplayLoader_V1X() { }; virtual int getVersionMajor() const { return 1; }; virtual int getVersionMinor() const { return 1; }; virtual std::string getPlayerName(PlayerSide player) const { if(player == LEFT_PLAYER) return mLeftPlayerName; if(player == RIGHT_PLAYER) return mRightPlayerName; assert(0); } virtual Color getBlobColor(PlayerSide player) const { if(player == LEFT_PLAYER) return mLeftColor; if(player == RIGHT_PLAYER) return mRightColor; assert(0); } virtual int getFinalScore(PlayerSide player) const { if(player == LEFT_PLAYER) return mLeftFinalScore; if(player == RIGHT_PLAYER) return mRightFinalScore; assert(0); } virtual int getSpeed() const { return mGameSpeed; }; virtual int getDuration() const { return mGameDuration; }; virtual int getLength() const { return mGameLength; }; virtual std::time_t getDate() const { return mGameDate; }; virtual void getInputAt(int step, InputSource* left, InputSource* right) { assert( step < mGameLength ); // for now, we have only a linear sequence of InputPackets, so finding the right one is just // a matter of address arithmetics. // each packet has size 1 byte for now // so we find step at mReplayOffset + step char packet = mBuffer[mReplayOffset + step]; // now read the packet data left->setInput(PlayerInput((bool)(packet & 32), (bool)(packet & 16), (bool)(packet & 8))); right->setInput(PlayerInput((bool)(packet & 4), (bool)(packet & 2), (bool)(packet & 1))); } virtual bool isSavePoint(int position, int& save_position) const { int foundPos; save_position = getSavePoint(position, foundPos); return save_position != -1 && foundPos == position; } // TODO: add optional argument: int previous = 0; // so we can start from it when calling // getSavePoint in a row (without "jumping"). // we can save this parameter in ReplayPlayer virtual int getSavePoint(int targetPosition, int& savepoint) const { // desired index can't be lower that this value, // cause additional savepoints could shift it only right int index = targetPosition / REPLAY_SAVEPOINT_PERIOD; if(index >= mSavePointsCount) return -1; savepoint = mSavePoints[index].step; // watch right from initial index, // cause best savepoint could be there. // we have no much additional savepoints, // so this cycle would be fast, // maybe even faster than binary search. do { int nextIndex = index + 1; if (nextIndex >= mSavePointsCount) break; int nextPos = mSavePoints[nextIndex].step; if (nextPos > targetPosition) break; index = nextIndex; savepoint = nextPos; } while (true); return index; } virtual void readSavePoint(int index, ReplaySavePoint& state) const { state = mSavePoints.at(index); } private: virtual void initLoading(boost::shared_ptr file, int minor_version) { mReplayFormatVersion = minor_version; mSavePoints.resize(0); /// \todo check if minor_version < getVersionMinor, otherwise issue a warning // we start with the replay header. uint32_t header_size, attr_ptr , attr_size , jptb_ptr, jptb_size , data_ptr , data_size, states_ptr, states_size; file->uint32(header_size); file->uint32(attr_ptr); file->uint32(attr_size); file->uint32(jptb_ptr); file->uint32(jptb_size); file->uint32(data_ptr); file->uint32(data_size); // legacy support for 1.0 RC 1 replays if(minor_version != 0) { file->uint32(states_ptr); file->uint32(states_size); } // now, we read the attributes section // jump over the attr - marker file->seek(attr_ptr + 4); // copy attributes into buffer // read the attributes file->uint32(mGameSpeed); file->uint32(mGameDuration); file->uint32(mGameLength); file->uint32(mGameDate); file->generic (mLeftColor); file->generic (mRightColor); if(minor_version != 0) { file->uint32(mLeftFinalScore); file->uint32(mRightFinalScore); file->string(mLeftPlayerName); file->string(mRightPlayerName); } else { mLeftPlayerName = ""; unsigned char c; do { file->byte(c); mLeftPlayerName += c; } while(c); mRightPlayerName = ""; do { file->byte(c); mRightPlayerName += c; } while(c); } // now, read the raw data file->seek(data_ptr + 8); // jump over the dat marker and over the length value /// \todo why do we set mBufferSize again? should we check if these two are identical // read into buffer std::cout << "read into buffer\n"; std::cout << "length: " << mGameLength << " " << data_size << "\n"; mBuffer = boost::shared_array(new char[data_size]); file->array(mBuffer.get(), data_size); mReplayOffset = 0; // now read savepoints if(minor_version != 0) { file->seek(states_ptr + 4); // jump over the sta marker file->uint32(mSavePointsCount); std::cout << "read " << mSavePointsCount << " savepoints\n"; mSavePoints.reserve(mSavePointsCount); for(int i = 0; i < mSavePointsCount; ++i) { ReplaySavePoint sp; file->generic(sp); mSavePoints.push_back(sp); } } else { mSavePointsCount = 0; } /// \todo check that mSavePointsCount and states_size match } boost::shared_array mBuffer; uint32_t mReplayOffset; std::vector mSavePoints; uint32_t mSavePointsCount; // specific data std::string mLeftPlayerName; std::string mRightPlayerName; unsigned int mLeftFinalScore; unsigned int mRightFinalScore; unsigned int mGameSpeed; unsigned int mGameDate; unsigned int mGameLength; unsigned int mGameDuration; Color mLeftColor; Color mRightColor; unsigned char mReplayFormatVersion; }; IReplayLoader* IReplayLoader::createReplayLoader(int major) { // we find a loader depending on major version /// \todo throw, when version is too old switch(major) { case 0: break; case 1: return new ReplayLoader_V1X(); break; } // fallback return 0; } blobby-1.0/src/server/DedicatedServer.cpp000644 001750 001750 00000036453 12313310252 023254 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #include "DedicatedServer.h" #include #include #include #include "raknet/RakServer.h" #include "raknet/PacketEnumerations.h" #include "NetworkMessage.h" #include "NetworkGame.h" #include "GenericIO.h" #ifndef WIN32 #ifndef __ANDROID__ #include #endif #endif extern int SWLS_PacketCount; extern int SWLS_Connections; extern int SWLS_Games; extern int SWLS_GameSteps; void syslog(int pri, const char* format, ...); DedicatedServer::DedicatedServer(const ServerInfo& info, const std::string& rulefile, int max_clients) : mConnectedClients(0) , mServer(new RakServer()) , mRulesFile(rulefile) , mAcceptNewPlayers(true) , mServerInfo(info) { if (!mServer->Start(max_clients, 1, mServerInfo.port)) { syslog(LOG_ERR, "Couldn't bind to port %i, exiting", mServerInfo.port); throw(2); } auto gamelogic = createGameLogic(rulefile, nullptr); // set rules data in ServerInfo /// \todo this code should be places in ServerInfo std::strncpy(mServerInfo.rulestitle, gamelogic->getTitle().c_str(), sizeof(mServerInfo.rulestitle)); mServerInfo.rulesauthor[sizeof(mServerInfo.rulestitle)-1] = 0; std::strncpy(mServerInfo.rulesauthor, gamelogic->getAuthor().c_str(), sizeof(mServerInfo.rulesauthor)); mServerInfo.rulesauthor[sizeof(mServerInfo.rulesauthor)-1] = 0; } DedicatedServer::~DedicatedServer() { mServer->Disconnect(50); } void DedicatedServer::processPackets() { packet_ptr packet; while ((packet = mServer->Receive())) { SWLS_PacketCount++; switch(packet->data[0]) { // connection status changes case ID_NEW_INCOMING_CONNECTION: mConnectedClients++; SWLS_Connections++; syslog(LOG_DEBUG, "New incoming connection from %s, %d clients connected now", packet->playerId.toString().c_str(), mConnectedClients); if ( !mAcceptNewPlayers ) { RakNet::BitStream stream; stream.Write( (char)ID_NO_FREE_INCOMING_CONNECTIONS ); mServer->Send( &stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->playerId, false); mServer->CloseConnection( packet->playerId, true ); mConnectedClients--; syslog(LOG_DEBUG, "Connection not accepted, %d clients connected now", mConnectedClients); } break; case ID_CONNECTION_LOST: case ID_DISCONNECTION_NOTIFICATION: { mConnectedClients--; auto player = mPlayerMap.find(packet->playerId); // delete the disconnectiong player if( player != mPlayerMap.end() ) { syslog(LOG_DEBUG, "Disconnected player %s", player->second->getName().c_str()); if( player->second->getGame() ) player->second->getGame()->injectPacket( packet ); // no longer count this player as connected mPlayerMap.erase( player ); updateLobby(); } else { } int pid = packet->data[0]; syslog(LOG_DEBUG, "Connection %s closed via %d, %d clients connected now", packet->playerId.toString().c_str(), pid, mConnectedClients); break; } // game progress packets case ID_INPUT_UPDATE: case ID_PAUSE: case ID_UNPAUSE: case ID_CHAT_MESSAGE: case ID_REPLAY: case ID_RULES: { auto player = mPlayerMap.find(packet->playerId); // delete the disconnectiong player if( player != mPlayerMap.end() && player->second->getGame() ) { player->second->getGame() ->injectPacket( packet ); } else { syslog(LOG_ERR, "received packet from player not in playerlist!"); } break; } // player connects to server case ID_ENTER_SERVER: { RakNet::BitStream stream = packet->getStream(); stream.IgnoreBytes(1); //ID_ENTER_SERVER auto newplayer = boost::make_shared(packet->playerId, stream); mPlayerMap[packet->playerId] = newplayer; syslog(LOG_DEBUG, "New player \"%s\" connected from %s ", newplayer->getName().c_str(), packet->playerId.toString().c_str()); // answer by sending the status to all players updateLobby(); break; } case ID_CHALLENGE: { /// \todo assert that the player send an ID_ENTER_SERVER before // which player is wanted as opponent auto stream = packet->getStream(); // check packet size if( stream.GetNumberOfBytesUsed() != 9 ) { syslog(LOG_NOTICE, "faulty ID_ENTER_PACKET received: Expected 9 bytes, got %d", stream.GetNumberOfBytesUsed()); } PlayerID first = packet->playerId; PlayerID second = UNASSIGNED_PLAYER_ID; auto player = mPlayerMap.find(first); if( player == mPlayerMap.end()) { // seems like we did not receive a ENTER_SERVER Packet before. syslog( LOG_ERR, "a player tried to enter a game, but has no player info" ); break; } auto firstPlayer = player->second; auto reader = createGenericReader(&stream); unsigned char temp; reader->byte(temp); reader->generic(second); bool started = false; // debug log challenge syslog(LOG_DEBUG, "%s challenged %s", first.toString().c_str(), second.toString().c_str()); // search if there is an open request for(auto it = mGameRequests.begin(); it != mGameRequests.end(); ++it) { // is this a game request of the player we want to play with, or if we want to play with everyone if( it->first == second || second == UNASSIGNED_PLAYER_ID) { // do they want to play with us or anyone if(it->second == first || it->second == UNASSIGNED_PLAYER_ID) { /// \todo check that these players are still connected and not already playing a game if( mPlayerMap.find(it->first) != mPlayerMap.end() && firstPlayer->getGame() == nullptr && mPlayerMap[it->first]->getGame() == nullptr ) { try { // we can create a game now auto newgame = createGame( firstPlayer, mPlayerMap[it->first] ); mGameList.push_back(newgame); // remove the game request mGameRequests.erase( it ); started = true; break; // we're done } catch (std::exception& ex) { syslog( LOG_ERR, "error while creating game: %s", ex.what() ); } } } } } if (!started) { // no match could be found -> add to request list mGameRequests[first] = second; // send challenge packets if( second == UNASSIGNED_PLAYER_ID ) { // challenge everybody for(auto it = mPlayerMap.begin(); it != mPlayerMap.end(); ++it) { if( it->second->getGame() == nullptr ) { RakNet::BitStream stream; auto writer = createGenericWriter( &stream ); writer->byte( ID_CHALLENGE ); writer->generic ( first ); mServer->Send(&stream, LOW_PRIORITY, RELIABLE_ORDERED, 0, it->second->getID(), false); } } } // challenge only one player else { RakNet::BitStream stream; auto writer = createGenericWriter( &stream ); writer->byte( ID_CHALLENGE ); writer->generic ( first ); mServer->Send(&stream, LOW_PRIORITY, RELIABLE_ORDERED, 0, second, false); } } break; } case ID_BLOBBY_SERVER_PRESENT: { processBlobbyServerPresent( packet ); break; } default: syslog(LOG_DEBUG, "Unknown packet %d received\n", int(packet->data[0])); } } } void DedicatedServer::updateGames() { // make sure all ingame packets are processed. /// \todo we iterate over all games twice! We should find a way to organize things better. for(auto it = mPlayerMap.begin(); it != mPlayerMap.end(); ++it) { auto game = it->second->getGame(); if(game) { game->processPackets(); } } for (auto iter = mGameList.begin(); iter != mGameList.end(); ) { SWLS_GameSteps++; (*iter)->processPackets(); (*iter)->step(); if (!(*iter)->isGameValid()) { syslog( LOG_DEBUG, "Removed game %s vs %s from gamelist", (*iter)->getPlayerID(LEFT_PLAYER).toString().c_str(), (*iter)->getPlayerID(RIGHT_PLAYER).toString().c_str() ); iter = mGameList.erase(iter); } else { ++iter; } } } void DedicatedServer::updateLobby() { // remove all invalid game requests for( auto it = mGameRequests.begin(); it != mGameRequests.end(); /* no increment, because we have to do that manually in case we erase*/ ) { PlayerID first = it->first; PlayerID second = it->second; auto firstPlayer = mPlayerMap.find(first); // if the first player is no longer available, everything is fine if( firstPlayer == mPlayerMap.end() || firstPlayer->second->getGame() != nullptr) { auto tmpIt = it; tmpIt++; // left server or is already playing -> remove game requests mGameRequests.erase(it); it = tmpIt; continue; } if( second != UNASSIGNED_PLAYER_ID ) { auto secondPlayer = mPlayerMap.find(second); if( secondPlayer == mPlayerMap.end() || secondPlayer->second->getGame() != nullptr) { auto tmpIt = it; tmpIt++; // left server or is already playing -> remove game requests mGameRequests.erase(it); it = tmpIt; // if the second player starts a game, or disconnected, no need to keep the first player waiting /// \todo this could be done a lot more elegant // close connection does not create a disconnect notification... mServer->CloseConnection(firstPlayer->first, true); // ... so we have to do the disconnection code manually mConnectedClients--; // delete the disconnectiong player if( firstPlayer != mPlayerMap.end() ) { // no longer count this player as connected mPlayerMap.erase( firstPlayer ); //updateLobby(); } syslog(LOG_DEBUG, "Connection %s closed, %d clients connected now", first.toString().c_str(), mConnectedClients); // done. continue; } } // if all still valid, increment iterator ++it; } broadcastServerStatus(); } bool DedicatedServer::hasActiveGame() const { return !mGameList.empty(); } int DedicatedServer::getActiveGamesCount() const { return mGameList.size(); } int DedicatedServer::getWaitingPlayers() const { return mPlayerMap.size() - 2 * mGameList.size(); } int DedicatedServer::getConnectedClients() const { return mConnectedClients; } void DedicatedServer::allowNewPlayers( bool allow ) { mAcceptNewPlayers = allow; } // debug void DedicatedServer::printAllPlayers(std::ostream& stream) const { for( std::map< PlayerID, boost::shared_ptr >::const_iterator it = mPlayerMap.begin(); it != mPlayerMap.end(); ++it) { stream << it->second->getID().toString() << " \"" << it->second->getName() << "\" status: "; if( it->second->getGame() ) { stream << "playing\n"; } else { stream << "waiting\n"; } } } void DedicatedServer::printAllGames(std::ostream& stream) const { for( std::list< boost::shared_ptr >::const_iterator it = mGameList.begin(); it != mGameList.end(); ++it) { stream << (*it)->getPlayerID(LEFT_PLAYER).toString() << " vs " << (*it)->getPlayerID(RIGHT_PLAYER).toString() << "\n"; } } // special packet processing void DedicatedServer::processBlobbyServerPresent( const packet_ptr& packet) { RakNet::BitStream stream = packet->getStream(); // If the client knows nothing about versioning, the version is 0.0 int major = 0; int minor = 0; bool wrongPackageSize = true; // current client has bitSize 72 if( stream.GetNumberOfBitsUsed() == 72) { stream.IgnoreBytes(1); //ID_BLOBBY_SERVER_PRESENT stream.Read(major); stream.Read(minor); wrongPackageSize = false; } RakNet::BitStream stream2; if (wrongPackageSize) { std::cerr << "outdated client tried to connect! Unable to determine client version due to packet size mismatch : " << stream.GetNumberOfBitsUsed() << "\n" ; stream2.Write((unsigned char)ID_VERSION_MISMATCH); stream2.Write((int)BLOBBY_VERSION_MAJOR); stream2.Write((int)BLOBBY_VERSION_MINOR); mServer->Send(&stream2, LOW_PRIORITY, RELIABLE_ORDERED, 0, packet->playerId, false); } else if (major < BLOBBY_VERSION_MAJOR || (major == BLOBBY_VERSION_MAJOR && minor < BLOBBY_VERSION_MINOR)) // Check if the packet contains matching version numbers { stream2.Write((unsigned char)ID_VERSION_MISMATCH); stream2.Write((int)BLOBBY_VERSION_MAJOR); stream2.Write((int)BLOBBY_VERSION_MINOR); mServer->Send(&stream2, LOW_PRIORITY, RELIABLE_ORDERED, 0, packet->playerId, false); } else { mServerInfo.activegames = mGameList.size(); mServerInfo.waitingplayers = mPlayerMap.size() - 2 * mServerInfo.activegames; stream2.Write((unsigned char)ID_BLOBBY_SERVER_PRESENT); mServerInfo.writeToBitstream(stream2); mServer->Send(&stream2, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->playerId, false); } } boost::shared_ptr DedicatedServer::createGame(boost::shared_ptr first, boost::shared_ptr second) { PlayerSide switchSide = NO_PLAYER; auto leftPlayer = first; auto rightPlayer = second; // put first player on his desired side in game if(RIGHT_PLAYER == first->getDesiredSide()) { std::swap(leftPlayer, rightPlayer); } // if both players want the same side, one of them is going to get inverted game data if (first->getDesiredSide() == second->getDesiredSide()) { // if both wanted to play on the left, the right player is the inverted one, if both wanted right, the left if (second->getDesiredSide() == LEFT_PLAYER) switchSide = RIGHT_PLAYER; if (second->getDesiredSide() == RIGHT_PLAYER) switchSide = LEFT_PLAYER; } auto newgame = boost::make_shared(*mServer.get(), leftPlayer, rightPlayer, switchSide, mRulesFile); leftPlayer->setGame( newgame ); rightPlayer->setGame( newgame ); SWLS_Games++; /// \todo add some logging? syslog(LOG_DEBUG, "Created game \"%s\" vs. \"%s\"", leftPlayer->getName().c_str(), rightPlayer->getName().c_str()); return newgame; } void DedicatedServer::broadcastServerStatus() { RakNet::BitStream stream; auto out = createGenericWriter(&stream); out->byte((unsigned char)ID_SERVER_STATUS); std::vector playernames; std::vector playerIDs; for( auto it = mPlayerMap.begin(); it != mPlayerMap.end(); ++it) { // only send players that are waiting if( it->second->getGame() == nullptr ) { playernames.push_back( it->second->getName() ); playerIDs.push_back( it->second->getID() ); } } out->generic>( playernames ); out->generic>( playerIDs ); out->uint32(mGameList.size()); for( auto it = mPlayerMap.begin(); it != mPlayerMap.end(); ++it) { if( it->second->getGame() == nullptr) { mServer->Send(&stream, LOW_PRIORITY, RELIABLE_ORDERED, 0, it->first, false); } } } blobby-1.0/data/rules/tennis.lua000644 001750 001750 00000001631 12313310254 021454 0ustar00danielknobedanielknobe000000 000000 __AUTHOR__ = "chameleon" __TITLE__ = "Crazy Volley - Tennis" -- left/right ground hits lgh = 0 rgh = 0 function OnMistake(player) lgh = 0 rgh = 0 score(opponent(player), true, 1) end function OnBallHitsPlayer(player) opp = opponent(player) if player == LEFT_PLAYER then mh = lgh oh = rgh else mh = rgh oh = lgh end lgh = 0 rgh = 0 if touches(player) > 1 then mistake(player, opp, 1) end if oh > 0 and touches(opp) == 0 then mistake(opp, player, 1) end end function OnBallHitsGround(player) opp = opponent(player) if player == LEFT_PLAYER then lgh = lgh + 1 mh = lgh oh = rgh rgh = 0 else rgh = rgh + 1 mh = rgh oh = lgh lgh = 0 end if mh > 1 or touches(player) > 0 then lgh = 0 rgh = 0 mistake(player, opp, 1) end if oh > 0 and touches(opp) == 0 then lgh = 0 rgh = 0 mistake(opp, player, 1) end end blobby-1.0/src/state/NetworkState.h000644 001750 001750 00000006050 12313310253 022117 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "GameState.h" #include "NetworkMessage.h" #include "PlayerIdentity.h" #include #include #include class RakClient; class RakServer; class DuelMatch; class InputSource; class NetworkGame; class PlayerIdentity; class DedicatedServer; /*! \class NetworkGameState \brief State for Network Game \details state which is responsible for presenting a network game, sending player input to the server, managing chat etc. */ class NetworkGameState : public GameState { public: /// create a NetworkGameState with connection to a certain server /// \param client A client which has an established connection to the server we want to start the game on. NetworkGameState(boost::shared_ptr client); virtual ~NetworkGameState(); virtual void step_impl(); virtual const char* getStateName() const; private: enum { WAITING_FOR_OPPONENT, OPPONENT_DISCONNECTED, DISCONNECTED, SERVER_FULL, PLAYING, PLAYER_WON, PAUSING } mNetworkState; // these are pointers to mLeftPlayer or mRightPlayer respectively, so we don't need a smart pointer here PlayerIdentity* mLocalPlayer; PlayerIdentity* mRemotePlayer; bool mUseRemoteColor; boost::scoped_ptr mLocalInput; bool mWaitingForReplay; boost::shared_ptr mClient; PlayerSide mOwnSide; PlayerSide mWinningPlayer; // Chat Vars std::vector mChatlog; std::vector mChatOrigin; unsigned mSelectedChatmessage; unsigned mChatCursorPosition; std::string mChattext; }; /*! \class NetworkHostState \brief state for hosting a game locally \details This class is a wrapper for NetworkGameState to run an instance of NetworkGame \todo this construction seems like a big hack ;) */ class NetworkHostState : public State { public: NetworkHostState(); virtual ~NetworkHostState(); virtual void step_impl(); virtual const char* getStateName() const; private: boost::scoped_ptr mServer; boost::shared_ptr mClient; NetworkGameState* mGameState; PlayerIdentity mLocalPlayer; unsigned int mLobbyCounter; }; blobby-1.0/src/FileExceptions.h000644 001750 001750 00000014010 12313310253 021261 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include /*! \class FileSystemException \brief common base class of all file system related errors */ class FileSystemException : public std::exception { public: FileSystemException() { }; ~FileSystemException() throw() { }; virtual const char* what() const throw() { return "a file system related exception occured!"; } }; /*! \class PhysfsException \brief signales errors reported by physfs \details base class for all exceptions that report physfs errors; */ class PhysfsException : public virtual FileSystemException { public: // implementation in FileSystem.cpp PhysfsException(); ~PhysfsException() throw() { }; virtual const char* what() const throw() { return ("physfs reported an error: " + getPhysfsMessage()).c_str(); } std::string getPhysfsMessage() const { return mPhysfsErrorMsg; } private: /// this string saves the error message std::string mPhysfsErrorMsg; }; /*! \class PhysfsInitException \brief signals an error during the physfs initialisation phase */ class PhysfsInitException : public PhysfsException { public: PhysfsInitException(const std::string& path) : mPath(path) { } ~PhysfsInitException() throw() { } virtual const char* what() const throw() { return ("could not initialise physfs to path " + getPath() + ": " + getPhysfsMessage()).c_str(); } std::string getPath() const { return mPath; } private: std::string mPath; }; /*! \class FileException \brief common base type for file exceptions. \details does not owerride what(), so there is no default error message for FileException s */ class FileException: public virtual FileSystemException { public: FileException(const std::string& f) : filename(f) { } virtual ~FileException() throw() { } /// get the name of the file of the exception const std::string& getFileName() const { return filename; } private: std::string filename; ///!< name of the file which caused the exception }; /*! \class FileLoadException \brief error thrown when a file could not be opened or created. \todo use a better name as FileLoadException does only fit for the open for reading case. */ class FileLoadException : public FileException, public PhysfsException { public: FileLoadException(std::string name) : FileException(name) { /// \todo do we really need to do this? std::exception already /// provides the functionality for setting exception messages, i think. error = "Couldn't load " + name + ": " + getPhysfsMessage(); } virtual ~FileLoadException() throw() {} virtual const char* what() const throw() { return error.c_str(); } private: std::string error; ///< saves the error message }; /*! \class FileAlreadyExistsException \brief error thrown when trying to create a new file even though this file exists already. */ class FileAlreadyExistsException : public FileException { public: FileAlreadyExistsException(std::string name) : FileException(name) { } virtual ~FileAlreadyExistsException() throw() { } virtual const char* what() const throw() { return ("File " + getFileName() + " already exists.").c_str(); } }; /*! \class PhysfsFileException \brief combines FileException with PhysfsException */ class PhysfsFileException : public FileException, public PhysfsException { public: PhysfsFileException(const std::string& filename) : FileException(filename) { }; ~PhysfsFileException() throw() { }; virtual const char* what() const throw() { return (getFileName() + ": " + getPhysfsMessage()).c_str(); } }; /*! \class NoFileOpenedException \brief signals operations on closed files \details Exceptions of this type are thrown when any file modifying or information querying functions are called without a file beeing opened. These are serious errors and generally, exceptions of this type should not occur, as it indicates logical errors in the code. Still, this allows us to handle this situation without having to crash or exit. \sa File::check_file_open() */ class NoFileOpenedException : public FileException { public: NoFileOpenedException() : FileException("") { }; ~NoFileOpenedException() throw() { }; virtual const char* what() const throw() { // default error message for now return "trying to perform a file operation when no file was opened."; } }; /*! \class EOFException \brief thrown when trying to read over eof \details Exceptions of this type are issued when a reading operation tries to read behind a files eof. */ class EOFException : public FileException { public: EOFException(const std::string& file) : FileException( file ) { }; ~EOFException() throw() { }; virtual const char* what() const throw() { // default error message for now return (getFileName() + " trying to read after eof.").c_str(); } }; blobby-1.0/src/raknet/RakServer.cpp000644 001750 001750 00000014773 12313310247 022106 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief RakServer Implementation * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "RakServer.h" #include "PacketEnumerations.h" #include "GetTime.h" #include RakServer::RakServer() { } RakServer::~RakServer() {} bool RakServer::Start( unsigned short AllowedPlayers, int threadSleepTimer, unsigned short port, const char *forceHostAddress ) { bool init; RakPeer::Disconnect( 30 ); init = RakPeer::Initialize( AllowedPlayers, port, threadSleepTimer, forceHostAddress ); RakPeer::SetMaximumIncomingConnections( AllowedPlayers ); return init; } void RakServer::Disconnect( unsigned int blockDuration ) { RakPeer::Disconnect( blockDuration ); } bool RakServer::Send( const char *data, const long length, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId, bool broadcast ) { return RakPeer::Send( data, length, priority, reliability, orderingChannel, playerId, broadcast ); } bool RakServer::Send( const RakNet::BitStream *bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId, bool broadcast ) { return RakPeer::Send( bitStream, priority, reliability, orderingChannel, playerId, broadcast ); } packet_ptr RakServer::Receive( void ) { packet_ptr packet = RakPeer::Receive(); if ( packet ) { if ( packet->data[ 0 ] == ID_DISCONNECTION_NOTIFICATION || packet->data[ 0 ] == ID_CONNECTION_LOST || packet->data[ 0 ] == ID_NEW_INCOMING_CONNECTION ) { // Relay the disconnection RakNet::BitStream bitStream( packet->length + PlayerID_Size ); unsigned char typeId; if ( packet->data[ 0 ] == ID_DISCONNECTION_NOTIFICATION ) typeId = ID_REMOTE_DISCONNECTION_NOTIFICATION; else if ( packet->data[ 0 ] == ID_CONNECTION_LOST ) typeId = ID_REMOTE_CONNECTION_LOST; else typeId = ID_REMOTE_NEW_INCOMING_CONNECTION; bitStream.Write( typeId ); bitStream.Write( packet->playerId.binaryAddress ); bitStream.Write( packet->playerId.port ); bitStream.Write( ( unsigned short& ) packet->playerIndex ); Send( &bitStream, SYSTEM_PRIORITY, RELIABLE, 0, packet->playerId, true ); if ( packet->data[ 0 ] == ID_NEW_INCOMING_CONNECTION ) { unsigned i; for ( i = 0; i < remoteSystemListSize; i++ ) { if ( remoteSystemList[ i ].playerId != UNASSIGNED_PLAYER_ID && packet->playerId != remoteSystemList[ i ].playerId ) { bitStream.Reset(); typeId = ID_REMOTE_EXISTING_CONNECTION; bitStream.Write( typeId ); bitStream.Write( remoteSystemList[ i ].playerId.binaryAddress ); bitStream.Write( remoteSystemList[ i ].playerId.port ); bitStream.Write( ( unsigned short ) i ); // One send to tell them of the connection Send( &bitStream, SYSTEM_PRIORITY, RELIABLE, 0, packet->playerId, false ); } } } } } return packet; } void RakServer::Kick( PlayerID playerId ) { RakPeer::NotifyAndFlagForDisconnect(playerId, false); } void RakServer::SetAllowedPlayers( unsigned short AllowedPlayers ) { RakPeer::SetMaximumIncomingConnections( AllowedPlayers ); } unsigned short RakServer::GetAllowedPlayers( void ) const { return RakPeer::GetMaximumIncomingConnections(); } unsigned short RakServer::GetConnectedPlayers( void ) { unsigned short numberOfSystems; RakPeer::GetConnectionList( 0, &numberOfSystems ); return numberOfSystems; } void RakServer::GetPlayerIPFromID( PlayerID playerId, char returnValue[ 22 ], unsigned short *port ) { *port = playerId.port; strcpy( returnValue, RakPeer::PlayerIDToDottedIP( playerId ) ); } void RakServer::PingPlayer( PlayerID playerId ) { RakPeer::Ping( playerId ); } int RakServer::GetLastPing( PlayerID playerId ) { return RakPeer::GetLastPing( playerId ); } int RakServer::GetLowestPing( PlayerID playerId ) { return RakPeer::GetLowestPing( playerId ); } bool RakServer::IsActive( void ) const { return RakPeer::IsActive(); } unsigned int RakServer::GetNumberOfAddresses( void ) { return RakPeer::GetNumberOfAddresses(); } const char* RakServer::GetLocalIP( unsigned int index ) { return RakPeer::GetLocalIP( index ); } void RakServer::PushBackPacket( Packet *packet ) { RakPeer::PushBackPacket( packet ); } int RakServer::GetIndexFromPlayerID( PlayerID playerId ) { return RakPeer::GetIndexFromPlayerID( playerId ); } PlayerID RakServer::GetPlayerIDFromIndex( int index ) { return RakPeer::GetPlayerIDFromIndex( index ); } bool RakServer::IsActivePlayerID( PlayerID playerId ) { return RakPeer::GetRemoteSystemFromPlayerID( playerId ) != 0; } bool RakServer::SetMTUSize( int size ) { return RakPeer::SetMTUSize( size ); } int RakServer::GetMTUSize( void ) const { return RakPeer::GetMTUSize(); } void RakServer::AdvertiseSystem( char *host, unsigned short remotePort, const char *data, int dataLength ) { RakPeer::AdvertiseSystem( host, remotePort, data, dataLength ); } RakNetStatisticsStruct * const RakServer::GetStatistics( PlayerID playerId ) { return RakPeer::GetStatistics( playerId ); } blobby-1.0/data/gfx/font53.bmp000644 001750 001750 00000003366 12313310254 020730 0ustar00danielknobedanielknobe000000 000000 BM6( sssWWW333}}}HHHppp===rrq000 z}lo<>(((尰WWWOR" ΋  DDDޚLMMK#++qqr|322Ufߧ2$ $۪\^]    EFFԌ7:8ltq-0/͝V^ZGKKƵɿ/50 ǼEUI8=;do2D7 |ʊMnV" z}lo<>"&%θڮbo1N7OR" ΋  foۯt·B|K)K#++#*'ͤ{ٍM[-_4Ufߧ2$ $`kXi070    Օcq.8^  Qv[|:D% 4 ~ԇip'-" ^eW[2;1B6ޑrz7w<blobby-1.0/data/gfx/font10.bmp000644 001750 001750 00000003370 12313310254 020714 0ustar00danielknobedanielknobe000000 000000 BM6( YXYSSS===@Aux\_89LKLi+l&~DF```ϯQOP55Ţ)BC/./റ`^`'&'JN?=@000ڰebf"!#w`K/0KHK%"%ׂfK$%zvzGDG)&)ycɆ6444<<<555...~ROR""hbD  ɼ״d`e)%)($(&"&1(2L?MmWn{p}K%&ёmem`Y_nbo}̜ͿfNa5dOOOzzzɡۺƛȯ~o|M}   ~z'#'ջέJ6KA-AHIHί'('˞+/+8<8ǵӴjjwvhyh_h^ɵٵΞgfSmRjzj߹୚ݙihOxM xvPN)(3'઱}HF5VnVHF%N$rqOJ3}1Ղeb31EhD}zDA [ZYV blobby-1.0/data/inputconfig.xml000644 001750 001750 00000002004 12313310254 021361 0ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/000755 001750 001750 00000000000 12313310253 016173 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/tinyxml/tinyxmlparser.cpp000644 001750 001750 00000110572 12313310251 023330 0ustar00danielknobedanielknobe000000 000000 /* www.sourceforge.net/projects/tinyxml Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include #include #include "tinyxml.h" //#define DEBUG_PARSER #if defined( DEBUG_PARSER ) # if defined( DEBUG ) && defined( _MSC_VER ) # include # define TIXML_LOG OutputDebugString # else # define TIXML_LOG printf # endif #endif // Note tha "PutString" hardcodes the same list. This // is less flexible than it appears. Changing the entries // or order will break putstring. TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = { { "&", 5, '&' }, { "<", 4, '<' }, { ">", 4, '>' }, { """, 6, '\"' }, { "'", 6, '\'' } }; // Bunch of unicode info at: // http://www.unicode.org/faq/utf_bom.html // Including the basic of this table, which determines the #bytes in the // sequence from the lead byte. 1 placed for invalid sequences -- // although the result will be junk, pass it through as much as possible. // Beware of the non-characters in UTF-8: // ef bb bf (Microsoft "lead bytes") // ef bf be // ef bf bf const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; const int TiXmlBase::utf8ByteTable[256] = { // 0 1 2 3 4 5 6 7 8 9 a b c d e f 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid }; void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) { const unsigned long BYTE_MASK = 0xBF; const unsigned long BYTE_MARK = 0x80; const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; if (input < 0x80) *length = 1; else if ( input < 0x800 ) *length = 2; else if ( input < 0x10000 ) *length = 3; else if ( input < 0x200000 ) *length = 4; else { *length = 0; return; } // This code won't covert this correctly anyway. output += *length; // Scary scary fall throughs. switch (*length) { case 4: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 3: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 2: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 1: --output; *output = (char)(input | FIRST_BYTE_MARK[*length]); } } /*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) // { if ( anyByte < 127 ) return isalpha( anyByte ); else return 1; // What else to do? The unicode set is huge...get the english ones right. // } // else // { // return isalpha( anyByte ); // } } /*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) // { if ( anyByte < 127 ) return isalnum( anyByte ); else return 1; // What else to do? The unicode set is huge...get the english ones right. // } // else // { // return isalnum( anyByte ); // } } class TiXmlParsingData { friend class TiXmlDocument; public: void Stamp( const char* now, TiXmlEncoding encoding ); const TiXmlCursor& Cursor() const { return cursor; } private: // Only used by the document! TiXmlParsingData( const char* start, int _tabsize, int row, int col ) { assert( start ); stamp = start; tabsize = _tabsize; cursor.row = row; cursor.col = col; } TiXmlCursor cursor; const char* stamp; int tabsize; }; void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) { assert( now ); // Do nothing if the tabsize is 0. if ( tabsize < 1 ) { return; } // Get the current row, column. int row = cursor.row; int col = cursor.col; const char* p = stamp; assert( p ); while ( p < now ) { // Treat p as unsigned, so we have a happy compiler. const unsigned char* pU = (const unsigned char*)p; // Code contributed by Fletcher Dunn: (modified by lee) switch (*pU) { case 0: // We *should* never get here, but in case we do, don't // advance past the terminating null character, ever return; case '\r': // bump down to the next line ++row; col = 0; // Eat the character ++p; // Check for \r\n sequence, and treat this as a single character if (*p == '\n') { ++p; } break; case '\n': // bump down to the next line ++row; col = 0; // Eat the character ++p; // Check for \n\r sequence, and treat this as a single // character. (Yes, this bizarre thing does occur still // on some arcane platforms...) if (*p == '\r') { ++p; } break; case '\t': // Eat the character ++p; // Skip to next tab stop col = (col / tabsize + 1) * tabsize; break; case TIXML_UTF_LEAD_0: if ( encoding == TIXML_ENCODING_UTF8 ) { if ( *(p+1) && *(p+2) ) { // In these cases, don't advance the column. These are // 0-width spaces. if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) p += 3; else { p +=3; ++col; } // A normal character. } } else { ++p; ++col; } break; default: if ( encoding == TIXML_ENCODING_UTF8 ) { // Eat the 1 to 4 byte utf8 character. int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; if ( step == 0 ) step = 1; // Error case from bad encoding, but handle gracefully. p += step; // Just advance one column, of course. ++col; } else { ++p; ++col; } break; } } cursor.row = row; cursor.col = col; assert( cursor.row >= -1 ); assert( cursor.col >= -1 ); stamp = p; assert( stamp ); } const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) { if ( !p || !*p ) { return 0; } if ( encoding == TIXML_ENCODING_UTF8 ) { while ( *p ) { const unsigned char* pU = (const unsigned char*)p; // Skip the stupid Microsoft UTF-8 Byte order marks if ( *(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) { p += 3; continue; } else if(*(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==0xbfU && *(pU+2)==0xbeU ) { p += 3; continue; } else if(*(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==0xbfU && *(pU+2)==0xbfU ) { p += 3; continue; } if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. ++p; else break; } } else { while ( *p && IsWhiteSpace( *p ) ) ++p; } return p; } #ifdef TIXML_USE_STL /*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) { for( ;; ) { if ( !in->good() ) return false; int c = in->peek(); // At this scope, we can't get to a document. So fail silently. if ( !IsWhiteSpace( c ) || c <= 0 ) return true; *tag += (char) in->get(); } } /*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) { //assert( character > 0 && character < 128 ); // else it won't work in utf-8 while ( in->good() ) { int c = in->peek(); if ( c == character ) return true; if ( c <= 0 ) // Silent failure: can't get document at this scope return false; in->get(); *tag += (char) c; } return false; } #endif // One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The // "assign" optimization removes over 10% of the execution time. // const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) { // Oddly, not supported on some comilers, //name->clear(); // So use this: *name = ""; assert( p ); // Names start with letters or underscores. // Of course, in unicode, tinyxml has no idea what a letter *is*. The // algorithm is generous. // // After that, they can be letters, underscores, numbers, // hyphens, or colons. (Colons are valid ony for namespaces, // but tinyxml can't tell namespaces from names.) if ( p && *p && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) { const char* start = p; while( p && *p && ( IsAlphaNum( (unsigned char ) *p, encoding ) || *p == '_' || *p == '-' || *p == '.' || *p == ':' ) ) { //(*name) += *p; // expensive ++p; } if ( p-start > 0 ) { name->assign( start, p-start ); } return p; } return 0; } const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) { // Presume an entity, and pull it out. TIXML_STRING ent; int i; *length = 0; if ( *(p+1) && *(p+1) == '#' && *(p+2) ) { unsigned long ucs = 0; ptrdiff_t delta = 0; unsigned mult = 1; if ( *(p+2) == 'x' ) { // Hexadecimal. if ( !*(p+3) ) return 0; const char* q = p+3; q = strchr( q, ';' ); if ( !q || !*q ) return 0; delta = q-p; --q; while ( *q != 'x' ) { if ( *q >= '0' && *q <= '9' ) ucs += mult * (*q - '0'); else if ( *q >= 'a' && *q <= 'f' ) ucs += mult * (*q - 'a' + 10); else if ( *q >= 'A' && *q <= 'F' ) ucs += mult * (*q - 'A' + 10 ); else return 0; mult *= 16; --q; } } else { // Decimal. if ( !*(p+2) ) return 0; const char* q = p+2; q = strchr( q, ';' ); if ( !q || !*q ) return 0; delta = q-p; --q; while ( *q != '#' ) { if ( *q >= '0' && *q <= '9' ) ucs += mult * (*q - '0'); else return 0; mult *= 10; --q; } } if ( encoding == TIXML_ENCODING_UTF8 ) { // convert the UCS to UTF-8 ConvertUTF32ToUTF8( ucs, value, length ); } else { *value = (char)ucs; *length = 1; } return p + delta + 1; } // Now try to match it. for( i=0; iappend( cArr, len ); } } else { bool whitespace = false; // Remove leading white space: p = SkipWhiteSpace( p, encoding ); while ( p && *p && !StringEqual( p, endTag, caseInsensitive, encoding ) ) { if ( *p == '\r' || *p == '\n' ) { whitespace = true; ++p; } else if ( IsWhiteSpace( *p ) ) { whitespace = true; ++p; } else { // If we've found whitespace, add it before the // new character. Any whitespace just becomes a space. if ( whitespace ) { (*text) += ' '; whitespace = false; } int len; char cArr[4] = { 0, 0, 0, 0 }; p = GetChar( p, cArr, &len, encoding ); if ( len == 1 ) (*text) += cArr[0]; // more efficient else text->append( cArr, len ); } } } if ( p && *p ) p += strlen( endTag ); return ( p && *p ) ? p : 0; } #ifdef TIXML_USE_STL void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) { // The basic issue with a document is that we don't know what we're // streaming. Read something presumed to be a tag (and hope), then // identify it, and call the appropriate stream method on the tag. // // This "pre-streaming" will never read the closing ">" so the // sub-tag can orient itself. if ( !StreamTo( in, '<', tag ) ) { SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } while ( in->good() ) { int tagIndex = (int) tag->length(); while ( in->good() && in->peek() != '>' ) { int c = in->get(); if ( c <= 0 ) { SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); break; } (*tag) += (char) c; } if ( in->good() ) { // We now have something we presume to be a node of // some sort. Identify it, and call the node to // continue streaming. TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); if ( node ) { node->StreamIn( in, tag ); bool isElement = node->ToElement() != 0; delete node; node = 0; // If this is the root element, we're done. Parsing will be // done by the >> operator. if ( isElement ) { return; } } else { SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } } } // We should have returned sooner. SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); } #endif const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) { ClearError(); // Parse away, at the document level. Since a document // contains nothing but other tags, most of what happens // here is skipping white space. if ( !p || !*p ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } // Note that, for a document, this needs to come // before the while space skip, so that parsing // starts from the pointer we are given. location.Clear(); if ( prevData ) { location.row = prevData->cursor.row; location.col = prevData->cursor.col; } else { location.row = 0; location.col = 0; } TiXmlParsingData data( p, TabSize(), location.row, location.col ); location = data.Cursor(); if ( encoding == TIXML_ENCODING_UNKNOWN ) { // Check for the Microsoft UTF-8 lead bytes. const unsigned char* pU = (const unsigned char*)p; if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) { encoding = TIXML_ENCODING_UTF8; useMicrosoftBOM = true; } } p = SkipWhiteSpace( p, encoding ); if ( !p ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } while ( p && *p ) { TiXmlNode* node = Identify( p, encoding ); if ( node ) { p = node->Parse( p, &data, encoding ); LinkEndChild( node ); } else { break; } // Did we get encoding info? if ( encoding == TIXML_ENCODING_UNKNOWN && node->ToDeclaration() ) { TiXmlDeclaration* dec = node->ToDeclaration(); const char* enc = dec->Encoding(); assert( enc ); if ( *enc == 0 ) encoding = TIXML_ENCODING_UTF8; else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) encoding = TIXML_ENCODING_UTF8; else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice else encoding = TIXML_ENCODING_LEGACY; } p = SkipWhiteSpace( p, encoding ); } // Was this empty? if ( !firstChild ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); return 0; } // All is well. return p; } void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) { // The first error in a chain is more accurate - don't set again! if ( error ) return; assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); error = true; errorId = err; errorDesc = errorString[ errorId ]; errorLocation.Clear(); if ( pError && data ) { data->Stamp( pError, encoding ); errorLocation = data->Cursor(); } } TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) { TiXmlNode* returnNode = 0; p = SkipWhiteSpace( p, encoding ); if( !p || !*p || *p != '<' ) { return 0; } p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) { return 0; } // What is this thing? // - Elements start with a letter or underscore, but xml is reserved. // - Comments: "; if ( !StringEqual( p, startTag, false, encoding ) ) { if ( document ) document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); return 0; } p += strlen( startTag ); // [ 1475201 ] TinyXML parses entities in comments // Oops - ReadText doesn't work, because we don't want to parse the entities. // p = ReadText( p, &value, false, endTag, false, encoding ); // // from the XML spec: /* [Definition: Comments may appear anywhere in a document outside other markup; in addition, they may appear within the document type declaration at places allowed by the grammar. They are not part of the document's character data; an XML processor MAY, but need not, make it possible for an application to retrieve the text of comments. For compatibility, the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity references MUST NOT be recognized within comments. An example of a comment: */ value = ""; // Keep all the white space. while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) { value.append( p, 1 ); ++p; } if ( p && *p ) p += strlen( endTag ); return p; } const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) return 0; if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } // Read the name, the '=' and the value. const char* pErr = p; p = ReadName( p, &name, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); return 0; } p = SkipWhiteSpace( p, encoding ); if ( !p || !*p || *p != '=' ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } ++p; // skip '=' p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } const char* end; const char SINGLE_QUOTE = '\''; const char DOUBLE_QUOTE = '\"'; if ( *p == SINGLE_QUOTE ) { ++p; end = "\'"; // single quote in string p = ReadText( p, &value, false, end, false, encoding ); } else if ( *p == DOUBLE_QUOTE ) { ++p; end = "\""; // double quote in string p = ReadText( p, &value, false, end, false, encoding ); } else { // All attribute values should be in single or double quotes. // But this is such a common error that the parser will try // its best, even without them. value = ""; while ( p && *p // existence && !IsWhiteSpace( *p ) // whitespace && *p != '/' && *p != '>' ) // tag end { if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { // [ 1451649 ] Attribute values with trailing quotes not handled correctly // We did not have an opening quote but seem to have a // closing one. Give up and throw an error. if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } value += *p; ++p; } } return p; } #ifdef TIXML_USE_STL void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) { while ( in->good() ) { int c = in->peek(); if ( !cdata && (c == '<' ) ) { return; } if ( c <= 0 ) { TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; in->get(); // "commits" the peek made above if ( cdata && c == '>' && tag->size() >= 3 ) { size_t len = tag->size(); if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { // terminator of cdata. return; } } } } #endif const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { value = ""; TiXmlDocument* document = GetDocument(); if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } const char* const startTag = ""; if ( cdata || StringEqual( p, startTag, false, encoding ) ) { cdata = true; if ( !StringEqual( p, startTag, false, encoding ) ) { if ( document ) document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); return 0; } p += strlen( startTag ); // Keep all the white space, ignore the encoding, etc. while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) { value += *p; ++p; } TIXML_STRING dummy; p = ReadText( p, &dummy, false, endTag, false, encoding ); return p; } else { bool ignoreWhite = true; const char* end = "<"; p = ReadText( p, &value, ignoreWhite, end, false, encoding ); if ( p && *p ) return p-1; // don't truncate the '<' return 0; } } #ifdef TIXML_USE_STL void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) { while ( in->good() ) { int c = in->get(); if ( c <= 0 ) { TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; if ( c == '>' ) { // All is well. return; } } } #endif const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) { p = SkipWhiteSpace( p, _encoding ); // Find the beginning, find the end, and look for // the stuff in-between. TiXmlDocument* document = GetDocument(); if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); return 0; } if ( data ) { data->Stamp( p, _encoding ); location = data->Cursor(); } p += 5; version = ""; encoding = ""; standalone = ""; while ( p && *p ) { if ( *p == '>' ) { ++p; return p; } p = SkipWhiteSpace( p, _encoding ); if ( StringEqual( p, "version", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); version = attrib.Value(); } else if ( StringEqual( p, "encoding", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); encoding = attrib.Value(); } else if ( StringEqual( p, "standalone", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); standalone = attrib.Value(); } else { // Read over whatever it is. while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) ++p; } } return 0; } bool TiXmlText::Blank() const { for ( unsigned i=0; i #define ltm_c #define LUA_CORE #include "lua.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" static const char udatatypename[] = "userdata"; LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { "no value", "nil", "boolean", udatatypename, "number", "string", "table", "function", udatatypename, "thread", "proto", "upval" /* these last two cases are used for tests only */ }; void luaT_init (lua_State *L) { static const char *const luaT_eventname[] = { /* ORDER TM */ "__index", "__newindex", "__gc", "__mode", "__len", "__eq", "__add", "__sub", "__mul", "__div", "__mod", "__pow", "__unm", "__lt", "__le", "__concat", "__call" }; int i; for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); luaS_fix(G(L)->tmname[i]); /* never collect these names */ } } /* ** function to be used with macro "fasttm": optimized for absence of ** tag methods */ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { const TValue *tm = luaH_getstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ events->flags |= cast_byte(1u<metatable; break; case LUA_TUSERDATA: mt = uvalue(o)->metatable; break; default: mt = G(L)->mt[ttypenv(o)]; } return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); } blobby-1.0/data/gfx/font02.bmp000644 001750 001750 00000003370 12313310254 020715 0ustar00danielknobedanielknobe000000 000000 BM6( 6R61g08$7$GFMJ85,v*!B!  />F7H@/@H#@H@Iٍfg4l  qH\+ebܒ_1CL^GáOև&DM %'hC߉%@L2!7\7~<J &+3%.5XͲ5s4DeMo}VtC4>-4K͟,_s% 2KDSjqJ!Q(e<|%K_  vv~sU%1 m45c#q4G }j=*N Dy8\#p ­piZu=kvqĴʳqO"%&v}~zvblobby-1.0/src/raknet/ReliabilityLayer.cpp000644 001750 001750 00000240400 12313310247 023434 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Reliability Layer Implementation * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "ReliabilityLayer.h" #include #include "GetTime.h" #include "SocketLayer.h" // alloca #ifdef _WIN32 #include #else #include #endif #include // Defined in rand.cpp extern void seedMT( unsigned int seed ); extern inline unsigned int randomMT( void ); extern inline float frandomMT( void ); static const int ACK_BIT_LENGTH = sizeof( PacketNumberType ) *8 + 1; static const int MAXIMUM_WINDOW_SIZE = ( 8000 - UDP_HEADER_SIZE ) *8 / ACK_BIT_LENGTH; // Sanity check - the most ack packets that could ever (usually) fit into a frame. static const int MINIMUM_WINDOW_SIZE = 5; // how many packets can be sent unacknowledged before waiting for an ack static const int DEFAULT_RECEIVED_PACKETS_SIZE=128; // Divide by timeout time in seconds to get the max ave. packets per second before requiring reallocation //------------------------------------------------------------------------------------------------------- // Constructor //------------------------------------------------------------------------------------------------------- ReliabilityLayer::ReliabilityLayer() : updateBitStream( MAXIMUM_MTU_SIZE ) // preallocate the update bitstream so we can avoid a lot of reallocs at runtime { InitializeVariables(); freeThreadedMemoryOnNextUpdate = false; } //------------------------------------------------------------------------------------------------------- // Destructor //------------------------------------------------------------------------------------------------------- ReliabilityLayer::~ReliabilityLayer() { FreeMemory( true ); // Free all memory immediately } //------------------------------------------------------------------------------------------------------- // Resets the layer for reuse //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::Reset( void ) { FreeMemory( true ); // true because making a memory reset pending in the update cycle causes resets after reconnects. Instead, just call Reset from a single thread InitializeVariables(); } //------------------------------------------------------------------------------------------------------- // Initialize the variables //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::InitializeVariables( void ) { memset( waitingForOrderedPacketReadIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType)); memset( waitingForSequencedPacketReadIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) ); memset( waitingForOrderedPacketWriteIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) ); memset( waitingForSequencedPacketWriteIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) ); memset( &statistics, 0, sizeof( statistics ) ); statistics.connectionStartTime = RakNet::GetTime(); splitPacketId = 0; packetNumber = 0; SetLostPacketResendDelay( 1000 ); deadConnection = false; lastAckTime = 0; blockWindowIncreaseUntilTime = 0; // Windowing windowSize = MINIMUM_WINDOW_SIZE; lossyWindowSize = MAXIMUM_WINDOW_SIZE + 1; // Infinite lastWindowIncreaseSizeTime = 0; receivedPacketsBaseIndex=0; resetReceivedPackets=true; } //------------------------------------------------------------------------------------------------------- // Frees all allocated memory //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::FreeMemory( bool freeAllImmediately ) { if ( freeAllImmediately ) { FreeThreadSafeMemory(); } else { FreeThreadSafeMemory(); freeThreadedMemoryOnNextUpdate = true; } } void ReliabilityLayer::FreeThreadSafeMemory( void ) { InternalPacket *internalPacket; for ( unsigned i = 0; i < splitPacketList.size(); i++ ) { delete [] splitPacketList[ i ]->data; internalPacketPool.ReleasePointer( splitPacketList[ i ] ); } splitPacketList.clear(); while ( outputQueue.size() > 0 ) { internalPacket = outputQueue.pop(); delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); } outputQueue.clearAndForceAllocation( 512 ); for ( unsigned i = 0; i < orderingList.size(); i++ ) { if ( orderingList[ i ] ) { BasicDataStructures::LinkedList* theList = orderingList[ i ]; if ( theList ) { while ( theList->size() ) { internalPacket = orderingList[ i ]->pop(); delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); } delete theList; } } } orderingList.clear(); while ( acknowledgementQueue.size() > 0 ) internalPacketPool.ReleasePointer( acknowledgementQueue.pop() ); acknowledgementQueue.clearAndForceAllocation( 64 ); while ( resendQueue.size() ) { // The resend Queue can have NULL pointer holes. This is so we can deallocate blocks without having to compress the array internalPacket = resendQueue.pop(); if ( internalPacket ) { delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); } } resendQueue.clearAndForceAllocation( DEFAULT_RECEIVED_PACKETS_SIZE ); unsigned j; for ( unsigned i = 0; i < NUMBER_OF_PRIORITIES; i++ ) { j = 0; for ( ; j < sendPacketSet[ i ].size(); j++ ) { delete [] ( sendPacketSet[ i ] ) [ j ]->data; internalPacketPool.ReleasePointer( ( sendPacketSet[ i ] ) [ j ] ); } sendPacketSet[ i ].clearAndForceAllocation( 512 ); // Preallocate the send lists so we don't do a bunch of reallocations unnecessarily } #ifdef _INTERNET_SIMULATOR #pragma message("-- RakNet _INTERNET_SIMULATOR is defined!! --") for (unsigned i = 0; i < delayList.size(); i++ ) delete delayList[ i ]; delayList.clear(); #endif internalPacketPool.ClearPool(); } //------------------------------------------------------------------------------------------------------- // Packets are read directly from the socket layer and skip the reliability //layer because unconnected players do not use the reliability layer // This function takes packet data after a player has been confirmed as //connected. The game should not use that data directly // because some data is used internally, such as packet acknowledgement and //split packets //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffer, int length ) { #ifdef _DEBUG assert( !( length <= 0 || buffer == 0 ) ); #endif if ( length <= 1 || buffer == 0 ) // Length of 1 is a connection request resend that we just ignore return true; int numberOfAcksInFrame = 0; bool indexFound; int count, size; PacketNumberType holeCount; UpdateThreadedMemory(); statistics.bitsReceived += length * 8; statistics.packetsReceived++; RakNet::BitStream socketData( (char*)buffer, length, false ); // Convert the incoming data to a bitstream for easy parsing unsigned int time = RakNet::GetTime(); // Parse the bitstream to create an internal packet InternalPacket* internalPacket = CreateInternalPacketFromBitStream( &socketData, time ); while ( internalPacket ) { if ( internalPacket->isAcknowledgement ) { numberOfAcksInFrame++; if ( resendQueue.size() == 0 ) { lastAckTime = 0; // Not resending anything so clear this var so we don't drop the connection on not getting any more acks } else { lastAckTime = time; // Just got an ack. Record when we got it so we know the connection is alive } // SHOW - ack received //printf("Got Ack for %i. resendQueue.size()=%i sendQueue[0].size() = %i\n",internalPacket->packetNumber, resendQueue.size(), sendQueue[0].size()); RemovePacketFromResendQueueAndDeleteOlderReliableSequenced( internalPacket->packetNumber ); internalPacketPool.ReleasePointer( internalPacket ); } else { if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability == RELIABLE ) { SendAcknowledgementPacket( internalPacket->packetNumber, time ); } // Show all arrived packets // printf("Got %i.\n", internalPacket->packetNumber); // resetReceivedPackets is set from a non-threadsafe function. // We do the actual reset in this function so the data is not modified by multiple threads if (resetReceivedPackets) { receivedPackets.clearAndForceAllocation(DEFAULT_RECEIVED_PACKETS_SIZE); receivedPacketsBaseIndex=0; resetReceivedPackets=false; } //printf("internalPacket->packetNumber=%i receivedPacketsBaseIndex=%i\n", internalPacket->packetNumber,receivedPacketsBaseIndex); // If the following conditional is true then this either a duplicate packet // or an older out of order packet // The subtraction unsigned overflow is intentional holeCount = (PacketNumberType)(internalPacket->packetNumber-receivedPacketsBaseIndex); const int typeRange = (PacketNumberType)-1; if (holeCount==0) { // Got what we were expecting if (receivedPackets.size()) receivedPackets.pop(); ++receivedPacketsBaseIndex; } else if (holeCount > typeRange-typeRange/2) { // Underflow - got a packet we have already counted past #ifdef _DEBUG //printf( "Warning: Got old duplicate packet (%i) with ID %i.\n", internalPacket->packetNumber, (unsigned char)internalPacket->data[0] ); #endif statistics.duplicateMessagesReceived++; // Duplicate packet delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } else if (holeCountpacketNumber, (unsigned char)internalPacket->data[0] ); #endif statistics.duplicateMessagesReceived++; // Duplicate packet delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } else // holeCount>=receivedPackets.size() { // Got a higher count out of order packet whose packetNumber is higher than we have ever got // Add 0 times to the queue until (packetNumber - baseIndex) < queue size. while ((PacketNumberType)(holeCount) > receivedPackets.size()) receivedPackets.push(MakeReceivedPacketHole(time)); receivedPackets.push(time); #ifdef _DEBUG // If this assert hits then PacketNumberType has overflowed assert(receivedPackets.size() < (unsigned int)((PacketNumberType)(-1))); #endif } // Pop all expired times. For each expired time popped, increase the baseIndex // Each time is either the actual time a packet was received or a time that is between // (time+TIMEOUT_TIME) to (time+TIMEOUT_TIME*2) in the future. Future times are used as a flag // to indicate that we never got this packet so we don't mark it as a duplicate. while ( receivedPackets.size()>0 && IsExpiredTime(receivedPackets.peek(), time) ) { receivedPackets.pop(); ++receivedPacketsBaseIndex; } statistics.messagesReceived++; // If the allocated buffer is > DEFAULT_RECEIVED_PACKETS_SIZE and it is 3x greater than the number of elements actually being used //if (receivedPackets.AllocationSize() > DEFAULT_RECEIVED_PACKETS_SIZE && receivedPackets.AllocationSize() > receivedPackets.size() * 3) // receivedPackets.compress(); // Keep on top of deleting old unreliable split packets so they don't clog the list. if ( internalPacket->splitPacketCount > 0 ) DeleteOldUnreliableSplitPackets( time ); if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED ) { #ifdef _DEBUG assert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS ); #endif if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) { // Invalid packet #ifdef _DEBUG printf( "Got invalid packet\n" ); #endif delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } if ( IsOlderOrderedPacket( internalPacket->orderingIndex, waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] ) == false ) { statistics.sequencedMessagesInOrder++; // Is this a split packet? if ( internalPacket->splitPacketCount > 0 ) { // Generate the split // Verify some parameters to make sure we don't get junk data #ifdef _DEBUG assert( internalPacket->splitPacketIndex < internalPacket->splitPacketCount ); assert( internalPacket->dataBitLength < MAXIMUM_MTU_SIZE * 8 ); #endif //reliabilityLayerMutexes[splitPacketList_MUTEX].Lock(); for ( unsigned cnt = 0; cnt < splitPacketList.size(); cnt++ ) { // Make sure this is not a duplicate insertion. // If this hits then most likely splitPacketId overflowed into existing waiting split packets (i.e. more than rangeof(splitPacketId) waiting) if ( splitPacketList[ cnt ]->splitPacketIndex == internalPacket->splitPacketIndex && splitPacketList[ cnt ]->splitPacketId == splitPacketId ) { #ifdef _DEBUG assert(0); #endif // Invalid packet #ifdef _DEBUG printf( "Error: Split packet duplicate insertion (1)\n" ); #endif delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } #ifdef _DEBUG int splitPacketListSize = splitPacketList.size() + 1; #endif //reliabilityLayerMutexes[splitPacketList_MUTEX].Unlock(); // Check for a rebuilt packet InsertIntoSplitPacketList( internalPacket ); // Sequenced internalPacket = BuildPacketFromSplitPacketList( internalPacket->splitPacketId, time ); if ( internalPacket ) { #ifdef _DEBUG assert( splitPacketList.size() == splitPacketListSize - internalPacket->splitPacketCount ); #endif // Update our index to the newest packet waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] = internalPacket->orderingIndex + 1; // If there is a rebuilt packet, add it to the output queue outputQueue.push( internalPacket ); internalPacket = 0; } #ifdef _DEBUG else { assert( splitPacketList.size() == (unsigned int) splitPacketListSize ); } #endif // else don't have all the parts yet } else { // Update our index to the newest packet waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] = internalPacket->orderingIndex + 1; // Not a split packet. Add the packet to the output queue outputQueue.push( internalPacket ); internalPacket = 0; } } else { statistics.sequencedMessagesOutOfOrder++; // Older sequenced packet. Discard it delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); } goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } // Is this an unsequenced split packet? if ( internalPacket->splitPacketCount > 0 ) { // An unsequenced split packet. May be ordered though. // Verify some parameters to make sure we don't get junk data #ifdef _DEBUG assert( internalPacket->splitPacketIndex < internalPacket->splitPacketCount ); assert( internalPacket->dataBitLength < MAXIMUM_MTU_SIZE * 8 ); #endif // Check for a rebuilt packet if ( internalPacket->reliability != RELIABLE_ORDERED ) internalPacket->orderingChannel = 255; // Use 255 to designate not sequenced and not ordered //reliabilityLayerMutexes[splitPacketList_MUTEX].Lock(); // Make sure this is not a duplicate insertion. If this assert hits then splitPacketId overflowed into existing waiting split packets (i.e. more than rangeof(splitPacketId) waiting) for ( unsigned cnt = 0; cnt < splitPacketList.size(); cnt++ ) { if ( splitPacketList[ cnt ]->splitPacketIndex == internalPacket->splitPacketIndex && splitPacketList[ cnt ]->splitPacketId == internalPacket->splitPacketId ) { #ifdef _DEBUG assert(0); #endif // Invalid packet #ifdef _DEBUG printf( "Error: Split packet duplicate insertion (2)\n" ); #endif delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } #ifdef _DEBUG int splitPacketListSize = splitPacketList.size() + 1; #endif InsertIntoSplitPacketList( internalPacket ); internalPacket = BuildPacketFromSplitPacketList( internalPacket->splitPacketId, time ); if ( internalPacket == 0 ) { #ifdef _DEBUG assert( splitPacketList.size() == (unsigned int) splitPacketListSize ); #endif // Don't have all the parts yet goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } #ifdef _DEBUG else { assert( splitPacketList.size() == splitPacketListSize - internalPacket->splitPacketCount ); } #endif // else continue down to handle RELIABLE_ORDERED } if ( internalPacket->reliability == RELIABLE_ORDERED ) { #ifdef _DEBUG assert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS ); #endif if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) { #ifdef _DEBUG printf("Got invalid ordering channel %i from packet %i\n", internalPacket->orderingChannel, internalPacket->packetNumber); #endif // Invalid packet delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } if ( waitingForOrderedPacketReadIndex[ internalPacket->orderingChannel ] == internalPacket->orderingIndex ) { // Get the list to hold ordered packets for this stream BasicDataStructures::LinkedList *orderingListAtOrderingStream; unsigned char orderingChannelCopy = internalPacket->orderingChannel; statistics.orderedMessagesInOrder++; // Show ordering index increment //printf("Pushing immediate packet %i with ordering index %i\n", internalPacket->packetNumber, internalPacket->orderingIndex ); // Push the packet for the user to read outputQueue.push( internalPacket ); internalPacket = 0; // Don't reference this any longer since other threads access it // Wait for the next ordered packet in sequence waitingForOrderedPacketReadIndex[ orderingChannelCopy ] ++; // This wraps //reliabilityLayerMutexes[orderingList_MUTEX].Lock(); orderingListAtOrderingStream = GetOrderingListAtOrderingStream( orderingChannelCopy ); if ( orderingListAtOrderingStream != 0) { while ( orderingListAtOrderingStream->size() > 0 ) { // Cycle through the list until nothing is found orderingListAtOrderingStream->beginning(); indexFound=false; size=orderingListAtOrderingStream->size(); count=0; while (count++ < size) { if ( orderingListAtOrderingStream->peek()->orderingIndex == waitingForOrderedPacketReadIndex[ orderingChannelCopy ] ) { //printf("Pushing delayed packet %i with ordering index %i. outputQueue.size()==%i\n", orderingListAtOrderingStream->peek()->packetNumber, orderingListAtOrderingStream->peek()->orderingIndex, outputQueue.size() ); outputQueue.push( orderingListAtOrderingStream->pop() ); waitingForOrderedPacketReadIndex[ orderingChannelCopy ]++; // This wraps at 255 indexFound=true; } else (*orderingListAtOrderingStream)++; } if (indexFound==false) break; } } internalPacket = 0; } else { // assert(waitingForOrderedPacketReadIndex[ internalPacket->orderingChannel ] < internalPacket->orderingIndex); statistics.orderedMessagesOutOfOrder++; // This is a newer ordered packet than we are waiting for. Store it for future use AddToOrderingList( internalPacket ); } goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } // Nothing special about this packet. Add it to the output queue outputQueue.push( internalPacket ); // Output queue fill rate test // if (outputQueue.size()%50==0) // printf("outputQueue.size()=%i Time=%i\n", outputQueue.size(), RakNet::GetTime()); internalPacket = 0; } // Used for a goto to jump to the next packet immediately CONTINUE_SOCKET_DATA_PARSE_LOOP: // Parse the bitstream to create an internal packet internalPacket = CreateInternalPacketFromBitStream( &socketData, time ); } // numberOfAcksInFrame>=windowSize means that all the packets we last sent from the resendQueue are cleared out // 11/17/05 - the problem with numberOfAcksInFrame >= windowSize is that if the entire frame is filled with resends but not all resends filled the frame // then the sender is limited by how many resends can fit in one frame if ( numberOfAcksInFrame >= windowSize && ( sendPacketSet[ SYSTEM_PRIORITY ].size() > 0 || sendPacketSet[ HIGH_PRIORITY ].size() > 0 || sendPacketSet[ MEDIUM_PRIORITY ].size() > 0 ) ) { //printf("windowSize=%i lossyWindowSize=%i\n", windowSize, lossyWindowSize); if ( windowSize < lossyWindowSize || (time>lastWindowIncreaseSizeTime && time-lastWindowIncreaseSizeTime>lostPacketResendDelay*2) ) // Increases the window size slowly, testing for packetloss { // If we get a frame which clears out the resend queue after handling one or more acks, and we have packets waiting to go out, // and we didn't recently lose a packet then increase the window size by 1 windowSize++; if ( (time>lastWindowIncreaseSizeTime && time-lastWindowIncreaseSizeTime>lostPacketResendDelay*2) ) // The increase is to test for packetloss lastWindowIncreaseSizeTime = time; // If the window is so large that we couldn't possibly fit any more packets into the frame, then just leave it alone if ( windowSize > MAXIMUM_WINDOW_SIZE ) windowSize = MAXIMUM_WINDOW_SIZE; // SHOW - WINDOWING //else // printf("Increasing windowSize to %i. Lossy window size = %i\n", windowSize, lossyWindowSize); // If we are more than 5 over the lossy window size, increase the lossy window size by 1 if ( windowSize == MAXIMUM_WINDOW_SIZE || windowSize - lossyWindowSize > 5 ) lossyWindowSize++; } } return true; } //------------------------------------------------------------------------------------------------------- // This gets an end-user packet already parsed out. Returns number of BITS put into the buffer //------------------------------------------------------------------------------------------------------- int ReliabilityLayer::Receive( char **data ) { // Wait until the clear occurs if (freeThreadedMemoryOnNextUpdate) return 0; InternalPacket * internalPacket; if ( outputQueue.size() > 0 ) { // #ifdef _DEBUG // assert(bitStream->GetNumberOfBitsUsed()==0); // #endif internalPacket = outputQueue.pop(); int bitLength; *data = internalPacket->data; bitLength = internalPacket->dataBitLength; internalPacketPool.ReleasePointer( internalPacket ); return bitLength; } else { return 0; } } //------------------------------------------------------------------------------------------------------- // Puts data on the send queue // bitStream contains the data to send // priority is what priority to send the data at // reliability is what reliability to use // ordering channel is from 0 to 255 and specifies what stream to use //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::Send( char *data, int numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, unsigned char orderingChannel, bool makeDataCopy, int MTUSize, unsigned int currentTime ) { #ifdef _DEBUG assert( !( reliability > RELIABLE_SEQUENCED || reliability < 0 ) ); assert( !( priority > NUMBER_OF_PRIORITIES || priority < 0 ) ); assert( !( orderingChannel < 0 || orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) ); assert( numberOfBitsToSend > 0 ); #endif // Fix any bad parameters if ( reliability > RELIABLE_SEQUENCED || reliability < 0 ) reliability = RELIABLE; if ( priority > NUMBER_OF_PRIORITIES || priority < 0 ) priority = HIGH_PRIORITY; if ( orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) orderingChannel = 0; int numberOfBytesToSend=BITS_TO_BYTES(numberOfBitsToSend); if ( numberOfBitsToSend == 0 ) { #ifdef _DEBUG printf( "Error!! ReliabilityLayer::Send bitStream->GetNumberOfBytesUsed()==0\n" ); #endif return false; } InternalPacket * internalPacket = internalPacketPool.GetPointer(); #ifdef _DEBUG // Remove accessing undefined memory warning memset( internalPacket, 255, sizeof( InternalPacket ) ); #endif internalPacket->creationTime = currentTime; if ( makeDataCopy ) { internalPacket->data = new char [ numberOfBytesToSend ]; memcpy( internalPacket->data, data, numberOfBytesToSend ); // printf("Allocated %i\n", internalPacket->data); } else { // Allocated the data elsewhere, delete it in here internalPacket->data = ( char* ) data; // printf("Using Pre-Allocated %i\n", internalPacket->data); } internalPacket->dataBitLength = numberOfBitsToSend; internalPacket->isAcknowledgement = false; internalPacket->nextActionTime = 0; internalPacket->packetNumber = packetNumber; internalPacket->priority = priority; internalPacket->reliability = reliability; internalPacket->splitPacketCount = 0; // Calculate if I need to split the packet int headerLength = BITS_TO_BYTES( GetBitStreamHeaderLength( internalPacket ) ); int maxDataSize = MTUSize - UDP_HEADER_SIZE - headerLength; bool splitPacket = numberOfBytesToSend > maxDataSize; // If a split packet, we might have to upgrade the reliability if ( splitPacket ) statistics.numberOfSplitMessages++; else statistics.numberOfUnsplitMessages++; // Increment the cyclical receivedPacketsIndex for use by the next packet. // This variable is used as the identifier of the packet on the remote machine. // When it cycles it will reuse older numbers but that is ok because by the time it // cycles those older packets will be pretty much guaranteed to arrive by then // if ( ++packetNumber == RECEIVED_PACKET_LOG_LENGTH ) // packetNumber = 0; ++packetNumber; if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED ) { // Assign the sequence stream and index internalPacket->orderingChannel = orderingChannel; internalPacket->orderingIndex = waitingForSequencedPacketWriteIndex[ orderingChannel ] ++; } else if ( internalPacket->reliability == RELIABLE_ORDERED ) { // Assign the ordering channel and index internalPacket->orderingChannel = orderingChannel; internalPacket->orderingIndex = waitingForOrderedPacketWriteIndex[ orderingChannel ] ++; } if ( splitPacket ) // If it uses a secure header it will be generated here { // Must split the packet. This will also generate the SHA1 if it is required. It also adds it to the send list. SplitPacket( internalPacket, MTUSize ); return true; } sendPacketSet[ internalPacket->priority ].push( internalPacket ); return true; } //------------------------------------------------------------------------------------------------------- // Run this once per game cycle. Handles internal lists and actually does the send //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::Update( SOCKET s, PlayerID playerId, int MTUSize, unsigned int time ) { // unsigned resendQueueSize; bool reliableDataSent; unsigned int lastAck; UpdateThreadedMemory(); // Accuracy isn't important on this value, and since this is called so often the mutex is sometimes causing deadlock problems. // So it is presently disabled lastAck = lastAckTime; // Due to thread vagarities and the way I store the time to avoid slow calls to RakNet::GetTime // time may be less than lastAck if ( resendQueue.size() > 0 && time > lastAck && lastAck && time - lastAck > TIMEOUT_TIME ) { // SHOW - dead connection // printf("The connection has been lost.\n"); // We've waited a very long time for a reliable packet to get an ack and it never has deadConnection = true; return; } //if (outputWindowFullTime && RakNet::GetTime() > TIMEOUT_TIME + outputWindowFullTime) //{ // // We've waited a long time with no data from the other system. Assume the connection is lost // deadConnection=true; // return; //} // Not a frame but a packet actually. // However, in a sense it is a frame because we are filling multiple logical packets into one datagram // Keep sending to available bandwidth while ( IsFrameReady( time ) ) { updateBitStream.Reset(); GenerateFrame( &updateBitStream, MTUSize, &reliableDataSent, time ); if ( updateBitStream.GetNumberOfBitsUsed() > 0 ) { #ifndef _INTERNET_SIMULATOR SendBitStream( s, playerId, &updateBitStream ); #else // Delay the send to simulate lag DataAndTime *dt; dt = new DataAndTime; memcpy( dt->data, updateBitStream.GetData(), updateBitStream.GetNumberOfBytesUsed() ); dt->length = updateBitStream.GetNumberOfBytesUsed(); dt->sendTime = time + 100 + ( rand() % 100 ); delayList.insert( dt ); #endif } else break; } #ifdef _INTERNET_SIMULATOR // Do any lagged sends unsigned i = 0; while ( i < delayList.size() ) { if ( delayList[ i ]->sendTime < time ) { updateBitStream.Reset(); updateBitStream.Write( delayList[ i ]->data, delayList[ i ]->length ); // Send it now SendBitStream( s, playerId, &updateBitStream ); delete delayList[ i ]; if (i != delayList.size() - 1) delayList[ i ] = delayList[ delayList.size() - 1 ]; delayList.del(); } else i++; } #endif } //------------------------------------------------------------------------------------------------------- // Writes a bitstream to the socket //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SendBitStream( SOCKET s, PlayerID playerId, RakNet::BitStream *bitStream ) { // SHOW - showing reliable flow // if (bitStream->GetNumberOfBytesUsed()>50) // printf("Sending %i bytes. sendQueue[0].size()=%i, resendQueue.size()=%i\n", bitStream->GetNumberOfBytesUsed(), sendQueue[0].size(),resendQueue.size()); // sentFrames++; #ifdef _INTERNET_SIMULATOR // packetloss if ((rand() % 101)/100.0f <= .05f) { // printf("Frame %i lost\n", sentFrames); return; } #endif int length = bitStream->GetNumberOfBytesUsed(); statistics.packetsSent++; statistics.totalBitsSent += length * 8; //printf("total bits=%i length=%i\n", BITS_TO_BYTES(statistics.totalBitsSent), length); SocketLayer::Instance()->SendTo( s, ( char* ) bitStream->GetData(), length, playerId.binaryAddress, playerId.port ); } //------------------------------------------------------------------------------------------------------- // Returns true if we can or should send a frame. False if we should not //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsFrameReady( unsigned int time ) { if ( IsSendThrottled() == false ) { // Show send throttled // printf("Send is throttled. resendQueue.size=%i windowSize=%i\n", resendQueue.size(), windowSize); return true; } // Any acknowledgement packets waiting? We will send these even if the send is throttled. // Otherwise the throttle may never end if ( acknowledgementQueue.size() >= MINIMUM_WINDOW_SIZE // Try not waiting to send acks - will take more bandwidth but maybe less packetloss // || acknowledgementQueue.peek()->nextActionTime < time ) { return true; } // Does the oldest packet need to be resent? If so, send it. // Otherwise the throttle may never end if ( resendQueue.size() > 0 && resendQueue.peek() && resendQueue.peek()->nextActionTime < time ) { // reliabilityLayerMutexes[resendQueue_MUTEX].Unlock(); return true; } // Send is throttled. Don't send. return false; } //------------------------------------------------------------------------------------------------------- // Generates a frame (coalesced packets) //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::GenerateFrame( RakNet::BitStream *output, int MTUSize, bool *reliableDataSent, unsigned int time ) { InternalPacket * internalPacket; int maxDataBitSize; int reliableBits = 0; int nextPacketBitLength; unsigned i; bool isReliable; bool acknowledgementPacketsSent; bool anyPacketsLost = false; maxDataBitSize = MTUSize - UDP_HEADER_SIZE; maxDataBitSize <<= 3; acknowledgementPacketsSent = false; *reliableDataSent = false; // Packet acknowledgements always go out first if they are overdue or if there are a lot of them if ( acknowledgementQueue.size() > 0 && ( acknowledgementQueue.size() >= MINIMUM_WINDOW_SIZE || acknowledgementQueue.peek()->nextActionTime < time ) ) { do { internalPacket = acknowledgementQueue.pop(); // Write the acknowledgement to the output bitstream statistics.acknowlegementsSent++; statistics.acknowlegementBitsSent += WriteToBitStreamFromInternalPacket( output, internalPacket ); acknowledgementPacketsSent = true; // Delete the acknowledgement internalPacketPool.ReleasePointer( internalPacket ); if ( output->GetNumberOfBitsUsed() + ACK_BIT_LENGTH > maxDataBitSize ) { // SHOW - show ack // printf("Sending FULL ack (%i) at time %i. acknowledgementQueue.size()=%i\n", output->GetNumberOfBytesUsed(), RakNet::GetTime(),acknowledgementQueue.size()); statistics.packetsContainingOnlyAcknowlegements++; // Show - Frame full // printf("Frame full in sending acks\n"); goto END_OF_GENERATE_FRAME; } } while ( acknowledgementQueue.size() > 0 ); } // SHOW - show ack //if (output->GetNumberOfBitsUsed()>0) // printf("Sending ack (%i) at time %i. acknowledgementQueue.size()=%i\n", output->GetNumberOfBytesUsed(), RakNet::GetTime(),acknowledgementQueue.size()); // The resend Queue can have NULL pointer holes. This is so we can deallocate blocks without having to compress the array while ( resendQueue.size() > 0 ) { if ( resendQueue.peek() == 0 ) { resendQueue.pop(); continue; // This was a hole } if ( resendQueue.peek()->nextActionTime < time ) { internalPacket = resendQueue.pop(); // Testing //printf("Resending %i. queue size = %i\n", internalPacket->packetNumber, resendQueue.size()); nextPacketBitLength = GetBitStreamHeaderLength( internalPacket ) + internalPacket->dataBitLength; if ( output->GetNumberOfBitsUsed() + nextPacketBitLength > maxDataBitSize ) { resendQueue.pushAtHead( internalPacket ); // Not enough room to use this packet after all! if ( anyPacketsLost ) { UpdatePacketloss( time ); } // Show - Frame full //printf("Frame full in sending resends\n"); goto END_OF_GENERATE_FRAME; } #ifdef _DEBUG assert( internalPacket->priority >= 0 ); assert( internalPacket->reliability >= 0 ); #endif // SHOW - show resends //printf("Resending packet. resendQueue.size()=%i. Data=%s\n",resendQueue.size(), internalPacket->data); // Write to the output bitstream // sentPackets++; statistics.messageResends++; statistics.messageDataBitsResent += internalPacket->dataBitLength; statistics.messagesTotalBitsResent += WriteToBitStreamFromInternalPacket( output, internalPacket ); *reliableDataSent = true; // if (output->GetNumberOfBitsUsed() + ACK_BIT_LENGTH > maxDataBitSize) // printf("Frame full of just acks and resends at time %i.\n", RakNet::GetTime()); statistics.packetsContainingOnlyAcknowlegementsAndResends++; anyPacketsLost = true; internalPacket->nextActionTime = time + lostPacketResendDelay; // Put the packet back into the resend list at the correct spot // Don't make a copy since I'm reinserting an allocated struct InsertPacketIntoResendQueue( internalPacket, time, false, false ); } else { break; } } if ( anyPacketsLost ) { // Update packetloss UpdatePacketloss( time ); } if ( IsSendThrottled() ) return ; // Don't send regular data if we are supposed to be waiting on the window // From highest to lowest priority, fill up the output bitstream from the send lists for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ ) { // if (i==LOW_PRIORITY && sendQueue[LOW_PRIORITY].size() > 0 && (sendQueue[LOW_PRIORITY].size()%100)==0) // { // printf("%i\n", sendQueue[LOW_PRIORITY].size()); // } // Not mutexed - may give a wrong value if another thread is inserting something but it's ok // Because we can avoid a slow mutex call a lot of the time //if ( sendQueue[ i ].size() == 0 ) // continue; while ( sendPacketSet[ i ].size() ) //while ( (internalPacket=sendPacketSet[i].ReadLock())!=0 ) { internalPacket = sendPacketSet[ i ].pop(); nextPacketBitLength = GetBitStreamHeaderLength( internalPacket ) + internalPacket->dataBitLength; if ( output->GetNumberOfBitsUsed() + nextPacketBitLength > maxDataBitSize ) { // This output won't fit. sendPacketSet[ i ].pushAtHead( internalPacket ); // Push this back at the head so it is the next thing to go out break; } if ( internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED ) isReliable = true; else isReliable = false; // Write to the output bitstream // sentPackets++; statistics.messagesSent[ i ] ++; statistics.messageDataBitsSent[ i ] += internalPacket->dataBitLength; // printf("Writing send packet %i to bitstream.\n", internalPacket->packetNumber); if (internalPacket->data[0]==49) { unsigned short packetPort; memcpy((char*)&packetPort, internalPacket->data+1, sizeof(unsigned short)); } statistics.messageTotalBitsSent[ i ] += WriteToBitStreamFromInternalPacket( output, internalPacket ); if ( isReliable ) { // Reliable packets are saved to resend later reliableBits += internalPacket->dataBitLength; internalPacket->nextActionTime = time + lostPacketResendDelay; // Third param is true to make a copy because this data is from a producer consumer pool and can't be stored out of order //InsertPacketIntoResendQueue( internalPacket, time, true, true ); InsertPacketIntoResendQueue( internalPacket, time, false, true ); *reliableDataSent = true; } else { // Unreliable packets are deleted delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); } } } // Optimization - if we sent data but didn't send an acknowledgement packet previously then send them now if ( acknowledgementPacketsSent == false && output->GetNumberOfBitsUsed() > 0 ) { if ( acknowledgementQueue.size() > 0 ) { while ( output->GetNumberOfBitsUsed() + ACK_BIT_LENGTH < maxDataBitSize && acknowledgementQueue.size() > 0 ) { internalPacket = acknowledgementQueue.pop(); #ifdef _DEBUG internalPacket->data=0; assert(internalPacket->isAcknowledgement==true); #endif // Write the acknowledgement to the output bitstream WriteToBitStreamFromInternalPacket( output, internalPacket ); #ifdef _DEBUG assert(internalPacket->data==0); #endif // Delete the acknowledgement internalPacketPool.ReleasePointer( internalPacket ); } } } END_OF_GENERATE_FRAME: ; // if (output->GetNumberOfBitsUsed()>0) // { // Update the throttle with the header // bytesSent+=output->GetNumberOfBytesUsed() + UDP_HEADER_SIZE; //} } //------------------------------------------------------------------------------------------------------- // Are we waiting for any data to be sent out or be processed by the player? //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsDataWaiting(void) { unsigned i; for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ ) { if (sendPacketSet[ i ].size() > 0) return true; } return acknowledgementQueue.size() > 0 || resendQueue.size() > 0 || outputQueue.size() > 0 || orderingList.size() > 0 || splitPacketList.size() > 0; } //------------------------------------------------------------------------------------------------------- // This will return true if we should not send at this time //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsSendThrottled( void ) { return ( int ) GetResendQueueDataSize() >= windowSize; } //------------------------------------------------------------------------------------------------------- // We lost a packet //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::UpdatePacketloss( unsigned int time ) { // unsigned int time = RakNet::GetTime(); /* maximumWindowSize = (unsigned int)((double)maximumWindowSize * DECREASE_THROUGHPUT_DELTA); if (maximumWindowSize < MINIMUM_THROUGHPUT) { maximumWindowSize = MINIMUM_THROUGHPUT; } */ //printf("Lost packet. resendQueue.size()=%i sendQueue[0].size() = %i\n",resendQueue.size(), sendQueue[0].size()); // retransmittedFrames++; // The window size will decrease everytime we have to retransmit a frame if ( --windowSize < MINIMUM_WINDOW_SIZE ) windowSize = MINIMUM_WINDOW_SIZE; lossyWindowSize = windowSize; lastWindowIncreaseSizeTime = time; // This will block the window size from increasing immediately // SHOW - windowing //if (resendQueue.size()>0) //printf("Frame lost. New window size = %i. Lossy window size = %i. Time=%i. Next send time=%i\n", windowSize, lossyWindowSize, RakNet::GetTime(),resendQueue.peek()->nextActionTime); } //------------------------------------------------------------------------------------------------------- // Does what the function name says //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::RemovePacketFromResendQueueAndDeleteOlderReliableSequenced( PacketNumberType packetNumber ) { InternalPacket * internalPacket; PacketReliability reliability; // What type of reliability algorithm to use with this packet unsigned char orderingChannel; // What ordering channel this packet is on, if the reliability type uses ordering channels OrderingIndexType orderingIndex; // The ID used as identification for ordering channels for ( unsigned i = 0; i < resendQueue.size(); i ++ ) { if ( resendQueue[i] && packetNumber == resendQueue[i]->packetNumber ) { // Found what we wanted to ack statistics.acknowlegementsReceived++; if ( i == 0 ) internalPacket = resendQueue.pop(); else { // Generate a hole internalPacket = resendQueue[ i ]; // testing // printf("Removing packet %i from resend\n", internalPacket->packetNumber); resendQueue[ i ] = 0; } // Save some of the data of the packet reliability = internalPacket->reliability; orderingChannel = internalPacket->orderingChannel; orderingIndex = internalPacket->orderingIndex; // Delete the packet //printf("Deleting %i\n", internalPacket->data); delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); // If the deleted packet was reliable sequenced, also delete all older reliable sequenced resends on the same ordering channel. // This is because we no longer need to send these. if ( reliability == RELIABLE_SEQUENCED ) { unsigned j = 0; while ( j < resendQueue.size() ) { internalPacket = resendQueue[ j ]; if ( internalPacket && internalPacket->reliability == RELIABLE_SEQUENCED && internalPacket->orderingChannel == orderingChannel && IsOlderOrderedPacket( internalPacket->orderingIndex, orderingIndex ) ) { // Delete the packet delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); resendQueue[ j ] = 0; // Generate a hole } j++; } } return ; } } // Didn't find what we wanted to ack statistics.duplicateAcknowlegementsReceived++; } //------------------------------------------------------------------------------------------------------- // Acknowledge receipt of the packet with the specified packetNumber //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SendAcknowledgementPacket( PacketNumberType packetNumber, unsigned int time ) { InternalPacket* internalPacket = internalPacketPool.GetPointer(); #ifdef _DEBUG // Remove boundschecker accessing undefined memory error memset( internalPacket, 255, sizeof( InternalPacket ) ); #endif internalPacket->packetNumber = packetNumber; internalPacket->isAcknowledgement = true; internalPacket->creationTime = time; // We send this acknowledgement no later than 1/4 the time the remote //machine would send the original packet again // DEBUG internalPacket->nextActionTime = internalPacket->creationTime + ( lostPacketResendDelay >> 2 ); //internalPacket->nextActionTime = internalPacket->creationTime; acknowledgementQueue.push( internalPacket ); // printf("Adding ack at time %i. acknowledgementQueue.size=%i\n",RakNet::GetTime(), acknowledgementQueue.size()); } //------------------------------------------------------------------------------------------------------- // Parse an internalPacket and figure out how many header bits would be // written. Returns that number //------------------------------------------------------------------------------------------------------- int ReliabilityLayer::GetBitStreamHeaderLength( const InternalPacket *const internalPacket ) { #ifdef _DEBUG assert( internalPacket ); #endif int bitLength; if ( internalPacket->isAcknowledgement ) return ACK_BIT_LENGTH; // Write if this packet has a security header (1 bit) //bitStream->Write(internalPacket->hasSecurityHeader); // -- bitLength+=1; bitLength = ACK_BIT_LENGTH; // Write the PacketReliability. This is encoded in 3 bits //bitStream->WriteBits((unsigned char*)&(internalPacket->reliability), 3, true); bitLength += 3; // If the reliability requires an ordering channel and ordering index, we Write those. if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED ) { // ordering channel encoded in 5 bits (from 0 to 31) //bitStream->WriteBits((unsigned char*)&(internalPacket->orderingChannel), 5, true); bitLength+=5; // ordering index is one byte //bitStream->WriteCompressed(internalPacket->orderingIndex); bitLength+=sizeof(OrderingIndexType)*8; } // Write if this is a split packet (1 bit) bool isSplitPacket = internalPacket->splitPacketCount > 0; //bitStream->Write(isSplitPacket); bitLength += 1; if ( isSplitPacket ) { // split packet indices are two bytes (so one packet can be split up to 65535 // times - maximum packet size would be about 500 * 65535) //bitStream->Write(internalPacket->splitPacketId); //bitStream->WriteCompressed(internalPacket->splitPacketIndex); //bitStream->WriteCompressed(internalPacket->splitPacketCount); bitLength += 3 * 8 * 2; } // Write how many bits the packet data is. Stored in an unsigned short and // read from 16 bits //bitStream->WriteBits((unsigned char*)&(internalPacket->dataBitLength), 16, true); // Read how many bits the packet data is. Stored in 16 bits bitLength += 16; // Byte alignment //bitLength += 8 - ((bitLength -1) %8 + 1); return bitLength; } //------------------------------------------------------------------------------------------------------- // Parse an internalPacket and create a bitstream to represent this data //------------------------------------------------------------------------------------------------------- int ReliabilityLayer::WriteToBitStreamFromInternalPacket( RakNet::BitStream *bitStream, const InternalPacket *const internalPacket ) { #ifdef _DEBUG assert( bitStream && internalPacket ); #endif int start = bitStream->GetNumberOfBitsUsed(); // testing //if (internalPacket->reliability==UNRELIABLE) // printf("Sending unreliable packet %i\n", internalPacket->packetNumber); //else if (internalPacket->reliability==RELIABLE_SEQUENCED || internalPacket->reliability==RELIABLE_ORDERED || internalPacket->reliability==RELIABLE) // printf("Sending reliable packet number %i\n", internalPacket->packetNumber); //bitStream->AlignWriteToByteBoundary(); // Write the packet number (2 bytes) bitStream->Write( internalPacket->packetNumber ); // Write if this packet is an acknowledgement (1 bit) bitStream->Write( internalPacket->isAcknowledgement ); // Acknowledgement packets have no more data than the packetnumber and whether it is an acknowledgement if ( internalPacket->isAcknowledgement ) { return bitStream->GetNumberOfBitsUsed() - start; } #ifdef _DEBUG assert( internalPacket->dataBitLength > 0 ); #endif // Write the PacketReliability. This is encoded in 3 bits unsigned char reliability = (unsigned char) internalPacket->reliability; bitStream->WriteBits( ( unsigned char* ) ( &( reliability ) ), 3, true ); // If the reliability requires an ordering channel and ordering index, we Write those. if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED ) { // ordering channel encoded in 5 bits (from 0 to 31) bitStream->WriteBits( ( unsigned char* ) & ( internalPacket->orderingChannel ), 5, true ); // One or two bytes bitStream->Write( internalPacket->orderingIndex ); } // Write if this is a split packet (1 bit) bool isSplitPacket = internalPacket->splitPacketCount > 0; bitStream->Write( isSplitPacket ); if ( isSplitPacket ) { // split packet indices are two bytes (so one packet can be split up to 65535 times - maximum packet size would be about 500 * 65535) bitStream->Write( internalPacket->splitPacketId ); bitStream->WriteCompressed( internalPacket->splitPacketIndex ); bitStream->WriteCompressed( internalPacket->splitPacketCount ); } // Write how many bits the packet data is. Stored in 13 bits #ifdef _DEBUG assert( BITS_TO_BYTES( internalPacket->dataBitLength ) < MAXIMUM_MTU_SIZE ); // I never send more than MTU_SIZE bytes #endif unsigned short length = ( unsigned short ) internalPacket->dataBitLength; // Ignore the 2 high bytes for WriteBits bitStream->WriteCompressed( length ); // Write the actual data. bitStream->WriteAlignedBytes( ( unsigned char* ) internalPacket->data, BITS_TO_BYTES( internalPacket->dataBitLength ) ); //bitStream->WriteBits((unsigned char*)internalPacket->data, internalPacket->dataBitLength); return bitStream->GetNumberOfBitsUsed() - start; } //------------------------------------------------------------------------------------------------------- // Parse a bitstream and create an internal packet to represent this data //------------------------------------------------------------------------------------------------------- InternalPacket* ReliabilityLayer::CreateInternalPacketFromBitStream( RakNet::BitStream *bitStream, unsigned int time ) { bool bitStreamSucceeded; InternalPacket* internalPacket; if ( bitStream->GetNumberOfUnreadBits() < sizeof( internalPacket->packetNumber ) * 8 ) return 0; // leftover bits internalPacket = internalPacketPool.GetPointer(); #ifdef _DEBUG // Remove accessing undefined memory error memset( internalPacket, 255, sizeof( InternalPacket ) ); #endif internalPacket->creationTime = time; //bitStream->AlignReadToByteBoundary(); // Read the packet number (2 bytes) bitStreamSucceeded = bitStream->Read( internalPacket->packetNumber ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.ReleasePointer( internalPacket ); return 0; } // Read if this packet is an acknowledgement (1 bit) bitStreamSucceeded = bitStream->Read( internalPacket->isAcknowledgement ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.ReleasePointer( internalPacket ); return 0; } // Acknowledgement packets have no more data than the packetnumber and whether it is an acknowledgement if ( internalPacket->isAcknowledgement ) return internalPacket; // Read the PacketReliability. This is encoded in 3 bits unsigned char reliability; bitStreamSucceeded = bitStream->ReadBits( ( unsigned char* ) ( &( reliability ) ), 3 ); internalPacket->reliability = ( PacketReliability ) reliability; #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets // assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.ReleasePointer( internalPacket ); return 0; } // If the reliability requires an ordering channel and ordering index, we read those. if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED ) { // ordering channel encoded in 5 bits (from 0 to 31) bitStreamSucceeded = bitStream->ReadBits( ( unsigned char* ) & ( internalPacket->orderingChannel ), 5 ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.ReleasePointer( internalPacket ); return 0; } bitStreamSucceeded = bitStream->Read( internalPacket->orderingIndex ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.ReleasePointer( internalPacket ); return 0; } } // Read if this is a split packet (1 bit) bool isSplitPacket; bitStreamSucceeded = bitStream->Read( isSplitPacket ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.ReleasePointer( internalPacket ); return 0; } if ( isSplitPacket ) { // split packet indices are one byte (so one packet can be split up to 65535 times - maximum packet size would be about 500 * 65535) bitStreamSucceeded = bitStream->Read( internalPacket->splitPacketId ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets // assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.ReleasePointer( internalPacket ); return 0; } bitStreamSucceeded = bitStream->ReadCompressed( internalPacket->splitPacketIndex ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.ReleasePointer( internalPacket ); return 0; } bitStreamSucceeded = bitStream->ReadCompressed( internalPacket->splitPacketCount ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.ReleasePointer( internalPacket ); return 0; } } else internalPacket->splitPacketIndex = internalPacket->splitPacketCount = 0; // Optimization - do byte alignment here //unsigned char zero; //bitStream->ReadBits(&zero, 8 - (bitStream->GetNumberOfBitsUsed() %8)); //assert(zero==0); unsigned short length; bitStreamSucceeded = bitStream->ReadCompressed( length ); // Read into an unsigned short. Otherwise the data would be offset too high by two bytes #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.ReleasePointer( internalPacket ); return 0; } internalPacket->dataBitLength = length; #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets arriving when the sender does not know we just connected, which is an unavoidable condition sometimes // assert( internalPacket->dataBitLength > 0 && BITS_TO_BYTES( internalPacket->dataBitLength ) < MAXIMUM_MTU_SIZE ); #endif if ( ! ( internalPacket->dataBitLength > 0 && BITS_TO_BYTES( internalPacket->dataBitLength ) < MAXIMUM_MTU_SIZE ) ) { // 10/08/05 - internalPacket->data wasn't allocated yet // delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); return 0; } // Allocate memory to hold our data internalPacket->data = new char [ BITS_TO_BYTES( internalPacket->dataBitLength ) ]; //printf("Allocating %i\n", internalPacket->data); // Set the last byte to 0 so if ReadBits does not read a multiple of 8 the last bits are 0'ed out internalPacket->data[ BITS_TO_BYTES( internalPacket->dataBitLength ) - 1 ] = 0; // Read the data the packet holds bitStreamSucceeded = bitStream->ReadAlignedBytes( ( unsigned char* ) internalPacket->data, BITS_TO_BYTES( internalPacket->dataBitLength ) ); //bitStreamSucceeded = bitStream->ReadBits((unsigned char*)internalPacket->data, internalPacket->dataBitLength); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); if ( bitStreamSucceeded == false ) { delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); return 0; } #endif // PRINTING UNRELIABLE STRINGS // if (internalPacket->data && internalPacket->dataBitLength>5*8) // printf("Received %s\n",internalPacket->data); return internalPacket; } //------------------------------------------------------------------------------------------------------- // Returns true if newPacketOrderingIndex is older than the waitingForPacketOrderingIndex //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsOlderOrderedPacket( OrderingIndexType newPacketOrderingIndex, OrderingIndexType waitingForPacketOrderingIndex ) { // This should give me 255 or 65535 OrderingIndexType maxRange = (OrderingIndexType) -1; if ( waitingForPacketOrderingIndex > maxRange/2 ) { if ( newPacketOrderingIndex >= waitingForPacketOrderingIndex - maxRange/2+1 && newPacketOrderingIndex < waitingForPacketOrderingIndex ) { return true; } } else if ( newPacketOrderingIndex >= ( OrderingIndexType ) ( waitingForPacketOrderingIndex - (( OrderingIndexType ) maxRange/2+1) ) || newPacketOrderingIndex < waitingForPacketOrderingIndex ) { return true; } // Old packet return false; } //------------------------------------------------------------------------------------------------------- // Split the passed packet into chunks under MTU_SIZEbytes (including headers) and save those new chunks // Optimized version //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SplitPacket( InternalPacket *internalPacket, int MTUSize ) { // Doing all sizes in bytes in this function so I don't write partial bytes with split packets internalPacket->splitPacketCount = 1; // This causes GetBitStreamHeaderLength to account for the split packet header int headerLength = BITS_TO_BYTES( GetBitStreamHeaderLength( internalPacket ) ); int dataByteLength = BITS_TO_BYTES( internalPacket->dataBitLength ); int maxDataSize; int byteOffset, bytesToSend; maxDataSize = MTUSize - UDP_HEADER_SIZE; #ifdef _DEBUG // Make sure we need to split the packet to begin with assert( dataByteLength > maxDataSize - headerLength ); // If this assert is hit the packet is so tremendous we need to widen the split packet types. You should never send something that big anyway assert( ( dataByteLength - 1 ) / ( maxDataSize - headerLength ) + 1 < 65535 ); #endif // How much to send in the largest block int maximumSendBlock = maxDataSize - headerLength; // Calculate how many packets we need to create internalPacket->splitPacketCount = ( unsigned short ) ( ( dataByteLength - 1 ) / ( maximumSendBlock ) + 1 ); statistics.totalSplits += internalPacket->splitPacketCount; // Optimization InternalPacket** internalPacketArray = ( InternalPacket** ) alloca( sizeof( InternalPacket* ) * internalPacket->splitPacketCount ); for ( int i = 0; i < ( int ) internalPacket->splitPacketCount; i++ ) { internalPacketArray[ i ] = internalPacketPool.GetPointer(); memcpy( internalPacketArray[ i ], internalPacket, sizeof( InternalPacket ) ); } // This identifies which packet this is in the set unsigned short splitPacketIndex = 0; // Do a loop to send out all the packets do { byteOffset = splitPacketIndex * maximumSendBlock; bytesToSend = dataByteLength - byteOffset; if ( bytesToSend > maximumSendBlock ) bytesToSend = maximumSendBlock; // Copy over our chunk of data internalPacketArray[ splitPacketIndex ]->data = new char[ bytesToSend ]; memcpy( internalPacketArray[ splitPacketIndex ]->data, internalPacket->data + byteOffset, bytesToSend ); if ( bytesToSend != maximumSendBlock ) internalPacketArray[ splitPacketIndex ]->dataBitLength = internalPacket->dataBitLength - splitPacketIndex * ( maximumSendBlock << 3 ); else internalPacketArray[ splitPacketIndex ]->dataBitLength = bytesToSend << 3; internalPacketArray[ splitPacketIndex ]->splitPacketIndex = splitPacketIndex; internalPacketArray[ splitPacketIndex ]->splitPacketId = splitPacketId; internalPacketArray[ splitPacketIndex ]->splitPacketCount = internalPacket->splitPacketCount; if ( splitPacketIndex > 0 ) // For the first split packet index we keep the packetNumber already assigned { // For every further packet we use a new packetNumber. // Note that all split packets are reliable internalPacketArray[ splitPacketIndex ]->packetNumber = packetNumber; //if ( ++packetNumber == RECEIVED_PACKET_LOG_LENGTH ) // packetNumber = 0; ++packetNumber; } // Add the new packet to send list at the correct priority // SHOW SPLIT PACKET GENERATION // if (splitPacketIndex % 100 == 0) // printf("splitPacketIndex=%i\n",splitPacketIndex); //} while(++splitPacketIndex < internalPacket->splitPacketCount); } while ( ++splitPacketIndex < internalPacket->splitPacketCount ); splitPacketId++; // It's ok if this wraps to 0 // Copy all the new packets into the split packet list for ( int i = 0; i < ( int ) internalPacket->splitPacketCount; i++ ) { sendPacketSet[ internalPacket->priority ].push( internalPacketArray[ i ] ); } // Delete the original delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); } //------------------------------------------------------------------------------------------------------- // Insert a packet into the split packet list //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::InsertIntoSplitPacketList( InternalPacket * internalPacket ) { splitPacketList.insert( internalPacket ); } //------------------------------------------------------------------------------------------------------- // Take all split chunks with the specified splitPacketId and try to //reconstruct a packet. If we can, allocate and return it. Otherwise return 0 // Optimized version //------------------------------------------------------------------------------------------------------- InternalPacket * ReliabilityLayer::BuildPacketFromSplitPacketList( unsigned int splitPacketId, unsigned int time ) { int i, j, size; // How much data all blocks but the last hold int maxDataSize; int numParts; int bitlength; int *indexList; int indexListIndex; size = splitPacketList.size(); for ( i = 0; i < size; i++ ) { if ( splitPacketList[ i ]->splitPacketId == splitPacketId ) { // Is there enough elements in the list to have all the parts? if ( splitPacketList[ i ]->splitPacketCount > splitPacketList.size() - i ) { // if (splitPacketList.size() % 100 == 0 || splitPacketList[i]->splitPacketCount-splitPacketList.size()<100) // printf("%i out of %i\n", splitPacketList.size(), splitPacketList[i]->splitPacketCount); return 0; } // printf("%i out of %i\n", splitPacketList.size(), splitPacketList[i]->splitPacketCount); // Keep track of the indices of the elements through our first scan so we don't have to rescan to find them indexListIndex = 0; numParts = 1; bitlength = splitPacketList[ i ]->dataBitLength; indexList = ( int* ) alloca( sizeof( int ) * splitPacketList[ i ]->splitPacketCount ); indexList[ indexListIndex++ ] = i; maxDataSize = BITS_TO_BYTES( splitPacketList[ i ]->dataBitLength ); // Are all the parts there? for ( j = i + 1; j < size; j++ ) { if ( splitPacketList[ j ]->splitPacketId == splitPacketId ) { indexList[ indexListIndex++ ] = j; numParts++; bitlength += splitPacketList[ j ]->dataBitLength; // Verify that we are dealing with the same splitPacketId #ifdef _DEBUG assert(splitPacketList[ j ]->splitPacketCount==splitPacketList[ i ]->splitPacketCount); #endif if ( ( int ) BITS_TO_BYTES( splitPacketList[ j ]->dataBitLength ) > maxDataSize ) maxDataSize = BITS_TO_BYTES( splitPacketList[ j ]->dataBitLength ); } } if ( (unsigned int)numParts == splitPacketList[ i ]->splitPacketCount ) { int allocatedLength; // All the parts are here InternalPacket * internalPacket = CreateInternalPacketCopy( splitPacketList[ i ], 0, 0, time ); allocatedLength=BITS_TO_BYTES( bitlength ); internalPacket->data = new char[ allocatedLength ]; #ifdef _DEBUG internalPacket->splitPacketCount = splitPacketList[ i ]->splitPacketCount; #endif // Add each part to internalPacket j = 0; while ( j < indexListIndex ) { if ( splitPacketList[ indexList[ j ] ]->splitPacketCount-1 == splitPacketList[ indexList[ j ] ]->splitPacketIndex ) { // Last split packet // If this assert fails, // then the total bit length calculated by adding the last block to the maximum block size * the number of blocks that are not the last block // doesn't match the amount calculated from traversing the list #ifdef _DEBUG assert( BITS_TO_BYTES( splitPacketList[ indexList[ j ] ]->dataBitLength ) + splitPacketList[ indexList[ j ] ]->splitPacketIndex * (unsigned)maxDataSize == ( (unsigned)bitlength - 1 ) / 8 + 1 ); #endif if (splitPacketList[ indexList[ j ] ]->splitPacketIndex * (unsigned int) maxDataSize + (unsigned int) BITS_TO_BYTES( splitPacketList[ indexList[ j ] ]->dataBitLength ) > (unsigned int) allocatedLength ) { // Watch for buffer overruns #ifdef _DEBUG assert(0); #endif delete internalPacket->data; internalPacketPool.ReleasePointer(internalPacket); return 0; } memcpy( internalPacket->data + splitPacketList[ indexList[ j ] ]->splitPacketIndex * maxDataSize, splitPacketList[ indexList[ j ] ]->data, BITS_TO_BYTES( splitPacketList[ indexList[ j ] ]->dataBitLength ) ); } else { if (splitPacketList[ indexList[ j ] ]->splitPacketIndex * (unsigned int) maxDataSize + (unsigned int) maxDataSize > (unsigned int) allocatedLength ) { // Watch for buffer overruns #ifdef _DEBUG assert(0); #endif delete internalPacket->data; internalPacketPool.ReleasePointer(internalPacket); return 0; } // Not last split packet memcpy( internalPacket->data + splitPacketList[ indexList[ j ] ]->splitPacketIndex * maxDataSize, splitPacketList[ indexList[ j ] ]->data, maxDataSize ); } internalPacket->dataBitLength += splitPacketList[ indexList[ j ] ]->dataBitLength; InternalPacket *temp; temp = splitPacketList[ indexList[ j ] ]; delete [] temp->data; internalPacketPool.ReleasePointer( temp ); splitPacketList[ indexList[ j ] ] = 0; #ifdef _DEBUG numParts--; #endif j++; size--; } #ifdef _DEBUG assert( numParts == 0 ); // Make sure the correct # of elements was removed from the list #endif j = 0; while ( ( unsigned ) j < splitPacketList.size() ) if ( splitPacketList[ j ] == 0 ) { // Since order doesn't matter, swap from the tail to the current element. splitPacketList[ j ] = splitPacketList[ splitPacketList.size() - 1 ]; splitPacketList[ splitPacketList.size() - 1 ] = 0; // Then just delete the tail (just changes a counter) splitPacketList.del( splitPacketList.size() - 1 ); } else j++; return internalPacket; } break; } } return 0; } // Delete any unreliable split packets that have long since expired void ReliabilityLayer::DeleteOldUnreliableSplitPackets( unsigned int time ) { unsigned size, i, orderingIndexToDelete; unsigned int newestUnreliableSplitPacket; bool found; InternalPacket *temp; // Scan through the list for split packets that were sent unreliably. // If the newest unreliable split packet for a particular ID is more than 3000 ms old, then // delete all of them of that id size = splitPacketList.size(); newestUnreliableSplitPacket = 0; found = false; for ( i = 0; i < size; i++ ) { if ( ( splitPacketList[ i ]->reliability == UNRELIABLE || splitPacketList[ i ]->reliability == UNRELIABLE_SEQUENCED ) && splitPacketList[ i ]->creationTime >= newestUnreliableSplitPacket ) { orderingIndexToDelete = splitPacketList[ i ]->orderingIndex; newestUnreliableSplitPacket = splitPacketList[ i ]->creationTime; found = true; } } if ( found && time>newestUnreliableSplitPacket && time-newestUnreliableSplitPacket > 5000 ) { // Delete all split packets that use orderingIndexToDelete i = 0; while ( i < splitPacketList.size() ) { #pragma warning( disable : 4701 ) // warning C4701: local variable 'orderingIndexToDelete' may be used without having been initialized if ( splitPacketList[ i ]->orderingIndex == orderingIndexToDelete ) { temp = splitPacketList[ i ]; splitPacketList[ i ] = splitPacketList[ splitPacketList.size() - 1 ]; splitPacketList.del(); // Removes the last element delete [] temp->data; internalPacketPool.ReleasePointer( temp ); } else i++; } } } //------------------------------------------------------------------------------------------------------- // Creates a copy of the specified internal packet with data copied from the original starting at dataByteOffset for dataByteLength bytes. // Does not copy any split data parameters as that information is always generated does not have any reason to be copied //------------------------------------------------------------------------------------------------------- InternalPacket * ReliabilityLayer::CreateInternalPacketCopy( InternalPacket *original, int dataByteOffset, int dataByteLength, unsigned int time ) { InternalPacket * copy = internalPacketPool.GetPointer(); #ifdef _DEBUG // Remove boundschecker accessing undefined memory error memset( copy, 255, sizeof( InternalPacket ) ); #endif // Copy over our chunk of data if ( dataByteLength > 0 ) { copy->data = new char[ dataByteLength ]; memcpy( copy->data, original->data + dataByteOffset, dataByteLength ); } else copy->data = 0; copy->dataBitLength = dataByteLength << 3; copy->creationTime = time; copy->isAcknowledgement = original->isAcknowledgement; copy->nextActionTime = 0; copy->orderingIndex = original->orderingIndex; copy->orderingChannel = original->orderingChannel; copy->packetNumber = original->packetNumber; copy->priority = original->priority; copy->reliability = original->reliability; return copy; } //------------------------------------------------------------------------------------------------------- // Get the specified ordering list // LOCK THIS WHOLE BLOCK WITH reliabilityLayerMutexes[orderingList_MUTEX].Unlock(); //------------------------------------------------------------------------------------------------------- BasicDataStructures::LinkedList *ReliabilityLayer::GetOrderingListAtOrderingStream( unsigned char orderingChannel ) { if ( orderingChannel >= orderingList.size() ) return 0; return orderingList[ orderingChannel ]; } //------------------------------------------------------------------------------------------------------- // Add the internal packet to the ordering list in order based on order index //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::AddToOrderingList( InternalPacket * internalPacket ) { #ifdef _DEBUG assert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS ); #endif if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) { return; } BasicDataStructures::LinkedList *theList; if ( internalPacket->orderingChannel >= orderingList.size() || orderingList[ internalPacket->orderingChannel ] == 0 ) { // Need a linked list in this index orderingList.replace( new BasicDataStructures::LinkedList, 0, internalPacket->orderingChannel ); theList=orderingList[ internalPacket->orderingChannel ]; } else { // Have a linked list in this index if ( orderingList[ internalPacket->orderingChannel ]->size() == 0 ) { theList=orderingList[ internalPacket->orderingChannel ]; } else { theList = GetOrderingListAtOrderingStream( internalPacket->orderingChannel ); } } theList->end(); theList->add(internalPacket); } //------------------------------------------------------------------------------------------------------- // Inserts a packet into the resend list in order // THIS WHOLE FUNCTION SHOULD BE LOCKED WITH // reliabilityLayerMutexes[resendQueue_MUTEX].Lock(); //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::InsertPacketIntoResendQueue( InternalPacket *internalPacket, unsigned int time, bool makeCopyOfInternalPacket, bool resetAckTimer ) { if ( lastAckTime == 0 || resetAckTimer ) lastAckTime = time; // Start the timer for the ack of this packet if we aren't already waiting for an ack if (makeCopyOfInternalPacket) { InternalPacket *pool=internalPacketPool.GetPointer(); //printf("Adding %i\n", internalPacket->data); memcpy(pool, internalPacket, sizeof(InternalPacket)); resendQueue.push( pool ); } else { resendQueue.push( internalPacket ); } } //------------------------------------------------------------------------------------------------------- // Were you ever unable to deliver a packet despite retries? //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsDeadConnection( void ) const { return deadConnection; } //------------------------------------------------------------------------------------------------------- // Causes IsDeadConnection to return true //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::KillConnection( void ) { deadConnection=true; } //------------------------------------------------------------------------------------------------------- // How long to wait between packet resends //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SetLostPacketResendDelay( unsigned int i ) { if ( i > 0 ) lostPacketResendDelay = i; if ( lostPacketResendDelay < 150 ) // To avoid unnecessary packetloss, this value should be UPDATE_THREAD_UPDATE_TIME + UPDATE_THREAD_POLL_TIME at a minimum lostPacketResendDelay = 150; } //------------------------------------------------------------------------------------------------------- // Statistics //------------------------------------------------------------------------------------------------------- RakNetStatisticsStruct * const ReliabilityLayer::GetStatistics( void ) { int i; for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ ) { statistics.messageSendBuffer[i] = sendPacketSet[i].size(); // statistics.messageSendBuffer[i] = sendPacketSet[i].Size(); } statistics.acknowlegementsPending = acknowledgementQueue.size(); statistics.messagesWaitingForReassembly = splitPacketList.size(); statistics.internalOutputQueueSize = outputQueue.size(); statistics.windowSize = windowSize; statistics.lossySize = lossyWindowSize == MAXIMUM_WINDOW_SIZE + 1 ? 0 : lossyWindowSize; statistics.messagesOnResendQueue = GetResendQueueDataSize(); return &statistics; } //------------------------------------------------------------------------------------------------------- // Decodes the time given and returns if that time should be removed from the recieved packets list //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsExpiredTime(unsigned int input, unsigned int currentTime) const { // A time in the future is just a flag that this was a packet we never got (a hole). We still expire these // after shifting the value to normal time if (IsReceivedPacketHole(input, currentTime)) input -= TIMEOUT_TIME*100; if (input < currentTime - TIMEOUT_TIME) return true; return false; } //------------------------------------------------------------------------------------------------------- // Returns if this packet time is encoded to mean we never got this packet //------------------------------------------------------------------------------------------------------- unsigned int ReliabilityLayer::IsReceivedPacketHole(unsigned int input, unsigned int currentTime) const { return input > currentTime+TIMEOUT_TIME; } //------------------------------------------------------------------------------------------------------- // Gets the time used to indicate that this received packet never arrived //------------------------------------------------------------------------------------------------------- unsigned int ReliabilityLayer::MakeReceivedPacketHole(unsigned int input) const { return input + TIMEOUT_TIME*100; // * 2 is enough but there is no reason to take that chance } //------------------------------------------------------------------------------------------------------- // Returns the number of packets in the resend queue, not counting holes //------------------------------------------------------------------------------------------------------- unsigned int ReliabilityLayer::GetResendQueueDataSize(void) const { // Not accurate but thread-safe. The commented version might crash if the queue is cleared while we loop through it return resendQueue.size(); } //------------------------------------------------------------------------------------------------------- // Process threaded commands //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::UpdateThreadedMemory(void) { if ( freeThreadedMemoryOnNextUpdate ) { freeThreadedMemoryOnNextUpdate = false; } } blobby-1.0/Blobby Volley.cbp000644 001750 001750 00000035777 12313310254 020562 0ustar00danielknobedanielknobe000000 000000 blobby-1.0/data/rules/blitz.lua000644 001750 001750 00000000121 12313310254 021271 0ustar00danielknobedanielknobe000000 000000 __AUTHOR__ = "chameleon" __TITLE__ = "Crazy Volley - Blitz" SCORE_TO_WIN = 2 blobby-1.0/data/gfx/font37.bmp000644 001750 001750 00000003370 12313310254 020725 0ustar00danielknobedanielknobe000000 000000 BM6( ABAB?A616miNjL6LnҝԼtO()PBQݎdO*Pmgo?qIICE %sw56:ҍ RSB.z~R-R\CEb2 ei  PL ')12cJ M  UDvzm9p_;=$%f?i nS`; = w; _eMb 9 >sS | xKJv!$ΈJ1R@Ze5Ablobby-1.0/src/raknet/RakNetStatistics.h000644 001750 001750 00000012505 12313310247 023075 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Store Statistics concerning Network Usage. * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __RAK_NET_STATISTICS_H #define __RAK_NET_STATISTICS_H #include "PacketPriority.h" /** * @brief Network Statisics Usage * * Store Statistics information related to network usage */ struct RakNetStatisticsStruct { //! Number of Messages in the send Buffer (high, medium, low priority) unsigned messageSendBuffer[ NUMBER_OF_PRIORITIES ]; //! Number of messages sent (high, medium, low priority) unsigned messagesSent[ NUMBER_OF_PRIORITIES ]; //! Number of data bits used for user messages unsigned messageDataBitsSent[ NUMBER_OF_PRIORITIES ]; //! Number of total bits used for user messages, including headers unsigned messageTotalBitsSent[ NUMBER_OF_PRIORITIES ]; //! Number of packets sent containing only acknowledgements unsigned packetsContainingOnlyAcknowlegements; //! Number of acknowledgements sent unsigned acknowlegementsSent; //! Number of acknowledgements waiting to be sent unsigned acknowlegementsPending; //! Number of acknowledgements bits sent unsigned acknowlegementBitsSent; //! Number of packets containing only acknowledgements and resends unsigned packetsContainingOnlyAcknowlegementsAndResends; //! Number of messages resent unsigned messageResends; //! Number of bits resent of actual data unsigned messageDataBitsResent; //! Total number of bits resent, including headers unsigned messagesTotalBitsResent; //! Number of messages waiting for ack unsigned messagesOnResendQueue; //! Number of messages not split for sending unsigned numberOfUnsplitMessages; //! Number of messages split for sending unsigned numberOfSplitMessages; //! Total number of splits done for sending unsigned totalSplits; //! Total packets sent unsigned packetsSent; //! total bits sent unsigned totalBitsSent; //! Number of sequenced messages arrived out of order unsigned sequencedMessagesOutOfOrder; //! Number of sequenced messages arrived in order unsigned sequencedMessagesInOrder; //! Number of ordered messages arrived out of order unsigned orderedMessagesOutOfOrder; //! Number of ordered messages arrived in order unsigned orderedMessagesInOrder; //! Packets with a good CRC received unsigned packetsReceived; //! Packets with a bad CRC received unsigned packetsWithBadCRCReceived; //! Bits with a good CRC received unsigned bitsReceived; //! Bits with a bad CRC received unsigned bitsWithBadCRCReceived; //! Number of acknowledgement messages received for packets we are resending unsigned acknowlegementsReceived; //! Number of acknowledgement messages received for packets we are not resending unsigned duplicateAcknowlegementsReceived; //! Number of data messages (anything other than an ack) received that are valid and not duplicate unsigned messagesReceived; //! Number of data messages (anything other than an ack) received that are invalid unsigned invalidMessagesReceived; //! Number of data messages (anything other than an ack) received that are duplicate unsigned duplicateMessagesReceived; //! Number of messages waiting for reassembly unsigned messagesWaitingForReassembly; //! Number of messages in reliability output queue unsigned internalOutputQueueSize; //! Current window size unsigned windowSize; //! lossy window size unsigned lossySize; //! connection start time unsigned int connectionStartTime; }; /** * Verbosity level currently supports 0 (low), 1 (medium), 2 (high) * @param s The Statistical information to format out * @param buffer The buffer containing a formated report * @param verbosityLevel * - 0 low * - 1 medium * - 2 high */ void StatisticsToString( RakNetStatisticsStruct *s, char *buffer, int verbosityLevel ); #endif blobby-1.0/src/raknet/PacketPool.cpp000644 001750 001750 00000006007 12313310247 022232 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "PacketPool.h" #include PacketPool::PacketPool() { #ifdef _DEBUG packetsReleased = 0; #endif } PacketPool::~PacketPool() { #ifdef _DEBUG // If this assert hits then not all packets given through GetPointer have been returned to ReleasePointer. // Either // 1. You got a packet from Receive and didn't give it back to DeallocatePacket when you were done with it // 2. You didn't call Disconnect before shutdown, and the order of destructor calls happened to hit the PacketPool singleton before it hit the RakPeer class(es). assert( packetsReleased == 0 ); #endif ClearPool(); } void PacketPool::ClearPool( void ) { poolMutex.Lock(); while ( !pool.empty() ) { Packet* p = pool.top(); pool.pop(); delete [] p->data; delete p; } poolMutex.Unlock(); } Packet* PacketPool::GetPointer( void ) { Packet * p = 0; poolMutex.Lock(); #ifdef _DEBUG packetsReleased++; #endif if ( !pool.empty() ) { p = pool.top(); pool.pop(); } poolMutex.Unlock(); if ( p ) return p; p = new Packet; p->data = 0; return p; } void PacketPool::ReleasePointer( Packet *p ) { if ( p == 0 ) { // Releasing a null pointer? #ifdef _DEBUG assert( 0 ); #endif return ; } delete [] p->data; p->data = 0; poolMutex.Lock(); pool.push( p ); #ifdef _DEBUG // assert( packetsReleased > 0 ); packetsReleased--; #endif poolMutex.Unlock(); } blobby-1.0/src/SoundManager.h000644 001750 001750 00000004410 12313310251 020724 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /** * @file SoundManager.h * @brief Contains a class which loads and plays sound */ #pragma once #include #include #include #include #include "BlobbyDebug.h" /// \brief struct for holding sound data struct Sound : public ObjectCounter { Sound() { data = 0; } Uint8* data; Uint32 length; int position; float volume; }; /*! \class SoundManager \brief class managing game sound. \details Managing loading, converting to target format, muting, setting volume and, of couse, playing of sounds. */ class SoundManager : public ObjectCounter { public: static SoundManager* createSoundManager(); static SoundManager& getSingleton(); bool init(); void deinit(); bool playSound(const std::string& filename, float volume); void setVolume(float volume); void setMute(bool mute); private: SoundManager(); ~SoundManager(); static SoundManager* mSingleton; SDL_AudioDeviceID mAudioDevice; /// This maps filenames to sound buffers, which are always in /// target format std::map mSound; std::list mPlayingSound; SDL_AudioSpec mAudioSpec; bool mInitialised; float mVolume; bool mMute; Sound* loadSound(const std::string& filename); static void playCallback(void* singleton, Uint8* stream, int length); }; blobby-1.0/src/RenderManagerSDL.cpp000644 001750 001750 00000055505 12313310251 021764 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "RenderManagerSDL.h" /* includes */ #include "FileExceptions.h" /* implementation */ SDL_Surface* RenderManagerSDL::colorSurface(SDL_Surface *surface, Color color) { // Create new surface SDL_Surface *newSurface = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0); SDL_LockSurface(newSurface); for (int p = 0; p < newSurface->w * newSurface->h; ++p) { SDL_Color* pixel = &(((SDL_Color*)newSurface->pixels)[p]); int rr = (int(pixel->r) * int(color.r)) >> 8; int rg = (int(pixel->g) * int(color.g)) >> 8; int rb = (int(pixel->b) * int(color.b)) >> 8; int fak = int(pixel->r) * 5 - 4 * 256 - 138; bool colorkey = !(pixel->r | pixel->g | pixel->b); if (colorkey) { pixel->r = 0; pixel->g = 0; pixel->b = 0; pixel->a = 0; continue; } if (fak > 0) { rr += fak; rg += fak; rb += fak; } rr = rr < 255 ? rr : 255; rg = rg < 255 ? rg : 255; rb = rb < 255 ? rb : 255; // This is clamped to 1 because dark colors may would be // colorkeyed otherwise pixel->r = rr > 0 ? rr : 1; pixel->g = rg > 0 ? rg : 1; pixel->b = rb > 0 ? rb : 1; } SDL_UnlockSurface(newSurface); // Use a black colorkey SDL_SetColorKey(newSurface, SDL_TRUE, SDL_MapRGB(newSurface->format, 0, 0, 0)); return newSurface; } RenderManagerSDL::RenderManagerSDL() : RenderManager() { mBallRotation = 0.0; mLeftBlobAnimationState = 0.0; mRightBlobAnimationState = 0.0; } RenderManager* RenderManager::createRenderManagerSDL() { return new RenderManagerSDL(); } void RenderManagerSDL::init(int xResolution, int yResolution, bool fullscreen) { SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); // Set modesetting Uint32 screenFlags = 0; if (fullscreen) { screenFlags |= SDL_WINDOW_FULLSCREEN; } else { screenFlags |= SDL_WINDOW_RESIZABLE; } // Create window mWindow = SDL_CreateWindow(AppTitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, xResolution, yResolution, screenFlags); // Set icon SDL_Surface* icon = loadSurface("Icon.bmp"); SDL_SetColorKey(icon, SDL_TRUE, SDL_MapRGB(icon->format, 0, 0, 0)); SDL_SetWindowIcon(mWindow, icon); SDL_FreeSurface(icon); // Create renderer to draw in window mRenderer = SDL_CreateRenderer(mWindow, -1, 0); // Hide mousecursor SDL_ShowCursor(0); // Create rendertarget to make window resizeable mRenderTarget = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, xResolution, yResolution); // Load all textures and surfaces to render the game SDL_Surface* tmpSurface; // Create a 1x1 black surface which will be scaled to draw an overlay tmpSurface = SDL_CreateRGBSurface(0, 1, 1, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); // Because of SDL bug we can't check at the moment if color mod is available... no risk no fun ;) SDL_FillRect(tmpSurface, NULL, SDL_MapRGB(tmpSurface->format, 255, 255, 255)); mOverlayTexture = SDL_CreateTextureFromSurface(mRenderer, tmpSurface); SDL_FreeSurface(tmpSurface); // Create marker texture for mouse and ball tmpSurface = SDL_CreateRGBSurface(0, 5, 5, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); SDL_FillRect(tmpSurface, NULL, SDL_MapRGB(tmpSurface->format, 255, 255, 255)); mMarker[0] = SDL_CreateTextureFromSurface(mRenderer, tmpSurface); SDL_FillRect(tmpSurface, NULL, SDL_MapRGB(tmpSurface->format, 0, 0, 0)); mMarker[1] = SDL_CreateTextureFromSurface(mRenderer, tmpSurface); SDL_FreeSurface(tmpSurface); // Load background tmpSurface = loadSurface("backgrounds/strand2.bmp"); mBackground = SDL_CreateTextureFromSurface(mRenderer, tmpSurface); BufferedImage* bgImage = new BufferedImage; bgImage->w = tmpSurface->w; bgImage->h = tmpSurface->h; bgImage->sdlImage = mBackground; SDL_FreeSurface(tmpSurface); mImageMap["background"] = bgImage; // Load ball for (int i = 1; i <= 16; ++i) { char filename[64]; sprintf(filename, "gfx/ball%02d.bmp", i); tmpSurface = loadSurface(filename); SDL_SetColorKey(tmpSurface, SDL_TRUE, SDL_MapRGB(tmpSurface->format, 0, 0, 0)); SDL_Texture *ballTexture = SDL_CreateTextureFromSurface(mRenderer, tmpSurface); SDL_FreeSurface(tmpSurface); mBall.push_back(ballTexture); } // Load ball shadow tmpSurface = loadSurface("gfx/schball.bmp"); SDL_SetColorKey(tmpSurface, SDL_TRUE, SDL_MapRGB(tmpSurface->format, 0, 0, 0)); SDL_SetSurfaceAlphaMod(tmpSurface, 127); mBallShadow = SDL_CreateTextureFromSurface(mRenderer, tmpSurface); SDL_FreeSurface(tmpSurface); // Load blobby and shadows surface // Load streamed textures for coloring for (int i = 1; i <= 5; ++i) { // Load blobby surface char filename[64]; sprintf(filename, "gfx/blobbym%d.bmp", i); SDL_Surface* blobImage = loadSurface(filename); SDL_Surface* formatedBlobImage = SDL_ConvertSurfaceFormat(blobImage, SDL_PIXELFORMAT_ABGR8888, 0); SDL_FreeSurface(blobImage); SDL_SetColorKey(formatedBlobImage, SDL_TRUE, SDL_MapRGB(formatedBlobImage->format, 0, 0, 0)); for(int j = 0; j < formatedBlobImage->w * formatedBlobImage->h; j++) { SDL_Color* pixel = &(((SDL_Color*)formatedBlobImage->pixels)[j]); if (!(pixel->r | pixel->g | pixel->b)) { pixel->a = 0; } } mStandardBlob.push_back(formatedBlobImage); // Load blobby shadow surface sprintf(filename, "gfx/sch1%d.bmp", i); SDL_Surface* blobShadow = loadSurface(filename); SDL_Surface* formatedBlobShadowImage = SDL_ConvertSurfaceFormat(blobShadow, SDL_PIXELFORMAT_ABGR8888, 0); SDL_FreeSurface(blobShadow); SDL_SetSurfaceAlphaMod(formatedBlobShadowImage, 127); SDL_SetColorKey(formatedBlobShadowImage, SDL_TRUE, SDL_MapRGB(formatedBlobShadowImage->format, 0, 0, 0)); for(int j = 0; j < formatedBlobShadowImage->w * formatedBlobShadowImage->h; j++) { SDL_Color* pixel = &(((SDL_Color*)formatedBlobShadowImage->pixels)[j]); if (!(pixel->r | pixel->g | pixel->b)) { pixel->a = 0; } else { pixel->a = 127; } } mStandardBlobShadow.push_back(formatedBlobShadowImage); // Prepare blobby textures SDL_Texture* leftBlobTex = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, formatedBlobImage->w, formatedBlobImage->h); SDL_SetTextureBlendMode(leftBlobTex, SDL_BLENDMODE_BLEND); SDL_UpdateTexture(leftBlobTex, NULL, formatedBlobImage->pixels, formatedBlobImage->pitch); mLeftBlob.push_back(DynamicColoredTexture( leftBlobTex, Color(255, 255, 255))); SDL_Texture* rightBlobTex = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, formatedBlobImage->w, formatedBlobImage->h); SDL_SetTextureBlendMode(rightBlobTex, SDL_BLENDMODE_BLEND); SDL_UpdateTexture(rightBlobTex, NULL, formatedBlobImage->pixels, formatedBlobImage->pitch); mRightBlob.push_back(DynamicColoredTexture( rightBlobTex, Color(255, 255, 255))); // Prepare blobby shadow textures SDL_Texture* leftBlobShadowTex = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, formatedBlobShadowImage->w, formatedBlobShadowImage->h); SDL_SetTextureBlendMode(leftBlobShadowTex, SDL_BLENDMODE_BLEND); mLeftBlobShadow.push_back(DynamicColoredTexture( leftBlobShadowTex, Color(255, 255, 255))); SDL_UpdateTexture(leftBlobShadowTex, NULL, formatedBlobShadowImage->pixels, formatedBlobShadowImage->pitch); SDL_Texture* rightBlobShadowTex = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, formatedBlobShadowImage->w, formatedBlobShadowImage->h); SDL_SetTextureBlendMode(rightBlobShadowTex, SDL_BLENDMODE_BLEND); mRightBlobShadow.push_back(DynamicColoredTexture( rightBlobShadowTex, Color(255, 255, 255))); SDL_UpdateTexture(rightBlobShadowTex, NULL, formatedBlobShadowImage->pixels, formatedBlobShadowImage->pitch); // Load iOS specific icon (because we have no backbutton) #ifdef __APPLE__ #if !MAC_OS_X tmpSurface = loadSurface("gfx/flag.bmp"); SDL_SetColorKey(tmpSurface, SDL_TRUE, SDL_MapRGB(tmpSurface->format, 0, 0, 0)); mBackFlag = SDL_CreateTextureFromSurface(mRenderer, tmpSurface); SDL_FreeSurface(tmpSurface); #endif #endif } // Load font for (int i = 0; i <= 54; ++i) { char filename[64]; sprintf(filename, "gfx/font%02d.bmp", i); SDL_Surface* tempFont = loadSurface(filename); SDL_SetColorKey(tempFont, SDL_TRUE, SDL_MapRGB(tempFont->format, 0, 0, 0)); mFont.push_back(SDL_CreateTextureFromSurface(mRenderer, tempFont)); SDL_Surface* tempFont2 = highlightSurface(tempFont, 60); mHighlightFont.push_back(SDL_CreateTextureFromSurface(mRenderer, tempFont2)); SDL_FreeSurface(tempFont); SDL_FreeSurface(tempFont2); } // Load blood surface SDL_Surface* blobStandardBlood = loadSurface("gfx/blood.bmp"); SDL_Surface* formatedBlobStandardBlood = SDL_ConvertSurfaceFormat(blobStandardBlood, SDL_PIXELFORMAT_ABGR8888, 0); SDL_FreeSurface(blobStandardBlood); SDL_SetColorKey(formatedBlobStandardBlood, SDL_TRUE, SDL_MapRGB(formatedBlobStandardBlood->format, 0, 0, 0)); for(int j = 0; j < formatedBlobStandardBlood->w * formatedBlobStandardBlood->h; j++) { SDL_Color* pixel = &(((SDL_Color*)formatedBlobStandardBlood->pixels)[j]); if (!(pixel->r | pixel->g | pixel->b)) { pixel->a = 0; } else { pixel->a = 255; } } mStandardBlobBlood = formatedBlobStandardBlood; // Create streamed textures for blood SDL_Texture* leftBlobBlood = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, formatedBlobStandardBlood->w, formatedBlobStandardBlood->h); SDL_SetTextureBlendMode(leftBlobBlood, SDL_BLENDMODE_BLEND); mLeftBlobBlood = DynamicColoredTexture( leftBlobBlood, Color(255, 0, 0)); SDL_UpdateTexture(leftBlobBlood, NULL, formatedBlobStandardBlood->pixels, formatedBlobStandardBlood->pitch); SDL_Texture* rightBlobBlood = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, formatedBlobStandardBlood->w, formatedBlobStandardBlood->h); SDL_SetTextureBlendMode(rightBlobBlood, SDL_BLENDMODE_BLEND); mRightBlobBlood = DynamicColoredTexture( rightBlobBlood, Color(255, 0, 0)); SDL_UpdateTexture(rightBlobBlood, NULL, formatedBlobStandardBlood->pixels, formatedBlobStandardBlood->pitch); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); } void RenderManagerSDL::deinit() { SDL_DestroyTexture(mOverlayTexture); SDL_DestroyTexture(mRenderTarget); for(unsigned int i = 0; i < 2; i++) { SDL_DestroyTexture(mMarker[i]); } SDL_DestroyTexture(mBackground); for (unsigned int i = 0; i < mBall.size(); ++i) SDL_DestroyTexture(mBall[i]); SDL_DestroyTexture(mBallShadow); for (unsigned int i = 0; i < mStandardBlob.size(); ++i) { SDL_FreeSurface(mStandardBlob[i]); SDL_FreeSurface(mStandardBlobShadow[i]); SDL_DestroyTexture(mLeftBlob[i].mSDLsf); SDL_DestroyTexture(mLeftBlobShadow[i].mSDLsf); SDL_DestroyTexture(mRightBlob[i].mSDLsf); SDL_DestroyTexture(mRightBlobShadow[i].mSDLsf); } SDL_FreeSurface(mStandardBlobBlood); SDL_DestroyTexture(mLeftBlobBlood.mSDLsf); SDL_DestroyTexture(mRightBlobBlood.mSDLsf); for (unsigned int i = 0; i < mFont.size(); ++i) { SDL_DestroyTexture(mFont[i]); SDL_DestroyTexture(mHighlightFont[i]); } #ifdef __APPLE__ #if !MAC_OS_X SDL_DestroyTexture(mBackFlag); #endif #endif SDL_DestroyRenderer(mRenderer); SDL_DestroyWindow(mWindow); } void RenderManagerSDL::draw() { if (!mDrawGame) return; SDL_RenderCopy(mRenderer, mBackground, NULL, NULL); int animationState; SDL_Rect position; // Ball marker position.y = 5; position.x = (int)lround(mBallPosition.x - 2.5); position.w = 5; position.h = 5; SDL_RenderCopy(mRenderer, mMarker[(int)SDL_GetTicks() % 1000 >= 500], 0, &position); // Mouse marker position.y = 590; position.x = (int)lround(mMouseMarkerPosition - 2.5); position.w = 5; position.h = 5; SDL_RenderCopy(mRenderer, mMarker[(int)SDL_GetTicks() % 1000 >= 500], 0, &position); if(mShowShadow) { // Ball Shadow position = ballShadowRect(ballShadowPosition(mBallPosition)); SDL_RenderCopy(mRenderer, mBallShadow, 0, &position); // Left blob shadow position = blobShadowRect(blobShadowPosition(mLeftBlobPosition)); animationState = int(mLeftBlobAnimationState) % 5; SDL_RenderCopy(mRenderer, mLeftBlobShadow[animationState].mSDLsf, 0, &position); // Right blob shadow position = blobShadowRect(blobShadowPosition(mRightBlobPosition)); animationState = int(mRightBlobAnimationState) % 5; SDL_RenderCopy(mRenderer, mRightBlobShadow[animationState].mSDLsf, 0, &position); } // Restore the rod position.x = 400 - 7; position.y = 300; SDL_Rect rodPosition; rodPosition.x = 400 - 7; rodPosition.y = 300; rodPosition.w = 14; rodPosition.h = 300; SDL_RenderCopy(mRenderer, mBackground, &rodPosition, &rodPosition); #ifdef __APPLE__ #if !MAC_OS_X position.x = 400 - 35; position.y = 70; position.w = 70; position.h = 82; SDL_RenderCopy(mRenderer, mBackFlag, 0, &position); #endif #endif // Drawing the Ball position = ballRect(mBallPosition); animationState = int(mBallRotation / M_PI / 2 * 16) % 16; SDL_RenderCopy(mRenderer, mBall[animationState], 0, &position); // update blob colors colorizeBlobs(LEFT_PLAYER); colorizeBlobs(RIGHT_PLAYER); // Drawing left blob position = blobRect(mLeftBlobPosition); animationState = int(mLeftBlobAnimationState) % 5; SDL_RenderCopy(mRenderer, mLeftBlob[animationState].mSDLsf, 0, &position); // Drawing right blob position = blobRect(mRightBlobPosition); animationState = int(mRightBlobAnimationState) % 5; SDL_RenderCopy(mRenderer, mRightBlob[animationState].mSDLsf, 0, &position); } bool RenderManagerSDL::setBackground(const std::string& filename) { try { SDL_Surface *tempBackgroundSurface = loadSurface(filename); SDL_Texture *tempBackgroundTexture = SDL_CreateTextureFromSurface(mRenderer, tempBackgroundSurface); BufferedImage* oldBackground = mImageMap["background"]; SDL_DestroyTexture(oldBackground->sdlImage); delete oldBackground; BufferedImage* newImage = new BufferedImage; newImage->w = tempBackgroundSurface->w; newImage->h = tempBackgroundSurface->h; newImage->sdlImage = tempBackgroundTexture; SDL_FreeSurface(tempBackgroundSurface); mBackground = newImage->sdlImage; mImageMap["background"] = newImage; } catch (FileLoadException) { return false; } return true; } void RenderManagerSDL::setBlobColor(int player, Color color) { if (color != mBlobColor[player]) { mBlobColor[player] = color; } else { return; } DynamicColoredTexture* handledBlobBlood; if (player == LEFT_PLAYER) { handledBlobBlood = &mLeftBlobBlood; } if (player == RIGHT_PLAYER) { handledBlobBlood = &mRightBlobBlood; } SDL_Surface* tempSurface = colorSurface(mStandardBlobBlood, mBlobColor[player]); SDL_UpdateTexture(handledBlobBlood->mSDLsf, NULL, tempSurface->pixels, tempSurface->pitch); SDL_FreeSurface(tempSurface); } void RenderManagerSDL::colorizeBlobs(int player) { std::vector *handledBlob = 0; std::vector *handledBlobShadow = 0; int frame; if (player == LEFT_PLAYER) { handledBlob = &mLeftBlob; handledBlobShadow = &mLeftBlobShadow; frame = mLeftBlobAnimationState; } if (player == RIGHT_PLAYER) { handledBlob = &mRightBlob; handledBlobShadow = &mRightBlobShadow; frame = mRightBlobAnimationState; } if( (*handledBlob)[frame].mColor != mBlobColor[player]) { SDL_Surface* tempSurface = colorSurface(mStandardBlob[frame], mBlobColor[player]); SDL_UpdateTexture((*handledBlob)[frame].mSDLsf, NULL, tempSurface->pixels, tempSurface->pitch); SDL_FreeSurface(tempSurface); SDL_Surface* tempSurface2 = colorSurface(mStandardBlobShadow[frame], mBlobColor[player]); SDL_UpdateTexture((*handledBlobShadow)[frame].mSDLsf, NULL, tempSurface2->pixels, tempSurface2->pitch); SDL_FreeSurface(tempSurface2); (*handledBlob)[frame].mColor = mBlobColor[player]; } } void RenderManagerSDL::showShadow(bool shadow) { mShowShadow = shadow; } void RenderManagerSDL::setBall(const Vector2& position, float rotation) { mBallPosition = position; mBallRotation = rotation; } void RenderManagerSDL::setMouseMarker(float position) { mMouseMarkerPosition = position; } void RenderManagerSDL::setBlob(int player, const Vector2& position, float animationState) { if (player == LEFT_PLAYER) { mLeftBlobPosition = position; mLeftBlobAnimationState = animationState; } if (player == RIGHT_PLAYER) { mRightBlobPosition = position; mRightBlobAnimationState = animationState; } } void RenderManagerSDL::drawText(const std::string& text, Vector2 position, unsigned int flags) { drawTextImpl(text, position, flags); } void RenderManagerSDL::drawTextImpl(const std::string& text, Vector2 position, unsigned int flags) { int FontSize = (flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL); int length = 0; for (auto iter = text.cbegin(); iter != text.cend(); ) { int index = getNextFontIndex(iter); if (flags & TF_OBFUSCATE) index = FONT_INDEX_ASTERISK; SDL_Rect charRect; charRect.x = lround(position.x) + length; charRect.y = lround(position.y); if (flags & TF_SMALL_FONT) { charRect.w = FONT_WIDTH_SMALL; charRect.h = FONT_WIDTH_SMALL; if (flags & TF_HIGHLIGHT) { SDL_RenderCopy(mRenderer, mHighlightFont[index], NULL, &charRect); } else { SDL_RenderCopy(mRenderer,mFont[index], NULL, &charRect); } } else { if (flags & TF_HIGHLIGHT) { SDL_QueryTexture(mHighlightFont[index], NULL, NULL, &charRect.w, &charRect.h); SDL_RenderCopy(mRenderer, mHighlightFont[index], NULL, &charRect); } else { SDL_QueryTexture(mHighlightFont[index], NULL, NULL, &charRect.w, &charRect.h); SDL_RenderCopy(mRenderer,mFont[index], NULL, &charRect); } } length += FontSize; } } void RenderManagerSDL::drawImage(const std::string& filename, Vector2 position, Vector2 size) { mNeedRedraw = true; BufferedImage* imageBuffer = mImageMap[filename]; if (!imageBuffer) { imageBuffer = new BufferedImage; SDL_Surface* tmpSurface = loadSurface(filename); SDL_SetColorKey(tmpSurface, SDL_TRUE, SDL_MapRGB(tmpSurface->format, 0, 0, 0)); imageBuffer->sdlImage = SDL_CreateTextureFromSurface(mRenderer, tmpSurface); imageBuffer->w = tmpSurface->w; imageBuffer->h = tmpSurface->h; SDL_FreeSurface(tmpSurface); mImageMap[filename] = imageBuffer; } if (size == Vector2(0,0)) { // No scaling const SDL_Rect blitRect = { (short)lround(position.x - float(imageBuffer->w) / 2.0), (short)lround(position.y - float(imageBuffer->h) / 2.0), (short)imageBuffer->w, (short)imageBuffer->h }; SDL_RenderCopy(mRenderer, imageBuffer->sdlImage, NULL, &blitRect); } else { // Scaling const SDL_Rect blitRect = { (short)lround(position.x - float(size.x) / 2.0), (short)lround(position.y - float(size.y) / 2.0), (short)size.x, (short)size.y }; SDL_RenderCopy(mRenderer, imageBuffer->sdlImage, NULL, &blitRect); } } void RenderManagerSDL::drawOverlay(float opacity, Vector2 pos1, Vector2 pos2, Color col) { SDL_Rect ovRect; ovRect.x = (int)lround(pos1.x); ovRect.y = (int)lround(pos1.y); ovRect.w = (int)lround(pos2.x - pos1.x); ovRect.h = (int)lround(pos2.y - pos1.y); SDL_SetTextureAlphaMod(mOverlayTexture, lround(opacity * 255)); SDL_SetTextureColorMod(mOverlayTexture, col.r, col.g, col.b); SDL_RenderCopy(mRenderer, mOverlayTexture, NULL, &ovRect); } void RenderManagerSDL::drawBlob(const Vector2& pos, const Color& col) { SDL_Rect position; position.x = (int)lround(pos.x); position.y = (int)lround(pos.y); static int toDraw = 0; mLeftBlobAnimationState = 0; mRightBlobAnimationState = 0; setBlobColor(toDraw, col); /// \todo this recolores the current frame (0) /// + shadows; thats not exactly what we want colorizeBlobs(toDraw); // Second dirty workaround in the function to have the right position of blobs in the GUI position.x = position.x - (int)(75/2); position.y = position.y - (int)(89/2); if(toDraw == 1) { SDL_QueryTexture(mRightBlob[mRightBlobAnimationState].mSDLsf, NULL, NULL, &position.w, &position.h); SDL_RenderCopy(mRenderer, mRightBlob[mRightBlobAnimationState].mSDLsf, 0, &position); toDraw = 0; } else { SDL_QueryTexture(mLeftBlob[mRightBlobAnimationState].mSDLsf, NULL, NULL, &position.w, &position.h); SDL_RenderCopy(mRenderer, mLeftBlob[mRightBlobAnimationState].mSDLsf, 0, &position); toDraw = 1; } } void RenderManagerSDL::drawParticle(const Vector2& pos, int player) { mNeedRedraw = true; SDL_Rect blitRect = { (short)lround(pos.x - float(9) / 2.0), (short)lround(pos.y - float(9) / 2.0), (short)9, (short)9, }; DynamicColoredTexture blood = player == LEFT_PLAYER ? mLeftBlobBlood : mRightBlobBlood; SDL_RenderCopy(mRenderer, blood.mSDLsf, 0, &blitRect); } void RenderManagerSDL::refresh() { SDL_SetRenderTarget(mRenderer, NULL); // We have a resizeable window // Resize renderer if needed // TODO: We should catch the resize event SDL_Rect renderRect; int windowX; int windowY; SDL_RenderGetViewport(mRenderer, &renderRect); SDL_GetWindowSize(mWindow, &windowX, &windowY); if (renderRect.w != windowX || renderRect.h != windowY) { renderRect.w = windowX; renderRect.h = windowY; SDL_RenderSetViewport(mRenderer, &renderRect); } SDL_RenderCopy(mRenderer, mRenderTarget, NULL, NULL); SDL_RenderPresent(mRenderer); SDL_SetRenderTarget(mRenderer, mRenderTarget); } blobby-1.0/data/gfx/font29.bmp000644 001750 001750 00000003370 12313310254 020726 0ustar00danielknobedanielknobe000000 000000 BM6( 3}Y 7 n \ ;61 EXWAAz  P22kk&' JssJKoQ00mm!#6  llLMa}GGlo(+! 2##uvKLG _`lm.0  2##BDIuweh'*q>&&rv5;5 ^bQXeo=Ack+) *NY.=U #-%; p! "6 > e+Y!DOZ7&b 0[ M E BN.Y'P 0iX O K:5 :H.[SNN[ggW|7_> +$ H"Ebelry}{uxqg`xXm@V';"t&+     0 $;)-K38N47\:?a9?c07GN>GBblobby-1.0/data/rules/the_double.lua000644 001750 001750 00000000643 12313310254 022270 0ustar00danielknobedanielknobe000000 000000 __AUTHOR__ = "chameleon" __TITLE__ = "Crazy Volley - The Double" function OnBallHitsPlayer(player) opp = opponent(player) if touches(player) > 2 then mistake(player, opp, 1) end if touches(opp) == 1 then mistake(opp, player, 1) end end function OnBallHitsGround(player) opp = opponent(player) if touches(opp) == 1 then mistake(opp, player, 1) else mistake(player, opp, 1) end end blobby-1.0/src/RenderManagerSDL.h000644 001750 001750 00000007676 12313310253 021441 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include "RenderManager.h" /*! \class RenderManagerSDL \brief Render Manager on top of SDL \details This render manager uses SDL for all drawing operations. This means it is highly portable, but somewhat slow (e.g. when doing morphing blobs). */ class RenderManagerSDL : public RenderManager { public: RenderManagerSDL(); virtual void init(int xResolution, int yResolution, bool fullscreen); virtual void deinit(); virtual void draw(); virtual void refresh(); virtual bool setBackground(const std::string& filename); virtual void setBlobColor(int player, Color color); virtual void showShadow(bool shadow); virtual void setBall(const Vector2& position, float rotation); virtual void setBlob(int player, const Vector2& position, float animationState); virtual void setMouseMarker(float position); virtual void drawText(const std::string& text, Vector2 position, unsigned int flags = TF_NORMAL); virtual void drawImage(const std::string& filename, Vector2 position, Vector2 size); virtual void drawOverlay(float opacity, Vector2 pos1, Vector2 pos2, Color col); virtual void drawBlob(const Vector2& pos, const Color& col); virtual void drawParticle(const Vector2& pos, int player); private: struct DynamicColoredTexture { // constructors // start surface is expected to have color 0xffffff DynamicColoredTexture() : mSDLsf(0), mColor(255, 255, 255) {}; explicit DynamicColoredTexture(SDL_Texture* sf) : mSDLsf(sf), mColor(255, 255, 255) {}; DynamicColoredTexture(SDL_Texture* sf, Color c) : mSDLsf(sf), mColor(c) {}; SDL_Texture* mSDLsf; Color mColor; }; SDL_Texture* mBackground; SDL_Texture* mBallShadow; SDL_Texture* mMarker[2]; std::vector mBall; std::vector mStandardBlob; std::vector mStandardBlobShadow; SDL_Surface* mStandardBlobBlood; std::vector mLeftBlob; std::vector mLeftBlobShadow; DynamicColoredTexture mLeftBlobBlood; std::vector mRightBlob; std::vector mRightBlobShadow; DynamicColoredTexture mRightBlobBlood; std::vector mFont; std::vector mHighlightFont; SDL_Texture *mOverlayTexture; SDL_Renderer* mRenderer; Vector2 mBallPosition; float mBallRotation; Vector2 mLeftBlobPosition; float mLeftBlobAnimationState; Vector2 mRightBlobPosition; float mRightBlobAnimationState; bool mShowShadow; // Store color for caching Color mBlobColor[MAX_PLAYERS]; // Rendertarget to make windowmode resizeable SDL_Texture* mRenderTarget; // colors a surface // the returned SDL_Surface* is already converted into DisplayFormat SDL_Surface* colorSurface(SDL_Surface *surface, Color color); void drawTextImpl(const std::string& text, Vector2 position, unsigned int flags); void colorizeBlobs(int player); #ifdef __APPLE__ #if !MAC_OS_X SDL_Texture* mBackFlag; #endif #endif }; blobby-1.0/src/DuelMatch.cpp000644 001750 001750 00000021515 12313310252 020550 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "DuelMatch.h" /* includes */ #include #include #include "DuelMatchState.h" #include "MatchEvents.h" #include "PhysicWorld.h" #include "GenericIO.h" #include "GameConstants.h" #include "InputSource.h" /* implementation */ DuelMatch::DuelMatch(bool remote, std::string rules) : // we send a pointer to an unconstructed object here! mLogic(createGameLogic(rules, this)), mPaused(false), events(0), external_events(0), mRemote(remote) { mPhysicWorld.reset( new PhysicWorld() ); setInputSources(boost::make_shared(), boost::make_shared()); } void DuelMatch::setPlayers( PlayerIdentity lplayer, PlayerIdentity rplayer) { mPlayers[LEFT_PLAYER] = lplayer; mPlayers[RIGHT_PLAYER] = rplayer; } void DuelMatch::setInputSources(boost::shared_ptr linput, boost::shared_ptr rinput ) { if(linput) mInputSources[LEFT_PLAYER] = linput; if(rinput) mInputSources[RIGHT_PLAYER] = rinput; mInputSources[LEFT_PLAYER]->setMatch(this); mInputSources[RIGHT_PLAYER]->setMatch(this); } void DuelMatch::reset() { mPhysicWorld.reset(new PhysicWorld()); mLogic = mLogic->clone(); } DuelMatch::~DuelMatch() { } void DuelMatch::setRules(std::string rulesFile) { mLogic = createGameLogic(rulesFile, this); } void DuelMatch::step() { events = external_events; // in pause mode, step does nothing if(mPaused) return; mTransformedInput[LEFT_PLAYER] = mInputSources[LEFT_PLAYER]->updateInput(); mTransformedInput[RIGHT_PLAYER] = mInputSources[RIGHT_PLAYER]->updateInput(); if(!mRemote) { mTransformedInput[LEFT_PLAYER] = mLogic->transformInput( mTransformedInput[LEFT_PLAYER], LEFT_PLAYER ); mTransformedInput[RIGHT_PLAYER] = mLogic->transformInput( mTransformedInput[RIGHT_PLAYER], RIGHT_PLAYER ); } // do steps in physic an logic mLogic->step(); int physicEvents = mPhysicWorld->step( mTransformedInput[LEFT_PLAYER], mTransformedInput[RIGHT_PLAYER], mLogic->isBallValid(), mLogic->isGameRunning() ); // check for all hit events if(!mRemote) events |= physicEvents; // process events if(events & EVENT_LEFT_BLOBBY_HIT) mLogic->onBallHitsPlayer(LEFT_PLAYER); if(events & EVENT_RIGHT_BLOBBY_HIT) mLogic->onBallHitsPlayer(RIGHT_PLAYER); if(events & EVENT_BALL_HIT_LEFT_GROUND) mLogic->onBallHitsGround(LEFT_PLAYER); if(events & EVENT_BALL_HIT_RIGHT_GROUND) mLogic->onBallHitsGround(RIGHT_PLAYER); if(events & EVENT_BALL_HIT_LEFT_WALL) mLogic->onBallHitsWall(LEFT_PLAYER); if(events & EVENT_BALL_HIT_RIGHT_WALL) mLogic->onBallHitsWall(RIGHT_PLAYER); if(events & EVENT_BALL_HIT_NET_LEFT) mLogic->onBallHitsNet(LEFT_PLAYER); if(events & EVENT_BALL_HIT_NET_RIGHT) mLogic->onBallHitsNet(RIGHT_PLAYER); if(events & EVENT_BALL_HIT_NET_TOP) mLogic->onBallHitsNet(NO_PLAYER); switch(mLogic->getLastErrorSide()){ case LEFT_PLAYER: events |= EVENT_ERROR_LEFT; case RIGHT_PLAYER: // if the error was caused by the right player // reset EVENT_ERROR_LEFT events &= ~EVENT_ERROR_LEFT; events |= EVENT_ERROR_RIGHT; mPhysicWorld->setBallVelocity( mPhysicWorld->getBallVelocity().scale(0.6) ); break; default: if ((events & EVENT_BALL_HIT_GROUND) && !mLogic->isBallValid()) { mPhysicWorld->setBallVelocity( mPhysicWorld->getBallVelocity().scale(0.6) ); } break; } // if the round is finished, we // reset BallDown, reset the World // to let the player serve // and trigger the EVENT_RESET if (!mLogic->isBallValid() && canStartRound(mLogic->getServingPlayer())) { resetBall( mLogic->getServingPlayer() ); mLogic->onServe(); events |= EVENT_RESET; } // reset external events external_events = 0; } void DuelMatch::setScore(int left, int right) { mLogic->setScore(LEFT_PLAYER, left); mLogic->setScore(RIGHT_PLAYER, right); } void DuelMatch::setLastHitIntensity(float intensity) { mPhysicWorld->setLastHitIntensity(intensity); } void DuelMatch::trigger(int event) { external_events |= event; } void DuelMatch::resetTriggeredEvents() { external_events = 0; } void DuelMatch::pause() { mLogic->onPause(); mPaused = true; } void DuelMatch::unpause() { mLogic->onUnPause(); mPaused = false; } PlayerSide DuelMatch::winningPlayer() const { return mLogic->getWinningPlayer(); } int DuelMatch::getHitcount(PlayerSide player) const { if (player == LEFT_PLAYER) return mLogic->getTouches(LEFT_PLAYER); else if (player == RIGHT_PLAYER) return mLogic->getTouches(RIGHT_PLAYER); else return 0; } int DuelMatch::getScore(PlayerSide player) const { return mLogic->getScore(player); } int DuelMatch::getScoreToWin() const { return mLogic->getScoreToWin(); } bool DuelMatch::getBallDown() const { return !mLogic->isBallValid(); } bool DuelMatch::getBallActive() const { return mLogic->isGameRunning(); } bool DuelMatch::getBlobJump(PlayerSide player) const { return !mPhysicWorld->blobHitGround(player); } Vector2 DuelMatch::getBlobPosition(PlayerSide player) const { if (player == LEFT_PLAYER || player == RIGHT_PLAYER) return mPhysicWorld->getBlobPosition(player); else return Vector2(0.0, 0.0); } Vector2 DuelMatch::getBlobVelocity(PlayerSide player) const { if (player == LEFT_PLAYER || player == RIGHT_PLAYER) return mPhysicWorld->getBlobVelocity(player); else return Vector2(0.0, 0.0); } Vector2 DuelMatch::getBallPosition() const { return mPhysicWorld->getBallPosition(); } Vector2 DuelMatch::getBallVelocity() const { return mPhysicWorld->getBallVelocity(); } PlayerSide DuelMatch::getServingPlayer() const { // NO_PLAYER hack was moved into ScriptedInpurSource.cpp return mLogic->getServingPlayer(); } void DuelMatch::setState(const DuelMatchState& state) { mPhysicWorld->setState(state.worldState); mLogic->setState(state.logicState); mTransformedInput[LEFT_PLAYER] = state.playerInput[LEFT_PLAYER]; mTransformedInput[RIGHT_PLAYER] = state.playerInput[RIGHT_PLAYER]; mInputSources[LEFT_PLAYER]->setInput( mTransformedInput[LEFT_PLAYER] ); mInputSources[RIGHT_PLAYER]->setInput( mTransformedInput[RIGHT_PLAYER] ); events &= ~EVENT_ERROR; switch (state.errorSide) { case LEFT_PLAYER: events |= EVENT_ERROR_LEFT; break; case RIGHT_PLAYER: events |= EVENT_ERROR_RIGHT; break; } } DuelMatchState DuelMatch::getState() const { DuelMatchState state; state.worldState = mPhysicWorld->getState(); state.logicState = mLogic->getState(); state.playerInput[LEFT_PLAYER] = mTransformedInput[LEFT_PLAYER]; state.playerInput[RIGHT_PLAYER] = mTransformedInput[RIGHT_PLAYER]; state.errorSide = (events & EVENT_ERROR_LEFT) ? LEFT_PLAYER : (events & EVENT_ERROR_RIGHT) ? RIGHT_PLAYER : NO_PLAYER; return state; } void DuelMatch::setServingPlayer(PlayerSide side) { mLogic->setServingPlayer( side ); resetBall( side ); mLogic->onServe( ); } const Clock& DuelMatch::getClock() const { return mLogic->getClock(); } Clock& DuelMatch::getClock() { return mLogic->getClock(); } boost::shared_ptr DuelMatch::getInputSource(PlayerSide player) const { return mInputSources[player]; } void DuelMatch::resetBall( PlayerSide side ) { if (side == LEFT_PLAYER) mPhysicWorld->setBallPosition( Vector2(200, STANDARD_BALL_HEIGHT) ); else if (side == RIGHT_PLAYER) mPhysicWorld->setBallPosition( Vector2(600, STANDARD_BALL_HEIGHT) ); else mPhysicWorld->setBallPosition( Vector2(400, 450) ); mPhysicWorld->setBallVelocity( Vector2(0, 0) ); mPhysicWorld->setBallAngularVelocity( (side == RIGHT_PLAYER ? -1 : 1) * STANDARD_BALL_ANGULAR_VELOCITY ); mPhysicWorld->setLastHitIntensity(0.0); } bool DuelMatch::canStartRound(PlayerSide servingPlayer) const { Vector2 ballVelocity = mPhysicWorld->getBallVelocity(); return (mPhysicWorld->blobHitGround(servingPlayer) && ballVelocity.y < 1.5 && ballVelocity.y > -1.5 && mPhysicWorld->getBallPosition().y > 430); } PlayerIdentity DuelMatch::getPlayer(PlayerSide player) const { return mPlayers[player]; } PlayerIdentity& DuelMatch::getPlayer(PlayerSide player) { return mPlayers[player]; } blobby-1.0/src/lua/ltm.h000644 001750 001750 00000002145 12313310253 017723 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: ltm.h,v 2.11.1.1 2013/04/12 18:48:47 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ #ifndef ltm_h #define ltm_h #include "lobject.h" /* * WARNING: if you change the order of this enumeration, * grep "ORDER TM" */ typedef enum { TM_INDEX, TM_NEWINDEX, TM_GC, TM_MODE, TM_LEN, TM_EQ, /* last tag method with `fast' access */ TM_ADD, TM_SUB, TM_MUL, TM_DIV, TM_MOD, TM_POW, TM_UNM, TM_LT, TM_LE, TM_CONCAT, TM_CALL, TM_N /* number of elements in the enum */ } TMS; #define gfasttm(g,et,e) ((et) == NULL ? NULL : \ ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) #define fasttm(l,et,e) gfasttm(G(l), et, e) #define ttypename(x) luaT_typenames_[(x) + 1] #define objtypename(x) ttypename(ttypenv(x)) LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event); LUAI_FUNC void luaT_init (lua_State *L); #endif blobby-1.0/data/gfx/schball.bmp000644 001750 001750 00000007006 12313310254 021215 0ustar00danielknobedanielknobe000000 000000 BM6(E 333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333blobby-1.0/data/gfx/ball09.bmp000644 001750 001750 00000012066 12313310254 020672 0ustar00danielknobedanielknobe000000 000000 BM66(@@ vux`_a|{}{z|$#$fdfecezyztstrqrqpqifhheftrrgeewvvpooa^]~}yxwvut{{z qro "{|zwxv WYWegeKLK|}|xyxuvuopoghgdedcdc {~~eggVXYstughi eehcce^^`ooqeegNNOrrs}}}xxxsssmmmjjjhhhgggeeedddcccbbb```___]]]ZZZXXXWWWUUUQQQ>>>000)'j醌#``{'c&&痗#f5e5U**_i**f5BB)f&*ii 66fe5)&`{)d6UBBBTej''zT NBB*'{z1ۓUdBgPb?1NN1di' 1❂s//?*h&*?uׂڂ?Y16ffgsXނM:rr:X0ڂ055Bdfga?!MXXdBNNBe ru!q/:ق311Nd)irr!ҁ:rӁM1d' ֜r777:ҁ!ru1Yf*j|r·r9Mٝ1)'jsќ̇pӁ:݂)iqWp9pՂۂ 8ẄpWqre*j98K71//؂fh8pK..Kˈڂ?ݝfg#p}.V۝dT'..NNdd6h.˚w..Ɉq::qޝ11NNbdBU c}..pqrׂ1NNde6;(o.}Lqp9rقN33fP #nnq!:؂ڝBBTTdT55 2\ʈnnn}!)))U5*錍JnɛM|ud5f)f&P{hJn¾.:XfP;-.̇8qXd6*i-pn.ҁ|/Yefg#2))ž"".nnǛ!r?ThQRHI"nnnnĖ.嗆v-HH"nnnn.L9!rׂ1"""H[nnnnnnǛ8Mu/>["mmI-H"nnÖ}͇WM["-Aƚo9HmH"-ƚ\VWrXaFFHH"-śoȚ.ww\ɈpsFGH}}ρr:u,~~~,,FFF[Hʈˇq~DDD,,FFH"nop!8qDkDk,HEFFFHq9++++++++CFFHp+l,~~EFFm\.C,,D,,FFHI+D~@kkFFFFHnQDk+DkC,FFFDk+Z~F,,Flk,,k~~kDD~mH+,,D++mmm[~D~DF[H",+~DF+,k+,~D,D~+,,D,D,~D"DC~+blobby-1.0/src/state/State.cpp000644 001750 001750 00000014622 12313310253 021104 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "State.h" /* includes */ #include #include #include #include "LocalGameState.h" #include "ReplaySelectionState.h" #include "NetworkState.h" #include "NetworkSearchState.h" #include "OptionsState.h" #include "IMGUI.h" #include "TextManager.h" #include "SpeedController.h" #include "InputManager.h" /* implementation */ // static state functions boost::scoped_ptr State::mCurrentState(nullptr); boost::scoped_ptr State::mStateToSwitchTo(nullptr); void State::deinit() { mCurrentState.reset( nullptr ); mStateToSwitchTo.reset( nullptr ); } void State::step() { // check that we are in a valid state if(mCurrentState == nullptr ) { // otherwise, create one mCurrentState.reset( new MainMenuState ); } // perform a state step mCurrentState->step_impl(); // check if we should switch to a new state if( mStateToSwitchTo != nullptr ) { // maybe this debug statuses will help pinpointing crashes faster DEBUG_STATUS( std::string("switching to state ") + mStateToSwitchTo->getStateName()); // if yes, set that new state // use swap so the states do not get destroyed here mCurrentState.swap( mStateToSwitchTo ); // now destroy the old state, which is saved in mStateToSwitchTo at this point mStateToSwitchTo.reset(nullptr); } } const char* State::getCurrenStateName() { return mCurrentState->getStateName(); } State::State() { IMGUI::getSingleton().resetSelection(); } void State::switchState(State* newState) { mStateToSwitchTo.reset(newState); } // -------------------------------------------------------------------------------------------------------------------------------- // concrete implementation of MainMenuState and CreditsState // ----------------------------------------------------------- MainMenuState::MainMenuState() { // set main menu fps SpeedController::getMainInstance()->setGameSpeed(75); } MainMenuState::~MainMenuState() { } void MainMenuState::step_impl() { IMGUI& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doImage(GEN_ID, Vector2(400.0, 300.0), "background"); imgui.doOverlay(GEN_ID, Vector2(0.0, 0.0), Vector2(800.0, 600.0)); imgui.doImage(GEN_ID, Vector2(250.0, 210.0), "gfx/titel.bmp"); if (imgui.doButton(GEN_ID, Vector2(434, 300.0), TextManager::MNU_LABEL_ONLINE)) { switchState( new OnlineSearchState() ); } if (imgui.doButton(GEN_ID, Vector2(434, 340.0), TextManager::MNU_LABEL_LAN)) { switchState( new LANSearchState() ); } if (imgui.doButton(GEN_ID, Vector2(434.0, 380.0), TextManager::MNU_LABEL_START)) { try { switchState(new LocalGameState()); } catch (const ScriptException& except) { FILE* file = fopen("lualog.txt", "wb"); fprintf(file, "Lua Error: %s\n", except.luaerror.c_str()); fclose(file); } } if (imgui.doButton(GEN_ID, Vector2(434.0, 420.0), TextManager::MNU_LABEL_OPTIONS)) { switchState(new OptionState()); } if (imgui.doButton(GEN_ID, Vector2(434.0, 460.0), TextManager::MNU_LABEL_REPLAY)) { switchState(new ReplaySelectionState()); } if (imgui.doButton(GEN_ID, Vector2(434.0, 500.0), TextManager::MNU_LABEL_CREDITS)) { switchState(new CreditsState()); } if (imgui.doButton(GEN_ID, Vector2(434.0, 540.0), TextManager::MNU_LABEL_EXIT)) { InputManager::getSingleton()->setEndBlobby(); } } const char* MainMenuState::getStateName() const { return "MainMenuState"; } CreditsState::CreditsState() { mYPosition = 600; } void CreditsState::step_impl() { IMGUI& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doImage(GEN_ID, Vector2(400.0, 300.0), "background"); imgui.doOverlay(GEN_ID, Vector2(0.0, 0.0), Vector2(800.0, 600.0)); const float xPosition = 50; imgui.doText(GEN_ID, Vector2(xPosition, mYPosition), TextManager::CRD_PROGRAMMERS); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+30), "Daniel Knobe"); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+60), " (daniel-knobe(at)web.de)", TF_SMALL_FONT); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+85), "Jonathan Sieber"); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+115), " (jonathan_sieber(at)yahoo.de)", TF_SMALL_FONT); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+140), "Sven Rech"); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+170), " (svenrech(at)gmx.de)", TF_SMALL_FONT); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+195), "Erik Schultheis"); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+225), " (erik-schultheis(at)freenet.de)", TF_SMALL_FONT); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+255), TextManager::CRD_GRAPHICS); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+285), "Silvio Mummert"); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+315), " (mummertathome(at)t-online.de)", TF_SMALL_FONT); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+340), "Richard Bertrand"); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+370), " (ricbertrand(at)hotmail.com)", TF_SMALL_FONT); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+415), TextManager::CRD_THX); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+445), "Daniel Skoraszewsky"); imgui.doText(GEN_ID, Vector2(xPosition, mYPosition+475), " (skoraszewsky(at)t-online.de)", TF_SMALL_FONT); if (mYPosition > 20) mYPosition -= 2.5; if (imgui.doButton(GEN_ID, Vector2(400.0, 560.0), TextManager::LBL_CANCEL)) { switchState(new MainMenuState()); } } const char* CreditsState::getStateName() const { return "CreditsState"; } blobby-1.0/data/gfx/font54.bmp000644 001750 001750 00000003472 12313310254 020727 0ustar00danielknobedanielknobe000000 000000 BM:zl BGRs$$>*?F+GzL{ȄQ.RW.".R)STE5EX.YR^I^R&TLrXsHJGb0 1sx^bABBdR&TX.YR)SQ.RF+G?@8;4233<~[LRTWzL{$$  E!Ek||~6|Ȅ>*?>.>aJbz\|g^b3~grXs^I^E5E.".sx2z\|4|aJb;|>.>8k0 1?@E!E  blobby-1.0/src/raknet/RakClient.h000644 001750 001750 00000027034 12313310247 021515 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Client communication End Point Declaration * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __RAK_CLIENT_H #define __RAK_CLIENT_H #include "RakPeer.h" /** * @brief Client Peer A client peer is used to contact a server. It * can connect to one server a a time. If you need to connect to * multiple server at the same time think of using a RakPeer instead * of a RakClient. * * @see RakServer */ class RakClient : public RakPeer { public: /** * Constructor */ RakClient(); /** * Destructor */ virtual ~RakClient(); /** * Call this to connect the client to the specified host (ip or domain name) and server port. * This is a non-blocking connection. You know the connection is successful when IsConnected() returns true * or receive gets a packet with the type identifier ID_CONNECTION_REQUEST_ACCEPTED. * serverPort is which port to connect to on the remote machine. clientPort is the port you want the * client to use. Both ports must be open for UDP * * @param host a hostname * @param serverPort The port on which to contact @em host * @param clientPort The port to use localy * @param depreciated is legacy and unused * @param threadSleepTimer >=0 for how many ms to Sleep each internal update cycle * (recommended 30 for low performance, 0 for regular) * @return true on successful initiation, false otherwise */ bool Connect( const char* host, unsigned short serverPort, unsigned short clientPort, unsigned int depreciated, int threadSleepTimer ); /** * Stops the client, stops synchronized data, and resets all internal data. * Does nothing if the client is not connected to begin with * blockDuration is how long you should wait for all remaining packets to go out * If you set it to 0 then the disconnection notification probably won't arrive * @param blockDuration The time to wait before truly close the communication and point */ void Disconnect( unsigned int blockDuration ); /** * This function only works while the client is connected (Use the * Connect function). Returns false on failure, true on success * Sends the data stream of length length If you aren't sure what to * specify for priority and reliability, use HIGH_PRIORITY and * RELIABLE, 0 for ordering channel * @param data a byte buffer * @param length the size of the byte buffer * @param priority the priority of the message * @param reliability the reliability policy required * @param orderingChannel the channel to send the message to. */ bool Send( const char *data, const long length, PacketPriority priority, PacketReliability reliability, char orderingChannel ); /** * This function only works while the client is connected (Use the * Connect function). Returns false on failure, true on success * Sends the BitStream If you aren't sure what to specify for * priority and reliability, use HIGH_PRIORITY and RELIABLE, 0 for * ordering channel * @param bitstream the data to send. * @param priority the priority of the message * @param reliability the reliability policy required * @param orderingChannel the channel to send the message to. */ bool Send( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel ); /** * Call this to get a packet from the incoming packet queue. Use * DeallocatePacket to deallocate the packet after you are done with * it. Check the Packet struct at the top of * CoreNetworkStructures.h for the format of the struct Returns 0 if * no packets are waiting to be handled If the client is not active * this will also return 0, as all waiting packets are flushed when * the client is Disconnected This also updates all memory blocks * associated with synchronized memory * @return the last receive packet */ packet_ptr Receive( void ); /** * Send a ping request to the server.Occasional pings are on by * default (see StartOccasionalPing and StopOccasionalPing) so * unless you turn them off it is not necessary to call this * function. It is here for completeness if you want it Does * nothing if the client is not connected to begin with */ void PingServer( void ); /** * Sends a ping request to a server we are not connected to. This will also initialize the * networking system if it is not already initialized. You can stop the networking system * by calling Disconnect() * The final ping time will be encoded in the following 4 bytes (2-5) as an unsigned int * You can specify if the server should only reply if it has an open connection or not * This must be true for LAN broadcast server discovery on "255.255.255.255" * or you will get replies from clients as well. * @param host The host to contact * @param ServerPort the port used by the server * @param clientPort the port used to receive the answer * @param onlyReplyOnAcceptingConnections if true the server must be ready to accept incomming connection. */ void PingServer( const char* host, unsigned short serverPort, unsigned short clientPort, bool onlyReplyOnAcceptingConnections ); /** * Returns the last ping time read for the specific player or -1 if none read yet * @return last ping value */ int GetLastPing( void ) const; /** * Returns the lowest ping time read or -1 if none read yet * @return lowest ping value */ int GetLowestPing( void ) const; /** * Returns the last ping for the specified player. This information * is broadcast by the server automatically In order to save * bandwidth this information is updated only infrequently and only * for the first 32 players * @param playerId The id of the player you want to have the ping (it might be your id) * @return the last ping for this player * @note You can read your own ping with * this method by passing your own playerId, however for more * up-to-date readings you should use one of the three functions * above * */ int GetPlayerPing( PlayerID playerId ); /** * Returns true if the client is connected to a responsive server * @return true if connected to a server */ bool IsConnected( void ) const; /** * Return the player number of the server. * @return the server playerID */ PlayerID GetServerID( void ) const; /** * Return the player number the server has assigned to you. * * @return our player ID * @note that unlike in previous versions, this is a struct and is not sequential * */ PlayerID GetPlayerID( void ) const; /** * Returns the dotted IP address for the specified playerId * * @param playerId Any player ID other than UNASSIGNED_PLAYER_ID, * even if that player is not currently connected * @return a dotted notation string representation of the address of playerId. */ const char* PlayerIDToDottedIP( PlayerID playerId ) const; /** * Put a packet back at the end of the receive queue in case you don't want to deal with it immediately * @param packet the packet to delayed */ void PushBackPacket( Packet *packet ); /** * Change the MTU size in order to improve performance when sending large packets * This can only be called when not connected. * Returns false on failure (we are connected). True on success. Maximum allowed size is MAXIMUM_MTU_SIZE * A too high of value will cause packets not to arrive at worst and be fragmented at best. * A too low of value will split packets unnecessarily. * Set according to the following table: * 1500. The largest Ethernet packet size; it is also the default value. * This is the typical setting for non-PPPoE, non-VPN connections. The default value for NETGEAR routers, adapters and switches. * 1492. The size PPPoE prefers. * 1472. Maximum size to use for pinging. (Bigger packets are fragmented.) * 1468. The size DHCP prefers. * 1460. Usable by AOL if you don't have large email attachments, etc. * 1430. The size VPN and PPTP prefer. * 1400. Maximum size for AOL DSL. * 576. Typical value to connect to dial-up ISPs. (Default) */ bool SetMTUSize( int size ); /** * Returns the current MTU size */ int GetMTUSize( void ) const; /** * Allow or disallow connection responses from any IP. Normally this should be false, but may be necessary * when connection to servers with multiple IP addresses. * * * @param allow True to allow this behavior, false to not allow. * Defaults to false. Value persists between connections */ void AllowConnectionResponseIPMigration( bool allow ); /** * Sends a one byte message ID_ADVERTISE_SYSTEM to the remote unconnected system. * This will tell the remote system our external IP outside the LAN, and can be used for NAT punch through * * @param host Either a dotted IP address or a domain name * @param remotePort Which port to connect to on the remote machine. * @param data Optional data to append to the packet. * @param dataLength length of data in bytes. Use 0 if no data. */ void AdvertiseSystem( char *host, unsigned short remotePort, const char *data, int dataLength ); /** * Returns a structure containing a large set of network statistics for the server/client connection * You can map this data to a string using the C style StatisticsToString function * * @return 0 on can't find the specified system. A pointer to a set of data otherwise. */ RakNetStatisticsStruct * const GetStatistics( void ); /** * @internal * Retrieve the player index corresponding to this client. */ PlayerIndex GetPlayerIndex( void ); private: /** * Get the player index of another client * @param playerId the id of a client * @return the index */ int GetOtherClientIndexByPlayerID( PlayerID playerId ); /** * Get one free client index. * @return an unsued yet index */ int GetFreeOtherClientIndex( void ); /** * Store other client information */ struct OtherClientsStruct { /** * The id of the other player */ PlayerID playerId; /** * The average ping time */ short ping; /** * Tel whether the remote client is active or not */ bool isActive; } otherClients[ 32 ]; /** * Our local index */ PlayerIndex localPlayerIndex; }; #endif blobby-1.0/data/gfx/stange.bmp000644 001750 001750 00000014126 12313310254 021067 0ustar00danielknobedanielknobe000000 000000 BMV6(B ʦPwlAЫ( |@wlA(%  DwlAЫ( |@wlA(%  8wlAЫ( |@wlA(%  ,wlAЫ( |@wlA(% @ @     @ @ @ @@@     @ @    @ @@   @ @ @    @   )@      @ @ @          @   @ @ @ @ @    @ @ @ @ #include //Bleeding blobs can be a lot of fun :) /*! \class Blood \brief Container to hold the data of a single drop of blood */ class Blood { public: /// \brief constructor, takes position, direction and player /// \param position Position this drop starts at /// \param direction initial velocity of the drop /// \param player Player this blood drop started from. Blood(const Vector2& position, const Vector2& direction, int player); /// this function has to be called each step /// it updates position and velocity. void step(); /// gets the current position of this drop const Vector2& getPosition() const { return mPos; } private: Vector2 mPos; ///< the drops position Vector2 mDir; ///< the drops current velocity int mPlayer; ///< player who spilled this blood drop int mLastFrame; ///< time this drop was updated for the last time }; /*! \class BloodManager \brief Manages blood effects \details this class is responsible for managing blood effects, creating and deleting the particles, updating their positions etc. It is designed as a singleton, so it is noncopyable. */ class BloodManager : private boost::noncopyable { public: /// update function, to be called each step. void step(); /// \brief creates a blood effect /// \param pos Position the effect occurs /// \param intensity intensity of the hit. determines the number of particles /// \param player player which was hit, determines the colour of the particles void spillBlood(Vector2 pos, float intensity, int player); /// enables or disables blood effects void enable(bool enable) { mEnabled = enable; } /// gets the instance of BloodManager, creating one if it does not exists static BloodManager& getSingleton() { if (!mSingleton) mSingleton = new BloodManager; return *mSingleton; } private: /// default constructor, sets mEnabled to the value /// set in config.xml BloodManager(); /// helper function which returns an integer between /// min and max, boundaries included static int random(int min, int max); /// list which contains all currently existing blood particles std::list mParticles; /// true, if blood should be handled/drawn bool mEnabled; /// singleton static BloodManager* mSingleton; }; blobby-1.0/src/lua/lcorolib.c000644 001750 001750 00000006767 12313310253 020745 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lcorolib.c,v 1.5.1.1 2013/04/12 18:48:47 roberto Exp $ ** Coroutine Library ** See Copyright Notice in lua.h */ #include #define lcorolib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" static int auxresume (lua_State *L, lua_State *co, int narg) { int status; if (!lua_checkstack(co, narg)) { lua_pushliteral(L, "too many arguments to resume"); return -1; /* error flag */ } if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { lua_pushliteral(L, "cannot resume dead coroutine"); return -1; /* error flag */ } lua_xmove(L, co, narg); status = lua_resume(co, L, narg); if (status == LUA_OK || status == LUA_YIELD) { int nres = lua_gettop(co); if (!lua_checkstack(L, nres + 1)) { lua_pop(co, nres); /* remove results anyway */ lua_pushliteral(L, "too many results to resume"); return -1; /* error flag */ } lua_xmove(co, L, nres); /* move yielded values */ return nres; } else { lua_xmove(co, L, 1); /* move error message */ return -1; /* error flag */ } } static int luaB_coresume (lua_State *L) { lua_State *co = lua_tothread(L, 1); int r; luaL_argcheck(L, co, 1, "coroutine expected"); r = auxresume(L, co, lua_gettop(L) - 1); if (r < 0) { lua_pushboolean(L, 0); lua_insert(L, -2); return 2; /* return false + error message */ } else { lua_pushboolean(L, 1); lua_insert(L, -(r + 1)); return r + 1; /* return true + `resume' returns */ } } static int luaB_auxwrap (lua_State *L) { lua_State *co = lua_tothread(L, lua_upvalueindex(1)); int r = auxresume(L, co, lua_gettop(L)); if (r < 0) { if (lua_isstring(L, -1)) { /* error object is a string? */ luaL_where(L, 1); /* add extra info */ lua_insert(L, -2); lua_concat(L, 2); } return lua_error(L); /* propagate error */ } return r; } static int luaB_cocreate (lua_State *L) { lua_State *NL; luaL_checktype(L, 1, LUA_TFUNCTION); NL = lua_newthread(L); lua_pushvalue(L, 1); /* move function to top */ lua_xmove(L, NL, 1); /* move function from L to NL */ return 1; } static int luaB_cowrap (lua_State *L) { luaB_cocreate(L); lua_pushcclosure(L, luaB_auxwrap, 1); return 1; } static int luaB_yield (lua_State *L) { return lua_yield(L, lua_gettop(L)); } static int luaB_costatus (lua_State *L) { lua_State *co = lua_tothread(L, 1); luaL_argcheck(L, co, 1, "coroutine expected"); if (L == co) lua_pushliteral(L, "running"); else { switch (lua_status(co)) { case LUA_YIELD: lua_pushliteral(L, "suspended"); break; case LUA_OK: { lua_Debug ar; if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ lua_pushliteral(L, "normal"); /* it is running */ else if (lua_gettop(co) == 0) lua_pushliteral(L, "dead"); else lua_pushliteral(L, "suspended"); /* initial state */ break; } default: /* some error occurred */ lua_pushliteral(L, "dead"); break; } } return 1; } static int luaB_corunning (lua_State *L) { int ismain = lua_pushthread(L); lua_pushboolean(L, ismain); return 2; } static const luaL_Reg co_funcs[] = { {"create", luaB_cocreate}, {"resume", luaB_coresume}, {"running", luaB_corunning}, {"status", luaB_costatus}, {"wrap", luaB_cowrap}, {"yield", luaB_yield}, {NULL, NULL} }; LUAMOD_API int luaopen_coroutine (lua_State *L) { luaL_newlib(L, co_funcs); return 1; } blobby-1.0/data/sounds/chat.wav000644 001750 001750 00000033514 12313310256 021277 0ustar00danielknobedanielknobe000000 000000 RIFFD7WAVEfmt DXdata 7)--,-,*  )--,-,& %+-,--+'-,--+$  *,---'*,--*%*)%     "# %*-+($*,-+)  "*-,--)'-,--,) +,-,-," &,---,-(-,-,-$#--,-,-&-,-,-',,-,-* ",,--+%",,-,( '*($     ##  %+,,& %-,-,)"*--,-',--,-,##,-,-,**,--,-& ,-,,-+# (----,)+--,-,& "+-,--*$,,-,+##*-,,&  !'+(#        $! (--,%  )---+&&-,-,-% +,-,-* *,-,--(*---,,$%-,--,+  '-,--,)+,-,--" $+-,-,+%+--,,!%--,-# !(*)#      #" (-,+$  (,-,-'#+-,-,%(-,-,,! $+-,--(*-,--,' #,,-,-* +,-,-,'*--,-*"%+----(%+-,-+"%,,-+# !()(!        #" (,,*" *,,,,$%,+,,*" ++,+,* &,+,++' ),,+,*$&++,+,) '++,++% (,,+,)""),,+,%&+,+,*  &*,+(! !'('          # ()+( (*+*)!(*+*+)   !(++*+'%++*+** (++++*# %*+*++)&*))*)%))*)*(#*)*))!%**)*% &*)*("''$          '()&&)()& %)()((  )()))&%)())(! ()()))$'('('#'('('(  (('('%%('((& &('(&#%'('#  $#!       %'%"  '&'&$  %&%&%#%%&&%& &%&%&$ "%&&&%#$%&&%%! %%&%&$!%$%$%#!%$$%$  #%$%$!"%$%  ""          ### "$##  !"#"# #"#"#  ""#"#"###"##"#"#"  ""#!"  !"!"" ""!"  !!"" "!""                                                                                                                                                                                               blobby-1.0/COPYING000644 001750 001750 00000043122 12313310254 016442 0ustar00danielknobedanielknobe000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. blobby-1.0/data/scripts/old/hyp09.lua000644 001750 001750 00000021642 12313310254 022244 0ustar00danielknobedanielknobe000000 000000 g=0.28 pg=0.88 v0=14.5 v_p=4.5 pj=0.44 r1=31.5 p0=0 p1=0.5 p2=1 h=31.5+19+25 estt=0 nettime=0 touch=0 est=0 p=0.4 esto=10 function yb(y,vy,t) return y+(vy-g/10)*t-1/2*g*t^2 end function move(x) if (posx()2.26) then right() elseif (posx()>x) and (math.abs(posx()-x)>2.26) then left() end end function tb(y,vy,height,typ) local sgn=0 if (typ==1) then sgn=-1 else sgn=1 end if vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g<0 then return -1 else return -1/10+vy/g+sgn*math.sqrt( vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g ) end end function time(t) return 1/5*math.ceil(5*t) end function pos(x) local x1,x2 x1=4.5*math.ceil((1/4.5)*x) x2=4.5*math.floor((1/4.5)*x) if (x1<0) or (x2<0) then return 0 else if (math.abs(x1-x)146) then return (v1p/0.88-1/2+math.sqrt((v1p/0.88-1/2)^2-(144.5-y1p)/0.44)) else return 0 end end function time(t) return 1/5*math.ceil(5*t) end -- function collide(x,y,vx,vy,objx,objy,r2) local t1=time(math.max(tb(y,vy,objy-(r1+r2),1)-0.2,0)) local t2=time(tb(y,vy,objy+(r1+r2),1)+0.2) local t3=time(math.max(tb(y,vy,objy+(r1+r2),2)-0.2,0)) local t4=time(tb(y,vy,objy-(r1+r2),2)+0.2) local t=-1 if (t1150) then t=-1 end return t end function estimate(x,y,vx,vy,height,typ) local collision=1 local tw,tn,ts=0,0,0 local tr,xr,yr,vxr,vyr,n=0,0,0,0,0,0 while(collision==1) do ts=collide(x,y,vx,vy,400,316,7) if (vx>0) then tw=time((768.5-x)/vx) tn=time((361.5-x)/vx) else tw=time((31.5-x)/vx) tn=time((438.5-x)/vx) end local th=time(tb(y,vy,height,typ)) local t=10000 if ((ts>0) and (ts0) and (tn0) and (twt) then if (t==ts) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vy=vy-g*t xr=x yr=y vxr=0 vyr=0 n=1 collision=0 elseif ((t==tn) or (t==tw)) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vx=-vx vy=vy-g*t collision=1 end else tr=tr+th vxr=vx vyr=vy-g*th xr=x+vx*th yr=yb(y,vy,th) collision=0 end end if (tr<0) then return -1,-1,-1,-1,-1,-1 else return xr,yr,vxr,vyr,tr,n end end function impact(x,y,vx,vy,xpos,ypos,targety,jump,move) local x1,y1,vx1,vy1=0,0,0,0 local x2,y2,vx2,vy2,t2,nn=0,0,0,0,0,0 local xpos1=xpos local ypos1=ypos for t=0,20,0.2 do if (jump==1) then ypos1=yp(tp(ypos)+t) end x1=x+vx*t if (x1<31.5) then x1=2*31.5-x1 end if (x1>368.5) then x1=2*368.5-x1 end y1=yb(y,vy,t) if ((xpos1-x1)^2+(ypos1+19-y1)^2<(31.5+25)^2) then local dx=x1-xpos1 local dy=y1-(ypos1+19) local l=math.sqrt(dx^2+dy^2) vx1=dx/l vy1=dy/l x1=x1+vx1*3 y1=y1+vy1*3 vy1=vy1*13.125 vx1=vx1*13.125 x2,y2,vx2,vy2,t2,nn=estimate(x1,y1,vx1,vy1,targety,2) break end end return x2,y2,x1,y1,vx1,vy1 end function lob() if (math.abs(est-esto)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 -- debug(-10) esto=est imp=0 x1=0 for t=33,0,-3 do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5700) and (math.abs(posx()-x1f)/4.50) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f break end end if (impt>imp) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t end if (imp>740) then break end end end t2=t2+1 end t2=t2-1 if (x1>0) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est) end end function attack() if (math.abs(est-esto)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 h2=900 -- debug(-10) esto=est imp=0 x1=0 for t=33,0,-3 do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5400) and (math.abs(posx()-x1f)/4.5+10) and (x1f<360) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f xat=xaf yat=yaf vxat=vxaf vyat=vyaf break end end h2t=yb(yat,vyat,(400-xat)/vxat) if (h2t316+31.5) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t xa=xat ya=yat vxa=vxat vya=vyat end h2=yb(ya,vya,(400-xa)/vxa) if (h2<316+31.5+10) and (h2>316+31.5) then break end end end t2=t2+1 end t2=t2-1 if (x1>0) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est) end end function netp() if (math.abs(est-esto)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 -- debug(-10) esto=est imp=0 x1=0 for t=33,0,-3 do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,nn=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5400) and (math.abs(posx()-x1f)/4.50) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f break end end if (impt>imp) and (impt<431.5) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t end if (imp>428) then break end end end t2=t2+1 end t2=t2-1 if (x1>0) and (est<368.5) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est) end end function OnOpponentServe() y1p=144.5 if (math.abs(pos(posx())-posx())>1) then move(400) else move(200) end valid=1 end function OnServe(ballready) y1p=144.5 est=700 if (math.abs(pos(posx())-posx())>1) then move(400) else if (math.abs(posx()-180)<2) then jump() else move(180) end end valid=1 end function OnGame() yp2=y1p y1p=oppy() vp=y1p-yp2 esttold=estt netold=net toucho=touch touch=touches() if (touch400-31.5) then move (250) elseif (est<400-10) and (est>400-22) then move(200) elseif (est<400) and (est>400-10) then move(180) else move(230) end end blobby-1.0/src/server/NetworkPlayer.h000644 001750 001750 00000005167 12313310252 022470 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include #include "raknet/NetworkTypes.h" #include "raknet/BitStream.h" #include "Global.h" #include "../BlobbyDebug.h" #include "PlayerIdentity.h" class NetworkGame; /*! \brief class for managing an online player \details This class manages an online player, that is, his identity (name, color, ...), his network address and associated game */ /// \todo add data to log when last packet arrived class NetworkPlayer : public ObjectCounter, public boost::noncopyable { public: NetworkPlayer(); NetworkPlayer(PlayerID id, const std::string& name, Color color, PlayerSide side); // i guess we should! not need to make a copy here // but this is saver as this constructor can't mess up other code. NetworkPlayer(PlayerID id, RakNet::BitStream stream); bool valid() const; // gets network ID of this player const PlayerID& getID() const; // gets name of this player const std::string& getName() const; // gets colour of this player Color getColor() const; // gets side this player wants to play on PlayerSide getDesiredSide() const; // gets the complete player identity PlayerIdentity getIdentity() const; // get game the player currently is in const boost::shared_ptr& getGame() const; void setGame(boost::shared_ptr); private: /* Network ID */ PlayerID mID; /* Identity */ PlayerIdentity mIdentity; /* Game Data */ boost::shared_ptr mGame; /* we could add more data such as stats, accoutn info, etc later. */ }; blobby-1.0/data/000755 001750 001750 00000000000 12313311354 016320 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/data/gfx/sch11.bmp000644 001750 001750 00000030066 12313310254 020526 0ustar00danielknobedanielknobe000000 000000 BM606( 0  333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333blobby-1.0/src/Clock.cpp000644 001750 001750 00000005373 12313310253 017742 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "Clock.h" /* includes */ #include #include "SDL2/SDL.h" /* implementation */ Clock::Clock() : mRunning(false), mGameTime(0), mLastTime(0) { } void Clock::reset() { // set all variables to their default values mRunning = false; mGameTime = 0; mLastTime = SDL_GetTicks(); } void Clock::start() { mLastTime = SDL_GetTicks(); mRunning = true; } void Clock::stop() { mRunning = false; } bool Clock::isRunning() const { return mRunning; } int Clock::getTime() const { return mGameTime / 1000; } void Clock::setTime(int newTime) { mGameTime = newTime * 1000; } std::string Clock::getTimeString() const { /// \todo maybe it makes sense to cache this value. we call this function ~75times a seconds /// when the string changes only once. guest it does not make that much of a difference, but still... // calculate seconds, minutes and hours as integers int time_sec = mGameTime / 1000; int seconds = time_sec % 60; int minutes = ((time_sec - seconds) / 60) % 60; int hours = ((time_sec - 60 * minutes - seconds) / 3600) % 60; // now convert to string via stringstream std::stringstream stream; // only write hours if already player more than 1h if(hours > 0) stream << hours << ":"; // write minutes // leading 0 if minutes < 10 if(minutes < 10) stream << "0"; stream << minutes << ":"; // write seconds // leading 0 if seconds < 10 if(seconds < 10) stream << "0"; stream << seconds; // convert stringstream to string and return return stream.str(); } void Clock::step() { if(mRunning) { int newTime = SDL_GetTicks(); if(newTime > mLastTime) { mGameTime += newTime - mLastTime; } mLastTime = newTime; } } blobby-1.0/data/Icon.ico000644 001750 001750 00000076446 12313310255 017724 0ustar00danielknobedanielknobe000000 000000  hF  00 %V@@ (B:(   mip fefa``hiiggg_^^ccbaaa pnpvuupnotturqqgff```eeecddZZY~~~}}~zyxllmpoojii`__ZYX^\\~~wwwonm_^]FIIRdcc bcepjsemR\CL/)T8m`ceee oUdHzvwE~CnDO6@Cov3|l0(>eeeeee@af{=ZX@H~{rVy@iFNKzQo?29;&KWccbddd@W]FbginfWS?xOYITQ{Ee=R:ys2"8[ZZa_]=F^04up{sw9C_DxbUjRCZQp1`=! oA#^[ZNPP'2f+OLvtHL0;^c18haqXJdeH~:Y5S4M#7ADRSS8>~PHRos^LqN(5|ag`CB2{FGeD[EXzNxI.R7=__\Ɛv{`faFRH[nqbg^aLJ3M8H.E&<#7.-* -'j?wv6&?Sfeeeeeeee.9tLvT&20yR[;n=_CX-B;>'#7S_eeeeeeeee~*3nIbS:>9Bw{~ndSK;MKM=oGmF[PqD)B4968f~3(;Liaaeeeeee0ߣ}%.dG:VtQIOqpT]PAiJMyDDLTW>PBF9;=$&6vQZbbaddbddd0@uy)0[Mcnki`[ar\}EiJTOpI3JEMjJ|IE>\3)>_4'.C\ZZ__]ba^@@]d<:YTYG|en|~DNaEkTG3]ZoDHWSAL[6EDX3[57B@,7[[YXWWYWW@ϢIO]Ja^(.^Ngp}uxpsJS0;<9pXx}crSKA{UIL< u7q0~?U*$c\[UUUIMMϩ+6wHf*"-zfksrbAG3<9DV\3:rDcblbTdSkfY9W+<%7"3".0 5;YYYMPP-6Ga&1GN=GbojND&2Q]OXFA_WgGHWvgg?^;ZGX[ZcZeX^S-H(/\\\\\Y=DdMQC7DmqAB~YJA,4;Q{6?eI@4:,[91;}OD[@X}QHpDl?e.#*ZZ\cc^LJgn\cy|fl)2UZ1>asw|V[NVMTJMC?)(EWX]X_A] =>]`_figou%/JDZ_]J;R]^24>IrXR`@\p^_eebllosr~܄܉םѴؖ}uh{fymi{izvޟth{t̄1A!- ,d\6?soo&%'1\P]Dd$@Ephgvtt);>^P^T`U\XIT>Q,:VSBE&2dQgX?C:;_OFL=O3D27^JFD+7$.XelVuqgPFX" `PcHj!GMoff ev~Әݜ|m_/7ϕlfYlt׈zLJe]s|pw`4cXlV-:?Hϥ~y?D!,/8lחYQҖ|vgtov|͆Opʪ֌zTpsʪms}KfmALnhi;?cisX~UyReQ^eeeeeeeeefbb}}}{xxu{rwtwrorilidd`]YY]YYdd`eeenad$I,+ /Leeeeeeeeeeeeiyeyl|}}}{xxurriii```]YY___ccckhdrc_)CnE 6O^eeeeeeeeeeee?Q"4$50Lav}}}xxxnkkdd`___```fffmgc1<|@F/-.Lgddeeeeeeeee=B(\L+;QgwRmPiOeOgVkcubr^qUgJ^AYF.OWb"+(91=9?MRgnptbgJP6?ZMQK"-)UB!!VU;6E4&DkD"#)?P80J]eeeeeeeeeeee=B,HST\+5&08BU\WZihO]*V/I(.q@GKJ'MT@:AA=6f5A0+"*Jdddeeeeeeeee+6'BT%QlZ+8DJr1_=943&P]IeE&N;@Y8KjEC@ 28S5 /HTdd`dddddd*4 (3Q)SVa@GQU]a;``(LUpW34'P(NVcJ#*.I`76: ?@1*#Ha[^```dd`ddd"+(3.Uj4_sTXNUse@V&.`-Q5>VRG3H2OLBQ"B))7< ?G6-0>4?MS1:''F\sfaoVlW:J7OYY`YYYhhaǃW`JQ@JLPel1;&{dwi%.1I~QZ>D9D;D7@6971 " bA`B^z`*(  $[__[__iliAH&ĉg1YeY /RiVT.1PZRe;Z^\66  %jcccc\dd`jjmľêç^j)%+4Wdmi)64Odi=<"67kkDbU]9>'$~VYdddhhhqqw_oVrYtd~mnu֢݇зugg~e~[nSkNePiWqQjObQkeʊySjLeSoiv+>*(4(~f1]sd$/Vnvv.- %'xkD`Lb:=*3xa^nqq{xu&/!/(58@3@4>6B0<3CDZCX)6*:2?$/ /4=HT4<#1-6>2>&9?TF_.;#/7?,8$0&3->;}x_^19iptt/99N', $sFaPa68/:|ps )5֌ކݕܫ唅;C!0",ϖݢ086:|{_~ݑihULhx؉ي6> +)jRSjЀsk(7%$,y:aŮҍt=d~k$0Ysmr$26$!"~nCbQZ+1FF +5ѝ=fƙѧ}\~sr*1ZzY[筁9b䭎jmysXu(W5`ڑik(2TTc1^ׇu%1bw3:.+{yQmz$!3BLbD^Mfai1<{AI"-+$.dfcʞ0DZȦ]_**7MgڐVxBhΏedSvᴐ%6ݬCkwg:IΠeg25"#AF[pH[4?ALkl蚋BK"/#-`a]~1Bȣ07(1wqX|vv{3@$0yGoݳjgs/;.9⮒^U$229zm)609̤vuPQ:=7533/9ZZѪKtz(3\\[#3)30:rRU&24\k䭰WaJR@H3>n|*p Ǔ맫읠~䪯}????blobby-1.0/src/Vector.h000644 001750 001750 00000012272 12313310252 017611 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /** * @file Vector.h * @brief Contains a class to handle two dimensional vectors */ #pragma once #include #include /// \brief class for repesenting 2d vectors /// \details e.g. positions, velocities. class Vector2 { public: union { struct { float x; float y; }; float val[2]; }; Vector2(); Vector2(float x, float y); Vector2(const Vector2& v1, const Vector2& v2); void clear(); Vector2 reflectX() const; Vector2 reflectY() const; Vector2 scale(float factor) const; Vector2 scaleX(float factor) const; Vector2 scaleY(float factor) const; float length() const; Vector2 normalise(); Vector2 contraVector() const ; inline Vector2 halfVector(const Vector2& vec) const { return Vector2(x + (vec.x - x) / 2, y + (vec.y - y) / 2); } inline Vector2& operator = (const Vector2& newVector) { x = newVector.x; y = newVector.y; return *this; } inline bool operator == (const Vector2& vector) const { return (x == vector.x && y == vector.y); } inline bool operator != (const Vector2& vector) const { return (x != vector.x || y != vector.y); } inline Vector2 operator + (const Vector2& vector) const { return Vector2(x + vector.x, y + vector.y); } inline Vector2 operator - (const Vector2& vector) const { return Vector2(x - vector.x, y - vector.y); } inline Vector2 operator * (float scalar) const { return Vector2(x * scalar, y * scalar); } inline Vector2 operator * (const Vector2& vector) const { return Vector2(x * vector.x, y * vector.y); } inline Vector2 operator / (float scalar) const { assert(scalar != 0.0); float invert = 1.0 / scalar; return Vector2(x * invert, y * invert); } inline Vector2 operator - () const { return Vector2(-x, -y); } inline Vector2& operator += (const Vector2& vector) { x += vector.x; y += vector.y; return *this; } inline Vector2& operator -= (const Vector2& vector) { x -= vector.x; y -= vector.y; return *this; } inline Vector2& operator *= (const Vector2& vector) { x *= vector.x; y *= vector.y; return *this; } inline float dotProduct(const Vector2& vector) const { return x * vector.x + y * vector.y; } inline float crossProduct(const Vector2& vector) const { return x * vector.y - y * vector.x; } inline Vector2 reflect(const Vector2& normal) const { return Vector2(*this - (normal * 2 * dotProduct(normal))); } }; // ------------------------------------------------------------------------------------------------- // INLINE IMPLEMENTATION // ------------------------------------------------------------------------------------------------- inline Vector2::Vector2() : x(0), y(0) { } inline Vector2::Vector2(float a, float b) : x(a), y(b) { } inline Vector2::Vector2(const Vector2& v1, const Vector2& v2) : x(v2.x - v1.x), y(v2.y - v1.y) { } inline Vector2 Vector2::reflectX() const { return Vector2(-x, y); } inline Vector2 Vector2::reflectY() const { return Vector2(x, -y); } inline Vector2 Vector2::scale(float factor) const { return Vector2(x * factor, y * factor); } inline Vector2 Vector2::scaleX(float factor) const { return Vector2(x * factor, y); } inline Vector2 Vector2::scaleY(float factor) const { return Vector2(x, y * factor); } inline float Vector2::length() const { #ifdef USE_SSE float ret; asm ( "movss %1, %%xmm0 \n" "movss %2, %%xmm1 \n" "mulss %%xmm0, %%xmm0 \n" "mulss %%xmm1, %%xmm1 \n" "addss %%xmm1, %%xmm0 \n" "sqrtss %%xmm0, %%xmm0 \n" "movss %%xmm0, %0 \n" : "=m"(ret) : "m"(x), "m"(y) : "%xmm0", "%xmm1" ); return ret; #else return sqrt(this->x * this->x + this->y * this->y); #endif } inline Vector2 Vector2::normalise() { float fLength = length(); if (fLength > 1e-08) return Vector2(x / fLength, y / fLength); return *this; } inline Vector2 Vector2::contraVector() const { return Vector2(-x, -y); } inline void Vector2::clear() { x = 0.0; y = 0.0; } inline bool operator < (const Vector2& v1, const Vector2& v2) { if (v1.x < v2.x) { if (v1.y < v2.y) return true; } return false; } inline bool operator > (const Vector2& v1, const Vector2& v2) { if (v1.x > v2.x) { if (v1.y > v2.y) return true; } return false; } blobby-1.0/data/server/server.xml000644 001750 001750 00000000577 12313310256 021667 0ustar00danielknobedanielknobe000000 000000 blobby-1.0/data/gfx/font11.bmp000644 001750 001750 00000003366 12313310254 020722 0ustar00danielknobedanielknobe000000 000000 BM6( %bf@ B3 3798:68<=9934.0$%%Ӹvztx%7EIMMIc:eI-J// I1Ƹ&>`zۓԌ̀͵rOO0P/0pIrjS8A~DpDr|\}{ղޣuk@mD,E&'#qqK9'()$)TKTѸײػdN3O.-sGt{P0i%l" "ǥɐhV=W,,_/y,|   Բ|e~H6G9|Q~zDׁ023mkm¼ãnco)$)҄nCP,Q uxv212dې޼ehAj !xv||͝п^=4>$1$;G;zRRR&7'N}Nlkvvyv(2(<7<Ɵgh:J9"/"' "%D#7j6QOa^rpBsB̦XW>q>8k6;w9;:@>CBFDJHMKOME{C282ةێmkSPFDNLfdnlsoni_ZQOA=}}vs_\XVQPsq֎䘛WT:7.h->[=~ifKH@=#/#bab_0-+)(WULH-)2/*.,%"!%!W  \$\-m,KE<8D?>:)$  [ > ; ^   d:r9yuvsxusoeaJE -(+%&" &DxDqqх쓘xu`\MIHCQM[WXUNJR(5N4 CONST_NETZ_RECHTS) then --Wenn Ball auf rechter Spielfeldseite dann generatenaechsterBallSchmettern() --Angriffsstaerke neu berechnen end if (target > CONST_MITTE) and (ballx() > CONST_NETZ_RECHTS) then --Wenn der Ball mich nix angeht moveto(135) --Dann auf Standartposition warten else if (targetNetz > CONST_NETZ_LINKS - 10) then --Bei Netzroller einfach schmettern naechsterBallSchmettern = true end if naechsterBallSchmettern then if ((math.abs(bspeedx()) < 4) or (bspeedx() < 0)) then sprungattacke(angriffsstaerke) else if (targetJump < CONST_MITTE / 2) then sprungattacke(-30) --an Rueckwand spielen else sprungattacke(0) --weiterleiten end end return end moveto(target) end end function sprungattacke(p_angriffsstaerke) if (bally() < 550) and (math.abs(ballx() - posx()) > 200) then -- Falls nicht schmetterbar moveto (target - 25) --Dann Notloesung versuchen return end moveto(targetJump-p_angriffsstaerke) -- Bei der Sprungatacke wird die Strke des gewnschten schlages angegeben if (bally() < 580) and (bspeedy() < 0) then jump() end end function naechsterBallSchmetternFlagTesten() if (touches() == 3) then -- falls der Bot einen Anschlag Findet der Direckt punktet so wird der Wer nicht neu berechnet da er dann nciht auf 3 Berhrungen kommt naechsterBallSchmettern = false return end if (ballx() > CONST_MITTE) then -- wenn der ball auf der Anderen Seite ist soll der bot nicht naechsterBallSchmettern sein naechsterBallSchmettern = false return end if (touches() == 1) and (math.abs(bspeedx()) < 2) then -- schon nach der 1ten Beruehrung angreifen wenn der Ball gut kommt naechsterBallSchmettern = true return end if (touches() == 2) then -- nach der 2. Berhrung angreifen naechsterBallSchmettern = true return end naechsterBallSchmettern = false end function generatenaechsterBallSchmettern() angriffsstaerke = math.random(MIN_ANGRIFFSSTAERKE,MAX_ANGRIFFSSTAERKE) end function estimImpact(bx,by,vbx,vby,destY,Frage) -- erlaubt ein besseres Estimate mit ein paar unbeding ntigen Angaben bgrav = 0.28 time1 =(-vby-math.sqrt((vby^2)-(-2*bgrav*(by-destY))))/(-bgrav) resultX = (vbx * time1) + bx estimbspeedx=bspeedx()/math.abs(bspeedx()) if(resultX > CONST_RECHTER_RAND) then -- Korrigieren der Appraller an der Rechten Ebene resultX = 2 * CONST_FELD_LAENGE - resultX estimbspeedx=-estimbspeedx end if(resultX < CONST_BALL_RADIUS) then -- korrigieren der Appraller an der linken Ebene resultX = math.abs(resultX - CONST_BALL_RADIUS) + CONST_BALL_RADIUS estimbspeedx=-estimbspeedx KollisionLinks = true else KollisionLinks = false end if (resultX > CONST_NETZ_RECHTS) and (estimbspeedx > 0) and ((KollisionLinks == true) or (ballx() < CONST_NETZ_LINKS)) then -- Abpraller am Netz unterhalb der Kugel erst wenn Netzroller ausgeschlossen sind resultX = 2 * CONST_NETZ_LINKS - resultX estimbspeedx=-estimbspeedx end if (Frage == 1) then return resultX end if (Frage == 2) then return estimbspeedx end endblobby-1.0/src/FileSystem.cpp000644 001750 001750 00000010533 12313310251 020763 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "FileSystem.h" /* includes */ #include #include /// \todo remove this? currently needed for that probeDir error messages #include /* implementation */ FileSystem* mFileSystemSingleton = 0; FileSystem::FileSystem(const std::string& path) { assert(mFileSystemSingleton == 0); PHYSFS_init(path.c_str()); /// \todo do we need to check if this operation suceeded? mFileSystemSingleton = this; } FileSystem& FileSystem::getSingleton() { assert(mFileSystemSingleton); /// \todo instead of assert, throw exception? return *mFileSystemSingleton; } FileSystem::~FileSystem() { PHYSFS_deinit(); mFileSystemSingleton = 0; } std::vector FileSystem::enumerateFiles(const std::string& directory, const std::string& extension, bool keepExtension) { std::vector files; char** filenames = PHYSFS_enumerateFiles(directory.c_str()); // now test which files have type extension for (int i = 0; filenames[i] != 0; ++i) { std::string tmp = filenames[i]; int position = tmp.length() - extension.length(); if (position >= 0 && tmp.substr(position) == extension) { files.push_back(std::string(tmp.begin(), keepExtension ? (tmp.end()) : (tmp.end() - extension.length()) )); } } // free the file list PHYSFS_freeList(filenames); return files; } bool FileSystem::deleteFile(const std::string& filename) { return PHYSFS_delete(filename.c_str()); } bool FileSystem::exists(const std::string& filename) const { return PHYSFS_exists(filename.c_str()); } bool FileSystem::isDirectory(const std::string& dirname) const { return PHYSFS_isDirectory(dirname.c_str()); } bool FileSystem::mkdir(const std::string& dirname) { return PHYSFS_mkdir(dirname.c_str()); } void FileSystem::addToSearchPath(const std::string& dirname, bool append) { /// \todo check if dir exists? /// \todo use PHYSFS_mount? PHYSFS_addToSearchPath is listed as legacy function only there for binary /// compatibility with older version. /// \todo check return value PHYSFS_addToSearchPath(dirname.c_str(), append ? 1 : 0); } void FileSystem::removeFromSearchPath(const std::string& dirname) { PHYSFS_removeFromSearchPath(dirname.c_str()); } void FileSystem::setWriteDir(const std::string& dirname) { if( !PHYSFS_setWriteDir(dirname.c_str()) ) { BOOST_THROW_EXCEPTION( PhysfsException() ); }; addToSearchPath(dirname, false); } std::string FileSystem::getDirSeparator() { return PHYSFS_getDirSeparator(); } std::string FileSystem::getUserDir() { return PHYSFS_getUserDir(); } void FileSystem::probeDir(const std::string& dirname) { if ( !isDirectory(dirname) ) { if (exists(dirname)) { /// \todo simple delete such files without a warning??? deleteFile(dirname); } if (mkdir(dirname)) { std::cout << PHYSFS_getWriteDir() << dirname << " created" << std::endl; } else { std::cout << "Warning: Creation of" << PHYSFS_getWriteDir() << dirname << " failed!" << std::endl; } } } // exception implementations std::string makeSafePhysfsErrorString() { const char* physfserror = PHYSFS_getLastError(); return physfserror != 0 ? physfserror : "no physfs error message available."; } PhysfsException::PhysfsException() : mPhysfsErrorMsg( makeSafePhysfsErrorString() ) { } blobby-1.0/src/input_device/000755 001750 001750 00000000000 12313310253 020651 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/data/gfx/font46.bmp000644 001750 001750 00000003370 12313310254 020725 0ustar00danielknobedanielknobe000000 000000 BM6( h=i~BQ+Sl^@l+n+,F+G~d8z.~ * *fA&&nG " 7!8 z}lo<>OR" ΋  K#++Ufߧ2$ $    blobby-1.0/data/gfx/font03.bmp000644 001750 001750 00000003370 12313310254 020716 0ustar00danielknobedanielknobe000000 000000 BM6( '*-27?8=E38BHP\?ES:?N+/;! *,6kpszt{Ж~ltPV;?g13N)  ϟҞӥˢݏ|dh?AC&&'/صᶸ``y ;910     blobby-1.0/src/ReplaySavePoint.h000644 001750 001750 00000002303 12313310253 021427 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "DuelMatchState.h" struct ReplaySavePoint { DuelMatchState state; // state of the match when the snapshot occured unsigned int step; // number of game step this snapshot happened void reset(); bool isEmpty() const; }; blobby-1.0/data/gfx/font38.bmp000644 001750 001750 00000003370 12313310254 020726 0ustar00danielknobedanielknobe000000 000000 BM6( H E 5 x   >  /   '# \1,#40 2,p3/H ?:"c  PM%!!t  VS2/+(  ZXPM:9[ZqoJI0AXA׌kj;R; % doczB2Cʵ̸~H11fWgڞ\|-/0 xBՋCFÇ8z#%q|:A CdDgqG blobby-1.0/src/RenderManager.cpp000644 001750 001750 00000015174 12313310252 021420 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "RenderManager.h" /* includes */ #include "FileRead.h" /* implementation */ RenderManager* RenderManager::mSingleton = 0; RenderManager::RenderManager() : mDrawGame(false) { //assert(!mSingleton); if (mSingleton) { mSingleton->deinit(); delete mSingleton; } mSingleton = this; mMouseMarkerPosition = -100.0; mNeedRedraw = true; } SDL_Surface* RenderManager::highlightSurface(SDL_Surface* surface, int luminance) { SDL_Surface *newSurface = createEmptySurface(surface->w, surface->h); SDL_SetColorKey(surface, SDL_FALSE, 0); SDL_BlitSurface(surface, 0, newSurface, 0); SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(newSurface->format, 0, 0, 0)); Uint8 alpha; SDL_GetSurfaceAlphaMod(surface, &alpha); SDL_SetSurfaceAlphaMod(newSurface, alpha); SDL_SetColorKey(newSurface, SDL_TRUE, SDL_MapRGB(newSurface->format, 0, 0, 0)); SDL_LockSurface(newSurface); for (int y = 0; y < surface->h; ++y) { for (int x = 0; x < surface->w; ++x) { // this seems overly complicated: // aren't we just calculating newSurface->pixels + (y * newSurface->w + x) SDL_Color* pixel = &( ((SDL_Color*)newSurface->pixels)[y * newSurface->w + x] ); Uint32 colorKey; SDL_GetColorKey(surface, &colorKey); // we index newSurface->pixels once as Uint32[] and once as SDL_Color[], so these must have the same size static_assert( sizeof(Uint32) == sizeof(SDL_Color), "Uint32 must have the same size as SDL_Color" ); if (colorKey != ((Uint32*)newSurface->pixels)[y * newSurface->w +x]) { pixel->r = pixel->r + luminance > 255 ? 255 : pixel->r + luminance; pixel->g = pixel->g + luminance > 255 ? 255 : pixel->g + luminance; pixel->b = pixel->b + luminance > 255 ? 255 : pixel->b + luminance; } } } SDL_UnlockSurface(newSurface); // no DisplayFormatAlpha, because of problems with // OpenGL RenderManager return newSurface; } SDL_Surface* RenderManager::loadSurface(std::string filename) { FileRead file(filename); int fileLength = file.length(); // just read the whole file boost::shared_array fileContent = file.readRawBytes(fileLength); SDL_RWops* rwops = SDL_RWFromMem(fileContent.get(), fileLength); SDL_Surface* newSurface = SDL_LoadBMP_RW(rwops , 1); if (!newSurface) BOOST_THROW_EXCEPTION ( FileLoadException(filename) ); return newSurface; } SDL_Surface* RenderManager::createEmptySurface(unsigned int width, unsigned int height) { SDL_Surface* newSurface = SDL_CreateRGBSurface(0, width, height, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000); return newSurface; } int RenderManager::getNextFontIndex(std::string::const_iterator& iter) { int index = 47; wchar_t testChar = *iter; ++iter; if (testChar >= '0' && testChar <= '9') index = testChar - '0'; else if (testChar >= 'a' && testChar <= 'z') index = testChar - 'a' + 10; else if (testChar >= 'A' && testChar <= 'Z') index = testChar - 'A' + 10; else if (testChar == '.') index = 36; else if (testChar == '!') index = 37; else if (testChar == '(') index = 38; else if (testChar == ')') index = 39; else if (testChar == '\'') index = 44; else if (testChar == ':') index = 45; else if (testChar == ';') index = 46; else if (testChar == '?') index = 47; else if (testChar == ',') index = 48; else if (testChar == '/') index = 49; else if (testChar == '_') index = 50; else if (testChar == ' ') index = 51; else if (testChar == '-') index = 52; else if (testChar == '%') index = 53; else if (testChar == '+') index = 54; else if (testChar == std::string("ß")[0]) // UTF-8 escape { testChar = *iter; ++iter; if (testChar == std::string("ß")[1]) return 40; else if (testChar == std::string("ä")[1]) return 41; else if (testChar == std::string("ö")[1]) return 42; else if (testChar == std::string("ü")[1]) return 43; else if (testChar == std::string("Ä")[1]) return 41; else if (testChar == std::string("Ö")[1]) return 42; else if (testChar == std::string("Ü")[1]) return 43; } return index; } void RenderManager::setMouseMarker(float position) { mMouseMarkerPosition = position; } SDL_Rect RenderManager::blobRect(const Vector2& position) { SDL_Rect rect = { (short)(lround(position.x) - 37), (short)(lround(position.y) - 44), 75, 89 }; return rect; } SDL_Rect RenderManager::ballRect(const Vector2& position) { SDL_Rect rect = { (short)(lround(position.x) - 32), (short)(lround(position.y) - 32), 64, 64 }; return rect; } Vector2 RenderManager::ballShadowPosition(const Vector2& position) { return Vector2( position.x + (500.0 - position.y) / 4 + 16.0, 500.0 - (500.0 - position.y) / 16.0 - 10.0 ); } SDL_Rect RenderManager::ballShadowRect(const Vector2& position) { SDL_Rect rect = { short(lround(position.x) - 64), short(lround(position.y) - 16), 69, 17 }; return rect; } Vector2 RenderManager::blobShadowPosition(const Vector2& position) { return Vector2( position.x + (500.0 - position.y) / 4 + 16.0, 500.0 - (500.0 - position.y) / 16.0 - 10.0 ); } SDL_Rect RenderManager::blobShadowRect(const Vector2& position) { SDL_Rect rect = { short(lround(position.x) - 64), short(lround(position.y) - 16), 128, 32 }; return rect; } void RenderManager::redraw() { mNeedRedraw = true; } void RenderManager::drawGame(bool draw) { mDrawGame = draw; } void RenderManager::setTitle(const std::string& title) { SDL_SetWindowTitle(mWindow, title.c_str()); } SDL_Window* RenderManager::getWindow() { return mWindow; } Color RenderManager::getOscillationColor() const { float time = float(SDL_GetTicks()) / 1000.0; return Color( int((std::sin(time*1.5) + 1.0) * 128), int((std::sin(time*2.5) + 1.0) * 128), int((std::sin(time*3.5) + 1.0) * 128) ); } blobby-1.0/src/CMakeLists.txt000644 001750 001750 00000007150 12313310253 020736 0ustar00danielknobedanielknobe000000 000000 add_subdirectory(lua) add_subdirectory(tinyxml) ADD_DEFINITIONS(-std=c++11) add_subdirectory(raknet) add_subdirectory(blobnet) add_definitions(-DTIXML_USE_STL) set(CMAKE_CXX_FLAGS "-std=c++11") set(CMAKE_CXX_FLAGS "-Wall") include_directories(.) set(common_SRC BlobbyDebug.cpp BlobbyDebug.h Clock.cpp Clock.h DuelMatch.cpp DuelMatch.h FileRead.cpp FileRead.h FileSystem.cpp FileSystem.h FileWrite.cpp FileWrite.h File.cpp File.h GameLogic.cpp GameLogic.h GenericIO.cpp GenericIO.h Global.h NetworkMessage.cpp NetworkMessage.h PhysicWorld.cpp PhysicWorld.h ReplayRecorder.cpp ReplayRecorder.h SpeedController.cpp SpeedController.h UserConfig.cpp UserConfig.h PhysicState.cpp PhysicState.h DuelMatchState.cpp DuelMatchState.h GameLogicState.cpp GameLogicState.h ReplaySavePoint.cpp ReplaySavePoint.h InputSource.cpp InputSource.h PlayerInput.h PlayerInput.cpp IScriptableComponent.cpp IScriptableComponent.h PlayerIdentity.cpp PlayerIdentity.h server/DedicatedServer.cpp server/DedicatedServer.h server/NetworkPlayer.cpp server/NetworkPlayer.h server/NetworkGame.cpp server/NetworkGame.h ) set (blobby_SRC ${common_SRC} ${inputdevice_SRC} Blood.cpp Blood.h TextManager.cpp TextManager.h main.cpp IMGUI.cpp IMGUI.h InputDevice.h InputManager.cpp InputManager.h LocalInputSource.cpp LocalInputSource.h RenderManager.cpp RenderManager.h RenderManagerGL2D.cpp RenderManagerGL2D.h # RenderManagerGP2X.cpp RenderManagerGP2X.h RenderManagerSDL.cpp RenderManagerSDL.h ScriptedInputSource.cpp ScriptedInputSource.h BotAPICalculations.cpp BotAPICalculations.h SoundManager.cpp SoundManager.h Vector.h ReplayRecorder.cpp ReplayRecorder.h ReplayPlayer.cpp ReplayPlayer.h ReplayLoader.cpp InputSourceFactory.cpp InputSourceFactory.h state/State.cpp state/State.h state/GameState.cpp state/GameState.h state/LocalGameState.cpp state/LocalGameState.h state/NetworkState.cpp state/NetworkState.h state/OptionsState.cpp state/OptionsState.h state/NetworkSearchState.cpp state/NetworkSearchState.h state/ReplayState.cpp state/ReplayState.h state/ReplaySelectionState.cpp state/ReplaySelectionState.h state/LobbyState.cpp state/LobbyState.h input_device/JoystickInput.cpp input_device/JoystickPool.cpp input_device/JoystickPool.h input_device/KeyboardInput.cpp input_device/MouseInput.cpp input_device/TouchInput.cpp ) set (blobby-server_SRC ${common_SRC} server/servermain.cpp ) find_package(Boost REQUIRED) find_package(PhysFS REQUIRED) find_package(OpenGL) find_package(Threads REQUIRED) INCLUDE(FindPkgConfig) PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2) include_directories( ${Boost_INCLUDE_DIR} ${PHYSFS_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS} ) if (OPENGL_FOUND) add_definitions(-DHAVE_LIBGL) endif (OPENGL_FOUND) if (CMAKE_SYSTEM_NAME STREQUAL Windows) set(RAKNET_LIBRARIES raknet ws2_32) else (CMAKE_SYSTEM_NAME STREQUAL Windows) set(RAKNET_LIBRARIES raknet) endif (CMAKE_SYSTEM_NAME STREQUAL Windows) add_executable(blobby ${blobby_SRC}) target_link_libraries(blobby lua raknet blobnet tinyxml ${RAKNET_LIBRARIES} ${PHYSFS_LIBRARY} ${OPENGL_LIBRARIES} ${SDL2_LIBRARIES} pthread) if (UNIX) add_executable(blobby-server ${blobby-server_SRC}) target_link_libraries(blobby-server lua raknet blobnet tinyxml ${RAKNET_LIBRARIES} ${PHYSFS_LIBRARY} ${SDL2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) endif (UNIX) if (CMAKE_SYSTEM_NAME STREQUAL Windows) set_target_properties(blobby PROPERTIES LINK_FLAGS "-mwindows") # disable the console window endif (CMAKE_SYSTEM_NAME STREQUAL Windows) if (WIN32) install(TARGETS blobby DESTINATION .) elseif (UNIX) install(TARGETS blobby blobby-server DESTINATION bin) endif (WIN32) blobby-1.0/data/server/000755 001750 001750 00000000000 12313310256 017626 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/lua/lua.h000644 001750 001750 00000032442 12313310253 017713 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lua.h,v 1.285.1.2 2013/11/11 12:09:16 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file */ #ifndef lua_h #define lua_h #include #include #include "luaconf.h" #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "2" #define LUA_VERSION_NUM 502 #define LUA_VERSION_RELEASE "3" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2013 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" /* mark for precompiled code ('Lua') */ #define LUA_SIGNATURE "\033Lua" /* option for multiple returns in 'lua_pcall' and 'lua_call' */ #define LUA_MULTRET (-1) /* ** pseudo-indices */ #define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX #define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) /* thread status */ #define LUA_OK 0 #define LUA_YIELD 1 #define LUA_ERRRUN 2 #define LUA_ERRSYNTAX 3 #define LUA_ERRMEM 4 #define LUA_ERRGCMM 5 #define LUA_ERRERR 6 typedef struct lua_State lua_State; typedef int (*lua_CFunction) (lua_State *L); /* ** functions that read/write blocks when loading/dumping Lua chunks */ typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); /* ** prototype for memory-allocation functions */ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); /* ** basic types */ #define LUA_TNONE (-1) #define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 #define LUA_TNUMBER 3 #define LUA_TSTRING 4 #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8 #define LUA_NUMTAGS 9 /* minimum Lua stack available to a C function */ #define LUA_MINSTACK 20 /* predefined values in the registry */ #define LUA_RIDX_MAINTHREAD 1 #define LUA_RIDX_GLOBALS 2 #define LUA_RIDX_LAST LUA_RIDX_GLOBALS /* type of numbers in Lua */ typedef LUA_NUMBER lua_Number; /* type for integer functions */ typedef LUA_INTEGER lua_Integer; /* unsigned integer type */ typedef LUA_UNSIGNED lua_Unsigned; /* ** generic extra include file */ #if defined(LUA_USER_H) #include LUA_USER_H #endif /* ** RCS ident string */ extern const char lua_ident[]; /* ** state manipulation */ LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); LUA_API void (lua_close) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); LUA_API const lua_Number *(lua_version) (lua_State *L); /* ** basic stack manipulation */ LUA_API int (lua_absindex) (lua_State *L, int idx); LUA_API int (lua_gettop) (lua_State *L); LUA_API void (lua_settop) (lua_State *L, int idx); LUA_API void (lua_pushvalue) (lua_State *L, int idx); LUA_API void (lua_remove) (lua_State *L, int idx); LUA_API void (lua_insert) (lua_State *L, int idx); LUA_API void (lua_replace) (lua_State *L, int idx); LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); LUA_API int (lua_checkstack) (lua_State *L, int sz); LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); /* ** access functions (stack -> C) */ LUA_API int (lua_isnumber) (lua_State *L, int idx); LUA_API int (lua_isstring) (lua_State *L, int idx); LUA_API int (lua_iscfunction) (lua_State *L, int idx); LUA_API int (lua_isuserdata) (lua_State *L, int idx); LUA_API int (lua_type) (lua_State *L, int idx); LUA_API const char *(lua_typename) (lua_State *L, int tp); LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); LUA_API lua_Unsigned (lua_tounsignedx) (lua_State *L, int idx, int *isnum); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); LUA_API size_t (lua_rawlen) (lua_State *L, int idx); LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); LUA_API const void *(lua_topointer) (lua_State *L, int idx); /* ** Comparison and arithmetic functions */ #define LUA_OPADD 0 /* ORDER TM */ #define LUA_OPSUB 1 #define LUA_OPMUL 2 #define LUA_OPDIV 3 #define LUA_OPMOD 4 #define LUA_OPPOW 5 #define LUA_OPUNM 6 LUA_API void (lua_arith) (lua_State *L, int op); #define LUA_OPEQ 0 #define LUA_OPLT 1 #define LUA_OPLE 2 LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); /* ** push functions (C -> stack) */ LUA_API void (lua_pushnil) (lua_State *L); LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); LUA_API void (lua_pushunsigned) (lua_State *L, lua_Unsigned n); LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t l); LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp); LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); LUA_API void (lua_pushboolean) (lua_State *L, int b); LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); LUA_API int (lua_pushthread) (lua_State *L); /* ** get functions (Lua -> stack) */ LUA_API void (lua_getglobal) (lua_State *L, const char *var); LUA_API void (lua_gettable) (lua_State *L, int idx); LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawget) (lua_State *L, int idx); LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); LUA_API void (lua_rawgetp) (lua_State *L, int idx, const void *p); LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); LUA_API void (lua_getuservalue) (lua_State *L, int idx); /* ** set functions (stack -> Lua) */ LUA_API void (lua_setglobal) (lua_State *L, const char *var); LUA_API void (lua_settable) (lua_State *L, int idx); LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawset) (lua_State *L, int idx); LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); LUA_API void (lua_setuservalue) (lua_State *L, int idx); /* ** 'load' and 'call' functions (load and run Lua code) */ LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, int ctx, lua_CFunction k); #define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) LUA_API int (lua_getctx) (lua_State *L, int *ctx); LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, int ctx, lua_CFunction k); #define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, const char *chunkname, const char *mode); LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); /* ** coroutine functions */ LUA_API int (lua_yieldk) (lua_State *L, int nresults, int ctx, lua_CFunction k); #define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); LUA_API int (lua_status) (lua_State *L); /* ** garbage-collection function and options */ #define LUA_GCSTOP 0 #define LUA_GCRESTART 1 #define LUA_GCCOLLECT 2 #define LUA_GCCOUNT 3 #define LUA_GCCOUNTB 4 #define LUA_GCSTEP 5 #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 #define LUA_GCSETMAJORINC 8 #define LUA_GCISRUNNING 9 #define LUA_GCGEN 10 #define LUA_GCINC 11 LUA_API int (lua_gc) (lua_State *L, int what, int data); /* ** miscellaneous functions */ LUA_API int (lua_error) (lua_State *L); LUA_API int (lua_next) (lua_State *L, int idx); LUA_API void (lua_concat) (lua_State *L, int n); LUA_API void (lua_len) (lua_State *L, int idx); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); /* ** =============================================================== ** some useful macros ** =============================================================== */ #define lua_tonumber(L,i) lua_tonumberx(L,i,NULL) #define lua_tointeger(L,i) lua_tointegerx(L,i,NULL) #define lua_tounsigned(L,i) lua_tounsignedx(L,i,NULL) #define lua_pop(L,n) lua_settop(L, -(n)-1) #define lua_newtable(L) lua_createtable(L, 0, 0) #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) #define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) #define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) #define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) #define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) #define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) #define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) #define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) #define lua_pushliteral(L, s) \ lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) #define lua_pushglobaltable(L) \ lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) /* ** {====================================================================== ** Debug API ** ======================================================================= */ /* ** Event codes */ #define LUA_HOOKCALL 0 #define LUA_HOOKRET 1 #define LUA_HOOKLINE 2 #define LUA_HOOKCOUNT 3 #define LUA_HOOKTAILCALL 4 /* ** Event masks */ #define LUA_MASKCALL (1 << LUA_HOOKCALL) #define LUA_MASKRET (1 << LUA_HOOKRET) #define LUA_MASKLINE (1 << LUA_HOOKLINE) #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) typedef struct lua_Debug lua_Debug; /* activation record */ /* Functions to be called by the debugger in specific events */ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, int fidx2, int n2); LUA_API int (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); LUA_API lua_Hook (lua_gethook) (lua_State *L); LUA_API int (lua_gethookmask) (lua_State *L); LUA_API int (lua_gethookcount) (lua_State *L); struct lua_Debug { int event; const char *name; /* (n) */ const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ const char *source; /* (S) */ int currentline; /* (l) */ int linedefined; /* (S) */ int lastlinedefined; /* (S) */ unsigned char nups; /* (u) number of upvalues */ unsigned char nparams;/* (u) number of parameters */ char isvararg; /* (u) */ char istailcall; /* (t) */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ struct CallInfo *i_ci; /* active function */ }; /* }====================================================================== */ /****************************************************************************** * Copyright (C) 1994-2013 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ #endif blobby-1.0/src/state/NetworkState.cpp000644 001750 001750 00000050651 12313310253 022460 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ /* includes */ #include #include #include #include #include #include #include "raknet/RakClient.h" #include "raknet/RakServer.h" #include "raknet/PacketEnumerations.h" #include "raknet/GetTime.h" #include "NetworkState.h" #include "NetworkMessage.h" #include "TextManager.h" #include "ReplayRecorder.h" #include "DuelMatch.h" #include "IMGUI.h" #include "SoundManager.h" #include "LocalInputSource.h" #include "UserConfig.h" #include "FileExceptions.h" #include "GenericIO.h" #include "FileRead.h" #include "FileWrite.h" #include "MatchEvents.h" #include "SpeedController.h" #include "server/DedicatedServer.h" #include "LobbyState.h" #include "InputManager.h" /* implementation */ NetworkGameState::NetworkGameState( boost::shared_ptr client): GameState(new DuelMatch(true, DEFAULT_RULES_FILE)), mClient( client ), mWinningPlayer(NO_PLAYER), mNetworkState(WAITING_FOR_OPPONENT), mWaitingForReplay(false), mSelectedChatmessage(0), mChatCursorPosition(0), mChattext("") { boost::shared_ptr config = IUserConfigReader::createUserConfigReader("config.xml"); mOwnSide = (PlayerSide)config->getInteger("network_side"); mUseRemoteColor = config->getBool("use_remote_color"); mLocalInput.reset(new LocalInputSource(mOwnSide)); mLocalInput->setMatch(mMatch.get()); /// \todo why do we need this here? RenderManager::getSingleton().redraw(); // game is not started until two players are connected mMatch->pause(); // load/init players if(mOwnSide == LEFT_PLAYER) { PlayerIdentity localplayer = config->loadPlayerIdentity(LEFT_PLAYER, true); PlayerIdentity remoteplayer = config->loadPlayerIdentity(RIGHT_PLAYER, true); mLocalPlayer = &mMatch->getPlayer( LEFT_PLAYER ); mRemotePlayer = &mMatch->getPlayer( RIGHT_PLAYER ); mMatch->setPlayers( localplayer, remoteplayer ); } else { PlayerIdentity localplayer = config->loadPlayerIdentity(RIGHT_PLAYER, true); PlayerIdentity remoteplayer = config->loadPlayerIdentity(LEFT_PLAYER, true); mLocalPlayer = &mMatch->getPlayer( RIGHT_PLAYER ); mRemotePlayer = &mMatch->getPlayer( LEFT_PLAYER ); mMatch->setPlayers( remoteplayer, localplayer ); } mRemotePlayer->setName(""); } NetworkGameState::~NetworkGameState() { mClient->Disconnect(50); } void NetworkGameState::step_impl() { IMGUI& imgui = IMGUI::getSingleton(); RenderManager* rmanager = &RenderManager::getSingleton(); packet_ptr packet; while (packet = mClient->Receive()) { switch(packet->data[0]) { case ID_PHYSIC_UPDATE: { RakNet::BitStream stream((char*)packet->data, packet->length, false); int ival; stream.IgnoreBytes(1); //ID_PHYSIC_UPDATE stream.IgnoreBytes(1); //ID_TIMESTAMP stream.Read(ival); //TODO: un-lag based on timestamp delta //printf("Physic packet received. Time: %d\n", ival); DuelMatchState ms; boost::shared_ptr in = createGenericReader(&stream); in->generic (ms); mMatch->setState(ms); break; } case ID_WIN_NOTIFICATION: { RakNet::BitStream stream((char*)packet->data, packet->length, false); stream.IgnoreBytes(1); //ID_WIN_NOTIFICATION stream.Read((int&)mWinningPlayer); // last point must not be added anymore, because // the score is also simulated local so it is already // right. under strange circumstances this need not // be true, but then the score is set to the correy value // by ID_BALL_RESET mNetworkState = PLAYER_WON; break; } case ID_OPPONENT_DISCONNECTED: { // In this state, a leaving opponent would not be very surprising if (mNetworkState != PLAYER_WON) mNetworkState = OPPONENT_DISCONNECTED; break; } case ID_BALL_RESET: { PlayerSide servingPlayer; RakNet::BitStream stream((char*)packet->data, packet->length, false); stream.IgnoreBytes(1); //ID_BALL_RESET stream.Read((int&)servingPlayer); // read and set new score int nLeftScore; int nRightScore; int time; stream.Read(nLeftScore); stream.Read(nRightScore); stream.Read(time); mMatch->setScore(nLeftScore, nRightScore); mMatch->setServingPlayer(servingPlayer); // sync the clocks... normally, they should not differ mMatch->getClock().setTime(time); /// \attention /// we can get a problem here: /// assume the packet informing about the game event which lead to this /// either BALL_GROUND_COLLISION or BALL_PLAYER_COLLISION got stalled /// and arrives at the same time time as this packet. Then we get the following behaviour: /// we set the score to the right value... the event causing the score to happen gets processed /// -> that player scores -> score is off! /// /// i don't have a clean fix for this right now, so we'll have to live with a workaround for now /// we just order the game to reset all triggered events. mMatch->resetTriggeredEvents(); /// \todo a good fix would involve ensuring we process all events in the right order break; } case ID_COLLISION: { int event; float intensity; RakNet::BitStream stream((char*)packet->data, packet->length, false); stream.IgnoreBytes(1); //ID_COLLISION stream.Read(event); stream.Read(intensity); mMatch->setLastHitIntensity(intensity); mMatch->trigger( event ); break; } case ID_PAUSE: if (mNetworkState == PLAYING) { mNetworkState = PAUSING; mMatch->pause(); } break; case ID_UNPAUSE: if (mNetworkState == PAUSING) { SDL_StopTextInput(); mNetworkState = PLAYING; mMatch->unpause(); } break; case ID_GAME_READY: { char charName[16]; RakNet::BitStream stream((char*)packet->data, packet->length, false); stream.IgnoreBytes(1); // ignore ID_GAME_READY // read gamespeed int speed; stream.Read(speed); SpeedController::getMainInstance()->setGameSpeed(speed); // read playername stream.Read(charName, sizeof(charName)); // ensures that charName is null terminated charName[sizeof(charName)-1] = '\0'; // read colors int temp; stream.Read(temp); Color ncolor = temp; mRemotePlayer->setName(charName); setDefaultReplayName(mLocalPlayer->getName(), mRemotePlayer->getName()); // check whether to use remote player color if(mUseRemoteColor) { mRemotePlayer->setStaticColor(ncolor); RenderManager::getSingleton().redraw(); } // Workarround for SDL-Renderer // Hides the GUI when networkgame starts rmanager->redraw(); mNetworkState = PLAYING; // start game mMatch->unpause(); // game ready whistle SoundManager::getSingleton().playSound("sounds/pfiff.wav", ROUND_START_SOUND_VOLUME); break; } case ID_RULES_CHECKSUM: { RakNet::BitStream stream((char*)packet->data, packet->length, false); stream.IgnoreBytes(1); // ignore ID_RULES_CHECKSUM int serverChecksum; stream.Read(serverChecksum); int ourChecksum = 0; if (serverChecksum != 0) { try { FileRead rulesFile("server_rules.lua"); ourChecksum = rulesFile.calcChecksum(0); rulesFile.close(); } catch( FileLoadException& ex ) { // file doesn't exist - nothing to do here } } RakNet::BitStream stream2; stream2.Write((unsigned char)ID_RULES); stream2.Write(bool(serverChecksum != 0 && serverChecksum != ourChecksum)); mClient->Send(&stream2, HIGH_PRIORITY, RELIABLE_ORDERED, 0); break; } case ID_RULES: { RakNet::BitStream stream((char*)packet->data, packet->length, false); stream.IgnoreBytes(1); // ignore ID_RULES int rulesLength; stream.Read(rulesLength); if (rulesLength) { boost::shared_array rulesString( new char[rulesLength + 1] ); stream.Read(rulesString.get(), rulesLength); // null terminate rulesString[rulesLength] = 0; FileWrite rulesFile("server_rules.lua"); rulesFile.write(rulesString.get(), rulesLength); rulesFile.close(); mMatch->setRules("server_rules.lua"); } else { // either old server, or we have to use fallback ruleset mMatch->setRules( FALLBACK_RULES_NAME ); } break; } // status messages we don't care about case ID_REMOTE_DISCONNECTION_NOTIFICATION: case ID_REMOTE_CONNECTION_LOST: case ID_SERVER_STATUS: case ID_CHALLENGE: case ID_REMOTE_NEW_INCOMING_CONNECTION: case ID_REMOTE_EXISTING_CONNECTION: break; case ID_DISCONNECTION_NOTIFICATION: case ID_CONNECTION_LOST: if (mNetworkState != PLAYER_WON) mNetworkState = DISCONNECTED; break; case ID_NO_FREE_INCOMING_CONNECTIONS: mNetworkState = SERVER_FULL; break; case ID_CHAT_MESSAGE: { RakNet::BitStream stream((char*)packet->data, packet->length, false); stream.IgnoreBytes(1); // ID_CHAT_MESSAGE // Insert Message in the log and focus the last element char message[31]; stream.Read(message, sizeof(message)); message[30] = '\0'; // Insert Message in the log and focus the last element mChatlog.push_back((std::string) message); mChatOrigin.push_back(false); mSelectedChatmessage = mChatlog.size() - 1; SoundManager::getSingleton().playSound("sounds/chat.wav", ROUND_START_SOUND_VOLUME); break; } case ID_REPLAY: { /// \todo we should take more action if server sends replay /// even if not requested! if(!mWaitingForReplay) break; RakNet::BitStream stream = RakNet::BitStream((char*)packet->data, packet->length, false); stream.IgnoreBytes(1); // ID_REPLAY // read stream into a dummy replay recorder boost::shared_ptr reader = createGenericReader( &stream ); ReplayRecorder dummyRec; dummyRec.receive( reader ); // and save that saveReplay(dummyRec); // mWaitingForReplay will be set to false even if replay could not be saved because // the server won't send it again. mWaitingForReplay = false; break; } // we never do anything that should cause such a packet to be received! case ID_CONNECTION_REQUEST_ACCEPTED: case ID_CONNECTION_ATTEMPT_FAILED: assert( 0 ); break; case ID_BLOBBY_SERVER_PRESENT: { // this should only be called if we use the stay on server option RakNet::BitStream stream( packet->getStream() ); stream.IgnoreBytes(1); //ID_BLOBBY_SERVER_PRESENT ServerInfo info(stream, mClient->PlayerIDToDottedIP(packet->playerId), packet->playerId.port); if (packet->length == ServerInfo::BLOBBY_SERVER_PRESENT_PACKET_SIZE ) { switchState(new LobbyState(info)); } break; } default: printf("Received unknown Packet %d\n", packet->data[0]); std::cout<data<<"\n"; break; } } // does this generate any problems if we pause at the exact moment an event is set ( i.e. the ball hit sound // could be played in a loop)? presentGame(); presentGameUI(); if (InputManager::getSingleton()->exit() && mNetworkState != PLAYING) { if(mNetworkState == PAUSING) { // end pause RakNet::BitStream stream; stream.Write((unsigned char)ID_UNPAUSE); mClient->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0); } else { switchState(new MainMenuState); } } else if (InputManager::getSingleton()->exit() && mSaveReplay) { mSaveReplay = false; IMGUI::getSingleton().resetSelection(); } else if (mErrorMessage != "") { displayErrorMessageBox(); } else if (mSaveReplay) { if ( displaySaveReplayPrompt() ) { // request replay from server RakNet::BitStream stream; stream.Write((unsigned char)ID_REPLAY); mClient->Send(&stream, LOW_PRIORITY, RELIABLE_ORDERED, 0); mSaveReplay = false; mWaitingForReplay = true; } } else if (mWaitingForReplay) { imgui.doOverlay(GEN_ID, Vector2(150, 200), Vector2(650, 400)); imgui.doText(GEN_ID, Vector2(190, 220), TextManager::RP_WAIT_REPLAY); if (imgui.doButton(GEN_ID, Vector2(440, 330), TextManager::LBL_CANCEL)) { mSaveReplay = false; mWaitingForReplay = false; imgui.resetSelection(); } imgui.doCursor(); } else switch (mNetworkState) { case WAITING_FOR_OPPONENT: { imgui.doOverlay(GEN_ID, Vector2(100.0, 210.0), Vector2(700.0, 310.0)); imgui.doText(GEN_ID, Vector2(150.0, 250.0), TextManager::GAME_WAITING); break; } case OPPONENT_DISCONNECTED: { imgui.doCursor(); imgui.doOverlay(GEN_ID, Vector2(100.0, 210.0), Vector2(700.0, 390.0)); imgui.doText(GEN_ID, Vector2(140.0, 240.0), TextManager::GAME_OPP_LEFT); if (imgui.doButton(GEN_ID, Vector2(230.0, 290.0), TextManager::LBL_OK)) { switchState(new MainMenuState); } if (imgui.doButton(GEN_ID, Vector2(350.0, 290.0), TextManager::RP_SAVE)) { mSaveReplay = true; imgui.resetSelection(); } if (imgui.doButton(GEN_ID, Vector2(250.0, 340.0), TextManager::NET_STAY_ON_SERVER)) { // Send a blobby server connection request RakNet::BitStream stream; stream.Write((unsigned char)ID_BLOBBY_SERVER_PRESENT); stream.Write(BLOBBY_VERSION_MAJOR); stream.Write(BLOBBY_VERSION_MINOR); mClient->Send(&stream, LOW_PRIORITY, RELIABLE_ORDERED, 0); } break; } case DISCONNECTED: { imgui.doCursor(); imgui.doOverlay(GEN_ID, Vector2(100.0, 210.0), Vector2(700.0, 370.0)); imgui.doText(GEN_ID, Vector2(120.0, 250.0), TextManager::NET_DISCONNECT); if (imgui.doButton(GEN_ID, Vector2(230.0, 320.0), TextManager::LBL_OK)) { switchState(new MainMenuState); } if (imgui.doButton(GEN_ID, Vector2(350.0, 320.0), TextManager::RP_SAVE)) { mSaveReplay = true; imgui.resetSelection(); } break; } case SERVER_FULL: { imgui.doCursor(); imgui.doOverlay(GEN_ID, Vector2(100.0, 210.0),Vector2(700.0, 370.0)); imgui.doText(GEN_ID, Vector2(200.0, 250.0), TextManager::NET_SERVER_FULL); if (imgui.doButton(GEN_ID, Vector2(350.0, 300.0), TextManager::LBL_OK)) { switchState(new MainMenuState); } break; } case PLAYING: { mMatch->step(); mLocalInput->updateInput(); PlayerInputAbs input = mLocalInput->getRealInput(); if (InputManager::getSingleton()->exit()) { RakNet::BitStream stream; stream.Write((unsigned char)ID_PAUSE); mClient->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0); } RakNet::BitStream stream; stream.Write((unsigned char)ID_INPUT_UPDATE); stream.Write((unsigned char)ID_TIMESTAMP); ///! \todo do we really need this time stamps? stream.Write(RakNet::GetTime()); input.writeTo(stream); mClient->Send(&stream, HIGH_PRIORITY, UNRELIABLE_SEQUENCED, 0); break; } case PLAYER_WON: { displayWinningPlayerScreen(mWinningPlayer); if (imgui.doButton(GEN_ID, Vector2(290, 360), TextManager::LBL_OK)) { switchState(new MainMenuState()); } if (imgui.doButton(GEN_ID, Vector2(380, 360), TextManager::RP_SAVE)) { mSaveReplay = true; imgui.resetSelection(); } break; } case PAUSING: { imgui.doOverlay(GEN_ID, Vector2(175, 20), Vector2(625, 175)); imgui.doText(GEN_ID, Vector2(275, 35), TextManager::GAME_PAUSED); if (imgui.doButton(GEN_ID, Vector2(205, 95), TextManager::LBL_CONTINUE)) { RakNet::BitStream stream; stream.Write((unsigned char)ID_UNPAUSE); mClient->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0); } // Chat imgui.doChatbox(GEN_ID, Vector2(10, 190), Vector2(790, 450), mChatlog, mSelectedChatmessage, mChatOrigin); if (imgui.doEditbox(GEN_ID, Vector2(30, 460), 30, mChattext, mChatCursorPosition, 0, true)) { // GUI-Hack, so that we can send messages if ((InputManager::getSingleton()->getLastActionKey() == "Return") && (mChattext != "")) { RakNet::BitStream stream; char message[31]; strncpy(message, mChattext.c_str(), sizeof(message)); stream.Write((unsigned char)ID_CHAT_MESSAGE); stream.Write(message, sizeof(message)); mClient->Send(&stream, LOW_PRIORITY, RELIABLE_ORDERED, 0); mChatlog.push_back(mChattext); mChatOrigin.push_back(true); mSelectedChatmessage = mChatlog.size() - 1; mChattext = ""; mChatCursorPosition = 0; SoundManager::getSingleton().playSound("sounds/chat.wav", ROUND_START_SOUND_VOLUME); } } if (imgui.doButton(GEN_ID, Vector2(500, 95), TextManager::GAME_QUIT)) { switchState(new MainMenuState); } if (imgui.doButton(GEN_ID, Vector2(285, 125), TextManager::RP_SAVE)) { mSaveReplay = true; imgui.resetSelection(); } imgui.doCursor(); } } } const char* NetworkGameState::getStateName() const { return "NetworkGameState"; } // --------------------------------------------------------------------------------------------------------------------------------- // implementation of the local host state // ---------------------------------------- NetworkHostState::NetworkHostState() : mServer( ), mClient( new RakClient ), mGameState(nullptr) { // read config /// \todo we need read-only access here! UserConfig config; config.loadFile("config.xml"); PlayerSide localSide = (PlayerSide)config.getInteger("network_side"); // load/init players if(localSide == LEFT_PLAYER) { mLocalPlayer = config.loadPlayerIdentity(LEFT_PLAYER, true); } else { mLocalPlayer = config.loadPlayerIdentity(RIGHT_PLAYER, true); } ServerInfo info( mLocalPlayer.getName().c_str()); std::string rulesfile = config.getString("rules"); mServer.reset( new DedicatedServer(info, rulesfile, 4)); // connect to server if (!mClient->Connect(info.hostname, info.port, 0, 0, RAKNET_THREAD_SLEEP_TIME)) throw( std::runtime_error(std::string("Could not connect to server ") + info.hostname) ); } NetworkHostState::~NetworkHostState() { delete mGameState; } void NetworkHostState::step_impl() { packet_ptr packet; if( mGameState == nullptr ) { while (packet = mClient->Receive()) { switch(packet->data[0]) { // as soon as we are connected to the server case ID_CONNECTION_REQUEST_ACCEPTED: { // ---------------------------------------------------- // Send ENTER SERVER packet RakNet::BitStream stream; stream.Write((unsigned char)ID_ENTER_SERVER); // Send preferred side stream.Write( mLocalPlayer.getPreferredSide() ); // Send playername char myname[16]; strncpy(myname, mLocalPlayer.getName().c_str(), sizeof(myname)); stream.Write(myname, sizeof(myname)); // send color settings stream.Write(mLocalPlayer.getStaticColor().toInt()); mClient->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0); // Send ENTER GAME packet RakNet::BitStream stream2; stream2.Write((char)ID_CHALLENGE); auto writer = createGenericWriter(&stream2); writer->generic( UNASSIGNED_PLAYER_ID ); mClient->Send(&stream2, HIGH_PRIORITY, RELIABLE_ORDERED, 0); mGameState = new NetworkGameState(mClient); break; } case ID_SERVER_STATUS: { } break; default: std::cout << "Unknown packet " << int(packet->data[0]) << " received\n"; } } } if(mServer->hasActiveGame()) { mServer->allowNewPlayers(false); } mServer->processPackets(); /// \todo make this gamespeed independent mLobbyCounter++; if(mLobbyCounter % (750 /*10s*/) == 0 ) { mServer->updateLobby(); } mServer->updateGames(); if( mGameState ) mGameState->step_impl(); } const char* NetworkHostState::getStateName() const { return "NetworkHostState"; } // definition of syslog for client hosted games void syslog(int pri, const char* format, ...) { // do nothing? } // debug counters int SWLS_PacketCount; int SWLS_Connections; int SWLS_Games; int SWLS_GameSteps; int SWLS_ServerEntered; blobby-1.0/src/GenericIODetail.h000644 001750 001750 00000012510 12313310253 021272 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "GenericIOFwd.h" #include #include #include "Global.h" struct PlayerInput; struct Color; struct DuelMatchState; struct PlayerID; namespace detail { // this class indicates the GenericIO is an input handler struct READER_TAG{}; // this class indicates the GenericIO is an output handler struct WRITER_TAG{}; // helper class to make parameter types /* \class conster helper class for parameter types. Zhis class is used to adapt the parameters of the read/write methods, making them const references for writing and reference for reading. The partial specialisations ensure that behaviour. */ template struct conster { }; // partial specialisations which generate the conster logic template struct conster { typedef T& type; }; template struct conster { typedef T* type; }; template struct conster { typedef const T& type; }; template struct conster { typedef const T* type; }; // helper classes to determine which io algorithm to use for which type // if any template specialisation of this class inherits from boost::true_type, // this means that the io algorithm uses a predifined_serializer. template struct has_default_io_implementation : public boost::false_type { }; // specialisations for default types template<> struct has_default_io_implementation : public boost::true_type { }; template<> struct has_default_io_implementation : public boost::true_type { }; template<> struct has_default_io_implementation : public boost::true_type { }; template<> struct has_default_io_implementation : public boost::true_type { }; template<> struct has_default_io_implementation : public boost::true_type { }; template<> struct has_default_io_implementation : public boost::true_type { }; template<> struct has_default_io_implementation : public boost::true_type { }; template<> struct has_default_io_implementation : public boost::true_type { }; template<> struct has_default_io_implementation : public boost::true_type { }; // this class uses SFINAE to determine whether a type can be used as a container type, i.e. // provided the methods size and begin template struct is_container_type { typedef char yes[1]; typedef char no[2]; template static yes& test_size( int arg = (C()).size()); template static no& test_size(...); template static yes& test_begin( typename C::iterator* it = &(C()).begin()); template static no& test_begin(...); // this is only true if size and begin functions exist. static const bool value = sizeof(test_size(0)) == sizeof(yes) && sizeof(test_begin(0)) == sizeof(yes); }; /*! \class serialize_dispatch \brief manages which generic implementation is used to serialize certain types \details uses partial specialisation with the parameters init and container. init has to be boost::true_type or boost::false_type. */ template struct serialize_dispatch; template struct predifined_serializer { static void serialize( GenericOut& out, const T& c); static void serialize( GenericIn& in, T& c); }; // inserts the methods from predefined_serializer, which are forward declared and // implemented in GenericIO.cpp. This happens when init is true_type template struct serialize_dispatch : public predifined_serializer { }; // uses a UserSerializer // the user has to implement the UserSerializer::serialize(GenericOut, const T&) and UserSerializer::serialize(GenericIn, T&) // somewhere, otherwise a link error happens. // User serializers are used when there is no default implementation and the type does not provide a container // interface. template struct serialize_dispatch : public UserSerializer { }; } blobby-1.0/src/lua/lua.c000644 001750 001750 00000033275 12313310253 017713 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lua.c,v 1.206.1.1 2013/04/12 18:48:47 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ #include #include #include #include #define lua_c #include "lua.h" #include "lauxlib.h" #include "lualib.h" #if !defined(LUA_PROMPT) #define LUA_PROMPT "> " #define LUA_PROMPT2 ">> " #endif #if !defined(LUA_PROGNAME) #define LUA_PROGNAME "lua" #endif #if !defined(LUA_MAXINPUT) #define LUA_MAXINPUT 512 #endif #if !defined(LUA_INIT) #define LUA_INIT "LUA_INIT" #endif #define LUA_INITVERSION \ LUA_INIT "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR /* ** lua_stdin_is_tty detects whether the standard input is a 'tty' (that ** is, whether we're running lua interactively). */ #if defined(LUA_USE_ISATTY) #include #define lua_stdin_is_tty() isatty(0) #elif defined(LUA_WIN) #include #include #define lua_stdin_is_tty() _isatty(_fileno(stdin)) #else #define lua_stdin_is_tty() 1 /* assume stdin is a tty */ #endif /* ** lua_readline defines how to show a prompt and then read a line from ** the standard input. ** lua_saveline defines how to "save" a read line in a "history". ** lua_freeline defines how to free a line read by lua_readline. */ #if defined(LUA_USE_READLINE) #include #include #include #define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) #define lua_saveline(L,idx) \ if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \ add_history(lua_tostring(L, idx)); /* add it to history */ #define lua_freeline(L,b) ((void)L, free(b)) #elif !defined(lua_readline) #define lua_readline(L,b,p) \ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ #define lua_saveline(L,idx) { (void)L; (void)idx; } #define lua_freeline(L,b) { (void)L; (void)b; } #endif static lua_State *globalL = NULL; static const char *progname = LUA_PROGNAME; static void lstop (lua_State *L, lua_Debug *ar) { (void)ar; /* unused arg. */ lua_sethook(L, NULL, 0, 0); luaL_error(L, "interrupted!"); } static void laction (int i) { signal(i, SIG_DFL); /* if another SIGINT happens before lstop, terminate process (default action) */ lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } static void print_usage (const char *badoption) { luai_writestringerror("%s: ", progname); if (badoption[1] == 'e' || badoption[1] == 'l') luai_writestringerror("'%s' needs argument\n", badoption); else luai_writestringerror("unrecognized option '%s'\n", badoption); luai_writestringerror( "usage: %s [options] [script [args]]\n" "Available options are:\n" " -e stat execute string " LUA_QL("stat") "\n" " -i enter interactive mode after executing " LUA_QL("script") "\n" " -l name require library " LUA_QL("name") "\n" " -v show version information\n" " -E ignore environment variables\n" " -- stop handling options\n" " - stop handling options and execute stdin\n" , progname); } static void l_message (const char *pname, const char *msg) { if (pname) luai_writestringerror("%s: ", pname); luai_writestringerror("%s\n", msg); } static int report (lua_State *L, int status) { if (status != LUA_OK && !lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); lua_pop(L, 1); /* force a complete garbage collection in case of errors */ lua_gc(L, LUA_GCCOLLECT, 0); } return status; } /* the next function is called unprotected, so it must avoid errors */ static void finalreport (lua_State *L, int status) { if (status != LUA_OK) { const char *msg = (lua_type(L, -1) == LUA_TSTRING) ? lua_tostring(L, -1) : NULL; if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); lua_pop(L, 1); } } static int traceback (lua_State *L) { const char *msg = lua_tostring(L, 1); if (msg) luaL_traceback(L, L, msg, 1); else if (!lua_isnoneornil(L, 1)) { /* is there an error object? */ if (!luaL_callmeta(L, 1, "__tostring")) /* try its 'tostring' metamethod */ lua_pushliteral(L, "(no error message)"); } return 1; } static int docall (lua_State *L, int narg, int nres) { int status; int base = lua_gettop(L) - narg; /* function index */ lua_pushcfunction(L, traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ globalL = L; /* to be available to 'laction' */ signal(SIGINT, laction); status = lua_pcall(L, narg, nres, base); signal(SIGINT, SIG_DFL); lua_remove(L, base); /* remove traceback function */ return status; } static void print_version (void) { luai_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); luai_writeline(); } static int getargs (lua_State *L, char **argv, int n) { int narg; int i; int argc = 0; while (argv[argc]) argc++; /* count total number of arguments */ narg = argc - (n + 1); /* number of arguments to the script */ luaL_checkstack(L, narg + 3, "too many arguments to script"); for (i=n+1; i < argc; i++) lua_pushstring(L, argv[i]); lua_createtable(L, narg, n + 1); for (i=0; i < argc; i++) { lua_pushstring(L, argv[i]); lua_rawseti(L, -2, i - n); } return narg; } static int dofile (lua_State *L, const char *name) { int status = luaL_loadfile(L, name); if (status == LUA_OK) status = docall(L, 0, 0); return report(L, status); } static int dostring (lua_State *L, const char *s, const char *name) { int status = luaL_loadbuffer(L, s, strlen(s), name); if (status == LUA_OK) status = docall(L, 0, 0); return report(L, status); } static int dolibrary (lua_State *L, const char *name) { int status; lua_getglobal(L, "require"); lua_pushstring(L, name); status = docall(L, 1, 1); /* call 'require(name)' */ if (status == LUA_OK) lua_setglobal(L, name); /* global[name] = require return */ return report(L, status); } static const char *get_prompt (lua_State *L, int firstline) { const char *p; lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); return p; } /* mark in error messages for incomplete statements */ #define EOFMARK "" #define marklen (sizeof(EOFMARK)/sizeof(char) - 1) static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) { lua_pop(L, 1); return 1; } } return 0; /* else... */ } static int pushline (lua_State *L, int firstline) { char buffer[LUA_MAXINPUT]; char *b = buffer; size_t l; const char *prmt = get_prompt(L, firstline); int readstatus = lua_readline(L, b, prmt); lua_pop(L, 1); /* remove result from 'get_prompt' */ if (readstatus == 0) return 0; /* no input */ l = strlen(b); if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ b[l-1] = '\0'; /* remove it */ if (firstline && b[0] == '=') /* first line starts with `=' ? */ lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ else lua_pushstring(L, b); lua_freeline(L, b); return 1; } static int loadline (lua_State *L) { int status; lua_settop(L, 0); if (!pushline(L, 1)) return -1; /* no input */ for (;;) { /* repeat until gets a complete line */ size_t l; const char *line = lua_tolstring(L, 1, &l); status = luaL_loadbuffer(L, line, l, "=stdin"); if (!incomplete(L, status)) break; /* cannot try to add lines? */ if (!pushline(L, 0)) /* no more input? */ return -1; lua_pushliteral(L, "\n"); /* add a new line... */ lua_insert(L, -2); /* ...between the two lines */ lua_concat(L, 3); /* join them */ } lua_saveline(L, 1); lua_remove(L, 1); /* remove line */ return status; } static void dotty (lua_State *L) { int status; const char *oldprogname = progname; progname = NULL; while ((status = loadline(L)) != -1) { if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET); report(L, status); if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */ luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); lua_getglobal(L, "print"); lua_insert(L, 1); if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != LUA_OK) l_message(progname, lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)", lua_tostring(L, -1))); } } lua_settop(L, 0); /* clear stack */ luai_writeline(); progname = oldprogname; } static int handle_script (lua_State *L, char **argv, int n) { int status; const char *fname; int narg = getargs(L, argv, n); /* collect arguments */ lua_setglobal(L, "arg"); fname = argv[n]; if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) fname = NULL; /* stdin */ status = luaL_loadfile(L, fname); lua_insert(L, -(narg+1)); if (status == LUA_OK) status = docall(L, narg, LUA_MULTRET); else lua_pop(L, narg); return report(L, status); } /* check that argument has no extra characters at the end */ #define noextrachars(x) {if ((x)[2] != '\0') return -1;} /* indices of various argument indicators in array args */ #define has_i 0 /* -i */ #define has_v 1 /* -v */ #define has_e 2 /* -e */ #define has_E 3 /* -E */ #define num_has 4 /* number of 'has_*' */ static int collectargs (char **argv, int *args) { int i; for (i = 1; argv[i] != NULL; i++) { if (argv[i][0] != '-') /* not an option? */ return i; switch (argv[i][1]) { /* option */ case '-': noextrachars(argv[i]); return (argv[i+1] != NULL ? i+1 : 0); case '\0': return i; case 'E': args[has_E] = 1; break; case 'i': noextrachars(argv[i]); args[has_i] = 1; /* go through */ case 'v': noextrachars(argv[i]); args[has_v] = 1; break; case 'e': args[has_e] = 1; /* go through */ case 'l': /* both options need an argument */ if (argv[i][2] == '\0') { /* no concatenated argument? */ i++; /* try next 'argv' */ if (argv[i] == NULL || argv[i][0] == '-') return -(i - 1); /* no next argument or it is another option */ } break; default: /* invalid option; return its index... */ return -i; /* ...as a negative value */ } } return 0; } static int runargs (lua_State *L, char **argv, int n) { int i; for (i = 1; i < n; i++) { lua_assert(argv[i][0] == '-'); switch (argv[i][1]) { /* option */ case 'e': { const char *chunk = argv[i] + 2; if (*chunk == '\0') chunk = argv[++i]; lua_assert(chunk != NULL); if (dostring(L, chunk, "=(command line)") != LUA_OK) return 0; break; } case 'l': { const char *filename = argv[i] + 2; if (*filename == '\0') filename = argv[++i]; lua_assert(filename != NULL); if (dolibrary(L, filename) != LUA_OK) return 0; /* stop if file fails */ break; } default: break; } } return 1; } static int handle_luainit (lua_State *L) { const char *name = "=" LUA_INITVERSION; const char *init = getenv(name + 1); if (init == NULL) { name = "=" LUA_INIT; init = getenv(name + 1); /* try alternative name */ } if (init == NULL) return LUA_OK; else if (init[0] == '@') return dofile(L, init+1); else return dostring(L, init, name); } static int pmain (lua_State *L) { int argc = (int)lua_tointeger(L, 1); char **argv = (char **)lua_touserdata(L, 2); int script; int args[num_has]; args[has_i] = args[has_v] = args[has_e] = args[has_E] = 0; if (argv[0] && argv[0][0]) progname = argv[0]; script = collectargs(argv, args); if (script < 0) { /* invalid arg? */ print_usage(argv[-script]); return 0; } if (args[has_v]) print_version(); if (args[has_E]) { /* option '-E'? */ lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); } /* open standard libraries */ luaL_checkversion(L); lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ luaL_openlibs(L); /* open libraries */ lua_gc(L, LUA_GCRESTART, 0); if (!args[has_E] && handle_luainit(L) != LUA_OK) return 0; /* error running LUA_INIT */ /* execute arguments -e and -l */ if (!runargs(L, argv, (script > 0) ? script : argc)) return 0; /* execute main script (if there is one) */ if (script && handle_script(L, argv, script) != LUA_OK) return 0; if (args[has_i]) /* -i option? */ dotty(L); else if (script == 0 && !args[has_e] && !args[has_v]) { /* no arguments? */ if (lua_stdin_is_tty()) { print_version(); dotty(L); } else dofile(L, NULL); /* executes stdin as a file */ } lua_pushboolean(L, 1); /* signal no errors */ return 1; } int main (int argc, char **argv) { int status, result; lua_State *L = luaL_newstate(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; } /* call 'pmain' in protected mode */ lua_pushcfunction(L, &pmain); lua_pushinteger(L, argc); /* 1st argument */ lua_pushlightuserdata(L, argv); /* 2nd argument */ status = lua_pcall(L, 2, 1, 0); result = lua_toboolean(L, -1); /* get result */ finalreport(L, status); lua_close(L); return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; } blobby-1.0/src/raknet/GetTime.h000644 001750 001750 00000003566 12313310247 021203 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file GetTime.h * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __GET_TIME_H #define __GET_TIME_H namespace RakNet { /** * This function return the current time * @return The number of seconds from 1970 january the 1st. */ unsigned int GetTime( void ); } #endif blobby-1.0/src/lua/lobject.h000644 001750 001750 00000035141 12313310253 020553 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lobject.h,v 2.71.1.1 2013/04/12 18:48:47 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ #ifndef lobject_h #define lobject_h #include #include "llimits.h" #include "lua.h" /* ** Extra tags for non-values */ #define LUA_TPROTO LUA_NUMTAGS #define LUA_TUPVAL (LUA_NUMTAGS+1) #define LUA_TDEADKEY (LUA_NUMTAGS+2) /* ** number of all possible tags (including LUA_TNONE but excluding DEADKEY) */ #define LUA_TOTALTAGS (LUA_TUPVAL+2) /* ** tags for Tagged Values have the following use of bits: ** bits 0-3: actual tag (a LUA_T* value) ** bits 4-5: variant bits ** bit 6: whether value is collectable */ #define VARBITS (3 << 4) /* ** LUA_TFUNCTION variants: ** 0 - Lua function ** 1 - light C function ** 2 - regular C function (closure) */ /* Variant tags for functions */ #define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) /* Lua closure */ #define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) /* light C function */ #define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */ /* Variant tags for strings */ #define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ #define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ /* Bit mark for collectable types */ #define BIT_ISCOLLECTABLE (1 << 6) /* mark a tag as collectable */ #define ctb(t) ((t) | BIT_ISCOLLECTABLE) /* ** Union of all collectable objects */ typedef union GCObject GCObject; /* ** Common Header for all collectable objects (in macro form, to be ** included in other objects) */ #define CommonHeader GCObject *next; lu_byte tt; lu_byte marked /* ** Common header in struct form */ typedef struct GCheader { CommonHeader; } GCheader; /* ** Union of all Lua values */ typedef union Value Value; #define numfield lua_Number n; /* numbers */ /* ** Tagged Values. This is the basic representation of values in Lua, ** an actual value plus a tag with its type. */ #define TValuefields Value value_; int tt_ typedef struct lua_TValue TValue; /* macro defining a nil value */ #define NILCONSTANT {NULL}, LUA_TNIL #define val_(o) ((o)->value_) #define num_(o) (val_(o).n) /* raw type tag of a TValue */ #define rttype(o) ((o)->tt_) /* tag with no variants (bits 0-3) */ #define novariant(x) ((x) & 0x0F) /* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ #define ttype(o) (rttype(o) & 0x3F) /* type tag of a TValue with no variants (bits 0-3) */ #define ttypenv(o) (novariant(rttype(o))) /* Macros to test type */ #define checktag(o,t) (rttype(o) == (t)) #define checktype(o,t) (ttypenv(o) == (t)) #define ttisnumber(o) checktag((o), LUA_TNUMBER) #define ttisnil(o) checktag((o), LUA_TNIL) #define ttisboolean(o) checktag((o), LUA_TBOOLEAN) #define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA) #define ttisstring(o) checktype((o), LUA_TSTRING) #define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR)) #define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR)) #define ttistable(o) checktag((o), ctb(LUA_TTABLE)) #define ttisfunction(o) checktype(o, LUA_TFUNCTION) #define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION) #define ttisCclosure(o) checktag((o), ctb(LUA_TCCL)) #define ttisLclosure(o) checktag((o), ctb(LUA_TLCL)) #define ttislcf(o) checktag((o), LUA_TLCF) #define ttisuserdata(o) checktag((o), ctb(LUA_TUSERDATA)) #define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) #define ttisdeadkey(o) checktag((o), LUA_TDEADKEY) #define ttisequal(o1,o2) (rttype(o1) == rttype(o2)) /* Macros to access values */ #define nvalue(o) check_exp(ttisnumber(o), num_(o)) #define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) #define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) #define rawtsvalue(o) check_exp(ttisstring(o), &val_(o).gc->ts) #define tsvalue(o) (&rawtsvalue(o)->tsv) #define rawuvalue(o) check_exp(ttisuserdata(o), &val_(o).gc->u) #define uvalue(o) (&rawuvalue(o)->uv) #define clvalue(o) check_exp(ttisclosure(o), &val_(o).gc->cl) #define clLvalue(o) check_exp(ttisLclosure(o), &val_(o).gc->cl.l) #define clCvalue(o) check_exp(ttisCclosure(o), &val_(o).gc->cl.c) #define fvalue(o) check_exp(ttislcf(o), val_(o).f) #define hvalue(o) check_exp(ttistable(o), &val_(o).gc->h) #define bvalue(o) check_exp(ttisboolean(o), val_(o).b) #define thvalue(o) check_exp(ttisthread(o), &val_(o).gc->th) /* a dead value may get the 'gc' field, but cannot access its contents */ #define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc)) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) #define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) /* Macros for internal tests */ #define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) #define checkliveness(g,obj) \ lua_longassert(!iscollectable(obj) || \ (righttt(obj) && !isdead(g,gcvalue(obj)))) /* Macros to set values */ #define settt_(o,t) ((o)->tt_=(t)) #define setnvalue(obj,x) \ { TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); } #define setnilvalue(obj) settt_(obj, LUA_TNIL) #define setfvalue(obj,x) \ { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); } #define setpvalue(obj,x) \ { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); } #define setbvalue(obj,x) \ { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); } #define setgcovalue(L,obj,x) \ { TValue *io=(obj); GCObject *i_g=(x); \ val_(io).gc=i_g; settt_(io, ctb(gch(i_g)->tt)); } #define setsvalue(L,obj,x) \ { TValue *io=(obj); \ TString *x_ = (x); \ val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \ checkliveness(G(L),io); } #define setuvalue(L,obj,x) \ { TValue *io=(obj); \ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TUSERDATA)); \ checkliveness(G(L),io); } #define setthvalue(L,obj,x) \ { TValue *io=(obj); \ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTHREAD)); \ checkliveness(G(L),io); } #define setclLvalue(L,obj,x) \ { TValue *io=(obj); \ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TLCL)); \ checkliveness(G(L),io); } #define setclCvalue(L,obj,x) \ { TValue *io=(obj); \ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TCCL)); \ checkliveness(G(L),io); } #define sethvalue(L,obj,x) \ { TValue *io=(obj); \ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \ checkliveness(G(L),io); } #define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) #define setobj(L,obj1,obj2) \ { const TValue *io2=(obj2); TValue *io1=(obj1); \ io1->value_ = io2->value_; io1->tt_ = io2->tt_; \ checkliveness(G(L),io1); } /* ** different types of assignments, according to destination */ /* from stack to (same) stack */ #define setobjs2s setobj /* to stack (not from same stack) */ #define setobj2s setobj #define setsvalue2s setsvalue #define sethvalue2s sethvalue #define setptvalue2s setptvalue /* from table to same table */ #define setobjt2t setobj /* to table */ #define setobj2t setobj /* to new object */ #define setobj2n setobj #define setsvalue2n setsvalue /* check whether a number is valid (useful only for NaN trick) */ #define luai_checknum(L,o,c) { /* empty */ } /* ** {====================================================== ** NaN Trick ** ======================================================= */ #if defined(LUA_NANTRICK) /* ** numbers are represented in the 'd_' field. All other values have the ** value (NNMARK | tag) in 'tt__'. A number with such pattern would be ** a "signaled NaN", which is never generated by regular operations by ** the CPU (nor by 'strtod') */ /* allows for external implementation for part of the trick */ #if !defined(NNMARK) /* { */ #if !defined(LUA_IEEEENDIAN) #error option 'LUA_NANTRICK' needs 'LUA_IEEEENDIAN' #endif #define NNMARK 0x7FF7A500 #define NNMASK 0x7FFFFF00 #undef TValuefields #undef NILCONSTANT #if (LUA_IEEEENDIAN == 0) /* { */ /* little endian */ #define TValuefields \ union { struct { Value v__; int tt__; } i; double d__; } u #define NILCONSTANT {{{NULL}, tag2tt(LUA_TNIL)}} /* field-access macros */ #define v_(o) ((o)->u.i.v__) #define d_(o) ((o)->u.d__) #define tt_(o) ((o)->u.i.tt__) #else /* }{ */ /* big endian */ #define TValuefields \ union { struct { int tt__; Value v__; } i; double d__; } u #define NILCONSTANT {{tag2tt(LUA_TNIL), {NULL}}} /* field-access macros */ #define v_(o) ((o)->u.i.v__) #define d_(o) ((o)->u.d__) #define tt_(o) ((o)->u.i.tt__) #endif /* } */ #endif /* } */ /* correspondence with standard representation */ #undef val_ #define val_(o) v_(o) #undef num_ #define num_(o) d_(o) #undef numfield #define numfield /* no such field; numbers are the entire struct */ /* basic check to distinguish numbers from non-numbers */ #undef ttisnumber #define ttisnumber(o) ((tt_(o) & NNMASK) != NNMARK) #define tag2tt(t) (NNMARK | (t)) #undef rttype #define rttype(o) (ttisnumber(o) ? LUA_TNUMBER : tt_(o) & 0xff) #undef settt_ #define settt_(o,t) (tt_(o) = tag2tt(t)) #undef setnvalue #define setnvalue(obj,x) \ { TValue *io_=(obj); num_(io_)=(x); lua_assert(ttisnumber(io_)); } #undef setobj #define setobj(L,obj1,obj2) \ { const TValue *o2_=(obj2); TValue *o1_=(obj1); \ o1_->u = o2_->u; \ checkliveness(G(L),o1_); } /* ** these redefinitions are not mandatory, but these forms are more efficient */ #undef checktag #undef checktype #define checktag(o,t) (tt_(o) == tag2tt(t)) #define checktype(o,t) (ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS)) #undef ttisequal #define ttisequal(o1,o2) \ (ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2))) #undef luai_checknum #define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; } #endif /* }====================================================== */ /* ** {====================================================== ** types and prototypes ** ======================================================= */ union Value { GCObject *gc; /* collectable objects */ void *p; /* light userdata */ int b; /* booleans */ lua_CFunction f; /* light C functions */ numfield /* numbers */ }; struct lua_TValue { TValuefields; }; typedef TValue *StkId; /* index to stack elements */ /* ** Header for string value; string bytes follow the end of this structure */ typedef union TString { L_Umaxalign dummy; /* ensures maximum alignment for strings */ struct { CommonHeader; lu_byte extra; /* reserved words for short strings; "has hash" for longs */ unsigned int hash; size_t len; /* number of characters in string */ } tsv; } TString; /* get the actual string (array of bytes) from a TString */ #define getstr(ts) cast(const char *, (ts) + 1) /* get the actual string (array of bytes) from a Lua value */ #define svalue(o) getstr(rawtsvalue(o)) /* ** Header for userdata; memory area follows the end of this structure */ typedef union Udata { L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ struct { CommonHeader; struct Table *metatable; struct Table *env; size_t len; /* number of bytes */ } uv; } Udata; /* ** Description of an upvalue for function prototypes */ typedef struct Upvaldesc { TString *name; /* upvalue name (for debug information) */ lu_byte instack; /* whether it is in stack */ lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ } Upvaldesc; /* ** Description of a local variable for function prototypes ** (used for debug information) */ typedef struct LocVar { TString *varname; int startpc; /* first point where variable is active */ int endpc; /* first point where variable is dead */ } LocVar; /* ** Function Prototypes */ typedef struct Proto { CommonHeader; TValue *k; /* constants used by the function */ Instruction *code; struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines (debug information) */ LocVar *locvars; /* information about local variables (debug information) */ Upvaldesc *upvalues; /* upvalue information */ union Closure *cache; /* last created closure with this prototype */ TString *source; /* used for debug information */ int sizeupvalues; /* size of 'upvalues' */ int sizek; /* size of `k' */ int sizecode; int sizelineinfo; int sizep; /* size of `p' */ int sizelocvars; int linedefined; int lastlinedefined; GCObject *gclist; lu_byte numparams; /* number of fixed parameters */ lu_byte is_vararg; lu_byte maxstacksize; /* maximum stack used by this function */ } Proto; /* ** Lua Upvalues */ typedef struct UpVal { CommonHeader; TValue *v; /* points to stack or to its own value */ union { TValue value; /* the value (when closed) */ struct { /* double linked list (when open) */ struct UpVal *prev; struct UpVal *next; } l; } u; } UpVal; /* ** Closures */ #define ClosureHeader \ CommonHeader; lu_byte nupvalues; GCObject *gclist typedef struct CClosure { ClosureHeader; lua_CFunction f; TValue upvalue[1]; /* list of upvalues */ } CClosure; typedef struct LClosure { ClosureHeader; struct Proto *p; UpVal *upvals[1]; /* list of upvalues */ } LClosure; typedef union Closure { CClosure c; LClosure l; } Closure; #define isLfunction(o) ttisLclosure(o) #define getproto(o) (clLvalue(o)->p) /* ** Tables */ typedef union TKey { struct { TValuefields; struct Node *next; /* for chaining */ } nk; TValue tvk; } TKey; typedef struct Node { TValue i_val; TKey i_key; } Node; typedef struct Table { CommonHeader; lu_byte flags; /* 1<

lsizenode)) /* ** (address of) a fixed nil value */ #define luaO_nilobject (&luaO_nilobject_) LUAI_DDEC const TValue luaO_nilobject_; LUAI_FUNC int luaO_int2fb (unsigned int x); LUAI_FUNC int luaO_fb2int (int x); LUAI_FUNC int luaO_ceillog2 (unsigned int x); LUAI_FUNC lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2); LUAI_FUNC int luaO_str2d (const char *s, size_t len, lua_Number *result); LUAI_FUNC int luaO_hexavalue (int c); LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp); LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); #endif blobby-1.0/src/blobnet/exception/000755 001750 001750 00000000000 12313310251 021614 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/lua/lobject.c000644 001750 001750 00000017341 12313310253 020550 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lobject.c,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ #include #include #include #include #define lobject_c #define LUA_CORE #include "lua.h" #include "lctype.h" #include "ldebug.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "lvm.h" LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; /* ** converts an integer to a "floating point byte", represented as ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if ** eeeee != 0 and (xxx) otherwise. */ int luaO_int2fb (unsigned int x) { int e = 0; /* exponent */ if (x < 8) return x; while (x >= 0x10) { x = (x+1) >> 1; e++; } return ((e+1) << 3) | (cast_int(x) - 8); } /* converts back */ int luaO_fb2int (int x) { int e = (x >> 3) & 0x1f; if (e == 0) return x; else return ((x & 7) + 8) << (e - 1); } int luaO_ceillog2 (unsigned int x) { static const lu_byte log_2[256] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }; int l = 0; x--; while (x >= 256) { l += 8; x >>= 8; } return l + log_2[x]; } lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { switch (op) { case LUA_OPADD: return luai_numadd(NULL, v1, v2); case LUA_OPSUB: return luai_numsub(NULL, v1, v2); case LUA_OPMUL: return luai_nummul(NULL, v1, v2); case LUA_OPDIV: return luai_numdiv(NULL, v1, v2); case LUA_OPMOD: return luai_nummod(NULL, v1, v2); case LUA_OPPOW: return luai_numpow(NULL, v1, v2); case LUA_OPUNM: return luai_numunm(NULL, v1); default: lua_assert(0); return 0; } } int luaO_hexavalue (int c) { if (lisdigit(c)) return c - '0'; else return ltolower(c) - 'a' + 10; } #if !defined(lua_strx2number) #include static int isneg (const char **s) { if (**s == '-') { (*s)++; return 1; } else if (**s == '+') (*s)++; return 0; } static lua_Number readhexa (const char **s, lua_Number r, int *count) { for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */ r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s))); (*count)++; } return r; } /* ** convert an hexadecimal numeric string to a number, following ** C99 specification for 'strtod' */ static lua_Number lua_strx2number (const char *s, char **endptr) { lua_Number r = 0.0; int e = 0, i = 0; int neg = 0; /* 1 if number is negative */ *endptr = cast(char *, s); /* nothing is valid yet */ while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ neg = isneg(&s); /* check signal */ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ return 0.0; /* invalid format (no '0x') */ s += 2; /* skip '0x' */ r = readhexa(&s, r, &i); /* read integer part */ if (*s == '.') { s++; /* skip dot */ r = readhexa(&s, r, &e); /* read fractional part */ } if (i == 0 && e == 0) return 0.0; /* invalid format (no digit) */ e *= -4; /* each fractional digit divides value by 2^-4 */ *endptr = cast(char *, s); /* valid up to here */ if (*s == 'p' || *s == 'P') { /* exponent part? */ int exp1 = 0; int neg1; s++; /* skip 'p' */ neg1 = isneg(&s); /* signal */ if (!lisdigit(cast_uchar(*s))) goto ret; /* must have at least one digit */ while (lisdigit(cast_uchar(*s))) /* read exponent */ exp1 = exp1 * 10 + *(s++) - '0'; if (neg1) exp1 = -exp1; e += exp1; } *endptr = cast(char *, s); /* valid up to here */ ret: if (neg) r = -r; return l_mathop(ldexp)(r, e); } #endif int luaO_str2d (const char *s, size_t len, lua_Number *result) { char *endptr; if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ return 0; else if (strpbrk(s, "xX")) /* hexa? */ *result = lua_strx2number(s, &endptr); else *result = lua_str2number(s, &endptr); if (endptr == s) return 0; /* nothing recognized */ while (lisspace(cast_uchar(*endptr))) endptr++; return (endptr == s + len); /* OK if no trailing characters */ } static void pushstr (lua_State *L, const char *str, size_t l) { setsvalue2s(L, L->top++, luaS_newlstr(L, str, l)); } /* this function handles only `%d', `%c', %f, %p, and `%s' formats */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { int n = 0; for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; luaD_checkstack(L, 2); /* fmt + item */ pushstr(L, fmt, e - fmt); switch (*(e+1)) { case 's': { const char *s = va_arg(argp, char *); if (s == NULL) s = "(null)"; pushstr(L, s, strlen(s)); break; } case 'c': { char buff; buff = cast(char, va_arg(argp, int)); pushstr(L, &buff, 1); break; } case 'd': { setnvalue(L->top++, cast_num(va_arg(argp, int))); break; } case 'f': { setnvalue(L->top++, cast_num(va_arg(argp, l_uacNumber))); break; } case 'p': { char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ int l = sprintf(buff, "%p", va_arg(argp, void *)); pushstr(L, buff, l); break; } case '%': { pushstr(L, "%", 1); break; } default: { luaG_runerror(L, "invalid option " LUA_QL("%%%c") " to " LUA_QL("lua_pushfstring"), *(e + 1)); } } n += 2; fmt = e+2; } luaD_checkstack(L, 1); pushstr(L, fmt, strlen(fmt)); if (n > 0) luaV_concat(L, n + 1); return svalue(L->top - 1); } const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { const char *msg; va_list argp; va_start(argp, fmt); msg = luaO_pushvfstring(L, fmt, argp); va_end(argp); return msg; } /* number of chars of a literal string without the ending \0 */ #define LL(x) (sizeof(x)/sizeof(char) - 1) #define RETS "..." #define PRE "[string \"" #define POS "\"]" #define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) void luaO_chunkid (char *out, const char *source, size_t bufflen) { size_t l = strlen(source); if (*source == '=') { /* 'literal' source */ if (l <= bufflen) /* small enough? */ memcpy(out, source + 1, l * sizeof(char)); else { /* truncate it */ addstr(out, source + 1, bufflen - 1); *out = '\0'; } } else if (*source == '@') { /* file name */ if (l <= bufflen) /* small enough? */ memcpy(out, source + 1, l * sizeof(char)); else { /* add '...' before rest of name */ addstr(out, RETS, LL(RETS)); bufflen -= LL(RETS); memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); } } else { /* string; format as [string "source"] */ const char *nl = strchr(source, '\n'); /* find first new line (if any) */ addstr(out, PRE, LL(PRE)); /* add prefix */ bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ if (l < bufflen && nl == NULL) { /* small one-line source? */ addstr(out, source, l); /* keep it */ } else { if (nl != NULL) l = nl - source; /* stop at first newline */ if (l > bufflen) l = bufflen; addstr(out, source, l); addstr(out, RETS, LL(RETS)); } memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); } } blobby-1.0/data/scripts/old/axji.lua000644 001750 001750 00000002310 12313310254 022215 0ustar00danielknobedanielknobe000000 000000 function OnOpponentServe() moveto(120) end wait = 0 serv = true aggroservice = 64 -- versetzung zum Ball je gr�sser desto tiefer fliegt der Service 0-64 function OnServe(ballready) moveto(ballx()) -- unter den Ball stellen wait = wait + 1 -- waittimer anwerfen serv = true -- servflag setzen if ballready then -- ball bereit if wait > 90 then -- 90 einheiten gewartet jump() -- Springen also eigentlich den Ball aufwerfen wait = 0 -- Wait timer zur�cksetzen end end end function OnGame() -- bestimmen wenn der service vertig ist if (ballx() > 400) then -- sobald der ball auf der anderen seite ist ;) serv = false -- serv flag zur�cksetzen end if serv then -- sprunganschlag code moveto(estimate()-aggroservice) -- Bewegt sich unter den Ball und schl�gt mit einer gewissen aggressivit�t an bei 64 knapp �bers Netz -- warscheinlich w�re ein Match.random() angebracht if bally() < 550 then -- wenn der Ball wieder runter kommt jump() end else if (estimate() < 0) then -- Falls der Ball von Hinten kommt moveto(math.abs(estimate())-100) -- funktioniert noch nicht richtig else moveto(estimate()-20) --sonst immer leicht hinter dem Ball bleiben end end end blobby-1.0/src/Clock.h000644 001750 001750 00000004206 12313310253 017401 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include /*! \class Clock \brief Game Timing Management \details This class represents a clock. It can be started, paused, resetted, and it is possible to get the time in a string for in-game representation */ class Clock { public: /// default c'tor Clock(); /// starts/unpauses the clock void start(); /// pauses the clock void stop(); /// resets the clock. after this, the clock is paused. void reset(); /// gets whether the clock is currently running bool isRunning() const; /// this function has to be called each frame. It calculates /// the passed time; void step(); /// gets the time in seconds as an integer int getTime() const; /// set the time to a specified value /// \param newTime: new time in seconds void setTime(int newTime); /// returns the time as a string std::string getTimeString() const; private: /// is the clock currently running? bool mRunning; /// recorded time in seconds time_t mGameTime; /// last time that step was called. /// needed to calculate the time difference. time_t mLastTime; }; blobby-1.0/data/lang_fr.xml000644 001750 001750 00000014533 12313310256 020460 0ustar00danielknobedanielknobe000000 000000 blobby-1.0/NEWS000644 001750 001750 00000000000 12313310256 016074 0ustar00danielknobedanielknobe000000 000000 blobby-1.0/data/scripts/Union.lua000644 001750 001750 00000024556 12313310254 021614 0ustar00danielknobedanielknobe000000 000000 --UNION --27.3.2007 - version 2 --Enormator -- 11.1.12 - insert game-provided physic constants where possible - by ngc92 --Startwerte setzen --set starting values OOSinit=false OSinit=false OGinit=false decision=0 funcs=4 oldtouches=0 oldbspeedx=0 serve=false --Weltkonstanten definieren --define world constants middle = CONST_FIELD_WIDTH/2 wallright = CONST_FIELD_WIDTH - CONST_BALL_RADIUS blobbyheadheight = CONST_GROUND_HEIGHT + CONST_BLOBBY_HEIGHT + CONST_BALL_RADIUS blobbymaxjump = 393.625 blobbygroundpos = CONST_GROUND_HEIGHT + CONST_BLOBBY_HEIGHT / 2 netheight = CONST_NET_HEIGHT + CONST_NET_RADIUS -- height is just the rod. for total height, we have to add the net-sphere-radius too netcolissionleft = middle - CONST_NET_RADIUS - CONST_BALL_RADIUS netcolissionright = middle + CONST_NET_RADIUS + CONST_BALL_RADIUS --Hauptfunktionen --main functions function OnOpponentServe() --initialisiere Funktion --initialise function OSinit=false OGinit=false if (OOSinit==false) then --einmal pro Aufruf von OnOpponentServe --one time per OnOpponentServe decision=decide(1) --Entscheidung faellen --make a decision OOSinit=true serve=false end dofunc (1, decision, true) --Entscheidung ausfuehren --follow the taken decision end function OnServe(ballready) --initialisiere Funktion --initialise function OOSinit=false OGinit=false if (OSinit==false) then --einmal pro Aufruf von OnServe --one time per OnServe decision=decide(2) --Entscheidung faellen --make a decision OSinit=true serve=true --Aufschlag auch waehrend OnGame weitermachen --continue serve while OnGame end dofunc (2, decision, true) --Entscheidung ausfuehren --follow the taken decision end function OnGame() --initialisiere Funktion --initialise function OOSinit=false OSinit=false if (OGinit==false) and (serve==false) then --einmal pro Aufruf von OnGame und wenn der Aufschlag schon vorbei ist --one time per OnGame and when serve is already over decision=decide(3) --Entscheidung faellen --make a decision OGinit=true end if (serve==true) then --Falls noch beim Aufschlag --if still while serve dofunc (2, decision, true) --Der Funktion sagen, dass sie immernoch beim Aufschlag ist --tell the function, it's still OnServe else dofunc (3, decision, true) --Der Funktion sagen, dass sie im Spiel ist --tell the function that it's OnGame end if (ballx()>netcolissionleft+CONST_BALL_RADIUS) then --Falls Ball nicht mehr erreichbar --If Ball not gettable by Bot serve=false --Aufschlagende erzwingen --Make an end to the serve end if (touches()~=oldtouches) or (math.abs(oldbspeedx)~=math.abs(bspeedx())) then --Hat sich die Situation gendert --If the situation has changed OGinit=false --gleich Entscheidung neu fllen --redo decision oldtouches=touches() oldbspeedx=bspeedx() end end --Entscheidungsfunktionen --decision functions function decide (funcno) t1=1 chosen=1 chosenret=0 --Alle Funktionen abfragen und die mit dem grten Return whlen --test all functions and take the one with the highest return value while (t1 <= funcs) do temp=dofunc(funcno,t1,false) if (temp > chosenret) then chosen=t1 chosenret=temp end t1=t1+1 end debug (chosenret) --Sagt, fr wie gut sich die gewhlte Funktion hlt --tells how good the chosen function says to fit return chosen end function dofunc (funcno, actionno, action) --Weist jeder Aktionsnummer den echten Funktionsnamen zu --converts actionnumbers to the real names of the functions if (actionno==1) then return std45deg (funcno, action) end if (actionno==2) then return takelow (funcno, action) end if (actionno==3) then return wait (funcno, action) end if (actionno==4) then return twohitserve1 (funcno, action) end return false end --Ausfhrbare Funktionen --executable functions function std45deg (funcno, action) --spielt Ball aus der Luft bei maxjump im 45 Winkel an --plays ball in the air at height maxjump with 45 angle --funcno(s)=2,3 maxjump = blobbymaxjump distance = 32.25 targetx=estimatex (maxjump) - distance if (funcno==1) then return -1 end if (action==false) then if (funcno==2) and (action==false) then return math.random(10, 100) end if (funcno==3) and (action==false) then if (bspeedx() <= 3) and (math.max(balltimetox(targetx),balltimetoy(maxjump)) >= math.max(blobtimetoy(maxjump), blobtimetox(targetx))) then if (bspeedx()==0) then ret=85 else ret=math.min((10^(-math.abs(bspeedx()))+1),1)*85 end if (estimhitnet()==true) and (blobtimetox(netcolissionleft)<=balltimetoy(netheight)) then ret=190 end return ret else return 0 end end end if (action==true) then if (funcno==2) then if (posy()==144.5) then moveto (targetx) end if (math.abs(posx()-targetx)<4.5) and (ballx()==200) and (bally()==299.5) then jump() end end if (funcno==3) then moveto (targetx) if ((bally()<580) and (bspeedy()<0)) then jump() end end if (jumpcase) then jump() end end end function takelow (funcno, action) --Ballannahme ohne Sprung zum Stellen (bspeedx()=0) selten exakt --take ball without jump to create a ball with bspeedx()=0 (sellen exactly) --funcno(s)=3 if (funcno==1) or (funcno==2) then return -1 end if (action==false) then if (touches()<=1) then return 1 else return -1 end end if (action==true) then moveto (estimatex(220.5)) end end function wait (funcno, action) --Auf guter Position auf eine gegnerische Aktion warten --wait for an opponent's move at a good position --funcno(s)=1,3 if (funcno==2) then return -1 end if (funcno==1) and (action==false) then return 200 end if (funcno==3) and (action==false) then if (estimatex(393.625) > 424.5) then return 200 else return -1 end end if (action==true) then moveto (180) end end function twohitserve1 (funcno, action) --Aufschlag: Stellen (bspeedx()=0), rueber --serve: up (bspeedx()=0), play --funcno(s)=2 if (funcno==1) or (funcno==3) then return -1 end if (action==false) then return math.random(10,100) else if (touches()==0) then moveto (200) if (math.abs(posx()-200)<5) then jump() end end if (touches()==1) then moveto (estimatex(blobbymaxjump)-45) if (bally()<580) and (bspeedy()<0) then jump() end end if (touches()==3) then serve=false end end end --mathematische Hilfsfunktionen --mathematical helpers function estimatex(destY) --gibt mglichst genaue Angabe der X-Koordinate zurck, bei der sich der Ball befindet, wenn er sich bei der angegebenen Y Koordinate befindet --returns exact ballx when bally will be given destY if (bspeedy()==0) and (bspeedx()==0) then return ballx() end time1 =(-bspeedy()-math.sqrt((bspeedy()^2)-(2*CONST_BALL_GRAVITY * (bally()-destY)))) / CONST_BALL_GRAVITY resultX = (bspeedx() * time1) + ballx() estimbspeedx=bspeedx() if(resultX > wallright) then -- Korrigieren der Appraller an der Rechten Ebene resultX = 2 * CONST_FIELD_WIDTH - resultX estimbspeedx=-estimbspeedx end if(resultX < CONST_BALL_RADIUS) then -- korrigieren der Appraller an der linken Ebene resultX = 2 * CONST_BALL_RADIUS - resultX estimbspeedx=-estimbspeedx end if (resultX > netcolissionleft) and (estimatey(netcolissionleft-CONST_BALL_RADIUS) <= netheight) and (estimbspeedx > 0) then resultX = 2 * netcolissionleft - resultX estimbspeedx=-estimbspeedx end return resultX end function balltimetox (x) --Zeit in Physikschritten, die der Ball bei der derzeitigen Geschwindigkeit zu der angegebenen X-Position braucht --time in physic steps, which the ball needs to reach the given x-position with momentany speed if (bspeedx() == 0) then return 10000 end strecke=x-ballx() time=(strecke)/bspeedx() return time end function blobtimetoy (y) --Zeit, die ein Blob braucht, um eine Y Position zu erreichen --time needed by a blob to reach a given y coordinate if (y>383) then y=383 end grav = CONST_BLOBBY_GRAVITY / 2 -- half, because we use jump buffer time1 = CONST_BLOBBY_JUMP/grav + math.sqrt(2*grav*(y-blobbygroundpos) + CONST_BLOBBY_JUMP*CONST_BLOBBY_JUMP) / grav time2 = CONST_BLOBBY_JUMP/grav - math.sqrt(2*grav*(y-blobbygroundpos) + CONST_BLOBBY_JUMP*CONST_BLOBBY_JUMP) / grav timemin=math.min(time1,time2) return timemin end function estimhitnet() --Wird der Ball das Netz treffen (bool) --Will the ball hit the net (bool) safety=5 if (361.5-safety < estimatex(323)) and (estimatex(323) < 438.5+safety) then answer=true else answer=false end return answer end function estimatey (x) --Y Position des Balls, wenn er sich an der angegebenen X Koordinate befindet --y position of the ball, when it is at the given x coordinate y=ballyaftertime(balltimetox(x,3)) return y end function ballyaftertime (t) --Y Position des Balls nach der angegebenen Zahl von Physikschritten --y position of the ball after the given time y=1/2*CONST_BALL_GRAVITY*t^2+bspeedy()*t+bally() return y end function blobtimetox (x) --Zeit, die der Bot benoetigt, um eine gewisse X-Koordinate zu erreichen --time needed for the bot to reach a given x-coordinate time=math.abs(posx()-x)/4.5 return time end function balltimetoy (y) --Zeit, die der Ball bis zu einer Y Position benoetigt --time needed by the ball to reach a given y position time1=-bspeedy()/CONST_BALL_GRAVITY+1/CONST_BALL_GRAVITY*math.sqrt(2*CONST_BALL_GRAVITY*(y-bally())+bspeedy()^2) time2=-bspeedy()/CONST_BALL_GRAVITY-1/CONST_BALL_GRAVITY*math.sqrt(2*CONST_BALL_GRAVITY*(y-bally())+bspeedy()^2) timemax=math.max(time1, time2) return timemax endblobby-1.0/src/blobnet/layer/Http.cpp000644 001750 001750 00000010542 12313310251 022357 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "Http.hpp" /* includes */ #include #include #include #include #include #include #include namespace BlobNet { namespace Layer { /* implementation */ Http::Http(const std::string& hostname, const int& port) : mHostname(hostname) , mPort(port) { } Http::~Http() { } void Http::request(const std::string& path, std::stringstream& response) { // Create TCP/IP Socket SOCKET inOutSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(inOutSocket == INVALID_SOCKET) { BOOST_THROW_EXCEPTION ( Exception::HttpException("Can't create HTTP-Socket.") ); } // Connect to the host const char* ipAddress = mSocketLayer.nameToIP(mHostname.c_str()); if(ipAddress == NULL) { BOOST_THROW_EXCEPTION ( Exception::HttpException("Can't resolve IP Address.") ); } if(mSocketLayer.Connect(inOutSocket, inet_addr(ipAddress), mPort) == -1) { BOOST_THROW_EXCEPTION ( Exception::HttpException("Can't connect to host.") ); }; // Message for a simple request std::string request = "GET /" + path + " HTTP/1.1\r\nHost: " + mHostname + "\r\n\r\n"; // Write the whole message int bytesSend = 0; do { bytesSend += mSocketLayer.Write(inOutSocket, request.c_str(), request.size()); if(bytesSend == -1) { BOOST_THROW_EXCEPTION ( Exception::HttpException("Can't send the request to host.") ); } } while(bytesSend < request.size()); // Read the header of the response and extract content size std::stringstream header; readHeader(inOutSocket, header); int contentSize = getContentSize(header); // Read the body readBody(inOutSocket, response, contentSize); close(inOutSocket); } void Http::readHeader(int inOutSocket, std::stringstream& response) { // Parser variables State state = something; bool done = false; // Read header for(char c; (!done) && (recv(inOutSocket, &c, 1, 0) > 0); response << c) { switch(c) { case '\r': if(state == something) { state = cr; break; } if(state == crlf) { state = crlfcr; break; } state = error; done = true; break; case '\n': if(state == cr) { state = crlf; break; } if(state == crlfcr) { state = headerDone; return; } state = error; done = true; break; default: state = something; break; } } BOOST_THROW_EXCEPTION ( Exception::HttpException("Can't read response.") ); } void Http::readBody(int inOutSocket, std::stringstream& response, int contentSize) { // Parser variables int counter = 0; // Read body for(char c; recv(inOutSocket, &c, 1, 0) > 0; response << c) { counter += 1; if(counter == contentSize) { return; } } BOOST_THROW_EXCEPTION ( Exception::HttpException("Can't read response.") ); } int Http::getContentSize(std::stringstream& response) { // Parser variables std::string token; State state = something; // Parser while(response >> token) { switch(state) { case something: if(token == "Content-Length:") { state = contentlength; } break; case contentlength: state = headerDone; return atoi(token.c_str()); } } BOOST_THROW_EXCEPTION ( Exception::HttpException("Can't get contentsize of http response.") ); } } } blobby-1.0/data/gfx/font20.bmp000644 001750 001750 00000003370 12313310254 020715 0ustar00danielknobedanielknobe000000 000000 BM6( $##NLKGFE onmqnmxxv777mlk : .B+8WVV343V6KtvPh6(/%&%ƾ_b^>+:͇lS?L żڊwΛcw4-0bfaϓ >1;ҭɲkahϼW_W؛645ltkж E?Eûmlk ~}ή$6:5]h\KdKUUU}}~}on$#$¦ǥsrJeJt}tțčqo#."Ÿɟψff$># on᱖ޕro>t>=  %+%ۮ~{KI*q)O5YT0,+(#!`.@T?fe31=:3/# L   }|ol2d1=TP\Y94? C_CtqROBlAc_-(p6旀~VS0s-omYU,&+)4~3PoOd`JE =V<{yzwXUEB1ywom+a)  LoKҁWUblobby-1.0/data/gfx/sch12.bmp000644 001750 001750 00000030066 12313310254 020527 0ustar00danielknobedanielknobe000000 000000 BM606( 0  333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333blobby-1.0/src/raknet/MTUSize.h000644 001750 001750 00000004674 12313310247 021146 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Provide some consts concerning the size of network packet. * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef DEFAULT_MTU_SIZE /** * 1500. The largest Ethernet packet size; it is also the default * value. This is the typical setting for non-PPPoE, non-VPN * connections. The default value for NETGEAR routers, adapters and * switches. 1492. The size PPPoE prefers. 1472. Maximum size to use * for pinging. (Bigger packets are fragmented.) 1468. The size DHCP * prefers. 1460. Usable by AOL if you don't have large email * attachments, etc. 1430. The size VPN and PPTP prefer. 1400. Maximum * size for AOL DSL. 576. Typical value to connect to dial-up ISPs. */ #define DEFAULT_MTU_SIZE 576 /** * This is the largest value for an UDP packet Fixe DEFAULT_MTU_SIZE * to a lower value. */ #define MAXIMUM_MTU_SIZE 8000 #endif blobby-1.0/src/Blood.cpp000644 001750 001750 00000006551 12313310247 017750 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "Blood.h" /* includes */ #include #include "RenderManager.h" #include "IUserConfigReader.h" /* implementation */ BloodManager* BloodManager::mSingleton = NULL; // Blood class // ------------ Blood::Blood(const Vector2& position, const Vector2& direction, int player): mPos(position), mDir(direction), mPlayer(player), mLastFrame(SDL_GetTicks()) { } void Blood::step() { const float GRAVITY = 3; /// \todo this is the only place where we do step-rate independent calculations. /// is this intended behaviour??? int diff = SDL_GetTicks() - mLastFrame; RenderManager::getSingleton().drawParticle(mPos, mPlayer); const int SPEED = 45; //this calculation is NOT based on physical rules mDir.y += GRAVITY / SPEED * diff; mPos.x += mDir.x / SPEED * diff; mPos.y += mDir.y / SPEED * diff; mLastFrame = SDL_GetTicks(); } // BloodManager class // ------------------- BloodManager::BloodManager() { mEnabled = IUserConfigReader::createUserConfigReader("config.xml")->getBool("blood"); } void BloodManager::step() { // don't do any processing if there are no particles if ( !mEnabled || mParticles.empty() ) return; // start drawing RenderManager::getSingleton().startDrawParticles(); // iterate over all particles std::list::iterator it = mParticles.begin(); while (it != mParticles.end()) { std::list::iterator it2 = it; ++it; it2->step(); // delete particles below lower screen border if (it2->getPosition().y > 600) mParticles.erase(it2); } // finish drawing RenderManager::getSingleton().endDrawParticles(); } void BloodManager::spillBlood(Vector2 pos, float intensity, int player) { const double EL_X_AXIS = 30; const double EL_Y_AXIS = 50; for (int c = 0; c <= int(intensity*50); c++) { /// \todo maybe we can find a better algorithm, but for now, /// we just discard particles outside the ellipses /// so it doesn't look that much like a square. int x = random(int(-EL_X_AXIS * intensity), int(EL_X_AXIS * intensity)); int y = random(int(-EL_Y_AXIS * intensity), 3); if( ( y * y / (EL_Y_AXIS * EL_Y_AXIS) + x * x / (EL_X_AXIS * EL_X_AXIS) ) > intensity * intensity) continue; mParticles.push_front( Blood(pos, Vector2(x, y), player) ); } } int BloodManager::random(int min, int max) { /// \todo is this really a good way of creating these numbers? return (int)((double(rand()) / RAND_MAX) * (max - min)) + min; } blobby-1.0/000755 001750 001750 00000000000 12313311460 015405 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/data/gfx/font12.bmp000644 001750 001750 00000003370 12313310254 020716 0ustar00danielknobedanielknobe000000 000000 BM6( "$- -) ,&(;={}[^79!# +ߔW\./  BGr{enq35#!2"$  !zN|~H ru3 426s$w:+;Di k89\_=*>{+\ ]PDnpTr% ]ZX^+܅)(m)O5Q}I 56kIia+ ׈h0cdbB_A'=sSsG߉(//Д|>`"^  sYroܗ8=:by3o)&2+1ڸXa+T ZJUסĨGT$B q\hߦ|FsQ$9 {ᬽGcU'4 }gj֥։[^e531 cRSٯԟvXxQ.L81'  E<9Ͳm:ky'Pk=\1W;Ti_SďsOc2JO A>6imWzxSb5blobby-1.0/src/raknet/ReliabilityLayer.h000644 001750 001750 00000031066 12313310247 023107 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Provide Reliability Communication * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __RELIABILITY_LAYER_H #define __RELIABILITY_LAYER_H #include "MTUSize.h" #include "LinkedList.h" #include "ArrayList.h" #include "SocketLayer.h" #include "PacketPriority.h" #include "BitStream.h" #include "SimpleMutex.h" #include "InternalPacket.h" #include "InternalPacketPool.h" #include "RakNetStatistics.h" #include "NetworkTypes.h" #include "../blobnet/adt/Queue.hpp" /** * Sizeof an UDP header in byte */ #define UDP_HEADER_SIZE 28 /** * Number of ordered streams available. * You can use up to 32 ordered streams */ #define NUMBER_OF_ORDERED_STREAMS 32 // 2^5 /** * Timeout before killing a connection. If no response to a reliable * packet for this long kill the connection */ #ifdef _DEBUG const unsigned int TIMEOUT_TIME = 30000; // In debug don't timeout for 30 seconds so the connection doesn't drop while debugging #else const unsigned int TIMEOUT_TIME = 10000; // In release timeout after the normal 10 seconds #endif #include "BitStream.h" /** * This class provide reliable communication services. * */ class ReliabilityLayer { public: /** * Default Constructor */ ReliabilityLayer(); /** * Destructor */ ~ReliabilityLayer(); /** * Resets the layer for reuse. * Callable from multiple threads */ void Reset( void ); /** * Must be called by the same thread as update Packets are read * directly from the socket layer and skip the reliability layer * because unconnected players do not use the reliability layer This * function takes packet data after a player has been confirmed as * connected. The game should not use that data directly because * some data is used internally, such as packet acknowledgement and * split packets * * @param buffer Store up to @em length byte from the incoming data * @param length The size of buffer * @param restrictToFirstPacket Set to true if this is a connection request. It will only allow packets with a packetNumber of 0 * @param firstPacketDataID If restrictToFirstPacket is true, then this is packetID type that is allowed. Other types are ignored * @param length The size of buffer * @return false on modified packets */ bool HandleSocketReceiveFromConnectedPlayer( const char *buffer, int length ); /** * This gets an end-user packet already parsed out. * * @param data The game data * @return Returns number of BITS put into the buffer * @note Callable from multiple threads * */ int Receive( char**data ); /** * Puts data on the send queue * @param bitStream contains the data to send * @param priority is what priority to send the data at * @param reliability is what reliability to use * @param orderingChannel is from 0 to 31 and specifies what stream to use * @param makeDataCopy if true @em bitStream will keep an internal copy of * the packet. * @param MTUSize * @note Callable from multiple threads * * @todo Document MTUSize parameter */ bool Send( char *data, int numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, unsigned char orderingChannel, bool makeDataCopy, int MTUSize, unsigned int currentTime ); /** * Run this once per game cycle. Handles internal lists and * actually does the send Must be called by the same thread as * HandleSocketReceiveFromConnectedPlayer * * @param s the communication end point * @param playerId The Unique Player Identifier who should * have sent some packets * @param MTUSize * @param time * @todo * Document MTUSize and time parameter */ void Update( SOCKET s, PlayerID playerId, int MTUSize, unsigned int time ); /** * Were you ever unable to deliver a packet despite retries? * @return true if the connection no more responds */ bool IsDeadConnection( void ) const; /** * Causes IsDeadConnection to return true */ void KillConnection(void); /** * How long to wait between packet resends * @param i time to wait before resending a packet */ void SetLostPacketResendDelay( unsigned int i ); /** * Get Statistics * @return The object containing all stats */ RakNetStatisticsStruct * const GetStatistics( void ); /** * Are we waiting for any data to be sent out or be processed by the player? */ bool IsDataWaiting(void); private: /** * Returns true if we can or should send a frame. False if we should not * @param time The time to wait before sending a frame * @return true if we can or should send a frame. */ bool IsFrameReady( unsigned int time ); /** * Generates a frame (coalesced packets) * @param output The resulting BitStream * @param MTUSize * @param reliableDataSent True if we have to sent a reliable data * @param time Delay to send the packet or deadline * @todo * Check for time paramter * */ void GenerateFrame( RakNet::BitStream *output, int MTUSize, bool *reliableDataSent, unsigned int time ); /** * Writes a bitstream to the socket * @param s The socket used for sending data * @param playerId The target of the communication * @param bitStream The data to send. */ void SendBitStream( SOCKET s, PlayerID playerId, RakNet::BitStream *bitStream ); /** * Parse an internalPacket and create a bitstream to represent this data * Returns number of bits used */ int WriteToBitStreamFromInternalPacket( RakNet::BitStream *bitStream, const InternalPacket *const internalPacket ); // Parse a bitstream and create an internal packet to represent this data InternalPacket* CreateInternalPacketFromBitStream( RakNet::BitStream *bitStream, unsigned int time ); // Does what the function name says void RemovePacketFromResendQueueAndDeleteOlderReliableSequenced( PacketNumberType packetNumber ); // Acknowledge receipt of the packet with the specified packetNumber void SendAcknowledgementPacket( PacketNumberType packetNumber, unsigned int time ); // This will return true if we should not send at this time bool IsSendThrottled( void ); // We lost a packet void UpdatePacketloss( unsigned int time ); // Parse an internalPacket and figure out how many header bits would be written. Returns that number int GetBitStreamHeaderLength( const InternalPacket *const internalPacket ); // Returns true if newPacketOrderingIndex is older than the waitingForPacketOrderingIndex bool IsOlderOrderedPacket( OrderingIndexType newPacketOrderingIndex, OrderingIndexType waitingForPacketOrderingIndex ); // Split the passed packet into chunks under MTU_SIZE bytes (including headers) and save those new chunks void SplitPacket( InternalPacket *internalPacket, int MTUSize ); // Insert a packet into the split packet list void InsertIntoSplitPacketList( InternalPacket * internalPacket ); // Take all split chunks with the specified splitPacketId and try to reconstruct a packet. If we can, allocate and return it. Otherwise return 0 InternalPacket * BuildPacketFromSplitPacketList( unsigned int splitPacketId, unsigned int time ); // Delete any unreliable split packets that have long since expired void DeleteOldUnreliableSplitPackets( unsigned int time ); // Creates a copy of the specified internal packet with data copied from the original starting at dataByteOffset for dataByteLength bytes. // Does not copy any split data parameters as that information is always generated does not have any reason to be copied InternalPacket * CreateInternalPacketCopy( InternalPacket *original, int dataByteOffset, int dataByteLength, unsigned int time ); // Get the specified ordering list // LOCK THIS WHOLE BLOCK WITH reliabilityLayerMutexes[orderingList_MUTEX].Unlock(); BasicDataStructures::LinkedList *GetOrderingListAtOrderingStream( unsigned char orderingChannel ); // Add the internal packet to the ordering list in order based on order index void AddToOrderingList( InternalPacket * internalPacket ); // Inserts a packet into the resend list in order void InsertPacketIntoResendQueue( InternalPacket *internalPacket, unsigned int time, bool makeCopyOfInternalPacket, bool resetAckTimer ); // Memory handling void FreeMemory( bool freeAllImmediately ); void FreeThreadSafeMemory( void ); // Initialize the variables void InitializeVariables( void ); bool IsExpiredTime(unsigned int input, unsigned int currentTime) const; unsigned int IsReceivedPacketHole(unsigned int input, unsigned int currentTime) const; unsigned int MakeReceivedPacketHole(unsigned int input) const; unsigned int GetResendQueueDataSize(void) const; void UpdateThreadedMemory(void); BasicDataStructures::List splitPacketList; BasicDataStructures::List*> orderingList; BlobNet::ADT::Queue acknowledgementQueue, outputQueue; BlobNet::ADT::Queue resendQueue; BlobNet::ADT::Queue sendPacketSet[ NUMBER_OF_PRIORITIES ]; PacketNumberType packetNumber; //unsigned int windowSize; unsigned int lastAckTime; RakNet::BitStream updateBitStream; OrderingIndexType waitingForOrderedPacketWriteIndex[ NUMBER_OF_ORDERED_STREAMS ], waitingForSequencedPacketWriteIndex[ NUMBER_OF_ORDERED_STREAMS ]; // STUFF TO NOT MUTEX HERE (called from non-conflicting threads, or value is not important) OrderingIndexType waitingForOrderedPacketReadIndex[ NUMBER_OF_ORDERED_STREAMS ], waitingForSequencedPacketReadIndex[ NUMBER_OF_ORDERED_STREAMS ]; bool deadConnection; unsigned int lostPacketResendDelay; unsigned int splitPacketId; unsigned int blockWindowIncreaseUntilTime; RakNetStatisticsStruct statistics; // New memory-efficient receivedPackets algorithm: // Store times in a queue. Store the base offset. // On time insert: // Pop all expired times. For each expired time popped, increase the baseIndex // If the packet number is >= the baseIndex and (packetNumber - baseIndex) < queue size // We got a duplicate packet. // else // Add 0 times to the queue until (packetNumber - baseIndex) < queue size. BlobNet::ADT::Queue receivedPackets; PacketNumberType receivedPacketsBaseIndex; bool resetReceivedPackets; // Windowing algorithm: // Start at a minimum size // Set the lossy window size to INFINITE // If the current window size is lower than the lossy window size, then increase the window size by 1 per frame if the number of acks is >= the window size and data is waiting to go out. // Otherwise, do the same, but also apply the limit of 1 frame per second. If we are more than 5 over the lossy window size, increase the lossy window size by 1 // If we lose a frame, decrease the window size by 1 per frame lost. Record the new window size as the lossy window size. int windowSize; int lossyWindowSize; unsigned int lastWindowIncreaseSizeTime; /** * This variable is so that free memory can be called by only the * update thread so we don't have to mutex things so much */ bool freeThreadedMemoryOnNextUpdate; #ifdef _INTERNET_SIMULATOR struct DataAndTime { char data[ 2000 ]; int length; unsigned int sendTime; }; BasicDataStructures::List delayList; #endif // This has to be a member because it's not threadsafe when I removed the mutexes InternalPacketPool internalPacketPool; }; #endif blobby-1.0/data/scripts/old/com_10eB2.lua000644 001750 001750 00000012536 12313310254 022704 0ustar00danielknobedanielknobe000000 000000 -- Com 1.0 extrem Beta 2 -- by Oreon, Axji & Enormator -- Flags und runners wait = 0 naechsterBallSchmettern = true -- evtl Variablennamen wechseln -- Weltkonstanten CONST_FELD_LAENGE = 800 CONST_BALL_RADIUS = 31.5 CONST_GROUND_PLANE = 100 CONST_BALL_GRAVITY = 0.28 CONST_MITTE = CONST_FELD_LAENGE/2 CONST_RECHTER_RAND = CONST_FELD_LAENGE - CONST_BALL_RADIUS CONST_BLOBBY_HOEHE = 89 CONST_BLOBBY_KOPF_RADIUS = 25 CONST_BLOBBY_BAUCH_RADIUS = 33 CONST_BLOBBY_KOPF_BERUEHRUNG = CONST_GROUND_PLANE + CONST_BLOBBY_HOEHE + CONST_BALL_RADIUS CONST_BLOBBY_MAXJUMP = 393.625 CONST_NETZ_RADIUS = 7 CONST_NETZ_HOEHE = 323 -- Berhrungsebene des Balls falls er ans Netz kommt CONST_NETZ_LINKS = CONST_MITTE - CONST_NETZ_RADIUS - CONST_BALL_RADIUS CONST_NETZ_RECHTS = CONST_MITTE + CONST_NETZ_RADIUS + CONST_BALL_RADIUS -- Charakter CONST_ANGRIFFSGRUNDWERT_MIN = 30 CONST_ANGRIFFSGRUNDWERT_MAX = 55 MIN_ANGRIFFSSTAERKE = CONST_ANGRIFFSGRUNDWERT_MIN MAX_ANGRIFFSSTAERKE = CONST_ANGRIFFSGRUNDWERT_MAX ANGRIFFSEINSCHRAENKUNG_HINTEN = 10 -- sonstige Einstellungen servexVersetzung=-7 --Wert ist so gewaehlt, dass der Ball nah ans Netz fliegt, der Gegner ihn aber grade nicht erreichen kann -- ***ANFANG*** function OnOpponentServe() moveto(130) end function OnServe(ballready) servex=ballx()+servexVersetzung naechsterBallSchmettern = true generatenaechsterBallSchmettern() moveto(servex) if ballready and (servex-2 < posx()) and (posx() < servex+2) then jump() end end function OnGame() target = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_KOPF_BERUEHRUNG,1) --X Ziel in Blobbyhoehe targets = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_KOPF_BERUEHRUNG,2) --X Richtung (-1 oder 1) bei Einschlag targetNetz = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_NETZ_HOEHE,1) --X Ziel in Netzhoehe (Netzrollerberechnung) targetJump = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_MAXJUMP,1) --X Ziel in Schmetterhoehe naechsterBallSchmetternFlagTesten() -- schaut ob der bot angreifen soll oder nicht if (ballx() > CONST_NETZ_RECHTS) then --Wenn Ball auf rechter Spielfeldseite dann generatenaechsterBallSchmettern() --Angriffsstaerke neu berechnen end if (target > CONST_MITTE) and (ballx() > CONST_NETZ_RECHTS) then --Wenn der Ball mich nix angeht moveto(135) --Dann auf Standartposition warten else if (targetNetz > CONST_NETZ_LINKS - 10) then --Bei Netzroller einfach schmettern naechsterBallSchmettern = true end if naechsterBallSchmettern then if ((math.abs(bspeedx()) < 4) or (estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_MAXJUMP,2) < 0)) then sprungattacke(angriffsstaerke) else if (targetJump < CONST_MITTE / 2) then sprungattacke(-35) --an Rueckwand spielen else sprungattacke(0) --weiterleiten end end return end moveto(target) end end function sprungattacke(p_angriffsstaerke) p_angriffsstaerke=math.max(p_angriffsstaerke, MIN_ANGRIFFSSTAERKE + ANGRIFFSEINSCHRAENKUNG_HINTEN * (targetJump / CONST_NETZ_LINKS)) --Weiter hinten nicht ganz so hoch spielen (kommt nicht auf die andere Seite) p_angriffsstaerke=math.min(p_angriffsstaerke, MAX_ANGRIFFSSTAERKE - ANGRIFFSEINSCHRAENKUNG_HINTEN * (targetJump / CONST_NETZ_LINKS)) --Weiter hinten nicht ganz so tief spielen (kommt ans Netz) moveto(targetJump-p_angriffsstaerke) -- Bei der Sprungatacke wird die Strke des gewnschten schlages angegeben if (bally() < 580) and (bspeedy() < 0) then jump() end end function naechsterBallSchmetternFlagTesten() if (touches() == 3) then -- falls der Bot einen Anschlag Findet der Direckt punktet so wird der Wer nicht neu berechnet da er dann nciht auf 3 Berhrungen kommt naechsterBallSchmettern = false return end if (ballx() > CONST_MITTE) then -- wenn der ball auf der Anderen Seite ist soll der bot nicht naechsterBallSchmettern sein naechsterBallSchmettern = false return end if (touches() == 1) and (math.abs(bspeedx()) < 2) then -- schon nach der 1ten Beruehrung angreifen wenn der Ball gut kommt naechsterBallSchmettern = true return end if (touches() == 2) then -- nach der 2. Berhrung angreifen naechsterBallSchmettern = true return end naechsterBallSchmettern = false end function generatenaechsterBallSchmettern() angriffsstaerke = math.random(MIN_ANGRIFFSSTAERKE,MAX_ANGRIFFSSTAERKE) end function estimImpact(bx,by,vbx,vby,destY,Frage) -- erlaubt ein besseres Estimate mit ein paar unbeding ntigen Angaben bgrav = 0.28 time1 =(-vby-math.sqrt((vby^2)-(-2*bgrav*(by-destY))))/(-bgrav) resultX = (vbx * time1) + bx estimbspeedx=bspeedx()/math.abs(bspeedx()) if(resultX > CONST_RECHTER_RAND) then -- Korrigieren der Appraller an der Rechten Ebene resultX = 2 * CONST_FELD_LAENGE - resultX estimbspeedx=-estimbspeedx end if(resultX < CONST_BALL_RADIUS) then -- korrigieren der Appraller an der linken Ebene resultX = math.abs(resultX - CONST_BALL_RADIUS) + CONST_BALL_RADIUS estimbspeedx=-estimbspeedx KollisionLinks = true else KollisionLinks = false end if (resultX > CONST_NETZ_RECHTS) and (estimbspeedx > 0) and ((KollisionLinks == true) or (ballx() < CONST_NETZ_LINKS)) then -- Abpraller am Netz unterhalb der Kugel erst wenn Netzroller ausgeschlossen sind resultX = 2 * CONST_NETZ_LINKS - resultX estimbspeedx=-estimbspeedx end if (Frage == 1) then return resultX end if (Frage == 2) then return estimbspeedx end endblobby-1.0/src/server/NetworkPlayer.cpp000644 001750 001750 00000005002 12313310252 023007 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "NetworkPlayer.h" /* includes */ /* implementation */ // initialise NetworkPlayer. Set NetworkID to 0.0.0.0:0, so we are sure no player // will ever have this. NetworkPlayer::NetworkPlayer() : mID(), mIdentity() { mID.binaryAddress = 0; mID.port = 0; } NetworkPlayer::NetworkPlayer(PlayerID id, const std::string& name, Color color, PlayerSide side) :mID(id), mIdentity(name, color, false, side) { } NetworkPlayer::NetworkPlayer(PlayerID id, RakNet::BitStream stream) : mID(id) { int playerSide; stream.Read(playerSide); // Read the Playername char charName[16]; stream.Read(charName, sizeof(charName)); // ensures that charName is null terminated charName[sizeof(charName)-1] = '\0'; // read colour data int color; stream.Read(color); mIdentity = PlayerIdentity(charName, color, false, (PlayerSide)playerSide); } bool NetworkPlayer::valid() const { return mID.port != 0; } const PlayerID& NetworkPlayer::getID() const { return mID; } const std::string& NetworkPlayer::getName() const { return mIdentity.getName(); } Color NetworkPlayer::getColor() const { return mIdentity.getStaticColor(); } PlayerSide NetworkPlayer::getDesiredSide() const { return mIdentity.getPreferredSide(); } PlayerIdentity NetworkPlayer::getIdentity() const { return mIdentity; } const boost::shared_ptr& NetworkPlayer::getGame() const { return mGame; } void NetworkPlayer::setGame(boost::shared_ptr game) { mGame = game; } blobby-1.0/data/gfx/font47.bmp000644 001750 001750 00000003370 12313310254 020726 0ustar00danielknobedanielknobe000000 000000 BM6( UT7a6%E$ RQNL5q4<RQpmCA-n,a tsb^B    *~(G 8y661 O qnUP S"+H,xvki,%  a 0 ,rp@<q2``KF |6L|J}{LG  { 8 9`8zxEB   9  (D'soKG  9 IiYJ:a8yuJF s *(% @=l;tq>;i % 8KH (DxAa^)"Y I}Gmj/+v  =:GC'$0fdzw95{,$GE63(&'c&  tsNJ)%,)){'65IE7475 ŅwtRNOKd`sqmk_]\ZWyW|y:k:&c}bΡ걥ᤛ֚MpMblobby-1.0/data/gfx/font04.bmp000644 001750 001750 00000003370 12313310254 020717 0ustar00danielknobedanielknobe000000 000000 BM6(  HwF p(@ x)]> r [6jK & P3l.L 0 w  G#@ * / #b2" M40  K , % 0 7M&x 5 ) / 9 A@:3$  y~#     $1hdMF"  . 5(" #!$*)50))>vrMF!'2-=:QK;5!,(G=+$#4։^Y83$!E1. "ԄRO'$ B({xCA**w N(novuHH--** _utfgBCq1ØxyKL"OwwUV*,u( uuRT,/K DG,."bbrsBEU\\ylm/2 ffUW##\LKn}~PP::^UUblobby-1.0/src/tinyxml/CMakeLists.txt000644 001750 001750 00000000264 12313310251 022437 0ustar00danielknobedanielknobe000000 000000 add_definitions(-DTIXML_USE_STL) set(tinyxml_SRC tinystr.cpp tinystr.h tinyxml.cpp tinyxml.h tinyxmlerror.cpp tinyxmlparser.cpp ) add_library(tinyxml STATIC ${tinyxml_SRC}) blobby-1.0/data/sounds/bums.wav000644 001750 001750 00000023410 12313310256 021320 0ustar00danielknobedanielknobe000000 000000 RIFF'WAVEfmt Ddata&aa\aai{^d_aaa^]c_aicdksphal(H _ ' 5e/$25jI*EV. ,SR 7"M=,K0z *(aQK\ NT   =߇BP%\πP#ʔZpB!`$$ZvUx]&ꖧI;)bd=<[\ nntNv/ikN%R*-O ˒Z˿?b  3O2?Q=Qz`aLY[b4k82oeUJ)|!ĆAZn𐊏1/ PQP;X{YSUNOFH:<+-/ z8cل/ޞ +V+596.>>wBC8;+@8vl}eڸΥȢ٢v~:Se;Z;EOOgOKQ6>@;%'Dr@|Sm<-?7t+(tؼ:D**2 4/0(/*] $/z^^Ho4ivu sk?sWm{֖*[ʹڸxڳ>϶M1ԙgWgFAv22mȀ1a"𝤠~uK߰ ر.*z7ݜECCE4ؠ ȑdz\XD8̶M<Єao۔ۇ(!^s@qJ,<5;RaɺnG޻dZP * a|j2n߯Әњt>˾qα؉=Nm:=  xt'sGt7@Tl~u fy PX S  EAKR<<-}- T=#i$n!")%RXQ I TL *v.D: Ms cX9tk)( ^ eD b# P y2Y!"$%)),-,-'X)h!"@~w M2Wtf CeW %!X$C%&^'/)%**+0,N-()h !#R%t9L %,&,b-Y0F123J4h55765768845#12U./(W*#K$"l#&'-,,012}34=52L40/2021245?6s7789 ;6 813K2r34!55667E8L9_7812.)0-.i,-a+,(_)&'&')).,-O/[001_212M2313/(1./././01263353 5,Y.E%&W!e"!"7$/%'()*=,2-,D-'(m%&#%A!j"!"@!c"(  ?\hs|{V# Xs{l L +qi| YQ!J cz qnNp+x:ibMp97TKT&\V/Q#g{9#rJ!U*'M,59S-[&X'O{SLy#?CFDZb&x,_d)M ^hB5 n"5aXRCl=U  ? on'#*%8dO|*>I   ^7 I  ptIi  xz' 6     P mJ! a q b  j}<<cL-QzQ>%|d 6 ^ 4 r K   `   9  Y=PM^  rO=e*  Y R n O g $ m'/c*eVZhsSf/tV-"x|B{d\A Z e> 3`'i$m'<y^ DNPP&C>,U;s]['$zj76qwPK !~0U=aOx#LqPwmEKWYoUVsw5.?*8Vq%@BxVcQ jb6aPP@M6sQJ0[&@U q D63PMTlU _   y Q @t;  , :I w- ZOr`b5%KKy;V~O"&#)&'&(a%&#$ !)`sun\/B jZr *  \i  e6r<f~*EN; ' r [ 7 3~](4 + : F  C %   i3TDWN" 0 u } +/Y<,X#I2yXyK-u[b aefz ;u%FD2N7v"&9de9:&Tz)\J9^T)i%F. )bsvIF-s#7}XFim{Ec2UB Q0s>+}\ E\2,y02G S54 |:,b{OC"B_M;C%E#Y `qpT##s7}[zP=}wG!pj&vnVm~` zNj]W ii< ybE^n:mBwByDm6[[! zJ\oYbKn$vAM dX!~utmn#ibM{AdK , 3+ SAhR * D  q ]v f D #!  4 )&erMA`,l< yo=:hSe`lC%/~KG0JO}  J)F64 vmoF`~H#?[ew4w_kN cX<oxn@^"c\$4,<(e \\.{MWvZzH7'ym_:pN= j`Jq/G]5 #8x,psj zJW'lv2Rf]G2IWtG@{Gk s2=/{/ 7*o,\(#f.nT7,8R3Y!=K2}VD^jt'Sp/JYaE?1r[z|bXA>fbeI, Wz;W5O6I%{EPR/i3TXRRn>%( (#FWGhqz=0E"q>Uivf"/lOdUxyiVAZFpJ>h:o |l:# )~i  * C )   p O J @ & | m  u f t Q   V G  C , X 2  i W /  >!UR >GRM'!Y.xw2 I [ 5(wh v s  "   @ P  < 7)  ~ _  & +  T . t Z ( - | g  + ; ) jjbU & ,  6 * C 9  61}L0*$?A/a@KQ! ~TO5v2 e7YN  -;sU-^*X"d|<7C5-N!Gk@hI1zK1^!nWXr4 YI[#9w%G6}*C4~7e5h71~2zc$fCN(&58fFQ<-~[_EtK> : w`3wB6 [Q'h$R+= x$ C{J5 Gf/>xh4<O+fwl[-9o>x>*   .P mTz=2   gb l h  Z 4 O ) *  V  Y T p B = + z w - , [ 9 I N e ] t Z N >   .  @ 0  T K  N = ^ [ m Q 0 w j _ : ? f S  0  1 1 x p 9  z d J 1 0   C E i ^ M , ! [3tfUbGXNL`fI`QdR-9q^Sp=J;-'e"-y3m?,G=[[,eU4j/4(z-db@&X<I%^I{HH>mT#':xl(:8-w7S-~KlP\~c^,3%n84."=<;i\: ' `).C6$,ic?wZ F9&W/7L,K92R9!Sn?H>}1.wL @il6g^4MP[f+tBud|WUw:F6ZP@wI|t$j@.|DT3g>|O`tOjH2 (Z,IA62WA8"R*IP4S1H*PK87M? -U(!M'-<G >]WL%4U U%I4D<*>01U DH*[/K4UZ/S*PF <>F(7*K%blobby-1.0/data/scripts/old/com_10hB1.lua000644 001750 001750 00000014340 12313310254 022701 0ustar00danielknobedanielknobe000000 000000 -- Com 1.0 human Beta 1 -- by Oreon, Axji & Enormator -- Flags und runners wait = 0 naechsterBallSchmettern = true -- evtl Variablennamen wechseln quatschFlag = 0 mood = math.random(1,3)+3 --Startlaune zwischen 4 und 6 -- Weltkonstanten CONST_FELD_LAENGE = 800 CONST_BALL_RADIUS = 31.5 CONST_GROUND_PLANE = 100 CONST_BALL_GRAVITY = 0.28 CONST_MITTE = CONST_FELD_LAENGE/2 CONST_RECHTER_RAND = CONST_FELD_LAENGE - CONST_BALL_RADIUS CONST_BLOBBY_HOEHE = 89 CONST_BLOBBY_KOPF_RADIUS = 25 CONST_BLOBBY_BAUCH_RADIUS = 33 CONST_BLOBBY_KOPF_BERUEHRUNG = CONST_GROUND_PLANE + CONST_BLOBBY_HOEHE + CONST_BALL_RADIUS CONST_BLOBBY_MAXJUMP = 393.625 CONST_NETZ_RADIUS = 7 CONST_NETZ_HOEHE = 323 -- Berhrungsebene des Balls falls er ans Netz kommt CONST_NETZ_LINKS = CONST_MITTE - CONST_NETZ_RADIUS - CONST_BALL_RADIUS CONST_NETZ_RECHTS = CONST_MITTE + CONST_NETZ_RADIUS + CONST_BALL_RADIUS -- Charakter CONST_MIN_MOOD = 0 CONST_MAX_MOOD = 10 CONST_ANGRIFFSGRUNDWERT_MIN = 35 CONST_ANGRIFFSGRUNDWERT_MAX = 60 MIN_ANGRIFFSSTAERKE = CONST_ANGRIFFSGRUNDWERT_MIN-mood MAX_ANGRIFFSSTAERKE = CONST_ANGRIFFSGRUNDWERT_MAX-mood CONST_GEDULD = 0.01 --weniger ist mehr Geduld -- ***ANFANG*** function OnOpponentServe() BallLinks=false if (LauneBerechnet == false) then mood=mood-1 --schlechter gelaunt LauneBerechnen () --anwenden auf Angriffswert LauneBerechnet = true end moveto(130) end function OnServe(ballready) BallLinks=true if (LauneBerechnet == false) then mood=mood+1 --besser gelaunt LauneBerechnen () --anwenden auf Angriffswert LauneBerechnet = true end naechsterBallSchmettern = true generatenaechsterBallSchmettern() if (quatschFlag == 0) then quatschFlag = math.random(5,10) end if (mood > quatschFlag) then --je besser gelaunt, desto wahrscheinlicher Quatsch quatschFlag = enormerQuatsch() else moveto(ballx()) if ballready and (ballx()-3 < posx()) and (posx() < ballx()+3) then jump() end end end function OnGame() debug (mood) if (BallLinks == (ballx() > CONST_MITTE)) then --Bei jedem Ballwechsel mood = mood - CONST_GEDULD --um CONST_GEDULD schlechter gelaunt sein LauneBerechnen () BallLinks = (ballx() < CONST_MITTE) end LauneBerechnet=false --Flag setzen fr Berechnung beim Aufschlag quatschFlag=0 --Flag setzen fr Berechnung beim Aufschlag los=false --Flag setzen fr Berechnung beim Aufschlag naechsterBallSchmetternFlagTesten() -- schaut ob der bot angreifen soll oder nicht target = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_KOPF_BERUEHRUNG) --X Ziel in Blobbyhoehe targetNetz = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_NETZ_HOEHE) --X Ziel in Netzhoehe (Netzrollerberechnung) targetJump = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_MAXJUMP) --X Ziel in Schmetterhoehe if (ballx() > CONST_NETZ_RECHTS) then --Wenn Ball auf rechter Spielfeldseite dann generatenaechsterBallSchmettern() --Angriffsstaerke neu berechnen end if (target > CONST_MITTE) and (ballx() > CONST_NETZ_RECHTS) then --Wenn der Ball mich nix angeht moveto(135) --Dann auf Standartposition warten else if (targetNetz > CONST_NETZ_LINKS - 10) then --Bei Netzroller einfach schmettern naechsterBallSchmettern = true end if naechsterBallSchmettern then sprungattacke(angriffsstaerke) return end moveto(target) end end function sprungattacke(p_angriffsstaerke) if (bally() < 550) and (math.abs(ballx() - posx()) > 200) then -- Falls nicht schmetterbar moveto (target - 25) --Dann Notloesung versuchen return end if ((bally() < 600) and (bspeedy() < 0)) or (math.abs(bspeedx()) > 2) or (math.abs(targetJump-posx()) > 40) then -- erst im letzten Moment bewegen -> unvorhersehbar moveto(targetJump-p_angriffsstaerke) -- Bei der Sprungatacke wird die Strke des gewnschten schlages angegeben end if (bally() < 580) and (bspeedy() < 0) then jump() end end function naechsterBallSchmetternFlagTesten() if (touches() == 3) then -- falls der Bot einen Anschlag Findet der Direckt punktet so wird der Wer nicht neu berechnet da er dann nciht auf 3 Berhrungen kommt naechsterBallSchmettern = false return end if (ballx() > CONST_MITTE) then -- wenn der ball auf der Anderen Seite ist soll der bot nicht naechsterBallSchmettern sein naechsterBallSchmettern = false return end if (touches() == 1) and (math.abs(bspeedx()) < 2) and (mood < CONST_MAX_MOOD) then -- schon nach der 1ten Beruehrung angreifen wenn der Ball gut kommt und er nicht zu gut gelaunt ist naechsterBallSchmettern = true return end if (touches() == 2) then -- nach der 2. Berhrung angreifen naechsterBallSchmettern = true return end naechsterBallSchmettern = false end function generatenaechsterBallSchmettern() angriffsstaerke = math.random(MIN_ANGRIFFSSTAERKE,MAX_ANGRIFFSSTAERKE) -- variiert mit der Laune end function estimImpact(bx,by,vbx,vby,destY) -- erlaubt ein besseres Estimate mit ein paar umbeding ntigen Angaben bgrav = 0.28 time1 =(-vby-math.sqrt((vby^2)-(-2*bgrav*(by-destY))))/(-bgrav) resultX = (vbx * time1) + bx estimbspeedx=bspeedx() if(resultX > CONST_RECHTER_RAND) then -- Korrigieren der Appraller an der Rechten Ebene resultX = 2 * CONST_FELD_LAENGE - resultX estimbspeedx=-estimbspeedx end if(resultX < CONST_BALL_RADIUS) then -- korrigieren der Appraller an der linken Ebene resultX = math.abs(resultX - CONST_BALL_RADIUS) + CONST_BALL_RADIUS estimbspeedx=-estimbspeedx KollisionLinks = true else KollisionLinks = false end if (resultX > CONST_NETZ_RECHTS) and (estimbspeedx > 0) and ((KollisionLinks == true) or (ballx() < CONST_NETZ_LINKS)) then -- Abpraller am Netz unterhalb der Kugel erst wenn Netzroller ausgeschlossen sind resultX = 2 * CONST_NETZ_LINKS - resultX estimbspeedx=-estimbspeedx end return resultX end function enormerQuatsch() if los then left() jump() else right() end if (posx() > 350) then los=true end if (posx() < 60) then los=false return CONST_MAX_MOOD + 1 -- MaxLaune+1 kann nie erreicht werden -> stop end return quatschFlag -- Wenn nicht fertig, dann nix aendern end function LauneBerechnen () if (mood < CONST_MIN_MOOD) then mood = 0 end if (mood > CONST_MAX_MOOD) then mood = 10 end MIN_ANGRIFFSSTAERKE=CONST_ANGRIFFSGRUNDWERT_MIN-mood MAX_ANGRIFFSSTAERKE=CONST_ANGRIFFSGRUNDWERT_MAX-mood endblobby-1.0/src/File.cpp000644 001750 001750 00000007174 12313310253 017567 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "File.h" /* includes */ #include #include #include "Global.h" #include "FileSystem.h" /* implementation */ File::File() : mHandle(0) { } File::File(const std::string& filename, OpenMode mode, bool no_override) : mHandle(0), mFileName("") { open(filename, mode, no_override); } File::~File() { // make sure we close this! close(); } void File::open(const std::string& filename, OpenMode mode, bool no_override) { // check that we don't have anything opened! /// \todo maybe we could just close the old file here... but /// then, this could also lead to errors... assert(mHandle == 0); // open depending on mode if( mode == OPEN_WRITE ) { if(no_override && FileSystem::getSingleton().exists(filename)) { BOOST_THROW_EXCEPTION(FileAlreadyExistsException(filename)); } mHandle = PHYSFS_openWrite(filename.c_str()); } else { mHandle = PHYSFS_openRead(filename.c_str()); } if (!mHandle) { BOOST_THROW_EXCEPTION(FileLoadException(filename)); } mFileName = filename; } void File::close() { // if handle is 0, no file is currently opened, so close does not do anything // maybe we could assert this, but i'm not sure that that is necessary. // we cannot assert this, because this function is run in the destrucor! if(mHandle) { if (PHYSFS_close( reinterpret_cast (mHandle) ) ) { /// we can't throw an error here, as this function gets called /// in the destructor and therefore might be called while another /// excpetion is active so we cant throw. }; mHandle = 0; mFileName = ""; } } void* File::getPHYSFS_file() { return mHandle; } bool File::is_open() const { return mHandle; } uint32_t File::length() const { check_file_open(); PHYSFS_sint64 len = PHYSFS_fileLength( reinterpret_cast (mHandle) ); if( len == -1 ) { BOOST_THROW_EXCEPTION( PhysfsFileException(mFileName) ); } return len; } uint32_t File::tell() const { check_file_open(); PHYSFS_sint64 tp = PHYSFS_tell( reinterpret_cast (mHandle) ); if(tp == -1) BOOST_THROW_EXCEPTION( PhysfsFileException(mFileName) ); return tp; } std::string File::getFileName() const { return mFileName; } void File::seek(uint32_t target) { check_file_open(); if(!PHYSFS_seek( reinterpret_cast(mHandle), target)) { BOOST_THROW_EXCEPTION( PhysfsFileException(mFileName) ); } } void File::check_file_open() const { // check that we have a handle if( !mHandle ) { BOOST_THROW_EXCEPTION( NoFileOpenedException() ); } } blobby-1.0/data/gfx/font39.bmp000644 001750 001750 00000003370 12313310254 020727 0ustar00danielknobedanielknobe000000 000000 BM6( Zm $+& } 6   _\IDA'wurp=7$";  feNL2/, on]Y:j8  ƘԎYX*6*?E?ɨXaX y|yuiv5*52-2vcCe  ~vς? Qkޞ7,-[1]^7<=N)ON.KM895!M OMN'KMor K NGJ '߳' (]a!ۢ$ 5.&r+wv+|]W@qh2nC0F{ blobby-1.0/src/raknet/LICENSE000644 001750 001750 00000011665 12313310247 020500 0ustar00danielknobedanielknobe000000 000000 RAKNET EMAIL: We are allowed to change every file to BSD-License: From - Tue Feb 16 17:22:10 2010 X-Account-Key: account2 X-UIDL: 743025276 X-Mozilla-Status: 0011 X-Mozilla-Status2: 00000000 X-Mozilla-Keys: Received: from [68.230.241.43] (helo=fed1rmmtao103.cox.net) by mx33.web.de with esmtp (WEB.DE 4.110 #314) id 1NhQB5-0007j2-00 for daniel-knobe@web.de; Tue, 16 Feb 2010 17:21:36 +0100 Received: from fed1rmimpo03.cox.net ([70.169.32.75]) by fed1rmmtao103.cox.net (InterMail vM.8.00.01.00 201-2244-105-20090324) with ESMTP id <20100216161827.WTHU19579.fed1rmmtao103.cox.net@fed1rmimpo03.cox.net> for ; Tue, 16 Feb 2010 11:18:27 -0500 Received: from [192.168.1.4] ([98.189.238.122]) by fed1rmimpo03.cox.net with bizsmtp id igJT1d0082f8TL204gJTL2; Tue, 16 Feb 2010 11:18:27 -0500 X-VR-Score: -210.00 X-Authority-Analysis: v=1.1 cv=3OYv9oSQMPl2mzQJct9Z0gr0/14v7p3aTRAVsPGESI0= c=1 sm=1 a=Iz04VOSJxDsDrARI3wmEZA==:17 a=MxczCRmKqDDVT_otjAYA:9 a=PMfHed8KGfxFHxPCxhMjB1GEX18A:4 a=Iz04VOSJxDsDrARI3wmEZA==:117 X-CM-Score: 0.00 Message-ID: <4B7AC558.60108@jenkinssoftware.com> Date: Tue, 16 Feb 2010 08:18:32 -0800 From: Kevin Jenkins User-Agent: Thunderbird 2.0.0.23 (Windows/20090812) MIME-Version: 1.0 To: Daniel Knobe Subject: Re: a second small question References: <4B7ABDAE.7010005@web.de> In-Reply-To: <4B7ABDAE.7010005@web.de> Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit Return-Path: rakkar@jenkinssoftware.com Just change everything to the BSD Daniel Knobe wrote: > Hello again, > we have one more problem. > The old raknet has the licensetext I send u before, but some > headerfiles have no licensetext: > ArrayList.h BigTypes.h BinarySearchTree.h CheckSum.cpp CheckSum.h > DataReplicator.cpp FullyConnectedMesh.cpp LinkedList.h > MessageHandlerInterface.cpp OrderedList.h Queue.h QueueLinkedList.h > RakNetQueue.h RPCMap.cpp RSACrypt.h Types.h > > Can we add the licensetext of the other files to it or can you tell me > the license of this files? > > Greets > Daniel Knobe > Blobby Volley 2 > RIJNDAEL EMAIL: From - Thu Mar 25 17:58:29 2010 X-Account-Key: account2 X-UIDL: 743025543 X-Mozilla-Status: 0011 X-Mozilla-Status2: 00000000 X-Mozilla-Keys: Received: from [134.58.240.44] (helo=cavuit02.kulnet.kuleuven.be) by mx36.web.de with esmtp (WEB.DE 4.110 #4) id 1NuoF1-0002hE-00 for daniel-knobe@web.de; Thu, 25 Mar 2010 15:40:59 +0100 Received: from smtps01.kuleuven.be (smtpshost01.kulnet.kuleuven.be [134.58.240.74]) by cavuit02.kulnet.kuleuven.be (Postfix) with ESMTP id C557E51C004 for ; Thu, 25 Mar 2010 15:40:38 +0100 (CET) Received: from hydrogen.esat.kuleuven.be (hydrogen.esat.kuleuven.be [134.58.56.153]) by smtps01.kuleuven.be (Postfix) with ESMTP id 7D9F031E702 for ; Thu, 25 Mar 2010 15:40:38 +0100 (CET) Received: from [10.33.137.107] (boguspomp.esat.kuleuven.be [10.33.137.107]) by hydrogen.esat.kuleuven.be (Postfix) with ESMTP id 8D91148002 for ; Thu, 25 Mar 2010 15:40:38 +0100 (CET) Message-ID: <4BAB75E6.2020408@esat.kuleuven.be> Date: Thu, 25 Mar 2010 15:40:38 +0100 X-Kuleuven: This mail passed the K.U.Leuven mailcluster From: Vincent Rijmen Organization: K.U. Leuven User-Agent: Thunderbird 2.0.0.22 (X11/20090625) MIME-Version: 1.0 To: Daniel Knobe Subject: Re: rijndael license problems References: <4BA93621.3060605@web.de> <4BA9C2D2.4060400@esat.kuleuven.be> <4BAA3650.30505@web.de> In-Reply-To: <4BAA3650.30505@web.de> Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit X-KULeuven-Information: Katholieke Universiteit Leuven X-KULeuven-Scanned: Found to be clean X-Spam-Status: not spam, SpamAssassin (not cached, score=-50, required 5, autolearn=disabled, KUL_SMTPS -50.00) X-KULeuven-Envelope-From: vincent.rijmen@esat.kuleuven.be Return-Path: vincent.rijmen@esat.kuleuven.be This code is public. There is no license. Vincent Daniel Knobe wrote: > I'm sorry, it was my mistake. > Here are the files (hope you use a free license). > > We need this version of the files (or a newer with 100% compatible API) > > Thanks for your support. > > Best regards, > Daniel Knobe > > On 24.03.2010 08:44, Vincent Rijmen wrote: >> >> >> Daniel Knobe wrote: >>> Hi, >>> we are using the 3 files below in our game blobby volley 2 >>> (blobby.sf.net) >> I did not see any files or file names. >>> >>> The problem is, that we can not find the lisensetext :(. We need it, >>> because we have problems to add our game to debian and ubuntu lucid. >>> Which version of lisence and version are you using? GPLv2? GPLv3, BSD? >> None. >>> >>> Thanks for your support :). >>> >>> Greetz >>> Daniel >>> >> > blobby-1.0/src/InputDevice.h000644 001750 001750 00000003147 12313310253 020570 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include "PlayerInput.h" #include "BlobbyDebug.h" /*! \class InputDevice \brief Abstract base class for game input methods */ class InputDevice : public ObjectCounter { public: InputDevice() {} virtual ~InputDevice() {} virtual PlayerInputAbs transferInput() = 0; }; class JoystickAction; InputDevice* createKeyboardInput(SDL_Keycode left, SDL_Keycode right, SDL_Keycode jump); InputDevice* createJoystrickInput(JoystickAction left, JoystickAction right, JoystickAction jump); InputDevice* createTouchInput(PlayerSide side, int type); InputDevice* createMouseInput(PlayerSide player, int jumpbutton); blobby-1.0/doc/ScriptAPI.txt000644 001750 001750 00000003732 12313310254 020516 0ustar00danielknobedanielknobe000000 000000 This document tries to design a new API for the Lua scripting interface for bots. This API is based on the old API, but replaces ugly functions and provides a more sophisticated way to implement serving behaviour. The main difference of the new API is, that the bot is always programmed for the left side. If the controlled blob is actually on the other side, the API converts all values automatically. These are the available function: left() : moves one step left right() : moves one step right jump() : presses jump key moveto(number) : moves to the given position with a small buffer touches() : Number of own ball touches since last ball exchange. launched() : Tells whether the player is jumping at the moment. estimate(): Estimated impact point of the ball, without collision estimx(number) : Estimates ball x component for n timesteps estimy(number) : Estimates ball y component for n timesteps ballx() : x component of the ball position bally() : y component of the ball position bspeedx() : x component of the ball velocity bspeedy() : y component of the ball velocity posx() : x component of own position posy() : y component of own position oppx() : x component of opponent position oppy() : y component of opponent position debug(number) : Prints a number to stderr for debugging purposes getScore() : own score getOppScore() : opponent's score getScoreToWin() : score needed to win the match getGameTime(): time the game is running (for bots simulating exhaustion) All functions of the lua math library are also available. You can find their documentation at: http://www.lua.org/manual/5.1/manual.html#5.6 Scripts MUST provide these entry point: function OnServe(ballready) : Called when the ball went down and the controlled blob has to serve it next. The boolean parameter is true when the ball is already placed. function OnOpponentServe() : Called after balldown when the opponent has to serve the next ball function OnGame() : Called during the normal game blobby-1.0/src/raknet/SimpleMutex.cpp000644 001750 001750 00000006147 12313310247 022452 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Simple Mutex * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "SimpleMutex.h" #include ////#include "MemoryManager.h" SimpleMutex::SimpleMutex() { #ifdef _WIN32 InitializeCriticalSection(&criticalSection); #else int error = pthread_mutex_init(&hMutex, 0); assert(error==0); #endif } SimpleMutex::~SimpleMutex() { #ifdef _WIN32 // CloseHandle(hMutex); DeleteCriticalSection(&criticalSection); #else pthread_mutex_destroy(&hMutex); #endif } #ifdef _WIN32 #ifdef _DEBUG #include #endif #endif void SimpleMutex::Lock(void) { #ifdef _WIN32 /* DWORD d = WaitForSingleObject(hMutex, INFINITE); #ifdef _DEBUG if (d==WAIT_FAILED) { LPVOID messageBuffer; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &messageBuffer, 0, NULL ); // Process any inserts in messageBuffer. // ... // Display the string. //MessageBox( NULL, (LPCTSTR)messageBuffer, "Error", MB_OK | MB_ICONINFORMATION ); printf("SimpleMutex error: %s", messageBuffer); // Free the buffer. LocalFree( messageBuffer ); } assert(d==WAIT_OBJECT_0); */ EnterCriticalSection(&criticalSection); #else int error = pthread_mutex_lock(&hMutex); assert(error==0); #endif } void SimpleMutex::Unlock(void) { #ifdef _WIN32 // ReleaseMutex(hMutex); LeaveCriticalSection(&criticalSection); #else int error = pthread_mutex_unlock(&hMutex); assert(error==0); #endif } blobby-1.0/src/lua/ltable.h000644 001750 001750 00000002602 12313310253 020370 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: ltable.h,v 2.16.1.2 2013/08/30 15:49:41 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ #ifndef ltable_h #define ltable_h #include "lobject.h" #define gnode(t,i) (&(t)->node[i]) #define gkey(n) (&(n)->i_key.tvk) #define gval(n) (&(n)->i_val) #define gnext(n) ((n)->i_key.nk.next) #define invalidateTMcache(t) ((t)->flags = 0) /* returns the key, given the value of a table entry */ #define keyfromval(v) \ (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) LUAI_FUNC const TValue *luaH_getint (Table *t, int key); LUAI_FUNC void luaH_setint (lua_State *L, Table *t, int key, TValue *value); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); LUAI_FUNC Table *luaH_new (lua_State *L); LUAI_FUNC void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize); LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); LUAI_FUNC int luaH_getn (Table *t); #if defined(LUA_DEBUG) LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); LUAI_FUNC int luaH_isdummy (Node *n); #endif #endif blobby-1.0/src/NetworkMessage.cpp000644 001750 001750 00000007232 12313310251 021637 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "NetworkMessage.h" /* includes */ #include #include "UserConfig.h" #include "SpeedController.h" /* implementation */ ServerInfo::ServerInfo(RakNet::BitStream& stream, const char* ip, uint16_t p) { strncpy(hostname, ip, sizeof(hostname)); hostname[sizeof(hostname) - 1] = 0; port = p; stream.Read(activegames); stream.Read(gamespeed); stream.Read(name, sizeof(name)); stream.Read(waitingplayers); stream.Read(description, sizeof(description)); stream.Read(rulestitle, sizeof(rulestitle)); stream.Read(rulesauthor, sizeof(rulesauthor)); } ServerInfo::ServerInfo(const IUserConfigReader& config) { /// \todo we only need a config reader here! // default values std::string n = "Blobby Volley 2 Server"; std::string d = "no description available"; memset(this, 0, sizeof(ServerInfo)); std::string tmp; tmp = config.getString("name", n); strncpy(name, tmp.c_str(), sizeof(name) - 1); tmp = config.getString("description", d); strncpy(description, tmp.c_str(), sizeof(description) - 1); gamespeed = config.getInteger("speed", 75); /// \todo maybe we should check if that's a reasonable value, too. if (gamespeed < 20 || gamespeed > 200) gamespeed = 75; port = config.getInteger("port", BLOBBY_PORT); } ServerInfo::ServerInfo(const std::string& playername) { memset(this, 0, sizeof(ServerInfo)); std::strncpy(hostname, "localhost", sizeof(hostname)); port = BLOBBY_PORT; std::strncpy(name, std::string(playername + "'s game").c_str(), sizeof(name) - 1); std::strncpy(description, "client hosted game", sizeof(description) - 1); gamespeed = (int)SpeedController::getMainInstance()->getGameSpeed(); } void ServerInfo::writeToBitstream(RakNet::BitStream& stream) { stream.Write(activegames); stream.Write(gamespeed); stream.Write(name, sizeof(name)); stream.Write(waitingplayers); stream.Write(description, sizeof(description)); stream.Write(rulestitle, sizeof(rulestitle)); stream.Write(rulesauthor, sizeof(rulesauthor)); assert( stream.GetNumberOfBytesUsed() == BLOBBY_SERVER_PRESENT_PACKET_SIZE); } const size_t ServerInfo::BLOBBY_SERVER_PRESENT_PACKET_SIZE = sizeof((unsigned char)ID_BLOBBY_SERVER_PRESENT) + 3 * sizeof(int) // activegames & gamespeed & waiting players + 32 // name + 192 // description + 64; // rules title / author bool operator == (const ServerInfo& lval, const ServerInfo& rval) { // check if ip and port are identical! /// \todo maybe we should user raknets pladerId directly? return lval.port == rval.port && !strncmp(lval.hostname, rval.hostname, sizeof(lval.hostname)); } std::ostream& operator<<(std::ostream& stream, const ServerInfo& val) { return stream << val.name << " (" << val.hostname << ":" << val.port << ")"; } blobby-1.0/src/lua/lua.hpp000644 001750 001750 00000000277 12313310253 020254 0ustar00danielknobedanielknobe000000 000000 // lua.hpp // Lua header files for C++ // <> not supplied automatically because Lua also compiles as C++ extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } blobby-1.0/src/blobnet/exception/HttpException.hpp000644 001750 001750 00000002546 12313310251 025132 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= blobNet Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #ifndef _BLOBNET_EXCEPTION_HTTPEXCEPTION_HPP_ #define _BLOBNET_EXCEPTION_HTTPEXCEPTION_HPP_ /* Includes */ #include namespace BlobNet { namespace Exception { /*! \class HttpException \brief Runtimeexception for HttpErrors */ class HttpException : public std::runtime_error { public: /// @brief constructor /// @param message Message to describe the error HttpException(const std::string& message) : std::runtime_error(message) { }; }; } } #endif blobby-1.0/src/lua/llex.c000644 001750 001750 00000035755 12313310253 020103 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: llex.c,v 2.63.1.2 2013/08/30 15:49:41 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #include #include #define llex_c #define LUA_CORE #include "lua.h" #include "lctype.h" #include "ldo.h" #include "llex.h" #include "lobject.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "lzio.h" #define next(ls) (ls->current = zgetc(ls->z)) #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') /* ORDER RESERVED */ static const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", "..", "...", "==", ">=", "<=", "~=", "::", "", "", "", "" }; #define save_and_next(ls) (save(ls, ls->current), next(ls)) static l_noret lexerror (LexState *ls, const char *msg, int token); static void save (LexState *ls, int c) { Mbuffer *b = ls->buff; if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { size_t newsize; if (luaZ_sizebuffer(b) >= MAX_SIZET/2) lexerror(ls, "lexical element too long", 0); newsize = luaZ_sizebuffer(b) * 2; luaZ_resizebuffer(ls->L, b, newsize); } b->buffer[luaZ_bufflen(b)++] = cast(char, c); } void luaX_init (lua_State *L) { int i; for (i=0; itsv.extra = cast_byte(i+1); /* reserved word */ } } const char *luaX_token2str (LexState *ls, int token) { if (token < FIRST_RESERVED) { /* single-byte symbols? */ lua_assert(token == cast(unsigned char, token)); return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) : luaO_pushfstring(ls->L, "char(%d)", token); } else { const char *s = luaX_tokens[token - FIRST_RESERVED]; if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ return luaO_pushfstring(ls->L, LUA_QS, s); else /* names, strings, and numerals */ return s; } } static const char *txtToken (LexState *ls, int token) { switch (token) { case TK_NAME: case TK_STRING: case TK_NUMBER: save(ls, '\0'); return luaO_pushfstring(ls->L, LUA_QS, luaZ_buffer(ls->buff)); default: return luaX_token2str(ls, token); } } static l_noret lexerror (LexState *ls, const char *msg, int token) { char buff[LUA_IDSIZE]; luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE); msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); if (token) luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); luaD_throw(ls->L, LUA_ERRSYNTAX); } l_noret luaX_syntaxerror (LexState *ls, const char *msg) { lexerror(ls, msg, ls->t.token); } /* ** creates a new string and anchors it in function's table so that ** it will not be collected until the end of the function's compilation ** (by that time it should be anchored in function's prototype) */ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; TValue *o; /* entry for `str' */ TString *ts = luaS_newlstr(L, str, l); /* create new string */ setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ o = luaH_set(L, ls->fs->h, L->top - 1); if (ttisnil(o)) { /* not in use yet? (see 'addK') */ /* boolean value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ setbvalue(o, 1); /* t[string] = true */ luaC_checkGC(L); } else { /* string already present */ ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */ } L->top--; /* remove string from stack */ return ts; } /* ** increment line number and skips newline sequence (any of ** \n, \r, \n\r, or \r\n) */ static void inclinenumber (LexState *ls) { int old = ls->current; lua_assert(currIsNewline(ls)); next(ls); /* skip `\n' or `\r' */ if (currIsNewline(ls) && ls->current != old) next(ls); /* skip `\n\r' or `\r\n' */ if (++ls->linenumber >= MAX_INT) luaX_syntaxerror(ls, "chunk has too many lines"); } void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, int firstchar) { ls->decpoint = '.'; ls->L = L; ls->current = firstchar; ls->lookahead.token = TK_EOS; /* no look-ahead token */ ls->z = z; ls->fs = NULL; ls->linenumber = 1; ls->lastline = 1; ls->source = source; ls->envn = luaS_new(L, LUA_ENV); /* create env name */ luaS_fix(ls->envn); /* never collect this name */ luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ } /* ** ======================================================= ** LEXICAL ANALYZER ** ======================================================= */ static int check_next (LexState *ls, const char *set) { if (ls->current == '\0' || !strchr(set, ls->current)) return 0; save_and_next(ls); return 1; } /* ** change all characters 'from' in buffer to 'to' */ static void buffreplace (LexState *ls, char from, char to) { size_t n = luaZ_bufflen(ls->buff); char *p = luaZ_buffer(ls->buff); while (n--) if (p[n] == from) p[n] = to; } #if !defined(getlocaledecpoint) #define getlocaledecpoint() (localeconv()->decimal_point[0]) #endif #define buff2d(b,e) luaO_str2d(luaZ_buffer(b), luaZ_bufflen(b) - 1, e) /* ** in case of format error, try to change decimal point separator to ** the one defined in the current locale and check again */ static void trydecpoint (LexState *ls, SemInfo *seminfo) { char old = ls->decpoint; ls->decpoint = getlocaledecpoint(); buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ if (!buff2d(ls->buff, &seminfo->r)) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ lexerror(ls, "malformed number", TK_NUMBER); } } /* LUA_NUMBER */ /* ** this function is quite liberal in what it accepts, as 'luaO_str2d' ** will reject ill-formed numerals. */ static void read_numeral (LexState *ls, SemInfo *seminfo) { const char *expo = "Ee"; int first = ls->current; lua_assert(lisdigit(ls->current)); save_and_next(ls); if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ expo = "Pp"; for (;;) { if (check_next(ls, expo)) /* exponent part? */ check_next(ls, "+-"); /* optional exponent sign */ if (lisxdigit(ls->current) || ls->current == '.') save_and_next(ls); else break; } save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ if (!buff2d(ls->buff, &seminfo->r)) /* format error? */ trydecpoint(ls, seminfo); /* try to update decimal point separator */ } /* ** skip a sequence '[=*[' or ']=*]' and return its number of '='s or ** -1 if sequence is malformed */ static int skip_sep (LexState *ls) { int count = 0; int s = ls->current; lua_assert(s == '[' || s == ']'); save_and_next(ls); while (ls->current == '=') { save_and_next(ls); count++; } return (ls->current == s) ? count : (-count) - 1; } static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { save_and_next(ls); /* skip 2nd `[' */ if (currIsNewline(ls)) /* string starts with a newline? */ inclinenumber(ls); /* skip it */ for (;;) { switch (ls->current) { case EOZ: lexerror(ls, (seminfo) ? "unfinished long string" : "unfinished long comment", TK_EOS); break; /* to avoid warnings */ case ']': { if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `]' */ goto endloop; } break; } case '\n': case '\r': { save(ls, '\n'); inclinenumber(ls); if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ break; } default: { if (seminfo) save_and_next(ls); else next(ls); } } } endloop: if (seminfo) seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), luaZ_bufflen(ls->buff) - 2*(2 + sep)); } static void escerror (LexState *ls, int *c, int n, const char *msg) { int i; luaZ_resetbuffer(ls->buff); /* prepare error message */ save(ls, '\\'); for (i = 0; i < n && c[i] != EOZ; i++) save(ls, c[i]); lexerror(ls, msg, TK_STRING); } static int readhexaesc (LexState *ls) { int c[3], i; /* keep input for error message */ int r = 0; /* result accumulator */ c[0] = 'x'; /* for error message */ for (i = 1; i < 3; i++) { /* read two hexadecimal digits */ c[i] = next(ls); if (!lisxdigit(c[i])) escerror(ls, c, i + 1, "hexadecimal digit expected"); r = (r << 4) + luaO_hexavalue(c[i]); } return r; } static int readdecesc (LexState *ls) { int c[3], i; int r = 0; /* result accumulator */ for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ c[i] = ls->current; r = 10*r + c[i] - '0'; next(ls); } if (r > UCHAR_MAX) escerror(ls, c, i, "decimal escape too large"); return r; } static void read_string (LexState *ls, int del, SemInfo *seminfo) { save_and_next(ls); /* keep delimiter (for error messages) */ while (ls->current != del) { switch (ls->current) { case EOZ: lexerror(ls, "unfinished string", TK_EOS); break; /* to avoid warnings */ case '\n': case '\r': lexerror(ls, "unfinished string", TK_STRING); break; /* to avoid warnings */ case '\\': { /* escape sequences */ int c; /* final character to be saved */ next(ls); /* do not save the `\' */ switch (ls->current) { case 'a': c = '\a'; goto read_save; case 'b': c = '\b'; goto read_save; case 'f': c = '\f'; goto read_save; case 'n': c = '\n'; goto read_save; case 'r': c = '\r'; goto read_save; case 't': c = '\t'; goto read_save; case 'v': c = '\v'; goto read_save; case 'x': c = readhexaesc(ls); goto read_save; case '\n': case '\r': inclinenumber(ls); c = '\n'; goto only_save; case '\\': case '\"': case '\'': c = ls->current; goto read_save; case EOZ: goto no_save; /* will raise an error next loop */ case 'z': { /* zap following span of spaces */ next(ls); /* skip the 'z' */ while (lisspace(ls->current)) { if (currIsNewline(ls)) inclinenumber(ls); else next(ls); } goto no_save; } default: { if (!lisdigit(ls->current)) escerror(ls, &ls->current, 1, "invalid escape sequence"); /* digital escape \ddd */ c = readdecesc(ls); goto only_save; } } read_save: next(ls); /* read next character */ only_save: save(ls, c); /* save 'c' */ no_save: break; } default: save_and_next(ls); } } save_and_next(ls); /* skip delimiter */ seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, luaZ_bufflen(ls->buff) - 2); } static int llex (LexState *ls, SemInfo *seminfo) { luaZ_resetbuffer(ls->buff); for (;;) { switch (ls->current) { case '\n': case '\r': { /* line breaks */ inclinenumber(ls); break; } case ' ': case '\f': case '\t': case '\v': { /* spaces */ next(ls); break; } case '-': { /* '-' or '--' (comment) */ next(ls); if (ls->current != '-') return '-'; /* else is a comment */ next(ls); if (ls->current == '[') { /* long comment? */ int sep = skip_sep(ls); luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ if (sep >= 0) { read_long_string(ls, NULL, sep); /* skip long comment */ luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ break; } } /* else short comment */ while (!currIsNewline(ls) && ls->current != EOZ) next(ls); /* skip until end of line (or end of file) */ break; } case '[': { /* long string or simply '[' */ int sep = skip_sep(ls); if (sep >= 0) { read_long_string(ls, seminfo, sep); return TK_STRING; } else if (sep == -1) return '['; else lexerror(ls, "invalid long string delimiter", TK_STRING); } case '=': { next(ls); if (ls->current != '=') return '='; else { next(ls); return TK_EQ; } } case '<': { next(ls); if (ls->current != '=') return '<'; else { next(ls); return TK_LE; } } case '>': { next(ls); if (ls->current != '=') return '>'; else { next(ls); return TK_GE; } } case '~': { next(ls); if (ls->current != '=') return '~'; else { next(ls); return TK_NE; } } case ':': { next(ls); if (ls->current != ':') return ':'; else { next(ls); return TK_DBCOLON; } } case '"': case '\'': { /* short literal strings */ read_string(ls, ls->current, seminfo); return TK_STRING; } case '.': { /* '.', '..', '...', or number */ save_and_next(ls); if (check_next(ls, ".")) { if (check_next(ls, ".")) return TK_DOTS; /* '...' */ else return TK_CONCAT; /* '..' */ } else if (!lisdigit(ls->current)) return '.'; /* else go through */ } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { read_numeral(ls, seminfo); return TK_NUMBER; } case EOZ: { return TK_EOS; } default: { if (lislalpha(ls->current)) { /* identifier or reserved word? */ TString *ts; do { save_and_next(ls); } while (lislalnum(ls->current)); ts = luaX_newstring(ls, luaZ_buffer(ls->buff), luaZ_bufflen(ls->buff)); seminfo->ts = ts; if (isreserved(ts)) /* reserved word? */ return ts->tsv.extra - 1 + FIRST_RESERVED; else { return TK_NAME; } } else { /* single-char tokens (+ - / ...) */ int c = ls->current; next(ls); return c; } } } } } void luaX_next (LexState *ls) { ls->lastline = ls->linenumber; if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ ls->t = ls->lookahead; /* use this one */ ls->lookahead.token = TK_EOS; /* and discharge it */ } else ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ } int luaX_lookahead (LexState *ls) { lua_assert(ls->lookahead.token == TK_EOS); ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); return ls->lookahead.token; } blobby-1.0/src/lua/ltable.c000644 001750 001750 00000040142 12313310253 020364 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: ltable.c,v 2.72.1.1 2013/04/12 18:48:47 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ /* ** Implementation of tables (aka arrays, objects, or hash tables). ** Tables keep its elements in two parts: an array part and a hash part. ** Non-negative integer keys are all candidates to be kept in the array ** part. The actual size of the array is the largest `n' such that at ** least half the slots between 0 and n are in use. ** Hash uses a mix of chained scatter table with Brent's variation. ** A main invariant of these tables is that, if an element is not ** in its main position (i.e. the `original' position that its hash gives ** to it), then the colliding element is in its own main position. ** Hence even when the load factor reaches 100%, performance remains good. */ #include #define ltable_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "lvm.h" /* ** max size of array part is 2^MAXBITS */ #if LUAI_BITSINT >= 32 #define MAXBITS 30 #else #define MAXBITS (LUAI_BITSINT-2) #endif #define MAXASIZE (1 << MAXBITS) #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) #define hashstr(t,str) hashpow2(t, (str)->tsv.hash) #define hashboolean(t,p) hashpow2(t, p) /* ** for some types, it is better to avoid modulus by power of 2, as ** they tend to have many 2 factors. */ #define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) #define hashpointer(t,p) hashmod(t, IntPoint(p)) #define dummynode (&dummynode_) #define isdummy(n) ((n) == dummynode) static const Node dummynode_ = { {NILCONSTANT}, /* value */ {{NILCONSTANT, NULL}} /* key */ }; /* ** hash for lua_Numbers */ static Node *hashnum (const Table *t, lua_Number n) { int i; luai_hashnum(i, n); if (i < 0) { if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */ i = 0; /* handle INT_MIN */ i = -i; /* must be a positive value */ } return hashmod(t, i); } /* ** returns the `main' position of an element in a table (that is, the index ** of its hash value) */ static Node *mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNUMBER: return hashnum(t, nvalue(key)); case LUA_TLNGSTR: { TString *s = rawtsvalue(key); if (s->tsv.extra == 0) { /* no hash? */ s->tsv.hash = luaS_hash(getstr(s), s->tsv.len, s->tsv.hash); s->tsv.extra = 1; /* now it has its hash */ } return hashstr(t, rawtsvalue(key)); } case LUA_TSHRSTR: return hashstr(t, rawtsvalue(key)); case LUA_TBOOLEAN: return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: return hashpointer(t, pvalue(key)); case LUA_TLCF: return hashpointer(t, fvalue(key)); default: return hashpointer(t, gcvalue(key)); } } /* ** returns the index for `key' if `key' is an appropriate key to live in ** the array part of the table, -1 otherwise. */ static int arrayindex (const TValue *key) { if (ttisnumber(key)) { lua_Number n = nvalue(key); int k; lua_number2int(k, n); if (luai_numeq(cast_num(k), n)) return k; } return -1; /* `key' did not match some condition */ } /* ** returns the index of a `key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The ** beginning of a traversal is signaled by -1. */ static int findindex (lua_State *L, Table *t, StkId key) { int i; if (ttisnil(key)) return -1; /* first iteration */ i = arrayindex(key); if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ return i-1; /* yes; that's the index (corrected to C) */ else { Node *n = mainposition(t, key); for (;;) { /* check whether `key' is somewhere in the chain */ /* key may be dead already, but it is ok to use it in `next' */ if (luaV_rawequalobj(gkey(n), key) || (ttisdeadkey(gkey(n)) && iscollectable(key) && deadvalue(gkey(n)) == gcvalue(key))) { i = cast_int(n - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ return i + t->sizearray; } else n = gnext(n); if (n == NULL) luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ } } } int luaH_next (lua_State *L, Table *t, StkId key) { int i = findindex(L, t, key); /* find original element */ for (i++; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ setnvalue(key, cast_num(i+1)); setobj2s(L, key+1, &t->array[i]); return 1; } } for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ setobj2s(L, key, gkey(gnode(t, i))); setobj2s(L, key+1, gval(gnode(t, i))); return 1; } } return 0; /* no more elements */ } /* ** {============================================================= ** Rehash ** ============================================================== */ static int computesizes (int nums[], int *narray) { int i; int twotoi; /* 2^i */ int a = 0; /* number of elements smaller than 2^i */ int na = 0; /* number of elements to go to array part */ int n = 0; /* optimal size for array part */ for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { if (nums[i] > 0) { a += nums[i]; if (a > twotoi/2) { /* more than half elements present? */ n = twotoi; /* optimal size (till now) */ na = a; /* all elements smaller than n will go to array part */ } } if (a == *narray) break; /* all elements already counted */ } *narray = n; lua_assert(*narray/2 <= na && na <= *narray); return na; } static int countint (const TValue *key, int *nums) { int k = arrayindex(key); if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ nums[luaO_ceillog2(k)]++; /* count as such */ return 1; } else return 0; } static int numusearray (const Table *t, int *nums) { int lg; int ttlg; /* 2^lg */ int ause = 0; /* summation of `nums' */ int i = 1; /* count to traverse all array keys */ for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ int lc = 0; /* counter */ int lim = ttlg; if (lim > t->sizearray) { lim = t->sizearray; /* adjust upper limit */ if (i > lim) break; /* no more elements to count */ } /* count elements in range (2^(lg-1), 2^lg] */ for (; i <= lim; i++) { if (!ttisnil(&t->array[i-1])) lc++; } nums[lg] += lc; ause += lc; } return ause; } static int numusehash (const Table *t, int *nums, int *pnasize) { int totaluse = 0; /* total number of elements */ int ause = 0; /* summation of `nums' */ int i = sizenode(t); while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { ause += countint(gkey(n), nums); totaluse++; } } *pnasize += ause; return totaluse; } static void setarrayvector (lua_State *L, Table *t, int size) { int i; luaM_reallocvector(L, t->array, t->sizearray, size, TValue); for (i=t->sizearray; iarray[i]); t->sizearray = size; } static void setnodevector (lua_State *L, Table *t, int size) { int lsize; if (size == 0) { /* no elements to hash part? */ t->node = cast(Node *, dummynode); /* use common `dummynode' */ lsize = 0; } else { int i; lsize = luaO_ceillog2(size); if (lsize > MAXBITS) luaG_runerror(L, "table overflow"); size = twoto(lsize); t->node = luaM_newvector(L, size, Node); for (i=0; ilsizenode = cast_byte(lsize); t->lastfree = gnode(t, size); /* all positions are free */ } void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; int oldasize = t->sizearray; int oldhsize = t->lsizenode; Node *nold = t->node; /* save old hash ... */ if (nasize > oldasize) /* array part must grow? */ setarrayvector(L, t, nasize); /* create new hash part with appropriate size */ setnodevector(L, t, nhsize); if (nasize < oldasize) { /* array part must shrink? */ t->sizearray = nasize; /* re-insert elements from vanishing slice */ for (i=nasize; iarray[i])) luaH_setint(L, t, i + 1, &t->array[i]); } /* shrink array */ luaM_reallocvector(L, t->array, oldasize, nasize, TValue); } /* re-insert elements from hash part */ for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; if (!ttisnil(gval(old))) { /* doesn't need barrier/invalidate cache, as entry was already present in the table */ setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); } } if (!isdummy(nold)) luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old array */ } void luaH_resizearray (lua_State *L, Table *t, int nasize) { int nsize = isdummy(t->node) ? 0 : sizenode(t); luaH_resize(L, t, nasize, nsize); } static void rehash (lua_State *L, Table *t, const TValue *ek) { int nasize, na; int nums[MAXBITS+1]; /* nums[i] = number of keys with 2^(i-1) < k <= 2^i */ int i; int totaluse; for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ nasize = numusearray(t, nums); /* count keys in array part */ totaluse = nasize; /* all those keys are integer keys */ totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ /* count extra key */ nasize += countint(ek, nums); totaluse++; /* compute new size for array part */ na = computesizes(nums, &nasize); /* resize the table to new computed sizes */ luaH_resize(L, t, nasize, totaluse - na); } /* ** }============================================================= */ Table *luaH_new (lua_State *L) { Table *t = &luaC_newobj(L, LUA_TTABLE, sizeof(Table), NULL, 0)->h; t->metatable = NULL; t->flags = cast_byte(~0); t->array = NULL; t->sizearray = 0; setnodevector(L, t, 0); return t; } void luaH_free (lua_State *L, Table *t) { if (!isdummy(t->node)) luaM_freearray(L, t->node, cast(size_t, sizenode(t))); luaM_freearray(L, t->array, t->sizearray); luaM_free(L, t); } static Node *getfreepos (Table *t) { while (t->lastfree > t->node) { t->lastfree--; if (ttisnil(gkey(t->lastfree))) return t->lastfree; } return NULL; /* could not find a free place */ } /* ** inserts a new key into a hash table; first, check whether key's main ** position is free. If not, check whether colliding node is in its main ** position or not: if it is not, move colliding node to an empty place and ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { Node *mp; if (ttisnil(key)) luaG_runerror(L, "table index is nil"); else if (ttisnumber(key) && luai_numisnan(L, nvalue(key))) luaG_runerror(L, "table index is NaN"); mp = mainposition(t, key); if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ Node *othern; Node *n = getfreepos(t); /* get a free place */ if (n == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ /* whatever called 'newkey' take care of TM cache and GC barrier */ return luaH_set(L, t, key); /* insert key into grown table */ } lua_assert(!isdummy(n)); othern = mainposition(t, gkey(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ gnext(mp) = NULL; /* now `mp' is free */ setnilvalue(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ gnext(n) = gnext(mp); /* chain new position */ gnext(mp) = n; mp = n; } } setobj2t(L, gkey(mp), key); luaC_barrierback(L, obj2gco(t), key); lua_assert(ttisnil(gval(mp))); return gval(mp); } /* ** search function for integers */ const TValue *luaH_getint (Table *t, int key) { /* (1 <= key && key <= t->sizearray) */ if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) return &t->array[key-1]; else { lua_Number nk = cast_num(key); Node *n = hashnum(t, nk); do { /* check whether `key' is somewhere in the chain */ if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) return gval(n); /* that's it */ else n = gnext(n); } while (n); return luaO_nilobject; } } /* ** search function for short strings */ const TValue *luaH_getstr (Table *t, TString *key) { Node *n = hashstr(t, key); lua_assert(key->tsv.tt == LUA_TSHRSTR); do { /* check whether `key' is somewhere in the chain */ if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); return luaO_nilobject; } /* ** main search function */ const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNIL: return luaO_nilobject; case LUA_TNUMBER: { int k; lua_Number n = nvalue(key); lua_number2int(k, n); if (luai_numeq(cast_num(k), n)) /* index is int? */ return luaH_getint(t, k); /* use specialized version */ /* else go through */ } default: { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ if (luaV_rawequalobj(gkey(n), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); return luaO_nilobject; } } } /* ** beware: when using this function you probably need to check a GC ** barrier and invalidate the TM cache. */ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { const TValue *p = luaH_get(t, key); if (p != luaO_nilobject) return cast(TValue *, p); else return luaH_newkey(L, t, key); } void luaH_setint (lua_State *L, Table *t, int key, TValue *value) { const TValue *p = luaH_getint(t, key); TValue *cell; if (p != luaO_nilobject) cell = cast(TValue *, p); else { TValue k; setnvalue(&k, cast_num(key)); cell = luaH_newkey(L, t, &k); } setobj2t(L, cell, value); } static int unbound_search (Table *t, unsigned int j) { unsigned int i = j; /* i is zero or a present index */ j++; /* find `i' and `j' such that i is present and j is not */ while (!ttisnil(luaH_getint(t, j))) { i = j; j *= 2; if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; while (!ttisnil(luaH_getint(t, i))) i++; return i - 1; } } /* now do a binary search between them */ while (j - i > 1) { unsigned int m = (i+j)/2; if (ttisnil(luaH_getint(t, m))) j = m; else i = m; } return i; } /* ** Try to find a boundary in table `t'. A `boundary' is an integer index ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). */ int luaH_getn (Table *t) { unsigned int j = t->sizearray; if (j > 0 && ttisnil(&t->array[j - 1])) { /* there is a boundary in the array part: (binary) search for it */ unsigned int i = 0; while (j - i > 1) { unsigned int m = (i+j)/2; if (ttisnil(&t->array[m - 1])) j = m; else i = m; } return i; } /* else must find a boundary in hash part */ else if (isdummy(t->node)) /* hash part is empty? */ return j; /* that is easy... */ else return unbound_search(t, j); } #if defined(LUA_DEBUG) Node *luaH_mainposition (const Table *t, const TValue *key) { return mainposition(t, key); } int luaH_isdummy (Node *n) { return isdummy(n); } #endif blobby-1.0/src/input_device/JoystickPool.h000644 001750 001750 00000003755 12313310253 023465 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include "BlobbyDebug.h" class JoystickPool : public ObjectCounter { public: static JoystickPool& getSingleton(); SDL_Joystick* getJoystick(int id); void probeJoysticks(); void closeJoysticks(); private: typedef std::map JoyMap; JoyMap mJoyMap; static JoystickPool* mSingleton; }; struct JoystickAction : public ObjectCounter { enum Type { AXIS, BUTTON, // We don't implement these exotic input methods here // HAT, // TRACKBALL }; JoystickAction(std::string string); JoystickAction(int _joyid, Type _type, int _number) : type(_type), joy(0), joyid(_joyid), number(_number) {} ~JoystickAction(); JoystickAction(const JoystickAction& action); std::string toString(); Type type; SDL_Joystick* joy; int joyid; // Note: Axis are stored as the SDL axis +1, so we can used // the signedness as direction indication int number; }; blobby-1.0/doc/ScriptAPI_de.txt000644 001750 001750 00000005244 12313310254 021166 0ustar00danielknobedanielknobe000000 000000 Dieses Dokument beschreibt die neue Lua-Schnittstelle, mit der Bots für Blobby Volley 2 gescriptet werden. Sie basiert auf der alten Schnittstelle von Blobby Volley 1, ersetzt aber hässliche Funktionen und stellt bessere Möglichkeit zur Programmierung von korrektem Aufschlagsverhalten bereit. Die wichtigste Neuerung ist aber, dass der Bot immer für die linke Seite programmiert wird. Wenn der Bot auf der rechten Seite spielt, dreht Blobby Volley 2 automatisch alle Werte um. Folgende Funktionen können aufgerufen werden: left() : Ein Tastendruck nach links right() : Ein Tastendruck nach rechts jump() : Ein Tastendruck der Sprungtaste moveto(zahl) : Läuft zur angegebenen X-Koordinate. Die Bewegung ist leicht gepuffert, sonst würde der Blobby immer um die Zielstelle "vibrieren", da er sie niemals exakt erreichen kann. touches() : Gibt die Anzahl der Ballberührungen zurück. launched() : Gibt zurück ob der Blobby gerade springt und in der Luft ist. estimate() : Gibt die X-Koordinate der Stelle zurück, an der der Ball vorraussichtlich auftreffen wird. Kollisionen am Netz oder am Rand werden aber nicht miteinkalkuliert! estimx(zahl) : Gibt die X-Koordinate der Stelle zurück, in der sich der Ball nach der angegebenen Zahl von Physikschritten befinden wird. Auch hier ohne Kollisionsberechnung. estimy(zahl) : Gibt die Y-Koordinate der Stelle zurück, in der sich der Ball nach der angegebenen Zahl von Physikschritten befinden wird. Auch hier ohne Kollisionsberechnung. ballx() : Gibt die X-Koordinate der Ballposition zurück. bally() : Gibt die Y-Koordinate der Ballposition zurück. bspeedx() : Gibt die X-Koordinate der Ballgeschwindigkeit zurück. bspeedy() : Gibt die Y-Koordinate der Ballgeschwindigkeit zurück. posx() : Gibt die X-Koordinate der Spielerposition zurück. posy() : Gibt die Y-Koordinate der Spielerposition zurück. oppx() : Gibt die X-Koordinate der Gegnerposition zurück. oppy() : Gibt die Y-Koordinate der Gegnerposition zurück. debug(zahl) : Gibt die angegebene Zahl auf der Konsole aus. Nützlich zur Fehlersuche Zusätzlich kann der Funktionsumfang der Lua-Mathematikbibliothek genutzt werden. Deren Funktionen sind hier dokumentiert: http://www.lua.org/manual/5.1/manual.html#5.6 Ein Skript muss selber die folgenden Funktionen enthalten: function OnServe(ballready) : Wird aufgerufen nachdem der Ball abgepfiffen wurde und der gesteuerte Spieler nun aufschlägt. ballready gibt an, ob der Ball schon zurückgesetzt wurde. function OnOpponentServe() : Wird aufgerufen nachdem der Ball abgepfiffen und nun der Gegner aufschlägt. function OnGame() : Wird während des regulären Spiels aufgerufen blobby-1.0/src/state/ReplayState.cpp000644 001750 001750 00000014502 12313310253 022256 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "ReplayState.h" /* includes */ #include #include "IMGUI.h" #include "ReplayPlayer.h" #include "DuelMatch.h" #include "SoundManager.h" #include "TextManager.h" #include "SpeedController.h" #include "IUserConfigReader.h" #include "ReplaySelectionState.h" #include "InputManager.h" /* implementation */ extern const std::string DUMMY_RULES_NAME; ReplayState::ReplayState() { IMGUI::getSingleton().resetSelection(); mPositionJump = -1; mPaused = false; mSpeedValue = 8; mSpeedTimer = 0; } ReplayState::~ReplayState() { } void ReplayState::loadReplay(const std::string& file) { mReplayPlayer.reset( new ReplayPlayer() ); //try //{ mReplayPlayer->load(std::string("replays/" + file + ".bvr")); mMatch.reset(new DuelMatch(false, DUMMY_RULES_NAME)); SoundManager::getSingleton().playSound( "sounds/pfiff.wav", ROUND_START_SOUND_VOLUME); mMatch->setPlayers(mReplayPlayer->getPlayerName(LEFT_PLAYER), mReplayPlayer->getPlayerName(RIGHT_PLAYER)); mMatch->getPlayer(LEFT_PLAYER).setStaticColor(mReplayPlayer->getBlobColor(LEFT_PLAYER)); mMatch->getPlayer(RIGHT_PLAYER).setStaticColor(mReplayPlayer->getBlobColor(RIGHT_PLAYER)); SpeedController::getMainInstance()->setGameSpeed( (float)IUserConfigReader::createUserConfigReader("config.xml")->getInteger("gamefps") ); //} /*catch (ChecksumException& e) { delete mReplayRecorder; mReplayRecorder = 0; mChecksumError = true; } catch (VersionMismatchException& e) { delete mReplayRecorder; mReplayRecorder = 0; mVersionError = true; }*/ /// \todo reintroduce error handling } void ReplayState::step_impl() { IMGUI& imgui = IMGUI::getSingleton(); // only draw cursor when mouse moved or clicked in the last second if(mLastMousePosition != InputManager::getSingleton()->position() || InputManager::getSingleton()->click()) { /// \todo we must do this framerate independent mMouseShowTimer = 75; } if(mMouseShowTimer > 0) { imgui.doCursor(); mMouseShowTimer--; } mLastMousePosition = InputManager::getSingleton()->position(); if(mPositionJump != -1) { if(mReplayPlayer->gotoPlayingPosition(mPositionJump, mMatch.get())) mPositionJump = -1; } else if(!mPaused) { while( mSpeedTimer >= 8) { mPaused = !mReplayPlayer->play(mMatch.get()); mSpeedTimer -= 8; presentGame(); } mSpeedTimer += mSpeedValue; } mMatch->getClock().setTime( mReplayPlayer->getReplayPosition() / mReplayPlayer->getGameSpeed() ); // draw the progress bar Vector2 prog_pos = Vector2(50, 600-22); imgui.doOverlay(GEN_ID, prog_pos, Vector2(750, 600-3), Color(0,0,0)); imgui.doOverlay(GEN_ID, prog_pos, Vector2(700*mReplayPlayer->getPlayProgress()+50, 600-3), Color(0,255,0)); PlayerSide side = NO_PLAYER; if (mReplayPlayer->endOfFile()) { int diff = mMatch->getScore(LEFT_PLAYER) - mMatch->getScore(RIGHT_PLAYER); if (diff > 0) { side = LEFT_PLAYER; } else if (diff < 0) { side = RIGHT_PLAYER; } } // play/pause button imgui.doOverlay(GEN_ID, Vector2(350, 535.0), Vector2(450, 575.0)); bool pause_click = imgui.doImageButton(GEN_ID, Vector2(400, 555), Vector2(24, 24), mPaused ? "gfx/btn_play.bmp" : "gfx/btn_pause.bmp"); bool fast_click = imgui.doImageButton(GEN_ID, Vector2(430, 555), Vector2(24, 24), "gfx/btn_fast.bmp"); bool slow_click = imgui.doImageButton(GEN_ID, Vector2(370, 555), Vector2(24, 24), "gfx/btn_slow.bmp"); // handle these image buttons. IMGUI is not capable of doing this. if(side == NO_PLAYER) { // control replay position Vector2 mousepos = InputManager::getSingleton()->position(); if (mousepos.x + 5 > prog_pos.x && mousepos.y > prog_pos.y && mousepos.x < prog_pos.x + 700 && mousepos.y < prog_pos.y + 24.0) { if (InputManager::getSingleton()->click()) { float pos = (mousepos.x - prog_pos.x) / 700.0; mPositionJump = pos * mReplayPlayer->getReplayLength(); } } if (pause_click) { if(mPaused) { if(mReplayPlayer->endOfFile()) mPositionJump = 0; } mPaused = !mPaused; } if (fast_click) { mSpeedValue *= 2; if(mSpeedValue > 64) mSpeedValue = 64; } if (slow_click) { mSpeedValue /= 2; if(mSpeedValue < 1) mSpeedValue = 1; } if ((InputManager::getSingleton()->exit())) { switchState(new ReplaySelectionState()); return; } } else { displayWinningPlayerScreen(side); if (imgui.doButton(GEN_ID, Vector2(290, 350), TextManager::LBL_OK)) { switchState(new ReplaySelectionState()); return; } if (imgui.doButton(GEN_ID, Vector2(400, 350), TextManager::RP_SHOW_AGAIN)) { // we don't have to reset the match, cause we don't use lua rules // we just have to jump to the beginning SoundManager::getSingleton().playSound( "sounds/pfiff.wav", ROUND_START_SOUND_VOLUME); // do we really need this? // maybe, users want to replay the game on the current speed SpeedController::getMainInstance()->setGameSpeed( (float)IUserConfigReader::createUserConfigReader("config.xml")->getInteger("gamefps") ); mPaused = false; mPositionJump = 0; } imgui.doCursor(); } // show the game ui presentGameUI(); } const char* ReplayState::getStateName() const { return "ReplayState"; } blobby-1.0/src/raknet/InternalPacket.h000644 001750 001750 00000007047 12313310247 022547 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Define the Structure of an Internal Packet * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __INTERNAL_PACKET_H #define __INTERNAL_PACKET_H #include "PacketPriority.h" #ifdef _DEBUG #include "NetworkTypes.h" #endif /** * This must be able to hold the highest value of RECEIVED_PACKET_LOG_LENGTH. */ typedef unsigned short PacketNumberType; /** * Use unsigned char for most apps. Unsigned short if you send many packets at the same time on the same ordering stream * This has to be the same value on all systems */ // TODO - Change to unsigned short? typedef unsigned char OrderingIndexType; /** * @brief Structure of an Internal Packet * * Internal packets are used with the RakNet Network Library for internal * management only. */ struct InternalPacket { /** * True if this is an acknowledgment packet */ bool isAcknowledgement; /** * The number of this packet, used as an identifier */ PacketNumberType packetNumber; /** * The priority level of this packet */ PacketPriority priority; /** * What type of reliability algorithm to use with this packet */ PacketReliability reliability; /** * What ordering channel this packet is on, if the reliability type uses ordering channels */ unsigned char orderingChannel; /** * The ID used as identification for ordering channels */ OrderingIndexType orderingIndex; /** * The ID of the split packet, if we have split packets */ unsigned int splitPacketId; /** * If this is a split packet, the index into the array of subsplit packets */ unsigned int splitPacketIndex; /** * The size of the array of subsplit packets */ unsigned int splitPacketCount; /** * When this packet was created */ unsigned int creationTime; /** * The next time to take action on this packet */ unsigned int nextActionTime; /** * How many bits the data is */ unsigned int dataBitLength; /** * Buffer is a pointer to the actual data, assuming this packet has data at all */ char *data; }; #endif blobby-1.0/src/lua/llex.h000644 001750 001750 00000004162 12313310253 020074 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: llex.h,v 1.72.1.1 2013/04/12 18:48:47 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #ifndef llex_h #define llex_h #include "lobject.h" #include "lzio.h" #define FIRST_RESERVED 257 /* * WARNING: if you change the order of this enumeration, * grep "ORDER RESERVED" */ enum RESERVED { /* terminal symbols denoted by reserved words */ TK_AND = FIRST_RESERVED, TK_BREAK, TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_DBCOLON, TK_EOS, TK_NUMBER, TK_NAME, TK_STRING }; /* number of reserved words */ #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) typedef union { lua_Number r; TString *ts; } SemInfo; /* semantics information */ typedef struct Token { int token; SemInfo seminfo; } Token; /* state of the lexer plus state of the parser when shared by all functions */ typedef struct LexState { int current; /* current character (charint) */ int linenumber; /* input line counter */ int lastline; /* line of last token `consumed' */ Token t; /* current token */ Token lookahead; /* look ahead token */ struct FuncState *fs; /* current function (parser) */ struct lua_State *L; ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ struct Dyndata *dyd; /* dynamic structures used by the parser */ TString *source; /* current source name */ TString *envn; /* environment variable name */ char decpoint; /* locale decimal point */ } LexState; LUAI_FUNC void luaX_init (lua_State *L); LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, int firstchar); LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); LUAI_FUNC void luaX_next (LexState *ls); LUAI_FUNC int luaX_lookahead (LexState *ls); LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); #endif blobby-1.0/src/ScriptedInputSource.cpp000644 001750 001750 00000035441 12313310251 022662 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "ScriptedInputSource.h" /* includes */ #include #include #include #include extern "C" { #include "lua/lua.h" #include "lua/lauxlib.h" #include "lua/lualib.h" } #include "DuelMatch.h" #include "GameConstants.h" #include "BotAPICalculations.h" #include "FileRead.h" /* implementation */ const DuelMatch* ScriptedInputSource::mMatch = 0; ScriptedInputSource* ScriptedInputSource::mCurrentSource = 0; struct pos_x; struct pos_y; struct vel_x; struct vel_y; template float convert(float f); template struct ScriptedInputSource::coordinate { coordinate(float f) : value(convert(f)) { } coordinate(double f) : value(convert(f)) { } operator float() const { return value; } float value; private: // other constructors ar prohibited ! template coordinate(U u); static float convert(float f); }; // functions for coodinate transformation template<> float ScriptedInputSource::coordinate::convert (float val) { return mCurrentSource->mSide == LEFT_PLAYER ? val : RIGHT_PLANE - val; } template<> float ScriptedInputSource::coordinate::convert (float val) { return 600.f - val; } template<> float ScriptedInputSource::coordinate::convert (float val) { return mCurrentSource->mSide == LEFT_PLAYER ? val : -val; } template<> float ScriptedInputSource::coordinate::convert (float val) { return -val; } ScriptedInputSource::ScriptedInputSource(const std::string& filename, PlayerSide playerside, unsigned int difficulty) : mMaxDelay(difficulty) , mCurDelay(difficulty) , mLastBallSpeed(0) , mSide(playerside) { mStartTime = SDL_GetTicks(); // set game constants setGameConstants(); //luaopen_math(mState); luaL_requiref(mState, "math", luaopen_math, 1); lua_register(mState, "touches", touches); lua_register(mState, "launched", launched); lua_register(mState, "debug", debug); lua_register(mState, "jump", jump); lua_register(mState, "moveto", moveto); lua_register(mState, "left", left); lua_register(mState, "right", right); lua_register(mState, "ballx", ballx); lua_register(mState, "bally", bally); lua_register(mState, "bspeedx", bspeedx); lua_register(mState, "bspeedy", bspeedy); lua_register(mState, "posx", posx); lua_register(mState, "posy", posy); lua_register(mState, "oppx", oppx); lua_register(mState, "oppy", oppy); lua_register(mState, "estimate", estimate); lua_register(mState, "estimx", estimx); lua_register(mState, "estimy", estimy); lua_register(mState, "timetox", timetox); lua_register(mState, "timetoy", timetoy); lua_register(mState, "predictx", predictx); lua_register(mState, "predicty", predicty); lua_register(mState, "xaty", xaty); lua_register(mState, "yatx", yatx); lua_register(mState, "nextevent", nextevent); lua_register(mState, "predictImpact", predictImpact); lua_register(mState, "getScore", getScore); lua_register(mState, "getOppScore", getOppScore); lua_register(mState, "getScoreToWin", getScoreToWin); lua_register(mState, "getGameTime", getGameTime); //lua_register(mState, "parabel", parabel); int error = FileRead::readLuaScript(filename, mState); if (error == 0) error = lua_pcall(mState, 0, 6, 0); if (error) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; ScriptException except; except.luaerror = lua_tostring(mState, -1); BOOST_THROW_EXCEPTION(except); } // check whether all required lua functions are available bool onserve, ongame, onoppserve; onserve = getLuaFunction("OnServe"); ongame = getLuaFunction("OnGame"); onoppserve = getLuaFunction("OnOpponentServe"); if (!onserve || !ongame ||!onoppserve) { std::string error_message = "Missing bot function "; error_message += onserve ? "" : "OnServe() "; error_message += ongame ? "" : "OnGame() "; error_message += onoppserve ? "" : "OnOpponentServe() "; std::cerr << "Lua Error: " << error_message << std::endl; ScriptException except; except.luaerror = error_message; BOOST_THROW_EXCEPTION(except); } // record which of the optional functions are available mOnBounce = getLuaFunction("OnBounce"); if(!mOnBounce) { std::cerr << "Lua Warning: Missing function OnBounce" << std::endl; } // clean up stack lua_pop(mState, lua_gettop(mState)); // init delay mBallPositions.set_capacity(mMaxDelay + 1); mBallVelocities.set_capacity(mMaxDelay + 1); for(unsigned int i = 0; i < mMaxDelay + 1; ++i) { mBallPositions.push_back(Vector2(0,0)); mBallVelocities.push_back(Vector2(0,0)); } } ScriptedInputSource::~ScriptedInputSource() { } PlayerInputAbs ScriptedInputSource::getNextInput() { bool serving = false; // reset input mLeft = false; mRight = false; mJump = false; mCurrentSource = this; mMatch = getMatch(); if (mMatch == 0) { return PlayerInputAbs(); } // ball position and velocity update mBallPositions.push_back(mMatch->getBallPosition()); mBallVelocities.push_back(mMatch->getBallVelocity()); // adapt current delay char action = rand() % 8; switch(action) { case 0: case 1: mCurDelay--; break; case 2: case 3: mCurDelay++; } if ( mLastBallSpeed != getMatch()->getBallVelocity().x ) { mLastBallSpeed = getMatch()->getBallVelocity().x; // reaction time after bounce mCurDelay += rand() % (mMaxDelay+1); } if(mCurDelay == -1) mCurDelay = 0; if(mCurDelay > mMaxDelay) mCurDelay = mMaxDelay; int error = 0; if (!mMatch->getBallActive() && mSide == // if no player is serving player, assume the left one is (mMatch->getServingPlayer() == NO_PLAYER ? LEFT_PLAYER : mMatch->getServingPlayer() )) { serving = true; lua_getglobal(mState, "OnServe"); lua_pushboolean(mState, !mMatch->getBallDown()); error = lua_pcall(mState, 1, 0, 0); } else if (!mMatch->getBallActive() && mCurrentSource->mSide != (mMatch->getServingPlayer() == NO_PLAYER ? LEFT_PLAYER : mMatch->getServingPlayer() )) { lua_getglobal(mState, "OnOpponentServe"); error = lua_pcall(mState, 0, 0, 0); } else { if ( mOnBounce && mLastBallSpeedVirtual != getBallVelocity().x ) { mLastBallSpeedVirtual = getBallVelocity().x; lua_getglobal(mState, "OnBounce"); error = lua_pcall(mState, 0, 0, 0); if (error) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; lua_pop(mState, 1); } } lua_getglobal(mState, "OnGame"); error = lua_pcall(mState, 0, 0, 0); } if (error) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; lua_pop(mState, 1); } // swap left/right if side is swapped if ( mSide == RIGHT_PLAYER ) std::swap(mLeft, mRight); int stacksize = lua_gettop(mState); if (stacksize > 0) { std::cerr << "Warning: Stack messed up!" << std::endl; std::cerr << "Element on stack is a "; std::cerr << lua_typename(mState, -1) << std::endl; lua_pop(mState, stacksize); } if (mStartTime + WAITING_TIME > SDL_GetTicks() && serving) return PlayerInputAbs(); else return PlayerInputAbs(mLeft, mRight, mJump); } void ScriptedInputSource::setflags(lua_State* state) { lua_pushnumber(state, FLAG_BOUNCE); lua_setglobal(state, "FLAG_BOUNCE"); } int ScriptedInputSource::touches(lua_State* state) { lua_pushnumber(state, mMatch->getHitcount(mCurrentSource->mSide)); return 1; } int ScriptedInputSource::launched(lua_State* state) { lua_pushnumber(state, mMatch->getBlobJump(mCurrentSource->mSide)); return 1; } int ScriptedInputSource::debug(lua_State* state) { float number = lua_tonumber(state, -1); lua_pop(state, 1); std::cerr << "Lua Debug: " << number << std::endl; return 0; } int ScriptedInputSource::jump(lua_State* state) { mCurrentSource->mJump = true; return 0; } int ScriptedInputSource::left(lua_State* state) { mCurrentSource->mLeft = true; return 0; } int ScriptedInputSource::right(lua_State* state) { mCurrentSource->mRight = true; return 0; } int ScriptedInputSource::moveto(lua_State* state) { float target = lua_tonumber(state, -1); lua_pop(state, 1); coordinate position = mMatch->getBlobPosition(mCurrentSource->mSide).x; if (position > target + 2) mCurrentSource->mLeft = true; if (position < target - 2) mCurrentSource->mRight = true; return 0; } const Vector2& ScriptedInputSource::getBallPosition() { return mCurrentSource->mBallPositions[mCurrentSource->mMaxDelay - mCurrentSource->mCurDelay]; } const Vector2& ScriptedInputSource::getBallVelocity() { return mCurrentSource->mBallVelocities[mCurrentSource->mMaxDelay - mCurrentSource->mCurDelay]; } int ScriptedInputSource::ballx(lua_State* state) { coordinate pos = getBallPosition().x; lua_pushnumber(state, pos); return 1; } int ScriptedInputSource::bally(lua_State* state) { coordinate pos = getBallPosition().y; lua_pushnumber(state, pos); return 1; } int ScriptedInputSource::bspeedx(lua_State* state) { coordinate vel = getBallVelocity().x; lua_pushnumber(state, vel); return 1; } int ScriptedInputSource::bspeedy(lua_State* state) { coordinate vel = getBallVelocity().y; lua_pushnumber(state, vel); return 1; } int ScriptedInputSource::posx(lua_State* state) { coordinate pos = mMatch->getBlobPosition(mCurrentSource->mSide).x; lua_pushnumber(state, pos); return 1; } int ScriptedInputSource::posy(lua_State* state) { coordinate pos = mMatch->getBlobPosition(mCurrentSource->mSide).y; lua_pushnumber(state, pos); return 1; } int ScriptedInputSource::oppx(lua_State* state) { PlayerSide invPlayer = mCurrentSource->mSide == LEFT_PLAYER ? RIGHT_PLAYER : LEFT_PLAYER; coordinate pos = mMatch->getBlobPosition(invPlayer).x; lua_pushnumber(state, pos); return 1; } int ScriptedInputSource::oppy(lua_State* state) { PlayerSide invPlayer = mCurrentSource->mSide == LEFT_PLAYER ? RIGHT_PLAYER : LEFT_PLAYER; coordinate pos = mMatch->getBlobPosition(invPlayer).y; lua_pushnumber(state, pos); return 1; } int ScriptedInputSource::estimate(lua_State* state) { static bool warning_issued = false; if( !warning_issued ) { warning_issued = true; std::cerr << "Lua Warning: function estimate() is deprecated!" << std::endl; } Vector2 pos = getBallPosition(); const Vector2& vel = getBallVelocity(); float time = (vel.y - std::sqrt((vel.y * vel.y)- (-2 * BALL_GRAVITATION * (-pos.y + GROUND_PLANE_HEIGHT_MAX - BALL_RADIUS)))) / (-BALL_GRAVITATION); coordinate estim = pos.x + vel.x * time; lua_pushnumber(state, estim); return 1; } int ScriptedInputSource::estimx(lua_State* state) { static bool warning_issued = false; if( !warning_issued ) { warning_issued = true; std::cerr << "Lua Warning: function estimx() is deprecated!" << std::endl; } int num = lround(lua_tonumber(state, -1)); lua_pop(state, 1); coordinate estim = getBallPosition().x + num * getBallVelocity().x; lua_pushnumber(state, estim); return 1; } int ScriptedInputSource::estimy(lua_State* state) { static bool warning_issued = false; if( !warning_issued ) { warning_issued = true; std::cerr << "Lua Warning: function estimy() is deprecated!" << std::endl; } int num = lround(lua_tonumber(state, -1)); lua_pop(state, 1); coordinate estim = getBallPosition().y + num * (getBallVelocity().y + 0.5*BALL_GRAVITATION*num); lua_pushnumber(state, estim); return 1; } int ScriptedInputSource::predictx(lua_State* state) { reset_flags(); float time = lua_tonumber(state, -1); lua_pop(state, 1); coordinate estim = predict_x(getBallPosition(), getBallVelocity(), time); lua_pushnumber(state, estim); setflags(state); return 1; } int ScriptedInputSource::predicty(lua_State* state) { reset_flags(); float time = lua_tonumber(state, -1); lua_pop(state, 1); coordinate estim = predict_y(getBallPosition(), getBallVelocity(), time); lua_pushnumber(state, estim); setflags(state); return 1; } int ScriptedInputSource::timetox(lua_State* state) { reset_flags(); coordinate destination = lua_tonumber(state, -1); lua_pop(state, 1); float time = time_to_x(getBallPosition(), getBallVelocity(), destination); lua_pushnumber(state, time); setflags(state); return 1; } int ScriptedInputSource::timetoy(lua_State* state) { reset_flags(); coordinate destination = lua_tonumber(state, -1); lua_pop(state, 1); float time = time_to_y(getBallPosition(), getBallVelocity(), destination); lua_pushnumber(state, time); setflags(state); return 1; } int ScriptedInputSource::xaty(lua_State* state) { reset_flags(); coordinate destination = lua_tonumber(state, -1); lua_pop(state, 1); coordinate x = x_at_y(getBallPosition(), getBallVelocity(), destination); lua_pushnumber(state, x); setflags(state); return 1; } int ScriptedInputSource::yatx(lua_State* state) { reset_flags(); coordinate destination = lua_tonumber(state, -1); lua_pop(state, 1); coordinate y = y_at_x(getBallPosition(), getBallVelocity(), destination); lua_pushnumber(state, y); setflags(state); return 1; } int ScriptedInputSource::predictImpact(lua_State* state) { reset_flags(); coordinate x = x_at_y(getBallPosition(), getBallVelocity(), GROUND_PLANE_HEIGHT_MAX - BLOBBY_HEIGHT - BALL_RADIUS); lua_pushnumber(state, x); setflags(state); return 1; } int ScriptedInputSource::nextevent(lua_State* state) { reset_flags(); float time = next_event(getBallPosition(), getBallVelocity()); lua_pushnumber(state, time); setflags(state); return 1; } int ScriptedInputSource::getScore(lua_State* state) { float score = mMatch->getScore( mCurrentSource->mSide ); lua_pushnumber(state, score); return 1; } int ScriptedInputSource::getOppScore(lua_State* state) { float score = mMatch->getScore( mCurrentSource->mSide == LEFT_PLAYER ? RIGHT_PLAYER: LEFT_PLAYER ); lua_pushnumber(state, score); return 1; } int ScriptedInputSource::getScoreToWin(lua_State* state) { float score = mMatch->getScoreToWin(); lua_pushnumber(state, score); return 1; } int ScriptedInputSource::getGameTime(lua_State* state) { float time = mMatch->getClock().getTime(); lua_pushnumber(state, time); return 1; } blobby-1.0/data/gfx/cursor.bmp000644 001750 001750 00000015466 12313310254 021133 0ustar00danielknobedanielknobe000000 000000 BM66(00  QQ__#A#JvJkkjj]]k>c",D,mmdd__bakkPM H hife``bb__SQ@7$C6&`^jia`cca`HE*$7/Ev͢J}Jddb`^^\\DD&"&(Muh5*4b4RQPQTVKJ9}9#"& IR`fZ\$<82X2ORAB;;55+*'%/,IHa_hHri*7*ihVV=>''%$?9WL`_ZΊzhhii^^DE%%"!=9Z_dx_^|yɼaaiibbaaNN3363OL]~]\~UUll``___`WXDBA;MRVXl-/1Ae?hh__^_]]`_]\OGE9DnJdCSP!J!SSZZ^^^^]__^`YW`G>K{Vyr&=%==@@RS\\\]]]_[_Z\NGxc8f6B@7&2&aaCC46HIUW[[^\_Y^X_TsqON<>UU^]`\dbr?`W]]^^HH9746LMddcbdd``_]_^bbYW:855QPdcggjj.F8&6&jj^_RQAA34;=RRb`b__^^^^Za```FF33HJ_`ba2X2FoFlj_]YXKL;;54BCWZ_e_k^z^e_YcaVU22**;=Uc`{__`dmSG# p 8Y8kl`a_]^^\\XVJH7448Gj^aa\N9v'$MKef`_^^]\^^\]UWC\4[=fU^\I13-cTT`a`a^^]]^`\fZcMv9q2@I@-0LSkg < IJ[Z`b_^^_]\][\`Ut@$*,0Mom'`&>@ST_^___\_k^_ZA-L|ߚ98ABLLWW_^_[_q``W52WҀޥ-85-J-TSGIDEJJYV````ZD%CtܤUUeeONBAB?QJbld]D),FЂݠnghdeUVHFA>MW^^G''IՌ޶ 6W6mm`a\\SPGECmG:%#Oѐ,63TTji`^a_afK]+z$hښƸ5B>ggcc`\d[^c7 kذʽAPM4V4mlc_b\ZQAbl׮DWPUUkhg_Zb9h Mۣ߰Pe`kjhaS]6r#)Uۨb|u%C%khLD:8vߟ`~PE:'2X tj +b(Z.64@V¥5B=:6(ʜDJH"VɽCTU@z(d]2"blobby-1.0/data/scripts/000755 001750 001750 00000000000 12313310254 020005 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/FileWrite.h000644 001750 001750 00000010330 12313310251 020231 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "File.h" /** \class FileWrite \brief File interface extesion for writing. \details This class provides methods for writing various data to files. Whenever a file is opened for writing, all its previous content is erased, or, in case it did not exist beforehand, the file is created. \sa FileRead */ class FileWrite : public File { public: /// \brief default ctor /// \details File has to be opended with open() /// \throw nothing explicit FileWrite(); /// \brief constructor which opens a file. /// \param filename File to be opened for writing /// \param no_override Set to true if you want to forbid writing over existing file. /// \throw FileLoadException, if the file could not be loaded /// \throw FileAlreadyExistsException in case of trying to write over existing file with no_override = true FileWrite(const std::string& filename, bool no_override = false); /// \brief opens a file. /// \param filename File to be opened for writing /// \param no_override Set to true if you want to forbid writing over existing file. /// \throw FileLoadException, if the file could not be created /// \throw FileAlreadyExistsException in case of trying to write over existing file with no_override = true /// \pre No file is currently opened. void open(const std::string& filename, bool no_override = false); /// destructor, closes the file (if any open) /// \sa close() /// \throw nothing ~FileWrite(); // ------------------------------------ // writing interface // ------------------------------------ /// \brief writes one character /// \details writes exactly the one character supplied. /// \throw PhysfsFileException when Physfs reports an error. /// \throw NoFileOpenedException when called while no file is opened. void writeByte(char c); /// \brief writes 32 bit integer /// \details writes an integer, converted to little endian if necessary /// \throw PhysfsFileException when Physfs reports an error. /// \throw NoFileOpenedException when called while no file is opened. void writeUInt32(uint32_t v); /// \brief writes a single precision float /// \throw PhysfsException when Physfs reports an error. /// \throw NoFileOpenedException when called while no file is opened. void writeFloat(float fl); /// \brief writes a std::string /// \details writes the content of the string to the file. /// does not write a null-termination character /// \throw PhysfsFileException when Physfs reports an error /// \throw NoFileOpenedException when called while no file is opened. void write(const std::string& data); /// \brief writes null-terminated std::string /// \details writes the content of the string to the file. /// ends the string with a null terminator. /// \throw NoFileOpenedException when called while no file is opened. /// \throw PhysfsFileException when Physfs reports an error void writeNullTerminated(const std::string& data); /// \brief writes a sequence of characters /// \details writes \p length characters from \p data to the file /// \throw PhysfsFileException when Physfs reports an error void write(const char* data, std::size_t length); }; blobby-1.0/doxyfile000644 001750 001750 00000210673 12313310247 017166 0ustar00danielknobedanielknobe000000 000000 # Doxyfile 1.7.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "Blobby Volley 2" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = "1.0 RC2" # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ./src/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.py \ *.f90 \ *.f \ *.vhd \ *.vhdl # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = src/lua \ src/raknet \ src/tinyxml # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = YES # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvances is that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans.ttf # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES blobby-1.0/src/GameConstants.h000644 001750 001750 00000005521 12313310253 021115 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #include // Difficulty Settings const float BALL_SPEED_FACTOR = 1.00; // Border Settings const float LEFT_PLANE = 0; const float RIGHT_PLANE = 800.0; // These numbers should include the blobbys width, but in the original game // the blobbys can go a bit into the walls too. // Blobby Settings const float BLOBBY_HEIGHT = 89; //const float BLOBBY_WIDTH = 75; // what is the meaning of this value ??????? const float BLOBBY_UPPER_SPHERE = 19; const float BLOBBY_UPPER_RADIUS = 25; const float BLOBBY_LOWER_SPHERE = 13; const float BLOBBY_LOWER_RADIUS = 33; // Ground Settings const float GROUND_PLANE_HEIGHT_MAX = 500; const float GROUND_PLANE_HEIGHT = GROUND_PLANE_HEIGHT_MAX - BLOBBY_HEIGHT / 2.0; // This is exactly the half of the gravitation, i checked it in // the original code const float BLOBBY_MAX_JUMP_HEIGHT = GROUND_PLANE_HEIGHT - 206.375; // GROUND_Y - MAX_Y const float BLOBBY_JUMP_ACCELERATION = 15.1; // these values are calculated from the other two const float GRAVITATION = BLOBBY_JUMP_ACCELERATION * BLOBBY_JUMP_ACCELERATION / BLOBBY_MAX_JUMP_HEIGHT; const float BLOBBY_JUMP_BUFFER = GRAVITATION / 2; // Ball Settings const float BALL_RADIUS = 31.5; const float BALL_GRAVITATION = 0.287 * BALL_SPEED_FACTOR * BALL_SPEED_FACTOR; const float BALL_COLLISION_VELOCITY = std::sqrt(0.75 * RIGHT_PLANE * BALL_GRAVITATION); /// \todo work on a full-fledged physics spec // Volley Ball Net const float NET_POSITION_X = RIGHT_PLANE / 2; const float NET_POSITION_Y = 438; const float NET_RADIUS = 7; //const float NET_SPHERE = 154; // what is the meaning of this value ??????? const float NET_SPHERE_POSITION = 284; const float STANDARD_BALL_HEIGHT = 269 + BALL_RADIUS; const float BLOBBY_SPEED = 4.5; // BLOBBY_SPEED is necessary to determine the size of the input buffer const float STANDARD_BALL_ANGULAR_VELOCITY = 0.1; blobby-1.0/data/gfx/font13.bmp000644 001750 001750 00000003370 12313310254 020717 0ustar00danielknobedanielknobe000000 000000 BM6(  l%kNM2/%#  3ӵ#]WKED=@7?44*   ^K,ҭ !y).~1ql+SH3-    r?pjlG3Ŀ79[g\Lwt;MC%)* 2"/nQЦ7/&S1G]x֚_[W>10$ wyT̲5(jX`׷bZ]/24 D+>^Ǣ8Q!BfR{)+B  qt–GV*J pmcϠ_?#Q iJ`b[SOJE)$    )!A9O;Jg,;9.|s||ql[UGB>9F?WPocjX=_,8Z5}uΜ➟喛㐘㋜Ҋsd?W5 blobby-1.0/src/state/LocalGameState.cpp000644 001750 001750 00000010706 12313310253 022650 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "LocalGameState.h" /* includes */ #include #include #include "DuelMatch.h" #include "InputManager.h" #include "IMGUI.h" #include "ReplayRecorder.h" #include "SoundManager.h" #include "TextManager.h" #include "SpeedController.h" #include "IUserConfigReader.h" #include "InputSourceFactory.h" /* implementation */ LocalGameState::~LocalGameState() { } LocalGameState::LocalGameState() : mRecorder(new ReplayRecorder()), mWinner(false) { boost::shared_ptr config = IUserConfigReader::createUserConfigReader("config.xml"); PlayerIdentity leftPlayer = config->loadPlayerIdentity(LEFT_PLAYER, false); PlayerIdentity rightPlayer = config->loadPlayerIdentity(RIGHT_PLAYER, false); boost::shared_ptr leftInput = InputSourceFactory::createInputSource( config, LEFT_PLAYER); boost::shared_ptr rightInput = InputSourceFactory::createInputSource( config, RIGHT_PLAYER); // create default replay name setDefaultReplayName(leftPlayer.getName(), rightPlayer.getName()); // set speed SpeedController::getMainInstance()->setGameSpeed( (float)config->getInteger("gamefps") ); SoundManager::getSingleton().playSound("sounds/pfiff.wav", ROUND_START_SOUND_VOLUME); mMatch.reset(new DuelMatch( false, config->getString("rules"))); mMatch->setPlayers(leftPlayer, rightPlayer); mMatch->setInputSources(leftInput, rightInput); mRecorder->setPlayerNames(leftPlayer.getName(), rightPlayer.getName()); mRecorder->setPlayerColors( leftPlayer.getStaticColor(), rightPlayer.getStaticColor() ); mRecorder->setGameSpeed((float)config->getInteger("gamefps")); } void LocalGameState::step_impl() { IMGUI& imgui = IMGUI::getSingleton(); if(mErrorMessage != "") { displayErrorMessageBox(); } else if (mSaveReplay) { if ( displaySaveReplayPrompt() ) { saveReplay( *mRecorder.get() ); } } else if (mMatch->isPaused()) { imgui.doOverlay(GEN_ID, Vector2(180, 200), Vector2(670, 400)); imgui.doText(GEN_ID, Vector2(281, 260), TextManager::LBL_CONF_QUIT); if (imgui.doButton(GEN_ID, Vector2(530, 300), TextManager::LBL_NO)){ mMatch->unpause(); } if (imgui.doButton(GEN_ID, Vector2(260, 300), TextManager::LBL_YES)) { switchState(new MainMenuState); } if (imgui.doButton(GEN_ID, Vector2(293, 340), TextManager::RP_SAVE)) { mSaveReplay = true; imgui.resetSelection(); } imgui.doCursor(); } else if (mWinner) { displayWinningPlayerScreen( mMatch->winningPlayer() ); if (imgui.doButton(GEN_ID, Vector2(290, 350), TextManager::LBL_OK)) { switchState(new MainMenuState()); } if (imgui.doButton(GEN_ID, Vector2(400, 350), TextManager::GAME_TRY_AGAIN)) { switchState(new LocalGameState()); } if (imgui.doButton(GEN_ID, Vector2(320, 390), TextManager::RP_SAVE)) { mSaveReplay = true; imgui.resetSelection(); } } else if (InputManager::getSingleton()->exit()) { if (mSaveReplay) { mSaveReplay = false; IMGUI::getSingleton().resetSelection(); } else if (mMatch->isPaused()) { switchState(new MainMenuState); } else { RenderManager::getSingleton().redraw(); mMatch->pause(); } } else { mRecorder->record(mMatch->getState()); mMatch->step(); if (mMatch->winningPlayer() != NO_PLAYER) { mWinner = true; mRecorder->record(mMatch->getState()); mRecorder->finalize( mMatch->getScore(LEFT_PLAYER), mMatch->getScore(RIGHT_PLAYER) ); } presentGame(); } presentGameUI(); } const char* LocalGameState::getStateName() const { return "LocalGameState"; } blobby-1.0/data/gfx/font21.bmp000644 001750 001750 00000003370 12313310254 020716 0ustar00danielknobedanielknobe000000 000000 BM6( GZI6H8!0#     CMDOjT0F5%=+#@*#I,+[6)c5%k3!o.k&h!^ckḑĭnvWy^Oy[KYQa_u`vYnNb5J'9& dje֭Ŵ{}Ǧ̨ɣ{Zp5HԻĜ7B<%& #+%&.'#)&# 766ֳ¾FJL ү``hYX[ʱxoŸŲ̓~A8Gulv䲐W=[ ϢՇ\6$:zk|pd>i "!ԫߑN57ph\+`  @3Aʼn~@#$’ISW\F\T~$')ѓp5Z\ `G_A~#$%͇`-HJWH%7)8v3i!m]4  7-7~l0qblobby-1.0/data/gfx/sch13.bmp000644 001750 001750 00000030066 12313310254 020530 0ustar00danielknobedanielknobe000000 000000 BM606( 0  333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333blobby-1.0/data/scripts/reduced.lua000644 001750 001750 00000010016 12313310254 022121 0ustar00danielknobedanielknobe000000 000000 -- Reduced but very effective bot. -- Borrows from axji.lua, com_10.lua and com_11.lua as distributed with -- Blobby Volley. -- Copyright (C) 2010 Soeren D. Schulze -- The terms of the GPLv2 or later apply. -- See the Blobby Volley distribution for the license text. -- 15.01.14 - ngc92: Use blobby volley api provided constants when possible modeLock = 0 timeto = 0 target = 0 naivetarget = 0 estimbspeedx = 0 direct = true servrand = nil -- Konstanten CONST_MITTE = CONST_FIELD_WIDTH/2 CONST_RECHTER_RAND = CONST_FIELD_WIDTH - CONST_BALL_RADIUS -- Berührungsebene des Balls falls er ans Netz kommt CONST_NETZ_LINKS = CONST_MITTE - CONST_NET_RADIUS - CONST_BALL_RADIUS CONST_NETZ_RECHTS = CONST_MITTE + CONST_NET_RADIUS + CONST_BALL_RADIUS CONST_BLOBBY_KOPF_BERUEHRUNG = CONST_GROUND_HEIGHT + CONST_BLOBBY_HEIGHT + CONST_BALL_RADIUS -- TODO calculate this from constants CONST_BLOBBY_MAXJUMP = 393.625 function OnServe(ballready) if servrand == nil then servrand = math.random() end moveto(ballx() + servrand * 5) if ballready and math.abs(posx() - (ballx() + servrand * 5)) < 3 then jump() servrand = nil end end function OnOpponentServe() moveto(100) end function OnGame() estimImpactHigh() if (not (target == nil)) and naivetarget < 400 and (modeLock == 1 or timeto > math.abs(posx()-highPlayPos())/4.5 + 26) and touches() < 3 then if (timeto < 30) then modeLock = 1 else modeLock = 0 servrand = nil end highPlay() else modeLock = 0 servrand = nil estimImpactLow() if (not (target == nil)) and ((estimbspeedx > 0 and timeto > (target-posx()-10)/4.5) or (estimbspeedx < 0 and timeto > (posx()-target-10)/4.5) or naivetarget >= 400) then lowPlay() else -- HEELLPPP... if not (target == nil) and naivetarget < 400 then -- This often saves your ass if you're standing inside a -- corner and the ball bounces from the wall or the net. lowPlay() jump() end end end end function highPlayPos() if estimbspeedx < 0 then -- safety againt fast balls return target - 50 - estimbspeedx*5 else return target - 50 end end function highPlay() if (target > 400) then moveto(100) else moveto(highPlayPos()) -- 33 time units for jumping to max height -- Regarding naive target here. -- If the ball really bounces back, it would be a bad idea to jump... if servrand == nil then servrand = math.random() end if naivetarget < 400 and timeto < 28 + servrand then jump() end end end function lowPlay() if (target > 400) then moveto(100) else moveto(target) end end function estimImpactHigh() estimImpact2(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_MAXJUMP - 25,1) end function estimImpactLow() estimImpact2(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_KOPF_BERUEHRUNG,1) end function estimImpact2(bx,by,vbx,vby,destY,Frage) -- erlaubt ein besseres Estimate mit ein paar unbeding nötigen Angaben bgrav = -CONST_BALL_GRAVITY if ((vby^2)-(-2*bgrav*(by-destY))) < 0 then target = nil return end time1 =(-vby-math.sqrt((vby^2)-(-2*bgrav*(by-destY))))/(-bgrav) --time2 =(-vby+math.sqrt((vby^2)-(-2*bgrav*(by-destY))))/(-bgrav) timeto = time1 if (timeto < 0) then target = nil return end naivetarget = (vbx * time1) + bx resultX = naivetarget estimbspeedx=bspeedx() direct = true if(resultX > CONST_RECHTER_RAND) then resultX = 2 * CONST_RECHTER_RAND - resultX estimbspeedx=-estimbspeedx direct = true end if(resultX < CONST_BALL_RADIUS) then -- korrigieren der Appraller an der linken Ebene resultX = 2 * CONST_BALL_RADIUS - resultX estimbspeedx=-estimbspeedx direct = false end if (estimbspeedx > 0) and (resultX > CONST_NETZ_LINKS) then direct = false resultX = 2 * CONST_NETZ_LINKS - resultX estimbspeedx=-estimbspeedx end target = resultX end blobby-1.0/data/backgrounds/000755 001750 001750 00000000000 12313310255 020621 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/data/sounds/pfiff.wav000644 001750 001750 00000047132 12313310256 021453 0ustar00danielknobedanielknobe000000 000000 RIFFRNWAVEfmt DDfact Ndata NМc//////HКc//////Lʘd2/////PÔe8/////WйhA////:]˯lL5//4IeȹpYH@@HXmvg]XY`iv|wtrtwz~~~wpiefjr}}l\PKMWfzz`I936D[xͷxV8///4RwÞuL/////Jv̢sD/////DuФp=/////@uЦo8/////>vЦm5/////>wХl4/////@xУl6/////DzРl9/////H{ɜm@/////P|nG////5W}ϴpP8//0D`ɼt\J@?GVjxi^XX^gt}wtrtvz}~~xpjfeip{n^RLLTdwdM;34AWtм}[DPcx}maZX\dp|xtrsux|~~{slgegmwtcUMKP]plT@44BM`upcZX[cmzztsstx|~|tmgegluweWMKP\mpWC63:LeƭkJ0///>_жf>////2Yпa4/////Uđ]//////SȑZ//////QɑX//////RȐW//////TŏW//////WX//////Zй\0////5`в`;////@eƨdG1//7NkƵkUF?@L\qsd\XZ`lxzusstw{~~}umhefktyhYOKNYju[E728H`~ɲpO4///:YмmD/////SŘi;/////M̙f4/////JКc//////IК`//////IЙ`//////K͘`//////Nȕ`0/////Sc7////0Xиf@////<_ʭjK4//4JgȸoXH@@IZnug]XY`jv|vsrtwz~~~woiefjr}|k[PKMWg{y_H937E\z̶wT7///5TxœtJ/////Lx̠pA/////GxТn;/////BxУl6/////@xУj3/////@zУi2/////B{Рi4/////F|Нi7/////K}Țj=/////QоmF////7YγpP7//1Faɼt\J@@GWjxh^XY^ht|wtrtwz}~~xpjfeip{m]QLLTdx}dL;35BXtϺ|Z;///1NrǣzP/////EpЧxI/////?pЪwC/////:oЬu=/////8pЬt;/////8pЬs://///:qЩr///>Xw|cOB>DPdz}m`ZX\dp}xtrsux|~~zslgegmxsbTMLQ^plS@44=Pk§dD////Dfа]7////:bжX/////1`кS//////]нO//////]оL//////]нL//////_лL//////aжN/////4dаR/////=hϩW4////Hm^B///;TqðgQD>CN`vpcZX[cn{ytsstx|~|tlgeglvvdWMKP\mpWB53;MgƬjI////@`еd=////4[м_2/////X[//////UŏX//////TƏU//////TƍT//////VÌT//////YоW//////]иZ/////7aа]9////CgŧdF0//8PlŴjTE?AL]srd[XZalxzusstx{~~}umhegltxgXOKOZjtZD738IbɰpM2///;ZлkC/////TÖg9/////Pɘd1/////M͘`//////LϘ^//////LΖ]//////M˕]//////PƓ_//////Tп`5////0Zжd?////=`ɬhJ4//5KhǸnWG?@JZotf\XZ`jw{vsrtwz~~~~wohefjs}|j[PKMWh|x^H827F]{̵tS6///7UzqH/////Mzɞo@/////HzРl8/////DzСj4/////C{Рh0/////C|Рg0/////D}Оg1/////H͜g5/////MƘh////Jm˧U0////@kЬ~N/////:jа}H/////4iг|D/////2iгzA/////2jвy@/////4kаxA/////8mЬxD/////=pЧxI/////FrȡxP/////OtлyX=///@ZxzaMB>DQdz|l`YX\ep}~xtrsuy}~~zrkgehnxraTLLR`rjQ?44=QlcC////EhЭ\5////;dдU/////4aиP//////`лL//////`мJ//////`лI//////aиJ/////0dдL/////7gЯP/////?jͨV4////Io]@///COawobZX\do|ytsstx|~|tlgegmwudVMKP]onUA53/////?tЧp9/////=tШn7/////wФm7/////BxСm://///Gz˝n@/////N{pH////4W}дrR8//0D`~ɼu]K@?GUixj^XX]gt}wtrtvz}~~xpjfehpzo_RLLTcveM<34@Wsм\=///0Lpɦ}T/////CmЪ|L//////////6mЭv?/////:pЩvB/////@qХvG/////GtƠwN////0PwйwW44>SmaA////GjάZ4////=fвT/////5dжN/////0cиJ//////bйG//////cиG//////dжG/////2gв~J/////8iЬ}N/////@m̦}T1////Kpо}\@///=Vt¯}dPC>DPcx~naZX\dp|ytssux|~~{tlgegmwtdVMKP]pmT@43BM_tpd[XZbmzztsstx|~|tmgegluwfXNKP[lqXD63:KdǮlK0///=]иg@////1Xc5/////Tœ_//////Qɓ\//////PʓY//////PɑX//////RƐX//////UŽZ//////Yл]2////4^г`/////P}пmG////6XϳpP8//1E`ɼt\J@?GVjxi^XX^ht}wtrtvz}~~xpjfeip{n^RLLTdw~dL;35BXtл}ZhаQ/////7fдL/////1eжH//////dзE//////eж}D/////0gг|E/////4iа|H/////:lЪ{L/////Coʤ{R0////Lrм|Z?///>Wv|dOB>DPdy}m`ZX\dp|xtrsux|~~{slgegmwtcUMKQ^plT@44BN`upcZX[cmzztsstx|~|tmgeglvweWMKP\mpWB53:LfƬjJ0///>`жe=////3Zн`4/////WÐ\//////TƐY//////SȐW//////TǏV//////TčV//////XX//////\йZ0////6`б_:////AfƨdG1//7OlƵkTE?@L]rrd\XZalxzusstw{~~}umhefktyhYOKOYjt[E728HaɱpN3///:ZмlD/////TĘh://///O˙d2/////Lϙb//////JЙ`//////JИ_//////L̖_//////Oǔ`0/////Tb6////0Yзe@////<`ɬjK4//4JgǸoXG?@JZntg\XY`jw|vsrtwz~~~wohefjr}|j[PKMWg|y_H837E]z̶vT7///6TysJ/////Mx˟p@/////GxСm://///DyУk4/////AzУi1/////A{Сh0/////D|Рh3/////G}Ϝh7/////L~Ǚj=/////RнlE////7ZͲoP7//2Gbɻs[J@@GWkwh]XY^ht|wtrtwz}~~xpjfeip|m]QLLUdx}cL:35CXuϹ|Y;///2OsƢzP/////GqЦxH/////@pЩvA/////tХp=/////Dv͠qD/////KxÜsJ////3TzзtT://0C]|ʾw_L@?FTh}zj_YX]gr}wtrtvy}~~yqjfehpzp`SLLTatgO<44@Tpо^?////Jm̨V0////@jЭP/////8hб~J/////4gд}E/////0gд|C/////0hг{A/////2iбzC/////7lЭyE/////DQdz}m`ZX\dp}xtrsuy|~~zslgehnxsbTLLQ_qkR?44=PldD////DgЯ]7////:dеW/////2`йQ//////_мM//////^нL//////_мJ//////`йK//////cеM/////5fаQ/////>jΩW4////Hm]A///CO`wobZX[dn{ytsstx|~|tlgegmvudWMKP\noVA53;MgŬiH////@`дd////=aȬhJ4//5LhǷmWG?@JZptf\XZ`jw{vsrtw{~~~~vnhefjs~{jZPKMXh|x]G827G^|̴tR5///7V{pH/////Ozɜm?/////I{Пk8/////E|Рh3/////D|Рg0/////D}Пf//////E~Мe0/////I̚f4/////Mŗh;/////TмjD////9[̰mN6//3HdȺqZI@@HXlwh]XY_ht|wtrtwz}~~wpifejq|}l]PKMVey|aJ:36DZwιzW:///3PtŠxN/////HtϤuF/////BsЧt@/////=sЩq://///;tЩp8/////;tШo7/////=uЦn8/////@wУn44>RmbB////FhϬ[4////CPbxnbZX\do|ytsstx|~~|tlgegmwtdVMKP]onT@43/////;pЩtA/////@sФtG/////HtƟuM////0QwйwVDPcx}maZX\dp|xtrsux|~~{slgegmwtdUMKP]pmT@44BM`upcZX[cmzztsstx|~|tmgegluwfWMKP[mpXC63:LeƭlJ0///=^зg?////2Yпa4/////UĒ]//////SȒZ//////QɑX//////QȐW//////TƏX//////VY//////Zк\0////5_в`;////@dƩeG2//7NkƵlUF?@K\qsd\XZ`lxzusstw{~~}umhefktzhYOKNYj~u\F728H`~ɲqP4///9X~мmD/////Rři;/////M̚f4/////JЛd//////HЛa//////HЙ`//////JΘ`//////MȖa0/////Rd7/////Xиg@////<_ʮjL4//4JfȸpXH@@IYnug]XY`jv|vsrtwz~~~woiefjr}|k\PKMWg{z`H937E\y̶wT7///5TxœtJ/////Lw̠qB/////FwУo;/////BxФl6/////@xФk4/////@yУj2/////AzРi4/////E|Оj8/////J}Țk=/////P~оmF////7XγpP7//1Faɼt\J@@GWjxh^XX^ht}wtrtwz}~~xpjfeip{m]QLLTdx}dL;35BXtк|Z/////8oЬt///>Xv|cOB>DPdz}m`ZX\dp}xtrsux|~~zslgegmxtcTMLQ^plS@44=Pk§dD////Dfа]7////9bжX/////0_лS//////]нP//////]пM//////]нL//////_лL//////aзO/////4dаS/////=hϩX4////Hl^B///;TqñgQD>BN`vpcZX[cn{ytsstx|~|tlgeglvvdWMKP\mpWB53:LgƬjI////?`еd=////4[м`3/////WÐ[//////TƐX//////TǏV//////TƎT//////VÌU//////XпW//////\иZ0////7`а^:////BgŧdF0//8OlŴjTE?AL]srd\XZalxzusstx{~~}umhegltxgXOKOZjtZD728IbɰpN3///:ZлkC/////TÖg9/////Pɘd1/////L͘`//////KИ_//////Kϗ^//////M̕^//////PƓ_//////Ta5////0Zжd?////=`ɬiJ4//4KgǸnWG?@JZotf\XZ`jw{vsrtwz~~~~wohefjs}|j[PKMWg|x^H827F]z̵uS6///7TzrI/////Mzɞo@/////HzРl9/////DzСj4/////B{Сh0/////B|Рg0/////D}Пg1/////H~Μg6/////LƘi////Jm˨U0////@kЬN/////:iа}H/////4hг|D/////2hг{A/////1iгz@/////4jаyA/////7lЬxD/////=oШxI/////EqȡxP/////OtлyX=///@YxzaNB>DQdz|l`ZX\ep}xtrsuy|~~zrkgehnxraTLLR_rjR?44=QlcC////EhЮ\6////;dдV/////3aиP//////`мM//////`мJ//////`мJ//////aйJ/////0dдL/////6gЯP/////?jͨV4////In]@///COawobZX[do{ytsstx|~|tlgegmwudWMKP\noUA53;MhīhH////@aдc;////5]л]0/////YY//////WČU//////WČT//////WċR//////XS//////[мT/////0_жX/////8dЯ\8////DhĦbD0//8PmĴiTD?AL^tqd[XZbmyzusstx|~~}tmhegltxgXNKOZlsYD739JdȰnL1///<\йiA////0V”e7/////QȖa0/////O̖^//////M̖\//////M̔\//////Pɓ\//////RĐ]//////Wн_4////3\еc=////>bȫgI3//6LhƷmWG?@J[ptf\XZ`kw{vsrtw{~~~~vnhefjs~{iZPKMXh}w]G827G_|˴tQ5///7W|pG/////P|Ȝm>/////J|Ϟj7/////G|Пg1/////D}Пf//////D~Оd//////GМd0/////J̙e4/////OĖg://///TлiC////9\̰mM6//3HdȹqZH@@HXlwh]XY_iu|wtrtwz}~~wpifejq|}l\PKMVez|aJ:blobby-1.0/src/BlobbyDebug.cpp000644 001750 001750 00000007274 12313310251 021067 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #include "BlobbyDebug.h" #include #include #include #include #include std::map& GetCounterMap() { static std::map CounterMap; return CounterMap; } std::map& GetAddressMap() { static std::map AddressMap; return AddressMap; } std::map& GetProfMap() { static std::map ProfMap; return ProfMap; } int count(const std::type_info& type) { std::string test = type.name(); if(GetCounterMap().find(type.name()) == GetCounterMap().end() ) { GetCounterMap()[type.name()] = CountingReport(); } GetCounterMap()[type.name()].created++; return ++GetCounterMap()[type.name()].alive; } int uncount(const std::type_info& type) { return --GetCounterMap()[type.name()].alive; } int getObjectCount(const std::type_info& type) { return GetCounterMap()[type.name()].alive; } int count(const std::type_info& type, std::string tag, int n) { std::string name = std::string(type.name()) + " - " + tag; if(GetCounterMap().find(name) == GetCounterMap().end() ) { GetCounterMap()[name] = CountingReport(); } GetCounterMap()[name].created += n; return GetCounterMap()[name].alive += n; } int uncount(const std::type_info& type, std::string tag, int n) { return GetCounterMap()[std::string(type.name()) + " - " + tag].alive -= n; } int count(const std::type_info& type, std::string tag, void* address, int num) { std::cout << "MALLOC " << num << "\n"; count(type, tag, num); GetAddressMap()[address] = num; return 0; } int uncount(const std::type_info& type, std::string tag, void* address) { int num = GetAddressMap()[address]; std::cout << "FREE " << num << "\n"; uncount(type, tag, num); return 0; } void debug_count_execution_fkt(std::string file, int line) { std::string rec = file + ":" + boost::lexical_cast(line); if(GetProfMap().find(rec) == GetProfMap().end() ) { GetProfMap()[rec] = 0; } GetProfMap()[rec]++; } std::fstream total_plot("logs/total.txt", std::fstream::out); void report(std::ostream& stream) { stream << "MEMORY REPORT\n"; int sum = 0; for(std::map::iterator i = GetCounterMap().begin(); i != GetCounterMap().end(); ++i) { stream << i->first << "\n- - - - - - - - - -\n"; stream << " alive: " << i->second.alive << "\n"; stream << " created: " << i->second.created << "\n\n"; sum += i->second.alive; } stream << "\n\nPROFILE REPORT\n"; for(std::map::iterator i = GetProfMap().begin(); i != GetProfMap().end(); ++i) { stream << i->first << ": "; stream << i->second << "\n"; } total_plot << sum << std::endl; } blobby-1.0/data/gfx/titel.bmp000644 001750 001750 00001147070 12313310254 020735 0ustar00danielknobedanielknobe000000 000000 BM86(  k%-{ #{ (u Xs t {&{ #Oy"cn!>{%v "o { ${ -{$j" |  #o @ii{ #{ ${ #{ -{ "{#{"+z "{ /{ "{3{ #i{ %fv 4{ #  % $n$yv $lq $ $S { Ht ~ Cqg{ $qm /{ #{${ #x !{ #o$(!$r'(& 0  *$ L ( # % $ : 1 $ ! .l1u &f4{ #{ #{ #g7{ #!$ 4& &$ "#*#)J !$ ,%$ *&$ ' < A{ "{#{ "{){%{ #*$--##8($4%#$  $$"0/ %$ 6 $+(w "{ *{ (x !p #< $#= (E#7$L"#!/;&$"3'2%$*=+$. ! A!g{ #{7,{ "{ #{ # D?($ #@' ^AA)$ ;#0$01(7($$  $ "g${ "{/n',m o "J0#&$9&8 ,D#:4"PXa!N-%&#$ ! { #{ K{ 't  $(#(#$*$K$9%=-& G-,"-*R!%&!$By ${ 'k{ G{ (*)G$,"+,&$,%8!$B']!'$+37Z^E7F<_o]-A"C]/@"$18 /p #r{&{ A&M'322#(/5K3a&$&%%2+/XK8nSRT__jakU]Lb5X"1K+G'($6% #u. | "{ #{#k,,r5A.;Z949%1#/"3 -/s,5bLQG^fZ]gmy||hpLW1<& $V)#$1&$" 4q t { #)2=E0^0M/@&3%0$0) #<'.(5?Byv { $`2SD%"JEk0xB @ = KN?mXirbV;9#$ @'!B , $y "g{ $Wb4=;G9E0=,3%3]+P*!q\$&-#pPI ROE}txg\A,%"2(!$` fSy !B98$3(# lf3% Q+eQkuQX-:(54%#A # #iM{ "{)1>:;2?2?6>*7I4= 7#uhpKmZ:iO*jjiE<߀w]i7P"04$ ,(%2 ( 8{ ;{ "m'm.{ #{%a{ #{#f{ (x Rr { #T{ #*835LRI?(2_F/()$E%4#bs}hрLh(K +",+~LXW>ktLXOV:++:%)%'%N($2( "{ #{ "{ 4| { !pc{ #V{)>{ "{$R{ #\r ,{ "l{ Jq""{ #s! +(3)iN:'4&44=%K'5  !mh\Dq|]q;a>#(-+ [{{vah:E!6%$%$$# %{ "{ 3d. A/8*&+v  { [{ 0{ #m{'f h{ +&+"5$.&1&4:<q$7( 2~(ZtɄjN|*S~%g mC|sMX38Y%3!#$ % !$ky "{ "w !. #( *qz+ $g $/4,( " $'\&k 7{ #y8{ #l{ ${ #s "+-4$\#-5#1$#@ lcvKs^y=Y<"z} a{xw]eD #' #" ! ) #t &{ 1{ %{ #x !{ #{ "$92-!K&(C>#0(89u0N)t͂kӃOk+U5ol^fbBo~HR+9%)%  $9$$ #w{$m)j#$Z$%($"" $$$ ;1&#.$ -} "} %{ #{ =x !y !s  "j;O+0:+'*&<)"(%)! O gaBs^|=bJ.ZH \Swyz~\b\ ^a@r^t=UA-2$} ExywZb=]7-'$K #&! .z !w !{ Dk Z)!P&&4U!0@#!#\?' )'% ,%$$#{ <`{ #{.{ "$ $#=$$!#m- %$$5!'%2H#  b sކjOi,U6*. WfaE~vP[0<(+B8"#1%(%"=:<;)6{ \Zx *$8- -/\!*)!@*!6!;&1.,,'A) :$# : ' 3{ O{ "z "(*&0"###$#3"B$$"$$5#*ndY?s֊`x@]8%&"!jP}us?K#2&#'>+%$#3' # i j 3j{ %l:'5'8&3'5&/c2$C'#G?&*71I2DEB%H, $$$$%5,'n{ "o { "# *($, $#1)"/$r* "3$.$U)>+#*# Q tvm|R_.G0p\CTR;lyOh-8,'&$)F:$Bt!q=v { "/:.80VP6,9(572#K'$$+(75?hOX}DP6B*,#;%$C  $Y{ $x (|.1u,dJ3Et2!Mt/~3:Vj"+6d%+55c)] 54u/r- 21po # '*$#*.!h$$%#=E&#-##'( 5 n T\>ucvBaO2&"q@ Cyr{}ah@M&3&$:'# >} &w 2x N{ #5B6C3>0:0<'1'B9%C%_:LK]^f`kJ[N@ J?&#:  $ ${ ${){ 0.K0d.AVn*=!6}/5!6"8%;e5/"?x"B$;#7#:#:<]#F"6#8"8o0!6y7FsOi*"4u./5p+y :t!y $ #-#$ S*$$X=$ 0$$ $R (%1 J  $ 2 P qqń0RB=8.{ PLS6~pwR\1;!$2"$1#6 U2( 0{ #{ #s :F;G7@?@9k/;,:,%9$ 2")o:fsBmRwegAL@5'"T!D,$+& &{${&{&EOo*'5p,o,rKm-x"D":-:%8%;t':|8;'='=+=BAs'7(J{%=b#/)Q+=~&<%K$;#6}"5"9!5]9t".z/k/r*{ #^({ #{ 1jZ{ %kH,d{ #{3l{0{${#u4Z( $** #/$!43A$D$?X'$$#$&%$'( P( $jb?1י|CR><4%%rGkrv|oAL%E$#$"+$&z{ !u { ;{ /ZJ;FOF-A-@{@:.B0c/C/D/B5=.@,@1B~):4A*@l/>{%8&^p#:">-8z26'5r-z!4z.a.l"'`"+/p1` q&g #j j1| %|0| %{ &l ;{'z #{ #{ 0{ 1kl d` o!{ &{ #Z@p{ #x {2{ 7{#{ ){5{$p{ $v {*{ "{ F{ %{${ A{)f%.,9 77aK6 dcv_g?I/ !#3%$ " ) ${8k { I:?(=36%6,5$9%\&;:C/@,=0bE>4D1D1F8J5G=I0R6HBH6H:FBI3J-91D2E/^>E-J,A8R:Cq)N}*9"8!C6o;31J%<:r'*0~+~)z'{&uIhs !ji| %z#{ ${ 'g#{ *Z{ #{ #iq $v {${ 2d{%c{ #Z { %{ #e2{ #Y { "{ "| #i # / / $|  "s $ "! , 0 1$&#<$$ $!#" 9$ " .#?))5$#)L"XE(s aD0sbyCR ;:3}fsUufv~\n>HU6&,%-)!$# e~ ({ "Tx !8A:D=^PIYES>'5.+ # 3$lDN.ygqGk+95O$0#" &&{ $y #0O31A:!6-8+;,=3A4G/A/O3I4F=L5C7E9I:L:tCI>MfP;c8LPN=[;K9H0T(;"Gv"]#655410v(Gj"1))~'k P} $''m-#Yk0 '$ $i!p & 8& $ # F~"tG " 3 $ $ $ ( #-'}  j$$ * #6$ E+# $21{$<3 $$99%1741$<&6%%"K"4J-#S)&$(, 1#"0- I pomՅUj1S=8&TqbEO/flSf1>+:121&$$ $#mE{ #n BK]L?W@IF@R?&6)-##$N;)\stmuZe7E-@'!"J-!$| -)| ,| %| 15=4 /4*M*R%8)=.<,\1@2?TF4CEK@>APM=L:K8\FI4F1DZL6ERC3B=D$</#34.40h#-.9/:)%"['&! F )>;~ %5% $ @$#57 ! o   &?w # # n+&+&H'$& .5& 'B$  $.S$#$1& %$# %)+-95B9N5@/;;.C.?)&$$#")&15+A"!s b>9u†dzEo"S >+bs Nujyik#J*1$ 2k|)*}A#0!Q3-!v<:&4'63A0F5G2>7F9G8CK`O;K9G6F5N0M.L+=*=%6%O+6(@6$1!,*"-=*)&(/ &)5$(#J#$ A%'# +  %$*"1*8:1+  -)$#+'&.&$#<-)#:($7VR" . !/>7DL[Yc]hVEQLC&3)*1$4#&. enfpWy4eD"frq b?f7iT^T@5%$Z!%$ # !y !{#a==PD1L(=2,$5 5VJ-Q=ylvR]2D,'3(&!$ 9<&kh}){+.-3!W#3'4A>/A.;5C8F8AFC9$T#*0*#(#%&*,%.(  "!$$V)23#!35>#=%"%$B.0ECZ[mn}nxXbAM-:)+"8 #) IU!, !fV71vfրGr#F ne[KKGqiyenXPD,6&#$$-$6$ #[{ #{ "?L@L?L'A3&O<%+F'D$L'$!5$$$T%$&#:?#$%9;&",%#!$%((7( ' !,#vs*jEQH6B;aCdBQ[U\ZTZPZ[_Ua[lYcXe_p\akayg{rep`iq~_gak]o\x]iZdYd{hS^eaP|{Oi{VDP=HLK7C7D2>3t&(X-@%/$%$("" $$5+$#O(/%( $! $(Eq4%*$K*8'"&%6N#$$3"&7'iq"+LEK3Ȍ앚v^hJT3@$3(%6d'# (v ]vfyGm$Z 1)%fmStjxrpGQ&;&0$#$)-@%%&j{ )a{ #=F>L>L*!W<o^香p^b=C&;-'# glzWoՆX5gF51sQQ!Gs|Xk8B'/$# 0V, $ 8u #{ $f]MNdKE?]?D1>'6D%?" g;:Z1R<$^YYh2=C>58G5L=/<8>,9$P52:/$B%#!+H#$&$#P&[1W/!/!/4*U'%,B#,R($#,(>7<,7I^AMOYcbY]h\eg^Q\LdfP1?l:-6))'L!!|3$Bp N(z^G=~|ze{KWXZ$01! =%w e).u֌fHf$H ==/hXHr[ߘ`gFX(618%"#!$C% $%{ &v !f8B>IfF@JBa1;'^M)# ;[3T8meWIruqqSa4`"@% $""1 T6,+('*(+,!["1@;5<<=,W;A6J8F>ICSlUE]O[qWkU]_ejijoploxqzs{xyvzx|~x|xy}u|t}qoxgoisfpmlkm[gRZT_O[IbGSAcLHNMMI;`1;gd-9&3-&'+5($('$5';+$49k;FHRgegq~}}}t{pyblXdQV@E*8 @'T&I;  y'f]Rq(Q#}C/ R\Aߧ醌t|XHEA8&( "zg mZpֈZm7O;61"i]!J"㊄rdbKA4 #$$$H! $u#{ #{ 6t >KK8C6E.:)5:@'!'";[4U"Ae\Ldeqy_jpQ#08&F"#J)0,&+.A5!3-5(2)82:1@EH8HTKNlDPjVMXQ[V`g\eamfwcixs{uu}⁇ޖ{wsnx}hs|k^ideV`sbQ\dZH[pTDYXYHVOVYc`ndrlsq{pd|\]=I58?(7''&&C* .%03BCNH~PZ^hgnii[k`W;A$2#'$"!#UL$A A++1.;QUJVT\irjimgoito߄폜sqkvT7E*0-zhP;h}Qp"J4-|^TUo^~cMX=B) * x `" vhJo&R 4(/'#WaVzeoEP(6*&$-#!<<"$ a8n{%{%>K=J=K;QYY1>%H*"%  %;k4e$U%tuS1\+xomOZ/=42&!C!7L,*\$//2!/-+7+9Q>1N/4SC:FaLEQaPPXYZWa]flaigvj~qzxsx||ntdi[_WUmMJ^?BY<@^?GlJINRZ^dnmt|}|~qjnetbahohWaT]NYXXITN]q{lik{~|xxSyOgM6,C$& U(',5EBMR^`juv~낏avJW2B',E''%(*H&8,`4:#N[ ntcCiF&!s\G/ EE2ʍ囏bmvST4 g(k_r\}9i> 9>.)fL#qRZZG*%$#L"#$ .{'{ #m=J>^;FW7D/D%1+`M! ;k4f%T.&$^Gtes{\f9X>4$.T#)(FA 0$["0(6'5,;1?<]8U:A @4 %o_dp}W .[ _uՈjLq(B :0dX{cclX(7,&<&$L!-h #{ $m Y)KE9D=H:T7E-8&:*Y& ? ;k4g%T 0,+r BfI:mmIT,;!,D)#D1.!0H#2)7+>[>4AJJ=IIZEsIe^ZR[\^ci_horoqzv|lhP<>!!!!!! !!'&(122778==>BBCHEEFEEAAB889.//''( !R:=cg|~t{lhqcmkYcT]JgHU]UxeJK?(F$@r1\).b5tU`6B",!!('9,S !4-[41t*MINS=<줊ޏrLQ3=)A!8(?$$' ?2R,5$"/ ;\4V%Q 4(71_9 y}nyUe@G!/0'6,#G ,$6$0)SD42P4@7i;F@Y>GCM\Za`Wb^hcmgonvtxkjY>@$$$"!",+-GGG\^\ghhjkjfggffgcca_^_ZZ[RRSLLLLKLQQQWWWQQQBBB)((_@Hejpxj}qn^gYbPZJTOU'J$G JGB;|2j+Ӆzmk:C#1)0'(* E  "l"&]A T^=A{{}uWb:E("&8!"ND '?#e&:'&/z"/#YM5 / pkS᠘]h?T(/c }{`iwRn0Z63*T1Cx' OGZ|a듧}^a*ldrևiӁLo([ ?30dXyZweoEX%/;=*$>$! * !1%l{ >{ 0^)8CyHIGuKGRU>&4-1! ;[4U%Q?(12rClTwomH_,9'290-'(//2&4#F+35:8UF]7J>SBNCLNY`^XcX`drimyנ~MP)%'!!#324NNNdddrrqttsqqrqqqnnmkljgef```YXYPPQOOPTRTYYYZZZZZZZZZVVVGGF../($&SW{㐀zkremai\f]_MUXk*b'Y"PF@=3_*jqTz}juL]8:-)%" -\L dUclKGfeAz{`j ; @!B ɌZf(.% m,(m}^{?^7.43&}ZG;EN5|Yd'z*bnIp[o:b>!1+" x'-J(t|^lB@N  2(<$ ".c{ #{A5BAJ&5Z!+  ;k4f%W?/2,h9 @wyT^7F$6E16$."/&2'599$=1>=B8DLGBNX\KZSpY[fuqhpo|{nteBE'()556NMM\[[kkkxtuzyyzzzxxyvvxvutppnfee]][QQQQQQ\\\cdc```[[]YZZYYYYYYYYZPPPA@A&&'! W<>pᑇ|{qxroreW_QWoˀWEi.P!EE;5o/"l2s{Yc9E0+14!'#le3T"I 6#/#YOt~esO_0=$" $!(! 2##+,  23y.!FM< 22O/J$kozL=oOZlldfځMr+M+ 4)e")a8 "*~ua q%q{gsLi)N x"*#v) UhZ|h^S*B9R*$#6($ Ex!bJq { "3ufu_kHO*72')2  Ym>T~Ek+W6):1 QeXmYx;K 8h) $"U7 ?;CD@+#:!F4KCZF^=L-=LV=O4&s#![6jd}\G 5| e[=k܆Y{:bH.44*,58.j5 )$s[OMY nZ@lz[v;e9j"Yd!V#߁t}\_HE$,! "##B$$!l{4{ $5VFB4K6TTM-:#2">&"<  7W1R#G 4"#>F4*d.A&oxha6@$252!/42&3*UD5?B5A=Zq}bkއq'5-0EA'##2W'+K%E? 8<45 I#XC`^mj~gyWd>M%?B4u%(H. tf_e"*r(jҀc݀Hf%W F6)1(!(1-gM6 1?'﬛GT-hwb}Kp)L63&NeXdd~c{HT+F"")*16$$- $yW{ #{ ${ #LEvJ7LAC2?+9GP&#*}5P/P"B 0,HL6*], khwcmUL-6"0)1`9,9+8bA2E8EMJ^NCMKvMYk_Zbbkqur{yr|aJMLLNkml|~~~~{~~vxyttuxxxxxxuuuqrqjjkdefeeeiggghhfffaaa]]]ZYYZZZWXWQQRIII>>? K35pvqzflazUYЗ|ۙfG{-i TF~6a+O$}t}]f8D%V/&y K t ai\}Ep$N (&XUswia_/N+#$}_+5V1Y.G $&)(),>F,mwM}}ْhӁLi0ZO,d#.f8 F|pxFd' ]dHiЁUl4ZD#h&+ );5/&o7 3zp9R("u`;^zSv7W?,(#"zG荃y{Xb9J)$%=G' B  %{ 2jf6C9E5n4A2?/P +"$S 2_-X A .2527,|NCS2~nyib8D+L) ++8-A2?2<1;leC^SVQcS`e`tisj{vSVVUWqrr||{zz{~~{||~~~~~uuullkefgeeghhhhhgfeedaa]]]ZZZZZZYYYQQQIIJ?>@  ^6C3@6BZJTIFTKVRbpd^lrp}}z`oWWXsrsvvxutu{{yyxvkmndegfffghgggggefdcc^^^ZZZZZZWWXPPQIIJ=== !\X쌈tymv_uhdϠy_x?e(U L@>|3_nJtwOX4A*''" i%fzXs( ,}fP'6($t Y \#y\};[A %#"m^RvgR{UN*kySguPe.P7-'%4*'--0,'y=5 ^pEag4j1=e/:9MZKCNIUNZU_]eblrzzo{YVUjkkyzzrrrvvuvvvmmmgkihhhggghghgefaac^^^YYYYYYWWXPPPGGG556(%'lowochZoӜݝi֋Kq0\"PKF7n.y]h>J"/6O6# r he_rGe&I =)%9 Ns~jtcs4G.)!(Cw9*CY9b&L 85()z=AC?(#$ [ Rzm{^u=YC5(("gQ{{]g# mX2lŀ\i=YG::$)4$|$#(1=; U`0m0XS#'2A-M(HF6 X/ dUckHT3:"R&&$K1%#!={ !mn {54@2?8C9?kE1<'5!F& !(vL)4f-aM 1)*))[flS{{eoHT3?+7ED0<5TQKYrFU{YP[T]^cdmsw~{gkqqp|}|~{{{yyyqsrjjjggghhhgfgeefa`a]]]ZZZZZZWWWOOOFFF))+W>I鍃qhn_ctV}8h$V RR@v2p[fsGS*;1)'!{^X@dpRg2K941*WTgQᄘ\f9O$2W+! #Ig?g+P16'!!M^^ {mufLf*@ *-"4:077,4D8 zhX|#PCU'?88 2cXQ< <{rWa9E-#L !)+$ &{ #u"{')R3@=?3J.91;(7 /%= aP+5^-P9 (*4454)+2r(^lJs|[ffM[AP]:@5Q=KBNHTMUmgZ_a}gmqzxwxxy{{{qrrklkgggfffgggded```]]]YYYYYYXXWPPP@@A!!"ae}}mtchcg{֙a̓Ck*Q!PZL6@[9{nwb[3R!/ F"4 l gsZg>M8/(-z\-^)vxooLT+9;!  g NkFl1[2*+$!Zapug?L% bT jZGuUjXlCR.5(~axpFN1 jbBlYr9V=*" 4@B; > 2%6(_]RC \ %h4!0 6/ (,$];cQ{iwu{*:(SR#62@$$5* 6p { #s %[B,74]MAFA,@`cg=M(#M}I*4^,Fy/ wq)*5>0.`%L~|҈oRS8F3BCdSG9QDXHVP[Wc^~`mqs|~y~zzyttsmmmgfgeeedeedddaaa[[[YYYZZYWWWNNN///Y=Byw|gllalMr2S"JFD:e+zyZdBK<16+>O$sh[azIa(D 4)%qlooohp\T?B!=c WcMc:bA..*uYiexeBK@, zW f_IחpQ^0ID/icfR]a= [ nxdxHg%Q B, 4?C 5<J=B:(YRM+a24::A*(,l`at|Zd;F,8Z 9#&% # &{ 1{'4{#3?8V-82?0=0:&36@&#D7wX-3e+VA)!((+55)%ZDg[Jz~_hRcBI7D:IDeESNWT[|j`juxxx|vz|~{tttjmmfgggfffeeddd`_`ZYZYYYZZZWWWCCC msu|i|gg|u֓Xt:U$IA?A5{_u{emHU+9/.)%} dg>eSq4WN?1zej{bJmu[`8O!.6% cUTeAW$? )!zmrYt}XYrI`,M/!"UfH돜ߋx^g3Cnޔۙzj|Vx3d1$e?H^@ W nɂ`lC^ I 2g)8X=4UE\ET8P#JD5h'916C4G0?/"!Z2 Gv~_h7B(@"  6$ $w !{ "{ #3?1=4H3?/;)4$1(F-#8R  `Q40I(PD$))}s$.,1. q&nwO퉒~ejJWFJLKGPHkNZS\Zsakiory|󏇧|{{srqihheeefeffefcac^]]ZZZYYYZZZGGG4%&~|qyhuaamO}2_!WNC7_)Ҙwv~Yd>J[5)#N( tjWb}Lv+K+*/QNmfluTe8D=-"g!Om4d<-&q `#raSvfTgaNZ#wwRۦܪѕzd9X4"W5"4%] kWgtPi.K-+%}ad|-}COs^yXlD])V@-+*(*+))?767&Q; jTirnbS;)$( $, #g{ #{ $2LTi3A2?86*8'U7=%C j`2/Y'XB/4*hi .0-45 u& Mwrⓒ{odCLALDPJVbYe`aefppnryrxyyynpphihffffffhggcaa\\\Y[ZZZZSSSƉt}qrkq_gsߣvږYz:]$VYM:(v;y\{tJVbI71# K hiO6gفV7`3i(+!upbErgk@J#12!/wy ]dRl;hA-(Yh`MVP;!J"w`ፐ`{ ' |I8puP||ؒat7R0K$3|nD5֗\}=[@:0$~{'!D|l>jqfLg-UH=4&'1*5'22$yNH׆zwjAG(32$<&!$#''${ F{ "z "/;:j3M4T*6)8!3C , a?-a%[F-*+0=1'.* s% [#QcBjrQ[Jn>QOWQ\Vdmgr롆uzxyynnnfgfddeedfeee___Z\ZZ[ZUUV)))`evjo_eY\}ezDi+c[Q6-d:3b8~qzU^2>!.;)& \ip^yDd"> m%pYryhrOZ+W"&'f`QUuBn$J()!kFUrT: DDbXE{wrzJf+   L1XJ3{=.C') ! .^ fLi*L 551)!n2$5,w~ٓnyQk1SA ;3'4*)_ !Sf[DktM[/ZL?3*$ $$ $ = %y${ ${ #4M2?,754-;W9!3'!"$  LH+M#QD)!$05 - . 320- 1 /n,w|bkf]VXPX~Ydakhppyyxxxnoneeedaceeecde`^_YXXOOP///Ygzotgj|WcԝnȊOo1d]U;Z'H fbv`k`J'5!')$ [ d]EdvOk.G-*oedYt[d9D%jjcEa7zk~zR^F84  #4g fS)'-;Z%D}{w]hHI+), $$E" % "{ 5y '{ >{ X-72?hN*5-@&;,9.&# Ht7*G"NA36940=7:FC D =Am4>a)'(:"D k,=f[@~uoGPA`($7"%9$$# !x ?o*{!&YC)67>S@P=99E;'O>'.#('% ><(LC++45 ==&R.R(MS@ 3 :J$n7?"xrlzYcX\{]d_uhqpw~Ƴ~uuuhhhedc`a`YZXLLKMLLCCClEHֈy{ekgeSV”}dEl)KGP=1h(|uvq_OD<(6%%%5(o jm`|Gg&I 1/3."LotҕpOY/< $vbyWk@O D:5>4*44(10#lD cRBTfgJpzXb:Q0B-"K]`BjUq4R7*23saT|>IU  `&xc̪ןZu9YA =600)5*h26%H'xzsztfps)3/' L$,?%N- "{ 7y !{ #s $.=481=0=(5+9'3.2r?$O' -K(GC ..4* 26oj:E\=^/cM 5 ;A.V)&P3f}XT][ebxixt|ܕǻŶzzyqqqfefXZXPOOLLKQQSKKK`>B|r~gleuT\{nP1bRI1y,~-yawbnCZ/5&' ( n iZ@fRp3T0}")'RcSx\hFG$ 7 z hU_yLb+D4(44445>=0ymvulSMq_⇍Xc=J'5  ]#n`sCZ {11=-adwhgcO  Bpy؏\}:bL H=%*?0&&)l> fbB}ktOW;9,'" U<'78(7 pG{ #V^-CkA0=5>0;/D-3%)%H# -K(TS 5#);&&VlThFe.XE 3425_/yk뗧v~aepU]dxڀqqy|~οxyxhhhYYYRPQWWWYY]OORY>@샊~}r{rzT]UU֞wٗ[;j"WK:60:v:xfs^\,FQ, #J j$j΁\}@oM%,+Z0E"rd}Na"2*iZ9gX{:Z>'-?*h*@>46?(`y smRGU\@ΐ|X_Bh-5" n k[gPl.G-50qovviGkn1@"lJ yi̙z؏^;;5)"($na{zu|]g?9H-:'4(A)=A> /!+U'ZQ ;d`4jMgy[h@W"?w&n$-4[+P/ړ힙pymjhyu}ʿź~~~qqqfefcaceeddddTUU"""a@H{sf_gW]KU}ɗfEq(ZVMA4 u(zxp[d5A!.(06wT jyUd}Lx+_6(7.z?ߐsnrRg#+" l mdJo(] <3?5+AC 0 3 F0hd_Vkl^G$="ˇ~mxDK+{ gI2m\}=Uy."23|#cRyYbG%] 7u{]ݟ|_r=]U 4->76=80*)]cbD{muk[,3$2&$KH $?$e- t cO{ #=A.;/H;8(H26*1%  .3*sC$,U'VH <3'$%/ rȂlUr3XB988|4oSw}nrnlm||ŻxxxtrrrrrppplllXWX#$%nIJ{r|lvbhU[L_l˗pÈRu1XE?6{, h%{jNmiJR?%-| %hV5iӁX9j=%"%ToU@r{`j@Z#1 s gpHmYt9Z:35**A =:JU@t& "{d"sjABzoza=P- j mxfLi*M *,E-Y4 kVnxFO7(p J l[I|ŋ_u/=+8(10.#5# 4$+D&E3',552-, $xsOxُfGv(]F<DE= e8vvkotp||{{zutt[[[$$&yRW~~~_ga^NQyANȑwƍ]} &od sgLj(D -%hs'01F)^7h:Z3L%M5l(8)|KEGseaa4: v ha@l݇Yw9b='++u3 !Dyei7D&! ZJ lbIݞz]{:Z~0 36%on*z> HaY?뉄wMX8N5,  $"&#0') 4mc U-:I;L=(=*8&4 .'PW!'ZK++G%H4$#*30Fr'"h |tŇ[9iN=EJ@z<@{O栞䗛ukhnuzⷹ¹{||\[\&&'\`p{em`V_LgBEs{gGx'X5- o% [Vtlsy_|>K%G(+&!" +p fzMf݂Ru1\96:(~Q]WpyZx8_# k jwRr։^mO0'u\HQX4vdjGW!:| \wÆmՆQu-Y:% )/'1*6"mDUwgh[C`)K7!({1H?τku8F'nrexJjUz4]<]2J(4!BTN4wpsCOh9 hT ofOܜwYu6YR 2m*5>1pm^C[3|n^.?,%0#L%#$ $ ${4g{%&2XU*7?2,8)%H@( )%oFH..UxQ-1ٖs֋Wu7[ SPPI!E&zDa{`㣯쯣zyĸSSUB37~~kucmaiT^SaAG;?|w_zڕh~H['OE + \FLkSt`h>B#$ugS4k܋W7hP,W4M* K[Xr~dk?I*02"t \yymσ7XH9(&vMYU26Lh]6zˊ~ٓpV8YAD=)r^5 YYA܂qz^QHvcdUgP{.X5,(*#hveJ|dpmN) n T ncיs֊Rn0ZE$ h('~a. E?-{Wj1?#&1<"%4^Q, $ ${ -{ #{ #>9,9\92B)8(6)(@'$$+  ?G$ZG 0>;%dC64B,F0g)knY~ڕk̂Li/]b^P F$F*wF囟wzۦ~~}KLMvWdzkofamZjRrKWLK@@s04|ΏodžTn1W6 n! m!X?$>rfi^K*B/"B dvgЂEd"PE2#$c!K~zhrRUN=6# l `:3pQn,XB4;-iB > cL",$ylt[v:ZUC70*hAh|[e%+; g9-mʂ\}=]HC=6,} Uz|jrT`??# eOv~boOr+^8-5)4)%KGrh~`l 01s n l:/R*8/:B/AS%1#/6)"$' &J#OI =F:}$J9|H%A4$$|$^~ؐzݒa}Ad7\)QE>$x>)kA;gL壬̖y씖ĻsssKKLntoxaijhYdZ\PU>E7<16zku`x?\@ 5 3*b?hZ~m`^g/D'-hjeHgsR`1TB4/(gDnUyifa/1  7_ msW}ŌhӀFl$M .39*vMLr^LG 8 u^u֌[o:ZD20)xN!L fn8D, jnrf~Lb*J 958+ktZ]eBM#,"! $j WlŀIh(@-3;5'*!sEc5lQ\h>&*<"#"$$$ &r &{ $t ({ C7797,9&:$D&2<*C$'.+"'R#E= 24=-(&Bh/5{)0x~oW{5WHF?4w UjuihxNF-: Nkgj*U *&5%\EŋhqgVW**%/ Q]3vY5^<-.!hgR]˃sPY.wV?tیgJh(B 08"ju1c+kwUi@2}fodHf%?14 MPLp|Xd=JJM"0 b[& ߛ}Ǎcv?fM =,h),"$sDS0oxR]0<#,6==##" , #t7o &4A0:?-5A3'C&26..($; rP*&Y"PF;!(,/l$5A/:'O&$'#v` !yaAm)VM U$X(I-tH?wTथ}ijuq늆|u}lfp_ijdpYLWHQ=k8B/4(2~z[bـ@] L<2)"lacEouo[M=$4)U i\9jԃXz7`2(8*X/ XJ7[[BO)+-%^dhBr։Rn.YC1.|L? BRzm]g7NuyOdU8Y5)jvedtd9F V% hpHjUq4M/0#sZ0 PD0xՈpCS&1=>'!%~^U.'y]x9aA 'j*=0&"Ligu|blGN,9*#''!!&!#$_"eqVܜuۏZ;q(c S$N)U-W2S[fꨓ遇ӯy~zpxgn}w`hWbflJUBK?\-(*&]~^Hn[[b<">6 @smlkfNhA](I+}"kbGmm}XGH0-#$S ^+Ƒe~Cn$D 45'g!~PA RV#J:):2o$.'WVCOUsF9B% _nqfـoҁRk F*#A/N_aw_h@K%-1$$6?#!  T N~{|Ōc?eN < .&`'8f]wdmCO$1'$ #$ x% ) #h=$1B.'5&/)6 *$Q/30$!%$3^1\: #%-)|26-94:#1)$-=('&"b!~oOr5_%["^'W*N/N4{R񽫬v|{y}lvqa}qdRfKUG[aT=W:J;A3@*4,3 ({jX;pތ_t>X>%e&%ZLwooyiYFIC44];1$ !y fhBkZ:a'xy j$b%rtohUd#1 S_6ȓڔeDf%H7,_v |} $+,(rJ<@DjE*,q u hkAlY{9aG-43 q!N kud\4T= $#%?%! e^/(xӍ[t7XI%'+7S"!MxxMY;./+8H4 4 nr}hڃMk*N6"&)} ^iV|ttfm[aXxjN;;&'V mxdIz7Z3OQ" TkLlY3=i 'i K`WMޡhHe*MC)$(.,"-8'f60uX:%6%0%"&##] fn݆dHt%P <<&ZXMhbywW`N"@#$"/1 M eN<ȓrRn.Y9"e~'ePwWwQg4A+2%$$9#  : A+*2U7&3'Z90#.!1%) 28,k_- EA1/4'#i6'$#i,I%}}w{qrcqDJs:0hdLkӃW6a85,v_WqqgaCC* 43'`&;(-%a5*l) 1 q g`BjڄUo4[M1wU[gUX;akDPC72&&#(+ {Y ppWjӃIu%[ 4 %#a#]&YaFV1g("% !%B # $f"G4&?P8*3IC$2 J(F&:  Sy3NTA6314vK(@BJ=&H(+:(1;#?+#>=$q%^zw˗rٍU}9o&b"X&P*O.N2vOmlۦ٠}tnxtcmgUTXRVH_SO>S9F|G3D@5&@*6$2]|b$r֊cGm$Q E(^uKj`aGFrF>dVB_Ohisz~kaDEf:8oaEa": 7- 'yKjYqqWw11C*zW]+tX:_!LA0")345)d!!0E7\ *f&nԅ`pCa V0}$Rdv`jNUU;'$$ C  ! hE |{|b@e ;7=+*%!Z=H5mU7+)##"!%%H$#/i*+1&4'*/",$2#1! Q)#$ ,#%$#m"-'3FZ$0&4GG-'$5)2VK< 1e]XR:1>%000 $( /)X&/8$$)')#mkPB~Ȑc|Ec.O H$J'V+V/T3xQx顦瓆xtqzg}~i^ildU_N_KVFRQQ)7G[4."0/$pf&pÃ_yAb@CD!q\!QdIn=Wtp~KY7E+[0% #&n^@oV:%*U7 砚g^?H**F>MG +3y 2TNu暈sӉ]{Gq5M(A M@@UB w!(&;)1! zW=)pczIl.PCM4..vq4).U.' &&8#   ^aF9ٗj|SoBj1[G+0(! O  !# #d40 '$2/,7=J3%+=)'(!**)#*+.'x3 U"t`xя[q>Z)R!E$G'T+U/P@mS檪|t|qxxド|xq~kurar^hZdVaU\UVKUDYRN@Q.G0=+7/7^a#1+  m nfh|Pj-VM4$wRB_rqm|p|;H> ##YegҀOz,`H11+Y/ ObF뤩pYYWk?`44[7B {g"TjP9ޞڙrcWrNjI_E_@j5U!|2 /bW0!bg rzx΋jޅUpCa9j'P 7:t &D M  3_Z{tޤؔjSqEYkQ#  D! o(&2;;%2]8>4 K<$-`#,aP0VL2$)(-+ v"0L.BXćnz 4v 7TSm~\}0#wX/*8,F-?'# ;":%*1M'(.0*'8&r jg[P~ږcӀDw,aF!B$K'L*L-tIymulpcjlu{lrt}szy{zz}}}zwu|stu{o|luisf{bnaia~ZdWU`PY]cQddaWaVbZcW{RVR_JkISGc8E.Q&5D6A/ t_gAmՅYq8\C~e!Z6 # Q,&Z,.ē׼IfCSCIo2SRm҄Yz8P4-(.$I@o{ipNSf2@]46SeFV|qစꁁwtjYYU`;8|,.n)_QT SR TR3&%hi?(f:4g5*m}!:;!5.a" ! F! 93-HE G{{4t+$'163I@&40?[+*!#$#.1 -<EK F@<9+pg3?5)74Q$']!&&'02)%(+S(!%%~ c r|c؟x[>n'UR Z#L&D)uE,qGǠ{}mrdmlghfiojzxnxruw|xrzpsnypygn{vrvtpbk_ibhZdWbV`T`Q[d^S]t[e^h_}jbcogt\deeQ^EN?KKD=6&4#* $ d pۅd܀Ij%M -m%#a5 F0%^1?Q^,,y팪qt|V\$9Tl%? )'!kNR{t^^z=Lj@Ft ?<<4UdI]iuܐttykT`GF9H|@8D(!+z9 ( 9)* r #H) 8< 4 6$( y{{{n'$1$V$W(3$.!I)$3#Q 2! z'<AJD><7#g59-:&S - L)',E% .Y'\"') +5/&#z ]&-{zלsَTs7]$QT QF[?S'qC8kJآlutl_ipakgqkfpfruxoirkvk~}frtrzrtpamck`w^hZe{fZy]_U^QlzmR[UWajletgp|qmvoxkt`ZeX[HT=R)7P8&&%)i ikFlȁWr5^F,2+m9 5DBz23\T d'/vz0@ZGm\{Ȇ5]B2-(+l W ϏxgqO9j@2B$$6X= ??05$ !<!#*IA. 86*8*NV % &5$ 1 s y{{z-#<&A&4%W -54"(;+Y)$::N)PJ>6<;6)!),8/F,`+$ 4><)%'(+&((#,;&$nq`(*ǔm~Mb0J DHH^EV$b9&V9RwW辶|nk^iYd{f\foi`jak_g_o|^f{j^o_kass{aj]g[eYdocR[R[TlR]QWU_dcT]Wu_erj~ltnvwwu{f]fOXBN^IV?#1(% 1/rf4qՈc}Fd#F =3%M5 jP>LTF]u)WTY,5~GMa:CJqctFb#C 4)*0%l_婱䏙n{@ 9 > (V -` F'Q)1]#G,+-KhLa`l҉{ꇙ|zrnnhhbg[gtS~XY@77-<)%25) K   $ 701)(.GF0103 5; t){{ fu ,7%7P6).4$/$0#,C##PR A j5J=,&'# Ur,;;:f&3$ "&45$m-2("'&8&-/OR,Op_#g<7ڦfڃFc-C}58? A"o<$]:OrTblXck_gwS^dnԀh[jdfV_]q[eW`Yc|dYaV`T_]]XqQ[OfOy^XR\Q[V`Tszd_iakguvuw~|s}foctWmFa6B(6""<{$VkYlUq3L6'#c6 BnmNN/4}$!j YL Q%,ccyRUk\ulŀUd3E:&'4*jM%zz쭸聏`rFIL] :}8I4D -`,1%-Y#G#)Q./QT7Mqly~~xxq}jfgi^RyIt@@8[0y<8*'(*F K,B 6 3 X"[ M%:%"#8 {{3{dV4)0&5(6'>&4I1'+$$!K452 5!g`uuQ)-9*8&X-#(%$#$"$%5&(&k.,L6(/d&olU|_Ak(PHNPC q:"V6zqfr]gQ]QeYoLUO`NWndq_T^T`R\uaS_Q\P[NZUZEMTWFlSWIUM]N`eQ[P[NWc^hemkv||dXeGNDP4A#0 (" 0vd 0qaCb!8-)rcBmKmc{H&'*&k D7<$+JY[qֈapC[!N/%(eKKkYtt^{~Ywj~'YCcq&l4vI_IZ 6z +\GQ):q)X*4c39a:?V, $G:S[qis||vppjj|regkUNdFSM@9993-3'R"""|<,G-d5!=E= 7>E(T.Mg7!6L/g~6O{{"/ +'4*8n;24#1$:6$@ P! 3>E @$&**L1,N*6$% /Z7&."%5(D!(('*9*$}W%xowY}:f#YPSIAw; W5~o~tXbOYKWJskcZYNYqVNY`ZNfMpLWKXjVIQGTDODPBcENZgEVHSFOeTIcS~_je`jmwm}`n[\Ae4J$13"Wm_kӃSv1M33-)'R1D z\\C;9P|M 0 \kkzSn1a7 ##go?썢rf|`x8b[wE0/{n}vn}τnzLY 7u8sU^ ;*+3bB @<%7SA__xszߍ蒆xssmmhddy^kmdT]vP]oMCC@@@>=z<;>?@Y4:dE00>-<+((S_&&C%%%%%0%)%V6.D.%%V:.%>Q18=%Sj1%]%%Q>( }{g*{5.668,8*8YF&4 -9 !"+%!;DI=#&!s60)7C5',62$#)&$-':==7)`,! 4#'+ V*K/#*Z/ t9Mʗr‡Sz5] DJE?Cq7T1eqS^^uDMBKF\FgGSEPFQUbURCMETBN?I@L=H>NGCL`LI;\;C8B[L@cDPGPS`|{enY`PaOG)8$*%'' paB'p`AcG.#*-q6 fXiiUp+/V267%pƃ`~AoC0,/3xK革bxUIax15M뭽䌛v\mOa?S 7v>L &S1e9Bw(4b$L/4ZEMQ/3S&,IWAbvWdsw|yu}jjrgducplkqa`^^]qu[Y\[mUfRiXRP\OokOOOOX_iOOYOOOYbOYROkq[OOS^c]nMFFd8&Q( )!{w{*N)7.:6:0P'6#*+UBM9(!&" de*DDA92(%o1X ,L *&5&$,>$-% )A)&*'55+0+]R\"Ig1.<-,3.*,)+R&$mX""ʗmՇMe/CBDFI=W.M-}ktVYEQ@KRLBL?J@LAMJ>I[V8BMFgK5@7H6E5ARB2=?>2>8:/^OR햋}rykt\_U\O_2?-2&%!&)Vnmj؄Qo.b8m)#XE[.oo]jBb;' T4^djρQu.P-!29"S'[?nn뢰BiN%[[wl[CUi~EP!n?_3YRhOb @ :S`bk.B /fLU*6j++U69,%6XF\biZikxj~|~||{{{zyxxvu{|stp|nnnnnyntqnnptnstnny}noo{v⎒mm^^OF62A-{\-:0T7h.;N0)2@0%":) #Pp+=P L8;1% kb+69&3#5+!$*O(--)%3(S&6*7+=64)X'8'.*--==-#Ghb<3јۘhӃGa*D>=<A:X,N,v~zhIT>JeB& ."WImfguYMA8%PVF6,p|^y>eA$.0$fDžesCl8Lkщkk((6NLk+yZ@67`OkSlcuD_2VE < > 6w B 0i G  / 2)UIPgNU`GN\/U3@3@-8/=)6'+$.&$D(B%04v*(@?6=+(i2D<;4!/&$;F"(*G"-%2Y;)65B3?=D@D3@*;C?(5$2 ") x#bdjO~cՀBU&B;29D8b,%`5Ә}|U\LS:F7F6C4@_E4@5B}X4A2=1G4:8D:B.>,:%M*9-6'6zynvtwf_OY>i1>!?*&# qfojiOq,N751"p?f[8oo[fT; <*rT foi~Os,`A)x PFnbl\NZ&t1)=f}ꓤtO%[X+yTBeV]sى哢<[<_o 5s 3n = +@;H>JkunzPX|+8m-]%QD)W"MA? #L&P +5;_9@^;A\&.Y F*1^4:^.5_@F]#I39^6;^(QB#4!G!G&.Z= ?*/Skl}Pf=. 1Ob IAPC4MjF2B0M.8) *!A'.=H<:04<3/-8:*>(:A0"2$&Z%*,3+94>_@NrDNZRDN?L<\GG0=*L D7!)!>q]ooO{ܒ^|=\#G:BH:`)K$$P.ӒКn{Q\8A5@2?2>-9C:9>Q@l@,Y/=+7_@(5+GZ=%9$Ax{ykulmWJY3>G2-"! rgN2p^w=Z>8({~]UߏlfK(.#$B,l aY7p˅^y=\K:'oN3 6Q9[w~)^oXt%[|LmIkΆLk+yZUm\R#sTpױEg/{Bb_uv4+M (x-F !V P  > #U>LW` > /g 4n %S7D)w A M7o$8qDM1lHN^&MXryh11#5KO8E8EDE4@1>'4#'"$#f%FPJ:,3-!!w!)7;7&U3")'('>!/ +I9:C@lDMPYa\\olHTDM9C1:*U#<!%L-y#PzmwY|9[D9?4r*n+U%!Q,Ӕh|NY2<.:.<'31;,;-D+8:E+7&1(?-6$8$525usndm^fSY7Ig{O*uex<^?#Z2z(qNWp>#ZoӟZo4["U4ZN  I2gDd@S9.;  Ay 9HPN8C7I4J2>59).'$#!&=b%+4 <@.ghR,)9'C w#1%5**ZO!.&2-8j^DN`hirvvkwٝq`kVlJUAKHh)6!?+$*}lZ~ۚp։Pn/O: 9 6 1 + m% ^#:]={chBZ0=#/'=-3%4K5&=A4!0-"D;1/,.[w}smyfpYcGO;F.W5()(! X sˀjփOg+<("tmiW~aHVb4_H>:H| ])s݃j݅Oo+M,*0(S=YaJtRG;d@eI6tQpi~=6DO(u%[lLbyCZ=pm@eXsG(\0^Lk@IOb@eȵf}QRoցOo8mLmҪCfFht=Xqyaxby [l#W"b M 3OI9C+3 , =J=`=J9E3=2>,900')7 )>:79>)!%a4..Y&4Q4!E%10,%#"0-C??Enp}u}nwat]dFM?PmC(="-B,&$eLЍmKp+M<= C 7 / + W 8Z6oxG{2=&4+]44+>#<>%.:2:-+'7,o)ts{vxgoYaTZFQ4>(4J(6%(*'$K fiAr}fuI;%\yiDpaAH:w@XHn df?rʅ^u=Y>/($xk[!tvnq̫颲鞬'bUQ!\=_UR^xf@NFLkk;_w0~RRoQpLmQpTpLkby_1sRpoROWRGyQp;d_wLmQp3_D}m3_k욫8W1FkQpԒOkH_Ta /7D;6I*"$'8B=HeM5=5CBO>;83*!$8!F$NJ<.)}'yf;%O&3*!$0%K' W&$##0-H|}yqnqYeC^CfyZuwzOmN5+yDN6\6W-|e|Fh(uCfa#s}.~\R#DOoQNX5TFh=Fh̆~#sW;[wCfy3}Cmx BBa6Z-* +%7?M?J>M>KaJ5G2: .'##k_< LTG1)m%E,97(6$?L*;('2'$ #?#!/R䔆닁t~ugfXW6A&AE/X2%T"_ a4+瞀fCq%RBC7*nfp#6o3iqO8F,I+1&,T/,H$2<"7+)"]c }$)u}t|i{bjOXEQ2?A.!,1 !#o `aAr^~=eT>&_wd!QuaEEm+  efH3r֋^=e8j"`pe!VVEGv,+RwZm誸pͣ*CTZDg8bRZuRoyqLpWqIy쉚-|0^!pm^x|tX8s^xf}+y!pi~^xLkO)_Akkf}(u+Caw6ao]s>[^j7s7E;aPH $3:GCUBN@LA991&#7%  Q@8R4U%LHC( ,g1(BD5 <&</*! !O%.%$#ᓎ{r{mkT[GVZF-;cA-#I*(%y X Y1/ޟ~ٔc|@g"YH4+,+*/4R\DPJAJ2447%#B7'6##'|(|4>|&s|y}l}qYdJTOoby1LkwR`ZdMT2<'':V6 5,<  C]mS?JAM>K9@Y>.z'3X YS\p[uMr:e'N 201F*=.)=-%<*$$$'%()4ߋwln\hFY09+8('4,, ~ O l^Hݟ}֒b@p$O7-19?:52M0>"-"+"=!>3'"'@)"'&]3"# %j z#[{ Jy|pyntfjSbDQ5I!,,*%'* n gfDv܎g؁Kp0U QK)Z o0'YE  2^gV9vg`Tj DK)%'<;AM' ~^B _5:џrz[yH7b*_!qWmNOoӉ;dUbyI6Cfe|聒n\ f(>22C7775ig.d++_*4|XwӄhGo[z(U(Uo㉙hq(9((7(7(L6k¡Lqz(-wCT%fJWT?;(\GD4" GSGVPX>G?N;F.904E%'qnjy|sdO`-GESk 2+R-!#B( $ $xpaia[Ul5B+`$2 #6,+ wP kcQ~גeHm1X"H6,9~[(!L-*&&+(Y*(&#%(  "?C&! %k s 7v"{$uzn~r\ewo7M/<*K+$ #h h _{Ӊ|ݓmVzCd1\J+'& M $!#_{͆|mVxCb1[B#22#H  t UTy]pݐSx˨C)w}@eȒU6@ [zt.k?aMMMXX]^^[vyToRTRgRɡXRR{}ܞayۧRRReRRmmӔ勜rFp**aE 1"7  -=(KkLXITHLJQ=[0:&4+!  q]nԅMj-]}e !%'0.&#9,"T;)$$##ዓ|yzks{qRfLO5C`; .6,) u TlVF̛ٗnՆUo%),C#$$(?ExktiOZ@L4A&0<+*("2,9 .)$ .-9-@)8)0&+%+##焋wjs^iOfAM4K77!/M>"2 # %# +%(I4AGSUQ-SP@<Ft}a_5B .;'$##$'#$9& *{ %{ -i 5~typXbGf;Q5B0<08(S&18!/.- .)(<1*(,1&* > 6%*0"?'-$/#. 4  &V%;(%BFA+<=  02 "!.E,cTl6>̮那k~߳!o7XR5Roքawdz\q#h]jLW0"A|䊊wwZZWi * 5-7 + *1 '+! 8?' M'=!*{vlublZkR]GRsVBQJF?L?W?LAK>K:FEI>J?I;H@C3B)4$nF## %!vor^hP[ieFY)7O5+I%$#)!4*5#@n"jsj_NKxkUjrmQ8@18&## 6$ % +e !{$Z~ulubmTscmDUA]VB[ED_B@7D4Q5T.77:D@EQH>^\H7@9E8E3>3O5CQ>4?FD2=/O%%%*Lj@;;7-F(''5'j)=U+Ha7 G( 842f TZ,tt}~@e-|8NRZu5`B} +a9B~%.X/gt__>@J"f 4=4.C;,27 X6=- d 配{qyltcq^iZdcNXOV[]PZq]KuVQRqNXQXGSSM8QI;53>&"|ry]hP[CM1;A9H>)'!&=% 0(#<qm*2'&2., _P~|~XbCE!1## $%<$0'$ ={ "{ #v !썫w~mir`kYW_Q[IkGPaSOWIfWLQ]ZxZKWJUMWPWLWKTjnENSWH\ITJ[GTtZIQD]EK:JT@<>/P]""$.' <$  !bLrO[菏|||bkm՟m3a\x=emlCfT&eAa3UVb9DD%+Skv~އdTq%%9M:1"# )+ QD  +ڏvleencmbk`j_jce[]h[gWaU`Q\NM>j7C*9J+'t|}egN`>K7?(O%&'&,2"!lm5"OB,($%!zYfSgpSW*4)+C'*%B"@ $gs { &|w~ireo`j^h\q`qnefbYoZpSt\dYdYbXcTu\f\h\fafZer`[e[eU_ZdYd_fddR_LLcL҆M`NRNNNrVY^IIQC<<55,,##R@S (-o Th(,ᄤl}n#'sWUI=el_wQ83|D 6 ;%0](.SjNckIIR*%%(# 2 <$Me-# ;䌐ꄊꁒwu|oylvktxthqwjpd{b[eQYnYRT;G09/2!0{syeofGu9E-B"1%(&#)lzFMyCe.L;+W_LDu~\f/#C-+, }\ RxڠW}<<|t2_Ux6hls&m8x%B3>w'N}~}\O11%40.4 :`7ZN)刟Ɯꩵ$O=AfFCfLk8CfȄex#P =LU.5gdQcvpZK/#, )% )?   4B+@<6<3()A)+) &J&K8~ a$r܇kOs+S<?2"l>f]Kku\G9*3%&3#:(/  # ${4r { )ꅇ|tsjj_jQQPCc<))%Z 6% ,OQ `iztꆖSrkkLmby吟j}1[@ 4q )X,J>aold;0/  2 ,11.hI5$3 2R,$"%##? f&ciFs^=bG8)0@&}3HE}{vYq6A%=-c'N3*>#0.!n&o{ #YC؊vz|ccVLHir-4D!3E0qfTc-6rԄ肒{qQpRoawe&s`u<\ #b : 0a.4UJ<[℈ꠈ[U|E%  *%!$3("$() - @>,9('1\!,$F#fas}jOm+O7*0K&>lNckCzk]X.yPQ%$$$!2& 8x!Z{ "܄yqqgg[MMbv1;%X& 3.vWYǔބMuw@iGJwoF PoӤiz=.DLTy/5Y)+MԆ욋wYYJ:?%"7F# l!$V9$A&/(%!("2&$$ c#!j gVGr^y=eK9)$!eEtt^i?JJ/3&%$!U* B |%o x "{ #酉||ttk_afXnZy52*. g ")F H qqqVn9iYGRKWq>bSTx "{ #{({%{ #o #`z 6gK{ 8i { "{$z *{ #{ #{ 2{ #w#q v y #{ "q ^n }%1*x z - &y  % # #x  >~ !% $v  # #&{ !{ #mo { #`N{ #{ "`{ #{ #l7{ $w!{E{%| #{ "} "| %t'mn{ 2o'#{#{ "{ #l{ #{ (s Qt n{ #f { %y C{ # ) Dw w'# %^ ${ oMx!} #o | "v {#pMjs { +j{E{ #m++{ 'e{){ #{ 2{ #{ 8|&T! "$;+$ $ )%;K%%1%9#$$$)(X/$"fSG0sbuCT G5-8.}\wpxam@K"0(Q(#!++, #~-{ #q q!zzsrnp_{f@C^0!!$ %*}>YāuwTwh}䍝Xt6_TpUGTmA I 00+FziKK]' ) $6p{m({S  ' # $"&8' +$ $#* $ B # ) > $~ &/ !~ !f| #x#{ 7v !dz E{ #v Dy )z "{ #{ #{ #{ :{ #gm{7{ #{ #p { #w!z !d8{ #{'(z "{ #{ #`fnz !{ " + $$) % ! / 0 #ih{ # 7t'" $v # #u5: 3 \ " ,$ #o N $ # #M5$j h %  $ % 1%% # # "% / "+ U&$ OZdw .v ;!' $ "8 $ $w! $ $ #%1, #A &; " $| ${ >n{%{ (m{ "{({#_0{ N%$ #&& ",( #t+! '$ #&&w.>5}YAg6wR]1@, #P$%$ $ ${Nk{ $zqimcd}\DKMD'%] %#" T FtKzkܩJlLkѣFh.~LA`]l 8w6@y/5X3)H⇠iiGR'' &$P) n { ra{!1{{$ G#     * # # B$ %$$$$ && j) $ #  $$ !~ . $ 9~ !**ry j1s1} !( 8 $!'} / $`~ "u #{/m g>v!{ %{ )j6{ #ksdv {(?{ #{ # . & $ #" $%" :%0#&t# $%'`o $ Yz \-' B $$ $ !l0' $7}$-' !(&5$N !"#&#,%C5$8( $$t! !"B $ " " .$ /0$# & !$&  !  ##$ E $' &x pey$u {${ "l$#{ #{*1h# $ / # 5)"'$ #'   >9 =2- $ < S $k m)"{ #{ #V_{'m( $ ! *$J%,3%$#7 -5%`=5G6k:E27'6.?)%A( ) KI# l cA0ud}Ed"O ;=7&`Gn|aviO$1,!!$#: #  $]{ A{ "{#fd`\RVEJ7I((-O (D(+e DzhmmPPq}+w,zki~LkT%qpH]NZ[cx*/X50OیuicG:'!75M%0}o`Zz?c/%# *($@*$3#%!7 $$S,%  #2$(0 #  $$'& Ls  1 $, $#!1 $*+#x"x";*$~ %y 3 "{ )q #{ #{ #{ #{ F{ #{%{#dt"=Y " I  %%%<+$+&# "h !!$%%(&8/y   $!$%!#$%,($>#$B'%$)E0$/!$!,UO'=+% $3!$*(&   #D%' '#$!,$%;%# >! %A<)~m." #t { #z ${ .{ ${ +u ,{ Y~ " $/ =   *$)&P L9@!$$#$$$ ^,"@,$$$! /b n%kPw / :Tu !? $1 H!-%   $$(&/IDhU]]g[aKScI&6*"$3!H, N nmpǃWr4fM@5.!DET1|nxPY4?%C+"IZ'4  $ #{ "{(D{%VvMMCE]Kg)94a -sjK jFZppQyv :[*xNWCP<,l? 93PC[돘拂iiTG*S"a@ Qy{i{{g"&%  X $& B(& % $$<0774D$%  >#@1 ! %%$ %" %#$2'%& 4(4 !$# ! O} &~ #{%b lA{ %X9{ #{ ${ @s -) 1$ #% : @0&) &$ .$#@$"?)B$&% % .&%'8 1A1$&6!$<6  %3% 650/%&$#06'$ +$@C&> &# /!5&'$("$' 9 +%-9  $w l:j jp { ?z !{Eh& .w !| ! &=42$ A$!%#" !$$ .,'${ ,$  $,$(" j$$2E$ JKO%**44''0.V(*46c!P lFVΊrzqՉuu6i~뜭Lke|S,tK 0:?VJ;Z⎉lh^G&*.3 ( F{{ /{+{ %8& F$%#$."C$$$+$$$$)"$$3#$" $Z7 ;(%5'#89>8!&"9$!0$$$&0 NG# ( 6 ! e& T#$$<##$  &)##*$K!i&(%" #'$"bj%oUAvnFy[䋒mqvtNJ/4/ F)$/&~Lm[pXu5]<&'vYPEW4muNW4AM%% 4 ! #&A$q U{ #F>7V/1%@$?!Q#9/@ k uO c#+賾rS|FtƁcy7bWKTpכTn; IQzIQUYH\ngtFD>N@='u'jiNr 'i!#6 5" $?J'%0## ,%" #$#0'F# >b 7B($(!"&$##!, ! $#*&#=&A""%5$-%!K #^ $t  $%>" = % 8 $/' $- >(+& (/ 1&*0$#+$"6!<"2 3255##"6#*$#8 '%'!C.= +$ C"##i1$.$$$J4 9 $##(#$%#(%0 "%$ {!(1'%#$"$6I2T5 " % %m3{ #f3h{ " $k r #"! (#$$-*M$H- :?#@)%# L,#(#$!*,%6$#  %&E2"$4$=$"'Qp.oW[D];ϒ甙xfhIh/:&.4@R()!& v`(vf߃Gm$W C,fiaLzj_mz(D6(#*T"%$] (p 2e{*(33//)@2`58 ,(rGa(.sb5N LTr)v@eRo5_L $2=t7#*.'%#" #9%FB$.F #!$3%%<$$"7#C)9$ $"$ $  !$ / <$4:&!#$*+* *##'$$.12- 1$S(8!!"$$890^- '8V'+(-1%3'= ,$qB-*$5"#$$E%'2%2%(S&(#O  0A'&6 6&'#9&%##B%: ?& ( % # ( !i/O7(%B$$+#I(3$Q)%$8!#Y+'!'%,%$'"$9&?$#$!%!$%3&$ #$S!$=&/%%8a+#(@)d: =z o#WGrc祥䏈ltR[:E,>0\#9## 'g leo΄Xm5VE5'(65s?OfFࡒs~Vt3>%)F"K' $!$ O{ #d{'(W&&""=Z, 4 "# ;$$%!yu N_#+觶5MXr86aRQpUn- 4u1b%LH<[~jceu 0 >zv{{m{764%#"& @% "$##%2(('3240?FA$/$3.\;!)"CM#):E9'"/1$<###/+02p.5;$=,#1$--%,&# $%$$)!.&  TP>(4$%$*$#"$S!#&%$49!0 ='(-& $40%&)I/%a@6!2*.%;!A&1=BMCOEOE}LUJSALIL7D4;#0D.C #%O,-0,!(4$# $$+$6&'!F,-MIHcJ:492-4.CJ+1' "$-$62# #$%E7< 7$$$!(/;(* $ #*%6&$@&&(.&<&00B-\'383-%#6 $ ## N$* $%#$&"#$C-4% :;%Bi D&~a6 ?x}aiNW5G$4?,S,% t X%ufyH\$E ;40??K1e8ta{ajNSA6 $;&;###$ !s  /w { #pH]/*5$&A.  K !%<+2L |K]#5S`}}yp~UE$0#3'A/&-%$$ -#!7'53IBNLXU^b^RX>fM9)7)0;2!+%2#/)7"5Z7+C%6&4/;)&3)3J4%c$.G2 .I,+#5$$2&=&#$:'?'!3P$3&%'$7'>$*#$%&$N"'+&,92-I9EBKAMUM:F/?9E (&F/$'K$4$#$($/',J4-7dMRZseclczmummwnwfxciOWFg3O(6,;3%.83%$3%$##9L&4&4S?:jnZT^gXQ_CT=J4A;M%2 -"(! +4 $C$;0$;+>$$0$2 % :/*2")$'"J$-2v1<>HMXgSbO`ZObK2?,4R4U0(4+%$$&##"$%5#d& *$.%&$6% 3$ y b[Ro(T+"[NMUX?Ԗov[eJ^,9!$-!  g"mapՈZt7^E6/0)v!V#qU_3?($" #"3$& 58 !] e{ #,A+"' A* I.(RZ!)Sf5P iClFhI6aM jNBN9P,4,77w(4b>*(6&$ &<$):$%%#$0A-%#1!6"&2$$$%<, &7"#E2=>II|U`^hrotV^VU4A-:$!% "??+6/KKcfirnervzrуငox}|hsmslvmw}v|vlvnv~wlvkuxvktmxgpotxwiqtdpco^alaKYAM~K.@E5'B#&9'!IL$+"$/$##3-(%" 4`'$%M2AE]U}sktw|hrJV'0+21( *#2$ .XS0&31?@KMZZoNlbDAR/EU2?d:EY5ES3piUtiʚ}[eA`@?"6%($( <%08% ..;7BGTvbfph[rezj錑}zqz`iQY6`4:?(3#Q7&+ +F'7'$$&% 0##$! -% #$#:@+>--eYKVLd`eqj]emyqy`iTZ6g17%9&-$G4 #"+$*%$&$N9"'' Xonc}Co@%' pU/ EY7ߚs}V_7I%3%/gj]r\9hF-#"f!K s{rb3?-%1 $ ! =$Ow !p # 32#"$  ($43/)52 Zb")4^L(^@e+y9TpNUz -*8w[dSX00C@ u5l {{{LN6B6AKCF=$.)DDI)$&)A"B+MGJK^XK!^"W1 5 vmS脈졋遐܁낉zvwvu]ie^MN4>&/%?&#$7'F3*8[EV8o"kgUTtNIYC8 CI2qf}iq^_BC&3C309! $B7"!<,909GVfC ULPEynww{vxmJVTp&4$!<5N$#$1 #9"#3 *$R(@$$U$$'*%#*,97@GV|G!v*K3 :uj|u}|}}uiKW2q),.(*%J%$$!$#$ *S1*J'!pr bYAj̀Us2V ,), uG1 BwahoSY-43*s _(ujLq(] I)%/#X~i{flHR.C"<"((5 $%  )| !v DffA#- , Ua:1  2>4CU2' X?)"P^#+Ќ1Cb|B&!pCQ.[ B 3<*pnzoN;u+Y +&{{ t"{=H8T7Q8CeF0=&Y(/A$!#,#1>)!i!siB2 KE^8E\7=e3AX2BF2EN0EP1DO0DS2CP7EG.BQ29b5Ec;Ec7CY2ER1=X3CM4EQ3uZ|eUsgv~s|upUicP8a35!/?$38)L($,.&A$[1I2$#" $%4/^:1Q G_bO0 !?ՂgnKU(4<?#2&%$ &%<+_N-81_ lzuw|~&hl"fJ=<!T%}{kyp_)63%=#;% &+HD1l.kztYB!BG QYXt`u{ocFR1>$IG/(G(#+#"@$$-$$R%$$X0%0E&#'%)EQ1," t Y I!J"G A:CzcؐwahO^4L#5M,+!$$"& 1"$'2V3# #6"foaxDg H1</#uZP5 -E'ߒ턍pQ\%29C kiOr։\s:gR1%%"h-W+ozWeJD13$#$$%%$ %{ 3{ "{ Q65 $ $  Y(1 (  1 % ( % Z ]#+M}ĉM&(u_wl5.}RI\0B:1΂}邏kjLHs%+=(~{ {{f7Hp^}V`)+ _uɅi~Lm(K 7,{KvbzfgdT'G#(%$!$"$:#%% %{ %{ "z $ @ 1  7'= 0 QF9..qJPV:-9+((0#uD&:JwKb"3ʅŏk@JGTp-|6pUoцׁ8E7/v|~p}X 7  L jt{*{V?L9B#%$#'#/!# -%B4($$4%|}f3&mֆ^n?XH0,3&*vmD9 =S5T\15z joIpߊ[|:ZF<%#)U!;}mj?D0.*@#F%$ >'  %s"y -T JX  !5 $<(P:IISRlXysW`[kTSOOHT?=c4@ 6)+3H|ImGSҜ㳾)VnYZy5`3|euXe0e8A6Qz^^:P"7%J{({{#{{FM[PBMAL8h3@18'/(  PRBd;Su'#31/$#+,,yXx#,,!)356-^$4*n|+E Xf\XL9:EV6vh셀lpQ\VL+:#+. !#") M''$$&! $LT3e"X G4x|q\v}sNY/9fpMב{ajK|3E)6+*%#$-(!1! +!#" F& _jefxMc+M9-<*):'"k@<B}c] /q9q~gLl)O ?)&/xSp\}ipIU)6C0"$'&"( h% ${ "w { "J!A%0('N11JN__mttvvuuuu~tsqmh]rCc*- !$ / %0wUtF[ܟ卡BB6Trn| P )/5ZUA]免ttqV<8-I++it { #{FRER;JB]UB5E4<T'&;  igD\wOf4MFA)((()# 2 ) 4 ? * 1 E D D ;:9#+?)2:%[#2.*&qOBG!K"r`節zcmK^AM%3:A&"0& $4!)FE jzJT~Es+_6'( ?aWowkL</2# !($"89,@A-w- );%Q5W?Y?X4T%C586)+,"TGvuVjxIT&A2#)dPOmCf*U0$55,)!#&&ueZ<EzauckGT6A;1/O*) C$$?&-! /$# # %_POzCn*P3()4?4(-+$!WF:Ecu~^iGR+:F*@!$*8'3%#Q%&$15;$fhY>lԄYm:ZB4A)&:/"!v\D;kgO㖈`Z'" nfDlԄ[x;U6&+.[!U$z}\_2< .6$E! 1"" # 6v %l h!,+*}:),aU|;`@/0;???4)3:+!^EEDwinx^~jL+Dh<+3$*D)($,)/)+"& .[ mwcoHf%I 3>,&+ -&PK<0F)ۏFQgbKa)B962uWMk\irOT*F,2"/*+$$%))q-s!V{ #!R9,)!J$#C=S ( D9@g/5b0128W B$+Rƀ{뛇rrSg2aeL7mo T |b %qCdzq;(~D +\)6f=kkqJV"4  B\0{"v/^ KWDMJtHafQ=e2?+4*&z qhfKkwVk5_D#~$* (J[ZkE\Sa\w`}`r`w`~`{`}_y]v[~ZqWrT~OlIfAp8a.P"ONFA&(0)cpYK9jclCa1<"0='Cr3-R&,%5& #Ofh\~Es$S +%SMr}irQaG@+$ #[{- G 1$%y*@<J5^aLrcݚuݍ]{@o%M2.1."]F?fiI똖k(8&, hiqaIk(P B,.73 '92-1!K"@%&qXP0Y.ztrP[4M57& ; #7('5$"5/ r iuaIv(] ?'1<574)(/5$wmK/ 1Q+~gpP`>G%P!-$"F6f'F'$$&&s )ifJj́Uv4]><1/'q-& T'9vx]R:wpF^|So7aE-2&}hN$~rzb;O'G( $6D" % t { $m**5'''%% L_&H,(>;uGb ) /i[den2A} D.?   :i{i{{PPl\LVKYHRaP5L-9*$ f#p{buEk"H **4*7,NKibtqxy̋yĉyҍzɋ{zܑy֏yڐy‰wvs֊oՆjd[}P{Cq5g'YF9;>($3'pJ:GEi<͓}Sf9F".<)#;&6@+:&H { \fAbOs0X4~#'h@dQlT\8DL7%&# ::O9 021I*N=>@R7}e[$ܕgH^*C=681&zT2 {eySb*$}$`e?h߄Vo6UG<4-,/4>3.0+H/@&#G!:sWINUnMג~\dLTGB%2W%# (# 2%E@C kh[>hV~6fK--608?5(&0:1$eFBU_B܏wakLe4B"0 JH&B*#7$: g $mσ_wCi S B6*4<*"$*"Y6 ( nXn)69SeT?n$N +#+!|^iRyj{GSW;)$%$&8'$$$'&{ 5` 4s 1{ \Y.t4,0)Y$XU ;]L &=sqD:C3P ] / !\  NUu8>Y>iwnLL*=S0 [BnfYmMM..jO6aÆaxZuDKe8OPX24)cT//22u {ZR{W_Uxg_OaRWIP8J*79E'9) (l kxVkwTo1]F,*)$+cn&&5&nA,kD0cD/`T3T3+W?6glLdlLghLnuVxvwxΒߝxnbUvDc3N"DG/) {su-r(WGyk\g@N&*4$$$%@nk$fXt (#/K$R98\~(G '_Jh\I˗ՖmMq-aMB411&XBpl:G jmu`sDd"Q G@- )+--.4*%4)Q&L*|ybDCua悌nvXp@L.\-*.0$$ 81$! ( hl܃`Dq"X 6#.990674;;4*$t!+ aHEw`zYzAM.D -A>,; #/#+*  n ]pPgxPr.^F2/?;')4)'-&y=8 eqFce)4`/=o%1 I157{ _%p{`zApV0)'*/"+*v @M v&u m o R debHFT N`H:oqR}wԞ؜і|ӐpՈ`sMe8d%It'r!10+*r"G=Ea:]h?P$0?A$ =##Jl gk_Gm&@ #-%#n߈rkt^`3`8  3/ .P(SC 4$.73-7" 6 ~ gTZ/(єoOz.bO6-/%kQOϗ^iY+w jXgRv0R<4'&.$"+7>-.=><6/.$cNL!Z(thsOw<@)@1)F(.E)#( ~ejYg߄R|0a@,5?9%+45>;46:(+- uTA3 !A s~hrPX8EVA$*)#$/3&, { h?/mވ\y=eT;+0:*+6*)/+0m7 Q1z4U}(-M-X(K:,(0)}[}jZ}irIS+9?$$$$"$#$v { "{ #m>W8866W2,DW" .vwWp{{lvPtoh~:l:+D'F (\ G!>گdBZ*! :2=BH \hAJ__g oHN;d@?p_oU_*Xiqy__;E"A%|.r {{+^g]gY|PgZZ?W6C/2-("0!| j mbi{Qt.bA5(%(zfW1;K+   ~   )| r "d\%T T hO?wgwЋeOo9W$@88:7,peWC=Ǐ펔y]hBK75<*04,))"( {`m?dRf2I84)!%wjMpxcx=N!.7/4*26_/Y"O >/42-3R&400 w M K‰pOx.b>$!nonX1T+҃yCOi@+m]t?S8$%0/-45:? :=G G9&+70" sR@E\9ߓt|ZgjYZ: .%:##KM!( _ W1#m]?cE05??.$%1@ A2/ 6'*#wjJ;FCg<ߔ~]gNl<9 /!)&!  j-.msfLq*^ I*04!o,-%(,/rXmjSN?|Z$FA3 )h(5*WE瞛h9I(&%$ *lQC)%iZcgRb4A#!J 5 )/ ln Q T @miK|Ǜ̖ydMo4[D 40"(qYHM{|gIB"/7(4;($!% lgҀZg>\I:."l1V'|dqLU;7<$;[4]&\8,60+z!HPAc3OD' (*TXŋoOx,Q+"!# CvWIr$/ulgf}Ml+R8792359<AJR#Y$[K74-!$-'iQIDq`虞wsKs.8i7,o\**%@$"" h l kjfMn+R3/:73/!07?#J$K96615,&#gWRPwbrnMY6C&L$#$6#Nu hZClY|9cQ.h+@,$0 ) $!(/~ $bT#g7 2 56 : /0hI}hQev`U.8T2%*&"# # ){ #m { "FFDDiBAnGC,,f/'fZ0:zp""5baxfkfx=?H~AGY`Fjg\KlC 4R To][yG:_syo}Nlyju$6m28_xbj{ffnV!0  > '2{bhzohqfpbl\gWaOZ]O4>$2?2511, %Q mqgyNk+VJ)nk`nSu~liLL %!$"1 8A!,#1, "  8  v k B T e94暴՘vߏ_~D[*C@,,9.&oPR~sWb7C)-', #;x o d[amIg(K 5,qkcTkjo{`^6L-!  @\9b*^='$'#|WZQ\^K)70! $| ` XËmKh)C:7.!$U4 vozHT i`@lZ:a>8?B3+924EO3W?i>k4\"K<-3;* tbM!Z)s{[|sP&0&;%#""I" c \`>lZ:kD%/8275+,*C3e?n>]4Q"R=45.3'! UI!N$|ovfmLL'3)n&&@m fodHj%U 9#/;+/ ><A64?&##~-l/+185 ,"fM}s|Yo^FJ1&$$$ %$%_ { .m1LLkKTJDM<<2]*-' ^pVmtΎ4f``z+yStK 8x^gu8=UdIZvvXX5O97K0!F'}j SgyEonK:Wax[wmdz{Re 4t4e.aC *#xfVXjWU@%Q'("*#d a X"}ϊhӀFl$W :0/+xF!G en7.gjzdIn'K 434&$)".6],4JOm[}YqIa4XI9-(,(~mVTva間~qGSGA"0 "6! Vo݁dIv'T *#67/5==4za+4_Oz[{YvIp4T=A84((uZ?2 s`~koI,3#1>$  ifyMjUz4aI/"%!3/L+_.P(KJ 1(8%f%# )* +)%tGcR|irJU(*C!1#$*-$$! ${ #r {%kjRQQWLD_k>,8 A uF{lϔss;QpPAJWaIPq ?Zht`U22!+[!  '"bf6H^oYv,yO[N8bWqq%k  N#M5$@ziiII%%   r'`{n !lwwtgjoYpLy{H/<"1,O:#eoygyLi(R <^vY<`V|bkFU=1#M8$$G?L,4%$$"(#"8  ~ n N T haI؝ȗwَ\=m"O *#+,&K5 P$cmAM&4&$H'&g m(h\}AfH6!%|]!X"v{rpIT2<# v $NVCj2eC(6%c|mE_sl]G@0B104 E'tN N}ԑb?b?46(wP?tTxEL# fnGkW{6W2(/"!#$03fi$D$iPgs֊oׇ^{Fj.S7 )*)'$ |gJ0Q.ێ꧍nwbY@F&3+4 r YwIkW6gF/6?7,)'0f.6%iQgso^Fe.R6 34&.,%u@@1V-ߐo~R_:F'3%#$} `: n`Cq W 4")/P64XE\E`8V#<++<'_&'((h4,i"uE:脁w^e;Z'0#057<$.rp { WmYZXTTMMBBD4L;5 UsM`"+譹훩e{Wqٍ#sD)o,MMW&dLX'#1 p h]EmxYm8YF,-#C =mMX1M!,F(%0$7%#4$)H+a#:& 2".,-/ l B K'|r}cCc%87?50|[\UY=s|SiQCE.!"###! {njTbxLg+VJ+kAmj{WaGQ#)  XSIn7`A .6%QUW2bmulHK$7%A!#!{ _^+&ѓx؎[s6[B)!"~Z;xyfp"q nb|F\"E 9;+'0143+J-J1w~pXw>`&K>>:/&# aBBs`voeLL.73("fpbFk"T C@621)%+4I,L4w|pXs>U&J@2%2-nTHJp_vqf>`)7 ndVgցPu.Z51=21=E~+i\>fxn߉XxD[)@@7"m%%))(57,0(sDeUhpNXY6+"%*9#&C, $f{ #[__`_[[Ufqt>O/e'N-2;_jAVz]_\~ϥGiMlτ)^-{\LcpisJQhhrpRQ3/ 6@tLksII|\{Ai>OKGe|莞~Na +^$R00XqsggIY4% 7 mc.PKoxowsubpboka9D0<"0C&!eq|eIn%I ((9.e7 g]u}yt>I&7 QN#)D%%1C ##&!+($0*?69!!!AT qpSޡڕfրE]%@A85$yoCrúbl?J&D"$%6iG4gVx7`<+'+wGodJw{blBX)1cJNq=b"H 0.//}!g%|]tFaE5- .S!`)FS \ eQ[#&q4;OOaCczWl*I+;v IK]rnWd44 8`k* oowxumvclccQlPI/::KF.+!$ n icEuW5S1*-1t0 EP/lO[EH'=.$?#;&$ "$! 8$$D('F"/# jH ^@3ЗgDS$H I?3+sxppr Q!{myOf>=+*# ei}^D\"6 2;,d^j#u~foOZ)7,} i^;SuDo*O:.*1!askd}Pc2@nA"%.4>-!.z%&XdY~g܂C`!I=8;+m_ڠx_j+# n $n_~AnVE;48:50$jfBE@auaw^Ck)Q?4*.*'RI \'됖e{WR,9$'} e$(o_yA`N9:4""&)vH}jCCA  E"uv^w^Cq)S4,-0+%#R= ^'ȎaiIR$B_ j mqfLn*R 3i%"#2Y1=!N9yڍ~ӑn˃Qy1[G 1+44)(<'!651 = LfkI▃kNP0R"*"'A#$;M--%6$ ${ #{ ?{$ׄjkfeh]\C`11!!_6 @" oJ 㩳P`11nTr:Cl}oABZf /e#*I~툈st\UM4J : !$$a]it挜g0Lm(ukavEJU(W1}tmaJC 82 5w{oyjn`jx{JViK'3!/!(&"! e.siEY"F 2&,g8 Isgy]m=H#1'j$7C#%FO9&>'2$-3&%*!$0#"[ tT _4)~ؓcv?_N ;33Zb`'EpZmusm7C!A%% *!#riUd݁Oa.ME>&mjQeXjucc2>" #b:(YyLx2[D:6-"z0e'lMk|or9E&.#"$ 0q U yƁvZ|5SA7("nQfaCnx:F mlhPr.^D704=;3%e'b$zjMJO#+bS1(ߡڗmԅRq6YK =+11&vk[R}~lv@V'D#! _lghPn.[F6-**w|hlpjYV*! [ i8=mRv6]I :.& &"dVTr듇btgR \&u hiClYz9aE*3%", ,?/*+ ~z͕s܌U{4f? (!**&80##43PPY}{v^k;G)1&0.%E!$ I  #ir,t7Moonkk\\OWC^--@< g^#[J69kdz吠椴L[ +T76Uр֓yXXP8' % , yU ާ>Xw\i7p#LSbggrS-- ($ 6{)o|zpo}xgu}iR]N[+6;3#+$!|/^ xfkӃTg1U4*(rYRXjAirxW-:4H$4'& ;$#)G,%5%%$!9"/P3!$%%'#F'K#[ G_<)ΓxZv5W=,7.!]UY'puaOF9#lәvX7V6 '+5)&14)){_If`A{jsJZ3;*#$D )&%:) < %Z{ 0[rrs|mmexnZPV9A8`L- 0w!Lh?9rg:-|aw=eKiΊw R ([3:`#Ap}yy~w>?"G),m\譸iLD_l(\Tnn|?N>FyXCcpkn}hA;"45Pgb|wzkclUd[S~G39 .K!{ g$ p`AfC8'|e^Vrv{Zj:H -$#9j['%#"8!1.%*%5%%7 $"!5)1hY b@2nLi(O 96'%!at`lHT>9!$# ;n o ei`pGg&I .$!$yShrEJ$2 3Z fd[zFb(L =5$tfBowpvfdmQ`,&68&"6 %]ixXu]:_<58.$gfOei<;wn{gNy+XA8&!2<+|gWkc}Rl aN X+xjԃNj1UHE;)"o_Izjꕕ`mAL)$U! cpՁgցNm+R?1$*40tisV~g_{R^+$ w S \~q͜ȐjρNa1I>7/j bGug[c1OI!rU`HjփUt4Q@@2#hgMm7IV,ZscxZv9bF 9A+j0%**s(!SE߅{vjAI"06;/:!$$Z$ ,q { #{ #{ #xummdVcFF5NNN,, nZmEU߃٧(YO[f}=eNS:_9|BPX'0\ (eu~eqJJ)@H*0 3crNl砮<NRD92A)H,>w@Fl[z^[AA!&4VPr{nvlfv]hlf;F1O/&-%5 j ioiQp.]@!rUftD|vqDMMH('%$% "$D'!,""$/5'$$:&#!%0-$ "*p X[nKxÈ^x:b>.)(&eWL[kwX*>F$# )xheEfzRw3]B)"' U[PpZ5B",~m\@aQw3dH*zt!WsdJt|asDZ&D$0'$FB&'>&" v !QvjLi(E 7;4$aHpyKY/GsifEo\};^J=0221#z!pJz{^b!1 .bM rxW顈sӉXuYy@k F1/2(|_T|hngoB3"lVcMo\w;ZJ4/*)7!n}^8 {{~V`($ bT r`P×֚sXm9cU <r$!aZPviV`-  f%#ñ`wCR DE=.qkcif?F U tey\:hN C,)2'*'.rYfeC{iwHQ;<%#,#K0&K~ w%l{ "d'~vw{sldUT[[22"9) (8vM}wh@v&4|.`Pp1_D's\r{nyKT*U!Qg韓mQ]U4: ) % g\}b럯uO-|a9'f 1o7?wEZ\\GQQ( *)<+k&qxmujarS\H_KB1/"-&-& { a e>/o^x>n@l).hNLza7E".+%&$$ $#&'% Gg(L+%*"$($6%$2 1#%2's[ tgҀIr%D 062,axQ=cfKW1>&0+))P)# fjӃ\@nX6!$a0Q(rzhpBb% `g[|@b? ${HMzmxRs2?1H:!$$8   i _tKqЇ[n9ZK82#lWgY`h.oqπg{L`)P >/54%,B#E.Y0J(튍yg+ o T W"ݞ{ᓑ{#TA8=1 rfLyfyS^Z;| T"mg߃Ll)M 45**0|"#cK(A$w[`!/Z@*gT Z& ƌם{`{@n#X6{&!TiiG{ewGR q /kZgӀP^.GB?&q svJrb@ }J ygz^4)*(6z\K|v[gJJ=.&"* $#$z C{ &{ "{ &yw|kkg`QQAE/YE v  2o Sx^}>>J%]r_w!qjZqn~GZOY8?k $S:T䓎w^~GA*3&,m\-7psR}S&ye|NI 2s$7n6*TgHyU["vt|szmfp\oNY=HRL#=* '!# ` mngNz+M}$.1n> - dNfk[O*#/%,$$ &H%$:!+ +"9$#$=$$# :E*+5 $n hR?hӀQ{0Q794'hUe3WbITN\)$ $#! q'j`dLp+_8p][pmsq}wY^%3#e i`dMl,N110lQ\tbx~]qLO7<$'&!E/'"X y aqf}Ir%[ 90/!hfsBhr\E8y beEoƂ[x:c?'./(-F%I0$iDU_B{]N4) }\ T r}^fFo([C0..!fA5 y膗zAO1# rgrJo[:Z0/%*0&*'"|PU\=dg'39d\N vaҞߖfFl(K92(e$WG~vyr7:(< 'LE,mՅ\p=UAC) (oOor[eOm Q tb|_=dL @50444)(8 l^`[@}wuN_,9 &$P$5*/ 7' " "{ %{ "u #z}r}j]]NnX=G$<"s hXq$}KaTpJV! )p"T jiKݟ|Ō_)*2lna||kh=_K3&#'O'$# =6!|0y _{ &{ 2zzw~ٌqhh[[KYG;*D0F("6)hJzz]]aIpɄ8CSo&qGx%A 74Bqu┊fMM+\$qteoIv**3*zl]\Z@uwMW1>+%#'%8;3  "!rYZ{ +{~yqgYYLp99),$7&5^KK{{爘wqPpZ.~FhD3K= 9 .d.6h05SH>_v~xclu@&9|hTYZ{BW=e5z(\$DdpCLAm==YW&<)`0 pgdlgjfoFQ5BMT%5&2=% Q ihGmYz8_N2)0#hZ&}mwMV8@1&'$*$$* #####LL$*!#.=&  kn;9a+N1*%n#@~5EtYU0=-2-&$"0%$!%kivOf}Rl1[M2/0!fhZrzXd,e s cfEn[r:^J.#wD-G*u`c5FH+#(?%416! p d}QazIm(\ F9,o`e=uAM S"reIt%U ;.2;>?=1%#mS{hՐikLK  o M`7)ȓn؉Nv,ZG2.3+{RiV}q+8/c%rȂe}Il%C 6759.&, "&Y;ye~oPI( oW[/(ΎnNt,V9*16}[YtXi_!m oمdHo%T 2' R2 ogoqh+cT _hF͙y؏[v8aS 2!4)+2$bH6 ߕy^iZL&bS',(&.$ ! #o!pz"\ V}}|{wpffnh^QM7':P G {cY {}cBv)JK[k=-{9*p 1m 5q;Cx:@[nT;/."hPa:~ci@L"q qerۉg|Ld5YE(.(eTq^nxV{8=#,#0$$'": s jE:buOh1\>.0$hYsqP[ bi}LmX6]@)(507>2-,~Q@vg䐕gvBN(+!b \ MܘmɂKm)U9-63'qY݀~wgX! g[kEmԅXy6SA;9>:61(&"W?5 odfpCM)$ \XmKp)P()6(!qVӊ|ux:fv dmGjUr4W;!)+!CMW6yeoBV$ r T mjP˗w׍Y6e> m*!"4'qV= E\4ܛpyan-8)-$K%#$#* $v b?{ "wwp|qW^PG79J(#& (  . b Yl҇--k;Dl쉚pIk7TLC J6o8,*D6PgpvvOO*&RfܴT1o@b5 8{4CWG79*,  uu|q|{xcj]fRuBM3I(&=)#>- ) nekJm{Wk5^O,*+nQCS/{kW[7=n"#U%P+'+-%## '#%.$$R'#%#"8-&"&+@K: &(+%$3_${H:GF?9'-$(&.%.<  hjhcKw)U ;2,"uXrsoxZ]0A n h}Tp\tHg(L-08,cDߏbjD\(<59>!!###*{ aa{Tl:b:!+(e@_]Xe09Fs*Z"rދd~Gb$O ?.117=<82'pOF|l穙jsGT :! |_XˆєhπFl$R @83&qUUb?|`j5B] d"0rdۀGe$V @39>@832$lcV9tg肈qtIR . v _XҔhӀFk$> +',/%VN`>yPg" \!nՆ`zCa Dv,3*fNw|wWf)2"+\ T wguVx3N30566?,) ; Eyl||wFM$1("$N ! ,f ~#z "{ %{ "|wwusyVVoFOV'')$ &$l cO$矰K|1IBj[O[wY_u~r2N H1g.\.4`(.TD(ILbNeEx.S[W>9C+yFh·T` < 0iXF3=((Q_9  s}~wku]eU]IS9E'25O(,!"  Q$pފbwE^"P 6.%hvght]hOZ!3&'#6$W>&$A&4$$$)!1& "%2Q16 C =# 0-'Ia(5[3@G=%!$O$#": kh\?iۄW7X40.+R`X}^5@0{ atjOt+N6&,-xIU_@xZdMK!;"'&>2 %z dZUu?k C)1"QM|_EZhEJ-.U j~WmÀXu5^G4699?;62,'!dNyj닙}Nm'6:$$o\ W"}b>jJ/#!c[vpnvB! _ f^mXw5fG04?4#.53#g{[8 qk焊nxMX)8# ^P‹}ْb>a;t'-"SJmf'5$wjWgԀPm.Y/$/-"fvjHwdnAL 3/ n DuisRi0NA6<:53.#aJAa5~txM]U@$1$#1-#+) # !s u!{ )woodhVWzU5;&&&   YGwײnʌ9cÇz6a‚厞.p = 2q2C8B7" + .hQ`)oN\x8lWOax,y.qHY 4p3B6.$0!#~0ov}utgv`iX\]HKEA4$+('+%"5! l"c^kڅTj1[G1!"#hUjAxisNZ/;)%$ )$Q(5$% ,%8(H16 ?!%$.3%!Vq$+58*'-(\2-;/H%M#, /*   cl`E_"B:4,c[!a&yirL}* k)hyNta?_A$,+]Bzmt|NVF .!& E" )"  ilATzAl%J 55'wrfp>`dEZ z c$%sڋe~Gk$M 52,1=<63+$!!hFonR߈uU1?' } _^0)ޕvX{4T3%0+ qdjBw|Xd42} R"seGs$V =8>7!)73-yo P( ucQv~S]0<- W ^3'͐vXz4R3-1(aQ\lBvwAKq\C3mօ\w=mF+*$|\OۊozR\2?(%&  l G vhoOp+P>@0$"vmPmg~akfO(9&="#7P#.'z +_!l {;-흎}w|w|qdUVGU;5&19D6  {jQ Wnvvvq>s(@87_yf}@XtKN!eM ,g *a0G;M 9}nzƔ+wKQpTZukmU OM_*B2?V&64  rzjvhzXcTQ;V,G'0)(!H'{ d'pՈ`zApV4u$ \Zyws|Zq1M!0(&C:!c*&#P=&&"=$"#$67$ *>1"55 -K)r*65' /.Y.M9LH 3&#, 2BOY-9 hg\gڂRg1XB5+|}gm_z]r5B| SułoɃTi0Q960*tSX樂wyQX/8*>g#"$qT:%RpCk*R=/*)#=q5ZrCL 5XihZo}Xo5ZC4.64..781))%gPfoR砖鍓|^h6W&!r\ ^N;mLn(H 0(loh qt\=@ il\oߊXy5aK:)4*)=:8%&uJ<dbI\p3B""\eL;mՅLi(F 9H=u^n'moS]!i nsf|Li*G 93%mSB[RtbjYO)%%  $iU̍lIl(YK5&)(r!sAS0yzKSRF8$"$""%'' 3n{ Q{ 5}xtddwEg55&&1oT !aB.$G&'-$$ .)84k,9!/-)*#)4:% .0&:4DDI;',"$>5%4(&+$ a%k\{>k@-,'(y>h5ynRS(k `]Ky͋gӀGo$T G, jnedgEU8sLa-:/-"&:+)|OgBi,U?4,#thxIU+8!+xb$uˈf׀Gm$[ F;;/$*8:46/'!pO/[.ߓt~QY! U mzYx_;\>($ nfTcmDQ#x b"ufyGj$R 0 0',2/;53,$!jS1P+ߑhBN 0 p\ fzUxَ_;[DKB eagXcc(15}hfBlYm9RG<.wxX:ykbb-<'2 e JˑgҀDk#F ;=6,(}"LgdyoeAU.3J-&^*.0%$h 2%{${ "xoowi^UGh55:') uSb#4nSo:G&YSqRq>fǍUZl-|8bK0G9MPQN^xTN+yelM\uu:V+ O / =5 r{rzeloR[HT0:)N';;798 ef?/oՇ^>i;$)}vwN퉆nv]gHT\[>N:F:W>A5<+I0761%*!0 .U-(2+6/A9CCH9GLZ.1&w#*5/00+1U46,I=+)%.#0 $p5##;. ihqdLq*P 6'$-"[pp~[e6L7l[ tpvڍ^}:WB4 sY]c'@f]FevIU;<;!@  3 lIh?i,UF2) q|t_HS@? !d j]pY|7cE04-*454/,) &(oPSwq|MY x Wu݇j߅Li(R 9-*'|viAakrY-  d lZpYm7T93+#+014?*'-#c7 Etꕧ{NX2 ar~jLu([ @.pkkZ<\f6BxKoۅdzHj%Q 7$ fPokv|Yq=J!02# y#PK}ōc}?_N ?%!3'rqXBL0nvT]1>,:&R(&*&  y ( 2| "{8.}xyodlhFF66+3  ;z\PٍzaQZz"M@my}A0^6DIk=ICf5RFh=)^axO`8^ux O=3 / "1Z.r{qzlwppXaObIK*5$Q(&(  goqhOv+H4<'!&\zY}pyirs]v`w`gZgTo\\JT@VgQBN@LGOBXFRImITEPBRNQ1( #1*h 4<7*8!#%3%-*!3&"$($8$ (" % nfbOjX{7c>'0$P\e?|kjfU' o ^.%Ғp݊Si.LF){"#cFhMX4A!3')K"%'OQ9a)XE&%+&}N]GQ6C dT$vg߄Jm&P 440%0*.90('+0'~VGvt`_E& icCePr1YB1*# Es4]hNX+< x a$&vÇgtJ^&F 0%'(3@+#9319-S>=vkU\d*l`?eނPw1\=1$E[-thrL" ,gh]CyɊU4U;51$vjUf=s}爦KW)2&(#!=^Z-'y؏]9jK *!42}K`Ge~ajD`%2'4$$%0h.$$  Kw { +s)$~xpp|kYLN7=60]$ #N+p fOo;Hp7mk瀑xlsOCfʂ0^.~%[9TNAcy$qXDCc*@O%*/K/"4s|lyem`j\_EPGg':-"$" s g\Ao\$$E"%6% $ #Nݍ{y|ffX[^I88-*+l % , u$sFY tT?uo⏝]3auIkax冗Xs.~)wRo֮Fh8Yuvb{c|Rq&`-|! $ 5,ps|owlgoV_MX8?0@$A7Z 1({ e qugLq)C 5)f"'TEW5Eb8E`:rYlXhWsyu䄊|sxs|lvcd^Cx$&~*#0& *8--;!!$.@S7'$&! $*$ #' Eo dhR{1Rs&)0,gVr^FfoDP$! h Xyz{c@jI3)( cR?~a}nmU_8~ %+APG 0/9.'$EQ>S,5*(M b(t҈jLs(U ;(#'2: @DEB9+++$dLJ@tmSѕjp(6iz6-M%QC47&xSXKU2< j `3uDŽjׄLw(Y D1#/;6 /=G?76;3>0g'Z SvoVcm%/i`.-O%Q;15&!aR]DZ&3u_ csQgڂPw.Y./;*#lvdGwfeTm&-&"&u C mnOpOn,Z9':)$-!Grnx}inIN&4=D!&$** ! y0 ({ "ڄy|gjZZVQG3,T0 Z  ETh-8||jjW|l55w(-wCki珟^x[-|4~Y&aJqYxjထ!O()b7)  Rdqrwiq{jL_JPUC&5#+()3 q gS;nهZt9Q="d$1s`c[]MMI1 / GLEL3EZ4voQhW`RqjaOvbH0p-ZQ$."u%%. @>4 5#b])(RF$ $)e#7##/I##%" a. l^~@_9*$lMz~yVazE!{k ]4*x\9dSC-$ ^QLfjL斞ﯜ{mlWM$$7: <:658##FL9aT?05?#t iiqKr\:kO4)!):>E"L(W%OB 0),"!`< 3 Ir^^i)7O" :B 305"u~MYF`5BU  a`hGr݋\:cN68C977B"Y(V%GD E52$&s2.[:M~q\^i*8B 2= 9=7%evX?I+9 { f>.m\z=eC5?/ UTnzTi082%/J !+r H wsjGi%J 67&2'QES5r{ja?7-@$## @$( 'w{ +zs}hhpMo>>.."" "0F" hKO|`tԖ~{``QQjDDr:Zo)?+H8s BILA .Q\$B "DV(%( #$##N%!$E2(  [lrfނNo+N(&)^@fNz|czLk* 3 +`ibGuW4fP0+4ieOS%yj扁YklUtl'9/3</-*z#=OTA+J*J$0 w `tiLx(Y =.(1*up-%D7V=[7Z'O?4.7*w_QYYUe8Z;1*.0(#%vxFRHM8AN( j#`tևiLs(U <AD779w8%R7Y=Y7Z'[I81((r\WBUUb7Z;1%"'153%yBL;G@=Oj nufLi*O -43zB Rr]jdP&7(# E~4l Wy|c?eJ 7{(/KGdcmAL06%!$l#  &! $냃㖙jjwfSxI@22%S %kA P cwznnpeee^lbώmQQPPbwۦjӗ9@" <#/*pltjs݆k[t\V@L x X rbsTp1X8-<%_ziK<!=u[xmfnuT7(85+11.3(C|)+58M3F^=\1"/*p k gyTq\:bK6*,%#/s.:TPhUtJt4aR F83*w~!z##%)17& #u{>I?KR=(&# hhkJq\:aGA4).9=U.UpJp4_Q 8-1"imO`}|%**+*'!%9BRG.> khV,"~!n d'weQ[/:2%<$2! 2e Z1%xڏ[7dL*06tZd!d&kRY/<+"'A!N $ $XꁒmaaSgbD@6?U0C+%!M8&* j SToHW넄||wtrjeee_aX̌^ ( -nmviaidgMXAM1;PA!2R% eqăcFh#> 2 *3%%)99261.21(%zS!*v$&&<(g)<+++v'k_!94!($-) 0<$$##%,/#%$$ $"h$nxd߁Ic'K 7*# $kpZ_hDM*#e Rxm͕rψSm2KAC)m$#ooWG_q^v*0.441f-"F#[).''4%-"})X+uhLp(W @62)/4m)6'\cgj؄\}Dp*_I;/"**&,,.4<=/&% $%.*5%T,)!" <u b t̅hLq(Y I7+&)+]%<5|ug؁j\{Dd*KB<)`# .#'47) '$!!0=f@;24%foyd|Hf%H (g&,|!hpcqz[i;G9O C'<qN eM<ۘrRy.Y:=A&#mgSirQ`bG,$&(*%#v % !'烃xxoodXrIK;T-6&"  2%/x ^^J Y {Mc|Ϥ懤Ҧ鲼oU|n6O$e  !"=4B jss|cm]fn_GV4@+8F.$! m zekUt3C:.+*#/8GI H D D 740y%%c''}%"-4)***)11u0 !! !$D$(#3;(>%$30#2#8&?0.. sbcCkWw6`@.1&&z!a&{mzl^A?# 'lKt֋Vm6UL 7"*/*)&z!$o+.,*|؆)R52*2'4$E+>$F'L& m hwLp\:dK875*&2+2pdzю{ܑmUr<^%M@-$-5558:666,,/U,".-;!.&'1"& 1m hhHpֈ\t:cRB=2(%-3pcz{m݇Us%3!58H  J q gaDjUx4U8!>C,vgUl -y$+嬇rrq\\YPAAZ3'a!0-6 QN/1%)h_J W@HSC X[`jw( 0-"R4QcolrlZeJRGc5?+7.?*Q+ | g'!pauCQ E =/!)-. 3<"O,W1[1L.P(M#=<=;9+ /5'0))90'/(d=DPCz7D'=,&'!$$D$0I2$+%"'##)"$L$W1 foaEr"F 1>)"_tb[g@G'& _!Xݞy؏]s=g"K0/7:96,#-9:2*-5+Oi""!'%$'/"+ ~PshLu([ H=:$%fw2R'7wvMݗ|ؑhҁRs=e*TBAE=:?: 6:@ C/)A#5%.1&<'G3u(~btɄhyLl([ E<82~`7U#wO욈|hRw=e*QN6%6,-< ?L; (1&4 )a+!"-x f!#nȂ`Cj I MH7etmj_afU'1+( #$9$( o T |z|בb@n RCB=$Mo ;I7d,D @6"&!$1n %j|xzzvbbUVGG::.97"$WN! @B +"_ifs&w3p A) T  ( aYfW``RZ]U-:&0'%$ W lajvRg/YE)"3), >A1RFlRnYgYkUqQsLdF\Ah<\4D+N!N3 5/+9:*(-%yhQkrcnQ[9C,"$"#$h2$M#J$(##/$$#! " X bZjсSz1R9?( kBh5l{NY)4<):$hRN~sМדgJf0LM A452+&*-0D HG >, ##4R$;  +$#!.hhuPp\:jQ@;,%xIG ;m& |~zjXHs;h2Z,P)P(S)G+M.P)LS:<&*#;''!% ( m hhHpʄ\:hK<;6t!uM+ c%}zjXzHj;W2N,R)C(A)T+^.Y)H;7F(  $3/$#'n k}Sg|Pe/OE;;#}|v`:LU?I,9J# !+*4 hZ.2čzDr0b%P=* #2'B3#1( 7$'*$) =i(yqqgot\rPlC@K++&!. C 4( ;3V/M %2&  "11YbP^LqEO1F.;01%$$ "= /x f?/o^@h<)5>)#<E1VPwgՀsxvӋsoՆlxiӁe׀aoYtMj=L+MA *96*(--`FknyLz-82,/3#$9'/%2!$"(kE&($#!. &8} f#n^~@_LD,")z\ogh?["/#*:sZOvv]릆s\}En1Y"NJ>?F<?72A"MSF2{Y#!I$/9#!{ btiLp)S B=5+!xfdKCM #f dM6}qf]{VoRlOlNiLqFf:S*PB5a$" !"$")*&!s bs~iLx)S <81"|~fjGGRb dF7yई}qދf|]wVyRnOkNqLwFd:U*Z9A""-)#%# &z gB2p؈cvIa.ZUL)$'v[.NH6A&4V+3%6%=!2*~ \!eC9өjS}Ba1JL)-0#> ,8"$ 4'$' ۫|vummccX\MJB66hS##E38 B.+ -.  <!=D!P"R\NZQduRH&D'& )$$$# 9R$%# #2%3  V hogԃOm,Y9.HCzZU_:zhpLa-H#:#"%( X%T jVA۞p_OwCk;^7Z4_4d4d6V7Q8T5W,\HoR%1.#:>$3KB&$$9 l!btLr]y;aM=2/%z]pBan T YE6{sנ柂{uplgakY:*!#( I$J'" cfXCrދ];\A70*|fAebfWn LeC6t՟埂ߘ{ؐuplgaWtLbdx9 "8#!@## &"Vtπx׎j}UzCl9d'K ('kn$'-%V'9'I$T%# 8 &}R {i㢀jSoESknB) ":J/,$J<$!#$ ! .%&rrzjf`aocMf[@Fn؇\tloTywtptpkslkhiIlZ:&((!++*'RO;A t hiIܢǐq^{RjC[.DMd'>!!&-,r-%Q3><$$'AH$ "r HŽq߄dX/  3%$T'+"&$$ *&衡wpދhaaZ_QXIB<<7W27R@N,I*((''&&&:&0&&^:4X2&&&)b&&'20'(`))*-****5)%1 Cj\<{BL>K;K?P>3"..$%U')*& V qҀg}L^)K H)97#)}~L-?" y ,} v n dV TXpjVѢܤu֋Y~:^< ,*%!?7r@dYz_i>JF4$+#J3&W$9&)"%,)%#. 00 gofLh)E =-*"mjf^CzhrIU+5', <3Y OT \& vcݗ顄~yvsoߊj~b[mjp>t @""#   ,AA  ~ Z htNta?kF)#"^GqgxFU` jj aaadhp }  @*+##E'$P) ''* k hbGtیa?j@'/2y^Gi|EN5   t fd] ad M b }  !"!9##!!B##$4 b ǘmՅdWfP7i% 0#<%!"$%A$!#*-$4%"7! li*drr 0($G%N## #0%%&vwpj~cf]VQdPQIrDYAAM?F><^0#c% ' $"$ #&."<-/ [O99.#  J umRq.K2( mdM\`T쑖txTP/( 5 :  " |(Sj S2: #'*BO"-#"{_u~mRz.X/*:*!P!DoyYV'  *  o    '!K$##8##< * +} j@1fE=_L1d/$} o 6"#,$"%8$$9&TB +&O-   G%*#.%#,. $'4/%#zz|vyqktoac\XXWZSRPP^cdMStLLxTVKKLKKciLK|JcJLIG_IMVYD==MaD@,,%5Mn6C:E:E9[2r0HA)#-'9&"(!O8-)rf q˂euIg&M -/50iOlWnS]D6-K"&= x \T glOݞxYq5NG0$0$wbjagqV[2N626C$ '$42:*.%*#6& ($0%+$! $f*ap΂dIv%K |"*' &NfUxe]X$f'+ " !- (} t%n mm n rw  (E## )"*D3#$i+#$0 1ma^Av܎dCf K?4+( 1d8m`aj=m %/""$4*$)!T#48%$+#$"m [Q7J:/(("D4A4@/94BV@;O'5- >?,& "#  n ]iLm̈́Xt6W;;74uI1^+|irQ`08*#$![#  gT k\NpՈOf+P. *%YvbAfp`^7D% %" # '$!!8%>5$")A&$" o ehFlW5i5,'#+_Cx|mtWm6D.-&%X# $21/ %   #$C,"1%$(Y)##B!$99%!$-2,`ojpԊV|2Y<($%"oPt{\vM@%$  -(#T5;&#1QG$#"$4'$,&#: >r` rmpVt2T<7-(N=덃`NP,A&#"#"(2<#$$&: =+  6;g !"!A #  "++*6A4&$:1=8*"&)(/(!LE](/#&&%8"4$';,aD#1F",##!<#&B%%ↆz|w{soomjkmffzedg}ccckqccbbv``boekVXQStFFe@99d22?5S>s5H/02;)5+)&+4& 5#";"2gYq։c|Fl#L B:/tU^ofsZc=H%a,< %$;W,! / a N gkVzؐ`p*=($:%""% "#4 !T4#-$>!$%Q'"  c#.cD1wg{Fb#E 5-('eNwiQmwNY<=%'1$#9'F&#'##U"D>%"!$$""$$%#$<!+, E%!*"Fb7-+`)56J.&3(/6)7*8'4)7(9=7'0a9(>&4#/86'9/6)7:F(1-9.:B=:3"0#%#"$}yyvvsqtymmqlkkklwj{pjjjihhugwcc`mocwVPiPODC4e.97;2?:I,F(5L1'1%%&$%$$"%(r/mk[k~Uy3aI=(drvC]5yjK[-k$0#$! '5*,10oMpje{F_#> 2/+'5\%YGOPJ(& *2$;&2! :%)"$%/8%OP6$# l h[lUp8]B(#HH X#悇pxT_4W%%! $N%%$2!R=&5 %/F) &(*(';%,''0|6$q&$2$1#1*\_.29!)1!#)$~ bplrZx7`OA65*jO|yjfBL%3& H%)"$ #@*%/6%MM(%!%)C/% +$$ ,blir։Zw7V72*#o[}}ymb>H#03)& # &!g9%$%)'&$#!#%0,&*-!.&4 -Q: !/!0"/.$2&3'69A.;9?IC7[Ua9DFLOD:d>K=J>EBK=MKF=4A2h2>2>&6J0!FF(.#-)- +% [$"p̅aCk TD4&t'g!vx|Yz9C 1?'.$#4%" ++lfS9\~Ei'? )2$!"ROX?F5Q"0L($$$<)&&&%&2$%6C'#C1{ c'qՈavCs!Z*'/kejq`{`jiN%2'$3$#7-#!8965]'522,-"-$\&4)6X93<9C0:.{aD5A7D7E9P@B3@-8C2%1$2 .9&#'#L(Q#R'xiJp&Y AJB$vS]bCꕈ}za_4A&+C<D&%?h&*&!"&6P7& &-,#4$! T _.xiJi&F =.#nWcbDpxS^(S,$ ( ( $&8$%%%T(!);* +(L(5,9-V=<3@6@=BG:5H9=6CaL7D?D\F:C>HOK@P?uGSITKXSTP\`tX]g}i]KTXZOZOZ[TO[MWVqOXWfR[JkEPEQ>O?a15%3 ,Q!/Z6C7C?A2B43K2/$%$+/Y?]FQDyIUpRLVDMEUOYEM2<3@.981#1*(%G:  S m^s\:hLNG%hRPtn}dpLm'A/*_<%$7&,$B'+$%,'*&#)'@')'C'!%&# z em^s\w:dL:7.s\]vwxmnFQW2TG%V#$#=" %Z.*- *<3)9,8=A8E^KFLUepTQRI]HRT[GUGTBKIiGRBJWVQXUYW[R]btUnZfZm_l]r\d[yajs`pfi]m]gth`[enpmdeaOVJV@UmK2WE5"0#(8`\FCU3ACX-:<1)G&(%0=EXY^eoW`SIg1OpF\.R:v*$~ Qxyr{Xm9E B1$@$$&$.U$  &6U)Ly. n=9u~poS@K5B F:!#*+(''*)(;F.D*-(E';%?L"jP6*pՈ`}A];6-Q0A $ipgt]fpM#2$DE'%('*$30$7//*JYD3KBMQXN_b[cUoXcpbXcYdxeiiXcgcY`WyW^Yh[e[v_n`zckemk{cigzntmukk{j|itnvlmkqgpceb^facVHPDN@L6E8A(<7A .%@"#F'Q1)$(&,2/*#1!0 .K,):'B #$ 1 gkojQh.A6+V3E}SAW0yjtJU4C.*E,' &H"4-"A/<(6,WIE>JNSU~S^[[Y^^h`{crdjagxqfpntio^V_LViR3<6U(5!+(%#' _biHt_=bO<47-}\sli}JU,:&&-'$"+,(4" .%&5/5LD4"0-+%' &$'' h dyMt_=mT=51%gRj^iHS,9D)%" $#$68(?1%BMb4?9EDNjWk]\bXx_cbpdnclhpqoaiinjpclulttbnemeo}tirlwyyv|nutzzryy蕄}wnwo{hnelisdm\dj^_M]KQ8U=WJUAF9J4G0:64+)%-E!$+U4U`2RS3t[|l~ws|NY'h1JD88<($%p\覆{fneQ4X+9N46/-1A ,!"!TO/D:,2&#&_6^8A/<'$-"9&W/*.)$1!,*8$027&3T41M(&!(( b eH1p^v>NAD1eVW}x~hFn".*""$$'!%$' (3+1130=KGDPK^S_녌[daja{isov{oxyst|xsxhusyi_XT>R,=(6V2,6'  | _ wދmRv.\F450!iY'憄w]g,&!! b g\@p׈^y=mM=2 cPxws|S[FG'%9F0%$DV(G&$#6h,$2F83@?GMY|d^tdnksjr||xltakS^CNH@*8!/;+% _uypوWw3^7 73"fT߉{bt&1$#3 &+o8&5J:+6\IC`HI^M@H0V4?-;".//&#"  Tq{pWy3[5#22 JI߀~䢃`ifs&3'S$$>1%X!%&/$08BZRNVg_hisqt}xyy|u}{s|qw{v|?yGJ>KgK@b(0'7A4?)'-k[)9-'/%%P#3754)''smb_Ftgۑ}u}dpTHH x!)$1))?)&1"n*"/.264'$2%$(.*3*70A4C=YDYGWE]>J^d??.D(6&>'+"= X rxjփOz+_H?6.iOvsKwn^tP7:$ *8&#,%$5<*2yylz\fQ@L/9*5C/'-7"( 1gbC0yُhHn$L :3)#{dUa$݌t|itybEMaJ56!/s$,H% andsߌ[y8aK=5/&pLumgqEP'4&5-$#$+$)( *(42/22WYQwUeWZNVEUKGIG,L$'"#*Cv P ois[w8S;@3$cGGs~foGR)7%D&h* %-9$"$CNB@fP;FE]1>)+#/  kq9Fd?n,Q>B1 .)#843=)(=)'60)nandF/ EPWwu*1=)i!34'b3$%$+)3$#0$$*&2}D8E[d]kdbQ\yS;E7K05"0(&(< b swj݅Os+Q1(' JeQtxDPbMc-M-1 $$'$C3~xnx]cOZDQ=D3i *'<"" sU6zЍkՃMn)U<46."Z1S/vYd6B!1!$!V#2$2-LbecjYaYcGPHSGL4A&4'%$?$-\ R4zkMq)PC9"r o1W+Yd4?))<9-5&2F;D$%!$$1QRDP?P>`9YN@%`59 &lfCbu_Pn9Z(R@>D =(*#(=42<)(;84 'S; f!r*?=?+j#45#!*-$$!($&O-,5T@4@kuirdq\fVxMVBL3C&4 ,=.$[ gUK9rۊ^=fB1,,&N!N և|wvTjG@"C'$ "@(%$$:tcj]qNY=HB8B1+(/!e #TlGv`>cC541(nQkT{clN^%2\+4%"$$#$2._9gqupwi\dQbIUBK,9'1!$%  *XckHv`>gL8')#yKxcPzfpBR'D## &%0 )#^aGQNNKY;G3L'E+8  #eP:v||ؒtdUjLaAg7h,_"Q92 >:8A>(!4<<'%.!kn(1-"t.8*70 y! ,+$bH?$-.&%;)X)8K6T0#b.IoKrowr\ePYMS;O/:!/"+( P qӃjOr+Z;/9#FOtVnwR[6jG71&(%$W)#%%#- 2~s{oyoWjGS7E)O#.$Y2L=  ` WyoRr.M456*PMЏyP[5@,T2$$R%$#grqmvjshn\qbBN9EL?+$($"" y #^x֋oRp.ZF80~~kL抂kxP\1>78 )7r #+ $ ,SDLJ\QUEvMG6T?;,2!oۗzs~kӃcZP{Fc<\2e*L"FSO6 $+8A**)(2160!)6/ >96? +$z!11"!$8)"!%9&= 2"$1-G5@xpy`rsi]UCO/;&4H.'#"  o a`Ar^=kL04%`n*2u3s~O['8!/(.&4$ mQqxjPr-XD/*""6(8[XFR7DE+< &83G%$$!~{wqclgkGP8X+>(I*$.!r M purXw4\C164'~ c!Q[D1?G%5&'$"$!.(rxt|mvgoSmIUXGd;)//"&#) z [ sorÄXq4aF*/*|uo$enBM,7D- "%$ %9 "!bVcriXbPWMWDN?V$0$+B*! 9 r T QO H^VBi\~y뢈ܛؗŎy؏tnhb\~WrRtLiFUA`=m:Z7W4f4U3P3[4[5b7Z:S<^;[7O.J=G7!4V%5''*$1'#K)+}v}kr`jS_CW.=FP-&O  n gR?vg~Ke0_ K9&'0H:1C(432*!$ ! %!# !ztw}l]_MJ1<'8+&/3I ZQ6zjԃMl-YIE>,!!y"953@&2i# $#U*+3}w~umsakPZ@^,9&4,)U*5 bb>0zՏjvMj-P2?3(! v!3@+F%0S(($$#$ @.$ $[j^h_iXnT_KW17L0%0*!4 ". z ec[ K P^K5nqSua|xܜ͖|ؒy؏tpk؄}`z^y[[vYiYmXmXqVkUdQpJo@`kZ1 55#&6(/2-%I/%$2&  CCxts\fQQ&4**$ " L ghGڝԕqZFl9Jmk. ;%,'*%$$&(% %"}u~p{dU`DNX?%/ 0F!%G u Q%瘂qZ~Fo6e%Omj.'5!0-H$=%B&#"O $%vzer`dGQ6DU;:)5+ ,d P昂qZzFl6W%?hk/1#'$!%K$!"#<" mszpjsajXaSS9E,9%2!R)8&CW& M .#     j yp R _Y X N R R V:.a:0faDi~PepLhrWhgJgUEe`Fi_G_4+b!d'-4!#R$5)$X=%%A '#$"ovgo{Q\?JmA&3$*% Q |y~gۂY}D "$m+ $e"$$x爕zyiR^HF1<$5$)@; gmqQ墂lT~VTk"/% D#*&$!.%#$ $&#~kt`jj_?L3@P72,!+( My g mpQ壟וlTxVI%$# $ ,$/$ &$xO~z~yqzjuZdKV@KWC/:$1<0!(?$ &$N* #5   " sc S rml m"mgQ o t%z _ '"!C,MO+$5"&/-+ $"?>wxqzhs]dJZ' 0 &|u|llW`SP@P9L2<,9;G$2@.+Q-!(#-%+%"@!)1!/ :#   '    ' 6# d0%!&)/- ."0!/B//0#vodnU_GR8E*8,'",(/)# ~#  !!(%& :H$$$-b%(|yzzguU_H[9J,9#0W/%'  t r (~ ) @+""3,5'$##U  ",~uqrVHSBX,9">"+1+ tr~4#0 "7&.D$%) '(! 2た|s|el\eVhP[BGHi;F8E2C)469%13-!/,+6'""$!-235!!5/,/ , !!0.)F**-#F!,&4n31)?&D&xks^j\`EQMx)7!/*W'O13020%!7@*)/%,#c-4 N偅xpyemT]FR4=)W**/&"" .%(>K ( $"9*/+6' %'*-"KC' #- #撍ꂌwpir]diW{`VKtSUB[ANOK7C-H$1&-(B/$/%Q&M'H(*p .-$)&*+"#3&yxnS_GQ7ZI2#1%' 5- M&O(:)()*.=$([*L %Cxz|clU_DZ7D+9#7%/( '$!$#$ZU),;$?'+ ## ㍅wrlygpcu`j[ebcU`R^SYL_HTDP=H=N6DKM2?J9-84A4A8A6g@:8Q7D7K;A1>*D#0 2/!%}yr{cnkdLW78-5.:+Y&,P5511>1!6G4%2%-&2'u&187D5$2('862 훁qzdsVaЀQ7=/8.5;Q0!.*W.!/*+-'B-!/$($M'2&0O1C'=!) $؄zqzdvTsYR9E0;l@42b40WDUC&"))*,, .5i)WVP;K9PQBC8E7C2I9E8E:E=HG:)1@&$$ ꇍ}pwhpZ_R]FP?Z8E3F1A3;-:'0-[19A=/<078>1?0?1>$.&3,#Iy|ir\hf]GS=JP@BA06B0+%=$2&%'VQ'[핏zv~tpyvymursmqfpct`j]edh`eYcX]YffWaT\hvWbYaWa_bXbXc]cWhWceSvW_TaS^ZY`[KWZSeEC0D)7$2yldl_nvfUxOWX]UUTZJZFo[VJUH}HSGSD|AM5?/;I=&+$H*腌xox~}^eV_O_LpRPCOH`i]=H@v@>oAM@SUL8B;F2<-9"V* ExoxaiVcSdQXdWEQdQASBN?XHCM@LGaAMLQS-G톌wjqtbvdhbc_g[eXaWbccWnR[p`QiKhISbu7D,1$4% !∛v{v}ludm_e[hYaU`P[R_PmPZS\OZenPYSWKTOPTF1?'5.9"(هut}ևpdm_ZbYcS`S^P\R^Q[MWS[GNNn^WOLEV9FEG'9/>y重~yrzsqxr{pyxzo|ktox֢voxnw}tvmo}ytnzkszxf~uuirhkjnYjgU`OZڈTB_MHցu~qzxjueoctjp`r_h`jmjYaYgPYNYDU;P3A-8~{pwpcjooak^fW^Ze^gYcYs|dx^IRJT^L5F.9%3V%|מrlxwaaiblff`j^iahgZgbj`^Lb@S?L3A0Z$T!Ea풑꓉큈퉈{z⣁ێ{vux|u~uur|t|yxuts}oxqvhqom_gXaR]\艏{~zw{r~pznvkswirencm[VgNVEP>N:G߃}}}ovqzltdlzisr{gleoirfiWeMRKWCSEO*5ܟ荱덏xswqnyiz|jrirxncn`hZeZcR]KuRMq1`P嚜鄊y|{zz|x|v}yzxxv~vuzl}en^h^h쑘폕}z~}wysyl|sgqˈfV^itLS펒克}戆v|s|otxpymjagenXVGPGSOV~wqynuoxmwjxgptn[eWpLVDJ;s܊~x錓xq~wj}hpnꘘzw|xutqkkudm`nzfOX쀆|yxzwszxk~mhigR^e}~zzxs{wxhww}v~mtwxms?blobby-1.0/AUTHORS000644 001750 001750 00000000721 12313310247 016457 0ustar00danielknobedanielknobe000000 000000 ------------ Programming: ------------ Jonathan Sieber (Mail: jonathan_sieber@yahoo.de) Daniel Knobe (Mail: daniel-knobe@web.de) Sven Rech (Mail: svenrech@gmx.de) Erik Schultheis (Mail: erik-schultheis@freenet.de) --------- Graphics: --------- Silvio Mummert (Mail: mummertathome@t-online.de) New beach image: Richard Bertrand (Mail: ricbertrand@hotmail.com) --------------- Special Thanks: --------------- Daniel Skoraszewsky (Mail: skoraszewsky@t-online.de) blobby-1.0/data/gfx/ball01.bmp000644 001750 001750 00000012066 12313310254 020662 0ustar00danielknobedanielknobe000000 000000 BM66(@@ xw{fehcbe |{}lkmdbeb_b\Z\vuvqpqifhgefpnnljjgeezyytssmlldcc[ZZyxwxwvhgfeec``^rrpggeuutbba\\[ vxu ^`^z|zoqojkjefertsehg z||eggGHHwxxopp\]]suvkmoz{}[[]ssunnokkleef}}}|||{{{xxxtttrrrnnniiihhhfffeeedddccc```___]]]YYYWWWTTTPPP222$$$ `+FE--[E-FEF%8EEr8@a**z$+8F$oy67D+*o$%-+*V67D$yV***]+&{FD?+%)y+Ew{Ep)+))7Da+%&&E--v S)Dv\)7`$$`w-ppRuݛ6*o]------Slޛ+D,F-EE-!!݂A:WS**D7D*`FFEE  444__ Rlݛ))y?$-F[Euف3333944ݛo*+-,ݛ9933_:ڂݛ)V`E--EuSl:393'!)*-88_APјӁ4ڂ+E8EE43433 4јڂlޛEEE3443ҙԚڂޛ+zEE,_4_43ԙ3ә4ڂܛ*D7+,EF-FE^^^3443ԙ3_ۛ)p`E EPP344՚4444zaFEE͗qU3444Aᛛ)+-E2h34ppSS)y]a---Eh2ʗP4Aقp܂ޛ\*aE--Η3ق!Sv%`F^ƖRڂޛ)*zzExmP4'SڂS*z?x2ihiq݂ڂ**DD?+&(2'oDV77+>mʎfffÖ3'SyDV)6*$` =OeeeeeĖɗPәӁ_\vD]{{`¾OfPP94ASy?&>EXO1OfffP^4lS)]ꍎOOfOffǗkׂ'p*%z6ᾔ0N00Ogfffh3قuo+//////0efTÀf–jPњ4 ؂py)0dd/ƖOfP3؂p)00dd/Ofeefȗ94BCdd/0gff˗P3SMdMcc~~ccddN1Xi: ~~M~~~~c0001ehUUjW:bb~/ccc}bbbbb~~c00gTh˘4LL~cb~~bLLbbbbb~~0d/0ϙ_bMLbb}bLLbbb}~// ~LJK}LLbddd01TjkbbJ}bKbccc0bLLLL~Mbbbb~/00UhbIIII|bbLLbKLLbb~d/d0TIIJcLLbbCd/0f.MbLLLL/JIcbb~~~cdIGb~ccJG.LKJM~cMNIbMHI.LbbMCNGIbcBIJKIILGLbIIIMJ.blobby-1.0/doc/000755 001750 001750 00000000000 12313310254 016152 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/lua/lgc.h000644 001750 001750 00000012434 12313310253 017676 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lgc.h,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ #ifndef lgc_h #define lgc_h #include "lobject.h" #include "lstate.h" /* ** Collectable objects may have one of three colors: white, which ** means the object is not marked; gray, which means the ** object is marked, but its references may be not marked; and ** black, which means that the object and all its references are marked. ** The main invariant of the garbage collector, while marking objects, ** is that a black object can never point to a white one. Moreover, ** any gray object must be in a "gray list" (gray, grayagain, weak, ** allweak, ephemeron) so that it can be visited again before finishing ** the collection cycle. These lists have no meaning when the invariant ** is not being enforced (e.g., sweep phase). */ /* how much to allocate before next GC step */ #if !defined(GCSTEPSIZE) /* ~100 small strings */ #define GCSTEPSIZE (cast_int(100 * sizeof(TString))) #endif /* ** Possible states of the Garbage Collector */ #define GCSpropagate 0 #define GCSatomic 1 #define GCSsweepstring 2 #define GCSsweepudata 3 #define GCSsweep 4 #define GCSpause 5 #define issweepphase(g) \ (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) #define isgenerational(g) ((g)->gckind == KGC_GEN) /* ** macros to tell when main invariant (white objects cannot point to black ** ones) must be kept. During a non-generational collection, the sweep ** phase may break the invariant, as objects turned white may point to ** still-black objects. The invariant is restored when sweep ends and ** all objects are white again. During a generational collection, the ** invariant must be kept all times. */ #define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) /* ** Outside the collector, the state in generational mode is kept in ** 'propagate', so 'keepinvariant' is always true. */ #define keepinvariantout(g) \ check_exp(g->gcstate == GCSpropagate || !isgenerational(g), \ g->gcstate <= GCSatomic) /* ** some useful bit tricks */ #define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) #define setbits(x,m) ((x) |= (m)) #define testbits(x,m) ((x) & (m)) #define bitmask(b) (1<<(b)) #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) #define l_setbit(x,b) setbits(x, bitmask(b)) #define resetbit(x,b) resetbits(x, bitmask(b)) #define testbit(x,b) testbits(x, bitmask(b)) /* Layout for bit use in `marked' field: */ #define WHITE0BIT 0 /* object is white (type 0) */ #define WHITE1BIT 1 /* object is white (type 1) */ #define BLACKBIT 2 /* object is black */ #define FINALIZEDBIT 3 /* object has been separated for finalization */ #define SEPARATED 4 /* object is in 'finobj' list or in 'tobefnz' */ #define FIXEDBIT 5 /* object is fixed (should not be collected) */ #define OLDBIT 6 /* object is old (only in generational mode) */ /* bit 7 is currently used by tests (luaL_checkmemory) */ #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) #define iswhite(x) testbits((x)->gch.marked, WHITEBITS) #define isblack(x) testbit((x)->gch.marked, BLACKBIT) #define isgray(x) /* neither white nor black */ \ (!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT))) #define isold(x) testbit((x)->gch.marked, OLDBIT) /* MOVE OLD rule: whenever an object is moved to the beginning of a GC list, its old bit must be cleared */ #define resetoldbit(o) resetbit((o)->gch.marked, OLDBIT) #define otherwhite(g) (g->currentwhite ^ WHITEBITS) #define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) #define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked) #define changewhite(x) ((x)->gch.marked ^= WHITEBITS) #define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) #define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) #define luaC_condGC(L,c) \ {if (G(L)->GCdebt > 0) {c;}; condchangemem(L);} #define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);) #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ luaC_barrier_(L,obj2gco(p),gcvalue(v)); } #define luaC_barrierback(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ luaC_barrierback_(L,p); } #define luaC_objbarrier(L,p,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ luaC_barrier_(L,obj2gco(p),obj2gco(o)); } #define luaC_objbarrierback(L,p,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); } #define luaC_barrierproto(L,p,c) \ { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); } LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); LUAI_FUNC void luaC_forcestep (lua_State *L); LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, int offset); LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv); LUAI_FUNC void luaC_changemode (lua_State *L, int mode); #endif blobby-1.0/src/lua/llimits.h000644 001750 001750 00000016551 12313310253 020612 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: llimits.h,v 1.103.1.1 2013/04/12 18:48:47 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ #ifndef llimits_h #define llimits_h #include #include #include "lua.h" typedef unsigned LUA_INT32 lu_int32; typedef LUAI_UMEM lu_mem; typedef LUAI_MEM l_mem; /* chars used as small naturals (so that `char' is reserved for characters) */ typedef unsigned char lu_byte; #define MAX_SIZET ((size_t)(~(size_t)0)-2) #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) #define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2)) #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ /* ** conversion of pointer to integer ** this is for hashing only; there is no problem if the integer ** cannot hold the whole pointer value */ #define IntPoint(p) ((unsigned int)(lu_mem)(p)) /* type to ensure maximum alignment */ #if !defined(LUAI_USER_ALIGNMENT_T) #define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } #endif typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; /* result of a `usual argument conversion' over lua_Number */ typedef LUAI_UACNUMBER l_uacNumber; /* internal assertions for in-house debugging */ #if defined(lua_assert) #define check_exp(c,e) (lua_assert(c), (e)) /* to avoid problems with conditions too long */ #define lua_longassert(c) { if (!(c)) lua_assert(0); } #else #define lua_assert(c) ((void)0) #define check_exp(c,e) (e) #define lua_longassert(c) ((void)0) #endif /* ** assertion for checking API calls */ #if !defined(luai_apicheck) #if defined(LUA_USE_APICHECK) #include #define luai_apicheck(L,e) assert(e) #else #define luai_apicheck(L,e) lua_assert(e) #endif #endif #define api_check(l,e,msg) luai_apicheck(l,(e) && msg) #if !defined(UNUSED) #define UNUSED(x) ((void)(x)) /* to avoid warnings */ #endif #define cast(t, exp) ((t)(exp)) #define cast_byte(i) cast(lu_byte, (i)) #define cast_num(i) cast(lua_Number, (i)) #define cast_int(i) cast(int, (i)) #define cast_uchar(i) cast(unsigned char, (i)) /* ** non-return type */ #if defined(__GNUC__) #define l_noret void __attribute__((noreturn)) #elif defined(_MSC_VER) #define l_noret void __declspec(noreturn) #else #define l_noret void #endif /* ** maximum depth for nested C calls and syntactical nested non-terminals ** in a program. (Value must fit in an unsigned short int.) */ #if !defined(LUAI_MAXCCALLS) #define LUAI_MAXCCALLS 200 #endif /* ** maximum number of upvalues in a closure (both C and Lua). (Value ** must fit in an unsigned char.) */ #define MAXUPVAL UCHAR_MAX /* ** type for virtual-machine instructions ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) */ typedef lu_int32 Instruction; /* maximum stack for a Lua function */ #define MAXSTACK 250 /* minimum size for the string table (must be power of 2) */ #if !defined(MINSTRTABSIZE) #define MINSTRTABSIZE 32 #endif /* minimum size for string buffer */ #if !defined(LUA_MINBUFFER) #define LUA_MINBUFFER 32 #endif #if !defined(lua_lock) #define lua_lock(L) ((void) 0) #define lua_unlock(L) ((void) 0) #endif #if !defined(luai_threadyield) #define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} #endif /* ** these macros allow user-specific actions on threads when you defined ** LUAI_EXTRASPACE and need to do something extra when a thread is ** created/deleted/resumed/yielded. */ #if !defined(luai_userstateopen) #define luai_userstateopen(L) ((void)L) #endif #if !defined(luai_userstateclose) #define luai_userstateclose(L) ((void)L) #endif #if !defined(luai_userstatethread) #define luai_userstatethread(L,L1) ((void)L) #endif #if !defined(luai_userstatefree) #define luai_userstatefree(L,L1) ((void)L) #endif #if !defined(luai_userstateresume) #define luai_userstateresume(L,n) ((void)L) #endif #if !defined(luai_userstateyield) #define luai_userstateyield(L,n) ((void)L) #endif /* ** lua_number2int is a macro to convert lua_Number to int. ** lua_number2integer is a macro to convert lua_Number to lua_Integer. ** lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned. ** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number. ** luai_hashnum is a macro to hash a lua_Number value into an integer. ** The hash must be deterministic and give reasonable values for ** both small and large values (outside the range of integers). */ #if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */ /* trick with Microsoft assembler for X86 */ #define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} #define lua_number2integer(i,n) lua_number2int(i, n) #define lua_number2unsigned(i,n) \ {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;} #elif defined(LUA_IEEE754TRICK) /* }{ */ /* the next trick should work on any machine using IEEE754 with a 32-bit int type */ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; #if !defined(LUA_IEEEENDIAN) /* { */ #define LUAI_EXTRAIEEE \ static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)}; #define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33) #else #define LUA_IEEEENDIANLOC LUA_IEEEENDIAN #define LUAI_EXTRAIEEE /* empty */ #endif /* } */ #define lua_number2int32(i,n,t) \ { LUAI_EXTRAIEEE \ volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ (i) = (t)u.l_p[LUA_IEEEENDIANLOC]; } #define luai_hashnum(i,n) \ { volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \ (i) = u.l_p[0]; (i) += u.l_p[1]; } /* add double bits for his hash */ #define lua_number2int(i,n) lua_number2int32(i, n, int) #define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned) /* the trick can be expanded to lua_Integer when it is a 32-bit value */ #if defined(LUA_IEEELL) #define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer) #endif #endif /* } */ /* the following definitions always work, but may be slow */ #if !defined(lua_number2int) #define lua_number2int(i,n) ((i)=(int)(n)) #endif #if !defined(lua_number2integer) #define lua_number2integer(i,n) ((i)=(lua_Integer)(n)) #endif #if !defined(lua_number2unsigned) /* { */ /* the following definition assures proper modulo behavior */ #if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT) #include #define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1) #define lua_number2unsigned(i,n) \ ((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED)) #else #define lua_number2unsigned(i,n) ((i)=(lua_Unsigned)(n)) #endif #endif /* } */ #if !defined(lua_unsigned2number) /* on several machines, coercion from unsigned to double is slow, so it may be worth to avoid */ #define lua_unsigned2number(u) \ (((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u)) #endif #if defined(ltable_c) && !defined(luai_hashnum) #include #include #define luai_hashnum(i,n) { int e; \ n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ lua_number2int(i, n); i += e; } #endif /* ** macro to control inclusion of some hard tests on stack reallocation */ #if !defined(HARDSTACKTESTS) #define condmovestack(L) ((void)0) #else /* realloc stack keeping its size */ #define condmovestack(L) luaD_reallocstack((L), (L)->stacksize) #endif #if !defined(HARDMEMTESTS) #define condchangemem(L) condmovestack(L) #else #define condchangemem(L) \ ((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1))) #endif #endif blobby-1.0/src/state/ReplayState.h000644 001750 001750 00000003222 12313310253 021720 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include "GameState.h" #include "Vector.h" class DuelMatch; class ReplayPlayer; /*! \class ReplayState \brief State playing a replay */ class ReplayState : public GameState { public: ReplayState(); ~ReplayState(); virtual void step_impl(); virtual const char* getStateName() const; void loadReplay(const std::string& replay); private: boost::scoped_ptr mReplayPlayer; //bool mChecksumError; //bool mVersionError; Vector2 mLastMousePosition; int mMouseShowTimer; // controls int mPositionJump; bool mPaused; // replay speed control int mSpeedValue; int mSpeedTimer; }; blobby-1.0/src/main.cpp000644 001750 001750 00000023763 12313310252 017635 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* includes */ #include #include #include #include #include #ifndef __APPLE__ #ifndef __ANDROID__ #include "config.h" #endif #endif #ifdef __APPLE__ #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR #include #else #include "config.h" #endif #endif #include "RenderManager.h" #include "SoundManager.h" #include "InputManager.h" #include "TextManager.h" #include "UserConfig.h" #include "IMGUI.h" #include "SpeedController.h" #include "Blood.h" #include "FileSystem.h" #include "state/State.h" #if defined(WIN32) #ifndef GAMEDATADIR #define GAMEDATADIR "data" #endif #endif #ifdef WIN32 #include #undef main #endif /* implementation */ void deinit() { RenderManager::getSingleton().deinit(); SoundManager::getSingleton().deinit(); State::deinit(); SDL_Quit(); } void setupPHYSFS() { FileSystem& fs = FileSystem::getSingleton(); std::string separator = fs.getDirSeparator(); // Game should be playable out of the source package on all // relevant platforms. std::string baseSearchPath("data" + separator); // Android and iOS are needing a special path #ifdef __ANDROID__ baseSearchPath = SDL_AndroidGetExternalStoragePath() + separator; #endif #ifdef __APPLE__ #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR baseSearchPath = PHYSFS_getBaseDir(); #endif #endif fs.addToSearchPath(baseSearchPath); fs.addToSearchPath(baseSearchPath + "gfx.zip"); fs.addToSearchPath(baseSearchPath + "sounds.zip"); fs.addToSearchPath(baseSearchPath + "scripts.zip"); fs.addToSearchPath(baseSearchPath + "backgrounds.zip"); fs.addToSearchPath(baseSearchPath + "rules.zip"); #if defined(WIN32) // Just write in installation directory fs.setWriteDir("data"); // handle the case when it is installed fs.addToSearchPath(BLOBBY_INSTALL_PREFIX "/share/blobby"); fs.addToSearchPath(BLOBBY_INSTALL_PREFIX "/share/blobby/gfx.zip"); fs.addToSearchPath(BLOBBY_INSTALL_PREFIX "/share/blobby/sounds.zip"); fs.addToSearchPath(BLOBBY_INSTALL_PREFIX "/share/blobby/scripts.zip"); fs.addToSearchPath(BLOBBY_INSTALL_PREFIX "/share/blobby/backgrounds.zip"); fs.addToSearchPath(BLOBBY_INSTALL_PREFIX "/share/blobby/rules.zip"); #else #ifndef __ANDROID__ // Create a search path in the home directory and ensure that // all paths exist and are actually directories #ifdef __APPLE__ #if TARGET_OS_IPHONE std::string userdir = baseSearchPath + "../Documents/"; #else std::string userdir = fs.getUserDir(); #endif #else std::string userdir = fs.getUserDir(); #endif std::string userAppend = ".blobby"; std::string homedir = userdir + userAppend; /// \todo please review this code and determine if we really need to add userdir to serach path /// only to remove it later fs.setWriteDir(userdir); fs.probeDir(userAppend); /// \todo why do we need separator here? fs.probeDir(userAppend + separator + "replays"); fs.probeDir(userAppend + separator + "gfx"); fs.probeDir(userAppend + separator + "sounds"); fs.probeDir(userAppend + separator + "scripts"); fs.probeDir(userAppend + separator + "backgrounds"); fs.probeDir(userAppend + separator + "rules"); fs.removeFromSearchPath(userdir); // here we set the write dir anew! fs.setWriteDir(homedir); #if defined(GAMEDATADIR) { // A global installation path makes only sense on non-Windows // platforms std::string basedir = GAMEDATADIR; fs.addToSearchPath(basedir); fs.addToSearchPath(basedir + separator + "gfx.zip"); fs.addToSearchPath(basedir + separator + "sounds.zip"); fs.addToSearchPath(basedir + separator + "scripts.zip"); fs.addToSearchPath(basedir + separator + "backgrounds.zip"); fs.addToSearchPath(basedir + separator + "rules.zip"); } #endif #else fs.setWriteDir(baseSearchPath); fs.probeDir("replays"); fs.probeDir("gfx"); fs.probeDir("sounds"); fs.probeDir("scripts"); fs.probeDir("backgrounds"); fs.probeDir("rules"); #endif #endif } #ifdef __ANDROID__ #undef main extern "C" int SDL_main(int argc, char* argv[]) #elif __APPLE__ #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR int main(int argc, char* argv[]) #else #undef main extern "C" int SDL_main(int argc, char* argv[]) #endif #else #undef main extern "C" int main(int argc, char* argv[]) #endif { DEBUG_STATUS("started main"); FileSystem filesys(argv[0]); setupPHYSFS(); DEBUG_STATUS("physfs initialised"); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK); DEBUG_STATUS("SDL initialised"); atexit(SDL_Quit); srand(SDL_GetTicks()); // Default is OpenGL and false // choose renderer RenderManager *rmanager = 0; SoundManager *smanager = 0; // Test Version Startup Warning #ifdef TEST_VERSION struct tm* ptm; time_t time = std::time(0); ptm = gmtime ( &time ); if( ptm->tm_year > (2014-1900) || ptm->tm_mon >= 4 ) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "TEST VERISON OUTDATED", (std::string("This is a test version of ") + AppTitle + " which expired on " "1.04.2014. Please visit blobby.sourceforge.net for a newer version").c_str(), 0); return -1; } SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "TEST VERISON WARNING", (std::string("This is a test version of ") + AppTitle + " for testing only.\n" "It might be unstable and/or incompatible to the current release. " "Use of this version is limited to 1.04.2014.\nUntil then, " "the final version will most likely be released and you should update to that one.\n" "Visit blobby.sourceforge.net for more information or bug reporting.").c_str(), 0); #endif try { UserConfig gameConfig; gameConfig.loadFile("config.xml"); TextManager::createTextManager(gameConfig.getString("language")); if(gameConfig.getString("device") == "SDL") rmanager = RenderManager::createRenderManagerSDL(); /*else if (gameConfig.getString("device") == "GP2X") rmanager = RenderManager::createRenderManagerGP2X();*/ #ifndef __ANDROID__ #ifndef __APPLE__ else if (gameConfig.getString("device") == "OpenGL") rmanager = RenderManager::createRenderManagerGL2D(); else { std::cerr << "Warning: Unknown renderer selected!"; std::cerr << "Falling back to OpenGL" << std::endl; rmanager = RenderManager::createRenderManagerGL2D(); } #else #if MAC_OS_X else if (gameConfig.getString("device") == "OpenGL") rmanager = RenderManager::createRenderManagerGL2D(); else { std::cerr << "Warning: Unknown renderer selected!"; std::cerr << "Falling back to OpenGL" << std::endl; rmanager = RenderManager::createRenderManagerGL2D(); } #endif #endif #endif // fullscreen? if(gameConfig.getString("fullscreen") == "true") rmanager->init(BASE_RESOLUTION_X, BASE_RESOLUTION_Y, true); else rmanager->init(BASE_RESOLUTION_X, BASE_RESOLUTION_Y, false); if(gameConfig.getString("show_shadow") == "true") rmanager->showShadow(true); else rmanager->showShadow(false); SpeedController scontroller(gameConfig.getFloat("gamefps")); SpeedController::setMainInstance(&scontroller); scontroller.setDrawFPS(gameConfig.getBool("showfps")); smanager = SoundManager::createSoundManager(); smanager->init(); smanager->setVolume(gameConfig.getFloat("global_volume")); smanager->setMute(gameConfig.getBool("mute")); /// \todo play sound is misleading. what we actually want to do is load the sound smanager->playSound("sounds/bums.wav", 0.0); smanager->playSound("sounds/pfiff.wav", 0.0); std::string bg = std::string("backgrounds/") + gameConfig.getString("background"); if ( FileSystem::getSingleton().exists(bg) ) rmanager->setBackground(bg); InputManager* inputmgr = InputManager::createInputManager(); int running = 1; DEBUG_STATUS("starting mainloop"); while (running) { inputmgr->updateInput(); running = inputmgr->running(); IMGUI::getSingleton().begin(); State::step(); rmanager = &RenderManager::getSingleton(); //RenderManager may change //draw FPS: static int lastfps = 0; if (scontroller.getDrawFPS()) { // We need to ensure that the title bar is only set // when the framerate changed, because setting the // title can ne quite resource intensive on some // windows manager, like for example metacity. int newfps = scontroller.getFPS(); if (newfps != lastfps) { std::stringstream tmp; tmp << AppTitle << " FPS: " << newfps; rmanager->setTitle(tmp.str()); } lastfps = newfps; } // Dirty workarround for hiding fps in title if (!scontroller.getDrawFPS() && (lastfps != -1)) { std::stringstream tmp; tmp << AppTitle; rmanager->setTitle(tmp.str()); lastfps = -1; } if (!scontroller.doFramedrop()) { rmanager->draw(); IMGUI::getSingleton().end(); BloodManager::getSingleton().step(); rmanager->refresh(); } scontroller.update(); } } catch (std::exception& e) { std::cerr << e.what() << std::endl; if (rmanager) rmanager->deinit(); if (smanager) smanager->deinit(); SDL_Quit(); exit (EXIT_FAILURE); } deinit(); exit(EXIT_SUCCESS); } blobby-1.0/data/gfx/font48.bmp000644 001750 001750 00000003370 12313310254 020727 0ustar00danielknobedanielknobe000000 000000 BM6( ###klk()({~{LOLUVUĿ^a^*++Ֆ   blobby-1.0/src/lua/lgc.c000644 001750 001750 00000111544 12313310253 017673 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lgc.c,v 2.140.1.2 2013/04/26 18:22:05 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ #include #define lgc_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" /* ** cost of sweeping one element (the size of a small object divided ** by some adjust for the sweep speed) */ #define GCSWEEPCOST ((sizeof(TString) + 4) / 4) /* maximum number of elements to sweep in each single step */ #define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) /* maximum number of finalizers to call in each GC step */ #define GCFINALIZENUM 4 /* ** macro to adjust 'stepmul': 'stepmul' is actually used like ** 'stepmul / STEPMULADJ' (value chosen by tests) */ #define STEPMULADJ 200 /* ** macro to adjust 'pause': 'pause' is actually used like ** 'pause / PAUSEADJ' (value chosen by tests) */ #define PAUSEADJ 100 /* ** 'makewhite' erases all color bits plus the old bit and then ** sets only the current white bit */ #define maskcolors (~(bit2mask(BLACKBIT, OLDBIT) | WHITEBITS)) #define makewhite(g,x) \ (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) #define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) #define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) #define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT) #define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) #define checkconsistency(obj) \ lua_longassert(!iscollectable(obj) || righttt(obj)) #define markvalue(g,o) { checkconsistency(o); \ if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } #define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ reallymarkobject(g, obj2gco(t)); } static void reallymarkobject (global_State *g, GCObject *o); /* ** {====================================================== ** Generic functions ** ======================================================= */ /* ** one after last element in a hash array */ #define gnodelast(h) gnode(h, cast(size_t, sizenode(h))) /* ** link table 'h' into list pointed by 'p' */ #define linktable(h,p) ((h)->gclist = *(p), *(p) = obj2gco(h)) /* ** if key is not marked, mark its entry as dead (therefore removing it ** from the table) */ static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); if (valiswhite(gkey(n))) setdeadvalue(gkey(n)); /* unused and unmarked key; remove it */ } /* ** tells whether a key or value can be cleared from a weak ** table. Non-collectable objects are never removed from weak ** tables. Strings behave as `values', so are never removed too. for ** other objects: if really collected, cannot keep them; for objects ** being finalized, keep them in keys, but not in values */ static int iscleared (global_State *g, const TValue *o) { if (!iscollectable(o)) return 0; else if (ttisstring(o)) { markobject(g, rawtsvalue(o)); /* strings are `values', so are never weak */ return 0; } else return iswhite(gcvalue(o)); } /* ** barrier that moves collector forward, that is, mark the white object ** being pointed by a black object. */ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); lua_assert(g->gcstate != GCSpause); lua_assert(gch(o)->tt != LUA_TTABLE); if (keepinvariantout(g)) /* must keep invariant? */ reallymarkobject(g, v); /* restore invariant */ else { /* sweep phase */ lua_assert(issweepphase(g)); makewhite(g, o); /* mark main obj. as white to avoid other barriers */ } } /* ** barrier that moves collector backward, that is, mark the black object ** pointing to a white object as gray again. (Current implementation ** only works for tables; access to 'gclist' is not uniform across ** different types.) */ void luaC_barrierback_ (lua_State *L, GCObject *o) { global_State *g = G(L); lua_assert(isblack(o) && !isdead(g, o) && gch(o)->tt == LUA_TTABLE); black2gray(o); /* make object gray (again) */ gco2t(o)->gclist = g->grayagain; g->grayagain = o; } /* ** barrier for prototypes. When creating first closure (cache is ** NULL), use a forward barrier; this may be the only closure of the ** prototype (if it is a "regular" function, with a single instance) ** and the prototype may be big, so it is better to avoid traversing ** it again. Otherwise, use a backward barrier, to avoid marking all ** possible instances. */ LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c) { global_State *g = G(L); lua_assert(isblack(obj2gco(p))); if (p->cache == NULL) { /* first time? */ luaC_objbarrier(L, p, c); } else { /* use a backward barrier */ black2gray(obj2gco(p)); /* make prototype gray (again) */ p->gclist = g->grayagain; g->grayagain = obj2gco(p); } } /* ** check color (and invariants) for an upvalue that was closed, ** i.e., moved into the 'allgc' list */ void luaC_checkupvalcolor (global_State *g, UpVal *uv) { GCObject *o = obj2gco(uv); lua_assert(!isblack(o)); /* open upvalues are never black */ if (isgray(o)) { if (keepinvariant(g)) { resetoldbit(o); /* see MOVE OLD rule */ gray2black(o); /* it is being visited now */ markvalue(g, uv->v); } else { lua_assert(issweepphase(g)); makewhite(g, o); } } } /* ** create a new collectable object (with given type and size) and link ** it to '*list'. 'offset' tells how many bytes to allocate before the ** object itself (used only by states). */ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, int offset) { global_State *g = G(L); char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz)); GCObject *o = obj2gco(raw + offset); if (list == NULL) list = &g->allgc; /* standard list for collectable objects */ gch(o)->marked = luaC_white(g); gch(o)->tt = tt; gch(o)->next = *list; *list = o; return o; } /* }====================================================== */ /* ** {====================================================== ** Mark functions ** ======================================================= */ /* ** mark an object. Userdata, strings, and closed upvalues are visited ** and turned black here. Other objects are marked gray and added ** to appropriate list to be visited (and turned black) later. (Open ** upvalues are already linked in 'headuv' list.) */ static void reallymarkobject (global_State *g, GCObject *o) { lu_mem size; white2gray(o); switch (gch(o)->tt) { case LUA_TSHRSTR: case LUA_TLNGSTR: { size = sizestring(gco2ts(o)); break; /* nothing else to mark; make it black */ } case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; markobject(g, mt); markobject(g, gco2u(o)->env); size = sizeudata(gco2u(o)); break; } case LUA_TUPVAL: { UpVal *uv = gco2uv(o); markvalue(g, uv->v); if (uv->v != &uv->u.value) /* open? */ return; /* open upvalues remain gray */ size = sizeof(UpVal); break; } case LUA_TLCL: { gco2lcl(o)->gclist = g->gray; g->gray = o; return; } case LUA_TCCL: { gco2ccl(o)->gclist = g->gray; g->gray = o; return; } case LUA_TTABLE: { linktable(gco2t(o), &g->gray); return; } case LUA_TTHREAD: { gco2th(o)->gclist = g->gray; g->gray = o; return; } case LUA_TPROTO: { gco2p(o)->gclist = g->gray; g->gray = o; return; } default: lua_assert(0); return; } gray2black(o); g->GCmemtrav += size; } /* ** mark metamethods for basic types */ static void markmt (global_State *g) { int i; for (i=0; i < LUA_NUMTAGS; i++) markobject(g, g->mt[i]); } /* ** mark all objects in list of being-finalized */ static void markbeingfnz (global_State *g) { GCObject *o; for (o = g->tobefnz; o != NULL; o = gch(o)->next) { makewhite(g, o); reallymarkobject(g, o); } } /* ** mark all values stored in marked open upvalues. (See comment in ** 'lstate.h'.) */ static void remarkupvals (global_State *g) { UpVal *uv; for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { if (isgray(obj2gco(uv))) markvalue(g, uv->v); } } /* ** mark root set and reset all gray lists, to start a new ** incremental (or full) collection */ static void restartcollection (global_State *g) { g->gray = g->grayagain = NULL; g->weak = g->allweak = g->ephemeron = NULL; markobject(g, g->mainthread); markvalue(g, &g->l_registry); markmt(g); markbeingfnz(g); /* mark any finalizing object left from previous cycle */ } /* }====================================================== */ /* ** {====================================================== ** Traverse functions ** ======================================================= */ static void traverseweakvalue (global_State *g, Table *h) { Node *n, *limit = gnodelast(h); /* if there is array part, assume it may have white values (do not traverse it just to check) */ int hasclears = (h->sizearray > 0); for (n = gnode(h, 0); n < limit; n++) { checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ else { lua_assert(!ttisnil(gkey(n))); markvalue(g, gkey(n)); /* mark key */ if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ hasclears = 1; /* table will have to be cleared */ } } if (hasclears) linktable(h, &g->weak); /* has to be cleared later */ else /* no white values */ linktable(h, &g->grayagain); /* no need to clean */ } static int traverseephemeron (global_State *g, Table *h) { int marked = 0; /* true if an object is marked in this traversal */ int hasclears = 0; /* true if table has white keys */ int prop = 0; /* true if table has entry "white-key -> white-value" */ Node *n, *limit = gnodelast(h); int i; /* traverse array part (numeric keys are 'strong') */ for (i = 0; i < h->sizearray; i++) { if (valiswhite(&h->array[i])) { marked = 1; reallymarkobject(g, gcvalue(&h->array[i])); } } /* traverse hash part */ for (n = gnode(h, 0); n < limit; n++) { checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ hasclears = 1; /* table must be cleared */ if (valiswhite(gval(n))) /* value not marked yet? */ prop = 1; /* must propagate again */ } else if (valiswhite(gval(n))) { /* value not marked yet? */ marked = 1; reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ } } if (prop) linktable(h, &g->ephemeron); /* have to propagate again */ else if (hasclears) /* does table have white keys? */ linktable(h, &g->allweak); /* may have to clean white keys */ else /* no white keys */ linktable(h, &g->grayagain); /* no need to clean */ return marked; } static void traversestrongtable (global_State *g, Table *h) { Node *n, *limit = gnodelast(h); int i; for (i = 0; i < h->sizearray; i++) /* traverse array part */ markvalue(g, &h->array[i]); for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ else { lua_assert(!ttisnil(gkey(n))); markvalue(g, gkey(n)); /* mark key */ markvalue(g, gval(n)); /* mark value */ } } } static lu_mem traversetable (global_State *g, Table *h) { const char *weakkey, *weakvalue; const TValue *mode = gfasttm(g, h->metatable, TM_MODE); markobject(g, h->metatable); if (mode && ttisstring(mode) && /* is there a weak mode? */ ((weakkey = strchr(svalue(mode), 'k')), (weakvalue = strchr(svalue(mode), 'v')), (weakkey || weakvalue))) { /* is really weak? */ black2gray(obj2gco(h)); /* keep table gray */ if (!weakkey) /* strong keys? */ traverseweakvalue(g, h); else if (!weakvalue) /* strong values? */ traverseephemeron(g, h); else /* all weak */ linktable(h, &g->allweak); /* nothing to traverse now */ } else /* not weak */ traversestrongtable(g, h); return sizeof(Table) + sizeof(TValue) * h->sizearray + sizeof(Node) * cast(size_t, sizenode(h)); } static int traverseproto (global_State *g, Proto *f) { int i; if (f->cache && iswhite(obj2gco(f->cache))) f->cache = NULL; /* allow cache to be collected */ markobject(g, f->source); for (i = 0; i < f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ markobject(g, f->upvalues[i].name); for (i = 0; i < f->sizep; i++) /* mark nested protos */ markobject(g, f->p[i]); for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ markobject(g, f->locvars[i].varname); return sizeof(Proto) + sizeof(Instruction) * f->sizecode + sizeof(Proto *) * f->sizep + sizeof(TValue) * f->sizek + sizeof(int) * f->sizelineinfo + sizeof(LocVar) * f->sizelocvars + sizeof(Upvaldesc) * f->sizeupvalues; } static lu_mem traverseCclosure (global_State *g, CClosure *cl) { int i; for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ markvalue(g, &cl->upvalue[i]); return sizeCclosure(cl->nupvalues); } static lu_mem traverseLclosure (global_State *g, LClosure *cl) { int i; markobject(g, cl->p); /* mark its prototype */ for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ markobject(g, cl->upvals[i]); return sizeLclosure(cl->nupvalues); } static lu_mem traversestack (global_State *g, lua_State *th) { int n = 0; StkId o = th->stack; if (o == NULL) return 1; /* stack not completely built yet */ for (; o < th->top; o++) /* mark live elements in the stack */ markvalue(g, o); if (g->gcstate == GCSatomic) { /* final traversal? */ StkId lim = th->stack + th->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); } else { /* count call infos to compute size */ CallInfo *ci; for (ci = &th->base_ci; ci != th->ci; ci = ci->next) n++; } return sizeof(lua_State) + sizeof(TValue) * th->stacksize + sizeof(CallInfo) * n; } /* ** traverse one gray object, turning it to black (except for threads, ** which are always gray). */ static void propagatemark (global_State *g) { lu_mem size; GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); switch (gch(o)->tt) { case LUA_TTABLE: { Table *h = gco2t(o); g->gray = h->gclist; /* remove from 'gray' list */ size = traversetable(g, h); break; } case LUA_TLCL: { LClosure *cl = gco2lcl(o); g->gray = cl->gclist; /* remove from 'gray' list */ size = traverseLclosure(g, cl); break; } case LUA_TCCL: { CClosure *cl = gco2ccl(o); g->gray = cl->gclist; /* remove from 'gray' list */ size = traverseCclosure(g, cl); break; } case LUA_TTHREAD: { lua_State *th = gco2th(o); g->gray = th->gclist; /* remove from 'gray' list */ th->gclist = g->grayagain; g->grayagain = o; /* insert into 'grayagain' list */ black2gray(o); size = traversestack(g, th); break; } case LUA_TPROTO: { Proto *p = gco2p(o); g->gray = p->gclist; /* remove from 'gray' list */ size = traverseproto(g, p); break; } default: lua_assert(0); return; } g->GCmemtrav += size; } static void propagateall (global_State *g) { while (g->gray) propagatemark(g); } static void propagatelist (global_State *g, GCObject *l) { lua_assert(g->gray == NULL); /* no grays left */ g->gray = l; propagateall(g); /* traverse all elements from 'l' */ } /* ** retraverse all gray lists. Because tables may be reinserted in other ** lists when traversed, traverse the original lists to avoid traversing ** twice the same table (which is not wrong, but inefficient) */ static void retraversegrays (global_State *g) { GCObject *weak = g->weak; /* save original lists */ GCObject *grayagain = g->grayagain; GCObject *ephemeron = g->ephemeron; g->weak = g->grayagain = g->ephemeron = NULL; propagateall(g); /* traverse main gray list */ propagatelist(g, grayagain); propagatelist(g, weak); propagatelist(g, ephemeron); } static void convergeephemerons (global_State *g) { int changed; do { GCObject *w; GCObject *next = g->ephemeron; /* get ephemeron list */ g->ephemeron = NULL; /* tables will return to this list when traversed */ changed = 0; while ((w = next) != NULL) { next = gco2t(w)->gclist; if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */ propagateall(g); /* propagate changes */ changed = 1; /* will have to revisit all ephemeron tables */ } } } while (changed); } /* }====================================================== */ /* ** {====================================================== ** Sweep Functions ** ======================================================= */ /* ** clear entries with unmarked keys from all weaktables in list 'l' up ** to element 'f' */ static void clearkeys (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); for (n = gnode(h, 0); n < limit; n++) { if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* and remove entry from table */ } } } } /* ** clear entries with unmarked values from all weaktables in list 'l' up ** to element 'f' */ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); int i; for (i = 0; i < h->sizearray; i++) { TValue *o = &h->array[i]; if (iscleared(g, o)) /* value was collected? */ setnilvalue(o); /* remove value */ } for (n = gnode(h, 0); n < limit; n++) { if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* and remove entry from table */ } } } } static void freeobj (lua_State *L, GCObject *o) { switch (gch(o)->tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TLCL: { luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); break; } case LUA_TCCL: { luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); break; } case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; case LUA_TTABLE: luaH_free(L, gco2t(o)); break; case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; case LUA_TSHRSTR: G(L)->strt.nuse--; /* go through */ case LUA_TLNGSTR: { luaM_freemem(L, o, sizestring(gco2ts(o))); break; } default: lua_assert(0); } } #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); /* ** sweep the (open) upvalues of a thread and resize its stack and ** list of call-info structures. */ static void sweepthread (lua_State *L, lua_State *L1) { if (L1->stack == NULL) return; /* stack not completely built yet */ sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ luaE_freeCI(L1); /* free extra CallInfo slots */ /* should not change the stack during an emergency gc cycle */ if (G(L)->gckind != KGC_EMERGENCY) luaD_shrinkstack(L1); } /* ** sweep at most 'count' elements from a list of GCObjects erasing dead ** objects, where a dead (not alive) object is one marked with the "old" ** (non current) white and not fixed. ** In non-generational mode, change all non-dead objects back to white, ** preparing for next collection cycle. ** In generational mode, keep black objects black, and also mark them as ** old; stop when hitting an old object, as all objects after that ** one will be old too. ** When object is a thread, sweep its list of open upvalues too. */ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { global_State *g = G(L); int ow = otherwhite(g); int toclear, toset; /* bits to clear and to set in all live objects */ int tostop; /* stop sweep when this is true */ if (isgenerational(g)) { /* generational mode? */ toclear = ~0; /* clear nothing */ toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */ tostop = bitmask(OLDBIT); /* do not sweep old generation */ } else { /* normal mode */ toclear = maskcolors; /* clear all color bits + old bit */ toset = luaC_white(g); /* make object white */ tostop = 0; /* do not stop */ } while (*p != NULL && count-- > 0) { GCObject *curr = *p; int marked = gch(curr)->marked; if (isdeadm(ow, marked)) { /* is 'curr' dead? */ *p = gch(curr)->next; /* remove 'curr' from list */ freeobj(L, curr); /* erase 'curr' */ } else { if (testbits(marked, tostop)) return NULL; /* stop sweeping this list */ if (gch(curr)->tt == LUA_TTHREAD) sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ /* update marks */ gch(curr)->marked = cast_byte((marked & toclear) | toset); p = &gch(curr)->next; /* go to next element */ } } return (*p == NULL) ? NULL : p; } /* ** sweep a list until a live object (or end of list) */ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { GCObject ** old = p; int i = 0; do { i++; p = sweeplist(L, p, 1); } while (p == old); if (n) *n += i; return p; } /* }====================================================== */ /* ** {====================================================== ** Finalization ** ======================================================= */ static void checkSizes (lua_State *L) { global_State *g = G(L); if (g->gckind != KGC_EMERGENCY) { /* do not change sizes in emergency */ int hs = g->strt.size / 2; /* half the size of the string table */ if (g->strt.nuse < cast(lu_int32, hs)) /* using less than that half? */ luaS_resize(L, hs); /* halve its size */ luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */ } } static GCObject *udata2finalize (global_State *g) { GCObject *o = g->tobefnz; /* get first element */ lua_assert(isfinalized(o)); g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ gch(o)->next = g->allgc; /* return it to 'allgc' list */ g->allgc = o; resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */ lua_assert(!isold(o)); /* see MOVE OLD rule */ if (!keepinvariantout(g)) /* not keeping invariant? */ makewhite(g, o); /* "sweep" object */ return o; } static void dothecall (lua_State *L, void *ud) { UNUSED(ud); luaD_call(L, L->top - 2, 0, 0); } static void GCTM (lua_State *L, int propagateerrors) { global_State *g = G(L); const TValue *tm; TValue v; setgcovalue(L, &v, udata2finalize(g)); tm = luaT_gettmbyobj(L, &v, TM_GC); if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ int status; lu_byte oldah = L->allowhook; int running = g->gcrunning; L->allowhook = 0; /* stop debug hooks during GC metamethod */ g->gcrunning = 0; /* avoid GC steps */ setobj2s(L, L->top, tm); /* push finalizer... */ setobj2s(L, L->top + 1, &v); /* ... and its argument */ L->top += 2; /* and (next line) call the finalizer */ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); L->allowhook = oldah; /* restore hooks */ g->gcrunning = running; /* restore state */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ if (status == LUA_ERRRUN) { /* is there an error object? */ const char *msg = (ttisstring(L->top - 1)) ? svalue(L->top - 1) : "no message"; luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); status = LUA_ERRGCMM; /* error in __gc metamethod */ } luaD_throw(L, status); /* re-throw error */ } } } /* ** move all unreachable objects (or 'all' objects) that need ** finalization from list 'finobj' to list 'tobefnz' (to be finalized) */ static void separatetobefnz (lua_State *L, int all) { global_State *g = G(L); GCObject **p = &g->finobj; GCObject *curr; GCObject **lastnext = &g->tobefnz; /* find last 'next' field in 'tobefnz' list (to add elements in its end) */ while (*lastnext != NULL) lastnext = &gch(*lastnext)->next; while ((curr = *p) != NULL) { /* traverse all finalizable objects */ lua_assert(!isfinalized(curr)); lua_assert(testbit(gch(curr)->marked, SEPARATED)); if (!(iswhite(curr) || all)) /* not being collected? */ p = &gch(curr)->next; /* don't bother with it */ else { l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ *p = gch(curr)->next; /* remove 'curr' from 'finobj' list */ gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */ *lastnext = curr; lastnext = &gch(curr)->next; } } } /* ** if object 'o' has a finalizer, remove it from 'allgc' list (must ** search the list to find it) and link it in 'finobj' list. */ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { global_State *g = G(L); if (testbit(gch(o)->marked, SEPARATED) || /* obj. is already separated... */ isfinalized(o) || /* ... or is finalized... */ gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ return; /* nothing to be done */ else { /* move 'o' to 'finobj' list */ GCObject **p; GCheader *ho = gch(o); if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */ lua_assert(issweepphase(g)); g->sweepgc = sweeptolive(L, g->sweepgc, NULL); } /* search for pointer pointing to 'o' */ for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } *p = ho->next; /* remove 'o' from root list */ ho->next = g->finobj; /* link it in list 'finobj' */ g->finobj = o; l_setbit(ho->marked, SEPARATED); /* mark it as such */ if (!keepinvariantout(g)) /* not keeping invariant? */ makewhite(g, o); /* "sweep" object */ else resetoldbit(o); /* see MOVE OLD rule */ } } /* }====================================================== */ /* ** {====================================================== ** GC control ** ======================================================= */ /* ** set a reasonable "time" to wait before starting a new GC cycle; ** cycle will start when memory use hits threshold */ static void setpause (global_State *g, l_mem estimate) { l_mem debt, threshold; estimate = estimate / PAUSEADJ; /* adjust 'estimate' */ threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ ? estimate * g->gcpause /* no overflow */ : MAX_LMEM; /* overflow; truncate to maximum */ debt = -cast(l_mem, threshold - gettotalbytes(g)); luaE_setdebt(g, debt); } #define sweepphases \ (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) /* ** enter first sweep phase (strings) and prepare pointers for other ** sweep phases. The calls to 'sweeptolive' make pointers point to an ** object inside the list (instead of to the header), so that the real ** sweep do not need to skip objects created between "now" and the start ** of the real sweep. ** Returns how many objects it swept. */ static int entersweep (lua_State *L) { global_State *g = G(L); int n = 0; g->gcstate = GCSsweepstring; lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); /* prepare to sweep strings, finalizable objects, and regular objects */ g->sweepstrgc = 0; g->sweepfin = sweeptolive(L, &g->finobj, &n); g->sweepgc = sweeptolive(L, &g->allgc, &n); return n; } /* ** change GC mode */ void luaC_changemode (lua_State *L, int mode) { global_State *g = G(L); if (mode == g->gckind) return; /* nothing to change */ if (mode == KGC_GEN) { /* change to generational mode */ /* make sure gray lists are consistent */ luaC_runtilstate(L, bitmask(GCSpropagate)); g->GCestimate = gettotalbytes(g); g->gckind = KGC_GEN; } else { /* change to incremental mode */ /* sweep all objects to turn them back to white (as white has not changed, nothing extra will be collected) */ g->gckind = KGC_NORMAL; entersweep(L); luaC_runtilstate(L, ~sweepphases); } } /* ** call all pending finalizers */ static void callallpendingfinalizers (lua_State *L, int propagateerrors) { global_State *g = G(L); while (g->tobefnz) { resetoldbit(g->tobefnz); GCTM(L, propagateerrors); } } void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); int i; separatetobefnz(L, 1); /* separate all objects with finalizers */ lua_assert(g->finobj == NULL); callallpendingfinalizers(L, 0); g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ g->gckind = KGC_NORMAL; sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ sweepwholelist(L, &g->allgc); for (i = 0; i < g->strt.size; i++) /* free all string lists */ sweepwholelist(L, &g->strt.hash[i]); lua_assert(g->strt.nuse == 0); } static l_mem atomic (lua_State *L) { global_State *g = G(L); l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */ GCObject *origweak, *origall; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ /* registry and global metatables may be changed by API */ markvalue(g, &g->l_registry); markmt(g); /* mark basic metatables */ /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); propagateall(g); /* propagate changes */ work += g->GCmemtrav; /* stop counting (do not (re)count grays) */ /* traverse objects caught by write barrier and by 'remarkupvals' */ retraversegrays(g); work -= g->GCmemtrav; /* restart counting */ convergeephemerons(g); /* at this point, all strongly accessible objects are marked. */ /* clear values from weak tables, before checking finalizers */ clearvalues(g, g->weak, NULL); clearvalues(g, g->allweak, NULL); origweak = g->weak; origall = g->allweak; work += g->GCmemtrav; /* stop counting (objects being finalized) */ separatetobefnz(L, 0); /* separate objects to be finalized */ markbeingfnz(g); /* mark objects that will be finalized */ propagateall(g); /* remark, to propagate `preserveness' */ work -= g->GCmemtrav; /* restart counting */ convergeephemerons(g); /* at this point, all resurrected objects are marked. */ /* remove dead objects from weak tables */ clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ clearkeys(g, g->allweak, NULL); /* clear keys from all allweak tables */ /* clear values from resurrected weak tables */ clearvalues(g, g->weak, origweak); clearvalues(g, g->allweak, origall); g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ work += g->GCmemtrav; /* complete counting */ return work; /* estimate of memory marked by 'atomic' */ } static lu_mem singlestep (lua_State *L) { global_State *g = G(L); switch (g->gcstate) { case GCSpause: { /* start to count memory traversed */ g->GCmemtrav = g->strt.size * sizeof(GCObject*); lua_assert(!isgenerational(g)); restartcollection(g); g->gcstate = GCSpropagate; return g->GCmemtrav; } case GCSpropagate: { if (g->gray) { lu_mem oldtrav = g->GCmemtrav; propagatemark(g); return g->GCmemtrav - oldtrav; /* memory traversed in this step */ } else { /* no more `gray' objects */ lu_mem work; int sw; g->gcstate = GCSatomic; /* finish mark phase */ g->GCestimate = g->GCmemtrav; /* save what was counted */; work = atomic(L); /* add what was traversed by 'atomic' */ g->GCestimate += work; /* estimate of total memory traversed */ sw = entersweep(L); return work + sw * GCSWEEPCOST; } } case GCSsweepstring: { int i; for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++) sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]); g->sweepstrgc += i; if (g->sweepstrgc >= g->strt.size) /* no more strings to sweep? */ g->gcstate = GCSsweepudata; return i * GCSWEEPCOST; } case GCSsweepudata: { if (g->sweepfin) { g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX); return GCSWEEPMAX*GCSWEEPCOST; } else { g->gcstate = GCSsweep; return 0; } } case GCSsweep: { if (g->sweepgc) { g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); return GCSWEEPMAX*GCSWEEPCOST; } else { /* sweep main thread */ GCObject *mt = obj2gco(g->mainthread); sweeplist(L, &mt, 1); checkSizes(L); g->gcstate = GCSpause; /* finish collection */ return GCSWEEPCOST; } } default: lua_assert(0); return 0; } } /* ** advances the garbage collector until it reaches a state allowed ** by 'statemask' */ void luaC_runtilstate (lua_State *L, int statesmask) { global_State *g = G(L); while (!testbit(statesmask, g->gcstate)) singlestep(L); } static void generationalcollection (lua_State *L) { global_State *g = G(L); lua_assert(g->gcstate == GCSpropagate); if (g->GCestimate == 0) { /* signal for another major collection? */ luaC_fullgc(L, 0); /* perform a full regular collection */ g->GCestimate = gettotalbytes(g); /* update control */ } else { lu_mem estimate = g->GCestimate; luaC_runtilstate(L, bitmask(GCSpause)); /* run complete (minor) cycle */ g->gcstate = GCSpropagate; /* skip restart */ if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) g->GCestimate = 0; /* signal for a major collection */ else g->GCestimate = estimate; /* keep estimate from last major coll. */ } setpause(g, gettotalbytes(g)); lua_assert(g->gcstate == GCSpropagate); } static void incstep (lua_State *L) { global_State *g = G(L); l_mem debt = g->GCdebt; int stepmul = g->gcstepmul; if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values (and 0) */ /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */ debt = (debt / STEPMULADJ) + 1; debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; do { /* always perform at least one single step */ lu_mem work = singlestep(L); /* do some work */ debt -= work; } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); if (g->gcstate == GCSpause) setpause(g, g->GCestimate); /* pause until next cycle */ else { debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */ luaE_setdebt(g, debt); } } /* ** performs a basic GC step */ void luaC_forcestep (lua_State *L) { global_State *g = G(L); int i; if (isgenerational(g)) generationalcollection(L); else incstep(L); /* run a few finalizers (or all of them at the end of a collect cycle) */ for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) GCTM(L, 1); /* call one finalizer */ } /* ** performs a basic GC step only if collector is running */ void luaC_step (lua_State *L) { global_State *g = G(L); if (g->gcrunning) luaC_forcestep(L); else luaE_setdebt(g, -GCSTEPSIZE); /* avoid being called too often */ } /* ** performs a full GC cycle; if "isemergency", does not call ** finalizers (which could change stack positions) */ void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); int origkind = g->gckind; lua_assert(origkind != KGC_EMERGENCY); if (isemergency) /* do not run finalizers during emergency GC */ g->gckind = KGC_EMERGENCY; else { g->gckind = KGC_NORMAL; callallpendingfinalizers(L, 1); } if (keepinvariant(g)) { /* may there be some black objects? */ /* must sweep all objects to turn them back to white (as white has not changed, nothing will be collected) */ entersweep(L); } /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ luaC_runtilstate(L, bitmask(GCSpause)); /* run entire collection */ if (origkind == KGC_GEN) { /* generational mode? */ /* generational mode must be kept in propagate phase */ luaC_runtilstate(L, bitmask(GCSpropagate)); } g->gckind = origkind; setpause(g, gettotalbytes(g)); if (!isemergency) /* do not run finalizers during emergency GC */ callallpendingfinalizers(L, 1); } /* }====================================================== */ blobby-1.0/data/gfx/font05.bmp000644 001750 001750 00000003370 12313310254 020720 0ustar00danielknobedanielknobe000000 000000 BM6(  $ >O [[M 4  ! s c 9  / %-=EVeelkqY`:= b. K[QPX]J^/#4;@T|^yƇtHY-!@  rv:) J/"&7-1' IdXըMŇ XC; %,37F og6D$,-f+Rm +B6IPQ d =f Nm D)#! 6[~c D/dZuL ?, D{ O ?5)''x QP6 F A 9;+LI=nRH)+  -d>98 ,Wu~b Pa-:($# %$C,r 7 <;6a|o,} O3a%M"O&h1='O8Y4P#f pyF|P 6/ 2?A`[tVj-8y "*ځUx'N:~"*8-6e 15B{Nh ;\72.26) then right() elseif (posx()>x) and (math.abs(posx()-x)>2.26) then left() end end function tb(y,vy,height,typ) local sgn=0 if (typ==1) then sgn=-1 else sgn=1 end if vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g<0 then return -1 else return -1/10+vy/g+sgn*math.sqrt( vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g ) end end function time(t) return 1/5*math.ceil(5*t) end function pos(x) local x1,x2 x1=4.5*math.ceil((1/4.5)*x) x2=4.5*math.floor((1/4.5)*x) if (x1<0) or (x2<0) then return 0 else if (math.abs(x1-x)146) then return (v1p/0.88-1/2+math.sqrt((v1p/0.88-1/2)^2-(144.5-y1p)/0.44)) else return 0 end end function time(t) return 1/5*math.ceil(5*t) end -- function collide(x,y,vx,vy,objx,objy,r2) local t1=time(math.max(tb(y,vy,objy-(r1+r2),1)-0.2,0)) local t2=time(tb(y,vy,objy+(r1+r2),1)+0.2) local t3=time(math.max(tb(y,vy,objy+(r1+r2),2)-0.2,0)) local t4=time(tb(y,vy,objy-(r1+r2),2)+0.2) local t=-1 if (t1150) then t=-1 end return t end function estimate(x,y,vx,vy,height,typ) local collision=1 local tw,tn,ts=0,0,0 local tr,xr,yr,vxr,vyr,n=0,0,0,0,0,0 while(collision==1) do ts=collide(x,y,vx,vy,400,316,7) if (vx>0) then tw=time((768.5-x)/vx) tn=time((361.5-x)/vx) else tw=time((31.5-x)/vx) tn=time((438.5-x)/vx) end local th=time(tb(y,vy,height,typ)) local t=10000 if ((ts>0) and (ts0) and (tn0) and (twt) then if (t==ts) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vy=vy-g*t xr=x yr=y vxr=0 vyr=0 n=1 collision=0 elseif ((t==tn) or (t==tw)) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vx=-vx vy=vy-g*t collision=1 end else tr=tr+th vxr=vx vyr=vy-g*th xr=x+vx*th yr=yb(y,vy,th) collision=0 end end if (tr<0) then return -1,-1,-1,-1,-1,-1 else return xr,yr,vxr,vyr,tr,n end end function impact(x,y,vx,vy,xpos,ypos,targety,jump,move) local x1,y1,vx1,vy1=0,0,0,0 local x2,y2,vx2,vy2,t2,nn=0,0,0,0,0,0 local xpos1=xpos local ypos1=ypos for t=0,20,0.2 do if (jump==1) then ypos1=yp(tp(ypos)+t) end x1=x+vx*t if (x1<31.5) then x1=2*31.5-x1 end if (x1>368.5) then x1=2*368.5-x1 end y1=yb(y,vy,t) if ((xpos1-x1)^2+(ypos1+19-y1)^2<(31.5+25)^2) then local dx=x1-xpos1 local dy=y1-(ypos1+19) local l=math.sqrt(dx^2+dy^2) vx1=dx/l vy1=dy/l x1=x1+vx1*3 y1=y1+vy1*3 vy1=vy1*13.125 vx1=vx1*13.125 x2,y2,vx2,vy2,t2,nn=estimate(x1,y1,vx1,vy1,targety,2) break end end return x2,y2,x1,y1,vx1,vy1 end function lob() if (math.abs(est-esto2)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 -- debug(-10) esto2=est imp=0 x1=0 t=30 while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5730) and (math.abs(posx()-x1f)/4.50) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f break end if (impfimp) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t end if (imp>740) then break end end if (t>12) then t=t-6 else t=t-4 end end t2=t2+1 end t2=t2-1 if (x1>0) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est) --p=0.5 end end function attack() if (math.abs(est-esto1)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 h2=900 -- debug(-10) esto1=est imp=0 x1=0 t=30 while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5400) and (math.abs(posx()-x1f)/4.5+10) and (x1f<360) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f xat=xaf yat=yaf vxat=vxaf vyat=vyaf break end end h2t=yb(yat,vyat,(400-xat)/vxat) if (h2t316+31.5+10) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t xa=xat ya=yat vxa=vxat vya=vyat end h2=yb(ya,vya,(400-xa)/vxa) if (h2>316+31.5+10) and (h2<316+31.5+45) then break end end if (t>12) then t=t-6 else t=t-4 end end t2=t2+1 end t2=t2-1 if (x1>0) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est) --p=0.9 end end function netp() if (math.abs(est-esto)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 -- debug(-10) esto=est imp=0 x1=0 for t=33,0,-3 do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,nn=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5400) and (math.abs(posx()-x1f)/4.50) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f break end end if (impt>imp) and (impt<431.5) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t end if (imp>428) then break end end end t2=t2+1 end t2=t2-1 if (x1>0) and (est<368.5) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est) end end function OnOpponentServe() y1p=144.5 if (math.abs(pos(posx())-posx())>1) then move(400) else move(200) end valid=1 end function OnServe(ballready) y1p=144.5 est=700 if (math.abs(pos(posx())-posx())>1) then move(400) else if (math.abs(posx()-180)<2) then jump() else move(180) end end valid=1 end function OnGame() yp2=y1p y1p=oppy() vp=y1p-yp2 esttold=estt netold=net toucho=touch touch=touches() if (touch400-31.5) then move (250) elseif (est<400-10) and (est>400-22) then move(200) elseif (est<400) and (est>400-10) then move(180) else move(230) end end blobby-1.0/data/scripts/old/com_10Schm.lua000644 001750 001750 00000011605 12313310254 023162 0ustar00danielknobedanielknobe000000 000000 -- Combot 1.0 - Schmettermod -- by Oreon, Axji & Enormator -- Flags und runners wait = 0 naechsterBallSchmettern = true -- evtl Variablennamen wechseln -- Weltkonstanten CONST_FELD_LAENGE = 800 CONST_BALL_RADIUS = 31.5 CONST_GROUND_PLANE = 100 CONST_BALL_GRAVITY = 0.28 CONST_MITTE = CONST_FELD_LAENGE/2 CONST_RECHTER_RAND = CONST_FELD_LAENGE - CONST_BALL_RADIUS CONST_BLOBBY_HOEHE = 89 CONST_BLOBBY_KOPF_RADIUS = 25 CONST_BLOBBY_BAUCH_RADIUS = 33 CONST_BLOBBY_KOPF_BERUEHRUNG = CONST_GROUND_PLANE + CONST_BLOBBY_HOEHE + CONST_BALL_RADIUS CONST_BLOBBY_MAXJUMP = 393.625 CONST_NETZ_RADIUS = 7 CONST_NETZ_HOEHE = 323 -- Berhrungsebene des Balls falls er ans Netz kommt CONST_NETZ_LINKS = CONST_MITTE - CONST_NETZ_RADIUS - CONST_BALL_RADIUS CONST_NETZ_RECHTS = CONST_MITTE + CONST_NETZ_RADIUS + CONST_BALL_RADIUS -- Charakter CONST_ANGRIFFSGRUNDWERT_MIN = 30 CONST_ANGRIFFSGRUNDWERT_MAX = 55 MIN_ANGRIFFSSTAERKE = CONST_ANGRIFFSGRUNDWERT_MIN MAX_ANGRIFFSSTAERKE = CONST_ANGRIFFSGRUNDWERT_MAX ANGRIFFSEINSCHRAENKUNG_HINTEN = 10 -- sonstige Einstellungen servexVersetzung=-7 --Wert ist so gewaehlt, dass der Ball nah ans Netz fliegt, der Gegner ihn aber grade nicht erreichen kann -- ***ANFANG*** function OnOpponentServe() movetoX(130) end function OnServe(ballready) servex=ballx()+servexVersetzung naechsterBallSchmettern = true generatenaechsterBallSchmettern() if ballready and movetoX(servex) then jump() end end function OnGame() target = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_KOPF_BERUEHRUNG,1) --X Ziel in Blobbyhoehe targets = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_KOPF_BERUEHRUNG,2) --X Richtung (-1 oder 1) bei Einschlag targetNetz = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_NETZ_HOEHE,1) --X Ziel in Netzhoehe (Netzrollerberechnung) targetJump = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_MAXJUMP,1) --X Ziel in Schmetterhoehe naechsterBallSchmetternFlagTesten() -- schaut ob der bot angreifen soll oder nicht if (ballx() > CONST_NETZ_RECHTS) then --Wenn Ball auf rechter Spielfeldseite dann generatenaechsterBallSchmettern() --Angriffsstaerke neu berechnen end if (target > CONST_MITTE) and (ballx() > CONST_NETZ_RECHTS) then --Wenn der Ball mich nix angeht movetoX(135) --Dann auf Standartposition warten else if (targetNetz > CONST_NETZ_LINKS - 10) then --Bei Netzroller einfach schmettern naechsterBallSchmettern = true end if naechsterBallSchmettern then if ((math.abs(bspeedx()) < 4) or (estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_MAXJUMP,2) < 0)) then sprungattacke(angriffsstaerke) else if (targetJump < CONST_MITTE / 2) then sprungattacke(-35) --an Rueckwand spielen else sprungattacke(0) --weiterleiten end end return end movetoX(target) end end function sprungattacke(p_angriffsstaerke) p_angriffsstaerke=math.max(p_angriffsstaerke, MIN_ANGRIFFSSTAERKE + ANGRIFFSEINSCHRAENKUNG_HINTEN * (targetJump / CONST_NETZ_LINKS)) --Weiter hinten nicht ganz so hoch spielen (kommt nicht auf die andere Seite) p_angriffsstaerke=math.min(p_angriffsstaerke, MAX_ANGRIFFSSTAERKE - ANGRIFFSEINSCHRAENKUNG_HINTEN * (targetJump / CONST_NETZ_LINKS)) --Weiter hinten nicht ganz so tief spielen (kommt ans Netz) movetoX(targetJump-p_angriffsstaerke) -- Bei der Sprungatacke wird die Strke des gewnschten schlages angegeben if (bally() < 580) and (bspeedy() < 0) then jump() end end function naechsterBallSchmetternFlagTesten() naechsterBallSchmettern = true end function generatenaechsterBallSchmettern() angriffsstaerke = math.random(MIN_ANGRIFFSSTAERKE,MAX_ANGRIFFSSTAERKE) end function estimImpact(bx,by,vbx,vby,destY,Frage) -- erlaubt ein besseres Estimate mit ein paar unbeding ntigen Angaben bgrav = 0.28 time1 =(-vby-math.sqrt((vby^2)-(-2*bgrav*(by-destY))))/(-bgrav) resultX = (vbx * time1) + bx estimbspeedx=bspeedx()/math.abs(bspeedx()) if(resultX > CONST_RECHTER_RAND) then -- Korrigieren der Appraller an der Rechten Ebene resultX = 2 * CONST_FELD_LAENGE - resultX estimbspeedx=-estimbspeedx end if(resultX < CONST_BALL_RADIUS) then -- korrigieren der Appraller an der linken Ebene resultX = math.abs(resultX - CONST_BALL_RADIUS) + CONST_BALL_RADIUS estimbspeedx=-estimbspeedx KollisionLinks = true else KollisionLinks = false end if (resultX > CONST_NETZ_RECHTS) and (estimbspeedx > 0) and ((KollisionLinks == true) or (ballx() < CONST_NETZ_LINKS)) then -- Abpraller am Netz unterhalb der Kugel erst wenn Netzroller ausgeschlossen sind resultX = 2 * CONST_NETZ_LINKS - resultX estimbspeedx=-estimbspeedx end if (Frage == 1) then return resultX end if (Frage == 2) then return estimbspeedx end end function movetoX (x) if (math.abs(posx()-x)>math.abs(posx()+4.5-x)) then right() done=false else if (math.abs(posx()-x)>math.abs(posx()-4.5-x)) then left() done=false else done=true end end return done end blobby-1.0/src/state/OptionsState.h000644 001750 001750 00000010361 12313310253 022121 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "Global.h" #include "UserConfig.h" #include "State.h" #include "TextManager.h" #include /*! \class OptionState \brief State for managing the main options menu */ class OptionState : public State { public: OptionState(); virtual ~OptionState(); virtual void step_impl(); virtual const char* getStateName() const; private: /// writes current settings to disk void save(); UserConfig mOptionConfig; std::vector mScriptNames; unsigned mPlayerOptions[MAX_PLAYERS]; std::string mPlayerName[MAX_PLAYERS]; unsigned mPlayerNamePosition[MAX_PLAYERS]; unsigned mBotStrength[MAX_PLAYERS]; }; /*! \class GraphicOptionsState \brief State for managing the graphics options menu */ class GraphicOptionsState : public State { public: GraphicOptionsState(); virtual ~GraphicOptionsState(); virtual void step_impl(); virtual const char* getStateName() const; private: /// writes current settings to disk void save(); UserConfig mOptionConfig; bool mFullscreen; std::string mRenderer; int mR1, mG1, mB1, mR2, mG2, mB2; bool mLeftMorphing, mRightMorphing; bool mShowShadow; }; /*! \class InputOptionsState \brief State for managing the input options menu */ class InputOptionsState : public State { public: InputOptionsState(); virtual ~InputOptionsState(); virtual void step_impl(); virtual const char* getStateName() const; private: enum InputAction { IA_LEFT, IA_RIGHT, IA_JUMP, IA_COUNT }; /// writes current settings to disk void save(); UserConfig mOptionConfig; std::string oldString; int mOldInteger; std::string mOldString; int mSetKeyboard; // 1-10 for LeftKeyboard | 11-20 for RightKeyboard //left data: std::string mLeftBlobbyDevice; int mLeftBlobbyMouseJumpbutton; /// \todo maybe use a struct here std::string mLeftBlobbyKeyboard[IA_COUNT]; std::string mLeftBlobbyJoystick[IA_COUNT]; //right data: std::string mRightBlobbyDevice; int mRightBlobbyMouseJumpbutton; std::string mRightBlobbyKeyboard[IA_COUNT]; std::string mRightBlobbyJoystick[IA_COUNT]; //global data: int mBlobbyTouchType; // input display functions void handleKeyboardInput(int base_x, std::string& lastActionKey, std::string input[]); void handleJoystickInput(int base_x, std::string input[]); void handleMouseInput(int base_x, int& input); // helper function void getMouseInput(int& action, TextManager::STRING input); void getKeyboardInput(std::string& action, TextManager::STRING input, std::string lastActionKey); void getJoystickInput(std::string& action, TextManager::STRING input); void getInputPrompt(TextManager::STRING prompt, TextManager::STRING input); // returns the correct text manager string for the device string TextManager::STRING getDeviceName(const std::string& device) const; }; /*! \class MiscOptionsState \brief State for managing the misc options menu */ class MiscOptionsState : public State { public: MiscOptionsState(); virtual ~MiscOptionsState(); virtual void step_impl(); virtual const char* getStateName() const; private: /// writes current settings to disk void save(); UserConfig mOptionConfig; std::vector mBackgrounds; unsigned mBackground; std::vector mRules; unsigned mRule; float mVolume; bool mMute; int mGameFPS; bool mShowFPS; bool mShowBlood; int mNetworkSide; std::string mLanguage; }; blobby-1.0/src/InputSourceFactory.h000644 001750 001750 00000002376 12313310253 022164 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "Global.h" #include class IUserConfigReader; class InputSource; class InputSourceFactory { public: static boost::shared_ptr createInputSource( boost::shared_ptr config, PlayerSide pls ); }; blobby-1.0/src/RenderManagerGL2D.h000644 001750 001750 00000007007 12313310251 021471 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #if HAVE_LIBGL #include #if __MACOSX__ #include #include #else #include #include #endif #include #include #include #include "RenderManager.h" /*! \class RenderManagerGL2D \brief RenderManager on top of OpenGL \details This render manager uses OpenGL for drawing, SDL is only used for loading the images. */ class RenderManagerGL2D : public RenderManager { public: RenderManagerGL2D(); virtual void init(int xResolution, int yResolution, bool fullscreen); virtual void deinit(); virtual void draw(); virtual void refresh(); virtual bool setBackground(const std::string& filename); virtual void setBlobColor(int player, Color color); virtual void showShadow(bool shadow); virtual void setBall(const Vector2& position, float rotation); virtual void setBlob(int player, const Vector2& position, float animationState); virtual void drawText(const std::string& text, Vector2 position, unsigned int flags = TF_NORMAL); virtual void drawImage(const std::string& filename, Vector2 position, Vector2 size); virtual void drawOverlay(float opacity, Vector2 pos1, Vector2 pos2, Color col); virtual void drawBlob(const Vector2& pos, const Color& col); virtual void startDrawParticles(); virtual void drawParticle(const Vector2& pos, int player); virtual void endDrawParticles(); private: // Make sure this object is created before any opengl call SDL_GLContext mGlContext; struct Texture { float indices[8]; float w, h ; GLuint texture; Texture( GLuint tex, int x, int y, int w, int h, int tw, int th ); }; GLuint mBackground; GLuint mBallShadow; std::vector mBall; std::vector mBlob; std::vector mBlobSpecular; std::vector mBlobShadow; std::vector mFont; std::vector mHighlightFont; GLuint mParticle; std::list mLastBallStates; Vector2 mBallPosition; float mBallRotation; Vector2 mLeftBlobPosition; float mLeftBlobAnimationState; Vector2 mRightBlobPosition; float mRightBlobAnimationState; bool mShowShadow; Color mLeftBlobColor; Color mRightBlobColor; void drawQuad(float x, float y, float width, float height); void drawQuad(float x, float y, const Texture& tex); GLuint loadTexture(SDL_Surface* surface, bool specular); int getNextPOT(int npot); void glEnable(unsigned int flag); void glDisable(unsigned int flag); void glBindTexture(GLuint texture); GLuint mCurrentTexture; std::set mCurrentFlags; }; #endif blobby-1.0/data/scripts/hyp014.lua000644 001750 001750 00000027341 12313310254 021544 0ustar00danielknobedanielknobe000000 000000 g= -CONST_BALL_GRAVITY pg= -CONST_BLOBBY_GRAVITY v0=14.5 v_p=4.5 pj= pg/2 r1= CONST_BALL_RADIUS h=31.5+19+25 estt=0 p=0.654 s=math.random() function reset() est=0 imp,imp1,imp2=0,0,0 nettime=0 touch=0 esto1=0 esto2=0 esto3=0 esto4=0 esto5=0 esto6=0 phase=0 valid=1 active=1 nettime=0 y1p=posy() end function yb(y,vy,t) return y+(vy-g/10)*t-1/2*g*t^2 end function move(x) if (posx()2.26) then right() elseif (posx()>x) and (math.abs(posx()-x)>2.26) then left() end end function tb(y,vy,height,typ) local sgn=0 if (typ==1) then sgn=-1 else sgn=1 end if vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g<0 then return -1 else return -1/10+vy/g+sgn*math.sqrt( vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g ) end end function time(t) return 1/5*math.ceil(5*t) end function pos2(x) local x1,x2 x1=4.5*math.ceil((1/4.5)*x) x2=4.5*math.floor((1/4.5)*x) if (x1<0) or (x2<0) then return 0 else if (math.abs(x1-x)146) then return (v1p/0.88-1/2+math.sqrt((v1p/0.88-1/2)^2-(144.5-y1p)/0.44)) else return 0 end end function time(t) return 1/5*math.ceil(5*t) end -- function collide(x,y,vx,vy,objx,objy,r2) local t1=time(math.max(tb(y,vy,objy-(r1+r2),1)-0.2,0)) local t2=time(tb(y,vy,objy+(r1+r2),1)+0.2) local t3=time(math.max(tb(y,vy,objy+(r1+r2),2)-0.2,0)) local t4=time(tb(y,vy,objy-(r1+r2),2)+0.2) local t=-1 if (t1=400-(31.5+7)) then return -1 end if ( (yb(y,vy,testimate)-objy)^2+(x+vx*testimate-objx)^2 < (r1+r2)^2) then t=testimate break end end end if (t<=0) and (t3=400-(31.5+7)) then return -1 end if ( (yb(y,vy,testimate)-objy)^2+(x+vx*testimate-objx)^2 < (r1+r2)^2) then t=testimate break end end end if (t<=0) or (t>150) then t=-1 end return t end function estimate(x,y,vx,vy,height,typ) local collision=1 local tw,tn,ts=0,0,0 local tr,xr,yr,vxr,vyr,n=0,0,0,0,0,0 while(collision==1) do ts=collide(x,y,vx,vy,400,316,7) if (vx>0) then tw=time((768.5-x)/vx) tn=time((361.5-x)/vx) else tw=time((31.5-x)/vx) tn=time((438.5-x)/vx) end local th=time(tb(y,vy,height,typ)) local t=10000 if ((ts>0) and (ts0) and (tn0) and (twt) then if (ts>0) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vy=vy-g*t xr=x yr=y vxr=vx vyr=vy n=1 collision=0 elseif ((t==tn) or (t==tw)) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vx=-vx vy=vy-g*t collision=1 end else tr=tr+th vxr=vx vyr=vy-g*th xr=x+vx*th yr=yb(y,vy,th) collision=0 end end if (tr<0) then return -1,-1,-1,-1,-1,-1 else return xr,yr,vxr,vyr,tr,n end end function impact(x,y,vx,vy,xpos,ypos,targety,jum,move) local x1,y1,vx1,vy1=0,0,0,0 local x2,y2,vx2,vy2,t2,nn=0,0,0,0,0,0 local xpos1=xpos local ypos1=ypos for t=0,7,0.2 do if (jum==1) then ypos1=yp(tp(ypos)+t) end x1=x+vx*t if (x1<31.5) then x1=2*31.5-x1 end if (x1>368.5) then x1=2*368.5-x1 end y1=yb(y,vy,t) if ((xpos1-x1)^2+(ypos1+19-y1)^2<(31.5+25)^2) then local dx=x1-xpos1 local dy=y1-(ypos1+19) local l=math.sqrt(dx^2+dy^2) vx1=dx/l vy1=dy/l x1=x1+vx1*3 y1=y1+vy1*3 vy1=vy1*13.125 vx1=vx1*13.125 x2,y2,vx2,vy2,t2,nn=estimate(x1,y1,vx1,vy1,targety,2) break end end return x2,y2,x1,y1,vx1,vy1 end function playto(position,delta) if (math.abs(est-esto5)>0.2) then esto5=est imp,impt,impf=0,0,0 x1=0 t=27 typ1=60 typ2=120 if (position<400) then n1=2 n2=-3 elseif (position>600) then n1=-4 n2=-11 else n1=-1 n2=-8 end while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(math.ceil((tp2(posy(),vp))))1) and (t2f>1) then for x1f=pos(x2f)+n1*4.5,pos(x2f)+n2*4.5,-4.5 do impf,_,xaf,yaf,vxaf,vyaf=impact(x2f,y2f,vx2f,vy2f,x1f,y1f,220,j,0) if (impf>position-delta) and (math.abs(posx()-x1f)/4.5+1=0) and (x1f<=360) and (x2f<=365) and (impfposition+delta) and ((x1f-pos(x2f))/4.5<0) then break end end end if (imp>position-delta) and (imp15) then t=t-6 else t=t-3 end end t2=t2+1 end if (x1>=0) and (imp>0) then t2=t2-1 move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else if (delta>60) then save() else playto(600,100) end end end function save() if (math.abs(est-esto3)>0.2) then delta=30 esto3=est imp,impt,impf=0,0,0 x1=0 t=33 typ1=60 typ2=120 while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f+0.1,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) -- if (y1f<316-h) then break end -- (t1f+math.abs(math.ceil((tp2(posy(),vp))))1) and (t1f+tp2(posy(),vp)+1=0) then impf,_,xaf,yaf,vxaf,vyaf=impact(x2f,y2f,vx2f,vy2f,x1f,y1f,220,j,0) imp=impf x1=x1f y1=y1f t1=t1f x2=x2f y2=y2f t2=t2f vx2=vx2f vy2=vy2f xa=xaf ya=yaf vxa=vxaf vya=vyaf t=-5 end if (t>15) then t=t-6 else t=t-3 end end t2=t2+1 end if (t2>-1) and (x1>=0) and (x1<=360) and (imp>0) then t2=t2-1 move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(200) end end function attack(low,high) if (math.abs(est-esto1)>0.2) then h2=900 esto1=est imp,impt,impf=0,0,0 x1=0 t=27 typ1=low--60 typ2=high--120 while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(math.ceil((tp2(posy(),vp))))+21) and (t2f>1) then for x1f=pos(x2f)-20*4.5,pos(x2f)-4*4.5,4.5 do impf,_,xaf,yaf,vxaf,vyaf=impact(x2f,y2f,vx2f,vy2f,x1f,y1f,220,j,0) h1=yb(yaf,vyaf,(380-xaf)/vxaf) h2=yb(yaf,vyaf,(420-xaf)/vxaf) height=316+7+31.5 if (impf>432) and (math.abs(posx()-x1f)/4.5+10) and (x2f<361) and (x1f<330) and (h2>height+typ1) and (h1>height+typ1) and (h2432) and (h2>height+typ2) then break end end end if (imp>0) then break end if (t>15) then t=t-6 else t=t-3 end end t2=t2+1 end if (x1>0) and (imp>0) then t2=t2-1 move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else playto(600,100) end end function wall() if (math.abs(est-esto4)>0.2) then delta=30 esto4=est imp,impt,impf=0,0,0 x1=0 t2=26 typ1=60 typ2=120 t1=t2 y1=yp(t1) t2g=math.floor(tb(y,vy,y1+h,2)) y2=yb(y,vy,t2g) vy2=vy-g*t2g x2,y2,vx2,vy2,t2,_=estimate(x,y,vx,vy,y2+vy2/30,2) t1=math.floor(tp(y2-h)) y1=yp(t1) x1=pos(x2)-10*4.5 t2=t2+1 end t2=t2-1 move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end end function OnOpponentServe() reset() if (math.abs(pos2(posx())-posx())>1) then move(400) else move(200) end end function OnServe(ballready) reset() if (math.abs(pos2(posx())-posx())>1) then move(400) else -- -10,-5,+8 if (s<0.3) then b=8 elseif (s>=0.3) and (s<0.7) then b=-10 elseif (s>=0.6) and (s<1) then b=-5 end a=198+b*4.5 if (math.abs(posx()-a)<2) then jump() else move(a) end end end function OnGame() s=math.random() yp2=y1p y1p=posy() vp=y1p-yp2 if (math.abs(imp1-imp)>0.1) then imp2=imp1 imp1=imp end esttold=estt netold=netc toucho=touch touch=touches() if (touch438.5) or (est<361.5)) then nettime=10 phase=5 elseif (phase==5) and (nettime>0) then nettime=nettime-1 else if (est>438.5) then phase=2 elseif (est<438.5) and (est>361.5) then if (est<400) and (math.abs(bspeedx())<1) then phase=99 wall() else if (yb(y,vy,(31.5-x)/vx)>220) then phase=6 else phase=4 end end else phase=1 end end else phase=0 end if (math.sqrt((ballx()-400)^2+(bally()-316)^2)<(31.5+7)) and (math.sqrt((bspeedx())^2+(bspeedy())^2)<2) then phase=3 end --phase --0: Spielstop --1: eigenes Feld --2: gegnerisches Feld --3: Ball hängt fest --4: Netzblock --5: Netzblock weiterführen --6: Netzball vorher abfangen if (phase==2) then move(200) elseif (phase==1) then if (p<0.5) then if (touch==0) then playto(320,30) elseif(touch==1) then if (p<0.2) then attack(60,120) elseif (p>=0.2) and (p<0.25) then attack(30,60) elseif (p>=0.25) and (p<0.275) then playto(420,20) elseif (p>=0.275) and (p<0.3) then playto(480,40) elseif (p>=0.3) and (p<0.38) then playto(760,40) elseif (p>=0.38) and (p<0.5) then playto(380,20) end elseif (touch==2) then if (p<0.4) then playto(600,100) else wall() end end else if (touch==0) then if (p<0.8) then attack(60,120) elseif (p>=0.8) and (p<0.9) then attack(30,60) elseif (p>=0.9) and (p<1) then playto(760,40) end else playto(600,100) end end elseif (phase==4) then if (tnet<=tp(393)-4) or (nettime>0) then jump() end if (math.abs(posx()-360)/4.5+2<=tnet) then left() else right() end elseif (phase==5) then right() jump() elseif (phase==6) then -- move(200) save() elseif (phase==3) then if (posx()>300) then jump() end right() end if ((x1==0) or (imp==0)) and (phase==1) then move(est) end if ((x1==0) or (imp==0)) and (phase==6) then move(200) end -- debug(0) -- debug(est) -- debug(imp) end blobby-1.0/src/raknet/NetworkTypes.h000644 001750 001750 00000011700 12313310247 022310 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file NetworkTypes.h * @brief Define Network Common Class and Types. * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __NETWORK_TYPES_H #define __NETWORK_TYPES_H #include #include namespace RakNet { class BitStream; } /** * Typename for player index */ typedef unsigned short PlayerIndex; /** * @brief Player Identifier * * This define a Player Unique Identifier. * In fact, it corresponds to the peer address. */ struct PlayerID { /** * The peer address from inet_addr. */ unsigned int binaryAddress; /** * The port number associated to the connexion. */ unsigned short port; /** * Copy operator * @param input a player ID * @return a reference to the current object */ PlayerID& operator = ( const PlayerID& input ) { binaryAddress = input.binaryAddress; port = input.port; return *this; } /** * Test if two Player Unique Identifier are the same * @param left a Player Unique Identifier * @param right a Player Unique Identifier * @return 1 if left and right corresponds to the same player 0 otherwise */ friend int operator==( const PlayerID& left, const PlayerID& right ); /** * Test if two Player Unique Identifier differs * @param left a Player Unique Identifier * @param right a Player Unique Identifier * @return 0 if left and right corresponds to the same player 1 otherwise */ friend int operator!=( const PlayerID& left, const PlayerID& right ); /** * Test if left is greater than right * @param left a Player Unique Identifier * @param right a Player Unique Identifier * @return 1 if left is greater than right, 0 otherwise */ friend int operator > ( const PlayerID& left, const PlayerID& right ); /** * Test if left is lesser than right * @param left a Player Unique Identifier * @param right a Player Unique Identifier * @return 1 if left is lesser than right, 0 otherwise */ friend int operator < ( const PlayerID& left, const PlayerID& right ); /** * Converts the playerID into a readable string representation */ std::string toString() const; }; /// Size of PlayerID data #define PlayerID_Size 6 /** * @brief Network Packet * * This structure store information concerning * a packet going throught the network */ struct Packet { /** * Server only - this is the index into the player array that this playerId maps to */ PlayerIndex playerIndex; /** * The Player Unique Identifier that send this packet. */ PlayerID playerId; /** * The length of the data. * @deprecated You should use bitSize inplace. * */ unsigned int length; /** * The number of bits in used. * Same as length but represents bits. Length is obsolete and retained for backwards compatibility. */ unsigned int bitSize; /** * The byte array. * The standard behaviour in RakNet define the first byte of the data array as the packet class. * @see PacketEnumerations.h */ unsigned char* data; /** * Converts the contents of this packet into a bitstream. Does not perform a deep copy of the packet data! * Use stream only as long as packet exists. */ RakNet::BitStream getStream() const; }; typedef boost::shared_ptr packet_ptr; /** * Index of an unassigned player */ const PlayerIndex UNASSIGNED_PLAYER_INDEX = 65535; /** * Index of an invalid Player Unique Id */ const PlayerID UNASSIGNED_PLAYER_ID = { 0xFFFFFFFF, 0xFFFF }; /** * Sizeof the Ping Array */ const int PING_TIMES_ARRAY_SIZE = 5; #endif blobby-1.0/src/raknet/NetworkTypes.cpp000644 001750 001750 00000005350 12313310247 022647 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Unique Player Identifier Class implementation * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "NetworkTypes.h" #include "BitStream.h" #include int operator==( const PlayerID& left, const PlayerID& right ) { return left.binaryAddress == right.binaryAddress && left.port == right.port; } int operator!=( const PlayerID& left, const PlayerID& right ) { return left.binaryAddress != right.binaryAddress || left.port != right.port; } int operator>( const PlayerID& left, const PlayerID& right ) { return ( ( left.binaryAddress > right.binaryAddress ) || ( ( left.binaryAddress == right.binaryAddress ) && ( left.port > right.port ) ) ); } int operator<( const PlayerID& left, const PlayerID& right ) { return ( ( left.binaryAddress < right.binaryAddress ) || ( ( left.binaryAddress == right.binaryAddress ) && ( left.port < right.port ) ) ); } std::string PlayerID::toString() const { return boost::lexical_cast(binaryAddress) + ":" + boost::lexical_cast(port); } RakNet::BitStream Packet::getStream() const { return RakNet::BitStream((char*)data, BITS_TO_BYTES(bitSize), false); } blobby-1.0/src/raknet/SimpleMutex.h000644 001750 001750 00000004162 12313310247 022112 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief SimpleMutex class implementation * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __SIMPLE_MUTEX_H #define __SIMPLE_MUTEX_H #ifdef _WIN32 #include #else #include #include #endif class SimpleMutex { public: SimpleMutex(); ~SimpleMutex(); void Lock(void); void Unlock(void); private: #ifdef _WIN32 //HANDLE hMutex; CRITICAL_SECTION criticalSection; // Docs say this is faster than a mutex for single process access #else pthread_mutex_t hMutex; #endif }; #endif blobby-1.0/data/scripts/old/hyp8.lua000644 001750 001750 00000022016 12313310254 022157 0ustar00danielknobedanielknobe000000 000000 g=0.28 pg=0.88 v0=14.5 v_p=4.5 pj=0.44 r1=31.5 p0=0 p1=0.5 p2=1 h=31.5+19+25 estt=0 nettime=0 touch=0 est=0 p=0.4 esto=10 function yb(y,vy,t) return y+(vy-g/10)*t-1/2*g*t^2 end function move(x) if (posx()2.26) then right() elseif (posx()>x) and (math.abs(posx()-x)>2.26) then left() end end function tb(y,vy,height,typ) local sgn=0 if (typ==1) then sgn=-1 else sgn=1 end if vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g<0 then return -1 else return -1/10+vy/g+sgn*math.sqrt( vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g ) end end function time(t) return 1/5*math.ceil(5*t) end function pos(x) local x1,x2 x1=4.5*math.ceil((1/4.5)*x) x2=4.5*math.floor((1/4.5)*x) if (x1<0) or (x2<0) then return 0 else if (math.abs(x1-x) function collide(x,y,vx,vy,objx,objy,r2) local t1=time(math.max(tb(y,vy,objy-(r1+r2),1)-0.2,0)) local t2=time(tb(y,vy,objy+(r1+r2),1)+0.2) local t3=time(math.max(tb(y,vy,objy+(r1+r2),2)-0.2,0)) local t4=time(tb(y,vy,objy-(r1+r2),2)+0.2) local t=-1 if (t1150) then t=-1 end return t end function estimate(x,y,vx,vy,height,typ) local collision=1 local tw,tn,ts=0,0,0 local tr,xr,yr,vxr,vyr,n=0,0,0,0,0,0 while(collision==1) do ts=collide(x,y,vx,vy,400,316,7) if (vx>0) then tw=time((768.5-x)/vx) tn=time((361.5-x)/vx) else tw=time((31.5-x)/vx) tn=time((438.5-x)/vx) end local th=time(tb(y,vy,height,typ)) local t=10000 if ((ts>0) and (ts0) and (tn0) and (twt) then if (t==ts) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vy=vy-g*t xr=x yr=y vxr=0 vyr=0 n=1 collision=0 elseif ((t==tn) or (t==tw)) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vx=-vx vy=vy-g*t collision=1 end else tr=tr+th vxr=vx vyr=vy-g*th xr=x+vx*th yr=yb(y,vy,th) collision=0 end end if (tr<0) then return -1,-1,-1,-1,-1,-1 else return xr,yr,vxr,vyr,tr,n end end function impact(x,y,vx,vy,xpos,ypos,targety,jump,move) local x1,y1,vx1,vy1=0,0,0,0 local x2,y2,vx2,vy2,t2,nn=0,0,0,0,0,0 local xpos1=xpos local ypos1=ypos for t=0,20,0.2 do if (jump==1) then ypos1=yp(tp(ypos)+t) end x1=x+vx*t if (x1<31.5) then x1=2*31.5-x1 end if (x1>368.5) then x1=2*368.5-x1 end y1=yb(y,vy,t) if ((xpos1-x1)^2+(ypos1+19-y1)^2<(31.5+25)^2) then local dx=x1-xpos1 local dy=y1-(ypos1+19) local l=math.sqrt(dx^2+dy^2) vx1=dx/l vy1=dy/l x1=x1+vx1*3 y1=y1+vy1*3 vy1=vy1*13.125 vx1=vx1*13.125 x2,y2,vx2,vy2,t2,nn=estimate(x1,y1,vx1,vy1,targety,2) break end end return x2,y2,x1,y1,vx1,vy1 end function netp() if (math.abs(est-esto)>0.2) then esto=est imp=0 x1=0 for t=27,0,-3 do t1f=t y1f=yp(t1f) t2f=math.floor(tb(y,vy,y1f+h,2)) if (t2f>0) then y2f=yb(y,vy,t2f) vy2f=vy-g*t2f x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/10,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) impt=0 if (t1f<=t2f-2) and (math.abs(posx()-x2f)/4.5400) and (math.abs(posx()-x1f)/4.5imp) and (impt<431.5) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t end if (imp>415) then break end end end end t2=t2+1 end t2=t2-1 move(x1) if (t2<=t1+0.1) and (y1>150) then jump() end end function lob() if (math.abs(est-esto)>0.2) then esto=est imp=0 x1=0 for t=27,0,-3 do t1f=t y1f=yp(t1f) t2f=math.floor(tb(y,vy,y1f+h,2)) if (t2f>0) then y2f=yb(y,vy,t2f) vy2f=vy-g*t2f x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/10,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) impt=0 if (t1f<=t2f-2) then for x1f=pos(x2f)+4.5,pos(x2f)-15*4.5,-4.5 do impf,_=impact(x2f,y2f,vx2f,vy2f,pos(x1f),y1f,220,1,0) if (impf>700) and (math.abs(posx()-x1f)/4.5imp) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t end if (imp>750) then break end end end end t2=t2+1 end t2=t2-1 move(x1) if (t2<=t1+0.1) then jump() end end function attack() h2=900 if (math.abs(est-esto)>0.2) then esto=est imp=0 x1=0 for t=27,0,-3 do t1f=t y1f=yp(t1f) t2f=math.floor(tb(y,vy,y1f+h,2)) if (t2f>0) then y2f=yb(y,vy,t2f) vy2f=vy-g*t2f x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/10,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) impt=0 if (t1f<=t2f-2) then for x1f=pos(x2f)-25*4.5,pos(x2f)+4.5,4.5 do impf,_,xaf,yaf,vxaf,vyaf=impact(x2f,y2f,vx2f,vy2f,pos(x1f),y1f,220,1,0) if (impf>400) and (math.abs(posx()-x1f)/4.5316+7+31.5) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t xa=xat ya=yat vxa=vxat vya=vyat end h2=yb(ya,vya,(400-xa)/vxa) if (h2<316+7+31.5+20) and (h2>316+7+20) then break end end end end t2=t2+1 t2t=t2t+1 end if (imp>400) then t2=t2-1 move(x1) if (t2<=t1+0.1) then jump() end else t2t=t2t-1 move(x1t) if (t2t<=t1t+0.1) then jump() end end end function OnOpponentServe() if (math.abs(pos(posx())-posx())>1) then move(400) else move(200) end valid=1 end function OnServe(ballready) est=700 if (math.abs(pos(posx())-posx())>1) then move(400) else if (math.abs(posx()-180)<2) then jump() else move(180) end end valid=1 end function OnGame() esttold=estt netold=net x,y,vx,vy=ballx(),bally(),bspeedx(),bspeedy() estt,_,_,_,tnet,net=estimate(x,y,vx,vy,220) if (math.abs(esttold-estt)<0.1) then -- Schutz gegen Fehler bei der estimate-Funktion während Netz/Wandkollisionen est=estt end -- phase1 -> Eigener Angriff -- phase2 -> Gegner hat den Ball -- phase3 -> Netzball blocken -- phase4 -> Ball ist nicht mehr gültig if (bally()<144) then valid=0 end if (net==1) then -- klare Netzkollision if (yb(y,vy,(380-x)/vx)>370) then phase=3 else phase=4 end else if (netold==1) then -- Ball hat gerade das Netz getroffen nettime=8 -- Rest des Kollisionsskriptes abarbeiten phase=3 elseif (netold==0) and (nettime>0) then nettime=nettime-1 -- Zeit runterzählen für den Rest des Kollisionsskriptes phase=3 else -- Keine direkte Netzkollision und deren Nachwirkungen if (est>431.5) and (est<460) and (oppx()<700) then -- Ball kommt nahe ans Netz und der Gegner kann blocken phase=3 elseif (est<400-31.5) then -- eigener Angriff phase=1 else -- gegnerischer Angriff phase=2 end end end if (valid==0) then phase=5 end -- Überschreibt alle vorherigen Berechnungen toucho=touch touch=touches() if (touch=tnet) then jump() end if (math.abs(posx()-360)/4.5 nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __PACKET_POOL #define __PACKET_POOL #include "SimpleMutex.h" #include "NetworkTypes.h" #include /** * @brief Manage memory for packet. * * * The PacketPool class as multiple roles : * - Managing memory associated to packets * - Reuse memory of old packet to increase performances. * */ class PacketPool { public: /** * Constructor */ PacketPool(); /** * Destructor */ ~PacketPool(); /** * Get Memory for a packet * @return a Packet object */ Packet* GetPointer( void ); /** * Free Memory for a packet * @param p The packet to free */ void ReleasePointer( Packet *p ); /** * Clear the Packet Pool */ void ClearPool( void ); private: /** * Store packets */ std::stack pool; /** * Exclusive access to the pool */ SimpleMutex poolMutex; #ifdef _DEBUG /** * In debugging stage, stores the number of packet released */ int packetsReleased; #endif }; #endif blobby-1.0/doc/codeconvention/000755 001750 001750 00000000000 12313310254 021167 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/state/LobbyState.cpp000644 001750 001750 00000020053 12313310253 022067 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #include "LobbyState.h" #include #include #include #include "IMGUI.h" #include "NetworkState.h" #include "UserConfig.h" #include "GenericIO.h" LobbyState::LobbyState(ServerInfo info) : mClient(new RakClient(), [](RakClient* client) { client->Disconnect(25); }), mInfo(info), mSelectedPlayer(0) { if (!mClient->Connect(mInfo.hostname, mInfo.port, 0, 0, RAKNET_THREAD_SLEEP_TIME)) throw( std::runtime_error(std::string("Could not connect to server ") + mInfo.hostname) ); mLobbyState = CONNECTING; // send an ENTER_SERVER packet with name and side preference RenderManager::getSingleton().redraw(); /// \todo we need read-only access here! UserConfig config; config.loadFile("config.xml"); PlayerSide side = (PlayerSide)config.getInteger("network_side"); // load player identity if(side == LEFT_PLAYER) { mLocalPlayer = config.loadPlayerIdentity(LEFT_PLAYER, true); } else { mLocalPlayer = config.loadPlayerIdentity(RIGHT_PLAYER, true); } } LobbyState::~LobbyState() { // we should properly disconnect if we do not connect to server! //mClient->Disconnect(50); } void LobbyState::step_impl() { // process packets packet_ptr packet; while (packet = mClient->Receive()) { switch(packet->data[0]) { case ID_CONNECTION_REQUEST_ACCEPTED: { RakNet::BitStream stream; stream.Write((unsigned char)ID_ENTER_SERVER); // Send preferred side stream.Write( mLocalPlayer.getPreferredSide() ); // Send playername char myname[16]; strncpy(myname, mLocalPlayer.getName().c_str(), sizeof(myname)); stream.Write(myname, sizeof(myname)); // send color settings stream.Write(mLocalPlayer.getStaticColor().toInt()); mClient->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0); mLobbyState = CONNECTED; break; } case ID_CONNECTION_ATTEMPT_FAILED: { mLobbyState = CONNECTION_FAILED; break; } case ID_CONNECTION_LOST: case ID_DISCONNECTION_NOTIFICATION: { mLobbyState = DISCONNECTED; break; }; case ID_SERVER_STATUS: { RakNet::BitStream stream = packet->getStream(); auto in = createGenericReader( &stream ); unsigned char t; in->byte(t); std::vector names; std::vector ids; PlayerID own_id = mClient->GetPlayerID( ); in->generic>( names ); in->generic>( ids ); unsigned int games; in->uint32( games ); mInfo.activegames = games; // now add every player as possible opponent, except us mConnectedPlayers.clear(); for(unsigned int i = 0; i < names.size(); ++i) { if(ids[i] != own_id) { mConnectedPlayers.push_back( {names[i], ids[i]} ); } } } break; case ID_CHALLENGE: { RakNet::BitStream stream = packet->getStream(); auto in = createGenericReader( &stream ); unsigned char t; in->byte(t); PlayerID challenger; in->generic( challenger ); // find player with that id auto pl = std::find_if( mConnectedPlayers.begin(), mConnectedPlayers.end(), [challenger](WaitingPlayer& wp) { return wp.id == challenger; } ); mChallenge = pl->displayname; } break; // we ignore these packets. they tell us about remote connections, which we handle manually with ID_SERVER_STATUS packets. case ID_REMOTE_EXISTING_CONNECTION: case ID_REMOTE_DISCONNECTION_NOTIFICATION: case ID_REMOTE_NEW_INCOMING_CONNECTION: // not surprising, but we are not interested in his packet break; default: std::cout << "Unknown packet " << int(packet->data[0]) << " received\n"; } } IMGUI& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doImage(GEN_ID, Vector2(400.0, 300.0), "background"); imgui.doOverlay(GEN_ID, Vector2(0.0, 0.0), Vector2(800.0, 600.0)); imgui.doInactiveMode(false); // server name imgui.doText(GEN_ID, Vector2(400 - 12 * std::strlen(mInfo.name), 20), mInfo.name); // server description if (mLobbyState == CONNECTING ) { imgui.doText(GEN_ID, Vector2( 100, 55 ), TextManager::NET_CONNECTING); } else if (mLobbyState == DISCONNECTED ) { imgui.doText(GEN_ID, Vector2( 100, 55 ), TextManager::NET_DISCONNECT); } else if (mLobbyState == CONNECTION_FAILED ) { imgui.doText(GEN_ID, Vector2( 100, 55 ), TextManager::NET_CON_FAILED); } else { std::string description = mInfo.description; for (unsigned int i = 0; i < description.length(); i += 70) { imgui.doText(GEN_ID, Vector2(25, 55 + i / 70 * 15), description.substr(i, 70), TF_SMALL_FONT); } } // player list std::vector playerlist; if( mLobbyState == CONNECTED ) { playerlist.push_back( TextManager::getSingleton()->getString(TextManager::NET_RANDOM_OPPONENT) ); for (unsigned int i = 0; i < mConnectedPlayers.size(); i++) { playerlist.push_back(mConnectedPlayers[i].displayname ); } } bool doEnterGame = false; if( imgui.doSelectbox(GEN_ID, Vector2(25.0, 90.0), Vector2(375.0, 470.0), playerlist, mSelectedPlayer) == SBA_DBL_CLICK ) { doEnterGame = true; } // info panel imgui.doOverlay(GEN_ID, Vector2(425.0, 90.0), Vector2(775.0, 470.0)); // info panel contents: // * gamespeed imgui.doText(GEN_ID, Vector2(435, 100), TextManager::getSingleton()->getString(TextManager::NET_SPEED) + boost::lexical_cast(int(100.0 / 75.0 * mInfo.gamespeed)) + "%"); // * number of active games imgui.doText(GEN_ID, Vector2(435, 135), TextManager::getSingleton()->getString(TextManager::NET_ACTIVE_GAMES) + boost::lexical_cast(mInfo.activegames) ); // * rulesfile imgui.doText(GEN_ID, Vector2(435, 170), TextManager::getSingleton()->getString(TextManager::NET_RULES_TITLE) ); std::string rulesstring = mInfo.rulestitle + TextManager::getSingleton()->getString(TextManager::NET_RULES_BY) + mInfo.rulesauthor; for (unsigned int i = 0; i < rulesstring.length(); i += 25) { imgui.doText(GEN_ID, Vector2(445, 205 + i / 25 * 15), rulesstring.substr(i, 25), TF_SMALL_FONT); } // * last challenge imgui.doText(GEN_ID, Vector2(435, 245), TextManager::getSingleton()->getString(TextManager::NET_CHALLENGE)); imgui.doText(GEN_ID, Vector2(435, 280), " " + mChallenge); // back button if (imgui.doButton(GEN_ID, Vector2(480, 530), TextManager::LBL_CANCEL)) { switchState( new MainMenuState ); } // ok button if (mLobbyState == CONNECTED && (imgui.doButton(GEN_ID, Vector2(230, 530), TextManager::LBL_OK) || doEnterGame)) { RakNet::BitStream stream; stream.Write((char)ID_CHALLENGE); auto writer = createGenericWriter(&stream); if( mSelectedPlayer != 0 ) { writer->generic( mConnectedPlayers[mSelectedPlayer-1].id ); } else { writer->generic( UNASSIGNED_PLAYER_ID ); } mClient->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0); switchState( new NetworkGameState(mClient) ); } } const char* LobbyState::getStateName() const { return "LobbyState"; } blobby-1.0/src/ReplaySavePoint.cpp000644 001750 001750 00000002443 12313310251 021765 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #include "ReplaySavePoint.h" #include #include "GenericIO.h" const unsigned int REPLAY_STEP_EMPTY = UINT_MAX; USER_SERIALIZER_IMPLEMENTATION_HELPER(ReplaySavePoint) { io.template generic (value.state); io.uint32(value.step); } void ReplaySavePoint::reset() { step = REPLAY_STEP_EMPTY; } bool ReplaySavePoint::isEmpty() const { return step == REPLAY_STEP_EMPTY; } blobby-1.0/src/lua/ldump.c000644 001750 001750 00000006225 12313310253 020246 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: ldump.c,v 2.17.1.1 2013/04/12 18:48:47 roberto Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ #include #define ldump_c #define LUA_CORE #include "lua.h" #include "lobject.h" #include "lstate.h" #include "lundump.h" typedef struct { lua_State* L; lua_Writer writer; void* data; int strip; int status; } DumpState; #define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) #define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) static void DumpBlock(const void* b, size_t size, DumpState* D) { if (D->status==0) { lua_unlock(D->L); D->status=(*D->writer)(D->L,b,size,D->data); lua_lock(D->L); } } static void DumpChar(int y, DumpState* D) { char x=(char)y; DumpVar(x,D); } static void DumpInt(int x, DumpState* D) { DumpVar(x,D); } static void DumpNumber(lua_Number x, DumpState* D) { DumpVar(x,D); } static void DumpVector(const void* b, int n, size_t size, DumpState* D) { DumpInt(n,D); DumpMem(b,n,size,D); } static void DumpString(const TString* s, DumpState* D) { if (s==NULL) { size_t size=0; DumpVar(size,D); } else { size_t size=s->tsv.len+1; /* include trailing '\0' */ DumpVar(size,D); DumpBlock(getstr(s),size*sizeof(char),D); } } #define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) static void DumpFunction(const Proto* f, DumpState* D); static void DumpConstants(const Proto* f, DumpState* D) { int i,n=f->sizek; DumpInt(n,D); for (i=0; ik[i]; DumpChar(ttypenv(o),D); switch (ttypenv(o)) { case LUA_TNIL: break; case LUA_TBOOLEAN: DumpChar(bvalue(o),D); break; case LUA_TNUMBER: DumpNumber(nvalue(o),D); break; case LUA_TSTRING: DumpString(rawtsvalue(o),D); break; default: lua_assert(0); } } n=f->sizep; DumpInt(n,D); for (i=0; ip[i],D); } static void DumpUpvalues(const Proto* f, DumpState* D) { int i,n=f->sizeupvalues; DumpInt(n,D); for (i=0; iupvalues[i].instack,D); DumpChar(f->upvalues[i].idx,D); } } static void DumpDebug(const Proto* f, DumpState* D) { int i,n; DumpString((D->strip) ? NULL : f->source,D); n= (D->strip) ? 0 : f->sizelineinfo; DumpVector(f->lineinfo,n,sizeof(int),D); n= (D->strip) ? 0 : f->sizelocvars; DumpInt(n,D); for (i=0; ilocvars[i].varname,D); DumpInt(f->locvars[i].startpc,D); DumpInt(f->locvars[i].endpc,D); } n= (D->strip) ? 0 : f->sizeupvalues; DumpInt(n,D); for (i=0; iupvalues[i].name,D); } static void DumpFunction(const Proto* f, DumpState* D) { DumpInt(f->linedefined,D); DumpInt(f->lastlinedefined,D); DumpChar(f->numparams,D); DumpChar(f->is_vararg,D); DumpChar(f->maxstacksize,D); DumpCode(f,D); DumpConstants(f,D); DumpUpvalues(f,D); DumpDebug(f,D); } static void DumpHeader(DumpState* D) { lu_byte h[LUAC_HEADERSIZE]; luaU_header(h); DumpBlock(h,LUAC_HEADERSIZE,D); } /* ** dump Lua function as precompiled chunk */ int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) { DumpState D; D.L=L; D.writer=w; D.data=data; D.strip=strip; D.status=0; DumpHeader(&D); DumpFunction(f,&D); return D.status; } blobby-1.0/src/raknet/BitStream.h000644 001750 001750 00000043643 12313310247 021537 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief RakNet::BitStream: packet encoding and decoding * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __BITSTREAM_H #define __BITSTREAM_H #include "../BlobbyDebug.h" // Arbitrary size, just picking something likely to be larger than most packets #define BITSTREAM_STACK_ALLOCATION_SIZE 256 /** * @brief This namespace only contains a few utility class used in * RakNet. * * RakNet namespace is the not really in use currently. */ /** \note If you want the default network byte stream to be in Network Byte Order (Big Endian) then #define __BITSTREAM_BIG_END otherwise the default is 'Little Endian'. If your CPU has the same Byte Order as your network stream, you can cut out some overheads using #define __BITSTREAM_NATIVE_END --- if this is defined, the __BITSTREAM_BIG_END flag becomes ineffective. */ namespace RakNet { /** * This macro transform a bit in byte * @param x Transform a bit to a byte */ #define BITS_TO_BYTES(x) (((x)+7)>>3) /** * @brief Packets encoding and decoding facilities * * Helper class to encode and decode packets. * */ class BitStream : public ObjectCounter { public: /** * Default Constructor */ BitStream(); /** * Preallocate some memory for the construction of the packet * @param initialBytesToAllocate the amount of byte to pre-allocate. */ BitStream( int initialBytesToAllocate ); /** * Initialize the BitStream object using data from the network. * Set _copyData to true if you want to make an internal copy of * the data you are passing. You can then Write and do all other * operations Set it to false if you want to just use a pointer to * the data you are passing, in order to save memory and speed. * You should only then do read operations. * @param _data An array of bytes. * @param lengthInBytes Size of the @em _data. * @param _copyData Does a copy of the input data. */ BitStream( char* _data, unsigned int lengthInBytes, bool _copyData ); /** * Destructor */ ~BitStream(); /** * Reset the bitstream for reuse */ void Reset( void ); /** * Write the native types to the end of the buffer * without any compression mecanism. * @param input The data */ void Write( const bool input ); /** * Write the native types to the end of the buffer * without any compression mecanism. * @param input The data */ void Write( const unsigned char input ); /** * Write the native types to the end of the buffer * without any compression mecanism. * @param input The data */ void Write( const char input ); /** * Write the native types to the end of the buffer * without any compression mecanism. * @param input The data */ void Write( const unsigned short input ); /** * Write the native types to the end of the buffer * without any compression mecanism. * @param input The data */ void Write( const short input ); /** * Write the native types to the end of the buffer * without any compression mecanism. * @param input The data */ void Write( const unsigned int input ); /** * Write the native types to the end of the buffer * without any compression mecanism. * @param input The data */ void Write( const int input ); /** * Write the native types to the end of the buffer * without any compression mecanism. * @param input The data */ void Write( const float input ); /** * Write the native types to the end of the buffer * without any compression mecanism. * @param input The data */ void Write( const double input ); /** * Write an array or casted stream. It is supossed to * be raw data. It is also not possible to deal with endian problem * @param input a byte buffer * @param numberOfBytes the size of the byte buffer */ void Write( const char* input, const int numberOfBytes ); /** * Write the native types with simple compression. * Best used with negatives and positives close to 0 * @param input The data. */ void WriteCompressed( const unsigned char input ); /** * Write the native types with simple compression. * Best used with negatives and positives close to 0 * @param input The data. */ void WriteCompressed( const char input ); /** * Write the native types with simple compression. * Best used with negatives and positives close to 0 * @param input The data. */ void WriteCompressed( const unsigned short input ); /** * Write the native types with simple compression. * Best used with negatives and positives close to 0 * @param input The data. */ void WriteCompressed( const short input ); /** * Write the native types with simple compression. * Best used with negatives and positives close to 0 * @param input The data. */ void WriteCompressed( const unsigned int input ); /** * Write the native types with simple compression. * Best used with negatives and positives close to 0 * @param input The data. */ void WriteCompressed( const int input ); /** * Read the native types from the front of the buffer * @param output The readed value. * @return true on success false otherwise. The result of a reading * can only be wrong in the case we reach the end of the BitStream * with some missing bits. */ bool Read( bool &output ); /** * Read the native types from the front of the buffer * @param output The readed value. * @return true on success false otherwise. The result of a reading * can only be wrong in the case we reach the end of the BitStream * with some missing bits. */ bool Read( unsigned char &output ); /** * Read the native types from the front of the buffer * @param output The readed value. * @return true on success false otherwise. The result of a reading * can only be wrong in the case we reach the end of the BitStream * with some missing bits. */ bool Read( char &output ); /** * Read the native types from the front of the buffer * @param output The readed value. * @return true on success false otherwise. The result of a reading * can only be wrong in the case we reach the end of the BitStream * with some missing bits. */ bool Read( unsigned short &output ); /** * Read the native types from the front of the buffer * @param output The readed value. * @return true on success false otherwise. The result of a reading * can only be wrong in the case we reach the end of the BitStream * with some missing bits. */ bool Read( short &output ); /** * Read the native types from the front of the buffer * @param output The readed value. * @return true on success false otherwise. The result of a reading * can only be wrong in the case we reach the end of the BitStream * with some missing bits. */ bool Read( unsigned int &output ); /** * Read the native types from the front of the buffer * @param output The readed value. * @return true on success false otherwise. The result of a reading * can only be wrong in the case we reach the end of the BitStream * with some missing bits. */ bool Read( int &output ); /** * Read the native types from the front of the buffer * @param output The readed value. * @return true on success false otherwise. The result of a reading * can only be wrong in the case we reach the end of the BitStream * with some missing bits. */ bool Read( float &output ); /** * Read the native types from the front of the buffer * @param output The readed value. * @return true on success false otherwise. The result of a reading * can only be wrong in the case we reach the end of the BitStream * with some missing bits. */ bool Read( double &output ); /** * Read an array or casted stream of byte. The array * is raw data. There is no automatic conversion on * big endian arch * @param output The result byte array. It should be larger than @em numberOfBytes. * @param numberOfBytes The number of byte to read * @return true on success false if there is some missing bytes. */ bool Read( char* output, const int numberOfBytes ); /** * Read the types you wrote with WriteCompressed * @param output The read value * @return true on success, false on not enough data to read */ bool ReadCompressed( unsigned char & output ); /** * Read the types you wrote with WriteCompressed * @param output The read value * @return true on success, false on not enough data to read */ bool ReadCompressed( char &output ); /** * Read the types you wrote with WriteCompressed * @param output The read value * @return true on success, false on not enough data to read */ bool ReadCompressed( unsigned short &output ); /** * Read the types you wrote with WriteCompressed * @param output The read value * @return true on success, false on not enough data to read */ bool ReadCompressed( short &output ); /** * Read the types you wrote with WriteCompressed * @param output The read value * @return true on success, false on not enough data to read */ bool ReadCompressed( unsigned int &output ); /** * Read the types you wrote with WriteCompressed * @param output The read value * @return true on success, false on not enough data to read */ bool ReadCompressed( int &output ); /** * Sets the read pointer back to the beginning of your data. */ void ResetReadPointer( void ); /** * Sets the write pointer back to the beginning of your data. */ void ResetWritePointer( void ); /** * This is good to call when you are done with the stream to make * sure you didn't leave any data left over void */ void AssertStreamEmpty( void ); /** * print to the standard output the state of the stream bit by bit */ void PrintBits( void ) const; /** * Ignore data we don't intend to read * @param numberOfBits The number of bits to ignore */ void IgnoreBits( const int numberOfBits ); /** * Ignore data we don't intend to read * @param numberOfBytes The number of bytes to ignore */ void IgnoreBytes( const int numberOfBytes ); /** * Move the write pointer to a position on the array. * @param offset the offset from the start of the array. * @attention * Dangerous if you don't know what you are doing! * */ void SetWriteOffset( const int offset ); /** * Returns the length in bits of the stream */ int GetNumberOfBitsUsed( void ) const; /** * Returns the length in bytes of the stream */ int GetNumberOfBytesUsed( void ) const; /** * Returns the number of bits into the stream that we have read */ int GetReadOffset( void ) const; /** * Returns the number of bits left in the stream that haven't been read */ int GetNumberOfUnreadBits( void ) const; /** * Makes a copy of the internal data for you Data will point to * the stream. Returns the length in bits of the stream. Partial * bytes are left aligned * @param _data the resulting byte copy of the internal state. */ int CopyData( unsigned char** _data ) const; /** * Set the stream to some initial data. For internal use * Partial bytes are left aligned * @param input The data * @param numberOfBits the number of bits set in the data buffer */ void SetData( const unsigned char* input, const int numberOfBits ); /** * Exposes the internal data. * Partial bytes are left aligned. * @return A pointer to the internal state */ unsigned char* GetData( void ) const; /** * Write numberToWrite bits from the input source Right aligned * data means in the case of a partial byte, the bits are aligned * from the right (bit 0) rather than the left (as in the normal * internal representation) You would set this to true when * writing user data, and false when copying bitstream data, such * as writing one bitstream to another * @param input The data * @param numberOfBitsToWrite The number of bits to write * @param rightAlignedBits if true data will be right aligned */ void WriteBits( const unsigned char* input, int numberOfBitsToWrite, const bool rightAlignedBits = true ); /** * Align the bitstream to the byte boundary and then write the * specified number of bits. This is faster than WriteBits but * wastes the bits to do the alignment and requires you to call * ReadAlignedBits at the corresponding read position. * @param input The data * @param numberOfBytesToWrite The size of data. */ void WriteAlignedBytes( const unsigned char* input, const int numberOfBytesToWrite ); /** * Read bits, starting at the next aligned bits. Note that the * modulus 8 starting offset of the sequence must be the same as * was used with WriteBits. This will be a problem with packet * coalescence unless you byte align the coalesced packets. * @param output The byte array larger than @em numberOfBytesToRead * @param numberOfBytesToRead The number of byte to read from the internal state * @return true if there is enough byte. */ bool ReadAlignedBytes( unsigned char* output, const int numberOfBytesToRead ); /** * Align the next write and/or read to a byte boundary. This can * be used to 'waste' bits to byte align for efficiency reasons It * can also be used to force coalesced bitstreams to start on byte * boundaries so so WriteAlignedBits and ReadAlignedBits both * calculate the same offset when aligning. */ void AlignWriteToByteBoundary( void ); /** * Align the next write and/or read to a byte boundary. This can * be used to 'waste' bits to byte align for efficiency reasons It * can also be used to force coalesced bitstreams to start on byte * boundaries so so WriteAlignedBits and ReadAlignedBits both * calculate the same offset when aligning. */ void AlignReadToByteBoundary( void ); /** * Read numberOfBitsToRead bits to the output source * alignBitsToRight should be set to true to convert internal * bitstream data to userdata It should be false if you used * WriteBits with rightAlignedBits false * @param output The resulting bits array * @param numberOfBitsToRead The number of bits to read * @param alignsBitsToRight if true bits will be right aligned. * @return true if there is enough bits to read */ bool ReadBits( unsigned char* output, int numberOfBitsToRead, const bool alignBitsToRight = true ); /** * --- Low level functions --- * These are for when you want to deal * with bits and don't care about type checking * Write a 0 */ void Write0( void ); /** * --- Low level functions --- * These are for when you want to deal * with bits and don't care about type checking * Write a 1 */ void Write1( void ); /** * --- Low level functions --- * These are for when you want to deal * with bits and don't care about type checking * Reads 1 bit and returns true if that bit is 1 and false if it is 0 */ bool ReadBit( void ); /** * If we used the constructor version with copy data off, this * makes sure it is set to on and the data pointed to is copied. */ void AssertCopyData( void ); /** * Use this if you pass a pointer copy to the constructor * (_copyData==false) and want to overallocate to prevent * reallocation */ void SetNumberOfBitsAllocated( const unsigned int lengthInBits ); private: /** * Assume the input source points to a native type, compress and write it. */ void WriteCompressed( const unsigned char* input, const int size, const bool unsignedData ); /** * Assume the input source points to a compressed native type. * Decompress and read it. */ bool ReadCompressed( unsigned char* output, const int size, const bool unsignedData ); /** * Reallocates (if necessary) in preparation of writing * numberOfBitsToWrite */ void AddBitsAndReallocate( const int numberOfBitsToWrite ); /** * Number of bits currently used */ int numberOfBitsUsed; /** * Number of bits currently allocated */ int numberOfBitsAllocated; /** * Current readOffset */ int readOffset; /** * array of byte storing the data. Points to stackData or if is bigger than that then is allocated */ unsigned char *data; /** * true if the internal buffer is copy of the data passed to the * constructor */ bool copyData; unsigned char stackData[BITSTREAM_STACK_ALLOCATION_SIZE]; }; } #endif blobby-1.0/data/gfx/font30.bmp000644 001750 001750 00000003370 12313310254 020716 0ustar00danielknobedanielknobe000000 000000 BM6( #%h )- s0 v&&n**H C"tA) "1144p,,$ KL!yF; 77;;55U'' z<>YZ%&\D( ?DDBB77'+ggSS##bF  >>CCEEBNOkkHH)) y:XHHHHe11 ;$$vvXX>>55))55k!!+GGJJv;;8$$ff^^;;..#k66eeLL--''""::CC~>>T22 W22gg77\N22wwppNNBBPPQQKK^88-  ]]AA>((ooeedd\\rFFH33 ~??PP  )ό}}nnTTY==#:""aa((M+ ֛勋pplKK:..WWJJ >⼼鼼YOOT//``$$! ppĥrdd411 aaGG%%BֿTNN LLkk77v,, $!!ʹʷ~vv$""7$$ttcc>>4QLLٱDAAjjjjMM}xxA//蝝𔔿jj:%%533qnn䕕jHH~~~~A77}}mUU mkkUUU blobby-1.0/data/gfx/pokal.bmp000644 001750 001750 00000423566 12313310254 020730 0ustar00danielknobedanielknobe000000 000000 BMv'6(h@'  ̬ܶĥ侼ĥ侼ܶܶv|̬̬ܶܶĥ侼ĥܶĥԮ̬v|侼侼ԲĴ̬ĞԮܶĥ侼Ĕv|ԮԼԲ侼ܴ̔v|ԲԲ༞ĥĥ侼ܤ|rt̬侼Ԯ̬̤ĥܶܶ侼̬̬ĥԲܶԲĥ̬Ĭചܶ侼̬ĥܶܶ侼̬ܶܶܶԲԲԲ侼ĥ侼ܶԲ̬侼ԲԲĥܶܶ侼侼ܶԲԲܶԲĥ̤̬Ąv|ܶԲ줊\VTԲܶԲܼ侼ܶ侼侼Բ侼Բ̬ܴ̬ԮԮĥ侼侼켞̴ܶܶԲԲ侼侼ܔԲĥ̬ĥ侼侼侼ܶԲĥ侼̬̬ĥܶܶ侼ĥ侼̬ܶܶܶܶ侼侼侼侼ĤԲ̬ԲԲ侼ļ̬Բĥ̼̬̬ܶܶܶܶܶ侼ܶԲ̼ܶܶĥ̬ܶܶĥļ侼侼v|ĥܶĥܶ侼侼̬ܶv|ԮĄv|ܶ侼̔ܶ侼ļܶܶĥ侼̬ܶܶĤ侼ܶ쬔ԲԲԮ̬̬ĥԮĴ侼̬侼ԲԲԲ侼ĥĞܶĥĥ̬侼侼ܶԮԲ侼ĥ̬ܶܶԮ侼ĥ侼ĥĄv|̬̜ܶܶԲԲĴ侼ܼԮ̬侼Ԯܶܶܶ侼ܶԮܶ侼̬ܶ侼侼侼侼侼侼侼侼侼侼侼ԮԲԮԲĥԮܶ侼ܶԮܶĥ侼Բ~T|rt|rt|rtLTZ\4VTTnl|rtTnl|rtTnl|rt~TnlTnl|rt|rt~~̬ĥ̬̬侼侼ܶܶܶ侼侼ܶԮܶԲ~|rt~|rtTnlTnlTnlTnlTnlL~~TTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnl|rtTnl|rt~~|rtĞԮ侼侼侼侼ĞĥԮĞĞ|rttjlTnlTnlTnlTnlTTTTTTTTTTTTTTLLLTnlLTnl4v|TnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlTnlLtjlLTnlLLL4v|Tnl4v|,fl$Z\$JL$JLd^\ĥԲ侼ܶ侼侼侼ԮĥĞĥԮԮܶ|rtTnlTnlLLTTTTTTTTT\TTTT$$$$~|vtvtlq bd bd bdZ\ VT VTZ\ OO OOZ\Z\Z\Z\Z\,fl,flTnlLTTTTTLLLTLLTL4v|NL <<$&$<:<\VTlbdԮԮ侼侼Ԯ侼ĥĞЌTnlLLTTTT$$,,,,,,,$,$$$$$~|~|vtlqcelqZ\Z\ VT OORT FD OO FD FD FD OO OO OOZ\,fl,fllq,flbd$rtlq4v|4v|LTTTTTce$JL$&$$&$$&$$&$,.,DBDd^\ĥܶ\VTܶĥԮ侼侼|rtL4v|$$$,,,,$,,,,,,,,$$$$$~|~|vtvtce bd bdZ\Z\ VT VT FDRT FD OO FD OOZ\,fl4v|L4v|$fd bd^\ce bd bd bd bdlq~|~|TLRT$&$$&$$&$$&$,.,,.,$&$$&$<:<\VTv|ܶ侼ܶ侼Ԯܶ侼ԲTnlcelq~|$$$$,,,,,,,,,,,,,,,,$$$$~|~|vtvtlqce^\ VTZ\ OORT OO OO FDRTRTZ\,flLTL$rtZ\ bd^\ bdlqcelqlqlqlqlq4v|$fd$&$$&$$&$,.,,.,,.,,.,,.,,.,$&$$&$<: ?-  L;rM*.t  /tW@w6 <& #6&5!TENCC l 8|V/G=|1G( @XW%#V_1X;LX(6 [, Pvve>M[?YD^Z C 07_fTX)0#J,Jr`cCPT  jlKF#j( 9 $&  w|HI*/4#DfMWf@OJpo>8"# +4,lm?>577U=S>kh83  MqMfe=;3s5=\B}a]C@;;3H4xv^[_^|yWU?=6L7XoXnk*&  مpmHF6X7~}@<[[]\;a;]\VR -2,ЉutGjF0;0nl(#~|NJTmU nm>Iblobby-1.0/data/gfx/abbruchbild.bmp000644 001750 001750 00000403730 12313310254 022052 0ustar00danielknobedanielknobe000000 000000 BM6(,! JHJ[KTf>JI9=T@d46i9;f&(u23V""JY++B&&T22nBB =**D66 )4#!:&# [>:fFBeJFnRN~^ZvZVfb~b^njjfvrzv~zL2.E.*V:5pZVzb^t^ZrnzvgVS~z~nkl_]?*&R72lNHvVOZC>S>:M:6YFByurnɻN60^B;bE>hJC.!~^V^F@z\UE40f^iPJe^mfunhSNTC?~f`_NJ~3+)vqtc_|jf<42KCAóZ>6rTL9*&nRJJ72vZRbZ_JDjbnWQrjngzaSOugczr~vL?;zgaJ2*dNFv^V<0,ybZjbvnrjzVJFg[Wnf~vo^VWPMWC9D<8B@?<97jF&^I71/-+*([ZXTE$wb.SM<;5#~rN bT540^X;sj;_\KFA!FC.ifEOM0YX+vv$$#JN fjR[e3:>*TXCYi5>o;]x.=I(-3"CI8E^ET06I L\:WiEV!HPACu7bB`1*HQ98D3/=*X<(>"#. 4"?14Y--z )g!(Y!5m./L+8,9R6%M"9@`> "EAVIzgFbZ+1'06,4;19C6>G333,33,,,+3,03,33-03-330-03,3,3-0-3+0,-,033300-303330-,00-3+0,3030-`3300,-,33-303-33+03-003,-,3333303`300,303+0,33300333330+3-3+3333,-00333,3--0333330-0-,,3+0,`,30-,333,3--3+0,30030-300---333,3-30,-3,33-3033330303`,0033,+3333,30,`3,33-`333`,30-+3330-0--,-33-30|@-33.B/|k||VkXm|./mkzQ./B.W).//kUdzWkWX|3/WWXW`QW`zIIV/.dBzk|-0WjW||`-VVzBXW3XX.|B-/|.-.dVVB.kIW.-/mkVmOXBzzQ|k|d/-.zdW|BQVd/VVWkXkVmmB`d/dmddV|`Bmm/`zQ-.Q.BVdBWVkmd`.k|`.--z-B/`./XmWBVXmW3.ddkd.B3.mmX|..|dQXV`0VVVk/zm||V-3mX.|B-/|.-.dVVB/k|.-/IXImmdB)/dVddd.BdVkkWdWBkWdWkWWXjm/-B.QXdBV|`Q).BB`/d/|VWXmIVQBX)Bz/)`WOdQddmVdXk|X|3.|dkd-.B3.mIXBBkOqVWmX`(,`,WXkB1SSceS\\xS:yQBxu<{y_b_y}}}LS._g1\inT^ni6__~_xARC2g6~8cTBhT6~inhTT_x}he6yx]a{}h_T}2S^^c{^{c~:yQ1]Sa_S6h}2:rn62S{{c8h}1x2}~R1{nnnS~^]=yceh:xC6g1R_Th>a^1A]:n~x^y~r_6h{yyS^22~{x~~6rnS2eechceeR^6ch1RcT.B_:aCC1A}8}8TSiC-_SAQgLh2A=SSScny6<}R{_B/.RSg{xh]{T]A\\B]_AQB2\^6S]CR~u2C_}Ti8~=S]{giS{g_~<_R~Liccc[6]ccTha_<~MnS2eech}g8C^TT1\6~C\1}81^xBS{c=}RS_AB/.x}h}^i_c~_^12^Ryc^Cxc_}iSnh1n{S=M_\]{{~:gg~{A^ygr~8~6_i}TW-2/aST62c~__^2egehyR],.g]1aSA8r:}yC^i8~yQ`C]Si{_uST_.S}xy2}RBwy~T^g~2CQ2_Sy\^nh]}cTun]h{,-:L}`ChSC]_in}_{/1c2RR`\c]BS}1y}^]x1c~gh{R^,`{\Ay]Qc~{S]S>L:}/1]Sh21=1_x`{6]yT2`/1yQ/6uy]_Lg1~ac>}C}_]}CQhS~T^g>h}_S{{Sx81yg81yc-.<>e_T`B]AS1QTe8STr:gyQ`Rx22]L]_1.c}8hcunR_yQ./2i^2C^Ji_^<]x_\QxCB]:=r<1,,B_xT:B,xcCCc1h2B/2SAQ,,^rA,C9A^cy{ngx26c^AQ2=<}{cT~i}\Q<~c2^Lh8{x<{rS,,hn\,28S}TSgcRRT}^1ynLi2xih1xR1ihhSQ]yhe2^8AA]Q`\69xC_nnu2-,B2r\_gc::B,16R{x:rS\BSTCA-,y_/{i^}u>cyScR1TSCQ`Rhhy{cTa:eCA8661x~SR2eghMiR1}1\]1_8a}~R\c6^CS^y>]crnh{S6L8T\TxQ]gc^huac6hg]i2]]_SChcaRC8:}^gC/\x^8chiaS]rRc]{]B^6hR{>8{u~B2:-1>6:yy=hCC{T]Agy}B}n8y1{:hiy}:y2ccgx.88{y_S2]hre~n1ST^yTA/B6BBcu2_~_\6R.xSTBT_ARCB6g2c-Ch_\]hg^6wwLeR__2_T5cTA^8S_6gS1SSR_c:nc 2Sxci2Ty{M^T{iMSA8yy_S2CW-giC_>_,Qn:.,6ngihR}hae9Lcxc2B]T21S6]A.B:{8ySS\]S]c6{hh_T1Rgx,/~:{{^\^}Syg1_^QC,.i2R_^S/AiSraRyygxR{^}g1]a9ayARSn:^}T}}C{g1Rc62}i}g//1~Lnx-x^ynaxgn,^:hcR-]~<:B^R_T\Ry8gcR`\Cy_c}c~^}2Rc62}n_:6..Cc]`^c:yrn]Qc8yAB~i].T6./_\-QQB{T]2i}R{TRRxSucu~2y~<:1cnhhgAcc]2AB2CST\Ry~6T1 ky7xyg^RcgS~Lh{ic/Q]6MM].]SVF]2:RQR,{hT~_B`A:CQ,,C~y~ngx}]2~Th_SCQA8i}S2ah}L]x}rc,`~hx{8Cchy1A.RcyS]]~ya1-_nn2cy5ghM]i]y__2BA`_8:{c_1u_/S6hy\/Ci^RQ,,C6{yyCT<:RxyT{y1R:6T_~>6S~R-ygB.a8n~g2\}h:8]y{{r>:uw_]c=nS,,26yBC{B_T1\B`y_^i=1R_x^B,4c]iun~chLiuL\^n_6cCC`^}y_R~CAyhy8<^BQB^~iL}Q]:yC2i6neCC=c^_e~A^1BT~^C{y}hhL:1\BQ_~8n_Th:x.S=iy2~r]-}y]{xQCS8Lu^S_h.c/Ah1Ryg{i]B:_;E?vvvvs5{kt^egR_^}82R^2_eg8neRRABSghuSzwL_{S2C\_i>icR{_R{6}~cc{..{}>^gT^M}h>hhinT>TSn~6xRg~MhneSS2`{hC_6A.2~yxCgwi\6r_aihL~~}<{Cg~ir}~ha:h{{2`{wCS~\/_gT1C~gB_ggB`]}]C2{\R_y6]yc:]/_BBaSx^~1`C^8~Sc2}ghrgTygu::rn8y=.,8n^_TRQB2]B]hx_eTc:}/1gc}h}1^AS=T6iS`2M8Q8x/{{a{2}TiTAccScQ`.Rniy]S{c~2c6_6gS2~{xy}>Sx_8_Q^Sec_LyC}^QC2^c~gSM8y=c_TMe6gnMng{.,h:2{cCBA_]B]hC_e}a:g_.R6Tyg{CCQ^:~STegcx.Su:BB6nx/{{~y^}y:yIv̧v}:S{hc^Tc>y^S8^.1_~T]hSR~_B1y .t]Tuc^yngc66a/r-Y~:h:_x]2:uc~^C_Bch^_^B_^xi:2_~].AQQgh}A/\2h^\_A/yT4cxxTycyB/Qx6TnSwi/xxc~2y}xB{cC}L=_y=g{~}nhg8T1T~Sc~e~}SgT/]u{12_RhgM>C]yi6Cy:a1^}2..}:i>C/x}gh_CCC8hS]{Aah^_LSCy:1R:h2xyx.AQQgCBCSi{1c_Rhg{~BB2^S^Q//]8{_6~{x{iT]{c~c_x{_/2SACh_RhgrR]{cWvvDMihiy]y\gi_{_R{xg]^c1.\B _RQ}c{6BB]12x`-BTS>Sw/Q^hg]BB_^^R-\}SC,/y/Rh{26gT~yR^c_^h7aT{ih^Tnh\R_:SC:S,B8>x-]<]1{B/cie~{_Byy//]8vv~]^aA.g=8Luy}yQTS^hT_\`cn61__._y6Q5mvLM1SSQA{c8ihS~cRRACahC1\F:urcx_eT]^=r_R6C,/RAQ.SsxcR~=}eh2T~n8{~2Cg}TeS{T211]RcaA/Q\TMnTT2`^]/cnhx/T=MwM^{_:>T\R2{BR}SaMn6~6=eih=6Rgu=SA^eice6]_RQ6Q\>uueyccTQTh8~caT..yh:{R\R\~yMyBR}1n}~TR]{iCA{~_Bxgng~ySy]\AAcaA/xaMnTy^/{S\ri^QyL[u_}M{n{Ax^/ByyerhhhL:=T\~u>1QQx~:y6c]_RQ[c/=hM:c}Sh_/Tih~cTmiCC}SR^h~6y_y]RA\RgM8RQ1x/6]Q{n>C]{9y-Bh~2~7shTgnhB.}gA^>86cg{_i{RI_._ygne/`\g~Q]}]]<{^S_^:]/3wB:}2]ih1:n2ygTin8yB,{}-\ML:hhSAa6a:hc_2hMrL2A-x6hT2RQcng2~_._rhgB/RAQ^TcSy~icSg<=g}]B_e~e]CM2i:y}hR_>SQ:6S_eAchR]ThM=yB,{g/]:~~}SAa688T_:Mu{C-`^8i}_\QaMiTTQyL~cec~AB^xA{gc~nuT8{B_9iBQBR1Sh~RR6hha}~8yR`R<{Sx:}:~Sg\/}_1ya}{cxB]]cg2_h2={Tx{gSS_=KR.xcc6~^,S_wQQS_c=hhi{~M>Lecvvyy^Mx,}{2ShLc{i6CRRtT{cgS\-AhSS]\i}:~x}\/}21T~TB3uLRg_{a_rL_]A`R~2\]c]cg86R\T8A_RM2\QQC]S]%`R\QC~nn^xT]Rx_1_BB>nh~]/QBS_S::n~SS/ATQ,SixRgMS\c_.c8]^cSB/}~C9eBAR^S2~n]A1}x_}x~S{cC1c}xRRA2}QSg]hy}MgSL]xB`_~S}^w~_gh:h]]8]}^T]BRC]S2B`/11B]hL2xT2Rx_1_8B\rn2`./]1^=rh}y/R6A`{R\~gL{C}xQ`Tr~Cxgh~T_B`_yR~hC]^Tc{hMxBxTC2V5x[g_g::11g<]}^=}2R|.tCQ1n]Cy]\]S^{hRC6x`./]1^hX,?Z\:Tx:hS]AThSB2_BBycyS181acRB6ga2Tin>_C~R`hSS^i2RA{1,B{^~<^~rTRgTiigTxRTBA21g_CAT-\{^S8RRg{C:TS2Ci~1y_BgaT1Shi1BT,6<_yyLy1_R,/S^m=_hiSS:cxQc2.~c~6)S{ASh_a>_{S2T}>],2:T\AT-AQ3H/STR]1B]Ty6~{26RSCThBRa_B]6hBBi8A}u8SB^{\_hn:]^T2xSaRyg:^>{,/1_T8g]\^BAC.RT]Sy}\2yB_iMwMB,y:]A.xciuwi16}/TiCSc>ng}C~gxy2}]1i8gS8TS:h8STgcS}yBT~1S_2}T~~6cn{8{c\xgyR_h=xCL=]h}A^:SA__SecSygxc6gxB8},\{ci{Ci>A`.B`Rhy]=_y6\]SQ2}-AygiTgn{^au:x]1xxc<}~y_h~iSI k{hi{xh^`gihx,^MX3^xSSxT8RRRBS\_T^hn>e}{2{.22Q/~>}~{Sg2RA/^nT]e^R^__{gnQQc~g^,,B1\R~TQ}iA/`2nM]B1RBCce\8n2B]hMgxx2~2{x:SR:Lca}iSBch_S_R}6_hiT}>RQ}~_Ac:Byc2]6;S^TT1{~ARRSR{gcr:aTS}RBy{RBhL8ig~i{xBB`x{1h_1{T2yhBA{T}x,,Q_^_ihR8\/`x:`B.-.1i6\:}xy^xghi:A{Tc2niS{gS]x}yB{n{Lr:_TcxQyh~i2Ay\Bh}-R~{{T6S{a2i]/.R2R^i>y_y]CQ,xi:cy{_\`-SayMxSi=:2/_^\^xccA1:g~chcRR_^2}:gahvTiy{yR/S8cg:rS]mUSy^2iS/_=_B1_C_hh^]SxCQ,xm,x{B_u}__QxTA8~A/ChLiyy{\,A6~M<~B~gyc2Ch}T~e8h}_=hLSA]ST6{C_81_=gnM:8~gTy~n~.Ah1hRTyA1]TSx}cruh{yyRcaRScinTC{r8xgcScyCc{^}RB8~^}\^rn> *E__y}c~8{^<>hrc^2_ST_\^6\xX3?H_TRxwrn_^cy8B~h:cA_8MA`R1yu^g=2r_By8iy2e~6nMr8CAxy~~S]S\:gS>hinrh]]S,`:BCT~CC]}S_S16c{uihSh>CQQxig`y]Bi{Txgg/Ag6cS]{ySS2ScCCM>^xgTSg6Q.T~g}RyMr:B,RSLigr2=e>hSr2B{6hySg6yir~6\AC_}c2x:]Ah~2c8y}{\1y/QiQ\yQciCBRCS^S2A_2x6yT1<2RR_i},h2gu>n/,CSMi$F1/2cg2CTTTu:^\CS}c2x<{C8|3JQ.{yyih2}8_BA8{Cgy{neTi<}AQA1Th~6{Q5BQTTgi}BQ2y`BCBQ2~c8n:~~cg_{CAcg_=w>1Q-1`}L6]1QyhyRCyR18~}]S=hc}_2TT}_1My/_SReg1~Laxch/QcS_8_/1e1he/`Syyh]y~^i/Qc^R~TRTL:Th:SQ.B]cTS6S62QyBQ}T>}B`C],QRQ/1a6TSThi8T~}B{g2{RyyA6eQ/`S/Tnc1]Q_<~_A2_h~_BCe}2^Rxyge}SLSQ]_<^8={e_Q.BR{hg6h}!`ES.`Ch],/\Q/1c8a}g8T681{_-N]2.-xhiS\88y]y}`^:22C2M:Thn:]Q]8h^B]AQTa:r6/B}6S_^S]yiy~L:Axi_\xSyx~2SMc~e~Q/~ha}2AQ-`h=RCy^h^2e~RR22{nn~ig}L~1a~A]7xynaB~gg}y_^yh1_{C2STS}riR]:~h~C/Bx1BQ~a>_`1nS]]6^i~{{}R,_R__SMB^:ny8gCS:cc^Sg8hnB.y:a{{^AB./n1]iTR}cnRC}cRR1S}ygrn]^:i}8h^R_SB.5)RnT]]a^hh6y_}g]-C}]}8xyhXL6Sex1hgg2}2A]]auy/chTi_{}Sa{2ci{SeMC,}ugT6]C1T~_{:T_{cTC8:]x8cg>T~]y.}_h6yu^Rherh8S.72{2/^^n:BBSaRBB}8S:hT_6TSyS=~SaT>hS{2~hrRRgc6}xSe1116cBchnhy}6Rx]C{{_ay{rC,ThT^ThT]__g:yS8yxhn1SSR~CR~}~<:{612AgrM=g\S_/\^2r2S_n}TiM{~]Rcgy]_u[nxQ^11TT1]Tn8i_AMT}hch}R1{C~M=SgMShCS2Q}c]2hSR8uu2S_u2B`8c^>]\RxAx~r:A]hx}=~^2gSC1B{h}=1Bcn}B]^/\^2___:nT2g6=h2~i^CaeT^S[CQ]1xc:_S~g^Bu_T8Ti{RSRcni2}_:C__B6~M2_h_Agu^y={=C/Tn{]L_xC]4BCScrT}SyTiLx_}%tIbS2Rxc<{x]y:{RSyeni6x^^-0?K2S1ShSxhiSy:6M[A]CxyC_8c{_]Th82Tr]A_,B6>ghru].^AQC]B.x}y]x]R2h_Cg^_8:yn6Q1CCyR_e}{2]yTC8hiMhiu>~R.C8nh\.-,Ax6Tyc>6SQ,_n~]yLe]^B^2RCx==LL2//C8{xSg~B^Q,R8{^]R~L~:%cch<=1~1-Q2CRg<1R2xQ1a]/{h=c6hTng2\\/^r6y11c^C~a2TgT88xyh6Mhh>hS2Q`2g~~x`]R]c{2AS}C-`R6n^`{>rTR2ux,ARxrrS%B]:>T]_6aA_,Re{]]Cgnng{~.,TTin:]~c22~T{iiTghTi^ST_gi:h2/^C2c\Q_iCC>={S~y{a}{TT{g~}{Sc:h{S{c:x^SSSSheT~hxBBC=8/BS8in8R]:i8cA2nMi}C.]h2^c~Ti{-A1cTR1aMc,\y_xTi~cv]]M8acy8~S21xSy*c822y{]1aT_ci2RC]~.B_gic-3wu{Tc]_:2{w~6gSS_^\>h}h>e^Ay6xRB1hhy:iy_h6g{_x28S__2S^_igS]Q.AB.^y\C6S1}B{gge^_{R]gx_Ty}_y{_Cnc<:cx}8]R2hTLi_xcc~nS]~=g1S~}>:e{Bgcx_ghhLLn{CT6\B.\}y1p}_:]S8ySh~c>{_\Q}T6gSxc_\n8^4hcTr}C~TncSTL1SxCa}~yTS1gxghig1{~TTecyBT>i].c6,.CRTa^aB1{CxABQRgTy_yS}~Sx]S=xQ2x\c2BQRhSQhuhh~1Tc>c_8R/_ghn:}yxBL~g~_\.S^AgaCxcT2i<{2i6{>nT_8xSa_]n}yg}cy]]:6:Q/]Tn{SA,/8/Q>`\QSgCR]TSc>h^Rx_6icu6iC,{Mg~{A2cxB_ciiMw8gigSRn_/_6{S^Rx~gxSn}_y1. S2}nS]2yihMrc^R-/SUo'oV_xAR_c1y{y:]~TB^Mn~6Mn{ceB,^V,x,S<}2M}.xC}c]^R1gihA``C]yi=}xQB]^Lg:8ge}y1CRCSxci22heC]TC-2~]ThcTi}/^RT~Sai]A2R1C1y6i1Q.`y=n=A,]cS/Cn~.R2_hSSx^h<:R-``^_cneSC]T}w=ccc{_RB/RQ^62_gC]TC-]}C6>gA1_xcygn2RSx2]_aahn:y2xQciT}B}r6Sx2hy>eQB//6~^LuTWkR}=].Q/1]SegSR/B1. tb2R\RBRQ2~1x8^{8_.{2ac}=c_aehxg<^S_y]Q^aB\TRcg~ech~e6]xS=h:>ec}R_ACa__~6^Q,{yhB~iy_}Su6RRy^_{h6~hCB]6c_12CSe{cC,/yhnrgx{:{/~:8cn]1e_CcQQQC}_]rcS~^hue:>S1yTTQS1S2y^Q^aB\yA{h2^y=iMSRyc_2c=CR~TT\RS_/.BQxSB]:]C/SRhTiih:h_x~c^,`{}8CRLhA_L2{R8hS__T2A]c~B,1~~^x]RRShg2RAS~1/R]82Q/B]1QBCRS6R{nSx`^h8}:y_n=}.Q8:^^{i8/ByCBx]~a~L{{Cxg~}e}~_ATig}gTy2]A^cyT]/]c_in}2S{hBA2nx_ngBcM8S_chc2}iR, ]-]CiLg==i81R~c~}V${<}/ARBShhnM\RR~^\^g=hS_a_x~w8encgycBu2xggg>h}6g>}Qc_{c]_\S}C\Bx{yc}:c^Anue=TQ\yhi^^:Mh1]cS.-yS.QBA_<}B}8Q]R2:{^{CThrc}T~i6S>8~=Sg}`Cm-HA\hu}8rSRa8_,2>c1Sy]QTgCc>yAST]Q_S\AyyA]L_Ry~icy2QA~a^1x=S~{S8M8>C/aST_Qhuhg~g8Cx1C~R^:c\C>i=RA{RAeMhyhS\cg2,2~^{}2B~hx6T\y6_A7a]Ryy\1in}A.C_c}TTR1:rhy_2n^}__gM2Bg:a}ih__:82y>}xc_6MT_nr~~y/gT1S8].guhni8~~g^{v\~c^1C8C{]]cnuS\Xu/Q6r{h_x_1r>_S^ST]8]i>BCrrinhxA/A6SAS_B^S6CS_1ih26y-,-Sgcc/c1T6cc_T6yiyxc_B.\8{A8MgyS/QxSg8a1u={{cgSSg6a{SMa._2\1y{2_chSB/._g1{u8SBBT>h~y2cB%yLhTi_C2xM_S^yiT]_A^<2xBxhcC__B1__Tg_.\RCyhe/.c8B6BCMrL:]RQC* {.RR\:]cT-,-S~}T/Th_SST{6h~c`zA`AThia]^SBMh~xh>]}~nw^-}M_}C`_6cneB1]R]h~6_}6y_`/y_]yh8yx]y^x{ghe8~,.~gaT8}y:<}C-B^}6_na}x,,2^RTTAQ^6~Ti^^_Qy/A_chCThMLmnc^h~1T{g-Q_n_ST4 TgnhR_]2c{ga\Bgc^2TQ]SRCA{cQ3wi:]_TL{{c]S~CBSABA_i6B/,_>^y8_R-/R]gi6~:yyyny=nhR,B1^SCQycSTTAe>_yx/CSAB2\A^^/B6B.T]y>rygT]Q]a_h^S6^{8{hQA{R`/xy=ng^aR`T}ryciShhgh;eRCh2Q8{ySR^68r]\SAB_QSABS8A/,_n2yhC,B]]_R/{:cS}}Chx]A.1.3wuh<1.8QTSx6}CC1y>2.Q.Q{cT.BiTy:~SSS{ycgyA^8SB\gQyiSQAS\TAC}2A1~h11~TgcC2xT]R]B1_1R16]^ia{:S8:T\C]B2aQ-g:\Q2}^e8c8_nT_2}hh~h__axCn}2hhT::cahR-Tc.2_xc{A\]}n{.Q.%Sg/A}T>c~6~8h<^}i_.Bi:\~nc\]c1c=RCy]Ax6xxc2y_1S]a_1y]}gy__~1xgS]62:h{A\1RSc.,a~BQSn6R_hh:]=rS1_~f }A-`heBT=i_QA_\ShCT2\]8={2c2y_R_Q3Mai~\~iBR~6yyTcyxC6TS_BCggMy]=y{6SSe:aT<\_hR.=-{6hhC^cA_6_R\aa\_inc\\]TCR_^Mg~1y2^_g~CC_^:<1]BCyxBT1x_T{S~]R:>T~h__hc1RT>c1Cxxyc{cSS_28}B{~/Bc6y{{{SRCghyS2Bxg8uc^>Ty~T~nn:8_aiAiQCc=]Sa2c2R\cc\_:cRC2c^^6ih_}gxRxc}AC_2:CCB`1TRQ:ny2]SchTc>{1L=cei{yTC\}6y_B]h8M{]>yy~y5T.,g.\y68h8\16\{gS1]2SiyA\Q3wM~h>{A2:e=T_2~xSx,,CC_~xAycT{cSS:6}_S~/-6/w6SC]6iu6_Sc{^]_SB^{Bg8SS~h_B.1y^]i^{C,,Cx_~xATa}y~yf-}:_,{gy1xci}^_g}_2TcxTrg\cia2Sk3[:L8n2xT8_/]~y_^R{2A_~}1e6/A}1B>nB2TRA_^gB,-2cRCggx{]hn8e:~{iag<{.QThy6c6_^~c{c1`]hy{i~>1g~=6T{xAy>}TT~<6g<2xcT::__2A_g^`RSThC{6Mnhy\yecc_a^6Q/>L1-.RiccyC~c/c}2u_a:{x{T1/B62^:2c_8a6hgSMhhThn:_.\:unih=aTi:S.]c~:in6Sh^2~={_y}g2yni^S62 :9^S\-xhx//`^Q.2TraLCcuy}_BQ.L^6~CSTTB,.TMn6e~_cy_1{cSMgB-2ii_BR2hS_{6cS{{8S}yQ}}]8hcRa~~8~\6r}1{B]}T2CgRCA_g2Rc}-R~]\cg~SAR2TnSRBRSS2RciThy}{=iABgh^_SB/2Ty,/6hTachT1S_^C2y2uh\`_=Sx_cMne~ei>hT_S:ry6ng\cyxg8cLy_L_=iT~xSMggS]Cx\_8_RT:c]8n6Tyn/_T2hi~22S6u~^C^cc{Lg~gia2}T_1{cSM\.S=So}~T211}=^y~hS/}M~2i8n_1nhcggV,L^8{cg~:{A2ch{C~M=_T~k-w^T2]:nr8R`,B^B,Aiur~x}6}c{R-By2~iSa>iQAuwn_R{h{S~T}cT~6\Q\]^C\y:c{6h<>>gx_6{R_C_cL]-2h_{1AhLcS8Q/]{C{>1^{Qygxc>}7~Tg~]{i}==]/1g]T^^:r1.\2Q,{B_S^^xQ,By_yg]/C}{c<]y~CSh.RwSC}8ea~6}gc]]{6~{^~c<6ii62}haR1{1SgM^-Sc8i2Ag~y2c~B{c^}LyaM1>TihM<*x/,B:uMyAyac6Tx/xgST8]vt}R^~`/M=]B_:cT:gh~h~R^T}_1cgTUc/,C_y{]{{ACg}\/Q]h:Syc=TgCQB^}aTncTR{}122-Shi]A1QRSx1y~nBQ^2xAc_]RS:h8iMch}BR~{\Q~wSyr;S>c1y~~c8nyBxcycM/,_82-Si]1yC{y_{aS\]{R-.ce6hc^_g:cQx_y}ScaR]8}RQ/18~x2Sh}]S/Q]hT}neyi}S2/1g^BC]{i_CyC]T]^c8wLx\yy_C~{2]}h~cg8>8A1hTC[uTc>gM2yc}{aiSA]gceL\.~}QgMa}hy2ge_vRa{B./x8~]Sc>}]RC_:Tcnoc1B\gR,behgxB2BCc^^}8BBycSxgy2z3{R]RRR`1cMg_/B{h}{RCS^\crLS8nnS6>>S{~^AA2iic}B\TCCC^2xhh]\giyA,/^}28^68RTT2R_8cxx8aCSy~h~g:ig^2ygyB^8~A/RRx\..QB^_{T]xAQ,,`BCSTc6yR]RCR._MeuS.Q{~~e^iS\R_]ATn6]}=}__Sg]/^hM>y6\..xyy{^\TcRBR]C2TxCRx1R]{h6}>:h]/2S^hh~_{ST8}cMh1iL__8aQ`^~~T}ru]]}aM^6n8Sge8__c1RS]S>eS{^_ghTCS}~:^/SyR]_/BT}T{6}B,\c{CQ`TMihSxx]g2BSMr:h~_cCQThTCSy2x~>~{]S_{8}gScc6B`^Wy}M1T~2ThT}i]2^\_]2ic2nS^SghTB3\Tc}=8_^B`R~i~_hS\:6_RScr~~\CTggn_S8_28{}}Ax^\y22ag1{aQ^i~Sah{T6T_6i_y{x26~T}M\R:{1`.{i:6S^86]Scgc~Q_Tyc_h66_2CvS\/]ia]2B~S1nix{~uhTBA`RSMxChc2{{/C^\aahgR_n6BS>ih}>xT:8in}S1]\-x6iRc8\y2ySx-7rL^,/TcC.2a_x^LT^c2a6{LcSxSS,,-xnigCC1x\_n1^T8{`Q{\CnnyB^6TTT~gTi~aR{cA2h8i}T__]._hnx}eAy8C^c1}MLn^,.{ax`1hSRBAu{1hT]cn6{LgT^ySS1chy~{_S8{h_6cTRQ^y_~1ynna-,/xng:^1]1Rx:Cx{:~/\8__SBvv4_1`2=\T~S~RS:{].gw],AQAi^\~SxSiS]~eygr_B8Sx}y6ua-_}g}S}h:}T9R}y{ryxh2QniB^=cLx-{g}SS~2{2B~:h_]S8~Shy./]rL_xA]S}~xn}Q~{1_^g:u^C{h},`e~ByL6y:h>1-.Q]g{<=66{R\,,yi{S=~C.TyB{6Axc~:8{>^]cc~8x_cTSc:gg]8~cu}xh^/~iihB]cLC-{hgTchSS].T^C2~T^~nc/Q2]R2}8hC2M~B~y1_]}anLS]y:c,`~{`_nT_SQBB^yigyCR,,^g6_BTn2Be8A2}Axg~:]e6}ryR8]/aehA_nnc<|o2C.{M66xCy_CT:hARTu1RA_}ehR^M~Vu{S1RCxTgh{cCQnR_cR2TLun_}~_c_6w^~=<]1SR1ce=]2~2BR1Srr_B.\n{xR^}cA^iT/BS_CQxrc.xue1.\_y{`1h8LTRQ_iT_hjvmhJLc8^A^y]_yg{}2cwN]_RCS}cACS\`QBCcxx>SC1S~8x{>cB`3K_^{S]CBRRQ^:_Q{i~2~:Tcr:TC_8eh6yn_a}\Ragyyy{1B~6ci{gcSi~_`SLTy}]CB-]nix-1Sy~x\c}/`1y_T~e<_Rg=Me}My8~_6BB22TSSag]TLhghnh{2S_Sh]T1QS6{R-Be_}{ynh2_cc_`,\y1S2ahyS=ec}12}ehh^B}:}SS=c]]T{/BgneQTa{i~S_:SCA]8<~SgSScc6R_gag{yyx]c~gn^_A.Sgc]`B6iB3cgLh6,xg}]\B]ihTg6CB^_{S1CScT_gy.\BQ.QC]cB]Sei{_8h12axT12uixc~cnigT=~}unSecT./B2y6gh8}yxRTiiy_:y6_gy~^x6ny]^cS16}2_cnSC^~:gcy16guh6\`28S]CS>ia6RQ]C2SCR_cgyS8Ma\SxB.B\C:yQ1Sg21c6e2yh^6]1Mh\y~6n:6{iy_i]gyhS./_cgh_h{]Q:LuLuw=n>hTg:2BAg}^y{gTAgyiQ1}}\{]8RhL_C}88y.~:~cce=acgg>:]>}8iLw>]{c6n=y_T]26g,,}g2g}\,]hx-x:x,A{_RC2yCgh}u_]~eh6y{hMnyC:~C6~y^B\iMLunM8z}T_.,Acc]yh~a:~2/]86c_x}^__28cS8Mm3cRQ1Ax:6_/Bn_cxCS^_Cc:T22}hn=]\g:^]1.A8>uc-`..`.__R>}R{_C~TTcgLiS_grnSR6xCaaT./yigy{11{yyC.CxS~Sc~6]Q~n^}gxQ%{22chxRSC]i]/]gQQ}].yh{g]}LyA2h>h1A_x^=a]/BnMy6Lx1T{y^ay]]T>:\/g:^]x.Aeg}``..`.S_xhnTR__2g8~6^x}n^AT\BSS~2-.{hc_]A]TyyC/2_~8hh2/yA2T,CcR1yCCSACC.Rc.`4aR-_g_a1TnSB]g6C_x^62.Bn_{S}_yriR1R.^1]CRnT_2A}SCc8g}\gM~rnc2xTT11ABchc1y_`^icM2xSA-/CyT]rgCA{],Ani_ci>c\,,B6gSAQSheTBS~66RRnLS{6A,iurir>_Q/1ga1]8gC,-_{/_2BQ=h^S1_nRx\.2]^RR:{1hR/Sc]Rey_I`N\{gn62^{_c:Tc~hugx2TyT{]RA{yx_]`ChgTgy8>y_xBQ_hcR.,1icLS{>gS8/{>u=hugx6iBQSy8c=ML{ghSg2}{`Rc2RcT1c<8hu}_`/BBC2_cr8xBS{_Lg~6ngh1~Mih_2~rh{_{_c:T}ch6R]yT}{1ABSyx_].2gST]T=c{^B{gx.,]iT82_:}8/_:c=Mc\T`-L_{~yhLL}hS={~RSy^8g_e~:]CTh}S2QR^]T_R\x11x8{Q^^]SS]]{6{Qa~/\2,6r\TCQyTe=ihSCA2c~yb8hyygn}_BB^^SaRQ1Sn_]8c]>~S\Shcc=iQ`_cSC^a}6rL8SR_M]Sc~6{`CT_nTx1}__~R] W~6TS1_]{2ARC]1gRS21Sy2A1_TnM{Qag-0O\RxgrnxA~g{_y6c]9c1:a2xgT1A2QTnc__\^6n>a]Ay^~~1^6{^iu;C-_CxyT/.Sc6xB^2SRA6gS^Scr{1~c1:c^\gT_hC\h8}^inS^yh8Snc/BCx:__TC]xcn]CTAAT{BShcrTccAQ.STSh_-\8~_R:<]Thi~A/SnM__]\L:~y}^^iMiB/^A.}in,eT^~y2}].ARQA]y~r\1~yT1]:h^1cxBh{iS^i_ThaS2_}n2\81]2_Q`]5S{y:hn1A{BQQS_/_r:~TccQ-12x6^-CgSR2}:nnRQyn__]\ha{T]^iB.^B-{A,igT^gT^yx`\RQACS8~rnC_h6g__=S_eRBTRTuS]2}~{2x^]Ae1S}cR.Rgh1x1_he1RTAATyQSr:gu}66\B.]2x6^`Lr>_A{^^x~}S{xxhQ`]B-yMr.0w{_2hy_S{2Q_h-1RxLrySTgTgMi^_~{]gaBC}6_y2,,R_h6~A^Lrn^B2:nx}i_y8_aA,B=<}yy^T~ah{_1/x{2^_]_=_.1cM}\T~{]ng]xT}xC_6cAccRyT{^BATLcS_:y^2~_x/^e-^C1M:MuTSST2Ti2_hgT^86BxcgTS,,R_h6gA2r>:]Q^:nx}]_6}h\,Bi}yy2T~~1ST6{c{Ch>aS__A^}{Sy_yn^`C2x`1{S1>~x1ca]RxSTBTc^gg~yxS:_]2{:i2S{2Q_h\`]C1i}{{T2TiU _:~nQ,A^8cgaB1c8C.18gRTh]_6c/0B\R~hMg}hM{hc1TB,]TC=Mr~cicSirg1]_CQCc~]^hSyanS_g}cihQyxAcL\A_6TxxMLS{2hS_~^B8{R]_11_gwh1RR^i~_CQ}a\CCg:Ma{eh~2g}]cA,^TCnn{Se6{]^SxBC6hSyr}{{CSyS~2`QSi6_cw<2]_A^~BQ2gc^C^n2_]ahSCCc]QgSA]S]Rx{rC\1yc2B/S{Q\R6h=~}hMSc^},_cxh=ny_8a4 1}2ThS{cx]{1__^~:niS]S:hghc{J\]^/2_B{c22]A/]^yTR{i=~TerhM~~C]~S_xA^cih8h:nc}hCBc8~8BRT^Cx8yxCh_C\AS<~cinM6~6\R2122]c=T2ya:uiLeac\xc2]\Bxyhg6ehnc}ixa8~nXS1x{~~h~BRcaL:_iS6:ycrB_~~n].2=_CC^1CQ.8i}c_2eSR~i:cS]g>y1}e1^}~6^_1`R>CT}STL{C_AS^C\[:}SS8Sa~x_TT^_ac6ichaci}a>{x^y]]}8y}{2c6^_8L8cy^1{gghc/ByT~{T8ycB]{{}hca3s:~]1cy]TMrT]_]cgC66]cgchwLu=u^-^~:T^1_SB,/~a{cynMyx]guhC_n}AThhyyiiT1CR,,\{mJx_1BcRSeTg1S^By_\^\1R-yyA.-BcTQQ,-Tg21:2^TBR^`/2_~T}iR]8].Q}n:6cSc:M6\^^xTySx2c_}2B_:hS]T~86hxyLw>ny]}1BRhc.\a=LniS6g:RheS`6Sc}cSC_1,/~}RS}8n]yL{Ra_A]\2^/\yyCQ.\~cQQ,-ThTSyygRC^`/^]c{{>hA18ex`.{=8Ty^ch:ryA11RT}{:^y8}g{R^gi~x\2{cTgy/x~8^26^Ax6/xM:Mg^Tc8QRg/BwTcTncT^{2`BcRSTgxS_A}21x\,BS^B.-. oc]Ch>}TcQAx`.xxy__:\18g]./T>h6ec:nnq`?pB\]2]S~_y6y=gnTCChiT~{~i__Ma_^8r~c{RcLS\Sh2C8i^]~aS}xBx82cM1..2ge6T}{~QC_T6}yg~\R6g{CB.C:=T2_QBx:rc\82/aiB,Bx}{haRx2SBg}TaC,ALi^_22R^B\]2]_a_TgT:hMa]^iiT~T}S:}{hgc{R}M6]c=}2g/\]y~a}hx]ha]Q,Ba8ghyC1`/Ag<{A8_QeR/xS8{h}AxS{ghe{_ahh],/g<8yS~=cc~ARR2{yiSSTSS}SAygi}2BA1R_{{y6>QA6}1:8x_}]TiyySxxQ~=]Tin2x:__Ty}aTgc1/R}agcgyT{{ng~g_]~;y{k*!inc28hg~nh9A`BScT8M>:i],/8=ihT{VwninaBTMn_R]S]~}xTS^:{C2~_Sn_TTRyTC8gCyy1y2./RSReA.`QABMgS{2c~}Cx8:TS_2{SSh~R{}QC{{h_Cgy]hn~S^.~x6}\xhCSn=in6B6r_R^{Se8i~\BT<2/S8STTR\B{ax{__MgS6M}ShxSSQSSR88x\{{x{2.Q/+[:eTg}C}6xz12CT\`^g2B^Ly{c_h{S_y_1_y:S8ngyTS^{uyy:e/^T]iA]8{Sg{:aTRTg~_T^\]c{Qxe:e~ehu~]-Shy{ccy{~hg{xryx^e~c}C/x]\T>B-}TByy]yy]x6i2Rc8rnCx6eCQ]h_x}R.^SCyr~~gTca}gy2Ta=iS~>~S{S]2r]CTnSCSChiAA]S_M6_8~B-8R~gy8h_1~2C66{~7x~xQ2S]61/S^Q]nSS}{iS_kgn8yTS_TTyi.C^A~hBQC}]]M~_ich}1cU,M}RB\C]_{}2Bxh{/x^S8cTTn~yT_::TTcy~iiMT}][Scuec}R^6ihTS8:}_n=M}=5S{__^_c8c_CS8y]Chgh6BAh8]g~hi5hBMTR}c{_2/`c{cSxggScT6hT]RQ{gRRC1:;2]_S2{}~SAxy/12{6gM:~eTgghM~nhy}RiwaR^=S{y6]ai:T_~y^9~6RMTc1n[i{aue}SQTCT~21T~y2g>ihcX?p~}SxB\2~gT<2Sh6~Sa_{{QA}ycg_{SB\2xCB\22]Sn{^xgC^T>ww>i2M^C^{SCR2}ie1\T8cx2^]8h_\S],,\~_]B8y/_ggLeT~/_66i_6g69}iTBQ~a}8}_]}yS6S}{]C/xTRBQSih8y\CS=hch_{hchT_h}~~R^h6h}a}R]T_2CC2^1_=S]Tu6QA]8<1iM]R]_2\]}8h]R}he}x2^]:Tx}_,,A~=_2BR:aQS8M8y6.1TT1{hhingxBB}y{6{^2g~}:a;c2\/C}RB/C}ySxB\Sh>hgLSTi8~Sc2SSQ6cg_SW t2^Sn{^Aah\1ywghgRhaRC]1\\^T=8hQ3PTny]]AR]x]2~{_^1_x]iTB_2ScRc6CB\xB,Q^\/^_/^rScSShnS~^T=aRQ]~:c_:Mc~_S:6{gg]-`2_S2A{x,/_xxnTcach~TTcyyS^ShT2RCR\_^_S_c}{{_2S^Cug22RC_]2h]}_^C\T^STBS{}]82R]_\-B^\/^n_-RnR]RC{c2~i~2{yB.xc6_h>LT~_Shc:8^`]:>_{S\}],Q{]^LyyyS6yeghug}2]_8S1R]1CyST}T8cS{_2y4QSny]]C1S2SwiSe}{^x_x^iTBS{}6\k.o2RQ2_Ci2y22~gi8ni1}hTC288_B/xc|Z1cg^{1BBBA2Tr:]i6BRc{xy2y}iy,Qh{Cy6]RggB/h=2_n\x:ScM~/BC8Q2e{2TcRTi^,^y}Sr}}~e6yAg=}a}Rx6}TSTeSxS=e-^y~^/^6hTg.TTx1cM_8\Ax]1yehieCxT22cSBQ8h]/Tc]cn_{Snh}B^icR^gi6AQcLg~{xRCQ7T.1A *AT=_,_hyS1gy{{{_1/Tu_S_QB_]]]Sc^A2hgW3w}xBSa}hg_\SScgQa=_6~BRR8A]_C_}>cQR_1,.{\{{_hc~:MT^c:/Riih{A2^ycB/h~yi]QQ}cBxxhix_Tx_c>aBC{1,.{\__]6T^_}h^A<2cy`A88hg:}MgCT_hAAT_a<}.B:h{B2:\2h_xCS{{^A6AQ86x_:c,/SgC}2tgg]Tnx~M8a_yRB_6gnT]}cRwh~=SA\~8R^2]A=n_~}`8cchn:gad[L_{Byc>h/B66h_^c{~T2^]S~}^8}BaTS\,Cen=]]c2\`^8B`]cgC6S~6-]yB\1xAxT]^~{~g]~Sa1-/Sh}cTr82Sec\_gx]a^1^CC_{66cTCTCcn2]=}ciT1_c~y1{c_wh2{QShc/Qy{~xRgS_6}S__y~28}Ba>{S,\a=2_gStq\/2e:x6S6a-]h2Q]1A1Ty}g{Tg_.Bcge~i\_gx]6_^_xR1_y6ayTTxcx6L_2<{yi}x]{S]`0ach_]2x\_{^cR^h_S].^8_2}c_xSTy81^hgx_LThATn{C2Lc:hx{22gh}/_c~ncTncnRcyx^hygA2]]cgS/Sacha~g~^y=c-Q{]{AB5gmmg{8~:2gg\-R^2}e}hy{_Q\2ARSe2_>}Sh6cTX.1/y;i>LiecB2^1x:<}Tn~LhBS<^B\g:im]AS>rn<6}AC/CxS^QCS^iMgyCcT}T:hS_T2S6ig~h}ggC2:{x}Tx,QihC]TS^yc}]=uLg/Qx1R^_/2>g_hMr2T8h~RT:agg/x}C_8in{e886S1C1Q.ync{8A1u:~c5xS=i8S:6xL^B1x{^BCS2r8c]86c}:__:a^]y8TThy6~R^hT]~9x`Rn_{g}Sa6nwa1ia`/RCAx]BS>g_h]Sc6}xcMgR{h^_ghcn>SgggcSx1V h}Sh:1Sh~c^B1h:g{i{B6iR/\R2xRygTrc]86XtFTxxS9SS8T~g2yy\{SB,Qih]26TS6hy:S8:-uSARRc]cy{n]2RCA.\^/\TTy,,xR_gcchcTaccg2]:}BRx{<2~{n>],1{.^]^A..~u2:cn_BT{1~}}:::TA2>MRC~S6-/S6~ixeT}~6a8hSR8rnh]]hg\MT/a,^i=hg]\\Ti}\S>6cM_{xCA.R2/RT}y,,R1}{T}yccacx\~_.xxS2Be\y=2/S6BxTS_C//enxn8yh>:_BQ_^C6g~h_]Mx]\RB\_aC]}}T,-R*5TyRc^-ACSTxhA2g\,CS.\S_Sx.-T:/R~B3HcT1^6]a=ig1x6y\{h_icC2{g~Sg_]ci}R,Qca2,Sicc=c]:L}~e6SS~igSSg]-QR4.RTShugnic1S}Q,AT2]:g­qy,Cn]]gT~}yhe5B\}yRThaAcMgS^22a<S{T<=ieSx1S//1Ryy~igc//_{~nxByLT,\ihh}QB/^^B^CAATM:^B,Q}rSS:~S`R~{A^~Mh}R1.2{{2-RniTLc]\a_By8hg{1AC2SShLhyhhhaA^Tc{T{RB.1iyx-T~r:a:S,\=}xQAT1y .]]TcgMi}}LiQ/ygxBC}MR,|1Q\^]{T]a}_Mu{_`x{hSShw\-/A_],/{QRnLn:Th:rLi__~Mgxhi21QCSM[{c~ieBx~S^_R1SccSaRAT}nRBxgTy21:QQ=BS}Ry}2]AQyRghC8],28rcSxCCQ]h8~^\S{_gxAy2A~8A`}ic_h2-{hnLux./^x,/^`Q=n=e_~8gne]/1cThM]hi1~iA-/\i_y}hc/C~{Sy^_~ii8_CySLR1;}T21=..:u`x_Q^:_C]CAaw^2<{-_y^gR\C/t褬vk^CcT]<]-_g~_{i_`1Sh{{hwAQx_~T/B{.B<phC-Cg~=uS2hC/BAi_yy~5/R}21^Rx_~V3uOQ}r:i/giQ]_.QxTAC~c/BT1.gn}~STTSy>car2:r}A1{RSnhyQRhgh/6:xcMeRCSyB\}y/BSR.hc~SSS^62iyy8_:}>82/dﲬOjC_c]cr6/Q6Tg/ehS._T2ch_{6M{B//_cR16Q2>n^/x8g^\xTga68Trh}ƽWvi{y_2g6_h{-/1_gaQ^2Qxn1QB]aMhBy}R~t1TM21uu8S]:8xRyhML=yAx1xSg6^ynyRim3_x\x8hT}S``_:}ccxyi6gnie_~c\R6ec6nTy:QQc82\]S~{\S^\2a=i]BRBTn8g{}h1nRTn{h:Q_exAS6Q6n6g~^Q_61x{6>yB/6g_c{xB\c7xRThg]1ha2CBAy1Qa=S1^c~_]RBQ_~{]}S``_6g1y:Syihhc^}TA1=:T}~=__8/`}:{x2yc^Q]R.26~]BBR/^hy{a1y}ruyg8B_8xASAA}ccecc6}\-xS]TncR`icc]B1~~1R}h8]CвIT^C1cc^Ryj,w[uLyyn:xBSx{=^gh_c~nc1ciaxx}yA]MyT<_2Trry12{hgR12\.C=:^x2C:iLhc<_~gA18h_gy}8SxRC:iS{T8S~Sci8]RyT_{CTCQS__n81`,xyBQ}ig/,\8_RR\S1Qx:yxx{_Bgun_Rgy:xB{1{iC6]T{}yCye^^~_BC~S{h]1Tuc^ST8TQAR/,Q8hSA~6cMh1``_aR8nB,OĬ^B^cc1QS2Q~r]]ig2R6S6]~g^gic6^68 x]6R\TycSyxChiy]S~}^1xT{8cTS~2\^yA,C6R`BxRyR\g]1C2LihABxSnwhC2STSTy]ciCB{STBT_1SM=\Rh8CQx}/yyu~2RhLga8{2_gyxccnSxgicce6~urS^xQQx{cS_T}]CS]^r]2\Ag:_x{c_^1cy:wMc~2xS6C,^h].ѯʴb{=~{~8g/C1>eCy7ecggSh^\cTTBTy_cx1:g k2yRBhM6}6ieShLni_A}:Ty=6SSRB`++?O,CihS__icRxCy=}\Cxgx/:C1r\/_S{g~<{=aLaA,Bcc6{}:nM86hx/B2ya<2B2}^RATcB`Tn~S^.B\Bch^STC2{-,^[}^Mc=r<_{S2xQR:{x}=arrc{8acxC_R]CA{,,nM{yLw>~ihc2.,Ah^\ATSRxR_8_QAR~x/hhARnBBT}}g:_i:yhTB,\~g8}ch=cei]Q{a8nyASy1A{TA\iT^.BRA_{~2T~.,^_R>6{h_y{_]QChS]Mhrrrr<}T:e_2T]V{fr_h:T]`,\h6xCCgc]_]}TRhh~S<8STS_`{>_\cMC]}y8Li2^S~cCRS~SR\2S1BTcxex\ncS:{}c22gh6]_gcc8_]hR\gSQR1BR_xSTST1-AyCA18i:h^~h_8c8TgLeB./iSAiih~y2}haRTTCc}ch>SR>iicnw:cc^{\\^g6x^_Q/xSBxRT=y.`]^QS_2h]`2]\hya8hixScc}]B2hTyT2y_C_}AS\A6A{y1CQa}]haBC/Q^^Sxyc.-B6SRc}CB._{2~ic2h:~:>MS/8}66rn~}SciaAB8g:=T2gT}>ggScx2c:^yTQ2cA^xThi~/.__B}{{_/21A8{7~g:]ycc}]B2ncccS}}2CS}A2QQ{Q__R~1B6{AcS.1BB]12\SyQ`Agy18^xAz⺭ܭty>{Q68e=n~}ThnC\:hi{^ga6~na)12_Q/x91S_8=uh\Bcc|ç.]RB~_yc<_ahh~Ly:r~~SS\y_AT~^]n:eLrS^icTBC_c_Ba>T1S=}R6e^~xQ_ghayC/`1AB~hiy`,ղoݬ|1T=x8u}{Ty_T\Rg.^{chT/,/C\_6ScS.C~x/Ry2/R]]:gIýѬgg8g66{Tx~}xgk-wya~:SS`,A8h6}.\iyQ,Q]C]y_yBh_ia-x<2x]8nec\`]SA]ic1_cggh8hgin8}c_]xc^`RTLe]_1~ihcr2yT}x^iuR]~x^g}]_n_28h~]ScgR`]w[hS12/R}/QS__~T5xRhRCua8g:SS-,Ci~Qx~A,A{^y6ycAx}`\2nLT^SiLrgT-2}CSg^yg:hh8hg>~T}_]xc^`Cy8S}_igui_SSyACenS1~L<~c2y~x._Tʭײy^^]]riQA~:rc]h8S~S~6S8_1xcuT1xTi>=y2}S.Q^B/ACST\AA-T_{T{{_]A]gi8SA{_\12T]{hy2AB]2^_`.gh_xggguLy.`yc}igyrhA/2Lݶj{x=}.cLg6rn8R,,.=.B}huc]hy8ykMSC_8nMMh}cS`o|oѭoBQ-Q{2SySy{LSRB3+upy2BS~yya}hc2S{S1T:_A^>{x^_RB^S2~62c~_ch8^e<,B`-Syg~STy8={QQ]h>gx]xABRhAQLuS22..S^C:Q8nniC^Sxee{xBTinMyce~x,Q]eƦWb}xQhL{2c_BS~<T{~hTvtu<_^yc2xT~7i62Ħv֭B,Q--2S~6_T}:}B-0Mi~AR~h_y]cMhhT_h}^}SQ\2S:g2^1hn~}~h~xCc2}g_rTyT8_8g^:TQ]ST}ai8a_.-B2^]_a{R^hA,2ur~c~1/2xALxC6c^ch2a~Scy_~{>~cc~^Q1BAx/\ra]S_h=\]h6xB]{a}BA~hcy:i::}_M_aS/A]Shnc1xxhn~Tca11c_}Le_~c6^6}xgS`RSccch:cS]B`.C{{_S6_1R,{~}C.]RQhnxRh8~_ch26~{6}yMhTh:{A_\C2B|W86xB^}h~AR~hi{c_8uh88T_hLnThMo~}Tg={SchLe_vѬϬ18S`A2{y}h6y^3(+ohri8^8hhgAh:c]62{ynM2Q}n{_8T}=e{^ecT:uhCcT^c].cnS\S{Tu:nh6}}]x6rhah2Q\Sc^{_1h=g.`~=~_}aQTg~gyh:c~}Su8{1Qc:cTTixB6]S~`,BC2RSM{AS82/\TT6c~]h<==]1>ng^~_TeSQan_]gyTcS2cTh>x6T2c]/6n^B22SM6gicTT~2xchnaT:yAxc8]^1R~hQ/nc^{}Q}uecgg}_hT2AgnA/1^C_:c]{hS^]^hS~wnB`h_8~Rcc8Rxg_TS~>ccTc8]Qy}\QAy_1i~ciy,QxT>cicg8~{8=6]}cchy\2c~AQg8]R>uc1Mh2AQ_eyT^>~h/`/1hnyCT6_cgrC/1]\1~{C_~S2^2_~\/oĬBBTxS26nhh:kttս*:g6i~2,Qxcnc->~.:]QC_SgyS]]n2cyS~~SBA~SC{Rx~yMS`68^Ci8cTc:]Rcag~S]}hc=SiQQB/in2MhS^a:i__c]eMM1R1ge1^ytpe^x2SSuS1:.x2Tc]QQ:2A/c2xh2AShc_yT/C8SAS:n:{CARx]RQg9/^n}MTRxScha6xBch_S>y./xexSSxx^C.R{2C1xR//^c~_^TyC/CS1y2AcT{^x]^8c_R_:~Cx_\S>_xxRccx\]^2=r_xuBQ^S6g_B:],AS~>y~n^TR-]ggei{8S82^Jrc6h>ihie6{_]._~/S~2hx`A2{}aRScxQyMgA.^82Shc}:yBC]2:6^xST_^~g]/\Q`y=CRTcx2c^\S{Riu1\c>2{8cg6_QQAh:r=x.1}8T}nu^ݭ~uTQenA,Svݲ/,{8g5yc~1{c^}C\h>3++PNBT^Q{:c]_C:w}-{]TgB-x{8egxBCR6iB]y\_8hi6]g[@wTgaT{6LcTcS_26ch2^1R}CS~h>8T6eS]}e1{<~S,,x]cgTS_^R,,Rin_AA/C6:h}Ay=8}{:12^Qce{A,Ax-BT^Q{hS}yR:~QT^,_LS~:-R^TT}xQ\{hQxguc^TincRTwL6x_21C26}~S]B]6}h^]xRTR2cenhc~{ygScnT`/5Tih}^x,,hu]BB.\}g~SB_:68gDvOto-\gS-B}iT~rnc\^8B~S,yh_cd驓{Q1g_\2̰ձ~]{_^x_hS_y]]Q]cTk3(,,y}ge]C}gc6=~BShSL_\~T^6TA-`^hiT6gTB]axQ1CA6]\x2626y_~M2T6hx]ccB,-Qy6]{cT~CR2{R.QR^8:_\ST2h]gy~g]]}Th}ch]CSTSSgn_.RSR{icRA~y]c{B-`^hiie_CRia^cw~1ARyhy/BgMwu}CR6cghc:h/1cBCQ22x:Sx]_g_gTSgS_y81-Bxc6gT8}AB1~ni_A.QA1~]26cکݺo~{1TcTyhMT.1TCTaR\g>}_gXǬd]=~2}wfooݛ9{:_RSg_y}_66Qx}B.,,uewyT_2{{M~T}grMrua8nhhrgB.^}:h]C\2irnR/{B\8:Q/^x~S.gu>8~=Sy~a~yxScyhe_AA^]gh,BrQBSxQeg~A,`1:ec8SC68g{]R]irnyC^_..:cy~c6gec1Srw:aui]21x]x{<_C1_=nT6geL~B.^}:h]C\_unR/:a\`C:~/`CAcry.~uTTy}>hLgc6{]}h~>i{xC2^e\,C6LSR=:i]`BTLnga2\T6~{]AxhLS\x^/BέݬǭD>S{^]2]}y]2{>LcMMi)*xcLun\.hrF)sx,_g6__8^_hc~=TT<~d3ݱﴴNB{L~]2_yacTgh6^2ehTS{T.,]}c6~S_ScTRTC/1}=SAxx]_2T6hg]^gycxyh}RQ}>_QB/x]/AAB6y_=hncR]SB.`^=B_={]1{>{ehy~<>5/Q_~xC=S./u{RyrhBTgh\CS>n_{h{^A~S~h~^]~ig{__{.,]-޾詤Q^6>n}]_Sy}Tag:8__h~xxy.B_yA-_y]]\]R\xAxR-AaM8y_2cy_S1S~uu<~n{_y21]ASMyx/B8gQ21]c6ycx,`]_6M1/w_xM@rSx8i{6iyiCAQ]SS^CCS:^g^6:^xTxg<_``ݭ.QS~:a2T]2c2_~~S2/Q].A}g]QvodoVx.\c8uF˵ݓg1yTx/B6y`CcB^_1_w81cycS_hSB_S^RSgn}AaT__gg^c{]Axh:a~c}QRin2Ta^2c6R]n1S6>~y>`Qi{]{hc{Mg^1B/^c_CT~_QTwTT:gxCR_\ASBQ^6hyx}]_2`\h{16c_^CB``]Tc6_Cg:S~R_]_8CRcx`RC\/RS{h]`]S]]ccxTg_xAxh:c~c6CxKi:urygLg21SgSB_L^{yhh^x\]B2Q/Ry-/h2C2g}{t+[w}Rc^Qng\19{ur~c6u]{u}cTcacy6>~^1CceRAyccguR-_8x.Se_xx7i^1hhy^_^_~_2i6xy}1C\T8C~nڻo:C^gyT1]}]1cCyM:yS1Wʬx{`fୌv^cgxRAx\`/aTA]cUSc}2c]`CaTT6crLycx\yRBA}y1xC\{^RT~}]^}T{{-]x8hh>~S1Th~^/CryB<{6Ti}SCQBS{RQg_B/__Q]c/B2B^cMcyCSM~66]A.1g2Qyy]^Sy{i2^=c\`.S<:QR:yQxi8]SS2~{/^eac}{1^:n~Q}^\R~~S__^6y2~~}]^y{kϬǴoM_`ahyg6S2R/Q2SxBh*`ʲӬtdo/acc2_T7}]cLd8S^y_1iySx^{S<_A_x^2}:Tx8_1_]T~]ARh=]QhuwM{C^}{.,gg21\}rR,/SScTR~ngRBgT`]g_hhRS^/_~xgM}c6Rc>g}c8T{y}hT{{R.Q6a`x=hgR1gSSi_\S]_Sgg_u6yyxSh\2n=]SDvSTS^TS:M2A`/8/^k˫ׯ.ܬv*|v*/6nnnW|_`,yoٱ+?HcAxcL2ixChc^-_n^C~a8{y]2Syi1\Q.2TB^:uMuy21n~_-_>1\a}~SS:h~h8y6hh{~:}]6n^^_~<_]T~gcS]Bc8c_QB}6y2S~ga=A/A^R16Se>SiB1hSi]hxa2^LcQRy_26fS/zDzݴ+PB6g\`QCy:hx1}.Ch~a.BT~SS_caS_]S1BR{_6nhTCA_nLcT262]RCh}C:n8Tcgehi:gThT{_{Q1{S2{gTuTC]C2g}8_C2nu:~SB\2}rhQx}gS`^2ii8/Bg{c2^^yT_}ycSxS8Teic1R_>gTgyT>aT1C~y\h=~a{{c~ghec{~y2^8yQ1{S]_6y>cx^x<^8Sc:]BxLg{]R_c:BxcgL~B}MhS~\1S]˭dSg=1R8y.R6hQ\n~ĸtv䵫8S]A}if *Y/5aac]BAS]Q^c\BSThBQ8T_gT]C^]]__TR,.B1]~c\x_\{=2T~_^R^2x}>y.B{yS]>=eyS<:QQc]CrS_iS{c]/1~2x}nn].QSai:yx2gSAy:^x}6ARhT]cSCRxxCcy6]/AR^28gC]SC{nii=i]yc}}_}cS~>=T.Bi\`1}}<~}S\Syi}`Q2A/R\xyh{Q-`cy~<]\yxBQyySg2cyhr_iS}S/QxS{Sx=]CBCQS_iB-__C^h>_A]_2Tncy8__C-R8}Q.xT1]icMh]C\`{^2=_2{cSBS6Q]n6>i^C^^_u{CR.,Q]SThc]Bgu}CyA,c^]SghC`^=].}66cy8S~g_ccSx{^-Rn],^gynL{:uhSy1^2in_.S}S2_Qx~ASS,xx\]h{~h^SCC^xc=_]nTA]]/,QC^Tehc1B:cCTA,}^]{:x`_]QyTT~i>h{T}h:Tegy^~}BSuT,^hM1/^ٲ*yygceyM]*tΧʵϷĺ*tWie\\xotĭ)TTTwMhTxx{LSS}x_]x]xT8]}6/`cc{hc_Bi[R18~}=ehABC2T].\{]iCAxThg1yM8\Ty^^_1A\TchM_Tc8a.`^CC\T].An2^2TSBT8hQ\_]c}]grn~y=A6R,`{~i~112BSLg1T}~_A]8Mge8]{^CxC{e]T>C\8n~]BhwARTg}TghS21S^/Sce~B^c{hynnn:]__2hi^^~}_<}TccRh}A/areA{7QS_1AR}g>TQ^r6Mr8~i^R:8C_nnytܬݴby1QAB.1BCFtħׯ̶ᵰ˴F|kvFQ[>cA.Q]6{R/^>TT{R\Qax^{Sh}CcaCSc_RAxS}yB^S/Sun1\{T]2T}TS^~c{8g^/BS6c{cS6T^x/B^RC^ycR8nh}2}T_\]:]6h]~:8M{\ARy`,]ccTihhyih/Qyhhn61/C_^y{=u{`B28c]/]=<{S_A\Q:uuyce88xc}B1SxRAx_TyB^S.2^RT}_{:{]6}Sg^/BShh~h}g}2C/B2C1{~h\C8nhc_c}2A1hM]T~R}gac2]2gB.yn:~:~~>8x:g`._a~Zپ头W={{_A\Qhβt*tdt˭h|3|@iiaS;icR{gyCx{y]x]^a8CBx_g8cQ]~]]\/`RT1CCQh~\C2AQx_1}hh~ga~B\^A.{S^868yC1SS1Q]:^BB}Tah::_S_\Ccih=iSSc:2QBxe~Rxc~2S:{Qx_}^A>hA\_ggSgy5hh}ihy^8cRyeTCxy}_]^_giS2y^~h:9]TAC\BQ`Ry]1C-/r8C]{CB_}2ch~6c6B\2xB}T_h~gyC1{{]AST\R6Tahh__2AR6=hT=ThC_Si7}yRenicgTCc~yh86c~c}i}2g_/Qc^TTB.Ax^<~\ShAQR\_]MT8_a}]hhSC^_}T//c~SRTgT_SC]2y~6={C1ScayT]^h/_rMh]QC~^-]i_]ghh~xB1cCx~^}e}x,`]gc~SRy:82\S8hThL~}hi`ByCyhSaMϾݭjn{:SCyiitĭú˺ŬjLB]I,p\h==C,.cTx>CB]~ghinc_c\}u8hM<~cg^\ACShyy}S\R_c=h~8^B]cB,\S_21\_[SQ}MTiLuy12y]R_ghi~2T>S,S_x{i<,^i_,.R]xC1_{h>~2{]/Q}r6T]~c}nc~hC,`{i]Agh:A,.gMg_1.R{Tae:2x{Byn::}^{SRAR1Se=yy}yx]TL=hS\SeQ,]xC\B1[SQygM2ernSC2c2\_~hic]{S,_:_CShhQ,1LM}`Q^S_]2ya=McecCxh}{B1a}T=IݭgM9_M2Q1cꬭdo[S.|3wuA2T8ec_C2}:cR_gTc6_1aT{hxcinrMegic_^xC^=n~g:aB.R_2c~~S_^Ax1}8]^8yBg>S8rMh_CxS2RThc~RRLg^~MB_iLuBBc~ST8g_2i8]c].\acT:\^S}c{6^x_~]TLT2{{1\_a1]6Q>~i>MLa{c6c2]]A.ng8i8\Q]}y:hcT^BRR_h}RC:c]/T]}n61ARS^Ry::~8nRRMcx7n~Q2:iM>\R:c~hiccyin}]=>e^S_R1ܬId}M6S}սحtIڧ鴦^_=n6}_C^i~R26{{_1a~AR]TT{TS2~72ng{gygi1\CRTLuTTy--A~_{:_ax^T6~68g^hMhhARc6^A6R]hg{Q\~8un}\./Ta]]]-,y~2c~T<>}_CxghTR2hiSC_Sci:hA2yShy`2_xgrn_x82c~/SnhC]_~g6~aT:TL:ye_}8\B\\_<1]],,QTg]^g^yh\x{6gg8>h^8ug~~BATg=Lyxh^_igx_216e]xcy^6g~nLgB,,S88_A{T{^6yg~hca]-R~cTy,/~/˹XhSh~voϴg_\C}2QT-uKri{~nRQ~>~SBaR_{M6B6iTa~c{Q1]_TTg^A2^cc\SL:QBcT^{g\}2{yAB_:urc_h\Re{a1Ry6cR{gT>hA1~M:_i^~<_].,^>}_ghcQ\~cc~S}h6,\ahgS]S8he6~}\Bhh_ySB]}e=i{~*ݴvn^_S٦ϭvtou:}_iBRW3uN6iS]6xC=x~R\/ghgS_r}cgcaQ2_^ARSBQcThLhSgw9,{h/QcB.ii^]Tx.C[hCcS2y2rS:<~_/]~Mna8u:AC_c8h:R1SiiTQC]{Mc]RB/}=gCx1^h^26<1]hiTRC6}Shn=xC=:\]gxQ_iTc_RA6__ySS`xxR:}BR_B/TSS>a]Tuc-~BARQnny_}1B_ui]~:]1_1>RaMcT]B/x}M~hQ\]y6g6~~nx2T>7Qx2TrM~_xB/}==gC1]_i_SgThL鞭obرxĭVr[R}hxRQ0GT^`C8QBTchgC^h~}2~~nRR_^SS8_~8{=hx]}R_i>h]_n]=]^\Q:8AS~x,QLcCS~8gyu{`\n8_=}]y_QS::~{:r~B.S=hcAC}{]~SQ2wx1A.cih_RCxy}i{c<~}^CTnˬܲt`߰ܭV`AcR_cST|3N{Ln_C_SAx_xTT{g8hSy:]^RC_R}M^C^2hy]c}iTA_CSgR2SA_=nS^cB,ca6h2^T}6`,cTMT6{QTgx_S1g-`A}^.-/T^\xTh:nS_:\A]B`\8RQxh=A_:gn=h~2^gMhc1guuyB8gx~T]gMcTccQxu6BQQAA/}:~^^=g{:wMC/Ax_eSagSxA9hT]}_A_iyQx:nc2}S:-x666nh2]{Tt鲲vU6_eM8y}8<1|uS}-C:{Rxg6xyrTB]xCx_Tg~]y~yhh}_y:]Bx{hS~]Q_Q2hy]T8hSQiyL6a>iT=xy~chh^A\{y`-2_{SBS8QB.C^.`_hy1__xCTe{,A82BCgcx_u8iMS.\AR]_TS]8TSg8y]S:]Bxy^6yBS{6hcce>h_8}hTAT],-_acTThTAShx..,RyB-RhcncAa^6\2_,/e`,TK8uhCci6g~8_Ay1/xS]\]yxB.QhSg{ByTR2{{:<8>65}B/y,-}>g_y2R_6yTex^x.,/=Sx{__h-Qh2~MTA{TT8yT6h_c}_~n8TA}1,-}h6S_c]a>SBQ,y2Sh_hh_t~RBa\,-ynR-x2}Mg1g:B-y>>h2Qx<{Bge/QSR`Q/Q2SRxh5ByS_ST~_nn_R^{h>iMeA_:T}S/^2CigTi:i{6x]8R_hhA,`SC__S>~:2x{cRR{TySQ,B21c6~8_~}Sacg^T--Rcr1-]_ynaRc=B,_ig1`Ahn_BQB{x.BQB2_\Ce{BSTxC^TM6_{]{6r]6h~\gne_{ne^6c~C魌2}nh{ic--A{u_Q2STI3Jx2h\QA,2~T~S.\]C\-,^h~eLR1T<12}_~]^\/cS]c=}2cR.ahRQ=M~yCB_c~cx{21T^2gg,.a<\2cA{igS1R.{_]RR6yTB,yLMSAcS_cnMBRgCeT_{ncx]Q{gc1^h\Q\,26ya2Q`A:CQ,,C6{yiyQR{ihRx{_g^2A/Ba:{{S8ngc^B=x.c:g}a2A}:L^T2C=g{n1xcc,{1S~AT8{]C/Rc_]:RR{^SB,{L_gr=cchLSnMi8M~BA`1ykˬgB.6i:Su::cy\Cc~*oT~^\]2Sg~=~R1x\cu_d3wL_{S2CA2:9SABy:{Cyh~Tcccy/QTc]gLT]LLThhnc>T_hg^1hh_~=gh{<6y>}{=i}~hc8>8:hTT_/cw~A1yB-1}SR\ceB_u2\c{2T6]]yTc^c<=2B2\A~=xB{S^cgRc:nyg_grc{_TMe6~68>T>nB.h=6x]_/QxR/R6BCa6>Rynh8~i6]1Q^:ay}hg^/SMeQ\8M^BT}h6{e~cR~~}hCAC{iySFN\i~nScu:i:ic_i.,8Yg::2\Rx8hS1SBT8x^xB]6AB6c]2a^/CB~}.\2h2\_\Q}c{6BB2^S_\B.Ac{_w/CCca]{yCQ{6]~nSSighh~2}T]{}~cS^}{Q^2A]i{xh~M^Sa=g1ci8_T8}BQ}:i>^|tvtB~9TAxyTcyB//A{2i]:/BC.0uO\}hT}6S^B.RT8ni]^}Q-Th}cg^_i^/S]2>c\SR/:Q`//chaS{c2a,B8M>R^iLyA\/R:urcx_g:T]2={181,/xRB.2i:~2_y:_S2S8]{h]B]6n1i.`/}<.B:[M2^x1]xSnS/_{i8BRcg^]g=e}cMS^=i\-Q]CATTgS./CSCB__/BSTgig2TyRABRT<~\C._rcCCQ1cx_86^Snu{x^.\_^CBT8c1]Sx1C/1TCcSxS~h:=TBcrn{\x~:}h9^SxBMcACL8c}c2{{S/Thhg6~T.-_8c2]C\=u{2c]6C~{T=cC2y:RAyg_A1=}T8_]y2\Aa6A/QRccT_/S_8ML]QSinx_>~]86x]{cR]T2}Mcac=icghah2/bgnc]]c=>g:g]_RQ[y`M9yi{12^2.y:8acc~T/.yh}1C\Aayj˴do.2^B8r_Bcnu[uS}r{h2BBx^/BySW-ZB:6Axc8yhrTA_gLhT~a/-STQR:~gT{TgySMTC_]^gh~:g18{._ygneQ`Bac/x}1_>}STySe]1i>g86~c7h~}.CLi2--B2~8~~~x]CRy:6hM6x~6hTQgcSa>{^SS2~1Q3wLAa2^eC=]{~~nric:hQ,_y`A>ic6hgi}Chh6gr8^}A~__<~A~iC_TT:}iiB,Tc.RM:}SAa6c:cS4=urT]-]g:T^\Q}n~2~2`]:iMB/RAQ^yc_y>r=ccyc>^/_A_nic~ix{VR״~riaSBB{i>gT^CuiT}Q{na}e6\-1ihi<]TCBc__hTyS1in,_h]C]}i__hT>LRBARxSh~\Rahhcy~8S\-Ah22RB8_~Ly1gR/~S^cg}_T\B2^6~]]hAS>yyC_h6T_=R`Ry6e2,S_h,,R\^~}yc1}n1i<^T\/T]^eSS_C:R,y_]Sr86>SiBQB\]~Tx9iga8_A-\hiSSxBhnSa{xg]TS~y^S/RRSy1_hASmccLr^/xcc6~1,^]6i,A1cSST]6~TT1T:__h_QA{g8_{:h~6Z鴭ݴy5~i:e=e_A_n6c_1>uagS8\/c_1y6d3]:yc~SM_^\.1hT1SRTxT~6}\AyC{C{xCx^S_-/1xB]hn]CyxAR]C^ABLi8]./Q_2_iL86c]gASixRgr{R6_Q`yL}\Cc:c{B`_TR~u6/QBR1R{igCQRSA2}Rc]2g_C_eg^]]B]T._g]hycMeSrn^1-R~SC_\wc2~g_SnSe^8M2\QQAR]xQ.Q2_BR~x\S1Rx_1_eBBn:~^/QBSS{6SS/AyA`SixRm/g11~ha52.,^_B}u~/QBR1R_gxA]6_c2hSScx]~~^1]C{~/WϬܴR]xQ`S{1Tc{hy^_}ScxCix`./]]{m-H1=g^i:5ic^.{hg<^c~h]]eyR.cMT]-}yc7>^A6TR\5TRC6yg_{22~6^,1}:6Cxng`RSg_~=2^c1ncyS11}yB6TSC2h=>1TA`811RghRQB2R,/2xci1}n_B{gecin~xA{/B]1~_TM:yx.,2ac:]~h_Si:yCihyBc2S_}n:CQTiyCR__B2g]T^{2]{SiA,Ryh8]Ce.C2a1SRR;c1incyS*|hna1SiiR/_Q,8n22xiCQBS_/x8}i>{hu~x6^A6cR^88_^8~iTcySc6n^,28n:}\Aic.xA3JBy}C^^Q]Ty6aS_:^c^6iBA}2QxcA:C~<}2i{R{=r=S{6{T]6r~2\2A`\yMr~Q__`S:CSc>~{CiS8}S_>nh~2gTSi:T6e{6tݭ豫*2i{R{>}ci~ych^g:SRiwgRy6:~1Ai1B`0rQA}2S6AQ}i8g:SACBR~S1ec2_i~Sa2TurB]McBA]8iaT]1g.]@chah{^enS{S2ShLh<~T8A/_]xC2r_,Q{2B.`]{ShgSRBa}yS]{\xi6B\~S16BBMg-\i^{a]{i21aSyy{yM:aT8\Q{S21дd/.1__8Lc^^ChM=68}hSyLi^Se^T_A8urc]2y~tñv魭YB^McBA]icMugy11:/1@ygi}gM1\}u=_W3LAQy]R~_`^c~=1_~}8h}1]2RSSS{A\]c.TS]yg\.~1A\_t׺|ܴoyT_]:ni1{g{h~g_{Q:>=],2LS^B1LX,2]y{C{cRCB_\S}_LnT{^SB.^^QQ:Mea~1hn1B_x`.-/^=h]:>]B1~>c\\^{cx9^R{yS_/_cRCCQ^T^e:hSSB`2yxQS6/Si~y]CTLT{6c]Te\RCASC{aSiM:6T{}RQ{SARuh~chSCA/^ny]:_x_S1^TT`/y6~],,Qx\Rg6B}i/BSnM]BxA/Sn]M{\S:na\AɭvnhSS^61/T**WAyia_in=ggx`Sc]BTB-}>gT]CyvtjSS6_xR\Q2n}^<{_}cST8nQghhS,_1^iA~>CQ.xiky7^8:{aT]CT{.xh6_gn~C_{\/T:~hrS]g]Ai~.1}TcccnML{/2:^B]_1Scyg{SR._8TySR`-Th]TyBC~gxQy_C_]~gAR88hgyABC]\]h=ySc_^B,CiX3uL]T]MLi}{TA]}R6/Ch{{_z,Q}cn>hRhag21iSSagh:S]i~M~_c~~}^Ti^2>_\2{T6{RS2_=gnnayyyTc6hMBxi~AT6\aoWa2ǬcitvC6VIoSRg>6S]ydzt`Ƿݧ8i>\hhaeTSacg8:ic{nMhLT1{}a}1{Cxk3?YS}RAnL{_:g}8ABc~g}A_nng:e/,ACShnu2]^}e8c{ny\hg]TTchc2y~>,-ci/{Bg=1AC]y^]cCB_^C8r:gg2RQ/Rhc,{]B~cCeLSA}T`Qc}y^C_yScTa^CMr__:~ch\Ac~g}AS<:Q,B\2<8Snhnwh_L]/_6hS16g~>uncR\1y~~S2yAhc1yg{T:c1STn`.8h`B_Bg=VAo`tLXz*魤tt}j.BWWVko*ox8nnn{h[}nST\1iyC6yS>gSg8_/.BR{:h~:cT\cAB}Tgii{/`1:_,/\Q/]ag86=n>ighhxe:2SR/_hS\~iC\Q=x`2>}1xQ{h{\AS\1=g7e2BCgTy^]{TT^RS/STC{_Q2SAS6`.y2]~2/^MSJiB.{yy:_6h{A\6^R6yB{n8{ehSQ`/2gc{aS6_BcA6c8<{/`1_,BxQ_~~T{ci:68~A6~CxQ.]g^AgiAB/_/T{CCQ{h{AĬdDY~SXŦv4o/˲t秶oV6ahThyA6RC8C{_Sh8\Tc\2}_^1_T1x]y2Q]ncQxB/]ii}x-n\BS2BB]9~RBgn86]h8SA^hS,1ncc]_~_nnRB^hSSA`SygnT.Qy~ccyc{C~1S6~}}}C]T1^rx8S/TgQRr:R^^.`1i8Q18R\T{`2na\_cS2^y}1BAC2R`A}yB^RA\Q^cx`nLCAySRA_~}B/6>i~hSAc8{11e2,C=yyC^M<~inRB2h<{AkŻtbڲzS`˭o˭ˬĦddoCg6\21x1A{_QCr]R{2R\S86\B8=iMy\~:cd3s8u~cTcySgn=^ST26g::M2R=T22~^h:aS]}g]-RT1T}c\2ic:c^}TB]:STr}~hu~Q/cT__n{<=T_y6x,\{Cy{{L/Rc:c]{SBx:6~n>^{hi~Q/c=cTUoշӭtvٶǭ̓ׯ̭ײݩڧBcgr}/2MLeT5Mwg^hhgcS}e^`R{cTL>Qxi8c:_ch^^i~g6^eT^}Tia.{6g_g]_S]S]RS8]1~rC,T:a_acC\RST]2c^M_{SC1Ry^_~}~~^cr8_}`{g2h9T^\hnieS.}^{2.]2:BB_nexA~n:TTcyxag^_{T{:ch~eM^Rhi~Mui˺嶭贫˴ٲڭ.ǭ٬]C{iiSS:2`TiyCARy8{T6_WSBc~BT{W-w12A{ha>S\~M<6]}cC_}6r_^^hna~nr1{~\QSy^A2uM]Q]xA]8niSRC_ia:_Anu]2achTABxQ2hiaRSun_8^]/T8cn]]hT1ww^S:2i]Q-gyxn_1]2x_nSyn=c2_Q\^_M>]2^h>yyh]{~A/{cSCS1B_^C_8n}]^Tnh<_n_S6{h6^/BxQ2h6xTMS]T{C=L2^h_\grM*.կܶv˴ײ˴Ĭ7zVmX1yr2\UWUD:SRCSnLDqX**a{h~_QA_`3?Y^_x_S]:_SicwixTS{hS~6{SSg=niTnc~c~nh{Q.]iM<]AQ`1_wn2]x^8cSQ,_T\2>Mrh\\.\c6],,ycA_8}S61,`^TJ]\S1\h{L{xy]nia1Q^SiS>{1cx-C8iyyMx.2AQ1_B.xcT2^_xS{]=2^~}w8B2]]cxS}{21{i~^M6~}gTAQ]hLCQ.,xSiwLy_2{ieTB,{cC_iu>yR\.\c8{`,~xch~iS.{gL^^\/Qg~^T1*ڴz̲鬭XskRB_ir]o*l2]xTtt_iu>cC]-3uungghTg2CRQ2ihTT}__cg^x\.CyC-`Rcnnh}8/,yy8SnS/Rc2C}caL>]R_]B^g2Q{=geia2RxB_uc22~S]h:{c8{gL]y~Th6a8gTSAQShe]/{yT=h{2xQ]~1-`C~x,_cyn},A{2]6iLuh}icA1xBR^}y}i1huMn6:=en~CR{>]]nigch}yg6yy_2cc}{22~ni}yTgn<2}8y^6}_y::1\xic-/^~:ncx:Sy:2Q2~<~Q\^yhcgA/~TR/yy_x`/exB1RTuTy\c-\_2}SA{iA16_S}yaT}nu=~TRBxB.2}\18T^~Ay8h:{ya2Si_Swac~ycT{]=niy1~h]RB1~S8>_]ggLT28nTgyhL6}:nyAAcSA1}~gA]{cy2{nB^c_Cn_S6{TSxh6Ra8hcxShe_1]6hg~]]uLyQhe,-BQ_SxLy/x{1_]CA.^=c8rycey^\_Tn]B21xgiy1C2}Bii<}S{~eac\Ac_Ai:.xRy}^Ntoʱ϶ݬ筭`籩ĭvcS}LhBR2RBhnQ3Ps,/h6z-/hB`A/]yBQCTS~S]]_a=~y./S2{ha]CS1.Cyc_C]Te2cTc\TSQ]niy{2aC,1=ac_B]TR/x{8g8>rui~g=c_]r_/S~yS^RAx~]_Sx_1B,,BT:yrg>B/2~Liy{R,Q>\/RnLR/xB{~RA1y_6y2Sci>=gyBR6T6{^}]/]T}^R^}:Tc{C}{/]r6cMyaA,2n8g{\_6CQ^Th:6hyxRhn^QyLc}S^C2::V*cT^{cQ,x<|3,Cg~cQCc.CCcc]21^8i1``-R]gnn^QB^2M8h~6_^1A]AS_2he^{8_.ScC{8y}c.B1RT~Sa11AC\RSScha^xAB~ix:u~{x2:TneQB/Q8]c>Mn=ic_1AB2i~RRy8{_2Q..y=nMR,_:~RSQx2^8g_Sx]gn2//Q_SgnnnhyRR{ywnh:~c2^^xS1a<_xg~x2c].yh_chy2CQgc:aB~M}S^S:cLARB]cvtܴoݴv|_~1}cy:{.Bx`0cCcn~Q6ehayg~1xgS]gBQ`Q_^2c_CS\ThngLnM6_6~6\}i^S_TSAyhR]aAScc~Tg7a}CCSihh>gTyBA_\\_RR__-,2:>gc}RSCxT^]}}x.,]:yhhQ}8h]x2^MaRR}S{TuPZDͥݬʩݴ鴭o{8CaCce~8chg8e2Qu6y}^28:S]hhyyR~6^\/ScA>r}}S168R{McT22/R2Ry6rT{8^bh6Sgn]AT^{=y{c6i_TiTcc{y_S_Rcgc~yeLgRyn2QR}yg\_a2i~r}~\_ehcRSiCa>:>8ccT_yT^e8/-xT::~T12iTyn=Ti}Cgg2RQ}h^rTc{1hi_g~}y5B]MrT_8Ma6ir{{=~h2}RQ{_y6c~e>TCg~gcTy_S_Cc~c8}h^~yQAS{T8.RrT1}guR2gh}\Sc/2vtttttttod#_R6_{c}gg=yRgh-=cCAxy{Q.B]T22A-^h8T8~~2xhigh~S,`ceL2_}>BRa2R22~a6Ln}~_2:~ScSTRQ]~y_6}2xR_gcaS/^M2\ah:Tyg:21A^nh]_MhQ}rMg{yyc_R2>^/cy_{^15h~2\\S~1QC18yA\2c}C\]2cA_2\`SRh}:h{1:<8hT`/~hn}ahrw\]hy^y_Ty{=_}__hT~Tc]BSy_cc}S]xR_gc6yB_uT]hiSSy}iA~Qx=gR]n88uhT{yc_A2gh,^hS{c_1_8~2\\{g*`7gr~S_Tgych1Q{gV-T>8TSc_B]R1e{/SM}RA_g68e2S\SMhgcnL2\S{{~cA`T:^^~Q2Lg~>:Sc}_6~c`,}]R11\QyL{xc:Xڭ宭ݴk}~2~c6SxS\Bh~x2edu6_M>i_86yT::12yL/R:ae^QB/^8gMR11>h^-\hha~}8hnh>].cc]Rx]C.R_]2_hC`2^Tg{gni^AA1c^`C{^2TRB}~hg8>~gcCCei<8\.A8y/2TxcnMr\Ch6}ccS~hScc^~MThc^guy[w~T7ih:1SiauQx:gcS]hBxxAC]Sh~:hx,]\,^c{yew=aB]g}gxB6e8~}^B_x1]^R}ghTQ.S]QSBSh8cyAc>iny116o㭭ݴ,ܴ-.t.TM[x{{]]2{hgC,_1,x|M25=1A}iB-_6A`h=2_eT/-}S.QB^cBchQA~cQR_C_hncy62C~=w:hiL:}inc_c2,B={RChhh=6_yTMu^`^RxS2{1a:^]CR_6ggc=c]>~SQ\}8yc~>}Qyx^_\/1}CRB]Tc6T:c^Anug=TQA{]]gy~Lc}86_1ckoﴧ˯xgw::M6g=i2cyAmKRxichSBSTnx,R>~^{72~~\{2B_c2TTRRccRA2~\/1{8{SgSR]iT{_2cSShn]BhL8Tii{{~}~x^c2Q2RS=~TMhgCi6]{ih].~eh:hgx1]CghRCe>yBR><\{Rxi8u}1eh],Ca]{6S\i]~cA{c2TTx1ga\A^LaAQ2}:S]c]QAg~2^]:]y2^6iC/Ti::hLhhgh_yh}x{C{>~]Cia8cQA:}1S8].gu8hi8aci6C]Sy>yyM{Rvt˼̺}R^iuicyS_}_2~u_AkLBB~riy^BxA>:x]R2hT^_nBC8]RQRey\{SB2Sy6hy/RCC:^6}--/6hA~=]}6a~:nT`2}\/\eLSAe6{S./A]cgcCQ6unMccc^_aTT_2:}-]h]Ax}}SS~:]Q/.S>6\^Mr6^/Byc{]TB~u~T]5_1]R^hy]SMC{h]R/\e{CT_B]SSc{B1]1h]}y-,`yh~cQa\Sy{cTc~yS,Ry]]R_e2h6cA]Ti~1Ber_iSyyC]y{{2^hT-]:^\1y_1]{g2B\C;S~~^/ٺݴvto`oI;:\81yTycT~~n~.)3u\`ATh~h\AC`8>c8{g>_~rhr[2-T:_6x-S6cn8B1^Ayc6~^/CeS{TaTu6T~CS~_88CT_6<_^hhSA.C\~:{}~y1Sc{_./y{}hiyRx_x\S~6g},`Tccchac8_Sc_7^^Ryc]cehCB8hB]62=6yxCSg^B,1h]{}Tc~TTQBSihr=_8iMMiS.R/2T>hia..6S\g_S]Ti1}MirrS1y8^Q,\T~M>R_>hy{T6yy/Q_cnCTenCSxQ{T.ӶݴO*彴h:~SSa_Mc]_1T~d3:h]_yQ8^^2A1{}in\TRA\yx,Sn_Th=c2BR_T.Q]c>Tx7h1QCggMyc2{]B_/3}hC.86.^=2Ry_AR_^.\B/B}n8Q\c}ii~g~g8ic\26R-.g~QyiSQAS\}x^g_Ax~hxx6_T{_T2c]R]Bx2C\Ccxxhy2e<_hi:}RC]ASc.,a8B/2=}]~i~g:ScSSaihg}yh^Cinc2hT:ic~hR-agBa6Sh~1\R_i^.\Q/BT8hA1n66SSSSTa8T\_~R-`g~Qyi{BRyRyiACT2x_:=__hTgcC_172x_A^S1C182SaS8i_hhiTA\CB_}-,}~Q.^yB1ccy61=rS1xS~~~hcg^]ftܶ7c紴̶d16SC2h_2y~g{aA,p]~}cg/Bcc__2_2RA}a}yAb:Lc^n>TTgcg=nR_n6.,8i-{6hh\1exT~2R\aaR_c]^{g]\_^hhaga1{g1C]e~C]S_]]`]TR/nS1x_T8<__8_xic8__hhS_8r:y\RxxTc{cSS_2}}A]~}SB6<~~TB.1n{}T}n^=~}c_`]}R\c~6y2=~h1SuMr6ABR^]CSC2gcnTgiT^6M:S]]i8]y],,]]{8_]~~}S}_{n5ygQ`~=T,}~SC1~La_{c{^2TcRSMcRh:y{gyA.2}n6{gxy^A]{1^Tey}n8B1n]g82]}}n,-^TAR~6RSg]8h:___ni\{h_/]ca;C/]S>i~_CT<~a^y_\Sgh--inA,B8{y>T1e8BC8_CMMCS~xR__:B,`_~x]hh2a<_e6~hg{ui~hn:_`Ag6h~~216cSTCCe_2giy=ott孭ܶfur_{6{BxiMC_}S~B2>cS6gxR2Aar6xx\T8BSx2=}8hhhrg]yTCy8R8ax8Mi=_Sghy]gcCxc~>y16y^{c8}BTuT{A\SR1~xA{~n_^{nTg:iS}nwhx]Sr8^]iMccihSyC-1i>C//`_Q.nCSraL\Trhc8c\QC/SyC]1gxRc_Ty8a~g~Lc1yTRye\Bg}RgMi8^_}chh2Cc{AS_8h_/vtXy6yR/?pBSyAQS~6B,.}g]8n6}yn.]Sxg8~S\AxyhrrTCCS{_]ThcTcy=iB~h^22B/^}~]A>}a~ic^TyS^T~yi6B-]y2{6Mn8~:ey^]a>]Sch}BRcTR~}]Sy6h]^6=SAaLi]{6Sc2-Bhy/Q_~SC1\Sr~:hhM^`^R/~r8]SLR`,Bx/,uc\y}yS1Q,Bc=ych_R26yTi~\{~CS-QM]B_:}}6gcT~TAQ\]^RAyi~T8i~h1_n>}6i_hM8gna::SRan:c<]/1cR2RR6>Mi_/]{B,B:uc\{T{y^Q,Q_^Sa{x_gTg_c]T=`/LixB2hTyec6~e8xA]{y^C}i6y~h}~hc^y6C^}2}hr2-_iSy~\Bg~y2~CB2{CS>1_n}Ba:^~ncy:}hcBxhc1A:[}6}ncx_}}y6i{Axc{cM.,ShS/}n{S~2C}c{y~yxScx`/686:c2_cgS`,x^_^gh^Sh7.Q^82STig_SB//x8Sy=e=nh~}\2hS\]i],^hi_A]QR{1]c:r[RAS{2Rch{^C{g}yc688R^~^Ri[6g}>}C_Tc}8ncx]}S}/,S:{/cySyC__^_aS˶٬Ƕp8gnn8{eTSڬ˴ttf*.r_\xAAR`]ni~uTB}h^_A\^]\crrh_g>nixSh1^yCQQ1hT~x6^11__81Ai_]h}\,Q28h^\ceSh_]hhy]yie2_i^y}hTg8Tc8e^2{~{B_h8RB^^_]BQ\_Sy6_]CB,,-QRS}ehhS2A\^x{uy]yii2Sc]ARSe8BRc1C^{S:n]\ii^Ce6R,Q2e^Ac{hi1\c6{]c=hSS=:_T5~h}h~8i_^S6{B_hhC^2_1../B1^S}|d٭oV]ATLncCyiWt魭Ħtݭ068=:n2.^SS<8T6T6~grgRh^2ga/S:h~~{2ccr]T62TT}2_c]C{2Sg_n{2Sge{xSTc8x`2{R2{BR~gcygcB,RayR`,_{]12g]/2hL=:c8CQB_g~~_x}aC\xS]{}ABA]]Sc=c~~gi1/2S^h~ScTc:~guxhn]2aTQ`2ih=2_~gu_68yg=e__}]xy_{62>_1SiTCSTc8x`2SA1^.Q{yyygA-1e}C.,xiic__{h_.^u==hTxBBSecS1Sy\BݱڌݶXS6Q-^6cyy8ru^bݭoJBSccry_xBShTyC:}^hcQC2nyn6AR}h=:~^/CyrM1xc2S{Q1_Cc{yh1SeB{n}8hT}~T2Qy8_}T_{h66>;RCi=yR,,2>ri~{]gTC^{c:g>}gyc_ghT68Ty]CST^_T]S_yy1^1ecB_{ShhcS:cR]S}:8hc8Thc_gh{{mUkWADZn}}BSc6{^_6h~QA~]]nncASh6y_y=}_i:]~R_ec8ay}__1`S=M]~hC}:]^yCQ,_u=h{RgSxce}rgT]yny\h82Cyh6a>_{iy]TTcR-B_c_~unx{><^,,\<8R\R\^^_~gQRVoǻ˶oninC,`S}R`]hyx\h̽٭+1Sgc5c:}T~1gTx:_Bi:6.Rc^`QB^i~_h~cS,,{h}RTn^BegBS6nC^8~gc2:C]gMi2S}S^S~hg~h]h:h]iSB~hha.\88Sh>A,_6{TeSy2Qcu~g1\]g~S:=nc/Q_M2C2y8]SuRy1S^caM_1Tc,/T`]S]~gi:R`/RhTng}_BB,,{h}C}nIVmttĭݬvy:nA,_h~{}hSy^.{Ko,,M^^xCx]}ag>{8S\nR_~x{TnMh]}a2c2cwCgLr}TTCx{cTARyC`BB]{A/i>SC1{8h1y{/Q2]RB.B}L}Q{r[RQ}i_]~T}i~6rhgy8cx{c{Mh6R`1Ta6/]h=8n{CBy6Tic2c^1~S/\<<{_CARR{=L}T]^{6x^2hx2{xS1ynx~n22T]^Tchc\xyC/CC]MSB.AinSRx{:^cLg\A{2C/A6r~.]>B/}i]Cy__~yScTT^cg2ceyiL8}\-1Tc6Q]=ڴڭපtWy]ynxg=S_yRR_T:ڭ˩,K_]yT_1R]/1:_Qy<~_8icAcL~SR2gg8ay:CycR^>=h~}_A.{_2g]yS^LS`{LT{}S2R.{CC__cR/ByTQByuy6}aih]ALrha_y__icx2ca_`,xc2cneCST].xc{SRCTSxy6_\]A_MMS;ݭݭש<6_ayx}cS{cTycc8^6Lhghƿ(~h=TB,Ra{x\^ia:]2]__CR2Tg{R_L].\BB/B\R8S/\]Tcxxcc2y2~2S]~:i~yi=i_^hxcy:cA\]x{ca~gT{xA{^R~:]{TCy2}9RB{=^C_gy]cgy261{g_A_gx`BT2cT6c2]]cyA/\y2A1T<^xTy\/~]hnSA~Th^AnRa]6c81B{STy^S~T6}^]1ccRQRcSCyi^x}T`uT<]iyCc2aCAnR~2yyAQ}S1T~6xyy/QS811i]B]2hT_,,1hnn8i{xg~ѹ׬oI^B]cC-BT>_c{8ySSh2\]6yAxyݴ˴説Ǿ,+PN,Q__112_\cTbnnxC}gh6y{:uyC:~Cyyx\/BhnMi<6_}6]BC:g{cTcxr}=iBxTLTA{1h6QTR9xc:r~Q6e6i~ha{__c\8_TwR.1_Sehn{^{x]}}g,,_yRy_A`_i1`11,Ay_x1Sc]c_^66{TBA>{cM^-/iM>_B/1g~x2],-^_.B}6]CST]SC]R/_^_CBc6_^2\68SC~i1B6Lcy~xQ^]QBBAgLia1y_`2ic^S~\,`rhna_Qo,-^_.B^]ȧ`ǭŶDni^{RQ]_R\AReLigS~y`^ic>nhx_ey_S]^:n8T1{1c~x]y2c6BTMng]A~SSm-ZR}ny_{2Th{TTgu8]_~6TS1AAyTxSx`\a:uy2{]yc{2AAT=h]Q-xThSS~{h\/SrhcM6R}h``r}~g>=]yc2ch]ycQxa2Cc}2ghruy_A./BC__cM~CyySMgyT:=]aL:2]~iT{yx_~2__T}R]}ca}_xR}yR^1`Rhgy6S~6_BB{81/,]icMyT8SigB`^Lhch^B.i~^y8}iMn_c6]yx_{.Rc^R}Tx}8uTSR..BQ\1]T=qܴ-tŬ 1MyS}2cn~}_R\}gx.,1i}:r}cLyh\/_:MT~.uHgcchrLe_RS>_y~ehg]B^c^6{\C{^_6AC_Rych<]RT8}{^QC2_c{xRCx]]hTQ]11_y^\^T9uyQ}6/\2,~n1]82C8Lh2}8a]BB^cgc_h__Tuye_A___c.x2gS2h~2e_AyniL=BQ}hc^{h8giurh{C2h>}R1SyT{R/xT_Tx1T1]}Ax{]68S^~iic/BRR_2yRxxc~1^^BSLB_ix^:/yuw~\iC]~^1x2nnn{C8u1}_Axiny2r}^:hSRQ_]jjWU麵ɿokˬdCLiey={_}R/{^^xAngy_SRxhM~c6{ghnh]]^{^_~2A6}ySRS6yy}2^i^`CSx`Cb1\:{AATc1\1yc\8h2ccT_Tn6{Shy__8S]QS<1Q21^icyTaSTS}=6ShR28h{T:S,,\_hg:R_rh]Q18Ry8x_a62,1rec}_aeg1Sya_{_eTh}QAycSaT-`x{gh8R^enMh]Q^:nx}h]_cT.+LRR~hc_6g>c]~y1cA,_yA6hec}icnh]]SCBCc~^y6_S\_S_6_./_::y1Sg:ahxC1^M}y8cyiSS}2R^h1^L}S{CSy{~_/QSi6_Thne^12R_QQ22:MiT}gy{:cTh8.S\Qy9Q/26^R2r2_]ahS\4\.yh1Qx_1\x}utt=ymvRjyTL=T}y\/\y}xS>~T}x{Ty~_./_::c2}wi2]^B]k^_S2~in_x28a8ySL\]^.x]/S~{{Sx_>]{{\{:hTy8ecc\^e{_CB]y8~}~8y{g/y9~>C]gy22iy]]R.ARc8ye1~u~xSB_=S^ncTc~>Myc2QC6}~_RRRT=>g{>SSTC2c2S{26hny2yii>aR]_Q_n{A}~S]x.]<{66x1a<{^T8M~6C1~yS1A^cihg8n}}RQc~:R]e{]x8>c]1\.\CcT~Ccr}B]h.-Cgi2xhh^12_hMyc2Qx6T~ig2RCCTg{jt:h*|ooB.SnTecQB28gS2~:8gx^e{_C]}g86c:CBa8g-wr>c2]ye8T/BS{cg{>yei2{aQ2TcnryBynh_Cx_]xRn8g2]~_CghT_Ry2ASc\Rhg2ceT}S/]i^gyScrT]yx}i]R\[u~i:^_~2T~^}eey}:hha]ciSS~_S2C^\R}{6c{gg^2gh62]{gg:aQA}8cT8T~uh2T_=e^.2iL}22y]R/.gTc_2eSR6cS]~_CygxxiSe:yTS.1>8\{cycMT1{Rc^xC>u{~a\C{1{cxy~S1]}Ty:6]cS_62_i:]Ax2Rxc=Tݭ4c鴶x.crMc]x^C\//h=c~S_{Cgi>hT_16SR{~1^yhTcd3p:_]6}^SL{R1RS=}1e8_g{6uLMiiryQ_~L:T21_{CA:ha~yM}C16rg1i_/Sag2^~gec42^-`]ahiTS_gige^ThB,_ry_}Mg_2SS{cTgy{ecyhySB_hc2T~T^RS_2g{2SSQ,.6cS}ynMyRxgLhR^_/Sag__8:g_2]--x{:y6Ty_9i~g^c,_rh8}^C_}^]B221^]ST_yhTSg_2~B]gyS6h~S^}c7ݬd\2G˭׬ZC`cnhc{T}A,Qg~yaTTx]~rR2{/_ch}}heS2Q0ZgiS.{_R~=yRC-R]\gQC_xC2c8gTxQx8-BS~cgS8:1A}~}:c_h^_SihBB}2/\_>y}Tcghiiyx12}{8}SaT_6g{S1^Lw.R^{c{rwh{T_Syx]~:S{inSgyx]6:}7^6Mg{CQg[y}aTg}^{/{S]8yxSQS{1gT.A1C]y6T_B`B{>h/,BAy~hTh~._{_8T_g]^ShBBT^/\2STag:ihS\R\]CSTScy^T6S_]_MwA.C^_~8~S]n8_{^]]Bx}8STiie_6{x1cg8{::gSCtשּׂth1A5ܲ謬o-]2g=gxQSTScSh2_{<\Rg_/R_888iK1S^`8T_~y~\^_\c_A]BAAyyCBQx:hBQ,-Tg2]>yy=gC]2`Q226yygBR}}\`.Sw~hu>ha_}S/AaRSeTe_}}RShxQRQ\B,/^^B.-B}ncQQ,.6:h{2:]]8yBR^`/^^cS_gBR}T\`.26SyS~i<~R1xCSS_e8x^}S6}x_hh21{aaTeTQCMn:L6]yeC_Jg/o/cSBVoڶotBx.Bh>=aync2h}C2.Q2_~}Tn:\1g}R-.TLgg{~g2A`\h=g]_SB1nugxy\h>B-B1cLS8TBx_TAg}T6C,\Mc66a_yC^{T__c^{cT>iu8CRgg2y]{g1x~R--Sh8cac-unT}{g~6:}x.\6ii6gyT{y~ggS2hg~cyi:i^\M~_gi~ySceh>hhx`B^{_T>~R,.aaSSggh1^]]2Sih^Tcyyg7xCcgcS1]S2}a6~u\]he2u}Ax_\_yT{^^BgCS{a\Bic]aMege6h6T8{R`R~8:}T_2]^:i}yT1Ccy{_^gr:=_xh{hic{S~hnnihA`B^S_T6gR,.}hhiTS~TSyBAA12_h]]_^Tgcxxc=n8S\1R_S{chMiBR61u6R]SRSgy{~hin=1/R{cT9~gR,:h}yU0[>ng\~n2CS~}ig\BT<^Q{yc61CR.2g_}1.T}R__C8iSR_eS_i1_2/B^h2\~6AB_2\_1-/]T]hCB/QQ6n~yTSghgxx:TSyyccc:]1~rhC_a}hun1BT2RrMc{BRchy_g^/^MSguuM>cB}]BCySh8geyB/_x.^}^{TRAA`x6Sa^Qc~1y_^SxShy{nix22/B^h^\ccAB2^Ay2./CSC6Q`-QQ6y]]x8hg^2ay_2_22ecAAc~A^}Tn]}2CMM}SQRr^nDt˭IacM2xݭݭ˴/`_g{yRhr:^}S^={xShTTL_TTB\_h_A~cCxcc^c2.Q/+[i}hg\1~h^Ry>a{hSB_e]Q]yS}{TT5a{2yc:_~>~S{2x]xxc{-A2\~8QQRT]]}^~hT8yR}:hTg:{gcC}6\.C{]~]/S6C/R<^]_^8SS_y21{}hSeney}y^_r^]~MT-R2AcgQQRc^]ny]ce}h}xc8SchxBR{SQxg:g69wh{/6r=6c}{_2}gc^RrTC28ga^Q]2CcnLB-g81hvvgy86Cg:^)WtUm~>6MhTcy2_n]]6y`xSx;iQC}]]>n~Tie:}xckMcRAC^_Tg<~]{nR{}xS6{{{>MgyySiia:agc>LnySSBchxTg~2^cg_]~=}=6ca}}Sy~8~}_ae_^ih6\iM:_~i~h{e/cngTC}cySRQ/\~T~Ly_iic8~8i~_^Rg_^2{:cAB\x]_yc2BRcB^SC}y22={^_^hh}}~c8=ir>}cRi~1SnTS_Qy~RTeS2c~2x6TyT{{1x_a}2C_gyCAgnhiCCrS~h}g_~8/eMhTRy8c{SRQ.\~Tc_]hhy;k˴kRAx^_cghToooF}ĭsnMnc6C:~1_nTy5a:C{g~2]}~{{:LM:aXY~T]BR{rM6gngh}]T^{TBRaTg{TyAC{^]\RSS2ynSxQSr6Q2u88C:Le2]2S2A]{{}<=gSTx]^.QyS}gSy{A]}2xAA2^]Sny2A}ugB\_ggRh~x\x22RR^Ti:^Rcha11R\ch2\S1,,B}i{_ARi~Q2i}caS}`]cai_ceh~cAR8~cT_2c}{e˺t8gc_R]Ti<ړ.BV2CCSS_ynLT2RT~Q\_:Mugig\cRAR]1RR]{:Q?scM}^^\]6T}wncS2xA^R^}ASSy>gx~g]AC^,SxB_L^,Ah1{__eg]c~S7}B.CTghuTMug8:C]i:~ih_./Si>_SS\T],/2Cx8n_{{S66n~~gMcc{_}6Sx]1xS2S5S8c6T5}SABTL}^]A\^x1grw{}y2x_\Rg^/]]_aRa8_R]2B,Q^RB_LS`Ch1_1]T6eni1}h}1S::TA/1c~Sirrc6x1ecSgcC`x8<_{yRc^,/]RRgS}TTcn66gMcc{_T:T2RCR\bot\crrgS{]^y_SQbt_\-ASxBSL{`Rhx_xxST:a1T8yC2SQ`A{6hW3p2gM2T]]]_ch_c/BSSxuT{}~c,inT1T~]]\Bi11iSg~c_/QBghx2TT86]RRA`R2^cnc__2T}iin^A}~6inh6_C./C6Lr8c_x_heS2SiugMhRAyTyhpS212gi{~{CCC]U鴭_2Xܓ72]hR<>]1g1yS^R`/Q6hC^{T^Ty_CA\B`AiW3wKB.Tn~68}{SS\g/_BAhh{6rgBBR8/_hy^y6]6S-S:cT_iM}}~e}SQ}hS{TCx6TT__T]]h:R/STg1-Re~caR/6a^1yu]gC1x{6cgyBB2^]}TA:=inSAeSgLyy{nigC_}\]~_/`{ng~SR\CQac.]=Bx:_S{.BR8QSc_c=cRc_-_:}{^}__{TS^/yu2S_BS_{2Sc^A^:8h\.2S6^.]:gSe8S}Q`S_RCyi288BBC1x{~g}A{]]}yAAh=i2Q}c]cݬoUiyB/cMhLic2^boo}/AtɴϻXg]~>S-Sc{^e>}2]_S21/Th_{_QB_^]x^{CBCghV,wwa^{g6cx{{~8AB:gTh2A\g8\RRge1SC^Tc1y2,Q}1c}y:hc~:MTCSg8Q]ih~g~yL~RS]hiQ/2xc6/RncRSn:\22\A2_^x/_8/.cax2{,Qc<=]6=S1Cr6CSLC~Leec2iTCBye~>h{\2_}~B/:h~=_BQSyBRCeh\2T1SccBxy^,Q}Cy{2~c_y~:n_\n2cy-hgh:h:ghch]a{ABS]}hhhS`BihyR{L1{]\A2_2xQy:Q/ggC2y,Bcr:RTh1\9-٭g{6^\chLa]}tܭ`cB]^k~1y_,Q}CyS26T^_}8i]RnS~c`a6~~=gc6ghWrSQAxCBC}_Shch_hB.]~8\c_cc-xriSBA1xAxT2_gyg8^g2.QSg{ySgM~n>_{e}A_h]2eS2SxAxS}ggcc~^STR}n2]T~c1]yTSRg8{gc=__/_}>h.Qyy6^]iTT}^]]_~}xcS.{iS_\,Cn^_~^\t˛eg`2ry\C2^x2~yT_;Tgchϴ~CSh81^gS^_1C_{acyyT\1a1~LS^i{yhS\C2yy/3Lgg:cRB\B/]S^6C2hSS1.1hyyeSxS}y8Lx]~1SMr:}ag}}}2Sg}}8TcTny\hB,Q2y2R\2RQR^n~gA^8_T]/CAR_Bxihg{T}___Cx{{Ta^:^BggB,B_Ty]1y]A]{rhhR{h^T^QCBx.x>8h8}S2T~y:}]]{Q,1Tx,662^hfVQ2cQ`cegig]C1R_y_X譻t2a~}_cxSLrh~STc___RC_^]c=hcSye_i]/}T.,/]}}Q3?Z_2cg}y{{B\:^-C1ThS]MM6y8}{__yur]Cc]Q}:<=>gig]]ccTy66Mnr=C~M}\C~8gh1{_B21]cgS.]}cc}8iig`QhchcT:{{cgc\gSTT~_Ay>g-B}S61A}̶~]g8R`1SS8:~6c}\]IӶ{2h:g6}TʹbQTi=r=}~TAA__]]uySxQxxS]B]}S6^8J6}cihS_h=}]]y8TTg{ca\]{_g1`C_yeaT88wraRg~i6c_-/RRAx^.2hT.B^^C^_/2r=T]e\]gcCci:~8Q^aCx}8}}nnTi}2une}aS\^ihTcCǽ׌V]r:~2h>g~}Wx{gyyhc8gR^hSCT{B,QhgRxyS2Th~>wLaxhMhm-uLS//2y\{nSS2_RCA.xyB]6~c,C]cychcTccccxRgS`A\_:^Qc\cn=_/S~1y{y^BQhACi}^c:~^By_]g6aie8{B_nnx18y=yB{hg8=A]hc6~{{STS]MMSS=]xucB~B,xh:~g~cSAQQ{axTn{SL]]\\B.xSBx6aa`/^x_ecg8TS}y{SAB}]-CxSi^BhaB_>SBye\1x]\..gR]ng_ggcaT^^TgT]]ynnR,/An_B`Ry_M}{<6_A]TQ,ReTX˶^.S~]S_Sh}\RcTxT鴶yT_ShR.B\_~h}Xy6BBASn6Ch8]_c=_CSR\S{R,Qc6n_,^8d>n_RQr~]B6T}_\Sc{nuMMheT~2hhygSyaS}_-`_xB:hn}T{eh6~n_xT_:i.Sc_{a{^]gy_S{nh2x^{yScMM}_SxT2_2RT>y_a2A}]:iQAc2/2h{^Sa{SRx6^{TTn6]A,B6~Gvķ鬌R_8=g12BS}ctt tc2/S6gc_1AC_S{hMiyhhcACB3uZh6Thu62/Ry~r:ciirT,.}_A-6]hT5/A{T6]^6~uy{8-,]yRB1h_..x^BRiyyhrrg,.M{B_6Ty_S:hhiuSA6_AexC>h:CR_A6ihaSi8ARS2yaCRCCx_y]A-Ac{26T1`\ch8iL{,.g:_-B}xhncTQR}aLSBccSnnM}\1{RS:y/QT{c9/>CA{nTQ2}R]hgQBT1.hc~S{{C{1gn2SL{nh}62-]e_C{i_S~Mu>T/B{g1^nR}u_.RacCBAScTTa:hygLiggT}}S~n8^2]16}^~_-/C^cTQS{]rSAA_g=LrhBQ{yAgM6^^{_}]eayu6_Ra^6uSVŻmESR^2^\Tng6^yrcC=m3CB/B}gyh6/`_:}cTA^gSyihhc^}TA6ha2_{hr]xgQ/6Myx2T6_B_1BCy=h_A\1Q^hyya1^g^=CcrLc/]cQ]iAx8n:~g86x.^TRR_T>TB-Qhhy6SC/A}TCAy~^]:nhT^Rx~n2Q6SC\CyT1:i/`/_~c{c//}>8gR_hTcinCBQ18}y./6:tv=hch]2^]nSC}1y:RycxT{cyCyhTRR{1.y1]e^2~g_{c~R1^-:S2y^~L6i}_6^6gA_T:n{Sc^RRxic~~8S~iS}ig]_:}^{CTn1B}y{ng\,,]}Q~8/,\h:c^^]c1Qx{SR/B^]/}hRC8g_R6Sa=1ag]6:ya}1ciaxxT^/AcS}<_26g_{a:aAR.,/gi21_xchga{hT1Sn~rc~T]1^}66g_~>Tc8T\/x~_]SCyiJvnB,2nn~RR\S1Qx~6]BRySuLyynnLS1y禊~8~Sh_S8yA]8n__1xytXǴ^{]c~T:~}B.^_S~cn^h{iL6\-xa~inr8n1QB_ya2B^S2C\caB/~g71_1~d0[x\1y_AC~<62]TT2B_SAT_Bx_6.Q_2}>eRACS^\cic]]T=}^ByyRa=ABn^C~h68e_yT^Shi8_Ry~6{_i:2SS/ACQAx\^__c2.Cc]BBcnncnT=a{a~BQna]r>7hnWkl6lqVA9cwTTS~=_`S]B1c:BA}y~h]1_6~_ShhS2aMc*tݤC\MS^hc_xy82]_g~{ynghSRa]_r<~~cR\1SSCxST:^R~giu6CcS/A=hCS_R^B,]2RhgT}8g^]Thy:ic^S8h}yh<8_Qhc1}c^:^aMڬtt4{~}T.{6yCR6h2ghg4yunh2]Scc2xS6g=CB}ch~1a_`QhvWBcy2_a~_2chgk,y{Sg}Tc:nx\:nh2xy2_h6_:}^{R]Ti{a~x\yh]yShL>nuiC\~ya}T{Q_2x6ih81}hh=8{\{=S__x{T2xcxyAcS{Rg2\TTSQ2BQ1x^A_{/-Bc2\}cCAB.S}{6uhAQymdB72{c~xSaahW3wSx]1y{xS\Cn8.^yc:y.,`B/C_xT2`Sh1y_xc{Ly\1>T_/x^_nnihnr}hiia}x~TxyS6hc~rS{neA^n{6SQ}c2T=n6Rc8_~xQS8hc{R.-RB/T62-,.,Ch}iT}{^A\_gA}^Rx]cc^T\CMhQSce=gQ,-B/CSxS1]gR_]A_x~:x/Aha]1`AC1>na~}n~_6~iuhTyRc{Rghn{_c6n_Sn8\{rchcxirhygt~8^cR/]6eTSA.-RBQc~8^-,-Q,A8Tiyccyx]}h\6MS2S_66{e^_uh/_iT6B1T^TS/yi2cy^g{yB\:cC,/BR>:hh~Y6cc22Ay_ATV[L}cc622-,R:e~Q1cR-,.n:/6L_RaT2~{g6{S_^SM_\R{=rMhchg\C}]A12c=~xCx/Cg}~86~{L{x{iSAS]Bx]T]{hyS1CRAS_2S`.~]A}ccMnS.`{}y}_hn6B`x[wyTMBCTR6c]cSg~{e^hxRSM_\\_8iMTSh\C}]\BR^g_BBQ`Ac{}6TyS=n_C_:ig_5SRRxyxSh{Sxx]1}g~e\igxTT}_-_{ShcSL8B`x[wur_Si\.S8c~8gS\{-y>~cL}A,,-g.A~i~_cS8~{hTM{_ea]]}:i>nS]{yB_\BC1Shy\B-Qb]_{__^=]A/Yc_BB2ch~A`S{ir{1^]{2]Tg=yTa}2~{Cxiu^Ax_\Qx_]68yThgx]CBQRAQLuS{yQ.S2CiBQghAx^}T^\/Sn:2ScyA,.\}i=Le^~c2Tnx^{a1/8n2xT_BS~in_y~cR,.\Th6x~c2}^_c~]/8n2x7SA_}hgyQ1]g]Rx]˽Sc6y}6}_e}]yMny12{\Qx21}i6_g{gh^8B,B-2_a}2ySg=yQ-0w=cQ}g=}g{>hy2>gy}BR^Si8^R\aiy_{6TCRT^Tn~2M:hhTi{=aB]}gg8c_RQ.C{{__cSR^\,Su~e1/_xBinR\ac]{cA_S]yS2ncS6~8_B^A\1Q]>8_}y\h=R]8]2}e:~AR~h<{T]cMhge8Sx6ic_cBx_Sh>cxCR6g{6gBT~6gy:cc2C6_CQThcTTi=]Be^{`,Brn]y<1y{A{:{QCc6g8^hAhhy\{cC^TMSr}S:}{=hch2CTS2~L:C6T^a]/c_RSSyu8incT621a:ngccx_hQ/nT8hR~heS8TT_]MT^Bch6}}]Ah_S~`,BL2}=]}u}Cy:{QCa~gnc6C~gegAh}R}j|Vm{Ar}S:c6>hnc2aTnuy:Rc=}ehB{x2^}}}Tcgx/ScCBCcy_:Mhy,B1cnaww:nh2_i6]T}ch~2}\B8h2RuT1ih^A/^6S}S6g}`,hS6T]gB,/^iLc]}T]Scn\/x1AC}_A]c^xC|jXXuRQy]88>RC~_Tyn6ca~<]Q{~1\xcy_ihgc<^,QCy=TO-Mg.:]B]{The6y{nMi^B}a}::yBAc2]BRhy2^STT\Be~c{}x]g6g6S^6~_}xhBBQ.^u:T1ca\BTiT{S{g}{T1^x,/_y]6_g<^_y>a}BB8^h6y~SSy/18x1aSc2]\_~8Sc~B.:^1_{6S^]inhCQ{yS8gTR1{x{BAeT_>]STTAh6Tc]\:iT{T{1R{8Tgi_iBQ.`~_g_~_}aMugR82hL8~:y^_.x:]]gS6S^\_~8Sc~B.eux/R]^ayS^2LxzmUg~c\18{x{Rx~}r{`ag81Rhgag<2Ci6y}y]Ry~{61g//.-~hRk3KM^{T_8>ySyx}cCAx~g1]SA18SRAAygy/Cn{B^~8h_,,18{26}:y2{RBAS{Qxe~cx,{=2SS^ccx2{xAC_a^1y^82uh{SQ_nh^R_yyy]anhyR]g8}:1\RC18~\/x}cCc>e6ih_xB__2>xTniT2~_2^AS]Si_]T8h]12\Ty)d}R]TC^hSRBB_g6unB2u~\{hT-,_y\2Teie^BTa1]{`/1C__CR^\.RTS1^^^QBS88S_cc1QxT^}nSC8~y2_Sc~T1QC8c\R]QxhcC]2]gg]A1^1x=:B12}a]BQ]._RB8h~CB_T_Tcga-~SRR}nrung_R1^_1\hAyn~ua1}h=e^c_S>y..Cgx_}2^2A`\{^C1]^yhhyScc1Qxy^cr6.x6cT21]^yT_1B]h~\R1/xhcC]]xa=~]R]__ST{A\gcC\x.xhc/CgTaLyBCha/T1,^n8]TgB`xS~gg^xRch/x~rrTx{hin~28@wuh_TyS2yi>6cgy{R{gm,nh=}SgecciuucQ^cRyL=c^xS\/2u_/Q]~T/B:hcyxASg_y6}hh_8R^A]CA61AR]6^c{^aex_{~ARhTTA,-Bc8_{Tyh~xR2Mi^B.Q\^g:_A{c_i2eS}cRRShrTh=T}h21}g}}:MrT.1}CTcABci{]cyA-Qyn=~T{nMh{R~wCBB_8}/iwgrnc]xci}~}8Q]~\]2^xhS1^{h{6ThS~8<^_nge^`BRc8_Syy~CR28i_AQR]y<>_2:{^:h16chR\_uc~=}S8h6}:MrT.CyR5TAA6y^cSB-.S>T^^}^}hgiyxxS2iRRBAy^ih_-Q_~6y6^\T6~T{^{n{A1^..g{_}c6cT_CM:eMwn}6y{_^cT]2S}engL9B/{~S^1}>A`Mi},giBQ21gS-cMihcT<{ThMn7. *?Z~Tx2_{}yeiS_i}6x{}\Q}nTAQ^_/CRAy^1hhaic_B}h2cg6S_}{S{.,CS{TT^]^S2/,QhTR/xTcC]7AQx/_uiQ^TSSyL_Tc^Th{/Q_ghnh]RM_-.rR.^M~QS8ehQ1iTx2h~_]~i_QBB^_/CxRcnnS2i<_QAcCC/2ui/^ySSyL{gh{ac^8:]`-Qx~:gcgniB.Mi2`.ThxyeSS}}{Thh}{QB].Q_yA-_y1xR]Cx^R_SBxiccMi~{SeyS{1_i_g82R/c{`C}A{}_y8C.]S6M_/g^Rn[<\/{h_}:ShA/.R_S2CC2>^82}g82]=g_:_``Qx~=agQ`gM2/}g~\^SC]T}{ThTS/Q1.Q_S-^_xx\^xC]R]1.8}gr:y<1x}cT}2{=S~g_xB\8~/2CRSy^Wz#""?w@]Sh]^h_Q1]CQR_2ex`]S]]ccxc}]A1h:ehe~QBinh~n2TT1]T<6C^nx^Tiy^<-/:SxSie}wiTSRBS8yR]6{cwLScigSaeCRA]B^Q/C{ia~^AS^TyB]=c]TT^1\Q`-C_{T]cg1}x6T~=yy=}\]]xBxTy^`2y_2gg]ce_xAxi=8hggBBhaaMMygLe_SaaR^nx2ci]BM6Qc>TCTh_^8~^cLnT26MCShc6na.Sh2CT}y}RT2Qnh]S:c}n>:hSA]y_SaC/B,,agxgMySg8~n8yh]`.B/Be>{{c]i~2iyR~~gy{1.R\]gScaxgyAnrx1*O;1@[GR^iMcS{^^}]1hcCy~^1Ryi6AC6gghMB,1c\.ShT2282xiiThi_xAx\`/TyA]cy1~/`2_Sn~6}RSuS_]16TASnc{}a6nicB^}B2=chMy_c~~S2cgyx28^.1cT]x6{]_C^~}_hg^gey~:gSS^2`/S^Tx8__^6nyy=CC9h8cy1C{T]_{x]^}c1/Ry__~2-BT_y:.Q{R-_nh]AR.y}2}/BAS6T6}yT_\_{#""?w@@?Yh_c}ii{2R/Q2SRQ6>TxAcCS}/Q]B^aMTSLR2h=c6g_1B_]/Bgcc2_cg~_h=]:x:uC..Tu>A]<7A^^{{1T]`Ccch;~{Sin1ChnSB.A6~__^1}S1c}{1xS4^2-Rg\hhg<}_^c:gyxSMMyQh{~{hS2R/Q^TxQ8SB/22QCcQB_B2c2xgQC8hh_R/161.Bhcc2_Tch{xcLhRh:xugC`.TnnR2r~RST}61`\}y{_^12ngBBc:^B/Byy5ySS8cS:{x1S2_S-xRh8cS2ciyR_MSQT~_cThS2R/Q2S]:ry\BySB]6QB_B_gLSC:7/\n961A._:_QBhg9S{c~6S=OPOOŅRhU֗25 ONOŅd.hFr`$)ǷO¿.g90i1ژr`[vMNNLLLLL{…|-fR/h0iؗktGmccccLL,dfƂgh0 '֍k{ccLPdNOPdg/90Aj1ـ LccNP}Q9A2yKzcNNLOd~RUuzOOd|eRUلtIIIIxzcLOn^eƆzIIxIxzcLOd|Uԍxyyb*IIILzzLPf'IIyba**zLmP-_9ĮabzIaaIxzcLNOgIxxIIxxx+yzNODdfIaaaaIKIIxIxccJKccNnfaby+LcLL{P:PxaxIIJczz:CJzzMCaHxIc**Ix{{IxLLx*xIaxII+Ixamblobby-1.0/data/gfx/sch14.bmp000644 001750 001750 00000030066 12313310254 020531 0ustar00danielknobedanielknobe000000 000000 BM606( 0  333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333blobby-1.0/src/PhysicState.cpp000644 001750 001750 00000005452 12313310253 021145 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "PhysicState.h" /* includes */ #include "GameConstants.h" #include "GenericIO.h" USER_SERIALIZER_IMPLEMENTATION_HELPER(PhysicState) { io.number( value.blobPosition[LEFT_PLAYER].x ); io.number( value.blobPosition[LEFT_PLAYER].y ); io.number( value.blobVelocity[LEFT_PLAYER].x ); io.number( value.blobVelocity[LEFT_PLAYER].y ); io.number( value.blobPosition[RIGHT_PLAYER].x ); io.number( value.blobPosition[RIGHT_PLAYER].y ); io.number( value.blobVelocity[RIGHT_PLAYER].x ); io.number( value.blobVelocity[RIGHT_PLAYER].y ); io.number( value.ballPosition.x ); io.number( value.ballPosition.y ); io.number( value.ballVelocity.x ); io.number( value.ballVelocity.y ); io.number( value.ballAngularVelocity ); } void PhysicState::swapSides() { blobPosition[LEFT_PLAYER].x = RIGHT_PLANE - blobPosition[LEFT_PLAYER].x; blobPosition[RIGHT_PLAYER].x = RIGHT_PLANE - blobPosition[RIGHT_PLAYER].x; blobVelocity[LEFT_PLAYER].x = -blobVelocity[LEFT_PLAYER].x; blobVelocity[RIGHT_PLAYER].x = -blobVelocity[RIGHT_PLAYER].x; std::swap(blobPosition[LEFT_PLAYER], blobPosition[RIGHT_PLAYER]); std::swap(blobVelocity[LEFT_PLAYER], blobVelocity[RIGHT_PLAYER]); ballPosition.x = RIGHT_PLANE - ballPosition.x; ballVelocity.x = -ballVelocity.x; ballAngularVelocity = -ballAngularVelocity; } bool PhysicState::operator==(const PhysicState& other) const { return blobPosition[LEFT_PLAYER] == other.blobPosition[LEFT_PLAYER] && blobPosition[RIGHT_PLAYER] == other.blobPosition[RIGHT_PLAYER] && blobVelocity[LEFT_PLAYER] == other.blobVelocity[LEFT_PLAYER] && blobVelocity[RIGHT_PLAYER] == other.blobVelocity[RIGHT_PLAYER] && ballPosition == other.ballPosition && ballVelocity == other.ballVelocity && ballAngularVelocity == other.ballAngularVelocity; } blobby-1.0/data/gfx/font14.bmp000644 001750 001750 00000003370 12313310254 020720 0ustar00danielknobedanielknobe000000 000000 BM6( )8 8v Y:2+ &*+12\S1 wc^dt  2 ?o.arQN/!.6(5(6+8,>2@6;..Ai;7.ajKlcR0 $=S1pPjsustmql\74 +HOnBnOD2#;    &)|hVK!,rY`Q 6='p[% =x^?4 e AS/_I  & X? A9~"'] &@$ v'-@G,;$ f B?<>A?:3#2'' -9000) { alti=i; if (j==1) { if (i>800-bsizx /2) { i=1600-i-bsizx;direct=0; } if (i<405+bsizx /2) { i=810+bsizx-i;direct=0; } if (i<500) { if (touchcnt<2) { i=i-bsizx /2; } } } else { if (i<0+bsizx /2) { i=-i+bsizx; direct=0; } if (i>395-bsizx /2) { i=790-bsizx-i; direct=0; } if (i>300) { if (touchcnt<2) { i=i+bsizx /2; } } } i=i+(bsizx / 3)*factor; //if (i>=x+7) right(); //if (i<=x-7) left(); moveto(i); } stopjump(); if(vby<=10) if (factor*(x-bx)<21) if (factor*(bx-x)<7) if (abs(bx-x)<120) if (abs(vby)<65) if (by>200) if (by-y>70) if ((by<400) || (vby==0)) if (abs(vbx)<20) if (!balldown()) jump(); if (random(300)==0) jump(); if (i>-9000) { if ((abs(i-x)>75) && (abs(bx-x)<65) && (vby<0) ) { jump(); } } if (touching()) { stop(); } if (!launched()) { delay+=1; stopjump(); if (delay>=30) jump(); } wait(); } //while } //function blobby-1.0/src/MatchEvents.h000644 001750 001750 00000003251 12313310251 020564 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once enum { // physic events EVENT_LEFT_BLOBBY_HIT = 1, EVENT_RIGHT_BLOBBY_HIT = 2, EVENT_BALL_HIT_LEFT_GROUND = 4, EVENT_BALL_HIT_RIGHT_GROUND = 8, EVENT_BALL_HIT_LEFT_WALL = 16, EVENT_BALL_HIT_RIGHT_WALL = 32, EVENT_BALL_HIT_NET_LEFT = 64, EVENT_BALL_HIT_NET_RIGHT = 128, EVENT_BALL_HIT_NET_TOP = 256, EVENT_BALL_HIT_GROUND = EVENT_BALL_HIT_LEFT_GROUND | EVENT_BALL_HIT_RIGHT_GROUND, EVENT_BALL_HIT_BLOBBY = EVENT_LEFT_BLOBBY_HIT | EVENT_RIGHT_BLOBBY_HIT, EVENT_COLLISION = EVENT_BALL_HIT_GROUND | EVENT_BALL_HIT_BLOBBY, // game events EVENT_ERROR_LEFT = 512, EVENT_ERROR_RIGHT = 1024, EVENT_ERROR = EVENT_ERROR_LEFT | EVENT_ERROR_RIGHT, EVENT_RESET = 2048 }; blobby-1.0/src/raknet/PacketEnumerations.h000644 001750 001750 00000025775 12313310247 023454 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @ingroup RALNET_MESSAGE_ID * @file * @brief Define RakNet internal packet identifier * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __PACKET_ENUMERATIONS_H #define __PACKET_ENUMERATIONS_H /** * @defgroup RAKNET_MESSAGE_ID Message Identifier * * You should not edit the file PacketEnumerations.h as it is a part of RakNet static library * To define your own message id, define an enum following the code example that follows. * * @code * enum { * ID_MYPROJECT_MSG_1 = ID_RESERVED_9 + 1, * ID_MYPROJECT_MSG_2, * ... * }; * @endcode * * @note RakNet define message ID as a 1 byte information. If you * require more than 256 message IDs do not reuse the function * Multiplayer::GetPacketIdentifier and replace the existing one by a * correct version of this function the version. In this case you can * integrate in the code of your project the file Multiplayer.h and * edit this file to fits your needs. */ enum { // // RESERVED TYPES - DO NOT CHANGE THESE // // Ignore these: ID_CONNECTED_PING, //!< 0: Ping from a connected system. Update timestamps (internal use only) ID_UNCONNECTED_PING, //!< 1: Ping from an unconnected system. Reply but do not update timestamps. (internal use only) ID_UNCONNECTED_PING_OPEN_CONNECTIONS, //!< 2: Ping from an unconnected system. Only reply if we have open connections. Do not update timestamps. (internal use only) ID_CONNECTED_PONG, //!< 3: Pong from a connected system. Update timestamps (internal use only) ID_REQUEST_STATIC_DATA, //!< 4: Someone asked for our static data (internal use only) ID_CONNECTION_REQUEST, //!< 5: Asking for a new connection (internal use only) ID_SECURED_CONNECTION_RESPONSE, //!< 6: Connecting to a secured server/peer ID_SECURED_CONNECTION_CONFIRMATION, //!< 7: Connecting to a secured server/peer ID_RPC, //!< 8: Remote procedure call (internal use only) ID_BROADCAST_PINGS, //!< 9: Server / Client only - The server is broadcasting the pings of all players in the game (internal use only) ID_SET_RANDOM_NUMBER_SEED, //!< 10: Server / Client only - The server is broadcasting a random number seed (internal use only) ID_RPC_MAPPING, //!< 11: Packet that tells us the packet contains an integer ID to name mapping for the remote system ID_KEEPALIVE, //!< 12: Just a reliable keepalive ID_OPEN_CONNECTION_REQUEST, //!< 13: Guaranteed offline message so we know when to reset and start a new connection ID_OPEN_CONNECTION_REPLY, ///!< 14: Guaranteed offline message response so we know when to reset and start a new connection //Handle these below. Possible recipients in [...] ID_PONG, //!< [CLIENT|PEER] 15: Pong from an unconnected system. First byte is ID_PONG, second 4 bytes is the ping, following bytes is system specific enumeration data. ID_RSA_PUBLIC_KEY_MISMATCH, //!< [CLIENT|PEER] 16: We preset an RSA public key which does not match what the system we connected to is using. ID_REMOTE_DISCONNECTION_NOTIFICATION, //!< [CLIENT] 17: In a client/server environment, a client other than ourselves has disconnected gracefully. Packet::playerID is modified to reflect the playerID of this client. ID_REMOTE_CONNECTION_LOST, //!< [CLIENT] 18: In a client/server environment, a client other than ourselves has been forcefully dropped. Packet::playerID is modified to reflect the playerID of this client. ID_REMOTE_NEW_INCOMING_CONNECTION, //!< [CLIENT] 19: In a client/server environment, a client other than ourselves has connected. Packet::playerID is modified to reflect the playerID of this client. ID_REMOTE_EXISTING_CONNECTION, //!< [CLIENT] 20: On our initial connection to the server, we are told of every other client in the game. Packet::playerID is modified to reflect the playerID of this client. ID_REMOTE_STATIC_DATA, //!< [CLIENT] - 21: Got the data for another client ID_CONNECTION_BANNED, //!< [PEER|CLIENT] 22: We are banned from the system we attempted to connect to. ID_CONNECTION_REQUEST_ACCEPTED, //!< [PEER|CLIENT] 23: In a client/server environment, our connection request to the server has been accepted. ID_NEW_INCOMING_CONNECTION, //!< [PEER|SERVER] 24: A remote system has successfully connected. ID_NO_FREE_INCOMING_CONNECTIONS, //!< [PEER|CLIENT] 25: The system we attempted to connect to is not accepting new connections. ID_DISCONNECTION_NOTIFICATION, //!< [PEER|SERVER|CLIENT] 26: The system specified in Packet::playerID has disconnected from us. For the client, this would mean the server has shutdown. ID_CONNECTION_LOST, //!< [PEER|SERVER|CLIENT] 27: Reliable packets cannot be delivered to the system specifed in Packet::playerID. The connection to that system has been closed. ID_TIMESTAMP, //!< [PEER|SERVER|CLIENT] 28: The four bytes following this byte represent an unsigned int which is automatically modified by the difference in system times between the sender and the recipient. Requires that you call StartOccasionalPing. ID_RECEIVED_STATIC_DATA, //!< [PEER|SERVER|CLIENT] 29: We got a bitstream containing static data. You can now read this data. This packet is transmitted automatically on connections, and can also be manually sent. ID_INVALID_PASSWORD, //!< [PEER|CLIENT] 30: The remote system is using a password and has refused our connection because we did not set the correct password. ID_MODIFIED_PACKET, //!< [PEER|SERVER|CLIENT] 31: A packet has been tampered with in transit. The sender is contained in Packet::playerID. ID_REMOTE_PORT_REFUSED, //!< [PEER|SERVER|CLIENT] 32: [11/14/05 - DEPRECIATED: No longer returned] The remote host is not accepting data on this port. This only comes up when connecting to yourself on the same computer and there is no bound socket on that port. ID_VOICE_PACKET, //!< [PEER] 33: This packet contains voice data. You should pass it to the RakVoice system. ID_UPDATE_DISTRIBUTED_NETWORK_OBJECT, //!< [CLIENT|SERVER] 34: Indicates creation or update of a distributed network object. Pass to DistributedNetworkObjectManager::Instance()->HandleDistributedNetworkObjectPacket ID_DISTRIBUTED_NETWORK_OBJECT_CREATION_ACCEPTED, //!< [CLIENT] 35: Client creation of a distributed network object was accepted. Pass to DistributedNetworkObjectManager::Instance()->HandleDistributedNetworkObjectPacketCreationAccepted ID_DISTRIBUTED_NETWORK_OBJECT_CREATION_REJECTED, //!< [CLIENT] 36: Client creation of a distributed network object was rejected. Pass to DistributedNetworkObjectManager::Instance()->HandleDistributedNetworkObjectPacketCreationRejected ID_AUTOPATCHER_REQUEST_FILE_LIST, //!< [PEER|SERVER|CLIENT] 37: Request for a list of downloadable files. Pass to Autopatcher::SendDownloadableFileList ID_AUTOPATCHER_FILE_LIST, //!< [PEER|SERVER|CLIENT] 38: Got a list of downloadable files. Pass to Autopatcher::OnAutopatcherFileList ID_AUTOPATCHER_REQUEST_FILES, //!< [PEER|SERVER|CLIENT] 39: Request for a particular set of downloadable files. Pass to Autopatcher::OnAutopatcherRequestFiles ID_AUTOPATCHER_SET_DOWNLOAD_LIST, //!< [PEER|SERVER|CLIENT] 40: Set the list of files that were approved for download and are incoming. Pass to Autopatcher::OnAutopatcherSetDownloadList ID_AUTOPATCHER_WRITE_FILE, //!< [PEER|SERVER|CLIENT] 41: Got a file that we requested for download. Pass to Autopatcher::OnAutopatcherWriteFile ID_QUERY_MASTER_SERVER, //!< [MASTERSERVER] 42: Request to the master server for the list of servers that contain at least one of the specified keys ID_MASTER_SERVER_DELIST_SERVER, //!< [MASTERSERVER] 43: Remove a game server from the master server. ID_MASTER_SERVER_UPDATE_SERVER, //!< [MASTERSERVER|MASTERCLIENT] 44: Add or update the information for a server. ID_MASTER_SERVER_SET_SERVER, //!< [MASTERSERVER|MASTERCLIENT] 45: Add or set the information for a server. ID_RELAYED_CONNECTION_NOTIFICATION, //!< [MASTERSERVER|MASTERCLIENT] 46: This message indicates a game client is connecting to a game server, and is relayed through the master server. ID_ADVERTISE_SYSTEM, //!< [PEER|SERVER|CLIENT] 47: Inform a remote system of our IP/Port. ID_FULLY_CONNECTED_MESH_JOIN_RESPONSE, //!< [PEER via MessageHandlerInterface] 48: Used by FullyConnectedMesh packet handler to automatically connect to other peers and form a fully connected mesh topology ID_FULLY_CONNECTED_MESH_JOIN_REQUEST, //!< [PEER] 49: Used by FullyConnectedMesh packet handler to automatically connect to other peers and form a fully connected mesh topology ID_CONNECTION_ATTEMPT_FAILED, //!< [PEER|SERVER|CLIENT] 50: Sent to the player when a connection request cannot be completed due to inability to connect ID_REPLICATOR_DATA_PUSH_OBJECT, ID_REPLICATOR_DATA_SEND_MEMORY, ID_REPLICATOR_DATA_SEND_OBJECT_SCOPE, ID_REPLICATOR_MEMORY_START, ID_REPLICATOR_DATA_STOP, ID_REPLICATOR_OBJECT_CREATION_REQUEST, ID_REPLICATOR_OBJECT_CREATION_REQUEST_RESPONSE, ID_REPLICATOR_STR_MAP_INDEX, ID_RESERVED7, //!< For future versions ID_RESERVED8, //!< For future versions ID_RESERVED9, //!< For future versions //------------------------------------------------------------------------------------------------------------- // // YOUR TYPES HERE! // WARNING - By default it is assumed that the packet identifier is one byte (unsigned char) // In the unlikely event that you need more than 256 types, including the built-in types, then you'll need // to request a special edition with larger identifiers, or change it yourself // ID_MASTER_REGISTER_USER, ID_MASTER_SERVER_REGISTRATION_FAILED }; #endif blobby-1.0/data/gfx/ball02.bmp000644 001750 001750 00000012066 12313310254 020663 0ustar00danielknobedanielknobe000000 000000 BM66(@@ xwyheh|z|geg~}~a`adbca__wuugee}||hgggffedd{zyjihrrpggeFFEmmlbba ab^ prpege<=<yzywxwVWV}~npofhg xzz{||effz{|NORbbe../nnpggieeg~~vvwqqrdde{{{xxxsssooojjjhhheeedddccc```___]]]ZZZXXXWWWTTTOOO###  D$4  ` CCCCC4o;;[ :CC4" 苔^^3_ZCCC;D` DDDDxk !34nC ^iT k3_C xu S00^:3 !3:# $1!~R0 T !^4orr0i~.R T^DCC$Sh.g..0!T 3^" CyDDDDD.ܡ~Si-g..~ !T x^Z 44# .g-.0h-.0iiSST 34쉌CCjQg.0RQ.h0Cn#D``g---,--.0CCD3v}}eddddڟ-.x ^ Q]|||||||=}ޡ3T 3:" ޠ*L||d}.x i 3CDL5)*|dd}ݡi 0hi 3_##Ԝќ|e} i~~i 3"y"o]|ќ||ee}}h..~hi  DLМL]dh~..~~i ^CCC4 5+)WW5LLddd.ޡ~~^ZCCnCC4 |)ϓϜ5Ԟd}}~ݡ.~ixZCC"[ D|L5ќLLd.i vܡ.~_::敕C DLd֞||||||ddM0ݟޡ~~3CoD l<55555555555Lh.}ޡ.Ri! DD()Lɒќ+-}ޡ.T^__4DKqBcќ}}ޡ0333^:C DW͓ќddڟ}-h3^^_C$DYМvf}}ޡ 33^$Obq|dde}ݡhk xyBw™|>hS CDBA'bJL5ќ)|]Q0001 n''LќҞ|}gQQQRS_C4Cљ''ƛWLKМܠݡiZC_uUVAJaIUUUUǛɛL+feܡT_3ppUUUUU'd}S3!HaUU''Ǜ)|=f, Lҝ|=.~ '™šB)<S U7šqW5]>Rhg pqqϝQ GGǂqd &&&& p]&F&& 7''ǛgU&E&&&7bƛ|FFE&&{'B+M+z&Iq΃E&&&&{H7'FF&{'@% & pa&E6% E { E&&%%&  EE& E%%%E&{ %&%%&&&%E%&E 6&&E&%%%EEEblobby-1.0/data/gfx/pfeil_oben.bmp000644 001750 001750 00000001466 12313310254 021713 0ustar00danielknobedanielknobe000000 000000 BM6(@  000,ZLutt *5HVdy$&d*.)GE.\Zvu   '" ++'"" )+'"" ()'"""&()""$&%"" $#" "   *!   .-,!  ..-*  ""/.-*  ..-* #/.-* ..-*/.-*! ./-* /.,/,blobby-1.0/src/lua/ldebug.c000644 001750 001750 00000037330 12313310253 020370 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: ldebug.c,v 2.90.1.3 2013/05/16 16:04:15 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ #include #include #include #define ldebug_c #define LUA_CORE #include "lua.h" #include "lapi.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lobject.h" #include "lopcodes.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lvm.h" #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); static int currentpc (CallInfo *ci) { lua_assert(isLua(ci)); return pcRel(ci->u.l.savedpc, ci_func(ci)->p); } static int currentline (CallInfo *ci) { return getfuncline(ci_func(ci)->p, currentpc(ci)); } /* ** this function can be called asynchronous (e.g. during a signal) */ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { if (func == NULL || mask == 0) { /* turn off hooks? */ mask = 0; func = NULL; } if (isLua(L->ci)) L->oldpc = L->ci->u.l.savedpc; L->hook = func; L->basehookcount = count; resethookcount(L); L->hookmask = cast_byte(mask); return 1; } LUA_API lua_Hook lua_gethook (lua_State *L) { return L->hook; } LUA_API int lua_gethookmask (lua_State *L) { return L->hookmask; } LUA_API int lua_gethookcount (lua_State *L) { return L->basehookcount; } LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { int status; CallInfo *ci; if (level < 0) return 0; /* invalid (negative) level */ lua_lock(L); for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) level--; if (level == 0 && ci != &L->base_ci) { /* level found? */ status = 1; ar->i_ci = ci; } else status = 0; /* no such level */ lua_unlock(L); return status; } static const char *upvalname (Proto *p, int uv) { TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); if (s == NULL) return "?"; else return getstr(s); } static const char *findvararg (CallInfo *ci, int n, StkId *pos) { int nparams = clLvalue(ci->func)->p->numparams; if (n >= ci->u.l.base - ci->func - nparams) return NULL; /* no such vararg */ else { *pos = ci->func + nparams + n; return "(*vararg)"; /* generic name for any vararg */ } } static const char *findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { const char *name = NULL; StkId base; if (isLua(ci)) { if (n < 0) /* access to vararg values? */ return findvararg(ci, -n, pos); else { base = ci->u.l.base; name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); } } else base = ci->func + 1; if (name == NULL) { /* no 'standard' name? */ StkId limit = (ci == L->ci) ? L->top : ci->next->func; if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ name = "(*temporary)"; /* generic name for any valid slot */ else return NULL; /* no name */ } *pos = base + (n - 1); return name; } LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { const char *name; lua_lock(L); if (ar == NULL) { /* information about non-active function? */ if (!isLfunction(L->top - 1)) /* not a Lua function? */ name = NULL; else /* consider live variables at function start (parameters) */ name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0); } else { /* active function; get information through 'ar' */ StkId pos = 0; /* to avoid warnings */ name = findlocal(L, ar->i_ci, n, &pos); if (name) { setobj2s(L, L->top, pos); api_incr_top(L); } } lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { StkId pos = 0; /* to avoid warnings */ const char *name = findlocal(L, ar->i_ci, n, &pos); lua_lock(L); if (name) setobjs2s(L, pos, L->top - 1); L->top--; /* pop value */ lua_unlock(L); return name; } static void funcinfo (lua_Debug *ar, Closure *cl) { if (noLuaClosure(cl)) { ar->source = "=[C]"; ar->linedefined = -1; ar->lastlinedefined = -1; ar->what = "C"; } else { Proto *p = cl->l.p; ar->source = p->source ? getstr(p->source) : "=?"; ar->linedefined = p->linedefined; ar->lastlinedefined = p->lastlinedefined; ar->what = (ar->linedefined == 0) ? "main" : "Lua"; } luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); } static void collectvalidlines (lua_State *L, Closure *f) { if (noLuaClosure(f)) { setnilvalue(L->top); api_incr_top(L); } else { int i; TValue v; int *lineinfo = f->l.p->lineinfo; Table *t = luaH_new(L); /* new table to store active lines */ sethvalue(L, L->top, t); /* push it on stack */ api_incr_top(L); setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ } } static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, Closure *f, CallInfo *ci) { int status = 1; for (; *what; what++) { switch (*what) { case 'S': { funcinfo(ar, f); break; } case 'l': { ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; break; } case 'u': { ar->nups = (f == NULL) ? 0 : f->c.nupvalues; if (noLuaClosure(f)) { ar->isvararg = 1; ar->nparams = 0; } else { ar->isvararg = f->l.p->is_vararg; ar->nparams = f->l.p->numparams; } break; } case 't': { ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; break; } case 'n': { /* calling function is a known Lua function? */ if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) ar->namewhat = getfuncname(L, ci->previous, &ar->name); else ar->namewhat = NULL; if (ar->namewhat == NULL) { ar->namewhat = ""; /* not found */ ar->name = NULL; } break; } case 'L': case 'f': /* handled by lua_getinfo */ break; default: status = 0; /* invalid option */ } } return status; } LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { int status; Closure *cl; CallInfo *ci; StkId func; lua_lock(L); if (*what == '>') { ci = NULL; func = L->top - 1; api_check(L, ttisfunction(func), "function expected"); what++; /* skip the '>' */ L->top--; /* pop function */ } else { ci = ar->i_ci; func = ci->func; lua_assert(ttisfunction(ci->func)); } cl = ttisclosure(func) ? clvalue(func) : NULL; status = auxgetinfo(L, what, ar, cl, ci); if (strchr(what, 'f')) { setobjs2s(L, L->top, func); api_incr_top(L); } if (strchr(what, 'L')) collectvalidlines(L, cl); lua_unlock(L); return status; } /* ** {====================================================== ** Symbolic Execution ** ======================================================= */ static const char *getobjname (Proto *p, int lastpc, int reg, const char **name); /* ** find a "name" for the RK value 'c' */ static void kname (Proto *p, int pc, int c, const char **name) { if (ISK(c)) { /* is 'c' a constant? */ TValue *kvalue = &p->k[INDEXK(c)]; if (ttisstring(kvalue)) { /* literal constant? */ *name = svalue(kvalue); /* it is its own name */ return; } /* else no reasonable name found */ } else { /* 'c' is a register */ const char *what = getobjname(p, pc, c, name); /* search for 'c' */ if (what && *what == 'c') { /* found a constant name? */ return; /* 'name' already filled */ } /* else no reasonable name found */ } *name = "?"; /* no reasonable name found */ } static int filterpc (int pc, int jmptarget) { if (pc < jmptarget) /* is code conditional (inside a jump)? */ return -1; /* cannot know who sets that register */ else return pc; /* current position sets that register */ } /* ** try to find last instruction before 'lastpc' that modified register 'reg' */ static int findsetreg (Proto *p, int lastpc, int reg) { int pc; int setreg = -1; /* keep last instruction that changed 'reg' */ int jmptarget = 0; /* any code before this address is conditional */ for (pc = 0; pc < lastpc; pc++) { Instruction i = p->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); switch (op) { case OP_LOADNIL: { int b = GETARG_B(i); if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ setreg = filterpc(pc, jmptarget); break; } case OP_TFORCALL: { if (reg >= a + 2) /* affect all regs above its base */ setreg = filterpc(pc, jmptarget); break; } case OP_CALL: case OP_TAILCALL: { if (reg >= a) /* affect all registers above base */ setreg = filterpc(pc, jmptarget); break; } case OP_JMP: { int b = GETARG_sBx(i); int dest = pc + 1 + b; /* jump is forward and do not skip `lastpc'? */ if (pc < dest && dest <= lastpc) { if (dest > jmptarget) jmptarget = dest; /* update 'jmptarget' */ } break; } case OP_TEST: { if (reg == a) /* jumped code can change 'a' */ setreg = filterpc(pc, jmptarget); break; } default: if (testAMode(op) && reg == a) /* any instruction that set A */ setreg = filterpc(pc, jmptarget); break; } } return setreg; } static const char *getobjname (Proto *p, int lastpc, int reg, const char **name) { int pc; *name = luaF_getlocalname(p, reg + 1, lastpc); if (*name) /* is a local? */ return "local"; /* else try symbolic execution */ pc = findsetreg(p, lastpc, reg); if (pc != -1) { /* could find instruction? */ Instruction i = p->code[pc]; OpCode op = GET_OPCODE(i); switch (op) { case OP_MOVE: { int b = GETARG_B(i); /* move from 'b' to 'a' */ if (b < GETARG_A(i)) return getobjname(p, pc, b, name); /* get name for 'b' */ break; } case OP_GETTABUP: case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ int t = GETARG_B(i); /* table index */ const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ ? luaF_getlocalname(p, t + 1, pc) : upvalname(p, t); kname(p, pc, k, name); return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; } case OP_GETUPVAL: { *name = upvalname(p, GETARG_B(i)); return "upvalue"; } case OP_LOADK: case OP_LOADKX: { int b = (op == OP_LOADK) ? GETARG_Bx(i) : GETARG_Ax(p->code[pc + 1]); if (ttisstring(&p->k[b])) { *name = svalue(&p->k[b]); return "constant"; } break; } case OP_SELF: { int k = GETARG_C(i); /* key index */ kname(p, pc, k, name); return "method"; } default: break; /* go through to return NULL */ } } return NULL; /* could not find reasonable name */ } static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { TMS tm; Proto *p = ci_func(ci)->p; /* calling function */ int pc = currentpc(ci); /* calling instruction index */ Instruction i = p->code[pc]; /* calling instruction */ switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: /* get function name */ return getobjname(p, pc, GETARG_A(i), name); case OP_TFORCALL: { /* for iterator */ *name = "for iterator"; return "for iterator"; } /* all other instructions can call only through metamethods */ case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: tm = TM_INDEX; break; case OP_SETTABUP: case OP_SETTABLE: tm = TM_NEWINDEX; break; case OP_EQ: tm = TM_EQ; break; case OP_ADD: tm = TM_ADD; break; case OP_SUB: tm = TM_SUB; break; case OP_MUL: tm = TM_MUL; break; case OP_DIV: tm = TM_DIV; break; case OP_MOD: tm = TM_MOD; break; case OP_POW: tm = TM_POW; break; case OP_UNM: tm = TM_UNM; break; case OP_LEN: tm = TM_LEN; break; case OP_LT: tm = TM_LT; break; case OP_LE: tm = TM_LE; break; case OP_CONCAT: tm = TM_CONCAT; break; default: return NULL; /* else no useful name can be found */ } *name = getstr(G(L)->tmname[tm]); return "metamethod"; } /* }====================================================== */ /* ** only ANSI way to check whether a pointer points to an array ** (used only for error messages, so efficiency is not a big concern) */ static int isinstack (CallInfo *ci, const TValue *o) { StkId p; for (p = ci->u.l.base; p < ci->top; p++) if (o == p) return 1; return 0; } static const char *getupvalname (CallInfo *ci, const TValue *o, const char **name) { LClosure *c = ci_func(ci); int i; for (i = 0; i < c->nupvalues; i++) { if (c->upvals[i]->v == o) { *name = upvalname(c->p, i); return "upvalue"; } } return NULL; } l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { CallInfo *ci = L->ci; const char *name = NULL; const char *t = objtypename(o); const char *kind = NULL; if (isLua(ci)) { kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ if (!kind && isinstack(ci, o)) /* no? try a register */ kind = getobjname(ci_func(ci)->p, currentpc(ci), cast_int(o - ci->u.l.base), &name); } if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", op, kind, name, t); else luaG_runerror(L, "attempt to %s a %s value", op, t); } l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) { if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; lua_assert(!ttisstring(p1) && !ttisnumber(p1)); luaG_typeerror(L, p1, "concatenate"); } l_noret luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { TValue temp; if (luaV_tonumber(p1, &temp) == NULL) p2 = p1; /* first operand is wrong */ luaG_typeerror(L, p2, "perform arithmetic on"); } l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { const char *t1 = objtypename(p1); const char *t2 = objtypename(p2); if (t1 == t2) luaG_runerror(L, "attempt to compare two %s values", t1); else luaG_runerror(L, "attempt to compare %s with %s", t1, t2); } static void addinfo (lua_State *L, const char *msg) { CallInfo *ci = L->ci; if (isLua(ci)) { /* is Lua code? */ char buff[LUA_IDSIZE]; /* add file:line information */ int line = currentline(ci); TString *src = ci_func(ci)->p->source; if (src) luaO_chunkid(buff, getstr(src), LUA_IDSIZE); else { /* no source available; use "?" instead */ buff[0] = '?'; buff[1] = '\0'; } luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } } l_noret luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ L->top++; luaD_call(L, L->top - 2, 1, 0); /* call it */ } luaD_throw(L, LUA_ERRRUN); } l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); addinfo(L, luaO_pushvfstring(L, fmt, argp)); va_end(argp); luaG_errormsg(L); } blobby-1.0/src/lua/ldebug.h000644 001750 001750 00000002077 12313310253 020375 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: ldebug.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ #ifndef ldebug_h #define ldebug_h #include "lstate.h" #define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) #define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) #define resethookcount(L) (L->hookcount = L->basehookcount) /* Active Lua function (given call info) */ #define ci_func(ci) (clLvalue((ci)->func)) LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *opname); LUAI_FUNC l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2); LUAI_FUNC l_noret luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); LUAI_FUNC l_noret luaG_errormsg (lua_State *L); #endif blobby-1.0/src/lua/lbaselib.c000644 001750 001750 00000027775 12313310253 020717 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lbaselib.c,v 1.276.1.1 2013/04/12 18:48:47 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ #include #include #include #include #define lbaselib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; lua_getglobal(L, "tostring"); for (i=1; i<=n; i++) { const char *s; size_t l; lua_pushvalue(L, -1); /* function to be called */ lua_pushvalue(L, i); /* value to print */ lua_call(L, 1, 1); s = lua_tolstring(L, -1, &l); /* get result */ if (s == NULL) return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print")); if (i>1) luai_writestring("\t", 1); luai_writestring(s, l); lua_pop(L, 1); /* pop result */ } luai_writeline(); return 0; } #define SPACECHARS " \f\n\r\t\v" static int luaB_tonumber (lua_State *L) { if (lua_isnoneornil(L, 2)) { /* standard conversion */ int isnum; lua_Number n = lua_tonumberx(L, 1, &isnum); if (isnum) { lua_pushnumber(L, n); return 1; } /* else not a number; must be something */ luaL_checkany(L, 1); } else { size_t l; const char *s = luaL_checklstring(L, 1, &l); const char *e = s + l; /* end point for 's' */ int base = luaL_checkint(L, 2); int neg = 0; luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); s += strspn(s, SPACECHARS); /* skip initial spaces */ if (*s == '-') { s++; neg = 1; } /* handle signal */ else if (*s == '+') s++; if (isalnum((unsigned char)*s)) { lua_Number n = 0; do { int digit = (isdigit((unsigned char)*s)) ? *s - '0' : toupper((unsigned char)*s) - 'A' + 10; if (digit >= base) break; /* invalid numeral; force a fail */ n = n * (lua_Number)base + (lua_Number)digit; s++; } while (isalnum((unsigned char)*s)); s += strspn(s, SPACECHARS); /* skip trailing spaces */ if (s == e) { /* no invalid trailing characters? */ lua_pushnumber(L, (neg) ? -n : n); return 1; } /* else not a number */ } /* else not a number */ } lua_pushnil(L); /* not a number */ return 1; } static int luaB_error (lua_State *L) { int level = luaL_optint(L, 2, 1); lua_settop(L, 1); if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ luaL_where(L, level); lua_pushvalue(L, 1); lua_concat(L, 2); } return lua_error(L); } static int luaB_getmetatable (lua_State *L) { luaL_checkany(L, 1); if (!lua_getmetatable(L, 1)) { lua_pushnil(L); return 1; /* no metatable */ } luaL_getmetafield(L, 1, "__metatable"); return 1; /* returns either __metatable field (if present) or metatable */ } static int luaB_setmetatable (lua_State *L) { int t = lua_type(L, 2); luaL_checktype(L, 1, LUA_TTABLE); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); if (luaL_getmetafield(L, 1, "__metatable")) return luaL_error(L, "cannot change a protected metatable"); lua_settop(L, 2); lua_setmetatable(L, 1); return 1; } static int luaB_rawequal (lua_State *L) { luaL_checkany(L, 1); luaL_checkany(L, 2); lua_pushboolean(L, lua_rawequal(L, 1, 2)); return 1; } static int luaB_rawlen (lua_State *L) { int t = lua_type(L, 1); luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, "table or string expected"); lua_pushinteger(L, lua_rawlen(L, 1)); return 1; } static int luaB_rawget (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); lua_settop(L, 2); lua_rawget(L, 1); return 1; } static int luaB_rawset (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); luaL_checkany(L, 3); lua_settop(L, 3); lua_rawset(L, 1); return 1; } static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", "count", "step", "setpause", "setstepmul", "setmajorinc", "isrunning", "generational", "incremental", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; int ex = luaL_optint(L, 2, 0); int res = lua_gc(L, o, ex); switch (o) { case LUA_GCCOUNT: { int b = lua_gc(L, LUA_GCCOUNTB, 0); lua_pushnumber(L, res + ((lua_Number)b/1024)); lua_pushinteger(L, b); return 2; } case LUA_GCSTEP: case LUA_GCISRUNNING: { lua_pushboolean(L, res); return 1; } default: { lua_pushinteger(L, res); return 1; } } } static int luaB_type (lua_State *L) { luaL_checkany(L, 1); lua_pushstring(L, luaL_typename(L, 1)); return 1; } static int pairsmeta (lua_State *L, const char *method, int iszero, lua_CFunction iter) { if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */ luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ lua_pushcfunction(L, iter); /* will return generator, */ lua_pushvalue(L, 1); /* state, */ if (iszero) lua_pushinteger(L, 0); /* and initial value */ else lua_pushnil(L); } else { lua_pushvalue(L, 1); /* argument 'self' to metamethod */ lua_call(L, 1, 3); /* get 3 values from metamethod */ } return 3; } static int luaB_next (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 2); /* create a 2nd argument if there isn't one */ if (lua_next(L, 1)) return 2; else { lua_pushnil(L); return 1; } } static int luaB_pairs (lua_State *L) { return pairsmeta(L, "__pairs", 0, luaB_next); } static int ipairsaux (lua_State *L) { int i = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TTABLE); i++; /* next value */ lua_pushinteger(L, i); lua_rawgeti(L, 1, i); return (lua_isnil(L, -1)) ? 1 : 2; } static int luaB_ipairs (lua_State *L) { return pairsmeta(L, "__ipairs", 1, ipairsaux); } static int load_aux (lua_State *L, int status, int envidx) { if (status == LUA_OK) { if (envidx != 0) { /* 'env' parameter? */ lua_pushvalue(L, envidx); /* environment for loaded function */ if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ lua_pop(L, 1); /* remove 'env' if not used by previous call */ } return 1; } else { /* error (message is on top of the stack) */ lua_pushnil(L); lua_insert(L, -2); /* put before error message */ return 2; /* return nil plus error message */ } } static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); const char *mode = luaL_optstring(L, 2, NULL); int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ int status = luaL_loadfilex(L, fname, mode); return load_aux(L, status, env); } /* ** {====================================================== ** Generic Read function ** ======================================================= */ /* ** reserved slot, above all arguments, to hold a copy of the returned ** string to avoid it being collected while parsed. 'load' has four ** optional arguments (chunk, source name, mode, and environment). */ #define RESERVEDSLOT 5 /* ** Reader for generic `load' function: `lua_load' uses the ** stack for internal stuff, so the reader cannot change the ** stack top. Instead, it keeps its resulting string in a ** reserved slot inside the stack. */ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { (void)(ud); /* not used */ luaL_checkstack(L, 2, "too many nested functions"); lua_pushvalue(L, 1); /* get function */ lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { lua_pop(L, 1); /* pop result */ *size = 0; return NULL; } else if (!lua_isstring(L, -1)) luaL_error(L, "reader function must return a string"); lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ return lua_tolstring(L, RESERVEDSLOT, size); } static int luaB_load (lua_State *L) { int status; size_t l; const char *s = lua_tolstring(L, 1, &l); const char *mode = luaL_optstring(L, 3, "bt"); int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ if (s != NULL) { /* loading a string? */ const char *chunkname = luaL_optstring(L, 2, s); status = luaL_loadbufferx(L, s, l, chunkname, mode); } else { /* loading from a reader function */ const char *chunkname = luaL_optstring(L, 2, "=(load)"); luaL_checktype(L, 1, LUA_TFUNCTION); lua_settop(L, RESERVEDSLOT); /* create reserved slot */ status = lua_load(L, generic_reader, NULL, chunkname, mode); } return load_aux(L, status, env); } /* }====================================================== */ static int dofilecont (lua_State *L) { return lua_gettop(L) - 1; } static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); lua_settop(L, 1); if (luaL_loadfile(L, fname) != LUA_OK) return lua_error(L); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); return dofilecont(L); } static int luaB_assert (lua_State *L) { if (!lua_toboolean(L, 1)) return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); return lua_gettop(L); } static int luaB_select (lua_State *L) { int n = lua_gettop(L); if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { lua_pushinteger(L, n-1); return 1; } else { int i = luaL_checkint(L, 1); if (i < 0) i = n + i; else if (i > n) i = n; luaL_argcheck(L, 1 <= i, 1, "index out of range"); return n - i; } } static int finishpcall (lua_State *L, int status) { if (!lua_checkstack(L, 1)) { /* no space for extra boolean? */ lua_settop(L, 0); /* create space for return values */ lua_pushboolean(L, 0); lua_pushstring(L, "stack overflow"); return 2; /* return false, msg */ } lua_pushboolean(L, status); /* first result (status) */ lua_replace(L, 1); /* put first result in first slot */ return lua_gettop(L); } static int pcallcont (lua_State *L) { int status = lua_getctx(L, NULL); return finishpcall(L, (status == LUA_YIELD)); } static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); lua_pushnil(L); lua_insert(L, 1); /* create space for status result */ status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont); return finishpcall(L, (status == LUA_OK)); } static int luaB_xpcall (lua_State *L) { int status; int n = lua_gettop(L); luaL_argcheck(L, n >= 2, 2, "value expected"); lua_pushvalue(L, 1); /* exchange function... */ lua_copy(L, 2, 1); /* ...and error handler */ lua_replace(L, 2); status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont); return finishpcall(L, (status == LUA_OK)); } static int luaB_tostring (lua_State *L) { luaL_checkany(L, 1); luaL_tolstring(L, 1, NULL); return 1; } static const luaL_Reg base_funcs[] = { {"assert", luaB_assert}, {"collectgarbage", luaB_collectgarbage}, {"dofile", luaB_dofile}, {"error", luaB_error}, {"getmetatable", luaB_getmetatable}, {"ipairs", luaB_ipairs}, {"loadfile", luaB_loadfile}, {"load", luaB_load}, #if defined(LUA_COMPAT_LOADSTRING) {"loadstring", luaB_load}, #endif {"next", luaB_next}, {"pairs", luaB_pairs}, {"pcall", luaB_pcall}, {"print", luaB_print}, {"rawequal", luaB_rawequal}, {"rawlen", luaB_rawlen}, {"rawget", luaB_rawget}, {"rawset", luaB_rawset}, {"select", luaB_select}, {"setmetatable", luaB_setmetatable}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, {"xpcall", luaB_xpcall}, {NULL, NULL} }; LUAMOD_API int luaopen_base (lua_State *L) { /* set global _G */ lua_pushglobaltable(L); lua_pushglobaltable(L); lua_setfield(L, -2, "_G"); /* open lib into global table */ luaL_setfuncs(L, base_funcs, 0); lua_pushliteral(L, LUA_VERSION); lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ return 1; } blobby-1.0/TODO000644 001750 001750 00000001217 12313310254 016076 0ustar00danielknobedanielknobe000000 000000 TODO: coderework: - new clean rendererarchitecture - multithreading fps independent physics - new gui system features: - full unicode support (e.g. for Russian characters) - improve replays (fast forward, rewind, etc) - improve bot system (more commands etc) - more dedicated server options (black/whitelist, statistics, etc) bugs: - net bugs: - squeezing ball through blocking blobby ? Please try to verify this - flat ball (replay Mr. Enderson) - don't close chat if one player leaves the game - whistle at the end of networkgame - ... has won screen in replay player when game ended prematurely data: - monochrome font - more translation blobby-1.0/data/rules/firewall.lua000644 001750 001750 00000000556 12313310254 021766 0ustar00danielknobedanielknobe000000 000000 __AUTHOR__ = "chameleon" __TITLE__ = "Crazy Volley - Firewall" function OnBallHitsPlayer(player) if touches(player) > 3 then mistake(player, opponent(player), 10) end end function OnBallHitsWall(player) score(opponent(player), 1) end function OnBallHitsGround(player) mistake(player, opponent(player), 10) end SCORE_TO_WIN = 10 * SCORE_TO_WIN blobby-1.0/data/gfx/font49.bmp000644 001750 001750 00000003370 12313310254 020730 0ustar00danielknobedanielknobe000000 000000 BM6( sssWWW333}}}HHHppp===rrq000(((尰WWWDDDޚLMMqqr|322۪\^]EFFԌ7:8ltq-0/͝V^ZGKKƵɿ/50 ǼEUI8=;do2D7 |ʊMnV""&%θڮbo1N7foۯt·B|K)#*'ͤ{ٍM[-_4`kXi070Օcq.8^  Qv[|:D% 4 ~ԇip'-" ^eW[2;1B6ޑrz7w<blobby-1.0/src/TextManager.cpp000644 001750 001750 00000022402 12313310251 021114 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "TextManager.h" /* includes */ #include #include #include #include "tinyxml/tinyxml.h" #include "Global.h" #include "FileRead.h" /* implementation */ TextManager* TextManager::mSingleton = 0; TextManager* TextManager::createTextManager(std::string langname){ delete mSingleton; mSingleton = new TextManager(langname); std::string langfile = "lang_"+langname+".xml"; bool loaded = false; try{ loaded = mSingleton->loadFromXML(langfile); }catch(FileLoadException& fle){ std::cerr << fle.what() << std::endl; }; if(!loaded){ std::cerr << "error loading language " << langfile << "!" << std::endl; std::cerr << "\tfalling back to english" << std::endl; } return mSingleton; } const TextManager* TextManager::getSingleton(){ return mSingleton; } TextManager::TextManager(std::string l):lang(l){ mStrings.resize(COUNT); setDefault(); } void TextManager::switchLanguage(std::string langname){ // if old and new language are the same, nothing must be done if(langname == mSingleton->lang) return; // otherwise, the old TextManager is destroyed and a new one is created createTextManager(langname); } const std::string& TextManager::getString(STRING str) const{ return mStrings[str]; } std::string TextManager::getLang() const{ return lang; } /// \todo why no const std::string& ? bool TextManager::loadFromXML(std::string filename){ // read and parse file boost::shared_ptr language_data = FileRead::readXMLDocument(filename); if (language_data->Error()) { std::cerr << "Warning: Parse error in " << filename; std::cerr << "!" << std::endl; } TiXmlElement* language = language_data->FirstChildElement("language"); if (!language) return false; int num_strings = mStrings.size(); int found_count = 0; #ifdef DEBUG std::set stringsToTranslate; for(std::string s: mStrings) { stringsToTranslate.insert( s ); } #endif // DEBUG // this loop assumes that the strings in the xml file are in the correct order // in each step, it reads the next string element and writes it to the next position in mStrings for ( TiXmlElement* stringel = language->FirstChildElement("string"); stringel; stringel = stringel->NextSiblingElement("string")) { /// \todo we don't check for duplicate entries! const char* e = stringel->Attribute("english"); const char* t = stringel->Attribute("translation"); if (t && e) { #ifdef DEBUG // remove every found element stringsToTranslate.erase( std::string(e) ); #endif // DEBUG // search the english string and replace it with the translation std::vector::iterator found = std::find(mStrings.begin(), mStrings.end(), e); if(found != mStrings.end()) { found_count++; *found = t; } else std::cerr << "error in language file: entry " << e << " -> " << t << " invalid\n"; } else if(t) { std::cerr << "error in language file: english not found for " << t << std::endl; } else if(e) { std::cerr << "error in language file: translation not found for " << e << std::endl; } } // do we check if we got all? if(num_strings != found_count) { std::cerr << "missing translations: got " << found_count << " out of " << num_strings << " translation entries" << std::endl; #ifdef DEBUG for(auto e : stringsToTranslate) { std::cerr << " missing " << e << "\n"; } #endif // DEBUG } return true; } void TextManager::setDefault() { // Hardcoded default language mStrings[LBL_OK] = "ok"; mStrings[LBL_CANCEL] = "cancel"; mStrings[LBL_YES] = "yes"; mStrings[LBL_NO] = "no"; mStrings[LBL_CONF_QUIT] = "really quit?"; mStrings[LBL_CONTINUE] = "continue"; mStrings[MNU_LABEL_ONLINE] = "online game"; mStrings[MNU_LABEL_LAN] = "lan game"; mStrings[MNU_LABEL_START] = "start"; mStrings[MNU_LABEL_OPTIONS] = "options"; mStrings[MNU_LABEL_REPLAY] = "watch replay"; mStrings[MNU_LABEL_CREDITS] = "credits"; mStrings[MNU_LABEL_EXIT] = "exit"; mStrings[CRD_PROGRAMMERS] = "programmers:"; mStrings[CRD_GRAPHICS] = "graphics:"; mStrings[CRD_THX] = "special thanks at:"; mStrings[RP_SHOW_AGAIN] = "show again"; mStrings[RP_PLAY] = "play"; mStrings[RP_DELETE] = "delete"; mStrings[RP_INFO] = "info"; mStrings[RP_DURATION] = "duration:"; mStrings[RP_RESULT] = "result:"; mStrings[RP_CHECKSUM] = "checksum error"; mStrings[RP_FILE_CORRUPT] = "file is corrupt"; mStrings[RP_VERSION] = "version error"; mStrings[RP_FILE_OUTDATED] = "file is outdated"; mStrings[RP_SAVE_NAME] = "name of the replay:"; mStrings[RP_WAIT_REPLAY] = "receiving replay..."; mStrings[RP_SAVE] = "save replay"; mStrings[GAME_WIN] = "has won the game!"; mStrings[GAME_TRY_AGAIN] = "try again"; mStrings[GAME_WAITING] = "waiting for opponent..."; mStrings[GAME_OPP_LEFT] = "opponent left the game"; mStrings[GAME_PAUSED] = "game paused"; mStrings[GAME_QUIT] = "quit"; mStrings[NET_SERVER_SCAN] = "scan for servers"; mStrings[NET_DIRECT_CONNECT] = "direct connect"; mStrings[NET_SERVER_INFO] = "server info"; mStrings[NET_ACTIVE_GAMES] = "games: "; mStrings[NET_WAITING_PLAYER] = "waiting player: "; mStrings[NET_HOST_GAME] = "host game"; mStrings[NET_CONNECTING] = "connecting to server ..."; mStrings[NET_DISCONNECT] = "disconnected from server"; mStrings[NET_CON_FAILED] = "connection failed"; mStrings[NET_SERVER_FULL] = "server full"; mStrings[NET_STAY_ON_SERVER] = "stay on server"; mStrings[NET_RANDOM_OPPONENT] = "random"; mStrings[NET_SPEED] = "speed: "; mStrings[NET_RULES_TITLE] = "rules: "; mStrings[NET_RULES_BY] = " by "; mStrings[NET_CHALLENGE] = "challenger: "; mStrings[OP_TOUCH_TYPE] = "touch input type:"; mStrings[OP_TOUCH_ARROWS] = "arrow keys"; mStrings[OP_TOUCH_DIRECT] = "blobby follows finger"; mStrings[OP_INPUT_OP] = "input options"; mStrings[OP_GFX_OP] = "graphic options"; mStrings[OP_MISC] = "misc options"; mStrings[OP_VIDEO] = "video settings"; mStrings[OP_FULLSCREEN] = "fullscreen mode"; mStrings[OP_WINDOW] = "window mode"; mStrings[OP_RENDER_DEVICE] = "render device"; mStrings[OP_SHOW_SHADOW] = "show shadow"; mStrings[OP_BLOB_COLORS] = "blob colors"; mStrings[OP_LEFT_PLAYER] = "left player"; mStrings[OP_RIGHT_PLAYER] = "right player"; mStrings[OP_RED] = "red"; mStrings[OP_GREEN] = "green"; mStrings[OP_BLUE] = "blue"; mStrings[OP_MORPHING] = "morphing blob?"; mStrings[OP_KEYBOARD] = "keyboard"; mStrings[OP_MOUSE] = "mouse"; mStrings[OP_JOYSTICK] = "joystick"; mStrings[OP_JUMP_BUTTON] = "jump button"; mStrings[OP_SET_ALL] = "set all"; mStrings[OP_LEFT_KEY] = "left key"; mStrings[OP_RIGHT_KEY] = "right key"; mStrings[OP_JUMP_KEY] = "jump key"; mStrings[OP_LEFT_BUTTON] = "left button"; mStrings[OP_RIGHT_BUTTON] = "right button"; mStrings[OP_PRESS_MOUSE_BUTTON] = "press mouse button for"; mStrings[OP_PRESS_KEY_FOR] = "press key for"; mStrings[OP_MOVING_LEFT] = "moving left"; mStrings[OP_MOVING_RIGHT] = "moving right"; mStrings[OP_JUMPING] = "jumping"; mStrings[OP_PRESS_BUTTON_FOR] = "press button for"; mStrings[OP_BACKGROUND] = "background:"; mStrings[OP_VOLUME] = "volume:"; mStrings[OP_MUTE] = "mute"; mStrings[OP_FPS] = "show fps"; mStrings[OP_BLOOD] = "show blood"; mStrings[OP_NETWORK_SIDE] = "network side:"; mStrings[OP_LEFT] = "left"; mStrings[OP_RIGHT] = "right"; mStrings[OP_SPEED] = "gamespeed:"; mStrings[OP_VSLOW] = "very slow"; mStrings[OP_SLOW] = "slow"; mStrings[OP_DEFAULT] = "default"; mStrings[OP_FAST] = "fast"; mStrings[OP_VFAST] = "very fast"; mStrings[OP_LANGUAGE] = "language"; mStrings[OP_DIFFICULTY] = "bot strength"; mStrings[OP_WEAK] = "weak"; mStrings[OP_MEDIUM] = "medium"; mStrings[OP_STRONG] = "strong"; mStrings[OP_RULES] = "rules:"; mStrings[UPDATE_NOTIFICATION] = "please visit http://blobby.sourceforge.net/ for a new version of blobby volley"; } std::map TextManager::language_names; struct lang_init{ lang_init(){ TextManager::language_names["de"] = "deutsch"; TextManager::language_names["en"] = "english"; TextManager::language_names["fr"] = "francais"; TextManager::language_names["it"] = "italiano"; } }; static lang_init init; blobby-1.0/data/gfx/font06.bmp000644 001750 001750 00000003370 12313310254 020721 0ustar00danielknobedanielknobe000000 000000 BM6( )!M#@AJRMB 7 "  $ :&#! sJ )  N* =#&G)9aԀk}`lBK{@& h @+7' !m֎{RVb2  m#/J)0 OtX~ʋz> stream xڅ= 0r ..ĥm҈-WS'{|Dx$ѳD"矟 |cO; endstream endobj 59 0 obj << /Length 5338 /Filter /FlateDecode >> stream x=ks6WQW1cjlflqrJd)H^IAQ AS` @7ߞ'>Ub"MSIr+υY+vSMϴsW<],4h?}*D2 8LA Fw>_lg*rB1 \>Ug+T]vn^f (ʩ,fYqԲP'=Lϓ&-5m-7>_/.=?N)eUÊ͚PJ >;8@b_v6]]vJ5\UjZjBwꆉ͸Fx_klfFCUM + . ;2ZKaL͉e͋_UjSwxO6I/m1oj<4INi=+TW[ 7QrqY5@JzSZg;qbR@b[^2 $~S>.]?uM~:5mWo;Am}z8%pEy9i'~"E( }o&6R8|ˍҥqaKdSM{b߿ժ•Rv?SL7R07_W^o$xHϨa4#$5Rz՟oyiCwvI.5:N< ~sù"n١/ni]5 Nކ1;U)5=H-;ghkEH/փuײt{1Bv'n'RqTG?ZN[K7zt'hSg~x}wdJס=XRV]^S@96P6h?,e'8&`)8-]S%#|t6C3Q%)U|04,QghЂ\8ghuYS"X'`0t^em7PCt%<<(JVYl(N#IR-hMQ&2ЌCsf C[ U ]t CaSüS:S@U(: 4 HdЯ!bc/O!b'bC=dG5TR~ۛ2,. U -sɃBwlöh| Ty"R(f!%V -j}]iA7!Ʊ-{Awn<ߵJ.sE0O*}1U$WN`T}, q*ԗǺ$F'o*M;Քj>=I5)RZ 'ys 3[oA Yn(I'dVI=^-gՆs7dTP|Ky+wP9|+[]5:'@˼ڢ/GM-6# ̽@y7kgTJ&ɻnEFRxE8U鋩"%mtGK !/qq6`,CZ oBႡ5C ݬAO.E0.JZEIoL=E F%w?@z`JyT뉨/u\ O$v0tm9pؾ َ3N kq UHM&hxnT4Zzn)#gkyG/:.s[iyG|d>xͅ -l@ـ(ޔΞ O qzS_Kq%*- ETA r%ɬ3)N_Oqv>;z.({Nq/駬[qsHo)=&Eޜ`UHԚI`̈́7eIY6=G>Pye}{155 +ԏ"v3x 95mFiY6yPeڇhΖ2| qS_-KqۈtG uRԞ%W|sL+L>[LΧ39&_cy:$tN='zC%]<$i-E@,z$)La}9\c fi\kTJTncou -:ATS_%byt64QePZX,??d}@g <1F%>h0!5KY&[  A"v@Oم iFTW*w TS_%Rgt6"QЎccĩ<S_`\ cw8mbt,4E2S:>6^q(ʽeiaO)]&f>ѹ#uO|ܳuGag]FЍ/>T/zK-Q6;UKҨ:u  ܑOꂶ?ytն jJ?`h{+^u?SDL%3דAdžC@D}QMt#5>jd!14pY&7{nEMO.[~-Z2f: =~$&P-ĉ7ɻI#w8-jQ:=]EAOhkU1: ֹn\B3,ؓo(+hjՕ圷K5=V0Ѳ;k/'CCFCw)5\3 EO-ĩ±/±Kqm#Qte6ݣa0`y BN7u뉨qgIXɴ)qsfNJ+]O=tW~kSعi*I[ p 'ޘz#:'~l@/S8oK"/Т F {6 -8{ɅsvM%xH@ۋ rH@d; bwX7Z\tݢLQW^u,_6~Gv 1b_ mZ0T1tс6 N NOUL;b~tQ nA AVpE8ULWLwI0lMpTbZFUZQJ W{֊[oN1ot&ߧg*b[@J22hګ,#9 f .Z6v J t # G u ? JH*|*H E=@쏮wyo='z@#c ;U]/E [Sy/<%<6:yHpTJKߠxto tyNTM^s;f-$s-Bs9\NYrp>sfo3:q^KZTY3zҳӬmPXYvWl^ƔBGP8xbwXh7#~4u},"M)) :& '8B W`\eht6L:}JSL)U}1&(9^rFǸ}[5wztBC>/Et 7^;lJ}H-7]esMGۛ%"$ 4kw9K& OpZ>΂5Jfrf|iTDc endstream endobj 100 0 obj << /Length 3421 /Filter /FlateDecode >> stream x][۶~[K~Ic'8qjI KW.[I})Q8!Abә>,@\>\e69/٤۽_}?8ʼn3drb,=y[?}=anr\U>']n/(nJei@RfV oQ%JOZIhI廉k4UbrP⊲jMsx]1)[<^x_v,g#*^C[letmFear& Ǜp,9ɝ̈́JQs[]QIVCiO%TdU B:*=HzW:އ-X1lC8/fUnhmէ;Tn"sJdJJd KdaHd:m)%"#,! A1V}upF9epBה ibv袵sVnElhf*#b1X#cŸ,'D(r5B(9 N %]%u %m %t|{:u ucG:URWkC0 oFWƇJѕK4^1w5<*a0}pLgf:k l^08 B#d0^V_{K-4"ko2=@굁Bj27A҃pKY>NA9^Θ &E CdYg"ay %U0o/( l*fd wxsqJq q!&qt/ J邱J{[ke8* o܋ϧ8[Z戈H_ABZ6 +Q\cDXd& *e3|XC<g_%OfmMPȏ|`,ke:Ƈ :0]8ޅY8ބC8" 'O{׸иeܣhܣgd+#TURW҆`X28 HǷB"W6qdFN^Cuf+~6lF]uOZ:JS>c%nL0 OQޅ!cK$Yw62sjGfqT̬S !u/vsM wl;.(ѣl8 Ne']%ue'me'Pt|Ji0"Q2_saRқ3w xCH'wGr /t wC?xMǒJE<$I, ^</Ћ?p|8y((U|3Fgo6RhgJa\67>>phx+ޢRtf˜NձXaulpxHǷ )Kԉ;I8 v!xE? > 7~ad% !J}JS<#r dgzjfOWgW73Deugv7!^â۷Թos!/zKE R> stream xWo6_G e} ehȒ@Q_;Q7me{x$w gY8Exvbqf( :mv0nNH޾P3m$ygtfIɛN˾ASoN]i`_P@ > k{Ë=M>g8ȢIQ Jqy`p{[- 4VsHZʭj\2.˞;(bMCk@@ qVcGG).)hG;ɝ.eS YxeFOtS 2 }RNAL VQJFA,EhrlA* *uȌFdb%4VL>tsu- 6OF'}Bj$D+^h% ;+lHkӈFS3}nhl >@D` AŠ]JJ}\jC7&yBDm ƅNF0WrRb@5#9<_ U.u%zdj$ cG6f'!^I%YNhs8#p@:Ĺ~c!_">In{˳Gb\.xʏd8r*cB6T,Z_ om:y٨ŃI}JbWS+OO ۼT endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 782 /Length 1498 /Filter /FlateDecode >> stream xڭX]O[G}bDh"Uʱ/`"Z gI01aT*9;kG"yKJ%T+9O 'H.+_réa&D\-N>_O> _ n)/&0Ed\ Bd3EKn"ˡM2BO;vMBt18¶LYW:xG %?""29\Cl22첗q 2 ZOY 3 W ʈBXI]lMA0c *]Av(;eb04Kd~BAmh"HoB+&W7J~oU෢:Pj㐼pwy$fA s*<'ԀdnK bx1G>ҀQ!)BssBR#p*rr" _ 5sPI *#EȠ BC P% <4%C98vDiO;z&ì_޼i^z2t#rFG*+ذTtZ.kQh*R*Ri#bllU1b0lUA1{U*"ʪ"Gr~U<{Pk<̷ljN[u!~#baeߙxv: @6^~,󯧌!=<8 n|_] Om-?ϳIVnl; EKw+&̞^(6)mOrv%PjHqR_ > endstream endobj 129 0 obj << /Length 590 /Filter /FlateDecode >> stream xmTK@+8X`x5ZIYKImXh 5IEB9wc:{Zx6CHwF^ڑiöh0bIBv-p;qt CA-}~0-/E"`of3QJL{ȬYx6QCP,ѥ O>2:gQEB'vYteڣ6\n~q9g5@~|]1gMU5ToYMǹqv(mWt8Đa6P ^:ۃWv޶:rOkL4<)u:KB5$`:MMwt}Og?ķdF GL}& =Tw#V \'"*77(sMeˈY9Ir} -=D=AE2S %Z24 t;<ߐ0~IR--Dk*&VƱD4@BmGz&il3Hs_E+P?8$S:ah endstream endobj 143 0 obj << /Length1 2651 /Length2 31389 /Length3 0 /Length 32889 /Filter /FlateDecode >> stream xڴeT[5S An5;[[p n!Xps;b._sSJ]Ud9Y98* G3'NVM+Vh9IB~ @ XppN@W` Pʹ: jnQm) w nVߑ~{K,An3'K" @ @Nsdhhj4tԵ ܝAEJK[G --t:AfjC@ hKhp N?A*) j r+ vbgdvw\ٜO r@^]qw m-NnN*!N9?A9 46fn*+l@'3' ! 0KZ]  ;ʿUI%AΌ| 22NR GGHn(银zwy:?VNVtwfquq*H"B# ea;_[[ ! 2spZ!/(nf@O#N~2Wt'+@o15 mUF>99x,V( 0d$iKA8_C3G[6=jTAfuZۂ-lo 2N@Ȳ% 9l_VNA  !*^d,@N.^>7 dxyz5,v6'pv@(.[7KA]se N `W  H?AdPdP$` A$?H3 : NHiуX@DA{ d--qtҒ? 5? E? O=os?@LDoBR͟!Tx;aBdOFH{G҃ 1G*NH?@lANҀ5 rY8,翤<Cvڂ!Oq|ukYhR !oAc;S`Kg dQ^- ʇ1;+rWS՞wq0Dn +f&.j0 Ķo'J%f65RM/{ggPZoAZa{;h@*wuKRÂ_3ܔ#x8]gn&Ft⓸\JԻZ[vЗh2O5ub>E'8i8AK_悡.*tx?d[T?_š-uOjݵ關 Ív6-"%"ØN/=ki}&G`fE19& X0sTMKA\n_)`;K{:pi>Y-Ww&0,EPtģ-'"Y6@yrإ-Nb)Ԝ0o-R oEdy9ByxchEmIU*T^YvB˅Ms\TqD>wF=[ВYy\ZG5a黰>3Yit qw `ې+abV.XK#vU lhֶQ$ h`$|?ovi6xqrV"yX5,|CM5(:I,YpsM.'G)ľqa g\lkR/=e]fjHQ?귢1N~lmbD\|#;%{s,,`=;ד0Rr.-:+|C̍5]k=eZ6{8-af5W=2C9GK#U6s\BGE0̀tYzAIU>B'(f햿Am=μQ}x¢i*\3qS{/%k:}.p!ra3&vt5Xf2o>Wٱ4 Gu(ޑ1ߒ cg5zvr C86?Y.J1S#u1~DɊf>,>kzՁgbXFC)x6Ie.GZU%Ag@IغY7-Z$[;'Ky v1#cC5 I)^BoR\(Qd"4{\c [eL=,~lđGuk@#-cg H'rW E9ݠS`Pru(4RoyGY z U \>:|&njA=, ѧ(nFsB-Fl_Wf F!pPܫHz䞗Va2iOtgM%pg>@(@I Pv6L(Ze!m3ST£Fe]#^Z7Mueu\9\9?d 髭'KQ:|یҳVԐ8'OyqwM4Tv(yyFdn n bqlm\0OlA;9ZAD'. Ip./*YSg:I-&euZPogt,͘')|hCta1\3/)}.'fuO)12`3ίm>|G !#0̘O G]Ȟ}z)΢Pɦ?ڞ,cS(̔v[ȷ;1gEX*{+cY }# 2?n~  d_SZc,9QЁR˽OIbD9lHp#k u(;δe-0{? iYah =g5ؗYB$ۗy5#H~\a ꨃYtùyeO%0qm* !9Fq5[Qw0ɓK+. +'Zb,yhmՇ%3.D^%7`YVN-ΤQ5^~\kaV귺3H8ձ R9:'$%xl¤@f~mI~W  3Y靵F0&/ 4KYeHWz7E5 ,4s08,Ա#]-?NDZYChk[;@ef};!X-oCk]pg^):m~sa SE+1RD&L}ˑ^&VH\uㇵī:BvyR7!صU$i$ ˡ8c?3ބMM||RG .G!k2c&P>Ĉ"yiB ԲWjǗq2nc9TC*4,W|Ж=?\my,G&Ɲi+E\7μtL_{}s/;bz"@pqQ&:NWT+ƿcI^h9ע b'(ju#Z.13IzӞ?.VP$~WGMRz8GptҜ,O$LqՋ z-"qVC*~m7Z, 86OˍCPe@6bZ*^}tL{e_~}B [5ZixE@#g,AKyTvQFkt^";=#(Y+;*+idwC-lE? T r;7T6g{<8Vg= Ӌ<Ʌy{E¹ag+e uMd 'd-; *]'tO[+uǭ ,N\1[dZ)uWDcn8Ivf8`ŋG<\ȍys]eKh}>/<9ER4:T;*UJ7đkVKMyX㸔3,2Gg*E>FtN?S)*C[OƚRe)ip'  Y^ت?֞-]Aߡ@slvL ȊE& ZXŤɿsbŪ^!c-2yC|i8rJp "^ skcKX[~*?f~ My43cz63i/{(YQL=sG7K6^:lk~0f$[u׎ؤ5<*vCW\Fhox(ԝfI z)t^kU,\6:#0 ]X+ ZpK[/ɓt0hYXPdLĬ:QQ?4Ĩ듡+դ4_)@"+F񽛕7dDcO/u6{:Fi΁gYSB_BJ7ҬlnPǴuzTSGPRB!:ols)Rɟ/ Hތ1R'[RA_5l4r'1B '0@'zXۤ3LlǑb;1j֤i GjzS="&[ǡMbn>vWD/J~-t6k62]; ݹsCcO^<ѷ2FS]d.$:r"'e#R]5f|ȽS6/j'{X^VMB+Y _B1W aj9/H7be% owKn'nd. VBF$R{ mk%mP]rQ=fc˒<+`A>jE { Fg& M^4{'WF*;QNț@ U죢G{?, 1`>hS?;0^.a #RA'^; 77O߱tᄴG_D^G"vTK >n|iˉ]bpR;@UaU,X䩽5F@9}1nz~",a[wqgvyM< Us/QOLLaȶhCg()[6*Er6 3\ʐ29,rӨMXpAVћWUu5ø*p1Oh:HOZ.!l9K]& ڊ~BDQ͹f4^ %U̽~|.<(~SSKd:B+8zE~AlLb)=zڌ- ll|Ȑejº\>dD KN~3lUaՃsaV=8"N0·MPUX;`qn2(FA['3V~}v]>>Q,|Ʈվ8Me6>MƺC~X7aF/oP2'F,wT>jޱ_ߦ ;ό_9x˲maMGU|E+Ѿ`W$+B.V>pYn55cEuj}}V.@(iGT6rQYzojE87N"un o= Os\/ [Ph.)bP5;x9ErMob肪 9eU1֚ç\{zD˅|G;wr r^ 3Td76[bD n^ uV: `X"Hi׌L95ӤHߜ*jwn (oܑ5#+)Rz/j lϊ}c'Zg9ݟsBмJrǵ|{~Ev7W$Lm~w pkiP_ar]v{k|*X@CD$^i[πQZ>_mx㿡ô 5ba|)#.!;4*<(J "X溻N]=y):ٌm(Uc8^&ۮc/_ 8V*)UJ>{ZAxS@yUuЈPZ&j;t8m]u|x"E68t_6?^Qr]DHtmOhpd {V,)͛8ە;H>spR$,urIܹZ{!Iʶ-SlZ2XaïfnawtB  $jV~~-3r\}ͻi7cdlJ5~W{pck9gכPham ?_?y,~zң>oIͽxQÁвs ޽Z8 gZeˆ4w"Z`Uf ^i蜾j|`nQ&]{r$@k LN g*ȯw <&?t@:Y9 佃OVW 7R}+u}&$w-XܞCu&1VIѱզrZ M8C/+=$%arq X:<܆ BW[M*>Y |9M7^듧 \SH06>yi 4)XE1VKgԷ$9ZO*Iӓ =o%Y g,/!0OK1G^6&+7n&Gу/ySQ-+L[µ~^t^gۋ5*4$nU1'F2]]e'w>1bi_妘P>]'R2L1D~P"&RP[D2 Myk{ixiȫڛRM(D7g.[sˍh湏{Wuw f}SC]m ɎC֒)z_9 ׅ]( ƞnUTröԂ38$[ c"[bcW˱!*Wuˋ R]9Ey)R>J#,C%g)E07՛=iz"AA*L*i!^܋qR\%M##o+s,DO)B#<3c0xȇXΚ5„^i=]݌{.xC=)kXRViX+zѫxe͠K,YjvUӲRZގU&Lַ)ԭwOs%vyhD$h3 i ?͛5 nH:ag?32EoIp+ 'EsMI°}ܭANnX=9Ѻ̤} VEKioJsTx ,~xZ],N``V~S&,,AX_f\o1`i` 51^Ş _;Xf0s;R/i!V`^rpCk+?(T~^1݉Βǜj &F%\Kan *ɼ1Z RROKTJIθ$y;2yJyO:1nIg{8/J~.rj5R:ފmYH h 2|0@ 'k/kw\#{\ ^i|"sUczpŋ<_-'h%uf vrTGr}N'3o"!%'/wg^Nt|S!}Ra.MǕ-V_,0c_ & Pp6y?$@q4=fx4ϛKV_6Xw Xx\>u؇3+a(r>ƥ#z5Dya @[jޓbh"ZaԌpqr AR*DhppIF2| VW/uӶxƿOaIލkb鰢1UٿΆ%a+&_0V*G_}X-[\Qq3]i<ʯE6U V-yΐl>O0bd|'G5?77R  dHlB3];83u,ZY[-L5%:r0 yo@vqI `7|Jޫ\}P\cY}g+*t˨&c+b".W2}.[O㜁$gP #byf5HM?b sh(3c6n QiB z_uck/,&o3Ah6CXٸA 7'yf=))'D~ݾ}/")p+{B3\t6(%X4AH))uӣ4ڰ|pP<}5،U5.UlVLWن\VFzlL>_q`ηOS"{(M3Y9ijc) 0 ٓͷ]Dw*)u~x] rlI9dlh4f DFx&}~uk( _'RޠAjlo>e vY3w{(_Nƣ7kR}PA0Aj(%8A-p8 獽ff/[J``( E3Gk홶PN,u~|l)Y^fn~ (fqCwiֽ?s9mÂML%Y֛_ߺ&hߞNWR|K|)umGzd CY塉>Gg$[1?ΞE,1r'ivyswG3 ⏪}:RY{[V^+"s);qP̧yP_ITq/kn`e2Zxѱ bY~k>'G~t ka:snoor.i` ]{ΜĎYij=LJFS y9#>ϼ.or T|աmHiqVeR:%fn>^NngW4/62_'f/Yn#7L[yTޛZgT탫VO)un)H#c|.Bf񭞓’&w<ͮ;lʼn,Em{-'fDB=:AnXBWSW- χ''rl:j#jӎk'9|`(#Cs}$+Ѭ6e҉1Ee[k*#p3q7ěCB]KYn+!oF }B+(e~\* Vf”Pv2@zTaXT+q׍΅n_=Հ~Nֆ5Ge}rcG )&_JզSjOC[,9NX[TS;9arJ\~&&!ğbꇠ &' /_41 ÏH"h[>{1n1ss*fXbhbtt]^oT]ABD ?QvX0ǞCHC6+t8`5[TsNmY7 0y6ܬFm$5(O|P*;˰Fo!Abr}eP'A|'d"I27tt=(u'ͧ.m @*&ZSR_7RdڡDxhXTnGKS׈O?j't ýy=dњ[wss>ZK%W搗~x U82?fTYWp8.bÖfbMEyFFgO`\O gߑů]\(`{> S*E8ET1*I3r 3*g4v@\gbcx'O*+'b1J"L!hncy xa~ҋY,+wҨ" 783oy/LKMq0f\Rg;hm9آPb鮛p[yϝ:ׂ%}mwpb:" s8ycUΑsxGb(U9= hDg'/Xy &HϛN瀙teHn^ ;z TbP_哩5j_7]!uh8VpD+.Yѯ3}Q qa~,IUB)Npqq*A9^fԌbѾKuي8XSlﻣ8{tcZ8-3ԑe+ZML]ܒ<4hM16acQ #3)jfLz1n&hzSIe26%_SG/쫓ߑ w?F=4"Nbml|8+`nX5b;Mgژ:"Z$$@f,b:vnrN.P*cRy ;cz O0NvfKWӴ5ٶV`RGx|\Åh]N@ z5Qj^cRM ,p0rEz|H ,fTJ7:.Pk_1Cj̒uԱޜ% ~kvk7KcꆶY6-X~@ClXB (ĆmÖ(bDѶm۶m۶m۶mm۶mw'A]ƻAP)"kPB0R rb<1MmyIwB}mPeH)ؔ EebOX?~FɹW3(L.cn ]R ms9LIt驖 󕅸2 {;mК^=bEěPۉKhk@3m6lx|j(l6*cMQ_lbL.z4= ҉GʒhW8emb~ lhٴvл?o$J\"u T=kGjR2\l9R"K %=QriLC;eS5(sg}r *>@Vxoo։H"96w5LN`v G&eD%\'f^x+Nd}h!z/Aêrt=zS@?JĮB]%K:饢R7r V{w*&%ݏ>N|FՍx}u- -/l{hc80mjl!ĵxf N.(nYXz4|?.RTPF2σ)q,]iX.]َVX`ȕ ;L5,2C>o%A Y{}TlQ?FݨiɒTܕ~4mĄ%7W_^}F294!tIln0`3 `ZNU=ٶM(apdFW-TpukX Z@(0IY9'LW5gP.IpkDRdwjv 4~͐t@n uL{{8}=8FD ɏ>PH#e\X¬h\ϥǑ^+{\c]+X/q.^urp:xMcmC:⫝̸B̥n O" ΥVqC1 ۛQǕMGhnOPW"S %&ٮ7XEPg`YlcGV3.lM$7WlW3T8)+/a m|RH?0m2Ix2;CF^$L' ^J: c%Z54&Sa ԏ~\OG!M=6. ~؇MӼ#mZ  jF6Gwt dEZtyZDA ? Hx?Ͻ0vK5C))u)zpB zj-NXqg" $U2In^>ю&1ڨ>|V!6PJ-d)^=&o`.$2ܽ*}eI;XX)~aWu{zg>YN֧;T*(QonH S\9% Yl: {bfGp7'g.c"YSs[@;M827Q~%<ǣx $-$:V)]4!_c@dZ]6)1z0Nѫg=V!W9ܚn#^"g(k|3sFE "(=Gs &$_Mc$!E{TlW >5JM$qja\%_[a.Y`҂ bk戅)\} >YA6|UyHzz˖e/dTW k0"ӪO|Ͳ?ωc=Zr*x#m[cT:5wx7X&L0k3;6J: ~o&؏4ҼUjl@._r1!Z`"`866I}ܦD'H uDF8p"^!fkb&:ŧLg,FYNC` ڲ௣<) &;d"&qGd]a %Fd;(ԟ҄xo9_7lzD+(fu}q m2tF}A2r(JH"m"obVVʥzrvڭ-!q/1Ć^n*㭚$.=zp*p *lcd٨O"u܅%B\}m"pb-Vx(PA^ cn WHV+Ȋ4>@^vNފY@a /" ~YҁI_ǿ!΀ZZ2|y;|KYp1#dy7mh&m27R$ڰ#YȤg-n3b$A:ZpƫXEާuGO#n}9ul$0 $81j΂)W.uRR.䋇L s2u&>P %m ynW,Iqbm6X/^locG6ȑ\yKzPҍw~6eK" ̒9F S),yh?Qdȸ|&lʎ >+;?m1֗5øm6L&%?qnAs v-LrnʶR3^ Җod !(DqO/ vۃ!~l4J=@3e- ~*1VjٱRй>d MܦjkDf?+aImg_Pkq2S* "52~nd<%~*FD\z/Sf0ZTJ**슏ʟ$# y,Y1q|ZǑ >\Aj>%%?5YU}d^@b+uŁ/)4cT̫P8H$#1D(v{֩`YB%՝1D5E=AJxanbCZu=XC{v9xRƙq~jb6- ,qWF[ AAhܺO>{c D6 EZKk Ay=gmH1&L0bnzvf1i|ȶB]dxpA{Ua.-Ŝty䩳d9J6O0şh!&}xK@B`ȑxbNvIx LP*fvB-ieuKfDA>yɣr6.c\Nir: (}_Y B{k>:MN>~m46+( qY#g@#8犤Ng1HKjq7e`w9D)jW "C6tړ..0␢}kU_'uQGrg[2lCQUyMшnr1= w:9@9+ ?S8Ԡ-X.vnK^Ep8&(w$2Cj %~m;ޚ0A89a*$I6e:zq6ZF"JrsXԃd@-wS|k*8s8f  +YqQy?]Vwi '2Ϳ%mn;C&-"K]3A }e Y9oS\lӚՀ)# {,<e)7BŜo?SlvX #>6i[gtm#y/YbonJb HJ=[v~kj)_k$-~~ 6o] TM鵨VNQQ!tE@#M堚g9v]l Oq5}cjb(EM'ˎ pH(t q =]0SL%#|d/5c(5,~Mu!lh$ejdbGJݦ)i&PÁ=2@-'TS~@V|Ĺ}]ɐ) J>Wdʕz=܁.UG5H>ƒm8Wk=^S)ZQ^S!`hT4_h_ \)#{f: oi֐ .YA,3 QtgvaV'eC6@swRN^dH,ʉ 9A>Tuj V"UVŗUX)Ra1끹:W bh<9J'c~x[q $~\IԠ&BvnTIH0*6I/jߦ=U)/%/#= u#fa#Ec;0p14*6$Z`~PO,ٿ` SLgd&2.6,7خֿWVhd[J\Klg 06ϴ>KN4>q/zuKI:R6'Ͳ"3gXZYcuk:O #ɱuIY ia{#Ua ʇ$qGImK3{aYc f/B2ΊYj#'tdPsDZ1tysl Lۜcz7A޴ɖ{ ;0]~@8?Bkv !zp>).Ⱓ۞矬ŸY9&|,5Tx \)-z|PWEn="Q7)z7Rzh]ȟe`?y͚ TW vB0.ί @΅gֺ + f~ `{櫇bE"+?0̯"ۺJD Ĥr&gKl;ali" YD_'d$™$/xԠ뺭jn yo W:,܄Õ,8ޜO7 m%VЈ#+Ի$?]zhxF΢?Է--ZIv˙bHu:_`E\7QWkH?u3>\i@ֵ][zMG_+{ýH*hM %5,R._U\(I7e.M{QOE?y|:OI2"#F %"kik*.)o%MD˔ }SN.m߄h{:q>8JXyu6'xi(x6o[֯op'ѦQHV>KNL!hj3<ׯO0PRgK=Dn}Mcf:GY53)%;(wGĭCߟܯ0-x[UW!+9IϨhy\Bk8#,,(5ߛޚ40]#dS>k*@&3_BP޿xxAII~ֹI\f''5Ezg v)E81\JIÕ? +piije#`-5b]~W;CזvytUuwJ -V<wϧ7ݿdsDqmۊ'g܉ HuCۛd=DlM2#HswZwg8•=nt`FCAH:t2K/uD#BeQjgH*TZ*GXelnڿ &0Z bgKjjBt*8&ͯ]x|zH` n.KMv n&bh5glcNYe[DnM/lUI[vt9uMuLyj@iCtOe8.*!zǀA^sksH\C> dV֮א0 9NˤKMF9H`ϼ Nŀ4$jQm,խE,&|zebSǂ*u n{oQwn_ 2 {@_Ja,Js\8/԰q0Wh~8pR!EnT˧Gp(RD޵;8 N9v{j(ɩr~jZ/g dX>^Ԧ̮ Yg@ 1Ʌ (ϫ 9>gY lXi6=S@lVxyM,8'TY)L(/7uUXyb|^VHR Ӈo]xά~Zhbj`gJ C3"S6]j^/@p](0ˠ'a[\X{\TsOM[c3`5%rs"˼L֔3ï!8!0v ybυQq] .l%#,0k5Y]z-9<`LWܪp Bc+;*JT{J]-- < y7.V˜NίLA2(z¢LdFhfxQF ~~_K8_d)?n7"w8dynxAplmڅF XrKVYw_OThI$^z8e~:ˌR&@&mVR+ CQ .7AGGCt _ܐ>*m0Ng31 bmc`pDd⩓[1b AxM?Ҽ$SolZR sQQ?u ڳT 5e )@ 1lCJk@hv%?^tryMO󮬭ܒ]}D6hԓagY4N4JP2`IvM9465|Ԥ1Au[PPNY6,<:Q_ |p\tN\޺V(4pM#y[Opb)c_*8s)X9__NȫپB /W]@-!d}A+!? Zz^J i4W4m=.7;TrCP*5i]SR|ғƍ- rpXe%IؽktɈh!%rڣΔM3@n;>C1,YPxƛ0Y2!=7R0"g]լ1ӑЧ7!P^L`~։p@X;榽D\|s)mYCms#lkbPPk5 Dx5UO;9v5T b۞"`8%{7 OMǒyrIgQ$,`HTC@]A΀T :02Z[5ԏ;>V-zNK(NwdŰ}q<\)Џ ?h67}v L8Ʊ?̾%_]T^GbWK+\-sw:xVz`ο5%$/#[WTS8wo/nQ>Ύ\c-" ,,LEmWquѢ9%z][B1Z0e]*`l׶8(;V ?VbqMqtM:O:1pz'P ij/9 Dz~˕:ո5ѱ5DP Azq<'$Ҕ^o{05:^oNhw9MRzxr?(Х/Dd".P[qH`Ή<݅·dwzi_ԸΆX Cm@u+#)VNÙ'`/6Bx(TWAWUt'n)vYlEoB&vqa>P8eO?4lRRc@x%gJhfTQD+*I2n:[K~ʑ:;( gurtPۑ|UeV>`2zS[30MGGdZ9ST#m?՗W\K- տ*ķT7-mXNX ̃iľg?^6!u(gBx̺dÊCĿ8[֮ĿܭOy4NoњPi(µ& 'w'4J9aID>^E-hDXXx0ɗ=׶X-7 &d%73hY(< Q۩Cqci&Qr "|&*$S(l͔)$n\e- ÕY\X [#NЂB5ۮw xDuLp,iFՅ$@ pP\Θt:.ɻ~9VE{I'Z\? ^t]n/^>}P.vtw81-D/r_mDӘ'lWwbfG0eMɓG;%P@UDW/#5D.l:" -kwu SY >2%uOt>}Mk.,)'5ZTo4x9'ƫN@a_Ҁd r詇< )*D+!of3P#720tR^{ī@(!zk8('$paլ FYL8dx@)6&{η@_5T"y :F#2Y95DžW5FsPX{fl$g "N(#~ Ӟ0R";h?~sq 1d;ȿy:pô}"'%VrX=ia?9I)zwe݆y8=_|]3Ah .w|; e& |(Xuh81߀`wš:ݺ^>j\cr E"ǮOQ2RiPb"B Y)@4/\bk rՖpD]!NIq,}lCnlҏcQ@vL"D*-r' Gi4պcx-{ߊ@b4]?V2 :k%6%gH½0 C.aH2Υa:v?mF.O.ĩ^#YfͲKe@k(&piteY0Q-5jҷ'C v$SOgr& [4<9dɱ3VQ[V%qqf%lzb~q_j~#,6:D}kȧI:9T|=iQ兠rO8*mz; /q,fnڷvBOO\$3oYW7:˰x]dn[33wRVsgArip=b3:֤`2֒6:<楷$;7:3 zB#kJVIIRfO`QZ\Ƅ'k -] }ۭ-Bf-|$lF3mDrph @N|[xב 8?WOY .T̀y2ql+ E=$v `}Oa@ϵGR '&֐hu S&bZ9v,J@y4T8:ڎBjS4{P`8eu 8%-{6Gr֝tyd; =~Bwd c ;MrNq3G1s-9l pE)+S@u9^AeV ڒ?O9 VP$uOa-6TA*m6x j[$MM-FL-pF]g3,vK5r.!b&v9ߦ2?s Xza|NqwE+]lg)9n>/-Ҧ5`^O)izw@tPs@{{ ҔY4|<)$gBЭuV7#Z\O{Im*q H(Ptۡ y!T'5{`*mAWmS:b&ZHEM_mŞa?|nӱzfu R䀦l 2r|8*3=K:]£{CB>It>QYy`.gKU.ގ|]J1#} pw=\꣨xS^ċRf@BoH~`O(%O.O%'k)ujchs`v@2\ 3 pO_2uQ2)Wmu&vhjtG5~L~`I=zfIQD`ԇF9TNɴd(Xw%jpሐeINI@~Bo7wLtI 2:o* _;Zuʐ_paoSyXH@48= ײ~#czя㺫! b\rOhz1%/y'q;NY4r:ttMJQ"we^\$#Ж?\%qD@ ݺ<,8yEWMH! # {cKZp+T'ɢ֫&4*+<Sjy|W_hqԝd*%M ) mti%y!#@EOX@ڝ>$h FČqj`x-|3=^j Dڤ5=c,2ri|?WTxw*Y7kffR+1jq њ]Րc1z}jȈl-U ȳI~cݧdƃ>uTHd|մzfE#vh"7B(qK daxE-ꗼKŵA=0W)`GR>ͧ3q~MwBW䖏CN:cXY8c2ZwuٻIeg陿WH> j %V ?E endstream endobj 145 0 obj << /Length1 1919 /Length2 21316 /Length3 0 /Length 22469 /Filter /FlateDecode >> stream xڴeT\k5 wwwwwp-5[ xpwww $~Y>Zs=5j%: Pޅ`glƨp5ؘXX8()A@c+{ c l‹@ AF3'@bd%880;V@qGO˟쌌2c8;XrLL%w`4584:MuI5u:-{buWGG`WДfH*iHZ iMu?@w %w:%5D5tU$Y9[)بޑjrőݝمdh> K+g~m5콝.%3)'H_FV]{#\;2*(쌭]..΀Of@j( ezČ]ћmS{g+gḙl;_:EQ%Y)Iu Fw3*:wǞ/?D%<,\V^;I%Q;#i{\@/mO\5\B[gtN%叚ގsc[g9l\4 02uy ]/;5 hZU=5s\)AϦG-)W[[%c; t4wpAK3L_^R}?_FVn |o ~f- ui56Iڛ:Y[8 ';89ެ6zE3{`B3Pn^_/of;Rfwl `="뻳K9# ="'"D. 8q;#"{Xލ^@п}(*6)ωrj[ZEd.fo(D9xx3rxއ~7bMuxt_=K!iMe~_fʡ)yN+tV3g:p%wɀE-YTE 2|~)_u(Cl_ZTEP$E4Wʻh uK8ڈ1lSoS 6 ݋X?l1E* qYid!8G/Jo5f,{rp%9E+,*n0]H Y:RzkO9/IU&߁DF͝hr♱0TP襷ū)L2Dթ\SC w F5kJso(\a^tY\ūH{=cQi]M""3ȪgMy3 ~f[\Ɲʡqncf 37t7c:1\߁ņ3h@\ LqVwUj¹QE§xKI w6'-洧͚MvY+ K;{3uxKu6-Hh@0.6 @p+wE? o8% Gb8k3 h`QSd3|'b;Q VH!(*Y'Sډe2Y卵O裵=FމwEl3 d(E ETL5'*A.7n<j$ȤxiMُxA0G%،t`\p,uRo5څIW;{0HǗ9 :Uh*e:2 esG~rH.5}V} :'X5UY4y4{x%$zOsLrA0{ IQ< 4zBq &'e۫hJ!ΑU`jh@*`۵ΔbP9ݔ!k:1Ne`("][>{-Lgl?U$ 3FuO-LDRwuHS_eo4m QU+*"垛meH KŘWjur< ]n1p)q_+g'O T!֔ߌC3ܷv eFM >E L &/W'zX_=kACjCC開 3-z;Ek+B'e(ٶߍz6ҼS i!|8A$W&}gM#gL|S)\Vڴ=`D%Z5rEH[f]gIX[s6@&xi0%M,=h1Ri˗£ %†T&YL,M6psIh6pT;~?NJPDhΜ&w}-p4koZ2zH$ zy>hP06ubA"{P\RJ=ENO$W~~(@8iMNj ͣZ=ݪn.a ,,т7hW-g[9V` 8Z^tCɯ Y( =-zK7{Pis]䥺r`X\⯦)(vhp4 >ǎm .-dRfPJ߬"z&ǮDI4rp:9eCTBXIp[T'/|&[F@SckJUv AY+dm`=h ~vڑMki\꽴h!9>g*vE]6)Te%,+1_r:֗y?}|7yQ -g!EjE*aՀ}>d9õϙ#K6i-;C>w#YvN&ഀ $׹²p\OLyx-[:Tp\)eav(^1ЏĿzi#F~o㋁¿v3lL{,H?q.uC݇4TՈFEvα>IhOR[fJgחv8@z5q/XSkʌ,,VE%@5 \P Nt!ӱu/|sM*e懆淓_eޙ6J`=ٹ\s:;s($wf ϲD_[~DŽ BqOc[X|?)l]2OgJ^prvX 4)bH;c~i8h|յS̔B79PUEV+wZ%Wppo<ȧhǫ eoHh<3F]%eA3|kkC&J,uj7&S"FIϊHБRm%GioEɛJJwL_ {Ce@lv 3$ޛ*^זS-P(bV^*c'£CS>Y$[)N\˾FL~>GƀȊY!mrx OIc}Sr `YʯjgoBӁ=8P͟`Kb|NzKy.id=#2+uxGF@QjdG׌ !R t:Gr Mwا˩Rd@ />R>aWCQҦqT%䉉֗@`*XYw|bnIEFV舕E?_lE!iA8i69"hP38p ǻBue,0%\fp)3ޱ.*UT/_,e.q %Cd rQ#C(oAH}SKG%j9+̟cbl3l]@cLnk(ѯL"2i_GNZ~=^LVS P8YUv3 23LBY76LBV+?˲@$.$eJˑJmr`2OiBmBJ6%tۗnVQys:ɵEzlgo|P[;) 6DqPhmLRMNgw\i"Sk^asoh #MEv)vݹ ~r ̜My7C룙]_ RёAXK[?[I)qEk ھ-5'=CO H;TUJ-ĵc#31\8 ~H9䩭kA<8T+FX>Oh^`'x΄Q)ӊ=e9e947K+w\4*~4HXg5#zXqBɵ~;T4}/ӓLʝ! {h75j?lH?678e; oa*}^e|un!Ozi Nϗm;u^$&S†Ț wZOu5j=6֥dL=!tn=cHta','0+6J!DrȊ}SʨtCaLG/Q({l4DE iJ| !0I9A}"W&.Bί(GBURu-9ĕ'z$e&ꚍ@UWUvB;Y5F4Sm;wv֤N5*ux*6pbAlhdrsjRo:d́ut=ZsA7BFiӕ&bݻZV8R, x)qC{ˮH` 5Pi:$prp-;_+0oBS_dMi qrnwv4G[ |v@QYIP;jg:l+}4u{SiM0Ca2V|Zzi_˯_uqx'tgB;/&I̛fArRW ?Agk@a/ Ϣ %]9jߏufѴbv,P GpO ͎IX=_|[OgD5IR֓&yҏy4mSt48^K9"gIY**TKNP5k/M_nci>1d>v[nA.8e={}u:vjam32r+ݒyҏ%oixνѯ،H4ǖ$!øƞ?3ڃ=uEb/lt@D֯e`Amgc>$ެ'GXU O7:^^}o 2mx]!4z|R0n2h¶,vw*~Ơ._\<_|ΐ7 0H];*!?9WI=iŀQ}R8O&M^}}ɗzzЏ%6%܅ P9" )z'ݡ^[Gƻ!W{dD[uIKj|Qabg ԊK3s/}o"I.D}}kι9e dK2 n' [k(>1lq_Sh֏aW&vJV8b= kQ7X_<h`Pk+{C̺̎rqqEkpXԶ>OEJQGPzIk![}L2K?'&KquD,SmO크QnׯnB| /9}1c#wc  X>_BP8bCCrzpq肉sMnmkHNꪫA_VaACԶU~kWKA(HS! FpMeH5 @=9?dj-ľS;8X,2|OV'oat(""7_ 4#H"ce0iTՍ]zl;ބDR1mW'&Vͅ"9 ԫ>LLLfMXTiqUqՂA$|7=غFDVo"O o\m>e  [5_C6vYXu֋*!TVHi'RSJ2F;ߛ_(@f8 'I!mb *9m^Z =jԞ,47Zsf S\% ImfwaBu:`jCMC;徦/yгGUNǕ:pԉ:Tcqf8s -m˪V>r"?^١grL-p_O2z($۽YBa Hp_k=yM _T_`g4{"X!37n.ׅ\;J#^ 0C4^Pe/k7 Sr1p۹-m_0%qUSZf6v6xߵCr?9LZh4 "^Cm M3|Wigk 6&ڱڎ*ar7I?.z>WC)I-aG02nPCxDD1Kf$shgK(͸mھ"d|+fM25Ry9!9I.q5Y(f>]H[ywg5N@L l$ӭzWiPsAtUk1-pUٞȧǢ7. ?3G6O f)t6', 9)YyH+B> 'Ox3*1.j*fToQ JrUVFrNjgܾ5fS|"_!k9ſ08(Jk ,@$!U3S[5JíI,WilӉ71:Eh"aʋk{Ic{JxS xSy",{!tĹl' .3ɼb)7vz31Ǐ mZʞ0E(T.I\cﱂ06֑z9(F[Vv6ĆSyX^m8oha1L= Y?K3f4Eݡؖ ㅴ568\\[ >Sc+M7$T'2r0Sעvb|3BD``b|}z?b6Gh?nJ.J9f$ `%vkcUD7دZ?"6;%Ɣ a3~,J8e?8FYaTzq#1mgs D xTN>"@H(= E6=?ό.^1?ȭ^/^)4Bb '="pBR#z"ۢ/{A_!Cڋ72}X#$ADv|D|.erXwLb"6dQ+ΑBCd68>PY娛;{D4+ ԴZ c<8Zq;QIZ6Ivu^iߚ2( %4mB f/Qt+goC op 9/B$MG~2nd'NH74eNMZ(Cl:/+[Dnf1þXY.qnu;TF3΄̹Io.gT^R>,%FVyYȿ q&bu(ur,;6Gs,֙i$vk«_V$Rt8}2<鹽ӶuWO3~54}nW%vVOC 7 VĔ$؜o|9f3/@tc)ֺ3cLk?b A1o^fqp!zddfl;] GE̅ލ燘pn To|_RO!F:7GfZੜl9g&F]K..{m1N)N \i7=E~B 4_ٟYH̻V@4YAƻj%P+5R4n5 KI"d5ظ쓆-׽rq4R teլӍs+J,O!.jf_< F;\!r3p2 4J%k s|UtT->~S׋L~ {j:hW\+v>LT`uG2 y8her-NZ rkpĀJ8KiQJ_:df)VcLitڲL K:*8FIpwf я>5"'=G !N"e) !vl>jNֱΞ%0.ejIG1h5[K2Po!ϯF5hvh#~bܚ*7J"ȳrAJ7]I7O{M;ɯnέr<. ft[ɳn} fwF&m73a3 轍 )MM֌O;8lR+#SՙrM.idک-alhٗ6RHDM!ڊXegHoiqi7QV7y='͍@",,E荚6zD]NB*ԣ;C;/ y{֥1 #J?~Ԭ#UqeN :t|kH7ŐR:Vkt+j.%Fľx T*q;-!X\X#閃?1*cca; (:G%֗Uݟ߭oL[uWKyOߪR+OvZ^t\bPުto-[;GqJZv;]WB-+d$]숡Jv5)Ou;!cK(9dv)hoo$⶝<=0U_xm<&^gﻭ/2n?Z#xNMjM~]I*NMp;(:dªb2ˇΛSX@a,Ps"0|FH,4 PF!ϛ킅:3|"Gh@ "z#i܀`BLO4&.Czqۉ(a^A?e*y&c`c3Iћt *6WfnTYDct=Q6,o0TKie.ʝYlIն}X[#ᛩа/ձ3-.HJOi a{aE@r:)=+̶5zZ>V~J[CxT"G>~%HxSGLE29ͨցH+)S䅎uxil@h 3%^XGt]ΩL>:c iBf&e$7H%2u:rn ]ۋsDl8􇏑[o ̏tu b~ȻF'A9Ȏ|NV9d!Tjjc iXV#&f>bHJA[:J7)n/fI~$g6߹sW̑_9Jvn6/RUmNwul+5s枽|0z<dɉduQ#b؜J+v'Y"2V{ѧgA"N2 WM ],v0mzW?D`D"` Z*bsR'jE5nY_S2K~9uϷ4\ TMXݏ)2ST_8SF%6W]lhKA!İiS|ǩ;{,)^U5 ȏqO ajr-INWb<_&\to!m}&)u-i/Yy%ue*DU-\L4/_GQ Dw }v(y)wq8W~djkIGnnRd1Gpv'ϝ)y3VR0} d>GkT6\%HX2bakATLZ5]6%:86%TNmUL.=k:=Pv%Emƌ="ipJͺrYFJ[BzW4/.yFB3+ң 3Bl> Y}E农"8^ʕ"Mš\9,숍UO8_ze35{F4 ?c)oGAL, 1$dVuӔ CMj/g&ec/X)/+-UNz唰_Ôf>[>Ѻj,~˳;Yu9A8Zk;$m"%>3f tai7^檊Jp2c\ ñ$Mgp#3%"xsSF|6ʨ/y5Yw{j G6ofǸϺhDA^#$%g!QŊ_xXbtCfga ʪ}D _|,'x^,ȃ*@)5^DpawOZ :/W u#nv! rAHldnxl%a)O}c饦(NgSRª5/27Su*7/H5s!QXY-h`.TF.  51. ?jNldx~RC3!QޚPT3qLyKuM%ul4<ڎc2dI72OPWz9x;]<' ,XV "|,oDcCl.5k0M a%mD MOa/D!k:R-[;uNtFԗ"BX^mH0XGyc cT} L%S֑ VΝ+$wWh mcy7\ jN >^;%~=Be[io+>QDz/JBR!yQ;e WM7U|sd3c#y5L}+,;D!|ǒ0hz:9tFW, fe#aHJnjPTExkV){_%ЁLOqsiAe(O3f*3[DٳjP"4Uk<6l4M0_"莃 .'orA^͘Xah~ R~/Y~ 1@7"?]@G[X>JC{FGh+zf[?kx?qˉF%]8'JF{.z kb%4_5B<AK>}F;x8"x;yHi1?-31o( FZV't_{PE#6)嵷%rV4dAЋ(Sy X+I4Ӗg4VadC8<{s1Y6n];'VݾɓbxwoZl/¡}aixA"WΌqҴc1A #*9{ނ*7|qu?=ŶHQ&x7HɋY\*Nyтl-@Irx\y嘮F5ER;~Na~gW̴˺TdaeqR,qr!uz<J))>êWYN7F`yUcŌnph#fe^yXh#v'[@ -+kfSr7F,@(w9_p T}wqٵXL?y_]s<壵cª﫲=Ȝg\˅WW13c2A\@O?)rn 'AQ|C1:r²h[-^a|G5}k"\=?KQ"7>5jdx*0E'/ZōсR^:d#ݘH{Dױ0(fCȿխogEj5֛ǍQH`n Ūک}ON-H-"+.z%: Ms醴[oB(k~ "bgPH 2lrvW%$<-.30{咉roz̤wH5%JED?u >it X`JFS@_m6ߙȁ[v@嬽C2震vD81L߫=ʯ)dnl TxCгxYww7J&?H&<'k])=;5:U͚Ho=z!-{;BV$8$ăOWx„LJmᄒ3i.]Н04*vRc9̔K+",`ҊhWmAE'(>TM3Ѓ_Pkk7g@ .&6 $ZHݙDm&$$L%yWn>EhCxaLڴ8gxdD>È=Va:{ND$Y32q#FWD/v)5{9h̡Fg bU-C"'!aHt|yqt|sSLYe9H k |f3LĿx^Io(}$=#n9G#t/~h>QMV".ٹ&>,"\;GhS"@LJɼRNa ݱt=l&o!oCAK|.$)b?@R*2VLT}n)cDrmv y.9:$:J@?Lv b4.E9Rij'=bz ?jQ]m͓_Y{6F\pٝm{Բ]E=~Q =<+);ӛۓ6F;Km Ӻ>AL,H9Uq(Xӓb0L1cWƒ&ZF>C'M4& Zsti!Dk~,Qt0ZK<-Xq>=8k(ӀTd6,)Mv;k+;|o'?rP`XJeׯi @쐠vN'哋& ~Hѹ#Y9rvQOl 6̴"v!t"2$5JXO$dzxu1]^+ SQӠbP!\ߡ+^p/dNT8"h";|?LKᓣ q5FY)9 5x%7~ x[\ /54l[x :u&^+_s%N/&$lL$YZ[4i+wH ,[-GlHLg)8QK] jB:ŲCu>5goh0!gz$ͅA\.y!V6C}/J##{%P;&b>RǞi˩( <;XrZ[XS{WǴHBm`(n'@03AːZ  ,aφסV!6"DqӱW5xܨo3)Pi%!Ǝ.O_nEeV4z[G I"b-.r R W:ajFThzWZ. yc{2V?'o Vw74Yf`qzMӜQ~ }ș }( )˧%RgK66[{'9j8T&b(\Rx((Z3{"5ۍ>RS_/PcjBCQtq܏o||4KH qfކL6( Gr꣬ q㭝pRyNsAWD*թW zleک>E_u~AhJe/3vRA͜=Xm 93/?{݃uR.FjIsp["H;`sl=Y g:$rNpslo \.?Ӥv!,of1RB ysYg-ԅ^~cל,)SvhRh3| p$zo=T12ȳuFxKXމ2GDm:}Xg$.R*=WI^zB=S%S;@u DͿF|83ŠiD!&Wޡ[B`+f8}/b,:mƝj$KcS$V*.=mg&s P}jͅ_dVp"bt s4+*,5'Uuوݓfh=S*CSD\'z'H1^5KqrH̒'^H4O9]@MO? l7Pr~;䝼+T7M42?/_جG{?Ȱ<~ax($w^{5Q@ d .][VB09pq]|E.wS"e/ q3x޸Ѣɿ|xpGŞgߙܠ@[ZV$dkHBb|U>K}t)[l +c C?.l8YjHF&"9TG( o25>rրX۸υ}2"Cv7'"AO7//"*vl-';Rד{s*@*b[A> q'g-󋵃k9:VYz3u )n2sa?.xV QMpҼcK?ȁlݪv(@l|E/ +s$I`"jvg{*C@窿]ѡn`y m_dȱX'WxU;!! ̹A˫@]Xi &dLV (q#-~hzz?annWÇ;1iMguMoAVDN7+G|$:a9Сo An{gr eW@rvyD{\r\, o9[T+ ^@"_} 9&q)NHBE;!P %N1JۼΰNpYolTpgmG"dT:=Th/r߷e,/%)S0D_fpC.As.mKR[-KY}hXW y:3EYR4jP7,X!q!<=Ŀrݾ2K ZwIΚ-N!4z 4zN\-8$_MZIޅ~ɿУ ѳ=pp5VՋ(5}$}n ሻ}sR<W(\H\A=Tp߿\P߾/P8y ?F) :@ve>mSE$ lQM#F i Љǒ0wJ;kBI2Oekv i.8ˡد"h&-A4? g ,^3hܓ\^ o߳o]pOqE&|׮+9 5)⌅nr] 3>}Gt-B1 ^ G/>5a?_ڷbq=ը])U(z+s{oHބzȥbH\' s%d!?}K4$wwznMNz"*}~x ])fD2 E>nIso5ϭ#kd.9fGR.OQ" ֓d$!d?4 .e`MߧXɆ;g}13,)/đIʕ|h1N*)־%x'rW$tdš07IW ]TF n=,Ze2;Y 6b 76JTC4&.:]ף$#ULcjҘ@ڼD|,!4B~u{Bḫ^<HO!Z]ʤ*y!v]f+%޼b؉"I"5~w}@Q̺c/?Rֺbv酲˜ 3Tp!ji`sPk&isTlӺh;9%m ?!DWfiAߞFDIp ~dՖ6ypN:dimsr0Ck/SQW/~rO ¶4t.Օ[#`(|NZMī.|ڂN YT^)8=)l̛&)fW3vRdƸZ D#Z"홰H}frkp^MSs,kP؄?ts+, R_/ї8Ym~=JMDn AT> stream xڴeT\[5 ww)nݵ5{p A rowv?o0Kku>c*1H΅ 'bo fPTTbN 8 r(S5 Kg5W;Sp;],@/{Sr& ;g$IVv76A:+$Zڹv&@3/dJ@@7]NtQ{pez6޾@1?ze9[:8"`fiYeQPUc=;v..E^OD\ `a0TTw-}rwd?smmgnfvf;ong W4؄fr0@o巙_o{ki z;@'W?Y&.A?,.mgf Vo׿F)5]As?\66 @[〶6?Zil6t*YXؿ.@ؙۀId[c0n#ibmrvq?-%+'*Af0 ;{SK;s+'Dd+<Ӧ &hgN8&'Io `Lb7I0Iq1$  ` v"A`-X֢ ֢U 0fW]kA`> /5.`8?j>6$0 o G:@pufn@0? b@pVຬ\nG8<l_npKd,} VrGXu:t#L 41 7?,E-=r:,`?J8],@nlbn[i<zDDכ_Xii ~Gc;`zvvAz_0* ŝu:2yA{Ҏ3Z`Av*\F*4>o4Nbi9J eTFql(j 7xsWck¦%#&7f++*#o5#(E#L?1|بC|ӇYcWLhOJ3=!*m] %\ AH/s,=Mi^vjG)}ZT}nZxA1=;>_HHS.e+kƣ٭/&=w,KĂo^qb^ _Gpaֈ~,F.&)NG gJam!?.)Ry6;rf"RЎd2 .)aE6/ `a$t}v_ |#(a5Itbsz,w@A!Mҿqz C/Gc^L/pv`X5v]k~(bv|`IsM R3$O$= J<>C'L*Z1vú4t\Dfs8kAxYgƮ'5YA.HSQ->2F8^0&Wk8Q$.S:&{rԊvmӕ3E8pOaCIXa_G>ǰ1T>%"1š2и^X_^mRw5DzCAwZb2Hu|nB8us }J/1aDO,r gɔ}g 0%[*Qz87h͆>MVoFB뿮LZƠ:o$f5})00؃/CxyHf9stg}Zie ,nSJYAx27EIhR^w9&Q kK9Lb/Ow Vr(bNid$0JJ̗!!]2sѶsܻ=9L-x:x`i-e:V)NE՗4Q Tͼ`nT`+g64`rJ!5hW B۞X-yYv<&vAHH -@&o,"ŐŨ>=MuӷrD:`ɇ[]yWӵs+vbQ[ g?aL6Oذ&g62q jq{o硠n`@K=ԧE۟Xg//[gB#uމN!LZPv^G|‚SNPK):loéERR#d>6܏׈1C4UooF'!z C?7L)RYsar*y<%1 G" 细~}Yy?yU#p#p>Kzۯ]O1*OY6,]}J7j |U'&[Xƴt]u*!\[2.h KR!Ȩ\ej(=58.p`2´+0^:z4Q-E\>v<ԽuevIo==ŗR@ caO^ATA5u xݩ7+Eo4A+?b_Ht9[^)cJE{"a"Cݚ?&',egJr8}Q_߯lJ md 1n .X b)%1(R2g!9J+Ւ!f|mr!+w}6TO^ލ{I]ZlS{pb37ָ ˠPY%5TʣFOxgnD70ϝGGM=}Y+o'<<g;&$CjA|.?eAq` ?ѵűVe |xu^,6J0|"析؂\  yc5rq6Mӗ{'mLk4I?b, A }5q0D!y1o0z[d`7Rrt.mRhzN}8{#!粜r5AeIl0x֮Cb uӴ-6fPU]׷o$5&!L -ĻwoUHZTX1P| E{I(r,sJ:±{`+(!H%!&@Lw>|!1;L3ؿ0N-jNifGqSް:~Mk~MSoe[\E9CUv8H)ǘ V;U3y-N(dIKR c! )bb\Z( {tDÌLY ԣ#Th.Dq^|Ks8C@p'șq SvΦ+ߨA(Tq{';j]V:KˏHYrJ}j:.Zi=9e?-Pl'3NYty=5-DW.SֶYG~_> As!7£obĵ~a /]n/™J)&ʶ;Cw@M7vQ*tt,ş2ZA5)PFupd^i LսA__#2ż0pZ gMb*E?{͜fKz3<*`j&q7#FZ!%x~a Ap5턆U Z k<@~6(L>:ʱ3b3&K%j2cLvbw䷯3y  $ɯ&JL}+1dJF蜺ߎINM#5b-W=8+#ml~6}EA}W/ZlqQ:!}(v/efPi^;CZf &j-ia]TP3ͬ /U!)N?Xeڍ幸xIaLf@f m|o]捅7W@q8ק}^ÚJ~WX<Kɸ/. Z ~vG֟֌D(* i}F Qe-tV$M-u,ȇy>r.y}zN&qtZ~)$N0f6eiM$~iy.)`㻥R=j#?}cUa0 eq/;?rR>]Mɻn ĤY|Il7F5`N@08 o^u(C2t4E~]Kf{nyg%ph_ߧ9۔OR8ptYdh8):̇O|E 6~o~9)%C=\SFHt[>>j"ҏEU+i&UaԐE"ӷ-'(Jܟeq3ߌ #Q.,=Kg,PLoUȉLqDŊ쯛 yY|3ӴCrő.quu h{Ǩ4k۶aO4 Qj|Wm>}g(}Ty+Z5U\"6-2 xi:#%~TCNUVBEwDxJ\9Yk\ylx Wwy!3D;goF^);ʽ hCop)y:ݗ s],t>k9 So|>RCpΖibxMu^>BpA9 +^IFc^ ^߽֧tGw%/ۙEsbt5%Ӏ)U.ރG3 v)۫(qb!N.uz>77LxKyUx6r:?w}%8V;[:2m#3J'n&v uB톉u3T^T0;VmQ Aҟa焀 OL|G}eպ'o:gI+_cK5_vR3kv 4QҽN݃v@E\d>.N牾+}!4<[oj-RR{IcnjzL?wJT6ӗ*TИL}rqNeM6GWNjB?Ys%t`c*5L).cIu/jؼ{>n7xˉ|u4$>$|]睈YuFvf3-G*Ugz+x!GdtF'T,sB$QJ"VZcۀĤ7IN yd ٨)jXekm` $&7SB'ם @IC6z1(vi9en y*9CW &7F/a-aD~!39qU:hit n_sOovA`sf~w*"G2)#nX'q۝M Ӗyt!l~QrDu8A:)/=82~#!(ϟ_9VUU qQ..9\ksA9wjy3KeR8c^^!3XԿ[HaBҨy5N+}~]!er2'+yo& )mBRi7ʐ}d@7G(; g7:ԧFZ{wD!DaǶvZBi ;AЏMad =G&>`ei9yKlevׂ͜[f<.o;zt>79|Zxz>.KHo'Oyv!哩<5tz}TJ+&Ў5rW= net@= /bR06F/3-+3і? 5tA1O*pP6t߭Rhwz\\༗Ity#&K]B2Ja..O3#Y?Wՙ@>\}dM>HDutu 1a5`#"Ggci .ٟF ic KFgk,(Qgg0vN|^nm`s4#J@b1Jov/5.&m|aq@ǩz/fp;ƌ8DKñouLͪ@=k = cj ʾn*a<eNPSUy2Y5zDJK{ثo7KV{WSD6*U|^2Em UCG#􊸴_8>:.VK@>`g;+RPVF)Ϊ!8)TQܑƓz!V$E'[c>2Hk=@Do7(P|!*bY:D(&?rͪfB3XAK U"hu( !h~Å <jJ\y>.ر1 vnU2)4$O+| MAg tͳE#5q ]੝j  )=hR>jO "<Ruzn~W/MZKwh\du%EYH>,Һ?vr'zyr)Ճh&5,V4yؒv #ПA~^ȘMk*<{ ["2PJBiLxzC!u?+7޵ׂp8wU5 o "ǛjXK0a0]1Sÿ !2T]uy?73)RHPPDmIy;xku؟䅣8KJEf$#t ۟ E/?=enSu3[R}h81}8~/bkǀ6Ywz*Q,Ѭ5iLVRAgcg'x 6V7bOzbMHճW uH˪ɩflo68sд-?\EJ<>5GYb߫X @Ϧ\..P^Z:n)fp=6Kmq S q=`;[*>xd!7`7YuzOT5[bG%m}MK, QÅ>c7CzzP!yjEv4-f7[%o꺴2"xXk qiV ]ީT6nX{MDž,]LSžu]".; y%fgƟ֬G TW*WME&qYQV&FF|gG=euk:߅Ϩ`_%V4{AnOÜq$mЬr߇- ]{ EDDR~S3>rlvȬ|rki^H.bNLdU y7Ct\}>YԸvNog:>,;MB1Ԕ9N H5F#Jڛi ԩʧNڶƖ*)5 ;u ;Wv򆷧*h'Xz-Z\&+%ۄ0TԆakˑ>ƚkJUЦQBfU;Rzjt#RREmO*w5mY÷?']&(]/][;& e%n aO./ng17OA[Q<Ӌޣb }4@Z:7#qۆ` M%|q:^m}~i [̌,,6߰Dx>3ᅪ;[%9F4 K_eDzDz6JMBe4\ZcBc5sI~CCtLƑ5,Qi((Z8oG23,El?Y P"xBpaQ|Kࡰ p9JZ𷘿f T\:ug18]Dbźh ıy' yUZV&(>ӿzyߠI͙Ķec16j˚7`cͨbQ}\O+QPOC|~@H{$P˂b>bj!G;A=L7B(x0od㰲ep3aH%?c6!G6媘Oq7YlmjS2rF~%H/ #" +6#"- +465$ 8oX`<~&T$p_54GX&wD)lfBz^RRp b*ԢJF6V./`쥽ftsd[R:K~i,QwLؑjC/v_QP_S1?˴]WfP¨b8 {"j\ݗAV񿸬LQxåhgx`Zn9IٚP=lWgfs77$0[h1ػQO;M $R )1#s!tlOkgYE cбHz1I {"/DcaQ7g,-|ഛG;axkMwkPu.φ3Nq*_TS],q5"pܠc:ȄAr6tQ BX\Ľ,x3B 6}-61_ O*CfKYx#W{4Ң'ɜj?.`3}Q2#N=dbK.{ӄ֢eUļ|Xc/[yh)iF;uN2 3˸T3gw`ͳ|o͹ݰN} f"n$bTx@4c}ZbCG֖qzzJJ g؈8槔p``N~?Fy..2cw lϒ%ICeޔkVE  gR|ֶ]J0eÛپxᰉPqde"y!7^'ԤHYyy $o%{ڿT[бa%$>T KIn|q]58s2Uapaׯ`Ify<ܶMײ5vY&M%bi:Nk?WL9kW<~}.$cov9+)0&[schKEO6AEql*<=/ߣlWGo$[$(CEf!?.|ʸM1V&/s(ջzWe'Ý;ќuBᏘ\6IDk x`DwDQs/l?XZRR9B[.Gq0nrxRPxO $' >"Y6W:?N4n&^klDeD%G: өPWqK@zsy m>չ&5_`tN3RZEaF ώ@|3*^#(`[󗦝(%Tu<(;ku]sd g=|oݩ\Q ƚDO_ Pd_ @d:W0xp~\ u$v'p(rf#wp/JR=3m{-fapx$fN+I$]y^&(mY!ݦZo1uf QQ\[c J$vB+ Z.襵.tj| !}ka2}{`& Zm~:Վ ep/W¼?\^YtmYH˜96CubqMp@)Jj:t) =tu5$IޖY< a~Թe}Βʽ Z=MT5A*{ݼkn,Wt,5["I&|UWCth-g?eO |cEf'qT;ap)EbnHr^ɰ5,?,_l}S=G來p,CFICv^%iTҹe1rKKjb2,~5_q><2zlDY^1 3qICZqd%ߑ8>C?i\_JN|rߧgWQ;}iV)q.0_c|e.SCacؿriQS>ЎPqbjˡs2n:yZ)˝~ewG,UF @.*r5yfrcOk޻O0;+Ϳ*4򐯶 sv еlK5*X+QŮ~[kx4^骗Po0Ǖ!~Z9F rU` Q))7.Ub7|y,Vk[١p}oFCzN,3R V^xx@<:wlDxt~O54eÅJ$|9~eH\c+\mؔQs"8y:%?wMN l5ޫ 2N?sңBpAObwH JAlggLPް%*1N/fMXkV3è~KHzZ!|(Ã/CY<01Jc¨za5z\VΣY|#"N] x> mO4S+`M7K* H#>bZu<kNb޿" ;wTl*0`NoztX-(9nK}]}FDa{A jJ2` 윑aZ=΃㧬[e?r>3D5YW:7~cUbk1GN@TuhQ[#k EmH\WHا {/4aCBe{ ^/2Xf?_99Q7wfnTa8UC"՜g_zde%i+w5"6SDt09Cם%ͧD,m2qEawэTuM&o*mտ2/yGrfJq3MZX73X13cx ',=vڠIlOГT1BRz`8$M@l;_3W+V:؛[z%k.DUXh$o؇&:#D?֬h`3xlE>nFcIv"C }G8GX5_(]hom嚸AUѝazbmKJU\d`,ː\ɤtxov!4׍Ϥ'5f>c¼ʛqpY9oL~6S( Qz.2`8J/q.gvh-$b|o#mv'ۯn/>1'p&4 t_M_~$"XDvu (a}Ӣ&3wVXBwGksRՅ[}~zFO`-J\-L]싸iRSn@i]Н7?(ffO. 5pD~ qC ~˨V71{Bb1LDs4.Nc`GN}"" 4F n K⋓]73hqx-Y1rC0Jrh8 |(sX%#>9bj#MePj] Z[2x؛*?Je tۣpa"^R/P/(RaFevO_CU~g6{񍴓2yW>Ueo%z4>]GH5*Xgޝg_D )1j%=_=Q.{,P_1QYWޡ>> 9>Ce5 8mW/83] )3W*NІ%N25\}V8#ƃ|Ģ{F*!EoJMo^{_>umnWX8֎\U/KU4z*14krބc%ф]JNx:2Xʸr{"[OZXk#jy.IҚrSd[S[pN_} `<%&J=PKĆ/ҹʾI ݖj+_\&4{2'c=t\I, VgTE((F}RI7΀tfePJq`LfzȺ+熏V燚PhoVL%뵘Kվ0)SI=0'F+\(}衠R'c˻҇eK,|cS'$aʁ34r‰6'yU#m{lé87RRwVdlK<اNđ2 r;pkMpF&(%&ݶA3:ɡ֢9&:Ŕo]!7Wjd><”|ʏfyg<TLwY1_<׫?ԈGQ(Q!.aIia鸗o\%Ϝa+.B{u*4KWtux{g}-0Kq}7>x;'py 67 ޛҺ'luMN/\5 =CUۄ :<&GYjI( e&`B0DYBzsUMYqw̩9[7{)Nkׇo^rӆv4mӖ(m,۶m۶m۶m۶m۶]v_O$IzKWܚ{j~,٪~`S9ѸĂsk-h">S+i6"7ɞg4x?MM~hP3!hQ}7fNY^.  CqCH.6h87ZAG;wohnkpo X>\8 ?fLW"Tr(λ<ꮠH3s~b!@ G.hYqx|A$mPcG)ZѲh31Îni"Ŗ DKu 1OeF`n=ؼJTlOʨGff$`Xm!I@/ s0z6$uur$1"؃Gՠ%DO3?@|w{̰pS?Wj-U)5Gnl$#z؉Q21NP~ qbRCԅ Z ۃnQo#C3867P0}d&tW6B ]UK7rUHmGM6'yqC?\#_vzZ_?.m;3&6?oM;EU#VI*e3O p!]W{@_#N94ﯳ ^0U5ΕydZNZdst]6A9ͩxʆ~f~ESBY8e&G>y*> DןszUKxۢ_SO@C@4@l4cO2=x9юu:lإǩhT(ɿYyȫicf A\2j-^T< u}oׁ'm^v68'@l5+S||)s/DBuxj] aLOL#.ΉҜk/$HO~H&<:O.ɶsjy=>U"/6煋gA˖D[çBOqsHvn8x$ijBnYNݜIڥ1yvqe@,4dzy_$ctߴ Wx9'蓣>GU"/B,ca<@ďxHbm< *gB1pȧ$n6Sb#(. 0%8,f~/F<@臩+ yhJ/{JC?$ bik3@)%W uXNDH1Q(G˸H$( +uI3V5uqEVk@b}:zct㡀QALCYdzJԇ,/"V6ԠR؈;􎾭 'tYZ>2!YP,Nvȣ,qlȜK5_T=B>k=Gޣ}">2kh4 ֛^@:˩Ya==x-7qIu~DTNg"Iauql?1 X^Uu_W2O~c%ThQEi 6u^ͺ0Lb,HKq*a`գr%%'FN391z $&닸&]|!R=$A #lR=4V;ȡ>3RwF7A]o|{Qp}mY'uClr|EmId?G#'~0N2/ ڻQvc89ϵzh =T"tޕڪSӫYH{ZᏜ $!o[囬 7]wD7Zʕ!)6#qUJ3RuP(lh5OhoJ<'i>3.ےnE%%#ebzh[G^qwVZ4uv"g1N9=˸}oTAR>%/Aմ},C@}X(L,k-ݒ[OcJUqa}(t@Zkƫ>4ҷwdϿ )Y[riƆLZ ĿUgix(Iw@q$ dTHkkl L1%Ehg6Q ͓{==@ ܉`؞%9߿ݍHm4=?52m~fmo)jK5YE2n ZgfQV dpq{0j]d##& !}&z@ 5cq nU[&E y.>J#aS̟QJ:9˝&A/7o*ztC~eZ=7 )_}@0d2+PG)_f+罀`tL\\a8ZM՝MOTSH1[HY꫶/sVD̃SO1T2Q[V~!! %.eBFbRLF? w6҂J<櫵K=D .5Ջ(9U٬1^+䦧 ( |MБLf/臛PZ,rܦɸa9qD]ӈ"1̖\L%xۚ T0bSXNI )^T7zh$-{[Q h?=Cuċ >cHScoxfZ;kᎨ ǧ[2'!jZ+ĦBv'%d:փ&V}lW`כb~K ԸKˀ8C] XK"Dj1-Z|䊏8(?iW57m5Wn/m}-]xvEI/Q5P e: IX437cѝ8s~) 36'|T98xi٭_эEu_~<&"K"&r;s̽]EP"MynӇBw6iDt-ˎarbq4=JqFN"2 6;Og> x>8n#ؖ]5j8$2 q!ĒPUq1\RNV\8r#-(/[>ޔM/X`W ?)~ADG |yo~A E*s<0dlG]Pa'fNM'fP<(oGERC"bwM2RyҰq%rQcozfw't.yr\dZHm9Ĭ~N9O}M~[3a@b=2h5/}F 0sWj"H_ zoICX D c4k׉W~}$[Gf?NJȨ3ee9Cl`!arɗK @R{ZהɟT1HFqۣs|uZCn m2Jgںu/7W69WYAr"%fl"epu+κܬW U{P rJ 2@qOb}t(c 6+GXj1u;mVKɀR mkjttqA#ld;d=[NILj1P)@hDd9k(#!r'N6yHp^+8j/~RRXdK ?,jx#T?=#Ke. t aNx}d$JQiV3VEo+U@O,1uܖP',BMu )&jl=xSݣD4\f9gKbمyW$,xРǓ1%(r.n`S3jL7.P=:hصKuZf$CLΎ?6%6O {kp @ -A12<*`LLcn=ߞ+Qaeۣ{3-dY6 3a%,}.ÌU ףnP="^a=йV8̶LRr17%gZM]ШA7|x'H࿧eA .8BlOdo^&Se?P3ܶR mgL,iAHF;cUR*W0ɤ?yEDi\5_TK: Z%2^xm8*GBg"+Hx޳_}A1qh1äĬÄ)#!@(==a'\M@xcjЂ3O%?i>rykEq֬cѮ0;TSO3G\ {SS2>RǨr| Y)7,LnS~+o43? + ˉ |2w{qzgE\4ĦsZЅ2|_`rID#E3Ĺm%6G%JBzV1IRu.lDGtJ)wK|&э2>CbC.MC 88^ʴe_ӥVUnJ1RK%b3WfcF0Y?>As@JwXƠ{/:Ic00>ёZpztnxny9H/wGjeֲX Ntl^3Uer$.6JG-Y|EE05i' Ss `;t߁(l+7WnV&zӔ3f7rfIUӱCEKG?+ l\P=?Ns㱣i*nN BG^V VY$JT`6vE!8옃׮<}͖a'r̲Pmb*lȳ@޽߯ڍ{e2>a9ki0pn$^`L`ء kT Y0KUY:%_EUiF&,¦cq488?L( 77Eyp8 Q~<֍ܘצN[O S0(Y$>/D,(FE#xELg;OI e$xfHDCo٥D(hf1MʤG6).*1k*IpE2[_kg[Oo赐13޼ ¶9sy8n ,l#r(|r[$f`S>C>fU[a3xXJAdM~?3 |bJ6* WG4Ryb1T!cMmZ6TEi,[A"0cLO@EAw.#İIº *Ti/+I8b!`;G-wrfOH]7*]Sr,?jt x{ҹRwL`IR th@) ~1KIJZaKMM Ե̡g4u NIog#r(p?0Y^ 0?_-M]ypmF€cM7G8#Ŝsvg3V0!g'jEGhn΅U0ͧ9Acz& [ɩ u3?g # }KI;K O%P `d(-?k* kroy`5%r; jD'd9h|CQNVǃwlx 7vC}'M/>rlv6B&0ЉԦ_6=C?'\0o: +ȆwX+laG+[NoUtM0UIN5^N~=(? !p@7A5H5Ҝa?GcۣἼ|)~~xNjf]K.|gKx2lsx/nnkVeN %^PCV|+3{>0 ZB D7a~O`D.q}jƏBqt䰕w8(5Y]p;yoG?mU*61;OA]"iG-oɃ>{rh0$6[|b]nST*!="@啶(8;Y Bu)Ky. /׏t'V3,$kW, swy#+/6.4ISP8-F."p{,s/ mtho1;w)taR 84d~Lް{-1.A0)b]ZF]`쐟oi&%/Z ]6[.^%k{.r&%r~>TJD4|a[֮7-Pu֎h­N$2_ H>KTT @C{)1P }ew DJs03s&w/uy3>o{n0x?/Cb)`*@)?Fh(dy%?GW( ! wT h47B Fp,5N8bi t;'@(37\Ow#˪me)>l`gn.).?Yp}XsE|_aᘗnqVoǀB)&pW^¿jf,@M d_&9jl ([ti@Ew"4@WeV eaزII{!ˬ n]Ex@zz9_GK?cq{T#D>5<s׵M̷F!$C}&UFdW'~ZOp /\d2x 7qTUֶ+f_Rs P/vHMqi%&,r¥ zȋd-A27U*1{l!5 5샳uQ7 hWi ;f z@U܆W qcphn9+|>XP;Wu5j[>"cQm?؁hOiH; y9b7i)0um}d6"9&2= zOQ_hVֹjrp?aF\aj0X‰[ld֬\b8CjBjftUSg/E>f3FwΦ.kF.=OK:*VW~§*lȾ匴"o`m.;ry]:v58B@2@WױO*2tgagkbRla(5eoyuwEjQž{J6B,1X+6ߓt)3SZrk*х^Y4BWϺGh=/bb=[ϛc@;7>ԌmZKN"BPK~v /)99  \a GD@4t_XK} ; _%EfM$UgW&]mȁŶUY)`^N$ns@p~HbqT'UqEӈ\#_P^\;mZ1 :üan#w1nY"# 6wmf Zobz Џ#]JH^J,k`d_⦘J?j_(fZݘ_O Pы},)B [?e(8s2 HP !5כl_BO) _gocU%6ڼmE-nk~=Ceߧ`ee8x#GaVgYc|2*LjB޸AKJ Nw{JftﷄyYF.pN+[8\8wwepNJlv̞>ط}[z(=PJՔ8hR\.ځ6 Oη-ڢɐn +[hy؆4r6m?j*!y&ٌٗ;հ?bsնp]>'"~0HI>80r--cá5RlafqfAiq Tb=@_!_W qTͦ%؉IG33pz!zǺ$K4|>?rKE>Y:cD~(ѐHQiiaEn(3D`NaHvяȘy~ $m,Wťm%>;Nr89`;eL2 9& ԩeKS0~y`)'7*u]{Z,;#w}ϛKoNp /qiUorbqRb=^+H5h段g{Lf}ygo: #fQy1y6}j~ =  GY"o9𗶫)agiqYy]f;|1Ƌ8v\$@$oopG|fl[M;KX7ڣIZ^.::[RwVAq u<栳+kbp3vᷫF(m~EQ.71h-$et'Gm :($ϭ|KgTx:${Z],fA6n?0$lz͇,,O:o}nbxi(H]㛮uݢ#< " kYlrT~SxmzVi*og_A7]9p )~n&NA7[.e":M/a6zD~#%鋻m`6 %^8|CX.=Ⓗ9Ν_&< ŕ6xDޓv)9Tu^|6uH4 k iqT(ɩkhUg4-gPtqKְ=m%='yx0LfRX7<#aBRzoQS2 1{qpoZ N$ҟ6`YJ7-  /3^~[ϣ=uHF_Ea@kZU@TݦpEmuE*=Z3 8rޒUy%Ol|0j.U$F2%P#?#4@"8̝X|>+⌽"S0˳[z )ٽ}ٜgiΊ|y%AR3!L`5.aRcfF /K03'3/L5^bV Ƭem~gR*yԝ$5RU|)] &5T3ܙտbmw~u=ч4nW'VB.Qw|**)2roy(Qd LA.gB -:`e-)PN<|QVm$z S^{Gcn7[=2L.ͭxl>˺=NVsԏLI/]|;g@b\AkgLo4ޢK|ާUx2@Eb /KkPr{m;tf?ѝIJU] ;3d@RF[;wƟAكw-wgJ|3S>Xm'X 5zûRgSFPH x'Vߒm{ ch.dW _Dzcm}W:iqPFC4Iܠ=# P:}?"OopJX#&+J()N0`nY1sE endstream endobj 149 0 obj << /Length1 2146 /Length2 24444 /Length3 0 /Length 25781 /Filter /FlateDecode >> stream xڴeT\[5 www 5[pנ $OUҹ^{s(IELR FV&> + 9Rhv0 +‹@ ߕSOddИ\@&.j=E ';#HŘr&f6.6{s@]h qLl-u6@CMRU FXkH3$D%@M_u;KOw? :ʒ`]nTS{wpv+ rcfvwwgtu198[29Olx:m +I_JR;A!^П2/_yeey=hobon2":;ɡom}MwL]]Q^ _ k[./:{3*8WǞ O ޤvv]ON gOnj{w{ZXۛ[#+PVLE, zY1IW`ab_]L܀+Fsk3{[8x%~gom>_G|;ź̊VO.)W[[E; Lm=,ZHY{͕AfV _"?gYy`d{]\<eC,)#A߽򗍤% `llo.6z!f&{л  ppF\\f?!n7 Yo`eF<f w?ѻ߈oo `6beyj `ZXsns1wpuGwwVfwLߙ:r:9;ǿtvRY߹);w {Orcl@px?ZQnE?woߍ/rvjYߔa`rcyϿWʿ?<9XlΘ|uk2?z~:Jk-,e:ҖKZʜn'ē& }n Ȣ*r3Kl_Mm-z\EdOERt&F`b@E'ܗR٬ ߉c]O1lѯS+Cϳ`9bx,t.Nw~?aE.8taG ?S6n;6^̋v]€#SeKKuŸx݇ao &Lrgڒ~@ZgH3[YT+}͒¨o8UdFUP""O6$cclGج+кыH;>xs:@s *rT>psNaOnl vNu%C( 9:$$6^?VߌVg_t:e^ұWrzC{ayMiKdmkxIVs@P4hhZD{9 ]K( )'g4%F+N|Ug/KSα#VrO$`J1?SEBx` haᚺFaGz%BqAE,r?$``[4ц/<e|դG 2Swqp>:S`,ZtC4^ON$oq??YaG~lӞ?*oDj Z.7uGy899/ rp0U佡֒֟DlLp-*xO`ʃ.Z,_R1>/*\/x[˷(e67{uO? Q|&lbݱ0g}˖0 ݧVM*E~K ͓'XRf X|K٬IYğXs_+ŻyX# T4q=j\6҃t$knYh}x7)gnԳ%1U9S25 MݻdN-^s1xə:)ud\acd[g0l T[Vu~w5&5^Cug9Oˏy#7=ޖpG=~ SI nK+,lJ;$cbTBzP11NWhk} i^QigŋYaߺݥ9ˀH'aRc\4ZQ (*֕6VI"Kt7>X=T69{!N=|JBU9}?4E8eYKydpIV3¤z=k'k݇ςX_ya>rH^.W$dsH f&/*ʩK"<A"R ލA }b}/¬W{3(Jƃo͝cxFQ*7ir%>ɻ)~ls :U55$K'{%Ⱦe~@&7>8%&>u&F(?x%TL(P(D] i&fm%yNU#AUf~UR* 7"_^Cm|9(TD[B8U"ҍ{PԷ OTOL{MήQ}}ˣ!2Vyy޹]8$@n"H'Qo q10It3~+c fÞC`'^k_\9yٺ1trhRgp'^ GDZGc!Ai5,oy9v%^ka~F}%r\  ÓDU~U_\jUa0Ɲ̹J]pMֶyrݜtp8Ʃ^#'4EU26NSJu4DYߦh¿N:Sx 3'=f!]e_•v}(9^w a39-k[eD3׿b80=ckB,~wL.͓/icOXY޷qoj}5_t#`!@0H'Fm$ZL1Ok+ޅu׬Wކ!XHbC, ̵<`7sMkvUf=ثPFW&bL}/. G r&:rEuc.Lǟ BBLhJxŔZwry^wuWnt ~)RRKfeSlpX80w"Ս TpLKx8D |g~ 2ib]TX QձpVv]9'=NmPfҵÍ9;Jܾb욻2&^F548@0<)؞QM6•9oWCkVMZH/пY:V0JʕFzӻsƤTȚ76ԆNͫ4>+U~ Yj#A!໭ߧ k*! zY58хrdmA+V?X3e?{@eOdNS%~s}/Cb0ì4$hd.)yw$n!SXuX6  x;} +,jj!x] #?\` V[: 3Yr,;b"lEaf/H$f@cN»tj3z.G'c>d< "AEJ muSSԻ ASʁˋfzIU@?Xiu2Jvn>RމB8sV}4mu(ɚzjKOuTS{l-ٗn&k䴳Oqb6>C%?aؼWdCI0Ş3%Oϲ`TJK&Ƙ%-Bz.%, V ]/H\LJ -g'O@~h%=7OI"Br7P*gVO]/=[s]S 3uSU `Ką7C, ̮ qc 0@L_"3E띥]<5~؄4ԻY!c!X~BxpB$3=al\h(3Ng6R~l1>9dt AqPf"Я ¥N$5Q. -S)+߸Ӭ)\Frw`Wiw Oo?W~vv}ؑ P<MZF)s9C>z|rwB54~ۚh=i$ J-;?0r } Tv y{Ud'fU慕 Xϐ܌WvsArk"b _rg(3^C9KT~eO%) 5\uLA(YD\/aE?S٣{*vMjt:xhxw7 ?c uV ;9E)qJ=9{Ÿ+>O>vy&gjS}"mǶ=K?mXXļ-}sAw,b?D8ʠqW㒮LxdxʭaYPa8`f: ި9XVs5m߾'[:|v&]b<;"S[fPSsQ &R ~?v5X]Phv9&ES 2D3\JA9'4`p.dg+M xIcKbLs~ClQ.}#LM/yhgy91xeRg 7z~ {}*y2H>{o#s}I|{ԓ^gWl$kmg ,9h0tRD96YRb,6' N[rNO"b4>K_urk3 PF7FdfK 1r3&·EԳEj&4%։דF>4w-v74b`͆G v$ub<#m&5O,j?D0$L"JҐɼG@Lh(M6X;L5|c Ζ 2|NC>o-Fp蝮d$h`ui/@00N[M:t*3:R_h^b3KG 2o ȇt(~pVV |8IZYLF]6bW[oN2blM>w$f}.|k#M2tqCtw $ybxPQx;h*$;Ż%qa?7o[?SW}U(zBS:xo]фʼnz&AsuRVAR]{0}˽ίI?{Y?kTuq6%Pl{ Dp 8p>EfFVi.KuD<b'S!J0?}3?eqϵD:V>4?*B-"R)+T5*F#91g+;t[+P #uYL˛w%,y?A sqh8M 9j3?|`Q5MqTOvS4%(_"z|?I~ҵ`yI1NAFodmJnfI|Ji;qW;:[smɨ}n",3j!VWm6*~`uvMA_?e:P\QaD}DŽgY |65)˖ǏٞRV0xz$M%"z2qE^! 98gƄ }nQ#`f9Q!X mټ.F`V`>/]A@siڅugMWl$6l 6Su@">j܆ bsFf eWڶa6Ct4)u;t8=${;~:= z\E`>ϧ.>qE'p \dnU"foxW7uU7䳈Эk=9syss.ayn\m)WKIR!yZKGd8FwT)@Hu;m4Z~kV I*p>حzJa#7'GfmА|`hף(:$#sɭ N '(辟'b@p?GctNs7侤%<6gh@ ?3SW a}L5E =1,4co$S& vy)Ӗ0Q>>t+'A'yYFV.2+0OÝ[e#ǝZ,c ;fyzkqn?GloCJjAnqQ6Tȓ ɣk"Ch-3_wS}ڎGjദ3T;U@ ]ǗydO]{8j13@vʐ@$r{fLttI9p+, |Gز6[e=`%V#WvGDDeH-uv!`LO:TX`߈xQ y;{ *%JRzj~$2"Vl SNK0lJ0MP.lޱ}_,,Pg|(dB(ѥ{R_Vq9f%R~i/GET>YڱeuE|vY( js''}0Ib(2R{yAuT^6pAnEq=\~$Шq^&1yMCcNDRSUnb˰41DY*Wa25]2󤢊e9q#[hCQp8XA0[fV/< #P ZRډ:Cѷ{QM&@^<u8 A ZXF[n : U%ɨ3\.O,7 w#srp*GFc$t׭*w'"*>s>X\&܍';jE]e!MliJ3 5FޘEok3XaGq(d9:Qz3r]jɓ$:C]f/>>XB4>bjoOQe[~p&~ =|#&Bg+7;ߪܗDq)-w=wB0GiUuO)M$fw>oQ Vt5Xv3=ׄݕy4kwRk#lARl:B=E^.oAYaLgaO!bWv}Rq4}a琮{djV2sn!{WԪ0kЬR9$Xɟ3ge>٠j4<乯lYo3Ә⚫/Kŷ!|C'jl.3'\}Uā. )U5|U)[=7wioOb`KZ #Bf+8Jx>* vƔE`zLOz+H`m>=6rҏb]E̿.>cGJwD9O2".L5bY!;[{aBKZ}cyD (O-bs;)U*&AX[lwU@`5UMac݋rr r ~%We3;d}eFZ\u2u3n{&ђb,'bzDܞ} HӑհDPJ&R1|eȬyX~ׯ#),L/+DiT%JM̖Oq?䂓ۏjH4:~}S=w0_x"--Y! plѫ'=ЫL/(F<"Uiw wg3&- ,3ـO %xȡÌ/OLxONtcI :1TS . QΞO3) d3s tϑ1%{5RF+3ZŢTĞPؑ0m$AOs2i$U*yNcxB L9 o7#:T, Z|ih.)VMaG;~( dvO݋kQt.qb+Cl;?6nչ(N%І-Wx2zm̃˼Ǽ>Shz''Y`K@E!6,99S,h0moxNyJe`aL'tAV+ZXYlc0l츏יmI$0F3k/NZ̔OѿjK}i@ ձBPaWxh@zGaӷ"C<ֺ&6.B#<3ǘ3T*1o4fs3i2y_F rNsST]ً4*qݐxn+bdKP'XG E|_1g끔@lV,x^2Ce[3d{Q_)ػna+fף@SPX`N9{aO&T)bJSLz#sjN*UZ|NwqLYّ(O`f$˳ߢ b>f)P7^^ (baչ1ˏ@؛Q?p. }\'* 4Ɔwkp~jDYQGIAX)ޗg6Xb&+SB0"g!ΗnvĬ$|,sWϞ87ܸM+Ý\|xu6@΅U(m7oHIv6CG0Į1o{Iu嚚v1;!Oy1c8sKu 2rS}YWcz(LgaڎB@:E.M"h5ȫJp|~O3@ϓ %>ݠx~\ y 6Wu -=' qvT3frBVQzhdQvr(!:c!kr?Sd{&<K)Nۼnd@_uXaSL;te^XYћo}8&)5ne2Va5gBQ< *+[L*s:g823*1Ƚ)Xqe[jkTw!ң?i/j5Z[v~ԪXfbP&L]םԱ@ݩ_1{J3yEܶQB *ёq\txVEujüA]_`mڿ򈁶FUEIkeBB"|H3x|rPhƟӓhrQK$EgL5/A4v;GƬ[A qз=jsR]F)~KrZNN.98K2 }4Q qa5A-V4zqFhC<k(st&5D\5 ̓#vll击-o%*L~gŜ,rL&e`< 5#Ո-. S6dO$W1=JCAlb2W;VeW}ĦZQbÒ{^Z1Ȯ",ȓ?nB>{rwV# ndV:T|LeV5\.p0ۥ,s5i*3%R1"b[tߑQ0y'RJgKz)UW]+3>.]:IB-G\^6:RK2.6V>G&ʥ+\u3Q`0* vi0(hfV"?F~iVUTY9]oNLe=m;f; V_\Al{Mj^\E:AP+&w,KFÐC>POPf<7.X8HIhs L# RJ'\"jEϝ҆NC\PI(k+'U rw54 AC?Ȣ1{1PMށx>N]D򶌖Zs b9H}jVSDJ J(z#eLǨ.'CI?b4JVDSCX&YcȕUƐ#cxM0ag e}K]faq]qiЩnIVl(8pӏpIqa/ԡ*iU\* c|8˔ |.f Ht!%c5^a!BKeIw=\yNGxIk*+zYVhj3qd 7%\->X~orRq0ghz &_'9c2=9ojWPغC)7h·׷׎!\%gt+b1Hw"rgV}% #}YGT̬ J,.'BE.M &n x0rݵ0 iڧ̞ȝz_' (!HeLA\ہP6bAk{P4C/ywySfzG&o=5p6{ZgȁHx)W). &NpDvu碷-p?P*Rp%?tQ8 $k{Zj%?Ej#d2 $ y.j%h7V:W"Q\%qVQ7(ꅕ==*C+tÛ9~=\lBLV!T!,QXH6@\ 7D;ܯ1m v g: % 3XR-T_32f#o㺅jdus 6٧鍔u\?vR&˻cg *gYt*l~^.:0ܥYRc[ƫMmS>`"qOt LO9saÓa1P[}ƺBr/VKgfNC߀+9#2N_zתT֥" \8%qܣjӐP>[DUE-a(Ew ~Aĩ{xчW<U,20"4<^:UrRZ\@Aj?վ-?E0>,y}x~D[*/= z.bD&NFh^B#n=`c3j 2tNTKr&Sq@Ӵv!\ iKUw0J̉&uArW:QS{QQ`"Ca.c1f'P bWLWeJf|u z56KaVtsy,+?˘q^ݛxo/nMG ^rn 0qyvj3֪0nknufѓ6EhuWYK<^e)b> t|%*K9l8&D|$ ^vo툿ɫBђ%%D7SNU}hr $ 9+wU"I"淛C6D׵:LJѹUVmP8i9ƕDL+~|V>,n:$<%V쎭*o7yiKEK',h$O_G WDyZ9#FHWo` =,at/.N:-Jk8Ϊq~k$|e+ؐuLㇻ,RG OB.p5ԕe216yTN0*jXRB= ~kok%90A20ˆG"vp0ye Hܒ8Xd/џN9=ۅ}QnE4sL$@}i '!B͗H=M8ʷ s~[຋o[Py1lmx쿳9~pNNPn%3_-VT+oAQYnmh X%[_X,PfKVx IѶM0-,C͉8F=}o5:=I{k1ɠL`ⲅLĐR(Ǥ"^3b3UY⟡DAS(:Gv"1s*39=,Ioy弲4+d/Rӻytt0K`;u%b]S8k P\RQNͩteB{ O:cdҵQFqo4om?>̘nOSQPzcJN|VTw 5I:O"Osri>Xj@#fmSTNnf)ڲSv覒^ltg8\aWܸ<2FyiF mFt!B5O!f}U@PE MVi6]N꼺<Ila>xNh]Nt%*2WF@~8 -I3\ NP..DsFp-}x,P$uP9*`VNg*OX 9֡0gKf A/{ ]0HcThLfNaNx6 7zv@}3V %IVZnR{l..YƠBCLl8uɹ.2ݰ0=yEqBDRԑLQw'4b:VRG,qINmB.z粓Sl("5cUw󕯐P3"*kU.Q #A ll| %%XBk=qKI0lޔ[Zgi.cj?<%[P7)]?emUU 5\un\_`$mGqNp!72+CˁQz7/}Nch* 7p֡8셛F\?&k5of#}#rg|`~:? tmRzve98k Pu۳dJ7bskȤq@mOnYH 3ӨzX m=bo `=j {VP4gݺOehB^1)y@EO19nf|^'@#wuzp)P%؆NP^E Xrq}!kt4>M/h\UA*٪LӴV-t5eDl-##x \ YzihbM0d]p,"e59>$qبZ./Dj.sO%55BF;./Mqi`Tgk JQ\35ӧBpp>s4*t|EdTlqUL r' RX}\g ڕy)U2YUj鞊IXPБxY] 9GO'kCހ6<\1&N"co9\4mq*Ag?D.}A\ p`6W 9dtheEےbX[1Z9(܇-ה{v#]D4ܻTG3 ixffڦJ]8@Ǧg5 ce{u3B v2njB~] Z@>b'Txn9Zu:q&ZK{[FlhTFe4A֩Ԑ>Cg o.#ҵ[) Wy̴GߦI8ƇMl)Z}Zup鴏c՘]EvR/FX^^΂)GA~?Ȃ'Kq@ԖY aùHCf`13p6vQU!J%ghFUz+̇ jg&xꪌ]#@hCz}* 7% IEtEaIټX<w*L;ĸ hxݿuV,.E 'F))`,bL1%?= ϟ& "[jM=SB֝Jg%pISLv{眐!|pI֤] ݽ(oʭZWM\S%14N~z5R6eh6 w n{FtUZ=4;?77 3W/Ӽ')6)cpzkьFߡ &( ,cY4ȒGZ-#7:[\~s-wfi -"ğ+HYpxm!otVU#8zINmY^5Ԝ7RWa_tN/5aHu7?7fYVEݎ}%зX KvI~S*mu HZ߹n?=: ȕŧRxeмfۂX:l\Qk 2 uWmO%F;O?:VߢO_(R;?X(ywLbIQ:魱kkp=Ķ?WO*GiTBcki`Ә.NY86a_a[Oc'G˹p=*ȱ?! .^r,a|_) :|eAe\ƭ\w>Y:?PA|76NCӪmpe l1iPb|TdHO3xi-[Q߫V&:I_ G0+/054E)oRp4{&/ɏ >y"z(ωxtOXrDA/x8.2ЊGDSPz ,0iI`!PW&C8'>Y`c"P&~6 Na!BT7O"P/ ibh ιdEarGy\9~Ǖk|=\<{ZA"e2κm{5RgNr;0b@j>B];!1"DeVi-;t?x%t_ݗ£`AeIk|#I?<2,]iwwDJG GgciGBӛTxWZȸ4m1.U컷E}y#+CQ*Z`KjC&{WO`ZTWMA [mlӾkUlᄵvM $G:Q]nZc d[Z[PF* m #0)ⵇ=F9C"4@H,?Y@;4M_trBܜB=rC #6ko޿5W/'t8u֗Z7.0Agpu;Oςf$ω*lEԴlc&.d@1 uҗ]]^|L< a0 ȗrmFbP bL=_k9+lHn9XR91Oy=^Xyz{ AH`-dmyi0].4aI0UzwOPGYta>#$|agwC `3t9tBHolG`L@p[>#b+ytlDR҇k3tfؓeA0\c~Qzm/zg!|UOCGOeq\qI@Na`f%X}/8# Q3~gPڊ$${q/Vڌl据)]f;WTˇ/A*s]al;TYC8Lfaz˪f蒲:.&x,Ϭ?yL,dj_:H>X2AG2qu}E@k0A*bum) SH)V7g؈WqJ8=6I4F+Q#sWpO9Ҏ%[T!\^-tR)".s2hD;!5*#Yޥ'i͓qtC|9>.iWtEֻ~gڌn1wbPG|FDKa]ge"nTa6o/:[kD?Ԛ(UBXƪց؇#{5a)7Z"0Zz2 $(! CY\!RR ;Y}J K2[O06yE RD㲂)*8I~yONKg,>j&IbUFhxT}8ڽʅO QPy$6ך^cͦv8D?@&#TjDg\oqs}Y&Z5?Ķ  }܆jhMb@6`̻7/ ^6q4& 2dSƪsS0CuC'|e(?GX x_:Q h{~Ķ;.߆z".BG]OXa>dU~_zΠizAB:_ns ~F93eL+ )K;~6cn-g:pWg6l 7/85{{M$k0a'P45u\r>w_gOXt?!L x%%`h+#Vhi] ɦᬅ`_tF`諓`b~s@YIFGbC匳rW6V={U/?sLo `hwZ?ogxɰg.Q' gKhr@NNlm\ V젋D$H;}{; :OzrhqUCd( D[ @@ Dͮew$* yb7zhEb*kW^үN.V>$^m^Tld Uc ׃oBx[3n !=l#xK|$Uo供SdK2mUb G fY{?"?)to(T+B߶rI`ʿIPĀ~,HLӝsxs8[4vrEM*]JYŘ-kU|VES"}G$6D>?N΁M픳`}CSf4nF=HI ESFW'MCSK$z 1qG%*UD8Ud숡|dJbPMu7ЇwR]պb=D'\FG6a5 zU&II g5u4[ $wс F(3272V|lEv/'isJ#M Ԅf%Թ|;'_ XKg$KN_*W93k垸5fɹ8ZS48xv$Vaz_xh8 >R8vn{oEԂps@&STWE fAPl Q4h/XtGW^0avM]i'U96Gm ]觙{ 0':>b-S.GgjlO&;LdZȝ)D6dpm 0fbP6%4{1A`K!%dHjxYZYC|HT w! #]!̠6\~ie;8;®B;j;'Ym{#,bk>}B\tB95P 7m_l fWOs蔱̰!*~NomBmKri%#m4؍fA߬"G H+I* G.@Z"] -{GlhJ xQKxBa6;="g dt?o}ZSLD$huuuJ2lXnw߽ Mߨ΋-xKZYpv)n]JUH[s9{(&P6O9ݰw,yzS"^}۱*47m|H۰EPhz:?x7Ø#ySuc"(T*򻴜da>RtbA"abZ1Hɖ jPlMam!jbӇhvjƽ.lA"OfukH _%]X(>PSfqKQqOa\ij^38)@E4mE6$j!O2ȣ2Y֐ \qqZ.OwG 74sIyz*2KpZ`$7$9x0&5n̹d7pN{pa#YOᙇA&{Rmf`/qbTSV(x,(SitNRL5ڃV/׎t_yőVaX ~*[hb܏gTCheS!(PrR&]w#\LGEzNP>>1k5$rޮ¯w]*:6lƱl2$. > 赏i@qQjXheYˎPöoܸr~>]#j~- (S{+ءNIA+K%]eE~Flt\&n^I>,E>3 ͏h~- e;^ޞHh-Q p ^YLz.6PB~l}[}#>]z,|&#U_˅kU)O 6 [·3N hP7hdB˂PtPG2G=lܜŋ9N\A9/\AWZDQ C)P+N,dcJ6k4NRER#v\yv+k+=W Xew6UħI@>Np1,?Tg5|@LbaEgsəv->*Z6ɶΝ,4m;Ot8U' P|*J;Szkgj8YzI^^B endstream endobj 151 0 obj << /Length1 1684 /Length2 1579 /Length3 0 /Length 2629 /Filter /FlateDecode >> stream xڵT{\LvI1QYR6SS*SHjJhN3gf9g9S. B7eV&hlEmZTr۵L,9|_l՝^S4;bAcBj ,TJ 9(ffr pНp2r@0(fFa9p`8U`:4 6ᐂpèAaK"P5T|!R|Kc@E` A 3W940G)aX<8 oe8xq?F B%d"Lg1l&ݖHX@ȶ_`3'OЈTj \lmhBar!M&b@D.@Gx0$/l)%$;0) F)4l?B(@• ̟? J#ePILAR3nFn D++@H`<3X>^LOh0Gh pttt!uDTJVPH<'lCbBc+@P<Rf"JCa| a8<-ZL'%q12LD!xQbP$ p1rE;> CTA` $]`aO#ɒZ>JT (N3s_RJ$wbD/_ĭI\ I! /$'&yCLB 4;'aO9mBՄ'#B4.` q؁-qsCL`&*b!RQ;::!|>NLN!l1Z2S>!pi\U? !ʑvf脝}Z7'lCuT :}#pvfč $~\c `8Qn\6:Rj޹gP?/_캐qPf§)~UG5<<ҧ> stream xڴsx>mm۶Lliض۶mq;/~g3,Zny%c[C -='@ZFƖFhle`g!!r889lNf9#zza4dNv@_Aщ 15R|ڹ;9DC'ӟhAZ9 I+C uPmm@3+ @PQQT)ʩ+Q~$Vru,BJ*baYeP Whߔ aSOݟ3.@G?e 2}8Z- 7sr㤣suu5uvtu0Oj` x:lcN'3 @h$j/G+?>NNrZG3ǿks'ч#@ 4&@ @O 59_.hq2m+Oo?z6q4wtrWF 㟙J()HφF;6NnN";@ARc![kԎ0'l''[wז66O獝Tl흁@7#3?叚 ޞvv+G h898=iO `lnAe]/5.*ǖX&0tN ϞW-Qg++Yk  ͭ<Ԁ:XXQ h,oddRK8|P_ 1*?dAۏa`e/#,mV&G Gi* HHQ?&bcdklnc `da88Aic_hml>BvN[?dg)Q8t'l>Nzz?DG2:,:,!~Qu> Cd!m᣶ÿ=>j9Z8 Gӿ5hd1p\9?wߵ++99Z̍?^Xp1pr0wӢG?m"eI8h*K~ZIn%7Js$YlI1ukg# /"0J.WIHq,Q<ۊP;hz8tD]ֺٵp m{y 5:ҠW`rN?1I.DMsm k?K&i1$*ŮD=_洑^o^BXU8Nl Z9B4D!K~]YubͥX^8vu%P֬'mp[X̲KYW1 0eډ]67+852tPʔ&;.K_vZs6h\Wf2j`@GK I</9qzda.bV u%>P;ӯzaiRPC]wpe $'hO k*#Vӫ;G\!盢oCw(e#28:5jpPeۂ1SC|9ae$lOiq .{r ;T kisӜQ*5~0Po47t.¦򾦇 _k'*(iQB^!@qR<4T(RWX5)܀B؄i6a ͉<+7@&؁L pԋ_h]ByǹM0䗬Ra;6)G;SǤvn">”H_A"L9-1ln{B4 B\qZwV~VXcD^VM8L26X`b)>-9=g#mV̜Ds7an1~z# N$l#*tpSfYݎs%M'ݖ, \gd!H.hr9 ᅦP]C7*p=TZɰCG9Q~$&ޖWSRpҰ`MF^ 0LEkg5F.0&oC6wsfsVIT+WL5@`=b3%Rjۢ V&>wiÐWq(|t 77tvMYl—CY$`[aw4V_Uо Pa&ۈzӟ t)[T⊃g}:>ŹHBGv)iKtS 1ynu xu+3δ:78Nń78G2(<`=f<qms1mgߊ_Kؤ݉2a79`s]{igoPRj=_Ea49Sm{k>-*ե'IIHWsަ3m|r&4Jzɣp1^It#Mqlz"π&D"-B9jiiClʣ8-!jJtΡ|oU"h7$—5A{OJ VJ-Kg! &•Fwf3C? b|'hLdy1Ƣ[L ̲H!R,'_\U{XS]&X4tq|*zYfQa+\`[`SֵlnvFˆХe*g|1E95 ʔWGf.Ǖ̖0U "h/g-7wþ=f^2y˳wY񴿮tn1b`p9\S TpPA6켇hmu%S 6ܻ! dDڛM\b41)Wߖ=E ޺5gLNp@}Ԟ63&g&:]iZfPD# U nWQxDDKC pCcs3;Y'WSJ eUG: t.jJJnZ7QZ:KA}ȶhX@~O`"OdD(htU>M{"r6JqMB4.LZ7㡋Gog :IG[I/G%K:Z?%^>sF.V뉹 aFߚkkXţ2]AF, K㡾> wu9Gو\VpY+a݉9)I0$\s'䷬Y/eTJi{Rߨ*͔Bc?gHA]HPX4܊'X F|>hJ5e orɤ#v\ 9œ`͗bLI.K I·qTmmqgXڱB#+4n̗U %&gg{.fSև~Uy:"a#l3F;zROjtyOuGxU 55J, ΐSWqE/ML+ q0nZ?CZ+W&e75R\'2+*sҭ^]6lL\d[0hɐ#i4$lW ^a?KR _毴8e~PSB7Zo3|/,XXvYT.,+؁jKрX X2ȋ߳3v;&1%BɊάVαO^t+HĖ]]5ޔUr+ǐ5يAB$3HQ+p?!DL7݃c~0`v1EgH fHy;!sׂ#ICtS ү\q2Ohݙ_)6 "ߢYU'-.7_-hΗW0A>᣻}etHe3nCBc MUWfb4u%p?cs -yR"[4 LSM1S+1yJ4ITY!s}!vrYy\/:ַ''W‡t*dlZa}=큨R|| 鐛OچejK6tq+6HX~ex2)8𺤝tKlI pK WT!U_*#e zBbCYTka]$> f8Qpp s6 /JiNY>, xb;^f'! m7~7bj|'.%85G3Cğ<H/,KZ zv2v5 SH^1ɧ%ɟdS ٔ;mP^C 7_ ;MƏT^1|Ri,JDGAFSgԻ+^^bn ?RH$d#4 ZM"~폘\.:"sܚRΫ @Zs?cz>Z|D=@Y*^\ǕMWWP >a\XH{;qzqk&Ry/"+BKY3rlw: 6Jyl,pjS?" #}SΐCkrӺ4UC!:ta_\WOKg|&!Ħe|T~.B=tBda)m8 !Y{`2O oabw}B-SCKn9Da*-NgpI^>'NpO8dMp~xݝS1M!Cji9LA" u7J϶,Ttd7[]윒Uo14S7%NϚ+ / >2D`D16% ZV])Ҏ=FC`Ub`nQ& u2PЂ~UjXmk PЊ!ob< 2zCo PƬ?Z\dGK6-مkLr0sU2&9ds'V'Y`|ᬽ{J?4Սet|]@4DBNJ,=Yc?=ׇII繏jO`[V3ȒrAF+jOPBB|^WL6Hˣ1h#mWIP]~*ä #ti+'PQMy~;61DvϹ86KjG(:  iVu {qF%sǔ[X`Ӂ+8--#X?+=]vTPӎSERl$ GL9oF9>TR{^e&X8+cwtR ֈF|8n4~zңnIp%8wQjo0ᡫ -kӺiV.NE Oc:Y&L4q<+dGr>jӥ:nm2y#%U~#VdGD'դ$LeA}_jcowAW#~<,NW:>+1_47CDH8/Z1isO-<&M/]:+g+@vzI*Mu [^ 73a*%pot~<>}}a87U9ǕcFz$Mn4[U(`%Go'r[o|W)/IKH4ZmZ ' aʁ>U~e M Y"m:Vr71 7>4(Bگ4/%1TMT w$X"^2ˍ5e4 &eMbPsf)FC't5M[0*Z:ี'WW'JI'*!+LJdRi=f,"-9:3 I0uwZ,v~a.S˼3%S@A-A%-Dƞo яUǒF0nd.v6ٞk7o~q:h!L0&-FW$ $CA6R'r+;H"ﴰ#Oށņw߰K.X? _M zIᡫ->ѡsrzbE@20Lnv}ؕl'n&KDGYeT4hvagz(+8''; A(!S S?HFy25M\΂%jX "|~} ҩ mUD]k4Bݏs3F-bT%,4Jkŧ@[X`NPz(HӃ~ϓt>cWs3x_/ f]\`!*d5{xǗ/AJ$YGR(n'\G TO?\3kƛg@B'dwc?%wC; [:Qw)o| /ݺ|ډ_' ]Y;T]~47 C{/Y7=zl*CYF&tLbozه-u[˧R[A,aޡ"f k)vm%f?h撥QXayi0}AӦ4YlT bfD{{%|7fx&_'b`}~!@XKkFEs61?џc\#묊{*s!1W6 bn9^b,BFop&u/3k[ v3a ^2+(Q/ǓrS3˷z_!%FyKۍ%E1}0)QCT=:xRGĤp_%hKԽo-.i,xP$vLo)1:6~FǦ!amh =$H鑽kܥͪ8jeN"li]r1*AZtŴak.n,y+#, }w]cM`u/dP!<>Z i:^olb =O-CSR>z5el\*p< r-[g ![%h%ռs z@^*[jnD~{k?#׵SD˄ H7qy%n2=aJ>{/Wd׵ꌈH2rȺ0.IGgdԏܐ `k@;XS(5Z^._Iئc/:f{Ccs+Gg( @~xuYX'HpRcQ.(f%W6)[9HrnM^+#z~g?$qKܘ3S^DQ 76Ƞ`dzg2zж.(mfy).,uټl^8IjyPuGؕ2VxG4aSPUYB#7d_` Ț??=7IX=}*8.Da?Rvxvd~/z *+T,t+'EL;v@K@w#aF"r3,8y Âսz)_f $|&r 8!],|HSh`s Zmc+^`҇Gga>(Q74q\ ДW8 +q>c!!%Q]֥}2^0d4 6Qb  p3;Pq XOKV2[f?^Bpcd?YZ|-Vⰻ G1N`b6 fpJYoہ #9b>8";$R2Gm6 ҪcNJ#O@gLgSX q̒өP 5v c~.%O5\2mEؕXH8x%1X׶OIDOFqeG(!V/Su{D>o$Y2ۙY"+rM\mVm'oڻI"DKܞw{[HwOA][?Ε"UytV %m<9'qaZTmL 8̢clɯ5J(|uiG|W D٘!Kh23(~0Tht_vWGlJb҄c'Arչ )mğgD8qzF ?$F56:^BL gTLaQԪyRxԅQ7ja# TF,y2*"RPb`xZ bS11īhPTMMf?ze%Ws\Ú1L_tv}<ǒxMt,pqAךpM:TfRԳrޡ9o&-}r1^ F\GM6ŒW aIVR}N3h7% #%&YE|!#fjf-띍2@Vrǝ3]?v?4*x+;wǃE"~5@+*%*1֗Є cbvBw}U)1^QA)Mk)\LS۞fm/5}{㙈;:vq}usy$To@C#TtP#]wfÂG+J%XpR!N1Uy֌Ņ_t|R-T'SJmOVٽ}{ꑳnbY([(ZW'/ϵũ/ wFmD,ʘ0m2booS>svЪ䰿,́ K^{C XS*4s)5MzYva]#ej1[0e#GRփӤ6!lYLFVSFwG~>tHȌ=/uaS:89̕MLtc嗭:bu 9ΨZ[Yn$Br;hP_dd58wսOOhxceĘϛ@=# R%F- Jbi+\kɎMYmDME*aJw x,w&BʙypWƠ(S YS*TS>!=#l !/[sxLKL~h*ˡb}JfM Fq {`_<}G'S$BߘdH]o'\Don:Lۥ!s`5]\a,T;/j9,RHq8ދ8؞x;Rb2Z͖8/DzF{ɗNS;L\Ы`ox[d׆=LfӿPM_p}zĠ͢)U7'~. ? m{Je4{gx}UJ/M,e: %J6(oo446a7s9F ޳Ts,aE X2,CO؂q +:jN`NPTh:">l(/˓|(u9Ϲ&5(#YT4n8Idxք!lAO@- S b[HhImV|r-'2)Aqf86LҎ>żń#tXNQqBD-{Yh^. {JC$Y$Y?\WNԨ݈+e׹bY[EPO;KSN.yPZ-7 춐 3ƏOmлTW)}ҳ0b\_AH/x(eN=r ֹڴYIDUD(اRD#kUO 1{؍AB)}6pzwb>tx0j62$馛Dt9k)xqNs7w bwQ) #ʞ3nΎ"xCvĵ$FZNC[~%A9A۶N9\EO/Ї"d|r~yLqv^ebGl~~\㐁 V jgK?_ fٮ,\:3}Ci&`*F^ )Hp BG(@cvbT^C5%u*H5ֈVzK(\ "qo@~ m 힝/3n;u^zro+ RRcKhtG$^5.gt>.y~m#Z1FqXg %Eח.bSx|t 1.Oež E:u"l "q|l Zt-Wʋ+&~$5}4weαYN{F}O +M+Xw* _\$F屰úȅ.hgm5V;Z9mY5hg@&ە7TWv; _q5LܠMx c!񰽁O(2|e3X* -}@d'{e\IrL0wQx3dF8Eq8qu6PK_冏pKc7tH7ӡnZ#NRYK'o_K<0<#7mfym/A"y\ͷ3]q'a7OW&֫|O,DׅE H4Y0ٺq ͈/!ߓ%%]]_jp0nk. 3 ᭌ$r4FV\YG|VѾLs H_] 358leWAn2ƌxW `/ }yw._M2}"QIvaFZN7A԰q}'hN[OuECcevs!p nAsZxOq pĀݵqU5KC#4 Ti~c-/bZ="<$ҽ7J LNUx;Ts/82#\<Ԩ;Ʊ \UC0ۆ dARm&v:a#7NB{6B;B+] ryD:"# # - naؽs).J̔A: r9R%[?7aDSuƎRldlj6tk?LJuhϼ>dUak+Jg.f3O/țeW8ZW6U#λ~j7\҃[!WR%_X"<<8=H?X费=!pDģ̖]mcD;~xfٹ%_;t1`h,T# E|+U%dh-6*?;\P+-&ڳiX602Zy {_":O1҉7M 2:/9M@ 1 :i^6lP}HTiPKOUFxDQ&E>jG?6nr$[{L^pKƭi m;e.м%Vzn|iv> 9a L M԰wjʷ,p B$M vyAGkiٞ\e}:·/<$44ɹm 5!9]E?}uHF£Au!AXtDaDl !DÛfȥ_j*nvKZF8$:Qx$s[ͯ]_aSoc-y[>ZZT dSdͰs>_\JZrrNj垧k1֓4*G9yȈ` -uKۈKDA V:'e))FAN#i7 upuêUVYL6X:oL|cadE1lZ[|rKFЀ/_'*3 9#4ki%4kMbU{-@zɹP-nG_zQ-)7l6#5b !p9%%qvkM_}'7'1hֆǢCmzR0{$5aIrjud9m^LoR'[әD"ڋ7XX Q&89~H8hzSs{Ww;,tiȗ=|vjV58=cdRUnŽGBy_{){~@/M6^_|2u?MNRID"6M&YwIoha2mfG$$Wu\0Q`TJwݼ~,Y?$R$wqKTCesD`I5B% w }LGiJ?qEiJ-T _1-@щo#Cvrbedsmޏ0# ;\r>Yy23ŽG~c!mB N*oAۯCIb! 2`nJ âhB^x9 9y=1X9AP+HN!{L Ԅ(`Aul6J8h@b{]0eOK2 LYvB9@m. J`^m/dpBSG" bSna16~~n;Z !ĢJ#0WG-j(&>eJ{ 39;p~sBArZG!л?2jW/2k ;zPðOE36eг5U&k5}qI d/I. /[+R7wA\ CX"Y*)%zIZ~f4A,'3&3~ΨF7I\mIm XޑD &2[N m/_fk݌jMf^ *+*X6zr|!|s*~\Νw~陼+ݛ$+ 8r(h"o]{'xQY\ܝH_k<&iY2%xreĔ,M->E\fU:pt}IVfPS#;D똅5EgCo0b ~*AYR_.o3ԓlQ $_69Thc;퓵2t8l-C}TKr!8 /؜D"쬂|wq#7)caZZr>صldXj:C>ȗW(lI{_B .p#kwk,{RSMEyOr{irh#"4!͛G=>?!ыii`,C}"kf3 ԡkT!{tupa+ȮئCR8FûʬmǻA1/sjKB[ ZL+~SݚĦjRy|CJ텑FX4Oi#i[~; R">x6n[ufǗi,mFrn杞^WK1ۈۖSr$2"/#n*?H&|R71{@3 )[/+N.11JQC"م˩tTMiX%2/QbUA2u[v+JIr6OkLX[9}5E肚[7M y SuVn2 Zb&j 2]\rh KNf&Y]d ;2/7Sk]NQ_-F<#EcDzVt/͵5o/׾ >JctZ#1s5̖K|S²^7xjQkIia+ꤨ#UNG)?P#yD0,XLvi0;krP W;=nⱡSن!=HuD!DKU.tAUW__4a`a3A?0[SB4 ~Itl嫫xA0DN^s5'Ku΋XsL ;d V8t27gP5kT~%R :k1jG u. H'q5k0$Ij9min:WBإE8?ݻ<2N~횫[~zO#'D"ed+Jڠ)%/dCozqv<"6ZV)JD~OMyU<(rw.|'p0QS;,{Alyu~CT/J;YygLBaxEw L^о8B?y, 9F_ `!ۿd,sJ氿!D6 34̇\C̖Lkd\ji,h}5w,'-..U{BF4sj!CIK5`{`?`}A69_Gj򑿪/Kai󂬧fws EjiҀq}^a@]xǂevMwPu{FpZsx$/w< WlV b;u./Ju3V![4ƛx h(tUIPon6A< w6TY+Ȕkxq)exytY?,j.OI}v~ޅ[R ߠ}[ %LГ2#.qn?JҴ6zZQ_s!ɌP?gt"IuGb4&VK19lB՝/52 VYK;]GŞgߙܠ@Z&l.OϚs 2/a(%0jpXց`J\6*Nbb>;8v%- 8!&[ Et~F*˽BLoH]jWNNΠ͊+,z8,|*le>B4BNDČY'H{}g|`~:? WP{i,RQT<^BDj: //o{oNM4٨.UKunU#r5ҏ5Bj1|5 Rl4펩(-[7S9yS?9u @; KycHxpaՂ7+Ij9iW2 ߚs}_ecZ]}}ʠx쯃Czr>Xy  04p ΒJB鼯;VLKxp]G* mul02W墥ÙHҾ7]}ܣȔR|c\.~~Wv1ǿ9Y OvSx:Q(,FB ;F4: nR`%UcȍYKl( 1XS$fX> uG5XhA}P k@mM- M$7sGoN$oNw]" zf<HCc@EXDOǗsppDN/mԄFkf<|S f@qws^Qƴud}͙/ui@8G>+\iP:pٸgP=7#+OhM'_ݑ[zpFs˺[ث~eV 1޿P?c2)R,A~y&`Ͻ|HkkGygGj[2OK kӂVռo^jwrщPjN'.\6 x `z'SX4LDF6Ry ǫ.dU4VzOhjE#LGT@d.F{QF/~úRV/~P\ jϺJmQYWyF m(@2;>_!ItL hbSuә7c[˭nYQtVwo5(a6j#mgs-/Lk%Xa~'<KTе)ˮJن?ܻ,*mٿ/:MM^"Nr4[n}2}kZF6TƂtrd_m!Ętz50i݂Sj'UM* H_ 1!k[m4֑S!%MEώ^;|lG5XT14ӱW:Dg*;0}m秭@/# 4Ěb`ZL3*`;_헯Cauu6ǭT]*Rv64I )9 (37X~!(-SbkHIUnZ h {~c#d$E8ٿXqǍX@&=Ïkg?m|Ė=K}p:7}jruI9m9 tX ((?u}RDBUbܚ׏œ=QhwerkwioOX+Aڛ,{@<Ǵ hI')Dq%U1-y|PAǑ\6CaooN|\I?Ut^ybζTm\69RaDxbl#f@|.k#j|(r`z$ z(b6/(T ]M ة~U#J'\5)lu,9ٗp/I陼B\j @ʠ#]Hэ)yL+$* ^]nBOލ[vIpaq2}^-<;a==cg |HY/)Z7=|_AlZ8ǖ)"dOH!x}g͓8%b࠾`#ՕD>/F2F7ȮΘK{%uAi<,(^Cba"G;t(zռ|iO4sLLJxS3jTMҝQ,~e,?ݷ l <bNG_bZ9 ]ɖ~+U+Н2)@qiic1<<&ޡPHZCxMkrM26*\y#H`C`H oc Zuخѩ;p9zꂥZ%0|l-ŹB ʜfKLVizLi@tORhH&s*SUXZR 5VÅn<1 y20H&l)3E .?V-)aMήh0Cu򠖍EƯ9<F=Rk$+^wSMcRN2&?QEqc6j{' M&ae}>PJ+«wvQcqO6=OB M.AL+Hy3z3LL~;8h&\❗hd ^$ d"ucL_/^j!7Ymճ2A%. "U endstream endobj 173 0 obj << /Author()/Title()/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.13)/Keywords() /CreationDate (D:20131031170344+01'00') /ModDate (D:20131031170344+01'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012/Debian) kpathsea version 6.1.0) >> endobj 131 0 obj << /Type /ObjStm /N 59 /First 499 /Length 2931 /Filter /FlateDecode >> stream xZr8}Wq\[;P*;'8Y;I&flȒ#JiIMjF}L(\`Z1 1ȊIge1S+px`ƁWtWƠ %E,:`i3%c5ԑLfL븲ey; C^ PϚY@/ 0i KJʂ #V AZ`U`ĚV9$! Y%80|^#-5ǜTdg.Zesa&f;5L҃*浇[xaZ A Rtς7 8#XaQڎ=W_oK_Np:eX//*FB$=//(PP}8A"ZN:e?X&;_f[yC5nf1~Diґp\\+V>9bUeŢw`:s΍=^ڱ(1kH Jo3L ziԦUڭ) #"!/IPjl2D7ڀ4$9'Kr  VVu61Uc`'-fF^% F-bjd`ʠ<JQ"f 1ML͐R3%-;Cjm8$g=mkJ\IUF*S&E'/ wjUAKBQTx:сIY],2N&7y|_8~~EZ^gM*a3[}h Tk0 6rBa?v|߃xM!3?o[-wRQTLV|X~\OfWU >$VcH7ӔU A-DrY],e!og^MJbvA6BP(ێ"7E-I[ gpn?Ϳv ߂ɫg'@9BŬ'" <Ep8Lvs\n_:=ou1ЈoJӃ_ Ž d+A,A_m&tW|llR~sHIBQ|NF>o;M+W>wO :N?|(igk8wtiI!^Y%kN 1|c ǔ% ԥ!Իdš6Sn߲ۛ`Z((I~Aa3]?"EØ^*qU|$"bpR ԮS'GhVt8$??*~Kc`mYuG7Mݶo}j6Tmٳzzw!?FQ9SMdGvߦWPlhi6߮h ] /Length 406 /Filter /FlateDecode >> stream xIVSQsH**AR * 0RA B@@j6^T}]:9y/kf/1K̭P3R=*`6NjF(3#=&8a6Jzp9R pl,\3"n ڠnȤ:fݐw\l I #include /* The support for explicit isn't that universal, and it isn't really required - it is used to check that the TiXmlString class isn't incorrectly used. Be nice to old compilers and macro it here: */ #if defined(_MSC_VER) && (_MSC_VER >= 1200 ) // Microsoft visual studio, version 6 and higher. #define TIXML_EXPLICIT explicit #elif defined(__GNUC__) && (__GNUC__ >= 3 ) // GCC version 3 and higher.s #define TIXML_EXPLICIT explicit #else #define TIXML_EXPLICIT #endif /* TiXmlString is an emulation of a subset of the std::string template. Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. Only the member functions relevant to the TinyXML project have been implemented. The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase a string and there's no more room, we allocate a buffer twice as big as we need. */ class TiXmlString { public : // The size type used typedef size_t size_type; // Error value for find primitive static const size_type npos; // = -1; // TiXmlString empty constructor TiXmlString () : rep_(&nullrep_) { } // TiXmlString copy constructor TiXmlString ( const TiXmlString & copy) : rep_(0) { init(copy.length()); memcpy(start(), copy.data(), length()); } // TiXmlString constructor, based on a string TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) { init( static_cast( strlen(copy) )); memcpy(start(), copy, length()); } // TiXmlString constructor, based on a string TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) { init(len); memcpy(start(), str, len); } // TiXmlString destructor ~TiXmlString () { quit(); } TiXmlString& operator = (const char * copy) { return assign( copy, (size_type)strlen(copy)); } TiXmlString& operator = (const TiXmlString & copy) { return assign(copy.start(), copy.length()); } // += operator. Maps to append TiXmlString& operator += (const char * suffix) { return append(suffix, static_cast( strlen(suffix) )); } // += operator. Maps to append TiXmlString& operator += (char single) { return append(&single, 1); } // += operator. Maps to append TiXmlString& operator += (const TiXmlString & suffix) { return append(suffix.data(), suffix.length()); } // Convert a TiXmlString into a null-terminated char * const char * c_str () const { return rep_->str; } // Convert a TiXmlString into a char * (need not be null terminated). const char * data () const { return rep_->str; } // Return the length of a TiXmlString size_type length () const { return rep_->size; } // Alias for length() size_type size () const { return rep_->size; } // Checks if a TiXmlString is empty bool empty () const { return rep_->size == 0; } // Return capacity of string size_type capacity () const { return rep_->capacity; } // single char extraction const char& at (size_type index) const { assert( index < length() ); return rep_->str[ index ]; } // [] operator char& operator [] (size_type index) const { assert( index < length() ); return rep_->str[ index ]; } // find a char in a string. Return TiXmlString::npos if not found size_type find (char lookup) const { return find(lookup, 0); } // find a char in a string from an offset. Return TiXmlString::npos if not found size_type find (char tofind, size_type offset) const { if (offset >= length()) return npos; for (const char* p = c_str() + offset; *p != '\0'; ++p) { if (*p == tofind) return static_cast< size_type >( p - c_str() ); } return npos; } void clear () { //Lee: //The original was just too strange, though correct: // TiXmlString().swap(*this); //Instead use the quit & re-init: quit(); init(0,0); } /* Function to reserve a big amount of data when we know we'll need it. Be aware that this function DOES NOT clear the content of the TiXmlString if any exists. */ void reserve (size_type cap); TiXmlString& assign (const char* str, size_type len); TiXmlString& append (const char* str, size_type len); void swap (TiXmlString& other) { Rep* r = rep_; rep_ = other.rep_; other.rep_ = r; } private: void init(size_type sz) { init(sz, sz); } void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } char* start() const { return rep_->str; } char* finish() const { return rep_->str + rep_->size; } struct Rep { size_type size, capacity; char str[1]; }; void init(size_type sz, size_type cap) { if (cap) { // Lee: the original form: // rep_ = static_cast(operator new(sizeof(Rep) + cap)); // doesn't work in some cases of new being overloaded. Switching // to the normal allocation, although use an 'int' for systems // that are overly picky about structure alignment. const size_type bytesNeeded = sizeof(Rep) + cap; const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); rep_ = reinterpret_cast( new int[ intsNeeded ] ); rep_->str[ rep_->size = sz ] = '\0'; rep_->capacity = cap; } else { rep_ = &nullrep_; } } void quit() { if (rep_ != &nullrep_) { // The rep_ is really an array of ints. (see the allocator, above). // Cast it back before delete, so the compiler won't incorrectly call destructors. delete [] ( reinterpret_cast( rep_ ) ); } } Rep * rep_; static Rep nullrep_; } ; inline bool operator == (const TiXmlString & a, const TiXmlString & b) { return ( a.length() == b.length() ) // optimization on some platforms && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare } inline bool operator < (const TiXmlString & a, const TiXmlString & b) { return strcmp(a.c_str(), b.c_str()) < 0; } inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); TiXmlString operator + (const TiXmlString & a, const char* b); TiXmlString operator + (const char* a, const TiXmlString & b); /* TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. Only the operators that we need for TinyXML have been developped. */ class TiXmlOutStream : public TiXmlString { public : // TiXmlOutStream << operator. TiXmlOutStream & operator << (const TiXmlString & in) { *this += in; return *this; } // TiXmlOutStream << operator. TiXmlOutStream & operator << (const char * in) { *this += in; return *this; } } ; #endif // TIXML_STRING_INCLUDED #endif // TIXML_USE_STL blobby-1.0/src/PhysicWorld.h000644 001750 001750 00000006205 12313310251 020614 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "Global.h" #include "Vector.h" #include "PlayerInput.h" #include "BlobbyDebug.h" #include "PhysicState.h" /*! \brief blobby world \details This class encapuslates the physical world where blobby happens. It manages the two blobs, the ball and collisions between them and the environment, it calculates object movements etc. */ class PhysicWorld : public ObjectCounter { public: PhysicWorld(); ~PhysicWorld(); // ball information queries Vector2 getBallPosition() const; void setBallPosition( Vector2 newPosition ); Vector2 getBallVelocity() const; void setBallVelocity( Vector2 newVelocity ); float getBallRotation() const; void setBallAngularVelocity( float angvel ); // blobby information queries Vector2 getBlobPosition(PlayerSide player) const; Vector2 getBlobVelocity(PlayerSide player) const; bool blobHitGround(PlayerSide player) const; float getBlobState(PlayerSide player) const; // Methods to set/get the intensity of the collision // which was detected and also queried last. void setLastHitIntensity(float intensity); float getLastHitIntensity() const; // Important: This assumes a fixed framerate of 60 FPS! int step(const PlayerInput& leftInput, const PlayerInput& rightInput, bool isBallValid, bool isGameRunning); // gets the physic state PhysicState getState() const; // sets a new physic state void setState(const PhysicState& state); private: // Blobby animation methods void blobbyStartAnimation(PlayerSide player); void blobbyAnimationStep(PlayerSide player); inline bool playerTopBallCollision(int player) const; inline bool playerBottomBallCollision(int player) const; // Do all blobby-related physic stuff which is independent from states void handleBlob(PlayerSide player, PlayerInput input); // Detect and handle ball to blobby collisions bool handleBlobbyBallCollision(PlayerSide player); Vector2 mBlobPosition[MAX_PLAYERS]; Vector2 mBallPosition; Vector2 mBlobVelocity[MAX_PLAYERS]; Vector2 mBallVelocity; float mBallRotation; float mBallAngularVelocity; float mBlobState[MAX_PLAYERS]; float mCurrentBlobbyAnimationSpeed[MAX_PLAYERS]; float mLastHitIntensity; }; blobby-1.0/data/scripts/old/gintonicV6.lua000644 001750 001750 00000017412 12313310254 023321 0ustar00danielknobedanielknobe000000 000000 --Gin Tonic v6 - No Comments, sorry :P CT_ServeSelf = { 152, 163, 180, 195, 205, 240 } CT_ServeOpp = { 140, 200, 240 } CT_ServeIndex = 0 CT_Tolerance = 5 CT_Action = "" CT_ShotDecision = 0 CT_NextGround = 9999 CT_LastTouches = 0 CT_LastHeight = 0 CT_WaitCounter = 0 CT_WaitName = "" CT_WaitMoveTo = 0 function IsAt(position) return (math.abs(posx()-position) <= CT_Tolerance) end function Wait(name, time, moveto) if (CT_WaitName == name) then if (CT_WaitCounter == 0) then return false end end CT_WaitCounter = time CT_WaitName = name CT_WaitMoveTo = moveto return true end function WaitQueue() if (CT_WaitCounter > 0) then CT_WaitCounter = CT_WaitCounter - 1 if (CT_WaitMoveTo > 0) then if (not IsAt(CT_WaitMoveTo)) then moveto(CT_WaitMoveTo) end end return true else return false end end function ResetWait() CT_WaitCounter = 0 CT_WaitName = "" end function OnOpponentServe() if (CT_ServeIndex == 0) then CT_ServeIndex = math.random(1,3) end if (not IsAt(CT_ServeOpp[CT_ServeIndex])) then moveto(CT_ServeOpp[CT_ServeIndex]) end end function OnServe(ballready) if (WaitQueue()) then return end if (CT_ServeIndex == 0) then CT_ServeIndex = math.random(1,6) end if (ballready) then if (Wait("ServeDelay",math.random(28,90),CT_ServeSelf[CT_ServeIndex]+math.random(-150, 150))) then return end if (IsAt(CT_ServeSelf[CT_ServeIndex])) then jump() else moveto(CT_ServeSelf[CT_ServeIndex]) end else if (posx() < 150) then jump() end moveto(40) end end function OnGame() ResetWait() CT_ServeIndex = 0 local timeJump = timeToHitHeight(380, 390, 20) local timeGround = timeToHitHeight(200, 222, 40) local timeBlock = timeToOppSmash(390) local estimhx = r_estimx(timeJump) local estimGround = r_estimx(timeGround) local estimBlock = r_estimx(timeBlock) local block = 0 local wallcoll = willHitWall(time) if (timeBlock ~= -1) then block = timeBlock+(estimBlock-400)/13 end if (timeBlock == -1) then timeBlock = 9999 end if (timeJump == -1) then estimhx = 9999 end if (timeGround == -1) then estimGround = 210 end if (posy() < CT_LastHeight and posy() > 150 and posy() < 330) then CT_Action = "" end CT_LastHeight = posy() if (CT_Action == "NetBlock") then if ((posy() < 150) or (timeBlock < 4 and oppy() < 150) or (ballx() <= posx()) or (touches() <= 0 and bspeedx() > 10)) then CT_Action = "" else jump() moveto(400) return end elseif (CT_Action == "JumpPlayFwd") then if (posy() < 150) then CT_Action = "" else if (estimhx == 9999) then estimhx = ballx()+bspeedx() end jump() if (posy() > 300) then if (math.abs(bally()-posy()) < 18) then moveto(ballx()+bspeedx()) elseif (estimhx < 200) then if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(3,5) end moveto(estimhx-10*CT_ShotDecision) elseif (oppx() > 600 and oppy() < 150) then if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(4,6) end moveto(estimhx-10*CT_ShotDecision) elseif (oppx() < 600 and oppy() > 180) then moveto(estimhx-40) else moveto(estimhx-60) end else moveto(estimhx-60) end return end elseif (CT_Action == "JumpPlayRev") then if (posy() < 150) then CT_Action = "" else if (estimhx == 9999) then estimhx = ballx()+bspeedx() end jump() if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(4,9) end moveto(estimhx+5*CT_ShotDecision) return end end if (touches() ~= CT_LastTouches) then CT_LastTouches = touches() CT_NextGround = math.random(-20,20) end if (CT_Action == "") then if ((ballx() < 400 or bspeedx() < -2) and estimGround < 400) then if (touches() >= 2) then moveto(estimGround+(posx()-500)/22) elseif (math.abs(bspeedx()) > 8) then moveto(estimGround) else moveto(estimGround+CT_NextGround) end elseif (estimhx < 600 and math.abs(bspeedx()) < 6) then moveto(280) elseif (estimhx > 650) then moveto(250) else moveto(190) end end if (posy() > 150) then return end if (timeBlock >= 17 and timeBlock <= 19) then if (posx() > 210 and estimBlock > 395 and estimBlock < 640) then jump() moveto(400) CT_Action = "NetBlock" return end end if (timeJump >= 17 and timeJump <= 19) then if (bspeedx() <= 7 and estimhx >= 65 and estimhx <= 420 and posx()-estimhx <= 120 and (bspeedx() >= -7 or (not wallcoll))) then if (estimGround > 400 or bally() > 250) then CT_Action = "JumpPlayFwd" CT_ShotDecision = 0 jump() end end if ((wallcoll or bspeedx() >= -7) and estimhx <= 250 and posx()-estimhx <= 180 and posx()-estimhx >= -120) then if (estimGround > 400 or bally() > 250) then if (CT_Action == "JumpPlayFwd" and (touches() >= 2 or math.random(100) > 15)) then return end CT_Action = "JumpPlayRev" CT_ShotDecision = 0 jump() end end end end function timeToHitHeight(minheight, maxheight, depth) local i = 0 for i=1, depth do if (estimy(i) >= minheight and estimy(i) <= maxheight and estimx(i) <= 420) then return i end end return -1 end function timeToOppSmash(height) if (bally() < height) then return -1 end local i = 0 for i=1, 17 do if (estimy(i) < height) then return i end end return -1 end function r_estimx(time) local estim = estimx(time) if estim < 31.5 then estim = 63-estim end if estim > 768.5 then estim = 1537-estim end if (bally() < 330) then if (ballx() < 400 and estim > 400) then estim = 723-estim end if (ballx() > 400 and estim < 400) then estim = 877-estim end end return estim end function willHitWall(time) if (estimx(time) < 31.5) then return true end return false endblobby-1.0/src/tinyxml/tinyxmlerror.cpp000644 001750 001750 00000003377 12313310251 023171 0ustar00danielknobedanielknobe000000 000000 /* www.sourceforge.net/projects/tinyxml Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "tinyxml.h" // The goal of the seperate error file is to make the first // step towards localization. tinyxml (currently) only supports // english error messages, but the could now be translated. // // It also cleans up the code a bit. // const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] = { "No error", "Error", "Failed to open file", "Error parsing Element.", "Failed to read Element name", "Error reading Element value.", "Error reading Attributes.", "Error: empty tag.", "Error reading end tag.", "Error parsing Unknown.", "Error parsing Comment.", "Error parsing Declaration.", "Error document empty.", "Error null (0) or unexpected EOF found in input stream.", "Error parsing CDATA.", "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.", }; blobby-1.0/src/state/LobbyState.h000644 001750 001750 00000003367 12313310253 021545 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "State.h" #include #include #include #include "raknet/RakClient.h" #include "NetworkMessage.h" #include "PlayerIdentity.h" class LobbyState : public State { public: LobbyState(ServerInfo info); virtual ~LobbyState(); virtual void step_impl(); virtual const char* getStateName() const; private: boost::shared_ptr mClient; PlayerIdentity mLocalPlayer; ServerInfo mInfo; unsigned mSelectedPlayer; struct WaitingPlayer { std::string displayname; PlayerID id; }; std::vector mConnectedPlayers; std::string mChallenge; enum { CONNECTING, CONNECTED, DISCONNECTED, CONNECTION_FAILED } mLobbyState; }; blobby-1.0/src/lua/ltablib.c000644 001750 001750 00000016775 12313310253 020551 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: ltablib.c,v 1.65.1.1 2013/04/12 18:48:47 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ #include #define ltablib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" #define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n)) #if defined(LUA_COMPAT_MAXN) static int maxn (lua_State *L) { lua_Number max = 0; luaL_checktype(L, 1, LUA_TTABLE); lua_pushnil(L); /* first key */ while (lua_next(L, 1)) { lua_pop(L, 1); /* remove value */ if (lua_type(L, -1) == LUA_TNUMBER) { lua_Number v = lua_tonumber(L, -1); if (v > max) max = v; } } lua_pushnumber(L, max); return 1; } #endif static int tinsert (lua_State *L) { int e = aux_getn(L, 1) + 1; /* first empty element */ int pos; /* where to insert new element */ switch (lua_gettop(L)) { case 2: { /* called with only 2 arguments */ pos = e; /* insert new element at the end */ break; } case 3: { int i; pos = luaL_checkint(L, 2); /* 2nd argument is the position */ luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); for (i = e; i > pos; i--) { /* move up elements */ lua_rawgeti(L, 1, i-1); lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ } break; } default: { return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); } } lua_rawseti(L, 1, pos); /* t[pos] = v */ return 0; } static int tremove (lua_State *L) { int size = aux_getn(L, 1); int pos = luaL_optint(L, 2, size); if (pos != size) /* validate 'pos' if given */ luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); lua_rawgeti(L, 1, pos); /* result = t[pos] */ for ( ; pos < size; pos++) { lua_rawgeti(L, 1, pos+1); lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */ } lua_pushnil(L); lua_rawseti(L, 1, pos); /* t[pos] = nil */ return 1; } static void addfield (lua_State *L, luaL_Buffer *b, int i) { lua_rawgeti(L, 1, i); if (!lua_isstring(L, -1)) luaL_error(L, "invalid value (%s) at index %d in table for " LUA_QL("concat"), luaL_typename(L, -1), i); luaL_addvalue(b); } static int tconcat (lua_State *L) { luaL_Buffer b; size_t lsep; int i, last; const char *sep = luaL_optlstring(L, 2, "", &lsep); luaL_checktype(L, 1, LUA_TTABLE); i = luaL_optint(L, 3, 1); last = luaL_opt(L, luaL_checkint, 4, luaL_len(L, 1)); luaL_buffinit(L, &b); for (; i < last; i++) { addfield(L, &b, i); luaL_addlstring(&b, sep, lsep); } if (i == last) /* add last value (if interval was not empty) */ addfield(L, &b, i); luaL_pushresult(&b); return 1; } /* ** {====================================================== ** Pack/unpack ** ======================================================= */ static int pack (lua_State *L) { int n = lua_gettop(L); /* number of elements to pack */ lua_createtable(L, n, 1); /* create result table */ lua_pushinteger(L, n); lua_setfield(L, -2, "n"); /* t.n = number of elements */ if (n > 0) { /* at least one element? */ int i; lua_pushvalue(L, 1); lua_rawseti(L, -2, 1); /* insert first element */ lua_replace(L, 1); /* move table into index 1 */ for (i = n; i >= 2; i--) /* assign other elements */ lua_rawseti(L, 1, i); } return 1; /* return table */ } static int unpack (lua_State *L) { int i, e, n; luaL_checktype(L, 1, LUA_TTABLE); i = luaL_optint(L, 2, 1); e = luaL_opt(L, luaL_checkint, 3, luaL_len(L, 1)); if (i > e) return 0; /* empty range */ n = e - i + 1; /* number of elements */ if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ return luaL_error(L, "too many results to unpack"); lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ while (i++ < e) /* push arg[i + 1...e] */ lua_rawgeti(L, 1, i); return n; } /* }====================================================== */ /* ** {====================================================== ** Quicksort ** (based on `Algorithms in MODULA-3', Robert Sedgewick; ** Addison-Wesley, 1993.) ** ======================================================= */ static void set2 (lua_State *L, int i, int j) { lua_rawseti(L, 1, i); lua_rawseti(L, 1, j); } static int sort_comp (lua_State *L, int a, int b) { if (!lua_isnil(L, 2)) { /* function? */ int res; lua_pushvalue(L, 2); lua_pushvalue(L, a-1); /* -1 to compensate function */ lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */ lua_call(L, 2, 1); res = lua_toboolean(L, -1); lua_pop(L, 1); return res; } else /* a < b? */ return lua_compare(L, a, b, LUA_OPLT); } static void auxsort (lua_State *L, int l, int u) { while (l < u) { /* for tail recursion */ int i, j; /* sort elements a[l], a[(l+u)/2] and a[u] */ lua_rawgeti(L, 1, l); lua_rawgeti(L, 1, u); if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ set2(L, l, u); /* swap a[l] - a[u] */ else lua_pop(L, 2); if (u-l == 1) break; /* only 2 elements */ i = (l+u)/2; lua_rawgeti(L, 1, i); lua_rawgeti(L, 1, l); if (sort_comp(L, -2, -1)) /* a[i]= P */ while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { if (i>=u) luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[i] */ } /* repeat --j until a[j] <= P */ while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { if (j<=l) luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[j] */ } if (jQ^eeeeeeeeefbb}}}{xxu{rwtwrorilidd`]YY]YYdd`eeenad$I,+ /Leeeeeeeeeeeeiyeyl|}}}{xxurriii```]YY___ccckhdrc_)CnE 6O^eeeeeeeeeeee?Q"4$50Lav}}}xxxnkkdd`___```fffmgc1<|@F/-.Lgddeeeeeeeee=B(\L+;QgwRmPiOeOgVkcubr^qUgJ^AYF.OWb"+(91=9?MRgnptbgJP6?ZMQK"-)UB!!VU;6E4&DkD"#)?P80J]eeeeeeeeeeee=B,HST\+5&08BU\WZihO]*V/I(.q@GKJ'MT@:AA=6f5A0+"*Jdddeeeeeeeee+6'BT%QlZ+8DJr1_=943&P]IeE&N;@Y8KjEC@ 28S5 /HTdd`dddddd*4 (3Q)SVa@GQU]a;``(LUpW34'P(NVcJ#*.I`76: ?@1*#Ha[^```dd`ddd"+(3.Uj4_sTXNUse@V&.`-Q5>VRG3H2OLBQ"B))7< ?G6-0>4?MS1:''F\sfaoVlW:J7OYY`YYYhhaǃW`JQ@JLPel1;&{dwi%.1I~QZ>D9D;D7@6971 " bA`B^z`*(  $[__[__iliAH&ĉg1YeY /RiVT.1PZRe;Z^\66  %jcccc\dd`jjmľêç^j)%+4Wdmi)64Odi=<"67kkDbU]9>'$~VYdddhhhqqw_oVrYtd~mnu֢݇зugg~e~[nSkNePiWqQjObQkeʊySjLeSoiv+>*(4(~f1]sd$/Vnvv.- %'xkD`Lb:=*3xa^nqq{xu&/!/(58@3@4>6B0<3CDZCX)6*:2?$/ /4=HT4<#1-6>2>&9?TF_.;#/7?,8$0&3->;}x_^19iptt/99N', $sFaPa68/:|ps )5֌ކݕጠܫ唅;C!0",ϖݢ086:|{_~ݑihULhx؉ي6> +)jRSjЀsk(7%$,y:aŮҍt=d~k$0Ysmr$26$!"~nCbQZ+1FF +5ѝ=fƙѧ}\~sr*1ZzY[筁9b䭎jmysXu(W5`ڑik(2TTc1^ׇu%1bw3:.+{yQmʬz$!3BLbD^Mfai1<{AI"-+$.dfcʞ0<闗xuRx秔)2楒Hq矌FlVv劂ݩAlܩyBhbwtȏCiȻԧBhڏ~`x+Zy4=DZȦ]_**7MgڐVxBhΏedSvᴐ%6ݬCkwg:IΠeg25"#AF[pH[4?ALkl蚋BK"/#-`a]~1Bȣ07(1wqX|vv{3@$0yGoݳjgs/;.9⮒^U$229zm)609̤vuPQ:=7533/9ZZѪKtz(3\\[#3)30:rRU&24\k䭰WaJR@H3>n|ǿ*p Ǔ맫읠~䪯}ɿȿǿǿblobby-1.0/src/lua/linit.c000644 001750 001750 00000003231 12313310253 020236 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: linit.c,v 1.32.1.1 2013/04/12 18:48:47 roberto Exp $ ** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ /* ** If you embed Lua in your program and need to open the standard ** libraries, call luaL_openlibs in your program. If you need a ** different set of libraries, copy this file to your project and edit ** it to suit your needs. */ #define linit_c #define LUA_LIB #include "lua.h" #include "lualib.h" #include "lauxlib.h" /* ** these libs are loaded by lua.c and are readily available to any Lua ** program */ static const luaL_Reg loadedlibs[] = { {"_G", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_BITLIBNAME, luaopen_bit32}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} }; /* ** these libs are preloaded and must be required before used */ static const luaL_Reg preloadedlibs[] = { {NULL, NULL} }; LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; /* call open functions from 'loadedlibs' and set results to global table */ for (lib = loadedlibs; lib->func; lib++) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ } /* add open functions from 'preloadedlibs' into 'package.preload' table */ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); for (lib = preloadedlibs; lib->func; lib++) { lua_pushcfunction(L, lib->func); lua_setfield(L, -2, lib->name); } lua_pop(L, 1); /* remove _PRELOAD table */ } blobby-1.0/src/InputManager.h000644 001750 001750 00000005445 12313310253 020746 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include "PlayerInput.h" #include "Vector.h" #include "BlobbyDebug.h" class InputDevice; /// \brief class for managing input class InputManager : public ObjectCounter { public: static InputManager* createInputManager(); static InputManager* getSingleton(); ~InputManager(); InputDevice* beginGame(PlayerSide side) const; bool running() const; void setEndBlobby(); // call to trigger the event that ends blobby, i.e. running will return false after this call. void updateInput(); // For GUI navigation (Gamepad, Joystick or Keyboard) bool up() const; bool down() const; bool left() const; bool right() const; bool select() const; bool exit() const; // extension for mouse included, so that right click = exit std::string getLastTextKey(); std::string getLastActionKey(); int getLastMouseButton() const { return mLastMouseButton; } std::string getLastJoyAction() const; // For GUI navigation (Mouse) Vector2 position(); bool click() const; bool doubleClick() const; bool mouseWheelUp() const; bool mouseWheelDown() const; bool unclick() const; bool windowFocus() const; // config conversion methods //std::string keyToString(const SDL_keysym& key) const; private: static InputManager* mSingleton; // Keyboard //static InputKeyMap mKeyMap[]; // Type for String <-convert-> SDLKey // GUI storage (because we need event based input for the GUI) bool mUp; bool mDown; bool mLeft; bool mRight; bool mSelect; bool mExit; bool mClick; bool mDoubleClick; bool mMouseWheelUp; bool mMouseWheelDown; bool mUnclick; bool mWindowFocus; int mMouseX; int mMouseY; int mLastClickTime; SDL_Keycode mLastActionKey; std::string mLastTextKey; int mLastMouseButton; std::string mLastJoyAction; bool mRunning; InputManager(); }; blobby-1.0/src/blobnet/layer/000755 001750 001750 00000000000 12313310251 020732 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/lua/ldo.h000644 001750 001750 00000002773 12313310253 017714 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: ldo.h,v 2.20.1.1 2013/04/12 18:48:47 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ #ifndef ldo_h #define ldo_h #include "lobject.h" #include "lstate.h" #include "lzio.h" #define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \ luaD_growstack(L, n); else condmovestack(L); #define incr_top(L) {L->top++; luaD_checkstack(L,0);} #define savestack(L,p) ((char *)(p) - (char *)L->stack) #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) /* type of protected functions, to be ran by `runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode); LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults, int allowyield); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); LUAI_FUNC void luaD_shrinkstack (lua_State *L); LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); #endif blobby-1.0/src/lua/lundump.h000644 001750 001750 00000001404 12313310253 020610 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lundump.h,v 1.39.1.1 2013/04/12 18:48:47 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ #ifndef lundump_h #define lundump_h #include "lobject.h" #include "lzio.h" /* load one chunk; from lundump.c */ LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); /* make header; from lundump.c */ LUAI_FUNC void luaU_header (lu_byte* h); /* dump one chunk; from ldump.c */ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); /* data to catch conversion errors */ #define LUAC_TAIL "\x19\x93\r\n\x1a\n" /* size in bytes of header of binary files */ #define LUAC_HEADERSIZE (sizeof(LUA_SIGNATURE)-sizeof(char)+2+6+sizeof(LUAC_TAIL)-sizeof(char)) #endif blobby-1.0/src/input_device/TouchInput.cpp000644 001750 001750 00000012704 12313310253 023463 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "InputDevice.h" /* other includes */ #include "RenderManager.h" // ******************************************************************************************************** // Interface Definition // ******************************************************************************************************** /*! \class TouchInputDevice \brief Ingame touch control */ class TouchInputDevice : public InputDevice { private: PlayerSide mPlayer; int mMarkerX; int mTouchXPos; int mTouchType; public: virtual ~TouchInputDevice(){}; TouchInputDevice(PlayerSide player, int type); virtual PlayerInputAbs transferInput(); }; // ******************************************************************************************************** // Class Implementation // ******************************************************************************************************** // ------------------------------------------------------------------------------------------------- // Creator Function // ------------------------------------------------------------------------------------------------- InputDevice* createTouchInput(PlayerSide player, int type) { return new TouchInputDevice(player, type); } // ------------------------------------------------------------------------------------------------- // Keyboard Input Device // ------------------------------------------------------------------------------------------------- TouchInputDevice::TouchInputDevice(PlayerSide player, int type) : InputDevice() { mPlayer = player; mTouchXPos = 400; mTouchType = type; } PlayerInputAbs TouchInputDevice::transferInput() { PlayerInputAbs input = PlayerInputAbs(); // Get the primary touch device SDL_TouchID device = SDL_GetTouchDevice(0); switch (mTouchType) { // ****************************************************************** // Blobby moves to playerside finger, opponentside is the jumpbutton* // ****************************************************************** case 0: { for (int i = 0; i < SDL_GetNumTouchFingers(device); i++) { SDL_Finger *finger = SDL_GetTouchFinger(device, i); if (finger == NULL) continue; // Check the playerside if (mPlayer == LEFT_PLAYER) { // If finger has a valid blobby position, take it! if (finger->x < 0.6) { mTouchXPos = 200 + finger->x * 800; } // If finger has a valid jump position if (finger->x > 0.7) { input.setJump( true ); } } else { // If finger has a valid blobby position, take it! if (finger->x > 0.4) { mTouchXPos = -200 + finger->x * 800; } // If finger has a valid jump position if (finger->x < 0.3) { input.setJump( true ); } } } const int playerOffset = mPlayer == RIGHT_PLAYER ? 200 : -200; mTouchXPos = mTouchXPos < 201 ? 201 : mTouchXPos; mTouchXPos = mTouchXPos > 600 ? 600 : mTouchXPos; mMarkerX = mTouchXPos + playerOffset; input.setTarget( mMarkerX, mPlayer ); RenderManager::getSingleton().setMouseMarker(mMarkerX); break; } // ********************************************************************************* // *playerside is devided in left/right move button, opponentside is the jumpbutton* // ********************************************************************************* case 1: { for (int i = 0; i < SDL_GetNumTouchFingers(device); i++) { SDL_Finger *finger = SDL_GetTouchFinger(device, i); if (finger == NULL) continue; // Check the playerside if (mPlayer == LEFT_PLAYER) { // If finger is on the playerside if (finger->x < 0.5) { // Left arrow if (finger->x < 0.25) { input.setLeft(true); } else { input.setRight(true); } } // If finger has a valid jump position if (finger->x > 0.7) { input.setJump(true); } } else { // If finger is on the playerside if (finger->x > 0.5) { // Left arrow if (finger->x < 0.75) { input.setLeft( true ); } else { input.setRight( true ); } } // If finger has a valid jump position if (finger->x < 0.3) { input.setJump( true ); } } } break; } default: // ************************************** // *An error happens we do no input here* // ************************************** break; } return input; } blobby-1.0/src/lua/lzio.c000644 001750 001750 00000003131 12313310253 020073 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lzio.c,v 1.35.1.1 2013/04/12 18:48:47 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ #include #define lzio_c #define LUA_CORE #include "lua.h" #include "llimits.h" #include "lmem.h" #include "lstate.h" #include "lzio.h" int luaZ_fill (ZIO *z) { size_t size; lua_State *L = z->L; const char *buff; lua_unlock(L); buff = z->reader(L, z->data, &size); lua_lock(L); if (buff == NULL || size == 0) return EOZ; z->n = size - 1; /* discount char being returned */ z->p = buff; return cast_uchar(*(z->p++)); } void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { z->L = L; z->reader = reader; z->data = data; z->n = 0; z->p = NULL; } /* --------------------------------------------------------------- read --- */ size_t luaZ_read (ZIO *z, void *b, size_t n) { while (n) { size_t m; if (z->n == 0) { /* no bytes in buffer? */ if (luaZ_fill(z) == EOZ) /* try to read more */ return n; /* no more input; return number of missing bytes */ else { z->n++; /* luaZ_fill consumed first byte; put it back */ z->p--; } } m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ memcpy(b, z->p, m); z->n -= m; z->p += m; b = (char *)b + m; n -= m; } return 0; } /* ------------------------------------------------------------------------ */ char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { if (n > buff->buffsize) { if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; luaZ_resizebuffer(L, buff, n); } return buff->buffer; } blobby-1.0/src/lua/lzio.h000644 001750 001750 00000002716 12313310253 020110 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lzio.h,v 1.26.1.1 2013/04/12 18:48:47 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ #ifndef lzio_h #define lzio_h #include "lua.h" #include "lmem.h" #define EOZ (-1) /* end of stream */ typedef struct Zio ZIO; #define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) typedef struct Mbuffer { char *buffer; size_t n; size_t buffsize; } Mbuffer; #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) #define luaZ_buffer(buff) ((buff)->buffer) #define luaZ_sizebuffer(buff) ((buff)->buffsize) #define luaZ_bufflen(buff) ((buff)->n) #define luaZ_resetbuffer(buff) ((buff)->n = 0) #define luaZ_resizebuffer(L, buff, size) \ (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ (buff)->buffsize = size) #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data); LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ /* --------- Private Part ------------------ */ struct Zio { size_t n; /* bytes still unread */ const char *p; /* current position in buffer */ lua_Reader reader; /* reader function */ void* data; /* additional data */ lua_State *L; /* Lua state (for reader) */ }; LUAI_FUNC int luaZ_fill (ZIO *z); #endif blobby-1.0/src/lua/ldo.c000644 001750 001750 00000050417 12313310253 017705 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: ldo.c,v 2.108.1.3 2013/11/08 18:22:50 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ #include #include #include #define ldo_c #define LUA_CORE #include "lua.h" #include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lundump.h" #include "lvm.h" #include "lzio.h" /* ** {====================================================== ** Error-recovery functions ** ======================================================= */ /* ** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By ** default, Lua handles errors with exceptions when compiling as ** C++ code, with _longjmp/_setjmp when asked to use them, and with ** longjmp/setjmp otherwise. */ #if !defined(LUAI_THROW) #if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) \ try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } #define luai_jmpbuf int /* dummy variable */ #elif defined(LUA_USE_ULONGJMP) /* in Unix, try _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #else /* default handling with long jumps */ #define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #endif #endif /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; luai_jmpbuf b; volatile int status; /* error code */ }; static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { case LUA_ERRMEM: { /* memory error? */ setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ break; } case LUA_ERRERR: { setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } default: { setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } } L->top = oldtop + 1; } l_noret luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { /* thread has an error handler? */ L->errorJmp->status = errcode; /* set status */ LUAI_THROW(L, L->errorJmp); /* jump to it */ } else { /* thread has no error handler */ L->status = cast_byte(errcode); /* mark it as dead */ if (G(L)->mainthread->errorJmp) { /* main thread has a handler? */ setobjs2s(L, G(L)->mainthread->top++, L->top - 1); /* copy error obj. */ luaD_throw(G(L)->mainthread, errcode); /* re-throw in main thread */ } else { /* no handler at all; abort */ if (G(L)->panic) { /* panic function? */ lua_unlock(L); G(L)->panic(L); /* call it (last chance to jump out) */ } abort(); } } } int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { unsigned short oldnCcalls = L->nCcalls; struct lua_longjmp lj; lj.status = LUA_OK; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; LUAI_TRY(L, &lj, (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ L->nCcalls = oldnCcalls; return lj.status; } /* }====================================================== */ static void correctstack (lua_State *L, TValue *oldstack) { CallInfo *ci; GCObject *up; L->top = (L->top - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->gch.next) gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; for (ci = L->ci; ci != NULL; ci = ci->previous) { ci->top = (ci->top - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack; if (isLua(ci)) ci->u.l.base = (ci->u.l.base - oldstack) + L->stack; } } /* some space for error handling */ #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) void luaD_reallocstack (lua_State *L, int newsize) { TValue *oldstack = L->stack; int lim = L->stacksize; lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); for (; lim < newsize; lim++) setnilvalue(L->stack + lim); /* erase new segment */ L->stacksize = newsize; L->stack_last = L->stack + newsize - EXTRA_STACK; correctstack(L, oldstack); } void luaD_growstack (lua_State *L, int n) { int size = L->stacksize; if (size > LUAI_MAXSTACK) /* error after extra size? */ luaD_throw(L, LUA_ERRERR); else { int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; int newsize = 2 * size; if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; if (newsize < needed) newsize = needed; if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ luaD_reallocstack(L, ERRORSTACKSIZE); luaG_runerror(L, "stack overflow"); } else luaD_reallocstack(L, newsize); } } static int stackinuse (lua_State *L) { CallInfo *ci; StkId lim = L->top; for (ci = L->ci; ci != NULL; ci = ci->previous) { lua_assert(ci->top <= L->stack_last); if (lim < ci->top) lim = ci->top; } return cast_int(lim - L->stack) + 1; /* part of stack in use */ } void luaD_shrinkstack (lua_State *L) { int inuse = stackinuse(L); int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; if (inuse > LUAI_MAXSTACK || /* handling stack overflow? */ goodsize >= L->stacksize) /* would grow instead of shrink? */ condmovestack(L); /* don't change stack (change only for debugging) */ else luaD_reallocstack(L, goodsize); /* shrink it */ } void luaD_hook (lua_State *L, int event, int line) { lua_Hook hook = L->hook; if (hook && L->allowhook) { CallInfo *ci = L->ci; ptrdiff_t top = savestack(L, L->top); ptrdiff_t ci_top = savestack(L, ci->top); lua_Debug ar; ar.event = event; ar.currentline = line; ar.i_ci = ci; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); L->allowhook = 0; /* cannot call hooks inside a hook */ ci->callstatus |= CIST_HOOKED; lua_unlock(L); (*hook)(L, &ar); lua_lock(L); lua_assert(!L->allowhook); L->allowhook = 1; ci->top = restorestack(L, ci_top); L->top = restorestack(L, top); ci->callstatus &= ~CIST_HOOKED; } } static void callhook (lua_State *L, CallInfo *ci) { int hook = LUA_HOOKCALL; ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ if (isLua(ci->previous) && GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) { ci->callstatus |= CIST_TAIL; hook = LUA_HOOKTAILCALL; } luaD_hook(L, hook, -1); ci->u.l.savedpc--; /* correct 'pc' */ } static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; int nfixargs = p->numparams; StkId base, fixed; lua_assert(actual >= nfixargs); /* move fixed parameters to final position */ luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */ fixed = L->top - actual; /* first fixed argument */ base = L->top; /* final position of first argument */ for (i=0; itop++, fixed + i); setnilvalue(fixed + i); } return base; } static StkId tryfuncTM (lua_State *L, StkId func) { const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; ptrdiff_t funcr = savestack(L, func); if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); /* Open a hole inside the stack at `func' */ for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); incr_top(L); func = restorestack(L, funcr); /* previous call may change stack */ setobj2s(L, func, tm); /* tag method is the new function to be called */ return func; } #define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) /* ** returns true if function has been executed (C function) */ int luaD_precall (lua_State *L, StkId func, int nresults) { lua_CFunction f; CallInfo *ci; int n; /* number of arguments (Lua) or returns (C) */ ptrdiff_t funcr = savestack(L, func); switch (ttype(func)) { case LUA_TLCF: /* light C function */ f = fvalue(func); goto Cfunc; case LUA_TCCL: { /* C closure */ f = clCvalue(func)->f; Cfunc: luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ ci = next_ci(L); /* now 'enter' new function */ ci->nresults = nresults; ci->func = restorestack(L, funcr); ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); ci->callstatus = 0; luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) luaD_hook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*f)(L); /* do the actual call */ lua_lock(L); api_checknelems(L, n); luaD_poscall(L, L->top - n); return 1; } case LUA_TLCL: { /* Lua function: prepare its call */ StkId base; Proto *p = clLvalue(func)->p; n = cast_int(L->top - func) - 1; /* number of real arguments */ luaD_checkstack(L, p->maxstacksize); for (; n < p->numparams; n++) setnilvalue(L->top++); /* complete missing arguments */ if (!p->is_vararg) { func = restorestack(L, funcr); base = func + 1; } else { base = adjust_varargs(L, p, n); func = restorestack(L, funcr); /* previous call can change stack */ } ci = next_ci(L); /* now 'enter' new function */ ci->nresults = nresults; ci->func = func; ci->u.l.base = base; ci->top = base + p->maxstacksize; lua_assert(ci->top <= L->stack_last); ci->u.l.savedpc = p->code; /* starting point */ ci->callstatus = CIST_LUA; L->top = ci->top; luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) callhook(L, ci); return 0; } default: { /* not a function */ func = tryfuncTM(L, func); /* retry with 'function' tag method */ return luaD_precall(L, func, nresults); /* now it must be a function */ } } } int luaD_poscall (lua_State *L, StkId firstResult) { StkId res; int wanted, i; CallInfo *ci = L->ci; if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { if (L->hookmask & LUA_MASKRET) { ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ luaD_hook(L, LUA_HOOKRET, -1); firstResult = restorestack(L, fr); } L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ } res = ci->func; /* res == final position of 1st result */ wanted = ci->nresults; L->ci = ci = ci->previous; /* back to caller */ /* move results to correct place */ for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); while (i-- > 0) setnilvalue(res++); L->top = res; return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ } /* ** Call a function (C or Lua). The function to be called is at *func. ** The arguments are on the stack, right after the function. ** When returns, all the results are on the stack, starting at the original ** function position. */ void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { if (++L->nCcalls >= LUAI_MAXCCALLS) { if (L->nCcalls == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } if (!allowyield) L->nny++; if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ luaV_execute(L); /* call it */ if (!allowyield) L->nny--; L->nCcalls--; } static void finishCcall (lua_State *L) { CallInfo *ci = L->ci; int n; lua_assert(ci->u.c.k != NULL); /* must have a continuation */ lua_assert(L->nny == 0); if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ L->errfunc = ci->u.c.old_errfunc; } /* finish 'lua_callk'/'lua_pcall' */ adjustresults(L, ci->nresults); /* call continuation function */ if (!(ci->callstatus & CIST_STAT)) /* no call status? */ ci->u.c.status = LUA_YIELD; /* 'default' status */ lua_assert(ci->u.c.status != LUA_OK); ci->callstatus = (ci->callstatus & ~(CIST_YPCALL | CIST_STAT)) | CIST_YIELDED; lua_unlock(L); n = (*ci->u.c.k)(L); lua_lock(L); api_checknelems(L, n); /* finish 'luaD_precall' */ luaD_poscall(L, L->top - n); } static void unroll (lua_State *L, void *ud) { UNUSED(ud); for (;;) { if (L->ci == &L->base_ci) /* stack is empty? */ return; /* coroutine finished normally */ if (!isLua(L->ci)) /* C function? */ finishCcall(L); else { /* Lua function */ luaV_finishOp(L); /* finish interrupted instruction */ luaV_execute(L); /* execute down to higher C 'boundary' */ } } } /* ** check whether thread has a suspended protected call */ static CallInfo *findpcall (lua_State *L) { CallInfo *ci; for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ if (ci->callstatus & CIST_YPCALL) return ci; } return NULL; /* no pending pcall */ } static int recover (lua_State *L, int status) { StkId oldtop; CallInfo *ci = findpcall(L); if (ci == NULL) return 0; /* no recovery point */ /* "finish" luaD_pcall */ oldtop = restorestack(L, ci->extra); luaF_close(L, oldtop); seterrorobj(L, status, oldtop); L->ci = ci; L->allowhook = ci->u.c.old_allowhook; L->nny = 0; /* should be zero to be yieldable */ luaD_shrinkstack(L); L->errfunc = ci->u.c.old_errfunc; ci->callstatus |= CIST_STAT; /* call has error status */ ci->u.c.status = status; /* (here it is) */ return 1; /* continue running the coroutine */ } /* ** signal an error in the call to 'resume', not in the execution of the ** coroutine itself. (Such errors should not be handled by any coroutine ** error handler and should not kill the coroutine.) */ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { L->top = firstArg; /* remove args from the stack */ setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ api_incr_top(L); luaD_throw(L, -1); /* jump back to 'lua_resume' */ } /* ** do the work for 'lua_resume' in protected mode */ static void resume (lua_State *L, void *ud) { int nCcalls = L->nCcalls; StkId firstArg = cast(StkId, ud); CallInfo *ci = L->ci; if (nCcalls >= LUAI_MAXCCALLS) resume_error(L, "C stack overflow", firstArg); if (L->status == LUA_OK) { /* may be starting a coroutine */ if (ci != &L->base_ci) /* not in base level? */ resume_error(L, "cannot resume non-suspended coroutine", firstArg); /* coroutine is in base level; start running it */ if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ luaV_execute(L); /* call it */ } else if (L->status != LUA_YIELD) resume_error(L, "cannot resume dead coroutine", firstArg); else { /* resuming from previous yield */ L->status = LUA_OK; ci->func = restorestack(L, ci->extra); if (isLua(ci)) /* yielded inside a hook? */ luaV_execute(L); /* just continue running Lua code */ else { /* 'common' yield */ if (ci->u.c.k != NULL) { /* does it have a continuation? */ int n; ci->u.c.status = LUA_YIELD; /* 'default' status */ ci->callstatus |= CIST_YIELDED; lua_unlock(L); n = (*ci->u.c.k)(L); /* call continuation */ lua_lock(L); api_checknelems(L, n); firstArg = L->top - n; /* yield results come from continuation */ } luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ } unroll(L, NULL); } lua_assert(nCcalls == L->nCcalls); } LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { int status; int oldnny = L->nny; /* save 'nny' */ lua_lock(L); luai_userstateresume(L, nargs); L->nCcalls = (from) ? from->nCcalls + 1 : 1; L->nny = 0; /* allow yields */ api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); status = luaD_rawrunprotected(L, resume, L->top - nargs); if (status == -1) /* error calling 'lua_resume'? */ status = LUA_ERRRUN; else { /* yield or regular error */ while (status != LUA_OK && status != LUA_YIELD) { /* error? */ if (recover(L, status)) /* recover point? */ status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */ else { /* unrecoverable error */ L->status = cast_byte(status); /* mark thread as `dead' */ seterrorobj(L, status, L->top); L->ci->top = L->top; break; } } lua_assert(status == L->status); } L->nny = oldnny; /* restore 'nny' */ L->nCcalls--; lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); lua_unlock(L); return status; } LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { CallInfo *ci = L->ci; luai_userstateyield(L, nresults); lua_lock(L); api_checknelems(L, nresults); if (L->nny > 0) { if (L != G(L)->mainthread) luaG_runerror(L, "attempt to yield across a C-call boundary"); else luaG_runerror(L, "attempt to yield from outside a coroutine"); } L->status = LUA_YIELD; ci->extra = savestack(L, ci->func); /* save current 'func' */ if (isLua(ci)) { /* inside a hook? */ api_check(L, k == NULL, "hooks cannot continue after yielding"); } else { if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ ci->u.c.ctx = ctx; /* save context */ ci->func = L->top - nresults - 1; /* protect stack below results */ luaD_throw(L, LUA_YIELD); } lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ lua_unlock(L); return 0; /* return to 'luaD_hook' */ } int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; CallInfo *old_ci = L->ci; lu_byte old_allowhooks = L->allowhook; unsigned short old_nny = L->nny; ptrdiff_t old_errfunc = L->errfunc; L->errfunc = ef; status = luaD_rawrunprotected(L, func, u); if (status != LUA_OK) { /* an error occurred? */ StkId oldtop = restorestack(L, old_top); luaF_close(L, oldtop); /* close possible pending closures */ seterrorobj(L, status, oldtop); L->ci = old_ci; L->allowhook = old_allowhooks; L->nny = old_nny; luaD_shrinkstack(L); } L->errfunc = old_errfunc; return status; } /* ** Execute a protected parser. */ struct SParser { /* data to `f_parser' */ ZIO *z; Mbuffer buff; /* dynamic structure used by the scanner */ Dyndata dyd; /* dynamic structures used by the parser */ const char *mode; const char *name; }; static void checkmode (lua_State *L, const char *mode, const char *x) { if (mode && strchr(mode, x[0]) == NULL) { luaO_pushfstring(L, "attempt to load a %s chunk (mode is " LUA_QS ")", x, mode); luaD_throw(L, LUA_ERRSYNTAX); } } static void f_parser (lua_State *L, void *ud) { int i; Closure *cl; struct SParser *p = cast(struct SParser *, ud); int c = zgetc(p->z); /* read first character */ if (c == LUA_SIGNATURE[0]) { checkmode(L, p->mode, "binary"); cl = luaU_undump(L, p->z, &p->buff, p->name); } else { checkmode(L, p->mode, "text"); cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); } lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */ UpVal *up = luaF_newupval(L); cl->l.upvals[i] = up; luaC_objbarrier(L, cl, up); } } int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode) { struct SParser p; int status; L->nny++; /* cannot yield during parsing */ p.z = z; p.name = name; p.mode = mode; p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; p.dyd.label.arr = NULL; p.dyd.label.size = 0; luaZ_initbuffer(L, &p.buff); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); luaZ_freebuffer(L, &p.buff); luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); L->nny--; return status; } blobby-1.0/src/input_device/JoystickPool.cpp000644 001750 001750 00000004200 12313310253 024002 0ustar00danielknobedanielknobe000000 000000 #include "JoystickPool.h" #include #include #include #include #include // Joystick Pool JoystickPool* JoystickPool::mSingleton = 0; //static JoystickPool& JoystickPool::getSingleton() { if (mSingleton == 0) mSingleton = new JoystickPool(); return *mSingleton; } SDL_Joystick* JoystickPool::getJoystick(int id) { SDL_Joystick* joy = mJoyMap[id]; if (!joy) std::cerr << "Warning: could not find joystick number " << id << "!" << std::endl; return joy; } void JoystickPool::probeJoysticks() { int numJoysticks = SDL_NumJoysticks(); SDL_Joystick* lastjoy; for(int i = 0; i < numJoysticks; i++) { lastjoy = SDL_JoystickOpen(i); if (lastjoy == NULL) continue; mJoyMap[SDL_JoystickInstanceID(lastjoy)] = lastjoy; } } void JoystickPool::closeJoysticks() { for (JoyMap::iterator iter = mJoyMap.begin(); iter != mJoyMap.end(); ++iter) { SDL_JoystickClose((*iter).second); } } // Joystick Action JoystickAction::JoystickAction(std::string string) { type = AXIS; number = 0; joy = 0; joyid = 0; try { const char* str = string.c_str(); if (std::strstr(str, "button")) { type = BUTTON; if (sscanf(str, "joy_%d_button_%d", &joyid, &number) < 2) throw string; } else if (std::strstr(str, "axis")) { if (sscanf(str, "joy_%d_axis_%d", &joyid, &number) < 2) throw string; } joy = JoystickPool::getSingleton().getJoystick(joyid); } catch (const std::string& e) { std::cerr << "Parse error in joystick config: " << e << std::endl; } } JoystickAction::JoystickAction(const JoystickAction& action) { type = action.type; joy = JoystickPool::getSingleton().getJoystick(action.joyid); joyid = action.joyid; number = action.number; } JoystickAction::~JoystickAction() { } std::string JoystickAction::toString() { const char* typestr = "unknown"; if (type == AXIS) typestr = "axis"; if (type == BUTTON) typestr = "button"; std::stringstream buf; buf << "joy_" << joyid << "_" << typestr << "_" << number; return buf.str(); } blobby-1.0/data/scripts/old/000755 001750 001750 00000000000 12313310254 020563 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/lua/lundump.c000644 001750 001750 00000012767 12313310253 020621 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lundump.c,v 2.22.1.1 2013/04/12 18:48:47 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ #include #define lundump_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" #include "lstring.h" #include "lundump.h" #include "lzio.h" typedef struct { lua_State* L; ZIO* Z; Mbuffer* b; const char* name; } LoadState; static l_noret error(LoadState* S, const char* why) { luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why); luaD_throw(S->L,LUA_ERRSYNTAX); } #define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) #define LoadByte(S) (lu_byte)LoadChar(S) #define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) #define LoadVector(S,b,n,size) LoadMem(S,b,n,size) #if !defined(luai_verifycode) #define luai_verifycode(L,b,f) /* empty */ #endif static void LoadBlock(LoadState* S, void* b, size_t size) { if (luaZ_read(S->Z,b,size)!=0) error(S,"truncated"); } static int LoadChar(LoadState* S) { char x; LoadVar(S,x); return x; } static int LoadInt(LoadState* S) { int x; LoadVar(S,x); if (x<0) error(S,"corrupted"); return x; } static lua_Number LoadNumber(LoadState* S) { lua_Number x; LoadVar(S,x); return x; } static TString* LoadString(LoadState* S) { size_t size; LoadVar(S,size); if (size==0) return NULL; else { char* s=luaZ_openspace(S->L,S->b,size); LoadBlock(S,s,size*sizeof(char)); return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ } } static void LoadCode(LoadState* S, Proto* f) { int n=LoadInt(S); f->code=luaM_newvector(S->L,n,Instruction); f->sizecode=n; LoadVector(S,f->code,n,sizeof(Instruction)); } static void LoadFunction(LoadState* S, Proto* f); static void LoadConstants(LoadState* S, Proto* f) { int i,n; n=LoadInt(S); f->k=luaM_newvector(S->L,n,TValue); f->sizek=n; for (i=0; ik[i]); for (i=0; ik[i]; int t=LoadChar(S); switch (t) { case LUA_TNIL: setnilvalue(o); break; case LUA_TBOOLEAN: setbvalue(o,LoadChar(S)); break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); break; case LUA_TSTRING: setsvalue2n(S->L,o,LoadString(S)); break; default: lua_assert(0); } } n=LoadInt(S); f->p=luaM_newvector(S->L,n,Proto*); f->sizep=n; for (i=0; ip[i]=NULL; for (i=0; ip[i]=luaF_newproto(S->L); LoadFunction(S,f->p[i]); } } static void LoadUpvalues(LoadState* S, Proto* f) { int i,n; n=LoadInt(S); f->upvalues=luaM_newvector(S->L,n,Upvaldesc); f->sizeupvalues=n; for (i=0; iupvalues[i].name=NULL; for (i=0; iupvalues[i].instack=LoadByte(S); f->upvalues[i].idx=LoadByte(S); } } static void LoadDebug(LoadState* S, Proto* f) { int i,n; f->source=LoadString(S); n=LoadInt(S); f->lineinfo=luaM_newvector(S->L,n,int); f->sizelineinfo=n; LoadVector(S,f->lineinfo,n,sizeof(int)); n=LoadInt(S); f->locvars=luaM_newvector(S->L,n,LocVar); f->sizelocvars=n; for (i=0; ilocvars[i].varname=NULL; for (i=0; ilocvars[i].varname=LoadString(S); f->locvars[i].startpc=LoadInt(S); f->locvars[i].endpc=LoadInt(S); } n=LoadInt(S); for (i=0; iupvalues[i].name=LoadString(S); } static void LoadFunction(LoadState* S, Proto* f) { f->linedefined=LoadInt(S); f->lastlinedefined=LoadInt(S); f->numparams=LoadByte(S); f->is_vararg=LoadByte(S); f->maxstacksize=LoadByte(S); LoadCode(S,f); LoadConstants(S,f); LoadUpvalues(S,f); LoadDebug(S,f); } /* the code below must be consistent with the code in luaU_header */ #define N0 LUAC_HEADERSIZE #define N1 (sizeof(LUA_SIGNATURE)-sizeof(char)) #define N2 N1+2 #define N3 N2+6 static void LoadHeader(LoadState* S) { lu_byte h[LUAC_HEADERSIZE]; lu_byte s[LUAC_HEADERSIZE]; luaU_header(h); memcpy(s,h,sizeof(char)); /* first char already read */ LoadBlock(S,s+sizeof(char),LUAC_HEADERSIZE-sizeof(char)); if (memcmp(h,s,N0)==0) return; if (memcmp(h,s,N1)!=0) error(S,"not a"); if (memcmp(h,s,N2)!=0) error(S,"version mismatch in"); if (memcmp(h,s,N3)!=0) error(S,"incompatible"); else error(S,"corrupted"); } /* ** load precompiled chunk */ Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) { LoadState S; Closure* cl; if (*name=='@' || *name=='=') S.name=name+1; else if (*name==LUA_SIGNATURE[0]) S.name="binary string"; else S.name=name; S.L=L; S.Z=Z; S.b=buff; LoadHeader(&S); cl=luaF_newLclosure(L,1); setclLvalue(L,L->top,cl); incr_top(L); cl->l.p=luaF_newproto(L); LoadFunction(&S,cl->l.p); if (cl->l.p->sizeupvalues != 1) { Proto* p=cl->l.p; cl=luaF_newLclosure(L,cl->l.p->sizeupvalues); cl->l.p=p; setclLvalue(L,L->top-1,cl); } luai_verifycode(L,buff,cl->l.p); return cl; } #define MYINT(s) (s[0]-'0') #define VERSION MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR) #define FORMAT 0 /* this is the official format */ /* * make header for precompiled chunks * if you change the code below be sure to update LoadHeader and FORMAT above * and LUAC_HEADERSIZE in lundump.h */ void luaU_header (lu_byte* h) { int x=1; memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-sizeof(char)); h+=sizeof(LUA_SIGNATURE)-sizeof(char); *h++=cast_byte(VERSION); *h++=cast_byte(FORMAT); *h++=cast_byte(*(char*)&x); /* endianness */ *h++=cast_byte(sizeof(int)); *h++=cast_byte(sizeof(size_t)); *h++=cast_byte(sizeof(Instruction)); *h++=cast_byte(sizeof(lua_Number)); *h++=cast_byte(((lua_Number)0.5)==0); /* is lua_Number integral? */ memcpy(h,LUAC_TAIL,sizeof(LUAC_TAIL)-sizeof(char)); } blobby-1.0/data/gfx/font23.bmp000644 001750 001750 00000003370 12313310254 020720 0ustar00danielknobedanielknobe000000 000000 BM6(  G/CI  $%g "V DD--##S%%F/2!"_. VV==55~ //>>%&uG KK|ccJJ C->>BB**i '!!+wxCC EETTII,,Vaa5BBZZ^^EE 10:yw0/d&&XKKYYJJCCy::bWU4..BBGG..l__ 21?eb,+h..2277EFF{@@ ] |xp>:.+*$$&& YY MJkQG%$i2!BB99 Q 'g\81EX&&>TT  g`~n@0j"y (ZZ22 ?#v]I,))?ZYi]~gN6 [Z-, >#2spT9e##AYV  q[iV1* P _]A<=F8fusG= 6@=ivq?9-*oܐ]V "{rUMjTqq*][}F?|~D rR`\ blobby-1.0/data/scripts/old/hyp011.lua000644 001750 001750 00000026752 12313310254 022324 0ustar00danielknobedanielknobe000000 000000 g=0.28 pg=0.88 v0=14.5 v_p=4.5 pj=0.44 r1=31.5 p0=0 p1=0.5 p2=1 h=31.5+19+25 estt=0 nettime=0 touch=0 est=0 p=0.4 esto1=10 esto2=10 esto3=10 function yb(y,vy,t) return y+(vy-g/10)*t-1/2*g*t^2 end function move(x) if (posx()2.26) then right() elseif (posx()>x) and (math.abs(posx()-x)>2.26) then left() end end function tb(y,vy,height,typ) local sgn=0 if (typ==1) then sgn=-1 else sgn=1 end if vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g<0 then return -1 else return -1/10+vy/g+sgn*math.sqrt( vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g ) end end function time(t) return 1/5*math.ceil(5*t) end function pos(x) local x1,x2 x1=4.5*math.ceil((1/4.5)*x) x2=4.5*math.floor((1/4.5)*x) if (x1<0) or (x2<0) then return 0 else if (math.abs(x1-x)146) then return (v1p/0.88-1/2+math.sqrt((v1p/0.88-1/2)^2-(144.5-y1p)/0.44)) else return 0 end end function time(t) return 1/5*math.ceil(5*t) end -- function collide(x,y,vx,vy,objx,objy,r2) local t1=time(math.max(tb(y,vy,objy-(r1+r2),1)-0.2,0)) local t2=time(tb(y,vy,objy+(r1+r2),1)+0.2) local t3=time(math.max(tb(y,vy,objy+(r1+r2),2)-0.2,0)) local t4=time(tb(y,vy,objy-(r1+r2),2)+0.2) local t=-1 if (t1150) then t=-1 end return t end function estimate(x,y,vx,vy,height,typ) local collision=1 local tw,tn,ts=0,0,0 local tr,xr,yr,vxr,vyr,n=0,0,0,0,0,0 while(collision==1) do ts=collide(x,y,vx,vy,400,316,7) if (vx>0) then tw=time((768.5-x)/vx) tn=time((361.5-x)/vx) else tw=time((31.5-x)/vx) tn=time((438.5-x)/vx) end local th=time(tb(y,vy,height,typ)) local t=10000 if ((ts>0) and (ts0) and (tn0) and (twt) then if (t==ts) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vy=vy-g*t xr=x yr=y vxr=0 vyr=0 n=1 collision=0 elseif ((t==tn) or (t==tw)) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vx=-vx vy=vy-g*t collision=1 end else tr=tr+th vxr=vx vyr=vy-g*th xr=x+vx*th yr=yb(y,vy,th) collision=0 end end if (tr<0) then return -1,-1,-1,-1,-1,-1 else return xr,yr,vxr,vyr,tr,n end end function impact(x,y,vx,vy,xpos,ypos,targety,jump,move) local x1,y1,vx1,vy1=0,0,0,0 local x2,y2,vx2,vy2,t2,nn=0,0,0,0,0,0 local xpos1=xpos local ypos1=ypos for t=0,20,0.2 do if (jump==1) then ypos1=yp(tp(ypos)+t) end x1=x+vx*t if (x1<31.5) then x1=2*31.5-x1 end if (x1>368.5) then x1=2*368.5-x1 end y1=yb(y,vy,t) if ((xpos1-x1)^2+(ypos1+19-y1)^2<(31.5+25)^2) then local dx=x1-xpos1 local dy=y1-(ypos1+19) local l=math.sqrt(dx^2+dy^2) vx1=dx/l vy1=dy/l x1=x1+vx1*3 y1=y1+vy1*3 vy1=vy1*13.125 vx1=vx1*13.125 x2,y2,vx2,vy2,t2,nn=estimate(x1,y1,vx1,vy1,targety,2) break end end return x2,y2,x1,y1,vx1,vy1 end function lob() if (math.abs(est-esto2)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 -- debug(-10) esto2=est imp=0 x1=0 t=30 while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5730) and (math.abs(posx()-x1f)/4.50) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f break end if (impfimp) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t end if (imp>740) then break end end if (t>12) then t=t-6 else t=t-4 end end t2=t2+1 end t2=t2-1 if (x1>0) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est) --p=0.5 end end function attack() if (math.abs(est-esto1)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 h2=900 -- debug(-10) esto1=est imp=0 x1=0 t=30 while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5400) and (math.abs(posx()-x1f)/4.5+10) and (x1f<360) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f xat=xaf yat=yaf vxat=vxaf vyat=vyaf break end end h2t=yb(yat,vyat,(400-xat)/vxat) if (h2t316+31.5+10) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t xa=xat ya=yat vxa=vxat vya=vyat end h2=yb(ya,vya,(400-xa)/vxa) if (h2>316+31.5+10) and (h2<316+31.5+45) then break end end if (t>12) then t=t-6 else t=t-4 end end t2=t2+1 end t2=t2-1 if (x1>0) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est) --p=0.9 end end function netp() if (math.abs(est-esto3)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 -- debug(-10) esto3=est imp=500 x1=0 for t=33,0,-3 do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,nn=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5380) and (math.abs(posx()-x1f)/4.50) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f break end end if (impt0) and (est<368.5) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est-4.5) end end function posplay() if (math.abs(est-esto3)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 -- debug(-10) esto3=est imp=500 x1=0 for t=33,0,-3 do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,nn=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5280) and (impf<340) and (math.abs(posx()-x1f)/4.50) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f break end end if (math.abs(impt-310)0) and (est<368.5) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est) end end function OnOpponentServe() y1p=144.5 if (math.abs(pos(posx())-posx())>1) then move(400) else move(200) end valid=1 nettime=0 phase=0 end function OnServe(ballready) nettime=0 y1p=144.5 phase=0 est=700 if (math.abs(pos(posx())-posx())>1) then move(400) else if (math.abs(posx()-180)<2) then jump() else move(180) end end valid=1 end function OnGame() yp2=y1p y1p=oppy() vp=y1p-yp2 esttold=estt netold=net toucho=touch touch=touches() if (touch431.5) or (est<368.5)) then nettime=10 phase=4 elseif (phase==4) and (nettime>0) then nettime=nettime-1 else if (est>431.5) then phase=3 elseif (est<431.5) and (est>368.5) then phase=2 else phase=1 end end if (math.sqrt((ballx()-400)^2+(bally()-316)^2)<(31.5+7)) and (math.sqrt((bspeedx())^2+(bspeedy())^2)<2) then phase=5 end --1 Player --2 Ball -- debug(0) -- debug(est) -- debug(imp) -- debug(t2) -- -- if (est<(400-31.5)) then -- if (p<1) then netp() -- else lob() -- end -- elseif (est<400-22) and (est>400-31.5) then -- move (250) -- elseif (est<400-10) and (est>400-22) then -- move(200) -- elseif (est<400) and (est>400-10) then -- move(180) -- else -- move(100) -- end if (phase==3) then move(100) elseif (phase==1) then if (p<0.4) then attack() elseif (p>=0.4) and (p<0.7) then lob() else if (touches()==0) then posplay() elseif (touches()==1) then netp() else attack() end end elseif (phase==2) then if (tnet<=tp(393)+1) or (nettime>0) then jump() end if (math.abs(posx()-360)/4.5-10<=tnet) then left() else right() end elseif (phase==4) then right() jump() elseif (phase==5) then if (posx()>300) then jump() end right() end end blobby-1.0/data/gfx/font31.bmp000644 001750 001750 00000003370 12313310254 020717 0ustar00danielknobedanielknobe000000 000000 BM6( :<:KMKcfbz~z OVO+.+^i^}}KRKaraZiZmmg}g190kh̜nm@Q@xw֖|zPmP#."}|癈҇[[6Q7   Ҍ勆eeFwF"7#  }{yymmTU3h4  ,eb~kkOP\^@B$O&3][kkUU  yzNQ15*QLJLI87=`>kp4;j% )p(=:+)%%`cW](J1/)$M*=,vz?H) &** 3 EoIpy(7v& ,)  akUa*X# ,) lxAQ% AO($ y.E5q1F $4.{-84E:WEq'@$ <$cbRQ20(Ot_l>0 C)rpLNTdm,MJ <_>?@@@@\n'Z' 틊??pq n11[1119Q@\@\||1x[>?@V \qk|M>?p\@q@YڔMMd1'?닋?@@ggg1? [2?(T((@1;0w//Lޔ''[Qp((q\k/.K.L;M111'?(p(@\@.K.ڔm|1Z[>(0mm%;01|?q\@\0gϓLL1????q͇./%..ӓL1d1'?????q@ч.ΓΓL??@\@bΓԇΓK싋??lqq̓wғaa˒ϓ01 >q@5wԓaaaϓ10>$@qq,b1101'>>>>??@{{aaaa.10L0'?(X@\zϒ{a1L0 $Ka..0LL0'?p\@cÈГwL|[99@\gJJaΒLL0ݔ999%I_``JvaaaawL1[2[9>?(!@a`aa,a0L19[?eþvaaL0LLNÑu+vacwL9Qq(^vJaK.0''''[@\q+PKLg111 \+^H5.ϓ:M|1 ~Gϓ-ߔdk1Zp\n=Gva,aZ[((tOG`Ja{/Ymd[[++vÑ-a:Mx'OO=ttJÑ,bwMߔ|h=Ja::L0ݔOG=`u`b%ccccmE&sOOOOGPHPIeb%LhHHvÁE**E}HPPEsEEE H_WasE**E=t**DEO=P_GBBBBCEO^=H{EBrrrBrBBBB* GvbrA rrrrrBBOG HB #include #include #include "raknet/PacketEnumerations.h" #include "raknet/NetworkTypes.h" #include "raknet/BitStream.h" #include "BlobbyDebug.h" enum MessageType { ID_GENERIC_MESSAGE = ID_RESERVED9 + 1, ID_INPUT_UPDATE, ID_PHYSIC_UPDATE, ID_WIN_NOTIFICATION, ID_OPPONENT_DISCONNECTED, ID_BALL_RESET, ID_COLLISION, ID_CURRENTLY_UNUSED_2, // was ID_BALL_PLAYER_COLLISION, now handled via ID_COLLISION ID_GAME_READY, ID_ENTER_SERVER, ID_PAUSE, ID_UNPAUSE, ID_BLOBBY_SERVER_PRESENT, ID_VERSION_MISMATCH, ID_CURRENTLY_UNUSED, // this value is to ensure network protocol compatibility between 0.9c and 1.0 ID_REPLAY, ID_CHAT_MESSAGE, ID_UPDATE_SCORE, // no longer used, as ID_PHYSIC_UPDATE also contains the score information, and ID_BALL_RESET also works as a sync point for clocks ID_RULES_CHECKSUM, ID_RULES, ID_SERVER_STATUS, ID_CHALLENGE }; // General Information: // Because the client may choose their side and the server rotates // everything if necessary, PlayerSide informations may not be // correct on all peers. When the server sends a side information // to a client, the information has to be converted into the view // of the client. // ID_INPUT_UPDATE = 63: // Description: // This packet is sent from client to server every frame. // It contains the current input state as three booleans. // Structure: // ID_INPUT_UPDATE // ID_TIMESTAMP // timestamp (int) // left keypress (bool) // right keypress (bool) // up keypress (bool) // // ID_PHYSIC_UPDATE: // Description: // The server sends this information of the current physics state // to all clients every frame. Local physic states will always // be overwritten. // Structure: // ID_PHYSIC_UPDATE // ID_TIMESTAMP // timestamp (int) // packet_number (unsigned char) // Physic data (analysed by PhysicWorld) // // ID_WIN_NOTIFICATION // Description: // Message sent from server to all clients when a player // won the game. The appended enum tells the client which // player won. // Structure: // ID_WIN_NOTIFICATION // winning player (PlayerSide) // // ID_BALL_RESET // Description: // Message sent from server to all clients when the ball // is reset to the starting position. It includes an information // about the current point state and is used to synchronize // the clocks. // Structure: // ID_BALL_RESET // serving player (PlayerSide) // left score (int) // right score (int) // time (int) // // ID_COLLISION // Description: // Message sent from server to all clients when the ball // hits a player or the ground. It is the only valid reason for a player // collision sound. The event attribute contains the DuelMatch Event that // caused the packet to be sent, intensity contains the hit intensity (only valid for player collisions) // Structure: // ID_BALL_PLAYER_COLLISION // event (int) // intensity (float) // // ID_GAME_READY // Description: // Message sent from server to client when all clients are // ready. The input is enabled after this message on the client. // The attribute opponent name carrys the name of the connected // opponent. // Structure: // ID_GAME_READY // gamespeed (int) // opponent name (char[16]) // opponent color (int) // // ID_ENTER_SERVER // Description: // Message sent from client to server after connecting to it. // The side attribute tells the server on which side the client // wants to play. The name attribute reports to players name, // truncated to 16 characters. Color is the network color. // Structure: // ID_ENTER_SERVER // side (PlayerSide) // name (char[16]) // color (int) // // ID_PAUSE // Description: // Sent from client to server, this message can be seen as a request // to pause the game. From server to client it is an acknowledgement // of the pause and request demand to display an appropriate dialog. // Structure: // ID_PAUSE // // ID_UNPAUSE // Description: // As ID_PAUSE, this packets is an acknowledgement if sent from a client // and a request if sent from the server. // Structure: // ID_UNPAUSE // // ID_OPPONENTED_DISCONNECTED // Description: // Sent from server to client when an opponent left the game // Structure: // ID_OPPONENT_DISCONNECTED // // ID_BLOBBY_SERVER_PRESENT // Description: // Sent from client to probe a server and from server to client // as answer to the same packet. // Sent with version number since alpha 7 in the first case. // Structure: // ID_BLOBBY_SERVER_PRESENT // major (int) // minor (int) // // ID_VERSION_MISMATCH // Description: // Sent from server to client if the version number // differes from the one of the server. // Structure: // ID_VERSION_MISMATCH // server_major (int) // server_minor (int) // // ID_REPLAY // Description: // Sent from client to server to request a replay // Sent from server to client to transmitt the replay // Structure: // ID_REPLAY // size (int) // data // // ID_RULES_CHECKSUM // Description: // Sent from server to client to tell rules file checksum // Client should send ID_RULES after receiving ID_RULES_CHECKSUM // to tell server if he needs rules file transmitting // Structure: // ID_RULES_CHECKSUM // checksum (int) // // ID_RULES // Description: // Sent from client to server to request a rules file // Sent from server to client to transmit the rules file // Game is starting only after transmitting a rules file // Structure (from client to server): // ID_RULES // needRules (bool) // Structure (from server to client): // ID_RULES // size (int) // data // // ID_SERVER_STATUS // Description: // Sent from server to waiting clients with information about the // current server status // Structure: // ID_SERVER_STATUS // vector playernames // // ID_CHALLENGE // Description: // Sent when the client wants to start a game. If desired opponent is set, the server looks for that // opponent and matches these players. // Sent from the server when another player wants to start a game with this client. // Structure: // ID_CHALLENGE // PlayerID opponent // class IUserConfigReader; struct ServerInfo : public ObjectCounter { // read server info from a bit stream, additionally, the server address and port are needed ServerInfo(RakNet::BitStream& stream, const char* ip, uint16_t port); // read server info from a user config object ServerInfo(const IUserConfigReader& config); ServerInfo(const std::string& playername); void writeToBitstream(RakNet::BitStream& stream); /// \todo maybe we should define ServerInfo a little bit more /// as e.g., hostname can be left uninitialised on server /// we combine to functionsalities here: server information and server addresses. int activegames; int gamespeed; uint16_t port; char hostname[64]; char name[32]; int waitingplayers; char description[192]; char rulestitle[32]; char rulesauthor[32]; static const size_t BLOBBY_SERVER_PRESENT_PACKET_SIZE; }; bool operator == (const ServerInfo& lval, const ServerInfo& rval); std::ostream& operator<<(std::ostream& stream, const ServerInfo& val); blobby-1.0/src/server/DedicatedServer.h000644 001750 001750 00000006344 12313310252 022715 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include #include #include #include "NetworkPlayer.h" #include "NetworkMessage.h" class RakServer; // function for logging to replacing syslog enum { LOG_ERR, LOG_NOTICE, LOG_DEBUG }; /*! \class DedicatedServer \brief manages a blobby server. \details Lets the players connect, matches games and processes them. */ class DedicatedServer { public: /// create a dedicated server with the data specified in info, using the rules from rulesfile, allowing max_clients /// simulatanious connections /// \todo Maybe two classes for server info: lokal server info for an server, and remote for data sent to client DedicatedServer(const ServerInfo& info, const std::string& rulefile, int max_clients); ~DedicatedServer(); // server processing void processPackets(); void updateGames(); void updateLobby(); // status queries bool hasActiveGame() const; int getActiveGamesCount() const; int getWaitingPlayers() const; int getConnectedClients() const; // debug functions void printAllPlayers(std::ostream& stream) const; void printAllGames(std::ostream& stream) const; // server settings void allowNewPlayers( bool allow ); private: // packet handling functions / utility functions void processBlobbyServerPresent( const packet_ptr& packet ); // creates a new game with those players // does not add the game to the active game list boost::shared_ptr createGame(boost::shared_ptr first, boost::shared_ptr second); // broadcasts the current server status to all waiting clients void broadcastServerStatus(); // member variables // number of currently connected clients /// \todo is this already counted by raknet? unsigned int mConnectedClients; // raknet server used boost::scoped_ptr mServer; // path to rules file std::string mRulesFile; // true, if new players should be accepted bool mAcceptNewPlayers; // server info with server config ServerInfo mServerInfo; // containers for all games and mapping players to their games std::list< boost::shared_ptr > mGameList; std::map< PlayerID, boost::shared_ptr> mPlayerMap; std::map< PlayerID, PlayerID> mGameRequests; }; blobby-1.0/data/gfx/blood.bmp000644 001750 001750 00000002242 12313310254 020701 0ustar00danielknobedanielknobe000000 000000 BM6( l    !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~¼ſÿǿblobby-1.0/data/gfx/font15.bmp000644 001750 001750 00000003370 12313310254 020721 0ustar00danielknobedanielknobe000000 000000 BM6( 9]lF)D%yCGd$J&f+ MV!3#G guFOQ8b"az&Ot05~OJpHG GB-^%dQ5&iI^Q3  wdKʜcj)m>.őgq:CE&nL8uGK)X/ 5$nOU9a4$)4&"l̈qyaP?R0'/3$ 2$#4'%." 2'%+ $( 2)(N:6ڞۦ՚paUuMDtTMgaxs}}sqgehf2)(aOI轳າΠ~spgyϢ溵㿼ԱϭNA@*&$sc`i_\Էėnkpnxvts:22Һܾծ~{-#"-''ϳẸ|{D87ԫ_KK     H??ڶԥ||oo]]kEEtJJlAAnEEh==d<<<22ⳳ譭ԖɆԊуuullRRD;;ܾبڧਨߡퟟ [[blobby-1.0/data/gfx/ball11.bmp000644 001750 001750 00000012066 12313310254 020663 0ustar00danielknobedanielknobe000000 000000 BM66(@@ ~YVY}z}/./pnpgeg;:;lklecdywxighheeljjhggbaaecbedcmlkqqohhfggeXXW "cdb z|zgigegeIJIvwvopoWXW^a_wyxkml ceeegg|}}fgg^__WYZ_`amnoffiVVXzz|NNOppq~~~|||{{{yyyxxxvvvsssooommmkkkjjjhhheeeccc```]]]ZZZTTT@@@$$$ 9k- 'dl--- (|\-EEd l' -D",-- {{!!{ "9("Ed-"j|c,| lX}lHHll|WXX9Ck,--  3w XC" y- -bX3VXVVw4*jCC|HX4>X4ދV{!!{' *Vvu=?X434Xb(-V> UU]VV?V3x4xwV44*X{j-v;UXWߜVVޜ33WXb{ ##TU3??3jk)f)f3X ?3WX-llHHllt?; ?4 H--S::)t?# =>3Wj ---- \ϊS:T; ?VC---sefS 3-eeesS2ssW --SseSsVwx44344XꙎ'-22;# ?33X( H6Sss?3}!j"ds  ??xXb,-UssS ?33*XCu:ssuU?w*!lHg;G͊wWk58-c::ʼnRRRssvVC9Ck9"'-,eRRRRssst 4Cj!" assRRRRv3!b\țPPPQRQQQÉRRssًwXWW*k-\¿RPPQQRssS?> WC9c-PRPQPPPQSw4* +QP]VV?PÑeSuvuUv1QaˊfMN/PRő#tqp/0QQQÉ#pooLQPRf)fKoKKNpQPQK^op/FPS)..noLKoqF.Ko..nKoK1Z..oNoKKpQooIJMpq.Ion.Oo^nnoqo.nKoooKN0poKKn.mpKKopoK.n.noKnnoNnnKpnKn.n..nK.blobby-1.0/data/gfx/sch15.bmp000644 001750 001750 00000030066 12313310254 020532 0ustar00danielknobedanielknobe000000 000000 BM606( 0  333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333blobby-1.0/src/ReplayPlayer.h000644 001750 001750 00000007705 12313310251 020764 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include "Global.h" #include "ReplayDefs.h" #include "PlayerInput.h" #include "BlobbyDebug.h" class DuelMatch; class IReplayLoader; /// \class ReplayPlayer /// \brief Manages playing of replays. /// \details This class is responsible for actually replaying the replays. /// It uses the data the IReplayLoader gets from files and uses them to create a full replay. /// \todo maybe we should rename this class. It might be confused with Player (a blob) and NetworkPlayer /// (a network connection on server). class ReplayPlayer : public ObjectCounter { public: ReplayPlayer(); ~ReplayPlayer(); void load(const std::string& filename); // ----------------------------------------------------------------------------------------- // Replay Attributes // ----------------------------------------------------------------------------------------- std::string getPlayerName(const PlayerSide side) const; Color getBlobColor(const PlayerSide side) const; int getGameSpeed() const; // ----------------------------------------------------------------------------------------- // Status information // ----------------------------------------------------------------------------------------- /// \brief Replaying finished /// \details This reports whether the record is played to the end, so the /// blobbys don't have to stand around bored after an incomplete /// input record. bool endOfFile() const; /// \brief Replay Progress in precent /// \details returns (an estimate for) the replay progress in percent. Depending on /// replay file version, this is either exact or a guess of the system (when we /// don't know how long the replay is). float getPlayProgress() const; /// \brief current replay position /// \details returns the current position in replay in steps. int getReplayPosition() const; /// \brief length of replay /// \details returns the replay length in steps. int getReplayLength() const; // ----------------------------------------------------------------------------------------- // replaying interface // ----------------------------------------------------------------------------------------- /// \brief advances the game one step bool play(DuelMatch* virtual_match); /// \brief Jumps to a position in replay. /// \details Goes to a certain position in replay. Simulates at most 100 steps per call /// to prevent visual lags, so it is possible that this function has to be called /// several times to reach the target. /// \param rep_position target position in number of physic steps. /// \return True, if desired position could be reached. bool gotoPlayingPosition(int rep_position, DuelMatch* virtual_match); private: int mPosition; int mLength; boost::scoped_ptr loader; std::string mPlayerNames[MAX_PLAYERS]; }; blobby-1.0/src/Global.h000644 001750 001750 00000006645 12313310251 017555 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include #include // I hope the GP2X is the only combination of these systems #if defined(__linux__) && defined(__arm__) #define GP2X GP2X #endif #if defined __ANDROID__ || (defined __APPLE__ && !MAC_OS_X) #define __MOBILE__ true #define __DESKTOP__ false #else #define __MOBILE__ false #define __DESKTOP__ true #endif // defined /*! \def DEBUG \brief Enable debugging support \details when this marko is present, Blobby generates some additional debugging code usefull for tracking down bugs. */ const int BLOBBY_PORT = 1234; const int BLOBBY_VERSION_MAJOR = 0; const int BLOBBY_VERSION_MINOR = 103; const char AppTitle[] = "Blobby Volley 2 Version 1.0"; const int BASE_RESOLUTION_X = 800; const int BASE_RESOLUTION_Y = 600; const float ROUND_START_SOUND_VOLUME = 0.2; const float BALL_HIT_PLAYER_SOUND_VOLUME = 0.4; // max. 1 ms additional latency, but much improved performance const int RAKNET_THREAD_SLEEP_TIME = 1; const std::string DEFAULT_RULES_FILE = "default.lua"; enum PlayerSide { NO_PLAYER = -1, LEFT_PLAYER = 0, RIGHT_PLAYER = 1, //LEFT_PLAYER_2 = 2, //RIGHT_PLAYER_2 = 3, MAX_PLAYERS // This is always one more than the highest player enum // and can be used to declare arrays }; enum InputDeviceName { KEYBOARD = 1, MOUSE = 2, JOYSTICK = 3 }; /*! \class Color \brief represents RGB Colours \details This class represents colors as RGB with one byte for each channel. */ struct Color { Color(int red, int green, int blue) : r(red) , g(green) , b(blue) {} /// \sa toInt() Color(unsigned int col) : r(col&0xff) , g((col>>8)&0xff) , b((col>>16)&0xff) { } Color() {} union { struct { Uint8 r; Uint8 g; Uint8 b; }; Uint8 val[3]; }; bool operator == (Color rval) const { return !std::memcmp(val, rval.val, 3); } bool operator != (Color rval) const { return !(*this == rval); } unsigned int toInt() const { int i = 0; i |= r; i |= g << 8; i |= b << 16; return i; } }; struct ExtensionUnsupportedException : public std::exception { std::string extension; ExtensionUnsupportedException(std::string name) : extension(name) {} ~ExtensionUnsupportedException() throw() {} }; struct ScriptException : public std::exception { std::string luaerror; ~ScriptException() throw() {} }; /// we need to define this constant to make it compile with strict c++98 mode #undef M_PI const double M_PI = 3.141592653589793238462643383279; blobby-1.0/src/state/OptionsState.cpp000644 001750 001750 00000102165 12313310253 022460 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "OptionsState.h" /* includes */ #include #include #include "State.h" #include "RenderManager.h" #include "InputManager.h" #include "LocalInputSource.h" #include "SpeedController.h" #include "SoundManager.h" #include "Blood.h" #include "IMGUI.h" #include "TextManager.h" #include "FileSystem.h" /* implementation */ OptionState::OptionState() { mOptionConfig.loadFile("config.xml"); mPlayerOptions[LEFT_PLAYER] = 0; mPlayerOptions[RIGHT_PLAYER] = 0; std::string leftScript = mOptionConfig.getString("left_script_name"); std::string rightScript = mOptionConfig.getString("right_script_name"); mScriptNames = FileSystem::getSingleton().enumerateFiles("scripts", ".lua"); // hack. we cant use something like push_front, though mScriptNames.push_back("Human"); std::swap(mScriptNames[0], mScriptNames[mScriptNames.size() - 1]); for(unsigned int i = 0; i < mScriptNames.size(); ++i) { if (mScriptNames[i] == leftScript) mPlayerOptions[LEFT_PLAYER] = i; if (mScriptNames[i] == rightScript) mPlayerOptions[RIGHT_PLAYER] = i; } if (mOptionConfig.getBool("left_player_human")) mPlayerOptions[LEFT_PLAYER] = 0; if (mOptionConfig.getBool("right_player_human")) mPlayerOptions[RIGHT_PLAYER] = 0; mPlayerName[LEFT_PLAYER] = mOptionConfig.getString("left_player_name"); mPlayerName[RIGHT_PLAYER] = mOptionConfig.getString("right_player_name"); mPlayerNamePosition[RIGHT_PLAYER] = 0; mPlayerNamePosition[LEFT_PLAYER] = 0; mBotStrength[LEFT_PLAYER] = mOptionConfig.getInteger("left_script_strength"); mBotStrength[RIGHT_PLAYER] = mOptionConfig.getInteger("right_script_strength"); } OptionState::~OptionState() { } void OptionState::save() { if (mPlayerOptions[LEFT_PLAYER] == 0) { mOptionConfig.setBool("left_player_human", true); } else { mOptionConfig.setBool("left_player_human", false); mOptionConfig.setString("left_script_name", mScriptNames[mPlayerOptions[LEFT_PLAYER]]); } if (mPlayerOptions[RIGHT_PLAYER] == 0) { mOptionConfig.setBool("right_player_human", true); } else { mOptionConfig.setBool("right_player_human", false); mOptionConfig.setString("right_script_name", mScriptNames[mPlayerOptions[RIGHT_PLAYER]]); } mOptionConfig.setString("left_player_name", mPlayerName[LEFT_PLAYER]); mOptionConfig.setString("right_player_name", mPlayerName[RIGHT_PLAYER]); mOptionConfig.setInteger("left_script_strength", mBotStrength[LEFT_PLAYER]); mOptionConfig.setInteger("right_script_strength", mBotStrength[RIGHT_PLAYER]); mOptionConfig.saveFile("config.xml"); } void OptionState::step_impl() { const int MAX_BOT_DELAY = 25; // 25 frames = 0.33s (gamespeed: normal) IMGUI& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doImage(GEN_ID, Vector2(400.0, 300.0), "background"); imgui.doOverlay(GEN_ID, Vector2(0.0, 0.0), Vector2(800.0, 600.0)); imgui.doEditbox(GEN_ID, Vector2(5.0, 10.0), 15, mPlayerName[LEFT_PLAYER], mPlayerNamePosition[LEFT_PLAYER]); imgui.doEditbox(GEN_ID, Vector2(425.0, 10.0), 15, mPlayerName[RIGHT_PLAYER], mPlayerNamePosition[RIGHT_PLAYER]); imgui.doSelectbox(GEN_ID, Vector2(5.0, 50.0), Vector2(375.0, 300.0), mScriptNames, mPlayerOptions[LEFT_PLAYER]); imgui.doSelectbox(GEN_ID, Vector2(425.0, 50.0), Vector2(795.0, 300.0), mScriptNames, mPlayerOptions[RIGHT_PLAYER]); imgui.doText(GEN_ID, Vector2(270.0, 310.0), TextManager::OP_DIFFICULTY ); float f = 1.f - (float)mBotStrength[0] / MAX_BOT_DELAY; imgui.doScrollbar(GEN_ID, Vector2(15.0, 350.0), f); mBotStrength[0] = static_cast ((1.f-f) * MAX_BOT_DELAY + 0.5f); imgui.doText(GEN_ID, Vector2(235.0, 350.0), f > 0.66 ? TextManager::OP_STRONG : (f > 0.33 ? TextManager::OP_MEDIUM: TextManager::OP_WEAK)); f = 1.f - (float)mBotStrength[1] / MAX_BOT_DELAY; imgui.doScrollbar(GEN_ID, Vector2(440.0, 350.0), f); mBotStrength[1] = static_cast ((1.f - f) * MAX_BOT_DELAY + 0.5f); imgui.doText(GEN_ID, Vector2(660.0, 350.0), f > 0.66 ? TextManager::OP_STRONG : (f > 0.33 ? TextManager::OP_MEDIUM: TextManager::OP_WEAK)); if (imgui.doButton(GEN_ID, Vector2(40.0, 390.0), TextManager::OP_INPUT_OP)) { save(); switchState(new InputOptionsState()); } if (imgui.doButton(GEN_ID, Vector2(40.0, 430.0), TextManager::OP_GFX_OP)) { save(); switchState(new GraphicOptionsState()); } if (imgui.doButton(GEN_ID, Vector2(40.0, 470.0), TextManager::OP_MISC)) { save(); switchState(new MiscOptionsState()); } if (imgui.doButton(GEN_ID, Vector2(224.0, 530.0), TextManager::LBL_OK)) { save(); switchState(new MainMenuState()); } if (imgui.doButton(GEN_ID, Vector2(424.0, 530.0), TextManager::LBL_CANCEL)) { switchState(new MainMenuState()); } } const char* OptionState::getStateName() const { return "OptionState"; } GraphicOptionsState::GraphicOptionsState() { mOptionConfig.loadFile("config.xml"); mFullscreen = mOptionConfig.getBool("fullscreen"); mRenderer = mOptionConfig.getString("device"); mR1 = mOptionConfig.getInteger("left_blobby_color_r"); mG1 = mOptionConfig.getInteger("left_blobby_color_g"); mB1 = mOptionConfig.getInteger("left_blobby_color_b"); mR2 = mOptionConfig.getInteger("right_blobby_color_r"); mG2 = mOptionConfig.getInteger("right_blobby_color_g"); mB2 = mOptionConfig.getInteger("right_blobby_color_b"); mLeftMorphing = mOptionConfig.getBool("left_blobby_oscillate"); mRightMorphing = mOptionConfig.getBool("right_blobby_oscillate"); mShowShadow = mOptionConfig.getBool("show_shadow"); } GraphicOptionsState::~GraphicOptionsState() { } void GraphicOptionsState::save() { #if __DESKTOP__ if ((mOptionConfig.getBool("fullscreen") != mFullscreen) || (mOptionConfig.getString("device") != mRenderer)) { mOptionConfig.setBool("fullscreen", mFullscreen); mOptionConfig.setString("device", mRenderer); if (mRenderer == "OpenGL") RenderManager::createRenderManagerGL2D()->init(800, 600, mFullscreen); else RenderManager::createRenderManagerSDL()->init(800, 600, mFullscreen); RenderManager::getSingleton().setBackground(std::string("backgrounds/") + mOptionConfig.getString("background")); } #endif RenderManager::getSingleton().showShadow(mShowShadow); mOptionConfig.setBool("show_shadow", mShowShadow); mOptionConfig.setInteger("left_blobby_color_r", mR1); mOptionConfig.setInteger("left_blobby_color_g", mG1); mOptionConfig.setInteger("left_blobby_color_b", mB1); mOptionConfig.setInteger("right_blobby_color_r", mR2); mOptionConfig.setInteger("right_blobby_color_g", mG2); mOptionConfig.setInteger("right_blobby_color_b", mB2); mOptionConfig.setBool("left_blobby_oscillate", mLeftMorphing); mOptionConfig.setBool("right_blobby_oscillate", mRightMorphing); mOptionConfig.saveFile("config.xml"); } void GraphicOptionsState::step_impl() { IMGUI& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doImage(GEN_ID, Vector2(400.0, 300.0), "background"); imgui.doOverlay(GEN_ID, Vector2(0.0, 0.0), Vector2(800.0, 600.0)); #if __DESKTOP__ imgui.doText(GEN_ID, Vector2(34.0, 10.0), TextManager::OP_VIDEO); if (imgui.doButton(GEN_ID, Vector2(34.0, 40.0), TextManager::OP_FULLSCREEN)) mFullscreen = true; if (imgui.doButton(GEN_ID, Vector2(34.0, 70.0), TextManager::OP_WINDOW)) mFullscreen = false; if (mFullscreen) imgui.doImage(GEN_ID, Vector2(18.0, 52.0), "gfx/pfeil_rechts.bmp"); else imgui.doImage(GEN_ID, Vector2(18.0, 82.0), "gfx/pfeil_rechts.bmp"); imgui.doText(GEN_ID, Vector2(444.0, 10.0), TextManager::OP_RENDER_DEVICE); if (imgui.doButton(GEN_ID, Vector2(444.0, 40.0), "OpenGL")) mRenderer = "OpenGL"; if (imgui.doButton(GEN_ID, Vector2(444.0, 70.0), "SDL")) mRenderer = "SDL"; if (mRenderer == "OpenGL") imgui.doImage(GEN_ID, Vector2(428.0, 52.0), "gfx/pfeil_rechts.bmp"); else imgui.doImage(GEN_ID, Vector2(428.0, 82.0), "gfx/pfeil_rechts.bmp"); #endif float heightOfElement = 110.0; #if __MOBILE__ heightOfElement = 10.0; #endif imgui.doText(GEN_ID, Vector2(34.0, heightOfElement), TextManager::OP_SHOW_SHADOW); heightOfElement += 30; if (imgui.doButton(GEN_ID, Vector2(72.0, heightOfElement), TextManager::LBL_YES)) mShowShadow = true; if (imgui.doButton(GEN_ID, Vector2(220.0, heightOfElement), TextManager::LBL_NO)) mShowShadow = false; if (mShowShadow) imgui.doImage(GEN_ID, Vector2(54.0, heightOfElement + 13.0), "gfx/pfeil_rechts.bmp"); else imgui.doImage(GEN_ID, Vector2(204.0, heightOfElement + 13.0), "gfx/pfeil_rechts.bmp"); #if __MOBILE__ float standardLineHeight = 50.0; #else float standardLineHeight = 30.0; #endif heightOfElement += standardLineHeight; //Blob colors: imgui.doText(GEN_ID, Vector2(280.0, heightOfElement), TextManager::OP_BLOB_COLORS); heightOfElement += 40.0; float playerColorSettingsHeight = heightOfElement; //left blob: imgui.doText(GEN_ID, Vector2(34.0, heightOfElement), TextManager::OP_LEFT_PLAYER); heightOfElement += standardLineHeight; { imgui.doText(GEN_ID, Vector2(34.0, heightOfElement), TextManager::OP_RED); float r1 = (float)mR1/255; imgui.doScrollbar(GEN_ID, Vector2(160.0, heightOfElement), r1); mR1 = (int)(r1*255); } heightOfElement += standardLineHeight; { imgui.doText(GEN_ID, Vector2(34.0, heightOfElement), TextManager::OP_GREEN); float g1 = (float)mG1/255; imgui.doScrollbar(GEN_ID, Vector2(160.0, heightOfElement), g1); mG1 = (int)(g1*255); } heightOfElement += standardLineHeight; { imgui.doText(GEN_ID, Vector2(34.0, heightOfElement), TextManager::OP_BLUE); float b1 = (float)mB1/255; imgui.doScrollbar(GEN_ID, Vector2(160.0, heightOfElement), b1); mB1 = (int)(b1*255); } imgui.doText(GEN_ID, Vector2(34.0, 360), TextManager::OP_MORPHING); if (imgui.doButton(GEN_ID, Vector2(72.0, 390), TextManager::LBL_YES)) mLeftMorphing = true; if (imgui.doButton(GEN_ID, Vector2(220.0, 390), TextManager::LBL_NO)) mLeftMorphing = false; if (mLeftMorphing) imgui.doImage(GEN_ID, Vector2(54.0, 402.0), "gfx/pfeil_rechts.bmp"); else imgui.doImage(GEN_ID, Vector2(204.0, 402.0), "gfx/pfeil_rechts.bmp"); //draw left blob: { float time = float(SDL_GetTicks()) / 1000.0; Color ourCol = Color(mR1, mG1, mB1); if (mLeftMorphing) ourCol = Color(int((sin(time*2) + 1.0) * 128), int((sin(time*4) + 1.0) * 128), int((sin(time*3) + 1.0) * 128)); imgui.doBlob(GEN_ID, Vector2(110, 500), ourCol); } //right blob: heightOfElement = playerColorSettingsHeight; imgui.doText(GEN_ID, Vector2(434.0, heightOfElement), TextManager::OP_RIGHT_PLAYER); heightOfElement += standardLineHeight; { imgui.doText(GEN_ID, Vector2(434.0, heightOfElement), TextManager::OP_RED); float r2 = (float)mR2/255; imgui.doScrollbar(GEN_ID, Vector2(560.0, heightOfElement), r2); mR2 = (int)(r2*255); } heightOfElement += standardLineHeight; { imgui.doText(GEN_ID, Vector2(434.0, heightOfElement), TextManager::OP_GREEN); float g2 = (float)mG2/255; imgui.doScrollbar(GEN_ID, Vector2(560.0, heightOfElement), g2); mG2 = (int)(g2*255); } heightOfElement += standardLineHeight; { imgui.doText(GEN_ID, Vector2(434.0, heightOfElement), TextManager::OP_BLUE); float b2 = (float)mB2/255; imgui.doScrollbar(GEN_ID, Vector2(560.0, heightOfElement), b2); mB2 = (int)(b2*255); } imgui.doText(GEN_ID, Vector2(434.0, 360), TextManager::OP_MORPHING); if (imgui.doButton(GEN_ID, Vector2(472.0, 390), TextManager::LBL_YES)) mRightMorphing = true; if (imgui.doButton(GEN_ID, Vector2(620.0, 390), TextManager::LBL_NO)) mRightMorphing = false; if (mRightMorphing) imgui.doImage(GEN_ID, Vector2(454.0, 402.0), "gfx/pfeil_rechts.bmp"); else imgui.doImage(GEN_ID, Vector2(604.0, 402.0), "gfx/pfeil_rechts.bmp"); //draw right blob: { float time = float(SDL_GetTicks()) / 1000.0; Color ourCol = Color(mR2, mG2, mB2); if (mRightMorphing) ourCol = Color(int((cos(time*2) + 1.0) * 128), int((cos(time*4) + 1.0) * 128), int((cos(time*3) + 1.0) * 128)); imgui.doBlob(GEN_ID, Vector2(670, 500), ourCol); } if (imgui.doButton(GEN_ID, Vector2(224.0, 530.0), TextManager::LBL_OK)) { save(); switchState(new OptionState()); } if (imgui.doButton(GEN_ID, Vector2(424.0, 530.0), TextManager::LBL_CANCEL)) { switchState(new OptionState()); } } const char* GraphicOptionsState::getStateName() const { return "GraphicOptionsState"; } InputOptionsState::InputOptionsState() { mSetKeyboard = 0; mOptionConfig.loadFile("inputconfig.xml"); //left data: mLeftBlobbyDevice = mOptionConfig.getString("left_blobby_device"); mLeftBlobbyMouseJumpbutton = mOptionConfig.getInteger("left_blobby_mouse_jumpbutton"); mLeftBlobbyKeyboard[IA_LEFT] = mOptionConfig.getString("left_blobby_keyboard_left"); mLeftBlobbyKeyboard[IA_RIGHT] = mOptionConfig.getString("left_blobby_keyboard_right"); mLeftBlobbyKeyboard[IA_JUMP] = mOptionConfig.getString("left_blobby_keyboard_jump"); mLeftBlobbyJoystick[IA_LEFT] = mOptionConfig.getString("left_blobby_joystick_left"); mLeftBlobbyJoystick[IA_RIGHT] = mOptionConfig.getString("left_blobby_joystick_right"); mLeftBlobbyJoystick[IA_JUMP] = mOptionConfig.getString("left_blobby_joystick_jump"); //right data: mRightBlobbyDevice = mOptionConfig.getString("right_blobby_device"); mRightBlobbyMouseJumpbutton = mOptionConfig.getInteger("right_blobby_mouse_jumpbutton"); mRightBlobbyKeyboard[IA_LEFT] = mOptionConfig.getString("right_blobby_keyboard_left"); mRightBlobbyKeyboard[IA_RIGHT] = mOptionConfig.getString("right_blobby_keyboard_right"); mRightBlobbyKeyboard[IA_JUMP] = mOptionConfig.getString("right_blobby_keyboard_jump"); mRightBlobbyJoystick[IA_LEFT] = mOptionConfig.getString("right_blobby_joystick_left"); mRightBlobbyJoystick[IA_RIGHT] = mOptionConfig.getString("right_blobby_joystick_right"); mRightBlobbyJoystick[IA_JUMP] = mOptionConfig.getString("right_blobby_joystick_jump"); //global data: mBlobbyTouchType = mOptionConfig.getInteger("blobby_touch_type"); } InputOptionsState::~InputOptionsState() { } void InputOptionsState::save() { //left data: mOptionConfig.setString("left_blobby_device", mLeftBlobbyDevice); mOptionConfig.setInteger("left_blobby_mouse_jumpbutton", mLeftBlobbyMouseJumpbutton); mOptionConfig.setString("left_blobby_keyboard_left", mLeftBlobbyKeyboard[IA_LEFT]); mOptionConfig.setString("left_blobby_keyboard_right", mLeftBlobbyKeyboard[IA_RIGHT]); mOptionConfig.setString("left_blobby_keyboard_jump", mLeftBlobbyKeyboard[IA_JUMP]); mOptionConfig.setString("left_blobby_joystick_left", mLeftBlobbyJoystick[IA_LEFT]); mOptionConfig.setString("left_blobby_joystick_right", mLeftBlobbyJoystick[IA_RIGHT]); mOptionConfig.setString("left_blobby_joystick_jump", mLeftBlobbyJoystick[IA_JUMP]); //right data: mOptionConfig.setString("right_blobby_device", mRightBlobbyDevice); mOptionConfig.setInteger("right_blobby_mouse_jumpbutton", mRightBlobbyMouseJumpbutton); mOptionConfig.setString("right_blobby_keyboard_left", mRightBlobbyKeyboard[IA_LEFT]); mOptionConfig.setString("right_blobby_keyboard_right", mRightBlobbyKeyboard[IA_RIGHT]); mOptionConfig.setString("right_blobby_keyboard_jump", mRightBlobbyKeyboard[IA_JUMP]); mOptionConfig.setString("right_blobby_joystick_left", mRightBlobbyJoystick[IA_LEFT]); mOptionConfig.setString("right_blobby_joystick_right", mRightBlobbyJoystick[IA_RIGHT]); mOptionConfig.setString("right_blobby_joystick_jump", mRightBlobbyJoystick[IA_JUMP]); //global data: mOptionConfig.setInteger("blobby_touch_type", mBlobbyTouchType); mOptionConfig.saveFile("inputconfig.xml"); } #if __DESKTOP__ void InputOptionsState::step_impl() { IMGUI& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doImage(GEN_ID, Vector2(400.0, 300.0), "background"); imgui.doOverlay(GEN_ID, Vector2(0.0, 0.0), Vector2(800.0, 600.0)); std::string lastActionKey = InputManager::getSingleton()->getLastActionKey(); // left player side: imgui.doText(GEN_ID, Vector2(34.0, 10.0), TextManager::OP_LEFT_PLAYER); if (imgui.doButton(GEN_ID, Vector2(80.0, 60.0), getDeviceName(mLeftBlobbyDevice))) { if (mLeftBlobbyDevice == "mouse") { mLeftBlobbyDevice = "keyboard"; } else if (mLeftBlobbyDevice == "keyboard") { mLeftBlobbyDevice = "joystick"; } else if (mLeftBlobbyDevice == "joystick") { if (mRightBlobbyDevice != "mouse") { mLeftBlobbyDevice = "mouse"; } else { mLeftBlobbyDevice = "keyboard"; } } } //if mouse device is selected: if (mLeftBlobbyDevice == "mouse") { handleMouseInput(0, mLeftBlobbyMouseJumpbutton); } if ((mLeftBlobbyMouseJumpbutton == -2) && (InputManager::getSingleton()->getLastMouseButton() == -1)) mLeftBlobbyMouseJumpbutton = -1; //if keyboard device is selected: if (mLeftBlobbyDevice == "keyboard") { handleKeyboardInput(0, lastActionKey, mLeftBlobbyKeyboard); } //if joystick device is selected: if (mLeftBlobbyDevice == "joystick") { handleJoystickInput(0, mLeftBlobbyJoystick); } //right player side: imgui.doText(GEN_ID, Vector2(434.0, 10.0), TextManager::OP_RIGHT_PLAYER); if (imgui.doButton(GEN_ID, Vector2(480.0, 60.0), getDeviceName(mRightBlobbyDevice))) { if (mRightBlobbyDevice == "mouse") { mRightBlobbyDevice = "keyboard"; } else if (mRightBlobbyDevice == "keyboard") { mRightBlobbyDevice = "joystick"; } else if (mRightBlobbyDevice == "joystick") { if (mLeftBlobbyDevice != "mouse") { mRightBlobbyDevice = "mouse"; } else { mRightBlobbyDevice = "keyboard"; } } } //if mouse device is selected: if (mRightBlobbyDevice == "mouse") { handleMouseInput(400, mRightBlobbyMouseJumpbutton); } if ((mRightBlobbyMouseJumpbutton == -2) && (InputManager::getSingleton()->getLastMouseButton() == -1)) mRightBlobbyMouseJumpbutton = -1; //if keyboard device is selected: if (mRightBlobbyDevice == "keyboard") { handleKeyboardInput(400, lastActionKey, mRightBlobbyKeyboard); } //if joystick device is selected: if (mRightBlobbyDevice == "joystick") { handleJoystickInput(400, mRightBlobbyJoystick); } //check if a capture window is open, to set all widgets inactive: if (mLeftBlobbyKeyboard[IA_LEFT] != "" && mLeftBlobbyKeyboard[IA_RIGHT] != "" && mLeftBlobbyKeyboard[IA_JUMP] != "" && mLeftBlobbyJoystick[IA_LEFT] != "" && mLeftBlobbyJoystick[IA_RIGHT] != "" && mLeftBlobbyJoystick[IA_JUMP] != "" && mLeftBlobbyMouseJumpbutton != -1 && mRightBlobbyKeyboard[IA_LEFT] != "" && mRightBlobbyKeyboard[IA_RIGHT] != "" && mRightBlobbyKeyboard[IA_JUMP] != "" && mRightBlobbyJoystick[IA_LEFT] != "" && mRightBlobbyJoystick[IA_RIGHT] != "" && mRightBlobbyJoystick[IA_JUMP] != "" && mRightBlobbyMouseJumpbutton != -1) { imgui.doCursor(true); imgui.doInactiveMode(false); } else { imgui.doInactiveMode(true); imgui.doCursor(false); } //Capture dialogs: getMouseInput(mLeftBlobbyMouseJumpbutton, TextManager::OP_JUMPING); getKeyboardInput(mLeftBlobbyKeyboard[IA_LEFT], TextManager::OP_MOVING_LEFT, lastActionKey); getKeyboardInput(mLeftBlobbyKeyboard[IA_RIGHT], TextManager::OP_MOVING_RIGHT, lastActionKey); getKeyboardInput(mLeftBlobbyKeyboard[IA_JUMP], TextManager::OP_JUMPING, lastActionKey); getJoystickInput(mLeftBlobbyJoystick[IA_LEFT], TextManager::OP_MOVING_LEFT); getJoystickInput(mLeftBlobbyJoystick[IA_RIGHT], TextManager::OP_MOVING_RIGHT); getJoystickInput(mLeftBlobbyJoystick[IA_JUMP], TextManager::OP_JUMPING); getMouseInput(mRightBlobbyMouseJumpbutton, TextManager::OP_JUMPING); getKeyboardInput(mRightBlobbyKeyboard[IA_LEFT], TextManager::OP_MOVING_LEFT, lastActionKey); getKeyboardInput(mRightBlobbyKeyboard[IA_RIGHT], TextManager::OP_MOVING_RIGHT, lastActionKey); getKeyboardInput(mRightBlobbyKeyboard[IA_JUMP], TextManager::OP_JUMPING, lastActionKey); getJoystickInput(mRightBlobbyJoystick[IA_LEFT], TextManager::OP_MOVING_LEFT); getJoystickInput(mRightBlobbyJoystick[IA_RIGHT], TextManager::OP_MOVING_RIGHT); getJoystickInput(mRightBlobbyJoystick[IA_JUMP], TextManager::OP_JUMPING); if (imgui.doButton(GEN_ID, Vector2(224.0, 530.0), TextManager::LBL_OK)) { save(); switchState(new OptionState()); } if (imgui.doButton(GEN_ID, Vector2(424.0, 530.0), TextManager::LBL_CANCEL)) { switchState(new OptionState()); } } void InputOptionsState::handleKeyboardInput(int base_x, std::string& lastActionKey, std::string input[]) { auto& imgui = IMGUI::getSingleton(); if (imgui.doButton(GEN_ID, Vector2(base_x + 34, 350.0), TextManager::OP_SET_ALL)) mSetKeyboard = base_x + 1; imgui.doText(GEN_ID, Vector2(base_x + 34.0, 120.0), TextManager::OP_LEFT_KEY); if (imgui.doButton(GEN_ID, Vector2(base_x + 50, 150.0), std::string("Key ")+input[IA_LEFT]) || mSetKeyboard == base_x + 1) { lastActionKey = ""; mOldString = input[IA_LEFT]; input[IA_LEFT] = ""; } if (mSetKeyboard == base_x + 1) mSetKeyboard = base_x + 2; if (mSetKeyboard == base_x + 2 && input[IA_LEFT] != "") mSetKeyboard = base_x + 3; imgui.doText(GEN_ID, Vector2(base_x + 34.0, 190.0), TextManager::OP_RIGHT_KEY); if (imgui.doButton(GEN_ID, Vector2(base_x + 50, 220.0), std::string("Key ")+input[IA_RIGHT]) || mSetKeyboard == base_x + 3) { lastActionKey = ""; mOldString = input[IA_RIGHT]; input[IA_RIGHT] = ""; } if (mSetKeyboard == base_x + 3) mSetKeyboard = base_x + 4; if (mSetKeyboard == base_x + 4 && input[IA_RIGHT] != "") mSetKeyboard = base_x + 5; imgui.doText(GEN_ID, Vector2(base_x + 34.0, 260.0), TextManager::OP_JUMP_KEY ); if (imgui.doButton(GEN_ID, Vector2(base_x + 50, 290.0), std::string("Key ")+input[IA_JUMP]) || mSetKeyboard == base_x + 5) { lastActionKey = ""; mOldString = input[IA_JUMP]; input[IA_JUMP] = ""; } if (mSetKeyboard == base_x + 5) mSetKeyboard = base_x + 6; if (mSetKeyboard == base_x + 6 && input[IA_JUMP] != "") mSetKeyboard = 0; } void InputOptionsState::handleJoystickInput(int base_x, std::string input[]) { auto& imgui = IMGUI::getSingleton(); imgui.doText(GEN_ID, Vector2(base_x + 34.0, 120.0), TextManager::OP_LEFT_BUTTON); if (imgui.doButton(GEN_ID, Vector2(base_x + 50, 150.0), input[IA_LEFT])) { mOldString = input[IA_LEFT]; input[IA_LEFT] = ""; } imgui.doText(GEN_ID, Vector2(base_x + 34.0, 190.0), TextManager::OP_RIGHT_BUTTON); if (imgui.doButton(GEN_ID, Vector2(base_x + 50, 220.0), input[IA_RIGHT])) { mOldString = input[IA_RIGHT]; input[IA_RIGHT] = ""; } imgui.doText(GEN_ID, Vector2(base_x + 34.0, 260.0), TextManager::OP_JUMP_BUTTON); if (imgui.doButton(GEN_ID, Vector2(base_x + 50, 290.0), input[IA_JUMP])) { mOldString = input[IA_JUMP]; input[IA_JUMP] = ""; } } void InputOptionsState::handleMouseInput(int base_x, int& input) { auto& imgui = IMGUI::getSingleton(); imgui.doText(GEN_ID, Vector2(base_x + 34.0, 120.0), TextManager::OP_JUMP_BUTTON); std::ostringstream text; if (input >= 0) text << "Button " << input; else text << "Button "; if (imgui.doButton(GEN_ID, Vector2(base_x + 50, 150.0), text.str())) { mOldInteger = input; input = -2; } } void InputOptionsState::getInputPrompt(TextManager::STRING prompt, TextManager::STRING input) { auto& imgui = IMGUI::getSingleton(); imgui.doOverlay(GEN_ID, Vector2(100.0, 150.0), Vector2(700.0, 450.0)); imgui.doText(GEN_ID, Vector2(400.0, 250.0), prompt, TF_ALIGN_CENTER); imgui.doText(GEN_ID, Vector2(400.0, 300.0), input, TF_ALIGN_CENTER); } void InputOptionsState::getMouseInput(int& action, TextManager::STRING input) { // if already set, do nothing if(action != -1) return; getInputPrompt(TextManager::OP_PRESS_MOUSE_BUTTON, input); action = InputManager::getSingleton()->getLastMouseButton(); if (InputManager::getSingleton()->exit()) action = mOldInteger; } void InputOptionsState::getKeyboardInput(std::string& action, TextManager::STRING input, std::string lastActionKey) { // if already set, do nothing if (action != "") return; getInputPrompt(TextManager::OP_PRESS_KEY_FOR, input); action = lastActionKey; if (InputManager::getSingleton()->exit()) action = mOldString; } void InputOptionsState::getJoystickInput(std::string& action, TextManager::STRING input) { // if already set, do nothing if (action != "") return; getInputPrompt(TextManager::OP_PRESS_BUTTON_FOR, input); action = InputManager::getSingleton()->getLastJoyAction(); if (InputManager::getSingleton()->exit()) action = mOldString; } TextManager::STRING InputOptionsState::getDeviceName(const std::string& device) const { // dirty hack for languagesupport if (device[0] == 'k') return TextManager::OP_KEYBOARD; else if (device[0] == 'm') return TextManager::OP_MOUSE; return TextManager::OP_JOYSTICK; } #else void InputOptionsState::step_impl() { IMGUI& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doImage(GEN_ID, Vector2(400.0, 300.0), "background"); imgui.doOverlay(GEN_ID, Vector2(0.0, 0.0), Vector2(800.0, 600.0)); imgui.doText(GEN_ID, Vector2(43.0, 10.0), TextManager::OP_TOUCH_TYPE); if (imgui.doButton(GEN_ID, Vector2(70.0, 50.0), TextManager::OP_TOUCH_DIRECT)) mBlobbyTouchType = 0; if (imgui.doButton(GEN_ID, Vector2(70.0, 100.0), TextManager::OP_TOUCH_ARROWS)) mBlobbyTouchType = 1; if (mBlobbyTouchType == 0) imgui.doImage(GEN_ID, Vector2(52.0, 62.0), "gfx/pfeil_rechts.bmp"); else imgui.doImage(GEN_ID, Vector2(52.0, 112.0), "gfx/pfeil_rechts.bmp"); imgui.doOverlay(GEN_ID, Vector2(180.0, 150.0), Vector2(620.0, 490.0)); imgui.doImage(GEN_ID, Vector2(400.0, 320.0), "background", Vector2(400.0, 300.0)); // We draw the range of the touchsurfaces here if (mBlobbyTouchType == 0) { // Left arrowkey imgui.doOverlay(GEN_ID, Vector2(200.0 + 5.0, 170.0 + 100.0 + 5.0), Vector2(200.0 + 95.0 + 100.0, 170.0 + 295)); imgui.doImage(GEN_ID, Vector2(289.0, 440.0), "gfx/pfeil_links.bmp"); imgui.doImage(GEN_ID, Vector2(311.0, 440.0), "gfx/pfeil_rechts.bmp"); } else { // Background is x: 200, y: 170, w: 400, h: 300 // Left arrowkey imgui.doOverlay(GEN_ID, Vector2(200.0 + 5.0, 170.0 + 100.0 + 5.0), Vector2(200.0 + 95.0, 170.0 + 295)); imgui.doImage(GEN_ID, Vector2(250.0, 440.0), "gfx/pfeil_links.bmp"); // Right arrowkey imgui.doOverlay(GEN_ID, Vector2(200.0 + 5.0 + 100.0, 170.0 + 100.0 + 5.0), Vector2(200.0 + 95.0 + 100.0, 170.0 + 295)); imgui.doImage(GEN_ID, Vector2(350.0, 440.0), "gfx/pfeil_rechts.bmp"); } imgui.doOverlay(GEN_ID, Vector2(200.0 + 5.0 + 250.0, 170.0 + 100.0 + 5.0), Vector2(200.0 + 95.0 + 300.0, 170.0 + 295)); imgui.doImage(GEN_ID, Vector2(525.0, 440.0), "gfx/pfeil_oben.bmp"); if (imgui.doButton(GEN_ID, Vector2(224.0, 530.0), TextManager::LBL_OK)) { save(); switchState(new OptionState()); } if (imgui.doButton(GEN_ID, Vector2(424.0, 530.0), TextManager::LBL_CANCEL)) { switchState(new OptionState()); } } #endif const char* InputOptionsState::getStateName() const { return "InputOptionsState"; } MiscOptionsState::MiscOptionsState() { mOptionConfig.loadFile("config.xml"); std::string currentBackground = mOptionConfig.getString("background"); mBackground = -1; mBackgrounds = FileSystem::getSingleton().enumerateFiles("backgrounds", ".bmp", true); for(unsigned int i = 0; i < mBackgrounds.size(); ++i) { if (mBackgrounds[i] == currentBackground) { mBackground = i; break; } } std::string currentRules = mOptionConfig.getString("rules"); currentRules = currentRules.substr(0, currentRules.length() - 4); mRule = -1; mRules = FileSystem::getSingleton().enumerateFiles("rules", ".lua", false); for(unsigned int i = 0; i < mRules.size(); ++i) { if (mRules[i] == currentRules) { mRule = i; break; } } mShowFPS = mOptionConfig.getBool("showfps"); mShowBlood = mOptionConfig.getBool("blood"); mVolume = mOptionConfig.getFloat("global_volume"); mMute = mOptionConfig.getBool("mute"); mGameFPS = mOptionConfig.getInteger("gamefps"); mNetworkSide = mOptionConfig.getInteger("network_side"); mLanguage = mOptionConfig.getString("language"); } MiscOptionsState::~MiscOptionsState() { } void MiscOptionsState::save() { mOptionConfig.setBool("showfps", mShowFPS); mOptionConfig.setBool("blood", mShowBlood); mOptionConfig.setFloat("global_volume", mVolume); mOptionConfig.setBool("mute", mMute); mOptionConfig.setInteger("gamefps", mGameFPS); mOptionConfig.setInteger("network_side", mNetworkSide); mOptionConfig.setString("language", mLanguage); mOptionConfig.setString("background", mBackgrounds[mBackground]); mOptionConfig.setString("rules", mRules[mRule] + ".lua"); mOptionConfig.saveFile("config.xml"); SpeedController::getMainInstance()->setDrawFPS(mOptionConfig.getBool("showfps")); BloodManager::getSingleton().enable(mOptionConfig.getBool("blood")); SoundManager::getSingleton().setVolume(mOptionConfig.getFloat("global_volume")); SoundManager::getSingleton().setMute(mOptionConfig.getBool("mute")); RenderManager::getSingleton().setBackground(std::string("backgrounds/") + mOptionConfig.getString("background")); TextManager::switchLanguage(mOptionConfig.getString("language")); } void MiscOptionsState::step_impl() { IMGUI& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doImage(GEN_ID, Vector2(400.0, 300.0), "background"); imgui.doOverlay(GEN_ID, Vector2(0.0, 0.0), Vector2(800.0, 600.0)); imgui.doText(GEN_ID, Vector2(34.0, 10.0), TextManager::OP_BACKGROUND); unsigned tmp = mBackground; imgui.doSelectbox(GEN_ID, Vector2(34.0, 40.0), Vector2(400.0, 175.0), mBackgrounds, tmp); if (tmp != mBackground) { mBackground = tmp; RenderManager::getSingleton().setBackground(std::string("backgrounds/") + mBackgrounds[mBackground]); } imgui.doText(GEN_ID, Vector2(34.0, 190.0), TextManager::OP_RULES); imgui.doSelectbox(GEN_ID, Vector2(34.0, 220.0), Vector2(400.0, 354.0), mRules, mRule); imgui.doText(GEN_ID, Vector2(484.0, 10.0), TextManager::OP_VOLUME); if (imgui.doScrollbar(GEN_ID, Vector2(484.0, 50.0), mVolume)) { SoundManager::getSingleton().setVolume(mVolume); SoundManager::getSingleton().playSound("sounds/bums.wav", 1.0); } if (imgui.doButton(GEN_ID, Vector2(531.0, 80.0), TextManager::OP_MUTE)) { mMute = !mMute; SoundManager::getSingleton().setMute(mMute); if (!mMute) SoundManager::getSingleton().playSound("sounds/bums.wav", 1.0); } if (mMute) { imgui.doImage(GEN_ID, Vector2(513.0, 92.0), "gfx/pfeil_rechts.bmp"); } #if __DESKTOP__ if (imgui.doButton(GEN_ID, Vector2(484.0, 120.0), TextManager::OP_FPS)) { mShowFPS = !mShowFPS; SpeedController::getMainInstance()->setDrawFPS(mShowFPS); } if (mShowFPS) { imgui.doImage(GEN_ID, Vector2(466.0, 132.0), "gfx/pfeil_rechts.bmp"); } #endif if (imgui.doButton(GEN_ID, Vector2(484.0, 160.0), TextManager::OP_BLOOD)) { mShowBlood = !mShowBlood; BloodManager::getSingleton().enable(mShowBlood); BloodManager::getSingleton().spillBlood(Vector2(484.0, 160.0), 1.5, 2); } if (mShowBlood) { imgui.doImage(GEN_ID, Vector2(466.0 ,172.0), "gfx/pfeil_rechts.bmp"); } imgui.doText(GEN_ID, Vector2(434.0, 200.0), TextManager::OP_NETWORK_SIDE); if (imgui.doButton(GEN_ID, Vector2(450.0, 240.0), TextManager::OP_LEFT)) mNetworkSide = 0; if (imgui.doButton(GEN_ID, Vector2(630.0, 240.0), TextManager::OP_RIGHT)) mNetworkSide = 1; if (mNetworkSide == 0) imgui.doImage(GEN_ID, Vector2(432.0, 252.0), "gfx/pfeil_rechts.bmp"); else imgui.doImage(GEN_ID, Vector2(612.0, 252.0), "gfx/pfeil_rechts.bmp"); imgui.doText(GEN_ID, Vector2(484.0, 290.0), TextManager::OP_SPEED); float gamefps = (mGameFPS - 30) / 90.0; if (gamefps < 0.0) gamefps = 0.0; imgui.doScrollbar(GEN_ID, Vector2(440.0, 330.0), gamefps); mGameFPS = (int)(gamefps*90.0+30); if (imgui.doButton(GEN_ID, Vector2(155.0, 380.0), TextManager::OP_VSLOW)) mGameFPS = 30; if (imgui.doButton(GEN_ID, Vector2(450.0, 380.0), TextManager::OP_SLOW)) mGameFPS = 60; if (imgui.doButton(GEN_ID, Vector2(319.0, 415.0), TextManager::OP_DEFAULT)) mGameFPS = 75; if (imgui.doButton(GEN_ID, Vector2(155.0, 450.0), TextManager::OP_FAST)) mGameFPS = 90; if (imgui.doButton(GEN_ID, Vector2(410.0, 450.0), TextManager::OP_VFAST)) mGameFPS = 120; std::stringstream FPSInPercent; FPSInPercent << int((float)mGameFPS/75*100); FPSInPercent << "%"; imgui.doText(GEN_ID, Vector2(660.0, 330.0), FPSInPercent.str()); //! \todo this must be reworked std::map::iterator olang = TextManager::language_names.find(TextManager::getSingleton()->getLang()); if(++olang == TextManager::language_names.end()){ olang = TextManager::language_names.begin(); } if (imgui.doButton(GEN_ID, Vector2(300.0, 490.0), (*olang).second)){ //! \todo autogenerierte liste mit allen lang_ dateien, namen auslesen mLanguage = (*olang).first; TextManager::switchLanguage(mLanguage); } if (imgui.doButton(GEN_ID, Vector2(224.0, 530.0), TextManager::LBL_OK)) { save(); switchState(new OptionState()); } if (imgui.doButton(GEN_ID, Vector2(424.0, 530.0), TextManager::LBL_CANCEL)) { switchState(new OptionState()); } } const char* MiscOptionsState::getStateName() const { return "MiscOptionsState"; } blobby-1.0/config.h.in000644 001750 001750 00000001732 12313310254 017433 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #define BLOBBY_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" blobby-1.0/src/GameLogic.cpp000644 001750 001750 00000053216 12313310251 020533 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "GameLogic.h" /* includes */ #include #include #include extern "C" { #include "lua/lua.h" #include "lua/lauxlib.h" #include "lua/lualib.h" } #include "FileRead.h" #include "GameLogicState.h" #include "DuelMatch.h" #include "GameConstants.h" #include "IUserConfigReader.h" #include "IScriptableComponent.h" #include "PlayerInput.h" int lua_toint(lua_State* state, int index) { double value = lua_tonumber(state, index); return int(value + (value > 0 ? 0.5 : -0.5)); } /* implementation */ /// how many steps must pass until the next hit can happen const int SQUISH_TOLERANCE = 11; const std::string FALLBACK_RULES_NAME = "__FALLBACK__"; const std::string DUMMY_RULES_NAME = "__DUMMY__"; IGameLogic::IGameLogic() : mScoreToWin(IUserConfigReader::createUserConfigReader("config.xml")->getInteger("scoretowin")) , mSquishWall(0) , mSquishGround(0) , mLastError(NO_PLAYER) , mServingPlayer(NO_PLAYER) , mIsBallValid(true) , mIsGameRunning(false) , mWinningPlayer(NO_PLAYER) { // init clock clock.reset(); clock.start(); mScores[LEFT_PLAYER] = 0; mScores[RIGHT_PLAYER] = 0; mTouches[LEFT_PLAYER] = 0; mTouches[RIGHT_PLAYER] = 0; mSquish[LEFT_PLAYER] = 0; mSquish[RIGHT_PLAYER] = 0; } IGameLogic::~IGameLogic() { // nothing to do } int IGameLogic::getTouches(PlayerSide side) const { return mTouches[side2index(side)]; } int IGameLogic::getScore(PlayerSide side) const { return mScores[side2index(side)]; } void IGameLogic::setScore(PlayerSide side, int score) { mScores[side2index(side)] = score; } int IGameLogic::getScoreToWin() const { return mScoreToWin; } PlayerSide IGameLogic::getServingPlayer() const { return mServingPlayer; } void IGameLogic::setServingPlayer(PlayerSide side) { mServingPlayer = side; } PlayerSide IGameLogic::getWinningPlayer() const { return mWinningPlayer; } Clock& IGameLogic::getClock() { return clock; } PlayerSide IGameLogic::getLastErrorSide() { PlayerSide t = mLastError; mLastError = NO_PLAYER; /// reset mLastError to NO_PLAYER /// why? return t; } GameLogicState IGameLogic::getState() const { GameLogicState gls; gls.leftScore = getScore(LEFT_PLAYER); gls.rightScore = getScore(RIGHT_PLAYER); gls.servingPlayer = getServingPlayer(); gls.leftSquish = mSquish[LEFT_PLAYER]; gls.rightSquish = mSquish[RIGHT_PLAYER]; gls.squishWall = mSquishWall; gls.squishGround = mSquishGround; gls.isGameRunning = mIsGameRunning; gls.isBallValid = mIsBallValid; return gls; } void IGameLogic::setState(GameLogicState gls) { setScore(LEFT_PLAYER, gls.leftScore); setScore(RIGHT_PLAYER, gls.rightScore); setServingPlayer(gls.servingPlayer); mSquish[LEFT_PLAYER] = gls.leftSquish; mSquish[RIGHT_PLAYER] = gls.rightSquish; mSquishWall = gls.squishWall; mSquishGround = gls.squishGround; mIsGameRunning = gls.isGameRunning; mIsBallValid = gls.isBallValid; } // ------------------------------------------------------------------------------------------------- // Event Handlers // ------------------------------------------------------------------------------------------------- void IGameLogic::step() { clock.step(); if(clock.isRunning()) { --mSquish[0]; --mSquish[1]; --mSquishWall; --mSquishGround; OnGameHandler(); } } void IGameLogic::onPause() { /// pausing for now only means stopping the clock clock.stop(); } void IGameLogic::onUnPause() { clock.start(); } PlayerInput IGameLogic::transformInput(PlayerInput ip, PlayerSide player) { return handleInput(ip, player); } void IGameLogic::onServe() { mIsBallValid = true; mIsGameRunning = false; } void IGameLogic::onBallHitsGround(PlayerSide side) { // check if collision valid if(!isGroundCollisionValid()) return; // otherwise, set the squish value mSquishGround = SQUISH_TOLERANCE; mTouches[other_side(side)] = 0; OnBallHitsGroundHandler(side); } bool IGameLogic::isBallValid() const { return mIsBallValid; } bool IGameLogic::isGameRunning() const { return mIsGameRunning; } bool IGameLogic::isCollisionValid(PlayerSide side) const { // check whether the ball is squished return mSquish[side2index(side)] <= 0; } bool IGameLogic::isGroundCollisionValid() const { // check whether the ball is squished return mSquishGround <= 0 && isBallValid(); } bool IGameLogic::isWallCollisionValid() const { // check whether the ball is squished return mSquishWall <= 0 && isBallValid(); } void IGameLogic::onBallHitsPlayer(PlayerSide side) { if(!isCollisionValid(side)) return; // otherwise, set the squish value mSquish[side2index(side)] = SQUISH_TOLERANCE; // now, the other blobby has to accept the new hit! mSquish[side2index(other_side(side))] = 0; // set the ball activity mIsGameRunning = true; // count the touches mTouches[side2index(side)]++; OnBallHitsPlayerHandler(side); // reset other players touches after OnBallHitsPlayerHandler is called, so // we have still access to its old value inside the handler function mTouches[side2index(other_side(side))] = 0; } void IGameLogic::onBallHitsWall(PlayerSide side) { if(!isWallCollisionValid()) return; // otherwise, set the squish value mSquishWall = SQUISH_TOLERANCE; OnBallHitsWallHandler(side); } void IGameLogic::onBallHitsNet(PlayerSide side) { if(!isWallCollisionValid()) return; // otherwise, set the squish value mSquishWall = SQUISH_TOLERANCE; OnBallHitsNetHandler(side); } void IGameLogic::score(PlayerSide side, int amount) { int index = side2index(side); mScores[index] += amount; if (mScores[index] < 0) mScores[index] = 0; mWinningPlayer = checkWin(); } void IGameLogic::onError(PlayerSide errorSide, PlayerSide serveSide) { mLastError = errorSide; mIsBallValid = false; mTouches[0] = 0; mTouches[1] = 0; mSquish[0] = 0; mSquish[1] = 0; mSquishWall = 0; mSquishGround = 0; mServingPlayer = serveSide; } // ------------------------------------------------------------------------------------------------- // Dummy Game Logic // --------------------- class DummyGameLogic : public IGameLogic { public: DummyGameLogic() { } virtual ~DummyGameLogic() { } virtual GameLogic clone() const { return GameLogic(new DummyGameLogic()); } virtual std::string getSourceFile() const { return std::string(""); } virtual std::string getAuthor() const { return "Blobby Volley 2 Developers"; } virtual std::string getTitle() const { return DUMMY_RULES_NAME; } protected: virtual PlayerSide checkWin() const { return NO_PLAYER; } virtual PlayerInput handleInput(PlayerInput ip, PlayerSide player) { return ip; } virtual void OnBallHitsPlayerHandler(PlayerSide side) { } virtual void OnBallHitsWallHandler(PlayerSide side) { } virtual void OnBallHitsNetHandler(PlayerSide side) { } virtual void OnBallHitsGroundHandler(PlayerSide side) { } virtual void OnGameHandler() { } }; // ------------------------------------------------------------------------------------------------- // Fallback Game Logic // --------------------- class FallbackGameLogic : public DummyGameLogic { public: FallbackGameLogic() { } virtual ~FallbackGameLogic() { } virtual GameLogic clone() const { return GameLogic(new FallbackGameLogic()); } virtual std::string getTitle() const { return FALLBACK_RULES_NAME; } protected: virtual PlayerSide checkWin() const { int left = getScore(LEFT_PLAYER); int right = getScore(RIGHT_PLAYER); int stw = getScoreToWin(); if( left >= stw && left >= right + 2 ) { return LEFT_PLAYER; } if( right >= stw && right >= left + 2 ) { return RIGHT_PLAYER; } return NO_PLAYER; } virtual void OnBallHitsPlayerHandler(PlayerSide side) { if (getTouches(side) > 3) { score( other_side(side), 1 ); onError( side, other_side(side) ); } } virtual void OnBallHitsGroundHandler(PlayerSide side) { score( other_side(side), 1 ); onError( side, other_side(side) ); } }; class LuaGameLogic : public FallbackGameLogic, public IScriptableComponent { public: LuaGameLogic(const std::string& file, DuelMatch* match); virtual ~LuaGameLogic(); virtual std::string getSourceFile() const { return mSourceFile; } virtual GameLogic clone() const { lua_getglobal(mState, "__MATCH_POINTER"); DuelMatch* match = (DuelMatch*)lua_touserdata(mState, -1); lua_pop(mState, 1); return GameLogic(new LuaGameLogic(mSourceFile, match)); } virtual std::string getAuthor() const { return mAuthor; } virtual std::string getTitle() const { return mTitle; } protected: virtual PlayerInput handleInput(PlayerInput ip, PlayerSide player); virtual PlayerSide checkWin() const; virtual void OnBallHitsPlayerHandler(PlayerSide side); virtual void OnBallHitsWallHandler(PlayerSide side); virtual void OnBallHitsNetHandler(PlayerSide side); virtual void OnBallHitsGroundHandler(PlayerSide side); virtual void OnGameHandler(); static LuaGameLogic* getGameLogic(lua_State* state); private: // lua functions static int luaTouches(lua_State* state); static int luaLaunched(lua_State* state); static int luaBallX(lua_State* state); static int luaBallY(lua_State* state); static int luaBSpeedX(lua_State* state); static int luaBSpeedY(lua_State* state); static int luaPosX(lua_State* state); static int luaPosY(lua_State* state); static int luaSpeedX(lua_State* state); static int luaSpeedY(lua_State* state); static int luaMistake(lua_State* state); static int luaScore(lua_State* state); static int luaGetScore(lua_State* state); static int luaGetOpponent(lua_State* state); static int luaGetServingPlayer(lua_State* state); static int luaGetGameTime(lua_State* state); static int luaIsGameRunning(lua_State* state); // lua state std::string mSourceFile; std::string mAuthor; std::string mTitle; }; LuaGameLogic::LuaGameLogic( const std::string& filename, DuelMatch* match ) : mSourceFile(filename) { lua_pushlightuserdata(mState, this); lua_setglobal(mState, "__GAME_LOGIC_POINTER"); /// \todo use lua registry instead of globals! lua_pushlightuserdata(mState, match); lua_setglobal(mState, "__MATCH_POINTER"); lua_pushnumber(mState, getScoreToWin()); lua_setglobal(mState, "SCORE_TO_WIN"); setGameConstants(); // add functions luaL_requiref(mState, "math", luaopen_math, 1); lua_register(mState, "touches", luaTouches); lua_register(mState, "launched", luaLaunched); lua_register(mState, "ballx", luaBallX); lua_register(mState, "bally", luaBallY); lua_register(mState, "bspeedx", luaBSpeedX); lua_register(mState, "bspeedy", luaBSpeedY); lua_register(mState, "posx", luaPosX); lua_register(mState, "posy", luaPosY); lua_register(mState, "speedx", luaSpeedX); lua_register(mState, "speedy", luaSpeedY); lua_register(mState, "getScore", luaGetScore); lua_register(mState, "score", luaScore); lua_register(mState, "mistake", luaMistake); lua_register(mState, "opponent", luaGetOpponent); lua_register(mState, "servingplayer", luaGetServingPlayer); lua_register(mState, "time", luaGetGameTime); lua_register(mState, "isgamerunning", luaIsGameRunning); // now load script file int error = FileRead::readLuaScript(std::string("rules/") + filename, mState); if (error == 0) error = lua_pcall(mState, 0, 6, 0); if (error) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; ScriptException except; except.luaerror = lua_tostring(mState, -1); throw except; } lua_getglobal(mState, "SCORE_TO_WIN"); mScoreToWin = lua_toint(mState, -1); lua_pop(mState, 1); lua_getglobal(mState, "__AUTHOR__"); const char* author = lua_tostring(mState, -1); mAuthor = ( author ? author : "unknown author" ); lua_pop(mState, 1); lua_getglobal(mState, "__TITLE__"); const char* title = lua_tostring(mState, -1); mTitle = ( title ? title : "untitled script" ); lua_pop(mState, 1); std::cout << "loaded rules "<< getTitle()<< " by " << getAuthor() << " from " << mSourceFile << std::endl; } LuaGameLogic::~LuaGameLogic() { } PlayerSide LuaGameLogic::checkWin() const { bool won = false; if (!getLuaFunction("IsWinning")) { return FallbackGameLogic::checkWin(); } lua_pushnumber(mState, getScore(LEFT_PLAYER) ); lua_pushnumber(mState, getScore(RIGHT_PLAYER) ); if( lua_pcall(mState, 2, 1, 0) ) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; }; won = lua_toboolean(mState, -1); lua_pop(mState, 1); if(won) { if( getScore(LEFT_PLAYER) > getScore(RIGHT_PLAYER) ) return LEFT_PLAYER; if( getScore(LEFT_PLAYER) < getScore(RIGHT_PLAYER) ) return RIGHT_PLAYER; } return NO_PLAYER; } PlayerInput LuaGameLogic::handleInput(PlayerInput ip, PlayerSide player) { if (!getLuaFunction( "HandleInput" )) { return FallbackGameLogic::handleInput(ip, player); } lua_pushnumber(mState, player); lua_pushboolean(mState, ip.left); lua_pushboolean(mState, ip.right); lua_pushboolean(mState, ip.up); if(lua_pcall(mState, 4, 3, 0)) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; }; PlayerInput ret; ret.up = lua_toboolean(mState, -1); ret.right = lua_toboolean(mState, -2); ret.left = lua_toboolean(mState, -3); // cleanup stack lua_pop(mState, lua_gettop(mState)); return ret; } void LuaGameLogic::OnBallHitsPlayerHandler(PlayerSide side) { if (!getLuaFunction("OnBallHitsPlayer")) { FallbackGameLogic::OnBallHitsPlayerHandler(side); return; } lua_pushnumber(mState, side); if( lua_pcall(mState, 1, 0, 0) ) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; }; } void LuaGameLogic::OnBallHitsWallHandler(PlayerSide side) { if (!getLuaFunction("OnBallHitsWall")) { FallbackGameLogic::OnBallHitsWallHandler(side); return; } lua_pushnumber(mState, side); if( lua_pcall(mState, 1, 0, 0) ) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; }; } void LuaGameLogic::OnBallHitsNetHandler(PlayerSide side) { if (!getLuaFunction( "OnBallHitsNet" )) { FallbackGameLogic::OnBallHitsNetHandler(side); return; } lua_pushnumber(mState, side); if( lua_pcall(mState, 1, 0, 0) ) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; }; } void LuaGameLogic::OnBallHitsGroundHandler(PlayerSide side) { if (!getLuaFunction( "OnBallHitsGround" )) { FallbackGameLogic::OnBallHitsGroundHandler(side); return; } lua_pushnumber(mState, side); if( lua_pcall(mState, 1, 0, 0) ) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; }; } void LuaGameLogic::OnGameHandler() { if (!getLuaFunction( "OnGame" )) { FallbackGameLogic::OnGameHandler(); return; } if( lua_pcall(mState, 0, 0, 0) ) { std::cerr << "Lua Error: " << lua_tostring(mState, -1); std::cerr << std::endl; }; } LuaGameLogic* LuaGameLogic::getGameLogic(lua_State* state) { lua_getglobal(state, "__GAME_LOGIC_POINTER"); LuaGameLogic* gl = (LuaGameLogic*)lua_touserdata(state, -1); lua_pop(state, 1); return gl; } int LuaGameLogic::luaTouches(lua_State* state) { LuaGameLogic* gl = getGameLogic(state); PlayerSide side = (PlayerSide)lua_toint(state, -1); lua_pop(state, 1); lua_pushnumber(state, gl->getTouches(side)); return 1; } int LuaGameLogic::luaLaunched(lua_State* state) { lua_getglobal(state, "__MATCH_POINTER"); DuelMatch* match = (DuelMatch*)lua_touserdata(state, -1); lua_pop(state, 1); PlayerSide side = (PlayerSide)lua_toint(state, -1); lua_pop(state, 1); lua_pushboolean(state, match->getBlobJump(side)); return 1; } int LuaGameLogic::luaBallX(lua_State* state) { lua_getglobal(state, "__MATCH_POINTER"); DuelMatch* match = (DuelMatch*)lua_touserdata(state, -1); lua_pop(state, 1); float pos = match->getBallPosition().x; lua_pushnumber(state, pos); return 1; } int LuaGameLogic::luaBallY(lua_State* state) { lua_getglobal(state, "__MATCH_POINTER"); DuelMatch* match = (DuelMatch*)lua_touserdata(state, -1); lua_pop(state, 1); float pos = match->getBallPosition().y; lua_pushnumber(state, pos); return 1; } int LuaGameLogic::luaBSpeedX(lua_State* state) { lua_getglobal(state, "__MATCH_POINTER"); DuelMatch* match = (DuelMatch*)lua_touserdata(state, -1); lua_pop(state, 1); float vel = match->getBallVelocity().x; lua_pushnumber(state, vel); return 1; } int LuaGameLogic::luaBSpeedY(lua_State* state) { lua_getglobal(state, "__MATCH_POINTER"); DuelMatch* match = (DuelMatch*)lua_touserdata(state, -1); lua_pop(state, 1); float vel = match->getBallVelocity().y; lua_pushnumber(state, vel); return 1; } int LuaGameLogic::luaPosX(lua_State* state) { lua_getglobal(state, "__MATCH_POINTER"); DuelMatch* match = (DuelMatch*)lua_touserdata(state, -1); lua_pop(state, 1); PlayerSide side = (PlayerSide)lua_toint(state, -1); lua_pop(state, 1); float pos = match->getBlobPosition(side).x; lua_pushnumber(state, pos); return 1; } int LuaGameLogic::luaPosY(lua_State* state) { lua_getglobal(state, "__MATCH_POINTER"); DuelMatch* match = (DuelMatch*)lua_touserdata(state, -1); lua_pop(state, 1); PlayerSide side = (PlayerSide)lua_toint(state, -1); lua_pop(state, 1); float pos = match->getBlobPosition(side).y; lua_pushnumber(state, pos); return 1; } int LuaGameLogic::luaSpeedX(lua_State* state) { lua_getglobal(state, "__MATCH_POINTER"); DuelMatch* match = (DuelMatch*)lua_touserdata(state, -1); lua_pop(state, 1); PlayerSide side = (PlayerSide)lua_toint(state, -1); lua_pop(state, 1); float pos = match->getBlobVelocity(side).x; lua_pushnumber(state, pos); return 1; } int LuaGameLogic::luaSpeedY(lua_State* state) { lua_getglobal(state, "__MATCH_POINTER"); DuelMatch* match = (DuelMatch*)lua_touserdata(state, -1); lua_pop(state, 1); PlayerSide side = (PlayerSide)lua_toint(state, -1); lua_pop(state, 1); float pos = match->getBlobVelocity(side).y; lua_pushnumber(state, pos); return 1; } int LuaGameLogic::luaGetScore(lua_State* state) { int pl = lua_toint(state, -1); lua_pop(state, 1); LuaGameLogic* gl = getGameLogic(state); lua_pushnumber(state, gl->getScore((PlayerSide)pl)); return 1; } int LuaGameLogic::luaMistake(lua_State* state) { int amount = lua_toint(state, -1); lua_pop(state, 1); PlayerSide serveSide = (PlayerSide)lua_toint(state, -1); lua_pop(state, 1); PlayerSide mistakeSide = (PlayerSide)lua_toint(state, -1); lua_pop(state, 1); LuaGameLogic* gl = getGameLogic(state); gl->score(other_side(mistakeSide), amount); gl->onError(mistakeSide, serveSide); return 0; } int LuaGameLogic::luaScore(lua_State* state) { int amount = lua_toint(state, -1); lua_pop(state, 1); int player = lua_toint(state, -1); lua_pop(state, 1); LuaGameLogic* gl = getGameLogic(state); gl->score((PlayerSide)player, amount); return 0; } int LuaGameLogic::luaGetOpponent(lua_State* state) { int pl = lua_toint(state, -1); lua_pop(state, 1); lua_pushnumber(state, other_side((PlayerSide)pl)); return 1; } int LuaGameLogic::luaGetServingPlayer(lua_State* state) { LuaGameLogic* gl = getGameLogic(state); lua_pushnumber(state, gl->getServingPlayer()); return 1; } int LuaGameLogic::luaGetGameTime(lua_State* state) { LuaGameLogic* gl = getGameLogic(state); lua_pushnumber(state, gl->getClock().getTime()); return 1; } int LuaGameLogic::luaIsGameRunning(lua_State* state) { LuaGameLogic* gl = getGameLogic(state); lua_pushboolean(state, gl->isGameRunning()); return 1; } GameLogic createGameLogic() { return GameLogic(new DummyGameLogic()); } GameLogic createGameLogic(const std::string& file, DuelMatch* match) { if(file == DUMMY_RULES_NAME) { return GameLogic(new DummyGameLogic()); } else if (file == FALLBACK_RULES_NAME) { return GameLogic(new FallbackGameLogic()); } try { return GameLogic( new LuaGameLogic(file, match) ); } catch( std::exception& exp) { std::cerr << "Script Error: Could not create LuaGameLogic: \n"; std::cerr << exp.what() << std::endl; std::cerr << " Using fallback ruleset"; std::cerr << std::endl; return GameLogic(new FallbackGameLogic()); } } blobby-1.0/src/BotAPICalculations.h000644 001750 001750 00000003077 12313310251 021771 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "Vector.h" // flags extern bool FLAG_BOUNCE; void reset_flags(); float time_to_x(const Vector2& pos, const Vector2& vel, float destination); float time_to_y(const Vector2& pos, const Vector2& vel, float destination); float predict_x(const Vector2& pos, const Vector2& vel, float time); float predict_y(const Vector2& pos, const Vector2& vel, float time); float y_at_x(const Vector2& pos, const Vector2& vel, float destination); float x_at_y(const Vector2& pos, const Vector2& vel, float destination); float next_event(const Vector2& pos, const Vector2& vel); blobby-1.0/CMakeLists.txt000644 001750 001750 00000000424 12313310256 020147 0ustar00danielknobedanielknobe000000 000000 cmake_minimum_required(VERSION 2.6) include(CPack) project(Blobby) # process the config.h configure_file(${Blobby_SOURCE_DIR}/config.h.in ${Blobby_BINARY_DIR}/config.h) include_directories(${Blobby_BINARY_DIR}) add_subdirectory(data) add_subdirectory(src) blobby-1.0/data/gfx/blobbym1.bmp000644 001750 001750 00000017242 12313310254 021317 0ustar00danielknobedanielknobe000000 000000 BM6(KYl  -------------------------------! ----------------------------------------------------------"!! ----------------------------------------------------""!! ------------------------------------------------#""!!! --------------------------------------------$#"""!!! ----------------------------------------$$##"""!!! -------------------------------------%$###"""!!! -----------------------------------%%$###"""!!!! --------------------------------'&%$$###""""!!! -----------------------------'&%%$$$###"""!!!! ---------------------------''&%%%$$###""""!!!!  -------------------------(''&&%%$$$###""""!!!!  ------------------------(''&&%%$$$####""""!!!!  -----------------------)(''&&%%%$$$####""""!!!!   ---------------------*)(''&&&%%%$$$####""""!!!    !--------------------))(''&&%%$$$$$#####""""!!!   -------------------*)('&&%%%$$$######"""""""!!  !------------------*('&&%%$$$####""""""""""""!!   !-----------------*('&&%$$$###"""""""!!!!!!!!!!!    !!!---------------,)''&%$$$###""""!!!!!!!!!!!!!!!  !!!!#--------------*('&%$$###""""!!!!!!!! !!!!!  !!!!!""--------------)'&%%$###"""!!!!!  !!!!!!!!!!!!!!""-------------)'&%%$##"""!!!! !!!!!!!!!!!!!!!!!!""""#------------''&%$$#"""!!!  !!!!"""""!!!!!!!!"""""##------------&&%$$#"""!!!  !!!!""""""""""""""""###------------&%%$##""!!!  !!!!""""""""""""""###$-----------&%$$##""!!!  !!!!""""""""""######$%----------%$###""!!  !!!!""###########$$$%----------$#"""""!!  !!!!""########$$$$$%----------#""!!!!!  !!!""###$$$$$$$$$%%----------""!!!  !!!""##$$$$$$$%%%&----------"!  !!"""##$$%%%%%%&&----------!  !!""##$$%%%%%&&'----------  !!"""#$$%%%&&&&'----------  !!""##$%%&&&&''---------- !!""##$$%&&'''(---------- !!!""#$$%&'''()----------- !!""##$%&'(((------------ !!""##$%&'(()------------ !!""##$%&'())------------ !!""##$%&'()*-------------!!! !!""##$%&()*-------------- !!!!!!!!"#####""#####""##$%(()*-------------- !!!""""""######$$%%%%%%%%%%%%%%''()*,--------------- !!!!"""####$$$$$$%%&&&&''''''''(()))))*---------------- !!!""""###$$$%%%%&&&''''((())))*)**++++++----------------- !!!""""###$$$%%%&&&'''(((()))**+++,,,,,,,------------------ !!!""""###$$$%%%&&&'''((()))***++,,,,,,,,,------------------- !!!!"""####$$$%%%&&&'''(()))**+++,,,,,,,,,-------------------- !!!!""""###$$$$%%%&&'''((())***++,,,,,,,,+*-------------------- !!!!""""###$$$$%%%&&'''((())***++,,,,,++***-------------------- !!!!!"""####$$$%%%&&'''((())**+++++++***)))--------------------  !!!!"""####$$$%%%&&&''((())))))*****))))))--------------------- !!!!""""###$$$%%%&&&&''''''(((())))))))))---------------------- !!!!"""####$$$%%%%%&&&&&''''((()))))((((---------------------- !!!!""""###$$$$$$%%%%%&&&&''''(())((((((---------------------- !!!!"""#####$$$$$$%%%%%&&&''''(((((((()---------------------- !!!""""######$$$$$$%%%%&&&'''(((((((()---------------------- !!!""""#######$$$$$%%%%&&&''(((((((()----------------------- !!!!""""#######$$$$$%%%&&&''((((((((------------------------ !!!"""""######$$$$$%%%&&&'''(((((()------------------------ !!!!""""#######$$$$%%%&&&'''((((())------------------------ !!!!""""######$$$$$%%%&&&''(())))))------------------------ !!!""""######$$$$$%%%&&&''(())))))------------------------ !!!"""######$$$$$%%%%&&&''(())))))------------------------ !!!!""######$$$$$%%%%&&&'''(())))))------------------------- !!!!""""#####$$$%%%&&&''(())))))-------------------------- !!!"""""####$$$%%&&''(()))))-------------------------- !!!!!""""###$$$%%&&'(())))-------------------------- !!!!"""###$$%%&&'())))-------------------------- !!!!""###$$%&&'())*--------------------------- !!"""##$%%&')*---------------------------- !!""##$%&')+----------------------------- !!""##$%&')------------------------------  !!""##$%&()------------------------------ !!""##$%'(*-------------------------------   !""#$%&'(---------------------------------  !""#$%&----------------------------------  !"#$%&-----------------------------------   !!"#%-------------------------------------   !"#--------------------------------------- !"-----------------------------------------!------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------blobby-1.0/data/scripts/old/hyperion6.lua000644 001750 001750 00000015226 12313310254 023217 0ustar00danielknobedanielknobe000000 000000 -- Dies ist der BlobbyVolley2 Bot "Hyperion" -- geschrieben und getestet wurde der Bot mit der SVN-Version -- Die Version Blobby0.6 hatte verschiedene Bugs, unter anderem bei der oppx() und der estimate() Funktion -- -- Hyperion ver. 0.6 -- - Einige Konstanten die die physikalische Welt in BlobbyVolley2 beschreiben g=0.28 g_p=0.88 v0=14.5 v_p=4.5 jb_p=0.44 r1=31.5 -- -- - kleine unkomplizierte Hilfsfunktionen die ich benötige function max(a,b) if (a>b) then return a else return b end end function min(a,b) if (a2.6) then right() elseif (posx()>x) and (math.abs(posx()-x)>2.6) then left() end end function t1_y(y,vy,height) -- Eingabe: Position und Geschwindigkeit des Balles, Höhe die der Ball erreichen soll -- Ausgabe: Ausgabe der Zeit bis zur Höhe height if (vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g<0) then return -1 else return -1/10+vy/g-math.sqrt( vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g ) end end function t2_y(y,vy,height) -- Eingabe: Position und Geschwindigkeit des Balles, Höhe die der Ball erreichen soll -- Ausgabe: Ausgabe der Zeit bis zur Höhe height if (vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g<0) then return -1 else return -1/10+vy/g+math.sqrt( vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g ) end end function y_p(y,t) -- Eingabe: Position und Geschwindigkeit des Players, Zeitpunkt an dem man die y-Koordinate des Players wissen möchte -- Ausgabe: Höhe des Players nach der Zeit t return y+(v0+jb_p/2+g_p/10)*t-1/2*(g_p-jb_p)*t^2 end tp_peak=(14.5+0.44/2+0.88/10)/(0.88-0.44) yp_max=y_p(144.5,tp_peak) function time(t) return 1/5*math.ceil(5*t) end function t2_yp(y,vy,height) y=144.5 return (v0+jb_p/2+g_p/10)/(g_p-jb_p)+math.sqrt((v0+jb_p/2+g_p/10)^2/(g_p-jb_p)^2+2*y/(g_p-jb_p)) end -- -- - Komplizierte Funktionen die die Game-Engine nachbilden und so Einschlagpunkte, etc. berechnen. function collide(x,y,vx,vy,x2,y2,r2) -- Berechnet, ob und nach welcher Zeit der Ball im Zustand (x,y,vx,vy) mit der Kugel an (x2,y2) mit Radius r2 kollidiert local leftb=x2-r2-r1 local rightb=x2+r2+r1 local lowerb=y2-r2-r1 local upperb=y2+r2+r1 local txlb=time((leftb-x)/vx) -- Zeit zur linken Begrenzung local txrb=time((rightb-x)/vx) -- Zeit zur rechten Begrenzung local tyla=time(t1_y(y,vy,lowerb)) --untere Grenze steigend (ascending) local tyld=time(t2_y(y,vy,lowerb)) --untere Grenze fallend (descending) local tyua=time(t1_y(y,vy,upperb)) --obere Grenze steigend (ascending) local tyud=time(t2_y(y,vy,upperb)) --obere Grenze fallend (descending) local tp=time(vy/g-1/10) -- Zeit bis die Ballkurve auf dem Höhepunkt ist (kann in der Vergangenheit liegen) local t1,t2,t_coll=0,0,-1 if (vx>0) then t1=max(max(txlb,tyla),0) t2=min(txrb,tyld) else t1=max(max(txrb,tyla),0) t2=min(txlb,tyld) end if (t10) then t_wall=time((768.5-x)/vx) t_net=time((361.5-x)/vx) else t_wall=time((31.5-x)/vx) t_net=time((438.5-x)/vx) end local t=10000 if ((t_netsphere>0) and (t_netsphere0) and (t_net0) and (t_wallt) then if (t==t_netsphere) then t_ret=t_ret+t vx_ret=0 vy_ret=0 x_ret=400 y_ret=316 collision=0 end if (t==t_net) or (t==t_wall) then t_ret=t_ret+t x=x+vx*t y=y_b(y,vy,t) vx=-vx vy=vy-g*t collision=1 end else t_ret=t_ret+t_height vx_ret=vx vy_ret=vy-g*t_height x_ret=x+vx*t_height y_ret=y_b(y,vy,t_height) collision=0 end end -- while Ende return x_ret,y_ret,vx_ret,vy_ret,t_ret end function impact(x,y,vx,vy,xpos,ypos) -- schätzt den Einschlagsort des Balles wenn er mit dem Blobby an Position xpos kollidiert ist und dann losfliegt. -- Funktioniert mit minimalem Fehler r1=31.5 r2=25 --local x,y,vx,vy,t1=estimate_t(x,y,vx,vy,(ypos+19+25)+31.5) Die Wete haben schon nahe genug zu sein local t=time(collide(x,y,vx,vy,xpos,ypos+19,25)) if(t>0) then x=x+vx*t y=y_b(y,vy,t) dx=x-xpos dy=y-(ypos+19) l=math.sqrt(dx^2+dy^2) vx=dx/l vy=dy/l x=x+vx*3 y=y+vy*3 vy=vy*13.125 vx=vx*13.125 -- x=x+vx/5 -- y=y+vy/5 x,y,vx,vy,t=estimate_t(x,y,vx,vy,220.5) return x,y,vx,vy,t else return -1,-1,-1,-1,-1 end end -- Funktionsende function xtoplayto(target,height) local x,y,vx,vy,t=estimate_t(ballx(),bally(),bspeedx(),bspeedy(),height+(25+19)+31.5+5) local xpos=estimate_t(ballx(),bally(),bspeedx(),bspeedy(),height+(25+19)+31.5) local sgn=0 if (x -- - High-Level Funktionen die bestimmen wo man s function stellen(tox,height) --t2_yp --t2_y if (tox<390) then elseif (390410) then end move(xplayto(tox,posy())) end function schmettern() end function ueberspielen() end -- -- - Die Hauptfunktionen des Spiels function OnOpponentServe() end function OnServe(ballready) if (math.abs(math.floor(posx()/4.5)-posx()/4.5)<0.4) then if(math.abs(180-posx())<2) then jump() else moveto(180) end else moveto(400) end old=5 end function OnGame() x1=ballx() y1=bally() vx1=bspeedx() vy1=bspeedy() x2=oppx() y2=163.5 r2=25 xe=estimate_t(x1,y1,vx1,vy1,220.5) --debug(xe) -- debug(x2) xr,yr,vxr,vyr,tr=impact(x1,y1,vx1,vy1,x2,144.5) -- debug(xr) -- debug(0) if (xe<400) then if (touches()==0) then test=xtoplayto(320,144.5) move(test) else test=xtoplayto(400,144.5) move(test-3.1) end elseif (xe==400) then move(180) else move(180) end old=touches() endblobby-1.0/data/scripts/old/gintonicV7.lua000644 001750 001750 00000017540 12313310254 023324 0ustar00danielknobedanielknobe000000 000000 --Gin Tonic v7 - No Comments, sorry :P CT_ServeSelf = { 152, 163, 180, 195, 205, 240 } CT_ServeOpp = { 140, 200, 240 } CT_ServeIndex = 0 CT_Tolerance = 5 CT_Action = "" CT_ShotDecision = 0 CT_NextGround = 9999 CT_LastTouches = 0 CT_LastHeight = 0 CT_WaitCounter = 0 CT_WaitName = "" CT_WaitMoveTo = 0 function IsAt(position) return (math.abs(posx()-position) <= CT_Tolerance) end function Wait(name, time, moveto) if (CT_WaitName == name) then if (CT_WaitCounter == 0) then return false end end CT_WaitCounter = time CT_WaitName = name CT_WaitMoveTo = moveto return true end function WaitQueue() if (CT_WaitCounter > 0) then CT_WaitCounter = CT_WaitCounter - 1 if (CT_WaitMoveTo > 0) then if (not IsAt(CT_WaitMoveTo)) then moveto(CT_WaitMoveTo) end end return true else return false end end function ResetWait() CT_WaitCounter = 0 CT_WaitName = "" end function OnOpponentServe() if (CT_ServeIndex == 0) then CT_ServeIndex = math.random(1,3) end if (not IsAt(CT_ServeOpp[CT_ServeIndex])) then moveto(CT_ServeOpp[CT_ServeIndex]) end end function OnServe(ballready) if (WaitQueue()) then return end if (CT_ServeIndex == 0) then CT_ServeIndex = math.random(1,6) end if (ballready) then if (Wait("ServeDelay",math.random(28,90),CT_ServeSelf[CT_ServeIndex]+math.random(-150, 150))) then return end if (IsAt(CT_ServeSelf[CT_ServeIndex])) then jump() else moveto(CT_ServeSelf[CT_ServeIndex]) end else if (posx() < 150) then jump() end moveto(40) end end function OnGame() ResetWait() CT_ServeIndex = 0 local timeJump = timeToHitHeight(380, 390, 20) local timeGround = timeToHitHeight(200, 222, 40) local timeBlock = timeToOppSmash(390) local estimhx = r_estimx(timeJump) local estimGround = r_estimx(timeGround) local estimBlock = r_estimx(timeBlock) local block = 0 local wallcoll = willHitWall(timeJump) if (timeBlock ~= -1) then block = timeBlock+(estimBlock-400)/13 end if (timeBlock == -1) then timeBlock = 9999 end if (timeJump == -1) then estimhx = 9999 end if (timeGround == -1) then estimGround = 210 end if (posy() < CT_LastHeight and posy() > 150 and posy() < 330) then CT_Action = "" end CT_LastHeight = posy() if (CT_Action == "NetBlock") then if ((posy() < 150) or (timeBlock < 4 and oppy() < 150) or (ballx() <= posx()) or (touches() <= 0 and bspeedx() > 10)) then CT_Action = "" else jump() moveto(400) return end elseif (CT_Action == "JumpPlayFwd") then if (posy() < 150) then CT_Action = "" else if (estimhx == 9999) then estimhx = ballx()+bspeedx() end jump() if (posy() > 300) then if (math.abs(bally()-posy()) < 18) then moveto(ballx()+bspeedx()) elseif (estimhx < 200) then if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(3,5) end moveto(estimhx-10*CT_ShotDecision) elseif (oppx() > 600 and oppy() < 150) then if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(4,6) end moveto(estimhx-10*CT_ShotDecision) elseif (oppx() < 600 and oppy() > 180) then moveto(estimhx-40) else moveto(estimhx-60) end else moveto(estimhx-60) end return end elseif (CT_Action == "JumpPlayRev") then if (posy() < 150 or touches() ~= CT_LastTouches) then CT_Action = "" else if (estimhx == 9999) then estimhx = ballx()+bspeedx() end jump() if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(4,9) end moveto(estimhx+5*CT_ShotDecision) return end end if (touches() ~= CT_LastTouches) then CT_LastTouches = touches() CT_NextGround = math.random(-20,20) end if (CT_Action == "") then if ((ballx() < 400 or bspeedx() < -2) and estimGround < 400) then if (touches() >= 2) then moveto(estimGround+(posx()-500)/22) elseif (math.abs(bspeedx()) > 8) then moveto(estimGround) else moveto(estimGround+CT_NextGround) end elseif (estimhx < 600 and math.abs(bspeedx()) < 6) then moveto(280) elseif (estimhx > 650) then moveto(250) else moveto(190) end end if (posy() > 150) then return end if (touches() > 2) then return end if (timeBlock >= 17 and timeBlock <= 19) then if (posx() > 210 and estimBlock > 395 and estimBlock < 640 and not wallcoll) then jump() moveto(400) CT_Action = "NetBlock" return end end if (timeJump >= 17 and timeJump <= 19) then if (bspeedx() <= 7 and estimhx >= 65 and estimhx <= 420 and posx()-estimhx <= 120 and (bspeedx() >= -7 or not wallcoll)) then if (estimGround > 400 or bally() > 250) then CT_Action = "JumpPlayFwd" CT_ShotDecision = 0 jump() end end if ((wallcoll or bspeedx() >= -7) and estimhx <= 250 and posx()-estimhx <= 180 and posx()-estimhx >= -120) then if (estimGround > 400 or bally() > 250) then if (CT_Action == "JumpPlayFwd" and (touches() >= 2 or math.random(100) > 15)) then return end CT_Action = "JumpPlayRev" CT_ShotDecision = 0 jump() end end end end function timeToHitHeight(minheight, maxheight, depth) local i = 0 for i=1, depth do if (estimy(i) >= minheight and estimy(i) <= maxheight and estimx(i) <= 420) then return i end end return -1 end function timeToOppSmash(height) if (bally() < height) then return -1 end local i = 0 for i=1, 17 do if (estimy(i) < height) then return i end end return -1 end function r_estimx(time) local estim = estimx(time) if estim < 31.5 then estim = 63-estim end if estim > 768.5 then estim = 1537-estim end if (bally() < 330) then if (ballx() < 400 and estim > 400) then estim = 723-estim end if (ballx() > 400 and estim < 400) then estim = 877-estim end end return estim end function willHitWall(time) if (estimx(time) < 31.5) then return true end return false endblobby-1.0/src/GenericIO.h000644 001750 001750 00000020560 12313310251 020151 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include #include #include "GenericIOFwd.h" #include "GenericIODetail.h" #include "Global.h" // forward declarations class FileWrite; class FileRead; namespace RakNet { class BitStream; } // Factory functions /// creates a generic writer that writes to a file boost::shared_ptr< GenericOut > createGenericWriter(boost::shared_ptr file); /// creates a generic writer that writes to a BitStream boost::shared_ptr< GenericOut > createGenericWriter(RakNet::BitStream* stream); /// creates a generic writer that writes hman readable to a stream /// currently, there is no corresponding reader because this is mostly for debugging purposes boost::shared_ptr< GenericOut > createGenericWriter(std::ostream& stream); /// creates a generic reader that reads from a file boost::shared_ptr< GenericIn > createGenericReader(boost::shared_ptr file); /// creates a generic reader that reads from a BitStream boost::shared_ptr< GenericIn > createGenericReader(RakNet::BitStream* stream); // GenericIO class template /*! \class GenericIO \brief Class template that abstracts IO \details This class abstract IO to/from different sources. Current implementations are File and BitStream input/output. The template parameter tag decides wether the actual instance is an input or an output object. This design ensure that input and output have exactly the same interface and enables writing algorithms that read and write data with exactly the same code, reducing the chance of errors. This class derives from boost::noncopyable, which seems a reasonable choice for these IO classes. Having different GenericIO objects which read/write from/to the same source/target just makes things more complicated and error prone. */ template class GenericIO : public boost::noncopyable { public: /// virtual d'tor to ensure correct cleanup virtual ~GenericIO() { }; /// reads/writes one byte virtual void byte ( typename detail::conster::type data) = 0; /// reads/writes one boolean. virtual void boolean( typename detail::conster::type data) = 0; /// reads/writes on 32 bit unsigned integer virtual void uint32( typename detail::conster::type data) = 0; /// reads/writes a floating point number virtual void number( typename detail::conster::type data) = 0; /// reads/writes a character string. virtual void string( typename detail::conster::type string) = 0; /// reads/writes a character array of certain length virtual void array ( typename detail::conster::type data, unsigned int length) = 0; /// returns the current read/write position virtual unsigned int tell() const = 0; /// sets the current read/write position /// \attention Use for pos only values you have received /// from a prior call to tell of the same instance /// of GenericIO as these positions are not /// guaranteed to match for different source/target /// types. virtual void seek(unsigned int pos) const = 0; // generic implementation /// this is a nonvirtual generic function which can be used to write or read arbitrary (supported) /// types. these types are serialized using the methods above for the primitive types. /// supported values for \p T are all the basic types which can be written directly, /// PlayerInput, PlayerSide and Color. If T can be serialized, this function can serialize /// containers of T provided they have the following methods: /// * begin() /// * end() /// * size() /// * resize() /// Additional user types can be serialized if the user defines the appropriate methods /// in UserSerializer. template void generic( typename detail::conster::type data ) { // thats a rather complicated template construct. It uses the serialize_dispatch template // with working type T, boost::true_type or boost::false_type as init depending wether the // supplied type T has a default implementation associated (as determined by the // has_default_io_implementation template). // the second parameter is a bool which is true if the type offeres a container interface // and false otherwise (determined by the is_container_type template) // depending on the second two template parameters, serialize_dispatch is either // derived from detail::predifined_serializer (when init is boost::true_type) // or UserSerializer if init is boost::false_type and container is false. // if it is a container type, the partial template specialisation foudn below is // used to serialize that template. detail::serialize_dispatch::type, detail::is_container_type::value >::serialize(*this, data); } typedef tag tag_type; }; /*! \def USER_SERIALIZER_IMPLEMENTATION_HELPER \brief Helper macro for autogenerated user serializers \details use like this: \code USER_SERIALIZER_IMPLEMENTATION_HELPER( \p type ) { generic serialisation algorithm for both input and output. Variable \p io contains the GenericIO object, variable value the \p type object. } \endcode remember to use generic\< \p type\> like this: \code io.template generic\< \p type\>(value) \endcode otherwise, the compiler won't recognise generic as a template function. \example USER_SERIALIZER_IMPLEMENTATION_HELPER(int) { io.uint32(value); } */ #define USER_SERIALIZER_IMPLEMENTATION_HELPER( UD_TYPE ) \ template \ void doSerialize##UD_TYPE(GenericIO&, typename detail::conster::type value); \ template<> \ void UserSerializer::serialize( GenericOut& out, const UD_TYPE& value) \ { \ doSerialize##UD_TYPE(out, value); \ } \ template<> \ void UserSerializer::serialize( GenericIn& in, UD_TYPE& value) \ { \ doSerialize##UD_TYPE(in, value); \ } \ template \ void doSerialize##UD_TYPE(GenericIO& io, typename detail::conster::type value) // ------------------------------------------------------------------------------------------------- // Implementation detail // ------------------------------------------------------------------------------------------------- namespace detail { // serialisation algorithm for container types: // read/write size of the container. // if reading, resize container to fit // iterate over all elements and read/write template struct serialize_dispatch { static void serialize( GenericOut& out, const T& list) { out.uint32( list.size() ); for(typename T::const_iterator i = list.begin(); i != list.end(); ++i) { out.generic( *i ); } } static void serialize( GenericIn& in, T& list) { unsigned int size; in.uint32( size ); list.resize( size ); for(typename T::iterator i = list.begin(); i != list.end(); ++i) { in.generic( *i ); } } }; } blobby-1.0/src/lua/luac.c000644 001750 001750 00000023354 12313310253 020053 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: luac.c,v 1.69 2011/11/29 17:46:33 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ #include #include #include #include #define luac_c #define LUA_CORE #include "lua.h" #include "lauxlib.h" #include "lobject.h" #include "lstate.h" #include "lundump.h" static void PrintFunction(const Proto* f, int full); #define luaU_print PrintFunction #define PROGNAME "luac" /* default program name */ #define OUTPUT PROGNAME ".out" /* default output file */ static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ static int stripping=0; /* strip debug information? */ static char Output[]={ OUTPUT }; /* default output file name */ static const char* output=Output; /* actual output file name */ static const char* progname=PROGNAME; /* actual program name */ static void fatal(const char* message) { fprintf(stderr,"%s: %s\n",progname,message); exit(EXIT_FAILURE); } static void cannot(const char* what) { fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); exit(EXIT_FAILURE); } static void usage(const char* message) { if (*message=='-') fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); else fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, "usage: %s [options] [filenames]\n" "Available options are:\n" " -l list (use -l -l for full listing)\n" " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" " -- stop handling options\n" " - stop handling options and process stdin\n" ,progname,Output); exit(EXIT_FAILURE); } #define IS(s) (strcmp(argv[i],s)==0) static int doargs(int argc, char* argv[]) { int i; int version=0; if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; for (i=1; itop+(i)) static const Proto* combine(lua_State* L, int n) { if (n==1) return toproto(L,-1); else { Proto* f; int i=n; if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1)); f=toproto(L,-1); for (i=0; ip[i]=toproto(L,i-n-1); if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0; } f->sizelineinfo=0; return f; } } static int writer(lua_State* L, const void* p, size_t size, void* u) { UNUSED(L); return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); } static int pmain(lua_State* L) { int argc=(int)lua_tointeger(L,1); char** argv=(char**)lua_touserdata(L,2); const Proto* f; int i; if (!lua_checkstack(L,argc)) fatal("too many input files"); for (i=0; i1); if (dumping) { FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); if (D==NULL) cannot("open"); lua_lock(L); luaU_dump(L,f,writer,D,stripping); lua_unlock(L); if (ferror(D)) cannot("write"); if (fclose(D)) cannot("close"); } return 0; } int main(int argc, char* argv[]) { lua_State* L; int i=doargs(argc,argv); argc-=i; argv+=i; if (argc<=0) usage("no input files given"); L=luaL_newstate(); if (L==NULL) fatal("cannot create state: not enough memory"); lua_pushcfunction(L,&pmain); lua_pushinteger(L,argc); lua_pushlightuserdata(L,argv); if (lua_pcall(L,2,0,0)!=LUA_OK) fatal(lua_tostring(L,-1)); lua_close(L); return EXIT_SUCCESS; } /* ** $Id: print.c,v 1.69 2013/07/04 01:03:46 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ #include #include #define luac_c #define LUA_CORE #include "ldebug.h" #include "lobject.h" #include "lopcodes.h" #define VOID(p) ((const void*)(p)) static void PrintString(const TString* ts) { const char* s=getstr(ts); size_t i,n=ts->tsv.len; printf("%c",'"'); for (i=0; ik[i]; switch (ttypenv(o)) { case LUA_TNIL: printf("nil"); break; case LUA_TBOOLEAN: printf(bvalue(o) ? "true" : "false"); break; case LUA_TNUMBER: printf(LUA_NUMBER_FMT,nvalue(o)); break; case LUA_TSTRING: PrintString(rawtsvalue(o)); break; default: /* cannot happen */ printf("? type=%d",ttype(o)); break; } } #define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-") #define MYK(x) (-1-(x)) static void PrintCode(const Proto* f) { const Instruction* code=f->code; int pc,n=f->sizecode; for (pc=0; pc0) printf("[%d]\t",line); else printf("[-]\t"); printf("%-9s\t",luaP_opnames[o]); switch (getOpMode(o)) { case iABC: printf("%d",a); if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (MYK(INDEXK(b))) : b); if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c); break; case iABx: printf("%d",a); if (getBMode(o)==OpArgK) printf(" %d",MYK(bx)); if (getBMode(o)==OpArgU) printf(" %d",bx); break; case iAsBx: printf("%d %d",a,sbx); break; case iAx: printf("%d",MYK(ax)); break; } switch (o) { case OP_LOADK: printf("\t; "); PrintConstant(f,bx); break; case OP_GETUPVAL: case OP_SETUPVAL: printf("\t; %s",UPVALNAME(b)); break; case OP_GETTABUP: printf("\t; %s",UPVALNAME(b)); if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } break; case OP_SETTABUP: printf("\t; %s",UPVALNAME(a)); if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); } if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } break; case OP_GETTABLE: case OP_SELF: if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } break; case OP_SETTABLE: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_POW: case OP_EQ: case OP_LT: case OP_LE: if (ISK(b) || ISK(c)) { printf("\t; "); if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); printf(" "); if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); } break; case OP_JMP: case OP_FORLOOP: case OP_FORPREP: case OP_TFORLOOP: printf("\t; to %d",sbx+pc+2); break; case OP_CLOSURE: printf("\t; %p",VOID(f->p[bx])); break; case OP_SETLIST: if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c); break; case OP_EXTRAARG: printf("\t; "); PrintConstant(f,ax); break; default: break; } printf("\n"); } } #define SS(x) ((x==1)?"":"s") #define S(x) (int)(x),SS(x) static void PrintHeader(const Proto* f) { const char* s=f->source ? getstr(f->source) : "=?"; if (*s=='@' || *s=='=') s++; else if (*s==LUA_SIGNATURE[0]) s="(bstring)"; else s="(string)"; printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n", (f->linedefined==0)?"main":"function",s, f->linedefined,f->lastlinedefined, S(f->sizecode),VOID(f)); printf("%d%s param%s, %d slot%s, %d upvalue%s, ", (int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams), S(f->maxstacksize),S(f->sizeupvalues)); printf("%d local%s, %d constant%s, %d function%s\n", S(f->sizelocvars),S(f->sizek),S(f->sizep)); } static void PrintDebug(const Proto* f) { int i,n; n=f->sizek; printf("constants (%d) for %p:\n",n,VOID(f)); for (i=0; isizelocvars; printf("locals (%d) for %p:\n",n,VOID(f)); for (i=0; ilocvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); } n=f->sizeupvalues; printf("upvalues (%d) for %p:\n",n,VOID(f)); for (i=0; iupvalues[i].instack,f->upvalues[i].idx); } } static void PrintFunction(const Proto* f, int full) { int i,n=f->sizep; PrintHeader(f); PrintCode(f); if (full) PrintDebug(f); for (i=0; ip[i],full); } blobby-1.0/data/gfx/font07.bmp000644 001750 001750 00000003370 12313310254 020722 0ustar00danielknobedanielknobe000000 000000 BM6( w*s H  8@  #O52C },PeGV g )93pևAX ' GEeXr*S }-0iaяXZ7 oTj@@0=B|C[s)> DWdl!m5j6ATq;q:Y/ 1F= S / 5@mKbB]0l <!  R[po]n4E" wXP R UbmLT|[c&.    ()+<-/A35SbeW\+/&#"0%7(  9:DE&'+&H  $& +7586*%*$& FY!%! <=UUa_XSB<2)1)!F-/x/2,/-/02=>VWpp|c\TJA4-"Z!-.`xyzzss}|Ԥ洲vlZfQ*E 76AcaywtߦzXGq #!)>;KF=X;/Fblobby-1.0/data/backgrounds/strand1.bmp000644 001750 001750 00001653466 12313310255 022722 0ustar00danielknobedanielknobe000000 000000 BM6W6( X  k/ 9<„WF*H#DP Nė{JM:EfS #$#uGO%)JHcdXgT.Fl/):f-iR0LbѨ#&3{ine[ *+)mrR&'SN+XZqlokRHuFIkjGG)'÷o:*0JGSw5pjhN⪹H0>>>>> 1zJsx0 m 0 x x>> >> > > > >>>> >>>>>>> > > >>"">>&> >> > >>> >> >>>>>>>> >>>>>>>>>>>>>> > >>>>>>>>>HHgXAAXggggX/lHHkBHHkk___HHfNN|*HY*N|gXg_AAA_HYHYkf|Xll_HHYHHXXgXPYHYYHYHll_llllllBlBYYYH lA/AA?__]]*](KRRRRRrMRR K2^S]2]] RaRRrK^oIaIIr q2{2{2{S22{MRMMRRMrM2nSn2nnnnqrGr GM]2^2] raGaaaIaaaaaar  krGr* rRr rHr GQa]((2^2]my1m0mm Y)m))kuggXBHkkkHk_l)GGyyym01B yy0mmmymmymymHm)))m)__Y)Ys)yyy)ym)Ymxm0[smxYBsYxxsXsl Y)))YHH)0ymknnAAkl_**{{*H HYxJz1mmm)Y)mym00)YYQk{iS GGGmy nqqk)yGmyyym)Bsl??myymmykH0ymyyym)my0yymGHl_)mmm0)Ym)k)GYl__ )myyG_[ x0m0y0y0000?yyym0mmmm))y000y0y0y00mmm)myyyyy0B%xxmx)&6xx)x%l)00ymy0ymyy0mmmmmx)x)m0my0mmym)x0ymyymm)m)mxmmmm0mm0mm0y0my)mmG[lll?g[A x))YslHYNNHG)mlX88/zlg[Bzz?l0)m00mmYOg̭Yxlzsxmmmm)mPXgXAHmmmm0m)mlBl Bsxs䶨zBBz[[[?g_HYY%HHHGHk?XAAA?lY)))YXqy))sz/[[/BYYY%GB ``TTs1xm)H_A/XgX?kl%HHr%Y_gA/llAAs뭭l0)m00m0xAOgk_kA1000)smymm0mn{B)H G)))mGry00xzxyyym))yyyyyymymm))mkllx)mmm_myymxsm0xYB xmxBsBBmm[BBBx)YmGm)ml_mm0gfnnlG))Hn*HsYxxBzBBsmmxY)mym00H_)ym)HS %GQyGYkHmymm)))szmYlB)0m)yyymyyym00m)m0yy0)_s̭)00Hm)Y)y)Hll_lx0yHXmyy0myyyym)_Xyyyyymm)))y0yyyyyymm)m)))yyyyyymm)YG)))YB&&!)YsY%kmyyyyyymmm)))))myyyyyyyymy))Y)yyyyyyyyy)))))myy00ymym)lAlY)_g?[[_$x)mxmm)YHlll_-8l%)%*?/[gg z_Bm0xmmss _/ggxmxmmmmyXlmym))m0m$/gg/?/=[sz/gBG)GGHHYH_BXA?HYmY?_yyyx [[z̨lBxm)x%z̭ W````T1sssxB?[gAYslHYHG))slXX[$Y)g̶lAsBzlB00x00s Yz/Xg_10 0000xsYx0m0xYmy)%)yGGm)mm)))y00 Ymyyymm0y0ymymyymm))mm)[mxm)))yyyH0YxymyyklYym/[/lm%)mmGYmm)5fqmymG 2XGG)))x%YzzzY0Ymmy))Y)y0ymm))% % %GGmGH)G0))G0m0000m)Y$0H)m))mmmyy0yymmmy)myymmY)mx_?)mxm0)Ym0m)AlyyA )x)x0))mm)mmAmy)))YHy0yyyym)))PYyyyyymm)YHx0m)sB&+YYHB)myymy))))m)sHYmmymyyy0)))00yyyy)yYHHYGYYYyy0ymG*qlYsllH)mlXBHl)Ymm0m)X/g˕f|NH))%lBGx?=/g zBY0AOsxmmm0mm)HHm0ym))xgA/Xzx0msA/ls[s[ ̶8|Bx)))mmYHk)mOX/A?lY)yylAṰ[zxzzHm)Ys$TӔ```T 1xxxsYB[/Yx)BHY))))xl/[[zYsT̃Ϩssz_BsxYml[/8g0y)l== 000000sBB)0000)ymx))mmGGGGmYYmmryy0000m)yym))ymyymmm)mm))))m)?xmYmmlg?0HymHx0sBYm)mGGykPggg=?mYmG)YHk_yYAqnXы))mmyG Rv2 aGGG)m)%YlYmmm0)%)m?gl)yy0mm0yy %0mmmyHGmy000000mmxmmYsmx?Y)m)))mmymy0ymy0)Gmm0mmm)xml[AYYmmmYmylmQy)__Y0mHYmBY))mmYBlmy))kHYHHyyyyyHkqG)Hyyy))YY)m)mB&HlBGGymmmG)YYYlmyy)ymymPPHHHlmyyyy)nX)PHymm)GfnYYH km0Hmx譭YsY)0m)H|NNNNf*GG)m))Yk)1lնOss[?lYxm[[O[[mx0mym)YHBm0yym))xY[T̶s000mm)slAsx0x000xxBYTTY/lm))mmYHHmy0Hsm0 lHHls)0y YB[̭sz[zHYmmmYT$x YBHx/sm0)YHY))xGB/B=̶B ըgO[s[[BYmxՃ[O)sz= x 0000000 1x0x 0 )yymm0))ym)x)m))Hy00yyymyyy))ymymymm)))))BmxxAXmkmym0xBPGrarGP\fAlxYG)mGY)mml5k*H)yyrr rrrRaGrrYl)0myyy)my)))0xmxmmxH?nkGm00mYk)mmYm0s0m)mmsYx0Blxmm))mmmy0mmym)myy0ymm)msH//)xYY00m0Al0Hl0yyYYm0xssxx0mYlH0y)fff_PYPHmyyyyyyyk*GHPmyyym))m0y0y)Ysz&&lYHBlm%Hym))Hk) HHyyyy)y_lmYYYl0yymyXgmYYkHyyyymym5)HHmmqGym)mBBYYY)ymknnXNff5N5yym%q[AO/sB/նsx sx[[ضlx0)mmm)YYYz/Yyy)mmm[[[zxsxy0))m0mGsm0m000mmAslzYYmY)mmHY%xxYlx00xxmY)HY%0l/0))lg̭_?z_?Y0y))TTmx))0m)lPx0x00BYm0Y)m))%sllsÃsB[OYz[/1)sx[[ )s m 00 0 00 000xxxYxHmym)0mYxYYm) yy00ymmmymm0yymymm)Y)))))Bm[)H)ymmlxHHaaraA0BlYm))))m0mmH|ff5yGP)mm)RPIRIRGIPPBmmm0ymm/H00ssx0xGHHx00HmY0Yy0A_y)mmm0Y0_mzlm)))Y)mmymym0ymymmymmm0m)YlA?)_/0mlAlY))m))yqmmYYxmxYYY1)x)xm_m))yfgf_YHHyyQHkyPyyyymy))m))mmmYs&Nj%HH yG%y)mmGml_m)skHyy)yfHmYYHy0yy))AnXA)Plymyym)m*AmHHPy)mGy000z)sH)myyA5NXf\fHGy)/H==g[T8Yxxxs̶Bxx/sx0[))mm)Ysxllyyyy0x[[խsxmY)y)YYsBsm0mm)s/XY%BlBx))))YG)xsBxmxm)s)))sY0xyY? )m)x[A/xY0yy)mxO`Ҁ`T$sxxm0x000xY)xxm mBBxY)))Gx)HlBHs/s[| sxxxs/[BxxՃsx0[mz" m000000 0 00 00xY)lPyy0my00m)xmYmG kyyy0yyy)m0myyy)yymmmx))))))0g 0[)lXH)Gymyyym))YYRrIrrGG{lmll)ym))y))mmGn_PG)y)GRRRrPPHY)))myyyy)ykBYsmx BBm%YkH%xmmmmHsxPyyyyP1/H0l0))Y))Y)mm)0y)mmym)m))y0))BYlll_[gBBlA)0)Gny)Ymx1s1sYYx)x)mx_0ym)AnHPHmyyyyyyyyHGymPYYyyyy)))_H0yyGY&&sGYHBGG)mGm)Gy))YsYyyy)yy_-XH)YYsm0mmmymmm)m)y))HH)yyyy)ym))yym)m)yHy)mQqHyY?_YHY)mymyn5X\5NSGGmG_A뭃 $lA[l1xm0[Y0zT_xՃzz))))mmHx0s?yyyy0[zx xymmyymymHY0mmYHX*HBk%ym)m)mY)Y0lz0 xxxx0_?mBxmmkH myyl_m0m_lxHBx0yy00)AWBY)m0)mxmHm)Ak0xxxxxBl0GmGxmxxm0l?l/[ T[BYm000/x0zzxm1ZD 00000 x00 0 0 0sm00mYxmxGm yymyymG)mm))yyymy))))))mmxs)/PmGymymY%GRaar0y0))?Ymmym))ym))yyyGGmGymm)yaIRGaaRPsY0mymymmGGP[YYsYxsYxmkkH0 m0)ym1P)mm?x/XmYYmY)mmy0mymm)G0mGmmmm)x)HHY0mmBx_A/H0))PyymxYxs1Y1xmx )m))ymy)Y)yyknPHPknA)ymym))XlkqAHsB&G%YHY yyGGmG)P))m))))YHY)yy)y)mGm)YYm)))mm)))m)m)))))yyy)mm))y))mmHyqXfBl)yyn5f\\\5kHG[s0xAg/Bx0B϶ 0xm zzz$smym)ms0A0yyyyy)zzzxsmmm)0m0))YHx)0mymHB)XXllH00m0y%mYmYBsx0xxm0NYY0)lH0yl_m)mm)0ym0mx00xs0mmm00)syNmxx xx0 B m)HmG%y0GxG00lAgxl[s0xA=[Bm0AsY0x x zxD1 0mx00x0 00 00m10yyyx)m)G)myyym0Yyyyymm))))Y0YYGHaGQyGPYqYG)araarRrG)))HyyyGy)))))my)GGymYy)mGPraaa_mmmyGYs0BNH{Al0m00m)))00BYyGPyY0s0s))Y)mYm0myymyYmmymy))YYHm0?8lAlY))m)yQy)xx1sxY)))mYYmmm))Y)))YHmyAXXAH_XYHHyQ)ymAglB&Hy))))))))YskHyyyymmm)my)m)s sm0mmmm)m))GYHk)my)m0)))))Y0mYPHGy k*B)mY)yn\\\f5\nnG5gl0mX|?%m0l8s008xضz[z)0lmxBY0Yyymm00 sm0mYYz)slsx_mYmH)k8N8{ffikGHHkHGGB_Bs0x xsxYB?YYx))m)YYmmym_)0ymlYx0myyyyyyy00 x0xm0mmxY)%0%_lxxx 01 [l)B?GG%kYәXXN8B_B0x Ng?Yym0l8 00Ox䃶lzD" m000 00000 0 x0)HyY)yxmmx)G)km0yyy)00)yGyyyy)0))YY)mmx[0xYGPkPPk*PrIaRarGG))kyyym))YYyyyyyarRarPkyHAg_yYGGYYmz1Bs/8s)/Xn)000xm)m))mxxyyyyPyyyymx0/m0)x)YYY)))m))0ymy)my)00ym)l뷷H)lgg//As)mmm))yyBxxx1Y))0)B)y)))YYYY)Y)0yymnlX̷XHmYHmyy_NHYs &6HHHBGHym)))YBYGm)m)mGx)s0Hxm)))YYYYYHkHy))YHHHmHyGQQy%/YHmyyy*55f\55\fnϕz0)yBAG0B8[00ssz00Hm)xlY x[0mm0̭?1H0XYBBBYxY)y)GHHNiqyQ_smB 01xx x[mxxxmmYYYyyyyHmym)))))m)yyyGmymmm0lsm0)x0m)xm0//mxx1xxxxsAxY_yy BA[g:X|l_g?00B[X)0B8/0g1YOPksxD 0 00000 0 00 00kxy)x)mYm)mmG))%_lmym0xylXyyG)))))))))00[mY)GayyGkkkPH*H*araPP**Pyyyyy_HYsHllHHyymmQaaRaIra*_XGGG)B̭l?1l88mA?xm0xmm0x00)mmy0m0xlmAgB)xmm)Y)))))myY_mxmmym)ymPkHH))yHXglxx)m))yyy)s x1x)x)00YHBHl_l_$B_)gnA?Bll)myPHHnX*뷭_AnXm)GGPYPHHHHHB_k)0y0mmYYYYs m0lXsYH)kn*mmm00BzYx))0YxYHyyGYg/?y*Nfff55N\i5Nf\5q8_0mmmXGy gYm0g[Yzzm0mmmm)) _ g[)m0Yxm[ss00mlg8Axz뭭B )y0ymyyLN8qL5Nfnq yG?)0BsxxxxxsY0mBBmxYxmBHyyymm)0yyyyyx[x0m0mxx 0BH0xxx x xsz0)mm)A:`:XX%lg?0xm)AXGBgYm0g[s001> 000 0000000 00BAmBm)_X/)mm)my)ym0_my)mmXXy))m)))))Y)mmmxXlm0ryGGH kHrqk2k\qIaayaGHGyyqPy0y)m))k0yyyrraaGRaMIrq5fXNNyPYyl1BBA|Y0Hlmxm0m0mx0)m)mmymm00x))ml)m0)x))Y))Y)m))yX)mmmymyyy)sl Ymmmymyyml/lx sxYxm))m)) lBBH_[_ЭAmyyymAg/AXgg_By0mGyy))Hl_l_mm)))H*HyyyYYH)ym)lYP)Bzs00Y[mmmm)_XXX̷ym)[zm0mmm00zy0y)GyyGGG[8y)yyn\f\55Nf\nn55\\L?Y)yB/ly?)m [䶃[x0)mm))xsxmXAl_AAzBOح Y0ml8lxH/=Bl )mmmyyyqSqkq5|5iinXq*?mmBsxxxxx1x00)1xxYHYY)P0)_YXHG)m)yymx00x0Y0)))00mx1xx xY0m_k̙:``:nXN_8Ax0H/km?)mBl[/ s"> 000000 0 0zs0sAgl)xm))m0yyy0m1mP))mm))m))))mY))mmGGGaym)PkG_2rGGyyyGGHmYklm0?sm0xmx)mA̷m0yPGGmyyGaar{-HH_ggA)myaGa G0B=s1x8xBxmmmYxsx)0sY)YHHYxBm)mx)YY))mm))mmY0Yx)00yymys_sx)mm)yy)Y? sY s)x)mm)ll)Ys)m BBmx[l[ABmxyX_H_ggXl)))yyyyyyymmmymym)mm))?lsY00mYqqHllBBs0[[ 00)BkngXmmYxYs00xx)mm=l0xmy)ymmGmyAlmm)yy*Nf5i5if\\fY88[AlXgX)lY))H/=[BBB sY)Y lsx|=OXAx0m_gX_/lY)lyyyyr5ffq NNNiqmszYxx1sxxx0m)xyYflYmY0Hly_NNfXX0myyyy0zm00xx00m x111xssmlԺg::A5XHg/H0lg)lY))g[z=[0 sD> > 00 0000 0̭smHxx)00mmPB)00Bmy000)mH0yy))m)))m)))x))))H/lGGGyyyyPkmna)Gyyn)m*lmy0ys)?Hmmmx)AXXkgPym)yaa(qn/mX|_0yymyyG)1 zY8?YBByl*y0llxm))Y0))mm)l mx)l Y)m))))mm)m))Yyy mmyyYyYs)mymy϶ssxmm)Ylz))xA/sBlmmlA//lXHY_*yyyyyyym)!yym0y))yymmymy))m//1=)Ylf_?Jzm0[m0lXnAA_ss10xxmxm0Y/smlsyyy_n[Bl?HmyN5NN5f{*q(ffG8)ggXgl)))Ylgg[Oz00 _Y)l[zBX̨g̭=/Hx0g=-̷BG)5qfN-**{Ymlz11xx0 x0mmxx)XglBs)y))))HYXgfffG0mm)yyAHYl10m0)YmY0x0xxxx11xszl0{Hg::TgTANXXmg| mgg̋)))YlXgg[Ozy D>>>x m000 x1x000zm 00x0Y0l1")y00m?1)))))m))))mY)0_gN)ymxmPXmmli_m̋00xmmBym0|Gmx N= 00/Hmmx0_n)_zGG XH))0y))aysx0 s1J|/ls1mAky0 lPY)myyyyyymY)/NOl))x))))))))))))Hxm)yyY_x1Y)0xxmxJxxxmmYBsg[s s=z$[[ly_X_Al_AXgyyyyyymy+yyyymx)Pmyyyymy))0zs1Ŷ$BAkB[ JY 0B惶l gXqgggXBzzx0Y sm011A0m))yH|lYlYHymGyN5Xq q(*BOgY/l)y))))nX[=Bx B )sY ?XTOl/zz1mN=0z8-/Sn k*Gyyn|n8{Xq **q%s/ 1s1sx0mmxmxYY?H%)ls))XXPBlll̷x?=/zBY))Bm0)mm0)xx1s111 [YB*] ?A[-ii5Nn_yHg8O/Alm0))))gX/lym00E"xxx 0 sJ00x x)mx)xm0y)mg؃lyy0m00)0sB)))))mm)))xmlmXNHGGy0)0YPyXnymG00)?ll/mx00)0GYmx_lN8xYH m l|zYxYnlA_)0)mm0Yk00)m)X)y)yG)H[J8zJs)yl100A)yyygXkHlY8NXmk))Y)))mm)))))YlX m0x)myPPysBxxPymB0 1 xxxxHB)m00z8OzOzϭ[g yYll/gXyyy)yy0yx)lyyyymmm1/zsz[[lB[xm000/[ A/nAf|fg涨 s=x [00mXmyHNXY)myy)HHPnXfGrq* 0B_)|zm00mmym)y8gYBxYYsY lz m00xA[x0xsxxX Ym[|8 -/ r%lGQyyfn)%%_{{AA[/zsssJxsxx0m00ylzYBBHsYYXnAPgHl)Ys/s0m?mm00mm11Bzss/{{*HYYs8NN5yYBlN|z)m0y)mm)yXOgzYBymmy0zzxxx0 zzAsx x[_s)m0)mmm0z00ymY))y)))mPy)YB)|Nymm)000Y_mllzsz_m)0xmBY/NsX)1z ?gglzl_Y0))xx00_ lzl_BmxY00x)00ymGlXN8?YsYAYyHyyyyyXmNY)))))mm)yYYyyPyA)mm))y0mmYPYmyklm))m))))m)))s[8gHy[Bl_yynGk**qqkmyyyyy)m)mG))&m))l)yyymymym)PYYH0$z_mxzxm00gf_=OO=zs szs ?lx00)x)0ym0y_/mmmYBlkyylB%%xHlYGxmy00BYss1x0)mkN|B111x)00mz00BzxszxmYB l|_-**{0myy558lB%H{q[A/X111s000NszlYHlBHYmk|N?X_)y)H_H00 xs1?1H{SSqn*nn2qsxss/NgnHm0HYszsx0xm)kN|z11ym000x 1 x 0σ涨1 s0m0mmm0mm)00000xzYxB0yy)00)))m0yyYGmYfHyGmYmx)xs Yx _lx0mmx00mB=zz8[1YYXzgAHBYmA)m00mxm0mll_Bxl[B00m0)m0myyy0%gNsx0mYm))HX00)y)mGyyyym0kNgPY)0Y0mm))mm)00yyyyyHl0))mmy)YYHmm)mm)))m0)YYHB$[T/mmm) gkyyP_GGGGGymym)yyy)Gmy)GY󌓟Um)PsHY)yy)mPH)PH00z$؃_xss sxx0BNnlzm x 0[?BmBY0syy)yym)AggY_lYHllyy*%l%%H)HHyy0Y 0sz s))ym)PyH/sYsxszsYYxm0BXlBxsB)[|//8XXn{%B{Y0yyyyG NNiB%lHynB/ 1sxsx/Hm00z[B_Hl))yHll)000ymxx1s[A* * *r_1B5X/PyH? 0sls1))0y)PyYgxsY0x0000sxxmm)BYslBxxz[0my__l)sl[[Aymm0))y0)m)mmmyH)Y)G)y%myy)mmxm0 YsY)00m)mm)Ag8_%0Yl0OYmmmmmmyy0)000m00000xmxmmYY)y)))G)mmm)l x00)0)m)X_)YG))yyyyymyHlm)mAYmYmHH0m0m))))0y)mmmm)ymmGGy))))myky))Y)ymPG0k)000m_lYBB0)))ABY)Y0)mmxmYYHBHHHY)yyyyykXX*)%lHYYYYH)my)my/XXYHHmz _HPlYx0x)mm0 Axx001A̷z$1x xx x H?Y))l)mmy)ymm0__Yl)YYHHHmy))G0)BH%̷m)YYyyy0lAY0 ssx)myyY0yl0x01xsY AAlm[sxg_xmxYxBHx)?[Agz*|8fXHm%_ymyyyfNg?xYBGX5N8JYx?0)0mxs?_BBsxY0x_zyymyyy0y00myymyyymmxY??*r]qQGlH xJz8gfmY0xB Ys1x)myyPy0[Bmx01Bm0y000s[B00m00Yl00000xm00)y)mH)A[Bm0mm))yYm)m)0mm0Y*HlH/|HHGGmmy0m))0))mmBlsYx)0m)YHY)YY?smm)xxY00m)Hl)my))mm0mmx)0sx0smmYmx)mmGYm0)xmxsYxx0y0BmmmHHHyyyym)y_l8_qHY0))0)))mPyyy))mmyy_Pmy))kmykHyylYyHPGYnAY)my)XAmYYYT樨msGx)x H0)BY)Y YYY%Y))Ymymyk5|qmH&#nPsYYlmy)mgfm)H0msm0HPky00xxxm0l[s1m0mHlsxss 1xx 0J[s00mm?m0my)y0)lB))g?)YYYHmyym))B)x))YHyylxx lz )0mYYYl xx0)/0xX0Y_m0m0x00_xx[/AlBHqX{lY)m/ym)yyy)nXX?z xYsqfXN|8ϭYxxY??smBm01 lB??lY)m)l_Y0m)))))))))))YP)YYBsxY?%m*I2rQBz?X_)gffXP0Hglxxslz )ymYHYYXlz 10x00000HBYyxH_mmmmyx00m)ym0y0y)yy0YH0mm)H_Y)mY0)0000lYg888_Y)))m0Gyy))mm) [A[lY))Hll)my0sYYzmmHyP_))GmramQHx0z 1z0mmm)YYy))mm))Gm))0mx)yymyl*myy0ym)_lAN8=Bk)m0y00mHHmm)HlHPyyyH)0)Bs0nqkHymyk*yyQ*nA*Y)YsA[YYH)mx)m)B )0 [[zA_B%m)yy)mPg\gf)H!kY0mAlmm)ymXnY lyB 0y)m)00zO1"1 0m$11 m0000=Bmy)mxmmym_/Yxs_H Blmmyym)HY%sYGlyyyY lBxyy)HHY0lsssx)m0?Y0m=YYmy0)xy[?mxgl*lkkaH)gmm)y)mm)mm0 [[xy_N55f-_x0mHX)x$l$B_/A xxs xm 0))m)))))mmmmmm)mYm0))%lGMoIKrQr*aYm%z[AYmymONly1BzzBxx)yGHYzzsYssmx0m00/)0GyYly)m))mm0yy_kmyy0yyPH))H0)yAAB0mmmYXf|||8Y)m)m)Y)y)m)mmmA[[ 0l_Xg)ymmHs0x/JY0yPyXymq2mBY0sxxs)0mY)))Gy)GY))m)mmxmm)mm0m__lyyyymy0ymy)HAs/NN8|8Y)mmml)mymm)Byyymyl0x0?m0)mlN5yYG)yy2q**AHmHH)Ys[xxYHYPlY)xGs)z[$T$ [X///mmyy)0GPHH&Y)HH0A_0mm))y)ymm)mYl /BxmPf*y0mm00zϨ1 11 xmmyzx xx0 0lm0y)mm)mmymy)nl))x)YmYYYHHmmy)mymsYY)YYHmyyy0_m lsl_mmymPHY0A[lm01)Y000y8?s00%YHmyY[sA X/*inqHHk/NY)myym)m)xxzxm mNNf55ff?mm000G/NmYTX[sxxxz xmsm0yyyyyymyymy0mmmm0m0%a*oIIrMaa%)xzYyy0y8Nȷmy[m lslzmmy)H0A[l0x/x0my00gGmYH0ymmmmm))mX0yyH)yyylY0ym0H8Nxmx0myHggB Y))_HY_Yyym)0mx)s l Y)s_m0)/8lAyy0Y0sxPknPy)q m%lYxmxss1x)xx0mmyQGH_HH?H))xYx0m0)yy0H_Y{H)yyyymy)yyyyY_l 1A8XYmymyx||y0y0yY_)yyym//s0Oz_)nf\GQyGyyyQ2*QG*nqyymm)Y )YHHYYY)Yms)lYAx_?*AYx)0ymm))Gm)Hl&&4ymYY0llmmmm))mm)m)xky_[sHy Qy)m00 z=D>x 0xmm >1> x0 00l=my)m0ym0mlyxyGmYYYslYmmy)mx)mYmyyyAYYYYs)myHY0ضlYx0mm0))lB00/x%)___X-l/XB=?*qnHl)%g/Ym000)xY)xlyqNN5f\\5Nf0Gm0mn/sz[OgX/sxm x[x xmmy0mmymmmyGQv]eIeK %)Bzl)0yymYNf_mmAYYs0yymHYY00[lB0x00m0X_HY)ym0ym))0mm)y0xY)mHymkGmyyymmշmyyy)l8xymygHm)))BnBmHB)yymmxm ssx0HY0mA/_lX|n)HYl[B)))y*GGrPH%_Bx)xxY1ssxm)mmmyyGBHmHl)mmxmss0mm0y0l_Y_XyyyymyyyyyymYsm00 XAYmymm0l8l)m0000n)yyyymY=0x=[BmyyQyQ)mmyQan*Hm))))Y/TmmHHkHY))%B0g[Y*** Yym)0yyyy)G)P&))Y0B)m)m))G))YHHyB[xY_GPyym)m0 Ń1 )1"1 x0000mymmY0mm)))000y00mHYH _ )mym)_km0)H)0))Y)mmGYY%yyHY0[zխm0yYg 0x/m)Gy_fgll[|NfLnSn{qlkkY0_mm0m)xxBmmYN85585mxm Q %[Ogg[xxx/xxxsm0my)))ymmm0mymmmQKIMeaamB_mmm)|NNgmmmY)xm)YYHYY0[zխYg)0m0mlNNfmmmm0mmmmmmmymmm0_BlmmH0kkmyyg)000 /[A00yy_nm0m))ms)YlY))mxYxssxsxxlm0_ /[[gk)mmm AByPyGGYHsYszz1mxsxYs1YYxmx)%lYmy)YxYx0)xss1H0ymmmmYyyyyyyyyymBsx0lm008XHm0ggmyym8s 1=[sm0)yaG HYG*ryQ*qG)HYHB[x)BlBPHHH)))*0)/AAgkY%mxmYHHYmHHP)))&ɉHHk_H00lBx)xYYHYl%HkqqrB{BsHHXmmymmxm ŚE1 s1 >x0 0 xymymm)xmmmY)m0mmymYH?s0x0))XAHP mym))))mx%HlHP))?B/szx00mmkB)0XXl00//mg{)mlX8N5\\X{B)Bg_m)BsBlxl[Y)mHP5NNN5f5fH)0m%GQ*q/X/ gJgO/lm011sxmyyyyGHHHYmmxm0yQQ)GmmyyQMMo m%)1[=lxyyG|)))m)HlH) [szxgAAlmm0mmkX||XY0))mmm)mm)m))0)BlmlH)HH))ylX_0xBlllBxk/AB)mm))xmYYyY**0)x)xxxxxxYmmx0xl)))m)0H)yyPGPyGyYYzx1x)xm)?_myGYx))0mxsx 0xx0myyy0)YY_Hyyy)myyymlzxmx0m_y0A88))mlg/yy)lO8歭s8=Bm0yqHkHHGGqPGaakPHPkHHBllHAxBYHHHsHHYY))xHHkY)Ag[g**G))mlllyH))&&!#4YHkl1Almm)))mmHH krq*l/AGGHYymm)mxs1lH >x0 00 z)0mymyyyyxxH)0mYx)0mmmyl__0A_Y_A_/A)0yGymYYYYYG%l_ll__Bϭ0mxm0_NԷ)8[m0Agm )x?O/XNfffff\Nn)000|X_XOzsBxmyyy\N|5555ff/lq*0\{qNN?lgXAlmmxms zxx0mmHHY))))xGH?kyKeoMRMG s01ssHHN_myYYYYYG_l__Hϭ0mx̷xm00)x0ym)xxm)m)))0)x0Bl0msgX/_YHYyyyyyyylBBsYs110y0yy?l)mm0)))myBly0G)x1xxxxz0mX[sx)m)Y)mXXmkGmyyYs1zxxxxY))0mBkYY)0mYxx0mxxmxx00mYmmmm0?*lPyyyYHmy))xBlxxx0lBmm0z/g8l0)xmY[l0mmy0B/N=s Ozmm*HGm)lkGGaHyQykPy0BAl_PBHHHHHHHm))))Y[ YYmmm)0Yy0yyy)&64B0x00Y̶lmYBmy0yGQGGHA_0yxmm0xm1#"ÿ"[sz x x 0 zx0x)0my)m0BmHg)?gXA sH0ggAHHl/)000Ym0mmYBHBHHk__Hx?sxmxm0YYm_lm////Y00m)0_ggX88NNf_xBBgOBN/)0yyN5fN55NN|i{?L8NN8?8/B000xz0xmmHlHHmxmyQGkqGQ ooaIam?x0x[k)ymmHHHHHk__ )?sxmxmx0mm)_m0Ymm))mmm0?OsH8|?lHmyyYlAsm0m)yPGHmmmm0))xs mmm_?0m)x)x)xx1xx mm[=[zYYm))mgymyym Y xxsx)xm)m_H))m sxx)mxxxYxx x000)H)mm)llPGyym)HH)y0YHBzm)yy)zszXն?l_[Ym)m)[OOzOOzm{2qmG?HQHyGyy0y0lխl_Hll/lHHHH))xm)mmxx X[mm)0m)mmm)l0myy0ym&&[[)mx|gB_mm)Qa Gm//gHy)Yy0mmsûû1_x x x0 0xJ000mm0my0[8/lH))?lAmY)_gA_ll)X88g8XgH00mmYmmmm)))mmmm0m0llY1|g_mm)ymmm)X[g/lxxx0YN|gXXX8fN|n*kssA8X Y8=lBx0mymyyq5fNfNNNX{qSnLg|N8/88?̋%%mG00 Ym0yGPYklk)Y)myQrMoRI MBi?lB 0zm0klP)mGmyG))ym))mymmm0lzY1?s00mxm*/xyy)YB0))myx0NglA|XHkYykg?Y1 mmxmmlgn))))mm))m)zmlXl0mm0m)xYsss xzlxglmxYm?mXg/)mmyyyy))Y1zxxYsY1)xG)0xm?)x0YzY)xx)m))Yx00xmxYm)YmY_lHPYmlm00yl/ll/0)Xnl0sY [[ϭX[xm00xl8=B[OlYmyy/*k0AB)88yH*ymymy0YAAHB_ YHPH)))m0mmmmϨx xmm)m)m))0)yxy&B=0B̭_/Ymy0kPk0 BG0kXgOϭ0mxHm0sxO##1>zl 0 0 xx [=s0000mm0y0x0sN/x_B)Am0_/A/?mf|gg8|NB0 lxml0)m0mmy0m)m)))0_gAss8_g|AYxs)0m)yy00Yzs1s00mmPAA8gglH%HsBT[YgOx OxxH00yyy55NNNNN88q*]q|N8LnNg?BB*k)1[1sm0PBll0Y)m)yyyKKKoK{sYs sxB BX?xmB)m)mmmy0mm)m)))0_A%s8B?_mxHHBg mHY0my))0x0gfXHmHXHklyy)B xxsmmY)m)ymYHxmmm)mm)xzlxmmmmm))msYxsBxz̭YmBY0m)0mxY_)lAgggGY))YyyyymB?[z1 sYssYmmxmm)x0Blxxm)xmmxYsYmx0sm))x) mHlHk)YH0m)my)H?gXXHm0))B/zO[Y0YO J[Bzs_Bn?)m/HmyAyyyymmmmxXgg__AYBPPmmmxm00m0zzszm)m)ymmy)m)y0y))myy&6zx O0m m0sglPkkPGHymkY_A)xOlsHs0 #Z[A0xx xmx x xlm0xmxmy0ymxmBzm/XYlm)?lY[gY00YAgN_/X|=_YxlY)m)00mY))my)BYgzYBsBxY00m)ymy00lsYx00)0XO88Nm)GYHlg[YYlxxO YY?Yyyq5ff*GqrqqnlX|/XAg?y%حsmyyPHk_kHmm)yyQrK]KKK {XB sgX/mmm))00)x)mmBYgzYBm1O[_ylH_mm0)mymmHmm_PyyG*g8lm0xx)m0mm0mm0Hm)mm)mx ?0))mmmYsY[[)yy_))mm0)00XgXgH0))0y)PBYxϭ Ys1)))))x)0zX1B)xm))HBmxsBB)Y0s)m)kY)_Bzsm))H%AXiXXn%Y)*? 1zzxzOJz=8A/OOYYHmmy)kHHm)Asls)0G)mPYmGP)))yymmy_nԷ?Y)xY)x))m[l))my)))YlYyxmm&&s1x[Yxx00m0mlA_HGQy0xyyYBmm_/%Ys#DꨶYmx 00xxx0x1)Y)m0mxszm0mm_/?m)BHY̶H0mmyg8[Yx[glxmmmmmmmmmxHy_X[zB0xH x0myyyymxx1mmyY s))G%Yz[ Tx0x=[ 1B)myPYy rqN__|Nf|f%lH)PA̶ 10xyGPHk_lgAlHlm0QyQaK]KKK l)/==樨=0[zYxx)mm)0)mm)Hy_[zB0m00s[YH0m AXAmY)ymsY)HP)kkymy0yyyyGHXX-BxBx00m0x0mymH_)m0)m)Yssz/glm))Y)m)m)xs[0yykHH)x0mm YA뷷з))xyxyYH00x[xx)mYml/lYYm)mmyH0mσ0m))H )xYmlymA뭭[BsYY%H %H8yYY?/xxsY0xz̨gABm)mYX/ggzA_BkHYY)Yyyy)mm)))NgA/_x))PBH)xYYmx?O[0))mmGkklHlPmyyymyyyy0&Bxxحxm000myQyyy0yymx)s?/X/z?l00h >0xx0 xm zzssxY Bxxmm0x//1m00ml0Ymm0sx0m00m8_x0z0N/l))0)|mmx))H?nlm_B00m0Y xYyyy)m)Ysxx YYlyy0xmxszlBG))l[[ YOO[B [ sz[m)myk*fqGG%)ykf|AlBNNlB%nnx0s0yyPHHl_HNlylHYQQQo]K]^S]{kB=[s xJN/Bm)0x|?mm)x)H*km_B00x0xx0x0mmm)yymx)mm))mHGy) rvqrGmHl)mm)0xm0)5NnGxkKQQmmy000yyyymymmxsx8/xm)m)Bx00 ssxsmmGGyNfqX//[?mm)) s)xxmYxm00xsmxx xmlB)))m)/g881x0myAzx1 xxmxyG򋕋Az$xxx l?q*_XXX|BBBx0BY1xxzB0Y"Z=z/sxxm0|O*k?_HHlHyym)yHkH)PNN[lx))n|xHHYHkm/xxx)XNfNnHPYymy0y0my&+smm000yymHsxxx%%%% mymm?[smx0mmmlBB1)x Ymm00 0000϶ 0GmyyHYyXm00)|l)HrPHl_BHxmmxNx)xxlx0ymy)m)zzs1B)0)yymy)?zzYx syyyymgg?BsY%s[OB:TB%0mxyqNglx%s0s= s1 ss1 m1>1BxxykPP_kAqHYYmyQym*ll?Y0BB0mlzJ?_N_s)xm)=Nxxx1x0yyyms1x00)mm00myyyYYx))mmyk_^Py[XYmmm0mnn*)m{S]]SSqY0mmy00xxxAzYBxmmm0))0)xxx Hm0yyyNnPlmm_xxYxYm0ymm0B0xxxxxx)))x))xmmml B?AxY1x0Y[s0)xxmknNz1xx?nLnXgN/A8AsYzYxxzllXŃD"#[=gжA==sx08/l0yyy)%mmly))mPA*yyP_xYmHffYHHHyHmYxmmgN|n)yyyymmyyym)&&!Ǩ=[sxmmyyyy)m mxx %Gymy0Y[xxm0x0mYgs BBYxHmx))0000001)mY)_yAlm000x̃Bm k*l)l_B8O?BYxxmYNXxx %zBYm0mmH_zBxH)m)y0m)Y x0x lymm)y_YYsY_жW:ә`zYx0 0$=sy58glB1 TT=Jzss 100g̨z1 myyGPPHk\fyyAYym_HmylX01x0B 냶_l_ )xmsgNx)x %BYm0m)m0 ssmx)mm0yyyzHmmx0)00)0)msXnq%)m)l[l))m mXgf{PH Y/q{qqqmmm00ms1lH0))Y)mlxm0_XAlPmxmmm)mxmyyQyyykNgA_100 1 00x0my0mxymxm00x0sBxYm))m)0y00m)x)00YBYmx%yYg smxsmYB{Hgm0xssxxxH8n|_?[xYsYx)zggAsm"DDhZ=A_xσz x0glm%mGGG)mmYY)lHk0m))))my))YlBm)NNX)YHBHHnHl)mmXyyymyy0ymmy&!Tض[?mm00yyyyyyyyymmxxmmG GQQy00lx0mx0NNNAmYBBHl)m)))m0000 0xBx))ykB)[x0y?0%kHPHmBYgN x)m_|Y)xBJY)mm)yHXHBsmm)Hmymyym)y lxxx xx)s))m)xAzBsBsB[= /y$Wgsx0m0x[Bmykll_lxYՒTcc=W [zzs x0BJJzssmkkHkHH_lNfXHAlxx0ks=0 ms=XHsmxmzgNx%x?s))my)ylz0l)0mmm_Ym)xmxmxmmA*2Y%Y0YYsG0ml_Pqk ?S qSy)m0))0z/lxYlHmy)mm)A /?lAYy0mmyymmyyy5X00 0 0 00000mm0mm0m)0x00xs x my0mm)mmmm)m0m0Yx)xyyy0xs))0s1xxmm0B8Osmx1m1m)%lqXqHB_B/[/ xmzl00000mlY0xZE"gl̃0g?))mymG))YmHYnny0y))yykyYmmq_YHHHX_k_)000xxmymyyyyyyym)ymymym&!zB= x00)yyyyyyyy000000Q0QQyQy00xmx)x)l_ msYBBB)mymmyx00 0 szm0mm))nH_00gY00BY %xHs xx|x)ssxJ%?Ymym)yG_)msm0x)y)ymmBlYs1xl)mymmm)m)0)zBYY1?Ogx yWڙT?00xxYm0y0)?Amxx =W؃1=ssBx1x0z[/JssHH_n|GyyY0ymm/_x0)0000x=8NBBx)8Yxssx?J%?Ymym)m sY)00m)00yy)0m00m0Y8AN*q*%HYm0zBx0x)HNnY[HkHm0mmmJsB_*)mmm0_)YnY0yP/HyGyyQyynN 1" > >x00ymm00m000x xYHXnPyyy0m000mmmmm0 yy0m)G)yyyy lxY0xxl00)HB|XmmmY/z%Ym___TxmAm0mm0y0xDD"hJNzxT Y AAyyGGGG)YY)HkYHkym))Yy)m)m))))G)))Y)YYkHk_Yyy00yyym))ymymm)WΕO/YmB?)00yyyyy)00my QR%G%QQQ0sBm00m)m0xm)YYl)))y0x 0 1 )m0mxHylH)Xm00̋?*kqBG%BHzNOlBs)O|HsY)0m)m)mym)Ymyyyyyyymmm)z s BkyH)mmm)x?Bs%ssym:xxm/_x0)m)m)Ym)y0xmxWWs/xs1mmyH[kHkHH*NX__)yyym))m0m01zsm0yx[= 1xzs88z s)XONs)Yx)0m)m)msA_m0yyyyHm0000x[A%{*{HY)mmBlm0m00xnqkAHmlmmmm)z?Yyy)mmm)YYyymHnX)YG)yyQyyl| 1z""> Y m)y)mm0000 xx0lnXmm0))m)xm0m_m0myHyyyy/lx0mz/y0sA/nA?BH0ymlHH{n_/?/=xAAmm%YY=dDs [/sx1=z [X_)y))%mmY))l*mmm)mm0lG)y0)m0)))))YYHHHy)H_))yyy00mym)m![xzOҭYl)yyyyyyyyyy00 %%M%GQQyYsl0))0)Y)Hk)lPHm)0xx 0 B))ym)k)yHy0|Xm/Bxnqq_Hx)BBs8Ns s[gNg xB[Bxy))))myHm00)yym)0l? zBBl0_m)mmx0l_zx00B=l`:`TTTzxxz)0)mYYmmm000 O`WWs1xm0s0xXmGGPHHnNfXHlGyyy0my?_ Ysx[Bxsy= z1sxxNs s/gNg xB/Bx0G)))//?Ymmmm0y0mGmmG))lXYYl/_H*gGm%)0)B0000m/gHXl%YB000mmysk)))HPBHxx m_)yyyyXXnAP_yymy)yyHfJ > 1"" 10s)0000m)x0xx z[BAnnH0ymmm)m0)m0)l)HHyyyAAA_0 ?0Yl[AP)y)mmmYl kBnin{nq{zBgHngg*B_B%)OzŃxzض xx=z 0[=lmm)Y)y)YY%mY)Hl)l)lmm00yymHHHYHkGHngXkHk_*nn)mm_))GmmBT1000sB$YB00Y))myyyyyyQyy QQ M % R%RmQyBm)x)mmHlHBlHHl*_mH_mx)x1 01Y))0y0mPHP)0m?1)?-/q_n%)Y1B/N=lss/gB%1Yml_lH))))Gy0YBm0y)Y)mYm0_zzzH)GYYYHH)m0))YmBkl?=B[c=O?YYYl)y))YY)mmm0msc`cccOTx xssm0)/mmymGPqHnN5NHyy0))yymYX/B00[z0y[1 zsz1x1N=lsY/gHY1Yml_lH))))zBm)Y))x)m0yyyGGG))m/XlYm_XHki*%)%m%Ymmm)g8?mgH0? H0)Ymm))mykyBks19l)myyyP2nAGGyyyHfJ>ZZ 01BYm)mx0x01x xlnHm)mm)mmm)m)x)xnXqHrym/8XXsxsBsl_lg_y)xmHkqni(fNN??=/[klggN))ml=ؽ1z=խsx$ x _BmY)Y)YY)Y)00Plm)HYmmmmHkyymmlklHlHG_gk)m5ffmx)Yk)mm))Ws 00000x_mm)yyyyyyL0QG %%%QyyYHYmmmmsHBllYYkPyk_m)Y)1 x 0Ym)yyymGyy)YmBA_1_/?B?YHBz88sBgNlsls?sY?lY))Y)Y0y0msl$ymXL)mY))lYmx[YԒ`O`$|)myy0yy00 $sc`ccs0s0x lsHYYk_BmGyGPGqP|NfHmy0myyyyymB)000[sy[zJszJs0B88 BN_sls?sYkY))YHzYx0mxl m)smm0m)m*kyy2aPqqXkPGm)m0gN8sxx0/m s)xm)yYGPyBBlyyG*_HlnGyyy0yY|ŶJ==O00 z1 xx100)mx)xxxx[Y/Xk_Y)mmmmmx)x)mm0Y5f*yy8|gAz00000/AfnkPY)0lnXL\fNl/ m)gXg?x%/˕X[Xgg歨=zxz zBx)x)s)YYyyyk0XX_Alyyy))myyYmm)mm)H*XnnH)?fNf5Xgym)lHY)Y:0)000mx0)BlmyyymymyGG R %QQyQ*Bm)mymmH[s111> z 00x)xy)yyPH_H zsY?lBYYssYBNlz/=8l1xmHY)mxm0B)0x000)y0)xmxB_sssmm0Hk5knxJh[Ox0lHGGyyyyyyyPPmms1cxx)x)xlHBlkH*kmQyGPyykGr\)mHBm?gs*m[$ZJzs 1sNz/g8B1xAYm Ymmxm0̭l)0?_0xB__)k{)yy2*GG**{aGry[/%0z8g% Y0m)m%)YkHGyyYB1_HHHPmyHq_*nn2kGGyy0yNJ==z10x?10 xxmm)mxxx[s_/lmm0mm)))mm)xYf\nayyyyyy0|8Azz )0mmxkHlAm_k)0m5\f5N\fNNLA[̕/?)mmH??g=/JJz䃃sB)Y0m)m)))mmy0)PYl[msB0y0yyyyymymmyy)HngnX?ngAng0YYYAH)))Y xmxxy00)xmxYYmyyyyymmyGQ K RmQQyY)mmymmmmyyyyy)/B1 1 1zsx0x)H)yyyyyyYkH _B?_YBszls[zzl/Bxs/0_l)mm00/[l0[O/_k00llYxmmgg0x[B y0Pqf5|2H00=xm00m)yQrl`cWz xm B0xHHHlkHllyQyQkrqqk*Py)?kmyym01̶mm̨Z11x xBBs/=lB/Bx𭭶/_l)mm00O/llA?/0m)my%qR2qn*rrryyyG s=/HB_syG)YkHGylG%*_HPPmmy0yQ%mmqrkyBlmygϭ[m)0z1sxxYx)mm)xxx B000m0mm)mx))mxm0mB_Hyyy0m Bl/̶mmx0YY_XH00\|558XX=l0yx%X/8?A//[JJ sx[lxzxYxYYm00Ym)HXAl_00A00myGymmmymyyy))myH_H*nXXABsxBBYAYYY ӒW BO m)0myy))mmlm)mymyyyy)mm)yyyy) Q% %%%Q0Qyyyym))mG)mm0yy)yyyyym/1 >"smx0lm)myyyHPB)xJBJz xx/樶sNz敕8|gl0x0mx ̭x0[Bx0y0_lx0[%x0sHmmkH|NN|NfGH1 DB))yyGyyGGl/بx0m GlmmHkkkkkyyQ)yayar2qvryymymyymmm)ys xYx涨BNl敕8Ngl0Ax0mx 8gBsmymym)nrkGHGGarGGPPyH//Bm)mm0mm)G)GyHAA/[?m)myyyy*kqkHyy?lGym[s0Yx)xs[zs11m0m)xx0s/lxx)mxmmxmxmmYs ?BmQ))yy00)Y0z=Y0m0Y)HHkyykB *nNN5XX|Nsy)xx)///̶mz J=g0 0mx0z?//)sBxY YmymYyyPHsllx))H*kGG)mmyyyyym)lAGl5f5f_x Bl_nX̷YYHYBl_AA$Bx1Bmm0))000mmsm)myyym0y0yyyy q% **xGyyyyHHHk)yyy0m)yyyys "xxxm%mmkPyy))mQyHHH?/J?Bxs 0xxY/[zxBx[BymHxmx[01=[Hm0l/$xxAzz10GkH8|XllklGxxEEx0sxsYx0mGGyyyG/z$1 /{X/mYHklHkkkkGmqkQ 2raaGGmmmHHyyyyQy)Hk))m)ym?浽 x m x///zxBx敕[k0mHmmOAA_klmm0m)sH0mm)nlnn/%aPkyy2fXg=0%)mGGGPYGYPyGyy\XP)))0yyHkr Gymyz_xmyyyzxmm))/zs0xx)mxmxx008Yx 1m000mm)mx?syGyysx)Q%) 0x[l0my0yyy)m̷GHHkAOgggXg?Ym)x00%1%m0y 0 ?=lx 00kB*XX[B mmyHkfqXHO[x0zg0fLkl%ymGA GGPH)A))NfffNf̭sY/gAlBHHlH_BxGxm)Gm00yy000Am))yym)lYmmy k{*))0yl?Hmm))YYyyyB>=xYmm0m)klHy)yyyyHH=̶x0)mYYsX/zzB1xxx0B0m0_s0sz=zzsz=|=lxm0xAsO[z[B_lx0Y)Bl[lszl0myy>"UEj=ssY)mPPGGyyyXXH?sxxmxgLqHkkkPyykHQer]2]rryQymyyyyyyyymkkkPmmmy0m_/ = 1 xxxszzB1xxx s x0m0_s szBmYn___l0ymmmg_Ymmm2XlyNf8OxxxH_?%mPPY%YyfXXnyy)x00YyQXkPqnrGa)ymm0Qy0BBxm000m[88[x0xxmmmmx)x0[8Bs0000000xmslzxy**yBAmm)HlYYm)1xs B0m)00m%)0Y88O8m0m)0xYsB0my00 00sl0x0YX/_kBlsxx)m)PmYN5nY_00gsqX\5?HYmmP*qqq_klklglYkf55nqmxY/XXXgXll_lAlss x)y0ymym0k)0mGHHkxmmmQG%l/kxmmmyyymmm))YlYyyym[=J1 s1 mmG*kkG)yyyyyYG xϭsx00mmsss1x z1x)0m0ls0z8zO8 B0mmmBz_ s00BYmmHz_?gO[ xyy"dN0xY0y0y)PPHyyyylAx0Jsx0_f|k*Hmyyryaaa rIav\(22kGGmGGyyyyQnAkH)))yyYmmx0xm0x g? ss1x1 01)0m0ls0z|=P)yY YmmxmBBsxxx0sNBmG)QyyYBmm0X5ԋGGPPPYBaPyykGPXnPyyx00xHyG22 vPram0)̭l?ByyYx0%)glsx xmxmxm0m)X|[z0mmm000m)x lzY0l)mx)m8?lmssxx0yGY))H)y)Y)))))Y zgAHymH)))101%m00m)my)0xmm)x0mi|{qkH0mBxxYxl_)0ymH5gYAO000YYslf5ff?_?k5qk0)A)m)mmymGkH0σ[[m/|g___$[s0xmmky0yymmy00)yAfs)))mmy)mG)YHB Y))yQ))mHl*))HlY0ml8zzs1x0qq*kBHlPyGmGH00B?AxYY)yxmB[zss xxx?z)00sOO[ O_mxՃzzYs00000x)0[88 =z10zZ 00)Élx0mmyyHkkymymm)myyyX)slBsxmkg5n **yy0lkyQrraar2(vGYHyyymynlP)my))xz0x0)mxssssx xxz[)00B OOyPm0mymx_zx BYmYnfg/sG)yy0)xzzx0kNlm%PPPPYPYqPPGql)Yx000ya*22qr*R*Gym%l/N|*GPkG0 x xxmy_Bx0xx0mmmxm00m0)[sx0mxm00xx)xY?*Aqklls0m0)lP_l)mYss X00_H)lymY__Hm))Y1H?zsxm)0YHYYsxYB)mymyyymmx0YHsm0fN*2qkHy000m_XlyH5H_x0s BYfHllHHXX2kH*k0mYYHyyllYHnfXA)Y%x0000NLQmy0m0m0XX5)mm)0m0ymmyHs0myyyymymXG)Hls0yym) [xx)?f52n*H%lHyyy)ymHHH0B?_zs0YY)0Bxx 0x1xxH0YBBT8TBH0mm$ϭsxxx0mxm01=[zz J 00>îdJlH 1mxmmmYGHkkkmyyyyk|B1Y0YgA\N( * Hk***HymlQ RQQQQQ QyyyyyyyyymnHG)y))mx% 00m0xBxx0 x1 H0s B=OTmm))H)00 zml[Al_)?Y[BssY[mQyxm0mmss)mmXPGPGGPHl)yq_mmmYykqyQ2v^varGQ0ll|5qqHBHxxmm)kqgx 0 xx00000000x mxmmmx00mz̋ln5\2k)01xmk_% krGmxzOmXn0ky_)m YsBJg)mmymmylBss s?lxm)m0)mmx0xs mm0 gNHn Hr*Hyy)nkGyYyNgl0Ollnqk H * rrk)yyPryy)m)XgnAlY_%%G/NNGkyyyyynPGllmxxmmm0yyym)msBx)x0)ymmyyN/mYH0mx0)yXX101zzxHfX/|LkHmyGy0Y[B0 xBl0YYxx x1s J%s Ymm_xOO?[z ϶H_x B[AOzH)xmx0s=B sxsxsxz1 y껞d A?Y 0xx1Bxx0H__ymm)YyGkrqNYkxGRrraarr yy_yQrraar rQyym)myyymy))myymxxxx00y)0xYs= 1JmYmm_)[OO?gl0m))m0  sA?YYl0xx1Bkmy[ABYYxm0mkYHPHP))GPGl_ym))))m0_yn*Ha2222ryymq[0iqqnq)lYxmxx0YrHB)xx0[ըsYx01smxm)mxx0̶l H nv*kk%  0x H%rrrPrsxsHYyyPYY)sszYy)mmB x0 mA)0000)x lmm//A_qnnPkNllAAAPy))m|Xg8zl_|*q*klk*k*rkk_HHHyyGkHHyyyX_mXqB)lsBG%%H HrHk HyGlY))x00yyy)))m)YY)Bl0my)myy)HlBBmHkmym)yY)yxYzz0)XN85Gy)ym00BX 0mxx01symx)x0xs敕xzxml )$XOO/8 =B[??[[8zHYyx)01϶x B1%s1 J1x0yym4z_mxxssxx0Pyyyyyyy)XPlzsHyQQrrMQQQPayGyQqrM]M*aQyyy0Qyymmyԋy)))y)xYzY0m0x sϕ zmml $O/XBm)y)kyy 00ll?kHkHYYY_ssxmxY)yy)y)z mx)kHPPHHHHYkGmmmm))mxmH HNGrqr2vqv*QmG/?ly)f]qG)mmm)0yyP*nY0mx0x[XXOmxmmmm0B[8gPHkkkrH*kBBxmy r rBm 0/Y_yyyyGYH1sA)mG)y)lYxx0xxlsyymmmYsxBx0l00xl[Hkk*NfYy_nXPyymfNgBs|l_5-*kk* rklkY_YyyGmyHkyyA8)HA*BY) HYgNLq*l%Gk kHk_PymyylHYHlAs00yy)))m)m00)y0mxmmym))lYm0mm))y)myms)G5XNNf\N0mmy0_lYYxx B_/AsylJ[ [88 z)mBzz=حl[O=zxB[ [J=Hxy)Y0x=sz1=zxxx m00E> xBx0m1x> 0yyyyyyyyyn*GBY)QrQaQQy yGH^]vQQyyy))yyyyym)yy))xHzxHz[ zz88=/xz xmBzz=?zHlHP))Pmm01BY?_lkkHHBY[_m0000mAY0yyYlsx0m0y)Gm)H%YYmy)PyPm)00000/gPQ2*r2qvrQy0_)m5qrm00y)y*)mx)x/ ))YY)YHlsmxm0000msllHYkl**Hrszlm0y krP0 xmyykyyyy)YYsB_m)))mlsxssllmy0mmsm1x0000/ԷrH*rHflY0AnYy0lgBOggBHnq*Hkkkkr k_lGyyHPg/HYHA?lY)YHsf?k klH * H kHmGqnk)_000ymy))G)0Hm0mmymyyyyGm)m))PGm0mmy)m))))BlmBsHP5|NN0))mm00B0̨Y0xzBlB0YkllJs sxz敜88 xz x0BTT歭[[__l8=zmy)x=Ϩs/ =01xx000 û> 1YllH11>>x0yyyyyyyyyyyq0B[lYmyGaQyaaQyQkyPyGarvrQyymyyyyyy*Xm)zB1mms sx1z=8 xzxyBխl0___H)kyYm0Y_mkkGkHklmyl0m0y0ylmy)m 0HPyyHY)%BmGP)y/[̶{l)B8NgXqrarnPrn2*Qym0/l)m5rQGymyGnBYB0y)gl)sm0mmmyyk*kk k_Hl ykrPrP0mxxsBXPyyyPG)Y)YBm)kP)HmBlY l X)yyyy Ysxx1?Ys0mYHkk5NfNgXmy0l8[AX_AqkkkHrHrrkkk_A_)mGY)HGyyyH|HHkl___HYYkX*kkkkqkkk k)mYklXAlml m00HH)ymy%)YlHPl_l0mm)))YYHY_|k0G)PN)yx00)s0̭Ym lH0ymls$A$1x/xs1J?% [=σX/g[lzzO=_YHmGY=Oz1/xxx0 0 0 x 0 x1D"1 00yyyyyyyPyaqGsls))yQQyQyQyryyyH2er^rQQQymym0yGyyy))yX_k)Gm?l0sl0zըYzsxx11JJBB[=ضOYl_kP)yyPmlBmHlyyGH?_ m0m))myyyH0yyymY0x)YPY)YmYH0akHygl8|[?f\qqH22k2qayyQy)l\\ HrGrnSy)ylH%lmmmyHgllsxm0Y)Hkkk* Hrk kYmmAkrH)mxxBXgfYPPyyy0m1lH)YkXqlmYlsz zymm00=BmxX{gHQykHkHHX|?_l_Y)y)y00?x8[?A)kkkkkPkkr rk B%%m?GyPP)yyyyymmgX_lqAHYm_5Lq*kkQ0Gk kk%yyXHmmymPl)m8| Y00yy0my0mym)myy0Hmm)m)YH__A?)ymY)m)fX?qy_HYm%0mYm)mm[[ xslB)0mszBYBBxB?lzg1/Og?z1zzB)y)Y)x1z1O8zzsx0x0x10 mض"> 0 yyyyynm)lg0QyQyQyQ kGyyPH22rr2rQQQyyyyymyyGGyyyy*X)G))_B0Yss% Bxl?z[[zz[=[g_)yyyYAHBX_yyyk_kymYyy)yy00_BYxmmY)))m)xm0)ynn)/)0)%_)m)00)xl_ykrykH*kmGym0?0y\vPRGyyylHBG)myyyP*AYm0kHkHkkkrr*?)mm0yHnkHPkHmm000_ggHG)yrkmYx00NL*qHGmYsz حxlmy0Yx _GxmBq*GQy krH Hy _B)_YJN ?/?mHmq*kHHHkHGkPHrk _)0%/AH)GGGG)yyyyyyyYggA_/Y)YYYYH5nk_mG%G0mmzx Pl0sAzx0m00yyyymm)mB%m0mm)y00m0)mH?kYHYmm)))nyy)mmm0)m)k)m)mm?)0[lY _s)m)yBzJ/?//[J/[zx=[̭ z[ m0_XHB_sYzBBYxY)yYxYx$s ص x0ms > xx)1> 0 )yyy)yyyyyym*vGy)nHyQQaIyQqkyyyGPv2rIeayQyyyy))yyPyyy0m0m)yk%GGG)G)m/lsmB[[T /?//J zx=A z[?_ll_Hmyymyyy_̷lyyGHP%kyyyy__yy)mymyyym0_[sx0x)my)mm)xmyykGm0B0ymyy)QyQy0mm)))mirkPP0Y))myyy)yyllABH_kkHkkrkHr rkrHm)0mmkn kkGmm)00y/ggPPHmNH)0YxlNnk*lmm)xBzY)0BA)mY)mx0Ynqrk*k0Xs0n_y[|[BmmHf2*kykHrrkH*lBBgH)HPyy*|XlXkA))YHB*55qq*ymm ***my00YAzz_s0s[B0m00yyymmm/X_)YH)BHxYlY)8*fl)xym5fNNN5yy)YH ymm)m)m0l0 szsmx))y0B8==̶̶?[=/J[N/zz؃[zm0Y|gO8 xx)y)YYYx1zz xxls1x 11xxsE> 0)yyyyyyyyyy*Gkyy)lHyyQQaaaQykyyyQyyQvorraayyQyyy)myyyyyy0mmy)nkGm)yym)ml/llzO== ̶//J/N/zzՃm)YAyyyy)GlgXAm)y)YH)lkPPyPH)0y)yyH?B0zlBmmm))))))0)0mymyQymm%0mYyyQm)000y)llx)nnPaH PkGyGym0?Ym_myyyGyy0XLXAq*kk l)HHrkkkyY000msYHlBlm)Ymylg8lA?nN5qmHBBm0xx)s0GkB??zB[ssA[[)0YYYYmPHXf\k* *kqk0) As00)Asm08Bs_)m|)mmmHkHr HHY_8|PY0YgfXqlnHYYH?lk/qnXy)mmGl **)x00zzz YBxx涭 mmyyy)yymmmlXA_lAsY/[sx8/H|8|gzm00m8-|n0szBll)m0yY)HX[sx))mm O==[s0 [涭Hg/x1xY|AOz0mlH11x Ϩ Jzxx B=Էl  zsxx 0 0yyky*yyQQaRaaaaaayyyQR2rRGyQQ)YkyyQy0xx zYyL*n{GGHlBmm0lO8===϶Bx0B[涭 XX/0ymm)Y)mmyyym)_g[m)myYH_[yPGX_YmmymyyH_Bz XlH))yy)m0y0Hyyym))Gyrmyy0)))m)ykYy?N{q kyy0))sl0))mGm_)ymmmsXlnnq*G%B rklHHY0Y?HxGsHHmxlsl?Hl/ql%*0mB趭 1m0)m0q?fNsx [ AOlxxm00xYmYNNfffLrkrr*qqG)mYzY_g 0zzs 1B[lB)Xf)y)HPqqHYHlHHkGyG)m0mYY|nBYYHl_*Af)Y)) *{H%H00s[?Bsl xxsz mmyyy)))mHgXAlYOX[?mB/?HH||O8OABHm-_yms/)ymmy0m00x_m0xsxsz88 s0x)xs/̭sxA/ggϨ x)H_nAAXX)Xҭ?BYs0mNX/?s1zZ1xmB) 88=J[$zsyyyHaGyyQQorraaayyyy2kQ22MrorayyGyyykmyyyyxlsx_lmff\f55kYGm001O88m01xs[̭Yx[/ggϨmmmmm0))mmmyy))0Xmxm0YYHmYyP_00ymy)yyymXz?AkqqkP)))ym0mmyyyyyyyYym*mYlm00G)G/lmgNX5NqqqH*rGyyyyllHH0))ym0Y?m)0%HynfnqX%mm0HrPkkkHl?lH/B0Bx0Y))0yyyy0Y0 ?YmGlGm)sB xxBlXBksYs$[sOY 0x00 )m_)n5NNN*mGkkHmHxmBs0mlsm=sBN/A[N|%0mmGHkPkgsm))_Alm)m)mmYllBmN8fH?_YHl/qY_N)YmyGYk*? )B00s[z===̶Jzz1 xs/z l)y0kq)Y?[XlsH/lxxYy)88 G%BsBJOlmY0)m00Ymmylzss0 00 1 x[sm s[ 0mx0mz/X8NN8BxxmqyNmyY/gg[sBJ 111xx00[=JJ[[lyyyyyyyyyynPyPGQyao,rayyyyQQa2]vrryQQyGGmyyy1s? l0f5fLf5ilHBHYB0sx 1m sAB0xm0xlg[X8NN8B)mm)))m)x00 ))xmmx0Pymm0my)yl/l/k**HY)Y))00)HHPy_yyy))ml_qyqGlm))HA_YXNX{5nq*PqHkkPy_?z00)lyY0mHm)))yyHny)0PrqH?AlBx00BYxPxzlxmHsm)xBmm[[s?yy%0))sYgO zxm0m)00gfyGGGHHmkkm)0l0l0l /[_g|fYmm)ngXlx))HABmmlllBmm/8N/_sB)l__k_XXklNY0mmHGYmx[[x1= ssxx0 )A|fN)H)yHA/?/z%Y_BYG)xGk0[T_)mxm0km00m0Y?s1Bz1xxm00xxJJsxz1xxBϭ000Y|f8gB11ByPyB0xYxy/[1s1xx00 zzx1"s1sYx)xmym))0)GyX2HQkQyarooayQyya22vvoroQy0yyP? z0555555f5XqH_XAm00B1zz1mzzm000g|/fg8AHm)mmm)mmyy0m)x0m)mm)m))mPyy0mxy)yyH)myPXmqqq* mmYyyHYmm0kmGPkQkGmmmyG{fq*qG2n rHrr*Ag/_0ymkyxm0xxm)H0y0mm)XNXNGm)mxkkHHgfYOlxxxx0z/ )m)m)mmx mmmm0xHmm)y=?YBBx[l[ x)x0xm0lmmAg?m0xmlAA s0xx[x00B0gAYx [$ /X|)))mm?ng//[BBYm0sBmmx)xmxY s0[A8N8g/_[YH_*q{[Gl)[[[l)m*k%m) mm xJ ss1sx0x0z 10ymqNgm)YH)Y[/ggXXA_z/lymH/sY))%%H0sglxm0l/))0BBBszm0xY 0 Z1DJJB 8x0m00 N8z1kykyyHz?=xx)mH̭ mmx0 x 1x0)yyx0 x000 0 s mmy)Hsm))yyQn nPGo,,ayyQPI]2vKere aQQaH*Yyyly\X5fq25ik|ˋ/Hmlz1 BOx0m0B8gN8zl_))mm)))xmmyxxY)mYm0yxmGykaymYmmy)ylGyHPlYX2qHGmYgXmnYYg))yGQl_0HnLnX\2Hn{q rrHk2AX?m)G0y0x)m0x00mHXg||mm)HPYl[8[xxxxx0myyYlmxxmyygl?xy)YB xmY0xszxxxx)x))mxmByA8zmmmmmYsl_[Ymxxm=s0xBm[ ss)B$sO_B00m0mfNX϶ Yx?msHx ABz0 [BNNX[/llX_s/Yzsy)mlGm)Yxl 0 ==zs1x 0̭m0m)ml_q_GYYlglgXlx=gyYgϨxkBHYYB/zx=gl [00)my)%s%zxx / 00 s"JJsx0zO[s0)z8gBYBBzxmByNnBmsB0HA 0000001sx0x0x00000[)xmxyyyY)yyyyraPnHyar,,,IaIyyyyQ2r2^vvvqraynkyyym_g[Yyyfq*k*fn XXY_)mJsx0z8[s0)08g YBz)m0)mxmm)mm000myHms)YG)ykr0)msxy)0my0G\\ov* ))l8gAnPkym)[B 0mmPkk yGx/[Bm5\fnn{ oX{HX_ylsxsxmxyyml?/B?)mm))lg[?BA?ly0B[s0B_A)0s00)HH)yHyHg8Ylqmy0mY [Bm00Yxxmx))x)xBBA0xxxxl[[sss)Y0[Ox0xAxmxm0mgm)xσsxz8s00m0m s0[m0϶0sxY Ym[yB8?s_BBBqn(n_?Yss1s0mk?YmY 1z =J10 0s=s0y))m0m)YYHxO[AgnkyB= xsYHxYy_O=0O[[$xxmmxmm)%00xmxsB 1x"D9zz YsmYx0lBq**l%1xPyyykNk sJ 0ymyymymmzszY0H zxxy0y0mzmmm0000msyyyynrXyyyQ,,Iay*M22]vKKrQayay*XnHyyQykyrfiA*q* qnqqX)y0zz10=smY0lkqB%))00xm0m)yym))m)mmy)mYBl쁳ay)))m)) xm)y25H)H55r*G)lNl*rQmOs)x)mmyPqqqq*qPG0myr5(N5ffkH2*K*2n_nkG0 mx Hyym/?_l[AY_0)mymf8lB)sA0)mm0Y01gs0x gx0Y)Hm0lHmmHkPlsBs)mmmmsH s0m0m0xxmx)0mxmxB?0YOm0mxxzzsxxY0z[s[X/ xYY)sgOg00)0 OHYm0000mlz/z 1x00=mxzYxmzsx0s)H/Axy0H?n2lsBss xyB_Y)m)B[ s1s1x 0zOx0ym))))%)GYmmYsl_nXqH) _m?Jx)0)Y)%xY)|=B10mssx /smxmmm)%%B00x000z0mx1" JxxYxB0[_?mszxm)yy_g ssx0)Gyyym00s000)m*=J JY00000Y0)mym00x)0)yyy2nqmmGae,,eyyGQQar]2vvraQmyyyyyn2*k * *n){kYxJzJBx /Y 0[̭??msB̷))m)))yymnXky))) sHGy)mBszx)ymyyQy%qY*qakka*PQGxx0A*Hqq*rryyqPQGa5(5Nf{Qv*q(q̋k-kyml0m0yyyy?Yz//sm0yxglYxYlXN?)x00[z0xxsY)m)BBYYx)0Pk*yQyQyyGGllYx0Ym0m0mm0mmxm)0lXlHH0m Y)YxY|l[[[AB1 sY=ggBA[?BY[s))Gmm̭sm[s)Y00/0m) m)mY )xmYB/?xx)*S{*Pks z)Gyq)%)Y0 BxBxx0 Ys1x0z/_0)G))B0zgg[_Bllkgq_Hx[?xx[z)?A)mmmx))%T szxm0Y01z0x0xBB-%QmmQl x"00YYx0sJ1xz1x[g/00zHm0xYyr\l0  m)myy)xsm0myk*k /?x00000yyyrkGyyQyyyynrnGmyzk,,ee,QyQyyrGQr2v߳ryyyryyQyyQyyyH{*k qHqnrf8*0%01  0sY_k/gym_XAAAY)m)y/fgnAqHys 0)yyyy01z0)))yyQyHHGq5qH**Sq)%HPa2QnxxxYml*HPaPqPkGQ PGGGG55\5LX*aGv**]*qL*{n˷)%l)mslxY0_?zl/lY0ym0)Bs)H?lgnB0mY00xYmsO ̭sz xssYxm00l)mmmHyyyyyyyyGBHx x0m)xm00)m00B[mx|NNnkBBB[gH))_[_z Xح xx Xg/zxYB))myllYzxm0l/ly00m0 0xY)_[zx)_qAnqHsBzBBm00mkGmmms[0ŭsx1zBx0[0)mYH_lB__k)00?[A_?Xgl%slx[lB)))mx))m0 zzY)s x0s붨m00s[?-H GG)xxz"1x01l_H0z/X888?x)s0mYy) Pky)lsBm0mGyyy))xs̭Ym0)yPYsBB 0000)y)Gnqq_yyyPnPyGl)?BRww,oQyQrQyev2vaaQyayQPyQQyQyyyyn2{q*** *qkqX*X0x xzs00YBlHAAgOO?m))YX/ABHmymmHA8̷kkH)s0mYYPyymmz/xm))HGk*XmyGH2)QkPyyB)m))QyQayPyyyQyQ55\rrv 22QykGkyyYYyz zBxHY)mmys/lYm*?k0)mmmYmO[mz Bm)Y0)ll)mmymqkyyyyyyymm0Y000y)00mYm%/|\Xkkl_z?BYYY%?/l[[[xx1 $z$XA/X sY)00/g_xAlxBx lGmy0YAl)mBY)PY_B)xXnnninSrHss)m))Ykk)YYY0x0s[ب1szz1x Bxmxxlx0m0m00YY_Y)m/l/gAAkHYxBYzO?_BYxmmm%sT[s/Ylx zzYxx)mA%H***%mmx1"1z xx 0sJ1m[ggXOBYm)))Grr)m)_s x0)myyyyyyymmH[lH)myyHHml0000ymPGyqnq*Gyyy)ynn)y0i_eweryyaya22SSGmmQ0QmQyyayyyyyyymnn{**kk*{k\lkqmGm%?Y0))Bl_lXXX8HHH)[lHGymym?|Ag[_s)))yyyyyml?HxYYHyyPG)G)yqqrrqlGyqksYxmmmyQPk**akkykPGP Pyrf5fffqGakraqeaqGPyPmkYl_H)Hm0??x)))zsmBXkyyym))Xgs szlxm))YY/_))mm)mmqHyQyyyyyx00Ymm00)HlBqHB_/lYHs%0lOض$s z=[=ggggggYsYYm0_8ϭYxmY[s)xBsBzffXABlgAYxmYxkllmx)XniHBBzzsBlBG%l_%))00Yz涭zz zz1m0x0x_B0mm00mm0YmAg/_AX/ԋkkYY_BB8/Bs)0)x%m%0Y z xxm0B0mkkLBGkk1"JJ1xxxY00xJ10 z/XX///_BB)YY raGH%xzlYm)yyyyyyHBl)yGPPH)m)xBBx0)0yGPGq**r*kQmGyy*Hnmxo,eeoaayQyQQ((Qmm0xQyyyyyyyyyyyyYlq{q*k HqH2fqk_ԋ)mxms00BY_k_ll̶[_BHm)0xBsYxmmm))m//m/g/AH0y0yy%*qnq8lB)yy*PPQy)ykky nkGqnyA)maPrPQPyngBkmGkr* GQGH)00)PY_)m0g[/Hm)qyB0mB/lyHHHgg[ mm))YHH)_ly0m0mxmm0AmyyyyymmHm00smm0G0BGHnXl%YH%HHx0x=z1x T؃BOgggOO))YsY)Yn_XO8Y))x)mmx_̃[|NNX/)0))YGl))))fSqlHBxxllmmmH)xmx0mmmmm Bl_ m00000H˷yy0gAgXXHkkHPklYm)|z1YxxmY0YY[/=1xsBx0mY8fXX)%H%xxZzxxmx x zzYAgX_YHHHBk r(rGXXlGgs0zB0)y0_kmykH)l0m0m00Qy22k2PyYmHqqPG2qva,;,oGQyQayyyyQyrrl%xmmxyyyyGyyyyyyyyyyy)H{qqqkkr*Hq5ik_))yy))))YYPYHAXXYlY)00x[x)m)mHYY 000g)0mA[H0myn-q?mmm0nHr*HyyGH*nkyyHY)mmyyyykgkm)my PQQyyY0ymPy)/)m0m0z[[Almm{l%s)0x//sYyyXgO[AOg_x)YYYl0mHl)xm0%*yyyyyyQ0mm0_lBYYmQ0m_8ff58N8=H)H%)00mJ[11xT[s8|8ggAl))l_YmNO))x)sms|=lzXAYym))x))Pmm))xkg{q?**BHBzlB)m%lmH/[[=[ x0mm0m)Bg涶sYY%l_Y8X|gglHHHHYl)0Als1mx%/?lx/zO=sxxz[Bx0mm_8ff|XGyH{kmx%JDJ00000xs1zsxlAgOOggYYYYHkkkaqѲa_g_ym̕ m?lmm))yymm0)0x)m0yyQ2q222kyYHqGqre,aQQyyQQaPaQ%l0x0yyyBnqn{qq* *H*5*k*k_Xnm)HYPlkHlxlzs0lYx00XBXB)sAm00BN/0)00mlm)0mByX(*)P*yPHkHHGyymyyyyyymyyX_m))yyyymm0Gyyq_)ymmxX//B*_)mHl)0mlkyRaHggTO[sx)m)YYYl0YY/_lBlBm_HymyyymkqBm)0yYYlBYxmxm%BH0N|NlxYm?0)msxxz1xx =T m|ABxxmB[)s__|xmmYYBYlB0B_gAYmmm))llkl)mylXABHs**HHBB[%)xm)B/[[$smmmmy0Y?mx_lY%s_mymy_NggggGlHYmmxO?xm0HN0??X8B0xmY//lm))AN888%)x_BxJJJDx0m000 zzl0XO|OAsm)YkY \2nG[G8 l0yym0))))mmPmY)y)m0yyyYGyQnq2yn8|lHy*yQr e,eraQQQPyy)_m)myyyn{qqqq* kN5ikGynPnXnymP_*l)0)l0?Ymmx0AxmgN_)l YxxX8smm0x)x0sX_G{\̋Hqym*GHyyPGyyyyy)Hyyyyyyyyyyyyy Y)0yyyyym))m0mHP_kQY_m)m0s/lygHmmm/Hm_kGQL| z= )x)mYH)HBYg?lBY%zlBy)/my)mHnYmym0)0G%G yx%Y0m?HX|YxYmBBms[0xxx[Ox0A1xmlAm00 YxYYYxl 000))g_m)m[YlX[)yknn0YgxHqlY)mx8/xYxmx/g[ s 11=[xmmmyYOs0000000Gmm0H|NNN_H))HGGYYlkmxmzmxYYmA_xml=?0x0 00B[?A)mNYm%m%Y001 ZJD0 m000 0 z/mAgl/TsHx)YHYQnq__An)O?0$Onm00Yxmm)y*H_llY)0mGyq2*nry)X8gmlPqQarMeo2rayy0yyyYBmx)myyyyyyyyyyyyyyyyyHXq{qP*nkL5NˋHP*nXuXn0yAgfXXlmmmY)0)m H)?g)YsY00s/m))xmxBlm%2\{Ry X*my)*HnyyPA)Gymyy0yyyyyyy))yGG)mymymyy))mmmyyyyy_Y00*kk)my)glsBzG*ksxll)%%GN8[s00z1mmmx)xYlsgB)Y%)Gmm_/)0))Pk)Y0YH)mxm00000m%0xm0x%YzH0z[Yx)0m_0H0_Yxm00my$z[l0g l xBBsx xYmYs sx01[l) /XBm)m00lgY00Yl z0lg̷lHgOz0xxkH_0YmYx))_XBx譶s01x10m)yHBxxyQyyy))yyHAXNNY)mB/smm0YY)00m))x0000AsAm0)m)%YB00%s1ml?Bx00B0 mm0 J[B)g[ssx xzsB0m)xmGknHY[1zA?xx z_ x s1mx0myyyyHlm0ym)Y2nv2kq8N?kq\yGGam QQyyyyyyyyyyy0yyyyymBm0yyyyy)yyyyymyyyyyyyHYng*H2nk kkkqN5N*lPXnXnnYYXXkXA?YmmnY0mx)H)Y[sx00gYm)xmxBX_yGaGRrIGalymYGiGyGyynyYAPH)myHPkPyyPYm0mmyyyyyYH xmykYPkk))mmYYmmmszGHy%s8%%G%k kXN 0sBx)xxYYYsB0BXBsYBkHYHYl_YsY)x))YHHG)GymBlYy)0mmmmxGxxGxGxmxY0B0mlBB1xxx000Bms0Bg )x)00y0xxm=00zsY1Yxss x YmsY0Ys00[xmYY)mx[m0[l[xk_gXO|[sYYYk|0mmxYY0ANgAxsبYs0xs)m)y0_0yyyymymmmGmmyymHXmY)kY0BB)0000m)YY)000BH|l[0ml_Bm_mmzBYxB88Y001mxmmmm 0z1Y)g8lحxx s mx)l)yHqY/s$sبsx0 B/gBBsm 0m0ymyyP_?/As00mmHYm))yQGʡnq2G_gNm0_kn5yQknryyQyyy0sBmmyyyyYyyyyH_qa*nnq2Hk5*{nkXY0)PHknqmB˕H0H)m0)Y_mm[zxx_XXXx0)lm0m0)L? narra)y%GGyyAy/HYGyy?)ya2yyyyyyyQyyayyyyyyyyyQyyyyyyGYG)mm *PyyyyG)_8BHYmGG%s%϶lxx0{{0msYlx0Yx)0xm slY[8_%lB__*HHkY0000_kGG0H?HBYlx0Yx%xxxxmxx%0 m0B0YYx)m00)0x_YkGGy m[xO1BBxxYsBB1xlsmYx0sYx0lsY)0)Y)mx Ax0/?A?0mlHnX_sxx)YkYyy)mmm%)__))xzx x)mgByyQyyQyQ)Y)mP)ym)0l))x1xmxXԷ)mmx)0)A m)y)YHmH0Y%mB 1xmxA[000Yz xmm0y0m00xmmB/z1xsx00)x)y))_zs1TϨmx 01=Jsmx0))yym0?Ys00x0)mqkyG2XqkkgNNXymGy)mm0mYmyyyQyyymy)mY_/_)0ymy)GHmm))mmyyQynnkk nԋq **n5N8nHqXXXXYyYkkg*HN0yymY8fgY$sYx_//)0000m̋kfL22] m)HmlPkyAmAlY%y%XkyrayyayQyyQyyQQyyGmmm)qyky)y%8))msYGG%%%Yz/B 00 L)y)YBmxx)xm/sl/[l/lB_*_*kYY/XlmxHn_HklH?YYYlzm00x%xG0mx10sxxsm0)xmm 0)A_)YH[lY0O/ss xz Bs)s)0x)msYY)00xslY0B8x%myYyxss1xxxYH)))m%00mm)Yl)[x[1Ym0yyyXXlyy)00mm)Y)mYmm)s0z xYmmgNH)mmxm0)NXgl0Ym)GGGHlHyx%x sxxxxxxHm00Y 0xmm0mxxmmmlAB붨s 1s1ym0)ym0zبx[sxx= gB00xx z10mmm)yyymm)msx0xx0m0m0l*lHH)ynX0//myP0)yms_)GPPaaPyyymmmyyyymyyyrfff*qq*2q2n*kPHf5{XXXy)qkH?HmyXYNN_lHA[TJlYxHXnXXggsxx0mmX 5X88m%m0HHm)HmmnXPqQlY_))y?A)yyQF3FFFFFFFFFFVFFFFF33FFFF3pbbbbbbߥ߹rQ\ *)H0m000B0XA*BG0m0G%%Gx%)l00m%)HYH)Ym0m_8/l?8O8|gH_***__kHH*Xglg*k* qBlB_lmm00m0)m%%Gx00mlB0Y 0)_mmmxmxmY)0))Y00Ysm|[mx xssxsB)))/k0llY0mxYYY00[mH)?N%mY))ymG)Yxl)Ymm0mmYlHHlXA)0lls Bxmmm)m_yyyyyQyQm)yYyyy))mHsYm0s)xmN)mmx0mm)5fgXxY0mGG%k mymG))xzsxx0ml )YO mm)m0)yy))mmg[_[sx mxmx0x))0)xY$s 0mYsx m?smm0ymGmm0mm))) s1x00xYY))x)%)llqgX)lny2P5vymayyyyyyyyyyyyyQyQQQyQyQ5fqqqq***kq Gff5NLfXnXXyyqHymX)H8Ngg0[ )lgXXXg80YG\*{%GG)myyX_)))*kqPy?AlHmyHymyQ3VV<< x0xm0)m0m)%mmGP)YHHY)gB05y)lmxBm0xsYYx)))y)l)G0{B)B_m))y)YYYsYsYxm)mm)0n_)m)mQ2 752ppN\vpp2|p5vfKv5257 ,m)y)YG)mmHkPg|=J q*kkHyyyyg/<QYBB11ssYkH_* QmH)fgHynqH%mG)mX5N)l) nnX/Bm%)G*n**V\f55\VV<\\\\\V\\ < \f f\5V\\\Vf55\\7bK2m*kyyk-nk0)_0)0)Ymmm)BYm00GGGyy0y)SnGQAHmYy)gl-k_N{GB%YYBmxss z[[0xY0)%l sxssgAHyGm)YmxB0mmmx0 x_xx0s0O?H/AzY0 lYlXN|fXnyHAnll_Bymm)BH))fkYHXBOAz敭)YH8N8LqX\5****qlz̭s)0NkmmqymHk**Yym0yPYYHll*_lB%_8[Yx0mmx0xx1Y mskYyH2G0mz[ϭsHxHm)0000ymmH 0xz1 >>> 0x0mm0mkPGmx)mYPP0_l mkX2yYm YBB Y) 000myGmGyH?0Y0s)mmPYPYH)gmx00BHYmk*Ba\p25p2eNʪvvf52vef,ymGy)Y))Yl|zHv(n?{Gk H Qyy2rv3FV01Y00xm0Y8N5rrm0)GqnLBxGmGN_0nH?n{l%/[HlYxkHGqrQepp..FFFFbFFF(FF333333FFFFFFFVV<>>>>x00xymmmmq00mm0mk?PymBk/?%0ssH _0AAkHXXky0G)l{BB0kmm_?smmN))mm0mAXnlg?mQ V\f55 V <\\ \\\5\ < \f55\\ >">>11x0ymm0%l*qXN01_Yyml/[[_HHl)mxsYlmBgNN|k)GBk_0l0?HXX?lN0mm00lg)Ymar F7777777737FF7VVF7<<<< 00x8Nm)?lsm00Ylmx?zBy_n\i*xBx)x))PHGP)myy0YYHllH0mm)ymy)llYx zxm0Yxsx1x0000000000xlx1[1 xmm0m0))mmmYHH)ll))m0mOz1Yے$T`_ϙ_ANf*xmyq\ *N55nii%mq_q*qq?l?s_0y0yyyymHJZJ>>"zs))yyy)m%0Bl[Al%x%Hs%x x11l )YHHkH%)Hq*All/Am0mmY=?_XԶxxmsxAHkkH ly)yky)ym{GB??O0y0Y z91BBx00zg?_NNfnqYY/̶zzBx0g8?BBY_glyy0mxG)kYYHkH)yy)GGHHHHHHklPyyyGHHHkkl_l0̕YAX̷Ym0ss?B_%mmHkHHBl)m))yymmmy)Hg_lY%0000Q*lH/YBg8AymkŨ1[[s0x)0)X{L_/sxx)m0x)m)*y)_xzYYk_HH*k))/0xB10 lyy)ym0mlx0xlYx0mymBmxlBsYmQk*mky0 %)myYXAsA/)0BBYxsYmxx1"1 Y0x0 )yH/xmxkgX_)B?lx0qi{*qHBsxmmPyyy)m))))l_Hllmmmm)m)HHk)00zx0Gy xxx00000mx0sx0m x1xm00Yxm0ym))ymmlll0)myHJs1BgOT$TϭOg$$ 1 s8%y*\n*fXffn{Hg̭8/inS{ Y0H)0yyylD >9 >10myyyy00 xxlBmYAl zB)0x%Ym0slB϶1Zzzsxmymy0m0)ymXX/mYH)y ?XNNnB 1zkHHHmGmY%BB)B0J̐sY Ny0)zz1sx /f\nkqHsY00m0mG%m0xlYmyxxGHslBBBBBmm)))YHHHkABBx0x))GPHkBkl?__0gs[=gYm0ls0lGmkHBl?Hmm))mmYPH)_G?mm0ymx//11%gg_m[B JJ/[x)yN55\55kxYYxm00)lH_kH)0Bm0sxlnHԶz01sx0xgmmy)y0)yy0mx%lBk_0 m1m0Y))s0Ysx sx0xmkq*kHH0BBY)_5g%g8A_0Y?sBsxx"DD 10 z0B)xmx[x _sX{HBl?sxm*]]]GYJBx0x))HGyyPyyym)YYs_?H_?)))YYYsH_*ms/ x00k x0000000000xmmm0)Ym)xsx0mmYy)H)yy0m)G)yBlm)m_JB1xBӒ`T$WTTOO $$Y*|NYxxmGHr*X{f5\fS***GgnNNNNf5Nq%x mmyQBB>">>Gr m0 01lBmY)00x000000l_ss00mY1 )xmm)000)m0yy0yHHHYl)l)myy00BgXBs) lHHkBkHH)YPPmlOl0yg J/ssYgmm)JJŭ [mxHL((\gsx)x)mymYmxA0m 0xxmx)PHlByX lmmmy0Hl0mxmym%m))ymYYm0x?s[=[[X[HllYlYmYHGxm0m000mmm)m)Y)yx000y)ym0s/sB kymy s00 lA xG\\̋xxB%)mYq*k0m) [/lnk*XB s1xxxAyy)y0YyH_0B/00m1B_x0y)))y0xH lB 0y 2aGQHABy[YyX|[BBYx/sl x0x9"1xsxAs[xxxy[lx mH)f\?xxmk**v*lBx0mB_ll_kykA_P)mYHlH)YHY))sYYH)y0B sx)myy0x1xx00000000xxx0lm)m% zxmxm)_m)l))))PmyGyyHl0yY)mmzxxYڀ`` O`gTs $Yk)x%rQ 2f\\\f(Sq{{GL5-kY))yyG>E9>" iXnGQ0x szsm)x00000000xxmx Y0xx0x1 mxmsm)0y)myyy00_ll)yyxxym)Hs l1lkHmmHm)BX0xz0/GBB1gOyy0m x [?m)mmv55\ffNgHX%xmmyk_H*kH)ykm0m0)YH?_sx[[lH0ymxmH)00x)yym)))Ym)yyyHnnnnXAl[Ymyr0ymxYy)00GmQGGQ0mG)0ymyHsxxlByyy)xxm0x[m0y)Ym)BX/-GBm0ynXfX)8_****qq_mxYsz1 Byyymm00Y0N0z88800/lx) AXx)mmYsszxmmmyryymyAPQY000Yg|OgBsBH%Y00s1 x1xب)yy 01x0xssx5{*BYx)*qqv***m0m00AglByyyfȺ**kyy)H0HBB Y00y0m0ll xmx00 1J0x00y000xx01Y)?HQG)lk)xmy_)m)000)Js0xm0)0mm0yGm0mx`ӑ6O[նA$A$ xHy mBBxmy0%GH*f5˪˲2]qx?l[Xl_̋G*)0mxsy000E>> 2k%m0m0z11xxm00000000 x x0)m)1Hm)0_)mm )mG)m0m)mYl?zxs Ym00yyyyABl/ymm0mlBx008/BBs_ymms%m 0z ==_Bm))r{\XlX)BGmmy%{n{XnHqmxBA0my0)_ms000mm0m)_zzH1l)GYmm)Yl)y)Hl*AlHmGr ))lkm0mmmm0ym0x%P**HABm0mmY)0mx1gyyllHYxmx00y)))YGmm_˕gf__kykLLN_myyY_BiXn*qHBHBxs/YyP)0m0ϭ001O?xxHY//O8YBB11Ym))ymkX)Hl)l8N|mYYB0)xx)lsx 1J0=mmm01BssYzYY\\{q_[Ym0**]kn0)m)0ygyyyXXnXq*k|Lllzlm0mY)0YO?xmxxsx1m1x1 Z10m0mx0mxxsY0sXkYGP)0yyYkym)mmmm0x 0mxxY0x0Pymmm ``T`OA[g  1[)mQyYkxxm)myki\LN5fN]r]]q{*0O?gX_ll000BB0y 1">>J2nv%00001x1J x)x0 0000 x 1x)m)BB)mmxl%)_x y0mm0Hlmmm)mxx1sxYx00XXByyHl??*)1zXHyyymYxxm0xJsm00my)yG//gA)?_0mmBn/iffX0)g_y0)m lm0ml/A_[g/Al0mGmYHmkH)ymH__HYHqHyY/A/G {nHX/mmmmYYBx000)y qX_YlYymxmm0mx0m0ymy_lYYx)xmmmy)yPH)BgN/lmykkymGHmyf5Nnyy)HnNf]qvʷHHmBsBsx)yy0m0 80x[l0l=?QmY?g[A0HHYzBxzlxmmYmyyyB*m)m0?gYBBx0l0011 xBg?y00m? xlgAH_lY%k]*PG)mm0/ggYyXY)lk*HBH)Ng?̨YmlHmYxgxY1JDz m)Y00xm00%N-ky|nx0Blz)Y)l)G)ym0 T6``TTg B)yy*lmm)%)y*5Nf\NNff2q]22HfX88/l%YHHG)XYx0B/ylxx0myxjEddE>00mG%000 xsBBJ xx0000m0mxx?ym))xllmymm0my)_xs)mmmms)0mmm)m0y)x0szx0XN[YYmXg8NNlYm0 myy0)llsYYx s0x0ym)mPG)8g8_H XXN*ymH0mmyy0)m0BsHl)ymB)001?_mymy)HY)mmmH_k̷)Y_Xgg̭[gGGX*|_yymx0mx?/BBYHBHl nBY?mG)Yxxx0ylYmxYBB)0y)mklHG0x%sl)0mm0)l)A_%mNNyl))kXXNfq*/_BssY0mHy08=mBxz/xH?zxymHl)HYlBs Y)yHHy)H)_Hss?l00lsBB1x s B)my%Bk0xsxzlzNfnlHHl**K*{Gf?Y)Xy)y_XnmqHmYm8/[0mAlA?0OsBsxx)x)YZ"Jx)0xx00xmNX)_lYYyymXHyl[sxmx/[Bx0sml_)y)kBm0l ``OgO kyHm)my)myy55555552*vqvnmnfggYm%Hm_gx0PXB0m0yy0 @@dEĻ 00m0 0zJ[[1m0mxm0mx1xsXBH)%ymy%HyyY0mmm0)0m/sx)))mmyH0ym0xz[H)ym)NBxmmLX)mmmm x))llY)0mm0y)yYH%mxl8Xl)kmkmy/8|/H)y)0))Gm00_y)00Y0mmmmY/̷m0m0x/l)mymmmXn_Y)_88myyGmH-Xgk)lm00yms0J_GlmQl)0lY))x)00xx?lmykHsy0)Yxm0myykY1slx0mm0my_YGmml_my)Hk*|Nnfflml[)0lBkms8000000)%_*%{|gA8X0HY?0_Y)0yymyyyH_m0A88g?ssxs?BY0s sz11[mr R HxxBYm) lB0x[Xf\f\kHlk Kkm_ _AXAx0y0H??lGq_{lm0l8NNm)B8N/Ys[sY1x)BYDJDx0 xxx00m00{N8Xs%klkmmkyyP//zx0))yOXAsmm0llslsN`OۀOO` _yrG0yyyy5NNf?Yk*qq{2yHf|f|BxGBmg8Nl[0my0y94ddEE1 0000 1[Jz 0x00mx)xG85k%mH%)?|qyyAxm lsYxB)YxByPmm J?Hy8HNXH_**_?GYmxxxm?*0ky0lHmHBYmyy))klH)0sYBz0myGyYlm)N0yBy0Gymmy)))m)0ms)H)m)sy0y0mlXkm0m)/mmxNfGmGGXfnGmy)_nlm))xm1 ))kkYGm)_)mYm0x0xgl)Ym_Yy0xm000mmGYHYm0xxz)xmmm)0YPH0m))0m)mXN8i k*q]\XH)0000_l%Hgz|O8///lHlL yii[|_mmB)mA x1[l lYYPPyy)m)yy__yX8fNNlYx1/x0BsxJ11x1[[Y)Hr ?%%Y Bm1Xf5N%mm amy0O gOAyym)slHBH%kHm0ml[?[TsYlYYm0mBsxxYklh9xxx000mglmYH?_?YXl)x /ll y)O?lHYYՑ҄`OO` $[HyGHH)m)yyyyNiHy)Hqq yyq|/_s%B?H?gBNYmNmm0yym>4E 000 0 >9ϕ81Js xm0ymx000%|ik% YsyyyXXkyAO[xm[ _)ḽ)ykH0lBH)YlyyylgyX*q{q*{GYmm0xxB)GykmymYY)ymyHks)sl0x0y*Y)))mm)l_)HH)yYy0000_Bmm)mmm0Y?00llmm0m )0mmxm00mlmm0Blmmmmm)xYlmym_XgXBmym))x000H_HY)Ya)r)0_0YYmmxmxYxYY00mkyy))GkY%%Bm))my))HB)m)YY))0mH|lmmG **|fXlYmm00Yk/HO[0g8=g8NN//))YkXG8g|/XsmmsHx[xm00YH0lGYyyk_008/B10xJs//)xx Bx1zs$__k mxxHHlTzgf55iHml_Hm0A8 l0yym_zB̶k{S/BYB0ml[?/ zNNB_xm)mm00mxxYBl JD[s00000Gx)Bl %__00)ykzslB?AYmmyl sszz%HYBxAO``s s[ շHqHHHyy)yy_|B0%B%0Gm0%kX=[lBB0ANY)8xmyyxΗ" 000 x1zz8gxDJx0xm))m0){N/H/%kklmmHyPl[[ Y[z)xm00[̭Y))yk_HlXl[)ymY/?s*NyyGqLLLfG)mxmxx_myPkYym)my)HHYm)xxm0x)mGGkHH)mmm)mmm)myYy0))mym00y0B0m00)0mm00mHB_?A_mmmxm)m0m0x)mxmlBm?l0YYmYm lg|Hy)mmm)yY_mxmx0mXkHHYHPHH)HY)GlY)m0mY0%xm)YYGyymyyH)0ym))ymmy_X_Y%%xmx)m)m)Ym*/H%GGGaGH*gYm)_X̋)=x0z8888mY{NX|/8XY?km0YsH)0xmllG)G)HlHYGm)GHHH_lm?Nsss x00xgB0ll z xm00Gxl%%Y O\\BxAyml)[ҭ $AҶxyym)B?8%H|Nn/BB)_[z0 s[z000)m)l)0mYxxHB hJ=l000)0B/n̕{?k0%)H_[01BBz[))yPHHYxx0 %Bgl 8:`O$s $0[AA**XLBymHyylNl11B_?H00m[[BY)%ym)N/HB8NmyPx0 ED 0m000 1 80l 1)mx00mmmXglm%YqYXG)z[[BB_0m0OOgHYHy)Pmml/[yNka\5ffGm0YmY̕By)y0yG)yyH_y))YBG0mmGG*klkym)Y)0mk?Y0Hm)m00mm00x0xlxxmm)m0mmmxmBH/Y0m)xmm0mxmx0mH?_)mB?)Hm)lBB0xHBYmmm))m00))y0yyyl1)s)GHnl0H_Yymm0)xYmxmmYkymyQ)GGyGayyYYYm0)mm0mYyy)YGB0Bss1m0m))Y/X00B-_OB000/8/ly0QH H)mGAN88sxB/Hxm000xJ ssxxszl|0GHB%xYYGPPPk__Y 8sx 0x?m0s[xl1000m_ll)%%$`O_X\N5l0x[)m0_g 虙[[OX ))ml%s/nk\nlB)AYm0x00000 0mx0)m0Ymxmmm0mYsl1 Bحs0xYkl00Hx _*?l?kYxmmyyHlmB_%B_BYYmm*lB s10m0sBl)ϒ[T[ s xB/qB_?lY_yYY)B/Bxs/ Bz/8X{H)Bl%00m_mNYz8|myGm xxm00m0)HgBJDzz10000ymmlllsmx-*__0m0y)H[/BHY)ml s=Y1Hsm_Xyyyy)m_NBkkq5ym)xm1g)yyPyyyyymmHY)mmmmGyHrlH)m))mmmm)Y0kmmm000yx00xxsB0mmmmmmxm0x__/B00xxmy0mxxYxm))0mB?mYg̶X/k0mmxm00YHm0mxmyym̭00x%0ynHAlHBGmmyx)x)Y00xB?8nkyQGGkqHPyyyGHlY0mxB_/m0m)G%z0sYYHYHlBl?_?lmxmm|X_)llzsxBls0mBXk%)OsYl0?00xxBBss Ym0l)_nnny0Ozsxzz10J0Y)0z0?̭00mm?Xls/ xx0ms0BXTgT5fS)xYY08O__N[lkHHlAYX{n2lBBk/sx0xmm00x00mx)0lYH0l Bz000x1sx xm0Bl?_)0Yzm1llll?l%m0))0sY y0mmxYxG_HAY Y1xxxsHYYBssgNՒOsmӨ[Bs/ml8|_GB?lllBYxH?BYx1YxmgNf-?sx)lmzN8/BlN8myyPm00x00myy/gY|0 z000YY)0H/̕_YHsm)y_zm%B_?s)ymPssxx0xxxlX?HXyyyyyymYl8=zXyP*rf|G0m)Y)Y00yyy))0ymyyQG GQ)0xm0mm0X8Bl)0mm0x0001z=mmm00x00mx00BAYm000mxxmm)0kY0)YHAHmsm[)m)HY_Yxls)YmH_q_?000m*_YXA00)))mm0yYH%/*k*qkP 2n\kGQynnyHHBY0m0m0?lY0mmYmYm0lzYxsBB0HgAlH_0m?f|8H)m|NA)YB0x0g̋Y_xxx)xY)00xzsYxx//Y%mmmms_mx_qkym=OzB0Bl0%Y0zl%0%mGm0YXAm)z0%LN|gg:_$qf))%0xx%Bm0g|gAHHYG)m)_l|PP2̋Hm?ymxmm 0m00xm0xx0BYmgiqPsmxm01mx)mm)m0/x1l?0%__)xx?nm?/YYHmmmx)YY)*llssY%YBllYBH[T$`O$ssxO=[ب_0)0lOll|gl0BBl)zx)lBBl%0y gfnYmB8NsY8|/x)myyyllxmm0)ygHX0/1 %0xYlBm0ss lA?_lYxxYmm_$xxllB%H)mm_lk Y x x1B_YYXyyyyyyYl=/yyaq*qXNxYm000kmy)myy0yG0yyyyyyG%GmyyH_kY0Y)xfY0m8?m00 0/m0my0mmxYYx00zg? x0mxxmm mmmm))0YnOX_00xmB8/)BlBl[llҭB0mHq%) 0 0x_Yy0000m)_kmy0mY)BBssH88qf*k\n*Py*qqPGYHk00xmY0)mym)m))Ym?sszxYAml888A?X?gfH?xmYBxm?AB_BmmxYx000xxgX0xxBBxBx000mmBBm)_y/N s=8/zlmx%HY)նXgk gYm)mm0xԭB_m0Gn`A_000B%mNY gY)xln0m?*G2X_Y)qm0m000xmm0m0xmmX0NNnl[1ym xxmm0m0)ml Y_%0x_?)000_gl_B))mm))00B)yni/gAsH Bz?H__BBBs_[`NO 0 OըTحzJ8llY)Bg[A?B0lx0lmm)l _5fN?xYNN%m|/mmyyQGGQ_Y0\N|0 1sx 00l_l0szm l%l__)xxx_)msB%00mxYmm_Asssxx s1HXmyyyyAkmy)yH%0/Nx0x0mm0m00GHyy%x000000y0QG2ymk*GXAYm))m0lHmNmmm0)m1x0mm0msը?B00?xz[0y))x000)Gmy_nfgXm0sz /X_l_[[Oxs00 0 0 000 xm0/8s00 0x0my_)__Hs?%YN*nX{qHn*mmmY)YPYHY)/l0YGG)%lBY)zxxH[lXNfNA|g_Yymm???)%HmklxGBssx0mx0)Hmmmml0m0mm)BmYyHl))aQQ_f_mmmm_[XN888lm)mG)nLqmnԪ|5Og%%HBHx)gg )?ymm/Gqnn{)5X0xmmx0mmm0mxxBxmYffL-zAlyyyy0)yymy)Y)0xAs01_*xmx_H xxAX?ssxmxx0mmsHBlsB__llYH[Tϒحxm$$l[//YBmmg[Am%Y?mm H58B/{0GBn5fAX|s0z)GmGyQykY)0fN5f|8/0xxmxmmm))Y)0xzxHzB0%?lxxxmXYmsYx0mxm)Hm)__XlYsYHlllHYXyyyys))yyyyG)%B[000))yG)mNXlx00000000GQmG *kyYkXHmYXNgm8N8lm)00z=0mymmmsBzBxsm0m0)xm00mm)Ymm*gNXmll x1B1xY_/?1z x mxz x0 00m)B00m00YyP)lg|YHBlzNqHq*)\iqkkkGlm)HHHlPHl_)0AY0)mmmG)_B xY xx?/X/H)%mkNNXXm)yyY??/?Gmm%%BYx0mymmBmm000m0HH0klHkmmyyQkgg88zmGXXOY0)mqfS*Hkkknqn5m|f_%0g/_[HY)lymlNi)*qqnfX0mm00mm0mmxmx ss0_lN{B/xyP)my)H)xs x_0xmk_B0xYgBx)xmxxxmmYlm?g?YB__?*_llH ӒҶ mxm0NT z0s=/xHmm0Y|NY0000HsB%0BY H)qfllng?_Azs%x0YH)aqOXkNfg_00)x)x0)m00)m0l0_%)*?)0x0Alzxmxmmmm)H)[sBBl_lBYHBHy_/= )mm)y0y)0mJl xs0BAnGy0l)mYyJ% 0 m0000000{GPGmGyPAYY_ggH)|g*0f8gXk0))lxxY)0m0ms0z/zBx0Ymm000m)))y)X5_PYxzHHY0=zOOB= >x m0mx ?x0xmxx00myy)PX/YllB%sXnH*GN{kH)?zxxmH__l0mlm0)yymymYllY _ ))l?Xqk*yqNXYxHGm)l/8BB)s)0)lBm%mBHlYGyGmGHmmYmHHkym)yyqnnSNmmmyyygg|00my2^KK((Xqaro]^^(|n)YX|LqHmgg))mn_)GXH%*{fXr5Nk00mm))mmmxmxss0G2km0lAYyyyyyyyGHll)0ml0 n0x0%?0 x?[8s 1xxxm0mx[HlXqklBHxҒ`ҭ0m0g`ll__/iYymmm/N|smBBBXG)%mz 10l8Yss?|fi=?sx%BH{lGymmmXgg_8NX˕i*ym)y0mYmx?m%*xGyBH0%x)X_1)mmxmx0YBH/glYHl*q_kHYYX)yyyyA[B))y)yHqxlJs xlN)%kY)mG0Y00xx0000000lXkGrmmmygm0m?lN))ygfg0m)x=k0 0[zxss81)0000m)my_lGHXmzx O[̶_YY==sgOlm > 000)A[Ysx0m00yGHY0lHs1BH/flkHN5**Ys[?y0mmA)m0)m0ymm)A[Asmy* *a*q2AA HgkyyYNNs1B)ms-BxG%x?YYHH)ym0HHGyyYYHnHykq*Q2qrqLHYxY)0yymll 0sf2](((]Rq5n o](^l*85_mH0y_gNYyH_H)ymg%B {rq5NfH0mm)m0mymmxxY=/yQmxY0yyyqkPkl)0x?xxL0x)_Y0xmg_x=zzxY0xxx)Yg8YAXnYGlk_YY O:O0m)mTB/B%0l|8Y lY8N8_Hlys[=YmYABYHm%lXGq _NBl//YmBGmmyy5gggkH8n|N?{8fl0)y)Pkm0x?s0m*q0mm_H0xm0/gz xxxm0xm)?m??lqkYHYmyyyA0HY̶0Y0)0myml[lB0x1000m0BHlkHPHBH_))))))))Y_)msmmHyH*l_H_mmyymmkH_qH*A100yGQ̕Ylxxm00YHBHkqkkglxgNA[Azs = Oz8Am1/Jl1x00xx[zX m0y_smgYssx1BHY_/̭slYmY Y00)lz 0x)HY0%y0l=zz[kGaoar22qqGxz [A?Y)H50ssm)kq5ˋkx=lJHx)m0BlmyGyy m0mBN_HYy*nNfGykQ2ʲv2zs%GGIIM)0mXgzmx)k2L*GyHAnl%BGrn^\iHl-_yBls H GG)x ?HYHB?HG55f)m0ym000xsO )0Q0Q00yyyYG)HHHl)/080x?ymyAx 1Z= s 1x)m0X_)Bk_GYYnn  )mY0*k//HY0BOOz 0XXgHHll)8As)lAXll)xAx%lYss[H_?[L{_|g/AnG)|8BlHyyyyyGPBlB0mBm0/?0mmsls0xm_ANs 1 xxxmxxmmnSnH̭llkyyyyy)Xl0sHQy0_m0/0%x0m0m)mYmzBs xsYx00xxxmyy)Y%%Y)ymm0y0ym))Y)Ym)yymGmHYx)myG)qXnы)Bz000lGGl[/10x000)_l_{q{*q_GHHmmN[g[x z8[gB)B8/%B0000 /ŕmmmxsḽ%1sxB?zll/Xggg[BYY0_sym_/xs0m_xx%0YOs0lyrrrq2S*G*)msxx0)GNqYxx2(*ks0[m0ms_)myHyHHy)BB|l)PXn|5Nmy\]2z1PaIrry0qH_/xxG\(qQyyGPyymG(NыBmPm0mY ) 0vyaGG0m))%lHkyn55f)mm0m0Ys [1mmQQQyymmyyyyG)Gmk))YH_)gllgYsxB)0)0lsx1ꗵDxYxxxmyyn)g8Bx))YkH*B52qgs_))H0Qa*BB%0)A/=[l0mm0)))H_YNgBY?lBBYG//Y0mm_/XYxYYx=̶l_q_HY)m_Gyg%m0%BkyHHHl0m/00xs0mm= zz11x0m)Yffi/YBkkkxmyyyyy0ss)YQqAB0l_Yymm)YYYBssY)xmxmmYHPYllHGyy0GGG)GPkHyy)mHHPYHH)))mmm%yAym_8J0 08l0mG)0/ 0Y/_8N8fk_)00̭gN[ s8B8_l8H0YmgAg[B/mPmlBlzlx8ggXA/AgAXX/Y)Bmmzz0mBx0ly)m))8B022oorv]vnGysAlm)Y)P)f\)B0xG2*km=sYB0l)xPGBH)YAYYkk*5f5\k2ʡeI]B1)xHaaG 0xX2rrngY0m qk )mmPHYHYH*%a2L2mxx0mHy0xxxBB1xYin00mBG0HHGyN_m0Y_zz[Y0%karaQ0ig)0ymymymmm)H_)0?|=lmx)l)0/? 09sx0x1Yx0x)BlYm0%ll%f-z YYGkrQyG)B0s|/O[O xm)mmYYHlY|8mY%xxmsԕ x)B)m_%8?Y)GGk)xml_xyl/B)xHlH)PGHYHlY0Ax)80xl0m0/m J= sxxmxxm00XglxY%kk*l)110m00yyyylsHHBYm_g_BH)YmmmmYBBBllAl xxmYBl) HBlkA--ABmymmHHHHPA*P̋m))HklHlql)Y00mYm%k*kB̭0YHmQG0/?0H_/fN58n*mg_gA[/AXlB8/lBm)HN|gNOXgO8=1 ?J))Y)/gzBYm00x=OX?X|XXH)msm0Am 0mmmm)myOBAiXN\(\(2e2]qylYlmx%)YP_55q)yYxmm*HBmlB0)xlAlz)))mmP)ml)m0YlHHH_H55f5f55n*r(rrMaHxx%Qa _[Y0Xvq*gm)k)GPkYkYHs?yyQa*SqHYYH_msmxl_Bz0BfNP)mx00yx_)mmmHXNlxxG*/H0z$Y(qMo m??y))))YHYB000Y?lB1)lB1 "xmx) xHmgsm0H{X0f/zx)YlHBy2**H/?sl8g|mHYYY_lXq00x)xx0Bm_ON00mxm)lY/8 /HmGYaGG)H)Y?)m)?mHH)GGGPYYk)0BllYs)Bm0mBxx1Jzxx1)x00yy{g8lx)kll1)lH)YGyymm0)smBX/HyyyH YHBymy_m0)xHY0YlmH_YNX_n8-/i0m)GGqYmmmYm)%)HAHk-m0mxx[?0m0)y0?xB)m_-̋*_q5L*P|Nfgggg[xYBYYgAgOg̷))nf555XnN8g|gAs)Ymy)x=Yx0x0z/ /gXgXgԷgNg0zm)m0lyymym[lX|\((vvqHlHmGGG\NPy00*%[O/_Ymmm[_mmGyHmxm0B)2X\5f]a(2eamyyyyagG*ReyXg80P0sHxx0yQ)H)Hs)sY0 sBll0HNN_YHmy0m)xm)00mmxzlzB%0%B%mzz[m{r?l0mm))))YYYYlH0)sH0xA0xY))8x>90 m0 1JB00sH0%HYH/ qYx)YraR2IayGGl/YxB8gNO[szslPkHyYN)0yy[[xYx[8A00mBHHHGlN/mGPkPaHGGln%xBXB)0GGmym))y)Y)Hl)/N=lxYxB) "xxY)sxxm0%BNOxx%klss0mY))0lgyyyXAշmmm_/m00mlgX_m)??sBNNgHBlmyGQyN*Xy))0m0mYY_*HGmGz$zxB_%mG%m0B000l-N88N*NNL*Hg88/Bm0mxyXg||O0myfn|f|NN8?smm0m0N%zsmsx0BY NN8NN?_A*nms0mm)00A***PmyymXk5Xnq2nvv]]qqn)g8qyQy5lP0y0ymG k_/0mA)))mm)yyymmm0)0G2*rk qrvevovQmQG*eCrkHN8GmyBB)mymQGl)Hz0m0϶0BlB)xgXlABm)m0_Al mmxm0xl mxYsBmGk]QG)y0mmyg8xYzxsxmml_BB/09x0mH0% ?0/[slY))x0)gX\Bsl%xraaaaR0%smNOO[ϨYYlymgNB0yyy B8XXHsXkHB_B*l*kH kPPkyyg)g/_00y)mmGYkm0msmxYBYlϐ01x0xYm%m0?/sxm0B_11smmllYmYyBAm/)myQQggB0))[BYYs||NX//l?s)Nf?qk*nXGmQyGQ*n Hl)Ylymmmx%lXHm)xmO= 1gX/)0Hs?%0XN8NgNiq55ymsYs/sx)xmyy))GH_8Oxx10G-N5|ON8gx%))mH0N/xxxxmx)Y0N|Hk_n*ylmPPmmXqqy0y)y)Ykn\ r2]]*lH)8NNNXyyn5 lk%k k*X/_lAA)xkBXl0)YPYmHY0)PHfqqkkmGGqSn(ʲQaGaya*^5fkXAyx[ xm0)A8[/Al0sBxBYmmy0nks0 /mlA*ḽlHYx0$ B m%?)z[l)q*kry)G)yy0m)m)x)00mYBYl BBx0l8?m-80B z1sxYxYy0mm)/Gnfl)m_HSQQymQ0mYB8N8/xxyyN/yyyyHl/-NXfnXBq0PGyyQyqrn?///lnYGGmYYklPYH0x̭smm)YH)m>000mxm0Yzl00s lHY)HYYss ss0mYm0m)ll_yyGsABgmX[xYls_A?Y)lg[sx 0)_gXXnyyyr*qGHHHyy0_BmmlsXX{Gmm)YzO8B/8?)YB)mN8X_qL(P)lY00 mBYmHm)s00mnNf2H_/X=lmHPkl%0 /mxYxm0mY)0sfN_HHkl_kGPlHyPP)mgHGmmyy)y)*NN*22]*{{klNPGk2\q*HllHy?NgXglA/XgAlkllm)BYlϷm*5kYm˪\(q5qaaGQyQakl?Gmm00kl[s0)XlXN[0)010 ?Y%myH/n_G00OXHn)l[[smss[xB)00%H%xx̶ [_Y_XX{ Gyy))m0mm0my)YYm0zgAx0ssYm0% NNXn[XBxx x0xmmYmmym0mgH\flH)*?qq{q Qy?/glz[mmmyyyA)?Hk_Xl%lLffԺX_)YHH_*HHnyyymQQy GlgX/[?lB8N||yyG0mm0ml%Bxs)0mxH_HB 9xxY%[xx [BsH0x)ymD1sszBs0x0)0mmAyyyymmB?AlB 1sJBxY)lxJ mX\2n)0yyf5H)HHHy0Ag_lBggY?gsy0mmx1xz϶8m0mH0m)?-|NAy)k*qnnk_B0xmm0gfn_lY00 s1m0{*)BY B1Ym)gPHHY0[Nxxmx)m))?BY)B*)my)PPPngBkmmmmm)mOGPXfXHG)**q*[g|lqN_NNXn*HGyGH kq(XnGA8|g*X|NNklkkmmBHBHOg0)_///BlY?n*arr{G0yy2]\qq2n_)m)m0yfQyym= 0sBl_m0000϶s x0sl)y)PHl_?BxxHsynH0XX_[=x$zx00)?xl[zg/Y))mmmyymyG0mlXgmllzm0/g˭q%N8gYx0 xxmmmy)0OXf\XB?kyH*___y0)BHsmm XB?myyy)y_llXHBx%m0nGai8)sYHBmkGQ00myqqrPXXsBgN8)mmymmm)))0g BBsBYxml8g? 9-880l/BBzxJymm) _s Y0)x0Ylxm1sfX)yGm00B=̶?붭?/XA) sx xlgg/qPG*qmymy*XXHPYPmy0y_HYXAs?l00GmB%mxx 8?m0mm0Ymmm%G/?YGmrk\*yBk001Bl0mXqqymHksx l?* kGB0sBx1mY5\Pkl)0?/1YmmBB)H%my_qHmkf)yPkXX00)m000yl[_Nf-m닋*/A?Grqf_)G k {X*yy_8g)HAglk__ymBll|Am0m_m)̶BYYx%)yraa2kGGG)yyy^(v2{2*_)my2GyyyGYl[XAHmmx0xxzxYzl)ykPY?10mmyXNXlBAllms[lY00lmxz$lmm)y)mymyH2AHY/g/NσBs[xlAkXAJ?%xXk)msYx00xxx))mymmB|*f\|-my)QmGYGH)YY[AAggHz)))Nf|XYx)Yx0mxQmQr G%Blm00n5XqQ)%yQQq\gXl=ss/NN)mmm)s)m_XA0m1sϭ00g[?/8gXl1Bxx0mm)mmmyys s )xAA[/lslyYgYyllx0?x?lB11[lm[A[ sx z_X22 2H)mm))GYGYHHHyy0ymy)m)_xmB?Bz0x0001Asm0%Y%HlBHkBl*0lmmymyGGGymPBl0_??B)mm)HlH0YBYY)YPyyP_mz)lAPPHlm0?J0xx))_/sBHs)mHly5x0m0PPmlBx)0xxPHH/LNNB)lX[A XggAmxmmYYHq-NNHGG q\5\LqyYmm)YG)l_l)%)?? |m?)z xs sBlGGkHYzxBz 0mmmX*\*qq)myyyyyyG)y [=gXAsHl?lzs00BzYYmGmmmmx?Y0mm*Y)m0lm0 )s)lxx00sz[[zxxmmm0ymy)G)l//ggO8[ Bx///x HPA0B10mmm)0)0mgXq5NfBHkPm))ssBYym00H/B_A[0kymyygg__Y%1%xx00m)xεks00xx)0Gq\NNgmy zBslAH)Hqk00Yl/gAz̨zl[lmmng-_%BgN8X)0000 xxxxm0)))y)kssY0/x000kfgGmX8?)0 =xxg8BsY 0Yx0YxlAXg[s sxz=kmP\5\\)YPmm)mmmPYHmmmy))mY)[0)0lA/l 0 0 0BBxx0BlgN?k_B_BYxm)yyH00lxmyGPYHYmY 0xmkrPH)mBB1mmyym |x1xmmymmzYls)m)0ymxmyxx000BXBxxHHmmX_YHYBX sx0 km0)YH_X)GG{nS2k*0)m)kH)kHlxx?l g|[)0x0x 00x000my**GGsHx%_m)00i*n\qH0)GyyHGPmss xs sl_BYsYs x B ssgHm)yHmy0xx0 lx0myyyxkY0)x sm zYs)00B_m |T [xxm0))ymyyXgg?8H lzs [=l)Y[_BNg?%%Hmf*y?=/حx)x)mYm)m)?Nin5Nl%YBkr?YYYmmB)mm00Ol_lHl[lx0myym)m)Ym_A?H0YzYm))m19Y)0yk51x%kXfHk_kYYzB ))0Hksg淭AO|[Bs[sm0H/HX?8=J?%%/XXHmY0s00x )))mym0)A[sYHsx)x00xY 0000sm0Xxx0OBx[=8/BY0Y|00s?[gYYx1sxB8%qov2qrQGym))))HHk_k__llY)))))HkHlkllXxx0001B00xms0))*Y0_Y)m)mGGPllkY0B/YBm0mYkHlB0)mg|fXlB?Bx00mBYHYYYYBmyzxx0))m)Hmmymmm0y0yymm)0yy)y0msz000)B)%HYHBkB*?HY0mxYB)xm0l8m)lllYmYlBYslm)ymNN(S2qyHH00lsm8xB00/s00mxm0xx0x)myGkyBs)m%z00ylx_Xqn*my)yy)HHY_Bm[1mxx000000mx0 1xm)Hm00m0mB0mmmmyYHlmlB0B sHXm_XsxAzsx Y)mm)mxyyN8BOOlzssX_xl?Hg8i\_)xsXyBgH0/m)mmm)m)m%|NY) P2{_0Ylzy)Y?YBOBn[/xmmmmm00ymmy0))G)mm)0O[ lzBmBl YYm000yHHlm_ymmml ls0ymy)yGH_/g/=gOO lgm0/H{mm0kB?xls0xm)m)m0ymAAzA Yxm0m000mxmm?O8_m_|_l0[N[0zB?/xxYsx8mlBsllB sslnav]rGGyym)GPPHkkBm)YPY)YHllsxmx00xm0x0000 l0x)Hm0Yklmmx))k)yyPHkl/ks/Y)m*_lx0 Y0)k*Xk?szY)l_l?AAY0m0lzBzs)yyy0)m)0mmm)my00myy)0xYx0Y_l%BHBH_nˋ)s)00000Y)0xlB/XlBzABHmyHN52]]_XHyH_lY00=x 08m00/s0 )xm0xY)mqk0 YJ10Yl?zH_X*nnqmmkkHY)HmYYYYzzxxm000m000mxxmmzBs01[sxmmm)x000xx)xmHY)y0H_B0B?BY1YYxlgf/_Xg xs1xg))YmHXlxBOO /zzA[)Bls0lfNNG))0)Ymz0x[xmmm)YBm0ykXABBHxk***n[m ̷lxG__H0sOY/[/ sx)))mmm)Y)YHYym/N A/s0sBY)x0Ylmy0GsBmmy0mG)))YYsYsm)mm0yy8X̨| Y szx)/_H5n*%H?yB00zl1xymy%%xm))gll)xxxxmmmxs8YYm_OA?/?/lY))s/88/?/H%YYsl(q2Gyyy0y)yyxx0xx0xz0 BYm0mzYx)%my)0y%H)x0ss)0lyk8?_00m0ymmmxx0 zBgz x0smmymmBsY)0y0 [[s))mmkHmy))y)yyyxxBB1x?Xni_*Hkq%Hym)xlBxlm))))BNN8)xY?B00)mNN55^]]qS-|XyG)m)00mzx1xs0m//)0)mxxxmx0lyqXnGm%/%y2%*{nByH?{Yyx?xmYY)xxJ0 xx0m00m000xls [xmmmY0 x0m))xm00yyyYy_YXz?sxqq_nXNNgYxxYx0g_*_mx)0m0000x8[[xxBgX Bs00l*P***Py0m0zJBmsY0s_xsm00)_0x0xls%kGn{*nksmylXB0Oqnls mmH YBl)PGAmmGXN-% -iiLmG%)m0Y/BmmsY000)YHl) Bx_lx0ymm)yNzlOÕz g_BB)gNn\ %/ll0[lsmm))mxmms 1xxmmx))m0)BB[8?AY_HsY0_g_Y8NB)YYHH_XgYYYssxXH2\\(S2 yGGy)m0yy)))0yym00B00 l x/Y00m0s Bl00Hm0mGmHmmm000mmmnmG)NY)000)mm))Bx1z?gN|zzmxxl00ym00Bxym0xmmmmH_lY))mmy))Hyyy00BYmm0/fffNN|8/i)G0mzs)lB)YY)/N8HmBxOl_HmmHNNNqv2]]*qH)_YymyYmx)0z1z0BB_xxx)xx)m)kXnXflaGQ/%q8AXkG%_?HYB??ml/_xxJ10m00000m0x0mxm0zsxxx0xxsY0mmx)m)0mYHYlm0YXgg/1sz0)YqNf|NgX[x10m[gXkmAkm000N8[m 0llx)X5*mm/B1H x0YYmx)//x0m)BBsxxHkH(2{PqqY0mmHA?YB ?__A0[Y)[YYHYHH0_qG %% Hx))xlmy0ls)mmm)YHxm0AB0m0)0YX_1s8A[1Bsy5N5*)m0mGmX00B=[xmmmY00)yyyXm0xx)x)mymA|zBBYx)sHH)y//8_%)%s0||_%%HY)GnXqn\n((aG))y))yymyym))YyyyGm0 01zxmm0x0xYmYysmxmxY)ymql_Y)nX0Yxk|{))H%H̶#h==mxx0sxxg/AnXAm00lzmyy)mm)kHYGm)m)0lsymrGyyym))0 l)0%8|glNN*Ym00A[[mPPHGgN[[BYXX?qG)*5(]]2vqq000mm YY)%mmsBl[mxB0 B1xxxx1x)mx)m_XH*aQGmymN|Nnqy*qk_Xzg?=xlxx xm0xxxxm0x x0xz 0x00)mYBy)m)m00000m)[0gg/l/0YYmXL_XgNymQN[0 [ mBB))A/l1xx0sgg)zY1011Bx[5Nlg8Tzx Y10m/ 10_Yyn2{{* HkGG*H_/ 00xzxs0m0_l)y*X{kRM}Mw o Gmgxxl8%)ys0 sxxBmmYHzl0))mm000y)g歶0lO/Y ymB*lY**mm0_l01x YxY 0m0ysxxxYm)m?8Nzlsx0m)mHg8N8B)YH%YmH|NO8NҶsmHYllH%fLq(2]qaaGrGyG)m))HGy)ymy)m))YHymym)YyPHP 0zsBsm))00xxx))Yx)0Ym{gnYmYX)BsG)mNNB)m)X|XHB[1"O))x $?Xs/ 0YYm0Bz)yyyy)x00m)PG)Ymmy0xlBmm)HG))Ym0mmx0?NNX̭)%8iYm0skPm?Aحlm0H{̋Q52v]n2*gHxmx0)00mxY 0[Xs BH01zsxx1xx)mmnX5\5q {lmnXf5f2HG*_*ضg涶Bxz mxxx)000xmxxx s[z[x00xmY)mm)m0mHY00mx0g-BBl%lmfgNyGG[ xx [8mBXYy00xx Ygs101Yl1x/NN85AYs_zss $x)mmmxBYxJB x)m)q^S2n{HGGYymyHkl[[Y0z[s[?HHxx)x?** ]o}Ko] Gm=zN{m0sY[[_XA0x/YBl000mN8=0m0 gsBzsxmYgNf*myY[gz xx0s 00xxy0uY[sx Ymm)))GNX)B[HBsxm)mkN8gX8Xsm))GlXYBOYmm)GB8GGGGyH)yXH)kk0my)yylAqk?s ym0xxmmml/Y00A/Y0m0)m5nAk)l*XXB%XGy%k|gmm|Y/ z">"=O x1A10000xz0mmyyyyyy)m))mHP_)mm)BYYmmHyymmm0̕?_Xg?_m)mY8Og))mYH)00[0nHf|SG2qrmgAxx0m0AYmB0xx0s_0mzg[sszsxm0m))A|NN\5NNmAng8qX\qq* 8gll//00/s x xxmm xxxxxm0xmx)mmxmxm0)0msYlx 0mym00l?1mmXXXgl)mylzBYz[AlXҶxA8Y0yy_BsmYgNglzsmxxBYxl8B0zAgsxzsxxmm)mY/=[/̭00yyG{2X{qyyyyG)y?_?l0m [//_Y*A?Hg?)QQQRKowKKeMQmyy_σ?)mxlX̷[gXXg/lAH)lzmmg?_mll))[zxY0HxmYBsm[f8|gBgǪl1xmxssxmxx)ByX zxx)x)Y0mB Y00)mXY?AB0mmm%mNN|H)B)zlxx)mfNX)HnqGG*/mm)kyymm|f|YHlyyym)P̷l??zxm)mxm0x)m)AYxmmymqn_)8_N_Gyy*??H))mHl_YHl_=EDDOm1xzO x=))mmmg0xmmmmy0Hmm)HHkkA))mzmxm)yHlmxx[?m/gX//_sHxlN8mmH_0BxzB AYx0m_?%{ԋGqar)s__s0mHYHym00mm000x_Y B xm0mmHNGyyGG*l)5f5fq**q**qnglHBl?m0Y/x Bsx1x0mxxx0x0x00xmxmYm0mxx[XxYYss0)myH/|N/lHBfXklNN_BGmQzAX|[10Bm0y/lYxxmxgY[涶/lll%Hl))xYm[g?ssmx)0l_Bxz[_Y*yQm*Ln̋y0yyyym))A|N8_A ?[?/Akkl?B)0ymGoKwwoQQQQ//=OYyn5nBmH/fNgXg?_)Bs0//|0 ym0xx0)0Y8Y0YHHYmYNNNgAYz [ 1xszxx0x))YmX[ϭ l x0)mmYH)xlYYx)mmG)))))xYYY)Ymxm))lHBs)0)))lklHYHlgl)0)GHlY))YHyyy_mHyymyym[ggOmmmmm0szg[sY0mm0m)))ymGHHHY*Y_nqqqqyXG0smm)m))mHP "#c=Y011O m0mmm)mmmym l000yyyBmx00kHHqn)m)llmm00yy)xls0lXg_qHmmmx[nAlmmsB0xs0zz)mxy0m?HYymkgg8HYklHmyy0m0x00000xH//?x)mm0)Ykmm)yGm)X8\f닋_k*58kl*_??HHA=x s1xxxm0xmmY)lOX[Yx)Bxx0x0z/BxY?Y0)mm0)mmH[z01YPmP**55gHGQ{ //Axm_0ymym))mmym[k/{YB*Bm0m0sAl%*̕mHY)00XNXGGGmmHl)m)lHym)mkH_l/H?X_%YHl *X_BH0)yy Ro]MRQQyQYX?Jσl lg*\5g?Ys[/[?A|/AymYYY0YNgz̶xmxB1 fN_0Bl sxmm0mHl00XY_n[zxx0xx)mYx%sm0mm)m)m)GYBmmm))))mmmHHBx)x)Gy0mPY)YHBY)mQyy)mYHGky)mm)YHy0)m)mk)Ymxmm0B?/l0xBx))0YGPHHPYHPH_klX8gGkl kqq*HQ0GlYHlkkl__"=N[x1 zsm00m0my0Ymm)Hm)mYlqqXm)lxm0yyyyyyyy0__0)__lXAl)))0Y)Hgmxmm0B0x xmYY)))0HHxY)mkBHl_HH_B%0yyym)000000mm0[/)m0mmmYH__/yG)m))gNf5N{)H*{N{ll_l__?*{*_H = xm0 0mm Y0lBB0x)sH0000l00xmx)xmmxm))0YY[Bxm0x0my_XfGm%Hq?/l=?/lg[0l)0yymyyymm0ymm0y0)[[Y0xYGHHH%mm)lmsBHA/zsxYsy)00y_N?mGmm)mmBmyPkyQ))mmy0)mm0/N̋HkX(kkG))*GmoMIooMo]my_N xxms_mlA15f0Bz̨/[A=f/0l0yXBY)m)g /A[[BlB%BHm)0l[gsm0mmYBl)Xy0lBx1xmmxYk0Ym0mYHHYkkYll0m)mmmmYYHGGGHlBx)x)HYHkHHl_YY)m))Gmmm))yYH_l))))Y)m)sl0y)m00))msYm))x0)g[xBs0xY0x))mYkl_____)XNXYH HymHYGGPPHH PsO#cx" J=x[Y0Pyymy00OY0yyBBmxmmYkAgym)))l0m0xm0mymyyyyyy lYlHHHHYmmx)xYlXNYmms0O[0O[Ys)YH)0llsmYYHYqAm)GyyyYY x1x000mH0Yx0)YYHHl_X0)YGHkHHO?sNNN8YmmmHkB0Sn***q{* k0z x m_YgYmBm0g[xx0x0zx0Ys)ymmYBAYsx?Nf5ym {*L/[mm|[Yxmmmmymymymy)mmYYHBBHB0 ?)%k{?*smx)00YlyyYymyyNNi)GPYl 0mkknnym)mYmxm/nk*q**GG)%rRr{_x)ms=t>"D0 EE?HA555f5f_lzA[[?[0?0ymy)m))m)mX[ B?/BqB0xslxH_/z/sxkyy00?0)m0mBBx0x0Ym)_lB_A_)))))mBH0))mm)HBHk*qA_smmYYkYHk_lHY))myHYlXAy)))_YHYlllB_mmmmm0)Hmm00mYx)0x0)z_xx mxm0)myy0ymmyYNlG*PGQymymyxhD促Ogx z=z /mHk)0mm8l0y)_mx)sk_gf)))m)x00l mm0myzx̷y)PHGm)mB?lnBy)Y0Y0s $YBYBYY)y0))?lm0mY̷yyyyyymlBx00BxBlmm0m0?8/BY)0)HlB_?0kmxm)G)Y0N/YqNGm)mQXNfnl**{*]*** m0sxx0xs?A/0BBm[g s8mmxx0/B0YYYYm))s00A/Bslzl_m*Nqf*yiԶ//B08g/xsm)0)))yyyyymmgsB_%_ YmY)H_* ?ˋ0BxYl?yYm))kqH))G0lm)mG2(nyHHHYBmyqNk{n{G **q{GGHr r rGm)xmm0>">E1 NNfN5f5*knl[_00 0myyyy)ymm0yymx[T0msBsHHYmm)zGmHBBzH)ymmx?YmYYlsmxxmlylmNN|˷Ym0mymY0x0mmAYkqX HH00sm00my0)mXymylmlYlHyymymA00xY1/%mxmxY?zBs0lB s0 )00[BBlgmm)Ym000mm)0mymyXkGGk GQmyYmQQ ֚ح|/1 =z0slmkkm0y0yxgl)Y/0)Al0)m)Y [llllBGys_BlX_x))s_AkyYGy)H0[[mzBzHm00mmxllxmm)qHQyyyyyyY0 xs000mmBN/Y))m0s0mmlsN8xmm00mmiN* **?**y)0xHxmxxs0mA0lAB1x0xxA0YYYYYHyxxz_sxBsxH0_/)Bi25NqGq2\i?8N |?mYYHmymG)0AllY Bk%m){**%%G)00km0yxySfqGPxlBmmmykn2nqqX/_))GN5i]nkq**q**//rr HGxxYx0EEdddEsmxy1sY8N|ik_A[smx?)0)mmyG)mm)0)XXH k BHBm0Bx%B *{ilsx)))y00 mmY)mY0xy0Gq\mlkmfXlH))mmy)m00mAXAqHHlYx0m)yynXYmB0mHYl_BB00x/smmm[lxxH̭000x?A00mm0mmm0mYHHm%kHGyGPlyGaQQQYOZ϶ ?>z mk0))H|O/ylgzm0x YlYHAY))sgXlBYBY?YmlAyyyyyy0_gl?/Xԋ)mmxxBkymymY)Y[s A̭ zBm0mmYBlxxmmy)PyQyy101xsBsx0)xm0lmYYym)Y)00YgXYBy0ym88?%)̶)0mx00m{q*q****k)Bm?lx0x x00[00x000sY Ymm0mYYHYHYmy0s)m0/|-zmH5f55\2nf*AY0B88xYY[mmyyyyym0_XYl **lYsA/m̲**ly0myHAlHmx)m)G)qfqPP*ll0my*(nnqGXNA?X-Xkfq(*qqX%rrH)x1m0EUĬE1H00 xmyX|GkHHA0ANg[mm)mGyymm)0gHHk%*lY)YxAAB{kB*-BxYm)y0xm0mYy0y0*X\yyynNfY0)0ygmYlHHHlHHmGk/Y0m0ymm0m0mGq*Hmlm)G))_[/?Yx??00s00z/0xx0Bsx 00 0xllBHB_)0))mAY)m_Gm*l{%)myGXXԷHHGPrQQQx= ON=s0 x [B)kY))ym0g00yl?0mm0mHmx000glmYY))%Ym)mm0BgO[X_Y)%ymmH/gmyyyHOgA[Xg[ mmYsm_Bx0)mm0yHyQyyy)x[B 1sxxmmy//)0x_B)00B//A? m0)[)0s00zm8xxBBmmm00/N2q{_k*** PylYm00xY|000=m0mm)00sm0xxBxm)sYPmx[$s[[YHHy/x)\|Nff5ѳqn/)xgBx==_mxYxH/Y0_ym)[XlHql*?**k*____[? {S*_*qyymmllAl_0xmmGmn52A225\X*|8-l_XXLXNfin***qn{m Q)))))mx@"4HyyyYX8gmGGmg|Yx0/80mYYBHmmyyyy0) gk GkHmlA/**SHmmm0ymmm0xxYsyy05n)mmlH0Hk0))0lsA/mYkHmH_B%smyymmyyymnnAY)_)))mm)YHHsY0?϶涭BlB00m00x0zx0)x 0 0 000HgXAl%xyyXXA?BB_˷)))y)HH_GxGmH5nHH kaGGm)sB8=zY100s/llYlmm0m m0yml ?YsXX/?_s0lHxHHlllYYH)_0y)0ym ///LXAg0G)0x̕))QXgOA8_x)YYHlm0Hlmy)HqGyyx11zs00mm0mgB00?)00B/[l00x)0my)mxAlx0mx00%_00))mxXiGy*HkynXl0_s0X0Ys0mmYxx000AY0__)Ym)0xzB/%z?S5f5N|NqnNiBzx0xHY0 lnYy\qyH)YgXl*kkk_?AHX\ **nm_H*k0xxmm)GmynXn{_HH\qG8NXlkB**5 *vnB%rokyyyQ D44DlPyyy)lYl/Y%Gkk)H0HXNN0Y[mmmyy))llY*k**k_q_YB//_)/**k0mxmyy1ssHByyyYGG%kq*)mmYxl0mm)lAH0Ylk)0GYlH))mHyyymG_NAlx 0y))))sBB0_OḽBmm0Y YB̙ϭx 0m0?|fX/qk*qggXXX GGyz)P̷YHBHG rl*yBG/xs% xmH[YmYAYHm0y_)yymnA_BBAXgAYA8_YkB_k%YYH00l)mmm0X/sm0mm%A?xymBB)yyG gg|Osxx))YHYHlmxYB/__lH_Hm_HQyy))yBXmm0yHklXBx)m0/lm))0YYBzslx)?XXqng*HN5fL-sxGG *lHlH|Nfn?l[s=0 Ymx00Bx0z0BH)))m?XBYy0%)%fNNNN8-_*qN%0xBYsAl)0m Y1BNH)lBgg2XG *kH-?gkG_*qPmBl/AHxm)YknXqrXy**r%8?lkHHG*ffXGGk nqrf8A rraP Gm)my2ssJ /?llymmH)Y?HHmmH_YlkHY[BxB0xB[00y*y)myAX__?***k***___/s/{{{]qkymmHyB 11llym_)ymm)X[XX_lBYl/l))HkY)H08/l%m)Gk_GmmmmG_x))YYHslYx00mHYm̶zYxz?sm?fff˕fNNNffX/kGkH%mGPyBlmxmmyYHlHmyG%GHYHkkB00xs1xmxBYyY_/Allmmmy)0Xyy00N/AAng?_88lH?**lBHYYm_Ym)))0[A/Xz0xxm%i/{)0)/k0__H%QQyX8[ Xzxx)m)Y)sYg?lHYkllly)G))yHlY0sB/[x0m))H{8_0mmm000xB[lYm))̭BzBsYxx 1xsNfm|Gxm kk5GBHfnmmzzzB[xm0gzx00xgm00)m)m?) Bsy)myx)0yyyr5NNG**{XB0 xYsBYY0xBBY%kA|lH)XiXˋmmHHr*k)//X)G GmlllAYxx)l*fiHX**nqkPGGBXHHHHmmf0mG q88 alkkPyPqkl x1Bgm0mBYm00Ys))HHxYsϭg_x0 YlBY˷)Y?q *qklklqA_H_Xn*q2X?%))yxx111HByYYHY)myH0Ymm_mlBB)000y)Y)0Hll/HGY%?X%YB%H*mmym))mmy00mmYx))PYHYYlg8_HY))kYmsl8[00==?sBBf85NN5\Sf{yGG aGHl)ms100mm%HYBHmy)PPq*GGx1x10mkGyx_[A m))0HmgY)0BxfXlkA*˕|Hl*?*qk**H%sl0 mm0Y-As)Y10lxBmssY_sGG%NNs00zssYmxmmm)Hl0HgBmYs)xYxAH)m)0m)m)00)m)*]kGyHl))0sAx00000xm*g mx000000)m0m%5N2Pyqk))kxxmqqHYHBmNgl[Ճ[)mmxH?s00xzlxm0xm0Y0B0yYY))x0G)QyHf/Y%G*km0H00 zxxYlHYsx /BYBl{N_?0YXN5/m))mkkqg|8g)GmQ 2l0mB_Hx))YHlG0{\kym0B[G%HH*H%GGmNm) qylgH)y_Ym {?lHkYlYz00xx)Hm))m0)sm)m)0xs ̶1)s/kY0s1l*55 )kPg/̋qYBlH?/gLlQmqq)m)mm0011BYykAsBsxYmGmmlAxYH0xmx00Ymml_*??%)%H?*YkkmyG))Y)HlBklBlllB_Ykl_*nA?Ag8gg|?m)Y)H0s8gm00x%lBXfN8N5N\nqn5nqYHkGr *m2))00x000m_??ls_llHHHHllk*)xxxxmHGyym/mm0)PYkml_ Bm n5nԋHl_|N8l_*{**BHYmxmm)X/%01xm1Y%y%Y%gJBG%% H|m0x0)YY_lgsBHlBHsYl_YH)m)HHHYG0)0sm)GG*QH%mH0Bgl00000000ykg_m0xmx0)x)Yxy0f5(yQyG)xm0mGH)HBlsm0qPBs1 s x ) [zx0m0l0ll00xmHHm0myGay*A0BG)m0%10? _BB [)Y**X/BmkXf5mxHnq0NN)G)mk2\8Ym0_xm))HmHH%)%rr**kPGGmmy%_G0mYGymlGymlx)mGrrrQ0sX?mGGyXAyy***ql0)H)m)0B 01lY0B_Hm01Y%m%s00 JHxsYBYYxmB zHlqNP_)g̕ikmm)l *km/f[|)Ga YGl)x11ByPXX[zB00Y)x0[f)m))mm)YHmy̋_/LXG_lkkHnBmmsBBYHYq8gNX/m0yq**q*OggAY0xsBxxOOxlBzA1zz%ANff555N5]q^f\LHrk r]kG)x)m0m))m0YY0)Yl_)_H)Y̶l_lPqym)mmyyyYB|)xmmlgklHm_N?l)mͺ0%k{_XH%H_lH*k00yy)xHGkYxxYm?0xmHYHBm0Ys))xxxxx00l%[*kBq_*_HY%HHmm00*kayYx)0G*qGxH0Y 0000xx00x)myYmmxxx)x)m0?--%YY)YBlm)x0mmxH2Hkf\fP?ssszxxBLH8s0xzx 0xmymy0BxmymyGmY/gYs1sBxxsm0[ls)0kXYY[/)B_-H*_?sHAgkYmxmY_XfQXNH)mm{nsmYYBGm0mYkkG5Lr]2rar rGHszBBk%G G%BkY0mykHymmG%HGmYm0mmymqkPm zB1G)/z0zxYms/ 1lYAs0xsxxxsBYmlB[BxlN_mN|iGmG)%l*kQk|N-%%mQPrvLkYYxssss1ss 0P0G[/zlss)0lY/xH/?_YBBmm)Y_fqyXf8Bmm)qs)x0x00Hsz)0e3 vmm))H)Ym?m_l)mm))mYkHmy_NXnLXX*k**%0z/BgB8XAYQ*2**qiXmNm00xYs)x[z/Azxs_ngXX|_)q*q5in2PHr kH0_Y00m)llYx0m) 8gx)*knXXkGqyQyyA0lBl)YH)mH0H_YyYmyB%%Gy/X8Nf*m0G/nlB0mmx-N5_m0mmGmGQ??Ylm)H%%%x%Y)Y)0lYBBBgNl?***? Yk*mXul)_k{H0n{ rmGkkxmxXl0xxmx)m)lxxxmx)mXB%BY)[XlYHAm0y)lAsm)myqGQQP)) _$s0mgXHYmx0/Bsx0Y0mmyyyyY_yyy0)A8=Bs xxm[s)Y0N0mx0HHB_//AlY%zkl_sxH_HPy000mY)0))mm̨_lls))G_?lYlmmyyrQ2]n2IrrrGy1gOB?|?NBsH0?XQykHHGBq[))y򋋋m /y0zlH000 91myYHYY0gxsY0HB)B/_00mszkGk)H Hy%mmx)BHXY%xmxGkLX_BB00x=J?m3b;\ > m0?_)m?N)Y00)mymmxyyYmmmy0m)lX)mHH_n_mm)0l/zBlmYgB000000m)lB0BnYf5fNPOW1 1 0lgԋk kk*_Gm)yyym_)yy_*H__HkPyykqGy)mkX m?gg/?YmXNf888lBmX[BsB=__G))_m))0mlYmmm5N(k kqq G**nylmmm)y糁 F VnrayyyYB)m00Gxs10m)yyGXym))mHHY5 m)xy0 gX/_AXNsH/OYxgg8A8|YYlxBO88=1??ymm)m)))YYmB)Hn\qx)xG\|qqqq%)0%l=/1B00_l0X)BBx00YsmxYm0x0m)YYm_8XgXk)0)ls0Bgy0)m0_X)yymm??qmq*H)lHm))YHymymGAXg 0m00xsx8z0)PGymsHBlsxx)s00_g)0mxxm0xGPPs)m0)yymHmymyymy0))0GyP*PymHf|*kkB%0_A/OHgxxBmmAAYzxB_Y=x0m0)mlYH0m)0m" 1111 00m_l_?__m[B00)yxH0mY000m0m)00)kH)my)mnXы)HHl)l8[[0Ϸ00000Ygg[smHfN|NNf-qkAmOOs1 s  ԋk kkkkkk*YymGyPNNXm)H))mmG%yy/XlxYsm0HX[l0Ns?m/O/Bzmyly0mmmmym0HBxxx0Hf5 qqk *kGyyy)kmyyy\Fyyyyyy)sY1m0))0myyY)Y z%xx0yyy))Yyym_Hy*)mm0%2Xq))XX=̶/8XY|gX8|gN8_smYmg8g|?mYlxyyy)ymmmyHPyn**]**qSmmH8|fX* **]{0 0涭1mxmB00mlyxm)_/m00xmmYm))xym)m_gNHm)_X xmBxmlXg_)m%)myNHlm0mmykNNN_))m)0yyy)NB[A ssxm gHAmmkG)yYx_Bx1x0mx0yY)mH)*)mY0_fYkYxm0)mHXnHll0ymGGGy%))HYHkyyy0 8 1B88A%0)0)mm)z?Y0sxB ?mmmy)Yxm0m)E>DD xx00ml/sX)ym0)PlH0HyHy0mYYlHyyH)mY)yyyyHn5n{YHl?YlA̭BYx/O=00x_gXBllYYx)Yy0f8lGPmO$s s sNH_kkrH**ymyyymy)f5HyyyyQyyyQymy)y/O|BsYH)0))[ z00ml%lH)yyyHm0yYmyYkHk)HH0)mH?S*S*k**PSPyQmyQP \\ yGGym*XnHHm0mm)))HPlP_? mmyyyyyy*k_kP0mQ0mxkXyy)_8/A/mX||?J|8?Hm?l1H8?_)m0)))H)mmPGPfq **\5/NnXqk*//H000B==[_m)Ymm|Nmx0mxYxm0mx)mym)mHAmymg m0YA)BY)xAԷkm0mlB%HH)yy)yYnHBYym))yXX)l[ Bxm)*XYYGyyyym)B=zsY)0mY)GkkYH0_ffP)BAB)mmyxBNklmyyP)lB0)mm0m00X**zz[|8/HYB%%00ymgB0xBBB0/Ng/Ak)mY0)0000#D x1xmmx /_m0mmmmPPlHxBmmm)HHYy0))yyyHXfgGYkB[zBsx̭ l[sB[Bm)y0*|l)xky)g ss sm|fn*{H qHy)mqqGyyyyGy)_Aqy)yGyymmmGym0YNxBB)ymm0xs YsByzzmY)yy)ymPXg_mmy)m|f8m)m0XA5n{2 kk *QHGrn kyGqn)mnNYHY)Y0)XPl_ByPN5˷yy0)m0x))GynX/z)YYY)XXBm[NBH|/zB[gXY)mm)ky0yyfki|5AXkmHk G//%)m m11xO8O=_YYxsmgX0m)0mYxmmmym0xxxHH)yy/YxABxBY_nl%x)))yGPHlPym)mymm))Hkyyy)yyyY)lxsxxBk*%myym)mY?zglzx0mYHGmyy)YY)m)HYHGYYm0m)y)?HHlYmy)m)B[m0)0m>괵Hl_zlZl?l0mGHq*G))HmAA*Ykffmm0mBYx0m00> z xsy)mlmBmyym0))PPlHm_0)yyyHHk0)myyymyy*nnHlB8ḽ?l=O/mHA_lXyym)kXB))_))Ts sHyXmHGyGH0m)X)H0y)m)Gymy))mm_YYBGyy0lYsmn)??1)_k)myy)qgXly)_f)y)mBgBkg|LXXSGG H *kkPG5fn*mmm)_08Nx)yl__/?Hmm)))Gf5HmPGyyyfPyy))yyGym0))yyA8gBsYH)y)/s1?0H008/zl̷_ql)Ylyy0yHqH2 yGG knf|mBlHBGGGQQ%%)ymm%sB[ll_BHYYmxlXgn0sx))mx))mm0lY)Ymy/0H) xm0̷Pymyms?0sm)HYHHlPmYYYYGGH)YHHYYxx/nyyyy)mm/lx[[8Axm0my)HHPyym)))Y)mm)YlY0m0m0Y)yyl0mmyP)GY)x000mx>J_zHmmklzDDm)mGmHG%%l_0s__HHmm)0mmnN55fymy?/Y00xm0B11x000myOB0XmyP0m)0)GHl?))mmYHlYm0yymyy)m)ymm)Bl| O[z8=z[)s)0))mm)ymmy)k0k0y0OW$ss HNXyym2Xk)Gy)yymNP_ymy))*Y)sYslyymm[ x ?lAfmmxJs)%lymy))YNfHyyymmy)G0)0AYYLX8) kkq Qnq* Nm)G/XAB)0Y??HxYyymmYHAAlHY))GkkPH_0)Gyym)y)_yyymyyy)m)mHGyy/NxYH))yymmmm 1B0mm?l[lm )YYm/gmY)YHAkmyGiXYYym)H_HmklH__ssH)QQyQml/l//1xBlH_BBlsHm0B?mmY)0mm0Y[xlxym_l_lmY/0Y)?m0Hlk_qHG))HYHkAP)GYHYYx0m*Pr2mmYm[BmyBzY)xYHkyymHlHl)Ym)yY%HHPHmm0yyl0[00m00y01>#DDx  0Y)QHamxxyHkmymGmyGm0ml= 0xmmP_H0B/)0lmkyymymm)y))mYHH0lBm))YYYYkYm))ymPyyY)YmGGYBl/Nz8Bl8X0l̷_))lGPG)Hl)G))k)yT[xx) A)mN?ymNXPmy)yyyymy0y))_HPy)_kmm)mHYY_l))mY)0lYml_Hyymm)sslBg)mmm1B)y0ym)mx??ymykXx8Nlxy%H*yyGHX/N|/??slYx)xm0mmHHHYHH_H))PGGGkG*yymy_XXHyymym)q_Ymlyy)mmzs%l)mymlz1ssmAgyY?As%B%0)X))lY))mG{NXG%Y))kmy)sHm)GQGQQQ _lBlBY)0-NiX8x%)xlY0)mlsm0lBB[l/P)Y)00sm0yyym)m)y0yyyy))mm)HQ*%mm0m))kH)yxx)B_BHHGQyQY)ymHH00m0)0YlY)HkHgH)00yyml1Y0 00my EW#Dx$0mmmmQa G0 Xll)y)%mm)ykXnlHmmf//-x%x11z x0mll*O_)m0x0Hm)PYYGYHlx)lmmYYHll_HmyY)HHkHyyy)YXg/HN8[8?)sl0Hklk)ymPHGy0mkkmyy`$$0xmxgA)y)yHHml*B)Ymm))ylP)0))_l0Hmm)))YkHyy)Y000mmYly0m ssY0lm BB0Bmy)))))0yPyHPyA/xmYNNlGmGH GGGy_Hy)lX=/A?lxymmYHY)Y)XXAmmYPHkkkklq)GQyy)mNgP_mfA_Ylyx)sxBlyyyyml[Bxss?l/)mmmYABm0Y_AY))lH)ym_/Lg0mYmy_mmmmx)x)0GQyQQQQg?/YmH__?l0NNNHm)mm00%lAm0s0msk)0x0Y[APm0m_llkymyHmm)yPlPymmymyymmG2*aQH0mmmm%mglyy_B)mm_HyyH)mm)myxH)kHP_myyyyB A/xx)xH) sƵxx E0000QGRGaRGG0%s1l%00mx)xGAX?sm%X*BGmml?B sx000B-/%0)mHyyyGyy)kmyk/km?xm)00l_l)llm0)myy0)yy))gl|0lN8/8?8NϷBYYlYAq)))GGyGmmmy)Yxm0)X)mY)yymmnlm0l))YYm)0y)m0)lAlAmY)YmY%H*m)yHmHYy)GykkB_B s B0lg?_x)xs0ymmm0_y0yyyyyysmxx00YBsmm)myxY0NsYy)N5Hf8Pm0BHG %ymmm_lY)k0y)y)A*kPH_y0)Ym0%YYB_Hymmlz xYym0Y[BxBl/Xg8X[l))PYymym%/_m)0BB00y0YY)000yQQQQ=xm)Y/A?H)X8N|fL0ymmm)AHyglsm0kH0m)BAsy)yYm%lBHkmymkkYH_0y))yyyHyyymmyymmyGHqqPQrsy0ym))?f?m0m0ly)yyGGQ_A_H)Bm0)00mBHB*qPY_)yy)kXl _1mxHm0ÿƌD1xx >ÿdxxyGIRaRqBs?J)00xs %s/8_YYB0nyymmBssxxx001kH/XHyyykYykm%mPY?Jm0)mmml0)m))_y)mY8NN8̶?HHkmkn_PymkPyymy_y))Pm$m0mlyym)Y*mkHyYg_HAm)mlgY)Xll/Y)YHP_ymHB|||)mqf|f[Bs0mNg_lsl Y8[m00)0)__08H)ymyyymx)xmBsmym)Ymm)A|YAXkPPXkYYymyAqyy0GHyyyGym)))yY))yyGPkk))0x0mHk)mymBl1Y1s0yyy)) Bs00zllHmm)Ym)myNgl)yy)mlY0mm00Hx)0m)GmmQQmH88|mm)%YXgH|NgHyQ00lHkl)myyY_%mGHGlXmm)_glYlPymYffHl)m))yyH_Hy0ymyyYkXkkq_Yyyy))%A%G_lyy)ymy_qyAgx0B_0mYmy*fkrkAq%)yyyym/H_0HyyyHx#>)m 4E x 0mG%GR*5/Yz˶0m)B%xm?N0xm*y)m0B/z x/8B%lHHyyymHll?%GPHk BJl0xlxY[Ym0000mym)Hm)mm)m_N8||8m0yHHyn|nP0m)mHyGyknqk)HHkHy0YY)ymml_ymyy/g?HH)nX/y0YlX//A_AYY yy_XHy)qBN80mmAXffgXzzs10lXlY0mlY0)Yx)l[8N)yy)Gyzx0x) l B)Yy_*_Y)))0mY8 55f*GkymlH_m/)_yyyy0P)m0m)_HyAAx))YGHPHkm)Y)Ym?YH)mBlll YlABY)xx[Bx_By))kymymmym)A/_)yymHYHB0m/lsYY)QQG)g880xGm%_HBAmmmGGy)HYmyxlY)))Y_)%XggHlll0)ynX_)llyymkHHPk)myyyHlk0yyG%kqyY)myqY)msl0Y|NX?k)Gy)yyy/BYY)8fmYs_H5f\X_HrGyyX_lmmy E">00 41 0 G%akѷ)zB)0mlBxYxYYXBHxyGkysH%zsY0xzsBl_/?xmyylnyl_ys0[XA)Ymlm?00000yYy)Hk)mYmHllgXx)YqlqfA0)))0GPlPyy)ylmP_kP)Yly)kllmy)mnN8H)HXymHm)0m/gXg8?Yx__0__yy_kQmymNXNNHfL8X A[YY/NO_x0m00)mABY|l)GG*Gymm00Yss00yy*ffgm0H|A)mf\mlYy0mYlmyyHYP)mlgY0YAY)XlyB_)sGGn0y0kBNNfNHGm)fNggBBY0)/NgBYB/sY8AmmmY)YlymyPHsm0)))yY0BY0mmmzH%mGQy))0)smx0mmGmnXH%0Y%Gm*m%s)myymm))m)yGkyl)BY))0G))))klPm)))yy))HlYm)ymymHHmmy)m)mH)%xmmxnNHH)%Yx0XNyl)mGyH0m0NAmBg*f55f\q*Pyy_nq*PyyyQyyGyy0>"">00 Eÿû1xGa H_nHy[)ymYsly nkqB x  lly*{YlmyyPlHyf{*)*klB mxm_g_Ymm1B0 %s)m0yml)0Y)0Hn*ykYyH)))0)mYkYyHmymy%*k*HmPlym|NNHy)ym)y)l/_HygYmmmmxY8O)lNg0q*GqkBHBmm-|0N0Hl)sggkyk*Y  ONNglm sO8z))0_fGH_B00m?xmmmBXYmy_llm))lgAx)yyyGkrl)syYY0y0ym?mB_ym)lg[[lsH?Hy0Ymm0*qkmmyyHNNmm_/gfglx0)llzsm0lYyPlG))lymymm)HHmymyyk000000YY00G%myY)xmxm1mxym))mym%)YHk0)xmQk)m%0yyyyym0)))mym))mYPlHY)m00ym)Ykkyy)YHHHmnmyG_)0ymHBkHYxxY)Pfnm)0m00YfgXyYmy|_z%0gslHXq\k*PHqkPPGQy)0 >4E>0x xd4ExG]kaHH*fNNqY_Hxmmm?Ymy\ 2*nXl/l_s1ss))yyyG?mmyPYHH)qfqG?rPslz m)Yx00BY0s[_Yx)YB)0k)myHmyY)mmyPl)0m)))HH?m)ymkHqyn5|*yy))yxmmPHyPnGHY_H)0gg)zgmX5*H{5k*2_HX)m?XmHnHBX*GH _B xz8[AXXXX/0B)Osg8l0)_N*yyBBmmxm/Amyyyymg/lY5XHmyGQG%sx)ym0y/yYlyymgX|AY0l*lg[0xylq*Hyy)mXNX|NyyHg8X/X8[s)l[8N8=zm0yyym))HH))ymymm0smymBH00 > 0%xxmmkm)HBB_1)x mGYkyGxGyH)HyQ0))ymm0)m)yY_HmyyHHPkHmy)mHHPkkk_Ymm)mmmmlm0)YPlBxG)yPqll)msxmm)0mHHmYXHHH000n]G?00YYlHNNq***yPkHHkyyymG00 >EE4U40  q*HlxG)mlxN)0(*P_l_yyGmGy)l0xs_Gy5G00%?1zxPPmB_sG0GYkyyyA0Y)mx0Y)Ymm)YH__Hm)YPHYPHH_Hym5nHkqGy))YHHHBl*Y\gHXkXXg/YYlNL5Nffq**lflyyl/H0|qH_sg_l[g YlY0z[|lBB00 0mq%mmBn0m%BXXYmy)xm0m?m0mmmm)mHg8g/)f?ms))mslBx00mmyY_my)yyyyyy0Xx0BN0qX2n k HlmmXNnHBxsgky*n{ 11 8ҒNgBx0xmmkmy)my0myymx0 [H0y)l*x0s">x 01xx0GH_HYmygABBx0xmYlBHABy0y)Hnnqkqyy00mmy)y00)HHHHkY__*_X)0y)m)mYHP)myyyyAy)0mmy0)YHmYm)QB01mx)GlYmm)0|fX)0y5q{/%0BmmX5˪v*HyHPqHPyy0mm)lY00xZD4E" xy*qHk0xmB)my))YsmgBHyq55ѲnY))myymyYGyBx00BY0YyH5NPm1mxrP1Bz P)mm/HBlB{YmyHXHyP))ym)mmmPHlYHy)))0)))PyyYPk0yyyy5Gyyyymy))mmY)fqQq{*{XgX?%)mXBnN-f85Xqq*lNXymY)mml|nHnqqllzz1_O[T[AA0sl88/lOB1msniX*HG_lBg)mm)xs0mm)HllmyA|mG)))_[?lyB)))yyy_?myyym/X_m|k5* q Ym)%BY8qGGGHssx z8[XgXЭB[s)YHmym))x1x_sXH_ m zDx0mm0mBX_xgl)m0y0llmYmAgnHm)GmlAggnkyyxx)0mmmymG)Ak)yHky)Yk_kllP))ymG)%H̷m)00y)mYAsm0?Bym0yGmm/X%)0HHyymY))lm0)mm)mG0)fNy)00HNˋ*B8YmXNXL5ff]q**kH*kk_0Q0yg_%00zŨ´DDD1xmxmg NnmG))yGG)BHY_OlYBf**q*mym)maGmyHmm0Y_)kBHX0yyl 0PPyyX__yyGPAkyyHqy00)GYHk)kY)mykk)ymyyyyHkPymGyymmyyyyAXmmyy_gA0m)f55NfqHqqq])X8X8sX)mX/m0gH*/?lBz zAgANOg?sYH%حNN=8=H[0)0k|%mGkkLymGmg0y0y)_l000)lYmm)0ssl 0llH0ymY_A000))0y)XXXg/HxHl?\n5N5q**nk8_Hx*/l0A8\ks 1 xl8B/AXYzY0)m)m)mmymm)yy0)O_0z  JŃx0Bl00_H8?y0A))_[XXk%)y?XA_YymYmmA̋_)m)mmYHXXnHqkym)|NPHlHymg|HmYY0))Y_yy)GmkBsl))mYGGyGmN8BHm))mmmmHgmmmxymNkBH)/X*|fNq** PkX_mmyxGm)m01z ø#c= 1s x XN8g[ONqmm)mm kkHkHlmA_smm{q*q*q_y))y0yyGGkGm00YxX0kGBxqnPYHPPPyYymym)myyyQm)HHlHm_ykgAlPyyyym)m)yyQyyymyy)yyyykGym%HYGm)BHYPNf85Nnn*P***qk)XgYlxBYmgԷXkBYzgXAgN|OBYxlA[[|[ gm 8/Yl-?YmknXmABymHnY_m00mmm00xY)m0m 00m_0yyyl0lG00GGGH_Ag%xm0[XlN55NfLqq*ԋNym_Hmy*g0B|nHnzlzls?Ol[NA_lsx0)Yyyyyymym)y sxYx//_Yml xŃ0m00[xky)mYsANNg/kHmx/8O:Xl0?mmylYyy)))H|Nn)mkymkgHkl0mmGgglY?_)m00)[)YHHmGGHmYP)))Gym_8XYHmmxmmmmyyy)_G0ym))Y)ANN-nkGm/NgqPN5Lkq*qHHykgBm00mHkmG_X))yl0 x [y)x :TOT|nmymmk_lH_H0xlBmx0y*qXGHyyy)GQyQP)y0mml)0Blm)00mm%NH)YȷPyyPPPHqkPyyymymmy P2Nf_Y)__yyAyYH*lk_YGmymyYYPkPPyyk)GyyGGyym_q)kyyBl0xmlmG)%HYYkl)HHGf8qHk_XG%[?xmxA00YAgxBslsX8gOXX/_H%_100)xYm0000s|m0ms%G)k qnmm*yG?NlB00000)ss)m0sxx100Y))))ymxH)mGarQ_g00m0)̷H|555fq ]*naX||/X)gmmXH*Xl _g[N|OggXYBYYYYY_H)yy)GPYyy xxx g|N_B[1JJ= 0mA)HY0xx0[s/nH_YlYmY/[Xl_Y)mOAAOggg__YmH/?HYX*)/Nk))yy)HHHymy)m))HHymmm))m))XgX[A/A?lm0m HHYYYHlPHyHm)G))Ymmm00m0mm_Xmm)mmm)HH|NmmmHNlmN*%**llGY/Y0m%yGkq)PGx 0 xxm0m0 WW$f)yrkkklHH0lz00HY)yXHHkkyyyyyQGGk*mm)m)mll_)m)0HkPPHHyyyG)G)yn*55n_Y)H_mkAH))ylkPGmGX_)H_HHnyy*yy)P)yy)yg)ky0H|fB)0ly)y_lHYAN?)BlPG|nPqXy0sB1xzH0?f/gXmx/mN|XlBlsl) ϨxxxxxxB)mOnlB_BYm]yy)y*GyHqYYl/s000Ys0BB0x000/Am sym00YGmY?[m0YYBYyGGarHsxm)HH5\N55kkq2k)/gsxlmkXHmgg_XX_ sBgg[?|NONOBllB_yymPHklPy/Azxxxz xxXB0l B B0000B/[xmx0x[B=8XnnnHlxxA_PAOOO`طm0HYgg?*kqGP_)y%HPHkHP_)HYPHll)y))mH))Hg?lHml_Y_)0mGHrHqlkP)G))))Ymym)yym)y_n0yx0m00B)0g?)Gmy8kHlqllllmG%GGHkPmylY)mQmmyQPyGlmGlPHPk)?ՑTTTfHYmyHq%*lx ضm1 sHBXHfnlHyyQyG*ryay0)x)YlkAmyyyy00xGNmmPnA*GmyyyyGPkmG|NfQQknn )YHYY*_yPmPPm)YPkYmmg||)Hk\yyHBmyHYmm)mH)Y)yyGy)/?)mx)lPyYYmHk)Hlk5_Y)lnHmmY/ssxly_YB? xYzxmg88?lkY%G0 10x[8xYsB[gz00mP*XkyyQ*rGmm)YBx00YBH0m0/0xs x0))000mY)xHBgx0_)mGaGaamsYlAHlmXfN|H*k*2Gy)[?xmx%/?yyO8|xHszYBBgg8XX[_slY)HlmymmGyg0x x//mB/B 00BA_x0xx=8NLmaHX)Ys8lA)̶sgO$``NN0YXl8g8-ыXY)H**qH_ԷYkHkl)y)Ylklk/Y00mH0)GHPrkk HHkkHm)y0kkHHkA_m0mmmm)mnXmm)m00m00Y0)sm)m*NXYHH*kH0k*kkHlPY0Y0y)yayGGkgGmY)HPG*qH%8T`OXNNfk))yHkqHq?)xx1 sYlm%)mqyQGqP* )_B))?mHyY%Yyyyyknk?ymy)%kQyyyya)))Pk))y)PPHPHlqHmmG))))HHnnfGmy0G)H0Yy)my)ykkmy)mls0Glm)yym)YHlGGyyGk))H)kQmy0?[x0_Y)Y)YX 0Y BB?_/qB|8flllY?H001x0xs0 x_[l B00z )0Hff8lGGGkyG%)YHlzA[/[/)000x0zبzBlsY0)_my0/AHm)m0)maaaaGQl/|Y*GiNrqmYsBxx_/k0AXgXxxxmXg8|XlBBlYmm)YHlX)yymyy)xm zBs[8))x0A100NN=1xY0xxxϕN8Y)mGm=80/AmYTOO[0?)X|N8N{l{Xm)mG)P*yy)Yyyymnkkmy)GG) rr kPkPk__GkG)mmm0m))yym)m))x00m0m0m)xY00myG)G m00x_)%B**mmHmyk)my)m)Gaym0*GyQQGg`OO?Xgyymy))yymmG))xzxxHmYyyy*PGrGrG0Bm))mHlGy)0))kP/glymmGqk%))yy0yyGGymmyyyyymG))y0G)mm))YHnXy)00HB0Ylxx0mxY0?lYm)y)k_lHy)m0yy0YYYllPmGykHGH*ymmJx00m_YmAxxs1Bms?_?|/HHllXGm00Bxx000YlB000x0 ssmGyarNB%Hnm))YPl g[_s)%%Y))X100mBG)0l[ mm)))mm0)aGaaaIGG%x0kkPP_)Gl)lnqHy%/lzssx?_y*sB mslxx/XN8_HY)HB?Ymm))Gmyk)mx) z ggmY0x00Bz00xmm zs[/)m[Bx|=8z0[l)Y [ҒYB0lN|f8*0Qmk/kmyn)myym)HPy)yynkGyYyyGGG*kq2r kHyGnNAyGyG))Y))ymmymym)mxm0mmxmmxm0mGyym))00y00H0m)yyymYm0yyyyG%mGQ0y%QGyQk2nO[YH00)m)ymmymG)YxY)mm)mGyGGyyy))?/x00mYyY2q8NHyyy00mmyy*mym)H?GQG_{ly)lmy)PyymmmPy0ymyy))YYYYHHkY_mfq_%mGlY0)l_B0[l/0_m_B))mP/_Hm)yymyyHHHHGqHAN5AYHkHaG)00l0m0mPy)llAx0xsm0B?*BLGH)mlxxzlxx0ml_YlYxmx[s xxP)QkXf_GGl*y00m))ls000mHY0x 000s0x)mmmBm)s0y)GGaaaayx00)mk))myl_)YYGHH)mm?s0?))HBx)BBYBB//8fB_B)))YYB_l_YH)m)yym)0xxBz8||/xmY_H)Y)10xs1x H0z/s00xmx)00msYB0mBsYB_H_mYYy0nXXHx*HH)y0)y)GYGymHkyy)mlnGkHyyyy)ykHkkyy)GyqqSq k k)m)BXmy))Y_m)mm)mymYxm0xmxmx)Yml_ymmymG0)m0ym%00mAGGyyyyYY0mBBG0yym00BkyQv ϶zxsBYmy0)mymHk_Bl 100)Gx)HH)*kklkHGGHGylggN00AnnmG-5? /G00y)yYf/Y)0y%k mmq{XXmmykXkGyy))HPllyyyyyy))YYHY)mHn_lHlHlHNmmB%m_YBxBx0B1%?mmyYYmyym)mmQkPmHHYGqHymm)Bz0HX00s0mYgNff8GH_xkly)Ymlz000?Bl0xx0xx)mmyymHBs0YHymy))m)PHmx8l0GmyyQyHYms0000m00m)y0Y/H0)0)Ymmy)GaaaymHPPkl))GylA)GYyG0xxx0llmmxssxH?%??GX|/kYHY_k0y0%)BYH*GQym)xm1szYxlgm0)l/X/B000011x 1lYl/xxm0x?Bmm s1xz HH _mym$ xgYBHmm00mH0)BYkHYyy))Gkmymy_Ngkkyyy*qHmmyGQkS\Xrkk nH0H?gY)GYYNX))mm))k*ym)xm000m0mYx?gXyslGYxYl))GXHHmy)GYxylxQQsxB)a5{yQQRF҃ [m0myym)kl_?l0ABmmmmm k)gkmHGlBm0gnq52*sl/J_yy0_lY0y0mmGlHg˷y)myH_HkkyyyYYYYl0ymy))lHHHl0lkYkYqYy_N)/y?g8xs0[l00%l0myyyymymmYHlkyyq*XqGG*m00YY0)myGyyxXOH000m0mlHHgkBxs*mlym0 ?lsxlYyy0mYx lxymy))mYsYmmkyym))YPk_m[|my)mQmY[_x0m00x0mmxY)mm)m)ymmGaayGymY)0YHHkyGPlAN/YkklkG)0z00mmkHl0xBsm0sA?lXfx)?B)HYyyy)HlYYYlkk*ym0s0x_PPlx̶?BG)00l/ 0 //lxB_B)myxmm01Aq*GGl//lYHYkP%m)lsmYHYY)yyy))Y%0mHHBHm0ymG)HyHyyyy))_YYHHyy)yy)ynXGmmGyG5  qqN%m0 O yymx%llBmm)yym)ym)m00sz)0)mx)m)g?%yHAsHHkG%_l0G2lG_X_GyBm)yAY0)GG%Hm0XN\2a3^yxxxJOsYqkP)))yyGP)lYYYHHy)8/H)yy)H*f_mmyy nL{8Nn*%G0))yyyyl)0)Y0yyHGQqfl0m)AyYq)ymymmYYlkym)m)ymHYHlm0yHBAB/)BBYYx?m 10BX0ymy)yH?)mHyymyYng*HlyLgXHG*q*inHBm0Y)AGymmm%_?Y)xmHXHm))%z)_)yHAlsm__ym0xx0/[_xmY)yYBs0kYm))lk)Hl_8XGQQyHY[s0xmmmmmmm))y)HY_z)))yyQyyyymmmrN?gmHHGk*k)ymBlsmm%HXm0m)HN|fX)?mYy0mHH))HHnыQ2001/gl[xl//lHl00z?x0x?l00%_B)Y)0mm0)000P%Yzz%xYYHHkG[sxmmmGYlmyym)?x)mmYBYHHm))m))Pymymmy0)Hlmy))yGHqn*rB)Gyyk k{L|xY8lyy)1Yx%lY)xymmyGHym)%lsHz[xxmmm)_*)XlmmYGHH)mH_lAQkyl 0mlmGrY0mmmmq|5*vFFF(mxs101O|lqymYyyyYmY|nm)YYBkY*NN˷my0yNyq*q /8Hl/0GkG_myx00mm*y*m0q)myy)0)lkm)ymy)H_0mym))xm0YY8/0m[1xlx01Y))mHnN0Hy)*NN_GllGGN5fNN_G*qnqN/?)mg|BkH/m)HlHYY_/YYGx0)H_BHY)mBlBs B0)y0m00A|O[lH)m)sxxxHyym)mm)PklQyyyy*BOxxxm0mxm)m)YB?_m0mmmmy0myyyy)yyyy))YHHky*XHGHkmm0Yx0m0mmy0/8B00mmym_YHg˷lHsl0ym)my))0)))YHknXqQ m00xY0[nAk?H%JH)ymBs)00xH0mm?k)GGymyxx*Gy0)mkl2%r?x00l*_ym_zY00kH_l)_Am))H))ym))YHkHll_)m)yy{_%mGmkkNnG*5?BB18 mB?xJ /Bm0mmymyBs)mmm)Yk8g?)mH Hk*5km*ynyllxm0ymm))yra0ym%L5Se^bF3F0x0Ym_0k* GGyyyHmykm)_H0YH0)my)_P5fG */X??mH0yPHm_H0Ym0mrqPGm_B_Hymmmm)x))YYkHkmm)))YYHlm0mmy)))y)?H0%mmmm?08JB1%%mmYH)y%l%0Hkm_lY)fqqkG]q{Ng8mNHYYYmԷmY/YHym0YYlBH)_PyyHY%)y x0[0m)0BY00kymGmmymGHkk) *GQG)0Q)H00Hlsl0xmmm)))Hl[Y0xY)mymmy00yP-%B_H\5\gHa *q*{H_00x/G))y0mm%_?Y)myPPym%)0%yymyyGkrrn]H000s)A5y0 lHH)_YxmlllH%_XG)yyrPkY0x00mYPrrIG%%m0HmyymmxmBklY)glmGYlkmkmyy)G))GHHH_H)yl))m_*XmXfGr]5?/B=As)0x0myy)GGHB򨶨zm0mx)B)k_mymXNg*kHkk*Xmkrmllmm0m_l0)mGarHGm?l055< 7 <55?0mmY0BmyyyyQkGy)HlXBm0mmmy)mm\5Q\\ *-8NN8Bm%HymmPHkX_AB)0H)5qnPaGkAY_*kHHly)HHYYHllYmHBB_)0)))mG_m0?B/̷Ym0x=)))ly)GG00kHyGyy)mQm fkkk*{G8_ON/0H__kHlkmHAlm_Xl)m0)YHHm0)0m0mq)m00x00)llHkyG0ml1x0_G))YGHk{?%mQ0y0mx[ب0)mm))))xX[Ym))%mmmm)Byq|mklmr55f|ˋ*qS5/˷Y)8_lklH*m)H?YnHPyy0mBl%yGP)G))PHqn2\\/)YH8fmm0xBxH*lHHHm%r**nng*Yy0yyGmyaR*q)aIaaraIaG%QaaQyym)mmy{gBm)0Y Bs000mym0)yymm)Y/X0qY)xm101̶HGm0/{Q/X8/lnXAx tjj xmxmm)mm0𶶨sm0mYm0xxxmsBY/nGkH rrn00m?f8Yllxm0xl0BmGG-$s zXqqqnXXXAY)m0m0/yB_0m00y00Y0)rы{X̶1s Okm0A/ymN\55Lq * B88fm0BlYmqYHmmX?s[Pkq GQYnrHAOBAm8fQQQ)lx)0000000ykXYY)Ym0-=̕ϕYm)mx0BY0xHYm0ml 0BB0)BklY000mn5]iL*]r*8ϭ8*kQP*Hy*)Ylz00[01)0xmB/{_lB*k)))Ym xHm1xxm0x0m0yl qn2qq%GQy*yyGyGX_y))*nkk mmmm_H))x*/[0x0mmGYYYlYy0mmmm)QP0mm%_H)H)yy%-{/{)yH*]{Gng[x |gklkGXGHYx_AYY)m)G)ss?*XX] ]]PG?Bx)%5f ymy01BqHkH_G kqH2Hyymy0G l)yaRaIraaGGm0Qyaym)yyGGy%Xkm0z=B/ 0m0)m00mGyyyy_*Y)yrx)x 1 xB?)0)B)mG_XiHm jj@@@x00))A)xB/8s x0YBxYlmxBl%Ni*H r * 80lHB*?Y[xxYmBY?%GHQ$AAkqqngXBls00xky)/%Yy0Y_yG\NNB00000%Ym01/)mmGk5\f\(n* qz[/NN_0)%A8H *lGxzmy*n*ryGxXXrrr/XglHs*_%QQxk00xB?Bsx0xx0)mGl000YHYB?00mmY??[B0lmmszm))ygBx)y5{_**]a5NA)qqyԲ)ksm0m0ml/x00Yg8_yll)y 00s0xx0xmmx0HgS5ky)HymknqXmyGykxm0Hlm)sm)mx%z100mnkq??0gXH0xx0k))mmm))m55Lkll%*2{N|0NmHkyP*kHHGY[B0XHH00m)0B?%mn  ]2Gx%mHXы0m[_NqHkkkkk *qnHm)HmrIak**rrPrIIaR0GGIraQQyQkYyyYGm_x0mmxY8zz|Y)0)mmmm/)/A)mk00 %sYmm)m00?x%y%?_Xm00Jll*nl[BYmx/sm1sB){* HHH k*H_Alx)0gl0 00mx8yGGY0xmy_BYBsxlAs xxymm/AY lYY)00yl_Gy?NNx 000ygmm[)))l{N5\*k*Bg/HYY00Yxl/lmk8/%YkBz?[gmlN*GGa[gXN*kYnnQyy0yQ?)XXXAYsmmGXBBxYxyyYB0xYYx0l/8 zgmmx[smslB)xAf5g8{)H*rQNOl[NNGGkXkmYl ))xlY)0m_*l mxx0xyxxxmz0xxmgNNNf{G*ykX*yH2nXyyymQG)l%x)mmmmx0?qr*HkH5YYm0_Y0lkH_0m0552nq2 Gq8B8NBH0m_B_Bmx/mY0ms[l0_/kG nLqaRv*0xxBxHyyG08/GA55{klkkkk**q5i?lm)y)PraaGPPHrIrRrraaIaG%GayGYYmyy)m00Ol|mym)y0)0mmQyGy%HHHGYAA))0kYxx)l0mm B?Bm%Q)%Y/Ysk{ gnX/Xn/ql_?l_AxH 8?slxNflyQ% r q*m)lAlHsYm0m[sH00lmmym * yHHHmm00gz[_HBl0x[_Aly0Gm?s0 0 00)0?msOBm)/Gk5iH GGyQ0lB0))000m)|/0%q/z gfH)_HqGGk5A?s/mH*2GQyyQyHG?g_lx0yy0Ys0ymHsYxxB?xBx0l_m)xxf_s0mA_5N8k00YkG)/N//ymQyGym)))YB0Yx)XAAzY)sym)Ym0YmxyBxxm0xms*/n5iHqG{yynn̋mmyGmymakXX)%llBkYl000msx00YA*HN)y5nX/x0my%%?_))00X)Yy*\qqaQ5N?Nym2yGk)klY%xxxxl?m0Bglm/8nkXnraaa*qmxxY0%)*SqBYxnX G 2{*kBHkq*fnlm0GrrraIIIaRrIrrraIaGRGaIaQyyQy%myyyy0yy)Gmy0g/gXmmmmm)Gm)yaGymG_mxl/X/ %YBmxz)GGQkgmfN\gg\2nnnn*qgXnAXA)B8ss))mG_g)mmkBYB Hlm)0sg[AYslBmyGGyGkmBlmxmmmx 0m0m0?ϭO=Tg[?00x00) Hmym%1 > mx))?N?BlOAm)Gkk%mQQmB[)xB)xm0mm0m)%gf8sx/l?H)mG%HG8X/g|HH *PqQ)mQQHffX|NYkXyQGH00xx)myy)_mxx1g00zgx0zO?mxml%)X_B%0xA_?sss?x1O/xY0m)GGx0000000mgggn)mGGGkm)0Ylxmys? 0xsx000xx00sN_kmyqyGq**kHy)Ymy)ymNX/AxlHm%B%*q{nXa5l??x/As)YlYmY[g?YB_N58/G) **PyN8?NNG0HXSm)?B0mBY$Yx00%lllk_*r(iSaaaa*k x>>)0YGqq{ y /%YYl%GS5({Xq l H*vq X?HmPrraaRarrrRaIPaMoaIaaaRaaIGQQQ)00yymymmyyXsY0yH)m)mGGGGP HG%mYg ))Yl%m_X_m xxxymG_0mx)Hf\nXnnAklf8fX/g-/xBJHGm_)mm)%H*{*G)00lsm))my0mmxA0mYHmyQym% r*)Y_0xm)x)mxm00BOOOҒN 000)mx0x > > xsx%m_N?xgmm*y0HY)0yyy)l?mms0m0)YYBx0xlXX*Bx0 l_Ym%lHGqNg)GS*y22aQyQyy*q*H)kymm0xx)m)Yl x0xxs00B=s0m[8AGmn_BYm1?ly0zBYY)G%ln?0m 0)GG%00000BglmGmGGG))_m0x00mymzxxm0x/?B0mkGkP2nGGGm%0)0)Gyy|/?B00yx/xkn2*GG *arqN8A)/?xY8-l?0xH_f5f|HmyrHGmN[?g/yyymGmyGmGHY0Y/A[llYY)00m_?Hq*IaaI{l1> myG2q]rnk%GGG 5fL0y%k]qrQBm0maaRIIIRIrIaaIaaraaIaaaaaaaH)G))myAfllNfm)GaRrRGGGHXA0?N8Yx)0_AlBx% 0x%G%rXn00խ/*%ff8Xgg(XHByHqPyYBJ8YBGH0%Bmml/m)m10mxxmm)0)018m000Y00xYyyym q*]q**g/0mmx)xmm00ҒNO )[Y0x00000myGG00 9E>">0xYx)mlN_[g8myH*H)_YYYkHPr*8=_mmmmY/m0?glx/lH_l_lGrGXX_xaar2kP22raQQyaQaGQQyQaam00xyyGQyakH001Bl%mG/z|zmmymB/N8*%G*_0%BzY)mGl?B00xY)0)Yslx00z_mmy{8_qPraaarGQvXN??x00QQQYYxxxl?=xx))GHqqn*q˲mymGm)Y)_kmHf55l%B?m0myy%{kQ\Sqa G aaaQrnqy))0?X?m)8̷B)0mYzg?̜s%xHm?)sg[m%yy))xm000000mH8AYm)yGyrԡrqraIa**1>>))yGni]rG m0GGaRq]XN0mki*vqRG%lY0xarraIRrIaIarIIaaRRaIrGaPaaaaaGakGmHQ[H8Y%mGGaaaaag%mX8H0mm)?_)%m xm))nXHHy%i-8g5NfmQB| 1x0)myyH/xmxHg/l0Yzx0x)ym)ms8mxmxm)HQy%**]*q2?m0)xmxx)mx0BY $x0x0g 00m0mm0m)00 E4E" 1xxm)%8ss8lyGrkHYYm)YkkP_/-NN|/*m0)GB//%l?HB)BB|HB_llkkHrGGa)G%l_xmav(]Qyyyrr a PrrPrPGGaGaIRqYm0 arayYl0xmmG%A?=8zxs8mm%myBNNG0Gx_?Hx)GGY?xYs0m0)HB|xB8BGm*** aGaaaGAg?)0BGGxxmmm?/%xm)mG\nGy)m)H)kGHGmB%0mymyyGGGkq Gy2aaRaarm0/̕n/{_llYx?z/m0Bzx%%G)%/_xx0x)Gy%000xxBgglA%m))GGG) *rarl* GQʪer]5*GGRGr]*]kH*G0Glnqqv Ga %)aRRaRrIaIIIIaaIIIaRIaaIIaIaaaRGG %mQQaB?0yGIaaIIaRRq)GGxl)x0GH%l0000 xx%%RGnl)mlq{-nGmmHYsyymyyyXs)0yQmmH?A%m00?)mmx?szxxxym)m/)xxYxmyym q]qHGl)xmxHmm)m km0Gm0mmYx00/l0xxmm0m0)my xx s0))%X_)0ANkky0mykrrHkX/*)0G)GGB%[gBYYYH)G|XH_lkk*aGBYsyyaRIIIq\ qaQQaRrRRarRaaaRaaIIaaakH)mGGaIaGyH00mGGaGA8xx|BQGymL8nnSaa nnNN/l)GraY?Yx/B?%GmGGG8s [8X%yG*L2r aGaaaaaRaanN_)G* IRRal)mmX/n/0O/Y%mf5L/qaGGyy)m0mGHakB?x0m0Gm aQ*qGaarraaaaRK aQmm)X*%GGB0BxmGzA 00xY)yY?000zmmmyNkrRaRGayQrvrr**%%lGQr\(vor2f*aqvqGy0) qq]*eaaGBmmIRIaRRRIIRRIaIIIRIRaIaIaIIaaaaGGQyG%)QQG GsBlxmmRaaaaIaIaIaG*XfYH)xx%l?000 0 0x%GGrrX8Y))m )*nmy)gs%)0yyyQyyxxmyY[Bxx0m00xB Yz_Yx)))myg0Ym)YGQqqq]k0y)m_[B)%*yym Y00xB1xx0mxm0) Ed x10G%)Hl)x0Y_Y k))yPrr /i/00HGBXHAg88XX_)q*?kkkrkaRr_)mmIPaaaQaaRIaIaIRraaaIIaIaYGaGaam0B?yyGGaGm_O/1zGGGGGQkGmyaG*{N)y0Ga)??s/BB*mGGGn8/8zxn GG%XfLGaRaaaaaqNg_mmyraaaa/qyl%gB=?_0G%G GGmQyaGG)lmmGyyG PaGkn//%0m)yPGrrQyGaIaIaaIaraQQyG)0GNNS)yG)?gY1%0GGY%xzsm00y)_8x0l8H)my*q_*HrIaGaqav*]q yQYve2eoev22\552GarRGaG0yyG rraaaa%HGarRRRaIIIaIaaaaRaaIaaaaaIaayym0QQrRa%%00%xyaaaaIIRIaan5q* Hxxx*-Bx0mxx00%mGIa_BYaPm%z)0mymYH?YmmyQyy%Y0yQm)H0m0y00Ax0Ysmm0)mm)[sYHyQyQQG **Nf*x{HGn QyymlHYmYAYxmx0mm m))0xd 0xmm0Gmm%yyrrHrkq*GPrGmmGffHslG5nnHkkraaG GymQyIIRIGayQQaaaIraRIIIaIaaIaaaIaaaGaGaaRaRaaGGG))8yyaaaaxLB|-aGa)ymGmGIIaraRmnyyyRrRmk/Hl?m)GGGrB/NGaGakGQyGaRR HYIRaG**2q mG%%?JsGyGQymmy0aaaPq*GmymGaaa*nG0y)GaGaGyQyaaaaaaaIoraQQQQyQmyQNnaanX5NB?GaqYx[zz_YGmG)88O=088XG*f2r RaaarqRQv*v*]raR]oeea  raaIaIRGa%yyyyaGaRaaaaaGq aRRrIIRIaIIIraIIaRRIIIIaIIaIaIaaGGmyQQarGB%0GIaIaIaIIIaXmGG k%))%m???x0%zx0mmRRPaYBsY)PrrP))yym)Bm0yyy)%0ymmm_x00m)0/[?smmmG)mymNglxx)mYPyQyyGGGrNNY)B%m%q{rQyyyH0)yyyg?sx mxy00)m §4m x0m%mykH *rr%?%%xkk%/x0krXmHHSraaGG)myIIIryGarMIIrIIIIRIaaaaIaaaIaaaGGGaaaaaamGm0H_GPIaaGsaGaGQGHGaaraaaGG)))GGaRRmGX?0mmGrG)B/xGGGQQyGGIaaaRRrRPP%%m)GPRIRaRG*qG0%x0liHGRymG)m%rraakymGyGaGaGrq0mqQRaaGmGGaaaIaaaIaIroQQQQyG )yGRaqqXxymaras[/B̋)Gn8=[x8GG 5Lraaaavav*]raaaRqoeooeooraQaaIIaIaaaaGQaaIaIIIaaaGaaraIrRIaIRaIaaaRaGaIaaaaaaRGGGmymyyGrRPar_BsmmaaarIRIrraGG2Gm0QQ%l?N10xmRarRa0GYGmRrrGXmyyyHH)yQyyyymQQyQy)mmmmyy)8_0mmyGyQ2HYY*nQQQ))Q5NXmHqqn2Qyy__0Q?smm0m_yBD1 xx)) arGGyyyrr kHkkrrkkxx0xBnGrP XA%1ayr\5NNNq)G{aIaRyaIaar)yy)aRrRIaaaaRraaaaIaaaGaGaaaaaaaaaRGaGGl%m))aaaaG_s)HyaaaaQGY)0GaRaaR%HY)GRGaraGB_Ymrar?/̶H0Gaa%Gm)GaGara%l%%GaaRIaararRGaG)YBmyH*kGaa%)mRaaaGymyGaRaaaGGGyGHGGa%m)mmGaaaaaIaaMQQmyQQ0G)maIaaraarnA)yGIra /k)xGGk%zO[?lGar]rGm0ayQaRraIrorrMaaaaoooMrMIaIaaaIaaIIaIaaGaGIaaaaaRIaaaaaRrRRaIRaaaIaGaIIaIaIaaaaaaaaGG))yRRaPGGB% mQaRaaaaIaIIRaaa*yyGPG?0m%m%rrIarrmy%))myaGIaaaQyyyHXYyymyyyyQQy)YGmQyQyHHmmmyyx_lY)0ymym)xm0mGQyGynxG)l*rQQQQG)yQB/zm0x)H_0x x mxGG*GGPrk HaarHxx)xYk)PaaHrHB%kXfmHf5qrRaaaaIrrrI)rrrrrrRraRPaaaaaaaaaaaaaaaaIaaRGmm__ yyaraIaaYm0GaGaaGGG)YmyRrGG?)0rIaRaQyxs))%PaaG%[[lsyayGGGQmGarRRrRYHByGrrRaRaaaaaraa)%l?lmx)aaayy0raGyQyyQyaaaRrPyyyyG*kaGaGQmm0)amaIaaaaaoGGmQQmG)))GaRarar))mxGGaGa[00GGGaGGGs ymGGGGGmRQQaQaaaQaIaaaIIaIaIRIIIaaRIIIIIaIIIaaaaaraaIIIaaRaaIIIrrrRPrrIaIIPIGRaaPGaRGGm)yyarrPaGaYaaaaaGyGGX[aGGmm)m)yGGQymmQyGmGm%%yGa)nqyyQyyGyGyyyyGGHmm0yyG)xmm)yyyy0mxxyyQyy)GmyyyGm0G*kGQymmGyymsxmPGGmmm00m)yaaa PyyaGrmGGGaPPHGxY1xYGGQarGJz1yyy2kmH)maaaaaaaaGQG)aaGaGGGaGaaaaaaaaaaaaaaaaaaGGY)0NNXGIaaG?B0yaQ))00m0yGaaGa%GzB)0mGRGaaam)BmmGarRIGXBmy0y))yyyaRHa%BsmGraaIrrrrrraH)YlGyarraaHmmIIaQGaaRIaaaaaayQ GGmGmy000xGIaaaaaGaaaa x0yQG%YmaGIRarHYxx%%aImHl_B))rrar?//HGayaGG x)mmGayGaaaaaaaaaIaaIIIaaaIIIaIIIaaIIa}IaaIRaaRaaIaaaIaaIaRaRaaIrrraaGaQQyQQQQayGmymyQQaYmyQaQaaaQQQyGH_PHQm%Y0mGYyQaaMrrPyQyQG yyXPPrrrQQyyGyyyQrG*Hm))yQQHkkHmyykyHx)0ykqq2qPmyXn-00GmG PrrHayQy)Y00)ayGk000GQQykqX22*HHnn5\?Bf5f55\nrPXXJB ykn)m))yQQQQQyQQQQyyGHGmQQQQQQQyyQyyQyQQQaayGlmN|NflyQQklaQyQG)yaaaQllaaaay)?Bm)GRQH/ myQayymmGmQmyQmGmyaaaaaaaIar%YmaQQH maaaaayGQaaaayyyGayyQyQQm00mGGaaaaaaaaaaIr]qH0xG))mIaIRRy_0G%RaraGammsGm%GPraaa%sHmaGGaa00mmaGaaaaaaaaaaIoooeIIII}}III,ewww_q^^vkk^KwoIaIoaaaaaaaaaaaIaaaQGGyrraIraIMoMIoooIaaax)Ira,eeeoeaaPR rYBn RaaaaRrrrraQIeIeoQQQop GyQIooQqmmayaw,oeeowGreem)aa eeaavp^verGQeee~CFCQpppIIwC~CCC]2^oMp(C^pFC//뷋?nnAn2PqkHYyQ]ovrRrGaKvK** qvRaIaaaQQQQIrMoaaQQQQaaaaaIaa000ygYn˕NyyG%B%pKaaRoMrIaaQQQIrMvaaaQaaaaraaevp^p^~wQyyyyQyIRIMIrrQQQQaIIaaaaaaaaIIIaaaaeeMaaaowveeaaarerRraQQQv22{q* QQQQaRQyH)yQGGGyyGGaGaBB)yImGm)Bx)GRRG){lkyyQmmyQyaaaaaaaaaaaaaaaCCCCCCCC(~(C(C(~(~(C(~CCCCCCCCC~C~CC(CC.~~Cqppkrekk]~C(C(~CC(CC(CCC222v]v]]]22HyQaP v222^2(((CCC(((((]raM^C(FC2qHmmxQ^2C(~(~FCCFFFCCC2S(?nS22*2^^^2*rQ2((CC(Cae(((CCC~(p(aQ2F((C(nrG2^^CC^.n r(iFF(lGl]{]qGev^^2FC(F(F^(( rnC^CCo(^^^C(C(~C(CC~CC(2]ovvvCFC~^BA{*qAq*_lky^^C2^n]2(C]v*qq*v*v22v2]2^2^2^2^2^22]22222^2v]vvvvvv^^^2^R)YYXYXNy)GmGG%%xwS^2222^22v^2^^^(^^2^^2]22vv]v^2S]]]^CCCCC(^oPrHaamyyQyyyPv2^^p^^^2v22vvv2^^^^^^^^^^^^^^^^^^^^^^CC^^^C^^^^^^vv]^^2^^^]vv]]2^^^2{Sq{**qrGPPrmyyyyGaBlyQaQyGQ0BmGaQyQ̶%yyQmy))GGaGaaaaaPrRaaaaaIaIa~~~~~C~C~~~~CC~C~~C~~C~C~~CCC~~CC~CCFC(~~Cq*v(n{{?HC~.CC~~CCC~~~~~C~CC~.~~.~....~....~CCC~C~C.~~...C~C~~~~~~~~~C~~~~~~~~CCC~C(C(.~~~~CvRyG^(C(~C~~~~~C~CF~C(~eya22qqq2H0x x 0I.~.~~.....^C~~~~....~(pIe~C..~~(C^IaQQ(FC~~~(C(/JJ/ --.~~CCFC.(~~C~~~.....~~C~C~C(C~CCC(CC~CF~CCC~~~~C~~CC~~~.~.~wC~CC~(CCSi(SiSq?HS((CC~.~......~~~~~~~~CC.~~.~~~..........~.......~.......~~~..CCCCCCCC~~CC~~~~  "9>D>Bsxxx xx w.~~CC~~CC~~CCCCCC~CC~CCCCCCC.C~~~CC.C.p~~CCCCCCC.C~.....^~vp^^^(C~CC((~C^FCCCCCCCCCCCC.~~~CC.CC~.C.CC~CCCC~~~~~~CC.CCC.C~CCCCCCCCCCCCCCCCCCCCCCCCCCC.CCCC~~...C.CCC~~C~C.~~.~~.C.CC~poowvIaorrIaQQQQIRP%IraaQQaHkGyQGHyyyQQQGaarrRIIIIee~~~~~~~~~C~~~~~~~~~C~~~~C~C~C~~~~~~^ppwC~CCpqq^CGGxmmm.~CCCCCCCCCCCCCC~C...~~........CCCCCC~C.~...~~~~.~~~C~~C~~C~C~~~C~~C~~~CCCCCCC~C~C^~(^ry^CC(C~C~~~C~~~~C~C(r2nvq2q2q0000 0F~......~~~...~.~~CC.C.~~~C(^~..~~RCCC.~.CFC?vpCCC~~CCC(~C.~~~......CC(CC~~~C~~CCC~~~~~~~~~~C~C~~~~~..~~CCCCoGRr **q*_ RMRIICC...~~~~~~C~~~~~~~.C~~~~~~.............~~..~..~.~.CCCCCCC~~~~~~.~G>>>>x xxxxxxw.3C~C~~C..C.C..C.C.C.C.~~~~~CC.CC.CC..C~~CCCCCCC.........FCCCCCCCCCCCC^CC.w.CCCCCCCCCCCCCC.C~~C.CCC.C.~~~.~~~~C.C~~C~~~~~~~~CCCCCCCCCCCCCCCCC...C.C.CC.C.CCC...~~C~CCCC.~~~..C.C.~~CCC~CCCC(^]q]v]]2^^22vvSn2q^]K^*Hr*GRrev]vqkPk222S{{]*]22222^^^^^^^^C^CC^C^^CCC..~......~.~.~~~~..~~.~...CCCCoIo^q20 >x}(..~~.C.~....~.~~........~.....~.....................~~.~~~~....C^CCCC~~...~..~~~~~Coy222vSq/>>> > (........~.........~....~.~~pCC..C(D@@@§E9"E""—JSii(~F~~CC.....7......~.~.~~.~.~.~.~~~....~.~..............CCCCC~x11> >x1 %%C~~~~C~C~~...........................~..~.~.~....C.....~.......dd"1>> ~~~...............................p..........~~.~~C^o]]wvvvvvv*qqra...~.....~~....................................~.~.~C.C.~C~CC.C......................~.......~..~.C.~.C.C..~.~CCCCCCCC~CC~C.CCC~~C(Cp ) > 0 x HCC...CCCC~C~~C~C~CCCCCCC~C~CC~~CCCC.~~~~~....~~~~.~~.~~......~~~~wIIae2^^22]]%x > x I(..~~...~.~~~.~~~~......~.~.~..C.~.~~......~.~~~~~..~~~~~.......~~~C(.~C...~.~C~v2222{q{ >> (.~~~~.......~.~C~.......~(~~..~.CC@@—j@@@D"""%%]CC~C.......~~~~~.~...~.~~~.~~.~....~~...~C~~~(p1s1111"11"11111>1G((~C~~CCC~C~~.~.......~~~~~..~~~~~~~~.C.~.~.~...............?%"EdEdE>껻>w~.............~.........................~.........~~~~~~CIoooororrr*aQ....C......~~~.~......~.....~....~........~....~~~~~~~.CC~~C~CC......................~~.~~.......C.~.~~~~.C~~C~Cp~C^CCCCCC~.~~C.~C(..~.CC^m > > xx x > GrCF....CCCCCC.C.C~CCCCCCCCCCC~~CC.C~~~~..~~~.~....~.~..~~~~~.~.~~.CCCwIIaS2S2S222x o(...~.~~....~~~~C~C~~CC~~~C~CCCC~~~~~~C~~~~~~..~~~~~CC~FFC~F~CC.................~~~Cnnn22{A%> > >Ii~~C~~CFCCC~~CC~~CC~~~~.~CCC~~(C........›@4@@j@E4E9Λ/~~~.~C.C...~...........~......~~~~~~CCC~~.~CC~.311s111111"111"11"xHCC.~~~~~~~~~~~~~~~C~C~CCCʾC~C~~C~CCCCCCC~CCCCC~CCCCCCC~C~~~~C.C.C.~.~Ļdd">"p(~~CC~~~~~~C..C.C.~~~~~~~~.~~.~~~~~C~~~~~..~..C.C~CC~C~C~~pMrooKwKooMroK]ao~~~~~CC~~C~~~~~~~C~~~C..~C.C~~~~C.~~~C~~C.C~~~~~...~.~.~...~.~~..~~~~~~~C~..C.CCCCCC~~C~~CCCCCC~CFCC~C~CCCCCCC.....~.C..C........~C...~C^C)xx 0 x xxx 0 0 > >>%CC.......~..........~....C..C.C..~......~..~....~..~.......~~..~...~~~~CMIIaa]2222n2* >> >xK(..~.....~.~..~~~C~~~~C~~~~~C~C~CCC~~~~~~~C~~~~~~~~.~~~~~~~~~~~~..~..........~..~^;nnq2{S > > C~~~~~~~~~~~~~~.~~~C~CC~~~CC..~~~C.....~—jD@@j@4Bev~~~~~.~~C...~.......~..~~~~~~~~~~~CC~~..~F111"1"11"1111111(.~C.~~~C~~~~~~~~~~~~~~C~C~CC~~~CCCCCC~CCCCCCCCCCCC~~~~C~~~.C.~.~.~{%dC~CC.~~~~.~~~~~C.~~C.~~~~C~~C~~~~~~~CCC~.~....~.C~~CCC~C~~C~^IaoMrwoooooRI2(2KrKC.~C.~.C.C.~~~C~~~~~~.~~~~~~~~~~~~~~~~~~~~~~~~C..~~.....~~~.~.C.~...~~~~~~.CC.~CCCCCCC~~~CCCCCCCC~CCCCCCCCC~CCC...~.C..CC..........C~....~CC^H0xx x xxx x xxx>> %~..~.............~.C.C.~~~~..C..C..~..~~.~...~~~.~.~..~~~~~.~.~C~oIa{22n22S*xxxxC~......~~~~~~~...~~..~...~..~~.~..C~C~CC~C~~~C~C~C~~~~~~~~~~~~~~~~~~~~F~~~.~..~.~~~~.߱PnS2/G > >aC~~~...~~~~~~~~~~~~C~~~~~~~~~~~CC...~~~~~~~~@DD@@@ç4C~CCCC~~~~~~~~~~~~.~.~..~...~.~~~~~~~~~~~~~~.C~~~%s1 11s1%1s1%11111*......~.~..~.~....~~.~.~~~~~~~~.~.~.~............~CCC~CC~C~C~C.C~%""""^~~CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.CC.CCCCCCC~....~.pwIoeeooore^vaaICCC~CCCCCCCCCCCC~CCCCC~CCC~C~C~C~CC~CC~C~C~CCC~C~~.C.~.~.C.C~C..CCCCCCCCCCCCCCCCC.C~C.....~..C.C~.~~..~~..C.C........C.C..C.........C~....~~CC x x x x xx m) G%~C~.CCSCC~........~~~~~~~.C.~.~...C..C.~.~~~~~~.~.~.~..~~.~..~....~.~.CCoaIGR2Sn2n2S >xpC~C~...~.~..~....~~~~~~..~~..~~.~.~~.~...~~CCC~C~C~~~~~~~~~~~~~~~~~~~~~~~~.~~~~.~~~~~~~.~߱nnn{) ~~~~~~~~.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~—@DDD@@@@j@@4EE~C~~~~~C~~~~C~~~.~.~~~....~.....~~~~~~~~~~~~~~.~~C~%s111111%1111x11]~~~.~........~.~.~~.~~~~~~~~~~~~~~................CC~~~C~C~C~C~~C~{%">Ꝼ^C..CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.C.CCCCCC~.....pewIweorIaaCCCCCCCCCCCCCCCCC~C~C~C~C~C~CC~C~C~~C~C~C~C~~~~C~.~.~.C...~~~C.CCC~CC~CCCCCCCCCCCC.~.C......~.C~~C.~.C~~.~.....~.~..~..C............~~..C~C~C^1xx x x x )m > CC..CCC^~..C..C...~.~~~~~.~..~.C......~.~~~~~~~~~~~~~~.~~.~~~~~~~~~~~~~~CoIIar22n2{ xxxxxpC~~~~C~~~.C.C.C.C~~.~.~...~~~.~....~~~~.~.~~.~.~.~.~.~.~~.~~.~~..~~~~~~~~~~~~~.~.~~~~~~~~~~ߘnn2{ >> > a(...~~~..~.~~.~.....~.~~~~~~~~~~C~~~~j@DD񧧞@@@@@@@4E"%S.~~~~.....~~~~~.~~~~~~~~~~.~~.~~~~~~~~.......~~~CC~~(~""111"111"1111]C~.C~CCC(C~...........~..~..~..~.....................~..~.......~%"껻1C~....C..C.C.~~..C.C.~..C....C..C.C..C.C.C..C..C.~.C~~C~~~.~~^eeorear r]\\RRQM.~...........~~.........................~.~.~.~~C.C~.CC.C.C~.C...C.~.~C..C.C.CC..C......~.~.~.~.~.~..~~..~....~~C~~~~~C~~C.CC..~C.CC..CCCCCp9x x x x x x> > GC~....C~C..C.C.CC~CCCCC~~.~C..~~~~.~~~.~~~~~~~~~~~~~~~~~~~~~~~.~.~~CIaa 222Sl xxxGxpC~CC~~C~~C~~C.CC.C~~~~~~.~.~.~...~~~~~~~~.~.~.~~..~.~....~...~..~~~~~~~~~~~~~.~~.~~~~~~~~~~~~.ߘ̡G> (~~~~~~~~~.~~.~..~~..~.~~~~~~~~~~~~~§DD@@EEEE"Gi~~~~~~~.~~.~..~~~~.~~~~~~~.~~~~~~~~~~~...~~~..~~C~C~~~C(1"""1"1111 {~C.~~(C(C~~~...~~...~~~~~~~~~~~~.~.................~...~.~.....~.~9p~3..~.~C.~.~~~.C..~~~~~.~C.C.~C.~.~.C........~.~C~C~CC~~~~~~Ceo^\Q q\^rRrRQ w..~~...~.~.~.................................~C.CC.CC.CCC.CCC.~~~.~~~.~~~~C.C..C.......~....~~~...~.~~......~~~~C.C.C.C.~C..C.~C~~..CC~CC^x xx x x x x >>> %q~C....~~~C~CCC~C~C~C~~CC..~~.~~~~..~~.~~~~~~.~~~~~~~~~~.~.~~~.~~~.~~~.~~poIIIa 22nS2/ x xxC.C~.C.~~~C.C.C.C.~~C~~~~~~~C~~~~~~~C~~~~~~~C~~~~~~~.~.~.~~...~.......~.~~~~~~~~~~~~~~~~~~~~~~~~~~~~.~..~e;Pn̡2G> >> a(~~~~~~~~~~~....~~~~...~.~~~..~~~~.~~@@4DE" S~~~..~.~.~~~.~~~~~~~.~~.~~~~~~.~~..~..~...~C~~{?%%%%%%%%%%% K~~.~~C~C~~~~~~C~C~~~~~~~~~~~~~~~~~~~~~C~~~C~~~C.~~~~C~C.C........~~...~.%껝1x1......~~.~~......~...~....................~......CCCC~~C~e\]QIK^]rIMRaaC~C~........~.................................~~C~.~C~.~..C..~...~..~........C~~~C~CC~CC~C.~~~CCC.C~C~~~.CC.C..C.C.C..C~C..C..C~CC.~CC~.~~9> xx x R{~~~.C.~.~~~~.~~~~~C~~C~~~C.~.C..~~~C.C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.~~poIRan22n2n x %xC.C~C~C~~C.CCC.C.CC~~~~C~C~C~~C~C.C~~~~~~~~~~~~C~~~~.....~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.~~~~ߘi)> > >a(~~~~~~~~~~~~~~~~~~~~.~~~~~~~~~~~~~~~~~F@@4EEEEDD"ûS~.~~~~~~~~~~~~~~~~~~~.~~~~~~~~~~~~~~~~.~....~~(i-?????????J????{?]~C.~~CC~C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C~~~~C~~~~~~~~.C..C................{%>껝껻껻1.~..C.....~..........................................CCCC~.C~Con\2^MMKraeraaIrqw.C~~.........................................~C~.CC.~.~.C..C...................~~CCCCCC~C~CC~CCC.CCC~CCCCCC.C.CC.C.C.C..C.CC...~C~C.~CC~..~9> x>x x x Rq~C~.C....C..C.C~C~~~~~~~..C..C.CC.C~~~~~..~.~~~~.~~~.~.~.~~~..~~..~pRan222/%xꝝ>xx.~~~~.~.~~~.~..C..~~.~~.~.~.~.~~.C.~~~~~~~~~.~.~.~~.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.......~~~~.~.~~C~;inS > > (~~~.~~...~~~~~~~~~CC~~~~CFCFC~~~~~~~~~~...D4@×EDDE4EĐp~~~~~~~~~~~~~~..~~~~~.~~~~..~~..~~~~CC~~~~~~~~C..CC~F Xnnnnnnnnnn2n^F..~~~...~.~.~~.~.~.~.~~~.~.~.~.~.~..~~..C.~~~~.C.CCC.CCC~~CCC~C~CCCC{ sxx19CC.CCCC~C~C.~C.CC.C.C.C.C.C.C.C.C.C.CC....CCCCCCCC.C.C.....pwwoe((KR^IIIoIIIIveCCCCCCC~C~CCCCCCCCCCCCCCCCCCCCC.CCC~C~CCCCC~CC~..C...C......C.~.C~~C.C~~~~C.CC.....C.C.CC.C...~..C...C....C..C.C.C...C.C...C.C..~C~~..CC....9xxxxxx xx x 0 mmR2~~.....C.C.C.C..~.~.~.C.C..C....C..C.~~.~...~~..~..~.~.~~...~.CpII(22n% x >>% ~~~~~~~~~.~..C..C.~...~..~.........~~~~~~~.~.~...~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.~.~~.~~~~~~~~~~~~~߱\X{) G(~~~.~~~~~~~~~~~~~~~~~~~~~~~~~~C~~~~~~~...~~D4DD@›D4@DE~~~~~~~~~~~~...~~.~.....~~~~~~~~~~~~~~~~~~~C.C~\ Xnn2nnn22222^(~.~.~.......~..~~.~.~~.~~~~...~........~~.C.~~~~~.~....CC~CCCC~CCCCCCCCS*11>>>>xx1111C~C~CCCC.C~CC.CC.C~CC.CC~C.CC.CCC.CCC.....C~CCCCCCC........wKoKoo}o2IIIMIaIrw^~CCCC~CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~CC~CCCC..C..C..C.......~C.C~CCC.C~C.C.C......CC.C~~.....C...C...C.C.~~~.C..C.....C.C.C....~~C..CC...J91> 0 0 0 0 xxR2~~~C......CC..C.C.~.......C..C.C..C.C.~~~.~..~~~~~~~~~~~.~~~~~~~~~~~~.pMMIvnn2% x%C~~~~~~~..C.~~.~.~.~.C..C.~~.C.C.~.C.~.~..~~~.~~..~~.~~~~~.~.~~~..~~~~..~.~.~.~~~~~..~~.~~.~.~ߘinn{) > ~~~~.~~~.~.~~~~~~..~.~~~~~~.~..~...~.~~@4E8-iLh@DDD@"ė^F~~~~.~.~~~~.~.~~.~~~.~~.~~~.~~.~~.~.~~~..~.~.~..~~.~~~~.~~XLnn*BB2n222^~~..~~C~~..~..~.~~~.~..~~~~~~~~~.~~~~~~~.~~.~~~~~~~~C.C.~~.C.~C.~~~~~~~C]*]?q?*kq*qq*********CC~.CC..C..~.~.~.~.C.~~.~.C..~.~.~~~.~.C.C.~.~.C.~.C~.C.~~~~~~CwoIIM]aoRaaIe^C...C~~C~C......C.~~..~.~.~.C.C.~C~~C.~~C.~~~C.~C..C.~C.C.C.C..~....C.C.C.C..C.C.CC..~.C.C.C~~.CC.CC.C..C.C.C.C.~~C.~~~~~~~~CC....~~~...CC({q* H r H kk^CC~..C.C~C...C.~.C.C.C.C.C.C.~..C~.~.C.~~~~~.~~~~~~.~.~~~~.~.~.~~~~~~~.~pRRRvn2% >G~~~~~~~.~C.C.~~~C.C.C.~~.~.~.~.~~.~~~..~~~~.~~.~~~~~.~.~~~.~~~...~~~..~~..~~.~.~~~~~~.~~~.~~~~.~;; XLn2G> Gi~.~~~~~.~~.~~~...~.~~~~...~~~~~.~~.~.~@çE"|-LfhDDEEΝC.~~~~.~~~.~.~~~.~~~..~~~~~.~..~.~~~~~.~.~.~~~.~~~~~~~~~g\((1G2222nn^CC~.~.~~C~.~...~.~~~~~.~~C.~~.~~~.~~~~~~.~.~~~~~~~~~~~~.~.~~C.C~.C.~C.C.C.~^q2{nqn{n{22{{vqCC~~CC.C.~C.C.C.C.~.~.~~~~~~~C.C.~.~.C..C..~C.C..C.~.~~~~.~.~~.pweooI,]oIaIopC~~....CC.C..C.C.C.C.~~C.C.C.~.C.C.~C.~C.~C.C.~C.C.C.C.~C..C.~C.C.C.C..C..C..C~C.CC.C.C~C.C.C.C.C.C.~.C.C.C.C.C.C.C.C~C.C.C.CCC...~CCC..CC\Lnnqqq2{qq2{22q22^~C~.C..C.~C.C.C~C.C.~C.C..~.C.C.~..C.~.~~~..~~~~~~~~~~~.~~~~~~~~~~~~..~pMMr]nn2/%xxx~C~~~~.C.~...C..~.~.~.~.~~~~~~.~.~~~~~~~.~.~~.~~~~~~~~.~..~~.~~~~~~~~.~.~~~.~~~~~~~..~~~~~~~~~~ߘinnA) > G~.~~....~..~.~.~~~~~~.~~~.~~.~~~~...~.@@D4E4hXf9@D~~.~~~~~.~..~~.~.~.~..~~~.~~.~~~~~~.~.~~~~~.~~..~.~~~~~.~iB11{n22^(~~~~.~C~~..~.~.~.~~~~.~.C.~~.~~~.~~~~~~~~.~~~~~~~~~..C.C.C.C.~~C.C.C.C.CC^^2222SrPk2{2q22~C..~C..C..~.~.~.C.C.C~~~~~~.~..C~C.C..C..C..~..C.~.C.~.~~~~~~CpwooeopMMvIaaapC~...C.CC.C.C.C...C..C..~.~.~C.C~.C.~C.C.C.C.C.C.C.C.C.C~~C.C.~~.~...C...C..~C.~~~~~~~~.~C..C~C.C.C~~C.C.C.C.C.C.~~C.~.C.C.C.CC....~C~.C.CCV\LXS22222222q2]2]^~CC..C.C.C.C.C.~~~C.C.C.C.C..C.C.~C..C.~.~~~~.~~~~~~.~.~~~.~.~~~~~~~~~pMr](n%xx%C~~~~~~~..C~C.~C.~~~~~~~~~~~.~~~~~~~~.~~..~~.~~.~~~.~~~.~~~.~.~~~~.~~~.~.~..~~.~~~~~.~...~~.~~~~..;\XXn) > i~~~~~~.~~~.~~~~~~~..~.~.~.~~~~~.~~~~~ç44@Z\fח@EEE~~..~~~.~.~~~~.~.~~..~~..~~~~~.~.~.~~~.~.~..~~.~~.~~~~~~\n{s%1x%_n22n^~~..~~~CC~....~.~~~~~~~.~.~.~.~.~.~.~.~.~~~~~.~~~~~.~C..~.~C.C.C.C.C.C.C..C^222{2kPG22qq{22CC..~C..C.C.C.C.~.~.~.~~.~~.C.~C~...C.C..C~C.C.C.C.C.~~~.~.~~~C.pwoo,oooIa(\]^MaC.....C~~CC.C..C.C.~.C.C.C.C.C.C.~C.C.C.C.C.C.C.C.C.C.C.~C.~C.~.C.C.C.~.C..C.~~~~~~~~C.~C.~C.~~.C.~~~~C.C.C.C.C.C.C.~CC.C..C.CC....~C~C..CCLinn2{2{22qq]q]qq2^CC.CC.C.C.C.C.~C.C.~.C.C.~..C..~~C..C.C.~~~.~~~~~~~~~.~~~~.~~.C.~~.~~~~.poMMMr2(n >xx~~.~.~.~C...C..~C.~~~~~~~~~~~.~~~~~~.~~~~.~..~.~.~.~.~~~.~~~..~.~.~.~.~~~~.~..~..~~...~.ߘ\XnG> G.~~......~~~~~~..~.~..~~~.~..~~~.DD§f\\5Z×9~~~~~..~~.~..~.~..~..~~~~~..~~~~~~~~~~~~~~.~.~~.~.~~~~.~~~\"11Ji/{2n2CC~~~~~~~~.~.~.~~~~~~~~.~~~~~~~~~~~~~~~~.~~~~~~~~~C..C.~C.~~C.~C.C.C.~C~(^222v kkym{22{222C..~C..C.~.~.~.C.C.C.C~C..C.C....C.C..C....~~.~..~..C..~~~~~~~~Cwooo,ee\KvraawC......CCC...C..~.C.~.~.~.~..~C.~C.C.C.C.C.C.C.C..C.C.C.C.~C..C.C.~~.~.C..C.~C.C.~C~~~~C~.C.C~C~C~~~~C.C.C.C.C.C.C.~C...C.C.CC.....CC....CC\(222S2]22q222]2CC....C.C.C.C.C.C.~CC.C..C.C..C.~..C..C.~~~~.~.~~.~..C.~.~~~.~..~~~~.~..~poMMr2(/G%C~~~~~C.~.CC..C.~.~~~~~~~~~~~~~~~~~~~.~..~.~.~.~~.~~.~~.~~~~.~.~~.~~~~.~~~.~.~~.~~~~~~~..~~..~~.~pߘ\\n{m > i~~.~~~~.~..~~~.~.~~.~~~~..~..~..@@D×D=f\\D@4EEx{~~~~~~~..~~~..~.~.~~~~~~.~~.~.~.~~~~.~..~.~~~..~.~.~.~~~~~\B"zJ*{2n2^~~.~~~~~~~.~.~..~~.~~~~~~~~~.~~~~~.~.~.~~~~~~~~~~.~..C.C.~C.C.~C.~~~~~C.~C^2222rP*))*2{222......C..~C.C.C.~.~.~....C...C.C.C...C.C.~C..C.C.C.C..C~~.~.~~CCpwoeoMeMvf(IMaeCC....C.C.C.C..C.~~~~C.C.C.C~C.~C.C.C.C~~~~~C.~C~C.C.C.C.C.~C.C...C.~C.~.C.~C.C.C~~.C~~~.~C..~~~.~C~~~.C.C.C.C.C.C~C.C.C.C.C.CC....~C~C..C.\V(S2222222222q]vCCCC.Cp.C.C.~C~C.C.C.~.C.C.~..~.C..C..C.~..~.~.~~~~~~~~C.~.~~~.~..C..~.~...~pMMM ^\((/BC~.~~.~.~.~...C.~~~~~~.~~.~~~.~.~~~.~~~~~.~..~~...~.~~.~~~~~~~..~.~~~....~~.~~~.~~.~~~~~~.߳\n)>> R..~~~~~~~...~~~~~..~~.~~~~~~~..~~~@DDD=\\\\JD99xi.~~~~~~~~~..~.~.~.~~.~.~~.~~~.~~~~...~..~~..~~.~.~~~.~~\"11{S2C~~.~~~~~~.~~~~~~~~~~~~~~~~~~~~.C.~~~~~~.~~~~~~~C.C..~.~C.~C.~~C.C.C.C.^22n22v YmaGnn222~C..~C..~C..~.~.~.C.C.~C.C..C.C...C..C...C..~C.~.~~..C.~.~~~~.C.CCpwwooe^aQR RwC......CC~C.C.C.C..~.~.~..~..~~C.~.C.C.C.C.C~~C.~C.C.C..C.C.~.~.~C..C..C.~.C.~C~C.C~C.~C~C.~C.C~C~~.C.C..C.C.C.C.~.C.C.C.C.C.CC....~C~C..CC(n22222222p.C..C.C.C..C.~.C.~~C.C.C.C.C.~C..C..C..C~~~~~.~~~~.~.~C.~.~C.C.C~C.~C..Cpoor2\\(( 1%C...~.C.~C~~.C..C.~.~~~~~~.~~~~.~~.~~~..~.~~~.~.~.~~~.~~.~~~~~~~~~~~.~~~..~.~.~.~..~...~~~.~p߳\\g /G > i.~~~~~~~...~~~~~...~~~~.~~~~.~~~~~@J i\\\\ Z"Gip.~~~..~~..~.~.~.~.~..~..~~.~~~~~~.~~~~~~..~.~.~~~~~~ -9"1111%%q22^C~~~~~~~~~~~.~~~~~~~~~.~.~~~~.~..C.~~~.~~~~~~.~~~....C.C.C.~C.C.C.C.C.C.CCC222raaky)xG22{22~...~~~C.~.~C.C.C..~.~.~~~.C...C.C..C.C.C.~C...C.C..C..~~~.~.~~C.CCwo,ooooKanQ Ie^.....~~~~C~~..C..C.C.~C.C.C.C.~C.C.C..C.C.C.~~~~~~~~C.C~C.C~C.~C..C..C~.C...C~.~C.C.~~.~~.C.~~~.C.C.C.~C.C.~C.C.C~C.C.CC.C.CCC....C~~~..CC\\\(nn2n222p~CC..C.C.CC~C.C.C.C.C.C...~~.C..C.C...C.~.~~~.~~.~..C.C.~.~C.~.~~...C..~~~oMoMoS\\1%CC..~C..C...C.C.~~~C.~~~~~~~.~..~~.~~~~.~~.~.~~~~~.~~.~~~~~~...~~.~~~.~.~.~..~.~.~~~~.~.~~..~C߹\\> i.~~~.~~.~~~~~~.~~~~~~~~~..~~~C@ 8\\=z9"i..~~~~..~.~~~~~.~.~~~.~~.~~~~.~~.~..~~~.~~~...~~.~~~~.~~~2A/"E11%m qn2^(~~.~~~~~.~~~~~~~.~~~~~~~~~~~C.C.~.C.C.~~~~~~~.~C.~C.~~~~~C.~~C.~C.C..C.(2nn2rqH))GHn2222C~~.CC.~.C.C..~.~~C.C.C~.~~~~~C..~.C.~.~.C..C.C..C.C.C~~~.~~~~.~CCCCwwwooIiiym{%%r.C....C.C.~.C.~.C.~.~.~~~.~~~C~~C..C.C.~C.C.C~~C.C.C.C.~~.C..C..~~~.C...C.C..C~C.C~C.C.C.C.C~C.C..C~~~C..C.C~.C.~~~.C.C..C.CCC....C~C~..CCV\\Ln2n2222p^~C.C..C.C.~~.C.C~~~C.~C~C.C.C..C.~.C.C.~.~~~~~~.~~.C..~~~C.~.C.C.~.C..C.~~poMM2\(̋1%C...~..C..~C...C.~~.~~~~~~~~~~~~~~~.~~.~.~~.~~.~~.~~~.~..~.~~~.~~~~~~~.~.~.~.~~.~~~..~.~~..~.߹\\G>> G~.~~~~.~.~~..~~~~~~~~.~.~~~C~›8f8\\\-=9"Gi.~~~.~..~~~~.~~.~...~.~~~~~~~.~.~~~~..~...~~~.~.~~~~~~~~\\ԛE"11122^C~~~.~~~~~~..~.~~~~~~~~~~~.~~~.~.~.C..~~.~~~~~~C..C..~.~~~~~~C.C.C~.C.C~~((n2qr H?_m(n{S22~C..CC~~~~..~C.~C..~~~..C.~..~.~C.~.C.~C..~C....C..~..~~~~~~.~.C~CCpwwowwMooM qGG p.~....~~~C.~.C.~.C.C.~C.~~C.~~.C.CC.C.C.~.C.C.C.~~C.~~C.~C.C..~C.~~~C..C...C..C.~~.~C.C.C.C.~~C.C.C~~~~.C.~~C.C.C~C.C.C.C.C.CC..C~~~C.CC\\\nn(n]^(.C...C.C.C.C.C..C.C~.C.~.~.~..C.~~~~.~.C~~~~~~~~~.~~~C.~~~~.C..C.C~~~C.~.CpwMo ^\\\\1"%%^~~.~.C.C.C..C.C.~~~.~~.~~.~...~.~~~~.~.~.~~~~~~~~~~.~~~~.~.~~.~~.~~~~..~.~.~~.~~~.~..~~~߹\\gѺ/%>> > (~~~.~..~~~~.~~~~~~~.~~C8f\f\\˕\\V =B99mi.~~~~.~~.~~~~~~..~~~.~~..~.~~~.~~~..~~~~.~~~~..~.~.~~~~.\\""x{n]n2^(~~.~~~~~..~.~.~~~.~.C.~.~~~~~~~C.C.~.C.~~~.~~~.~.C.C.C.C.CC.C.~~C.~C.C.~~C(nn2{rq2k*qkqn22n2C~..CC~.~~.C..~~..C..~~C.C.~C.C.~.C..~~..C.~.C.C..C.C.~~~~.~~~~~C.CCwwoeoMoK]qiJ%G]2CC~...C~C.C.~.C.C.~.~~~.~~.~C.C..C.C.C.C.C.~.C.C.C.C.C~~C.C.C.C..~~...C..C.C.C.~C.C.C.CC.C.C~~C.C.C.~~~C.~~~.C.C.C.C..C.C.C.CC..~.~C~~..CCV\\\L(n2^C~C.C.C.~C.C.C.CC.C.~C.~C.C.C.C..C.~~.C.~.~~~.~.~~~C..~.C.~C~C~C..C~C.~~~~~poooM2\"1.C..~C....C.C..~.~.~~.~.~.~.~.~~.~.~~~.~.~...~.~~~~~~.~.~.~~~~~.~~~.~.~~~~~~~.~~~~~~..~.~~~.\\>> i~~~~..~~.~...~.~~~.~..~~CC-855\\9"i~..~~~~~~.~.~~~.~~.~~.~..~~.~.~..~~~.~~.~..~~~.~~.~.~~~.~~\"J{nS2^CC~.~~~~~.~.~.~.~~~~~.~.C.C.C~~C~~~C~~C~C~~~.~.C.C.~.~.C....C.C.C~.C.C.C.~( n2 2n**n2222~C.~CC~~~~.~C.C.C.C.C..~..C..~.C.~.~C.~C.C..C..C..C..C~~~~~~.~~~~C~.o,o,oweoo]{{̶ {]CC...~~~~~.C.~.~.~.C.~.C.~~~~C.C.C.C.C.C~~C~C.~C.~C.C.C.C..C.~.C~C.~C.C.C.C..C.C.C~~C.C.C.CC~~~C..C.C.C.~~~~C..C.C.C.C.C.C.CCC....~C.C..CC\\X(\((2C~C.C..C..C.C.C..C.C.C~C.~.~.~.C.~~.C.~.C~.~..~~~.~..C.~~C~~.C.C~C.~.C~~.~~pKooo^\\\\?""CC.~.~.C.C..~~~~~~~~.~~.~.~...~~.~~.~..~~~.~...~.~~~~~.~~~.~~..~~.~.~.~.~~.~~.~.~~..~.~~.~~.~.\f\%>> > G(~~~.~~~~~~~.~..~~~~..~~CZZ8ff\\\ (""~~..~.~~~.~~~~.~~~~.~~.~.~~~.....~~~~.~~~.~~.~~~~~.~~\\sinn222C(~~.~~~~~~.~.~~...C.C..CC~~~~~C~C.C~~~~~.C.C...C..C...C.C.C.C.~C.C.C.C.CV (nn(2q2nn2S....CC~.C.C~.~.~.C..C.C.~C..C.~..C.C.~~~...C..C..C..C.~C~~.~~~~.C.C^wKoeeoeovK]?i {̲]CC~~..~~C.~.C.C.C.C.~~~~~.C.~~C.C.~~.C.C.~C.~~C.~C.~~~.C.C.C.~~~..~...C.C.C.C.C~.C.C.C.C.C..~~C.C.C..C.C~~~C.C~~C.C.C.C.C..C~C...C.CC..CC\\\\\L(C^~C..C.~~C.C..C.C.~~C.~.C.C.C...C.~~~.C.~.~.~~~.~.C..C.C~~~CC.~~~~C~C~~C.~pwooo]\f\-""9CC.~C.C...~~~~~~~~.~~.~~~.~~~.~.~.~~~~~.~.~..~~~~.~~~~.~~~.~~~~~~~~~~.~.~~~~~~~~~..~.~~.~.~~~.\> GL~~~~.~..~..~.~~~.~CCZ-85ffff\\ \("i.~~~.~~.~~~~~~~.~~.~~.~~~.~.~.~~~~~~.~.~~~~~..~.~.~~~~~~\\\-g1?/{2^C~~~~~~~~~~.~.~.~~~.C.~.C..C.~C.~~.C~~C~~C..C..C.C.C.C..C.C.C.C.C.C.C.C.CCC  2nn2....CC.~.~~.~~C.C..C..C.C..C.C.~C.~.~.C..CC..C.C..~C..~~~C~~~.~.C.~.,,eoooooeMo]{?/=0Bi*pC~C..~~~C.~.~..~.~.C.~~.~~~C.C.C.C.C.C.C~.C.C.~C.~C.C.C.C.C.~~.~C.C.C....C.~C.~~C.C.C..C.C.C.~~C..C.C.~..C..C.~~.C.C.CC.C.CCC....CCC...CC\\\\\(L((CC~C...~C.C~~C.C~C.C.~C.C.~.~~C.C.~.C.~.C~~.~~.~.~~~.~C..~~C.~.~C~~C~~~~~.C~pwoKo^\\\˕9""%pC...~..C.C.~~~~~~~~..~~~.~~~~.~~~.~~~~~.~~.~..~.~~.~.~~~~..~~~~.~~.~.~~~.~~~~.~~..~...~..~...\f\gX%> > >Gʢ~~~~.~~..~.~~~~.~~~~.~FZZ=888\g\ - 91"(C.~~~.~..~.~~~~~~~.~.~.~...~.~~~~.~~~~~~~.~.~~~~~~~\\\|B922(2C~~~~~~~~.~..~~.~~.C.~~C.C~~C.CC.C~~~~C.C.C..C..C~..CC.C.C..C.C~~.C.C.~FXnFn22.....C.C..~~~~....C..C....C...C..~.C.C..C...C.C.C.C..C.~~~~.~~.C.C~pw,peew,oe{̕)k KCC...C.~~..C.~C.C.~.C.~~C..C..C.C.C.C~C..C.C.~C.C.C.C.C.C~~~.~C..C.C..C.C..C.~~C.~.C.CC.C.C.C.C.CC.C.~C~C..C.C.C.C.C.C.C.C~CC....C..C.pC.f\f\f\\\\\\\\(C~C.~.C.~.~~C.~~.~C.~C.C~.C.C....~~~~.C.~~~.~~~.~.C.~~C.~C~CC.C~~~~~CC..~pKwoo]\f\\f\˕/99"1pCCC.C.C.~~.~~~~~~~~~.~.~.~.~~~~.~~~.~~.~~.~.~~.~~~~~.~~~.~~~~.~..~~~~.~.~~.~.~~~.~~~~..~~C\5\\>>> GLV~~..~.~~~~~~~CZ=LXi\X{{{J1(C~~...~~.~~~~~~~.~~.~.~..~.~.~~~~.~~.~~~~~~.~~.~..~~.~~~C~~~~~\\˕ΐ222^C~~~~~~~~~..~...~.~.~.~.C.C.C.C..C.~~C~C....C...C...C...C.C.CC.~~~C.~C.C^2v옳vp.C..C.C.~~.C.C...C..C.C..C.C.C.C..~..C..C.....~..C.C~~~.~~~.C.C~pwwv(^CewoK2]{i8/x% eC.~...C....~C..~.C.~~.~~.~~C.C.CC.C.C.~~CC.C~C.C~C.C.C.C.~~~~~~.C....C.~..C~~C.~CC.C.C.C.C.C.C.~~.~~~~~..CC.C.C.C..C.C.C.C.CC....CCC...CC(F222qv*owCC~.C~.~~C~~~C~C~C.~C.~C.~~.~.C.C.~.~.~.~~~~~~~.~.C.C~.C~.C.~.~.~.~.C.~.~..pwKoK2\58i4EEE"1(CCC..~~~~~~....~.~..~~~~.~~~.~~~~~~~~.~~.~.~~~~~~~~~~~.~~~~~~~.~~.~~~.~~.~~....\5B>> G\VVVʾ7ʾ~..~~~~~~~~~~~~(CZj@DX\99"9"""11(~~~~~~.~....~~~~.~.~~~.~.~~.....~~..~~.~~~~~CC.~8XXnS2{p(.~C~~~~~~~~~.~~.C.C~C~~C.~.C.C..C.C..~.~.C.C.C.C.~~C.~C~.C.C.~.C.C..C.~..;;;;;;;;;;;;;;;C~~C~C.C.~~C.C.C.~C.C.C.~.~C.~.~.C..C.~CC.C.C~~C.C.C.~~~.~~~.~~.C~Cw\\(oeC-Z"{]2CC.CCCCCCC..~C.C.C..C.~~~~~.C....C..C.C...~~~~C..C.C.C.C.C~~~.C..C~C~.C.C.~~.C.~.C.C.C.CCC.C.C.C.C.C..C...C.C.C.C.C.~~~~C~..C.~~..C.CC.~pKKweeeooIIoIII^~CC..~~~~...~.~~.~C.C.~.C.C.C.C.C.C.C.C~~..~~~~~~.C.C~.C.~.C.C.C.~.C.C..~.CwKo]\f\ff8EEE""9KCCC.~~.~~.~~.~.~...~~~.~~~~~~.~~~~~~~.~~..~.~..~~~~~~~~~~~~.~~~~~~~.~~~~.~.~.~~.\5\B aVVVʢ~~~~.~~~~~~.C^j@@@D—\\LX"111~..~~..~..~~.~..~~~..~..~~.~.~.~~.~~.~~~~~~.~~CC.F-g8\\Lnn^~~~~~~~~~~.~~.C.~.C~.C.~.C.~..C.~~.C~C.C.C.C.C.C.C.C..C.~.~.C.C..C.~.C.;;;;;;;;;;;;;3~~C~C~.C.C.~C.C.C~~.C.C.C..~.C.~..C~.C..C.C.~C.C.C.C.C.C.~.~~C.C~Cppw\\ve>9%C~C.CC~C.C.C..~....C..~~~.~~.C..C..C..~~C.C.~C.~C.C.C.C.C.C.C.C.C.~~.C.C.C.~C.C.C.C.C.C..C..~.~~.~~..C.CC.C.C.C.C.C.C.~~C..C.~~..C.CC.CCwKoooweoooKMMooeMICCC~.CC...C.C.C~.C..~.C.~.C.C.C..C.C.C.~~~~~~~~~..C.C.~C.~.C.~.~.C.~.~.~.~CwwKwKv5ffff\f(4EE99o(.....~~~~~....~~..~.~~.~.~~~~.~.~.~.~~~~~.~~~.~.~~~~.~.~.~~~~.~~.~~.~~.b\5f8-l> %\\VVVVVVV~~~~~~~~.~~~(^@U껝> i~~~~~~~~~..~~~..~~~.~~.~~~..~~~~..~~.~~~.~..~~~CC~̜˕g==/{](.~~~~~~~CC~~~.~~.C.C.~C~C.C..C.C.~~~~~...C.C.~~.C.C.C.CC.C.C.~~.~.C.C.~~.3;;;;;;;;;;;,p~~~~~C~C.C.C.~.C.C.C.~.~.~C.C..C.C...C.C.C.C~.C.C.C.C~~~~~~~..CC~C.w\^eeKJ"1m vC........C.C.C.C.C.C.~~C..C.C.C...C..~.C.C.~C~~.C..C.C..C.C.C.C.C.C.C.~~C.C.~C.C.C.C.CC.C.C..C.~~C.~...C.C.C.C.C.~C.~C.C.~.~.C.C..CC.wwooooweooooKoMoKo,C~C~C....C..C....C.C.~.C.~C.C~.CC.~C.C.C~~.~~~.~~C.C.CC~.C.~.C.C.~.C.C.C....wwKv5f5ff5f\\@E99MC...C.~.~.~~~...~~..~.~.~.~~~~~.~.~~..~~~~~.~~~~~~~~.~~.~..~~~..~.~~~.C5ff8>>>>V\VVVVVV~.~..~~~~~.~~(^@L{Ꝼ"껋iC~~.~~~~..~.~~..~~~~~.~.~~~~...~~~~.~~~.~..~.~~CC~p??{??zllBl BHHe~~~~C~~~~~C~~~.~~..~.C~C.~.~~.C.~..C.~.~..C..C~C~C~~~~C.~.~.~..C..C.~.~.C.~b;;;;;;;;;C~~C.~~~.C.C.CC.C~.~C.C.C.C..~.C.~~.C.C.C.C.C.~C.C.C.~~~~.~.~.C.~~CCwv(ioepi˕=h]2.C.~.~....C.~~..C.~~~..C.~.C..~~.C.C.~~C.C.C.C.C.C~~C.~C~C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.~.~.C.~.~~..C.C.C..C.C.C.C~C.C.C.C.C.~..CCC.CCwwwKoeoeoKoMMoowoMICC~C..C...CC..C.C.~.C.~.~C.~~.C..C~C.C.C.~~~.~~~C..C.C.~.~.C.~.~.C.C.~.~..CCwwKwK]55ff58N5DçErn~F.~.~~.~~~~~~.~~~..~~~~~~.~~~~~~.~.~~~.~~~~.~~....~.~..~~~~3\5ff5\f\=ddd>>RVVVVVVVʢVVVVVVV~..~~~~~~~~~CZz=X/?1s"11%S~.~~~~~~.~....~~..~..~~~~.~..~~~~~~.~~~.~.~.~~~~C~~i{@@DDDDDD×E""11H~~~~C~~C~~.~~~~.C.~~~~C~C..C..C.C.CC.C.C.C.C.~~~~~C.~C~C~C.~C.~~~.C.C~.~~3bb;;;;~~C.C.C..C.~.C.~CC.C..~.~.C...C.~~.C.C~.C.~~C.C..C.C~~~~~~~~.C~C~Cpweewweeq˵82qpC~~C~CCC~.~.C..C.~~.~~C..~C..C.~~.C.~C...C~.C.C..C.~C.C.~~C.C.C.C.C.C.~~~C..C.C~.C~.C.~C.C.C.~C.~~~~C..~.C.C.C..C.C..C.C.~C.~~.C.C.C.C~wKooeweoeMwooooKwoo,C~C~C...C....~~~.C.~.C.C.~C.C.C.C~.~.C.C.~.~~~.~..C.C.CC~C.~.~C.~.~..C.C~~.~.wwKvv555ff||5fZDDRS~~~..~~~~~~~~~~~.~.~~~.~~.~.~~~~~~~.~~~..~~.~~..~.~~~~.77~~~~~. 55|5f\=Jdddd>>(VVVVVVVVVVVVVVVVV77~..~~~.~~~.(=i(̶s1"111"%{.~~.~~.~.~~~.~..~~.~~.~~~.~..~~~~~~.~~.~~.~~..C~~~S]@@D@@D@@@D9""1 nF~~~C~~~.~C~~~~.~~.C.~C~~~~~C..C.C......C.C.C.C.C.~C.C.C.C.~~~~~.C.~.~~.~~~.;;b~~~~.C.C.C.CC.C.C.~.C.~C.C.~C.C.C..C.~~.C~C.C.~C.C.C~~~~.~.~.~.~C~~pw,owowe,e i{8J-K]pCCCCCC~C~C.C..C..~~C..~.C.~.C.~..C.~..C.C.~~C..CC.C.~~C.C.~~.C.C.C.C.C.C.~~C.C~.C.~C.~C.~.~.C.~.C.~.~.C~C.C.C.C.C.~C.C.C.C.C..~.C..CCC~wwoowwoeooKKKoowwo,op~CC.C.C.C.C.C.~.~.C.~..~C.C~C.C.~~C.C.~~~~~~.~.C.~C.C.~~.~.C.~.C.C.C.~.....Cww](555fN5f55חU4 i...~C.~~~~.~~~~~~.~.~.~~~~~~.~~~.~~~~~.~~~~~.~~~.7~.~~~..\5f55\|Jd>VVVVV\VVVVVVVVVVVVVVV>iV\VVVVVVVVVVVVVVVVVVVVVVVV~~~~~~~.(^@D4D %%"""1111Gq.~~.~~.....~...~.~~~.~~..~..~.~.~~~~~~~~.~.CC..~.i*çD@@@@@@@D×9SCC~~~~...~~~~..C.~~C~~~~.C..C.C..C..~~.C.C.C.C.C.~~~~~C~~C.~C.~~~.~C.~~C33F3~~~~C.C.~C~.C.C.~C.C.C.~~C.~.~C.C.C.C~~~~~C.C.~C.C.~C~.~~~.~.~~.C~~pwMKMKoKweo{LX89{S(CCC~.....C~C..C.C.~..C.~~.~.~...C.~...~.C.C.C.C.~~~~~C.~.C.C.~~C.C~C.C.~~.C.~C.~C~C.C.C..C.C.~.C...C.C.C.C..C.C.C..C..C~C.C.~.C.C.CC~pwowo,eooKeo,wwow,,p~C.CC.C.C..C.~~~C..~.C..C.~CC.C.C.C.C.~~~~~~~..C.C~~C.C.~.C.C.~.C.C.~..C..C.pwp(5555NNN5=J@@]CC~~~~~~~~.~~~~..~~.~.~~~~~.~~~~~.~.~.~~~~~~~~~~~777~~5555558EdVV\VVVVVVVVV\VVV\VV9"11111*(~.~~.~~.~....~.~.~.~.~~~~~..~~.~.~~.~~~.~.~CC..~~i]›@››DΐM]..~~~..~.~.~~C.~.C.~C.C~.C..~.C.~.C..C.~~C.C.C.~C.C.C.~.~.~.~.~~~~.C.~~F33b.~~.C~~C.~C.~C.C.~C~.~C.~.~.C..~.~..C.~C.~C.~C.~C.C.~C.~~~.~.C..C.wooKoowoKenq{ʜ-i]^CCC~C.....C....C.~~.C.C.~..C.C..C.~C.~~C.~C.C.~~~C.C.C.C.C~~~~C.C.C.~~~C.C~~C.C.C~~~.C.C.C..~~~.C.C.C..C.C.C.C.~C~C.C.C.C.C~~~~C...C.C.C.wwwweweevweeo,,woow.C.C.....~~~~.C..~.C.~.C.C.C.~.C.C.~C.~C.~~~.~C..~.C~C.C.~.~.~.C.~.C.C.~.C.ppwpp](V555ff5f=J@@@@@@^.~~~~~.~~.~..~.~~~.~.~~~~.~~~.~~~.~~~.~~~.~~..~~777~35555558EE9 nV\V\>1) /* `sBx' is signed */ #else #define MAXARG_Bx MAX_INT #define MAXARG_sBx MAX_INT #endif #if SIZE_Ax < LUAI_BITSINT-1 #define MAXARG_Ax ((1<>POS_OP) & MASK1(SIZE_OP,0))) #define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ ((cast(Instruction, o)<>pos) & MASK1(size,0))) #define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ ((cast(Instruction, v)<= R(A) + 1 */ OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) > 4) & 3)) #define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) #define testAMode(m) (luaP_opmodes[m] & (1 << 6)) #define testTMode(m) (luaP_opmodes[m] & (1 << 7)) LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ /* number of list items to accumulate before a SETLIST instruction */ #define LFIELDS_PER_FLUSH 50 #endif blobby-1.0/src/blobnet/layer/Http.hpp000644 001750 001750 00000003722 12313310251 022366 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= blobNet Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #ifndef _BLOBNET_LAYER_HTTP_HPP_ #define _BLOBNET_LAYER_HTTP_HPP_ /* Includes */ #include "../exception/HttpException.hpp" #include "../../raknet/SocketLayer.h" #include namespace BlobNet { namespace Layer { /*! \class Http \brief Simple Layer for HTTP communication over TCP/IP */ class Http { public: /// @brief constructor, connects to an host Http(const std::string& hostname, const int& port); /// @brief deconstructor, closes connection to host ~Http(); /// @brief sends a request /// @param path Path to the requested file /// @param response Stringstream where the response will pushed in void request(const std::string& path, std::stringstream& response); private: void readHeader(int inOutSocket, std::stringstream& response); void readBody(int inOutSocket, std::stringstream& response, int contentSize); int getContentSize(std::stringstream& response); std::string mHostname; int mPort; SocketLayer mSocketLayer; enum State { cr, crlf, crlfcr, headerDone, contentlength, something, error }; }; } } #endif blobby-1.0/src/lua/000755 001750 001750 00000000000 12313310253 016754 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/lua_api_doc.dox000644 001750 001750 00000041277 12313310251 021157 0ustar00danielknobedanielknobe000000 000000 /* This file contains the documentation of the blobby volley lua bot api in a form readable by doxygen for generating a clearer documentation. As doxygen is not capable of parsing lua source code, the function declarations are in C++ syntax, providing parameter and return types, too (in contrast to lua functions which would be unable to define type inforamtion) */ // ---------------------------------------------------------- // | documentation of the api function set | // ---------------------------------------------------------- /*! \defgroup lua_api API Documentation Here you find the documentation of the functions offered by Blobby Volley's lua interface for scripting a bot. For each function you get to know what it does, which parameters are expected and which values are returned. This documentation is subdivided into several function groups: \li Functions for input simulation: \ref command_func "Input" \li Functions for getting data: \ref ball_func "Ball Information", \ref blobby_func "Blobby Information", \ref game_status_func "Game Status" \li Estimation/Calculation functions: \ref estim_func "Estimation/Calculation" All functions of the lua math library are also available. You can find their documentation at: http://www.lua.org/manual/5.1/manual.html#5.6 \n Besides these functions that are provided by Blobby Volley, each script can define the functions listed under \ref script_func "Script Functions". Note that some of them are required to get your bot working. In addition to these functions, the Blobby Volley 2 Lua API provides a lot of preset constants to simplify bot development and make adaption to new circumstances (e.g. different fieldsize, gravity) easier if that gets implemented. \attention Remember that Lua is \b not able to declare a variables as const. Thus, it IS possible to change the value of these constants. @{ */ // ---------------------------------------------------------- // other // ---------------------------------------------------------- /*! \brief debugging \details prints \p num to the debugging output (stderr) \ingroup lua_api */ void debug(float num); // ---------------------------------------------------------- // input performing functions // ---------------------------------------------------------- /*! @{ \anchor command_func \name Input Functions */ //! \brief step to the left void left(); //! \brief step to the right void right(); /*! \brief simulate jump key \details Simulates pressing the jump key, so a first call causes the blobby to jump whereas successive calls (in the next time steps) make the jump higher */ void jump(); /*! \brief Move to position \details moves to a given position, using a small buffer to avoid whobbling around the target \param target destination */ void moveto(int target); //! @} // ---------------------------------------------------------- // ball information querying // ---------------------------------------------------------- /*! @{ \anchor ball_func \name Ball Information This set of functions allows the script to query information about \n ball position, velocity and the number of touches done by the bot. */ /*! \brief get number of touches \details returns the number of touches the player had made since the opponend had touched the ball last. */ int touches(); //! \brief x component of ball position float ballx(); //! \brief y component of ball position float bally(); //! \brief x component of ball velocity float bspeedx(); //! \brief y component of ball velocity float bspeedy(); //! @} // ---------------------------------------------------------- // blob information querying // ---------------------------------------------------------- /*! @{ \anchor blobby_func \name Blobby Information */ //! \brief is blobby launched //! \return returns true if blobby doesn't stand on the ground bool launched(); /*! \brief x component of blobby position \details returns the x component of the middle of the blobby \sa oppx(), posy() */ float posx(); /*! \brief y component of blobby position \details returns the y component of the middle of the blobby, i.e. the blobby's top minus half of \ref CONST_BLOBBY_HEIGHT. \sa oppy(), posx() */ float posy(); /*! \brief x component of enemy position \details returns the x component of the middle of the enemy \sa posx(), oppy() */ float oppx(); /*! \brief y component of enemy position \details returns the y component of the middle of the enemy, i.e. the enemy's top minus half of \ref CONST_BLOBBY_HEIGHT. \sa posy(), oppy() */ float oppy(); //! @} // ---------------------------------------------------------- // game status // ---------------------------------------------------------- /*! @{ \anchor game_status_func \name Game Status Information */ /*! \brief get own score \sa getOppScore() \sa getScoreToWin() */ int getScore(); /*! \brief get opponent's score \sa getScore() \sa getScoreToWin() */ int getOppScore(); /*! \brief score required for winning \sa getScore() \sa getOppScore() */ int getScoreToWin(); //! \brief game time passed so far //! \return game time in seconds int getGameTime(); //! @} // ---------------------------------------------------------- // estimations // ---------------------------------------------------------- /*! @{ \anchor estim_func \name Calculation/Estimation Functions */ /*! \brief estimates ball impact on ground \details Calculates the position where the ball is going to hit the ground. Ignores bounces with walls and the net. \deprecated This funcion is relatively useless as both its purpose (calculating ground impace, where it is already to late to catch the ball) and its calculation itself (ignoring bounces) are not good. As a consequence, it is hardly used in the current bots so it might be removed in one of the next releases. \return x component of the estimated position \sa predictImpact */ float estimate(); /*! \brief estimates x position after certain time \details calculates the estimated x position of the ball after \p time steps, ignoring bounces with walls and net \param time Number of steps to anticipate \deprecated use predictx() for more accurate estimations \sa estimx() */ float estimx(int time); /*! \brief estimates y position after certain time \details calculates the estimated y position of the ball after \p time steps, ignoring bounces with walls and net \warning May be a little inaccurate for long timespans as it uses explicit formulars instead of step-by-step simulation \param time Number of steps to anticipate \deprecated use predicty() for more accurate estimations \sa estimy() */ float estimy(int time); /*! \brief estimates ball impact on blobby head \details Calculates the position where the ball will be on height with the blobby head. Takes bounces with the walls into account. \return x component of the calculated position \sideeffect Sets \ref FLAG_BOUNCE to true if ball hits a wall before it reaches its destination. */ float predictImpact(); /*! \brief estimates time ball need to hit net top \details Reckons the time the ball needs to hit the net's center the next time. Collisions with blobbys, walls or the ned rod are not calculated. \attention extensive use may need a lot of cpu power */ float nettime(); // ---------------------------------------------------------- // spec in development // ---------------------------------------------------------- /*! \brief predicts ball position \details Calculates the position the ball will have after \p time steps, taking into account bounces with walls and a simplified model for the net (i.e., the more complicated collision with the net top is diregarded). \warning As this uses explicit formulas instead of simulating step by step, the results may slightly vary from the real values. \sideeffect Sets \ref FLAG_BOUNCE to true if ball hits a wall during the considered timespan. \sa predicty(int time); */ float predictx(int time); /*! \brief predicts ball position \details Calculates the position the ball will have after \p time steps, taking into account bounces with walls and a simplified model for the net (i.e., the more complicated collision with the net top is diregarded). \warning As this uses explicit formulas instead of simulating step by step, the results may slightly vary from the real values. \sideeffect Sets \ref FLAG_BOUNCE to true if ball hits a wall during the considered timespan. \sa predictx(int time); */ float predicty(int time); /*! \brief time ball needs to position \details Calculates the duration until the ball reaches a certain position the next time. Bounces with the wall and net rod are calculated correctly, net top is disregarded. \sideeffect Sets \ref FLAG_BOUNCE to true if ball hits a wall before reaching its destination. \sa timetoy(float target) */ float timetox(float target); /*! \brief time ball needs to position \details Calculates the duration until the ball reaches a certain position the next time. Bounces with the wall and net rod are calculated correctly, net top is disregarded. \sideeffect Sets \ref FLAG_BOUNCE to true if ball hits a wall before reaching its destination. \sa timetoy(float target) */ float timetoy(float target); /*! \brief x when ball reaches certain y \details caluclates the x coordinate the ball has when it reaches \p target. Equivalent to predictx(timetoy(target)) \sideeffect Sets \ref FLAG_BOUNCE to true if ball hits a wall before reaching its destination. \sa yatx */ float xaty(float target); /*! \brief y when ball reaches certain x \details caluclates the y coordinate the ball has when it reaches \p target. Equivalent to predicty(timetox(target)) \sideeffect Sets \ref FLAG_BOUNCE to true if ball hits a wall before reaching its destination. \sa xaty */ float yatx(float target); /*! \brief time the blobby needs to reach \p target */ float blobtimetox(float target); /*! \brief time the blobby needs to reach \p target. \details calculates the time the blobby needs to reach a certain height. It is assumed that jump() is called incessantly. */ float blobtimetoy(float target); /*! \brief time till next event \details calculates when the next event will occur. in this context, event means bouncing against the wall, the net or hitting the ground. \sideeffect Sets \ref FLAG_BOUNCE to true if next event is hitting wall or net. */ float nextevent(); //! @} // ---------------------------------------------------------- // functions to be implemented by script // ---------------------------------------------------------- /*! @{ \anchor script_func \name Script Functions These functions are to be implemented by the scripter. \n They create the bot behaviour and allow response to certain events. \n Some of them are required for a working bot and marked with \b required. */ /*! \brief function for serving \details Called when the ball went down and the controlled blob has to serve it next. \param ballready true when ball is placed \attention \b required */ void OnServe(bool ballready); /*! \brief Oppenent is serving \details Called after balldown when the opponent has to serve the next ball */ void OnOpponentServe(); /*! \brief Mainloop function \details Called each step during the normal game \attention \b required */ void OnGame(); /*! \brief ball bounce event \details Called when ball trajectory changes (i.e. ball hits border/net/blobby) */ void OnBounce(); //! @} // ---------------------------------------------------------- // | constants | // ---------------------------------------------------------- //! width of the playing field const float CONST_FIELD_WIDTH = 800; //! y coordinate of the gound plane const float CONST_GROUND_HEIGHT = 100; //! strenght of the gravity that affects the ball const float CONST_BALL_GRAVITY = -0.28; //! radius of ball const float CONST_BALL_RADIUS = 31.5; //! start velocity of jumping blobby const float CONST_BLOBBY_JUMP = 15.1; //! radius of the lower sphere of the blobby const float CONST_BLOBBY_BODY_RADIUS = 33; //! radius of the upper sphere of the blobby const float CONST_BLOBBY_HEAD_RADIUS = 25; //! height of the blobby const float CONST_BLOBBY_HEIGHT = 89; //! gravity that affects the blobby if jump() is not called. //! otherwise, half of this value is used const float CONST_BLOBBY_GRAVITY = -0.88; //! y coordinate of the top of the net const float CONST_NET_HEIGHT = 316; //! radius of the net / half the breadth const float CONST_NET_RADIUS = 7; // ---------------------------------------------------------- // | variables | // ---------------------------------------------------------- /*! \brief wall bounce calculated? \details Is set by some functions to indicate whether a collision with the wall had to be taken into account, i.e. the ball hits a wall during the processed timespan. */ extern bool FLAG_BOUNCE; //! @} // ---------------------------------------------------------- // | tutorial | // ---------------------------------------------------------- /*! \mainpage \page tutorial In diesem Tutorial werden die Grundlagen von Lua und der Botprogrammierung von Blobby Volley 2 erlutert. Fr weiterfhrende Informationen gibt es die Dokumentation der Script-API. \n Fr Leute, die noch nie programmiert haben, empfehle ich folgendes Tutorial, um die wichtigsten Grundlagen zu erlernen: http://robertico.ro.funpic.de/index.php \n Vor der Programmierung ist zu beachten, dass Blobby-Skripte in 'data/scripts' abgelegt werden mssen und die Dateiendung '.lua' tragen mssen, um vom Spiel erkannt zu werden \n Fr ein gltiges Blobby-Script msst ihr 3 Funktionen festlegen: \n \code function OnServe(parameter) -- Wird aufgerufen wenn der Ball abgepfiffen wurde und man selber angeben -- soll. Der Parameter gibt an, ob der Ball schon in der Schwebe plaziert ist end function OnOpponentServe() -- Wird aufgerufen wenn der Gegner angeben soll end function OnGame() -- Wird ansonsten whrend des gesamten Spieles aufgerufen -- Mit -- werden brigens Kommentare markiert, solltet ihr es noch nicht bemerkt haben ;D end \endcode Bevor ihr jetzt loslegt, noch etwas zum Koordinatensystem: Das Spielfeld ist 800 Einheiten breit und 600 Einheiten hoch, ganz an der alten Blobby-Auflsung orientiert. X wchst dabei nach rechts und Y nach oben. Damit wre also 0,0 unten links und 800,600 oben rechts. Falls ihr euch wundert dass es keine Mglichkeit gibt die eigene Seite zu bestimmen, das ist Absicht. Programmiert einfach als ob der Bot immer links stehen wrde, das Programm dreht gegebenenfalls alle Koordinaten um. Ich werde jetzt einfach mal ein Beispiel zeigen, wie ein simpler Bot aufgebaut sein kann: \code function OnOpponentServe() moveto(130) -- Wenn der Gegner spielt, in Ausgangsposition gehen end function OnServe(ballready) moveto(ballx() - 40) -- Etwas links vom Ball hinstellen if posx() < ballx() - 37 and posx() > ballx() - 43 then -- Dieser zugegeben etwas komplizierte Ausdruck bewirkt, dass -- man sich erstmal unterhalb des Balles befinden muss. Leider muss -- das so aufwendig gemacht werden, weil moveto() niemals eine Stelle -- ganz exakt erreicht. if ballready then jump() -- Natrlich nur springen wenn der Ball schon bereitsteht end end end function OnGame() if ballx() < 400 then -- Wenn sich der Ball links von der Mitte, -- also auf unserer Seite befindet moveto(ballx() - 20) -- Etwas links vom Ball ausrichten if ballx() < posx() + 50 then jump() -- Wenn der Ball kurz vor oder hinter dem Blobby ist, springen end end end \endcode Ich hoffe, dieses Tutorial hat einen Eindruck entwickelt, wie man einen Bot programmiert. Fr weitere Informationen gibt es wie gesagt die Script-API-Doku. Um fortgeschrittene Bots zu programmieren, solltet ihr auch nicht immer blind dem Ball hinterherrennen, sondern mit den estim*-Funktionen Vorhersagen machen. Ansonsten kann ich euch nur als Tip mitgeben, euren Bot immer wieder zu beobachten und gegen jede gefundene Schwche einen Schutzmechanismus zu entwickeln. */ blobby-1.0/src/tinyxml/tinyxml.cpp000644 001750 001750 00000111327 12313310251 022112 0ustar00danielknobedanielknobe000000 000000 /* www.sourceforge.net/projects/tinyxml Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include #ifdef TIXML_USE_STL #include #include #endif #include "tinyxml.h" FILE* TiXmlFOpen( const char* filename, const char* mode ); bool TiXmlBase::condenseWhiteSpace = true; // Microsoft compiler security FILE* TiXmlFOpen( const char* filename, const char* mode ) { #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) FILE* fp = 0; errno_t err = fopen_s( &fp, filename, mode ); if ( !err && fp ) return fp; return 0; #else return fopen( filename, mode ); #endif } void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) { int i=0; while( i<(int)str.length() ) { unsigned char c = (unsigned char) str[i]; if ( c == '&' && i < ( (int)str.length() - 2 ) && str[i+1] == '#' && str[i+2] == 'x' ) { // Hexadecimal character reference. // Pass through unchanged. // © -- copyright symbol, for example. // // The -1 is a bug fix from Rob Laveaux. It keeps // an overflow from happening if there is no ';'. // There are actually 2 ways to exit this loop - // while fails (error case) and break (semicolon found). // However, there is no mechanism (currently) for // this function to return an error. while ( i<(int)str.length()-1 ) { outString->append( str.c_str() + i, 1 ); ++i; if ( str[i] == ';' ) break; } } else if ( c == '&' ) { outString->append( entity[0].str, entity[0].strLength ); ++i; } else if ( c == '<' ) { outString->append( entity[1].str, entity[1].strLength ); ++i; } else if ( c == '>' ) { outString->append( entity[2].str, entity[2].strLength ); ++i; } else if ( c == '\"' ) { outString->append( entity[3].str, entity[3].strLength ); ++i; } else if ( c == '\'' ) { outString->append( entity[4].str, entity[4].strLength ); ++i; } else if ( c < 32 ) { // Easy pass at non-alpha/numeric/symbol // Below 32 is symbolic. char buf[ 32 ]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); #else sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); #endif //*ME: warning C4267: convert 'size_t' to 'int' //*ME: Int-Cast to make compiler happy ... outString->append( buf, (int)strlen( buf ) ); ++i; } else { //char realc = (char) c; //outString->append( &realc, 1 ); *outString += (char) c; // somewhat more efficient function call. ++i; } } } TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() { parent = 0; type = _type; firstChild = 0; lastChild = 0; prev = 0; next = 0; } TiXmlNode::~TiXmlNode() { TiXmlNode* node = firstChild; TiXmlNode* temp = 0; while ( node ) { temp = node; node = node->next; delete temp; } } void TiXmlNode::CopyTo( TiXmlNode* target ) const { target->SetValue (value.c_str() ); target->userData = userData; target->location = location; } void TiXmlNode::Clear() { TiXmlNode* node = firstChild; TiXmlNode* temp = 0; while ( node ) { temp = node; node = node->next; delete temp; } firstChild = 0; lastChild = 0; } TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) { assert( node->parent == 0 || node->parent == this ); assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) { delete node; if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } node->parent = this; node->prev = lastChild; node->next = 0; if ( lastChild ) lastChild->next = node; else firstChild = node; // it was an empty list. lastChild = node; return node; } TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) { if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; return LinkEndChild( node ); } TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) { if ( !beforeThis || beforeThis->parent != this ) { return 0; } if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; node->parent = this; node->next = beforeThis; node->prev = beforeThis->prev; if ( beforeThis->prev ) { beforeThis->prev->next = node; } else { assert( firstChild == beforeThis ); firstChild = node; } beforeThis->prev = node; return node; } TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) { if ( !afterThis || afterThis->parent != this ) { return 0; } if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; node->parent = this; node->prev = afterThis; node->next = afterThis->next; if ( afterThis->next ) { afterThis->next->prev = node; } else { assert( lastChild == afterThis ); lastChild = node; } afterThis->next = node; return node; } TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) { if ( !replaceThis ) return 0; if ( replaceThis->parent != this ) return 0; if ( withThis.ToDocument() ) { // A document can never be a child. Thanks to Noam. TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = withThis.Clone(); if ( !node ) return 0; node->next = replaceThis->next; node->prev = replaceThis->prev; if ( replaceThis->next ) replaceThis->next->prev = node; else lastChild = node; if ( replaceThis->prev ) replaceThis->prev->next = node; else firstChild = node; delete replaceThis; node->parent = this; return node; } bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) { if ( !removeThis ) { return false; } if ( removeThis->parent != this ) { assert( 0 ); return false; } if ( removeThis->next ) removeThis->next->prev = removeThis->prev; else lastChild = removeThis->prev; if ( removeThis->prev ) removeThis->prev->next = removeThis->next; else firstChild = removeThis->next; delete removeThis; return true; } const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const { const TiXmlNode* node; for ( node = firstChild; node; node = node->next ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const { const TiXmlNode* node; for ( node = lastChild; node; node = node->prev ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const { if ( !previous ) { return FirstChild(); } else { assert( previous->parent == this ); return previous->NextSibling(); } } const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const { if ( !previous ) { return FirstChild( val ); } else { assert( previous->parent == this ); return previous->NextSibling( val ); } } const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const { const TiXmlNode* node; for ( node = next; node; node = node->next ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const { const TiXmlNode* node; for ( node = prev; node; node = node->prev ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } void TiXmlElement::RemoveAttribute( const char * name ) { #ifdef TIXML_USE_STL TIXML_STRING str( name ); TiXmlAttribute* node = attributeSet.Find( str ); #else TiXmlAttribute* node = attributeSet.Find( name ); #endif if ( node ) { attributeSet.Remove( node ); delete node; } } const TiXmlElement* TiXmlNode::FirstChildElement() const { const TiXmlNode* node; for ( node = FirstChild(); node; node = node->NextSibling() ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const { const TiXmlNode* node; for ( node = FirstChild( _value ); node; node = node->NextSibling( _value ) ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::NextSiblingElement() const { const TiXmlNode* node; for ( node = NextSibling(); node; node = node->NextSibling() ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const { const TiXmlNode* node; for ( node = NextSibling( _value ); node; node = node->NextSibling( _value ) ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlDocument* TiXmlNode::GetDocument() const { const TiXmlNode* node; for( node = this; node; node = node->parent ) { if ( node->ToDocument() ) return node->ToDocument(); } return 0; } TiXmlElement::TiXmlElement (const char * _value) : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; value = _value; } #ifdef TIXML_USE_STL TiXmlElement::TiXmlElement( const std::string& _value ) : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; value = _value; } #endif TiXmlElement::TiXmlElement( const TiXmlElement& copy) : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; copy.CopyTo( this ); } TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) { ClearThis(); base.CopyTo( this ); return *this; } TiXmlElement::~TiXmlElement() { ClearThis(); } void TiXmlElement::ClearThis() { Clear(); while( attributeSet.First() ) { TiXmlAttribute* node = attributeSet.First(); attributeSet.Remove( node ); delete node; } } const char* TiXmlElement::Attribute( const char* name ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( node ) return node->Value(); return 0; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( attrib ) return &attrib->ValueStr(); return 0; } #endif const char* TiXmlElement::Attribute( const char* name, int* i ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const char* result = 0; if ( attrib ) { result = attrib->Value(); if ( i ) { attrib->QueryIntValue( i ); } } return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const std::string* result = 0; if ( attrib ) { result = &attrib->ValueStr(); if ( i ) { attrib->QueryIntValue( i ); } } return result; } #endif const char* TiXmlElement::Attribute( const char* name, double* d ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const char* result = 0; if ( attrib ) { result = attrib->Value(); if ( d ) { attrib->QueryDoubleValue( d ); } } return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const std::string* result = 0; if ( attrib ) { result = &attrib->ValueStr(); if ( d ) { attrib->QueryDoubleValue( d ); } } return result; } #endif int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryIntValue( ival ); } int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; int ival = 0; int result = node->QueryIntValue( &ival ); *value = (unsigned)ival; return result; } int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; int result = TIXML_WRONG_TYPE; if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) { *bval = true; result = TIXML_SUCCESS; } else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) { *bval = false; result = TIXML_SUCCESS; } return result; } #ifdef TIXML_USE_STL int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryIntValue( ival ); } #endif int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryDoubleValue( dval ); } #ifdef TIXML_USE_STL int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryDoubleValue( dval ); } #endif void TiXmlElement::SetAttribute( const char * name, int val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetIntValue( val ); } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& name, int val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetIntValue( val ); } } #endif void TiXmlElement::SetDoubleAttribute( const char * name, double val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetDoubleValue( val ); } } #ifdef TIXML_USE_STL void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetDoubleValue( val ); } } #endif void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); if ( attrib ) { attrib->SetValue( cvalue ); } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); if ( attrib ) { attrib->SetValue( _value ); } } #endif void TiXmlElement::Print( FILE* cfile, int depth ) const { int i; assert( cfile ); for ( i=0; iNext() ) { fprintf( cfile, " " ); attrib->Print( cfile, depth ); } // There are 3 different formatting approaches: // 1) An element without children is printed as a node // 2) An element with only a text child is printed as text // 3) An element with children is printed on multiple lines. TiXmlNode* node; if ( !firstChild ) { fprintf( cfile, " />" ); } else if ( firstChild == lastChild && firstChild->ToText() ) { fprintf( cfile, ">" ); firstChild->Print( cfile, depth + 1 ); fprintf( cfile, "", value.c_str() ); } else { fprintf( cfile, ">" ); for ( node = firstChild; node; node=node->NextSibling() ) { if ( !node->ToText() ) { fprintf( cfile, "\n" ); } node->Print( cfile, depth+1 ); } fprintf( cfile, "\n" ); for( i=0; i", value.c_str() ); } } void TiXmlElement::CopyTo( TiXmlElement* target ) const { // superclass: TiXmlNode::CopyTo( target ); // Element class: // Clone the attributes, then clone the children. const TiXmlAttribute* attribute = 0; for( attribute = attributeSet.First(); attribute; attribute = attribute->Next() ) { target->SetAttribute( attribute->Name(), attribute->Value() ); } TiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { target->LinkEndChild( node->Clone() ); } } bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const { if ( visitor->VisitEnter( *this, attributeSet.First() ) ) { for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) break; } } return visitor->VisitExit( *this ); } TiXmlNode* TiXmlElement::Clone() const { TiXmlElement* clone = new TiXmlElement( Value() ); if ( !clone ) return 0; CopyTo( clone ); return clone; } const char* TiXmlElement::GetText() const { const TiXmlNode* child = this->FirstChild(); if ( child ) { const TiXmlText* childText = child->ToText(); if ( childText ) { return childText->Value(); } } return 0; } TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; ClearError(); } TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; value = documentName; ClearError(); } #ifdef TIXML_USE_STL TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; value = documentName; ClearError(); } #endif TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { copy.CopyTo( this ); } TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) { Clear(); copy.CopyTo( this ); return *this; } bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) { return LoadFile( Value(), encoding ); } bool TiXmlDocument::SaveFile() const { return SaveFile( Value() ); } bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) { TIXML_STRING filename( _filename ); value = filename; // reading in binary mode so that tinyxml can normalize the EOL FILE* file = TiXmlFOpen( value.c_str (), "rb" ); if ( file ) { bool result = LoadFile( file, encoding ); fclose( file ); return result; } else { SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } } bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) { if ( !file ) { SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // Delete the existing data: Clear(); location.Clear(); // Get the file size, so we can pre-allocate the string. HUGE speed impact. long length = 0; fseek( file, 0, SEEK_END ); length = ftell( file ); fseek( file, 0, SEEK_SET ); // Strange case, but good to handle up front. if ( length <= 0 ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // Subtle bug here. TinyXml did use fgets. But from the XML spec: // 2.11 End-of-Line Handling // // // ...the XML processor MUST behave as if it normalized all line breaks in external // parsed entities (including the document entity) on input, before parsing, by translating // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to // a single #xA character. // // // It is not clear fgets does that, and certainly isn't clear it works cross platform. // Generally, you expect fgets to translate from the convention of the OS to the c/unix // convention, and not work generally. /* while( fgets( buf, sizeof(buf), file ) ) { data += buf; } */ char* buf = new char[ length+1 ]; buf[0] = 0; if ( fread( buf, length, 1, file ) != 1 ) { delete [] buf; SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // Process the buffer in place to normalize new lines. (See comment above.) // Copies from the 'p' to 'q' pointer, where p can advance faster if // a newline-carriage return is hit. // // Wikipedia: // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 const char* p = buf; // the read head char* q = buf; // the write head const char CR = 0x0d; const char LF = 0x0a; buf[length] = 0; while( *p ) { assert( p < (buf+length) ); assert( q <= (buf+length) ); assert( q <= p ); if ( *p == CR ) { *q++ = LF; p++; if ( *p == LF ) { // check for CR+LF (and skip LF) p++; } } else { *q++ = *p++; } } assert( q <= (buf+length) ); *q = 0; Parse( buf, 0, encoding ); delete [] buf; return !Error(); } bool TiXmlDocument::SaveFile( const char * filename ) const { // The old c stuff lives on... FILE* fp = TiXmlFOpen( filename, "w" ); if ( fp ) { bool result = SaveFile( fp ); fclose( fp ); return result; } return false; } bool TiXmlDocument::SaveFile( FILE* fp ) const { if ( useMicrosoftBOM ) { const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; fputc( TIXML_UTF_LEAD_0, fp ); fputc( TIXML_UTF_LEAD_1, fp ); fputc( TIXML_UTF_LEAD_2, fp ); } Print( fp, 0 ); return (ferror(fp) == 0); } void TiXmlDocument::CopyTo( TiXmlDocument* target ) const { TiXmlNode::CopyTo( target ); target->error = error; target->errorId = errorId; target->errorDesc = errorDesc; target->tabsize = tabsize; target->errorLocation = errorLocation; target->useMicrosoftBOM = useMicrosoftBOM; TiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { target->LinkEndChild( node->Clone() ); } } TiXmlNode* TiXmlDocument::Clone() const { TiXmlDocument* clone = new TiXmlDocument(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlDocument::Print( FILE* cfile, int depth ) const { assert( cfile ); for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { node->Print( cfile, depth ); fprintf( cfile, "\n" ); } } bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const { if ( visitor->VisitEnter( *this ) ) { for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) break; } } return visitor->VisitExit( *this ); } const TiXmlAttribute* TiXmlAttribute::Next() const { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( next->value.empty() && next->name.empty() ) return 0; return next; } /* TiXmlAttribute* TiXmlAttribute::Next() { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( next->value.empty() && next->name.empty() ) return 0; return next; } */ const TiXmlAttribute* TiXmlAttribute::Previous() const { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( prev->value.empty() && prev->name.empty() ) return 0; return prev; } /* TiXmlAttribute* TiXmlAttribute::Previous() { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( prev->value.empty() && prev->name.empty() ) return 0; return prev; } */ void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const { TIXML_STRING n, v; EncodeString( name, &n ); EncodeString( value, &v ); if (value.find ('\"') == TIXML_STRING::npos) { if ( cfile ) { fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; } } else { if ( cfile ) { fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; } } } int TiXmlAttribute::QueryIntValue( int* ival ) const { if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } int TiXmlAttribute::QueryDoubleValue( double* dval ) const { if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } void TiXmlAttribute::SetIntValue( int _value ) { char buf [64]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); #else sprintf (buf, "%d", _value); #endif SetValue (buf); } void TiXmlAttribute::SetDoubleValue( double _value ) { char buf [256]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); #else sprintf (buf, "%g", _value); #endif SetValue (buf); } int TiXmlAttribute::IntValue() const { return atoi (value.c_str ()); } double TiXmlAttribute::DoubleValue() const { return atof (value.c_str ()); } TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { copy.CopyTo( this ); } TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) { Clear(); base.CopyTo( this ); return *this; } void TiXmlComment::Print( FILE* cfile, int depth ) const { assert( cfile ); for ( int i=0; i", value.c_str() ); } void TiXmlComment::CopyTo( TiXmlComment* target ) const { TiXmlNode::CopyTo( target ); } bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlComment::Clone() const { TiXmlComment* clone = new TiXmlComment(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlText::Print( FILE* cfile, int depth ) const { assert( cfile ); if ( cdata ) { int i; fprintf( cfile, "\n" ); for ( i=0; i\n", value.c_str() ); // unformatted output } else { TIXML_STRING buffer; EncodeString( value, &buffer ); fprintf( cfile, "%s", buffer.c_str() ); } } void TiXmlText::CopyTo( TiXmlText* target ) const { TiXmlNode::CopyTo( target ); target->cdata = cdata; } bool TiXmlText::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlText::Clone() const { TiXmlText* clone = 0; clone = new TiXmlText( "" ); if ( !clone ) return 0; CopyTo( clone ); return clone; } TiXmlDeclaration::TiXmlDeclaration( const char * _version, const char * _encoding, const char * _standalone ) : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { version = _version; encoding = _encoding; standalone = _standalone; } #ifdef TIXML_USE_STL TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ) : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { version = _version; encoding = _encoding; standalone = _standalone; } #endif TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { copy.CopyTo( this ); } TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) { Clear(); copy.CopyTo( this ); return *this; } void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const { if ( cfile ) fprintf( cfile, "" ); if ( str ) (*str) += "?>"; } void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const { TiXmlNode::CopyTo( target ); target->version = version; target->encoding = encoding; target->standalone = standalone; } bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlDeclaration::Clone() const { TiXmlDeclaration* clone = new TiXmlDeclaration(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlUnknown::Print( FILE* cfile, int depth ) const { for ( int i=0; i", value.c_str() ); } void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const { TiXmlNode::CopyTo( target ); } bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlUnknown::Clone() const { TiXmlUnknown* clone = new TiXmlUnknown(); if ( !clone ) return 0; CopyTo( clone ); return clone; } TiXmlAttributeSet::TiXmlAttributeSet() { sentinel.next = &sentinel; sentinel.prev = &sentinel; } TiXmlAttributeSet::~TiXmlAttributeSet() { assert( sentinel.next == &sentinel ); assert( sentinel.prev == &sentinel ); } void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) { #ifdef TIXML_USE_STL assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. #else assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. #endif addMe->next = &sentinel; addMe->prev = sentinel.prev; sentinel.prev->next = addMe; sentinel.prev = addMe; } void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) { TiXmlAttribute* node; for( node = sentinel.next; node != &sentinel; node = node->next ) { if ( node == removeMe ) { node->prev->next = node->next; node->next->prev = node->prev; node->next = 0; node->prev = 0; return; } } assert( 0 ); // we tried to remove a non-linked attribute. } #ifdef TIXML_USE_STL TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const { for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( node->name == name ) return node; } return 0; } TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) { TiXmlAttribute* attrib = Find( _name ); if ( !attrib ) { attrib = new TiXmlAttribute(); Add( attrib ); attrib->SetName( _name ); } return attrib; } #endif TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const { for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( strcmp( node->name.c_str(), name ) == 0 ) return node; } return 0; } TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) { TiXmlAttribute* attrib = Find( _name ); if ( !attrib ) { attrib = new TiXmlAttribute(); Add( attrib ); attrib->SetName( _name ); } return attrib; } #ifdef TIXML_USE_STL std::istream& operator>> (std::istream & in, TiXmlNode & base) { TIXML_STRING tag; tag.reserve( 8 * 1000 ); base.StreamIn( &in, &tag ); base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); return in; } #endif #ifdef TIXML_USE_STL std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) { TiXmlPrinter printer; printer.SetStreamPrinting(); base.Accept( &printer ); out << printer.Str(); return out; } std::string& operator<< (std::string& out, const TiXmlNode& base ) { TiXmlPrinter printer; printer.SetStreamPrinting(); base.Accept( &printer ); out.append( printer.Str() ); return out; } #endif TiXmlHandle TiXmlHandle::FirstChild() const { if ( node ) { TiXmlNode* child = node->FirstChild(); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const { if ( node ) { TiXmlNode* child = node->FirstChild( value ); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChildElement() const { if ( node ) { TiXmlElement* child = node->FirstChildElement(); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const { if ( node ) { TiXmlElement* child = node->FirstChildElement( value ); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::Child( int count ) const { if ( node ) { int i; TiXmlNode* child = node->FirstChild(); for ( i=0; child && iNextSibling(), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const { if ( node ) { int i; TiXmlNode* child = node->FirstChild( value ); for ( i=0; child && iNextSibling( value ), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::ChildElement( int count ) const { if ( node ) { int i; TiXmlElement* child = node->FirstChildElement(); for ( i=0; child && iNextSiblingElement(), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const { if ( node ) { int i; TiXmlElement* child = node->FirstChildElement( value ); for ( i=0; child && iNextSiblingElement( value ), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) { return true; } bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) { return true; } bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) { DoIndent(); buffer += "<"; buffer += element.Value(); for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) { buffer += " "; attrib->Print( 0, 0, &buffer ); } if ( !element.FirstChild() ) { buffer += " />"; DoLineBreak(); } else { buffer += ">"; if ( element.FirstChild()->ToText() && element.LastChild() == element.FirstChild() && element.FirstChild()->ToText()->CDATA() == false ) { simpleTextPrint = true; // no DoLineBreak()! } else { DoLineBreak(); } } ++depth; return true; } bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) { --depth; if ( !element.FirstChild() ) { // nothing. } else { if ( simpleTextPrint ) { simpleTextPrint = false; } else { DoIndent(); } buffer += ""; DoLineBreak(); } return true; } bool TiXmlPrinter::Visit( const TiXmlText& text ) { if ( text.CDATA() ) { DoIndent(); buffer += ""; DoLineBreak(); } else if ( simpleTextPrint ) { TIXML_STRING str; TiXmlBase::EncodeString( text.ValueTStr(), &str ); buffer += str; } else { DoIndent(); TIXML_STRING str; TiXmlBase::EncodeString( text.ValueTStr(), &str ); buffer += str; DoLineBreak(); } return true; } bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) { DoIndent(); declaration.Print( 0, 0, &buffer ); DoLineBreak(); return true; } bool TiXmlPrinter::Visit( const TiXmlComment& comment ) { DoIndent(); buffer += ""; DoLineBreak(); return true; } bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) { DoIndent(); buffer += "<"; buffer += unknown.Value(); buffer += ">"; DoLineBreak(); return true; } blobby-1.0/src/RenderManagerGP2X.cpp000644 001750 001750 00000026410 12313310252 022054 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "RenderManagerGP2X.h" /* includes */ #include "FileExceptions.h" /* implementation */ SDL_Surface* RenderManagerGP2X::colorSurface(SDL_Surface *surface, Color color) { SDL_Surface *newSurface = SDL_CreateRGBSurface( SDL_SWSURFACE | SDL_SRCALPHA | SDL_SRCCOLORKEY, surface->w, surface->h, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000); SDL_BlitSurface(surface, 0, newSurface, 0); SDL_SetAlpha(newSurface, SDL_SRCALPHA, surface->format->alpha); SDL_SetColorKey(newSurface, SDL_SRCCOLORKEY, SDL_MapRGB(newSurface->format, 0, 0, 0)); SDL_LockSurface(newSurface); for (int y = 0; y < surface->h; ++y) for (int x = 0; x < surface->w; ++x) { SDL_Color* pixel = &(((SDL_Color*)newSurface->pixels) [y * newSurface->w +x]); int rr = (int(pixel->r) * int(color.r)) >> 8; int rg = (int(pixel->g) * int(color.g)) >> 8; int rb = (int(pixel->b) * int(color.b)) >> 8; int fak = int(pixel->r) * 5 - 4 * 256 - 138; if (fak > 0) { rr += fak; rg += fak; rb += fak; } pixel->r = rr < 255 ? rr : 255; pixel->g = rg < 255 ? rg : 255; pixel->b = rb < 255 ? rb : 255; } SDL_UnlockSurface(newSurface); SDL_Surface *convSurface = SDL_DisplayFormat(newSurface); SDL_FreeSurface(newSurface); return convSurface; } RenderManagerGP2X::RenderManagerGP2X() : RenderManager() { } RenderManager* RenderManager::createRenderManagerGP2X() { return new RenderManagerGP2X(); } void RenderManagerGP2X::init(int xResolution, int yResolution, bool fullscreen) { Uint32 screenFlags = SDL_HWSURFACE | SDL_HWACCEL | SDL_DOUBLEBUF; // screenFlags |= SDL_FULLSCREEN; mScreen = SDL_SetVideoMode(320, 240, 0, screenFlags); SDL_ShowCursor(0); SDL_Surface* tempBackground = loadSurface("backgrounds/strand2.bmp"); mBackground = SDL_DisplayFormat(tempBackground); SDL_FreeSurface(tempBackground); for (int i = 1; i <= 16; ++i) { char filename[64]; sprintf(filename, "gf2x/ball%02d.bmp", i); SDL_Surface* ballImage = loadSurface(filename); SDL_SetColorKey(ballImage, SDL_SRCCOLORKEY, SDL_MapRGB(ballImage->format, 0, 0, 0)); SDL_Surface *convertedBallImage = SDL_DisplayFormat(ballImage); SDL_FreeSurface(ballImage); mBall.push_back(convertedBallImage); } SDL_Surface *tempBallShadow = loadSurface("gf2x/schball.bmp"); SDL_SetColorKey(tempBallShadow, SDL_SRCCOLORKEY, SDL_MapRGB(tempBallShadow->format, 0, 0, 0)); SDL_SetAlpha(tempBallShadow, SDL_SRCALPHA, 127); mBallShadow = SDL_DisplayFormat(tempBallShadow); SDL_FreeSurface(tempBallShadow); for (int i = 1; i <= 5; ++i) { char filename[64]; sprintf(filename, "gf2x/blobbym%d.bmp", i); SDL_Surface* blobImage = loadSurface(filename); mStandardBlob.push_back(blobImage); mLeftBlob.push_back(colorSurface(blobImage, Color(255, 0, 0))); mRightBlob.push_back(colorSurface(blobImage, Color(0, 255, 0))); sprintf(filename, "gf2x/sch1%d.bmp", i); SDL_Surface* blobShadow = loadSurface(filename); SDL_SetColorKey(blobShadow, SDL_SRCCOLORKEY, SDL_MapRGB(blobShadow->format, 0, 0, 0)); SDL_SetAlpha(blobShadow, SDL_SRCALPHA, 127); mStandardBlobShadow.push_back(blobShadow); mLeftBlobShadow.push_back( colorSurface(blobShadow, Color(255, 0, 0))); mRightBlobShadow.push_back( colorSurface(blobShadow, Color(0, 255, 0))); } for (int i = 0; i <= 54; ++i) { char filename[64], filename2[64]; sprintf(filename, "gf2x/font%02d.bmp", i); sprintf(filename2, "gf2x/font_small/font%02d.bmp", i); SDL_Surface *tempFont = loadSurface(filename); SDL_Surface *tempFont2 = loadSurface(filename2); SDL_SetColorKey(tempFont, SDL_SRCCOLORKEY, SDL_MapRGB(tempFont->format, 0, 0, 0)); SDL_SetColorKey(tempFont2, SDL_SRCCOLORKEY, SDL_MapRGB(tempFont2->format, 0, 0, 0)); SDL_Surface *newFont = SDL_DisplayFormat(tempFont); SDL_Surface *newFont2 = SDL_DisplayFormat(tempFont2); SDL_FreeSurface(tempFont); SDL_FreeSurface(tempFont2); mFont.push_back(newFont); mHighlightFont.push_back(highlightSurface(newFont, 60)); mSmallFont.push_back(newFont2); mHighlightSmallFont.push_back(highlightSurface(newFont2, 60)); } } void RenderManagerGP2X::deinit() { SDL_FreeSurface(mBackground); SDL_FreeSurface(mBallShadow); for (unsigned int i = 0; i < mBall.size(); ++i) SDL_FreeSurface(mBall[i]); for (unsigned int i = 0; i < mStandardBlob.size(); ++i) { SDL_FreeSurface(mStandardBlob[i]); SDL_FreeSurface(mStandardBlobShadow[i]); SDL_FreeSurface(mLeftBlob[i]); SDL_FreeSurface(mLeftBlobShadow[i]); SDL_FreeSurface(mRightBlob[i]); SDL_FreeSurface(mRightBlobShadow[i]); } for (unsigned int i = 0; i < mFont.size(); ++i) { SDL_FreeSurface(mFont[i]); SDL_FreeSurface(mHighlightFont[i]); SDL_FreeSurface(mSmallFont[i]); SDL_FreeSurface(mHighlightSmallFont[i]); } } void RenderManagerGP2X::draw() { if (!mDrawGame) return; SDL_BlitSurface(mBackground, 0, mScreen, 0); int animationState; SDL_Rect position; // Ball marker Uint8 markerColor = SDL_GetTicks() % 1000 >= 500 ? 255 : 0; position.y = 5; position.x = lround(mBallPosition.x - 2.5); position.w = 5; position.h = 5; SDL_FillRect(mScreen, &position, SDL_MapRGB(mScreen->format, markerColor, markerColor, markerColor)); // Ball Shadow position.x = lround(mBallPosition.x) + (200 - lround(mBallPosition.y)) / 4 - 19; position.y = 200 - (200 - lround(mBallPosition.y)) / 16 - 5; SDL_BlitSurface(mBallShadow, 0, mScreen, &position); // Left blob shadow position.x = lround(mLeftBlobPosition.x) + (200 - lround(mLeftBlobPosition.y)) / 4 - 19; position.y = 200 - (200 - lround(mLeftBlobPosition.y)) / 16 - 10; animationState = int(mLeftBlobAnimationState) % 5; SDL_BlitSurface(mLeftBlobShadow[animationState], 0, mScreen, &position); // Right blob shadow position.x = lround(mRightBlobPosition.x) + (200 - lround(mRightBlobPosition.y)) / 4 - 19; position.y = 200 - (200 - lround(mRightBlobPosition.y)) / 16 - 10; animationState = int(mRightBlobAnimationState) % 5; SDL_BlitSurface(mRightBlobShadow[animationState], 0, mScreen, &position); // Restore the rod position.x = 160 - 3; position.y = 120; SDL_Rect rodPosition; rodPosition.x = 160 - 3; rodPosition.y = 120; rodPosition.w = 7; rodPosition.h = 120; SDL_BlitSurface(mBackground, &rodPosition, mScreen, &position); // Drawing the Ball position.x = lround(mBallPosition.x) - 13; position.y = lround(mBallPosition.y) - 13; animationState = int(mBallRotation / M_PI / 2 * 16) % 16; SDL_BlitSurface(mBall[animationState], 0, mScreen, &position); // Drawing left blob position.x = lround(mLeftBlobPosition.x) - 15; position.y = lround(mLeftBlobPosition.y) - 18; animationState = int(mLeftBlobAnimationState) % 5; SDL_BlitSurface(mLeftBlob[animationState], 0, mScreen, &position); // Drawing right blob position.x = lround(mRightBlobPosition.x) - 15; position.y = lround(mRightBlobPosition.y) - 18; animationState = int(mRightBlobAnimationState) % 5; SDL_BlitSurface(mRightBlob[animationState], 0, mScreen, &position); // Drawing the score char textBuffer[8]; snprintf(textBuffer, 8, mLeftPlayerWarning ? "%02d!" : "%02d", mLeftPlayerScore); drawText(textBuffer, Vector2(20, 10), false); snprintf(textBuffer, 8, mRightPlayerWarning ? "%02d!" : "%02d", mRightPlayerScore); drawText(textBuffer, Vector2(320 - 65, 10), false); // Drawing the names drawText(mLeftPlayerName, Vector2(12, 550), false); drawText(mRightPlayerName, Vector2(788-(24*mRightPlayerName.length()), 550), false); // Drawing the clock drawText(mTime, Vector2(400 - mTime.length()*12, 24), false); } bool RenderManagerGP2X::setBackground(const std::string& filename) { try { SDL_Surface *tempBackground = loadSurface(filename); mBackground = SDL_DisplayFormat(tempBackground); SDL_FreeSurface(tempBackground); } catch (FileLoadException) { return false; } return true; } void RenderManagerGP2X::setBlobColor(int player, Color color) { std::vector *handledBlob = 0; std::vector *handledBlobShadow = 0; if (player == LEFT_PLAYER) { handledBlob = &mLeftBlob; handledBlobShadow = &mLeftBlobShadow; } if (player == RIGHT_PLAYER) { handledBlob = &mRightBlob; handledBlobShadow = &mRightBlobShadow; } for (int i = 0; i < 5; ++i) { SDL_FreeSurface((*handledBlob)[i]); SDL_FreeSurface((*handledBlobShadow)[i]); } handledBlob->clear(); handledBlobShadow->clear(); for (int i = 0; i < 5; ++i) { SDL_Surface *tempBlob = colorSurface(mStandardBlob[i], color); handledBlob->push_back( SDL_DisplayFormat(tempBlob)); SDL_FreeSurface(tempBlob); SDL_Surface *tempShadow = colorSurface( mStandardBlobShadow[i], color); handledBlobShadow->push_back( SDL_DisplayFormat(tempShadow)); SDL_FreeSurface(tempShadow); } } void RenderManagerGP2X::setBall(const Vector2& position, float rotation) { mBallPosition = position * 0.4; mBallRotation = rotation; } void RenderManagerGP2X::setBlob(int player, const Vector2& position, float animationState) { if (player == LEFT_PLAYER) { mLeftBlobPosition = position * 0.4; mLeftBlobAnimationState = animationState; } if (player == RIGHT_PLAYER) { mRightBlobPosition = position * 0.4; mRightBlobAnimationState = animationState; } } void RenderManagerGP2X::setScore(int leftScore, int rightScore, bool leftWarning, bool rightWarning) { mLeftPlayerScore = leftScore; mRightPlayerScore = rightScore; mLeftPlayerWarning = leftWarning; mRightPlayerWarning = rightWarning; } void RenderManagerGP2X::setTime(const std::string& t) { mTime = t; } void RenderManagerGP2X::drawText(const std::string& text, Vector2 position, unsigned int flags) { int FontSize = (flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL); int length = 0; std::string string = text; int index = getNextFontIndex(string); while (index != -1) { if (flags & TF_OBFUSCATE) index = FONT_INDEX_ASTERISK; length += FontSize; SDL_Rect charPosition; charPosition.x = lround(position.x) + length - FontSize; charPosition.y = lround(position.y); if (flags & TF_SMALL_FONT) if (flags & TF_HIGHLIGHT) SDL_BlitSurface( mHighlightSmallFont[index], 0, mScreen, &charPosition ); else SDL_BlitSurface( mSmallFont[index], 0, mScreen, &charPosition ); else if (flags & TF_HIGHLIGHT) SDL_BlitSurface( mHighlightFont[index], 0, mScreen, &charPosition ); else SDL_BlitSurface( mFont[index], 0, mScreen, &charPosition ); index = getNextFontIndex(string); } } void RenderManagerGP2X::refresh() { SDL_Flip(mScreen); } blobby-1.0/src/InputManager.cpp000644 001750 001750 00000022503 12313310251 021271 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "InputManager.h" /* includes */ #include #include #include #include "UserConfig.h" #include "RenderManager.h" #include "InputDevice.h" #include "input_device/JoystickPool.h" /* implementation */ InputManager* InputManager::mSingleton = 0; const unsigned int DOUBLE_CLICK_TIME = 200; InputManager::InputManager() { SDL_InitSubSystem(SDL_INIT_JOYSTICK); SDL_JoystickEventState(SDL_ENABLE); JoystickPool::getSingleton().probeJoysticks(); assert (mSingleton == 0); mSingleton = this; mRunning = true; mWindowFocus = true; /// \todo init properly? mLastTextKey = ""; mLastClickTime = 0; } InputManager::~InputManager() { JoystickPool::getSingleton().closeJoysticks(); } InputDevice* InputManager::beginGame(PlayerSide side) const { SDL_Window* window = RenderManager::getSingleton().getWindow(); // Move Mouse to default position SDL_WarpMouseInWindow(window, 400, 300); std::string prefix; if (side == LEFT_PLAYER) prefix = "left_blobby_"; if (side == RIGHT_PLAYER) prefix = "right_blobby_"; UserConfig config; /// \todo we need only read only access here! config.loadFile("inputconfig.xml"); // determine which device is to be used std::string device = config.getString(prefix + "device"); // load config for mouse if (device == "mouse") { int jumpbutton = config.getInteger(prefix + "mouse_jumpbutton"); return createMouseInput(side, jumpbutton); } // load config for keyboard else if (device == "keyboard") { SDL_Keycode lkey = SDL_GetKeyFromName((config.getString(prefix + "keyboard_left")).c_str()); SDL_Keycode rkey = SDL_GetKeyFromName((config.getString(prefix + "keyboard_right")).c_str()); SDL_Keycode jkey = SDL_GetKeyFromName((config.getString(prefix + "keyboard_jump")).c_str()); return createKeyboardInput(lkey, rkey, jkey); } // load config for joystick else if (device == "joystick") { JoystickAction laction(config.getString(prefix + "joystick_left")); JoystickAction raction(config.getString(prefix + "joystick_right")); JoystickAction jaction(config.getString(prefix + "joystick_jump")); return createJoystrickInput(laction, raction, jaction); } // load config for touch else if (device == "touch") { return createTouchInput(side, config.getInteger("blobby_touch_type")); } else std::cerr << "Error: unknown input device: " << device << std::endl; return 0; } InputManager* InputManager::getSingleton() { assert(mSingleton); return mSingleton; } InputManager* InputManager::createInputManager() { return new InputManager(); } void InputManager::updateInput() { mUp = false; mDown = false; mLeft = false; mRight = false; mSelect = false; mExit = false; mClick = false; mMouseWheelUp = false; mMouseWheelDown = false; mUnclick = false; mLastMouseButton = -1; mLastActionKey = SDLK_UNKNOWN; mLastTextKey = ""; mLastJoyAction = ""; // Init GUI Events for buffered Input SDL_PumpEvents(); SDL_Event event; SDL_JoystickUpdate(); // process all SDL events while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: mRunning = false; break; case SDL_KEYDOWN: mLastActionKey = event.key.keysym.sym; switch (event.key.keysym.sym) { case SDLK_UP: mUp = true; break; case SDLK_DOWN: mDown = true; break; case SDLK_LEFT: mLeft = true; break; case SDLK_RIGHT: mRight = true; break; case SDLK_RETURN: mLastTextKey = "return"; case SDLK_SPACE: mSelect = true; break; case SDLK_ESCAPE: case SDLK_AC_BACK: mExit = true; break; case SDLK_BACKSPACE: mLastTextKey = "backspace"; break; case SDLK_DELETE: mLastTextKey = "del"; break; default: break; } break; case SDL_TEXTINPUT: mLastTextKey = std::string(event.text.text); break; // Workarround because SDL has a bug in Version 2.0.1, // so that we can't use mouse here #ifndef __ANDROID__ #ifdef __APPLE__ #if MAC_OS_X case SDL_MOUSEBUTTONDOWN: mLastMouseButton = event.button.button; switch (event.button.button) { case SDL_BUTTON_LEFT: mClick = true; if(SDL_GetTicks() - mLastClickTime < DOUBLE_CLICK_TIME ) { mDoubleClick = true; } mLastClickTime = SDL_GetTicks(); break; } break; #else case SDL_FINGERDOWN: mClick = true; if(SDL_GetTicks() - mLastClickTime < DOUBLE_CLICK_TIME ) { mDoubleClick = true; } mLastClickTime = SDL_GetTicks(); break; #endif #else case SDL_MOUSEBUTTONDOWN: mLastMouseButton = event.button.button; switch (event.button.button) { case SDL_BUTTON_LEFT: mClick = true; if(SDL_GetTicks() - mLastClickTime < DOUBLE_CLICK_TIME ) { mDoubleClick = true; } mLastClickTime = SDL_GetTicks(); break; } break; #endif #else case SDL_FINGERDOWN: mClick = true; if(SDL_GetTicks() - mLastClickTime < DOUBLE_CLICK_TIME ) { mDoubleClick = true; } mLastClickTime = SDL_GetTicks(); break; #endif case SDL_MOUSEWHEEL: if (event.wheel.y < 0) { mMouseWheelDown = true; } else { mMouseWheelUp = true; } break; case SDL_MOUSEBUTTONUP: mUnclick = true; break; case SDL_JOYBUTTONDOWN: { JoystickAction joyAction(event.jbutton.which, JoystickAction::BUTTON, event.jbutton.button); mLastJoyAction = joyAction.toString(); break; } case SDL_JOYAXISMOTION: { if (abs(event.jaxis.value) > 10000) { int axis = 0; if (event.jaxis.value > 0) axis = event.jaxis.axis + 1; if (event.jaxis.value < 0) axis = -(event.jaxis.axis + 1); JoystickAction joyAction(event.jaxis.which, JoystickAction::AXIS, axis); mLastJoyAction = joyAction.toString(); } break; } case SDL_WINDOWEVENT: switch (event.window.event) { case SDL_WINDOWEVENT_FOCUS_LOST: mWindowFocus = false; break; case SDL_WINDOWEVENT_FOCUS_GAINED: mWindowFocus = true; break; } /* This handles the special buttons on the GP2X, this will * have to be renewed with the next GP2X release. /// even if we reintroduce this behaviour, we should move this code /// elsewhere... /// this is input processing not input retrieving/managing! #if defined(__arm__) && defined(linux) case SDL_JOYBUTTONDOWN: switch (event.jbutton.button) { case 17: volume -= 0.15; break; case 16: volume += 0.15; break; } SoundManager::getSingleton().setVolume(volume); break; #else #endif */ } } } // GUI-Methods bool InputManager::up() const { return mUp; } bool InputManager::down() const { return mDown; } bool InputManager::left() const { return mLeft; } bool InputManager::right() const { return mRight; } bool InputManager::select() const { return mSelect; } bool InputManager::exit() const { return mExit; } Vector2 InputManager::position() { // Workarround because SDL has a bug in Version 2.0.1, // so that we can't use mouse here #if !defined(__ANDROID__) && !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE SDL_GetMouseState(&mMouseX,&mMouseY); #else SDL_TouchID device = SDL_GetTouchDevice(0); for (int i = 0; i < SDL_GetNumTouchFingers(device); i++) { SDL_Finger *finger = SDL_GetTouchFinger(device, i); if (finger == NULL) continue; mMouseX = finger->x * 800; mMouseY = finger->y * 600; } #endif return Vector2(mMouseX,mMouseY); } bool InputManager::click() const { return mClick; } bool InputManager::doubleClick() const { return mDoubleClick; } bool InputManager::mouseWheelUp() const { return mMouseWheelUp; } bool InputManager::mouseWheelDown() const { return mMouseWheelDown; } bool InputManager::unclick() const { return mUnclick; } bool InputManager::windowFocus() const { return mWindowFocus; } bool InputManager::running() const { return mRunning; } void InputManager::setEndBlobby() { mRunning = false; } std::string InputManager::getLastTextKey() { if (mLastTextKey != "") { return mLastTextKey; } else return ""; } std::string InputManager::getLastActionKey() { return SDL_GetKeyName(mLastActionKey); } std::string InputManager::getLastJoyAction() const { return mLastJoyAction; } blobby-1.0/data/gfx/schild.bmp000644 001750 001750 00001437416 12313310254 021070 0ustar00danielknobedanielknobe000000 000000 BM?6(N  dnXK],6Mf|LVt,duTa4>T'%% ,! !!# !!!!  ! , "! ,  $!  !! ! ,#!! !#!.%( '# ! .% ,!!! ! ," , .# " !   ,#!! $ !'.'##%! ! %  ! ! (   ! "  , " ! !#!,'%(  '# ! !% !!! ,    " ! % ! . ! !% ,, !!'% #., ! ! # !!!!,,, " ! !,%, .  ! !,,, !!!'#( .!  ,, # !!!,!,, !, '".! ,,,$, . ,#! !  !!'%  ,!#.!!!,   !!, "!  , !$   !,%!!! !!'%  .!!  ,!#.!!!!  !! ". , '"  , %! !!, ! '%(#  .,!  !!,! !!, !$ ,$!,  !#  ! !! '%# ,  ! ,%! !!!!   ". ,,, ! $   ! #!,! , !! ''%(  #   #!,!,(   ! " ! !#  $!, , !!!''% , %, , !! !!! !!!    '"!! # !" , ! % ! ! '%( #  !, ! !  , " ! # . "!  !#,! !! ''#,  ,  ,!!!! % !  , !" !,  #.. $!  !% ,  ! !! %# ,!, !, !,!!   , !" .!!.."  ,% !, !!!'%(.#  ! # ! !!!  , !'"  # "!   , !%  ! ,!'%#  %  ,,   ,! (!   "# ,!,     !.% ,! !!!' #! ! ! !!! , ,, "!,!,. "    .# !  !!''#( .#!    !!,  !"! ,     # ,!  !! !'/'% %# !, !    !!(#!  '",!    *! ,! %   ! ,,''%##! , ! ( !! !! #!  ", ,  "   , %  !(! '.'#. !,,  ,# ,!!, ! " !! "!  % !, ''%   , !%,!,!  , !" !   %  !! ! !''%( .(,    !,!!! ( ,  !'", . !  "!  !   !#! !!''#  # , ! # ! !!! . ,!" ! . "   ! %!  !!!''% % ,,,  ! !!! !,!, ,$  !'"!   ! !, !'%% %#   ,!# , !! !    "., !", !, !,% ! ,! ,!''%( ## ,,!!. !,!,, !$.  ! '"!  ,!! %  !.!#! !''%  , !!! !,!,, !,! ! ".,  . ", !! ,,!% ! # !!'%# # ,!!!  !!!,! ! , $  ! !," . ! ! % !#   '%(#!   !! , ,!!  %! !  "  " ! %  !!!,!'%#  !,!, # !,!,."%, ! ,, $    '"  ,! %  %, ''$(!  , , !!#  ,,!  ! "  ,  "!  , !% ,,! !! '% . .( ,,,!  !,! , ! ! $ . . "! ,, ! %   !#! .'#(! # !  .!! ,! , , !, $,#  " .  !# !  # !'%,!% ,, !! # !! , !  . , "  !  % ! # !!''%(##  ! %. !!# ,  %. ! . "!, !!!%   , !'%( . # ,,!! !,,,!$# ! ,, . !# .$.  !,.!!#  #, !''#! % !,! # !,!!!$. , , $..#  %. ,!! %.## ! '%(  %# ,,! !#. , !!. , ! ,! $,  , "!, #.!, ,#, # ,! ''% ##!  !!   !    ! ! ".  ",  !,# % !!'%(.% , !!% ,!,! !! ,, $. .!." .! !!#  # '%!. ,, !! #   ,.#, , ,    . $ !!, ,#  ! ''(#. ##!,! !# , !,.##  , .# .* ! !!!%!# ! ''#% '%# ,!!# !!!!.#! , , ,   # ." #!, !,#  !'' (# ## ,! .!# !,! (  , , .  $, .!!! ! !% ,! .! ''#.! # ! ! !,  , , . ! ,  , .!!! #,  !!  %(##! ! ! !!. ! ! !!  ! ",!!  !# ! #!'%! '%,, ! !  !.%#! . , , # .,   ,, !#!! , .''( %% ! !, % !! ! % ! !! % , ., %,!  !, ,#!!!! ! !'#  !, !,!! #,!,  ,  ! %,! %!! ! ,#,!  !!'''%  % ,  !!! !!!! !.!    ., #,!  ! !!!  ! '''#!! !.! !,! ! . !. ! . .!!   !!.!!!!''''+'! !.'' .  !!!..  ! . !! .!!/ . ! . !'  +''/'.'/'''''''''''''''''''/'''!''/''/ '' !.!'  '...'!'.' ''''. '!''.','./'///'/'//////////////'/////'//////////.+//'//++/////'/''''/+''//. / ' '''''!''''''''''.''.'''''''''''''''/+.///+//////////////////++/////////////./'/'//'///////////////'////////'/////'////////''//.'''''.''/''/'/''''/'/'''''/'/'/'''////////'+/////'///'+/////////////''/'//////''/'////////'//////'/////'''//''/'//'////////'////////'////////'/////'///'//////+//'/////////////////+/++////////'///////////'////'///////////'/'/'+//////////'/////+/''////////////////////////+'///////////////////'///////////////////////////////////////+//////////////////////////'/////////////////////+//+////////////////////'//////////'///////////////////////////'//////////////////'/////////////++///+/////+///+/////////+++/////////////////+///////////////////+/////+//+'/////////////'/////////////'///////////////////////////'////////+///+////////////////////+///////////////+'/////////////////////////////'////////////'+//////////''//'''////''//'/'//'///'''/''''////'/'/''//'''///////////////////////////////////////////////////!                   ! """"""""""""""'''''//'/////////////////'////'/'/'//''////'////++++++++++++++++++''''///////'''''/////'''/'!!     , ! ! ! ! , ,,,                              '   '..........''......       '  ''''''''''''''''''''''''''''''''''''//////////////+''/'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''.'.''''''''''''''''''''''''''...'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''/'///'''''''''''/''/''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''..'''/...''''.  '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''...'''''''''''.'''''''.''''''''''''''''''''''''''''''''''''''''''''''''''''...''''.'''''''''''''''''''''''''''''''''''''''''' .....      !!  '/ '.      !     !  !! !!!! ! ''''.  . .'.       #      !      !                           !     ! ##          !        ")"""$#$$"""$""$"""""$"""$""$""""""""""""""""""#"#$""""""""""""""""""""" ### ##$$"""""""""""""""""""""""""  $""""""##"""""""    #  #$#      ##$$       ####                      ## ### ####   !     !            /$      #   #  ##!! !        !       #!   $    ###$ # ##!  ##       #       !,        .            !        !  #                ###  '%!  !!!! !   , !  !   !!!  !  !!,!  ! !   !   ! ! ! ! ! !      !!!! !    !!!!!, !! ,      ,! !, !! !!,!!! !, !!!! ,!!,!, ,!   !!!!!!!! , ! ! !!! !,,! !!  !   .. ..         , . ... ...  ! ... .   , ,! .    '.   !!, !  ..... .   !!!!!! !!,!!, ! !! !  ,' % .  !  , ,!,,,,,, ,,,   , ,!, ,   ,     ,,,!,, ..     ,,, .,..,,,,,!!!!,, ,,,,.....  ............................... ........... ..... . .''......................    .. ... ''%$#,,!!!!,!!!!  !!!      !!!!!!!,!!!!! , !!!!    !!!       ! ,!!!,!!!!! !!!!!!!!!!!!,,, ,.,,,!!!,!!!!!!!!!!!!!,,,!!!,!,!!!!,,,!!,!!! !!!!!!!!  , ,,,,,, ,!!,,!,,!,,!!!,,,!. !,!!!! !!!   ! ,! ,!!! ,, !!!!!!!!!! ! !!!    !  ,!! ,  ,!!  ! !!  !..  !,,! !! ! ,  !!!!!!! ,,! !!!   ! , !!  , ,!   , , ! .%"# ##  # ##$$$$$### ### ######### # ## #######  #### ##   ########$####  ## ###########   ######  #   # #  ##### !       ######   !             #   !! ######### ##       ! !    #### #$""$     #%$$# #  # # #######  ##    # ##$#  ##$## # #####   #####   ## ! #  ##   #       ###        #   !            !   ####         !!! ,!   ### +(,!!!!,, !,,!!,!!  !,!!!, , ! ,!!!!!!!!!!!!!!!!!!,,!!!!!!!,,! ! !!,!!,, ,!!!!!!!!!!!!!,,! !, ! ! !!,,,, !!!!!!!!!!!!,,,,!,!!,!! ,!!!!!,!!!,!! ,,!,,!!!! !!!,! !!!,!!!  !,!!!,!!!, ! ! !!! !!!,, !! .  !!, ,!!! ! ! , ,!,,!, ,, !!!!    !!   , !!, ! ! !!!!!!!,,   !  ! .. !! !! .! . !  ! ! .  !  ,! ,,!! ! , !, !!!!!!!! , !!!!!!!!,!!! ,! !  !    !!!!!!!! !!!!! ...!, , ,,...    , ,,, , ,,    ,  .  , .......  ,,,, ., . , ,,,,,,, ,.... ,,,   .......... ., ..    .......... . ............................................ ............. ..........'..................... ...............  .. .  ../ !!!!!!!!!!!,,,,,!!!,,,!!,!!!!!!!!,!!!!!!!!!!!!!!!!!! !!,!!!!!!!!!,!,,!!,!!,,!! ,!!,,,!!!!!!!!!!,!!!!,, ,!!,,!!,!!!!!!!!!,!   ,,!,!,!,!!,!!,,,!!!,!,,!,,!,,,!, ,!,!!,.,,,!,!!!,!!!!!,, ,!, !!,!,,, ,!,!!!!!!!!, , !! . !,,!,!!!!!!!!,!!,!!!!,!!,   ,   !  ! !,, , ! , ,   ,,!!  .! !!!   ,!  !! !! . ... !   , , !,! !,, , , , , ,   .. !  !,....    ,   '!"**$################# $#"#########%%$#### !############%$# ###!! #####$$### !!### #### #!  ##########    #### !   #########  #      ######          !      !# #    #!   ! !  ####   !! !    ! #  !!!     +"""$########  #####$$$##$$$## # !### #######$  ### $##    ### #   #########   ! ####       ###      ##    #   # ####       #        #   ########             !    !"!,,!!,,,!, !!!, ,!!!!!!!!!!!,!,, ,,, ,!!! !,, , ,, ,,, , !!!!, ,,,!, ,,, ! ,,,,,,!!!!,! !,,! !!,  ! ,,,!!! ,, ,!,!!!!,,,, ,!,!,!!,, , !!,,,,! ! ,, ,!!!!!,!, , ,,!!,!!!,!!,, ,!!!!!!,!,!!!!!, ,!,,!!,,,,!    !, !,,!!!,, ,,,,!!!!,!!! !!,,,,!!!!, , ,,,,   !, ! ,!! ,,,,, , ! ! ,  , ! !!!,!!  ,  . !!!  ,   , !   ,  !!! ! !! ...   !! ,   !! ! !, ,,!(,,!   , ,! ,!  !    ,  !   .   ''+' ,    ,  , ,   .  ,, . , , , ,  .    ,,, , .. ,  ,     ,. ,, , ,,,,   , ,.  ,, , ,     . ...   ,      ,, ...... .....  ................. ................ ......   ...............'......'....... . ''' (!.. ...................... ''!!     !!!! !!!!!!!, !,      !!  !!!,!! !  !!!!!,!,,      ! ,,,!     !,,!!!!!!     !! ,, (!,!,!!!! !!!,! ,! !,   !  !!!!,, !!!!  ! , ! !!  .  ! ! ,   ! !!! !   ,  , !! /'( !!!! ,,! , !  !! !  , , , ,.,$%####%%$$$#%## ##########%###$%$$$$$### $##$$  ####$$## # ########## ## ###$### ##$$$##  ##### ''"$# !  !# ####  # ! #   #####    #  ########### # !#    ###       ''(#  ###########  #       '#%# #    ,!!!  ############    ##  ,!       !    ##     ########           ! !  '(%%  ! ! !       ! !! !! ! !!!!      .!  ,, !           !!   # ,!      !    !!!  !!!   '' !       ! !!!! ,!  . (%, ,,                 .  !   ,,, ,,    ,,!, , ,      ,, , ,,      ,, ,   . , , ,   .., ,    ,,,.,. . .    ,,  ,    .    ..  .........'''!,   .   ........ ....................  ......  ...................................'( ' .  .. ..............'.......... /%,,,,,,,,,,,,,,,,,,,,!,,!!,,!,,,,!,,!!!,,,!,,,,,,,,,,!,,,,,,,,,, ,!, ,!, ,,,,  ,,  ,,,,,, , , ,!!,,,,, ,,,,,,,,!   ,,,,!, !,,,!,!!!!!!!!!,,!!!!,,,,,!!,,!,,, ,,,,!,,,,,,,!,..,.. ,!,,,,,,,,!!,, !!!,!, ,,,,!!,,,, , ,,, , ,,, ,,,  ,' ''!,,, ,!   . , ,!,,  ...  ,      ,  .  , ,,, ,       ,, .......... ,.... ''( '!'.........'.''  .. . '''/-$## ###%%######################!!! !     #######      !!!!!     ####!,    !, !# , !!       !             !. '      ! !! !!   !     !!!!   !!,            ! ! ''.  '''''''! '''' ' '      %"$"# $$$##!  ###########  !!###   ## ##########  !!!,  !..!. !!!!  ..' !!!,  !!!!!!! !. !! !!!!!...! !!!!  ! !! !!!! ! .''''''/!! !!!! !!!!!! ,! ..'  ! ! ! ! . !!''''' .    ''.''''.'.'. ! ! ! ! , !!   !   . ! !'''///////''/////'////''////////////''''''''//'''    ! "' % . ,, ,,,...    ,,  ...'.''''''''''''''''''''''''''''''''''''''.''''''''/''''''''''''''''''///////////////////////////////////////////////////////++'!*****************/' .   .. ''(, ,,  ,,  ,, .'''''////////////////////////////////////////////////////////////////////////////////////   * **********************************************************************************************'....'' (% ! ##,,#!'' (                     ** **************************************************************    '$%%!! # !#                *******************************/        %%, #,!!,  ,!,  ****************************************************************************************************************  /!!. , . ,, ,,, ,************************************************************************************'!%%%#%%#$%%%#%#%%#%#%/   !!,!!!,!,!           *********************************************************************************/. ! , #$"#### !!, !*          *****************************************************************************************'       '%" ####  !,!!!!!! *                      *****************************************************************************/.!     . /%,%%%%%%%%%%%%%%%%%%%%%%%%              ********************************************************************************************'......... '''%$.    *                 ***************************************************************************************'  !! !!! ''$$       *                  **********************************************************************************************/   !    %$    ! !               ***************************************************************************************************'  ,!!,!, !!,'/%, ,,,, ,   ,, ,,                 *******************************************************************************************..  .. .. '' !$*"#######,                *******************************************************************************************'   !  **$#                          **********************************************************************************'      +!,!,!,!!!!,,!,, ,,,,,,!,,,*                   ******************************************************************************'     ''.,!!!!!!!!,!!!,,,,,,!,,!,,!,                       *************************************************************************/', .  .' '$$###############*                      *************************************************************************** ! !!    '$" #####                               *******************************************************************       /(% , , ,  ,, !,,!,,!! ,!                         ******************************************************************************'. !! ,   '%..,,.                                     **************************************************************************************'..... ,''% !,!!!! !!,  !                        ********************************************************************* /'!!!! !   ! ,%% ##### #### *                                 *******************************************************************************/   !     #%$% ! ,  , #, ! !                               *****************************************************************************/' ! ! .! .  ! !  ,,, ... , ..   *                          ****************************************************************'...............''''##!,,!!## ,#%!!!                                    *********************************************************************** !!!!! .!%$#  #####                                 ************************************************************ ###   /%- ,,  !  #!*                                  ********************************************************************    %..,,  ......                                      **********************************************************....... ''(,,,,,, ,,,,  ,! !!!..                                *************************************************************** !#$$$$%$$$*) '%$%######                                           *************************************************************$""$$$*#   $$ #'""$######                                             *****************************************************'%$$"""$#%%%# .!!  $$$#   ! !                                        *****************************************************************'    !/%- ......  . *                                 **********************************************************'. ......'!$$$$$$$"$$$$$$$$$$$$$$""%                                           ************************************************************************** .   ! .'/#$. ####### *                                        ******************************************  !  #!!,!!,,!!                                           ***************************************************************'     '## !     *                                         ****************************************************************  !! !!! ! '' '(. ,   .                                                *************************************************************'.. .....',%! !!!!!!!.!! ,!,  *                                            ******************************************************************'...   .'+%$!!! # ! !!,                                                 **********************************************************************        $""#  ##!##                                                     *************************************************************' ## '$*"#     #                                                         ****************************************************************    !!,!!  !                                                       ************************************************************/' .!!!!! / , , , , , ,  ,                                                   ************************************************************'.  ...... .., ,,,,,,,,,,,,,!!,,                                                    ***************************************************...... .. ''+%-%,!!,                                                      ***************************************************** !! !  !""%###    #                                                    ************************************************************/     #"""#####    ##                                                        ****************************************************       #-$    ! ,,!                                                *********************************************************' # , !! !  '%$,,,, ,!!!!!!!!,,!!,,,!,,                                                   ****************************************************************/' ,!,, , , ''.(%-!      *                                              ***************************************************'  ....' +$,!!,,, ,,,,,,,!,,,,!,                                                  **************************-******************************************/  ,,   '% !      , *                                                 **********************-**************************************/     # ##%                                               ****************************--***********************************   ### /'###    # *                                                **********************-*****************************    ' ##%$%%#%%###$!#                                                   ********************-****************************************** /!,!!, %# """""$"$$$-$$!                                                ********************-******************************************* /'  ,!, !  ,  ,.#$ '  """%                                        * ****************-*****************************************/ ,  ,  .' %%,! ,,!!,!!!!!!!!!''. *                                              ****************** ****************************************' ...''!. ,,,, ,!!!,,,,,,, ,, ..'                                                ******************** ***************************************************'...'!,,,!, ,!!!!!!!,,,,,!!,!                                              *******************************************************************.  ! ! .'# !!     #                                             ******************* *********************************************/'! ! !   $*#  # #                                                 ********************* ************************************************' !!   "$""#  # ##                                               ********************** ************************************     ! .%% ##  !                                                  ************************* *************************************************' $$$$" "    '/+%% !!                                                     ************************ *****************************************************/! ##*  ####% ' ,,!!!,,!!!!,!!!!!!!                                                    *********************** **************************************************/!!$"$$$-$"*&'.' !,,,!, ,, ,  , , , , ,                                                     ********************** ************************************/!!  //   %.  ,,,,, ,,,,,,,,,,                                                 ********************* ***********************************************'..........%$,!!!!,!!!,!!!,!!!!!!!!!*                                                       *************** ********************************************/'   ! '.$   !!!!!!                                                     *********************** ****-***********************************/'  !!! ! ! !  %"  !! *                                                  *************** *************************************************** /    $$ ########%####! *                                     )              *********************** ***--****************************************************/'!       %$######                                      ) )              *********************** ***--*************************************************** #     %!  !  #######*                                  ) )            ************************* ****--***************************************************      !,!!!  "(%. !,!!!                                          ) )                *************************** ****-******************************************************* !!!! ,,, !  %$,!,,,!!!,!!! ! ,,!!!!!!!*                                   ) )            *-************************ ***-*****************************************************/!!, !!!!,,! ,, '%,!,,,, ,, ,,, ,, ,,,,!!                                     )            -*************************** ***-************************************************************/' , ,,   '%. , , , , , ,  *                                       )               --****************************** ****************************************************************' ...'!!% ,,,,!,!,,,,,,,,,,,                                     ) )               -**************************************-***************************************************************    ,  ''"%%!!!!!!!!,,!,,!,, *                                     ) )                  -**************************************** **************************************************************' , ,  !! ,, '%$"#     ,                                        ) )                   --***************************************************************************************************/' !! !!! !!! %$% ######## *                                       )  )                *-***************************************************************************************** /  !  .' /#%$#####%#                                        )  ) )                  -****************************************************************************************** '    #     !# # # ##                                                       -**********************************-*********************************************************     #%!       ***-----------------------------------------------------------------------------------------------------------------------------------------------------            ------ -    % % % % % % %  %    % % % %  % %  % % % % %%  ---------------------       ---*****!    !, !%$,!!!!!!!!    *****------------------------------------------------------------------------------------------------------------------------------------------------------             ------            ---------------                         ----**/'! !!! !! (%, ,,, ,  ,,  ,, *                                                      -*******-**************************************************.....  ..' $%((!*                                                   -*************************-**** *********************************************** /! !(!$.%$%(  )  )                           )  ) ) )  ) )                     -**************************** *****************************************************%*    )" ''+++*                                                          -***************************-**** ************************************************************************+                                                        -****************************-********* **************************************************************** """"""""""""""""""""%                                      )                        -*************************************-*********** *********************************************************************** ' """""""""                                                              -**************************************-******* *************************************************************** ''    $*"#                                                       **********************************-*** ************************************************************/'      +*#                                                             --********************************-*******************************************************************/ !#   . $"                                )                            -***************************************** *******************************************************/        ++$$$###                                                    -******************************************-**********************************************  ! # '$$$###  #                                                         --****************************************************************************************       # $"$########                                                          -********************************************************************************/  !  !# +/$"###########                                                    -*********************************--**********************************************************   . ,  '+#%$$##### #                                                              -****************************** **--****************************************************  !    %"$  ##                                                                     -****************************** *******--****************************************************     ''#         !*                                                   --******************************* ***********--*************************************************************!    !! ' (      ! *                                                           **************************************--********************************************************/   !+%%!    !*                                                       **********************************************--********************************************    !   %$%,!!    ! *                                                         *********************************** ********-*************************************************  %#,!!!!!!!!!!!!!*                                                  ****************************************--***************************************/' ! ''(%!!!!!!!!!!!,!!,!!,!!!*                                                   *********************************-******************************************/' ! !!!!!!!!!!!!% ,,!!!!,!!!!,,,,,,,,,,,,                                             *****************************-***************************************.. . .%( ,,,,,,, ,,, ,, ,                                              ***********************************-**************************************/'!!!!!!!,!!!!!,,!!!,, '. ,,, ,  ,,,,                                         ******************************--********************************'!(%%%%%%%%%%%%%%%%%%& ', ,,,,,!!,!,,,,,!,,, !                                                      ************************--************************************'.',!,!!,!!!!!!!!,,,!!!!, .   ***---------------------------------------------------------------------------------------     -    %  % %  %%  %  ------------------------------           ----' .  , ''%( !!!    ------------------------------------------------------------------------------                       ------           --------------------------------               -*/     ,,, .%%  !                             *************-*************--*****************************/ !! !! !! '%$#     ###                                                **********************************-***************************************   ! !   $$"$#############                                       -***********************--************************************* ##### ""*$*                                           -*********************-****************************************** #########  $*$ ###################                                        ***************-*--*******************************************/       ##           *                                     *********************-********************************************/! !!! ,!+!!!!!!!!,*                                              ************-***-********************************************** !!,!,!!!,!,, . ! '%-,!!!!!!!!!!!,,!!,!,!!,!,                                          ****************-**-******************************************' , , ,  . '%, , ,, ,, , , , ,,, *                                    *************************-****************************************************''      ...'%"., , ,,,,,, ,  ,,                                           -************************-*****************************************.  .'(% ,!!!,,,!,,!!,,,!!!!,                                   ********************--**********************************'. .   '%!!! ,!!!,                                       -**********************--****************************************/' !  ! ,   ' + !!,,!# !##  !!  *                                  ************************-*******************************/ !!,!!! !!!! #!##                                   ************* ****--**********************************       # ###*                                  ********************--************************************ ### ### '%$    # #* *                                          *********************-************************************************ #  #%$ !!!                                        ****************************--*******************************************      #$!,!!!!,!,,,!!!!,*                                    ******************************-****************************************************/' !!!,,!!!! !, !!' ,,,,!,,,,,,,,, !! , ,,,,   *                                        *******************-*********************-************************************************' .   . ...  **                                        ********************-***********************-**************************************'..... '!,,!,!!!!!!!!! ! **                                   ******************-*********************--*****************************************'  , , , '+%,$ %%% $$$ $%%%%%%%%%%% *                                               *******************--******************-**********************************',! ,!,,, , !! .%$" '. ... ...**                                       *******************--*********************-************************************/ ,! . ,! ,! ' $"$####   #                                            ******************--******************--*********************************  # ,!,, $"##  **                                         ***************-************************-************************************/ #    ! '/$"$#########                                             ***************-**********************-************************************'  ! !!  !!''%#########*******-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------   ------------------------------------                      ---/'!., ! !,!  +$!,!    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------                  ---*/' , ! !,, !!,, %,,,,! ,!,!!!!!!!!! ,!,!!!**                             **********--*************************************--**************************************'.  !!' %! , ,   , , ,  **                                        ************-*****************************************--***************************************************..'' %,, , ,  , **                                         **************--*************************************--**********************************************'!!!! ,!!, ! , %(, ,,,!,,,!!!,,, ,,!,!!,!!,**                                           **************-*********************************--**************************************************'!%%%%%%%%%%%%%%%%#%%%$*"%!!!!!!!!!!!!!!**                                           -***********--********************************--******************************************/. ' %# ###  **                                                 -************--*****************************--*****************************************'    %$#%#$###                                                 -**************-***********************************--********************************************/.    '$$% ##$ *                                          ************--*****************************--********************************************      /%%# !!   ###### ****                                               -**********-************************--*****************************************    !   .% ,!,!,!,!!! *                                                  -********--***************************-*****************************************/   ,!,!, ''%!, ....... ..****                                        -***************-************************--****************************************'.  . .  '//+(% %##                                             -*************--*******************************--***********************************************.................%$%%%%%%%%%% %% %( %%%%*                                             -- *************-***************************-****************************************************'    .%*'........'.*                                           -*************-*****************************--**********************************************/!!!  %%# ""$""$"%#**                                             - *******************-*******************************-*********************************************/#    /#! *                                          --*************-****************************-************************************************** ##  $$% ####### **                                        -******************-***************************-************************************************'       %"%!,!!! ,,,*****                                             -***************-*****************************-*****************************************************'  , !!! ! , !!!.'% ,,,!,,!!!, ,, , , ,,****                                            --  ********************-*************************-*****************************************************************'..   ,   ,   .,,***                                                -*****************-***********************************-************************************************************'... ..... !!,!!,,!,,!,!,,!,,!!,!..**                                         -******************--**********************-***********************************************************/' !!!  ! ,! "$% ## ! !**                                            ****************-*********************************************************************************   !! !!+$**$ ####### ****                                         -*****************-***********************-*********************************************** ##    $%#### # # *** *                                          -  ****************--***************************-******************************************************** # #  +#$%   !***** *                                   *****************-********************-****************************************************'    !,!! ,,,,,, ,,,,,,,,, ,,, ,,.***                                             *****************--********************-***********************************************'.   ,!,  , ,, ,,,,,  ****------------------------------------------------------------------------------------------------------------------  -------------------------------------------------------   ---------------------------------------------              --------*****........./+(% !!!! ,******----------------------------------------------------------------------------------------------------------       --------------------------------------------------         ------------------------------------          ---------****/' !! !  , , //+$"-! ####*                            ********--*******-***************************************** #   $""%##### #****                                         **********--*********--**********************************************************/ #    #%%     ! ,!!! *                                  -***********--*********--*******************************************************************'    ,! ',. , ,,,,,,, !,, ,  ....                                **************--*********--*****************************************************************/' .. '+(!,  ,   ,,,,,,,..**                             -   *****************--*********--***********************************************************************'.....%%# ,!!!!!  ,                                **************--************-***********************************************************/.! ,      $%#### **                        - **************-*********--***************************************************************/#  ## %#                                 -   **********--*****************************************************************************/      %,. !,!!,,,,!, !!  , *                       -******************************************************************************.   !/+((,. , , ,,,,,,, , ,,***                   -      **********-***************************************************************** .....''%%!#  **                        --   *********************************************************************/,!!!!!'%%%# ##  ##                       -    ************************************************************  ##### . ,!!!,! ! ,!!!!!*                     -   **************************************************************************    ,,,, ,   .   ,  ,.*****                     -- ******** *****************************************************' ,    .   ''! !!!!,,, ,,,,,,,,**              -     *********************************************************************************.... $"%##$##  !!*           -  *****************************************************************************'.     #%$"#"#####**                 -   ***************************************************************************$"$"*"$"%$$$$$$$"$"" % .. , ,!!,!!,!!!,!!**              --     *************************************************************************************/'''''''''''''''%%%!  !!!!****         -   ************-**************************************************************'''',$ %%%%%% %(((%%%%(%(% %             ******** -****************************************************************/      *,,!!!!! '' ,!,,, ****               -   ******** --********************************************************/    .%$"%##########  *              ************ --*****************************************************'    ' #$    , ,! ,! ,,****                  ****--*************************************************'  .. '%%!,!!!!,!,!!!!!!,***            ********  *--*******************************************************/.  !   .'"$%%$$#$$****             ********--****************************************************       +*$"$## ****              *********** *--**************************************************/'!     + !,, , ,, , ,  , !,,*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------           --****.........'!,!!!,!!,!!!!!!!,!!!**----     --------       ------------------------------------------------------------------------------------------------------------------------------------------------------                 ---******/'!!  !!+      **    **-*-******************************** ## # (% !!,! ,  ! !!! !****    **-*--********************************      %..,  ,, .,  ****        *-*-**************************************************'..........''/%" ! ! ! ! ****           --*--********************************************'.    .''$*$######## *******                - -*******************************************************     ',$$  !,,!,.**********          *-** -*****************************************************/    %, , ,,,,,,,,!,,,,, !,.*******   **        ******--***********************************************..   ..'%#   .********* *          -****** ***********************************************/ .,!,,, ,/%$$$###**************  *       -* *****************************************/'   ##### %    !***********     -**-***********************************(/!!! !  !  /'( , , , , ,!!,,,,,************            -*   -**************************************//'. ........../'++$!!,!,,,,,,,,!!!**********         -**  *********************************** ' !! !..! '''"*##! #********* *        -*   ******************************'       $"% !,  ,!!*******************            -*  -**************************************.  ! !    '!%. ... . .  ************          --***  *-*******************************'.......%!,, !!!!, ,! !,!! *********************      -* ******************************************/' ! ! , !  . '-""$"%$""%"$$%$%%%"$%$$$"$$$**********************-           -*-****************************************       $%$%%%$"$$$$$$$%$$%$$-$$"-%**************-         -** -****************************************#     "&"%""****"$"$"$"$"$"$""$$*************************            --************************************/'.. '**********************  -          -**  --************************************/.  !!/++++*************************-            -*    --******************************%""""$$"$""""""$"-$""$ ''., !,, , ,! ,,,*************************         **    --********************************'$""""""""""""""""$"""" * '''''''..'.....**************************             -     --**********************.  !!! !! !!! ") "#  ######************************-         *   -****************************%"$ ### ### ************************            *         --*****************************++ . ,,,!!!!,!!! !****************************       -       -************************'...'.'''''''%,  , , ,  ***----                   ------------------------------------------------------------------------------------------------------------------------------------------------------ -------------'............. /$*" !!,!!!!!!!!!!!,,*----                    ------------------------------------------------------------------------------------------------------------------------------------------------------------------    ---------------------*'''...'  $""####### %#### **********************  - -*****************.!  #      / $######****************************** --     -********************/',!,  !!! !   ' %,     ************************************   -   *-************************....../, ,,,, ,, , ,,!!!!,,,, ,, *******************************   -    ************************** ... '.%%  .  , , , ******************************************     --    -************************       ! '($%.!,.',! ,! ,, !!!************************************     --              *****************    !    $""## #   *****************************************       --          -*************************/   !!!,   '$"" ### ##*****************************************        --           ***********' ... .. '/#%,     #  *********************************          --               -********************'......  ! ! , ,!!,,, ,!,.********************************          --       *****************/!   !  ,  '!.. .. ,,,,,,.'********************************         --         *-*********************** ##   ' %-" ##!,, , !!! !************************************         -             -*********************/. ,    $"*#####   ************************************       --         *-*********************/'  !!!  !  ! '#$$#  # #   !**********************************      -       -*********************'......! .. . %.. . !  !!'***********************************        -              ********************'............../'%#%$    .....'*******************************************     --             -****************'!! !! ,,  .   .. , %%%%%%%#%#(%%********************************       -           *-*****************     ,, !  %%,!!,! ##%##(((!****************************************       --                   *****************/ ###    *%**$""$!!!!!!,'..*****************************************   *-            -*****************/         $$"$$$#**********************************************     --                  -*********************'   ,! ,  //'%%. ,!,! !****************************************** *--            *********************....................'/.   ,,  .************************************************      --                     -***************'   ,!     .   '$ !!!!,!,!!,,!!,,!,!,,,,.*******************************************    -              ****************          '"*"# ##, ### **************************************************      *-                   -****************      # ""*#######  # ## ******************************************    *-             **************** !  !!!!!!!!  !'/%.,,,,,,,,, ,!! !, !, !!!*****************************************************    *                      ****************'''............''!.( ,,!,,, ,    . .*******---   ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------******/'    .....'.(%%$ !      !!!!!********---             -----------  ---------------------------------------------------------------------------------------------------------------------------------------------  -------------------------------------  ---*******  !    .%"" ## !****************************                  - ***********/    !    '$$, #   ##### ,****************************                  -****************  ..   .. .  . ,,   ,.'*******************************************  *                    *********************!%%#$',,,,, ,,., ,,,,,,,,,********************************     * -              -***************** .....'.'.'$* %###   ####*********************************** ***                   -*************/   ..  ..  $" "##   # *********************************   **                      -   *****************       %!!!!!!!!!!!,! !!!!!*******************************     *                       -- **********************'..  ! ..'., ,( ,,    ,**********************************************     ****                     - ***************................./$$!  ## !, *************************    ****-                     -******************/.      "'/$######### *****************************    **** -                        --   ************/ ########### !! !,,      ****************************  -     *--                    -**********/     . , .  , ,  ,'*******************************  **-                        -   ***********'.................'%" !  !!######**************************   --    ** --                     --  * ***************'  ! ! !,! !!!! , '$""$  !  ##### ****************************   -   ****--                    ****************      "+%%%,,, ,!! , !!!!!!!!************************       -*****--                   -   ***************/       !,!,!,,,,!,,,,  ,'*********************** -- ********--                    -  ***************'.    .. ... ' %$-$####### #!  #************************   --  *****--                     ****************** !, , !... ,..,'$""     !  # ,*********************************   *-  ********-                 -    *****************    !  #%%- ,,, ,,  , ,****************************** --*******-                       ***************  ! ! ,  '%$,!!,!!!!!,!!,!!,,!,,,,.********************************   -*************                              ***************'..  ,  .   !.' /%%  ##############**************************   --***********-                     -    *****************' . ! ,! !!!!!'.,!!! ,  ***************************      -******                       -      *************         #!!,    , , !, ************************** -**********-                  -  ****************/ , !!,!,   !!! ' #%%### !!,*************************  --************-                        -        ****************/ !!,!!!!!!,,! !'',#%% ####  !!***************************** -******************-                   -   ***************/!  !(. !,,!!!!!!!!!!!!!!*******************************  ***************-                     -   *******************'!!,,! ,, ,,! .%! .,!, , ,,,,,,!!,!!!,,,!*---------------      -------------------------------------------------------------------    ----------------------------------------------------------------------------------------------------------------------------------     --***.............''%" ## ## #### -----------            ---------------------------------------------------------------        --------------------------------------------------------------------------------------------------------------------------------------------          ----******/       .#$% ,!! ! ! !  !***************************  *-*******-                -- **********       %!,!,,!!,, ,!!,!, ,!!, ,,!****************************** **************--*                       -   ****************/ !  , ,!  %%!   !!! ************************************** ******************--*                - *************'.   .........(%%  ##  !!******************************  *-*******************-                --  ********************       % ,,,,  ,,,!,,,,,,,,,! ,,******************************* *******************--              ********************'#$$$$"""""""$$"$$"$""""""&$%$"%,,!     ****************************      -************************-               --     ***********************'''''....'.....$ !'$$. !    ************************************-**************************-               -  *****************''''''''($. ,,,,,! ,,,,,!!!!!!,,**********************************   ***************************-              -            ****************           !,!,,,,,,,,,, ,!!!!,!!,.*********************************-************************                     *******************' , ! !!!,  #  ! ###***************************************  -*************************                    -     ********************/ !!!!!!!!!  ! , ,! , ! ,,, ! ! ,   , ************************************* *-*********************** *                          *****************            % ! ! ! ********************************   **-**************************** *             -         ***************/!!!!  $-$$-$-$-$$$$-$-$-$-$-$-$%%%%%**********************************   -****************** *                  ************.................... ''%"$! ,  , .*****************************-******************************                             *******************/ !, !, ! !  ! . !  ! ,!!!!!!!!!!!,*****************************   -************************* **           -  ***********************          .!!, , ,!!!!!,,,,,,!,!,!!!!!!************************************* -*****************************                  *****************/ !!!!,!!, ,!  #-$         !*****************************   ***-***********************************              -  **********************/.!!!,!!! !!! !!,,,  .#$% #   ###***************************************** *-****************************                  - ********************          ,!%  , ,, ,, ,,,,,.************************************-************************************               -     ********************'      # %%$#,!!!!,!!,,!,,! !!,, ,, ,!********************************************************************************              --          ******************' ... ..... '' $*###    !********************************************************************                 --  ****************/' ! !!, ,!  .$$########    !*************************************************************************              -     *******************/      , !  '+,     , , ,,, ,,**************************************** **********************************-***                  -    ***********************'  ! !!!!,   !  ,!,,, ,,,, ,,  ,,,,,.***************************************************************************                  -      ***************........... ''#-$#%%%# ******************************************************************--**                        ******************'        "%$########## ********************************************************************-**                        *******************/       %% ,,,, ,,, ,,!!!!!!!,!,,,,,,****------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------        ---*******/    , ..  !'%-, ,. ,, ,! ,  , .***-----     ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------           -****'........ ........'" !!! ####   #####*******************************--**                 *************        '*$  !!    ##******************************************************--**               ***********************' # ### .,% !!!! !!*********************************************************************--******                     *****************************' ,, !!,, , !,  ! !!,, ! .'+,%((((((( ***********************************************-*********************************--***                   ******************'.... ..  ....,'/#$%%$%-%%%%%%%%%%%%%%%%%%%%%**********************************************-****************************--***                   *******************/! !!!!!! . "$""*" "**$""""**""*$$"$%******************************************--************************--*                             *****************'    ## ******************************************--********************-**                            ******************/ !!!  ,,!, !,,!, !!.#.'''''''//'/***********************************************--******************-**                                *****************************  !!'/'' !  !!*************************************--******************-***                                  ****************** '!#$%%%%%%%%%-%-%%%%%%%%%%%%% % ! '****************************************-**************-**                             ************************' %$$%$$$%%%%%#%%%$$$$%%$%$-% , , ,,'*********************************************-*************--*                                     **************************+//////////''/''''.'''(% ...,!!,*************************************************-********************-****                                       ***************************%$(  !,!,! ********************************************--*****************--                                      **********************$%   #!#,**************************************************-******************-***                                        **********************/    ! !%%$"!# # ###   !*****************************************************--*********************--*                           *                   *********************** ...'%$$!!!,!  !!! .***********************************************************--**********************--***                                        ************************* /''''''''''''''''. '***********************************************************--**************--*                                               **************************'!  /+(%% !,!!,,!! !!. ****************************************************-*****************-                                                **************************/      '$$""###  !************************************************-*******************                                                    *****************************/     ''$* ## !   ## !*******************************************************************--                                                  ***********************         '$%!,!!, ! !! ,! !**************************************************************-***************-**                                                 ***************************'        ,.  ...'***************************************************************************--*                                             ********************.. .. ! ,,,,,,!, ,,,.******************************************************-******-**                                                    ****************************.. ...../ #  ######## !*******************************************************-*************-*                                                    *********************** !!   $""$#####******************************************************************-                                                **************************** '      %$$     ,*********************************************************************                                                 ****************************/    !' ' ',    '*********************************************-*****-                           -                    ********************************'........../.!!,!!!!!!!,*******************************************************--*                                        **************************************/'!   .  '#%###$$# ********************************************-**********-                         -                         ***********************************     $##$$#************************************************************-*                                          ***********************************     " !%. , . ,, ,, .***************************************************-********-**                                                 *******************************************,....... //!(!%%%%%%%%%. /*------------------------------------------------------------------------------------------------------------------------------------------          ----------------------------------------------------------------------------------------------------------------------------------------------          --************.... .... /'/" !! !%$%$$"""$""$#**-----------------------------------------------------------------------------------------------------------   -------------------------------------------------------------------------------------------------------------------------------------    --****************/!!    %"#,,,  $"""$$$""%***************-************--                                        *****************    ! -% !,!! ''''******************************************-*********-***                                             ************************/,      !!.. , *************************************--*********--                                         **********-****************......'/%# !! !,,!! !********************************************-************-                                           **********-  ************/.!   ,$ ### !!  ********************************************-**********-                                          **********-((-************** #     %$$ ,, ,!!,*************************************************--*****                                         ***********-(( ( -**************/! !!! ! '%% ,  ,'********************************************--*******                                          *****--( ( *****************''.....   . /%$    !  *******************************************--**********-                                      *************-((-' (-*************    '%    ******************************************--********                                           *********-- --(' **********/ !   !    #% ,, ,,,, ,,!!,,!, ,,,,************************************************--***********-                                      ***********-(--' ( *********************'   ,! .. .  !' %%%!!,,,,, ,,,,,,,!,,,,,.'*****************************************--*********-                                    ********* ( -('(-*************** ..  . .. ''$ ########*********************************************************-********-                                    ******-((----'( -****************/ !    #  # ###*************************************************-********-                                    ********-(-----' -********** '$""$""" &. ''!,. , . . ,  ..'************************************************--**************-                                     ******((----' (-***********+/// #$&%% , ,!!!,!!!!!!!****************************************--*********-                                 *****-( --$-'  ************  .,, !$''#$$    ####***************************--*********-                                      ******-((---' (-*********/       %! # ,!   ********************-********-                            **-((--- '' (***********  .,! '/... ,  . '****************************--********                  *             ***-(---(**********'.......%"" ! # !!!! ************************-******                                ***-(---'' ( *******'        !$""     ***************--*********                  *       ****-(--- ' *******/    !   %$.!!!!,, ,!!!,!!!***********--*********                        *             **-((----$ (-********/'.  , ! , .% , ,,,!!!!!,  .**********--*********                *        **- -----''  -******/' ! '##########**********-********                                ****-( ------'(********. ###  ,!,! ! *******--********                          **-(------$-$*' (-**********'         ,!!,!!,!!!!!!!*****-************                    ****-(---- '' *******/ !!!!!!!!,''$""%,!,,!!! !***--**********                         **( ----$-**  ******** !  !    $"  !!!!! *****-********                          -(---**'  ******' !!!!!   .% !!!,!, ,,,!!, ,!,****************                           *- (---$-*******'( ******** ..   '/%"$#####   !! !**********         )               ***-(------*** ' (*****.       %!!!!!!.***************              )              **-(---$$****' ( *******.     !!!',!,! ,, ,!!!!!!!,!!!,!!,'***********                            *-(---------*****' ( ******'!! , ,, ,!! !       # ****************                 ) )                -( -------$******' ( ****/' ! ,!! !  . '%- *" #   *********           ) ) ) )   )  ) )              *-(-$----*******'' ( ********/ !! ,      %.'/. %%%%%%%#%%#%%#%**************                )   )  ) )             ((-$****** ' ( -****/'.. .. .. /$ !!!! !!! ********             )   )  )  ) )                 - ----***** ' ( ** ! ... ! ! ' %$" .,,,, !!, .********                    )    ) )            -( ---**** '  -*        /%"$    !!! **************              )  )     )             ((--$-***** ' (( -' !!!  ! ,  ......'**********               )    ) ) ) ) ) )           *-(( ---***''  ('..............'%$% ##### ***************                ) )    ) )             ((--******  '' (      %%!  # !*************                )  )    ) )  )            -((---******' ( -'       !  .. ,, ,, ,!!,,,********            )   )  )  )           ((--********( ((-'' ,, ! !!!!!!,  ''!% ...  ..... '***************             )  ) ) )  )    )           **-(-**********-- ''......... .....  '%*"$# #  ### ***************              )    ) )  )           (----*************-(     # ##" %$"% !,   !!****************               )  ) ) )             -( ---***********---%!, !! !.%%%,,!!,,,,,,,,,, '***********************              ) ) )  )  )             ((----******----!.     .'' %$ ! !!,!!*****************              )))  )              *-(-*********--- ,, ! ! !!!!!!  !!!! .'%$$ ###  ********************            ) ) ) ) ) ) )              -(-*********$-     ###### # . , ,,!!,!! !!!! ************           )  ) ) ) ) )           -( ----*************-----   ..  !,!!,, ,! ,,!, !,,   ! !!,,,*******************         ) ) )  ) ) )           -((-$-***********--((%##%%%#%%#%%#%%%..'#$$ #   !  !******************            ) ) ) ) )  )  )        --(-****************--$!!(((! (% %#%%%#%"%%%%#%$"$$$$"") $""   !*******************        ) ) )  ) ) ) ) ) )         -(-******************--   !  ..  !! $$$$%%%%$""$%$$$$$%$"$$$$$*& %$,!!!!!,,, ,, ,******************         ) ) )) ) )        *-(---****** **  ! ! !!!  !! ''/  . ,,,,  ..'********************          ) ) ) )  )  )           -(--**********--!'.......  ...... ...  .  '.%$$! ###### !*****************           ) ) )  ) ) ) )         -(---***********-             %$ ##****************            )  ) ))           -(---*********--#              (! ,! ,   ****"************           ) ) ) )    )       -(--*********** . !!!!!!,!! !    .!  ,,!!!!! !!!!!,!!!!, .%.  ....... '**************          )   ) ))          -(----****** ................................................''%$., ,! !!!!  ,,,.***********************          ) ) ) ) )          -(--$*****   ******-!   ! ! !!!!!,!!!!!  !. ! , ,!"########******"**************           )  ) ) )          -(---*** ***********!##   #####       #   !!***************             ) ) ) ) )        -((---***   ****%             ,      , ,, ..*******************               )             -(--****  ********% .. .. ........      ..... ... ...! , ,!,!!,!,, ,,,, ,,..'****************               )        (-****   **-!'.............'..................... .  .''/$"$!###########*****************            )          -(--*    *****%!  # !    !    !       !  !!    . $%""- ## ## **************           ) )         ( ---**  ***-#    !!!!   ####  !!   ####     %"$.!  !!******************               )            - (----**   *! !    !  !! ,,   ! ! ! ! ! , ,!!!,,,,!!!!!!!!************                       -(--**** * *(.''... ....... ...... ............. .. . ''',%%%%%%%%%%%#%%%%%%%*****************              )             --**    *!'..'........... ........ . .  ..      .. . .. .#) '''.'....''' .*****************                      ---***   ***-!!,.! ! !..     !!!!!!! !!!,! !! ,      ")### # !! !***************                         -(---****    *** ##     ! !   !    #####      ## # *********************                     -(--****    **!     !!!  !   ! ! !     !  ! !  !  !! . , ,!!, ., !,,''*********************                  -(--****      ''.............. !.'    ... ..................   . '....''...... , ..*****************                -(-******    *-.................. .................. ........ '       **************                     -((-**** **(    !!! , ! ,, ,..    . ! .. ,, ,! ! ,,, , , ,,  ,! , .%%######****************                  (-****   !!    !           !!   !               #%#    ****************               -(-**    *      #####                #####  !%.     , , , ,, ***************               -(-****     **( !! !!! !!,  !,  ,!        !!!!  ! .  !  , ,! , !! !!!!    !(!... ..    '*********************                 (-****   !'.........................( ( !...  ....................  .....!' ,,,,,! !!!!,,,*********                 -(--**    *-!   ! ! ,!!  . .. ... .. /''/',!!!,!!!!!!!!!!! ,!!  !  .  ! ,!   ,,    ...'.+%    # !,*******************                 ***    **!  !!     !     ! !    !''-#    !   !!     '!##   ##  !************************            -(-**    !!        !!        !'$####    !      !   ! **************************                  -(-* -%(. !   !  !! !! ! , !!! ,  '#!!!!!!!!, ! ! !  !!!!,,!,!!  %% ,!,. ,!!!!! ,. .************************               -(-****  -!  ..!    !!  ,!     .  , '   ', ..................... ..............,'' .......'***********************                   (** -, ...........................( ................    ......'''..... '(% !, ,!!,,, !!,**********************                      --**  !......' .     .  ! . '( !         !     ,  ' $$$%#     !*************************                    (*  % !       ! !! ##  ! ! ! '( #       $$#  !  ,************************************                    - ** *!.  !   ##  ##  !!   '( !,!!,!, , , ,! !! ! ,, !, !!!!!!!!    !    !%%. ,,,,     ******************************************                 -   ('' .   ,! .. !  !!!!! ,, !, ,!!    .'''''...........................................  ........ '($     ...'********************************************                   *--**  ( ' ........................................'.'...'.  ... ! !!! !, , ,       .......... ''%$#,!!!!!!!!!******************************************                    -*    ! !!! !!!!!!!,!!!! ,, !! !,!!,!   !            !!!  !! !+#%%##########*****************************************                   *-   -% #   !!  ####    #   !!     ########## #%#   #*******************************************************                            ( #  !            !     ! !,#       # %,   .....  ,*********************** ) ! ! , !!!!!!,!! ,!     .......'................' ,.   ,!  .              '... ........... ..*"*****       )   )          '''''........... ........................................................... .....................................'$$     *******************************************************************  *          )            $-   !  !! !                          ! !   ! !         !"*$#######***************************************************** **..   !   !  !,!!!!!        !! ! !! (      %%(      #####################  !       ###########"$%     ,, , !!!, !!!!!! !!!!!,!,!!!!! !!!,,,, ,, ,!  ! ,!!, !!,!!!!!!!!!!!, !,!!,..,, !!!,   ,!,!!!!!   !, ! ! ,,!!!! !! ! !! , !!! ,  !! ! !,! !!! !!!!!! ,!  ,!!, !!!!!!!    #   !!!  !!! !    ##!  ! !!                     !! !  !   ! !        ... .. .. .   .   .., , ..... .. .    ,,,  .. ,!!................ ... . ..  .........   .....  .... ......   , !,........... ,.............., .................... ........................................................................................ ..... ... .....................''.,,! #$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"&%,,,  ,,,,,............. . . .. ...........   ,!,,!,,,,!!!!!!,,  ,!!,,,!!!!,!! !,   ! !,,,! , !!,!,,,!!!!!!!!,!!! ,,,   ! ! ,!!,!!! !, ,,!, ,,,,,. ! . , ! .  , , , ,, , , , ,, , ,, ,,,, ! , ! ,  , !! , ! !,!    ! , , ,! !    .,   .! , .. ... .  '  #!    $$##  #"""""""""""*"*"""""""""""""*"""""""""$$$%$$$$"""*"""""""""""""""""""""*"""""""$$"""""""$$$$$"""""""""""""""""""""""""$$$$"""""*"""$$"""""""""""""""""""""$*"$$$$$""""""""""""""""""" &       .                      !    !    ########     !      #%! !!   # , #%#%##$%%%#%#%%####%####%###%#%####$%%#(%%#%#%#%#$##$%#%%$#%#%##%%#%##%###%####%#%$%%%#%%### ##%%#%#%#########%##%#%%%#%##%##%#!##### ####%#$%#%#####$   ! ! $$$$$$$$"$$$$$$%%$$%#$%%##%%%#%$$$$$$$$$$$%%%%%%%#%%%$####%#%%#$#%#####%#%$$$$$$$$%%%%%#%%#%####%$#%##%%$%$$$$$$$$$$$$$$%$$$$$#%#%$ $###%$$$%%##%#%%$$$$$$$"""$$$$$"$$$$$$$$$$$$$"$$$$"                    !      ! !! !!! ,!,,,!, ,, .'''.'.'''''''''''''''    %#%#%%%%%%% (%(%#%%%%%%%(( ((((((# ((((##(%%%%#((( %(#((#%%%%%%%%%(%%% (%%#%#%###%%%#%%##%#%#    ,, ! !!! ,! ! ,! !!    ! !!! !!  !,! !!!! ,!, !! ! , !!  !!! '!(... .       .,,,, , , !, ,,, ,  , !, !,!,, , ,!,!,!,!, ,!! !!,,,  ,!! ,  !!!!!,,, ,!,,,!!,, ,  !,,  ,!!!..  , . !,,,, ,!,! ,!!!, ,!,.. ,,!, !! , ! ,, ,, ,!!!,, ,,   . ,, !,,! .  ...//'''''''''''''///'''''''''''''/''/'/'''''/'''''''//'/''......!%%%%##%#%%%%#%%%#%%%#%%%%%%%%%%%#%%%%%%%%%%%%%%%%%%%%%#%%%#%%%%%%%*($$%  !!    , ###### ####### ####   # !  #####     #### ! !!!!!!  # ############   #######  # $$$#! # "#"$$$## ###  # $"$$##   $$$$$$# !  $ #  ##   ".! ! !!!!,  ! ! ! ! ! ,  !  !,!    %$"$  !!!    , ! ,  #   ##   #  # !!!  !!!      ##             , !!!!        ,!          ! !  #              !         !              !  ##                          ! $ !!. . ,,! ,    , !,,!,!!!!,,,,,, ,,,,, ,,,, , ,, , ,,, ,  ,, ,!!!,,, ,  ,,,, ,!!,,,,!,!,  , !!!!,!!,,,,,,,,,, , ! ,! ,   . , . ,,,!,,,,,, ,,! , ,, . . ,!,, , ,, ,,,,,,,,,,,  .   , ,, ,,, ,  . .. !,.. ,!!!! ., !!!!, ,   .  ,!, ,,     .. ,                ..  !, !,  ...    , ,, , ! !, , ,, ,  ,   , , ,  ,  !,!!, ! , , ! ,,  ,  ,.! ,..,   !!!,  ,,,,  , ,,,,,,,,,,         ,,,.. . ,,,,, ,,,, , ,. ,,,.  , ,,! .. ,,!,,,,,,, , , ,,,,!,! ,,,!! . ,, , , ,,, , ,,,,,, ,,,,, .  ,    ,,, ,, ,,,, ......  , , ,..  ..... .  .....      . .       ..  ...... .. . ......    ....  ................................  ... ... ..''#$% !!# ! ##  ! #######!   ##%#%#%########  ####### #!!! ! ##  ######## ##   ############# # !!!! , ! ! ###### # #  # !  ###  !  ,! ###  #   ! ,  ########   !   #####  ! !  #   !  #       !! !                             '%$#. !! ! !!     #,,  ,,!! #######################  !!!    #        , !!!!!!!        ,    !!  , #######   !    #      ##  !  ###    !!,! !       !. !     !!    !!!  . ! #############%#%$$$$$$$$$$$$$$$$$$$$$$$$$"""$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%$$$$$$$$$$$$$$$$$$$$$$$$$"$ '#$'........................ ...................... . . ........................................  ............. ................ .. ...... ......... ............'. .....!,!, !,,,,!!!!!!!! !! (###!!!####(#( (   %'-  !# !!  !  !! ,,!!,!!!  !!!!!!!!!!! !!       #  !! #      !!!!  !!!!!# ! #,,!!,!!!#(((((#% %#%%%%%%%%%#%%%#(%(((#%%%%%(%%%#%%#%%%%%%%##%%# #% #%%%#((  (( ((((((((( ((((((((! !.    !, ! !'/'''/-""$$%$$$$$"-%"$%% -""$% %""$$$"$"$""$""""$$"%%$"*"%%%"$%-$$$$$$$$-$%%%$"$-$-$"%$$"""""""""""""""""$-""""""""""""""$""$"""""-$$-"-$"-$-$%$"$-"$-$ $%$%-$-$$"-%$%$%$$"""""*"""""""""""""""$"$$$$"$-%%%$%$$-"$$$$"$$""""""""""$""""$"$"$$$$$$$ %$-$-"$$$% $%%$$$$%$$%%$$$$"$""$""""""""""$""$"$"$-$"$$$$%$"$$"$"""""""""$"$$$$% $$"$"$$$$$$$$$$-"$-$"$"$$"$$"$-"$-$$$$-%$%%$$-$$$$$$$$$$%$$$$$$$$$$%$$%$%$%%%%%%%##%%%%%%%$%%%%$%%%$%$%%######%%#%(#%$%# %#%###%%%%%%%%#%%#%%%#%%#%%%%%%########%%#!# ##%## ! #!!!!! . +$%! ##(###%#(###%((%## #%#%####%#%%#%#%#%%$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%##%##%#%###%#%#%##%##%%##%%#%################%%%! %%#%###%%###%##%#! ( ((######%#%##%##%#%((,(###((( (########(#(###%#%%##%%###%#####!!!,!!!!!!!! ! !! ! ,,!!///////////$##,#,!!,!!!!! !'%!,# #,  .,%,# , ,!# ! ,!!!!,.'$%## !%,#,,$ !,! !,". . !,!!! ,.!!! !'%%$, !,,%". ,   ,, %! ,,% #!$! ,,!,!!! !!,% ''$(!,!#,,!! !, !!! !$,  %,   # # !!! !  !!!!!,'$#. ,,%,#!!!!$ !,!  ! #$. ,#,,,!!# !!!!'"! !#.!, $* !,!#!,!, .%, , # " # !! ,, !!  $%% ! !! #!!, !, ,!,!,$,!!%,# ##,$ !,!!! !! ! .'%(%#! ,$ , !!  % !! ! ! ,#.". ! . ,!! !!#,! !!..%$!  !,, !,#,, .%! , #!$   , !!,!,! !'%%%$,%,, #% !#!!%,.",%%" %%%%% % $%%%,#,% ##%%%% ..$!,,#$ ! ,, $ !!!! $. .  #,,,,!!!! '#("! ! !! %$. ! #!, '$!!,,# $!! ! ,,!!!! , ,'$ %$""#%%$%%-$%%%%%$$#$%%,"%#%!$$"%$$"$%$% $%$%"%#(%$ #%%%$%%%%%!.% %%#! ! !# , !.$ !!#!!,! %."!. ! # !! # !! ,! !  %$!,! ,# %. !(# , .$,!  % #!"  ,! !!,  "$$$$($$%%$(%$%$$$$(#%$ $$%%#%$  "%%%%%$$$(#%%% %$%%"%%#%%%%$$%%%%% .$%%"$ %!%,$!###,%$%%#%%%"! #.#!$!#%#!!  %%#!,!'%!,  !#$ !#!  $,!,#!$# !! ! !!!! , .$%%"$ %#+$$$%%%%%$-%% %%%%!%$-%-$%%/%%(%-%% $$$"*$%%$%"$$%$%%%#-%%%$$% %%%%%"$%%%%$$%$(#(%%%$$#%%#%%%$%%!$$! ! !!#,% !!,#!, $ ,  #$.# #,!  ! ! ! !, ''/''!,/'/+'/'/+'/$$'!//.""%-%%$%%%%$%$%%$%%  !-$-!%%$%%$'"%%*$$%%%-$% "%/$%%$ %%%%%%%%%(!! #,'%$,!  !#,%#,!(,!!! ,.$! !.,#."#  !! ,!!   '"%%$%%$%$% $%%%%%%%$%%"$%%%$$%$% "%%%%%%%%/%%#$ !  ! # % # , ,!!!  .$!, #$ ,! ! ,!!!! %'$($ !#, !!#% !.!!! $  ,#$,   ,! ,, ,! !! '%$,!, !,. # !!#!! $! ,$. # , ! ,!, !! '%$,,#, ,.,,!,! $ ! #$,  ! ,!,$! ! , , %,.%$ !#, ,! !,!!! .$ ! % #$  ,  ! ,,". ! , !#  '%%$#,,!#% #! ,#,#,,$ ! ,!#.",   ,.$ ! ,! ,   '%$ !#!!,!# #!!,%!!!  .$!!, .$ , ! ,, $ ,,!  '% !#!,, #!,#!!!",! ,#.$. ,   , % !! ! !  .%$ #!!,%. #! !!!! !$!! , !  #.$. , ,#!  !!   .!'%$ !,!!,! ,#!,!!.$!! !% #". , # ,$ ,! ! , # %",,!!%,#.%! !,$,,   ,#.$. ,   $ ,, , !''%($ , !#%!   ,!, $, ,!,#.$. # #!  .$  ! ! ,#%$,,!,% !! #!!, $,,!.$  #!!!,$ ,,! !# !'%$ !!# %, %,,! , $,  !#.$,  , , $,, , ! !%$,!,%,  #!!,  $  ! %!$.#, !,."  , !!!,# !'''%($!,,# %   %! ,! ! ! !  !#.#,# , $..! ! !#!!'%$,!!%.% !! # !  ,!$! ! !-#, # ! ,," ! , !#!!'%%% !,,.% ! ,#! ,, , %  !# . !! , $.  !!,.% !%%  ,.%,! (#! ,!,$! ! #!# %,#!!,$ !, !! % !''$($!!% ! #,, !!,$,,!%!# %#,,, ,,$!!! !! !, .% !'%% , !!# % !! .%,!!!!!,!!!!  !%  !! ,, "!!! % !'%%,# !% !  #!! ! $!!,! !# # ,,   , $!!, % , ''+'%% .#.$ #! .%, ,!,$,,,# #.,# #! #! ,$. !!! % !!'$%,!.% #!!% !!% ,,!!# ! ! # ,!, "., ! !!, % !''%(#,# $ ! ! %!,!,$ ! ,#! ,#,!, !  ! ,! $! ,!! $ '%%!,  !,#$   %%   ,!%!!#! $,#! !! # !  !".  , !!! % ''%%,,!.$.! !, !% ,! #! !, ,,  $ !!!!  % !!''%%! !$! !#% ,!  % !#! ,%,! ! "!,!!! %''%# #.!#", %!!!!!%, ,#! ,%# !  , ! $.! ,!  % !'%  #$  !#% , !!!#, !!$ # .#! , !$.,!! # ''%%,#,." ! !#$ , !,!!,# %$%!!#!,!%!*,# #!! % ''$%$$#!-%%",%"  !$$####, !#!"%%"%$"-% #$%% %"#"%%$%%$%$# '+/$-$$%%'$$*$*%%- -" $%%-%%! %%%$,% $$%$$%$$$% $ "(%%%%%%$%($-#*%%# '""$%%%'!$"($$ $$%+%$%$%$$%($$ %"%% !''/$ %$$%+''%(+'/''%(!!%$%# -%% #-$%%(%$%%$% %%%%$%$!%"/%$%%%%%blobby-1.0/src/LocalInputSource.h000644 001750 001750 00000002345 12313310253 021603 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "InputSource.h" #include "Global.h" class InputDevice; class LocalInputSource : public InputSource { public: LocalInputSource(PlayerSide player); ~LocalInputSource(); virtual PlayerInputAbs getNextInput(); private: InputDevice* mInputDevice; }; blobby-1.0/src/lua/lauxlib.h000644 001750 001750 00000016260 12313310253 020572 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lauxlib.h,v 1.120.1.1 2013/04/12 18:48:47 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ #ifndef lauxlib_h #define lauxlib_h #include #include #include "lua.h" /* extra error code for `luaL_load' */ #define LUA_ERRFILE (LUA_ERRERR+1) typedef struct luaL_Reg { const char *name; lua_CFunction func; } luaL_Reg; LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); #define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM) LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, size_t *l); LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, const char *def, size_t *l); LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, lua_Integer def); LUALIB_API lua_Unsigned (luaL_checkunsigned) (lua_State *L, int numArg); LUALIB_API lua_Unsigned (luaL_optunsigned) (lua_State *L, int numArg, lua_Unsigned def); LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); LUALIB_API void (luaL_checkany) (lua_State *L, int narg); LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); LUALIB_API void (luaL_where) (lua_State *L, int lvl); LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, const char *const lst[]); LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); LUALIB_API int (luaL_execresult) (lua_State *L, int stat); /* pre-defined references */ #define LUA_NOREF (-2) #define LUA_REFNIL (-1) LUALIB_API int (luaL_ref) (lua_State *L, int t); LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, const char *mode); #define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); LUALIB_API int (luaL_len) (lua_State *L, int idx); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, const char *msg, int level); LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, lua_CFunction openf, int glb); /* ** =============================================================== ** some useful macros ** =============================================================== */ #define luaL_newlibtable(L,l) \ lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) #define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) #define luaL_argcheck(L, cond,numarg,extramsg) \ ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) #define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) #define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) #define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) #define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) #define luaL_dofile(L, fn) \ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) #define luaL_dostring(L, s) \ (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) #define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ typedef struct luaL_Buffer { char *b; /* buffer address */ size_t size; /* buffer size */ size_t n; /* number of characters in buffer */ lua_State *L; char initb[LUAL_BUFFERSIZE]; /* initial buffer */ } luaL_Buffer; #define luaL_addchar(B,c) \ ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ ((B)->b[(B)->n++] = (c))) #define luaL_addsize(B,s) ((B)->n += (s)) LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); #define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) /* }====================================================== */ /* ** {====================================================== ** File handles for IO library ** ======================================================= */ /* ** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and ** initial structure 'luaL_Stream' (it may contain other fields ** after that initial structure). */ #define LUA_FILEHANDLE "FILE*" typedef struct luaL_Stream { FILE *f; /* stream (NULL for incompletely created streams) */ lua_CFunction closef; /* to close stream (NULL for closed streams) */ } luaL_Stream; /* }====================================================== */ /* compatibility with old module system */ #if defined(LUA_COMPAT_MODULE) LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname, int sizehint); LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, const luaL_Reg *l, int nup); #define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) #endif #endif blobby-1.0/src/lua/lopcodes.c000644 001750 001750 00000006004 12313310253 020730 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lopcodes.c,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ #define lopcodes_c #define LUA_CORE #include "lopcodes.h" /* ORDER OP */ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "MOVE", "LOADK", "LOADKX", "LOADBOOL", "LOADNIL", "GETUPVAL", "GETTABUP", "GETTABLE", "SETTABUP", "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", "ADD", "SUB", "MUL", "DIV", "MOD", "POW", "UNM", "NOT", "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL", "RETURN", "FORLOOP", "FORPREP", "TFORCALL", "TFORLOOP", "SETLIST", "CLOSURE", "VARARG", "EXTRAARG", NULL }; #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { /* T A B C mode opcode */ opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */ ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ }; blobby-1.0/src/UserConfig.cpp000644 001750 001750 00000015545 12313310251 020753 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "UserConfig.h" /* includes */ #include #include #include #include "tinyxml/tinyxml.h" #include "Global.h" #include "FileRead.h" #include "FileWrite.h" #include "PlayerIdentity.h" #include "LocalInputSource.h" #include "ScriptedInputSource.h" /* implementation */ std::map >& userConfigCache() { static std::map > cache; return cache; }; boost::shared_ptr IUserConfigReader::createUserConfigReader(const std::string& file) { // if we have this userconfig already cached, just return from cache std::map >:: iterator cfg_cached = userConfigCache().find(file); if( cfg_cached != userConfigCache().end() ) { return cfg_cached->second; } // otherwise, load user config... UserConfig* uc = new UserConfig(); uc->loadFile(file); boost::shared_ptr config(uc); // ... and add to cache userConfigCache()[file] = config; return config; } PlayerIdentity UserConfig::loadPlayerIdentity(PlayerSide side, bool force_human) { std::string prefix = side == LEFT_PLAYER ? "left" : "right"; std::string name = ""; // init local input if(force_human) { name = getString(prefix + "_player_name"); } else { name = getBool(prefix + "_player_human") ? getString(prefix + "_player_name") : getString(prefix + "_script_name") + ".lua"; } PlayerIdentity player = PlayerIdentity(name); player.setStaticColor( Color( getInteger(prefix + "_blobby_color_r"), getInteger(prefix + "_blobby_color_g"), getInteger(prefix + "_blobby_color_b") ) ); player.setOscillating(getBool(prefix + "_blobby_oscillate")); player.setPreferredSide((PlayerSide)getInteger("network_side")); return player; } bool UserConfig::loadFile(const std::string& filename) { boost::shared_ptr configDoc = FileRead::readXMLDocument(filename); if (configDoc->Error()) { std::cerr << "Warning: Parse error in " << filename; std::cerr << "!" << std::endl; } TiXmlElement* userConfigElem = configDoc->FirstChildElement("userconfig"); if (userConfigElem == NULL) return false; for (TiXmlElement* varElem = userConfigElem->FirstChildElement("var"); varElem != NULL; varElem = varElem->NextSiblingElement("var")) { std::string name, value; const char* c; c = varElem->Attribute("name"); if (c) name = c; c = varElem->Attribute("value"); if (c) value = c; createVar(name, value); } return true; } bool UserConfig::saveFile(const std::string& filename) const { // this trows an exception if the file could not be opened for writing FileWrite file(filename); const std::string xmlHeader = "\n\n\n"; const std::string xmlFooter = "\n\n"; file.write(xmlHeader); for (unsigned int i = 0; i < mVars.size(); ++i) { char writeBuffer[256]; int charsWritten = snprintf(writeBuffer, 256, "\t\n", mVars[i]->Name.c_str(), mVars[i]->Value.c_str()); file.write(writeBuffer, charsWritten); } file.write(xmlFooter); file.close(); // we have to make sure that we don't cache any outdated user configs auto cfg_cached = userConfigCache().find(filename); if( cfg_cached != userConfigCache().end() ) { userConfigCache().erase(cfg_cached); } return true; } float UserConfig::getFloat(const std::string& name, float default_value) const { auto var = checkVarByName(name); if (var) return std::atof( var->Value.c_str() ); return default_value; } std::string UserConfig::getString(const std::string& name, const std::string& default_value) const { auto var = checkVarByName(name); if (var) return var->Value; return default_value; } bool UserConfig::getBool(const std::string& name, bool default_value) const { auto var = checkVarByName(name); if (var) return (var->Value == "true") ? true : false;; return default_value; } int UserConfig::getInteger(const std::string& name, int default_value) const { auto var = checkVarByName(name); if (var) return std::atoi( var->Value.c_str() ); return default_value; } void UserConfig::setFloat(const std::string& name, float var) { char writeBuffer[256]; snprintf(writeBuffer, 256, "%f", var); setValue(name, writeBuffer); } void UserConfig::setString(const std::string& name, const std::string& var) { setValue(name, var); } void UserConfig::setBool(const std::string& name, bool var) { setValue(name, var ? "true" : "false"); } void UserConfig::setInteger(const std::string& name, int var) { char writeBuffer[256]; snprintf(writeBuffer, 256, "%d", var); setValue(name, writeBuffer); } UserConfigVar* UserConfig::createVar(const std::string& name, const std::string& value) { if (findVarByName(name)) return NULL; UserConfigVar *var = new UserConfigVar; var->Name = name; var->Value = value; mVars.push_back(var); return var; } void UserConfig::setValue(const std::string& name, const std::string& value) { UserConfigVar *var = findVarByName(name); if (!var) { std::cerr << "Warning: impossible to set value of " << "unknown configuration variable " << name << "\n Creating new variable" << std::endl; var = createVar(name, value); mChangeFlag = true; return; } if (var->Value != value) mChangeFlag = true; var->Value = value; } UserConfig::~UserConfig() { for (unsigned int i = 0; i < mVars.size(); ++i) delete mVars[i]; } UserConfigVar* UserConfig::checkVarByName(const std::string& name) const { auto var = findVarByName(name); if( !var ) { std::cerr << "Warning: impossible to get value of " << "unknown configuration variable " << name << std::endl; } return var; } UserConfigVar* UserConfig::findVarByName(const std::string& name) const { for (unsigned int i = 0; i < mVars.size(); ++i) if (mVars[i]->Name == name) return mVars[i]; return nullptr; } blobby-1.0/src/lua/lauxlib.c000644 001750 001750 00000065625 12313310253 020576 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lauxlib.c,v 1.248.1.1 2013/04/12 18:48:47 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ #include #include #include #include #include /* This file uses only the official API of Lua. ** Any function declared here could be written as an application function. */ #define lauxlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" /* ** {====================================================== ** Traceback ** ======================================================= */ #define LEVELS1 12 /* size of the first part of the stack */ #define LEVELS2 10 /* size of the second part of the stack */ /* ** search for 'objidx' in table at index -1. ** return 1 + string at top if find a good name. */ static int findfield (lua_State *L, int objidx, int level) { if (level == 0 || !lua_istable(L, -1)) return 0; /* not found */ lua_pushnil(L); /* start 'next' loop */ while (lua_next(L, -2)) { /* for each pair in table */ if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ if (lua_rawequal(L, objidx, -1)) { /* found object? */ lua_pop(L, 1); /* remove value (but keep name) */ return 1; } else if (findfield(L, objidx, level - 1)) { /* try recursively */ lua_remove(L, -2); /* remove table (but keep name) */ lua_pushliteral(L, "."); lua_insert(L, -2); /* place '.' between the two names */ lua_concat(L, 3); return 1; } } lua_pop(L, 1); /* remove value */ } return 0; /* not found */ } static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { int top = lua_gettop(L); lua_getinfo(L, "f", ar); /* push function */ lua_pushglobaltable(L); if (findfield(L, top + 1, 2)) { lua_copy(L, -1, top + 1); /* move name to proper place */ lua_pop(L, 2); /* remove pushed values */ return 1; } else { lua_settop(L, top); /* remove function and global table */ return 0; } } static void pushfuncname (lua_State *L, lua_Debug *ar) { if (*ar->namewhat != '\0') /* is there a name? */ lua_pushfstring(L, "function " LUA_QS, ar->name); else if (*ar->what == 'm') /* main? */ lua_pushliteral(L, "main chunk"); else if (*ar->what == 'C') { if (pushglobalfuncname(L, ar)) { lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); lua_remove(L, -2); /* remove name */ } else lua_pushliteral(L, "?"); } else lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); } static int countlevels (lua_State *L) { lua_Debug ar; int li = 1, le = 1; /* find an upper bound */ while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } /* do a binary search */ while (li < le) { int m = (li + le)/2; if (lua_getstack(L, m, &ar)) li = m + 1; else le = m; } return le - 1; } LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level) { lua_Debug ar; int top = lua_gettop(L); int numlevels = countlevels(L1); int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0; if (msg) lua_pushfstring(L, "%s\n", msg); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { if (level == mark) { /* too many levels? */ lua_pushliteral(L, "\n\t..."); /* add a '...' */ level = numlevels - LEVELS2; /* and skip to last ones */ } else { lua_getinfo(L1, "Slnt", &ar); lua_pushfstring(L, "\n\t%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); lua_pushliteral(L, " in "); pushfuncname(L, &ar); if (ar.istailcall) lua_pushliteral(L, "\n\t(...tail calls...)"); lua_concat(L, lua_gettop(L) - top); } } lua_concat(L, lua_gettop(L) - top); } /* }====================================================== */ /* ** {====================================================== ** Error-report functions ** ======================================================= */ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { lua_Debug ar; if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); lua_getinfo(L, "n", &ar); if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ if (narg == 0) /* error is in the self argument itself? */ return luaL_error(L, "calling " LUA_QS " on bad self (%s)", ar.name, extramsg); } if (ar.name == NULL) ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", narg, ar.name, extramsg); } static int typeerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg)); return luaL_argerror(L, narg, msg); } static void tag_error (lua_State *L, int narg, int tag) { typeerror(L, narg, lua_typename(L, tag)); } LUALIB_API void luaL_where (lua_State *L, int level) { lua_Debug ar; if (lua_getstack(L, level, &ar)) { /* check function at level */ lua_getinfo(L, "Sl", &ar); /* get info about it */ if (ar.currentline > 0) { /* is there info? */ lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); return; } } lua_pushliteral(L, ""); /* else, no information available... */ } LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); luaL_where(L, 1); lua_pushvfstring(L, fmt, argp); va_end(argp); lua_concat(L, 2); return lua_error(L); } LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { int en = errno; /* calls to Lua API may change this value */ if (stat) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); if (fname) lua_pushfstring(L, "%s: %s", fname, strerror(en)); else lua_pushstring(L, strerror(en)); lua_pushinteger(L, en); return 3; } } #if !defined(inspectstat) /* { */ #if defined(LUA_USE_POSIX) #include /* ** use appropriate macros to interpret 'pclose' return status */ #define inspectstat(stat,what) \ if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } #else #define inspectstat(stat,what) /* no op */ #endif #endif /* } */ LUALIB_API int luaL_execresult (lua_State *L, int stat) { const char *what = "exit"; /* type of termination */ if (stat == -1) /* error? */ return luaL_fileresult(L, 0, NULL); else { inspectstat(stat, what); /* interpret result */ if (*what == 'e' && stat == 0) /* successful termination? */ lua_pushboolean(L, 1); else lua_pushnil(L); lua_pushstring(L, what); lua_pushinteger(L, stat); return 3; /* return true/nil,what,code */ } } /* }====================================================== */ /* ** {====================================================== ** Userdata's metatable manipulation ** ======================================================= */ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { luaL_getmetatable(L, tname); /* try to get metatable */ if (!lua_isnil(L, -1)) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); lua_newtable(L); /* create metatable */ lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ return 1; } LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) { luaL_getmetatable(L, tname); lua_setmetatable(L, -2); } LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { void *p = lua_touserdata(L, ud); if (p != NULL) { /* value is a userdata? */ if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ luaL_getmetatable(L, tname); /* get correct metatable */ if (!lua_rawequal(L, -1, -2)) /* not the same? */ p = NULL; /* value is a userdata with wrong metatable */ lua_pop(L, 2); /* remove both metatables */ return p; } } return NULL; /* value is not a userdata with a metatable */ } LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { void *p = luaL_testudata(L, ud, tname); if (p == NULL) typeerror(L, ud, tname); return p; } /* }====================================================== */ /* ** {====================================================== ** Argument check functions ** ======================================================= */ LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) { const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg); int i; for (i=0; lst[i]; i++) if (strcmp(lst[i], name) == 0) return i; return luaL_argerror(L, narg, lua_pushfstring(L, "invalid option " LUA_QS, name)); } LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { /* keep some extra space to run error routines, if needed */ const int extra = LUA_MINSTACK; if (!lua_checkstack(L, space + extra)) { if (msg) luaL_error(L, "stack overflow (%s)", msg); else luaL_error(L, "stack overflow"); } } LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { if (lua_type(L, narg) != t) tag_error(L, narg, t); } LUALIB_API void luaL_checkany (lua_State *L, int narg) { if (lua_type(L, narg) == LUA_TNONE) luaL_argerror(L, narg, "value expected"); } LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { const char *s = lua_tolstring(L, narg, len); if (!s) tag_error(L, narg, LUA_TSTRING); return s; } LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, const char *def, size_t *len) { if (lua_isnoneornil(L, narg)) { if (len) *len = (def ? strlen(def) : 0); return def; } else return luaL_checklstring(L, narg, len); } LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { int isnum; lua_Number d = lua_tonumberx(L, narg, &isnum); if (!isnum) tag_error(L, narg, LUA_TNUMBER); return d; } LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { return luaL_opt(L, luaL_checknumber, narg, def); } LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { int isnum; lua_Integer d = lua_tointegerx(L, narg, &isnum); if (!isnum) tag_error(L, narg, LUA_TNUMBER); return d; } LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) { int isnum; lua_Unsigned d = lua_tounsignedx(L, narg, &isnum); if (!isnum) tag_error(L, narg, LUA_TNUMBER); return d; } LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, lua_Integer def) { return luaL_opt(L, luaL_checkinteger, narg, def); } LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg, lua_Unsigned def) { return luaL_opt(L, luaL_checkunsigned, narg, def); } /* }====================================================== */ /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ /* ** check whether buffer is using a userdata on the stack as a temporary ** buffer */ #define buffonstack(B) ((B)->b != (B)->initb) /* ** returns a pointer to a free area with at least 'sz' bytes */ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { lua_State *L = B->L; if (B->size - B->n < sz) { /* not enough space? */ char *newbuff; size_t newsize = B->size * 2; /* double buffer size */ if (newsize - B->n < sz) /* not big enough? */ newsize = B->n + sz; if (newsize < B->n || newsize - B->n < sz) luaL_error(L, "buffer too large"); /* create larger buffer */ newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char)); /* move content to new buffer */ memcpy(newbuff, B->b, B->n * sizeof(char)); if (buffonstack(B)) lua_remove(L, -2); /* remove old buffer */ B->b = newbuff; B->size = newsize; } return &B->b[B->n]; } LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { char *b = luaL_prepbuffsize(B, l); memcpy(b, s, l * sizeof(char)); luaL_addsize(B, l); } LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { luaL_addlstring(B, s, strlen(s)); } LUALIB_API void luaL_pushresult (luaL_Buffer *B) { lua_State *L = B->L; lua_pushlstring(L, B->b, B->n); if (buffonstack(B)) lua_remove(L, -2); /* remove old buffer */ } LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { luaL_addsize(B, sz); luaL_pushresult(B); } LUALIB_API void luaL_addvalue (luaL_Buffer *B) { lua_State *L = B->L; size_t l; const char *s = lua_tolstring(L, -1, &l); if (buffonstack(B)) lua_insert(L, -2); /* put value below buffer */ luaL_addlstring(B, s, l); lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ } LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { B->L = L; B->b = B->initb; B->n = 0; B->size = LUAL_BUFFERSIZE; } LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { luaL_buffinit(L, B); return luaL_prepbuffsize(B, sz); } /* }====================================================== */ /* ** {====================================================== ** Reference system ** ======================================================= */ /* index of free-list header */ #define freelist 0 LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; if (lua_isnil(L, -1)) { lua_pop(L, 1); /* remove from stack */ return LUA_REFNIL; /* `nil' has a unique fixed reference */ } t = lua_absindex(L, t); lua_rawgeti(L, t, freelist); /* get first free element */ ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ lua_pop(L, 1); /* remove it from stack */ if (ref != 0) { /* any free element? */ lua_rawgeti(L, t, ref); /* remove it from list */ lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ } else /* no free elements */ ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ lua_rawseti(L, t, ref); return ref; } LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { if (ref >= 0) { t = lua_absindex(L, t); lua_rawgeti(L, t, freelist); lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ lua_pushinteger(L, ref); lua_rawseti(L, t, freelist); /* t[freelist] = ref */ } } /* }====================================================== */ /* ** {====================================================== ** Load functions ** ======================================================= */ typedef struct LoadF { int n; /* number of pre-read characters */ FILE *f; /* file being read */ char buff[LUAL_BUFFERSIZE]; /* area for reading file */ } LoadF; static const char *getF (lua_State *L, void *ud, size_t *size) { LoadF *lf = (LoadF *)ud; (void)L; /* not used */ if (lf->n > 0) { /* are there pre-read characters to be read? */ *size = lf->n; /* return them (chars already in buffer) */ lf->n = 0; /* no more pre-read characters */ } else { /* read a block from file */ /* 'fread' can return > 0 *and* set the EOF flag. If next call to 'getF' called 'fread', it might still wait for user input. The next check avoids this problem. */ if (feof(lf->f)) return NULL; *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ } return lf->buff; } static int errfile (lua_State *L, const char *what, int fnameindex) { const char *serr = strerror(errno); const char *filename = lua_tostring(L, fnameindex) + 1; lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); lua_remove(L, fnameindex); return LUA_ERRFILE; } static int skipBOM (LoadF *lf) { const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */ int c; lf->n = 0; do { c = getc(lf->f); if (c == EOF || c != *(const unsigned char *)p++) return c; lf->buff[lf->n++] = c; /* to be read by the parser */ } while (*p != '\0'); lf->n = 0; /* prefix matched; discard it */ return getc(lf->f); /* return next character */ } /* ** reads the first character of file 'f' and skips an optional BOM mark ** in its beginning plus its first line if it starts with '#'. Returns ** true if it skipped the first line. In any case, '*cp' has the ** first "valid" character of the file (after the optional BOM and ** a first-line comment). */ static int skipcomment (LoadF *lf, int *cp) { int c = *cp = skipBOM(lf); if (c == '#') { /* first line is a comment (Unix exec. file)? */ do { /* skip first line */ c = getc(lf->f); } while (c != EOF && c != '\n') ; *cp = getc(lf->f); /* skip end-of-line, if present */ return 1; /* there was a comment */ } else return 0; /* no comment */ } LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode) { LoadF lf; int status, readstatus; int c; int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ if (filename == NULL) { lua_pushliteral(L, "=stdin"); lf.f = stdin; } else { lua_pushfstring(L, "@%s", filename); lf.f = fopen(filename, "r"); if (lf.f == NULL) return errfile(L, "open", fnameindex); } if (skipcomment(&lf, &c)) /* read initial portion */ lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); skipcomment(&lf, &c); /* re-read initial portion */ } if (c != EOF) lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { lua_settop(L, fnameindex); /* ignore results from `lua_load' */ return errfile(L, "read", fnameindex); } lua_remove(L, fnameindex); return status; } typedef struct LoadS { const char *s; size_t size; } LoadS; static const char *getS (lua_State *L, void *ud, size_t *size) { LoadS *ls = (LoadS *)ud; (void)L; /* not used */ if (ls->size == 0) return NULL; *size = ls->size; ls->size = 0; return ls->s; } LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, const char *name, const char *mode) { LoadS ls; ls.s = buff; ls.size = size; return lua_load(L, getS, &ls, name, mode); } LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { return luaL_loadbuffer(L, s, strlen(s), s); } /* }====================================================== */ LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ return 0; lua_pushstring(L, event); lua_rawget(L, -2); if (lua_isnil(L, -1)) { lua_pop(L, 2); /* remove metatable and metafield */ return 0; } else { lua_remove(L, -2); /* remove only metatable */ return 1; } } LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { obj = lua_absindex(L, obj); if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ return 0; lua_pushvalue(L, obj); lua_call(L, 1, 1); return 1; } LUALIB_API int luaL_len (lua_State *L, int idx) { int l; int isnum; lua_len(L, idx); l = (int)lua_tointegerx(L, -1, &isnum); if (!isnum) luaL_error(L, "object length is not a number"); lua_pop(L, 1); /* remove object */ return l; } LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ switch (lua_type(L, idx)) { case LUA_TNUMBER: case LUA_TSTRING: lua_pushvalue(L, idx); break; case LUA_TBOOLEAN: lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); break; case LUA_TNIL: lua_pushliteral(L, "nil"); break; default: lua_pushfstring(L, "%s: %p", luaL_typename(L, idx), lua_topointer(L, idx)); break; } } return lua_tolstring(L, -1, len); } /* ** {====================================================== ** Compatibility with 5.1 module functions ** ======================================================= */ #if defined(LUA_COMPAT_MODULE) static const char *luaL_findtable (lua_State *L, int idx, const char *fname, int szhint) { const char *e; if (idx) lua_pushvalue(L, idx); do { e = strchr(fname, '.'); if (e == NULL) e = fname + strlen(fname); lua_pushlstring(L, fname, e - fname); lua_rawget(L, -2); if (lua_isnil(L, -1)) { /* no such field? */ lua_pop(L, 1); /* remove this nil */ lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ lua_pushlstring(L, fname, e - fname); lua_pushvalue(L, -2); lua_settable(L, -4); /* set new table into field */ } else if (!lua_istable(L, -1)) { /* field has a non-table value? */ lua_pop(L, 2); /* remove table and value */ return fname; /* return problematic part of the name */ } lua_remove(L, -2); /* remove previous table */ fname = e + 1; } while (*e == '.'); return NULL; } /* ** Count number of elements in a luaL_Reg list. */ static int libsize (const luaL_Reg *l) { int size = 0; for (; l && l->name; l++) size++; return size; } /* ** Find or create a module table with a given name. The function ** first looks at the _LOADED table and, if that fails, try a ** global variable with that name. In any case, leaves on the stack ** the module table. */ LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname, int sizehint) { luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */ lua_getfield(L, -1, modname); /* get _LOADED[modname] */ if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ lua_pushglobaltable(L); if (luaL_findtable(L, 0, modname, sizehint) != NULL) luaL_error(L, "name conflict for module " LUA_QS, modname); lua_pushvalue(L, -1); lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */ } lua_remove(L, -2); /* remove _LOADED table */ } LUALIB_API void luaL_openlib (lua_State *L, const char *libname, const luaL_Reg *l, int nup) { luaL_checkversion(L); if (libname) { luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */ lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ } if (l) luaL_setfuncs(L, l, nup); else lua_pop(L, nup); /* remove upvalues */ } #endif /* }====================================================== */ /* ** set functions from list 'l' into table at top - 'nup'; each ** function gets the 'nup' elements at the top as upvalues. ** Returns with only the table at the stack. */ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { luaL_checkversion(L); luaL_checkstack(L, nup, "too many upvalues"); for (; l->name != NULL; l++) { /* fill the table with given functions */ int i; for (i = 0; i < nup; i++) /* copy upvalues to the top */ lua_pushvalue(L, -nup); lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ lua_setfield(L, -(nup + 2), l->name); } lua_pop(L, nup); /* remove upvalues */ } /* ** ensure that stack[idx][fname] has a table and push that table ** into the stack */ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { lua_getfield(L, idx, fname); if (lua_istable(L, -1)) return 1; /* table already there */ else { lua_pop(L, 1); /* remove previous result */ idx = lua_absindex(L, idx); lua_newtable(L); lua_pushvalue(L, -1); /* copy to be left at top */ lua_setfield(L, idx, fname); /* assign new table to field */ return 0; /* false, because did not find table there */ } } /* ** stripped-down 'require'. Calls 'openf' to open a module, ** registers the result in 'package.loaded' table and, if 'glb' ** is true, also registers the result in the global table. ** Leaves resulting module on the top. */ LUALIB_API void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb) { lua_pushcfunction(L, openf); lua_pushstring(L, modname); /* argument to open function */ lua_call(L, 1, 1); /* open module */ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_pushvalue(L, -2); /* make copy of module (call result) */ lua_setfield(L, -2, modname); /* _LOADED[modname] = module */ lua_pop(L, 1); /* remove _LOADED table */ if (glb) { lua_pushvalue(L, -1); /* copy of 'mod' */ lua_setglobal(L, modname); /* _G[modname] = module */ } } LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, const char *r) { const char *wild; size_t l = strlen(p); luaL_Buffer b; luaL_buffinit(L, &b); while ((wild = strstr(s, p)) != NULL) { luaL_addlstring(&b, s, wild - s); /* push prefix */ luaL_addstring(&b, r); /* push replacement in place of pattern */ s = wild + l; /* continue after `p' */ } luaL_addstring(&b, s); /* push last suffix */ luaL_pushresult(&b); return lua_tostring(L, -1); } static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; /* not used */ if (nsize == 0) { free(ptr); return NULL; } else return realloc(ptr, nsize); } static int panic (lua_State *L) { luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); return 0; /* return to Lua to abort */ } LUALIB_API lua_State *luaL_newstate (void) { lua_State *L = lua_newstate(l_alloc, NULL); if (L) lua_atpanic(L, &panic); return L; } LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) { const lua_Number *v = lua_version(L); if (v != lua_version(NULL)) luaL_error(L, "multiple Lua VMs detected"); else if (*v != ver) luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", ver, *v); /* check conversions number -> integer types */ lua_pushnumber(L, -(lua_Number)0x1234); if (lua_tointeger(L, -1) != -0x1234 || lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234) luaL_error(L, "bad conversion number->int;" " must recompile Lua with proper settings"); lua_pop(L, 1); } blobby-1.0/src/ReplayDefs.h000644 001750 001750 00000011221 12313310253 020377 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "ReplaySavePoint.h" const char validHeader[4] = { 'B', 'V', '2', 'R' }; //!< header of replay file const unsigned char REPLAY_FILE_VERSION_MAJOR = 1; const unsigned char REPLAY_FILE_VERSION_MINOR = 1; // 10 secs for normal gamespeed const int REPLAY_SAVEPOINT_PERIOD = 750; /*! \class ChecksumException \brief thrown when actual and expected file checksum mismatch */ struct ChecksumException : public std::exception { ChecksumException(std::string filename, uint32_t expected, uint32_t real); ~ChecksumException() throw(); virtual const char* what() const throw(); std::string error; }; /** \page replay_system Replay System \section rep_file_spec Replay File Specification Blobby Volley Replay files have the following structure:

Replay File V 1.x:
OffsetSizeValuesDescription
File Header
04 bytesbv2rReplay file header
44 bytes01xpFile version information. First byte ist always 0, second byte contains major version (1), x is minor version and p contains additional versioning information. \sa rep_versioning
84 byteschecksumcontains a checksum of the whole file
Replay Header
124 bytesintlength of this replay header in bytes
164 bytespointerPoints to the starting position of the attributes section
204 bytesintLength of attributes section
244 bytespointerPoints to the starting position of the jump table
284 bytesintLength of jump table section
324 bytespointerPoints to the starting position of the data section
364 bytesintLength of data section (bytes)
Attributes Section (AS)
AS+04 bytesatr\nAttribute beginning indicator
AS+44 bytesintGamespeed
AS+84 bytesintGame duration [sec]
AS+124 bytesintGame duration [steps]
AS+164 bytesintDate of match
AS+204 bytesintLeft player color
AS+244 bytesintRight player color
AS+284 bytesintLeft player score
AS+324 bytesintRight player score
AS+36stringstringLeft player name
...stringstringRight player name
...
Jump Table (JT)
JT+04 bytesjpt\nJump table beginning indicator
[currently undefined]
Data Section (DS)
DS+04 bytesjpt\nData beginning indicator
DS+44 bytesintLength of data section [steps]
DS+8...*Packetgame data
**/ blobby-1.0/data/gfx/font40.bmp000644 001750 001750 00000003370 12313310254 020717 0ustar00danielknobedanielknobe000000 000000 BM6( A[ <~ yW=*r^%%%% ]4J- YY{{wwkjQQ('O# KK!!b..?WWwrrge c &NNCC $$3hg}>:h &..OZZCJHi@7^aa)) g IGtrg0#%2KIFE  cYI47'@7WU 8F;aCQ9$L SQ1- ZD2fA[9"FEDOK  !<]:vHk=-L65ahc,$53M/qBdžP|F e_MD,L 7,h1%\, N7$aC'ze:|DBN4h]Xi\@.1& qR~Q}MyCEP͂H=$T<:]u_I@-8 rѴ︇p[J {aX;3#] oyШЕcCR!bobxtIK1z ,%0}k=w* 0'=Zh>!,"e8ӊ+6: tpJ@"R\80@D{`Ώc{7)0 t%~?0,LN=1C]4P Y-0.2MP*./+$!#h\6Ұ20/.ALB'uZzݟ{g`^jvh6 ##gKj|Êȿ~ÁǓ]W1Y%%blobby-1.0/data/scripts/old/hyp012.lua000644 001750 001750 00000026545 12313310254 022325 0ustar00danielknobedanielknobe000000 000000 g=0.28 pg=0.88 v0=14.5 v_p=4.5 pj=0.44 r1=31.5 h=31.5+19+25 estt=0 nettime=0 touch=0 est=0 p=math.random()/2+0.5 esto1=10 esto2=10 esto3=10 esto4=10 function yb(y,vy,t) return y+(vy-g/10)*t-1/2*g*t^2 end function move(x) if (posx()2.26) then right() elseif (posx()>x) and (math.abs(posx()-x)>2.26) then left() end end function tb(y,vy,height,typ) local sgn=0 if (typ==1) then sgn=-1 else sgn=1 end if vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g<0 then return -1 else return -1/10+vy/g+sgn*math.sqrt( vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g ) end end function time(t) return 1/5*math.ceil(5*t) end function pos(x) local x1,x2 x1=4.5*math.ceil((1/4.5)*x) x2=4.5*math.floor((1/4.5)*x) if (x1<0) or (x2<0) then return 0 else if (math.abs(x1-x)146) then return (v1p/0.88-1/2+math.sqrt((v1p/0.88-1/2)^2-(144.5-y1p)/0.44)) else return 0 end end function time(t) return 1/5*math.ceil(5*t) end -- function collide(x,y,vx,vy,objx,objy,r2) local t1=time(math.max(tb(y,vy,objy-(r1+r2),1)-0.2,0)) local t2=time(tb(y,vy,objy+(r1+r2),1)+0.2) local t3=time(math.max(tb(y,vy,objy+(r1+r2),2)-0.2,0)) local t4=time(tb(y,vy,objy-(r1+r2),2)+0.2) local t=-1 if (t1150) then t=-1 end return t end function estimate(x,y,vx,vy,height,typ) local collision=1 local tw,tn,ts=0,0,0 local tr,xr,yr,vxr,vyr,n=0,0,0,0,0,0 while(collision==1) do ts=collide(x,y,vx,vy,400,316,7) if (vx>0) then tw=time((768.5-x)/vx) tn=time((361.5-x)/vx) else tw=time((31.5-x)/vx) tn=time((438.5-x)/vx) end local th=time(tb(y,vy,height,typ)) local t=10000 if ((ts>0) and (ts0) and (tn0) and (twt) then if (t==ts) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vy=vy-g*t xr=x yr=y vxr=0 vyr=0 n=1 collision=0 elseif ((t==tn) or (t==tw)) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vx=-vx vy=vy-g*t collision=1 end else tr=tr+th vxr=vx vyr=vy-g*th xr=x+vx*th yr=yb(y,vy,th) collision=0 end end if (tr<0) then return -1,-1,-1,-1,-1,-1 else return xr,yr,vxr,vyr,tr,n end end function impact(x,y,vx,vy,xpos,ypos,targety,jump,move) local x1,y1,vx1,vy1=0,0,0,0 local x2,y2,vx2,vy2,t2,nn=0,0,0,0,0,0 local xpos1=xpos local ypos1=ypos for t=0,20,0.2 do if (jump==1) then ypos1=yp(tp(ypos)+t) end x1=x+vx*t if (x1<31.5) then x1=2*31.5-x1 end if (x1>368.5) then x1=2*368.5-x1 end y1=yb(y,vy,t) if ((xpos1-x1)^2+(ypos1+19-y1)^2<(31.5+25)^2) then local dx=x1-xpos1 local dy=y1-(ypos1+19) local l=math.sqrt(dx^2+dy^2) vx1=dx/l vy1=dy/l x1=x1+vx1*3 y1=y1+vy1*3 vy1=vy1*13.125 vx1=vx1*13.125 x2,y2,vx2,vy2,t2,nn=estimate(x1,y1,vx1,vy1,targety,2) break end end return x2,y2,x1,y1,vx1,vy1 end function lob() if (math.abs(est-esto2)>0.2) then esto2=est imp=0 x1=0 t=30 while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5730) and (math.abs(posx()-x1f)/4.50) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f break end if (impfimp) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t end if (imp>740) then break end end if (t>12) then t=t-6 else t=t-4 end end t2=t2+1 end t2=t2-1 if (x1>0) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else -- move(est) p=math.random() esto2=0 end end function attack() if (math.abs(est-esto1)>0.2) then h2=900 esto1=est imp=0 x1=0 t=30 while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(pos(x2f)+4.5))/4.5400) and (math.abs(posx()-x1f)/4.5+10) and (x1f<360) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f xat=xaf yat=yaf vxat=vxaf vyat=vyaf break end end h2t=yb(yat,vyat,(400-xat)/vxat) if (h2t316+31.5+10) then imp=impt x1=x1t y1=y1t t1=t1t x2=x2t y2=y2t t2=t2t vx2=vx2t vy2=vy2t xa=xat ya=yat vxa=vxat vya=vyat end h2=yb(ya,vya,(400-xa)/vxa) if (h2>316+31.5+10) and (h2<316+31.5+60) then break end end if (t>12) then t=t-6 else t=t-4 end end t2=t2+1 end t2=t2-1 if (x1>0) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else -- move(est-5) --p=0.9 p=math.random() esto1=0 end end function netp() if (math.abs(est-esto3)>0.2) then esto3=est imp=500 x1=0 for t=33,0,-3 do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,nn=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5380) and (math.abs(posx()-x1f)/4.50) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f break end end if (impt0) and (est<368.5) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else -- move(est-4.5) p=math.random() esto3=0 end end function playto(dest) --310 if (math.abs(est-esto4)>0.2) then x1,y1,t1,x2,y2,t2,vx2,vy2,x1f,y1f,t1f,x2f,y2f,t2f,vx2f,vy2f,x1t,y1t,t1t,x2t,y2t,t2t,vx2t,vy2t=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 t2g=0 -- debug(-10) esto4=est imp=500 x1=0 for t=33,0,-3 do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,nn=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(tp2(posy(),vp))1) and (t2f>1) and ((math.abs(posx()-(x2f+4.5))/4.5dest-30) and (impf0) then impt=impf x1t=x1f y1t=y1f t1t=t1f x2t=x2f y2t=y2f t2t=t2f vx2t=vx2f vy2t=vy2f break end end if (math.abs(impt-dest)0) and (est<368.5) then move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else -- move(est) p=math.random() esto4=0 end end function OnOpponentServe() pp=math.random() y1p=144.5 if (math.abs(pos(posx())-posx())>1) then move(400) else move(200) end valid=1 nettime=0 phase=0 imp1=0 imp2=0 imp=0 active=1 end function OnServe(ballready) pp=math.random() active=1 nettime=0 y1p=144.5 phase=0 est=700 imp1=0 imp2=0 imp=0 if (math.abs(pos(posx())-posx())>1) then move(400) else if (math.abs(posx()-198)<2) then jump() else move(198) end end valid=1 end function OnGame() yp2=y1p y1p=oppy() vp=y1p-yp2 if (math.abs(imp1-imp)>0.1) then imp2=imp1 imp1=imp end esttold=estt netold=net toucho=touch touch=touches() if (touch431.5) or (est<368.5)) then nettime=11 phase=4 elseif (phase==4) and (nettime>0) then nettime=nettime-1 else if (est>431.5) then phase=3 elseif (est<431.5) and (est>368.5) then phase=2 else phase=1 end end else phase=6 end if (bally()<130) then active=0 end if (math.sqrt((ballx()-400)^2+(bally()-316)^2)<(31.5+7)) and (math.sqrt((bspeedx())^2+(bspeedy())^2)<2) then phase=5 end if (phase==3) then move(170) elseif (phase==1) then if (p<0.5) then if (touch==0) then playto(310) elseif (touch==1) then if (p<0.2) then netp() elseif (p>=0.2) and (p<0.35) then playto(pp*300+450) elseif (p>=0.35) and (p<0.5) then attack() end else attack() end else if (touch==0) then if (p>=0.5) and (p<0.75) then playto(pp*300+450) elseif (p>=0.75) and (p<=1.0) then attack() end else attack() end end elseif (phase==2) then if (tnet<=tp(393)+1) or (nettime>0) then jump() end if (math.abs(posx()-360)/4.5-10<=tnet) then left() else right() end elseif (phase==4) then right() jump() elseif (phase==5) then if (posx()>300) then jump() end right() end if ((x1==0) or (imp==0)) and (phase==1) then -- debug(-1) move(est) end --debug(phase) end blobby-1.0/data/gfx/font32.bmp000644 001750 001750 00000003370 12313310254 020720 0ustar00danielknobedanielknobe000000 000000 BM6( &+[@.)0}Z %/3.wn>= (`. 1>.oBS <7 n7 ""3)]Ar  KP rL B- - H8>!Pd rlM=  -<- Z@b iNT,. /2 " s #G^Jv1? +#0 B&BWE3_/?)0 i #7-VG7(T!R27"  X -7S=ZD0 $O Y;>48# /&x1FHY*7mC -C&&b?@@C=? #o+?N7H?4 % j:;BBS:<?H$0*/PQe.L'c t/177J1[]-/ #G#+&X]fx1G'K~ #')DJK_`58$&#'8 lqbr2C4"%2mmde;<: +|]j1=($+99Zhh22!"O@AZO[(1{ $/ppSS))""nVX}=E %n  CO(7zz::&&hhgk+1z  btHX"u!!/ab-- km_c%" n]r(.XHHp~~==E"stWY(+ 1-2M  abeg$$x -LN"#NVV88blobby-1.0/src/SoundManager.cpp000644 001750 001750 00000015531 12313310252 021266 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "SoundManager.h" /* includes */ #include #include #include "Global.h" #include "FileRead.h" /* implementation */ SoundManager* SoundManager::mSingleton; Sound* SoundManager::loadSound(const std::string& filename) { FileRead file(filename); int fileLength = file.length(); // safe file data into a shared_array to ensure it is deleten properly // in case of exceptions boost::shared_array fileBuffer = file.readRawBytes( fileLength ); SDL_RWops* rwops = SDL_RWFromMem(fileBuffer.get(), fileLength); // we don't need the file handle anymore file.close(); SDL_AudioSpec newSoundSpec; Uint8* newSoundBuffer; Uint32 newSoundLength; if (!SDL_LoadWAV_RW(rwops , 1, &newSoundSpec, &newSoundBuffer, &newSoundLength)) BOOST_THROW_EXCEPTION(FileLoadException(filename)); // check if current audio format is target format if (newSoundSpec.freq == mAudioSpec.freq && newSoundSpec.format == mAudioSpec.format && newSoundSpec.channels == mAudioSpec.channels) { Sound *newSound = new Sound; newSound->data = new Uint8[newSoundLength]; memcpy(newSound->data, newSoundBuffer, newSoundLength); newSound->length = newSoundLength; newSound->position = 0; SDL_FreeWAV(newSoundBuffer); return newSound; } else // otherwise, convert audio { SDL_AudioCVT conversionStructure; if (!SDL_BuildAudioCVT(&conversionStructure, newSoundSpec.format, newSoundSpec.channels, newSoundSpec.freq, mAudioSpec.format, mAudioSpec.channels, mAudioSpec.freq)) BOOST_THROW_EXCEPTION ( FileLoadException(filename) ); conversionStructure.buf = new Uint8[newSoundLength * conversionStructure.len_mult]; memcpy(conversionStructure.buf, newSoundBuffer, newSoundLength); conversionStructure.len = newSoundLength; if (SDL_ConvertAudio(&conversionStructure)) BOOST_THROW_EXCEPTION ( FileLoadException(filename) ); SDL_FreeWAV(newSoundBuffer); Sound *newSound = new Sound; newSound->data = conversionStructure.buf; newSound->length = Uint32(conversionStructure.len_cvt); newSound->position = 0; return newSound; } } bool SoundManager::playSound(const std::string& filename, float volume) { if (!mInitialised) return false; // everything is fine, so we return true // but we don't need to play the sound if( mMute ) return true; try { Sound* soundBuffer = mSound[filename]; if (!soundBuffer) { soundBuffer = loadSound(filename); mSound[filename] = soundBuffer; } Sound soundInstance = Sound(*soundBuffer); soundInstance.volume = volume > 0.0 ? (volume < 1.0 ? volume : 1.0) : 0.0; SDL_LockAudioDevice(mAudioDevice); mPlayingSound.push_back(soundInstance); SDL_UnlockAudioDevice(mAudioDevice); } catch (const FileLoadException& exception) { std::cerr << "Warning: " << exception.what() << std::endl; return false; } return true; } bool SoundManager::init() { SDL_AudioSpec desiredSpec; desiredSpec.freq = 44100; desiredSpec.format = AUDIO_S16LSB; desiredSpec.channels = 2; desiredSpec.samples = 1024; desiredSpec.callback = playCallback; desiredSpec.userdata = mSingleton; mAudioDevice = SDL_OpenAudioDevice(NULL, 0, &desiredSpec, &mAudioSpec, SDL_AUDIO_ALLOW_FORMAT_CHANGE); if (desiredSpec.format != mAudioSpec.format) { std::cerr << "Warning: Can't create device with desired audio spec!" << std::endl; std::cerr << "Reason: " << SDL_GetError() << std::endl; } if (mAudioDevice == 0) { std::cerr << "Warning: Couldn't open audio Device!" << std::endl; std::cerr << "Reason: " << SDL_GetError() << std::endl; return false; } SDL_PauseAudioDevice(mAudioDevice, 0); mInitialised = true; mVolume = 1.0; return true; } void SoundManager::playCallback(void* singleton, Uint8* stream, int length) { SDL_memset(stream, 0, length); std::list& playingSound = ((SoundManager*)singleton)->mPlayingSound; int volume = int(SDL_MIX_MAXVOLUME * ((SoundManager*)singleton)->mVolume); for (auto iter = playingSound.begin(); iter != playingSound.end(); ++iter) { int bytesLeft = iter->length - iter->position; if (bytesLeft < length) { SDL_MixAudio(stream, iter->data + iter->position, bytesLeft, int(volume * iter->volume)); auto eraseIter = iter; auto nextIter = ++iter; playingSound.erase(eraseIter); iter = nextIter; // prevents increment of past-end-interator if(iter == playingSound.end()) break; } else { SDL_MixAudioFormat(stream, iter->data + iter->position, mSingleton->mAudioSpec.format, length, int(volume * iter->volume)); iter->position += length; } } } void SoundManager::deinit() { for (std::map::iterator iter = mSound.begin(); iter != mSound.end(); ++iter) { if (iter->second) { if (iter->second->data != 0) { delete[] iter->second->data; } delete iter->second; } } SDL_UnlockAudioDevice(mAudioDevice); SDL_CloseAudioDevice(mAudioDevice); mInitialised = false; } SoundManager* SoundManager::createSoundManager() { return new SoundManager(); } SoundManager::SoundManager() { mMute = false; mSingleton = this; mInitialised = false; mAudioDevice = 0; } SoundManager::~SoundManager() { if (mInitialised) { deinit(); } } SoundManager& SoundManager::getSingleton() { assert(mSingleton); return *mSingleton; } void SoundManager::setVolume(float volume) { volume = volume > 0.0 ? (volume < 1.0 ? volume : 1.0) : 0.0; mVolume = volume; } void SoundManager::setMute(bool mute) { // don't do anything if mute is set. // this prevents the crash under xp when mute is set to false, as the second call to SDL_PauseAudio(false) // never returns in that case. if( mute == mMute ) return; static bool locked = false; if (mute) { if (!locked) //locking audio twice leads to a bug(??) { locked = true; SDL_LockAudioDevice(mAudioDevice); } } else { mPlayingSound.clear(); SDL_UnlockAudioDevice(mAudioDevice); locked = false; } mMute = mute; SDL_PauseAudioDevice(mAudioDevice, (int)mute); } blobby-1.0/src/lua/lbitlib.c000644 001750 001750 00000010426 12313310253 020544 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lbitlib.c,v 1.18.1.2 2013/07/09 18:01:41 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ #define lbitlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* number of bits to consider in a number */ #if !defined(LUA_NBITS) #define LUA_NBITS 32 #endif #define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) /* macro to trim extra bits */ #define trim(x) ((x) & ALLONES) /* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ #define mask(n) (~((ALLONES << 1) << ((n) - 1))) typedef lua_Unsigned b_uint; static b_uint andaux (lua_State *L) { int i, n = lua_gettop(L); b_uint r = ~(b_uint)0; for (i = 1; i <= n; i++) r &= luaL_checkunsigned(L, i); return trim(r); } static int b_and (lua_State *L) { b_uint r = andaux(L); lua_pushunsigned(L, r); return 1; } static int b_test (lua_State *L) { b_uint r = andaux(L); lua_pushboolean(L, r != 0); return 1; } static int b_or (lua_State *L) { int i, n = lua_gettop(L); b_uint r = 0; for (i = 1; i <= n; i++) r |= luaL_checkunsigned(L, i); lua_pushunsigned(L, trim(r)); return 1; } static int b_xor (lua_State *L) { int i, n = lua_gettop(L); b_uint r = 0; for (i = 1; i <= n; i++) r ^= luaL_checkunsigned(L, i); lua_pushunsigned(L, trim(r)); return 1; } static int b_not (lua_State *L) { b_uint r = ~luaL_checkunsigned(L, 1); lua_pushunsigned(L, trim(r)); return 1; } static int b_shift (lua_State *L, b_uint r, int i) { if (i < 0) { /* shift right? */ i = -i; r = trim(r); if (i >= LUA_NBITS) r = 0; else r >>= i; } else { /* shift left */ if (i >= LUA_NBITS) r = 0; else r <<= i; r = trim(r); } lua_pushunsigned(L, r); return 1; } static int b_lshift (lua_State *L) { return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2)); } static int b_rshift (lua_State *L) { return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2)); } static int b_arshift (lua_State *L) { b_uint r = luaL_checkunsigned(L, 1); int i = luaL_checkint(L, 2); if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1)))) return b_shift(L, r, -i); else { /* arithmetic shift for 'negative' number */ if (i >= LUA_NBITS) r = ALLONES; else r = trim((r >> i) | ~(~(b_uint)0 >> i)); /* add signal bit */ lua_pushunsigned(L, r); return 1; } } static int b_rot (lua_State *L, int i) { b_uint r = luaL_checkunsigned(L, 1); i &= (LUA_NBITS - 1); /* i = i % NBITS */ r = trim(r); if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ r = (r << i) | (r >> (LUA_NBITS - i)); lua_pushunsigned(L, trim(r)); return 1; } static int b_lrot (lua_State *L) { return b_rot(L, luaL_checkint(L, 2)); } static int b_rrot (lua_State *L) { return b_rot(L, -luaL_checkint(L, 2)); } /* ** get field and width arguments for field-manipulation functions, ** checking whether they are valid. ** ('luaL_error' called without 'return' to avoid later warnings about ** 'width' being used uninitialized.) */ static int fieldargs (lua_State *L, int farg, int *width) { int f = luaL_checkint(L, farg); int w = luaL_optint(L, farg + 1, 1); luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); if (f + w > LUA_NBITS) luaL_error(L, "trying to access non-existent bits"); *width = w; return f; } static int b_extract (lua_State *L) { int w; b_uint r = luaL_checkunsigned(L, 1); int f = fieldargs(L, 2, &w); r = (r >> f) & mask(w); lua_pushunsigned(L, r); return 1; } static int b_replace (lua_State *L) { int w; b_uint r = luaL_checkunsigned(L, 1); b_uint v = luaL_checkunsigned(L, 2); int f = fieldargs(L, 3, &w); int m = mask(w); v &= m; /* erase bits outside given width */ r = (r & ~(m << f)) | (v << f); lua_pushunsigned(L, r); return 1; } static const luaL_Reg bitlib[] = { {"arshift", b_arshift}, {"band", b_and}, {"bnot", b_not}, {"bor", b_or}, {"bxor", b_xor}, {"btest", b_test}, {"extract", b_extract}, {"lrotate", b_lrot}, {"lshift", b_lshift}, {"replace", b_replace}, {"rrotate", b_rrot}, {"rshift", b_rshift}, {NULL, NULL} }; LUAMOD_API int luaopen_bit32 (lua_State *L) { luaL_newlib(L, bitlib); return 1; } blobby-1.0/src/LocalInputSource.cpp000644 001750 001750 00000002755 12313310253 022143 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "LocalInputSource.h" /* include */ #include "InputManager.h" #include "RenderManager.h" #include "InputDevice.h" /* implementation */ LocalInputSource::LocalInputSource(PlayerSide player) { mInputDevice = InputManager::getSingleton()->beginGame(player); } LocalInputSource::~LocalInputSource() { RenderManager::getSingleton().setMouseMarker(-6); delete mInputDevice; } PlayerInputAbs LocalInputSource::getNextInput() { return mInputDevice->transferInput( ); } blobby-1.0/src/raknet/RakPeer.cpp000644 001750 001750 00000253070 12313310247 021526 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief RakPeer Implementation * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "RakPeer.h" #include "NetworkTypes.h" #ifdef _WIN32 #include #else #define closesocket close #include #include #endif #include // toupper #include "GetTime.h" #include "PacketEnumerations.h" #include "PacketPool.h" // alloca #ifdef _WIN32 #include #else #include #endif #include // On a Little-endian machine the RSA key and message are mangled, but we're // trying to be friendly to the little endians, so we do byte order // mangling on Big-Endian machines. Note that this mangling is independent // of the byte order used on the network (which also defaults to little-end). #ifdef HOST_ENDIAN_IS_BIG void __inline BSWAPCPY(unsigned char *dest, unsigned char *source, int bytesize) { #ifdef _DEBUG assert( (bytesize % 4 == 0)&&(bytesize)&& "Something is wrong with your exponent or modulus size."); #endif int i; for (i=0; i=0 for how many ms to Sleep each internal update cycle (recommended 30 for low performance, 0 for regular) // forceHostAddress Can force RakNet to use a particular IP to host on. Pass 0 to automatically pick an IP // Returns: // False on failure (can't create socket or thread), true on success. // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::Initialize( unsigned short MaximumNumberOfPeers, unsigned short localPort, int _threadSleepTimer, const char *forceHostAddress ) { // Maximum number of peers must be > 0 assert(MaximumNumberOfPeers > 0); if (MaximumNumberOfPeers <= 0) { return false; } if ( connectionSocket == INVALID_SOCKET ) { connectionSocket = SocketLayer::Instance()->CreateBoundSocket( localPort, true, forceHostAddress ); if ( connectionSocket == INVALID_SOCKET ) return false; } if ( _threadSleepTimer < 0 ) return false; if ( maximumNumberOfPeers == 0 ) { // Don't allow more incoming connections than we have peers. if ( maximumIncomingConnections > MaximumNumberOfPeers ) maximumIncomingConnections = MaximumNumberOfPeers; maximumNumberOfPeers = MaximumNumberOfPeers; // Allocate a few extra remote systems to handle new connections from players trying to connect when the server is full remoteSystemListSize = MaximumNumberOfPeers + 1 + MaximumNumberOfPeers/8; // rakPeerMutexes[ RakPeer::remoteSystemList_Mutex ].Lock(); remoteSystemList = new RemoteSystemStruct[ remoteSystemListSize ]; // rakPeerMutexes[ RakPeer::remoteSystemList_Mutex ].Unlock(); for ( unsigned i = 0; i < remoteSystemListSize; i++ ) { remoteSystemList[ i ].playerId = UNASSIGNED_PLAYER_ID; // remoteSystemList[ i ].allowPlayerIdAssigment=true; } } // For histogram statistics // nextReadBytesTime=0; // lastSentBytes=lastReceivedBytes=0; if ( endThreads ) { lastUserUpdateCycle = 0; updateCycleIsRunning = false; endThreads = false; // Create the threads threadSleepTimer = _threadSleepTimer; ClearBufferedCommands(); char ipList[ 10 ][ 16 ]; SocketLayer::Instance()->GetMyIP( ipList ); myPlayerId.port = localPort; myPlayerId.binaryAddress = inet_addr( ipList[ 0 ] ); { #ifdef _WIN32 if ( isMainLoopThreadActive == false ) { unsigned ProcessPacketsThreadID = 0; processPacketsThreadHandle = ( HANDLE ) _beginthreadex( NULL, 0, UpdateNetworkLoop, this, 0, &ProcessPacketsThreadID ); if ( processPacketsThreadHandle == 0 ) { Disconnect( 0 ); return false; } // SetThreadPriority(processPacketsThreadHandle, THREAD_PRIORITY_HIGHEST); CloseHandle( processPacketsThreadHandle ); processPacketsThreadHandle = 0; } #else pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); // sched_param sp; // sp.sched_priority = sched_get_priority_max(SCHED_OTHER); // pthread_attr_setschedparam(&attr, &sp); if ( isMainLoopThreadActive == false ) { int error = pthread_create( &processPacketsThreadHandle, &attr, &UpdateNetworkLoop, this ); if ( error ) { Disconnect( 0 ); return false; } } processPacketsThreadHandle = 0; #endif // Wait for the threads to activate. When they are active they will set these variables to true while ( /*isRecvfromThreadActive==false || */isMainLoopThreadActive == false ) #ifdef _WIN32 Sleep( 10 ); #else usleep( 10 * 1000 ); #endif } } return true; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Sets how many incoming connections are allowed. If this is less than the number of players currently connected, no // more players will be allowed to connect. If this is greater than the maximum number of peers allowed, it will be reduced // to the maximum number of peers allowed. Defaults to 0. // // Parameters: // numberAllowed - Maximum number of incoming connections allowed. // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::SetMaximumIncomingConnections( unsigned short numberAllowed ) { maximumIncomingConnections = numberAllowed; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Returns the maximum number of incoming connections, which is always <= MaximumNumberOfPeers // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- unsigned short RakPeer::GetMaximumIncomingConnections( void ) const { return maximumIncomingConnections; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Call this to connect to the specified host (ip or domain name) and server port. // Calling Connect and not calling SetMaximumIncomingConnections acts as a dedicated client. Calling both acts as a true peer. // This is a non-blocking connection. You know the connection is successful when IsConnected() returns true // or receive gets a packet with the type identifier ID_CONNECTION_ACCEPTED. If the connection is not // successful, such as rejected connection or no response then neither of these things will happen. // Requires that you first call Initialize // // Parameters: // host: Either a dotted IP address or a domain name // remotePort: Which port to connect to on the remote machine. // passwordData: A data block that must match the data block on the server. This can be just a password, or can be a stream of data // passwordDataLength: The length in bytes of passwordData // // Returns: // True on successful initiation. False on incorrect parameters, internal error, or too many existing peers // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::Connect( const char* host, unsigned short remotePort ) { // If endThreads is true here you didn't call Initialize() first. if ( host == 0 || endThreads || connectionSocket == INVALID_SOCKET ) return false; // If the host starts with something other than 0, 1, or 2 it's (probably) a domain name. if ( host[ 0 ] < '0' || host[ 0 ] > '2' ) { host = ( char* ) SocketLayer::Instance()->DomainNameToIP( host ); if (host==0) return false; } // Connecting to ourselves in the same instance of the program? if ( ( strcmp( host, "127.0.0.1" ) == 0 || strcmp( host, "0.0.0.0" ) == 0 ) && remotePort == myPlayerId.port ) { // Feedback loop. if ( !AllowIncomingConnections() ) { // Tell the game that this person has connected Packet * p; p = packetPool.GetPointer(); p->data = new unsigned char [ 1 ]; p->data[ 0 ] = (unsigned char) ID_NO_FREE_INCOMING_CONNECTIONS; p->playerId = myPlayerId; p->playerIndex = ( PlayerIndex ) GetIndexFromPlayerID( myPlayerId ); p->length = 1; p->bitSize = 8; #ifdef _DEBUG assert( p->data ); #endif incomingQueueMutex.Lock(); incomingPacketQueue.push( p ); incomingQueueMutex.Unlock(); } else { // Just assume we are connected. This is really just for testing. // RemoteSystemStruct* remoteSystem = AssignPlayerIDToRemoteSystemList( myPlayerId, RemoteSystemStruct::CONNECTED ); // if ( remoteSystem != 0 ) // { RakNet::BitStream bitStream(sizeof(unsigned char)+sizeof(unsigned int)+sizeof(unsigned short)); bitStream.Write((unsigned char)ID_NEW_INCOMING_CONNECTION); bitStream.Write(myPlayerId.binaryAddress); bitStream.Write(myPlayerId.port); // Send( &bitStream, SYSTEM_PRIORITY, RELIABLE, 0, myPlayerId, false ); SendBuffered(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, myPlayerId, false, RemoteSystemStruct::CONNECTED); return true; // } // else // return false; } } return SendConnectionRequest( host, remotePort ); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Stops the network threads and close all connections. Multiple calls are ok. // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::Disconnect( unsigned int blockDuration ) { unsigned i; unsigned short systemListSize = remoteSystemListSize; // This is done for threading reasons if ( blockDuration > 0 ) { for ( i = 0; i < systemListSize; i++ ) { NotifyAndFlagForDisconnect(remoteSystemList[i].playerId, false); } unsigned time = RakNet::GetTime(); unsigned stopWaitingTime = time + blockDuration; while ( time < stopWaitingTime ) { bool anyActive = false; for (unsigned j = 0; j < systemListSize; j++) { if (remoteSystemList[j].playerId!=UNASSIGNED_PLAYER_ID) { anyActive=true; break; } } // If this system is out of packets to send, then stop waiting if ( anyActive==false ) break; // This will probably cause the update thread to run which will probably // send the disconnection notification #ifdef _WIN32 Sleep( 15 ); #else usleep( 15 * 1000 ); #endif time = RakNet::GetTime(); } } if ( endThreads == false ) { // Stop the threads endThreads = true; // Normally the thread will call DecreaseUserCount on termination but if we aren't using threads just do it // manually } while ( isMainLoopThreadActive ) #ifdef _WIN32 Sleep( 15 ); #else usleep( 15 * 1000 ); #endif // Reset the remote system list after the threads are known to have stopped so threads do not add or update data to them after they are reset //rakPeerMutexes[ RakPeer::remoteSystemList_Mutex ].Lock(); for ( i = 0; i < systemListSize; i++ ) { // Reserve this reliability layer for ourselves remoteSystemList[ i ].playerId = UNASSIGNED_PLAYER_ID; // Remove any remaining packets remoteSystemList[ i ].reliabilityLayer.Reset(); } //rakPeerMutexes[ remoteSystemList_Mutex ].Unlock(); // Setting maximumNumberOfPeers to 0 allows remoteSystemList to be reallocated in Initialize. // Setting remoteSystemListSize prevents threads from accessing the reliability layer maximumNumberOfPeers = 0; remoteSystemListSize = 0; if ( connectionSocket != INVALID_SOCKET ) { closesocket( connectionSocket ); connectionSocket = INVALID_SOCKET; } // Clear out the queues while ( incomingPacketQueue.size() ) packetPool.ReleasePointer( incomingPacketQueue.pop() ); ClearBufferedCommands(); bytesSentPerSecond = bytesReceivedPerSecond = 0; ClearRequestedConnectionList(); // Clear out the reliabilty layer list in case we want to reallocate it in a successive call to Init. RemoteSystemStruct * temp = remoteSystemList; remoteSystemList = 0; delete [] temp; packetPool.ClearPool(); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Returns true if the network threads are running // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::IsActive( void ) const { return endThreads == false; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Fills the array remoteSystems with the playerID of all the systems we are connected to // // Parameters: // remoteSystems (out): An array of PlayerID structures to be filled with the PlayerIDs of the systems we are connected to // - pass 0 to remoteSystems to only get the number of systems we are connected to // numberOfSystems (int, out): As input, the size of remoteSystems array. As output, the number of elements put into the array // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::GetConnectionList( PlayerID *remoteSystems, unsigned short *numberOfSystems ) const { int count, index; count=0; if ( remoteSystemList == 0 || endThreads == true ) { *numberOfSystems = 0; return false; } // This is called a lot so I unrolled the loop if ( remoteSystems ) { for ( count = 0, index = 0; index < remoteSystemListSize; ++index ) if ( remoteSystemList[ index ].playerId != UNASSIGNED_PLAYER_ID && remoteSystemList[ index ].connectMode==RemoteSystemStruct::CONNECTED) { if ( count < *numberOfSystems ) remoteSystems[ count ] = remoteSystemList[ index ].playerId; ++count; } } else { for ( count = 0, index = 0; index < remoteSystemListSize; ++index ) if ( remoteSystemList[ index ].playerId != UNASSIGNED_PLAYER_ID && remoteSystemList[ index ].connectMode==RemoteSystemStruct::CONNECTED) ++count; } *numberOfSystems = ( unsigned short ) count; return 0; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Sends a block of data to the specified system that you are connected to. // This function only works while the client is connected (Use the Connect function). // // Parameters: // data: The block of data to send // length: The size in bytes of the data to send // bitStream: The bitstream to send // priority: What priority level to send on. // reliability: How reliability to send this data // orderingChannel: When using ordered or sequenced packets, what channel to order these on. // - Packets are only ordered relative to other packets on the same stream // playerId: Who to send this packet to, or in the case of broadcasting who not to send it to. Use UNASSIGNED_PLAYER_ID to specify none // broadcast: True to send this packet to all connected systems. If true, then playerId specifies who not to send the packet to. // Returns: // False if we are not connected to the specified recipient. True otherwise // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::Send( const char *data, const long length, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId, bool broadcast ) { #ifdef _DEBUG assert( data && length > 0 ); #endif if ( data == 0 || length < 0 ) return false; RakNet::BitStream temp( (char*)data, length, false ); return Send( &temp, priority, reliability, orderingChannel, playerId, broadcast ); } bool RakPeer::Send( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId, bool broadcast ) { #ifdef _DEBUG assert( bitStream->GetNumberOfBytesUsed() > 0 ); #endif if ( bitStream->GetNumberOfBytesUsed() == 0 ) return false; if ( remoteSystemList == 0 || endThreads == true ) return false; if ( broadcast == false && playerId == UNASSIGNED_PLAYER_ID ) return false; if (ValidSendTarget(playerId, broadcast)) { // Sends need to be buffered and processed in the update thread because the playerID associated with the reliability layer can change, // from that thread, resulting in a send to the wrong player! While I could mutex the playerID, that is much slower than doing this SendBuffered(bitStream, priority, reliability, orderingChannel, playerId, broadcast, RemoteSystemStruct::NO_ACTION); return true; } return false; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Gets a packet from the incoming packet queue. Use DeallocatePacket to deallocate the packet after you are done with it. // Check the Packet struct at the top of CoreNetworkStructures.h for the format of the struct // // Returns: // 0 if no packets are waiting to be handled, otherwise an allocated packet // If the client is not active this will also return 0, as all waiting packets are flushed when the client is Disconnected // This also updates all memory blocks associated with synchronized memory and distributed objects // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- packet_ptr RakPeer::Receive( void ) { if ( !( IsActive() ) ) return packet_ptr(); Packet *val; #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant while ( true ) { if (incomingPacketQueue.size() > 0) // First fast unlocked check { incomingQueueMutex.Lock(); if ( incomingPacketQueue.size() > 0 ) // Second safe locked check { val = incomingPacketQueue.pop(); } else { incomingQueueMutex.Unlock(); return packet_ptr(); } incomingQueueMutex.Unlock(); } else return packet_ptr(); break; } #ifdef _DEBUG assert( val->data ); #endif struct deleter { RakPeer* peer; void operator()(Packet* p) { if ( p == 0 ) return ; peer->packetPool.ReleasePointer( p ); } }; deleter del; del.peer = this; return packet_ptr(val, del); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Return the total number of connections we are allowed // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- unsigned short RakPeer::GetMaximumNumberOfPeers( void ) const { return maximumNumberOfPeers; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Close the connection to another host (if we initiated the connection it will disconnect, if they did it will kick them out). // // Parameters: // target: Which connection to close // sendDisconnectionNotification: True to send ID_DISCONNECTION_NOTIFICATION to the recipient. False to close it silently. // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::CloseConnection( PlayerID target, bool sendDisconnectionNotification ) { CloseConnectionInternalBuffered(target, sendDisconnectionNotification); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Given a playerID, returns an index from 0 to the maximum number of players allowed - 1. // // Parameters // playerId - The playerID to search for // // Returns // An integer from 0 to the maximum number of peers -1, or -1 if that player is not found // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- int RakPeer::GetIndexFromPlayerID( PlayerID playerId ) { unsigned i; if ( playerId == UNASSIGNED_PLAYER_ID ) return -1; for ( i = 0; i < maximumNumberOfPeers; i++ ) if ( remoteSystemList[ i ].playerId == playerId ) return i; return -1; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // This function is only useful for looping through all players. // // Parameters // index - an integer between 0 and the maximum number of players allowed - 1. // // Returns // A valid playerID or UNASSIGNED_PLAYER_ID if no such player at that index // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- PlayerID RakPeer::GetPlayerIDFromIndex( int index ) { if ( index >= 0 && index < remoteSystemListSize ) if (remoteSystemList[ index ].connectMode==RakPeer::RemoteSystemStruct::CONNECTED) // Don't give the user players that aren't fully connected, since sends will fail return remoteSystemList[ index ].playerId; return UNASSIGNED_PLAYER_ID; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Send a ping to the specified connected system. // // Parameters: // target - who to ping // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::Ping( PlayerID target ) { PingInternal(target, false); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Send a ping to the specified unconnected system. // The remote system, if it is Initialized, will respond with ID_PONG. // The final ping time will be encoded in the following 4 bytes (2-5) as an unsigned int // // Requires: // The sender and recipient must already be started via a successful call to Initialize // // Parameters: // host: Either a dotted IP address or a domain name. Can be 255.255.255.255 for LAN broadcast. // remotePort: Which port to connect to on the remote machine. // onlyReplyOnAcceptingConnections: Only request a reply if the remote system has open connections // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::Ping( const char* host, unsigned short remotePort, bool onlyReplyOnAcceptingConnections ) { if ( host == 0 ) return; if ( IsActive() == false ) return; // If the host starts with something other than 0, 1, or 2 it's (probably) a domain name. if ( host[ 0 ] < '0' || host[ 0 ] > '2' ) { host = ( char* ) SocketLayer::Instance()->DomainNameToIP( host ); } if ( host == NULL ) return; PlayerID playerId; IPToPlayerID( host, remotePort, &playerId ); // disabled so can send while shutting down // if (GetRemoteSystemFromPlayerID(playerId)) // return; if (strcmp(host, "255.255.255.255")==0) { RakNet::BitStream bitStream( sizeof(unsigned char) + sizeof(unsigned int) ); if ( onlyReplyOnAcceptingConnections ) bitStream.Write((unsigned char)ID_UNCONNECTED_PING_OPEN_CONNECTIONS); else bitStream.Write((unsigned char)ID_UNCONNECTED_PING); // No timestamp for 255.255.255.255 SocketLayer::Instance()->SendTo( connectionSocket, (const char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed(), ( char* ) host, remotePort ); } else { RequestedConnectionStruct *rcs = requestedConnectionList.WriteLock(); rcs->playerId=playerId; rcs->nextRequestTime=RakNet::GetTime(); rcs->requestsMade=0; rcs->data=0; if (onlyReplyOnAcceptingConnections) rcs->actionToTake=RequestedConnectionStruct::PING_OPEN_CONNECTIONS; else rcs->actionToTake=RequestedConnectionStruct::PING; requestedConnectionList.WriteUnlock(); } } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Returns the last ping time read for the specific player or -1 if none read yet // // Parameters: // target - whose time to read // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- int RakPeer::GetLastPing( PlayerID playerId ) const { RemoteSystemStruct * remoteSystem = GetRemoteSystemFromPlayerID( playerId ); if ( remoteSystem == 0 ) return -1; return remoteSystem->pingTime; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Returns the lowest ping time read or -1 if none read yet // // Parameters: // target - whose time to read // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- int RakPeer::GetLowestPing( PlayerID playerId ) const { RemoteSystemStruct * remoteSystem = GetRemoteSystemFromPlayerID( playerId ); if ( remoteSystem == 0 ) return -1; return remoteSystem->lowestPing; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Return the unique PlayerID that represents you on the the network // Note that unlike in previous versions, this is a struct and is not sequential // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- PlayerID RakPeer::GetInternalID( void ) const { return myPlayerId; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Return the unique address identifier that represents you on the the network and is based on your external // IP / port (the IP / port the specified player uses to communicate with you) // Note that unlike in previous versions, this is a struct and is not sequential // // Parameters: // target: Which remote system you are referring to for your external ID // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- PlayerID RakPeer::GetExternalID( PlayerID target ) const { RemoteSystemStruct * remoteSystem = GetRemoteSystemFromPlayerID( target ); if ( remoteSystem == 0 ) return UNASSIGNED_PLAYER_ID; else return remoteSystem->myExternalPlayerId; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Change the MTU size in order to improve performance when sending large packets // This can only be called when not connected. // A too high of value will cause packets not to arrive at worst and be fragmented at best. // A too low of value will split packets unnecessarily. // // Parameters: // size: Set according to the following table: // 1500. The largest Ethernet packet size // This is the typical setting for non-PPPoE, non-VPN connections. The default value for NETGEAR routers, adapters and switches. // 1492. The size PPPoE prefers. // 1472. Maximum size to use for pinging. (Bigger packets are fragmented.) // 1468. The size DHCP prefers. // 1460. Usable by AOL if you don't have large email attachments, etc. // 1430. The size VPN and PPTP prefer. // 1400. Maximum size for AOL DSL. // 576. Typical value to connect to dial-up ISPs. (Default) // // Returns: // False on failure (we are connected). True on success. Maximum allowed size is MAXIMUM_MTU_SIZE // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::SetMTUSize( int size ) { if ( IsActive() ) return false; if ( size < 512 ) size = 512; else if ( size > MAXIMUM_MTU_SIZE ) size = MAXIMUM_MTU_SIZE; MTUSize = size; return true; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Returns the current MTU size // // Returns: // The MTU sized specified in SetMTUSize // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- int RakPeer::GetMTUSize( void ) const { return MTUSize; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Returns the number of IP addresses we have // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- unsigned int RakPeer::GetNumberOfAddresses( void ) { char ipList[ 10 ][ 16 ]; memset( ipList, 0, sizeof( char ) * 16 * 10 ); SocketLayer::Instance()->GetMyIP( ipList ); int i = 0; while ( ipList[ i ][ 0 ] ) i++; return i; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Given a PlayerID struct, returns the dotted IP address string this binaryAddress field represents // // Returns: // Null terminated dotted IP address string. // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- const char* RakPeer::PlayerIDToDottedIP( PlayerID playerId ) const { in_addr in; in.s_addr = playerId.binaryAddress; return inet_ntoa( in ); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Returns an IP address at index 0 to GetNumberOfAddresses-1 // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- const char* RakPeer::GetLocalIP( unsigned int index ) { static char ipList[ 10 ][ 16 ]; if ( index >= 10 ) index = 9; memset( ipList, 0, sizeof( char ) * 16 * 10 ); SocketLayer::Instance()->GetMyIP( ipList ); return ipList[ index ]; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Allow or disallow connection responses from any IP. Normally this should be false, but may be necessary // when connection to servers with multiple IP addresses // // Parameters: // allow - True to allow this behavior, false to not allow. Defaults to false. Value persists between connections // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::AllowConnectionResponseIPMigration( bool allow ) { allowConnectionResponseIPMigration = allow; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Sends a one byte message ID_ADVERTISE_SYSTEM to the remote unconnected system. // This will tell the remote system our external IP outside the LAN, and can be used for NAT punch through // // Requires: // The sender and recipient must already be started via a successful call to Initialize // // host: Either a dotted IP address or a domain name // remotePort: Which port to connect to on the remote machine. // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::AdvertiseSystem( char *host, unsigned short remotePort, const char *data, int dataLength ) { if ( IsActive() == false ) return ; // This is a security measure. Don't send data longer than this value assert(dataLength <= MAX_OFFLINE_DATA_LENGTH); assert(dataLength>=0); // If the host starts with something other than 0, 1, or 2 it's (probably) a domain name. if ( host[ 0 ] < '0' || host[ 0 ] > '2' ) { host = ( char* ) SocketLayer::Instance()->DomainNameToIP( host ); } PlayerID playerId; IPToPlayerID( host, remotePort, &playerId ); // disabled so can send while shutting down //if (GetRemoteSystemFromPlayerID(playerId)) // return; RequestedConnectionStruct *rcs = requestedConnectionList.WriteLock(); rcs->playerId=playerId; rcs->nextRequestTime=RakNet::GetTime(); rcs->requestsMade=0; if (data && dataLength>0) { rcs->data=new char [dataLength]; rcs->dataLength=dataLength; memcpy(rcs->data, data, dataLength); } else { rcs->data=0; rcs->dataLength=0; } rcs->actionToTake=RequestedConnectionStruct::ADVERTISE_SYSTEM; requestedConnectionList.WriteUnlock(); // unsigned char c = ID_ADVERTISE_SYSTEM; // RakNet::BitStream temp(sizeof(c)); // temp.Write((unsigned char)c); // if (data && dataLength>0) // temp.Write(data, dataLength); // Send(&temp, SYSTEM_PRIORITY, UNRELIABLE, 0, playerId, false); //SendBuffered(&temp, SYSTEM_PRIORITY, UNRELIABLE, 0, playerId, false, RemoteSystemStruct::DISCONNECT_ASAP); // SocketLayer::Instance()->SendTo( connectionSocket, (const char*)temp.GetData(), temp.GetNumberOfBytesUsed(), ( char* ) host, remotePort ); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Description: // Put a packet back at the end of the receive queue in case you don't want to deal with it immediately // // Parameters // packet: The packet you want to push back. // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::PushBackPacket( Packet *packet ) { if ( packet ) { #ifdef _DEBUG assert( packet->data ); #endif incomingPacketQueue.pushAtHead( packet ); } } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- RakNetStatisticsStruct * const RakPeer::GetStatistics( PlayerID playerId ) { RemoteSystemStruct * rss; rss = GetRemoteSystemFromPlayerID( playerId ); if ( rss && endThreads==false ) return rss->reliabilityLayer.GetStatistics(); return 0; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::SendConnectionRequest( const char* host, unsigned short remotePort ) { PlayerID playerId; // RemoteSystemStruct *rss; // bool success; IPToPlayerID( host, remotePort, &playerId ); // rss=AssignPlayerIDToRemoteSystemList(playerId, RemoteSystemStruct::REQUESTED_CONNECTION); // if (rss==0) // return false; // full or already connected // Already connected? if (GetRemoteSystemFromPlayerID(playerId)) return false; RequestedConnectionStruct *rcs = requestedConnectionList.WriteLock(); rcs->playerId=playerId; rcs->nextRequestTime=RakNet::GetTime(); rcs->requestsMade=0; rcs->data=0; rcs->actionToTake=RequestedConnectionStruct::CONNECT; requestedConnectionList.WriteUnlock(); // Request will be sent in the other thread //char c = ID_OPEN_CONNECTION_REQUEST; //SocketLayer::Instance()->SendTo( connectionSocket, (char*)&c, 1, ( char* ) host, remotePort ); /* RakNet::BitStream temp( sizeof(unsigned char) + outgoingPasswordBitStream.GetNumberOfBytesUsed() ); temp.Write( (unsigned char) ID_CONNECTION_REQUEST ); if ( outgoingPasswordBitStream.GetNumberOfBytesUsed() > 0 ) temp.Write( ( char* ) outgoingPasswordBitStream.GetData(), outgoingPasswordBitStream.GetNumberOfBytesUsed() ); // success=Send(&temp, SYSTEM_PRIORITY, RELIABLE, 0, playerId, false); SendBuffered(&temp, SYSTEM_PRIORITY, RELIABLE, 0, playerId, false, RemoteSystemStruct::REQUESTED_CONNECTION); //#ifdef _DEBUG // assert(success); //#endif */ return true; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::IPToPlayerID( const char* host, unsigned short remotePort, PlayerID *playerId ) { if ( host == 0 ) return ; playerId->binaryAddress = inet_addr( host ); playerId->port = remotePort; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- RakPeer::RemoteSystemStruct *RakPeer::GetRemoteSystemFromPlayerID( PlayerID playerID ) const { unsigned i; if ( playerID == UNASSIGNED_PLAYER_ID ) return 0; for ( i = 0; i < remoteSystemListSize; i++ ) if ( remoteSystemList[ i ].playerId == playerID ) return remoteSystemList + i; return 0; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::ParseConnectionRequestPacket( RakPeer::RemoteSystemStruct *remoteSystem, PlayerID playerId, const char *data, int byteSize ) { // If we are full tell the sender. if ( !AllowIncomingConnections() ) { unsigned char c = ID_NO_FREE_INCOMING_CONNECTIONS; // SocketLayer::Instance()->SendTo( rakPeer->connectionSocket, ( char* ) & c, sizeof( char ), playerId.binaryAddress, playerId.port ); SendImmediate(( char* ) & c, sizeof( char )*8, SYSTEM_PRIORITY, RELIABLE, 0, playerId, false, false, RakNet::GetTime()); remoteSystem->connectMode=RemoteSystemStruct::DISCONNECT_ASAP; } else { remoteSystem->connectMode=RemoteSystemStruct::HANDLING_CONNECTION_REQUEST; // Connect this player assuming we have open slots OnConnectionRequest( remoteSystem ); } } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::OnConnectionRequest( RakPeer::RemoteSystemStruct *remoteSystem ) { if ( AllowIncomingConnections() ) { RakNet::BitStream bitStream(sizeof(unsigned char)+sizeof(unsigned short)+sizeof(unsigned int)+sizeof(unsigned short)+sizeof(PlayerIndex)); bitStream.Write((unsigned char)ID_CONNECTION_REQUEST_ACCEPTED); bitStream.Write((unsigned short)myPlayerId.port); bitStream.Write(remoteSystem->playerId.binaryAddress); bitStream.Write(remoteSystem->playerId.port); bitStream.Write(( PlayerIndex ) GetIndexFromPlayerID( remoteSystem->playerId )); SendImmediate((char*)bitStream.GetData(), bitStream.GetNumberOfBitsUsed(), SYSTEM_PRIORITY, RELIABLE, 0, remoteSystem->playerId, false, false, RakNet::GetTime()); } else { unsigned char c = ID_NO_FREE_INCOMING_CONNECTIONS; SendImmediate((char*)&c, sizeof(c)*8, SYSTEM_PRIORITY, RELIABLE, 0, remoteSystem->playerId, false, false, RakNet::GetTime()); remoteSystem->connectMode=RemoteSystemStruct::DISCONNECT_ASAP; } } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::NotifyAndFlagForDisconnect( PlayerID playerId, bool performImmediate ) { RakNet::BitStream temp( sizeof(unsigned char) ); temp.Write( (unsigned char) ID_DISCONNECTION_NOTIFICATION ); if (performImmediate) { SendImmediate((char*)temp.GetData(), temp.GetNumberOfBitsUsed(), SYSTEM_PRIORITY, RELIABLE, 0, playerId, false, false, RakNet::GetTime()); RemoteSystemStruct *rss=GetRemoteSystemFromPlayerID(playerId); rss->connectMode=RemoteSystemStruct::DISCONNECT_ASAP; } else { SendBuffered(&temp, SYSTEM_PRIORITY, RELIABLE, 0, playerId, false, RemoteSystemStruct::DISCONNECT_ASAP); } } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- unsigned short RakPeer::GetNumberOfRemoteInitiatedConnections( void ) const { unsigned short i, numberOfIncomingConnections; if ( remoteSystemList == 0 || endThreads == true ) return 0; numberOfIncomingConnections = 0; for ( i = 0; i < remoteSystemListSize; i++ ) { if ( remoteSystemList[ i ].playerId != UNASSIGNED_PLAYER_ID && remoteSystemList[ i ].weInitiatedTheConnection == false && remoteSystemList[i].connectMode==RemoteSystemStruct::CONNECTED) numberOfIncomingConnections++; } return numberOfIncomingConnections; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- RakPeer::RemoteSystemStruct * RakPeer::AssignPlayerIDToRemoteSystemList( PlayerID playerId, RemoteSystemStruct::ConnectMode connectionMode ) { RemoteSystemStruct * remoteSystem = 0; unsigned i; unsigned int time = RakNet::GetTime(); // If this guy is already connected, return 0. This needs to be checked inside the mutex // because threads may call the connection routine multiple times at the same time for ( i = 0; i < remoteSystemListSize; i++ ) { if ( remoteSystemList[ i ].playerId == playerId ) { return 0; } } for ( i = 0; i < remoteSystemListSize; i++ ) { if ( remoteSystemList[ i ].playerId == UNASSIGNED_PLAYER_ID) { remoteSystem=remoteSystemList+i; remoteSystem->playerId = playerId; // This one line causes future incoming packets to go through the reliability layer remoteSystem->pingTime = -1; remoteSystem->connectMode=connectionMode; remoteSystem->lowestPing = -1; remoteSystem->nextPingTime = 0; // Ping immediately remoteSystem->weInitiatedTheConnection = false; remoteSystem->connectionTime = time; remoteSystem->myExternalPlayerId = UNASSIGNED_PLAYER_ID; remoteSystem->lastReliableSend=time; // Reserve this reliability layer for ourselves. remoteSystem->reliabilityLayer.Reset(); return remoteSystem; } } return remoteSystem; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::PushPortRefused( PlayerID target ) { // Tell the game we can't connect to this host Packet * p; p = packetPool.GetPointer(); p->data = new unsigned char[ 1 ]; p->data[ 0 ] = ID_REMOTE_PORT_REFUSED; p->length = sizeof( char ); p->playerId = target; // We don't know this! p->playerIndex = ( PlayerIndex ) GetIndexFromPlayerID( p->playerId ); #ifdef _DEBUG assert( p->data ); #endif // Relay this message to the game incomingQueueMutex.Lock(); incomingPacketQueue.push( p ); incomingQueueMutex.Unlock(); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::AllowIncomingConnections(void) const { return GetNumberOfRemoteInitiatedConnections() < GetMaximumIncomingConnections(); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::PingInternal( PlayerID target, bool performImmediate ) { if ( IsActive() == false ) return ; RakNet::BitStream bitStream(sizeof(unsigned char)+sizeof(unsigned int)); bitStream.Write((unsigned char)ID_CONNECTED_PING); unsigned int currentTime = RakNet::GetTime(); bitStream.Write(currentTime); if (performImmediate) SendImmediate( (char*)bitStream.GetData(), bitStream.GetNumberOfBitsUsed(), SYSTEM_PRIORITY, UNRELIABLE, 0, target, false, false, currentTime ); else Send( &bitStream, SYSTEM_PRIORITY, UNRELIABLE, 0, target, false ); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::CloseConnectionInternalBuffered( PlayerID target, bool sendDisconnectionNotification ) { if ( remoteSystemList == 0 || endThreads == true ) return; if (sendDisconnectionNotification) { NotifyAndFlagForDisconnect(target, false); } else { BufferedCommandStruct *bcs; bcs=bufferedCommands.WriteLock(); bcs->command=BufferedCommandStruct::BCS_CLOSE_CONNECTION; bcs->playerId=target; bcs->data=0; bufferedCommands.WriteUnlock(); } } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::CloseConnectionInternalImmediate( PlayerID target) { if ( remoteSystemList == 0 || endThreads == true ) return; for (unsigned int i = 0 ; i < remoteSystemListSize; i++ ) { if ( remoteSystemList[ i ].playerId == target ) { // Reserve this reliability layer for ourselves remoteSystemList[ i ].playerId = UNASSIGNED_PLAYER_ID; // remoteSystemList[ i ].allowPlayerIdAssigment=false; // Remove any remaining packets. remoteSystemList[ i ].reliabilityLayer.Reset(); break; } } } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::ValidSendTarget(PlayerID playerId, bool broadcast) { unsigned remoteSystemIndex; for ( remoteSystemIndex = 0; remoteSystemIndex < remoteSystemListSize; remoteSystemIndex++ ) { if ( remoteSystemList[ remoteSystemIndex ].playerId != UNASSIGNED_PLAYER_ID && remoteSystemList[ remoteSystemIndex ].connectMode==RakPeer::RemoteSystemStruct::CONNECTED && // Not fully connected players are not valid user-send targets because the reliability layer wasn't reset yet ( ( broadcast == false && remoteSystemList[ remoteSystemIndex ].playerId == playerId ) || ( broadcast == true && remoteSystemList[ remoteSystemIndex ].playerId != playerId ) ) ) return true; } return false; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::SendBuffered( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId, bool broadcast, RemoteSystemStruct::ConnectMode connectionMode ) { BufferedCommandStruct *bcs; bcs=bufferedCommands.WriteLock(); bcs->data = new char[bitStream->GetNumberOfBytesUsed()]; // Making a copy doesn't lose efficiency because I tell the reliability layer to use this allocation for its own copy memcpy(bcs->data, bitStream->GetData(), bitStream->GetNumberOfBytesUsed()); bcs->numberOfBitsToSend=bitStream->GetNumberOfBitsUsed(); bcs->priority=priority; bcs->reliability=reliability; bcs->orderingChannel=orderingChannel; bcs->playerId=playerId; bcs->broadcast=broadcast; bcs->connectionMode=connectionMode; bcs->command=BufferedCommandStruct::BCS_SEND; bufferedCommands.WriteUnlock(); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::SendImmediate( char *data, int numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId, bool broadcast, bool useCallerDataAllocation, unsigned int currentTime ) { unsigned *sendList; unsigned sendListSize; bool callerDataAllocationUsed; unsigned remoteSystemIndex, sendListIndex; // Iterates into the list of remote systems callerDataAllocationUsed=false; sendList=(unsigned *)alloca(sizeof(unsigned)*remoteSystemListSize); sendListSize=0; for ( remoteSystemIndex = 0; remoteSystemIndex < remoteSystemListSize; remoteSystemIndex++ ) { if ( remoteSystemList[ remoteSystemIndex ].playerId != UNASSIGNED_PLAYER_ID && ( ( broadcast == false && remoteSystemList[ remoteSystemIndex ].playerId == playerId ) || ( broadcast == true && remoteSystemList[ remoteSystemIndex ].playerId != playerId ) ) ) sendList[sendListSize++]=remoteSystemIndex; } if (sendListSize==0) return false; for (sendListIndex=0; sendListIndex < sendListSize; sendListIndex++) { // Send may split the packet and thus deallocate data. Don't assume data is valid if we use the callerAllocationData bool useData = useCallerDataAllocation && callerDataAllocationUsed==false && sendListIndex+1==sendListSize; remoteSystemList[sendList[sendListIndex]].reliabilityLayer.Send( data, numberOfBitsToSend, priority, reliability, orderingChannel, useData==false, MTUSize, currentTime ); if (useData) callerDataAllocationUsed=true; if (reliability==RELIABLE || reliability==RELIABLE_ORDERED || reliability==RELIABLE_SEQUENCED) remoteSystemList[sendList[sendListIndex]].lastReliableSend=currentTime; } // Return value only meaningful if true was passed for useCallerDataAllocation. Means the reliability layer used that data copy, so the caller should not deallocate it return callerDataAllocationUsed; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::ClearBufferedCommands(void) { BufferedCommandStruct *bcs; while ((bcs=bufferedCommands.ReadLock())!=0) { if (bcs->data) delete [] bcs->data; bufferedCommands.ReadUnlock(); } bufferedCommands.Clear(); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::ClearRequestedConnectionList(void) { RequestedConnectionStruct *bcs; while ((bcs=requestedConnectionList.ReadLock())!=0) { if (bcs->data) delete [] bcs->data; requestedConnectionList.ReadUnlock(); } requestedConnectionList.Clear(); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #ifdef _WIN32 void __stdcall ProcessNetworkPacket( unsigned int binaryAddress, unsigned short port, const char *data, int length, RakPeer *rakPeer ) #else void ProcessNetworkPacket( unsigned int binaryAddress, unsigned short port, const char *data, int length, RakPeer *rakPeer ) #endif { PlayerID playerId; // unsigned i; RakPeer::RemoteSystemStruct *remoteSystem; playerId.binaryAddress = binaryAddress; playerId.port = port; // UNCONNECTED MESSAGE to establish a connection if ((unsigned char)(data)[0] == ID_OPEN_CONNECTION_REPLY && length == sizeof(unsigned char)) { // Verify that we were waiting for this bool acceptOpenConnection; int actionToTake=0; char data[MAX_OFFLINE_DATA_LENGTH]; unsigned short dataLength; RakPeer::RequestedConnectionStruct *rcsFirst, *rcs; rcsFirst = rakPeer->requestedConnectionList.ReadLock(); rcs=rcsFirst; acceptOpenConnection=false; while (rcs) { if (rcs->playerId==playerId) { acceptOpenConnection=true; actionToTake|=(int)rcs->actionToTake; if (rcs->data) { #ifdef _DEBUG assert(rcs->actionToTake==RakPeer::RequestedConnectionStruct::ADVERTISE_SYSTEM); assert(rcs->dataLength <= MAX_OFFLINE_DATA_LENGTH); #endif memcpy(data, rcs->data, rcs->dataLength); dataLength=rcs->dataLength; delete [] rcs->data; rcs->data=0; } if (rcs==rcsFirst) { rakPeer->requestedConnectionList.ReadUnlock(); rcsFirst=rakPeer->requestedConnectionList.ReadLock(); rcs=rcsFirst; continue; } else { // Duplicate call - cancel it rcs->playerId=UNASSIGNED_PLAYER_ID; } } rcs=rakPeer->requestedConnectionList.ReadLock(); } if (rcsFirst) rakPeer->requestedConnectionList.CancelReadLock(rcsFirst); if (acceptOpenConnection) { remoteSystem=rakPeer->AssignPlayerIDToRemoteSystemList(playerId, RakPeer::RemoteSystemStruct::UNVERIFIED_SENDER); // if (remoteSystem==0) // remoteSystem=rakPeer->GetRemoteSystemFromPlayerID(playerId); // Get the already connected guy if (remoteSystem) { unsigned int time = RakNet::GetTime(); if (actionToTake & RakPeer::RequestedConnectionStruct::CONNECT) { remoteSystem->connectMode=RakPeer::RemoteSystemStruct::REQUESTED_CONNECTION; remoteSystem->weInitiatedTheConnection=true; RakNet::BitStream temp( sizeof(unsigned char) ); temp.Write( (unsigned char) ID_CONNECTION_REQUEST ); rakPeer->SendImmediate((char*)temp.GetData(), temp.GetNumberOfBitsUsed(), SYSTEM_PRIORITY, RELIABLE, 0, playerId, false, false, time ); } if ((actionToTake & RakPeer::RequestedConnectionStruct::PING) || (actionToTake & RakPeer::RequestedConnectionStruct::PING_OPEN_CONNECTIONS)) { RakNet::BitStream temp( sizeof(unsigned char) + sizeof(unsigned int) ); if ( actionToTake & RakPeer::RequestedConnectionStruct::PING_OPEN_CONNECTIONS ) temp.Write((unsigned char)ID_UNCONNECTED_PING_OPEN_CONNECTIONS); else temp.Write((unsigned char)ID_UNCONNECTED_PING); temp.Write(time); // SocketLayer::Instance()->SendTo( connectionSocket, (const char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed(), ( char* ) host, remotePort ); rakPeer->SendImmediate((char*)temp.GetData(), temp.GetNumberOfBitsUsed(), SYSTEM_PRIORITY, RELIABLE, 0, playerId, false, false, time ); } if (actionToTake & RakPeer::RequestedConnectionStruct::ADVERTISE_SYSTEM) { RakNet::BitStream temp; temp.Write((unsigned char)ID_ADVERTISE_SYSTEM); if (dataLength>0) temp.Write(data, dataLength); rakPeer->SendImmediate((char*)temp.GetData(), temp.GetNumberOfBitsUsed(), SYSTEM_PRIORITY, RELIABLE, 0, playerId, false, false, time ); remoteSystem->connectMode=RakPeer::RemoteSystemStruct::DISCONNECT_ASAP; } } } return; } // UNCONNECTED MESSAGE Broadcast ping with no data else if ( ( (unsigned char) data[ 0 ] == ID_UNCONNECTED_PING_OPEN_CONNECTIONS || (unsigned char)(data)[0] == ID_UNCONNECTED_PING) && length == sizeof(unsigned char) ) { if ( (unsigned char)(data)[0] == ID_UNCONNECTED_PING || rakPeer->AllowIncomingConnections() ) // Open connections with players { RakNet::BitStream outBitStream; outBitStream.Write((unsigned char)ID_PONG); // Should be named ID_UNCONNECTED_PONG eventually SocketLayer::Instance()->SendTo( rakPeer->connectionSocket, (const char*)outBitStream.GetData(), outBitStream.GetNumberOfBytesUsed(), (char*)rakPeer->PlayerIDToDottedIP(playerId) , playerId.port ); } return; } // UNCONNECTED MESSAGE Pong with no data else if ((unsigned char) data[ 0 ] == ID_PONG && length == sizeof(unsigned char) ) { Packet * packet = rakPeer->packetPool.GetPointer(); packet->data = new unsigned char[ sizeof( char )+sizeof(unsigned int) ]; unsigned int zero=0; packet->data[ 0 ] = ID_PONG; memcpy(packet->data+sizeof( char ), (char*)&zero, sizeof(unsigned int)); packet->length = sizeof( char ); packet->bitSize = sizeof( char ) * 8; packet->playerId = playerId; packet->playerIndex = ( PlayerIndex ) rakPeer->GetIndexFromPlayerID( playerId ); rakPeer->incomingQueueMutex.Lock(); rakPeer->incomingPacketQueue.push( packet ); rakPeer->incomingQueueMutex.Unlock(); return; } remoteSystem = rakPeer->GetRemoteSystemFromPlayerID( playerId ); if ( remoteSystem ) { // Handle regular incoming data // HandleSocketReceiveFromConnectedPlayer is only safe to be called from the same thread as Update, which is this thread if ( remoteSystem->reliabilityLayer.HandleSocketReceiveFromConnectedPlayer( data, length ) == false ) { // These kinds of packets may have been duplicated and incorrectly determined to be // cheat packets. Anything else really is a cheat packet if ( !( ( (unsigned char)data[0] == ID_OPEN_CONNECTION_REQUEST && length == 1 ) || ( (unsigned char)data[0] == ID_OPEN_CONNECTION_REPLY && length == 1 ) || (((unsigned char)data[0] == ID_UNCONNECTED_PING_OPEN_CONNECTIONS || (unsigned char)(data)[0] == ID_UNCONNECTED_PING) && length == sizeof(unsigned char)+sizeof(unsigned int) ) || ( (unsigned char)data[0] == ID_PONG && length >= sizeof(unsigned char)+sizeof(unsigned int) ) || ( (unsigned char)data[0] == ID_ADVERTISE_SYSTEM && lengthpacketPool.GetPointer(); packet->data = new unsigned char[ 1 ]; packet->data[ 0 ] = ID_MODIFIED_PACKET; packet->length = sizeof( char ); packet->bitSize = sizeof( char ) * 8; packet->playerId = playerId; packet->playerIndex = ( PlayerIndex ) rakPeer->GetIndexFromPlayerID( playerId ); rakPeer->incomingQueueMutex.Lock(); rakPeer->incomingPacketQueue.push( packet ); rakPeer->incomingQueueMutex.Unlock(); } } } else { // The reason for ID_OPEN_CONNECTION_REQUEST and ID_OPEN_CONNECTION_REPLY is that they are only one byte so I can be sure // that they are offline messages and I know to reset the connections. This is because the smallest possible connected packet is 17 bits. // This is the only way I can tell for sure that a message is asking for a new connection. // This fixes bugs where I ignore a connection request from a connected player or handle a message that looks like a connection request but actually wasn't. if ((unsigned char)(data)[0] == ID_OPEN_CONNECTION_REQUEST && length == sizeof(unsigned char)) { remoteSystem=rakPeer->AssignPlayerIDToRemoteSystemList(playerId, RakPeer::RemoteSystemStruct::UNVERIFIED_SENDER); if (remoteSystem) // If this guy is already connected remote system will be 0 { char c = ID_OPEN_CONNECTION_REPLY; SocketLayer::Instance()->SendTo( rakPeer->connectionSocket, (char*)&c, 1, playerId.binaryAddress, playerId.port ); } } } } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool RakPeer::RunUpdateCycle( void ) { RakPeer::RemoteSystemStruct * remoteSystem; unsigned remoteSystemIndex; Packet *packet; int ping, lastPing; // int currentSentBytes,currentReceivedBytes; // unsigned numberOfBytesUsed; //PlayerID authoritativeClientPlayerId; int bitSize, byteSize; char *data; int errorCode; int gotData; unsigned int time; PlayerID playerId; BufferedCommandStruct *bcs; bool callerDataAllocationUsed; RakNetStatisticsStruct *rnss; do { // Read a packet gotData = SocketLayer::Instance()->RecvFrom( connectionSocket, this, &errorCode ); if ( gotData == SOCKET_ERROR ) { #ifdef _WIN32 if ( errorCode == WSAECONNRESET ) { gotData=false; // 11/14/05 - RecvFrom now calls HandlePortUnreachable rather than PushPortRefused //PushPortRefused( UNASSIGNED_PLAYER_ID ); //closesocket(peer->connectionSocket); //peer->connectionSocket = SocketLayer::Instance()->CreateBoundSocket(peer->myPlayerId.port, true); } else if ( errorCode != 0 && endThreads == false ) { #ifdef _DO_PRINTF printf( "Server RecvFrom critical failure!\n" ); #endif // Some kind of critical error // peer->isRecvfromThreadActive=false; endThreads = true; Disconnect( 0 ); return false; } #else if ( errorCode == -1 ) { // isRecvfromThreadActive=false; endThreads = true; Disconnect( 0 ); return false; } #endif } if ( endThreads ) return false; } while ( gotData>0 ); // Read until there is nothing left time=0; // Process all the deferred user thread Send and connect calls while ( ( bcs = bufferedCommands.ReadLock() ) != 0 ) // Don't immediately check mutex since it's so slow to activate it { if (bcs->command==BufferedCommandStruct::BCS_SEND) { // This will create a new connection if requested if (bcs->connectionMode!=RemoteSystemStruct::NO_ACTION) { remoteSystem=AssignPlayerIDToRemoteSystemList(bcs->playerId, bcs->connectionMode); if (!remoteSystem) { // Does this system already exist? remoteSystem=GetRemoteSystemFromPlayerID(bcs->playerId); if (remoteSystem) remoteSystem->connectMode=bcs->connectionMode; } } // GetTime is a very slow call so do it once and as late as possible if (time==0) time = RakNet::GetTime(); callerDataAllocationUsed=SendImmediate((char*)bcs->data, bcs->numberOfBitsToSend, bcs->priority, bcs->reliability, bcs->orderingChannel, bcs->playerId, bcs->broadcast, true, time); if ( callerDataAllocationUsed==false ) delete [] bcs->data; } else { #ifdef _DEBUG assert(bcs->command==BufferedCommandStruct::BCS_CLOSE_CONNECTION); #endif CloseConnectionInternalImmediate(bcs->playerId); } #ifdef _DEBUG bcs->data=0; #endif bufferedCommands.ReadUnlock(); } // Process connection attempts RequestedConnectionStruct *rcsFirst, *rcs; bool condition1, condition2; rcsFirst = requestedConnectionList.ReadLock(); rcs=rcsFirst; while (rcs) { if (time==0) time = RakNet::GetTime(); if (rcs->nextRequestTime < time) { condition1=rcs->requestsMade==3; condition2=(bool)((rcs->playerId==UNASSIGNED_PLAYER_ID)==1); // If too many requests made or a hole then remove this if possible, otherwise invalidate it if (condition1 || condition2) { if (rcs->data) { delete [] rcs->data; rcs->data=0; } if (condition1 && !condition2 && rcs->actionToTake==RequestedConnectionStruct::CONNECT) { // Tell user of connection attempt failed packet = packetPool.GetPointer(); packet->data = new unsigned char [ sizeof( char ) ]; packet->data[ 0 ] = ID_CONNECTION_ATTEMPT_FAILED; // Attempted a connection and couldn't packet->length = sizeof( char ); packet->bitSize = ( sizeof( char ) * 8); packet->playerId = myPlayerId; packet->playerIndex = 65535; incomingQueueMutex.Lock(); ( incomingPacketQueue ).push( packet ); incomingQueueMutex.Unlock(); } // Remove this if possible if (rcs==rcsFirst) { requestedConnectionList.ReadUnlock(); rcsFirst = requestedConnectionList.ReadLock(); rcs=rcsFirst; } else { // Hole in the middle rcs->playerId=UNASSIGNED_PLAYER_ID; rcs=requestedConnectionList.ReadLock(); } continue; } rcs->requestsMade++; rcs->nextRequestTime=time+1000; char c = ID_OPEN_CONNECTION_REQUEST; SocketLayer::Instance()->SendTo( connectionSocket, (char*)&c, 1, ( char* ) PlayerIDToDottedIP(rcs->playerId), rcs->playerId.port ); } rcs=requestedConnectionList.ReadLock(); } if (rcsFirst) requestedConnectionList.CancelReadLock(rcsFirst); for ( remoteSystemIndex = 0; remoteSystemIndex < remoteSystemListSize; ++remoteSystemIndex ) { // I'm using playerId from remoteSystemList but am not locking it because this loop is called very frequently and it doesn't // matter if we miss or do an extra update. The reliability layers themselves never care which player they are associated with playerId = remoteSystemList[ remoteSystemIndex ].playerId; // Allow the playerID for this remote system list to change. We don't care if it changes now. // remoteSystemList[ remoteSystemIndex ].allowPlayerIdAssigment=true; if ( playerId != UNASSIGNED_PLAYER_ID ) { // Found an active remote system remoteSystem = remoteSystemList + remoteSystemIndex; // Update is only safe to call from the same thread that calls HandleSocketReceiveFromConnectedPlayer, // which is this thread if (time==0) time = RakNet::GetTime(); if (time > remoteSystem->lastReliableSend && time-remoteSystem->lastReliableSend > 5000 && remoteSystem->connectMode==RemoteSystemStruct::CONNECTED) { // If no reliable packets are waiting for an ack, do a one byte reliable send so that disconnections are noticed rnss=remoteSystem->reliabilityLayer.GetStatistics(); if (rnss->messagesOnResendQueue==0) { unsigned char keepAlive=ID_KEEPALIVE; SendImmediate((char*)&keepAlive,8,LOW_PRIORITY, RELIABLE, 0, remoteSystem->playerId, false, false, time); remoteSystem->lastReliableSend=time+TIMEOUT_TIME; } } remoteSystem->reliabilityLayer.Update( connectionSocket, playerId, MTUSize, time ); // playerId only used for the internet simulator test // Check for failure conditions if ( remoteSystem->reliabilityLayer.IsDeadConnection() || (remoteSystem->connectMode==RemoteSystemStruct::DISCONNECT_ASAP && remoteSystem->reliabilityLayer.IsDataWaiting()==false) || ((remoteSystem->connectMode!=RemoteSystemStruct::CONNECTED && time > remoteSystem->connectionTime && time - remoteSystem->connectionTime > 10000)) ) { // Failed. Inform the user? if (remoteSystem->connectMode==RemoteSystemStruct::CONNECTED || remoteSystem->connectMode==RemoteSystemStruct::REQUESTED_CONNECTION) { // Inform the user of the connection failure. packet = packetPool.GetPointer(); packet->data = new unsigned char [ sizeof( char ) ]; if (remoteSystem->connectMode==RemoteSystemStruct::REQUESTED_CONNECTION) packet->data[ 0 ] = ID_CONNECTION_ATTEMPT_FAILED; // Attempted a connection and couldn't else packet->data[ 0 ] = ID_CONNECTION_LOST; // DeadConnection packet->length = sizeof( char ); packet->bitSize = sizeof( char ) * 8; packet->playerId = playerId; packet->playerIndex = ( PlayerIndex ) remoteSystemIndex; incomingQueueMutex.Lock(); ( incomingPacketQueue ).push( packet ); incomingQueueMutex.Unlock(); } // else connection shutting down, don't bother telling the user #ifdef _DO_PRINTF printf("Connection dropped for player %i:%i\n", playerId.binaryAddress, playerId.port); #endif CloseConnectionInternalImmediate( playerId ); continue; } // Ping this guy if it is time to do so if ( remoteSystem->connectMode==RemoteSystemStruct::CONNECTED && time > remoteSystem->nextPingTime && ( remoteSystem->lowestPing == -1 ) ) { remoteSystem->nextPingTime = time + 5000; PingInternal( playerId, true ); } // Find whoever has the lowest player ID //if (playerId < authoritativeClientPlayerId) // authoritativeClientPlayerId=playerId; // Does the reliability layer have any packets waiting for us? // To be thread safe, this has to be called in the same thread as HandleSocketReceiveFromConnectedPlayer bitSize = remoteSystem->reliabilityLayer.Receive( &data ); while ( bitSize > 0 ) { // Fast and easy - just use the data that was returned byteSize = BITS_TO_BYTES( bitSize ); // For unknown senders we only accept a few specific packets if (remoteSystem->connectMode==RemoteSystemStruct::UNVERIFIED_SENDER) { if ( (unsigned char)(data)[0] == ID_CONNECTION_REQUEST ) { ParseConnectionRequestPacket(remoteSystem, playerId, data, byteSize); delete [] data; } else if ( ((unsigned char) data[0] == ID_PONG && byteSize >= sizeof(unsigned char)+sizeof(unsigned int)) || ((unsigned char) data[0] == ID_ADVERTISE_SYSTEM && byteSize<=MAX_OFFLINE_DATA_LENGTH)) { // Push to the user Packet *packet = packetPool.GetPointer(); packet->data = ( unsigned char* ) data; packet->length = byteSize; packet->bitSize = byteSize*8; packet->playerId = playerId; packet->playerIndex=65535; incomingQueueMutex.Lock(); incomingPacketQueue.push( packet ); incomingQueueMutex.Unlock(); if (remoteSystem->connectMode!=RemoteSystemStruct::CONNECTED) { remoteSystem->connectMode=RemoteSystemStruct::DISCONNECT_ASAP; } } else if ( ( (unsigned char) data[ 0 ] == ID_UNCONNECTED_PING_OPEN_CONNECTIONS || (unsigned char)(data)[0] == ID_UNCONNECTED_PING) && byteSize == sizeof(unsigned char)+sizeof(unsigned int) ) { RakNet::BitStream inBitStream( data, byteSize, false ); inBitStream.IgnoreBits(8); unsigned int sendPingTime; inBitStream.Read(sendPingTime); if ( (unsigned char)(data)[0] == ID_UNCONNECTED_PING || AllowIncomingConnections() ) // Open connections with players { RakNet::BitStream outBitStream; outBitStream.Write((unsigned char)ID_PONG); // Should be named ID_UNCONNECTED_PONG eventually outBitStream.Write(sendPingTime); SendImmediate( (char*)outBitStream.GetData(), outBitStream.GetNumberOfBitsUsed(), SYSTEM_PRIORITY, UNRELIABLE, 0, playerId, false, false, time ); } // else ID_UNCONNECTED_PING_OPEN_CONNECTIONS and we are full so don't send anything delete [] data; // Disconnect them after replying to their offline ping if (remoteSystem->connectMode!=RemoteSystemStruct::CONNECTED) remoteSystem->connectMode=RemoteSystemStruct::DISCONNECT_ASAP; } else { CloseConnectionInternalImmediate( playerId ); #ifdef _DO_PRINTF printf("Temporarily banning %i:%i for sending nonsense data\n", playerId.binaryAddress, playerId.port); #endif delete [] data; } } else { // However, if we are connected we still take a connection request in case both systems are trying to connect to each other // at the same time if ( (unsigned char)(data)[0] == ID_CONNECTION_REQUEST ) { if (remoteSystem->weInitiatedTheConnection==false) ParseConnectionRequestPacket(remoteSystem, playerId, data, byteSize); delete [] data; } else if ( (unsigned char) data[ 0 ] == ID_NEW_INCOMING_CONNECTION && byteSize == sizeof(unsigned char)+sizeof(unsigned int)+sizeof(unsigned short) ) { #ifdef _DEBUG // This assert can be ignored since it could hit from duplicate packets. // It's just here for internal testing since it should only happen rarely and will mostly be from bugs // assert(remoteSystem->connectMode==RemoteSystemStruct::HANDLING_CONNECTION_REQUEST); #endif if (remoteSystem->connectMode==RemoteSystemStruct::HANDLING_CONNECTION_REQUEST || playerId==myPlayerId) // local system connect { remoteSystem->connectMode=RemoteSystemStruct::CONNECTED; PingInternal( playerId, true ); RakNet::BitStream inBitStream(data, byteSize, false); PlayerID bsPlayerId; inBitStream.IgnoreBits(8); inBitStream.Read(bsPlayerId.binaryAddress); inBitStream.Read(bsPlayerId.port); // Overwrite the data in the packet // NewIncomingConnectionStruct newIncomingConnectionStruct; // RakNet::BitStream nICS_BS( data, NewIncomingConnectionStruct_Size, false ); // newIncomingConnectionStruct.Deserialize( nICS_BS ); remoteSystem->myExternalPlayerId = bsPlayerId; // Send this info down to the game packet = packetPool.GetPointer(); packet->data = ( unsigned char* ) data; packet->length = byteSize; packet->bitSize = bitSize; packet->playerId = playerId; packet->playerIndex = ( PlayerIndex ) remoteSystemIndex; #ifdef _DEBUG assert( packet->data ); #endif incomingQueueMutex.Lock(); incomingPacketQueue.push( packet ); incomingQueueMutex.Unlock(); } else delete [] data; } else if ( (unsigned char) data[ 0 ] == ID_CONNECTED_PONG && byteSize == sizeof(unsigned char)+sizeof(unsigned int)*2 ) { unsigned int sendPingTime, sendPongTime; // Copy into the ping times array the current time - the value returned // First extract the sent ping RakNet::BitStream inBitStream( data, byteSize, false ); //PingStruct ps; //ps.Deserialize(psBS); inBitStream.IgnoreBits(8); inBitStream.Read(sendPingTime); inBitStream.Read(sendPongTime); time = RakNet::GetTime(); // Update the time value to be accurate ping = time - sendPingTime; lastPing = remoteSystem->pingTime; // Ignore super high spikes in the average if ( lastPing <= 0 || ( ( ( int ) ping < ( lastPing * 3 ) ) && ping < 1200 ) ) { remoteSystem->pingTime = ( short ) ping; if ( remoteSystem->lowestPing == -1 || remoteSystem->lowestPing > ping ) remoteSystem->lowestPing = ping; // Most packets should arrive by the ping time. remoteSystem->reliabilityLayer.SetLostPacketResendDelay( ping * 2 ); } delete [] data; } else if ( (unsigned char)data[0] == ID_CONNECTED_PING && byteSize == sizeof(unsigned char)+sizeof(unsigned int) ) { RakNet::BitStream inBitStream( data, byteSize, false ); inBitStream.IgnoreBits(8); unsigned int sendPingTime; inBitStream.Read(sendPingTime); if ((unsigned char)(data)[0] == ID_CONNECTED_PING) { RakNet::BitStream outBitStream; outBitStream.Write((unsigned char)ID_CONNECTED_PONG); outBitStream.Write(sendPingTime); time = RakNet::GetTime(); outBitStream.Write((unsigned int)time); SendImmediate( (char*)outBitStream.GetData(), outBitStream.GetNumberOfBitsUsed(), SYSTEM_PRIORITY, UNRELIABLE, 0, playerId, false, false, time ); } delete [] data; } else if ( (unsigned char) data[ 0 ] == ID_DISCONNECTION_NOTIFICATION ) { packet = packetPool.GetPointer(); packet->data = ( unsigned char* ) data; packet->bitSize = 8; packet->length = 1; packet->playerId = playerId; packet->playerIndex = ( PlayerIndex ) remoteSystemIndex; // We shouldn't close the connection immediately because we need to ack the ID_DISCONNECTION_NOTIFICATION remoteSystem->connectMode=RemoteSystemStruct::DISCONNECT_ASAP; //CloseConnectionInternal( playerId, false, true ); #ifdef _DEBUG assert( packet->data ); #endif // Relay this message to the game incomingQueueMutex.Lock(); incomingPacketQueue.push( packet ); incomingQueueMutex.Unlock(); } else if ( (unsigned char)(data)[0] == ID_KEEPALIVE && byteSize == sizeof(unsigned char) ) { // Do nothing delete [] data; } else if ( (unsigned char)(data)[0] == ID_CONNECTION_REQUEST_ACCEPTED && byteSize == sizeof(unsigned char)+sizeof(unsigned short)+sizeof(unsigned int)+sizeof(unsigned short)+sizeof(PlayerIndex) ) { // Make sure this connection accept is from someone we wanted to connect to bool allowConnection, alreadyConnected; if (remoteSystem->connectMode==RemoteSystemStruct::HANDLING_CONNECTION_REQUEST || remoteSystem->connectMode==RemoteSystemStruct::REQUESTED_CONNECTION || allowConnectionResponseIPMigration) allowConnection=true; else allowConnection=false; if (remoteSystem->connectMode==RemoteSystemStruct::HANDLING_CONNECTION_REQUEST) alreadyConnected=true; else alreadyConnected=false; if ( allowConnection ) { if (alreadyConnected==false) { unsigned short remotePort; PlayerID externalID; PlayerIndex playerIndex; RakNet::BitStream inBitStream(data, byteSize, false); inBitStream.IgnoreBits(8); // ID_CONNECTION_REQUEST_ACCEPTED inBitStream.Read(remotePort); inBitStream.Read(externalID.binaryAddress); inBitStream.Read(externalID.port); inBitStream.Read(playerIndex); // Find a free remote system struct to use // RakNet::BitStream casBitS(data, byteSize, false); // ConnectionAcceptStruct cas; // cas.Deserialize(casBitS); playerId.port = remotePort; remoteSystem->connectMode=RemoteSystemStruct::CONNECTED; // The remote system told us our external IP, so save it remoteSystem->myExternalPlayerId = externalID; } // Send the connection request complete to the game Packet *packet = packetPool.GetPointer(); //packet->data = new unsigned char[ byteSize ]; //memcpy( packet->data, data, byteSize ); packet->data=(unsigned char*)data; // packet->data[0]=ID_CONNECTION_REQUEST_ACCEPTED; packet->length = byteSize; packet->bitSize = byteSize * 8; packet->playerId = playerId; packet->playerIndex = ( PlayerIndex ) GetIndexFromPlayerID( playerId ); #ifdef _DEBUG assert( packet->data ); #endif incomingQueueMutex.Lock(); incomingPacketQueue.push( packet ); incomingQueueMutex.Unlock(); RakNet::BitStream outBitStream(sizeof(unsigned char)+sizeof(unsigned int)+sizeof(unsigned short)); outBitStream.Write((unsigned char)ID_NEW_INCOMING_CONNECTION); outBitStream.Write(playerId.binaryAddress); outBitStream.Write(playerId.port); SendImmediate( (char*)outBitStream.GetData(), outBitStream.GetNumberOfBitsUsed(), SYSTEM_PRIORITY, RELIABLE, 0, playerId, false, false, RakNet::GetTime() ); if (alreadyConnected==false) { PingInternal( playerId, true ); } } else { // Tell the remote system the connection failed NotifyAndFlagForDisconnect(playerId, true); #ifdef _DO_PRINTF printf( "Error: Got a connection accept when we didn't request the connection.\n" ); #endif delete [] data; } } else { packet = packetPool.GetPointer(); packet->data = ( unsigned char* ) data; packet->length = byteSize; packet->bitSize = bitSize; packet->playerId = playerId; packet->playerIndex = ( PlayerIndex ) remoteSystemIndex; #ifdef _DEBUG assert( packet->data ); #endif incomingQueueMutex.Lock(); incomingPacketQueue.push( packet ); incomingQueueMutex.Unlock(); } } // Does the reliability layer have any more packets waiting for us? // To be thread safe, this has to be called in the same thread as HandleSocketReceiveFromConnectedPlayer bitSize = remoteSystem->reliabilityLayer.Receive( &data ); } } } return true; } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #ifdef _WIN32 unsigned __stdcall UpdateNetworkLoop( LPVOID arguments ) #else void* UpdateNetworkLoop( void* arguments ) #endif { RakPeer * rakPeer = ( RakPeer * ) arguments; rakPeer->isMainLoopThreadActive = true; while ( rakPeer->endThreads == false ) { rakPeer->RunUpdateCycle(); #ifdef _WIN32 Sleep( rakPeer->threadSleepTimer ); #else usleep( rakPeer->threadSleepTimer * 1000 ); #endif } rakPeer->isMainLoopThreadActive = false; return 0; } blobby-1.0/src/RenderManagerGL2D.cpp000644 001750 001750 00000045452 12313310251 022032 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "RenderManagerGL2D.h" /* includes */ #include "FileExceptions.h" /* implementation */ #if HAVE_LIBGL RenderManagerGL2D::Texture::Texture( GLuint tex, int x, int y, int width, int height, int tw, int th ) : w(width), h(height), texture(tex) { assert(x + w <= tw); assert(y + h <= th); indices[0] = x / (float)tw; indices[1] = y / (float)th; indices[2] = (x + w) / (float)tw; indices[3] = y / (float)th; indices[4] = (x + w) / (float)tw; indices[5] = (y + h) / (float)th; indices[6] = x / (float)tw; indices[7] = (y + h) / (float)th; } int debugStateChanges = 0; int debugBindTextureCount = 0; // wrapper functions for debugging purposes void RenderManagerGL2D::glEnable(unsigned int flag) { if(mCurrentFlags.find(flag) != mCurrentFlags.end()) return; debugStateChanges++; ::glEnable(flag); mCurrentFlags.insert(flag); } void RenderManagerGL2D::glDisable(unsigned int flag) { if( mCurrentFlags.find(flag) == mCurrentFlags.end() ) return; debugStateChanges++; ::glDisable(flag); mCurrentFlags.erase( mCurrentFlags.find(flag) ); } void RenderManagerGL2D::glBindTexture(GLuint texture) { if(mCurrentTexture == texture) return; debugBindTextureCount++; ::glBindTexture(GL_TEXTURE_2D, texture); mCurrentTexture = texture; } int RenderManagerGL2D::getNextPOT(int npot) { int pot = 1; while (pot < npot) pot *= 2; return pot; } GLuint RenderManagerGL2D::loadTexture(SDL_Surface *surface, bool specular) { SDL_Surface* textureSurface; SDL_Surface* convertedTexture; textureSurface = surface; // Determine size of padding for 2^n format int oldX = textureSurface->w; int oldY = textureSurface->h; int paddedX = getNextPOT(textureSurface->w); int paddedY = getNextPOT(textureSurface->h); SDL_Rect targetRect; targetRect.w = oldX; targetRect.h = oldY; targetRect.x = (paddedX - oldX) / 2; targetRect.y = (paddedY - oldY) / 2; SDL_SetColorKey(textureSurface, SDL_TRUE, SDL_MapRGB(textureSurface->format, 0, 0, 0)); convertedTexture = SDL_CreateRGBSurface(SDL_SWSURFACE, paddedX, paddedY, 32, #if SDL_BYTEORDER == SDL_BIG_ENDIAN 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); #else 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); #endif SDL_BlitSurface(textureSurface, 0, convertedTexture, &targetRect); if (specular) { for (int y = 0; y < convertedTexture->h; ++y) { for (int x = 0; x < convertedTexture->w; ++x) { SDL_Color* pixel = &(((SDL_Color*)convertedTexture->pixels) [y * convertedTexture->w +x]); int luminance = int(pixel->r) * 5 - 4 * 256 - 138; luminance = luminance > 0 ? luminance : 0; luminance = luminance < 255 ? luminance : 255; pixel->r = luminance; pixel->g = luminance; pixel->b = luminance; } } } GLuint texture; glGenTextures(1, &texture); glBindTexture(texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, convertedTexture->w, convertedTexture->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, convertedTexture->pixels); SDL_FreeSurface(textureSurface); SDL_FreeSurface(convertedTexture); return texture; } void RenderManagerGL2D::drawQuad(float x, float y, float w, float h) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); GLfloat vertices[] = {x - w / 2.f, y - h / 2.f, x + w / 2.f, y - h / 2.f, x + w / 2.f, y + h / 2.f, x - w / 2.f, y + h / 2.f}; GLfloat texCoords[] = {0.f, 0.f, 1.f, 0.f, 1.f, 1.f, 0.f, 1.f}; glVertexPointer(2, GL_FLOAT, 0, vertices); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); glDrawArrays(GL_QUADS, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void RenderManagerGL2D::drawQuad(float x, float y, const Texture& tex) { glBindTexture(tex.texture); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); float w = tex.w; float h = tex.h; GLfloat vertices[] = {x - w / 2.f, y - h / 2.f, x + w / 2.f, y - h / 2.f, x + w / 2.f, y + h / 2.f, x - w / 2.f, y + h / 2.f}; glVertexPointer(2, GL_FLOAT, 0, vertices); glTexCoordPointer(2, GL_FLOAT, 0, tex.indices); glDrawArrays(GL_QUADS, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } RenderManagerGL2D::RenderManagerGL2D() : RenderManager() { } RenderManager* RenderManager::createRenderManagerGL2D() { return new RenderManagerGL2D(); } void RenderManagerGL2D::init(int xResolution, int yResolution, bool fullscreen) { glDisable(GL_DEPTH_TEST); mCurrentFlags.insert(GL_MULTISAMPLE); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // Set modesetting Uint32 screenFlags = SDL_WINDOW_OPENGL; if (fullscreen) screenFlags |= SDL_WINDOW_FULLSCREEN; // Create window mWindow = SDL_CreateWindow(AppTitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, xResolution, yResolution, screenFlags); // Set icon SDL_Surface* icon = loadSurface("Icon.bmp"); SDL_SetColorKey(icon, SDL_TRUE, SDL_MapRGB(icon->format, 0, 0, 0)); SDL_SetWindowIcon(mWindow, icon); SDL_FreeSurface(icon); // Create gl context mGlContext = SDL_GL_CreateContext(mWindow); SDL_ShowCursor(0); glDisable(GL_MULTISAMPLE); mLeftBlobColor = Color(255, 0, 0); mRightBlobColor = Color(0, 255, 0); glEnable(GL_TEXTURE_2D); // Load background SDL_Surface* bgSurface = loadSurface("backgrounds/strand2.bmp"); BufferedImage* bgBufImage = new BufferedImage; bgBufImage->w = getNextPOT(bgSurface->w); bgBufImage->h = getNextPOT(bgSurface->h); bgBufImage->glHandle = loadTexture(bgSurface, false); mBackground = bgBufImage->glHandle; mImageMap["background"] = bgBufImage; mBallShadow = loadTexture(loadSurface("gfx/schball.bmp"), false); for (int i = 1; i <= 16; ++i) { char filename[64]; sprintf(filename, "gfx/ball%02d.bmp", i); GLuint ballImage = loadTexture(loadSurface(filename), false); mBall.push_back(ballImage); } for (int i = 1; i <= 5; ++i) { char filename[64]; sprintf(filename, "gfx/blobbym%d.bmp", i); GLuint blobImage = loadTexture(loadSurface(filename), false); mBlob.push_back(blobImage); sprintf(filename, "gfx/blobbym%d.bmp", i); GLuint blobSpecular = loadTexture(loadSurface(filename), true); mBlobSpecular.push_back(blobSpecular); sprintf(filename, "gfx/sch1%d.bmp", i); GLuint blobShadow = loadTexture(loadSurface(filename), false); mBlobShadow.push_back(blobShadow); } // create text base textures SDL_Surface* textbase = createEmptySurface(2048, 32); SDL_Surface* hltextbase = createEmptySurface(2048, 32); int x = 0; int sx = 0; for (int i = 0; i <= 54; ++i) { char filename[64]; sprintf(filename, "gfx/font%02d.bmp", i); SDL_Surface* fontSurface = loadSurface(filename); SDL_Surface* highlight = highlightSurface(fontSurface, 60); SDL_Rect r = {(Uint16)x, 0, (Uint16)fontSurface->w, (Uint16)fontSurface->h}; SDL_BlitSurface(fontSurface, 0, textbase, &r); SDL_BlitSurface(highlight, 0, hltextbase, &r); r.x = sx; r.y = 0; Texture s = Texture(0, x, 0, fontSurface->w, fontSurface->h, 2048, 32); mFont.push_back(s); mHighlightFont.push_back(s); x += fontSurface->w; SDL_FreeSurface(fontSurface); } GLuint texture = loadTexture(textbase, false); GLuint hltexture = loadTexture(hltextbase, false); for (unsigned int i = 0; i < mFont.size(); ++i) { mFont[i].texture = texture; mHighlightFont[i].texture = hltexture; } mParticle = loadTexture(loadSurface("gfx/blood.bmp"), false); glViewport(0, 0, xResolution, yResolution); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, 800, 600, 0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_TEXTURE_2D); glAlphaFunc(GL_GREATER, 0.5); glEnable(GL_ALPHA_TEST); } void RenderManagerGL2D::deinit() { glDeleteTextures(1, &mBackground); glDeleteTextures(mBall.size(), &mBall[0]); glDeleteTextures(1, &mBallShadow); glDeleteTextures(mBlob.size(), &mBlob[0]); glDeleteTextures(mBlobSpecular.size(), &mBlobSpecular[0]); glDeleteTextures(mBlobShadow.size(), &mBlobShadow[0]); glDeleteTextures(1/*mFont.size()*/, &mFont[0].texture); glDeleteTextures(/*mHighlightFont.size()*/1, &mHighlightFont[0].texture); for (std::map::iterator iter = mImageMap.begin(); iter != mImageMap.end(); ++iter) { glDeleteTextures(1, &(*iter).second->glHandle); delete iter->second; } glDeleteTextures(1, &mParticle); SDL_GL_DeleteContext(mGlContext); SDL_DestroyWindow(mWindow); } void RenderManagerGL2D::draw() { if (!mDrawGame) return; // Background glDisable(GL_ALPHA_TEST); glColor4f(1.0, 1.0, 1.0, 1.0); glBindTexture(mBackground); glLoadIdentity(); drawQuad(400.0, 300.0, 1024.0, 1024.0); if(mShowShadow) { // Generic shadow settings glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); // Blob shadows Vector2 pos; pos = blobShadowPosition(mLeftBlobPosition); glColor4ub(mLeftBlobColor.r, mLeftBlobColor.g, mLeftBlobColor.b, 128); glBindTexture(mBlobShadow[int(mLeftBlobAnimationState) % 5]); drawQuad(pos.x, pos.y, 128.0, 32.0); pos = blobShadowPosition(mRightBlobPosition); glColor4ub(mRightBlobColor.r, mRightBlobColor.g, mRightBlobColor.b, 128); glBindTexture(mBlobShadow[int(mRightBlobAnimationState) % 5]); drawQuad(pos.x, pos.y, 128.0, 32.0); // Ball shadow pos = ballShadowPosition(mBallPosition); glColor4f(1.0, 1.0, 1.0, 0.5); glBindTexture(mBallShadow); drawQuad(pos.x, pos.y, 128.0, 32.0); glDisable(GL_BLEND); } glEnable(GL_ALPHA_TEST); // General object settings glBlendFunc(GL_SRC_ALPHA, GL_ONE); // The Ball glColor4f(1.0, 1.0, 1.0, 1.0); glBindTexture(mBall[int(mBallRotation / M_PI / 2 * 16) % 16]); /* float opacity = 0.0; for (std::list::iterator iter = mLastBallStates.begin(); iter != mLastBallStates.end(); ++iter) { // glColor4f(1.0 / MotionBlurIterations, // 1.0 / MotionBlurIterations, 1.0 / MotionBlurIterations, 1.0 - opacity); glColor4f(1.0, 1.0, 1.0, opacity); Vector2& ballPosition = *iter; */ drawQuad(mBallPosition.x, mBallPosition.y, 64.0, 64.0); /* opacity += 0.1; } if (mLastBallStates.size() > MotionBlurIterations) mLastBallStates.pop_back(); glDisable(GL_BLEND); */ // blob normal // left blob glBindTexture(mBlob[int(mLeftBlobAnimationState) % 5]); glColor3ubv(mLeftBlobColor.val); drawQuad(mLeftBlobPosition.x, mLeftBlobPosition.y, 128.0, 128.0); // right blob glBindTexture(mBlob[int(mRightBlobAnimationState) % 5]); glColor3ubv(mRightBlobColor.val); drawQuad(mRightBlobPosition.x, mRightBlobPosition.y, 128.0, 128.0); // blob specular glEnable(GL_BLEND); glColor4f(1.0, 1.0, 1.0, 1.0); // left blob glBindTexture(mBlobSpecular[int(mLeftBlobAnimationState) % 5]); drawQuad(mLeftBlobPosition.x, mLeftBlobPosition.y, 128.0, 128.0); // right blob glBindTexture(mBlobSpecular[int(mRightBlobAnimationState) % 5]); drawQuad(mRightBlobPosition.x, mRightBlobPosition.y, 128.0, 128.0); glDisable(GL_BLEND); // Ball marker glDisable(GL_ALPHA_TEST); glDisable(GL_TEXTURE_2D); GLubyte markerColor = SDL_GetTicks() % 1000 >= 500 ? 255 : 0; glColor3ub(markerColor, markerColor, markerColor); drawQuad(mBallPosition.x, 7.5, 5.0, 5.0); // Mouse marker // Position relativ zu BallMarker drawQuad(mMouseMarkerPosition, 592.5, 5.0, 5.0); glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); } bool RenderManagerGL2D::setBackground(const std::string& filename) { try { SDL_Surface* newSurface = loadSurface(filename); glDeleteTextures(1, &mBackground); delete mImageMap["background"]; BufferedImage *imgBuffer = new BufferedImage; imgBuffer->w = getNextPOT(newSurface->w); imgBuffer->h = getNextPOT(newSurface->h); imgBuffer->glHandle = loadTexture(newSurface, false); mBackground = imgBuffer->glHandle; mImageMap["background"] = imgBuffer; } catch (FileLoadException) { return false; } return true; } void RenderManagerGL2D::setBlobColor(int player, Color color) { if (player == LEFT_PLAYER) mLeftBlobColor = color; if (player == RIGHT_PLAYER) mRightBlobColor = color; } void RenderManagerGL2D::showShadow(bool shadow) { mShowShadow = shadow; } void RenderManagerGL2D::setBall(const Vector2& position, float rotation) { mBallPosition = position; mBallRotation = rotation; static int mbCounter = 0; mbCounter++; if (mbCounter > 1) { mLastBallStates.push_front(position); mbCounter = 0; } } void RenderManagerGL2D::setBlob(int player, const Vector2& position, float animationState) { if (player == LEFT_PLAYER) { mLeftBlobPosition = position; mLeftBlobAnimationState = animationState; } if (player == RIGHT_PLAYER) { mRightBlobPosition = position; mRightBlobAnimationState = animationState; } } void RenderManagerGL2D::drawText(const std::string& text, Vector2 position, unsigned int flags) { glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glDisable(GL_BLEND); glColor4f(1.0, 1.0, 1.0, 1.0); int FontSize = (flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL); float x = position.x - (FontSize / 2); float y = position.y + (FontSize / 2); for (auto iter = text.cbegin(); iter != text.cend(); ) { int index = getNextFontIndex(iter); if (flags & TF_OBFUSCATE) index = FONT_INDEX_ASTERISK; x += FontSize; if (flags & TF_SMALL_FONT) { if (flags & TF_HIGHLIGHT) { int charWidth = mHighlightFont[index].w; int charHeight = mHighlightFont[index].h; mHighlightFont[index].w = FONT_WIDTH_SMALL; mHighlightFont[index].h = FONT_WIDTH_SMALL; drawQuad(x, y, mHighlightFont[index]); mHighlightFont[index].w = charWidth; mHighlightFont[index].h = charHeight; } else { int charWidth = mFont[index].w; int charHeight = mFont[index].h; mFont[index].w = FONT_WIDTH_SMALL; mFont[index].h = FONT_WIDTH_SMALL; drawQuad(x, y, mFont[index]); mFont[index].w = charWidth; mFont[index].h = charHeight; } } else { if (flags & TF_HIGHLIGHT) drawQuad(x, y, mHighlightFont[index]); else drawQuad(x, y, mFont[index]); } } } void RenderManagerGL2D::drawImage(const std::string& filename, Vector2 position, Vector2 size) { glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glDisable(GL_BLEND); BufferedImage* imageBuffer = mImageMap[filename]; if (!imageBuffer) { imageBuffer = new BufferedImage; SDL_Surface* newSurface = loadSurface(filename); imageBuffer->w = getNextPOT(newSurface->w); imageBuffer->h = getNextPOT(newSurface->h); imageBuffer->glHandle = loadTexture(newSurface, false); mImageMap[filename] = imageBuffer; } glColor4f(1.0, 1.0, 1.0, 1.0); glDisable(GL_BLEND); //glLoadIdentity(); //glTranslatef(position.x , position.y, 0.0); glBindTexture(imageBuffer->glHandle); drawQuad(position.x, position.y, imageBuffer->w, imageBuffer->h); } void RenderManagerGL2D::drawOverlay(float opacity, Vector2 pos1, Vector2 pos2, Color col) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_TEXTURE_2D); glDisable(GL_ALPHA_TEST); glEnable(GL_BLEND); glColor4f(col.r, col.g, col.b, opacity); //glLoadIdentity(); glBegin(GL_QUADS); glVertex2f(pos1.x, pos1.y); glVertex2f(pos1.x, pos2.y); glVertex2f(pos2.x, pos2.y); glVertex2f(pos2.x, pos1.y); glEnd(); } void RenderManagerGL2D::drawBlob(const Vector2& pos, const Color& col) { glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glDisable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); //glLoadIdentity(); //glTranslatef(pos.x, pos.y, 0.6); glBindTexture(mBlob[0]); glColor3ubv(col.val); drawQuad(pos.x, pos.y, 128.0, 128.0); glEnable(GL_BLEND); glColor4f(1.0, 1.0, 1.0, 1.0); glBindTexture(mBlobSpecular[0]); drawQuad(pos.x, pos.y, 128.0, 128.0); glDisable(GL_BLEND); } void RenderManagerGL2D::startDrawParticles() { glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glDisable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBindTexture(mParticle); glBegin(GL_QUADS); } void RenderManagerGL2D::drawParticle(const Vector2& pos, int player) { //glLoadIdentity(); //glTranslatef(pos.x, pos.y, 0.6); if (player == LEFT_PLAYER) glColor3ubv(mLeftBlobColor.val); if (player == RIGHT_PLAYER) glColor3ubv(mRightBlobColor.val); if (player > 1) glColor3ubv(Color(255, 0, 0).val); float w = 16.0; float h = 16.0; glTexCoord2f(0.0, 0.0); glVertex2f(pos.x - w / 2.0, pos.y - h / 2.0); glTexCoord2f(1.0, 0.0); glVertex2f(pos.x + w / 2.0, pos.y - h / 2.0); glTexCoord2f(1.0, 1.0); glVertex2f(pos.x + w / 2.0, pos.y + h / 2.0); glTexCoord2f(0.0, 1.0); glVertex2f(pos.x - w / 2.0, pos.y + h / 2.0); } void RenderManagerGL2D::endDrawParticles() { glEnd(); } void RenderManagerGL2D::refresh() { //std::cout << debugStateChanges << "\n"; SDL_GL_SwapWindow(mWindow); debugStateChanges = 0; //std::cerr << debugBindTextureCount << "\n"; debugBindTextureCount = 0; } #else RenderManager* RenderManager::createRenderManagerGL2D() { std::cerr << "OpenGL not available! Falling back to SDL renderer" << std::endl; return RenderManager::createRenderManagerSDL(); } #endif blobby-1.0/data/replays/000755 001750 001750 00000000000 12313310254 017775 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/data/scripts/axji-0-2.lua000644 001750 001750 00000006002 12313310254 021735 0ustar00danielknobedanielknobe000000 000000 -- 15.01.14 - ngc92: Use blobby volley api provided constants when possible function OnOpponentServe() moveto(120) end -- Flags und runners wait = 0 aggro = true -- evtl Variablennamen wechseln aggroservice = 50 -- versetzung zum Ball je gr�sser desto tiefer fliegt der Service 0-64( 64 ist ca CONST_BALLRADIUS + CONST_BLOBBY_BAUCH_RADIUS) -- Korrekturfaktor f�r die Flugberechnung korrekturfaktor = 7 -- Konstanten CONST_MITTE = CONST_FIELD_WIDTH/2 -- Linke Ber�hrungsebene des Balls falls er ans Netz kommt CONST_NETZ_LINKS = CONST_MITTE - CONST_NET_RADIUS - CONST_BALL_RADIUS function OnServe(ballready) moveto(ballx()) wait = wait + 1 aggro = true if ballready then if wait > 90 then jump() wait = 0 end end end function OnGame() aggroflagtesten() -- schaut ob der bot aggro werden soll oder nicht target = estimImpact() if aggro then sprungattacke(aggroservice) return end -- Zielbestimmung --> optimierung weniger CPU power n�tig ;) if (target < CONST_BALL_RADIUS) then -- ball wird hinten apprallen vonhinten(target) return end -- nun k�mmern wir uns um die B�lle die ans netz prallen if ((target > CONST_NETZ_LINKS) and (ballx() < CONST_NETZ_LINKS)) then netzappraller(target) return end if (bspeedx() < 10 ) then moveto(target - 20) else moveto(target) end end function netzappraller(p_target) --moveto(netzlinks - (netzlinks - estimate())) moveto(CONST_NETZ_LINKS - (p_target - CONST_NETZ_LINKS) + math.abs(bspeedx()*bspeedx()*1.4)) end function vonhinten(p_target) p_target = CONST_BALL_RADIUS + math.abs(CONST_BALL_RADIUS-p_target) --das ist der fall wenn der Ball hinten abprallt moveto(p_target-math.abs(bspeedx()*bspeedx()*1.1)) end function sprungattacke(p_aggroservice) moveto(ballx()-p_aggroservice) if bally() < 580 then jump() end end function aggroflagtesten() if (ballx() > CONST_MITTE) then aggro = false return end if (touches() == 2) then aggro = true return end if ((ballx() < (400-CONST_BALL_RADIUS)) and (bally() < 200) and (math.abs(bspeedx()) < 40)) then -- der ball k�nnte nohc dr�ber fliegen ** noch optimieren aggro = true return end end function estimTime() bgrav = 0.248 -- standart Realfloor ist 144 -- warscheinilcher Realflfoor f�r Ball + blobby ist 144 (der Ball muss schon berechnet worden sein) realFloor = 144 by=bally() vby=bspeedy()-600 time1 =(-vby+math.sqrt((vby^2)-(4*-0.5*bgrav*(by-realFloor))))/(-2*0.5*bgrav) time2 =(-vby-math.sqrt((vby^2)-(4*-0.5*bgrav*(by-realFloor))))/(-2*0.5*bgrav) if time1>time2 then time3 = time1 else time3 = time2 end return time3 --ist die Funktion nicht auf folgende aussage minimierbar ? -- time1 =(-vby-math.sqrt((vby^2)-(-2*bgrav*(by-realFloor))))/-bgrav -- return time1 end function estimImpact() --diese Funktion sollte die einschlagkoordinaten auf K�pfh�he Rechnen bx=ballx() vbx=bspeedx() time3 = estimTime() resultX = (vbx * time3) + bx return resultX endblobby-1.0/src/lua/lcode.c000644 001750 001750 00000053604 12313310253 020216 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lcode.c,v 2.62.1.1 2013/04/12 18:48:47 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ #include #define lcode_c #define LUA_CORE #include "lua.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstring.h" #include "ltable.h" #include "lvm.h" #define hasjumps(e) ((e)->t != (e)->f) static int isnumeral(expdesc *e) { return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); } void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; int l = from + n - 1; /* last register to set nil */ if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ previous = &fs->f->code[fs->pc-1]; if (GET_OPCODE(*previous) == OP_LOADNIL) { int pfrom = GETARG_A(*previous); int pl = pfrom + GETARG_B(*previous); if ((pfrom <= from && from <= pl + 1) || (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ if (pl > l) l = pl; /* l = max(l, pl) */ SETARG_A(*previous, from); SETARG_B(*previous, l - from); return; } } /* else go through */ } luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ } int luaK_jump (FuncState *fs) { int jpc = fs->jpc; /* save list of jumps to here */ int j; fs->jpc = NO_JUMP; j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); luaK_concat(fs, &j, jpc); /* keep them on hold */ return j; } void luaK_ret (FuncState *fs, int first, int nret) { luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); } static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); } static void fixjump (FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; int offset = dest-(pc+1); lua_assert(dest != NO_JUMP); if (abs(offset) > MAXARG_sBx) luaX_syntaxerror(fs->ls, "control structure too long"); SETARG_sBx(*jmp, offset); } /* ** returns current `pc' and marks it as a jump target (to avoid wrong ** optimizations with consecutive instructions not in the same basic block). */ int luaK_getlabel (FuncState *fs) { fs->lasttarget = fs->pc; return fs->pc; } static int getjump (FuncState *fs, int pc) { int offset = GETARG_sBx(fs->f->code[pc]); if (offset == NO_JUMP) /* point to itself represents end of list */ return NO_JUMP; /* end of list */ else return (pc+1)+offset; /* turn offset into absolute position */ } static Instruction *getjumpcontrol (FuncState *fs, int pc) { Instruction *pi = &fs->f->code[pc]; if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) return pi-1; else return pi; } /* ** check whether list has any jump that do not produce a value ** (or produce an inverted value) */ static int need_value (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) { Instruction i = *getjumpcontrol(fs, list); if (GET_OPCODE(i) != OP_TESTSET) return 1; } return 0; /* not found */ } static int patchtestreg (FuncState *fs, int node, int reg) { Instruction *i = getjumpcontrol(fs, node); if (GET_OPCODE(*i) != OP_TESTSET) return 0; /* cannot patch other instructions */ if (reg != NO_REG && reg != GETARG_B(*i)) SETARG_A(*i, reg); else /* no register to put value or register already has the value */ *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); return 1; } static void removevalues (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) patchtestreg(fs, list, NO_REG); } static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, int dtarget) { while (list != NO_JUMP) { int next = getjump(fs, list); if (patchtestreg(fs, list, reg)) fixjump(fs, list, vtarget); else fixjump(fs, list, dtarget); /* jump to default target */ list = next; } } static void dischargejpc (FuncState *fs) { patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } void luaK_patchlist (FuncState *fs, int list, int target) { if (target == fs->pc) luaK_patchtohere(fs, list); else { lua_assert(target < fs->pc); patchlistaux(fs, list, target, NO_REG, target); } } LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level) { level++; /* argument is +1 to reserve 0 as non-op */ while (list != NO_JUMP) { int next = getjump(fs, list); lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && (GETARG_A(fs->f->code[list]) == 0 || GETARG_A(fs->f->code[list]) >= level)); SETARG_A(fs->f->code[list], level); list = next; } } void luaK_patchtohere (FuncState *fs, int list) { luaK_getlabel(fs); luaK_concat(fs, &fs->jpc, list); } void luaK_concat (FuncState *fs, int *l1, int l2) { if (l2 == NO_JUMP) return; else if (*l1 == NO_JUMP) *l1 = l2; else { int list = *l1; int next; while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ list = next; fixjump(fs, list, l2); } } static int luaK_code (FuncState *fs, Instruction i) { Proto *f = fs->f; dischargejpc(fs); /* `pc' will change */ /* put new instruction in code array */ luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, MAX_INT, "opcodes"); f->code[fs->pc] = i; /* save corresponding line information */ luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int, MAX_INT, "opcodes"); f->lineinfo[fs->pc] = fs->ls->lastline; return fs->pc++; } int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { lua_assert(getOpMode(o) == iABC); lua_assert(getBMode(o) != OpArgN || b == 0); lua_assert(getCMode(o) != OpArgN || c == 0); lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); return luaK_code(fs, CREATE_ABC(o, a, b, c)); } int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); lua_assert(getCMode(o) == OpArgN); lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); return luaK_code(fs, CREATE_ABx(o, a, bc)); } static int codeextraarg (FuncState *fs, int a) { lua_assert(a <= MAXARG_Ax); return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); } int luaK_codek (FuncState *fs, int reg, int k) { if (k <= MAXARG_Bx) return luaK_codeABx(fs, OP_LOADK, reg, k); else { int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); codeextraarg(fs, k); return p; } } void luaK_checkstack (FuncState *fs, int n) { int newstack = fs->freereg + n; if (newstack > fs->f->maxstacksize) { if (newstack >= MAXSTACK) luaX_syntaxerror(fs->ls, "function or expression too complex"); fs->f->maxstacksize = cast_byte(newstack); } } void luaK_reserveregs (FuncState *fs, int n) { luaK_checkstack(fs, n); fs->freereg += n; } static void freereg (FuncState *fs, int reg) { if (!ISK(reg) && reg >= fs->nactvar) { fs->freereg--; lua_assert(reg == fs->freereg); } } static void freeexp (FuncState *fs, expdesc *e) { if (e->k == VNONRELOC) freereg(fs, e->u.info); } static int addk (FuncState *fs, TValue *key, TValue *v) { lua_State *L = fs->ls->L; TValue *idx = luaH_set(L, fs->h, key); Proto *f = fs->f; int k, oldsize; if (ttisnumber(idx)) { lua_Number n = nvalue(idx); lua_number2int(k, n); if (luaV_rawequalobj(&f->k[k], v)) return k; /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0"); go through and create a new entry for this value */ } /* constant not found; create a new entry */ oldsize = f->sizek; k = fs->nk; /* numerical value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ setnvalue(idx, cast_num(k)); luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[k], v); fs->nk++; luaC_barrier(L, f, v); return k; } int luaK_stringK (FuncState *fs, TString *s) { TValue o; setsvalue(fs->ls->L, &o, s); return addk(fs, &o, &o); } int luaK_numberK (FuncState *fs, lua_Number r) { int n; lua_State *L = fs->ls->L; TValue o; setnvalue(&o, r); if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */ /* use raw representation as key to avoid numeric problems */ setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r))); n = addk(fs, L->top - 1, &o); L->top--; } else n = addk(fs, &o, &o); /* regular case */ return n; } static int boolK (FuncState *fs, int b) { TValue o; setbvalue(&o, b); return addk(fs, &o, &o); } static int nilK (FuncState *fs) { TValue k, v; setnilvalue(&v); /* cannot use nil as key; instead use table itself to represent nil */ sethvalue(fs->ls->L, &k, fs->h); return addk(fs, &k, &v); } void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { if (e->k == VCALL) { /* expression is an open function call? */ SETARG_C(getcode(fs, e), nresults+1); } else if (e->k == VVARARG) { SETARG_B(getcode(fs, e), nresults+1); SETARG_A(getcode(fs, e), fs->freereg); luaK_reserveregs(fs, 1); } } void luaK_setoneret (FuncState *fs, expdesc *e) { if (e->k == VCALL) { /* expression is an open function call? */ e->k = VNONRELOC; e->u.info = GETARG_A(getcode(fs, e)); } else if (e->k == VVARARG) { SETARG_B(getcode(fs, e), 2); e->k = VRELOCABLE; /* can relocate its simple result */ } } void luaK_dischargevars (FuncState *fs, expdesc *e) { switch (e->k) { case VLOCAL: { e->k = VNONRELOC; break; } case VUPVAL: { e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); e->k = VRELOCABLE; break; } case VINDEXED: { OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */ freereg(fs, e->u.ind.idx); if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */ freereg(fs, e->u.ind.t); op = OP_GETTABLE; } e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); e->k = VRELOCABLE; break; } case VVARARG: case VCALL: { luaK_setoneret(fs, e); break; } default: break; /* there is one value available (somewhere) */ } } static int code_label (FuncState *fs, int A, int b, int jump) { luaK_getlabel(fs); /* those instructions may be jump targets */ return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); } static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_dischargevars(fs, e); switch (e->k) { case VNIL: { luaK_nil(fs, reg, 1); break; } case VFALSE: case VTRUE: { luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); break; } case VK: { luaK_codek(fs, reg, e->u.info); break; } case VKNUM: { luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); break; } case VRELOCABLE: { Instruction *pc = &getcode(fs, e); SETARG_A(*pc, reg); break; } case VNONRELOC: { if (reg != e->u.info) luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); break; } default: { lua_assert(e->k == VVOID || e->k == VJMP); return; /* nothing to do... */ } } e->u.info = reg; e->k = VNONRELOC; } static void discharge2anyreg (FuncState *fs, expdesc *e) { if (e->k != VNONRELOC) { luaK_reserveregs(fs, 1); discharge2reg(fs, e, fs->freereg-1); } } static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) luaK_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(fs, e->t) || need_value(fs, e->f)) { int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); p_f = code_label(fs, reg, 0, 1); p_t = code_label(fs, reg, 1, 0); luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); patchlistaux(fs, e->f, final, reg, p_f); patchlistaux(fs, e->t, final, reg, p_t); } e->f = e->t = NO_JUMP; e->u.info = reg; e->k = VNONRELOC; } void luaK_exp2nextreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); freeexp(fs, e); luaK_reserveregs(fs, 1); exp2reg(fs, e, fs->freereg - 1); } int luaK_exp2anyreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); if (e->k == VNONRELOC) { if (!hasjumps(e)) return e->u.info; /* exp is already in a register */ if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ exp2reg(fs, e, e->u.info); /* put value on it */ return e->u.info; } } luaK_exp2nextreg(fs, e); /* default */ return e->u.info; } void luaK_exp2anyregup (FuncState *fs, expdesc *e) { if (e->k != VUPVAL || hasjumps(e)) luaK_exp2anyreg(fs, e); } void luaK_exp2val (FuncState *fs, expdesc *e) { if (hasjumps(e)) luaK_exp2anyreg(fs, e); else luaK_dischargevars(fs, e); } int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); switch (e->k) { case VTRUE: case VFALSE: case VNIL: { if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */ e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); e->k = VK; return RKASK(e->u.info); } else break; } case VKNUM: { e->u.info = luaK_numberK(fs, e->u.nval); e->k = VK; /* go through */ } case VK: { if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */ return RKASK(e->u.info); else break; } default: break; } /* not a constant in the right range: put it in a register */ return luaK_exp2anyreg(fs, e); } void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { freeexp(fs, ex); exp2reg(fs, ex, var->u.info); return; } case VUPVAL: { int e = luaK_exp2anyreg(fs, ex); luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); break; } case VINDEXED: { OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; int e = luaK_exp2RK(fs, ex); luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); break; } default: { lua_assert(0); /* invalid var kind to store */ break; } } freeexp(fs, ex); } void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { int ereg; luaK_exp2anyreg(fs, e); ereg = e->u.info; /* register where 'e' was placed */ freeexp(fs, e); e->u.info = fs->freereg; /* base register for op_self */ e->k = VNONRELOC; luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); freeexp(fs, key); } static void invertjump (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->u.info); lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && GET_OPCODE(*pc) != OP_TEST); SETARG_A(*pc, !(GETARG_A(*pc))); } static int jumponcond (FuncState *fs, expdesc *e, int cond) { if (e->k == VRELOCABLE) { Instruction ie = getcode(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); } /* else go through */ } discharge2anyreg(fs, e); freeexp(fs, e); return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); } void luaK_goiftrue (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { case VJMP: { invertjump(fs, e); pc = e->u.info; break; } case VK: case VKNUM: case VTRUE: { pc = NO_JUMP; /* always true; do nothing */ break; } default: { pc = jumponcond(fs, e, 0); break; } } luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ luaK_patchtohere(fs, e->t); e->t = NO_JUMP; } void luaK_goiffalse (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { case VJMP: { pc = e->u.info; break; } case VNIL: case VFALSE: { pc = NO_JUMP; /* always false; do nothing */ break; } default: { pc = jumponcond(fs, e, 1); break; } } luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ luaK_patchtohere(fs, e->f); e->f = NO_JUMP; } static void codenot (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); switch (e->k) { case VNIL: case VFALSE: { e->k = VTRUE; break; } case VK: case VKNUM: case VTRUE: { e->k = VFALSE; break; } case VJMP: { invertjump(fs, e); break; } case VRELOCABLE: case VNONRELOC: { discharge2anyreg(fs, e); freeexp(fs, e); e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); e->k = VRELOCABLE; break; } default: { lua_assert(0); /* cannot happen */ break; } } /* interchange true and false lists */ { int temp = e->f; e->f = e->t; e->t = temp; } removevalues(fs, e->f); removevalues(fs, e->t); } void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { lua_assert(!hasjumps(t)); t->u.ind.t = t->u.info; t->u.ind.idx = luaK_exp2RK(fs, k); t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : check_exp(vkisinreg(t->k), VLOCAL); t->k = VINDEXED; } static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { lua_Number r; if (!isnumeral(e1) || !isnumeral(e2)) return 0; if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0) return 0; /* do not attempt to divide by 0 */ r = luaO_arith(op - OP_ADD + LUA_OPADD, e1->u.nval, e2->u.nval); e1->u.nval = r; return 1; } static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2, int line) { if (constfolding(op, e1, e2)) return; else { int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; int o1 = luaK_exp2RK(fs, e1); if (o1 > o2) { freeexp(fs, e1); freeexp(fs, e2); } else { freeexp(fs, e2); freeexp(fs, e1); } e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); e1->k = VRELOCABLE; luaK_fixline(fs, line); } } static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, expdesc *e2) { int o1 = luaK_exp2RK(fs, e1); int o2 = luaK_exp2RK(fs, e2); freeexp(fs, e2); freeexp(fs, e1); if (cond == 0 && op != OP_EQ) { int temp; /* exchange args to replace by `<' or `<=' */ temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ cond = 1; } e1->u.info = condjump(fs, op, cond, o1, o2); e1->k = VJMP; } void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { expdesc e2; e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; switch (op) { case OPR_MINUS: { if (isnumeral(e)) /* minus constant? */ e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */ else { luaK_exp2anyreg(fs, e); codearith(fs, OP_UNM, e, &e2, line); } break; } case OPR_NOT: codenot(fs, e); break; case OPR_LEN: { luaK_exp2anyreg(fs, e); /* cannot operate on constants */ codearith(fs, OP_LEN, e, &e2, line); break; } default: lua_assert(0); } } void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { switch (op) { case OPR_AND: { luaK_goiftrue(fs, v); break; } case OPR_OR: { luaK_goiffalse(fs, v); break; } case OPR_CONCAT: { luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: case OPR_MOD: case OPR_POW: { if (!isnumeral(v)) luaK_exp2RK(fs, v); break; } default: { luaK_exp2RK(fs, v); break; } } } void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2, int line) { switch (op) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->f, e1->f); *e1 = *e2; break; } case OPR_OR: { lua_assert(e1->f == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->t, e1->t); *e1 = *e2; break; } case OPR_CONCAT: { luaK_exp2val(fs, e2); if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1); freeexp(fs, e1); SETARG_B(getcode(fs, e2), e1->u.info); e1->k = VRELOCABLE; e1->u.info = e2->u.info; } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ codearith(fs, OP_CONCAT, e1, e2, line); } break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: case OPR_MOD: case OPR_POW: { codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line); break; } case OPR_EQ: case OPR_LT: case OPR_LE: { codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2); break; } case OPR_NE: case OPR_GT: case OPR_GE: { codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2); break; } default: lua_assert(0); } } void luaK_fixline (FuncState *fs, int line) { fs->f->lineinfo[fs->pc - 1] = line; } void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; int b = (tostore == LUA_MULTRET) ? 0 : tostore; lua_assert(tostore != 0); if (c <= MAXARG_C) luaK_codeABC(fs, OP_SETLIST, base, b, c); else if (c <= MAXARG_Ax) { luaK_codeABC(fs, OP_SETLIST, base, b, 0); codeextraarg(fs, c); } else luaX_syntaxerror(fs->ls, "constructor too long"); fs->freereg = base + 1; /* free registers with list values */ } blobby-1.0/src/lua/lcode.h000644 001750 001750 00000006060 12313310253 020215 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lcode.h,v 1.58.1.1 2013/04/12 18:48:47 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ #ifndef lcode_h #define lcode_h #include "llex.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" /* ** Marks the end of a patch list. It is an invalid value both as an absolute ** address, and as a list link (would link an element to itself). */ #define NO_JUMP (-1) /* ** grep "ORDER OPR" if you change these enums (ORDER OP) */ typedef enum BinOpr { OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, OPR_CONCAT, OPR_EQ, OPR_LT, OPR_LE, OPR_NE, OPR_GT, OPR_GE, OPR_AND, OPR_OR, OPR_NOBINOPR } BinOpr; typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define getcode(fs,e) ((fs)->f->code[(e)->u.info]) #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_jump (FuncState *fs); LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level); LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); LUAI_FUNC int luaK_getlabel (FuncState *fs); LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2, int line); LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); #endif blobby-1.0/data/gfx/ball12.bmp000644 001750 001750 00000012066 12313310254 020664 0ustar00danielknobedanielknobe000000 000000 BM66(@@  \[][Z\|{}wuxfcfqoqihi^]^XWXywx\ZZ|zzxvv~~igf`_^yxw ZZW$$#ppoddc\\[hif`a^ [^[z}zcecvxvopohih  []]TUUwxxoppklp--.zz|<<=gghXXY}}}|||yyyuuurrrmmmjjjfffeeedddcccbbb```___YYYWWWOOOJJJ&d<얖M[>uw{۞ ww"Kl!Z>tڞuZww!KkKlgw{9gZZ)uu?ݟ'&KLtٞڞutYtZ?wiK󗂂M)Zt t؞KMMמZgZZxsӜXu6ܟwwwwxMMMuu/6w6wwx9>WZXXX͏6(ttZwwx 86yVZZɌXXXtڞtZZwwK.556ˌZZttww&k8ȋ5ƋʌX6ʌ6tttwwb W_VʌV6Xtuw 'My__ŋ6stܟ7 MrUVVUY6ZxGLM:UyȋrUUUUřXx* %_U-./UUrXsWX@wib=MrUÊeÊU-˝Vtvvw!"hG&쉉rXĉUyXZڞuuZZ@Z{ 3SSSTҝ^>۟xR}SRSSrXs^)w{+R1SSRRSS_g^e6gYtvSQQ}RRSS3-.XfΜ(tR1p}R23,‰‰ˏQ|QQ,ˌ ooP|QS3TeXfoPQnnOoo}QTTŌO0Q|2W6mmoQSPIQ2+TmoooSmHNooQSRSTHQQRRSHQ1PQRRjmoSOmommoRmmSSIonm0ѺRblobby-1.0/data/gfx/blobbym2.bmp000644 001750 001750 00000017242 12313310254 021320 0ustar00danielknobedanielknobe000000 000000 BM6(KYl  ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,! ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,!! ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"!!! ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#""!!! ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,$#"""!!! ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,$##"""!!! ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,$$##"""!!! ,,,,,,,,,,,,,,,,,,,,,,,,,,,%$$##"""!!!! ,,,,,,,,,,,,,,,,,,,,,,,,'%%$$###"""!!!! ,,,,,,,,,,,,,,,,,,,,,,&%%$$###""""!!!! ,,,,,,,,,,,,,,,,,,,,,'&%%$$$###""""!!!! ,,,,,,,,,,,,,,,,,,,('&%%%$$####""""!!!! ,,,,,,,,,,,,,,,,,,('&&%%$$####"""""!!!!   ,,,,,,,,,,,,,,,,,((&&%$$##""""!!!!!!!!  ,,,,,,,,,,,,,,,)('%%$###""!!!!!    ,,,,,,,,,,,,,,('&%$##""!!!!    ,,,,,,,,,,,,,)'&%$##""!!    !,,,,,,,,,,,,(&%$#""!!!   !,,,,,,,,,,,(&%$#""!!  !",,,,,,,,,,'&$#""!!  !!",,,,,,,,,,&%$#"!!  !!!!",,,,,,,,,&%$#"!!  !!!!!!!!!!!!!""#,,,,,,,,%$#""!  !!!!!!!!!!!"""#,,,,,,,,#""!!  !!!!!!""""""#$,,,,,,,,"!!  !!"""""""###$,,,,,,,,!!  !""""#####$$,,,,,,,,!  !!""#####$$%,,,,,,,,  !!"##$$$$%%,,,,,,,, !!""#$$%%%&,,,,,,,, !""#$%%%&&,,,,,,,, !!"#$%&&&',,,,,,,, !!"#$%&''(,,,,,,,, !!"#$%&'(*,,,,,,,,, !""$%&'*,,,,,,,,,, !""$%&(*,,,,,,,,,, !""$%')+,,,,,,,,,,, !!!!!!!!! !"#%&(),,,,,,,,,,,, !!!!!!!""###########"""#$%((*,,,,,,,,,,,,, !!!""""""####$$$$%%%%%%&&&&%%%''(),,,,,,,,,,,,,, !!!"""####$$$$$%%%&&&&&'''''(((((((),,,,,,,,,,,,,,, !!!"""###$$$$%%%&&&&'''(((((())****(,,,,,,,,,,,,,,,,, !!!"""####$$$%%%&&&'''((((()***+++++,,,,,,,,,,,,,,,,,, !!!!"""###$$$%%%&&&'''(((())**+++++++,,,,,,,,,,,,,,,,,,, !!!""""###$$$%%%&&'''(((())**+++++++,,,,,,,,,,,,,,,,,,,, !!!"""####$$%%%&&&'''(((()***++++++*,,,,,,,,,,,,,,,,,,,, !!!"""####$$%%%&&&'''((())**+++*****,,,,,,,,,,,,,,,,,,,, !!!"""####$$%%%&&&'''((((())****)))),,,,,,,,,,,,,,,,,,,, !!!"""####$$%%%&&&&'''''((((())(((((,,,,,,,,,,,,,,,,,,,,, !!!"""####$$$%%%%%&&&&''''(((((((((,,,,,,,,,,,,,,,,,,,,,, !!!!""####$$$$$%%%%%&&&&'''((((((((,,,,,,,,,,,,,,,,,,,,,, !!!!""#####$$$$$$%%%%&&&'''((((((((,,,,,,,,,,,,,,,,,,,,,, !!!"""######$$$$$%%%%&&&'''((((((((,,,,,,,,,,,,,,,,,,,,,,, !!!"""######$$$$$%%%%&&&'''(((((((,,,,,,,,,,,,,,,,,,,,,,,, !!!"""######$$$$$%%%%&&&'''(((((((,,,,,,,,,,,,,,,,,,,,,,,, !!!"""######$$$$$%%%%&&&&'''(((((((,,,,,,,,,,,,,,,,,,,,,,,, !!!"""####$$$$$$%%%%%&&&&'''((((((((,,,,,,,,,,,,,,,,,,,,,,,, !!!"""###$$$$$$%%%%%&&&&''''(((((((((,,,,,,,,,,,,,,,,,,,,,,,,, !!!""""###$$$$$$%%%%&&&''''((((((((((,,,,,,,,,,,,,,,,,,,,,,,,,, !!!!"""######$$$$%%%&&&''(((((((((,,,,,,,,,,,,,,,,,,,,,,,,,, !!!""""""####$$$%%&&&'((((((((,,,,,,,,,,,,,,,,,,,,,,,,,, !!!!!!""""###$$$%%&&''((((((,,,,,,,,,,,,,,,,,,,,,,,,,, !!!!!"""###$$%%&&'('''',,,,,,,,,,,,,,,,,,,,,,,,,, !!!"""##$$%%&''''(,,,,,,,,,,,,,,,,,,,,,,,,,,, !!!""##$%%&'(,,,,,,,,,,,,,,,,,,,,,,,,,,,, !!"#$$%&((,,,,,,,,,,,,,,,,,,,,,,,,,,,, !!"##$%&(),,,,,,,,,,,,,,,,,,,,,,,,,,,, !!"##$%&(*,,,,,,,,,,,,,,,,,,,,,,,,,,,,, !!"##$%&(,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,   !!"##$%'),,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, !!"#$$&',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,   !!"#$%&',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,  !!"#$%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,  !"#$%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, !"$,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,   !",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, !,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,blobby-1.0/data/gfx/font24.bmp000644 001750 001750 00000003366 12313310254 020726 0ustar00danielknobedanielknobe000000 000000 BM6( - B@C@ :0 &f}"$c A %-:PSfbsZk:K ` 3"| 3IVEIz %9:I]`zBL| A( %)4)HJmim)/L!*"Y%~€<>J*1 )yzED&%E16}}SO303>A ˌ^W62k SU /65JXN-(ELL23UuqxODvEEWW} (蠏hX)7,,Nrr>?7yrkD4Xzzll55j>;Gݜ~qVBBb``88F Ԅe,!/{{``??)Ǡߊe+/(ϓff99i"әq:*<AAUꞞii;:]&  w>0Akk~߰놆QQk%#.D:HǜΤw+!,ccr׽䥣nm:9E!("*Ю̟ИpIIOדlhwJGP.+/3/6[T_յʝF5F..0ƿϒ³ȴ˵ֺYGXedh̼j_i../ZYZ}z}~y|TQS!blobby-1.0/data/gfx/flag.bmp000644 001750 001750 00000042142 12313310254 020516 0ustar00danielknobedanielknobe000000 000000 BMbDzlFRC BGRs                                         ---LLLyyyƼoooBBB    RRR777    777ώ   ///|||۝   VVV~~~ hhh𔔔 ddd :::  *** <<< ^^^ yyy 펎 '''񩩩 ///󻻻 666 ???$$$ GGG333 OOOIII [[[``` hhhyyy uuu 򦦦 򴴴 򢢢 xxx RRR 111  󶶶  jjj ::: ɾ򸸸''' Ҿooo@@@???uuu򝝝 бvvv444@@@{{{ ˟LLL  ^^^VVV ױOOO  \\\333  zzz  +++ YYY  TTTTTT ///       blobby-1.0/data/lang_de.xml000644 001750 001750 00000015631 12313310254 020437 0ustar00danielknobedanielknobe000000 000000 blobby-1.0/test/FileTest.cpp000644 001750 001750 00000032571 12313310246 020620 0ustar00danielknobedanielknobe000000 000000 #define BOOST_TEST_MODULE FileAbstraction #include #include "FileRead.h" #include "FileWrite.h" #include "FileSystem.h" #include #include #include #define TEST_EXECUTION_PATH "C:\\Dokumente und Einstellungen\\Erik\\Eigene Dateien\\Blobby Volley 2\\test" // helper void init_Physfs() { static bool initialised = false; if(!initialised) { std::cout << "initialising physfs to " << TEST_EXECUTION_PATH << "\n"; static FileSystem fs( TEST_EXECUTION_PATH ); fs.setWriteDir("."); PHYSFS_addToSearchPath(".", 1); initialised = true; } } #define CHECK_EXCEPTION_SAFETY(expr, excp) try { \ BOOST_TEST_CHECKPOINT("trying " #expr); \ expr; \ BOOST_ERROR(#expr " does not cause " #excp " to be thrown");\ } \ catch(excp& e) {\ \ } catch (std::exception& exp) \ { \ BOOST_ERROR(std::string("unexpected exception ") + exp.what() + "instead of " #excp " caught from "#expr); \ }; // Tests of common FileSystem functions // test init BOOST_AUTO_TEST_SUITE( FileSystemTest ) BOOST_AUTO_TEST_CASE( default_constructor ) { /// \todo spec what happens here; currently asserts // FileSystem::getSingleton(); /// \todo how to make this a sensible path on all platforms? { FileSystem fs( TEST_EXECUTION_PATH ); BOOST_CHECK_EQUAL( &fs, &FileSystem::getSingleton()); /// \todo currently, an assertion fails here! // try to init again //FileSystem fs2("C:\\Dokumente und Einstellungen\\Erik\\Eigene Dateien\\Blobby Volley 2\\test\\bin\\debug\\"); } // here, fs is deleted so we can create a new file system // try to create it with spam path /// \todo spec, what error happens here FileSystem fs3("__SPAM__"); } // the functions deleteFile, exists, isDirectory, addToSearchPath, removeFromSearchPath, setWriteDir and getUserDir // currently just wrap PHYSFS functions, so they actually don't do anything. Thus, these functions are not // tested here. Once we have a defined error reporting policy etc, tests will be added. /// \todo test EnumerateFiles BOOST_AUTO_TEST_CASE( enumerate_files ) { /// \todo spec what happens here; currently asserts // FileSystem::getSingleton(); /// \todo how to make this a sensible path on all platforms? { FileSystem fs( TEST_EXECUTION_PATH ); BOOST_CHECK_EQUAL( &fs, &FileSystem::getSingleton()); /// \todo currently, an assertion fails here! // try to init again //FileSystem fs2("C:\\Dokumente und Einstellungen\\Erik\\Eigene Dateien\\Blobby Volley 2\\test\\bin\\debug\\"); } // here, fs is deleted so we can create a new file system // try to create it with spam path /// \todo spec, what error happens here FileSystem fs3("__SPAM__"); } /// \todo test probeDir BOOST_AUTO_TEST_SUITE_END() // most of the following functions just wrap to PHYSFS calls. /// \todo how to test these? // test enumerate files // test deleteFile // test exists // test isDirectory // test mkdir // ... /// \todo check all FileSystem methods are covered in tests /// \todo check all FileRead/FileWrite methods are covered in tests BOOST_AUTO_TEST_SUITE( ReadFileTest ) BOOST_AUTO_TEST_CASE( default_constructor ) { FileRead default_constructed; // no file is opened after default construction BOOST_CHECK( default_constructed.is_open() == false ); BOOST_CHECK( default_constructed.getPHYSFS_file() == 0 ); BOOST_CHECK( default_constructed.getFileName() == "" ); // all other operations should raise an assertion! CHECK_EXCEPTION_SAFETY (default_constructed.length(), NoFileOpenedException); CHECK_EXCEPTION_SAFETY (default_constructed.tell(), NoFileOpenedException); char target; CHECK_EXCEPTION_SAFETY (default_constructed.readRawBytes(&target, 1), NoFileOpenedException); CHECK_EXCEPTION_SAFETY (default_constructed.readRawBytes(1), NoFileOpenedException); CHECK_EXCEPTION_SAFETY (default_constructed.readUInt32(), NoFileOpenedException); CHECK_EXCEPTION_SAFETY (default_constructed.readString(), NoFileOpenedException); } BOOST_AUTO_TEST_CASE( open_read_constructor ) { init_Physfs(); // create a temp file for the next check try { FileWrite write_file("test_open_read_constructor.tmp"); write_file.write("test"); write_file.close(); } catch (std::exception& s) { std::cout << "Error: " << s.what() << "\n"; BOOST_ERROR("this should never happen!"); } // now this file exists try{ FileRead read_file("test_open_read_constructor.tmp"); // now, a file is opened! BOOST_REQUIRE( read_file.is_open() == true ); BOOST_CHECK( read_file.getPHYSFS_file() != 0 ); BOOST_CHECK( read_file.getFileName() == "test_open_read_constructor.tmp" ); BOOST_CHECK( read_file.length() == 4); read_file.close(); BOOST_CHECK( read_file.is_open() == false ); BOOST_CHECK( read_file.getPHYSFS_file() == 0 ); BOOST_CHECK( read_file.getFileName() == "" ); } catch (std::exception& e) { BOOST_ERROR(e.what()); } CHECK_EXCEPTION_SAFETY(FileRead read_file("this_file_surely_does_not_exists?!@<|.tmp"), FileLoadException); PHYSFS_delete("test_open_read_constructor.tmp"); } // !!!!!!!!!!! // we don't have any tests for the functions close, getPHYSFS_file and is_open. // These are already tested together with the constructors (and other functions) // // wrongly closed file BOOST_AUTO_TEST_CASE( wrongly_closed_file_test ) { init_Physfs() ; FileWrite create_test_file("test_open_close.tmp"); create_test_file.writeByte(1); // close the file, loughing wickedly ;) // don't ever do that in non-test code! create_test_file.close(); FileRead test_file ("test_open_close.tmp"); test_file.close(); /// \todo this test can't work as we do it now because physfs just crashes when we /// do this. //PHYSFS_close( (PHYSFS_file*)test_file.getPHYSFS_file() ); // now, every action we try to perform on that file should yield an excpetion /// For now, these are all functions we have to test /// make sure to add new ones! CHECK_EXCEPTION_SAFETY(test_file.tell(), NoFileOpenedException); CHECK_EXCEPTION_SAFETY(test_file.seek(2), NoFileOpenedException); CHECK_EXCEPTION_SAFETY(test_file.length(), NoFileOpenedException); char buffer[3]; CHECK_EXCEPTION_SAFETY(test_file.readRawBytes(buffer, 3), NoFileOpenedException); CHECK_EXCEPTION_SAFETY(test_file.readRawBytes(1), NoFileOpenedException); CHECK_EXCEPTION_SAFETY(test_file.readUInt32(), NoFileOpenedException); CHECK_EXCEPTION_SAFETY(test_file.readString(), NoFileOpenedException); CHECK_EXCEPTION_SAFETY(create_test_file.writeByte(5), NoFileOpenedException); CHECK_EXCEPTION_SAFETY(create_test_file.writeUInt32(5), NoFileOpenedException); CHECK_EXCEPTION_SAFETY(create_test_file.write( std::string("bye bye world;)") ), NoFileOpenedException); CHECK_EXCEPTION_SAFETY(create_test_file.writeNullTerminated( std::string("bye bye world;)") ), NoFileOpenedException); CHECK_EXCEPTION_SAFETY(create_test_file.write( "bye bye world;)", 8 ), NoFileOpenedException); } BOOST_AUTO_TEST_CASE( exception_test ) { init_Physfs() ; // create a temp helper file { FileWrite helper("read.tmp"); helper.writeByte(5); } FileRead test_file("read.tmp"); BOOST_REQUIRE( test_file.is_open() == true ); // move reader in front of file beginning CHECK_EXCEPTION_SAFETY(test_file.seek(-1), PhysfsException); // move reader after file ending CHECK_EXCEPTION_SAFETY(test_file.seek(100), PhysfsException); char buffer[3]; // read negative amounts of bytes CHECK_EXCEPTION_SAFETY(test_file.readRawBytes(buffer, -5), PhysfsException); CHECK_EXCEPTION_SAFETY(test_file.readRawBytes(-5), std::bad_alloc); test_file.seek(0); // read more than there is CHECK_EXCEPTION_SAFETY(test_file.readRawBytes(buffer, 3), EOFException); CHECK_EXCEPTION_SAFETY(test_file.readUInt32(), EOFException); CHECK_EXCEPTION_SAFETY(test_file.readRawBytes(5), EOFException); CHECK_EXCEPTION_SAFETY(test_file.readString(), EOFException); } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE( WriteFileTest ) BOOST_AUTO_TEST_CASE( default_constructor ) { FileWrite default_constructed; // no file is opened after default construction BOOST_CHECK( default_constructed.is_open() == false ); BOOST_CHECK( default_constructed.getPHYSFS_file() == 0 ); BOOST_CHECK( default_constructed.getFileName() == "" ); // all other operations should raise an assertion! CHECK_EXCEPTION_SAFETY (default_constructed.length(), NoFileOpenedException); CHECK_EXCEPTION_SAFETY (default_constructed.tell(), NoFileOpenedException); char target; CHECK_EXCEPTION_SAFETY (default_constructed.writeByte('c'), NoFileOpenedException); CHECK_EXCEPTION_SAFETY (default_constructed.write(std::string("c")), NoFileOpenedException); CHECK_EXCEPTION_SAFETY (default_constructed.writeUInt32(5), NoFileOpenedException); CHECK_EXCEPTION_SAFETY (default_constructed.writeNullTerminated(std::string("c")), NoFileOpenedException); CHECK_EXCEPTION_SAFETY (default_constructed.write(&target, 1), NoFileOpenedException); } BOOST_AUTO_TEST_CASE( open_write_constructor ) { init_Physfs() ; FileWrite write_file("test_open_write_constructor.tmp"); // now, a file is opened! BOOST_REQUIRE( write_file.is_open() == true ); BOOST_CHECK( write_file.getPHYSFS_file() != 0 ); BOOST_CHECK( write_file.getFileName() == "test_open_write_constructor.tmp" ); // this file is new, so length should be 0 BOOST_CHECK( write_file.length() == 0 ); write_file.close(); BOOST_CHECK( write_file.is_open() == false ); // make sure we delete this file after the test, so we can run the test a second time // under same circumstances PHYSFS_delete("test_open_write_constructor.tmp"); try { FileWrite write_file2("this_file_surely_cannot_exists?!@<|.tmp"); BOOST_ERROR("opening fiels with invalid names should lead to an exception"); } catch (std::exception& s) { // fine } } BOOST_AUTO_TEST_CASE( open_close_test ) { init_Physfs(); FileWrite test_file("test_open_close.tmp"); BOOST_REQUIRE( test_file.is_open() == true ); test_file.close(); BOOST_REQUIRE( test_file.is_open() == false ); // now open another file test_file.open("test_open_close2.tmp"); BOOST_REQUIRE( test_file.is_open() == true ); test_file.close(); BOOST_REQUIRE( test_file.is_open() == false ); // and again the first file test_file.open("test_open_close.tmp"); BOOST_REQUIRE( test_file.is_open() == true ); test_file.close(); BOOST_REQUIRE( test_file.is_open() == false ); // cleanup PHYSFS_delete("test_open_close.tmp"); PHYSFS_delete("test_open_close2.tmp"); } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE( FileWriteReadCycle ) BOOST_AUTO_TEST_CASE( raw_data_test ) { init_Physfs(); char data[] = { 's', 'p', 'a', 'm', ' ', 't', 'e', 's', 't' }; FileWrite writer("cycle.tmp"); BOOST_REQUIRE( writer.is_open() == true ); //FileRead reader_e("cycle.tmp"); /// \todo we need to define what happens when we open a file for reading and writing simultaniuosly writer.write( data, sizeof(data) ); writer.close(); FileRead reader("cycle.tmp"); char data2[sizeof(data)]; reader.readRawBytes(data2, sizeof(data)); BOOST_CHECK( std::memcmp(data, data2, sizeof(data)) == 0 ); reader.seek(0); boost::shared_array data3 = reader.readRawBytes(sizeof(data)); BOOST_CHECK( std::memcmp(data, data3.get(), sizeof(data)) == 0 ); PHYSFS_delete("cycle.tmp"); } BOOST_AUTO_TEST_CASE( string_test ) { init_Physfs(); std::string teststr = "hello world!"; BOOST_CHECKPOINT( "string_test: writing test file" ); FileWrite writer("cycle.tmp"); BOOST_REQUIRE( writer.is_open() == true ); writer.write( teststr ); writer.writeNullTerminated( teststr ); writer.write( teststr ); writer.close(); BOOST_CHECKPOINT( "string_test: reading test file" ); FileRead reader("cycle.tmp"); boost::shared_array data = reader.readRawBytes(teststr.size()); BOOST_CHECK_EQUAL (reader.tell(), teststr.size() ); std::string str2 = reader.readString(); BOOST_CHECK_EQUAL (reader.tell(), 2 * teststr.size() + 1 ); BOOST_CHECK( std::memcmp(data.get(), teststr.data(), teststr.length()) == 0 ); BOOST_CHECK_EQUAL( teststr, str2 ); // now, try to read as null terminated when it isn't CHECK_EXCEPTION_SAFETY( reader.readString(), EOFException); PHYSFS_delete("cycle.tmp"); } BOOST_AUTO_TEST_CASE( int_test ) { init_Physfs(); BOOST_CHECKPOINT( "int_test: writing test file" ); FileWrite writer("cycle.tmp"); BOOST_REQUIRE( writer.is_open() == true ); const int TEST_INT_1 = 12; const int TEST_INT_2 = -8; const int TEST_INT_3 = 1275343; writer.writeUInt32( TEST_INT_1 ); writer.writeUInt32( TEST_INT_2 ); writer.writeUInt32( TEST_INT_3 ); writer.writeByte( 5 ); writer.close(); BOOST_CHECKPOINT( "int_test: reading test file" ); FileRead reader("cycle.tmp"); int res = reader.readUInt32( ); BOOST_CHECK_EQUAL (res, TEST_INT_1 ); res = reader.readUInt32( ); BOOST_CHECK_EQUAL (res, TEST_INT_2 ); res = reader.readUInt32( ); BOOST_CHECK_EQUAL (res, TEST_INT_3 ); // try to read more CHECK_EXCEPTION_SAFETY( reader.readUInt32(), EOFException); PHYSFS_delete("cycle.tmp"); } BOOST_AUTO_TEST_SUITE_END() blobby-1.0/data/gfx/000755 001750 001750 00000000000 12313310254 017102 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/blobnet/Logger.hpp000644 001750 001750 00000003625 12313310251 021554 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= blobNet Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* Includes */ /** * Macros for primitive plattform independend logging and debugging * * This header include the the logging macros for debugging. * You can log information by calling the LOG(class, message) macro. * There are the following log-modes available which you can set by changing the * definition of the LOGGER_MODE macro: */ #define LOGGER_OFF 0 // Debugging is off and all overhead is removed #define LOGGER_CONSOLE 1 // The debugging information is printed to the std::out /** * Set the mode here: */ #define LOGGER_MODE LOGGER_CONSOLE /* Implemenation */ #if LOGGER_MODE == LOGGER_OFF #define LOG(class, message) #endif #if LOGGER_MODE == LOGGER_CONSOLE #include #include #define LOG(class, message) \ { \ time_t timeRaw; \ struct tm * timeInfo; \ char* timeAsc; \ time(&timeRaw); \ timeInfo = localtime(&timeRaw); \ timeAsc = asctime(timeInfo); \ timeAsc[strlen(timeAsc)-1] = '\0'; \ std::cout << timeAsc << " " << class << ": " << message << std::endl; \ } #endif blobby-1.0/data/gfx/font16.bmp000644 001750 001750 00000003370 12313310254 020722 0ustar00danielknobedanielknobe000000 000000 BM6( * ^Nx"%|"&C08*6J  >E8Fe$0    L!%KVo.<1!&\''g''q*-<>NTtCHU^GRO,7 5EBKJ[\]`哙Ӊjwb?L# MLfdwwpq~XYghҫ踿ҟ]gH6= ׀~3,.ȰiUZ痢E00ƜA88᪩ݥ&c\S֭||@33ljU--#¥bPP,)%cy{YAH/ ޺& J<9D86@71?4-2+"oeIVTf6&.aWWУWEDR?<}vxkzǟvxat=Lp&& Ͱ񿾹W?<ÈȍСڵ׾Td'"F YNN堞gf#2&#G95ZLCqdX~lj^yE-Mpp]X    sjD=3((ΎzK?0#+{w{qE32X$  a]wcJC<n; E132&) E21i`~h~Uq1nvpL\T?9nQ?qL@cW%blobby-1.0/data/gfx/ball04.bmp000644 001750 001750 00000012066 12313310254 020665 0ustar00danielknobedanielknobe000000 000000 BM66(@@ dcfcbe [Z\tqt~a_agegpnomkl~zwx|xx\ZZljjgeeecbihghgeqpn ``]$$#uusggewwvlmj susoqojljegeghg eggsttoppcddqrsjklmnp^^avvxeeg~~hhiggh]]^}}}zzzxxxvvvsssqqqpppnnnmmmllliiihhhgggeeecccbbb```___\\\[[[YYYSSSCCC000  sꂄtt tS5RKn8@t9"W恁Ktt"DD"tDPntPd?n0pD707~d"##t~0cdDRncmicpc0rrQT&חd7ccd7#6hhoM0d 77pcD"0L//7dpciM7いQdmTӃ3a33c7DQ66/aaϖ0c&60?5t̃hh3_֗7Ԗ&&60taaM&ؗdD|b%ӗٗ&idDt|`/^`ؗ&dr5{`ؗ&&drnt]{{{ӗb&D?t%$JJ}|{{{bחD#t $$\({Ɋ^{{ϗc/ח0r{({{{{Ηcݗח0dQ5S|ÿ{{{{&ۗ՗0?Q#þ{\Ӗ&7rW^%\yyzy\{|&7脂f$]¾y\yyyy\|&&c7D1R(J¿\yy\{{{T07R@=!"$$\yyy|{{&&֗0P@"Vy\]¾y{{{\|ٗ&&~d=Ry\\yx\y{їo&6c7⁎1WQ.xxxxxyyy|ח&Ds9RRxwIwyyy\aaod DDPQrwxxIxxxxxa&0ddd?.x{`՗6iim0dpIIv-------vxxyy`hחcjw--wwvvv\{`//-,HH--vx.x%3}i CH--xxwwxyb^3&D++Uvv-vwwVbg_u+-+++v|_]{]b~,+[u+++[vv--vy{||]JJ++G+[-[[--vy{{\{o+[[[-wxxxV{{+*++++-vIxV\]g^))*+F++vIyg++XX)++u+[vvvvw_$X-vv---w'EE*+-v---vC|XEXEv-vqAXE+-Z-v'+[XXE'+[[-EEEE-,AXEB-EX)'Z[-+XX+XXXEEX)XZ-Yblobby-1.0/data/scripts/old/com_04c.lua000644 001750 001750 00000007664 12313310254 022527 0ustar00danielknobedanielknobe000000 000000 -- Flags und runners wait = 0 naechsterBallSchmettern = true -- evtl Variablennamen wechseln angriffsstaerke = 50 -- versetzung zum Ball je grsser desto tiefer fliegt der Service 0-64( 64 ist ca CONST_BALLRADIUS + CONST_BLOBBY_BAUCH_RADIUS) angriffsstaerkeNeuBerechnen =false -- neuberechnung von angriffsstaerke => Variable Angriffe -- Konstanten CONST_FELD_LAENGE = 800 CONST_BALL_RADIUS = 31.5 CONST_GROUND_PLANE = 100 CONST_MITTE = CONST_FELD_LAENGE/2 CONST_RECHTER_RAND = CONST_FELD_LAENGE - CONST_BALL_RADIUS CONST_BLOBBY_HOEHE = 89 CONST_BLOBBY_KOPF_RADIUS = 25 CONST_BLOBBY_BAUCH_RADIUS = 33 CONST_BLOBBY_KOPF_BERUEHRUNG = CONST_GROUND_PLANE + CONST_BLOBBY_HOEHE + CONST_BALL_RADIUS CONST_NETZ_RADIUS = 7 CONST_NETZ_HOEHE = 157 -- Linke Berhrungsebene des Balls falls er ans Netz kommt CONST_NETZ_LINKS = CONST_MITTE - CONST_NETZ_RADIUS - CONST_BALL_RADIUS function OnOpponentServe() moveto(120) generatenaechsterBallSchmettern() -- der gegner soll den smash ja nicht vorhersagen knnen end function OnServe(ballready) moveto(ballx()) wait = wait + 1 naechsterBallSchmettern = true if ballready then if wait > 90 then jump() wait = 0 end end end function OnGame() naechsterBallSchmetternFlagTesten() -- schaut ob der bot angreifen soll oder nicht target = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_KOPF_BERUEHRUNG) if naechsterBallSchmettern then sprungattacke(angriffsstaerke) return end -- nun kmmern wir uns um die Blle die ans netz prallen if ((target > CONST_NETZ_LINKS) and (ballx() < CONST_NETZ_LINKS)) then netzappraller(target) return end moveto(target) end function netzappraller(p_target) moveto(CONST_NETZ_LINKS - (p_target - CONST_NETZ_LINKS) + math.abs(bspeedx()*bspeedx()*1.4)) end function sprungattacke(p_angriffsstaerke) moveto(ballx()-p_angriffsstaerke) -- Bei der Sprungatacke wird die Strke des gewnschten schlages angegeben if bally() < 580 then jump() end end function naechsterBallSchmetternFlagTesten() if (touches() == 3) then -- falls der Bot einen Anschlag Findet der Direckt punktet so wird der Wer nicht neu berechnet da er dann nciht auf 3 Berhrungen kommt naechsterBallSchmettern = false angriffsstaerkeNeuBerechnen = true -- da wrde es sicher auch einen Inteligenteren Test geben. return end if (angriffsstaerkeNeuBerechnen == true) then generatenaechsterBallSchmettern() end if (ballx() > CONST_MITTE) then -- wenn der ball auf der Anderen Seite ist soll der bot nicht naechsterBallSchmettern sein naechsterBallSchmettern = false return end if (touches() == 2) then -- nach der 2. Berhrung angreifen if (bally() > 500) then -- erst wenn der Ball hoeher als 500 fliegt sonst gibt es keinen schnen Schmetterball. naechsterBallSchmettern = true end return end if ((ballx() < (400-CONST_BALL_RADIUS)) and (bally() < 200) and (math.abs(bspeedx()) < 40)) then -- der ball knnte noch drber fliegen ** noch optimieren naechsterBallSchmettern = true return end end function generatenaechsterBallSchmettern() angriffsstaerkeNeuBerechnen = false; angriffsstaerke = math.random(15,64) -- variiert mit der Angriffsstrke also auch mit den Anschlgen end function estimImpact(bx,by,vbx,vby,destY) -- erlaubt ein besseres Estimate mit ein paar umbeding ntigen Angaben bgrav = 0.28 time1 =(-vby-math.sqrt((vby^2)-(-2*bgrav*(by-destY))))/(-bgrav) resultX = (vbx * time1) + bx if(resultX < CONST_BALL_RADIUS) then -- korrigieren der Appraller an der Hinteren Ebene resultX = math.abs(CONST_BALL_RADIUS - resultX) + CONST_BALL_RADIUS end if(resultX > CONST_RECHTER_RAND) then -- Korrigieren der Appraller an der Rechten Ebene resultX = CONST_FELD_LAENGE - (resultX - CONST_FELD_LAENGE) end -- test -- if(resultX > CONST_MITTE - CONST_BALL_RADIUS)then -- resultX = -resultX -- end return resultX end function cleanMoveTo(position) -- eine nette Spielerei ;) if (posx() ~= position) then moveto(position) end end blobby-1.0/src/DuelMatch.h000644 001750 001750 00000010354 12313310253 020215 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include #include "GameLogic.h" #include "Vector.h" #include "PlayerInput.h" #include "PlayerIdentity.h" #include "BlobbyDebug.h" class InputSource; struct DuelMatchState; class PhysicWorld; /*! \class DuelMatch \brief class representing a blobby game. \details This class represents a single game between two players It applys the rules itself and provides an interface for querying different parameters. For this purpose it is designed as something similar to a singleton, but it can be instantiated multiple times on a server or be completely unavailable */ class DuelMatch : public ObjectCounter { public: // If remote is true, only physical responses will be calculated // but hit events and score events are received from network DuelMatch(bool remote, std::string rules); void setPlayers( PlayerIdentity lplayer, PlayerIdentity rplayer); void setInputSources(boost::shared_ptr linput, boost::shared_ptr rinput ); ~DuelMatch(); void setRules(std::string rulesFile); void reset(); // This steps through one frame void step(); // this methods allow external input // events triggered by the network void setScore(int left, int right); void resetBall(PlayerSide side); void trigger(int event); void resetTriggeredEvents(); // This reports the index of the winning player and -1 if the // game is still running PlayerSide winningPlayer() const; // This methods report the current game state and a useful for // the input manager, which needs information about the blob // positions and for lua export, which makes them accessable // for scripted input sources int getScore(PlayerSide player) const; int getScoreToWin() const; PlayerSide getServingPlayer() const; void setLastHitIntensity(float intensity); int getHitcount(PlayerSide player) const; Vector2 getBallPosition() const; Vector2 getBallVelocity() const; Vector2 getBlobPosition(PlayerSide player) const; Vector2 getBlobVelocity(PlayerSide player) const; const PhysicWorld& getWorld() const{ return *mPhysicWorld.get(); }; const Clock& getClock() const; Clock& getClock(); bool getBallDown() const; bool getBallActive() const; bool canStartRound(PlayerSide servingPlayer) const; void pause(); void unpause(); bool isPaused() const{ return mPaused; } // This functions returns true if the player launched // and is jumping at the moment bool getBlobJump(PlayerSide player) const; /// Set a new state using a saved DuelMatchState void setState(const DuelMatchState& state); /// gets the current state DuelMatchState getState() const; //Input stuff for recording and playing replays boost::shared_ptr getInputSource(PlayerSide player) const; PlayerIdentity getPlayer(PlayerSide player) const; PlayerIdentity& getPlayer(PlayerSide player); void setServingPlayer(PlayerSide side); int getEvents() const { return events; } private: boost::scoped_ptr mPhysicWorld; boost::shared_ptr mInputSources[MAX_PLAYERS]; PlayerInput mTransformedInput[MAX_PLAYERS]; PlayerIdentity mPlayers[MAX_PLAYERS]; GameLogic mLogic; bool mPaused; int events; int external_events; bool mRemote; }; blobby-1.0/src/InputSource.h000644 001750 001750 00000004622 12313310251 020626 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "PlayerInput.h" #include "BlobbyDebug.h" class DuelMatch; /*! \class InputSource \brief abstracts several possible input sources. \details This class abstracts several possible input sources, like local input from InputDevices, input from a scripted player or input over network which in turn can all be recorded by a recorder. The updateInput method has to be called (and is called) once per frame in DuelMatch in local mode, so input written with setInput will be overwritten in these cases.*/ class InputSource : public ObjectCounter { public: InputSource(); virtual ~InputSource(); /// forces a recalculation of the input PlayerInput updateInput(); /// gets the current input PlayerInput getInput() const; /// get original input data PlayerInputAbs getRealInput() const; /// set input which is returned on next call /// of getInput void setInput(PlayerInput ip); /// set input which is returned on next call /// of getInput void setInput(PlayerInputAbs ip); /// gets match associated with this InputSource const DuelMatch* getMatch() const; /// sets match associated with this InputSource /// should only be called once! void setMatch(const DuelMatch* match); private: /// method that actually calculates the new input virtual PlayerInputAbs getNextInput(); /// cached input PlayerInputAbs mInput; /// match connected with this source const DuelMatch* mMatch; }; blobby-1.0/data/gfx/font08.bmp000644 001750 001750 00000003370 12313310254 020723 0ustar00danielknobedanielknobe000000 000000 BM6(   ",)$3-$4<.D=,DA/G=,C4&6-#/  '&::6RI;_\BstNVekjgbZvJ{Q3T8$8 5/VMDȝIհQރF").'/P@RnoFqA1D DΟFݯ@1 B5CըޘhzN|C1DFۯ@.JbŽt~V~  O=!8K:*;؉z` [D\m  xa֛S ]^ 29RXӢQ 5%BzZ~5:BD9OϦH|T^QV-0  GJ#3EؽT hiptDH=?/ 246`a$1GD^Ddvu2ؙ|x}|   7ߪ<)* ^;dU1   '\ ]  TG&,Sjv|oU.#SU ]C&#NQ//+,9#;Y;Ze݋V?@_Cbn$gj`\* _ c  q4s*{ "c=g]NR22ؚ+-ebnqDF*++,km 57 iy? Ȧ *#%,,D0En{V:07FUVHk&n1$0sOt̊~O.-blobby-1.0/data/backgrounds/strand2.bmp000644 001750 001750 00001653466 12313310255 022723 0ustar00danielknobedanielknobe000000 000000 BM6W6( X   /SFQPF 6X˄KQLnn&L*Q\Ph%*mOh(TQԋpF+),S&KN<nb<@pgLP#</F Ģ,;DmV,bco/PxQUQKIRpSCao`0g +*7K)5gc^a<|,0 a6RisFCPe\;D0W nKФmAPX;B{`SDԗs]W1n'48A-9lc;(F@I;KqLx,XZZFFOH4Ǧ裕{D+%n6neU]#yH" wNhɴgzgpDfYw.<nĻxx~l20I.7SUW78ux@tZH LGKbedDJ,Mw\.霎l:X[no<0-yFl6hnx{d0gP4-g:R{S09ϝ/;ΐQwSc8͸p 0C?x0V9Z:ebaFEEE(!FBEF|z{h9GXTz)yzzDEFzN|14nZZkF]]0pp%pp%$S]ppp-,:kpp%00p]]]5]5F5FF+F+++++++F5]p]]]]]]]]5]5]5]]55]]]]5]]+5+]55Fpp0p]]p00p]00p00000p00]]]]0]]]]]5]]]:5]]]5]]]]]]]]]]]]]]]|FjSFF]]]]p]]pp0]]55]+FFFFF]]pp]]]ppSpppp]ZZZjjDDDDDDDD0]]]00KZ:DDDDODO0]]00]5S5+5Sjjpj0DDDDDD]]S0]0p5]00$gDD000000pSjj3j5XX]0]]5]00j000000000]0]X++++F]]ppD$00+v+XNv+]]00]]]]]pp]55]]]5]]]+5]]00]0%]p]Xvv55]p0%]F]FFF]]+++++++N+++5]5+vv+5]p]5555+5]p]]lX55]]]Fl5555]]555]]5l5+X+X+X5]]]]]]]]5]5]05X++5+5F5X+FF5F]]FF+FF++]]]p]]F+5+55]vN555l5+55X5+5Xl5l55+l++5Gxx\;~555XNS5555X5+vv+v+X+Xvv+55X5l5]Fp]5pp0]l+X+X555X+v+X5++]555+55]+555]pp]0p]5FFFF]p]p]]]]]p]]]]]]5]]FF+5S]]55l]p0]%%ppp]]F]+++5NNN++5SSFFF+]]]]FS]F]pp%ppppppppp0%p0pp]S]]]p]Zp%p%ppp0pp$lS]5JZZ+F]]pppp0pppppp]]]]]p]55Nv+NFF]pp5]]5p]+FFFF]F]]]]]]]p]]]]]p]]]F]F]]]]]]p]]5]]]]]pp0p]]]0]]pp]5]B8Z]]]]]]]]]p]5+++]p]5F55]]]]p5]55]]5FF55555]]p]pppp]]]]]p]p]5]]]]p0rZZ:k000OOKKOODD0]005+5vNuu++ZZZ88DD00p00ODDDD0]0p0]]0p50]]5]0]50]55]0]5+]]]p0]00]0055]]00jjj55XX]]05DD00p+5]55F55+N++]0DD0DD]p0p]]]]]p]p]p]]]p]]p]+5FNN++5++555FF+++N+5]SSFj]0]5]]5]]]0p]]]0]]]]]]]]]5555555555+l5l]5]]]]]]]55F+N5F+Xl+l555+5+++++v+l+F5555+ll+55l55]%pp+5++++++5]p555ul++5l55l5Xl55555]X5+5]]]550]]]؅{{x;1j]]]]]]]]5+5+++55ll55F555+55F5+5]]5]5+5]]55Xv+X5v]+X5+55lXvl555X55]]Fp]]]55+++5+NN5]]p]]p]pp]]SS5]+N+FF+5F]55]]]]]5+555]]p]p]p]]]]]]5]+]FFF]SFpp]pppp]Sppppppppppp%pp]]]]]F+]:]ppp0pp0]]ppppZ:8]]]]]00]]]55]]]]pp]pp]p]]]0]]p]55]]5]]]]]]]5F]SpSjSS]p]]5]]pp]]]]]]F+]]]]]]]]]]]]]]]]p]]p]]pp]]p]]5F:5]S]]55]]]]]]]]]FSjS]]]]5]]]5]]]]]]S]F]]]p]]p0pp]5]]p0]p]]pp0pp]͓AZZr000쀀0000033@ODDD00zZZZ:3+v5DDD000000000DDDDDDD000]]55]50000DOOOK0pSj@jSj3jwjg000vvvXXXXX]j00]000000000p000]]l5]]0OOO0OKOOOD0pppp]pp]0p0ppppppp0pppp]5F55+]0]]SF5j5j5j\g]pF]+5+NFp0]]]]]]]]5]p]]F5+++]FX+55]555]5555l5+5+55S5]05555555+vNXX+lXlul+l+5555]5]]]55p]55+5]]]5]+5+5+5|__uu+ll5]5llXl+X+++5]55FFFF]]5؅{{x\;1|]]Fll_u_uXvvvvX+XXl55+55]F]F5v+NvN+]55vv++XlXll5X+55]555+N5S]]p55]p]p]p]]0]]p]]00ppp0ppppp0p]p0]%ppp]SF++F]pppp]pF5]5+]]pp]]p]]55p]5p]S]F]F+F5+p0ppppp$p$g$$p$ppp]]]55F]F]+pFSFmZ:Zp]00ppp0ppppppp]]]ZZ8Z]p]pp]]]]5++FF5]]]]0]5]]5]]]]]]]]5+]]]]]]5S|]FjS]]]0]]pp5++]5F]FF]5]p]p]]pp]0p]0p]]]]]]]]]]]]0ppp]]p]5BZ:-+FF55++]]pp]p5ll5l+5+5]FF5++SF+F]]]]]p]p]]]]]]5F55]]5]]550ppp]A:ZZ:ZZ]]550OODDDDD000jD]550ODD8ZZZZZ0]0]OKKKKKOO00DDDDD]5X+5lj30j]+5]]]0]0]0005]00]]55]00]vXvvvX]5j]j卍p000]]ll5gjwjgO$00p00]0O]0]55]]]p]]]]55+55X]]5]]]]p0]pp5XX55XX5XX]]]]]]]5]5]]500p]F]]5]]]p0]]p00p]+p]]5]5]]5]]]+5]]]l+55F5555l5X555X]]FF++5+555555555+l]5l++X5+v55++]++l]55]5555+555]5X555v+55+5]5+5++5+5+lF++5555+55؅{{x;l55X5X]Fllll+vv+Xl5]5+]+++l+5_lll+vl55v55]55]5XluNF]FFSp$SF5u5]]]]]]]]]p0p0]]]]]]]]]]5F]]]+l5F+]]]]pppppp%pp$p]p%p]p%ppppp0pppppp%pp]pp]]p]pppp00p0p0]Sp]%]]pppp%]]]]p]5]]]0pp0p0]5]]5p]]~rZ]pp0]p]F]]]p0]]]p]]]]]]]]pp]]5+Xl55]5]]]05]055]]]]]]]]p0p]]]]]]FF55]]5555FFFFFF5p]5]]5]]]5p]]]]]]5+J:Z:5]]F|FS]]]55]]pp]555FFFFFS]]5]]p]]FjSjSF]]]55+5F]]F5]]]]]]5555FF]\8ZZZ+]pOOO0]]]]SDDDOg:ZZ3+0500D00gKK0]]]ODDD]]]]5++55FmKKOOD0DDguF]55]]0000]]]5505XXXXX5vvX5S0pgppS+++5+500]JJJJJKp0]0O0p5++Nv+]]]]p]0]0]]]]]p]]]0%]]X+pp0]]XX0X0X55X50X5]0]p]+5F++5+555+5500]5]55555555]0]5]]]]55]5]555]]]]5+5+l+5lX+ll+X++5+55555+55X55555555+55+555555+55Xlll5X++5lX+X+X+X+Xll+l55ll]555+555]؅{{x\;1X+X+v+lXv+5]]5Xl++5X+5+5X50]]500]5XXXl]5+5+X+ll5+55X5F555]5F]F5l+5]]++]+5pp]0]p]pppp]p]]]pSp]Spp]]+]]]ppp]p]ppppp]]SF+F]5]]]ppppppp00p]p]]S5]]F]]]]]pppp]]FF]5FF5]p]N+++F]JZ-S]pppp]p]50ppp]p]0::]+]]pF]]]5F5]p]ppppppp]]]]FSF5+5+5+]5l5]5]5]F5F]S|F5]555p]]pp]5FFF]]F]]F]FF]5F5]]]]55]55]]5555]]0]:ZZZJ++FF]555]]55555p55+55]p]]0pppFF55]p0FF]]0]p]]]p55]]SSppSS]Spp]pp5D4ZZ0D0OOK00OOODD0]555ZZZZZkODDDDDDDDDO0DOOOg]]55005DOO0DD쀀]]]5++++5X50X5X555X555555X5]+XF]5]ppp]F+++5Nv555DDDOKJmmO0000]55]005++ÈvS5]]pS$S]ppS]ppp]]p0p]+Xv5]]]X55X+]5550]55X]500%pp]]S]]]]]5p]+]+++5pppp]]]pp]5555]]F+]++N+5+l5]]]0]]5+5]05+Xv55l+X+XX+X55555]55X5+l5++l5+55ll5l5X+5555lXl+X+X+5+X555555Xll5F]55l55؅{xx;X+X55X55+5F5]F55lX+vX+Xl++X+llll+X5+5555X+X+55X+5]5555]5]]0]55]]]]]]]]]]p0p]p]p0]0p]p]]S]F]ppg0%055]]p]++5+]++]]ppppp]]0S]SSSS]]5]]]]]p]ppp]]ppp]ppppp]SSSS55]pp]]]F]]++F]555SppppZF]p%0pppp0]]]p]p]]::Zj55]S]]]pp]]F]]]55]55]]]]]5]555555+]p]]]]]55]5]5]]]0]]]5]]5]]p]]pFFFF]F|@jwjjjS]]]]]p++5+5]5]]F]F]]FFgZ555]]55555]]]FS]]]pppp]]S]]]55FF+5+5]55]]]5]pp]]]]S0SgggpS]]pp0pDbeZZZZDDDDDDDDDD0F5555X]0D:8:ZZZZOOOOODD05]]0]]]]0]]]00OOOODDOD0ppp0DD000]]5]+FjSS000000]p0555X5X5555]]+55]+l+]55v055++l]KK000jj3D]0OO333300]p]]pF]]]]]0p0pp0]Sp0p0pp]]XX5XXX5]55]0XX5555]550]j555pS0]]p0ppp]pp]]]]]]]]]5555555555]+5+FF]F]55X+5555+555]5555]]]+v5+555XX+X+X+X+l+X+l+X+XlX5]55]l5l5+l]]]]55l5555]+]]5vl5]5555+X+5++5+5+]5؅{{x\;1иN+]]l5+X+X+l5555X+X+X55555]X55+X+l+ll55+lF55p]5+5+5F5l+5]]]p]]5]]ppp%p0p]]5p]F]]p]]00ppppp]5]]5+F]S55FX+F]pp]pppp]p]p+++]Sp%%%pppp]]]pp0pp0p5]ppp]$gpp$pppp]]]pppp]S]]p%p%0pZ:Zpp0]ppppp]S]0p0pFz:ZZS]5F]FF+F+N+]55]5]555555]FSF+++l++5+]5]]55]p]]]]]ppp]]]]]p]]]]p]]]5]]p0]]]55]p]5FF+]+++55lN5g@FFF]]Z]]5]]S]5]]]p]]0pp0p00]]]S|]S55]]+X5]p]]5]55+5F]p]]]]]0]0]Sgpgp]DDO48:88:Zv0ODDDDOKKKKK3gOOKrZZ:8:ZJKmw3F]0p]0]00]00]]]000p5F]S]0]]5]+jKJJJJJOO0]0]055]0]55Fluu5+5]j0j]0]Sjjjjl]0]0000]0]00D05]]00OgF+5]]]ppppp]p00]F5F]S]0]Spp]5XX5XvvvXXXX]5]]]]5X550]5]0]555+]+]0]5F++]]]]]]]]5]]5+5++5]5]555]p]F]5+05555++++++++5F5FF+5++v+l+555]p]0]5+55]55l5555555555]5+++5l5vl+]55+55]5ll5luuX+XlX5+55+X+G{{xƲ5l55555X+X+X+5+X5l55F05lX+X+5lvN+v+X+]l5]]]5l+555+55]5]]]5S]Fp]]S]]+5]p]p0p]]]]]5+55]p0p0ppp]]]]]]pppp]]p]p]pp]0pp]p+0p]S]]S]]pppp0pppp]ppppp5]]]]]5+5+]pppppp%0p]]5]]]55]::3p]++]0pp]pppp]]p]+B:Z]]]]]]]]p0]]]+5+5+++F+++++FF]55]5555+lFF55]55]5]]]5FFF0]F]5]]p5+55F5++N+l++F5]]5555]]]0]5]FS:Z:+5]pp]]]]]]]]]]]]5]5+]]50]55555555]F555555+]5555]]5]]55]]5]pS]00pp00:8:::ZZKD0O0000]NvN5]]55]l+++]F5K:8:8Z-0OO$000]00O0jS0S0KKKO0jF000DDDDOKKKOKOD0]0]]XX5+5]]]F+X+vvlF000O000+N+]5++NlNv5v5]]]0D]00000ODDD]5]F]+F5]]]0pppp]50pp]]]]]Xl5p]N+N++++]]00X]Xl5l500p5]p]5]]]]]+5F]]]]]]55]]55]]5l5555]p5+++]+5lll55l555555+5X+5+l+5+5+5+X+l+5p]5+5+5]]5555+l+5]++]5]55+Xv+55]55+++5555555]55X5]+55555X5+X]0؅{{x\;|vv+v++5]]]5Xvvv+X+lX+lX++X+55+5]555]%0555+5]lN+55+5+]]]]p]55]pp5]]]]0p]50ppp]pSSF]S]ppp]p]0pp%%pppp0ppp]p]pppppp]p0vN+++++++]]%0ppF]SF]]]]p0pp]p]pp5+55]]]pppppppp]]+FF+Spppppp]p]p0pp0ppj::(F]p]]]]]FFF]555]]]]p0]55]p]]50]]]]]p]]5l5FF]FF5555555]55]]FFF5F55555]55+5]]5]5]0]]5F55]p]5]]]p]]p5]:5+]]]pSF+F5p]]]]]]]5]]]]]]0]+5++F+5+55555]]]5p]5555]]]]]]]X+5]5g3eA:8:0DDOOOODDD50p]0DDDD0pO:8:ـDD000DD0]5l5++++X5+]0F0ODDDOOOKOOOjgOKOOOp0p0D050j5X55555XXX5jj000005]]]0p000]D0XS]X]0]]50DDOO0$0g]]]]0gOppppp0]p]]]]p]]0p]p]p0]Sp5vXX5Xv555555555]5]55]jj]]5]55]]]]]]]]+555]]p5]FSF5555]FFFF]+]5]5]5FF]555]55555555]v++vNv5]55]+X+++5+++X+55+++]]5XllX]5]055lXlXl555l+5+l5+5+5p5FF5+l]5X5+X+X+Xl5]G{{x;+55]]5l]555++5555v+55555++X55+5555Sp]F5]]5]]F]p]5pp]]]]]]]]]pp]55F+]]F5]5]p]]SpSS]]]]]0]++FFF++]++]F]p%0pppp]pp]0pppp]ppSSpSpp0ppp]ppp0pppppppppp]p]5S]Spp0pp0pp]pp]pppp%pZ:]pppppppp]]]+5++vFg::5p]]]]]p]]]+5+5+F]5]5]55]]]]5]555555555]5555555555]5555555F5F5555+5]5+5]]5]]5]]5pp++5]FF++]F5p]]]5p::]FF5]]p]p]pp55]]]]Fjj]]]S]+]]]F]55]5]5+lll5FF555]5+p55ppppppD0SƕrZ:0000DOODD0D05]DDz::8:8:0000DDD0000D00]55]]0OOO000S]5F]]000DDODODKKKKKO305]0]05]XXXX5X50X5]j]0000D00D0D]000N+p]]5]0]000]]5j0pDDDDp]p]]]0p]+NF]]pp0p]p]p]]]]]F]5555Xj]X]555X5X00000j@SS]]5F]]]]00pp5]55+5]5]]55]5555555]]]]]555ll55+5+X+X+5]55l+55+X+55]FF5+]]]55]]]5X+++]F]]55l]+]5+Xl555++]5]5F]]5X+Xlll++l55FX+lX5+5XllF|G{{x\;v+X+X+v+]]5]555v+55l55++X55X+5]p5+55l5+555555]]]55]+5]]N5]pp]]0pppp]pppppp0pppp0pppppppp%p]pp]]F]]]]]p0pp0p55ppg$ppp]]SF]]p]pp55pp]]]ppp0p0$p]]]0p]p]pp%p%$p$p]]]]]]]]]F]F++:ZU]]p]]]F]5p0pp0ppp]]]3Z:Z]p]]]0p]]]]]5555++5+++]+FF]]p]p0]F55F5]]555]]55555]]pp5]XNl5FFF5]55]]5F5+5+55]555]]]pS55++F5pp]]]5S::Z]]]]]]]]]]p]]+]p]]]]p]5+++]]]]]]5]]5]]5l555FFF]]]]55FFF++]]]]DDDDD:Z00p0]+55]p00S5]500jK8ZZ50OOKg]F]F0OOKOO0pgj0DDOKOOODDD$D0]555]]5v+55000]55]0j0]XXXXv5X0]00]5]]]0j3]X05]]555F5FFFSS00j000]jl5S5Sp0]]p0FSp]]F5F+5]5p]p0]]]5]5j55]55+X055]5]5+F]]ljX0]5]5]]F5]++5FF+++F]5]]555F5F5l55+5+5l]lXlll55555]F+++55X+5X+X+v5l+5+X5]]5]ppp]]5pp]5]F5+NÈv+55555+]5]5555]5]]5]5v+X+l5555X]+5X+]0]]؅{xxƲ|+XX+Xvl]]]+++5+l+X+X5+X+55FF+555+X5l5555+5]]]p]]5]]]]]F]F]5]]5]p]]pp0]p]0p0]]5]]]F]pp$0p]5]]]]F]]p]]S]]p]p]]p]p000p]pp%pp]]5Fpp0]5pppp]p]]]p0p0]]p]55]FFp]]ppppppppppS]pp%p5:ZZkpp%p$pppppp0p0ppp$Z5]ppS]]55Fp]]]]]5]]5555+5]]+]]]l5+l555+5l+5]]55F]555]++]++X55]]55]]]55]F+55555]]]5555]55]]p]555]]]F5ZZ+555555]55]55]]S]]]]p]]]]]]]]55++NN55]]+]]v+X+50]55]5SF5]5++FSpp0DD8Z8DOO0000]50]50D8:8:ZDDDOKOOKOOOO0]]S00OOOKOOOOKODD쀀0gp00]0DKK5X]XX]XvvvXXXj]0]55XX5X+X+55]050]]5+]]5l]S]S0j0jj]]0]00]5+l+5]FF]]0p0p]pp]p]]]FS]X5XXl55]5]55]5]]]5]XlXF5]05]p5]5]]]]]pp55+F]]]55555]]55F]]]555555]55F5++5F555X5Xll]]]]]5555]X+X++++5l5vN+Fpp]]5]55X5555+l5]]]]]]SF]5X+55555++v+]5l5505N5+5]5+55]؅{{x;]]555+Xlu+5F+X+l5++5+l55]p]55]555+55]]+5p]S]p]FFFF]]pp]]pppp0pgp0p]0pp]FFFFFSppp]]]]5+F+FSSp]ppS]]p]ppS]SSp]F]+5F]ppp]]S55+F]ppp5+5p0]S]]]SS]]p]]]pSp]]pppppp]pp]%ppp%pppFF]8:Z]p]]ppppppp0pp0]]8]p]]5+5++]++]]p]]]]+]5555]]5]l5555]5F]]]]F]55l555555]p005]]555]l]]555]p]5+5FF555]]]55pp]555F]+]]]55lZ:55F5+]5]55F55F55]]]]]]]]]]]S@j5]]555]]]55l55]]]]5F]]555]+5]p]]]kJkJ Z:8::8KKKOODO쀀DODOODDDDDDDDJ:8:ZOO0]00ODODDDDD]5DDDKg0j000D0DDOK05FS000pODDDD000]0]X55XX5j]5]]]]5X0]05]]00DD0]500j]jSj]j00050000]]]0]0D00p]]]0F]]p]p]p]]5+]p]]]]]5]pp]SF55XXvXX5j5j]X]X]]]]j]]S]]pp]55F]55]p]FFF5]55]p++F+5]]F555]55++555]5++++]5l+5X5555+l+l+l+v555+]55++555l5]+5]55+XXlX55lv+5]5lX+l5+5X5+55]5555X5555F55]]]+v5]G{{x\;55+5l55lul5++5+l5+XX+5+l]5+]5+]]555555++]]5]F]]]p]pp]pp]+]5]pp0]]]pp]p]]ppp]p]]pp$0ppp0Sp5]pp$pp$555Fpp0pppppppp]5pS5]pp]ppppp$$0]p]p]pp0Fppppppppp%pppp$$$ppppp]p5F]]55]]]]@:Z:ZS]]]F]]pp0]ppp0$pp0p]Zj5]]F+]]]]]FF5]p]]]5]555]555+]F5]5]FF]55p555++l]]55]]]+5+]S55F]55+l]5]]S5+]5F]]5]]F5F]]555555]555555ZZ5]5]5]]]]]]]]]SFF]pppppp]]5]5]]]]5]5]]]]]+5]]]]p]]+l55F]F]p]]]]ppzZ:8::zBUz3pj0DDOOD]B8:::::8DDDDD0쀀DDDO0O$DDDDD0]]0pD0]DDODOOD0DDKOK00000]0]0XXX50]055]0]50X]]5]jjOj0]0j5500F0]]]]3KODDD]]F+]p]]0pp]00p]p]0p]]0pp]5XXXXX550]0]]X]XXXj0j]005]]F5]F5555]]5]5F5+55FF]]5+555555l5+555+55l5+55+5555X+5lX+X++55+++5+55++X5+5+5555+Xl55+555+++5+555lXl55+5]]555X+5l5lll5X55+55++]]p0]F5]G{{x;1+5l5v+X+v5555]F55]]5]]+]5F]]]]ll++5++55]]]]]]]]]5pp]]F]]0ppp]]F]F]]]]p]]]]]]]p+50p]]p]pp]pp]]]]]0ppppp0pp$p]pp]]]pppp]]]]]p0]]]]]pp0p]]ppp]F5]p]0ppp$pp0pp%pp%p0ppp]]]p%p]5pZZppp]pp]p]]]]]]]0p]p]z:::gS]p]]555FXl]]]FF555F]]]]]p]]pp]+5+555]]555]5++F+]]]++5++FF]]5]555555]0]]5]]]+5]ll55]]5FFSFF]]55+r5+5]]]5]]F]5]]]]0p]0]]]p]]]]]5]]]]]F5]+55]]]+55F]5]]S]p0ppppp]8A:8::r1zrJJK0D쀀0Z:88Z0쀀DjKKOODDK0]OOD00]D00p0FF0]ppDDD0g]p00S]]]SSjjXXX5X5v5XXXXXXjj005]005DD0K0jjj]]0]]DS]pDpp]]]]]p0]p0pp0]FF]]]]]FXXX5X5]]lX5555j55X]5XXlj0S]]]55]55]SS]5+]]]]]55]55]55]p]]]5]55555]55l55]]5l+l555XllXX+5555X55+555]F55F5]5+v5+55++X+5Xll5X+Xlll555l55555+55+55555+5555+5+]]S]]]p5]G{{x;~+555+X+v]5]5++5++]]55+]5l+l]55555]|F]]]5]]]]FF+55]]5pppp]p0pgpp]pp]]F]]p]ppp]5+lp]]]F]p]]]5]]Spp0p0p0]]p]]555]pppp]F]p0pp$pp]]5Sp55]Fppppppp0]p$%ppp]p%0pp]p]]pp]]SFZZk]]]]]]]ppp]S]p]]]p]]]BZZ::g]]]p55]]5]]5555+5FFF]5]555]]55F]++FSF5]5555]]F5+55]pF]]]F5]Fp]+5]5]]]5]ppp]5||SS]]]]]]]p]]]]]0]5F5++:55]5]555+]5F]p]]]]pp]]p]]p]]SS]]]]5555555555]5F5]]+FF]]p]]p0p]:8r48Z:r88rz1JB:::Z:D000000]000쀀DDODDDSDD0OOOOOOB0]0F00000]]]]XvXX50]0]0]5]]]]5F]]Jg]00000X5DDO0]0]]0j]]0jD0]000]]F5]0p]5+]]p+5l5]XXXXXX05j]55]5]]0]00500S]]]5555p]]0]5]55]pp]F5+55pp]]5FF]+F+]+]]5555]5l5X5lX+5ll+55555555]5+55]+5+55vv++55X5++55+X5]5]]555ll5X+]5F55+5p]+5]5X5l55ll5]5+++5+]؅{{x\;jX555]555l+++55+5555lp]]55++55]0pp0]0]]55]]5F55]]]pppp]]0p]p0p]55]]]pSF5p]S]Fpp]%p]]55]]]]]pp]F]@p5++5FF]pS]]pp+5pp$gp]$0ppp0pgggppS]]ppppp]]]pppp]]F]F00]S]]pp0p]0%pp%ppppp0p]ppzZ:Z]pp%ppppppp]p0ppS50p]]gZZZ5F]]]SS5lp]55F5]]]]]55+5FF5FF5]]5+555555]]FS5+]]555555]55FF]FS]]]]]]]]]jS]]]]55+]555]55]F++ZZZ+F++FF55++5]5]p]]00p]]5F%p]]FF+5]55]5l5F]]]]]]]]0pp]]5]]p]]]p00Z888:Z:::::rr:8::888ZzkkJJKODD00DDDDDDO쀀00033000550OKKOODD]0000]00]505X50XXXvXvXXXXXX]X000]50000DSjg00KO]lF0jO0+5Sl]S]]0]p]0]]]p]pp]p]]5]55]]]]]]5X5]X555X]]XXXX5]Xv55]5]05]5]5]55]]5F]]p]]]p]+5F0pp]]]55]5555]]]]]++55p55]]5]]]l5XlX5555555555]]55]5l+5+55F++5ll+++5]5lX+X5lX55+]5+5l+55555l]]p]5+5]5+5Xl55+X55X+X+]؅{{x;j55+v55555555+lv+5]]l55llXX5+55]]]55++]FF]]]+5+]pp++5+55]p]]F5+5]SSF]p]+5pp5]]]]]]]]]]]p]]+]]]]p]p]p0pp]pppp]]]]]]]p0]p]0pp0p0p]]S5+]F+]5]ppp]pppFF+]]pSp]F]]]]pp]pp]]]]+]ppppZZ:5ppp]]]p0]pp0]]Spppppz5]p]]F]FS]]]p]0]5]555]]S]55+555]5]]55]5F]F5]5F]55]555555F5]FF5555]]5]]]p0]p]F]]]]55+55Nl555Sp]+55]]]5ZZ]]+]F+++5++5++]p]+5555FF5F5+]5]555]]]5SSF5]]]]5]]]]F+]]]S]p]pp:AZ8::8:Z:::::::Z:8::::88:JKOODDDDD0쀀OD0000S0]DD쀀DDDD0j0]0XXX]]0XX]]]]0]]X]]5]]0]j0]0m0]0]05005]50000jSp]]5pp]0]p]]p]]5]]+]pp]]]l5]]5XX5]]555X55]55jlj]5j]]jjjjp]]]]]]]]5]]]]]F]555]]555]5++FF+F5F5F555+55555+Xlll5555]]]]]5+X+5X+X+5]55ll55+555+5555X5lX+Xll++]+5+l55+555+5]55l5]55p]p]55XlX55]5]]555G{xx\;N55+v+X+X+555l5X+5lX+X+5]5lXF+555+]5]5]5]p0]]]]]]]]]]p]ppp]pppp]]pppppppp]pp]%p%pppp]ppppp0@pppFp]]]p0ppppppS]]FFFFpp0ppp]p]p5+]p]]]]]0p$p]+]5]%p0p]pppp]p0p]p]p]]]]]pp]]p5ZZZS]S]pppp]S]]ppp]pp0ZZ]]]]]]]p]5p]555]F5]p]]5]]]]0p]5]555550p5+55555555]5F5FF]]]]]5]]5l+5]]p]]p0p]]]55]]]]]5+F]F5FF]]]]]]+ZZZZ]]]+]]SpF+]]]]]++F5+5]5F555l555+]]]]FF550pp]]]]]pp]pp]]F]pS5F]]:::AZ8:8::8:Z8Z8:8::::::::::88kkkJJkKJKOK]0000DDj]055XXvXX]X5XXXXXX5X05XX5]X5]]5003S$00D00쀀00000]00]p]]]0]5]55]0]]]]]]p]l55v55X5]55X]j5XX5]]]0]505]50]]p5]]]]]5]]]5]F]]5]]]5FF+F55]5+FF+]]F]555555555l5X55555]]]]555]5+5X55]5]]555]55++X+llX5lXl555+5+5+]]X55X555]55555+5l55+55+5l5l5+5]]+5]؅{{x\;1j5l5]l5]]++F5+555l_X55555]+]55X555]]5]5F]]F]]]F]]]]]]S]]p0p]p]pp0ppp5ppp]pp]]]F]]ppp5]p%p]0p]@0p0ppppp]]gpppp]+]p0ppppp0p0pp]]p]pp]Sppp0pp]p]pp]+]p]]pp]]pp%]ppppppppp5Z:Zr5]ppppppp]ppp]F]Sp5]]]Z]ppp]5SF]]]]5S]]5]]5]5]]]]p]]]]5++++5p]5]5]]+++5]5]]]]]]p5]5]F55p]]]pF+5]]]]5]S]]5]]0]]]pp5]p]]]]]Z]5]5F]FF]]]]5FF]55]]]+55+0pp]]]]]]S]]5FF]]ppp]]]5]p0p]]p3pppp88y8rZZ8:8:::::8:Z:::8::8:::::::::::::8:8::rrkkJJJOOD0XvXvXXXXX5XpO00000Ojj]00D0500D0pp]]0+N+p$pS5]]p0+]5F5]]55XXX55F+5]5]555055500555]]]5F]FSp]]]]5+]5]]]5]F5F]p]5]]]]5]]]55F5]p]55+5555l5+5]55]]5]]+]p555+55]5F5X+l55+]]5]55X+X+55]555X5X5]F++FF55+55+0]+FX+5ll55F]555]F]5+5]؅{{xCXl]5]F5l+55l]]]]5Xl]+55555]555+F]]5ll]5]S]+pp]]]S]]5]5]]pppp0pp0p5F]]p]p]]ppppp]]]]]%]ppp5S`@p0p$p0pSS]5p]]pppp]pppp0pp5]p+F]F]+]]pppp]ppp]]pppppppp5]]p]]p]pp]p]pp]p]0::]S]ppppp]]F]0++F]]0ppp]kZ8ZZ]+]]5]FS]]F5]F]]]]55]]]]]FS]]]]F+]]]]]]]p]5]p]S]F]5]0]p]55]5]]]0ppp]]]5FFF]p]]]p]p]F]]]@F5]]]]5+]S]zZZ5]]FF]]]p]]]]p]555FF|55]]5]05]pp]]]p0pp]0p0p]0p]]]]p]p]pppp0]8:8r::Z8:8:88::88888:888:8888:::::::::::::::: \ϖϓ{xxx͕x\D00]000000D00050D0DDD000]]00]]]]]]]]]]]555XX55XX55XXXXX5]55]55j]0]]]]]5]]]5pp0p]]]]55]+F55]]550]]5]55]5F]5]5]5555]5]]5l5]5]F+5]+5+555]55555555]+55+555Xl5]]p0p5X5555+555l5F5F++F555]5555l5l5555l+555F5++XX5]{{x;~j55]55+5+5555+5]]]5555SS++l]5F5]5S]]F550p]]]]]5]]5]SSp]]F]F50]p]]]]F]F]F]p]5Fpp]]pppSp]]+pp05+]pg]p]]]SS]]S]ppp]]]p0pp0pppp0]$0ppp]++Fp]p0]5+]pppp]]pp%]+SpFFp]]5]p0]FF+]]pp5Z::Z]]pSpp]]]]]]]]pppp0p]]@l]]p]]p]p]FF]]S@j]55]]p]FF5+F]F]]]5]]5555FF]]F]5]]5FF]]55]5]55pp55SS]p]]F]Sp]p0]pppp]]]]5+5+]ppp](Z::ZFF]]]]]p]F]F+]F]]F555+5+]p]5]]]FF]0]p0]]p]FFp]pppp]p]p]pp]5+]F]8:::rAZZ:ZZ:::::8Zr8:::::::8:::8::8:::8::8::8\ A{{7{\\\\\\ƲR::88881 18׺KJDO$p0p$p]]]5]]5XvXXvvXvvvvvXvXXvvvXXX+XXXXXXXX5Xv5F]]p55]]]]+]]+]p5]+pF]55]]5]]555]p+]]5]+5]]5555]+555FX+]5555lX+5+5]55l5]5v++5+5+F++5+555F555l55+555l5555+F+55ll55+5+55]5++5055]FF5G{xx\;1+5555l50]5]5505+55F55++]]]55]5]55]F5]+5]pFF5]]]]]p]]00SS]p0p]0p]p]pppppppp]pSp]p0pp]pppFF+F]ppp0pw@pppp%pp]pp0pp]]ppp0p$]5]p]]pp0p0p]pp]p]]p]]p]]p]ppppp]5p]5FSp]0ppp]pppp+5pp]pp]]ppppp]]]]p]ppS]]]5B8Z3]p]p]]]]p]]]p]]]]]]5]]]]]]]]F5]]]]p]5+]]]]p]p55F55]55S5]]p]]]]]]]p]]]]FFF++5p]]]0pS]]]]p]]]5p]p]]3Z]]]pp]+5]p]p]]pp]F]]]55+l]5l555jS]5+F]]ppSp5]]]]pp]p]pp]pppF]:AZZ8ZZ88::888r:8Z::88:::8:::88r\Ʋ7xxxxx૕\\\\ 11:::::r1r:::r:Z~::::88:m3wwȓȓȖ7x7774xw0S]]5]]]]pS]5]5]p]]5]]F55]5+F]]55]]]5]p]55555]5]]]5+55X55]+]5+5]55ll+55]]]55]5l555+]555+5]5l55555]55l5555+555X5555]5F55]5555]+]G{{x;l++]5lF555F]5555]p]]5]5]5]]5]]]5]]]]5]]5]+Fp]5]pp5+]]]5]p]]]p]p]]S0]5]pp]]p]p0]pp0p0p0pp]]ppp]pw`]]pppFF]Sp]]]pppp0pp]]0pp0pp0p0p]$pp0p0pp]pppp0pp]]5pppFF]pppp0ppp$p0]pppppZgp]Sp]]F]5]Fpp]Sgp]]FF5]]gZ::Z35]55]]]]]pF50p]5pp]FFp]5]5]p]]]]]5]55F]F]]p]]5F5]]F]5]5]p]p]Sp]p]]]]]]]]]pp]+Fpp]p0]]]pp0]Spppp]+]3Z:F]]]FF]]]]]5]5]]F]p]]]]5X+50]]]]5p]]]F]ppp]F+]pppp]]]p]pppS]]p:8:8AZZ:888::::8:8::88:8::::::::::88:::8::::::8:8:\ƚ xx\ƚƲ1rz1r8RR1r r:888r1r8:::8j3z@5FF]Sp5x{xxͭ୭\\\\\ABp]]]]]]]]]]]]]5]55]5]]]F+]]S]]]]]]]5]555F]]]+F55]FF555555]55555555555]5F5++]]p]]555+555]p]55]F55]5l5]]55+5]]]]5l55]]55l+5FF5+]55555]؅{{x\;155555l]5+55555]p]55l+]]5555]]F]]]5F]+5F]S]5]+F]]]]+]]F]5]]]pp]0p]]]pppp0p]Fp]F]p]]p0p5Fpp]]]p0pST]p0ppF+]5ppp0p]]pS]p0gpp0pp0p]p+5p0p]pp]p]]pp0p]p]5pp]]p]Sp]]]0$S]0p]pp]50p]5ZpF]]]]pppF+]p]S]p]pp0pp]FrZ8::]p]5]p]F]]]p0SS]p]S]]p]]5pp]]]]5+]p]]55F]]]]]]]j|F]5Fj]p55]S]S]]]F]]]ppp]p0pp]ppp]pppp]p]]]p]pF]]Z:Zg5Fgppp]]pSS]]]]]]]5F]0]]]p]]]5]]gppp]]+5pp]pp]]5]pp]]]ppS]]S]:rZrZ8::r:8::88:88:8::8888:8r\;Ʋx\\\\ 1r 1:R8r1r88: r1 18:35F5zZ8S5l5F]5X+550]xxx\x\\\ 35]F]p]5]@SS]pp5F+5]]F]]]]p]]pp]F]F|]]]]F]]5Fp]55]]5]]l+55]55555+555ll555+5F5555ll55]55]555]]l55]]]5]5]]555F]]5555]5+]5]]]+555]]]5555]7{xƲ55l555+555+]5F5555p05F555]FFFFS]5Fp]]]]]]]5]]]55]]pp0]F]]p]p5]5]p]S0p0pp]]ppp]]pp]pp]Sp]pp]pppp0`Igpp]pp0p$S]p]5]p0p]p]p0ppp5]pppp0]p0p0]F]p0]F]]ppp$p+0]pFFFp]S]]ppp]]p]pp]pp$p]F5+]ppp]pS0p0+ppp0r8:]pp]F]Fpppp]]p]]]]0p]S]]]]5FF+S]5+]5]]]]S]5]5]]]FF]SF]F]]Fp]F5p]S5ppF]pppp0p]pp05]p$ppp]F5]p]gZ:Z]]]]]]pp]gS0]]@]]]]SSg]]]FS]]F]]]pg]]pg]ppp]F]FFp0pppp]pp]$$]:8::8:r88Z:::::8::r8::8888:8888:88:8:8::8:::::8::: \;Ʋ xx\\\Ʋ18Rrr rz::z1z 1r8zS5]p]B855]0]]5]]]5]]pcxxxx\୭\\\\\r]]]]5]]SjF5]]]5]]F]5SS]pS@]5]+]]]5+5F]]]5FF]]p]FFF]F]]F555FF5p]]5]]+F55+]]]5]555+55]l5555F55]F]5]]]5]]5]p+5555555+55l55555555l55++|+5؅{xx\; j+5555]5]55555]5+5]p55]]5p]FF]]]]]]S]5]F5]]F]]]]]]p]]F]]]p]]F+]Spppp]F]pp0pp]]5]pp5]pp]F]pp5]05pgT@pp]55+]p]]p]+pp]p$]pppp]]]]pSpp]]]]ppp]pp]S]ppp]]pp0p]pp]ppp0ppSFFp]pp$pp]p:pp]]]p]S]5ppp]p0pp]p]pp]558:Z]]p]F+p]]]p55S0]+]Fp]]]]F5p]55]]]F]S]]F]]]]F]5]+5]Sj5w]]]]p]55]@g]]]p0p00$$pp]5ppppp0$]p]]]S]pp]]ppZZZZp]ppp]p]p]p0pp]]]]]ppp]0p]]]]5F]]]p0pp]Spp]]]p]p%p]pppSgpp]ppp8::::Z8888:8:8::88:::::88::8:88:88:r\\ \\;\1zrrrrRRf818z111:1\1r1zr::5]5p]+5]F]]5]]]5]]]]]]x୭\\\\\r]]5+SS5]]]]]]]]]]]]F]p]]]SSF]]]]]5F]5]S]5]]55F]F0]+]]55]55]555+]]]555+5F]5]Fp]555]55F55]55]FF]p]p55]+0]55l]5]S5+5]S555]555555l55؅{{x;5+55]l5ll]]5+]55]]]F]55]F+]]]5SS55]]]SS]F]]S]5p]]]]Fpp]p]p]pp]]p]]]S]S0pp]p]]]pp]]ppppSFppp]p5]EISpSp]]ppSp0pFp0p0pppp]]pp$p0]0]ppp]]Spp0p]Spp0]p0$%0]]pppppppp]p%]p]]p]Z:::ppF]pppp]pppp]pp00Sp]m]]p]p0]]]p]]SS@S]]pp@F]p]]]FpS]]p]]@]@5]]]]S]S]]]0]]j]pF5]]p0pg0]]Spppp]]%]]p0p]]]]]p]]pp$0p]p]3:Z3]p0]Fpp$]pp]p]S]p]]]p]ppp]]p]5]p0]pp]00]Fp0p]pp0p]FF]pp]p]p$0:8::8r:Z:8Z:8:::8::rZZ::8:8::8:::::::::8:::;\ \xx\\\Ʋ11zr8r11r8rR8\8r1r111rr:g5]]]S]]]]]S]]]]5j|S]]FFx\\\\\\;;1m5]]F]jS]0SS]pp]p]pSp0]]p0@]]]S]]Fp0]]]]]F]]]]]5]]]]]]5F]55p5F]]jFF5]+]p]5F55]FF]]+F55]55]55]F]+55]+F]555]5FF]F5]]]F5]|555555S5]]]؅{{x\;|5]]55555l5F5]55]S55]F]]]]5SS5FS]S]5FSS]SSgS0p]]0p]pp$p]0$$pp]0p5ppp$p]p]]]0pppp]0pp]]p0pp0pp0ppppE@]p]p0pppp5]pp]ppp]p0p]S]]Spp0ppp]ppgSpp0pp]]p$ppp]p0p]p]p]p$p]$pp]JZ::Z]ppFppp]pppp]pp0pp]]p0SpZ8ZpFFpSg]p]]p]@j3p]5]]SS]]SF]SF]5p]F]]]]]@F]p]]0]S]]p]SS5]p]]]p]]0pp+p$p]]0ppS$$$pp]pppppp]p]pp]+Z::Zp]ppp]0p0]pp]]pSp]]]pS$]gpS]pS]]S]]]]0ppp0pp]p]]pp]Fpp0p]ppp8:r888Z8:8rZ:::888::8:88:8::8:8:8888:: \\Ʋ;xxxxx\\\ 1zr81r18RR\1r11r;88:r8r::8]]]p5Fp]]]p5p]]]]]0]SF]0x୭\\\\\\\\\A1rS]]p]]]p]]$p]p0F]]p0]]p0p]p]0p]S]pp0SF]SS]p]F]]]F5]FS5]]]]]F]]]]F]]5SF]]5]]FF]55]5SlX]FF]F]]F]]F55]]]5FF]]55S]5]]5]]F5|5FF]|F5]]555]؅{{x;]55F+5FF]]]S]F]SS]|]]F]]]]Sj05]]SpSj]]]SS]]]S]S0]p]0Spp]$0FS]p]]pp$]pp]pp%0ppSp0]]$pppp$pp]0p0($$$$$$$p$$p$$p!p$&$pMfE<WRT%p$$$$$WRRRRRٳRR::88:8:88r8:::888r:r rzrr:Zrr8r:8\r:8:88RRRRRRRRRRRWWWaWWRrfRf8rrrrryfWW8rR:y1RRRRRRy11118:8:+lluluuluululuuuuuuYHRHuuuuuuuuuuuuuuuuuuuuuuluululuullllluuuuuuuuuluuuuuululuuuuuuuuuuuuuuullllulllllllllFF|FFF|luuuluuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuul_lululluuuuuuuu_uu_uu_uuuuuuuuuuuuuluuluulull+lulululllF|F|SFSS@pp@pp$p$p%p}}66a%T%$$fRRRRIII?##h#}L}6R%ML%$$$UUfRUUURR&RRI<a`MhhW##RR!<%$$$$$$$$$$$$$$$$pppUSRRRRRRRfRp`<$$<fW!MaaW<66RfRRR::$$$$$$$$$pp$$`ppMf}QR%p$$$$$W8RRRRRR8R8:8:8888r8ZZ:888r1rrϕA8ZZZ:118\r::888RRRRRRRRRRRRRryR8zrzr8fWzr8rR8&:RRRRRRy 1 1z8:8:|+uuuluuluull lY!I+vNuuuuuuuuuuuuuuuuuuuuuuulll+l+l|+luuululuuuluul_uuu_uuuuuuuuuuul+uuluulullullluululll||FFFF|FFFluluuuuuu_uuuuuuuuuu_uuu_uuuuuuuuuuuuuuuuuuu_uuuu_uuuuuuuuu_uuullll|uluuuuuuuuuuuuuuuuuuuul_luuuluuuuuulllluuuuuuuullFFFSS@pSppSpppppppW}h^%6%T`$$$fR&RRRRRR%#RC}yRWRrz8:Z18r81 rzAS]]FRRp]]Rf]ppRR]RRRRRRRRR%U(%(cR-%$%L6Uf&}}}!(2aER}}}R#R&WRRRRf%RRRRR%%R%%R%pR&R&UWR%$p%&ppS`TS`&F5`5F&EWl|FF|F|F|F||luu|lul|F|F|F|FF@FF@SFF|FFF|F||F|FF|FF@FS|S|SSSS|SFFF|F|llllllllllu+uullu_ululuulll+lllullulllulluuluuu_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuulll|llll55+"V###}##}R#}##W}RRRRRRRRRRRRWwLhRLI&gppppppp$$%%2V}2 VW0M#6&6ERRRWs}W}RRW?}R6WRRfRRfUWhfE¿Rhf-Whh^RWV(IWfRRRRRRRRRRRRRRRRRRET&RfR&&RM%$UR$W$$$$$$}R>#}yRR8zZC8811rr|]&F]]R]]gRR]]RpRRRRfRRR&%%~A:ZRWZ%%f%a&}a%%(:ޠR?@%fRRRUEERRRRR6RRRRRRRRRRRRRRRRRRRRRRRRRWIfRRRfRRRRRRRRRRRR&RRR}WR&WR&IRR6WR}W}RRZޠWWWRRRRRRRWRRRRRRRRRRRRRRf&RUfR%$p$%$$$$$%%$$$$$$$p$pppp@S@Sp@SSSSSF|FFFFFFFulF|FF|FSSSSSSSpSSSSS@`]F`I&@FFFFSFS@FSSSSppp@pSppp$@ppppp$ppppp@p@SpS@Spp@ppSp@pS@SS@FSSS FSFSFFFSF@FF FFSSFSFFSFFFSFF|FFFF|FFFF|llll|FFFl|FF|FFFFFFFFSFFSFFFFF|FF|FFFF|F|FFFFFF|FF|FF|FF FS|SFSFSF|F|FF|FSFF|YEWWRRRRRRRRRRIERRR+hWRRRRaEEEV}R1VaWfa}}}WWRI?}6^[LWWWWWWWRRRRWR}RaIIRRg0`L?V##VV#"<%%%(&RfIE}}}}}}RRRRRRRRRf&ITTpppSS@$$$$$$$$$$$ppgSSS@FF@F@SSS@S||uluWRW#R}}}}WR6##Wf%RRRR(RRfRRRRRRRRRRRRRRRRRW}WfUERRRRRRRRRRRRRRRRRfIRRR(RRWRURRRWRW}WR}WRZ}#}RRRRRRRRRRRRRRRRRRRRRR&U&%&RU$$%$p$$$$$$$$$$$$$$$$$$pppSSpSp SFSFSFFFllllFFFF|FSF@SSS@SSSpS`]] #include struct UserConfigVar : public ObjectCounter { std::string Name; std::string Value; }; /*! \class UserConfig \brief user configuration from xml data \details This class manages user configurations read from/written to xml data. It allows saving/loading from disk and getting/setting floats, booleans, strings and integers by name */ class UserConfig: public IUserConfigReader, public ObjectCounter { public: ~UserConfig(); bool loadFile(const std::string& filename); bool saveFile(const std::string& filename) const; void setValue(const std::string& name, const std::string& value); float getFloat(const std::string& name, float default_value = 0.f) const; std::string getString(const std::string& name, const std::string& default_value = "") const; bool getBool(const std::string& name, bool default_value = false) const; int getInteger(const std::string& name, int default_value = 0) const; PlayerIdentity loadPlayerIdentity(PlayerSide player, bool force_human); void setFloat(const std::string& name, float value); void setString(const std::string& name, const std::string& value); void setBool(const std::string& name, bool value); void setInteger(const std::string& name, int value); private: std::vector mVars; bool mChangeFlag; UserConfigVar* findVarByName(const std::string& Name) const; UserConfigVar* checkVarByName(const std::string& name) const; UserConfigVar* createVar(const std::string& name, const std::string& value); }; blobby-1.0/data/scripts/old/hyp013.lua000644 001750 001750 00000024313 12313310254 022315 0ustar00danielknobedanielknobe000000 000000 g=0.28 pg=0.88 v0=14.5 v_p=4.5 pj=0.44 r1=31.5 h=31.5+19+25 estt=0 p=0.654 function reset() est=0 imp,imp1,imp2=0,0,0 nettime=0 touch=0 esto1=0 esto2=0 esto3=0 esto4=0 esto5=0 esto6=0 phase=0 valid=1 active=1 nettime=0 y1p=posy() end function yb(y,vy,t) return y+(vy-g/10)*t-1/2*g*t^2 end function move(x) if (posx()2.26) then right() elseif (posx()>x) and (math.abs(posx()-x)>2.26) then left() end end function tb(y,vy,height,typ) local sgn=0 if (typ==1) then sgn=-1 else sgn=1 end if vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g<0 then return -1 else return -1/10+vy/g+sgn*math.sqrt( vy^2/g^2-vy/(5*g)+1/100+2*(y-height)/g ) end end function time(t) return 1/5*math.ceil(5*t) end function pos2(x) local x1,x2 x1=4.5*math.ceil((1/4.5)*x) x2=4.5*math.floor((1/4.5)*x) if (x1<0) or (x2<0) then return 0 else if (math.abs(x1-x)146) then return (v1p/0.88-1/2+math.sqrt((v1p/0.88-1/2)^2-(144.5-y1p)/0.44)) else return 0 end end function time(t) return 1/5*math.ceil(5*t) end -- function collide(x,y,vx,vy,objx,objy,r2) local t1=time(math.max(tb(y,vy,objy-(r1+r2),1)-0.2,0)) local t2=time(tb(y,vy,objy+(r1+r2),1)+0.2) local t3=time(math.max(tb(y,vy,objy+(r1+r2),2)-0.2,0)) local t4=time(tb(y,vy,objy-(r1+r2),2)+0.2) local t=-1 if (t1150) then t=-1 end return t end function estimate(x,y,vx,vy,height,typ) local collision=1 local tw,tn,ts=0,0,0 local tr,xr,yr,vxr,vyr,n=0,0,0,0,0,0 while(collision==1) do ts=collide(x,y,vx,vy,400,316,7) if (vx>0) then tw=time((768.5-x)/vx) tn=time((361.5-x)/vx) else tw=time((31.5-x)/vx) tn=time((438.5-x)/vx) end local th=time(tb(y,vy,height,typ)) local t=10000 if ((ts>0) and (ts0) and (tn0) and (twt) then if (t==ts) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vy=vy-g*t xr=x yr=y vxr=vx vyr=vy n=1 collision=0 elseif ((t==tn) or (t==tw)) then tr=tr+t x=x+vx*t y=yb(y,vy,t) vx=-vx vy=vy-g*t collision=1 end else tr=tr+th vxr=vx vyr=vy-g*th xr=x+vx*th yr=yb(y,vy,th) collision=0 end end if (tr<0) then return -1,-1,-1,-1,-1,-1 else return xr,yr,vxr,vyr,tr,n end end function impact(x,y,vx,vy,xpos,ypos,targety,jum,move) local x1,y1,vx1,vy1=0,0,0,0 local x2,y2,vx2,vy2,t2,nn=0,0,0,0,0,0 local xpos1=xpos local ypos1=ypos for t=0,7,0.2 do if (jum==1) then ypos1=yp(tp(ypos)+t) end x1=x+vx*t if (x1<31.5) then x1=2*31.5-x1 end if (x1>368.5) then x1=2*368.5-x1 end y1=yb(y,vy,t) if ((xpos1-x1)^2+(ypos1+19-y1)^2<(31.5+25)^2) then local dx=x1-xpos1 local dy=y1-(ypos1+19) local l=math.sqrt(dx^2+dy^2) vx1=dx/l vy1=dy/l x1=x1+vx1*3 y1=y1+vy1*3 vy1=vy1*13.125 vx1=vx1*13.125 x2,y2,vx2,vy2,t2,nn=estimate(x1,y1,vx1,vy1,targety,2) break end end return x2,y2,x1,y1,vx1,vy1 end function playto(position) if (math.abs(est-esto3)>0.2) then delta=30 esto3=est imp,impt,impf=0,0,0 x1=0 t=27 typ1=60 typ2=120 if (position<400) then n1=2 n2=-3 elseif (position>600) then n1=-4 n2=-11 else n1=-1 n2=-8 end while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(math.ceil((tp2(posy(),vp))))1) and (t2f>1) then for x1f=pos(x2f)+n1*4.5,pos(x2f)+n2*4.5,-4.5 do impf,_,xaf,yaf,vxaf,vyaf=impact(x2f,y2f,vx2f,vy2f,x1f,y1f,220,j,0) if (impf>position-delta) and (math.abs(posx()-x1f)/4.5+10) and (x1f<330) and (impfposition+delta) and ((x1f-pos(x2f))/4.5<0) then break end end end if (imp>position-delta) and (imp15) then t=t-6 else t=t-3 end end t2=t2+1 end if (x1>0) and (imp>0) then t2=t2-1 move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else move(est+4.5) end end function net() if (math.abs(est-esto2)>0.2) then esto2=est imp,impt,impf=0,0,0 x1=0 t=27 typ1=60 typ2=120 while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(math.ceil((tp2(posy(),vp))))+21) and (t2f>1) then for x1f=pos(x2f)-1*4.5,pos(x2f)-10*4.5,-4.5 do impf,_,xaf,yaf,vxaf,vyaf=impact(x2f,y2f,vx2f,vy2f,x1f,y1f,220,j,0) if (impf>400) and (math.abs(posx()-x1f)/4.50) and (x1f<330) and (impf<438) then imp=impf x1=x1f y1=y1f t1=t1f x2=x2f y2=y2f t2=t2f vx2=vx2f vy2=vy2f xa=xaf ya=yaf vxa=vxaf vya=vyaf break end if (imp>400) then break end end end if (imp>400) and (imp<438) then break end if (t>15) then t=t-6 else t=t-3 end end t2=t2+1 end if (x1>0) and (imp>0) then t2=t2-1 move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else playto(600) end end function attack() if (math.abs(est-esto1)>0.2) then h2=900 esto1=est imp,impt,impf=0,0,0 x1=0 t=27 typ1=60 typ2=120 while (t>=0) do if (t==0) then j=0 else j=1 end t1f=t y1f=yp(t1f) t2g=math.floor(tb(y,vy,y1f+h,2)) y2f=yb(y,vy,t2g) vy2f=vy-g*t2g x2f,y2f,vx2f,vy2f,t2f,_=estimate(x,y,vx,vy,y2f-vy2f/30,2) t1f=math.floor(tp(y2f-h)) y1f=yp(t1f) if (t1f+math.abs(math.ceil((tp2(posy(),vp))))+21) and (t2f>1) then for x1f=pos(x2f)-20*4.5,pos(x2f)-4*4.5,4.5 do impf,_,xaf,yaf,vxaf,vyaf=impact(x2f,y2f,vx2f,vy2f,x1f,y1f,220,j,0) h1=yb(yaf,vyaf,(380-xaf)/vxaf) h2=yb(yaf,vyaf,(420-xaf)/vxaf) height=316+7+31.5 if (impf>432) and (math.abs(posx()-x1f)/4.5+10) and (x1f<330) and (h2>height+typ1) and (h1>height+typ1) and (h2432) and (h2>height+typ2) then break end end end if (imp>0) then break end if (t>15) then t=t-6 else t=t-3 end end t2=t2+1 end if (x1>0) and (imp>0) then t2=t2-1 move(x1) if (t2<=t1+0.1) and (y1>146) then jump() end else playto(600) end end function OnOpponentServe() reset() if (math.abs(pos2(posx())-posx())>1) then move(400) else move(200) end end function OnServe(ballready) reset() if (math.abs(pos2(posx())-posx())>1) then move(400) else if (math.abs(posx()-198)<2) then jump() else move(198) end end end function OnGame() yp2=y1p y1p=posy() vp=y1p-yp2 if (math.abs(imp1-imp)>0.1) then imp2=imp1 imp1=imp end esttold=estt netold=netc toucho=touch touch=touches() if (touch438.5) or (est<361.5)) then nettime=11 phase=4 elseif (phase==4) and (nettime>0) then nettime=nettime-1 else if (est>438.5) then phase=2 elseif (est<438.5) and (est>361.5) then if (((vyestt-g*(80-estt)/vxestt)>0) or (vxestt<0)) and ((360-posx())/4.5=0.2)) then attack() else playto(600) end elseif (p>=0.6) and (p<0.9) then if (p<0.7) and (touch==0) then playto(300) else playto(770) end -- elseif (p>=0.9) and (p<0.95) then -- playto(480) else if (p<0.95) and (touch==0) then playto(300) elseif (touch==1) or ((touch==0) and (p>=0.95)) then playto(480) else playto(600) end end elseif (phase==3) then if (tnet<=tp(393)-3) or (nettime>0) then jump() end if (math.abs(posx()-360)/4.5-7<=tnet) then left() else right() end elseif (phase==4) then right() jump() elseif (phase==5) then move(200) elseif (phase==6) then if (posx()>300) then jump() end right() end if ((x1==0) or (imp==0)) and (phase==1) then move(est) end -- debug(0) -- debug(imp) -- debug(est) end blobby-1.0/src/FileRead.h000644 001750 001750 00000011263 12313310253 020022 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "File.h" #include // forward declarations for convenience functions struct lua_State; class TiXmlDocument; /** \class FileRead \brief Extension of file interface for reading file access. \details Provides various methods for reading numbers, strings and raw bytes from a file. \todo add more convenience methods for easier integration with lua script loading and tinyXML. \sa FileWrite */ class FileRead : public File { public: /// \brief default ctor /// \details File has to be opended with open() /// \throw nothing explicit FileRead(); /// \brief constructor which opens a file. /// \param filename File to be opened for reading /// \throw FileLoadException, if the file could not be loaded FileRead(const std::string& filename); /// \brief opens a file. /// \param filename File to be opened for reading /// \throw FileLoadException, if the file could not be loaded /// \pre No file is currently opened. void open(const std::string& filename); /// destructor, closes the file (if any open) /// \sa close() /// \throw nothing ~FileRead(); // ------------------------------------ // reading interface // ------------------------------------ /// reads bytes into a buffer /// \param target buffer to read into /// \param num_of_bytes number of bytes to read /// \throw PhysfsFileException when nothing could be read /// \throw NoFileOpenedException when called while no file is opened. /// \throw EOFException when cless than \p num_of_bytes bytes are available. uint32_t readRawBytes( char* target, std::size_t num_of_bytes ); /// reads bytes and returns a safe-pointed buffer /// the buffer is allocated by this function and has a size of \p num_of_bytes /// \param num_of_bytes Number of bytes to read; size of buffer /// \throw PhysfsFileException when nothing could be read /// \throw NoFileOpenedException when called while no file is opened. /// \throw EOFException when cless than \p num_of_bytes bytes are available. boost::shared_array readRawBytes( std::size_t num_of_bytes ); /// reads exactly one byte /// \throw PhysfsFileException when Physfs reports an error /// \throw NoFileOpenedException when called while no file is opened. char readByte(); /// reads an unsinged 32 bit integer from the next four bytes in the file /// the integer is expected to be in little-endian-order and is converted /// to the native format. /// \throw PhysfsFileException when Physfs reports an error /// \throw NoFileOpenedException when called while no file is opened. uint32_t readUInt32(); /// reads a 32 bit float from the next four bytes in the file /// \throw PhysfsFileException when Physfs reports an error /// \throw NoFileOpenedException when called while no file is opened. float readFloat(); /// reads a null-terminated string from the file /// \throw PhysfsFileException when Physfs reports an error /// \throw NoFileOpenedException when called while no file is opened. std::string readString(); // helper function for checksum /// calculates a crc checksum of the file contents beginning at posInFile till the end of the file. uint32_t calcChecksum(uint32_t start); // ----------------------------------------------------------------------------------------- // LUA/XML reading helper function // ----------------------------------------------------------------------------------------- static int readLuaScript(std::string filename, lua_State* mState); static boost::shared_ptr readXMLDocument(const std::string& filename); }; blobby-1.0/data/scripts/old/gintonicV8.lua000644 001750 001750 00000020403 12313310254 023315 0ustar00danielknobedanielknobe000000 000000 --Gin Tonic v8 - No Comments, sorry :P CT_ServeSelf = { 152, 163, 180, 195, 205, 240 } CT_ServeOpp = { 140, 200, 240 } CT_ServeIndex = 0 CT_Tolerance = 5 CT_Action = "" CT_ShotDecision = 0 CT_NextGround = 9999 CT_LastTouches = 9999 CT_LastHeight = 0 CT_SkipNextBlock = 0 CT_WaitCounter = 0 CT_WaitName = "" CT_WaitMoveTo = 0 function IsAt(position) return (math.abs(posx()-position) <= CT_Tolerance) end function Wait(name, time, moveto) if (CT_WaitName == name) then if (CT_WaitCounter == 0) then return false end end CT_WaitCounter = time CT_WaitName = name CT_WaitMoveTo = moveto return true end function WaitQueue() if (CT_WaitCounter > 0) then CT_WaitCounter = CT_WaitCounter - 1 if (CT_WaitMoveTo > 0) then if (not IsAt(CT_WaitMoveTo)) then moveto(CT_WaitMoveTo) end end return true else return false end end function ResetWait() CT_WaitCounter = 0 CT_WaitName = "" end function OnOpponentServe() if (CT_ServeIndex == 0) then CT_ServeIndex = math.random(1,3) end if (not IsAt(CT_ServeOpp[CT_ServeIndex])) then moveto(CT_ServeOpp[CT_ServeIndex]) end end function OnServe(ballready) if (WaitQueue()) then return end if (CT_ServeIndex == 0) then CT_ServeIndex = math.random(1,6) end if (ballready) then if (Wait("ServeDelay",math.random(28,90),CT_ServeSelf[CT_ServeIndex]+math.random(-150, 150))) then return end if (IsAt(CT_ServeSelf[CT_ServeIndex])) then jump() else moveto(CT_ServeSelf[CT_ServeIndex]) end else if (posx() < 150) then jump() end moveto(40) end end function OnGame() ResetWait() CT_ServeIndex = 0 local timeJump = timeToHitHeight(380, 390, 20) local timeGround = timeToHitHeight(200, 222, 40) local timeBlock = timeToOppSmash(390) local estimhx = r_estimx(timeJump) local estimGround = r_estimx(timeGround) local estimBlock = r_estimx(timeBlock) local block = 0 local wallcoll = willHitWall(timeJump) if (timeBlock ~= -1) then timeBlock = timeBlock+(estimBlock-400)/13 end if (timeBlock == -1) then timeBlock = 9999 end if (timeJump == -1) then estimhx = 9999 end if (timeGround == -1) then estimGround = 210 end if (CT_SkipNextBlock == 0) then CT_SkipNextBlock = math.random(1,10) end if (posy() < CT_LastHeight and posy() > 150 and posy() < 330) then CT_Action = "" end CT_LastHeight = posy() if (CT_Action == "NetBlock") then if ((posy() < 150) or (timeBlock <= 8 and oppy() < 150) or (ballx() <= posx()) or (touches() <= 0 and bspeedx() > 9)) then CT_Action = "" else jump() moveto(400) return end elseif (CT_Action == "JumpPlayFwd") then if (posy() < 150) then CT_Action = "" else if (estimhx == 9999) then estimhx = ballx()+bspeedx() end jump() if (posy() > 300) then if (math.abs(bally()-posy()) < 18) then moveto(ballx()+bspeedx()) elseif (estimhx < 200) then if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(3,5) end moveto(estimhx-10*CT_ShotDecision) elseif (oppx() > 600 and oppy() < 150) then if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(4,6) end moveto(estimhx-10*CT_ShotDecision) elseif (oppx() < 600 and oppy() > 180) then moveto(estimhx-40) else moveto(estimhx-60) end else moveto(estimhx-50) end return end elseif (CT_Action == "JumpPlayRev") then if (posy() < 150 or touches() ~= CT_LastTouches) then CT_Action = "" else if (estimhx == 9999) then estimhx = ballx()+bspeedx() end jump() if (CT_ShotDecision == 0 and touches() == 2) then CT_ShotDecision = math.random(5,7) end if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(3,8) end if (math.abs(bally()-posy()) < 18) then moveto(ballx()+bspeedx()) else moveto(estimhx+5*CT_ShotDecision) end return end end if (touches() ~= CT_LastTouches) then CT_LastTouches = touches() CT_NextGround = math.random(-20,20) CT_SkipNextBlock = 0 end if (CT_Action == "") then if ((ballx() < 400 or bspeedx() < -2 or bspeedx() > 10) and estimGround < 400) then if (touches() >= 2) then moveto(estimGround+(posx()-500)/22) elseif (math.abs(bspeedx()) > 8) then moveto(estimGround) else moveto(estimGround+CT_NextGround) end elseif (estimhx < 650 and math.abs(bspeedx()) < 6) then moveto(215) elseif (estimhx > 650) then moveto(250) else moveto(180) end end if (posy() > 150) then return end if (touches() > 2) then return end if (timeBlock >= 23 and timeBlock <= 25 and CT_SkipNextBlock ~= 1) then if (posx() > 210 and estimBlock > 395 and estimBlock < 650 and not wallcoll) then jump() moveto(400) CT_Action = "NetBlock" return end end if (timeJump >= 17 and timeJump <= 19) then if (bspeedx() <= 7 and estimhx >= 65 and estimhx <= 420 and posx()-estimhx <= 120 and (bspeedx() >= -7 or not wallcoll)) then if (estimGround > 400 or bally() > 250) then CT_Action = "JumpPlayFwd" CT_ShotDecision = 0 jump() end end if ((wallcoll or bspeedx() >= -7) and estimhx <= 250 and posx()-estimhx <= 180 and posx()-estimhx >= -120) then if (estimGround > 400 or bally() > 250) then if (CT_Action == "JumpPlayFwd" and (touches() >= 2 or math.random(100) > 15)) then return end CT_Action = "JumpPlayRev" CT_ShotDecision = 0 jump() end end end end function timeToHitHeight(minheight, maxheight, depth) local i = 0 for i=1, depth do if (estimy(i) >= minheight and estimy(i) <= maxheight) then return i end end return -1 end function timeToOppSmash(height) if (bally() < height) then return -1 end local i = 0 for i=1, 17 do if (estimy(i) < height) then return i end end return -1 end function r_estimx(time) local estim = estimx(time) if estim < 31.5 then estim = 63-estim end if estim > 768.5 then estim = 1537-estim end if (bally() < 330) then if (ballx() < 400 and estim > 400) then estim = 723-estim end if (ballx() > 400 and estim < 400) then estim = 877-estim end end return estim end function willHitWall(time) if (estimx(time) < 31.5) then return true end if (estimx(time) > 768.5) then return true end return false endblobby-1.0/data/gfx/pfeil_unten.bmp000644 001750 001750 00000001466 12313310254 022121 0ustar00danielknobedanielknobe000000 000000 BM6(@  00& LF . l+hK&LZHT blobby-1.0/src/raknet/LinkedList.h000644 001750 001750 00000102314 12313310247 021676 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * * @brief LinkedList and Circular Linked List * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * 9/04 Giblet - updated code to work with new compilers adhering more * closely to ISO standard * */ #ifndef __LINKED_LIST_H #define __LINKED_LIST_H /** * @brief Basic Data Structures (containers) * * This namespace contains containers used in RakNet. */ namespace BasicDataStructures { // Prototype to prevent error in CircularLinkedList class when a reference is made to a LinkedList class template class LinkedList; /** * (Circular) Linked List ADT (Doubly Linked Pointer to Node Style) - * By Kevin Jenkins (http://www.rakkar.org) * Initilize with the following command * LinkedList * OR * CircularLinkedList * * Has the following member functions * - size: returns number of elements in the linked list * - insert(item): inserts @em item at the current position in * the LinkedList. * - add(item): inserts @em item after the current position in * the LinkedList. Does not increment the position * - replace(item): replaces the element at the current position @em item. * - peek: returns the element at the current position * - pop: returns the element at the current position and deletes it * - del: deletes the current element. Does nothing for an empty list. * - clear: empties the LinkedList and returns storage * - bool is_in(item): Does a linear search for @em item. Does not set * the position to it, only returns true on item found, false otherwise * - bool find(item): Does a linear search for @em item and sets the current * position to point to it if and only if the item is found. Returns true * on item found, false otherwise * - sort: Sorts the elements of the list with a mergesort and sets the * current pointer to the first element * - concatenate(list L): This appends L to the current list * - ++(prefix): moves the pointer one element up in the list and returns the * appropriate copy of the element in the list * - --(prefix): moves the pointer one element back in the list and returns * the appropriate copy of the element in the list * - beginning - moves the pointer to the start of the list. For circular * linked lists this is first 'position' created. You should call this * after the sort function to read the first value. * - end - moves the pointer to the end of the list. For circular linked * lists this is one less than the first 'position' created * The assignment and copy constructor operators are defined * * @note * 1. LinkedList and CircularLinkedList are exactly the same except LinkedList * won't let you wrap around the root and lets you jump to two positions * relative to the root/ * 2. Postfix ++ and -- can be used but simply call the prefix versions. * * * EXAMPLE: * @code * LinkedList A; // Creates a Linked List of integers called A * CircularLinkedList B; // Creates a Circular Linked List of * // integers called B * * A.insert(20); // Adds 20 to A. A: 20 - current is 20 * A.insert(5); // Adds 5 to A. A: 5 20 - current is 5 * A.insert(1); // Adds 1 to A. A: 1 5 20 - current is 1 * * A.is_in(1); // returns true * A.is_in(200); // returns false * A.find(5); // returns true and sets current to 5 * A.peek(); // returns 5 * A.find(1); // returns true and sets current to 1 * * (++A).peek(); // Returns 5 * A.peek(); // Returns 5 * * A.replace(10); // Replaces 5 with 10. * A.peek(); // Returns 10 * * A.beginning(); // Current points to the beginning of the list at 1 * * (++A).peek(); // Returns 5 * A.peek(); // Returns 10 * * A.del(); // Deletes 10. Current points to the next element, which is 20 * A.peek(); // Returns 20 * * A.beginning(); // Current points to the beginning of the list at 1 * * (++A).peek(); // Returns 5 * A.peek(); // Returns 20 * * A.clear(); // Deletes all nodes in A * * A.insert(5); // A: 5 - current is 5 * A.insert(6); // A: 6 5 - current is 6 * A.insert(7); // A: 7 6 5 - current is 7 * * A.clear(); * B.clear(); * * B.add(10); * B.add(20); * B.add(30); * B.add(5); * B.add(2); * B.add(25); * // Sorts the numbers in the list and sets the current pointer to the * // first element * B.sort(); * * // Postfix ++ just calls the prefix version and has no functional * // difference. * B.peek(); // Returns 2 * B++; * B.peek(); // Returns 5 * B++; * B.peek(); // Returns 10 * B++; * B.peek(); // Returns 20 * B++; * B.peek(); // Returns 25 * B++; * B.peek(); // Returns 30 * @endcode */ template class CircularLinkedList { public: struct node { CircularLinkedListType item; node* previous; node* next; }; CircularLinkedList(); ~CircularLinkedList(); CircularLinkedList( const CircularLinkedList& original_copy ); // CircularLinkedList(LinkedList original_copy) {CircularLinkedList(original_copy);} // Converts linked list to circular type bool operator= ( const CircularLinkedList& original_copy ); CircularLinkedList& operator++(); // CircularLinkedList A; ++A; CircularLinkedList& operator++( int ); // Circular_Linked List A; A++; CircularLinkedList& operator--(); // CircularLinkedList A; --A; CircularLinkedList& operator--( int ); // Circular_Linked List A; A--; bool is_in( const CircularLinkedListType& input ); bool find( const CircularLinkedListType& input ); void insert( const CircularLinkedListType& input ); CircularLinkedListType& add ( const CircularLinkedListType& input ) ; // Adds after the current position void replace( const CircularLinkedListType& input ); void del( void ); unsigned int size( void ); CircularLinkedListType& peek( void ); const CircularLinkedListType pop( void ); void clear( void ); void sort( void ); void beginning( void ); void end( void ); void concatenate( const CircularLinkedList& L ); protected: unsigned int list_size; node *root; node *position; node* find_pointer( const CircularLinkedListType& input ); private: CircularLinkedList merge( CircularLinkedList L1, CircularLinkedList L2 ); CircularLinkedList mergesort( const CircularLinkedList& L ); }; template class LinkedList : public CircularLinkedList { public: LinkedList() {} LinkedList( const LinkedList& original_copy ); ~LinkedList(); bool operator= ( const LinkedList& original_copy ); LinkedList& operator++(); // LinkedList A; ++A; LinkedList& operator++( int ); // Linked List A; A++; LinkedList& operator--(); // LinkedList A; --A; LinkedList& operator--( int ); // Linked List A; A--; private: LinkedList merge( LinkedList L1, LinkedList L2 ); LinkedList mergesort( const LinkedList& L ); }; template inline void CircularLinkedList::beginning( void ) { if ( this->root ) this->position = this->root; } template inline void CircularLinkedList::end( void ) { if ( this->root ) this->position = this->root->previous; } template bool LinkedList::operator= ( const LinkedList& original_copy ) { typename LinkedList::node * original_copy_pointer, *save_position; if ( ( &original_copy ) != this ) { this->clear(); if ( original_copy.list_size == 0 ) { this->root = 0; this->position = 0; this->list_size = 0; } else if ( original_copy.list_size == 1 ) { this->root = new typename LinkedList::node; // root->item = new LinkedListType; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; } else { // Setup the first part of the root node original_copy_pointer = original_copy.root; this->root = new typename LinkedList::node; // root->item = new LinkedListType; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; do { // Save the current element this->last = this->position; // Point to the next node in the source list original_copy_pointer = original_copy_pointer->next; // Create a new node and point position to it this->position = new typename LinkedList::node; // position->item = new LinkedListType; // Copy the item to the new node // *(position->item)=*(original_copy_pointer->item); this->position->item = original_copy_pointer->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; // Set the previous pointer for the new node ( this->position->previous ) = this->last; // Set the next pointer for the old node to the new node ( this->last->next ) = this->position; } while ( ( original_copy_pointer->next ) != ( original_copy.root ) ); // Complete the circle. Set the next pointer of the newest node to the root and the previous pointer of the root to the newest node this->position->next = this->root; this->root->previous = this->position; this->list_size = original_copy.list_size; this->position = save_position; } } return true; } template CircularLinkedList::CircularLinkedList() { this->root = 0; this->position = 0; this->list_size = 0; } template CircularLinkedList::~CircularLinkedList() { this->clear(); } template LinkedList::~LinkedList() { this->clear(); } template LinkedList::LinkedList( const LinkedList& original_copy ) { typename LinkedList::node * original_copy_pointer, *last, *save_position; if ( original_copy.list_size == 0 ) { this->root = 0; this->position = 0; this->list_size = 0; return ; } else if ( original_copy.list_size == 1 ) { this->root = new typename LinkedList::node; // root->item = new CircularLinkedListType; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; // *(root->item) = *((original_copy.root)->item); this->root->item = original_copy.root->item; } else { // Setup the first part of the root node original_copy_pointer = original_copy.root; this->root = new typename LinkedList::node; // root->item = new CircularLinkedListType; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; do { // Save the current element this->last = this->position; // Point to the next node in the source list original_copy_pointer = original_copy_pointer->next; // Create a new node and point position to it this->position = new typename LinkedList::node; // position->item = new CircularLinkedListType; // Copy the item to the new node // *(position->item)=*(original_copy_pointer->item); this->position->item = original_copy_pointer->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; // Set the previous pointer for the new node ( this->position->previous ) = last; // Set the next pointer for the old node to the new node ( this->last->next ) = this->position; } while ( ( original_copy_pointer->next ) != ( original_copy.root ) ); // Complete the circle. Set the next pointer of the newest node to the root and the previous pointer of the root to the newest node this->position->next = this->root; this->root->previous = this->position; this->list_size = original_copy.list_size; this->position = save_position; } } template CircularLinkedList::CircularLinkedList( const CircularLinkedList& original_copy ) { node * original_copy_pointer; node *save_position; if ( original_copy.list_size == 0 ) { this->root = 0; this->position = 0; this->list_size = 0; return ; } else if ( original_copy.list_size == 1 ) { this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; // *(root->item) = *((original_copy.root)->item); this->root->item = original_copy.root->item; } else { // Setup the first part of the root node original_copy_pointer = original_copy.root; this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; do { // Save the current element this->last = this->position; // Point to the next node in the source list original_copy_pointer = original_copy_pointer->next; // Create a new node and point position to it this->position = new typename CircularLinkedList::node; // position->item = new CircularLinkedListType; // Copy the item to the new node // *(position->item)=*(original_copy_pointer->item); this->position->item = original_copy_pointer->item; if ( original_copy_pointer == original_copy.position ) save_position = position; // Set the previous pointer for the new node ( this->position->previous ) = this->last; // Set the next pointer for the old node to the new node ( this->last->next ) = this->position; } while ( ( original_copy_pointer->next ) != ( original_copy.root ) ); // Complete the circle. Set the next pointer of the newest node to the root and the previous pointer of the root to the newest node this->position->next = this->root; this->root->previous = position; this->list_size = original_copy.list_size; this->position = save_position; } } template bool CircularLinkedList::operator= ( const CircularLinkedList& original_copy ) { node * original_copy_pointer; node *save_position; if ( ( &original_copy ) != this ) { this->clear(); if ( original_copy.list_size == 0 ) { this->root = 0; this->position = 0; this->list_size = 0; } else if ( original_copy.list_size == 1 ) { this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; } else { // Setup the first part of the root node original_copy_pointer = original_copy.root; this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; do { // Save the current element this->last = this->position; // Point to the next node in the source list original_copy_pointer = original_copy_pointer->next; // Create a new node and point position to it this->position = new typename CircularLinkedList::node; // position->item = new CircularLinkedListType; // Copy the item to the new node // *(position->item)=*(original_copy_pointer->item); this->position->item = original_copy_pointer->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; // Set the previous pointer for the new node ( this->position->previous ) = this->last; // Set the next pointer for the old node to the new node ( this->last->next ) = this->position; } while ( ( original_copy_pointer->next ) != ( original_copy.root ) ); // Complete the circle. Set the next pointer of the newest node to the root and the previous pointer of the root to the newest node this->position->next = this->root; this->root->previous = this->position; this->list_size = original_copy.list_size; this->position = save_position; } } return true; } template void CircularLinkedList::insert( const CircularLinkedListType& input ) { node * new_node; if ( list_size == 0 ) { this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; //*(root->item)=input; this->root->item = input; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; } else if ( list_size == 1 ) { this->position = new typename CircularLinkedList::node; // position->item = new CircularLinkedListType; this->root->next = this->position; this->root->previous = this->position; this->position->previous = this->root; this->position->next = this->root; // *(position->item)=input; this->position->item = input; this->root = this->position; // Since we're inserting into a 1 element list the old root is now the second item this->list_size = 2; } else { /* B | A --- C position->previous=A new_node=B position=C Note that the order of the following statements is important */ new_node = new typename CircularLinkedList::node; // new_node->item = new CircularLinkedListType; // *(new_node->item)=input; new_node->item = input; // Point next of A to B ( this->position->previous ) ->next = new_node; // Point last of B to A new_node->previous = this->position->previous; // Point last of C to B this->position->previous = new_node; // Point next of B to C new_node->next = this->position; // Since the root pointer is bound to a node rather than an index this moves it back if you insert an element at the root if ( this->position == this->root ) { this->root = new_node; this->position = this->root; } // Increase the recorded size of the list by one this->list_size++; } } template CircularLinkedListType& CircularLinkedList::add ( const CircularLinkedListType& input ) { node * new_node; if ( this->list_size == 0 ) { this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; // *(root->item)=input; this->root->item = input; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; // return *(position->item); return this->position->item; } else if ( list_size == 1 ) { this->position = new typename CircularLinkedList::node; // position->item = new CircularLinkedListType; this->root->next = this->position; this->root->previous = this->position; this->position->previous = this->root; this->position->next = this->root; // *(position->item)=input; this->position->item = input; this->list_size = 2; this->position = this->root; // Don't move the position from the root // return *(position->item); return this->position->item; } else { /* B | A --- C new_node=B position=A position->next=C Note that the order of the following statements is important */ new_node = new typename CircularLinkedList::node; // new_node->item = new CircularLinkedListType; // *(new_node->item)=input; new_node->item = input; // Point last of B to A new_node->previous = this->position; // Point next of B to C new_node->next = ( this->position->next ); // Point last of C to B ( this->position->next ) ->previous = new_node; // Point next of A to B ( this->position->next ) = new_node; // Increase the recorded size of the list by one this->list_size++; // return *(new_node->item); return new_node->item; } } template inline void CircularLinkedList::replace( const CircularLinkedListType& input ) { if ( this->list_size > 0 ) // *(position->item)=input; this->position->item = input; } template void CircularLinkedList::del() { node * new_position; if ( this->list_size == 0 ) return ; else if ( this->list_size == 1 ) { // delete root->item; delete this->root; this->root = this->position = 0; this->list_size = 0; } else { ( this->position->previous ) ->next = this->position->next; ( this->position->next ) ->previous = this->position->previous; new_position = this->position->next; if ( this->position == this->root ) this->root = new_position; // delete position->item; delete this->position; this->position = new_position; this->list_size--; } } template bool CircularLinkedList::is_in( const CircularLinkedListType& input ) { node * return_value, *old_position; old_position = this->position; return_value = find_pointer( input ); this->position = old_position; if ( return_value != 0 ) return true; else return false; // Can't find the item don't do anything } template bool CircularLinkedList::find( const CircularLinkedListType& input ) { node * return_value; return_value = find_pointer( input ); if ( return_value != 0 ) { this->position = return_value; return true; } else return false; // Can't find the item don't do anything } template typename CircularLinkedList::node* CircularLinkedList::find_pointer( const CircularLinkedListType& input ) { node * current; if ( this->list_size == 0 ) return 0; current = this->root; // Search for the item starting from the root node and incrementing the pointer after every check // If you wind up pointing at the root again you looped around the list so didn't find the item, in which case return 0 do { // if (*(current->item) == input) return current; if ( current->item == input ) return current; current = current->next; } while ( current != this->root ); return 0; } template inline unsigned int CircularLinkedList::size( void ) { return this->list_size; } template inline CircularLinkedListType& CircularLinkedList::peek( void ) { // return *(position->item); return this->position->item; } template const CircularLinkedListType CircularLinkedList::pop( void ) { CircularLinkedListType element; element = peek(); del(); return CircularLinkedListType( element ); // return temporary } // Prefix template CircularLinkedList& CircularLinkedList::operator++() { if ( this->list_size != 0 ) position = position->next; return *this; } /* // Postfix template CircularLinkedList& CircularLinkedList::operator++(int) { CircularLinkedList before; before=*this; operator++(); return before; } */ template CircularLinkedList& CircularLinkedList::operator++( int ) { return this->operator++(); } // Prefix template CircularLinkedList& CircularLinkedList::operator--() { if ( this->list_size != 0 ) this->position = this->position->previous; return *this; } /* // Postfix template CircularLinkedList& CircularLinkedList::operator--(int) { CircularLinkedList before; before=*this; operator--(); return before; } */ template CircularLinkedList& CircularLinkedList::operator--( int ) { return this->operator--(); } template void CircularLinkedList::clear( void ) { if ( this->list_size == 0 ) return ; else if ( this->list_size == 1 ) // {delete root->item; delete root;} { delete this->root; } else { node* current; current = this->root; do { node* temp = current; current = current->next; // delete temp->item; delete temp; } while ( current != this->root ); } this->list_size = 0; this->root = 0; this->position = 0; } template inline void CircularLinkedList::concatenate( const CircularLinkedList& L ) { unsigned int counter; node* ptr; if ( L.list_size == 0 ) return ; if ( this->list_size == 0 ) * this = L; ptr = L.root; this->position = this->root->previous; // Cycle through each element in L and add it to the current list for ( counter = 0; counter < L.list_size; counter++ ) { // Add item after the current item pointed to // add(*(ptr->item)); add ( ptr->item ) ; // Update pointers. Moving ptr keeps the current pointer at the end of the list since the add function does not move the pointer ptr = ptr->next; this->position = this->position->next; } } template inline void CircularLinkedList::sort( void ) { if ( this->list_size <= 1 ) return ; // Call equal operator to assign result of mergesort to current object *this = mergesort( *this ); this->position = this->root; } template CircularLinkedList CircularLinkedList::mergesort( const CircularLinkedList& L ) { unsigned int counter; node* location; CircularLinkedList L1; CircularLinkedList L2; location = L.root; // Split the list into two equal size sublists, L1 and L2 for ( counter = 0; counter < L.list_size / 2; counter++ ) { // L1.add (*(location->item)); L1.add ( location->item ); location = location->next; } for ( ;counter < L.list_size; counter++ ) { // L2.add(*(location->item)); L2.add ( location->item ); location = location->next; } // Recursively sort the sublists if ( L1.list_size > 1 ) L1 = mergesort( L1 ); if ( L2.list_size > 1 ) L2 = mergesort( L2 ); // Merge the two sublists return merge( L1, L2 ); } template CircularLinkedList CircularLinkedList::merge( CircularLinkedList L1, CircularLinkedList L2 ) { CircularLinkedList X; CircularLinkedListType element; L1.position = L1.root; L2.position = L2.root; // While neither list is empty while ( ( L1.list_size != 0 ) && ( L2.list_size != 0 ) ) { // Compare the first items of L1 and L2 // Remove the smaller of the two items from the list if ( ( ( L1.root ) ->item ) < ( ( L2.root ) ->item ) ) // if ((*((L1.root)->item)) < (*((L2.root)->item))) { // element = *((L1.root)->item); element = ( L1.root ) ->item; L1.del(); } else { // element = *((L2.root)->item); element = ( L2.root ) ->item; L2.del(); } // Add this item to the end of X X.add( element ); X++; } // Add the remaining list to X if ( L1.list_size != 0 ) X.concatenate( L1 ); else X.concatenate( L2 ); return X; } template LinkedList LinkedList::mergesort( const LinkedList& L ) { unsigned int counter; typename LinkedList::node* location; LinkedList L1; LinkedList L2; location = L.root; // Split the list into two equal size sublists, L1 and L2 for ( counter = 0; counter < L.LinkedList_size / 2; counter++ ) { // L1.add (*(location->item)); L1.add ( location->item ); location = location->next; } for ( ;counter < L.LinkedList_size; counter++ ) { // L2.add(*(location->item)); L2.add ( location->item ); location = location->next; } // Recursively sort the sublists if ( L1.list_size > 1 ) L1 = mergesort( L1 ); if ( L2.list_size > 1 ) L2 = mergesort( L2 ); // Merge the two sublists return merge( L1, L2 ); } template LinkedList LinkedList::merge( LinkedList L1, LinkedList L2 ) { LinkedList X; LinkedListType element; L1.position = L1.root; L2.position = L2.root; // While neither list is empty while ( ( L1.LinkedList_size != 0 ) && ( L2.LinkedList_size != 0 ) ) { // Compare the first items of L1 and L2 // Remove the smaller of the two items from the list if ( ( ( L1.root ) ->item ) < ( ( L2.root ) ->item ) ) // if ((*((L1.root)->item)) < (*((L2.root)->item))) { element = ( L1.root ) ->item; // element = *((L1.root)->item); L1.del(); } else { element = ( L2.root ) ->item; // element = *((L2.root)->item); L2.del(); } // Add this item to the end of X X.add( element ); } // Add the remaining list to X if ( L1.LinkedList_size != 0 ) X.concatenate( L1 ); else X.concatenate( L2 ); return X; } // Prefix template LinkedList& LinkedList::operator++() { if ( ( this->list_size != 0 ) && ( this->position->next != this->root ) ) this->position = this->position->next; return *this; } /* // Postfix template LinkedList& LinkedList::operator++(int) { LinkedList before; before=*this; operator++(); return before; } */ // Postfix template LinkedList& LinkedList::operator++( int ) { return this->operator++(); } // Prefix template LinkedList& LinkedList::operator--() { if ( ( this->list_size != 0 ) && ( this->position != this->root ) ) this->position = this->position->previous; return *this; } /* // Postfix template LinkedList& LinkedList::operator--(int) { LinkedList before; before=*this; operator--(); return before; } */ // Postfix template LinkedList& LinkedList::operator--( int ) { return this->operator--(); } } // End namespace #endif blobby-1.0/src/state/GameState.cpp000644 001750 001750 00000016116 12313310253 021676 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "GameState.h" /* includes */ #include #include "ReplayRecorder.h" #include "DuelMatch.h" #include "SoundManager.h" #include "IMGUI.h" #include "TextManager.h" #include "Blood.h" #include "MatchEvents.h" #include "PhysicWorld.h" #include "FileWrite.h" /* implementation */ GameState::GameState(DuelMatch* match) : mMatch(match), mSaveReplay(false), mErrorMessage("") { } GameState::~GameState() { // disable game drawing RenderManager::getSingleton().drawGame(false); } void GameState::presentGame() { // enable game drawing RenderManager::getSingleton().drawGame(true); RenderManager& rmanager = RenderManager::getSingleton(); SoundManager& smanager = SoundManager::getSingleton(); rmanager.setBlob(LEFT_PLAYER, mMatch->getBlobPosition(LEFT_PLAYER), mMatch->getWorld().getBlobState(LEFT_PLAYER)); rmanager.setBlob(RIGHT_PLAYER, mMatch->getBlobPosition(RIGHT_PLAYER), mMatch->getWorld().getBlobState(RIGHT_PLAYER)); if(mMatch->getPlayer(LEFT_PLAYER).getOscillating()) { rmanager.setBlobColor(LEFT_PLAYER, rmanager.getOscillationColor()); } else { rmanager.setBlobColor(LEFT_PLAYER, mMatch->getPlayer(LEFT_PLAYER).getStaticColor()); } if(mMatch->getPlayer(RIGHT_PLAYER).getOscillating()) { rmanager.setBlobColor(RIGHT_PLAYER, rmanager.getOscillationColor()); } else { rmanager.setBlobColor(RIGHT_PLAYER, mMatch->getPlayer(RIGHT_PLAYER).getStaticColor()); } rmanager.setBall(mMatch->getBallPosition(), mMatch->getWorld().getBallRotation()); int events = mMatch->getEvents(); if(events & EVENT_LEFT_BLOBBY_HIT) { smanager.playSound("sounds/bums.wav", mMatch->getWorld().getLastHitIntensity() + BALL_HIT_PLAYER_SOUND_VOLUME); Vector2 hitPos = mMatch->getBallPosition() + (mMatch->getBlobPosition(LEFT_PLAYER) - mMatch->getBallPosition()).normalise().scale(31.5); BloodManager::getSingleton().spillBlood(hitPos, mMatch->getWorld().getLastHitIntensity(), 0); } if (events & EVENT_RIGHT_BLOBBY_HIT) { smanager.playSound("sounds/bums.wav", mMatch->getWorld().getLastHitIntensity() + BALL_HIT_PLAYER_SOUND_VOLUME); Vector2 hitPos = mMatch->getBallPosition() + (mMatch->getBlobPosition(RIGHT_PLAYER) - mMatch->getBallPosition()).normalise().scale(31.5); BloodManager::getSingleton().spillBlood(hitPos, mMatch->getWorld().getLastHitIntensity(), 1); } if (events & EVENT_ERROR) smanager.playSound("sounds/pfiff.wav", ROUND_START_SOUND_VOLUME); } void GameState::presentGameUI() { auto& imgui = IMGUI::getSingleton(); // Scores char textBuffer[64]; snprintf(textBuffer, 8, mMatch->getServingPlayer() == LEFT_PLAYER ? "%02d!" : "%02d ", mMatch->getScore(LEFT_PLAYER)); imgui.doText(GEN_ID, Vector2(24, 24), textBuffer); snprintf(textBuffer, 8, mMatch->getServingPlayer() == RIGHT_PLAYER ? "%02d!" : "%02d ", mMatch->getScore(RIGHT_PLAYER)); imgui.doText(GEN_ID, Vector2(800-24, 24), textBuffer, TF_ALIGN_RIGHT); // blob name / time textfields imgui.doText(GEN_ID, Vector2(12, 550), mMatch->getPlayer(LEFT_PLAYER).getName()); imgui.doText(GEN_ID, Vector2(788, 550), mMatch->getPlayer(RIGHT_PLAYER).getName(), TF_ALIGN_RIGHT); imgui.doText(GEN_ID, Vector2(400, 24), mMatch->getClock().getTimeString(), TF_ALIGN_CENTER); } bool GameState::displaySaveReplayPrompt() { auto& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doOverlay(GEN_ID, Vector2(150, 200), Vector2(650, 400)); imgui.doText(GEN_ID, Vector2(190, 220), TextManager::RP_SAVE_NAME); static unsigned cpos; imgui.doEditbox(GEN_ID, Vector2(180, 270), 18, mFilename, cpos); bool doSave = false; if(imgui.doButton(GEN_ID, Vector2(220, 330), TextManager::LBL_OK)) { if(mFilename != "") { imgui.resetSelection(); doSave = true; } } if (imgui.doButton(GEN_ID, Vector2(440, 330), TextManager::LBL_CANCEL)) { mSaveReplay = false; imgui.resetSelection(); doSave = false; } return doSave; } bool GameState::displayErrorMessageBox() { auto& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doOverlay(GEN_ID, Vector2(100, 200), Vector2(700, 360)); size_t split = mErrorMessage.find(':'); std::string mProblem = mErrorMessage.substr(0, split); std::string mInfo = mErrorMessage.substr(split+1); imgui.doText(GEN_ID, Vector2(120, 220), mProblem); imgui.doText(GEN_ID, Vector2(120, 260), mInfo); if(imgui.doButton(GEN_ID, Vector2(330, 320), TextManager::LBL_OK)) { mErrorMessage = ""; return true; } return false; } bool GameState::displayWinningPlayerScreen(PlayerSide winner) { auto& imgui = IMGUI::getSingleton(); std::string tmp = mMatch->getPlayer(winner).getName(); imgui.doOverlay(GEN_ID, Vector2(200, 150), Vector2(700, 450)); imgui.doImage(GEN_ID, Vector2(200, 250), "gfx/pokal.bmp"); imgui.doText(GEN_ID, Vector2(274, 240), tmp); imgui.doText(GEN_ID, Vector2(274, 300), TextManager::GAME_WIN); imgui.doCursor(); return false; } void GameState::setDefaultReplayName(const std::string& left, const std::string& right) { mFilename = left; if(mFilename.size() > 7) mFilename.resize(7); mFilename += " vs "; std::string opp = right; if(right.size() > 7) opp.resize(7); mFilename += opp; } void GameState::saveReplay(ReplayRecorder& recorder) { try { if (mFilename != "") { std::string repFileName = std::string("replays/") + mFilename + std::string(".bvr"); boost::shared_ptr savetarget = boost::make_shared(repFileName); /// \todo add a check whether we overwrite a file recorder.save(savetarget); savetarget->close(); mSaveReplay = false; } } catch( FileLoadException& ex) { mErrorMessage = std::string("Unable to create file:" + ex.getFileName()); mSaveReplay = true; // try again } catch( FileAlreadyExistsException& ex) { mErrorMessage = std::string("File already exists!:"+ ex.getFileName()); mSaveReplay = true; // try again } catch( std::exception& ex) { mErrorMessage = std::string("Could not save replay: "); mSaveReplay = true; // try again } } blobby-1.0/src/state/State.h000644 001750 001750 00000005711 12313310253 020550 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "Global.h" #include class DuelMatch; class ReplayRecorder; /*! \class State \brief Base class for all programme states. \details A programm state describes which state a programme is in ( e.g. MainMenu, OptionsMenu, SingleplayerGame etc. ). It defines an abstract step function which is called each frame for the currently active state. Switching to a new state is a little cumbersome right now, as it requires deleting the current State (deleteCurrentState()) and setting the new state afterwards. This approach is very error prone and generally not nice, so I hope we can replace it someday with something better ;) */ class State { public: virtual ~State() {} // step function defines the steps actual work virtual void step_impl() = 0; virtual const char* getStateName() const = 0; // static functions /// performs a step in the current state static void step(); /// deinits the state system, deleting the current state. /// this is necessary for now to ensure correct destruction order, so the debug counters are destroyed after the /// state is uncounted. static void deinit(); /// gets the currently active state static boost::scoped_ptr& getCurrentState(); /// gets the name of the currently active state static const char* getCurrenStateName(); protected: /// generic state constructor. automatically resets imgui selection State(); static void switchState(State* newState); private: static boost::scoped_ptr mCurrentState; static boost::scoped_ptr mStateToSwitchTo; }; /*! \class MainMenuState \brief state for main menu */ class MainMenuState : public State { public: MainMenuState(); virtual ~MainMenuState(); virtual void step_impl(); virtual const char* getStateName() const; }; /*! \class CreditsState \brief State for credits screen */ class CreditsState : public State { public: CreditsState(); virtual void step_impl(); virtual const char* getStateName() const; private: float mYPosition; }; blobby-1.0/src/IScriptableComponent.cpp000644 001750 001750 00000002677 12313310252 022776 0ustar00danielknobedanielknobe000000 000000 #include "IScriptableComponent.h" #include "lua/lua.hpp" #include "Global.h" #include "GameConstants.h" IScriptableComponent::IScriptableComponent() : mState(luaL_newstate()) { } IScriptableComponent::~IScriptableComponent() { lua_close(mState); } void IScriptableComponent::setLuaGlobal(const char* name, double value) { lua_pushnumber(mState, value); lua_setglobal(mState, name); } bool IScriptableComponent::getLuaFunction(const char* fname) const { lua_getglobal(mState, fname); if (!lua_isfunction(mState, -1)) { lua_pop(mState, 1); return false; } return true; } void IScriptableComponent::setGameConstants() { // set game constants setLuaGlobal("CONST_FIELD_WIDTH", RIGHT_PLANE); setLuaGlobal("CONST_GROUND_HEIGHT", 600 - GROUND_PLANE_HEIGHT_MAX); setLuaGlobal("CONST_BALL_GRAVITY", -BALL_GRAVITATION); setLuaGlobal("CONST_BALL_RADIUS", BALL_RADIUS); setLuaGlobal("CONST_BLOBBY_JUMP", BLOBBY_JUMP_ACCELERATION); setLuaGlobal("CONST_BLOBBY_BODY_RADIUS", BLOBBY_LOWER_RADIUS); setLuaGlobal("CONST_BLOBBY_HEAD_RADIUS", BLOBBY_UPPER_RADIUS); setLuaGlobal("CONST_BLOBBY_HEIGHT", BLOBBY_HEIGHT); setLuaGlobal("CONST_BLOBBY_GRAVITY", -GRAVITATION); setLuaGlobal("CONST_NET_HEIGHT", 600 - NET_SPHERE_POSITION); setLuaGlobal("CONST_NET_RADIUS", NET_RADIUS); setLuaGlobal("NO_PLAYER", NO_PLAYER); setLuaGlobal("LEFT_PLAYER", LEFT_PLAYER); setLuaGlobal("RIGHT_PLAYER", RIGHT_PLAYER); } blobby-1.0/src/raknet/000755 001750 001750 00000000000 12313310247 017462 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/GenericIOFwd.h000644 001750 001750 00000004223 12313310252 020611 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once /** \file GenericIOFwd.h Including this header will declare the types \p GenericIn an \p GenericOut so they can be passed as parameters etc. If you wan't to use these classes for actual io, you have to include GenericIO.h. Including this header spares the compiler from having to parse all the template stuff, though. */ /// base class template for all GenericIO operations. do not use this class directly. /// use the provided typedefs GenericIn and GenericOut instead. template class GenericIO; // implementation detail, if you just use GenericIO, ignore this namespace ;) namespace detail { struct READER_TAG; struct WRITER_TAG; } // the two typedefs /// Base class for generic input operations. typedef GenericIO GenericIn; /// Base class for generic output operations. typedef GenericIO GenericOut; /// to make GenericIO support a user defined type, you have to implement /// the two functions in this template for that type. template struct UserSerializer { static void serialize( GenericOut& out, const T& value); static void serialize( GenericIn& in, T& value); }; blobby-1.0/data/gfx/font41.bmp000644 001750 001750 00000003370 12313310254 020720 0ustar00danielknobedanielknobe000000 000000 BM6( ]NO}egQAB l2dS#P+*ijګaCD2*Ml=e0-opo?@!S4EjyTo" ™bbl00!K08nu&!kjqp?>]"" \B={zh CBCA% G"jQCTbqK @=-&~E RF-g}=C`.  HFJEJFZTOB, ] +    !OM%U~/9b$  gckexpxsp^T9.'S"H* R@]aa#Q&9'o$O [X|yҍؒߙڗ׌y߆c_#M rQ fae_M6)-u    {jդuB!VX':f-F6"e"JvúzPt,Fk3#.+"~i{;W Cv%  IF8zXX+6 MW;ufO/  t_uPC #)tj_# *@N3rc(2 P<(= #L%I  ,A<'  e aX?L6NGPJ?9/  Ih8w{~w{en\OD-6 i\ڎv?N5ra5O"blobby-1.0/src/InputSource.cpp000644 001750 001750 00000003447 12313310253 021167 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "InputSource.h" /* includes */ #include /* implementation */ /* InputSource */ InputSource::InputSource() : mInput(), mMatch(0) { } InputSource::~InputSource() { } PlayerInput InputSource::getInput() const { return mInput.toPlayerInput( this->getMatch() );; } PlayerInput InputSource::updateInput() { mInput = getNextInput(); return getInput(); } void InputSource::setInput(PlayerInput ip) { mInput = PlayerInputAbs(ip.left, ip.right, ip.up); } void InputSource::setInput(PlayerInputAbs ip) { mInput = ip; } PlayerInputAbs InputSource::getRealInput() const { return mInput; } PlayerInputAbs InputSource::getNextInput() { return mInput; } const DuelMatch* InputSource::getMatch() const { return mMatch; } void InputSource::setMatch(const DuelMatch* match) { assert(mMatch == 0); mMatch = match; } blobby-1.0/data/gfx/blobZeichenWeiss.bmp000644 001750 001750 00000001460 12313310254 023042 0ustar00danielknobedanielknobe000000 000000 BM0(  ..---------! ----------------#"! ------------'%#"! ----------'%$#"! ---------)&%##""! --------&#"!!! !  !-------&$"!  !"""""#------$"  !"###$------!  !"$%&------ "#&'------ !#&)------- !!#####(-------- "#$%&'()+,,-------- !"#$%'(*+,+*--------- !"#$%&'(())---------- !"#$$%&'((---------- !""##$&'((---------- "##$%&'))---------- !"#$&()----------- !#&------------ !#'------------- !-------------------------------------------blobby-1.0/src/lua/lapi.h000644 001750 001750 00000001041 12313310253 020046 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lapi.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ #ifndef lapi_h #define lapi_h #include "llimits.h" #include "lstate.h" #define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ "stack overflow");} #define adjustresults(L,nres) \ { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } #define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ "not enough elements in the stack") #endif blobby-1.0/src/lua/liolib.c000644 001750 001750 00000041454 12313310253 020402 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: liolib.c,v 2.112.1.1 2013/04/12 18:48:47 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ /* ** This definition must come before the inclusion of 'stdio.h'; it ** should not affect non-POSIX systems */ #if !defined(_FILE_OFFSET_BITS) #define _LARGEFILE_SOURCE 1 #define _FILE_OFFSET_BITS 64 #endif #include #include #include #include #define liolib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" #if !defined(lua_checkmode) /* ** Check whether 'mode' matches '[rwa]%+?b?'. ** Change this macro to accept other modes for 'fopen' besides ** the standard ones. */ #define lua_checkmode(mode) \ (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \ (*mode != '+' || ++mode) && /* skip if char is '+' */ \ (*mode != 'b' || ++mode) && /* skip if char is 'b' */ \ (*mode == '\0')) #endif /* ** {====================================================== ** lua_popen spawns a new process connected to the current ** one through the file streams. ** ======================================================= */ #if !defined(lua_popen) /* { */ #if defined(LUA_USE_POPEN) /* { */ #define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) #define lua_pclose(L,file) ((void)L, pclose(file)) #elif defined(LUA_WIN) /* }{ */ #define lua_popen(L,c,m) ((void)L, _popen(c,m)) #define lua_pclose(L,file) ((void)L, _pclose(file)) #else /* }{ */ #define lua_popen(L,c,m) ((void)((void)c, m), \ luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) #define lua_pclose(L,file) ((void)((void)L, file), -1) #endif /* } */ #endif /* } */ /* }====================================================== */ /* ** {====================================================== ** lua_fseek: configuration for longer offsets ** ======================================================= */ #if !defined(lua_fseek) && !defined(LUA_ANSI) /* { */ #if defined(LUA_USE_POSIX) /* { */ #define l_fseek(f,o,w) fseeko(f,o,w) #define l_ftell(f) ftello(f) #define l_seeknum off_t #elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \ && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ /* Windows (but not DDK) and Visual C++ 2005 or higher */ #define l_fseek(f,o,w) _fseeki64(f,o,w) #define l_ftell(f) _ftelli64(f) #define l_seeknum __int64 #endif /* } */ #endif /* } */ #if !defined(l_fseek) /* default definitions */ #define l_fseek(f,o,w) fseek(f,o,w) #define l_ftell(f) ftell(f) #define l_seeknum long #endif /* }====================================================== */ #define IO_PREFIX "_IO_" #define IO_INPUT (IO_PREFIX "input") #define IO_OUTPUT (IO_PREFIX "output") typedef luaL_Stream LStream; #define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) #define isclosed(p) ((p)->closef == NULL) static int io_type (lua_State *L) { LStream *p; luaL_checkany(L, 1); p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); if (p == NULL) lua_pushnil(L); /* not a file */ else if (isclosed(p)) lua_pushliteral(L, "closed file"); else lua_pushliteral(L, "file"); return 1; } static int f_tostring (lua_State *L) { LStream *p = tolstream(L); if (isclosed(p)) lua_pushliteral(L, "file (closed)"); else lua_pushfstring(L, "file (%p)", p->f); return 1; } static FILE *tofile (lua_State *L) { LStream *p = tolstream(L); if (isclosed(p)) luaL_error(L, "attempt to use a closed file"); lua_assert(p->f); return p->f; } /* ** When creating file handles, always creates a `closed' file handle ** before opening the actual file; so, if there is a memory error, the ** file is not left opened. */ static LStream *newprefile (lua_State *L) { LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); p->closef = NULL; /* mark file handle as 'closed' */ luaL_setmetatable(L, LUA_FILEHANDLE); return p; } static int aux_close (lua_State *L) { LStream *p = tolstream(L); lua_CFunction cf = p->closef; p->closef = NULL; /* mark stream as closed */ return (*cf)(L); /* close it */ } static int io_close (lua_State *L) { if (lua_isnone(L, 1)) /* no argument? */ lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ tofile(L); /* make sure argument is an open stream */ return aux_close(L); } static int f_gc (lua_State *L) { LStream *p = tolstream(L); if (!isclosed(p) && p->f != NULL) aux_close(L); /* ignore closed and incompletely open files */ return 0; } /* ** function to close regular files */ static int io_fclose (lua_State *L) { LStream *p = tolstream(L); int res = fclose(p->f); return luaL_fileresult(L, (res == 0), NULL); } static LStream *newfile (lua_State *L) { LStream *p = newprefile(L); p->f = NULL; p->closef = &io_fclose; return p; } static void opencheck (lua_State *L, const char *fname, const char *mode) { LStream *p = newfile(L); p->f = fopen(fname, mode); if (p->f == NULL) luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno)); } static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newfile(L); const char *md = mode; /* to traverse/check mode */ luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode"); p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } /* ** function to close 'popen' files */ static int io_pclose (lua_State *L) { LStream *p = tolstream(L); return luaL_execresult(L, lua_pclose(L, p->f)); } static int io_popen (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newprefile(L); p->f = lua_popen(L, filename, mode); p->closef = &io_pclose; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } static int io_tmpfile (lua_State *L) { LStream *p = newfile(L); p->f = tmpfile(); return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; } static FILE *getiofile (lua_State *L, const char *findex) { LStream *p; lua_getfield(L, LUA_REGISTRYINDEX, findex); p = (LStream *)lua_touserdata(L, -1); if (isclosed(p)) luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX)); return p->f; } static int g_iofile (lua_State *L, const char *f, const char *mode) { if (!lua_isnoneornil(L, 1)) { const char *filename = lua_tostring(L, 1); if (filename) opencheck(L, filename, mode); else { tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } lua_setfield(L, LUA_REGISTRYINDEX, f); } /* return current value */ lua_getfield(L, LUA_REGISTRYINDEX, f); return 1; } static int io_input (lua_State *L) { return g_iofile(L, IO_INPUT, "r"); } static int io_output (lua_State *L) { return g_iofile(L, IO_OUTPUT, "w"); } static int io_readline (lua_State *L); static void aux_lines (lua_State *L, int toclose) { int i; int n = lua_gettop(L) - 1; /* number of arguments to read */ /* ensure that arguments will fit here and into 'io_readline' stack */ luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options"); lua_pushvalue(L, 1); /* file handle */ lua_pushinteger(L, n); /* number of arguments to read */ lua_pushboolean(L, toclose); /* close/not close file when finished */ for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1); /* copy arguments */ lua_pushcclosure(L, io_readline, 3 + n); } static int f_lines (lua_State *L) { tofile(L); /* check that it's a valid file handle */ aux_lines(L, 0); return 1; } static int io_lines (lua_State *L) { int toclose; if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ if (lua_isnil(L, 1)) { /* no file name? */ lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ lua_replace(L, 1); /* put it at index 1 */ tofile(L); /* check that it's a valid file handle */ toclose = 0; /* do not close it after iteration */ } else { /* open a new file */ const char *filename = luaL_checkstring(L, 1); opencheck(L, filename, "r"); lua_replace(L, 1); /* put file at index 1 */ toclose = 1; /* close it after iteration */ } aux_lines(L, toclose); return 1; } /* ** {====================================================== ** READ ** ======================================================= */ static int read_number (lua_State *L, FILE *f) { lua_Number d; if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { lua_pushnumber(L, d); return 1; } else { lua_pushnil(L); /* "result" to be removed */ return 0; /* read fails */ } } static int test_eof (lua_State *L, FILE *f) { int c = getc(f); ungetc(c, f); lua_pushlstring(L, NULL, 0); return (c != EOF); } static int read_line (lua_State *L, FILE *f, int chop) { luaL_Buffer b; luaL_buffinit(L, &b); for (;;) { size_t l; char *p = luaL_prepbuffer(&b); if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ luaL_pushresult(&b); /* close buffer */ return (lua_rawlen(L, -1) > 0); /* check whether read something */ } l = strlen(p); if (l == 0 || p[l-1] != '\n') luaL_addsize(&b, l); else { luaL_addsize(&b, l - chop); /* chop 'eol' if needed */ luaL_pushresult(&b); /* close buffer */ return 1; /* read at least an `eol' */ } } } #define MAX_SIZE_T (~(size_t)0) static void read_all (lua_State *L, FILE *f) { size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */ luaL_Buffer b; luaL_buffinit(L, &b); for (;;) { char *p = luaL_prepbuffsize(&b, rlen); size_t nr = fread(p, sizeof(char), rlen, f); luaL_addsize(&b, nr); if (nr < rlen) break; /* eof? */ else if (rlen <= (MAX_SIZE_T / 4)) /* avoid buffers too large */ rlen *= 2; /* double buffer size at each iteration */ } luaL_pushresult(&b); /* close buffer */ } static int read_chars (lua_State *L, FILE *f, size_t n) { size_t nr; /* number of chars actually read */ char *p; luaL_Buffer b; luaL_buffinit(L, &b); p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ luaL_addsize(&b, nr); luaL_pushresult(&b); /* close buffer */ return (nr > 0); /* true iff read something */ } static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int success; int n; clearerr(f); if (nargs == 0) { /* no arguments? */ success = read_line(L, f, 1); n = first+1; /* to return 1 result */ } else { /* ensure stack space for all results and for auxlib's buffer */ luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { size_t l = (size_t)lua_tointeger(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { const char *p = lua_tostring(L, n); luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); switch (p[1]) { case 'n': /* number */ success = read_number(L, f); break; case 'l': /* line */ success = read_line(L, f, 1); break; case 'L': /* line with end-of-line */ success = read_line(L, f, 0); break; case 'a': /* file */ read_all(L, f); /* read entire file */ success = 1; /* always success */ break; default: return luaL_argerror(L, n, "invalid format"); } } } } if (ferror(f)) return luaL_fileresult(L, 0, NULL); if (!success) { lua_pop(L, 1); /* remove last result */ lua_pushnil(L); /* push nil instead */ } return n - first; } static int io_read (lua_State *L) { return g_read(L, getiofile(L, IO_INPUT), 1); } static int f_read (lua_State *L) { return g_read(L, tofile(L), 2); } static int io_readline (lua_State *L) { LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); int i; int n = (int)lua_tointeger(L, lua_upvalueindex(2)); if (isclosed(p)) /* file is already closed? */ return luaL_error(L, "file is already closed"); lua_settop(L , 1); for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ lua_pushvalue(L, lua_upvalueindex(3 + i)); n = g_read(L, p->f, 2); /* 'n' is number of results */ lua_assert(n > 0); /* should return at least a nil */ if (!lua_isnil(L, -n)) /* read at least one value? */ return n; /* return them */ else { /* first result is nil: EOF or error */ if (n > 1) { /* is there error information? */ /* 2nd result is error message */ return luaL_error(L, "%s", lua_tostring(L, -n + 1)); } if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(1)); aux_close(L); /* close it */ } return 0; } } /* }====================================================== */ static int g_write (lua_State *L, FILE *f, int arg) { int nargs = lua_gettop(L) - arg; int status = 1; for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ status = status && fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; } else { size_t l; const char *s = luaL_checklstring(L, arg, &l); status = status && (fwrite(s, sizeof(char), l, f) == l); } } if (status) return 1; /* file handle already on stack top */ else return luaL_fileresult(L, status, NULL); } static int io_write (lua_State *L) { return g_write(L, getiofile(L, IO_OUTPUT), 1); } static int f_write (lua_State *L) { FILE *f = tofile(L); lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ return g_write(L, f, 2); } static int f_seek (lua_State *L) { static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, "cur", modenames); lua_Number p3 = luaL_optnumber(L, 3, 0); l_seeknum offset = (l_seeknum)p3; luaL_argcheck(L, (lua_Number)offset == p3, 3, "not an integer in proper range"); op = l_fseek(f, offset, mode[op]); if (op) return luaL_fileresult(L, 0, NULL); /* error */ else { lua_pushnumber(L, (lua_Number)l_ftell(f)); return 1; } } static int f_setvbuf (lua_State *L) { static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; static const char *const modenames[] = {"no", "full", "line", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, NULL, modenames); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); int res = setvbuf(f, NULL, mode[op], sz); return luaL_fileresult(L, res == 0, NULL); } static int io_flush (lua_State *L) { return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); } static int f_flush (lua_State *L) { return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); } /* ** functions for 'io' library */ static const luaL_Reg iolib[] = { {"close", io_close}, {"flush", io_flush}, {"input", io_input}, {"lines", io_lines}, {"open", io_open}, {"output", io_output}, {"popen", io_popen}, {"read", io_read}, {"tmpfile", io_tmpfile}, {"type", io_type}, {"write", io_write}, {NULL, NULL} }; /* ** methods for file handles */ static const luaL_Reg flib[] = { {"close", io_close}, {"flush", f_flush}, {"lines", f_lines}, {"read", f_read}, {"seek", f_seek}, {"setvbuf", f_setvbuf}, {"write", f_write}, {"__gc", f_gc}, {"__tostring", f_tostring}, {NULL, NULL} }; static void createmeta (lua_State *L) { luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ lua_pushvalue(L, -1); /* push metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ lua_pop(L, 1); /* pop new metatable */ } /* ** function to (not) close the standard files stdin, stdout, and stderr */ static int io_noclose (lua_State *L) { LStream *p = tolstream(L); p->closef = &io_noclose; /* keep file opened */ lua_pushnil(L); lua_pushliteral(L, "cannot close standard file"); return 2; } static void createstdfile (lua_State *L, FILE *f, const char *k, const char *fname) { LStream *p = newprefile(L); p->f = f; p->closef = &io_noclose; if (k != NULL) { lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ } lua_setfield(L, -2, fname); /* add file to module */ } LUAMOD_API int luaopen_io (lua_State *L) { luaL_newlib(L, iolib); /* new module */ createmeta(L); /* create (and set) default files */ createstdfile(L, stdin, IO_INPUT, "stdin"); createstdfile(L, stdout, IO_OUTPUT, "stdout"); createstdfile(L, stderr, NULL, "stderr"); return 1; } blobby-1.0/data/scripts/old/com_04d.lua000644 001750 001750 00000007623 12313310254 022523 0ustar00danielknobedanielknobe000000 000000 -- Flags und runners wait = 0 naechsterBallSchmettern = true -- evtl Variablennamen wechseln angriffsstaerke = 50 -- versetzung zum Ball je grsser desto tiefer fliegt der Service 0-64( 64 ist ca CONST_BALLRADIUS + CONST_BLOBBY_BAUCH_RADIUS) angriffsstaerkeNeuBerechnen =false -- neuberechnung von angriffsstaerke => Variable Angriffe -- Konstanten CONST_FELD_LAENGE = 800 CONST_BALL_RADIUS = 31.5 CONST_GROUND_PLANE = 100 CONST_MITTE = CONST_FELD_LAENGE/2 CONST_RECHTER_RAND = CONST_FELD_LAENGE - CONST_BALL_RADIUS CONST_BLOBBY_HOEHE = 89 CONST_BLOBBY_KOPF_RADIUS = 25 CONST_BLOBBY_BAUCH_RADIUS = 33 CONST_BLOBBY_KOPF_BERUEHRUNG = CONST_GROUND_PLANE + CONST_BLOBBY_HOEHE + CONST_BALL_RADIUS CONST_NETZ_RADIUS = 7 CONST_NETZ_HOEHE = 157 -- Linke Berhrungsebene des Balls falls er ans Netz kommt CONST_NETZ_LINKS = CONST_MITTE - CONST_NETZ_RADIUS - CONST_BALL_RADIUS function OnOpponentServe() moveto(120) generatenaechsterBallSchmettern() -- der gegner soll den smash ja nicht vorhersagen knnen end function OnServe(ballready) moveto(ballx()) wait = wait + 1 naechsterBallSchmettern = true if ballready then if wait > 90 then jump() wait = 0 end end end function OnGame() naechsterBallSchmetternFlagTesten() -- schaut ob der bot angreifen soll oder nicht target = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_KOPF_BERUEHRUNG) if target > 440 then moveto(120) else if naechsterBallSchmettern then sprungattacke(angriffsstaerke) return end -- nun kmmern wir uns um die Blle die ans netz prallen if ((target > CONST_NETZ_LINKS) and (ballx() < CONST_NETZ_LINKS)) then netzappraller(target) return end moveto(target) end end function netzappraller(p_target) moveto(CONST_NETZ_LINKS - (p_target - CONST_NETZ_LINKS) + math.abs(bspeedx()*bspeedx()*1.4)) end function sprungattacke(p_angriffsstaerke) moveto(ballx()-p_angriffsstaerke) -- Bei der Sprungatacke wird die Strke des gewnschten schlages angegeben if bally() < 580 then jump() end end function naechsterBallSchmetternFlagTesten() if (touches() == 3) then -- falls der Bot einen Anschlag Findet der Direckt punktet so wird der Wer nicht neu berechnet da er dann nciht auf 3 Berhrungen kommt naechsterBallSchmettern = false angriffsstaerkeNeuBerechnen = true -- da wrde es sicher auch einen Inteligenteren Test geben. return end if (angriffsstaerkeNeuBerechnen == true) then generatenaechsterBallSchmettern() end if (ballx() > CONST_MITTE) then -- wenn der ball auf der Anderen Seite ist soll der bot nicht naechsterBallSchmettern sein naechsterBallSchmettern = false return end if (touches() == 2) then -- nach der 2. Berhrung angreifen if (bally() > 500) then -- erst wenn der Ball hoeher als 500 fliegt sonst gibt es keinen schnen Schmetterball. naechsterBallSchmettern = true end return end if ((ballx() < (400-CONST_BALL_RADIUS)) and (bally() < 200) and (math.abs(bspeedx()) < 40)) then -- der ball knnte noch drber fliegen ** noch optimieren naechsterBallSchmettern = true return end end function generatenaechsterBallSchmettern() angriffsstaerkeNeuBerechnen = false; angriffsstaerke = math.random(20,55) -- variiert mit der Angriffsstrke also auch mit den Anschlgen end function estimImpact(bx,by,vbx,vby,destY) -- erlaubt ein besseres Estimate mit ein paar umbeding ntigen Angaben bgrav = 0.28 time1 =(-vby-math.sqrt((vby^2)-(-2*bgrav*(by-destY))))/(-bgrav) resultX = (vbx * time1) + bx if(resultX < CONST_BALL_RADIUS) then -- korrigieren der Appraller an der Hinteren Ebene resultX = math.abs(CONST_BALL_RADIUS - resultX) + CONST_BALL_RADIUS end if(resultX > CONST_RECHTER_RAND) then -- Korrigieren der Appraller an der Rechten Ebene resultX = CONST_FELD_LAENGE - (resultX - CONST_FELD_LAENGE) end return resultX end function cleanMoveTo(position) -- eine nette Spielerei ;) if (posx() ~= position) then moveto(position) end end blobby-1.0/src/state/LocalGameState.h000644 001750 001750 00000002620 12313310253 022311 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "GameState.h" #include class ReplayRecorder; /*! \class LocalGameState \brief state for singleplayer game */ class LocalGameState : public GameState { public: LocalGameState(); virtual ~LocalGameState(); // implementation of the State Interface virtual void step_impl(); virtual const char* getStateName() const; private: bool mWinner; boost::scoped_ptr mRecorder; }; blobby-1.0/data/rules/jumping_jack.lua000644 001750 001750 00000000225 12313310254 022613 0ustar00danielknobedanielknobe000000 000000 __AUTHOR__ = "chameleon" __TITLE__ = "Crazy Volley - Jumping Jack" function HandleInput(player, left, right, up) return left, right, true end blobby-1.0/data/gfx/font33.bmp000644 001750 001750 00000003370 12313310254 020721 0ustar00danielknobedanielknobe000000 000000 BM6( "+'"7#)-. !:&+j,(e(9]</!,3"))&$20?bE7  ?  )*(%CF$h)58 K  '~)::$>' [bkl,* ^  *Z/,'=gD_}g>;  h   56A[C݄QO s & n  -,#)%ԋWT   / &_*!'$~΂VS 8f"  #&  +7.}VU ,!"($w~KJ  Q% *&Za33 ( IV%'$Z6[Xy.8;IsYar#-  .\Rh.k@o rgz. o!"w||#w-+Oi$Y 2L"wny'12q9Z % C/M@}+uBc #include "InputSource.h" #include "LagDetectionSystem.h" #include #include "CrossCorrelation.h" #include #include #include #include #include #include #include #include #include using namespace boost::accumulators; PlayerInput randomInputGen() { return PlayerInput( rand() % 2, rand() % 2, rand() % 2); } PlayerInput randomInput(int p = 1) { static PlayerInput last = randomInputGen(); if(rand() % p == 0) { last = randomInputGen(); } return last; } /// \todo add parameters: lag, packet loss, input randomness struct LaggingNetworkInputSimulator { LaggingNetworkInputSimulator(int p) { lag_simulator.resize(p + 1); srand(5011); } void sendInput( PlayerInput ip) { lag_simulator.push_back(ip); } void changePing(int p) { lag_simulator.set_capacity(p + 1); // we must ensure that this is full, otherwise // back and front do not work as expected? while(!lag_simulator.full()) { lag_simulator.push_front(getRemote()); } } PlayerInput getLocal() const { return lag_simulator.back(); } PlayerInput getRemote() const { return lag_simulator.front(); } private: boost::circular_buffer lag_simulator; }; /// Fixture for creating a LagDetector struct LagDetectionSetup { LagDetectionSetup() : D (LagDetector()), NetworkSimulator(LaggingNetworkInputSimulator( 0 )) { } LagDetectionSetup(int l) : D (LagDetector()), NetworkSimulator(LaggingNetworkInputSimulator( l )) { } ~LagDetectionSetup() { }; void reset_simulator(int l) { *this = LagDetectionSetup(l); } void simulate( int steps = 1, int p = 1) { for(int i = 0; i < steps; ++i) { PlayerInput ip = randomInput(p); NetworkSimulator.sendInput(ip); D.insertData(NetworkSimulator.getLocal(), NetworkSimulator.getRemote()); } } LagDetector D; LaggingNetworkInputSimulator NetworkSimulator; }; // ------------------------------------------------------------------------------------------------- // // T E S T S // // ------------------------------------------------------------------------------------------------- /// file which logs additional debug data std::fstream file ("debug.txt", std::fstream::out); /// file which logs quality data std::fstream result ("results.txt", std::fstream::out); /// how many steps do we simulate each test const int SIMULATION_DURATION = 500; /// \todo add a test which looks how good the algorithm performs on periodic data BOOST_AUTO_TEST_SUITE( lag_detector ) // correlation BOOST_AUTO_TEST_CASE( self_correlation ) { boost::circular_buffer buf; buf.resize(100); // insert zero lag data for(int i=0; i < 100; ++i) { PlayerInput ip = randomInput(); buf.push_back(ip); } int t = crossCorrelation(buf, buf).offset; BOOST_REQUIRE(t == 0); } // test that checks wether LagDetector finds zero lag when no lag is present BOOST_FIXTURE_TEST_CASE( zero_lag, LagDetectionSetup ) { // insert zero lag data simulate(10); // now we do 50 steps and check for lag for(int i = 0; i < SIMULATION_DURATION; ++i) { simulate(); int lag = D.getLag(); if( lag != 0 ) { char errormsg[1024]; sprintf(errormsg, "lag of %d detected when simulating zero lag", lag); BOOST_FAIL(""); }; } } // test that checks wether LagDetector finds constant lags /// \todo use http://www.boost.org/doc/libs/1_48_0/libs/test/doc/html/utf/user-guide/test-organization/unary-test-case.html BOOST_FIXTURE_TEST_CASE( constant_lag, LagDetectionSetup ) { file << "\nconstant lag" << "\n"; // test for all small constant lags for(int clag = 1; clag < 10; clag++) { reset_simulator(clag); simulate(25); // now we do 50 steps and check for lag for(int i = 0; i < SIMULATION_DURATION; ++i) { simulate(); int lag = D.getLag(); if( lag != clag ) { file << D.getDebugString() << "\n"; char errormsg[1024]; sprintf(errormsg, "detected lag of %d when constant lag of %d was simulated", lag, clag); BOOST_FAIL(errormsg); }; } } } // CONFIGURE: const int REAL_INPUT_PATTERN_LENGTH = 40; const int INPUT_CHANGE_STEP_WIDTH = 5; // check constant lag with bad input data BOOST_FIXTURE_TEST_CASE( constant_lag_real_input, LagDetectionSetup ) { file << "\nconstant lag - real input" << "\n"; result << "constant lag - real input\n"; result << "In\tF%\tsig\n"; for(int input_quality = 10; input_quality <= REAL_INPUT_PATTERN_LENGTH; input_quality += INPUT_CHANGE_STEP_WIDTH ) { // determine a random lag and set up the simulation int clag = rand() % 4 + 4; reset_simulator(clag); // start simulate(25, input_quality); // now we do 500 steps and check for lag int errors = 0; int cum_err = 0; for(int i = 0; i < SIMULATION_DURATION; ++i) { simulate(1, input_quality); int lag = D.getLag(); // if( lag != clag ) { file << D.getDebugString() << "\n"; errors++; cum_err += (lag - clag) * (lag - clag); }; } result << input_quality << ",\t" << (int)((100.f * errors / SIMULATION_DURATION)) << ",\t" << std::sqrt(cum_err / (float)SIMULATION_DURATION) << "\n"; // we consider this test failed if more than 20% of our results are incorrect if(errors / (float)SIMULATION_DURATION > 0.2) { char errormsg[1024]; sprintf(errormsg, "realisitc input and constant lag: %d %% not correct", (int)(100.f * errors / SIMULATION_DURATION) ); BOOST_ERROR(errormsg); } } } const int LAG_CHANGE_RATE = 10; // test with high quality data but changing lags // in this test, we can see how fast die algorithm can detect changing lag // in this test, the lag changes are only slight, so more than 1frame per change // does not happen BOOST_FIXTURE_TEST_CASE( changing_lag, LagDetectionSetup ) { file << "\nchanging lag - real input" << "\n"; result << "changing lag - real input - small change\n"; // test for all small constant lags int clag = rand() % 8 + 4; NetworkSimulator.changePing(clag); // start a game simulate(100); // accumulator for collecting statistical data of our run accumulator_set< int, features< tag::count, tag::max, tag::mean, tag::mean_of_variates > > acc; int lag = 0; int errors = 0; int timer = 0; int cum_timer = 0; // now we do 500 steps and check for lag for(int i = 0; i < 500; ++i) { // randomly change lags. we are friendly for now. // only change lag after system has adapted to new lag if(rand() % LAG_CHANGE_RATE == 0 && clag == lag) { int nclag = (rand() % 2) * 2 - 1 + clag; nclag = std::max(5, std::min(15, nclag)); clag = nclag; NetworkSimulator.changePing(clag); timer = 0; } simulate(); lag = D.getLag(); if( lag != clag ) { errors++; timer++; } else if(timer != 0) { result << "took " << timer << " steps to recognice lag of "<< lag << std::endl; file << lag << " " << timer << "\n" << D.getDebugString() << "\n"; // calculate cum timer cum_timer += timer; acc(std::max(0, timer - lag), covariate1 = timer); timer = 0; } } // when we take longer than 10ms to detect the lag change after the first packet with new lag arrived // we are too slow. // when we take longer than 15ms once, it is bad, too if( mean(acc) > 5 || max(acc) > 15) { char errormsg[1024]; sprintf(errormsg, "LagDetector takes too long to detect lag change of 1ms. Add: %d, Avg: %d, Max: %d", (int)mean(acc), (int)boost::accumulators::mean_of_variates(acc), max(acc)); BOOST_ERROR(errormsg); } result << "maximum reaction time: " << max(acc) << std::endl; result << "average reaction time: " << boost::accumulators::mean_of_variates(acc) << std::endl; result << "average additional reaction time: " << mean(acc) << std::endl; } // test with high quality data but changing lags // in this test, we can see how fast die algorithm can detect changing lag // in this test, the lag changes are only slight, so more than 1frame per change // does not happen BOOST_FIXTURE_TEST_CASE( changing_lag_real, LagDetectionSetup ) { file << "\nchanging lag - good input" << "\n"; result << "changing lag - good input - small change\n"; for(int input_quality = 10; input_quality <= REAL_INPUT_PATTERN_LENGTH; input_quality += INPUT_CHANGE_STEP_WIDTH ) { result << "data quality: " << input_quality << std::endl; // test for all small constant lags int clag = rand() % 8 + 4; NetworkSimulator.changePing(clag); // start a game simulate(100, input_quality); // accumulator for collecting statistical data of our run accumulator_set< int, features< tag::count, tag::max, tag::mean, tag::mean_of_variates > > acc; int lag = 0; int errors = 0; int timer = 0; int cum_timer = 0; // now we do 500 steps and check for lag for(int i = 0; i < 500; ++i) { // randomly change lags. we are friendly for now. // only change lag after system has adapted to new lag if(rand() % LAG_CHANGE_RATE == 0 && clag == lag) { int nclag = (rand() % 2) * 2 - 1 + clag; nclag = std::max(5, std::min(15, nclag)); clag = nclag; NetworkSimulator.changePing(clag); timer = 0; } simulate(1, input_quality); lag = D.getLag(); if( lag != clag ) { errors++; timer++; } else if(timer != 0) { // don't do any reporting here, as we would get too much messags // result << "took " << timer << " steps to recognice lag of "<< lag << std::endl; // file << lag << " " << timer << "\n" << D.getDebugString() << "\n"; // calculate cum timer cum_timer += timer; acc(std::max(0, timer - lag), covariate1 = timer); timer = 0; } } // when we take longer than 10ms to detect the lag change after the first packet with new lag arrived // we are too slow. // when we take longer than 15ms once, it is bad, too if( mean(acc) > 10 || max(acc) > 25) { char errormsg[1024]; sprintf(errormsg, "LagDetector takes too long to detect lag change of 1ms. Add: %d, Avg: %d, Max: %d", (int)mean(acc), (int)boost::accumulators::mean_of_variates(acc), max(acc)); BOOST_ERROR(errormsg); } result << "maximum reaction time: " << max(acc) << std::endl; result << "average reaction time: " << boost::accumulators::mean_of_variates(acc) << std::endl; result << "average additional reaction time: " << mean(acc) << std::endl; } } BOOST_AUTO_TEST_SUITE_END() blobby-1.0/data/gfx/pfeil_rechts.bmp000644 001750 001750 00000003226 12313310254 022254 0ustar00danielknobedanielknobe000000 000000 BM6(`  u00ZZd,,ZuH5LLLtyd5* 0,ttdH  00td5**0ZdV5 $&GE\Z\ZZuyH*  GEvuuyH5*  GEvuyH5 GEvu)V5* GEvu..).*d5  GEvu.).*d*  GEvu$&vu\Zvu$&GEblobby-1.0/src/PhysicState.h000644 001750 001750 00000002575 12313310251 020613 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "Global.h" #include "Vector.h" #include "GenericIOFwd.h" namespace RakNet { class BitStream; } struct PhysicState { Vector2 blobPosition[MAX_PLAYERS]; Vector2 blobVelocity[MAX_PLAYERS]; Vector2 ballPosition; Vector2 ballVelocity; float ballAngularVelocity; // equality comparision bool operator==(const PhysicState& other) const; void swapSides(); }; blobby-1.0/src/GameLogic.h000644 001750 001750 00000017032 12313310253 020176 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include #include "Global.h" #include "Clock.h" #include "BlobbyDebug.h" class IGameLogic; /// typedef to make GameLogic an auto_ptr /// \todo is auto_ptr the best choice here? typedef std::auto_ptr GameLogic; struct GameLogicState; class DuelMatch; struct PlayerInput; /// \class IGameLogic /// \brief Interface for managing game rules, score counting etc. /// \details this class is told what happens in the game and it applies the rules to count /// the points. it is designed as a abstract base class to provide different /// implementations (ie old/new volleyball rules) class IGameLogic: public ObjectCounter { public: // constuctor and destructor IGameLogic(); virtual ~IGameLogic(); virtual GameLogic clone() const = 0; virtual std::string getSourceFile() const = 0; // ----------------------------------------------------------------------------------------- // Read/Write Basic Data // ----------------------------------------------------------------------------------------- // methods for querying the score/touches of a patricular team /// returns hits count of the specified player int getTouches(PlayerSide side) const; /// returns current points of one player int getScore(PlayerSide side) const; /// sets the score of the specified player void setScore(PlayerSide side, int score); // when might need such a method if we add saved games // method for querying and setting the serving player /// returns which player is the serving player PlayerSide getServingPlayer() const; /// sets which player is currently the serving player void setServingPlayer(PlayerSide side); /// returns the winning player or NO_PLAYER if the /// game still runs PlayerSide getWinningPlayer() const; /// \brief returns which player made the last mistake. /// After this request, that value is reset. PlayerSide getLastErrorSide(); // method for getting the target score /// returns the score required for winning. int getScoreToWin() const; /// gets the associated clock Clock& getClock(); /// transform input PlayerInput transformInput(PlayerInput ip, PlayerSide player); // ----------------------------------------------------------------------------------------- // Read / Write - State // ----------------------------------------------------------------------------------------- GameLogicState getState() const; void setState(GameLogicState gls); // ----------------------------------------------------------------------------------------- // Event - Handlers // ----------------------------------------------------------------------------------------- // methods to inform the game logic what is happening in the game /// called when the serve begins void onServe(); /// called when ball hits ground void onBallHitsGround(PlayerSide side); /// called when ball hits player void onBallHitsPlayer(PlayerSide side); /// called when ball hits wall void onBallHitsWall(PlayerSide side); /// called when ball hits net void onBallHitsNet(PlayerSide side); /// returns whether ball is valid. The timespan between making a mistake and resetting the ball, /// it is not considered valid, which means no collisions with blobs are calculated. bool isBallValid() const; /// returns whether game is running bool isGameRunning() const; /// returns whether the collision was valid (not squished) bool isCollisionValid(PlayerSide side) const; bool isWallCollisionValid() const; bool isGroundCollisionValid() const; // set/unset pause mode /// pauses the game logic. void onPause(); /// disables pause mode void onUnPause(); /// must be called every step void step(); // script information virtual std::string getAuthor() const = 0; virtual std::string getTitle() const = 0; protected: /// this method must be called if a team scores /// it increments the points of that team void score(PlayerSide side, int amount); // helper functions /// convert player side into array index static inline int side2index(PlayerSide side) { return side == NO_PLAYER ? MAX_PLAYERS : side - LEFT_PLAYER; } /// determine the opposite player side static inline PlayerSide other_side(PlayerSide side) { switch(side) { case LEFT_PLAYER: return RIGHT_PLAYER; case RIGHT_PLAYER: return LEFT_PLAYER; default: assert(0); } } /// this is called when a player makes a mistake void onError(PlayerSide errorSide, PlayerSide serveSide); /// thi function can change input made by a player virtual PlayerInput handleInput(PlayerInput ip, PlayerSide player) = 0; /// this function handles ball/player hits virtual void OnBallHitsPlayerHandler(PlayerSide side) = 0; /// this function handles ball/wall hits virtual void OnBallHitsWallHandler(PlayerSide side) = 0; /// this function handles ball/ground hits virtual void OnBallHitsGroundHandler(PlayerSide side) = 0; /// this function handles ball/net hits virtual void OnBallHitsNetHandler(PlayerSide side) = 0; /// this function gets called every frame virtual void OnGameHandler() = 0; /// this function checks whether a player has won the game virtual PlayerSide checkWin() const = 0; /// config parameter: score to win /// lua rules can change it by changing SCORE_TO_WIN variable in the global scope int mScoreToWin; private: // data members /// this array contains the scores int mScores[2]; /// in this array the touches are counted int mTouches[2]; /// these are helper arrays to prevent counting hits that happen too fast twice int mSquish[2]; int mSquishWall; // also for net squishes int mSquishGround; /// last side that made an error PlayerSide mLastError; /// player that is currently serving PlayerSide mServingPlayer; /// whether ball is touchable bool mIsBallValid; /// whether game is running (first ball hit was made) bool mIsGameRunning; /// player that has won the game /// \todo do we really need to cache this information here?? PlayerSide mWinningPlayer; /// clock for determining game time Clock clock; }; extern const std::string DUMMY_RULES_NAME; extern const std::string FALLBACK_RULES_NAME; // functions for creating a game logic object GameLogic createGameLogic(const std::string& rulefile, DuelMatch* match); blobby-1.0/src/ReplayRecorder.h000644 001750 001750 00000006605 12313310253 021275 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /// \file ReplayRecorder.h /// \brief contains replay recorder and associated enums #pragma once #include #include #include #include "Global.h" #include "ReplayDefs.h" #include "PlayerInput.h" #include "DuelMatchState.h" #include "BlobbyDebug.h" #include "GenericIOFwd.h" namespace RakNet { class BitStream; } class FileWrite; /*! \class VersionMismatchException \brief thrown when replays of incompatible version are loaded. */ struct VersionMismatchException : public std::exception, public ObjectCounter { VersionMismatchException(const std::string& filename, uint8_t major, uint8_t minor); ~VersionMismatchException() throw(); virtual const char* what() const throw(); std::string error; uint8_t major; uint8_t minor; }; /// \brief recording game /// \todo we safe replays in continuous storeage (array or std::vector) /// which might be ineffective for huge replays (1h ~ 270kb) class ReplayRecorder : public ObjectCounter { public: ReplayRecorder(); ~ReplayRecorder(); void save(boost::shared_ptr target) const; void send(boost::shared_ptr stream) const; void receive(boost::shared_ptrstream); // recording functions void record(const DuelMatchState& input); // saves the final score void finalize(unsigned int left, unsigned int right); // game setup setting void setPlayerNames(const std::string& left, const std::string& right); void setPlayerColors(Color left, Color right); void setGameSpeed(int fps); private: void writeFileHeader(boost::shared_ptr, uint32_t checksum) const; void writeReplayHeader(boost::shared_ptr) const; void writeAttributesSection(boost::shared_ptr) const; void writeJumpTable(boost::shared_ptr) const; void writeInputSection(boost::shared_ptr) const; void writeStatesSection(boost::shared_ptr) const; std::vector mSaveData; std::vector mSavePoints; // general replay attributes std::string mPlayerNames[MAX_PLAYERS]; Color mPlayerColors[MAX_PLAYERS]; unsigned int mEndScore[MAX_PLAYERS]; unsigned int mGameSpeed; // here we save the information needed to create the header // pointers to replay sections /// \todo this is ugly mutable uint32_t attr_ptr; mutable uint32_t jptb_ptr; mutable uint32_t data_ptr; mutable uint32_t states_ptr; }; blobby-1.0/data/rules/default.lua000644 001750 001750 00000005453 12313310254 021606 0ustar00danielknobedanielknobe000000 000000 -- most simple ruleset: for each mistake, the opponent gets a point -- includes comments for documentation purposes __AUTHOR__ = "Blobby Volley 2 Developers" __TITLE__ = "BV2 Default Rules" -- rules.lua doc -- function IsWinning -- IMPLEMENTED BY rules.lua -- called when it is determined whether a player has won -- params: lscore: score of left player -- rscore: score of right player -- return: whether a player has won function IsWinning(lscore, rscore) -- constant SCORE_TO_WIN: number of points for a player to win if lscore >= SCORE_TO_WIN and lscore >= rscore + 2 then return true end if rscore >= SCORE_TO_WIN and rscore >= lscore + 2 then return true end return false end -- function OnBallHitsPlayer -- IMPLEMENTEDBY rules.lua -- called when a valid collision between a player and the ball happens. -- params: player - the player that hit the ball -- return: none function OnBallHitsPlayer(player) -- function touches -- PREDEFINED -- param: player - player whos touches you want to get -- return: how many touches did player -- function opponent -- PREDEFINED -- param: player - player of whom you want to get the opponent -- return: opponent of the player, so, for LEFT_PLAYER, RIGHT_PLAYER is returned and vice-versa -- function mistake -- PREDEFINED -- params: mistakeSide - player who made a mistake -- serveSide - player who should make a serve -- amount - how many points opponent of mistakeSide gets -- return: none if touches(player) > 3 then mistake(player, opponent(player), 1) end end -- function OnBallHitsWall -- IMPLEMENTEDBY rules.lua -- called when a valid collision between the ball and a wall happens. -- params: player - the player on whos side the ball hit a wall -- return: none function OnBallHitsWall(player) end -- function OnBallHitsNet -- IMPLEMENTEDBY rules.lua -- called when a valid collision between the ball and a net happens. -- params: player - the player on whos side the ball hits a net (NO_PLAYER for net top) -- return: none function OnBallHitsNet(player) end -- function OnBallHitsGround -- IMPLEMENTEDBY rules.lua -- called when the ball hits the ground. -- params: player - the player on whos side the ball hits the ground -- return: none function OnBallHitsGround(player) mistake(player, opponent(player), 1) end -- function OnGame -- IMPLEMENTEDBY rules.lua -- called for every moment in the game. -- params: none -- return: none function OnGame() end -- function HandleInput -- IMPLEMENTEDBY rules.lua -- called to control player movement -- params: player - the player to check -- left, right, up - source user input -- return: new input values function HandleInput(player, left, right, up) return left, right, up end -- uncomment this to change number of points for a player to win -- SCORE_TO_WIN = 15 blobby-1.0/data/gfx/ball13.bmp000644 001750 001750 00000012066 12313310254 020665 0ustar00danielknobedanielknobe000000 000000 BM66(@@ gfi srtecegegyxyrqrpop[Z[ifhb_amkliefussgeePOOa``|yxYXWxwvgfd rrommkuutddc^^]_a_Z\ZWYWjljhjhz{znqobdc  '((eggvwwsttpqq\]]nopWXZ))*ZZ\jjleegttuccdaab~~~}}}xxxuuusssooonnnkkkiiihhhgggeeedddccc```___\\\ZZZXXXVVVSSSIII<<<111 ||A^"CC|W| WW|&&CBCl|C u7&&C펍<= |&||B A3yz{{2X|||CC(i!y!!{ |^^yzz^^3{獎 u &&2CQ%{^Q%/ጉ[=""|&&&|nh3A^ځPQZuCCwwOOOOnPhPQz{Ov-----5gO{^zCCꍎ|2.Ҁg5OOghؕ^/C&5O-44NN-.--OhP^3%^|C&whgN4mN-OO-ҀOPQ^^C|OgO-f$NQQ5ځ^B|lNMҀ-v-MP5MeϔN>ϔOOPCKKJ4ҀMLLLπOggԀ--OP{ ΓǒMLLLLLM$-O3|NLȒLJLMԀNfO^^l|edđLLӀϔ--y^&CK,]Icđ,MД-^QC&&C$,jHLNДf^P^2CHHoILMLДOQٕP^zV(|NcIHH,LMKLLДgٕ^ u"CJMH~HHLJLLϔgPP[CcJLdd~LLOhQ3傉 oH,,~~~LLL͔h5P%y{{[0½e~~KLLӀO.hQ/{<=,LJHLLLπOOyzN-g 6GGdKe>wnFbG~j,ȓ84$OhbG]]~dJ\Nw*HǐY#fE*G~LEE)E6HLEE+bj,LaxaE+++bÑE```pSc,J___EE d,6E_DD__`EF H~oEDDDDD__`F}?DDD__E'Rbb`? D_E* D_` R``_D DD_`*E `_D D_FEE D_EE `` _EaE`_DED __D D`_`D` D__ blobby-1.0/data/gfx/font25.bmp000644 001750 001750 00000003370 12313310254 020722 0ustar00danielknobedanielknobe000000 000000 BM6( :@_6A^'.=$banmJJg-0<  JE_ނqRGc% DZ|\E5NhTsȖۭma;kɔuރ>< Ag|@^'c  aEeK߅*%&!"}[$JKck.v| 1!2u@^c; =*)$ %  aX s vt xl n\^C E/ 0\9^pFҫ{~J J23  ad@./8Yvd<ܥ`c78 IqO6PP $$jg'eg88<$ň N:K΃ͧVk:kA&>\+[0"km44fjuQsB3@ ** 3)g i88 UvrodjDE@4;ó?H?}3L$L #|ksvphy`NUC Zlx|ʽvbyJyO4L0"-# <27`bXpglcbTOG>ђѝڮֲ̬˼|mphfr_h`qiyowhqW Iy1+" vfGa*'LFӴdT {ztskF8> Y2Lm3o"EB?|nO\B$sV ~U;qQ>4=%_uu7sK\cOxXA8e&. "ֈU}'N=!  yX@3$>pshq7HW, Oa=[@-#V<($pYG;_''" U6't ) Y5T+`5 5$="! G     dN"vc]EC( iDQ;4"VEE#N -W 6qvfD5 /Lr>awڇڑٖыXbBP   j`>-/"    zs.Ew/8 ^wN{nC8 N jyQOH 2YoOE u %`L1~-PAbT   qR`9+(V ,:"wfE;$b Ge6z_A"(#lwm3(-rlY398:-q`=ygdMGNgBHp9#1'1"O|G?w6/H!blobby-1.0/src/blobnet/CMakeLists.txt000644 001750 001750 00000000140 12313310251 022351 0ustar00danielknobedanielknobe000000 000000 set (blobnet_SRC layer/Http.cpp layer/Http.hpp ) add_library(blobnet STATIC ${blobnet_SRC}) blobby-1.0/ChangeLog000644 001750 001750 00000007453 12313310247 017172 0ustar00danielknobedanielknobe000000 000000 New in 1.0 (rev. 1516) since RC4: - small improvements to lua rules - smoother loading of server list - improved mouse input in online games - lots of tiny fixes New in 1.0 RC 4 (rev. 1345) since RC3: - Added Lobby - Added lua gamerules - Updated to SDL2 - some more code refactoring New in 1.0 RC 3 (rev. 1123) since RC 2: - Fixed ball rotation in onlinegame - Fixed switched player bug - Fixed missing colon in server info - Fixed broken play again button in replay player New in 1.0 RC 2 (rev. 1111) since RC 1: - Show waiting player in network game menu (currently not updated) - Load server list from blobby.sourceforge.net - Option to specify maximum clients in server.xml - Added replay info screen - Added italian translation - Optimized sending replays over network - New replay default names - Possibility to select server port to connect to (Thanks to Stefano Ansaloni) - Fix: CPU usage in network game menu - Fix: trying to save replays with invalid filename now issues an error message - Fix: writing over existing replays no longer possible - Fix: Ball speed - Fix: typos in translation - Fix: "two hit bug" (again ;) - Fix: server crash when server could not find server.xml - Fix: server did not delete temp replay files - Fix: file list properly freed in replay menu - some code refractoring - REPLAY PLAYER: - more information saved in replay files: final score - better jumping to replay positions - show replay info in replay menu New in 1.0 RC 1 (rev. 732) since Beta 9: * Features: - REPLAY PLAYER: still in development, features for now: - pausing - fast forwarding - jumping to certain positions in replay (may take some time new replay save file format, not fixed yet, so replays may become incompatible in the future - enabled writing in chat without clicking into editbox - Blobby speed more stable on slow systems (framedrop) - auto disconnect when game is closed - use native keyboard layout when possible - small physics improvements - mouse input for online games - join server with double click - improved chat UI - small gfx enhancements * Bugfixes: - Fix: severe network problem - Fix: "two hit bug" - Fix: wrong winning condition in default rules - Fix: online replays sometimes not saved - squished ball generates only one sound now - corrected version in server startup message - [Windows] fixed server output messages - [Windows] pointer no longer freezes when alt+tab * Performance: - fixed a major memory leak in dedicated server - removed possible lag due to rounding issues in speed controller - removed needless wait in network server (only 1 ms) - improved OpenGL performance significantly (10-30%) - fixed some small and unlikely memleaks - fixed performance killer in "... has won" screen New in Beta 9 (rev. 622) since Alpha 8: - network game: reduced data transfer - fixed memleaks - OGL: improved text rendering speed - SDL: improved render speed for morphing blobs - generally improved performance - limited FPS in menu - chat - clock - blood in SDL mode - bots sorted - online replays - improved bots: difficulty adjustable, better api, better documentation - customizable rules file New in Alpha 8 (rev. 469) since Alpha 6: - some graphics improvements - performance improvements - names - credits added New in Alpha 6 (rev. 335) since Alpha 5: - More options - Network support - Fixed Speedcontroller - Fixed ball reset Since Alpha 4: - Many options configurable through new GUI - Configurable game speed, with frame dropping for slow PCs - Sound volume option - Keyboard, mouse, Joystick and Gamepad can be used for input now - Further optimized physics by Fliegus123 (old replays won't work) - Many bugfixes for the scripting API, bots which rely on estimate/estimx/estimy now work much better - Special cooperation with the OpenAnno team: Sven Rech will work for Blobby until final release blobby-1.0/src/ReplayRecorder.cpp000644 001750 001750 00000022406 12313310251 021623 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "ReplayRecorder.h" /* includes */ #include #include #include #include #include #include "tinyxml/tinyxml.h" #include "raknet/BitStream.h" #include #include "Global.h" #include "IReplayLoader.h" #include "PhysicState.h" #include "GenericIO.h" #include "FileRead.h" #include "FileWrite.h" /* implementation */ ChecksumException::ChecksumException(std::string filename, uint32_t expected, uint32_t real) { std::stringstream errorstr; errorstr << "Error: Corrupted replay file: " << filename << std::endl << "real crc: " << real << " crc in file: " << expected; error = errorstr.str(); } ChecksumException::~ChecksumException() throw() { } const char* ChecksumException::what() const throw() { return error.c_str(); } VersionMismatchException::VersionMismatchException(const std::string& filename, uint8_t major, uint8_t minor) { std::stringstream errorstr; errorstr << "Error: Outdated replay file: " << filename << std::endl << "expected version: " << (int)REPLAY_FILE_VERSION_MAJOR << "." << (int)REPLAY_FILE_VERSION_MINOR << std::endl << "got: " << (int)major << "." << (int)minor << " instead!" << std::endl; error = errorstr.str(); } VersionMismatchException::~VersionMismatchException() throw() { } const char* VersionMismatchException::what() const throw() { return error.c_str(); } ReplayRecorder::ReplayRecorder() { mGameSpeed = -1; } ReplayRecorder::~ReplayRecorder() { } void ReplayRecorder::save( boost::shared_ptr file) const { boost::shared_ptr target = createGenericWriter(file); writeFileHeader(target, 0); uint32_t replayHeaderStart = target->tell(); writeReplayHeader(target); writeAttributesSection(target); writeJumpTable(target); writeInputSection(target); writeStatesSection(target); // the last thing we write is the header again, so // we can fill in all data we gathered during the // rest of the writing process target->seek(replayHeaderStart); writeReplayHeader(target); target->seek(0); FileRead checksum_calculator(file->getFileName()); /// \todo how can we make sure that we open the right file? uint32_t checksum = checksum_calculator.calcChecksum(replayHeaderStart); writeFileHeader(target, checksum); } void ReplayRecorder::send(boost::shared_ptr target) const { target->string(mPlayerNames[LEFT_PLAYER]); target->string(mPlayerNames[RIGHT_PLAYER]); target->generic (mPlayerColors[LEFT_PLAYER]); target->generic (mPlayerColors[RIGHT_PLAYER]); target->uint32( mGameSpeed ); target->uint32( mEndScore[LEFT_PLAYER] ); target->uint32( mEndScore[RIGHT_PLAYER] ); target->generic >(mSaveData); target->generic > (mSavePoints); } void ReplayRecorder::receive(boost::shared_ptr source) { source->string(mPlayerNames[LEFT_PLAYER]); source->string(mPlayerNames[RIGHT_PLAYER]); source->generic (mPlayerColors[LEFT_PLAYER]); source->generic (mPlayerColors[RIGHT_PLAYER]); source->uint32( mGameSpeed ); source->uint32( mEndScore[LEFT_PLAYER] ); source->uint32( mEndScore[RIGHT_PLAYER] ); source->generic >(mSaveData); source->generic > (mSavePoints); } void ReplayRecorder::writeFileHeader(boost::shared_ptr file, uint32_t checksum) const { file->array(validHeader, sizeof(validHeader)); // after the header, we write the replay version // first, write zero. leading zero indicates that the following value // really is a version number (and not a checksum of an older replay!) file->byte(0); file->byte(REPLAY_FILE_VERSION_MAJOR); file->byte(REPLAY_FILE_VERSION_MINOR); file->byte(0); file->uint32(checksum); } void ReplayRecorder::writeReplayHeader(boost::shared_ptr file) const { /// for now, this are fixed numbers /// we have to make sure they are right! uint32_t header_ptr = file->tell(); uint32_t header_size = 9*sizeof(header_ptr); uint32_t attr_size = 128; /// for now, we reserve 128 bytes! uint32_t jptb_size = 128; /// for now, we reserve 128 bytes! uint32_t data_size = mSaveData.size(); /// assumes 1 byte per data record! uint32_t states_size = mSavePoints.size() * sizeof(ReplaySavePoint); file->uint32(header_size); file->uint32(attr_ptr); file->uint32(attr_size); file->uint32(jptb_ptr); file->uint32(jptb_size); file->uint32(data_ptr); file->uint32(data_size); file->uint32(states_ptr); file->uint32(states_size); // check that we really needed header_size space assert( file->tell() - header_size ); } void ReplayRecorder::writeAttributesSection(boost::shared_ptr file) const { attr_ptr = file->tell(); // we have to check that we are at attr_ptr! char attr_header[4] = {'a', 't', 'r', '\n'}; uint32_t gamespeed = mGameSpeed; uint32_t gamelength = mSaveData.size(); /// \attention 1 byte = 1 step is assumed here uint32_t gameduration = gamelength / gamespeed; uint32_t gamedat = std::time(0); // check that we can really safe time in gamedat. ideally, we should use a static assertion here //static_assert (sizeof(uint32_t) >= sizeof(time_t), "time_t does not fit into 32bit" ); file->array(attr_header, sizeof(attr_header)); file->uint32(gamespeed); file->uint32(gameduration); file->uint32(gamelength); file->uint32(gamedat); // write blob colors file->generic(mPlayerColors[LEFT_PLAYER]); file->generic(mPlayerColors[RIGHT_PLAYER]); file->uint32( mEndScore[LEFT_PLAYER] ); file->uint32( mEndScore[RIGHT_PLAYER] ); // write names file->string(mPlayerNames[LEFT_PLAYER]); file->string(mPlayerNames[RIGHT_PLAYER]); // we need to check that we don't use more space than we got! // set up writing for next section. not good! file->seek(attr_ptr + 128); } void ReplayRecorder::writeJumpTable(boost::shared_ptr file) const { jptb_ptr = file->tell(); // we have to check that we are at attr_ptr! char jtbl_header[4] = {'j', 'p', 't', '\n'}; file->array(jtbl_header, sizeof(jtbl_header)); file->seek(jptb_ptr + 128); } void ReplayRecorder::writeInputSection(boost::shared_ptr file) const { data_ptr = file->tell(); // we have to check that we are at attr_ptr! char data_header[4] = {'i', 'p', 't', '\n'}; file->array(data_header, sizeof(data_header)); file->generic > (mSaveData); /// \todo why don't we zip it? even though it's quite compact, /// we still save a lot of redundant information. } void ReplayRecorder::writeStatesSection(boost::shared_ptr file) const { states_ptr = file->tell(); // we have to check that we are at attr_ptr! char states_header[4] = {'s', 't', 'a', '\n'}; file->array(states_header, sizeof(states_header)); file->generic > (mSavePoints); } void ReplayRecorder::record(const DuelMatchState& state) { // save the state every REPLAY_SAVEPOINT_PERIOD frames // or when something interesting occurs if(mSaveData.size() % REPLAY_SAVEPOINT_PERIOD == 0 || mEndScore[LEFT_PLAYER] != state.logicState.leftScore || mEndScore[RIGHT_PLAYER] != state.logicState.rightScore || state.errorSide != (unsigned char)NO_PLAYER) { ReplaySavePoint sp; sp.state = state; sp.step = mSaveData.size(); mSavePoints.push_back(sp); } // we save this 1 here just for compatibility // set highest bit to 1 unsigned char packet = 1 << 7; packet |= (state.playerInput[LEFT_PLAYER].getAll() & 7) << 3; packet |= (state.playerInput[RIGHT_PLAYER].getAll() & 7) ; mSaveData.push_back(packet); // update the score mEndScore[LEFT_PLAYER] = state.logicState.leftScore; mEndScore[RIGHT_PLAYER] = state.logicState.rightScore; } void ReplayRecorder::setPlayerNames(const std::string& left, const std::string& right) { mPlayerNames[LEFT_PLAYER] = left; mPlayerNames[RIGHT_PLAYER] = right; } void ReplayRecorder::setPlayerColors(Color left, Color right) { mPlayerColors[LEFT_PLAYER] = left; mPlayerColors[RIGHT_PLAYER] = right; } void ReplayRecorder::setGameSpeed(int fps) { mGameSpeed = fps; } void ReplayRecorder::finalize(unsigned int left, unsigned int right) { mEndScore[LEFT_PLAYER] = left; mEndScore[RIGHT_PLAYER] = right; // fill with one second of do nothing for(int i = 0; i < 75; ++i) { unsigned char packet = 0; mSaveData.push_back(packet); } } blobby-1.0/data/gfx/blobbym3.bmp000644 001750 001750 00000017242 12313310254 021321 0ustar00danielknobedanielknobe000000 000000 BM6(KYl  ------------------------------- ---------------------------------------------------------!! -------------------------------------------------"!!! --------------------------------------------""!!! ---------------------------------------##""!!!! -----------------------------------##""!!!!! --------------------------------$##"""!!!!! ----------------------------%$$##""""!!!! -------------------------%%$$##""""!!!!! -----------------------&%$$$###""""!!!!! ---------------------&&%$$$###""""!!!!!! -------------------'&&%%$$$###""""!!!!!! -----------------('&&%%$$$####"""""!!!!!  ---------------)('&&%%%$$####""""""!!!!!! !--------------)('&%%$$##""""!!!!!!!!!   -------------*)'&%$$##""!!!!    !------------)'&%$##""!!!    -----------)'&$$#""!!   !!----------(&%$#"!!    !!!---------)&%$#"!!    !!!""--------'%$#"!  !!!!!!!""--------&%#"!  !!!!!!!!!!"""#-------&$$#"!  !!!!!!"""""##$------$#""!  !""""""###$%------#"!!  !""#####$$%------"!  !!"###$$$%&------!  !""#$$%%%&------  !"#$%%&&)------ !"##%&&'*------ !!"#$&'**------  !!"#$&)*------- !!"#&')+--------  !!$%&')+-------- !!"#$$&'),---------  !!"##$&'*---------- !!!!!!!!"########"""!!!""#$&)+----------- !!!!"""""""####$$$$$$%%%%%$$$#""#$))------------- !!!"""#####$$$$%%%%%&&&&&&&&&&&%%'((-------------- !!!"""###$$$$%%%&&&&&''''(((((((*))()--------------- !!!"""####$$$%%%&&&''''(((()))))+***)----------------- !!!""""###$$$%%%&&&&'''((())))**+++++------------------ !!!"""###$$$%%%&&&'''(((()))***+,,,,,------------------- !!!""""###$$$%%%&&&'''((()))**++,,,,,-------------------- !!!"""###$$$%%%&&&'''((()))***+,,,,,,--------------------- !!!"""###$$$%%%&&&'''(()))***+,,,,,,---------------------- !!!!""###$$$%%%&&&'''((())))***++++++---------------------- !!!"""###$$$%%&&&'''''(((())))**+++++----------------------- !!!"""###$$$%%%&&&&''''((((())*******------------------------ !!!"""###$$$%%%&&&&'''''(((())********------------------------ !!!"""###$$%%%&&&&&'''''((((()*********------------------------ !!!"""##$$$%%%&&&''''''((((())**********------------------------ !!"""##$$$%%&&&'''''(((((())))***********------------------------- !!""##$$$%%&&&'''((((())))))**********)))*-------------------------- !!""####$$$$%%%%&&&'''''((()))*******)))))))-------------------------- !!"""""""#####$$$%%%&&&&&&'''((()))**)))))))))-------------------------- !!!!!!!!!!"""""####$$$%%%%%%&&&&'''(()))))))))))--------------------------!!! !!!!!!"""#####$$$$$%%%%&&&''(()))))((((--------------------------!  !!!!""""""#####$$$%%%&&'''((((((((--------------------------  !!!!!!!!"""""###$$$%%&&''''''(--------------------------  !!!!"""###$$%%&'''()--------------------------- !!!""#$$%&'(((---------------------------- !!""##$%&'(()---------------------------- !!""##$%&&()*---------------------------- !!""#$%%&()*----------------------------- !!""#$%%&(*------------------------------ !!""#$%%'(*-------------------------------   !!""#$%&')--------------------------------  !!""#$%&')---------------------------------  !!""#$%&'----------------------------------  !!""#$%'-----------------------------------  !"#$%------------------------------------  !!#$&-------------------------------------  !"$--------------------------------------- !#----------------------------------------- !------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------blobby-1.0/data/gfx/ball05.bmp000644 001750 001750 00000012066 12313310254 020666 0ustar00danielknobedanielknobe000000 000000 BM66(@@ usv}z}hfhgegMLMsrsWVWdbca_`mkl|yzgeeRQQ}||wvvpoolkkife~utszyw PPNmmkgge~~}rrqddc__^sur "$"orouvututpqpjkjVWVeigwyx bddeggyzzkllhii_``XYZz{|nop ffiddfccevvxjjliijffg|||{{{xxxwwwssspppnnnhhheeedddcccbbb^^^[[[YYYXXXTTTOOOHHH???000|&L "f fOFtOt NOOOMM (F uuAceM'(GNLLLLL%b=M'끜 OUUU%M]MLu&cM뜂|Lrrr:c%:L%ucY'( `r}UuMLL%%%uMe|O~`r8666oo}U=Mb%%cd'f oLLLUL%倀&cM onorrU`%瀀u&bbM'eO r??vvn766q%&&cM'e U}U!577 rU%bbMMd''e86oT5vnnoo~%&cM'eIٟn^!nnn5nn67U&(nnܟTnn6oU'(eے>>>ъ!6onnnn6opULc(O҉ωTnߋnn6orrUU(NnЛ44mno6Tnnn6oULbꁝNOm4m֟nn5nnnoU%(N>43ˈ2щ۟Tnn6oUL%b";2x24nnnnnn6oUU%cMOOȇx2444nn67rULcN҉ʇ@͈4oonvٟnnoo7rUUL'N6nnnnnnnooULL'4ΈƇ556oqU%f43wԟn6777o6qr`uM''뜖f@@ww͉ԉ4ωSorrUMYMF9Oađ1@ 4Њ6rUUrU%cY=&MFOw12kkww4ЊrrrrU%%=Mcb'eN00w00ΊoUA=dcu=]{e0kkٟ̉֟I6%bM'M&M /0/jjj/k0Ԋ֟6rMbuM e/j///0k00w44Њ5r:uuu'9'ɿ$jj/0003?7bd}Xj//0k@w2>nvv LY('$ii./jwRk͉;n_`'iij000kTv! rH0ćmϊT}Qii-ii./j// 0Rl3Њ?o}hQ.i.-/j//0kax3mS?ތ#,ii-ijRwaLjlЉ;nq+W,iKƑwЊvW,-@3Њn**-iQ0wwa4PP*iii-h-/†)))))PQ-K03mS°PP../w͒j#)))PX/g)*J))))QiijK))))*Q-j))Q-))))+))ii-i)))),ii,,+))h-ii*))))i))))))))P+))))))))))iblobby-1.0/src/lua/lparser.h000644 001750 001750 00000006404 12313310253 020601 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lparser.h,v 1.70.1.1 2013/04/12 18:48:47 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ #ifndef lparser_h #define lparser_h #include "llimits.h" #include "lobject.h" #include "lzio.h" /* ** Expression descriptor */ typedef enum { VVOID, /* no value */ VNIL, VTRUE, VFALSE, VK, /* info = index of constant in `k' */ VKNUM, /* nval = numerical value */ VNONRELOC, /* info = result register */ VLOCAL, /* info = local register */ VUPVAL, /* info = index of upvalue in 'upvalues' */ VINDEXED, /* t = table register/upvalue; idx = index R/K */ VJMP, /* info = instruction pc */ VRELOCABLE, /* info = instruction pc */ VCALL, /* info = instruction pc */ VVARARG /* info = instruction pc */ } expkind; #define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) #define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) typedef struct expdesc { expkind k; union { struct { /* for indexed variables (VINDEXED) */ short idx; /* index (R/K) */ lu_byte t; /* table (register or upvalue) */ lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ } ind; int info; /* for generic use */ lua_Number nval; /* for VKNUM */ } u; int t; /* patch list of `exit when true' */ int f; /* patch list of `exit when false' */ } expdesc; /* description of active local variable */ typedef struct Vardesc { short idx; /* variable index in stack */ } Vardesc; /* description of pending goto statements and label statements */ typedef struct Labeldesc { TString *name; /* label identifier */ int pc; /* position in code */ int line; /* line where it appeared */ lu_byte nactvar; /* local level where it appears in current block */ } Labeldesc; /* list of labels or gotos */ typedef struct Labellist { Labeldesc *arr; /* array */ int n; /* number of entries in use */ int size; /* array size */ } Labellist; /* dynamic structures used by the parser */ typedef struct Dyndata { struct { /* list of active local variables */ Vardesc *arr; int n; int size; } actvar; Labellist gt; /* list of pending gotos */ Labellist label; /* list of active labels */ } Dyndata; /* control of blocks */ struct BlockCnt; /* defined in lparser.c */ /* state needed to generate code for a given function */ typedef struct FuncState { Proto *f; /* current function header */ Table *h; /* table to find (and reuse) elements in `k' */ struct FuncState *prev; /* enclosing function */ struct LexState *ls; /* lexical state */ struct BlockCnt *bl; /* chain of current blocks */ int pc; /* next position to code (equivalent to `ncode') */ int lasttarget; /* 'label' of last 'jump label' */ int jpc; /* list of pending jumps to `pc' */ int nk; /* number of elements in `k' */ int np; /* number of elements in `p' */ int firstlocal; /* index of first local var (in Dyndata array) */ short nlocvars; /* number of elements in 'f->locvars' */ lu_byte nactvar; /* number of active local variables */ lu_byte nups; /* number of upvalues */ lu_byte freereg; /* first free register */ } FuncState; LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Dyndata *dyd, const char *name, int firstchar); #endif blobby-1.0/src/state/000755 001750 001750 00000000000 12313310253 017313 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/lua/lparser.c000644 001750 001750 00000131625 12313310253 020600 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lparser.c,v 2.130.1.1 2013/04/12 18:48:47 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ #include #define lparser_c #define LUA_CORE #include "lua.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" /* maximum number of local variables per function (must be smaller than 250, due to the bytecode format) */ #define MAXVARS 200 #define hasmultret(k) ((k) == VCALL || (k) == VVARARG) /* ** nodes for block list (list of active blocks) */ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ short firstlabel; /* index of first label in this block */ short firstgoto; /* index of first pending goto in this block */ lu_byte nactvar; /* # active locals outside the block */ lu_byte upval; /* true if some variable in the block is an upvalue */ lu_byte isloop; /* true if `block' is a loop */ } BlockCnt; /* ** prototypes for recursive non-terminal functions */ static void statement (LexState *ls); static void expr (LexState *ls, expdesc *v); static void anchor_token (LexState *ls) { /* last token from outer function must be EOS */ lua_assert(ls->fs != NULL || ls->t.token == TK_EOS); if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { TString *ts = ls->t.seminfo.ts; luaX_newstring(ls, getstr(ts), ts->tsv.len); } } /* semantic error */ static l_noret semerror (LexState *ls, const char *msg) { ls->t.token = 0; /* remove 'near to' from final message */ luaX_syntaxerror(ls, msg); } static l_noret error_expected (LexState *ls, int token) { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); } static l_noret errorlimit (FuncState *fs, int limit, const char *what) { lua_State *L = fs->ls->L; const char *msg; int line = fs->f->linedefined; const char *where = (line == 0) ? "main function" : luaO_pushfstring(L, "function at line %d", line); msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s", what, limit, where); luaX_syntaxerror(fs->ls, msg); } static void checklimit (FuncState *fs, int v, int l, const char *what) { if (v > l) errorlimit(fs, l, what); } static int testnext (LexState *ls, int c) { if (ls->t.token == c) { luaX_next(ls); return 1; } else return 0; } static void check (LexState *ls, int c) { if (ls->t.token != c) error_expected(ls, c); } static void checknext (LexState *ls, int c) { check(ls, c); luaX_next(ls); } #define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } static void check_match (LexState *ls, int what, int who, int where) { if (!testnext(ls, what)) { if (where == ls->linenumber) error_expected(ls, what); else { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, "%s expected (to close %s at line %d)", luaX_token2str(ls, what), luaX_token2str(ls, who), where)); } } } static TString *str_checkname (LexState *ls) { TString *ts; check(ls, TK_NAME); ts = ls->t.seminfo.ts; luaX_next(ls); return ts; } static void init_exp (expdesc *e, expkind k, int i) { e->f = e->t = NO_JUMP; e->k = k; e->u.info = i; } static void codestring (LexState *ls, expdesc *e, TString *s) { init_exp(e, VK, luaK_stringK(ls->fs, s)); } static void checkname (LexState *ls, expdesc *e) { codestring(ls, e, str_checkname(ls)); } static int registerlocalvar (LexState *ls, TString *varname) { FuncState *fs = ls->fs; Proto *f = fs->f; int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, LocVar, SHRT_MAX, "local variables"); while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; luaC_objbarrier(ls->L, f, varname); return fs->nlocvars++; } static void new_localvar (LexState *ls, TString *name) { FuncState *fs = ls->fs; Dyndata *dyd = ls->dyd; int reg = registerlocalvar(ls, name); checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, MAXVARS, "local variables"); luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, dyd->actvar.size, Vardesc, MAX_INT, "local variables"); dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); } static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { new_localvar(ls, luaX_newstring(ls, name, sz)); } #define new_localvarliteral(ls,v) \ new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) static LocVar *getlocvar (FuncState *fs, int i) { int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; lua_assert(idx < fs->nlocvars); return &fs->f->locvars[idx]; } static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; fs->nactvar = cast_byte(fs->nactvar + nvars); for (; nvars; nvars--) { getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; } } static void removevars (FuncState *fs, int tolevel) { fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); while (fs->nactvar > tolevel) getlocvar(fs, --fs->nactvar)->endpc = fs->pc; } static int searchupvalue (FuncState *fs, TString *name) { int i; Upvaldesc *up = fs->f->upvalues; for (i = 0; i < fs->nups; i++) { if (luaS_eqstr(up[i].name, name)) return i; } return -1; /* not found */ } static int newupvalue (FuncState *fs, TString *name, expdesc *v) { Proto *f = fs->f; int oldsize = f->sizeupvalues; checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, Upvaldesc, MAXUPVAL, "upvalues"); while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; f->upvalues[fs->nups].instack = (v->k == VLOCAL); f->upvalues[fs->nups].idx = cast_byte(v->u.info); f->upvalues[fs->nups].name = name; luaC_objbarrier(fs->ls->L, f, name); return fs->nups++; } static int searchvar (FuncState *fs, TString *n) { int i; for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { if (luaS_eqstr(n, getlocvar(fs, i)->varname)) return i; } return -1; /* not found */ } /* Mark block where variable at given level was defined (to emit close instructions later). */ static void markupval (FuncState *fs, int level) { BlockCnt *bl = fs->bl; while (bl->nactvar > level) bl = bl->previous; bl->upval = 1; } /* Find variable with given name 'n'. If it is an upvalue, add this upvalue into all intermediate functions. */ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { if (fs == NULL) /* no more levels? */ return VVOID; /* default is global */ else { int v = searchvar(fs, n); /* look up locals at current level */ if (v >= 0) { /* found? */ init_exp(var, VLOCAL, v); /* variable is local */ if (!base) markupval(fs, v); /* local will be used as an upval */ return VLOCAL; } else { /* not found as local at current level; try upvalues */ int idx = searchupvalue(fs, n); /* try existing upvalues */ if (idx < 0) { /* not found? */ if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ return VVOID; /* not found; is a global */ /* else was LOCAL or UPVAL */ idx = newupvalue(fs, n, var); /* will be a new upvalue */ } init_exp(var, VUPVAL, idx); return VUPVAL; } } } static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ expdesc key; singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ lua_assert(var->k == VLOCAL || var->k == VUPVAL); codestring(ls, &key, varname); /* key is variable name */ luaK_indexed(fs, var, &key); /* env[varname] */ } } static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { FuncState *fs = ls->fs; int extra = nvars - nexps; if (hasmultret(e->k)) { extra++; /* includes call itself */ if (extra < 0) extra = 0; luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ if (extra > 1) luaK_reserveregs(fs, extra-1); } else { if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ if (extra > 0) { int reg = fs->freereg; luaK_reserveregs(fs, extra); luaK_nil(fs, reg, extra); } } } static void enterlevel (LexState *ls) { lua_State *L = ls->L; ++L->nCcalls; checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); } #define leavelevel(ls) ((ls)->L->nCcalls--) static void closegoto (LexState *ls, int g, Labeldesc *label) { int i; FuncState *fs = ls->fs; Labellist *gl = &ls->dyd->gt; Labeldesc *gt = &gl->arr[g]; lua_assert(luaS_eqstr(gt->name, label->name)); if (gt->nactvar < label->nactvar) { TString *vname = getlocvar(fs, gt->nactvar)->varname; const char *msg = luaO_pushfstring(ls->L, " at line %d jumps into the scope of local " LUA_QS, getstr(gt->name), gt->line, getstr(vname)); semerror(ls, msg); } luaK_patchlist(fs, gt->pc, label->pc); /* remove goto from pending list */ for (i = g; i < gl->n - 1; i++) gl->arr[i] = gl->arr[i + 1]; gl->n--; } /* ** try to close a goto with existing labels; this solves backward jumps */ static int findlabel (LexState *ls, int g) { int i; BlockCnt *bl = ls->fs->bl; Dyndata *dyd = ls->dyd; Labeldesc *gt = &dyd->gt.arr[g]; /* check labels in current block for a match */ for (i = bl->firstlabel; i < dyd->label.n; i++) { Labeldesc *lb = &dyd->label.arr[i]; if (luaS_eqstr(lb->name, gt->name)) { /* correct label? */ if (gt->nactvar > lb->nactvar && (bl->upval || dyd->label.n > bl->firstlabel)) luaK_patchclose(ls->fs, gt->pc, lb->nactvar); closegoto(ls, g, lb); /* close it */ return 1; } } return 0; /* label not found; cannot close goto */ } static int newlabelentry (LexState *ls, Labellist *l, TString *name, int line, int pc) { int n = l->n; luaM_growvector(ls->L, l->arr, n, l->size, Labeldesc, SHRT_MAX, "labels/gotos"); l->arr[n].name = name; l->arr[n].line = line; l->arr[n].nactvar = ls->fs->nactvar; l->arr[n].pc = pc; l->n++; return n; } /* ** check whether new label 'lb' matches any pending gotos in current ** block; solves forward jumps */ static void findgotos (LexState *ls, Labeldesc *lb) { Labellist *gl = &ls->dyd->gt; int i = ls->fs->bl->firstgoto; while (i < gl->n) { if (luaS_eqstr(gl->arr[i].name, lb->name)) closegoto(ls, i, lb); else i++; } } /* ** "export" pending gotos to outer level, to check them against ** outer labels; if the block being exited has upvalues, and ** the goto exits the scope of any variable (which can be the ** upvalue), close those variables being exited. */ static void movegotosout (FuncState *fs, BlockCnt *bl) { int i = bl->firstgoto; Labellist *gl = &fs->ls->dyd->gt; /* correct pending gotos to current block and try to close it with visible labels */ while (i < gl->n) { Labeldesc *gt = &gl->arr[i]; if (gt->nactvar > bl->nactvar) { if (bl->upval) luaK_patchclose(fs, gt->pc, bl->nactvar); gt->nactvar = bl->nactvar; } if (!findlabel(fs->ls, i)) i++; /* move to next one */ } } static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { bl->isloop = isloop; bl->nactvar = fs->nactvar; bl->firstlabel = fs->ls->dyd->label.n; bl->firstgoto = fs->ls->dyd->gt.n; bl->upval = 0; bl->previous = fs->bl; fs->bl = bl; lua_assert(fs->freereg == fs->nactvar); } /* ** create a label named "break" to resolve break statements */ static void breaklabel (LexState *ls) { TString *n = luaS_new(ls->L, "break"); int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); findgotos(ls, &ls->dyd->label.arr[l]); } /* ** generates an error for an undefined 'goto'; choose appropriate ** message when label name is a reserved word (which can only be 'break') */ static l_noret undefgoto (LexState *ls, Labeldesc *gt) { const char *msg = isreserved(gt->name) ? "<%s> at line %d not inside a loop" : "no visible label " LUA_QS " for at line %d"; msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); semerror(ls, msg); } static void leaveblock (FuncState *fs) { BlockCnt *bl = fs->bl; LexState *ls = fs->ls; if (bl->previous && bl->upval) { /* create a 'jump to here' to close upvalues */ int j = luaK_jump(fs); luaK_patchclose(fs, j, bl->nactvar); luaK_patchtohere(fs, j); } if (bl->isloop) breaklabel(ls); /* close pending breaks */ fs->bl = bl->previous; removevars(fs, bl->nactvar); lua_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */ if (bl->previous) /* inner block? */ movegotosout(fs, bl); /* update pending gotos to outer block */ else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ } /* ** adds a new prototype into list of prototypes */ static Proto *addprototype (LexState *ls) { Proto *clp; lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; /* prototype of current function */ if (fs->np >= f->sizep) { int oldsize = f->sizep; luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); while (oldsize < f->sizep) f->p[oldsize++] = NULL; } f->p[fs->np++] = clp = luaF_newproto(L); luaC_objbarrier(L, f, clp); return clp; } /* ** codes instruction to create new closure in parent function. ** The OP_CLOSURE instruction must use the last available register, ** so that, if it invokes the GC, the GC knows which registers ** are in use at that time. */ static void codeclosure (LexState *ls, expdesc *v) { FuncState *fs = ls->fs->prev; init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); luaK_exp2nextreg(fs, v); /* fix it at the last register */ } static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { lua_State *L = ls->L; Proto *f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; ls->fs = fs; fs->pc = 0; fs->lasttarget = 0; fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; fs->np = 0; fs->nups = 0; fs->nlocvars = 0; fs->nactvar = 0; fs->firstlocal = ls->dyd->actvar.n; fs->bl = NULL; f = fs->f; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ fs->h = luaH_new(L); /* anchor table of constants (to avoid being collected) */ sethvalue2s(L, L->top, fs->h); incr_top(L); enterblock(fs, bl, 0); } static void close_func (LexState *ls) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; luaK_ret(fs, 0, 0); /* final return */ leaveblock(fs); luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); f->sizecode = fs->pc; luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); f->sizelineinfo = fs->pc; luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); f->sizek = fs->nk; luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); f->sizep = fs->np; luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); f->sizelocvars = fs->nlocvars; luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); f->sizeupvalues = fs->nups; lua_assert(fs->bl == NULL); ls->fs = fs->prev; /* last token read was anchored in defunct function; must re-anchor it */ anchor_token(ls); L->top--; /* pop table of constants */ luaC_checkGC(L); } /*============================================================*/ /* GRAMMAR RULES */ /*============================================================*/ /* ** check whether current token is in the follow set of a block. ** 'until' closes syntactical blocks, but do not close scope, ** so it handled in separate. */ static int block_follow (LexState *ls, int withuntil) { switch (ls->t.token) { case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_EOS: return 1; case TK_UNTIL: return withuntil; default: return 0; } } static void statlist (LexState *ls) { /* statlist -> { stat [`;'] } */ while (!block_follow(ls, 1)) { if (ls->t.token == TK_RETURN) { statement(ls); return; /* 'return' must be last statement */ } statement(ls); } } static void fieldsel (LexState *ls, expdesc *v) { /* fieldsel -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; luaK_exp2anyregup(fs, v); luaX_next(ls); /* skip the dot or colon */ checkname(ls, &key); luaK_indexed(fs, v, &key); } static void yindex (LexState *ls, expdesc *v) { /* index -> '[' expr ']' */ luaX_next(ls); /* skip the '[' */ expr(ls, v); luaK_exp2val(ls->fs, v); checknext(ls, ']'); } /* ** {====================================================================== ** Rules for Constructors ** ======================================================================= */ struct ConsControl { expdesc v; /* last list item read */ expdesc *t; /* table descriptor */ int nh; /* total number of `record' elements */ int na; /* total number of array elements */ int tostore; /* number of array elements pending to be stored */ }; static void recfield (LexState *ls, struct ConsControl *cc) { /* recfield -> (NAME | `['exp1`]') = exp1 */ FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc key, val; int rkkey; if (ls->t.token == TK_NAME) { checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); checkname(ls, &key); } else /* ls->t.token == '[' */ yindex(ls, &key); cc->nh++; checknext(ls, '='); rkkey = luaK_exp2RK(fs, &key); expr(ls, &val); luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val)); fs->freereg = reg; /* free registers */ } static void closelistfield (FuncState *fs, struct ConsControl *cc) { if (cc->v.k == VVOID) return; /* there is no list item */ luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; if (cc->tostore == LFIELDS_PER_FLUSH) { luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ cc->tostore = 0; /* no more items pending */ } } static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; if (hasmultret(cc->v.k)) { luaK_setmultret(fs, &cc->v); luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET); cc->na--; /* do not count last expression (unknown number of elements) */ } else { if (cc->v.k != VVOID) luaK_exp2nextreg(fs, &cc->v); luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); } } static void listfield (LexState *ls, struct ConsControl *cc) { /* listfield -> exp */ expr(ls, &cc->v); checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); cc->na++; cc->tostore++; } static void field (LexState *ls, struct ConsControl *cc) { /* field -> listfield | recfield */ switch(ls->t.token) { case TK_NAME: { /* may be 'listfield' or 'recfield' */ if (luaX_lookahead(ls) != '=') /* expression? */ listfield(ls, cc); else recfield(ls, cc); break; } case '[': { recfield(ls, cc); break; } default: { listfield(ls, cc); break; } } } static void constructor (LexState *ls, expdesc *t) { /* constructor -> '{' [ field { sep field } [sep] ] '}' sep -> ',' | ';' */ FuncState *fs = ls->fs; int line = ls->linenumber; int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); struct ConsControl cc; cc.na = cc.nh = cc.tostore = 0; cc.t = t; init_exp(t, VRELOCABLE, pc); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */ checknext(ls, '{'); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); if (ls->t.token == '}') break; closelistfield(fs, &cc); field(ls, &cc); } while (testnext(ls, ',') || testnext(ls, ';')); check_match(ls, '}', '{', line); lastlistfield(fs, &cc); SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ } /* }====================================================================== */ static void parlist (LexState *ls) { /* parlist -> [ param { `,' param } ] */ FuncState *fs = ls->fs; Proto *f = fs->f; int nparams = 0; f->is_vararg = 0; if (ls->t.token != ')') { /* is `parlist' not empty? */ do { switch (ls->t.token) { case TK_NAME: { /* param -> NAME */ new_localvar(ls, str_checkname(ls)); nparams++; break; } case TK_DOTS: { /* param -> `...' */ luaX_next(ls); f->is_vararg = 1; break; } default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); } } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); f->numparams = cast_byte(fs->nactvar); luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } static void body (LexState *ls, expdesc *e, int ismethod, int line) { /* body -> `(' parlist `)' block END */ FuncState new_fs; BlockCnt bl; new_fs.f = addprototype(ls); new_fs.f->linedefined = line; open_func(ls, &new_fs, &bl); checknext(ls, '('); if (ismethod) { new_localvarliteral(ls, "self"); /* create 'self' parameter */ adjustlocalvars(ls, 1); } parlist(ls); checknext(ls, ')'); statlist(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); codeclosure(ls, e); close_func(ls); } static int explist (LexState *ls, expdesc *v) { /* explist -> expr { `,' expr } */ int n = 1; /* at least one expression */ expr(ls, v); while (testnext(ls, ',')) { luaK_exp2nextreg(ls->fs, v); expr(ls, v); n++; } return n; } static void funcargs (LexState *ls, expdesc *f, int line) { FuncState *fs = ls->fs; expdesc args; int base, nparams; switch (ls->t.token) { case '(': { /* funcargs -> `(' [ explist ] `)' */ luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; else { explist(ls, &args); luaK_setmultret(fs, &args); } check_match(ls, ')', '(', line); break; } case '{': { /* funcargs -> constructor */ constructor(ls, &args); break; } case TK_STRING: { /* funcargs -> STRING */ codestring(ls, &args, ls->t.seminfo.ts); luaX_next(ls); /* must use `seminfo' before `next' */ break; } default: { luaX_syntaxerror(ls, "function arguments expected"); } } lua_assert(f->k == VNONRELOC); base = f->u.info; /* base register for call */ if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { if (args.k != VVOID) luaK_exp2nextreg(fs, &args); /* close last argument */ nparams = fs->freereg - (base+1); } init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); luaK_fixline(fs, line); fs->freereg = base+1; /* call remove function and arguments and leaves (unless changed) one result */ } /* ** {====================================================================== ** Expression parsing ** ======================================================================= */ static void primaryexp (LexState *ls, expdesc *v) { /* primaryexp -> NAME | '(' expr ')' */ switch (ls->t.token) { case '(': { int line = ls->linenumber; luaX_next(ls); expr(ls, v); check_match(ls, ')', '(', line); luaK_dischargevars(ls->fs, v); return; } case TK_NAME: { singlevar(ls, v); return; } default: { luaX_syntaxerror(ls, "unexpected symbol"); } } } static void suffixedexp (LexState *ls, expdesc *v) { /* suffixedexp -> primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; int line = ls->linenumber; primaryexp(ls, v); for (;;) { switch (ls->t.token) { case '.': { /* fieldsel */ fieldsel(ls, v); break; } case '[': { /* `[' exp1 `]' */ expdesc key; luaK_exp2anyregup(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; } case ':': { /* `:' NAME funcargs */ expdesc key; luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); funcargs(ls, v, line); break; } case '(': case TK_STRING: case '{': { /* funcargs */ luaK_exp2nextreg(fs, v); funcargs(ls, v, line); break; } default: return; } } } static void simpleexp (LexState *ls, expdesc *v) { /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | constructor | FUNCTION body | suffixedexp */ switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VKNUM, 0); v->u.nval = ls->t.seminfo.r; break; } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); break; } case TK_NIL: { init_exp(v, VNIL, 0); break; } case TK_TRUE: { init_exp(v, VTRUE, 0); break; } case TK_FALSE: { init_exp(v, VFALSE, 0); break; } case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, "cannot use " LUA_QL("...") " outside a vararg function"); init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } case '{': { /* constructor */ constructor(ls, v); return; } case TK_FUNCTION: { luaX_next(ls); body(ls, v, 0, ls->linenumber); return; } default: { suffixedexp(ls, v); return; } } luaX_next(ls); } static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; case '#': return OPR_LEN; default: return OPR_NOUNOPR; } } static BinOpr getbinopr (int op) { switch (op) { case '+': return OPR_ADD; case '-': return OPR_SUB; case '*': return OPR_MUL; case '/': return OPR_DIV; case '%': return OPR_MOD; case '^': return OPR_POW; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; case TK_EQ: return OPR_EQ; case '<': return OPR_LT; case TK_LE: return OPR_LE; case '>': return OPR_GT; case TK_GE: return OPR_GE; case TK_AND: return OPR_AND; case TK_OR: return OPR_OR; default: return OPR_NOBINOPR; } } static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `*' `/' `%' */ {10, 9}, {5, 4}, /* ^, .. (right associative) */ {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ {2, 2}, {1, 1} /* and, or */ }; #define UNARY_PRIORITY 8 /* priority for unary operators */ /* ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { BinOpr op; UnOpr uop; enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { int line = ls->linenumber; luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(ls->fs, uop, v, line); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls->t.token); while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; int line = ls->linenumber; luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(ls->fs, op, v, &v2, line); op = nextop; } leavelevel(ls); return op; /* return first untreated operator */ } static void expr (LexState *ls, expdesc *v) { subexpr(ls, v, 0); } /* }==================================================================== */ /* ** {====================================================================== ** Rules for Statements ** ======================================================================= */ static void block (LexState *ls) { /* block -> statlist */ FuncState *fs = ls->fs; BlockCnt bl; enterblock(fs, &bl, 0); statlist(ls); leaveblock(fs); } /* ** structure to chain all variables in the left-hand side of an ** assignment */ struct LHS_assign { struct LHS_assign *prev; expdesc v; /* variable (global, local, upvalue, or indexed) */ }; /* ** check whether, in an assignment to an upvalue/local variable, the ** upvalue/local variable is begin used in a previous assignment to a ** table. If so, save original upvalue/local value in a safe place and ** use this safe copy in the previous assignment. */ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { FuncState *fs = ls->fs; int extra = fs->freereg; /* eventual position to save local variable */ int conflict = 0; for (; lh; lh = lh->prev) { /* check all previous assignments */ if (lh->v.k == VINDEXED) { /* assigning to a table? */ /* table is the upvalue/local being assigned now? */ if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { conflict = 1; lh->v.u.ind.vt = VLOCAL; lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ } /* index is the local being assigned? (index cannot be upvalue) */ if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { conflict = 1; lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ } } } if (conflict) { /* copy upvalue/local value to a temporary (in position 'extra') */ OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; luaK_codeABC(fs, op, extra, v->u.info, 0); luaK_reserveregs(fs, 1); } } static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { expdesc e; check_condition(ls, vkisvar(lh->v.k), "syntax error"); if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ struct LHS_assign nv; nv.prev = lh; suffixedexp(ls, &nv.v); if (nv.v.k != VINDEXED) check_conflict(ls, lh, &nv.v); checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, "C levels"); assignment(ls, &nv, nvars+1); } else { /* assignment -> `=' explist */ int nexps; checknext(ls, '='); nexps = explist(ls, &e); if (nexps != nvars) { adjust_assign(ls, nvars, nexps, &e); if (nexps > nvars) ls->fs->freereg -= nexps - nvars; /* remove extra values */ } else { luaK_setoneret(ls->fs, &e); /* close last expression */ luaK_storevar(ls->fs, &lh->v, &e); return; /* avoid default */ } } init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ luaK_storevar(ls->fs, &lh->v, &e); } static int cond (LexState *ls) { /* cond -> exp */ expdesc v; expr(ls, &v); /* read condition */ if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ luaK_goiftrue(ls->fs, &v); return v.f; } static void gotostat (LexState *ls, int pc) { int line = ls->linenumber; TString *label; int g; if (testnext(ls, TK_GOTO)) label = str_checkname(ls); else { luaX_next(ls); /* skip break */ label = luaS_new(ls->L, "break"); } g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); findlabel(ls, g); /* close it if label already defined */ } /* check for repeated labels on the same block */ static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { int i; for (i = fs->bl->firstlabel; i < ll->n; i++) { if (luaS_eqstr(label, ll->arr[i].name)) { const char *msg = luaO_pushfstring(fs->ls->L, "label " LUA_QS " already defined on line %d", getstr(label), ll->arr[i].line); semerror(fs->ls, msg); } } } /* skip no-op statements */ static void skipnoopstat (LexState *ls) { while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) statement(ls); } static void labelstat (LexState *ls, TString *label, int line) { /* label -> '::' NAME '::' */ FuncState *fs = ls->fs; Labellist *ll = &ls->dyd->label; int l; /* index of new label being created */ checkrepeated(fs, ll, label); /* check for repeated labels */ checknext(ls, TK_DBCOLON); /* skip double colon */ /* create new entry for this label */ l = newlabelentry(ls, ll, label, line, fs->pc); skipnoopstat(ls); /* skip other no-op statements */ if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ /* assume that locals are already out of scope */ ll->arr[l].nactvar = fs->bl->nactvar; } findgotos(ls, &ll->arr[l]); } static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ FuncState *fs = ls->fs; int whileinit; int condexit; BlockCnt bl; luaX_next(ls); /* skip WHILE */ whileinit = luaK_getlabel(fs); condexit = cond(ls); enterblock(fs, &bl, 1); checknext(ls, TK_DO); block(ls); luaK_jumpto(fs, whileinit); check_match(ls, TK_END, TK_WHILE, line); leaveblock(fs); luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ } static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ int condexit; FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); BlockCnt bl1, bl2; enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ luaX_next(ls); /* skip REPEAT */ statlist(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); condexit = cond(ls); /* read condition (inside scope block) */ if (bl2.upval) /* upvalues? */ luaK_patchclose(fs, condexit, bl2.nactvar); leaveblock(fs); /* finish scope */ luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ leaveblock(fs); /* finish loop */ } static int exp1 (LexState *ls) { expdesc e; int reg; expr(ls, &e); luaK_exp2nextreg(ls->fs, &e); lua_assert(e.k == VNONRELOC); reg = e.u.info; return reg; } static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { /* forbody -> DO block */ BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; adjustlocalvars(ls, 3); /* control variables */ checknext(ls, TK_DO); prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); enterblock(fs, &bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); luaK_reserveregs(fs, nvars); block(ls); leaveblock(fs); /* end of scope for declared variables */ luaK_patchtohere(fs, prep); if (isnum) /* numeric for? */ endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); else { /* generic for */ luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); luaK_fixline(fs, line); endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); } luaK_patchlist(fs, endfor, prep + 1); luaK_fixline(fs, line); } static void fornum (LexState *ls, TString *varname, int line) { /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; new_localvarliteral(ls, "(for index)"); new_localvarliteral(ls, "(for limit)"); new_localvarliteral(ls, "(for step)"); new_localvar(ls, varname); checknext(ls, '='); exp1(ls); /* initial value */ checknext(ls, ','); exp1(ls); /* limit */ if (testnext(ls, ',')) exp1(ls); /* optional step */ else { /* default step = 1 */ luaK_codek(fs, fs->freereg, luaK_numberK(fs, 1)); luaK_reserveregs(fs, 1); } forbody(ls, base, line, 1, 1); } static void forlist (LexState *ls, TString *indexname) { /* forlist -> NAME {,NAME} IN explist forbody */ FuncState *fs = ls->fs; expdesc e; int nvars = 4; /* gen, state, control, plus at least one declared var */ int line; int base = fs->freereg; /* create control variables */ new_localvarliteral(ls, "(for generator)"); new_localvarliteral(ls, "(for state)"); new_localvarliteral(ls, "(for control)"); /* create declared variables */ new_localvar(ls, indexname); while (testnext(ls, ',')) { new_localvar(ls, str_checkname(ls)); nvars++; } checknext(ls, TK_IN); line = ls->linenumber; adjust_assign(ls, 3, explist(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 3, 0); } static void forstat (LexState *ls, int line) { /* forstat -> FOR (fornum | forlist) END */ FuncState *fs = ls->fs; TString *varname; BlockCnt bl; enterblock(fs, &bl, 1); /* scope for loop and control variables */ luaX_next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { case '=': fornum(ls, varname, line); break; case ',': case TK_IN: forlist(ls, varname); break; default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); } check_match(ls, TK_END, TK_FOR, line); leaveblock(fs); /* loop scope (`break' jumps to this point) */ } static void test_then_block (LexState *ls, int *escapelist) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ BlockCnt bl; FuncState *fs = ls->fs; expdesc v; int jf; /* instruction to skip 'then' code (if condition is false) */ luaX_next(ls); /* skip IF or ELSEIF */ expr(ls, &v); /* read condition */ checknext(ls, TK_THEN); if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ enterblock(fs, &bl, 0); /* must enter block before 'goto' */ gotostat(ls, v.t); /* handle goto/break */ skipnoopstat(ls); /* skip other no-op statements */ if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ leaveblock(fs); return; /* and that is it */ } else /* must skip over 'then' part if condition is false */ jf = luaK_jump(fs); } else { /* regular case (not goto/break) */ luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ enterblock(fs, &bl, 0); jf = v.f; } statlist(ls); /* `then' part */ leaveblock(fs); if (ls->t.token == TK_ELSE || ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ luaK_patchtohere(fs, jf); } static void ifstat (LexState *ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState *fs = ls->fs; int escapelist = NO_JUMP; /* exit list for finished parts */ test_then_block(ls, &escapelist); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ if (testnext(ls, TK_ELSE)) block(ls); /* `else' part */ check_match(ls, TK_END, TK_IF, line); luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ } static void localfunc (LexState *ls) { expdesc b; FuncState *fs = ls->fs; new_localvar(ls, str_checkname(ls)); /* new local variable */ adjustlocalvars(ls, 1); /* enter its scope */ body(ls, &b, 0, ls->linenumber); /* function created in next register */ /* debug information will only see the variable after this point! */ getlocvar(fs, b.u.info)->startpc = fs->pc; } static void localstat (LexState *ls) { /* stat -> LOCAL NAME {`,' NAME} [`=' explist] */ int nvars = 0; int nexps; expdesc e; do { new_localvar(ls, str_checkname(ls)); nvars++; } while (testnext(ls, ',')); if (testnext(ls, '=')) nexps = explist(ls, &e); else { e.k = VVOID; nexps = 0; } adjust_assign(ls, nvars, nexps, &e); adjustlocalvars(ls, nvars); } static int funcname (LexState *ls, expdesc *v) { /* funcname -> NAME {fieldsel} [`:' NAME] */ int ismethod = 0; singlevar(ls, v); while (ls->t.token == '.') fieldsel(ls, v); if (ls->t.token == ':') { ismethod = 1; fieldsel(ls, v); } return ismethod; } static void funcstat (LexState *ls, int line) { /* funcstat -> FUNCTION funcname body */ int ismethod; expdesc v, b; luaX_next(ls); /* skip FUNCTION */ ismethod = funcname(ls, &v); body(ls, &b, ismethod, line); luaK_storevar(ls->fs, &v, &b); luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ } static void exprstat (LexState *ls) { /* stat -> func | assignment */ FuncState *fs = ls->fs; struct LHS_assign v; suffixedexp(ls, &v.v); if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ v.prev = NULL; assignment(ls, &v, 1); } else { /* stat -> func */ check_condition(ls, v.v.k == VCALL, "syntax error"); SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ } } static void retstat (LexState *ls) { /* stat -> RETURN [explist] [';'] */ FuncState *fs = ls->fs; expdesc e; int first, nret; /* registers with returned values */ if (block_follow(ls, 1) || ls->t.token == ';') first = nret = 0; /* return no values */ else { nret = explist(ls, &e); /* optional return values */ if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ SET_OPCODE(getcode(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); } first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ first = luaK_exp2anyreg(fs, &e); else { luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ first = fs->nactvar; /* return all `active' values */ lua_assert(nret == fs->freereg - first); } } } luaK_ret(fs, first, nret); testnext(ls, ';'); /* skip optional semicolon */ } static void statement (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ enterlevel(ls); switch (ls->t.token) { case ';': { /* stat -> ';' (empty statement) */ luaX_next(ls); /* skip ';' */ break; } case TK_IF: { /* stat -> ifstat */ ifstat(ls, line); break; } case TK_WHILE: { /* stat -> whilestat */ whilestat(ls, line); break; } case TK_DO: { /* stat -> DO block END */ luaX_next(ls); /* skip DO */ block(ls); check_match(ls, TK_END, TK_DO, line); break; } case TK_FOR: { /* stat -> forstat */ forstat(ls, line); break; } case TK_REPEAT: { /* stat -> repeatstat */ repeatstat(ls, line); break; } case TK_FUNCTION: { /* stat -> funcstat */ funcstat(ls, line); break; } case TK_LOCAL: { /* stat -> localstat */ luaX_next(ls); /* skip LOCAL */ if (testnext(ls, TK_FUNCTION)) /* local function? */ localfunc(ls); else localstat(ls); break; } case TK_DBCOLON: { /* stat -> label */ luaX_next(ls); /* skip double colon */ labelstat(ls, str_checkname(ls), line); break; } case TK_RETURN: { /* stat -> retstat */ luaX_next(ls); /* skip RETURN */ retstat(ls); break; } case TK_BREAK: /* stat -> breakstat */ case TK_GOTO: { /* stat -> 'goto' NAME */ gotostat(ls, luaK_jump(ls->fs)); break; } default: { /* stat -> func | assignment */ exprstat(ls); break; } } lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && ls->fs->freereg >= ls->fs->nactvar); ls->fs->freereg = ls->fs->nactvar; /* free registers */ leavelevel(ls); } /* }====================================================================== */ /* ** compiles the main function, which is a regular vararg function with an ** upvalue named LUA_ENV */ static void mainfunc (LexState *ls, FuncState *fs) { BlockCnt bl; expdesc v; open_func(ls, fs, &bl); fs->f->is_vararg = 1; /* main function is always vararg */ init_exp(&v, VLOCAL, 0); /* create and... */ newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ luaX_next(ls); /* read first token */ statlist(ls); /* parse main body */ check(ls, TK_EOS); close_func(ls); } Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Dyndata *dyd, const char *name, int firstchar) { LexState lexstate; FuncState funcstate; Closure *cl = luaF_newLclosure(L, 1); /* create main closure */ /* anchor closure (to avoid being collected) */ setclLvalue(L, L->top, cl); incr_top(L); funcstate.f = cl->l.p = luaF_newproto(L); funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ lexstate.buff = buff; lexstate.dyd = dyd; dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); mainfunc(&lexstate, &funcstate); lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); /* all scopes should be correctly finished */ lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); return cl; /* it's on the stack too */ } blobby-1.0/src/lua/lapi.c000644 001750 001750 00000072326 12313310253 020057 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lapi.c,v 2.171.1.1 2013/04/12 18:48:47 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ #include #include #define lapi_c #define LUA_CORE #include "lua.h" #include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lundump.h" #include "lvm.h" const char lua_ident[] = "$LuaVersion: " LUA_COPYRIGHT " $" "$LuaAuthors: " LUA_AUTHORS " $"; /* value at a non-valid index */ #define NONVALIDVALUE cast(TValue *, luaO_nilobject) /* corresponding test */ #define isvalid(o) ((o) != luaO_nilobject) /* test for pseudo index */ #define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) /* test for valid but not pseudo index */ #define isstackindex(i, o) (isvalid(o) && !ispseudo(i)) #define api_checkvalidindex(L, o) api_check(L, isvalid(o), "invalid index") #define api_checkstackindex(L, i, o) \ api_check(L, isstackindex(i, o), "index not in the stack") static TValue *index2addr (lua_State *L, int idx) { CallInfo *ci = L->ci; if (idx > 0) { TValue *o = ci->func + idx; api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); if (o >= L->top) return NONVALIDVALUE; else return o; } else if (!ispseudo(idx)) { /* negative index */ api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); return L->top + idx; } else if (idx == LUA_REGISTRYINDEX) return &G(L)->l_registry; else { /* upvalues */ idx = LUA_REGISTRYINDEX - idx; api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); if (ttislcf(ci->func)) /* light C function? */ return NONVALIDVALUE; /* it has no upvalues */ else { CClosure *func = clCvalue(ci->func); return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; } } } /* ** to be called by 'lua_checkstack' in protected mode, to grow stack ** capturing memory errors */ static void growstack (lua_State *L, void *ud) { int size = *(int *)ud; luaD_growstack(L, size); } LUA_API int lua_checkstack (lua_State *L, int size) { int res; CallInfo *ci = L->ci; lua_lock(L); if (L->stack_last - L->top > size) /* stack large enough? */ res = 1; /* yes; check is OK */ else { /* no; need to grow stack */ int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; if (inuse > LUAI_MAXSTACK - size) /* can grow without overflow? */ res = 0; /* no */ else /* try to grow stack */ res = (luaD_rawrunprotected(L, &growstack, &size) == LUA_OK); } if (res && ci->top < L->top + size) ci->top = L->top + size; /* adjust frame top */ lua_unlock(L); return res; } LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { int i; if (from == to) return; lua_lock(to); api_checknelems(from, n); api_check(from, G(from) == G(to), "moving among independent states"); api_check(from, to->ci->top - to->top >= n, "not enough elements to move"); from->top -= n; for (i = 0; i < n; i++) { setobj2s(to, to->top++, from->top + i); } lua_unlock(to); } LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { lua_CFunction old; lua_lock(L); old = G(L)->panic; G(L)->panic = panicf; lua_unlock(L); return old; } LUA_API const lua_Number *lua_version (lua_State *L) { static const lua_Number version = LUA_VERSION_NUM; if (L == NULL) return &version; else return G(L)->version; } /* ** basic stack manipulation */ /* ** convert an acceptable stack index into an absolute index */ LUA_API int lua_absindex (lua_State *L, int idx) { return (idx > 0 || ispseudo(idx)) ? idx : cast_int(L->top - L->ci->func + idx); } LUA_API int lua_gettop (lua_State *L) { return cast_int(L->top - (L->ci->func + 1)); } LUA_API void lua_settop (lua_State *L, int idx) { StkId func = L->ci->func; lua_lock(L); if (idx >= 0) { api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); while (L->top < (func + 1) + idx) setnilvalue(L->top++); L->top = (func + 1) + idx; } else { api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); L->top += idx+1; /* `subtract' index (index is negative) */ } lua_unlock(L); } LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); p = index2addr(L, idx); api_checkstackindex(L, idx, p); while (++p < L->top) setobjs2s(L, p-1, p); L->top--; lua_unlock(L); } LUA_API void lua_insert (lua_State *L, int idx) { StkId p; StkId q; lua_lock(L); p = index2addr(L, idx); api_checkstackindex(L, idx, p); for (q = L->top; q > p; q--) /* use L->top as a temporary */ setobjs2s(L, q, q - 1); setobjs2s(L, p, L->top); lua_unlock(L); } static void moveto (lua_State *L, TValue *fr, int idx) { TValue *to = index2addr(L, idx); api_checkvalidindex(L, to); setobj(L, to, fr); if (idx < LUA_REGISTRYINDEX) /* function upvalue? */ luaC_barrier(L, clCvalue(L->ci->func), fr); /* LUA_REGISTRYINDEX does not need gc barrier (collector revisits it before finishing collection) */ } LUA_API void lua_replace (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 1); moveto(L, L->top - 1, idx); L->top--; lua_unlock(L); } LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { TValue *fr; lua_lock(L); fr = index2addr(L, fromidx); moveto(L, fr, toidx); lua_unlock(L); } LUA_API void lua_pushvalue (lua_State *L, int idx) { lua_lock(L); setobj2s(L, L->top, index2addr(L, idx)); api_incr_top(L); lua_unlock(L); } /* ** access functions (stack -> C) */ LUA_API int lua_type (lua_State *L, int idx) { StkId o = index2addr(L, idx); return (isvalid(o) ? ttypenv(o) : LUA_TNONE); } LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); return ttypename(t); } LUA_API int lua_iscfunction (lua_State *L, int idx) { StkId o = index2addr(L, idx); return (ttislcf(o) || (ttisCclosure(o))); } LUA_API int lua_isnumber (lua_State *L, int idx) { TValue n; const TValue *o = index2addr(L, idx); return tonumber(o, &n); } LUA_API int lua_isstring (lua_State *L, int idx) { int t = lua_type(L, idx); return (t == LUA_TSTRING || t == LUA_TNUMBER); } LUA_API int lua_isuserdata (lua_State *L, int idx) { const TValue *o = index2addr(L, idx); return (ttisuserdata(o) || ttislightuserdata(o)); } LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { StkId o1 = index2addr(L, index1); StkId o2 = index2addr(L, index2); return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; } LUA_API void lua_arith (lua_State *L, int op) { StkId o1; /* 1st operand */ StkId o2; /* 2nd operand */ lua_lock(L); if (op != LUA_OPUNM) /* all other operations expect two operands */ api_checknelems(L, 2); else { /* for unary minus, add fake 2nd operand */ api_checknelems(L, 1); setobjs2s(L, L->top, L->top - 1); L->top++; } o1 = L->top - 2; o2 = L->top - 1; if (ttisnumber(o1) && ttisnumber(o2)) { setnvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2))); } else luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD)); L->top--; lua_unlock(L); } LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { StkId o1, o2; int i = 0; lua_lock(L); /* may call tag method */ o1 = index2addr(L, index1); o2 = index2addr(L, index2); if (isvalid(o1) && isvalid(o2)) { switch (op) { case LUA_OPEQ: i = equalobj(L, o1, o2); break; case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; default: api_check(L, 0, "invalid option"); } } lua_unlock(L); return i; } LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *isnum) { TValue n; const TValue *o = index2addr(L, idx); if (tonumber(o, &n)) { if (isnum) *isnum = 1; return nvalue(o); } else { if (isnum) *isnum = 0; return 0; } } LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum) { TValue n; const TValue *o = index2addr(L, idx); if (tonumber(o, &n)) { lua_Integer res; lua_Number num = nvalue(o); lua_number2integer(res, num); if (isnum) *isnum = 1; return res; } else { if (isnum) *isnum = 0; return 0; } } LUA_API lua_Unsigned lua_tounsignedx (lua_State *L, int idx, int *isnum) { TValue n; const TValue *o = index2addr(L, idx); if (tonumber(o, &n)) { lua_Unsigned res; lua_Number num = nvalue(o); lua_number2unsigned(res, num); if (isnum) *isnum = 1; return res; } else { if (isnum) *isnum = 0; return 0; } } LUA_API int lua_toboolean (lua_State *L, int idx) { const TValue *o = index2addr(L, idx); return !l_isfalse(o); } LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { StkId o = index2addr(L, idx); if (!ttisstring(o)) { lua_lock(L); /* `luaV_tostring' may create a new string */ if (!luaV_tostring(L, o)) { /* conversion failed? */ if (len != NULL) *len = 0; lua_unlock(L); return NULL; } luaC_checkGC(L); o = index2addr(L, idx); /* previous call may reallocate the stack */ lua_unlock(L); } if (len != NULL) *len = tsvalue(o)->len; return svalue(o); } LUA_API size_t lua_rawlen (lua_State *L, int idx) { StkId o = index2addr(L, idx); switch (ttypenv(o)) { case LUA_TSTRING: return tsvalue(o)->len; case LUA_TUSERDATA: return uvalue(o)->len; case LUA_TTABLE: return luaH_getn(hvalue(o)); default: return 0; } } LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { StkId o = index2addr(L, idx); if (ttislcf(o)) return fvalue(o); else if (ttisCclosure(o)) return clCvalue(o)->f; else return NULL; /* not a C function */ } LUA_API void *lua_touserdata (lua_State *L, int idx) { StkId o = index2addr(L, idx); switch (ttypenv(o)) { case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } } LUA_API lua_State *lua_tothread (lua_State *L, int idx) { StkId o = index2addr(L, idx); return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TLCL: return clLvalue(o); case LUA_TCCL: return clCvalue(o); case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); case LUA_TTHREAD: return thvalue(o); case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: return lua_touserdata(L, idx); default: return NULL; } } /* ** push functions (C -> stack) */ LUA_API void lua_pushnil (lua_State *L) { lua_lock(L); setnilvalue(L->top); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { lua_lock(L); setnvalue(L->top, n); luai_checknum(L, L->top, luaG_runerror(L, "C API - attempt to push a signaling NaN")); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { lua_lock(L); setnvalue(L->top, cast_num(n)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushunsigned (lua_State *L, lua_Unsigned u) { lua_Number n; lua_lock(L); n = lua_unsigned2number(u); setnvalue(L->top, n); api_incr_top(L); lua_unlock(L); } LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { TString *ts; lua_lock(L); luaC_checkGC(L); ts = luaS_newlstr(L, s, len); setsvalue2s(L, L->top, ts); api_incr_top(L); lua_unlock(L); return getstr(ts); } LUA_API const char *lua_pushstring (lua_State *L, const char *s) { if (s == NULL) { lua_pushnil(L); return NULL; } else { TString *ts; lua_lock(L); luaC_checkGC(L); ts = luaS_new(L, s); setsvalue2s(L, L->top, ts); api_incr_top(L); lua_unlock(L); return getstr(ts); } } LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp) { const char *ret; lua_lock(L); luaC_checkGC(L); ret = luaO_pushvfstring(L, fmt, argp); lua_unlock(L); return ret; } LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { const char *ret; va_list argp; lua_lock(L); luaC_checkGC(L); va_start(argp, fmt); ret = luaO_pushvfstring(L, fmt, argp); va_end(argp); lua_unlock(L); return ret; } LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { lua_lock(L); if (n == 0) { setfvalue(L->top, fn); } else { Closure *cl; api_checknelems(L, n); api_check(L, n <= MAXUPVAL, "upvalue index too large"); luaC_checkGC(L); cl = luaF_newCclosure(L, n); cl->c.f = fn; L->top -= n; while (n--) setobj2n(L, &cl->c.upvalue[n], L->top + n); setclCvalue(L, L->top, cl); } api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushboolean (lua_State *L, int b) { lua_lock(L); setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { lua_lock(L); setpvalue(L->top, p); api_incr_top(L); lua_unlock(L); } LUA_API int lua_pushthread (lua_State *L) { lua_lock(L); setthvalue(L, L->top, L); api_incr_top(L); lua_unlock(L); return (G(L)->mainthread == L); } /* ** get functions (Lua -> stack) */ LUA_API void lua_getglobal (lua_State *L, const char *var) { Table *reg = hvalue(&G(L)->l_registry); const TValue *gt; /* global table */ lua_lock(L); gt = luaH_getint(reg, LUA_RIDX_GLOBALS); setsvalue2s(L, L->top++, luaS_new(L, var)); luaV_gettable(L, gt, L->top - 1, L->top - 1); lua_unlock(L); } LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); } LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { StkId t; lua_lock(L); t = index2addr(L, idx); setsvalue2s(L, L->top, luaS_new(L, k)); api_incr_top(L); luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); } LUA_API void lua_rawget (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); } LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { StkId t; lua_lock(L); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setobj2s(L, L->top, luaH_getint(hvalue(t), n)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_rawgetp (lua_State *L, int idx, const void *p) { StkId t; TValue k; lua_lock(L); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setpvalue(&k, cast(void *, p)); setobj2s(L, L->top, luaH_get(hvalue(t), &k)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { Table *t; lua_lock(L); luaC_checkGC(L); t = luaH_new(L); sethvalue(L, L->top, t); api_incr_top(L); if (narray > 0 || nrec > 0) luaH_resize(L, t, narray, nrec); lua_unlock(L); } LUA_API int lua_getmetatable (lua_State *L, int objindex) { const TValue *obj; Table *mt = NULL; int res; lua_lock(L); obj = index2addr(L, objindex); switch (ttypenv(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; break; case LUA_TUSERDATA: mt = uvalue(obj)->metatable; break; default: mt = G(L)->mt[ttypenv(obj)]; break; } if (mt == NULL) res = 0; else { sethvalue(L, L->top, mt); api_incr_top(L); res = 1; } lua_unlock(L); return res; } LUA_API void lua_getuservalue (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2addr(L, idx); api_check(L, ttisuserdata(o), "userdata expected"); if (uvalue(o)->env) { sethvalue(L, L->top, uvalue(o)->env); } else setnilvalue(L->top); api_incr_top(L); lua_unlock(L); } /* ** set functions (stack -> Lua) */ LUA_API void lua_setglobal (lua_State *L, const char *var) { Table *reg = hvalue(&G(L)->l_registry); const TValue *gt; /* global table */ lua_lock(L); api_checknelems(L, 1); gt = luaH_getint(reg, LUA_RIDX_GLOBALS); setsvalue2s(L, L->top++, luaS_new(L, var)); luaV_settable(L, gt, L->top - 1, L->top - 2); L->top -= 2; /* pop value and key */ lua_unlock(L); } LUA_API void lua_settable (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); t = index2addr(L, idx); luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ lua_unlock(L); } LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { StkId t; lua_lock(L); api_checknelems(L, 1); t = index2addr(L, idx); setsvalue2s(L, L->top++, luaS_new(L, k)); luaV_settable(L, t, L->top - 1, L->top - 2); L->top -= 2; /* pop value and key */ lua_unlock(L); } LUA_API void lua_rawset (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); invalidateTMcache(hvalue(t)); luaC_barrierback(L, gcvalue(t), L->top-1); L->top -= 2; lua_unlock(L); } LUA_API void lua_rawseti (lua_State *L, int idx, int n) { StkId t; lua_lock(L); api_checknelems(L, 1); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); luaH_setint(L, hvalue(t), n, L->top - 1); luaC_barrierback(L, gcvalue(t), L->top-1); L->top--; lua_unlock(L); } LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { StkId t; TValue k; lua_lock(L); api_checknelems(L, 1); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setpvalue(&k, cast(void *, p)); setobj2t(L, luaH_set(L, hvalue(t), &k), L->top - 1); luaC_barrierback(L, gcvalue(t), L->top - 1); L->top--; lua_unlock(L); } LUA_API int lua_setmetatable (lua_State *L, int objindex) { TValue *obj; Table *mt; lua_lock(L); api_checknelems(L, 1); obj = index2addr(L, objindex); if (ttisnil(L->top - 1)) mt = NULL; else { api_check(L, ttistable(L->top - 1), "table expected"); mt = hvalue(L->top - 1); } switch (ttypenv(obj)) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) { luaC_objbarrierback(L, gcvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt); } break; } case LUA_TUSERDATA: { uvalue(obj)->metatable = mt; if (mt) { luaC_objbarrier(L, rawuvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt); } break; } default: { G(L)->mt[ttypenv(obj)] = mt; break; } } L->top--; lua_unlock(L); return 1; } LUA_API void lua_setuservalue (lua_State *L, int idx) { StkId o; lua_lock(L); api_checknelems(L, 1); o = index2addr(L, idx); api_check(L, ttisuserdata(o), "userdata expected"); if (ttisnil(L->top - 1)) uvalue(o)->env = NULL; else { api_check(L, ttistable(L->top - 1), "table expected"); uvalue(o)->env = hvalue(L->top - 1); luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); } L->top--; lua_unlock(L); } /* ** `load' and `call' functions (run Lua code) */ #define checkresults(L,na,nr) \ api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ "results from function overflow current stack size") LUA_API int lua_getctx (lua_State *L, int *ctx) { if (L->ci->callstatus & CIST_YIELDED) { if (ctx) *ctx = L->ci->u.c.ctx; return L->ci->u.c.status; } else return LUA_OK; } LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, lua_CFunction k) { StkId func; lua_lock(L); api_check(L, k == NULL || !isLua(L->ci), "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); checkresults(L, nargs, nresults); func = L->top - (nargs+1); if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ L->ci->u.c.k = k; /* save continuation */ L->ci->u.c.ctx = ctx; /* save context */ luaD_call(L, func, nresults, 1); /* do the call */ } else /* no continuation or no yieldable */ luaD_call(L, func, nresults, 0); /* just do the call */ adjustresults(L, nresults); lua_unlock(L); } /* ** Execute a protected call. */ struct CallS { /* data to `f_call' */ StkId func; int nresults; }; static void f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); luaD_call(L, c->func, c->nresults, 0); } LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, int ctx, lua_CFunction k) { struct CallS c; int status; ptrdiff_t func; lua_lock(L); api_check(L, k == NULL || !isLua(L->ci), "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); checkresults(L, nargs, nresults); if (errfunc == 0) func = 0; else { StkId o = index2addr(L, errfunc); api_checkstackindex(L, errfunc, o); func = savestack(L, o); } c.func = L->top - (nargs+1); /* function to be called */ if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ c.nresults = nresults; /* do a 'conventional' protected call */ status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); } else { /* prepare continuation (call is already protected by 'resume') */ CallInfo *ci = L->ci; ci->u.c.k = k; /* save continuation */ ci->u.c.ctx = ctx; /* save context */ /* save information for error recovery */ ci->extra = savestack(L, c.func); ci->u.c.old_allowhook = L->allowhook; ci->u.c.old_errfunc = L->errfunc; L->errfunc = func; /* mark that function may do error recovery */ ci->callstatus |= CIST_YPCALL; luaD_call(L, c.func, nresults, 1); /* do the call */ ci->callstatus &= ~CIST_YPCALL; L->errfunc = ci->u.c.old_errfunc; status = LUA_OK; /* if it is here, there were no errors */ } adjustresults(L, nresults); lua_unlock(L); return status; } LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname, const char *mode) { ZIO z; int status; lua_lock(L); if (!chunkname) chunkname = "?"; luaZ_init(L, &z, reader, data); status = luaD_protectedparser(L, &z, chunkname, mode); if (status == LUA_OK) { /* no errors? */ LClosure *f = clLvalue(L->top - 1); /* get newly created function */ if (f->nupvalues == 1) { /* does it have one upvalue? */ /* get global table from registry */ Table *reg = hvalue(&G(L)->l_registry); const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ setobj(L, f->upvals[0]->v, gt); luaC_barrier(L, f->upvals[0], gt); } } lua_unlock(L); return status; } LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { int status; TValue *o; lua_lock(L); api_checknelems(L, 1); o = L->top - 1; if (isLfunction(o)) status = luaU_dump(L, getproto(o), writer, data, 0); else status = 1; lua_unlock(L); return status; } LUA_API int lua_status (lua_State *L) { return L->status; } /* ** Garbage-collection function */ LUA_API int lua_gc (lua_State *L, int what, int data) { int res = 0; global_State *g; lua_lock(L); g = G(L); switch (what) { case LUA_GCSTOP: { g->gcrunning = 0; break; } case LUA_GCRESTART: { luaE_setdebt(g, 0); g->gcrunning = 1; break; } case LUA_GCCOLLECT: { luaC_fullgc(L, 0); break; } case LUA_GCCOUNT: { /* GC values are expressed in Kbytes: #bytes/2^10 */ res = cast_int(gettotalbytes(g) >> 10); break; } case LUA_GCCOUNTB: { res = cast_int(gettotalbytes(g) & 0x3ff); break; } case LUA_GCSTEP: { if (g->gckind == KGC_GEN) { /* generational mode? */ res = (g->GCestimate == 0); /* true if it will do major collection */ luaC_forcestep(L); /* do a single step */ } else { lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE; if (g->gcrunning) debt += g->GCdebt; /* include current debt */ luaE_setdebt(g, debt); luaC_forcestep(L); if (g->gcstate == GCSpause) /* end of cycle? */ res = 1; /* signal it */ } break; } case LUA_GCSETPAUSE: { res = g->gcpause; g->gcpause = data; break; } case LUA_GCSETMAJORINC: { res = g->gcmajorinc; g->gcmajorinc = data; break; } case LUA_GCSETSTEPMUL: { res = g->gcstepmul; g->gcstepmul = data; break; } case LUA_GCISRUNNING: { res = g->gcrunning; break; } case LUA_GCGEN: { /* change collector to generational mode */ luaC_changemode(L, KGC_GEN); break; } case LUA_GCINC: { /* change collector to incremental mode */ luaC_changemode(L, KGC_NORMAL); break; } default: res = -1; /* invalid option */ } lua_unlock(L); return res; } /* ** miscellaneous functions */ LUA_API int lua_error (lua_State *L) { lua_lock(L); api_checknelems(L, 1); luaG_errormsg(L); /* code unreachable; will unlock when control actually leaves the kernel */ return 0; /* to avoid warnings */ } LUA_API int lua_next (lua_State *L, int idx) { StkId t; int more; lua_lock(L); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); more = luaH_next(L, hvalue(t), L->top - 1); if (more) { api_incr_top(L); } else /* no more elements */ L->top -= 1; /* remove key */ lua_unlock(L); return more; } LUA_API void lua_concat (lua_State *L, int n) { lua_lock(L); api_checknelems(L, n); if (n >= 2) { luaC_checkGC(L); luaV_concat(L, n); } else if (n == 0) { /* push empty string */ setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); api_incr_top(L); } /* else n == 1; nothing to do */ lua_unlock(L); } LUA_API void lua_len (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); luaV_objlen(L, L->top, t); api_incr_top(L); lua_unlock(L); } LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { lua_Alloc f; lua_lock(L); if (ud) *ud = G(L)->ud; f = G(L)->frealloc; lua_unlock(L); return f; } LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { lua_lock(L); G(L)->ud = ud; G(L)->frealloc = f; lua_unlock(L); } LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); u = luaS_newudata(L, size, NULL); setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); return u + 1; } static const char *aux_upvalue (StkId fi, int n, TValue **val, GCObject **owner) { switch (ttype(fi)) { case LUA_TCCL: { /* C closure */ CClosure *f = clCvalue(fi); if (!(1 <= n && n <= f->nupvalues)) return NULL; *val = &f->upvalue[n-1]; if (owner) *owner = obj2gco(f); return ""; } case LUA_TLCL: { /* Lua closure */ LClosure *f = clLvalue(fi); TString *name; Proto *p = f->p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->upvals[n-1]->v; if (owner) *owner = obj2gco(f->upvals[n - 1]); name = p->upvalues[n-1].name; return (name == NULL) ? "" : getstr(name); } default: return NULL; /* not a closure */ } } LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val = NULL; /* to avoid warnings */ lua_lock(L); name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); if (name) { setobj2s(L, L->top, val); api_incr_top(L); } lua_unlock(L); return name; } LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val = NULL; /* to avoid warnings */ GCObject *owner = NULL; /* to avoid warnings */ StkId fi; lua_lock(L); fi = index2addr(L, funcindex); api_checknelems(L, 1); name = aux_upvalue(fi, n, &val, &owner); if (name) { L->top--; setobj(L, val, L->top); luaC_barrier(L, owner, L->top); } lua_unlock(L); return name; } static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { LClosure *f; StkId fi = index2addr(L, fidx); api_check(L, ttisLclosure(fi), "Lua function expected"); f = clLvalue(fi); api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); if (pf) *pf = f; return &f->upvals[n - 1]; /* get its upvalue pointer */ } LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { StkId fi = index2addr(L, fidx); switch (ttype(fi)) { case LUA_TLCL: { /* lua closure */ return *getupvalref(L, fidx, n, NULL); } case LUA_TCCL: { /* C closure */ CClosure *f = clCvalue(fi); api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index"); return &f->upvalue[n - 1]; } default: { api_check(L, 0, "closure expected"); return NULL; } } } LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, int fidx2, int n2) { LClosure *f1; UpVal **up1 = getupvalref(L, fidx1, n1, &f1); UpVal **up2 = getupvalref(L, fidx2, n2, NULL); *up1 = *up2; luaC_objbarrier(L, f1, *up2); } blobby-1.0/src/PhysicWorld.cpp000644 001750 001750 00000030376 12313310252 021156 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "PhysicWorld.h" /* includes */ #include #include "raknet/BitStream.h" #include "GameConstants.h" #include "MatchEvents.h" /* implementation */ const int TIMESTEP = 5; // calculations per frame const float TIMEOUT_MAX = 2.5; // Gamefeeling relevant constants: const float BLOBBY_ANIMATION_SPEED = 0.5; // helper function for setting FPU precision inline short set_fpu_single_precision(); void reset_fpu_flags(short flags); PhysicWorld::PhysicWorld() : mBallPosition(Vector2(200, STANDARD_BALL_HEIGHT)) , mBallRotation(0) , mBallAngularVelocity(STANDARD_BALL_ANGULAR_VELOCITY) , mLastHitIntensity(0) { mCurrentBlobbyAnimationSpeed[LEFT_PLAYER] = 0.0; mCurrentBlobbyAnimationSpeed[RIGHT_PLAYER] = 0.0; mBlobState[LEFT_PLAYER] = 0.0; mBlobState[RIGHT_PLAYER] = 0.0; mBlobPosition[LEFT_PLAYER] = Vector2( 200, GROUND_PLANE_HEIGHT); mBlobPosition[RIGHT_PLAYER] = Vector2(600, GROUND_PLANE_HEIGHT); } PhysicWorld::~PhysicWorld() { } bool PhysicWorld::blobHitGround(PlayerSide player) const { if (player == LEFT_PLAYER || player == RIGHT_PLAYER) { return (getBlobPosition(player).y >= GROUND_PLANE_HEIGHT); } else return false; } void PhysicWorld::setLastHitIntensity(float intensity) { mLastHitIntensity = intensity; } float PhysicWorld::getLastHitIntensity() const { float intensity = mLastHitIntensity / 25.0; return intensity < 1.0 ? intensity : 1.0; } bool PhysicWorld::playerTopBallCollision(int player) const { if (Vector2(mBallPosition, Vector2(mBlobPosition[player].x, mBlobPosition[player].y - BLOBBY_UPPER_SPHERE)).length() <= BALL_RADIUS + BLOBBY_UPPER_RADIUS) return true; return false; } inline bool PhysicWorld::playerBottomBallCollision(int player) const { if (Vector2(mBallPosition, Vector2(mBlobPosition[player].x, mBlobPosition[player].y + BLOBBY_LOWER_SPHERE)).length() <= BALL_RADIUS + BLOBBY_LOWER_RADIUS) return true; return false; } float PhysicWorld::getBallRotation() const { return mBallRotation; } Vector2 PhysicWorld::getBlobPosition(PlayerSide player) const { return mBlobPosition[player]; } Vector2 PhysicWorld::getBlobVelocity(PlayerSide player) const { return mBlobVelocity[player]; } float PhysicWorld::getBlobState(PlayerSide player) const { return mBlobState[player]; } // Blobby animation methods void PhysicWorld::blobbyAnimationStep(PlayerSide player) { if (mBlobState[player] < 0.0) { mCurrentBlobbyAnimationSpeed[player] = 0; mBlobState[player] = 0; } if (mBlobState[player] >= 4.5) { mCurrentBlobbyAnimationSpeed[player] = -BLOBBY_ANIMATION_SPEED; } mBlobState[player] += mCurrentBlobbyAnimationSpeed[player]; if (mBlobState[player] >= 5) { mBlobState[player] = 4.99; } } void PhysicWorld::blobbyStartAnimation(PlayerSide player) { if (mCurrentBlobbyAnimationSpeed[player] == 0) mCurrentBlobbyAnimationSpeed[player] = BLOBBY_ANIMATION_SPEED; } void PhysicWorld::handleBlob(PlayerSide player, PlayerInput input) { float currentBlobbyGravity = GRAVITATION; if (input.up) { if (blobHitGround(player)) { mBlobVelocity[player].y = -BLOBBY_JUMP_ACCELERATION; blobbyStartAnimation( player ); } currentBlobbyGravity -= BLOBBY_JUMP_BUFFER; } if ((input.left || input.right) && blobHitGround(player)) { blobbyStartAnimation(player); } mBlobVelocity[player].x = (input.right ? BLOBBY_SPEED : 0) - (input.left ? BLOBBY_SPEED : 0); // compute blobby fall movement (dt = 1) // ds = a/2 * dt^2 + v * dt mBlobPosition[player] += Vector2(0, 0.5f * currentBlobbyGravity ) + mBlobVelocity[player]; // dv = a * dt mBlobVelocity[player].y += currentBlobbyGravity; // Hitting the ground if (mBlobPosition[player].y > GROUND_PLANE_HEIGHT) { if(mBlobVelocity[player].y > 3.5) { blobbyStartAnimation(player); } mBlobPosition[player].y = GROUND_PLANE_HEIGHT; mBlobVelocity[player].y = 0.0; } blobbyAnimationStep(player); } bool PhysicWorld::handleBlobbyBallCollision(PlayerSide player) { // Check for bottom circles if(playerBottomBallCollision(player)) { mLastHitIntensity = Vector2(mBallVelocity, mBlobVelocity[player]).length(); const Vector2& blobpos = mBlobPosition[player]; const Vector2 circlepos = Vector2(blobpos.x, blobpos.y + BLOBBY_LOWER_SPHERE); mBallVelocity = -Vector2(mBallPosition, circlepos); mBallVelocity = mBallVelocity.normalise(); mBallVelocity = mBallVelocity.scale(BALL_COLLISION_VELOCITY); mBallPosition += mBallVelocity; return true; } else if(playerTopBallCollision(player)) { mLastHitIntensity = Vector2(mBallVelocity, mBlobVelocity[player]).length(); const Vector2& blobpos = mBlobPosition[player]; const Vector2 circlepos = Vector2(blobpos.x, blobpos.y - BLOBBY_UPPER_SPHERE); mBallVelocity = -Vector2(mBallPosition, circlepos); mBallVelocity = mBallVelocity.normalise(); mBallVelocity = mBallVelocity.scale(BALL_COLLISION_VELOCITY); mBallPosition += mBallVelocity; return true; } return false; } int PhysicWorld::step(const PlayerInput& leftInput, const PlayerInput& rightInput, bool isBallValid, bool isGameRunning) { // Determistic IEEE 754 floating point computations short fpf = set_fpu_single_precision(); int events = 0; // Compute independent actions handleBlob(LEFT_PLAYER, leftInput); handleBlob(RIGHT_PLAYER, rightInput); // Move ball when game is running if (isGameRunning) { // dt = 1 !! // move ball ds = a/2 * dt^2 + v * dt mBallPosition += Vector2(0, 0.5f * BALL_GRAVITATION) + mBallVelocity; // dv = a*dt mBallVelocity.y += BALL_GRAVITATION; } // Collision detection if(isBallValid) { if (handleBlobbyBallCollision(LEFT_PLAYER)) events |= EVENT_LEFT_BLOBBY_HIT; if (handleBlobbyBallCollision(RIGHT_PLAYER)) events |= EVENT_RIGHT_BLOBBY_HIT; } // Ball to ground Collision if (mBallPosition.y + BALL_RADIUS > GROUND_PLANE_HEIGHT_MAX) { mBallVelocity = mBallVelocity.reflectY(); mBallVelocity = mBallVelocity.scale(0.95); mBallPosition.y = GROUND_PLANE_HEIGHT_MAX - BALL_RADIUS; events |= mBallPosition.x > NET_POSITION_X ? EVENT_BALL_HIT_RIGHT_GROUND : EVENT_BALL_HIT_LEFT_GROUND; } // Border Collision if (mBallPosition.x - BALL_RADIUS <= LEFT_PLANE && mBallVelocity.x < 0.0) { mBallVelocity = mBallVelocity.reflectX(); // set the ball's position mBallPosition.x = LEFT_PLANE + BALL_RADIUS; events |= EVENT_BALL_HIT_LEFT_WALL; } else if (mBallPosition.x + BALL_RADIUS >= RIGHT_PLANE && mBallVelocity.x > 0.0) { mBallVelocity = mBallVelocity.reflectX(); // set the ball's position mBallPosition.x = RIGHT_PLANE - BALL_RADIUS; events |= EVENT_BALL_HIT_RIGHT_WALL; } else if (mBallPosition.y > NET_SPHERE_POSITION && fabs(mBallPosition.x - NET_POSITION_X) < BALL_RADIUS + NET_RADIUS) { bool right = mBallPosition.x - NET_POSITION_X > 0; mBallVelocity = mBallVelocity.reflectX(); // set the ball's position so that it touches the net mBallPosition.x = NET_POSITION_X + (right ? (BALL_RADIUS + NET_RADIUS) : (-BALL_RADIUS - NET_RADIUS)); events |= right ? EVENT_BALL_HIT_NET_RIGHT : EVENT_BALL_HIT_NET_LEFT; } else { // Net Collisions float ballNetDistance = Vector2(mBallPosition, Vector2(NET_POSITION_X, NET_SPHERE_POSITION)).length(); if (ballNetDistance < NET_RADIUS + BALL_RADIUS) { // calculate Vector2 normal = Vector2(mBallPosition, Vector2(NET_POSITION_X, NET_SPHERE_POSITION)).normalise(); // normal component of kinetic energy float perp_ekin = normal.dotProduct(mBallVelocity); perp_ekin *= perp_ekin; // parallel component of kinetic energy float para_ekin = mBallVelocity.length() * mBallVelocity.length() - perp_ekin; // the normal component is damped stronger than the parallel component // the values are ~ 0.85 and ca. 0.95, because speed is sqrt(ekin) perp_ekin *= 0.7; para_ekin *= 0.9; float nspeed = sqrt(perp_ekin + para_ekin); mBallVelocity = Vector2(mBallVelocity.reflect(normal).normalise().scale(nspeed)); // pushes the ball out of the net mBallPosition = (Vector2(NET_POSITION_X, NET_SPHERE_POSITION) - normal * (NET_RADIUS + BALL_RADIUS)); events |= EVENT_BALL_HIT_NET_TOP; } // mBallVelocity = mBallVelocity.reflect( Vector2( mBallPosition, Vector2 (NET_POSITION_X, temp) ).normalise()).scale(0.75); } // Collision between blobby and the net if (mBlobPosition[LEFT_PLAYER].x+BLOBBY_LOWER_RADIUS>NET_POSITION_X-NET_RADIUS) // Collision with the net mBlobPosition[LEFT_PLAYER].x=NET_POSITION_X-NET_RADIUS-BLOBBY_LOWER_RADIUS; if (mBlobPosition[RIGHT_PLAYER].x-BLOBBY_LOWER_RADIUS RIGHT_PLANE) mBlobPosition[RIGHT_PLAYER].x=RIGHT_PLANE; // Velocity Integration if( !isGameRunning ) mBallRotation -= mBallAngularVelocity; else if (mBallVelocity.x > 0.0) mBallRotation += mBallAngularVelocity * (mBallVelocity.length() / 6); else mBallRotation -= mBallAngularVelocity * (mBallVelocity.length()/ 6); // Overflow-Protection if (mBallRotation <= 0) mBallRotation = 6.25 + mBallRotation; else if (mBallRotation >= 6.25) mBallRotation = mBallRotation - 6.25; reset_fpu_flags(fpf); return events; } Vector2 PhysicWorld::getBallPosition() const { return mBallPosition; } void PhysicWorld::setBallPosition( Vector2 newPosition ) { /// \todo should we check here if this new position is valid, i.e. not inside walls etc. mBallPosition = newPosition; } Vector2 PhysicWorld::getBallVelocity() const { return mBallVelocity; } void PhysicWorld::setBallVelocity( Vector2 newVelocity ) { mBallVelocity = newVelocity; } void PhysicWorld::setBallAngularVelocity( float angvel ) { mBallAngularVelocity = angvel; } PhysicState PhysicWorld::getState() const { PhysicState st; st.blobPosition[LEFT_PLAYER] = mBlobPosition[LEFT_PLAYER]; st.blobPosition[RIGHT_PLAYER] = mBlobPosition[RIGHT_PLAYER]; st.blobVelocity[LEFT_PLAYER] = mBlobVelocity[LEFT_PLAYER]; st.blobVelocity[RIGHT_PLAYER] = mBlobVelocity[RIGHT_PLAYER]; st.ballPosition = mBallPosition; st.ballVelocity = mBallVelocity; st.ballAngularVelocity = mBallAngularVelocity; return st; } void PhysicWorld::setState(const PhysicState& ps) { mBlobPosition[LEFT_PLAYER] = ps.blobPosition[LEFT_PLAYER]; mBlobPosition[RIGHT_PLAYER] = ps.blobPosition[RIGHT_PLAYER]; mBlobVelocity[LEFT_PLAYER] = ps.blobVelocity[LEFT_PLAYER]; mBlobVelocity[RIGHT_PLAYER] = ps.blobVelocity[RIGHT_PLAYER]; mBallPosition = ps.ballPosition; mBallVelocity = ps.ballVelocity; mBallAngularVelocity = ps.ballAngularVelocity; } inline short set_fpu_single_precision() { short fl = 0; #if defined(i386) || defined(__x86_64) // We need to set a precision for diverse x86 hardware #if defined(__GNUC__) volatile short cw; asm volatile ("fstcw %0" : "=m"(cw)); fl = cw; cw = cw & 0xfcff; asm volatile ("fldcw %0" :: "m"(cw)); #elif defined(_MSC_VER) short cw; asm fstcw cw; fl = cw; cw = cw & 0xfcff; asm fldcw cw; #endif #else #warning FPU precision may not conform to IEEE 754 #endif return fl; } void reset_fpu_flags(short flags) { #if defined(i386) || defined(__x86_64) // We need to set a precision for diverse x86 hardware #if defined(__GNUC__) asm volatile ("fldcw %0" :: "m"(flags)); #elif defined(_MSC_VER) asm fldcw flags; #endif #else #warning FPU precision may not conform to IEEE 754 #endif } blobby-1.0/src/raknet/SocketLayer.cpp000644 001750 001750 00000022537 12313310247 022424 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief SocketLayer class implementation * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "../blobnet/Logger.hpp" #include "SocketLayer.h" #include #include "MTUSize.h" #ifdef _WIN32 #include typedef int socklen_t; #else #include // memcpy #include #endif int SocketLayer::socketLayerInstanceCount = 0; SocketLayer SocketLayer::I; #ifdef _WIN32 extern void __stdcall ProcessNetworkPacket( unsigned int binaryAddress, unsigned short port, const char *data, int length, RakPeer *rakPeer ); #else extern void ProcessNetworkPacket( unsigned int binaryAddress, unsigned short port, const char *data, int length, RakPeer *rakPeer ); #endif #ifdef _DEBUG #include #endif SocketLayer::SocketLayer() { // Check if the socketlayer is already started if (socketLayerInstanceCount == 0) { #ifdef _WIN32 WSADATA winsockInfo; // Initiate use of the Winsock DLL (Up to Verion 2.2) if (WSAStartup(MAKEWORD(2, 2), &winsockInfo ) != 0) { LOG("SocketLayer", "WSAStartup failed") } #endif } // increase usecount socketLayerInstanceCount++; } SocketLayer::~SocketLayer() { if (socketLayerInstanceCount == 1) { #ifdef _WIN32 // Terminate use of the Winsock DLL WSACleanup(); #endif } // decrease usecount socketLayerInstanceCount--; } SOCKET SocketLayer::Connect(SOCKET writeSocket, unsigned int binaryAddress, unsigned short port) { assert(writeSocket != INVALID_SOCKET); sockaddr_in connectSocketAddress; connectSocketAddress.sin_family = AF_INET; connectSocketAddress.sin_port = htons( port ); connectSocketAddress.sin_addr.s_addr = binaryAddress; if ( connect( writeSocket, ( struct sockaddr * ) & connectSocketAddress, sizeof( struct sockaddr ) ) != 0 ) { LOG("SocketLayer", "WSAConnect failed") } return writeSocket; } #pragma warning( disable : 4100 ) // warning C4100: : unreferenced formal parameter SOCKET SocketLayer::CreateBoundSocket( unsigned short port, bool blockingSocket, const char *forceHostAddress ) { SOCKET listenSocket; sockaddr_in listenerSocketAddress; int ret; listenSocket = socket( AF_INET, SOCK_DGRAM, 0 ); if ( listenSocket == INVALID_SOCKET ) { LOG("SocketLayer", "socket(...) failed") return INVALID_SOCKET; } int sock_opt = 1; if ( setsockopt( listenSocket, SOL_SOCKET, SO_REUSEADDR, ( char * ) & sock_opt, sizeof ( sock_opt ) ) == -1 ) { LOG("SocketLayer", "setsockopt(SO_REUSEADDR) failed") } //Set non-blocking #ifdef _WIN32 unsigned long nonblocking = 1; if ( ioctlsocket( listenSocket, FIONBIO, &nonblocking ) != 0 ) { assert( 0 ); return INVALID_SOCKET; } #else if ( fcntl( listenSocket, F_SETFL, O_NONBLOCK ) != 0 ) { assert( 0 ); return INVALID_SOCKET; } #endif // Set broadcast capable if ( setsockopt( listenSocket, SOL_SOCKET, SO_BROADCAST, ( char * ) & sock_opt, sizeof( sock_opt ) ) == -1 ) { LOG("SocketLayer", "setsockopt(SO_BROADCAST) failed") } // Listen on our designated Port# listenerSocketAddress.sin_port = htons( port ); // Fill in the rest of the address structure listenerSocketAddress.sin_family = AF_INET; if (forceHostAddress) { listenerSocketAddress.sin_addr.s_addr = inet_addr( forceHostAddress ); } else { listenerSocketAddress.sin_addr.s_addr = INADDR_ANY; } // bind our name to the socket ret = bind( listenSocket, ( struct sockaddr * ) & listenerSocketAddress, sizeof( struct sockaddr ) ); if ( ret == SOCKET_ERROR ) { LOG("SocketLayer", "bind(...) failed") return INVALID_SOCKET; } return listenSocket; } const char* SocketLayer::DomainNameToIP( const char *domainName ) { struct hostent * phe = gethostbyname( domainName ); if ( phe == 0 || phe->h_addr_list[ 0 ] == 0 ) { //cerr << "Yow! Bad host lookup." << endl; return 0; } struct in_addr addr; memcpy( &addr, phe->h_addr_list[ 0 ], sizeof( struct in_addr ) ); return inet_ntoa( addr ); } int SocketLayer::Write( SOCKET writeSocket, const char* data, int length ) { #ifdef _DEBUG assert( writeSocket != INVALID_SOCKET ); #endif return send( writeSocket, data, length, 0 ); } int SocketLayer::RecvFrom( SOCKET s, RakPeer *rakPeer, int *errorCode ) { int len; char data[ MAXIMUM_MTU_SIZE ]; sockaddr_in sa; unsigned short portnum; socklen_t len2 = sizeof( struct sockaddr_in ); sa.sin_family = AF_INET; #ifdef _DEBUG portnum = 0; data[ 0 ] = 0; len = 0; sa.sin_addr.s_addr = 0; #endif if ( s == INVALID_SOCKET ) { *errorCode = SOCKET_ERROR; return SOCKET_ERROR; } len = recvfrom( s, data, MAXIMUM_MTU_SIZE, 0, ( sockaddr* ) & sa, ( socklen_t* ) & len2 ); // if (len>0) // printf("Got packet on port %i\n",ntohs(sa.sin_port)); if ( len == 0 ) { LOG("SocketLayer", "Recvfrom returned 0 on a connectionless blocking call\non port %i. This is a bug with Zone Alarm. Please turn off Zone Alarm.\n" << ntohs( sa.sin_port ) ) #ifdef _DEBUG assert( 0 ); #endif *errorCode = SOCKET_ERROR; return SOCKET_ERROR; } if ( len != SOCKET_ERROR ) { portnum = ntohs( sa.sin_port ); //strcpy(ip, inet_ntoa(sa.sin_addr)); //if (strcmp(ip, "0.0.0.0")==0) // strcpy(ip, "127.0.0.1"); ProcessNetworkPacket( sa.sin_addr.s_addr, portnum, data, len, rakPeer ); return 1; } else { *errorCode = 0; #if defined(_WIN32) && defined(_DEBUG) DWORD dwIOError = WSAGetLastError(); if ( dwIOError == WSAEWOULDBLOCK ) { return SOCKET_ERROR; } if ( dwIOError == WSAECONNRESET ) { // ProcessPortUnreachable(sa.sin_addr.s_addr, portnum, rakPeer); // this function no longer exists, as the old implementation did nothing // *errorCode = dwIOError; return SOCKET_ERROR; } else { if ( dwIOError != WSAEINTR ) { LOG("SocketLayer", "recvfrom failed") } } #endif } return 0; // no data } int SocketLayer::SendTo( SOCKET s, const char *data, int length, unsigned int binaryAddress, unsigned short port ) { if ( s == INVALID_SOCKET ) { return -1; } int len; sockaddr_in sa; sa.sin_port = htons( port ); sa.sin_addr.s_addr = binaryAddress; sa.sin_family = AF_INET; do { len = sendto( s, data, length, 0, ( const sockaddr* ) & sa, sizeof( struct sockaddr_in ) ); } while ( len == 0 ); if ( len != SOCKET_ERROR ) return 0; #if defined(_WIN32) DWORD dwIOError = WSAGetLastError(); if ( dwIOError == WSAECONNRESET ) { // LOG("A previous send operation resulted in an ICMP Port Unreachable message.\n" ) } else { LOG("SocketLayer", "recvfrom failed") } return dwIOError; #else return 1; #endif } int SocketLayer::SendTo( SOCKET s, const char *data, int length, char ip[ 16 ], unsigned short port ) { unsigned int binaryAddress; binaryAddress = inet_addr( ip ); return SendTo( s, data, length, binaryAddress, port ); } void SocketLayer::GetMyIP( char ipList[ 10 ][ 16 ] ) { // Longest possible Hostname char hostname[80]; // Get the hostname of the local maschine if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) { LOG("SocketLayer", "gethostname failed") return ; } LOG("SocketLayer", "Host name is " << hostname ) struct hostent *phe = gethostbyname( hostname ); if ( phe == 0 ) { LOG("SocketLayer", "gethostbyname failed") return ; } for ( int i = 0; phe->h_addr_list[ i ] != 0 && i < 10; ++i ) { struct in_addr addr; memcpy( &addr, phe->h_addr_list[ i ], sizeof( struct in_addr ) ); //cout << "Address " << i << ": " << inet_ntoa(addr) << endl; strcpy( ipList[ i ], inet_ntoa( addr ) ); LOG("SocketLayer", "My IP addresses "<< ipList[ i ]) } } const char* SocketLayer::nameToIP(const char* name) const { struct in_addr address; struct hostent * hostInformation = gethostbyname(name); if (hostInformation == 0 || hostInformation->h_addr_list[0] == 0) { LOG("SocketLayer", "Domainname of ip can't be resolved") return 0; } memcpy(&address, hostInformation->h_addr_list[0], sizeof(struct in_addr)); return inet_ntoa(address); } blobby-1.0/data/gfx/font09.bmp000644 001750 001750 00000003370 12313310254 020724 0ustar00danielknobedanielknobe000000 000000 BM6( @D@NRNHIHý\_[&*$OPOگq}oEME#(#SURÿΧWhW$1$  #%#իѪfe5K5"AEAƲ¤ܣYX%B$.  vuD~A'M&9 >V?igZX<:$V#> !$,$@N?RlQca~kjbbVTPK52X:*U_U\qZdcts}{҄މ`[A=!`B =I=|{ឮﭲ쏁~[X85!y I Ğע<];;O  n  £ߠol;|:5KxJok  B 3<3Ңc`0y/0  li83  u OcONJ!{=  #O$?;  VoV@;Q $   -) J`IڑEAx C   '4'Ԓda#  y Q 3 *,p kiPL    +;,if䈄c_FB=8E?KGB>4/">[ CONST_FIELD_WIDTH / 4 and posx(player) < CONST_FIELD_WIDTH * 3 / 4 then if launched(player) then if player == LEFT_PLAYER then right = false else left = false end else up = false end end return left, right, up end blobby-1.0/src/state/GameState.h000644 001750 001750 00000004736 12313310253 021350 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "State.h" /*! \class GameState \brief base class for any game related state (Local, Network, Replay) */ class GameState : public State { public: GameState(DuelMatch* match = nullptr); virtual ~GameState(); // step function defines the steps actual work virtual void step_impl() = 0; protected: /// static protected helper function that /// draws the game. It is in State because /// this functionality is shared by /// LocalGameState, NetworkGameState and ReplayState void presentGame(); /// this draws the ui in the game, i.e. clock, score and player names void presentGameUI(); // ui helpers /// this function draws the save replay ui /// it returns true if the player clicks on the OK button bool displaySaveReplayPrompt(); /// this function draws the error message box /// it returns true if the player clicks on the OK button bool displayErrorMessageBox(); /// this function draws the winning player screen /// does not display any buttons because they depend on the game type bool displayWinningPlayerScreen(PlayerSide winner); /// calculates the default name for a replay file void setDefaultReplayName(const std::string& left, const std::string& right); /// saves the replay to the desired file void saveReplay(ReplayRecorder& recorder); boost::scoped_ptr mMatch; // ui helper variable for storing a filename bool mSaveReplay; std::string mErrorMessage; private: std::string mFilename; }; blobby-1.0/data/gfx/btn_fast.bmp000644 001750 001750 00000003366 12313310254 021412 0ustar00danielknobedanielknobe000000 000000 BM6(  jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjblobby-1.0/data/scripts/old/hyperion03.lua000644 001750 001750 00000010066 12313310254 023271 0ustar00danielknobedanielknobe000000 000000 -- Hyperion v0.3 by Hyperion -- Ein paar Ideen stammen von anderen Bots, z.B. vom Combot -- Playtesting hauptsächlich gegen Combot und Dumpjump -- Bot hat noch einige Schwierigkeiten bei Netzbällen, der Aufschlag ist zu variabel und dadurch nicht gut genug -- Die Spielweise ist nicht berechnet, sondern durch Playtesting entstanden -- Wird sich vielleicht bei der nächsten Version ändern, ich habe allerdings noch keine echte Schwäche gefunden, deswegen bin ich ein bisschen unmotiviert. -- Kann noch nicht blocken und macht ab und zu Fehlaufschläge. -- Hat in meinen Tests gegen alle anderen Bots gewonnen (und gegen mich leider auch). Verliert zwar ab und zu durch Netzroller, aber ich habs nicht geschafft zwei Punkte hintereinander zu machen. -- Der Code ist stellenweise ziemlich schlecht, ich weiß. -- [Die Dimensionen der Blobbywelt] field_width = 800 field_middle = 400 ball_radius = 31.5 net_radius = 7 net_height = 323 -- Die Kugel am Netz mit eingeschlossen, das ist im Sourcecode falsch dokumentiert blobby_groesse = 89 blobby_head = 25 blobby_bottom_radius = 33 blobby_center = 100+89/2 ground = 100 plane = 220.5 -- [Die Physik in der Blobbywelt] -- Die Zeit wird in steps=t gemessen, ein step entspricht dabei einen Frame, die Geschwindigkeit ist also von der Framerate abhängig (die Spielgeschwindigkeit wird auch über die Framerate gesteuert!!! ball_grav = 0.28 -- Der Ball fällt also langsamer als der Blobby auf die Erde zurück blobby_grav = 0.44 --eigentlich 0.88 aber wenn man sprungtaste gedrückt hält dann so, da es ohne sinnlos ist, kümmern wir uns nicht um die andere blobby_speed = 4.5 blobby_jump_speed = 14.5 -- [Hilfsfunktionen] function timetoy(y) -- Funktion arbeitet korrekt, driftet nur t=0.001 pro step a=ball_grav v=bspeedy() y0=bally() t=(v/a-1/10+math.sqrt(v^2/a^2-v/(5*a)+1/100+2*(y0-y)/a)) return t end function timetox(x) v=bspeedx() x0=ballx() t=(x-x0)/v return t end function ypos(t) y=bally()+(bspeedy()-(ball_grav/10))*t-(1/2)*ball_grav*t^2 return y end function estimatef(height) x=ballx()+bspeedx()*timetoy(height) return x end function estimate(y) x=estimatef(y) if (x>ball_radius) and (x<361.5) then impact=x end if (x361.5) then if (ballx()<361.5) then if(ypos(timetox(361.5))3) then moveto(x-40) end if (timetoy(333)<10) then jump() end else x=estimate(333) if (math.abs((x-20)-posx())>3) then moveto(x-20) end if (timetoy(333)<10) then jump() end end end function ueberspielen() if (posx()<280) then x=estimate(437) if (math.abs((x-30)-posx())>3) then moveto(x-30) end if (timetoy(437)<24) then jump() end else x=estimate(437) if (math.abs((x-15)-posx())>3) then moveto(x-15) end if (timetoy(437)<24) then jump() end end end function schmettern() x=estimate(437) t=timetoy(437) if (t>24) and (math.abs((x-90)-posx())>3) then moveto(x-90) end if (t<24) then jump() end if (t<5) then right() end end -- [Hauptprogramm] function OnServe(ballready) if (new==nil) then new=1 end if (new==1) then j=math.random() p=math.random(30,55) new=2 end if (j>0.5) then if (math.abs(posx()-200)>3) then moveto(200) else jump() end else if (math.abs(posx()-(200-p))>3) then moveto(200-p) else jump() end end end function OnOpponentServe() moveto(200) end function OnGame() new=1 x=estimate(220.5) if (x<420) then if (touches()==0) then moveto(x) newp=1 end if (touches()==1) then if (newp==1) then p1=math.random() newp=2 end if (oppx()>300) then if(p1>0.4) then ueberspielen() else schmettern() end else if(p1>0.6) then ueberspielen() else schmettern() end end end if (touches()==2) then retten() end else moveto(200) end end blobby-1.0/data/gfx/font50.bmp000644 001750 001750 00000003366 12313310254 020725 0ustar00danielknobedanielknobe000000 000000 BM6( "lqlqQSFIFIFIFIFIJLZ/[Z/[P(QR3TA5224>444AźHQQTZ   }{|~~~~~""[F[aammmmmdbdNddNd?0?blobby-1.0/src/GameLogicState.h000644 001750 001750 00000003103 12313310253 021171 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include "Global.h" #include "GenericIOFwd.h" struct GameLogicState { unsigned int leftScore; unsigned int rightScore; PlayerSide servingPlayer; unsigned int leftSquish; unsigned int rightSquish; unsigned int squishWall; unsigned int squishGround; bool isGameRunning; bool isBallValid; void swapSides(); void serialize(GenericOut* io) const; void deserialize(GenericIn* io); // equality comparision bool operator==(const GameLogicState& other) const; }; std::ostream& operator<<(std::ostream&, const GameLogicState&); blobby-1.0/src/ReplayPlayer.cpp000644 001750 001750 00000010204 12313310251 021303 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "ReplayPlayer.h" /* includes */ #include #include "IReplayLoader.h" #include "DuelMatch.h" /* implementation */ ReplayPlayer::ReplayPlayer() { } ReplayPlayer::~ReplayPlayer() { } bool ReplayPlayer::endOfFile() const { return (mPosition >= mLength); } void ReplayPlayer::load(const std::string& filename) { loader.reset(IReplayLoader::createReplayLoader(filename)); mPlayerNames[LEFT_PLAYER] = loader->getPlayerName(LEFT_PLAYER); mPlayerNames[RIGHT_PLAYER] = loader->getPlayerName(RIGHT_PLAYER); mPosition = 0; mLength = loader->getLength(); } std::string ReplayPlayer::getPlayerName(const PlayerSide side) const { return mPlayerNames[side]; } Color ReplayPlayer::getBlobColor(const PlayerSide side) const { return loader->getBlobColor(side); } int ReplayPlayer::getGameSpeed() const { return loader->getSpeed(); } float ReplayPlayer::getPlayProgress() const { return (float)mPosition / mLength; } int ReplayPlayer::getReplayPosition() const { return mPosition; } int ReplayPlayer::getReplayLength() const { return mLength; } bool ReplayPlayer::play(DuelMatch* virtual_match) { mPosition++; if( mPosition < mLength ) { PlayerInput left; PlayerInput right; loader->getInputAt(mPosition, virtual_match->getInputSource( LEFT_PLAYER ).get(), virtual_match->getInputSource( RIGHT_PLAYER ).get() ); virtual_match->step(); int point; if(loader->isSavePoint(mPosition, point)) { ReplaySavePoint reference; loader->readSavePoint(point, reference); virtual_match->setState(reference.state); } // everything was as expected return true; } // error or end of file return false; } bool ReplayPlayer::gotoPlayingPosition(int rep_position, DuelMatch* virtual_match) { /// \todo add validity check for rep_position /// \todo replay clock does not work! // find next safepoint int save_position = -1; int savepoint = loader->getSavePoint(rep_position, save_position); // save position contains game step at which the save point is // savepoint is index of save point in array // now compare safepoint and actual position // if we have to forward and save_position is nearer than current position, jump if( (rep_position < mPosition || save_position > mPosition) && savepoint >= 0) { // can't use mPosition // set match to safepoint ReplaySavePoint state; loader->readSavePoint(savepoint, state); // set position and update match mPosition = save_position; virtual_match->setState(state.state); } // otherwise, use current position // this is legacy code which will make fast forwarding possible even // when we have no safepoint and have to go back if(rep_position < mPosition) { // reset the match and simulate from start! virtual_match->reset(); mPosition = 0; } // in the end, simulate the remaining steps // maximum: 100 steps for(int i = 0; i < 100; ++i) { // check if we have to do another step if(endOfFile() || rep_position == mPosition) return true; // do one play step play(virtual_match); } return false; } blobby-1.0/src/raknet/PacketPriority.h000644 001750 001750 00000005134 12313310247 022607 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Defines Priority and Reliability Constants * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __PACKET_PRIORITY_H #define __PACKET_PRIORITY_H /** * This enum contains all level of priority that can be applyed to a packet. */ enum PacketPriority { SYSTEM_PRIORITY, //!< System priority is for system related messaging. Don't use it. HIGH_PRIORITY, //!< Those message are handle first MEDIUM_PRIORITY, //!< Message relativly important LOW_PRIORITY, //!< Not critical information NUMBER_OF_PRIORITIES }; /** * This define the reliability behaviour to apply to a packet * * @note Note to self: I write this with 3 bits in the stream! * */ enum PacketReliability { UNRELIABLE, //!< Send packet not reliable and not sequenced UNRELIABLE_SEQUENCED, //!< Send packet not reliable but sequenced RELIABLE, //!< Send packet reliable RELIABLE_ORDERED, //!< Send packet reliable respecting ordering RELIABLE_SEQUENCED //!< Send packet reliable respecting sequenced }; #endif blobby-1.0/src/lua/lstrlib.c000644 001750 001750 00000067303 12313310253 020604 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lstrlib.c,v 1.178.1.1 2013/04/12 18:48:47 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ #include #include #include #include #include #define lstrlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** maximum number of captures that a pattern can do during ** pattern-matching. This limit is arbitrary. */ #if !defined(LUA_MAXCAPTURES) #define LUA_MAXCAPTURES 32 #endif /* macro to `unsign' a character */ #define uchar(c) ((unsigned char)(c)) static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); lua_pushinteger(L, (lua_Integer)l); return 1; } /* translate a relative string position: negative means back from end */ static size_t posrelat (ptrdiff_t pos, size_t len) { if (pos >= 0) return (size_t)pos; else if (0u - (size_t)pos > len) return 0; else return len - ((size_t)-pos) + 1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); size_t start = posrelat(luaL_checkinteger(L, 2), l); size_t end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; if (end > l) end = l; if (start <= end) lua_pushlstring(L, s + start - 1, end - start + 1); else lua_pushliteral(L, ""); return 1; } static int str_reverse (lua_State *L) { size_t l, i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); char *p = luaL_buffinitsize(L, &b, l); for (i = 0; i < l; i++) p[i] = s[l - i - 1]; luaL_pushresultsize(&b, l); return 1; } static int str_lower (lua_State *L) { size_t l; size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); char *p = luaL_buffinitsize(L, &b, l); for (i=0; i> 1) static int str_rep (lua_State *L) { size_t l, lsep; const char *s = luaL_checklstring(L, 1, &l); int n = luaL_checkint(L, 2); const char *sep = luaL_optlstring(L, 3, "", &lsep); if (n <= 0) lua_pushliteral(L, ""); else if (l + lsep < l || l + lsep >= MAXSIZE / n) /* may overflow? */ return luaL_error(L, "resulting string too large"); else { size_t totallen = n * l + (n - 1) * lsep; luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, totallen); while (n-- > 1) { /* first n-1 copies (followed by separator) */ memcpy(p, s, l * sizeof(char)); p += l; if (lsep > 0) { /* avoid empty 'memcpy' (may be expensive) */ memcpy(p, sep, lsep * sizeof(char)); p += lsep; } } memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ luaL_pushresultsize(&b, totallen); } return 1; } static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); size_t posi = posrelat(luaL_optinteger(L, 2, 1), l); size_t pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; if (posi < 1) posi = 1; if (pose > l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ n = (int)(pose - posi + 1); if (posi + n <= pose) /* (size_t -> int) overflow? */ return luaL_error(L, "string slice too long"); luaL_checkstack(L, n, "string slice too long"); for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) return luaL_error(ms->L, "invalid capture index %%%d", l + 1); return l; } static int capture_to_close (MatchState *ms) { int level = ms->level; for (level--; level>=0; level--) if (ms->capture[level].len == CAP_UNFINISHED) return level; return luaL_error(ms->L, "invalid pattern capture"); } static const char *classend (MatchState *ms, const char *p) { switch (*p++) { case L_ESC: { if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a `]' */ if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); if (*(p++) == L_ESC && p < ms->p_end) p++; /* skip escapes (e.g. `%]') */ } while (*p != ']'); return p+1; } default: { return p; } } } static int match_class (int c, int cl) { int res; switch (tolower(cl)) { case 'a' : res = isalpha(c); break; case 'c' : res = iscntrl(c); break; case 'd' : res = isdigit(c); break; case 'g' : res = isgraph(c); break; case 'l' : res = islower(c); break; case 'p' : res = ispunct(c); break; case 's' : res = isspace(c); break; case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; case 'x' : res = isxdigit(c); break; case 'z' : res = (c == 0); break; /* deprecated option */ default: return (cl == c); } return (islower(cl) ? res : !res); } static int matchbracketclass (int c, const char *p, const char *ec) { int sig = 1; if (*(p+1) == '^') { sig = 0; p++; /* skip the `^' */ } while (++p < ec) { if (*p == L_ESC) { p++; if (match_class(c, uchar(*p))) return sig; } else if ((*(p+1) == '-') && (p+2 < ec)) { p+=2; if (uchar(*(p-2)) <= c && c <= uchar(*p)) return sig; } else if (uchar(*p) == c) return sig; } return !sig; } static int singlematch (MatchState *ms, const char *s, const char *p, const char *ep) { if (s >= ms->src_end) return 0; else { int c = uchar(*s); switch (*p) { case '.': return 1; /* matches any char */ case L_ESC: return match_class(c, uchar(*(p+1))); case '[': return matchbracketclass(c, p, ep-1); default: return (uchar(*p) == c); } } } static const char *matchbalance (MatchState *ms, const char *s, const char *p) { if (p >= ms->p_end - 1) luaL_error(ms->L, "malformed pattern " "(missing arguments to " LUA_QL("%%b") ")"); if (*s != *p) return NULL; else { int b = *p; int e = *(p+1); int cont = 1; while (++s < ms->src_end) { if (*s == e) { if (--cont == 0) return s+1; } else if (*s == b) cont++; } } return NULL; /* string ends out of balance */ } static const char *max_expand (MatchState *ms, const char *s, const char *p, const char *ep) { ptrdiff_t i = 0; /* counts maximum expand for item */ while (singlematch(ms, s + i, p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { const char *res = match(ms, (s+i), ep+1); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } return NULL; } static const char *min_expand (MatchState *ms, const char *s, const char *p, const char *ep) { for (;;) { const char *res = match(ms, s, ep+1); if (res != NULL) return res; else if (singlematch(ms, s, p, ep)) s++; /* try with one more repetition */ else return NULL; } } static const char *start_capture (MatchState *ms, const char *s, const char *p, int what) { const char *res; int level = ms->level; if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); ms->capture[level].init = s; ms->capture[level].len = what; ms->level = level+1; if ((res=match(ms, s, p)) == NULL) /* match failed? */ ms->level--; /* undo capture */ return res; } static const char *end_capture (MatchState *ms, const char *s, const char *p) { int l = capture_to_close(ms); const char *res; ms->capture[l].len = s - ms->capture[l].init; /* close capture */ if ((res = match(ms, s, p)) == NULL) /* match failed? */ ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ return res; } static const char *match_capture (MatchState *ms, const char *s, int l) { size_t len; l = check_capture(ms, l); len = ms->capture[l].len; if ((size_t)(ms->src_end-s) >= len && memcmp(ms->capture[l].init, s, len) == 0) return s+len; else return NULL; } static const char *match (MatchState *ms, const char *s, const char *p) { if (ms->matchdepth-- == 0) luaL_error(ms->L, "pattern too complex"); init: /* using goto's to optimize tail recursion */ if (p != ms->p_end) { /* end of pattern? */ switch (*p) { case '(': { /* start capture */ if (*(p + 1) == ')') /* position capture? */ s = start_capture(ms, s, p + 2, CAP_POSITION); else s = start_capture(ms, s, p + 1, CAP_UNFINISHED); break; } case ')': { /* end capture */ s = end_capture(ms, s, p + 1); break; } case '$': { if ((p + 1) != ms->p_end) /* is the `$' the last char in pattern? */ goto dflt; /* no; go to default */ s = (s == ms->src_end) ? s : NULL; /* check end of string */ break; } case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ switch (*(p + 1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p + 2); if (s != NULL) { p += 4; goto init; /* return match(ms, s, p + 4); */ } /* else fail (s == NULL) */ break; } case 'f': { /* frontier? */ const char *ep; char previous; p += 2; if (*p != '[') luaL_error(ms->L, "missing " LUA_QL("[") " after " LUA_QL("%%f") " in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s - 1); if (!matchbracketclass(uchar(previous), p, ep - 1) && matchbracketclass(uchar(*s), p, ep - 1)) { p = ep; goto init; /* return match(ms, s, ep); */ } s = NULL; /* match failed */ break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { /* capture results (%0-%9)? */ s = match_capture(ms, s, uchar(*(p + 1))); if (s != NULL) { p += 2; goto init; /* return match(ms, s, p + 2) */ } break; } default: goto dflt; } break; } default: dflt: { /* pattern class plus optional suffix */ const char *ep = classend(ms, p); /* points to optional suffix */ /* does not match at least once? */ if (!singlematch(ms, s, p, ep)) { if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ } else /* '+' or no suffix */ s = NULL; /* fail */ } else { /* matched once */ switch (*ep) { /* handle optional suffix */ case '?': { /* optional */ const char *res; if ((res = match(ms, s + 1, ep + 1)) != NULL) s = res; else { p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ } break; } case '+': /* 1 or more repetitions */ s++; /* 1 match already done */ /* go through */ case '*': /* 0 or more repetitions */ s = max_expand(ms, s, p, ep); break; case '-': /* 0 or more repetitions (minimum) */ s = min_expand(ms, s, p, ep); break; default: /* no suffix */ s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ } } break; } } } ms->matchdepth++; return s; } static const char *lmemfind (const char *s1, size_t l1, const char *s2, size_t l2) { if (l2 == 0) return s1; /* empty strings are everywhere */ else if (l2 > l1) return NULL; /* avoids a negative `l1' */ else { const char *init; /* to search for a `*s2' inside `s1' */ l2--; /* 1st char will be checked by `memchr' */ l1 = l1-l2; /* `s2' cannot be found after that */ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { init++; /* 1st char is already checked */ if (memcmp(init, s2+1, l2) == 0) return init-1; else { /* correct `l1' and `s1' to try again */ l1 -= init-s1; s1 = init; } } return NULL; /* not found */ } } static void push_onecapture (MatchState *ms, int i, const char *s, const char *e) { if (i >= ms->level) { if (i == 0) /* ms->level == 0, too */ lua_pushlstring(ms->L, s, e - s); /* add whole match */ else luaL_error(ms->L, "invalid capture index"); } else { ptrdiff_t l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); else lua_pushlstring(ms->L, ms->capture[i].init, l); } } static int push_captures (MatchState *ms, const char *s, const char *e) { int i; int nlevels = (ms->level == 0 && s) ? 1 : ms->level; luaL_checkstack(ms->L, nlevels, "too many captures"); for (i = 0; i < nlevels; i++) push_onecapture(ms, i, s, e); return nlevels; /* number of strings pushed */ } /* check whether pattern has no special characters */ static int nospecials (const char *p, size_t l) { size_t upto = 0; do { if (strpbrk(p + upto, SPECIALS)) return 0; /* pattern has a special character */ upto += strlen(p + upto) + 1; /* may have more after \0 */ } while (upto <= l); return 1; /* no special chars found */ } static int str_find_aux (lua_State *L, int find) { size_t ls, lp; const char *s = luaL_checklstring(L, 1, &ls); const char *p = luaL_checklstring(L, 2, &lp); size_t init = posrelat(luaL_optinteger(L, 3, 1), ls); if (init < 1) init = 1; else if (init > ls + 1) { /* start after string's end? */ lua_pushnil(L); /* cannot find anything */ return 1; } /* explicit request or no special characters? */ if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { /* do a plain search */ const char *s2 = lmemfind(s + init - 1, ls - init + 1, p, lp); if (s2) { lua_pushinteger(L, s2 - s + 1); lua_pushinteger(L, s2 - s + lp); return 2; } } else { MatchState ms; const char *s1 = s + init - 1; int anchor = (*p == '^'); if (anchor) { p++; lp--; /* skip anchor character */ } ms.L = L; ms.matchdepth = MAXCCALLS; ms.src_init = s; ms.src_end = s + ls; ms.p_end = p + lp; do { const char *res; ms.level = 0; lua_assert(ms.matchdepth == MAXCCALLS); if ((res=match(&ms, s1, p)) != NULL) { if (find) { lua_pushinteger(L, s1 - s + 1); /* start */ lua_pushinteger(L, res - s); /* end */ return push_captures(&ms, NULL, 0) + 2; } else return push_captures(&ms, s1, res); } } while (s1++ < ms.src_end && !anchor); } lua_pushnil(L); /* not found */ return 1; } static int str_find (lua_State *L) { return str_find_aux(L, 1); } static int str_match (lua_State *L) { return str_find_aux(L, 0); } static int gmatch_aux (lua_State *L) { MatchState ms; size_t ls, lp; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); const char *src; ms.L = L; ms.matchdepth = MAXCCALLS; ms.src_init = s; ms.src_end = s+ls; ms.p_end = p + lp; for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); src <= ms.src_end; src++) { const char *e; ms.level = 0; lua_assert(ms.matchdepth == MAXCCALLS); if ((e = match(&ms, src, p)) != NULL) { lua_Integer newstart = e-s; if (e == src) newstart++; /* empty match? go at least one position */ lua_pushinteger(L, newstart); lua_replace(L, lua_upvalueindex(3)); return push_captures(&ms, src, e); } } return 0; /* not found */ } static int gmatch (lua_State *L) { luaL_checkstring(L, 1); luaL_checkstring(L, 2); lua_settop(L, 2); lua_pushinteger(L, 0); lua_pushcclosure(L, gmatch_aux, 3); return 1; } static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { size_t l, i; const char *news = lua_tolstring(ms->L, 3, &l); for (i = 0; i < l; i++) { if (news[i] != L_ESC) luaL_addchar(b, news[i]); else { i++; /* skip ESC */ if (!isdigit(uchar(news[i]))) { if (news[i] != L_ESC) luaL_error(ms->L, "invalid use of " LUA_QL("%c") " in replacement string", L_ESC); luaL_addchar(b, news[i]); } else if (news[i] == '0') luaL_addlstring(b, s, e - s); else { push_onecapture(ms, news[i] - '1', s, e); luaL_addvalue(b); /* add capture to accumulated result */ } } } } static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, const char *e, int tr) { lua_State *L = ms->L; switch (tr) { case LUA_TFUNCTION: { int n; lua_pushvalue(L, 3); n = push_captures(ms, s, e); lua_call(L, n, 1); break; } case LUA_TTABLE: { push_onecapture(ms, 0, s, e); lua_gettable(L, 3); break; } default: { /* LUA_TNUMBER or LUA_TSTRING */ add_s(ms, b, s, e); return; } } if (!lua_toboolean(L, -1)) { /* nil or false? */ lua_pop(L, 1); lua_pushlstring(L, s, e - s); /* keep original text */ } else if (!lua_isstring(L, -1)) luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); luaL_addvalue(b); /* add result to accumulator */ } static int str_gsub (lua_State *L) { size_t srcl, lp; const char *src = luaL_checklstring(L, 1, &srcl); const char *p = luaL_checklstring(L, 2, &lp); int tr = lua_type(L, 3); size_t max_s = luaL_optinteger(L, 4, srcl+1); int anchor = (*p == '^'); size_t n = 0; MatchState ms; luaL_Buffer b; luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, "string/function/table expected"); luaL_buffinit(L, &b); if (anchor) { p++; lp--; /* skip anchor character */ } ms.L = L; ms.matchdepth = MAXCCALLS; ms.src_init = src; ms.src_end = src+srcl; ms.p_end = p + lp; while (n < max_s) { const char *e; ms.level = 0; lua_assert(ms.matchdepth == MAXCCALLS); e = match(&ms, src, p); if (e) { n++; add_value(&ms, &b, src, e, tr); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ else if (src < ms.src_end) luaL_addchar(&b, *src++); else break; if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); luaL_pushresult(&b); lua_pushinteger(L, n); /* number of substitutions */ return 2; } /* }====================================================== */ /* ** {====================================================== ** STRING FORMAT ** ======================================================= */ /* ** LUA_INTFRMLEN is the length modifier for integer conversions in ** 'string.format'; LUA_INTFRM_T is the integer type corresponding to ** the previous length */ #if !defined(LUA_INTFRMLEN) /* { */ #if defined(LUA_USE_LONGLONG) #define LUA_INTFRMLEN "ll" #define LUA_INTFRM_T long long #else #define LUA_INTFRMLEN "l" #define LUA_INTFRM_T long #endif #endif /* } */ /* ** LUA_FLTFRMLEN is the length modifier for float conversions in ** 'string.format'; LUA_FLTFRM_T is the float type corresponding to ** the previous length */ #if !defined(LUA_FLTFRMLEN) #define LUA_FLTFRMLEN "" #define LUA_FLTFRM_T double #endif /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ #define MAX_ITEM 512 /* valid flags in a format specification */ #define FLAGS "-+ #0" /* ** maximum size of each format specification (such as '%-099.99d') ** (+10 accounts for %99.99x plus margin of error) */ #define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { size_t l; const char *s = luaL_checklstring(L, arg, &l); luaL_addchar(b, '"'); while (l--) { if (*s == '"' || *s == '\\' || *s == '\n') { luaL_addchar(b, '\\'); luaL_addchar(b, *s); } else if (*s == '\0' || iscntrl(uchar(*s))) { char buff[10]; if (!isdigit(uchar(*(s+1)))) sprintf(buff, "\\%d", (int)uchar(*s)); else sprintf(buff, "\\%03d", (int)uchar(*s)); luaL_addstring(b, buff); } else luaL_addchar(b, *s); s++; } luaL_addchar(b, '"'); } static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) luaL_error(L, "invalid format (repeated flags)"); if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ if (*p == '.') { p++; if (isdigit(uchar(*p))) p++; /* skip precision */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ } if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char)); form += p - strfrmt + 1; *form = '\0'; return p; } /* ** add length modifier into formats */ static void addlenmod (char *form, const char *lenmod) { size_t l = strlen(form); size_t lm = strlen(lenmod); char spec = form[l - 1]; strcpy(form + l - 1, lenmod); form[l + lm - 1] = spec; form[l + lm] = '\0'; } static int str_format (lua_State *L) { int top = lua_gettop(L); int arg = 1; size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); const char *strfrmt_end = strfrmt+sfl; luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { if (*strfrmt != L_ESC) luaL_addchar(&b, *strfrmt++); else if (*++strfrmt == L_ESC) luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ int nb = 0; /* number of bytes in added item */ if (++arg > top) luaL_argerror(L, arg, "no value"); strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { nb = sprintf(buff, form, luaL_checkint(L, arg)); break; } case 'd': case 'i': { lua_Number n = luaL_checknumber(L, arg); LUA_INTFRM_T ni = (LUA_INTFRM_T)n; lua_Number diff = n - (lua_Number)ni; luaL_argcheck(L, -1 < diff && diff < 1, arg, "not a number in proper range"); addlenmod(form, LUA_INTFRMLEN); nb = sprintf(buff, form, ni); break; } case 'o': case 'u': case 'x': case 'X': { lua_Number n = luaL_checknumber(L, arg); unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n; lua_Number diff = n - (lua_Number)ni; luaL_argcheck(L, -1 < diff && diff < 1, arg, "not a non-negative number in proper range"); addlenmod(form, LUA_INTFRMLEN); nb = sprintf(buff, form, ni); break; } case 'e': case 'E': case 'f': #if defined(LUA_USE_AFORMAT) case 'a': case 'A': #endif case 'g': case 'G': { addlenmod(form, LUA_FLTFRMLEN); nb = sprintf(buff, form, (LUA_FLTFRM_T)luaL_checknumber(L, arg)); break; } case 'q': { addquoted(L, &b, arg); break; } case 's': { size_t l; const char *s = luaL_tolstring(L, arg, &l); if (!strchr(form, '.') && l >= 100) { /* no precision and string is too long to be formatted; keep original string */ luaL_addvalue(&b); break; } else { nb = sprintf(buff, form, s); lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ break; } } default: { /* also treat cases `pnLlh' */ return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " LUA_QL("format"), *(strfrmt - 1)); } } luaL_addsize(&b, nb); } } luaL_pushresult(&b); return 1; } /* }====================================================== */ static const luaL_Reg strlib[] = { {"byte", str_byte}, {"char", str_char}, {"dump", str_dump}, {"find", str_find}, {"format", str_format}, {"gmatch", gmatch}, {"gsub", str_gsub}, {"len", str_len}, {"lower", str_lower}, {"match", str_match}, {"rep", str_rep}, {"reverse", str_reverse}, {"sub", str_sub}, {"upper", str_upper}, {NULL, NULL} }; static void createmetatable (lua_State *L) { lua_createtable(L, 0, 1); /* table to be metatable for strings */ lua_pushliteral(L, ""); /* dummy string */ lua_pushvalue(L, -2); /* copy table */ lua_setmetatable(L, -2); /* set table as metatable for strings */ lua_pop(L, 1); /* pop dummy string */ lua_pushvalue(L, -2); /* get string library */ lua_setfield(L, -2, "__index"); /* metatable.__index = string */ lua_pop(L, 1); /* pop metatable */ } /* ** Open string library */ LUAMOD_API int luaopen_string (lua_State *L) { luaL_newlib(L, strlib); createmetatable(L); return 1; } blobby-1.0/src/lua/lctype.h000644 001750 001750 00000003461 12313310253 020431 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $ ** 'ctype' functions for Lua ** See Copyright Notice in lua.h */ #ifndef lctype_h #define lctype_h #include "lua.h" /* ** WARNING: the functions defined here do not necessarily correspond ** to the similar functions in the standard C ctype.h. They are ** optimized for the specific needs of Lua */ #if !defined(LUA_USE_CTYPE) #if 'A' == 65 && '0' == 48 /* ASCII case: can use its own tables; faster and fixed */ #define LUA_USE_CTYPE 0 #else /* must use standard C ctype */ #define LUA_USE_CTYPE 1 #endif #endif #if !LUA_USE_CTYPE /* { */ #include #include "llimits.h" #define ALPHABIT 0 #define DIGITBIT 1 #define PRINTBIT 2 #define SPACEBIT 3 #define XDIGITBIT 4 #define MASK(B) (1 << (B)) /* ** add 1 to char to allow index -1 (EOZ) */ #define testprop(c,p) (luai_ctype_[(c)+1] & (p)) /* ** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' */ #define lislalpha(c) testprop(c, MASK(ALPHABIT)) #define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) #define lisdigit(c) testprop(c, MASK(DIGITBIT)) #define lisspace(c) testprop(c, MASK(SPACEBIT)) #define lisprint(c) testprop(c, MASK(PRINTBIT)) #define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) /* ** this 'ltolower' only works for alphabetic characters */ #define ltolower(c) ((c) | ('A' ^ 'a')) /* two more entries for 0 and -1 (EOZ) */ LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; #else /* }{ */ /* ** use standard C ctypes */ #include #define lislalpha(c) (isalpha(c) || (c) == '_') #define lislalnum(c) (isalnum(c) || (c) == '_') #define lisdigit(c) (isdigit(c)) #define lisspace(c) (isspace(c)) #define lisprint(c) (isprint(c)) #define lisxdigit(c) (isxdigit(c)) #define ltolower(c) (tolower(c)) #endif /* } */ #endif blobby-1.0/data/gfx/font42.bmp000644 001750 001750 00000003370 12313310254 020721 0ustar00danielknobedanielknobe000000 000000 BM6( .&$^,+e53o:8u76j;:b//I)'OFCOKb_us̅ђ֋Ȑ_^..<(jbia΅}慁-,@$?>NᖔQR]#KBzkߍ{KKPᛙXV_ vfߚ+):"##㡜d`fqzf ग़NHK fk СPIJ}ҡ} #)'(÷ζ|ikaJk͒ệG6LumnŶYGH."0ā}Z$ дhi ۉd7'9q]^ܣln=&&K9MrpAp 2()֐UWb76  }ZI,GuwgjKLH3HwM6!3`c^aFGjFhqٔM2.inLN'*rf͉:uB$7s8=FJ7:-. geKZ)B" @ @E6;03<xZoyK5MP +B[!')0,2+/')B0;ɁoEq1L#2$0#-$((*"h=L\;]+?+8.6&*BLcnTr?Uu.6.6ql|ucvfpQY& )  yrxy~]b26+ E-3ېꖠnvTXhj>?blobby-1.0/src/tinyxml/000755 001750 001750 00000000000 12313310251 017675 5ustar00danielknobedanielknobe000000 000000 blobby-1.0/src/InputSourceFactory.cpp000644 001750 001750 00000003725 12313310252 022515 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "InputSourceFactory.h" /* includes */ #include #include #include "IUserConfigReader.h" #include "LocalInputSource.h" #include "ScriptedInputSource.h" boost::shared_ptr InputSourceFactory::createInputSource( boost::shared_ptr config, PlayerSide side ) { std::string prefix = side == LEFT_PLAYER ? "left" : "right"; try { // these operations may throw, i.e., when the script is not found (should not happen) // or has errors if (config->getBool(prefix + "_player_human")) { return boost::make_shared(side); } else { return boost::make_shared("scripts/" + config->getString(prefix + "_script_name"), side, config->getInteger(prefix + "_script_strength")); } } catch (std::exception& e) { /// \todo REWORK ERROR REPORTING std::cerr << e.what() << std::endl; return boost::make_shared(); } } blobby-1.0/src/ScriptedInputSource.h000644 001750 001750 00000010667 12313310252 022333 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /** * @file ScriptedInputSource.h * @brief Contains a class which allows using lua scripted bots */ #pragma once #include #include #include "Global.h" #include "InputSource.h" #include "Vector.h" #include "IScriptableComponent.h" /// \class ScriptedInputSource /// \brief Bot controller /// \details ScriptedInputSource provides an implementation of InputSource, which uses /// Lua scripts to get its input. The given script is automatically initialised /// and provided with an interface to the game. /// The API documentation can now be found in doc/ScriptAPI.txt // The time the bot waits after game start const int WAITING_TIME = 1500; struct lua_State; class DuelMatch; class ScriptedInputSource : public InputSource, public IScriptableComponent { public: /// The constructor automatically loads and initializes the script /// with the given filename. The side parameter tells the script /// which side is it on. ScriptedInputSource(const std::string& filename, PlayerSide side, unsigned int difficulty); ~ScriptedInputSource(); virtual PlayerInputAbs getNextInput(); private: /// this variable saves the current match /// it is set each step in getInput /// as in current design, only in single match mode bots are allowed /// it would even be enough to set it once, but we may change this /// for making bot tournaments^^, so the idea of setting it for each /// bot seems better to me static const DuelMatch* mMatch; static ScriptedInputSource* mCurrentSource; // helpers static int debug(lua_State* state); static void setflags(lua_State* state); // coordinate system conversion template struct coordinate; // commands static int jump(lua_State* state); static int left(lua_State* state); static int right(lua_State* state); static int moveto(lua_State* state); // ball information // internals static const Vector2& getBallPosition(); static const Vector2& getBallVelocity(); static int touches(lua_State* state); static int ballx(lua_State* state); static int bally(lua_State* state); static int bspeedx(lua_State* state); static int bspeedy(lua_State* state); // blob information static int launched(lua_State* state); static int posx(lua_State* state); static int posy(lua_State* state); static int oppx(lua_State* state); static int oppy(lua_State* state); // game status static int getScore(lua_State* state); static int getOppScore(lua_State* state); static int getScoreToWin(lua_State* state); static int getGameTime(lua_State* state); // predictions static int estimate(lua_State* state); // deprecated static int estimx(lua_State* state); // deprecated static int estimy(lua_State* state); // deprecated static int predictx(lua_State* state); static int predicty(lua_State* state); static int timetox(lua_State* state); static int timetoy(lua_State* state); static int xaty(lua_State* state); static int yatx(lua_State* state); static int nextevent(lua_State* state); static int predictImpact(lua_State* state); unsigned int mStartTime; // ki strength values unsigned int mMaxDelay; unsigned int mCurDelay; // which functions are available bool mOnBounce; // ball position and velocity in adapted coordinate system boost::circular_buffer mBallPositions; boost::circular_buffer mBallVelocities; float mLastBallSpeed; float mLastBallSpeedVirtual; PlayerSide mSide; // input data bool mLeft, mRight, mJump; }; blobby-1.0/src/lua/lctype.c000644 001750 001750 00000004373 12313310253 020427 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lctype.c,v 1.11.1.1 2013/04/12 18:48:47 roberto Exp $ ** 'ctype' functions for Lua ** See Copyright Notice in lua.h */ #define lctype_c #define LUA_CORE #include "lctype.h" #if !LUA_USE_CTYPE /* { */ #include LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { 0x00, /* EOZ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #endif /* } */ blobby-1.0/src/IMGUI.h000644 001750 001750 00000007425 12313310252 017225 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include "Vector.h" #include "Global.h" #include "RenderManager.h" #include "TextManager.h" /// needed because we can't forward declare that enum #include "BlobbyDebug.h" // Warning: This may explode if we use the GUI from several files #define GEN_ID (__LINE__) enum KeyAction { UP, DOWN, LEFT, RIGHT, SELECT, BACK, NONE }; enum SelectBoxAction { SBA_NONE = 0, SBA_SELECT, SBA_DBL_CLICK }; /*! \class IMGUI \brief GUI Manager \details This class manages drawing and input handling of the blobby GUI. It is poorly designed, does not use OOP and makes extension difficult, so it needs a complete rewrite. */ class IMGUI : public ObjectCounter { public: static IMGUI& getSingleton(); void begin(); void end(); void resetSelection(); void doImage(int id, const Vector2& position, const std::string& name, const Vector2& size = Vector2(0,0)); void doText(int id, const Vector2& position, const std::string& text, unsigned int flags = TF_NORMAL); void doText(int id, const Vector2& position, TextManager::STRING text, unsigned int flags = TF_NORMAL); void doOverlay(int id, const Vector2& pos1, const Vector2& pos2, const Color& col = Color(0, 0, 0), float alpha = 0.65); void doCursor(bool draw = true) { mDrawCursor = draw; mUsingCursor = true; } bool doButton(int id, const Vector2& position, const std::string& text, unsigned int flags = TF_NORMAL); bool doButton(int id, const Vector2& position, TextManager::STRING text, unsigned int flags = TF_NORMAL); // draws an image that also works as a button // for now, it is not included in keyboard navigation, so it is more like a clickable image than a real button /// \todo the size parameter should be calculated from the passed image bool doImageButton(int id, const Vector2& position, const Vector2& size, const std::string& image); bool doScrollbar(int id, const Vector2& position, float& value); bool doEditbox(int id, const Vector2& position, unsigned length, std::string& text, unsigned& cpos, unsigned int flags = TF_NORMAL, bool force_active = false); SelectBoxAction doSelectbox(int id, const Vector2& pos1, const Vector2& pos2, const std::vector& entries, unsigned& selected, unsigned int flags = TF_NORMAL); void doChatbox(int id, const Vector2& pos1, const Vector2& pos2, const std::vector& entries, unsigned& selected, const std::vector& local, unsigned int flags = TF_NORMAL); bool doBlob(int id, const Vector2& position, const Color& col); bool usingCursor() const; void doInactiveMode(bool inactive) { mInactive = inactive; } private: IMGUI(); ~IMGUI(); static IMGUI* mSingleton; int mActiveButton; int mHeldWidget; KeyAction mLastKeyAction; int mLastWidget; bool mDrawCursor; bool mButtonReset; bool mInactive; bool mUsingCursor; }; blobby-1.0/src/raknet/GetTime.cpp000644 001750 001750 00000005075 12313310247 021533 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file GetTime.cpp * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "GetTime.h" #ifdef _WIN32 #include #else #include #endif unsigned int RakNet::GetTime( void ) { #ifdef _WIN32 static LARGE_INTEGER yo; static LONGLONG counts; #else static timeval tp, initialTime; #endif static bool initialized = false; if ( initialized == false ) { #ifdef _WIN32 QueryPerformanceFrequency( &yo ); // The original code shifted right 10 bits //counts = yo.QuadPart >> 10; // It gives the wrong value since 2^10 is not 1000 counts = yo.QuadPart / 1000; #else gettimeofday( &initialTime, 0 ); #endif initialized = true; } #ifdef _WIN32 LARGE_INTEGER PerfVal; QueryPerformanceCounter( &PerfVal ); return ( unsigned int ) ( PerfVal.QuadPart / counts ); #else gettimeofday( &tp, 0 ); // Seconds to ms and microseconds to ms return ( tp.tv_sec - initialTime.tv_sec ) * 1000 + ( tp.tv_usec - initialTime.tv_usec ) / 1000; #endif } blobby-1.0/data/gfx/btn_slow.bmp000644 001750 001750 00000003366 12313310254 021441 0ustar00danielknobedanielknobe000000 000000 BM6(  blobby-1.0/src/FileSystem.h000644 001750 001750 00000006342 12313310251 020433 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include #include #include #include "FileExceptions.h" #include "BlobbyDebug.h" // some convenience wrappers around physfs class FileSystem : public boost::noncopyable, public ObjectCounter { public: FileSystem(const std::string& path); ~FileSystem(); /// \brief gets the file system /// \details throws an error when file system has /// not been initialised. static FileSystem& getSingleton(); /// \brief enumerates files /// \details searches for all files in a certain directory with a given extension. The found files /// are returned as a vector containing the filenames. The extension is cuttet from the filenames. /// \param directory where to search /// \param extension file types to search for. /// \param keepExtension If true, the return vector contains the full filenames, if false [default behaviour], /// only the filenames without the extensions are saved. std::vector enumerateFiles(const std::string& directory, const std::string& extension, bool keepExtension = false); /// \brief deletes a file bool deleteFile(const std::string& filename); /// \brief tests whether a file exists bool exists(const std::string& filename) const; /// \brief tests wether given path is a directory bool isDirectory(const std::string& dirname) const; /// \brief creates a directory and reports success/failure /// \return true, if the directory could be created bool mkdir(const std::string& dirname); // general setup methods void addToSearchPath(const std::string& dirname, bool append = true); void removeFromSearchPath(const std::string& dirname); /// \details automatically registers this directory as primary read directory! void setWriteDir(const std::string& dirname); /// \todo this method is currently only copied code. it needs some review and a spec what it really should /// do. also, its uses should be looked at again. void probeDir(const std::string& dir); /// \todo ideally, this method would never be needed by client code!! std::string getDirSeparator(); /// \todo ideally, this method would never be needed by client code!! std::string getUserDir(); }; blobby-1.0/src/state/NetworkSearchState.cpp000644 001750 001750 00000034674 12313310253 023615 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "NetworkSearchState.h" /* includes */ #include #include #include #include #include // debugging #include #include "raknet/RakClient.h" #include "raknet/PacketEnumerations.h" #include "raknet/RakServer.h" #include "blobnet/layer/Http.hpp" #include "blobnet/exception/HttpException.hpp" #include "tinyxml/tinyxml.h" #include "NetworkState.h" #include "LobbyState.h" #include "TextManager.h" #include "IMGUI.h" #include "IUserConfigReader.h" #include "FileWrite.h" #include "FileRead.h" /* implementation */ NetworkSearchState::NetworkSearchState() : mPingClient(new RakClient) { mSelectedServer = 0; mServerBoxPosition = 0; mDisplayInfo = false; mEnteringServer = false; mDisplayUpdateNotification = false; } NetworkSearchState::~NetworkSearchState() { // Disconnect from servers for (ClientList::iterator iter = mQueryClients.begin(); iter != mQueryClients.end(); ++iter) { if (*iter) { (*iter)->Disconnect(50); delete *iter; } } } void NetworkSearchState::searchServers() { // we need the explicit async launch policy here, because otherwise gcc will always launch deferred and we have no sync point // where we would wait for that. mPingJob = std::async(std::launch::async, [this](){ doSearchServers();}); } void NetworkSearchState::step_impl() { packet_ptr packet; // set to true to initiate server connection bool doEnterServer = false; for (ClientList::iterator iter = mQueryClients.begin(); iter != mQueryClients.end(); ++iter) { bool skip = false; bool skip_iter = false; while ((packet = (*iter)->Receive()) && !skip) { switch(packet->data[0]) { case ID_CONNECTION_REQUEST_ACCEPTED: { printf("connection accepted from %s:%d\n", mPingClient->PlayerIDToDottedIP( packet->playerId), packet->playerId.port); RakNet::BitStream stream; stream.Write((unsigned char)ID_BLOBBY_SERVER_PRESENT); stream.Write(BLOBBY_VERSION_MAJOR); stream.Write(BLOBBY_VERSION_MINOR); (*iter)->Send(&stream, LOW_PRIORITY, RELIABLE_ORDERED, 0); break; } case ID_BLOBBY_SERVER_PRESENT: { //FIXME: We must copy the needed informations, so that we can call DeallocatePacket(packet) //FIXME: The client finds a server at this point, which is not valid RakNet::BitStream stream((char*)packet->data, packet->length, false); printf("server is a blobby server\n"); stream.IgnoreBytes(1); //ID_BLOBBY_SERVER_PRESENT ServerInfo info(stream, (*iter)->PlayerIDToDottedIP(packet->playerId), packet->playerId.port); // check that the packet sizes match if(packet->length == ServerInfo::BLOBBY_SERVER_PRESENT_PACKET_SIZE) { if (std::find( mScannedServers.begin(), mScannedServers.end(), info) == mScannedServers.end() ) { mScannedServers.push_back(info); // check whether this was a direct connect server if(*iter == mDirectConnectClient) { mSelectedServer = mScannedServers.size() - 1; doEnterServer = true; } } else { std::cout << "duplicate server entry\n"; std::cout << info << "\n"; } } else { std::cout << " server invalid " << packet->length << " " << ServerInfo::BLOBBY_SERVER_PRESENT_PACKET_SIZE << "\n"; } // the RakClient will be deleted, so // we must free the packet here packet.reset(); (*iter)->Disconnect(50); delete *iter; iter = mQueryClients.erase(iter); if (iter == mQueryClients.end()) skip_iter = true; skip = true; break; } case ID_VERSION_MISMATCH: { // this packet is send when the client is older than the server! // so RakNet::BitStream stream((char*)packet->data, packet->length, false); stream.IgnoreBytes(1); // ID_VERSION_MISMATCH // default values if server does not send versions. // thats the 0.9 behaviour int smajor = 0, sminor = 9; stream.Read(smajor); // load server version information stream.Read(sminor); printf("found blobby server with version %d.%d\n", smajor, sminor); mDisplayUpdateNotification = true; // the RakClient will be deleted, so // we must free the packet here packet.reset(); (*iter)->Disconnect(50); delete *iter; iter = mQueryClients.erase(iter); if (iter == mQueryClients.end()) skip_iter = true; skip = true; break; } default: break; } if (skip) break; } if (skip_iter) break; } while (packet = mPingClient->Receive()) { switch (packet->data[0]) { case ID_PONG: { std::string hostname = mPingClient->PlayerIDToDottedIP(packet->playerId); printf("got ping response by \"%s:%d\", trying to connect\n", hostname.c_str(), packet->playerId.port); RakClient* newClient = new RakClient; newClient->Connect( hostname.c_str(), packet->playerId.port, 0, 0, RAKNET_THREAD_SLEEP_TIME); mQueryClients.push_back(newClient); } default: break; } } IMGUI& imgui = IMGUI::getSingleton(); imgui.doCursor(); imgui.doImage(GEN_ID, Vector2(400.0, 300.0), "background"); imgui.doOverlay(GEN_ID, Vector2(0.0, 0.0), Vector2(800.0, 600.0)); imgui.doInactiveMode(false); if (mDisplayInfo || mEnteringServer) { imgui.doInactiveMode(true); } if (imgui.doButton(GEN_ID, Vector2(10, 20), TextManager::NET_SERVER_SCAN)) searchServers(); if (imgui.doButton(GEN_ID, Vector2(420, 20), TextManager::NET_DIRECT_CONNECT) && !mEnteringServer) { mEnteringServer = true; imgui.resetSelection(); mEnteredServer = ""; mServerBoxPosition = 0; } std::vector servernames; for (unsigned int i = 0; i < mScannedServers.size(); i++) { servernames.push_back(std::string(mScannedServers[i].name) + " (" + boost::lexical_cast(mScannedServers[i].waitingplayers) + ")" ); } if( imgui.doSelectbox(GEN_ID, Vector2(25.0, 60.0), Vector2(775.0, 470.0), servernames, mSelectedServer) == SBA_DBL_CLICK ) { doEnterServer = true; } if (imgui.doButton(GEN_ID, Vector2(50, 480), TextManager::NET_SERVER_INFO) && !mDisplayInfo && !mScannedServers.empty()) { mDisplayInfo = true; imgui.resetSelection(); } if (mEnteringServer) { imgui.doInactiveMode(false); imgui.doOverlay(GEN_ID, Vector2(100.0, 200.0), Vector2(650.0, 400.0)); // Game crashes if the mEnteredServer is not a possible input imgui.doEditbox(GEN_ID, Vector2(130.0, 210.0), 20, mEnteredServer, mServerBoxPosition); if (imgui.doButton(GEN_ID, Vector2(270.0, 300.0), TextManager::LBL_OK)) { /// \todo adapt direct connect std::string server = mEnteredServer; int port = BLOBBY_PORT; std::size_t found = mEnteredServer.find(':'); if (found != std::string::npos) { server = mEnteredServer.substr(0, found); try { port = boost::lexical_cast(mEnteredServer.substr(found+1)); } catch (boost::bad_lexical_cast) { /// \todo inform the user that default port was selected } if ((port <= 0) || (port > 65535)) port = BLOBBY_PORT; } // add this address / port info as client mDirectConnectClient = new RakClient; mDirectConnectClient->Connect(server.c_str(), port, 0, 0, RAKNET_THREAD_SLEEP_TIME); mQueryClients.push_back( mDirectConnectClient ); mEnteringServer = false; imgui.resetSelection(); } if (imgui.doButton(GEN_ID, Vector2(370.0, 300.0), TextManager::LBL_CANCEL)) { mEnteringServer = false; imgui.resetSelection(); } imgui.doInactiveMode(true); } if (mDisplayInfo) { imgui.doInactiveMode(false); imgui.doOverlay(GEN_ID, Vector2(40.0, 80.0), Vector2(760.0, 440.0), Color(0,0,0), 1.0); imgui.doText(GEN_ID, Vector2(50, 100), mScannedServers[mSelectedServer].name); imgui.doText(GEN_ID, Vector2(50, 130), mScannedServers[mSelectedServer].hostname); std::stringstream activegames; activegames << TextManager::getSingleton()->getString(TextManager::NET_ACTIVE_GAMES) << mScannedServers[mSelectedServer].activegames; imgui.doText(GEN_ID, Vector2(50, 160), activegames.str()); std::stringstream waitingplayer; waitingplayer << TextManager::getSingleton()->getString(TextManager::NET_WAITING_PLAYER) << mScannedServers[mSelectedServer].waitingplayers; imgui.doText(GEN_ID, Vector2(50, 190), waitingplayer.str()); std::stringstream gamespeed; gamespeed << TextManager::getSingleton()->getString(TextManager::OP_SPEED) << " " << int(100.0 / 75.0 * mScannedServers[mSelectedServer].gamespeed) << "%"; imgui.doText(GEN_ID, Vector2(50, 220), gamespeed.str()); std::string description = mScannedServers[mSelectedServer].description; for (unsigned int i = 0; i < description.length(); i += 29) { imgui.doText(GEN_ID, Vector2(50, 250 + i / 29 * 30), description.substr(i, 29)); } if (imgui.doButton(GEN_ID, Vector2(410, 405), TextManager::LBL_OK)) { mDisplayInfo = false; imgui.resetSelection(); } imgui.doInactiveMode(true); } if (imgui.doButton(GEN_ID, Vector2(450, 480), TextManager::NET_HOST_GAME) && !mDisplayInfo) { switchState(new NetworkHostState()); } if ((imgui.doButton(GEN_ID, Vector2(230, 530), TextManager::LBL_OK) && !mScannedServers.empty()) || doEnterServer) { ServerInfo server = mScannedServers[mSelectedServer]; switchState(new LobbyState(server)); } if (imgui.doButton(GEN_ID, Vector2(480, 530), TextManager::LBL_CANCEL)) { switchState(new MainMenuState); } if(mDisplayUpdateNotification) { imgui.doOverlay(GEN_ID, Vector2(71, 572), Vector2(729, 590), Color(128, 0, 0)); imgui.doText(GEN_ID, Vector2(85, 577), TextManager::UPDATE_NOTIFICATION, TF_SMALL_FONT); } } const char* NetworkSearchState::getStateName() const { return "NetworkSearchState"; } // the different networkmodi classes (online/LAN) OnlineSearchState::OnlineSearchState() { searchServers(); } void OnlineSearchState::doSearchServers() { // Get the serverlist try { BlobNet::Layer::Http http("blobby.sourceforge.net", 80); std::stringstream serverListXml; http.request("server.php", serverListXml); // this trows an exception if the file could not be opened for writing FileWrite file("onlineserver.xml"); file.write(serverListXml.str()); file.close(); } catch (std::exception& e) { std::cout << "Can't get onlineserver.xml: " << e.what() << std::endl; } catch (...) { std::cout << "Can't get onlineserver.xml. Unknown error." << std::endl; } std::vector< std::pair > serverList; // Get the serverlist try { boost::shared_ptr serverListXml = FileRead::readXMLDocument("onlineserver.xml"); if (serverListXml->Error()) { std::cerr << "Warning: Parse error in " << "onlineserver.xml"; std::cerr << "!" << std::endl; } TiXmlElement* onlineserverElem = serverListXml->FirstChildElement("onlineserver"); if (onlineserverElem == NULL) { std::cout << "Can't read onlineserver.xml" << std::endl; return; } for (TiXmlElement* serverElem = onlineserverElem->FirstChildElement("server"); serverElem != NULL; serverElem = serverElem->NextSiblingElement("server")) { std::string host; int port; for (TiXmlElement* varElem = serverElem->FirstChildElement("var"); varElem != NULL; varElem = varElem->NextSiblingElement("var")) { const char* tmp; tmp = varElem->Attribute("host"); if(tmp) { host = tmp; continue; } tmp = varElem->Attribute("port"); if(tmp) { try { port = boost::lexical_cast(tmp); } catch (boost::bad_lexical_cast) { port = BLOBBY_PORT; } if ((port <= 0) || (port > 65535)) { port = BLOBBY_PORT; } continue; } } std::pair pairs(host, port); serverList.push_back(pairs); } } catch (...) { std::cout << "Can't read onlineserver.xml" << std::endl; } /// \todo check if we already try to connect to this one! std::string address = IUserConfigReader::createUserConfigReader("config.xml")->getString("additional_network_server"); std::string server = address; int port = BLOBBY_PORT; std::size_t found = address.find(':'); if (found != std::string::npos) { server = address.substr(0, found); try { port = boost::lexical_cast(address.substr(found+1)); } catch (boost::bad_lexical_cast) { /// \todo inform the user that default port was selected } if ((port <= 0) || (port > 65535)) port = BLOBBY_PORT; } std::pair pairs(server.c_str(), port); serverList.push_back(pairs); mScannedServers.clear(); mPingClient->Initialize( serverList.size() + 2, 0, 10 ); for( auto& server : serverList ) { std::cout << "ping" << server.first << "\n"; mPingClient->Ping(server.first.c_str(), server.second, true); } } const char* OnlineSearchState::getStateName() const { return "OnlineSearchState"; } LANSearchState::LANSearchState() { searchServers(); } void LANSearchState::doSearchServers() { mScannedServers.clear(); mPingClient->PingServer("255.255.255.255", BLOBBY_PORT, 0, true); } const char* LANSearchState::getStateName() const { return "LANSearchState"; } blobby-1.0/src/lua/ldblib.c000644 001750 001750 00000023541 12313310253 020355 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: ldblib.c,v 1.132.1.1 2013/04/12 18:48:47 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ #include #include #include #define ldblib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" #define HOOKKEY "_HKEY" static int db_getregistry (lua_State *L) { lua_pushvalue(L, LUA_REGISTRYINDEX); return 1; } static int db_getmetatable (lua_State *L) { luaL_checkany(L, 1); if (!lua_getmetatable(L, 1)) { lua_pushnil(L); /* no metatable */ } return 1; } static int db_setmetatable (lua_State *L) { int t = lua_type(L, 2); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); lua_settop(L, 2); lua_setmetatable(L, 1); return 1; /* return 1st argument */ } static int db_getuservalue (lua_State *L) { if (lua_type(L, 1) != LUA_TUSERDATA) lua_pushnil(L); else lua_getuservalue(L, 1); return 1; } static int db_setuservalue (lua_State *L) { if (lua_type(L, 1) == LUA_TLIGHTUSERDATA) luaL_argerror(L, 1, "full userdata expected, got light userdata"); luaL_checktype(L, 1, LUA_TUSERDATA); if (!lua_isnoneornil(L, 2)) luaL_checktype(L, 2, LUA_TTABLE); lua_settop(L, 2); lua_setuservalue(L, 1); return 1; } static void settabss (lua_State *L, const char *i, const char *v) { lua_pushstring(L, v); lua_setfield(L, -2, i); } static void settabsi (lua_State *L, const char *i, int v) { lua_pushinteger(L, v); lua_setfield(L, -2, i); } static void settabsb (lua_State *L, const char *i, int v) { lua_pushboolean(L, v); lua_setfield(L, -2, i); } static lua_State *getthread (lua_State *L, int *arg) { if (lua_isthread(L, 1)) { *arg = 1; return lua_tothread(L, 1); } else { *arg = 0; return L; } } static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { if (L == L1) { lua_pushvalue(L, -2); lua_remove(L, -3); } else lua_xmove(L1, L, 1); lua_setfield(L, -2, fname); } static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); const char *options = luaL_optstring(L, arg+2, "flnStu"); if (lua_isnumber(L, arg+1)) { if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } else if (lua_isfunction(L, arg+1)) { lua_pushfstring(L, ">%s", options); options = lua_tostring(L, -1); lua_pushvalue(L, arg+1); lua_xmove(L, L1, 1); } else return luaL_argerror(L, arg+1, "function or level expected"); if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+2, "invalid option"); lua_createtable(L, 0, 2); if (strchr(options, 'S')) { settabss(L, "source", ar.source); settabss(L, "short_src", ar.short_src); settabsi(L, "linedefined", ar.linedefined); settabsi(L, "lastlinedefined", ar.lastlinedefined); settabss(L, "what", ar.what); } if (strchr(options, 'l')) settabsi(L, "currentline", ar.currentline); if (strchr(options, 'u')) { settabsi(L, "nups", ar.nups); settabsi(L, "nparams", ar.nparams); settabsb(L, "isvararg", ar.isvararg); } if (strchr(options, 'n')) { settabss(L, "name", ar.name); settabss(L, "namewhat", ar.namewhat); } if (strchr(options, 't')) settabsb(L, "istailcall", ar.istailcall); if (strchr(options, 'L')) treatstackoption(L, L1, "activelines"); if (strchr(options, 'f')) treatstackoption(L, L1, "func"); return 1; /* return table */ } static int db_getlocal (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; int nvar = luaL_checkint(L, arg+2); /* local-variable index */ if (lua_isfunction(L, arg + 1)) { /* function argument? */ lua_pushvalue(L, arg + 1); /* push function */ lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ return 1; } else { /* stack-level argument */ if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); name = lua_getlocal(L1, &ar, nvar); if (name) { lua_xmove(L1, L, 1); /* push local value */ lua_pushstring(L, name); /* push name */ lua_pushvalue(L, -2); /* re-order */ return 2; } else { lua_pushnil(L); /* no name (nor value) */ return 1; } } } static int db_setlocal (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); luaL_checkany(L, arg+3); lua_settop(L, arg+3); lua_xmove(L, L1, 1); lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); return 1; } static int auxupvalue (lua_State *L, int get) { const char *name; int n = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TFUNCTION); name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); lua_insert(L, -(get+1)); return get + 1; } static int db_getupvalue (lua_State *L) { return auxupvalue(L, 1); } static int db_setupvalue (lua_State *L) { luaL_checkany(L, 3); return auxupvalue(L, 0); } static int checkupval (lua_State *L, int argf, int argnup) { lua_Debug ar; int nup = luaL_checkint(L, argnup); luaL_checktype(L, argf, LUA_TFUNCTION); lua_pushvalue(L, argf); lua_getinfo(L, ">u", &ar); luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index"); return nup; } static int db_upvalueid (lua_State *L) { int n = checkupval(L, 1, 2); lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); return 1; } static int db_upvaluejoin (lua_State *L) { int n1 = checkupval(L, 1, 2); int n2 = checkupval(L, 3, 4); luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); lua_upvaluejoin(L, 1, n1, 3, n2); return 0; } #define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY) static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = {"call", "return", "line", "count", "tail call"}; gethooktable(L); lua_pushthread(L); lua_rawget(L, -2); if (lua_isfunction(L, -1)) { lua_pushstring(L, hooknames[(int)ar->event]); if (ar->currentline >= 0) lua_pushinteger(L, ar->currentline); else lua_pushnil(L); lua_assert(lua_getinfo(L, "lS", ar)); lua_call(L, 2, 0); } } static int makemask (const char *smask, int count) { int mask = 0; if (strchr(smask, 'c')) mask |= LUA_MASKCALL; if (strchr(smask, 'r')) mask |= LUA_MASKRET; if (strchr(smask, 'l')) mask |= LUA_MASKLINE; if (count > 0) mask |= LUA_MASKCOUNT; return mask; } static char *unmakemask (int mask, char *smask) { int i = 0; if (mask & LUA_MASKCALL) smask[i++] = 'c'; if (mask & LUA_MASKRET) smask[i++] = 'r'; if (mask & LUA_MASKLINE) smask[i++] = 'l'; smask[i] = '\0'; return smask; } static int db_sethook (lua_State *L) { int arg, mask, count; lua_Hook func; lua_State *L1 = getthread(L, &arg); if (lua_isnoneornil(L, arg+1)) { lua_settop(L, arg+1); func = NULL; mask = 0; count = 0; /* turn off hooks */ } else { const char *smask = luaL_checkstring(L, arg+2); luaL_checktype(L, arg+1, LUA_TFUNCTION); count = luaL_optint(L, arg+3, 0); func = hookf; mask = makemask(smask, count); } if (gethooktable(L) == 0) { /* creating hook table? */ lua_pushstring(L, "k"); lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ lua_pushvalue(L, -1); lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ } lua_pushthread(L1); lua_xmove(L1, L, 1); lua_pushvalue(L, arg+1); lua_rawset(L, -3); /* set new hook */ lua_sethook(L1, func, mask, count); /* set hooks */ return 0; } static int db_gethook (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); char buff[5]; int mask = lua_gethookmask(L1); lua_Hook hook = lua_gethook(L1); if (hook != NULL && hook != hookf) /* external hook? */ lua_pushliteral(L, "external hook"); else { gethooktable(L); lua_pushthread(L1); lua_xmove(L1, L, 1); lua_rawget(L, -2); /* get hook */ lua_remove(L, -2); /* remove hook table */ } lua_pushstring(L, unmakemask(mask, buff)); lua_pushinteger(L, lua_gethookcount(L1)); return 3; } static int db_debug (lua_State *L) { for (;;) { char buffer[250]; luai_writestringerror("%s", "lua_debug> "); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || lua_pcall(L, 0, 0, 0)) luai_writestringerror("%s\n", lua_tostring(L, -1)); lua_settop(L, 0); /* remove eventual returns */ } } static int db_traceback (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); const char *msg = lua_tostring(L, arg + 1); if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ lua_pushvalue(L, arg + 1); /* return it untouched */ else { int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0); luaL_traceback(L, L1, msg, level); } return 1; } static const luaL_Reg dblib[] = { {"debug", db_debug}, {"getuservalue", db_getuservalue}, {"gethook", db_gethook}, {"getinfo", db_getinfo}, {"getlocal", db_getlocal}, {"getregistry", db_getregistry}, {"getmetatable", db_getmetatable}, {"getupvalue", db_getupvalue}, {"upvaluejoin", db_upvaluejoin}, {"upvalueid", db_upvalueid}, {"setuservalue", db_setuservalue}, {"sethook", db_sethook}, {"setlocal", db_setlocal}, {"setmetatable", db_setmetatable}, {"setupvalue", db_setupvalue}, {"traceback", db_traceback}, {NULL, NULL} }; LUAMOD_API int luaopen_debug (lua_State *L) { luaL_newlib(L, dblib); return 1; } blobby-1.0/data/gfx/font34.bmp000644 001750 001750 00000003370 12313310254 020722 0ustar00danielknobedanielknobe000000 000000 BM6( #-_&.gB$K]/E&i@ 0:_Jk;"c %e9c3KM_|dM (m !"'0mAv : K _{Z[*e -&`,{D "H  ,#T;'!3Rb7 _2Z,F0? {& A (y sGc%A  0Q;!R4)  4= wy[h4H+(:8Zu&?!oSQ( W7==cfncHO&7"]udu/E % #4JaebW9C-  qЄdr7I+'0 CZebXR1;)AoMx]g6GAN.\?oAx(uePN)6!ńoxOY+E(Y4U\φjא]ʏ4 kGM 1 ;VJz\c/>3 (N(-1); // Null rep. TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; void TiXmlString::reserve (size_type cap) { if (cap > capacity()) { TiXmlString tmp; tmp.init(length(), cap); memcpy(tmp.start(), data(), length()); swap(tmp); } } TiXmlString& TiXmlString::assign(const char* str, size_type len) { size_type cap = capacity(); if (len > cap || cap > 3*(len + 8)) { TiXmlString tmp; tmp.init(len); memcpy(tmp.start(), str, len); swap(tmp); } else { memmove(start(), str, len); set_size(len); } return *this; } TiXmlString& TiXmlString::append(const char* str, size_type len) { size_type newsize = length() + len; if (newsize > capacity()) { reserve (newsize + capacity()); } memmove(finish(), str, len); set_size(newsize); return *this; } TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) { TiXmlString tmp; tmp.reserve(a.length() + b.length()); tmp += a; tmp += b; return tmp; } TiXmlString operator + (const TiXmlString & a, const char* b) { TiXmlString tmp; TiXmlString::size_type b_len = static_cast( strlen(b) ); tmp.reserve(a.length() + b_len); tmp += a; tmp.append(b, b_len); return tmp; } TiXmlString operator + (const char* a, const TiXmlString & b) { TiXmlString tmp; TiXmlString::size_type a_len = static_cast( strlen(a) ); tmp.reserve(a_len + b.length()); tmp.append(a, a_len); tmp += b; return tmp; } #endif // TIXML_USE_STL blobby-1.0/src/lua/loslib.c000644 001750 001750 00000017573 12313310253 020421 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: loslib.c,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ #include #include #include #include #include #define loslib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** list of valid conversion specifiers for the 'strftime' function */ #if !defined(LUA_STRFTIMEOPTIONS) #if !defined(LUA_USE_POSIX) #define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } #else #define LUA_STRFTIMEOPTIONS \ { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \ "", "E", "cCxXyY", \ "O", "deHImMSuUVwWy" } #endif #endif /* ** By default, Lua uses tmpnam except when POSIX is available, where it ** uses mkstemp. */ #if defined(LUA_USE_MKSTEMP) #include #define LUA_TMPNAMBUFSIZE 32 #define lua_tmpnam(b,e) { \ strcpy(b, "/tmp/lua_XXXXXX"); \ e = mkstemp(b); \ if (e != -1) close(e); \ e = (e == -1); } #elif !defined(lua_tmpnam) #define LUA_TMPNAMBUFSIZE L_tmpnam #define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } #endif /* ** By default, Lua uses gmtime/localtime, except when POSIX is available, ** where it uses gmtime_r/localtime_r */ #if defined(LUA_USE_GMTIME_R) #define l_gmtime(t,r) gmtime_r(t,r) #define l_localtime(t,r) localtime_r(t,r) #elif !defined(l_gmtime) #define l_gmtime(t,r) ((void)r, gmtime(t)) #define l_localtime(t,r) ((void)r, localtime(t)) #endif static int os_execute (lua_State *L) { const char *cmd = luaL_optstring(L, 1, NULL); int stat = system(cmd); if (cmd != NULL) return luaL_execresult(L, stat); else { lua_pushboolean(L, stat); /* true if there is a shell */ return 1; } } static int os_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); return luaL_fileresult(L, remove(filename) == 0, filename); } static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); } static int os_tmpname (lua_State *L) { char buff[LUA_TMPNAMBUFSIZE]; int err; lua_tmpnam(buff, err); if (err) return luaL_error(L, "unable to generate a unique filename"); lua_pushstring(L, buff); return 1; } static int os_getenv (lua_State *L) { lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ return 1; } static int os_clock (lua_State *L) { lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); return 1; } /* ** {====================================================== ** Time/Date operations ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, ** wday=%w+1, yday=%j, isdst=? } ** ======================================================= */ static void setfield (lua_State *L, const char *key, int value) { lua_pushinteger(L, value); lua_setfield(L, -2, key); } static void setboolfield (lua_State *L, const char *key, int value) { if (value < 0) /* undefined? */ return; /* does not set field */ lua_pushboolean(L, value); lua_setfield(L, -2, key); } static int getboolfield (lua_State *L, const char *key) { int res; lua_getfield(L, -1, key); res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); lua_pop(L, 1); return res; } static int getfield (lua_State *L, const char *key, int d) { int res, isnum; lua_getfield(L, -1, key); res = (int)lua_tointegerx(L, -1, &isnum); if (!isnum) { if (d < 0) return luaL_error(L, "field " LUA_QS " missing in date table", key); res = d; } lua_pop(L, 1); return res; } static const char *checkoption (lua_State *L, const char *conv, char *buff) { static const char *const options[] = LUA_STRFTIMEOPTIONS; unsigned int i; for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) { if (*conv != '\0' && strchr(options[i], *conv) != NULL) { buff[1] = *conv; if (*options[i + 1] == '\0') { /* one-char conversion specifier? */ buff[2] = '\0'; /* end buffer */ return conv + 1; } else if (*(conv + 1) != '\0' && strchr(options[i + 1], *(conv + 1)) != NULL) { buff[2] = *(conv + 1); /* valid two-char conversion specifier */ buff[3] = '\0'; /* end buffer */ return conv + 2; } } } luaL_argerror(L, 1, lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); return conv; /* to avoid warnings */ } static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); struct tm tmr, *stm; if (*s == '!') { /* UTC? */ stm = l_gmtime(&t, &tmr); s++; /* skip `!' */ } else stm = l_localtime(&t, &tmr); if (stm == NULL) /* invalid date? */ lua_pushnil(L); else if (strcmp(s, "*t") == 0) { lua_createtable(L, 0, 9); /* 9 = number of fields */ setfield(L, "sec", stm->tm_sec); setfield(L, "min", stm->tm_min); setfield(L, "hour", stm->tm_hour); setfield(L, "day", stm->tm_mday); setfield(L, "month", stm->tm_mon+1); setfield(L, "year", stm->tm_year+1900); setfield(L, "wday", stm->tm_wday+1); setfield(L, "yday", stm->tm_yday+1); setboolfield(L, "isdst", stm->tm_isdst); } else { char cc[4]; luaL_Buffer b; cc[0] = '%'; luaL_buffinit(L, &b); while (*s) { if (*s != '%') /* no conversion specifier? */ luaL_addchar(&b, *s++); else { size_t reslen; char buff[200]; /* should be big enough for any conversion result */ s = checkoption(L, s + 1, cc); reslen = strftime(buff, sizeof(buff), cc, stm); luaL_addlstring(&b, buff, reslen); } } luaL_pushresult(&b); } return 1; } static int os_time (lua_State *L) { time_t t; if (lua_isnoneornil(L, 1)) /* called without args? */ t = time(NULL); /* get current time */ else { struct tm ts; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); /* make sure table is at the top */ ts.tm_sec = getfield(L, "sec", 0); ts.tm_min = getfield(L, "min", 0); ts.tm_hour = getfield(L, "hour", 12); ts.tm_mday = getfield(L, "day", -1); ts.tm_mon = getfield(L, "month", -1) - 1; ts.tm_year = getfield(L, "year", -1) - 1900; ts.tm_isdst = getboolfield(L, "isdst"); t = mktime(&ts); } if (t == (time_t)(-1)) lua_pushnil(L); else lua_pushnumber(L, (lua_Number)t); return 1; } static int os_difftime (lua_State *L) { lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), (time_t)(luaL_optnumber(L, 2, 0)))); return 1; } /* }====================================================== */ static int os_setlocale (lua_State *L) { static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME}; static const char *const catnames[] = {"all", "collate", "ctype", "monetary", "numeric", "time", NULL}; const char *l = luaL_optstring(L, 1, NULL); int op = luaL_checkoption(L, 2, "all", catnames); lua_pushstring(L, setlocale(cat[op], l)); return 1; } static int os_exit (lua_State *L) { int status; if (lua_isboolean(L, 1)) status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); else status = luaL_optint(L, 1, EXIT_SUCCESS); if (lua_toboolean(L, 2)) lua_close(L); if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ return 0; } static const luaL_Reg syslib[] = { {"clock", os_clock}, {"date", os_date}, {"difftime", os_difftime}, {"execute", os_execute}, {"exit", os_exit}, {"getenv", os_getenv}, {"remove", os_remove}, {"rename", os_rename}, {"setlocale", os_setlocale}, {"time", os_time}, {"tmpname", os_tmpname}, {NULL, NULL} }; /* }====================================================== */ LUAMOD_API int luaopen_os (lua_State *L) { luaL_newlib(L, syslib); return 1; } blobby-1.0/src/DuelMatchState.h000644 001750 001750 00000002453 12313310252 021216 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #pragma once #include "PhysicState.h" #include "GameLogicState.h" #include "PlayerInput.h" struct DuelMatchState { void swapSides(); bool operator==(const DuelMatchState& other) const; PhysicState worldState; GameLogicState logicState; PlayerInput playerInput[MAX_PLAYERS]; unsigned char errorSide; }; blobby-1.0/data/gfx/font26.bmp000644 001750 001750 00000003370 12313310254 020723 0ustar00danielknobedanielknobe000000 000000 BM6( !"U X^_Z \QR OP 64 $ %Q Th klpmpi lUXsuʴ# !>? ˻$! 4LRF%֧ @=ik5I"J^3\T7ƅ 4 06T R};|ZQDv q% 0#&@[]o;hO6 k]8 'Jgf:"4_>۵X B J*ߖ"  `xd#d# h2c7ؘ   k߀a |BdR j8SQҞ,6-_( K&B)=tǥC^$S|@TI Me' }nu 0) then CT_WaitCounter = CT_WaitCounter - 1 if (CT_WaitMoveTo > 0) then if (not IsAt(CT_WaitMoveTo)) then moveto(CT_WaitMoveTo) end end return true else return false end end function ResetWait() CT_WaitCounter = 0 CT_WaitName = "" end function OnOpponentServe() if (CT_ServeIndex == 0) then CT_ServeIndex = math.random(1,3) end if (not IsAt(CT_ServeOpp[CT_ServeIndex])) then moveto(CT_ServeOpp[CT_ServeIndex]) end end function OnServe(ballready) if (WaitQueue()) then return end if (CT_ServeIndex == 0) then CT_ServeIndex = math.random(1,6) end if (ballready) then if (Wait("ServeDelay",math.random(28,90),CT_ServeSelf[CT_ServeIndex]+math.random(-150, 150))) then return end if (IsAt(CT_ServeSelf[CT_ServeIndex])) then jump() else moveto(CT_ServeSelf[CT_ServeIndex]) end else if (posx() < 150) then jump() end moveto(40) end end function OnGame() ResetWait() CT_ServeIndex = 0 local timeJump = timeToHitHeight(380, 390, 20) local timeGround = timeToHitHeight(200, 222, 40) local timeBlock = timeToOppSmash(390) local estimhx = r_estimx(timeJump) local estimGround = r_estimx(timeGround) local estimBlock = r_estimx(timeBlock) local block = 0 local wallcoll = willHitWall(timeJump) if (timeBlock ~= -1) then timeBlock = timeBlock+(estimBlock-400)/13 end if (timeBlock == -1) then timeBlock = 9999 end if (timeJump == -1) then estimhx = 9999 end if (timeGround == -1) then estimGround = 210 end if (CT_SkipNextBlock == 0) then CT_SkipNextBlock = math.random(1,10) end if (posy() < CT_LastHeight and posy() > 150 and posy() < 330) then CT_Action = "" end CT_LastHeight = posy() if (CT_Action == "NetBlock") then if ((posy() < 150) or (timeBlock <= 8 and oppy() < 150) or (ballx() <= posx()) or (touches() <= 0 and bspeedx() > 9)) then CT_Action = "" else jump() moveto(400) return end elseif (CT_Action == "JumpPlayFwd") then if ((posy() < 150) or (touches() ~= CT_LastTouches)) then CT_Action = "" else if (estimhx == 9999) then estimhx = ballx()+bspeedx() end jump() if (posy() > 300) then if (math.abs(bally()-posy()) < 18) then moveto(ballx()+bspeedx()) elseif (estimhx < 200) then moveto(estimhx-50) elseif (oppx() > 600 and oppy() < 150) then if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(4,6) end moveto(estimhx-10*CT_ShotDecision) elseif (oppx() < 600 and oppy() > 180) then moveto(estimhx-40) else moveto(estimhx-60) end else moveto(estimhx-70) end return end elseif (CT_Action == "JumpPlayRev") then if ((posy() < 150) or (touches() ~= CT_LastTouches)) then CT_Action = "" else if (estimhx == 9999) then estimhx = ballx()+bspeedx() end jump() if (CT_ShotDecision == 0 and touches() == 2) then CT_ShotDecision = math.random(5,6) end if (CT_ShotDecision == 0) then CT_ShotDecision = math.random(3,6) end if (bspeedx() > 5 and touches() < 2 and CT_ShotDecision < 6) then CT_ShotDecision = math.random(6,8) end if (math.abs(bally()-posy()) < 18) then moveto(ballx()+bspeedx()) else moveto(estimhx+5*CT_ShotDecision) end return end end if (touches() ~= CT_LastTouches) then CT_LastTouches = touches() CT_NextGround = math.random(-20,20) CT_SkipNextBlock = 0 end if (CT_Action == "") then if ((ballx() < 400 or bspeedx() < -2 or bspeedx() > 10) and estimGround < 400) then if (touches() >= 2) then moveto(estimGround+(posx()-500)/22) elseif (math.abs(bspeedx()) > 8) then moveto(estimGround) else moveto(estimGround+CT_NextGround) end elseif (estimhx < 650 and math.abs(bspeedx()) < 6) then moveto(215) elseif (estimhx > 650) then moveto(250) else moveto(180) end end if (posy() > 150) then return end if (touches() > 2) then return end if (timeBlock >= 23 and timeBlock <= 25 and CT_SkipNextBlock ~= 1) then if (posx() > 210 and estimBlock > 395 and estimBlock < 650 and not wallcoll) then jump() moveto(400) CT_Action = "NetBlock" return end end if (timeJump >= 17 and timeJump <= 19) then if (bspeedx() <= 7 and estimhx >= 65 and estimhx <= 420 and posx()-estimhx <= 90 and (bspeedx() >= -7 or not wallcoll)) then if (estimGround > 400 or bally() > 250) then CT_Action = "JumpPlayFwd" CT_ShotDecision = 0 jump() end end if ((wallcoll or bspeedx() >= -7) and estimhx <= 250 and posx()-estimhx >= -90) then if (estimGround > 400 or bally() > 250) then if (CT_Action == "JumpPlayFwd" and (touches() >= 2 or math.random(100) > 15)) then return end CT_Action = "JumpPlayRev" CT_ShotDecision = 0 jump() end end end end function timeToHitHeight(minheight, maxheight, depth) local i = 0 for i=1, depth do if (estimy(i) >= minheight and estimy(i) <= maxheight) then return i end end return -1 end function timeToOppSmash(height) if (bally() < height) then return -1 end local i = 0 for i=1, 17 do if (estimy(i) < height) then return i end end return -1 end function r_estimx(time) local estim = estimx(time) if estim < 31.5 then estim = 63-estim end if estim > 768.5 then estim = 1537-estim end if (bally() < 330) then if (ballx() < 400 and estim > 400) then estim = 723-estim end if (ballx() > 400 and estim < 400) then estim = 877-estim end end return estim end function willHitWall(time) if (estimx(time) < 31.5) then return true end if (estimx(time) > 768.5) then return true end return false endblobby-1.0/src/SpeedController.h000644 001750 001750 00000005040 12313310252 021446 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /** * @file SpeedController.h * @brief Contains a class which determine the framerate */ #pragma once #include "BlobbyDebug.h" /// \brief class controlling game speed /// \details This class can control the game speed and the displayed FPS. /// It is updated once a frame and waits the necessary time. /// A distinction is made between game FPS and real FPS. /// Game FPS is the number of game loop iterations per second, /// real FPS is the number of screen updates per second. The real /// FPS is reached with framedropping /// The class can report how much time is actually waited. If this value /// is close to zero, the real speed can be altered. class SpeedController : public ObjectCounter { public: SpeedController(float gameFPS); ~SpeedController(); void setGameSpeed(float fps); float getGameSpeed() const{return mGameFPS;} /// This reports whether a framedrop is necessary to hold the real FPS bool doFramedrop() const; /// gives the caller the fps of the drawn frames: int getFPS() const { return mFPS; } void setDrawFPS(bool draw) { mDrawFPS = draw; } //help methods bool getDrawFPS() const { return mDrawFPS; } /// This updates everything and waits the necessary time void update(); static void setMainInstance(SpeedController* inst) { mMainInstance = inst; } static SpeedController* getMainInstance() { return mMainInstance; } private: float mGameFPS; int mFPS; int mFPSCounter; bool mFramedrop; bool mDrawFPS; static SpeedController* mMainInstance; int mOldTicks; // internal data unsigned int mBeginSecond; int mCounter; }; blobby-1.0/data/gfx/ball14.bmp000644 001750 001750 00000012066 12313310254 020666 0ustar00danielknobedanielknobe000000 000000 BM66(@@ pmpfdf|z|NMNihi`^_ywxjffgeeonnxvu|{zrqpaa_  $%$z|zoqo~~yzyhihefeadb  vwwfggeffcefbcdUVX{|~z{} ffi__aXXZvvxeegxxynnodde}}}|||xxxuuurrrpppkkkeeedddcccbbb```___]]]ZZZWWWTTTQQQKKK===///w"$ ^^ x ^_/vv^xw$$ 9]\\\Wvv$wv\]/ xv-\v/\2]]$ ""nh]>cccddzz& 6I(kHI*4nd#d>cccdz&'eH[IJfKgngdccccddd&QF[o4gdcDEccccdd&P ǖfautbaaDcccddd&6 {dEEb>ccdd&?{e[&C>EDE>>ccddz{'(EEccEE>cd&&F?'eHBBBB`cccdd& 'QCBEEcccd'{CB`aEE>ccczz@y BABC%aacc&zCB = B`C>AC BBCdCBBtcaBCcadCBEdzCCCCCCaE>P`CCaEBB%blobby-1.0/src/lua/lstring.h000644 001750 001750 00000002370 12313310253 020611 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lstring.h,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ #ifndef lstring_h #define lstring_h #include "lgc.h" #include "lobject.h" #include "lstate.h" #define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) #define sizeudata(u) (sizeof(union Udata)+(u)->len) #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) #define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) /* ** test whether a string is a reserved word */ #define isreserved(s) ((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0) /* ** equality for short strings, which are always internalized */ #define eqshrstr(a,b) check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b)) LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); LUAI_FUNC int luaS_eqstr (TString *a, TString *b); LUAI_FUNC void luaS_resize (lua_State *L, int newsize); LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); #endif blobby-1.0/src/IMGUI.cpp000644 001750 001750 00000061011 12313310251 017546 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "IMGUI.h" /* includes */ #include #include #include #include "InputManager.h" /* implementation */ enum ObjectType { IMAGE, OVERLAY, TEXT, BUTTON, // Unused! SCROLLBAR, ACTIVESCROLLBAR, EDITBOX, ACTIVEEDITBOX, SELECTBOX, ACTIVESELECTBOX, BLOB, CHAT }; struct QueueObject { ObjectType type; int id; Vector2 pos1; Vector2 pos2; Color col; float alpha; std::string text; std::vector entries; int selected; int length; unsigned int flags; }; typedef std::queue RenderQueue; IMGUI* IMGUI::mSingleton = 0; RenderQueue *mQueue; IMGUI::IMGUI() { mQueue = new RenderQueue; mActiveButton = -1; mHeldWidget = 0; mLastKeyAction = NONE; mLastWidget = 0; mButtonReset = false; mInactive = false; } IMGUI::~IMGUI() { delete mQueue; } IMGUI& IMGUI::getSingleton() { if (!mSingleton) mSingleton = new IMGUI; return *mSingleton; } void IMGUI::begin() { mUsingCursor = false; mButtonReset = false; while (!mQueue->empty()) mQueue->pop(); mLastKeyAction = NONE; if (InputManager::getSingleton()->up()) mLastKeyAction = UP; if (InputManager::getSingleton()->down()) mLastKeyAction = DOWN; if (InputManager::getSingleton()->left()) mLastKeyAction = LEFT; if (InputManager::getSingleton()->right()) mLastKeyAction = RIGHT; if (InputManager::getSingleton()->select()) mLastKeyAction = SELECT; if (InputManager::getSingleton()->exit()) mLastKeyAction = BACK; } void IMGUI::end() { int FontSize; RenderManager& rmanager = RenderManager::getSingleton(); while (!mQueue->empty()) { QueueObject& obj = mQueue->front(); switch (obj.type) { case IMAGE: rmanager.drawImage(obj.text, obj.pos1, obj.pos2); break; case OVERLAY: rmanager.drawOverlay(obj.alpha, obj.pos1, obj.pos2, obj.col); break; case TEXT: rmanager.drawText(obj.text, obj.pos1, obj.flags); break; case SCROLLBAR: rmanager.drawOverlay(0.5, obj.pos1, obj.pos1 + Vector2(210.0, 26.0)); rmanager.drawImage("gfx/scrollbar.bmp",obj.pos1 + Vector2(obj.pos2.x * 200.0 + 5 , 13)); break; case ACTIVESCROLLBAR: rmanager.drawOverlay(0.4, obj.pos1, obj.pos1 + Vector2(210.0, 26.0)); rmanager.drawImage("gfx/scrollbar.bmp",obj.pos1 + Vector2(obj.pos2.x * 200.0 + 5 , 13)); break; case EDITBOX: FontSize = (obj.flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL); rmanager.drawOverlay(0.5, obj.pos1, obj.pos1 + Vector2(10+obj.length*FontSize, 10+FontSize)); rmanager.drawText(obj.text, obj.pos1+Vector2(5, 5), obj.flags); break; case ACTIVEEDITBOX: FontSize = (obj.flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL); rmanager.drawOverlay(0.3, obj.pos1, obj.pos1 + Vector2(10+obj.length*FontSize, 10+FontSize)); rmanager.drawText(obj.text, obj.pos1+Vector2(5, 5), obj.flags); if (obj.pos2.x >= 0) rmanager.drawOverlay(1.0, Vector2((obj.pos2.x)*FontSize+obj.pos1.x+5, obj.pos1.y+5), Vector2((obj.pos2.x)*FontSize+obj.pos1.x+5+3, obj.pos1.y+5+FontSize), Color(255,255,255)); break; case SELECTBOX: FontSize = (obj.flags & TF_SMALL_FONT ? (FONT_WIDTH_SMALL+LINE_SPACER_SMALL) : (FONT_WIDTH_NORMAL+LINE_SPACER_NORMAL)); rmanager.drawOverlay(0.5, obj.pos1, obj.pos2); for (unsigned int c = 0; c < obj.entries.size(); c++) { if( c == static_cast(obj.selected) ) rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags | TF_HIGHLIGHT); else rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags); } break; case ACTIVESELECTBOX: FontSize = (obj.flags & TF_SMALL_FONT ? (FONT_WIDTH_SMALL+LINE_SPACER_SMALL) : (FONT_WIDTH_NORMAL+LINE_SPACER_NORMAL)); rmanager.drawOverlay(0.3, obj.pos1, obj.pos2); for (unsigned int c = 0; c < obj.entries.size(); c++) { if( c == static_cast(obj.selected) ) rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags | TF_HIGHLIGHT); else rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags); } break; case CHAT: FontSize = (obj.flags & TF_SMALL_FONT ? (FONT_WIDTH_SMALL+LINE_SPACER_SMALL) : (FONT_WIDTH_NORMAL+LINE_SPACER_NORMAL)); rmanager.drawOverlay(0.5, obj.pos1, obj.pos2); for (unsigned int c = 0; c < obj.entries.size(); c++) { if (obj.text[c] == 'R' ) rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags | TF_HIGHLIGHT); else rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags); } break; case BLOB: rmanager.drawBlob(obj.pos1, obj.col); break; default: break; } mQueue->pop(); } #if __DESKTOP__ if (mDrawCursor) { rmanager.drawImage("gfx/cursor.bmp", InputManager::getSingleton()->position() + Vector2(24.0, 24.0)); mDrawCursor = false; } #endif } void IMGUI::doImage(int id, const Vector2& position, const std::string& name, const Vector2& size) { QueueObject obj; obj.type = IMAGE; obj.id = id; obj.pos1 = position; obj.pos2 = size; obj.text = name; mQueue->push(obj); } void IMGUI::doText(int id, const Vector2& position, const std::string& text, unsigned int flags) { QueueObject obj; obj.type = TEXT; obj.id = id; obj.pos1 = position; int fontSize = flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL; // update position depending on alignment if( flags & TF_ALIGN_CENTER ) { obj.pos1.x -= text.size() * fontSize / 2; } if( flags & TF_ALIGN_RIGHT ) { obj.pos1.x -= text.size() * fontSize; } obj.text = text; obj.flags = flags; mQueue->push(obj); } void IMGUI::doText(int id, const Vector2& position, TextManager::STRING text, unsigned int flags) { doText(id, position, TextManager::getSingleton()->getString(text), flags); } void IMGUI::doOverlay(int id, const Vector2& pos1, const Vector2& pos2, const Color& col, float alpha) { QueueObject obj; obj.type = OVERLAY; obj.id = id; obj.pos1 = pos1; obj.pos2 = pos2; obj.col = col; obj.alpha = alpha; mQueue->push(obj); RenderManager::getSingleton().redraw(); } bool IMGUI::doButton(int id, const Vector2& position, TextManager::STRING text, unsigned int flags) { return doButton(id, position, TextManager::getSingleton()->getString(text), flags); } bool IMGUI::doButton(int id, const Vector2& position, const std::string& text, unsigned int flags) { bool clicked = false; QueueObject obj; obj.id = id; obj.pos1 = position; obj.text = text; obj.type = TEXT; obj.flags = flags; int fontSize = flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL; // update position depending on alignment if( flags & TF_ALIGN_CENTER ) { obj.pos1.x -= text.size() * fontSize / 2; } if( flags & TF_ALIGN_RIGHT ) { obj.pos1.x -= text.size() * fontSize; } if (!mInactive) { // M.W. : Activate cursorless object-highlighting once the up or down key is pressed. if (mActiveButton == -1) { switch (mLastKeyAction) { case DOWN: mActiveButton = 0; mLastKeyAction = NONE; break; case UP: mActiveButton = mLastWidget; mLastKeyAction = NONE; break; default: break; } } // Highlight first menu object for arrow key navigation. if (mActiveButton == 0 && !mButtonReset) mActiveButton = id; // React to keyboard input. if (id == mActiveButton) { obj.flags = obj.flags | TF_HIGHLIGHT; switch (mLastKeyAction) { case DOWN: mActiveButton = 0; mLastKeyAction = NONE; break; case UP: mActiveButton = mLastWidget; mLastKeyAction = NONE; break; case SELECT: clicked = true; mLastKeyAction = NONE; break; default: break; } } // React to back button if (mLastKeyAction == BACK) { if ((text == (TextManager::getSingleton())->getString(TextManager::LBL_CANCEL)) || (text == (TextManager::getSingleton())->getString(TextManager::MNU_LABEL_EXIT))) { //todo: Workarround to catch backkey clicked = true; mActiveButton = id; } } #if __MOBILE__ const int tolerance = 3; #else const int tolerance = 0; #endif // React to mouse input. Vector2 mousepos = InputManager::getSingleton()->position(); if (mousepos.x + tolerance >= position.x && mousepos.y + tolerance * 2 >= position.y && mousepos.x - tolerance <= position.x + text.length() * (flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL) && mousepos.y - tolerance * 2 <= position.y + (flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL)) { obj.flags = obj.flags #if __DESKTOP__ | TF_HIGHLIGHT #endif ; if (InputManager::getSingleton()->click()) { clicked = true; mActiveButton = id; } } } mLastWidget = id; mQueue->push(obj); return clicked; } bool IMGUI::doImageButton(int id, const Vector2& position, const Vector2& size, const std::string& image) { doImage(id, position, image); // React to mouse input. if (InputManager::getSingleton()->click()) { Vector2 mousepos = InputManager::getSingleton()->position(); Vector2 btnpos = position - size * 0.5; if (mousepos.x > btnpos.x && mousepos.y > btnpos.y && mousepos.x < btnpos.x + size.x && mousepos.y < btnpos.y + size.y) { return true; } } return false; } bool IMGUI::doScrollbar(int id, const Vector2& position, float& value) { QueueObject obj; obj.id = id; obj.pos1 = position; obj.type = SCROLLBAR; bool deselected = false; if (InputManager::getSingleton()->unclick()) { if (id == mHeldWidget) deselected = true; mHeldWidget = 0; } if (!mInactive) { // M.W. : Activate cursorless object-highlighting once the up or down key is pressed. if (mActiveButton == -1) { switch (mLastKeyAction) { case DOWN: mActiveButton = 0; mLastKeyAction = NONE; break; case UP: mActiveButton = mLastWidget; mLastKeyAction = NONE; break; default: break; } } // Highlight first menu object for arrow key navigation. if (mActiveButton == 0 && !mButtonReset) mActiveButton = id; // React to keyboard input. if (id == mActiveButton) { obj.type = ACTIVESCROLLBAR; switch (mLastKeyAction) { case DOWN: mActiveButton = 0; mLastKeyAction = NONE; break; case UP: mActiveButton = mLastWidget; mLastKeyAction = NONE; break; case LEFT: value -= 0.1; mLastKeyAction = NONE; break; case RIGHT: value += 0.1; mLastKeyAction = NONE; break; default: break; } } #if __MOBILE__ const int tolerance = 3; #else const int tolerance = 0; #endif // React to mouse input. Vector2 mousepos = InputManager::getSingleton()->position(); if (mousepos.x + 5 > position.x && mousepos.y + tolerance * 2 > position.y && mousepos.x < position.x + 205 && mousepos.y - tolerance < position.y + 24.0) { obj.type = ACTIVESCROLLBAR; if (InputManager::getSingleton()->click()) { mHeldWidget = id; } if (mHeldWidget == id) { value = (mousepos.x - position.x) / 200.0; mActiveButton = id; } if(InputManager::getSingleton()->mouseWheelUp()) value += 0.1; if(InputManager::getSingleton()->mouseWheelDown()) value -= 0.1; } } value = value > 0.0 ? (value < 1.0 ? value : 1.0) : 0.0; obj.pos2.x = value; mLastWidget = id; mQueue->push(obj); return deselected; } void IMGUI::resetSelection() { mInactive = false; mActiveButton = -1; mButtonReset = true; } bool IMGUI::doEditbox(int id, const Vector2& position, unsigned int length, std::string& text, unsigned& cpos, unsigned int flags, bool force_active) { int FontSize = (flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL); bool changed = false; QueueObject obj; obj.id = id; obj.pos1 = position; obj.type = EDITBOX; obj.length = length; // lenght does not actually work! obj.flags = flags; // React to mouse input. Vector2 mousepos = InputManager::getSingleton()->position(); if (mousepos.x > position.x && mousepos.y > position.y && mousepos.x < position.x + length * FontSize + 10 && mousepos.y < position.y + FontSize + 10) { obj.flags = obj.flags | TF_HIGHLIGHT; if (InputManager::getSingleton()->click()) { // Handle click on the text. if (mousepos.x < position.x + text.length() * FontSize) cpos = (int) ((mousepos.x-position.x-5+(FontSize/2)) / FontSize); // Handle click behind the text. else if (mousepos.x < position.x + length * FontSize + 10) cpos = (int) text.length(); mActiveButton = id; // Show keyboard SDL_StartTextInput(); } } if (!mInactive) { // M.W. : Activate cursorless object-highlighting once the up or down key is pressed. if (mActiveButton == -1) { switch (mLastKeyAction) { case DOWN: mActiveButton = 0; mLastKeyAction = NONE; break; case UP: mActiveButton = mLastWidget; mLastKeyAction = NONE; break; default: break; } // M.W. : Initialize the cursor position at the end of the string. // IMPORTANT: If you make changes to EditBox text that alter the length // of the text, either call resetSelection() to come back // to this area of code or update cpos manually to prevent // crashes due to a misplaced cursor. cpos = text.length(); } // Highlight first menu object for arrow key navigation. if (mActiveButton == 0 && !mButtonReset) mActiveButton = id; // React to keyboard input. if (id == mActiveButton || force_active) { obj.type = ACTIVEEDITBOX; switch (mLastKeyAction) { case DOWN: mActiveButton = 0; mLastKeyAction = NONE; break; case UP: mActiveButton = mLastWidget; mLastKeyAction = NONE; break; case LEFT: if (cpos > 0) cpos--; mLastKeyAction = NONE; break; case RIGHT: if (cpos < text.length()) cpos++; mLastKeyAction = NONE; break; default: break; } std::string input = InputManager::getSingleton()->getLastTextKey(); if (input == "backspace" && text.length() > 0 && cpos > 0) { text.erase(cpos - 1, 1); cpos--; } else if (input == "del" && text.length() > cpos) { text.erase(cpos, 1); } else if (input == "return") { // Workarround for chatwindow! Delete this after GUI-Rework changed = true; } // This is a temporary solution until the new // UTF-8 class can tell the real length!!! else if (text.length() < length) { if (input == "space") { text.insert(cpos, " "); cpos++; changed = true; } else if (input == "keypad0") { text.insert(cpos, "0"); cpos++; changed = true; } else if (input == "keypad1") { text.insert(cpos, "1"); cpos++; changed = true; } else if (input == "keypad2") { text.insert(cpos, "2"); cpos++; changed = true; } else if (input == "keypad3") { text.insert(cpos, "3"); cpos++; changed = true; } else if (input == "keypad4") { text.insert(cpos, "4"); cpos++; changed = true; } else if (input == "keypad5") { text.insert(cpos, "5"); cpos++; changed = true; } else if (input == "keypad6") { text.insert(cpos, "6"); cpos++; changed = true; } else if (input == "keypad7") { text.insert(cpos, "7"); cpos++; changed = true; } else if (input == "keypad8") { text.insert(cpos, "8"); cpos++; changed = true; } else if (input == "keypad9") { text.insert(cpos, "9"); cpos++; changed = true; } else if (input.length() == 1) { text.insert(cpos, input); cpos++; changed = true; } } } } obj.pos2.x = SDL_GetTicks() % 1000 >= 500 ? cpos : -1.0; obj.text = text; mLastWidget = id; mQueue->push(obj); // when content changed, it is active // part of chat window hack if( changed && force_active ) mActiveButton = id; return changed; } SelectBoxAction IMGUI::doSelectbox(int id, const Vector2& pos1, const Vector2& pos2, const std::vector& entries, unsigned int& selected, unsigned int flags) { int FontSize = (flags & TF_SMALL_FONT ? (FONT_WIDTH_SMALL+LINE_SPACER_SMALL) : (FONT_WIDTH_NORMAL+LINE_SPACER_NORMAL)); SelectBoxAction changed = SBA_NONE; QueueObject obj; obj.id = id; obj.pos1 = pos1; obj.pos2 = pos2; obj.type = SELECTBOX; obj.flags = flags; const int itemsPerPage = int(pos2.y - pos1.y - 10) / FontSize; int first = (int)(selected / itemsPerPage)*itemsPerPage; //the first visible element in the list if (!mInactive) { // M.W. : Activate cursorless object-highlighting once the up or down key is pressed. if (mActiveButton == -1) { switch (mLastKeyAction) { case DOWN: mActiveButton = 0; mLastKeyAction = NONE; break; case UP: mActiveButton = mLastWidget; mLastKeyAction = NONE; break; default: break; } } // Highlight first menu object for arrow key navigation. if (mActiveButton == 0 && !mButtonReset) mActiveButton = id; // React to keyboard input. if (id == mActiveButton) { obj.type = ACTIVESELECTBOX; switch (mLastKeyAction) { case DOWN: mActiveButton = 0; mLastKeyAction = NONE; break; case UP: mActiveButton = mLastWidget; mLastKeyAction = NONE; break; case LEFT: if (selected > 0) { selected--; changed = SBA_SELECT; } mLastKeyAction = NONE; break; case RIGHT: if (selected + 1 < entries.size()) { selected++; changed = SBA_SELECT; } mLastKeyAction = NONE; break; default: break; } } // React to mouse input. Vector2 mousepos = InputManager::getSingleton()->position(); if (mousepos.x > pos1.x && mousepos.y > pos1.y && mousepos.x < pos2.x && mousepos.y < pos2.y) { obj.type = ACTIVESELECTBOX; if (InputManager::getSingleton()->click()) mActiveButton = id; } //entries mouseclick: if (mousepos.x > pos1.x && mousepos.y > pos1.y+5 && mousepos.x < pos2.x-35 && mousepos.y < pos1.y+5+FontSize*itemsPerPage) { if (InputManager::getSingleton()->click()) { int tmp = (int)((mousepos.y - pos1.y - 5) / FontSize) + first; /// \todo well, it's not really a doulbe click... /// we need to do this in inputmanager if( selected == tmp && InputManager::getSingleton()->doubleClick() ) changed = SBA_DBL_CLICK; if (tmp >= 0 && static_cast(tmp) < entries.size()) selected = tmp; mActiveButton = id; } if ((InputManager::getSingleton()->mouseWheelUp()) && (selected > 0)) { selected--; changed = SBA_SELECT; } if ((InputManager::getSingleton()->mouseWheelDown()) && (selected + 1 < entries.size())) { selected++; changed = SBA_SELECT; } } //arrows mouseclick: if (mousepos.x > pos2.x-30 && mousepos.x < pos2.x-30+24 && InputManager::getSingleton()->click()) { if (mousepos.y > pos1.y+3 && mousepos.y < pos1.y+3+24 && selected > 0) { selected--; changed = SBA_SELECT; } if (mousepos.y > pos2.y-27 && mousepos.y < pos2.y-27+24 && selected + 1 < entries.size()) { selected++; changed = SBA_SELECT; } } } doImage(GEN_ID, Vector2(pos2.x-15, pos1.y+15), "gfx/pfeil_oben.bmp"); doImage(GEN_ID, Vector2(pos2.x-15, pos2.y-15), "gfx/pfeil_unten.bmp"); first = (selected / itemsPerPage)*itemsPerPage; //recalc first if ( !entries.empty() ) { unsigned int last = first + itemsPerPage; if (last > entries.size()) last = entries.size(); obj.entries = std::vector(entries.begin()+first, entries.begin()+last); } else obj.entries = std::vector(); obj.selected = selected-first; mLastWidget = id; mQueue->push(obj); return changed; } void IMGUI::doChatbox(int id, const Vector2& pos1, const Vector2& pos2, const std::vector& entries, unsigned int& selected, const std::vector& local, unsigned int flags) { assert( entries.size() == local.size() ); int FontSize = (flags & TF_SMALL_FONT ? (FONT_WIDTH_SMALL+LINE_SPACER_SMALL) : (FONT_WIDTH_NORMAL+LINE_SPACER_NORMAL)); QueueObject obj; obj.id = id; obj.pos1 = pos1; obj.pos2 = pos2; obj.type = CHAT; obj.flags = flags; const unsigned int itemsPerPage = int(pos2.y - pos1.y - 10) / FontSize; if (!mInactive) { // M.W. : Activate cursorless object-highlighting once the up or down key is pressed. if (mActiveButton == -1) { switch (mLastKeyAction) { case DOWN: mActiveButton = 0; mLastKeyAction = NONE; break; case UP: mActiveButton = mLastWidget; mLastKeyAction = NONE; break; default: break; } } // Highlight first menu object for arrow key navigation. if (mActiveButton == 0 && !mButtonReset) mActiveButton = id; // React to keyboard input. if (id == mActiveButton) { switch (mLastKeyAction) { case DOWN: mActiveButton = 0; mLastKeyAction = NONE; break; case UP: mActiveButton = mLastWidget; mLastKeyAction = NONE; break; case LEFT: if (selected > 0) { selected--; } mLastKeyAction = NONE; break; case RIGHT: if (selected + 1 < entries.size()) { selected++; } mLastKeyAction = NONE; break; default: break; } } // React to mouse input. Vector2 mousepos = InputManager::getSingleton()->position(); if (mousepos.x > pos1.x && mousepos.y > pos1.y && mousepos.x < pos2.x && mousepos.y < pos2.y) { if (InputManager::getSingleton()->click()) mActiveButton = id; } //entries mouseclick: if (mousepos.x > pos1.x && mousepos.y > pos1.y+5 && mousepos.x < pos2.x-35 && mousepos.y < pos1.y+5+FontSize*itemsPerPage) { if ((InputManager::getSingleton()->mouseWheelUp()) && (selected > 0)) { selected--; } if ((InputManager::getSingleton()->mouseWheelDown()) && (selected + 1 < entries.size())) { selected++; } } //arrows mouseclick: if (mousepos.x > pos2.x-30 && mousepos.x < pos2.x-30+24 && InputManager::getSingleton()->click()) { if (mousepos.y > pos1.y+3 && mousepos.y < pos1.y+3+24 && selected > 0) { selected--; } if (mousepos.y > pos2.y-27 && mousepos.y < pos2.y-27+24 && selected + 1 < entries.size()) { selected++; } } } doImage(GEN_ID, Vector2(pos2.x-15, pos1.y+15), "gfx/pfeil_oben.bmp"); doImage(GEN_ID, Vector2(pos2.x-15, pos2.y-15), "gfx/pfeil_unten.bmp"); unsigned int first = (selected / itemsPerPage) * itemsPerPage; //recalc first if ( !entries.empty() ) { unsigned int last = selected + 1; /// \todo maybe we should adapt selected so we even can't scroll up further! // we don't want negative chatlog, so we just scroll upward without coming to negative // elements. if (last >= itemsPerPage) first = last - itemsPerPage; else first = 0; // check that we don't create out of bounds problems if(last > entries.size()) { last = entries.size(); } obj.entries = std::vector(entries.begin()+first, entries.begin()+last); // HACK: we use taxt to store information which text is from local player and which from // remote player. obj.text = ""; for(unsigned int i = first; i < last; ++i) { obj.text += local[i] ? 'L' : 'R'; } } else obj.entries = std::vector(); obj.selected = selected-first; mLastWidget = id; mQueue->push(obj); } bool IMGUI::doBlob(int id, const Vector2& position, const Color& col) { QueueObject obj; obj.id = id; obj.pos1 = position; obj.type = BLOB; obj.col = col; mQueue->push(obj); return false; } bool IMGUI::usingCursor() const { return mUsingCursor; } blobby-1.0/src/BotAPICalculations.cpp000644 001750 001750 00000014515 12313310251 022323 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ /* header include */ #include "BotAPICalculations.h" /* includes */ #include #include #include "GameConstants.h" /* implementation */ bool FLAG_BOUNCE = false; // helpers float time_to_x_direct(float pos, float vel, float destination); float time_to_y_direct(float pos, float vel, float destination); float parabel_time_first(float pos, float vel, float gravity, float destination); float make_unsigned(float f) { return (f > 0 ? f : std::numeric_limits::infinity()); } void reset_flags() { FLAG_BOUNCE = false; } float time_to_x(const Vector2& pos, const Vector2& vel, float destination) { // check whether velocity is valid if( vel.x == 0 ) return std::numeric_limits::max(); // direct? float timedirect = time_to_x_direct(pos.x, vel.x, destination); // needs wall bounce if( timedirect < 0 ) { FLAG_BOUNCE = true; float wall = vel.x > 0 ? (RIGHT_PLANE - BALL_RADIUS) : BALL_RADIUS; float twall = time_to_x_direct(pos.x, vel.x, wall); float net = vel.x > 0 ? (NET_POSITION_X - BALL_RADIUS - NET_RADIUS) : (NET_POSITION_X + BALL_RADIUS + NET_RADIUS); float tnet = make_unsigned(time_to_x_direct(pos.x, vel.x, net)); if ( tnet < twall ) { Vector2 nhitpos = Vector2(net, predict_y(pos, vel, tnet)); if ( nhitpos.y > NET_SPHERE_POSITION - NET_RADIUS - BALL_RADIUS ) return tnet + time_to_x(nhitpos, vel.reflectX(), destination); } Vector2 whitpos = Vector2(wall, predict_y(pos, vel, twall)); return twall + time_to_x(whitpos, vel.reflectX(), destination); } float net = vel.x > 0 ? (NET_POSITION_X - BALL_RADIUS - NET_RADIUS) : (NET_POSITION_X + BALL_RADIUS + NET_RADIUS); float tnet = make_unsigned(time_to_x_direct(pos.x, vel.x, net)); Vector2 nhitpos = Vector2(net, predict_y(pos, vel, tnet)); if ( tnet > timedirect || nhitpos.y < NET_SPHERE_POSITION - NET_RADIUS - BALL_RADIUS) { // if ball is too high or destination is reached before net, no collision can occur return timedirect; } FLAG_BOUNCE = true; // if ball hits net on false side, it is impossible to reach its destination if( nhitpos.y > pos.y ) { return std::numeric_limits::max(); } return tnet + time_to_x(nhitpos, vel.reflectX(), destination); } float time_to_y(const Vector2& pos, const Vector2& vel, float destination) { return time_to_y_direct(pos.y, vel.y, destination); } float predict_x(const Vector2& pos, const Vector2& vel, float time) { // can net collision occur float net = vel.x > 0 ? (NET_POSITION_X - BALL_RADIUS - NET_RADIUS) : (NET_POSITION_X + BALL_RADIUS + NET_RADIUS); float tnet = make_unsigned( time_to_x_direct(pos.x, vel.x, net) ); // calculate estimated hitpos Vector2 nhitpos = Vector2(net, predict_y(pos, vel, tnet)); // can ignore net bounce if ( tnet > time || nhitpos.y < NET_SPHERE_POSITION - NET_RADIUS - BALL_RADIUS) { float spos = pos.x + vel.x*time; if ( spos < BALL_RADIUS) return 2 * BALL_RADIUS - spos; else if ( spos > RIGHT_PLANE - BALL_RADIUS ) return 2*(RIGHT_PLANE - BALL_RADIUS) - spos; return spos; } // collision with net return predict_x(nhitpos, vel.reflectX(), time - tnet); } float predict_y(const Vector2& pos, const Vector2& vel, float time) { return pos.y + (vel.y + BALL_GRAVITATION/2.0 * time) * time; } float y_at_x(const Vector2& pos, const Vector2& vel, float destination) { float time = time_to_x(pos, vel, destination); return predict_y(pos, vel, time); } float x_at_y(const Vector2& pos, const Vector2& vel, float destination) { float time = time_to_y(pos, vel, destination); return predict_x(pos, vel, time); } float next_event(const Vector2& pos, const Vector2& vel) { // walls and net float time_wall; float time_net; if( vel.x > 0 ) { time_wall = time_to_x_direct(pos.x, vel.x, RIGHT_PLANE - BALL_RADIUS); time_net = time_to_x_direct(pos.x, vel.x, NET_POSITION_X - NET_RADIUS - BALL_RADIUS); } else { time_wall = time_to_x_direct(pos.x, vel.x, LEFT_PLANE + BALL_RADIUS); time_net = time_to_x_direct(pos.x, vel.x, NET_POSITION_X + NET_RADIUS + BALL_RADIUS); } // ground float time_ground = time_to_y_direct(pos.y, vel.y, GROUND_PLANE_HEIGHT_MAX - BALL_RADIUS); time_net = make_unsigned(time_net); time_wall = make_unsigned(time_wall); time_ground = make_unsigned(time_ground); if ( time_net < time_wall && time_net < time_ground ) { FLAG_BOUNCE = true; return time_net; } else if ( time_wall < time_net && time_wall < time_ground ) { FLAG_BOUNCE = true; return time_wall; } else { return time_ground; } } float time_to_x_direct(float pos, float vel, float destination) { return (destination - pos) / vel; } float time_to_y_direct(float pos, float vel, float destination) { return parabel_time_first(pos, vel, BALL_GRAVITATION, destination); } float parabel_time_first(float pos, float vel, float grav, float destination) { float sq = vel*vel + 2*grav*(destination - pos); // if unreachable, return -1 if ( sq < 0 ) { return -1; } sq = std::sqrt(sq); float tmin = (-vel - sq) / grav; float tmax = (-vel + sq) / grav; if ( grav < 0 ) { float temp = tmin; tmin = tmax; tmax = temp; } if ( tmin > 0 ) return tmin; else if ( tmax > 0 ) return tmax; return -1; } blobby-1.0/src/lua/lmathlib.c000644 001750 001750 00000014672 12313310253 020726 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lmathlib.c,v 1.83.1.1 2013/04/12 18:48:47 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ #include #include #define lmathlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" #undef PI #define PI ((lua_Number)(3.1415926535897932384626433832795)) #define RADIANS_PER_DEGREE ((lua_Number)(PI/180.0)) static int math_abs (lua_State *L) { lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); return 1; } static int math_sinh (lua_State *L) { lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); return 1; } static int math_cos (lua_State *L) { lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); return 1; } static int math_cosh (lua_State *L) { lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); return 1; } static int math_tan (lua_State *L) { lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); return 1; } static int math_tanh (lua_State *L) { lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); return 1; } static int math_asin (lua_State *L) { lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); return 1; } static int math_acos (lua_State *L) { lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); return 1; } static int math_atan (lua_State *L) { lua_pushnumber(L, l_mathop(atan)(luaL_checknumber(L, 1))); return 1; } static int math_atan2 (lua_State *L) { lua_pushnumber(L, l_mathop(atan2)(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_ceil (lua_State *L) { lua_pushnumber(L, l_mathop(ceil)(luaL_checknumber(L, 1))); return 1; } static int math_floor (lua_State *L) { lua_pushnumber(L, l_mathop(floor)(luaL_checknumber(L, 1))); return 1; } static int math_fmod (lua_State *L) { lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_modf (lua_State *L) { lua_Number ip; lua_Number fp = l_mathop(modf)(luaL_checknumber(L, 1), &ip); lua_pushnumber(L, ip); lua_pushnumber(L, fp); return 2; } static int math_sqrt (lua_State *L) { lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); return 1; } static int math_pow (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); lua_Number y = luaL_checknumber(L, 2); lua_pushnumber(L, l_mathop(pow)(x, y)); return 1; } static int math_log (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); lua_Number res; if (lua_isnoneornil(L, 2)) res = l_mathop(log)(x); else { lua_Number base = luaL_checknumber(L, 2); if (base == (lua_Number)10.0) res = l_mathop(log10)(x); else res = l_mathop(log)(x)/l_mathop(log)(base); } lua_pushnumber(L, res); return 1; } #if defined(LUA_COMPAT_LOG10) static int math_log10 (lua_State *L) { lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); return 1; } #endif static int math_exp (lua_State *L) { lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); return 1; } static int math_deg (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); return 1; } static int math_rad (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); return 1; } static int math_frexp (lua_State *L) { int e; lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); lua_pushinteger(L, e); return 2; } static int math_ldexp (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); int ep = luaL_checkint(L, 2); lua_pushnumber(L, l_mathop(ldexp)(x, ep)); return 1; } static int math_min (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ lua_Number dmin = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { lua_Number d = luaL_checknumber(L, i); if (d < dmin) dmin = d; } lua_pushnumber(L, dmin); return 1; } static int math_max (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ lua_Number dmax = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { lua_Number d = luaL_checknumber(L, i); if (d > dmax) dmax = d; } lua_pushnumber(L, dmax); return 1; } static int math_random (lua_State *L) { /* the `%' avoids the (rare) case of r==1, and is needed also because on some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; switch (lua_gettop(L)) { /* check number of arguments */ case 0: { /* no arguments */ lua_pushnumber(L, r); /* Number between 0 and 1 */ break; } case 1: { /* only upper limit */ lua_Number u = luaL_checknumber(L, 1); luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty"); lua_pushnumber(L, l_mathop(floor)(r*u) + (lua_Number)(1.0)); /* [1, u] */ break; } case 2: { /* lower and upper limits */ lua_Number l = luaL_checknumber(L, 1); lua_Number u = luaL_checknumber(L, 2); luaL_argcheck(L, l <= u, 2, "interval is empty"); lua_pushnumber(L, l_mathop(floor)(r*(u-l+1)) + l); /* [l, u] */ break; } default: return luaL_error(L, "wrong number of arguments"); } return 1; } static int math_randomseed (lua_State *L) { srand(luaL_checkunsigned(L, 1)); (void)rand(); /* discard first value to avoid undesirable correlations */ return 0; } static const luaL_Reg mathlib[] = { {"abs", math_abs}, {"acos", math_acos}, {"asin", math_asin}, {"atan2", math_atan2}, {"atan", math_atan}, {"ceil", math_ceil}, {"cosh", math_cosh}, {"cos", math_cos}, {"deg", math_deg}, {"exp", math_exp}, {"floor", math_floor}, {"fmod", math_fmod}, {"frexp", math_frexp}, {"ldexp", math_ldexp}, #if defined(LUA_COMPAT_LOG10) {"log10", math_log10}, #endif {"log", math_log}, {"max", math_max}, {"min", math_min}, {"modf", math_modf}, {"pow", math_pow}, {"rad", math_rad}, {"random", math_random}, {"randomseed", math_randomseed}, {"sinh", math_sinh}, {"sin", math_sin}, {"sqrt", math_sqrt}, {"tanh", math_tanh}, {"tan", math_tan}, {NULL, NULL} }; /* ** Open math library */ LUAMOD_API int luaopen_math (lua_State *L) { luaL_newlib(L, mathlib); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); lua_pushnumber(L, HUGE_VAL); lua_setfield(L, -2, "huge"); return 1; } blobby-1.0/data/gfx/blobbym4.bmp000644 001750 001750 00000017242 12313310254 021322 0ustar00danielknobedanielknobe000000 000000 BM6(KYl  ,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,! ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,!! ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"!! ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,""!!! ,,,,,,,,,,,,,,,,,,,,,,,,,,"""!!! ,,,,,,,,,,,,,,,,,,,,,,,$#""!!!! ,,,,,,,,,,,,,,,,,,,,$##"""!!!! ,,,,,,,,,,,,,,,,,&$$##"""!!!! ,,,,,,,,,,,,,,&%$$##""""!!!! ,,,,,,,,,,,,,,%%$$###""""!!!!! ,,,,,,,,,,,,'%%$$$#""!!! ,,,,,,,,,,('%$##"!! ,,,,,,,,)'%$#"!!   ,,,,,,,(%$"!!    ,,,,,,)&$"!   !,,,,,&$"!    !,,,,($#!    !&,,,%#!  !!!&,,,#"! !!!!"&,,,!  !!"""#',,,  !"##'',,, !"#''(,,,!%&'((,,,"#$%'(),,,   !!#$%&(*,,,,   !"#$&(,,,,,   !"#$&(,,,,,, !"#$&,,,,,,,  !"#%',,,,,,,, !!!!!!!!!!!!  !"#$,,,,,,,,,, !!!!!!"""""############"! "&,,,,,,,,,,,, !!!""""####$$$$$%%%%%%%%%$$'&%&,,,,,,,,,,,,, !!!""""###$$$$$%%%%&&&&&&&((('&&,,,,,,,,,,,,,, !!!""""###$$$$%%%%&&&&'''')))((',,,,,,,,,,,,,,,, !!!"""####$$$%%%%&&&&''''))))))),,,,,,,,,,,,,,,,,, !!!""""###$$$%%%&&&&''''())))))),,,,,,,,,,,,,,,,,,,, !!!"""###$$$%%%%&&&''''())))****,,,,,,,,,,,,,,,,,,,,, !!!"""###$$$%%%&&&''''(()))***+++,,,,,,,,,,,,,,,,,,,,, !!!"""###$$$%%%&&&''''((())***+++++,,,,,,,,,,,,,,,,,,,,,, !!"""###$$$%%%&&&'''(((()))*****+++,,,,,,,,,,,,,,,,,,,,,,, !!""###$$%%%&&&'''((((())))))*******+,,,,,,,,,,,,,,,,,,,,,,,, !!"""##$$%%&&&'''((())))))))*)*********,,,,,,,,,,,,,,,,,,,,,,,,, !!""##$$%&&&''((()))))**+**+******))))))),,,,,,,,,,,,,,,,,,,,,,,,, !""#$$%%%&&&&'''((())))**+++****))))))))))),,,,,,,,,,,,,,,,,,,,,,,,, !"#####$$$$$%%%%&&&'''(((())))**)))))))))))))),,,,,,,,,,,,,,,,,,,,,,,,, !""""""""#####$$$$%%%&&&''''(((())))))))))))((((,,,,,,,,,,,,,,,,,,,,,,,,,,"""!!!!!!"""""####$$$%%%%%&&&&'''((())))((((((((,,,,,,,,,,,,,,,,,,,,,,,,,,,"!!! !!!!!!!""""###$$$$$$$%%%%&&&''((((((''''',,,,,,,,,,,,,,,,,,,,,,,,,,,  !!!!"""""""""####$$$%%%&&'''&&&&&%,,,,,,,,,,,,,,,,,,,,,,,,,,,  !!!!!""""###$$%%&%%%%%%,,,,,,,,,,,,,,,,,,,,,,,,,,, !!!""##$%%%%%&,,,,,,,,,,,,,,,,,,,,,,,,,,, !!"##$%%&&&&,,,,,,,,,,,,,,,,,,,,,,,,,,, !!""#$$%&&'',,,,,,,,,,,,,,,,,,,,,,,,,,, !""##$%&''(,,,,,,,,,,,,,,,,,,,,,,,,,,, !!"##$%&'(),,,,,,,,,,,,,,,,,,,,,,,,,,,, !!""#$%&'),,,,,,,,,,,,,,,,,,,,,,,,,,,,, !""#$%&'),,,,,,,,,,,,,,,,,,,,,,,,,,,,, !""#$%&(),,,,,,,,,,,,,,,,,,,,,,,,,,,,,,  !""#$%&(,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,   !""#$%'),,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,  !""#$%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,  !"#$%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,  !!"#%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,  !"#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,  !"#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,!,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,blobby-1.0/src/lua/lstring.c000644 001750 001750 00000011450 12313310253 020603 0ustar00danielknobedanielknobe000000 000000 /* ** $Id: lstring.c,v 2.26.1.1 2013/04/12 18:48:47 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ #include #define lstring_c #define LUA_CORE #include "lua.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" /* ** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to ** compute its hash */ #if !defined(LUAI_HASHLIMIT) #define LUAI_HASHLIMIT 5 #endif /* ** equality for long strings */ int luaS_eqlngstr (TString *a, TString *b) { size_t len = a->tsv.len; lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR); return (a == b) || /* same instance or... */ ((len == b->tsv.len) && /* equal length and ... */ (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ } /* ** equality for strings */ int luaS_eqstr (TString *a, TString *b) { return (a->tsv.tt == b->tsv.tt) && (a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b)); } unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { unsigned int h = seed ^ cast(unsigned int, l); size_t l1; size_t step = (l >> LUAI_HASHLIMIT) + 1; for (l1 = l; l1 >= step; l1 -= step) h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1])); return h; } /* ** resizes the string table */ void luaS_resize (lua_State *L, int newsize) { int i; stringtable *tb = &G(L)->strt; /* cannot resize while GC is traversing strings */ luaC_runtilstate(L, ~bitmask(GCSsweepstring)); if (newsize > tb->size) { luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *); for (i = tb->size; i < newsize; i++) tb->hash[i] = NULL; } /* rehash */ for (i=0; isize; i++) { GCObject *p = tb->hash[i]; tb->hash[i] = NULL; while (p) { /* for each node in the list */ GCObject *next = gch(p)->next; /* save next */ unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */ gch(p)->next = tb->hash[h]; /* chain it */ tb->hash[h] = p; resetoldbit(p); /* see MOVE OLD rule */ p = next; } } if (newsize < tb->size) { /* shrinking slice must be empty */ lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *); } tb->size = newsize; } /* ** creates a new string object */ static TString *createstrobj (lua_State *L, const char *str, size_t l, int tag, unsigned int h, GCObject **list) { TString *ts; size_t totalsize; /* total size of TString object */ totalsize = sizeof(TString) + ((l + 1) * sizeof(char)); ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts; ts->tsv.len = l; ts->tsv.hash = h; ts->tsv.extra = 0; memcpy(ts+1, str, l*sizeof(char)); ((char *)(ts+1))[l] = '\0'; /* ending 0 */ return ts; } /* ** creates a new short string, inserting it into string table */ static TString *newshrstr (lua_State *L, const char *str, size_t l, unsigned int h) { GCObject **list; /* (pointer to) list where it will be inserted */ stringtable *tb = &G(L)->strt; TString *s; if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) luaS_resize(L, tb->size*2); /* too crowded */ list = &tb->hash[lmod(h, tb->size)]; s = createstrobj(L, str, l, LUA_TSHRSTR, h, list); tb->nuse++; return s; } /* ** checks whether short string exists and reuses it or creates a new one */ static TString *internshrstr (lua_State *L, const char *str, size_t l) { GCObject *o; global_State *g = G(L); unsigned int h = luaS_hash(str, l, g->seed); for (o = g->strt.hash[lmod(h, g->strt.size)]; o != NULL; o = gch(o)->next) { TString *ts = rawgco2ts(o); if (h == ts->tsv.hash && l == ts->tsv.len && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */ changewhite(o); /* resurrect it */ return ts; } } return newshrstr(L, str, l, h); /* not found; create a new string */ } /* ** new string (with explicit length) */ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { if (l <= LUAI_MAXSHORTLEN) /* short string? */ return internshrstr(L, str, l); else { if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) luaM_toobig(L); return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL); } } /* ** new zero-terminated string */ TString *luaS_new (lua_State *L, const char *str) { return luaS_newlstr(L, str, strlen(str)); } Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; if (s > MAX_SIZET - sizeof(Udata)) luaM_toobig(L); u = &luaC_newobj(L, LUA_TUSERDATA, sizeof(Udata) + s, NULL, 0)->u; u->uv.len = s; u->uv.metatable = NULL; u->uv.env = e; return u; } blobby-1.0/data/gfx/font18.bmp000644 001750 001750 00000003370 12313310254 020724 0ustar00danielknobedanielknobe000000 000000 BM6( {bneIB(ѲtnC9* f[N"?Bݜ@2T1lV;nO Ɣt/ !H'7\)ĸW <WE Wa4H`bM - g; ml = x?T\rF+$k6xMN %YkYQx7e?FsAb%?5׃lw;Ka%.geމ][v36%/%%՟jI($ yyMDK0`nRҍibG$/7*Ֆߊ~eOoA젘ZK?N;zq!=blobby-1.0/data/gfx/ball06.bmp000644 001750 001750 00000012066 12313310254 020667 0ustar00danielknobedanielknobe000000 000000 BM66(@@ gejMLNwvxqnq}{}igigeg~~}~zvx~ieeebbxvv{zzsrrfeeYWVrqpponbb_yyx $%$npnege{|{yzywxwpqpghg]a^bdc`ba eggz{|ghi WWYeegdde|||xxxuuuooommmjjjhhhgggfffeeedddcccbbb```___]]]ZZZXXXWWWTTTPPPIII===/// 8Ql#Z)Q}#mmmmmmmmmm<)[}})< (((((ZZ)$((}u|'3'>(8))p~~~i3'>(788}umhoI~I3W'((Z}m%ShԐIIohWX>((7)%goi&IIhi|'>Y((ihHhh|>(Z{22{IhIIhi'(ZZ2deiאIIh~Y(ZHdRʏfӑ{{g%&'(ZɏdeԐIi'(KɏɏԐIoi'$7{nɏɏ{ԐI'K2ȍc1ʏɏԐI~'YZ)uKedK1cɏI'dKɏe{I7}"m12cU1VĎɏe{{Ip21ɏ11ʏ{Ґh'[[)Q͏2ʏe{Hh38[lmK nÍ1ȏ{{i>(8[lVq1{i33>$Z)unGGUʏHii3'(P77mj1GbbbbT11ȏϐhhH~3'$7"#1T0zzҐ{{Ӑh'YYX>$(Y>>(8<````zG2f3|(Z}[`r//``zˏɏe{ӑp3 (0F``///`00Rd2ӑi&|>( P㶰__///`zGn1ɏIhi((8ǯ/F//`zG1hho~WY((FFF//F///////`V>8r//EE//Ə{%h~iWY(Z(E/G0gHI...E`zbȏde{~.LLL..-.E/`zbG1Io,,,,,,,.EabVVcRd ,,D,.,,,E/UUg+D-D,,,,.ȏ^Dy+E..*****,,x+D,=,Eza0U1w****w=***C.D,,,EzC,,**.,,EbGVƏD*AB*DD-.GqÂ.,,\AA,*].q*\*@@@AA,,***.,../_*A@@@*D***,D,,.?A?AADD,,*AA]@A,-E*AA@@@DDyLE?*?Aw*@@Ax***,EA@],?vA???AD*AAD*A@A@,,D,LD*,,,AACAAAAAA***AA@??AB******blobby-1.0/data/rules/sticky_mode.lua000644 001750 001750 00000000333 12313310254 022464 0ustar00danielknobedanielknobe000000 000000 __AUTHOR__ = "chameleon" __TITLE__ = "Crazy Volley - Sticky Mode" function HandleInput(player, left, right, up) if isgamerunning() then return left, right, false else return left, right, up end end blobby-1.0/src/GameLogicState.cpp000644 001750 001750 00000004766 12313310253 021544 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= Blobby Volley 2 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de) Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #include "GameLogicState.h" #include #include "GenericIO.h" USER_SERIALIZER_IMPLEMENTATION_HELPER(GameLogicState) { io.uint32(value.leftScore); io.uint32(value.rightScore); io.template generic( value.servingPlayer ); io.uint32(value.leftSquish); io.uint32(value.rightSquish); io.uint32(value.squishWall); io.uint32(value.squishGround); io.boolean(value.isGameRunning); io.boolean(value.isBallValid); } void GameLogicState::swapSides() { std::swap(leftScore, rightScore); std::swap(leftSquish, rightSquish); if(servingPlayer == LEFT_PLAYER) { servingPlayer = RIGHT_PLAYER; } else if(servingPlayer == RIGHT_PLAYER) { servingPlayer = LEFT_PLAYER; } } bool GameLogicState::operator==(const GameLogicState& other) const { return leftScore == other.leftScore && rightScore == other.rightScore && isGameRunning == other.isGameRunning && isBallValid == other.isBallValid && servingPlayer == other.servingPlayer && leftSquish == other.leftSquish && rightSquish == other.rightSquish && squishWall == other.squishWall && squishGround == other.squishGround; } std::ostream& operator<<(std::ostream& stream, const GameLogicState& state) { stream << "GAME LOGIC STATE [ " << state.leftScore << " : " << state.rightScore << " " << state.servingPlayer << " " << state.leftSquish << " " << state.rightSquish << " " << state.squishWall << " " << state.squishGround << " " << state.isGameRunning << " " << state.isBallValid << "]"; return stream; } blobby-1.0/doc/Tutorial_de.txt000644 001750 001750 00000005745 12313310254 021201 0ustar00danielknobedanielknobe000000 000000 In diesem Tutorial werden die Grundlagen von Lua und der Botprogrammierung von Blobby Volley 2 erläutert. Für weiterführende Informationen gibt es die Dokumentation der Script-API. Für Leute, die noch nie programmiert haben, empfehle ich folgendes Tutorial, um die wichtigsten Grundlagen zu erlernen: http://robertico.ro.funpic.de/index.php Vor der Programmierung ist zu beachten, dass Blobby-Skripte in 'data/scripts' abgelegt werden müssen und die Dateiendung '.lua' tragen müssen, um vom Spiel erkannt zu werden Für ein gültiges Blobby-Script müsst ihr 3 Funktionen festlegen: function OnServe(parameter) -- Wird aufgerufen wenn der Ball abgepfiffen wurde und man selber angeben -- soll. Der Parameter gibt an, ob der Ball schon in der Schwebe plaziert ist end function OnOpponentServe() -- Wird aufgerufen wenn der Gegner angeben soll end function OnGame() -- Wird ansonsten während des gesamten Spieles aufgerufen -- Mit -- werden übrigens Kommentare markiert, solltet ihr es noch nicht bemerkt haben ;D end Bevor ihr jetzt loslegt, noch etwas zum Koordinatensystem: Das Spielfeld ist 800 Einheiten breit und 600 Einheiten hoch, ganz an der alten Blobby-Auflösung orientiert. X wächst dabei nach rechts und Y nach oben. Damit wäre also 0,0 unten links und 800,600 oben rechts. Falls ihr euch wundert dass es keine Möglichkeit gibt die eigene Seite zu bestimmen, das ist Absicht. Programmiert einfach als ob der Bot immer links stehen würde, das Programm dreht gegebenenfalls alle Koordinaten um. Ich werde jetzt einfach mal ein Beispiel zeigen, wie ein simpler Bot aufgebaut sein kann: function OnOpponentServe() moveto(130) -- Wenn der Gegner spielt, in Ausgangsposition gehen end function onServer(ballready) moveto(ballx() - 40) -- Etwas links vom Ball hinstellen if posx() < ballx() - 37 and posx() > ballx() - 43 then -- Dieser zugegeben etwas komplizierte Ausdruck bewirkt, dass -- man sich erstmal unterhalb des Balles befinden muss. Leider muss -- das so aufwendig gemacht werden, weil moveto() niemals eine Stelle -- ganz exakt erreicht. if ballready then jump() -- Natürlich nur springen wenn der Ball schon bereitsteht end end end function OnGame() if ballx() < 400 then -- Wenn sich der Ball links von der Mitte, -- also auf unserer Seite befindet moveto(ballx() - 20) -- Etwas links vom Ball ausrichten if ballx() < posx() + 50 then jump() -- Wenn der Ball kurz vor oder hinter dem Blobby ist, springen end end end Ich hoffe, dieses Tutorial hat einen Eindruck entwickelt, wie man einen Bot programmiert. Für weitere Informationen gibt es wie gesagt die Script-API-Doku. Um fortgeschrittene Bots zu programmieren, solltet ihr auch nicht immer blind dem Ball hinterherrennen, sondern mit den estim*-Funktionen Vorhersagen machen. Ansonsten kann ich euch nur als Tip mitgeben, euren Bot immer wieder zu beobachten und gegen jede gefundene Schwäche einen Schutzmechanismus zu entwickeln. blobby-1.0/src/raknet/InternalPacketPool.h000644 001750 001750 00000005355 12313310247 023401 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Internal Packet Pool Class Declaration. * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __INTERNAL_PACKET_POOL #define __INTERNAL_PACKET_POOL #include #include "InternalPacket.h" /** * @brief Manage Internal Packet using pools. * * This class provide memory management for packets used internally in RakNet. * @see PacketPool * * @note Implement Singleton Pattern * */ class InternalPacketPool { public: /** * Constructor */ InternalPacketPool(); /** * Destructor */ ~InternalPacketPool(); /** * Retrieve a new InternalPacket instance. * @return a pointer to an InternalPacket structure. */ InternalPacket* GetPointer( void ); /** * Free am InternalPacket instance * @param p a pointer to the InternalPacket instance. */ void ReleasePointer( InternalPacket *p ); /** * Clear the pool */ void ClearPool( void ); private: /** * InternalPacket pool */ std::stack pool; /** * Multithread access management */ #ifdef _DEBUG /** * Used in debugging stage to monitor the number of internal packet released. */ int packetsReleased; #endif }; #endif blobby-1.0/src/blobnet/adt/Queue.hpp000644 001750 001750 00000011470 12313310251 022166 0ustar00danielknobedanielknobe000000 000000 /*============================================================================= blobNet Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =============================================================================*/ #ifndef _QUEUE_HPP_ #define _QUEUE_HPP_ /* Includes */ #include #include namespace BlobNet { namespace ADT { /*! \class Queue \brief ADT for a Queue with some extra functionality \note This class needs a cleanup. There are some dummy methods */ template class Queue { public: /// @brief constructor, creates an queue Queue(); /// @brief deconstructor, destroys an queue ~Queue(); /// @brief constructor, creates a copy of an queue /// @param originalCopy The queue which will be copied Queue(const Queue& originalCopy); const QueueType& operator[] (unsigned int position) const; QueueType& operator[] (unsigned int position); bool operator= (const Queue& original_copy); /// @brief Count of elements in the queue /// @return Count of elements inline const unsigned int size() const; /// @brief Adds an element to the queue /// @param input Element to add void push(const QueueType& input); /// @brief Adds an element to the head of the queue /// @param input Element to add void pushAtHead(const QueueType& input); /// @brief Pops the first element of queue. Check if queue is not empty before. /// @return First element of queue inline const QueueType pop(); /// @brief Deletes all elements of the array inline void clear(); /// @brief Reorganizes the queue. Really dump implemented at the moment void compress(); /// @brief Checks if element is in queue or not /// @param q Element bool find(QueueType q); /// @brief Returns first element of queue. Really dump implemented at the moment /// @return First element inline const QueueType peek() const; /// @brief Deletes an element. This is not very fast /// @param position Index of element void del(unsigned int position); /// @brief Reallocates the queue with no elements /// @param size Size of internal array size void clearAndForceAllocation(int size); private: typedef std::deque ContainerType; ContainerType array; }; template Queue::Queue() { } template Queue::~Queue() { } template Queue::Queue(const Queue& original_copy) { this->array = original_copy->array; } template inline const QueueType& Queue::operator[] (unsigned int position) const { return this->array.at(position); } template inline QueueType& Queue::operator[] (unsigned int position) { return this->array.at(position); } template bool Queue::operator= (const Queue& original_copy) { return this->array = original_copy->array; } template inline const unsigned int Queue::size() const { return this->array.size(); } template void Queue::push(const QueueType& input) { this->array.push_back(input); } template void Queue::pushAtHead(const QueueType& input) { this->array.push_front(input); } template inline const QueueType Queue::pop() { QueueType tmp = this->array.front(); this->array.pop_front(); return tmp; } template inline void Queue::clear() { this->array.clear(); } template void Queue::compress() { } template bool Queue::find(QueueType q) { typename ContainerType::iterator it; it = std::find(this->array.begin(), this->array.end(), q); return it != this->array.end(); } template inline const QueueType Queue::peek( void ) const { return this->array.front(); } template void Queue::del(unsigned int position) { this->array.erase(this->array.begin() + position); } template void Queue::clearAndForceAllocation(int size) { return this->array.clear(); } } } #endif blobby-1.0/src/raknet/InternalPacketPool.cpp000644 001750 001750 00000005424 12313310247 023731 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Internal Packet Pool Implementation * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "InternalPacketPool.h" #include InternalPacketPool::InternalPacketPool() { #ifdef _DEBUG packetsReleased = 0; #endif for (unsigned i = 0; i < 64; i++) pool.push(new InternalPacket); } InternalPacketPool::~InternalPacketPool() { #ifdef _DEBUG // If this assert hits then not all packets given through GetPointer have been returned to ReleasePointer assert( packetsReleased == 0 ); #endif ClearPool(); } void InternalPacketPool::ClearPool( void ) { while ( !pool.empty() ) { InternalPacket* p = pool.top(); pool.pop(); delete p; } } InternalPacket* InternalPacketPool::GetPointer( void ) { #ifdef _DEBUG packetsReleased++; #endif InternalPacket *p = 0; if ( !pool.empty() ) { p = pool.top(); pool.pop(); } if ( p ) return p; p = new InternalPacket; #ifdef _DEBUG p->data=0; #endif return p; } void InternalPacketPool::ReleasePointer( InternalPacket *p ) { if ( p == 0 ) { // Releasing a null pointer? #ifdef _DEBUG assert( 0 ); #endif return ; } #ifdef _DEBUG packetsReleased--; #endif #ifdef _DEBUG p->data=0; #endif pool.push( p ); } blobby-1.0/src/raknet/RakPeer.h000644 001750 001750 00000056720 12313310247 021176 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief A RakPeer is the lower level Communication End Point. * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __RAK_PEER_H #define __RAK_PEER_H #include "ReliabilityLayer.h" #include "BitStream.h" #include "SingleProducerConsumer.h" #include "PacketPool.h" #ifdef _WIN32 void __stdcall ProcessNetworkPacket( unsigned int binaryAddress, unsigned short port, const char *data, int length, RakPeer *rakPeer ); unsigned __stdcall UpdateNetworkLoop( LPVOID arguments ); #else void ProcessNetworkPacket( unsigned int binaryAddress, unsigned short port, const char *data, int length, RakPeer *rakPeer ); void* UpdateNetworkLoop( void* arguments ); #endif /** * @brief The lowest communication end point in RakNet. * * This class provide the lowest communication end point in RakNet. * It is recommended that you use it if you are going to be at the * same time client and server. */ class RakPeer { public: /** * Constructor */ RakPeer(); /** * Destructor */ virtual ~RakPeer(); /* * -------------------------------------------------------------------------------------------- * Major Low Level Functions - Functions needed by most users * -------------------------------------------------------------------------------------------- */ /** * Starts the network threads, opens the listen port * You must call this before calling SetMaximumIncomingConnections or Connect * Multiple calls while already active are ignored. To call this function again with different settings, you must first call Disconnect() * To accept incoming connections, use SetMaximumIncomingConnections * * Parameters: * @param MaximumNumberOfPeers Required so the network can preallocate and for thread safety. * - A pure client would set this to 1. A pure server would set it to the number of allowed clients. * - A hybrid would set it to the sum of both types of connections * @param localPort The port to listen for connections on. * @param _threadSleepTimer >=0 for how many ms to Sleep each internal update cycle (recommended 30 for low performance, 0 for regular) * @param forceHostAddress Can force RakNet to use a particular IP to host on. Pass 0 to automatically pick an IP * * @return False on failure (can't create socket or thread), true on success. */ bool Initialize( unsigned short MaximumNumberOfPeers, unsigned short localPort, int _threadSleepTimer, const char *forceHostAddress=0 ); /** * Sets how many incoming connections are allowed. If this is less than the number of players currently connected, no * more players will be allowed to connect. If this is greater than the maximum number of peers allowed, it will be reduced * to the maximum number of peers allowed. Defaults to 0. * * @param numberAllowed Maximum number of incoming connections allowed. */ void SetMaximumIncomingConnections( unsigned short numberAllowed ); /** * Get the number of maximum incoming connection. * @return the maximum number of incoming connections, which is always <= MaximumNumberOfPeers */ unsigned short GetMaximumIncomingConnections( void ) const; /** * Call this to connect to the specified host (ip or domain name) and server port. * Calling Connect and not calling SetMaximumIncomingConnections acts as a dedicated client. Calling both acts as a true peer. * This is a non-blocking connection. You know the connection is successful when IsConnected() returns true * or receive gets a packet with the type identifier ID_CONNECTION_ACCEPTED. If the connection is not * successful, such as rejected connection or no response then neither of these things will happen. * Requires that you first call Initialize * * @param host Either a dotted IP address or a domain name * @param remotePort Which port to connect to on the remote machine. * * @return True on successful initiation. False on incorrect parameters, internal error, or too many existing peers */ bool Connect( const char* host, unsigned short remotePort ); /** * Stops the network threads and close all connections. Multiple calls are ok. * * * @param blockDuration How long you should wait for all remaining packets to go out, per connected system * If you set it to 0 then the disconnection notification probably won't arrive */ virtual void Disconnect( unsigned int blockDuration ); /** * Returns true if the network threads are running */ bool IsActive( void ) const; /** * Fills the array remoteSystems with the playerID of all the systems we are connected to * * @param[out] remoteSystems An array of PlayerID structures to be filled with the PlayerIDs of the systems we are connected to * - pass 0 to remoteSystems to only get the number of systems we are connected to * @param numberOfSystems As input, the size of remoteSystems array. As output, the number of elements put into the array */ bool GetConnectionList( PlayerID *remoteSystems, unsigned short *numberOfSystems ) const; /** * Sends a block of data to the specified system that you are connected to. * This function only works while the client is connected (Use the Connect function). * * @param data The block of data to send * @param length The size in bytes of the data to send * @param priority What priority level to send on. * @param reliability How reliability to send this data * @param orderingChannel When using ordered or sequenced packets, what channel to order these on. * - Packets are only ordered relative to other packets on the same stream * @param playerId Who to send this packet to, or in the case of broadcasting who not to send it to. Use UNASSIGNED_PLAYER_ID to specify none * @param broadcast True to send this packet to all connected systems. If true, then playerId specifies who not to send the packet to. * @return * False if we are not connected to the specified recipient. True otherwise */ bool Send( const char *data, const long length, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId, bool broadcast ); /** * Sends a block of data to the specified system that you are connected to. * This function only works while the client is connected (Use the Connect function). * * @param bitStream The bitstream to send * @param priority What priority level to send on. * @param reliability How reliability to send this data * @param orderingChannel When using ordered or sequenced packets, what channel to order these on. * - Packets are only ordered relative to other packets on the same stream * @param playerId Who to send this packet to, or in the case of broadcasting who not to send it to. Use UNASSIGNED_PLAYER_ID to specify none * @param broadcast True to send this packet to all connected systems. If true, then playerId specifies who not to send the packet to. * @return * False if we are not connected to the specified recipient. True otherwise */ bool Send( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId, bool broadcast ); /** * Gets a packet from the incoming packet queue. Use DeallocatePacket to deallocate the packet after you are done with it. * Check the Packet struct at the top of CoreNetworkStructures.h for the format of the struct * * @return * 0 if no packets are waiting to be handled, otherwise an allocated packet * If the client is not active this will also return 0, as all waiting packets are flushed when the client is Disconnected * This also updates all memory blocks associated with synchronized memory and distributed objects */ packet_ptr Receive( void ); /** * Return the total number of connections we are allowed */ unsigned short GetMaximumNumberOfPeers( void ) const; /* * -------------------------------------------------------------------------------------------- * Player Management Functions * -------------------------------------------------------------------------------------------- */ /** * Close the connection to another host (if we initiated the connection it will disconnect, if they did it will kick them out). * * @param target Which connection to close * @param sendDisconnectionNotification True to send ID_DISCONNECTION_NOTIFICATION to the recipient. False to close it silently. */ void CloseConnection( PlayerID target, bool sendDisconnectionNotification ); /** * Given a playerID, returns an index from 0 to the maximum number of players allowed - 1. * * @param playerId The playerID to search for * * @return An integer from 0 to the maximum number of peers -1, or -1 if that player is not found */ int GetIndexFromPlayerID( PlayerID playerId ); /** * This function is only useful for looping through all players. * * @param index an integer between 0 and the maximum number of players allowed - 1. * * @return A valid playerID or UNASSIGNED_PLAYER_ID if no such player at that index */ PlayerID GetPlayerIDFromIndex( int index ); /* * -------------------------------------------------------------------------------------------- * Pinging Functions - Functions dealing with the automatic ping mechanism * -------------------------------------------------------------------------------------------- */ /** * Send a ping to the specified connected system. * * Requires: * The sender and recipient must already be started via a successful call to Initialize * * @param target who to ping */ void Ping( PlayerID target ); /** * Send a ping to the specified unconnected system. * The remote system, if it is Initialized, will respond with ID_PONG. * The final ping time will be encoded in the following 4 bytes (2-5) as an unsigned int * * Requires: * The sender and recipient must already be started via a successful call to Initialize * * * @param host Either a dotted IP address or a domain name. Can be 255.255.255.255 for LAN broadcast. * @param remotePort Which port to connect to on the remote machine. * @param onlyReplyOnAcceptingConnections Only request a reply if the remote system is accepting connections */ void Ping( const char* host, unsigned short remotePort, bool onlyReplyOnAcceptingConnections ); /** * Gets the last ping time read for the specific player or -1 if none read yet * * @param target whose time to read * @return Just the last ping */ int GetLastPing( PlayerID playerId ) const; /** * Gets the lowest ping time read or -1 if none read yet * * @param target whose time to read * @return the lowest ping time */ int GetLowestPing( PlayerID playerId ) const; /* * -------------------------------------------------------------------------------------------- * Network Functions - Functions dealing with the network in general * -------------------------------------------------------------------------------------------- */ /** * Return the unique address identifier that represents you on the the network and is based on your local IP / port * Note that unlike in previous versions, this is a struct and is not sequential */ PlayerID GetInternalID( void ) const; /** * Return the unique address identifier that represents you on the the network and is based on your external * IP / port (the IP / port the specified player uses to communicate with you) * @note that unlike in previous versions, this is a struct and is not sequential * * @param target Which remote system you are referring to for your external ID */ PlayerID GetExternalID( PlayerID target ) const; /** * Change the MTU size in order to improve performance when sending large packets * This can only be called when not connected. * A too high of value will cause packets not to arrive at worst and be fragmented at best. * A too low of value will split packets unnecessarily. * * Parameters: * @param size: Set according to the following table: * - 1500. The largest Ethernet packet size; it is also the default value. * This is the typical setting for non-PPPoE, non-VPN connections. The default value for NETGEAR routers, adapters and switches. * - 1492. The size PPPoE prefers. * - 1472. Maximum size to use for pinging. (Bigger packets are fragmented.) * - 1468. The size DHCP prefers. * - 1460. Usable by AOL if you don't have large email attachments, etc. * - 1430. The size VPN and PPTP prefer. * - 1400. Maximum size for AOL DSL. * - 576. Typical value to connect to dial-up ISPs. (Default) * * @return False on failure (we are connected). True on success. Maximum allowed size is MAXIMUM_MTU_SIZE */ bool SetMTUSize( int size ); /** * Returns the current MTU size * * @return The MTU sized specified in SetMTUSize */ int GetMTUSize( void ) const; /** * Returns the number of IP addresses we have */ unsigned GetNumberOfAddresses( void ); /** * Returns the dotted IP address for the specified playerId * * @param playerId Any player ID other than UNASSIGNED_PLAYER_ID, even if that player is not currently connected */ const char* PlayerIDToDottedIP( PlayerID playerId ) const; /** * Converts a dotted IP to a playerId * * @param[in] host Either a dotted IP address or a domain name * @param[in] remotePort Which port to connect to on the remote machine. * @param[out] playerId The result of this operation */ void IPToPlayerID( const char* host, unsigned short remotePort, PlayerID *playerId ); /** * Returns an IP address at index 0 to GetNumberOfAddresses-1 */ const char* GetLocalIP( unsigned int index ); /** * Allow or disallow connection responses from any IP. Normally this should be false, but may be necessary * when connection to servers with multiple IP addresses. * * @param allow - True to allow this behavior, false to not allow. Defaults to false. Value persists between connections */ void AllowConnectionResponseIPMigration( bool allow ); /** * Sends a one byte message ID_ADVERTISE_SYSTEM to the remote unconnected system. * This will tell the remote system our external IP outside the LAN, and can be used for NAT punch through * * Requires: * The sender and recipient must already be started via a successful call to Initialize * * @param host Either a dotted IP address or a domain name * @param remotePort Which port to connect to on the remote machine. * @param data Optional data to append to the packet. * @param dataLength length of data in bytes. Use 0 if no data. */ void AdvertiseSystem( char *host, unsigned short remotePort, const char *data, int dataLength ); /* * -------------------------------------------------------------------------------------------- * Micellaneous Functions * -------------------------------------------------------------------------------------------- */ /** * Put a packet back at the end of the receive queue in case you don't want to deal with it immediately * * @param packet The packet you want to push back. */ void PushBackPacket( Packet *packet ); /* * -------------------------------------------------------------------------------------------- * Statistical Functions - Functions dealing with API performance * -------------------------------------------------------------------------------------------- */ /** * Returns a structure containing a large set of network statistics for the specified system * You can map this data to a string using the C style StatisticsToString function * * @param playerId Which connected system to get statistics for * * @return 0 on can't find the specified system. A pointer to a set of data otherwise. */ RakNetStatisticsStruct * const GetStatistics( PlayerID playerId ); /** * @brief Store Remote System Description. * * RakPeer need to maintain a set of information concerning all remote peer * This is the goal of this structure. */ struct RemoteSystemStruct { PlayerID playerId; /**< The remote system associated with this reliability layer*/ PlayerID myExternalPlayerId; /**< Your own IP, as reported by the remote system*/ ReliabilityLayer reliabilityLayer; /**< The reliability layer associated with this player*/ bool weInitiatedTheConnection; /**< True if we started this connection via Connect. False if someone else connected to us.*/ short pingTime; /**< last ping time */ int lowestPing; /** incomingPacketQueue; // BitStream enumerationData; struct RequestedConnectionStruct { PlayerID playerId; unsigned int nextRequestTime; unsigned char requestsMade; char *data; unsigned short dataLength; enum {CONNECT=1, PING=2, PING_OPEN_CONNECTIONS=4, ADVERTISE_SYSTEM=8} actionToTake; }; BasicDataStructures::SingleProducerConsumer requestedConnectionList; bool RunUpdateCycle( void ); // void RunMutexedUpdateCycle(void); struct BufferedCommandStruct { char *data; int numberOfBitsToSend; PacketPriority priority; PacketReliability reliability; char orderingChannel; PlayerID playerId; bool broadcast; RemoteSystemStruct::ConnectMode connectionMode; enum {BCS_SEND, BCS_CLOSE_CONNECTION, BCS_DO_NOTHING} command; }; // Single producer single consumer queue using a linked list BasicDataStructures::SingleProducerConsumer bufferedCommands; bool AllowIncomingConnections(void) const; void PingInternal( PlayerID target, bool performImmediate ); bool ValidSendTarget(PlayerID playerId, bool broadcast); // This stores the user send calls to be handled by the update thread. This way we don't have thread contention over playerIDs void CloseConnectionInternalBuffered( PlayerID target, bool sendDisconnectionNotification ); void CloseConnectionInternalImmediate( PlayerID target ); void SendBuffered( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId, bool broadcast, RemoteSystemStruct::ConnectMode connectionMode ); bool SendImmediate( char *data, int numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId, bool broadcast, bool useCallerDataAllocation, unsigned int currentTime ); void ClearBufferedCommands(void); void ClearRequestedConnectionList(void); int MTUSize; int threadSleepTimer; SOCKET connectionSocket; /** * How long it has been since things were updated by a call to receive * Update thread uses this to determine how long to sleep for */ unsigned int lastUserUpdateCycle; /* * True to allow connection accepted packets from anyone. False to only allow these packets from servers * we requested a connection to. */ bool allowConnectionResponseIPMigration; PacketPool packetPool; }; #endif blobby-1.0/src/raknet/RakNetStatistics.cpp000644 001750 001750 00000017602 12313310247 023433 0ustar00danielknobedanielknobe000000 000000 /* -*- mode: c++; c-file-style: raknet; tab-always-indent: nil; -*- */ /** * @file * @brief Statistical Information Formatting Implementation * * Copyright (c) 2003, Rakkarsoft LLC and Kevin Jenkins * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "RakNetStatistics.h" #include // sprintf #include "BitStream.h" // BITS_TO_BYTES // Verbosity level currently supports 0 (low), 1 (medium), 2 (high) // Buffer must be hold enough to hold the output string. See the source to get an idea of how many bytes will be output void StatisticsToString( RakNetStatisticsStruct *s, char *buffer, int verbosityLevel ) { if ( s == 0 ) { sprintf( buffer, "stats is a NULL pointer in statsToString\n" ); return ; } if ( verbosityLevel == 0 ) { // Verbosity level 0 sprintf( buffer, "Total bytes sent: %u\n" "Total bytes received: %u\n" "Packetloss: %.1f%%\n", BITS_TO_BYTES( s->totalBitsSent ), BITS_TO_BYTES( s->bitsReceived + s->bitsWithBadCRCReceived ), 100.0f * ( float ) s->messagesTotalBitsResent / ( float ) s->totalBitsSent ); } else if ( verbosityLevel == 1 ) { // Verbosity level 1 sprintf( buffer, "Messages in Send buffer: %u\n" "Messages sent: %u\n" "Bytes sent: %u\n" "Acks sent: %u\n" "Acks in send buffer: %u\n" "Messages waiting for ack: %u\n" "Messages resent: %u\n" "Bytes resent: %u\n" "Packetloss: %.1f%%\n" "Messages received: %u\n" "Bytes received: %u\n" "Acks received: %u\n" "Duplicate acks received: %u\n" "Window size: %u\n", s->messageSendBuffer[ SYSTEM_PRIORITY ] + s->messageSendBuffer[ HIGH_PRIORITY ] + s->messageSendBuffer[ MEDIUM_PRIORITY ] + s->messageSendBuffer[ LOW_PRIORITY ], s->messagesSent[ SYSTEM_PRIORITY ] + s->messagesSent[ HIGH_PRIORITY ] + s->messagesSent[ MEDIUM_PRIORITY ] + s->messagesSent[ LOW_PRIORITY ], BITS_TO_BYTES( s->totalBitsSent ), s->acknowlegementsSent, s->acknowlegementsPending, s->messagesOnResendQueue, s->messageResends, BITS_TO_BYTES( s->messagesTotalBitsResent ), 100.0f * ( float ) s->messagesTotalBitsResent / ( float ) s->totalBitsSent, s->duplicateMessagesReceived + s->invalidMessagesReceived + s->messagesReceived, BITS_TO_BYTES( s->bitsReceived + s->bitsWithBadCRCReceived ), s->acknowlegementsReceived, s->duplicateAcknowlegementsReceived, s->windowSize ); } else { // Verbosity level 2. sprintf( buffer, "Bytes sent:\t\t\t\t%u\n" "Messages in send buffer:\t\tSP:%u HP:%u MP:%u LP:%u\n" "Messages sent:\t\t\t\tSP:%u HP:%u MP:%u LP:%u\n" "Message data bytes sent:\t\tSP:%u HP:%u MP:%u LP:%u\n" "Message header bytes sent:\t\tSP:%u HP:%u MP:%u LP:%u\n" "Message total bytes sent:\t\tSP:%u HP:%u MP:%u LP:%u\n" "Bytes received:\t\t\t\tTtl:%u Good:%u Bad:%u\n" "Packets received:\t\t\tTtl:%u Good:%u Bad:%u\n" "Acks received:\t\t\t\tTtl:%u Good:%u Dup:%u\n" "Messages received:\t\t\tTotal:%u Valid:%u Invalid:%u Dup:%u\n" "Packetloss:\t\t\t\t%.1f%%\n" "Packets sent:\t\t\t\t%u\n" "Acks sent:\t\t\t\t%u\n" "Acks in send buffer:\t\t\t%u\n" "Messages waiting for ack:\t\t%u\n" "Ack bytes sent:\t\t\t\t%u\n" "Sent packets containing only acks:\t%u\n" "Sent packets w/only acks and resends:\t%u\n" "Reliable messages resent:\t\t%u\n" "Reliable message data bytes resent:\t%u\n" "Reliable message header bytes resent:\t%u\n" "Reliable message total bytes resent:\t%u\n" "Number of messages split:\t\t%u\n" "Number of messages unsplit:\t\t%u\n" "Message splits performed:\t\t%u\n" "Sequenced messages out of order:\t%u\n" "Sequenced messages in order:\t\t%u\n" "Ordered messages out of order:\t\t%u\n" "Ordered messages in of order:\t\t%u\n" "Split messages waiting for reassembly:\t%u\n" "Messages in internal output queue:\t%u\n" "Window size:\t\t\t\t%u\n" "Lossy window size\t\t\t%u\n" "Connection start time:\t\t\t%u\n", BITS_TO_BYTES( s->totalBitsSent ), s->messageSendBuffer[ SYSTEM_PRIORITY ], s->messageSendBuffer[ HIGH_PRIORITY ], s->messageSendBuffer[ MEDIUM_PRIORITY ], s->messageSendBuffer[ LOW_PRIORITY ], s->messagesSent[ SYSTEM_PRIORITY ], s->messagesSent[ HIGH_PRIORITY ], s->messagesSent[ MEDIUM_PRIORITY ], s->messagesSent[ LOW_PRIORITY ], BITS_TO_BYTES( s->messageDataBitsSent[ SYSTEM_PRIORITY ] ), BITS_TO_BYTES( s->messageDataBitsSent[ HIGH_PRIORITY ] ), BITS_TO_BYTES( s->messageDataBitsSent[ MEDIUM_PRIORITY ] ), BITS_TO_BYTES( s->messageDataBitsSent[ LOW_PRIORITY ] ), BITS_TO_BYTES( s->messageTotalBitsSent[ SYSTEM_PRIORITY ] - s->messageDataBitsSent[ SYSTEM_PRIORITY ] ), BITS_TO_BYTES( s->messageTotalBitsSent[ HIGH_PRIORITY ] - s->messageDataBitsSent[ HIGH_PRIORITY ] ), BITS_TO_BYTES( s->messageTotalBitsSent[ MEDIUM_PRIORITY ] - s->messageDataBitsSent[ MEDIUM_PRIORITY ] ), BITS_TO_BYTES( s->messageTotalBitsSent[ LOW_PRIORITY ] - s->messageDataBitsSent[ LOW_PRIORITY ] ), BITS_TO_BYTES( s->messageTotalBitsSent[ SYSTEM_PRIORITY ] ), BITS_TO_BYTES( s->messageTotalBitsSent[ HIGH_PRIORITY ] ), BITS_TO_BYTES( s->messageTotalBitsSent[ MEDIUM_PRIORITY ] ), BITS_TO_BYTES( s->messageTotalBitsSent[ LOW_PRIORITY ] ), BITS_TO_BYTES( s->bitsReceived + s->bitsWithBadCRCReceived ), BITS_TO_BYTES( s->bitsReceived ), BITS_TO_BYTES( s->bitsWithBadCRCReceived ), s->packetsReceived + s->packetsWithBadCRCReceived, s->packetsReceived, s->packetsWithBadCRCReceived, s->acknowlegementsReceived + s->duplicateAcknowlegementsReceived, s->acknowlegementsReceived, s->duplicateAcknowlegementsReceived, s->messagesReceived + s->invalidMessagesReceived + s->duplicateMessagesReceived, s->messagesReceived, s->invalidMessagesReceived, s->duplicateMessagesReceived, 100.0f * ( float ) s->messagesTotalBitsResent / ( float ) s->totalBitsSent, s->packetsSent, s->acknowlegementsSent, s->acknowlegementsPending, s->messagesOnResendQueue, BITS_TO_BYTES( s->acknowlegementBitsSent ), s->packetsContainingOnlyAcknowlegements, s->packetsContainingOnlyAcknowlegementsAndResends, s->messageResends, BITS_TO_BYTES( s->messageDataBitsResent ), BITS_TO_BYTES( s->messagesTotalBitsResent - s->messageDataBitsResent ), BITS_TO_BYTES( s->messagesTotalBitsResent ), s->numberOfSplitMessages, s->numberOfUnsplitMessages, s->totalSplits, s->sequencedMessagesOutOfOrder, s->sequencedMessagesInOrder, s->orderedMessagesOutOfOrder, s->orderedMessagesInOrder, s->messagesWaitingForReassembly, s->internalOutputQueueSize, s->windowSize, s->lossySize, s->connectionStartTime ); } } blobby-1.0/data/scripts/old/com_10B2ex.lua000644 001750 001750 00000011367 12313310254 023075 0ustar00danielknobedanielknobe000000 000000 -- Com 1.0 extrem Beta 2 Schmetter-Mod -- by Oreon, Axji & Enormator -- Name: com_10eB2_Schmettermod -- Flags und runners wait = 0 naechsterBallSchmettern = true -- evtl Variablennamen wechseln -- Weltkonstanten CONST_FELD_LAENGE = 800 CONST_BALL_RADIUS = 31.5 CONST_GROUND_PLANE = 100 CONST_BALL_GRAVITY = 0.28 CONST_MITTE = CONST_FELD_LAENGE/2 CONST_RECHTER_RAND = CONST_FELD_LAENGE - CONST_BALL_RADIUS CONST_BLOBBY_HOEHE = 89 CONST_BLOBBY_KOPF_RADIUS = 25 CONST_BLOBBY_BAUCH_RADIUS = 33 CONST_BLOBBY_KOPF_BERUEHRUNG = CONST_GROUND_PLANE + CONST_BLOBBY_HOEHE + CONST_BALL_RADIUS CONST_BLOBBY_MAXJUMP = 393.625 CONST_NETZ_RADIUS = 7 CONST_NETZ_HOEHE = 323 -- Ber�hrungsebene des Balls falls er ans Netz kommt CONST_NETZ_LINKS = CONST_MITTE - CONST_NETZ_RADIUS - CONST_BALL_RADIUS CONST_NETZ_RECHTS = CONST_MITTE + CONST_NETZ_RADIUS + CONST_BALL_RADIUS -- Charakter CONST_ANGRIFFSGRUNDWERT_MIN = 30 CONST_ANGRIFFSGRUNDWERT_MAX = 55 MIN_ANGRIFFSSTAERKE = CONST_ANGRIFFSGRUNDWERT_MIN MAX_ANGRIFFSSTAERKE = CONST_ANGRIFFSGRUNDWERT_MAX ANGRIFFSEINSCHRAENKUNG_HINTEN = 10 -- sonstige Einstellungen servexVersetzung=-7 --Wert ist so gewaehlt, dass der Ball nah ans Netz fliegt, der Gegner ihn aber grade nicht erreichen kann -- ***ANFANG*** function OnOpponentServe() moveto(130) end function OnServe(ballready) servex=ballx()+servexVersetzung naechsterBallSchmettern = true generatenaechsterBallSchmettern() moveto(servex) if ballready and (servex-2 < posx()) and (posx() < servex+2) then jump() end end function OnGame() target = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_KOPF_BERUEHRUNG,1) --X Ziel in Blobbyhoehe targets = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_KOPF_BERUEHRUNG,2) --X Richtung (-1 oder 1) bei Einschlag targetNetz = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_NETZ_HOEHE,1) --X Ziel in Netzhoehe (Netzrollerberechnung) targetJump = estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_MAXJUMP,1) --X Ziel in Schmetterhoehe naechsterBallSchmetternFlagTesten() -- schaut ob der bot angreifen soll oder nicht if (ballx() > CONST_NETZ_RECHTS) then --Wenn Ball auf rechter Spielfeldseite dann generatenaechsterBallSchmettern() --Angriffsstaerke neu berechnen end if (target > CONST_MITTE) and (ballx() > CONST_NETZ_RECHTS) then --Wenn der Ball mich nix angeht moveto(135) --Dann auf Standartposition warten else if (targetNetz > CONST_NETZ_LINKS - 10) then --Bei Netzroller einfach schmettern naechsterBallSchmettern = true end if naechsterBallSchmettern then if ((math.abs(bspeedx()) < 4) or (estimImpact(ballx(),bally(),bspeedx(),bspeedy(),CONST_BLOBBY_MAXJUMP,2) < 0)) then sprungattacke(angriffsstaerke) else if (targetJump < CONST_MITTE / 2) then sprungattacke(-35) --an Rueckwand spielen else sprungattacke(0) --weiterleiten end end return end moveto(target) end end function sprungattacke(p_angriffsstaerke) p_angriffsstaerke=math.max(p_angriffsstaerke, MIN_ANGRIFFSSTAERKE + ANGRIFFSEINSCHRAENKUNG_HINTEN * (targetJump / CONST_NETZ_LINKS)) --Weiter hinten nicht ganz so hoch spielen (kommt nicht auf die andere Seite) p_angriffsstaerke=math.min(p_angriffsstaerke, MAX_ANGRIFFSSTAERKE - ANGRIFFSEINSCHRAENKUNG_HINTEN * (targetJump / CONST_NETZ_LINKS)) --Weiter hinten nicht ganz so tief spielen (kommt ans Netz) moveto(targetJump-p_angriffsstaerke) -- Bei der Sprungatacke wird die St�rke des gew�nschten schlages angegeben if (bally() < 580) and (bspeedy() < 0) then jump() end end function naechsterBallSchmetternFlagTesten() naechsterBallSchmettern = true end function generatenaechsterBallSchmettern() angriffsstaerke = math.random(MIN_ANGRIFFSSTAERKE,MAX_ANGRIFFSSTAERKE) end function estimImpact(bx,by,vbx,vby,destY,Frage) -- erlaubt ein besseres Estimate mit ein paar unbeding n�tigen Angaben bgrav = 0.28 time1 =(-vby-math.sqrt((vby^2)-(-2*bgrav*(by-destY))))/(-bgrav) resultX = (vbx * time1) + bx estimbspeedx=bspeedx()/math.abs(bspeedx()) if(resultX > CONST_RECHTER_RAND) then -- Korrigieren der Appraller an der Rechten Ebene resultX = 2 * CONST_FELD_LAENGE - resultX estimbspeedx=-estimbspeedx end if(resultX < CONST_BALL_RADIUS) then -- korrigieren der Appraller an der linken Ebene resultX = math.abs(resultX - CONST_BALL_RADIUS) + CONST_BALL_RADIUS estimbspeedx=-estimbspeedx KollisionLinks = true else KollisionLinks = false end if (resultX > CONST_NETZ_RECHTS) and (estimbspeedx > 0) and ((KollisionLinks == true) or (ballx() < CONST_NETZ_LINKS)) then -- Abpraller am Netz unterhalb der Kugel erst wenn Netzroller ausgeschlossen sind resultX = 2 * CONST_NETZ_LINKS - resultX estimbspeedx=-estimbspeedx end if (Frage == 1) then return resultX end if (Frage == 2) then return estimbspeedx end endblobby-1.0/src/tinyxml/tinyxml.h000644 001750 001750 00000176502 12313310251 021565 0ustar00danielknobedanielknobe000000 000000 /* www.sourceforge.net/projects/tinyxml Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef TINYXML_INCLUDED #define TINYXML_INCLUDED #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4530 ) #pragma warning( disable : 4786 ) #endif #include #include #include #include #include // Help out windows: #if defined( _DEBUG ) && !defined( DEBUG ) #define DEBUG #endif #ifdef TIXML_USE_STL #include #include #include #define TIXML_STRING std::string #else #include "tinystr.h" #define TIXML_STRING TiXmlString #endif // Deprecated library function hell. Compilers want to use the // new safe versions. This probably doesn't fully address the problem, // but it gets closer. There are too many compilers for me to fully // test. If you get compilation troubles, undefine TIXML_SAFE #define TIXML_SAFE #ifdef TIXML_SAFE #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) // Microsoft visual studio, version 2005 and higher. #define TIXML_SNPRINTF _snprintf_s #define TIXML_SSCANF sscanf_s #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) // Microsoft visual studio, version 6 and higher. //#pragma message( "Using _sn* functions." ) #define TIXML_SNPRINTF _snprintf #define TIXML_SSCANF sscanf #elif defined(__GNUC__) && (__GNUC__ >= 3 ) // GCC version 3 and higher.s //#warning( "Using sn* functions." ) #define TIXML_SNPRINTF snprintf #define TIXML_SSCANF sscanf #else #define TIXML_SNPRINTF snprintf #define TIXML_SSCANF sscanf #endif #endif class TiXmlDocument; class TiXmlElement; class TiXmlComment; class TiXmlUnknown; class TiXmlAttribute; class TiXmlText; class TiXmlDeclaration; class TiXmlParsingData; const int TIXML_MAJOR_VERSION = 2; const int TIXML_MINOR_VERSION = 6; const int TIXML_PATCH_VERSION = 2; /* Internal structure for tracking location of items in the XML file. */ struct TiXmlCursor { TiXmlCursor() { Clear(); } void Clear() { row = col = -1; } int row; // 0 based. int col; // 0 based. }; /** Implements the interface to the "Visitor pattern" (see the Accept() method.) If you call the Accept() method, it requires being passed a TiXmlVisitor class to handle callbacks. For nodes that contain other nodes (Document, Element) you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves are simply called with Visit(). If you return 'true' from a Visit method, recursive parsing will continue. If you return false, no children of this node or its sibilings will be Visited. All flavors of Visit methods have a default implementation that returns 'true' (continue visiting). You need to only override methods that are interesting to you. Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. You should never change the document from a callback. @sa TiXmlNode::Accept() */ class TiXmlVisitor { public: virtual ~TiXmlVisitor() {} /// Visit a document. virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } /// Visit a document. virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } /// Visit an element. virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } /// Visit an element. virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } /// Visit a declaration virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } /// Visit a text node virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } /// Visit a comment node virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } /// Visit an unknown node virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } }; // Only used by Attribute::Query functions enum { TIXML_SUCCESS, TIXML_NO_ATTRIBUTE, TIXML_WRONG_TYPE }; // Used by the parsing routines. enum TiXmlEncoding { TIXML_ENCODING_UNKNOWN, TIXML_ENCODING_UTF8, TIXML_ENCODING_LEGACY }; const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; /** TiXmlBase is a base class for every class in TinyXml. It does little except to establish that TinyXml classes can be printed and provide some utility functions. In XML, the document and elements can contain other elements and other types of nodes. @verbatim A Document can contain: Element (container or leaf) Comment (leaf) Unknown (leaf) Declaration( leaf ) An Element can contain: Element (container or leaf) Text (leaf) Attributes (not on tree) Comment (leaf) Unknown (leaf) A Decleration contains: Attributes (not on tree) @endverbatim */ class TiXmlBase { friend class TiXmlNode; friend class TiXmlElement; friend class TiXmlDocument; public: TiXmlBase() : userData(0) {} virtual ~TiXmlBase() {} /** All TinyXml classes can print themselves to a filestream or the string class (TiXmlString in non-STL mode, std::string in STL mode.) Either or both cfile and str can be null. This is a formatted print, and will insert tabs and newlines. (For an unformatted stream, use the << operator.) */ virtual void Print( FILE* cfile, int depth ) const = 0; /** The world does not agree on whether white space should be kept or not. In order to make everyone happy, these global, static functions are provided to set whether or not TinyXml will condense all white space into a single space or not. The default is to condense. Note changing this value is not thread safe. */ static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } /// Return the current white space setting. static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } /** Return the position, in the original source file, of this node or attribute. The row and column are 1-based. (That is the first row and first column is 1,1). If the returns values are 0 or less, then the parser does not have a row and column value. Generally, the row and column value will be set when the TiXmlDocument::Load(), TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set when the DOM was created from operator>>. The values reflect the initial load. Once the DOM is modified programmatically (by adding or changing nodes and attributes) the new values will NOT update to reflect changes in the document. There is a minor performance cost to computing the row and column. Computation can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. @sa TiXmlDocument::SetTabSize() */ int Row() const { return location.row + 1; } int Column() const { return location.col + 1; } ///< See Row() void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. // Table that returs, for a given lead byte, the total number of bytes // in the UTF-8 sequence. static const int utf8ByteTable[256]; virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, or they will be transformed into entities! */ static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); enum { TIXML_NO_ERROR = 0, TIXML_ERROR, TIXML_ERROR_OPENING_FILE, TIXML_ERROR_PARSING_ELEMENT, TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, TIXML_ERROR_READING_ELEMENT_VALUE, TIXML_ERROR_READING_ATTRIBUTES, TIXML_ERROR_PARSING_EMPTY, TIXML_ERROR_READING_END_TAG, TIXML_ERROR_PARSING_UNKNOWN, TIXML_ERROR_PARSING_COMMENT, TIXML_ERROR_PARSING_DECLARATION, TIXML_ERROR_DOCUMENT_EMPTY, TIXML_ERROR_EMBEDDED_NULL, TIXML_ERROR_PARSING_CDATA, TIXML_ERROR_DOCUMENT_TOP_ONLY, TIXML_ERROR_STRING_COUNT }; protected: static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); inline static bool IsWhiteSpace( char c ) { return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); } inline static bool IsWhiteSpace( int c ) { if ( c < 256 ) return IsWhiteSpace( (char) c ); return false; // Again, only truly correct for English/Latin...but usually works. } #ifdef TIXML_USE_STL static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); #endif /* Reads an XML name into the string provided. Returns a pointer just past the last character of the name, or 0 if the function has an error. */ static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); /* Reads text. Returns a pointer past the given end tag. Wickedly complex options, but it keeps the (sensitive) code in one place. */ static const char* ReadText( const char* in, // where to start TIXML_STRING* text, // the string read bool ignoreWhiteSpace, // whether to keep the white space const char* endTag, // what ends this text bool ignoreCase, // whether to ignore case in the end tag TiXmlEncoding encoding ); // the current encoding // If an entity has been found, transform it into a character. static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); // Get a character, while interpreting entities. // The length can be from 0 to 4 bytes. inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) { assert( p ); if ( encoding == TIXML_ENCODING_UTF8 ) { *length = utf8ByteTable[ *((const unsigned char*)p) ]; assert( *length >= 0 && *length < 5 ); } else { *length = 1; } if ( *length == 1 ) { if ( *p == '&' ) return GetEntity( p, _value, length, encoding ); *_value = *p; return p+1; } else if ( *length ) { //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), // and the null terminator isn't needed for( int i=0; p[i] && i<*length; ++i ) { _value[i] = p[i]; } return p + (*length); } else { // Not valid text. return 0; } } // Return true if the next characters in the stream are any of the endTag sequences. // Ignore case only works for english, and should only be relied on when comparing // to English words: StringEqual( p, "version", true ) is fine. static bool StringEqual( const char* p, const char* endTag, bool ignoreCase, TiXmlEncoding encoding ); static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; TiXmlCursor location; /// Field containing a generic user pointer void* userData; // None of these methods are reliable for any language except English. // Good for approximation, not great for accuracy. static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); inline static int ToLower( int v, TiXmlEncoding encoding ) { if ( encoding == TIXML_ENCODING_UTF8 ) { if ( v < 128 ) return tolower( v ); return v; } else { return tolower( v ); } } static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); private: TiXmlBase( const TiXmlBase& ); // not implemented. void operator=( const TiXmlBase& base ); // not allowed. struct Entity { const char* str; unsigned int strLength; char chr; }; enum { NUM_ENTITY = 5, MAX_ENTITY_LENGTH = 6 }; static Entity entity[ NUM_ENTITY ]; static bool condenseWhiteSpace; }; /** The parent class for everything in the Document Object Model. (Except for attributes). Nodes have siblings, a parent, and children. A node can be in a document, or stand on its own. The type of a TiXmlNode can be queried, and it can be cast to its more defined type. */ class TiXmlNode : public TiXmlBase { friend class TiXmlDocument; friend class TiXmlElement; public: #ifdef TIXML_USE_STL /** An input stream operator, for every class. Tolerant of newlines and formatting, but doesn't expect them. */ friend std::istream& operator >> (std::istream& in, TiXmlNode& base); /** An output stream operator, for every class. Note that this outputs without any newlines or formatting, as opposed to Print(), which includes tabs and new lines. The operator<< and operator>> are not completely symmetric. Writing a node to a stream is very well defined. You'll get a nice stream of output, without any extra whitespace or newlines. But reading is not as well defined. (As it always is.) If you create a TiXmlElement (for example) and read that from an input stream, the text needs to define an element or junk will result. This is true of all input streams, but it's worth keeping in mind. A TiXmlDocument will read nodes until it reads a root element, and all the children of that root element. */ friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); /// Appends the XML node or attribute to a std::string. friend std::string& operator<< (std::string& out, const TiXmlNode& base ); #endif /** The types of XML nodes supported by TinyXml. (All the unsupported types are picked up by UNKNOWN.) */ enum NodeType { TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, TINYXML_UNKNOWN, TINYXML_TEXT, TINYXML_DECLARATION, TINYXML_TYPECOUNT }; virtual ~TiXmlNode(); /** The meaning of 'value' changes for the specific type of TiXmlNode. @verbatim Document: filename of the xml file Element: name of the element Comment: the comment text Unknown: the tag contents Text: the text string @endverbatim The subclasses will wrap this function. */ const char *Value() const { return value.c_str (); } #ifdef TIXML_USE_STL /** Return Value() as a std::string. If you only use STL, this is more efficient than calling Value(). Only available in STL mode. */ const std::string& ValueStr() const { return value; } #endif const TIXML_STRING& ValueTStr() const { return value; } /** Changes the value of the node. Defined as: @verbatim Document: filename of the xml file Element: name of the element Comment: the comment text Unknown: the tag contents Text: the text string @endverbatim */ void SetValue(const char * _value) { value = _value;} #ifdef TIXML_USE_STL /// STL std::string form. void SetValue( const std::string& _value ) { value = _value; } #endif /// Delete all the children of this node. Does not affect 'this'. void Clear(); /// One step up the DOM. TiXmlNode* Parent() { return parent; } const TiXmlNode* Parent() const { return parent; } const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. TiXmlNode* FirstChild() { return firstChild; } const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. /// The first child of this node with the matching 'value'. Will be null if none found. TiXmlNode* FirstChild( const char * _value ) { // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) // call the method, cast the return back to non-const. return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); } const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. TiXmlNode* LastChild() { return lastChild; } const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. TiXmlNode* LastChild( const char * _value ) { return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); } #ifdef TIXML_USE_STL const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. #endif /** An alternate way to walk the children of a node. One way to iterate over nodes is: @verbatim for( child = parent->FirstChild(); child; child = child->NextSibling() ) @endverbatim IterateChildren does the same thing with the syntax: @verbatim child = 0; while( child = parent->IterateChildren( child ) ) @endverbatim IterateChildren takes the previous child as input and finds the next one. If the previous child is null, it returns the first. IterateChildren will return null when done. */ const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; TiXmlNode* IterateChildren( const TiXmlNode* previous ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); } /// This flavor of IterateChildren searches for children with a particular 'value' const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); } #ifdef TIXML_USE_STL const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. #endif /** Add a new node related to this. Adds a child past the LastChild. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); /** Add a new node related to this. Adds a child past the LastChild. NOTE: the node to be added is passed by pointer, and will be henceforth owned (and deleted) by tinyXml. This method is efficient and avoids an extra copy, but should be used with care as it uses a different memory model than the other insert functions. @sa InsertEndChild */ TiXmlNode* LinkEndChild( TiXmlNode* addThis ); /** Add a new node related to this. Adds a child before the specified child. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); /** Add a new node related to this. Adds a child after the specified child. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); /** Replace a child of this node. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); /// Delete a child of this node. bool RemoveChild( TiXmlNode* removeThis ); /// Navigate to a sibling node. const TiXmlNode* PreviousSibling() const { return prev; } TiXmlNode* PreviousSibling() { return prev; } /// Navigate to a sibling node. const TiXmlNode* PreviousSibling( const char * ) const; TiXmlNode* PreviousSibling( const char *_prev ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); } #ifdef TIXML_USE_STL const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. #endif /// Navigate to a sibling node. const TiXmlNode* NextSibling() const { return next; } TiXmlNode* NextSibling() { return next; } /// Navigate to a sibling node with the given 'value'. const TiXmlNode* NextSibling( const char * ) const; TiXmlNode* NextSibling( const char* _next ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); } /** Convenience function to get through elements. Calls NextSibling and ToElement. Will skip all non-Element nodes. Returns 0 if there is not another element. */ const TiXmlElement* NextSiblingElement() const; TiXmlElement* NextSiblingElement() { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); } /** Convenience function to get through elements. Calls NextSibling and ToElement. Will skip all non-Element nodes. Returns 0 if there is not another element. */ const TiXmlElement* NextSiblingElement( const char * ) const; TiXmlElement* NextSiblingElement( const char *_next ) { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); } #ifdef TIXML_USE_STL const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. #endif /// Convenience function to get through elements. const TiXmlElement* FirstChildElement() const; TiXmlElement* FirstChildElement() { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); } /// Convenience function to get through elements. const TiXmlElement* FirstChildElement( const char * _value ) const; TiXmlElement* FirstChildElement( const char * _value ) { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); } #ifdef TIXML_USE_STL const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. #endif /** Query the type (as an enumerated value, above) of this node. The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION. */ int Type() const { return type; } /** Return a pointer to the Document this node lives in. Returns null if not in a document. */ const TiXmlDocument* GetDocument() const; TiXmlDocument* GetDocument() { return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); } /// Returns true if this node has no children. bool NoChildren() const { return !firstChild; } virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. /** Create an exact duplicate of this node and return it. The memory must be deleted by the caller. */ virtual TiXmlNode* Clone() const = 0; /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the TiXmlVisitor interface. This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML is unchanged by using this interface versus any other.) The interface has been based on ideas from: - http://www.saxproject.org/ - http://c2.com/cgi/wiki?HierarchicalVisitorPattern Which are both good references for "visiting". An example of using Accept(): @verbatim TiXmlPrinter printer; tinyxmlDoc.Accept( &printer ); const char* xmlcstr = printer.CStr(); @endverbatim */ virtual bool Accept( TiXmlVisitor* visitor ) const = 0; protected: TiXmlNode( NodeType _type ); // Copy to the allocated object. Shared functionality between Clone, Copy constructor, // and the assignment operator. void CopyTo( TiXmlNode* target ) const; #ifdef TIXML_USE_STL // The real work of the input operator. virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; #endif // Figure out what is at *p, and parse it. Returns null if it is not an xml node. TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); TiXmlNode* parent; NodeType type; TiXmlNode* firstChild; TiXmlNode* lastChild; TIXML_STRING value; TiXmlNode* prev; TiXmlNode* next; private: TiXmlNode( const TiXmlNode& ); // not implemented. void operator=( const TiXmlNode& base ); // not allowed. }; /** An attribute is a name-value pair. Elements have an arbitrary number of attributes, each with a unique name. @note The attributes are not TiXmlNodes, since they are not part of the tinyXML document object model. There are other suggested ways to look at this problem. */ class TiXmlAttribute : public TiXmlBase { friend class TiXmlAttributeSet; public: /// Construct an empty attribute. TiXmlAttribute() : TiXmlBase() { document = 0; prev = next = 0; } #ifdef TIXML_USE_STL /// std::string constructor. TiXmlAttribute( const std::string& _name, const std::string& _value ) { name = _name; value = _value; document = 0; prev = next = 0; } #endif /// Construct an attribute with a name and value. TiXmlAttribute( const char * _name, const char * _value ) { name = _name; value = _value; document = 0; prev = next = 0; } const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. #ifdef TIXML_USE_STL const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. #endif int IntValue() const; ///< Return the value of this attribute, converted to an integer. double DoubleValue() const; ///< Return the value of this attribute, converted to a double. // Get the tinyxml string representation const TIXML_STRING& NameTStr() const { return name; } /** QueryIntValue examines the value string. It is an alternative to the IntValue() method with richer error checking. If the value is an integer, it is stored in 'value' and the call returns TIXML_SUCCESS. If it is not an integer, it returns TIXML_WRONG_TYPE. A specialized but useful call. Note that for success it returns 0, which is the opposite of almost all other TinyXml calls. */ int QueryIntValue( int* _value ) const; /// QueryDoubleValue examines the value string. See QueryIntValue(). int QueryDoubleValue( double* _value ) const; void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. void SetValue( const char* _value ) { value = _value; } ///< Set the value. void SetIntValue( int _value ); ///< Set the value from an integer. void SetDoubleValue( double _value ); ///< Set the value from a double. #ifdef TIXML_USE_STL /// STL std::string form. void SetName( const std::string& _name ) { name = _name; } /// STL std::string form. void SetValue( const std::string& _value ) { value = _value; } #endif /// Get the next sibling attribute in the DOM. Returns null at end. const TiXmlAttribute* Next() const; TiXmlAttribute* Next() { return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); } /// Get the previous sibling attribute in the DOM. Returns null at beginning. const TiXmlAttribute* Previous() const; TiXmlAttribute* Previous() { return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); } bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } /* Attribute parsing starts: first letter of the name returns: the next char after the value end quote */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); // Prints this Attribute to a FILE stream. virtual void Print( FILE* cfile, int depth ) const { Print( cfile, depth, 0 ); } void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; // [internal use] // Set the document pointer so the attribute can report errors. void SetDocument( TiXmlDocument* doc ) { document = doc; } private: TiXmlAttribute( const TiXmlAttribute& ); // not implemented. void operator=( const TiXmlAttribute& base ); // not allowed. TiXmlDocument* document; // A pointer back to a document, for error reporting. TIXML_STRING name; TIXML_STRING value; TiXmlAttribute* prev; TiXmlAttribute* next; }; /* A class used to manage a group of attributes. It is only used internally, both by the ELEMENT and the DECLARATION. The set can be changed transparent to the Element and Declaration classes that use it, but NOT transparent to the Attribute which has to implement a next() and previous() method. Which makes it a bit problematic and prevents the use of STL. This version is implemented with circular lists because: - I like circular lists - it demonstrates some independence from the (typical) doubly linked list. */ class TiXmlAttributeSet { public: TiXmlAttributeSet(); ~TiXmlAttributeSet(); void Add( TiXmlAttribute* attribute ); void Remove( TiXmlAttribute* attribute ); const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } TiXmlAttribute* Find( const char* _name ) const; TiXmlAttribute* FindOrCreate( const char* _name ); # ifdef TIXML_USE_STL TiXmlAttribute* Find( const std::string& _name ) const; TiXmlAttribute* FindOrCreate( const std::string& _name ); # endif private: //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), //*ME: this class must be also use a hidden/disabled copy-constructor !!! TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) TiXmlAttribute sentinel; }; /** The element is a container class. It has a value, the element name, and can contain other elements, text, comments, and unknowns. Elements also contain an arbitrary number of attributes. */ class TiXmlElement : public TiXmlNode { public: /// Construct an element. TiXmlElement (const char * in_value); #ifdef TIXML_USE_STL /// std::string constructor. TiXmlElement( const std::string& _value ); #endif TiXmlElement( const TiXmlElement& ); TiXmlElement& operator=( const TiXmlElement& base ); virtual ~TiXmlElement(); /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. */ const char* Attribute( const char* name ) const; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. If the attribute exists and can be converted to an integer, the integer value will be put in the return 'i', if 'i' is non-null. */ const char* Attribute( const char* name, int* i ) const; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. If the attribute exists and can be converted to an double, the double value will be put in the return 'd', if 'd' is non-null. */ const char* Attribute( const char* name, double* d ) const; /** QueryIntAttribute examines the attribute - it is an alternative to the Attribute() method with richer error checking. If the attribute is an integer, it is stored in 'value' and the call returns TIXML_SUCCESS. If it is not an integer, it returns TIXML_WRONG_TYPE. If the attribute does not exist, then TIXML_NO_ATTRIBUTE is returned. */ int QueryIntAttribute( const char* name, int* _value ) const; /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). int QueryUnsignedAttribute( const char* name, unsigned* _value ) const; /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). Note that '1', 'true', or 'yes' are considered true, while '0', 'false' and 'no' are considered false. */ int QueryBoolAttribute( const char* name, bool* _value ) const; /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). int QueryDoubleAttribute( const char* name, double* _value ) const; /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). int QueryFloatAttribute( const char* name, float* _value ) const { double d; int result = QueryDoubleAttribute( name, &d ); if ( result == TIXML_SUCCESS ) { *_value = (float)d; } return result; } #ifdef TIXML_USE_STL /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). int QueryStringAttribute( const char* name, std::string* _value ) const { const char* cstr = Attribute( name ); if ( cstr ) { *_value = std::string( cstr ); return TIXML_SUCCESS; } return TIXML_NO_ATTRIBUTE; } /** Template form of the attribute query which will try to read the attribute into the specified type. Very easy, very powerful, but be careful to make sure to call this with the correct type. NOTE: This method doesn't work correctly for 'string' types that contain spaces. @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE */ template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; std::stringstream sstream( node->ValueStr() ); sstream >> *outValue; if ( !sstream.fail() ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } int QueryValueAttribute( const std::string& name, std::string* outValue ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; *outValue = node->ValueStr(); return TIXML_SUCCESS; } #endif /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetAttribute( const char* name, const char * _value ); #ifdef TIXML_USE_STL const std::string* Attribute( const std::string& name ) const; const std::string* Attribute( const std::string& name, int* i ) const; const std::string* Attribute( const std::string& name, double* d ) const; int QueryIntAttribute( const std::string& name, int* _value ) const; int QueryDoubleAttribute( const std::string& name, double* _value ) const; /// STL std::string form. void SetAttribute( const std::string& name, const std::string& _value ); ///< STL std::string form. void SetAttribute( const std::string& name, int _value ); ///< STL std::string form. void SetDoubleAttribute( const std::string& name, double value ); #endif /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetAttribute( const char * name, int value ); /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetDoubleAttribute( const char * name, double value ); /** Deletes an attribute with the given name. */ void RemoveAttribute( const char * name ); #ifdef TIXML_USE_STL void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. #endif const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } /** Convenience function for easy access to the text inside an element. Although easy and concise, GetText() is limited compared to getting the TiXmlText child and accessing it directly. If the first child of 'this' is a TiXmlText, the GetText() returns the character string of the Text node, else null is returned. This is a convenient method for getting the text of simple contained text: @verbatim This is text const char* str = fooElement->GetText(); @endverbatim 'str' will be a pointer to "This is text". Note that this function can be misleading. If the element foo was created from this XML: @verbatim This is text @endverbatim then the value of str would be null. The first child node isn't a text node, it is another element. From this XML: @verbatim This is text @endverbatim GetText() will return "This is ". WARNING: GetText() accesses a child node - don't become confused with the similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are safe type casts on the referenced node. */ const char* GetText() const; /// Creates a new Element and returns it - the returned element is a copy. virtual TiXmlNode* Clone() const; // Print the Element to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /* Attribtue parsing starts: next char past '<' returns: next char past '>' */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlElement* target ) const; void ClearThis(); // like clear, but initializes 'this' object as well // Used to be public [internal use] #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif /* [internal use] Reads the "value" of the element -- another element, or text. This should terminate with the current end tag. */ const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); private: TiXmlAttributeSet attributeSet; }; /** An XML comment. */ class TiXmlComment : public TiXmlNode { public: /// Constructs an empty comment. TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {} /// Construct a comment from text. TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { SetValue( _value ); } TiXmlComment( const TiXmlComment& ); TiXmlComment& operator=( const TiXmlComment& base ); virtual ~TiXmlComment() {} /// Returns a copy of this Comment. virtual TiXmlNode* Clone() const; // Write this Comment to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /* Attribtue parsing starts: at the ! of the !-- returns: next char past '>' */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlComment* target ) const; // used to be public #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif // virtual void StreamOut( TIXML_OSTREAM * out ) const; private: }; /** XML text. A text node can have 2 ways to output the next. "normal" output and CDATA. It will default to the mode it was parsed from the XML file and you generally want to leave it alone, but you can change the output mode with SetCDATA() and query it with CDATA(). */ class TiXmlText : public TiXmlNode { friend class TiXmlElement; public: /** Constructor for text element. By default, it is treated as normal, encoded text. If you want it be output as a CDATA text element, set the parameter _cdata to 'true' */ TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) { SetValue( initValue ); cdata = false; } virtual ~TiXmlText() {} #ifdef TIXML_USE_STL /// Constructor. TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) { SetValue( initValue ); cdata = false; } #endif TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT ) { copy.CopyTo( this ); } TiXmlText& operator=( const TiXmlText& base ) { base.CopyTo( this ); return *this; } // Write this text object to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /// Queries whether this represents text using a CDATA section. bool CDATA() const { return cdata; } /// Turns on or off a CDATA representation of text. void SetCDATA( bool _cdata ) { cdata = _cdata; } virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected : /// [internal use] Creates a new Element and returns it. virtual TiXmlNode* Clone() const; void CopyTo( TiXmlText* target ) const; bool Blank() const; // returns true if all white space and new lines // [internal use] #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: bool cdata; // true if this should be input and output as a CDATA style text element }; /** In correct XML the declaration is the first entry in the file. @verbatim @endverbatim TinyXml will happily read or write files without a declaration, however. There are 3 possible attributes to the declaration: version, encoding, and standalone. Note: In this version of the code, the attributes are handled as special cases, not generic attributes, simply because there can only be at most 3 and they are always the same. */ class TiXmlDeclaration : public TiXmlNode { public: /// Construct an empty declaration. TiXmlDeclaration() : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {} #ifdef TIXML_USE_STL /// Constructor. TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ); #endif /// Construct. TiXmlDeclaration( const char* _version, const char* _encoding, const char* _standalone ); TiXmlDeclaration( const TiXmlDeclaration& copy ); TiXmlDeclaration& operator=( const TiXmlDeclaration& copy ); virtual ~TiXmlDeclaration() {} /// Version. Will return an empty string if none was found. const char *Version() const { return version.c_str (); } /// Encoding. Will return an empty string if none was found. const char *Encoding() const { return encoding.c_str (); } /// Is this a standalone document? const char *Standalone() const { return standalone.c_str (); } /// Creates a copy of this Declaration and returns it. virtual TiXmlNode* Clone() const; // Print this declaration to a FILE stream. virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; virtual void Print( FILE* cfile, int depth ) const { Print( cfile, depth, 0 ); } virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlDeclaration* target ) const; // used to be public #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: TIXML_STRING version; TIXML_STRING encoding; TIXML_STRING standalone; }; /** Any tag that tinyXml doesn't recognize is saved as an unknown. It is a tag of text, but should not be modified. It will be written back to the XML, unchanged, when the file is saved. DTD tags get thrown into TiXmlUnknowns. */ class TiXmlUnknown : public TiXmlNode { public: TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) {} virtual ~TiXmlUnknown() {} TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) { copy.CopyTo( this ); } TiXmlUnknown& operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); return *this; } /// Creates a copy of this Unknown and returns it. virtual TiXmlNode* Clone() const; // Print this Unknown to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected: void CopyTo( TiXmlUnknown* target ) const; #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: }; /** Always the top level node. A document binds together all the XML pieces. It can be saved, loaded, and printed to the screen. The 'value' of a document node is the xml file name. */ class TiXmlDocument : public TiXmlNode { public: /// Create an empty document, that has no name. TiXmlDocument(); /// Create a document with a name. The name of the document is also the filename of the xml. TiXmlDocument( const char * documentName ); #ifdef TIXML_USE_STL /// Constructor. TiXmlDocument( const std::string& documentName ); #endif TiXmlDocument( const TiXmlDocument& copy ); TiXmlDocument& operator=( const TiXmlDocument& copy ); virtual ~TiXmlDocument() {} /** Load a file using the current document value. Returns true if successful. Will delete any existing document data before loading. */ bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the current document value. Returns true if successful. bool SaveFile() const; /// Load a file using the given filename. Returns true if successful. bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the given filename. Returns true if successful. bool SaveFile( const char * filename ) const; /** Load a file using the given FILE*. Returns true if successful. Note that this method doesn't stream - the entire object pointed at by the FILE* will be interpreted as an XML file. TinyXML doesn't stream in XML from the current file location. Streaming may be added in the future. */ bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the given FILE*. Returns true if successful. bool SaveFile( FILE* ) const; #ifdef TIXML_USE_STL bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. { return LoadFile( filename.c_str(), encoding ); } bool SaveFile( const std::string& filename ) const ///< STL std::string version. { return SaveFile( filename.c_str() ); } #endif /** Parse the given null terminated block of xml data. Passing in an encoding to this method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml to use that encoding, regardless of what TinyXml might otherwise try to detect. */ virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /** Get the root element -- the only top level element -- of the document. In well formed XML, there should only be one. TinyXml is tolerant of multiple elements at the document level. */ const TiXmlElement* RootElement() const { return FirstChildElement(); } TiXmlElement* RootElement() { return FirstChildElement(); } /** If an error occurs, Error will be set to true. Also, - The ErrorId() will contain the integer identifier of the error (not generally useful) - The ErrorDesc() method will return the name of the error. (very useful) - The ErrorRow() and ErrorCol() will return the location of the error (if known) */ bool Error() const { return error; } /// Contains a textual (english) description of the error if one occurs. const char * ErrorDesc() const { return errorDesc.c_str (); } /** Generally, you probably want the error string ( ErrorDesc() ). But if you prefer the ErrorId, this function will fetch it. */ int ErrorId() const { return errorId; } /** Returns the location (if known) of the error. The first column is column 1, and the first row is row 1. A value of 0 means the row and column wasn't applicable (memory errors, for example, have no row/column) or the parser lost the error. (An error in the error reporting, in that case.) @sa SetTabSize, Row, Column */ int ErrorRow() const { return errorLocation.row+1; } int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) to report the correct values for row and column. It does not change the output or input in any way. By calling this method, with a tab size greater than 0, the row and column of each node and attribute is stored when the file is loaded. Very useful for tracking the DOM back in to the source file. The tab size is required for calculating the location of nodes. If not set, the default of 4 is used. The tabsize is set per document. Setting the tabsize to 0 disables row/column tracking. Note that row and column tracking is not supported when using operator>>. The tab size needs to be enabled before the parse or load. Correct usage: @verbatim TiXmlDocument doc; doc.SetTabSize( 8 ); doc.Load( "myfile.xml" ); @endverbatim @sa Row, Column */ void SetTabSize( int _tabsize ) { tabsize = _tabsize; } int TabSize() const { return tabsize; } /** If you have handled the error, it can be reset with this call. The error state is automatically cleared if you Parse a new XML block. */ void ClearError() { error = false; errorId = 0; errorDesc = ""; errorLocation.row = errorLocation.col = 0; //errorLocation.last = 0; } /** Write the document to standard out using formatted printing ("pretty print"). */ void Print() const { Print( stdout, 0 ); } /* Write the document to a string using formatted printing ("pretty print"). This will allocate a character array (new char[]) and return it as a pointer. The calling code pust call delete[] on the return char* to avoid a memory leak. */ //char* PrintToMemory() const; /// Print this Document to a FILE stream. virtual void Print( FILE* cfile, int depth = 0 ) const; // [internal use] void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected : // [internal use] virtual TiXmlNode* Clone() const; #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: void CopyTo( TiXmlDocument* target ) const; bool error; int errorId; TIXML_STRING errorDesc; int tabsize; TiXmlCursor errorLocation; bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. }; /** A TiXmlHandle is a class that wraps a node pointer with null checks; this is an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml DOM structure. It is a separate utility class. Take an example: @verbatim @endverbatim Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very easy to write a *lot* of code that looks like: @verbatim TiXmlElement* root = document.FirstChildElement( "Document" ); if ( root ) { TiXmlElement* element = root->FirstChildElement( "Element" ); if ( element ) { TiXmlElement* child = element->FirstChildElement( "Child" ); if ( child ) { TiXmlElement* child2 = child->NextSiblingElement( "Child" ); if ( child2 ) { // Finally do something useful. @endverbatim And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity of such code. A TiXmlHandle checks for null pointers so it is perfectly safe and correct to use: @verbatim TiXmlHandle docHandle( &document ); TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); if ( child2 ) { // do something useful @endverbatim Which is MUCH more concise and useful. It is also safe to copy handles - internally they are nothing more than node pointers. @verbatim TiXmlHandle handleCopy = handle; @endverbatim What they should not be used for is iteration: @verbatim int i=0; while ( true ) { TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); if ( !child ) break; // do something ++i; } @endverbatim It seems reasonable, but it is in fact two embedded while loops. The Child method is a linear walk to find the element, so this code would iterate much more than it needs to. Instead, prefer: @verbatim TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); for( child; child; child=child->NextSiblingElement() ) { // do something } @endverbatim */ class TiXmlHandle { public: /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } /// Copy constructor TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } TiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; } /// Return a handle to the first child node. TiXmlHandle FirstChild() const; /// Return a handle to the first child node with the given name. TiXmlHandle FirstChild( const char * value ) const; /// Return a handle to the first child element. TiXmlHandle FirstChildElement() const; /// Return a handle to the first child element with the given name. TiXmlHandle FirstChildElement( const char * value ) const; /** Return a handle to the "index" child with the given name. The first child is 0, the second 1, etc. */ TiXmlHandle Child( const char* value, int index ) const; /** Return a handle to the "index" child. The first child is 0, the second 1, etc. */ TiXmlHandle Child( int index ) const; /** Return a handle to the "index" child element with the given name. The first child element is 0, the second 1, etc. Note that only TiXmlElements are indexed: other types are not counted. */ TiXmlHandle ChildElement( const char* value, int index ) const; /** Return a handle to the "index" child element. The first child element is 0, the second 1, etc. Note that only TiXmlElements are indexed: other types are not counted. */ TiXmlHandle ChildElement( int index ) const; #ifdef TIXML_USE_STL TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } #endif /** Return the handle as a TiXmlNode. This may return null. */ TiXmlNode* ToNode() const { return node; } /** Return the handle as a TiXmlElement. This may return null. */ TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } /** Return the handle as a TiXmlText. This may return null. */ TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } /** Return the handle as a TiXmlUnknown. This may return null. */ TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } /** @deprecated use ToNode. Return the handle as a TiXmlNode. This may return null. */ TiXmlNode* Node() const { return ToNode(); } /** @deprecated use ToElement. Return the handle as a TiXmlElement. This may return null. */ TiXmlElement* Element() const { return ToElement(); } /** @deprecated use ToText() Return the handle as a TiXmlText. This may return null. */ TiXmlText* Text() const { return ToText(); } /** @deprecated use ToUnknown() Return the handle as a TiXmlUnknown. This may return null. */ TiXmlUnknown* Unknown() const { return ToUnknown(); } private: TiXmlNode* node; }; /** Print to memory functionality. The TiXmlPrinter is useful when you need to: -# Print to memory (especially in non-STL mode) -# Control formatting (line endings, etc.) When constructed, the TiXmlPrinter is in its default "pretty printing" mode. Before calling Accept() you can call methods to control the printing of the XML document. After TiXmlNode::Accept() is called, the printed document can be accessed via the CStr(), Str(), and Size() methods. TiXmlPrinter uses the Visitor API. @verbatim TiXmlPrinter printer; printer.SetIndent( "\t" ); doc.Accept( &printer ); fprintf( stdout, "%s", printer.CStr() ); @endverbatim */ class TiXmlPrinter : public TiXmlVisitor { public: TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), buffer(), indent( " " ), lineBreak( "\n" ) {} virtual bool VisitEnter( const TiXmlDocument& doc ); virtual bool VisitExit( const TiXmlDocument& doc ); virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); virtual bool VisitExit( const TiXmlElement& element ); virtual bool Visit( const TiXmlDeclaration& declaration ); virtual bool Visit( const TiXmlText& text ); virtual bool Visit( const TiXmlComment& comment ); virtual bool Visit( const TiXmlUnknown& unknown ); /** Set the indent characters for printing. By default 4 spaces but tab (\t) is also useful, or null/empty string for no indentation. */ void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } /// Query the indention string. const char* Indent() { return indent.c_str(); } /** Set the line breaking string. By default set to newline (\n). Some operating systems prefer other characters, or can be set to the null/empty string for no indenation. */ void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } /// Query the current line breaking string. const char* LineBreak() { return lineBreak.c_str(); } /** Switch over to "stream printing" which is the most dense formatting without linebreaks. Common when the XML is needed for network transmission. */ void SetStreamPrinting() { indent = ""; lineBreak = ""; } /// Return the result. const char* CStr() { return buffer.c_str(); } /// Return the length of the result string. size_t Size() { return buffer.size(); } #ifdef TIXML_USE_STL /// Return the result. const std::string& Str() { return buffer; } #endif private: void DoIndent() { for( int i=0; i