/** * eAdventure (formerly <e-Adventure> and <e-Game>) is a research project of the * <e-UCM> research group. * * Copyright 2005-2010 <e-UCM> research group. * * You can access a list of all the contributors to eAdventure at: * http://e-adventure.e-ucm.es/contributors * * <e-UCM> is a research group of the Department of Software Engineering * and Artificial Intelligence at the Complutense University of Madrid * (School of Computer Science). * * C Profesor Jose Garcia Santesmases sn, * 28040 Madrid (Madrid), Spain. * * For more info please visit: <http://e-adventure.e-ucm.es> or * <http://www.e-ucm.es> * * **************************************************************************** * * This file is part of eAdventure, version 2.0 * * eAdventure is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * eAdventure 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with eAdventure. If not, see <http://www.gnu.org/licenses/>. */ package es.eucm.ead.importer.subconverters; import com.google.inject.Inject; import com.google.inject.Singleton; import es.eucm.ead.importer.EAdElementsCache; import es.eucm.ead.importer.ModelQuerier; import es.eucm.ead.importer.StringsConverter; import es.eucm.ead.importer.UtilsConverter; import es.eucm.ead.importer.resources.ResourcesConverter; import es.eucm.ead.importer.subconverters.actors.ElementConverter; import es.eucm.ead.importer.subconverters.actors.NPCConverter; import es.eucm.ead.importer.subconverters.conditions.ConditionsConverter; import es.eucm.ead.importer.subconverters.effects.EffectsConverter; import es.eucm.ead.importer.testers.ConverterTester; import es.eucm.ead.legacyplugins.model.LegacyVars; import es.eucm.ead.model.assets.drawable.EAdDrawable; import es.eucm.ead.model.assets.drawable.basics.shapes.AbstractShape; import es.eucm.ead.model.assets.drawable.basics.shapes.BezierShape; import es.eucm.ead.model.assets.multimedia.Music; import es.eucm.ead.model.elements.BasicElement; import es.eucm.ead.model.elements.conditions.Condition; import es.eucm.ead.model.elements.conditions.EmptyCond; import es.eucm.ead.model.elements.effects.ChangeSceneEf; import es.eucm.ead.model.elements.effects.Effect; import es.eucm.ead.model.elements.effects.EmptyEffect; import es.eucm.ead.model.elements.effects.PlayMusicEf; import es.eucm.ead.model.elements.effects.TriggerMacroEf; import es.eucm.ead.model.elements.effects.variables.ChangeFieldEf; import es.eucm.ead.model.elements.events.WatchFieldEv; import es.eucm.ead.model.elements.extra.EAdList; import es.eucm.ead.model.elements.huds.MouseHud; import es.eucm.ead.model.elements.operations.ElementField; import es.eucm.ead.model.elements.predef.effects.MakeActiveElementEf; import es.eucm.ead.model.elements.predef.effects.MoveActiveElementToMouseEf; import es.eucm.ead.model.elements.scenes.GhostElement; import es.eucm.ead.model.elements.scenes.Scene; import es.eucm.ead.model.elements.scenes.SceneElement; import es.eucm.ead.model.elements.scenes.SceneElementDef; import es.eucm.ead.model.params.fills.ColorFill; import es.eucm.ead.model.params.guievents.MouseGEv; import es.eucm.ead.model.params.text.EAdString; import es.eucm.ead.model.params.util.Position.Corner; import es.eucm.eadventure.common.data.adventure.AdventureData; import es.eucm.eadventure.common.data.chapter.ElementReference; import es.eucm.eadventure.common.data.chapter.Exit; import es.eucm.eadventure.common.data.chapter.ExitLook; import es.eucm.eadventure.common.data.chapter.Trajectory; import es.eucm.eadventure.common.data.chapter.elements.ActiveArea; import es.eucm.eadventure.common.data.chapter.elements.Player; import es.eucm.eadventure.common.data.chapter.resources.Resources; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.*; import java.util.List; @Singleton public class SceneConverter { private static final Logger logger = LoggerFactory .getLogger(SceneConverter.class); private static final int EXIT_Z = 20000; private static final int ACTIVE_AREA_Z = 10000; private static final int PLAYER_Z = 5000; private static final int FOREGROUND_Z = Integer.MAX_VALUE / 2; private static final ColorFill EXIT_FILL = new ColorFill(255, 0, 0, 100); private static final ColorFill ACTIVE_AREA_FILL = new ColorFill(0, 255, 0, 100); private TransitionConverter transitionConverter; private ResourcesConverter resourceConverter; private EAdElementsCache elementsCache; private RectangleConverter rectangleConverter; private UtilsConverter utilsConverter; private EffectsConverter effectConverter; private ConditionsConverter conditionsConverter; private StringsConverter stringsConverter; private ModelQuerier modelQuerier; private TrajectoryConverter trajectoryConverter; private ElementConverter elementConverter; private ConverterTester converterTester; @Inject public SceneConverter(ResourcesConverter resourceConverter, EAdElementsCache elementsCache, TransitionConverter transitionConverter, RectangleConverter rectangleConverter, UtilsConverter utilsConverter, EffectsConverter effectConverter, ConditionsConverter conditionsConverter, StringsConverter stringsConverter, ModelQuerier modelQuerier, TrajectoryConverter trajectoryConverter, NPCConverter elementConverter, ConverterTester converterTester) { this.resourceConverter = resourceConverter; this.elementsCache = elementsCache; this.transitionConverter = transitionConverter; this.rectangleConverter = rectangleConverter; this.utilsConverter = utilsConverter; this.effectConverter = effectConverter; this.conditionsConverter = conditionsConverter; this.stringsConverter = stringsConverter; this.modelQuerier = modelQuerier; this.trajectoryConverter = trajectoryConverter; this.elementConverter = elementConverter; this.converterTester = converterTester; } public Scene convert(es.eucm.eadventure.common.data.chapter.scenes.Scene s) { SceneElement background = new SceneElement(); Scene scene = new Scene(background); scene.setId(s.getId()); background.setId(s.getId() + "$bg"); logger.debug("Importing background..."); addAppearance(scene, s); // XXX Information logger.debug("Importing references..."); addReferences(scene, s); logger.debug("Importing active zones..."); addActiveZones(scene, s); logger.debug("Importing exits..."); addExits(scene, s); // Add trajectory if (modelQuerier.getAventureData().getPlayerMode() == AdventureData.MODE_PLAYER_3RDPERSON) { logger.debug("Importing trajectory..."); scene.setTrajectoryDefinition(trajectoryConverter.convert(s .getTrajectory())); } return scene; } public void addAppearance(Scene scene, es.eucm.eadventure.common.data.chapter.scenes.Scene s) { // Appearance tab SceneElement background = scene.getBackground(); // The foreground is only initialized if needed SceneElement foreground = null; // Resources blocks int i = 0; for (Resources r : s.getResources()) { logger.debug("---- Adding resources {}", i); // Background [SC - Bg] String backgroundPath = r .getAssetPath(es.eucm.eadventure.common.data.chapter.scenes.Scene.RESOURCE_TYPE_BACKGROUND); EAdDrawable drawable = utilsConverter.getBackground(backgroundPath); Dimension d = resourceConverter.getSize(backgroundPath); float scale = 1.0f; // If dimension is greater than 600, we have to scale if (d.getHeight() > 600) { scale = 600.0f / (float) d.getHeight(); } background.setAppearance(utilsConverter.getResourceBundleId(i), drawable); if (i == 0) { background.setBundle(utilsConverter.getResourceBundleId(i)); } // Foreground [SC - Fg] String foregroundPath = r .getAssetPath(es.eucm.eadventure.common.data.chapter.scenes.Scene.RESOURCE_TYPE_FOREGROUND); if (foregroundPath != null) { foregroundPath = utilsConverter.applyForegroundMask( foregroundPath, backgroundPath); if (foreground == null) { foreground = new SceneElement(); foreground.setEnable(false); foreground.setZ(FOREGROUND_Z); foreground.setBundle(utilsConverter.getResourceBundleId(i)); scene.add(foreground); } foreground.setAppearance(utilsConverter.getResourceBundleId(i), new es.eucm.ead.model.assets.drawable.basics.Image( foregroundPath)); } int finalWidth = (int) (d.getWidth() * scale); // [GE - Arrows] [GE - Follow] scene.putProperty(LegacyVars.SCENE_WIDTH, finalWidth); i++; } logger.debug("---- Adding resources conditions"); // Add conditioned resources utilsConverter.addResourcesConditions(s.getResources(), scene .getBackground(), SceneElement.VAR_BUNDLE_ID); if (foreground != null) { utilsConverter.addResourcesConditions(s.getResources(), foreground, SceneElement.VAR_BUNDLE_ID); } // [SC - Fg] this.addForegroundMusicConditions(scene, s.getResources(), foreground); } private void addReferences(Scene scene, es.eucm.eadventure.common.data.chapter.scenes.Scene s) { addReferences(scene, s.getAtrezzoReferences()); addReferences(scene, s.getItemReferences()); addReferences(scene, s.getCharacterReferences()); // Add player if (modelQuerier.getAventureData().getPlayerMode() == AdventureData.MODE_PLAYER_3RDPERSON) { SceneElement playerRef = new SceneElement( (SceneElementDef) elementsCache.get(Player.IDENTIFIER)); // [SC - Player Layer] if (s.isAllowPlayerLayer() && s.getPlayerLayer() != -1) { playerRef.setZ(s.getPlayerLayer()); } else { playerRef.setZ(PLAYER_Z); } playerRef.setScale(s.getPlayerScale()); playerRef.setPosition(Corner.BOTTOM_CENTER, s.getPositionX(), s .getPositionY()); if (s.getTrajectory() != null) { Trajectory t = s.getTrajectory(); playerRef.setScale(t.getInitial().getScale()); playerRef.setPosition(Corner.BOTTOM_CENTER, t.getInitial() .getX(), t.getInitial().getY()); } scene.addAddedEffect(new MakeActiveElementEf(playerRef)); scene.add(playerRef); scene.addBehavior(MouseGEv.MOUSE_LEFT_PRESSED, new MoveActiveElementToMouseEf()); } } private void addReferences(Scene scene, List<ElementReference> references) { for (ElementReference e : references) { SceneElementDef def = (SceneElementDef) elementsCache.get(e .getTargetId()); SceneElement sceneElement = new SceneElement(def); String sceneElementId = e.getTargetId() + "$" + elementsCache.newReference(e.getTargetId()); converterTester.checkBundles(e, sceneElementId); sceneElement.setId(sceneElementId); sceneElement.setPosition(Corner.BOTTOM_CENTER, e.getX(), e.getY()); // [ER - Layer] sceneElement.setZ(e.getLayer()); sceneElement.setScale(e.getScale()); // XXX Influence area scene.add(sceneElement); // Add event to change appearance when required by the actor's // definition if (def.getResources().size() > 1) { utilsConverter.addWatchDefinitionField(sceneElement, SceneElement.VAR_BUNDLE_ID); } // Add visibility condition // [ER - Conditions] utilsConverter.addWatchCondition(sceneElement, new ElementField( sceneElement, SceneElement.VAR_VISIBLE, true), e .getConditions()); } } private void addExits(Scene scene, es.eucm.eadventure.common.data.chapter.scenes.Scene s) { int i = 0; for (Exit e : s.getExits()) { AbstractShape shape = rectangleConverter.convert(e, EXIT_FILL); GhostElement exit = new GhostElement(shape); exit.setId(s.getId() + "$ex" + i); if (e.isRectangular()) { exit.setPosition(Corner.TOP_LEFT, e.getX(), e.getY()); } else { // Wrap bezier shape BezierShape bezier = (BezierShape) shape; Integer[] offset = bezier.removeOffset(); exit.setPosition(Corner.TOP_LEFT, offset[0], offset[1]); } // [EXIT - CondInactive] [EXIT - Conditions] Condition cond = conditionsConverter.convert(e.getConditions()); Effect effectWhenClick; // Next scene // [EXIT - Next] ChangeSceneEf nextScene = new ChangeSceneEf(); nextScene.setId(exit.getId() + "$cs"); nextScene.setNextEffectsAlways(true); nextScene.setNextScene(new BasicElement(e.getNextSceneId())); // [EXIT - Transition] nextScene.setTransition(transitionConverter.getTransitionExit(e .getTransitionType(), e.getTransitionTime())); // Add effects // [EXIT - Effects] List<Effect> effects = effectConverter.convert(e.getEffects()); if (effects.size() > 0) { effectWhenClick = effects.get(0); effects.get(effects.size() - 1).addNextEffect(nextScene); } else { effectWhenClick = nextScene; } // Add next effects // [EXIT - PostEffects] List<Effect> postEffects = effectConverter.convert(e .getPostEffects()); if (postEffects.size() > 0) { nextScene.addNextEffect(postEffects.get(0)); } // Set Z exit.setZ(EXIT_Z + i); // Add appearance ExitLook exitLook = e.getDefaultExitLook(); // Text if (!"".equals(exitLook.getExitText())) { EAdString text = stringsConverter.convert(exitLook .getExitText(), false); exit.putProperty(LegacyVars.BUBBLE_NAME, text); } // XXX For now, we use the default exit image utilsConverter.addCursorChange(exit, MouseHud.EXIT_CURSOR); // Add the exit to the scene scene.add(exit); List<Effect> notEffects = null; // [EXIT - NotEffects] // If it has not-effects if (e.isHasNotEffects()) { TriggerMacroEf triggerMacro = new TriggerMacroEf(); // Add ACTIVE effects triggerMacro.putEffect(cond, effectWhenClick); // Add INACTIVE effects EAdList<Effect> macro = new EAdList<Effect>(); notEffects = effectConverter.convert(e.getNotEffects()); if (notEffects.size() > 0) { macro.add(notEffects.get(0)); } // The macro only executes if the first condition fails triggerMacro.putEffects(EmptyCond.TRUE, macro); exit.addBehavior(MouseGEv.MOUSE_LEFT_PRESSED, triggerMacro); } else { if (!cond.equals(EmptyCond.TRUE)) { EmptyEffect empty = new EmptyEffect(); empty.setCondition(cond); empty.addNextEffect(effectWhenClick); effectWhenClick = empty; } exit.addBehavior(MouseGEv.MOUSE_LEFT_PRESSED, effectWhenClick); // Add visibility condition utilsConverter.addWatchCondition(exit, exit .getField(SceneElement.VAR_VISIBLE), e.getConditions()); } // Add tests converterTester.checkExit(s.getId(), e, exit, effects, nextScene, postEffects, notEffects); i++; } } private void addActiveZones(Scene scene, es.eucm.eadventure.common.data.chapter.scenes.Scene s) { int i = 0; for (ActiveArea a : s.getActiveAreas()) { // [AA - Shape] AbstractShape shape = rectangleConverter.convert(a, ACTIVE_AREA_FILL); GhostElement activeArea = new GhostElement(shape); // Add actions // [AA - Actions] elementConverter.addActions(a, activeArea.getDefinition()); elementConverter.addDescription(a, activeArea.getDefinition()); // [AA - Id] activeArea.setId(a.getId()); if (a.isRectangular()) { activeArea.setPosition(Corner.TOP_LEFT, a.getX(), a.getY()); } else { // Wrap bezier shape BezierShape bezier = (BezierShape) shape; Integer[] offset = bezier.removeOffset(); activeArea.setPosition(Corner.TOP_LEFT, offset[0], offset[1]); } // Set Z activeArea.setZ(ACTIVE_AREA_Z + i); elementsCache.put(activeArea); // Add visibility condition // [AA - Conditions] utilsConverter.addWatchCondition(activeArea, activeArea .getField(SceneElement.VAR_VISIBLE), a.getConditions()); scene.add(activeArea); i++; } } /** * Foregrounds are imported os objects over the scene. A bundle could have an empty foreground. Then, the foreground * should be invisible. * <p/> * Also, music of the scene is converted (since it shares conditions with the foreground) * * @param scene * @param resources * @param foreground */ private void addForegroundMusicConditions(Scene scene, List<Resources> resources, SceneElement foreground) { WatchFieldEv watchField = new WatchFieldEv(); boolean hasMusic = false; TriggerMacroEf triggerMacroVisible = new TriggerMacroEf(); TriggerMacroEf triggerMacroMusic = new TriggerMacroEf(); // Prepare visibility for foreground ChangeFieldEf makeForegroundVisible = null; ChangeFieldEf makeForegroundInvisible = null; if (foreground != null) { ElementField foregroundVisible = (foreground .getField(SceneElement.VAR_VISIBLE)); makeForegroundVisible = new ChangeFieldEf(foregroundVisible, EmptyCond.TRUE); makeForegroundInvisible = new ChangeFieldEf(foregroundVisible, EmptyCond.FALSE); } for (Resources r : resources) { Condition cond = conditionsConverter.convert(r.getConditions()); // Watch all the fields in the condition for (ElementField field : conditionsConverter .getFieldsLastCondition()) { watchField.watchField(field); } if (foreground != null) { // Check if there is foreground in this bundle if (r .getAssetPath(es.eucm.eadventure.common.data.chapter.scenes.Scene.RESOURCE_TYPE_FOREGROUND) == null) { triggerMacroVisible .putEffect(cond, makeForegroundInvisible); } else { triggerMacroVisible.putEffect(cond, makeForegroundVisible); } } // Check for music [SC - Music] String musicPath = r .getAssetPath(es.eucm.eadventure.common.data.chapter.scenes.Scene.RESOURCE_TYPE_MUSIC); if (musicPath != null) { hasMusic = true; Music music = resourceConverter.getMusic(musicPath); PlayMusicEf playMusic = new PlayMusicEf(music, 1.0f, true); triggerMacroMusic.putEffect(cond, playMusic); } } if (hasMusic) { scene.addAddedEffect(triggerMacroMusic); } if (foreground != null) { scene.addAddedEffect(triggerMacroVisible); } } }