3
*************************************************************************
5
ArmageTron -- Just another Tron Lightcycle Game in 3D.
6
Copyright (C) 2000 Manuel Moos (manuel@moosnet.de)
8
**************************************************************************
10
This program is free software; you can redistribute it and/or
11
modify it under the terms of the GNU General Public License
12
as published by the Free Software Foundation; either version 2
13
of the License, or (at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
***************************************************************************
42
#include "eSoundMixer.h"
49
static int sg_zoneAlphaToggle = 0;
50
static tSettingItem<int> sg_zoneAlphaToggleConf( "ZONE_ALPHA_TOGGLE", sg_zoneAlphaToggle );
52
std::deque<gZone *> sg_Zones;
54
static int sg_zoneDeath = 1;
55
static tSettingItem<int> sg_zoneDeathConf( "WIN_ZONE_DEATHS", sg_zoneDeath );
57
REAL sg_expansionSpeed = 1.0f;
58
REAL sg_initialSize = 5.0f;
60
static nSettingItem< REAL > sg_expansionSpeedConf( "WIN_ZONE_EXPANSION", sg_expansionSpeed );
61
static nSettingItem< REAL > sg_initialSizeConf( "WIN_ZONE_INITIAL_SIZE", sg_initialSize );
63
static int sg_zoneSegments = 11;
64
static tSettingItem<int> sg_zoneSegmentsConf( "ZONE_SEGMENTS", sg_zoneSegments );
66
static REAL sg_zoneSegLength = .5;
67
static tSettingItem<REAL> sg_zoneSegLengthConf( "ZONE_SEG_LENGTH", sg_zoneSegLength );
69
static REAL sg_zoneBottom = 0.0f;
70
static tSettingItem<REAL> sg_zoneBottomConf( "ZONE_BOTTOM", sg_zoneBottom );
72
static REAL sg_zoneHeight = 5.0f;
73
static tSettingItem<REAL> sg_zoneHeightConf( "ZONE_HEIGHT", sg_zoneHeight );
76
//! creates a win or death zone (according to configuration) at the specified position
77
gZone * sg_CreateWinDeathZone( eGrid * grid, const eCoord & pos )
82
ret = tNEW( gDeathZoneHack( grid, pos ) );
83
sn_ConsoleOut( "$instant_death_activated" );
87
ret = tNEW( gWinZoneHack( grid, pos ) );
88
if ( sg_currentSettings->gameType != gFREESTYLE )
90
sn_ConsoleOut( "$instant_win_activated" );
94
sn_ConsoleOut( "$instant_round_end_activated" );
98
// initialize radius and expansion speed
99
static_cast<eGameObject*>(ret)->Timestep( se_GameTime() );
100
ret->SetReferenceTime();
101
ret->SetRadius( sg_initialSize );
102
ret->SetExpansionSpeed( sg_expansionSpeed );
103
ret->SetRotationSpeed( .3f );
108
// number of segments to render a zone with
109
static const int sg_segments = 11;
111
// *******************************************************************************
113
// * EvaluateFunctionNow
115
// *******************************************************************************
117
//! @param f function to evaluate
118
//! @return the function's value at lastTime - referenceTime_
120
// *******************************************************************************
122
inline REAL gZone::EvaluateFunctionNow( tFunction const & f ) const
124
return f( lastTime - referenceTime_ );
127
// *******************************************************************************
131
// *******************************************************************************
133
//! @param f function to modify
134
//! @param value value the function should have at lastTime - referenceTime_
136
// *******************************************************************************
138
inline void gZone::SetFunctionNow( tFunction & f, REAL value ) const
140
f.SetOffset( value + f.GetSlope() * ( referenceTime_ - lastTime ) );
143
// *******************************************************************************
147
// *******************************************************************************
149
//! @param grid Grid to put the zone into
150
//! @param pos Position to spawn the zone at
152
// *******************************************************************************
154
gZone::gZone( eGrid * grid, const eCoord & pos )
155
:eNetGameObject( grid, pos, eCoord( 0,0 ), NULL, true ), rotation_(1,0)
157
// store creation time
158
referenceTime_ = createTime_ = lastTime = 0;
163
sg_Zones.push_back(this);
165
// initialize position functions
167
eSoundMixer* mixer = eSoundMixer::GetMixer();
168
mixer->PushButton(ZONE_SPAWN, pos);
171
// *******************************************************************************
175
// *******************************************************************************
177
//! @param m Message to read creation data from
179
// *******************************************************************************
181
gZone::gZone( nMessage & m )
182
:eNetGameObject( m ), rotation_(1,0)
184
// read creation time
186
referenceTime_ = lastTime = createTime_;
188
// initialize color to white, ReadSync will fill in the true value if available
189
color_.r_ = color_.g_ = color_.b_ = 1.0f;
194
sg_Zones.push_back(this);
196
// initialize position functions
198
eSoundMixer* mixer = eSoundMixer::GetMixer();
199
mixer->PushButton(ZONE_SPAWN, pos);
202
// *******************************************************************************
206
// *******************************************************************************
209
// *******************************************************************************
211
gZone::~gZone( void )
218
std::equal_to<gZone *>(),
224
// *******************************************************************************
228
// *******************************************************************************
230
//! @param m Message to write creation data to
232
// *******************************************************************************
234
void gZone::WriteCreate( nMessage & m )
237
eNetGameObject::WriteCreate( m );
242
// *******************************************************************************
246
// *******************************************************************************
248
//! @param m Message to write sync data to
250
// *******************************************************************************
252
void gZone::WriteSync( nMessage & m )
255
eNetGameObject::WriteSync( m );
262
// write reference time and functions
268
// write rotation speed
272
// *******************************************************************************
276
// *******************************************************************************
278
//! @param m Message to read sync data from
280
// *******************************************************************************
282
void gZone::ReadSync( nMessage & m )
285
eNetGameObject::ReadSync( m );
293
se_MakeColorValid(color_.r_, color_.g_, color_.b_, 1.0f);
296
// read reference time and functions
306
referenceTime_ = createTime_;
308
// take old default values
309
this->radius_.SetOffset( sg_initialSize );
310
this->radius_.SetSlope( sg_expansionSpeed );
312
SetVelocity( eCoord() );
315
// read rotation speed
323
SetRotationSpeed( .3f );
324
SetRotationAcceleration( 0.0f );
328
// *******************************************************************************
332
// *******************************************************************************
334
//! @param time the current time
336
// *******************************************************************************
338
bool gZone::Timestep( REAL time )
341
REAL speed = GetRotationSpeed();
342
REAL angle = ( time - lastTime ) * speed;
343
// angle /= ( 1 + 2 * 3.14159 * angle/sg_segments );
344
rotation_ = rotation_.Turn( cos( angle ), sin( angle ) );
346
// move to new position
347
REAL dt = time - referenceTime_;
348
Move( eCoord( posx_( dt ), posy_( dt ) ), lastTime, time );
353
// kill this zone if it shrunk down to zero radius
354
if ( GetExpansionSpeed() < 0 && GetRadius() <= 0 )
363
// *******************************************************************************
367
// *******************************************************************************
370
// *******************************************************************************
372
void gZone::OnVanish( void )
376
// *******************************************************************************
380
// *******************************************************************************
382
//! @param target the other game object
383
//! @param time the current time
384
//! @param recursion if set to true, don't recurse into other InteractWith functions (quite silly now that I think about it...)
386
// *******************************************************************************
388
void gZone::InteractWith( eGameObject * target, REAL time, int recursion )
390
gCycle* prey = dynamic_cast< gCycle* >( target );
393
REAL r = this->Radius();
394
if ( ( prey->Position() - this->Position() ).NormSquared() < r*r )
396
if ( prey->Player() && prey->Alive() )
398
OnEnter( prey, time );
404
// *******************************************************************************
408
// *******************************************************************************
410
//! @param target the cycle that has been found inside the zone
411
//! @param time the current time
413
// *******************************************************************************
415
void gZone::OnEnter( gCycle * target, REAL time )
419
// the zone's network initializator
420
static nNOInitialisator<gZone> zone_init(340,"zone");
422
// *******************************************************************************
424
// * CreatorDescriptor
426
// *******************************************************************************
430
// *******************************************************************************
432
nDescriptor & gZone::CreatorDescriptor( void ) const
437
// *******************************************************************************
441
// *******************************************************************************
445
// *******************************************************************************
447
REAL gZone::Radius( void ) const
452
// extra alpha blending factors
453
static REAL sg_zoneAlpha = 1.0, sg_zoneAlphaServer = 1.0;
454
static tSettingItem< REAL > sg_zoneAlphaConf( "ZONE_ALPHA", sg_zoneAlpha );
455
static nSettingItem< REAL > sg_zoneAlphaConfServer( "ZONE_ALPHA_SERVER", sg_zoneAlphaServer );
457
// *******************************************************************************
461
// *******************************************************************************
463
//! @param cam the camera used for rendering
465
// *******************************************************************************
467
void gZone::Render( const eCamera * cam )
470
if ( sg_zoneSegLength <= 0 )
471
sg_zoneSegLength = .5;
472
if ( sg_zoneSegments < 1 )
473
sg_zoneSegments = 11;
475
color_.a_ = ( lastTime - createTime_ ) * .2f;
476
if ( color_.a_ > .7f )
478
if ( color_.a_ <= 0 )
481
color_.a_ *= sg_zoneAlpha * sg_zoneAlphaServer;
486
REAL seglen = 2 * M_PI / sg_zoneSegments * sg_zoneSegLength;
489
GLfloat m[4][4]={{r*rotation_.x,r*rotation_.y,0,0},
490
{-r*rotation_.y,r*rotation_.x,0,0},
491
{0,0,sg_zoneHeight,0},
492
{pos.x,pos.y,sg_zoneBottom,1}};
494
glMultMatrixf(&m[0][0]);
498
bool useAlpha = sr_alphaBlend ? !sg_zoneAlphaToggle : sg_zoneAlphaToggle;
499
static bool lastAlpha = useAlpha;
501
static rDisplayList zoneList;
502
if ( lastAlpha != useAlpha || !zoneList.Call() )
504
lastAlpha = useAlpha;
506
rDisplayListFiller filler( zoneList );
508
glDisable(GL_LIGHT0);
509
glDisable(GL_LIGHT1);
510
glDisable(GL_LIGHTING);
511
glDisable(GL_CULL_FACE);
512
glDepthMask(GL_FALSE);
513
glBlendFunc( GL_SRC_ALPHA, GL_ONE );
514
glDisable(GL_TEXTURE_2D);
520
sr_DepthOffset(true);
524
for ( int i = sg_zoneSegments - 1; i>=0; --i )
526
REAL a = i * 2 * M_PI / REAL( sg_zoneSegments );
534
glVertex3f(sa, ca, 0);
535
glVertex3f(sa, ca, 1);
536
glVertex3f(sb, cb, 1);
537
glVertex3f(sb, cb, 0);
541
glVertex3f(sa, ca, 0);
549
sr_DepthOffset(false);
550
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
551
glDepthMask(GL_TRUE);
558
void gZone::Render2D(tCoord) const {
560
if ( color_.a_ <= 0 )
563
GLfloat m[4][4]={{rotation_.x,rotation_.y,0,0},
564
{-rotation_.y,rotation_.x,0,0},
571
glMultMatrixf(&m[0][0]);
572
// glScalef(.5,.5,.5);
576
const REAL seglen = .2f;
581
for ( int i = sg_segments - 1; i>=0; --i )
583
REAL a = i * 2 * 3.14159 / REAL( sg_segments );
586
REAL sa = r * sin(a);
587
REAL ca = r * cos(a);
588
REAL sb = r * sin(b);
589
REAL cb = r * cos(b);
597
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
598
glDepthMask(GL_TRUE);
604
// *******************************************************************************
608
// *******************************************************************************
610
//! @return True if alpha blending is used
612
// *******************************************************************************
613
bool gZone::RendersAlpha() const
615
return sr_alphaBlend ? !sg_zoneAlphaToggle : sg_zoneAlphaToggle;
618
// *******************************************************************************
622
// *******************************************************************************
624
//! @param grid Grid to put the zone into
625
//! @param pos Position to spawn the zone at
627
// *******************************************************************************
629
gWinZoneHack::gWinZoneHack( eGrid * grid, const eCoord & pos )
637
// *******************************************************************************
641
// *******************************************************************************
643
//! @param m Message to read creation data from
646
// *******************************************************************************
648
gWinZoneHack::gWinZoneHack( nMessage & m )
653
// *******************************************************************************
657
// *******************************************************************************
660
// *******************************************************************************
662
gWinZoneHack::~gWinZoneHack( void )
666
// *******************************************************************************
670
// *******************************************************************************
672
//! @param target the cycle that has been found inside the zone
673
//! @param time the current time
675
// *******************************************************************************
677
void gWinZoneHack::OnEnter( gCycle * target, REAL time )
679
static const char* message="$player_win_instant";
680
sg_DeclareWinner( target->Player()->CurrentTeam(), message );
683
if ( GetExpansionSpeed() >= 0 )
686
SetExpansionSpeed( -GetRadius()*.5 );
691
// *******************************************************************************
695
// *******************************************************************************
697
//! @param grid Grid to put the zone into
698
//! @param pos Position to spawn the zone at
700
// *******************************************************************************
702
gDeathZoneHack::gDeathZoneHack( eGrid * grid, const eCoord & pos )
710
// *******************************************************************************
714
// *******************************************************************************
716
//! @param m Message to read creation data from
719
// *******************************************************************************
721
gDeathZoneHack::gDeathZoneHack( nMessage & m )
726
// *******************************************************************************
730
// *******************************************************************************
733
// *******************************************************************************
735
gDeathZoneHack::~gDeathZoneHack( void )
739
static int score_deathzone=-1;
740
static tSettingItem<int> s_dz("SCORE_DEATHZONE",score_deathzone);
742
// *******************************************************************************
746
// *******************************************************************************
748
//! @param target the cycle that has been found inside the zone
749
//! @param time the current time
751
// *******************************************************************************
753
void gDeathZoneHack::OnEnter( gCycle * target, REAL time )
755
target->Player()->AddScore(score_deathzone, tOutput(), "$player_lose_suicide");
759
// *******************************************************************************
763
// *******************************************************************************
765
//! @param grid Grid to put the zone into
766
//! @param pos Position to spawn the zone at
768
// *******************************************************************************
770
gBaseZoneHack::gBaseZoneHack( eGrid * grid, const eCoord & pos )
771
:gZone( grid, pos), onlySurvivor_( false ), currentState_( State_Safe )
773
enemiesInside_ = ownersInside_ = 0;
777
lastEnemyContact_ = se_GameTime();
780
color_.r_ = color_.g_ = color_.b_ = 0;
783
// *******************************************************************************
787
// *******************************************************************************
789
//! @param m Message to read creation data from
791
// *******************************************************************************
793
gBaseZoneHack::gBaseZoneHack( nMessage & m )
794
: gZone( m ), onlySurvivor_( false ), currentState_( State_Safe )
796
enemiesInside_ = ownersInside_ = 0;
800
lastEnemyContact_ = se_GameTime();
804
// *******************************************************************************
808
// *******************************************************************************
811
// *******************************************************************************
813
gBaseZoneHack::~gBaseZoneHack( void )
817
REAL sg_conquestRate = .5;
818
REAL sg_defendRate = .25;
819
REAL sg_conquestDecayRate = .1;
821
static tSettingItem< REAL > sg_conquestRateConf( "FORTRESS_CONQUEST_RATE", sg_conquestRate );
822
static tSettingItem< REAL > sg_defendRateConf( "FORTRESS_DEFEND_RATE", sg_defendRate );
823
static tSettingItem< REAL > sg_conquestDecayRateConf( "FORTRESS_CONQUEST_DECAY_RATE", sg_conquestDecayRate );
825
// time with no enemy inside a zone before it collapses harmlessly
826
static REAL sg_conquestTimeout = 0;
827
static tSettingItem< REAL > sg_conquestTimeoutConf( "FORTRESS_CONQUEST_TIMEOUT", sg_conquestTimeout );
829
// kill at least than many players from the team that just got its zone conquered
830
static int sg_onConquestKillMin = 0;
831
static tSettingItem< int > sg_onConquestKillMinConfig( "FORTRESS_CONQUERED_KILL_MIN", sg_onConquestKillMin );
833
// and at least this ratio
834
static REAL sg_onConquestKillRatio = 0;
835
static tSettingItem< REAL > sg_onConquestKillRationConfig( "FORTRESS_CONQUERED_KILL_RATIO", sg_onConquestKillRatio );
837
// score you get for conquering a zone
838
static int sg_onConquestScore = 0;
839
static tSettingItem< int > sg_onConquestConquestScoreConfig( "FORTRESS_CONQUERED_SCORE", sg_onConquestScore );
841
// flag indicating whether the team conquering the first zone wins (good for one on one matches)
842
static int sg_onConquestWin = 1;
843
static tSettingItem< int > sg_onConquestConquestWinConfig( "FORTRESS_CONQUERED_WIN", sg_onConquestWin );
845
// maximal number of base zones ownable by a team
846
static int sg_baseZonesPerTeam = 0;
847
static tSettingItem< int > sg_baseZonesPerTeamConfig( "FORTRESS_MAX_PER_TEAM", sg_baseZonesPerTeam );
849
// count zones belonging to the given team.
850
// fill in count and the zone that is farthest to the team.
851
void gBaseZoneHack::CountZonesOfTeam( eGrid const * grid, eTeam * otherTeam, int & count, gBaseZoneHack * & farthest )
856
// check whether other zones are already registered to that team
857
const tList<eGameObject>& gameObjects = grid->GameObjects();
858
for (int j=gameObjects.Len()-1;j>=0;j--)
860
gBaseZoneHack *otherZone=dynamic_cast<gBaseZoneHack *>(gameObjects(j));
862
if ( otherZone && otherTeam == otherZone->Team() )
865
if ( !farthest || otherZone->teamDistance_ > farthest->teamDistance_ )
866
farthest = otherZone;
871
static int sg_onSurviveScore = 0;
872
static tSettingItem< int > sg_onSurviveConquestScoreConfig( "FORTRESS_HELD_SCORE", sg_onSurviveScore );
874
static REAL sg_collapseSpeed = .5;
875
static tSettingItem< REAL > sg_collapseSpeedConfig( "FORTRESS_COLLAPSE_SPEED", sg_collapseSpeed );
878
// *******************************************************************************
882
// *******************************************************************************
884
//! @param time the current time
886
// *******************************************************************************
888
bool gBaseZoneHack::Timestep( REAL time )
890
// no team?!? Get rid of this zone ASAP.
896
if ( currentState_ == State_Conquering )
901
// let it light up in agony
902
if ( sg_collapseSpeed < .4 )
904
color_.r_ = color_.g_ = color_.b_ = 1;
907
SetExpansionSpeed( -GetRadius()*sg_collapseSpeed );
908
SetRotationAcceleration( -GetRotationSpeed()*.4 );
911
currentState_ = State_Conquered;
913
else if ( currentState_ == State_Conquered && GetRotationSpeed() < 0 )
917
SetRotationSpeed( 0 );
918
SetRotationAcceleration( 0 );
919
color_.r_ = color_.g_ = color_.b_ = .5;
923
REAL dt = time - lastTime;
926
REAL conquest = sg_conquestRate * enemiesInside_ - sg_defendRate * ownersInside_ - sg_conquestDecayRate;
927
conquered_ += dt * conquest;
929
if ( touchy_ && enemiesInside_ > 0 )
935
if ( conquered_ < 0 )
940
if ( conquered_ > 1.01 )
946
// set speed according to conquest status
947
if ( currentState_ == State_Safe )
949
REAL maxSpeed = 10 * ( 2 * M_PI ) / sg_segments;
950
REAL omega = .3 + conquered_ * conquered_ * maxSpeed;
951
REAL omegaDot = 2 * conquered_ * conquest * maxSpeed;
953
// determine the time since the last sync (exaggerate for smoother motion in local games)
954
REAL timeStep = lastTime - lastSync_;
955
if ( sn_GetNetState() != nSERVER )
958
if ( sn_GetNetState() != nCLIENT &&
959
( ( fabs( omega - GetRotationSpeed() ) + fabs( omegaDot - GetRotationAcceleration() ) ) * timeStep > .5 ) )
961
SetRotationSpeed( omega );
962
SetRotationAcceleration( omegaDot );
965
lastSync_ = lastTime;
969
// check for enemy contact timeout
970
if ( sg_conquestTimeout > 0 && lastEnemyContact_ + sg_conquestTimeout < time )
974
// if the zone would collapse without defenders, let it collapse now. A smart defender would
975
// have left the zone to let it collapse anyway.
976
if ( sg_conquestDecayRate < 0 )
980
if ( sg_onSurviveScore != 0 )
982
// give player the survive score bonus right now, they deserve it
987
sn_ConsoleOut( tOutput( "$zone_collapse_harmless", team->GetColoredName() ) );
994
// check whether the zone got conquered
995
if ( conquered_ >= 1 )
997
currentState_ = State_Conquering;
1003
enemiesInside_ = ownersInside_ = 0;
1006
bool ret = gZone::Timestep( time );
1009
if ( team && !ret && onlySurvivor_ )
1011
const char* message= ( eTeam::teams.Len() > 2 || sg_onConquestScore ) ? "$player_win_held_fortress" : "$player_win_conquest";
1012
sg_DeclareWinner( team, message );
1018
// *******************************************************************************
1022
// *******************************************************************************
1025
// *******************************************************************************
1027
void gBaseZoneHack::OnVanish( void )
1034
// kill the closest owners of the zone
1035
if ( currentState_ != State_Safe && ( enemies_.size() > 0 || sg_defendRate < 0 ) )
1037
int kills = int( sg_onConquestKillRatio * team->NumPlayers() );
1038
kills = kills > sg_onConquestKillMin ? kills : sg_onConquestKillMin;
1044
ePlayerNetID * closest = NULL;
1045
REAL closestDistance = 0;
1047
// find the closest living owner
1048
for ( int i = team->NumPlayers()-1; i >= 0; --i )
1050
ePlayerNetID * player = team->Player(i);
1051
eNetGameObject * object = player->Object();
1052
if ( object && object->Alive() )
1054
eCoord otherpos = object->Position() - pos;
1055
REAL distance = otherpos.NormSquared();
1056
if ( !closest || distance < closestDistance )
1059
closestDistance = distance;
1066
tColoredString playerName;
1067
playerName = closest->GetColoredName();
1068
playerName << tColoredStringProxy(-1,-1,-1);
1069
sn_ConsoleOut( tOutput("$player_kill_collapse", playerName ) );
1070
closest->Object()->Kill();
1076
// *******************************************************************************
1080
// *******************************************************************************
1083
// *******************************************************************************
1085
static eLadderLogWriter sg_basezoneConqueredWriter("BASEZONE_CONQUERED", true);
1086
static eLadderLogWriter sg_basezoneConquererWriter("BASEZONE_CONQUERER", true);
1088
void gBaseZoneHack::OnConquest( void )
1092
sg_basezoneConqueredWriter << ePlayerNetID::FilterName(team->Name()) << GetPosition().x << GetPosition().y;
1093
sg_basezoneConqueredWriter.write();
1095
float rr = GetRadius();
1097
for(int i = se_PlayerNetIDs.Len()-1; i >=0; --i) {
1098
ePlayerNetID *player = se_PlayerNetIDs(i);
1102
gCycle *cycle = dynamic_cast<gCycle *>(player->Object());
1106
if(cycle->Alive() && (cycle->Position() - Position()).NormSquared() < rr) {
1107
sg_basezoneConquererWriter << player->GetUserName();
1108
sg_basezoneConquererWriter.write();
1112
// calculate score. If nobody really was inside the zone any more, half it.
1113
int totalScore = sg_onConquestScore;
1114
if ( 0 == enemiesInside_ )
1117
// eliminate dead enemies
1118
TeamArray enemiesAlive;
1119
for ( TeamArray::iterator iter = enemies_.begin(); iter != enemies_.end(); ++iter )
1121
eTeam* team = *iter;
1122
if ( team->Alive() )
1123
enemiesAlive.push_back( team );
1125
enemies_ = enemiesAlive;
1127
// add score for successful conquest, divided equally between the teams that are
1129
if ( totalScore && enemies_.size() > 0 )
1134
win.SetTemplateParameter( 3, team->GetColoredName() );
1135
win << "$player_win_conquest_specific";
1139
win << "$player_win_conquest";
1142
int score = totalScore / enemies_.size();
1143
for ( TeamArray::iterator iter = enemies_.begin(); iter != enemies_.end(); ++iter )
1145
(*iter)->AddScore( score, win, tOutput() );
1149
// trigger immediate win
1150
if ( sg_onConquestWin && enemies_.size() > 0 )
1152
static const char* message="$player_win_conquest";
1153
sg_DeclareWinner( enemies_[0], message );
1159
// if this flag is enabled, the last team with a non-conquered zone wins the round.
1160
static int sg_onSurviveWin = 1;
1161
static tSettingItem< int > sg_onSurviveWinConfig( "FORTRESS_SURVIVE_WIN", sg_onSurviveWin );
1163
// *******************************************************************************
1167
// *******************************************************************************
1170
// *******************************************************************************
1172
void gBaseZoneHack::CheckSurvivor( void )
1174
// test if there is only one team with non-conquered zones left
1175
if ( sg_onSurviveWin )
1177
// find surviving team and test whether it is the only one
1178
gBaseZoneHack * survivor = 0;
1179
bool onlySurvivor = true;
1181
const tList<eGameObject>& gameObjects = Grid()->GameObjects();
1182
for (int i=gameObjects.Len()-1;i>=0 && onlySurvivor;i--){
1183
gBaseZoneHack *other=dynamic_cast<gBaseZoneHack *>(gameObjects(i));
1185
if ( other && other->currentState_ == State_Safe && other->team )
1187
if ( survivor && survivor->team != other->team )
1188
onlySurvivor = false;
1195
if ( onlySurvivor && survivor )
1197
survivor->onlySurvivor_ = true;
1202
// *******************************************************************************
1206
// *******************************************************************************
1209
// *******************************************************************************
1211
void gBaseZoneHack::ZoneWasHeld( void )
1214
if ( currentState_ == State_Safe && sg_onSurviveScore != 0 )
1216
// award owning team
1217
if ( team && team->Alive() )
1219
team->AddScore( sg_onSurviveScore, tOutput("$player_win_held_fortress"), tOutput("$player_lose_held_fortress") );
1221
currentState_ = State_Conquering;
1226
// give a little conquering help. The round is almost over, if
1227
// an enemy actually made it into the zone by now, it should be his.
1233
// *******************************************************************************
1237
// *******************************************************************************
1239
//! @return shall the hole process be repeated?
1241
// *******************************************************************************
1243
void gBaseZoneHack::OnRoundBegin( void )
1245
// determine the owning team: the one that has a player spawned closest
1246
// find the closest player
1250
const tList<eGameObject>& gameObjects = Grid()->GameObjects();
1251
gCycle * closest = NULL;
1252
REAL closestDistance = 0;
1253
for (int i=gameObjects.Len()-1;i>=0;i--)
1255
gCycle *other=dynamic_cast<gCycle *>(gameObjects(i));
1259
eTeam * otherTeam = other->Player()->CurrentTeam();
1260
eCoord otherpos = other->Position() - pos;
1261
REAL distance = otherpos.NormSquared();
1262
if ( !closest || distance < closestDistance )
1264
// check whether other zones are already registered to that team
1265
gBaseZoneHack * farthest = NULL;
1267
if ( sg_baseZonesPerTeam > 0 )
1268
CountZonesOfTeam( Grid(), otherTeam, count, farthest );
1270
// only set team if not too many closer other zones are registered
1271
if ( sg_baseZonesPerTeam == 0 || count < sg_baseZonesPerTeam || farthest->teamDistance_ > distance )
1274
closestDistance = distance;
1282
// take over team and color
1283
team = closest->Player()->CurrentTeam();
1284
color_.r_ = team->R()/15.0;
1285
color_.g_ = team->G()/15.0;
1286
color_.b_ = team->B()/15.0;
1287
teamDistance_ = closestDistance;
1292
// if this zone does not belong to a team, discard it.
1299
// check other zones owned by the same team. Discard the one farthest away
1300
// if the max count is exceeded
1301
if ( team && sg_baseZonesPerTeam > 0 )
1303
gBaseZoneHack * farthest = 0;
1305
CountZonesOfTeam( Grid(), team, count, farthest );
1307
// discard team of farthest zone
1308
if ( count > sg_baseZonesPerTeam )
1310
farthest->team = NULL;
1311
farthest->RemoveFromGame();
1317
// *******************************************************************************
1321
// *******************************************************************************
1324
// *******************************************************************************
1326
void gBaseZoneHack::OnRoundEnd( void )
1329
if ( currentState_ == State_Safe )
1335
// *******************************************************************************
1339
// *******************************************************************************
1341
//! @param target the cycle that has been found inside the zone
1342
//! @param time the current time
1344
// *******************************************************************************
1346
void gBaseZoneHack::OnEnter( gCycle * target, REAL time )
1348
// determine the team of the player
1350
if ( !target->Player() )
1352
tJUST_CONTROLLED_PTR< eTeam > otherTeam = target->Player()->CurrentTeam();
1355
if ( currentState_ != State_Safe )
1358
// remember who is inside
1359
if ( team == otherTeam )
1365
if ( enemiesInside_ == 0 )
1369
if ( std::find( enemies_.begin(), enemies_.end(), otherTeam ) == enemies_.end() )
1370
enemies_.push_back( otherTeam );
1372
lastEnemyContact_ = time;
1376
// *******************************************************************************
1380
// *******************************************************************************
1382
//! @return the current position
1384
// *******************************************************************************
1386
eCoord gZone::GetPosition( void ) const
1393
// *******************************************************************************
1397
// *******************************************************************************
1399
//! @param position the current position to fill
1400
//! @return A reference to this to allow chaining
1402
// *******************************************************************************
1404
gZone const & gZone::GetPosition( eCoord & position ) const
1406
position.x = EvaluateFunctionNow( posx_ );
1407
position.y = EvaluateFunctionNow( posy_ );
1411
// *******************************************************************************
1415
// *******************************************************************************
1417
//! @param position the current position to set
1418
//! @return A reference to this to allow chaining
1420
// *******************************************************************************
1422
gZone & gZone::SetPosition( eCoord const & position )
1424
SetFunctionNow( posx_, position.x );
1425
SetFunctionNow( posy_, position.y );
1429
// *******************************************************************************
1433
// *******************************************************************************
1435
//! @return the current velocity
1437
// *******************************************************************************
1439
eCoord gZone::GetVelocity( void ) const
1447
// *******************************************************************************
1451
// *******************************************************************************
1453
//! @param velocity the current velocity to fill
1454
//! @return A reference to this to allow chaining
1456
// *******************************************************************************
1458
gZone const & gZone::GetVelocity( eCoord & velocity ) const
1460
velocity.x = posx_.GetSlope();
1461
velocity.y = posy_.GetSlope();
1466
// *******************************************************************************
1470
// *******************************************************************************
1472
//! @param velocity the current velocity to set
1473
//! @return A reference to this to allow chaining
1475
// *******************************************************************************
1477
gZone & gZone::SetVelocity( eCoord const & velocity )
1483
posx_.SetSlope( velocity.x );
1484
posy_.SetSlope( velocity.y );
1492
// *******************************************************************************
1496
// *******************************************************************************
1498
//! @return the current radius
1500
// *******************************************************************************
1502
REAL gZone::GetRadius( void ) const
1504
REAL ret = EvaluateFunctionNow( this->radius_ );
1505
ret = ret > 0 ? ret : 0;
1510
// *******************************************************************************
1514
// *******************************************************************************
1516
//! @param radius the current radius to fill
1517
//! @return A reference to this to allow chaining
1519
// *******************************************************************************
1521
gZone const & gZone::GetRadius( REAL & radius ) const
1523
radius = GetRadius();
1528
// *******************************************************************************
1532
// *******************************************************************************
1534
//! @param radius the current radius to set
1535
//! @return A reference to this to allow chaining
1537
// *******************************************************************************
1539
gZone & gZone::SetRadius( REAL radius )
1541
SetFunctionNow( this->radius_, radius );
1546
// *******************************************************************************
1548
// * GetExpansionSpeed
1550
// *******************************************************************************
1552
//! @return the current expansion speed
1554
// *******************************************************************************
1556
REAL gZone::GetExpansionSpeed( void ) const
1558
return this->radius_.GetSlope();
1561
// *******************************************************************************
1563
// * GetExpansionSpeed
1565
// *******************************************************************************
1567
//! @param expansionSpeed the current expansion speed to fill
1568
//! @return A reference to this to allow chaining
1570
// *******************************************************************************
1572
gZone const & gZone::GetExpansionSpeed( REAL & expansionSpeed ) const
1574
expansionSpeed = this->radius_.GetSlope();
1579
// *******************************************************************************
1581
// * SetExpansionSpeed
1583
// *******************************************************************************
1585
//! @param expansionSpeed the current expansion speed to set
1586
//! @return A reference to this to allow chaining
1588
// *******************************************************************************
1590
gZone & gZone::SetExpansionSpeed( REAL expansionSpeed )
1592
REAL r = EvaluateFunctionNow( this->radius_ );
1593
this->radius_.SetSlope( expansionSpeed );
1599
// *******************************************************************************
1601
// * SetReferenceTime
1603
// *******************************************************************************
1606
// *******************************************************************************
1608
void gZone::SetReferenceTime( void )
1610
// set offsets to current values
1611
this->posx_.SetOffset( EvaluateFunctionNow( this->posx_ ) );
1612
this->posy_.SetOffset( EvaluateFunctionNow( this->posy_ ) );
1613
this->radius_.SetOffset( EvaluateFunctionNow( this->radius_ ) );
1614
this->rotationSpeed_.SetOffset( EvaluateFunctionNow( this->rotationSpeed_ ) );
1617
this->referenceTime_ = lastTime;
1620
// *******************************************************************************
1622
// * GetRotationSpeed
1624
// *******************************************************************************
1626
//! @return The current rotation speed
1628
// *******************************************************************************
1630
REAL gZone::GetRotationSpeed( void ) const
1632
return EvaluateFunctionNow( rotationSpeed_ );
1635
// *******************************************************************************
1639
// *******************************************************************************
1641
//! @return The current rotation position, as normalized x and y coordinates
1643
// *******************************************************************************
1645
tCoord const &gZone::GetRotation( void ) const
1650
// *******************************************************************************
1652
// * GetRotationSpeed
1654
// *******************************************************************************
1656
//! @param rotationSpeed The current rotation speed to fill
1657
//! @return A reference to this to allow chaining
1659
// *******************************************************************************
1661
gZone const & gZone::GetRotationSpeed( REAL & rotationSpeed ) const
1663
rotationSpeed = this->GetRotationSpeed();
1667
// *******************************************************************************
1669
// * SetRotationSpeed
1671
// *******************************************************************************
1673
//! @param rotationSpeed The current rotation speed to set
1674
//! @return A reference to this to allow chaining
1676
// *******************************************************************************
1678
gZone & gZone::SetRotationSpeed( REAL rotationSpeed )
1680
SetFunctionNow( this->rotationSpeed_, rotationSpeed );
1684
// *******************************************************************************
1686
// * GetRotationAcceleration
1688
// *******************************************************************************
1690
//! @return the current acceleration of the rotation
1692
// *******************************************************************************
1694
REAL gZone::GetRotationAcceleration( void ) const
1696
return this->rotationSpeed_.GetSlope();
1699
// *******************************************************************************
1701
// * GetRotationAcceleration
1703
// *******************************************************************************
1705
//! @param rotationAcceleration the current acceleration of the rotation to fill
1706
//! @return A reference to this to allow chaining
1708
// *******************************************************************************
1710
gZone const & gZone::GetRotationAcceleration( REAL & rotationAcceleration ) const
1712
rotationAcceleration = this->GetRotationAcceleration();
1716
// *******************************************************************************
1720
// *******************************************************************************
1722
//! @return the current color of the zone
1724
// *******************************************************************************
1726
rColor const & gZone::GetColor( void ) const
1731
// *******************************************************************************
1733
// * SetRotationAcceleration
1735
// *******************************************************************************
1737
//! @param rotationAcceleration the current acceleration of the rotation to set
1738
//! @return A reference to this to allow chaining
1740
// *******************************************************************************
1742
gZone & gZone::SetRotationAcceleration( REAL rotationAcceleration )
1744
REAL omega = this->GetRotationSpeed();
1745
this->rotationSpeed_.SetSlope( rotationAcceleration );
1746
SetRotationSpeed( omega );