Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/src/world_entities/weapons/weapon.cc @ 4959

Last change on this file since 4959 was 4959, checked in by bensch, 19 years ago

orxonox/trunk: orxonox runs again (the TrackManager produces speed)

File size: 15.3 KB
RevLine 
[3573]1
[4597]2/*
[3573]3   orxonox - the future of 3D-vertical-scrollers
4
5   Copyright (C) 2004 orx
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2, or (at your option)
10   any later version.
11
[4826]12### File Specific
[3573]13   main-programmer: Patrick Boenzli
[4832]14   co-programmer: Benjamin Grauer
[4885]15
16   2005-07-15: Benjamin Grauer: restructurating the entire Class
[3573]17*/
18
[4885]19#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WEAPON
20
[4828]21#include "weapon.h"
22
[4834]23#include "projectile.h"
24
[4894]25#include "class_list.h"
[4834]26#include "load_param.h"
[4828]27#include "state.h"
[4948]28#include "sound_engine.h"
[4885]29#include "animation3d.h"
[4948]30#include "vector.h"
[3573]31
[4892]32////////////////////
33// INITAILISATION //
34// SETTING VALUES //
35////////////////////
[3870]36/**
[4885]37 * standard constructor
38 *
39 * creates a new weapon
[3575]40*/
[4955]41Weapon::Weapon (WeaponManager* weaponManager)
[3620]42{
[4885]43  this->init();
[4955]44  this->setWeaponManager(weaponManager);
[3620]45}
[3573]46
[3575]47/**
[4885]48 * standard deconstructor
[3575]49*/
[4597]50Weapon::~Weapon ()
[3573]51{
[4885]52  for (int i = 0; i < WS_STATE_COUNT; i++)
[4894]53    if (this->animation[i] && ClassList::exists(animation[i], CL_ANIMATION))  //!< @todo this should check animation3D
[4885]54      delete this->animation[i];
55  for (int i = 0; i < WA_ACTION_COUNT; i++)
56    if (this->soundBuffers[i])
57      ResourceManager::getInstance()->unload(this->soundBuffers[i]);
[4959]58
59  if (ClassList::exists(this->soundSource, CL_SOUND_SOURCE))
60    delete this->soundSource;
[4885]61}
[4597]62
[4885]63/**
64 * initializes the Weapon with ALL default values
65 */
66void Weapon::init()
67{
68  this->currentState     = WS_INACTIVE;
69  this->requestedAction  = WA_NONE;
70  this->stateDuration    = 0.0;
71  for (int i = 0; i < WS_STATE_COUNT; i++)
72    {
73      this->times[i] = 0.0;
74      this->animation[i] = NULL;
75    }
76  for (int i = 0; i < WA_ACTION_COUNT; i++)
77    this->soundBuffers[i] = NULL;
[3888]78
[4885]79  this->soundSource = new SoundSource(this);
[4892]80  this->emissionPoint.setParent(this);
[4885]81
[4947]82  this->projectile = CL_NULL;
83  this->projectileFactory = NULL;
[4885]84
[4906]85  this->hideInactive = true;
86
[4885]87  this->minCharge = 1.0;
88  this->maxCharge = 1.0;
[4927]89
[4885]90  this->energyLoaded = .0;
[4930]91  this->energyLoadedMax = 5.0;
[4885]92  this->energy = .0;
[4930]93  this->energyMax = 10.0;
[4955]94
95  this->setWeaponManager(NULL);
[3573]96}
97
[4947]98/**
99 * sets the Projectile to use for this weapon.
100 * @param projectile The ID of the Projectile to use
[4950]101 * @returns true, if it was sucessfull, false on error
[4947]102 *
103 * be aware, that this function does not create Factories, as this is job of Bullet-classes.
104 */
105bool Weapon::setProjectile(ClassID projectile)
106{
107  if (projectile == CL_NULL)
108    return false;
109  this->projectile = projectile;
110  this->projectileFactory = FastFactory::searchFastFactory(projectile);
111  if (this->projectileFactory == NULL)
112    return false;
[4948]113  else
114  {
115    // grabbing Parameters from the Projectile to have them at hand here.
116    this->projectileFactory->prepare(1);
117    Projectile* pj = dynamic_cast<Projectile*>(this->projectileFactory->resurrect());
118    this->minCharge = pj->getEnergyMin();
119    this->maxCharge = pj->getEnergyMax();
120    this->chargeable = pj->isChageable();
121  }
[4947]122};
[3573]123
[4891]124/**
[4950]125 * @see bool Weapon::setProjectile(ClassID projectile)
126 * @param projectile the Name of the Projectile.
127 * @return true if
128 */
129bool Weapon::setProjectile(const char* projectile)
130{
131  if (projectile == NULL)
132    return false;
133  FastFactory* tmpFac = FastFactory::searchFastFactory(projectile);
134  if (tmpFac != NULL)
135  {
136    this->setProjectile(tmpFac->getStoredID());
137  }
138}
139
140/**
[4892]141 * sets the emissionPoint's relative position from the Weapon
142 * @param point the Point relative to the mass-point of the Weapon
143 */
144void Weapon::setEmissionPoint(const Vector& point)
145{
146  this->emissionPoint.setRelCoor(point);
147}
148
149/**
[4891]150 * assigns a Sound-file to an action
151 * @param action the action the sound should be assigned too
152 * @param soundFile the soundFile's relative position to the data-directory (will be looked for by the ResourceManager)
153 */
[4885]154void Weapon::setActionSound(WeaponAction action, const char* soundFile)
155{
156  if (action >= WA_ACTION_COUNT)
157    return;
[4930]158  if (this->soundBuffers[action] != NULL)
159    ResourceManager::getInstance()->unload(this->soundBuffers[action]);
160
[4885]161  else if (soundFile != NULL)
162  {
163    this->soundBuffers[action] = (SoundBuffer*)ResourceManager::getInstance()->load(soundFile, WAV);
164    if (this->soundBuffers[action] != NULL)
165    {
166      PRINTF(4)("Loaded sound %s to action %s\n", soundFile, actionToChar(action));
167    }
168    else
169    {
170      PRINTF(4)("failed to load sound %s to %s\n", soundFile, actionToChar(action));
171    }
172  }
173  else
174    this->soundBuffers[action] = NULL;
175}
176
[4893]177
178/**
[4895]179 * creates/returns an Animation3D for a certain State.
180 * @param state what State should the Animation be created/returned for
181 * @param node the node this Animation should apply to. (NULL is fine if the animation was already created)
182 * @returns The created animation.Animation(), NULL on error (or if the animation does not yet exist).
[4893]183 *
184 * This function does only generate the Animation Object, and if set it will
185 * automatically be executed, when a certain State is reached.
186 * What this does not do, is set keyframes, you have to operate on the returned animation.
187 */
[4895]188Animation3D* Weapon::getAnimation(WeaponState state, PNode* node)
[4893]189{
[4895]190  if (state >= WS_STATE_COUNT) // if the state is not known
[4893]191    return NULL;
192
[4895]193  if (unlikely(this->animation[state] == NULL)) // if the animation does not exist yet create it.
[4893]194  {
[4895]195    if (likely(node != NULL))
196      return this->animation[state] = new Animation3D(node);
197    else
198    {
199      PRINTF(2)("Node not defined for the Creation of the 3D-animation of state %s\n", stateToChar(state));
200      return NULL;
201    }
[4893]202  }
[4895]203  else
204    return this->animation[state];
[4893]205}
206
207
[4892]208/////////////////
209//  EXECUTION  //
210// GAME ACTION //
211/////////////////
[4597]212/**
[4885]213 * request an action that should be executed,
214 * @param action the next action to take
215 *
216 * This function must be called instead of the actions (like fire/reload...)
217 * to make all the checks needed to have a usefull WeaponSystem.
218 */
219void Weapon::requestAction(WeaponAction action)
220{
[4906]221  if (likely(this->isActive()))
[4885]222  {
[4906]223    if (this->requestedAction != WA_NONE)
224      return;
[4885]225    printf("next action will be %s in %f seconds\n", actionToChar(action), this->stateDuration);
226    this->requestedAction = action;
227  }
[4906]228  //else
229  else if (unlikely(action == WA_ACTIVATE))
230  {
231    this->currentState = WS_ACTIVATING;
[4926]232    this->requestedAction = WA_ACTIVATE;
[4906]233  }
[4885]234}
[3577]235
[4890]236/**
237 * adds energy to the Weapon
238 * @param energyToAdd The amount of energy
239 * @returns the amount of energy we did not pick up, because the weapon is already full
240 */
241float Weapon::increaseEnergy(float energyToAdd)
242{
243  float maxAddEnergy = this->energyMax - this->energy;
244
245  if (maxAddEnergy >= energyToAdd)
246  {
247    this->energy += energyToAdd;
248    return 0.0;
249  }
250  else
251  {
252    this->energy += maxAddEnergy;
253    return energyToAdd - maxAddEnergy;
254  }
255}
256
[4892]257//////////////////////
258// WEAPON INTERNALS //
259//////////////////////
[4891]260/**
261 * executes an action, and with it starts a new State.
262 * @return true, if it worked, false otherwise
263 *
264 * This function checks, wheter the possibility of executing an action is valid,
265 * and does all the necessary stuff, to execute them. If an action does not succeed,
266 * it tries to go around it. (ex. shoot->noAmo->reload()->wait until shoot comes again)
267 */
[4885]268bool Weapon::execute()
[3583]269{
[4906]270#if DEBUG > 4
[4885]271  PRINTF(4)("trying to execute action %s\n", actionToChar(this->requestedAction));
272  this->debug();
[4906]273#endif
[4885]274
[4926]275  WeaponAction action = this->requestedAction;
276  this->requestedAction = WA_NONE;
277
278  switch (action)
[4885]279  {
280    case WA_SHOOT:
[4894]281      return this->fireW();
[4885]282      break;
283    case WA_CHARGE:
[4894]284      return this->chargeW();
[4885]285      break;
286    case WA_RELOAD:
[4894]287      return this->reloadW();
[4885]288      break;
289    case WA_DEACTIVATE:
[4894]290      return this->deactivateW();
[4885]291      break;
292    case WA_ACTIVATE:
[4894]293      return this->activateW();
[4885]294      break;
295  }
[3583]296}
[3577]297
[4597]298/**
[4894]299 * checks and activates the Weapon.
300 * @return true on success.
[4892]301 */
302bool Weapon::activateW()
[3583]303{
[4926]304//  if (this->currentState == WS_INACTIVE)
[4892]305  {
306        // play Sound
[4893]307    if (likely(this->soundBuffers[WA_ACTIVATE] != NULL))
[4892]308      this->soundSource->play(this->soundBuffers[WA_ACTIVATE]);
309        // activate
[4895]310    PRINTF(4)("Activating the Weapon %s\n", this->getName());
[4892]311    this->activate();
[4895]312    // setting up for next action
[4926]313    this->enterState(WS_ACTIVATING);
[4892]314  }
[3583]315}
[3577]316
[4597]317/**
[4894]318 * checks and deactivates the Weapon
319 * @return true on success.
[4892]320 */
321bool Weapon::deactivateW()
[3583]322{
[4949]323//  if (this->currentState != WS_INACTIVE)
[4892]324  {
325    PRINTF(4)("Deactivating the Weapon %s\n", this->getName());
326        // play Sound
327    if (this->soundBuffers[WA_DEACTIVATE] != NULL)
328      this->soundSource->play(this->soundBuffers[WA_DEACTIVATE]);
[4926]329    // deactivate
[4892]330    this->deactivate();
[4926]331    this->enterState(WS_DEACTIVATING);
[4892]332  }
[3583]333}
[3577]334
[4892]335/**
[4894]336 * checks and charges the Weapon
337 * @return true on success.
[4892]338 */
339bool Weapon::chargeW()
[4885]340{
[4892]341  if ( this->currentState != WS_INACTIVE && this->energyLoaded >= this->minCharge)
342  {
343        // playing Sound
344    if (this->soundBuffers[WA_CHARGE] != NULL)
345      this->soundSource->play(this->soundBuffers[WA_CHARGE]);
[4893]346
[4892]347        // charge
348    this->charge();
349        // setting up for the next state
[4926]350    this->enterState(WS_CHARGING);
[4892]351  }
352  else // deactivate the Weapon if we do not have enough energy
353  {
354    this->requestAction(WA_RELOAD);
355  }
[4885]356}
[3573]357
[4892]358/**
[4894]359 * checks and fires the Weapon
360 * @return true on success.
[4892]361 */
362bool Weapon::fireW()
[3575]363{
[4892]364     //if (likely(this->currentState != WS_INACTIVE))
365  if (this->minCharge <= this->energyLoaded)
366  {
367          // playing Sound
368    if (this->soundBuffers[WA_SHOOT] != NULL)
369      this->soundSource->play(this->soundBuffers[WA_SHOOT]);
370          // fire
371    this->fire();
372    this->energyLoaded -= this->minCharge;
373          // setting up for the next state
[4926]374    this->enterState(WS_SHOOTING);
[4892]375  }
376  else  // reload if we still have the charge
377  {
378    this->requestAction(WA_RELOAD);
[4930]379    this->execute();
[4892]380  }
381}
382
383
384/**
[4894]385 * checks and Reloads the Weapon
386 * @return true on success.
[4892]387 */
388bool Weapon::reloadW()
389{
[4885]390  PRINTF(4)("Reloading Weapon %s\n", this->getName());
[4892]391  if (unlikely(this->energy + this->energyLoaded < this->minCharge))
[4885]392  {
393    this->requestAction(WA_DEACTIVATE);
[4930]394    this->execute();
[4892]395    return false;
[4885]396  }
[3573]397
[4885]398  float chargeSize = this->energyLoadedMax - this->energyLoaded;       //!< The energy to be charged
[3573]399
[4892]400  if (this->soundBuffers[WA_RELOAD] != NULL)
401    this->soundSource->play(this->soundBuffers[WA_RELOAD]);
402
[4885]403  if (chargeSize > this->energy)
404  {
405    this->energyLoaded += this->energy;
406    this->energy = 0.0;
407    PRINT(3)("Energy empty");
408  }
409  else
410  {
411    PRINTF(3)("Loaded %f energy into the Guns Buffer\n", chargeSize);
412    this->energyLoaded += chargeSize;
413    this->energy -= chargeSize;
414  }
[4892]415  this->reload();
[4926]416  this->enterState(WS_RELOADING);
417}
[3575]418
[4926]419/**
420 * enters the requested State, plays back animations updates the timing.
421 * @param state the state to enter.
422 */
423inline void Weapon::enterState(WeaponState state)
424{
[4949]425  PRINTF(3)("ENTERING STATE %s\n", stateToChar(state));
[4926]426  // playing animation if availiable
427  if (likely(this->animation[state] != NULL))
428    this->animation[state]->replay();
429
430  this->stateDuration = this->times[state] + this->stateDuration;
431  this->currentState = state;
[3575]432}
433
434
[4927]435
436///////////////////
437//  WORLD-ENTITY //
438// FUNCTIONALITY //
439///////////////////
[3575]440/**
[4885]441 * tick signal for time dependent/driven stuff
[3575]442*/
[4906]443void Weapon::tickW(float dt)
[4885]444{
[4934]445  //printf("%s ", stateToChar(this->currentState));
[4910]446
[4885]447  // setting up the timing properties
448  this->stateDuration -= dt;
[3575]449
[4949]450  if (this->stateDuration <= 0.0)
[4885]451  {
[4949]452    if (unlikely (this->currentState == WS_DEACTIVATING))
[4885]453    {
[4949]454      this->currentState = WS_INACTIVE;
455      return;
456    }
457    else
458      this->currentState = WS_IDLE;
[4906]459
[4949]460    if (this->requestedAction != WA_NONE)
461    {
462      this->stateDuration = -dt;
463      this->execute();
[4885]464    }
465  }
[4906]466  tick(dt);
[4885]467}
468
[3575]469/**
[4885]470 *  this will draw the weapon
[3575]471*/
[4885]472void Weapon::draw ()
[3575]473{}
474
475
476
477
[3576]478
[4885]479//////////////////////
480// HELPER FUNCTIONS //
481//////////////////////
[3576]482/**
[4891]483 * checks wether all the Weapons functions are valid, and if it is possible to go to action with it.
484 *
485 */
486bool Weapon::check() const
487{
488  bool retVal = true;
489
[4947]490//  if (this->projectile == NULL)
[4891]491  {
492    PRINTF(2)("There was no projectile assigned to the Weapon.\n");
493    retVal = false;
494  }
495
496
497
498
499  return retVal;
500}
501
502/**
[4885]503 * some nice debugging information about this Weapon
504 */
505void Weapon::debug() const
506{
507  PRINT(3)("Weapon-Debug %s, state: %s, nexAction: %s\n", this->getName(), Weapon::stateToChar(this->currentState), Weapon::actionToChar(requestedAction));
508  PRINT(3)("Energy: max: %f; current: %f;  loadedMax: %f; loadedCurrent: %f; chargeMin: %f, chargeMax %f\n",
509            this->energyMax, this->energy, this->energyLoadedMax, this->energyLoaded, this->minCharge, this->maxCharge);
510}
[3575]511
512
[4885]513// static
514/**
515 * Converts a String into an Action.
516 * @param action the String input holding the Action.
517 * @return The Action if known, WA_NONE otherwise.
518 */
519WeaponAction Weapon::charToAction(const char* action)
520{
521  if (!strcmp(action, "none"))
522    return WA_NONE;
523  else if (!strcmp(action, "shoot"))
524    return WA_SHOOT;
525  else if (!strcmp(action, "charge"))
526    return WA_CHARGE;
527  else if (!strcmp(action, "reload"))
528    return WA_RELOAD;
529  else if (!strcmp(action, "acitvate"))
530    return WA_ACTIVATE;
531  else if (!strcmp(action, "deactivate"))
532    return WA_DEACTIVATE;
533  else if (!strcmp(action, "special1"))
534    return WA_SPECIAL1;
535  else
536    {
537      PRINTF(2)("action %s could not be identified.\n", action);
538      return WA_NONE;
539    }
540}
[3575]541
542/**
[4885]543 * converts an action into a String
544 * @param action the action to convert
545 * @return a String matching the name of the action
546 */
547const char* Weapon::actionToChar(WeaponAction action)
548{
549  switch (action)
550  {
551    case WA_SHOOT:
552      return "shoot";
553      break;
554    case WA_CHARGE:
555      return "charge";
556      break;
557    case WA_RELOAD:
558      return "reload";
559      break;
560    case WA_ACTIVATE:
561      return "activate";
562      break;
563    case WA_DEACTIVATE:
564      return "deactivate";
565      break;
566    case WA_SPECIAL1:
567      return "special1";
568      break;
569    default:
570      return "none";
571      break;
572  }
573}
[3577]574
575/**
[4885]576 * Converts a String into a State.
577 * @param state the String input holding the State.
578 * @return The State if known, WS_NONE otherwise.
579 */
580WeaponState Weapon::charToState(const char* state)
581{
582  if (!strcmp(state, "none"))
583    return WS_NONE;
584  else if (!strcmp(state, "shooting"))
585    return WS_SHOOTING;
586  else if (!strcmp(state, "charging"))
587    return WS_CHARGING;
588  else if (!strcmp(state, "reloading"))
589    return WS_RELOADING;
590  else if (!strcmp(state, "activating"))
591    return WS_ACTIVATING;
592  else if (!strcmp(state, "deactivating"))
593    return WS_DEACTIVATING;
594  else if (!strcmp(state, "inactive"))
595    return WS_INACTIVE;
596  else if (!strcmp(state, "idle"))
597    return WS_IDLE;
598  else
599    {
600      PRINTF(2)("state %s could not be identified.\n", state);
601      return WS_NONE;
602    }
603}
[3583]604
605/**
[4885]606 * converts a State into a String
607 * @param state the state to convert
608 * @return a String matching the name of the state
609 */
610const char* Weapon::stateToChar(WeaponState state)
611{
612  switch (state)
613  {
614    case WS_SHOOTING:
615      return "shooting";
616      break;
617    case WS_CHARGING:
618      return "charging";
619      break;
620    case WS_RELOADING:
621      return "reloading";
622      break;
623    case WS_ACTIVATING:
624      return "activating";
625      break;
626    case WS_DEACTIVATING:
627      return "deactivating";
628      break;
629    case WS_IDLE:
630      return "idle";
631      break;
[4906]632    case WS_INACTIVE:
633      return "inactive";
634      break;
[4885]635    default:
636      return "none";
637      break;
638  }
639}
Note: See TracBrowser for help on using the repository browser.