// // ToyBlockingActionParser.cpp // SteveMaggieCpp // // Created by Katarzyna Kalinowska-Górska on 31.05.2017. // // #include #include "ToyBlockingActionParser.h" #include "ToyJSONParseUtils.h" #include "TouchHandlerTypes.h" #include "ToyGeometryUtils.h" #include "ToyDragAndDropHandler.h" #include "ToySimpleValue.h" #include "ToyChangingSprite.h" #include "ToyLayoutObject.h" #include "ToySimpleValue.h" #include "ToyMathUtils.h" #include "ToyValueStorage.h" #include "ToyPaletteNode.h" #include "ToyContainerSprite.h" #include "ToySoundsRepo.h" // main parse function cocos2d::Action* ToyBlockingActionParser::parseJSONAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { cocos2d::Action* parsedAction = NULL; auto blocking = ToyJSONParseUtils::checkMemberBool(jsonActionObject, "dontBlock", true); if(!blocking){ notifyDelegateWhenFinished = true; } // log("ToyBlockingActionParser: parsing action of type "+jsonActionObject.actionType); if(ToyJSONParseUtils::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* ToyBlockingActionParser::parseCallFunctionWithBlockingAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate){ auto storedValue = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); if(ToyActionParser::getInstance().checkLateCondition(*storedValue, pParseDelegate) == false){ return; } auto object = ToyActionParser::getInstance().prepareObjectsForAction(*storedValue, pParseDelegate)[0]; auto callback = [&](std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate, bool p2NotifyDelegate){ auto storedValue2 = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); if(p2NotifyDelegate){ p2ParseDelegate->actionFinished(*storedValue2); } ToyValueStorage::getInstance().removeStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); }; const rapidjson::Value* params = NULL; if(ToyJSONParseUtils::hasMemberArray(*storedValue, "parameters")){ params = &((*storedValue)["parameters"]); } object->callFunctionByName((*storedValue)["functionName"].GetString(), params, pParseDelegate, std::bind(callback, pStoredValueKey, pParseDelegate, pNotifyDelegate)); }; return ToyActionParser::getInstance().embedFunctionInAction(std::bind(actionFunction, storedValueKey, parseDelegate, notifyDelegateWhenFinished), jsonActionObject, parseDelegate, false); } // functions for parsing differenct actions cocos2d::Action* ToyBlockingActionParser::parseWaitForTouchAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { static const std::string TouchHandlerFunctionKey = "WaitForTouchActionTouchesBeganHandler"; auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate){ auto storedValue = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); TouchHandlerFunction newTouchBeganHandler = std::bind([&](cocos2d::Touch* touch, cocos2d::Event* event, std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate, bool p2NotifyDelegate){ auto storedValue2 = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); auto objectsToTouch = ToyActionParser::getInstance().parseObjectOrObjects(*storedValue2, "rightObjectName", "rightObjectNames", p2ParseDelegate); auto wrongObjects = ToyActionParser::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 = ToyValueStorage::getInstance().getStoredToySimpleValue(SubContainer+objectToTouch->getObjectName(), p2ParseDelegate->getToyValueStorageContainerName()); if(!touchedPtr){ ToySimpleValue temp{false}; touchedPtr = &temp; ToyValueStorage::getInstance().storeToySimpleValueWithKey(touchedPtr, SubContainer+objectToTouch->getObjectName(), p2ParseDelegate->getToyValueStorageContainerName()); } if(!touchedPtr->getBoolValue() && ToyGeometryUtils::getBoundingBoxToWorld(objAsNode).containsPoint(touch->getLocation())){ if(ToyJSONParseUtils::hasMemberArray(*storedValue2, "rightActions")){ ToyActionParser::getInstance().parseAndRunActions((*storedValue2)["rightActions"], p2ParseDelegate, false); } if(ToyJSONParseUtils::hasMemberArray(*storedValue2, "rightActionsForObjects")){ ToyActionParser::getInstance().parseAndRunActions((*storedValue2)["rightActionsForObjects"].GetArray()[i], p2ParseDelegate, false); } touchedPtr->setBoolValue(true); if(++touchedObjectsCount == objectsToTouch.size()){ if(ToyJSONParseUtils::checkMemberBool(*storedValue2, "dontBlock", false)){ p2ParseDelegate->removeTouchHandler(TouchHandlerFunctionKey, TOUCHES_BEGAN); p2ParseDelegate->cancelAllCompletingActions(); if(p2NotifyDelegate){ p2ParseDelegate->actionFinished(*storedValue2); } ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); ToyValueStorage::getInstance().clearStoredData(p2ParseDelegate->getToyValueStorageContainerName()); } else { //to enable picking the objects again touchedObjectsCount = 0; for(auto object : objectsToTouch){ ToySimpleValue* touchedPtr2 = ToyValueStorage::getInstance().getStoredToySimpleValue(SubContainer + object->getObjectName(), p2ParseDelegate->getToyValueStorageContainerName()); if(touchedPtr2){ touchedPtr2->setBoolValue(false); } else { ToySimpleValue temp2{false}; ToyValueStorage::getInstance().storeToySimpleValueWithKey(&temp2, SubContainer + objectToTouch->getObjectName(), p2ParseDelegate->getToyValueStorageContainerName()); } } } } return true; } } if(ToyJSONParseUtils::hasMemberArray(*storedValue2, "wrongActions")){ for(auto wrongObject : wrongObjects){ auto objAsNode = dynamic_cast(wrongObject); if(ToyGeometryUtils::getBoundingBoxToWorld(objAsNode).containsPoint(touch->getLocation())){ ToyActionParser::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 = ToyJSONParseUtils::checkMemberBool(jsonActionObject, "dontBlock", true); return ToyActionParser::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* ToyBlockingActionParser::parseWaitForPaletteComponentAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate){ auto storedValue = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); auto objectsToTouch = ToyActionParser::getInstance().parseObjectOrObjects(*storedValue, "rightObjectName", "rightObjectNames", pParseDelegate); auto paletteNode = dynamic_cast(dynamic_cast(objectsToTouch[0])->getParent()); std::function callback = std::bind([&](ToyPaletteNode * pToyPaletteNode, ToyPaletteComponentSprite * paletteComponentSprite, bool chosen, bool pressed, std::string pStoredValueKey2, ActionParseDelegate* pParseDelegate2, bool pNotifyDelegate2){ if(pressed){ bool wasRightObject = false; auto storedValue2 = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey2, pParseDelegate2->getToyValueStorageContainerName()); auto rightObjects = ToyActionParser::getInstance().parseObjectOrObjects(*storedValue2, "rightObjectName", "rightObjectNames", pParseDelegate2); for(ToyScenarioObject* rightObject : rightObjects){ ToyPaletteComponentSprite* rightToyPaletteComponentSprite = dynamic_cast(rightObject); if(paletteComponentSprite->objectName == rightToyPaletteComponentSprite->objectName){ if(ToyJSONParseUtils::hasMemberArray(*storedValue2, "rightActions")){ ToyActionParser::getInstance().parseAndRunActions((*storedValue2)["rightActions"], pParseDelegate2, false); } wasRightObject = true; if(ToyJSONParseUtils::checkMemberBool(*storedValue2, "dontBlock", false)){ pToyPaletteNode->setOnPaletteStateChangedCallback([](ToyPaletteNode*, ToyPaletteComponentSprite*, bool, bool){}); pParseDelegate2->cancelAllCompletingActions(); if(pNotifyDelegate2){ pParseDelegate2->actionFinished(*storedValue2); } ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey2, pParseDelegate2->getToyValueStorageContainerName()); } break; } } if(!wasRightObject && ToyJSONParseUtils::hasMemberArray(*storedValue2, "wrongActions")){ auto wrongObjects = ToyActionParser::getInstance().parseObjectOrObjects(*storedValue2, "wrongObjectName", "wrongObjectNames", pParseDelegate2); for(auto wrongObject : wrongObjects){ auto wrongToyPaletteComponentSprite = dynamic_cast(wrongObject); if(paletteComponentSprite->objectName == wrongToyPaletteComponentSprite->objectName){ ToyActionParser::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 = ToyJSONParseUtils::checkMemberBool(jsonActionObject, "dontBlock", true); return ToyActionParser::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* ToyBlockingActionParser::parseWaitForDragAndDropAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate){ auto pJsonActionObject = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); auto objectsToDrag = ToyActionParser::getInstance().parseObjectOrObjects(*pJsonActionObject, "draggedObjectName", "draggedObjectNames", pParseDelegate); auto extendPercent = 0; if(ToyJSONParseUtils::hasMemberFloat(*pJsonActionObject, "draggedObjectGrabAreaExtendByPercent")){ extendPercent = (*pJsonActionObject)["draggedObjectGrabAreaExtendByPercent"].GetFloat(); } auto objectsToDragExtendPercentValues = std::vector(objectsToDrag.size(), extendPercent); std::vector wrongDraggedObjects = ToyActionParser::getInstance().parseObjectOrObjects(*pJsonActionObject, "wrongDraggedObjectName", "wrongDraggedObjectNames", pParseDelegate); ToyScenarioObject* destObject = nullptr; std::vector wrongDstObjects; int indexForConditionedCompletingActions = 0; if(ToyJSONParseUtils::hasMemberObject(*pJsonActionObject, "randomDestinationObjectNameFrom")){ auto detailsObject = (*pJsonActionObject)["randomDestinationObjectNameFrom"].GetObject(); auto allDstObjects = ToyActionParser::getInstance().parseObjects(detailsObject["namesList"], pParseDelegate); int index = -1; while(destObject == nullptr){ index = ToyMathUtils::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 = ToyJSONParseUtils::parseStringArray(detailsObject["correspSoundsList"])[index]; ToySoundsRepo::playSound(pParseDelegate->getDefaultSoundsPath() + destObjSoundPath); if(ToyJSONParseUtils::hasMemberBool(detailsObject, "determineConditionedCompletingActions")){// && //detailsObject["determineConditionedCompletingActions"].GetBool() == true){ indexForConditionedCompletingActions = index; } } else { destObject = ToyActionParser::getInstance().parseObject((*pJsonActionObject)["destinationObjectName"].GetString(), pParseDelegate); wrongDstObjects = ToyActionParser::getInstance().parseObjectOrObjects(*pJsonActionObject, "wrongDestinationObjectName", "wrongDestinationObjectNames", pParseDelegate); } auto dndHandler = new ToyDragAndDropHandler(ToyActionParser::convertToNodeArray(objectsToDrag), ToyActionParser::convertToNode(destObject), ToyActionParser::convertToNodeArray(wrongDraggedObjects), ToyActionParser::convertToNodeArray(wrongDstObjects)); dndHandler->setObjectToDragExtendPercentValues(objectsToDragExtendPercentValues); if(ToyJSONParseUtils::checkMemberBool(*pJsonActionObject, "moreAccurateDestinationCheck", true)){ dndHandler->setAccurateDestinationCheck(true); } else if(ToyJSONParseUtils::checkMemberBool(*pJsonActionObject, "fingerOnlyDestinationCheck", true)){ dndHandler->setFingerOnlyDestinationCheck(true); } if(ToyJSONParseUtils::hasMemberArray(*pJsonActionObject, "startDraggingCorrectObjectActions")){ dndHandler->_startDraggingCorrectObjectCallback = std::bind([&](cocos2d::Node* object, std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); ToyActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["startDraggingCorrectObjectActions"], p2ParseDelegate, false); }, std::placeholders::_1, pStoredValueKey, pParseDelegate); } // if(ToyJSONParseUtils::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 = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); // ToyActionParser::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 = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); ToyActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["rightActions"], p2ParseDelegate, false); },pStoredValueKey, pParseDelegate); if(ToyJSONParseUtils::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, ToyDragAndDropHandler* pDndHandler){ auto p2JsonActionObject = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); 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; ToyValueStorage::getInstance().removeStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); }, std::placeholders::_1, std::placeholders::_2, pStoredValueKey, pParseDelegate, pNotifyDelegate, dndHandler); if(ToyJSONParseUtils::checkMemberBool(*pJsonActionObject, "requireFullDestinationColourIn", true)){ dndHandler->_allowMultipleDrag = true; auto dstObjAsToyColourableSprite = dynamic_cast(destObject); std::function callbackToStore = std::bind(finalSuccessCallback, nullptr, nullptr); auto storedCallbackKey = ToyValueStorage::getInstance().storeFunction(callbackToStore, pParseDelegate->getToyValueStorageContainerName()); dstObjAsToyColourableSprite->_autofillCallback = std::bind([&](ToyDragAndDropHandler* pDndHandler, std::string pStoredCallbackKey, ActionParseDelegate* p2ParseDelegate){ pDndHandler->draggedObjectMoveBack(false); ToyValueStorage::getInstance().runAndRemoveStoredFunction(pStoredCallbackKey, p2ParseDelegate->getToyValueStorageContainerName()); }, dndHandler, storedCallbackKey, pParseDelegate); } else { dndHandler->_finalSuccessCallback = finalSuccessCallback; } if(ToyJSONParseUtils::checkMemberBool(*pJsonActionObject, "wrongDraggedObjectAllowDrag", true)){ dndHandler->_allowDraggingWrongObjects = true; } if(ToyJSONParseUtils::hasMemberArray(*pJsonActionObject, "wrongDraggedObjectActions")){ auto wrongObjectCallback = std::bind([&](cocos2d::Node* wrongDraggedObject,std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); ToyActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["wrongDraggedObjectActions"], p2ParseDelegate, false); }, std::placeholders::_1, pStoredValueKey, pParseDelegate); if(dndHandler->_allowDraggingWrongObjects){ dndHandler->_draggedWrongObjectCallback = wrongObjectCallback; } else { dndHandler->_startDraggingWrongObjectCallback = wrongObjectCallback; } } if(ToyJSONParseUtils::hasMemberArray(*pJsonActionObject, "wrongDestinationObjectActions")){ dndHandler->_wrongDestinationObjectCallback = std::bind([&](cocos2d::Node* wrongDestObject,std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); ToyActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["wrongDestinationObjectActions"], p2ParseDelegate, false); }, std::placeholders::_1, pStoredValueKey, pParseDelegate); } if(ToyJSONParseUtils::hasMemberArray(*pJsonActionObject, "draggedObjectEnterCorrectDestinationActions")){ dndHandler->_draggedObjectEnterCorrectDestinationCallback = std::bind([&](cocos2d::Node* draggedObject, cocos2d::Node* destinationObject,std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); ToyActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["draggedObjectEnterCorrectDestinationActions"], p2ParseDelegate, false); }, std::placeholders::_1, std::placeholders::_2, pStoredValueKey, pParseDelegate); } if(ToyJSONParseUtils::hasMemberArray(*pJsonActionObject, "draggedObjectEnterWrongDestinationActions")){ dndHandler->_draggedObjectEnterWrongDestinationCallback = std::bind([&](cocos2d::Node* draggedObject, cocos2d::Node* destinationObject,std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); ToyActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["draggedObjectEnterWrongDestinationActions"], p2ParseDelegate, false); }, std::placeholders::_1, std::placeholders::_2, pStoredValueKey, pParseDelegate); } if(ToyJSONParseUtils::hasMemberArray(*pJsonActionObject, "dropTooSoonActions")){ dndHandler->_dropTooSoonCallback = std::bind([&](std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); ToyActionParser::getInstance().parseAndRunActions((*p2JsonActionObject)["dropTooSoonActions"], p2ParseDelegate, false); }, pStoredValueKey, pParseDelegate); } auto destObjectAsToyLayoutObject = dynamic_cast(destObject); if(destObjectAsToyLayoutObject->className == "ChangingSprite"){ dndHandler->_objectDragNDropSuccessBehaviour = [&](cocos2d::Node* destinationObject, cocos2d::Node* draggedObject, cocos2d::Point startingObjectPosition){ draggedObject->setOpacity(0); dynamic_cast(destinationObject)->switchSprites(); }; } else if(destObjectAsToyLayoutObject->className == "ContainerSprite"){ dndHandler->_objectDragNDropSuccessBehaviour = [&](cocos2d::Node* destinationObject, cocos2d::Node* draggedObject, cocos2d::Point startingObjectPosition){ dynamic_cast(destinationObject)->addContentNode(draggedObject); }; } else if(destObjectAsToyLayoutObject->className == "ColourableSprite"){ if(ToyJSONParseUtils::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 p2ToyValueStorageKey, ActionParseDelegate* p2ParseDelegate){ auto p2JsonActionObject = ToyValueStorage::getInstance().getStoredValue(p2ToyValueStorageKey, p2ParseDelegate->getToyValueStorageContainerName()); if(ToyJSONParseUtils::checkMemberBool(*p2JsonActionObject, "draggedObjectShouldDisappear", true)){ draggedObject->setOpacity(0); } else { cocos2d::Point draggedObjectFinalPosition = cocos2d::Point(-1, -1); if(ToyJSONParseUtils::hasMemberPoint(*p2JsonActionObject, "draggedObjectFinalPosition")){ draggedObjectFinalPosition = ToyJSONParseUtils::getMemberPoint(*p2JsonActionObject, "draggedObjectFinalPosition"); } else if(ToyJSONParseUtils::hasMemberString(*p2JsonActionObject, "draggedObjectFinalPosition")){ auto positionValue = ToyActionParser::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 = ToyJSONParseUtils::checkMemberBool(jsonActionObject, "dontBlock", true); return ToyActionParser::getInstance().embedFunctionInAction(std::bind(actionFunction, storedValueKey, parseDelegate, notifyDelegateWhenFinished), jsonActionObject, parseDelegate, notify); } cocos2d::Action* ToyBlockingActionParser::parseWaitForObjectUnlockAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { // if(jsonActionObject.objectName == null){ // log("ToyBlockingActionParser: parseWaitForObjectUnlockAction: objectName must not be null."); // return null; // } auto unlockingObject = parseDelegate->getObjectByName(jsonActionObject["objectName"].GetString()); // if(unlockingObject == null){ // log("ToyBlockingActionParser: 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_ToyColourableSprite(dynamic_cast(unlockingObject), jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } // else { // log("ToyBlockingActionParser: parseWaitForObjectUnlockAction: cannot determine object type. Unlocking object must have the classNAme specified."); // } auto notify = ToyJSONParseUtils::checkMemberBool(jsonActionObject, "dontBlock", true); return ToyActionParser::getInstance().embedFunctionInAction(actionFunction, jsonActionObject, parseDelegate, notify); } std::function ToyBlockingActionParser::parseWaitForObjectUnlockActionFunction_ToyColourableSprite(ToyColourableSprite* unlockingObject, const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate, ToyColourableSprite* pUnlockingObject){ auto storedValue = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); auto newTouchBeganHandler = std::bind([&](cocos2d::Touch* touch, cocos2d::Event* event, std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate, ToyColourableSprite* p2UnlockingObject){ auto storedValue2 = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); if(!ToyGeometryUtils::getBoundingBoxToWorld(p2UnlockingObject).containsPoint(touch->getLocation())){ if(ToyJSONParseUtils::hasMemberArray(*storedValue2, "wrongActions")){ auto wrongObjects = ToyActionParser::getInstance().parseObjectOrObjects(*storedValue2, "wrongObjectName", "wrongObjectNames", p2ParseDelegate); auto wrongNodes = ToyActionParser::getInstance().convertToNodeArray(wrongObjects); for(int j = 0; j < wrongNodes.size(); ++j){ if(ToyGeometryUtils::getBoundingBoxToWorld(wrongNodes[j]).containsPoint(touch->getLocation())){ ToyActionParser::getInstance().parseAndRunActions((*storedValue2)["wrongActions"], p2ParseDelegate, false); break; } } } } else if(ToyJSONParseUtils::hasMemberArray(*storedValue2, "rightActions")) { ToyActionParser::getInstance().parseAndRunActions((*storedValue2)["rightActions"], p2ParseDelegate, false); } return false; }, std::placeholders::_1, std::placeholders::_2, pStoredValueKey, pParseDelegate, pUnlockingObject); static const std::string nthKey = "waitForToyColourableSpriteTBH"; pParseDelegate->newTouchHandler(nthKey, newTouchBeganHandler, TOUCHES_BEGAN); pUnlockingObject->_autofillCallback = std::bind([&](std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate, bool p2NotifyDelegate){ auto storedValue2 = ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); p2ParseDelegate->removeTouchHandler(nthKey, TOUCHES_BEGAN); //TODO what about nth key? p2ParseDelegate->cancelAllCompletingActions(); if(p2NotifyDelegate){ p2ParseDelegate->actionFinished(*storedValue2); } ToyValueStorage::getInstance().removeStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); }, pStoredValueKey, pParseDelegate, pNotifyDelegate); this->runCompletingActions(*storedValue, pParseDelegate); }; return std::bind(actionFunction, storedValueKey, parseDelegate, notifyDelegateWhenFinished, unlockingObject); } // helper functions //TODO descriptions void ToyBlockingActionParser::runCompletingActions(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, int indexForConditionedActions) { if(ToyJSONParseUtils::hasMemberArray(jsonActionObject, "completingActions")){ auto randomTagBase = ToyMathUtils::getRandomInt(0,10000); const auto& array = jsonActionObject["completingActions"]; for(int i = 0; i < array.Size(); ++i){ auto action = ToyActionParser::getInstance().parseJSONAction(array[i], parseDelegate, false); if(action){ action->setTag(randomTagBase+i); parseDelegate->runCompletingAction(action); } } } else if(ToyJSONParseUtils::hasMemberArray(jsonActionObject, "conditionedCompletingActions")){ auto randomTagBase = ToyMathUtils::getRandomInt(0,10000); const auto& array = jsonActionObject["conditionedCompletingActions"].GetArray()[indexForConditionedActions]; for(int i = 0; i < array.Size(); ++i){ auto action = ToyActionParser::getInstance().parseJSONAction(array[i], parseDelegate, false); if(action){ action->setTag(randomTagBase+i); parseDelegate->runCompletingAction(action); } } } }