Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: ProjectileFactory now handled in Weapon-class

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