Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10710 was 10710, checked in by rennerc, 17 years ago

player cannot shoot throu walls
per default worldentities cannot be killed
weapon correct again

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