Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: resurection of shoots works perfectly… now it is the question of how to recollect them… most probably the GarbageCollector… this will be one step deeper then..

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