Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8068 was 8055, checked in by bensch, 19 years ago

trunk: new Playmode FirstPerson

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