Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

merged the single_player branche to trunk

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