Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/bsp_model/src/world_entities/playable.cc @ 8217

Last change on this file since 8217 was 8217, checked in by patrick, 18 years ago

bsp: major restructure: going over bsp_entity for collision detection. adjusting interfaces

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