Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/proxy/src/world_entities/world_entity.cc @ 9470

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

heavy permissions fight: no node was ever thought to be client and server at the same time, proxy server are hybrid nodes so there is need for a big framework extension.

  • made the obb creation saver
  • prevented segfaults in the aabb tree creation, this was very dangerous code
  • inserted handshake hack to make the handshake work.

No I will have to get the handshake right so the node works correctly

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