Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/presentation/src/world_entities/world_entity.cc @ 9232

Last change on this file since 9232 was 9232, checked in by patrick, 18 years ago

last changes

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