~z-man/armagetronad/cmake-rescue

« back to all changes in this revision

Viewing changes to src/tron/gWinZone.cpp

  • Committer: z-man
  • Date: 2009-01-18 12:50:55 UTC
  • Revision ID: svn-v3-list-QlpoOTFBWSZTWZvbKhsAAAdRgAAQABK6798QIABURMgAAaeoNT1TxT1DQbKaeobXKiyAmlWT7Y5MkdJOtXDtB7w7DOGFBHiOBxaUIu7HQyyQSvxdyRThQkJvbKhs:7d95bf1e-0414-0410-9756-b78462a59f44:armagetronad%2Ftrunk%2Farmagetronad:8853
Merging branch 0.2.8 from revision 8841 to 8852:
(Also: finally got gWinZone.* back in sync with 0.2.8. Future merges
 should be possible again, yay.)
 ------------------------------------------------------------------------
 r8851 | bazaarmagetron | 2009-01-18 01:48:12 +0100 (Sun, 18 Jan 2009) | 2 lines
 
 Manuel Moos: Applied hoop's zone rendering patch. 'tis good.

 ------------------------------------------------------------------------

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
*************************************************************************
 
4
 
 
5
ArmageTron -- Just another Tron Lightcycle Game in 3D.
 
6
Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
 
7
 
 
8
**************************************************************************
 
9
 
 
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.
 
14
 
 
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.
 
19
 
 
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.
 
23
  
 
24
***************************************************************************
 
25
 
 
26
*/
 
27
 
 
28
#include "rSDL.h"
 
29
 
 
30
#include "gWinZone.h"
 
31
#include "eFloor.h"
 
32
#include "eTimer.h"
 
33
#include "eGrid.h"
 
34
#include "gCycle.h"
 
35
#include "gGame.h"
 
36
#include "eTeam.h"
 
37
#include "ePlayer.h"
 
38
#include "rRender.h"
 
39
#include "nConfig.h"
 
40
#include "tString.h"
 
41
#include "rScreen.h"
 
42
#include "eSoundMixer.h"
 
43
 
 
44
#include <time.h>
 
45
#include <algorithm>
 
46
#include <functional>
 
47
#include <deque>
 
48
 
 
49
static int sg_zoneAlphaToggle = 0;
 
50
static tSettingItem<int> sg_zoneAlphaToggleConf( "ZONE_ALPHA_TOGGLE", sg_zoneAlphaToggle );
 
51
 
 
52
std::deque<gZone *> sg_Zones;
 
53
 
 
54
static int sg_zoneDeath = 1;
 
55
static tSettingItem<int> sg_zoneDeathConf( "WIN_ZONE_DEATHS", sg_zoneDeath );
 
56
 
 
57
REAL sg_expansionSpeed = 1.0f;
 
58
REAL sg_initialSize = 5.0f;
 
59
 
 
60
static nSettingItem< REAL > sg_expansionSpeedConf( "WIN_ZONE_EXPANSION", sg_expansionSpeed );
 
61
static nSettingItem< REAL > sg_initialSizeConf( "WIN_ZONE_INITIAL_SIZE", sg_initialSize );
 
62
 
 
63
static int sg_zoneSegments = 11;
 
64
static tSettingItem<int> sg_zoneSegmentsConf( "ZONE_SEGMENTS", sg_zoneSegments );
 
65
 
 
66
static REAL sg_zoneSegLength = .5;
 
67
static tSettingItem<REAL> sg_zoneSegLengthConf( "ZONE_SEG_LENGTH", sg_zoneSegLength );
 
68
 
 
69
static REAL sg_zoneBottom = 0.0f;
 
70
static tSettingItem<REAL> sg_zoneBottomConf( "ZONE_BOTTOM", sg_zoneBottom );
 
71
 
 
72
static REAL sg_zoneHeight = 5.0f;
 
73
static tSettingItem<REAL> sg_zoneHeightConf( "ZONE_HEIGHT", sg_zoneHeight );
 
74
 
 
75
 
 
76
//! creates a win or death zone (according to configuration) at the specified position
 
77
gZone * sg_CreateWinDeathZone( eGrid * grid, const eCoord & pos )
 
78
{
 
79
    gZone * ret = NULL;
 
80
    if ( sg_zoneDeath )
 
81
    {
 
82
        ret = tNEW( gDeathZoneHack( grid, pos ) );
 
83
        sn_ConsoleOut( "$instant_death_activated" );
 
84
    }
 
85
    else
 
86
    {
 
87
        ret = tNEW( gWinZoneHack( grid, pos ) );
 
88
        if ( sg_currentSettings->gameType != gFREESTYLE )
 
89
        {
 
90
            sn_ConsoleOut( "$instant_win_activated" );
 
91
        }
 
92
        else
 
93
        {
 
94
            sn_ConsoleOut( "$instant_round_end_activated" );
 
95
        }
 
96
    }
 
97
 
 
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 );
 
104
 
 
105
    return ret;
 
106
}
 
107
 
 
108
// number of segments to render a zone with
 
109
static const int sg_segments = 11;
 
110
 
 
111
// *******************************************************************************
 
112
// *
 
113
// *   EvaluateFunctionNow
 
114
// *
 
115
// *******************************************************************************
 
116
//!
 
117
//!        @param  f   function to evaluate
 
118
//!        @return     the function's value at lastTime - referenceTime_
 
119
//!
 
120
// *******************************************************************************
 
121
 
 
122
inline REAL gZone::EvaluateFunctionNow( tFunction const & f ) const
 
123
{
 
124
    return f( lastTime - referenceTime_ );
 
125
}
 
126
 
 
127
// *******************************************************************************
 
128
// *
 
129
// *   SetFunctionNow
 
130
// *
 
131
// *******************************************************************************
 
132
//!
 
133
//!        @param  f      function to modify
 
134
//!        @param  value  value the function should have at lastTime - referenceTime_
 
135
//!
 
136
// *******************************************************************************
 
137
 
 
138
inline void gZone::SetFunctionNow( tFunction & f, REAL value ) const
 
139
{
 
140
    f.SetOffset( value + f.GetSlope() * ( referenceTime_ - lastTime ) );
 
141
}
 
142
 
 
143
// *******************************************************************************
 
144
// *
 
145
// *    gZone
 
146
// *
 
147
// *******************************************************************************
 
148
//!
 
149
//!             @param  grid Grid to put the zone into
 
150
//!             @param  pos      Position to spawn the zone at
 
151
//!
 
152
// *******************************************************************************
 
153
 
 
154
gZone::gZone( eGrid * grid, const eCoord & pos )
 
155
        :eNetGameObject( grid, pos, eCoord( 0,0 ), NULL, true ), rotation_(1,0)
 
156
{
 
157
    // store creation time
 
158
    referenceTime_ = createTime_ = lastTime = 0;
 
159
 
 
160
    // add to game grid
 
161
    this->AddToList();
 
162
 
 
163
    sg_Zones.push_back(this);
 
164
 
 
165
    // initialize position functions
 
166
    SetPosition( pos );
 
167
    eSoundMixer* mixer = eSoundMixer::GetMixer();
 
168
    mixer->PushButton(ZONE_SPAWN, pos);
 
169
}
 
170
 
 
171
// *******************************************************************************
 
172
// *
 
173
// *    gZone
 
174
// *
 
175
// *******************************************************************************
 
176
//!
 
177
//!             @param  m Message to read creation data from
 
