Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7347 was 7347, checked in by bensch, 18 years ago

orxonox/trunk: some more stuff (now one can play around with them using the Shell →
GameWorld Urban Playmode …. Vertical/Full3D/Horizontal

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