Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: seg-fault prevention thanks to the ClassList.
The animations will only be deleted, if they are in the ClassList stored as animations.
PS: commiting this out of the Kdevelop-svn-environment, and it totally rocks.
@patrick: switching payed out :)

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