diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/language/english_base.txt 0.2.8-armagetronad-sty+ct/language/english_base.txt --- 0.2.8-armagetronad-sty/language/english_base.txt 2009-03-12 23:14:35.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/language/english_base.txt 2009-03-13 00:02:53.000000000 -0500 @@ -749,10 +749,12 @@ ladderlog_write_all_usage Usage: LADDER_LOG_WRITE_ALL 1|0 ladderlog_write_all_enabled Enabled full ladderlog output. ladderlog_write_all_disabled Disabled ladderlog output. +ladderlog_write_admin_command Write to ladderlog: ADMIN_COMMAND ladderlog_write_authority_blurb_help Write to ladderlog: AUTHORITY_BLURB ladderlog_write_basezone_conquered_help Write to ladderlog: BASEZONE_CONQUERED ladderlog_write_basezone_conquerer_help Write to ladderlog: BASEZONE_CONQUERER ladderlog_write_chat_help Write to ladderlog: CHAT [/me] +ladderlog_write_command_help Write to ladderlog: COMMAND ladderlog_write_death_frag_help Write to ladderlog: DEATH_FRAG ladderlog_write_death_suicide_help Write to ladderlog: DEATH_SUICIDE ladderlog_write_death_teamkill_help Write to ladderlog: DEATH_TEAMKILL @@ -772,7 +774,12 @@ ladderlog_write_sacrifice_help Write to ladderlog: SACRIFICE ladderlog_write_wait_for_external_script_help Write to ladderlog: WAIT_FOR_EXTERNAL_SCRIPT (see also: WAIT_FOR_EXTERNAL_SCRIPT and WAIT_FOR_EXTERNAL_SCRIPT_TIMEOUT) ladderlog_game_time_interval_help If nonnegative, write a line with the current game time to the ladder log every n seconds. + + chat_log_help Write machine parsable chat messages to var/chatlog.txt +chatlog_write_team Write /team messages to chatlog [1: on | 0:off] +chatlog_write_pm Write Private messages (/msg) to chatlog [1: on | 0:off] +CHATLOG_WRITE_TEAM CHATLOG_WRITE_PM show_fps_help Enable fps display floor_mirror_help Floor mirror mode floor_detail_help Floor detail settings @@ -2278,6 +2285,8 @@ player_win_default \1 got \2 points for a very strange reason.\n player_lose_default \1 lost \2 points for a very strange reason.\n player_lose_suicide \1 committed suicide and lost \2 points.\n +player_lose_deathzone \1 exploded on a deathzone and lost \2 points.\n +player_lose_rubberzone \1 exploded on a rubberzone and lost \2 points.\n player_free_suicide \1 committed suicide.\n player_win_frag \1 core dumped \3 for \2 points.\n player_win_survive \1 got \2 points for surviving.\n @@ -2328,6 +2337,11 @@ player_flag_cant_score \1 took the flag home, but their flag isn't back yet. Get it!\n player_flag_hold_score_win \1 got \2 points for holding the flag!\n player_flag_hold_score_lose \1 lost \2 points for holding the flag!\n +min_flags_home minimum number of flags that must be home in order for flag to be captured + +player_target_score_win \1 got \2 points for entering a target.\n +player_target_score_lose \1 lost \2 points for entering a target.\n +player_target_win_conquest \1 win round for being the first to get the last target.\n player_base_respawn \1 was respawned by \2.\n player_base_enemy_respawn \1 was respawned by their enemy \2.\n diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/minor_version 0.2.8-armagetronad-sty+ct/minor_version --- 0.2.8-armagetronad-sty/minor_version 2009-03-12 23:13:57.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/minor_version 2009-03-12 23:08:05.000000000 -0500 @@ -1 +1 @@ -_alphaDATE +-sty+ct_alphaDATE diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/resource/proto/AATeam/map-0.2.8.0_pig2.dtd 0.2.8-armagetronad-sty+ct/resource/proto/AATeam/map-0.2.8.0_pig2.dtd --- 0.2.8-armagetronad-sty/resource/proto/AATeam/map-0.2.8.0_pig2.dtd 2009-03-12 23:13:57.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/resource/proto/AATeam/map-0.2.8.0_pig2.dtd 2009-03-13 00:02:06.000000000 -0500 @@ -26,7 +26,7 @@ - + Only in 0.2.8-armagetronad-sty+ct/resource/proto/AATeam: map-0.2.8.0_sty+ct.dtd Only in 0.2.8-armagetronad-sty+ct/resource/proto/AATeam: map-0.2.8.0_sty+ct2.dtd diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/Makefile.am 0.2.8-armagetronad-sty+ct/src/Makefile.am --- 0.2.8-armagetronad-sty/src/Makefile.am 2009-03-12 23:13:57.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/Makefile.am 2009-03-12 23:08:06.000000000 -0500 @@ -105,6 +105,7 @@ tron/gSensor.cpp tron/gSensor.h tron/gServerBrowser.cpp tron/gServerBrowser.h tron/gSparks.cpp tron/gSparks.h\ tron/gSpawn.cpp tron/gSpawn.h tron/gStuff.cpp tron/gStuff.h tron/gTeam.cpp tron/gTeam.h tron/gWall.cpp\ tron/gWall.h tron/gWinZone.cpp tron/gWinZone.h\ + tron/gSvgOutput.h tron/gSvgOutput.cpp\ tron/gFriends.h tron/gFriends.cpp\ tron/gServerFavorites.h tron/gServerFavorites.cpp diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/engine/eAdvWall.cpp 0.2.8-armagetronad-sty+ct/src/engine/eAdvWall.cpp --- 0.2.8-armagetronad-sty/src/engine/eAdvWall.cpp 2009-03-12 23:13:58.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/engine/eAdvWall.cpp 2009-03-12 23:08:06.000000000 -0500 @@ -37,12 +37,15 @@ #include "eRectangle.h" #include "rRender.h" +#include + /* ********************************************** RimWall ********************************************** */ static eRectangle se_rimWallBounds; tList se_rimWalls; +std::vector se_unsplittedRimWalls; eWallRim::eWallRim(eGrid *grid, bool backface_cull, REAL h) :eWall(grid), rim_id(-1),bf_cull(backface_cull), height(h) diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/engine/eAdvWall.h 0.2.8-armagetronad-sty+ct/src/engine/eAdvWall.h --- 0.2.8-armagetronad-sty/src/engine/eAdvWall.h 2009-03-12 23:13:57.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/engine/eAdvWall.h 2009-03-12 23:08:06.000000000 -0500 @@ -30,10 +30,19 @@ #define ArmageTron_ADV_WALL_H #include "eWall.h" +#include "eCoord.h" #include "nNetObject.h" class eRectangle; +// class to keep unsplitted rimwalls as a svg path +class ePolyLine { +public: + char op; //!< operation M: moveto, L: lineto + eCoord pt; //!< corresponding point + ePolyLine(char p_op, eCoord p_pt):op(p_op),pt(p_pt) {}; +}; + class eWallRim:public eWall{ protected: int rim_id; diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/engine/eAxis.h 0.2.8-armagetronad-sty+ct/src/engine/eAxis.h --- 0.2.8-armagetronad-sty/src/engine/eAxis.h 2009-03-12 23:13:56.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/engine/eAxis.h 2009-03-12 23:08:06.000000000 -0500 @@ -23,6 +23,7 @@ int WindingNumber() const {return numberWinding;} int NearestWinding (eCoord pos); eCoord GetDirection (int winding); + float GetWindingAngle (int winding) {return windingAngles?windingAngles[winding]:0;} void Turn(int ¤tWinding, int direction); void TurnRight(int &direction); diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/engine/eGameObject.cpp 0.2.8-armagetronad-sty+ct/src/engine/eGameObject.cpp --- 0.2.8-armagetronad-sty/src/engine/eGameObject.cpp 2009-03-12 23:14:35.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/engine/eGameObject.cpp 2009-03-12 23:11:25.000000000 -0500 @@ -638,6 +638,9 @@ // draws it to the screen using OpenGL void eGameObject::Render(const eCamera *){} +//! draws it in a svg file +void eGameObject::DrawSvg(std::ofstream &f) {} + // ******************************************************************************* // * // * RendersAlpha diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/engine/eGameObject.h 0.2.8-armagetronad-sty+ct/src/engine/eGameObject.h --- 0.2.8-armagetronad-sty/src/engine/eGameObject.h 2009-03-12 23:13:58.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/engine/eGameObject.h 2009-03-12 23:08:06.000000000 -0500 @@ -34,6 +34,9 @@ #include "eCoord.h" #include "tSafePTR.h" +#include +#include + class eGrid; class uActionPlayer; class eTeam; @@ -173,6 +176,9 @@ //! draws object to the screen using OpenGL virtual void Render(const eCamera *cam); + //! draws it in a svg file + virtual void DrawSvg(std::ofstream &f); + //! returns whether the rendering uses alpha blending (massively, so sorting errors would show) virtual bool RendersAlpha() const; diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/engine/eGrid.cpp 0.2.8-armagetronad-sty+ct/src/engine/eGrid.cpp --- 0.2.8-armagetronad-sty/src/engine/eGrid.cpp 2009-03-12 23:13:57.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/engine/eGrid.cpp 2009-03-12 23:08:07.000000000 -0500 @@ -686,6 +686,14 @@ } /* + * Return the direction associated with a winding number + */ +float eGrid::GetWindingAngle(int winding) +{ + return axis.GetWindingAngle(winding); +} + +/* * Define the number of winding to be used on this grid */ void eGrid::SetWinding(int number) diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/engine/eGrid.h 0.2.8-armagetronad-sty+ct/src/engine/eGrid.h --- 0.2.8-armagetronad-sty/src/engine/eGrid.h 2009-03-12 23:14:00.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/engine/eGrid.h 2009-03-12 23:08:07.000000000 -0500 @@ -100,6 +100,7 @@ void SetWinding(int number); void SetWinding(int number, eCoord directions[], bool normalise=true); + float GetWindingAngle(int winding); // Ask the grid to turn a winding void Turn(int ¤tWinding, int direction); diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/engine/ePlayer.cpp 0.2.8-armagetronad-sty+ct/src/engine/ePlayer.cpp --- 0.2.8-armagetronad-sty/src/engine/ePlayer.cpp 2009-03-12 23:14:35.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/engine/ePlayer.cpp 2009-03-13 00:02:54.000000000 -0500 @@ -58,6 +58,7 @@ #include #include "../tron/gCycle.h" #include "../tron/gWinZone.h" +#include "eGrid.h" // call on commands that only work on the server; quit if it returns true bool se_NeedsServer(char const * command, std::istream & s, bool strict ) @@ -150,6 +151,12 @@ static bool se_allowTeamChanges = true; static tSettingItem< bool > se_allowTeamChangesConf( "ALLOW_TEAM_CHANGE", se_allowTeamChanges ); +static bool se_chatLogWritePM = false; +static tSettingItem< bool > se_chatLogWritePMConf( "CHATLOG_WRITE_PM", se_chatLogWritePM ); + +static bool se_chatLogWriteTeam = false; +static tSettingItem< bool > se_chatLogWriteTeamConf( "CHATLOG_WRITE_TEAM", se_chatLogWriteTeam ); + static bool se_enableChat = true; //flag indicating whether chat should be allowed at all (logged in players can always chat) static tSettingItem< bool > se_enaChat("ENABLE_CHAT", se_enableChat); @@ -162,6 +169,11 @@ static tReferenceHolder< ePlayerNetID > se_PlayerReferences; +int ladder_highscore_output=1; +static tSettingItem ldd_rout("LADDER_HIGHSCORE_OUTPUT", + ladder_highscore_output); + + class PasswordStorage { public: @@ -2351,6 +2363,9 @@ } #endif // KRAWALL +static eLadderLogWriter se_adminLoginWriter("ADMIN_LOGIN", false); +static eLadderLogWriter se_adminLogoutWriter("ADMIN_LOGOUT", false); + // the following function really is only supposed to be called from here and nowhere else // (access right escalation risk): // log in (via admin password or hash based login) @@ -2396,6 +2411,8 @@ // the following function really is only supposed to be called from here and nowhere else // (access right escalation risk) se_AdminLogin_ReallyOnlyCallFromChatKTHNXBYE( p ); + se_adminLoginWriter << p->GetUserName() << nMachine::GetMachine(p->Owner()).GetIP(); + se_adminLoginWriter.write(); } else { @@ -2456,11 +2473,15 @@ if ( p->IsLoggedIn() ) { sn_ConsoleOut("You have been logged out!\n",p->Owner()); + se_adminLogoutWriter << p->GetUserName() << nMachine::GetMachine(p->Owner()).GetIP(); + se_adminLogoutWriter.write(); } p->BeNotLoggedIn(); #endif } +static eLadderLogWriter se_adminCommandWriter("ADMIN_COMMAND", false); + // access level a user has to have to be able to see what's being typed at /admin static tAccessLevel se_consoleSpyAccessLevel = tAccessLevel_Moderator; static tSettingItem< tAccessLevel > se_consoleSpyAccessLevelConf( "ACCESS_LEVEL_SPY_CONSOLE", se_consoleSpyAccessLevel ); @@ -2482,6 +2503,8 @@ tString str; str.ReadLine(s); + se_adminCommandWriter << p->GetUserName() << nMachine::GetMachine(p->Owner()).GetIP() << p->GetAccessLevel() << str; + se_adminCommandWriter.write(); tColoredString msg; msg << tColoredString::ColorString(1,0,0) << "Remote admin command" << tColoredString::ColorString(-1,-1,-1) << " by " << tColoredString::ColorString(1,1,.5) << p->GetUserName() << tColoredString::ColorString(-1,-1,-1) << ": " << tColoredString::ColorString(.5,.5,1) << str << "\n"; se_SecretConsoleOut( msg, p, &se_cannotSeeConsole, p ); @@ -2499,6 +2522,9 @@ } } +static eLadderLogWriter se_commandWriter("COMMAND", false); +static eLadderLogWriter se_invalidCommandWriter("INVALID_COMMAND", false); + static void handle_chat_admin_commands( ePlayerNetID * p, tString const & command, tString const & say, std::istream & s, eChatSpamTester &spam ) { if (command == "/login") @@ -2554,7 +2580,21 @@ { se_AdminAdmin( p, s ); } - else + else if ( command == "/cmd" && se_commandWriter.isEnabled() ) + { + tString str; + str.ReadLine(s); + se_commandWriter << p->GetUserName() << nMachine::GetMachine(p->Owner()).GetIP() << p->GetAccessLevel() << str; + se_commandWriter.write(); + } + else{ + if (se_invalidCommandWriter.isEnabled() ) + { + tString str; + str.ReadLine(s); + se_invalidCommandWriter << command << p->GetUserName() << nMachine::GetMachine(p->Owner()).GetIP() << p->GetAccessLevel() << str; + se_invalidCommandWriter.write(); + } if (se_interceptUnknownCommands) { handle_command_intercept(p, say); @@ -2564,6 +2604,7 @@ sn_ConsoleOut( tOutput( "$chat_command_unknown", command ), p->Owner() ); } } +} #else // DEDICATED // returns the team managed by an admin static eTeam * se_GetManagedTeam( ePlayerNetID * admin ) @@ -2629,6 +2670,7 @@ se_silenceDefault); // handles spam checking at the right time +// handles spam checking at the right time eChatSpamTester::eChatSpamTester( ePlayerNetID * p, tString const & say ) : tested_( false ), shouldBlock_( false ), player_( p ), say_( say ), factor_( 1 ) { @@ -2893,6 +2935,13 @@ } } } + + //add /team to chatlog + if (se_chatLogWriteTeam){ + tString str; + str << p->GetUserName() << " /team " << msg; + se_SaveToChatLog(str); + } } // /msg chat commant: talk to anyone team @@ -2942,6 +2991,13 @@ se_SendPrivateMessage( p, receiver, admin, msg_core ); } } + + //send /msg to chatlog + if (se_chatLogWritePM ){ + tString str; + str << p->GetUserName() << " /msg " << receiver->GetUserName() << msg_core; + se_SaveToChatLog(str); + } } } } @@ -5638,8 +5694,10 @@ tString s; s << o; s << "\n"; + if (ladder_highscore_output) { GreetHighscores(s); s << "\n"; + } //std::cout << s; sn_ConsoleOut(s,Owner()); greeted=true; @@ -6024,6 +6082,9 @@ se_onlinePlayerWriter << p->GetLogName(); + // add player color to the message + se_onlinePlayerWriter << p->r << p->g << p->b; + if(p->IsActive()) { se_onlinePlayerWriter << p->ping; if(p->currentTeam) { @@ -6037,6 +6098,145 @@ se_numHumansWriter.write(); } +static eLadderLogWriter se_playerGridPosWriter("PLAYER_GRIDPOS", false); + +void ePlayerNetID::GridPosLadderLog() { + if(!se_playerGridPosWriter.isEnabled()) { + return; + } + if (se_PlayerNetIDs.Len()>0){ + int max = se_PlayerNetIDs.Len(); + for(int i=0;iIsActive() && p->currentTeam && p->Object() && p->Object()->Alive() ) + { + se_playerGridPosWriter << p->GetUserName() << p->Object()->Position().x << p->Object()->Position().y << p->Object()->Direction().x << p->Object()->Direction().y; + if (p->Object() && p->Object()->Team()) + se_playerGridPosWriter << FilterName(p->Object()->Team()->Name()); + else se_playerGridPosWriter << " "; + se_playerGridPosWriter.write(); + } + } + } +} + +// ratio used to set midfield between defense and offense. <= 1.0 means no midfield, n means (n-1)/(n+1) of the distance from zones center is midfield +static REAL sg_playerPositioningMidfieldFactor = 3.0; +static tSettingItem sg_playerPositioningMidfieldFactorConf( "PLAYER_POSITIONING_MIDFIELD_FACTOR", sg_playerPositioningMidfieldFactor ); + +// ratio used to set the circle around a zone dedicated to sumo or goal position. +REAL sg_playerPositioningZoneFactor = 1.5; +static tSettingItem sg_playerPositioningZoneFactorConf( "PLAYER_POSITIONING_ZONE_FACTOR", sg_playerPositioningZoneFactor ); + +static eLadderLogWriter se_tacticalPositionWriter("PLAYER_POSITION", false); + +void ePlayerNetID::TacticalPositioning() { + if(!se_tacticalPositionWriter.isEnabled()) { + return; + } + eGrid *grid = eGrid::CurrentGrid(); + for ( int i = se_PlayerNetIDs.Len()-1; i >= 0; --i ) { + ePlayerNetID *p = se_PlayerNetIDs(i); + // if this player is not active, continue with next one + if (!p->IsActive()||!p->Object()) continue; + // compute closest friend and enemy zones distances + const tList& gameObjects = grid->GameObjects(); + REAL cHighDist = 9999999999.0; + REAL closestHomeDistance = cHighDist; + REAL closestHomeRadius = 0; + REAL closestTargetDistance = cHighDist; + REAL closestTargetRadius = 0; + gBaseZoneHack *zoneHome=0, *zoneTarget=0; + for (int j=gameObjects.Len()-1;j>=0;j--) { + gBaseZoneHack *zone=dynamic_cast(gameObjects(j)); + // for all active base zone ... + if ( zone ) { + REAL zoneDistance = (zone->Position() - p->Object()->Position()).Norm(); + if ( p->CurrentTeam() != zone->Team() ) { + if (zoneDistanceGetRadius(); + } + } else { + if (zoneDistanceGetRadius(); + } + } + } + } + REAL zoneDistance=cHighDist; + if (zoneHome && zoneTarget) { + zoneDistance=(zoneHome->Position()-zoneTarget->Position()).Norm(); + } + // determine new position + tString TacPosStr=tString("NS"); + ePlayerNetID::TacticalPosition newTacticalPos = ePlayerNetID::TP_NS; + int newClosestZoneID = -1; + if ((closestHomeDistance!=cHighDist)||(closestTargetDistance!=cHighDist)) { + if (closestHomeDistanceGOID(); + else + newClosestZoneID = zoneTarget->GOID(); + } + if ((closestHomeDistance==cHighDist)&&(closestTargetDistance==cHighDist)) { + // nothing to do ... just to avoid this case + } else if (closestHomeDistance==cHighDist) { + // no home base, weird but yet, you must be offence + TacPosStr = tString(""); + if (closestTargetDistance<=closestTargetRadius) { + newTacticalPos = ePlayerNetID::TP_Conquering; + TacPosStr<GOID(); + } else if (closestTargetDistance<=closestTargetRadius*sg_playerPositioningZoneFactor) { + newTacticalPos = ePlayerNetID::TP_Attacking; + TacPosStr<GOID(); + } else { + newTacticalPos = ePlayerNetID::TP_Offense; + TacPosStr=tString("OFFENSE"); + } + } else if ((zoneDistance<0.1)&&(closestHomeDistance<=closestHomeRadius*sg_playerPositioningZoneFactor)) { + // Both home and target are at the same place ... it's sumo ;) + newTacticalPos = ePlayerNetID::TP_Sumo; + TacPosStr=tString("SUMO"); + } else if (closestHomeDistance<=closestHomeRadius*sg_playerPositioningZoneFactor) { + // player in the goalie zone + newTacticalPos = ePlayerNetID::TP_Goal; + TacPosStr=tString("GOAL"); + } else if (closestTargetDistance>closestHomeDistance*sg_playerPositioningMidfieldFactor) { + // Home is at least 2 times closer than target + newTacticalPos = ePlayerNetID::TP_Defense; + TacPosStr=tString("DEFENSE"); + } else if (closestHomeDistance>closestTargetDistance*sg_playerPositioningMidfieldFactor) { + // target is at least 2 times closer than home + TacPosStr = tString(""); + if (closestTargetDistance<=closestTargetRadius) { + newTacticalPos = ePlayerNetID::TP_Conquering; + TacPosStr<GOID(); + } else if (closestTargetDistance<=closestTargetRadius*sg_playerPositioningZoneFactor) { + newTacticalPos = ePlayerNetID::TP_Attacking; + TacPosStr<GOID(); + } else { + newTacticalPos = ePlayerNetID::TP_Offense; + TacPosStr=tString("OFFENSE"); + } + } else { + // player seems to be midfield + newTacticalPos = ePlayerNetID::TP_Midfield; + TacPosStr=tString("MIDFIELD"); + } + // if position changed, send a message and store new one + if ((p->tactical_pos != newTacticalPos) || ((p->closest_zoneid != newClosestZoneID) && (newTacticalPos>=6))) { + nMachine const &machine = nMachine::GetMachine(p->Owner()); + se_tacticalPositionWriter << p->GetUserName() << TacPosStr; + se_tacticalPositionWriter.write(); + p->tactical_pos = newTacticalPos; + p->closest_zoneid = newClosestZoneID; + } + } +} + void ePlayerNetID::ClearAll(){ for(int i=MAX_PLAYERS-1;i>=0;i--){ ePlayer *local_p=ePlayer::PlayerConfig(i); @@ -7456,7 +7658,7 @@ // read name of player to be returned tString name; s >> name; - + /* Removed by ed so players are not selected by id number, just names, So players with a number for a name do not confuse things int num = name.toInt(); if ( num > 0 ) { @@ -7472,10 +7674,15 @@ } } } - + */ return ePlayerNetID::FindPlayerByName( name ); } +static bool se_enableAdminKillMessage = true; +static tSettingItem< bool > se_enableAdminKillMessageConf( "ADMIN_KILL_MESSAGE", se_enableAdminKillMessage ); + +static eLadderLogWriter se_playerKilledWriter("PLAYER_KILLED", true); + static void Kill_conf(std::istream &s) { if ( se_NeedsServer( "KILL", s, false ) ) @@ -7487,9 +7694,16 @@ if ( p && p->Object() && p->Object()->Alive() ) { - p->Object()->Kill(); + if (se_enableAdminKillMessage){ sn_ConsoleOut( tOutput( "$player_admin_kill", p->GetColoredName() ) ); } + + se_playerKilledWriter << p->GetUserName() << nMachine::GetMachine(p->Owner()).GetIP() << p->Object()->Position().x << p->Object()->Position().y << p->Object()->Direction().x << p->Object()->Direction().y; + se_playerKilledWriter.write(); + p->Object()->Kill(); + + + } } static tConfItemFunc kill_conf("KILL",&Kill_conf); @@ -7730,7 +7944,11 @@ } else if ( logName != oldLogName_ || screenName != oldScreenName_ ) { - se_playerRenamedWriter << oldLogName_ << logName << nMachine::GetMachine(player_.Owner()).GetIP() << screenName; + se_playerRenamedWriter << oldLogName_ << logName << nMachine::GetMachine(player_.Owner()).GetIP(); +#ifdef KRAWALL_SERVER + se_playerRenamedWriter << (player_.IsAuthenticated()?1:0); +#endif + se_playerRenamedWriter << screenName; se_playerRenamedWriter.write(); if ( oldScreenName_ != screenName ) @@ -8467,6 +8685,24 @@ eTeam::LogScoreDifferences(); } +static eLadderLogWriter se_matchScoreWriter("MATCH_SCORE", true); + +void ePlayerNetID::LogMatchScores( void ) +{ + for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i ) + { + ePlayerNetID* p = se_PlayerNetIDs(i); + if (p->IsHuman()) { + se_matchScoreWriter << p->score << p->GetUserName(); + if ( p->currentTeam ) + se_matchScoreWriter << FilterName( p->currentTeam->Name() ); + se_matchScoreWriter.write(); + } + } + + eTeam::LogMatchScores(); +} + void ePlayerNetID::UpdateSuspensions() { for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i ) { @@ -8505,7 +8741,7 @@ if ( lastScore_ > IMPOSSIBLY_LOW_SCORE && IsHuman() ) { int scoreDifference = score - lastScore_; - lastScore_ = IMPOSSIBLY_LOW_SCORE; + //lastScore_ = IMPOSSIBLY_LOW_SCORE; se_roundScoreWriter << scoreDifference << GetUserName(); if ( currentTeam ) se_roundScoreWriter << FilterName( currentTeam->Name() ); @@ -8548,3 +8784,61 @@ { return suspended_; } + +static void sg_AddScorePlayer(std::istream &s) +{ + tString params; + params.ReadLine( s, true ); + + // parse the line to get the param : Teamname Points Message + int pos = 0; // + tString PlayerStr = tString(""); + PlayerStr = params.ExtractNonBlankSubString(pos); + ePlayerNetID *pPlayer = 0; + int num_matches = -1; + pPlayer = ePlayerNetID::FindPlayerByName(PlayerStr, NULL); + if (!pPlayer) return; + tString ScoreStr = tString(""); + ScoreStr = params.ExtractNonBlankSubString(pos); + int pScore = atoi(ScoreStr); + tString pMessage = params.SubStr(pos+1); + pMessage << "\n"; + + // Add score to team pTeam then send a message + pPlayer->AddScore(pScore,pMessage,pMessage); +} + +static tConfItemFunc sg_AddScorePlayer_conf("ADD_SCORE_PLAYER",&sg_AddScorePlayer); + +static void sg_SetPlayerTeam(std::istream &s) +{ + tString params; + params.ReadLine( s, true ); + + // parse the line to get the param : Teamname Points Message + int pos = 0; // + tString PlayerStr = tString(""); + PlayerStr = params.ExtractNonBlankSubString(pos); + ePlayerNetID *pPlayer = 0; + int num_matches = -1; + pPlayer = ePlayerNetID::FindPlayerByName(PlayerStr, NULL); + if (!pPlayer) return; + + tString TeamStr = tString(""); + TeamStr = params.ExtractNonBlankSubString(pos); + eTeam *pTeam=NULL; + for (int i = eTeam::teams.Len() - 1; i>=0; --i) { + tString teamName = eTeam::teams(i)->Name(); + if (TeamStr==ePlayerNetID::FilterName(teamName)) { + pTeam = eTeam::teams(i); + break; + } + } + if (!pTeam) return; + + // Force player to a team + pPlayer->SetTeamForce(pTeam); +} + +static tConfItemFunc sg_SetPlayerTeam_conf("SET_PLAYER_TEAM",&sg_SetPlayerTeam); + diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/engine/ePlayer.h 0.2.8-armagetronad-sty+ct/src/engine/ePlayer.h --- 0.2.8-armagetronad-sty/src/engine/ePlayer.h 2009-03-12 23:13:58.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/engine/ePlayer.h 2009-03-13 00:02:54.000000000 -0500 @@ -196,6 +196,20 @@ bool flagOverrideChat; bool flagChatState; + enum TacticalPosition + { + TP_NS = 0, + TP_Goal = 1, + TP_Defense = 2, + TP_Midfield = 3, + TP_Sumo = 4, + TP_Offense = 5, + TP_Attacking = 6, + TP_Conquering = 7 + }; + TacticalPosition tactical_pos; + int closest_zoneid; + int pID; // REAL rubberstatus; tArray lastSaid; @@ -238,6 +252,7 @@ eTeam* NextTeam() const { return nextTeam; } // return the team I will be next round eTeam* CurrentTeam() const { return currentTeam; } // return the team I am in int TeamListID() const { return teamListID; } // return my position in the team + int ListID() const { return listID; } // return my position in the player's list void FindDefaultTeam(); // look for a good default team for us void SetTeamForce(eTeam* team ); // register me in the given team without checks void SetTeam(eTeam* team); // register me in the given team (callable on the server) @@ -313,10 +328,13 @@ static void LogScoreDifferences(); //=0; --i ) + { + eTeam* t = teams(i); + if ( t->IsHuman() ) + { + se_matchScoreTeamWriter << t->score << ePlayerNetID::FilterName( t->Name() ); + se_matchScoreTeamWriter.write(); + } + } +} + + // ******************************************************************************* // * // * LogScoreDifference @@ -527,7 +543,7 @@ { tString ret; int scoreDifference = score - lastScore_; - lastScore_ = IMPOSSIBLY_LOW_SCORE; + //lastScore_ = IMPOSSIBLY_LOW_SCORE; se_roundScoreTeamWriter << scoreDifference << ePlayerNetID::FilterName( Name() ); se_roundScoreTeamWriter.write(); } @@ -1560,6 +1576,40 @@ } } +static void sg_AddScoreTeam(std::istream &s) + +{ + + tString params; + params.ReadLine( s, true ); + + // parse the line to get the param : Teamname Points Message + int pos = 0; // + tString TeamStr = tString(""); + TeamStr = params.ExtractNonBlankSubString(pos); + eTeam *pTeam=NULL; + for (int i = eTeam::teams.Len() - 1; i>=0; --i) { + tString teamName = eTeam::teams(i)->Name(); + if (TeamStr==ePlayerNetID::FilterName(teamName)) { + pTeam = eTeam::teams(i); + break; + } + } + if (!pTeam) return; + tString ScoreStr = tString(""); + ScoreStr = params.ExtractNonBlankSubString(pos); + int pScore = atoi(ScoreStr); + tString pMessage = params.SubStr(pos+1); + pMessage << "\n"; + + // Add score to team pTeam then send a message + pTeam->AddScore(pScore); + sn_ConsoleOut( pMessage ); +} + +static tConfItemFunc sg_AddScoreTeam_conf("ADD_SCORE_TEAM",&sg_AddScoreTeam); + + tColoredString eTeam::GetColoredName(void) const { tColoredString ret; diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/engine/eTeam.h 0.2.8-armagetronad-sty+ct/src/engine/eTeam.h --- 0.2.8-armagetronad-sty/src/engine/eTeam.h 2009-03-12 23:14:00.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/engine/eTeam.h 2009-03-12 23:08:07.000000000 -0500 @@ -137,6 +137,7 @@ static void ResetScoreDifferences(); //= 0 ); + + if (currentPos > Len()) + return tString(""); + + tString toReturn(""); + + // first ignore leading blanks ... + while (currentPos < Len() && isblank((*this)(currentPos))) { + currentPos++; + } + // then store the substring ... + while (currentPos < Len() && !isblank((*this)(currentPos))) { + toReturn << (*this)(currentPos++); + } + pos = currentPos; + return toReturn; +} + + +// ******************************************************************************************* +// * // * RemoveWordRight // * // ******************************************************************************************* diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tools/tString.h 0.2.8-armagetronad-sty+ct/src/tools/tString.h --- 0.2.8-armagetronad-sty/src/tools/tString.h 2009-03-12 23:13:59.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tools/tString.h 2009-03-12 23:08:08.000000000 -0500 @@ -127,6 +127,8 @@ void RemoveSubStr(int start, int length); //! Remove a substring, in-place tString Reverse(); //! Reverses strings + tString ExtractNonBlankSubString( int &pos ) const; //!< Extract non blank char sequence starting at pos + //! Truncate a string tString Truncate( int truncateAt ) const; diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gAIBase.cpp 0.2.8-armagetronad-sty+ct/src/tron/gAIBase.cpp --- 0.2.8-armagetronad-sty/src/tron/gAIBase.cpp 2009-03-12 23:13:59.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gAIBase.cpp 2009-03-12 23:08:08.000000000 -0500 @@ -43,8 +43,6 @@ #include "tRandom.h" #include "tRecorder.h" #include -#include -#include #define AI_REACTION 0 #define AI_EMERGENCY 1 @@ -1087,6 +1085,10 @@ freeSide = 0; log = NULL; + route_.clear(); + lastCoord_ = 0; + targetCurrentFace_ = 0; + // find a good color current_ai=(current_ai+1) % MAXAI_COLOR; @@ -1355,6 +1357,8 @@ case AI_PATH: thisAbility = character->properties[AI_STATE_PATH]; break; + case AI_ROUTE: + break; case AI_SURVIVE: break; }; @@ -1371,6 +1375,8 @@ case AI_PATH: nextAbility = character->properties[AI_STATE_PATH]; break; + case AI_ROUTE: + break; case AI_SURVIVE: break; }; @@ -1424,6 +1430,11 @@ if (nextStateChange > se_GameTime()) { data.thinkAgain = .5f; + // if a route path is define, update the path and return to path state + if (!route_.empty()) + { + UpdateRouteStep(); + } return; } @@ -1705,6 +1713,168 @@ data.thinkAgain *= .7; } +void gAIPlayer::ThinkRoute( ThinkData & data ) +{ + int lr = 0; + REAL mindist = 10; + + eCoord dir = Object()->Direction(); + // REAL fs=front.distance; + REAL ls=data.left.distance; + REAL rs=data.right.distance; + + eCoord tDir; + + if ( !targetCurrentFace_ ) + { +#ifdef DEBUG + con << "Path: out 1 :( ...\n"; +#endif + SwitchToState(AI_SURVIVE, 1); + EmergencySurvive( data ); + + data.thinkAgain = 4; + return; + } + else + { + tDir = route_[lastCoord_] - Object()->Position(); + + // check closest enemy ... + eCoord enemypos=eCoord(1000,1000); + + const tList& gameObjects = Object()->Grid()->GameObjects(); + gCycle *secondbest = NULL; + + // find the closest enemy + for (int i=gameObjects.Len()-1;i>=0;i--){ + gCycle *other=dynamic_cast(gameObjects(i)); + + if (other && other->Team()!=Object()->Team() && + !IsTrapped(other, Object())){ + // then, enemy is realy an enemy + eCoord otherpos=other->Position()-Object()->Position(); + if (otherpos.NormSquared()Position(),otherpos); + p.detect(REAL(.98)); + secondbest = dynamic_cast(other); + if (p.hit>=.98){ + enemypos = otherpos; + target = secondbest; + } + } + } + } + + if (!target) + target = secondbest; + + if (target && (enemypos.NormSquared()<25)) + SwitchToState(AI_CLOSECOMBAT, 2); + } + + // find a new path if the one we got is outdated: + if (lastPath < se_GameTime() - 10) + if (targetCurrentFace_) + { + Object()->FindCurrentFace(); + eHalfEdge::FindPath(Object()->Position(), Object()->CurrentFace(), + route_[lastCoord_], targetCurrentFace_, + Object(), + path); + lastPath = se_GameTime(); + } + + if (!path.Valid()) + { + data.thinkAgain = 1; + return; + } + + // find the most advanced path point that is in our viewing range: + + for (int z = 10; z>=0; z--) + path.Proceed(); + + bool goon = path.Proceed(); + bool nogood = false; + + do + { + if (goon) + goon = path.GoBack(); + else + goon = true; + + eCoord pos = path.CurrentPosition() + path.CurrentOffset() * 0.1f; + eCoord opos = Object()->Position(); + eCoord odir = pos - opos; + + eCoord intermediate = opos + dir * eCoord::F(odir, dir); + + gSensor p(Object(), opos, intermediate - opos); + p.detect(1.1f); + nogood = (p.hit <= .999999999 || eCoord::F(path.CurrentOffset(), odir) < 0); + + if (!nogood) + { + gSensor p(Object(), intermediate, pos - intermediate); + p.detect(1); + nogood = (p.hit <= .99999999 || eCoord::F(path.CurrentOffset(), odir) < 0); + } + + } + while (goon && nogood); + + if (goon) + { + // now we have found our next goal. Try to get there. + eCoord pos = Object()->Position(); + eCoord target = path.CurrentPosition(); + + // look how far ahead the target is: + REAL ahead = eCoord::F(target - pos, dir) + + eCoord::F(path.CurrentOffset(), dir); + + if ( ahead > 0) + { // it is still before us. just wait a while. + mindist = ahead; + } + else + { // we have passed it. Make a turn towards it. + REAL side = (target - pos) * dir; + + if ( !((side > 0 && ls < 3) || (side < 0 && rs < 3)) + && (fabs(side) > 3 || ahead < -10) ) + { +#ifdef DEBUG + con << "Following path...\n"; +#endif + lr += (side > 0 ? 1 : -1); + } + } + } + else // nogood + { +#ifdef DEBUG + con << "Path: out 2 :( ...\n"; +#endif + lastPath -= 1; + SwitchToState(AI_SURVIVE); + } + + EmergencySurvive( data, 1, -lr ); + + REAL d = sqrt(tDir.NormSquared()) * .2f; + if (d < mindist) + mindist = d; + + data.thinkAgain = mindist / Object()->Speed(); + if (data.thinkAgain > .4) + data.thinkAgain *= .7; +} + void gAIPlayer::ThinkCloseCombat( ThinkData & data ) { @@ -1721,17 +1891,36 @@ // REAL ls=left.hit; // REAL rs=right.hit; + if (nextStateChange > se_GameTime()) + { + data.thinkAgain = .5f; + // if a route path is define, update the path and return to path state + if (!route_.empty()) + { + UpdateRouteStep(); + } + return; + } + if ( bool( target ) && !IsTrapped(target, Object()) && nextStateChange < se_GameTime() ) { gSensor p(Object(),Object()->Position(),target->Position() - Object()->Position()); p.detect(REAL(1)); if (p.hit <= .999999) // no free line of sight to victim. Switch to path mode. { + // if a route path is define, update the path and return to path state + if (!route_.empty()) + { + UpdateRouteStep(); + } + else + { SwitchToState(AI_PATH, 5); EmergencySurvive( data ); return; } } + } REAL ed = 0; @@ -1831,11 +2020,19 @@ if (enemyspeed > ourspeed) { + // if a route path is define, update the path and return to path state + if (!route_.empty()) + { + UpdateRouteStep(); + } + else + { SetTraceSide(-side); SwitchToState(AI_TRACE, 10); } } } + } else if (enemypos.y*ourspeed<-enemypos.x*enemyspeed){ /* // good attack position @@ -2508,6 +2705,11 @@ EmergencySurvive( data ); } +void gAIPlayer::EmergencyRoute( ThinkData & data ) +{ + EmergencySurvive( data ); +} + void gAIPlayer::EmergencyCloseCombat( ThinkData & data ) { EmergencySurvive( data ); @@ -2599,6 +2801,9 @@ case AI_PATH: EmergencyPath(data); break; + case AI_ROUTE: + EmergencyRoute(data); + break; case AI_TRACE: EmergencyTrace(data); break; @@ -2783,6 +2988,9 @@ case AI_PATH: ThinkPath(data); break; + case AI_ROUTE: + ThinkRoute(data); + break; case AI_TRACE: ThinkTrace(data); break; @@ -2931,6 +3139,12 @@ if(.1+4*nextthought<1) concentration*=REAL(.1+4*nextthought); } + + // check if a route is defined and if current destination is touched + if(!route_.empty()) { + eCoord tDir = route_[lastCoord_] - Object()->Position(); + if (tDir.Norm()<2) NextRouteStep(); + } } @@ -2970,3 +3184,122 @@ ePlayerNetID::Release(); } */ + +gAIPlayer &gAIPlayer::AddWaypoint(eCoord const &point) { + route_.push_back(point); + return *this; +} + +void gAIPlayer::SetRoute(std::vector route) +{ + if(!route.empty()) { + eGrid *grid = eGrid::CurrentGrid(); + // start clearing the current route and storing the new one + route_.clear(); + for(std::vector::const_iterator iter = route.begin(); iter != route.end(); ++iter) { + AddWaypoint(*iter); + } + eCoord targetPos = route_.front(); + lastCoord_ = 0; + targetCurrentFace_ = grid->FindSurroundingFace(targetPos); + Object()->FindCurrentFace(); + eHalfEdge::FindPath(Object()->Position(), Object()->CurrentFace(), + targetPos, targetCurrentFace_, + Object(), + path); + lastPath = se_GameTime(); + + if (!(path.Valid())) + { + route_.clear(); + targetCurrentFace_ = NULL; + con << "invalid path.\n"; + } else { + SwitchToState(AI_ROUTE, 5); + Think(); + con << "let's go to the first point.\n"; + } + } else + { + route_.clear(); + targetCurrentFace_ = NULL; + } +} + +void gAIPlayer::UpdateRouteStep() +{ + eGrid *grid = eGrid::CurrentGrid(); + // update path + eCoord targetPos = route_[lastCoord_]; + lastCoord_ = 0; + targetCurrentFace_ = grid->FindSurroundingFace(targetPos); + Object()->FindCurrentFace(); + eHalfEdge::FindPath(Object()->Position(), Object()->CurrentFace(), + targetPos, targetCurrentFace_, + Object(), + path); + lastPath = se_GameTime(); + + if (!(path.Valid())) + { + route_.clear(); + targetCurrentFace_ = NULL; + con << "invalid path.\n"; + } else { + SwitchToState(AI_ROUTE, 5); + Think(); + con << "let's go to the next point.\n"; + } +} + +void gAIPlayer::NextRouteStep() +{ + // increment the position in the route ... + eCoord const &lastPos = route_[lastCoord_++]; + if(lastCoord_ >= route_.size()) { + lastCoord_ = 0; + } + eCoord delta = route_[lastCoord_] - lastPos; + REAL dist = delta.Norm(); + if(dist < EPS) { // next point is the same. Stop the route ... + route_.clear(); + targetCurrentFace_ = NULL; + return; + } + // update path + UpdateRouteStep(); +} + +static void sg_SetAIRoute(std::istream &s) +{ + tString params; + params.ReadLine( s, true ); + + // parse the line to get the param : object_id, positions ... + int pos = 0; // + const tString object_id_str = params.ExtractNonBlankSubString(pos); + std::vector route; + tString x,y; + while(true) { + x = params.ExtractNonBlankSubString(pos); + if(x == "") break; + y = params.ExtractNonBlankSubString(pos); + route.push_back(eCoord(atof(x), atof(y))); + } + ePlayerNetID *p = 0; + p = ePlayerNetID::FindPlayerByName(object_id_str); + + // if no player found, or not a IA player, just leave ... + if (!p) return; + gAIPlayer *ai = dynamic_cast(p); + if ((!ai) || (!p->Object())) return; + + tJUST_CONTROLLED_PTR currentFace; // the eFace pos it is currently + + if(!route.empty()) { + ai->SetRoute(route); + } +} + +static tConfItemFunc sg_SetAIRoute_conf("SET_AI_POSITION",&sg_SetAIRoute); + diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gAIBase.h 0.2.8-armagetronad-sty+ct/src/tron/gAIBase.h --- 0.2.8-armagetronad-sty/src/tron/gAIBase.h 2009-03-12 23:13:57.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gAIBase.h 2009-03-12 23:08:08.000000000 -0500 @@ -39,6 +39,8 @@ #include "tRandom.h" #include "nObserver.h" +#include + class gSensor; class gAISensor; class gAILog; @@ -48,7 +50,8 @@ { AI_SURVIVE = 0, // just try to stay alive AI_TRACE, // trace a wall AI_PATH, // follow a path to a target - AI_CLOSECOMBAT // try to frag a nearby opponent + AI_CLOSECOMBAT, // try to frag a nearby opponent + AI_ROUTE // follow a route (a set of coord) } gAI_STATE; @@ -67,6 +70,11 @@ ePath path; // last found path to the victim REAL lastPath; // when was the last time we did a pathsearch? + // for route mode: + std::vector route_; + unsigned int lastCoord_; + tJUST_CONTROLLED_PTR targetCurrentFace_; + // for trace mode: int traceSide; REAL lastChangeAttempt; @@ -95,11 +103,11 @@ // set trace side: void SetTraceSide(int side); +public: // state change: void SwitchToState(gAI_STATE nextState, REAL minTime=10); // data structure common to thinking functions -public: struct ThinkDataBase { int turn; // direction to turn to @@ -129,12 +137,14 @@ virtual void ThinkTrace( ThinkData & data ); virtual void ThinkPath( ThinkData & data ); virtual void ThinkCloseCombat( ThinkData & data ); + virtual void ThinkRoute( ThinkData & data ); // emergency functions: virtual bool EmergencySurvive( ThinkData & data, int enemyEvade = -1, int preferedSide = 0); virtual void EmergencyTrace( ThinkData & data ); virtual void EmergencyPath( ThinkData & data ); virtual void EmergencyCloseCombat( ThinkData & data ); + virtual void EmergencyRoute( ThinkData & data ); // acting on gathered data virtual void ActOnData( ThinkData & data ); @@ -142,6 +152,11 @@ public: gAICharacter* Character() const {return character;} + gAIPlayer & AddWaypoint(eCoord const &point); + void SetRoute(std::vector route); + void UpdateRouteStep(); + void NextRouteStep(); + // virtual void AddRef(); // virtual void Release(); diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gArena.cpp 0.2.8-armagetronad-sty+ct/src/tron/gArena.cpp --- 0.2.8-armagetronad-sty/src/tron/gArena.cpp 2009-03-12 23:13:58.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gArena.cpp 2009-03-13 00:02:01.000000000 -0500 @@ -47,9 +47,8 @@ { } -void gArena::NewSpawnPoint(const eCoord &loc,const eCoord &dir){ - gSpawnPoint *s=tNEW(gSpawnPoint) (loc,dir); - spawnPoints.Add(s,s->id); +void gArena::NewSpawnPoint(gSpawnPoint *sp){ + spawnPoints.Add(sp,sp->id); } diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gArena.h 0.2.8-armagetronad-sty+ct/src/tron/gArena.h --- 0.2.8-armagetronad-sty/src/tron/gArena.h 2009-03-12 23:13:57.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gArena.h 2009-03-13 00:02:01.000000000 -0500 @@ -42,7 +42,7 @@ friend class gParser; public: - void NewSpawnPoint(const eCoord &loc,const eCoord &dir); + void NewSpawnPoint(gSpawnPoint *sp); gArena(); virtual ~gArena(); diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gCycle.cpp 0.2.8-armagetronad-sty+ct/src/tron/gCycle.cpp --- 0.2.8-armagetronad-sty/src/tron/gCycle.cpp 2009-03-12 23:14:35.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gCycle.cpp 2009-03-13 00:02:55.000000000 -0500 @@ -43,6 +43,7 @@ #include "eFloor.h" #include "gSparks.h" #include "gExplosion.h" +#include "gSvgOutput.h" #include "gWall.h" #include "nKrawall.h" #include "gAIBase.h" @@ -3276,9 +3277,9 @@ } } -static eLadderLogWriter sg_deathFragWriter("DEATH_FRAG", true); -static eLadderLogWriter sg_deathSuicideWriter("DEATH_SUICIDE", true); -static eLadderLogWriter sg_deathTeamkillWriter("DEATH_TEAMKILL", true); +eLadderLogWriter sg_deathFragWriter("DEATH_FRAG", true); +eLadderLogWriter sg_deathSuicideWriter("DEATH_SUICIDE", true); +eLadderLogWriter sg_deathTeamkillWriter("DEATH_TEAMKILL", true); void gCycle::KillAt( const eCoord& deathPos){ // don't kill invulnerable cycles @@ -5102,8 +5103,38 @@ } #endif +//! draws it in a svg file +void gCycle::DrawSvg(std::ofstream &f) { + double alpha = 1; + if(!Alive()) { + alpha -= 2 * (se_GameTime() - DeathTime()); + if(alpha <= 0) return; + } + eCoord p = PredictPosition(), dir = Direction(); + float a = Grid()->GetWindingAngle(WindingNumber())*180/M_PI; + f << " \n"; + if (Player()) { + eCoord v = p - eCoord(SvgOutput::cx,SvgOutput::cy); + v.Normalize(); + float tx = p.x + v.x * 2; + float ty = p.y + v.y * 3; - + f << " "; + tString const &n = Player()->GetName(); + for( char *c = &n(0); *c != 0; ++c ) + { + unsigned char u = *c; + if ( u=='<' ) f << "<"; + else if ( u=='>' ) f << ">"; + else if( u < ' ' ); + else if( u > '~' && u < 0xa0 ); + else f << *c; + } + f << "\n"; + } +} // cycle network routines: @@ -6544,3 +6574,61 @@ } } +static void sg_RespawnPlayer(std::istream &s) +{ + eGrid *grid = eGrid::CurrentGrid(); + if(!grid) { + con << "Must be called while a grid exists!\n"; + return; + } + + tString params; + params.ReadLine( s, true ); + + // first parse the line to get the params : + int pos = 0; // + tString PlayerName = ePlayerNetID::FilterName(params.ExtractNonBlankSubString(pos)); + ePlayerNetID *pPlayer = 0; + pPlayer = ePlayerNetID::FindPlayerByName(PlayerName, NULL); + if(!pPlayer) { + return; + } + const tString message_str = params.ExtractNonBlankSubString(pos); + int message = atoi(message_str); + const tString x_str = params.ExtractNonBlankSubString(pos); + REAL x = atof(x_str); + const tString y_str = params.ExtractNonBlankSubString(pos); + REAL y = atof(y_str); + const tString dirx_str = params.ExtractNonBlankSubString(pos); + REAL dirx = atof(dirx_str); + const tString diry_str = params.ExtractNonBlankSubString(pos); + REAL diry = atof(diry_str); + // prepare coord and direction ... + eCoord ppos, pdir; + if (((x_str == "") && (y_str == "")) || ((dirx ==0) && (diry == 0))) { + return; + } + ppos = eCoord(x,y); + pdir = eCoord(dirx,diry); + + // let's respawn now ... + eGameObject *pGameObject = pPlayer->Object(); + if ((!pGameObject) || + (!(pGameObject->Alive()) )) + { + gCycle *pCycle = new gCycle(grid, ppos, pdir, pPlayer); + pPlayer->ControlObject(pCycle); + + if (message) { + tColoredString playerName; + playerName << *pPlayer << tColoredString::ColorString(1,1,1); + + // send a console message to the player + sn_CenterMessage(tOutput("$player_respawn_center_message"), pPlayer->Owner()); + } + } +} + +static tConfItemFunc sg_RespawnPlayer_conf("RESPAWN_PLAYER",&sg_RespawnPlayer); + + diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gCycle.h 0.2.8-armagetronad-sty+ct/src/tron/gCycle.h --- 0.2.8-armagetronad-sty/src/tron/gCycle.h 2009-03-12 23:13:57.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gCycle.h 2009-03-13 00:02:55.000000000 -0500 @@ -330,6 +330,9 @@ int viewer,REAL rvol,REAL lvol); #endif + //! draws it in a svg file + virtual void DrawSvg(std::ofstream &f); + virtual eCoord CamPos() const; virtual eCoord PredictPosition() const; virtual eCoord CamTop() const; diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gCycleMovement.h 0.2.8-armagetronad-sty+ct/src/tron/gCycleMovement.h --- 0.2.8-armagetronad-sty/src/tron/gCycleMovement.h 2009-03-12 23:13:56.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gCycleMovement.h 2009-03-13 00:02:55.000000000 -0500 @@ -92,6 +92,7 @@ virtual REAL Speed () const ; //!< returns the current speed virtual bool Alive () const ; //!< returns whether the cycle is still alive virtual bool Vulnerable () const ; //!< returns whether the cycle can be killed + REAL GetAcceleration(void) const { return acceleration; }; //!< Gets the cycle's acceleration bool CanMakeTurn (int direction) const ; //!< returns whether a turn is currently possible bool CanMakeTurn ( REAL time, int direction ) const ; //!< returns whether a turn is possible at the given time @@ -268,12 +269,12 @@ inline gCycleMovement const & GetLastTurnPos( eCoord & lastTurnPos ) const; //!< Gets the location of the last turn inline REAL const & GetLastTurnTime( void ) const; //!< Gets the time of the last turn inline gCycleMovement const & GetLastTurnTime( REAL & lastTurnTime ) const; //!< Gets the time of the last turn + inline gCycleMovement & SetRubber( REAL rubber ); //!< Sets the amount rubber used up by the cycle protected: inline gCycleMovement & SetLastTurnPos( eCoord const & lastTurnPos ); //!< Sets the location of the last turn inline gCycleMovement & SetLastTurnTime( REAL const & lastTurnTime ); //!< Sets the time of the last turn private: inline gCycleMovement & SetDistance( REAL distance ); //!< Sets the distance traveled so far - inline gCycleMovement & SetRubber( REAL rubber ); //!< Sets the amount rubber used up by the cycle inline gCycleMovement & SetTurns( unsigned short turns ); //!< Sets the number of turns taken so far inline gCycleMovement & SetBraking( unsigned short braking ); //!< Sets flag indicating status of brakes ( on/off ) inline gCycleMovement & SetBrakingReservoir( REAL brakingReservoir ); //!< Sets the reservoir for braking. 1 means full, 0 is empty diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gExplosion.cpp 0.2.8-armagetronad-sty+ct/src/tron/gExplosion.cpp --- 0.2.8-armagetronad-sty/src/tron/gExplosion.cpp 2009-03-12 23:13:57.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gExplosion.cpp 2009-03-12 23:08:08.000000000 -0500 @@ -31,15 +31,17 @@ #include "tInitExit.h" #include "gWall.h" #include "gCycle.h" +#include "gSvgOutput.h" #include "eGrid.h" #include "tRandom.h" #include "tMath.h" +#include "nConfig.h" static eWavData explode("moviesounds/dietron.wav","sound/expl.wav"); static tList< gExplosion > sg_Explosions; -static void clamp01(REAL &c) +void clamp01(REAL &c) { if (!finite(c)) c = 0.5; @@ -135,7 +137,7 @@ } */ -gExplosion::gExplosion(eGrid *grid, const eCoord &pos,REAL time, gRealColor& color, gCycle * owner ) +gExplosion::gExplosion(eGrid *grid, const eCoord &pos,REAL time, gRealColor& color, gCycle * owner, REAL radius ) :eReferencableGameObject(grid, pos, eCoord(0,0), NULL, true), sound(explode), createTime(time), @@ -149,6 +151,7 @@ explosion_r = color.r; explosion_g = color.g; explosion_b = color.b; + radius_ = radius; sound.Reset(); sg_Explosions.Add( this, listID ); z=0; @@ -188,7 +191,7 @@ { /* s_explosionCoord = pos; - s_explosionRadius = gCycle::ExplosionRadius()*1.5f; + s_explosionRadius = ((radius_==0)?gCycle::ExplosionRadius():radius_)*1.5f; grid->ProcessWallsInRange( &S_Sync, s_explosionCoord, @@ -215,7 +218,7 @@ s_explosionCoord = pos; REAL factor = expansion / REAL( expansionSteps ); - s_explosionRadius = gCycle::ExplosionRadius() * sqrt(factor); + s_explosionRadius = ((radius_==0)?gCycle::ExplosionRadius():radius_) * sqrt(factor); s_explosionTime = currentTime; s_holer = this; @@ -415,3 +418,65 @@ eReferencableGameObject::OnRemoveFromGame(); } +//! draws it in a svg file +void gExplosion::DrawSvg(std::ofstream &f) { + REAL a1=(lastTime-createTime)+.01f;//+.2; + REAL e=a1-1; + + if (e<0) e=0; + + REAL fade=(2-a1); + if (fade<0) fade=0; + if (fade>1) fade=1; + + a1*=100; + e*=100; + + f << "\n\n"; +} + +extern REAL se_GameTime(); + +static void sg_SetExplosion(std::istream &s) +{ + eGrid *grid = eGrid::CurrentGrid(); + if(!grid) { + con << "Must be called while a grid exists!\n"; + return; + } + + tString params; + params.ReadLine( s, true ); + + // parse the line to get the param : x y radius + int pos = 0; // + const tString x = params.ExtractNonBlankSubString(pos); + const tString y = params.ExtractNonBlankSubString(pos); + eCoord epos = eCoord(atof(x), atof(y)); + const tString radius_str = params.ExtractNonBlankSubString(pos); + int radius = atoi(radius_str); + if (radius<=0) return; + + // extra parameters for explosion init ... + gRealColor ecolor; + ecolor.r = 1.0; + ecolor.g = 1.0; + ecolor.b = 1.0; + REAL time = se_GameTime(); + + gExplosion *explosion = NULL; + explosion = tNEW( gExplosion( grid, epos, time, ecolor, NULL, radius) ); +} + +static tConfItemFunc sg_SetExplosion_conf("SPAWN_EXPLOSION",&sg_SetExplosion); + diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gExplosion.h 0.2.8-armagetronad-sty+ct/src/tron/gExplosion.h --- 0.2.8-armagetronad-sty/src/tron/gExplosion.h 2009-03-12 23:14:00.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gExplosion.h 2009-03-12 23:08:08.000000000 -0500 @@ -38,7 +38,7 @@ class gExplosion: virtual public eReferencableGameObject { // Boom! public: - gExplosion(eGrid *grid, const eCoord &pos,REAL time, gRealColor& color, gCycle * owner ); + gExplosion(eGrid *grid, const eCoord &pos,REAL time, gRealColor& color, gCycle * owner, REAL radius = 0 ); virtual ~gExplosion(); virtual bool Timestep(REAL currentTime); @@ -55,6 +55,9 @@ int viewer,REAL rvol,REAL lvol); #endif + //! draws it in a svg file + virtual void DrawSvg(std::ofstream &f); + bool AccountForHole(); // will return true exactly once per explosion; to be used to make the holing score only count once. static void OnNewWall( eWall* w ); // blow holes into a new wall @@ -73,6 +76,7 @@ gParticles *theExplosion; REAL createTime; + REAL radius_; // gRealColor color_; REAL explosion_r; diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gGame.cpp 0.2.8-armagetronad-sty+ct/src/tron/gGame.cpp --- 0.2.8-armagetronad-sty/src/tron/gGame.cpp 2009-03-12 23:14:35.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gGame.cpp 2009-03-13 00:02:55.000000000 -0500 @@ -67,6 +67,7 @@ #include "gWinZone.h" #include "eVoter.h" #include "tRecorder.h" +#include "gSvgOutput.h" #include "gParser.h" #include "tResourceManager.h" @@ -125,6 +126,16 @@ static REAL sg_waitForExternalScriptTimeout = 3; static tSettingItem sg_waitForExternalScriptTimeoutConf( "WAIT_FOR_EXTERNAL_SCRIPT_TIMEOUT", sg_waitForExternalScriptTimeout ); +static REAL sg_svgOutputFreq = -1; +static tSettingItem sg_svgOutputFreqConf( "SVG_OUTPUT_TIMING", sg_svgOutputFreq ); + +static bool sg_svgOutputScoreDifferences = false; +static tSettingItem sg_svgOutputScoreDifferencesConf( "SVG_OUTPUT_LOG_SCORE_DIFFERENCES", sg_svgOutputScoreDifferences ); + +// time in sec before player positioning starts +static REAL sg_playerPositioningStartTime = 5.0; +static tSettingItem sg_playerPositioningStartTimeConf( "PLAYER_POSITIONING_START_TIME", sg_playerPositioningStartTime ); + static nSettingItemWatched conf_mapfile("MAP_FILE",mapfile, nConfItemVersionWatcher::Group_Breaking, 8 ); // bool globalingame=false; @@ -186,7 +197,7 @@ #define AUTO_AI_WIN 3 #define AUTO_AI_LOSE 1 -gGameSettings::gGameSettings(int a_scoreWin, +gGameSettings::gGameSettings(int a_scoreWin, int a_scoreDiffWin, int a_limitTime, int a_limitRounds, int a_limitScore, int a_numAIs, int a_minPlayers, int a_AI_IQ, bool a_autoNum, bool a_autoIQ, @@ -195,7 +206,7 @@ int a_minTeams, REAL a_winZoneMinRoundTime, REAL a_winZoneMinLastDeath ) - :scoreWin(a_scoreWin), + :scoreWin(a_scoreWin), scoreDiffWin(a_scoreDiffWin), limitTime(a_limitTime), limitRounds(a_limitRounds), limitScore(a_limitScore), numAIs(a_numAIs), minPlayers(a_minPlayers), AI_IQ(a_AI_IQ), autoNum(a_autoNum), autoIQ(a_autoIQ), @@ -513,7 +524,7 @@ GameSettings.Enter(); } -gGameSettings singlePlayer(10, +gGameSettings singlePlayer(10, 1, 30, 10, 100000, 1, 0, 30, true, true, @@ -521,7 +532,7 @@ gDUEL, gFINISH_IMMEDIATELY, 1, 100000, 1000000); -gGameSettings multiPlayer(10, +gGameSettings multiPlayer(10, 1, 30, 10, 100, 0, 4, 100, false, false, @@ -531,9 +542,8 @@ gGameSettings* sg_currentSettings = &singlePlayer; - - static tSettingItem mp_sw("SCORE_WIN" ,multiPlayer.scoreWin); +static tSettingItem mp_sd("SCORE_DIFF_WIN" ,multiPlayer.scoreDiffWin); static tSettingItem mp_lt("LIMIT_TIME" ,multiPlayer.limitTime); static tSettingItem mp_lr("LIMIT_ROUNDS",multiPlayer.limitRounds); static tSettingItem mp_ls("LIMIT_SCORE" ,multiPlayer.limitScore); @@ -567,6 +577,7 @@ static tConfItem mp_er ("EXPLOSION_RADIUS" , multiPlayer.explosionRadius ); static tSettingItem sp_sw("SP_SCORE_WIN" ,singlePlayer.scoreWin); +static tSettingItem sp_sd("SP_SCORE_DIFF_WIN" ,singlePlayer.scoreDiffWin); static tSettingItem sp_lt("SP_LIMIT_TIME" ,singlePlayer.limitTime); static tSettingItem sp_lr("SP_LIMIT_ROUNDS",singlePlayer.limitRounds); static tSettingItem sp_ls("SP_LIMIT_SCORE" ,singlePlayer.limitScore); @@ -618,6 +629,8 @@ static tSettingItem sg_ttm("TALK_TO_MASTER", sg_TalkToMaster); +extern int ladder_highscore_output; + class gHighscoresBase{ int id; static tList highscoreList; @@ -645,7 +658,7 @@ // send the poor guy who just dropped a message ePlayerNetID *p=online(i); - if (p){ + if (p && ladder_highscore_output){ tColoredString name; name << *p << tColoredString::ColorString(1,.5,.5); @@ -902,7 +915,7 @@ ePlayerNetID *p=online(newpos); //con << message; - if (p) + if (p && ladder_highscore_output) sn_ConsoleOut(tString(message),p->Owner()); //Save(); } @@ -981,6 +994,14 @@ static tSettingItem sggti("LADDERLOG_GAME_TIME_INTERVAL", sg_gameTimeInterval); +static float sg_tacticalPositionInterval=5; +static tSettingItem sgtpi("TACTICAL_POSITION_INTERVAL", + sg_tacticalPositionInterval); + +static float sg_gridPosInterval=1; +static tSettingItem sggpi("GRID_POSITION_INTERVAL", + sg_gridPosInterval); + class ladder: public highscores{ public: @@ -1056,7 +1077,7 @@ ePlayerNetID *p=online(newpos); // con << message; - if (p){ + if (p && ladder_highscore_output){ sn_ConsoleOut(tString(message),p->Owner()); } @@ -1236,6 +1257,8 @@ grid->Clear(); } +extern std::vector se_unsplittedRimWalls; + void exit_game_objects(eGrid *grid){ sr_con.fullscreen=true; @@ -1258,6 +1281,8 @@ gNetPlayerWall::Clear(); + se_unsplittedRimWalls.clear(); + exit_game_grid(grid); } @@ -1451,6 +1476,9 @@ static REAL g[MAX_PLAYERS]={.2,1,.2,1}; static REAL b[MAX_PLAYERS]={.2,.2,1,.2}; */ + // 0 loser first 1 winners first +static int sg_spawnWinnersFirst = 0; +static tSettingItem sg_spawnWinnersFirstConf( "SPAWN_WINNERS_FIRST", sg_spawnWinnersFirst); if (sn_GetNetState()!=nCLIENT) { @@ -1463,8 +1491,13 @@ for(int t=eTeam::teams.Len()-1;t>=0;t--) { - eTeam *team = eTeam::teams(t); - + int z; + if (sg_spawnWinnersFirst == 1){ + z =(-1*t)+ eTeam::teams.Len()-1; + }else{ + z =t; + } + eTeam *team = eTeam::teams(z); // reset team color of fresh teams if ( team->RoundsPlayed() == 0 ) @@ -1488,7 +1522,7 @@ // the next spawn point is the last of this group. Skip it if // either only two players are left (and the one would need to play alone) // or we can fill the remaining groups well with one player short. - if ( t == 2 || ( ( t % ( sg_spawnPointGroupSize - 1 ) ) == 0 && t < ( sg_spawnPointGroupSize - 1 ) * ( sg_spawnPointGroupSize - 1 ) ) ) + if ( z == 2 || ( ( z % ( sg_spawnPointGroupSize - 1 ) ) == 0 && z < ( sg_spawnPointGroupSize - 1 ) * ( sg_spawnPointGroupSize - 1 ) ) ) { eCoord pos, dir; spawn->Spawn( pos, dir ); @@ -3079,6 +3113,9 @@ static eLadderLogWriter sg_newRoundWriter("NEW_ROUND", true); static eLadderLogWriter sg_newMatchWriter("NEW_MATCH", true); static eLadderLogWriter sg_waitForExternalScriptWriter("WAIT_FOR_EXTERNAL_SCRIPT", true); +static eLadderLogWriter sg_nextRoundWriter("NEXT_ROUND", false); +static eLadderLogWriter sg_roundCommencingWriter("ROUND_COMMENCING", false); +static SvgOutput sg_svgOutput; void gGame::StateUpdate(){ @@ -3139,6 +3176,7 @@ // log scores before players get renamed ePlayerNetID::LogScoreDifferences(); ePlayerNetID::UpdateSuspensions(); + sg_newRoundWriter << sg_GetCurrentTime("%Y-%m-%d %H:%M:%S"); sg_newRoundWriter.write(); // kick spectators @@ -3199,6 +3237,8 @@ nNetObject::ClearAllDeleted(); + if (sg_svgOutputFreq >= 0) sg_svgOutput.Create(); + SetState(GS_CREATE_OBJECTS,GS_CAMERA); break; case GS_CREATE_OBJECTS: @@ -3324,6 +3364,8 @@ if (strlen(sg_roundConsoleMessage) > 2) sn_ConsoleOut(sg_roundConsoleMessage + "\n"); + sg_nextRoundWriter << rounds+1 << sg_currentSettings->limitRounds << mapfile << sg_roundCenterMessage; + sg_nextRoundWriter.write(); } else mess << "$gamestate_newround_goldengoal"; @@ -3351,6 +3393,14 @@ Analysis(0); + // log scores before players get renamed + //ePlayerNetID::LogScoreDifferences(); + + //ePlayerNetID::RankingLadderLog(); + + sg_roundCommencingWriter << rounds+1 << sg_currentSettings->limitRounds; + sg_roundCommencingWriter.write(); + // wait for external script to end its work if needed REAL timeout = tSysTimeFloat() + sg_waitForExternalScriptTimeout; if ( sg_waitForExternalScript ) @@ -3926,7 +3976,9 @@ || ( eTeam::teams(0)->Score() > eTeam::teams(1)->Score() && sg_EnemyExists(0))){ // only then we can have a true winner: - if (eTeam::teams(0)->Score() >= sg_currentSettings->limitScore || // the score limit must be hit + if ( + ( eTeam::teams(0)->Score() >= sg_currentSettings->limitScore + && eTeam::teams.Len()>1 && eTeam::teams(0)->Score() >= eTeam::teams(1)->Score() + sg_currentSettings->scoreDiffWin ) || // the score limit must be hit rounds + winnerExtraRound >= sg_currentSettings->limitRounds || // or the round limit tSysTimeFloat()>=startTime+sg_currentSettings->limitTime*60 || // or the time limit (active <= 1 && eTeam::teams.Len() > 1) // or all but one players must have disconnected. @@ -3978,6 +4030,8 @@ message << "$gamestate_champ_default"; } + ePlayerNetID::LogMatchScores(); + se_SaveToScoreFile(message); se_SaveToScoreFile("$gamestate_champ_finalscores"); se_SaveToScoreFile(eTeam::Ranking( -1, false )); @@ -4060,9 +4114,10 @@ } void gGame::StartNewMatchNow(){ - if ( rounds != 0 ) + if ( rounds != 0 ) { + sg_newMatchWriter << sg_GetCurrentTime("%Y-%m-%d %H:%M:%S"); sg_newMatchWriter.write(); - + } rounds=0; warning=0; startTime=tSysTimeFloat()-10; @@ -4161,6 +4216,7 @@ static int lastcountdown=0; int cd=int(floor(-time))+1; if (cd>=0 && cdIsSynced() ){ + if (cd==1) ePlayerNetID::GridPosLadderLog(); lastcountdown=cd; tString s; s << cd; @@ -4278,13 +4334,41 @@ synced_ = true; } + { static float lastTime = 1e42; - if(sg_gameTimeInterval >= 0 && (gtime >= lastTime + sg_gameTimeInterval || gtime < lastTime)) { - sg_gameTimeWriter << gtime; + double time; + if (sg_gameTimeInterval >0){ + time = (floor(gtime/sg_gameTimeInterval))*sg_gameTimeInterval; + } else{ + time = gtime; + } + sg_gameTimeWriter << time; sg_gameTimeWriter.write(); + lastTime = time; + } + } { + static float lastTime = 1e42; + if((gtime > 0) && (sg_tacticalPositionInterval >= 0) && (gtime >= lastTime + sg_tacticalPositionInterval || gtime < lastTime)) { + ePlayerNetID::TacticalPositioning(); lastTime = gtime; } + } { + static float lastTime = 1e42; + if((sg_gridPosInterval >= 0) && (gtime > sg_gridPosInterval) && (gtime >= lastTime + sg_gridPosInterval + 1 || gtime < lastTime)) { + ePlayerNetID::GridPosLadderLog(); + lastTime = gtime; + } + } { + static float lastTime = 1e42; + if(sg_svgOutputFreq >= 0 && (gtime >= lastTime + sg_svgOutputFreq || gtime < lastTime)) { + sg_svgOutput.Create(); + if(sg_svgOutputScoreDifferences) { + ePlayerNetID::LogScoreDifferences(); + } + lastTime = gtime; + } + } if (state==GS_PLAY){ if (gtime<0 && gtime>-PREPARE_TIME+.3) diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gGame.h 0.2.8-armagetronad-sty+ct/src/tron/gGame.h --- 0.2.8-armagetronad-sty/src/tron/gGame.h 2009-03-12 23:13:58.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gGame.h 2009-03-12 23:08:08.000000000 -0500 @@ -132,6 +132,7 @@ { public: int scoreWin; // score you get when you win a round + int scoreDiffWin; // score must be over scorewin by this amount int limitTime; // match time limit int limitRounds; // match round limit @@ -166,7 +167,7 @@ REAL wallsLength; // the maximum total length of the walls REAL explosionRadius; // the radius of the holes blewn in by an explosion - gGameSettings(int a_scoreWin, + gGameSettings(int a_scoreWin, int a_scoreDiffWin, int a_limitTime, int a_limitRounds, int a_limitScore, int a_numAIs, int a_minPlayers, int a_AI_IQ, bool a_autoNum, bool a_autoIQ, diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gParser.cpp 0.2.8-armagetronad-sty+ct/src/tron/gParser.cpp --- 0.2.8-armagetronad-sty/src/tron/gParser.cpp 2009-03-12 23:13:57.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gParser.cpp 2009-03-13 00:02:55.000000000 -0500 @@ -12,11 +12,13 @@ #include #include "eCoord.h" +#include "eAdvWall.h" #include "eGrid.h" #include "eTess2.h" #include "gWall.h" #include "gArena.h" #include "gWinZone.h" +#include "gSpawn.h" #include "tMemManager.h" #include "tResourceManager.h" #include "tRecorder.h" @@ -444,7 +446,30 @@ y = myxmlGetPropFloat(cur, "y"); myxmlGetDirection(cur, xdir, ydir); - theArena->NewSpawnPoint(eCoord(x, y), eCoord(xdir, ydir)); + eCoord rootPos = eCoord(x, y); + eCoord rootDir = eCoord(xdir, ydir); + gSpawnPoint *sp = tNEW(gSpawnPoint)(rootPos, rootDir); + for(xmlNodePtr child = cur->xmlChildrenNode; child; child = child->next) { + if(!isElement(child->name, (const xmlChar *)"Spawn", keyword)) { + continue; + } + + x = myxmlGetPropFloat(child, "x"); + y = myxmlGetPropFloat(child, "y"); + myxmlGetDirection(child, xdir, ydir); + + eCoord pos = eCoord(x, y); + eCoord dir = eCoord(xdir, ydir); + + if(xdir == 0 && ydir == 0) { + // no direction given (at least no sensible one) + // assume the same direction as the root spawn point + dir = rootDir; + } + + sp->AddSubSpawn(pos, dir); + } + theArena->NewSpawnPoint(sp); endElementAlternative(grid, cur, keyword); } @@ -513,6 +538,17 @@ else if (!xmlStrcmp(xmlGetProp(cur, (const xmlChar *)"effect"), (const xmlChar *)"ball")) { zone = tNEW( gBallZoneHack) ( grid, eCoord(x*sizeMultiplier,y*sizeMultiplier) ); } + else if (!xmlStrcmp(xmlGetProp(cur, (const xmlChar *)"effect"), (const xmlChar *)"target")) { + zone = tNEW( gTargetZoneHack) ( grid, eCoord(x*sizeMultiplier,y*sizeMultiplier) ); + } + else if (!xmlStrcmp(xmlGetProp(cur, (const xmlChar *) "effect"), (const xmlChar *)"rubber")) { + REAL rubberVal = myxmlGetPropFloat(cur, "rubberVal"); + if (rubberVal != 0.0 ){ + gRubberZoneHack *rZone= tNEW(gRubberZoneHack(grid, eCoord(x*sizeMultiplier,y*sizeMultiplier), false )); + rZone->SetRubber(rubberVal); + zone = rZone; + } + } // leaving zone undeleted is no memory leak here, the gid takes control of it if ( zone ) @@ -572,6 +608,8 @@ endElementAlternative(grid, cur, keyword); } +extern std::vector se_unsplittedRimWalls; + void gParser::parseWall(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword) { @@ -590,10 +628,15 @@ x = myxmlGetPropFloat(cur, "x"); y = myxmlGetPropFloat(cur, "y"); - if (R == NULL) + if (R == NULL) { R = grid->Insert(eCoord(x, y) * sizeMultiplier); - else + ePolyLine P('M',eCoord(x, y) * sizeMultiplier); + se_unsplittedRimWalls.push_back(P); + } else { R = this->DrawRim(grid, R, eCoord(x, y) * sizeMultiplier, height); + ePolyLine P('L',eCoord(x, y) * sizeMultiplier); + se_unsplittedRimWalls.push_back(P); + } // TODO-Alt: // if this function returns a point, use it in the wall. Otherwise, ignore what comes out. diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gParser.h 0.2.8-armagetronad-sty+ct/src/tron/gParser.h --- 0.2.8-armagetronad-sty/src/tron/gParser.h 2009-03-12 23:13:59.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gParser.h 2009-03-12 23:08:08.000000000 -0500 @@ -13,6 +13,7 @@ class gGame; class gWallRim; class gXMLCharReturn; +class gSpawnPoint; /* Note to the reader: In the full World idea, the parser should, diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gSpawn.cpp 0.2.8-armagetronad-sty+ct/src/tron/gSpawn.cpp --- 0.2.8-armagetronad-sty/src/tron/gSpawn.cpp 2009-03-12 23:13:58.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gSpawn.cpp 2009-03-13 00:02:06.000000000 -0500 @@ -54,8 +54,17 @@ numberOfUses=0; */ + lastTimeUsed=se_GameTime(); + + if(numberOfUses > 0 && numberOfUses <= subPositions.size()) { + loc = subPositions[numberOfUses - 1] * gArena::SizeMultiplier(); + dir = subDirections[numberOfUses - 1]; + ++numberOfUses; + return; + } + int d,away; - int wrappedNumberOfUses = numberOfUses % sg_spawnWrap; + int wrappedNumberOfUses = (numberOfUses ? numberOfUses- subPositions.size() : 0) % sg_spawnWrap; if (wrappedNumberOfUses%2==1){ d=1; @@ -69,10 +78,7 @@ dir=direction; loc=location * gArena::SizeMultiplier() - dir.Turn(sg_spawnBack,-d*sg_spawnSide) * away * gCycle::SpeedMultiplier(); - - lastTimeUsed=se_GameTime(); numberOfUses++; - } // estimates the danger of spawning here (0: no problem, 10: certain death) @@ -86,4 +92,7 @@ } - +void gSpawnPoint::AddSubSpawn(eCoord const &pos, eCoord const &dir){ + subPositions.push_back(pos); + subDirections.push_back(dir); +} diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gSpawn.h 0.2.8-armagetronad-sty+ct/src/tron/gSpawn.h --- 0.2.8-armagetronad-sty/src/tron/gSpawn.h 2009-03-12 23:13:56.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gSpawn.h 2009-03-13 00:02:02.000000000 -0500 @@ -29,6 +29,7 @@ #define ArmageTron_SPAWN_H #include "eCoord.h" +#include class gSpawnPoint{ friend class gArena; @@ -36,7 +37,10 @@ int id; eCoord location,direction; REAL lastTimeUsed; - int numberOfUses; + unsigned numberOfUses; + + std::vector subPositions; + std::vector subDirections; public: gSpawnPoint(const eCoord &loc,const eCoord &dir); @@ -45,6 +49,8 @@ //enters valid spawn eCoordinates and direction in loc and dir void Spawn(eCoord &loc,eCoord &dir); + void AddSubSpawn(eCoord const &loc, eCoord const &dir); + // estimates the danger of spawning here (0: no problem, 10: certain death) REAL Danger(); Only in 0.2.8-armagetronad-sty+ct/src/tron: gSvgOutput.cpp Only in 0.2.8-armagetronad-sty+ct/src/tron: gSvgOutput.h diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gWall.h 0.2.8-armagetronad-sty+ct/src/tron/gWall.h --- 0.2.8-armagetronad-sty/src/tron/gWall.h 2009-03-12 23:13:59.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gWall.h 2009-03-12 23:08:08.000000000 -0500 @@ -31,6 +31,7 @@ #include "eAdvWall.h" #include "nNetObject.h" +#include "gExplosion.h" #include "rDisplayList.h" //#include "nObserver.h" class gExplosion; @@ -187,6 +188,9 @@ //eCoord Vec(){return w->Vec();} eCoord Vec(); //!< returns the vector from the beginning to the end of the wall + + tArray &Coords() { return coords_; } + protected: virtual ~gNetPlayerWall(); void ReleaseData(); // release all references diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gWinZone.cpp 0.2.8-armagetronad-sty+ct/src/tron/gWinZone.cpp --- 0.2.8-armagetronad-sty/src/tron/gWinZone.cpp 2009-03-12 23:13:58.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gWinZone.cpp 2009-03-13 00:13:15.000000000 -0500 @@ -46,6 +46,7 @@ #include "eTess2.h" #include "eWall.h" #include "gWall.h" +#include "gSvgOutput.h" #include "eSound.h" #include "uInput.h" #include "tMath.h" @@ -69,6 +70,27 @@ static nSettingItem< REAL > sg_expansionSpeedConf( "WIN_ZONE_EXPANSION", sg_expansionSpeed ); static nSettingItem< REAL > sg_initialSizeConf( "WIN_ZONE_INITIAL_SIZE", sg_initialSize ); +static int sg_ballsInteract = 0; +static tSettingItem sg_ballsInteractConf( "BALLS_INTERACT", sg_ballsInteract ); + +static int sg_cycleWallsInteract = 0; +static tSettingItem sg_cycleWallsInteractConf( "BALLS_BOUNCE_ON_CYCLE_WALLS", sg_cycleWallsInteract ); + +static int sg_ballTeamMode = 0; //0=ball score other team, 1=ball score only team owner ... +static tSettingItem sg_ballTeamModeConfig( "BALL_TEAM_MODE", sg_ballTeamMode ); + +static int sg_ballKiller = 0; //1=ball kill other team players ... +static tSettingItem sg_ballKillerConfig( "BALL_KILLS", sg_ballKiller ); + +static REAL sg_ballSpeedDecay = 0; +static tSettingItem sg_ballSpeedDecayConf( "BALL_SPEED_DECAY", sg_ballSpeedDecay ); + +static REAL sg_ballCycleBoost = 0; +static tSettingItem sg_ballCycleBoostConf( "BALL_CYCLE_ACCEL_BOOST", sg_ballCycleBoost ); + +static int sg_ballAutoRespawn = 1; +static tSettingItem sg_ballAutoRespawnConf( "BALL_AUTORESPAWN", sg_ballAutoRespawn ); + static int sg_zoneSegments = 11; static tSettingItem sg_zoneSegmentsConf( "ZONE_SEGMENTS", sg_zoneSegments ); @@ -149,6 +172,60 @@ f.SetOffset( value + f.GetSlope() * ( referenceTime_ - lastTime ) ); } + +// ******************************************************************************* +// * +// * FindFirst / FindNext +// * +// ******************************************************************************* +//! +//! @param name name of the zone or group of zones +//! @param prev_pos value of a previous result +//! +// ******************************************************************************* + +int gZone::FindFirst(tString name) +{ + eGrid *grid = eGrid::CurrentGrid(); + const tList& gameObjects = grid->GameObjects(); + for (int j=gameObjects.Len()-1;j>=0;j--) + { + gZone *zone=dynamic_cast(gameObjects(j)); + // for all active base zone ... + if ( zone ) + { + if (zone->name_ == name) + { + return j; + } + } + } + // if no zone has been found ... + return -1; +} + + +int gZone::FindNext(tString name, int prev_pos) +{ + eGrid *grid = eGrid::CurrentGrid(); + const tList& gameObjects = grid->GameObjects(); + for (int j=prev_pos-1;j>=0;j--) + { + gZone *zone=dynamic_cast(gameObjects(j)); + // for all active base zone ... + if ( zone ) + { + if (zone->name_ == name) + { + return j; + } + } + } + // if no zone has been found ... + return -1; +} + + // ******************************************************************************* // * // * gZone @@ -161,7 +238,7 @@ // ******************************************************************************* gZone::gZone( eGrid * grid, const eCoord & pos, bool dynamicCreation ) - :eNetGameObject( grid, pos, eCoord( 0,0 ), NULL, true ), rotation_(1,0) +:eNetGameObject( grid, pos, eCoord( 0,0 ), NULL, true ), rotation_(1,0), lastCoord_(0), nextUpdate_(-1) { // store creation time referenceTime_ = createTime_ = lastTime = 0; @@ -171,12 +248,14 @@ wallInteract_ = false; wallBouncesLeft_ = 0; targetRadius_ = 0; + lastImpactTime_ = 0; + resizeRequested_ = false; fallSpeed_ = 0; lastSeekTime_ = 0; pOwner_ = NULL; pSeekingCycle_ = NULL; seeking_ = false; //??? change this to a game object, allow seeking any - pLastWall_ = NULL; + name_ = tString(""); color_.r = color_.g = color_.b = 1.0f; @@ -196,8 +275,12 @@ // initialize position functions SetPosition( pos ); + + //wrtl: Ok, this is the result of three hours of debugging, I hope it helps... + eGameObject::pos = pos; } + // ******************************************************************************* // * // * gZone @@ -215,13 +298,15 @@ dynamicCreation_ = false; wallInteract_ = false; wallBouncesLeft_ = 0; + lastImpactTime_ = 0; targetRadius_ = 0; + resizeRequested_ = false; fallSpeed_ = 0; lastSeekTime_ = 0; pOwner_ = NULL; pSeekingCycle_ = NULL; seeking_ = false; - pLastWall_ = NULL; + name_ = tString(""); // read creation time m >> createTime_; @@ -360,23 +450,102 @@ static float sg_zombieZoneSpeed = 10; static tSettingItem conf_zombieZoneSpeed ("ZOMBIE_ZONE_SPEED", sg_zombieZoneSpeed); -static float sg_ballWallMod = 1; -static tSettingItem conf_ballWallMod ("BALL_WALL_MOD", sg_ballWallMod); - static bool s_zoneWallInteractionFound; static eCoord s_zoneWallInteractionCoord; static eCoord s_zoneWallInteractionClosestCoord; static REAL s_zoneWallInteractionRadius; -static eWall *s_zoneWallInteractionWallPtr; +static REAL s_zoneWallInteractionImpactTime; +static eCoord s_zoneWallInteractionZoneVelocity; +static eCoord s_zoneWallInteractionImpactCoord; +static REAL s_zoneWallInteractionZoneDeltaTime; static void S_ZoneWallInteraction(eWall *pWall) { - //Ignore if we hit this wall last - if (pWall == s_zoneWallInteractionWallPtr) + //Ignore player walls for now + gPlayerWall *pPlayerWall = dynamic_cast(pWall); + if (pPlayerWall && !sg_cycleWallsInteract) { return; } + // determine the coord (I) and time (t) of the impact + eCoord V = s_zoneWallInteractionZoneVelocity; + REAL R = s_zoneWallInteractionRadius; + + eCoord XY = pWall->EndPoint(1) - pWall->EndPoint(0); + REAL norm_XY = XY.Norm(); + XY *= (1/norm_XY); + eCoord XP = s_zoneWallInteractionCoord - pWall->EndPoint(0); + + REAL Vn = XY*V; + if (Vn==0) return; // if zone is moving along the wall, no impact ... + REAL d = XY*XP; + + REAL t1 = (R-d)/Vn; + REAL t2 = (-R-d)/Vn; + REAL t = 0; + if ((t1>0) && (t2>0)) return;// can't be, again ... + if (t1>0) t = t2; + else if (t2>0) t = t1; + else if (t1>t2) t = t2; + else t = t1; + + // coordinate of the impact on the wall's line space + REAL i = eCoord::F(XY,XP+V*t); + eCoord I; // position of the impact + if (i>=0 && i<=norm_XY) // there's an impact on the wall + { + I = pWall->EndPoint(0) + XY * i; + } + else // the zone might hit a wall end point, let's check this + { + // select the wall end according to wall's line intersection coord (i) + eCoord P; + if (i<0) P = pWall->EndPoint(0); + else P = pWall->EndPoint(1); + + // get the time of the impact ... + eCoord dp = s_zoneWallInteractionCoord - P; + eCoord dv = s_zoneWallInteractionZoneVelocity; + REAL a = dv.NormSquared(); + if (a0) && (t2>0)) return; + if (t1>0) t = t2; + else if (t2>0) t = t1; + else if (t1>t2) t = t2; + else t = t1; + I = P; + } + } + + // t must be negative and close to 0 to make sence ... + if (t>0 || t<-s_zoneWallInteractionZoneDeltaTime) return; + + // at this point, we have the intersection (I), the time of intersection (t) + // let's check if it is the first impact ... + if (!s_zoneWallInteractionFound || (t(pWall); if (pPlayerWall) @@ -397,23 +566,11 @@ if ( Pos1.x != Pos2.x) alpha = Pos1.x / ( Pos1.x - Pos2.x ); - //don't need this??? -#if 0 - REAL radius = s_zoneWallInteractionRadius * s_zoneWallInteractionRadius - Pos1.y * Pos2.y; - - // wall too far away - if ( radius < 0 ) - return; - -// radius = sqrt( radius ); -#endif - eCoord closestCoord = pWall->Point(alpha); if (!s_zoneWallInteractionFound) { s_zoneWallInteractionClosestCoord = closestCoord; - s_zoneWallInteractionWallPtr = pWall; s_zoneWallInteractionFound = true; } else @@ -422,51 +579,26 @@ (s_zoneWallInteractionClosestCoord - s_zoneWallInteractionCoord).NormSquared()) { s_zoneWallInteractionClosestCoord = closestCoord; - s_zoneWallInteractionWallPtr = pWall; } } } -void gZone::BounceOffPoint(eCoord dest, eCoord collide, REAL mod) -{ - //Use a simple angle deflection for now not even accounting for points that made too far in - - //??? This should back calculate the time and point at which we collided - - //Get the collide vector and normalize - eCoord collideVec = collide - dest; - collideVec.Normalize(); - - eCoord velocity = GetVelocity(); - REAL speed = velocity.Norm(); - - eCoord startVec = velocity; - startVec.Normalize(); - startVec *= -1; - - REAL angleX = eCoord::F(collideVec, startVec); - - REAL angle = acos(angleX); - REAL angleY = sin(angle); - - //Turn the collide vector by the angle to get the target vector - eCoord endVec = collideVec.Turn(angleX, angleY); - - //con << "Zone collision: Old: " << startVec << " C: " << collideVec << " E1: " << endVec; - - if (((endVec.x * startVec.x) >= 0) && - ((endVec.y * startVec.y) >= 0)) +void gZone::BounceOffPoint(eCoord dest, eCoord collide) { - endVec = collideVec.Turn(cos((2 * M_PI) - angle), sin((2 * M_PI) - angle)); - //con << " E2: " << endVec << '\n'; - } - - //con << " E2N: " << collideVec.Turn(angleX, angleY) << '\n'; - + //Use a simple angle deflection for now not even accounting for points that made too far in + eCoord V = GetVelocity(); + // adjust position to be like at at impact time + eCoord P = GetPosition()+V*s_zoneWallInteractionImpactTime; + eCoord base = collide - P; // get normal vector to the impact + base.Normalize(); + // adjust speed + V = V - base*(eCoord::F(base,V)*2); + // adjust position according to new speed + P = P-V*s_zoneWallInteractionImpactTime; SetReferenceTime(); - //??? why does mod cause wall stick? (multiwall infinite stick) - SetVelocity(endVec * speed * mod); + SetVelocity(V); + SetPosition(P); RequestSync(); } @@ -494,17 +627,46 @@ return (false); } + bool doRequestSync = false; + + // resize + if (resizeRequested_) + { + REAL r = GetRadius(); + REAL s = GetExpansionSpeed(); + if (((s>0)&&(r>expectedRadius_)) || ((s<0)&&(r1)?1:s_zoneWallInteractionZoneDeltaTime; grid->ProcessWallsInRange(&S_ZoneWallInteraction, s_zoneWallInteractionCoord, - s_zoneWallInteractionRadius, + s_zoneWallInteractionRadius*1.5, CurrentFace()); if (s_zoneWallInteractionFound) @@ -560,11 +723,8 @@ else { // bounce off wall - BounceOffPoint(dest, s_zoneWallInteractionClosestCoord, sg_ballWallMod); - - // save the last wall pointer so we don't act on it again next time - //??? really should make the - pLastWall_ = s_zoneWallInteractionWallPtr; + BounceOffPoint(GetPosition(), s_zoneWallInteractionImpactCoord); + lastImpactTime_ = time + s_zoneWallInteractionImpactTime; if (wallBouncesLeft_ > 0) { @@ -574,10 +734,6 @@ return false; } } - else - { - pLastWall_ = NULL; - } // only clip if zone is moving if ((posx_.GetSlope() != 0) || (posy_.GetSlope() != 0)) @@ -585,13 +741,18 @@ // clip movement to rim walls eCoord dest(posx_(dt), posy_(dt)); tStackObject< ePoint > start(pos),stop(dest); - // ePoint* pstart = &start; - // ePoint* pstop = &stop; REAL clip = eWallRim::Clip(start,stop,0); if (clip < 1) { + gBallZoneHack *thisBallZone = dynamic_cast(this); + if (thisBallZone && sg_ballAutoRespawn) + { + // just respawn the ball at the original location + thisBallZone->GoHome(); + } else + { //Don't allow going outside, kill it destroyed_ = true; OnVanish(); @@ -603,10 +764,42 @@ } } } + } - bool doRequestSync = false; + if(!route_.empty() && time >= nextUpdate_) + { + if(nextUpdate_ < 0) nextUpdate_ = time; + eCoord const &lastPos = route_[lastCoord_++]; + REAL speed = GetVelocity().Norm(); + SetPosition(lastPos); + // no speed, no point... + if(speed < EPS) route_.clear(); + if(lastCoord_ >= route_.size()) + { + lastCoord_ = 0; + } + eCoord delta = route_[lastCoord_] - lastPos; + REAL dist = delta.Norm(); + if(dist < EPS) // next point is the same. Stop the route ... + { + eCoord zoneDir = eCoord(0,0); + SetVelocity(zoneDir); + route_.clear(); + } + else + { + delta.Normalize(); + SetVelocity(delta * speed); + nextUpdate_ += dist/speed; + } + doRequestSync = true; + } - if ((GetExpansionSpeed() > 0) && (targetRadius_) && (GetRadius() >= targetRadius_)) + if ( targetRadius_ && ( + ((GetExpansionSpeed() > 0) && (GetRadius() >= targetRadius_)) + || + ((GetExpansionSpeed() < 0) && (GetRadius() <= targetRadius_)) + )) { //??? change this to allow negative fall speed and keeping the target radius SetReferenceTime(); @@ -656,6 +849,14 @@ return false; } + +gZone &gZone::AddWaypoint(eCoord const &point) +{ + route_.push_back(point); + return *this; +} + + // ******************************************************************************* // * // * OnVanish @@ -748,6 +950,90 @@ } } } + + // interaction between 2 balls + gBallZoneHack *thisBallZone = dynamic_cast(this); + if (thisBallZone && sg_ballsInteract) + { + gBallZoneHack *ball = dynamic_cast(target); + + s_zoneWallInteractionFound = false; + s_zoneWallInteractionCoord = GetPosition(); + s_zoneWallInteractionRadius = GetRadius(); + grid->ProcessWallsInRange(&S_ZoneWallIntersect, + s_zoneWallInteractionCoord, + s_zoneWallInteractionRadius+.5, + CurrentFace()); + + if (s_zoneWallInteractionFound) + return; + + if ((ball) && + (ball != this) && + (!ball->destroyed_)) + { + REAL r1 = this->Radius(); + REAL r2 = ball->Radius(); + REAL R = r1 + r2; + eCoord p1 = this->Position(); + eCoord p2 = ball->Position(); + eCoord dp = p2 - p1; + REAL c = dp.NormSquared() - R * R; + + if (c < 0) // the 2 balls just hit each other ... + { + // first find the real time and position of the impact ... + eCoord v1 = this->GetVelocity(); + eCoord v2 = ball->GetVelocity(); + eCoord dv = v2 - v1; + REAL a = dv.NormSquared(); + REAL b = 2*(dp.x*dv.x+dp.y*dv.y); + REAL delta = b*b-4*a*c; + // no t. it can't be, an impact just occured ... + if (delta<0) return; + else // delta is positive, it means we have 2 different solutions + { // the t we are looking for is negative and as close as possible to 0 = it just happens ;) + delta = sqrt(delta); + REAL t1 = (-b-delta)/(2*a); + REAL t2 = (-b+delta)/(2*a); + REAL t = 0; + // can't be, again ... + if ((t1>0) && (t2>0)) return; + if (t1>0) t = t2; + else if (t2>0) t = t1; + else if (t1>t2) t = t1; + else t = t2; + + // if a wall impact happens too close, just skip balls interaction for now ... + if (t > lastImpactTime_ - time) return; + + // now that we have the time, get the positions ... + eCoord p1c = p1+v1*t; + eCoord p2c = p2+v2*t; + //eCoord pi = p1c + (p2c-p1c)*(R/this->Radius()); + // now compute the impact : new velocities and new correct positions ... + eCoord base = (p2c-p1c); + base.Normalize(); + // the weight of the zones are set according to the area + REAL m1 = r1*r1; + REAL m2 = r2*r2; + REAL M = m1+m2; + eCoord new_v1 = v1 + base*((2*m2/M)*(eCoord::F(dv,base))); + eCoord new_v2 = v2 - base*((2*m1/M)*(eCoord::F(dv,base))); + eCoord new_p1 = p1c + new_v1*(-t+0.01); + eCoord new_p2 = p2c + new_v2*(-t+0.01); + this->SetReferenceTime(); + this->SetPosition(new_p1); + this->SetVelocity(new_v1); + this->RequestSync(); + ball->SetReferenceTime(); + ball->SetPosition(new_p2); + ball->SetVelocity(new_v2); + ball->RequestSync(); + } + } + } + } } } } @@ -940,6 +1231,45 @@ // ******************************************************************************* // * +// * DrawSvg +// * +// ******************************************************************************* +//! +//! @return +//! +// ******************************************************************************* +//! draws it in a svg file +void gZone::DrawSvg(std::ofstream &f) { + REAL r = Radius(); + REAL dash = 2 * r * M_PI / 20; + + REAL alpha = ( lastTime - createTime_ ) * .2f; + if ( alpha > .7f ) + alpha = .7f; + if ( alpha <= 0 ) + return; + alpha *= sg_zoneAlpha * sg_zoneAlphaServer; + + f << " \n"; + REAL speed = GetRotationSpeed(); + if(fabs(speed) > EPS) { + REAL t = fabs(2*M_PI/speed); + f << " \n"; + } + f << " \n"; + +} + + +// ******************************************************************************* +// * // * RendersAlpha // * // ******************************************************************************* @@ -963,8 +1294,8 @@ //! // ******************************************************************************* -gWinZoneHack::gWinZoneHack( eGrid * grid, const eCoord & pos ) - :gZone( grid, pos ) +gWinZoneHack::gWinZoneHack( eGrid * grid, const eCoord & pos, bool dynamicCreation ) +:gZone( grid, pos, dynamicCreation ) { color_.r = 0.0f; color_.g = 1.0f; @@ -1036,7 +1371,7 @@ //! // ******************************************************************************* -gDeathZoneHack::gDeathZoneHack( eGrid * grid, const eCoord & pos, bool dynamicCreation ) +gDeathZoneHack::gDeathZoneHack( eGrid * grid, const eCoord & pos, bool dynamicCreation, eTeam * teamowner ) :gZone( grid, pos, dynamicCreation ) { deathZoneType = TYPE_NORMAL; @@ -1046,6 +1381,8 @@ color_.g = 0.0f; color_.b = 0.0f; + if (teamowner!=NULL) team = teamowner; + grid->AddGameObjectInteresting(this); } @@ -1217,13 +1561,18 @@ //! @param time the current time //! // ******************************************************************************* - +static eLadderLogWriter sg_deathShotFragWriter("DEATH_SHOT_FRAG", true); +static eLadderLogWriter sg_deathShotSuicideWriter("DEATH_SHOT_SUICIDE", true); +static eLadderLogWriter sg_deathShotTeamkillWriter("DEATH_SHOT_TEAMKILL", true); +static eLadderLogWriter sg_deathDeathZoneWriter("DEATH_DEATHZONE", true); void gDeathZoneHack::OnEnter( gCycle * target, REAL time ) { - if (!dynamicCreation_) + if (!dynamicCreation_ || ( deathZoneType == TYPE_NORMAL && !team ) ) { - target->Player()->AddScore(score_deathzone, tOutput(), "$player_lose_suicide"); + target->Player()->AddScore(score_deathzone, tOutput(), "$player_lose_deathzone"); target->Kill(); + sg_deathDeathZoneWriter << ePlayerNetID::FilterName(target->Player()->GetUserName()); + sg_deathDeathZoneWriter.write(); } else { @@ -1231,6 +1580,17 @@ //Checks to see if their cycle is invulnerable, don't kill invulnerable players return; } + + // check normal death zone linked to a team ... + if (team && deathZoneType == TYPE_NORMAL) + { + if ((!target) || (!target->Player())) + { + return; + } + if (target->Player()->CurrentTeam() == team) return; + } + //Validate the owner player ID pOwner_ = validatePlayer(pOwner_); //??? Really need for the player to get cleared when they exit, it is possible for @@ -1252,6 +1612,8 @@ } else { + sg_deathShotSuicideWriter << *target->Player()->GetUserName(); + sg_deathShotSuicideWriter.write(); if (!score_shot_suicide) { tColoredString playerName; @@ -1282,6 +1644,8 @@ if (prey->CurrentTeam() != hunter->CurrentTeam()) { + sg_deathShotFragWriter << prey->GetUserName() << hunter->GetUserName(); + sg_deathShotFragWriter.write(); char const *pWinString = "$player_win_shot"; char const *pFreeString = "$player_free_shot"; int score = score_shot; @@ -1338,6 +1702,8 @@ return; } + sg_deathShotTeamkillWriter << prey->GetUserName() << hunter->GetUserName(); + sg_deathShotTeamkillWriter.write(); tColoredString hunterName; hunterName << *hunter << tColoredString::ColorString(1,1,1); sn_ConsoleOut( tOutput( "$player_teamkill", hunterName, preyName ) ); @@ -1350,7 +1716,14 @@ } else { + if(deathZoneType == TYPE_ZOMBIE_ZONE) + { + target->Player()->AddScore(score_zombie_zone, tOutput(), "$player_lose_suicide"); + } + else + { target->Player()->AddScore(score_die, tOutput(), "$player_lose_frag"); + } target->Kill(); } @@ -1530,6 +1904,131 @@ // ******************************************************************************* // * +// * gRubberZoneHack +// * +// ******************************************************************************* +//! +//! @param grid Grid to put the zone into +//! @param pos Position to spawn the zone at +//! +// ******************************************************************************* + +gRubberZoneHack::gRubberZoneHack( eGrid * grid, const eCoord & pos, bool dynamicCreation) +:gZone( grid, pos, dynamicCreation ) +{ + color_.r = 1.0f; + color_.g = 0.7f; + color_.b = 0.2f; + + grid->AddGameObjectInteresting(this); +} + + +// ******************************************************************************* +// * +// * ~gRubberZoneHack +// * +// ******************************************************************************* +//! +//! +// ******************************************************************************* + +gRubberZoneHack::~gRubberZoneHack( void ) +{ +} + + +static int score_rubberzone=-1; +static tSettingItem s_rz("SCORE_RUBBERZONE",score_rubberzone); + +void gRubberZoneHack::OnVanish( void ) +{ + grid->RemoveGameObjectInteresting(this); +} + +gZone & gRubberZoneHack::SetRubber(REAL rubber) +{ + rmRubber = rubber; + + return (*this); +} + +gCycle * gRubberZoneHack::getPlayerCycle(ePlayerNetID *pPlayer) +{ + gCycle *pPlayerCycle = NULL; + if (pPlayer) + { + const tList& gameObjects = Grid()->GameObjects(); + for (int i=gameObjects.Len()-1;i>=0;i--) + { + gCycle *pCycle=dynamic_cast(gameObjects(i)); + + if (pCycle) + { + if (pCycle->Player() == pOwner_) + { + pPlayerCycle = pCycle; + break; + } + } + } + } + + return (pPlayerCycle); +} + +// ******************************************************************************* +// * +// * sg_RubberZoneHurt +// * +// ******************************************************************************* +//! +//! @param target the cycle that has been found inside the zone +//! @brief when DZ_RUBBER is not 0: change target's rubber instead of just killing +//! +// ******************************************************************************* +static eLadderLogWriter sg_deathRubberZoneWriter("DEATH_RUBBERZONE", true); +static void sg_RubberZoneHurt( gCycle * target, REAL rmRubber ); +void sg_RubberZoneHurt( gCycle * target, REAL rmRubber) +{ + REAL rubber = target->GetRubber(); + + if ( rubber + rmRubber >= sg_rubberCycle ) // max rubber amount reached, kill the cycle + { + target->Player()->AddScore( score_rubberzone, tOutput(), "$player_lose_rubberzone" ); + target->Kill(); + target->SetRubber( sg_rubberCycle ); + sg_deathRubberZoneWriter << target->Player()->GetUserName(); + sg_deathRubberZoneWriter.write(); + } + else if ( rubber + rmRubber > 0 ) // sg_deathZoneRubberMalus might be negative, avoid setting a negative rubber! + { + target->SetRubber( rubber + rmRubber ); + } + else // too low value, just set to zero + target->SetRubber( 0 ); +} + + +// ******************************************************************************* +// * gRubberZoneHack +// * OnEnter +// * +// ******************************************************************************* +//! +//! @param target the cycle that has been found inside the zone +//! @param time the current time +//! +// ******************************************************************************* + +void gRubberZoneHack::OnEnter( gCycle * target, REAL time ) +{ + sg_RubberZoneHurt( target, rmRubber ); +} + + +// ******************************************************************************* +// * // * gBaseZoneHack // * // ******************************************************************************* @@ -1539,8 +2038,8 @@ //! // ******************************************************************************* -gBaseZoneHack::gBaseZoneHack( eGrid * grid, const eCoord & pos ) - :gZone( grid, pos), onlySurvivor_( false ), currentState_( State_Safe ) +gBaseZoneHack::gBaseZoneHack( eGrid * grid, const eCoord & pos, bool dynamicCreation, eTeam * teamowner ) +:gZone( grid, pos, dynamicCreation), onlySurvivor_( false ), currentState_( State_Safe ) { enemiesInside_ = ownersInside_ = 0; conquered_ = 0; @@ -1551,12 +2050,14 @@ lastRespawnRemindWaiting_ = 0; touchy_ = false; - color_.r = color_.g = color_.b = 0; + if (teamowner!=NULL) team = teamowner; - lastRespawnRemindTime_ = -500; - lastRespawnRemindWaiting_ = 0; + for (int i=0; i sg_baseRespawnRemindTimeConfig("BASE_RESPAWN_REMIND_TIME", sg_baseRespawnRemindTime); +//number of flags that must be home in order to capture +static int sg_minFlagsHome = 0; +static tSettingItem sg_minFlagsHomeConfig( "MIN_FLAGS_HOME", sg_minFlagsHome ); + // count zones belonging to the given team. // fill in count and the zone that is farthest to the team. void gBaseZoneHack::CountZonesOfTeam( eGrid const * grid, eTeam * otherTeam, int & count, gBaseZoneHack * & farthest ) @@ -1928,74 +2434,6 @@ lastRespawnRemindWaiting_ = waiting; } - // determine the owning team: the one that has a player spawned closest - - // find the closest player - if ( !team ) - { - teamDistance_ = 0; - const tList& gameObjects = Grid()->GameObjects(); - gCycle * closest = NULL; - REAL closestDistance = 0; - for (int i=gameObjects.Len()-1;i>=0;i--) - { - gCycle *other=dynamic_cast(gameObjects(i)); - - if (other ) - { - eTeam * otherTeam = other->Player()->CurrentTeam(); - eCoord otherpos = other->Position() - pos; - REAL distance = otherpos.NormSquared(); - if ( !closest || distance < closestDistance ) - { - // check whether other zones are already registered to that team - gBaseZoneHack * farthest = NULL; - int count = 0; - if ( sg_baseZonesPerTeam > 0 ) - CountZonesOfTeam( Grid(), otherTeam, count, farthest ); - - // only set team if not too many closer other zones are registered - if ( sg_baseZonesPerTeam == 0 || count < sg_baseZonesPerTeam || farthest->teamDistance_ > distance ) - { - closest = other; - closestDistance = distance; - } - } - } - } - - if ( closest ) - { - // take over team and color - team = closest->Player()->CurrentTeam(); - color_.r = team->R()/15.0; - color_.g = team->G()/15.0; - color_.b = team->B()/15.0; - teamDistance_ = closestDistance; - - RequestSync(); - } - - // if this zone does not belong to a team, discard it. - if ( !team ) - { - return true; - } - - // check other zones owned by the same team. Discard the one farthest away - // if the max count is exceeded - if ( team && sg_baseZonesPerTeam > 0 ) - { - gBaseZoneHack * farthest = 0; - int count = 0; - CountZonesOfTeam( Grid(), team, count, farthest ); - - // discard team of farthest zone - if ( count > sg_baseZonesPerTeam ) - farthest->team = NULL; - } - } - // delegate bool ret = gZone::Timestep( time ); @@ -2018,8 +2457,11 @@ //! // ******************************************************************************* +static eLadderLogWriter sg_deathBasezoneConqueredWriter("DEATH_BASEZONE_CONQUERED", true); + void gBaseZoneHack::OnVanish( void ) { + if (!team) return; @@ -2057,12 +2499,21 @@ if ( closest ) { + sg_deathBasezoneConqueredWriter << ePlayerNetID::FilterName(closest->GetUserName()); + if ( enemies_.size() > 0 || sg_defendRate < 0) + { tColoredString playerName; playerName = closest->GetColoredName(); playerName << tColoredStringProxy(-1,-1,-1); sn_ConsoleOut( tOutput("$player_kill_collapse", playerName ) ); closest->Object()->Kill(); } + else + { + sg_deathBasezoneConqueredWriter << "NO_ENEMIES"; + } + sg_deathBasezoneConqueredWriter.write(); + } } } } @@ -2078,27 +2530,59 @@ static eLadderLogWriter sg_basezoneConqueredWriter("BASEZONE_CONQUERED", true); static eLadderLogWriter sg_basezoneConquererWriter("BASEZONE_CONQUERER", true); +static eLadderLogWriter sg_basezoneConquererTeamWriter("BASEZONE_CONQUERER_TEAM", true); void gBaseZoneHack::OnConquest( void ) { if ( team ) { sg_basezoneConqueredWriter << ePlayerNetID::FilterName(team->Name()) << GetPosition().x << GetPosition().y; + if ( enemies_.size() == 0 ) //no enemies inside + { + sg_basezoneConqueredWriter << "NO_ENEMIES"; + } sg_basezoneConqueredWriter.write(); } float rr = GetRadius(); rr *= rr; - for(int i = se_PlayerNetIDs.Len()-1; i >=0; --i) { + int totalInZone = 0; + for(int i = se_PlayerNetIDs.Len()-1; i >=0; --i) + { ePlayerNetID *player = se_PlayerNetIDs(i); - if(!player) { + if(!player) + { continue; } gCycle *cycle = dynamic_cast(player->Object()); - if(!cycle) { + if(!cycle) + { continue; } - if(cycle->Alive() && (cycle->Position() - Position()).NormSquared() < rr) { + if(cycle->Alive() && (cycle->Position() - Position()).NormSquared() < rr) + { + totalInZone++; + } + } + float percentWon = 0.0; + if (totalInZone > 0){ + percentWon = 1.0 /totalInZone; + } + for(int i = se_PlayerNetIDs.Len()-1; i >=0; --i) + { + ePlayerNetID *player = se_PlayerNetIDs(i); + if(!player) + { + continue; + } + gCycle *cycle = dynamic_cast(player->Object()); + if(!cycle) + { + continue; + } + if(cycle->Alive() && (cycle->Position() - Position()).NormSquared() < rr) + { sg_basezoneConquererWriter << player->GetUserName(); + sg_basezoneConquererWriter << percentWon; sg_basezoneConquererWriter.write(); } } @@ -2136,10 +2619,21 @@ int score = totalScore / enemies_.size(); for ( TeamArray::iterator iter = enemies_.begin(); iter != enemies_.end(); ++iter ) { + //sg_basezoneConquererTeamWriter << ePlayerNetID::FilterName((*iter)->Name()) << score; + //sg_basezoneConquererTeamWriter.write(); (*iter)->AddScore( score, win, tOutput() ); } } - + //write basezoneConquererTeam msg regardless of whether a score is given + if( enemies_.size() > 0) + { + int score = totalScore / enemies_.size(); + for ( TeamArray::iterator iter = enemies_.begin(); iter != enemies_.end(); ++iter ) + { + sg_basezoneConquererTeamWriter << ePlayerNetID::FilterName((*iter)->Name()) << score; + sg_basezoneConquererTeamWriter.write(); + } + } // trigger immediate win if ( sg_onConquestWin && enemies_.size() > 0 ) { @@ -2173,7 +2667,8 @@ bool onlySurvivor = true; const tList& gameObjects = Grid()->GameObjects(); - for (int i=gameObjects.Len()-1;i>=0 && onlySurvivor;i--){ + for (int i=gameObjects.Len()-1;i>=0 && onlySurvivor;i--) + { gBaseZoneHack *other=dynamic_cast(gameObjects(i)); if ( other && other->currentState_ == State_Safe && other->team ) @@ -2224,17 +2720,18 @@ } } + // ******************************************************************************* // * -// * OnRoundBegin +// * CheckTeamAssignment // * // ******************************************************************************* //! -//! @return shall the hole process be repeated? +//! @return true if a team is assigned, false if not //! // ******************************************************************************* -void gBaseZoneHack::OnRoundBegin( void ) +bool gBaseZoneHack::CheckTeamAssignment() { // determine the owning team: the one that has a player spawned closest // find the closest player @@ -2283,11 +2780,10 @@ RequestSync(); } - // if this zone does not belong to a team, discard it. + // if this zone does not belong to a team, return false. if ( !team ) { - RemoveFromGame(); - return; + return false; } // check other zones owned by the same team. Discard the one farthest away @@ -2306,8 +2802,31 @@ } } } + return true; } + +// ******************************************************************************* +// * +// * OnRoundBegin +// * +// ******************************************************************************* +//! +//! @return shall the hole process be repeated? +//! +// ******************************************************************************* + +void gBaseZoneHack::OnRoundBegin( void ) +{ + // if this zone does not belong to a team, discard it. + if ( !CheckTeamAssignment() ) + { + RemoveFromGame(); + return; + } +} + + // ******************************************************************************* // * // * OnRoundEnd @@ -2383,11 +2903,16 @@ } ++ enemiesInside_; + conquerer_[target->Player()->ListID()]+=time - lastTime; if ( std::find( enemies_.begin(), enemies_.end(), otherTeam ) == enemies_.end() ) enemies_.push_back( otherTeam ); lastEnemyContact_ = time; } + else + { + conquerer_[target->Player()->ListID()]+=time - lastTime; + } // check if player has a flag if (target->flag_) @@ -2397,9 +2922,8 @@ { // search for another flag owned by our team bool allFlagsHome = true; - - if (sg_flagRequiredHome) - { + int flagsHome = 0; + int flagsTaken = 0; const tList& gameObjects = Grid()->GameObjects(); for (int i=gameObjects.Len()-1;i>=0;i--) { @@ -2412,9 +2936,21 @@ if (!otherFlag->IsHome()) { allFlagsHome = false; + flagsTaken++; + } + else + { + flagsHome++; } } } + if (!sg_flagRequiredHome) + { + if (sg_minFlagsHome > (flagsHome+flagsTaken)){ + allFlagsHome=false; + }else if(sg_minFlagsHome <= flagsHome){ + allFlagsHome=true; + } } if (!allFlagsHome) @@ -2451,26 +2988,86 @@ void gBaseZoneHack::OnEnter( gZone * target, REAL time ) { + //it already hit the zone. + if(currentState_ == State_Conquering || currentState_ == State_Conquered) return; gBallZoneHack *ball = dynamic_cast(target); + if (!ball) return; - if (ball) + // check ball team mode + int toScore; + if (!team || !target ) toScore = 1; + else if (sg_ballTeamMode) toScore = target->Team() == team ? 1 : 0; + else toScore = target->Team() == team ? 0 : 1; + + if (ball && toScore) { - if(currentState_ == State_Conquering || currentState_ == State_Conquered) + // the ball entered the goal, figure out who shot it + ePlayerNetID *lastPlayer = ball->GetLastPlayer(); + + // and respawn players ... + if ( sg_baseRespawn || sg_baseEnemyRespawn ) { - return; // the zone is already being conquered, no more points + // check for respawn + //??? change this to divide up spawns between bases, and randomly choose among those closest + gSpawnPoint *pSpawn = Arena.ClosestSpawnPoint(GetPosition()); + + if (pSpawn) + { + for (int i = team->NumPlayers() - 1; i >= 0; --i) + { + ePlayerNetID *pPlayer = team->Player(i); + + eGameObject *pGameObject = pPlayer->Object(); + + if ((!pGameObject) || + ((!pGameObject->Alive()) && + (pGameObject->DeathTime() < (time - 1)))) + { + lastRespawnRemindTime_ = time - sg_baseRespawnRemindTime - 1; + + eCoord pos, dir; + + pSpawn->Spawn(pos, dir); + + gCycle *pCycle = new gCycle(grid, pos, dir, pPlayer); + pPlayer->ControlObject(pCycle); + + tColoredString playerName; + playerName << *pPlayer << tColoredString::ColorString(1,1,1); + + if ((ownersInside_ > 0) && (sg_baseRespawn)) + { + tColoredString spawnerName; + spawnerName << teamPlayerName_ << tColoredString::ColorString(1,1,1); + sn_ConsoleOut( tOutput( "$player_base_respawn", playerName, spawnerName ) ); + } + else + { + tColoredString spawnerName; + spawnerName << enemyPlayerName_ << tColoredString::ColorString(1,1,1); + sn_ConsoleOut( tOutput( "$player_base_enemy_respawn", playerName, spawnerName ) ); } - // the ball entered the goal, figure out who shot it - ePlayerNetID *lastPlayer_ = ball->GetLastPlayer(); - if (lastPlayer_) + // send a console message to the player + sn_CenterMessage(tOutput("$player_respawn_center_message"), pPlayer->Owner()); + } + } + } + } + + if (!lastPlayer) { - eTeam *lastTeam = lastPlayer_->CurrentTeam(); + return; + } + else + { + eTeam *lastTeam = lastPlayer->CurrentTeam(); if (lastTeam == team) { // own team hit it in tColoredString playerName; - playerName << *lastPlayer_ << tColoredString::ColorString(1,1,1); + playerName << *lastPlayer << tColoredString::ColorString(1,1,1); sn_ConsoleOut( tOutput( "$player_score_own_goal", playerName ) ); // search through the teams and add a point to each @@ -2491,7 +3088,7 @@ int score = sg_scoreGoal; win << "$player_score_goal"; - lastPlayer_->AddScore(score, win, lose); + lastPlayer->AddScore(score, win, lose); } // check if the round should end or we should respawn the ball @@ -2500,7 +3097,7 @@ //static const char* message="$player_win_instant"; //sg_DeclareWinner( lastTeam, message ); - // destroy the ball + //// destroy the ball //ball->Destroy(); OnConquest(); currentState_ = State_Conquering; @@ -2781,6 +3392,32 @@ return *this; } + +// ******************************************************************************* +// * +// * SetRadiusSmoothly +// * +// ******************************************************************************* +//! +//! @param radius the current radius to set +//! @param expansionSpeed the current expansion speed to set +//! @return A reference to this to allow chaining +//! +// ******************************************************************************* + +gZone & gZone::SetRadiusSmoothly( REAL radius, REAL expansionSpeed ) +{ + expectedRadius_ = radius; + // save expansion speed if not already resizing ... + if (!resizeRequested_) previousExpansionSpeed_ = GetExpansionSpeed(); + resizeRequested_ = true; + expansionSpeed = (expansionSpeed==0?radius*0.5:(expansionSpeed<0?-expansionSpeed:expansionSpeed)); + SetExpansionSpeed( (GetRadius()>radius?-expansionSpeed:expansionSpeed )); + + return *this; +} + + // ******************************************************************************* // * // * GetExpansionSpeed @@ -2967,8 +3614,8 @@ //! // ******************************************************************************* -gBallZoneHack::gBallZoneHack( eGrid * grid, const eCoord & pos ) - :gZone( grid, pos, false ) +gBallZoneHack::gBallZoneHack( eGrid * grid, const eCoord & pos, bool dynamicCreation, eTeam * teamowner ) +:gZone( grid, pos, dynamicCreation ) { color_.r = 1.0f; color_.g = 1.0f; @@ -2978,6 +3625,11 @@ wallBouncesLeft_ = -1; lastPlayer_ = NULL; originalPosition_ = pos; + originalVelocity_ = eCoord(0,0); + init_ = false; + lastImpactTime_ = 0; + + if (teamowner!=NULL) team = teamowner; grid->AddGameObjectInteresting(this); } @@ -2997,9 +3650,12 @@ : gZone( m ) { lastPlayer_ = NULL; + init_ = false; originalPosition_ = pos; + originalVelocity_ = eCoord(0,0); } + // ******************************************************************************* // * // * ~gBallZoneHack @@ -3013,11 +3669,43 @@ { } + +static eLadderLogWriter sg_ballVanishWriter("BALL_VANISH", false); + void gBallZoneHack::OnVanish( void ) { grid->RemoveGameObjectInteresting(this); + sg_ballVanishWriter << this->GOID() << name_ << GetPosition().x << GetPosition().y; + sg_ballVanishWriter.write(); } + +// ******************************************************************************* +// * +// * Timestep +// * +// ******************************************************************************* +//! +//! @param time the current time +//! +// ******************************************************************************* + +bool gBallZoneHack::Timestep( REAL time ) +{ + // initialize the zone info, this happens only once, but has to happen after construction + if (!init_) + { + init_ = true; + originalVelocity_ = GetVelocity(); + } + + // delegate + bool returnStatus = gZone::Timestep( time ); + + return (returnStatus); +} + + // ******************************************************************************* // * // * OnEnter @@ -3028,6 +3716,9 @@ //! @param time the current time //! // ******************************************************************************* +extern eLadderLogWriter sg_deathFragWriter; +extern eLadderLogWriter sg_deathSuicideWriter; +extern eLadderLogWriter sg_deathTeamkillWriter; void gBallZoneHack::OnEnter( gCycle * target, REAL time ) { @@ -3036,30 +3727,129 @@ return; } - // save the last cycle to enter even if we're discarding this hit + REAL dt = time - referenceTime_; + eCoord dest(posx_(dt), posy_(dt)); + s_zoneWallInteractionFound = false; + s_zoneWallInteractionCoord = dest; + s_zoneWallInteractionRadius = GetRadius(); + grid->ProcessWallsInRange(&S_ZoneWallIntersect, + s_zoneWallInteractionCoord, + s_zoneWallInteractionRadius, + CurrentFace()); + + // keep some data to allow to bounce even for killing balls ... + eCoord p2 = target->Position(); + eCoord v2 = target->Direction()*target->Speed(); + + // check killer balls ... ;) + ePlayerNetID * prey = target->Player(); + if ((sg_ballKiller) && (team) && !(prey->CurrentTeam() == team)) + { + target->Kill(); + // scoring ... + if ( lastPlayer_ ) + { + tOutput lose; + tOutput win; + ePlayerNetID * hunter = lastPlayer_; + + if ( hunter->CurrentTeam() != prey->CurrentTeam() ) + { + tColoredString preyName; + preyName << *prey; + preyName << tColoredString::ColorString(1,1,1); + if (prey->CurrentTeam() != hunter->CurrentTeam()) + { + sg_deathFragWriter << prey->GetUserName() << nMachine::GetMachine(prey->Owner()).GetIP() + << hunter->GetUserName() << nMachine::GetMachine(hunter->Owner()).GetIP(); + sg_deathFragWriter.write(); + + win.SetTemplateParameter(3, preyName); + win << "$player_win_frag"; + if ( score_kill != 0 ) + hunter->AddScore(score_kill, win, lose ); + else + { + tColoredString hunterName; + hunterName << *hunter << tColoredString::ColorString(1,1,1); + sn_ConsoleOut( tOutput( "$player_free_frag", hunterName, preyName ) ); + } + } + else // this should never happens as the killed player is not kept as lastplayer but we can change it easily ;) + { + sg_deathTeamkillWriter << prey->GetUserName() << nMachine::GetMachine(prey->Owner()).GetIP() + << hunter->GetUserName() << nMachine::GetMachine(hunter->Owner()).GetIP(); + sg_deathTeamkillWriter.write(); + + tColoredString hunterName; + hunterName << *hunter << tColoredString::ColorString(1,1,1); + sn_ConsoleOut( tOutput( "$player_teamkill", hunterName, preyName ) ); + } + } + } + else + target->Player()->AddScore(score_deathzone, tOutput(), "$player_lose_suicide"); + } + else + { + // keep the last cycle to enter even if we're discarding this hit lastPlayer_ = target->Player(); + } //Only process the cycle kick if there is no wall inside the zone + if (s_zoneWallInteractionFound) + return; + + REAL r1 = this->GetRadius(); + REAL r2 = 0.2; // the cycle "radius". to be adjusted ... + REAL R = r1 + r2; + eCoord p1 = this->Position(); + eCoord dp = p2 - p1; + REAL c = dp.NormSquared() - R * R; + // first find the real time and position of the impact ... + eCoord v1 = this->GetVelocity(); + eCoord dv = v2 - v1; + REAL a = dv.NormSquared(); + REAL b = 2*(dp.x*dv.x+dp.y*dv.y); + REAL delta = b*b-4*a*c; + if (delta<0) return; // no t. it can't be, an impact just occured ... + delta = sqrt(delta); + REAL t1 = (-b-delta)/(2*a); + REAL t2 = (-b+delta)/(2*a); + REAL t = 0; + if ((t1>0) && (t2>0)) return;// can't be, again ... + if (t1>0) t = t2; + else if (t2>0) t = t1; + else if (t1>t2) t = t1; + else t = t2; + + // if a wall impact happens too close, just skip cycle bouncing for now ... + if (t < lastImpactTime_ - time) return; + + // now that we have the time, get the positions ... + eCoord p1c = p1+v1*t; + eCoord p2c = p2+v2*t; + // now compute the impact : new velocities and new correct positions ... + eCoord base = (p2c-p1c); + base.Normalize(); + eCoord new_v1 = base*-target->Speed(); + eCoord new_p1 = p1c + new_v1*(-t+0.01); + new_v1 = new_v1*(1+sg_ballCycleBoost*target->GetAcceleration()/100); + s_zoneWallInteractionFound = false; - s_zoneWallInteractionCoord = GetPosition(); + s_zoneWallInteractionCoord = new_p1 + new_v1 * dt; s_zoneWallInteractionRadius = GetRadius(); - s_zoneWallInteractionWallPtr = NULL; - grid->ProcessWallsInRange(&S_ZoneWallInteraction, + grid->ProcessWallsInRange(&S_ZoneWallIntersect, s_zoneWallInteractionCoord, s_zoneWallInteractionRadius, CurrentFace()); if (s_zoneWallInteractionFound) - { return; - } - - //Get the collide vector and normalize - eCoord collideVec = GetPosition() - target->Position(); - collideVec.Normalize(); SetReferenceTime(); - SetVelocity(collideVec * target->Speed()); + this->SetPosition(new_p1); + this->SetVelocity(new_v1); RequestSync(); } @@ -3102,7 +3895,7 @@ // put the ball at home SetReferenceTime(); SetPosition(originalPosition_); - SetVelocity(eCoord(0,0)); + SetVelocity(originalVelocity_); RequestSync(); } @@ -3117,8 +3911,8 @@ //! // ******************************************************************************* -gFlagZoneHack::gFlagZoneHack( eGrid * grid, const eCoord & pos ) - :gZone( grid, pos, false ) +gFlagZoneHack::gFlagZoneHack( eGrid * grid, const eCoord & pos, bool dynamicCreation, eTeam * teamowner ) +:gZone( grid, pos, dynamicCreation ) { color_.r = 1.0f; color_.g = 1.0f; @@ -3140,8 +3934,10 @@ SetExpansionSpeed(0); SetRotationSpeed( .3f ); + if (teamowner!=NULL) team = teamowner; } + // ******************************************************************************* // * // * gFlagZoneHack @@ -3520,11 +4319,21 @@ { gFlagZoneHack *otherFlag=dynamic_cast(gameObjects(i)); if ((otherFlag)){ - if (otherFlag->Owner() == target ){ + if (otherFlag->Owner()){ + //make sure they are on the oposite team else pointless to continue + if(otherFlag->Team() != target->Player()->CurrentTeam()) + { + ePlayerNetID *flagHolder = otherFlag->Owner()->Player(); + if (flagHolder){ + if (flagHolder == target->Player()) + { playerHasFlag = true; } } } + } + } + } // check if the player is on our team or not (check will fail if team not enabled) if (target->Player()->CurrentTeam() == team) @@ -3540,7 +4349,7 @@ sn_ConsoleOut( tOutput( "$player_flag_return", playerName ) ); } } - // check if this player dropped the flag previously + // check if this player dropped the flag previously and ensure that player does not have another flag else if (((target != ownerDropped_) || (time > (ownerDroppedTime_ + sg_flagDropTime))) && (!playerHasFlag)) { // take the flag @@ -3752,3 +4566,989 @@ } } } + + +// ******************************************************************************* +// * +// * gTargetZoneHack settings +// * +// ******************************************************************************* + +// time in sec before the zone vanished. -1 for infinite +static int sg_targetTimeBeforeVanish = -1; +static tSettingItem sg_targetTimeBeforeVanishConf( "TARGET_LIFETIME", sg_targetTimeBeforeVanish ); + +// time in sec before the zone vanished once a player entered. -1 for infinite +static int sg_targetTimeBeforeVanishOnceConquered = 10; +static tSettingItem sg_targetTimeBeforeVanishOnceConqueredConf( "TARGET_SURVIVE_TIME", sg_targetTimeBeforeVanishOnceConquered ); + +// score for the first player entering the zone +static int sg_targetInitScore = 10; +static tSettingItem sg_targetInitScoreConf( "TARGET_INITIAL_SCORE", sg_targetInitScore ); + +// score suppress to the zone score each time a player entered +static int sg_targetScoreDeplete = 2; +static tSettingItem sg_targetScoreDepleteConf( "TARGET_SCORE_DEPLETE", sg_targetScoreDeplete ); + +// last target zone is a winzone ?; +static int sg_targetIsWinzone = 1; +static tSettingItem sg_targetIsWinzoneConf( "TARGET_DECLARE_WINNER", sg_targetIsWinzone ); + + //!< count check zone on grid +int gTargetZoneHack::TargetZoneCounter_ = 0; + //!< game time when a winner can be declared if nothing happens soon +REAL gTargetZoneHack::winnerTime_ = 0; + //!< first player entering the last zone to be declare winner +ePlayerNetID *gTargetZoneHack::winner_ = 0; + +// ******************************************************************************* +// * +// * gTargetZoneHack +// * +// ******************************************************************************* +//! +//! @param grid Grid to put the zone into +//! @param pos Position to spawn the zone at +//! +// ******************************************************************************* + +gTargetZoneHack::gTargetZoneHack( eGrid * grid, const eCoord & pos, bool dynamicCreation) +:gZone( grid, pos, dynamicCreation ) +{ + color_.r = 0.0f; + color_.g = 1.0f; + color_.b = 0.0f; + + TargetZoneCounter_++; + winnerTime_ = -1; + winner_ = 0; + firstPlayer_ = 0; + zoneInitialScore_ = sg_targetInitScore; + zoneScore_ = sg_targetInitScore; + zoneScoreDeplete_ = sg_targetScoreDeplete; + timeFirstEntry_ = -1.0; + targetEmptyTime_ = -1.0; + currentState_ = State_Safe; + for(int i=0; iAddGameObjectInteresting(this); + + SetExpansionSpeed(0); + SetRotationSpeed( .3f ); + RequestSync(); +} + + +// ******************************************************************************* +// * +// * gTargetZoneHack +// * +// ******************************************************************************* +//! +//! @param m Message to read creation data from +//! @param null +//! +// ******************************************************************************* + +gTargetZoneHack::gTargetZoneHack( nMessage & m ) +: gZone( m ) +{ + TargetZoneCounter_++; + winnerTime_ = -1; + winner_ = 0; + firstPlayer_ = 0; + zoneInitialScore_ = sg_targetInitScore; + zoneScore_ = sg_targetInitScore; + zoneScoreDeplete_ = sg_targetScoreDeplete; + timeFirstEntry_ = -1.0; + targetEmptyTime_ = -1.0; + currentState_ = State_Safe; + for(int i=0; i0) && ((time - createTime_ - 3.5)>sg_targetTimeBeforeVanish) ) + { + // zone is conquered, make the zone collapse ... + currentState_ = State_Conquered; + SetReferenceTime(); + SetExpansionSpeed( -GetRadius()*.5 ); + RequestSync(); + // send message to ladder log file ... + sg_targetzoneTimeoutWriter << eGameObject::GOID() << name_ << GetPosition().x << GetPosition().y; + sg_targetzoneTimeoutWriter.write(); + } + + if ( ((currentState_ == State_Conquering) && (sg_targetTimeBeforeVanishOnceConquered>0) && (time - timeFirstEntry_>sg_targetTimeBeforeVanishOnceConquered)) + ||((currentState_ != State_Conquered) && (zoneScore_<=0) && (zoneScore_!=zoneInitialScore_)) ) + { + // zone is conquered, make the zone collapse ... + currentState_ = State_Conquered; + SetReferenceTime(); + SetExpansionSpeed( -GetRadius()*.5 ); + RequestSync(); + // send message to ladder log file ... + sg_targetzoneConqueredWriter << eGameObject::GOID() << name_ << GetPosition().x << GetPosition().y; + if (firstPlayer_) + { + sg_targetzoneConqueredWriter << firstPlayer_->GetUserName(); + if ( firstPlayer_->CurrentTeam() ) + { + sg_targetzoneConqueredWriter << ePlayerNetID::FilterName( firstPlayer_->CurrentTeam()->Name() ); + } + } + sg_targetzoneConqueredWriter.write(); + } + + for (int i=0; i( p->Object() ); + if ( prey ) + { + REAL r = this->GetRadius(); + if (!prey->Alive() || (( prey->Position() - this->Position() ).NormSquared() >= r*r)) + { + sg_targetzonePlayerLeftWriter << this->GOID() << name_ << GetPosition().x << GetPosition().y << p->GetUserName(); + sg_targetzonePlayerLeftWriter.write(); + playersFlags[i] = 1; + } + } else playersFlags[i] = 1; + } else playersFlags[i] = 1; + } + } + + // manage rotation speed + REAL omega; + REAL omegaDot; + REAL maxSpeed = 10 * ( 2 * 3.141 ) / sg_segments; + if (currentState_ != State_Conquered) + { + // set rotation speed accordingly to remaining points ... + REAL conquered = (zoneInitialScore_==0?0:(REAL)(zoneInitialScore_ - zoneScore_) / (REAL)zoneInitialScore_); + omega = .3 + conquered * conquered * maxSpeed; + omegaDot = 2 * conquered * maxSpeed; + } + else + { + omega = .3 + maxSpeed; + omegaDot = 2 * maxSpeed; + } + REAL timeStep = lastTime; + if ( sn_GetNetState() != nSERVER ) + timeStep *= 100; + + if ( sn_GetNetState() != nCLIENT && + ( ( fabs( omega - GetRotationSpeed() ) + fabs( omegaDot - GetRotationAcceleration() ) ) * timeStep > .5 ) ) + { + SetRotationSpeed( omega ); + SetRotationAcceleration( omegaDot ); + SetReferenceTime(); + RequestSync(); + } + + // delegate + bool returnStatus = gZone::Timestep( time ); + + return (returnStatus); +} + + +// ******************************************************************************* +// * +// * OnEnter +// * +// ******************************************************************************* +//! +//! @param target the cycle that has been found inside the zone +//! @param time the current time +//! +// ******************************************************************************* +static eLadderLogWriter sg_targetzonePlayerEnterWriter("TARGETZONE_PLAYER_ENTER", false); + +void gTargetZoneHack::OnEnter( gCycle * target, REAL time ) +{ + // make sure target and player are OK + if ((!target) || + (!target->Player()) || + (currentState_ == State_Conquered)) + { + return; + } + + // keep first player in memory, if it's the last zone, he is the winner ... + if (!firstPlayer_) + { + firstPlayer_= target->Player(); + timeFirstEntry_ = time; + currentState_ = State_Conquering; + // keep winner ... + winnerTime_ = timeFirstEntry_; + winner_ = firstPlayer_; + // send on enter commands ... + std::istringstream stream(&OnEnterCmd(0)); + tConfItemBase::LoadAll(stream); + } + + // Check if player already entered this zone + // If not ... + if (!playersFlags[target->Player()->ListID()]) + { + if (zoneScore_>0) + { + // flag the player + playersFlags[target->Player()->ListID()]=1; + // grant the player + tOutput win; + tOutput lose; + win << "$player_target_score_win"; + lose << "$player_target_score_lose"; + target->Player()->AddScore(zoneScore_, win, lose); + } + // and decrease zone score value + zoneScore_-=zoneScoreDeplete_; + if (zoneScore_<=0) + { + zoneScore_=0; + targetEmptyTime_=time; + } + } + + // message in edlog + if (playersFlags[target->Player()->ListID()] != 2) + { + sg_targetzonePlayerEnterWriter << this->GOID() << name_ << GetPosition().x << GetPosition().y << target->Player()->GetUserName(); + sg_targetzonePlayerEnterWriter.write(); + playersFlags[target->Player()->ListID()] = 2; + } +} + + +// ******************************************************************************* +// * +// * OnVanish +// * +// ******************************************************************************* + +void gTargetZoneHack::OnVanish( void ) +{ + // send on vanish commands ... + std::istringstream stream(&OnVanishCmd(0)); + tConfItemBase::LoadAll(stream); + + // check if we have a winner ... + if (sg_targetIsWinzone && (TargetZoneCounter_==1) && firstPlayer_) + { + winnerTime_ = timeFirstEntry_; + winner_ = firstPlayer_; + static const char* message="$player_target_win_conquest"; + sg_DeclareWinner( firstPlayer_->CurrentTeam(), message ); + } + // decrement target zone counter + TargetZoneCounter_--; +} + + +// ******************************************************************************* +// * +// * gBlastZoneHack +// * +// ******************************************************************************* +//! +//! @param grid Grid to put the zone into +//! @param pos Position to spawn the zone at +//! +// ******************************************************************************* + +gBlastZoneHack::gBlastZoneHack( eGrid * grid, const eCoord & pos, bool dynamicCreation) +:gZone( grid, pos, dynamicCreation ) +{ + color_.r = 0.0f; + color_.g = 1.0f; + color_.b = 0.0f; + + grid->AddGameObjectInteresting(this); + + SetExpansionSpeed(0); + SetRotationSpeed( .3f ); + RequestSync(); +} + + +// ******************************************************************************* +// * +// * gBlastZoneHack +// * +// ******************************************************************************* +//! +//! @param m Message to read creation data from +//! @param null +//! +// ******************************************************************************* + +gBlastZoneHack::gBlastZoneHack( nMessage & m ) +: gZone( m ) +{ +} + + +// ******************************************************************************* +// * +// * ~gBlastZoneHack +// * +// ******************************************************************************* +//! +//! +// ******************************************************************************* + +gBlastZoneHack::~gBlastZoneHack( void ) +{ +} + + +// ******************************************************************************* +// * +// * Timestep +// * +// ******************************************************************************* +//! +//! @param time the current time +//! +// ******************************************************************************* + +eCoord s_blastCoord; +REAL s_blastRadius; +extern void clamp01(REAL &c); + +// remove walls in the blast zone ... +void S_BlastWalls( eWall * w ) +{ + // determine the point closest to s_blastCoord + eCoord normal = w->Vec().Conj(); + normal.Normalize(); + + eCoord Pos1 = normal.Turn( w->EndPoint(0) - s_blastCoord ); + eCoord Pos2 = normal.Turn( w->EndPoint(1) - s_blastCoord ); + + tASSERT( fabs( Pos1.y - Pos2.y ) <= fabs( Pos1.y + Pos2.y + .1f ) * .1f ); + + REAL alpha = .5f; + if ( Pos1.x != Pos2.x) + alpha = Pos1.x / ( Pos1.x - Pos2.x ); + + REAL radius = s_blastRadius * s_blastRadius - Pos1.y * Pos2.y; + + // wall too far away + if ( radius < 0 ) + return; + + radius = sqrt( radius ); + + // works only for player walls + gPlayerWall* wall = dynamic_cast( w ); + if ( ! wall ) + return; + + REAL closestPos = wall->Pos( alpha ); + + REAL start = closestPos - radius; + REAL end = closestPos + radius; + + // cut away walls in the zone (if they are not reduced to a point) + REAL wallEnd = wall->EndPos(); + REAL wallBeg = wall->BegPos(); + if ( wallEnd <= wallBeg ) + { + return; + } + REAL endAlpha = ( end - wallBeg ) / ( wallEnd - wallBeg ); + // std::cout << wall->BegTime() << "\n"; + clamp01( endAlpha ); + end = wall->Pos( endAlpha ); + + if ( end > start ) + { + wall->BlowHole ( start, end, NULL ); + wall->NetWall()->RequestSync (); + } +} + + +bool gBlastZoneHack::Timestep( REAL time ) +{ + s_blastCoord = GetPosition(); + s_blastRadius = GetRadius(); + + if ( s_blastRadius > 0 ) + { + grid->ProcessWallsInRange( &S_BlastWalls, + s_blastCoord, + s_blastRadius, + CurrentFace() ); + } + + // delegate + bool returnStatus = gZone::Timestep( time ); + + return (returnStatus); +} + + +// ******************************************************************************* +// * +// * OnEnter +// * +// ******************************************************************************* +//! +//! @param target the cycle that has been found inside the zone +//! @param time the current time +//! +// ******************************************************************************* + +void gBlastZoneHack::OnEnter( gCycle * target, REAL time ) +{ +} + + +// ******************************************************************************* +// * +// * OnVanish +// * +// ******************************************************************************* + +void gBlastZoneHack::OnVanish( void ) +{ +} + + +// ******************************************************************************* +// * +// * Spawn_Zone +// * +// ******************************************************************************* + +static eLadderLogWriter sg_spawnzoneWriter("ZONE_SPAWNED", false); + +static void sg_CreateZone_conf(std::istream &s) +{ + eGrid *grid = eGrid::CurrentGrid(); + if(!grid) + { + con << "Must be called while a grid exists!\n"; + return; + } + + tString params; + params.ReadLine( s, true ); + + // first parse the line to get the params : + eTeam *zoneTeam=NULL; + int pos = 0; // + tString zoneTypeStr = params.ExtractNonBlankSubString(pos); + tString zoneNameStr; + if ((zoneTypeStr=="n")||(zoneTypeStr=="N")) + { + zoneNameStr = params.ExtractNonBlankSubString(pos); + zoneTypeStr = params.ExtractNonBlankSubString(pos); + } + else + { + zoneNameStr = tString(""); + } + tString zoneTeamStr = tString(""); + if ((zoneTypeStr=="fortress")||(zoneTypeStr=="flag")||(zoneTypeStr=="deathTeam")||(zoneTypeStr=="ballTeam")) + { + zoneTeamStr = params.ExtractNonBlankSubString(pos); + for (int i = eTeam::teams.Len() - 1; i>=0; --i) + { + tString teamName = eTeam::teams(i)->Name(); + if (zoneTeamStr==ePlayerNetID::FilterName(teamName)) + { + zoneTeam = eTeam::teams(i); + break; + } + } + } + + ePlayerNetID *zonePlayer = 0; + ePlayerNetID *zoneOwner = 0; + if(zoneTypeStr=="zombie" || zoneTypeStr == "zombieOwner") + { + tString targetPlayer = params.ExtractNonBlankSubString(pos); + zonePlayer = ePlayerNetID::FindPlayerByName(targetPlayer, NULL); + + if(!zonePlayer) + { + return; + } + } + if(zoneTypeStr == "zombieOwner") + { + tString targetPlayer = params.ExtractNonBlankSubString(pos); + zoneOwner = ePlayerNetID::FindPlayerByName(targetPlayer, NULL); + if(zoneOwner) + { + zoneTeam = zoneOwner->CurrentTeam(); + } + } + + tString zonePosXStr = params.ExtractNonBlankSubString(pos); + tString zonePosYStr; + + std::vector route; + if(zonePosXStr == "L") + { + tString x,y; + while(true) + { + x = params.ExtractNonBlankSubString(pos); + if(x == "Z" || x == "z" || x == "") break; + y = params.ExtractNonBlankSubString(pos); + route.push_back(eCoord(atof(x), atof(y))); + } + } + else + { + zonePosYStr = params.ExtractNonBlankSubString(pos); + } + + const tString zoneSizeStr = params.ExtractNonBlankSubString(pos); + const tString zoneGrowthStr = params.ExtractNonBlankSubString(pos); + const tString zoneDirXStr = params.ExtractNonBlankSubString(pos); + const tString zoneDirYStr = params.ExtractNonBlankSubString(pos); + tString zoneRubberStr; + REAL zoneRubber; + if(zoneTypeStr == "rubber"){ + zoneRubberStr = params.ExtractNonBlankSubString(pos); + zoneRubber = atof(zoneRubberStr); + con << zoneRubber; + } + const tString zoneInteractive = params.ExtractNonBlankSubString(pos); + const tString zoneRedStr = params.ExtractNonBlankSubString(pos); + const tString zoneGreenStr = params.ExtractNonBlankSubString(pos); + const tString zoneBlueStr = params.ExtractNonBlankSubString(pos); + const tString targetRadiusStr = params.ExtractNonBlankSubString(pos); + + // second convert params ( to do : check validity). + eCoord zonePos = route.empty() ? eCoord(atof(zonePosXStr),atof(zonePosYStr)) : route.front(); + const REAL zoneSize = atof(zoneSizeStr); + const REAL zoneGrowth = atof(zoneGrowthStr); + //const REAL zoneRubber = atof(zoneRubberStr); + eCoord zoneDir = eCoord(atof(zoneDirXStr),atof(zoneDirYStr)); + gRealColor zoneColor; + bool setColorFlag = false; + if ((zoneRedStr!="")&&(zoneGreenStr!="")&&(zoneBlueStr!="")) + { + zoneColor.r = atof(zoneRedStr); + zoneColor.g = atof(zoneGreenStr); + zoneColor.b = atof(zoneBlueStr); + setColorFlag = true; + } + + // if no_team was pass, assigns one: the one that has a player spawned closest + if ( zoneTeamStr=="no_team" ) + { + //REAL teamDistance_ = 0; + const tList& gameObjects = grid->GameObjects(); + gCycle * closest = 0; + REAL closestDistance = 0; + for (int i=gameObjects.Len()-1;i>=0;i--) + { + gCycle *other=dynamic_cast(gameObjects(i)); + + if (other ) + { + //eTeam * otherTeam = other->Player()->CurrentTeam(); + eCoord otherpos = other->Position() - zonePos; + REAL distance = otherpos.NormSquared(); + if ( !closest || distance < closestDistance ) + { + closest = other; + closestDistance = distance; + } + } + } + + if ( closest ) + { + // take over team + zoneTeam = closest->Player()->CurrentTeam(); + } + } + // then create zone ... + gZone *Zone = NULL; + if ( zoneTypeStr=="death" || zoneTypeStr=="deathTeam" ) + { + Zone = tNEW( gDeathZoneHack( grid, zonePos, true, zoneTeam ) ); + //sn_ConsoleOut( "$instant_death_activated" ); + if (zoneTeam!=NULL) + { + zoneColor.r = zoneTeam->R()/15.0; + zoneColor.g = zoneTeam->G()/15.0; + zoneColor.b = zoneTeam->B()/15.0; + zoneColor.r += (1.0 - zoneColor.r) / 1.8; + zoneColor.g += (1.0 - zoneColor.g) / 1.8; + zoneColor.b += (1.0 - zoneColor.b) / 1.8; + setColorFlag = true; + } + } + else if ( zoneTypeStr=="win") + { + Zone = tNEW( gWinZoneHack( grid, zonePos, true ) ); + //sn_ConsoleOut( "$instant_win_activated" ); + } + else if ( zoneTypeStr=="rubber") + { + gRubberZoneHack *rZone = tNEW(gRubberZoneHack(grid, zonePos, true)); + rZone->SetRubber(zoneRubber); + Zone = rZone; + } + else if ( zoneTypeStr=="ball" || zoneTypeStr=="ballTeam" ) + { + Zone = tNEW( gBallZoneHack( grid, zonePos, true, zoneTeam ) ); + //sn_ConsoleOut( "$instant_win_activated" ); + if (zoneTeam!=NULL) + { + zoneColor.r = zoneTeam->R()/15.0; + zoneColor.g = zoneTeam->G()/15.0; + zoneColor.b = zoneTeam->B()/15.0; + zoneColor.r += (1.0 - zoneColor.r) / 1.8; + zoneColor.g += (1.0 - zoneColor.g) / 1.8; + zoneColor.b += (1.0 - zoneColor.b) / 1.8; + setColorFlag = true; + } + } + else if ( zoneTypeStr=="flag" ) + { + Zone = tNEW( gFlagZoneHack( grid, zonePos, true, zoneTeam ) ); + //sn_ConsoleOut( "$instant_win_activated" ); + if (zoneTeam!=NULL) + { + zoneColor.r = zoneTeam->R()/15.0; + zoneColor.g = zoneTeam->G()/15.0; + zoneColor.b = zoneTeam->B()/15.0; + zoneColor.r += (1.0 - zoneColor.r) / 1.8; + zoneColor.g += (1.0 - zoneColor.g) / 1.8; + zoneColor.b += (1.0 - zoneColor.b) / 1.8; + setColorFlag = true; + } + } + else if ( zoneTypeStr=="fortress" ) + { + gBaseZoneHack *fZone = tNEW( gBaseZoneHack( grid, zonePos, true, zoneTeam ) ); + // if this zone does not belong to a team, discard it. + if ( !fZone->CheckTeamAssignment() ) + { + fZone->RemoveFromGame(); + return; + } + Zone = fZone; + //sn_ConsoleOut( "$instant_win_activated" ); + if (Zone->Team()!=NULL) + { + zoneColor.r = Zone->Team()->R()/15.0; + zoneColor.g = Zone->Team()->G()/15.0; + zoneColor.b = Zone->Team()->B()/15.0; + setColorFlag = true; + } + } + else if ( zoneTypeStr=="zombie" || zoneTypeStr=="zombieOwner" ) + { + gCycle *target = dynamic_cast(zonePlayer->Object()); + if(target) + { + gDeathZoneHack *dZone = tNEW(gDeathZoneHack(grid, zonePos, true)); + dZone->SetSeekingCycle(target); + dZone->SetType(gDeathZoneHack::TYPE_ZOMBIE_ZONE); + if(zoneOwner) + { + dZone->SetOwner(zoneOwner); + if (zoneTeam!=NULL) + { + zoneColor.r = zoneTeam->R()/15.0; + zoneColor.g = zoneTeam->G()/15.0; + zoneColor.b = zoneTeam->B()/15.0; + setColorFlag = true; + } + } + Zone = dZone; + } + else + { + goto usage; + } + } + else if ( zoneTypeStr=="target" ) + { + Zone = tNEW( gTargetZoneHack( grid, zonePos, true ) ); + } + else + { + usage: + con << "Usage:\n" + "SPAWN_ZONE \n" + "SPAWN_ZONE rubber \n" + "SPAWN_ZONE \n" + "SPAWN_ZONE zombie \n" + "SPAWN_ZONE zombieOwner \n" + "instead of one can write: L [...] Z\n"; + return; + } + static_cast(Zone)->Timestep( se_GameTime() ); + Zone->SetReferenceTime(); + Zone->SetRadius( zoneSize ); + Zone->SetExpansionSpeed( zoneGrowth ); + Zone->SetRotationSpeed( .3f ); + Zone->SetVelocity(zoneDir); + if (setColorFlag) + { + zoneColor.r = (zoneColor.r>1.0)?1.0:zoneColor.r; + zoneColor.g = (zoneColor.g>1.0)?1.0:zoneColor.g; + zoneColor.b = (zoneColor.b>1.0)?1.0:zoneColor.b; + Zone->SetColor(zoneColor); + } + if (zoneInteractive=="true") + { + Zone->SetWallInteract(true); + Zone->SetWallBouncesLeft(-1); + } + REAL targetRadius = atof(targetRadiusStr); + if(targetRadius != 0) + { + Zone->SetTargetRadius(targetRadius); + } + if(!route.empty()) + { + Zone->SetPosition(route.front()); + for(std::vector::const_iterator iter = route.begin(); iter != route.end(); ++iter) + { + Zone->AddWaypoint(*iter); + } + } + Zone->SetName(zoneNameStr); + Zone->RequestSync(); + + sg_spawnzoneWriter << Zone->GOID() << zoneNameStr << Zone->GetPosition().x << Zone->GetPosition().y; + sg_spawnzoneWriter.write(); +} + + +static tConfItemFunc sg_CreateZone_c("SPAWN_ZONE",&sg_CreateZone_conf); + +static eLadderLogWriter sg_collapsezoneWriter("ZONE_COLLAPSED", false); + +static void sg_CollapseZone(std::istream &s) +{ + tString params; + params.ReadLine( s, true ); + + // first parse the line to get the param : object_id + int pos = 0; // + const tString object_id_str = params.ExtractNonBlankSubString(pos); + // first check for the name + int zone_id; + zone_id=gZone::FindFirst(object_id_str); + if (zone_id==-1) + { + zone_id = atoi(object_id_str); + if (zone_id==0 && object_id_str!="0") return; + } + + const tList& gameObjects = eGrid::CurrentGrid()->GameObjects(); + while (zone_id!=-1) + { + // get the zone ... + gZone *zone=dynamic_cast(gameObjects(zone_id)); + if (zone) + { + zone->SetReferenceTime(); + zone->SetExpansionSpeed( -zone->GetRadius()*.5 ); + zone->RequestSync(); + sg_collapsezoneWriter << zone_id << object_id_str << zone->GetPosition().x << zone->GetPosition().y; + sg_collapsezoneWriter.write(); + zone_id=gZone::FindNext(object_id_str, zone_id); + } + } +} + + +static tConfItemFunc sg_CollapseZone_conf("COLLAPSE_ZONE",&sg_CollapseZone); + +static void sg_SetZoneRadius(std::istream &s) +{ + tString params; + params.ReadLine( s, true ); + + // parse the line to get the param : object_id, radius, speed + int pos = 0; // + const tString object_id_str = params.ExtractNonBlankSubString(pos); + const tString radius_str = params.ExtractNonBlankSubString(pos); + int radius = atoi(radius_str); + const tString speed_str = params.ExtractNonBlankSubString(pos); + REAL speed = atof(speed_str); + + // first check for the name + int zone_id; + zone_id=gZone::FindFirst(object_id_str); + if (zone_id==-1) + { + zone_id = atoi(object_id_str); + if (zone_id==0 && object_id_str!="0") return; + } + + const tList& gameObjects = eGrid::CurrentGrid()->GameObjects(); + while (zone_id!=-1) + { + // get the zone ... + gZone *zone=dynamic_cast(gameObjects(zone_id)); + if (zone) + { + zone->SetReferenceTime(); + // set new radius and speed to reach it ... + if (speed==0) + zone->SetRadiusSmoothly( radius ); + else + zone->SetRadiusSmoothly( radius, speed ); + zone->RequestSync(); + } + zone_id=gZone::FindNext(object_id_str, zone_id); + } +} + +static tConfItemFunc sg_SetZoneRadius_conf("SET_ZONE_RADIUS",&sg_SetZoneRadius); + +static void sg_SetZoneRoute(std::istream &s) +{ + tString params; + params.ReadLine( s, true ); + + // parse the line to get the param : object_id, positions ... + int pos = 0; // + const tString object_id_str = params.ExtractNonBlankSubString(pos); + // const tString mode_str = params.ExtractNonBlankSubString(pos); + std::vector route; + tString x,y; + while(true) + { + x = params.ExtractNonBlankSubString(pos); + if(x == "") break; + y = params.ExtractNonBlankSubString(pos); + route.push_back(eCoord(atof(x), atof(y))); + } + + // first check for the name + int zone_id; + zone_id=gZone::FindFirst(object_id_str); + if (zone_id==-1) + { + zone_id = atoi(object_id_str); + if (zone_id==0 && object_id_str!="0") return; + } + + const tList& gameObjects = eGrid::CurrentGrid()->GameObjects(); + while (zone_id!=-1) + { + // get the zone ... + gZone *zone=dynamic_cast(gameObjects(zone_id)); + if (zone) + { + zone->SetReferenceTime(); + eCoord zoneDir = eCoord(0,0); + if(!route.empty()) + { + eCoord curPos = zone->GetPosition(); + zone->AddWaypoint(curPos); + zoneDir = route.front(); + for(std::vector::const_iterator iter = route.begin(); iter != route.end(); ++iter) + { + zone->AddWaypoint(*iter + curPos); + } + } + zone->SetVelocity(zoneDir); + zone->RequestSync(); + } + zone_id=gZone::FindNext(object_id_str, zone_id); + } +} + +static tConfItemFunc sg_SetZoneRoute_conf("SET_ZONE_POSITION",&sg_SetZoneRoute); + +static void sg_SetTargetCmd(std::istream &s) +{ + tString params; + params.ReadLine( s, true ); + + // first parse the line to get the param : object_id + int pos = 0; // + const tString object_id_str = params.ExtractNonBlankSubString(pos); + tString event_str = params.ExtractNonBlankSubString(pos); + tString mode_str("new"); + if (event_str=="add") { + mode_str = tString("add"); + event_str = params.ExtractNonBlankSubString(pos); + } + tString cmd_str = params.SubStr(pos); + // first check for the name + int zone_id; + zone_id=gZone::FindFirst(object_id_str); + if (zone_id==-1) + { + zone_id = atoi(object_id_str); + if (zone_id==0 && object_id_str!="0") return; + } + + const tList& gameObjects = eGrid::CurrentGrid()->GameObjects(); + while (zone_id!=-1) + { + // get the zone ... + gTargetZoneHack *zone=dynamic_cast(gameObjects(zone_id)); + if (zone) + { + if (event_str=="onenter") { + zone->SetOnEnterCmd(cmd_str, mode_str); + con << "Zone " << zone->GOID() << " command onenter '" << cmd_str << "'\n"; + } else if (event_str=="onvanish") { + zone->SetOnVanishCmd(cmd_str, mode_str); + con << "Zone " << zone->GOID() << " command onvanish '" << cmd_str << "'\n"; + } + zone_id=gZone::FindNext(object_id_str, zone_id); + } + } +} + +static tConfItemFunc sg_SetTargetCmd_conf("SET_TARGET_COMMAND",&sg_SetTargetCmd); diff -uBbwdr --exclude=.bzr 0.2.8-armagetronad-sty/src/tron/gWinZone.h 0.2.8-armagetronad-sty+ct/src/tron/gWinZone.h --- 0.2.8-armagetronad-sty/src/tron/gWinZone.h 2009-03-12 23:14:00.000000000 -0500 +++ 0.2.8-armagetronad-sty+ct/src/tron/gWinZone.h 2009-03-13 00:17:08.000000000 -0500 @@ -46,83 +45,173 @@ tFunction(); //!< constructor ~tFunction(); //!< destructor - REAL Evaluate( REAL argument ) const; //!< evaluates the function - inline REAL operator()( REAL argument ) const; //!< evaluation operator + //!< evaluates the function + REAL Evaluate( REAL argument ) const; + //!< evaluation operator + inline REAL operator()( REAL argument ) const; // function parameters: currently limited to offset_ + slope_ * argument REAL offset_; //!< offset value REAL slope_; //!< function slope public: - inline tFunction & SetOffset( REAL const & offset ); //!< Sets offset value - inline REAL const & GetOffset( void ) const; //!< Gets offset value - inline tFunction const & GetOffset( REAL & offset ) const; //!< Gets offset value - inline tFunction & SetSlope( REAL const & slope ); //!< Sets function slope - inline REAL const & GetSlope( void ) const; //!< Gets function slope - inline tFunction const & GetSlope( REAL & slope ) const; //!< Gets function slope + //!< Sets offset value + inline tFunction & SetOffset( REAL const & offset ); + //!< Gets offset value + inline REAL const & GetOffset( void ) const; + //!< Gets offset value + inline tFunction const & GetOffset( REAL & offset ) const; + //!< Sets function slope + inline tFunction & SetSlope( REAL const & slope ); + //!< Gets function slope + inline REAL const & GetSlope( void ) const; + //!< Gets function slope + inline tFunction const & GetSlope( REAL & slope ) const; protected: private: }; -nMessage & operator << ( nMessage & m, tFunction const & f ); //! function network message writing operator -nMessage & operator >> ( nMessage & m, tFunction & f ); //! function network message reading operator + //! function network message writing operator +nMessage & operator << ( nMessage & m, tFunction const & f ); + //! function network message reading operator +nMessage & operator >> ( nMessage & m, tFunction & f ); //! basic zone class: handles rendering and entwork syncing class gZone: public eNetGameObject { public: - gZone(eGrid *grid, const eCoord &pos, bool dynamicCreation = false); //!< local constructor + //!< local constructor + gZone(eGrid *grid, const eCoord &pos, bool dynamicCreation = false); gZone(nMessage &m); //!< network constructor ~gZone(); //!< destructor void SetReferenceTime(); //!< sets the reference time to the current time - gZone & SetPosition ( eCoord const & position ); //!< Sets the current position - eCoord GetPosition ( void ) const; //!< Gets the current position - gZone const & GetPosition ( eCoord & position ) const; //!< Gets the current position - gZone & SetVelocity ( eCoord const & velocity ); //!< Sets the current velocity - eCoord GetVelocity ( void ) const; //!< Gets the current velocity - gZone const & GetVelocity ( eCoord & velocity ) const; //!< Gets the current velocity - gZone & SetRadius ( REAL radius ); //!< Sets the current radius - REAL GetRadius ( void ) const; //!< Gets the current radius - gZone const & GetRadius ( REAL & radius ) const; //!< Gets the current radius - gZone & SetExpansionSpeed ( REAL expansionSpeed ); //!< Sets the current expansion speed - REAL GetExpansionSpeed ( void ) const; //!< Gets the current expansion speed - gZone const & GetExpansionSpeed ( REAL & expansionSpeed ) const;//!< Gets the current expansion speed - gZone & SetRotationSpeed ( REAL rotationSpeed ); //!< Sets the current rotation speed - REAL GetRotationSpeed ( void ) const; //!< Gets the current rotation speed - gZone const & GetRotationSpeed ( REAL & rotationSpeed ) const; //!< Gets the current rotation speed - gZone & SetRotationAcceleration( REAL rotationAcceleration ); //!< Sets the current acceleration of the rotation - REAL GetRotationAcceleration( void ) const; //!< Gets the current acceleration of the rotation - gZone const & GetRotationAcceleration( REAL & rotationAcceleration ) const; //!< Gets the current acceleration of the rotation + //!< Sets the current position + gZone & SetPosition ( eCoord const & position ); + //!< Gets the current position + eCoord GetPosition ( void ) const; + //!< Gets the current position + gZone const & GetPosition ( eCoord & position ) const; + //!< Sets the current velocity + gZone & SetVelocity ( eCoord const & velocity ); + //!< Gets the current velocity + eCoord GetVelocity ( void ) const; + //!< Gets the current velocity + gZone const & GetVelocity ( eCoord & velocity ) const; + //!< Sets the current radius + gZone & SetRadius ( REAL radius ); + //!< Sets the radius to go to smoothly + gZone & SetRadiusSmoothly ( REAL radius, REAL expansionSpeed = 5); + //!< Gets the current radius + REAL GetRadius ( void ) const; + //!< Gets the current radius + gZone const & GetRadius ( REAL & radius ) const; + //!< Sets the current expansion speed + gZone & SetExpansionSpeed ( REAL expansionSpeed ); + //!< Gets the current expansion speed + REAL GetExpansionSpeed ( void ) const; + //!< Gets the current expansion speed + gZone const & GetExpansionSpeed ( REAL & expansionSpeed ) const; + //!< Sets the current rotation speed + gZone & SetRotationSpeed ( REAL rotationSpeed ); + //!< Gets the current rotation speed + REAL GetRotationSpeed ( void ) const; + //!< Gets the current rotation speed + gZone const & GetRotationSpeed ( REAL & rotationSpeed ) const; + //!< Sets the current acceleration of the rotation + gZone & SetRotationAcceleration( REAL rotationAcceleration ); + //!< Gets the current acceleration of the rotation + REAL GetRotationAcceleration( void ) const; + //!< Gets the current acceleration of the rotation + gZone const & GetRotationAcceleration( REAL & rotationAcceleration ) const; - gZone & SetColor (gRealColor color) {color_ = color; return *this;} //!< Sets the current color - gRealColor & GetColor () {return color_;} //!< Gets the current color - gZone & GetColor (gRealColor & color) {color = color_; return *this;} //!< Gets the current color - gZone & SetOwner (ePlayerNetID *pOwner) {pOwner_ = pOwner; return *this;} //!< Sets the current owner - ePlayerNetID * GetOwner () {return pOwner_;} //!< Sets the current owner - gZone & SetSeekingCycle (gCycle *pCycle) {if (pCycle) {seeking_ = true;} else {seeking_ = false;} pSeekingCycle_ = pCycle; return *this;} //!< Sets the current seeking cycle - gCycle * GetSeekingCycle () {return pSeekingCycle_;} //!< Sets the current seeking cycle - gZone & SetTargetRadius (REAL radius) {targetRadius_ = radius; return *this;} //!< Sets the target radius - gZone & SetFallSpeed (REAL speed) {fallSpeed_ = speed; return *this;} //!< Sets the fall speed - void BounceOffPoint(eCoord dest, eCoord collide, REAL mod); + gZone & SetWallInteract (bool wallInteract) {wallInteract_=wallInteract; return *this;} + gZone & SetWallBouncesLeft (int wallBouncesLeft) {wallBouncesLeft_=wallBouncesLeft; return *this;} + //!< Sets the current color + gZone & SetColor (gRealColor color) + { + color_ = color; return *this; + } + //!< Gets the current color + gRealColor & GetColor () + { + return color_; + } + //!< Gets the current color + gZone & GetColor (gRealColor & color) + { + color = color_; return *this; + } + //!< Sets the current owner + gZone & SetOwner (ePlayerNetID *pOwner) + { + pOwner_ = pOwner; return *this; + } + //!< Sets the current owner + ePlayerNetID * GetOwner () + { + return pOwner_; + } + //!< Sets the current seeking cycle + gZone & SetSeekingCycle (gCycle *pCycle) + { + if (pCycle) + { + seeking_ = true; + } + else + { + seeking_ = false; + } + pSeekingCycle_ = pCycle; return *this; + } + //!< Sets the current seeking cycle + gCycle * GetSeekingCycle () + { + return pSeekingCycle_; + } + //!< Sets the target radius + gZone & SetTargetRadius (REAL radius) + { + targetRadius_ = radius; return *this; + } + //!< Sets the fall speed + gZone & SetFallSpeed (REAL speed) + { + fallSpeed_ = speed; return *this; + } + void BounceOffPoint(eCoord dest, eCoord collide); + + gZone & AddWaypoint(eCoord const &point); void Destroy(); bool destroyed_; + tString GetName() {return name_;} + void SetName(tString name) {name_ = name;} + static int FindFirst(tString name); + static int FindNext(tString name, int prev_pos); protected: bool wallInteract_; int wallBouncesLeft_; - eWall *pLastWall_; + REAL lastImpactTime_; + REAL newImpactTime_; + eCoord newImpactPos_; + eCoord newImpactVelocity_; bool dynamicCreation_; //??? remove ePlayerNetID *pOwner_; gCycle *pSeekingCycle_; //!< cycle owner of this zone bool seeking_; REAL targetRadius_; + REAL expectedRadius_; + bool resizeRequested_; + REAL previousExpansionSpeed_; REAL fallSpeed_; REAL lastSeekTime_; + tString name_; gRealColor color_; //!< the zone's color REAL createTime_; //!< the time the zone was created at @@ -133,30 +222,48 @@ tFunction rotationSpeed_; //!< the zone's rotation speed eCoord rotation_; //!< the current rotation state - virtual bool Timestep(REAL currentTime); //!< simulates behaviour up to currentTime + std::vector route_; + unsigned int lastCoord_; + REAL nextUpdate_; + + //!< simulates behaviour up to currentTime + virtual bool Timestep(REAL currentTime); virtual void OnVanish(); //!< called when the zone vanishes private: - virtual void WriteCreate(nMessage &m); //!< writes data for network constructor - virtual void WriteSync(nMessage &m); //!< writes sync data - virtual void ReadSync(nMessage &m); //!< reads sync data + //!< writes data for network constructor + virtual void WriteCreate(nMessage &m); + //!< writes sync data + virtual void WriteSync(nMessage &m); + //!< reads sync data + virtual void ReadSync(nMessage &m); - virtual void InteractWith( eGameObject *target,REAL time,int recursion=1 ); //!< looks for objects inzide the zone and reacts on them + //!< looks for objects inzide the zone and reacts on them + virtual void InteractWith( eGameObject *target,REAL time,int recursion=1 ); - virtual void OnEnter( gCycle *target, REAL time ); //!< reacts on objects inside the zone - virtual void OnEnter( gZone *target, REAL time ); //!< reacts on objects inside the zone + //!< reacts on objects inside the zone + virtual void OnEnter( gCycle *target, REAL time ); + //!< reacts on objects inside the zone + virtual void OnEnter( gZone *target, REAL time ); - virtual nDescriptor& CreatorDescriptor() const; //!< returns the descriptor to recreate this object over the network + //!< returns the descriptor to recreate this object over the network + virtual nDescriptor& CreatorDescriptor() const; REAL Radius() const; //!< returns the current radius - virtual void Render(const eCamera *cam); //!< renders the zone + //!< renders the zone + virtual void Render(const eCamera *cam); + + //! draws it in a svg file + virtual void DrawSvg(std::ofstream &f); //! returns whether the rendering uses alpha blending (massively, so sorting errors would show) virtual bool RendersAlpha() const; - inline REAL EvaluateFunctionNow( tFunction const & f ) const; //!< evaluates the given function with lastTime - referenceTime_ as argument - inline void SetFunctionNow( tFunction & f, REAL value ) const; //!< makes sure EvaluateFunctionNow() returns the given value + //!< evaluates the given function with lastTime - referenceTime_ as argument + inline REAL EvaluateFunctionNow( tFunction const & f ) const; + //!< makes sure EvaluateFunctionNow() returns the given value + inline void SetFunctionNow( tFunction & f, REAL value ) const; }; // all the following zones are hacks until the full zone system is in place @@ -165,13 +272,16 @@ class gWinZoneHack: public gZone { public: - gWinZoneHack(eGrid *grid, const eCoord &pos); //!< local constructor - gWinZoneHack(nMessage &m); //!< network constructor + //!< local constructor + gWinZoneHack(eGrid *grid, const eCoord &pos, bool dynamicCreation = false); + //!< network constructor + gWinZoneHack(nMessage &m); ~gWinZoneHack(); //!< destructor protected: private: - virtual void OnEnter( gCycle *target, REAL time ); //!< reacts on objects inside the zone (declares them the winner) + //!< reacts on objects inside the zone (declares them the winner) + virtual void OnEnter( gCycle *target, REAL time ); }; //! death zone: kills players who enter @@ -190,16 +300,20 @@ NUM_DEATH_ZONE_TYPES }; - gDeathZoneHack(eGrid *grid, const eCoord &pos, bool dynamicCreation = false ); //!< local constructor - gDeathZoneHack(nMessage &m); //!< network constructor + //!< local constructor + gDeathZoneHack(eGrid *grid, const eCoord &pos, bool dynamicCreation = false, eTeam * teamowner = NULL ); + //!< network constructor + gDeathZoneHack(nMessage &m); ~gDeathZoneHack(); //!< destructor gDeathZoneHack *pLastShotCollision; - gZone & SetType (int type); //!< Sets the current type + //!< Sets the current type + gZone & SetType (int type); int GetType () {return (deathZoneType);} - virtual void OnEnter( gDeathZoneHack *target, REAL time ); //!< reacts on objects inside the zone + //!< reacts on objects inside the zone + virtual void OnEnter( gDeathZoneHack *target, REAL time ); protected: virtual void OnVanish(); //!< called when the zone vanishes @@ -207,7 +321,35 @@ int deathZoneType; private: - virtual void OnEnter( gCycle *target, REAL time ); //!< reacts on objects inside the zone (kills them) + //!< reacts on objects inside the zone (kills them) + virtual void OnEnter( gCycle *target, REAL time ); + + gCycle * getPlayerCycle(ePlayerNetID *pPlayer); +}; +//! Rubber zone: Increase players rubber on enter +class gRubberZoneHack: public gZone +{ + public: + + //!< local constructor + gRubberZoneHack(eGrid *grid, const eCoord &pos, bool dynamicCreation = false); + //!< network constructor + gRubberZoneHack(nMessage &m); + ~gRubberZoneHack(); //!< destructor + + + //!< Sets the current rubber + gZone & SetRubber (REAL rubber); + REAL GetRubber () {return (rmRubber);} + + //!< reacts on objects inside the zone + protected: + virtual void OnVanish(); //!< called when the zone vanishes + REAL rmRubber; + + private: + //!< reacts on objects inside the zone (kills them) + virtual void OnEnter( gCycle *target, REAL time ); gCycle * getPlayerCycle(ePlayerNetID *pPlayer); }; @@ -216,31 +358,46 @@ class gBaseZoneHack: public gZone { public: - gBaseZoneHack(eGrid *grid, const eCoord &pos ); //!< local constructor - gBaseZoneHack(nMessage &m); //!< network constructor + //!< local constructor + gBaseZoneHack(eGrid *grid, const eCoord &pos, bool dynamicCreation = false, eTeam * teamowner = NULL ); + //!< network constructor + gBaseZoneHack(nMessage &m); ~gBaseZoneHack(); //!< destructor + bool CheckTeamAssignment(); //!< Check if this zone is assigned to a team, if not, try to assign one. private: - virtual bool Timestep(REAL currentTime); //!< simulates behaviour up to currentTime + //!< simulates behaviour up to currentTime + virtual bool Timestep(REAL currentTime); - virtual void OnEnter( gCycle *target, REAL time ); //!< reacts on objects inside the zone - virtual void OnEnter( gZone *target, REAL time ); //!< reacts on objects inside the zone + //!< reacts on objects inside the zone + virtual void OnEnter( gCycle *target, REAL time ); + //!< reacts on objects inside the zone + virtual void OnEnter( gZone *target, REAL time ); virtual void OnVanish(); //!< called when the zone vanishes - virtual void OnConquest(); //!< called when the zone gets conquered - virtual void CheckSurvivor(); //!< checks for the only surviving zone - virtual void OnRoundBegin(); //!< called on the beginning of the round - virtual void OnRoundEnd(); //!< called on the end of the round + //!< called when the zone gets conquered + virtual void OnConquest(); + //!< checks for the only surviving zone + virtual void CheckSurvivor(); + //!< called on the beginning of the round + virtual void OnRoundBegin(); + //!< called on the end of the round + virtual void OnRoundEnd(); void ZoneWasHeld(); //!< call when the zone was held as long as possible with the set game rules - static void CountZonesOfTeam( eGrid const * grid, eTeam * otherTeam, int & count, gBaseZoneHack * & farthest ); //!< counts the zones belonging to the given team. + //!< counts the zones belonging to the given team. + static void CountZonesOfTeam( eGrid const * grid, eTeam * otherTeam, int & count, gBaseZoneHack * & farthest ); REAL conquered_; //!< conquest status; zero if it is free, 1 if it has been completely conquered by the enemy + //!< time spend in the zone + REAL conquerer_[MAXCLIENTS+1]; int enemiesInside_; //!< count of enemies currently inside the zone - tColoredString enemyPlayerName_; //!< name of the first enemy player that was inside us + //!< name of the first enemy player that was inside us + tColoredString enemyPlayerName_; int ownersInside_; //!< count of owners currently inside the zone - tColoredString teamPlayerName_; //!< name of the first team player that was inside us + //!< name of the first team player that was inside us + tColoredString teamPlayerName_; bool onlySurvivor_; //!< flag set if this zone is the only survivor @@ -270,8 +427,10 @@ class gBallZoneHack: public gZone { public: - gBallZoneHack(eGrid *grid, const eCoord &pos ); //!< local constructor - gBallZoneHack(nMessage &m); //!< network constructor + //!< local constructor + gBallZoneHack(eGrid *grid, const eCoord &pos, bool dynamicCreation = false, eTeam * teamowner = NULL ); + //!< network constructor + gBallZoneHack(nMessage &m); ~gBallZoneHack(); //!< destructor void RemovePlayer(ePlayerNetID *player); @@ -279,11 +438,16 @@ void GoHome(); protected: + bool init_; eCoord originalPosition_; + eCoord originalVelocity_; private: virtual void OnVanish(); //!< called when the zone vanishes - virtual void OnEnter( gCycle *target, REAL time ); //!< reacts on objects inside the zone (kills them) + //!< simulates behaviour up to currentTime + virtual bool Timestep(REAL currentTime); + //!< reacts on objects inside the zone (kills them) + virtual void OnEnter( gCycle *target, REAL time ); tJUST_CONTROLLED_PTR lastPlayer_; }; @@ -291,7 +455,8 @@ class gFlagZoneHack: public gZone { public: - gFlagZoneHack(eGrid *grid, const eCoord &pos ); //!< local constructor + //!< local constructor + gFlagZoneHack(eGrid *grid, const eCoord &pos, bool dynamicCreation = false, eTeam * teamowner = NULL ); gFlagZoneHack(nMessage &m); //!< network constructor ~gFlagZoneHack(); //!< destructor @@ -325,6 +490,71 @@ virtual void OnEnter( gCycle *target, REAL time ); //!< reacts on objects inside the zone (kills them) }; +class gTargetZoneHack: public gZone +{ + public: + //!< local constructor + gTargetZoneHack(eGrid *grid, const eCoord &pos, bool dynamicCreation = false ); + //!< network constructor + gTargetZoneHack(nMessage &m); + ~gTargetZoneHack(); //!< destructor + + protected: + + private: + //!< simulates behaviour up to currentTime + virtual bool Timestep(REAL currentTime); + virtual void OnVanish(); //!< called when the zone vanishes + //!< reacts on objects inside the zone + virtual void OnEnter( gCycle *target, REAL time ); + + //!< count check zone on grid + static int TargetZoneCounter_; + static REAL winnerTime_; //!< game time when a winner can be declared if nothing happens soon + //!< first player entering the last zone to be declare winner + static ePlayerNetID *winner_; + //!< first player entering the zone + ePlayerNetID *firstPlayer_; + //!< flags for players who already use the zone + int playersFlags[MAXCLIENTS+1]; + int zoneInitialScore_; //!< score to give to the first player entering the zone + int zoneScore_; //!< score to give to the next player entering the zone + int zoneScoreDeplete_; //!< value to substract from score each time a player enter the zone + REAL timeFirstEntry_; //!< game time of the first player entering the zone + REAL targetEmptyTime_; //!< game time of the last points granted ... + //! possible states + enum State + { + State_Safe, //!< not yet conquered + State_Conquering, //!< conquering in this frame + State_Conquered //!< conquered + }; + State currentState_; //!< the current state + tString OnEnterCmd, OnVanishCmd; //!< commands to be parse when the first player enter the target and when the target vanish + public: + void SetOnEnterCmd(tString &cmd, tString &mode) {if (mode=="add") OnEnterCmd << "\n" << cmd; else OnEnterCmd = cmd;}; + void SetOnVanishCmd(tString &cmd, tString &mode) {if (mode=="add") OnVanishCmd << "\n" << cmd; else OnVanishCmd = cmd;}; +}; + +class gBlastZoneHack: public gZone +{ + public: + //!< local constructor + gBlastZoneHack(eGrid *grid, const eCoord &pos, bool dynamicCreation = false ); + //!< network constructor + gBlastZoneHack(nMessage &m); + ~gBlastZoneHack(); //!< destructor + + protected: + + private: + //!< simulates behaviour up to currentTime + virtual bool Timestep(REAL currentTime); + virtual void OnVanish(); //!< called when the zone vanishes + //!< reacts on objects inside the zone + virtual void OnEnter( gCycle *target, REAL time ); +}; + //! creates a win or death zone (according to configuration) at the specified position gZone * sg_CreateWinDeathZone( eGrid * grid, const eCoord & pos );