Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/modules/objects/triggers/Trigger.cc @ 11071

Last change on this file since 11071 was 11071, checked in by landauf, 8 years ago

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 12.0 KB
Line 
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 *      Benjamin Knecht
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file Trigger.cc
31    @brief Implementation of the Trigger class.
32    @ingroup NormalTrigger
33*/
34
35#include "Trigger.h"
36
37#include "core/CoreIncludes.h"
38#include "core/GameMode.h"
39#include "core/command/ConsoleCommandIncludes.h"
40
41#include "Scene.h"
42
43namespace orxonox
44{
45
46    SetConsoleCommand("Trigger", "debugFlares", &Trigger::debugFlares).defaultValues(false);
47
48    RegisterClass(Trigger);
49
50    /**
51    @brief
52        Constructor. Registers and initializes the object.
53    @param creator
54        The creator of the Trigger.
55    */
56    Trigger::Trigger(Context* context) : TriggerBase(context)
57    {
58        RegisterObject(Trigger);
59
60        this->bActive_ = false;
61        this->bTriggered_ = false;
62        this->latestState_ = 0x0;
63
64        this->remainingTime_ = 0.0f;
65        this->timeSinceLastEvent_ = 0.0f;
66
67        // Set the debug billboard.
68        if (this->getScene() && GameMode::showsGraphics())
69        {
70            this->debugBillboard_.setBillboardSet(this->getScene()->getSceneManager(), "Examples/Flare", ColourValue(1.0, 0.0, 0.0), 1);
71            this->debugBillboard_.setVisible(false);
72
73            if (this->debugBillboard_.getBillboardSet())
74                this->attachOgreObject(this->debugBillboard_.getBillboardSet());
75        }
76
77        this->setSyncMode(ObjectDirection::None);
78    }
79
80    /**
81    @brief
82        Destructor.
83    */
84    Trigger::~Trigger()
85    {
86
87    }
88
89    /**
90    @brief
91
92    @param dt
93        The time elapsed since last tick.
94    */
95    void Trigger::tick(float dt)
96    {
97        // If this is the first tick, announce, that the trigger is not triggered.
98        // This is needed, e.g. for an inverted trigger, that needs to announce at the beginning, that it is active.
99        if (this->bFirstTick_)
100        {
101            this->bFirstTick_ = false;
102            this->triggered(false);
103        }
104
105        // Check if the object is active (this is NOT Trigger::isActive()!)
106        // If the object is not active we do nothing.
107        if (!this->BaseObject::isActive())
108            return;
109
110        SUPER(Trigger, tick, dt);
111
112        // Apply the invert operation.
113        bool newTriggered = this->isTriggered() ^ this->getInvert();
114
115        // Check if new triggering event is really new. (i.e. if the previous triggering state is not the same as the current)
116        if ((this->latestState_ & 0x1) != newTriggered)
117        {
118            // Create new state
119            if (newTriggered)
120            {
121                this->latestState_ |= 1; // Set triggered bit to 1.
122                this->switchState(); // Toggle the activity of the trigger.
123            }
124            else
125            {
126                this->latestState_ &= 0xFE; // Set triggered bit to 0.
127                // If this trigger is not in switched-mode (i.e. it switches its activity only if it changes from not triggered to triggered and not the other way around), the activity of the trigger is toggled.
128                if (!this->getSwitch())
129                    this->switchState();
130            }
131        }
132
133        // If there is time remaining, i.e. there are states in the queue waiting to take effect.
134        if (this->remainingTime_ > 0.0)
135        {
136            // Discount the last tick time from the time remaining.
137            this->remainingTime_ -= dt;
138            // Increase the time since the last event (the time since the last state took effect), but only when actually waiting for a state in the queue
139            if (this->timeSinceLastEvent_ >= 0.0)
140                this->timeSinceLastEvent_ += dt;
141        }
142
143        // If the remaining time has run out and there are states in the queue waiting to take effect.
144        while (this->remainingTime_ <= 0.0 && this->stateChanges_.size() > 0)
145        {
146            // Get the state to take effect and apply it.
147            char newState = this->stateChanges_.front().second;
148            this->bTriggered_ = (newState & 0x1);
149            this->bActive_ = newState & 0x2;
150
151            // Fire a triggered (or un-triggered, depending on the activity) event.
152            this->triggered(this->bActive_);
153
154            // Remove the state that was just applied from the queue.
155            this->stateChanges_.pop();
156
157            // If there are still states in the queue, set the remaining time to the time of the next state to take effect.
158            if (this->stateChanges_.size() != 0)
159                this->remainingTime_ = this->stateChanges_.front().first;
160            // Else the time since the last event is set to the delay.
161            else
162                this->timeSinceLastEvent_ = this->getDelay();
163        }
164
165        // Set the color of the debug billboard according to the current state of the trigger.
166        if (this->bTriggered_ && this->bActive_)
167            this->setBillboardColour(ColourValue(0.5, 1.0, 0.0));
168        else if (!this->bTriggered_ && this->bActive_)
169            this->setBillboardColour(ColourValue(0.0, 1.0, 0.0));
170        else if (this->bTriggered_ && !this->bActive_)
171            this->setBillboardColour(ColourValue(1.0, 0.5, 0.0));
172        else
173            this->setBillboardColour(ColourValue(1.0, 0.0, 0.0));
174    }
175
176    /**
177    @brief
178        Fires an event with the input triggered state.
179    @param bIsTriggered
180        The triggered state.
181    */
182    void Trigger::triggered(bool bIsTriggered)
183    {
184        this->fireEvent(bIsTriggered);
185    }
186
187    /**
188    @brief
189        Check whether the Trigger should be triggered, given only its sub-triggers, given a specific mode.
190    @param mode
191        The Trigger mode. Specifies how the sub-triggers are combined and how they affect the Trigger.
192    @return
193        Returns true if the Trigger should be triggered and false if not.
194    */
195    bool Trigger::isTriggered(TriggerMode mode)
196    {
197        // If the trigger has sub-triggers.
198        if (this->children_.size() > 0)
199        {
200            switch (mode)
201            {
202                case TriggerMode::EventTriggerAND:
203                    return checkAnd();
204                case TriggerMode::EventTriggerOR:
205                    return checkOr();
206                case TriggerMode::EventTriggerXOR:
207                    return checkXor();
208                default:
209                    return false;
210            }
211        }
212        // If the trigger has no sub-triggers, whether it is triggered should only depend on itself and nothing else, thus this returns true.
213        return true;
214    }
215
216    /**
217    @brief
218        Check whether all the sub-triggers of this Trigger are active.
219        This is in fact the conjunction (logical AND) of the activity of all its sub-triggers.
220    @return
221        Returns true if all the sub-triggers of this Trigger are active, false if at least one of them is not active.
222    */
223    bool Trigger::checkAnd()
224    {
225        // Iterate over all sub-triggers.
226        for (TriggerBase* child : this->children_)
227        {
228            if (!child->isActive())
229                return false;
230        }
231        return true;
232    }
233
234    /**
235    @brief
236        Check whether at least one of the sub-triggers of this Trigger is active.
237        This is in fact the disjunction (logical OR) of the activity of all its sub-triggers.
238    @return
239        Returns true if at least one of the sub-triggers of this Trigger is active, false if none of them is active.
240    */
241    bool Trigger::checkOr()
242    {
243        // Iterate over all sub-triggers.
244        for (TriggerBase* child : this->children_)
245        {
246            if (child->isActive())
247                return true;
248        }
249        return false;
250    }
251
252    /**
253    @brief
254        Check whether exactly one of the sub-triggers of this Trigger is active.
255        This is in fact the logical XOR of the activity of all its sub-triggers.
256    @return
257        Returns true if exactly one of the sub-triggers of this Trigger is active, false if none of them or two or more of them are active.
258    */
259    bool Trigger::checkXor()
260    {
261        bool test = false;
262        for (TriggerBase* child : this->children_)
263        {
264            if (test && child->isActive())
265                return false;
266            if (child->isActive())
267                test = true;
268        }
269        return test;
270    }
271
272    /**
273    @brief
274        Switch (toggle) the activity of the Trigger.
275    @return
276        Returns true if the activity of the Trigger has changed. False if not.
277    */
278    bool Trigger::switchState()
279    {
280        // If the previous state was active and there are no remaining activations, but the trigger stays active.
281        // or if the previous state was inactive and there are no remaining activations.
282        // the activity is not switched.
283        if (( (this->latestState_ & 0x2) && this->getStayActive() && (this->remainingActivations_ <= 0))
284           || (!(this->latestState_ & 0x2)                        && (this->remainingActivations_ == 0)))
285            return false;
286        // Else the activity is switched.
287        else
288        {
289            this->latestState_ ^= 0x2; // Toggle activity bit.
290
291            // If the activity has switched to active, decrease the remaining activations.
292            if (this->latestState_ & 0x2 && this->remainingActivations_ > 0)
293                this->remainingActivations_--;
294
295            // Store the new state in the queue.
296            this->storeState();
297
298            return true;
299        }
300    }
301
302    /**
303    @brief
304        Stores the state in the queue.
305        The queue is a list of states that are waiting to take effect paired with the time it has to wait after its preceding state takes effect.
306    */
307    void Trigger::storeState()
308    {
309        // Put the state change into the queue.
310        this->stateChanges_.push(std::pair<float, char>(this->timeSinceLastEvent_, this->latestState_));
311        // Reset time since last event
312        this->timeSinceLastEvent_ = 0.0;
313
314        // If there is just one state in the queue. (i.e. the one that we just added), The remaining time is set to the time it takes for the next state to take effect.
315        if (this->stateChanges_.size() == 1)
316            this->remainingTime_ = this->stateChanges_.front().first;
317    }
318
319    /**
320    @brief
321        React to a change in delay.
322        Only newly arriving states are affected by a change in delay.
323    */
324    void Trigger::delayChanged(void)
325    {
326        this->timeSinceLastEvent_ = this->getDelay();
327    }
328
329    /**
330    @brief
331        Set the visibility of all debug billboards of all Triggers.
332    @param bVisible
333        The visibility the billboards are set to.
334    */
335    void Trigger::debugFlares(bool bVisible)
336    {
337        // Iterate over all Triggers.
338        for (Trigger* trigger : ObjectList<Trigger>())
339            trigger->setVisible(bVisible);
340    }
341
342    /**
343    @brief
344        Set the colour of the debug billboard.
345    @param colour
346        The colour the billboard is set to.
347    */
348    void Trigger::setBillboardColour(const ColourValue& colour)
349    {
350        this->debugBillboard_.setColour(colour);
351    }
352
353    /**
354    @brief
355        React to a change of visibility of the trigger by adjusting the visibility of the debug billboards.
356    */
357    void Trigger::changedVisibility()
358    {
359        SUPER(Trigger, changedVisibility);
360
361        this->debugBillboard_.setVisible(this->isVisible());
362    }
363}
Note: See TracBrowser for help on using the repository browser.