Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/world_entities/playable.cc @ 7465

Last change on this file since 7465 was 7412, checked in by bensch, 19 years ago

orxonox/trunk: Another CompletionMode is working

File size: 13.8 KB
RevLine 
[5838]1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
[5841]12   main-programmer: Silvan Nellen
13   co-programmer: Benjamin Knecht
[5838]14*/
15
[5881]16
[5838]17#include "playable.h"
[7350]18#include "event_handler.h"
[5895]19
[5875]20#include "player.h"
[6241]21#include "state.h"
[7347]22#include "camera.h"
23
[7193]24#include "util/loading/load_param.h"
[5838]25
[6547]26#include "power_ups/weapon_power_up.h"
27#include "power_ups/param_power_up.h"
[5872]28
[7044]29#include "game_rules.h"
[6547]30
[6959]31#include "dot_emitter.h"
32#include "sprite_particles.h"
33
[7121]34#include "shared_network_data.h"
35
[7118]36#include "effects/explosion.h"
[6959]37
[7350]38#include "shell_command.h"
[7356]39SHELL_COMMAND_STATIC(orxoWeapon, Playable, Playable::addSomeWeapons_CHEAT)
40  ->setAlias("orxoWeapon");
[7118]41
[7350]42
[5838]43Playable::Playable()
[7338]44    : weaponMan(this),
45    supportedPlaymodes(Playable::Full3D),
46    playmode(Playable::Full3D)
[5838]47{
[6442]48  this->setClassID(CL_PLAYABLE, "Playable");
49  PRINTF(4)("PLAYABLE INIT\n");
50
51  this->toList(OM_GROUP_01);
52
53  // the reference to the Current Player is NULL, because we dont have one at the beginning.
54  this->currentPlayer = NULL;
[6695]55
[6804]56  this->bFire = false;
[6868]57  this->oldFlags = 0;
[6804]58
[6695]59  this->setSynchronized(true);
[6959]60
61  this->score = 0;
62  this->oldScore = 0;
63
[7118]64  this->bDead = false;
[5838]65}
66
[6695]67
[7346]68/**
69 * @brief destroys the Playable
70 */
[5875]71Playable::~Playable()
[5838]72{
[6986]73  // THE DERIVED CLASS MUST UNSUBSCRIBE THE PLAYER THROUGH
74  // this->setPlayer(NULL);
75  // IN ITS DESTRUCTOR.
76  assert(this->currentPlayer == NULL);
[5875]77}
78
[7346]79/**
80 * @brief loads Playable parameters onto the Playable
81 * @param root the XML-root to load from
82 */
[7092]83void Playable::loadParams(const TiXmlElement* root)
84{
85  WorldEntity::loadParams(root);
86
[7346]87  LoadParam(root, "abs-dir", this, Playable, setPlayDirection);
[7092]88}
89
[7346]90/**
91 * @brief picks up a powerup
92 * @param powerUp the PowerUp that should be picked.
93 * @returns true on success (pickup was picked, false otherwise)
94 *
95 * This function also checks if the Pickup can be picked up by this Playable
96 */
97bool Playable::pickup(PowerUp* powerUp)
98{
99  if(powerUp->isA(CL_WEAPON_POWER_UP))
100  {
101    return dynamic_cast<WeaponPowerUp*>(powerUp)->process(&this->getWeaponManager());
102  }
103  else if(powerUp->isA(CL_PARAM_POWER_UP))
104  {
105    ParamPowerUp* ppu = dynamic_cast<ParamPowerUp*>(powerUp);
106    switch(ppu->getType())
107    {
108      case POWERUP_PARAM_HEALTH:
109        this->increaseHealth(ppu->getValue());
110        return true;
111      case POWERUP_PARAM_MAX_HEALTH:
112        this->increaseHealthMax(ppu->getValue());
113        return true;
114    }
115  }
116  return false;
117}
118
119/**
120 * @brief adds a Weapon to the Playable.
121 * @param weapon the Weapon to add.
122 * @param configID the Configuration ID to add this weapon to.
123 * @param slotID the slotID to add the Weapon to.
124 */
[7350]125bool Playable::addWeapon(Weapon* weapon, int configID, int slotID)
[6443]126{
[7350]127  if(this->weaponMan.addWeapon(weapon, configID, slotID))
128  {
129    this->weaponConfigChanged();
130    return true;
131  }
132  else
133  {
134    if (weapon != NULL)
135      PRINTF(2)("Unable to add Weapon (%s::%s) to %s::%s\n",
[7351]136                weapon->getClassName(), weapon->getName(), this->getClassName(), this->getName());
[7350]137    else
138      PRINTF(2)("No weapon defined\n");
139    return false;
[6443]140
[7350]141  }
[6443]142}
143
[7346]144/**
145 * @brief removes a Weapon.
146 * @param weapon the Weapon to remove.
147 */
[6443]148void Playable::removeWeapon(Weapon* weapon)
149{
[7337]150  this->weaponMan.removeWeapon(weapon);
[6443]151
[7338]152  this->weaponConfigChanged();
[6443]153}
154
[7346]155/**
156 * @brief jumps to the next WeaponConfiguration
157 */
[6444]158void Playable::nextWeaponConfig()
159{
[7337]160  this->weaponMan.nextWeaponConfig();
[7338]161  this->weaponConfigChanged();
[6444]162}
[6443]163
[7346]164/**
165 * @brief moves to the last WeaponConfiguration
166 */
[6444]167void Playable::previousWeaponConfig()
168{
[7337]169  this->weaponMan.previousWeaponConfig();
[7338]170  this->weaponConfigChanged();
[6444]171}
172
[7346]173/**
174 * @brief tells the Player, that the Weapon-Configuration has changed.
175 *
176 * TODO remove this
177 * This function is needed, so that the WeponManager of this Playable can easily update the HUD
178 */
[6568]179void Playable::weaponConfigChanged()
180{
[6578]181  if (this->currentPlayer != NULL)
182    this->currentPlayer->weaponConfigChanged();
[6568]183}
[6444]184
[7350]185/**
186 * @brief a Cheat that gives us some Weapons
187 */
188void Playable::addSomeWeapons_CHEAT()
189{
[7351]190  if (State::getPlayer() != NULL)
191  {
192    Playable* playable = State::getPlayer()->getPlayable();
193    if (playable != NULL)
194    {
195      PRINTF(2)("ADDING WEAPONS - you cheater\n");
196      playable->addWeapon(Weapon::createWeapon(CL_HYPERBLASTER));
197      playable->addWeapon(Weapon::createWeapon(CL_TURRET));
198      playable->addWeapon(Weapon::createWeapon(CL_AIMING_TURRET));
199      playable->addWeapon(Weapon::createWeapon(CL_CANNON));
200      playable->addWeapon(Weapon::createWeapon(CL_TARGETING_TURRET));
201      PRINTF(2)("ADDING WEAPONS FINISHED\n");
202    }
203  }
[7350]204}
[7346]205
[7173]206/**
[7346]207 * @brief subscribe to all events the controllable needs
208 * @param player the player that shall controll this Playable
209 * @returns false on error true otherwise.
210 */
211bool Playable::setPlayer(Player* player)
212{
213  // if we already have a Player inside do nothing
214  if (this->currentPlayer != NULL && player != NULL)
215  {
216    return false;
217  }
218
219  // eject the Player if player == NULL
220  if (this->currentPlayer != NULL && player == NULL)
221  {
222    PRINTF(4)("Player gets ejected\n");
223
224    // unsubscibe all events.
225    EventHandler* evh = EventHandler::getInstance();
226    std::vector<int>::iterator ev;
227    for (ev = this->events.begin(); ev != events.end(); ev++)
228      evh->unsubscribe( ES_GAME, (*ev));
229
230    // leave the entity
231    this->leave();
232
233    // eject the current Player.
234    Player* ejectPlayer = this->currentPlayer;
235    this->currentPlayer = NULL;
236    // eject the Player.
237    ejectPlayer->setPlayable(NULL);
238
239    return true;
240  }
241
242  // get the new Player inside
243  if (this->currentPlayer == NULL && player != NULL)
244  {
245    PRINTF(4)("New Player gets inside\n");
246    this->currentPlayer = player;
247    if (this->currentPlayer->getPlayable() != this)
248      this->currentPlayer->setPlayable(this);
249
250    /*EventHandler*/
251    EventHandler* evh = EventHandler::getInstance();
252    std::vector<int>::iterator ev;
253    for (ev = this->events.begin(); ev != events.end(); ev++)
254      evh->subscribe(player, ES_GAME, (*ev));
255
256    this->enter();
257    return true;
258  }
259
260  return false;
261}
262
263/**
264 * @brief attaches the current Camera to this Playable
265 *
266 * this function can be derived, so that any Playable can make the attachment differently.
267 */
268void Playable::attachCamera()
269{
270  State::getCameraNode()->setParentSoft(this);
271  State::getCameraTargetNode()->setParentSoft(this);
272
273}
274
275/**
276 * @brief detaches the Camera
277 * @see void Playable::attachCamera()
278 */
279void  Playable::detachCamera()
280{}
281
282
283/**
[7173]284 * @brief sets the CameraMode.
285 * @param cameraMode: the Mode to switch to.
286 */
287void Playable::setCameraMode(unsigned int cameraMode)
[7347]288{
289  State::getCamera()->setViewMode((Camera::ViewMode)cameraMode);
290}
[7338]291
[7346]292
[7338]293/**
294 * @brief sets the Playmode
295 * @param playmode the Playmode
296 * @returns true on success, false otherwise
297 */
[7339]298bool Playable::setPlaymode(Playable::Playmode playmode)
[7173]299{
[7338]300  if (!this->playmodeSupported(playmode))
301    return false;
302  else
[7345]303  {
[7347]304    this->enterPlaymode(playmode);
[7338]305    this->playmode = playmode;
[7345]306    return true;
307  }
[7173]308}
309
[7346]310/**
311 * @brief This function look, that the Playable rotates to the given rotation.
312 * @param angle the Angle around
313 * @param dirX directionX
314 * @param dirY directionY
315 * @param dirZ directionZ
316 * @param speed how fast to turn there.
317 */
318void Playable::setPlayDirection(float angle, float dirX, float dirY, float dirZ, float speed)
319{
320  this->setPlayDirection(Quaternion(angle, Vector(dirX, dirY, dirZ)), speed);
321}
[7173]322
[5872]323/**
[7346]324 * @brief all Playable will enter the Playmode Differently, say here how to do it.
325 * @param playmode the Playmode to enter.
326 *
327 * In this function all the actions that are required to enter the Playmode are described.
328 * e.g: camera, rotation, wait cycle and so on...
[7347]329 *
330 * on enter of this function the playmode is still the old playmode.
[7346]331 */
332void Playable::enterPlaymode(Playable::Playmode playmode)
333{
[7347]334  switch(playmode)
335  {
336    default:
337      this->attachCamera();
338      break;
339    case Playable::Horizontal:
340      this->setCameraMode(Camera::ViewTop);
341      break;
342    case Playable::Vertical:
343      this->setCameraMode(Camera::ViewLeft);
344      break;
345    case Playable::FromBehind:
346      this->setCameraMode(Camera::ViewBehind);
347      break;
348  }
[7346]349}
350/**
[6436]351 * @brief helps us colliding Playables
[7346]352 * @param entity the Entity to collide
353 * @param location where the collision occured.
[6436]354 */
355void Playable::collidesWith(WorldEntity* entity, const Vector& location)
356{
[7072]357  if (entity == collider)
358    return;
359  collider = entity;
360
[7121]361  if ( entity->isA(CL_PROJECTILE) && ( !State::isOnline() || SharedNetworkData::getInstance()->isGameServer() ) )
[6966]362  {
[7072]363    this->decreaseHealth(entity->getHealth() *(float)rand()/(float)RAND_MAX);
[6966]364    // EXTREME HACK
[7072]365    if (this->getHealth() <= 0.0f)
[6966]366    {
367      this->die();
368    }
369  }
370}
[6436]371
[6966]372
[7044]373void Playable::respawn()
[6966]374{
[7044]375  PRINTF(0)("Playable respawn\n");
376  // only if this is the spaceship of the player
377  if( this == State::getPlayer()->getPlayable())
378    State::getGameRules()->onPlayerSpawn();
[6966]379
[7085]380
[7082]381  if( this->getOwner() % 2 == 0)
382  {
[7338]383    //     this->toList(OM_GROUP_00);
[7082]384    this->setAbsCoor(213.37, 57.71, -47.98);
[7100]385    this->setAbsDir(0, 0, 1, 0);
[7082]386  }
[6966]387  else
[7099]388  { // red team
[7338]389    //     this->toList(OM_GROUP_01);
[7082]390    this->setAbsCoor(-314.450, 40.701, 83.554);
[7100]391    this->setAbsDir(1.0, -0.015, -0.012, 0.011);
[7082]392  }
[7118]393  this->reset();
394  this->bDead = false;
[6436]395}
396
[6966]397
[7088]398
[7044]399void Playable::die()
400{
[7119]401  Explosion::explode(dynamic_cast<PNode*>(this), Vector(1.0f, 1.0f, 1.0f));
402
403
[7118]404  if( !this->bDead)
405  {
406    PRINTF(0)("Playable dies\n");
[7338]407    // only if this is the spaceship of the player
[7118]408    if (State::isOnline())
409    {
410      if( this == State::getPlayer()->getPlayable())
411        State::getGameRules()->onPlayerDeath();
[7044]412
[7338]413      //     this->toList(OM_GROUP_05);
414      //HACK: moves the entity to an unknown place far far away: in the future, GameRules will look for that
[7118]415      this->setAbsCoor(-2000.0, -2000.0, -2000.0);
[7078]416
[7338]417      //explosion hack
[7118]418
419    }
420    this->bDead = true;
[7072]421  }
[7044]422}
423
424
[6986]425
426
427
[5896]428/**
[7346]429 * @brief add an event to the event list of events this Playable can capture
[5898]430 * @param eventType the Type of event to add
[5889]431 */
[5896]432void Playable::registerEvent(int eventType)
[5889]433{
434  this->events.push_back(eventType);
435
[5896]436  if (this->currentPlayer != NULL)
437    EventHandler::getInstance()->subscribe(this->currentPlayer, ES_GAME, eventType);
[5889]438}
439
[5896]440/**
[7339]441 * @brief remove an event to the event list this Playable can capture.
[5898]442 * @param event the event to unregister.
[5896]443 */
444void Playable::unregisterEvent(int eventType)
445{
[7338]446  std::vector<int>::iterator rmEvent = std::find(this->events.begin(), this->events.end(), eventType);
447  this->events.erase(rmEvent);
[5889]448
[5896]449  if (this->currentPlayer != NULL)
450    EventHandler::getInstance()->unsubscribe(ES_GAME, eventType);
451}
[5889]452
[6804]453/**
454 * @brief ticks a Playable
455 * @param dt: the passed time since the last Tick
456 */
457void Playable::tick(float dt)
458{
[7337]459  this->weaponMan.tick(dt);
[6804]460  if (this->bFire)
[7337]461    weaponMan.fire();
[6804]462}
[5896]463
[6804]464
465/**
466 * @brief processes Playable events.
467 * @param event the Captured Event.
468 */
469void Playable::process(const Event &event)
470{
471  if( event.type == KeyMapper::PEV_FIRE1)
472    this->bFire = event.bPressed;
473  else if( event.type == KeyMapper::PEV_NEXT_WEAPON && event.bPressed)
474  {
475    this->nextWeaponConfig();
476  }
477  else if ( event.type == KeyMapper::PEV_PREVIOUS_WEAPON && event.bPressed)
478    this->previousWeaponConfig();
479}
480
481
[6959]482#define DATA_FLAGS    1
483#define DATA_SCORE    2
484
[6868]485#define FLAGS_bFire   1
486
487int Playable::writeSync( const byte * data, int length, int sender )
488{
489  SYNCHELP_READ_BEGIN();
[7010]490
[6994]491  byte b;
492  SYNCHELP_READ_BYTE( b, NWT_PL_B );
[7010]493
[6868]494  byte flags;
[7010]495
[6994]496  if ( b == DATA_FLAGS )
497  {
498    SYNCHELP_READ_BYTE( flags, NWT_PL_FLAGS );
[6871]499
[6994]500    bFire = (flags & FLAGS_bFire) != 0;
[7010]501
[6994]502    return SYNCHELP_READ_N;
503  }
[7010]504
[6994]505  if ( b == DATA_SCORE )
506  {
507    int newScore;
508    SYNCHELP_READ_BYTE( newScore, NWT_PL_SCORE );
509    setScore( newScore );
[7010]510
[6994]511    return SYNCHELP_READ_N;
512  }
[6871]513
[6868]514  return SYNCHELP_READ_N;
515}
516
517int Playable::readSync( byte * data, int maxLength )
518{
519  SYNCHELP_WRITE_BEGIN();
[7010]520
[6994]521  if ( score != oldScore && isServer() )
522  {
523    SYNCHELP_WRITE_BYTE( DATA_SCORE, NWT_PL_B);
524    SYNCHELP_WRITE_INT( score, NWT_PL_SCORE );
525    oldScore = score;
[7010]526
[6994]527    return SYNCHELP_WRITE_N;
528  }
[7010]529
[6868]530  byte flags = 0;
[6871]531
[6868]532  if ( bFire )
533    flags |= FLAGS_bFire;
534
[6871]535
[6994]536  SYNCHELP_WRITE_BYTE( DATA_FLAGS, NWT_PL_B);
[6868]537  SYNCHELP_WRITE_BYTE( flags, NWT_PL_FLAGS );
538  oldFlags = flags;
539
[6871]540
[6868]541  return SYNCHELP_WRITE_N;
542}
543
544bool Playable::needsReadSync( )
545{
[6994]546  if ( score != oldScore && isServer() )
547    return true;
[6959]548
[6868]549  byte flags = 0;
[6871]550
[6868]551  if ( bFire )
552    flags |= FLAGS_bFire;
[6871]553
[6868]554  return flags!=oldFlags;
555}
[7339]556
557
[7346]558/**
559 * @brief converts a string into a Playable::Playmode.
560 * @param playmode the string naming the Playable::Playmode to convert.
561 * @returns the Playable::Playmode converted from playmode.
562 */
[7339]563Playable::Playmode Playable::stringToPlaymode(const std::string& playmode)
564{
[7412]565  if (playmode == Playable::playmodeNames[0])
[7339]566    return Playable::Vertical;
[7412]567  if (playmode == Playable::playmodeNames[1])
[7339]568    return Playable::Horizontal;
[7412]569  if (playmode == Playable::playmodeNames[2])
[7339]570    return Playable::FromBehind;
[7412]571  if (playmode == Playable::playmodeNames[3])
[7339]572    return Playable::Full3D;
573
574  return Playable::Full3D;
575}
576
[7346]577
578/**
579 * @brief converts a playmode into a string.
580 * @param playmode the Playable::Playmode to convert.
581 * @returns the String.
582 */
[7412]583const std::string& Playable::playmodeToString(Playable::Playmode playmode)
[7339]584{
585  switch(playmode)
586  {
587    case Playable::Vertical:
[7412]588      return Playable::playmodeNames[0];
[7339]589    case Playable::Horizontal:
[7412]590      return Playable::playmodeNames[1];
[7339]591    case Playable::FromBehind:
[7412]592      return Playable::playmodeNames[2];
[7339]593    case Playable::Full3D:
[7412]594      return Playable::playmodeNames[3];
[7339]595
596    default:
[7412]597      return Playable::playmodeNames[3];
[7339]598  }
[7412]599}
[7339]600
[7412]601/**
602 * @brief PlaymodeNames
603 */
604const std::string Playable::playmodeNames[] =
605{
606  "Vertical",
607  "Horizontal",
608  "FromBehind",
609  "Full3D"
610};
Note: See TracBrowser for help on using the repository browser.