/**
* 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.ModelQuerier;
import es.eucm.ead.importer.UtilsConverter;
import es.eucm.ead.importer.resources.ResourcesConverter;
import es.eucm.ead.importer.subconverters.effects.EffectsConverter;
import es.eucm.ead.model.assets.drawable.EAdDrawable;
import es.eucm.ead.model.assets.multimedia.Video;
import es.eucm.ead.model.elements.BasicElement;
import es.eucm.ead.model.elements.conditions.EmptyCond;
import es.eucm.ead.model.elements.effects.ChangeChapterEf;
import es.eucm.ead.model.elements.effects.ChangeSceneEf;
import es.eucm.ead.model.elements.effects.Effect;
import es.eucm.ead.model.elements.effects.QuitGameEf;
import es.eucm.ead.model.elements.effects.timedevents.WaitEf;
import es.eucm.ead.model.elements.effects.variables.ChangeFieldEf;
import es.eucm.ead.model.elements.operations.ElementField;
import es.eucm.ead.model.elements.scenes.Scene;
import es.eucm.ead.model.elements.scenes.SceneElement;
import es.eucm.ead.model.elements.scenes.VideoScene;
import es.eucm.ead.model.params.guievents.MouseGEv;
import es.eucm.eadventure.common.data.animation.Animation;
import es.eucm.eadventure.common.data.animation.Transition;
import es.eucm.eadventure.common.data.chapter.resources.Resources;
import es.eucm.eadventure.common.data.chapter.scenes.Cutscene;
import es.eucm.eadventure.common.data.chapter.scenes.Slidescene;
import es.eucm.eadventure.common.data.chapter.scenes.Videoscene;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
@Singleton
public class CutsceneConverter {
private static Logger logger = LoggerFactory
.getLogger(CutsceneConverter.class);
public static final String IN_CUTSCENE = "in_cutscene";
private final ModelQuerier modelQuerier;
private ResourcesConverter resourceConverter;
private TransitionConverter transitionConverter;
private UtilsConverter utilsConverter;
private EffectsConverter effectsConverter;
// Aux vars
private Animation animation;
private ArrayList<String> uris;
private static final String[] EXTENSIONS = new String[] { "png", "jpg",
"jpeg", "gif", "bmp" };
@Inject
public CutsceneConverter(ResourcesConverter resourceConverter,
TransitionConverter transitionConverter,
UtilsConverter utilsConverter, EffectsConverter effectsConverter,
ModelQuerier modelQuerier) {
this.resourceConverter = resourceConverter;
this.transitionConverter = transitionConverter;
this.utilsConverter = utilsConverter;
this.effectsConverter = effectsConverter;
this.modelQuerier = modelQuerier;
}
public List<Scene> convert(Cutscene scene) {
List<Scene> cutscene;
if (scene instanceof Slidescene) {
cutscene = convertSlidesScene((Slidescene) scene);
} else {
cutscene = convertVideoScene(scene);
}
int i = 0;
for (Scene s : cutscene) {
if (i == 0) {
s.setId(scene.getId());
} else {
s.setId(scene.getId() + i);
}
i++;
}
return cutscene;
}
public List<Scene> convertSlidesScene(Slidescene cs) {
List<Scene> cutscene = new ArrayList<Scene>();
// XXX when more than one appearance, we need to create a series of
// different slides
for (Resources r : cs.getResources()) {
// We import every slide as an independent scene
String slidesPath = r.getAssetPath(Slidescene.RESOURCE_TYPE_SLIDES);
// [SS - Slides]
prepareFrames(slidesPath);
for (int i = 0; i < frames(); i++) {
EAdDrawable background = utilsConverter.getBackground(uri(i),
true);
// XXX Sound
Scene scene = new Scene(new SceneElement(background));
Effect nextEffect;
if (cs.getNext() == Slidescene.ENDCHAPTER) {
// [SS - NextScene]
nextEffect = generateEndChapter();
} else {
// Link to next slide
ChangeSceneEf nextSlide;
// If it's last frame, we link with the next scene, ad
// we add the next effects
if (i == frames() - 1) {
// [SS - NextScene]
nextSlide = generateNextScene(cs);
} else {
// Else, we link with the next slide
nextSlide = new ChangeSceneEf(new BasicElement(cs
.getId()
+ (i + 1)));
}
// Add transition, if any
// For the last scene, we add the next transition
// [SS - Transition]
if (i == frames() - 1) {
nextSlide.setTransition(transitionConverter
.getTransitionNextScene(cs.getTransitionType(),
cs.getTransitionTime()));
} else {
// If the animation has transitions, we add it
if (isUseTransitions()) {
Transition t = getTransition(i);
nextSlide.setTransition(transitionConverter
.getTransition(t.getType(), (int) t
.getTime()));
}
}
nextEffect = nextSlide;
}
if (isWaitforclick(i)) {
// Change to next slide when click
scene.getBackground().addBehavior(
MouseGEv.MOUSE_LEFT_PRESSED, nextEffect);
} else {
// Wait the time given by the frame
WaitEf wait = new WaitEf(time(i));
wait.addNextEffect(nextEffect);
scene.addAddedEffect(wait);
}
scene.setReturnable(false);
cutscene.add(scene);
}
// Slides
// XXX scene music
}
// avoid empty cutscenes
if (cutscene.isEmpty()) {
logger.error("No scenes in cutscene {} (id {})", cs.getName(), cs
.getId());
return cutscene;
}
// Add conditioned resources
for (Scene scene : cutscene) {
utilsConverter.addResourcesConditions(cs.getResources(), scene
.getBackground(), SceneElement.VAR_BUNDLE_ID);
}
return cutscene;
}
public List<Scene> convertVideoScene(Cutscene cs) {
// [VI - Video]
Videoscene vs = (Videoscene) cs;
// XXX Not working when there's more than one resource
Video video = resourceConverter.getVideo(vs.getResources().get(0)
.getAssetPath(Videoscene.RESOURCE_TYPE_VIDEO));
VideoScene videoScene = new VideoScene();
videoScene.setVideo(video);
// [VI - NextScene]
Effect finalEffect;
if (cs.getType() == Cutscene.ENDCHAPTER) {
finalEffect = generateEndChapter();
} else {
finalEffect = generateNextScene(cs);
}
videoScene.addFinalEffect(finalEffect);
ArrayList<Scene> scenes = new ArrayList<Scene>();
scenes.add(videoScene);
return scenes;
}
private BasicElement getNextScene(Cutscene cs) {
BasicElement nextScene = null;
switch (cs.getNext()) {
// [CS - PrevScene]
case Slidescene.GOBACK:
nextScene = null;
break;
// [CS - NewScene]
case Slidescene.NEWSCENE:
nextScene = new BasicElement(cs.getTargetId());
break;
}
return nextScene;
}
public Effect generateEndChapter() {
Effect nextEffect;
// [CS - ChapterEnds]
int index = modelQuerier.getCurrentChapterIndex();
int totalChapter = modelQuerier.getAventureData().getChapters().size();
// Last chapter, quit the game
if (index == totalChapter - 1) {
nextEffect = new QuitGameEf();
} else {
// Go to next chapter
nextEffect = new ChangeChapterEf(modelQuerier
.generateChapterId(index + 1));
}
return nextEffect;
}
public ChangeSceneEf generateNextScene(Cutscene cs) {
// [CS - PrevScene] [CS - NewScene]
ChangeSceneEf nextScene = new ChangeSceneEf();
nextScene.setNextScene(getNextScene(cs));
List<Effect> effects = effectsConverter.convert(cs.getEffects());
ElementField inCutscene = new ElementField(modelQuerier
.getCurrentChapter(), IN_CUTSCENE + cs.getId(), false);
ChangeFieldEf finalEffect = new ChangeFieldEf(inCutscene,
EmptyCond.FALSE);
if (effects.size() > 0) {
nextScene.addNextEffect(effects.get(0));
effects.get(effects.size() - 1).addNextEffect(finalEffect);
} else {
nextScene.addNextEffect(finalEffect);
}
return nextScene;
}
void prepareFrames(String slidesPath) {
animation = null;
if (slidesPath.endsWith(".eaa")) {
animation = resourceConverter.getAnimation(slidesPath);
} else {
int frames = 0;
uris = new ArrayList<String>();
boolean done = false;
while (!done) {
String name = slidesPath + "_0" + (frames + 1);
done = true;
for (String ext : EXTENSIONS) {
String uri = name + "." + ext;
if (resourceConverter.fileExists(uri)) {
done = false;
uris.add(uri);
break;
}
uri = name + "." + ext.toUpperCase();
if (resourceConverter.fileExists(uri)) {
done = false;
uris.add(uri);
break;
}
}
frames++;
}
}
}
private int frames() {
return animation == null ? uris.size() : animation.getFrames().size();
}
private String uri(int i) {
return animation == null ? uris.get(i) : animation.getFrames().get(i)
.getUri();
}
private boolean isWaitforclick(int i) {
return animation == null
|| animation.getFrames().get(i).isWaitforclick();
}
private int time(int i) {
return (int) (animation == null ? 0 : animation.getFrames().get(i)
.getTime());
}
private boolean isUseTransitions() {
return animation != null && animation.isUseTransitions();
}
private Transition getTransition(int i) {
return animation.getTransitions().get(i);
}
}