Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/modules/objects/triggers/MultiTrigger.cc @ 6807

Last change on this file since 6807 was 6805, checked in by dafrick, 15 years ago

Possible bug fix.

File size: 15.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 *      Damian 'Mozork' Frick
24 *   Co-authors:
25 *      Benjamin Knecht
26 *
27*/
28
29#include "MultiTrigger.h"
30
31#include "core/CoreIncludes.h"
32#include "core/XMLPort.h"
33
34#include "MultiTriggerContainer.h"
35
36namespace orxonox
37{
38   
39    /*static*/ const int MultiTrigger::INF_s = -1;
40    /*static*/ const std::string MultiTrigger::or_s = "or";
41    /*static*/ const std::string MultiTrigger::and_s = "and";
42    /*static*/ const std::string MultiTrigger::xor_s = "xor";
43   
44    CreateFactory(MultiTrigger);
45   
46    //TODO: Clean up.
47    MultiTrigger::MultiTrigger(BaseObject* creator) : StaticEntity(creator)
48    {
49        RegisterObject(MultiTrigger);
50       
51        this->mode_ = MultiTriggerMode::EventTriggerAND;
52
53        this->bFirstTick_ = true;
54
55        this->bInvertMode_ = false;
56        this->bSwitch_ = false;
57        this->bStayActive_ = false;
58        this->delay_ = 0.0f;
59        this->remainingActivations_ = INF_s;
60        this->maxNumSimultaniousTriggerers_ = INF_s;
61       
62        this->targetMask_.exclude(Class(BaseObject));
63
64        this->setSyncMode(0x0);
65       
66    }
67   
68    //TODO: Document
69    MultiTrigger::~MultiTrigger()
70    {
71        COUT(4) << "Destorying MultiTrigger &" << this << ". " << this->stateQueue_.size() << " states still in queue. Deleting." << std::endl;
72        while(this->stateQueue_.size() > 0)
73        {
74            MultiTriggerState* state = this->stateQueue_.front().second;
75            this->stateQueue_.pop_front();
76            delete state;
77        }
78    }
79   
80    //TODO: Clean up?
81    void MultiTrigger::XMLPort(Element& xmlelement, XMLPort::Mode mode)
82    {
83        SUPER(MultiTrigger, XMLPort, xmlelement, mode);
84
85        XMLPortParam(MultiTrigger, "delay", setDelay, getDelay, xmlelement, mode).defaultValues(0.0f);
86        XMLPortParam(MultiTrigger, "switch", setSwitch, getSwitch, xmlelement, mode).defaultValues(false);
87        XMLPortParam(MultiTrigger, "stayactive", setStayActive, getStayActive, xmlelement, mode).defaultValues(false);
88        XMLPortParam(MultiTrigger, "activations", setActivations, getActivations, xmlelement, mode).defaultValues(INF_s);
89        XMLPortParam(MultiTrigger, "invert", setInvert, getInvert, xmlelement, mode).defaultValues(false);
90        XMLPortParam(MultiTrigger, "simultaniousTriggerers", setSimultaniousTriggerers, getSimultaniousTriggerers, xmlelement, mode).defaultValues(INF_s);
91        XMLPortParamTemplate(MultiTrigger, "mode", setMode, getModeString, xmlelement, mode, const std::string&).defaultValues(MultiTrigger::and_s);
92        XMLPortParamLoadOnly(MultiTrigger, "target", addTargets, xmlelement, mode).defaultValues("ControllableEntity"); //TODO: Remove load only
93
94        XMLPortObject(MultiTrigger, MultiTrigger, "", addTrigger, getTrigger, xmlelement, mode);
95       
96        COUT(4) << "MultiTrigger &" << this << " created." << std::endl;
97    }
98   
99    //TODO: Document
100    void MultiTrigger::tick(float dt)
101    {
102        if(this->bFirstTick_) // If this is the first tick.
103        {
104            this->bFirstTick_ = false;
105            this->fire(false); //TODO: Does this work? Resp. Is it correct?
106        }
107
108        // Check if the object is active (this is NOT Trigger::isActive()!)
109        if (!this->BaseObject::isActive())
110            return;
111
112        SUPER(MultiTrigger, tick, dt);
113       
114        std::queue<MultiTriggerState*>* queue  = this->letTrigger();
115        if(queue != NULL)
116            COUT(4) << "MultiTrigger &" << this << ": " << queue->size() << " new states to state queue." << std::endl;
117       
118        if(queue != NULL)
119        {
120            while(queue->size() > 0)
121            {
122                //TODO: Be more efficient, Don't delete a state and create a new one immediately after that. Reuse!
123                MultiTriggerState* state = queue->front();
124                if(state == NULL)
125                    break;
126                   
127                this->addState(state->bTriggered & this->isModeTriggered(state->originator), state->originator);
128                queue->pop();
129                delete state;
130            }
131            delete queue;
132        }
133
134        if (this->stateQueue_.size() > 0)
135        {
136            MultiTriggerState* state;
137            float timeRemaining;
138            for(int size = this->stateQueue_.size(); size >= 1; size--)
139            {
140                timeRemaining = this->stateQueue_.front().first;
141                state = this->stateQueue_.front().second;
142                if(timeRemaining <= dt)
143                {
144                    if(this->maxNumSimultaniousTriggerers_ == INF_s || this->triggered_.size() < (unsigned int)this->maxNumSimultaniousTriggerers_)
145                    {
146                        // Add the originator to the objects triggering this MultiTrigger.
147                        if(state->bTriggered == true)
148                        {
149                            this->triggered_.insert(state->originator);
150                        }
151                        // Remove the originator from the objects triggering this MultiTrigger.
152                        else
153                        {
154                            this->triggered_.erase(state->originator);
155                        }
156                       
157                        // Add the originator to the objects activating this MultiTrigger.
158                        if(state->bActive == true)
159                        {
160                            this->active_.insert(state->originator);
161                        }
162                        // Remove the originator from the objects activating this MultiTrigger.
163                        else
164                        {
165                            this->active_.erase(state->originator);
166                        }
167                       
168                        // Fire the event.
169                        this->fire(state->bActive, state->originator);
170                    }
171                   
172                    // Remove the state from the state queue.
173                    this->stateQueue_.pop_front();
174                    COUT(4) << "MultiTrigger &" << this << ": State processed, removing from state queue. originator: " << state->originator->getIdentifier()->getName() << " (&" << state->originator << "), active: " << state->bActive << "|" << this->isActive(state->originator) << ", triggered: " << state->bTriggered << "|" << this->isTriggered(state->originator) << "." << std::endl;
175                    delete state;
176                    size -= 1;
177                }
178                else
179                {
180                    this->stateQueue_.push_back(std::pair<float, MultiTriggerState*>(timeRemaining-dt, state));
181                    this->stateQueue_.pop_front();
182                    COUT(4) << "MultiTrigger &" << this << ": State processed, decreasing time remaining. originator: " << state->originator->getIdentifier()->getName() << " (&" << state->originator << "), active: " << state->bActive << ", triggered: " << state->bTriggered << ", time remaining: " << timeRemaining-dt << "." << std::endl;
183                }
184            }
185        }
186    }
187
188    //TODO: Document
189    bool MultiTrigger::isModeTriggered(BaseObject* triggerer)
190    {
191        if (this->children_.size() != 0)
192        {
193            bool returnVal = false;
194
195            switch (this->mode_)
196            {
197                case MultiTriggerMode::EventTriggerAND:
198                    returnVal = checkAnd(triggerer);
199                    break;
200                case MultiTriggerMode::EventTriggerOR:
201                    returnVal = checkOr(triggerer);
202                    break;
203                case MultiTriggerMode::EventTriggerXOR:
204                    returnVal = checkXor(triggerer);
205                    break;
206                default:
207                    returnVal = false;
208                    break;
209            }
210
211            return returnVal;
212        }
213       
214        return true;
215    }
216   
217    //TODO: Document
218    std::queue<MultiTriggerState*>* MultiTrigger::letTrigger(void)
219    {
220        std::queue<MultiTriggerState*>* queue = new std::queue<MultiTriggerState*>();
221        MultiTriggerState* state = new MultiTriggerState;
222        state->bTriggered = true;
223        state->originator = NULL;
224        queue->push(state);
225        return queue;
226    }
227   
228    //TODO: Document
229    bool MultiTrigger::isTriggered(BaseObject* triggerer)
230    {
231        std::set<BaseObject*>::iterator it = this->triggered_.find(triggerer);
232        if(it == this->triggered_.end())
233            return false;
234        return true;
235    }
236
237    //TODO: Document
238    bool MultiTrigger::checkAnd(BaseObject* triggerer)
239    {
240        std::set<MultiTrigger*>::iterator it;
241        for(it = this->children_.begin(); it != this->children_.end(); ++it)
242        {
243            if (!(*it)->isActive(triggerer))
244                return false;
245        }
246        return true;
247    }
248
249    //TODO: Document
250    bool MultiTrigger::checkOr(BaseObject* triggerer)
251    {
252        std::set<MultiTrigger*>::iterator it;
253        for(it = this->children_.begin(); it != this->children_.end(); ++it)
254        {
255            if ((*it)->isActive(triggerer))
256                return true;
257        }
258        return false;
259    }
260
261    //TODO: Document
262    bool MultiTrigger::checkXor(BaseObject* triggerer)
263    {
264        std::set<MultiTrigger*>::iterator it;
265        bool test = false;
266        for(it = this->children_.begin(); it != this->children_.end(); ++it)
267        {
268            if (test && (*it)->isActive(triggerer))
269                return false;
270            if ((*it)->isActive(triggerer))
271                test = true;
272        }
273        return test;
274    }
275   
276    //TODO: Document
277    bool MultiTrigger::addState(bool bTriggered, BaseObject* originator)
278    {
279        if(!this->isTarget(originator))
280            return false;
281       
282        bTriggered ^= this->bInvertMode_;
283        // If the state doesn't change.
284        if(this->isTriggered() && bTriggered)
285            return false;
286       
287        bool bActive = !this->isActive(originator);
288       
289        // If the MultiTrigger is in switch mode.
290        if(this->bSwitch_ && !bTriggered)
291            return false;
292       
293        // If the state changes to active.
294        if(this->remainingActivations_ != INF_s && bActive)
295        {
296            if(this->remainingActivations_ == 0)
297                return false;
298            this->remainingActivations_--;
299        }
300        else
301        {
302            // If the MultiTrigger should stay active and there are no more remaining activations.
303            if(this->bStayActive_ && this->remainingActivations_ == 0)
304                return false;
305        }
306       
307        COUT(4) << "MultiTrigger &" << this << ": State added to state queue. originator: " << originator->getIdentifier()->getName() << " (&" << originator << "), active: " << bActive << "|" << this->isActive(originator) << ", triggered: " << bTriggered << "|" << this->isTriggered(originator) <<  "." << std::endl;
308       
309        // Create state.
310        MultiTriggerState* state = new MultiTriggerState;
311        state->bActive = bActive;
312        state->bTriggered = bTriggered;
313        state->originator = originator;
314        this->stateQueue_.push_back(std::pair<float, MultiTriggerState*>(this->delay_, state));
315       
316        return true;
317    }
318
319    //TODO: Document
320    void MultiTrigger::setMode(const std::string& modeName)
321    {
322        if (modeName == MultiTrigger::and_s)
323            this->setMode(MultiTriggerMode::EventTriggerAND);
324        else if (modeName == MultiTrigger::or_s)
325            this->setMode(MultiTriggerMode::EventTriggerOR);
326        else if (modeName == MultiTrigger::xor_s)
327            this->setMode(MultiTriggerMode::EventTriggerXOR);
328    }
329
330    //TODO: Document
331    const std::string& MultiTrigger::getModeString() const
332    {
333        if (this->mode_ == MultiTriggerMode::EventTriggerAND)
334            return MultiTrigger::and_s;
335        else if (this->mode_ == MultiTriggerMode::EventTriggerOR)
336            return MultiTrigger::or_s;
337        else if (this->mode_ == MultiTriggerMode::EventTriggerXOR)
338            return MultiTrigger::xor_s;
339        else
340            return MultiTrigger::and_s;
341    }
342   
343    //TODO: Document
344    bool MultiTrigger::isActive(BaseObject* triggerer)
345    {
346        std::set<BaseObject*>::iterator it = this->active_.find(triggerer);
347        if(it == this->active_.end())
348            return false;
349        return true;
350    }
351
352    //TODO: Document
353    void MultiTrigger::addTrigger(MultiTrigger* trigger)
354    {
355        if (this != trigger && trigger != NULL)
356            this->children_.insert(trigger);
357    }
358
359    //TODO: Document
360    const MultiTrigger* MultiTrigger::getTrigger(unsigned int index) const
361    {
362        if (this->children_.size() <= index)
363            return NULL;
364
365        std::set<MultiTrigger*>::const_iterator it;
366        it = this->children_.begin();
367
368        for (unsigned int i = 0; i != index; ++i)
369            ++it;
370
371        return (*it);
372    }
373   
374    //TODO: Document
375    void MultiTrigger::fire(bool status, BaseObject* originator)
376    {
377        if(originator == NULL)
378        {
379            this->fireEvent(status);
380            return;
381        }
382        MultiTriggerContainer* container = new MultiTriggerContainer(this, this, originator);
383        this->fireEvent(status, container);
384        COUT(4) << "MultiTrigger &" << this << ": Fired event. originator: " << originator->getIdentifier()->getName() << " (&" << originator << "), status: " << status << "." << std::endl;
385        delete container;
386    }
387   
388    //TODO: Document
389    void MultiTrigger::addTargets(const std::string& targets)
390    {
391        Identifier* target = ClassByString(targets);
392
393        if (target == NULL)
394        {
395            COUT(1) << "Error: \"" << targets << "\" is not a valid class name to include in ClassTreeMask (in " << this->getName() << ", class " << this->getIdentifier()->getName() << ')' << std::endl;
396            return;
397        }
398
399        this->targetMask_.include(target);
400
401        // trigger shouldn't react on itself or other triggers
402        this->targetMask_.exclude(Class(MultiTrigger), true);
403
404        // we only want WorldEntities
405        ClassTreeMask WEMask;
406        WEMask.include(Class(WorldEntity));
407        this->targetMask_ *= WEMask;
408
409        this->notifyMaskUpdate();
410    }
411
412    //TODO: Document
413    void MultiTrigger::removeTargets(const std::string& targets)
414    {
415        Identifier* target = ClassByString(targets);
416        this->targetMask_.exclude(target);
417    }
418   
419}
Note: See TracBrowser for help on using the repository browser.