178
//!
 
179
// *******************************************************************************
 
180
 
 
181
gZone::gZone( nMessage & m )
 
182
        :eNetGameObject( m ), rotation_(1,0)
 
183
{
 
184
    // read creation time
 
185
    m >> createTime_;
 
186
    referenceTime_ = lastTime = createTime_;
 
187
 
 
188
    // initialize color to white, ReadSync will fill in the true value if available
 
189
    color_.r_ = color_.g_ = color_.b_ = 1.0f;
 
190
 
 
191
    // add to game grid
 
192
    this->AddToList();
 
193
 
 
194
    sg_Zones.push_back(this);
 
195
 
 
196
    // initialize position functions
 
197
    SetPosition( pos );
 
198
    eSoundMixer* mixer = eSoundMixer::GetMixer();
 
199
    mixer->PushButton(ZONE_SPAWN, pos);
 
200
}
 
201
 
 
202
// *******************************************************************************
 
203
// *
 
204
// *    ~gZone
 
205
// *
 
206
// *******************************************************************************
 
207
//!
 
208
//!
 
209
// *******************************************************************************
 
210
 
 
211
gZone::~gZone( void )
 
212
{
 
213
    sg_Zones.erase(
 
214
        std::find_if(
 
215
            sg_Zones.begin(),
 
216
            sg_Zones.end(),
 
217
            std::bind2nd(
 
218
                std::equal_to<gZone *>(),
 
219
                this)
 
220
        )
 
221
    );
 
222
}
 
223
 
 
224
// *******************************************************************************
 
225
// *
 
226
// *    WriteCreate
 
227
// *
 
228
// *******************************************************************************
 
229
//!
 
230
//!             @param  m Message to write creation data to
 
231
//!
 
232
// *******************************************************************************
 
233
 
 
234
void gZone::WriteCreate( nMessage & m )
 
235
{
 
236
    // delegate
 
237
    eNetGameObject::WriteCreate( m );
 
238
 
 
239
    m << createTime_;
 
240
}
 
241
 
 
242
// *******************************************************************************
 
243
// *
 
244
// *    WriteSync
 
245
// *
 
246
// *******************************************************************************
 
247
//!
 
248
//!             @param  m Message to write sync data to
 
249
//!
 
250
// *******************************************************************************
 
251
 
 
252
void gZone::WriteSync( nMessage & m )
 
253
{
 
254
    // delegate
 
255
    eNetGameObject::WriteSync( m );
 
256
 
 
257
    // write color
 
258
    m << color_.r_;
 
259
    m << color_.g_;
 
260
    m << color_.b_;
 
261
 
 
262
    // write reference time and functions
 
263
    m << referenceTime_;
 
264
    m << posx_;
 
265
    m << posy_;
 
266
    m << radius_;
 
267
 
 
268
    // write rotation speed
 
269
    m << rotationSpeed_;
 
270
}
 
271
 
 
272
// *******************************************************************************
 
273
// *
 
274
// *    ReadSync
 
275
// *
 
276
// *******************************************************************************
 
277
//!
 
278
//!             @param  m Message to read sync data from
 
279
//!
 
280
// *******************************************************************************
 
281
 
 
282
void gZone::ReadSync( nMessage & m )
 
283
{
 
284
    // delegage
 
285
    eNetGameObject::ReadSync( m );
 
286
 
 
287
    // read color
 
288
    if (!m.End())
 
289
    {
 
290
        m >> color_.r_;
 
291
        m >> color_.g_;
 
292
        m >> color_.b_;
 
293
        se_MakeColorValid(color_.r_, color_.g_, color_.b_, 1.0f);
 
294
    }
 
295
 
 
296
    // read reference time and functions
 
297
    if (!m.End())
 
298
    {
 
299
        m >> referenceTime_;
 
300
        m >> posx_;
 
301
        m >> posy_;
 
302
        m >> radius_;
 
303
    }
 
304
    else
 
305
    {
 
306
        referenceTime_ = createTime_;
 
307
 
 
308
        // take old default values
 
309
        this->radius_.SetOffset( sg_initialSize );
 
310
        this->radius_.SetSlope( sg_expansionSpeed );
 
311
        SetPosition( pos );
 
312
        SetVelocity( eCoord() );
 
313
    }
 
314
 
 
315
    // read rotation speed
 
316
    if (!m.End())
 
317
    {
 
318
        m >> rotationSpeed_;
 
319
    }
 
320
    else
 
321
    {
 
322
        // set fixed values
 
323
        SetRotationSpeed( .3f );
 
324
        SetRotationAcceleration( 0.0f );
 
325
    }
 
326
}
 
327
 
 
328
// *******************************************************************************
 
329
// *
 
330
// *    Timestep
 
331
// *
 
332
// *******************************************************************************
 
333
//!
 
334
//!             @param  time    the current time
 
335
//!
 
336
// *******************************************************************************
 
337
 
 
338
bool gZone::Timestep( REAL time )
 
339
{
 
340
    // rotate
 
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 ) );
 
345
 
 
346
    // move to new position
 
347
    REAL dt = time - referenceTime_;
 
348
    Move( eCoord( posx_( dt ), posy_( dt ) ), lastTime, time );
 
349
 
 
350
    // update time
 
351
    lastTime = time;
 
352
 
 
353
    // kill this zone if it shrunk down to zero radius
 
354
    if ( GetExpansionSpeed() < 0 && GetRadius() <= 0 )
 
355
    {
 
356
        OnVanish();
 
357
        return true;
 
358
    }
 
359
 
 
360
    return false;
 
361
}
 
362
 
 
363
// *******************************************************************************
 
364
// *
 
365
// *    OnVanish
 
366
// *
 
367
// *******************************************************************************
 
368
//!
 
369
//!
 
370
// *******************************************************************************
 
371
 
 
372
void gZone::OnVanish( void )
 
373
{
 
374
}
 
375
 
 
376
// *******************************************************************************
 
377
// *
 
378
// *    InteractWith
 
379
// *
 
380
// *******************************************************************************
 
381
//!
 
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...)
 
385
//!
 
386
// *******************************************************************************
 
387
 
 
388
void gZone::InteractWith( eGameObject * target, REAL time, int recursion )
 
389
{
 
390
    gCycle* prey = dynamic_cast< gCycle* >( target );
 
391
    if ( prey )
 
392
    {
 
393
        REAL r = this->Radius();
 
394
        if ( ( prey->Position() - this->Position() ).NormSquared() < r*r )
 
395
        {
 
396
            if ( prey->Player() && prey->Alive() )
 
397
            {
 
398
                OnEnter( prey, time );
 
399
            }
 
400
        }
 
401
    }
 
402
}
 
403
 
 
404
// *******************************************************************************
 
405
// *
 
406
// *    OnEnter
 
407
// *
 
408
// *******************************************************************************
 
409
//!
 
410
//!             @param  target  the cycle that has been found inside the zone
 
411
//!             @param  time    the current time
 
412
//!
 
413
// *******************************************************************************
 
414
 
 
415
void gZone::OnEnter( gCycle * target, REAL time )
 
416
{
 
417
}
 
418
 
 
419
// the zone's network initializator
 
420
static nNOInitialisator<gZone> zone_init(340,"zone");
 
421
 
 
422
// *******************************************************************************
 
423
// *
 
424
// *    CreatorDescriptor
 
425
// *
 
426
// *******************************************************************************
 
427
//!
 
428
//!             @return
 
