1 /*************************************************************************** 2 * Copyright (C) 2005-2019 by the FIFE team * 3 * http://www.fifengine.net * 4 * This file is part of FIFE. * 5 * * 6 * FIFE is free software; you can redistribute it and/or * 7 * modify it under the terms of the GNU Lesser General Public * 8 * License as published by the Free Software Foundation; either * 9 * version 2.1 of the License, or (at your option) any later version. * 10 * * 11 * This library is distributed in the hope that it will be useful, * 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 * Lesser General Public License for more details. * 15 * * 16 * You should have received a copy of the GNU Lesser General Public * 17 * License along with this library; if not, write to the * 18 * Free Software Foundation, Inc., * 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 20 ***************************************************************************/ 21 22 // Standard C++ library includes 23 #include <vector> 24 25 // 3rd party library includes 26 27 // FIFE includes 28 // These includes are split up in two parts, separated by one empty line 29 // First block: files included from the FIFE root src directory 30 // Second block: files included from the same folder 31 32 #include "cell.h" 33 #include "cellcache.h" 34 #include "instance.h" 35 #include "layer.h" 36 #include "location.h" 37 #include "trigger.h" 38 39 namespace FIFE { 40 41 class TriggerChangeListener : public CellChangeListener, public InstanceChangeListener, public InstanceDeleteListener { 42 public: TriggerChangeListener(Trigger * trigger)43 TriggerChangeListener(Trigger* trigger) { 44 m_trigger = trigger; 45 } ~TriggerChangeListener()46 virtual ~TriggerChangeListener() {} 47 48 // InstanceDeleteListener callback onInstanceDeleted(Instance * instance)49 virtual void onInstanceDeleted(Instance* instance) { 50 const std::vector<TriggerCondition>& types = m_trigger->getTriggerConditions(); 51 if (std::find(types.begin(), types.end(), INSTANCE_TRIGGER_DELETE) != types.end()) { 52 m_trigger->setTriggered(); 53 } 54 m_trigger->detach(); 55 } 56 57 // CellChangeListener callback onInstanceEnteredCell(Cell * cell,Instance * instance)58 virtual void onInstanceEnteredCell(Cell* cell, Instance* instance) { 59 const std::vector<TriggerCondition>& types = m_trigger->getTriggerConditions(); 60 if (std::find(types.begin(), types.end(), CELL_TRIGGER_ENTER) != types.end()) { 61 const std::vector<Instance*>& restrict = m_trigger->getEnabledInstances(); 62 if (m_trigger->isEnabledForAllInstances() || 63 std::find(restrict.begin(), restrict.end(), instance) != restrict.end()) { 64 m_trigger->setTriggered(); 65 } 66 } 67 } 68 69 // CellChangeListener callback onInstanceExitedCell(Cell * cell,Instance * instance)70 virtual void onInstanceExitedCell(Cell* cell, Instance* instance) { 71 const std::vector<TriggerCondition>& types = m_trigger->getTriggerConditions(); 72 if (std::find(types.begin(), types.end(), CELL_TRIGGER_EXIT) != types.end()) { 73 const std::vector<Instance*>& restrict = m_trigger->getEnabledInstances(); 74 if (m_trigger->isEnabledForAllInstances() || 75 std::find(restrict.begin(), restrict.end(), instance) != restrict.end()) { 76 m_trigger->setTriggered(); 77 } 78 } 79 } 80 81 // CellChangeListener callback onBlockingChangedCell(Cell * cell,CellTypeInfo type,bool blocks)82 virtual void onBlockingChangedCell(Cell* cell, CellTypeInfo type, bool blocks) { 83 const std::vector<TriggerCondition>& types = m_trigger->getTriggerConditions(); 84 if (std::find(types.begin(), types.end(), CELL_TRIGGER_BLOCKING_CHANGE) != types.end()) { 85 m_trigger->setTriggered(); 86 } 87 } 88 89 // InstanceChangeListener callback onInstanceChanged(Instance * instance,InstanceChangeInfo info)90 virtual void onInstanceChanged(Instance* instance, InstanceChangeInfo info) { 91 const std::vector<TriggerCondition>& types = m_trigger->getTriggerConditions(); 92 if (m_trigger->getAttached() == instance && (info & ICHANGE_CELL) == ICHANGE_CELL) { 93 m_trigger->move(); 94 } 95 96 if (types.empty()) { 97 return; 98 } 99 100 if ((info & ICHANGE_LOC) == ICHANGE_LOC && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_LOCATION) != types.end()) { 101 m_trigger->setTriggered(); 102 } else if ((info & ICHANGE_ROTATION) == ICHANGE_ROTATION && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_ROTATION) != types.end()) { 103 m_trigger->setTriggered(); 104 } else if ((info & ICHANGE_SPEED) == ICHANGE_SPEED && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_SPEED) != types.end()) { 105 m_trigger->setTriggered(); 106 } else if ((info & ICHANGE_ACTION) == ICHANGE_ACTION && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_ACTION) != types.end()) { 107 m_trigger->setTriggered(); 108 } else if ((info & ICHANGE_TIME_MULTIPLIER) == ICHANGE_TIME_MULTIPLIER && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_TIME_MULTIPLIER) != types.end()) { 109 m_trigger->setTriggered(); 110 } else if ((info & ICHANGE_SAYTEXT) == ICHANGE_SAYTEXT && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_SAYTEXT) != types.end()) { 111 m_trigger->setTriggered(); 112 } else if ((info & ICHANGE_BLOCK) == ICHANGE_BLOCK && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_BLOCK) != types.end()) { 113 m_trigger->setTriggered(); 114 } else if ((info & ICHANGE_CELL) == ICHANGE_CELL && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_CELL) != types.end()) { 115 m_trigger->setTriggered(); 116 } else if ((info & ICHANGE_TRANSPARENCY) == ICHANGE_TRANSPARENCY && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_TRANSPARENCY) != types.end()) { 117 m_trigger->setTriggered(); 118 } else if ((info & ICHANGE_VISIBLE) == ICHANGE_VISIBLE && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_VISIBLE) != types.end()) { 119 m_trigger->setTriggered(); 120 } else if ((info & ICHANGE_STACKPOS) == ICHANGE_STACKPOS && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_STACKPOS) != types.end()) { 121 m_trigger->setTriggered(); 122 } else if ((info & ICHANGE_VISUAL) == ICHANGE_VISUAL && std::find(types.begin(), types.end(), INSTANCE_TRIGGER_VISUAL) != types.end()) { 123 m_trigger->setTriggered(); 124 } 125 } 126 127 private: 128 Trigger* m_trigger; 129 }; 130 Trigger()131 Trigger::Trigger(): 132 m_name(""), 133 m_triggered(false), 134 m_enabledAll(false), 135 m_attached(NULL) { 136 m_changeListener = new TriggerChangeListener(this); 137 } 138 Trigger(const std::string & name)139 Trigger::Trigger(const std::string& name): 140 m_name(name), 141 m_triggered(false), 142 m_enabledAll(false), 143 m_attached(NULL) { 144 m_changeListener = new TriggerChangeListener(this); 145 } 146 ~Trigger()147 Trigger::~Trigger() { 148 detach(); 149 std::vector<Cell*>::iterator it = m_assigned.begin(); 150 for (; it != m_assigned.end(); ++it) { 151 (*it)->removeChangeListener(m_changeListener); 152 } 153 delete m_changeListener; 154 } 155 addTriggerListener(ITriggerListener * listener)156 void Trigger::addTriggerListener(ITriggerListener* listener) { 157 std::vector<ITriggerListener*>::iterator it = std::find(m_triggerListeners.begin(), m_triggerListeners.end(), listener); 158 if (it == m_triggerListeners.end()) { 159 m_triggerListeners.push_back(listener); 160 } 161 } 162 removeTriggerListener(ITriggerListener * listener)163 void Trigger::removeTriggerListener(ITriggerListener* listener) { 164 std::vector<ITriggerListener*>::iterator i = m_triggerListeners.begin(); 165 while (i != m_triggerListeners.end()) { 166 if ((*i) == listener) { 167 // set the pointer to null, so it can be removed later 168 *i = NULL; 169 return; 170 } 171 ++i; 172 } 173 } 174 reset()175 void Trigger::reset() { 176 m_triggered = false; 177 } 178 setTriggered()179 void Trigger::setTriggered() { 180 if (!m_triggered) { 181 m_triggered = true; 182 std::vector<ITriggerListener*>::iterator i = m_triggerListeners.begin(); 183 while (i != m_triggerListeners.end()) { 184 if (*i) { 185 (*i)->onTriggered(); 186 } 187 ++i; 188 } 189 } 190 // remove null pointer 191 m_triggerListeners.erase(std::remove(m_triggerListeners.begin(), m_triggerListeners.end(), (ITriggerListener*)NULL), m_triggerListeners.end()); 192 } 193 addTriggerCondition(TriggerCondition type)194 void Trigger::addTriggerCondition(TriggerCondition type) { 195 std::vector<TriggerCondition>::iterator it = std::find(m_triggerConditions.begin(), m_triggerConditions.end(), type); 196 if (it == m_triggerConditions.end()) { 197 m_triggerConditions.push_back(type); 198 } 199 } 200 getTriggerConditions()201 const std::vector<TriggerCondition>& Trigger::getTriggerConditions() { 202 return m_triggerConditions; 203 } 204 removeTriggerCondition(TriggerCondition type)205 void Trigger::removeTriggerCondition(TriggerCondition type) { 206 std::vector<TriggerCondition>::iterator it = std::find(m_triggerConditions.begin(), m_triggerConditions.end(), type); 207 if (it != m_triggerConditions.end()) { 208 m_triggerConditions.erase(it); 209 } 210 } 211 enableForInstance(Instance * instance)212 void Trigger::enableForInstance(Instance* instance) { 213 std::vector<Instance*>::iterator it = std::find(m_enabledInstances.begin(), m_enabledInstances.end(), instance); 214 if (it == m_enabledInstances.end()) { 215 m_enabledInstances.push_back(instance); 216 } 217 } 218 getEnabledInstances()219 const std::vector<Instance*>& Trigger::getEnabledInstances() { 220 return m_enabledInstances; 221 } 222 disableForInstance(Instance * instance)223 void Trigger::disableForInstance(Instance* instance) { 224 std::vector<Instance*>::iterator it = std::find(m_enabledInstances.begin(), m_enabledInstances.end(), instance); 225 if (it != m_enabledInstances.end()) { 226 m_enabledInstances.erase(it); 227 } 228 } 229 enableForAllInstances()230 void Trigger::enableForAllInstances() { 231 m_enabledAll = true; 232 } 233 isEnabledForAllInstances()234 bool Trigger::isEnabledForAllInstances() { 235 return m_enabledAll; 236 } 237 disableForAllInstances()238 void Trigger::disableForAllInstances() { 239 m_enabledAll = false; 240 } 241 assign(Layer * layer,const ModelCoordinate & pt)242 void Trigger::assign(Layer* layer, const ModelCoordinate& pt) { 243 Cell* cell = layer->getCellCache()->getCell(pt); 244 if (!cell) { 245 return; 246 } 247 std::vector<Cell*>::iterator it = std::find(m_assigned.begin(), m_assigned.end(), cell); 248 if (it == m_assigned.end()) { 249 m_assigned.push_back(cell); 250 cell->addChangeListener(m_changeListener); 251 } 252 } 253 remove(Layer * layer,const ModelCoordinate & pt)254 void Trigger::remove(Layer* layer, const ModelCoordinate& pt) { 255 Cell* cell = layer->getCellCache()->getCell(pt); 256 if (!cell) { 257 return; 258 } 259 std::vector<Cell*>::iterator it = std::find(m_assigned.begin(), m_assigned.end(), cell); 260 if (it != m_assigned.end()) { 261 m_assigned.erase(it); 262 cell->removeChangeListener(m_changeListener); 263 } 264 } 265 assign(Cell * cell)266 void Trigger::assign(Cell* cell) { 267 std::vector<Cell*>::iterator it = std::find(m_assigned.begin(), m_assigned.end(), cell); 268 if (it == m_assigned.end()) { 269 m_assigned.push_back(cell); 270 cell->addChangeListener(m_changeListener); 271 } 272 } 273 remove(Cell * cell)274 void Trigger::remove(Cell* cell) { 275 std::vector<Cell*>::iterator it = std::find(m_assigned.begin(), m_assigned.end(), cell); 276 if (it != m_assigned.end()) { 277 m_assigned.erase(it); 278 cell->removeChangeListener(m_changeListener); 279 } 280 } 281 getAssignedCells()282 const std::vector<Cell*>& Trigger::getAssignedCells() { 283 return m_assigned; 284 } 285 attach(Instance * instance)286 void Trigger::attach(Instance* instance) { 287 if (instance == m_attached) { 288 return; 289 } 290 291 if (m_attached) { 292 detach(); 293 } 294 m_attached = instance; 295 m_attached->addDeleteListener(m_changeListener); 296 m_attached->addChangeListener(m_changeListener); 297 } 298 detach()299 void Trigger::detach() { 300 if (m_attached) { 301 m_attached->removeDeleteListener(m_changeListener); 302 m_attached->removeChangeListener(m_changeListener); 303 m_attached = 0; 304 } 305 } 306 move()307 void Trigger::move() { 308 if (m_assigned.empty()) { 309 return; 310 } 311 ModelCoordinate newPos = m_attached->getLocationRef().getLayerCoordinates(); 312 ModelCoordinate oldPos = m_attached->getOldLocationRef().getLayerCoordinates(); 313 moveTo(newPos, oldPos); 314 } 315 moveTo(const ModelCoordinate & newPos,const ModelCoordinate & oldPos)316 void Trigger::moveTo(const ModelCoordinate& newPos, const ModelCoordinate& oldPos) { 317 ModelCoordinate mc(newPos.x-oldPos.x, newPos.y-oldPos.y); 318 319 CellCache* cache = m_attached->getLocationRef().getLayer()->getCellCache(); 320 std::vector<Cell*> newCells; 321 std::vector<Cell*>::iterator it = m_assigned.begin(); 322 for (; it != m_assigned.end(); ++it) { 323 ModelCoordinate coord = (*it)->getLayerCoordinates(); 324 coord.x += mc.x; 325 coord.y += mc.y; 326 Cell* c = cache->getCell(coord); 327 if (c) { 328 newCells.push_back(c); 329 } 330 } 331 for (it = newCells.begin(); it != newCells.end(); ++it) { 332 std::vector<Cell*>::iterator found = std::find(m_assigned.begin(), m_assigned.end(), *it); 333 if (found != m_assigned.end()) { 334 m_assigned.erase(found); 335 } else { 336 // add new 337 (*it)->addChangeListener(m_changeListener); 338 } 339 } 340 // remove old 341 for (it = m_assigned.begin(); it != m_assigned.end(); ++it) { 342 (*it)->removeChangeListener(m_changeListener); 343 } 344 m_assigned = newCells; 345 } 346 } 347