/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific main-programmer: Patrick Boenzli co-programmer: Benjamin Grauer 2005-07-15: Benjamin Grauer: restructurating the entire Class */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WEAPON #include "weapon.h" #include "projectile.h" #include "load_param.h" #include "vector.h" #include "list.h" #include "state.h" #include "animation3d.h" #include "sound_engine.h" /** * standard constructor * * creates a new weapon */ Weapon::Weapon (PNode* parent, const Vector& coordinate, const Quaternion& direction) { this->init(); parent->addChild(this, PNODE_ALL); this->setRelCoor(coordinate); this->setRelDir(direction); } /** * standard deconstructor */ Weapon::~Weapon () { for (int i = 0; i < WS_STATE_COUNT; i++) if (this->animation[i]) delete this->animation[i]; for (int i = 0; i < WA_ACTION_COUNT; i++) if (this->soundBuffers[i]) ResourceManager::getInstance()->unload(this->soundBuffers[i]); } /** * initializes the Weapon with ALL default values */ void Weapon::init() { this->currentState = WS_INACTIVE; this->requestedAction = WA_NONE; this->stateDuration = 0.0; for (int i = 0; i < WS_STATE_COUNT; i++) { this->times[i] = 0.0; this->animation[i] = NULL; } for (int i = 0; i < WA_ACTION_COUNT; i++) this->soundBuffers[i] = NULL; this->requestedAction = WA_NONE; this->soundSource = new SoundSource(this); this->active = true; this->projectile = NULL; this->minCharge = 1.0; this->maxCharge = 1.0; this->energyLoaded = .0; this->energyLoadedMax = 10.0; this->energy = .0; this->energyMax = 100.0; } void Weapon::setActionSound(WeaponAction action, const char* soundFile) { if (action >= WA_ACTION_COUNT) return; else { this->soundBuffers[action] = (SoundBuffer*)ResourceManager::getInstance()->load(soundFile, WAV); if (this->soundBuffers[action] != NULL) { PRINTF(4)("Loaded sound %s to action %s\n", soundFile, actionToChar(action)); } else { PRINTF(4)("failed to load sound %s to %s\n", soundFile, actionToChar(action)); } } } /** * request an action that should be executed, * @param action the next action to take * * This function must be called instead of the actions (like fire/reload...) * to make all the checks needed to have a usefull WeaponSystem. */ void Weapon::requestAction(WeaponAction action) { if (this->requestedAction != WA_NONE) return; else { printf("next action will be %s in %f seconds\n", actionToChar(action), this->stateDuration); this->requestedAction = action; } } bool Weapon::execute() { this->stateDuration = this->times[this->requestedAction] + this->stateDuration; PRINTF(4)("trying to execute action %s\n", actionToChar(this->requestedAction)); this->debug(); switch (this->requestedAction) { case WA_SHOOT: //if (likely(this->currentState != WS_INACTIVE)) { if (this->minCharge < this->energyLoaded) { this->fire(); this->requestedAction = WA_NONE; } else // reload if we still have the charge { this->requestedAction = WA_NONE; this->requestAction(WA_RELOAD); } } break; case WA_CHARGE: if ( this->currentState != WS_INACTIVE && this->energyLoaded >= this->minCharge) { this->charge(); this->requestedAction = WA_NONE; } else // deactivate the Weapon if we do not have enough energy { this->requestedAction = WA_NONE; this->requestAction(WA_RELOAD); } break; case WA_RELOAD: //if (this->currentState != WS_INACTIVE && this->energy + this->energyLoaded >= this->minCharge) { this->reload(); this->requestedAction = WA_NONE; } break; case WA_DEACTIVATE: if (this->currentState != WS_INACTIVE) { this->deactivate(); this->requestedAction = WA_NONE; } break; case WA_ACTIVATE: if (this->currentState == WS_INACTIVE) { this->activate(); this->requestedAction = WA_NONE; } break; } } /** * this activates the weapon */ void Weapon::activate() { PRINTF(4)("Activating the Weapon %s\n", this->getName()); if (this->soundBuffers[WA_ACTIVATE] != NULL) this->soundSource->play(this->soundBuffers[WA_ACTIVATE]); } /** * this deactivates the weapon */ void Weapon::deactivate() { PRINTF(4)("Deactivating the Weapon %s\n", this->getName()); if (this->soundBuffers[WA_DEACTIVATE] != NULL) this->soundSource->play(this->soundBuffers[WA_DEACTIVATE]); } void Weapon::fire() { this->energyLoaded -= this->minCharge; if (this->soundBuffers[WA_SHOOT] != NULL) this->soundSource->play(this->soundBuffers[WA_SHOOT]); } void Weapon::reload() { PRINTF(4)("Reloading Weapon %s\n", this->getName()); if (this->energy + this->energyLoaded < this->minCharge) { this->requestAction(WA_DEACTIVATE); return; } float chargeSize = this->energyLoadedMax - this->energyLoaded; //!< The energy to be charged if (chargeSize > this->energy) { this->energyLoaded += this->energy; this->energy = 0.0; PRINT(3)("Energy empty"); } else { PRINTF(3)("Loaded %f energy into the Guns Buffer\n", chargeSize); this->energyLoaded += chargeSize; this->energy -= chargeSize; } if (this->soundBuffers[WA_RELOAD] != NULL) this->soundSource->play(this->soundBuffers[WA_RELOAD]); } void Weapon::charge() { if (this->soundBuffers[WA_CHARGE] != NULL) this->soundSource->play(this->soundBuffers[WA_CHARGE]); } /** * is called, when the weapon is destroyed * * this is in conjunction with the hit function, so when a weapon is able to get * hit, it can also be destoryed. */ void Weapon::destroy () {} /** * tick signal for time dependent/driven stuff */ void Weapon::tick(float dt) { // setting up the timing properties this->stateDuration -= dt; if (this->isActive()) { if (this->stateDuration <= 0.0 && this->requestedAction != WA_NONE) { this->stateDuration = -dt; this->execute(); } } else if (this->requestedAction == WA_ACTIVATE) this->activate(); } /** * this will draw the weapon */ void Weapon::draw () {} ////////////////////// // HELPER FUNCTIONS // ////////////////////// // inclass /** * checks if the next Action given is valid * @returns if the Action that comes next is valid * @todo more checks */ bool Weapon::nextActionValid() const { if (this->currentState == WS_INACTIVE) { return (this->requestedAction == WA_ACTIVATE || this->requestedAction == WA_NONE); } else return true; } /** * some nice debugging information about this Weapon */ void Weapon::debug() const { PRINT(3)("Weapon-Debug %s, state: %s, nexAction: %s\n", this->getName(), Weapon::stateToChar(this->currentState), Weapon::actionToChar(requestedAction)); PRINT(3)("Energy: max: %f; current: %f; loadedMax: %f; loadedCurrent: %f; chargeMin: %f, chargeMax %f\n", this->energyMax, this->energy, this->energyLoadedMax, this->energyLoaded, this->minCharge, this->maxCharge); } // static /** * Converts a String into an Action. * @param action the String input holding the Action. * @return The Action if known, WA_NONE otherwise. */ WeaponAction Weapon::charToAction(const char* action) { if (!strcmp(action, "none")) return WA_NONE; else if (!strcmp(action, "shoot")) return WA_SHOOT; else if (!strcmp(action, "charge")) return WA_CHARGE; else if (!strcmp(action, "reload")) return WA_RELOAD; else if (!strcmp(action, "acitvate")) return WA_ACTIVATE; else if (!strcmp(action, "deactivate")) return WA_DEACTIVATE; else if (!strcmp(action, "special1")) return WA_SPECIAL1; else { PRINTF(2)("action %s could not be identified.\n", action); return WA_NONE; } } /** * converts an action into a String * @param action the action to convert * @return a String matching the name of the action */ const char* Weapon::actionToChar(WeaponAction action) { switch (action) { case WA_SHOOT: return "shoot"; break; case WA_CHARGE: return "charge"; break; case WA_RELOAD: return "reload"; break; case WA_ACTIVATE: return "activate"; break; case WA_DEACTIVATE: return "deactivate"; break; case WA_SPECIAL1: return "special1"; break; default: return "none"; break; } } /** * Converts a String into a State. * @param state the String input holding the State. * @return The State if known, WS_NONE otherwise. */ WeaponState Weapon::charToState(const char* state) { if (!strcmp(state, "none")) return WS_NONE; else if (!strcmp(state, "shooting")) return WS_SHOOTING; else if (!strcmp(state, "charging")) return WS_CHARGING; else if (!strcmp(state, "reloading")) return WS_RELOADING; else if (!strcmp(state, "activating")) return WS_ACTIVATING; else if (!strcmp(state, "deactivating")) return WS_DEACTIVATING; else if (!strcmp(state, "inactive")) return WS_INACTIVE; else if (!strcmp(state, "idle")) return WS_IDLE; else { PRINTF(2)("state %s could not be identified.\n", state); return WS_NONE; } } /** * converts a State into a String * @param state the state to convert * @return a String matching the name of the state */ const char* Weapon::stateToChar(WeaponState state) { switch (state) { case WS_SHOOTING: return "shooting"; break; case WS_CHARGING: return "charging"; break; case WS_RELOADING: return "reloading"; break; case WS_ACTIVATING: return "activating"; break; case WS_DEACTIVATING: return "deactivating"; break; case WS_IDLE: return "idle"; break; default: return "none"; break; } }