Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9958 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
Line 
1
2
3/*
4   orxonox - the future of 3D-vertical-scrollers
5
6   Copyright (C) 2004 orx
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2, or (at your option)
11   any later version.
12
13   ### File Specific
14   main-programmer: Patrick Boenzli
15   co-programmer:
16*/
17#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD_ENTITY
18
19#include "generic_npc.h"
20
21
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
28#include "sound_buffer.h"
29#include "resource_sound_buffer.h"
30
31#include "sound/resource_sound_buffer.h"
32
33#include "bsp_entity.h"
34#include "terrain.h"
35
36#include "class_id_DEPRECATED.h"
37ObjectListDefinitionID(GenericNPC, CL_GENERIC_NPC);
38CREATE_FACTORY(GenericNPC);
39
40#include "script_class.h"
41CREATE_SCRIPTABLE_CLASS(GenericNPC,
42                        // Move
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))
50                        // Display
51                        ->addMethod("hide", Executor0<WorldEntity, lua_State*>(&WorldEntity::hide))
52                        ->addMethod("unhide", Executor0<WorldEntity, lua_State*>(&WorldEntity::unhide))
53                        // Coordinates
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))
59                       );
60
61
62
63/**
64 * constructor
65 */
66GenericNPC::GenericNPC(const TiXmlElement* root)
67    : NPC(root)
68{
69  this->init();
70
71  if (root != NULL)
72    this->loadParams(root);
73}
74
75
76/**
77 * deconstructor
78 */
79GenericNPC::~GenericNPC ()
80{}
81
82
83/**
84 * initializing the npc enity
85 */
86void GenericNPC::init()
87{
88  this->registerObject(this, GenericNPC::_objectList);
89
90  this->toList(OM_GROUP_00);
91
92  this->soundBuffer = OrxSound::ResourceSoundBuffer("sound/rain.wav");
93
94  time = 30.0f;
95
96  this->behaviourList = new std::list<GenericNPC::Anim>;
97
98  // collision reaction registration
99  //this->subscribeReaction(CREngine::CR_PHYSICS_GROUND_WALK, BspEntity::staticClassID());
100   this->subscribeReaction(CREngine::CR_PHYSICS_FULL_WALK, Terrain::staticClassID());
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{
110  NPC::loadParams(root);
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
127
128/**
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/**
165 * sets the animation of this npc
166 * @param anumationIndex: the animation index
167 * @param anumPlaybackMode: the playback mode
168 */
169void GenericNPC::playAnimation(int animationIndex, int animPlaybackMode)
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 */
181void GenericNPC::playSound(const std::string& filename)
182{}
183
184
185
186/**
187 * stops the generic animation
188 */
189void GenericNPC::stop()
190{
191  this->animationStack.push(this->behaviourList);
192  this->behaviourList = new std::list<GenericNPC::Anim>;
193
194  if( this->getAnimation() != STAND)
195    this->setAnimation(STAND, MD2_ANIM_LOOP);
196}
197
198
199/**
200 * continue the generic animation
201 */
202void GenericNPC::resume()
203{
204  if( this->animationStack.size() == 0)
205    return;
206
207  delete this->behaviourList;
208  this->behaviourList = this->animationStack.top();
209  this->animationStack.pop();
210}
211
212
213/**
214 * each animation has to be initialized here
215 */
216/**
217 *
218 */
219void GenericNPC::initNPC()
220{
221  if (!this->behaviourList->empty())
222  {
223    GenericNPC::Anim currentAnimation = this->behaviourList->front();
224
225    switch(this->behaviourList->front().type)
226    {
227      case Walk:
228      {
229        if( this->getAnimation() != RUN)
230          this->setAnimation(RUN, MD2_ANIM_LOOP);
231
232        Vector dir = (currentAnimation.v - this->getAbsCoor());
233        dir.y = 0.0f;
234        dir.normalize();
235        this->setAbsDir(Quaternion(dir, Vector(0.0, 1.0, 0.0)) * Quaternion(-M_PI_2, Vector(0.0, 1.0, 0.0)));
236
237        this->setAnimationSpeed(0.5f);
238      }
239      break;
240      case Run:
241      {
242        if( this->getAnimation() != RUN)
243          this->setAnimation(RUN, MD2_ANIM_LOOP);
244
245        Vector dir = (currentAnimation.v - this->getAbsCoor()).getNormalized();
246        dir.y = 0.0f;
247        dir.getNormalized();
248        this->setAbsDir(Quaternion(dir, Vector(0.0, 1.0, 0.0)) * Quaternion(-M_PI_2, Vector(0.0, 1.0, 0.0)));
249
250        this->setAnimationSpeed(1.0f);
251      }
252      break;
253      case Crouch:
254      {
255        if( this->getAnimation() != CROUCH_WALK)
256          this->setAnimation(CROUCH_WALK, MD2_ANIM_LOOP);
257
258        Vector dir = (currentAnimation.v - this->getAbsCoor()).getNormalized();
259        dir.y = 0.0f;
260        dir.getNormalized();
261        this->setAbsDir(Quaternion(dir, Vector(0.0, 1.0, 0.0)) * Quaternion(-M_PI_2, Vector(0.0, 1.0, 0.0)));
262
263        this->setAnimationSpeed(1.0f);
264      }
265      break;
266      case LookAt:
267      if( this->getAnimation() != STAND)
268        this->setAnimation(STAND, MD2_ANIM_LOOP);
269      break;
270      case Shoot:
271      if( this->getAnimation() != STAND)
272        this->setAnimation(STAND, MD2_ANIM_LOOP);
273      break;
274
275      default:
276      if( this->getAnimation() != STAND)
277        this->setAnimation(STAND, MD2_ANIM_LOOP);
278      break;
279
280    }
281  }
282}
283
284
285void GenericNPC::nextStep()
286{
287  if (!this->behaviourList->empty())
288    this->behaviourList->pop_front();
289  else
290    return;
291
292
293  if (!this->behaviourList->empty())
294  {
295    GenericNPC::Anim currentAnimation = this->behaviourList->front();
296
297    switch( currentAnimation.type)
298    {
299      case Walk:
300      {
301        if( this->getAnimation() != RUN)
302          this->setAnimation(RUN, MD2_ANIM_LOOP);
303
304
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);
309
310        this->setAnimationSpeed(0.5f);
311      }
312      break;
313      case Run:
314      {
315        if( this->getAnimation() != RUN)
316          this->setAnimation(RUN, MD2_ANIM_LOOP);
317
318        Vector dir = (currentAnimation.v - this->getAbsCoor()).getNormalized();
319        dir.y = 0.0f;
320        dir.getNormalized();
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);
322
323        this->setAnimationSpeed(1.0f);
324      }
325      break;
326      case Crouch:
327      {
328        if( this->getAnimation() != CROUCH_WALK)
329          this->setAnimation(CROUCH_WALK, MD2_ANIM_LOOP);
330
331        Vector dir = (currentAnimation.v - this->getAbsCoor()).getNormalized();
332        dir.y = 0.0f;
333        dir.getNormalized();
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);
335
336        this->setAnimationSpeed(1.0f);
337      }
338      break;
339      case LookAt:
340      {
341        if( this->getAnimation() != STAND)
342          this->setAnimation(STAND, MD2_ANIM_LOOP);
343      }
344      break;
345      case Shoot:
346      if( this->getAnimation() != STAND)
347        this->setAnimation(STAND, MD2_ANIM_LOOP);
348      break;
349
350      default:
351      if( this->getAnimation() != STAND)
352        this->setAnimation(STAND, MD2_ANIM_LOOP);
353      break;
354
355    }
356  }
357  else
358  {
359    this->setAnimation(STAND, MD2_ANIM_LOOP);
360  }
361}
362
363
364
365
366void GenericNPC::walkTo(const Vector& coordinate)
367{
368
369  GenericNPC::Anim anim;
370  anim.v = coordinate;
371  anim.type = Walk;
372  anim.speed = 30.0f;
373
374  if( this->behaviourList->empty())
375  {
376    this->behaviourList->push_back(anim);
377    this->initNPC();
378  }
379  else
380    this->behaviourList->push_back(anim);
381}
382
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));
387
388}
389
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;
397
398  if( this->behaviourList->empty())
399  {
400    this->behaviourList->push_back(anim);
401    this->initNPC();
402  }
403  else
404    this->behaviourList->push_back(anim);
405}
406
407void GenericNPC::runTo(float x, float y, float z)
408{
409  this->runTo(Vector(x,y,z));
410}
411
412/* couching functinos */
413void GenericNPC::crouchTo(const Vector& coordinate)
414{
415  GenericNPC::Anim anim;
416  anim.v = coordinate;
417  anim.type = Crouch;
418
419  if( this->behaviourList->empty())
420  {
421    this->behaviourList->push_back(anim);
422    this->initNPC();
423  }
424  else
425    this->behaviourList->push_back(anim);
426}
427void GenericNPC::crouchTo(float x, float y, float z)
428{
429  this->crouchTo(Vector(x,y,z));
430}
431
432
433
434void GenericNPC::turnTo(float degreeInY)
435{
436  GenericNPC::Anim anim;
437  anim.q = Quaternion(Vector(0,1,0), degreeInY);
438  anim.type = TurnTo;
439
440  if( this->behaviourList->empty())
441  {
442    this->behaviourList->push_back(anim);
443    this->initNPC();
444  }
445  else
446    this->behaviourList->push_back(anim);
447}
448
449
450
451/**
452 * lookat a world entity
453 * @param worldEntity: the worldentity to look at
454 */
455void GenericNPC::lookAt(WorldEntity* worldEntity)
456{
457  GenericNPC::Anim anim;
458  anim.entity = worldEntity;
459  anim.type = LookAt;
460
461  if( this->behaviourList->empty())
462  {
463    this->behaviourList->push_back(anim);
464    this->initNPC();
465  }
466  else
467    this->behaviourList->push_back(anim);
468}
469
470
471
472
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 */
478void GenericNPC::talkTo(WorldEntity* worldEntity, int dialogNr)
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/**
499 * tick this world entity
500 * @param time: time in seconds expirded since the last tick
501 */
502void GenericNPC::tick (float dt)
503{
504  if( likely(this->getModel(0) != NULL))
505    ((InteractiveModel*)this->getModel(0))->tick(dt);
506
507
508  if (!this->behaviourList->empty())
509  {
510    GenericNPC::Anim currentAnimation = this->behaviourList->front();
511
512    switch( currentAnimation.type)
513    {
514      case Walk:
515      {
516        Vector dest = currentAnimation.v - this->getAbsCoor();
517        dest.y = 0.0f;
518        if (dest.len() < .5)
519        {
520          this->nextStep();
521        }
522        else
523        {
524          Vector move = dest.getNormalized() * currentAnimation.speed * dt;
525          this->shiftCoor(move);
526        }
527      }
528      break;
529
530      case Run:
531      {
532        Vector dest = currentAnimation.v - this->getAbsCoor();
533        dest.y = 0.0f;
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();
546        dest.y = 0.0f;
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:
557      //Quaternion direction = this->
558      break;
559
560      case LookAt:
561      break;
562
563      case Shoot:
564      break;
565
566      default:
567      break;
568
569    }
570  }
571
572  // physical falling of the player
573  if( !this->isOnGround())
574  {
575    this->fallVelocity += 300.0f * dt;
576    //velocity -= Vector(0.0, 1.0, 0.0) * this->fallVelocity;
577    // PRINTF(0)("%s is not on ground\n", this->getName());
578    this->shiftCoor(Vector(0, -this->fallVelocity * dt,0));
579
580  }
581  else
582  {
583    this->fallVelocity = 0.0f;
584  }
585
586}
587
588
589
590void GenericNPC::destroy(WorldEntity* killer)
591{
592  int randi = (int)(5.0f * (float)rand()/(float)RAND_MAX);
593
594  this->setAnimationSpeed(1.0f);
595
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.