429
//!
 
430
// *******************************************************************************
 
431
 
 
432
nDescriptor & gZone::CreatorDescriptor( void ) const
 
433
{
 
434
    return zone_init;
 
435
}
 
436
 
 
437
// *******************************************************************************
 
438
// *
 
439
// *    Radius
 
440
// *
 
441
// *******************************************************************************
 
442
//!
 
443
//!             @return
 
444
//!
 
445
// *******************************************************************************
 
446
 
 
447
REAL gZone::Radius( void ) const
 
448
{
 
449
    return GetRadius();
 
450
}
 
451
 
 
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 );
 
456
 
 
457
// *******************************************************************************
 
458
// *
 
459
// *    Render
 
460
// *
 
461
// *******************************************************************************
 
462
//!
 
463
//!             @param  cam  the camera used for rendering
 
464
//!
 
465
// *******************************************************************************
 
466
 
 
467
void gZone::Render( const eCamera * cam )
 
468
{
 
469
#ifndef DEDICATED
 
470
    if ( sg_zoneSegLength <= 0 )
 
471
        sg_zoneSegLength = .5;
 
472
    if ( sg_zoneSegments < 1 )
 
473
        sg_zoneSegments = 11;
 
474
 
 
475
    color_.a_ = ( lastTime - createTime_ ) * .2f;
 
476
    if ( color_.a_ > .7f )
 
477
        color_.a_ = .7f;
 
478
    if ( color_.a_ <= 0 )
 
479
        return;
 
480
 
 
481
    color_.a_ *= sg_zoneAlpha * sg_zoneAlphaServer;
 
482
 
 
483
    ModelMatrix();
 
484
    glPushMatrix();
 
485
 
 
486
    REAL seglen = 2 * M_PI / sg_zoneSegments * sg_zoneSegLength;
 
487
 
 
488
    REAL r = Radius();
 
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}};
 
493
 
 
494
    glMultMatrixf(&m[0][0]);
 
495
 
 
496
    color_.Apply();
 
497
 
 
498
        bool useAlpha = sr_alphaBlend ? !sg_zoneAlphaToggle : sg_zoneAlphaToggle;
 
499
    static bool lastAlpha = useAlpha;
 
500
 
 
501
    static rDisplayList zoneList;
 
502
    if ( lastAlpha != useAlpha || !zoneList.Call() )
 
503
    {
 
504
        lastAlpha = useAlpha;
 
505
 
 
506
        rDisplayListFiller filler( zoneList );
 
507
        
 
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);
 
515
        
 
516
        if ( useAlpha )
 
517
            BeginQuads();
 
518
        else
 
519
        {
 
520
            sr_DepthOffset(true);
 
521
            BeginLineStrip();
 
522
        }
 
523
 
 
524
        for ( int i = sg_zoneSegments - 1; i>=0; --i )
 
525
        {
 
526
            REAL a = i * 2 * M_PI / REAL( sg_zoneSegments );
 
527
            REAL b = a + seglen;
 
528
            
 
529
            REAL sa = sin(a);
 
530
            REAL ca = cos(a);
 
531
            REAL sb = sin(b);
 
532
            REAL cb = cos(b);
 
533
            
 
534
            glVertex3f(sa, ca, 0);
 
535
            glVertex3f(sa, ca, 1);
 
536
            glVertex3f(sb, cb, 1);
 
537
            glVertex3f(sb, cb, 0);
 
538
            
 
539
            if ( !useAlpha )
 
540
            {
 
541
                glVertex3f(sa, ca, 0);
 
542
                RenderEnd();
 
543
                BeginLineStrip();
 
544
            }
 
545
        }
 
546
        
 
547
        RenderEnd();
 
548
 
 
549
        sr_DepthOffset(false);
 
550
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
 
551
        glDepthMask(GL_TRUE);
 
552
    }
 
553
 
 
554
    glPopMatrix();
 
555
#endif
 
556
}
 
557
 
 
558
void gZone::Render2D(tCoord) const {
 
559
#ifndef DEDICATED
 
560
    if ( color_.a_ <= 0 )
 
561
        return;
 
562
 
 
563
    GLfloat m[4][4]={{rotation_.x,rotation_.y,0,0},
 
564
                     {-rotation_.y,rotation_.x,0,0},
 
565
                     {0,0,1,0},
 
566
                     {pos.x,pos.y,0,1}};
 
567
 
 
568
    ModelMatrix();
 
569
    glPushMatrix();
 
570
 
 
571
    glMultMatrixf(&m[0][0]);
 
572
    //  glScalef(.5,.5,.5);
 
573
 
 
574
    BeginLines();
 
575
 
 
576
    const REAL seglen = .2f;
 
577
 
 
578
    color_.Apply();
 
579
 
 
580
    REAL r = Radius();
 
581
    for ( int i = sg_segments - 1; i>=0; --i )
 
582
    {
 
583
        REAL a = i * 2 * 3.14159 / REAL( sg_segments );
 
584
        REAL b = a + seglen;
 
585
 
 
586
        REAL sa = r * sin(a);
 
587
        REAL ca = r * cos(a);
 
588
        REAL sb = r * sin(b);
 
589
        REAL cb = r * cos(b);
 
590
 
 
591
        glVertex2f(sa, ca);
 
592
        glVertex2f(sb, cb);
 
593
    }
 
594
 
 
595
    RenderEnd();
 
596
 
 
597
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
 
598
    glDepthMask(GL_TRUE);
 
599
 
 
600
    glPopMatrix();
 
601
#endif
 
602
}
 
603
 
 
604
// *******************************************************************************
 
605
// *
 
606
// *    RendersAlpha
 
607
// *
 
608
// *******************************************************************************
 
609
//!
 
610
//!             @return True if alpha blending is used
 
611
//!
 
612
// *******************************************************************************
 
613
bool gZone::RendersAlpha() const
 
614
{
 
615
        return sr_alphaBlend ? !sg_zoneAlphaToggle : sg_zoneAlphaToggle;
 
616
}
 
617
 
 
618
// *******************************************************************************
 
619
// *
 
620
// *    gWinZoneHack
 
621
// *
 
622
// *******************************************************************************
 
623
//!
 
624
//!             @param  grid Grid to put the zone into
 
625
//!             @param  pos      Position to spawn the zone at
 
626
//!
 
627
// *******************************************************************************
 
628
 
 
629
gWinZoneHack::gWinZoneHack( eGrid * grid, const eCoord & pos )
 
630
        :gZone( grid, pos )
 
631
{
 
632
    color_.r_ = 0.0f;
 
633
    color_.g_ = 1.0f;
 
634
    color_.b_ = 0.0f;
 
635
}
 
636
 
 
637
// *******************************************************************************
 
638
// *
 
639
// *    gWinZoneHack
 
640
// *
 
641
// *******************************************************************************
 
642
//!
 
643
//!             @param  m Message to read creation data from
 
644
//!             @param  null
 
645
//!
 
646
// *******************************************************************************
 
647
 
 
648
gWinZoneHack::gWinZoneHack( nMessage & m )
 
649
        : gZone( m )
 
650
{
 
651
}
 
652
 
 
653
// *******************************************************************************
 
654
// *
 
655
// *    ~gWinZoneHack
 
656
// *
 
657
// *******************************************************************************
 
658
//!
 
659
//!
 
660
// *******************************************************************************
 
661
 
 
662
gWinZoneHack::~gWinZoneHack( void )
 
