Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8013 was 7351, checked in by bensch, 19 years ago

orxonox/trunk: the cheat is now a Static function

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