Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6802 was 6800, checked in by dafrick, 15 years ago

Created a new class of triggers called Multitriggers.
MultiTriggers are triggers which (as opposed to normal triggers) have a state for each object triggering the MultiTrigger, that means, that a MultiTrigger can be triggered for two different Players, while not being triggered for a third.
To go with this MultiTrigger I created a data structure (MultitriggerContainer), which helps relaying important information to the objects, that receive the Events of the trigger.
Also there is a MultiDistanceTrigger, which is just the DistanceTrigger as a MultiTrigger.

To make this work I had to make some adjustements to the eventsystem, namely an EventState can now be either an EventState (as it was before) or an EventSink, which means that every efent arriving at the EventState is processed as opposed to just the ones which change the state.
There is a new makro (XMLPortEventSink) to create an EventState with sink behaviour. It can be used exacly as the XMLPortEventState makro.

File size: 14.9 KB
RevLine 
[6800]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        while(queue != NULL && queue->size() > 0)
118        {
119            //TODO: Be more efficient, Don't delete a state and create a new one immediately after that. Reuse!
120            MultiTriggerState* state = queue->front();
121            this->addState(state->bTriggered & this->isModeTriggered(state->originator), state->originator);
122            queue->pop();
123            delete state;
124        }
125        delete queue;
126
127        if (this->stateQueue_.size() > 0)
128        {
129            MultiTriggerState* state;
130            float timeRemaining;
131            for(int size = this->stateQueue_.size(); size >= 1; size--)
132            {
133                timeRemaining = this->stateQueue_.front().first;
134                state = this->stateQueue_.front().second;
135                if(timeRemaining <= dt)
136                {
137                    if(this->maxNumSimultaniousTriggerers_ == INF_s || this->triggered_.size() < (unsigned int)this->maxNumSimultaniousTriggerers_)
138                    {
139                        // Add the originator to the objects triggering this MultiTrigger.
140                        if(state->bTriggered == true)
141                        {
142                            this->triggered_.insert(state->originator);
143                        }
144                        // Remove the originator from the objects triggering this MultiTrigger.
145                        else
146                        {
147                            this->triggered_.erase(state->originator);
148                        }
149                       
150                        // Add the originator to the objects activating this MultiTrigger.
151                        if(state->bActive == true)
152                        {
153                            this->active_.insert(state->originator);
154                        }
155                        // Remove the originator from the objects activating this MultiTrigger.
156                        else
157                        {
158                            this->active_.erase(state->originator);
159                        }
160                       
161                        // Fire the event.
162                        this->fire(state->bActive, state->originator);
163                    }
164                   
165                    // Remove the state from the state queue.
166                    this->stateQueue_.pop_front();
167                    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;
168                    delete state;
169                    size -= 1;
170                }
171                else
172                {
173                    this->stateQueue_.push_back(std::pair<float, MultiTriggerState*>(timeRemaining-dt, state));
174                    this->stateQueue_.pop_front();
175                    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;
176                }
177            }
178        }
179    }
180
181    //TODO: Document
182    bool MultiTrigger::isModeTriggered(BaseObject* triggerer)
183    {
184        if (this->children_.size() != 0)
185        {
186            bool returnVal = false;
187
188            switch (this->mode_)
189            {
190                case MultiTriggerMode::EventTriggerAND:
191                    returnVal = checkAnd(triggerer);
192                    break;
193                case MultiTriggerMode::EventTriggerOR:
194                    returnVal = checkOr(triggerer);
195                    break;
196                case MultiTriggerMode::EventTriggerXOR:
197                    returnVal = checkXor(triggerer);
198                    break;
199                default:
200                    returnVal = false;
201                    break;
202            }
203
204            return returnVal;
205        }
206       
207        return true;
208    }
209   
210    //TODO: Document
211    std::queue<MultiTriggerState*>* MultiTrigger::letTrigger(void)
212    {
213        std::queue<MultiTriggerState*>* queue = new std::queue<MultiTriggerState*>();
214        MultiTriggerState* state = new MultiTriggerState;
215        state->bTriggered = true;
216        state->originator = NULL;
217        queue->push(state);
218        return queue;
219    }
220   
221    //TODO: Document
222    bool MultiTrigger::isTriggered(BaseObject* triggerer)
223    {
224        std::set<BaseObject*>::iterator it = this->triggered_.find(triggerer);
225        if(it == this->triggered_.end())
226            return false;
227        return true;
228    }
229
230    //TODO: Document
231    bool MultiTrigger::checkAnd(BaseObject* triggerer)
232    {
233        std::set<MultiTrigger*>::iterator it;
234        for(it = this->children_.begin(); it != this->children_.end(); ++it)
235        {
236            if (!(*it)->isActive(triggerer))
237                return false;
238        }
239        return true;
240    }
241
242    //TODO: Document
243    bool MultiTrigger::checkOr(BaseObject* triggerer)
244    {
245        std::set<MultiTrigger*>::iterator it;
246        for(it = this->children_.begin(); it != this->children_.end(); ++it)
247        {
248            if ((*it)->isActive(triggerer))
249                return true;
250        }
251        return false;
252    }
253
254    //TODO: Document
255    bool MultiTrigger::checkXor(BaseObject* triggerer)
256    {
257        std::set<MultiTrigger*>::iterator it;
258        bool test = false;
259        for(it = this->children_.begin(); it != this->children_.end(); ++it)
260        {
261            if (test && (*it)->isActive(triggerer))
262                return false;
263            if ((*it)->isActive(triggerer))
264                test = true;
265        }
266        return test;
267    }
268   
269    //TODO: Document
270    bool MultiTrigger::addState(bool bTriggered, BaseObject* originator)
271    {
272        if(!this->isTarget(originator))
273            return false;
274       
275        bTriggered ^= this->bInvertMode_;
276        // If the state doesn't change.
277        if(this->isTriggered() && bTriggered)
278            return false;
279       
280        bool bActive = !this->isActive(originator);
281       
282        // If the MultiTrigger is in switch mode.
283        if(this->bSwitch_ && !bTriggered)
284            return false;
285       
286        // If the state changes to active.
287        if(this->remainingActivations_ != INF_s && bActive)
288        {
289            if(this->remainingActivations_ == 0)
290                return false;
291            this->remainingActivations_--;
292        }
293        else
294        {
295            // If the MultiTrigger should stay active and there are no more remaining activations.
296            if(this->bStayActive_ && this->remainingActivations_ == 0)
297                return false;
298        }
299       
300        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;
301       
302        // Create state.
303        MultiTriggerState* state = new MultiTriggerState;
304        state->bActive = bActive;
305        state->bTriggered = bTriggered;
306        state->originator = originator;
307        this->stateQueue_.push_back(std::pair<float, MultiTriggerState*>(this->delay_, state));
308       
309        return true;
310    }
311
312    //TODO: Document
313    void MultiTrigger::setMode(const std::string& modeName)
314    {
315        if (modeName == MultiTrigger::and_s)
316            this->setMode(MultiTriggerMode::EventTriggerAND);
317        else if (modeName == MultiTrigger::or_s)
318            this->setMode(MultiTriggerMode::EventTriggerOR);
319        else if (modeName == MultiTrigger::xor_s)
320            this->setMode(MultiTriggerMode::EventTriggerXOR);
321    }
322
323    //TODO: Document
324    const std::string& MultiTrigger::getModeString() const
325    {
326        if (this->mode_ == MultiTriggerMode::EventTriggerAND)
327            return MultiTrigger::and_s;
328        else if (this->mode_ == MultiTriggerMode::EventTriggerOR)
329            return MultiTrigger::or_s;
330        else if (this->mode_ == MultiTriggerMode::EventTriggerXOR)
331            return MultiTrigger::xor_s;
332        else
333            return MultiTrigger::and_s;
334    }
335   
336    //TODO: Document
337    bool MultiTrigger::isActive(BaseObject* triggerer)
338    {
339        std::set<BaseObject*>::iterator it = this->active_.find(triggerer);
340        if(it == this->active_.end())
341            return false;
342        return true;
343    }
344
345    //TODO: Document
346    void MultiTrigger::addTrigger(MultiTrigger* trigger)
347    {
348        if (this != trigger && trigger != NULL)
349            this->children_.insert(trigger);
350    }
351
352    //TODO: Document
353    const MultiTrigger* MultiTrigger::getTrigger(unsigned int index) const
354    {
355        if (this->children_.size() <= index)
356            return NULL;
357
358        std::set<MultiTrigger*>::const_iterator it;
359        it = this->children_.begin();
360
361        for (unsigned int i = 0; i != index; ++i)
362            ++it;
363
364        return (*it);
365    }
366   
367    //TODO: Document
368    void MultiTrigger::fire(bool status, BaseObject* originator)
369    {
370        if(originator == NULL)
371        {
372            this->fireEvent(status);
373            return;
374        }
375        MultiTriggerContainer* container = new MultiTriggerContainer(this, this, originator);
376        this->fireEvent(status, container);
377        COUT(4) << "MultiTrigger &" << this << ": Fired event. originator: " << originator->getIdentifier()->getName() << " (&" << originator << "), status: " << status << "." << std::endl;
378        delete container;
379    }
380   
381    //TODO: Document
382    void MultiTrigger::addTargets(const std::string& targets)
383    {
384        Identifier* target = ClassByString(targets);
385
386        if (target == NULL)
387        {
388            COUT(1) << "Error: \"" << targets << "\" is not a valid class name to include in ClassTreeMask (in " << this->getName() << ", class " << this->getIdentifier()->getName() << ')' << std::endl;
389            return;
390        }
391
392        this->targetMask_.include(target);
393
394        // trigger shouldn't react on itself or other triggers
395        this->targetMask_.exclude(Class(MultiTrigger), true);
396
397        // we only want WorldEntities
398        ClassTreeMask WEMask;
399        WEMask.include(Class(WorldEntity));
400        this->targetMask_ *= WEMask;
401
402        this->notifyMaskUpdate();
403    }
404
405    //TODO: Document
406    void MultiTrigger::removeTargets(const std::string& targets)
407    {
408        Identifier* target = ClassByString(targets);
409        this->targetMask_.exclude(target);
410    }
411   
412}
Note: See TracBrowser for help on using the repository browser.