663
{
 
664
}
 
665
 
 
666
// *******************************************************************************
 
667
// *
 
668
// *    OnEnter
 
669
// *
 
670
// *******************************************************************************
 
671
//!
 
672
//!             @param  target  the cycle that has been found inside the zone
 
673
//!             @param  time    the current time
 
674
//!
 
675
// *******************************************************************************
 
676
 
 
677
void gWinZoneHack::OnEnter( gCycle * target, REAL time )
 
678
{
 
679
    static const char* message="$player_win_instant";
 
680
    sg_DeclareWinner( target->Player()->CurrentTeam(), message );
 
681
 
 
682
    // let zone vanish
 
683
    if ( GetExpansionSpeed() >= 0 )
 
684
    {
 
685
        SetReferenceTime();
 
686
        SetExpansionSpeed( -GetRadius()*.5 );
 
687
        RequestSync();
 
688
    }
 
689
}
 
690
 
 
691
// *******************************************************************************
 
692
// *
 
693
// *    gDeathZoneHack
 
694
// *
 
695
// *******************************************************************************
 
696
//!
 
697
//!             @param  grid Grid to put the zone into
 
698
//!             @param  pos      Position to spawn the zone at
 
699
//!
 
700
// *******************************************************************************
 
701
 
 
702
gDeathZoneHack::gDeathZoneHack( eGrid * grid, const eCoord & pos )
 
703
        :gZone( grid, pos )
 
704
{
 
705
    color_.r_ = 1.0f;
 
706
    color_.g_ = 0.0f;
 
707
    color_.b_ = 0.0f;
 
708
}
 
709
 
 
710
// *******************************************************************************
 
711
// *
 
712
// *    gDeathZoneHack
 
713
// *
 
714
// *******************************************************************************
 
715
//!
 
716
//!             @param  m Message to read creation data from
 
717
//!             @param  null
 
718
//!
 
719
// *******************************************************************************
 
720
 
 
721
gDeathZoneHack::gDeathZoneHack( nMessage & m )
 
722
        : gZone( m )
 
723
{
 
724
}
 
725
 
 
726
// *******************************************************************************
 
727
// *
 
728
// *    ~gDeathZoneHack
 
729
// *
 
730
// *******************************************************************************
 
731
//!
 
732
//!
 
733
// *******************************************************************************
 
734
 
 
735
gDeathZoneHack::~gDeathZoneHack( void )
 
736
{
 
737
}
 
738
 
 
739
static int score_deathzone=-1;
 
740
static tSettingItem<int> s_dz("SCORE_DEATHZONE",score_deathzone);
 
741
 
 
742
// *******************************************************************************
 
743
// *
 
744
// *    OnEnter
 
745
// *
 
746
// *******************************************************************************
 
747
//!
 
748
//!             @param  target  the cycle that has been found inside the zone
 
749
//!             @param  time    the current time
 
750
//!
 
751
// *******************************************************************************
 
752
 
 
753
void gDeathZoneHack::OnEnter( gCycle * target, REAL time )
 
754
{
 
755
    target->Player()->AddScore(score_deathzone, tOutput(), "$player_lose_suicide");
 
756
    target->Kill();
 
757
}
 
758
 
 
759
// *******************************************************************************
 
760
// *
 
761
// *    gBaseZoneHack
 
762
// *
 
763
// *******************************************************************************
 
764
//!
 
765
//!             @param  grid Grid to put the zone into
 
766
//!             @param  pos      Position to spawn the zone at
 
767
//!
 
768
// *******************************************************************************
 
769
 
 
770
gBaseZoneHack::gBaseZoneHack( eGrid * grid, const eCoord & pos )
 
771
        :gZone( grid, pos), onlySurvivor_( false ), currentState_( State_Safe )
 
772
{
 
773
    enemiesInside_ = ownersInside_ = 0;
 
774
    conquered_ = 0;
 
775
    lastSync_ = -10;
 
776
    teamDistance_ = 0;
 
777
    lastEnemyContact_ = se_GameTime();
 
778
    touchy_ = false;
 
779
 
 
780
    color_.r_ = color_.g_ = color_.b_ = 0;
 
781
}
 
782
 
 
783
// *******************************************************************************
 
784
// *
 
785
// *    gBaseZoneHack
 
786
// *
 
787
// *******************************************************************************
 
788
//!
 
789
//!             @param  m Message to read creation data from
 
790
//!
 
791
// *******************************************************************************
 
792
 
 
793
gBaseZoneHack::gBaseZoneHack( nMessage & m )
 
794
        : gZone( m ), onlySurvivor_( false ), currentState_( State_Safe )
 
795
{
 
796
    enemiesInside_ = ownersInside_ = 0;
 
797
    conquered_ = 0;
 
798
    lastSync_ = -10;
 
799
    teamDistance_ = 0;
 
800
    lastEnemyContact_ = se_GameTime();
 
801
    touchy_ = false;
 
802
}
 
803
 
 
804
// *******************************************************************************
 
805
// *
 
806
// *    ~gBaseZoneHack
 
807
// *
 
808
// *******************************************************************************
 
809
//!
 
810
//!
 
811
// *******************************************************************************
 
812
 
 
813
gBaseZoneHack::~gBaseZoneHack( void )
 
814
{
 
815
}
 
816
 
 
817
REAL sg_conquestRate = .5;
 
818
REAL sg_defendRate = .25;
 
819
REAL sg_conquestDecayRate = .1;
 
820
 
 
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 );
 
824
 
 
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 );
 
828
 
 
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 );
 
832
 
 
833
// and at least this ratio
 
834
static REAL sg_onConquestKillRatio = 0;
 
835
static tSettingItem< REAL > sg_onConquestKillRationConfig( "FORTRESS_CONQUERED_KILL_RATIO", sg_onConquestKillRatio );
 
836
 
 
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 );
 
840
 
 
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 );
 
844
 
 
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 );
 
848
 
 
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 )
 
852
{
 
853
    count = 0;
 
854
    farthest = NULL;
 
855
 
 
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--)
 
859
    {
 
860
        gBaseZoneHack *otherZone=dynamic_cast<gBaseZoneHack *>(gameObjects(j));
 
861
 
 
862
        if ( otherZone && otherTeam == otherZone->Team() )
 
863
        {
 
864
            count++;
 
865
            if ( !farthest || otherZone->teamDistance_ > farthest->teamDistance_ )
 
866
                farthest = otherZone;
 
867
        }
 
868
    }
 
869
}
 
870
 
 
871
static int sg_onSurviveScore = 0;
 
872
static tSettingItem< int > sg_onSurviveConquestScoreConfig( "FORTRESS_HELD_SCORE", sg_onSurviveScore );
 
873
 
 
874
static REAL sg_collapseSpeed = .5;
 
875
static tSettingItem< REAL > sg_collapseSpeedConfig( "FORTRESS_COLLAPSE_SPEED", sg_collapseSpeed );
 
876
 
 
877
 
 
878
// *******************************************************************************
 
879
// *
 
880
// *    Timestep
 
881
// *
 
882
// *******************************************************************************
 
883
//!
 
884
//!             @param  time    the current time
 
885
//!
 
886
// *******************************************************************************
 
887
 
 
888
bool gBaseZoneHack::Timestep( REAL time )
 
