Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10758 was 10758, checked in by nicolasc, 17 years ago

added shield functionality, reverted paeddae's MP patch - does not work

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