// // BlockingActionParser.cpp // SteveMaggieCpp // // Created by Katarzyna Kalinowska-Górska on 31.05.2017. // // #include #include "BlockingActionParser.h" #include "JSONParseUtils.h" #include "TouchHandlerTypes.h" #include "GeometryUtils.h" #include "DragAndDropHandler.h" #include "SimpleValue.h" #include "ChangingSprite.h" #include "LayoutObject.h" #include "SimpleValue.h" #include "MathUtils.h" #include "ValueStorage.h" #include "PaletteNode.h" #include "ContainerSprite.h" #include "SoundsRepo.h" // main parse function cocos2d::Action* BlockingActionParser::parseJSONAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { cocos2d::Action* parsedAction = NULL; auto blocking = JSONParseUtils::checkMemberBool(jsonActionObject, "dontBlock", true); if(!blocking){ notifyDelegateWhenFinished = true; } // log("BlockingActionParser: parsing action of type "+jsonActionObject.actionType); if(JSONParseUtils::hasMemberString(jsonActionObject, "actionType")){ std::string actionType = jsonActionObject["actionType"].GetString(); if(actionType == "callFunctionWithBlocking"){ parsedAction = this->parseCallFunctionWithBlockingAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "waitForTouch"){ parsedAction = this->parseWaitForTouchAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "waitForPaletteComponent"){ parsedAction = this->parseWaitForPaletteComponentAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "waitForObjectUnlock"){ parsedAction = this->parseWaitForObjectUnlockAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "waitForDragAndDrop"){ parsedAction = this->parseWaitForDragAndDropAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } } return parsedAction; } // the function's last parameter has to be the callback cocos2d::Action* BlockingActionParser::parseCallFunctionWithBlockingAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate){ auto storedValue = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); if(ActionParser::getInstance().checkLateCondition(*storedValue, pParseDelegate) == false){ return; } auto object = ActionParser::getInstance().prepareObjectsForAction(*storedValue, pParseDelegate)[0]; auto callback = [&](std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate, bool p2NotifyDelegate){ auto storedValue2 = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); if(p2NotifyDelegate){ p2ParseDelegate->actionFinished(*storedValue2); } ValueStorage::getInstance().removeStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); }; const rapidjson::Value* params = NULL; if(JSONParseUtils::hasMemberArray(*storedValue, "parameters")){ params = &((*storedValue)["parameters"]); } object->callFunctionByName((*storedValue)["functionName"].GetString(), params, pParseDelegate, std::bind(callback, pStoredValueKey, pParseDelegate, pNotifyDelegate)); }; return ActionParser::getInstance().embedFunctionInAction(std::bind(actionFunction, storedValueKey, parseDelegate, notifyDelegateWhenFinished), jsonActionObject, parseDelegate, false); } // functions for parsing differenct actions cocos2d::Action* BlockingActionParser::parseWaitForTouchAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { static const std::string TouchHandlerFunctionKey = "WaitForTouchActionTouchesBeganHandler"; auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate){ auto storedValue = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); TouchHandlerFunction newTouchBeganHandler = std::bind([&](cocos2d::Touch* touch, cocos2d::Event* event, std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate, bool p2NotifyDelegate){ auto storedValue2 = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); auto objectsToTouch = ActionParser::getInstance().parseObjectOrObjects(*storedValue2, "rightObjectName", "rightObjectNames", p2ParseDelegate); auto wrongObjects = ActionParser::getInstance().parseObjectOrObjects(*storedValue2, "wrongObjectName", "wrongObjectNames", p2ParseDelegate); int touchedObjectsCount = 0; static std::string SubContainer = "WaitForTouchActionTouchedFlags"; //TODO: container name from the delegate for(int i = 0; i < objectsToTouch.size(); ++i){ auto objectToTouch = objectsToTouch[i]; auto objAsNode = dynamic_cast(objectToTouch); auto touchedPtr = ValueStorage::getInstance().getStoredSimpleValue(SubContainer+objectToTouch->getObjectName(), p2ParseDelegate->getValueStorageContainerName()); if(!touchedPtr){ SimpleValue temp{false}; touchedPtr = &temp; ValueStorage::getInstance().storeSimpleValueWithKey(touchedPtr, SubContainer+objectToTouch->getObjectName(), p2ParseDelegate->getValueStorageContainerName()); } if(!touchedPtr->getBoolValue() && GeometryUtils::getBoundingBoxToWorld(objAsNode).containsPoint(touch->getLocation())){ if(JSONParseUtils::hasMemberArray(*storedValue2, "rightActions")){ ActionParser::getInstance().parseAndRunActions((*storedValue2)["rightActions"], p2ParseDelegate, false); } if(JSONParseUtils::hasMemberArray(*storedValue2, "rightActionsForObjects")){ ActionParser::getInstance().parseAndRunActions((*storedValue2)["rightActionsForObjects"].GetArray()[i], p2ParseDelegate, false); } touchedPtr->setBoolValue(true); if(++touchedObjectsCount == objectsToTouch.size()){ if(JSONParseUtils::checkMemberBool(*storedValue2, "dontBlock", false)){ p2ParseDelegate->removeTouchHandler(TouchHandlerFunctionKey, TOUCHES_BEGAN); p2ParseDelegate->cancelAllCompletingActions(); if(p2NotifyDelegate){ p2ParseDelegate->actionFinished(*storedValue2); } ValueStorage::getInstance().removeStoredValue(pStoredValueKey, p2ParseDelegate->getValueStorageContainerName()); ValueStorage::getInstance().clearStoredData(p2ParseDelegate->getValueStorageContainerName()); } else { //to enable picking the objects again touchedObjectsCount = 0; for(auto object : objectsToTouch){ SimpleValue* touchedPtr2 = ValueStorage::getInstance().getStoredSimpleValue(SubContainer + object->getObjectName(), p2ParseDelegate->getValueStorageContainerName()); if(touchedPtr2){ touchedPtr2->setBoolValue(false); } else { SimpleValue temp2{false}; ValueStorage::getInstance().storeSimpleValueWithKey(&temp2, SubContainer + objectToTouch->getObjectName(), p2ParseDelegate->getValueStorageContainerName()); } } } } return true; } } if(JSONParseUtils::hasMemberArray(*storedValue2, "wrongActions")){ for(auto wrongObject : wrongObjects){ auto objAsNode = dynamic_cast(wrongObject); if(GeometryUtils::getBoundingBoxToWorld(objAsNode).containsPoint(touch->getLocation())){ ActionParser::getInstance().parseAndRunActions((*storedValue2)["wrongActions"], p2ParseDelegate, false); break; } } } return false; }, std::placeholders::_1, std::placeholders::_2, pStoredValueKey, pParseDelegate, pNotifyDelegate); pParseDelegate->newTouchHandler(TouchHandlerFunctionKey, newTouchBeganHandler, TOUCHES_BEGAN); this->runCompletingActions(*storedValue, pParseDelegate); }; auto notify = JSONParseUtils::checkMemberBool(jsonActionObject, "dontBlock", true); return ActionParser::getInstance().embedFunctionInAction(std::bind(actionFunction, storedValueKey, parseDelegate, notifyDelegateWhenFinished), jsonActionObject, parseDelegate, notify); //todo there is some ambiguity here... dont notify now or later? will have to solve it somehow } cocos2d::Action* BlockingActionParser::parseWaitForPaletteComponentAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate){ auto storedValue = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); auto objectsToTouch = ActionParser::getInstance().parseObjectOrObjects(*storedValue, "rightObjectName", "rightObjectNames", pParseDelegate); auto paletteNode = dynamic_cast(dynamic_cast(objectsToTouch[0])->getParent()); std::function callback = std::bind([&](PaletteNode * pPaletteNode, PaletteComponentSprite * paletteComponentSprite, bool chosen, bool pressed, std::string pStoredValueKey2, ActionParseDelegate* pParseDelegate2, bool pNotifyDelegate2){ if(pressed){ bool wasRightObject = false; auto storedValue2 = ValueStorage::getInstance().getStoredValue(pStoredValueKey2, pParseDelegate2->getValueStorageContainerName()); auto rightObjects = ActionParser::getInstance().parseObjectOrObjects(*storedValue2, "rightObjectName", "rightObjectNames", pParseDelegate2); for(ScenarioObject* rightObject : rightObjects){ PaletteComponentSprite* rightPaletteComponentSprite = dynamic_cast(rightObject); if(paletteComponentSprite->objectName == rightPaletteComponentSprite->objectName){ if(JSONParseUtils::hasMemberArray(*storedValue2, "rightActions")){ ActionParser::getInstance().parseAndRunActions((*storedValue2)["rightActions"], pParseDelegate2, false); } wasRightObject = true; if(JSONParseUtils::checkMemberBool(*storedValue2, "dontBlock", false)){ pPaletteNode->setOnPaletteStateChangedCallback([](PaletteNode*, PaletteComponentSprite*, bool, bool){}); pParseDelegate2->cancelAllCompletingActions(); if(pNotifyDelegate2){ pParseDelegate2->actionFinished(*storedValue2); } ValueStorage::getInstance().removeStoredValue(pStoredValueKey2, pParseDelegate2->getValueStorageContainerName()); } break; } } if(!wasRightObject && JSONParseUtils::hasMemberArray(*storedValue2, "wrongActions")){ auto wrongObjects = ActionParser::getInstance().parseObjectOrObjects(*storedValue2, "wrongObjectName", "wrongObjectNames", pParseDelegate2); for(auto wrongObject : wrongObjects){ auto wrongPaletteComponentSprite = dynamic_cast(wrongObject); if(paletteComponentSprite->objectName == wrongPaletteComponentSprite->objectName){ ActionParser::getInstance().parseAndRunActions((*storedValue2)["wrongActions"], pParseDelegate2, false); break; } } } } }, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,pStoredValueKey, pParseDelegate, pNotifyDelegate); paletteNode->setOnPaletteStateChangedCallback(callback); this->runCompletingActions(*storedValue, pParseDelegate); }; auto notify = JSONParseUtils::checkMemberBool(jsonActionObject, "dontBlock", true); return ActionParser::getInstance().embedFunctionInAction(std::bind(actionFunction, storedValueKey, parseDelegate, notifyDelegateWhenFinished), jsonActionObject, parseDelegate, notify); //todo there is some ambiguity here... dont notify now or later? will have to solve it somehow } cocos2d::Action* BlockingActionParser::parseWaitForDragAndDropAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate){ auto pJsonActionObject = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); auto objectsToDrag = ActionParser::getInstance().parseObjectOrObjects(*pJsonActionObject, "draggedObjectName", "draggedObjectNames", pParseDelegate); auto extendPercent = 0; if(JSONParseUtils::hasMemberFloat(*pJsonActionObject, "draggedObjectGrabAreaExtendByPercent")){ extendPercent = (*pJsonActionObject)["draggedObjectGrabAreaExtendByPercent"].GetFloat(); } auto objectsToDragExtendPercentValues = std::vector(objectsToDrag.size(), extendPercent); std::vector wrongDraggedObjects = ActionParser::getInstance().parseObjectOrObjects(*pJsonActionObject, "wrongDraggedObjectName", "wrongDraggedObjectNames", pParseDelegate); ScenarioObject* destObject = nullptr; std::vector wrongDstObjects; int indexForConditionedCompletingActions = 0; if(JSONParseUtils::hasMemberObject(*pJsonActionObject, "randomDestinationObjectNameFrom")){ auto detailsObject = (*pJsonActionObject)["randomDestinationObjectNameFrom"].GetObject(); auto allDstObjects = ActionParser::getInstance().parseObjects(detailsObject["namesList"], pParseDelegate); int index = -1; while(destObject == nullptr){ index = MathUtils::getRandomInt(0, allDstObjects.size()-1); if(!dynamic_cast(allDstObjects[index])->hasContent()){//TODO parse the condition first destObject = allDstObjects[index]; break; } } for(int i = 0; i < index; ++i){ wrongDstObjects.push_back(allDstObjects[i]); } for(int i = index+1; i < allDstObjects.size(); ++i){ wrongDstObjects.push_back(allDstObjects[i]); } auto destObjSoundPath = JSONParseUtils::parseStringArray(detailsObject["correspSoundsList"])[index]; SoundsRepo::playSound(pParseDelegate->getDefaultSoundsPath() + destObjSoundPath); if(JSONParseUtils::hasMemberBool(detailsObject, "determineConditionedCompletingActions")){// && //detailsObject["determineConditionedCompletingActions"].GetBool() == true){ indexForConditionedCompletingActions = index; } } else { destObject = ActionParser::getInstance().parseObject((*pJsonActionObject)["destinationObjectName"].GetString(), pParseDelegate); wrongDstObjects = ActionParser::getInstance().parseObjectOrObjects(*pJsonActionObject, "wrongDestinationObjectName", "wrongDestinationObjectNames", pParseDelegate); } auto dndHandler = new DragAndDropHandler(ActionParser::convertToNodeArray(objectsToDrag), ActionParser::convertToNode(destObject), ActionParser::convertToNodeArray(wrongDraggedObjects), ActionParser::convertToNodeArray(wrongDstObjects)); dndHandler->setObjectToDragExtendPercentValues(objectsToDragExtendPercentValues); if(JSONParseUtils::checkMemberBool(*pJsonActionObject, "moreAccurateDestinationCheck", true)){ dndHandler->setAccurateDestinationCheck(true); } else if(JSONParseUtils::checkMemberBool(*pJsonActionObject, "fingerOnlyDestinationCheck", true)){ dndHandler->setFingerOnlyDestinationCheck(true); } if(JSONParseUtils::hasMemberArray(*pJsonActionObject, "startDraggingCorrectObjectActions")){ dndHandler->_startDraggingCorrectObjectCallback = std::bind([&](cocos2d::Node* object, std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); ActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["startDraggingCorrectObjectActions"], p2ParseDelegate, false); }, std::placeholders::_1, pStoredValueKey, pParseDelegate); } // if(JSONParseUtils::hasMemberArray(*pJsonActionObject, "startDraggingConcreteObjectCallbacks")){ // // auto allCallbacks = (*pJsonActionObject)["startDraggingConcreteObjectCallbacks"].GetArray(); // // for(int i = 0; i < allCallbacks.Size(); ++i){ // // std::string objectName = allCallbacks[i]["objectName"].GetString(); // auto callback = std::bind([&](cocos2d::Node* wrongDraggedObject,std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ // auto p2JsonActionObject = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); // ActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["actions"], p2ParseDelegate, false); // }, std::placeholders::_1, pStoredValueKey, pParseDelegate); // dndHandler->_startDraggingConcreteObjectCallbacks.insert({objectName, callback}); // } // } std::function successCallback = std::bind([&](std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); ActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["rightActions"], p2ParseDelegate, false); },pStoredValueKey, pParseDelegate); if(JSONParseUtils::hasMemberArray(*pJsonActionObject, "rightActions")){ dndHandler->_successCallback = std::bind([&](cocos2d::Node* destinationObject, cocos2d::Node* rightObject, std::function pSuccessCallback){ if(rightObject){ pSuccessCallback(); } }, std::placeholders::_1, std::placeholders::_2, successCallback); } auto newTBH = dndHandler->prepareTouchBeganHandler(); auto newTMH = dndHandler->prepareTouchMovedHandler(); auto newTEH = dndHandler->prepareTouchEndedHandler(); static const std::string tbhKey = "dragNDropHandlerTBH"; static const std::string tmhKey = "dragNDropHandlerTMH"; static const std::string tehKey = "dragNDropHandlerTEH"; pParseDelegate->newTouchHandler(tbhKey, newTBH, TOUCHES_BEGAN); pParseDelegate->newTouchHandler(tmhKey, newTMH, TOUCHES_MOVED); pParseDelegate->newTouchHandler(tehKey, newTEH, TOUCHES_ENDED); std::function finalSuccessCallback = std::bind([&](cocos2d::Node* destinationObject, cocos2d::Node* rightObject, std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate, bool p2NotifyDelegate, DragAndDropHandler* pDndHandler){ auto p2JsonActionObject = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); p2ParseDelegate->removeTouchHandler(tbhKey, TOUCHES_BEGAN); p2ParseDelegate->removeTouchHandler(tmhKey, TOUCHES_MOVED); //TODO what about static strings? it's probably ok... p2ParseDelegate->removeTouchHandler(tehKey, TOUCHES_ENDED); p2ParseDelegate->cancelAllCompletingActions(); if(p2NotifyDelegate){ p2ParseDelegate->actionFinished(*p2JsonActionObject); } delete pDndHandler; ValueStorage::getInstance().removeStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); }, std::placeholders::_1, std::placeholders::_2, pStoredValueKey, pParseDelegate, pNotifyDelegate, dndHandler); if(JSONParseUtils::checkMemberBool(*pJsonActionObject, "requireFullDestinationColourIn", true)){ dndHandler->_allowMultipleDrag = true; auto dstObjAsColourableSprite = dynamic_cast(destObject); std::function callbackToStore = std::bind(finalSuccessCallback, nullptr, nullptr); auto storedCallbackKey = ValueStorage::getInstance().storeFunction(callbackToStore, pParseDelegate->getValueStorageContainerName()); dstObjAsColourableSprite->_autofillCallback = std::bind([&](DragAndDropHandler* pDndHandler, std::string pStoredCallbackKey, ActionParseDelegate* p2ParseDelegate){ pDndHandler->draggedObjectMoveBack(false); ValueStorage::getInstance().runAndRemoveStoredFunction(pStoredCallbackKey, p2ParseDelegate->getValueStorageContainerName()); }, dndHandler, storedCallbackKey, pParseDelegate); } else { dndHandler->_finalSuccessCallback = finalSuccessCallback; } if(JSONParseUtils::checkMemberBool(*pJsonActionObject, "wrongDraggedObjectAllowDrag", true)){ dndHandler->_allowDraggingWrongObjects = true; } if(JSONParseUtils::hasMemberArray(*pJsonActionObject, "wrongDraggedObjectActions")){ auto wrongObjectCallback = std::bind([&](cocos2d::Node* wrongDraggedObject,std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); ActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["wrongDraggedObjectActions"], p2ParseDelegate, false); }, std::placeholders::_1, pStoredValueKey, pParseDelegate); if(dndHandler->_allowDraggingWrongObjects){ dndHandler->_draggedWrongObjectCallback = wrongObjectCallback; } else { dndHandler->_startDraggingWrongObjectCallback = wrongObjectCallback; } } if(JSONParseUtils::hasMemberArray(*pJsonActionObject, "wrongDestinationObjectActions")){ dndHandler->_wrongDestinationObjectCallback = std::bind([&](cocos2d::Node* wrongDestObject,std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); ActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["wrongDestinationObjectActions"], p2ParseDelegate, false); }, std::placeholders::_1, pStoredValueKey, pParseDelegate); } if(JSONParseUtils::hasMemberArray(*pJsonActionObject, "draggedObjectEnterCorrectDestinationActions")){ dndHandler->_draggedObjectEnterCorrectDestinationCallback = std::bind([&](cocos2d::Node* draggedObject, cocos2d::Node* destinationObject,std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); ActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["draggedObjectEnterCorrectDestinationActions"], p2ParseDelegate, false); }, std::placeholders::_1, std::placeholders::_2, pStoredValueKey, pParseDelegate); } if(JSONParseUtils::hasMemberArray(*pJsonActionObject, "draggedObjectEnterWrongDestinationActions")){ dndHandler->_draggedObjectEnterWrongDestinationCallback = std::bind([&](cocos2d::Node* draggedObject, cocos2d::Node* destinationObject,std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); ActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["draggedObjectEnterWrongDestinationActions"], p2ParseDelegate, false); }, std::placeholders::_1, std::placeholders::_2, pStoredValueKey, pParseDelegate); } if(JSONParseUtils::hasMemberArray(*pJsonActionObject, "dropTooSoonActions")){ dndHandler->_dropTooSoonCallback = std::bind([&](std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); ActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["dropTooSoonActions"], p2ParseDelegate, false); }, pStoredValueKey, pParseDelegate); } auto destObjectAsLayoutObject = dynamic_cast(destObject); if(destObjectAsLayoutObject->className == "ChangingSprite"){ dndHandler->_objectDragNDropSuccessBehaviour = [&](cocos2d::Node* destinationObject, cocos2d::Node* draggedObject, cocos2d::Point startingObjectPosition){ draggedObject->setOpacity(0); dynamic_cast(destinationObject)->switchSprites(); }; } else if(destObjectAsLayoutObject->className == "ContainerSprite"){ dndHandler->_objectDragNDropSuccessBehaviour = [&](cocos2d::Node* destinationObject, cocos2d::Node* draggedObject, cocos2d::Point startingObjectPosition){ dynamic_cast(destinationObject)->addContentNode(draggedObject); }; } else if(destObjectAsLayoutObject->className == "ColourableSprite"){ if(JSONParseUtils::checkMemberBool(*pJsonActionObject, "requireFullDestinationColourIn", true)){ dndHandler->_objectDragNDropSuccessBehaviour = [&](cocos2d::Node* destinationObject, cocos2d::Node* draggedObject, cocos2d::Point startingObjectPosition){ dynamic_cast(destinationObject)->_colouringEnabled = false; }; } else { dndHandler->_objectDragNDropSuccessBehaviour = std::bind([&](cocos2d::Node* destinationObject, cocos2d::Node* draggedObject, cocos2d::Point startingObjectPosition, std::function pSuccessCallback){ auto dstColSprite = dynamic_cast(destinationObject); dstColSprite->_autofillCallback = pSuccessCallback; dstColSprite->startAutofillAnimation(); draggedObject->runAction(cocos2d::MoveTo::create(0.2, startingObjectPosition)); }, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, successCallback); } } else { dndHandler->_objectDragNDropSuccessBehaviour = std::bind([&](cocos2d::Node* destinationObject, cocos2d::Node* draggedObject, cocos2d::Point startingObjectPosition, std::string p2ValueStorageKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ValueStorage::getInstance().getStoredValue(p2ValueStorageKey, p2ParseDelegate->getValueStorageContainerName()); if(JSONParseUtils::checkMemberBool(*p2JsonActionObject, "draggedObjectShouldDisappear", true)){ draggedObject->setOpacity(0); } else { cocos2d::Point draggedObjectFinalPosition = cocos2d::Point(-1, -1); if(JSONParseUtils::hasMemberPoint(*p2JsonActionObject, "draggedObjectFinalPosition")){ draggedObjectFinalPosition = JSONParseUtils::getMemberPoint(*p2JsonActionObject, "draggedObjectFinalPosition"); } else if(JSONParseUtils::hasMemberString(*p2JsonActionObject, "draggedObjectFinalPosition")){ auto positionValue = ActionParser::getInstance().parseObject((*p2JsonActionObject)["draggedObjectFinalPosition"].GetString(), p2ParseDelegate); auto castPositionValue = dynamic_cast(positionValue); draggedObjectFinalPosition = castPositionValue->getPointValue(); } if(draggedObjectFinalPosition.x != -1){ draggedObject->runAction(cocos2d::MoveTo::create(0.2, draggedObjectFinalPosition)); } } }, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, pStoredValueKey, pParseDelegate); } this->runCompletingActions(*pJsonActionObject, pParseDelegate, indexForConditionedCompletingActions); }; auto notify = JSONParseUtils::checkMemberBool(jsonActionObject, "dontBlock", true); return ActionParser::getInstance().embedFunctionInAction(std::bind(actionFunction, storedValueKey, parseDelegate, notifyDelegateWhenFinished), jsonActionObject, parseDelegate, notify); } cocos2d::Action* BlockingActionParser::parseWaitForObjectUnlockAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { // if(jsonActionObject.objectName == null){ // log("BlockingActionParser: parseWaitForObjectUnlockAction: objectName must not be null."); // return null; // } auto unlockingObject = parseDelegate->getObjectByName(jsonActionObject["objectName"].GetString()); // if(unlockingObject == null){ // log("BlockingActionParser: parseWaitForObjectUnlockAction: no object with given objectName. Unlocking object must not be null."); // return null; // } std::function actionFunction = [&](){}; auto className = unlockingObject->getClassName(); if(className == "ColourableSprite"){ actionFunction = this->parseWaitForObjectUnlockActionFunction_ColourableSprite(dynamic_cast(unlockingObject), jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } // else { // log("BlockingActionParser: parseWaitForObjectUnlockAction: cannot determine object type. Unlocking object must have the classNAme specified."); // } auto notify = JSONParseUtils::checkMemberBool(jsonActionObject, "dontBlock", true); return ActionParser::getInstance().embedFunctionInAction(actionFunction, jsonActionObject, parseDelegate, notify); } std::function BlockingActionParser::parseWaitForObjectUnlockActionFunction_ColourableSprite(ColourableSprite* unlockingObject, const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate, ColourableSprite* pUnlockingObject){ auto storedValue = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); auto newTouchBeganHandler = std::bind([&](cocos2d::Touch* touch, cocos2d::Event* event, std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate, ColourableSprite* p2UnlockingObject){ auto storedValue2 = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); if(!GeometryUtils::getBoundingBoxToWorld(p2UnlockingObject).containsPoint(touch->getLocation())){ if(JSONParseUtils::hasMemberArray(*storedValue2, "wrongActions")){ auto wrongObjects = ActionParser::getInstance().parseObjectOrObjects(*storedValue2, "wrongObjectName", "wrongObjectNames", p2ParseDelegate); auto wrongNodes = ActionParser::getInstance().convertToNodeArray(wrongObjects); for(int j = 0; j < wrongNodes.size(); ++j){ if(GeometryUtils::getBoundingBoxToWorld(wrongNodes[j]).containsPoint(touch->getLocation())){ ActionParser::getInstance().parseAndRunActions((*storedValue2)["wrongActions"], p2ParseDelegate, false); break; } } } } else if(JSONParseUtils::hasMemberArray(*storedValue2, "rightActions")) { ActionParser::getInstance().parseAndRunActions((*storedValue2)["rightActions"], p2ParseDelegate, false); } return false; }, std::placeholders::_1, std::placeholders::_2, pStoredValueKey, pParseDelegate, pUnlockingObject); static const std::string nthKey = "waitForColourableSpriteTBH"; pParseDelegate->newTouchHandler(nthKey, newTouchBeganHandler, TOUCHES_BEGAN); pUnlockingObject->_autofillCallback = std::bind([&](std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate, bool p2NotifyDelegate){ auto storedValue2 = ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); p2ParseDelegate->removeTouchHandler(nthKey, TOUCHES_BEGAN); //TODO what about nth key? p2ParseDelegate->cancelAllCompletingActions(); if(p2NotifyDelegate){ p2ParseDelegate->actionFinished(*storedValue2); } ValueStorage::getInstance().removeStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); }, pStoredValueKey, pParseDelegate, pNotifyDelegate); this->runCompletingActions(*storedValue, pParseDelegate); }; return std::bind(actionFunction, storedValueKey, parseDelegate, notifyDelegateWhenFinished, unlockingObject); } // helper functions //TODO descriptions void BlockingActionParser::runCompletingActions(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, int indexForConditionedActions) { if(JSONParseUtils::hasMemberArray(jsonActionObject, "completingActions")){ auto randomTagBase = MathUtils::getRandomInt(0,10000); const auto& array = jsonActionObject["completingActions"]; for(int i = 0; i < array.Size(); ++i){ auto action = ActionParser::getInstance().parseJSONAction(array[i], parseDelegate, false); if(action){ action->setTag(randomTagBase+i); parseDelegate->runCompletingAction(action); } } } else if(JSONParseUtils::hasMemberArray(jsonActionObject, "conditionedCompletingActions")){ auto randomTagBase = MathUtils::getRandomInt(0,10000); const auto& array = jsonActionObject["conditionedCompletingActions"].GetArray()[indexForConditionedActions]; for(int i = 0; i < array.Size(); ++i){ auto action = ActionParser::getInstance().parseJSONAction(array[i], parseDelegate, false); if(action){ action->setTag(randomTagBase+i); parseDelegate->runCompletingAction(action); } } } }