889
{
 
890
    // no team?!? Get rid of this zone ASAP.
 
891
    if ( !team )
 
892
    {
 
893
        return true;
 
894
    }
 
895
 
 
896
    if ( currentState_ == State_Conquering )
 
897
    {
 
898
        // let zone vanish
 
899
        SetReferenceTime();
 
900
 
 
901
        // let it light up in agony
 
902
        if ( sg_collapseSpeed < .4 )
 
903
        {
 
904
            color_.r_ = color_.g_ = color_.b_ = 1;
 
905
        }
 
906
 
 
907
        SetExpansionSpeed( -GetRadius()*sg_collapseSpeed );
 
908
        SetRotationAcceleration( -GetRotationSpeed()*.4 );
 
909
        RequestSync();
 
910
 
 
911
        currentState_ = State_Conquered;
 
912
    }
 
913
    else if ( currentState_ == State_Conquered && GetRotationSpeed() < 0 )
 
914
    {
 
915
        // let zone vanish
 
916
        SetReferenceTime();
 
917
        SetRotationSpeed( 0 );
 
918
        SetRotationAcceleration( 0 );
 
919
        color_.r_ = color_.g_ = color_.b_ = .5;
 
920
        RequestSync();
 
921
    }
 
922
 
 
923
    REAL dt = time - lastTime;
 
924
 
 
925
    // conquest going on
 
926
    REAL conquest = sg_conquestRate * enemiesInside_ - sg_defendRate * ownersInside_ - sg_conquestDecayRate;
 
927
    conquered_ += dt * conquest;
 
928
 
 
929
    if ( touchy_ && enemiesInside_ > 0 )
 
930
    {
 
931
        conquered_ = 1.01;
 
932
    }
 
933
 
 
934
    // clamp
 
935
    if ( conquered_ < 0 )
 
936
    {
 
937
        conquered_ = 0;
 
938
        conquest = 0;
 
939
    }
 
940
    if ( conquered_ > 1.01 )
 
941
    {
 
942
        conquered_ = 1.01;
 
943
        conquest = 0;
 
944
    }
 
945
 
 
946
    // set speed according to conquest status
 
947
    if ( currentState_ == State_Safe )
 
948
    {
 
949
        REAL maxSpeed = 10 * ( 2 * M_PI ) / sg_segments;
 
950
        REAL omega = .3 + conquered_ * conquered_ * maxSpeed;
 
951
        REAL omegaDot = 2 * conquered_ * conquest * maxSpeed;
 
952
 
 
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 )
 
956
            timeStep *= 100;
 
957
 
 
958
        if ( sn_GetNetState() != nCLIENT &&
 
959
                ( ( fabs( omega - GetRotationSpeed() ) + fabs( omegaDot - GetRotationAcceleration() ) ) * timeStep > .5 ) )
 
960
        {
 
961
            SetRotationSpeed( omega );
 
962
            SetRotationAcceleration( omegaDot );
 
963
            SetReferenceTime();
 
964
            RequestSync();
 
965
            lastSync_ = lastTime;
 
966
        }
 
967
 
 
968
 
 
969
        // check for enemy contact timeout
 
970
        if ( sg_conquestTimeout > 0 && lastEnemyContact_ + sg_conquestTimeout < time )
 
971
        {
 
972
            enemies_.clear();
 
973
 
 
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 )
 
977
            {
 
978
                if ( team )
 
979
                {
 
980
                    if ( sg_onSurviveScore != 0 )
 
981
                    {
 
982
                        // give player the survive score bonus right now, they deserve it
 
983
                        ZoneWasHeld();
 
984
                    }
 
985
                    else
 
986
                    {
 
987
                        sn_ConsoleOut( tOutput( "$zone_collapse_harmless", team->GetColoredName()  ) );
 
988
                    }
 
989
                }
 
990
                conquered_ = 1.0;
 
991
            }
 
992
        }
 
993
 
 
994
        // check whether the zone got conquered
 
995
        if ( conquered_ >= 1 )
 
996
        {
 
997
            currentState_ = State_Conquering;
 
998
            OnConquest();
 
999
        }
 
1000
    }
 
1001
 
 
1002
    // reset counts
 
1003
    enemiesInside_ = ownersInside_ = 0;
 
1004
 
 
1005
    // delegate
 
1006
    bool ret = gZone::Timestep( time );
 
1007
 
 
1008
    // reward survival
 
1009
    if ( team && !ret && onlySurvivor_ )
 
1010
    {
 
1011
        const char* message= ( eTeam::teams.Len() > 2 || sg_onConquestScore ) ? "$player_win_held_fortress" : "$player_win_conquest";
 
1012
        sg_DeclareWinner( team, message );
 
1013
    }
 
1014
    
 
1015
    return ret;
 
1016
}
 
1017
 
 
1018
// *******************************************************************************
 
1019
// *
 
1020
// *    OnVanish
 
1021
// *
 
1022
// *******************************************************************************
 
1023
//!
 
1024
//!
 
1025
// *******************************************************************************
 
1026
 
 
1027
void gBaseZoneHack::OnVanish( void )
 
1028
{
 
1029
    if (!team)
 
1030
        return;
 
1031
 
 
1032
    CheckSurvivor();
 
1033
 
 
1034
    // kill the closest owners of the zone
 
1035
    if ( currentState_ != State_Safe && ( enemies_.size() > 0 || sg_defendRate < 0 ) )
 
1036
    {
 
1037
        int kills = int( sg_onConquestKillRatio * team->NumPlayers() );
 
1038
        kills = kills > sg_onConquestKillMin ? kills : sg_onConquestKillMin;
 
1039
 
 
1040
        while ( kills > 0 )
 
1041
        {
 
1042
            -- kills;
 
1043
 
 
1044
            ePlayerNetID * closest = NULL;
 
1045
            REAL closestDistance = 0;
 
1046
 
 
1047
            // find the closest living owner
 
1048
            for ( int i = team->NumPlayers()-1; i >= 0; --i )
 
1049
            {
 
1050
                ePlayerNetID * player = team->Player(i);
 
1051
                eNetGameObject * object = player->Object();
 
1052
                if ( object && object->Alive() )
 
1053
                {
 
1054
                    eCoord otherpos = object->Position() - pos;
 
1055
                    REAL distance = otherpos.NormSquared();
 
1056
                    if ( !closest || distance < closestDistance )
 
1057
                    {
 
1058
                        closest = player;
 
1059
                        closestDistance = distance;
 
1060
                    }
 
1061
                }
 
1062
            }
 
1063
 
 
1064
            if ( closest )
 
1065
            {
 
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();
 
1071
            }
 
1072
        }
 
1073
    }
 
1074
}
 
1075
 
 
1076
// *******************************************************************************
 
1077
// *
 
1078
// *    OnConquest
 
1079
// *
 
1080
// *******************************************************************************
 
1081
//!
 
1082
//!
 
1083
// *******************************************************************************
 
1084
 
 
1085
static eLadderLogWriter sg_basezoneConqueredWriter("BASEZONE_CONQUERED", true);
 
1086
static eLadderLogWriter sg_basezoneConquererWriter("BASEZONE_CONQUERER", true);
 
1087
 
 
1088
void gBaseZoneHack::OnConquest( void )
 
