Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/world_entities/npcs/generic_npc.cc @ 10742

Last change on this file since 10742 was 10618, checked in by bknecht, 18 years ago

merged cleanup into trunk (only improvements)

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