Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/single_player_map/src/world_entities/playable.cc @ 9047

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

orxonox/trunk: Each Playable has an EnterRange

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