1089
{
 
1090
    if ( team )
 
1091
    {
 
1092
        sg_basezoneConqueredWriter << ePlayerNetID::FilterName(team->Name()) << GetPosition().x << GetPosition().y;
 
1093
        sg_basezoneConqueredWriter.write();
 
1094
    }
 
1095
    float rr = GetRadius();
 
1096
    rr *= rr;
 
1097
    for(int i = se_PlayerNetIDs.Len()-1; i >=0; --i) {
 
1098
        ePlayerNetID *player = se_PlayerNetIDs(i);
 
1099
        if(!player) {
 
1100
            continue;
 
1101
        }
 
1102
        gCycle *cycle = dynamic_cast<gCycle *>(player->Object());
 
1103
        if(!cycle) {
 
1104
            continue;
 
1105
        }
 
1106
        if(cycle->Alive() && (cycle->Position() - Position()).NormSquared() < rr) {
 
1107
            sg_basezoneConquererWriter << player->GetUserName();
 
1108
            sg_basezoneConquererWriter.write();
 
1109
        }
 
1110
    }
 
1111
 
 
1112
    // calculate score. If nobody really was inside the zone any more, half it.
 
1113
    int totalScore = sg_onConquestScore;
 
1114
    if ( 0 == enemiesInside_ )
 
1115
        totalScore /= 2;
 
1116
 
 
1117
    // eliminate dead enemies
 
1118
    TeamArray enemiesAlive;
 
1119
    for ( TeamArray::iterator iter = enemies_.begin(); iter != enemies_.end(); ++iter )
 
1120
    {
 
1121
        eTeam* team = *iter;
 
1122
        if ( team->Alive() )
 
1123
            enemiesAlive.push_back( team );
 
1124
    }
 
1125
    enemies_ = enemiesAlive;
 
1126
 
 
1127
    // add score for successful conquest, divided equally between the teams that are
 
1128
    // inside the zone
 
1129
    if ( totalScore && enemies_.size() > 0 )
 
1130
    {
 
1131
        tOutput win;
 
1132
        if ( team )
 
1133
        {
 
1134
            win.SetTemplateParameter( 3, team->GetColoredName() );
 
1135
            win << "$player_win_conquest_specific";
 
1136
        }
 
1137
        else
 
1138
        {
 
1139
            win << "$player_win_conquest";
 
1140
        }
 
1141
 
 
1142
        int score = totalScore / enemies_.size();
 
1143
        for ( TeamArray::iterator iter = enemies_.begin(); iter != enemies_.end(); ++iter )
 
1144
        {
 
1145
            (*iter)->AddScore( score, win, tOutput() );
 
1146
        }
 
1147
    }
 
1148
 
 
1149
    // trigger immediate win
 
1150
    if ( sg_onConquestWin && enemies_.size() > 0 )
 
1151
    {
 
1152
        static const char* message="$player_win_conquest";
 
1153
        sg_DeclareWinner( enemies_[0], message );
 
1154
    }
 
1155
 
 
1156
    CheckSurvivor();
 
1157
}
 
1158
 
 
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 );
 
1162
 
 
1163
// *******************************************************************************
 
1164
// *
 
1165
// *    CheckSurvivor
 
1166
// *
 
1167
// *******************************************************************************
 
1168
//!
 
1169
//!
 
1170
// *******************************************************************************
 
1171
 
 
1172
void gBaseZoneHack::CheckSurvivor( void )
 
1173
{
 
1174
    // test if there is only one team with non-conquered zones left
 
1175
    if ( sg_onSurviveWin )
 
1176
    {
 
1177
        // find surviving team and test whether it is the only one
 
1178
        gBaseZoneHack * survivor = 0;
 
1179
        bool onlySurvivor = true;
 
1180
 
 
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));
 
1184
 
 
1185
            if ( other && other->currentState_ == State_Safe && other->team )
 
1186
            {
 
1187
                if ( survivor && survivor->team != other->team )
 
1188
                    onlySurvivor = false;
 
1189
                else
 
1190
                    survivor = other;
 
1191
            }
 
1192
        }
 
1193
 
 
1194
        // reward it later
 
1195
        if ( onlySurvivor && survivor )
 
1196
        {
 
1197
            survivor->onlySurvivor_ = true;
 
1198
        }
 
1199
    }
 
1200
}
 
1201
 
 
1202
// *******************************************************************************
 
1203
// *
 
1204
// *   ZoneWasHeld
 
1205
// *
 
1206
// *******************************************************************************
 
1207
//!
 
1208
//!
 
1209
// *******************************************************************************
 
1210
 
 
1211
void gBaseZoneHack::ZoneWasHeld( void )
 
1212
{
 
1213
    // survived?
 
1214
    if ( currentState_ == State_Safe && sg_onSurviveScore != 0 )
 
1215
    {
 
1216
        // award owning team
 
1217
        if ( team && team->Alive() )
 
1218
        {
 
1219
            team->AddScore( sg_onSurviveScore, tOutput("$player_win_held_fortress"), tOutput("$player_lose_held_fortress") );
 
1220
 
 
1221
            currentState_ = State_Conquering;
 
1222
            enemies_.clear();
 
1223
        }
 
1224
        else
 
1225
        {
 
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.
 
1228
            touchy_ = true;
 
1229
        }
 
1230
    }
 
1231
}
 
1232
 
 
1233
// *******************************************************************************
 
1234
// *
 
1235
// *   OnRoundBegin
 
1236
// *
 
1237
// *******************************************************************************
 
1238
//!
 
1239
//! @return shall the hole process be repeated?
 
1240
//!
 
1241
// *******************************************************************************
 
1242
 
 
1243
void gBaseZoneHack::OnRoundBegin( void )
 
1244
{
 
1245
    // determine the owning team: the one that has a player spawned closest
 
1246
    // find the closest player
 
1247
    if ( !team )
 
1248
    {
 
1249
        teamDistance_ = 0;
 
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--)
 
1254
        {
 
1255
            gCycle *other=dynamic_cast<gCycle *>(gameObjects(i));
 
1256
 
 
1257
            if (other )
 
1258
            {
 
1259
                eTeam * otherTeam = other->Player()->CurrentTeam();
 
1260
                eCoord otherpos = other->Position() - pos;
 
1261
                REAL distance = otherpos.NormSquared();
 
1262
                if ( !closest || distance < closestDistance )
 
1263
                {
 
1264
                    // check whether other zones are already registered to that team
 
1265
                    gBaseZoneHack * farthest = NULL;
 
1266
                    int count = 0;
 
1267
                    if ( sg_baseZonesPerTeam > 0 )
 
1268
                        CountZonesOfTeam( Grid(), otherTeam, count, farthest );
 
1269
 
 
1270
                    // only set team if not too many closer other zones are registered
 
1271
                    if ( sg_baseZonesPerTeam == 0 || count < sg_baseZonesPerTeam || farthest->teamDistance_ > distance )
 
1272
                    {
 
1273
                        closest = other;
 
1274
                        closestDistance = distance;
 
1275
                    }
 
1276
                }
 
1277
            }
 
1278
        }
 
1279
 
 
1280
        if ( closest )
 
1281
        {
 
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;
 
1288
 
 
1289
            RequestSync();
 
1290
        }
 
1291
 
 
1292
        // if this zone does not belong to a team, discard it.
 
1293
        if ( !team )
 
1294
        {
 
1295
            RemoveFromGame();
 
1296
            return;
 
1297
        }
 
1298
 
 
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 )
 
1302
        {
 
1303
            gBaseZoneHack * farthest = 0;
 
1304
            int count = 0;
 
1305
            CountZonesOfTeam( Grid(), team, count, farthest );
 
1306
 
 
1307
            // discard team of farthest zone
 
1308
            if ( count > sg_baseZonesPerTeam )
 
1309
            {
 
1310
                farthest->team = NULL;
 
1311
                farthest->RemoveFromGame();
 
1312
            }
 
1313
        }
 
