Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/playability/src/world_entities/world_entity.cc @ 10088

Last change on this file since 10088 was 10088, checked in by patrick, 17 years ago

added the track subsystem to the buildprocess again, integrated it into the new basobject framework and commented out big regions of code because it didn't compile.
@beni: your work now can begin :D

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