Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: some more stuff (now one can play around with them using the Shell →
GameWorld Urban Playmode …. Vertical/Full3D/Horizontal

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