Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: more loadability functionality in Weapon and FastFactory

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