Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/water/src/world_entities/playable.cc @ 8528

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

trunk: fixed most -Wall warnings… but there are still many missing :/

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