1314
    }
 
1315
}
 
1316
 
 
1317
// *******************************************************************************
 
1318
// *
 
1319
// *   OnRoundEnd
 
1320
// *
 
1321
// *******************************************************************************
 
1322
//!
 
1323
//!
 
1324
// *******************************************************************************
 
1325
 
 
1326
void gBaseZoneHack::OnRoundEnd( void )
 
1327
{
 
1328
    // survived?
 
1329
    if ( currentState_ == State_Safe )
 
1330
    {
 
1331
        ZoneWasHeld();
 
1332
    }
 
1333
}
 
1334
 
 
1335
// *******************************************************************************
 
1336
// *
 
1337
// *    OnEnter
 
1338
// *
 
1339
// *******************************************************************************
 
1340
//!
 
1341
//!             @param  target  the cycle that has been found inside the zone
 
1342
//!             @param  time    the current time
 
1343
//!
 
1344
// *******************************************************************************
 
1345
 
 
1346
void gBaseZoneHack::OnEnter( gCycle * target, REAL time )
 
1347
{
 
1348
    // determine the team of the player
 
1349
    tASSERT( target );
 
1350
    if ( !target->Player() )
 
1351
        return;
 
1352
    tJUST_CONTROLLED_PTR< eTeam > otherTeam = target->Player()->CurrentTeam();
 
1353
    if (!otherTeam)
 
1354
        return;
 
1355
    if ( currentState_ != State_Safe )
 
1356
        return;
 
1357
 
 
1358
    // remember who is inside
 
1359
    if ( team == otherTeam )
 
1360
    {
 
1361
        ++ ownersInside_;
 
1362
    }
 
1363
    else if ( team )
 
1364
    {
 
1365
        if ( enemiesInside_ == 0 )
 
1366
            enemies_.clear();
 
1367
 
 
1368
        ++ enemiesInside_;
 
1369
        if ( std::find( enemies_.begin(), enemies_.end(), otherTeam ) == enemies_.end() )
 
1370
            enemies_.push_back( otherTeam );
 
1371
 
 
1372
        lastEnemyContact_ = time;
 
1373
    }
 
1374
}
 
1375
 
 
1376
// *******************************************************************************
 
1377
// *
 
1378
// *    GetPosition
 
1379
// *
 
1380
// *******************************************************************************
 
1381
//!
 
1382
//!             @return         the current position
 
1383
//!
 
1384
// *******************************************************************************
 
1385
 
 
1386
eCoord gZone::GetPosition( void ) const
 
1387
{
 
1388
    eCoord ret;
 
1389
    GetPosition( ret );
 
1390
    return ret;
 
1391
}
 
1392
 
 
1393
// *******************************************************************************
 
1394
// *
 
1395
// *    GetPosition
 
1396
// *
 
1397
// *******************************************************************************
 
1398
//!
 
1399
//!             @param  position        the current position to fill
 
1400
//!             @return         A reference to this to allow chaining
 
1401
//!
 
1402
// *******************************************************************************
 
1403
 
 
1404
gZone const & gZone::GetPosition( eCoord & position ) const
 
1405
{
 
1406
    position.x = EvaluateFunctionNow( posx_ );
 
1407
    position.y = EvaluateFunctionNow( posy_ );
 
1408
    return *this;
 
1409
}
 
1410
 
 
1411
// *******************************************************************************
 
1412
// *
 
1413
// *    SetPosition
 
1414
// *
 
1415
// *******************************************************************************
 
1416
//!
 
1417
//!             @param  position        the current position to set
 
1418
//!             @return         A reference to this to allow chaining
 
1419
//!
 
1420
// *******************************************************************************
 
1421
 
 
1422
gZone & gZone::SetPosition( eCoord const & position )
 
1423
{
 
1424
    SetFunctionNow( posx_, position.x );
 
1425
    SetFunctionNow( posy_, position.y );
 
1426
    return *this;
 
1427
}
 
1428
 
 
1429
// *******************************************************************************
 
1430
// *
 
1431
// *    GetVelocity
 
1432
// *
 
1433
// *******************************************************************************
 
1434
//!
 
1435
//!             @return         the current velocity
 
1436
//!
 
1437
// *******************************************************************************
 
1438
 
 
1439
eCoord gZone::GetVelocity( void ) const
 
1440
{
 
1441
    eCoord ret;
 
1442
    GetVelocity( ret );
 
1443
 
 
1444
    return ret;
 
1445
}
 
1446
 
 
1447
// *******************************************************************************
 
1448
// *
 
1449
// *    GetVelocity
 
1450
// *
 
1451
// *******************************************************************************
 
1452
//!
 
1453
//!             @param  velocity        the current velocity to fill
 
1454
//!             @return         A reference to this to allow chaining
 
1455
//!
 
1456
// *******************************************************************************
 
1457
 
 
1458
gZone const & gZone::GetVelocity( eCoord & velocity ) const
 
1459
{
 
1460
    velocity.x = posx_.GetSlope();
 
1461
    velocity.y = posy_.GetSlope();
 
1462
 
 
1463
    return *this;
 
1464
}
 
1465
 
 
1466
// *******************************************************************************
 
1467
// *
 
1468
// *    SetVelocity
 
1469
// *
 
1470
// *******************************************************************************
 
1471
//!
 
1472
//!             @param  velocity        the current velocity to set
 
1473
//!             @return         A reference to this to allow chaining
 
1474
//!
 
1475
// *******************************************************************************
 
1476
 
 
1477
gZone & gZone::SetVelocity( eCoord const & velocity )
 
1478
{
 
1479
    // backup position
 
1480
    eCoord pos;
 
1481
    GetPosition( pos );
 
1482
 
 
1483
    posx_.SetSlope( velocity.x );
 
1484
    posy_.SetSlope( velocity.y );
 
1485
 
 
1486
    // restore position
 
1487
    SetPosition( pos );
 
1488
 
 
1489
    return *this;
 
1490
}
 
1491
 
 
1492
// *******************************************************************************
 
1493
// *
 
1494
// *    GetRadius
 
1495
// *
 
1496
// *******************************************************************************
 
1497
//!
 
1498
//!             @return         the current radius
 
1499
//!
 
1500
// *******************************************************************************
 
1501
 
 
1502
REAL gZone::GetRadius( void ) const
 
1503
{
 
1504
    REAL ret = EvaluateFunctionNow( this->radius_ );
 
1505
    ret = ret > 0 ? ret : 0;
 
1506
 
 
1507
    return ret;
 
1508
}
 
1509
 
 
1510
// *******************************************************************************
 
1511
// *
 
1512
// *    GetRadius
 
1513
// *
 
1514
// *******************************************************************************
 
1515
//!
 
1516
//!             @param  radius  the current radius to fill
 
1517
//!             @return         A reference to this to allow chaining
 
1518
//!
 
1519
// *******************************************************************************
 
1520
 
 
1521
gZone const & gZone::GetRadius( REAL & radius ) const
 
1522
{
 
1523
    radius = GetRadius();
 
1524
 
 
1525
    return *this;
 
1526
}
 
1527
 
 
1528
// *******************************************************************************
 
1529
// *
 
1530
// *    SetRadius
 
1531
// *
 
1532
// *******************************************************************************
 
