/* * Catroid: An on-device visual programming system for Android devices * Copyright (C) 2010-2016 The Catrobat Team * (<http://developer.catrobat.org/credits>) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * An additional term exception under section 7 of the GNU Affero * General Public License, version 3, is available at * http://developer.catrobat.org/license_additional_term * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.catrobat.catroid.content; import android.content.Context; import android.graphics.PointF; import android.util.Log; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.scenes.scene2d.Action; import com.badlogic.gdx.scenes.scene2d.actions.ParallelAction; import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import org.catrobat.catroid.CatroidApplication; import org.catrobat.catroid.ProjectManager; import org.catrobat.catroid.common.BrickValues; import org.catrobat.catroid.common.BroadcastSequenceMap; import org.catrobat.catroid.common.Constants; import org.catrobat.catroid.common.LookData; import org.catrobat.catroid.common.NfcTagData; import org.catrobat.catroid.common.SoundInfo; import org.catrobat.catroid.content.bricks.Brick; import org.catrobat.catroid.content.bricks.FormulaBrick; import org.catrobat.catroid.content.bricks.PlaySoundBrick; import org.catrobat.catroid.content.bricks.UserBrick; import org.catrobat.catroid.content.bricks.UserScriptDefinitionBrick; import org.catrobat.catroid.content.bricks.UserVariableBrick; import org.catrobat.catroid.content.bricks.WhenConditionBrick; import org.catrobat.catroid.formulaeditor.DataContainer; import org.catrobat.catroid.formulaeditor.Formula; import org.catrobat.catroid.formulaeditor.InterpretationException; import org.catrobat.catroid.formulaeditor.UserList; import org.catrobat.catroid.formulaeditor.UserVariable; import org.catrobat.catroid.io.XStreamFieldKeyOrder; import org.catrobat.catroid.physics.PhysicsLook; import org.catrobat.catroid.physics.PhysicsWorld; import org.catrobat.catroid.stage.StageActivity; import org.catrobat.catroid.ui.fragment.SpriteFactory; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; // Remove checkstyle disable when https://github.com/checkstyle/checkstyle/issues/1349 is fixed // CHECKSTYLE DISABLE IndentationCheck FOR 8 LINES @XStreamFieldKeyOrder({ "name", "lookList", "soundList", "scriptList", "userBricks", "nfcTagList" }) public class Sprite implements Serializable, Cloneable { private static final long serialVersionUID = 1L; private static final String TAG = Sprite.class.getSimpleName(); private static SpriteFactory spriteFactory = new SpriteFactory(); public transient Look look = new Look(this); public transient boolean isBackpackObject = false; public transient PenConfiguration penConfiguration = new PenConfiguration(); private transient boolean convertToSingleSprite = false; private transient boolean convertToGroupItemSprite = false; @XStreamAsAttribute private String name; private List<Script> scriptList = new ArrayList<>(); private List<LookData> lookList = new ArrayList<>(); private List<SoundInfo> soundList = new ArrayList<>(); private List<UserBrick> userBricks = new ArrayList<>(); private List<NfcTagData> nfcTagList = new ArrayList<>(); private transient ActionFactory actionFactory = new ActionFactory(); public transient boolean isClone = false; private transient boolean isMobile = false; public Sprite(String name) { this.name = name; } public Sprite() { } @Override public boolean equals(Object obj) { if (!(obj instanceof Sprite)) { return false; } if (obj == this) { return true; } Sprite sprite = (Sprite) obj; return sprite.name.equals(this.name); } @Override public int hashCode() { return super.hashCode() * TAG.hashCode(); } public List<Script> getScriptList() { return scriptList; } public List<Brick> getListWithAllBricks() { List<Brick> allBricks = new ArrayList<>(); for (Script script : scriptList) { allBricks.add(script.getScriptBrick()); allBricks.addAll(script.getBrickList()); } for (UserBrick userBrick : userBricks) { allBricks.add(userBrick); Script userScript = userBrick.getDefinitionBrick().getUserScript(); if (userScript != null) { allBricks.addAll(userScript.getBrickList()); } } return allBricks; } public List<Brick> getAllBricks() { List<Brick> result = new ArrayList<>(); for (Script script : scriptList) { for (Brick brick : script.getBrickList()) { result.add(brick); } } for (UserBrick userBrick : userBricks) { result.add(userBrick); Script userScript = userBrick.getDefinitionBrick().getUserScript(); for (Brick brick : userScript.getBrickList()) { result.add(brick); } } return result; } public List<PlaySoundBrick> getPlaySoundBricks() { List<PlaySoundBrick> result = new ArrayList<>(); for (Brick brick : getAllBricks()) { if (brick instanceof PlaySoundBrick) { result.add((PlaySoundBrick) brick); } } return result; } public void resetSprite() { if ((getRequiredResources() & Brick.PHYSICS) > 0) { PhysicsWorld physicsWorld = ProjectManager.getInstance().getSceneToPlay().getPhysicsWorld(); look = new PhysicsLook(this, physicsWorld); } else { look = new Look(this); } for (LookData lookData : lookList) { lookData.resetLookData(); } penConfiguration = new PenConfiguration(); } public void removeUserBrick(UserBrick brickToRemove) { for (UserBrick userBrick : userBricks) { userBrick.getDefinitionBrick().getUserScript().removeInstancesOfUserBrick(brickToRemove); } for (Script script : scriptList) { script.removeInstancesOfUserBrick(brickToRemove); } userBricks.remove(brickToRemove); } public UserBrick addUserBrick(UserBrick brick) { if (userBricks == null) { userBricks = new ArrayList<>(); } userBricks.add(brick); return brick; } public List<UserBrick> getUserBrickList() { if (userBricks == null) { userBricks = new ArrayList<>(); } return userBricks; } public List<UserBrick> getUserBricksByDefinitionBrick(UserScriptDefinitionBrick definitionBrick, boolean scriptBricks, boolean prototypeBricks) { List<UserBrick> matchingUserBricks = new ArrayList<>(); if (scriptBricks) { for (Brick brick : getAllBricks()) { if (brick instanceof UserBrick) { UserBrick userBrick = (UserBrick) brick; if (userBrick.getDefinitionBrick().equals(definitionBrick)) { matchingUserBricks.add(userBrick); } } } } if (prototypeBricks) { for (UserBrick userBrick : userBricks) { if (userBrick.getDefinitionBrick().equals(definitionBrick)) { matchingUserBricks.add(userBrick); } } } return matchingUserBricks; } public void createStartScriptActionSequenceAndPutToMap(Map<String, List<String>> scriptActions) { for (int scriptCounter = 0; scriptCounter < scriptList.size(); scriptCounter++) { Script script = scriptList.get(scriptCounter); if (script instanceof StartScript && !isClone) { Action sequenceAction = createActionSequence(script); look.addAction(sequenceAction); BroadcastHandler.getActionScriptMap().put(sequenceAction, script); BroadcastHandler.getScriptSpriteMap().put(script, this); String actionName = sequenceAction.toString() + Constants.ACTION_SPRITE_SEPARATOR + name + scriptCounter; if (scriptActions.containsKey(Constants.START_SCRIPT)) { scriptActions.get(Constants.START_SCRIPT).add(actionName); BroadcastHandler.getStringActionMap().put(actionName, sequenceAction); } else { List<String> startScriptList = new ArrayList<>(); startScriptList.add(actionName); scriptActions.put(Constants.START_SCRIPT, startScriptList); BroadcastHandler.getStringActionMap().put(actionName, sequenceAction); } } else if (script instanceof BroadcastScript) { BroadcastScript broadcastScript = (BroadcastScript) script; SequenceAction action = createActionSequence(broadcastScript); BroadcastHandler.getActionScriptMap().put(action, script); BroadcastHandler.getScriptSpriteMap().put(script, this); putBroadcastSequenceAction(broadcastScript.getBroadcastMessage(), action); String actionName = action.toString() + Constants.ACTION_SPRITE_SEPARATOR + name + scriptCounter; if (scriptActions.containsKey(Constants.BROADCAST_SCRIPT)) { scriptActions.get(Constants.BROADCAST_SCRIPT).add(actionName); BroadcastHandler.getStringActionMap().put(actionName, action); } else { List<String> broadcastScriptList = new ArrayList<>(); broadcastScriptList.add(actionName); scriptActions.put(Constants.BROADCAST_SCRIPT, broadcastScriptList); BroadcastHandler.getStringActionMap().put(actionName, action); } } else if (script instanceof WhenConditionScript) { createWhenConditionBecomesTrueAction((WhenConditionScript) script); } } } private void createWhenConditionBecomesTrueAction(WhenConditionScript script) { ActionFactory actionFactory = getActionFactory(); Formula condition = ((WhenConditionBrick) script.getScriptBrick()).getConditionFormula(); Formula negatedCondition = new Formula(condition.getRoot().clone()) { @Override public Boolean interpretBoolean(Sprite sprite) throws InterpretationException { return !super.interpretBoolean(sprite); } }; Action waitAction = actionFactory.createWaitUntilAction(this, condition); Action waitActionNegated = actionFactory.createWaitUntilAction(this, negatedCondition); SequenceAction foreverSequence = ActionFactory.sequence(ActionFactory.sequence(waitAction, createActionSequence(script)), waitActionNegated); Action whenConditionBecomesTrueAction = actionFactory.createForeverAction(this, foreverSequence); look.addAction(whenConditionBecomesTrueAction); } private void putBroadcastSequenceAction(String broadcastMessage, SequenceAction action) { String sceneName = ProjectManager.getInstance().getSceneToPlay().getName(); if (BroadcastSequenceMap.containsKey(broadcastMessage, sceneName)) { BroadcastSequenceMap.get(broadcastMessage, sceneName).add(action); } else { ArrayList<SequenceAction> actionList = new ArrayList<>(); actionList.add(action); BroadcastSequenceMap.put(sceneName, broadcastMessage, actionList); } } public ActionFactory getActionFactory() { return actionFactory; } public void setActionFactory(ActionFactory actionFactory) { this.actionFactory = actionFactory; } @Override public Sprite clone() { final Sprite cloneSprite = createSpriteInstance(); cloneSprite.setName(this.getName()); cloneSprite.isBackpackObject = false; cloneSprite.convertToSingleSprite = false; cloneSprite.convertToGroupItemSprite = false; cloneSprite.isMobile = false; ProjectManager projectManager = ProjectManager.getInstance(); Scene currentScene = ProjectManager.getInstance().getCurrentScene(); if (currentScene == null) { throw new RuntimeException("Current scene was null, cannot clone Sprite."); } Sprite originalSprite = projectManager.getCurrentSprite(); projectManager.setCurrentSprite(cloneSprite); cloneSpriteVariables(currentScene, cloneSprite); cloneLooks(cloneSprite); cloneSounds(cloneSprite); cloneUserBricks(cloneSprite); cloneNfcTags(cloneSprite); cloneScripts(cloneSprite); cloneSprite.resetSprite(); cloneLook(cloneSprite); setUserAndVariableBrickReferences(cloneSprite, userBricks); projectManager.checkCurrentSprite(cloneSprite, false); projectManager.setCurrentSprite(originalSprite); return cloneSprite; } public Sprite cloneForCloneBrick() { final Sprite cloneSprite = new SpriteFactory().newInstance(SpriteFactory.SPRITE_SINGLE); cloneSprite.setName(this.getName() + "-c" + StageActivity.getAndIncrementNumberOfClonedSprites()); cloneSprite.isClone = true; cloneSprite.actionFactory = this.actionFactory; cloneSprite.soundList = this.soundList; cloneSprite.nfcTagList = this.nfcTagList; Sprite originalSprite = ProjectManager.getInstance().getCurrentSprite(); ProjectManager.getInstance().setCurrentSprite(cloneSprite); cloneLooks(cloneSprite); cloneUserBricks(cloneSprite); cloneSpriteVariables(ProjectManager.getInstance().getCurrentScene(), cloneSprite); cloneScripts(cloneSprite); cloneSprite.resetSprite(); cloneLook(cloneSprite); setUserAndVariableBrickReferences(cloneSprite, userBricks); ProjectManager.getInstance().setCurrentSprite(originalSprite); return cloneSprite; } public Sprite cloneForScene() { Sprite clone = clone(); return clone; } public Sprite shallowClone() { final Sprite cloneSprite = createSpriteInstance(); cloneSprite.setName(this.name); cloneSprite.isBackpackObject = false; cloneSprite.convertToSingleSprite = false; cloneSprite.convertToGroupItemSprite = false; cloneSprite.isMobile = this.isMobile; cloneSprite.look = this.look; cloneSprite.scriptList = this.scriptList; cloneSprite.lookList = this.lookList; cloneSprite.soundList = this.soundList; cloneSprite.userBricks = this.userBricks; cloneSprite.nfcTagList = this.nfcTagList; ProjectManager projectManager = ProjectManager.getInstance(); shallowCloneSpriteVariables(projectManager.getCurrentScene().getDataContainer(), cloneSprite); shallowCloneSpriteLists(projectManager.getCurrentScene().getDataContainer(), cloneSprite); if (projectManager.getCurrentSprite() != null && projectManager.getCurrentSprite().equals(this)) { projectManager.setCurrentSprite(cloneSprite); } return cloneSprite; } private void shallowCloneSpriteVariables(DataContainer dataContainer, Sprite cloneSprite) { List<UserVariable> originalSpriteVariables = dataContainer.getOrCreateVariableListForSprite(this); List<UserVariable> clonedSpriteVariables = dataContainer.getOrCreateVariableListForSprite(cloneSprite); for (UserVariable variable : originalSpriteVariables) { clonedSpriteVariables.add(variable); } dataContainer.cleanVariableListForSprite(this); } private void shallowCloneSpriteLists(DataContainer dataContainer, Sprite cloneSprite) { List<UserList> originalSpriteLists = dataContainer.getOrCreateUserListListForSprite(this); List<UserList> clonedSpriteLists = dataContainer.getOrCreateUserListListForSprite(cloneSprite); for (UserList list : originalSpriteLists) { clonedSpriteLists.add(list); } dataContainer.cleanUserListForSprite(this); } private Sprite createSpriteInstance() { Sprite cloneSprite; if (convertToSingleSprite) { cloneSprite = spriteFactory.newInstance(SpriteFactory.SPRITE_SINGLE); } else if (convertToGroupItemSprite) { cloneSprite = spriteFactory.newInstance(SpriteFactory.SPRITE_GROUP_ITEM); } else { cloneSprite = spriteFactory.newInstance(getClass().getSimpleName()); } return cloneSprite; } public void setUserAndVariableBrickReferences(Sprite cloneSprite, List<UserBrick> originalPrototypeUserBricks) { setDefinitionBrickReferences(cloneSprite, originalPrototypeUserBricks); setVariableReferencesOfClonedSprite(cloneSprite); } private void setDefinitionBrickReferences(Sprite cloneSprite, List<UserBrick> originalPrototypeUserBricks) { for (int scriptPosition = 0; scriptPosition < cloneSprite.getScriptList().size(); scriptPosition++) { Script clonedScript = cloneSprite.getScript(scriptPosition); for (int brickPosition = 0; brickPosition < clonedScript.getBrickList().size(); brickPosition++) { Brick clonedBrick = clonedScript.getBrick(brickPosition); if (!(clonedBrick instanceof UserBrick)) { continue; } UserBrick clonedUserBrick = ((UserBrick) clonedBrick); UserBrick originalUserBrick = ((UserBrick) getScript(scriptPosition).getBrick(brickPosition)); int originalIndexOfDefinitionBrick = 0; for (int prototypeUserBrickPosition = 0; prototypeUserBrickPosition < originalPrototypeUserBricks.size(); prototypeUserBrickPosition++) { UserBrick originalPrototypeUserBrick = originalPrototypeUserBricks.get(prototypeUserBrickPosition); if (originalPrototypeUserBrick.getDefinitionBrick().equals(originalUserBrick.getDefinitionBrick())) { originalIndexOfDefinitionBrick = prototypeUserBrickPosition; break; } } UserBrick clonedPrototypeUserBrick = cloneSprite.getUserBrickList().get(originalIndexOfDefinitionBrick); UserScriptDefinitionBrick correctClonedDefinitionBrick = clonedPrototypeUserBrick.getDefinitionBrick(); clonedUserBrick.setDefinitionBrick(correctClonedDefinitionBrick); clonedPrototypeUserBrick.updateUserBrickParametersAndVariables(); clonedUserBrick.updateUserBrickParametersAndVariables(); } } } private void setVariableReferencesOfClonedSprite(Sprite cloneSprite) { DataContainer dataContainer = ProjectManager.getInstance().getCurrentScene().getDataContainer(); List<UserVariable> clonedSpriteVariables = dataContainer.getOrCreateVariableListForSprite(cloneSprite); cloneSprite.updateUserVariableReferencesInUserVariableBricks(clonedSpriteVariables); List<UserVariable> clonedProjectVariables = dataContainer.getProjectVariables(); cloneSprite.updateUserVariableReferencesInUserVariableBricks(clonedProjectVariables); } private void cloneSpriteVariables(Scene currentScene, Sprite cloneSprite) { DataContainer userVariables = currentScene.getDataContainer(); List<UserVariable> originalSpriteVariables = userVariables.getOrCreateVariableListForSprite(this); List<UserVariable> clonedSpriteVariables = userVariables.getOrCreateVariableListForSprite(cloneSprite); for (UserVariable variable : originalSpriteVariables) { clonedSpriteVariables.add(new UserVariable(variable.getName(), variable.getValue())); } } private void cloneLook(Sprite cloneSprite) { int currentLookDataIndex = this.lookList.indexOf(this.look.getLookData()); if (currentLookDataIndex != -1) { cloneSprite.look.setLookData(cloneSprite.lookList.get(currentLookDataIndex)); } cloneSprite.look = this.look.copyLookForSprite(cloneSprite); } private void cloneLooks(Sprite cloneSprite) { List<LookData> cloneLookList = new ArrayList<>(); for (LookData element : this.lookList) { cloneLookList.add(element.clone()); } cloneSprite.lookList = cloneLookList; } private void cloneSounds(Sprite cloneSprite) { List<SoundInfo> cloneSoundList = new ArrayList<>(); for (SoundInfo element : this.soundList) { cloneSoundList.add(element.clone()); } cloneSprite.soundList = cloneSoundList; } private void cloneUserBricks(Sprite cloneSprite) { List<UserBrick> clonedUserBrickList = new ArrayList<>(); for (UserBrick original : userBricks) { ProjectManager.getInstance().checkCurrentScript(original.getDefinitionBrick().getScriptSafe(), false); UserBrick clonedUserBrick = original.copyBrickForSprite(cloneSprite); clonedUserBrickList.add(clonedUserBrick); clonedUserBrick.updateUserBrickParametersAndVariables(); } cloneSprite.userBricks = clonedUserBrickList; } private void cloneNfcTags(Sprite cloneSprite) { List<NfcTagData> cloneNfcTagList = new ArrayList<>(); for (NfcTagData element : this.nfcTagList) { cloneNfcTagList.add(element.clone()); } cloneSprite.nfcTagList = cloneNfcTagList; } private void cloneScripts(Sprite cloneSprite) { List<Script> cloneScriptList = new ArrayList<>(); for (Script element : this.scriptList) { Script addElement = element.copyScriptForSprite(cloneSprite); cloneScriptList.add(addElement); } cloneSprite.scriptList = cloneScriptList; } public Sprite cloneForBackPack() { final Sprite cloneSprite = spriteFactory.newInstance(SpriteFactory.SPRITE_SINGLE); cloneSprite.setName(name); return cloneSprite; } public void createWhenScriptActionSequence(String action) { ParallelAction whenParallelAction = actionFactory.parallel(); for (Script s : scriptList) { if (s instanceof WhenScript && (((WhenScript) s).getAction().equalsIgnoreCase(action))) { SequenceAction sequence = createActionSequence(s); whenParallelAction.addAction(sequence); } } look.setWhenParallelAction(whenParallelAction); look.addAction(whenParallelAction); } private SequenceAction createActionSequence(Script script) { SequenceAction sequence = ActionFactory.sequence(); script.run(this, sequence); return sequence; } public void createWhenNfcScriptAction(String uid) { ParallelAction whenParallelAction = ActionFactory.parallel(); for (Script s : scriptList) { if (s instanceof WhenNfcScript) { WhenNfcScript whenNfcScript = (WhenNfcScript) s; if (whenNfcScript.isMatchAll() || whenNfcScript.getNfcTag().getNfcTagUid().equals(uid)) { SequenceAction sequence = createActionSequence(s); whenParallelAction.addAction(sequence); } } } //TODO: quick fix for faulty behaviour - nfc action triggers again after touchevents //look.setWhenParallelAction(whenParallelAction); look.addAction(whenParallelAction); } public void createTouchDownAction() { ParallelAction whenParallelAction = ActionFactory.parallel(); for (Script s : scriptList) { if (s instanceof WhenTouchDownScript) { SequenceAction sequence = createActionSequence(s); whenParallelAction.addAction(sequence); } } look.addAction(whenParallelAction); } public ParallelAction createBackgroundChangedAction(LookData lookData) { ParallelAction whenParallelAction = ActionFactory.parallel(); for (Script s : scriptList) { if (s instanceof WhenBackgroundChangesScript && ((WhenBackgroundChangesScript) s).getLook().equals(lookData)) { SequenceAction sequence = createActionSequence(s); SequenceAction sequenceWithNotifyAtEnd = ActionFactory.sequence(sequence, ActionFactory.createBackgroundNotifyAction(lookData)); whenParallelAction.addAction(sequenceWithNotifyAtEnd); } } look.addAction(whenParallelAction); return whenParallelAction; } public int getNumberOfWhenBackgroundChangesScripts(LookData lookData) { int numberOfScripts = 0; for (Script s : scriptList) { if (s instanceof WhenBackgroundChangesScript && ((WhenBackgroundChangesScript) s).getLook().equals(lookData)) { numberOfScripts++; } } return numberOfScripts; } public void createWhenClonedAction() { ParallelAction whenParallelAction = ActionFactory.parallel(); for (Script s : scriptList) { if (s instanceof WhenClonedScript) { SequenceAction sequence = createActionSequence(s); whenParallelAction.addAction(sequence); } } look.addAction(whenParallelAction); } public String getName() { return name; } public void setName(String name) { this.name = name; } public void addScript(Script script) { if (script != null && !scriptList.contains(script)) { scriptList.add(script); } } public void addScript(int index, Script script) { if (script != null && !scriptList.contains(script)) { scriptList.add(index, script); } } public Script getScript(int index) { if (index < 0 || index >= scriptList.size()) { Log.e(TAG, "getScript() Index out of Scope! scriptList size: " + scriptList.size()); return null; } return scriptList.get(index); } public int getNumberOfScripts() { if (scriptList != null) { return scriptList.size(); } return 0; } public int getNumberOfBricks() { int brickCount = 0; for (Script s : scriptList) { brickCount += s.getBrickList().size(); } return brickCount; } public int getScriptIndex(Script script) { return scriptList.indexOf(script); } public void removeAllScripts() { scriptList.clear(); } public boolean removeScript(Script script) { return scriptList.remove(script); } public List<LookData> getLookDataList() { return lookList; } public void setLookDataList(List<LookData> list) { lookList = list; } public boolean existLookDataByName(LookData look) { for (LookData lookdata : lookList) { if (lookdata.getLookName().equals(look.getLookName())) { return true; } } return false; } public boolean existLookDataByFileName(LookData look) { for (LookData lookdata : lookList) { if (lookdata.getLookFileName().equals(look.getLookFileName())) { return true; } } return false; } public List<SoundInfo> getSoundList() { return soundList; } public void setSoundList(List<SoundInfo> list) { soundList = list; } public int getRequiredResources() { int resources = Brick.NO_RESOURCES; for (Script script : scriptList) { if (!script.isCommentedOut()) { resources |= script.getRequiredResources(); } } for (LookData lookData : getLookDataList()) { resources |= lookData.getRequiredResources(); } return resources; } public List<NfcTagData> getNfcTagList() { return nfcTagList; } public void setNfcTagList(List<NfcTagData> list) { nfcTagList = list; } public int getNextNewUserBrickId() { return userBricks.size(); } @Override public String toString() { return name; } public void rename(String newSpriteName) { if ((getRequiredResources() & Brick.PHYSICS) > 0) { List<Sprite> spriteList = ProjectManager.getInstance().getCurrentScene().getSpriteList(); for (Sprite currentSprite : spriteList) { if ((currentSprite.getRequiredResources() & Brick.PHYSICS) > 0) { currentSprite.updateCollisionBroadcastMessages(getName(), newSpriteName); } } } if (hasCollision()) { renameSpriteInCollisionFormulas(newSpriteName, CatroidApplication.getAppContext()); } setName(newSpriteName); } public void updateCollisionBroadcastMessages(String oldCollisionObjectIdentifier, String newCollisionObjectIdentifier) { for (int scriptIndex = 0; scriptIndex < getNumberOfScripts(); scriptIndex++) { Script currentScript = getScript(scriptIndex); if (currentScript instanceof CollisionScript) { ((CollisionScript) currentScript).updateBroadcastMessage(oldCollisionObjectIdentifier, newCollisionObjectIdentifier); } } } public boolean containsLookData(LookData lookData) { for (LookData lookOfSprite : lookList) { if (lookOfSprite.equals(lookData)) { return true; } } return false; } public boolean existSoundInfoByName(SoundInfo sound) { for (SoundInfo soundInfo : soundList) { if (soundInfo.getTitle().equals(sound.getTitle())) { return true; } } return false; } public boolean existSoundInfoByFileName(SoundInfo sound) { for (SoundInfo soundInfo : soundList) { if (soundInfo.getSoundFileName().equals(sound.getSoundFileName())) { return true; } } return false; } public void updateUserVariableReferencesInUserVariableBricks(List<UserVariable> variables) { for (Brick brick : getListWithAllBricks()) { if (brick instanceof UserVariableBrick) { UserVariableBrick userVariableBrick = (UserVariableBrick) brick; for (UserVariable variable : variables) { UserVariable userVariableBrickVariable = userVariableBrick.getUserVariable(); if (userVariableBrickVariable != null && variable.getName().equals(userVariableBrickVariable.getName())) { userVariableBrick.setUserVariable(variable); break; } } } } } public boolean hasCollision() { boolean hasCollision = (this.getRequiredResources() & Brick.COLLISION) > 0; if (hasCollision) { return true; } Scene scene = ProjectManager.getInstance().getCurrentScene(); for (Sprite sprite : scene.getSpriteList()) { if (sprite.hasToCollideWith(this)) { return true; } } return false; } public boolean hasToCollideWith(Sprite other) { for (Script script : getScriptList()) { Brick scriptBrick = script.getScriptBrick(); if (scriptBrick instanceof FormulaBrick) { FormulaBrick formulaBrick = (FormulaBrick) scriptBrick; for (Formula formula : formulaBrick.getFormulas()) { if (formula.containsSpriteInCollision(other.getName())) { return true; } } } for (Brick brick : script.brickList) { if (brick instanceof FormulaBrick) { FormulaBrick formulaBrick = (FormulaBrick) brick; for (Formula formula : formulaBrick.getFormulas()) { if (formula.containsSpriteInCollision(other.getName())) { return true; } } } } } return false; } public void updateCollisionFormulasToVersion(float catroidLanguageVersion) { for (Script script : getScriptList()) { Brick scriptBrick = script.getScriptBrick(); if (scriptBrick instanceof FormulaBrick) { FormulaBrick formulaBrick = (FormulaBrick) scriptBrick; for (Formula formula : formulaBrick.getFormulas()) { formula.updateCollisionFormulasToVersion(catroidLanguageVersion); } } for (Brick brick : script.getBrickList()) { if (brick instanceof UserBrick) { UserBrick formulaBrick = (UserBrick) brick; for (Formula formula : formulaBrick.getFormulas()) { formula.updateCollisionFormulasToVersion(catroidLanguageVersion); } } else if (brick instanceof FormulaBrick) { FormulaBrick formulaBrick = (FormulaBrick) brick; for (Formula formula : formulaBrick.getFormulas()) { formula.updateCollisionFormulasToVersion(catroidLanguageVersion); } } } } } private void renameSpriteInCollisionFormulas(String newName, Context context) { String oldName = getName(); List<Sprite> spriteList = ProjectManager.getInstance().getCurrentScene().getSpriteList(); for (Sprite sprite : spriteList) { for (Script currentScript : sprite.getScriptList()) { if (currentScript == null) { return; } Brick scriptBrick = currentScript.getScriptBrick(); if (scriptBrick instanceof FormulaBrick) { FormulaBrick formulaBrick = (FormulaBrick) scriptBrick; for (Formula formula : formulaBrick.getFormulas()) { formula.updateCollisionFormulas(oldName, newName, context); } } List<Brick> brickList = currentScript.getBrickList(); for (Brick brick : brickList) { if (brick instanceof UserBrick) { List<Formula> formulaList = ((UserBrick) brick).getFormulas(); for (Formula formula : formulaList) { formula.updateCollisionFormulas(oldName, newName, context); } } if (brick instanceof FormulaBrick) { List<Formula> formulaList = ((FormulaBrick) brick).getFormulas(); for (Formula formula : formulaList) { formula.updateCollisionFormulas(oldName, newName, context); } } } } } } public void createCollisionPolygons() { for (LookData lookData : getLookDataList()) { lookData.getCollisionInformation().calculate(); } } public class PenConfiguration { public boolean penDown = false; public float penSize = BrickValues.PEN_SIZE; public Color penColor = BrickValues.PEN_COLOR; public PointF previousPoint = null; public boolean stamp = false; } public void setConvertToSingleSprite(boolean convertToSingleSprite) { this.convertToGroupItemSprite = false; this.convertToSingleSprite = convertToSingleSprite; } public void setConvertToGroupItemSprite(boolean convertToGroupItemSprite) { this.convertToSingleSprite = false; this.convertToGroupItemSprite = convertToGroupItemSprite; } public boolean isMobile() { return isMobile; } public void setIsMobile(boolean isMobile) { this.isMobile = isMobile; } public List<Brick> getBricksRequiringResource(int resource) { List<Brick> resourceBrickList = new ArrayList<Brick>(); for (Script script : scriptList) { resourceBrickList.addAll(script.getBricksRequiringResources(resource)); } return resourceBrickList; } }