/**
* 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.json.reader;
import com.google.gson.internal.StringMap;
import es.eucm.ead.model.assets.multimedia.Music;
import es.eucm.ead.model.assets.multimedia.Sound;
import es.eucm.ead.model.assets.text.EAdFont;
import es.eucm.ead.model.elements.BasicElement;
import es.eucm.ead.model.elements.conditions.Condition;
import es.eucm.ead.model.elements.effects.AddChildEf;
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.InterpolationEf;
import es.eucm.ead.model.elements.effects.PlayMusicEf;
import es.eucm.ead.model.elements.effects.PlaySoundEf;
import es.eucm.ead.model.elements.effects.QuitGameEf;
import es.eucm.ead.model.elements.effects.RemoveEf;
import es.eucm.ead.model.elements.effects.TogglePauseEf;
import es.eucm.ead.model.elements.effects.ToggleSoundEf;
import es.eucm.ead.model.elements.effects.TriggerMacroEf;
import es.eucm.ead.model.elements.effects.sceneelements.MoveSceneElementEf;
import es.eucm.ead.model.elements.effects.text.QuestionEf;
import es.eucm.ead.model.elements.effects.timedevents.WaitEf;
import es.eucm.ead.model.elements.effects.variables.ChangeFieldEf;
import es.eucm.ead.model.elements.extra.EAdList;
import es.eucm.ead.model.elements.operations.ElementField;
import es.eucm.ead.model.elements.operations.Operation;
import es.eucm.ead.model.elements.operations.SystemFields;
import es.eucm.ead.model.elements.operations.ValueOp;
import es.eucm.ead.model.elements.predef.effects.OneShotEf;
import es.eucm.ead.model.elements.predef.effects.SpeakSceneElementEf;
import es.eucm.ead.model.elements.scenes.SceneElement;
import es.eucm.ead.model.elements.transitions.EmptyTransition;
import es.eucm.ead.model.elements.transitions.FadeInTransition;
import es.eucm.ead.model.elements.transitions.ScaleTransition;
import es.eucm.ead.model.elements.transitions.Transition;
import es.eucm.ead.model.params.fills.ColorFill;
import es.eucm.ead.model.params.fills.Paint;
import es.eucm.ead.model.params.paint.EAdPaint;
import es.eucm.ead.model.params.text.EAdString;
import es.eucm.ead.reader.ObjectsFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Iterator;
@SuppressWarnings("unchecked")
public class EffectsReader {
static private Logger logger = LoggerFactory.getLogger(EffectsReader.class);
private ObjectsFactory objectsFactory;
private OperationReader operationReader;
private ConditionReader conditionsReader;
private TemplateReader templateReader;
private SceneReader sceneReader;
public EffectsReader(ObjectsFactory objectsFactory,
OperationReader operationReader, ConditionReader conditionsReader,
TemplateReader templateReader, SceneReader sceneReader) {
this.objectsFactory = objectsFactory;
this.operationReader = operationReader;
this.conditionsReader = conditionsReader;
this.templateReader = templateReader;
this.sceneReader = sceneReader;
}
public Effect read(StringMap<Object> e) {
Effect effect = null;
String type = (String) e.get("type");
if (type == null) {
logger.error("Effect without type {}", e);
}
try {
if (type.equals("interpolation")) {
effect = getInterpolation(e);
} else if (type.equals("changefield")) {
effect = getChangeField(e);
} else if (type.equals("changescene")) {
effect = getChangeScene(e);
} else if (type.equals("playsound")) {
effect = getPlaySound(e);
} else if (type.equals("wait")) {
effect = getWait(e);
} else if (type.equals("ref")) {
effect = getRef(e);
} else if (type.equals("sequence")) {
effect = getSequence(e);
} else if (type.equals("sequenceref")) {
effect = getSequenceRef(e);
} else if (type.equals("speak")) {
effect = getSpeak(e);
} else if (type.equals("triggermacro")) {
effect = getTriggerMacro(e);
} else if (type.equals("addchild")) {
effect = getAddChild(e);
} else if (type.equals("remove")) {
effect = getRemove(e);
} else if (type.equals("goto")) {
effect = getGoTo(e);
} else if (type.equals("oneshot")) {
effect = getOneShot(e);
} else if (type.equals("stopgoto")) {
effect = getGoTo(e);
((MoveSceneElementEf) effect).setXtarget(null);
((MoveSceneElementEf) effect).setYtarget(null);
} else if (type.equals("gotoposition")) {
effect = getGoToPosition(e);
} else if (type.equals("togglesound")) {
effect = new ToggleSoundEf();
} else if (type.equals("quit")) {
effect = getQuit(e);
} else if (type.equals("question")) {
effect = getQuestion(e);
} else if (type.equals("togglepause")) {
effect = new TogglePauseEf();
}
Boolean oneshot = (Boolean) e.get("oneshot");
if (oneshot != null && oneshot) {
effect = new OneShotEf(effect);
}
StringMap<Object> cond = (StringMap<Object>) e.get("cond");
if (cond != null) {
Condition condition = conditionsReader.read(cond);
effect.setCondition(condition);
}
String id = (String) e.get("id");
if (id != null) {
effect.setId(id);
}
Boolean persistent = (Boolean) e.get("persistent");
if (persistent != null) {
effect.setPersistent(persistent);
}
Boolean nextEffectsAlways = (Boolean) e.get("nextEffectsAlways");
effect.setNextEffectsAlways(nextEffectsAlways != null
&& nextEffectsAlways);
objectsFactory.putIdentified(effect);
addNextEffects(effect, e);
} catch (Exception ex) {
logger.error("Error reading {}", e, ex);
}
return effect;
}
private Effect getQuit(StringMap<Object> e) {
QuitGameEf effect = new QuitGameEf();
Boolean restart = (Boolean) e.get("restart");
effect.setRestart(restart != null ? restart : false);
return effect;
}
private Effect getQuestion(StringMap<Object> e) {
String question = (String) e.get("question");
QuestionEf effect = new QuestionEf();
effect.setQuestion(new EAdString(question));
Collection<StringMap<Object>> answers = (Collection<StringMap<Object>>) e
.get("answers");
for (StringMap<Object> a : answers) {
EAdString text = new EAdString((String) a.get("string"));
EAdList<Effect> effects = new EAdList<Effect>();
Collection<StringMap<Object>> effs = ((Collection<StringMap<Object>>) a
.get("effects"));
for (StringMap<Object> ef : effs) {
effects.add(read(ef));
}
// A empty list is ignored by the writer
if (effects.isEmpty()) {
effects.add(new EmptyEffect());
}
effect.addAnswer(text, effects);
}
return effect;
}
private Effect getGoToPosition(StringMap<Object> e) {
MoveSceneElementEf move = new MoveSceneElementEf();
move.setXtarget(new ValueOp(((Number) e.get("x")).floatValue()));
move.setYtarget(new ValueOp(((Number) e.get("y")).floatValue()));
SceneElement element = (SceneElement) objectsFactory
.getObjectById((String) e.get("sceneElement"));
move.setSceneElement(element);
Boolean useTrajectory = (Boolean) e.get("useTrajectory");
move.setUseTrajectory(useTrajectory == null ? false : useTrajectory);
return move;
}
private Effect getOneShot(StringMap<Object> e) {
Effect effect = this.read((StringMap<Object>) e.get("effect"));
return new OneShotEf(effect);
}
private Effect getGoTo(StringMap<Object> e) {
MoveSceneElementEf effect = new MoveSceneElementEf();
effect.setUseTrajectory(true);
String target = (String) e.get("target");
if (target != null) {
BasicElement element = (BasicElement) objectsFactory
.getObjectById(target);
effect.setSceneElement(element);
} else {
effect.setSceneElement(SystemFields.ACTIVE_ELEMENT);
}
String sceneElement = (String) e.get("sceneElement");
if (sceneElement != null)
effect.setTarget((SceneElement) objectsFactory
.getObjectById(sceneElement));
return effect;
}
private Effect getRemove(StringMap<Object> e) {
String target = (String) e.get("target");
return new RemoveEf((SceneElement) objectsFactory.getObjectById(target));
}
private Effect getAddChild(StringMap<Object> e) {
String parent = (String) e.get("parent");
SceneElement sceneElement = sceneReader
.parseSceneElement((StringMap<Object>) e.get("sceneElement"));
return new AddChildEf(parent, sceneElement);
}
private Effect getTriggerMacro(StringMap<Object> e) {
TriggerMacroEf triggerMacro = new TriggerMacroEf();
Collection<StringMap<Object>> conditions = (Collection<StringMap<Object>>) e
.get("conditions");
Collection<String> effects = (Collection<String>) e.get("effects");
Iterator<String> i = effects.iterator();
for (StringMap<Object> c : conditions) {
Condition cond = conditionsReader.read(c);
Effect effect = (Effect) objectsFactory.getObjectById(i.next());
triggerMacro.putEffect(cond, effect);
}
return triggerMacro;
}
private Effect getSpeak(StringMap<Object> e) {
String string = (String) e.get("string");
String sceneElement = (String) e.get("sceneElement");
BasicElement element = null;
if (sceneElement != null) {
element = (BasicElement) objectsFactory.getObjectById(sceneElement);
}
SpeakSceneElementEf speak = new SpeakSceneElementEf(element,
new EAdString(string));
String font = (String) e.get("font");
if (font != null) {
speak.setFont((EAdFont) objectsFactory.getObjectById(font));
}
String tp = (String) e.get("textPaint");
String bp = (String) e.get("bubblePaint");
EAdPaint textPaint = ColorFill.BLACK;
EAdPaint bubblePaint = Paint.BLACK_ON_WHITE;
if (tp != null) {
textPaint = objectsFactory.getPaint(tp);
}
if (bp != null) {
bubblePaint = objectsFactory.getPaint(bp);
}
Collection<StringMap<Object>> ops = (Collection<StringMap<Object>>) e
.get("operations");
if (ops != null)
for (StringMap<Object> op : ops) {
speak.getCaption().getOperations()
.add(operationReader.read(op));
}
Number time = (Number) e.get("time");
if (time != null) {
speak.setTime(time.intValue());
}
speak.setColor(textPaint, bubblePaint);
return speak;
}
private Effect getSequenceRef(StringMap<Object> e) {
Effect first = null;
Effect effect = null;
Collection<String> ef = (Collection<String>) e.get("sequence");
for (String eff : ef) {
Effect nextEffect = (Effect) objectsFactory.getObjectById(eff);
if (first == null) {
first = nextEffect;
effect = first;
} else {
effect.getNextEffects().add(nextEffect);
effect = nextEffect;
}
}
return first;
}
private Effect getSequence(StringMap<Object> e) {
Effect first = null;
Effect effect = null;
Collection<StringMap<Object>> ef = (Collection<StringMap<Object>>) e
.get("sequence");
for (StringMap<Object> eff : ef) {
Effect nextEffect = read(eff);
if (first == null) {
first = nextEffect;
effect = first;
} else {
effect.getNextEffects().add(nextEffect);
effect = nextEffect;
}
}
return first;
}
private Effect getRef(StringMap<Object> e) {
String ref = (String) e.get("ref");
Effect reference = (Effect) objectsFactory.getObjectById(ref);
if (reference == null) {
logger.warn("Reference to effect {} not found", ref);
}
return reference;
}
private Effect getWait(StringMap<Object> e) {
WaitEf effect = new WaitEf();
Boolean waitUntilClick = (Boolean) e.get("waitUntilClick");
if (waitUntilClick != null) {
effect.setWaitUntilClick(waitUntilClick);
}
Number time = (Number) e.get("time");
if (time != null) {
effect.setTime(time.intValue());
}
Boolean blockInput = (Boolean) e.get("blockInput");
if (blockInput != null) {
effect.setBlockInput(blockInput);
}
return effect;
}
private Effect getPlaySound(StringMap<Object> e) {
Boolean background = (Boolean) e.get("background");
String uri = (String) e.get("uri");
if (background != null && background) {
return new PlayMusicEf(uri == null ? null : new Music(uri), 1.0f,
true);
} else {
return new PlaySoundEf(uri == null ? null : new Sound(uri));
}
}
private Effect getChangeScene(StringMap<Object> e) {
StringMap<Object> t = (StringMap<Object>) e.get("transition");
Transition transition = EmptyTransition.instance();
if (t != null) {
Number time = (Number) t.get("time");
if (t.get("type").equals("fadein")) {
transition = new FadeInTransition(time.intValue());
} else if (t.get("type").equals("scale")) {
Boolean grow = (Boolean) t.get("grow");
Boolean targetNext = (Boolean) t.get("targetNext");
transition = new ScaleTransition(time.intValue(), grow != null
&& grow, targetNext != null && targetNext);
}
}
String ns = (String) e.get("nextScene");
BasicElement nextScene = null;
if (ns != null) {
nextScene = (BasicElement) objectsFactory.getObjectById(ns);
if (nextScene == null) {
nextScene = new BasicElement(ns);
}
}
return new ChangeSceneEf(nextScene, transition);
}
private void addNextEffects(Effect effect, StringMap<Object> e) {
Collection<Object> nextEffects = (Collection<Object>) e
.get("nextEffects");
if (nextEffects != null) {
for (Object o : nextEffects) {
Effect nextEffect = read((StringMap<Object>) o);
effect.getNextEffects().add(nextEffect);
}
}
Collection<Object> simultaneousEffects = (Collection<Object>) e
.get("simultaneousEffects");
if (simultaneousEffects != null) {
for (Object o : simultaneousEffects) {
Effect sEffect = read((StringMap<Object>) o);
effect.getSimultaneousEffects().add(sEffect);
}
}
}
private Effect getChangeField(StringMap<Object> e) {
ChangeFieldEf changeField = new ChangeFieldEf();
Operation operation = operationReader.read((StringMap<Object>) e
.get("operation"));
Collection<String> fields = (Collection<String>) e.get("fields");
for (String f : fields) {
// XXX only takes the last field in the list
ElementField field = operationReader.translateField(f);
changeField.setElement(field.getElement());
changeField.setVarName(field.getVarName());
}
changeField.setOperation(operation);
return changeField;
}
private Effect getInterpolation(StringMap<Object> e) {
InterpolationEf interpolation = new InterpolationEf();
Number start = (Number) e.get("start");
Number end = (Number) e.get("end");
Number time = (Number) e.get("time");
Collection<String> fields = (Collection<String>) e.get("fields");
for (String f : fields) {
interpolation.addField(operationReader.translateField(f),
new ValueOp(start.floatValue()), new ValueOp(end
.floatValue()));
}
Boolean relative = (Boolean) e.get("relative");
if (relative != null) {
interpolation.setRelative(relative);
}
interpolation.setInterpolationTime(time.intValue());
return interpolation;
}
public void readEffects(Collection<StringMap<Object>> effects) {
for (StringMap<Object> e : effects) {
templateReader.applyTemplates(e);
read(e);
}
}
}