Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/world_entities/world_entity.cc @ 10505

Last change on this file since 10505 was 10498, checked in by bknecht, 18 years ago

use pauseCamera in scripts to pause the track of the camera. this works also with pause on NPCs and spaceships with tracks

File size: 25.1 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 "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 "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->healthMax = 1.0f;
78  this->health = 1.0f;
79  this->damage = 0.0f; // no damage dealt by a default entity
80  this->scaling = 1.0f;
81  this->oiFile = NULL;
82  // add 10 members to this array
83  this->mountPoints.reserve(10);
84
85  /* OSOLETE */
86  this->bVisible = true;
87  this->bCollide = true;
88
89  this->objectListNumber = OM_INIT;
90  this->lastObjectListNumber = OM_INIT;
91
92  this->_bOnGround = false;
93
94  // Track of this entity
95  this->entityTrack = NULL;
96  this->bDrawTrack = false;
97
98  // registering default reactions:
99  this->subscribeReaction(CoRe::CREngine::CR_OBJECT_DAMAGE, Projectile::staticClassID());
100
101  this->toList(OM_NULL);
102
103  this->registerVar( new SynchronizeableString( &this->md2TextureFileName, &this->md2TextureFileName, "md2TextureFileName", PERMISSION_MASTER_SERVER ) );
104  this->modelFileName_handle = registerVarId( new SynchronizeableString( &modelFileName, &modelFileName, "modelFileName", PERMISSION_MASTER_SERVER ) );
105  this->scaling_handle = registerVarId( new SynchronizeableFloat( &scaling, &scaling, "scaling", PERMISSION_MASTER_SERVER ) );
106  this->list_handle = registerVarId( new SynchronizeableInt( (int*)&objectListNumber, &list_write, "list", PERMISSION_MASTER_SERVER ) );
107
108  this->health_handle = registerVarId( new SynchronizeableFloat( &this->health, &this->health_write, "health", PERMISSION_MASTER_SERVER ) );
109  this->healthMax_handle = registerVarId( new SynchronizeableFloat( &this->healthMax, &this->healthMax_write, "maxHealth", PERMISSION_MASTER_SERVER ) );
110}
111
112/**
113 *  standard destructor
114*/
115WorldEntity::~WorldEntity ()
116{
117  State::getObjectManager()->toList(this, OM_INIT);
118
119  // Delete the model (unregister it with the ResourceManager)
120  for (unsigned int i = 0; i < this->models.size(); i++)
121    this->setModel(NULL, i);
122
123  // remove the object information file
124  if( this->oiFile)
125    delete this->oiFile;
126  // and clear all monut points
127  this->mountPoints.clear();
128
129  // Delete the obbTree
130  if( this->obbTree != NULL)
131    delete this->obbTree;
132
133  if (this->healthWidget != NULL)
134    delete this->healthWidget;
135
136  this->unsubscribeReactions();
137}
138
139/**
140 * loads the WorldEntity Specific Parameters.
141 * @param root: the XML-Element to load the Data From
142 */
143void WorldEntity::loadParams(const TiXmlElement* root)
144{
145  // Do the PNode loading stuff
146  PNode::loadParams(root);
147
148  LoadParam(root, "md2texture", this, WorldEntity, loadMD2Texture)
149  .describe("the fileName of the texture, that should be loaded onto this world-entity. (must be relative to the data-dir)")
150  .defaultValues("");
151
152  // Model Loading
153  LoadParam(root, "model", this, WorldEntity, loadModel)
154  .describe("the fileName of the model, that should be loaded onto this world-entity. (must be relative to the data-dir)")
155  .defaultValues("", 1.0f, 0);
156
157  LoadParam(root, "mountpoints", this, WorldEntity, loadMountPoints)
158  .describe("the fileName of the object information file (optional)");
159
160  // Entity Attributes
161  LoadParam(root, "maxHealth", this, WorldEntity, setHealthMax)
162  .describe("The Maximum health that can be loaded onto this entity")
163  .defaultValues(1.0f);
164
165  LoadParam(root, "health", this, WorldEntity, setHealth)
166  .describe("The Health the WorldEntity has at this moment")
167  .defaultValues(1.0f);
168
169  LoadParam(root, "list", this, WorldEntity, toListS);
170
171  LoadParam(root, "drawTrack", this, WorldEntity, drawDebugTrack)
172      .describe("draws the track for debugging purposes");
173
174  // Track
175  LoadParamXML(root, "Track", this, WorldEntity, addTrack)
176  .describe("creates and adds a track to this WorldEntity");
177}
178
179
180/**
181 * this functions adds a track to this workd entity. This can be usefull, if you like this WE to follow a some waypoints.
182 * here the track is created and further initializing left for the Track itself
183 */
184void WorldEntity::addTrack(const TiXmlElement* root)
185{
186  // The problem we have is most likely here. The track should be constructed WITH the XML-Code
187  this->entityTrack = new Track(root);
188  this->setParent(this->entityTrack->getTrackNode());
189  this->entityTrack->getTrackNode()->setParentMode(PNODE_ALL);
190  /*LOAD_PARAM_START_CYCLE(root, element);
191  {
192    PRINTF(4)("element is: %s\n", element->Value());
193    Factory::fabricate(element);
194  }
195  LOAD_PARAM_END_CYCLE(element);*/
196
197
198}
199
200void WorldEntity::pauseTrack(bool stop)
201{
202     if(this->entityTrack)
203       this->entityTrack->pauseTrack(stop);
204}
205
206
207/**
208 * loads a Model onto a WorldEntity
209 * @param fileName the name of the model to load
210 * @param scaling the Scaling of the model
211 *
212 * FIXME
213 * @todo: separate the obb tree generation from the model
214 */
215void WorldEntity::loadModel(const std::string& fileName, float scaling, unsigned int modelNumber, unsigned int obbTreeDepth)
216{
217  this->modelLODName = fileName;
218  this->scaling = scaling;
219
220  std::string name = fileName;
221
222  if (  name.find( Resources::ResourceManager::getInstance()->mainGlobalPath().name() ) == 0 )
223  {
224    name.erase(Resources::ResourceManager::getInstance()->mainGlobalPath().name().size());
225  }
226
227  this->modelFileName = name;
228
229  if (!fileName.empty())
230  {
231    // search for the special character # in the LoadParam
232    if (fileName.find('#') != std::string::npos)
233    {
234      PRINTF(4)("Found # in %s... searching for LOD's\n", fileName.c_str());
235      std::string lodFile = fileName;
236      unsigned int offset = lodFile.find('#');
237      for (unsigned int i = 0; i < 3; i++)
238      {
239        lodFile[offset] = 48+(int)i;
240        if (Resources::ResourceManager::getInstance()->checkFileInMainPath( lodFile))
241          this->loadModel(lodFile, scaling, i);
242      }
243      return;
244    }
245    if (this->scaling <= 0.0)
246    {
247      PRINTF(1)("YOU GAVE ME A CRAPY SCALE resetting to 1.0\n");
248      this->scaling = 1.0;
249    }
250    /// LOADING AN OBJ FILE
251    if(fileName.find(".obj") != std::string::npos)
252    {
253      PRINTF(4)("fetching OBJ file: %s\n", fileName.c_str());
254      // creating the model and loading it
255      StaticModel* model = new StaticModel();
256      *model = ResourceOBJ(fileName, this->scaling);
257
258      // check if ther is a valid model and load other stuff
259      if (model->getVertexCount() > 0)
260      {
261        this->setModel(model, modelNumber);
262
263        if( modelNumber == 0)
264        {
265          this->buildObbTree(obbTreeDepth);
266        }
267      }
268      else
269        delete model;
270    }
271    /// LOADING AN MD2-model
272    else if(fileName.find(".md2") != std::string::npos)
273    {
274      PRINTF(4)("fetching MD2 file: %s\n", fileName.c_str());
275      Model* m = new MD2Model(fileName, this->md2TextureFileName, this->scaling);
276      //this->setModel((Model*)ResourceManager::getInstance()->load(fileName, MD2, RP_CAMPAIGN), 0);
277      this->setModel(m, 0);
278
279      if( m != NULL)
280        this->buildObbTree(obbTreeDepth);
281    }
282    /// LOADING AN MD3-MODEL.
283    else if(fileName.find(".md3") != std::string::npos)
284    {
285      PRINTF(4)("fetching MD3 file: %s\n", fileName.c_str());
286      //      Model* m = new md3::MD3Model(fileName, this->scaling);
287      //      this->setModel(m, 0);
288
289      //       if( m != NULL)
290      //         this->buildObbTree(obbTreeDepth);
291    }
292  }
293  else
294  {
295    this->setModel(NULL);
296  }
297}
298
299/**
300 * sets a specific Model for the Object.
301 * @param model The Model to set
302 * @param modelNumber the n'th model in the List to get.
303 */
304void WorldEntity::setModel(Model* model, unsigned int modelNumber)
305{
306  if (this->models.size() <= modelNumber)
307    this->models.resize(modelNumber+1, NULL);
308
309  if (this->models[modelNumber] != NULL)
310  {
311    delete this->models[modelNumber];
312  }
313
314  this->models[modelNumber] = model;
315}
316
317
318
319/**
320 * loads the object information file for this model
321 * @param fileName the name of the file
322 */
323void WorldEntity::loadMountPoints(const std::string& fileName)
324{
325  PRINTF(5)("loading the oif File: %s\n", fileName.c_str());
326
327  // now load the object information file
328  this->oiFile = new ObjectInformationFile(fileName);
329
330  // get the model to load
331  Model* model = this->getModel();
332
333  // extract the mount points
334  model->extractMountPoints();
335
336  // first get all mount points from the model
337  const std::list<mountPointSkeleton> mpList = model->getMountPoints();
338  // for each skeleton create a mounting point world entity
339  std::list<mountPointSkeleton>::const_iterator it = mpList.begin();
340
341  for( ; it != mpList.end(); it++)
342  {
343    // create the mount points world entity
344    MountPoint* mp = new MountPoint( (*it).up, (*it).forward, (*it).center, (*it).name);
345    // parent it to this WE
346    mp->setParent( this);
347    // now add to the right group
348    mp->toList( (OM_LIST)(this->getOMListNumber()+1));
349    // now get the number and add the mount point to the slot
350    std::string nrStr = (*it).name.substr(3, 2);
351    // add the mount point
352    this->addMountPoint(atoi(nrStr.c_str()), mp);
353
354    // now fill the mount point
355    mp->initMountPoint( this->oiFile->getMountPointDescription());
356  }
357
358}
359
360
361/**
362 * builds the obb-tree
363 * @param depth the depth to calculate
364 */
365bool WorldEntity::buildObbTree(int depth)
366{
367  if( this->obbTree != NULL)
368  {
369    delete this->obbTree;
370    this->obbTree = NULL;
371  }
372
373  if (this->models[0] != NULL)
374    this->obbTree = new OBBTree(depth, models[0]->getModelInfo(), this);
375  else
376  {
377    PRINTF(1)("could not create obb-tree, because no model was loaded yet\n");
378    this->obbTree = NULL;
379    return false;
380  }
381
382
383  // create the axis aligned bounding box
384  if( this->aabbNode != NULL)
385  {
386    delete this->aabbNode;
387    this->aabbNode = NULL;
388  }
389
390  if( this->models[0] != NULL)
391  {
392    this->aabbNode = new AABBTreeNode();
393    this->aabbNode->spawnBVTree(this->models[0]);
394  }
395  else
396  {
397    PRINTF(1)("could not create aabb bounding box, because no model was loaded yet\n");
398    this->aabbNode = NULL;
399    return false;
400  }
401  return true;
402}
403
404
405/**
406 * adds a mount point to the end of the list
407 * @param mountPoint point to be added
408 */
409void WorldEntity::addMountPoint(MountPoint* mountPoint)
410{
411  // add the mount point at the last position
412  this->mountPoints.push_back(mountPoint);
413}
414
415/**
416 * adds a mount point to a world entity
417 * @param mountPoint point to be added
418 */
419void WorldEntity::addMountPoint(int slot, MountPoint* mountPoint)
420{
421  if( this->mountPoints.capacity() < (unsigned int)slot)
422  {
423    // reserve 5 more slots than needed so this function is called as rare as possible
424    this->mountPoints.reserve(slot + 5);
425  }
426  else if( this->mountPoints[slot] != NULL)
427  {
428    PRINTF(4)("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());
429  }
430
431  // just connect the mount point
432  this->mountPoints[slot] = mountPoint;
433}
434
435
436/**
437 * mounts a world entity on a specified mount point (~socket)
438 * @param entity entity to be connected
439 */
440void WorldEntity::mount(int slot, WorldEntity* entity)
441{
442  if( this->mountPoints[slot] == NULL)
443  {
444    PRINTF(0)("you tried to add an entity to a mount point that doesn't exist (slot %i)\n", slot);
445    return;
446  }
447
448  // mount the entity
449  this->mountPoints[slot]->mount(entity);
450}
451
452
453/**
454 * removes a mount point from a specified mount point
455 * @param mountPoint entity to be unconnected
456 */
457void WorldEntity::unmount(int slot)
458{
459  if( this->mountPoints[slot] == NULL)
460  {
461    PRINTF(0)("you tried to remove an entity from a mount point that doesn't exist (slot %i)\n", slot);
462    return;
463  }
464
465  // unmount the entity
466  this->mountPoints[slot]->unmount();
467}
468
469
470/**
471 * subscribes this world entity to a collision reaction
472 *  @param type the type of reaction to subscribe to
473 *  @param target1 a filter target (classID)
474 */
475void WorldEntity::subscribeReaction(CoRe::CREngine::ReactionType type, const ClassID& target1)
476{
477  this->_collisionFilter.subscribeReaction(type, target1);
478}
479
480
481/**
482 * subscribes this world entity to a collision reaction
483 *  @param type the type of reaction to subscribe to
484 *  @param target1 a filter target (classID)
485 */
486void WorldEntity::subscribeReaction(CoRe::CREngine::ReactionType type, const ClassID& target1, const ClassID& target2)
487{
488  this->_collisionFilter.subscribeReaction(type, target1, target2);
489}
490
491
492/**
493 * subscribes this world entity to a collision reaction
494 *  @param type the type of reaction to subscribe to
495 *  @param target1 a filter target (classID)
496 */
497void WorldEntity::subscribeReaction(CoRe::CREngine::ReactionType type, const ClassID& target1, const ClassID& target2, const ClassID& target3)
498{
499  this->_collisionFilter.subscribeReaction(type, target1, target2, target3);
500}
501
502
503/**
504 * unsubscribes a specific reaction from the worldentity
505 *  @param type the reaction to unsubscribe
506 */
507void WorldEntity::unsubscribeReaction(CoRe::CREngine::ReactionType type)
508{
509  this->_collisionFilter.unsubscribeReaction(type);
510}
511
512
513/**
514 * unsubscribes all collision reactions
515 */
516void WorldEntity::unsubscribeReactions()
517{
518  this->_collisionFilter.unsubscribeReactions();
519}
520
521
522/**
523 * @brief moves this entity to the List OM_List
524 * @param list the list to set this Entity to.
525 *
526 * this is the same as a call to State::getObjectManager()->toList(entity , list);
527 * directly, but with an easier interface.
528 *
529 * @todo inline this (peut etre)
530 */
531void WorldEntity::toList(OM_LIST list)
532{
533  State::getObjectManager()->toList(this, list);
534}
535
536void WorldEntity::toListS(const std::string& listName)
537{
538  OM_LIST id = ObjectManager::StringToOMList(listName);
539  if (id != OM_NULL)
540    this->toList(id);
541  else
542    PRINTF(2)("List %s not found\n", listName.c_str());
543}
544
545
546void WorldEntity::toReflectionList()
547{
548  State::getObjectManager()->toReflectionList( this );
549}
550
551void removeFromReflectionList()
552{
553  /// TODO
554  ///  State::getObject
555}
556
557/**
558 * sets the character attributes of a worldentity
559 * @param character attributes
560 *
561 * these attributes don't have to be set, only use them, if you need them
562*/
563//void WorldEntity::setCharacterAttributes(CharacterAttributes* charAttr)
564//{}
565
566
567/**
568 *  this function is called, when two entities collide
569 * @param entity: the world entity with whom it collides
570 *
571 * Implement behaviour like damage application or other miscellaneous collision stuff in this function
572 */
573void WorldEntity::collidesWith(WorldEntity* entity, const Vector& location)
574{
575  /**
576   * THIS IS A DEFAULT COLLISION-Effect.
577   * IF YOU WANT TO CREATE A SPECIFIC COLLISION ON EACH OBJECT
578   * USE::
579   * if (entity->isA(CL_WHAT_YOU_ARE_LOOKING_FOR)) { printf "dothings"; };
580   *
581   * You can always define a default Action.... don't be affraid just test it :)
582   */
583  //  PRINTF(3)("collision %s vs %s @ (%f,%f,%f)\n", this->getClassCName(), entity->getClassCName(), location.x, location.y, location.z);
584}
585
586
587/**
588 *  this function is called, when two entities collide
589 * @param entity: the world entity with whom it collides
590 *
591 * Implement behaviour like damage application or other miscellaneous collision stuff in this function
592 */
593void WorldEntity::collidesWithGround(const Vector& location)
594{
595  PRINTF(0)("BSP_GROUND: %s collides \n", this->getClassCName() );
596}
597
598void WorldEntity::collidesWithGround(const Vector& feet, const Vector& ray_1, const Vector& ray_2)
599{
600
601  // PRINTF(0)("BSP_GROUND: Player collides \n", this->getClassCName() );
602
603  Vector v = this->getAbsDirX();
604  v.x *= 10.1;
605  v.y *= 10.1;
606  v.z *= 10.1;
607  Vector u = Vector(0.0,-20.0,0.0);
608
609
610  if(!(this->getAbsCoor().x == ray_2.x && this->getAbsCoor().y == ray_2.y && this->getAbsCoor().z == ray_2.z) )
611  {
612
613    this->setAbsCoor(ray_2 - v);
614
615  }
616  else
617  {
618    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)
619    {
620      this->setAbsCoor(feet -u );
621    }
622
623    this->setAbsCoor(ray_2 - v);
624
625  }
626
627
628}
629
630/**
631 *  this is called immediately after the Entity has been constructed, initialized and then Spawned into the World
632 *
633 */
634void WorldEntity::postSpawn ()
635{}
636
637
638/**
639 *  this method is called by the world if the WorldEntity leaves the game
640 */
641void WorldEntity::leaveWorld ()
642{}
643
644
645/**
646 * resets the WorldEntity to its initial values. eg. used for multiplayer games: respawning
647 */
648void WorldEntity::reset()
649{
650  this->setHealth( this->getHealthMax() );
651}
652
653/**
654 *  this method is called every frame
655 * @param time: the time in seconds that has passed since the last tick
656 *
657 * Handle all stuff that should update with time inside this method (movement, animation, etc.)
658*/
659void WorldEntity::tick(float time)
660{}
661
662
663/**
664 *  the entity is drawn onto the screen with this function
665 *
666 * This is a central function of an entity: call it to let the entity painted to the screen.
667 * Just override this function with whatever you want to be drawn.
668*/
669void WorldEntity::draw() const
670{
671  //PRINTF(0)("(%s::%s)\n", this->getClassCName(), this->getName());
672  //  assert(!unlikely(this->models.empty()));
673  {
674    glMatrixMode(GL_MODELVIEW);
675    glPushMatrix();
676
677    /* translate */
678    glTranslatef (this->getAbsCoor ().x,
679                  this->getAbsCoor ().y,
680                  this->getAbsCoor ().z);
681    Vector tmpRot = this->getAbsDir().getSpacialAxis();
682    glRotatef (this->getAbsDir().getSpacialAxisAngle(), tmpRot.x, tmpRot.y, tmpRot.z );
683
684
685    // This Draws the LOD's
686    float cameraDistance = State::getCamera()->distance(this);
687    if (cameraDistance > 30 && this->models.size() >= 3 && this->models[2] != NULL)
688    {
689      this->models[2]->draw();
690    }
691    else if (cameraDistance > 10 && this->models.size() >= 2 && this->models[1] != NULL)
692    {
693      this->models[1]->draw();
694    }
695    else if (this->models.size() >= 1 && this->models[0] != NULL)
696    {
697      this->models[0]->draw();
698    }
699
700    //if (this->entityTrack)
701    //this->entityTrack->drawGraph(0.02);
702
703    //     if( this->aabbNode != NULL)
704    //       this->aabbNode->drawBV(0, DRAW_BV_POLYGON, Vector(1, 0.6, 0.2), true);
705
706    glPopMatrix();
707  }
708}
709
710
711/**
712 *  the entity is drawn onto the screen with this function
713 *
714 * This is a central function of an entity: call it to let the entity painted to the screen.
715 * Just override this function with whatever you want to be drawn.
716*/
717void WorldEntity::draw(const Model* model) const
718{
719  glMatrixMode(GL_MODELVIEW);
720  glPushMatrix();
721
722  /* translate */
723  glTranslatef (this->getAbsCoor ().x,
724                this->getAbsCoor ().y,
725                this->getAbsCoor ().z);
726  Vector tmpRot = this->getAbsDir().getSpacialAxis();
727  glRotatef (this->getAbsDir().getSpacialAxisAngle(), tmpRot.x, tmpRot.y, tmpRot.z );
728
729
730  // This Draws the LOD's
731  if( model != NULL)
732    model->draw();
733
734  glPopMatrix();
735}
736
737
738/**
739 * @param health the Health to add.
740 * @returns the health left (this->healthMax - health+this->health)
741 */
742float WorldEntity::increaseHealth(float health)
743{
744  this->health += health;
745  if (this->health > this->healthMax)
746  {
747    float retHealth = this->healthMax - this->health;
748    this->health = this->healthMax;
749    this->updateHealthWidget();
750    return retHealth;
751  }
752  this->updateHealthWidget();
753  return 0.0;
754}
755
756/**
757 * @param health the Health to be removed
758 * @returns 0.0 or the rest, that was not substracted (bellow 0.0)
759 */
760float WorldEntity::decreaseHealth(float health)
761{
762  this->health -= health;
763
764  if (this->health < 0)
765  {
766    float retHealth = -this->health;
767    this->health = 0.0f;
768    this->updateHealthWidget();
769    return retHealth;
770  }
771  this->updateHealthWidget();
772  return 0.0;
773
774}
775
776/**
777 * @param maxHealth the maximal health that can be loaded onto the entity.
778 */
779void WorldEntity::setHealthMax(float healthMax)
780{
781  this->healthMax = healthMax;
782  if (this->health > this->healthMax)
783  {
784    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());
785    this->health = this->healthMax;
786  }
787  this->updateHealthWidget();
788}
789
790/**
791 * @brief creates the HealthWidget
792 *
793 * since not all entities need an HealthWidget, it is only created on request.
794 */
795void WorldEntity::createHealthWidget()
796{
797  if (this->healthWidget == NULL)
798  {
799    this->healthWidget = new OrxGui::GLGuiEnergyWidgetVertical();
800    //this->healthWidget->setDisplayedName("Health");
801    //this->healthWidget->setSize2D(100,20);
802    //this->healthWidget->setAbsCoor2D(100,200);
803
804    this->updateHealthWidget();
805  }
806  else
807    PRINTF(3)("Allready created the HealthWidget for %s::%s\n", this->getClassCName(), this->getCName());
808}
809
810void WorldEntity::increaseHealthMax(float increaseHealth)
811{
812  this->healthMax += increaseHealth;
813  this->updateHealthWidget();
814}
815
816
817OrxGui::GLGuiWidget* WorldEntity::getHealthWidget()
818{
819  this->createHealthWidget();
820  return this->healthWidget;
821}
822
823/**
824 * @param visibility shows or hides the health-bar
825 * (creates the widget if needed)
826 */
827void WorldEntity::setHealthWidgetVisibilit(bool visibility)
828{
829  if (visibility)
830  {
831    if (this->healthWidget != NULL)
832      this->healthWidget->show();
833    else
834    {
835      this->createHealthWidget();
836      this->updateHealthWidget();
837      this->healthWidget->show();
838    }
839  }
840  else if (this->healthWidget != NULL)
841    this->healthWidget->hide();
842}
843
844
845/**
846 * hit the world entity with
847 *  @param damage damage to be dealt
848 */
849void WorldEntity::hit(float damage, WorldEntity* killer)
850{
851
852  this->decreaseHealth(damage);
853
854  PRINTF(5)("Hit me: %s::%s now only %f/%f health\n", this->getClassCName(), this->getCName(), this->getHealth(), this->getHealthMax());
855
856  if( this->getHealth() > 0)
857  {
858    // any small explosion animaitions
859  }
860  else
861  {
862    this->destroy( killer );
863  }
864}
865
866
867/**
868 * destoys the world entity
869 */
870void WorldEntity::destroy(WorldEntity* killer)
871{
872  this->toList(OM_DEAD);
873}
874
875
876/**
877 * @brief updates the HealthWidget
878 */
879void WorldEntity::updateHealthWidget()
880{
881  if (this->healthWidget != NULL)
882  {
883    this->healthWidget->setMaximum(this->healthMax);
884    this->healthWidget->setValue(this->health);
885  }
886}
887
888
889/**
890 * DEBUG-DRAW OF THE BV-Tree.
891 * @param depth What depth to draw
892 * @param drawMode the mode to draw this entity under
893 */
894void WorldEntity::drawBVTree(int depth, int drawMode) const
895{
896  glMatrixMode(GL_MODELVIEW);
897  glPushMatrix();
898  /* translate */
899  glTranslatef (this->getAbsCoor ().x,
900                this->getAbsCoor ().y,
901                this->getAbsCoor ().z);
902  /* rotate */
903  Vector tmpRot = this->getAbsDir().getSpacialAxis();
904  glRotatef (this->getAbsDir().getSpacialAxisAngle(), tmpRot.x, tmpRot.y, tmpRot.z );
905
906
907  if (this->obbTree)
908    this->obbTree->drawBV(depth, drawMode);
909
910
911  glPopMatrix();
912}
913
914
915
916/**
917 * draw the mounting points
918 */
919void WorldEntity::debugDrawMountPoints() const
920{
921
922  std::vector<MountPoint*>::const_iterator it = this->mountPoints.begin();
923  for( ; it < this->mountPoints.end(); it++)
924  {
925    if( (*it) != NULL)
926    {
927      (*it)->debugDraw();
928    }
929  }
930}
931
932
933/**
934 * Debug the WorldEntity
935 */
936void WorldEntity::debugEntity() const
937{
938  PRINT(0)("WorldEntity %s::%s  (DEBUG)\n", this->getClassCName(), this->getCName());
939  this->debugNode();
940  PRINT(0)("List: %s ; ModelCount %d - ", ObjectManager::OMListToString(this->objectListNumber).c_str(), this->models.size());
941  for (unsigned int i = 0; i < this->models.size(); i++)
942  {
943    if (models[i] != NULL)
944      PRINT(0)(" : %d:%s", i, this->models[i]->getCName());
945  }
946  PRINT(0)("\n");
947
948}
949
950
951/**
952 * handler for changes on registred vars
953 * @param id id's which changed
954 */
955void WorldEntity::varChangeHandler( std::list< int > & id )
956{
957  if ( std::find( id.begin(), id.end(), modelFileName_handle ) != id.end() ||
958       std::find( id.begin(), id.end(), scaling_handle ) != id.end()
959     )
960  {
961    loadModel( modelFileName, scaling );
962  }
963
964  if ( std::find( id.begin(), id.end(), list_handle ) != id.end() )
965  {
966    this->toList( (OM_LIST)list_write );
967  }
968
969  if ( std::find( id.begin(), id.end(), health_handle ) != id.end() )
970  {
971    this->setHealth( health_write );
972  }
973
974  if ( std::find( id.begin(), id.end(), healthMax_handle ) != id.end() )
975  {
976    this->setHealthMax( healthMax_write );
977  }
978
979  PNode::varChangeHandler( id );
980}
981
Note: See TracBrowser for help on using the repository browser.