Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/ODE/src/world_entities/npcs/generic_npc.cc @ 9919

Last change on this file since 9919 was 9919, checked in by bottac, 18 years ago

CrPhysicsFullWalk on Static Models and BSP Patches almost working. libODE≥0.7 required.
Screenshot: http://people.ee.ethz.ch/~bottac/Collision_ODE/

File size: 13.9 KB
RevLine 
[8514]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:
16*/
17#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD_ENTITY
18
[9003]19#include "generic_npc.h"
[8514]20
[9003]21
[8514]22#include "util/loading/factory.h"
23#include "util/loading/load_param.h"
24
25#include "interactive_model.h"
26#include "md2/md2Model.h"
27
[8516]28#include "sound_buffer.h"
[9869]29#include "resource_sound_buffer.h"
[8516]30
[9869]31#include "sound/resource_sound_buffer.h"
[8516]32
[9869]33#include "bsp_entity.h"
[9919]34#include "terrain.h"
[8514]35
[9869]36#include "class_id_DEPRECATED.h"
37ObjectListDefinitionID(GenericNPC, CL_GENERIC_NPC);
38CREATE_FACTORY(GenericNPC);
[8514]39
[8894]40#include "script_class.h"
[9869]41CREATE_SCRIPTABLE_CLASS(GenericNPC,
[9003]42                        // Move
[9869]43                        addMethod("walkTo", Executor3<GenericNPC, lua_State*,float,float,float>(&GenericNPC::walkTo))
44                        ->addMethod("runTo", Executor3<GenericNPC, lua_State*,float,float,float>(&GenericNPC::runTo))
45                        ->addMethod("turnTo", Executor1<GenericNPC, lua_State*,float>(&GenericNPC::turnTo))
46                        ->addMethod("finalGoalReached", Executor0ret<GenericNPC, lua_State*,bool>(&GenericNPC::finalGoalReached))
47                        ->addMethod("stop", Executor0<GenericNPC, lua_State*>(&GenericNPC::stop))
48                        ->addMethod("resume", Executor0<GenericNPC, lua_State*>(&GenericNPC::resume))
49                        ->addMethod("playAnimation", Executor2<GenericNPC, lua_State*,int,int>(&GenericNPC::playAnimation))
[9003]50                        // Display
[9869]51                        ->addMethod("hide", Executor0<WorldEntity, lua_State*>(&WorldEntity::hide))
52                        ->addMethod("unhide", Executor0<WorldEntity, lua_State*>(&WorldEntity::unhide))
[9003]53                        // Coordinates
[9869]54                        ->addMethod("getAbsCoorX", Executor0ret<PNode, lua_State*, float>(&PNode::getAbsCoorX))
55                        ->addMethod("getAbsCoorY", Executor0ret<PNode, lua_State*, float>(&PNode::getAbsCoorY))
56                        ->addMethod("getAbsCoorZ", Executor0ret<PNode, lua_State*, float>(&PNode::getAbsCoorZ))
57                        ->addMethod("setAbsCoor", Executor3<PNode, lua_State*,float,float,float>(&PNode::setAbsCoor))
58                        ->addMethod("setAbsDir", Executor4<PNode, lua_State*,float,float,float,float>(&PNode::setAbsDir))
[8894]59                       );
[8514]60
61
[8894]62
[8514]63/**
64 * constructor
65 */
66GenericNPC::GenericNPC(const TiXmlElement* root)
[9003]67    : NPC(root)
[8514]68{
69  this->init();
70
71  if (root != NULL)
72    this->loadParams(root);
73}
74
75
76/**
77 * deconstructor
78 */
79GenericNPC::~GenericNPC ()
[9003]80{}
[8514]81
82
83/**
84 * initializing the npc enity
85 */
86void GenericNPC::init()
87{
[9869]88  this->registerObject(this, GenericNPC::_objectList);
[9235]89
[8514]90  this->toList(OM_GROUP_00);
[8516]91
[9869]92  this->soundBuffer = OrxSound::ResourceSoundBuffer("sound/rain.wav");
[8705]93
[8894]94  time = 30.0f;
[9003]95
[9061]96  this->behaviourList = new std::list<GenericNPC::Anim>;
97
[8705]98  // collision reaction registration
[9919]99  //this->subscribeReaction(CREngine::CR_PHYSICS_GROUND_WALK, BspEntity::staticClassID());
100   this->subscribeReaction(CREngine::CR_PHYSICS_FULL_WALK, Terrain::staticClassID());
[8514]101}
102
103
104/**
105 * loads the Settings of a MD2Creature from an XML-element.
106 * @param root the XML-element to load the MD2Creature's properties from
107 */
108void GenericNPC::loadParams(const TiXmlElement* root)
109{
[8705]110  NPC::loadParams(root);
[8514]111
112}
113
114
115/**
116 * sets the animation of this npc
117 * @param anumationIndex: the animation index
118 * @param anumPlaybackMode: the playback mode
119 */
120void GenericNPC::setAnimation(int animationIndex, int animPlaybackMode)
121{
122  if( likely(this->getModel(0) != NULL))
123    ((InteractiveModel*)this->getModel(0))->setAnimation(animationIndex, animPlaybackMode);
124}
125
126
[9003]127
[8514]128/**
[9003]129 * @returns the current animation number
130 */
131int GenericNPC::getAnimation()
132{
133  if( likely(this->getModel(0) != NULL))
134    return ((InteractiveModel*)this->getModel(0))->getAnimation();
135  else
136    return -1;
137}
138
139
140
141/**
142 * @returns true if animation is finished
143 */
144bool GenericNPC::isAnimationFinished()
145{
146  if( likely(this->getModel(0) != NULL))
147    return ((InteractiveModel*)this->getModel(0))->isAnimationFinished();
148  else
149    return false;
150}
151
152
153/**
154 * sets the animation speed of this entity
155 */
156void GenericNPC::setAnimationSpeed(float speed)
157{
158  if( likely(this->getModel(0) != NULL))
159    ((InteractiveModel*)this->getModel(0))->setAnimationSpeed(speed);
160}
161
162
163
164/**
[8514]165 * sets the animation of this npc
166 * @param anumationIndex: the animation index
167 * @param anumPlaybackMode: the playback mode
168 */
[8705]169void GenericNPC::playAnimation(int animationIndex, int animPlaybackMode)
[8514]170{
171  if( likely(this->getModel(0) != NULL))
172    ((InteractiveModel*)this->getModel(0))->setAnimation(animationIndex, animPlaybackMode);
173
174}
175
176
177/**
178 * play a sound
179 * @param filename: name of the file
180 */
[9061]181void GenericNPC::playSound(const std::string& filename)
[9003]182{}
[8705]183
[8514]184
185
186/**
[9003]187 * stops the generic animation
[8514]188 */
[9003]189void GenericNPC::stop()
[9061]190{
191  this->animationStack.push(this->behaviourList);
192  this->behaviourList = new std::list<GenericNPC::Anim>;
[9110]193
194  if( this->getAnimation() != STAND)
195    this->setAnimation(STAND, MD2_ANIM_LOOP);
[9061]196}
[8590]197
[8802]198
[9061]199/**
200 * continue the generic animation
201 */
202void GenericNPC::resume()
203{
[9110]204  if( this->animationStack.size() == 0)
205    return;
206
[9061]207  delete this->behaviourList;
208  this->behaviourList = this->animationStack.top();
209  this->animationStack.pop();
210}
[8802]211
[9061]212
213/**
214 * each animation has to be initialized here
215 */
[9235]216/**
217 *
218 */
[9003]219void GenericNPC::initNPC()
220{
[9061]221  if (!this->behaviourList->empty())
[9003]222  {
[9061]223    GenericNPC::Anim currentAnimation = this->behaviourList->front();
[8802]224
[9061]225    switch(this->behaviourList->front().type)
[9003]226    {
227      case Walk:
228      {
229        if( this->getAnimation() != RUN)
230          this->setAnimation(RUN, MD2_ANIM_LOOP);
[8894]231
[9003]232        Vector dir = (currentAnimation.v - this->getAbsCoor());
233        dir.y = 0.0f;
[9110]234        dir.normalize();
[9003]235        this->setAbsDir(Quaternion(dir, Vector(0.0, 1.0, 0.0)) * Quaternion(-M_PI_2, Vector(0.0, 1.0, 0.0)));
[8894]236
[9003]237        this->setAnimationSpeed(0.5f);
238      }
[9869]239      break;
[9003]240      case Run:
241      {
242        if( this->getAnimation() != RUN)
243          this->setAnimation(RUN, MD2_ANIM_LOOP);
[8802]244
[9003]245        Vector dir = (currentAnimation.v - this->getAbsCoor()).getNormalized();
[9061]246        dir.y = 0.0f;
247        dir.getNormalized();
[9003]248        this->setAbsDir(Quaternion(dir, Vector(0.0, 1.0, 0.0)) * Quaternion(-M_PI_2, Vector(0.0, 1.0, 0.0)));
[8590]249
[9003]250        this->setAnimationSpeed(1.0f);
251      }
[9869]252      break;
[9003]253      case Crouch:
254      {
255        if( this->getAnimation() != CROUCH_WALK)
256          this->setAnimation(CROUCH_WALK, MD2_ANIM_LOOP);
[8590]257
[9003]258        Vector dir = (currentAnimation.v - this->getAbsCoor()).getNormalized();
[9061]259        dir.y = 0.0f;
260        dir.getNormalized();
[9003]261        this->setAbsDir(Quaternion(dir, Vector(0.0, 1.0, 0.0)) * Quaternion(-M_PI_2, Vector(0.0, 1.0, 0.0)));
[8802]262
[9003]263        this->setAnimationSpeed(1.0f);
264      }
[9869]265      break;
[9003]266      case LookAt:
[9869]267      if( this->getAnimation() != STAND)
268        this->setAnimation(STAND, MD2_ANIM_LOOP);
269      break;
[9003]270      case Shoot:
[9869]271      if( this->getAnimation() != STAND)
272        this->setAnimation(STAND, MD2_ANIM_LOOP);
273      break;
[8894]274
[9003]275      default:
[9869]276      if( this->getAnimation() != STAND)
277        this->setAnimation(STAND, MD2_ANIM_LOOP);
278      break;
[8894]279
[9003]280    }
281  }
[8802]282}
283
284
[9003]285void GenericNPC::nextStep()
[8805]286{
[9061]287  if (!this->behaviourList->empty())
288    this->behaviourList->pop_front();
[9003]289  else
290    return;
[8805]291
292
[9061]293  if (!this->behaviourList->empty())
[9003]294  {
[9061]295    GenericNPC::Anim currentAnimation = this->behaviourList->front();
[8894]296
[9003]297    switch( currentAnimation.type)
298    {
299      case Walk:
300      {
301        if( this->getAnimation() != RUN)
302          this->setAnimation(RUN, MD2_ANIM_LOOP);
[8894]303
[9061]304
[9003]305        Vector dir = (currentAnimation.v - this->getAbsCoor());
306        dir.y = 0.0f;
307        dir.getNormalized();
308        this->setAbsDirSoft(Quaternion(dir, Vector(0.0, 1.0, 0.0)) * Quaternion(-M_PI_2, Vector(0.0, 1.0, 0.0)), 4.0);
[8894]309
[9003]310        this->setAnimationSpeed(0.5f);
311      }
[9869]312      break;
[9003]313      case Run:
314      {
315        if( this->getAnimation() != RUN)
316          this->setAnimation(RUN, MD2_ANIM_LOOP);
[8894]317
[9003]318        Vector dir = (currentAnimation.v - this->getAbsCoor()).getNormalized();
[9061]319        dir.y = 0.0f;
320        dir.getNormalized();
[9003]321        this->setAbsDirSoft(Quaternion(dir, Vector(0.0, 1.0, 0.0)) * Quaternion(-M_PI_2, Vector(0.0, 1.0, 0.0)), 4.0);
[8894]322
[9003]323        this->setAnimationSpeed(1.0f);
324      }
[9869]325      break;
[9003]326      case Crouch:
327      {
328        if( this->getAnimation() != CROUCH_WALK)
329          this->setAnimation(CROUCH_WALK, MD2_ANIM_LOOP);
[8894]330
[9003]331        Vector dir = (currentAnimation.v - this->getAbsCoor()).getNormalized();
[9061]332        dir.y = 0.0f;
333        dir.getNormalized();
[9003]334        this->setAbsDirSoft(Quaternion(dir, Vector(0.0, 1.0, 0.0)) * Quaternion(-M_PI_2, Vector(0.0, 1.0, 0.0)), 4.0);
[8894]335
[9003]336        this->setAnimationSpeed(1.0f);
337      }
[9869]338      break;
[9003]339      case LookAt:
340      {
341        if( this->getAnimation() != STAND)
342          this->setAnimation(STAND, MD2_ANIM_LOOP);
343      }
[9869]344      break;
[9003]345      case Shoot:
[9869]346      if( this->getAnimation() != STAND)
[9003]347        this->setAnimation(STAND, MD2_ANIM_LOOP);
[9869]348      break;
[8894]349
[9003]350      default:
[9869]351      if( this->getAnimation() != STAND)
[9003]352        this->setAnimation(STAND, MD2_ANIM_LOOP);
[9869]353      break;
[9003]354
355    }
[8894]356  }
[9003]357  else
358  {
359    this->setAnimation(STAND, MD2_ANIM_LOOP);
360  }
[8894]361}
362
363
364
365
[9003]366void GenericNPC::walkTo(const Vector& coordinate)
[8894]367{
368
[9003]369  GenericNPC::Anim anim;
370  anim.v = coordinate;
371  anim.type = Walk;
372  anim.speed = 30.0f;
[8894]373
[9061]374  if( this->behaviourList->empty())
[8894]375  {
[9061]376    this->behaviourList->push_back(anim);
[9003]377    this->initNPC();
378  }
379  else
[9061]380    this->behaviourList->push_back(anim);
[9003]381}
[8894]382
[9003]383void GenericNPC::walkTo(float x, float y, float z)
384{
385  //printf("Walking to %f, %f, %f \n",x,y,z);
386  this->walkTo(Vector(x,y,z));
[8894]387
[9003]388}
[8894]389
[9003]390/* running functions */
391void GenericNPC::runTo(const Vector& coordinate)
392{
393  GenericNPC::Anim anim;
394  anim.v = coordinate;
395  anim.type = Run;
396  anim.speed = 60.0f;
[8894]397
[9061]398  if( this->behaviourList->empty())
[9003]399  {
[9061]400    this->behaviourList->push_back(anim);
[9003]401    this->initNPC();
[8894]402  }
[9003]403  else
[9061]404    this->behaviourList->push_back(anim);
[9003]405}
[8894]406
[9003]407void GenericNPC::runTo(float x, float y, float z)
408{
409  this->runTo(Vector(x,y,z));
[8894]410}
411
[9003]412/* couching functinos */
413void GenericNPC::crouchTo(const Vector& coordinate)
414{
415  GenericNPC::Anim anim;
416  anim.v = coordinate;
417  anim.type = Crouch;
[8894]418
[9061]419  if( this->behaviourList->empty())
[9003]420  {
[9061]421    this->behaviourList->push_back(anim);
[9003]422    this->initNPC();
423  }
424  else
[9061]425    this->behaviourList->push_back(anim);
[9003]426}
427void GenericNPC::crouchTo(float x, float y, float z)
[8894]428{
[9003]429  this->crouchTo(Vector(x,y,z));
[8894]430}
431
432
433
[9003]434void GenericNPC::turnTo(float degreeInY)
[8894]435{
[9003]436  GenericNPC::Anim anim;
437  anim.q = Quaternion(Vector(0,1,0), degreeInY);
438  anim.type = TurnTo;
[8894]439
[9061]440  if( this->behaviourList->empty())
[8894]441  {
[9061]442    this->behaviourList->push_back(anim);
[9003]443    this->initNPC();
[8894]444  }
[9003]445  else
[9061]446    this->behaviourList->push_back(anim);
[8894]447}
448
449
[9003]450
[8894]451/**
452 * lookat a world entity
453 * @param worldEntity: the worldentity to look at
454 */
[9003]455void GenericNPC::lookAt(WorldEntity* worldEntity)
[8894]456{
[9003]457  GenericNPC::Anim anim;
458  anim.entity = worldEntity;
459  anim.type = LookAt;
[8894]460
[9061]461  if( this->behaviourList->empty())
[8894]462  {
[9061]463    this->behaviourList->push_back(anim);
[9003]464    this->initNPC();
[8894]465  }
[9003]466  else
[9061]467    this->behaviourList->push_back(anim);
[8894]468}
469
470
471
[9003]472
[8894]473/**
474 * talk to a world entity and play a sound/music/voice
475 * @param worldEntity: entity
476 * @param dialogNr: sound nr to be played (from the xml load tags)
477 */
[9003]478void GenericNPC::talkTo(WorldEntity* worldEntity, int dialogNr)
[8894]479{}
480
481
482/**
483 * world entity to shoot at if there is any weapon on the npc
484 * @param entity: entity to shoot entity
485 */
486void GenericNPC::shootAt(WorldEntity* entity)
487{}
488
489
490
491
492
493
494
495
496
497
498/**
[8514]499 * tick this world entity
500 * @param time: time in seconds expirded since the last tick
501 */
[9003]502void GenericNPC::tick (float dt)
[8514]503{
504  if( likely(this->getModel(0) != NULL))
[9003]505    ((InteractiveModel*)this->getModel(0))->tick(dt);
[8894]506
[9003]507
[9061]508  if (!this->behaviourList->empty())
[9003]509  {
[9061]510    GenericNPC::Anim currentAnimation = this->behaviourList->front();
[9003]511
512    switch( currentAnimation.type)
513    {
514      case Walk:
[9869]515      {
516        Vector dest = currentAnimation.v - this->getAbsCoor();
517        dest.y = 0.0f;
518        if (dest.len() < .5)
[9003]519        {
[9869]520          this->nextStep();
[9003]521        }
[9869]522        else
523        {
524          Vector move = dest.getNormalized() * currentAnimation.speed * dt;
525          this->shiftCoor(move);
526        }
527      }
528      break;
[9003]529
530      case Run:
531      {
532        Vector dest = currentAnimation.v - this->getAbsCoor();
[9110]533        dest.y = 0.0f;
[9003]534        if (dest.len() < .5)
535          this->nextStep();
536        else
537        {
538          this->shiftCoor(dest.getNormalized() * currentAnimation.speed * dt);
539        }
540      }
541      break;
542
543      case Crouch:
544      {
545        Vector dest = currentAnimation.v - this->getAbsCoor();
[9110]546        dest.y = 0.0f;
[9003]547        if (dest.len() < .5)
548          this->nextStep();
549        else
550        {
551          this->shiftCoor(dest.getNormalized() * currentAnimation.speed * dt);
552        }
553      }
554      break;
555
556      case TurnTo:
[9869]557      //Quaternion direction = this->
558      break;
[9003]559
560      case LookAt:
[9869]561      break;
[9003]562
563      case Shoot:
[9869]564      break;
[9003]565
566      default:
[9869]567      break;
[9003]568
569    }
570  }
571
572  // physical falling of the player
[9061]573  if( !this->isOnGround())
574  {
575    this->fallVelocity += 300.0f * dt;
576    //velocity -= Vector(0.0, 1.0, 0.0) * this->fallVelocity;
[9869]577    // PRINTF(0)("%s is not on ground\n", this->getName());
[9061]578    this->shiftCoor(Vector(0, -this->fallVelocity * dt,0));
[9003]579
[9061]580  }
581  else
582  {
583    this->fallVelocity = 0.0f;
584  }
[9003]585
[8514]586}
587
588
589
[9235]590void GenericNPC::destroy(WorldEntity* killer)
[8514]591{
592  int randi = (int)(5.0f * (float)rand()/(float)RAND_MAX);
593
[9003]594  this->setAnimationSpeed(1.0f);
595
[8514]596  if( randi == 1)
597    this->setAnimation(DEATH_FALLBACK, MD2_ANIM_ONCE);
598  else if( randi == 2)
599    this->setAnimation(DEATH_FALLFORWARD, MD2_ANIM_ONCE);
600  else if( randi == 3)
601    this->setAnimation(DEATH_FALLBACKSLOW, MD2_ANIM_ONCE);
602  else if( randi == 4)
603    this->setAnimation(CROUCH_DEATH, MD2_ANIM_ONCE);
604  else
605    this->setAnimation(DEATH_FALLBACK, MD2_ANIM_ONCE);
606}
607
Note: See TracBrowser for help on using the repository browser.