Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7952 was 7868, checked in by bensch, 19 years ago

trunk: merge Check in the Event-changes:
r7867 | bensch | 2006-05-26 13:19:46 +0200 (Fri, 26 May 2006) | 1 line

Events better subscribed


r7866 | bensch | 2006-05-26 13:11:10 +0200 (Fri, 26 May 2006) | 1 line

Events are subscribed at the EventListener, and not the EventHandler

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