Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: many loadParams

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