Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/single_player_map/src/world_entities/npcs/generic_npc.cc @ 8968

Last change on this file since 8968 was 8968, checked in by snellen, 18 years ago

made testentity scriptable

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