00001 /* 00002 00003 ************************************************************************* 00004 00005 ArmageTron -- Just another Tron Lightcycle Game in 3D. 00006 Copyright (C) 2000 Manuel Moos (manuel@moosnet.de) 00007 00008 ************************************************************************** 00009 00010 This program is free software; you can redistribute it and/or 00011 modify it under the terms of the GNU General Public License 00012 as published by the Free Software Foundation; either version 2 00013 of the License, or (at your option) any later version. 00014 00015 This program is distributed in the hope that it will be useful, 00016 but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 GNU General Public License for more details. 00019 00020 You should have received a copy of the GNU General Public License 00021 along with this program; if not, write to the Free Software 00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00023 00024 *************************************************************************** 00025 00026 */ 00027 00028 #include "rSDL.h" 00029 00030 #include "zone/zZone.h" 00031 #include "eFloor.h" 00032 #include "eTimer.h" 00033 #include "eGrid.h" 00034 #include "gCycle.h" 00035 #include "gGame.h" 00036 //#include "eTeam.h" 00037 //#include "ePlayer.h" 00038 #include "rRender.h" 00039 #include "nConfig.h" 00040 #include "tString.h" 00041 #include "rScreen.h" 00042 #include "eSoundMixer.h" 00043 #include "tPolynomial.h" 00044 00045 00046 #include <time.h> 00047 #include <map> 00048 #include <algorithm> 00049 #include <functional> 00050 #include <deque> 00051 #include <iterator> 00052 00053 #include "gWinZone.h" 00054 00055 std::deque<zZone *> sz_Zones; 00056 00057 // number of segments to render a zone with 00058 static const int sg_segments = 11; 00059 00060 // ******************************************************************************* 00061 // * 00062 // * EvaluateFunctionNow 00063 // * 00064 // ******************************************************************************* 00069 // ******************************************************************************* 00070 00071 inline REAL zZone::EvaluateFunctionNow( tFunction const & f ) const 00072 { 00073 return f( lastTime - referenceTime_ ); 00074 } 00075 00076 // ******************************************************************************* 00077 // * 00078 // * SetFunctionNow 00079 // * 00080 // ******************************************************************************* 00085 // ******************************************************************************* 00086 00087 inline void zZone::SetFunctionNow( tFunction & f, REAL value ) const 00088 { 00089 f.SetOffset( value + f.GetSlope() * ( referenceTime_ - lastTime ) ); 00090 } 00091 00092 // ******************************************************************************* 00093 // * 00094 // * zZone 00095 // * 00096 // ******************************************************************************* 00101 // ******************************************************************************* 00102 zZone::zZone( eGrid * grid ) 00103 :eNetGameObject( grid, eCoord(0,0), eCoord(0,0), NULL, true ), 00104 // rotation_(1,0), 00105 effectGroupEnter(), 00106 effectGroupInside(), 00107 effectGroupLeave(), 00108 effectGroupOutside(), 00109 playersInside(), 00110 playersOutside(), 00111 oldFortressAutomaticAssignmentBehavior_(false), 00112 name_() 00113 { 00114 // store creation time 00115 referenceTime_ = createTime_ = lastTime = 0; 00116 00117 // add to game grid 00118 this->AddToList(); 00119 00120 sz_Zones.push_back(this); 00121 00122 // initialize position functions 00123 // SetPosition( pos ); 00124 eSoundMixer* mixer = eSoundMixer::GetMixer(); 00125 mixer->PushButton(ZONE_SPAWN, pos); 00126 } 00127 00128 static nVersionFeature sz_ShapedZones(20); 00129 00130 // ******************************************************************************* 00131 // * 00132 // * zZone 00133 // * 00134 // ******************************************************************************* 00138 // ******************************************************************************* 00139 00140 zZone::zZone( nMessage & m ) 00141 :eNetGameObject( m ), 00142 //rotation_(1,0), 00143 playersInside(), 00144 playersOutside(), 00145 oldFortressAutomaticAssignmentBehavior_(false), 00146 name_() 00147 { 00148 // read creation time 00149 m >> createTime_; 00150 referenceTime_ = lastTime = createTime_; 00151 00152 // initialize color to white, ReadSync will fill in the true value if available 00153 // color_.r_ = color_.g_ = color_.b_ = 1.0f; 00154 00155 // add to game grid 00156 this->AddToList(); 00157 00158 sz_Zones.push_back(this); 00159 00160 // initialize position functions 00161 // SetPosition( pos ); 00162 eSoundMixer* mixer = eSoundMixer::GetMixer(); 00163 mixer->PushButton(ZONE_SPAWN, pos); 00164 00165 00166 /* 00167 shape = zShapePtr(new zShapeCircle(Grid(), ID())); 00168 00169 tFunction asdf = tFunction(); 00170 asdf.SetSlope(0.0); 00171 asdf.SetOffset(100.0); 00172 shape->setPosX(asdf); 00173 shape->setPosY(asdf); 00174 shape->setScale(asdf); 00175 shape->setRotation(asdf); 00176 shape->setScale(asdf); 00177 shape->setColor(rColor(0.7, 0.0, 0.7)); 00178 zShapeCircle *circle = dynamic_cast<zShapeCircle *>( (zShape*)shape ); 00179 00180 circle->emulatingOldZone_ = true; 00181 */ 00182 00183 /* 00184 if (!m.End() && sz_ShapedZones.Supported() ) 00185 { 00186 // Factory to make the shapes 00187 // HACK 00188 // This makes them static for the life of the zone 00189 // rather than to re-send them all at each updates 00190 typedef zShape* (*shapeFactory)(nMessage &); 00191 std::map<tString, shapeFactory> shapes; 00192 // Build the list of supported shapes 00193 shapes[tString("circle")] = zShapeCircle::create; 00194 shapes[tString("polygon")] = zShapePolygon::create; 00195 00196 // Get the name of the shape from the network 00197 tString shapeName; 00198 m >> shapeName; 00199 00200 std::map<tString, shapeFactory>::const_iterator iterShapeFactory; 00201 // Build that shape if it is available 00202 if((iterShapeFactory = shapes.find(shapeName)) != shapes.end()) 00203 { 00204 shape = zShapePtr((*(iterShapeFactory->second))(m)); 00205 } 00206 } 00207 else 00208 { 00209 // Didnt receive a shape information. Assume we are talking to a 0.2.8- server 00210 shape = zShapePtr(new zShapeCircle()); 00211 shape->setPosX(posx_); 00212 shape->setPosY(posy_); 00213 shape->setScale(scale_); 00214 tPolynomial<nMessage> tpRotationSpeed(2); 00215 tpRotationSpeed[0] = rotationSpeed_.GetOffset(); 00216 tpRotationSpeed[0] = rotationSpeed_.GetOffset(); 00217 shape->setRotation2(tpRotationSpeed); 00218 shape->setScale(scale_); 00219 shape->setColor(color_); 00220 00221 emulateOldZoneShape = true; 00222 } 00223 */ 00224 00225 } 00226 00227 // ******************************************************************************* 00228 // * 00229 // * ~zZone 00230 // * 00231 // ******************************************************************************* 00234 // ******************************************************************************* 00235 00236 zZone::~zZone( void ) 00237 { 00238 RemoveFromZoneList(); 00239 } 00240 00241 void zZone::RemoveFromGame(void) { 00242 RemoveFromZoneList(); 00243 eNetGameObject::RemoveFromGame(); 00244 } 00245 00246 void zZone::RemoveFromZoneList(void) { 00247 std::deque<zZone *>::iterator pos_found = 00248 std::find_if( 00249 sz_Zones.begin(), 00250 sz_Zones.end(), 00251 std::bind2nd( 00252 std::equal_to<zZone *>(), 00253 this) 00254 ); 00255 if(pos_found != sz_Zones.end()) 00256 sz_Zones.erase(pos_found); 00257 } 00258 00259 // ******************************************************************************* 00260 // * 00261 // * WriteCreate 00262 // * 00263 // ******************************************************************************* 00267 // ******************************************************************************* 00268 00269 void zZone::WriteCreate( nMessage & m ) 00270 { 00271 // delegate 00272 eNetGameObject::WriteCreate( m ); 00273 00274 m << createTime_; 00275 00276 /* 00277 if(!emulateOldZoneShape && sz_ShapedZones.Supported() ) 00278 shape->WriteCreate( m ); 00279 */ 00280 } 00281 00282 // ******************************************************************************* 00283 // * 00284 // * WriteSync 00285 // * 00286 // ******************************************************************************* 00290 // ******************************************************************************* 00291 00292 void zZone::WriteSync( nMessage & m ) 00293 { 00294 // delegate 00295 eNetGameObject::WriteSync( m ); 00296 00297 /* 00298 // write color 00299 m << color_.r_; 00300 m << color_.g_; 00301 m << color_.b_; 00302 00303 // write reference time and functions 00304 m << referenceTime_; 00305 m << posx_; 00306 m << posy_; 00307 m << scale_; 00308 00309 // write rotation speed 00310 m << rotationSpeed_; 00311 */ 00312 00313 // Simply populate the message with semi-meaningful data 00314 m << shape->getColor().r_; 00315 m << shape->getColor().g_; 00316 m << shape->getColor().b_; 00317 00318 m << referenceTime_; 00319 00320 m << shape->getPosX(); 00321 m << shape->getPosY(); 00322 m << shape->getScale(); 00323 // shape->getRotation no longer exist. Fake it! 00324 tFunction tfFakedRotation; 00325 m << tfFakedRotation; 00326 00327 m << shape->ID(); 00328 } 00329 00330 // ******************************************************************************* 00331 // * 00332 // * ReadSync 00333 // * 00334 // ******************************************************************************* 00338 // ******************************************************************************* 00339 00340 void zZone::ReadSync( nMessage & m ) 00341 { 00342 // delegage 00343 eNetGameObject::ReadSync( m ); 00344 00345 if(shape && shape->isEmulatingOldZone()) 00346 { 00347 // read color 00348 rColor aColor(0.0, 0.7, 0.5); 00349 if (!m.End()) 00350 { 00351 m >> aColor.r_; 00352 m >> aColor.g_; 00353 m >> aColor.b_; 00354 } 00355 se_MakeColorValid(aColor.r_, aColor.g_, aColor.b_, 1.0f); 00356 shape->setColor(aColor); 00357 00358 // read reference time and functions 00359 if (!m.End()) 00360 { 00361 m >> referenceTime_; 00362 shape->setReferenceTime(referenceTime_); 00363 if (!m.End()) 00364 { 00365 tFunction aFunc; 00366 m >> aFunc; 00367 shape->setPosX(aFunc); 00368 m >> aFunc; 00369 shape->setPosY(aFunc); 00370 m >> aFunc; 00371 shape->setScale(aFunc); 00372 } 00373 } 00374 else 00375 { 00376 // Uses values from the eNetGameObject 00377 referenceTime_ = createTime_; 00378 shape->setReferenceTime(referenceTime_); 00379 00380 tFunction aFunc; 00381 aFunc.SetOffset( pos.x ); 00382 aFunc.SetSlope( 0 ); 00383 shape->setPosX( aFunc ); 00384 00385 aFunc.SetOffset( pos.y ); 00386 aFunc.SetSlope( 0 ); 00387 shape->setPosY( aFunc ); 00388 00389 aFunc.SetOffset( sg_initialSize ); 00390 aFunc.SetSlope( sg_expansionSpeed ); 00391 shape->setScale( aFunc ); 00392 } 00393 00394 // read rotation speed 00395 tFunction rotationSpeed; 00396 if (!m.End()) 00397 { 00398 m >> rotationSpeed; 00399 } 00400 else 00401 { 00402 // set fixed values 00403 rotationSpeed.SetOffset( .3f ); 00404 rotationSpeed.SetSlope( 0.0f ); 00405 } 00406 tPolynomial<nMessage> tpRotationSpeed(2); 00407 tpRotationSpeed[0] = rotationSpeed.GetOffset(); 00408 tpRotationSpeed[1] = rotationSpeed.GetSlope(); 00409 shape->setRotation2(tpRotationSpeed); 00410 } 00411 else 00412 { 00413 bool b; 00414 00415 // while(!m.End() ) { m >> b;} 00416 00417 int count=44-16; 00418 // Discard the information 00419 while(!m.End() && count-->0) { m >> b;} 00420 unsigned short shapeID; 00421 m >> shapeID; 00422 if(sn_netObjects[shapeID]) { 00423 // zShape *asdf = dynamic_cast<zShape*>(&*sn_netObjects[shapeID]); 00424 shape = zShapePtr( dynamic_cast<zShape*>(&*sn_netObjects[shapeID]) ); 00425 } 00426 00427 } 00428 } 00429 00430 // ******************************************************************************* 00431 // * 00432 // * Timestep 00433 // * 00434 // ******************************************************************************* 00438 // ******************************************************************************* 00439 00440 bool zZone::Timestep( REAL time ) 00441 { 00442 if(0 != shape) { 00443 shape->TimeStep( time ); 00444 } 00445 /* 00446 if(!emulateOldZoneShape) { 00447 shape->TimeStep( time ); 00448 } 00449 else { // Old representation of zone 00450 // rotate 00451 REAL speed = GetRotationSpeed(); 00452 REAL angle = ( time - lastTime ) * speed; 00453 // angle /= ( 1 + 2 * 3.14159 * angle/sg_segments ); 00454 rotation_ = rotation_.Turn( cos( angle ), sin( angle ) ); 00455 00456 // move to new position 00457 REAL dt = time - referenceTime_; 00458 Move( eCoord( posx_( dt ), posy_( dt ) ), lastTime, time ); 00459 00460 00461 // kill this zone if it shrunk down to zero scale 00462 if ( GetExpansionSpeed() < 0 && GetScale() <= 0 ) 00463 { 00464 OnVanish(); 00465 return true; 00466 } 00467 } 00468 // update time 00469 */ 00470 lastTime = time; 00471 00472 return false; 00473 } 00474 00475 // ******************************************************************************* 00476 // * 00477 // * OnVanish 00478 // * 00479 // ******************************************************************************* 00482 // ******************************************************************************* 00483 00484 void zZone::OnVanish( void ) 00485 { 00486 } 00487 00488 // ******************************************************************************* 00489 // * 00490 // * InteractWith 00491 // * 00492 // ******************************************************************************* 00498 // ******************************************************************************* 00499 00500 void zZone::InteractWith( eGameObject * target, REAL time, int recursion ) 00501 { 00502 gCycle* prey = dynamic_cast< gCycle* >( target ); 00503 if ( prey && 0 != shape) 00504 { 00505 if ( prey->Player() && prey->Alive() ) 00506 { 00507 // Is the player inside or outside the zone 00508 if ( shape->isInteracting(target) == true ) 00509 { 00510 // If the player is not on the "inside" list, then he was outside 00511 std::set<ePlayerNetID *>::iterator iter; 00512 if ((iter = playersInside.find(prey->Player()) ) == playersInside.end()) { 00513 playersInside.insert(prey->Player()); 00514 00515 // Should the player not be marked as being outside 00516 // avoid the OnEnter transition. This happens at game 00517 // start-up for example, when players are neither inside nor outside 00518 if( playersOutside.find(prey->Player()) != playersOutside.end() ) 00519 { 00520 // Passing from outside to inside triggers the OnEnter event 00521 OnEnter( prey, time ); 00522 } 00523 // The player is no longer outside 00524 playersOutside.erase(prey->Player()); 00525 } 00526 // Being inside gives the OnInside event 00527 OnInside( prey, time ); 00528 } 00529 else { 00530 // If the player is not on the "outside" list, then he was inside 00531 std::set<ePlayerNetID *>::iterator iter; 00532 if ((iter = playersOutside.find(prey->Player())) == playersOutside.end()) { 00533 playersOutside.insert(prey->Player()); 00534 00535 // Should the player not be marked as being inside 00536 // avoid OnLeave transition. This happens at game 00537 // start-up for example, when players are neither inside nor outside 00538 if( playersInside.find(prey->Player()) != playersInside.end() ) 00539 { 00540 // Passing from inside to outside triggers the OnLeave event 00541 OnLeave( prey, time ); 00542 } 00543 // The player is no longer inside 00544 playersInside.erase(prey->Player()); 00545 } 00546 // Being inside gives the OnOutside event 00547 OnOutside( prey, time ); 00548 } 00549 } 00550 } 00551 } 00552 00553 REAL asdf[] = {0, 1}; 00554 tPolynomial<nMessage> tpOne(asdf, sizeof(asdf)/sizeof(asdf[0])); 00555 // ******************************************************************************* 00556 // * 00557 // * OnEnter 00558 // * 00559 // ******************************************************************************* 00564 // ******************************************************************************* 00565 void zZone::OnEnter( gCycle * target, REAL time ) 00566 { 00567 Triggerer triggerer; 00568 triggerer.who = target; 00569 triggerer.positive = _ignore; 00570 triggerer.marked = _ignore; 00571 00572 zEffectGroupPtrs::const_iterator iter; 00573 for (iter = effectGroupEnter.begin(); 00574 iter != effectGroupEnter.end(); 00575 ++iter) 00576 { 00577 (*iter)->apply(triggerer, time, tpOne); 00578 } 00579 } 00580 00581 void zZone::OnInside( gCycle * target, REAL time ) 00582 { 00583 Triggerer triggerer; 00584 triggerer.who = target; 00585 triggerer.positive = _ignore; 00586 triggerer.marked = _ignore; 00587 00588 zEffectGroupPtrs::const_iterator iter; 00589 for (iter = effectGroupInside.begin(); 00590 iter != effectGroupInside.end(); 00591 ++iter) 00592 { 00593 (*iter)->apply(triggerer, time, tpOne); 00594 } 00595 } 00596 void zZone::OnLeave( gCycle * target, REAL time ) 00597 { 00598 Triggerer triggerer; 00599 triggerer.who = target; 00600 triggerer.positive = _ignore; 00601 triggerer.marked = _ignore; 00602 00603 zEffectGroupPtrs::const_iterator iter; 00604 for (iter = effectGroupLeave.begin(); 00605 iter != effectGroupLeave.end(); 00606 ++iter) 00607 { 00608 (*iter)->apply(triggerer, time, tpOne); 00609 } 00610 } 00611 void zZone::OnOutside( gCycle * target, REAL time ) 00612 { 00613 Triggerer triggerer; 00614 triggerer.who = target; 00615 triggerer.positive = _ignore; 00616 triggerer.marked = _ignore; 00617 00618 zEffectGroupPtrs::const_iterator iter; 00619 for (iter = effectGroupOutside.begin(); 00620 iter != effectGroupOutside.end(); 00621 ++iter) 00622 { 00623 (*iter)->apply(triggerer, time, tpOne); 00624 } 00625 } 00626 00627 // the zone's network initializator 00628 static nNOInitialisator<zZone> zone_init(341,"zonev2"); 00629 00630 // ******************************************************************************* 00631 // * 00632 // * CreatorDescriptor 00633 // * 00634 // ******************************************************************************* 00638 // ******************************************************************************* 00639 00640 nDescriptor & zZone::CreatorDescriptor( void ) const 00641 { 00642 return zone_init; 00643 } 00644 00645 /* 00646 // ******************************************************************************* 00647 // * 00648 // * Scale 00649 // * 00650 // ******************************************************************************* 00654 // ******************************************************************************* 00655 00656 REAL zZone::Scale( void ) const 00657 { 00658 // return GetScale(); 00659 return shape->getScale(); 00660 } 00661 */ 00662 00663 // ******************************************************************************* 00664 // * 00665 // * Render 00666 // * 00667 // ******************************************************************************* 00671 // ******************************************************************************* 00672 00673 void zZone::Render( const eCamera * cam ) 00674 { 00675 if (shape) 00676 shape->render(cam); 00677 } 00678 00679 void zZone::Render2D( tCoord scale ) const { 00680 if (shape) 00681 shape->render2d(scale); 00682 } 00683 00684 00685 // ******************************************************************************* 00686 // * 00687 // * GetPosition 00688 // * 00689 // ******************************************************************************* 00693 // ******************************************************************************* 00694 00695 eCoord zZone::GetPosition( void ) const 00696 { 00697 // HACK, to be implemented later and differently 00698 // Should get this info from the shape, not the zone 00699 eCoord ret; 00700 GetPosition( ret ); 00701 return ret; 00702 } 00703 00704 // ******************************************************************************* 00705 // * 00706 // * GetPosition 00707 // * 00708 // ******************************************************************************* 00713 // ******************************************************************************* 00714 00715 zZone const & zZone::GetPosition( eCoord & position ) const 00716 { 00717 if(0 != shape) { 00718 position.x = EvaluateFunctionNow( shape->getPosX() ); 00719 position.y = EvaluateFunctionNow( shape->getPosY() ); 00720 } 00721 return *this; 00722 } 00723 00724 // ******************************************************************************* 00725 // * 00726 // * GetScale 00727 // * 00728 // ******************************************************************************* 00732 // ******************************************************************************* 00733 00734 REAL zZone::GetScale( void ) const 00735 { 00736 // REAL ret = EvaluateFunctionNow( this->scale_ ); 00737 // ret = ret > 0 ? ret : 0; 00738 00739 00740 // HACK, to be implemented later and differently 00741 // Should get this info from the shape, not the zone 00742 REAL scale = 0.0; 00743 if(0 != shape) { 00744 scale = EvaluateFunctionNow( shape->getScale() ) ; 00745 } 00746 return scale; 00747 } 00748 00749 // ******************************************************************************* 00750 // * 00751 // * SetReferenceTime 00752 // * 00753 // ******************************************************************************* 00756 // ******************************************************************************* 00757 00758 void zZone::SetReferenceTime( void ) 00759 { 00760 // set offsets to current values 00761 /* 00762 this->posx_.SetOffset( EvaluateFunctionNow( this->posx_ ) ); 00763 this->posy_.SetOffset( EvaluateFunctionNow( this->posy_ ) ); 00764 this->scale_.SetOffset( EvaluateFunctionNow( this->scale_ ) ); 00765 this->rotationSpeed_.SetOffset( EvaluateFunctionNow( this->rotationSpeed_ ) ); 00766 */ 00767 // reset time 00768 this->referenceTime_ = lastTime; 00769 } 00770 00771 // ******************************************************************************* 00772 // * 00773 // * GetRotation 00774 // * 00775 // ******************************************************************************* 00779 // ******************************************************************************* 00780 00781 tCoord const zZone::GetRotation( void ) const 00782 { 00783 // HACK, to be implemented later and differently 00784 // Should get this info from the shape, not the zone 00785 return tCoord(0.0, 0.0); 00786 } 00787 00788 // ******************************************************************************* 00789 // * 00790 // * GetColor 00791 // * 00792 // ******************************************************************************* 00796 // ******************************************************************************* 00797 00798 rColor const zZone::GetColor( void ) const 00799 { 00800 rColor color; 00801 if(0 != shape) { 00802 color = shape->getColor(); 00803 } 00804 return color; 00805 } 00806