Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: minor cleanup

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