1533
//!
 
1534
//!             @param  radius  the current radius to set
 
1535
//!             @return         A reference to this to allow chaining
 
1536
//!
 
1537
// *******************************************************************************
 
1538
 
 
1539
gZone & gZone::SetRadius( REAL radius )
 
1540
{
 
1541
    SetFunctionNow( this->radius_, radius );
 
1542
 
 
1543
    return *this;
 
1544
}
 
1545
 
 
1546
// *******************************************************************************
 
1547
// *
 
1548
// *    GetExpansionSpeed
 
1549
// *
 
1550
// *******************************************************************************
 
1551
//!
 
1552
//!             @return         the current expansion speed
 
1553
//!
 
1554
// *******************************************************************************
 
1555
 
 
1556
REAL gZone::GetExpansionSpeed( void ) const
 
1557
{
 
1558
    return this->radius_.GetSlope();
 
1559
}
 
1560
 
 
1561
// *******************************************************************************
 
1562
// *
 
1563
// *    GetExpansionSpeed
 
1564
// *
 
1565
// *******************************************************************************
 
1566
//!
 
1567
//!             @param  expansionSpeed  the current expansion speed to fill
 
1568
//!             @return         A reference to this to allow chaining
 
1569
//!
 
1570
// *******************************************************************************
 
1571
 
 
1572
gZone const & gZone::GetExpansionSpeed( REAL & expansionSpeed ) const
 
1573
{
 
1574
    expansionSpeed = this->radius_.GetSlope();
 
1575
 
 
1576
    return *this;
 
1577
}
 
1578
 
 
1579
// *******************************************************************************
 
1580
// *
 
1581
// *    SetExpansionSpeed
 
1582
// *
 
1583
// *******************************************************************************
 
1584
//!
 
1585
//!             @param  expansionSpeed  the current expansion speed to set
 
1586
//!             @return         A reference to this to allow chaining
 
1587
//!
 
1588
// *******************************************************************************
 
1589
 
 
1590
gZone & gZone::SetExpansionSpeed( REAL expansionSpeed )
 
1591
{
 
1592
    REAL r = EvaluateFunctionNow( this->radius_ );
 
1593
    this->radius_.SetSlope( expansionSpeed );
 
1594
    SetRadius( r );
 
1595
 
 
1596
    return *this;
 
1597
}
 
1598
 
 
1599
// *******************************************************************************
 
1600
// *
 
1601
// *    SetReferenceTime
 
1602
// *
 
1603
// *******************************************************************************
 
1604
//!
 
1605
//!
 
1606
// *******************************************************************************
 
1607
 
 
1608
void gZone::SetReferenceTime( void )
 
1609
{
 
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_ ) );
 
1615
 
 
1616
    // reset time
 
1617
    this->referenceTime_ = lastTime;
 
1618
}
 
1619
 
 
1620
// *******************************************************************************
 
1621
// *
 
1622
// *    GetRotationSpeed
 
1623
// *
 
1624
// *******************************************************************************
 
1625
//!
 
1626
//!             @return         The current rotation speed
 
1627
//!
 
1628
// *******************************************************************************
 
1629
 
 
1630
REAL gZone::GetRotationSpeed( void ) const
 
1631
{
 
1632
    return EvaluateFunctionNow( rotationSpeed_ );
 
1633
}
 
1634
 
 
1635
// *******************************************************************************
 
1636
// *
 
1637
// *    GetRotation
 
1638
// *
 
1639
// *******************************************************************************
 
1640
//!
 
1641
//!             @return         The current rotation position, as normalized x and y coordinates
 
1642
//!
 
1643
// *******************************************************************************
 
1644
 
 
1645
tCoord const &gZone::GetRotation( void ) const
 
1646
{
 
1647
    return rotation_;
 
1648
}
 
1649
 
 
1650
// *******************************************************************************
 
1651
// *
 
1652
// *    GetRotationSpeed
 
1653
// *
 
1654
// *******************************************************************************
 
1655
//!
 
1656
//!             @param  rotationSpeed   The current rotation speed to fill
 
1657
//!             @return         A reference to this to allow chaining
 
1658
//!
 
1659
// *******************************************************************************
 
1660
 
 
1661
gZone const & gZone::GetRotationSpeed( REAL & rotationSpeed ) const
 
1662
{
 
1663
    rotationSpeed = this->GetRotationSpeed();
 
1664
    return *this;
 
1665
}
 
1666
 
 
1667
// *******************************************************************************
 
1668
// *
 
1669
// *    SetRotationSpeed
 
1670
// *
 
1671
// *******************************************************************************
 
1672
//!
 
1673
//!             @param  rotationSpeed   The current rotation speed to set
 
1674
//!             @return         A reference to this to allow chaining
 
1675
//!
 
1676
// *******************************************************************************
 
1677
 
 
1678
gZone & gZone::SetRotationSpeed( REAL rotationSpeed )
 
1679
{
 
1680
    SetFunctionNow( this->rotationSpeed_, rotationSpeed );
 
1681
    return *this;
 
1682
}
 
1683
 
 
1684
// *******************************************************************************
 
1685
// *
 
1686
// *    GetRotationAcceleration
 
1687
// *
 
1688
// *******************************************************************************
 
1689
//!
 
1690
//!             @return         the current acceleration of the rotation
 
1691
//!
 
1692
// *******************************************************************************
 
1693
 
 
1694
REAL gZone::GetRotationAcceleration( void ) const
 
1695
{
 
1696
    return this->rotationSpeed_.GetSlope();
 
1697
}
 
1698
 
 
1699
// *******************************************************************************
 
1700
// *
 
1701
// *    GetRotationAcceleration
 
1702
// *
 
1703
// *******************************************************************************
 
1704
//!
 
1705
//!             @param  rotationAcceleration    the current acceleration of the rotation to fill
 
1706
//!             @return         A reference to this to allow chaining
 
1707
//!
 
1708
// *******************************************************************************
 
1709
 
 
1710
gZone const & gZone::GetRotationAcceleration( REAL & rotationAcceleration ) const
 
1711
{
 
1712
    rotationAcceleration = this->GetRotationAcceleration();
 
1713
    return *this;
 
1714
}
 
1715
 
 
1716
// *******************************************************************************
 
1717
// *
 
1718
// *    GetColor
 
1719
// *
 
1720
// *******************************************************************************
 
1721
//!
 
1722
//!             @return         the current color of the zone
 
1723
//!
 
1724
// *******************************************************************************
 
1725
 
 
1726
rColor const & gZone::GetColor( void ) const
 
1727
{
 
1728
    return color_;
 
1729
}
 
1730
 
 
1731
// *******************************************************************************
 
1732
// *
 
1733
// *    SetRotationAcceleration
 
1734
// *
 
1735
// *******************************************************************************
 
1736
//!
 
1737
//!             @param  rotationAcceleration    the current acceleration of the rotation to set
 
1738
//!             @return         A reference to this to allow chaining
 
1739
//!
 
1740
// *******************************************************************************
 
1741
 
 
1742
gZone & gZone::SetRotationAcceleration( REAL rotationAcceleration )
 
1743
{
 
1744
    REAL omega = this->GetRotationSpeed();
 
1745
    this->rotationSpeed_.SetSlope( rotationAcceleration );
 
1746
    SetRotationSpeed( omega );
 
1747
 
 
1748
    return *this;
 
1749
}
 
1750
 
 
1751
 
 
1752