Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/worldentities/pawns/Pawn.cc @ 8804

Last change on this file since 8804 was 8706, checked in by dafrick, 14 years ago

Merging presentation branch back into trunk.
There are many new features and also a lot of other changes and bugfixes, if you want to know, digg through the svn log.
Not everything is yet working as it should, but it should be fairly stable. If you habe any bug reports, just send me an email.

  • Property svn:eol-style set to native
File size: 14.8 KB
RevLine 
[2072]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
[8706]25 *      Simon Miescher
[2072]26 *
27 */
28
29#include "Pawn.h"
30
[3280]31#include <algorithm>
32
[3196]33#include "core/CoreIncludes.h"
[2896]34#include "core/GameMode.h"
[2072]35#include "core/XMLPort.h"
[3196]36#include "network/NetworkFunction.h"
37
[5735]38#include "infos/PlayerInfo.h"
[6417]39#include "controllers/Controller.h"
[5735]40#include "gametypes/Gametype.h"
[5737]41#include "graphics/ParticleSpawner.h"
[5735]42#include "worldentities/ExplosionChunk.h"
43#include "worldentities/BigExplosion.h"
44#include "weaponsystem/WeaponSystem.h"
45#include "weaponsystem/WeaponSlot.h"
46#include "weaponsystem/WeaponPack.h"
47#include "weaponsystem/WeaponSet.h"
[2072]48
[3084]49
[2072]50namespace orxonox
51{
52    CreateFactory(Pawn);
53
[7163]54    Pawn::Pawn(BaseObject* creator)
55        : ControllableEntity(creator)
56        , RadarViewable(creator, static_cast<WorldEntity*>(this))
[2072]57    {
58        RegisterObject(Pawn);
59
[2662]60        this->bAlive_ = true;
[3053]61        this->bReload_ = false;
[2072]62
63        this->health_ = 0;
64        this->maxHealth_ = 0;
65        this->initialHealth_ = 0;
[8706]66
[7163]67        this->shieldHealth_ = 0;
[8706]68        this->initialShieldHealth_ = 0;
69        this->maxShieldHealth_ = 100; //otherwise shield might increase to float_max
[7163]70        this->shieldAbsorption_ = 0.5;
[2072]71
[8706]72        this->reloadRate_ = 0;
73        this->reloadWaitTime_ = 1.0f;
74        this->reloadWaitCountdown_ = 0;
75
[2072]76        this->lastHitOriginator_ = 0;
77
[2662]78        this->spawnparticleduration_ = 3.0f;
[2098]79
[6417]80        this->aimPosition_ = Vector3::ZERO;
81
[2896]82        if (GameMode::isMaster())
[2662]83        {
84            this->weaponSystem_ = new WeaponSystem(this);
[3053]85            this->weaponSystem_->setPawn(this);
[2662]86        }
87        else
88            this->weaponSystem_ = 0;
89
90        this->setRadarObjectColour(ColourValue::Red);
91        this->setRadarObjectShape(RadarViewable::Dot);
92
[2072]93        this->registerVariables();
[3089]94
95        this->isHumanShip_ = this->hasLocalController();
[8329]96       
97        this->setSyncMode(ObjectDirection::Bidirectional); // needed to synchronise e.g. aimposition
[2072]98    }
99
100    Pawn::~Pawn()
101    {
[2662]102        if (this->isInitialized())
103        {
104            if (this->weaponSystem_)
[5929]105                this->weaponSystem_->destroy();
[2662]106        }
[2072]107    }
108
109    void Pawn::XMLPort(Element& xmlelement, XMLPort::Mode mode)
110    {
111        SUPER(Pawn, XMLPort, xmlelement, mode);
112
[2662]113        XMLPortParam(Pawn, "health", setHealth, getHealth, xmlelement, mode).defaultValues(100);
[2072]114        XMLPortParam(Pawn, "maxhealth", setMaxHealth, getMaxHealth, xmlelement, mode).defaultValues(200);
115        XMLPortParam(Pawn, "initialhealth", setInitialHealth, getInitialHealth, xmlelement, mode).defaultValues(100);
[7163]116
117        XMLPortParam(Pawn, "shieldhealth", setShieldHealth, getShieldHealth, xmlelement, mode).defaultValues(0);
[8706]118        XMLPortParam(Pawn, "initialshieldhealth", setInitialShieldHealth, getInitialShieldHealth, xmlelement, mode).defaultValues(0);
119        XMLPortParam(Pawn, "maxshieldhealth", setMaxShieldHealth, getMaxShieldHealth, xmlelement, mode).defaultValues(100);
[7163]120        XMLPortParam(Pawn, "shieldabsorption", setShieldAbsorption, getShieldAbsorption, xmlelement, mode).defaultValues(0);
121
[2662]122        XMLPortParam(Pawn, "spawnparticlesource", setSpawnParticleSource, getSpawnParticleSource, xmlelement, mode);
123        XMLPortParam(Pawn, "spawnparticleduration", setSpawnParticleDuration, getSpawnParticleDuration, xmlelement, mode).defaultValues(3.0f);
124        XMLPortParam(Pawn, "explosionchunks", setExplosionChunks, getExplosionChunks, xmlelement, mode).defaultValues(7);
125
[3053]126        XMLPortObject(Pawn, WeaponSlot, "weaponslots", addWeaponSlot, getWeaponSlot, xmlelement, mode);
127        XMLPortObject(Pawn, WeaponSet, "weaponsets", addWeaponSet, getWeaponSet, xmlelement, mode);
[6417]128        XMLPortObject(Pawn, WeaponPack, "weapons", addWeaponPackXML, getWeaponPack, xmlelement, mode);
[8706]129
130        XMLPortParam(Pawn, "reloadrate", setReloadRate, getReloadRate, xmlelement, mode).defaultValues(0);
131        XMLPortParam(Pawn, "reloadwaittime", setReloadWaitTime, getReloadWaitTime, xmlelement, mode).defaultValues(1.0f);
[2072]132    }
133
134    void Pawn::registerVariables()
135    {
[7163]136        registerVariable(this->bAlive_,           VariableDirection::ToClient);
137        registerVariable(this->health_,           VariableDirection::ToClient);
[8706]138        registerVariable(this->maxHealth_,        VariableDirection::ToClient);
[7163]139        registerVariable(this->shieldHealth_,     VariableDirection::ToClient);
[8706]140        registerVariable(this->maxShieldHealth_,  VariableDirection::ToClient);
[7163]141        registerVariable(this->shieldAbsorption_, VariableDirection::ToClient);
142        registerVariable(this->bReload_,          VariableDirection::ToServer);
143        registerVariable(this->aimPosition_,      VariableDirection::ToServer);  // For the moment this variable gets only transfered to the server
[2072]144    }
145
146    void Pawn::tick(float dt)
147    {
[2809]148        SUPER(Pawn, tick, dt);
[2072]149
[3053]150        this->bReload_ = false;
[2662]151
[8706]152        // TODO: use the existing timer functions instead
153        if(this->reloadWaitCountdown_ > 0)
154        {
155            this->decreaseReloadCountdownTime(dt);
156        }
157        else
158        {
159            this->addShieldHealth(this->getReloadRate() * dt);
160            this->resetReloadCountdown();
161        }
162
[3084]163        if (GameMode::isMaster())
[8706]164        {
[3087]165            if (this->health_ <= 0 && bAlive_)
[6864]166            {
[8706]167                this->fireEvent(); // Event to notify anyone who wants to know about the death.
[3087]168                this->death();
[6864]169            }
[8706]170        }
[2072]171    }
172
[7889]173    void Pawn::preDestroy()
174    {
175        // yay, multiple inheritance!
176        this->ControllableEntity::preDestroy();
177        this->PickupCarrier::preDestroy();
178    }
179
[2826]180    void Pawn::setPlayer(PlayerInfo* player)
181    {
182        ControllableEntity::setPlayer(player);
183
184        if (this->getGametype())
185            this->getGametype()->playerStartsControllingPawn(player, this);
186    }
187
188    void Pawn::removePlayer()
189    {
190        if (this->getGametype())
191            this->getGametype()->playerStopsControllingPawn(this->getPlayer(), this);
192
193        ControllableEntity::removePlayer();
194    }
195
[8706]196
[2072]197    void Pawn::setHealth(float health)
198    {
[8706]199        this->health_ = std::min(health, this->maxHealth_); //Health can't be set to a value bigger than maxHealth, otherwise it will be reduced at first hit
[2072]200    }
201
[8706]202    void Pawn::setShieldHealth(float shieldHealth)
[2072]203    {
[8706]204        this->shieldHealth_ = std::min(shieldHealth, this->maxShieldHealth_);
205    }
206
207    void Pawn::setMaxShieldHealth(float maxshieldhealth)
208    {
209        this->maxShieldHealth_ = maxshieldhealth;
210    }
211
212    void Pawn::setReloadRate(float reloadrate)
213    {
214        this->reloadRate_ = reloadrate;
215    }
216
217    void Pawn::setReloadWaitTime(float reloadwaittime)
218    {
219        this->reloadWaitTime_ = reloadwaittime;
220    }
221
222    void Pawn::decreaseReloadCountdownTime(float dt)
223    {
224        this->reloadWaitCountdown_ -= dt;
225    }
226
227    void Pawn::damage(float damage, float healthdamage, float shielddamage, Pawn* originator)
228    {
[2826]229        if (this->getGametype() && this->getGametype()->allowPawnDamage(this, originator))
230        {
[8706]231            if (shielddamage >= this->getShieldHealth())
[7163]232            {
233                this->setShieldHealth(0);
[8706]234                this->setHealth(this->health_ - (healthdamage + damage));
[7163]235            }
[8706]236            else
237            {
238                this->setShieldHealth(this->shieldHealth_ - shielddamage);
[7163]239
[8706]240                // remove remaining shieldAbsorpton-Part of damage from shield
241                shielddamage = damage * this->shieldAbsorption_;
242                shielddamage = std::min(this->getShieldHealth(),shielddamage);
243                this->setShieldHealth(this->shieldHealth_ - shielddamage);
[7163]244
[8706]245                // set remaining damage to health
246                this->setHealth(this->health_ - (damage - shielddamage) - healthdamage);
[7163]247            }
248
[2826]249            this->lastHitOriginator_ = originator;
250        }
[2072]251    }
252
[8706]253// TODO: Still valid?
254/* HIT-Funktionen
255    Die hit-Funktionen muessen auch in src/orxonox/controllers/Controller.h angepasst werden! (Visuelle Effekte)
256
257*/
258
259    void Pawn::hit(Pawn* originator, const Vector3& force, float damage, float healthdamage, float shielddamage)
[2072]260    {
[6417]261        if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator) && (!this->getController() || !this->getController()->getGodMode()) )
[2826]262        {
[8706]263            this->damage(damage, healthdamage, shielddamage, originator);
[2826]264            this->setVelocity(this->getVelocity() + force);
265        }
[2072]266    }
267
[8706]268
269    void Pawn::hit(Pawn* originator, btManifoldPoint& contactpoint, float damage, float healthdamage, float shielddamage)
[6417]270    {
271        if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator) && (!this->getController() || !this->getController()->getGodMode()) )
272        {
[8706]273            this->damage(damage, healthdamage, shielddamage, originator);
[6417]274
275            if ( this->getController() )
[8706]276                this->getController()->hit(originator, contactpoint, damage); // changed to damage, why shielddamage?
[6417]277        }
278    }
279
[8706]280
[2072]281    void Pawn::kill()
282    {
283        this->damage(this->health_);
284        this->death();
285    }
286
[2662]287    void Pawn::spawneffect()
[2072]288    {
289        // play spawn effect
[6417]290        if (!this->spawnparticlesource_.empty())
[2662]291        {
292            ParticleSpawner* effect = new ParticleSpawner(this->getCreator());
293            effect->setPosition(this->getPosition());
294            effect->setOrientation(this->getOrientation());
295            effect->setDestroyAfterLife(true);
296            effect->setSource(this->spawnparticlesource_);
297            effect->setLifetime(this->spawnparticleduration_);
298        }
[2072]299    }
300
301    void Pawn::death()
302    {
[3033]303        this->setHealth(1);
[2826]304        if (this->getGametype() && this->getGametype()->allowPawnDeath(this, this->lastHitOriginator_))
305        {
306            // Set bAlive_ to false and wait for PawnManager to do the destruction
307            this->bAlive_ = false;
[2662]308
[2826]309            this->setDestroyWhenPlayerLeft(false);
[2662]310
[2826]311            if (this->getGametype())
312                this->getGametype()->pawnKilled(this, this->lastHitOriginator_);
[2662]313
[3038]314            if (this->getPlayer() && this->getPlayer()->getControllableEntity() == this)
315                this->getPlayer()->stopControl();
[2072]316
[2896]317            if (GameMode::isMaster())
[3087]318            {
319//                this->deathEffect();
320                this->goWithStyle();
321            }
[2826]322        }
[2662]323    }
[3087]324    void Pawn::goWithStyle()
325    {
326        this->bAlive_ = false;
327        this->setDestroyWhenPlayerLeft(false);
[2072]328
[3087]329        BigExplosion* chunk = new BigExplosion(this->getCreator());
330        chunk->setPosition(this->getPosition());
331
332    }
[2662]333    void Pawn::deatheffect()
334    {
[2072]335        // play death effect
[2662]336        {
337            ParticleSpawner* effect = new ParticleSpawner(this->getCreator());
338            effect->setPosition(this->getPosition());
339            effect->setOrientation(this->getOrientation());
340            effect->setDestroyAfterLife(true);
341            effect->setSource("Orxonox/explosion2b");
342            effect->setLifetime(4.0f);
343        }
344        {
345            ParticleSpawner* effect = new ParticleSpawner(this->getCreator());
346            effect->setPosition(this->getPosition());
347            effect->setOrientation(this->getOrientation());
348            effect->setDestroyAfterLife(true);
349            effect->setSource("Orxonox/smoke6");
350            effect->setLifetime(4.0f);
351        }
352        {
353            ParticleSpawner* effect = new ParticleSpawner(this->getCreator());
354            effect->setPosition(this->getPosition());
355            effect->setOrientation(this->getOrientation());
356            effect->setDestroyAfterLife(true);
357            effect->setSource("Orxonox/sparks");
358            effect->setLifetime(4.0f);
359        }
360        for (unsigned int i = 0; i < this->numexplosionchunks_; ++i)
361        {
362            ExplosionChunk* chunk = new ExplosionChunk(this->getCreator());
363            chunk->setPosition(this->getPosition());
364        }
[2072]365    }
366
[6417]367    void Pawn::fired(unsigned int firemode)
[2098]368    {
[6417]369        if (this->weaponSystem_)
370            this->weaponSystem_->fire(firemode);
[2098]371    }
372
[3053]373    void Pawn::reload()
374    {
375        this->bReload_ = true;
376    }
377
[2072]378    void Pawn::postSpawn()
379    {
380        this->setHealth(this->initialHealth_);
[2896]381        if (GameMode::isMaster())
[2662]382            this->spawneffect();
[2072]383    }
[2662]384
[2893]385    /* WeaponSystem:
386    *   functions load Slot, Set, Pack from XML and make sure all parent-pointers are set.
387    *   with setWeaponPack you can not just load a Pack from XML but if a Pack already exists anywhere, you can attach it.
388    *       --> e.g. Pickup-Items
389    */
[3053]390    void Pawn::addWeaponSlot(WeaponSlot * wSlot)
[2662]391    {
392        this->attach(wSlot);
393        if (this->weaponSystem_)
[3053]394            this->weaponSystem_->addWeaponSlot(wSlot);
[2662]395    }
396
397    WeaponSlot * Pawn::getWeaponSlot(unsigned int index) const
398    {
399        if (this->weaponSystem_)
[3053]400            return this->weaponSystem_->getWeaponSlot(index);
[2662]401        else
402            return 0;
403    }
404
[3053]405    void Pawn::addWeaponSet(WeaponSet * wSet)
[2662]406    {
407        if (this->weaponSystem_)
[3053]408            this->weaponSystem_->addWeaponSet(wSet);
[2662]409    }
410
[3053]411    WeaponSet * Pawn::getWeaponSet(unsigned int index) const
[2662]412    {
413        if (this->weaponSystem_)
[3053]414            return this->weaponSystem_->getWeaponSet(index);
[2662]415        else
416            return 0;
417    }
418
[3053]419    void Pawn::addWeaponPack(WeaponPack * wPack)
[2662]420    {
421        if (this->weaponSystem_)
[7163]422        {
[3053]423            this->weaponSystem_->addWeaponPack(wPack);
[7163]424            this->addedWeaponPack(wPack);
425        }
[2662]426    }
427
[6417]428    void Pawn::addWeaponPackXML(WeaponPack * wPack)
429    {
430        if (this->weaponSystem_)
[7163]431        {
[6417]432            if (!this->weaponSystem_->addWeaponPack(wPack))
433                wPack->destroy();
[7163]434            else
435                this->addedWeaponPack(wPack);
436        }
[6417]437    }
438
[3053]439    WeaponPack * Pawn::getWeaponPack(unsigned int index) const
[2662]440    {
441        if (this->weaponSystem_)
[3053]442            return this->weaponSystem_->getWeaponPack(index);
[2662]443        else
444            return 0;
445    }
446
[3089]447    //Tell the Map (RadarViewable), if this is a playership
448    void Pawn::startLocalHumanControl()
449    {
450//        SUPER(ControllableEntity, changedPlayer());
451        ControllableEntity::startLocalHumanControl();
452        this->isHumanShip_ = true;
453    }
[2072]454}
Note: See TracBrowser for help on using the repository browser.