Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/vs-enhencements/src/world_entities/world_entity.cc @ 10670

Last change on this file since 10670 was 10670, checked in by nicolasc, 17 years ago

moved "ship attributes" to world entity
electronic and shield widget not yet working

File size: 29.2 KB
Line 
1
2
3/*
4   orxonox - the future of 3D-vertical-scrollers
5
6   Copyright (C) 2004 orx
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2, or (at your option)
11   any later version.
12
13   ### File Specific:
14   main-programmer: Patrick Boenzli
15   main-programmer: Benjamin Grauer
16   co-programmer:   Christian Meier
17*/
18#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD_ENTITY
19
20#include "world_entity.h"
21#include "shell_command.h"
22
23#include "util/loading/resource_manager.h"
24#include "resource_obj.h"
25#include "md2/md2Model.h"
26#include "md3/md3_model.h"
27
28#include "oif/object_information_file.h"
29#include "tools/mount_point.h"
30
31#include "aabb_tree_node.h"
32
33#include "util/loading/load_param.h"
34#include "loading/load_param_xml.h"
35#include "util/loading/factory.h"
36
37#include "obb_tree.h"
38
39#include "elements/glgui_energywidget.h"
40#include "elements/glgui_energywidgetvertical.h"
41
42#include "state.h"
43#include "tools/camera.h"
44
45#include "collision_filter.h"
46#include "collision_event.h"
47#include "game_rules.h"
48#include "kill.h"
49#include "debug.h"
50
51#include "track/track.h"
52
53#include "projectiles/projectile.h"
54
55SHELL_COMMAND(model, WorldEntity, loadModel)
56->describe("sets the Model of the WorldEntity")
57->defaultValues("models/ships/fighter.obj", 1.0f);
58
59SHELL_COMMAND(debugEntity, WorldEntity, debugWE);
60
61
62ObjectListDefinition(WorldEntity);
63/**
64 *  Loads the WordEntity-specific Part of any derived Class
65 *
66 * @param root: Normally NULL, as the Derived Entities define a loadParams Function themeselves,
67 *              that can calls WorldEntities loadParams for itself.
68 */
69WorldEntity::WorldEntity()
70    : Synchronizeable(), _collisionFilter(this)
71{
72  this->registerObject(this, WorldEntity::_objectList);
73
74  this->obbTree = NULL;
75  this->aabbNode = NULL;
76  this->healthWidget = NULL;
77  this->electronicWidget = NULL;
78  this->shieldWidget = NULL;
79  this->healthMax = 1.0f;
80  this->health = 1.0f;
81  this->damage = 0.0f; // no damage dealt by a default entity
82  this->scaling = 1.0f;
83  this->oiFile = NULL;
84  // add 10 members to this array
85  this->mountPoints.reserve(10);
86
87  /* OSOLETE */
88  this->bVisible = true;
89  this->bCollide = true;
90
91  this->objectListNumber = OM_INIT;
92  this->lastObjectListNumber = OM_INIT;
93
94  this->_bOnGround = false;
95
96  // Track of this entity
97  this->entityTrack = NULL;
98  this->bDrawTrack = false;
99
100  // registering default reactions:
101  this->subscribeReaction(CoRe::CREngine::CR_OBJECT_DAMAGE, Projectile::staticClassID());
102
103  this->toList(OM_NULL);
104
105  this->registerVar( new SynchronizeableString( &this->md2TextureFileName, &this->md2TextureFileName, "md2TextureFileName", PERMISSION_MASTER_SERVER ) );
106  this->modelFileName_handle = registerVarId( new SynchronizeableString( &modelFileName, &modelFileName, "modelFileName", PERMISSION_MASTER_SERVER ) );
107  this->scaling_handle = registerVarId( new SynchronizeableFloat( &scaling, &scaling, "scaling", PERMISSION_MASTER_SERVER ) );
108  this->list_handle = registerVarId( new SynchronizeableInt( (int*)&objectListNumber, &list_write, "list", PERMISSION_MASTER_SERVER ) );
109
110  this->health_handle = registerVarId( new SynchronizeableFloat( &this->health, &this->health_write, "health", PERMISSION_MASTER_SERVER ) );
111  this->healthMax_handle = registerVarId( new SynchronizeableFloat( &this->healthMax, &this->healthMax_write, "maxHealth", PERMISSION_MASTER_SERVER ) );
112}
113
114/**
115 *  standard destructor
116*/
117WorldEntity::~WorldEntity ()
118{
119  State::getObjectManager()->toList(this, OM_INIT);
120
121  // Delete the model (unregister it with the ResourceManager)
122  for (unsigned int i = 0; i < this->models.size(); i++)
123    this->setModel(NULL, i);
124
125  // remove the object information file
126  if( this->oiFile)
127    delete this->oiFile;
128  // and clear all monut points
129  this->mountPoints.clear();
130
131  // Delete the obbTree
132  if( this->obbTree != NULL)
133    delete this->obbTree;
134
135  if (this->healthWidget != NULL)
136    delete this->healthWidget;
137
138  this->unsubscribeReactions();
139}
140
141/**
142 * loads the WorldEntity Specific Parameters.
143 * @param root: the XML-Element to load the Data From
144 */
145void WorldEntity::loadParams(const TiXmlElement* root)
146{
147  // Do the PNode loading stuff
148  PNode::loadParams(root);
149
150  LoadParam(root, "md2texture", this, WorldEntity, loadMD2Texture)
151  .describe("the fileName of the texture, that should be loaded onto this world-entity. (must be relative to the data-dir)")
152  .defaultValues("");
153
154  // Model Loading
155  LoadParam(root, "model", this, WorldEntity, loadModel)
156  .describe("the fileName of the model, that should be loaded onto this world-entity. (must be relative to the data-dir)")
157  .defaultValues("", 1.0f, 0);
158
159  LoadParam(root, "mountpoints", this, WorldEntity, loadMountPoints)
160  .describe("the fileName of the object information file (optional)");
161
162  // Entity Attributes
163  LoadParam(root, "maxHealth", this, WorldEntity, setHealthMax)
164  .describe("The Maximum health that can be loaded onto this entity")
165  .defaultValues(1.0f);
166
167  LoadParam(root, "health", this, WorldEntity, setHealth)
168  .describe("The Health the WorldEntity has at this moment")
169  .defaultValues(1.0f);
170
171  LoadParam(root, "list", this, WorldEntity, toListS);
172
173  LoadParam(root, "drawTrack", this, WorldEntity, drawDebugTrack)
174      .describe("draws the track for debugging purposes");
175
176  // Track
177  LoadParamXML(root, "Track", this, WorldEntity, addTrack)
178  .describe("creates and adds a track to this WorldEntity");
179}
180
181
182/**
183 * this functions adds a track to this workd entity. This can be usefull, if you like this WE to follow a some waypoints.
184 * here the track is created and further initializing left for the Track itself
185 */
186void WorldEntity::addTrack(const TiXmlElement* root)
187{
188  // The problem we have is most likely here. The track should be constructed WITH the XML-Code
189  this->entityTrack = new Track(root);
190  this->setParent(this->entityTrack->getTrackNode());
191  this->entityTrack->getTrackNode()->setParentMode(PNODE_ALL);
192  /*LOAD_PARAM_START_CYCLE(root, element);
193  {
194    PRINTF(4)("element is: %s\n", element->Value());
195    Factory::fabricate(element);
196  }
197  LOAD_PARAM_END_CYCLE(element);*/
198
199
200}
201
202void WorldEntity::pauseTrack(bool stop)
203{
204     if(this->entityTrack)
205       this->entityTrack->pauseTrack(stop);
206}
207
208
209/**
210 * loads a Model onto a WorldEntity
211 * @param fileName the name of the model to load
212 * @param scaling the Scaling of the model
213 *
214 * FIXME
215 * @todo: separate the obb tree generation from the model
216 */
217void WorldEntity::loadModel(const std::string& fileName, float scaling, unsigned int modelNumber, unsigned int obbTreeDepth)
218{
219  this->modelLODName = fileName;
220  this->scaling = scaling;
221
222  std::string name = fileName;
223
224  if (  name.find( Resources::ResourceManager::getInstance()->mainGlobalPath().name() ) == 0 )
225  {
226    name.erase(Resources::ResourceManager::getInstance()->mainGlobalPath().name().size());
227  }
228
229  this->modelFileName = name;
230
231  if (!fileName.empty())
232  {
233    // search for the special character # in the LoadParam
234    if (fileName.find('#') != std::string::npos)
235    {
236      PRINTF(4)("Found # in %s... searching for LOD's\n", fileName.c_str());
237      std::string lodFile = fileName;
238      unsigned int offset = lodFile.find('#');
239      for (unsigned int i = 0; i < 3; i++)
240      {
241        lodFile[offset] = 48+(int)i;
242        if (Resources::ResourceManager::getInstance()->checkFileInMainPath( lodFile))
243          this->loadModel(lodFile, scaling, i);
244      }
245      return;
246    }
247    if (this->scaling <= 0.0)
248    {
249      PRINTF(1)("YOU GAVE ME A CRAPY SCALE resetting to 1.0\n");
250      this->scaling = 1.0;
251    }
252    /// LOADING AN OBJ FILE
253    if(fileName.find(".obj") != std::string::npos)
254    {
255      PRINTF(4)("fetching OBJ file: %s\n", fileName.c_str());
256      // creating the model and loading it
257      StaticModel* model = new StaticModel();
258      *model = ResourceOBJ(fileName, this->scaling);
259
260      // check if ther is a valid model and load other stuff
261      if (model->getVertexCount() > 0)
262      {
263        this->setModel(model, modelNumber);
264
265        if( modelNumber == 0)
266        {
267          this->buildObbTree(obbTreeDepth);
268        }
269      }
270      else
271        delete model;
272    }
273    /// LOADING AN MD2-model
274    else if(fileName.find(".md2") != std::string::npos)
275    {
276      PRINTF(4)("fetching MD2 file: %s\n", fileName.c_str());
277      Model* m = new MD2Model(fileName, this->md2TextureFileName, this->scaling);
278      //this->setModel((Model*)ResourceManager::getInstance()->load(fileName, MD2, RP_CAMPAIGN), 0);
279      this->setModel(m, 0);
280
281      if( m != NULL)
282        this->buildObbTree(obbTreeDepth);
283    }
284    /// LOADING AN MD3-MODEL.
285    else if(fileName.find(".md3") != std::string::npos)
286    {
287      PRINTF(4)("fetching MD3 file: %s\n", fileName.c_str());
288      //      Model* m = new md3::MD3Model(fileName, this->scaling);
289      //      this->setModel(m, 0);
290
291      //       if( m != NULL)
292      //         this->buildObbTree(obbTreeDepth);
293    }
294  }
295  else
296  {
297    this->setModel(NULL);
298  }
299}
300
301/**
302 * sets a specific Model for the Object.
303 * @param model The Model to set
304 * @param modelNumber the n'th model in the List to get.
305 */
306void WorldEntity::setModel(Model* model, unsigned int modelNumber)
307{
308  if (this->models.size() <= modelNumber)
309    this->models.resize(modelNumber+1, NULL);
310
311  if (this->models[modelNumber] != NULL)
312  {
313    delete this->models[modelNumber];
314  }
315
316  this->models[modelNumber] = model;
317}
318
319
320
321/**
322 * loads the object information file for this model
323 * @param fileName the name of the file
324 */
325void WorldEntity::loadMountPoints(const std::string& fileName)
326{
327  PRINTF(5)("loading the oif File: %s\n", fileName.c_str());
328
329  // now load the object information file
330  this->oiFile = new ObjectInformationFile(fileName);
331
332  // get the model to load
333  Model* model = this->getModel();
334
335  // extract the mount points
336  if(model != NULL)
337    model->extractMountPoints();
338  else
339  {
340    PRINTF(0)("Worldentity %s has no mount points", (this->getName()).c_str());
341    return;
342  }
343
344  // first get all mount points from the model
345  const std::list<mountPointSkeleton> mpList = model->getMountPoints();
346  // for each skeleton create a mounting point world entity
347  std::list<mountPointSkeleton>::const_iterator it = mpList.begin();
348
349  for( ; it != mpList.end(); it++)
350  {
351    // create the mount points world entity
352    MountPoint* mp = new MountPoint( (*it).up, (*it).forward, (*it).center, (*it).name);
353    // parent it to this WE
354    mp->setParent( this);
355    // now add to the right group
356    mp->toList( (OM_LIST)(this->getOMListNumber()+1));
357    // now get the number and add the mount point to the slot
358    std::string nrStr = (*it).name.substr(3, 2);
359    // add the mount point
360    this->addMountPoint(atoi(nrStr.c_str()), mp);
361
362    // now fill the mount point
363    mp->initMountPoint( this->oiFile->getMountPointDescription());
364  }
365
366}
367
368
369/**
370 * builds the obb-tree
371 * @param depth the depth to calculate
372 */
373bool WorldEntity::buildObbTree(int depth)
374{
375  if( this->obbTree != NULL)
376  {
377    delete this->obbTree;
378    this->obbTree = NULL;
379  }
380
381  if (this->models[0] != NULL)
382    this->obbTree = new OBBTree(depth, models[0]->getModelInfo(), this);
383  else
384  {
385    PRINTF(1)("could not create obb-tree, because no model was loaded yet\n");
386    this->obbTree = NULL;
387    return false;
388  }
389
390
391  // create the axis aligned bounding box
392  if( this->aabbNode != NULL)
393  {
394    delete this->aabbNode;
395    this->aabbNode = NULL;
396  }
397
398  if( this->models[0] != NULL)
399  {
400    this->aabbNode = new AABBTreeNode();
401    this->aabbNode->spawnBVTree(this->models[0]);
402  }
403  else
404  {
405    PRINTF(1)("could not create aabb bounding box, because no model was loaded yet\n");
406    this->aabbNode = NULL;
407    return false;
408  }
409  return true;
410}
411
412
413/**
414 * adds a mount point to the end of the list
415 * @param mountPoint point to be added
416 */
417void WorldEntity::addMountPoint(MountPoint* mountPoint)
418{
419  // add the mount point at the last position
420//   this->mountPointMap[](mountPoint);
421  assert(false);
422}
423
424/**
425 * adds a mount point to a world entity
426 * @param mountPoint point to be added
427 */
428void WorldEntity::addMountPoint(int slot, MountPoint* mountPoint)
429{
430  if( this->mountPointMap.find(slot) != this->mountPointMap.end())
431  {
432    PRINTF(2)("adding a mount point to a slot, that already is occupied! ignoring - maybe some object did not get connected well (object: %s)\n", this->getClassCName());
433  }
434
435  // just connect the mount point
436  this->mountPointMap[slot] = mountPoint;
437}
438
439
440/**
441 * mounts a world entity on a specified mount point (~socket)
442 * @param entity entity to be connected
443 */
444void WorldEntity::mount(int slot, WorldEntity* entity)
445{
446  if( this->mountPointMap.find(slot) != this->mountPointMap.end())
447  {
448    PRINTF(0)("you tried to add an entity to a mount point that doesn't exist (slot %i)\n", slot);
449    return;
450  }
451
452  // mount the entity
453  this->mountPoints[slot]->mount(entity);
454}
455
456
457/**
458 * removes a mount point from a specified mount point
459 * @param mountPoint entity to be unconnected
460 */
461void WorldEntity::unmount(int slot)
462{
463  if( this->mountPoints[slot] == NULL)
464  {
465    PRINTF(0)("you tried to remove an entity from a mount point that doesn't exist (slot %i)\n", slot);
466    return;
467  }
468
469  // unmount the entity
470  this->mountPoints[slot]->unmount();
471}
472
473
474/**
475 * subscribes this world entity to a collision reaction
476 *  @param type the type of reaction to subscribe to
477 *  @param target1 a filter target (classID)
478 */
479void WorldEntity::subscribeReaction(CoRe::CREngine::ReactionType type, const ClassID& target1)
480{
481  this->_collisionFilter.subscribeReaction(type, target1);
482}
483
484
485/**
486 * subscribes this world entity to a collision reaction
487 *  @param type the type of reaction to subscribe to
488 *  @param target1 a filter target (classID)
489 */
490void WorldEntity::subscribeReaction(CoRe::CREngine::ReactionType type, const ClassID& target1, const ClassID& target2)
491{
492  this->_collisionFilter.subscribeReaction(type, target1, target2);
493}
494
495
496/**
497 * subscribes this world entity to a collision reaction
498 *  @param type the type of reaction to subscribe to
499 *  @param target1 a filter target (classID)
500 */
501void WorldEntity::subscribeReaction(CoRe::CREngine::ReactionType type, const ClassID& target1, const ClassID& target2, const ClassID& target3)
502{
503  this->_collisionFilter.subscribeReaction(type, target1, target2, target3);
504}
505
506
507/**
508 * unsubscribes a specific reaction from the worldentity
509 *  @param type the reaction to unsubscribe
510 */
511void WorldEntity::unsubscribeReaction(CoRe::CREngine::ReactionType type)
512{
513  this->_collisionFilter.unsubscribeReaction(type);
514}
515
516
517/**
518 * unsubscribes all collision reactions
519 */
520void WorldEntity::unsubscribeReactions()
521{
522  this->_collisionFilter.unsubscribeReactions();
523}
524
525
526/**
527 * @brief moves this entity to the List OM_List
528 * @param list the list to set this Entity to.
529 *
530 * this is the same as a call to State::getObjectManager()->toList(entity , list);
531 * directly, but with an easier interface.
532 *
533 * @todo inline this (peut etre)
534 */
535void WorldEntity::toList(OM_LIST list)
536{
537  State::getObjectManager()->toList(this, list);
538}
539
540void WorldEntity::toListS(const std::string& listName)
541{
542  OM_LIST id = ObjectManager::StringToOMList(listName);
543  if (id != OM_NULL)
544    this->toList(id);
545  else
546    PRINTF(2)("List %s not found\n", listName.c_str());
547}
548
549
550void WorldEntity::toReflectionList()
551{
552  State::getObjectManager()->toReflectionList( this );
553}
554
555void removeFromReflectionList()
556{
557  /// TODO
558  ///  State::getObject
559}
560
561/**
562 * sets the character attributes of a worldentity
563 * @param character attributes
564 *
565 * these attributes don't have to be set, only use them, if you need them
566*/
567//void WorldEntity::setCharacterAttributes(CharacterAttributes* charAttr)
568//{}
569
570
571/**
572 *  this function is called, when two entities collide
573 * @param entity: the world entity with whom it collides
574 *
575 * Implement behaviour like damage application or other miscellaneous collision stuff in this function
576 */
577void WorldEntity::collidesWith(WorldEntity* entity, const Vector& location)
578{
579  /**
580   * THIS IS A DEFAULT COLLISION-Effect.
581   * IF YOU WANT TO CREATE A SPECIFIC COLLISION ON EACH OBJECT
582   * USE::
583   * if (entity->isA(CL_WHAT_YOU_ARE_LOOKING_FOR)) { printf "dothings"; };
584   *
585   * You can always define a default Action.... don't be affraid just test it :)
586   */
587  //  PRINTF(3)("collision %s vs %s @ (%f,%f,%f)\n", this->getClassCName(), entity->getClassCName(), location.x, location.y, location.z);
588}
589
590
591/**
592 *  this function is called, when two entities collide
593 * @param entity: the world entity with whom it collides
594 *
595 * Implement behaviour like damage application or other miscellaneous collision stuff in this function
596 */
597void WorldEntity::collidesWithGround(const Vector& location)
598{
599  PRINTF(0)("BSP_GROUND: %s collides \n", this->getClassCName() );
600}
601
602void WorldEntity::collidesWithGround(const Vector& feet, const Vector& ray_1, const Vector& ray_2)
603{
604
605  // PRINTF(0)("BSP_GROUND: Player collides \n", this->getClassCName() );
606
607  Vector v = this->getAbsDirX();
608  v.x *= 10.1;
609  v.y *= 10.1;
610  v.z *= 10.1;
611  Vector u = Vector(0.0,-20.0,0.0);
612
613
614  if(!(this->getAbsCoor().x == ray_2.x && this->getAbsCoor().y == ray_2.y && this->getAbsCoor().z == ray_2.z) )
615  {
616
617    this->setAbsCoor(ray_2 - v);
618
619  }
620  else
621  {
622    if(ray_1.x == this->getAbsCoor().x + v.x && ray_1.y == this->getAbsCoor().y + v.y + 0.1 && ray_1.z ==this->getAbsCoor().z + v.z)
623    {
624      this->setAbsCoor(feet -u );
625    }
626
627    this->setAbsCoor(ray_2 - v);
628
629  }
630
631
632}
633
634/**
635 *  this is called immediately after the Entity has been constructed, initialized and then Spawned into the World
636 *
637 */
638void WorldEntity::postSpawn ()
639{}
640
641
642/**
643 *  this method is called by the world if the WorldEntity leaves the game
644 */
645void WorldEntity::leaveWorld ()
646{}
647
648
649/**
650 * resets the WorldEntity to its initial values. eg. used for multiplayer games: respawning
651 */
652void WorldEntity::reset()
653{
654  this->setHealth( this->getHealthMax() );
655}
656
657/**
658 *  this method is called every frame
659 * @param time: the time in seconds that has passed since the last tick
660 *
661 * Handle all stuff that should update with time inside this method (movement, animation, etc.)
662*/
663void WorldEntity::tick(float time)
664{}
665
666
667/**
668 *  the entity is drawn onto the screen with this function
669 *
670 * This is a central function of an entity: call it to let the entity painted to the screen.
671 * Just override this function with whatever you want to be drawn.
672*/
673void WorldEntity::draw() const
674{
675  //PRINTF(0)("(%s::%s)\n", this->getClassCName(), this->getName());
676  //  assert(!unlikely(this->models.empty()));
677  {
678    glMatrixMode(GL_MODELVIEW);
679    glPushMatrix();
680
681    /* translate */
682    glTranslatef (this->getAbsCoor ().x,
683                  this->getAbsCoor ().y,
684                  this->getAbsCoor ().z);
685    Vector tmpRot = this->getAbsDir().getSpacialAxis();
686    glRotatef (this->getAbsDir().getSpacialAxisAngle(), tmpRot.x, tmpRot.y, tmpRot.z );
687
688
689    // This Draws the LOD's
690    float cameraDistance = State::getCamera()->distance(this);
691    if (cameraDistance > 30 && this->models.size() >= 3 && this->models[2] != NULL)
692    {
693      this->models[2]->draw();
694    }
695    else if (cameraDistance > 10 && this->models.size() >= 2 && this->models[1] != NULL)
696    {
697      this->models[1]->draw();
698    }
699    else if (this->models.size() >= 1 && this->models[0] != NULL)
700    {
701      this->models[0]->draw();
702    }
703
704    //if (this->entityTrack)
705    //this->entityTrack->drawGraph(0.02);
706
707    //     if( this->aabbNode != NULL)
708    //       this->aabbNode->drawBV(0, DRAW_BV_POLYGON, Vector(1, 0.6, 0.2), true);
709
710    glPopMatrix();
711  }
712}
713
714
715/**
716 *  the entity is drawn onto the screen with this function
717 *
718 * This is a central function of an entity: call it to let the entity painted to the screen.
719 * Just override this function with whatever you want to be drawn.
720*/
721void WorldEntity::draw(const Model* model) const
722{
723  if(bVisible)
724  {
725  glMatrixMode(GL_MODELVIEW);
726  glPushMatrix();
727
728  /* translate */
729  glTranslatef (this->getAbsCoor ().x,
730                this->getAbsCoor ().y,
731                this->getAbsCoor ().z);
732  Vector tmpRot = this->getAbsDir().getSpacialAxis();
733  glRotatef (this->getAbsDir().getSpacialAxisAngle(), tmpRot.x, tmpRot.y, tmpRot.z );
734
735
736  // This Draws the LOD's
737  if( model != NULL)
738    model->draw();
739
740  glPopMatrix();
741  }
742}
743
744
745/**
746 * @param health the Health to add.
747 * @returns the health left (this->healthMax - health+this->health)
748 */
749float WorldEntity::increaseHealth(float health)
750{
751  this->health += health;
752  if (this->health > this->healthMax)
753  {
754    float retHealth = this->healthMax - this->health;
755    this->health = this->healthMax;
756    this->updateHealthWidget();
757    return retHealth;
758  }
759  this->updateHealthWidget();
760  return 0.0;
761}
762
763/**
764 * @param health the Health to be removed
765 * @returns 0.0 or the rest, that was not substracted (bellow 0.0)
766 */
767float WorldEntity::decreaseHealth(float health)
768{
769  this->health -= health;
770
771  if (this->health < 0)
772  {
773    float retHealth = -this->health;
774    this->health = 0.0f;
775    this->updateHealthWidget();
776    return retHealth;
777  }
778  this->updateHealthWidget();
779  return 0.0;
780}
781
782
783/**
784 * @param maxHealth the maximal health that can be loaded onto the entity.
785 */
786void WorldEntity::setHealthMax(float healthMax)
787{
788  this->healthMax = healthMax;
789  if (this->health > this->healthMax)
790  {
791    PRINTF(3)("new maxHealth is bigger as the old health. Did you really intend to do this for (%s::%s)\n", this->getClassCName(), this->getCName());
792    this->health = this->healthMax;
793  }
794  this->updateHealthWidget();
795}
796
797
798
799/**
800 * @param shiled the Shieldstength to add.
801 * @returns the shield left (this->shieldMax - shiled + this->shield)
802 */
803float WorldEntity::increaseShield(float shiled)
804{
805  this->shield += shield;
806  if (this->shield > this->shieldTH * this->shieldMax) { this->bShieldActive = true; }
807  if (this->shield > this->shieldMax)
808  {
809    float retShield = this->shieldMax - this->shield;
810    this->shield = this->shieldMax;
811    this->updateShieldWidget();
812    return retShield;
813  }
814  this->updateShieldWidget();
815  return 0.0;
816}
817
818/**
819 * @param shield the Shieldstrength to be removed
820 * @returns 0.0 or the rest, if the shield drops belew 0.0
821 */
822float WorldEntity::decreaseShield(float shield)
823{
824  this->shield -= shield;
825
826  if (this->shield <= 0)
827  {
828    float retShield = -this->shield;
829    this->updateShieldWidget();
830    this->bShieldActive = false;
831    return retShield;
832  }
833  this->updateShieldWidget();
834  return 0.0;
835}
836
837
838
839/**
840 * @brief creates the HealthWidget
841 *
842 * since not all entities need an HealthWidget, it is only created on request.
843 */
844void WorldEntity::createHealthWidget()
845{
846  if (this->healthWidget == NULL)
847  {
848    this->healthWidget = new OrxGui::GLGuiEnergyWidgetVertical();
849    //this->healthWidget->setDisplayedName("Health");
850    //this->healthWidget->setSize2D(100,20);
851    //this->healthWidget->setAbsCoor2D(100,200);
852
853    this->updateHealthWidget();
854  }
855  else
856    PRINTF(3)("Allready created the HealthWidget for %s::%s\n", this->getClassCName(), this->getCName());
857}
858
859
860void WorldEntity::createShieldWidget()
861{
862  if (this->shieldWidget == NULL)
863  {
864    this->shieldWidget = new OrxGui::GLGuiEnergyWidgetVertical();
865    this->updateHealthWidget();
866  }
867  else
868    PRINTF(3)("Allready created the ShieldWidget for %s::%s\n", this->getClassCName(), this->getCName());
869}
870
871void WorldEntity::createElectronicWidget()
872{
873  if (this->electronicWidget == NULL)
874  {
875    this->electronicWidget = new OrxGui::GLGuiEnergyWidgetVertical();
876    this->updateElectronicWidget();
877  }
878  else
879    PRINTF(3)("Allready created the ElectronicWidget for %s::%s\n", this->getClassCName(), this->getCName());
880}
881
882
883void WorldEntity::increaseHealthMax(float increaseHealth)
884{
885  this->healthMax += increaseHealth;
886  this->updateHealthWidget();
887}
888
889
890OrxGui::GLGuiWidget* WorldEntity::getHealthWidget()
891{
892  if ( this->healthWidget == NULL)
893    this->createHealthWidget();
894  return this->healthWidget;
895}
896
897
898OrxGui::GLGuiWidget* WorldEntity::getShieldWidget()
899{
900  if ( this->shieldWidget == NULL)
901    this->createShieldWidget();
902  return this->shieldWidget;
903}
904
905
906OrxGui::GLGuiWidget* WorldEntity::getElectronicWidget()
907{
908  if ( this->electronicWidget == NULL)
909    this->createElectronicWidget();
910  return this->electronicWidget;
911}
912
913
914
915/**
916 * @param visibility shows or hides the health-bar
917 * (creates the widget if needed)
918 */
919void WorldEntity::setHealthWidgetVisibility(bool visibility)
920{
921  if (visibility)
922  {
923    if (this->healthWidget != NULL)
924      this->healthWidget->show();
925    else
926    {
927      this->createHealthWidget();
928      this->updateHealthWidget();
929      this->healthWidget->show();
930    }
931  }
932  else if (this->healthWidget != NULL)
933    this->healthWidget->hide();
934}
935
936
937/**
938 * hit the world entity with
939 *  @param damage damage to be dealt
940 */
941void WorldEntity::hit(float damage, WorldEntity* killer)
942{
943
944  this->decreaseHealth(damage);
945
946  PRINTF(5)("Hit me: %s::%s now only %f/%f health\n", this->getClassCName(), this->getCName(), this->getHealth(), this->getHealthMax());
947
948  if( this->getHealth() > 0)
949  {
950    // any small explosion animaitions
951  }
952  else
953  {
954    this->destroy( killer );
955  }
956}
957
958
959/**
960 * destoys the world entity
961 */
962void WorldEntity::destroy(WorldEntity* killer)
963{
964  this->toList(OM_DEAD);
965}
966
967
968/**
969 * @brief updates the HealthWidget
970 */
971void WorldEntity::updateHealthWidget()
972{
973  if (this->healthWidget != NULL)
974  {
975    this->healthWidget->setMaximum(this->healthMax);
976    this->healthWidget->setValue(this->health);
977  }
978}
979
980/**
981 * @brief updates the Electronic Widget
982 */
983//!< xferred from spaceship
984void WorldEntity::updateElectronicWidget(){
985  if (this->electronicWidget != NULL)
986  { //if it exists already: update it
987     this->electronicWidget->setMaximum(this->electronicMax);
988     this->electronicWidget->setValue(this->electronic);
989  }
990  else
991  { //create the widget
992    this->electronicWidget = new OrxGui::GLGuiEnergyWidgetVertical();
993    this->electronicWidget->getBarWidget()->setChangedValueColor(Color(1,0,0,1));
994    //this->electronicWidget->setDisplayedName("Electronics:");
995    //this->electronicWidget->setSize2D(100,20);
996    //this->electronicWidget->setAbsCoor2D(150,200);
997    this->updateElectronicWidget();
998//     if ( dynamic_cast<SpaceShip*>(this)->hasPlayer() )
999//       State::getPlayer()->hud().setEnergyWidget(this->electronicWidget);
1000  }
1001}
1002
1003/**
1004 * @brief updates the ShieldWidget
1005 */
1006//!< xferred from spaceship
1007void WorldEntity::updateShieldWidget()
1008{
1009  if (this->shieldWidget != NULL)
1010  {
1011    this->shieldWidget->setMaximum(this->shieldMax);
1012    this->shieldWidget->setValue(this->shield);;
1013  }
1014  else
1015  {
1016    this->shieldWidget = new OrxGui::GLGuiEnergyWidgetVertical();
1017    this->shieldWidget->getBarWidget()->setChangedValueColor(Color(1,0,0,1));
1018    //this->shieldWidget->setDisplayedName("Shield:");
1019    //his->shieldWidget->setSize2D(100,20);
1020    //this->shieldWidget->setAbsCoor2D(200,200);
1021    this->updateShieldWidget();
1022//     if (dynamic_cast<SpaceShip*>(this)->hasPlayer())
1023//       State::getPlayer()->hud().setShieldWidget(this->shieldWidget);
1024  }
1025}
1026
1027
1028
1029/**
1030 * DEBUG-DRAW OF THE BV-Tree.
1031 * @param depth What depth to draw
1032 * @param drawMode the mode to draw this entity under
1033 */
1034void WorldEntity::drawBVTree(int depth, int drawMode) const
1035{
1036  glMatrixMode(GL_MODELVIEW);
1037  glPushMatrix();
1038  /* translate */
1039  glTranslatef (this->getAbsCoor ().x,
1040                this->getAbsCoor ().y,
1041                this->getAbsCoor ().z);
1042  /* rotate */
1043  Vector tmpRot = this->getAbsDir().getSpacialAxis();
1044  glRotatef (this->getAbsDir().getSpacialAxisAngle(), tmpRot.x, tmpRot.y, tmpRot.z );
1045
1046
1047  if (this->obbTree)
1048    this->obbTree->drawBV(depth, drawMode);
1049
1050
1051  glPopMatrix();
1052}
1053
1054
1055
1056/**
1057 * draw the mounting points
1058 */
1059void WorldEntity::debugDrawMountPoints() const
1060{
1061
1062  std::vector<MountPoint*>::const_iterator it = this->mountPoints.begin();
1063  for( ; it < this->mountPoints.end(); it++)
1064  {
1065    if( (*it) != NULL)
1066    {
1067      (*it)->debugDraw();
1068    }
1069  }
1070}
1071
1072
1073/**
1074 * Debug the WorldEntity
1075 */
1076void WorldEntity::debugEntity() const
1077{
1078  PRINT(0)("WorldEntity %s::%s  (DEBUG)\n", this->getClassCName(), this->getCName());
1079  this->debugNode();
1080  PRINT(0)("List: %s ; ModelCount %d - ", ObjectManager::OMListToString(this->objectListNumber).c_str(), this->models.size());
1081  for (unsigned int i = 0; i < this->models.size(); i++)
1082  {
1083    if (models[i] != NULL)
1084      PRINT(0)(" : %d:%s", i, this->models[i]->getCName());
1085  }
1086  PRINT(0)("\n");
1087
1088}
1089
1090
1091/**
1092 * handler for changes on registred vars
1093 * @param id id's which changed
1094 */
1095void WorldEntity::varChangeHandler( std::list< int > & id )
1096{
1097  if ( std::find( id.begin(), id.end(), modelFileName_handle ) != id.end() ||
1098       std::find( id.begin(), id.end(), scaling_handle ) != id.end()
1099     )
1100  {
1101    loadModel( modelFileName, scaling );
1102  }
1103
1104  if ( std::find( id.begin(), id.end(), list_handle ) != id.end() )
1105  {
1106    this->toList( (OM_LIST)list_write );
1107  }
1108
1109  if ( std::find( id.begin(), id.end(), health_handle ) != id.end() )
1110  {
1111    this->setHealth( health_write );
1112  }
1113
1114  if ( std::find( id.begin(), id.end(), healthMax_handle ) != id.end() )
1115  {
1116    this->setHealthMax( healthMax_write );
1117  }
1118
1119  PNode::varChangeHandler( id );
1120}
1121
1122
1123void WorldEntity::regen(float time){
1124  static float tmp;
1125  increaseHealth(time * this->healthRegen);
1126  increaseShield(time * this->shieldRegen);
1127//   updateHealthWidget();
1128//   updateShieldWidget();
1129
1130  //this->setHealth( this->shieldCur);      // FIXME currently just to test share system
1131
1132  if (this->electronic != this->electronicMax || this->electronicRegen != 0){
1133    tmp = this->electronic + this->electronicRegen * time;
1134    if ( tmp > electronicMax)
1135      this->electronic = this->electronicMax;
1136    else
1137      this->electronic = tmp;
1138
1139    updateElectronicWidget();
1140  }
1141
1142}
Note: See TracBrowser for help on using the repository browser.