Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8252 was 8147, checked in by bensch, 19 years ago

orxonox/trunk: merged the network branche back here
merged with command:
svn merge -r8070:HEAD https://svn.orxonox.net/orxonox/branches/network .
no conflicts

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